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.
10 "crypto/internal/boring/fipstls"
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{
31 cipherSuites: allCipherSuites(),
32 compressionMethods: []uint8{compressionNone},
34 testClientHelloFailure(t, serverConfig, clientHello, msg)
38 test("VersionSSL30", VersionSSL30, "")
39 test("VersionTLS10", VersionTLS10, "")
40 test("VersionTLS11", VersionTLS11, "")
41 test("VersionTLS12", VersionTLS12, "")
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, "")
51 func isBoringCipherSuite(id uint16) bool {
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:
64 func isBoringCurve(id CurveID) bool {
66 case CurveP256, CurveP384, CurveP521:
72 func isECDSA(id uint16) bool {
73 for _, suite := range cipherSuites {
75 return suite.flags&suiteECDSA == suiteECDSA
78 panic(fmt.Sprintf("unknown cipher suite %#x", id))
81 func isBoringSignatureAndHash(sigHash signatureAndHash) bool {
82 switch sigHash.signature {
99 func TestBoringServerCipherSuites(t *testing.T) {
100 serverConfig := testConfig.Clone()
101 serverConfig.CipherSuites = allCipherSuites()
102 serverConfig.Certificates = make([]Certificate, 1)
104 for _, id := range allCipherSuites() {
106 serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
107 serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
109 serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
110 serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
112 serverConfig.BuildNameToCertificate()
113 t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
114 clientHello := &clientHelloMsg{
116 cipherSuites: []uint16{id},
117 compressionMethods: []uint8{compressionNone},
118 supportedCurves: defaultCurvePreferences,
119 supportedPoints: []uint8{pointFormatUncompressed},
122 testClientHello(t, serverConfig, clientHello)
123 t.Run("fipstls", func(t *testing.T) {
125 defer fipstls.Abandon()
127 if !isBoringCipherSuite(id) {
128 msg = "no cipher suite supported by both client and server"
130 testClientHelloFailure(t, serverConfig, clientHello, msg)
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()
143 for _, curveid := range defaultCurvePreferences {
144 t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) {
145 clientHello := &clientHelloMsg{
147 cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
148 compressionMethods: []uint8{compressionNone},
149 supportedCurves: []CurveID{curveid},
150 supportedPoints: []uint8{pointFormatUncompressed},
153 testClientHello(t, serverConfig, clientHello)
155 // With fipstls forced, bad curves should be rejected.
156 t.Run("fipstls", func(t *testing.T) {
158 defer fipstls.Abandon()
160 if !isBoringCurve(curveid) {
161 msg = "no cipher suite supported by both client and server"
163 testClientHelloFailure(t, serverConfig, clientHello, msg)
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)
175 done <- client.Handshake()
178 serverErr = server.Handshake()
184 func TestBoringServerSignatureAndHash(t *testing.T) {
185 serverConfig := testConfig.Clone()
186 serverConfig.Certificates = make([]Certificate, 1)
189 testingOnlyForceClientHelloSignatureAndHashes = nil
192 for _, sigHash := range defaultSupportedSignatureAlgorithms {
193 testingOnlyForceClientHelloSignatureAndHashes = []signatureAndHash{sigHash}
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
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
206 serverConfig.BuildNameToCertificate()
208 clientErr, _ := boringHandshake(t, testConfig, serverConfig)
209 if clientErr != nil {
210 t.Fatalf("expected handshake with %v to succeed; err=%v", sigHash, clientErr)
213 // With fipstls forced, bad curves should be rejected.
214 t.Run("fipstls", func(t *testing.T) {
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)
223 if clientErr == nil {
224 t.Fatalf("expected handshake with %v to fail, but it succeeded", sigHash)
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.
236 defer fipstls.Abandon()
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
248 go Client(c, testConfig).Handshake()
249 srv := Server(s, testConfig)
250 msg, err := srv.readHandshake()
254 hello, ok := msg.(*clientHelloMsg)
256 t.Fatalf("unexpected message type %T", msg)
259 if hello.vers != VersionTLS12 {
260 t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
262 for _, id := range hello.cipherSuites {
263 if !isBoringCipherSuite(id) {
264 t.Errorf("client offered disallowed suite %#x", id)
267 for _, id := range hello.supportedCurves {
268 if !isBoringCurve(id) {
269 t.Errorf("client offered disallowed curve %d", id)
272 for _, sigHash := range hello.signatureAndHashes {
273 if !isBoringSignatureAndHash(sigHash) {
274 t.Errorf("client offered disallowed signature-and-hash %v", sigHash)
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)
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)
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)
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)
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)
301 // boringCert checked that isBoringCertificate matches the caller's boringCertFIPSOK bit.
302 // If not, no point in building bigger end-to-end tests.
304 t.Fatalf("isBoringCertificate failures; not continuing")
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"
314 serverConfig := testConfig.Clone()
315 serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
316 serverConfig.BuildNameToCertificate()
318 clientErr, _ := boringHandshake(t, clientConfig, serverConfig)
320 if (clientErr == nil) == ok {
322 t.Logf("%s: accept", desc)
324 t.Logf("%s: reject", desc)
328 t.Errorf("%s: BAD reject (%v)", desc, clientErr)
330 t.Errorf("%s: BAD accept", desc)
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}}
341 serverConfig := testConfig.Clone()
342 serverConfig.ClientCAs = pool
343 serverConfig.ClientAuth = RequireAndVerifyClientCert
345 _, serverErr := boringHandshake(t, clientConfig, serverConfig)
347 if (serverErr == nil) == ok {
349 t.Logf("%s: accept", desc)
351 t.Logf("%s: reject", desc)
355 t.Errorf("%s: BAD reject (%v)", desc, serverErr)
357 t.Errorf("%s: BAD accept", desc)
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)
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)
374 t.Fatal("basic test failed, skipping exhaustive test")
378 t.Logf("basic test passed; skipping exhaustive test in -short mode")
382 for l := 1; l <= 2; l++ {
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) {
394 list = append(list, c.der)
395 listName += "," + c.name
396 if reachable[c.org] {
397 reachable[c.parentOrg] = true
399 if reachableFIPS[c.org] && c.fipsOK {
400 reachableFIPS[c.parentOrg] = true
411 for r := 1; r <= 3; r++ {
412 pool := x509.NewCertPool()
414 shouldVerify := false
415 shouldVerifyFIPS := false
416 addRoot := func(cond int, c *boringCertificate) {
418 rootName += "," + c.name
420 if reachable[c.org] {
423 if reachableFIPS[c.org] && c.fipsOK {
424 shouldVerifyFIPS = true
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)
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)
445 boringCertFIPSOK = 0x80
448 func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
449 k, err := rsa.GenerateKey(rand.Reader, size)
456 func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
457 k, err := ecdsa.GenerateKey(curve, rand.Reader)
464 type boringCertificate struct {
469 cert *x509.Certificate
474 func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
477 if i := strings.Index(org, "_"); i >= 0 {
479 parentOrg = name[i+1:]
481 tmpl := &x509.Certificate{
482 SerialNumber: big.NewInt(1),
484 Organization: []string{org},
486 NotBefore: time.Unix(0, 0),
487 NotAfter: time.Unix(0, 0),
489 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
490 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
491 BasicConstraintsValid: true,
493 if mode&^boringCertFIPSOK == boringCertLeaf {
494 tmpl.DNSNames = []string{"example.com"}
497 tmpl.KeyUsage |= x509.KeyUsageCertSign
500 var pcert *x509.Certificate
512 switch k := key.(type) {
513 case *rsa.PrivateKey:
515 desc = fmt.Sprintf("RSA-%d", k.N.BitLen())
516 case *ecdsa.PrivateKey:
518 desc = "ECDSA-" + k.Curve.Params().Name
520 t.Fatalf("invalid key %T", key)
523 der, err := x509.CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
527 cert, err := x509.ParseCertificate(der)
532 // Tell isBoringCertificate to enforce FIPS restrictions for this check.
534 defer fipstls.Abandon()
536 fipsOK := mode&boringCertFIPSOK != 0
537 if isBoringCertificate(cert) != fipsOK {
538 t.Errorf("isBoringCertificate(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK)
540 return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
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)
555 func boringList(t *testing.T, list ...*boringCertificate) [][]byte {
557 for _, c := range list {
558 all = append(all, c.der)
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)
569 c, err := net.Dial("tcp", l.Addr().String())