1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package x509
17
18 import (
19 "bytes"
20 "crypto"
21 "crypto/ecdsa"
22 "crypto/ed25519"
23 "crypto/rsa"
24 "crypto/sha256"
25 "crypto/x509"
26 "encoding/hex"
27 "net"
28 "net/url"
29 "reflect"
30 "strings"
31 "testing"
32
33 "github.com/sigstore/rekor/pkg/pki/identity"
34 "github.com/sigstore/rekor/pkg/pki/x509/testutils"
35 "github.com/sigstore/sigstore/pkg/cryptoutils"
36 "github.com/sigstore/sigstore/pkg/signature"
37 )
38
39
40
41
42 const pkcs1v15Priv = `-----BEGIN PRIVATE KEY-----
43 MIIBVQIBADANBgkqhkiG9w0BAQEFAASCAT8wggE7AgEAAkEAoLEL57Kd5w8b5LCl
44 SM+5mJbVYj4GoFXP/Gynfk6mDj7aANYWAkU74xkjz0BX2Nq0IT9DyxWI8aXZ8B6R
45 YtbsPwIDAQABAkA2WgwTz5eXKsYdgR421YQKN6JvO1mUa9IQqFOy5jlGgbR+W5HG
46 JfQVJKhCGMYYmByHgR0QDk/6gvJjhuszTHuJAiEA0siY/vE20zC1UHpPgDXXVSNN
47 dKtM6YKBKSo47oTKQHsCIQDDKZgal50Cd3W+lOWpNO23QGZgBhJrJ70TpcPWGEsS
48 DQIhAIDIMLnq1G1Z4B2IbRRPUP3icMtscbRlmNZ2xovsM8oLAiBluZh+w+gjEQFe
49 hV3wBJajnf2+r2uKTvxO8WhSf/chQQIhAKzYjX2chfvPN6hRqeGeoPpRLXS8cdxC
50 A4hZJRvZgkO3
51 -----END PRIVATE KEY-----
52 `
53
54
55
56 const pkcs1v15Pub = `-----BEGIN PUBLIC KEY-----
57 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKCxC+eynecPG+SwpUjPuZiW1WI+BqBV
58 z/xsp35Opg4+2gDWFgJFO+MZI89AV9jatCE/Q8sViPGl2fAekWLW7D8CAwEAAQ==
59 -----END PUBLIC KEY-----
60 `
61
62
63
64
65 const priv = `-----BEGIN PRIVATE KEY-----
66 MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmrLtCpBdXgXLUr7o
67 nSUPfo3oXMjmvuwTOjpTulIBKlKhRANCAATH6KSpTFe6uXFmW1qNEFXaO7fWPfZt
68 pPZrHZ1cFykidZoURKoYXfkohJ+U/USYy8Sd8b4DMd5xDRZCnlDM0h37
69 -----END PRIVATE KEY-----
70 `
71
72
73
74 const pubStr = `-----BEGIN PUBLIC KEY-----
75 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEx+ikqUxXurlxZltajRBV2ju31j32
76 baT2ax2dXBcpInWaFESqGF35KISflP1EmMvEnfG+AzHecQ0WQp5QzNId+w==
77 -----END PUBLIC KEY-----
78 `
79
80
81
82 const ed25519Priv = `-----BEGIN PRIVATE KEY-----
83 MC4CAQAwBQYDK2VwBCIEIKjlXfR/VFvO9qM9+CG2qbuSM54k8ciKWHhgNwKTgqpG
84 -----END PRIVATE KEY-----
85 `
86
87
88
89 const ed25519Pub = `-----BEGIN PUBLIC KEY-----
90 MCowBQYDK2VwAyEAizWek2gKgMM+bad4rVJ5nc9NsbNOba0A0BNfzOgklRs=
91 -----END PUBLIC KEY-----
92 `
93
94 const pubWithTrailingNewLine = `-----BEGIN PUBLIC KEY-----
95 MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEx+ikqUxXurlxZltajRBV2ju31j32
96 baT2ax2dXBcpInWaFESqGF35KISflP1EmMvEnfG+AzHecQ0WQp5QzNId+w==
97 -----END PUBLIC KEY-----
98
99 `
100
101 func signData(t *testing.T, b []byte, pkey string) []byte {
102
103 priv, err := cryptoutils.UnmarshalPEMToPrivateKey([]byte(pkey), cryptoutils.SkipPassword)
104 if err != nil {
105 t.Fatal(err)
106 }
107 signer, err := signature.LoadSigner(priv, crypto.SHA256)
108 if err != nil {
109 t.Fatal(err)
110 }
111
112 signature, err := signer.SignMessage(bytes.NewReader(b))
113 if err != nil {
114 t.Fatal(err)
115 }
116 return signature
117 }
118
119 func TestSignature_Verify(t *testing.T) {
120 tests := []struct {
121 name string
122 priv string
123 pub string
124 }{
125 {
126 name: "rsa",
127 priv: pkcs1v15Priv,
128 pub: pkcs1v15Pub,
129 },
130 {
131 name: "ec",
132 priv: priv,
133 pub: pubStr,
134 },
135 {
136 name: "ed25519",
137 priv: ed25519Priv,
138 pub: ed25519Pub,
139 },
140 }
141 for _, tt := range tests {
142 t.Run(tt.name, func(t *testing.T) {
143 data := []byte("hey! this is my test data")
144 sigBytes := signData(t, data, tt.priv)
145 s, err := NewSignature(bytes.NewReader(sigBytes))
146 if err != nil {
147 t.Fatal(err)
148 }
149
150 pub, err := NewPublicKey(strings.NewReader(tt.pub))
151 if err != nil {
152 t.Fatal(err)
153 }
154
155 if err := s.Verify(bytes.NewReader(data), pub); err != nil {
156 t.Errorf("Signature.Verify() error = %v", err)
157 }
158
159
160 cb, err := s.CanonicalValue()
161 if err != nil {
162 t.Error(err)
163 }
164 canonicalSig, err := NewSignature(bytes.NewReader(cb))
165 if err != nil {
166 t.Error(err)
167 }
168 if err := canonicalSig.Verify(bytes.NewReader(data), pub); err != nil {
169 t.Errorf("Signature.Verify() error = %v", err)
170 }
171
172 pubKey, _ := cryptoutils.UnmarshalPEMToPublicKey([]byte(tt.pub))
173 derKey, _ := cryptoutils.MarshalPublicKeyToDER(pubKey)
174 digest := sha256.Sum256(derKey)
175 expectedID := identity.Identity{Crypto: pubKey, Raw: derKey, Fingerprint: hex.EncodeToString(digest[:])}
176 ids, err := pub.Identities()
177 if err != nil {
178 t.Fatal(err)
179 }
180 if len(ids) != 1 {
181 t.Errorf("%v: too many identities, expected 1, got %v", tt.name, len(ids))
182 }
183 switch v := ids[0].Crypto.(type) {
184 case *rsa.PublicKey:
185 if tt.name != "rsa" {
186 t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v))
187 }
188 case *ecdsa.PublicKey:
189 if tt.name != "ec" {
190 t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v))
191 }
192 case ed25519.PublicKey:
193 if tt.name != "ed25519" {
194 t.Fatalf("unexpected key, expected RSA, got %v", reflect.TypeOf(v))
195 }
196 default:
197 t.Fatalf("unexpected key type, got %v", reflect.TypeOf(v))
198 }
199 if err := cryptoutils.EqualKeys(expectedID.Crypto, ids[0].Crypto); err != nil {
200 t.Errorf("%v: public keys did not match: %v", tt.name, err)
201 }
202 if !reflect.DeepEqual(expectedID.Raw, ids[0].Raw) {
203 t.Errorf("%v: raw identities did not match, expected %v, got %v", tt.name, expectedID.Raw, ids[0].Raw)
204 }
205 if expectedID.Fingerprint != ids[0].Fingerprint {
206 t.Errorf("%v: fingerprints did not match, expected %v, got %v", tt.name, expectedID.Fingerprint, ids[0].Fingerprint)
207 }
208 })
209 }
210 }
211
212 func TestSignature_VerifyFail(t *testing.T) {
213 tests := []struct {
214 name string
215 priv string
216 pub string
217 }{
218 {
219 name: "rsa",
220 priv: pkcs1v15Priv,
221 pub: pkcs1v15Pub,
222 },
223 {
224 name: "ec",
225 priv: priv,
226 pub: pubStr,
227 },
228 {
229 name: "ed25519",
230 priv: ed25519Priv,
231 pub: ed25519Pub,
232 },
233 }
234 for _, tt := range tests {
235 t.Run(tt.name, func(t *testing.T) {
236
237 data := []byte("hey! this is my test data")
238 sigBytes := signData(t, data, tt.priv)
239 sigBytes[0]--
240 s, err := NewSignature(bytes.NewReader(sigBytes))
241 if err != nil {
242 t.Fatal(err)
243 }
244
245 pub, err := NewPublicKey(strings.NewReader(tt.pub))
246 if err != nil {
247 t.Fatal(err)
248 }
249
250 if err := s.Verify(bytes.NewReader(data), pub); err == nil {
251 t.Error("Signature.Verify() expected error!")
252 }
253 })
254 }
255 }
256
257 func TestPublicKeyWithCertChain(t *testing.T) {
258 rootCert, rootKey, _ := testutils.GenerateRootCa()
259 subCert, subKey, _ := testutils.GenerateSubordinateCa(rootCert, rootKey)
260 subjectURL, _ := url.Parse("https://github.com/slsa-framework/slsa-github-generator/.github/workflows/builder_go_slsa3.yml@refs/tags/v1.1.1")
261 leafCert, leafKey, _ := testutils.GenerateLeafCertWithSubjectAlternateNames(
262 []string{"example.com"}, []string{"subject@example.com"}, []net.IP{{1, 1, 1, 1}}, []*url.URL{subjectURL}, "oidc-issuer", subCert, subKey)
263
264 pemCertChain, err := cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{leafCert, subCert, rootCert})
265 if err != nil {
266 t.Fatalf("unexpected error marshalling certificate chain: %v", err)
267 }
268
269 pub, err := NewPublicKey(bytes.NewReader(pemCertChain))
270 if err != nil {
271 t.Fatalf("unexpected error generating public key: %v", err)
272 }
273 if pub.certs == nil || !pub.certs[0].Equal(leafCert) || !pub.certs[1].Equal(subCert) || !pub.certs[2].Equal(rootCert) {
274 t.Fatal("expected certificate chain to match provided certificate chain")
275 }
276
277 if !pub.CryptoPubKey().(*ecdsa.PublicKey).Equal(leafKey.Public()) {
278 t.Fatal("expected public keys to match")
279 }
280
281 if !reflect.DeepEqual(pub.EmailAddresses(), leafCert.EmailAddresses) {
282 t.Fatalf("expected matching subjects, expected %v, got %v", leafCert.EmailAddresses, pub.EmailAddresses())
283 }
284
285 var expectedSubjects []string
286 expectedSubjects = append(expectedSubjects, leafCert.DNSNames...)
287 expectedSubjects = append(expectedSubjects, leafCert.EmailAddresses...)
288 expectedSubjects = append(expectedSubjects, leafCert.IPAddresses[0].String())
289 expectedSubjects = append(expectedSubjects, leafCert.URIs[0].String())
290 if !reflect.DeepEqual(pub.Subjects(), expectedSubjects) {
291 t.Fatalf("expected matching subjects, expected %v, got %v", expectedSubjects, pub.Subjects())
292 }
293
294 digest := sha256.Sum256(leafCert.Raw)
295 expectedID := identity.Identity{Crypto: leafCert, Raw: leafCert.Raw, Fingerprint: hex.EncodeToString((digest[:]))}
296 ids, err := pub.Identities()
297 if err != nil {
298 t.Fatal(err)
299 }
300 if len(ids) != 1 {
301 t.Errorf("too many identities, expected 1, got %v", len(ids))
302 }
303 if !ids[0].Crypto.(*x509.Certificate).Equal(expectedID.Crypto.(*x509.Certificate)) {
304 t.Errorf("certificates did not match")
305 }
306 if !reflect.DeepEqual(expectedID.Raw, ids[0].Raw) {
307 t.Errorf("raw identities did not match, expected %v, got %v", expectedID.Raw, ids[0].Raw)
308 }
309 if expectedID.Fingerprint != ids[0].Fingerprint {
310 t.Errorf("fingerprints did not match, expected %v, got %v", expectedID.Fingerprint, ids[0].Fingerprint)
311 }
312
313 canonicalValue, err := pub.CanonicalValue()
314 if err != nil {
315 t.Fatalf("unexpected error fetching canonical value: %v", err)
316 }
317 if !reflect.DeepEqual(canonicalValue, pemCertChain) {
318 t.Fatalf("expected canonical value %v, got %v", pemCertChain, canonicalValue)
319 }
320
321
322 data := []byte("test")
323 signer, err := signature.LoadSigner(leafKey, crypto.SHA256)
324 if err != nil {
325 t.Fatal(err)
326 }
327 sigBytes, err := signer.SignMessage(bytes.NewReader(data))
328 if err != nil {
329 t.Fatal(err)
330 }
331 s, err := NewSignature(bytes.NewReader(sigBytes))
332 if err != nil {
333 t.Fatalf("unexpected error generating signature: %v", err)
334 }
335 err = s.Verify(bytes.NewReader(data), pub)
336 if err != nil {
337 t.Fatalf("unexpected error verifying signature, %v", err)
338 }
339
340
341 leafCert, leafKey, _ = testutils.GenerateExpiredLeafCert("subject@example.com", "oidc-issuer", subCert, subKey)
342 pemCertChain, _ = cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{leafCert, subCert, rootCert})
343 pub, _ = NewPublicKey(bytes.NewReader(pemCertChain))
344 signer, _ = signature.LoadSigner(leafKey, crypto.SHA256)
345 sigBytes, _ = signer.SignMessage(bytes.NewReader(data))
346 s, _ = NewSignature(bytes.NewReader(sigBytes))
347 err = s.Verify(bytes.NewReader(data), pub)
348 if err != nil {
349 t.Fatalf("unexpected error verifying signature with expired certificate: %v", err)
350 }
351
352
353 pemCertChain, _ = cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{leafCert, rootCert})
354 pub, _ = NewPublicKey(bytes.NewReader(pemCertChain))
355 signer, _ = signature.LoadSigner(leafKey, crypto.SHA256)
356 sigBytes, _ = signer.SignMessage(bytes.NewReader(data))
357 s, _ = NewSignature(bytes.NewReader(sigBytes))
358 err = s.Verify(bytes.NewReader(data), pub)
359 if err == nil || !strings.Contains(err.Error(), "x509: certificate signed by unknown authority") {
360 t.Fatalf("expected error verifying signature, got %v", err)
361 }
362
363
364 leafCert, leafKey, _ = testutils.GenerateLeafCert("subject@example.com", "oidc-issuer", nil, rootCert, rootKey)
365 pemCertChain, _ = cryptoutils.MarshalCertificatesToPEM([]*x509.Certificate{leafCert, rootCert})
366 pub, _ = NewPublicKey(bytes.NewReader(pemCertChain))
367 signer, _ = signature.LoadSigner(leafKey, crypto.SHA256)
368 sigBytes, _ = signer.SignMessage(bytes.NewReader(data))
369 s, _ = NewSignature(bytes.NewReader(sigBytes))
370 err = s.Verify(bytes.NewReader(data), pub)
371 if err != nil {
372 t.Fatalf("unexpected error verifying signature, %v", err)
373 }
374
375
376 chain := []*x509.Certificate{}
377 for i := 0; i < 11; i++ {
378 chain = append(chain, leafCert)
379 }
380 pemCertChain, _ = cryptoutils.MarshalCertificatesToPEM(chain)
381 _, err = NewPublicKey(bytes.NewReader(pemCertChain))
382 if err == nil || !strings.Contains(err.Error(), "too many certificates specified in PEM block") {
383 t.Fatalf("expected error with long certificate chain, got %v", err)
384 }
385
386
387 key, err := NewPublicKey(strings.NewReader(pubWithTrailingNewLine))
388 if err != nil {
389 t.Fatalf("unexpected error parsing public key with extra trailing newline: %v", err)
390 }
391 canonicalKeyBytes, err := key.CanonicalValue()
392 if err != nil {
393 t.Fatalf("unexpected error canonicalizing public key with extra trailing newline: %v", err)
394 }
395
396 if !bytes.Equal([]byte(pubStr), canonicalKeyBytes) {
397 t.Fatalf("expected canonical value to match original without extra trailing new line")
398 }
399 }
400
View as plain text