Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
a7de78b
add launch spec variable
mayafleischer Oct 24, 2025
41b44b4
add fake verifier variable to tests
mayafleischer Oct 24, 2025
14f2779
fix rand import err
mayafleischer Oct 24, 2025
082d325
format errors
mayafleischer Oct 26, 2025
1c3bf83
disable fakeverifier
mayafleischer Oct 26, 2025
39456ba
metadata flag fix
mayafleischer Oct 27, 2025
034934b
delimiter selection
mayafleischer Oct 27, 2025
f76f805
no custom token test
mayafleischer Oct 28, 2025
547f1a9
no custom token test + true
mayafleischer Oct 28, 2025
bdf0c69
add test keys to verifier & test_custom_token
mayafleischer Oct 30, 2025
0032cfc
launcher workload tests shortened
mayafleischer Oct 31, 2025
14cb595
launcher test fixes
mayafleischer Oct 31, 2025
ec0368d
launcher test fixes 1
mayafleischer Oct 31, 2025
9f62904
aud update workload tests
mayafleischer Oct 31, 2025
fe7c3b1
aud update workload tests
mayafleischer Oct 31, 2025
cf6f313
escape seq add
mayafleischer Oct 31, 2025
4c2abbc
escape seq add
mayafleischer Oct 31, 2025
f2b410b
clean up and custom test
mayafleischer Nov 3, 2025
9d3bd2d
clean up and custom test
mayafleischer Nov 3, 2025
6a31da2
needs image update
mayafleischer Nov 3, 2025
e133ee7
needs image update
mayafleischer Nov 3, 2025
0210328
needs image update
mayafleischer Nov 3, 2025
8419621
needs image update
mayafleischer Nov 3, 2025
099745d
update image and signature
mayafleischer Nov 3, 2025
24aaf30
format
mayafleischer Nov 3, 2025
f1236c7
update sig to correct location
mayafleischer Nov 3, 2025
61ae754
add fake fields to claims
mayafleischer Nov 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions launcher/agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,11 @@ func TestAttest(t *testing.T) {
t.Errorf("Invalid exp, iat, or nbf: %s", err)
}

if !claims.VerifyAudience("https://sts.googleapis.com/", true) {
if !claims.VerifyAudience("https://sts.googleapis.com", true) {
t.Errorf("Invalid aud")
}

if !claims.VerifyIssuer("https://confidentialcomputing.googleapis.com/", true) {
if !claims.VerifyIssuer("fake-issuer-for-testing", true) {
t.Errorf("Invalid iss")
}

Expand Down
12 changes: 10 additions & 2 deletions launcher/container_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import (
"github.com/google/go-tpm-tools/launcher/spec"
"github.com/google/go-tpm-tools/launcher/teeserver"
"github.com/google/go-tpm-tools/verifier"
"github.com/google/go-tpm-tools/verifier/fake"
"github.com/google/go-tpm-tools/verifier/ita"
"github.com/google/go-tpm-tools/verifier/util"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
Expand Down Expand Up @@ -240,7 +241,9 @@ func NewRunner(ctx context.Context, cdClient *containerd.Client, token oauth2.To
asAddr := launchSpec.AttestationServiceAddr

var verifierClient verifier.Client
if launchSpec.ITAConfig.ITARegion == "" {
if launchSpec.FakeVerifierEnabled {
verifierClient = fake.NewClient(nil)
} else if launchSpec.ITAConfig.ITARegion == "" {
gcaClient, err := util.NewRESTClient(ctx, asAddr, launchSpec.ProjectID, launchSpec.Region)
if err != nil {
return nil, fmt.Errorf("failed to create REST verifier client: %v", err)
Expand Down Expand Up @@ -592,7 +595,12 @@ func (r *ContainerRunner) Run(ctx context.Context) error {
r.logger.Info("EnableOnDemandAttestation is enabled: initializing TEE server.")

attestClients := teeserver.AttestClients{}
if r.launchSpec.ITAConfig.ITARegion != "" {

if r.launchSpec.FakeVerifierEnabled {
fakeClient := fake.NewClient(nil)
attestClients.GCA = fakeClient
attestClients.ITA = fakeClient
} else if r.launchSpec.ITAConfig.ITARegion != "" {
itaClient, err := ita.NewClient(r.launchSpec.ITAConfig)
if err != nil {
return fmt.Errorf("failed to create ITA client: %v", err)
Expand Down
11 changes: 10 additions & 1 deletion launcher/image/test/create_vm.sh
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,18 @@ create_vm() {
exit 1
fi

# use the fake verifier for all tests
FAKE_VERIFIER='test-fake-verifier=true'

APPEND_METADATA=''
if ! [ -z "$METADATA" ]; then
APPEND_METADATA="--metadata ${METADATA}"
if [[ "${METADATA}" == *"^~^"* ]]; then
APPEND_METADATA="--metadata ${METADATA}~${FAKE_VERIFIER}"
else
APPEND_METADATA="--metadata ${METADATA},${FAKE_VERIFIER}"
fi
else
APPEND_METADATA="--metadata ${FAKE_VERIFIER}"
fi

APPEND_METADATA_FILE=''
Expand Down
10 changes: 5 additions & 5 deletions launcher/image/test/scripts/test_launcher_workload.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ else
print_serial=true
fi

if echo $SERIAL_OUTPUT | grep -q 'aud: https://sts.googleapis.com'
if echo $SERIAL_OUTPUT | grep -q 'aud: \[https://sts.googleapis.com\]'
then
echo "- token aud verified"
else
Expand All @@ -52,7 +52,7 @@ else
print_serial=true
fi

if echo $SERIAL_OUTPUT | grep -q 'iss: https://confidentialcomputing.googleapis.com'
if echo $SERIAL_OUTPUT | grep -q 'iss: fake-issuer-for-testing'
then
echo "- token iss verified"
else
Expand All @@ -70,7 +70,7 @@ else
print_serial=true
fi

if echo $SERIAL_OUTPUT | grep -q 'oemid: 11129'
if echo $SERIAL_OUTPUT | grep -q 'oemid: fake-oem-id'
then
echo "- token oemid verified"
else
Expand All @@ -79,7 +79,7 @@ else
print_serial=true
fi

if echo $SERIAL_OUTPUT | grep -q 'hwmodel: GCP_AMD_SEV'
if echo $SERIAL_OUTPUT | grep -q 'hwmodel: fake-hw-model'
then
echo "- token hwmodel verified"
else
Expand All @@ -88,7 +88,7 @@ else
print_serial=true
fi

if echo $SERIAL_OUTPUT | grep -q 'swname: GCE'
if echo $SERIAL_OUTPUT | grep -q 'swname: fake-sw-name'
then
echo "- token swname verified"
else
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ else
print_logs=true
fi

if echo $CLOUD_LOGGING_OUTPUT | grep -q 'aud: https://sts.googleapis.com'
if echo $CLOUD_LOGGING_OUTPUT | grep -q 'aud: \[https://sts.googleapis.com\]'
then
echo "- token aud verified"
else
Expand All @@ -55,7 +55,7 @@ else
print_logs=true
fi

if echo $CLOUD_LOGGING_OUTPUT | grep -q 'iss: https://confidentialcomputing.googleapis.com'
if echo $CLOUD_LOGGING_OUTPUT | grep -q 'iss: fake-issuer-for-testing'
then
echo "- token iss verified"
else
Expand All @@ -73,7 +73,7 @@ else
print_logs=true
fi

if echo $CLOUD_LOGGING_OUTPUT | grep -q 'oemid: 11129'
if echo $CLOUD_LOGGING_OUTPUT | grep -q 'oemid: fake-oem-id'
then
echo "- token oemid verified"
else
Expand All @@ -82,7 +82,7 @@ else
print_logs=true
fi

if echo $CLOUD_LOGGING_OUTPUT | grep -q 'hwmodel: GCP_AMD_SEV'
if echo $CLOUD_LOGGING_OUTPUT | grep -q 'hwmodel: fake-hw-model'
then
echo "- token hwmodel verified"
else
Expand All @@ -91,7 +91,7 @@ else
print_logs=true
fi

if echo $CLOUD_LOGGING_OUTPUT | grep -q 'swname: GCE'
if echo $CLOUD_LOGGING_OUTPUT | grep -q 'swname: fake-sw-name'
then
echo "- token swname verified"
else
Expand Down
4 changes: 2 additions & 2 deletions launcher/image/test/test_oda_with_signed_container.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ substitutions:
'_VM_NAME_PREFIX': 'oda-signedcontainer'
'_ZONE': 'us-west1-a'
# If the workload image changes, the commit author should change the cosign signature as well to not break tests.
'_WORKLOAD_IMAGE': 'us-west1-docker.pkg.dev/confidential-space-images-dev/cs-integ-test-images/ipc/happypath@sha256:a7d9b216e16ad1fb2b1e8a35e3da58b21ee8dba84c3b4970567d7ec0234a4010'
'_WORKLOAD_IMAGE': 'us-west1-docker.pkg.dev/confidential-space-images-dev/cs-integ-test-images/ipc/happypath@sha256:36ba628076b4de46ada0226cfea198a25b396ce11e8b69710ae9172b2e4382b0'
'_SIGNATURE_REPO': 'us-docker.pkg.dev/confidential-space-images-dev/cs-cosign-tests/oda'
'_EXPECTED_SIG': 'MEUCIQCytUYBmuaWckWX6tNshHPELSyRLb41eRh6os3l4NCFMgIgUalPTILyb02Tqri9Ebtm56FkF+gcKbaVHkbpIJencOs='
'_EXPECTED_SIG': 'MEYCIQD7s2ozy2hSIafSVW/kQUCLJ6aOELI4Z0W9+vX/xgmDcAIhAMsic7ET83kEHtCxZXBXQfgIGWTSYiS1mbv58rSDpqdQ'

steps:
- name: 'gcr.io/cloud-builders/gcloud'
Expand Down
153 changes: 24 additions & 129 deletions launcher/image/testworkloads/customtoken/happypath/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ package main

import (
"context"
"crypto/rsa"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"math/big"
"net"
"net/http"
"strings"
Expand All @@ -19,38 +16,9 @@ import (
)

const (
socketPath = "/run/container_launcher/teeserver.sock"
expectedIssuer = "https://confidentialcomputing.googleapis.com"
wellKnownPath = "/.well-known/openid-configuration"
socketPath = "/run/container_launcher/teeserver.sock"
)

type jwksFile struct {
Keys []jwk `json:"keys"`
}

type jwk struct {
N string `json:"n"` // "nMMTBwJ7H6Id8zUCZd-L7uoNyz9b7lvoyse9izD9l2rtOhWLWbiG-7pKeYJyHeEpilHP4KdQMfUo8JCwhd-OMW0be_XtEu3jXEFjuq2YnPSPFk326eTfENtUc6qJohyMnfKkcOcY_kTE11jM81-fsqtBKjO_KiSkcmAO4wJJb8pHOjue3JCP09ZANL1uN4TuxbM2ibcyf25ODt3WQn54SRQTV0wn098Y5VDU-dzyeKYBNfL14iP0LiXBRfHd4YtEaGV9SBUuVhXdhx1eF0efztCNNz0GSLS2AEPLQduVuFoUImP4s51YdO9TPeeQ3hI8aGpOdC0syxmZ7LsL0rHE1Q",
E string `json:"e"` // "AQAB" or 65537 as an int
Kid string `json:"kid"` // "1f12fa916c3a0ef585894b4b420ad17dc9d6cdf5",

// Unused fields:
// Alg string `json:"alg"` // "RS256",
// Kty string `json:"kty"` // "RSA",
// Use string `json:"use"` // "sig",
}

type wellKnown struct {
JwksURI string `json:"jwks_uri"` // "https://www.googleapis.com/service_accounts/v1/metadata/jwk/signer@confidentialspace-sign.iam.gserviceaccount.com"

// Unused fields:
// Iss string `json:"issuer"` // "https://confidentialcomputing.googleapis.com"
// Subject_types_supported string `json:"subject_types_supported"` // [ "public" ]
// Response_types_supported string `json:"response_types_supported"` // [ "id_token" ]
// Claims_supported string `json:"claims_supported"` // [ "sub", "aud", "exp", "iat", "iss", "jti", "nbf", "dbgstat", "eat_nonce", "google_service_accounts", "hwmodel", "oemid", "secboot", "submods", "swname", "swversion" ]
// Id_token_signing_alg_values_supported string `json:"id_token_signing_alg_values_supported"` // [ "RS256" ]
// Scopes_supported string `json:"scopes_supported"` // [ "openid" ]
}

func getCustomTokenBytes(body string) ([]byte, error) {
httpClient := http.Client{
Transport: &http.Transport{
Expand Down Expand Up @@ -78,100 +46,6 @@ func getCustomTokenBytes(body string) ([]byte, error) {
return tokenbytes, nil
}

func getWellKnownFile() (wellKnown, error) {
httpClient := http.Client{}
resp, err := httpClient.Get(expectedIssuer + wellKnownPath)
if err != nil {
return wellKnown{}, fmt.Errorf("failed to get raw .well-known response: %w", err)
}

wellKnownJSON, err := io.ReadAll(resp.Body)
if err != nil {
return wellKnown{}, fmt.Errorf("failed to read .well-known response: %w", err)
}
resp.Body.Close()

wk := wellKnown{}
json.Unmarshal(wellKnownJSON, &wk)
return wk, nil
}

func getJWKFile() (jwksFile, error) {
wk, err := getWellKnownFile()
if err != nil {
return jwksFile{}, fmt.Errorf("failed to get .well-known json: %w", err)
}

// Get JWK URI from .wellknown
uri := wk.JwksURI
fmt.Printf("jwks URI: %v\n", uri)

httpClient := http.Client{}
resp, err := httpClient.Get(uri)
if err != nil {
return jwksFile{}, fmt.Errorf("failed to get raw JWK response: %w", err)
}

jwkbytes, err := io.ReadAll(resp.Body)
if err != nil {
return jwksFile{}, fmt.Errorf("failed to read JWK body: %w", err)
}

file := jwksFile{}
err = json.Unmarshal(jwkbytes, &file)
if err != nil {
return jwksFile{}, fmt.Errorf("failed to unmarshall JWK content: %w", err)
}

return file, nil
}

// N and E are 'base64urlUInt' encoded: https://www.rfc-editor.org/rfc/rfc7518#section-6.3
func base64urlUIntDecodeToBigInt(s string) (*big.Int, error) {
b, err := base64.RawURLEncoding.DecodeString(s)
if err != nil {
return nil, err
}
z := new(big.Int)
z.SetBytes(b)
return z, nil
}

func getRSAPublicKeyFromJWKsFile(t *jwt.Token) (any, error) {
keysfile, err := getJWKFile()
if err != nil {
return nil, fmt.Errorf("failed to fetch the JWK file: %w", err)
}

// Multiple keys are present in this endpoint to allow for key rotation.
// This method finds the key that was used for signing to pass to the validator.
kid := t.Header["kid"]
for _, key := range keysfile.Keys {
if key.Kid != kid {
continue // Select the key used for signing
}

n, err := base64urlUIntDecodeToBigInt(key.N)
if err != nil {
return nil, fmt.Errorf("failed to decode key.N %w", err)
}
e, err := base64urlUIntDecodeToBigInt(key.E)
if err != nil {
return nil, fmt.Errorf("failed to decode key.E %w", err)
}

// The parser expects an rsa.PublicKey: https://github.com/golang-jwt/jwt/blob/main/rsa.go#L53
// or an array of keys. We chose to show passing a single key in this example as its possible
// not all validators accept multiple keys for validation.
return &rsa.PublicKey{
N: n,
E: int(e.Int64()),
}, nil
}

return nil, fmt.Errorf("failed to find key with kid '%v' from well-known endpoint", kid)
}

func decodeAndValidateToken(tokenBytes []byte, keyFunc func(t *jwt.Token) (any, error)) (*jwt.Token, error) {
var err error

Expand Down Expand Up @@ -217,6 +91,27 @@ func decodeAndValidateToken(tokenBytes []byte, keyFunc func(t *jwt.Token) (any,
return nil, fmt.Errorf("couldn't handle this token or couldn't read a validation error: %v", err)
}

func getTestRSAPublicKey(token *jwt.Token) (any, error) {
// Always return the same hardcoded public key.

// Verify the signing method
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}

const publicKeyPEM = `-----BEGIN PUBLIC KEY-----
Copy link
Contributor

@alexmwu alexmwu Nov 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should go in a file such as verifier/fake/signer_rsa.pub

MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjz/x1INhnRfOm2eE71YE
FByB9mDyyjyQJ4HN+Vha8vqvtjM9T5DaFguG3LGlA9sTKEz72VWPs0K5ftlcI+/G
cbF4J4wH+j4T9VTprvQ8WE+3r6Kd+gqmmTDX8H/lZQqf/EgqmZ8rXzUSaXEGttBE
ZKitCpgbucE47981dhEqdX7zPGJUIuKW5T+JcRVwZ2I5sZyqXV7cVX9x/Uo+i2B+
fWS+zQFz3qXN8oeEAHPthrFfCv82+TRaqIWX9BOzJWo6TkCh+kkRG4rMcWXQqE+Z
tsRwRDo362eMUQqsowckm5XAsLWbHUz/JwVJNPLqT5zeQn7ru0xlAhi0wcb31OAU
RwIDAQAB
-----END PUBLIC KEY-----`

return jwt.ParseRSAPublicKeyFromPEM([]byte(publicKeyPEM))
}

func main() {
// Format token request
body := `{
Expand All @@ -233,8 +128,8 @@ func main() {
return
}

// Write a method to return a public key from the well-known endpoint
keyFunc := getRSAPublicKeyFromJWKsFile
// Method to return a public key used for testing
keyFunc := getTestRSAPublicKey

// The following code could be run by a remote party (not necessarily in a
// Confidential Space workload) in order to verify properties of the original
Expand Down
7 changes: 6 additions & 1 deletion launcher/spec/launch_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const (

// Metadata variable names.
const (
fakeVerifierKey = "test-fake-verifier"
imageRefKey = "tee-image-reference"
signedImageRepos = "tee-signed-image-repos"
restartPolicyKey = "tee-restart-policy"
Expand Down Expand Up @@ -109,7 +110,8 @@ type EnvVar struct {
// LaunchSpec contains specification set by the operator who wants to
// launch a container.
type LaunchSpec struct {
Experiments experiments.Experiments
Experiments experiments.Experiments
FakeVerifierEnabled bool

// MDS-based values.
ImageRef string
Expand Down Expand Up @@ -141,6 +143,9 @@ func (s *LaunchSpec) UnmarshalJSON(b []byte) error {
return err
}

//
Copy link

Copilot AI Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The empty comment on line 146 should be removed or replaced with a meaningful explanation of what the following code does.

Suggested change
//
// Parse the fake verifier flag from the input map.

Copilot uses AI. Check for mistakes.
s.FakeVerifierEnabled, _ = strconv.ParseBool(unmarshaledMap[fakeVerifierKey])

s.ImageRef = unmarshaledMap[imageRefKey]
if s.ImageRef == "" {
return errImageRefNotSpecified
Expand Down
Loading
Loading