@@ -73,127 +73,165 @@ func TestMissingRootFails(t *testing.T) {
7373 }
7474}
7575
76- func TestAPI (t * testing.T ) {
77- signer , issuer := newOIDCIssuer (t )
78-
79- subject := strings .ReplaceAll (issuer + "/foo/bar" , "http" , "spiffe" )
80-
81- // Create an OIDC token using this issuer's signer.
82- tok , err := jwt .Signed (signer ).Claims (jwt.Claims {
83- Issuer : issuer ,
84- IssuedAt : jwt .NewNumericDate (time .Now ()),
85- Expiry : jwt .NewNumericDate (time .Now ().Add (30 * time .Minute )),
86- Subject : subject ,
87- Audience : jwt.Audience {"sigstore" },
88- }).CompactSerialize ()
89- if err != nil {
90- t .Fatalf ("CompactSerialize() = %v" , err )
91- }
76+ // oidcTestContainer holds values needed for each API test invocation
77+ type oidcTestContainer struct {
78+ Signer jose.Signer
79+ Issuer string
80+ Subject string
81+ }
9282
93- // Create a FulcioConfig that supports this issuer.
83+ // Tests API for SPIFFE and URI subject types
84+ func TestAPIWithUriSubject (t * testing.T ) {
85+ spiffeSigner , spiffeIssuer := newOIDCIssuer (t )
86+ uriSigner , uriIssuer := newOIDCIssuer (t )
87+
88+ // Create a FulcioConfig that supports these issuers.
9489 cfg , err := config .Read ([]byte (fmt .Sprintf (`{
9590 "OIDCIssuers": {
9691 %q: {
9792 "IssuerURL": %q,
9893 "ClientID": "sigstore",
9994 "Type": "spiffe"
95+ },
96+ %q: {
97+ "IssuerURL": %q,
98+ "ClientID": "sigstore",
99+ "SubjectDomain": %q,
100+ "Type": "uri"
100101 }
101102 }
102- }` , issuer , issuer )))
103+ }` , spiffeIssuer , spiffeIssuer , uriIssuer , uriIssuer , uriIssuer )))
103104 if err != nil {
104105 t .Fatalf ("config.Read() = %v" , err )
105106 }
106107
107- // Stand up an ephemeral CA we can use for signing certificate requests.
108- eca , err := ephemeralca .NewEphemeralCA ()
109- if err != nil {
110- t .Fatalf ("ephemeralca.NewEphemeralCA() = %v" , err )
111- }
108+ spiffeSubject := strings .ReplaceAll (spiffeIssuer + "/foo/bar" , "http" , "spiffe" )
109+ uriSubject := uriIssuer + "/users/1"
112110
113- ctlogServer := fakeCTLogServer (t )
114- if ctlogServer == nil {
115- t .Fatalf ("Failed to create the fake ctlog server" )
116- }
111+ for _ , c := range []oidcTestContainer {
112+ {
113+ Signer : spiffeSigner , Issuer : spiffeIssuer , Subject : spiffeSubject ,
114+ },
115+ {
116+ Signer : uriSigner , Issuer : uriIssuer , Subject : uriSubject ,
117+ }} {
118+ // Create an OIDC token using this issuer's signer.
119+ tok , err := jwt .Signed (c .Signer ).Claims (jwt.Claims {
120+ Issuer : c .Issuer ,
121+ IssuedAt : jwt .NewNumericDate (time .Now ()),
122+ Expiry : jwt .NewNumericDate (time .Now ().Add (30 * time .Minute )),
123+ Subject : c .Subject ,
124+ Audience : jwt.Audience {"sigstore" },
125+ }).CompactSerialize ()
126+ if err != nil {
127+ t .Fatalf ("CompactSerialize() = %v" , err )
128+ }
117129
118- // Create a test HTTP server to host our API.
119- h := New (ctl .New (ctlogServer .URL ), eca )
120- server := httptest .NewServer (http .HandlerFunc (func (rw http.ResponseWriter , r * http.Request ) {
121- ctx := r .Context ()
122- // For each request, infuse context with our snapshot of the FulcioConfig.
123- ctx = config .With (ctx , cfg )
130+ // Stand up an ephemeral CA we can use for signing certificate requests.
131+ eca , err := ephemeralca .NewEphemeralCA ()
132+ if err != nil {
133+ t .Fatalf ("ephemeralca.NewEphemeralCA() = %v" , err )
134+ }
124135
125- h .ServeHTTP (rw , r .WithContext (ctx ))
126- }))
127- t .Cleanup (server .Close )
136+ ctlogServer := fakeCTLogServer (t )
137+ if ctlogServer == nil {
138+ t .Fatalf ("Failed to create the fake ctlog server" )
139+ }
128140
129- // Create an API client that speaks to the API endpoint we created above .
130- u , err := url . Parse ( server .URL )
131- if err != nil {
132- t . Fatalf ( "url.Parse() = %v" , err )
133- }
134- client := NewClient ( u )
141+ // Create a test HTTP server to host our API .
142+ h := New ( ctl . New ( ctlogServer .URL ), eca )
143+ server := httptest . NewServer ( http . HandlerFunc ( func ( rw http. ResponseWriter , r * http. Request ) {
144+ ctx := r . Context ( )
145+ // For each request, infuse context with our snapshot of the FulcioConfig.
146+ ctx = config . With ( ctx , cfg )
135147
136- // Sign the subject with our keypair, and provide the public key
137- // for verification.
138- priv , err := ecdsa .GenerateKey (elliptic .P256 (), rand .Reader )
139- if err != nil {
140- t .Fatalf ("GenerateKey() = %v" , err )
141- }
142- pubBytes , err := x509 .MarshalPKIXPublicKey (& priv .PublicKey )
143- if err != nil {
144- t .Fatalf ("x509.MarshalPKIXPublicKey() = %v" , err )
145- }
146- hash := sha256 .Sum256 ([]byte (subject ))
147- proof , err := ecdsa .SignASN1 (rand .Reader , priv , hash [:])
148- if err != nil {
149- t .Fatalf ("SignASN1() = %v" , err )
150- }
148+ h .ServeHTTP (rw , r .WithContext (ctx ))
149+ }))
150+ t .Cleanup (server .Close )
151151
152- // Hit the API to have it sign our certificate.
153- resp , err := client .SigningCert (CertificateRequest {
154- PublicKey : Key {
155- Content : pubBytes ,
156- },
157- SignedEmailAddress : proof ,
158- }, tok )
159- if err != nil {
160- t .Fatalf ("SigningCert() = %v" , err )
161- }
152+ // Create an API client that speaks to the API endpoint we created above.
153+ u , err := url .Parse (server .URL )
154+ if err != nil {
155+ t .Fatalf ("url.Parse() = %v" , err )
156+ }
157+ client := NewClient (u )
162158
163- if string (resp .SCT ) == "" {
164- t .Error ("Did not get SCT" )
165- }
159+ // Sign the subject with our keypair, and provide the public key
160+ // for verification.
161+ priv , err := ecdsa .GenerateKey (elliptic .P256 (), rand .Reader )
162+ if err != nil {
163+ t .Fatalf ("GenerateKey() = %v" , err )
164+ }
165+ pubBytes , err := x509 .MarshalPKIXPublicKey (& priv .PublicKey )
166+ if err != nil {
167+ t .Fatalf ("x509.MarshalPKIXPublicKey() = %v" , err )
168+ }
169+ hash := sha256 .Sum256 ([]byte (c .Subject ))
170+ proof , err := ecdsa .SignASN1 (rand .Reader , priv , hash [:])
171+ if err != nil {
172+ t .Fatalf ("SignASN1() = %v" , err )
173+ }
166174
167- // Check that we get the CA root back as well.
168- root , err := client .RootCert ()
169- if err != nil {
170- t .Fatal ("Failed to get Root" , err )
171- }
172- if root == nil {
173- t .Fatal ("Got nil root back" )
174- }
175- if len (root .ChainPEM ) == 0 {
176- t .Fatal ("Got back empty chain" )
177- }
178- block , rest := pem .Decode (root .ChainPEM )
179- if block == nil {
180- t .Fatal ("Did not find PEM data" )
181- }
182- if len (rest ) != 0 {
183- t .Fatal ("Got more than bargained for, should only have one cert" )
184- }
185- if block .Type != "CERTIFICATE" {
186- t .Fatalf ("Unexpected root type, expected CERTIFICATE, got %s" , block .Type )
187- }
188- rootCert , err := x509 .ParseCertificate (block .Bytes )
189- if err != nil {
190- t .Fatalf ("Failed to parse the received root cert: %v" , err )
191- }
192- if ! rootCert .Equal (eca .RootCA ) {
193- t .Errorf ("Root CA does not match, wanted %+v got %+v" , eca .RootCA , rootCert )
175+ // Hit the API to have it sign our certificate.
176+ resp , err := client .SigningCert (CertificateRequest {
177+ PublicKey : Key {
178+ Content : pubBytes ,
179+ },
180+ SignedEmailAddress : proof ,
181+ }, tok )
182+ if err != nil {
183+ t .Fatalf ("SigningCert() = %v" , err )
184+ }
185+
186+ if string (resp .SCT ) == "" {
187+ t .Error ("Did not get SCT" )
188+ }
189+
190+ // Check that we get the CA root back as well.
191+ root , err := client .RootCert ()
192+ if err != nil {
193+ t .Fatal ("Failed to get Root" , err )
194+ }
195+ if root == nil {
196+ t .Fatal ("Got nil root back" )
197+ }
198+ if len (root .ChainPEM ) == 0 {
199+ t .Fatal ("Got back empty chain" )
200+ }
201+ block , rest := pem .Decode (root .ChainPEM )
202+ if block == nil {
203+ t .Fatal ("Did not find PEM data" )
204+ }
205+ if len (rest ) != 0 {
206+ t .Fatal ("Got more than bargained for, should only have one cert" )
207+ }
208+ if block .Type != "CERTIFICATE" {
209+ t .Fatalf ("Unexpected root type, expected CERTIFICATE, got %s" , block .Type )
210+ }
211+ rootCert , err := x509 .ParseCertificate (block .Bytes )
212+ if err != nil {
213+ t .Fatalf ("Failed to parse the received root cert: %v" , err )
214+ }
215+ if ! rootCert .Equal (eca .RootCA ) {
216+ t .Errorf ("Root CA does not match, wanted %+v got %+v" , eca .RootCA , rootCert )
217+ }
218+ // Compare leaf certificate values
219+ block , _ = pem .Decode (resp .CertPEM )
220+ leafCert , err := x509 .ParseCertificate (block .Bytes )
221+ if err != nil {
222+ t .Fatalf ("Failed to parse the received leaf cert: %v" , err )
223+ }
224+ if len (leafCert .URIs ) != 1 {
225+ t .Fatalf ("Unexpected length of leaf certificate URIs, expected 1, got %d" , len (leafCert .URIs ))
226+ }
227+ uSubject , err := url .Parse (c .Subject )
228+ if err != nil {
229+ t .Fatalf ("Failed to parse subject URI" )
230+ }
231+ if * leafCert .URIs [0 ] != * uSubject {
232+ t .Fatalf ("Subjects do not match: Expected %v, got %v" , uSubject , leafCert .URIs [0 ])
233+ }
194234 }
195- // TODO(mattmoor): What interesting checks can we perform on
196- // the other return values?
197235}
198236
199237// Stand up a very simple OIDC endpoint.
0 commit comments