mirror of
https://github.com/ultravioletrs/cocos.git
synced 2026-06-22 20:00:18 +00:00
fix: Implement KBS RCAR handshake with cookies
Fixes 'cookie not found' error (401) from KBS by: 1. Adding CookieJar support to KBS client 2. Implementing GetChallenge() to perform /auth handshake and capture session cookie 3. Updating Agent to get challenge, decode nonce, and use it for evidence generation 4. Regenerating mocks
This commit is contained in:
+24
-7
@@ -533,6 +533,26 @@ func (as *agentService) downloadAndDecryptResource(ctx context.Context, source *
|
||||
// 2. Get TEE evidence for KBS attestation
|
||||
as.logger.Info("getting TEE evidence for KBS attestation")
|
||||
|
||||
// Initialize KBS client first to get the challenge (nonce)
|
||||
as.logger.Info("initiating KBS attestation handshake", "kbs_url", as.computation.KBS.URL)
|
||||
kbsClient := kbs.NewClient(kbs.Config{
|
||||
URL: as.computation.KBS.URL,
|
||||
Timeout: 30 * time.Second,
|
||||
})
|
||||
|
||||
// Start RCAR handshake - get nonce and establish session cookie
|
||||
nonceStr, err := kbsClient.GetChallenge(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get KBS challenge: %w", err)
|
||||
}
|
||||
as.logger.Info("received KBS challenge nonce")
|
||||
|
||||
// Decode nonce for Attestation Service
|
||||
nonceBytes, err := base64.StdEncoding.DecodeString(nonceStr)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to decode KBS nonce: %w", err)
|
||||
}
|
||||
|
||||
// Auto-detect the platform type
|
||||
platform := attestation.CCPlatform()
|
||||
as.logger.Info("detected platform type", "platform", platform)
|
||||
@@ -542,6 +562,8 @@ func (as *agentService) downloadAndDecryptResource(ctx context.Context, source *
|
||||
|
||||
// Use computation ID as report data
|
||||
copy(reportData[:], []byte(as.computation.ID))
|
||||
// Use KBS provided nonce
|
||||
copy(nonce[:], nonceBytes)
|
||||
|
||||
var kbsEvidence []byte
|
||||
|
||||
@@ -574,15 +596,10 @@ func (as *agentService) downloadAndDecryptResource(ctx context.Context, source *
|
||||
as.logger.Info("evidence prepared for KBS", "kbs_evidence_len", len(kbsEvidence))
|
||||
|
||||
// 3. Attest with KBS and get token
|
||||
as.logger.Info("attesting with KBS", "kbs_url", as.computation.KBS.URL)
|
||||
|
||||
kbsClient := kbs.NewClient(kbs.Config{
|
||||
URL: as.computation.KBS.URL,
|
||||
Timeout: 30 * time.Second,
|
||||
})
|
||||
as.logger.Info("attesting with KBS")
|
||||
|
||||
runtimeData := kbs.RuntimeData{
|
||||
Nonce: base64.StdEncoding.EncodeToString(nonce[:]),
|
||||
Nonce: nonceStr,
|
||||
}
|
||||
|
||||
token, err := kbsClient.Attest(ctx, kbsEvidence, runtimeData)
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/http/cookiejar"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
@@ -26,6 +27,9 @@ var (
|
||||
|
||||
// Client defines the interface for KBS (Key Broker Service) communication.
|
||||
type Client interface {
|
||||
// GetChallenge initiates the attestation handshake and returns the nonce.
|
||||
GetChallenge(ctx context.Context) (string, error)
|
||||
|
||||
// Attest performs attestation with KBS and returns a token.
|
||||
Attest(ctx context.Context, evidence []byte, runtimeData RuntimeData) (string, error)
|
||||
|
||||
@@ -86,14 +90,57 @@ func NewClient(config Config) Client {
|
||||
config.Timeout = 30 * time.Second
|
||||
}
|
||||
|
||||
jar, _ := cookiejar.New(nil)
|
||||
|
||||
return &kbsClient{
|
||||
config: config,
|
||||
client: &http.Client{
|
||||
Timeout: config.Timeout,
|
||||
Jar: jar,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// GetChallenge initiates the RCAR handshake calling /kbs/v0/auth
|
||||
func (c *kbsClient) GetChallenge(ctx context.Context) (string, error) {
|
||||
url := fmt.Sprintf("%s/kbs/v0/auth", c.config.URL)
|
||||
|
||||
authReq := AuthRequest{
|
||||
Version: "0.1.0",
|
||||
TEE: "sample", // Initial handshake can be generic or specific
|
||||
}
|
||||
|
||||
reqBody, err := json.Marshal(authReq)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrAttestationFailed, err)
|
||||
}
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodPost, url, bytes.NewReader(reqBody))
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrAttestationFailed, err)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrAttestationFailed, err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return "", errors.Wrap(ErrAttestationFailed,
|
||||
fmt.Errorf("auth HTTP %d: %s", resp.StatusCode, string(body)))
|
||||
}
|
||||
|
||||
var authResp AuthResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&authResp); err != nil {
|
||||
return "", errors.Wrap(ErrInvalidResponse, err)
|
||||
}
|
||||
|
||||
return authResp.Nonce, nil
|
||||
}
|
||||
|
||||
// Attest performs attestation with KBS and returns a token.
|
||||
func (c *kbsClient) Attest(ctx context.Context, evidence []byte, runtimeData RuntimeData) (string, error) {
|
||||
// Build attest request
|
||||
@@ -115,6 +162,7 @@ func (c *kbsClient) Attest(ctx context.Context, evidence []byte, runtimeData Run
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
// Cookie jar handles the session cookie automatically
|
||||
resp, err := c.client.Do(req)
|
||||
if err != nil {
|
||||
return "", errors.Wrap(ErrAttestationFailed, err)
|
||||
@@ -123,6 +171,7 @@ func (c *kbsClient) Attest(ctx context.Context, evidence []byte, runtimeData Run
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
// Try to parse error details if JSON
|
||||
return "", errors.Wrap(ErrAttestationFailed,
|
||||
fmt.Errorf("HTTP %d: %s", resp.StatusCode, string(body)))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user