diff options
Diffstat (limited to 'libgo/go/crypto')
28 files changed, 633 insertions, 106 deletions
diff --git a/libgo/go/crypto/cipher/cbc.go b/libgo/go/crypto/cipher/cbc.go index 6fab9b42131..913a5643f22 100644 --- a/libgo/go/crypto/cipher/cbc.go +++ b/libgo/go/crypto/cipher/cbc.go @@ -42,6 +42,12 @@ func NewCBCEncrypter(b Block, iv []byte) BlockMode { func (x *cbcEncrypter) BlockSize() int { return x.blockSize } func (x *cbcEncrypter) CryptBlocks(dst, src []byte) { + if len(src)%x.blockSize != 0 { + panic("crypto/cipher: input not full blocks") + } + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } for len(src) > 0 { for i := 0; i < x.blockSize; i++ { x.iv[i] ^= src[i] @@ -70,6 +76,12 @@ func NewCBCDecrypter(b Block, iv []byte) BlockMode { func (x *cbcDecrypter) BlockSize() int { return x.blockSize } func (x *cbcDecrypter) CryptBlocks(dst, src []byte) { + if len(src)%x.blockSize != 0 { + panic("crypto/cipher: input not full blocks") + } + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } for len(src) > 0 { x.b.Decrypt(x.tmp, src[:x.blockSize]) for i := 0; i < x.blockSize; i++ { diff --git a/libgo/go/crypto/cipher/cipher_test.go b/libgo/go/crypto/cipher/cipher_test.go new file mode 100644 index 00000000000..8da5bce93ff --- /dev/null +++ b/libgo/go/crypto/cipher/cipher_test.go @@ -0,0 +1,36 @@ +// 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. + +package cipher_test + +import ( + "crypto/aes" + "crypto/cipher" + "testing" +) + +func TestCryptBlocks(t *testing.T) { + buf := make([]byte, 16) + block, _ := aes.NewCipher(buf) + + mode := cipher.NewCBCDecrypter(block, buf) + mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) }) + mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) }) + + mode = cipher.NewCBCEncrypter(block, buf) + mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) }) + mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) }) +} + +func mustPanic(t *testing.T, msg string, f func()) { + defer func() { + err := recover() + if err == nil { + t.Errorf("function did not panic, wanted %q", msg) + } else if err != msg { + t.Errorf("got panic %v, wanted %q", err, msg) + } + }() + f() +} diff --git a/libgo/go/crypto/cipher/example_test.go b/libgo/go/crypto/cipher/example_test.go index e0027cac23b..373f6791be4 100644 --- a/libgo/go/crypto/cipher/example_test.go +++ b/libgo/go/crypto/cipher/example_test.go @@ -233,7 +233,7 @@ func ExampleStreamReader() { } defer outFile.Close() - reader := &cipher.StreamReader{stream, inFile} + reader := &cipher.StreamReader{S: stream, R: inFile} // Copy the input file to the output file, decrypting as we go. if _, err := io.Copy(outFile, reader); err != nil { panic(err) @@ -270,7 +270,7 @@ func ExampleStreamWriter() { } defer outFile.Close() - writer := &cipher.StreamWriter{stream, outFile, nil} + writer := &cipher.StreamWriter{S: stream, W: outFile} // Copy the input file to the output file, encrypting as we go. if _, err := io.Copy(writer, inFile); err != nil { panic(err) diff --git a/libgo/go/crypto/dsa/dsa.go b/libgo/go/crypto/dsa/dsa.go index 05766a2f136..5a2a65744ed 100644 --- a/libgo/go/crypto/dsa/dsa.go +++ b/libgo/go/crypto/dsa/dsa.go @@ -144,8 +144,6 @@ GeneratePrimes: params.G = g return } - - panic("unreachable") } // GenerateKey generates a public&private key pair. The Parameters of the diff --git a/libgo/go/crypto/dsa/dsa_test.go b/libgo/go/crypto/dsa/dsa_test.go index 177aa444dfd..568416d0dfb 100644 --- a/libgo/go/crypto/dsa/dsa_test.go +++ b/libgo/go/crypto/dsa/dsa_test.go @@ -63,8 +63,9 @@ func testParameterGeneration(t *testing.T, sizes ParameterSizes, L, N int) { } func TestParameterGeneration(t *testing.T) { - // This test is too slow to run all the time. - return + if testing.Short() { + t.Skip("skipping parameter generation test in short mode") + } testParameterGeneration(t, L1024N160, 1024, 160) testParameterGeneration(t, L2048N224, 2048, 224) diff --git a/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go index 512d20c635c..25500022939 100644 --- a/libgo/go/crypto/ecdsa/ecdsa.go +++ b/libgo/go/crypto/ecdsa/ecdsa.go @@ -49,7 +49,7 @@ func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) return } -// GenerateKey generates a public&private key pair. +// GenerateKey generates a public and private key pair. func GenerateKey(c elliptic.Curve, rand io.Reader) (priv *PrivateKey, err error) { k, err := randFieldElement(c, rand) if err != nil { diff --git a/libgo/go/crypto/md5/gen.go b/libgo/go/crypto/md5/gen.go index 966bdae267b..275b4aeea39 100644 --- a/libgo/go/crypto/md5/gen.go +++ b/libgo/go/crypto/md5/gen.go @@ -161,6 +161,11 @@ var data = Data{ } var program = ` +// DO NOT EDIT. +// Generate with: go run gen.go{{if .Full}} -full{{end}} | gofmt >md5block.go + +// +build !amd64 + package md5 import ( @@ -186,6 +191,16 @@ import ( } {{end}} +const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386" + +var littleEndian bool + +func init() { + x := uint32(0x04030201) + y := [4]byte{0x1, 0x2, 0x3, 0x4} + littleEndian = *(*[4]byte)(unsafe.Pointer(&x)) == y +} + func block(dig *digest, p []byte) { a := dig.s[0] b := dig.s[1] @@ -197,13 +212,13 @@ func block(dig *digest, p []byte) { aa, bb, cc, dd := a, b, c, d // This is a constant condition - it is not evaluated on each iteration. - if runtime.GOARCH == "amd64" || runtime.GOARCH == "386" { + if x86 { // MD5 was designed so that x86 processors can just iterate // over the block data directly as uint32s, and we generate // less code and run 1.3x faster if we take advantage of that. // My apologies. X = (*[16]uint32)(unsafe.Pointer(&p[0])) - } else if uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { + } else if littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { X = (*[16]uint32)(unsafe.Pointer(&p[0])) } else { X = &xbuf diff --git a/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go index cac39ad054b..3ef4519b9ad 100644 --- a/libgo/go/crypto/md5/md5_test.go +++ b/libgo/go/crypto/md5/md5_test.go @@ -2,10 +2,9 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -package md5_test +package md5 import ( - "crypto/md5" "fmt" "io" "testing" @@ -54,7 +53,7 @@ var golden = []md5Test{ func TestGolden(t *testing.T) { for i := 0; i < len(golden); i++ { g := golden[i] - c := md5.New() + c := New() buf := make([]byte, len(g.in)+4) for j := 0; j < 3+4; j++ { if j < 2 { @@ -79,14 +78,14 @@ func TestGolden(t *testing.T) { } func ExampleNew() { - h := md5.New() + h := New() io.WriteString(h, "The fog is getting thicker!") io.WriteString(h, "And Leon's getting laaarger!") fmt.Printf("%x", h.Sum(nil)) // Output: e2c569be17396eca2a2e3c11578123ed } -var bench = md5.New() +var bench = New() var buf = make([]byte, 8192+1) var sum = make([]byte, bench.Size()) diff --git a/libgo/go/crypto/md5/md5block.go b/libgo/go/crypto/md5/md5block.go index 0ca42177403..a376fbee99b 100644 --- a/libgo/go/crypto/md5/md5block.go +++ b/libgo/go/crypto/md5/md5block.go @@ -1,3 +1,8 @@ +// DO NOT EDIT. +// Generate with: go run gen.go -full | gofmt >md5block.go + +// +build !amd64,!386 + package md5 import ( diff --git a/libgo/go/crypto/md5/md5block_decl.go b/libgo/go/crypto/md5/md5block_decl.go new file mode 100644 index 00000000000..14190c6ff29 --- /dev/null +++ b/libgo/go/crypto/md5/md5block_decl.go @@ -0,0 +1,9 @@ +// 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 amd64 386 + +package md5 + +func block(dig *digest, p []byte) diff --git a/libgo/go/crypto/rand/util.go b/libgo/go/crypto/rand/util.go index 50e5b162bdd..0cd5e0e022f 100644 --- a/libgo/go/crypto/rand/util.go +++ b/libgo/go/crypto/rand/util.go @@ -98,12 +98,13 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) { return } } - - return } -// Int returns a uniform random value in [0, max). +// Int returns a uniform random value in [0, max). It panics if max <= 0. 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. @@ -130,6 +131,4 @@ func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) { return } } - - return } diff --git a/libgo/go/crypto/rc4/rc4.go b/libgo/go/crypto/rc4/rc4.go index 1bb278f74a4..3d717c63b0c 100644 --- a/libgo/go/crypto/rc4/rc4.go +++ b/libgo/go/crypto/rc4/rc4.go @@ -13,7 +13,7 @@ import "strconv" // A Cipher is an instance of RC4 using a particular key. type Cipher struct { - s [256]byte + s [256]uint32 i, j uint8 } @@ -32,27 +32,16 @@ func NewCipher(key []byte) (*Cipher, error) { } var c Cipher for i := 0; i < 256; i++ { - c.s[i] = uint8(i) + c.s[i] = uint32(i) } var j uint8 = 0 for i := 0; i < 256; i++ { - j += c.s[i] + key[i%k] + j += uint8(c.s[i]) + key[i%k] c.s[i], c.s[j] = c.s[j], c.s[i] } return &c, nil } -// XORKeyStream sets dst to the result of XORing src with the key stream. -// Dst and src may be the same slice but otherwise should not overlap. -func (c *Cipher) XORKeyStream(dst, src []byte) { - for i := range src { - c.i += 1 - c.j += c.s[c.i] - c.s[c.i], c.s[c.j] = c.s[c.j], c.s[c.i] - dst[i] = src[i] ^ c.s[c.s[c.i]+c.s[c.j]] - } -} - // Reset zeros the key data so that it will no longer appear in the // process's memory. func (c *Cipher) Reset() { diff --git a/libgo/go/crypto/rc4/rc4_asm.go b/libgo/go/crypto/rc4/rc4_asm.go new file mode 100644 index 00000000000..c582a4488b8 --- /dev/null +++ b/libgo/go/crypto/rc4/rc4_asm.go @@ -0,0 +1,18 @@ +// 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 amd64 arm 386 + +package rc4 + +func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8) + +// XORKeyStream sets dst to the result of XORing src with the key stream. +// Dst and src may be the same slice but otherwise should not overlap. +func (c *Cipher) XORKeyStream(dst, src []byte) { + if len(src) == 0 { + return + } + xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j) +} diff --git a/libgo/go/crypto/rc4/rc4_ref.go b/libgo/go/crypto/rc4/rc4_ref.go new file mode 100644 index 00000000000..13d52b95dd3 --- /dev/null +++ b/libgo/go/crypto/rc4/rc4_ref.go @@ -0,0 +1,20 @@ +// 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 !amd64,!arm,!386 + +package rc4 + +// XORKeyStream sets dst to the result of XORing src with the key stream. +// Dst and src may be the same slice but otherwise should not overlap. +func (c *Cipher) XORKeyStream(dst, src []byte) { + i, j := c.i, c.j + for k, v := range src { + i += 1 + j += uint8(c.s[i]) + c.s[i], c.s[j] = c.s[j], c.s[i] + dst[k] = v ^ byte(c.s[byte(c.s[i]+c.s[j])]) + } + c.i, c.j = i, j +} diff --git a/libgo/go/crypto/rc4/rc4_test.go b/libgo/go/crypto/rc4/rc4_test.go index 6265d9408f4..7b4df6791d9 100644 --- a/libgo/go/crypto/rc4/rc4_test.go +++ b/libgo/go/crypto/rc4/rc4_test.go @@ -5,6 +5,8 @@ package rc4 import ( + "bytes" + "fmt" "testing" ) @@ -37,23 +39,124 @@ var golden = []rc4Test{ []byte{0x57, 0x69, 0x6b, 0x69}, []byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7}, }, + { + []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + []byte{ + 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a, + 0x8a, 0x06, 0x1e, 0x67, 0x57, 0x6e, 0x92, 0x6d, + 0xc7, 0x1a, 0x7f, 0xa3, 0xf0, 0xcc, 0xeb, 0x97, + 0x45, 0x2b, 0x4d, 0x32, 0x27, 0x96, 0x5f, 0x9e, + 0xa8, 0xcc, 0x75, 0x07, 0x6d, 0x9f, 0xb9, 0xc5, + 0x41, 0x7a, 0xa5, 0xcb, 0x30, 0xfc, 0x22, 0x19, + 0x8b, 0x34, 0x98, 0x2d, 0xbb, 0x62, 0x9e, 0xc0, + 0x4b, 0x4f, 0x8b, 0x05, 0xa0, 0x71, 0x08, 0x50, + 0x92, 0xa0, 0xc3, 0x58, 0x4a, 0x48, 0xe4, 0xa3, + 0x0a, 0x39, 0x7b, 0x8a, 0xcd, 0x1d, 0x00, 0x9e, + 0xc8, 0x7d, 0x68, 0x11, 0xf2, 0x2c, 0xf4, 0x9c, + 0xa3, 0xe5, 0x93, 0x54, 0xb9, 0x45, 0x15, 0x35, + 0xa2, 0x18, 0x7a, 0x86, 0x42, 0x6c, 0xca, 0x7d, + 0x5e, 0x82, 0x3e, 0xba, 0x00, 0x44, 0x12, 0x67, + 0x12, 0x57, 0xb8, 0xd8, 0x60, 0xae, 0x4c, 0xbd, + 0x4c, 0x49, 0x06, 0xbb, 0xc5, 0x35, 0xef, 0xe1, + 0x58, 0x7f, 0x08, 0xdb, 0x33, 0x95, 0x5c, 0xdb, + 0xcb, 0xad, 0x9b, 0x10, 0xf5, 0x3f, 0xc4, 0xe5, + 0x2c, 0x59, 0x15, 0x65, 0x51, 0x84, 0x87, 0xfe, + 0x08, 0x4d, 0x0e, 0x3f, 0x03, 0xde, 0xbc, 0xc9, + 0xda, 0x1c, 0xe9, 0x0d, 0x08, 0x5c, 0x2d, 0x8a, + 0x19, 0xd8, 0x37, 0x30, 0x86, 0x16, 0x36, 0x92, + 0x14, 0x2b, 0xd8, 0xfc, 0x5d, 0x7a, 0x73, 0x49, + 0x6a, 0x8e, 0x59, 0xee, 0x7e, 0xcf, 0x6b, 0x94, + 0x06, 0x63, 0xf4, 0xa6, 0xbe, 0xe6, 0x5b, 0xd2, + 0xc8, 0x5c, 0x46, 0x98, 0x6c, 0x1b, 0xef, 0x34, + 0x90, 0xd3, 0x7b, 0x38, 0xda, 0x85, 0xd3, 0x2e, + 0x97, 0x39, 0xcb, 0x23, 0x4a, 0x2b, 0xe7, 0x40, + }, + }, +} + +func testEncrypt(t *testing.T, desc string, c *Cipher, src, expect []byte) { + dst := make([]byte, len(src)) + c.XORKeyStream(dst, src) + for i, v := range dst { + if v != expect[i] { + t.Fatalf("%s: mismatch at byte %d:\nhave %x\nwant %x", desc, i, dst, expect) + } + } } func TestGolden(t *testing.T) { - for i := 0; i < len(golden); i++ { - g := golden[i] - c, err := NewCipher(g.key) - if err != nil { - t.Errorf("Failed to create cipher at golden index %d", i) - return + for gi, g := range golden { + data := make([]byte, len(g.keystream)) + for i := range data { + data[i] = byte(i) } - keystream := make([]byte, len(g.keystream)) - c.XORKeyStream(keystream, keystream) - for j, v := range keystream { - if g.keystream[j] != v { - t.Errorf("Failed at golden index %d", i) - break + + expect := make([]byte, len(g.keystream)) + for i := range expect { + expect[i] = byte(i) ^ g.keystream[i] + } + + for size := 1; size <= len(g.keystream); size++ { + c, err := NewCipher(g.key) + if err != nil { + t.Fatalf("#%d: NewCipher: %v", gi, err) + } + + off := 0 + for off < len(g.keystream) { + n := len(g.keystream) - off + if n > size { + n = size + } + desc := fmt.Sprintf("#%d@[%d:%d]", gi, off, off+n) + testEncrypt(t, desc, c, data[off:off+n], expect[off:off+n]) + off += n } } } } + +func TestBlock(t *testing.T) { + c1a, _ := NewCipher(golden[0].key) + c1b, _ := NewCipher(golden[1].key) + data1 := make([]byte, 1<<20) + for i := range data1 { + c1a.XORKeyStream(data1[i:i+1], data1[i:i+1]) + c1b.XORKeyStream(data1[i:i+1], data1[i:i+1]) + } + + c2a, _ := NewCipher(golden[0].key) + c2b, _ := NewCipher(golden[1].key) + data2 := make([]byte, 1<<20) + c2a.XORKeyStream(data2, data2) + c2b.XORKeyStream(data2, data2) + + if !bytes.Equal(data1, data2) { + t.Fatalf("bad block") + } +} + +func benchmark(b *testing.B, size int64) { + buf := make([]byte, size) + c, err := NewCipher(golden[0].key) + if err != nil { + panic(err) + } + b.SetBytes(size) + + for i := 0; i < b.N; i++ { + c.XORKeyStream(buf, buf) + } +} + +func BenchmarkRC4_128(b *testing.B) { + benchmark(b, 128) +} + +func BenchmarkRC4_1K(b *testing.B) { + benchmark(b, 1024) +} + +func BenchmarkRC4_8K(b *testing.B) { + benchmark(b, 8096) +} diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go index 543070f90fb..f56fb37ee54 100644 --- a/libgo/go/crypto/rsa/rsa.go +++ b/libgo/go/crypto/rsa/rsa.go @@ -150,6 +150,20 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *Priva NextSetOfPrimes: for { todo := bits + // crypto/rand should set the top two bits in each prime. + // Thus each prime has the form + // p_i = 2^bitlen(p_i) × 0.11... (in base 2). + // And the product is: + // P = 2^todo × α + // where α is the product of nprimes numbers of the form 0.11... + // + // If α < 1/2 (which can happen for nprimes > 2), we need to + // shift todo to compensate for lost bits: the mean value of 0.11... + // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2 + // will give good results. + if nprimes >= 7 { + todo += (nprimes - 2) / 5 + } for i := 0; i < nprimes; i++ { primes[i], err = rand.Prime(random, todo/(nprimes-i)) if err != nil { @@ -176,8 +190,9 @@ NextSetOfPrimes: totient.Mul(totient, pminus1) } if n.BitLen() != bits { - // This should never happen because crypto/rand should - // set the top two bits in each prime. + // This should never happen for nprimes == 2 because + // crypto/rand should set the top two bits in each prime. + // For nprimes > 2 we hope it does not happen often. continue NextSetOfPrimes } @@ -188,7 +203,9 @@ NextSetOfPrimes: g.GCD(priv.D, y, e, totient) if g.Cmp(bigOne) == 0 { - priv.D.Add(priv.D, totient) + if priv.D.Sign() < 0 { + priv.D.Add(priv.D, totient) + } priv.Primes = primes priv.N = n diff --git a/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go index 9be22a8f0bf..ffd96e62f64 100644 --- a/libgo/go/crypto/rsa/rsa_test.go +++ b/libgo/go/crypto/rsa/rsa_test.go @@ -28,11 +28,11 @@ func TestKeyGeneration(t *testing.T) { } func Test3PrimeKeyGeneration(t *testing.T) { + size := 768 if testing.Short() { - return + size = 256 } - size := 768 priv, err := GenerateMultiPrimeKey(rand.Reader, 3, size) if err != nil { t.Errorf("failed to generate key") @@ -41,11 +41,11 @@ func Test3PrimeKeyGeneration(t *testing.T) { } func Test4PrimeKeyGeneration(t *testing.T) { + size := 768 if testing.Short() { - return + size = 256 } - size := 768 priv, err := GenerateMultiPrimeKey(rand.Reader, 4, size) if err != nil { t.Errorf("failed to generate key") @@ -53,6 +53,24 @@ func Test4PrimeKeyGeneration(t *testing.T) { testKeyBasics(t, priv) } +func TestNPrimeKeyGeneration(t *testing.T) { + primeSize := 64 + maxN := 24 + if testing.Short() { + primeSize = 16 + maxN = 16 + } + // Test that generation of N-prime keys works for N > 4. + for n := 5; n < maxN; n++ { + priv, err := GenerateMultiPrimeKey(rand.Reader, n, 64+n*primeSize) + if err == nil { + testKeyBasics(t, priv) + } else { + t.Errorf("failed to generate %d-prime key", n) + } + } +} + func TestGnuTLSKey(t *testing.T) { // This is a key generated by `certtool --generate-privkey --bits 128`. // It's such that de ≢ 1 mod φ(n), but is congruent mod the order of @@ -75,6 +93,9 @@ func testKeyBasics(t *testing.T, priv *PrivateKey) { if err := priv.Validate(); err != nil { t.Errorf("Validate() failed: %s", err) } + if priv.D.Cmp(priv.N) > 0 { + t.Errorf("private exponent too large") + } pub := &priv.PublicKey m := big.NewInt(42) diff --git a/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go index 58541127784..57cd4313eb2 100644 --- a/libgo/go/crypto/sha1/sha1_test.go +++ b/libgo/go/crypto/sha1/sha1_test.go @@ -4,10 +4,9 @@ // SHA1 hash algorithm. See RFC 3174. -package sha1_test +package sha1 import ( - "crypto/sha1" "fmt" "io" "testing" @@ -55,7 +54,7 @@ var golden = []sha1Test{ func TestGolden(t *testing.T) { for i := 0; i < len(golden); i++ { g := golden[i] - c := sha1.New() + c := New() for j := 0; j < 3; j++ { if j < 2 { io.WriteString(c, g.in) @@ -74,13 +73,13 @@ func TestGolden(t *testing.T) { } func ExampleNew() { - h := sha1.New() + h := New() io.WriteString(h, "His money is twice tainted: 'taint yours and 'taint mine.") fmt.Printf("% x", h.Sum(nil)) // Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd } -var bench = sha1.New() +var bench = New() var buf = make([]byte, 8192) func benchmarkSize(b *testing.B, size int) { diff --git a/libgo/go/crypto/sha1/sha1block.go b/libgo/go/crypto/sha1/sha1block.go index 1c9507c68e5..92224fc0ef8 100644 --- a/libgo/go/crypto/sha1/sha1block.go +++ b/libgo/go/crypto/sha1/sha1block.go @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// +build !amd64,!386 + // SHA1 block step. // In its own file so that a faster assembly or C version // can be substituted easily. diff --git a/libgo/go/crypto/sha1/sha1block_decl.go b/libgo/go/crypto/sha1/sha1block_decl.go new file mode 100644 index 00000000000..3512a582991 --- /dev/null +++ b/libgo/go/crypto/sha1/sha1block_decl.go @@ -0,0 +1,9 @@ +// 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 amd64 386 + +package sha1 + +func block(dig *digest, p []byte) diff --git a/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index a888df762db..f86c90de74d 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/crypto/tls/common.go @@ -204,7 +204,24 @@ type Config struct { // connections using that key are compromised. SessionTicketKey [32]byte - serverInitOnce sync.Once + serverInitOnce sync.Once // guards calling (*Config).serverInit +} + +func (c *Config) serverInit() { + if c.SessionTicketsDisabled { + return + } + + // If the key has already been set then we have nothing to do. + for _, b := range c.SessionTicketKey { + if b != 0 { + return + } + } + + if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil { + c.SessionTicketsDisabled = true + } } func (c *Config) rand() io.Reader { diff --git a/libgo/go/crypto/tls/generate_cert.go b/libgo/go/crypto/tls/generate_cert.go index 84be5bfd856..215644d2435 100644 --- a/libgo/go/crypto/tls/generate_cert.go +++ b/libgo/go/crypto/tls/generate_cert.go @@ -16,36 +16,80 @@ import ( "crypto/x509/pkix" "encoding/pem" "flag" + "fmt" "log" "math/big" + "net" "os" + "strings" "time" ) -var hostName *string = flag.String("host", "127.0.0.1", "Hostname to generate a certificate for") +var ( + host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for") + validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011") + 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", 1024, "Size of RSA key to generate") +) func main() { flag.Parse() - priv, err := rsa.GenerateKey(rand.Reader, 1024) + if len(*host) == 0 { + log.Fatalf("Missing required --host parameter") + } + + priv, err := rsa.GenerateKey(rand.Reader, *rsaBits) if err != nil { log.Fatalf("failed to generate private key: %s", err) return } - now := time.Now() + var notBefore time.Time + if len(*validFrom) == 0 { + notBefore = time.Now() + } else { + notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom) + if err != nil { + fmt.Fprintf(os.Stderr, "Failed to parse creation date: %s\n", err) + os.Exit(1) + } + } + + notAfter := notBefore.Add(*validFor) + + // end of ASN.1 time + endOfTime := time.Date(2049, 12, 31, 23, 59, 59, 0, time.UTC) + if notAfter.After(endOfTime) { + notAfter = endOfTime + } template := x509.Certificate{ SerialNumber: new(big.Int).SetInt64(0), Subject: pkix.Name{ - CommonName: *hostName, Organization: []string{"Acme Co"}, }, - NotBefore: now.Add(-5 * time.Minute).UTC(), - NotAfter: now.AddDate(1, 0, 0).UTC(), // valid for 1 year. + NotBefore: notBefore, + NotAfter: notAfter, + + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, + BasicConstraintsValid: true, + } + + hosts := strings.Split(*host, ",") + for _, h := range hosts { + if ip := net.ParseIP(h); ip != nil { + template.IPAddresses = append(template.IPAddresses, ip) + } else { + template.DNSNames = append(template.DNSNames, h) + } + } - SubjectKeyId: []byte{1, 2, 3, 4}, - KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + if *isCA { + template.IsCA = true + template.KeyUsage |= x509.KeyUsageCertSign } derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) diff --git a/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index 730991016aa..823730c605c 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/crypto/tls/handshake_server.go @@ -33,22 +33,7 @@ func (c *Conn) serverHandshake() error { // If this is the first server handshake, we generate a random key to // encrypt the tickets with. - config.serverInitOnce.Do(func() { - if config.SessionTicketsDisabled { - return - } - - // If the key has already been set then we have nothing to do. - for _, b := range config.SessionTicketKey { - if b != 0 { - return - } - } - - if _, err := io.ReadFull(config.rand(), config.SessionTicketKey[:]); err != nil { - config.SessionTicketsDisabled = true - } - }) + config.serverInitOnce.Do(config.serverInit) hs := serverHandshakeState{ c: c, diff --git a/libgo/go/crypto/x509/pkcs8.go b/libgo/go/crypto/x509/pkcs8.go index 30caacb3c54..8e1585e15cc 100644 --- a/libgo/go/crypto/x509/pkcs8.go +++ b/libgo/go/crypto/x509/pkcs8.go @@ -51,6 +51,4 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { default: return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm) } - - panic("unreachable") } diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 51be5feb063..b29ddbc80f0 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -5,6 +5,7 @@ package x509 import ( + "net" "runtime" "strings" "time" @@ -63,14 +64,28 @@ type HostnameError struct { } func (h HostnameError) Error() string { - var valid string c := h.Certificate - if len(c.DNSNames) > 0 { - valid = strings.Join(c.DNSNames, ", ") + + var valid string + if ip := net.ParseIP(h.Host); ip != nil { + // Trying to validate an IP + if len(c.IPAddresses) == 0 { + return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs" + } + for _, san := range c.IPAddresses { + if len(valid) > 0 { + valid += ", " + } + valid += san.String() + } } else { - valid = c.Subject.CommonName + if len(c.DNSNames) > 0 { + valid = strings.Join(c.DNSNames, ", ") + } else { + valid = c.Subject.CommonName + } } - return "certificate is valid for " + valid + ", not " + h.Host + return "x509: certificate is valid for " + valid + ", not " + h.Host } // UnknownAuthorityError results when the certificate issuer is unknown @@ -334,6 +349,22 @@ func toLowerCaseASCII(in string) string { // VerifyHostname returns nil if c is a valid certificate for the named host. // Otherwise it returns an error describing the mismatch. func (c *Certificate) VerifyHostname(h string) error { + // IP addresses may be written in [ ]. + candidateIP := h + if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' { + candidateIP = h[1 : len(h)-1] + } + if ip := net.ParseIP(candidateIP); ip != nil { + // We only match IP addresses against IP SANs. + // https://tools.ietf.org/html/rfc6125#appendix-B.2 + for _, candidate := range c.IPAddresses { + if ip.Equal(candidate) { + return nil + } + } + return HostnameError{c, candidateIP} + } + lowered := toLowerCaseASCII(h) if len(c.DNSNames) > 0 { @@ -389,6 +420,14 @@ func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { for _, usage := range cert.ExtKeyUsage { if requestedUsage == usage { continue NextRequestedUsage + } else if requestedUsage == ExtKeyUsageServerAuth && + (usage == ExtKeyUsageNetscapeServerGatedCrypto || + usage == ExtKeyUsageMicrosoftServerGatedCrypto) { + // In order to support COMODO + // certificate chains, we have to + // accept Netscape or Microsoft SGC + // usages as equal to ServerAuth. + continue NextRequestedUsage } } diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 631a0f84981..5103ed814aa 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -158,6 +158,19 @@ var verifyTests = []verifyTest{ {"Ryan Hurst", "GlobalSign PersonalSign 2 CA - G2"}, }, }, + { + leaf: megaLeaf, + intermediates: []string{comodoIntermediate1}, + roots: []string{comodoRoot}, + currentTime: 1360431182, + + // CryptoAPI can find alternative validation paths so we don't + // perform this test with system validation. + systemSkip: true, + expectedChains: [][]string{ + {"mega.co.nz", "EssentialSSL CA", "COMODO Certification Authority"}, + }, + }, } func expectHostnameError(t *testing.T, i int, err error) (ok bool) { @@ -563,3 +576,90 @@ YEvTWbWwGdPytDFPYIl3/6OqNSXSnZ7DxPcdLJq2uyiga8PB/TTIIHYkdM2+1DE0 7y3rH/7TjwDVD7SLu5/SdOfKskuMPTjOEvz3K161mymW06klVhubCIWOro/Gx1Q2 2FQOZ7/2k4uYoOdBTSlb8kTAuzZNgIE0rB2BIYCTz/P6zZIKW0ogbRSH -----END CERTIFICATE-----` + +var megaLeaf = `-----BEGIN CERTIFICATE----- +MIIFOjCCBCKgAwIBAgIQWYE8Dup170kZ+k11Lg51OjANBgkqhkiG9w0BAQUFADBy +MQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYD +VQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01PRE8gQ0EgTGltaXRlZDEYMBYGA1UE +AxMPRXNzZW50aWFsU1NMIENBMB4XDTEyMTIxNDAwMDAwMFoXDTE0MTIxNDIzNTk1 +OVowfzEhMB8GA1UECxMYRG9tYWluIENvbnRyb2wgVmFsaWRhdGVkMS4wLAYDVQQL +EyVIb3N0ZWQgYnkgSW5zdHJhIENvcnBvcmF0aW9uIFB0eS4gTFREMRUwEwYDVQQL +EwxFc3NlbnRpYWxTU0wxEzARBgNVBAMTCm1lZ2EuY28ubnowggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQDcxMCClae8BQIaJHBUIVttlLvhbK4XhXPk3RQ3 +G5XA6tLZMBQ33l3F9knYJ0YErXtr8IdfYoulRQFmKFMJl9GtWyg4cGQi2Rcr5VN5 +S5dA1vu4oyJBxE9fPELcK6Yz1vqaf+n6za+mYTiQYKggVdS8/s8hmNuXP9Zk1pIn ++q0pGsf8NAcSHMJgLqPQrTDw+zae4V03DvcYfNKjuno88d2226ld7MAmQZ7uRNsI +/CnkdelVs+akZsXf0szefSqMJlf08SY32t2jj4Ra7RApVYxOftD9nij/aLfuqOU6 +ow6IgIcIG2ZvXLZwK87c5fxL7UAsTTV+M1sVv8jA33V2oKLhAgMBAAGjggG9MIIB +uTAfBgNVHSMEGDAWgBTay+qtWwhdzP/8JlTOSeVVxjj0+DAdBgNVHQ4EFgQUmP9l +6zhyrZ06Qj4zogt+6LKFk4AwDgYDVR0PAQH/BAQDAgWgMAwGA1UdEwEB/wQCMAAw +NAYDVR0lBC0wKwYIKwYBBQUHAwEGCCsGAQUFBwMCBgorBgEEAYI3CgMDBglghkgB +hvhCBAEwTwYDVR0gBEgwRjA6BgsrBgEEAbIxAQICBzArMCkGCCsGAQUFBwIBFh1o +dHRwczovL3NlY3VyZS5jb21vZG8uY29tL0NQUzAIBgZngQwBAgEwOwYDVR0fBDQw +MjAwoC6gLIYqaHR0cDovL2NybC5jb21vZG9jYS5jb20vRXNzZW50aWFsU1NMQ0Eu +Y3JsMG4GCCsGAQUFBwEBBGIwYDA4BggrBgEFBQcwAoYsaHR0cDovL2NydC5jb21v +ZG9jYS5jb20vRXNzZW50aWFsU1NMQ0FfMi5jcnQwJAYIKwYBBQUHMAGGGGh0dHA6 +Ly9vY3NwLmNvbW9kb2NhLmNvbTAlBgNVHREEHjAcggptZWdhLmNvLm56gg53d3cu +bWVnYS5jby5uejANBgkqhkiG9w0BAQUFAAOCAQEAcYhrsPSvDuwihMOh0ZmRpbOE +Gw6LqKgLNTmaYUPQhzi2cyIjhUhNvugXQQlP5f0lp5j8cixmArafg1dTn4kQGgD3 +ivtuhBTgKO1VYB/VRoAt6Lmswg3YqyiS7JiLDZxjoV7KoS5xdiaINfHDUaBBY4ZH +j2BUlPniNBjCqXe/HndUTVUewlxbVps9FyCmH+C4o9DWzdGBzDpCkcmo5nM+cp7q +ZhTIFTvZfo3zGuBoyu8BzuopCJcFRm3cRiXkpI7iOMUIixO1szkJS6WpL1sKdT73 +UXp08U0LBqoqG130FbzEJBBV3ixbvY6BWMHoCWuaoF12KJnC5kHt2RoWAAgMXA== +-----END CERTIFICATE-----` + +var comodoIntermediate1 = `-----BEGIN CERTIFICATE----- +MIIFAzCCA+ugAwIBAgIQGLLLuqME8aAPwfLzJkYqSjANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0xOTEyMzEyMzU5NTlaMHIxCzAJBgNVBAYTAkdCMRswGQYDVQQIExJHcmVh +dGVyIE1hbmNoZXN0ZXIxEDAOBgNVBAcTB1NhbGZvcmQxGjAYBgNVBAoTEUNPTU9E +TyBDQSBMaW1pdGVkMRgwFgYDVQQDEw9Fc3NlbnRpYWxTU0wgQ0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCt8AiwcsargxIxF3CJhakgEtSYau2A1NHf +5I5ZLdOWIY120j8YC0YZYwvHIPPlC92AGvFaoL0dds23Izp0XmEbdaqb1IX04XiR +0y3hr/yYLgbSeT1awB8hLRyuIVPGOqchfr7tZ291HRqfalsGs2rjsQuqag7nbWzD +ypWMN84hHzWQfdvaGlyoiBSyD8gSIF/F03/o4Tjg27z5H6Gq1huQByH6RSRQXScq +oChBRVt9vKCiL6qbfltTxfEFFld+Edc7tNkBdtzffRDPUanlOPJ7FAB1WfnwWdsX +Pvev5gItpHnBXaIcw5rIp6gLSApqLn8tl2X2xQScRMiZln5+pN0vAgMBAAGjggGD +MIIBfzAfBgNVHSMEGDAWgBQLWOWLxkwVN6RAqTCpIb5HNlpW/zAdBgNVHQ4EFgQU +2svqrVsIXcz//CZUzknlVcY49PgwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI +MAYBAf8CAQAwIAYDVR0lBBkwFwYKKwYBBAGCNwoDAwYJYIZIAYb4QgQBMD4GA1Ud +IAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwczovL3NlY3VyZS5jb21v +ZG8uY29tL0NQUzBJBgNVHR8EQjBAMD6gPKA6hjhodHRwOi8vY3JsLmNvbW9kb2Nh +LmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDBsBggrBgEFBQcB +AQRgMF4wNgYIKwYBBQUHMAKGKmh0dHA6Ly9jcnQuY29tb2RvY2EuY29tL0NvbW9k +b1VUTlNHQ0NBLmNydDAkBggrBgEFBQcwAYYYaHR0cDovL29jc3AuY29tb2RvY2Eu +Y29tMA0GCSqGSIb3DQEBBQUAA4IBAQAtlzR6QDLqcJcvgTtLeRJ3rvuq1xqo2l/z +odueTZbLN3qo6u6bldudu+Ennv1F7Q5Slqz0J790qpL0pcRDAB8OtXj5isWMcL2a +ejGjKdBZa0wztSz4iw+SY1dWrCRnilsvKcKxudokxeRiDn55w/65g+onO7wdQ7Vu +F6r7yJiIatnyfKH2cboZT7g440LX8NqxwCPf3dfxp+0Jj1agq8MLy6SSgIGSH6lv ++Wwz3D5XxqfyH8wqfOQsTEZf6/Nh9yvENZ+NWPU6g0QO2JOsTGvMd/QDzczc4BxL +XSXaPV7Od4rhPsbXlM1wSTz/Dr0ISKvlUhQVnQ6cGodWaK2cCQBk +-----END CERTIFICATE-----` + +var comodoRoot = `-----BEGIN CERTIFICATE----- +MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB +gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G +A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV +BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw +MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl +YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P +RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0 +aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3 +UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI +2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8 +Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp ++2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+ +DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O +nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW +/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g +PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u +QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY +SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv +IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/ +RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4 +zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd +BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB +ZQ== +-----END CERTIFICATE-----` diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 7983217696e..4dfea2c9499 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -19,6 +19,8 @@ import ( "errors" "io" "math/big" + "net" + "strconv" "time" ) @@ -360,16 +362,18 @@ const ( // id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } var ( - oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} - oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} - oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} - oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} - oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} - oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} - oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} - oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} - oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} - oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} + oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} + oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} + oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} + oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} + oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} + oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} + oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} + oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} + oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} + oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} + oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} + oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} ) // ExtKeyUsage represents an extended set of actions that are valid for a given key. @@ -387,6 +391,8 @@ const ( ExtKeyUsageIPSECUser ExtKeyUsageTimeStamping ExtKeyUsageOCSPSigning + ExtKeyUsageMicrosoftServerGatedCrypto + ExtKeyUsageNetscapeServerGatedCrypto ) // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. @@ -404,6 +410,8 @@ var extKeyUsageOIDs = []struct { {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, + {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, + {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, } func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { @@ -458,6 +466,7 @@ type Certificate struct { // Subject Alternate Name values DNSNames []string EmailAddresses []string + IPAddresses []net.IP // Name constraints PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. @@ -660,6 +669,13 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ return nil, err } + if p.N.Sign() <= 0 { + return nil, errors.New("x509: RSA modulus is not a positive number") + } + if p.E <= 0 { + return nil, errors.New("x509: RSA public exponent is not a positive number") + } + pub := &rsa.PublicKey{ E: p.E, N: p.N, @@ -713,7 +729,6 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{ default: return nil, nil } - panic("unreachable") } func parseCertificate(in *certificate) (*Certificate, error) { @@ -828,6 +843,13 @@ func parseCertificate(in *certificate) (*Certificate, error) { case 2: out.DNSNames = append(out.DNSNames, string(v.Bytes)) parsedName = true + case 7: + switch len(v.Bytes) { + case net.IPv4len, net.IPv6len: + out.IPAddresses = append(out.IPAddresses, v.Bytes) + default: + return nil, errors.New("x509: certificate contained IP address of length " + strconv.Itoa(len(v.Bytes))) + } } } @@ -1072,11 +1094,22 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { n++ } - if len(template.DNSNames) > 0 { + if len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 { ret[n].Id = oidExtensionSubjectAltName - rawValues := make([]asn1.RawValue, len(template.DNSNames)) - for i, name := range template.DNSNames { - rawValues[i] = asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)} + var rawValues []asn1.RawValue + for _, name := range template.DNSNames { + rawValues = append(rawValues, asn1.RawValue{Tag: 2, Class: 2, Bytes: []byte(name)}) + } + for _, email := range template.EmailAddresses { + rawValues = append(rawValues, asn1.RawValue{Tag: 1, Class: 2, Bytes: []byte(email)}) + } + for _, rawIP := range template.IPAddresses { + // If possible, we always want to encode IPv4 addresses in 4 bytes. + ip := rawIP.To4() + if ip == nil { + ip = rawIP + } + rawValues = append(rawValues, asn1.RawValue{Tag: 7, Class: 2, Bytes: ip}) } ret[n].Value, err = asn1.Marshal(rawValues) if err != nil { diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index b2d6fe3d552..abd4fe84d7e 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -19,6 +19,7 @@ import ( "encoding/hex" "encoding/pem" "math/big" + "net" "reflect" "testing" "time" @@ -174,6 +175,49 @@ func TestMatchHostnames(t *testing.T) { } } +func TestMatchIP(t *testing.T) { + // Check that pattern matching is working. + c := &Certificate{ + DNSNames: []string{"*.foo.bar.baz"}, + Subject: pkix.Name{ + CommonName: "*.foo.bar.baz", + }, + } + err := c.VerifyHostname("quux.foo.bar.baz") + if err != nil { + t.Fatalf("VerifyHostname(quux.foo.bar.baz): %v", err) + } + + // But check that if we change it to be matching against an IP address, + // it is rejected. + c = &Certificate{ + DNSNames: []string{"*.2.3.4"}, + Subject: pkix.Name{ + CommonName: "*.2.3.4", + }, + } + err = c.VerifyHostname("1.2.3.4") + if err == nil { + t.Fatalf("VerifyHostname(1.2.3.4) should have failed, did not") + } + + c = &Certificate{ + IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")}, + } + err = c.VerifyHostname("127.0.0.1") + if err != nil { + t.Fatalf("VerifyHostname(127.0.0.1): %v", err) + } + err = c.VerifyHostname("::1") + if err != nil { + t.Fatalf("VerifyHostname(::1): %v", err) + } + err = c.VerifyHostname("[::1]") + if err != nil { + t.Fatalf("VerifyHostname([::1]): %v", err) + } +} + func TestCertificateParse(t *testing.T) { s, _ := hex.DecodeString(certBytes) certs, err := ParseCertificates(s) @@ -284,8 +328,11 @@ func TestCreateSelfSignedCertificate(t *testing.T) { UnknownExtKeyUsage: testUnknownExtKeyUsage, BasicConstraintsValid: true, - IsCA: true, - DNSNames: []string{"test.example.com"}, + IsCA: true, + + DNSNames: []string{"test.example.com"}, + EmailAddresses: []string{"gopher@golang.org"}, + IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")}, PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, PermittedDNSDomains: []string{".example.com", "example.com"}, @@ -327,6 +374,18 @@ func TestCreateSelfSignedCertificate(t *testing.T) { t.Errorf("%s: unknown extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.UnknownExtKeyUsage, testUnknownExtKeyUsage) } + if !reflect.DeepEqual(cert.DNSNames, template.DNSNames) { + t.Errorf("%s: SAN DNS names differ from template. Got %v, want %v", test.name, cert.DNSNames, template.DNSNames) + } + + if !reflect.DeepEqual(cert.EmailAddresses, template.EmailAddresses) { + t.Errorf("%s: SAN emails differ from template. Got %v, want %v", test.name, cert.EmailAddresses, template.EmailAddresses) + } + + if !reflect.DeepEqual(cert.IPAddresses, template.IPAddresses) { + t.Errorf("%s: SAN IPs differ from template. Got %v, want %v", test.name, cert.IPAddresses, template.IPAddresses) + } + if test.checkSig { err = cert.CheckSignatureFrom(cert) if err != nil { |