diff --git a/src/server/utils/gcp-attestation.ts b/src/server/utils/gcp-attestation.ts index b8aba752..c86fa602 100644 --- a/src/server/utils/gcp-attestation.ts +++ b/src/server/utils/gcp-attestation.ts @@ -27,7 +27,7 @@ interface JwtPayload { exp: number iat: number aud: string - eat_nonce?: string // Contains "tee_k_public_key:0x..." or "tee_t_public_key:0x..." + eat_nonce?: string | string[] // Single nonce or array; first element is always the public key nonce dbgstat?: string // Debug status: "enabled" or "disabled-since-boot" // GCP Confidential Computing specific claims google?: { @@ -353,15 +353,31 @@ export async function validateGcpAttestationAndExtractKey( } // 5. Extract ETH address from eat_nonce + // GCP returns eat_nonce as a string (single nonce) or string array (multiple nonces). + // Find the public key nonce by pattern; additional nonces (e.g. cert hash) are ignored here. if(!payload.eat_nonce) { errors.push('No eat_nonce field found in JWT payload') return { isValid: false, errors } } - // Format: "tee_k_public_key:0x..." or "tee_t_public_key:0x..." - const match = payload.eat_nonce.match(/^(tee_[kt])_public_key:0x([0-9a-fA-F]{40})$/) - if(!match) { - errors.push(`Invalid eat_nonce format: ${payload.eat_nonce}`) + const publicKeyPattern = /^(tee_[kt])_public_key:0x([0-9a-fA-F]{40})$/ + const nonces = Array.isArray(payload.eat_nonce) + ? payload.eat_nonce + : [payload.eat_nonce] + + let eatNonce: string | undefined + let match: RegExpMatchArray | null = null + for(const n of nonces) { + const m = n.match(publicKeyPattern) + if(m) { + eatNonce = n + match = m + break + } + } + + if(!match || !eatNonce) { + errors.push(`No public key nonce found in eat_nonce: ${JSON.stringify(payload.eat_nonce)}`) return { isValid: false, errors } } @@ -371,7 +387,7 @@ export async function validateGcpAttestationAndExtractKey( const ethAddress = new Uint8Array(Buffer.from(hexAddress, 'hex')) if(logger) { - logger.info(`Extracted address from eat_nonce: ${payload.eat_nonce}`) + logger.info(`Extracted address from eat_nonce: ${eatNonce}`) } // Extract image digest from JWT payload (GCP's equivalent to PCR0)