]> Cypherpunks.ru repositories - gostls13.git/blob - src/crypto/tls/boring_test.go
[dev.boringcrypto] misc/boring: add go1.9.2b4 release
[gostls13.git] / src / crypto / tls / boring_test.go
1 // Copyright 2017 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package tls
6
7 import (
8         "crypto/ecdsa"
9         "crypto/elliptic"
10         "crypto/internal/boring/fipstls"
11         "crypto/rand"
12         "crypto/rsa"
13         "crypto/x509"
14         "crypto/x509/pkix"
15         "fmt"
16         "math/big"
17         "net"
18         "runtime"
19         "strings"
20         "testing"
21         "time"
22 )
23
24 func TestBoringServerProtocolVersion(t *testing.T) {
25         test := func(name string, v uint16, msg string) {
26                 t.Run(name, func(t *testing.T) {
27                         serverConfig := testConfig.Clone()
28                         serverConfig.MinVersion = VersionSSL30
29                         clientHello := &clientHelloMsg{
30                                 vers:               v,
31                                 cipherSuites:       allCipherSuites(),
32                                 compressionMethods: []uint8{compressionNone},
33                         }
34                         testClientHelloFailure(t, serverConfig, clientHello, msg)
35                 })
36         }
37
38         test("VersionSSL30", VersionSSL30, "")
39         test("VersionTLS10", VersionTLS10, "")
40         test("VersionTLS11", VersionTLS11, "")
41         test("VersionTLS12", VersionTLS12, "")
42
43         fipstls.Force()
44         defer fipstls.Abandon()
45         test("VersionSSL30", VersionSSL30, "unsupported, maximum protocol version")
46         test("VersionTLS10", VersionTLS10, "unsupported, maximum protocol version")
47         test("VersionTLS11", VersionTLS11, "unsupported, maximum protocol version")
48         test("VersionTLS12", VersionTLS12, "")
49 }
50
51 func isBoringCipherSuite(id uint16) bool {
52         switch id {
53         case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
54                 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
55                 TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
56                 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
57                 TLS_RSA_WITH_AES_128_GCM_SHA256,
58                 TLS_RSA_WITH_AES_256_GCM_SHA384:
59                 return true
60         }
61         return false
62 }
63
64 func isBoringCurve(id CurveID) bool {
65         switch id {
66         case CurveP256, CurveP384, CurveP521:
67                 return true
68         }
69         return false
70 }
71
72 func isECDSA(id uint16) bool {
73         for _, suite := range cipherSuites {
74                 if suite.id == id {
75                         return suite.flags&suiteECDSA == suiteECDSA
76                 }
77         }
78         panic(fmt.Sprintf("unknown cipher suite %#x", id))
79 }
80
81 func isBoringSignatureAndHash(sigHash signatureAndHash) bool {
82         switch sigHash.signature {
83         default:
84                 return false
85         case signatureRSA,
86                 signatureECDSA:
87                 // ok
88         }
89         switch sigHash.hash {
90         default:
91                 return false
92         case hashSHA256,
93                 hashSHA384:
94                 // ok
95         }
96         return true
97 }
98
99 func TestBoringServerCipherSuites(t *testing.T) {
100         serverConfig := testConfig.Clone()
101         serverConfig.CipherSuites = allCipherSuites()
102         serverConfig.Certificates = make([]Certificate, 1)
103
104         for _, id := range allCipherSuites() {
105                 if isECDSA(id) {
106                         serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
107                         serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
108                 } else {
109                         serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
110                         serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
111                 }
112                 serverConfig.BuildNameToCertificate()
113                 t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
114                         clientHello := &clientHelloMsg{
115                                 vers:               VersionTLS12,
116                                 cipherSuites:       []uint16{id},
117                                 compressionMethods: []uint8{compressionNone},
118                                 supportedCurves:    defaultCurvePreferences,
119                                 supportedPoints:    []uint8{pointFormatUncompressed},
120                         }
121
122                         testClientHello(t, serverConfig, clientHello)
123                         t.Run("fipstls", func(t *testing.T) {
124                                 fipstls.Force()
125                                 defer fipstls.Abandon()
126                                 msg := ""
127                                 if !isBoringCipherSuite(id) {
128                                         msg = "no cipher suite supported by both client and server"
129                                 }
130                                 testClientHelloFailure(t, serverConfig, clientHello, msg)
131                         })
132                 })
133         }
134 }
135
136 func TestBoringServerCurves(t *testing.T) {
137         serverConfig := testConfig.Clone()
138         serverConfig.Certificates = make([]Certificate, 1)
139         serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
140         serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
141         serverConfig.BuildNameToCertificate()
142
143         for _, curveid := range defaultCurvePreferences {
144                 t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) {
145                         clientHello := &clientHelloMsg{
146                                 vers:               VersionTLS12,
147                                 cipherSuites:       []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
148                                 compressionMethods: []uint8{compressionNone},
149                                 supportedCurves:    []CurveID{curveid},
150                                 supportedPoints:    []uint8{pointFormatUncompressed},
151                         }
152
153                         testClientHello(t, serverConfig, clientHello)
154
155                         // With fipstls forced, bad curves should be rejected.
156                         t.Run("fipstls", func(t *testing.T) {
157                                 fipstls.Force()
158                                 defer fipstls.Abandon()
159                                 msg := ""
160                                 if !isBoringCurve(curveid) {
161                                         msg = "no cipher suite supported by both client and server"
162                                 }
163                                 testClientHelloFailure(t, serverConfig, clientHello, msg)
164                         })
165                 })
166         }
167 }
168
169 func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) {
170         c, s := realNetPipe(t)
171         client := Client(c, clientConfig)
172         server := Server(s, serverConfig)
173         done := make(chan error, 1)
174         go func() {
175                 done <- client.Handshake()
176                 c.Close()
177         }()
178         serverErr = server.Handshake()
179         s.Close()
180         clientErr = <-done
181         return
182 }
183
184 func TestBoringServerSignatureAndHash(t *testing.T) {
185         serverConfig := testConfig.Clone()
186         serverConfig.Certificates = make([]Certificate, 1)
187
188         defer func() {
189                 testingOnlyForceClientHelloSignatureAndHashes = nil
190         }()
191
192         for _, sigHash := range defaultSupportedSignatureAlgorithms {
193                 testingOnlyForceClientHelloSignatureAndHashes = []signatureAndHash{sigHash}
194
195                 t.Run(fmt.Sprintf("%v", sigHash), func(t *testing.T) {
196                         if sigHash.signature == signatureRSA {
197                                 serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
198                                 serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
199                                 serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
200                         } else {
201                                 serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
202                                 serverConfig.Certificates = make([]Certificate, 1)
203                                 serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
204                                 serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
205                         }
206                         serverConfig.BuildNameToCertificate()
207
208                         clientErr, _ := boringHandshake(t, testConfig, serverConfig)
209                         if clientErr != nil {
210                                 t.Fatalf("expected handshake with %v to succeed; err=%v", sigHash, clientErr)
211                         }
212
213                         // With fipstls forced, bad curves should be rejected.
214                         t.Run("fipstls", func(t *testing.T) {
215                                 fipstls.Force()
216                                 defer fipstls.Abandon()
217                                 clientErr, _ := boringHandshake(t, testConfig, serverConfig)
218                                 if isBoringSignatureAndHash(sigHash) {
219                                         if clientErr != nil {
220                                                 t.Fatalf("expected handshake with %v to succeed; err=%v", sigHash, clientErr)
221                                         }
222                                 } else {
223                                         if clientErr == nil {
224                                                 t.Fatalf("expected handshake with %v to fail, but it succeeded", sigHash)
225                                         }
226                                 }
227                         })
228                 })
229         }
230 }
231
232 func TestBoringClientHello(t *testing.T) {
233         // Test that no matter what we put in the client config,
234         // the client does not offer non-FIPS configurations.
235         fipstls.Force()
236         defer fipstls.Abandon()
237
238         c, s := net.Pipe()
239         defer c.Close()
240         defer s.Close()
241
242         clientConfig := testConfig.Clone()
243         // All sorts of traps for the client to avoid.
244         clientConfig.MinVersion = VersionSSL30
245         clientConfig.CipherSuites = allCipherSuites()
246         clientConfig.CurvePreferences = defaultCurvePreferences
247
248         go Client(c, testConfig).Handshake()
249         srv := Server(s, testConfig)
250         msg, err := srv.readHandshake()
251         if err != nil {
252                 t.Fatal(err)
253         }
254         hello, ok := msg.(*clientHelloMsg)
255         if !ok {
256                 t.Fatalf("unexpected message type %T", msg)
257         }
258
259         if hello.vers != VersionTLS12 {
260                 t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
261         }
262         for _, id := range hello.cipherSuites {
263                 if !isBoringCipherSuite(id) {
264                         t.Errorf("client offered disallowed suite %#x", id)
265                 }
266         }
267         for _, id := range hello.supportedCurves {
268                 if !isBoringCurve(id) {
269                         t.Errorf("client offered disallowed curve %d", id)
270                 }
271         }
272         for _, sigHash := range hello.signatureAndHashes {
273                 if !isBoringSignatureAndHash(sigHash) {
274                         t.Errorf("client offered disallowed signature-and-hash %v", sigHash)
275                 }
276         }
277 }
278
279 func TestBoringCertAlgs(t *testing.T) {
280         // NaCl and arm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those.
281         if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" {
282                 t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH)
283         }
284
285         // Set up some roots, intermediate CAs, and leaf certs with various algorithms.
286         // X_Y is X signed by Y.
287         R1 := boringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
288         R2 := boringCert(t, "R2", boringRSAKey(t, 4096), nil, boringCertCA)
289
290         M1_R1 := boringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
291         M2_R1 := boringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA)
292
293         I_R1 := boringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK)
294         I_R2 := boringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK)
295         I_M1 := boringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK)
296         I_M2 := boringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK)
297
298         L1_I := boringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK)
299         L2_I := boringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf)
300
301         // boringCert checked that isBoringCertificate matches the caller's boringCertFIPSOK bit.
302         // If not, no point in building bigger end-to-end tests.
303         if t.Failed() {
304                 t.Fatalf("isBoringCertificate failures; not continuing")
305         }
306
307         // client verifying server cert
308         testServerCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
309                 clientConfig := testConfig.Clone()
310                 clientConfig.RootCAs = pool
311                 clientConfig.InsecureSkipVerify = false
312                 clientConfig.ServerName = "example.com"
313
314                 serverConfig := testConfig.Clone()
315                 serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
316                 serverConfig.BuildNameToCertificate()
317
318                 clientErr, _ := boringHandshake(t, clientConfig, serverConfig)
319
320                 if (clientErr == nil) == ok {
321                         if ok {
322                                 t.Logf("%s: accept", desc)
323                         } else {
324                                 t.Logf("%s: reject", desc)
325                         }
326                 } else {
327                         if ok {
328                                 t.Errorf("%s: BAD reject (%v)", desc, clientErr)
329                         } else {
330                                 t.Errorf("%s: BAD accept", desc)
331                         }
332                 }
333         }
334
335         // server verifying client cert
336         testClientCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
337                 clientConfig := testConfig.Clone()
338                 clientConfig.ServerName = "example.com"
339                 clientConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
340
341                 serverConfig := testConfig.Clone()
342                 serverConfig.ClientCAs = pool
343                 serverConfig.ClientAuth = RequireAndVerifyClientCert
344
345                 _, serverErr := boringHandshake(t, clientConfig, serverConfig)
346
347                 if (serverErr == nil) == ok {
348                         if ok {
349                                 t.Logf("%s: accept", desc)
350                         } else {
351                                 t.Logf("%s: reject", desc)
352                         }
353                 } else {
354                         if ok {
355                                 t.Errorf("%s: BAD reject (%v)", desc, serverErr)
356                         } else {
357                                 t.Errorf("%s: BAD accept", desc)
358                         }
359                 }
360         }
361
362         // Run simple basic test with known answers before proceeding to
363         // exhaustive test with computed answers.
364         r1pool := x509.NewCertPool()
365         r1pool.AddCert(R1.cert)
366         testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
367         testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
368         fipstls.Force()
369         testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
370         testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
371         fipstls.Abandon()
372
373         if t.Failed() {
374                 t.Fatal("basic test failed, skipping exhaustive test")
375         }
376
377         if testing.Short() {
378                 t.Logf("basic test passed; skipping exhaustive test in -short mode")
379                 return
380         }
381
382         for l := 1; l <= 2; l++ {
383                 leaf := L1_I
384                 if l == 2 {
385                         leaf = L2_I
386                 }
387                 for i := 0; i < 64; i++ {
388                         reachable := map[string]bool{leaf.parentOrg: true}
389                         reachableFIPS := map[string]bool{leaf.parentOrg: leaf.fipsOK}
390                         list := [][]byte{leaf.der}
391                         listName := leaf.name
392                         addList := func(cond int, c *boringCertificate) {
393                                 if cond != 0 {
394                                         list = append(list, c.der)
395                                         listName += "," + c.name
396                                         if reachable[c.org] {
397                                                 reachable[c.parentOrg] = true
398                                         }
399                                         if reachableFIPS[c.org] && c.fipsOK {
400                                                 reachableFIPS[c.parentOrg] = true
401                                         }
402                                 }
403                         }
404                         addList(i&1, I_R1)
405                         addList(i&2, I_R2)
406                         addList(i&4, I_M1)
407                         addList(i&8, I_M2)
408                         addList(i&16, M1_R1)
409                         addList(i&32, M2_R1)
410
411                         for r := 1; r <= 3; r++ {
412                                 pool := x509.NewCertPool()
413                                 rootName := ","
414                                 shouldVerify := false
415                                 shouldVerifyFIPS := false
416                                 addRoot := func(cond int, c *boringCertificate) {
417                                         if cond != 0 {
418                                                 rootName += "," + c.name
419                                                 pool.AddCert(c.cert)
420                                                 if reachable[c.org] {
421                                                         shouldVerify = true
422                                                 }
423                                                 if reachableFIPS[c.org] && c.fipsOK {
424                                                         shouldVerifyFIPS = true
425                                                 }
426                                         }
427                                 }
428                                 addRoot(r&1, R1)
429                                 addRoot(r&2, R2)
430                                 rootName = rootName[1:] // strip leading comma
431                                 testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify)
432                                 testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify)
433                                 fipstls.Force()
434                                 testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS)
435                                 testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS)
436                                 fipstls.Abandon()
437                         }
438                 }
439         }
440 }
441
442 const (
443         boringCertCA = iota
444         boringCertLeaf
445         boringCertFIPSOK = 0x80
446 )
447
448 func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
449         k, err := rsa.GenerateKey(rand.Reader, size)
450         if err != nil {
451                 t.Fatal(err)
452         }
453         return k
454 }
455
456 func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
457         k, err := ecdsa.GenerateKey(curve, rand.Reader)
458         if err != nil {
459                 t.Fatal(err)
460         }
461         return k
462 }
463
464 type boringCertificate struct {
465         name      string
466         org       string
467         parentOrg string
468         der       []byte
469         cert      *x509.Certificate
470         key       interface{}
471         fipsOK    bool
472 }
473
474 func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
475         org := name
476         parentOrg := ""
477         if i := strings.Index(org, "_"); i >= 0 {
478                 org = org[:i]
479                 parentOrg = name[i+1:]
480         }
481         tmpl := &x509.Certificate{
482                 SerialNumber: big.NewInt(1),
483                 Subject: pkix.Name{
484                         Organization: []string{org},
485                 },
486                 NotBefore: time.Unix(0, 0),
487                 NotAfter:  time.Unix(0, 0),
488
489                 KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
490                 ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
491                 BasicConstraintsValid: true,
492         }
493         if mode&^boringCertFIPSOK == boringCertLeaf {
494                 tmpl.DNSNames = []string{"example.com"}
495         } else {
496                 tmpl.IsCA = true
497                 tmpl.KeyUsage |= x509.KeyUsageCertSign
498         }
499
500         var pcert *x509.Certificate
501         var pkey interface{}
502         if parent != nil {
503                 pcert = parent.cert
504                 pkey = parent.key
505         } else {
506                 pcert = tmpl
507                 pkey = key
508         }
509
510         var pub interface{}
511         var desc string
512         switch k := key.(type) {
513         case *rsa.PrivateKey:
514                 pub = &k.PublicKey
515                 desc = fmt.Sprintf("RSA-%d", k.N.BitLen())
516         case *ecdsa.PrivateKey:
517                 pub = &k.PublicKey
518                 desc = "ECDSA-" + k.Curve.Params().Name
519         default:
520                 t.Fatalf("invalid key %T", key)
521         }
522
523         der, err := x509.CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
524         if err != nil {
525                 t.Fatal(err)
526         }
527         cert, err := x509.ParseCertificate(der)
528         if err != nil {
529                 t.Fatal(err)
530         }
531
532         // Tell isBoringCertificate to enforce FIPS restrictions for this check.
533         fipstls.Force()
534         defer fipstls.Abandon()
535
536         fipsOK := mode&boringCertFIPSOK != 0
537         if isBoringCertificate(cert) != fipsOK {
538                 t.Errorf("isBoringCertificate(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK)
539         }
540         return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
541 }
542
543 func boringPool(t *testing.T, list ...*boringCertificate) *x509.CertPool {
544         pool := x509.NewCertPool()
545         for _, c := range list {
546                 cert, err := x509.ParseCertificate(c.der)
547                 if err != nil {
548                         t.Fatal(err)
549                 }
550                 pool.AddCert(cert)
551         }
552         return pool
553 }
554
555 func boringList(t *testing.T, list ...*boringCertificate) [][]byte {
556         var all [][]byte
557         for _, c := range list {
558                 all = append(all, c.der)
559         }
560         return all
561 }
562
563 // realNetPipe is like net.Pipe but returns an actual network socket pair,
564 // which has buffering that avoids various deadlocks if both sides
565 // try to speak at the same time.
566 func realNetPipe(t *testing.T) (net.Conn, net.Conn) {
567         l := newLocalListener(t)
568         defer l.Close()
569         c, err := net.Dial("tcp", l.Addr().String())
570         if err != nil {
571                 t.Fatal(err)
572         }
573         s, err := l.Accept()
574         if err != nil {
575                 c.Close()
576                 t.Fatal(err)
577         }
578         return c, s
579 }