diff options
author | Ian Lance Taylor <iant@golang.org> | 2017-09-14 17:11:35 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2017-09-14 17:11:35 +0000 |
commit | bc998d034f45d1828a8663b2eed928faf22a7d01 (patch) | |
tree | 8d262a22ca7318f4bcd64269fe8fe9e45bcf8d0f /libgo/go/crypto | |
parent | a41a6142df74219f596e612d3a7775f68ca6e96f (diff) | |
download | gcc-bc998d034f45d1828a8663b2eed928faf22a7d01.tar.gz |
libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753
From-SVN: r252767
Diffstat (limited to 'libgo/go/crypto')
41 files changed, 1053 insertions, 243 deletions
diff --git a/libgo/go/crypto/aes/cipher_generic.go b/libgo/go/crypto/aes/cipher_generic.go index 2c8d299c880..98169bf5fd7 100644 --- a/libgo/go/crypto/aes/cipher_generic.go +++ b/libgo/go/crypto/aes/cipher_generic.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// -build !amd64,!s390x +// -build !amd64,!s390x,!ppc64le package aes diff --git a/libgo/go/crypto/aes/cipher_ppc64le.go b/libgo/go/crypto/aes/cipher_ppc64le.go new file mode 100644 index 00000000000..1d16fe03f04 --- /dev/null +++ b/libgo/go/crypto/aes/cipher_ppc64le.go @@ -0,0 +1,82 @@ +// Copyright 2016 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. + +// +build ignore + +package aes + +import ( + "crypto/cipher" +) + +// defined in asm_ppc64le.s + +//go:noescape + +func setEncryptKeyAsm(key *byte, keylen int, enc *uint32) int + +//go:noescape + +func setDecryptKeyAsm(key *byte, keylen int, dec *uint32) int + +//go:noescape + +func doEncryptKeyAsm(key *byte, keylen int, dec *uint32) int + +//go:noescape + +func encryptBlockAsm(dst, src *byte, enc *uint32) + +//go:noescape + +func decryptBlockAsm(dst, src *byte, dec *uint32) + +type aesCipherAsm struct { + aesCipher +} + +func newCipher(key []byte) (cipher.Block, error) { + n := 64 // size is fixed for all and round value is stored inside it too + c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}} + k := len(key) + + ret := 0 + ret += setEncryptKeyAsm(&key[0], k*8, &c.enc[0]) + ret += setDecryptKeyAsm(&key[0], k*8, &c.dec[0]) + + if ret > 0 { + return nil, KeySizeError(k) + } + + return &c, nil +} + +func (c *aesCipherAsm) BlockSize() int { return BlockSize } + +func (c *aesCipherAsm) Encrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + encryptBlockAsm(&dst[0], &src[0], &c.enc[0]) +} + +func (c *aesCipherAsm) Decrypt(dst, src []byte) { + if len(src) < BlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < BlockSize { + panic("crypto/aes: output not full block") + } + decryptBlockAsm(&dst[0], &src[0], &c.dec[0]) +} + +// expandKey is used by BenchmarkExpand to ensure that the asm implementation +// of key expansion is used for the benchmark when it is available. +func expandKey(key []byte, enc, dec []uint32) { + setEncryptKeyAsm(&key[0], len(key)*8, &enc[0]) + setDecryptKeyAsm(&key[0], len(key)*8, &dec[0]) +} diff --git a/libgo/go/crypto/crypto.go b/libgo/go/crypto/crypto.go index a80ebd36931..b4d6cdcab4e 100644 --- a/libgo/go/crypto/crypto.go +++ b/libgo/go/crypto/crypto.go @@ -21,40 +21,48 @@ func (h Hash) HashFunc() Hash { } const ( - MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 - MD5 // import crypto/md5 - SHA1 // import crypto/sha1 - SHA224 // import crypto/sha256 - SHA256 // import crypto/sha256 - SHA384 // import crypto/sha512 - SHA512 // import crypto/sha512 - MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA - RIPEMD160 // import golang.org/x/crypto/ripemd160 - SHA3_224 // import golang.org/x/crypto/sha3 - SHA3_256 // import golang.org/x/crypto/sha3 - SHA3_384 // import golang.org/x/crypto/sha3 - SHA3_512 // import golang.org/x/crypto/sha3 - SHA512_224 // import crypto/sha512 - SHA512_256 // import crypto/sha512 + MD4 Hash = 1 + iota // import golang.org/x/crypto/md4 + MD5 // import crypto/md5 + SHA1 // import crypto/sha1 + SHA224 // import crypto/sha256 + SHA256 // import crypto/sha256 + SHA384 // import crypto/sha512 + SHA512 // import crypto/sha512 + MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA + RIPEMD160 // import golang.org/x/crypto/ripemd160 + SHA3_224 // import golang.org/x/crypto/sha3 + SHA3_256 // import golang.org/x/crypto/sha3 + SHA3_384 // import golang.org/x/crypto/sha3 + SHA3_512 // import golang.org/x/crypto/sha3 + SHA512_224 // import crypto/sha512 + SHA512_256 // import crypto/sha512 + BLAKE2s_256 // import golang.org/x/crypto/blake2s + BLAKE2b_256 // import golang.org/x/crypto/blake2b + BLAKE2b_384 // import golang.org/x/crypto/blake2b + BLAKE2b_512 // import golang.org/x/crypto/blake2b maxHash ) var digestSizes = []uint8{ - MD4: 16, - MD5: 16, - SHA1: 20, - SHA224: 28, - SHA256: 32, - SHA384: 48, - SHA512: 64, - SHA512_224: 28, - SHA512_256: 32, - SHA3_224: 28, - SHA3_256: 32, - SHA3_384: 48, - SHA3_512: 64, - MD5SHA1: 36, - RIPEMD160: 20, + MD4: 16, + MD5: 16, + SHA1: 20, + SHA224: 28, + SHA256: 32, + SHA384: 48, + SHA512: 64, + SHA512_224: 28, + SHA512_256: 32, + SHA3_224: 28, + SHA3_256: 32, + SHA3_384: 48, + SHA3_512: 64, + MD5SHA1: 36, + RIPEMD160: 20, + BLAKE2s_256: 32, + BLAKE2b_256: 32, + BLAKE2b_384: 48, + BLAKE2b_512: 64, } // Size returns the length, in bytes, of a digest resulting from the given hash diff --git a/libgo/go/crypto/des/block.go b/libgo/go/crypto/des/block.go index 99338d62a6e..21e6d4e82f6 100644 --- a/libgo/go/crypto/des/block.go +++ b/libgo/go/crypto/des/block.go @@ -4,25 +4,29 @@ package des -import ( - "encoding/binary" -) +import "encoding/binary" func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) { b := binary.BigEndian.Uint64(src) b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) - var subkey uint64 - for i := 0; i < 16; i++ { - if decrypt { - subkey = subkeys[15-i] - } else { - subkey = subkeys[i] - } + left = (left << 1) | (left >> 31) + right = (right << 1) | (right >> 31) - left, right = right, left^feistel(right, subkey) + if decrypt { + for i := 0; i < 8; i++ { + left, right = feistel(left, right, subkeys[15-2*i], subkeys[15-(2*i+1)]) + } + } else { + for i := 0; i < 8; i++ { + left, right = feistel(left, right, subkeys[2*i], subkeys[2*i+1]) + } } + + left = (left << 31) | (left >> 1) + right = (right << 31) | (right >> 1) + // switch left & right and perform final permutation preOutput := (uint64(right) << 32) | uint64(left) binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) @@ -39,19 +43,34 @@ func decryptBlock(subkeys []uint64, dst, src []byte) { } // DES Feistel function -func feistel(right uint32, key uint64) (result uint32) { - sBoxLocations := key ^ expandBlock(right) - var sBoxResult uint32 - for i := uint8(0); i < 8; i++ { - sBoxLocation := uint8(sBoxLocations>>42) & 0x3f - sBoxLocations <<= 6 - // row determined by 1st and 6th bit - // column is middle four bits - row := (sBoxLocation & 0x1) | ((sBoxLocation & 0x20) >> 4) - column := (sBoxLocation >> 1) & 0xf - sBoxResult ^= feistelBox[i][16*row+column] - } - return sBoxResult +func feistel(l, r uint32, k0, k1 uint64) (lout, rout uint32) { + var t uint32 + + t = r ^ uint32(k0>>32) + l ^= feistelBox[7][t&0x3f] ^ + feistelBox[5][(t>>8)&0x3f] ^ + feistelBox[3][(t>>16)&0x3f] ^ + feistelBox[1][(t>>24)&0x3f] + + t = ((r << 28) | (r >> 4)) ^ uint32(k0) + l ^= feistelBox[6][(t)&0x3f] ^ + feistelBox[4][(t>>8)&0x3f] ^ + feistelBox[2][(t>>16)&0x3f] ^ + feistelBox[0][(t>>24)&0x3f] + + t = l ^ uint32(k1>>32) + r ^= feistelBox[7][t&0x3f] ^ + feistelBox[5][(t>>8)&0x3f] ^ + feistelBox[3][(t>>16)&0x3f] ^ + feistelBox[1][(t>>24)&0x3f] + + t = ((l << 28) | (l >> 4)) ^ uint32(k1) + r ^= feistelBox[6][(t)&0x3f] ^ + feistelBox[4][(t>>8)&0x3f] ^ + feistelBox[2][(t>>16)&0x3f] ^ + feistelBox[0][(t>>24)&0x3f] + + return l, r } // feistelBox[s][16*i+j] contains the output of permutationFunction @@ -73,27 +92,22 @@ func init() { for j := 0; j < 16; j++ { f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s))) f = permuteBlock(f, permutationFunction[:]) - feistelBox[s][16*i+j] = uint32(f) + + // Row is determined by the 1st and 6th bit. + // Column is the middle four bits. + row := uint8(((i & 2) << 4) | i&1) + col := uint8(j << 1) + t := row | col + + // The rotation was performed in the feistel rounds, being factored out and now mixed into the feistelBox. + f = (f << 1) | (f >> 31) + + feistelBox[s][t] = uint32(f) } } } } -// expandBlock expands an input block of 32 bits, -// producing an output block of 48 bits. -func expandBlock(src uint32) (block uint64) { - // rotate the 5 highest bits to the right. - src = (src << 5) | (src >> 27) - for i := 0; i < 8; i++ { - block <<= 6 - // take the 6 bits on the right - block |= uint64(src) & (1<<6 - 1) - // advance by 4 bits. - src = (src << 4) | (src >> 28) - } - return -} - // permuteInitialBlock is equivalent to the permutation defined // by initialPermutation. func permuteInitialBlock(block uint64) uint64 { @@ -218,6 +232,24 @@ func (c *desCipher) generateSubkeys(keyBytes []byte) { // combine halves to form 56-bit input to PC2 pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i]) // apply PC2 permutation to 7 byte input - c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:]) + c.subkeys[i] = unpack(permuteBlock(pc2Input, permutedChoice2[:])) } } + +// Expand 48-bit input to 64-bit, with each 6-bit block padded by extra two bits at the top. +// By doing so, we can have the input blocks (four bits each), and the key blocks (six bits each) well-aligned without +// extra shifts/rotations for alignments. +func unpack(x uint64) uint64 { + var result uint64 + + result = ((x>>(6*1))&0xff)<<(8*0) | + ((x>>(6*3))&0xff)<<(8*1) | + ((x>>(6*5))&0xff)<<(8*2) | + ((x>>(6*7))&0xff)<<(8*3) | + ((x>>(6*0))&0xff)<<(8*4) | + ((x>>(6*2))&0xff)<<(8*5) | + ((x>>(6*4))&0xff)<<(8*6) | + ((x>>(6*6))&0xff)<<(8*7) + + return result +} diff --git a/libgo/go/crypto/des/cipher.go b/libgo/go/crypto/des/cipher.go index 2f929ca7bed..46af5b0f022 100644 --- a/libgo/go/crypto/des/cipher.go +++ b/libgo/go/crypto/des/cipher.go @@ -6,6 +6,7 @@ package des import ( "crypto/cipher" + "encoding/binary" "strconv" ) @@ -61,13 +62,51 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) { func (c *tripleDESCipher) BlockSize() int { return BlockSize } func (c *tripleDESCipher) Encrypt(dst, src []byte) { - c.cipher1.Encrypt(dst, src) - c.cipher2.Decrypt(dst, dst) - c.cipher3.Encrypt(dst, dst) + b := binary.BigEndian.Uint64(src) + b = permuteInitialBlock(b) + left, right := uint32(b>>32), uint32(b) + + left = (left << 1) | (left >> 31) + right = (right << 1) | (right >> 31) + + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher1.subkeys[2*i], c.cipher1.subkeys[2*i+1]) + } + for i := 0; i < 8; i++ { + right, left = feistel(right, left, c.cipher2.subkeys[15-2*i], c.cipher2.subkeys[15-(2*i+1)]) + } + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher3.subkeys[2*i], c.cipher3.subkeys[2*i+1]) + } + + left = (left << 31) | (left >> 1) + right = (right << 31) | (right >> 1) + + preOutput := (uint64(right) << 32) | uint64(left) + binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) } func (c *tripleDESCipher) Decrypt(dst, src []byte) { - c.cipher3.Decrypt(dst, src) - c.cipher2.Encrypt(dst, dst) - c.cipher1.Decrypt(dst, dst) + b := binary.BigEndian.Uint64(src) + b = permuteInitialBlock(b) + left, right := uint32(b>>32), uint32(b) + + left = (left << 1) | (left >> 31) + right = (right << 1) | (right >> 31) + + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher3.subkeys[15-2*i], c.cipher3.subkeys[15-(2*i+1)]) + } + for i := 0; i < 8; i++ { + right, left = feistel(right, left, c.cipher2.subkeys[2*i], c.cipher2.subkeys[2*i+1]) + } + for i := 0; i < 8; i++ { + left, right = feistel(left, right, c.cipher1.subkeys[15-2*i], c.cipher1.subkeys[15-(2*i+1)]) + } + + left = (left << 31) | (left >> 1) + right = (right << 31) | (right >> 1) + + preOutput := (uint64(right) << 32) | uint64(left) + binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) } diff --git a/libgo/go/crypto/des/const.go b/libgo/go/crypto/des/const.go index 2bd485ee80e..a20879d5741 100644 --- a/libgo/go/crypto/des/const.go +++ b/libgo/go/crypto/des/const.go @@ -5,6 +5,9 @@ // Package des implements the Data Encryption Standard (DES) and the // Triple Data Encryption Algorithm (TDEA) as defined // in U.S. Federal Information Processing Standards Publication 46-3. +// +// DES is cryptographically broken and should not be used for secure +// applications. package des // Used to perform an initial permutation of a 64-bit input block. diff --git a/libgo/go/crypto/des/des_test.go b/libgo/go/crypto/des/des_test.go index 2bd525afecc..690a49f5efb 100644 --- a/libgo/go/crypto/des/des_test.go +++ b/libgo/go/crypto/des/des_test.go @@ -1526,17 +1526,6 @@ func TestFinalPermute(t *testing.T) { } } -func TestExpandBlock(t *testing.T) { - for i := uint(0); i < 32; i++ { - bit := uint32(1) << i - got := expandBlock(bit) - want := permuteBlock(uint64(bit), expansionFunction[:]) - if got != want { - t.Errorf("expand(%x) = %x, want %x", bit, got, want) - } - } -} - func BenchmarkEncrypt(b *testing.B) { tt := encryptDESTests[0] c, err := NewCipher(tt.key) @@ -1564,3 +1553,31 @@ func BenchmarkDecrypt(b *testing.B) { c.Decrypt(out, tt.out) } } + +func BenchmarkTDESEncrypt(b *testing.B) { + tt := encryptTripleDESTests[0] + c, err := NewTripleDESCipher(tt.key) + if err != nil { + b.Fatal("NewCipher:", err) + } + out := make([]byte, len(tt.in)) + b.SetBytes(int64(len(out))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Encrypt(out, tt.in) + } +} + +func BenchmarkTDESDecrypt(b *testing.B) { + tt := encryptTripleDESTests[0] + c, err := NewTripleDESCipher(tt.key) + if err != nil { + b.Fatal("NewCipher:", err) + } + out := make([]byte, len(tt.out)) + b.SetBytes(int64(len(out))) + b.ResetTimer() + for i := 0; i < b.N; i++ { + c.Decrypt(out, tt.out) + } +} diff --git a/libgo/go/crypto/dsa/dsa_test.go b/libgo/go/crypto/dsa/dsa_test.go index 8600059f032..7fc246bc2bd 100644 --- a/libgo/go/crypto/dsa/dsa_test.go +++ b/libgo/go/crypto/dsa/dsa_test.go @@ -82,12 +82,17 @@ func fromHex(s string) *big.Int { } func TestSignAndVerify(t *testing.T) { - var priv PrivateKey - priv.P, _ = new(big.Int).SetString("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF", 16) - priv.Q, _ = new(big.Int).SetString("E1D3391245933D68A0714ED34BBCB7A1F422B9C1", 16) - priv.G, _ = new(big.Int).SetString("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA", 16) - priv.Y, _ = new(big.Int).SetString("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2", 16) - priv.X, _ = new(big.Int).SetString("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A", 16) + priv := PrivateKey{ + PublicKey: PublicKey{ + Parameters: Parameters{ + P: fromHex("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF"), + Q: fromHex("E1D3391245933D68A0714ED34BBCB7A1F422B9C1"), + G: fromHex("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA"), + }, + Y: fromHex("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2"), + }, + X: fromHex("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A"), + } testSignAndVerify(t, 0, &priv) } diff --git a/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go index ce58d5e713a..b682f008942 100644 --- a/libgo/go/crypto/md5/md5.go +++ b/libgo/go/crypto/md5/md5.go @@ -5,6 +5,9 @@ //go:generate go run gen.go -full -output md5block.go // Package md5 implements the MD5 hash algorithm as defined in RFC 1321. +// +// MD5 is cryptographically broken and should not be used for secure +// applications. package md5 import ( diff --git a/libgo/go/crypto/rand/rand_linux.go b/libgo/go/crypto/rand/rand_linux.go index 472daa7650b..8a4c7572363 100644 --- a/libgo/go/crypto/rand/rand_linux.go +++ b/libgo/go/crypto/rand/rand_linux.go @@ -6,34 +6,20 @@ package rand import ( "internal/syscall/unix" - "sync" ) func init() { altGetRandom = getRandomLinux } -var ( - once sync.Once - useSyscall bool -) - -func pickStrategy() { - // Test whether we should use the system call or /dev/urandom. - // We'll fall back to urandom if: - // - the kernel is too old (before 3.17) - // - the machine has no entropy available (early boot + no hardware - // entropy source?) and we want to avoid blocking later. - var buf [1]byte - n, err := unix.GetRandom(buf[:], unix.GRND_NONBLOCK) - useSyscall = n == 1 && err == nil -} - +// If the kernel is too old (before 3.17) to support the getrandom syscall(), +// unix.GetRandom will immediately return ENOSYS and we will then fall back to +// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS +// result so we only suffer the syscall overhead once in this case. +// If the kernel supports the getrandom() syscall, unix.GetRandom will block +// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK). +// In this case, unix.GetRandom will not return an error. func getRandomLinux(p []byte) (ok bool) { - once.Do(pickStrategy) - if !useSyscall { - return false - } n, err := unix.GetRandom(p, 0) return n == len(p) && err == nil } diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go index 592c57e7638..4dd17112034 100644 --- a/libgo/go/crypto/rand/util.go +++ b/libgo/go/crypto/rand/util.go @@ -107,16 +107,23 @@ func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) { if max.Sign() <= 0 { panic("crypto/rand: argument to Int is <= 0") } - k := (max.BitLen() + 7) / 8 - - // b is the number of bits in the most significant byte of max. - b := uint(max.BitLen() % 8) + n = new(big.Int) + n.Sub(max, n.SetUint64(1)) + // bitLen is the maximum bit length needed to encode a value < max. + bitLen := n.BitLen() + if bitLen == 0 { + // the only valid result is 0 + return + } + // k is the maximum byte length needed to encode a value < max. + k := (bitLen + 7) / 8 + // b is the number of bits in the most significant byte of max-1. + b := uint(bitLen % 8) if b == 0 { b = 8 } bytes := make([]byte, k) - n = new(big.Int) for { _, err = io.ReadFull(rand, bytes) diff --git a/libgo/go/crypto/rand/util_test.go b/libgo/go/crypto/rand/util_test.go index 48a2c3fc0cb..685624e1b3d 100644 --- a/libgo/go/crypto/rand/util_test.go +++ b/libgo/go/crypto/rand/util_test.go @@ -5,7 +5,10 @@ package rand_test import ( + "bytes" "crypto/rand" + "fmt" + "io" "math/big" mathrand "math/rand" "testing" @@ -45,6 +48,56 @@ func TestInt(t *testing.T) { } } +type countingReader struct { + r io.Reader + n int +} + +func (r *countingReader) Read(p []byte) (n int, err error) { + n, err = r.r.Read(p) + r.n += n + return n, err +} + +// Test that Int reads only the necessary number of bytes from the reader for +// max at each bit length +func TestIntReads(t *testing.T) { + for i := 0; i < 32; i++ { + max := int64(1 << uint64(i)) + t.Run(fmt.Sprintf("max=%d", max), func(t *testing.T) { + reader := &countingReader{r: rand.Reader} + + _, err := rand.Int(reader, big.NewInt(max)) + if err != nil { + t.Fatalf("Can't generate random value: %d, %v", max, err) + } + expected := (i + 7) / 8 + if reader.n != expected { + t.Errorf("Int(reader, %d) should read %d bytes, but it read: %d", max, expected, reader.n) + } + }) + } +} + +// Test that Int does not mask out valid return values +func TestIntMask(t *testing.T) { + for max := 1; max <= 256; max++ { + t.Run(fmt.Sprintf("max=%d", max), func(t *testing.T) { + for i := 0; i < max; i++ { + var b bytes.Buffer + b.WriteByte(byte(i)) + n, err := rand.Int(&b, big.NewInt(int64(max))) + if err != nil { + t.Fatalf("Can't generate random value: %d, %v", max, err) + } + if n.Int64() != int64(i) { + t.Errorf("Int(reader, %d) should have returned value of %d, but it returned: %v", max, i, n) + } + } + }) + } +} + func testIntPanics(t *testing.T, b *big.Int) { defer func() { if err := recover(); err == nil { diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go index bd04aee6955..772af0e7e0d 100644 --- a/libgo/go/crypto/rc4/rc4.go +++ b/libgo/go/crypto/rc4/rc4.go @@ -4,11 +4,11 @@ // Package rc4 implements RC4 encryption, as defined in Bruce Schneier's // Applied Cryptography. +// +// RC4 is cryptographically broken and should not be used for secure +// applications. package rc4 -// BUG(agl): RC4 is in common use but has design weaknesses that make -// it a poor choice for new protocols. - import "strconv" // A Cipher is an instance of RC4 using a particular key. diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go index fbb2f946132..6b1721470b2 100644 --- a/libgo/go/crypto/sha1/sha1.go +++ b/libgo/go/crypto/sha1/sha1.go @@ -2,7 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Package sha1 implements the SHA1 hash algorithm as defined in RFC 3174. +// Package sha1 implements the SHA-1 hash algorithm as defined in RFC 3174. +// +// SHA-1 is cryptographically broken and should not be used for secure +// applications. package sha1 import ( @@ -14,10 +17,10 @@ func init() { crypto.RegisterHash(crypto.SHA1, New) } -// The size of a SHA1 checksum in bytes. +// The size of a SHA-1 checksum in bytes. const Size = 20 -// The blocksize of SHA1 in bytes. +// The blocksize of SHA-1 in bytes. const BlockSize = 64 const ( @@ -189,7 +192,7 @@ func (d *digest) constSum() [Size]byte { return digest } -// Sum returns the SHA1 checksum of the data. +// Sum returns the SHA-1 checksum of the data. func Sum(data []byte) [Size]byte { var d digest d.Reset() diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go index 3e59a5defe3..faa9916bc06 100644 --- a/libgo/go/crypto/sha1/sha1_test.go +++ b/libgo/go/crypto/sha1/sha1_test.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// SHA1 hash algorithm. See RFC 3174. +// SHA-1 hash algorithm. See RFC 3174. package sha1 diff --git a/libgo/go/crypto/sha1/sha1block.go b/libgo/go/crypto/sha1/sha1block.go index fde3c981c08..1d37544940f 100644 --- a/libgo/go/crypto/sha1/sha1block.go +++ b/libgo/go/crypto/sha1/sha1block.go @@ -11,7 +11,7 @@ const ( _K3 = 0xCA62C1D6 ) -// blockGeneric is a portable, pure Go version of the SHA1 block step. +// blockGeneric is a portable, pure Go version of the SHA-1 block step. // It's used by sha1block_generic.go and tests. func blockGeneric(dig *digest, p []byte) { var w [16]uint32 diff --git a/libgo/go/crypto/sha1/sha1block_amd64.go b/libgo/go/crypto/sha1/sha1block_amd64.go index 8ef8b1faffc..2d7a314d51d 100644 --- a/libgo/go/crypto/sha1/sha1block_amd64.go +++ b/libgo/go/crypto/sha1/sha1block_amd64.go @@ -6,18 +6,18 @@ package sha1 -//go:noescape +import "internal/cpu" +//go:noescape func blockAVX2(dig *digest, p []byte) //go:noescape func blockAMD64(dig *digest, p []byte) -func checkAVX2() bool -var hasAVX2 = checkAVX2() +var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI1 && cpu.X86.HasBMI2 func block(dig *digest, p []byte) { - if hasAVX2 && len(p) >= 256 { + if useAVX2 && len(p) >= 256 { // blockAVX2 calculates sha1 for 2 block per iteration // it also interleaves precalculation for next block. // So it may read up-to 192 bytes past end of p diff --git a/libgo/go/crypto/sha1/sha1block_s390x.go b/libgo/go/crypto/sha1/sha1block_s390x.go index 9edcbb0d4b4..55a23599a97 100644 --- a/libgo/go/crypto/sha1/sha1block_s390x.go +++ b/libgo/go/crypto/sha1/sha1block_s390x.go @@ -7,7 +7,7 @@ package sha1 // featureCheck reports whether the CPU supports the -// SHA1 compute intermediate message digest (KIMD) +// SHA-1 compute intermediate message digest (KIMD) // function code. func featureCheck() bool diff --git a/libgo/go/crypto/sha256/sha256block_amd64.go b/libgo/go/crypto/sha256/sha256block_amd64.go new file mode 100644 index 00000000000..b311a125c98 --- /dev/null +++ b/libgo/go/crypto/sha256/sha256block_amd64.go @@ -0,0 +1,11 @@ +// 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. + +// +build ignore + +package sha256 + +import "internal/cpu" + +var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2 diff --git a/libgo/go/crypto/sha512/sha512block_amd64.go b/libgo/go/crypto/sha512/sha512block_amd64.go new file mode 100644 index 00000000000..0ce599b8ebc --- /dev/null +++ b/libgo/go/crypto/sha512/sha512block_amd64.go @@ -0,0 +1,26 @@ +// Copyright 2013 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. + +// +build ignore +// +build amd64 + +package sha512 + +import "internal/cpu" + +//go:noescape +func blockAVX2(dig *digest, p []byte) + +//go:noescape +func blockAMD64(dig *digest, p []byte) + +var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI1 && cpu.X86.HasBMI2 + +func block(dig *digest, p []byte) { + if useAVX2 { + blockAVX2(dig, p) + } else { + blockAMD64(dig, p) + } +} diff --git a/libgo/go/crypto/sha512/sha512block_decl.go b/libgo/go/crypto/sha512/sha512block_decl.go index 3859a40e328..3d098c5b17e 100644 --- a/libgo/go/crypto/sha512/sha512block_decl.go +++ b/libgo/go/crypto/sha512/sha512block_decl.go @@ -3,7 +3,7 @@ // license that can be found in the LICENSE file. // +build ignore -// +build amd64 s390x ppc64le +// +build s390x ppc64le package sha512 diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index de833a90563..5860838dd25 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -163,8 +163,8 @@ type ConnectionState struct { HandshakeComplete bool // TLS handshake is complete DidResume bool // connection resumes a previous TLS connection CipherSuite uint16 // cipher suite in use (TLS_RSA_WITH_RC4_128_SHA, ...) - NegotiatedProtocol string // negotiated next protocol (from Config.NextProtos) - NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server + NegotiatedProtocol string // negotiated next protocol (not guaranteed to be from Config.NextProtos) + NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server (client side only) ServerName string // server name requested by client, if any (server side only) PeerCertificates []*x509.Certificate // certificate chain presented by remote peer VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates @@ -174,9 +174,9 @@ type ConnectionState struct { // TLSUnique contains the "tls-unique" channel binding value (see RFC // 5929, section 3). For resumed sessions this value will be nil // because resumption does not include enough context (see - // https://secure-resumption.com/#channelbindings). This will change in - // future versions of Go once the TLS master-secret fix has been - // standardized and implemented. + // https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will + // change in future versions of Go once the TLS master-secret fix has + // been standardized and implemented. TLSUnique []byte } @@ -206,7 +206,8 @@ type ClientSessionState struct { // ClientSessionCache is a cache of ClientSessionState objects that can be used // by a client to resume a TLS session with a given server. ClientSessionCache // implementations should expect to be called concurrently from different -// goroutines. +// goroutines. Only ticket-based resumption is supported, not SessionID-based +// resumption. type ClientSessionCache interface { // Get searches for a ClientSessionState associated with the given key. // On return, ok is true if one was found. @@ -508,17 +509,13 @@ type Config struct { serverInitOnce sync.Once // guards calling (*Config).serverInit - // mutex protects sessionTicketKeys and originalConfig. + // mutex protects sessionTicketKeys. mutex sync.RWMutex // sessionTicketKeys contains zero or more ticket keys. If the length // is zero, SessionTicketsDisabled must be true. The first key is used // for new tickets and any subsequent keys can be used to decrypt old // tickets. sessionTicketKeys []ticketKey - // originalConfig is set to the Config that was passed to Server if - // this Config is returned by a GetConfigForClient callback. It's used - // by serverInit in order to copy session ticket keys if needed. - originalConfig *Config } // ticketKeyNameLen is the number of bytes of identifier that is prepended to @@ -550,7 +547,7 @@ func ticketKeyFromBytes(b [32]byte) (key ticketKey) { func (c *Config) Clone() *Config { // Running serverInit ensures that it's safe to read // SessionTicketsDisabled. - c.serverInitOnce.Do(c.serverInit) + c.serverInitOnce.Do(func() { c.serverInit(nil) }) var sessionTicketKeys []ticketKey c.mutex.RLock() @@ -584,20 +581,17 @@ func (c *Config) Clone() *Config { Renegotiation: c.Renegotiation, KeyLogWriter: c.KeyLogWriter, sessionTicketKeys: sessionTicketKeys, - // originalConfig is deliberately not duplicated. } } -func (c *Config) serverInit() { +// serverInit is run under c.serverInitOnce to do initialization of c. If c was +// returned by a GetConfigForClient callback then the argument should be the +// Config that was passed to Server, otherwise it should be nil. +func (c *Config) serverInit(originalConfig *Config) { if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 { return } - var originalConfig *Config - c.mutex.Lock() - originalConfig, c.originalConfig = c.originalConfig, nil - c.mutex.Unlock() - alreadySet := false for _, b := range c.SessionTicketKey { if b != 0 { @@ -947,9 +941,7 @@ func initDefaultCipherSuites() { } varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites)) - for _, topCipher := range topCipherSuites { - varDefaultCipherSuites = append(varDefaultCipherSuites, topCipher) - } + varDefaultCipherSuites = append(varDefaultCipherSuites, topCipherSuites...) NextCipherSuite: for _, suite := range cipherSuites { diff --git a/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go index 03895a723fa..e6d85aa2639 100644 --- a/libgo/go/crypto/tls/conn.go +++ b/libgo/go/crypto/tls/conn.go @@ -1206,10 +1206,10 @@ func (c *Conn) Close() error { var alertErr error c.handshakeMutex.Lock() - defer c.handshakeMutex.Unlock() if c.handshakeComplete { alertErr = c.closeNotify() } + c.handshakeMutex.Unlock() if err := c.conn.Close(); err != nil { return err diff --git a/libgo/go/crypto/tls/conn_test.go b/libgo/go/crypto/tls/conn_test.go index 5e5c7a2e96e..e27c5414b22 100644 --- a/libgo/go/crypto/tls/conn_test.go +++ b/libgo/go/crypto/tls/conn_test.go @@ -138,7 +138,7 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) { tlsConn := Client(clientConn, config) if err := tlsConn.Handshake(); err != nil { - t.Errorf("Error from client handshake: %s", err) + t.Errorf("Error from client handshake: %v", err) return } @@ -147,12 +147,12 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) { var recordSizes []int for { - n, err := clientConn.Read(recordHeader[:]) + n, err := io.ReadFull(clientConn, recordHeader[:]) if err == io.EOF { break } if err != nil || n != len(recordHeader) { - t.Errorf("Error from client read: %s", err) + t.Errorf("io.ReadFull = %d, %v", n, err) return } @@ -161,9 +161,9 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) { record = make([]byte, length) } - n, err = clientConn.Read(record[:length]) + n, err = io.ReadFull(clientConn, record[:length]) if err != nil || n != length { - t.Errorf("Error from client read: %s", err) + t.Errorf("io.ReadFull = %d, %v", n, err) return } @@ -241,3 +241,34 @@ func TestDynamicRecordSizingWithAEAD(t *testing.T) { config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256} runDynamicRecordSizingTest(t, config) } + +// hairpinConn is a net.Conn that makes a “hairpin” call when closed, back into +// the tls.Conn which is calling it. +type hairpinConn struct { + net.Conn + tlsConn *Conn +} + +func (conn *hairpinConn) Close() error { + conn.tlsConn.ConnectionState() + return nil +} + +func TestHairpinInClose(t *testing.T) { + // This tests that the underlying net.Conn can call back into the + // tls.Conn when being closed without deadlocking. + client, server := net.Pipe() + defer server.Close() + defer client.Close() + + conn := &hairpinConn{client, nil} + tlsConn := Server(conn, &Config{ + GetCertificate: func(*ClientHelloInfo) (*Certificate, error) { + panic("unreachable") + }, + }) + conn.tlsConn = tlsConn + + // This call should not deadlock. + tlsConn.Close() +} diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go index 83f9916ff9d..8ee2b5922b3 100644 --- a/libgo/go/crypto/tls/generate_cert.go +++ b/libgo/go/crypto/tls/generate_cert.go @@ -33,7 +33,7 @@ var ( validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for") isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority") rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set") - ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256, P384, P521") + ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521") ) func publicKey(priv interface{}) interface{} { diff --git a/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index 6eda18dbfce..a4ca5d34fb8 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/crypto/tls/handshake_client.go @@ -815,7 +815,7 @@ func hostnameInSNI(name string) string { if net.ParseIP(host) != nil { return "" } - if len(name) > 0 && name[len(name)-1] == '.' { + for len(name) > 0 && name[len(name)-1] == '.' { name = name[:len(name)-1] } return name diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go index 694bd918d85..0c7581f3e36 100644 --- a/libgo/go/crypto/tls/handshake_messages.go +++ b/libgo/go/crypto/tls/handshake_messages.go @@ -4,7 +4,10 @@ package tls -import "bytes" +import ( + "bytes" + "strings" +) type clientHelloMsg struct { raw []byte @@ -393,6 +396,12 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { } if nameType == 0 { m.serverName = string(d[:nameLen]) + // An SNI value may not include a + // trailing dot. See + // https://tools.ietf.org/html/rfc6066#section-3. + if strings.HasSuffix(m.serverName, ".") { + return false + } break } d = d[nameLen:] diff --git a/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go index f1154d4d01d..7add97c32c1 100644 --- a/libgo/go/crypto/tls/handshake_messages_test.go +++ b/libgo/go/crypto/tls/handshake_messages_test.go @@ -8,6 +8,7 @@ import ( "bytes" "math/rand" "reflect" + "strings" "testing" "testing/quick" ) @@ -123,6 +124,9 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { } if rand.Intn(10) > 5 { m.serverName = randomString(rand.Intn(255), rand) + for strings.HasSuffix(m.serverName, ".") { + m.serverName = m.serverName[:len(m.serverName)-1] + } } m.ocspStapling = rand.Intn(10) > 5 m.supportedPoints = randomBytes(rand.Intn(5)+1, rand) diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index b786c3083a2..ae328487088 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/crypto/tls/handshake_server.go @@ -40,7 +40,7 @@ type serverHandshakeState struct { func (c *Conn) serverHandshake() error { // If this is the first server handshake, we generate a random key to // encrypt the tickets with. - c.config.serverInitOnce.Do(c.config.serverInit) + c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) }) hs := serverHandshakeState{ c: c, @@ -129,11 +129,7 @@ func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { c.sendAlert(alertInternalError) return false, err } else if newConfig != nil { - newConfig.mutex.Lock() - newConfig.originalConfig = c.config - newConfig.mutex.Unlock() - - newConfig.serverInitOnce.Do(newConfig.serverInit) + newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) }) c.config = newConfig } } diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go index bcd3d43ea3c..63845c170d7 100644 --- a/libgo/go/crypto/tls/handshake_server_test.go +++ b/libgo/go/crypto/tls/handshake_server_test.go @@ -137,6 +137,10 @@ func TestNoRC4ByDefault(t *testing.T) { testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server") } +func TestRejectSNIWithTrailingDot(t *testing.T) { + testClientHelloFailure(t, testConfig, &clientHelloMsg{vers: VersionTLS12, serverName: "foo.com."}, "unexpected message") +} + func TestDontSelectECDSAWithRSAKey(t *testing.T) { // Test that, even when both sides support an ECDSA cipher suite, it // won't be selected if the server's private key doesn't support it. diff --git a/libgo/go/crypto/x509/pkcs1.go b/libgo/go/crypto/x509/pkcs1.go index df20a442049..73bc7623a5a 100644 --- a/libgo/go/crypto/x509/pkcs1.go +++ b/libgo/go/crypto/x509/pkcs1.go @@ -35,6 +35,12 @@ type pkcs1AdditionalRSAPrime struct { Coeff *big.Int } +// pkcs1PublicKey reflects the ASN.1 structure of a PKCS#1 public key. +type pkcs1PublicKey struct { + N *big.Int + E int +} + // ParsePKCS1PrivateKey returns an RSA private key from its ASN.1 PKCS#1 DER encoded form. func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) { var priv pkcs1PrivateKey @@ -113,9 +119,3 @@ func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte { b, _ := asn1.Marshal(priv) return b } - -// rsaPublicKey reflects the ASN.1 structure of a PKCS#1 public key. -type rsaPublicKey struct { - N *big.Int - E int -} diff --git a/libgo/go/crypto/x509/root_bsd.go b/libgo/go/crypto/x509/root_bsd.go index 93172837368..13719338910 100644 --- a/libgo/go/crypto/x509/root_bsd.go +++ b/libgo/go/crypto/x509/root_bsd.go @@ -8,7 +8,8 @@ package x509 // Possible certificate files; stop after finding one. var certFiles = []string{ - "/usr/local/share/certs/ca-root-nss.crt", // FreeBSD/DragonFly + "/usr/local/etc/ssl/cert.pem", // FreeBSD "/etc/ssl/cert.pem", // OpenBSD + "/usr/local/share/certs/ca-root-nss.crt", // DragonFly "/etc/openssl/certs/ca-certificates.crt", // NetBSD } diff --git a/libgo/go/crypto/x509/root_darwin.go b/libgo/go/crypto/x509/root_darwin.go index 66cdb5ea261..bc35a1cf212 100644 --- a/libgo/go/crypto/x509/root_darwin.go +++ b/libgo/go/crypto/x509/root_darwin.go @@ -16,6 +16,7 @@ import ( "io/ioutil" "os" "os/exec" + "os/user" "path/filepath" "strings" "sync" @@ -61,7 +62,26 @@ func execSecurityRoots() (*CertPool, error) { println(fmt.Sprintf("crypto/x509: %d certs have a trust policy", len(hasPolicy))) } - cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain") + args := []string{"find-certificate", "-a", "-p", + "/System/Library/Keychains/SystemRootCertificates.keychain", + "/Library/Keychains/System.keychain", + } + + u, err := user.Current() + if err != nil { + if debugExecDarwinRoots { + println(fmt.Sprintf("crypto/x509: get current user: %v", err)) + } + } else { + args = append(args, + filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain"), + + // Fresh installs of Sierra use a slightly different path for the login keychain + filepath.Join(u.HomeDir, "/Library/Keychains/login.keychain-db"), + ) + } + + cmd := exec.Command("/usr/bin/security", args...) data, err := cmd.Output() if err != nil { return nil, err diff --git a/libgo/go/crypto/x509/root_unix.go b/libgo/go/crypto/x509/root_unix.go index c44a5241685..0547460437b 100644 --- a/libgo/go/crypto/x509/root_unix.go +++ b/libgo/go/crypto/x509/root_unix.go @@ -16,28 +16,52 @@ import ( var certDirectories = []string{ "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139 "/system/etc/security/cacerts", // Android + "/usr/local/share/certs", // FreeBSD + "/etc/pki/tls/certs", // Fedora/RHEL + "/etc/openssl/certs", // NetBSD "/var/ssl/certs", // AIX } +const ( + // certFileEnv is the environment variable which identifies where to locate + // the SSL certificate file. If set this overrides the system default. + certFileEnv = "SSL_CERT_FILE" + + // certDirEnv is the environment variable which identifies which directory + // to check for SSL certificate files. If set this overrides the system default. + certDirEnv = "SSL_CERT_DIR" +) + func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { return nil, nil } func loadSystemRoots() (*CertPool, error) { roots := NewCertPool() + + files := certFiles + if f := os.Getenv(certFileEnv); f != "" { + files = []string{f} + } + var firstErr error - for _, file := range certFiles { + for _, file := range files { data, err := ioutil.ReadFile(file) if err == nil { roots.AppendCertsFromPEM(data) - return roots, nil + break } if firstErr == nil && !os.IsNotExist(err) { firstErr = err } } - for _, directory := range certDirectories { + dirs := certDirectories + if d := os.Getenv(certDirEnv); d != "" { + dirs = []string{d} + } + + for _, directory := range dirs { fis, err := ioutil.ReadDir(directory) if err != nil { if firstErr == nil && !os.IsNotExist(err) { @@ -57,5 +81,9 @@ func loadSystemRoots() (*CertPool, error) { } } + if len(roots.certs) > 0 { + return roots, nil + } + return nil, firstErr } diff --git a/libgo/go/crypto/x509/root_unix_test.go b/libgo/go/crypto/x509/root_unix_test.go new file mode 100644 index 00000000000..03f935d4e82 --- /dev/null +++ b/libgo/go/crypto/x509/root_unix_test.go @@ -0,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. + +// +build dragonfly freebsd linux netbsd openbsd solaris + +package x509 + +import ( + "fmt" + "os" + "testing" +) + +const ( + testDir = "testdata" + testDirCN = "test-dir" + testFile = "test-file.crt" + testFileCN = "test-file" + testMissing = "missing" +) + +func TestEnvVars(t *testing.T) { + testCases := []struct { + name string + fileEnv string + dirEnv string + files []string + dirs []string + cns []string + }{ + { + // Environment variables override the default locations preventing fall through. + name: "override-defaults", + fileEnv: testMissing, + dirEnv: testMissing, + files: []string{testFile}, + dirs: []string{testDir}, + cns: nil, + }, + { + // File environment overrides default file locations. + name: "file", + fileEnv: testFile, + dirEnv: "", + files: nil, + dirs: nil, + cns: []string{testFileCN}, + }, + { + // Directory environment overrides default directory locations. + name: "dir", + fileEnv: "", + dirEnv: testDir, + files: nil, + dirs: nil, + cns: []string{testDirCN}, + }, + { + // File & directory environment overrides both default locations. + name: "file+dir", + fileEnv: testFile, + dirEnv: testDir, + files: nil, + dirs: nil, + cns: []string{testFileCN, testDirCN}, + }, + { + // Environment variable empty / unset uses default locations. + name: "empty-fall-through", + fileEnv: "", + dirEnv: "", + files: []string{testFile}, + dirs: []string{testDir}, + cns: []string{testFileCN, testDirCN}, + }, + } + + // Save old settings so we can restore before the test ends. + origCertFiles, origCertDirectories := certFiles, certDirectories + origFile, origDir := os.Getenv(certFileEnv), os.Getenv(certDirEnv) + defer func() { + certFiles = origCertFiles + certDirectories = origCertDirectories + os.Setenv(certFileEnv, origFile) + os.Setenv(certDirEnv, origDir) + }() + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + if err := os.Setenv(certFileEnv, tc.fileEnv); err != nil { + t.Fatalf("setenv %q failed: %v", certFileEnv, err) + } + if err := os.Setenv(certDirEnv, tc.dirEnv); err != nil { + t.Fatalf("setenv %q failed: %v", certDirEnv, err) + } + + certFiles, certDirectories = tc.files, tc.dirs + + r, err := loadSystemRoots() + if err != nil { + t.Fatal("unexpected failure:", err) + } + + if r == nil { + if tc.cns == nil { + // Expected nil + return + } + t.Fatal("nil roots") + } + + // Verify that the returned certs match, otherwise report where the mismatch is. + for i, cn := range tc.cns { + if i >= len(r.certs) { + t.Errorf("missing cert %v @ %v", cn, i) + } else if r.certs[i].Subject.CommonName != cn { + fmt.Printf("%#v\n", r.certs[0].Subject) + t.Errorf("unexpected cert common name %q, want %q", r.certs[i].Subject.CommonName, cn) + } + } + if len(r.certs) > len(tc.cns) { + t.Errorf("got %v certs, which is more than %v wanted", len(r.certs), len(tc.cns)) + } + }) + } +} diff --git a/libgo/go/crypto/x509/test-file.crt b/libgo/go/crypto/x509/test-file.crt new file mode 100644 index 00000000000..caa83b9f824 --- /dev/null +++ b/libgo/go/crypto/x509/test-file.crt @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFbTCCA1WgAwIBAgIJAN338vEmMtLsMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV +BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz +dHMxEjAQBgNVBAMMCXRlc3QtZmlsZTAeFw0xNzAyMDEyMzUyMDhaFw0yNzAxMzAy +MzUyMDhaME0xCzAJBgNVBAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYD +VQQKDAxHb2xhbmcgVGVzdHMxEjAQBgNVBAMMCXRlc3QtZmlsZTCCAiIwDQYJKoZI +hvcNAQEBBQADggIPADCCAgoCggIBAPMGiLjdiffQo3Xc8oUe7wsDhSaAJFOhO6Qs +i0xYrYl7jmCuz9rGD2fdgk5cLqGazKuQ6fIFzHXFU2BKs4CWXt9KO0KFEhfvZeuW +jG5d7C1ZUiuKOrPqjKVu8SZtFPc7y7Ke7msXzY+Z2LLyiJJ93LCMq4+cTSGNXVlI +KqUxhxeoD5/QkUPyQy/ilu3GMYfx/YORhDP6Edcuskfj8wRh1UxBejP8YPMvI6St +cE2GkxoEGqDWnQ/61F18te6WI3MD29tnKXOkXVhnSC+yvRLljotW2/tAhHKBG4tj +iQWT5Ri4Wrw2tXxPKRLsVWc7e1/hdxhnuvYpXkWNhKsm002jzkFXlzfEwPd8nZdw +5aT6gPUBN2AAzdoqZI7E200i0orEF7WaSoMfjU1tbHvExp3vyAPOfJ5PS2MQ6W03 +Zsy5dTVH+OBH++rkRzQCFcnIv/OIhya5XZ9KX9nFPgBEP7Xq2A+IjH7B6VN/S/bv +8lhp2V+SQvlew9GttKC4hKuPsl5o7+CMbcqcNUdxm9gGkN8epGEKCuix97bpNlxN +fHZxHE5+8GMzPXMkCD56y5TNKR6ut7JGHMPtGl5lPCLqzG/HzYyFgxsDfDUu2B0A +GKj0lGpnLfGqwhs2/s3jpY7+pcvVQxEpvVTId5byDxu1ujP4HjO/VTQ2P72rE8Ft +C6J2Av0tAgMBAAGjUDBOMB0GA1UdDgQWBBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAf +BgNVHSMEGDAWgBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAMBgNVHRMEBTADAQH/MA0G +CSqGSIb3DQEBCwUAA4ICAQB3sCntCcQwhMgRPPyvOCMyTcQ/Iv+cpfxz2Ck14nlx +AkEAH2CH0ov5GWTt07/ur3aa5x+SAKi0J3wTD1cdiw4U/6Uin6jWGKKxvoo4IaeK +SbM8w/6eKx6UbmHx7PA/eRABY9tTlpdPCVgw7/o3WDr03QM+IAtatzvaCPPczake +pbdLwmBZB/v8V+6jUajy6jOgdSH0PyffGnt7MWgDETmNC6p/Xigp5eh+C8Fb4NGT +xgHES5PBC+sruWp4u22bJGDKTvYNdZHsnw/CaKQWNsQqwisxa3/8N5v+PCff/pxl +r05pE3PdHn9JrCl4iWdVlgtiI9BoPtQyDfa/OEFaScE8KYR8LxaAgdgp3zYncWls +BpwQ6Y/A2wIkhlD9eEp5Ib2hz7isXOs9UwjdriKqrBXqcIAE5M+YIk3+KAQKxAtd +4YsK3CSJ010uphr12YKqlScj4vuKFjuOtd5RyyMIxUG3lrrhAu2AzCeKCLdVgA8+ +75FrYMApUdvcjp4uzbBoED4XRQlx9kdFHVbYgmE/+yddBYJM8u4YlgAL0hW2/D8p +z9JWIfxVmjJnBnXaKGBuiUyZ864A3PJndP6EMMo7TzS2CDnfCYuJjvI0KvDjFNmc +rQA04+qfMSEz3nmKhbbZu4eYLzlADhfH8tT4GMtXf71WLA5AUHGf2Y4+HIHTsmHG +vQ== +-----END CERTIFICATE----- diff --git a/libgo/go/crypto/x509/testdata/test-dir.crt b/libgo/go/crypto/x509/testdata/test-dir.crt new file mode 100644 index 00000000000..b7fc9c51861 --- /dev/null +++ b/libgo/go/crypto/x509/testdata/test-dir.crt @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIJAL8a/lsnspOqMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV +BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz +dHMxETAPBgNVBAMMCHRlc3QtZGlyMB4XDTE3MDIwMTIzNTAyN1oXDTI3MDEzMDIz +NTAyN1owTDELMAkGA1UEBhMCVUsxEzARBgNVBAgMClRlc3QtU3RhdGUxFTATBgNV +BAoMDEdvbGFuZyBUZXN0czERMA8GA1UEAwwIdGVzdC1kaXIwggIiMA0GCSqGSIb3 +DQEBAQUAA4ICDwAwggIKAoICAQDzBoi43Yn30KN13PKFHu8LA4UmgCRToTukLItM +WK2Je45grs/axg9n3YJOXC6hmsyrkOnyBcx1xVNgSrOAll7fSjtChRIX72Xrloxu +XewtWVIrijqz6oylbvEmbRT3O8uynu5rF82Pmdiy8oiSfdywjKuPnE0hjV1ZSCql +MYcXqA+f0JFD8kMv4pbtxjGH8f2DkYQz+hHXLrJH4/MEYdVMQXoz/GDzLyOkrXBN +hpMaBBqg1p0P+tRdfLXuliNzA9vbZylzpF1YZ0gvsr0S5Y6LVtv7QIRygRuLY4kF +k+UYuFq8NrV8TykS7FVnO3tf4XcYZ7r2KV5FjYSrJtNNo85BV5c3xMD3fJ2XcOWk ++oD1ATdgAM3aKmSOxNtNItKKxBe1mkqDH41NbWx7xMad78gDznyeT0tjEOltN2bM +uXU1R/jgR/vq5Ec0AhXJyL/ziIcmuV2fSl/ZxT4ARD+16tgPiIx+welTf0v27/JY +adlfkkL5XsPRrbSguISrj7JeaO/gjG3KnDVHcZvYBpDfHqRhCgrosfe26TZcTXx2 +cRxOfvBjMz1zJAg+esuUzSkerreyRhzD7RpeZTwi6sxvx82MhYMbA3w1LtgdABio +9JRqZy3xqsIbNv7N46WO/qXL1UMRKb1UyHeW8g8btboz+B4zv1U0Nj+9qxPBbQui +dgL9LQIDAQABo1AwTjAdBgNVHQ4EFgQUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwHwYD +VR0jBBgwFoAUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwDAYDVR0TBAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAvEVnUYsIOt87rggmLPqEueynkuQ+562M8EDHSQl82zbe +xDCxeg3DvPgKb+RvaUdt1362z/szK10SoeMgx6+EQLoV9LiVqXwNqeYfixrhrdw3 +ppAhYYhymdkbUQCEMHypmXP1vPhAz4o8Bs+eES1M+zO6ErBiD7SqkmBElT+GixJC +6epC9ZQFs+dw3lPlbiZSsGE85sqc3VAs0/JgpL/pb1/Eg4s0FUhZD2C2uWdSyZGc +g0/v3aXJCp4j/9VoNhI1WXz3M45nysZIL5OQgXymLqJElQa1pZ3Wa4i/nidvT4AT +Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt +3UFGzYXDjxYnK2frQfjLS8stOQIqSrGthW6x0fdkVx0y8BByvd5J6+JmZl4UZfzA +m99VxXSt4B9x6BvnY7ktzcFDOjtuLc4B/7yg9fv1eQuStA4cHGGAttsCg1X/Kx8W +PvkkeH0UWDZ9vhH9K36703z89da6MWF+bz92B0+4HoOmlVaXRkvblsNaynJnL0LC +Ayry7QBxuh5cMnDdRwJB3AVJIiJ1GVpb7aGvBOnx+s2lwRv9HWtghb+cbwwktx1M +JHyBf3GZNSWTpKY7cD8V+NnBv3UuioOVVo+XAU4LF/bYUjdRpxWADJizNtZrtFo= +-----END CERTIFICATE----- diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 29345a1755c..2b4f39d62ea 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -87,7 +87,7 @@ func (h HostnameError) Error() string { valid += san.String() } } else { - if len(c.DNSNames) > 0 { + if c.hasSANExtension() { valid = strings.Join(c.DNSNames, ", ") } else { valid = c.Subject.CommonName @@ -166,7 +166,7 @@ const ( func matchNameConstraint(domain, constraint string) bool { // The meaning of zero length constraints is not specified, but this - // code follows NSS and accepts them as valid for everything. + // code follows NSS and accepts them as matching everything. if len(constraint) == 0 { return true } @@ -220,6 +220,12 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V } } + for _, constraint := range c.ExcludedDNSDomains { + if matchNameConstraint(opts.DNSName, constraint) { + return CertificateInvalidError{c, CANotAuthorizedForThisName} + } + } + // KeyUsage status flags are ignored. From Engineering Security, Peter // Gutmann: A European government CA marked its signing certificates as // being valid for encryption only, but no-one noticed. Another @@ -482,7 +488,7 @@ func (c *Certificate) VerifyHostname(h string) error { lowered := toLowerCaseASCII(h) - if len(c.DNSNames) > 0 { + if c.hasSANExtension() { for _, match := range c.DNSNames { if matchHostnames(toLowerCaseASCII(match), lowered) { return nil diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 15c40914444..335c477d0da 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -263,6 +263,39 @@ var verifyTests = []verifyTest{ errorCallback: expectSubjectIssuerMismatcthError, }, + { + // An X.509 v1 certificate should not be accepted as an + // intermediate. + leaf: x509v1TestLeaf, + intermediates: []string{x509v1TestIntermediate}, + roots: []string{x509v1TestRoot}, + currentTime: 1481753183, + systemSkip: true, + + errorCallback: expectNotAuthorizedError, + }, + { + // If any SAN extension is present (even one without any DNS + // names), the CN should be ignored. + leaf: ignoreCNWithSANLeaf, + dnsName: "foo.example.com", + roots: []string{ignoreCNWithSANRoot}, + currentTime: 1486684488, + systemSkip: true, + + errorCallback: expectHostnameError, + }, + { + // Test that excluded names are respected. + leaf: excludedNamesLeaf, + dnsName: "bender.local", + intermediates: []string{excludedNamesIntermediate}, + roots: []string{excludedNamesRoot}, + currentTime: 1486684488, + systemSkip: true, + + errorCallback: expectNameConstraintsError, + }, } func expectHostnameError(t *testing.T, i int, err error) (ok bool) { @@ -330,6 +363,22 @@ func expectSubjectIssuerMismatcthError(t *testing.T, i int, err error) (ok bool) return true } +func expectNameConstraintsError(t *testing.T, i int, err error) (ok bool) { + if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName { + t.Errorf("#%d: error was not a CANotAuthorizedForThisName: %s", i, err) + return false + } + return true +} + +func expectNotAuthorizedError(t *testing.T, i int, err error) (ok bool) { + if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NotAuthorizedToSign { + t.Errorf("#%d: error was not a NotAuthorizedToSign: %s", i, err) + return false + } + return true +} + func certificateFromPEM(pemBytes string) (*Certificate, error) { block, _ := pem.Decode([]byte(pemBytes)) if block == nil { @@ -1269,6 +1318,174 @@ vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ= -----END CERTIFICATE----- ` +const x509v1TestRoot = ` +-----BEGIN CERTIFICATE----- +MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE +ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1 +MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1 +siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw ++QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD +JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw +FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE +EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAcIwqeNUpQr9cOcYm +YjpGpYkQ6b248xijCK7zI+lOeWN89zfSXn1AvfsC9pSdTMeDklWktbF/Ad0IN8Md +h2NtN34ard0hEfHc8qW8mkXdsysVmq6cPvFYaHz+dBtkHuHDoy8YQnC0zdN/WyYB +/1JmacUUofl+HusHuLkDxmadogI= +-----END CERTIFICATE-----` + +const x509v1TestIntermediate = ` +-----BEGIN CERTIFICATE----- +MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH +b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx +MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50 +ZXJtZWRpYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ2QyniAOT+5YL +jeinEBJr3NsC/Q2QJ/VKmgvp+xRxuKTHJiVmxVijmp0vWg8AWfkmuE4p3hXQbbqM +k5yxrk1n60ONhim2L4VXriEvCE7X2OXhTmBls5Ufr7aqIgPMikwjScCXwz8E8qI8 +UxyAhnjeJwMYBU8TuwBImSd4LBHoQQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAIab +DRG6FbF9kL9jb/TDHkbVBk+sl/Pxi4/XjuFyIALlARgAkeZcPmL5tNW1ImHkwsHR +zWE77kJDibzd141u21ZbLsKvEdUJXjla43bdyMmEqf5VGpC3D4sFt3QVH7lGeRur +x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+ +-----END CERTIFICATE-----` + +const x509v1TestLeaf = ` +-----BEGIN CERTIFICATE----- +MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV +BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw +MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW +BgNVBAMTD2Zvby5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC +gYEApUh60Z+a5/oKJxG//Dn8CihSo2CJHNIIO3zEJZ1EeNSMZCynaIR6D3IPZEIR ++RG2oGt+f5EEukAPYxwasp6VeZEezoQWJ+97nPCT6DpwLlWp3i2MF8piK2R9vxkG +Z5n0+HzYk1VM8epIrZFUXSMGTX8w1y041PX/yYLxbdEifdcCAwEAAaNaMFgwDgYD +VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV +HRMBAf8EAjAAMBkGA1UdDgQSBBBFozXe0SnzAmjy+1U6M/cvMA0GCSqGSIb3DQEB +CwUAA4GBADYzYUvaToO/ucBskPdqXV16AaakIhhSENswYVSl97/sODaxsjishKq9 +5R7siu+JnIFotA7IbBe633p75xEnLN88X626N/XRFG9iScLzpj0o0PWXBUiB+fxL +/jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/ +-----END CERTIFICATE-----` + +const ignoreCNWithSANRoot = ` +-----BEGIN CERTIFICATE----- +MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE +ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx +MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa +BgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQC4YAf5YqlXGcikvbMWtVrNICt+V/NNWljwfvSKdg4Inm7k6BwW +P6y4Y+n4qSYIWNU4iRkdpajufzctxQCO6ty13iw3qVktzcC5XBIiS6ymiRhhDgnY +VQqyakVGw9MxrPwdRZVlssUv3Hmy6tU+v5Ok31SLY5z3wKgYWvSyYs0b8bKNU8kf +2FmSHnBN16lxGdjhe3ji58F/zFMr0ds+HakrLIvVdFcQFAnQopM8FTHpoWNNzGU3 +KaiO0jBbMFkd6uVjVnuRJ+xjuiqi/NWwiwQA+CEr9HKzGkxOF8nAsHamdmO1wW+w +OsCrC0qWQ/f5NTOVATTJe0vj88OMTvo3071VAgMBAAGjXTBbMA4GA1UdDwEB/wQE +AwICpDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw +AwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOC +AQEAGOn3XjxHyHbXLKrRmpwV447B7iNBXR5VlhwOgt1kWaHDL2+8f/9/h0HMkB6j +fC+/yyuYVqYuOeavqMGVrh33D2ODuTQcFlOx5lXukP46j3j+Lm0jjZ1qNX7vlP8I +VlUXERhbelkw8O4oikakwIY9GE8syuSgYf+VeBW/lvuAZQrdnPfabxe05Tre6RXy +nJHMB1q07YHpbwIkcV/lfCE9pig2nPXTLwYZz9cl46Ul5RCpPUi+IKURo3x8y0FU +aSLjI/Ya0zwUARMmyZ3RRGCyhIarPb20mKSaMf1/Nb23pS3k1QgmZhk5pAnXYsWu +BJ6bvwEAasFiLGP6Zbdmxb2hIA== +-----END CERTIFICATE-----` + +const ignoreCNWithSANLeaf = ` +-----BEGIN CERTIFICATE----- +MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV +BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw +MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw +FgYDVQQDEw9mb28uZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +ggEKAoIBAQDBqskp89V/JMIBBqcauKSOVLcMyIE/t0jgSWVrsI4sksBTabLsfMdS +ui2n+dHQ1dRBuw3o4g4fPrWwS3nMnV3pZUHEn2TPi5N1xkjTaxObXgKIY2GKmFP3 +rJ9vYqHT6mT4K93kCHoRcmJWWySc7S3JAOhTcdB4G+tIdQJN63E+XRYQQfNrn5HZ +hxQoOzaguHFx+ZGSD4Ntk6BSZz5NfjqCYqYxe+iCpTpEEYhIpi8joSPSmkTMTxBW +S1W2gXbYNQ9KjNkGM6FnQsUJrSPMrWs4v3UB/U88N5LkZeF41SqD9ySFGwbGajFV +nyzj12+4K4D8BLhlOc0Eo/F/8GwOwvmxAgMBAAGjgYkwgYYwDgYDVR0PAQH/BAQD +AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA +MBkGA1UdDgQSBBCjeab27q+5pV43jBGANOJ1MBsGA1UdIwQUMBKAEEA31wH7QC+4 +HH5UBCeMWQEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGZfZ +ErTVxxpIg64s22mQpXSk/72THVQsfsKHzlXmztM0CJzH8ccoN67ZqKxJCfdiE/FI +Emb6BVV4cGPeIKpcxaM2dwX/Y+Y0JaxpQJvqLxs+EByRL0gPP3shgg86WWCjYLxv +AgOn862d/JXGDrC9vIlQ/DDQcyL5g0JV5UjG2G9TUigbnrXxBw7BoWK6wmoSaHnR +sZKEHSs3RUJvm7qqpA9Yfzm9jg+i9j32zh1xFacghAOmFRFXa9eCVeigZ/KK2mEY +j2kBQyvnyKsXHLAKUoUOpd6t/1PHrfXnGj+HmzZNloJ/BZ1kiWb4eLvMljoLGkZn +xZbqP3Krgjj4XNaXjg== +-----END CERTIFICATE-----` + +const excludedNamesLeaf = ` +-----BEGIN CERTIFICATE----- +MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE +BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU +MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5 +ICgzNzM0NTE1NTYyODA2Mzk3KTEhMB8GA1UEAwwYSW50ZXJtZWRpYXRlIENBIGZv +ciAzMzkyMB4XDTE3MDIwODIxMTUwNFoXDTE4MDIwODIwMjQ1OFowgZAxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlMb3MgR2F0b3Mx +FDASBgNVBAoMC05ldGZsaXggSW5jMS0wKwYDVQQLDCRQbGF0Zm9ybSBTZWN1cml0 +eSAoMzczNDUxNTc0ODUwMjY5NikxEzARBgNVBAMMCjE3Mi4xNi4wLjEwggEiMA0G +CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZ0oP1bMv6bOeqcKbzinnGpNOpenhA +zdFFsgea62znWsH3Wg4+1Md8uPCqlaQIsaJQKZHc50eKD3bg0Io7c6kxHkBQr1b8 +Q7cGeK3CjdqG3NwS/aizzrLKOwL693hFwwy7JY7GGCvogbhyQRKn6iV0U9zMm7bu +/9pQVV/wx8u01u2uAlLttjyQ5LJkxo5t8cATFVqxdN5J9eY//VSDiTwXnlpQITBP +/Ow+zYuZ3kFlzH3CtCOhOEvNG3Ar1NvP3Icq35PlHV+Eki4otnKfixwByoiGpqCB +UEIY04VrZJjwBxk08y/3jY2B3VLYGgi+rryyCxIqkB7UpSNPMMWSG4UpAgMBAAGj +LzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0RBBYwFIIMYmVuZGVyLmxvY2FshwSsEAAB +MA0GCSqGSIb3DQEBCwUAA4IBAQCLW3JO8L7LKByjzj2RciPjCGH5XF87Wd20gYLq +sNKcFwCIeyZhnQy5aZ164a5G9AIk2HLvH6HevBFPhA9Ivmyv/wYEfnPd1VcFkpgP +hDt8MCFJ8eSjCyKdtZh1MPMLrLVymmJV+Rc9JUUYM9TIeERkpl0rskcO1YGewkYt +qKlWE+0S16+pzsWvKn831uylqwIb8ANBPsCX4aM4muFBHavSWAHgRO+P+yXVw8Q+ +VQDnMHUe5PbZd1/+1KKVs1K/CkBCtoHNHp1d/JT+2zUQJphwja9CcgfFdVhSnHL4 +oEEOFtqVMIuQfR2isi08qW/JGOHc4sFoLYB8hvdaxKWSE19A +-----END CERTIFICATE----- +` + +const excludedNamesIntermediate = ` +-----BEGIN CERTIFICATE----- +MIIDzTCCArWgAwIBAgIHDUSFqYeczDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UE +BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU +MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5 +ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBmb3IgMzM5 +MjAeFw0xNzAyMDgyMTE1MDRaFw0xODAyMDgyMDI0NThaMIGeMQswCQYDVQQGEwJV +UzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJTG9zIEdhdG9zMRQwEgYD +VQQKDAtOZXRmbGl4IEluYzEtMCsGA1UECwwkUGxhdGZvcm0gU2VjdXJpdHkgKDM3 +MzQ1MTU1NjI4MDYzOTcpMSEwHwYDVQQDDBhJbnRlcm1lZGlhdGUgQ0EgZm9yIDMz +OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCOyEs6tJ/t9emQTvlx +3FS7uJSou5rKkuqVxZdIuYQ+B2ZviBYUnMRT9bXDB0nsVdKZdp0hdchdiwNXDG/I +CiWu48jkcv/BdynVyayOT+0pOJSYLaPYpzBx1Pb9M5651ct9GSbj6Tz0ChVonoIE +1AIZ0kkebucZRRFHd0xbAKVRKyUzPN6HJ7WfgyauUp7RmlC35wTmrmARrFohQLlL +7oICy+hIQePMy9x1LSFTbPxZ5AUUXVC3eUACU3vLClF/Xs8XGHebZpUXCdMQjOGS +nq1eFguFHR1poSB8uSmmLqm4vqUH9CDhEgiBAC8yekJ8//kZQ7lUEqZj3YxVbk+Y +E4H5AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB +ADxrnmNX5gWChgX9K5fYwhFDj5ofxZXAKVQk+WjmkwMcmCx3dtWSm++Wdksj/ZlA +V1cLW3ohWv1/OAZuOlw7sLf98aJpX+UUmIYYQxDubq+4/q7VA7HzEf2k/i/oN1NI +JgtrhpPcZ/LMO6k7DYx0qlfYq8pTSfd6MI4LnWKgLc+JSPJJjmvspgio2ZFcnYr7 +A264BwLo6v1Mos1o1JUvFFcp4GANlw0XFiWh7JXYRl8WmS5DoouUC+aNJ3lmyF6z +LbIjZCSfgZnk/LK1KU1j91FI2bc2ULYZvAC1PAg8/zvIgxn6YM2Q7ZsdEgWw0FpS +zMBX1/lk4wkFckeUIlkD55Y= +-----END CERTIFICATE-----` + +const excludedNamesRoot = ` +-----BEGIN CERTIFICATE----- +MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE +BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU +MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5 +ICgzNzMxNTA5NDM3NDYyNDg1KTEmMCQGA1UEAwwdTmFtZSBDb25zdHJhaW50cyBU +ZXN0IFJvb3QgQ0EwHhcNMTcwMjA4MjExNTA0WhcNMTgwMjA4MjAyNDU4WjCBmTEL +MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBH +YXRvczEUMBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNl +Y3VyaXR5ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBm +b3IgMzM5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJymcnX29ekc +7+MLyr8QuAzoHWznmGdDd2sITwWRjM89/21cdlHCGKSpULUNdFp9HDLWvYECtxt+ +8TuzKiQz7qAerzGUT1zI5McIjHy0e/i4xIkfiBiNeTCuB/N9QRbZlcfM80ErkaA4 +gCAFK8qZAcWkHIl6e+KaQFMPLKk9kckgAnVDHEJe8oLNCogCJ15558b65g05p9eb +5Lg+E98hoPRTQaDwlz3CZPfTTA2EiEZInSi8qzodFCbTpJUVTbiVUH/JtVjlibbb +smdcx5PORK+8ZJkhLEh54AjaWOX4tB/7Tkk8stg2VBmrIARt/j4UVj7cTrIWU3bV +m8TwHJG+YgsCAwEAAaNaMFgwDwYDVR0TAQH/BAUwAwEB/zBFBgNVHR4EPjA8oBww +CocICgEAAP//AAAwDoIMYmVuZGVyLmxvY2FsoRwwCocICgEAAP//AAAwDoIMYmVu +ZGVyLmxvY2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAMjbheffPxtSKSv9NySW+8qmHs +n7Mb5GGyCFu+cMZSoSaabstbml+zHEFJvWz6/1E95K4F8jKhAcu/CwDf4IZrSD2+ +Hee0DolVSQhZpnHgPyj7ZATz48e3aJaQPUlhCEOh0wwF4Y0N4FV0t7R6woLylYRZ +yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT +6mOAFN0qFb4RGzfGJW7x6z7KCULS7qVDp6fU3tRoScHFEgRubks6jzQ1W5ooSm4o ++NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy +-----END CERTIFICATE-----` + var unknownAuthorityErrorTests = []struct { cert string expected string @@ -1294,7 +1511,7 @@ func TestUnknownAuthorityError(t *testing.T) { hintCert: c, } actual := uae.Error() - if strings.Compare(actual, tt.expected) != 0 { + if actual != tt.expected { t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected) } } diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 949ce018561..fdc7c5307bd 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -3,6 +3,10 @@ // license that can be found in the LICENSE file. // Package x509 parses X.509-encoded keys and certificates. +// +// On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR +// can be used to override the system default locations for the SSL certificate +// file and SSL certificate files directory, respectively. package x509 import ( @@ -59,7 +63,7 @@ func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { switch pub := pub.(type) { case *rsa.PublicKey: - publicKeyBytes, err = asn1.Marshal(rsaPublicKey{ + publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{ N: pub.N, E: pub.E, }) @@ -69,9 +73,7 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith publicKeyAlgorithm.Algorithm = oidPublicKeyRSA // This is a NULL parameters value which is required by // https://tools.ietf.org/html/rfc3279#section-2.3.1. - publicKeyAlgorithm.Parameters = asn1.RawValue{ - Tag: 5, - } + publicKeyAlgorithm.Parameters = asn1.NullRawValue case *ecdsa.PublicKey: publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) oid, ok := oidFromNamedCurve(pub.Curve) @@ -355,10 +357,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { params := pssParameters{ Hash: pkix.AlgorithmIdentifier{ - Algorithm: hashOID, - Parameters: asn1.RawValue{ - Tag: 5, /* ASN.1 NULL */ - }, + Algorithm: hashOID, + Parameters: asn1.NullRawValue, }, MGF: pkix.AlgorithmIdentifier{ Algorithm: oidMGF1, @@ -368,10 +368,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { } mgf1Params := pkix.AlgorithmIdentifier{ - Algorithm: hashOID, - Parameters: asn1.RawValue{ - Tag: 5, /* ASN.1 NULL */ - }, + Algorithm: hashOID, + Parameters: asn1.NullRawValue, } var err error @@ -418,11 +416,10 @@ func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm // https://tools.ietf.org/html/rfc3447#section-8.1), that the // salt length matches the hash length, and that the trailer // field has the default value. - asn1NULL := []byte{0x05, 0x00} - if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1NULL) || + if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes) || !params.MGF.Algorithm.Equal(oidMGF1) || !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || - !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) || + !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes) || params.TrailerField != 1 { return UnknownSignatureAlgorithm } @@ -668,13 +665,28 @@ type Certificate struct { ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. - BasicConstraintsValid bool // if true then the next two fields are valid. + // BasicConstraintsValid indicates whether IsCA, MaxPathLen, + // and MaxPathLenZero are valid. + BasicConstraintsValid bool IsCA bool - MaxPathLen int - // MaxPathLenZero indicates that BasicConstraintsValid==true and - // MaxPathLen==0 should be interpreted as an actual maximum path length - // of zero. Otherwise, that combination is interpreted as MaxPathLen - // not being set. + + // MaxPathLen and MaxPathLenZero indicate the presence and + // value of the BasicConstraints' "pathLenConstraint". + // + // When parsing a certificate, a positive non-zero MaxPathLen + // means that the field was specified, -1 means it was unset, + // and MaxPathLenZero being true mean that the field was + // explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false + // should be treated equivalent to -1 (unset). + // + // When generating a certificate, an unset pathLenConstraint + // can be requested with either MaxPathLen == -1 or using the + // zero value for both MaxPathLen and MaxPathLenZero. + MaxPathLen int + // MaxPathLenZero indicates that BasicConstraintsValid==true + // and MaxPathLen==0 should be interpreted as an actual + // maximum path length of zero. Otherwise, that combination is + // interpreted as MaxPathLen not being set. MaxPathLenZero bool SubjectKeyId []byte @@ -692,6 +704,7 @@ type Certificate struct { // Name constraints PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. PermittedDNSDomains []string + ExcludedDNSDomains []string // CRL Distribution Points CRLDistributionPoints []string @@ -723,6 +736,10 @@ func (c *Certificate) Equal(other *Certificate) bool { return bytes.Equal(c.Raw, other.Raw) } +func (c *Certificate) hasSANExtension() bool { + return oidInExtensions(oidExtensionSubjectAltName, c.Extensions) +} + // Entrust have a broken root certificate (CN=Entrust.net Certification // Authority (2048)) which isn't marked as a CA certificate and is thus invalid // according to PKIX. @@ -924,20 +941,17 @@ type distributionPointName struct { RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` } -// asn1Null is the ASN.1 encoding of a NULL value. -var asn1Null = []byte{5, 0} - func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) { asn1Data := keyData.PublicKey.RightAlign() switch algo { case RSA: // RSA public keys must have a NULL in the parameters // (https://tools.ietf.org/html/rfc3279#section-2.3.1). - if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1Null) { + if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) { return nil, errors.New("x509: RSA key missing NULL parameters") } - p := new(rsaPublicKey) + p := new(pkcs1PublicKey) rest, err := asn1.Unmarshal(asn1Data, p) if err != nil { return nil, err @@ -1150,7 +1164,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.IsCA = constraints.IsCA out.MaxPathLen = constraints.MaxPathLen out.MaxPathLenZero = out.MaxPathLen == 0 - + // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) case 17: out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value) if err != nil { @@ -1185,19 +1199,27 @@ func parseCertificate(in *certificate) (*Certificate, error) { return nil, errors.New("x509: trailing data after X.509 NameConstraints") } - if len(constraints.Excluded) > 0 && e.Critical { - return out, UnhandledCriticalExtension{} - } - - for _, subtree := range constraints.Permitted { - if len(subtree.Name) == 0 { - if e.Critical { - return out, UnhandledCriticalExtension{} + getDNSNames := func(subtrees []generalSubtree, isCritical bool) (dnsNames []string, err error) { + for _, subtree := range subtrees { + if len(subtree.Name) == 0 { + if isCritical { + return nil, UnhandledCriticalExtension{} + } + continue } - continue + dnsNames = append(dnsNames, subtree.Name) } - out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name) + + return dnsNames, nil + } + + if out.PermittedDNSDomains, err = getDNSNames(constraints.Permitted, e.Critical); err != nil { + return out, err + } + if out.ExcludedDNSDomains, err = getDNSNames(constraints.Excluded, e.Critical); err != nil { + return out, err } + out.PermittedDNSDomainsCritical = e.Critical case 31: // RFC 5280, 4.2.1.13 @@ -1451,7 +1473,7 @@ func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBy return asn1.Marshal(rawValues) } -func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { +func buildExtensions(template *Certificate, authorityKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) n := 0 @@ -1525,9 +1547,9 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { n++ } - if len(template.AuthorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) { + if len(authorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) { ret[n].Id = oidExtensionAuthorityKeyId - ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId}) + ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId}) if err != nil { return } @@ -1581,16 +1603,22 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { n++ } - if len(template.PermittedDNSDomains) > 0 && + if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0) && !oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) { ret[n].Id = oidExtensionNameConstraints ret[n].Critical = template.PermittedDNSDomainsCritical var out nameConstraints + out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains)) for i, permitted := range template.PermittedDNSDomains { out.Permitted[i] = generalSubtree{Name: permitted} } + out.Excluded = make([]generalSubtree, len(template.ExcludedDNSDomains)) + for i, excluded := range template.ExcludedDNSDomains { + out.Excluded[i] = generalSubtree{Name: excluded} + } + ret[n].Value, err = asn1.Marshal(out) if err != nil { return @@ -1646,9 +1674,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori pubType = RSA hashFunc = crypto.SHA256 sigAlgo.Algorithm = oidSignatureSHA256WithRSA - sigAlgo.Parameters = asn1.RawValue{ - Tag: 5, - } + sigAlgo.Parameters = asn1.NullRawValue case *ecdsa.PublicKey: pubType = ECDSA @@ -1706,11 +1732,12 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori return } -// CreateCertificate creates a new certificate based on a template. The -// following members of template are used: SerialNumber, Subject, NotBefore, -// NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid, -// IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, -// PermittedDNSDomains, SignatureAlgorithm. +// CreateCertificate creates a new certificate based on a template. +// The following members of template are used: AuthorityKeyId, +// BasicConstraintsValid, DNSNames, ExcludedDNSDomains, ExtKeyUsage, +// IsCA, KeyUsage, MaxPathLen, MaxPathLenZero, NotAfter, NotBefore, +// PermittedDNSDomains, PermittedDNSDomainsCritical, SerialNumber, +// SignatureAlgorithm, Subject, SubjectKeyId, and UnknownExtKeyUsage. // // The certificate is signed by parent. If parent is equal to template then the // certificate is self-signed. The parameter pub is the public key of the @@ -1720,6 +1747,10 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori // // All keys types that are implemented via crypto.Signer are supported (This // includes *rsa.PublicKey and *ecdsa.PublicKey.) +// +// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any, +// unless the resulting certificate is self-signed. Otherwise the value from +// template will be used. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) { key, ok := priv.(crypto.Signer) if !ok { @@ -1750,11 +1781,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return } + authorityKeyId := template.AuthorityKeyId if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { - template.AuthorityKeyId = parent.SubjectKeyId + authorityKeyId = parent.SubjectKeyId } - extensions, err := buildExtensions(template) + extensions, err := buildExtensions(template, authorityKeyId) if err != nil { return } @@ -2025,10 +2057,10 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) return ret, nil } -// CreateCertificateRequest creates a new certificate request based on a template. -// The following members of template are used: Subject, Attributes, -// SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses. -// The private key is the private key of the signer. +// CreateCertificateRequest creates a new certificate request based on a +// template. The following members of template are used: Attributes, DNSNames, +// EmailAddresses, ExtraExtensions, IPAddresses, SignatureAlgorithm, and +// Subject. The private key is the private key of the signer. // // The returned slice is the certificate request in DER encoding. // diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index b085dad90f0..2d1acf93bf5 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -405,6 +405,7 @@ func TestCreateSelfSignedCertificate(t *testing.T) { PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, PermittedDNSDomains: []string{".example.com", "example.com"}, + ExcludedDNSDomains: []string{"bar.example.com"}, CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"}, @@ -442,6 +443,10 @@ func TestCreateSelfSignedCertificate(t *testing.T) { t.Errorf("%s: failed to parse name constraints: %#v", test.name, cert.PermittedDNSDomains) } + if len(cert.ExcludedDNSDomains) != 1 || cert.ExcludedDNSDomains[0] != "bar.example.com" { + t.Errorf("%s: failed to parse name constraint exclusions: %#v", test.name, cert.ExcludedDNSDomains) + } + if cert.Subject.CommonName != commonName { t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName) } |