This is a git merge of master into dev.boringcrypto.
The branch was previously based on release-branch.go1.9,
so there are a handful of spurious conflicts that would
also arise if trying to merge master into release-branch.go1.9
(which we never do). Those have all been resolved by taking
the original file from master, discarding any Go 1.9-specific
edits.
all.bash passes on darwin/amd64, which is to say without
actually using BoringCrypto.
Go 1.10-related fixes to BoringCrypto itself will be in a followup CL.
This CL is just the merge.
Change-Id: I4c97711fec0fb86761913dcde28d25c001246c35
// ../../../../runtime/type.go:/structType
// for security, only the exported fields.
case TSTRUCT:
-
- n := 0
-
- for _, t1 := range t.Fields().Slice() {
- if omitFieldForAwfulBoringCryptoKludge(t1) {
- continue
+ fields := t.Fields().Slice()
+
+ // omitFieldForAwfulBoringCryptoKludge reports whether
+ // the field t should be omitted from the reflect data.
+ // In the crypto/... packages we omit an unexported field
+ // named "boring", to keep from breaking client code that
+ // expects rsa.PublicKey etc to have only public fields.
+ // As the name suggests, this is an awful kludge, but it is
+ // limited to the dev.boringcrypto branch and avoids
+ // much more invasive effects elsewhere.
+ omitFieldForAwfulBoringCryptoKludge := func(t *types.Field) bool {
+ if t.Sym == nil || t.Sym.Name != "boring" || t.Sym.Pkg == nil {
+ return false
+ }
+ path := t.Sym.Pkg.Path
+ if t.Sym.Pkg == localpkg {
+ path = myimportpath
+ }
+ return strings.HasPrefix(path, "crypto/")
+ }
++ newFields := fields[:0:0]
++ for _, t1 := range fields {
++ if !omitFieldForAwfulBoringCryptoKludge(t1) {
++ newFields = append(newFields, t1)
+ }
++ }
++ fields = newFields
++
+ for _, t1 := range fields {
dtypesym(t1.Type)
- n++
}
- ot = dcommontype(lsym, ot, t)
- pkg := localpkg
- if t.Sym != nil {
- pkg = t.Sym.Pkg
- } else {
- // Unnamed type. Grab the package from the first field, if any.
- for _, f := range t.Fields().Slice() {
- if f.Embedded != 0 {
- continue
- }
- pkg = f.Sym.Pkg
+ // All non-exported struct field names within a struct
+ // type must originate from a single package. By
+ // identifying and recording that package within the
+ // struct type descriptor, we can omit that
+ // information from the field descriptors.
+ var spkg *types.Pkg
+ for _, f := range fields {
+ if !exportname(f.Sym.Name) {
+ spkg = f.Sym.Pkg
break
}
}
tg.grepStdout("false", "did not see BinaryOnly=false for p4")
}
-// Issue 16050.
-func TestAlwaysLinkSysoFiles(t *testing.T) {
+// Issue 16050 and 21884.
+func TestLinkSysoFiles(t *testing.T) {
++ if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
++ t.Skip("not linux/amd64")
++ }
++
tg := testgo(t)
defer tg.cleanup()
tg.parallel()
type PublicKey struct {
elliptic.Curve
X, Y *big.Int
+
+ boring unsafe.Pointer
}
- // PrivateKey represents a ECDSA private key.
+ // PrivateKey represents an ECDSA private key.
type PrivateKey struct {
PublicKey
D *big.Int
return &priv.PublicKey
}
- // Sign signs msg with priv, reading randomness from rand. This method is
- // intended to support keys where the private part is kept in, for example, a
- // hardware module. Common uses should use the Sign function in this package
- // directly.
- func (priv *PrivateKey) Sign(rand io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
+ // Sign signs digest with priv, reading randomness from rand. The opts argument
+ // is not currently used but, in keeping with the crypto.Signer interface,
+ // should be the hash function used to digest the message.
+ //
+ // This method implements crypto.Signer, which is an interface to support keys
+ // where the private part is kept in, for example, a hardware module. Common
+ // uses should use the Sign function in this package directly.
+ func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
+ if boring.Enabled && rand == boring.RandReader {
+ b, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
- return boring.SignMarshalECDSA(b, msg)
++ return boring.SignMarshalECDSA(b, digest)
+ }
+ boring.UnreachableExceptTests()
+
- r, s, err := Sign(rand, priv, msg)
+ r, s, err := Sign(rand, priv, digest)
if err != nil {
return nil, err
}
}
// New returns a new HMAC hash using the given hash.Hash type and key.
+ // Note that unlike other hash implementations in the standard library,
+ // the returned Hash does not implement encoding.BinaryMarshaler
+ // or encoding.BinaryUnmarshaler.
func New(h func() hash.Hash, key []byte) hash.Hash {
+ if boring.Enabled {
+ hm := boring.NewHMAC(h, key)
+ if hm != nil {
+ return hm
+ }
+ // BoringCrypto did not recognize h, so fall through to standard Go code.
+ }
hm := new(hmac)
hm.outer = h()
hm.inner = h()
--- /dev/null
-package crypto
+ // 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 crypto_test
+
+ import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rc4"
+ "testing"
+ )
+
+ func TestRC4OutOfBoundsWrite(t *testing.T) {
+ // This cipherText is encrypted "0123456789"
+ cipherText := []byte{238, 41, 187, 114, 151, 2, 107, 13, 178, 63}
+ cipher, err := rc4.NewCipher([]byte{0})
+ if err != nil {
+ panic(err)
+ }
+ test(t, "RC4", cipherText, cipher.XORKeyStream)
+ }
+ func TestCTROutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "CTR", cipher.NewCTR)
+ }
+ func TestOFBOutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "OFB", cipher.NewOFB)
+ }
+ func TestCFBEncryptOutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "CFB Encrypt", cipher.NewCFBEncrypter)
+ }
+ func TestCFBDecryptOutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "CFB Decrypt", cipher.NewCFBDecrypter)
+ }
+ func testBlock(t *testing.T, name string, newCipher func(cipher.Block, []byte) cipher.Stream) {
+ // This cipherText is encrypted "0123456789"
+ cipherText := []byte{86, 216, 121, 231, 219, 191, 26, 12, 176, 117}
+ var iv, key [16]byte
+ block, err := aes.NewCipher(key[:])
+ if err != nil {
+ panic(err)
+ }
+ stream := newCipher(block, iv[:])
+ test(t, name, cipherText, stream.XORKeyStream)
+ }
+ func test(t *testing.T, name string, cipherText []byte, xor func([]byte, []byte)) {
+ want := "abcdefghij"
+ plainText := []byte(want)
+ shorterLen := len(cipherText) / 2
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Errorf("%v XORKeyStream expected to panic on len(dst) < len(src), but didn't", name)
+ }
+ const plain = "0123456789"
+ if plainText[shorterLen] == plain[shorterLen] {
+ t.Errorf("%v XORKeyStream did out of bounds write, want %v, got %v", name, want, string(plainText))
+ }
+ }()
+ xor(plainText[:shorterLen], cipherText)
+ }
d.len = 0
}
- // New returns a new hash.Hash computing the SHA1 checksum.
+ // New returns a new hash.Hash computing the SHA1 checksum. The Hash also
+ // implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
+ // marshal and unmarshal the internal state of the hash.
func New() hash.Hash {
+ if boringEnabled {
+ return boringNewSHA1()
+ }
d := new(digest)
d.Reset()
return d
package sha1
import (
+ "bytes"
+ "crypto/internal/boring"
"crypto/rand"
+ "encoding"
"fmt"
"io"
"testing"
import (
"crypto"
+ "crypto/internal/boring"
+ "errors"
"hash"
)
d.len = 0
}
- // New returns a new hash.Hash computing the SHA256 checksum.
+ // New returns a new hash.Hash computing the SHA256 checksum. The Hash
+ // also implements encoding.BinaryMarshaler and
+ // encoding.BinaryUnmarshaler to marshal and unmarshal the internal
+ // state of the hash.
func New() hash.Hash {
+ if boring.Enabled {
+ return boring.NewSHA256()
+ }
d := new(digest)
d.Reset()
return d
package sha256
import (
+ "bytes"
+ "crypto/internal/boring"
"crypto/rand"
+ "encoding"
"fmt"
+ "hash"
"io"
"testing"
)
import (
"crypto"
+ "crypto/internal/boring"
+ "errors"
"hash"
)
d.len = 0
}
+ const (
+ magic384 = "sha\x04"
+ magic512_224 = "sha\x05"
+ magic512_256 = "sha\x06"
+ magic512 = "sha\x07"
+ marshaledSize = len(magic512) + 8*8 + chunk + 8
+ )
+
+ func (d *digest) MarshalBinary() ([]byte, error) {
+ b := make([]byte, 0, marshaledSize)
+ switch d.function {
+ case crypto.SHA384:
+ b = append(b, magic384...)
+ case crypto.SHA512_224:
+ b = append(b, magic512_224...)
+ case crypto.SHA512_256:
+ b = append(b, magic512_256...)
+ case crypto.SHA512:
+ b = append(b, magic512...)
+ default:
+ return nil, errors.New("crypto/sha512: invalid hash function")
+ }
+ b = appendUint64(b, d.h[0])
+ b = appendUint64(b, d.h[1])
+ b = appendUint64(b, d.h[2])
+ b = appendUint64(b, d.h[3])
+ b = appendUint64(b, d.h[4])
+ b = appendUint64(b, d.h[5])
+ b = appendUint64(b, d.h[6])
+ b = appendUint64(b, d.h[7])
+ b = append(b, d.x[:]...)
+ b = appendUint64(b, d.len)
+ return b, nil
+ }
+
+ func (d *digest) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic512) {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ switch {
+ case d.function == crypto.SHA384 && string(b[:len(magic384)]) == magic384:
+ case d.function == crypto.SHA512_224 && string(b[:len(magic512_224)]) == magic512_224:
+ case d.function == crypto.SHA512_256 && string(b[:len(magic512_256)]) == magic512_256:
+ case d.function == crypto.SHA512 && string(b[:len(magic512)]) == magic512:
+ default:
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize {
+ return errors.New("crypto/sha512: invalid hash state size")
+ }
+ b = b[len(magic512):]
+ b, d.h[0] = consumeUint64(b)
+ b, d.h[1] = consumeUint64(b)
+ b, d.h[2] = consumeUint64(b)
+ b, d.h[3] = consumeUint64(b)
+ b, d.h[4] = consumeUint64(b)
+ b, d.h[5] = consumeUint64(b)
+ b, d.h[6] = consumeUint64(b)
+ b, d.h[7] = consumeUint64(b)
+ b = b[copy(d.x[:], b):]
+ b, d.len = consumeUint64(b)
+ d.nx = int(d.len) % chunk
+ return nil
+ }
+
+ func appendUint64(b []byte, x uint64) []byte {
+ a := [8]byte{
+ byte(x >> 56),
+ byte(x >> 48),
+ byte(x >> 40),
+ byte(x >> 32),
+ byte(x >> 24),
+ byte(x >> 16),
+ byte(x >> 8),
+ byte(x),
+ }
+ return append(b, a[:]...)
+ }
+
+ func consumeUint64(b []byte) ([]byte, uint64) {
+ _ = b[7]
+ x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ return b[8:], x
+ }
+
// New returns a new hash.Hash computing the SHA-512 checksum.
func New() hash.Hash {
+ if boring.Enabled {
+ return boring.NewSHA512()
+ }
d := &digest{function: crypto.SHA512}
d.Reset()
return d
package sha512
import (
+ "bytes"
+ "crypto/internal/boring"
"crypto/rand"
+ "encoding"
"encoding/hex"
"hash"
"io"
--- /dev/null
- func supportedSignatureAlgorithms() []signatureAndHash {
+// 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/internal/boring/fipstls"
+ "crypto/rsa"
+ "crypto/x509"
+)
+
+// needFIPS returns fipstls.Required(); it avoids a new import in common.go.
+func needFIPS() bool {
+ return fipstls.Required()
+}
+
+// fipsMinVersion replaces c.minVersion in FIPS-only mode.
+func fipsMinVersion(c *Config) uint16 {
+ // FIPS requires TLS 1.2.
+ return VersionTLS12
+}
+
+// fipsMaxVersion replaces c.maxVersion in FIPS-only mode.
+func fipsMaxVersion(c *Config) uint16 {
+ // FIPS requires TLS 1.2.
+ return VersionTLS12
+}
+
+// default defaultFIPSCurvePreferences is the FIPS-allowed curves,
+// in preference order (most preferable first).
+var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode.
+func fipsCurvePreferences(c *Config) []CurveID {
+ if c == nil || len(c.CurvePreferences) == 0 {
+ return defaultFIPSCurvePreferences
+ }
+ var list []CurveID
+ for _, id := range c.CurvePreferences {
+ for _, allowed := range defaultFIPSCurvePreferences {
+ if id == allowed {
+ list = append(list, id)
+ break
+ }
+ }
+ }
+ return list
+}
+
+// default FIPSCipherSuites is the FIPS-allowed cipher suites,
+// in preference order (most preferable first).
+var defaultFIPSCipherSuites = []uint16{
+ 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,
+}
+
+// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode.
+func fipsCipherSuites(c *Config) []uint16 {
+ if c == nil || c.CipherSuites == nil {
+ return defaultFIPSCipherSuites
+ }
+ var list []uint16
+ for _, id := range c.CipherSuites {
+ for _, allowed := range defaultFIPSCipherSuites {
+ if id == allowed {
+ list = append(list, id)
+ break
+ }
+ }
+ }
+ return list
+}
+
+// isBoringCertificate reports whether a certificate may be used
+// when constructing a verified chain.
+// It is called for each leaf, intermediate, and root certificate.
+func isBoringCertificate(c *x509.Certificate) bool {
+ if !needFIPS() {
+ // Everything is OK if we haven't forced FIPS-only mode.
+ return true
+ }
+
+ // Otherwise the key must be RSA 2048, RSA 3072, or ECDSA P-256.
+ switch k := c.PublicKey.(type) {
+ default:
+ return false
+ case *rsa.PublicKey:
+ if size := k.N.BitLen(); size != 2048 && size != 3072 {
+ return false
+ }
+ case *ecdsa.PublicKey:
+ if name := k.Curve.Params().Name; name != "P-256" && name != "P-384" {
+ return false
+ }
+ }
+
+ return true
+}
+
+// supportedSignatureAlgorithms returns the supported signature algorithms.
+// It knows that the FIPS-allowed ones are all at the beginning of
+// defaultSupportedSignatureAlgorithms.
- for i < len(all) && all[i].hash != hashSHA1 {
++func supportedSignatureAlgorithms() []SignatureScheme {
+ all := defaultSupportedSignatureAlgorithms
+ if !needFIPS() {
+ return all
+ }
+ i := 0
- var testingOnlyForceClientHelloSignatureAndHashes []signatureAndHash
++ for i < len(all) && all[i] != PKCS1WithSHA1 {
+ i++
+ }
+ return all[:i]
+}
+
++var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
--- /dev/null
- func isBoringSignatureAndHash(sigHash signatureAndHash) bool {
- switch sigHash.signature {
+// 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))
+}
+
- case signatureRSA,
- signatureECDSA:
- // ok
- }
- switch sigHash.hash {
- default:
- return false
- case hashSHA256,
- hashSHA384:
++func isBoringSignatureScheme(alg SignatureScheme) bool {
++ switch alg {
+ default:
+ return false
- testingOnlyForceClientHelloSignatureAndHashes = nil
++ 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() {
- testingOnlyForceClientHelloSignatureAndHashes = []signatureAndHash{sigHash}
++ testingOnlyForceClientHelloSignatureAlgorithms = nil
+ }()
+
+ for _, sigHash := range defaultSupportedSignatureAlgorithms {
- if sigHash.signature == signatureRSA {
++ testingOnlyForceClientHelloSignatureAlgorithms = []SignatureScheme{sigHash}
+
+ t.Run(fmt.Sprintf("%v", sigHash), func(t *testing.T) {
- if isBoringSignatureAndHash(sigHash) {
++ 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)
- for _, sigHash := range hello.signatureAndHashes {
- if !isBoringSignatureAndHash(sigHash) {
++ 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" {
+ 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
+}
signatureECDSA uint8 = 3
)
- // signatureAndHash mirrors the TLS 1.2, SignatureAndHashAlgorithm struct. See
- // RFC 5246, section A.4.1.
- type signatureAndHash struct {
- hash, signature uint8
- }
-
-// 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.
- var defaultSupportedSignatureAlgorithms = []signatureAndHash{
- {hashSHA256, signatureRSA},
- {hashSHA256, signatureECDSA},
- {hashSHA384, signatureRSA},
- {hashSHA384, signatureECDSA},
- {hashSHA1, signatureRSA},
- {hashSHA1, signatureECDSA},
+ // 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.
-var supportedSignatureAlgorithms = []SignatureScheme{
++var defaultSupportedSignatureAlgorithms = []SignatureScheme{
+ PKCS1WithSHA256,
+ ECDSAWithP256AndSHA256,
+ PKCS1WithSHA384,
+ ECDSAWithP384AndSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithP521AndSHA512,
+ PKCS1WithSHA1,
+ ECDSAWithSHA1,
}
// ConnectionState records basic TLS details about the connection.
}
if hello.vers >= VersionTLS12 {
- hello.signatureAndHashes = supportedSignatureAlgorithms()
- hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms
++ hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
++ }
++ if testingOnlyForceClientHelloSignatureAlgorithms != nil {
++ hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
}
- if testingOnlyForceClientHelloSignatureAndHashes != nil {
- hello.signatureAndHashes = testingOnlyForceClientHelloSignatureAndHashes
+ return hello, nil
+ }
+
+ // c.out.Mutex <= L; c.handshakeMutex <= L.
+ func (c *Conn) clientHandshake() error {
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
+
+ // This may be a renegotiation handshake, in which case some fields
+ // need to be reset.
+ c.didResume = false
+
+ hello, err := makeClientHello(c.config)
+ if err != nil {
+ return err
+ }
+
+ if c.handshakes > 0 {
+ hello.secureRenegotiation = c.clientFinished[:]
}
var session *ClientSessionState
}
}
if rand.Intn(10) > 5 {
- m.signatureAndHashes = supportedSignatureAlgorithms()
- m.supportedSignatureAlgorithms = supportedSignatureAlgorithms
++ m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
}
m.alpnProtocols = make([]string, rand.Intn(5))
for i := range m.alpnProtocols {
}
if c.vers >= VersionTLS12 {
certReq.hasSignatureAndHash = true
- certReq.signatureAndHashes = supportedSignatureAlgorithms()
- certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms
++ certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
}
// An empty list of certificateAuthorities signals to
}
// Determine the signature type.
- var signatureAndHash signatureAndHash
+ var signatureAlgorithm SignatureScheme
+ var sigType uint8
if certVerify.hasSignatureAndHash {
- signatureAndHash = certVerify.signatureAndHash
- if !isSupportedSignatureAndHash(signatureAndHash, supportedSignatureAlgorithms()) {
+ signatureAlgorithm = certVerify.signatureAlgorithm
- if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms) {
++ 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
}
// hashForServerKeyExchange hashes the given slices and returns their digest
- // and the identifier of the hash function used. The sigAndHash argument is
- // only used for >= TLS 1.2 and precisely identifies the hash function to use.
- func hashForServerKeyExchange(sigAndHash signatureAndHash, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
+ // and the identifier of the hash function used. The signatureAlgorithm argument
+ // is only used for >= TLS 1.2 and identifies the hash function to use.
+ func hashForServerKeyExchange(sigType uint8, signatureAlgorithm SignatureScheme, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
if version >= VersionTLS12 {
- if !isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms()) {
- if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms) {
++ if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms()) {
return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer")
}
- hashFunc, err := lookupTLSHash(sigAndHash.hash)
+ hashFunc, err := lookupTLSHash(signatureAlgorithm)
if err != nil {
return nil, crypto.Hash(0), err
}
// If the client didn't specify any signature_algorithms
// extension then we can assume that it supports SHA1. See
// http://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
- return hashSHA1, nil
+ switch sigType {
+ case signatureRSA:
+ return PKCS1WithSHA1, nil
+ case signatureECDSA:
+ return ECDSAWithSHA1, nil
+ default:
+ return 0, errors.New("tls: unknown signature algorithm")
+ }
}
- for _, sigAndHash := range clientList {
- if sigAndHash.signature != sigType {
+ for _, sigAlg := range clientList {
+ if signatureFromSignatureScheme(sigAlg) != sigType {
continue
}
- if isSupportedSignatureAndHash(sigAndHash, supportedSignatureAlgorithms()) {
- return sigAndHash.hash, nil
- if isSupportedSignatureAlgorithm(sigAlg, supportedSignatureAlgorithms) {
++ if isSupportedSignatureAlgorithm(sigAlg, supportedSignatureAlgorithms()) {
+ return sigAlg, nil
}
}
return out
}
- // selectClientCertSignatureAlgorithm returns a signatureAndHash to sign a
+ // selectClientCertSignatureAlgorithm returns a SignatureScheme to sign a
// client's CertificateVerify with, or an error if none can be found.
- func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []signatureAndHash, sigType uint8) (signatureAndHash, error) {
- if h.version < VersionTLS12 {
- // Nothing to negotiate before TLS 1.2.
- return signatureAndHash{signature: sigType}, nil
- }
-
+ func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []SignatureScheme, sigType uint8) (SignatureScheme, error) {
for _, v := range serverList {
- if v.signature == sigType && isSupportedSignatureAndHash(v, supportedSignatureAlgorithms()) {
- if signatureFromSignatureScheme(v) == sigType && isSupportedSignatureAlgorithm(v, supportedSignatureAlgorithms) {
++ if signatureFromSignatureScheme(v) == sigType && isSupportedSignatureAlgorithm(v, supportedSignatureAlgorithms()) {
return v, nil
}
}
// VerifyOptions contains parameters for Certificate.Verify. It's a structure
// because other PKIX verification APIs have ended up needing many options.
type VerifyOptions struct {
++ // IsBoring is a validity check for BoringCrypto.
++ // If not nil, it will be called to check whether a given certificate
++ // can be used for constructing verification chains.
++ IsBoring func(*Certificate) bool
++
DNSName string
Intermediates *CertPool
Roots *CertPool // if nil, the system roots are used
}
}
- return CertificateInvalidError{c, IncompatibleUsage}
+ if opts.IsBoring != nil && !opts.IsBoring(c) {
+ // IncompatibleUsage is not quite right here,
+ // but it's also the "no chains found" error
+ // and is close enough.
++ return CertificateInvalidError{c, IncompatibleUsage, ""}
+ }
+
return nil
}
--- /dev/null
--- /dev/null
++// 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 runtime
++
++import _ "unsafe" // for go:linkname
++
++//go:linkname boring_runtime_arg0 crypto/internal/boring.runtime_arg0
++func boring_runtime_arg0() string {
++ // On Windows, argslice is not set, and it's too much work to find argv0.
++ if len(argslice) == 0 {
++ return ""
++ }
++ return argslice[0]
++}
++
++//go:linkname fipstls_runtime_arg0 crypto/internal/boring/fipstls.runtime_arg0
++func fipstls_runtime_arg0() string { return boring_runtime_arg0() }