-
Notifications
You must be signed in to change notification settings - Fork 83
Add fake verifier #607
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Add fake verifier #607
Changes from all commits
a7de78b
41b44b4
14f2779
082d325
1c3bf83
39456ba
034934b
f76f805
547f1a9
bdf0c69
0032cfc
14cb595
ec0368d
9f62904
fe7c3b1
cf6f313
4c2abbc
f2b410b
9d3bd2d
6a31da2
e133ee7
0210328
8419621
099745d
24aaf30
f1236c7
61ae754
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,13 +3,10 @@ package main | |
|
|
||
| import ( | ||
| "context" | ||
| "crypto/rsa" | ||
| "encoding/base64" | ||
| "encoding/json" | ||
| "errors" | ||
| "fmt" | ||
| "io" | ||
| "math/big" | ||
| "net" | ||
| "net/http" | ||
| "strings" | ||
|
|
@@ -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{ | ||
|
|
@@ -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 | ||
|
|
||
|
|
@@ -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----- | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this should go in a file such as |
||
| 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 := `{ | ||
|
|
@@ -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 | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -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" | ||||||
|
|
@@ -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 | ||||||
|
|
@@ -141,6 +143,9 @@ func (s *LaunchSpec) UnmarshalJSON(b []byte) error { | |||||
| return err | ||||||
| } | ||||||
|
|
||||||
| // | ||||||
|
||||||
| // | |
| // Parse the fake verifier flag from the input map. |
Uh oh!
There was an error while loading. Please reload this page.