From: Filippo Valsorda Date: Fri, 29 Jun 2018 17:16:42 +0000 (-0400) Subject: [dev.boringcrypto] all: merge master into dev.boringcrypto X-Git-Tag: go1.19beta1~484^2~142 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=77db076129160d50a098958c8e3f3fd5caa6257a;p=gostls13.git [dev.boringcrypto] all: merge master into dev.boringcrypto Add a couple of skips for slow js/wasm tests. Change-Id: Ic95256b1d3c6e5e2f0cc536fad51e914d31cda9e --- 77db076129160d50a098958c8e3f3fd5caa6257a diff --cc src/crypto/aes/cipher.go index fbd01a8f40,bb93fbb36e..db0ee38b78 --- a/src/crypto/aes/cipher.go +++ b/src/crypto/aes/cipher.go @@@ -6,7 -6,7 +6,8 @@@ package ae import ( "crypto/cipher" + "crypto/internal/boring" + "crypto/internal/subtle" "strconv" ) diff --cc src/crypto/aes/cipher_amd64.go index 7efab31065,b12d9b46a2..fd88343cae --- a/src/crypto/aes/cipher_amd64.go +++ b/src/crypto/aes/cipher_amd64.go @@@ -6,7 -6,7 +6,8 @@@ package ae import ( "crypto/cipher" + "crypto/internal/boring" + "crypto/internal/subtle" "internal/cpu" ) diff --cc src/crypto/rsa/boring_test.go index f68dfc9999,0000000000..26fdabb197 mode 100644,000000..100644 --- a/src/crypto/rsa/boring_test.go +++ b/src/crypto/rsa/boring_test.go @@@ -1,127 -1,0 +1,127 @@@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Note: Can run these tests against the non-BoringCrypto +// version of the code by using "CGO_ENABLED=0 go test". + +package rsa + +import ( + "crypto" + "crypto/rand" + "encoding/asn1" + "reflect" + "runtime" + "runtime/debug" + "sync" + "sync/atomic" + "testing" + "unsafe" +) + +func TestBoringASN1Marshal(t *testing.T) { + k, err := GenerateKey(rand.Reader, 128) + if err != nil { + t.Fatal(err) + } + // This used to fail, because of the unexported 'boring' field. + // Now the compiler hides it [sic]. + _, err = asn1.Marshal(k.PublicKey) + if err != nil { + t.Fatal(err) + } +} + +func TestBoringDeepEqual(t *testing.T) { + k, err := GenerateKey(rand.Reader, 128) + if err != nil { + t.Fatal(err) + } + k.boring = nil // probably nil already but just in case + k2 := *k + k2.boring = unsafe.Pointer(k) // anything not nil, for this test + if !reflect.DeepEqual(k, &k2) { + // compiler should be hiding the boring field from reflection + t.Fatalf("DeepEqual compared boring fields") + } +} + +func TestBoringVerify(t *testing.T) { + // This changed behavior and broke golang.org/x/crypto/openpgp. + // Go accepts signatures without leading 0 padding, while BoringCrypto does not. + // So the Go wrappers must adapt. + key := &PublicKey{ + N: bigFromHex("c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be1"), + E: 65537, + } + + hash := fromHex("019c5571724fb5d0e47a4260c940e9803ba05a44") + paddedHash := fromHex("3021300906052b0e03021a05000414019c5571724fb5d0e47a4260c940e9803ba05a44") + + // signature is one byte shorter than key.N. + sig := fromHex("5edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56") + + err := VerifyPKCS1v15(key, 0, paddedHash, sig) + if err != nil { + t.Errorf("raw: %v", err) + } + + err = VerifyPKCS1v15(key, crypto.SHA1, hash, sig) + if err != nil { + t.Errorf("sha1: %v", err) + } +} + +func TestBoringGenerateKey(t *testing.T) { + k, err := GenerateKey(rand.Reader, 2048) // 2048 is smallest size BoringCrypto might kick in for + if err != nil { + t.Fatal(err) + } + + // Non-Boring GenerateKey always sets CRTValues to a non-nil (possibly empty) slice. + if k.Precomputed.CRTValues == nil { + t.Fatalf("GenerateKey: Precomputed.CRTValues = nil") + } +} + +func TestBoringFinalizers(t *testing.T) { - if runtime.GOOS == "nacl" { - // Times out on nacl (without BoringCrypto) ++ if runtime.GOOS == "nacl" || runtime.GOOS == "js" { ++ // Times out on nacl and js/wasm (without BoringCrypto) + // but not clear why - probably consuming rand.Reader too quickly + // and being throttled. Also doesn't really matter. - t.Skip("skipping on nacl") ++ t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH) + } + + k, err := GenerateKey(rand.Reader, 2048) + if err != nil { + t.Fatal(err) + } + + // Run test with GOGC=10, to make bug more likely. + // Without the KeepAlives, the loop usually dies after + // about 30 iterations. + defer debug.SetGCPercent(debug.SetGCPercent(10)) + for n := 0; n < 200; n++ { + // Clear the underlying BoringCrypto object. + atomic.StorePointer(&k.boring, nil) + + // Race to create the underlying BoringCrypto object. + // The ones that lose the race are prime candidates for + // being GC'ed too early if the finalizers are not being + // used correctly. + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + sum := make([]byte, 32) + _, err := SignPKCS1v15(rand.Reader, k, crypto.SHA256, sum) + if err != nil { + panic(err) // usually caused by memory corruption, so hard stop + } + }() + } + wg.Wait() + } +} diff --cc src/crypto/tls/boring_test.go index f31f3f6bc8,0000000000..2ac62a5540 mode 100644,000000..100644 --- a/src/crypto/tls/boring_test.go +++ b/src/crypto/tls/boring_test.go @@@ -1,576 -1,0 +1,576 @@@ +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "crypto/ecdsa" + "crypto/elliptic" + "crypto/internal/boring/fipstls" + "crypto/rand" + "crypto/rsa" + "crypto/x509" + "crypto/x509/pkix" + "fmt" + "math/big" + "net" + "runtime" + "strings" + "testing" + "time" +) + +func TestBoringServerProtocolVersion(t *testing.T) { + test := func(name string, v uint16, msg string) { + t.Run(name, func(t *testing.T) { + serverConfig := testConfig.Clone() + serverConfig.MinVersion = VersionSSL30 + clientHello := &clientHelloMsg{ + vers: v, + cipherSuites: allCipherSuites(), + compressionMethods: []uint8{compressionNone}, + } + testClientHelloFailure(t, serverConfig, clientHello, msg) + }) + } + + test("VersionSSL30", VersionSSL30, "") + test("VersionTLS10", VersionTLS10, "") + test("VersionTLS11", VersionTLS11, "") + test("VersionTLS12", VersionTLS12, "") + + fipstls.Force() + defer fipstls.Abandon() + test("VersionSSL30", VersionSSL30, "unsupported, maximum protocol version") + test("VersionTLS10", VersionTLS10, "unsupported, maximum protocol version") + test("VersionTLS11", VersionTLS11, "unsupported, maximum protocol version") + test("VersionTLS12", VersionTLS12, "") +} + +func isBoringCipherSuite(id uint16) bool { + switch id { + case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + TLS_RSA_WITH_AES_128_GCM_SHA256, + TLS_RSA_WITH_AES_256_GCM_SHA384: + return true + } + return false +} + +func isBoringCurve(id CurveID) bool { + switch id { + case CurveP256, CurveP384, CurveP521: + return true + } + return false +} + +func isECDSA(id uint16) bool { + for _, suite := range cipherSuites { + if suite.id == id { + return suite.flags&suiteECDSA == suiteECDSA + } + } + panic(fmt.Sprintf("unknown cipher suite %#x", id)) +} + +func isBoringSignatureScheme(alg SignatureScheme) bool { + switch alg { + default: + return false + case PKCS1WithSHA256, + ECDSAWithP256AndSHA256, + PKCS1WithSHA384, + ECDSAWithP384AndSHA384, + PKCS1WithSHA512, + ECDSAWithP521AndSHA512: + // ok + } + return true +} + +func TestBoringServerCipherSuites(t *testing.T) { + serverConfig := testConfig.Clone() + serverConfig.CipherSuites = allCipherSuites() + serverConfig.Certificates = make([]Certificate, 1) + + for _, id := range allCipherSuites() { + if isECDSA(id) { + serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} + serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey + } else { + serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate} + serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey + } + serverConfig.BuildNameToCertificate() + t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) { + clientHello := &clientHelloMsg{ + vers: VersionTLS12, + cipherSuites: []uint16{id}, + compressionMethods: []uint8{compressionNone}, + supportedCurves: defaultCurvePreferences, + supportedPoints: []uint8{pointFormatUncompressed}, + } + + testClientHello(t, serverConfig, clientHello) + t.Run("fipstls", func(t *testing.T) { + fipstls.Force() + defer fipstls.Abandon() + msg := "" + if !isBoringCipherSuite(id) { + msg = "no cipher suite supported by both client and server" + } + testClientHelloFailure(t, serverConfig, clientHello, msg) + }) + }) + } +} + +func TestBoringServerCurves(t *testing.T) { + serverConfig := testConfig.Clone() + serverConfig.Certificates = make([]Certificate, 1) + serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} + serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey + serverConfig.BuildNameToCertificate() + + for _, curveid := range defaultCurvePreferences { + t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) { + clientHello := &clientHelloMsg{ + vers: VersionTLS12, + cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}, + compressionMethods: []uint8{compressionNone}, + supportedCurves: []CurveID{curveid}, + supportedPoints: []uint8{pointFormatUncompressed}, + } + + testClientHello(t, serverConfig, clientHello) + + // With fipstls forced, bad curves should be rejected. + t.Run("fipstls", func(t *testing.T) { + fipstls.Force() + defer fipstls.Abandon() + msg := "" + if !isBoringCurve(curveid) { + msg = "no cipher suite supported by both client and server" + } + testClientHelloFailure(t, serverConfig, clientHello, msg) + }) + }) + } +} + +func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) { + c, s := realNetPipe(t) + client := Client(c, clientConfig) + server := Server(s, serverConfig) + done := make(chan error, 1) + go func() { + done <- client.Handshake() + c.Close() + }() + serverErr = server.Handshake() + s.Close() + clientErr = <-done + return +} + +func TestBoringServerSignatureAndHash(t *testing.T) { + serverConfig := testConfig.Clone() + serverConfig.Certificates = make([]Certificate, 1) + + defer func() { + testingOnlyForceClientHelloSignatureAlgorithms = nil + }() + + for _, sigHash := range defaultSupportedSignatureAlgorithms { + testingOnlyForceClientHelloSignatureAlgorithms = []SignatureScheme{sigHash} + + t.Run(fmt.Sprintf("%v", sigHash), func(t *testing.T) { + if sigHash == PKCS1WithSHA1 || sigHash == PKCS1WithSHA256 || sigHash == PKCS1WithSHA384 || sigHash == PKCS1WithSHA512 { + serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} + serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate} + serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey + } else { + serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256} + serverConfig.Certificates = make([]Certificate, 1) + serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate} + serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey + } + serverConfig.BuildNameToCertificate() + + clientErr, _ := boringHandshake(t, testConfig, serverConfig) + if clientErr != nil { + t.Fatalf("expected handshake with %v to succeed; err=%v", sigHash, clientErr) + } + + // With fipstls forced, bad curves should be rejected. + t.Run("fipstls", func(t *testing.T) { + fipstls.Force() + defer fipstls.Abandon() + clientErr, _ := boringHandshake(t, testConfig, serverConfig) + if isBoringSignatureScheme(sigHash) { + if clientErr != nil { + t.Fatalf("expected handshake with %v to succeed; err=%v", sigHash, clientErr) + } + } else { + if clientErr == nil { + t.Fatalf("expected handshake with %v to fail, but it succeeded", sigHash) + } + } + }) + }) + } +} + +func TestBoringClientHello(t *testing.T) { + // Test that no matter what we put in the client config, + // the client does not offer non-FIPS configurations. + fipstls.Force() + defer fipstls.Abandon() + + c, s := net.Pipe() + defer c.Close() + defer s.Close() + + clientConfig := testConfig.Clone() + // All sorts of traps for the client to avoid. + clientConfig.MinVersion = VersionSSL30 + clientConfig.CipherSuites = allCipherSuites() + clientConfig.CurvePreferences = defaultCurvePreferences + + go Client(c, testConfig).Handshake() + srv := Server(s, testConfig) + msg, err := srv.readHandshake() + if err != nil { + t.Fatal(err) + } + hello, ok := msg.(*clientHelloMsg) + if !ok { + t.Fatalf("unexpected message type %T", msg) + } + + if hello.vers != VersionTLS12 { + t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12) + } + for _, id := range hello.cipherSuites { + if !isBoringCipherSuite(id) { + t.Errorf("client offered disallowed suite %#x", id) + } + } + for _, id := range hello.supportedCurves { + if !isBoringCurve(id) { + t.Errorf("client offered disallowed curve %d", id) + } + } + for _, sigHash := range hello.supportedSignatureAlgorithms { + if !isBoringSignatureScheme(sigHash) { + t.Errorf("client offered disallowed signature-and-hash %v", sigHash) + } + } +} + +func TestBoringCertAlgs(t *testing.T) { - // NaCl and arm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those. - if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" { ++ // NaCl, arm and wasm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those. ++ if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" || runtime.GOOS == "js" { + t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH) + } + + // Set up some roots, intermediate CAs, and leaf certs with various algorithms. + // X_Y is X signed by Y. + R1 := boringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK) + R2 := boringCert(t, "R2", boringRSAKey(t, 4096), nil, boringCertCA) + + M1_R1 := boringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK) + M2_R1 := boringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA) + + I_R1 := boringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK) + I_R2 := boringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK) + I_M1 := boringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK) + I_M2 := boringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK) + + L1_I := boringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK) + L2_I := boringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf) + + // boringCert checked that isBoringCertificate matches the caller's boringCertFIPSOK bit. + // If not, no point in building bigger end-to-end tests. + if t.Failed() { + t.Fatalf("isBoringCertificate failures; not continuing") + } + + // client verifying server cert + testServerCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) { + clientConfig := testConfig.Clone() + clientConfig.RootCAs = pool + clientConfig.InsecureSkipVerify = false + clientConfig.ServerName = "example.com" + + serverConfig := testConfig.Clone() + serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}} + serverConfig.BuildNameToCertificate() + + clientErr, _ := boringHandshake(t, clientConfig, serverConfig) + + if (clientErr == nil) == ok { + if ok { + t.Logf("%s: accept", desc) + } else { + t.Logf("%s: reject", desc) + } + } else { + if ok { + t.Errorf("%s: BAD reject (%v)", desc, clientErr) + } else { + t.Errorf("%s: BAD accept", desc) + } + } + } + + // server verifying client cert + testClientCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) { + clientConfig := testConfig.Clone() + clientConfig.ServerName = "example.com" + clientConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}} + + serverConfig := testConfig.Clone() + serverConfig.ClientCAs = pool + serverConfig.ClientAuth = RequireAndVerifyClientCert + + _, serverErr := boringHandshake(t, clientConfig, serverConfig) + + if (serverErr == nil) == ok { + if ok { + t.Logf("%s: accept", desc) + } else { + t.Logf("%s: reject", desc) + } + } else { + if ok { + t.Errorf("%s: BAD reject (%v)", desc, serverErr) + } else { + t.Errorf("%s: BAD accept", desc) + } + } + } + + // Run simple basic test with known answers before proceeding to + // exhaustive test with computed answers. + r1pool := x509.NewCertPool() + r1pool.AddCert(R1.cert) + testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) + testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true) + fipstls.Force() + testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) + testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false) + fipstls.Abandon() + + if t.Failed() { + t.Fatal("basic test failed, skipping exhaustive test") + } + + if testing.Short() { + t.Logf("basic test passed; skipping exhaustive test in -short mode") + return + } + + for l := 1; l <= 2; l++ { + leaf := L1_I + if l == 2 { + leaf = L2_I + } + for i := 0; i < 64; i++ { + reachable := map[string]bool{leaf.parentOrg: true} + reachableFIPS := map[string]bool{leaf.parentOrg: leaf.fipsOK} + list := [][]byte{leaf.der} + listName := leaf.name + addList := func(cond int, c *boringCertificate) { + if cond != 0 { + list = append(list, c.der) + listName += "," + c.name + if reachable[c.org] { + reachable[c.parentOrg] = true + } + if reachableFIPS[c.org] && c.fipsOK { + reachableFIPS[c.parentOrg] = true + } + } + } + addList(i&1, I_R1) + addList(i&2, I_R2) + addList(i&4, I_M1) + addList(i&8, I_M2) + addList(i&16, M1_R1) + addList(i&32, M2_R1) + + for r := 1; r <= 3; r++ { + pool := x509.NewCertPool() + rootName := "," + shouldVerify := false + shouldVerifyFIPS := false + addRoot := func(cond int, c *boringCertificate) { + if cond != 0 { + rootName += "," + c.name + pool.AddCert(c.cert) + if reachable[c.org] { + shouldVerify = true + } + if reachableFIPS[c.org] && c.fipsOK { + shouldVerifyFIPS = true + } + } + } + addRoot(r&1, R1) + addRoot(r&2, R2) + rootName = rootName[1:] // strip leading comma + testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify) + testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify) + fipstls.Force() + testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS) + testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS) + fipstls.Abandon() + } + } + } +} + +const ( + boringCertCA = iota + boringCertLeaf + boringCertFIPSOK = 0x80 +) + +func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey { + k, err := rsa.GenerateKey(rand.Reader, size) + if err != nil { + t.Fatal(err) + } + return k +} + +func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey { + k, err := ecdsa.GenerateKey(curve, rand.Reader) + if err != nil { + t.Fatal(err) + } + return k +} + +type boringCertificate struct { + name string + org string + parentOrg string + der []byte + cert *x509.Certificate + key interface{} + fipsOK bool +} + +func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate { + org := name + parentOrg := "" + if i := strings.Index(org, "_"); i >= 0 { + org = org[:i] + parentOrg = name[i+1:] + } + tmpl := &x509.Certificate{ + SerialNumber: big.NewInt(1), + Subject: pkix.Name{ + Organization: []string{org}, + }, + NotBefore: time.Unix(0, 0), + NotAfter: time.Unix(0, 0), + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth}, + BasicConstraintsValid: true, + } + if mode&^boringCertFIPSOK == boringCertLeaf { + tmpl.DNSNames = []string{"example.com"} + } else { + tmpl.IsCA = true + tmpl.KeyUsage |= x509.KeyUsageCertSign + } + + var pcert *x509.Certificate + var pkey interface{} + if parent != nil { + pcert = parent.cert + pkey = parent.key + } else { + pcert = tmpl + pkey = key + } + + var pub interface{} + var desc string + switch k := key.(type) { + case *rsa.PrivateKey: + pub = &k.PublicKey + desc = fmt.Sprintf("RSA-%d", k.N.BitLen()) + case *ecdsa.PrivateKey: + pub = &k.PublicKey + desc = "ECDSA-" + k.Curve.Params().Name + default: + t.Fatalf("invalid key %T", key) + } + + der, err := x509.CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey) + if err != nil { + t.Fatal(err) + } + cert, err := x509.ParseCertificate(der) + if err != nil { + t.Fatal(err) + } + + // Tell isBoringCertificate to enforce FIPS restrictions for this check. + fipstls.Force() + defer fipstls.Abandon() + + fipsOK := mode&boringCertFIPSOK != 0 + if isBoringCertificate(cert) != fipsOK { + t.Errorf("isBoringCertificate(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK) + } + return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK} +} + +func boringPool(t *testing.T, list ...*boringCertificate) *x509.CertPool { + pool := x509.NewCertPool() + for _, c := range list { + cert, err := x509.ParseCertificate(c.der) + if err != nil { + t.Fatal(err) + } + pool.AddCert(cert) + } + return pool +} + +func boringList(t *testing.T, list ...*boringCertificate) [][]byte { + var all [][]byte + for _, c := range list { + all = append(all, c.der) + } + return all +} + +// realNetPipe is like net.Pipe but returns an actual network socket pair, +// which has buffering that avoids various deadlocks if both sides +// try to speak at the same time. +func realNetPipe(t *testing.T) (net.Conn, net.Conn) { + l := newLocalListener(t) + defer l.Close() + c, err := net.Dial("tcp", l.Addr().String()) + if err != nil { + t.Fatal(err) + } + s, err := l.Accept() + if err != nil { + c.Close() + t.Fatal(err) + } + return c, s +} diff --cc src/crypto/tls/common.go index a76e4efac0,7c8f0de6e8..9a63eef571 --- a/src/crypto/tls/common.go +++ b/src/crypto/tls/common.go @@@ -128,13 -127,15 +128,15 @@@ const // Rest of these are reserved by the TLS spec ) - // Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1) + // Signature algorithms (for internal signaling use). Starting at 16 to avoid overlap with + // TLS 1.2 codepoints (RFC 5246, section A.4.1), with which these have nothing to do. const ( - signatureRSA uint8 = 1 - signatureECDSA uint8 = 3 + signaturePKCS1v15 uint8 = iota + 16 + signatureECDSA + signatureRSAPSS ) -// supportedSignatureAlgorithms contains the signature and hash algorithms that +// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that // the code advertises as supported in a TLS 1.2 ClientHello and in a TLS 1.2 // CertificateRequest. The two fields are merged to match with TLS 1.3. // Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc. diff --cc src/crypto/tls/handshake_server.go index 5b1aa64166,0d685927b3..c5caab1224 --- a/src/crypto/tls/handshake_server.go +++ b/src/crypto/tls/handshake_server.go @@@ -520,59 -519,15 +519,15 @@@ func (hs *serverHandshakeState) doFullH } // Determine the signature type. - var signatureAlgorithm SignatureScheme - var sigType uint8 - if certVerify.hasSignatureAndHash { - signatureAlgorithm = certVerify.signatureAlgorithm - if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms()) { - return errors.New("tls: unsupported hash function for client certificate") - } - sigType = signatureFromSignatureScheme(signatureAlgorithm) - } else { - // Before TLS 1.2 the signature algorithm was implicit - // from the key type, and only one hash per signature - // algorithm was possible. Leave signatureAlgorithm - // unset. - switch pub.(type) { - case *ecdsa.PublicKey: - sigType = signatureECDSA - case *rsa.PublicKey: - sigType = signatureRSA - } - _, sigType, hashFunc, err := pickSignatureAlgorithm(pub, []SignatureScheme{certVerify.signatureAlgorithm}, supportedSignatureAlgorithms, c.vers) ++ _, sigType, hashFunc, err := pickSignatureAlgorithm(pub, []SignatureScheme{certVerify.signatureAlgorithm}, supportedSignatureAlgorithms(), c.vers) + if err != nil { + c.sendAlert(alertIllegalParameter) + return err } - switch key := pub.(type) { - case *ecdsa.PublicKey: - if sigType != signatureECDSA { - err = errors.New("tls: bad signature type for client's ECDSA certificate") - break - } - ecdsaSig := new(ecdsaSignature) - if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil { - break - } - if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { - err = errors.New("tls: ECDSA signature contained zero or negative values") - break - } - var digest []byte - if digest, _, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil { - break - } - if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) { - err = errors.New("tls: ECDSA verification failure") - } - case *rsa.PublicKey: - if sigType != signatureRSA { - err = errors.New("tls: bad signature type for client's RSA certificate") - break - } - var digest []byte - var hashFunc crypto.Hash - if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil { - break - } - err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature) + var digest []byte + if digest, err = hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret); err == nil { + err = verifyHandshakeSignature(sigType, pub, hashFunc, digest, certVerify.signature) } if err != nil { c.sendAlert(alertBadCertificate) diff --cc src/crypto/tls/key_agreement.go index 5d6dc21c6d,1e77facce0..0754d1b389 --- a/src/crypto/tls/key_agreement.go +++ b/src/crypto/tls/key_agreement.go @@@ -247,17 -208,12 +208,12 @@@ NextCandidate serverECDHParams[3] = byte(len(ecdhePublic)) copy(serverECDHParams[4:], ecdhePublic) - var signatureAlgorithm SignatureScheme - - if ka.version >= VersionTLS12 { - var err error - signatureAlgorithm, err = pickTLS12HashForSignature(ka.sigType, clientHello.supportedSignatureAlgorithms) - if err != nil { - return nil, err - } + priv, ok := cert.PrivateKey.(crypto.Signer) + if !ok { + return nil, errors.New("tls: certificate private key does not implement crypto.Signer") } - digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, signatureAlgorithm, ka.version, clientHello.random, hello.random, serverECDHParams) - signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(priv.Public(), clientHello.supportedSignatureAlgorithms, supportedSignatureAlgorithms, ka.version) ++ signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(priv.Public(), clientHello.supportedSignatureAlgorithms, supportedSignatureAlgorithms(), ka.version) if err != nil { return nil, err } diff --cc src/go/build/deps_test.go index ff04b9e982,29dbe47d29..08ab218610 --- a/src/go/build/deps_test.go +++ b/src/go/build/deps_test.go @@@ -99,34 -99,29 +99,36 @@@ var pkgDeps = map[string][]string // L3 adds reflection and some basic utility packages // and interface definitions, but nothing that makes // system calls. - "crypto": {"L2", "hash"}, // interfaces - "crypto/cipher": {"L2", "crypto/subtle"}, - "crypto/subtle": {}, - "encoding/base32": {"L2"}, - "encoding/base64": {"L2", "encoding/binary"}, - "encoding/binary": {"L2", "reflect"}, - "hash": {"L2"}, // interfaces - "hash/adler32": {"L2", "hash"}, - "hash/crc32": {"L2", "hash"}, - "hash/crc64": {"L2", "hash"}, - "hash/fnv": {"L2", "hash"}, - "image": {"L2", "image/color"}, // interfaces - "image/color": {"L2"}, // interfaces - "image/color/palette": {"L2", "image/color"}, - "reflect": {"L2"}, - "sort": {"reflect"}, + "crypto": {"L2", "hash"}, // interfaces + "crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle"}, + "crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag + "crypto/subtle": {}, + "encoding/base32": {"L2"}, + "encoding/base64": {"L2", "encoding/binary"}, + "encoding/binary": {"L2", "reflect"}, + "hash": {"L2"}, // interfaces + "hash/adler32": {"L2", "hash"}, + "hash/crc32": {"L2", "hash"}, + "hash/crc64": {"L2", "hash"}, + "hash/fnv": {"L2", "hash"}, + "image": {"L2", "image/color"}, // interfaces + "image/color": {"L2"}, // interfaces + "image/color/palette": {"L2", "image/color"}, + "reflect": {"L2"}, + "sort": {"reflect"}, + "crypto/internal/boring": {"L2", "C", "crypto", "crypto/cipher", "crypto/internal/boring/sig", "crypto/subtle", "encoding/asn1", "hash", "math/big"}, + "crypto/internal/boring/fipstls": {"sync/atomic"}, + "crypto/internal/cipherhw": {"crypto/internal/boring"}, + "crypto/tls/fipsonly": {"crypto/internal/boring/fipstls", "crypto/internal/boring/sig"}, + "L3": { "L2", "crypto", "crypto/cipher", + "crypto/internal/boring", + "crypto/internal/boring/fipstls", + "crypto/internal/subtle", "crypto/subtle", "encoding/base32", "encoding/base64", @@@ -236,49 -231,49 +238,49 @@@ "go/types": {"L4", "GOPARSER", "container/heap", "go/constant"}, // One of a kind. -- "archive/tar": {"L4", "OS", "syscall", "os/user"}, -- "archive/zip": {"L4", "OS", "compress/flate"}, -- "container/heap": {"sort"}, -- "compress/bzip2": {"L4"}, -- "compress/flate": {"L4"}, -- "compress/gzip": {"L4", "compress/flate"}, -- "compress/lzw": {"L4"}, -- "compress/zlib": {"L4", "compress/flate"}, -- "context": {"errors", "fmt", "reflect", "sync", "time"}, -- "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"}, -- "database/sql/driver": {"L4", "context", "time", "database/sql/internal"}, -- "debug/dwarf": {"L4"}, -- "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"}, -- "debug/gosym": {"L4"}, - "debug/macho": {"L4", "OS", "debug/dwarf"}, - "debug/pe": {"L4", "OS", "debug/dwarf"}, - "debug/macho": {"L4", "OS", "debug/dwarf", "compress/zlib"}, - "debug/pe": {"L4", "OS", "debug/dwarf", "compress/zlib"}, -- "debug/plan9obj": {"L4", "OS"}, -- "encoding": {"L4"}, -- "encoding/ascii85": {"L4"}, -- "encoding/asn1": {"L4", "math/big"}, -- "encoding/csv": {"L4"}, -- "encoding/gob": {"L4", "OS", "encoding"}, -- "encoding/hex": {"L4"}, -- "encoding/json": {"L4", "encoding"}, -- "encoding/pem": {"L4"}, -- "encoding/xml": {"L4", "encoding"}, -- "flag": {"L4", "OS"}, -- "go/build": {"L4", "OS", "GOPARSER"}, -- "html": {"L4"}, -- "image/draw": {"L4", "image/internal/imageutil"}, -- "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, -- "image/internal/imageutil": {"L4"}, -- "image/jpeg": {"L4", "image/internal/imageutil"}, -- "image/png": {"L4", "compress/zlib"}, -- "index/suffixarray": {"L4", "regexp"}, -- "internal/singleflight": {"sync"}, -- "internal/trace": {"L4", "OS"}, -- "math/big": {"L4"}, -- "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, -- "mime/quotedprintable": {"L4"}, -- "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"}, -- "net/url": {"L4"}, -- "plugin": {"L0", "OS", "CGO"}, ++ "archive/tar": {"L4", "OS", "syscall", "os/user"}, ++ "archive/zip": {"L4", "OS", "compress/flate"}, ++ "container/heap": {"sort"}, ++ "compress/bzip2": {"L4"}, ++ "compress/flate": {"L4"}, ++ "compress/gzip": {"L4", "compress/flate"}, ++ "compress/lzw": {"L4"}, ++ "compress/zlib": {"L4", "compress/flate"}, ++ "context": {"errors", "fmt", "reflect", "sync", "time"}, ++ "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"}, ++ "database/sql/driver": {"L4", "context", "time", "database/sql/internal"}, ++ "debug/dwarf": {"L4"}, ++ "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"}, ++ "debug/gosym": {"L4"}, ++ "debug/macho": {"L4", "OS", "debug/dwarf", "compress/zlib"}, ++ "debug/pe": {"L4", "OS", "debug/dwarf", "compress/zlib"}, ++ "debug/plan9obj": {"L4", "OS"}, ++ "encoding": {"L4"}, ++ "encoding/ascii85": {"L4"}, ++ "encoding/asn1": {"L4", "math/big"}, ++ "encoding/csv": {"L4"}, ++ "encoding/gob": {"L4", "OS", "encoding"}, ++ "encoding/hex": {"L4"}, ++ "encoding/json": {"L4", "encoding"}, ++ "encoding/pem": {"L4"}, ++ "encoding/xml": {"L4", "encoding"}, ++ "flag": {"L4", "OS"}, ++ "go/build": {"L4", "OS", "GOPARSER"}, ++ "html": {"L4"}, ++ "image/draw": {"L4", "image/internal/imageutil"}, ++ "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"}, ++ "image/internal/imageutil": {"L4"}, ++ "image/jpeg": {"L4", "image/internal/imageutil"}, ++ "image/png": {"L4", "compress/zlib"}, ++ "index/suffixarray": {"L4", "regexp"}, ++ "internal/singleflight": {"sync"}, ++ "internal/trace": {"L4", "OS"}, ++ "math/big": {"L4"}, ++ "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"}, ++ "mime/quotedprintable": {"L4"}, ++ "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"}, ++ "net/url": {"L4"}, ++ "plugin": {"L0", "OS", "CGO"}, "runtime/pprof/internal/profile": {"L4", "OS", "compress/gzip", "regexp"}, "testing/internal/testdeps": {"L4", "internal/testlog", "runtime/pprof", "regexp"}, "text/scanner": {"L4", "OS"},