diff options
Diffstat (limited to 'src/pkg/crypto')
82 files changed, 6640 insertions, 2163 deletions
| diff --git a/src/pkg/crypto/aes/aes_test.go b/src/pkg/crypto/aes/aes_test.go index e500c666d..6261dd09f 100644 --- a/src/pkg/crypto/aes/aes_test.go +++ b/src/pkg/crypto/aes/aes_test.go @@ -221,7 +221,10 @@ L:  		if tt.dec != nil {  			dec = make([]uint32, len(tt.dec))  		} -		expandKey(tt.key, enc, dec) +		// This test could only test Go version of expandKey because asm +		// version might use different memory layout for expanded keys +		// This is OK because we don't expose expanded keys to the outside +		expandKeyGo(tt.key, enc, dec)  		for j, v := range enc {  			if v != tt.enc[j] {  				t.Errorf("key %d: enc[%d] = %#x, want %#x", i, j, v, tt.enc[j]) @@ -352,15 +355,39 @@ func TestCipherDecrypt(t *testing.T) {  }  func BenchmarkEncrypt(b *testing.B) { -	b.StopTimer()  	tt := encryptTests[0]  	c, err := NewCipher(tt.key)  	if err != nil {  		b.Fatal("NewCipher:", err)  	}  	out := make([]byte, len(tt.in)) -	b.StartTimer() +	b.SetBytes(int64(len(out))) +	b.ResetTimer()  	for i := 0; i < b.N; i++ {  		c.Encrypt(out, tt.in)  	}  } + +func BenchmarkDecrypt(b *testing.B) { +	tt := encryptTests[0] +	c, err := NewCipher(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) +	} +} + +func BenchmarkExpand(b *testing.B) { +	tt := encryptTests[0] +	n := len(tt.key) + 28 +	c := &aesCipher{make([]uint32, n), make([]uint32, n)} +	b.ResetTimer() +	for i := 0; i < b.N; i++ { +		expandKey(tt.key, c.enc, c.dec) +	} +} diff --git a/src/pkg/crypto/aes/asm_amd64.s b/src/pkg/crypto/aes/asm_amd64.s new file mode 100644 index 000000000..25decf978 --- /dev/null +++ b/src/pkg/crypto/aes/asm_amd64.s @@ -0,0 +1,287 @@ +// Copyright 2012 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. + +// func hasAsm() bool +// returns whether AES-NI is supported +TEXT ·hasAsm(SB),7,$0 +	XORQ AX, AX +	INCL AX +	CPUID +	SHRQ $25, CX +	ANDQ $1, CX +	MOVB CX, ret+0(FP) +	RET + +// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·encryptBlockAsm(SB),7,$0 +	MOVQ nr+0(FP), CX +	MOVQ xk+8(FP), AX +	MOVQ dst+16(FP), DX +	MOVQ src+24(FP), BX +	MOVUPS 0(AX), X1 +	MOVUPS 0(BX), X0 +	ADDQ $16, AX +	PXOR X1, X0 +	SUBQ $12, CX +	JE Lenc196 +	JB Lenc128 +Lenc256: +	MOVUPS 0(AX), X1 +	AESENC X1, X0 +	MOVUPS 16(AX), X1 +	AESENC X1, X0 +	ADDQ $32, AX +Lenc196: +	MOVUPS 0(AX), X1 +	AESENC X1, X0 +	MOVUPS 16(AX), X1 +	AESENC X1, X0 +	ADDQ $32, AX +Lenc128: +	MOVUPS 0(AX), X1 +	AESENC X1, X0 +	MOVUPS 16(AX), X1 +	AESENC X1, X0 +	MOVUPS 32(AX), X1 +	AESENC X1, X0 +	MOVUPS 48(AX), X1 +	AESENC X1, X0 +	MOVUPS 64(AX), X1 +	AESENC X1, X0 +	MOVUPS 80(AX), X1 +	AESENC X1, X0 +	MOVUPS 96(AX), X1 +	AESENC X1, X0 +	MOVUPS 112(AX), X1 +	AESENC X1, X0 +	MOVUPS 128(AX), X1 +	AESENC X1, X0 +	MOVUPS 144(AX), X1 +	AESENCLAST X1, X0 +	MOVUPS X0, 0(DX) +	RET + +// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) +TEXT ·decryptBlockAsm(SB),7,$0 +	MOVQ nr+0(FP), CX +	MOVQ xk+8(FP), AX +	MOVQ dst+16(FP), DX +	MOVQ src+24(FP), BX +	MOVUPS 0(AX), X1 +	MOVUPS 0(BX), X0 +	ADDQ $16, AX +	PXOR X1, X0 +	SUBQ $12, CX +	JE Ldec196 +	JB Ldec128 +Ldec256: +	MOVUPS 0(AX), X1 +	AESDEC X1, X0 +	MOVUPS 16(AX), X1 +	AESDEC X1, X0 +	ADDQ $32, AX +Ldec196: +	MOVUPS 0(AX), X1 +	AESDEC X1, X0 +	MOVUPS 16(AX), X1 +	AESDEC X1, X0 +	ADDQ $32, AX +Ldec128: +	MOVUPS 0(AX), X1 +	AESDEC X1, X0 +	MOVUPS 16(AX), X1 +	AESDEC X1, X0 +	MOVUPS 32(AX), X1 +	AESDEC X1, X0 +	MOVUPS 48(AX), X1 +	AESDEC X1, X0 +	MOVUPS 64(AX), X1 +	AESDEC X1, X0 +	MOVUPS 80(AX), X1 +	AESDEC X1, X0 +	MOVUPS 96(AX), X1 +	AESDEC X1, X0 +	MOVUPS 112(AX), X1 +	AESDEC X1, X0 +	MOVUPS 128(AX), X1 +	AESDEC X1, X0 +	MOVUPS 144(AX), X1 +	AESDECLAST X1, X0 +	MOVUPS X0, 0(DX) +	RET + +// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) { +// Note that round keys are stored in uint128 format, not uint32 +TEXT ·expandKeyAsm(SB),7,$0 +	MOVQ nr+0(FP), CX +	MOVQ key+8(FP), AX +	MOVQ enc+16(FP), BX +	MOVQ dec+24(FP), DX +	MOVUPS (AX), X0 +	// enc +	MOVUPS X0, (BX) +	ADDQ $16, BX +	PXOR X4, X4 // _expand_key_* expect X4 to be zero +	CMPL CX, $12 +	JE Lexp_enc196 +	JB Lexp_enc128 +Lexp_enc256: +	MOVUPS 16(AX), X2 +	MOVUPS X2, (BX) +	ADDQ $16, BX +	AESKEYGENASSIST $0x01, X2, X1 +	CALL _expand_key_256a<>(SB) +	AESKEYGENASSIST $0x01, X0, X1 +	CALL _expand_key_256b<>(SB) +	AESKEYGENASSIST $0x02, X2, X1 +	CALL _expand_key_256a<>(SB) +	AESKEYGENASSIST $0x02, X0, X1 +	CALL _expand_key_256b<>(SB) +	AESKEYGENASSIST $0x04, X2, X1 +	CALL _expand_key_256a<>(SB) +	AESKEYGENASSIST $0x04, X0, X1 +	CALL _expand_key_256b<>(SB) +	AESKEYGENASSIST $0x08, X2, X1 +	CALL _expand_key_256a<>(SB) +	AESKEYGENASSIST $0x08, X0, X1 +	CALL _expand_key_256b<>(SB) +	AESKEYGENASSIST $0x10, X2, X1 +	CALL _expand_key_256a<>(SB) +	AESKEYGENASSIST $0x10, X0, X1 +	CALL _expand_key_256b<>(SB) +	AESKEYGENASSIST $0x20, X2, X1 +	CALL _expand_key_256a<>(SB) +	AESKEYGENASSIST $0x20, X0, X1 +	CALL _expand_key_256b<>(SB) +	AESKEYGENASSIST $0x40, X2, X1 +	CALL _expand_key_256a<>(SB) +	JMP Lexp_dec +Lexp_enc196: +	MOVQ 16(AX), X2 +	AESKEYGENASSIST $0x01, X2, X1 +	CALL _expand_key_192a<>(SB) +	AESKEYGENASSIST $0x02, X2, X1 +	CALL _expand_key_192b<>(SB) +	AESKEYGENASSIST $0x04, X2, X1 +	CALL _expand_key_192a<>(SB) +	AESKEYGENASSIST $0x08, X2, X1 +	CALL _expand_key_192b<>(SB) +	AESKEYGENASSIST $0x10, X2, X1 +	CALL _expand_key_192a<>(SB) +	AESKEYGENASSIST $0x20, X2, X1 +	CALL _expand_key_192b<>(SB) +	AESKEYGENASSIST $0x40, X2, X1 +	CALL _expand_key_192a<>(SB) +	AESKEYGENASSIST $0x80, X2, X1 +	CALL _expand_key_192b<>(SB) +	JMP Lexp_dec +Lexp_enc128: +	AESKEYGENASSIST $0x01, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x02, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x04, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x08, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x10, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x20, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x40, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x80, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x1b, X0, X1 +	CALL _expand_key_128<>(SB) +	AESKEYGENASSIST $0x36, X0, X1 +	CALL _expand_key_128<>(SB) +Lexp_dec: +	// dec +	SUBQ $16, BX +	MOVUPS (BX), X1 +	MOVUPS X1, (DX) +	DECQ CX +Lexp_dec_loop: +	MOVUPS -16(BX), X1 +	AESIMC X1, X0 +	MOVUPS X0, 16(DX) +	SUBQ $16, BX +	ADDQ $16, DX +	DECQ CX +	JNZ Lexp_dec_loop +	MOVUPS -16(BX), X0 +	MOVUPS X0, 16(DX) +	RET + +#define PSHUFD_X0_X0_ BYTE $0x66; BYTE $0x0f; BYTE $0x70; BYTE $0xc0 +#define PSHUFD_X1_X1_ BYTE $0x66; BYTE $0x0f; BYTE $0x70; BYTE $0xc9 +TEXT _expand_key_128<>(SB),7,$0 +	PSHUFD $0xff, X1, X1 +	SHUFPS $0x10, X0, X4 +	PXOR X4, X0 +	SHUFPS $0x8c, X0, X4 +	PXOR X4, X0 +	PXOR X1, X0 +	MOVUPS X0, (BX) +	ADDQ $16, BX +	RET + +#define PSLLDQ_X5_ BYTE $0x66; BYTE $0x0f; BYTE $0x73; BYTE $0xfd +#define PSHUFD_X0_X3_ BYTE $0x66; BYTE $0x0f; BYTE $0x70; BYTE $0xd8 +TEXT _expand_key_192a<>(SB),7,$0 +	PSHUFD $0x55, X1, X1 +	SHUFPS $0x10, X0, X4 +	PXOR X4, X0 +	SHUFPS $0x8c, X0, X4 +	PXOR X4, X0 +	PXOR X1, X0 + +	MOVAPS X2, X5 +	MOVAPS X2, X6 +	PSLLDQ_X5_; BYTE $0x4 +	PSHUFD $0xff, X0, X3 +	PXOR X3, X2 +	PXOR X5, X2 + +	MOVAPS X0, X1 +	SHUFPS $0x44, X0, X6 +	MOVUPS X6, (BX) +	SHUFPS $0x4e, X2, X1 +	MOVUPS X1, 16(BX) +	ADDQ $32, BX +	RET + +TEXT _expand_key_192b<>(SB),7,$0 +	PSHUFD $0x55, X1, X1 +	SHUFPS $0x10, X0, X4 +	PXOR X4, X0 +	SHUFPS $0x8c, X0, X4 +	PXOR X4, X0 +	PXOR X1, X0 + +	MOVAPS X2, X5 +	PSLLDQ_X5_; BYTE $0x4 +	PSHUFD $0xff, X0, X3 +	PXOR X3, X2 +	PXOR X5, X2 + +	MOVUPS X0, (BX) +	ADDQ $16, BX +	RET + +TEXT _expand_key_256a<>(SB),7,$0 +	JMP _expand_key_128<>(SB) + +TEXT _expand_key_256b<>(SB),7,$0 +	PSHUFD $0xaa, X1, X1 +	SHUFPS $0x10, X2, X4 +	PXOR X4, X2 +	SHUFPS $0x8c, X2, X4 +	PXOR X4, X2 +	PXOR X1, X2 + +	MOVUPS X2, (BX) +	ADDQ $16, BX +	RET diff --git a/src/pkg/crypto/aes/block.go b/src/pkg/crypto/aes/block.go index b930787ce..57a7e9e25 100644 --- a/src/pkg/crypto/aes/block.go +++ b/src/pkg/crypto/aes/block.go @@ -37,7 +37,7 @@  package aes  // Encrypt one block from src into dst, using the expanded key xk. -func encryptBlock(xk []uint32, dst, src []byte) { +func encryptBlockGo(xk []uint32, dst, src []byte) {  	var s0, s1, s2, s3, t0, t1, t2, t3 uint32  	s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) @@ -82,7 +82,7 @@ func encryptBlock(xk []uint32, dst, src []byte) {  }  // Decrypt one block from src into dst, using the expanded key xk. -func decryptBlock(xk []uint32, dst, src []byte) { +func decryptBlockGo(xk []uint32, dst, src []byte) {  	var s0, s1, s2, s3, t0, t1, t2, t3 uint32  	s0 = uint32(src[0])<<24 | uint32(src[1])<<16 | uint32(src[2])<<8 | uint32(src[3]) @@ -139,7 +139,7 @@ func rotw(w uint32) uint32 { return w<<8 | w>>24 }  // Key expansion algorithm.  See FIPS-197, Figure 11.  // Their rcon[i] is our powx[i-1] << 24. -func expandKey(key []byte, enc, dec []uint32) { +func expandKeyGo(key []byte, enc, dec []uint32) {  	// Encryption key setup.  	var i int  	nk := len(key) / 4 diff --git a/src/pkg/crypto/aes/cipher.go b/src/pkg/crypto/aes/cipher.go index 7d307c93a..d931134a7 100644 --- a/src/pkg/crypto/aes/cipher.go +++ b/src/pkg/crypto/aes/cipher.go @@ -45,6 +45,10 @@ func NewCipher(key []byte) (cipher.Block, error) {  func (c *aesCipher) BlockSize() int { return BlockSize } -func (c *aesCipher) Encrypt(dst, src []byte) { encryptBlock(c.enc, dst, src) } +func (c *aesCipher) Encrypt(dst, src []byte) { +	encryptBlock(c.enc, dst, src) +} -func (c *aesCipher) Decrypt(dst, src []byte) { decryptBlock(c.dec, dst, src) } +func (c *aesCipher) Decrypt(dst, src []byte) { +	decryptBlock(c.dec, dst, src) +} diff --git a/src/pkg/crypto/aes/cipher_asm.go b/src/pkg/crypto/aes/cipher_asm.go new file mode 100644 index 000000000..21369fc38 --- /dev/null +++ b/src/pkg/crypto/aes/cipher_asm.go @@ -0,0 +1,46 @@ +// Copyright 2012 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 + +package aes + +// defined in asm_$GOARCH.s +func hasAsm() bool +func encryptBlockAsm(nr int, xk *uint32, dst, src *byte) +func decryptBlockAsm(nr int, xk *uint32, dst, src *byte) +func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32) + +var useAsm = hasAsm() + +func encryptBlock(xk []uint32, dst, src []byte) { +	if useAsm { +		encryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0]) +	} else { +		encryptBlockGo(xk, dst, src) +	} +} +func decryptBlock(xk []uint32, dst, src []byte) { +	if useAsm { +		decryptBlockAsm(len(xk)/4-1, &xk[0], &dst[0], &src[0]) +	} else { +		decryptBlockGo(xk, dst, src) +	} +} +func expandKey(key []byte, enc, dec []uint32) { +	if useAsm { +		rounds := 10 +		switch len(key) { +		case 128 / 8: +			rounds = 10 +		case 192 / 8: +			rounds = 12 +		case 256 / 8: +			rounds = 14 +		} +		expandKeyAsm(rounds, &key[0], &enc[0], &dec[0]) +	} else { +		expandKeyGo(key, enc, dec) +	} +} diff --git a/src/pkg/crypto/aes/cipher_generic.go b/src/pkg/crypto/aes/cipher_generic.go new file mode 100644 index 000000000..1714e0f1e --- /dev/null +++ b/src/pkg/crypto/aes/cipher_generic.go @@ -0,0 +1,19 @@ +// Copyright 2012 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 + +package aes + +func encryptBlock(xk []uint32, dst, src []byte) { +	encryptBlockGo(xk, dst, src) +} + +func decryptBlock(xk []uint32, dst, src []byte) { +	decryptBlockGo(xk, dst, src) +} + +func expandKey(key []byte, enc, dec []uint32) { +	expandKeyGo(key, enc, dec) +} diff --git a/src/pkg/crypto/cipher/cbc.go b/src/pkg/crypto/cipher/cbc.go index a48929cf5..913a5643f 100644 --- a/src/pkg/crypto/cipher/cbc.go +++ b/src/pkg/crypto/cipher/cbc.go @@ -33,12 +33,21 @@ type cbcEncrypter cbc  // mode, using the given Block. The length of iv must be the same as the  // Block's block size.  func NewCBCEncrypter(b Block, iv []byte) BlockMode { +	if len(iv) != b.BlockSize() { +		panic("cipher.NewCBCEncrypter: IV length must equal block size") +	}  	return (*cbcEncrypter)(newCBC(b, iv))  }  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] @@ -58,12 +67,21 @@ type cbcDecrypter cbc  // mode, using the given Block. The length of iv must be the same as the  // Block's block size and must match the iv used to encrypt the data.  func NewCBCDecrypter(b Block, iv []byte) BlockMode { +	if len(iv) != b.BlockSize() { +		panic("cipher.NewCBCDecrypter: IV length must equal block size") +	}  	return (*cbcDecrypter)(newCBC(b, iv))  }  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/src/pkg/crypto/cipher/cfb.go b/src/pkg/crypto/cipher/cfb.go index d14165a86..99006b546 100644 --- a/src/pkg/crypto/cipher/cfb.go +++ b/src/pkg/crypto/cipher/cfb.go @@ -17,6 +17,9 @@ type cfb struct {  // using the given Block. The iv must be the same length as the Block's block  // size.  func NewCFBEncrypter(block Block, iv []byte) Stream { +	if len(iv) != block.BlockSize() { +		panic("cipher.NewCBFEncrypter: IV length must equal block size") +	}  	return newCFB(block, iv, false)  } @@ -24,6 +27,9 @@ func NewCFBEncrypter(block Block, iv []byte) Stream {  // using the given Block. The iv must be the same length as the Block's block  // size.  func NewCFBDecrypter(block Block, iv []byte) Stream { +	if len(iv) != block.BlockSize() { +		panic("cipher.NewCBFEncrypter: IV length must equal block size") +	}  	return newCFB(block, iv, true)  } diff --git a/src/pkg/crypto/cipher/cipher_test.go b/src/pkg/crypto/cipher/cipher_test.go new file mode 100644 index 000000000..8da5bce93 --- /dev/null +++ b/src/pkg/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/src/pkg/crypto/cipher/ctr.go b/src/pkg/crypto/cipher/ctr.go index 147b74fc2..d9ee9d827 100644 --- a/src/pkg/crypto/cipher/ctr.go +++ b/src/pkg/crypto/cipher/ctr.go @@ -23,7 +23,7 @@ type ctr struct {  // counter mode. The length of iv must be the same as the Block's block size.  func NewCTR(block Block, iv []byte) Stream {  	if len(iv) != block.BlockSize() { -		panic("cipher.NewCTR: iv length must equal block size") +		panic("cipher.NewCTR: IV length must equal block size")  	}  	return &ctr{ diff --git a/src/pkg/crypto/cipher/example_test.go b/src/pkg/crypto/cipher/example_test.go new file mode 100644 index 000000000..e0027cac2 --- /dev/null +++ b/src/pkg/crypto/cipher/example_test.go @@ -0,0 +1,283 @@ +// Copyright 2012 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" +	"crypto/rand" +	"encoding/hex" +	"fmt" +	"io" +	"os" +) + +func ExampleNewCBCDecrypter() { +	key := []byte("example key 1234") +	ciphertext, _ := hex.DecodeString("f363f3ccdcb12bb883abf484ba77d9cd7d32b5baecb3d4b1b3e0e4beffdb3ded") + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// The IV needs to be unique, but not secure. Therefore it's common to +	// include it at the beginning of the ciphertext. +	if len(ciphertext) < aes.BlockSize { +		panic("ciphertext too short") +	} +	iv := ciphertext[:aes.BlockSize] +	ciphertext = ciphertext[aes.BlockSize:] + +	// CBC mode always works in whole blocks. +	if len(ciphertext)%aes.BlockSize != 0 { +		panic("ciphertext is not a multiple of the block size") +	} + +	mode := cipher.NewCBCDecrypter(block, iv) + +	// CryptBlocks can work in-place if the two arguments are the same. +	mode.CryptBlocks(ciphertext, ciphertext) + +	// If the original plaintext lengths are not a multiple of the block +	// size, padding would have to be added when encrypting, which would be +	// removed at this point. For an example, see +	// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's +	// critical to note that ciphertexts must be authenticated (i.e. by +	// using crypto/hmac) before being decrypted in order to avoid creating +	// a padding oracle. + +	fmt.Printf("%s\n", ciphertext) +	// Output: exampleplaintext +} + +func ExampleNewCBCEncrypter() { +	key := []byte("example key 1234") +	plaintext := []byte("exampleplaintext") + +	// CBC mode works on blocks so plaintexts may need to be padded to the +	// next whole block. For an example of such padding, see +	// https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll +	// assume that the plaintext is already of the correct length. +	if len(plaintext)%aes.BlockSize != 0 { +		panic("plaintext is not a multiple of the block size") +	} + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// The IV needs to be unique, but not secure. Therefore it's common to +	// include it at the beginning of the ciphertext. +	ciphertext := make([]byte, aes.BlockSize+len(plaintext)) +	iv := ciphertext[:aes.BlockSize] +	if _, err := io.ReadFull(rand.Reader, iv); err != nil { +		panic(err) +	} + +	mode := cipher.NewCBCEncrypter(block, iv) +	mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext) + +	// It's important to remember that ciphertexts must be authenticated +	// (i.e. by using crypto/hmac) as well as being encrypted in order to +	// be secure. + +	fmt.Printf("%x\n", ciphertext) +} + +func ExampleNewCFBDecrypter() { +	key := []byte("example key 1234") +	ciphertext, _ := hex.DecodeString("22277966616d9bc47177bd02603d08c9a67d5380d0fe8cf3b44438dff7b9") + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// The IV needs to be unique, but not secure. Therefore it's common to +	// include it at the beginning of the ciphertext. +	if len(ciphertext) < aes.BlockSize { +		panic("ciphertext too short") +	} +	iv := ciphertext[:aes.BlockSize] +	ciphertext = ciphertext[aes.BlockSize:] + +	stream := cipher.NewCFBDecrypter(block, iv) + +	// XORKeyStream can work in-place if the two arguments are the same. +	stream.XORKeyStream(ciphertext, ciphertext) +	fmt.Printf("%s", ciphertext) +	// Output: some plaintext +} + +func ExampleNewCFBEncrypter() { +	key := []byte("example key 1234") +	plaintext := []byte("some plaintext") + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// The IV needs to be unique, but not secure. Therefore it's common to +	// include it at the beginning of the ciphertext. +	ciphertext := make([]byte, aes.BlockSize+len(plaintext)) +	iv := ciphertext[:aes.BlockSize] +	if _, err := io.ReadFull(rand.Reader, iv); err != nil { +		panic(err) +	} + +	stream := cipher.NewCFBEncrypter(block, iv) +	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + +	// It's important to remember that ciphertexts must be authenticated +	// (i.e. by using crypto/hmac) as well as being encrypted in order to +	// be secure. +} + +func ExampleNewCTR() { +	key := []byte("example key 1234") +	plaintext := []byte("some plaintext") + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// The IV needs to be unique, but not secure. Therefore it's common to +	// include it at the beginning of the ciphertext. +	ciphertext := make([]byte, aes.BlockSize+len(plaintext)) +	iv := ciphertext[:aes.BlockSize] +	if _, err := io.ReadFull(rand.Reader, iv); err != nil { +		panic(err) +	} + +	stream := cipher.NewCTR(block, iv) +	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + +	// It's important to remember that ciphertexts must be authenticated +	// (i.e. by using crypto/hmac) as well as being encrypted in order to +	// be secure. + +	// CTR mode is the same for both encryption and decryption, so we can +	// also decrypt that ciphertext with NewCTR. + +	plaintext2 := make([]byte, len(plaintext)) +	stream = cipher.NewCTR(block, iv) +	stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:]) + +	fmt.Printf("%s\n", plaintext2) +	// Output: some plaintext +} + +func ExampleNewOFB() { +	key := []byte("example key 1234") +	plaintext := []byte("some plaintext") + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// The IV needs to be unique, but not secure. Therefore it's common to +	// include it at the beginning of the ciphertext. +	ciphertext := make([]byte, aes.BlockSize+len(plaintext)) +	iv := ciphertext[:aes.BlockSize] +	if _, err := io.ReadFull(rand.Reader, iv); err != nil { +		panic(err) +	} + +	stream := cipher.NewOFB(block, iv) +	stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext) + +	// It's important to remember that ciphertexts must be authenticated +	// (i.e. by using crypto/hmac) as well as being encrypted in order to +	// be secure. + +	// OFB mode is the same for both encryption and decryption, so we can +	// also decrypt that ciphertext with NewOFB. + +	plaintext2 := make([]byte, len(plaintext)) +	stream = cipher.NewOFB(block, iv) +	stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:]) + +	fmt.Printf("%s\n", plaintext2) +	// Output: some plaintext +} + +func ExampleStreamReader() { +	key := []byte("example key 1234") + +	inFile, err := os.Open("encrypted-file") +	if err != nil { +		panic(err) +	} +	defer inFile.Close() + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// If the key is unique for each ciphertext, then it's ok to use a zero +	// IV. +	var iv [aes.BlockSize]byte +	stream := cipher.NewOFB(block, iv[:]) + +	outFile, err := os.OpenFile("decrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) +	if err != nil { +		panic(err) +	} +	defer outFile.Close() + +	reader := &cipher.StreamReader{stream, inFile} +	// Copy the input file to the output file, decrypting as we go. +	if _, err := io.Copy(outFile, reader); err != nil { +		panic(err) +	} + +	// Note that this example is simplistic in that it omits any +	// authentication of the encrypted data. It you were actually to use +	// StreamReader in this manner, an attacker could flip arbitrary bits in +	// the output. +} + +func ExampleStreamWriter() { +	key := []byte("example key 1234") + +	inFile, err := os.Open("plaintext-file") +	if err != nil { +		panic(err) +	} +	defer inFile.Close() + +	block, err := aes.NewCipher(key) +	if err != nil { +		panic(err) +	} + +	// If the key is unique for each ciphertext, then it's ok to use a zero +	// IV. +	var iv [aes.BlockSize]byte +	stream := cipher.NewOFB(block, iv[:]) + +	outFile, err := os.OpenFile("encrypted-file", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600) +	if err != nil { +		panic(err) +	} +	defer outFile.Close() + +	writer := &cipher.StreamWriter{stream, outFile, nil} +	// Copy the input file to the output file, encrypting as we go. +	if _, err := io.Copy(writer, inFile); err != nil { +		panic(err) +	} + +	// Note that this example is simplistic in that it omits any +	// authentication of the encrypted data. It you were actually to use +	// StreamReader in this manner, an attacker could flip arbitrary bits in +	// the decrypted result. +} diff --git a/src/pkg/crypto/cipher/io.go b/src/pkg/crypto/cipher/io.go index 76048fbf3..807e8daea 100644 --- a/src/pkg/crypto/cipher/io.go +++ b/src/pkg/crypto/cipher/io.go @@ -28,13 +28,10 @@ func (r StreamReader) Read(dst []byte) (n int, err error) {  type StreamWriter struct {  	S   Stream  	W   io.Writer -	Err error +	Err error // unused  }  func (w StreamWriter) Write(src []byte) (n int, err error) { -	if w.Err != nil { -		return 0, w.Err -	}  	c := make([]byte, len(src))  	w.S.XORKeyStream(c, src)  	n, err = w.W.Write(c) @@ -42,7 +39,6 @@ func (w StreamWriter) Write(src []byte) (n int, err error) {  		if err == nil { // should never happen  			err = io.ErrShortWrite  		} -		w.Err = err  	}  	return  } diff --git a/src/pkg/crypto/des/des_test.go b/src/pkg/crypto/des/des_test.go index e9fc23629..2e87e99b6 100644 --- a/src/pkg/crypto/des/des_test.go +++ b/src/pkg/crypto/des/des_test.go @@ -1503,3 +1503,21 @@ func TestSubstitutionTableKnownAnswerDecrypt(t *testing.T) {  		}  	}  } + +func ExampleNewTripleDESCipher() { +	// NewTripleDESCipher can also be used when EDE2 is required by +	// duplicating the first 8 bytes of the 16-byte key. +	ede2Key := []byte("example key 1234") + +	var tripleDESKey []byte +	tripleDESKey = append(tripleDESKey, ede2Key[:16]...) +	tripleDESKey = append(tripleDESKey, ede2Key[:8]...) + +	_, err := NewTripleDESCipher(tripleDESKey) +	if err != nil { +		panic(err) +	} + +	// See crypto/cipher for how to use a cipher.Block for encryption and +	// decryption. +} diff --git a/src/pkg/crypto/ecdsa/ecdsa.go b/src/pkg/crypto/ecdsa/ecdsa.go index 8508e3b4f..512d20c63 100644 --- a/src/pkg/crypto/ecdsa/ecdsa.go +++ b/src/pkg/crypto/ecdsa/ecdsa.go @@ -140,14 +140,16 @@ func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {  	w := new(big.Int).ModInverse(s, N)  	u1 := e.Mul(e, w) +	u1.Mod(u1, N)  	u2 := w.Mul(r, w) +	u2.Mod(u2, N)  	x1, y1 := c.ScalarBaseMult(u1.Bytes())  	x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes()) -	if x1.Cmp(x2) == 0 { +	x, y := c.Add(x1, y1, x2, y2) +	if x.Sign() == 0 && y.Sign() == 0 {  		return false  	} -	x, _ := c.Add(x1, y1, x2, y2)  	x.Mod(x, N)  	return x.Cmp(r) == 0  } diff --git a/src/pkg/crypto/ecdsa/ecdsa_test.go b/src/pkg/crypto/ecdsa/ecdsa_test.go index 3a2b3efba..0c0643193 100644 --- a/src/pkg/crypto/ecdsa/ecdsa_test.go +++ b/src/pkg/crypto/ecdsa/ecdsa_test.go @@ -5,11 +5,19 @@  package ecdsa  import ( +	"bufio" +	"compress/bzip2"  	"crypto/elliptic"  	"crypto/rand"  	"crypto/sha1" +	"crypto/sha256" +	"crypto/sha512"  	"encoding/hex" +	"hash" +	"io"  	"math/big" +	"os" +	"strings"  	"testing"  ) @@ -72,156 +80,112 @@ func fromHex(s string) *big.Int {  	return r  } -// These test vectors were taken from -//   http://csrc.nist.gov/groups/STM/cavp/documents/dss/ecdsatestvectors.zip -var testVectors = []struct { -	msg    string -	Qx, Qy string -	r, s   string -	ok     bool -}{ -	{ -		"09626b45493672e48f3d1226a3aff3201960e577d33a7f72c7eb055302db8fe8ed61685dd036b554942a5737cd1512cdf811ee0c00e6dd2f08c69f08643be396e85dafda664801e772cdb7396868ac47b172245b41986aa2648cb77fbbfa562581be06651355a0c4b090f9d17d8f0ab6cced4e0c9d386cf465a516630f0231bd", -		"9504b5b82d97a264d8b3735e0568decabc4b6ca275bc53cbadfc1c40", -		"03426f80e477603b10dee670939623e3da91a94267fc4e51726009ed", -		"81d3ac609f9575d742028dd496450a58a60eea2dcf8b9842994916e1", -		"96a8c5f382c992e8f30ccce9af120b067ec1d74678fa8445232f75a5", -		false, -	}, -	{ -		"96b2b6536f6df29be8567a72528aceeaccbaa66c66c534f3868ca9778b02faadb182e4ed34662e73b9d52ecbe9dc8e875fc05033c493108b380689ebf47e5b062e6a0cdb3dd34ce5fe347d92768d72f7b9b377c20aea927043b509c078ed2467d7113405d2ddd458811e6faf41c403a2a239240180f1430a6f4330df5d77de37", -		"851e3100368a22478a0029353045ae40d1d8202ef4d6533cfdddafd8", -		"205302ac69457dd345e86465afa72ee8c74ca97e2b0b999aec1f10c2", -		"4450c2d38b697e990721aa2dbb56578d32b4f5aeb3b9072baa955ee0", -		"e26d4b589166f7b4ba4b1c8fce823fa47aad22f8c9c396b8c6526e12", -		false, -	}, -	{ -		"86778dbb4a068a01047a8d245d632f636c11d2ad350740b36fad90428b454ad0f120cb558d12ea5c8a23db595d87543d06d1ef489263d01ee529871eb68737efdb8ff85bc7787b61514bed85b7e01d6be209e0a4eb0db5c8df58a5c5bf706d76cb2bdf7800208639e05b89517155d11688236e6a47ed37d8e5a2b1e0adea338e", -		"ad5bda09d319a717c1721acd6688d17020b31b47eef1edea57ceeffc", -		"c8ce98e181770a7c9418c73c63d01494b8b80a41098c5ea50692c984", -		"de5558c257ab4134e52c19d8db3b224a1899cbd08cc508ce8721d5e9", -		"745db7af5a477e5046705c0a5eff1f52cb94a79d481f0c5a5e108ecd", -		true, -	}, -	{ -		"4bc6ef1958556686dab1e39c3700054a304cbd8f5928603dcd97fafd1f29e69394679b638f71c9344ce6a535d104803d22119f57b5f9477e253817a52afa9bfbc9811d6cc8c8be6b6566c6ef48b439bbb532abe30627548c598867f3861ba0b154dc1c3deca06eb28df8efd28258554b5179883a36fbb1eecf4f93ee19d41e3d", -		"cc5eea2edf964018bdc0504a3793e4d2145142caa09a72ac5fb8d3e8", -		"a48d78ae5d08aa725342773975a00d4219cf7a8029bb8cf3c17c374a", -		"67b861344b4e416d4094472faf4272f6d54a497177fbc5f9ef292836", -		"1d54f3fcdad795bf3b23408ecbac3e1321d1d66f2e4e3d05f41f7020", -		false, -	}, -	{ -		"bb658732acbf3147729959eb7318a2058308b2739ec58907dd5b11cfa3ecf69a1752b7b7d806fe00ec402d18f96039f0b78dbb90a59c4414fb33f1f4e02e4089de4122cd93df5263a95be4d7084e2126493892816e6a5b4ed123cb705bf930c8f67af0fb4514d5769232a9b008a803af225160ce63f675bd4872c4c97b146e5e", -		"6234c936e27bf141fc7534bfc0a7eedc657f91308203f1dcbd642855", -		"27983d87ca785ef4892c3591ef4a944b1deb125dd58bd351034a6f84", -		"e94e05b42d01d0b965ffdd6c3a97a36a771e8ea71003de76c4ecb13f", -		"1dc6464ffeefbd7872a081a5926e9fc3e66d123f1784340ba17737e9", -		false, -	}, -	{ -		"7c00be9123bfa2c4290be1d8bc2942c7f897d9a5b7917e3aabd97ef1aab890f148400a89abd554d19bec9d8ed911ce57b22fbcf6d30ca2115f13ce0a3f569a23bad39ee645f624c49c60dcfc11e7d2be24de9c905596d8f23624d63dc46591d1f740e46f982bfae453f107e80db23545782be23ce43708245896fc54e1ee5c43", -		"9f3f037282aaf14d4772edffff331bbdda845c3f65780498cde334f1", -		"8308ee5a16e3bcb721b6bc30000a0419bc1aaedd761be7f658334066", -		"6381d7804a8808e3c17901e4d283b89449096a8fba993388fa11dc54", -		"8e858f6b5b253686a86b757bad23658cda53115ac565abca4e3d9f57", -		false, -	}, -	{ -		"cffc122a44840dc705bb37130069921be313d8bde0b66201aebc48add028ca131914ef2e705d6bedd19dc6cf9459bbb0f27cdfe3c50483808ffcdaffbeaa5f062e097180f07a40ef4ab6ed03fe07ed6bcfb8afeb42c97eafa2e8a8df469de07317c5e1494c41547478eff4d8c7d9f0f484ad90fedf6e1c35ee68fa73f1691601", -		"a03b88a10d930002c7b17ca6af2fd3e88fa000edf787dc594f8d4fd4", -		"e0cf7acd6ddc758e64847fe4df9915ebda2f67cdd5ec979aa57421f5", -		"387b84dcf37dc343c7d2c5beb82f0bf8bd894b395a7b894565d296c1", -		"4adc12ce7d20a89ce3925e10491c731b15ddb3f339610857a21b53b4", -		false, -	}, -	{ -		"26e0e0cafd85b43d16255908ccfd1f061c680df75aba3081246b337495783052ba06c60f4a486c1591a4048bae11b4d7fec4f161d80bdc9a7b79d23e44433ed625eab280521a37f23dd3e1bdc5c6a6cfaa026f3c45cf703e76dab57add93fe844dd4cda67dc3bddd01f9152579e49df60969b10f09ce9372fdd806b0c7301866", -		"9a8983c42f2b5a87c37a00458b5970320d247f0c8a88536440173f7d", -		"15e489ec6355351361900299088cfe8359f04fe0cab78dde952be80c", -		"929a21baa173d438ec9f28d6a585a2f9abcfc0a4300898668e476dc0", -		"59a853f046da8318de77ff43f26fe95a92ee296fa3f7e56ce086c872", -		true, -	}, -	{ -		"1078eac124f48ae4f807e946971d0de3db3748dd349b14cca5c942560fb25401b2252744f18ad5e455d2d97ed5ae745f55ff509c6c8e64606afe17809affa855c4c4cdcaf6b69ab4846aa5624ed0687541aee6f2224d929685736c6a23906d974d3c257abce1a3fb8db5951b89ecb0cda92b5207d93f6618fd0f893c32cf6a6e", -		"d6e55820bb62c2be97650302d59d667a411956138306bd566e5c3c2b", -		"631ab0d64eaf28a71b9cbd27a7a88682a2167cee6251c44e3810894f", -		"65af72bc7721eb71c2298a0eb4eed3cec96a737cc49125706308b129", -		"bd5a987c78e2d51598dbd9c34a9035b0069c580edefdacee17ad892a", -		false, -	}, -	{ -		"919deb1fdd831c23481dfdb2475dcbe325b04c34f82561ced3d2df0b3d749b36e255c4928973769d46de8b95f162b53cd666cad9ae145e7fcfba97919f703d864efc11eac5f260a5d920d780c52899e5d76f8fe66936ff82130761231f536e6a3d59792f784902c469aa897aabf9a0678f93446610d56d5e0981e4c8a563556b", -		"269b455b1024eb92d860a420f143ac1286b8cce43031562ae7664574", -		"baeb6ca274a77c44a0247e5eb12ca72bdd9a698b3f3ae69c9f1aaa57", -		"cb4ec2160f04613eb0dfe4608486091a25eb12aa4dec1afe91cfb008", -		"40b01d8cd06589481574f958b98ca08ade9d2a8fe31024375c01bb40", -		false, -	}, -	{ -		"6e012361250dacf6166d2dd1aa7be544c3206a9d43464b3fcd90f3f8cf48d08ec099b59ba6fe7d9bdcfaf244120aed1695d8be32d1b1cd6f143982ab945d635fb48a7c76831c0460851a3d62b7209c30cd9c2abdbe3d2a5282a9fcde1a6f418dd23c409bc351896b9b34d7d3a1a63bbaf3d677e612d4a80fa14829386a64b33f", -		"6d2d695efc6b43b13c14111f2109608f1020e3e03b5e21cfdbc82fcd", -		"26a4859296b7e360b69cf40be7bd97ceaffa3d07743c8489fc47ca1b", -		"9a8cb5f2fdc288b7183c5b32d8e546fc2ed1ca4285eeae00c8b572ad", -		"8c623f357b5d0057b10cdb1a1593dab57cda7bdec9cf868157a79b97", -		true, -	}, -	{ -		"bf6bd7356a52b234fe24d25557200971fc803836f6fec3cade9642b13a8e7af10ab48b749de76aada9d8927f9b12f75a2c383ca7358e2566c4bb4f156fce1fd4e87ef8c8d2b6b1bdd351460feb22cdca0437ac10ca5e0abbbce9834483af20e4835386f8b1c96daaa41554ceee56730aac04f23a5c765812efa746051f396566", -		"14250131b2599939cf2d6bc491be80ddfe7ad9de644387ee67de2d40", -		"b5dc473b5d014cd504022043c475d3f93c319a8bdcb7262d9e741803", -		"4f21642f2201278a95339a80f75cc91f8321fcb3c9462562f6cbf145", -		"452a5f816ea1f75dee4fd514fa91a0d6a43622981966c59a1b371ff8", -		false, -	}, -	{ -		"0eb7f4032f90f0bd3cf9473d6d9525d264d14c031a10acd31a053443ed5fe919d5ac35e0be77813071b4062f0b5fdf58ad5f637b76b0b305aec18f82441b6e607b44cdf6e0e3c7c57f24e6fd565e39430af4a6b1d979821ed0175fa03e3125506847654d7e1ae904ce1190ae38dc5919e257bdac2db142a6e7cd4da6c2e83770", -		"d1f342b7790a1667370a1840255ac5bbbdc66f0bc00ae977d99260ac", -		"76416cabae2de9a1000b4646338b774baabfa3db4673790771220cdb", -		"bc85e3fc143d19a7271b2f9e1c04b86146073f3fab4dda1c3b1f35ca", -		"9a5c70ede3c48d5f43307a0c2a4871934424a3303b815df4bb0f128e", -		false, -	}, -	{ -		"5cc25348a05d85e56d4b03cec450128727bc537c66ec3a9fb613c151033b5e86878632249cba83adcefc6c1e35dcd31702929c3b57871cda5c18d1cf8f9650a25b917efaed56032e43b6fc398509f0d2997306d8f26675f3a8683b79ce17128e006aa0903b39eeb2f1001be65de0520115e6f919de902b32c38d691a69c58c92", -		"7e49a7abf16a792e4c7bbc4d251820a2abd22d9f2fc252a7bf59c9a6", -		"44236a8fb4791c228c26637c28ae59503a2f450d4cfb0dc42aa843b9", -		"084461b4050285a1a85b2113be76a17878d849e6bc489f4d84f15cd8", -		"079b5bddcc4d45de8dbdfd39f69817c7e5afa454a894d03ee1eaaac3", -		false, -	}, -	{ -		"1951533ce33afb58935e39e363d8497a8dd0442018fd96dff167b3b23d7206a3ee182a3194765df4768a3284e23b8696c199b4686e670d60c9d782f08794a4bccc05cffffbd1a12acd9eb1cfa01f7ebe124da66ecff4599ea7720c3be4bb7285daa1a86ebf53b042bd23208d468c1b3aa87381f8e1ad63e2b4c2ba5efcf05845", -		"31945d12ebaf4d81f02be2b1768ed80784bf35cf5e2ff53438c11493", -		"a62bebffac987e3b9d3ec451eb64c462cdf7b4aa0b1bbb131ceaa0a4", -		"bc3c32b19e42b710bca5c6aaa128564da3ddb2726b25f33603d2af3c", -		"ed1a719cc0c507edc5239d76fe50e2306c145ad252bd481da04180c0", -		false, -	}, -} -  func TestVectors(t *testing.T) { -	sha := sha1.New() +	// This test runs the full set of NIST test vectors from +	// http://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip +	// +	// The SigVer.rsp file has been edited to remove test vectors for +	// unsupported algorithms and has been compressed. + +	if testing.Short() { +		return +	} + +	f, err := os.Open("testdata/SigVer.rsp.bz2") +	if err != nil { +		t.Fatal(err) +	} + +	buf := bufio.NewReader(bzip2.NewReader(f)) + +	lineNo := 1 +	var h hash.Hash +	var msg []byte +	var hashed []byte +	var r, s *big.Int +	pub := new(PublicKey) -	for i, test := range testVectors { -		pub := PublicKey{ -			Curve: elliptic.P224(), -			X:     fromHex(test.Qx), -			Y:     fromHex(test.Qy), +	for { +		line, err := buf.ReadString('\n') +		if len(line) == 0 { +			if err == io.EOF { +				break +			} +			t.Fatalf("error reading from input: %s", err)  		} -		msg, _ := hex.DecodeString(test.msg) -		sha.Reset() -		sha.Write(msg) -		hashed := sha.Sum(nil) -		r := fromHex(test.r) -		s := fromHex(test.s) -		if Verify(&pub, hashed, r, s) != test.ok { -			t.Errorf("%d: bad result", i) +		lineNo++ +		// Need to remove \r\n from the end of the line. +		if !strings.HasSuffix(line, "\r\n") { +			t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)  		} -		if testing.Short() { -			break +		line = line[:len(line)-2] + +		if len(line) == 0 || line[0] == '#' { +			continue +		} + +		if line[0] == '[' { +			line = line[1 : len(line)-1] +			parts := strings.SplitN(line, ",", 2) + +			switch parts[0] { +			case "P-224": +				pub.Curve = elliptic.P224() +			case "P-256": +				pub.Curve = elliptic.P256() +			case "P-384": +				pub.Curve = elliptic.P384() +			case "P-521": +				pub.Curve = elliptic.P521() +			default: +				pub.Curve = nil +			} + +			switch parts[1] { +			case "SHA-1": +				h = sha1.New() +			case "SHA-224": +				h = sha256.New224() +			case "SHA-256": +				h = sha256.New() +			case "SHA-384": +				h = sha512.New384() +			case "SHA-512": +				h = sha512.New() +			default: +				h = nil +			} + +			continue +		} + +		if h == nil || pub.Curve == nil { +			continue +		} + +		switch { +		case strings.HasPrefix(line, "Msg = "): +			if msg, err = hex.DecodeString(line[6:]); err != nil { +				t.Fatalf("failed to decode message on line %d: %s", lineNo, err) +			} +		case strings.HasPrefix(line, "Qx = "): +			pub.X = fromHex(line[5:]) +		case strings.HasPrefix(line, "Qy = "): +			pub.Y = fromHex(line[5:]) +		case strings.HasPrefix(line, "R = "): +			r = fromHex(line[4:]) +		case strings.HasPrefix(line, "S = "): +			s = fromHex(line[4:]) +		case strings.HasPrefix(line, "Result = "): +			expected := line[9] == 'P' +			h.Reset() +			h.Write(msg) +			hashed := h.Sum(hashed[:0]) +			if Verify(pub, hashed, r, s) != expected { +				t.Fatalf("incorrect result on line %d", lineNo) +			} +		default: +			t.Fatalf("unknown variable on line %d: %s", lineNo, line)  		}  	}  } diff --git a/src/pkg/crypto/ecdsa/testdata/SigVer.rsp.bz2 b/src/pkg/crypto/ecdsa/testdata/SigVer.rsp.bz2Binary files differ new file mode 100644 index 000000000..09fe2b427 --- /dev/null +++ b/src/pkg/crypto/ecdsa/testdata/SigVer.rsp.bz2 diff --git a/src/pkg/crypto/elliptic/elliptic.go b/src/pkg/crypto/elliptic/elliptic.go index 30835a90b..7a4ff6614 100644 --- a/src/pkg/crypto/elliptic/elliptic.go +++ b/src/pkg/crypto/elliptic/elliptic.go @@ -31,10 +31,10 @@ type Curve interface {  	// Double returns 2*(x,y)  	Double(x1, y1 *big.Int) (x, y *big.Int)  	// ScalarMult returns k*(Bx,By) where k is a number in big-endian form. -	ScalarMult(x1, y1 *big.Int, scalar []byte) (x, y *big.Int) -	// ScalarBaseMult returns k*G, where G is the base point of the group and k -	// is an integer in big-endian form. -	ScalarBaseMult(scalar []byte) (x, y *big.Int) +	ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int) +	// ScalarBaseMult returns k*G, where G is the base point of the group +	// and k is an integer in big-endian form. +	ScalarBaseMult(k []byte) (x, y *big.Int)  }  // CurveParams contains the parameters of an elliptic curve and also provides @@ -69,9 +69,24 @@ func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {  	return x3.Cmp(y2) == 0  } +// zForAffine returns a Jacobian Z value for the affine point (x, y). If x and +// y are zero, it assumes that they represent the point at infinity because (0, +// 0) is not on the any of the curves handled here. +func zForAffine(x, y *big.Int) *big.Int { +	z := new(big.Int) +	if x.Sign() != 0 || y.Sign() != 0 { +		z.SetInt64(1) +	} +	return z +} +  // affineFromJacobian reverses the Jacobian transform. See the comment at the -// top of the file. +// top of the file. If the point is ∞ it returns 0, 0.  func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) { +	if z.Sign() == 0 { +		return new(big.Int), new(big.Int) +	} +  	zinv := new(big.Int).ModInverse(z, curve.P)  	zinvsq := new(big.Int).Mul(zinv, zinv) @@ -84,14 +99,29 @@ func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.  }  func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { -	z := new(big.Int).SetInt64(1) -	return curve.affineFromJacobian(curve.addJacobian(x1, y1, z, x2, y2, z)) +	z1 := zForAffine(x1, y1) +	z2 := zForAffine(x2, y2) +	return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))  }  // addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and  // (x2, y2, z2) and returns their sum, also in Jacobian form.  func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {  	// See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl +	x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int) +	if z1.Sign() == 0 { +		x3.Set(x2) +		y3.Set(y2) +		z3.Set(z2) +		return x3, y3, z3 +	} +	if z2.Sign() == 0 { +		x3.Set(x1) +		y3.Set(y1) +		z3.Set(z1) +		return x3, y3, z3 +	} +  	z1z1 := new(big.Int).Mul(z1, z1)  	z1z1.Mod(z1z1, curve.P)  	z2z2 := new(big.Int).Mul(z2, z2) @@ -102,6 +132,7 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int  	u2 := new(big.Int).Mul(x2, z1z1)  	u2.Mod(u2, curve.P)  	h := new(big.Int).Sub(u2, u1) +	xEqual := h.Sign() == 0  	if h.Sign() == -1 {  		h.Add(h, curve.P)  	} @@ -119,17 +150,21 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int  	if r.Sign() == -1 {  		r.Add(r, curve.P)  	} +	yEqual := r.Sign() == 0 +	if xEqual && yEqual { +		return curve.doubleJacobian(x1, y1, z1) +	}  	r.Lsh(r, 1)  	v := new(big.Int).Mul(u1, i) -	x3 := new(big.Int).Set(r) +	x3.Set(r)  	x3.Mul(x3, x3)  	x3.Sub(x3, j)  	x3.Sub(x3, v)  	x3.Sub(x3, v)  	x3.Mod(x3, curve.P) -	y3 := new(big.Int).Set(r) +	y3.Set(r)  	v.Sub(v, x3)  	y3.Mul(y3, v)  	s1.Mul(s1, j) @@ -137,16 +172,10 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int  	y3.Sub(y3, s1)  	y3.Mod(y3, curve.P) -	z3 := new(big.Int).Add(z1, z2) +	z3.Add(z1, z2)  	z3.Mul(z3, z3)  	z3.Sub(z3, z1z1) -	if z3.Sign() == -1 { -		z3.Add(z3, curve.P) -	}  	z3.Sub(z3, z2z2) -	if z3.Sign() == -1 { -		z3.Add(z3, curve.P) -	}  	z3.Mul(z3, h)  	z3.Mod(z3, curve.P) @@ -154,7 +183,7 @@ func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int  }  func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { -	z1 := new(big.Int).SetInt64(1) +	z1 := zForAffine(x1, y1)  	return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))  } @@ -219,40 +248,19 @@ func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int,  }  func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { -	// We have a slight problem in that the identity of the group (the -	// point at infinity) cannot be represented in (x, y) form on a finite -	// machine. Thus the standard add/double algorithm has to be tweaked -	// slightly: our initial state is not the identity, but x, and we -	// ignore the first true bit in |k|.  If we don't find any true bits in -	// |k|, then we return nil, nil, because we cannot return the identity -	// element. -  	Bz := new(big.Int).SetInt64(1) -	x := Bx -	y := By -	z := Bz +	x, y, z := new(big.Int), new(big.Int), new(big.Int) -	seenFirstTrue := false  	for _, byte := range k {  		for bitNum := 0; bitNum < 8; bitNum++ { -			if seenFirstTrue { -				x, y, z = curve.doubleJacobian(x, y, z) -			} +			x, y, z = curve.doubleJacobian(x, y, z)  			if byte&0x80 == 0x80 { -				if !seenFirstTrue { -					seenFirstTrue = true -				} else { -					x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z) -				} +				x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)  			}  			byte <<= 1  		}  	} -	if !seenFirstTrue { -		return nil, nil -	} -  	return curve.affineFromJacobian(x, y, z)  } @@ -370,7 +378,7 @@ func P384() Curve {  	return p384  } -// P256 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5) +// P521 returns a Curve which implements P-521 (see FIPS 186-3, section D.2.5)  func P521() Curve {  	initonce.Do(initAll)  	return p521 diff --git a/src/pkg/crypto/elliptic/elliptic_test.go b/src/pkg/crypto/elliptic/elliptic_test.go index 1e3407ee0..58f903966 100644 --- a/src/pkg/crypto/elliptic/elliptic_test.go +++ b/src/pkg/crypto/elliptic/elliptic_test.go @@ -322,6 +322,44 @@ func TestGenericBaseMult(t *testing.T) {  	}  } +func TestInfinity(t *testing.T) { +	tests := []struct { +		name  string +		curve Curve +	}{ +		{"p224", P224()}, +		{"p256", P256()}, +	} + +	for _, test := range tests { +		curve := test.curve +		x, y := curve.ScalarBaseMult(nil) +		if x.Sign() != 0 || y.Sign() != 0 { +			t.Errorf("%s: x^0 != ∞", test.name) +		} +		x.SetInt64(0) +		y.SetInt64(0) + +		x2, y2 := curve.Double(x, y) +		if x2.Sign() != 0 || y2.Sign() != 0 { +			t.Errorf("%s: 2∞ != ∞", test.name) +		} + +		baseX := curve.Params().Gx +		baseY := curve.Params().Gy + +		x3, y3 := curve.Add(baseX, baseY, x, y) +		if x3.Cmp(baseX) != 0 || y3.Cmp(baseY) != 0 { +			t.Errorf("%s: x+∞ != x", test.name) +		} + +		x4, y4 := curve.Add(x, y, baseX, baseY) +		if x4.Cmp(baseX) != 0 || y4.Cmp(baseY) != 0 { +			t.Errorf("%s: ∞+x != x", test.name) +		} +	} +} +  func BenchmarkBaseMult(b *testing.B) {  	b.ResetTimer()  	p224 := P224() diff --git a/src/pkg/crypto/elliptic/p224.go b/src/pkg/crypto/elliptic/p224.go index 17571c252..1f7ff3f9d 100644 --- a/src/pkg/crypto/elliptic/p224.go +++ b/src/pkg/crypto/elliptic/p224.go @@ -80,10 +80,14 @@ func (p224Curve) Add(bigX1, bigY1, bigX2, bigY2 *big.Int) (x, y *big.Int) {  	p224FromBig(&x1, bigX1)  	p224FromBig(&y1, bigY1) -	z1[0] = 1 +	if bigX1.Sign() != 0 || bigY1.Sign() != 0 { +		z1[0] = 1 +	}  	p224FromBig(&x2, bigX2)  	p224FromBig(&y2, bigY2) -	z2[0] = 1 +	if bigX2.Sign() != 0 || bigY2.Sign() != 0 { +		z2[0] = 1 +	}  	p224AddJacobian(&x3, &y3, &z3, &x1, &y1, &z1, &x2, &y2, &z2)  	return p224ToAffine(&x3, &y3, &z3) @@ -132,6 +136,44 @@ func (curve p224Curve) ScalarBaseMult(scalar []byte) (x, y *big.Int) {  // exactly, making the reflections during a reduce much nicer.  type p224FieldElement [8]uint32 +// p224P is the order of the field, represented as a p224FieldElement. +var p224P = [8]uint32{1, 0, 0, 0xffff000, 0xfffffff, 0xfffffff, 0xfffffff, 0xfffffff} + +// p224IsZero returns 1 if a == 0 mod p and 0 otherwise. +// +// a[i] < 2**29 +func p224IsZero(a *p224FieldElement) uint32 { +	// Since a p224FieldElement contains 224 bits there are two possible +	// representations of 0: 0 and p. +	var minimal p224FieldElement +	p224Contract(&minimal, a) + +	var isZero, isP uint32 +	for i, v := range minimal { +		isZero |= v +		isP |= v - p224P[i] +	} + +	// If either isZero or isP is 0, then we should return 1. +	isZero |= isZero >> 16 +	isZero |= isZero >> 8 +	isZero |= isZero >> 4 +	isZero |= isZero >> 2 +	isZero |= isZero >> 1 + +	isP |= isP >> 16 +	isP |= isP >> 8 +	isP |= isP >> 4 +	isP |= isP >> 2 +	isP |= isP >> 1 + +	// For isZero and isP, the LSB is 0 iff all the bits are zero. +	result := isZero & isP +	result = (^result) & 1 + +	return result +} +  // p224Add computes *out = a+b  //  // a[i] + b[i] < 2**32 @@ -406,7 +448,7 @@ func p224Contract(out, in *p224FieldElement) {  	// true.  	top4AllOnes := uint32(0xffffffff)  	for i := 4; i < 8; i++ { -		top4AllOnes &= (out[i] & bottom28Bits) - 1 +		top4AllOnes &= out[i]  	}  	top4AllOnes |= 0xf0000000  	// Now we replicate any zero bits to all the bits in top4AllOnes. @@ -441,7 +483,7 @@ func p224Contract(out, in *p224FieldElement) {  	out3Equal = ^uint32(int32(out3Equal<<31) >> 31)  	// If out[3] > 0xffff000 then n's MSB will be zero. -	out3GT := ^uint32(int32(n<<31) >> 31) +	out3GT := ^uint32(int32(n) >> 31)  	mask := top4AllOnes & ((out3Equal & bottom3NonZero) | out3GT)  	out[0] -= 1 & mask @@ -463,6 +505,9 @@ func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) {  	var z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v p224FieldElement  	var c p224LargeFieldElement +	z1IsZero := p224IsZero(z1) +	z2IsZero := p224IsZero(z2) +  	// Z1Z1 = Z1²  	p224Square(&z1z1, z1, &c)  	// Z2Z2 = Z2² @@ -480,6 +525,7 @@ func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) {  	// H = U2-U1  	p224Sub(&h, &u2, &u1)  	p224Reduce(&h) +	xEqual := p224IsZero(&h)  	// I = (2*H)²  	for j := 0; j < 8; j++ {  		i[j] = h[j] << 1 @@ -491,6 +537,11 @@ func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) {  	// r = 2*(S2-S1)  	p224Sub(&r, &s2, &s1)  	p224Reduce(&r) +	yEqual := p224IsZero(&r) +	if xEqual == 1 && yEqual == 1 && z1IsZero == 0 && z2IsZero == 0 { +		p224DoubleJacobian(x3, y3, z3, x1, y1, z1) +		return +	}  	for i := 0; i < 8; i++ {  		r[i] <<= 1  	} @@ -524,6 +575,13 @@ func p224AddJacobian(x3, y3, z3, x1, y1, z1, x2, y2, z2 *p224FieldElement) {  	p224Mul(&z1z1, &z1z1, &r, &c)  	p224Sub(y3, &z1z1, &s1)  	p224Reduce(y3) + +	p224CopyConditional(x3, x2, z1IsZero) +	p224CopyConditional(x3, x1, z2IsZero) +	p224CopyConditional(y3, y2, z1IsZero) +	p224CopyConditional(y3, y1, z2IsZero) +	p224CopyConditional(z3, z2, z1IsZero) +	p224CopyConditional(z3, z1, z2IsZero)  }  // p224DoubleJacobian computes *out = a+a. @@ -593,22 +651,19 @@ func p224CopyConditional(out, in *p224FieldElement, control uint32) {  func p224ScalarMult(outX, outY, outZ, inX, inY, inZ *p224FieldElement, scalar []byte) {  	var xx, yy, zz p224FieldElement  	for i := 0; i < 8; i++ { +		outX[i] = 0 +		outY[i] = 0  		outZ[i] = 0  	} -	firstBit := uint32(1)  	for _, byte := range scalar {  		for bitNum := uint(0); bitNum < 8; bitNum++ {  			p224DoubleJacobian(outX, outY, outZ, outX, outY, outZ)  			bit := uint32((byte >> (7 - bitNum)) & 1)  			p224AddJacobian(&xx, &yy, &zz, inX, inY, inZ, outX, outY, outZ) -			p224CopyConditional(outX, inX, firstBit&bit) -			p224CopyConditional(outY, inY, firstBit&bit) -			p224CopyConditional(outZ, inZ, firstBit&bit) -			p224CopyConditional(outX, &xx, ^firstBit&bit) -			p224CopyConditional(outY, &yy, ^firstBit&bit) -			p224CopyConditional(outZ, &zz, ^firstBit&bit) -			firstBit = firstBit & ^bit +			p224CopyConditional(outX, &xx, bit) +			p224CopyConditional(outY, &yy, bit) +			p224CopyConditional(outZ, &zz, bit)  		}  	}  } @@ -618,16 +673,8 @@ func p224ToAffine(x, y, z *p224FieldElement) (*big.Int, *big.Int) {  	var zinv, zinvsq, outx, outy p224FieldElement  	var tmp p224LargeFieldElement -	isPointAtInfinity := true -	for i := 0; i < 8; i++ { -		if z[i] != 0 { -			isPointAtInfinity = false -			break -		} -	} - -	if isPointAtInfinity { -		return nil, nil +	if isPointAtInfinity := p224IsZero(z); isPointAtInfinity == 1 { +		return new(big.Int), new(big.Int)  	}  	p224Invert(&zinv, z) diff --git a/src/pkg/crypto/hmac/hmac.go b/src/pkg/crypto/hmac/hmac.go index a97ce0972..b6f4919a7 100644 --- a/src/pkg/crypto/hmac/hmac.go +++ b/src/pkg/crypto/hmac/hmac.go @@ -2,13 +2,27 @@  // Use of this source code is governed by a BSD-style  // license that can be found in the LICENSE file. -// Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as -// defined in U.S. Federal Information Processing Standards Publication 198. -// An HMAC is a cryptographic hash that uses a key to sign a message. -// The receiver verifies the hash by recomputing it using the same key. +/* +Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as +defined in U.S. Federal Information Processing Standards Publication 198. +An HMAC is a cryptographic hash that uses a key to sign a message. +The receiver verifies the hash by recomputing it using the same key. + +Receivers should be careful to use Equal to compare MACs in order to avoid +timing side-channels: + +	// CheckMAC returns true if messageMAC is a valid HMAC tag for message. +	func CheckMAC(message, messageMAC, key []byte) bool { +		mac := hmac.New(sha256.New, key) +		mac.Write(message) +		expectedMAC := mac.Sum(nil) +		return hmac.Equal(messageMAC, expectedMAC) +	} +*/  package hmac  import ( +	"crypto/subtle"  	"hash"  ) @@ -57,7 +71,7 @@ func (h *hmac) BlockSize() int { return h.blocksize }  func (h *hmac) Reset() {  	h.inner.Reset()  	h.tmpPad(0x36) -	h.inner.Write(h.tmp[0:h.blocksize]) +	h.inner.Write(h.tmp[:h.blocksize])  }  // New returns a new HMAC hash using the given hash.Hash type and key. @@ -78,3 +92,11 @@ func New(h func() hash.Hash, key []byte) hash.Hash {  	hm.Reset()  	return hm  } + +// Equal compares two MACs for equality without leaking timing information. +func Equal(mac1, mac2 []byte) bool { +	// We don't have to be constant time if the lengths of the MACs are +	// different as that suggests that a completely different hash function +	// was used. +	return len(mac1) == len(mac2) && subtle.ConstantTimeCompare(mac1, mac2) == 1 +} diff --git a/src/pkg/crypto/hmac/hmac_test.go b/src/pkg/crypto/hmac/hmac_test.go index 07957414c..d4860424e 100644 --- a/src/pkg/crypto/hmac/hmac_test.go +++ b/src/pkg/crypto/hmac/hmac_test.go @@ -491,3 +491,22 @@ func TestHMAC(t *testing.T) {  		}  	}  } + +func TestEqual(t *testing.T) { +	a := []byte("test") +	b := []byte("test1") +	c := []byte("test2") + +	if !Equal(b, b) { +		t.Error("Equal failed with equal arguments") +	} +	if Equal(a, b) { +		t.Error("Equal accepted a prefix of the second argument") +	} +	if Equal(b, a) { +		t.Error("Equal accepted a prefix of the first argument") +	} +	if Equal(b, c) { +		t.Error("Equal accepted unequal slices") +	} +} diff --git a/src/pkg/crypto/md5/gen.go b/src/pkg/crypto/md5/gen.go new file mode 100644 index 000000000..966bdae26 --- /dev/null +++ b/src/pkg/crypto/md5/gen.go @@ -0,0 +1,300 @@ +// Copyright 2012 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 + +// This program generates md5block.go +// Invoke as +// +//	go run gen.go [-full] |gofmt >md5block.go +// +// The -full flag causes the generated code to do a full +// (16x) unrolling instead of a 4x unrolling. + +package main + +import ( +	"flag" +	"log" +	"os" +	"strings" +	"text/template" +) + +func main() { +	flag.Parse() + +	t := template.Must(template.New("main").Funcs(funcs).Parse(program)) +	if err := t.Execute(os.Stdout, data); err != nil { +		log.Fatal(err) +	} +} + +type Data struct { +	a, b, c, d string +	Shift1     []int +	Shift2     []int +	Shift3     []int +	Shift4     []int +	Table1     []uint32 +	Table2     []uint32 +	Table3     []uint32 +	Table4     []uint32 +	Full       bool +} + +var funcs = template.FuncMap{ +	"dup":     dup, +	"relabel": relabel, +	"rotate":  rotate, +} + +func dup(count int, x []int) []int { +	var out []int +	for i := 0; i < count; i++ { +		out = append(out, x...) +	} +	return out +} + +func relabel(s string) string { +	return strings.NewReplacer("a", data.a, "b", data.b, "c", data.c, "d", data.d).Replace(s) +} + +func rotate() string { +	data.a, data.b, data.c, data.d = data.d, data.a, data.b, data.c +	return "" // no output +} + +func init() { +	flag.BoolVar(&data.Full, "full", false, "complete unrolling") +} + +var data = Data{ +	a:      "a", +	b:      "b", +	c:      "c", +	d:      "d", +	Shift1: []int{7, 12, 17, 22}, +	Shift2: []int{5, 9, 14, 20}, +	Shift3: []int{4, 11, 16, 23}, +	Shift4: []int{6, 10, 15, 21}, + +	// table[i] = int((1<<32) * abs(sin(i+1 radians))). +	Table1: []uint32{ +		// round 1 +		0xd76aa478, +		0xe8c7b756, +		0x242070db, +		0xc1bdceee, +		0xf57c0faf, +		0x4787c62a, +		0xa8304613, +		0xfd469501, +		0x698098d8, +		0x8b44f7af, +		0xffff5bb1, +		0x895cd7be, +		0x6b901122, +		0xfd987193, +		0xa679438e, +		0x49b40821, +	}, +	Table2: []uint32{ +		// round 2 +		0xf61e2562, +		0xc040b340, +		0x265e5a51, +		0xe9b6c7aa, +		0xd62f105d, +		0x2441453, +		0xd8a1e681, +		0xe7d3fbc8, +		0x21e1cde6, +		0xc33707d6, +		0xf4d50d87, +		0x455a14ed, +		0xa9e3e905, +		0xfcefa3f8, +		0x676f02d9, +		0x8d2a4c8a, +	}, +	Table3: []uint32{ +		// round3 +		0xfffa3942, +		0x8771f681, +		0x6d9d6122, +		0xfde5380c, +		0xa4beea44, +		0x4bdecfa9, +		0xf6bb4b60, +		0xbebfbc70, +		0x289b7ec6, +		0xeaa127fa, +		0xd4ef3085, +		0x4881d05, +		0xd9d4d039, +		0xe6db99e5, +		0x1fa27cf8, +		0xc4ac5665, +	}, +	Table4: []uint32{ +		// round 4 +		0xf4292244, +		0x432aff97, +		0xab9423a7, +		0xfc93a039, +		0x655b59c3, +		0x8f0ccc92, +		0xffeff47d, +		0x85845dd1, +		0x6fa87e4f, +		0xfe2ce6e0, +		0xa3014314, +		0x4e0811a1, +		0xf7537e82, +		0xbd3af235, +		0x2ad7d2bb, +		0xeb86d391, +	}, +} + +var program = ` +package md5 + +import ( +	"unsafe" +	"runtime" +) + +{{if not .Full}} +	var t1 = [...]uint32{ +	{{range .Table1}}{{printf "\t%#x,\n" .}}{{end}} +	} +	 +	var t2 = [...]uint32{ +	{{range .Table2}}{{printf "\t%#x,\n" .}}{{end}} +	} +	 +	var t3 = [...]uint32{ +	{{range .Table3}}{{printf "\t%#x,\n" .}}{{end}} +	} +	 +	var t4 = [...]uint32{ +	{{range .Table4}}{{printf "\t%#x,\n" .}}{{end}} +	} +{{end}} + +func block(dig *digest, p []byte) { +	a := dig.s[0] +	b := dig.s[1] +	c := dig.s[2] +	d := dig.s[3] +	var X *[16]uint32 +	var xbuf [16]uint32 +	for len(p) >= chunk { +		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" { +			// 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 { +			X = (*[16]uint32)(unsafe.Pointer(&p[0])) +		} else { +			X = &xbuf +			j := 0 +			for i := 0; i < 16; i++ { +				X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 +				j += 4 +			} +		} + +		{{if .Full}} +			// Round 1. +			{{range $i, $s := dup 4 .Shift1}} +				{{index $.Table1 $i | printf "a += (((c^d)&b)^d) + X[%d] + %d" $i | relabel}} +				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +				{{rotate}} +			{{end}} +	 +			// Round 2. +			{{range $i, $s := dup 4 .Shift2}} +				{{index $.Table2 $i | printf "a += (((b^c)&d)^c) + X[(1+5*%d)&15] + %d" $i | relabel}} +				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +				{{rotate}} +			{{end}} +	 +			// Round 3. +			{{range $i, $s := dup 4 .Shift3}} +				{{index $.Table3 $i | printf "a += (b^c^d) + X[(5+3*%d)&15] + %d" $i | relabel}} +				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +				{{rotate}} +			{{end}} +	 +			// Round 4. +			{{range $i, $s := dup 4 .Shift4}} +				{{index $.Table4 $i | printf "a += (c^(b|^d)) + X[(7*%d)&15] + %d" $i | relabel}} +				{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +				{{rotate}} +			{{end}} +		{{else}} +			// Round 1. +			for i := uint(0); i < 16; { +				{{range $s := .Shift1}} +					{{printf "a += (((c^d)&b)^d) + X[i&15] + t1[i&15]" | relabel}} +					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +					i++ +					{{rotate}} +				{{end}} +			} +	 +			// Round 2. +			for i := uint(0); i < 16; { +				{{range $s := .Shift2}} +					{{printf "a += (((b^c)&d)^c) + X[(1+5*i)&15] + t2[i&15]" | relabel}} +					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +					i++ +					{{rotate}} +				{{end}} +			} +	 +			// Round 3. +			for i := uint(0); i < 16; { +				{{range $s := .Shift3}} +					{{printf "a += (b^c^d) + X[(5+3*i)&15] + t3[i&15]" | relabel}} +					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +					i++ +					{{rotate}} +				{{end}} +			} +	 +			// Round 4. +			for i := uint(0); i < 16; { +				{{range $s := .Shift4}} +					{{printf "a += (c^(b|^d)) + X[(7*i)&15] + t4[i&15]" | relabel}} +					{{printf "a = a<<%d | a>>(32-%d) + b" $s $s | relabel}} +					i++ +					{{rotate}} +				{{end}} +			} +		{{end}} + +		a += aa +		b += bb +		c += cc +		d += dd + +		p = p[chunk:] +	} + +	dig.s[0] = a +	dig.s[1] = b +	dig.s[2] = c +	dig.s[3] = d +} +` diff --git a/src/pkg/crypto/md5/md5.go b/src/pkg/crypto/md5/md5.go index cfb728c94..825e5c8a2 100644 --- a/src/pkg/crypto/md5/md5.go +++ b/src/pkg/crypto/md5/md5.go @@ -21,26 +21,26 @@ const Size = 16  const BlockSize = 64  const ( -	_Chunk = 64 -	_Init0 = 0x67452301 -	_Init1 = 0xEFCDAB89 -	_Init2 = 0x98BADCFE -	_Init3 = 0x10325476 +	chunk = 64 +	init0 = 0x67452301 +	init1 = 0xEFCDAB89 +	init2 = 0x98BADCFE +	init3 = 0x10325476  )  // digest represents the partial evaluation of a checksum.  type digest struct {  	s   [4]uint32 -	x   [_Chunk]byte +	x   [chunk]byte  	nx  int  	len uint64  }  func (d *digest) Reset() { -	d.s[0] = _Init0 -	d.s[1] = _Init1 -	d.s[2] = _Init2 -	d.s[3] = _Init3 +	d.s[0] = init0 +	d.s[1] = init1 +	d.s[2] = init2 +	d.s[3] = init3  	d.nx = 0  	d.len = 0  } @@ -61,21 +61,24 @@ func (d *digest) Write(p []byte) (nn int, err error) {  	d.len += uint64(nn)  	if d.nx > 0 {  		n := len(p) -		if n > _Chunk-d.nx { -			n = _Chunk - d.nx +		if n > chunk-d.nx { +			n = chunk - d.nx  		}  		for i := 0; i < n; i++ {  			d.x[d.nx+i] = p[i]  		}  		d.nx += n -		if d.nx == _Chunk { -			_Block(d, d.x[0:]) +		if d.nx == chunk { +			block(d, d.x[0:chunk])  			d.nx = 0  		}  		p = p[n:]  	} -	n := _Block(d, p) -	p = p[n:] +	if len(p) >= chunk { +		n := len(p) &^ (chunk - 1) +		block(d, p[:n]) +		p = p[n:] +	}  	if len(p) > 0 {  		d.nx = copy(d.x[:], p)  	} diff --git a/src/pkg/crypto/md5/md5_test.go b/src/pkg/crypto/md5/md5_test.go index aae875464..3ef4519b9 100644 --- a/src/pkg/crypto/md5/md5_test.go +++ b/src/pkg/crypto/md5/md5_test.go @@ -2,13 +2,13 @@  // 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" +	"unsafe"  )  type md5Test struct { @@ -53,14 +53,20 @@ var golden = []md5Test{  func TestGolden(t *testing.T) {  	for i := 0; i < len(golden); i++ {  		g := golden[i] -		c := md5.New() -		for j := 0; j < 3; j++ { +		c := New() +		buf := make([]byte, len(g.in)+4) +		for j := 0; j < 3+4; j++ {  			if j < 2 {  				io.WriteString(c, g.in) -			} else { +			} else if j == 2 {  				io.WriteString(c, g.in[0:len(g.in)/2])  				c.Sum(nil)  				io.WriteString(c, g.in[len(g.in)/2:]) +			} else if j > 2 { +				// test unaligned write +				buf = buf[1:] +				copy(buf, g.in) +				c.Write(buf[:len(g.in)])  			}  			s := fmt.Sprintf("%x", c.Sum(nil))  			if s != g.out { @@ -72,9 +78,53 @@ 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 = New() +var buf = make([]byte, 8192+1) +var sum = make([]byte, bench.Size()) + +func benchmarkSize(b *testing.B, size int, unaligned bool) { +	b.SetBytes(int64(size)) +	buf := buf +	if unaligned { +		if uintptr(unsafe.Pointer(&buf[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { +			buf = buf[1:] +		} +	} +	b.ResetTimer() +	for i := 0; i < b.N; i++ { +		bench.Reset() +		bench.Write(buf[:size]) +		bench.Sum(sum[:0]) +	} +} + +func BenchmarkHash8Bytes(b *testing.B) { +	benchmarkSize(b, 8, false) +} + +func BenchmarkHash1K(b *testing.B) { +	benchmarkSize(b, 1024, false) +} + +func BenchmarkHash8K(b *testing.B) { +	benchmarkSize(b, 8192, false) +} + +func BenchmarkHash8BytesUnaligned(b *testing.B) { +	benchmarkSize(b, 8, true) +} + +func BenchmarkHash1KUnaligned(b *testing.B) { +	benchmarkSize(b, 1024, true) +} + +func BenchmarkHash8KUnaligned(b *testing.B) { +	benchmarkSize(b, 8192, true) +} diff --git a/src/pkg/crypto/md5/md5block.go b/src/pkg/crypto/md5/md5block.go index a887e2e05..0ca421774 100644 --- a/src/pkg/crypto/md5/md5block.go +++ b/src/pkg/crypto/md5/md5block.go @@ -1,172 +1,258 @@ -// Copyright 2009 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 md5 -// MD5 block step. -// In its own file so that a faster assembly or C version -// can be substituted easily. +import ( +	"runtime" +	"unsafe" +) -package md5 +const x86 = runtime.GOARCH == "amd64" || runtime.GOARCH == "386" -// table[i] = int((1<<32) * abs(sin(i+1 radians))). -var table = []uint32{ -	// round 1 -	0xd76aa478, -	0xe8c7b756, -	0x242070db, -	0xc1bdceee, -	0xf57c0faf, -	0x4787c62a, -	0xa8304613, -	0xfd469501, -	0x698098d8, -	0x8b44f7af, -	0xffff5bb1, -	0x895cd7be, -	0x6b901122, -	0xfd987193, -	0xa679438e, -	0x49b40821, - -	// round 2 -	0xf61e2562, -	0xc040b340, -	0x265e5a51, -	0xe9b6c7aa, -	0xd62f105d, -	0x2441453, -	0xd8a1e681, -	0xe7d3fbc8, -	0x21e1cde6, -	0xc33707d6, -	0xf4d50d87, -	0x455a14ed, -	0xa9e3e905, -	0xfcefa3f8, -	0x676f02d9, -	0x8d2a4c8a, - -	// round3 -	0xfffa3942, -	0x8771f681, -	0x6d9d6122, -	0xfde5380c, -	0xa4beea44, -	0x4bdecfa9, -	0xf6bb4b60, -	0xbebfbc70, -	0x289b7ec6, -	0xeaa127fa, -	0xd4ef3085, -	0x4881d05, -	0xd9d4d039, -	0xe6db99e5, -	0x1fa27cf8, -	0xc4ac5665, - -	// round 4 -	0xf4292244, -	0x432aff97, -	0xab9423a7, -	0xfc93a039, -	0x655b59c3, -	0x8f0ccc92, -	0xffeff47d, -	0x85845dd1, -	0x6fa87e4f, -	0xfe2ce6e0, -	0xa3014314, -	0x4e0811a1, -	0xf7537e82, -	0xbd3af235, -	0x2ad7d2bb, -	0xeb86d391, -} +var littleEndian bool -var shift1 = []uint{7, 12, 17, 22} -var shift2 = []uint{5, 9, 14, 20} -var shift3 = []uint{4, 11, 16, 23} -var shift4 = []uint{6, 10, 15, 21} +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) int { +func block(dig *digest, p []byte) {  	a := dig.s[0]  	b := dig.s[1]  	c := dig.s[2]  	d := dig.s[3] -	n := 0 -	var X [16]uint32 -	for len(p) >= _Chunk { +	var X *[16]uint32 +	var xbuf [16]uint32 +	for len(p) >= chunk {  		aa, bb, cc, dd := a, b, c, d -		j := 0 -		for i := 0; i < 16; i++ { -			X[i] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 -			j += 4 +		// This is a constant condition - it is not evaluated on each iteration. +		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 littleEndian && uintptr(unsafe.Pointer(&p[0]))&(unsafe.Alignof(uint32(0))-1) == 0 { +			X = (*[16]uint32)(unsafe.Pointer(&p[0])) +		} else { +			X = &xbuf +			j := 0 +			for i := 0; i < 16; i++ { +				X[i&15] = uint32(p[j]) | uint32(p[j+1])<<8 | uint32(p[j+2])<<16 | uint32(p[j+3])<<24 +				j += 4 +			}  		} -		// If this needs to be made faster in the future, -		// the usual trick is to unroll each of these -		// loops by a factor of 4; that lets you replace -		// the shift[] lookups with constants and, -		// with suitable variable renaming in each -		// unrolled body, delete the a, b, c, d = d, a, b, c -		// (or you can let the optimizer do the renaming). -		// -		// The index variables are uint so that % by a power -		// of two can be optimized easily by a compiler. -  		// Round 1. -		for i := uint(0); i < 16; i++ { -			x := i -			s := shift1[i%4] -			f := ((c ^ d) & b) ^ d -			a += f + X[x] + table[i] -			a = a<<s | a>>(32-s) + b -			a, b, c, d = d, a, b, c -		} + +		a += (((c ^ d) & b) ^ d) + X[0] + 3614090360 +		a = a<<7 | a>>(32-7) + b + +		d += (((b ^ c) & a) ^ c) + X[1] + 3905402710 +		d = d<<12 | d>>(32-12) + a + +		c += (((a ^ b) & d) ^ b) + X[2] + 606105819 +		c = c<<17 | c>>(32-17) + d + +		b += (((d ^ a) & c) ^ a) + X[3] + 3250441966 +		b = b<<22 | b>>(32-22) + c + +		a += (((c ^ d) & b) ^ d) + X[4] + 4118548399 +		a = a<<7 | a>>(32-7) + b + +		d += (((b ^ c) & a) ^ c) + X[5] + 1200080426 +		d = d<<12 | d>>(32-12) + a + +		c += (((a ^ b) & d) ^ b) + X[6] + 2821735955 +		c = c<<17 | c>>(32-17) + d + +		b += (((d ^ a) & c) ^ a) + X[7] + 4249261313 +		b = b<<22 | b>>(32-22) + c + +		a += (((c ^ d) & b) ^ d) + X[8] + 1770035416 +		a = a<<7 | a>>(32-7) + b + +		d += (((b ^ c) & a) ^ c) + X[9] + 2336552879 +		d = d<<12 | d>>(32-12) + a + +		c += (((a ^ b) & d) ^ b) + X[10] + 4294925233 +		c = c<<17 | c>>(32-17) + d + +		b += (((d ^ a) & c) ^ a) + X[11] + 2304563134 +		b = b<<22 | b>>(32-22) + c + +		a += (((c ^ d) & b) ^ d) + X[12] + 1804603682 +		a = a<<7 | a>>(32-7) + b + +		d += (((b ^ c) & a) ^ c) + X[13] + 4254626195 +		d = d<<12 | d>>(32-12) + a + +		c += (((a ^ b) & d) ^ b) + X[14] + 2792965006 +		c = c<<17 | c>>(32-17) + d + +		b += (((d ^ a) & c) ^ a) + X[15] + 1236535329 +		b = b<<22 | b>>(32-22) + c  		// Round 2. -		for i := uint(0); i < 16; i++ { -			x := (1 + 5*i) % 16 -			s := shift2[i%4] -			g := ((b ^ c) & d) ^ c -			a += g + X[x] + table[i+16] -			a = a<<s | a>>(32-s) + b -			a, b, c, d = d, a, b, c -		} + +		a += (((b ^ c) & d) ^ c) + X[(1+5*0)&15] + 4129170786 +		a = a<<5 | a>>(32-5) + b + +		d += (((a ^ b) & c) ^ b) + X[(1+5*1)&15] + 3225465664 +		d = d<<9 | d>>(32-9) + a + +		c += (((d ^ a) & b) ^ a) + X[(1+5*2)&15] + 643717713 +		c = c<<14 | c>>(32-14) + d + +		b += (((c ^ d) & a) ^ d) + X[(1+5*3)&15] + 3921069994 +		b = b<<20 | b>>(32-20) + c + +		a += (((b ^ c) & d) ^ c) + X[(1+5*4)&15] + 3593408605 +		a = a<<5 | a>>(32-5) + b + +		d += (((a ^ b) & c) ^ b) + X[(1+5*5)&15] + 38016083 +		d = d<<9 | d>>(32-9) + a + +		c += (((d ^ a) & b) ^ a) + X[(1+5*6)&15] + 3634488961 +		c = c<<14 | c>>(32-14) + d + +		b += (((c ^ d) & a) ^ d) + X[(1+5*7)&15] + 3889429448 +		b = b<<20 | b>>(32-20) + c + +		a += (((b ^ c) & d) ^ c) + X[(1+5*8)&15] + 568446438 +		a = a<<5 | a>>(32-5) + b + +		d += (((a ^ b) & c) ^ b) + X[(1+5*9)&15] + 3275163606 +		d = d<<9 | d>>(32-9) + a + +		c += (((d ^ a) & b) ^ a) + X[(1+5*10)&15] + 4107603335 +		c = c<<14 | c>>(32-14) + d + +		b += (((c ^ d) & a) ^ d) + X[(1+5*11)&15] + 1163531501 +		b = b<<20 | b>>(32-20) + c + +		a += (((b ^ c) & d) ^ c) + X[(1+5*12)&15] + 2850285829 +		a = a<<5 | a>>(32-5) + b + +		d += (((a ^ b) & c) ^ b) + X[(1+5*13)&15] + 4243563512 +		d = d<<9 | d>>(32-9) + a + +		c += (((d ^ a) & b) ^ a) + X[(1+5*14)&15] + 1735328473 +		c = c<<14 | c>>(32-14) + d + +		b += (((c ^ d) & a) ^ d) + X[(1+5*15)&15] + 2368359562 +		b = b<<20 | b>>(32-20) + c  		// Round 3. -		for i := uint(0); i < 16; i++ { -			x := (5 + 3*i) % 16 -			s := shift3[i%4] -			h := b ^ c ^ d -			a += h + X[x] + table[i+32] -			a = a<<s | a>>(32-s) + b -			a, b, c, d = d, a, b, c -		} + +		a += (b ^ c ^ d) + X[(5+3*0)&15] + 4294588738 +		a = a<<4 | a>>(32-4) + b + +		d += (a ^ b ^ c) + X[(5+3*1)&15] + 2272392833 +		d = d<<11 | d>>(32-11) + a + +		c += (d ^ a ^ b) + X[(5+3*2)&15] + 1839030562 +		c = c<<16 | c>>(32-16) + d + +		b += (c ^ d ^ a) + X[(5+3*3)&15] + 4259657740 +		b = b<<23 | b>>(32-23) + c + +		a += (b ^ c ^ d) + X[(5+3*4)&15] + 2763975236 +		a = a<<4 | a>>(32-4) + b + +		d += (a ^ b ^ c) + X[(5+3*5)&15] + 1272893353 +		d = d<<11 | d>>(32-11) + a + +		c += (d ^ a ^ b) + X[(5+3*6)&15] + 4139469664 +		c = c<<16 | c>>(32-16) + d + +		b += (c ^ d ^ a) + X[(5+3*7)&15] + 3200236656 +		b = b<<23 | b>>(32-23) + c + +		a += (b ^ c ^ d) + X[(5+3*8)&15] + 681279174 +		a = a<<4 | a>>(32-4) + b + +		d += (a ^ b ^ c) + X[(5+3*9)&15] + 3936430074 +		d = d<<11 | d>>(32-11) + a + +		c += (d ^ a ^ b) + X[(5+3*10)&15] + 3572445317 +		c = c<<16 | c>>(32-16) + d + +		b += (c ^ d ^ a) + X[(5+3*11)&15] + 76029189 +		b = b<<23 | b>>(32-23) + c + +		a += (b ^ c ^ d) + X[(5+3*12)&15] + 3654602809 +		a = a<<4 | a>>(32-4) + b + +		d += (a ^ b ^ c) + X[(5+3*13)&15] + 3873151461 +		d = d<<11 | d>>(32-11) + a + +		c += (d ^ a ^ b) + X[(5+3*14)&15] + 530742520 +		c = c<<16 | c>>(32-16) + d + +		b += (c ^ d ^ a) + X[(5+3*15)&15] + 3299628645 +		b = b<<23 | b>>(32-23) + c  		// Round 4. -		for i := uint(0); i < 16; i++ { -			x := (7 * i) % 16 -			s := shift4[i%4] -			j := c ^ (b | ^d) -			a += j + X[x] + table[i+48] -			a = a<<s | a>>(32-s) + b -			a, b, c, d = d, a, b, c -		} + +		a += (c ^ (b | ^d)) + X[(7*0)&15] + 4096336452 +		a = a<<6 | a>>(32-6) + b + +		d += (b ^ (a | ^c)) + X[(7*1)&15] + 1126891415 +		d = d<<10 | d>>(32-10) + a + +		c += (a ^ (d | ^b)) + X[(7*2)&15] + 2878612391 +		c = c<<15 | c>>(32-15) + d + +		b += (d ^ (c | ^a)) + X[(7*3)&15] + 4237533241 +		b = b<<21 | b>>(32-21) + c + +		a += (c ^ (b | ^d)) + X[(7*4)&15] + 1700485571 +		a = a<<6 | a>>(32-6) + b + +		d += (b ^ (a | ^c)) + X[(7*5)&15] + 2399980690 +		d = d<<10 | d>>(32-10) + a + +		c += (a ^ (d | ^b)) + X[(7*6)&15] + 4293915773 +		c = c<<15 | c>>(32-15) + d + +		b += (d ^ (c | ^a)) + X[(7*7)&15] + 2240044497 +		b = b<<21 | b>>(32-21) + c + +		a += (c ^ (b | ^d)) + X[(7*8)&15] + 1873313359 +		a = a<<6 | a>>(32-6) + b + +		d += (b ^ (a | ^c)) + X[(7*9)&15] + 4264355552 +		d = d<<10 | d>>(32-10) + a + +		c += (a ^ (d | ^b)) + X[(7*10)&15] + 2734768916 +		c = c<<15 | c>>(32-15) + d + +		b += (d ^ (c | ^a)) + X[(7*11)&15] + 1309151649 +		b = b<<21 | b>>(32-21) + c + +		a += (c ^ (b | ^d)) + X[(7*12)&15] + 4149444226 +		a = a<<6 | a>>(32-6) + b + +		d += (b ^ (a | ^c)) + X[(7*13)&15] + 3174756917 +		d = d<<10 | d>>(32-10) + a + +		c += (a ^ (d | ^b)) + X[(7*14)&15] + 718787259 +		c = c<<15 | c>>(32-15) + d + +		b += (d ^ (c | ^a)) + X[(7*15)&15] + 3951481745 +		b = b<<21 | b>>(32-21) + c  		a += aa  		b += bb  		c += cc  		d += dd -		p = p[_Chunk:] -		n += _Chunk +		p = p[chunk:]  	}  	dig.s[0] = a  	dig.s[1] = b  	dig.s[2] = c  	dig.s[3] = d -	return n  } diff --git a/src/pkg/crypto/rand/example_test.go b/src/pkg/crypto/rand/example_test.go new file mode 100644 index 000000000..5af8e46f5 --- /dev/null +++ b/src/pkg/crypto/rand/example_test.go @@ -0,0 +1,29 @@ +// Copyright 2011 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 rand_test + +import ( +	"bytes" +	"crypto/rand" +	"fmt" +	"io" +) + +// This example reads 10 cryptographically secure pseudorandom numbers from +// rand.Reader and writes them to a byte slice. +func ExampleRead() { +	c := 10 +	b := make([]byte, c) +	n, err := io.ReadFull(rand.Reader, b) +	if n != len(b) || err != nil { +		fmt.Println("error:", err) +		return +	} +	// The slice should now contain random bytes instead of only zeroes. +	fmt.Println(bytes.Equal(b, make([]byte, c))) + +	// Output: +	// false +} diff --git a/src/pkg/crypto/rand/rand_test.go b/src/pkg/crypto/rand/rand_test.go index be3a5a221..e46e61d37 100644 --- a/src/pkg/crypto/rand/rand_test.go +++ b/src/pkg/crypto/rand/rand_test.go @@ -7,6 +7,7 @@ package rand  import (  	"bytes"  	"compress/flate" +	"io"  	"testing"  ) @@ -16,9 +17,9 @@ func TestRead(t *testing.T) {  		n = 1e5  	}  	b := make([]byte, n) -	n, err := Read(b) +	n, err := io.ReadFull(Reader, b)  	if n != len(b) || err != nil { -		t.Fatalf("Read(buf) = %d, %s", n, err) +		t.Fatalf("ReadFull(buf) = %d, %s", n, err)  	}  	var z bytes.Buffer @@ -29,3 +30,14 @@ func TestRead(t *testing.T) {  		t.Fatalf("Compressed %d -> %d", len(b), z.Len())  	}  } + +func TestReadEmpty(t *testing.T) { +	n, err := Reader.Read(make([]byte, 0)) +	if n != 0 || err != nil { +		t.Fatalf("Read(make([]byte, 0)) = %d, %v", n, err) +	} +	n, err = Reader.Read(nil) +	if n != 0 || err != nil { +		t.Fatalf("Read(nil) = %d, %v", n, err) +	} +} diff --git a/src/pkg/crypto/rand/rand_unix.go b/src/pkg/crypto/rand/rand_unix.go index 5eb4cda2b..18f482472 100644 --- a/src/pkg/crypto/rand/rand_unix.go +++ b/src/pkg/crypto/rand/rand_unix.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 darwin freebsd linux netbsd openbsd +// +build darwin freebsd linux netbsd openbsd plan9  // Unix cryptographically secure pseudorandom number  // generator. @@ -15,6 +15,7 @@ import (  	"crypto/cipher"  	"io"  	"os" +	"runtime"  	"sync"  	"time"  ) @@ -22,7 +23,13 @@ import (  // Easy implementation: read from /dev/urandom.  // This is sufficient on Linux, OS X, and FreeBSD. -func init() { Reader = &devReader{name: "/dev/urandom"} } +func init() { +	if runtime.GOOS == "plan9" { +		Reader = newReader(nil) +	} else { +		Reader = &devReader{name: "/dev/urandom"} +	} +}  // A devReader satisfies reads by reading the file named name.  type devReader struct { @@ -39,14 +46,17 @@ func (r *devReader) Read(b []byte) (n int, err error) {  		if f == nil {  			return 0, err  		} -		r.f = bufio.NewReader(f) +		if runtime.GOOS == "plan9" { +			r.f = f +		} else { +			r.f = bufio.NewReader(f) +		}  	}  	return r.f.Read(b)  }  // Alternate pseudo-random implementation for use on -// systems without a reliable /dev/urandom.  So far we -// haven't needed it. +// systems without a reliable /dev/urandom.  // newReader returns a new pseudorandom generator that  // seeds itself by reading from entropy.  If entropy == nil, diff --git a/src/pkg/crypto/rand/rand_windows.go b/src/pkg/crypto/rand/rand_windows.go index 2b2bd4bba..82b39b64a 100644 --- a/src/pkg/crypto/rand/rand_windows.go +++ b/src/pkg/crypto/rand/rand_windows.go @@ -35,6 +35,10 @@ func (r *rngReader) Read(b []byte) (n int, err error) {  		}  	}  	r.mu.Unlock() + +	if len(b) == 0 { +		return 0, nil +	}  	err = syscall.CryptGenRandom(r.prov, uint32(len(b)), &b[0])  	if err != nil {  		return 0, os.NewSyscallError("CryptGenRandom", err) diff --git a/src/pkg/crypto/rand/util.go b/src/pkg/crypto/rand/util.go index 5391c1829..50e5b162b 100644 --- a/src/pkg/crypto/rand/util.go +++ b/src/pkg/crypto/rand/util.go @@ -10,6 +10,21 @@ import (  	"math/big"  ) +// smallPrimes is a list of small, prime numbers that allows us to rapidly +// exclude some fraction of composite candidates when searching for a random +// prime. This list is truncated at the point where smallPrimesProduct exceeds +// a uint64. It does not include two because we ensure that the candidates are +// odd by construction. +var smallPrimes = []uint8{ +	3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, +} + +// smallPrimesProduct is the product of the values in smallPrimes and allows us +// to reduce a candidate prime by this number and then determine whether it's +// coprime to all the elements of smallPrimes without further big.Int +// operations. +var smallPrimesProduct = new(big.Int).SetUint64(16294579238595022365) +  // Prime returns a number, p, of the given size, such that p is prime  // with high probability.  func Prime(rand io.Reader, bits int) (p *big.Int, err error) { @@ -25,6 +40,8 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {  	bytes := make([]byte, (bits+7)/8)  	p = new(big.Int) +	bigMod := new(big.Int) +  	for {  		_, err = io.ReadFull(rand, bytes)  		if err != nil { @@ -33,13 +50,51 @@ func Prime(rand io.Reader, bits int) (p *big.Int, err error) {  		// Clear bits in the first byte to make sure the candidate has a size <= bits.  		bytes[0] &= uint8(int(1<<b) - 1) -		// Don't let the value be too small, i.e, set the most significant bit. -		bytes[0] |= 1 << (b - 1) +		// Don't let the value be too small, i.e, set the most significant two bits. +		// Setting the top two bits, rather than just the top bit, +		// means that when two of these values are multiplied together, +		// the result isn't ever one bit short. +		if b >= 2 { +			bytes[0] |= 3 << (b - 2) +		} else { +			// Here b==1, because b cannot be zero. +			bytes[0] |= 1 +			if len(bytes) > 1 { +				bytes[1] |= 0x80 +			} +		}  		// Make the value odd since an even number this large certainly isn't prime.  		bytes[len(bytes)-1] |= 1  		p.SetBytes(bytes) -		if p.ProbablyPrime(20) { + +		// Calculate the value mod the product of smallPrimes.  If it's +		// a multiple of any of these primes we add two until it isn't. +		// The probability of overflowing is minimal and can be ignored +		// because we still perform Miller-Rabin tests on the result. +		bigMod.Mod(p, smallPrimesProduct) +		mod := bigMod.Uint64() + +	NextDelta: +		for delta := uint64(0); delta < 1<<20; delta += 2 { +			m := mod + delta +			for _, prime := range smallPrimes { +				if m%uint64(prime) == 0 { +					continue NextDelta +				} +			} + +			if delta > 0 { +				bigMod.SetUint64(delta) +				p.Add(p, bigMod) +			} +			break +		} + +		// There is a tiny possibility that, by adding delta, we caused +		// the number to be one bit too long. Thus we check BitLen +		// here. +		if p.ProbablyPrime(20) && p.BitLen() == bits {  			return  		}  	} diff --git a/src/pkg/crypto/rc4/rc4.go b/src/pkg/crypto/rc4/rc4.go index 1bb278f74..e0c33fa4b 100644 --- a/src/pkg/crypto/rc4/rc4.go +++ b/src/pkg/crypto/rc4/rc4.go @@ -42,17 +42,6 @@ func NewCipher(key []byte) (*Cipher, error) {  	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/src/pkg/crypto/rc4/rc4_amd64.s b/src/pkg/crypto/rc4/rc4_amd64.s new file mode 100644 index 000000000..ffe9ada85 --- /dev/null +++ b/src/pkg/crypto/rc4/rc4_amd64.s @@ -0,0 +1,53 @@ +// 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. + +// func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8) +TEXT ·xorKeyStream(SB),7,$0 +	MOVQ dst+0(FP), DI +	MOVQ src+8(FP), SI +	MOVQ n+16(FP), CX +	MOVQ state+24(FP), R8 + +	MOVQ xPtr+32(FP), AX +	MOVBQZX (AX), AX +	MOVQ yPtr+40(FP), BX +	MOVBQZX (BX), BX + +loop: +	CMPQ CX, $0 +	JE done + +	// c.i += 1 +	INCB AX + +	// c.j += c.s[c.i] +	MOVB (R8)(AX*1), R9 +	ADDB R9, BX + +	MOVBQZX (R8)(BX*1), R10 + +	MOVB R10, (R8)(AX*1) +	MOVB R9, (R8)(BX*1) + +	// R11 = c.s[c.i]+c.s[c.j] +	MOVQ R10, R11 +	ADDB R9, R11 + +	MOVB (R8)(R11*1), R11 +	MOVB (SI), R12 +	XORB R11, R12 +	MOVB R12, (DI) + +	INCQ SI +	INCQ DI +	DECQ CX + +	JMP loop +done: +	MOVQ xPtr+32(FP), R8 +	MOVB AX, (R8) +	MOVQ yPtr+40(FP), R8 +	MOVB BX, (R8) + +	RET diff --git a/src/pkg/crypto/rc4/rc4_arm.s b/src/pkg/crypto/rc4/rc4_arm.s new file mode 100644 index 000000000..51a332f62 --- /dev/null +++ b/src/pkg/crypto/rc4/rc4_arm.s @@ -0,0 +1,58 @@ +// 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. + +// Registers +dst = 0 +src = 1 +n = 2 +state = 3 +pi = 4 +pj = 5 +i = 6 +j = 7 +k = 8 +t = 11 +t2 = 12 + +// func xorKeyStream(dst, src *byte, n int, state *[256]byte, i, j *uint8) +TEXT ·xorKeyStream(SB),7,$0 +	MOVW 0(FP), R(dst) +	MOVW 4(FP), R(src) +	MOVW 8(FP), R(n) +	MOVW 12(FP), R(state) +	MOVW 16(FP), R(pi) +	MOVW 20(FP), R(pj) +	MOVBU (R(pi)), R(i) +	MOVBU (R(pj)), R(j) +	MOVW $0, R(k) + +loop: +	// i += 1; j += state[i] +	ADD $1, R(i) +	AND $0xff, R(i) +	MOVBU R(i)<<0(R(state)), R(t) +	ADD R(t), R(j) +	AND $0xff, R(j) + +	// swap state[i] <-> state[j] +	MOVBU R(j)<<0(R(state)), R(t2) +	MOVB R(t2), R(i)<<0(R(state)) +	MOVB R(t), R(j)<<0(R(state)) + +	// dst[k] = src[k] ^ state[state[i] + state[j]] +	ADD R(t2), R(t) +	AND $0xff, R(t) +	MOVBU R(t)<<0(R(state)), R(t) +	MOVBU R(k)<<0(R(src)), R(t2) +	EOR R(t), R(t2) +	MOVB R(t2), R(k)<<0(R(dst)) + +	ADD $1, R(k) +	CMP R(k), R(n) +	BNE loop + +done: +	MOVB R(i), (R(pi)) +	MOVB R(j), (R(pj)) +	RET diff --git a/src/pkg/crypto/rc4/rc4_asm.go b/src/pkg/crypto/rc4/rc4_asm.go new file mode 100644 index 000000000..0b66e4a9e --- /dev/null +++ b/src/pkg/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 + +package rc4 + +func xorKeyStream(dst, src *byte, n int, state *[256]byte, 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/src/pkg/crypto/rc4/rc4_ref.go b/src/pkg/crypto/rc4/rc4_ref.go new file mode 100644 index 000000000..1018548c2 --- /dev/null +++ b/src/pkg/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 + +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 += c.s[i] +		c.s[i], c.s[j] = c.s[j], c.s[i] +		dst[k] = v ^ c.s[c.s[i]+c.s[j]] +	} +	c.i, c.j = i, j +} diff --git a/src/pkg/crypto/rc4/rc4_test.go b/src/pkg/crypto/rc4/rc4_test.go index 6265d9408..9e12789f7 100644 --- a/src/pkg/crypto/rc4/rc4_test.go +++ b/src/pkg/crypto/rc4/rc4_test.go @@ -37,6 +37,39 @@ 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 TestGolden(t *testing.T) { @@ -51,9 +84,34 @@ func TestGolden(t *testing.T) {  		c.XORKeyStream(keystream, keystream)  		for j, v := range keystream {  			if g.keystream[j] != v { -				t.Errorf("Failed at golden index %d", i) +				t.Errorf("Failed at golden index %d:\n%x\nvs\n%x", i, keystream, g.keystream)  				break  			}  		}  	}  } + +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/src/pkg/crypto/rsa/pkcs1v15.go b/src/pkg/crypto/rsa/pkcs1v15.go index a32236e47..28ca5d73b 100644 --- a/src/pkg/crypto/rsa/pkcs1v15.go +++ b/src/pkg/crypto/rsa/pkcs1v15.go @@ -19,16 +19,19 @@ import (  // WARNING: use of this function to encrypt plaintexts other than session keys  // is dangerous. Use RSA OAEP in new protocols.  func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, err error) { +	if err := checkPub(pub); err != nil { +		return nil, err +	}  	k := (pub.N.BitLen() + 7) / 8  	if len(msg) > k-11 {  		err = ErrMessageTooLong  		return  	} -	// EM = 0x02 || PS || 0x00 || M -	em := make([]byte, k-1) -	em[0] = 2 -	ps, mm := em[1:len(em)-len(msg)-1], em[len(em)-len(msg):] +	// EM = 0x00 || 0x02 || PS || 0x00 || M +	em := make([]byte, k) +	em[1] = 2 +	ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):]  	err = nonZeroRandomBytes(ps, rand)  	if err != nil {  		return @@ -38,13 +41,18 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er  	m := new(big.Int).SetBytes(em)  	c := encrypt(new(big.Int), pub, m) -	out = c.Bytes() + +	copyWithLeftPad(em, c.Bytes()) +	out = em  	return  }  // DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS#1 v1.5.  // If rand != nil, it uses RSA blinding to avoid timing side-channel attacks.  func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out []byte, err error) { +	if err := checkPub(&priv.PublicKey); err != nil { +		return nil, err +	}  	valid, out, err := decryptPKCS1v15(rand, priv, ciphertext)  	if err == nil && valid == 0 {  		err = ErrDecryption @@ -67,6 +75,9 @@ func DecryptPKCS1v15(rand io.Reader, priv *PrivateKey, ciphertext []byte) (out [  // Encryption Standard PKCS #1'', Daniel Bleichenbacher, Advances in Cryptology  // (Crypto '98).  func DecryptPKCS1v15SessionKey(rand io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) (err error) { +	if err := checkPub(&priv.PublicKey); err != nil { +		return err +	}  	k := (priv.N.BitLen() + 7) / 8  	if k-(len(key)+3+8) < 0 {  		err = ErrDecryption @@ -185,9 +196,12 @@ func SignPKCS1v15(rand io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []b  	m := new(big.Int).SetBytes(em)  	c, err := decrypt(rand, priv, m) -	if err == nil { -		s = c.Bytes() +	if err != nil { +		return  	} + +	copyWithLeftPad(em, c.Bytes()) +	s = em  	return  } @@ -233,11 +247,21 @@ func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte)  func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {  	hashLen = hash.Size()  	if inLen != hashLen { -		return 0, nil, errors.New("input must be hashed message") +		return 0, nil, errors.New("crypto/rsa: input must be hashed message")  	}  	prefix, ok := hashPrefixes[hash]  	if !ok { -		return 0, nil, errors.New("unsupported hash function") +		return 0, nil, errors.New("crypto/rsa: unsupported hash function")  	}  	return  } + +// copyWithLeftPad copies src to the end of dest, padding with zero bytes as +// needed. +func copyWithLeftPad(dest, src []byte) { +	numPaddingBytes := len(dest) - len(src) +	for i := 0; i < numPaddingBytes; i++ { +		dest[i] = 0 +	} +	copy(dest[numPaddingBytes:], src) +} diff --git a/src/pkg/crypto/rsa/pkcs1v15_test.go b/src/pkg/crypto/rsa/pkcs1v15_test.go index 58d5fda19..bf9219bae 100644 --- a/src/pkg/crypto/rsa/pkcs1v15_test.go +++ b/src/pkg/crypto/rsa/pkcs1v15_test.go @@ -57,7 +57,7 @@ func TestDecryptPKCS1v15(t *testing.T) {  			t.Errorf("#%d error decrypting", i)  		}  		want := []byte(test.out) -		if bytes.Compare(out, want) != 0 { +		if !bytes.Equal(out, want) {  			t.Errorf("#%d got:%#v want:%#v", i, out, want)  		}  	} @@ -90,7 +90,7 @@ func TestEncryptPKCS1v15(t *testing.T) {  			return false  		} -		if bytes.Compare(plaintext, in) != 0 { +		if !bytes.Equal(plaintext, in) {  			t.Errorf("output mismatch: %#v %#v", plaintext, in)  			return false  		} @@ -132,7 +132,7 @@ func TestEncryptPKCS1v15SessionKey(t *testing.T) {  			t.Errorf("#%d error decrypting", i)  		}  		want := []byte(test.out) -		if bytes.Compare(key, want) != 0 { +		if !bytes.Equal(key, want) {  			t.Errorf("#%d got:%#v want:%#v", i, key, want)  		}  	} @@ -176,7 +176,7 @@ func TestSignPKCS1v15(t *testing.T) {  		}  		expected, _ := hex.DecodeString(test.out) -		if bytes.Compare(s, expected) != 0 { +		if !bytes.Equal(s, expected) {  			t.Errorf("#%d got: %x want: %x", i, s, expected)  		}  	} diff --git a/src/pkg/crypto/rsa/rsa.go b/src/pkg/crypto/rsa/rsa.go index ec77e6869..35a5f7c3c 100644 --- a/src/pkg/crypto/rsa/rsa.go +++ b/src/pkg/crypto/rsa/rsa.go @@ -25,6 +25,30 @@ type PublicKey struct {  	E int      // public exponent  } +var ( +	errPublicModulus       = errors.New("crypto/rsa: missing public modulus") +	errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small") +	errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large") +) + +// checkPub sanity checks the public key before we use it. +// We require pub.E to fit into a 32-bit integer so that we +// do not have different behavior depending on whether +// int is 32 or 64 bits. See also +// http://www.imperialviolet.org/2012/03/16/rsae.html. +func checkPub(pub *PublicKey) error { +	if pub.N == nil { +		return errPublicModulus +	} +	if pub.E < 2 { +		return errPublicExponentSmall +	} +	if pub.E > 1<<31-1 { +		return errPublicExponentLarge +	} +	return nil +} +  // A PrivateKey represents an RSA key  type PrivateKey struct {  	PublicKey            // public part. @@ -37,7 +61,7 @@ type PrivateKey struct {  }  type PrecomputedValues struct { -	Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)  +	Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)  	Qinv   *big.Int // Q^-1 mod Q  	// CRTValues is used for the 3rd and subsequent primes. Due to a @@ -57,13 +81,17 @@ type CRTValue struct {  // Validate performs basic sanity checks on the key.  // It returns nil if the key is valid, or else an error describing a problem.  func (priv *PrivateKey) Validate() error { +	if err := checkPub(&priv.PublicKey); err != nil { +		return err +	} +  	// Check that the prime factors are actually prime. Note that this is  	// just a sanity check. Since the random witnesses chosen by  	// ProbablyPrime are deterministic, given the candidate number, it's  	// easy for an attack to generate composites that pass this test.  	for _, prime := range priv.Primes {  		if !prime.ProbablyPrime(20) { -			return errors.New("prime factor is composite") +			return errors.New("crypto/rsa: prime factor is composite")  		}  	} @@ -73,27 +101,23 @@ func (priv *PrivateKey) Validate() error {  		modulus.Mul(modulus, prime)  	}  	if modulus.Cmp(priv.N) != 0 { -		return errors.New("invalid modulus") +		return errors.New("crypto/rsa: invalid modulus")  	} -	// Check that e and totient(Πprimes) are coprime. -	totient := new(big.Int).Set(bigOne) + +	// Check that de ≡ 1 mod p-1, for each prime. +	// This implies that e is coprime to each p-1 as e has a multiplicative +	// inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) = +	// exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1 +	// mod p. Thus a^de ≡ a mod n for all a coprime to n, as required. +	congruence := new(big.Int) +	de := new(big.Int).SetInt64(int64(priv.E)) +	de.Mul(de, priv.D)  	for _, prime := range priv.Primes {  		pminus1 := new(big.Int).Sub(prime, bigOne) -		totient.Mul(totient, pminus1) -	} -	e := big.NewInt(int64(priv.E)) -	gcd := new(big.Int) -	x := new(big.Int) -	y := new(big.Int) -	gcd.GCD(x, y, totient, e) -	if gcd.Cmp(bigOne) != 0 { -		return errors.New("invalid public exponent E") -	} -	// Check that de ≡ 1 (mod totient(Πprimes)) -	de := new(big.Int).Mul(priv.D, e) -	de.Mod(de, totient) -	if de.Cmp(bigOne) != 0 { -		return errors.New("invalid private exponent D") +		congruence.Mod(de, pminus1) +		if congruence.Cmp(bigOne) != 0 { +			return errors.New("crypto/rsa: invalid exponents") +		}  	}  	return nil  } @@ -118,7 +142,7 @@ func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (priv *Priva  	priv.E = 65537  	if nprimes < 2 { -		return nil, errors.New("rsa.GenerateMultiPrimeKey: nprimes must be >= 2") +		return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2")  	}  	primes := make([]*big.Int, nprimes) @@ -126,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 { @@ -151,6 +189,12 @@ NextSetOfPrimes:  			pminus1.Sub(prime, bigOne)  			totient.Mul(totient, pminus1)  		} +		if n.BitLen() != bits { +			// 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 +		}  		g := new(big.Int)  		priv.D = new(big.Int) @@ -220,6 +264,9 @@ func encrypt(c *big.Int, pub *PublicKey, m *big.Int) *big.Int {  // The message must be no longer than the length of the public modulus less  // twice the hash length plus 2.  func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) (out []byte, err error) { +	if err := checkPub(pub); err != nil { +		return nil, err +	}  	hash.Reset()  	k := (pub.N.BitLen() + 7) / 8  	if len(msg) > k-2*hash.Size()-2 { @@ -406,6 +453,9 @@ func decrypt(random io.Reader, priv *PrivateKey, c *big.Int) (m *big.Int, err er  // DecryptOAEP decrypts ciphertext using RSA-OAEP.  // If random != nil, DecryptOAEP uses RSA blinding to avoid timing side-channel attacks.  func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) (msg []byte, err error) { +	if err := checkPub(&priv.PublicKey); err != nil { +		return nil, err +	}  	k := (priv.N.BitLen() + 7) / 8  	if len(ciphertext) > k ||  		k < hash.Size()*2+2 { diff --git a/src/pkg/crypto/rsa/rsa_test.go b/src/pkg/crypto/rsa/rsa_test.go index 0fb9875d0..f08cfe73c 100644 --- a/src/pkg/crypto/rsa/rsa_test.go +++ b/src/pkg/crypto/rsa/rsa_test.go @@ -21,15 +21,18 @@ func TestKeyGeneration(t *testing.T) {  	if err != nil {  		t.Errorf("failed to generate key")  	} +	if bits := priv.N.BitLen(); bits != size { +		t.Errorf("key too short (%d vs %d)", bits, size) +	}  	testKeyBasics(t, priv)  }  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") @@ -38,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") @@ -50,6 +53,42 @@ 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 +	// the group. +	priv := &PrivateKey{ +		PublicKey: PublicKey{ +			N: fromBase10("290684273230919398108010081414538931343"), +			E: 65537, +		}, +		D: fromBase10("31877380284581499213530787347443987241"), +		Primes: []*big.Int{ +			fromBase10("16775196964030542637"), +			fromBase10("17328218193455850539"), +		}, +	} +	testKeyBasics(t, priv) +} +  func testKeyBasics(t *testing.T, priv *PrivateKey) {  	if err := priv.Validate(); err != nil {  		t.Errorf("Validate() failed: %s", err) @@ -98,7 +137,7 @@ func BenchmarkRSA2048Decrypt(b *testing.B) {  	}  	priv.Precompute() -	c := fromBase10("1000") +	c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313")  	b.StartTimer() @@ -123,7 +162,7 @@ func Benchmark3PrimeRSA2048Decrypt(b *testing.B) {  	}  	priv.Precompute() -	c := fromBase10("1000") +	c := fromBase10("8472002792838218989464636159316973636630013835787202418124758118372358261975764365740026024610403138425986214991379012696600761514742817632790916315594342398720903716529235119816755589383377471752116975374952783629225022962092351886861518911824745188989071172097120352727368980275252089141512321893536744324822590480751098257559766328893767334861211872318961900897793874075248286439689249972315699410830094164386544311554704755110361048571142336148077772023880664786019636334369759624917224888206329520528064315309519262325023881707530002540634660750469137117568199824615333883758410040459705787022909848740188613313")  	b.StartTimer() @@ -158,7 +197,7 @@ func TestEncryptOAEP(t *testing.T) {  			if err != nil {  				t.Errorf("#%d,%d error: %s", i, j, err)  			} -			if bytes.Compare(out, message.out) != 0 { +			if !bytes.Equal(out, message.out) {  				t.Errorf("#%d,%d bad result: %x (want %x)", i, j, out, message.out)  			}  		} @@ -182,7 +221,7 @@ func TestDecryptOAEP(t *testing.T) {  			out, err := DecryptOAEP(sha1, nil, private, message.out, nil)  			if err != nil {  				t.Errorf("#%d,%d error: %s", i, j, err) -			} else if bytes.Compare(out, message.in) != 0 { +			} else if !bytes.Equal(out, message.in) {  				t.Errorf("#%d,%d bad result: %#v (want %#v)", i, j, out, message.in)  			} @@ -190,7 +229,7 @@ func TestDecryptOAEP(t *testing.T) {  			out, err = DecryptOAEP(sha1, random, private, message.out, nil)  			if err != nil {  				t.Errorf("#%d,%d (blind) error: %s", i, j, err) -			} else if bytes.Compare(out, message.in) != 0 { +			} else if !bytes.Equal(out, message.in) {  				t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in)  			}  		} diff --git a/src/pkg/crypto/sha1/sha1.go b/src/pkg/crypto/sha1/sha1.go index 876e7992a..7cfde47dc 100644 --- a/src/pkg/crypto/sha1/sha1.go +++ b/src/pkg/crypto/sha1/sha1.go @@ -21,28 +21,28 @@ const Size = 20  const BlockSize = 64  const ( -	_Chunk = 64 -	_Init0 = 0x67452301 -	_Init1 = 0xEFCDAB89 -	_Init2 = 0x98BADCFE -	_Init3 = 0x10325476 -	_Init4 = 0xC3D2E1F0 +	chunk = 64 +	init0 = 0x67452301 +	init1 = 0xEFCDAB89 +	init2 = 0x98BADCFE +	init3 = 0x10325476 +	init4 = 0xC3D2E1F0  )  // digest represents the partial evaluation of a checksum.  type digest struct {  	h   [5]uint32 -	x   [_Chunk]byte +	x   [chunk]byte  	nx  int  	len uint64  }  func (d *digest) Reset() { -	d.h[0] = _Init0 -	d.h[1] = _Init1 -	d.h[2] = _Init2 -	d.h[3] = _Init3 -	d.h[4] = _Init4 +	d.h[0] = init0 +	d.h[1] = init1 +	d.h[2] = init2 +	d.h[3] = init3 +	d.h[4] = init4  	d.nx = 0  	d.len = 0  } @@ -63,21 +63,24 @@ func (d *digest) Write(p []byte) (nn int, err error) {  	d.len += uint64(nn)  	if d.nx > 0 {  		n := len(p) -		if n > _Chunk-d.nx { -			n = _Chunk - d.nx +		if n > chunk-d.nx { +			n = chunk - d.nx  		}  		for i := 0; i < n; i++ {  			d.x[d.nx+i] = p[i]  		}  		d.nx += n -		if d.nx == _Chunk { -			_Block(d, d.x[0:]) +		if d.nx == chunk { +			block(d, d.x[0:])  			d.nx = 0  		}  		p = p[n:]  	} -	n := _Block(d, p) -	p = p[n:] +	if len(p) >= chunk { +		n := len(p) &^ (chunk - 1) +		block(d, p[:n]) +		p = p[n:] +	}  	if len(p) > 0 {  		d.nx = copy(d.x[:], p)  	} diff --git a/src/pkg/crypto/sha1/sha1_test.go b/src/pkg/crypto/sha1/sha1_test.go index 2dc14ac98..57cd4313e 100644 --- a/src/pkg/crypto/sha1/sha1_test.go +++ b/src/pkg/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,8 +73,33 @@ 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 = New() +var buf = make([]byte, 8192) + +func benchmarkSize(b *testing.B, size int) { +	b.SetBytes(int64(size)) +	sum := make([]byte, bench.Size()) +	for i := 0; i < b.N; i++ { +		bench.Reset() +		bench.Write(buf[:size]) +		bench.Sum(sum[:0]) +	} +} + +func BenchmarkHash8Bytes(b *testing.B) { +	benchmarkSize(b, 8) +} + +func BenchmarkHash1K(b *testing.B) { +	benchmarkSize(b, 1024) +} + +func BenchmarkHash8K(b *testing.B) { +	benchmarkSize(b, 8192) +} diff --git a/src/pkg/crypto/sha1/sha1block.go b/src/pkg/crypto/sha1/sha1block.go index b5d32af70..1c9507c68 100644 --- a/src/pkg/crypto/sha1/sha1block.go +++ b/src/pkg/crypto/sha1/sha1block.go @@ -15,54 +15,67 @@ const (  	_K3 = 0xCA62C1D6  ) -func _Block(dig *digest, p []byte) int { -	var w [80]uint32 +func block(dig *digest, p []byte) { +	var w [16]uint32 -	n := 0  	h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] -	for len(p) >= _Chunk { +	for len(p) >= chunk {  		// Can interlace the computation of w with the  		// rounds below if needed for speed.  		for i := 0; i < 16; i++ {  			j := i * 4  			w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])  		} -		for i := 16; i < 80; i++ { -			tmp := w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16] -			w[i] = tmp<<1 | tmp>>(32-1) -		}  		a, b, c, d, e := h0, h1, h2, h3, h4  		// Each of the four 20-iteration rounds  		// differs only in the computation of f and  		// the choice of K (_K0, _K1, etc). -		for i := 0; i < 20; i++ { +		i := 0 +		for ; i < 16; i++ { +			f := b&c | (^b)&d +			a5 := a<<5 | a>>(32-5) +			b30 := b<<30 | b>>(32-30) +			t := a5 + f + e + w[i&0xf] + _K0 +			a, b, c, d, e = t, a, b30, c, d +		} +		for ; i < 20; i++ { +			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] +			w[i&0xf] = tmp<<1 | tmp>>(32-1) +  			f := b&c | (^b)&d  			a5 := a<<5 | a>>(32-5)  			b30 := b<<30 | b>>(32-30) -			t := a5 + f + e + w[i] + _K0 +			t := a5 + f + e + w[i&0xf] + _K0  			a, b, c, d, e = t, a, b30, c, d  		} -		for i := 20; i < 40; i++ { +		for ; i < 40; i++ { +			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] +			w[i&0xf] = tmp<<1 | tmp>>(32-1)  			f := b ^ c ^ d  			a5 := a<<5 | a>>(32-5)  			b30 := b<<30 | b>>(32-30) -			t := a5 + f + e + w[i] + _K1 +			t := a5 + f + e + w[i&0xf] + _K1  			a, b, c, d, e = t, a, b30, c, d  		} -		for i := 40; i < 60; i++ { -			f := b&c | b&d | c&d +		for ; i < 60; i++ { +			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] +			w[i&0xf] = tmp<<1 | tmp>>(32-1) +			f := ((b | c) & d) | (b & c) +  			a5 := a<<5 | a>>(32-5)  			b30 := b<<30 | b>>(32-30) -			t := a5 + f + e + w[i] + _K2 +			t := a5 + f + e + w[i&0xf] + _K2  			a, b, c, d, e = t, a, b30, c, d  		} -		for i := 60; i < 80; i++ { +		for ; i < 80; i++ { +			tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf] +			w[i&0xf] = tmp<<1 | tmp>>(32-1)  			f := b ^ c ^ d  			a5 := a<<5 | a>>(32-5)  			b30 := b<<30 | b>>(32-30) -			t := a5 + f + e + w[i] + _K3 +			t := a5 + f + e + w[i&0xf] + _K3  			a, b, c, d, e = t, a, b30, c, d  		} @@ -72,10 +85,8 @@ func _Block(dig *digest, p []byte) int {  		h3 += d  		h4 += e -		p = p[_Chunk:] -		n += _Chunk +		p = p[chunk:]  	}  	dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4 -	return n  } diff --git a/src/pkg/crypto/sha256/sha256.go b/src/pkg/crypto/sha256/sha256.go index a61e30b42..dc0e18f50 100644 --- a/src/pkg/crypto/sha256/sha256.go +++ b/src/pkg/crypto/sha256/sha256.go @@ -26,29 +26,29 @@ const Size224 = 28  const BlockSize = 64  const ( -	_Chunk     = 64 -	_Init0     = 0x6A09E667 -	_Init1     = 0xBB67AE85 -	_Init2     = 0x3C6EF372 -	_Init3     = 0xA54FF53A -	_Init4     = 0x510E527F -	_Init5     = 0x9B05688C -	_Init6     = 0x1F83D9AB -	_Init7     = 0x5BE0CD19 -	_Init0_224 = 0xC1059ED8 -	_Init1_224 = 0x367CD507 -	_Init2_224 = 0x3070DD17 -	_Init3_224 = 0xF70E5939 -	_Init4_224 = 0xFFC00B31 -	_Init5_224 = 0x68581511 -	_Init6_224 = 0x64F98FA7 -	_Init7_224 = 0xBEFA4FA4 +	chunk     = 64 +	init0     = 0x6A09E667 +	init1     = 0xBB67AE85 +	init2     = 0x3C6EF372 +	init3     = 0xA54FF53A +	init4     = 0x510E527F +	init5     = 0x9B05688C +	init6     = 0x1F83D9AB +	init7     = 0x5BE0CD19 +	init0_224 = 0xC1059ED8 +	init1_224 = 0x367CD507 +	init2_224 = 0x3070DD17 +	init3_224 = 0xF70E5939 +	init4_224 = 0xFFC00B31 +	init5_224 = 0x68581511 +	init6_224 = 0x64F98FA7 +	init7_224 = 0xBEFA4FA4  )  // digest represents the partial evaluation of a checksum.  type digest struct {  	h     [8]uint32 -	x     [_Chunk]byte +	x     [chunk]byte  	nx    int  	len   uint64  	is224 bool // mark if this digest is SHA-224 @@ -56,23 +56,23 @@ type digest struct {  func (d *digest) Reset() {  	if !d.is224 { -		d.h[0] = _Init0 -		d.h[1] = _Init1 -		d.h[2] = _Init2 -		d.h[3] = _Init3 -		d.h[4] = _Init4 -		d.h[5] = _Init5 -		d.h[6] = _Init6 -		d.h[7] = _Init7 +		d.h[0] = init0 +		d.h[1] = init1 +		d.h[2] = init2 +		d.h[3] = init3 +		d.h[4] = init4 +		d.h[5] = init5 +		d.h[6] = init6 +		d.h[7] = init7  	} else { -		d.h[0] = _Init0_224 -		d.h[1] = _Init1_224 -		d.h[2] = _Init2_224 -		d.h[3] = _Init3_224 -		d.h[4] = _Init4_224 -		d.h[5] = _Init5_224 -		d.h[6] = _Init6_224 -		d.h[7] = _Init7_224 +		d.h[0] = init0_224 +		d.h[1] = init1_224 +		d.h[2] = init2_224 +		d.h[3] = init3_224 +		d.h[4] = init4_224 +		d.h[5] = init5_224 +		d.h[6] = init6_224 +		d.h[7] = init7_224  	}  	d.nx = 0  	d.len = 0 @@ -107,21 +107,24 @@ func (d *digest) Write(p []byte) (nn int, err error) {  	d.len += uint64(nn)  	if d.nx > 0 {  		n := len(p) -		if n > _Chunk-d.nx { -			n = _Chunk - d.nx +		if n > chunk-d.nx { +			n = chunk - d.nx  		}  		for i := 0; i < n; i++ {  			d.x[d.nx+i] = p[i]  		}  		d.nx += n -		if d.nx == _Chunk { -			_Block(d, d.x[0:]) +		if d.nx == chunk { +			block(d, d.x[0:])  			d.nx = 0  		}  		p = p[n:]  	} -	n := _Block(d, p) -	p = p[n:] +	if len(p) >= chunk { +		n := len(p) &^ (chunk - 1) +		block(d, p[:n]) +		p = p[n:] +	}  	if len(p) > 0 {  		d.nx = copy(d.x[:], p)  	} diff --git a/src/pkg/crypto/sha256/sha256_test.go b/src/pkg/crypto/sha256/sha256_test.go index a6efb3754..29bf1619a 100644 --- a/src/pkg/crypto/sha256/sha256_test.go +++ b/src/pkg/crypto/sha256/sha256_test.go @@ -123,3 +123,28 @@ func TestGolden(t *testing.T) {  		}  	}  } + +var bench = New() +var buf = make([]byte, 8192) + +func benchmarkSize(b *testing.B, size int) { +	b.SetBytes(int64(size)) +	sum := make([]byte, bench.Size()) +	for i := 0; i < b.N; i++ { +		bench.Reset() +		bench.Write(buf[:size]) +		bench.Sum(sum[:0]) +	} +} + +func BenchmarkHash8Bytes(b *testing.B) { +	benchmarkSize(b, 8) +} + +func BenchmarkHash1K(b *testing.B) { +	benchmarkSize(b, 1024) +} + +func BenchmarkHash8K(b *testing.B) { +	benchmarkSize(b, 8192) +} diff --git a/src/pkg/crypto/sha256/sha256block.go b/src/pkg/crypto/sha256/sha256block.go index 7b0f55444..2ac49100a 100644 --- a/src/pkg/crypto/sha256/sha256block.go +++ b/src/pkg/crypto/sha256/sha256block.go @@ -75,11 +75,10 @@ var _K = []uint32{  	0xc67178f2,  } -func _Block(dig *digest, p []byte) int { +func block(dig *digest, p []byte) {  	var w [64]uint32 -	n := 0  	h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] -	for len(p) >= _Chunk { +	for len(p) >= chunk {  		// Can interlace the computation of w with the  		// rounds below if needed for speed.  		for i := 0; i < 16; i++ { @@ -87,10 +86,10 @@ func _Block(dig *digest, p []byte) int {  			w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])  		}  		for i := 16; i < 64; i++ { -			t1 := (w[i-2]>>17 | w[i-2]<<(32-17)) ^ (w[i-2]>>19 | w[i-2]<<(32-19)) ^ (w[i-2] >> 10) - -			t2 := (w[i-15]>>7 | w[i-15]<<(32-7)) ^ (w[i-15]>>18 | w[i-15]<<(32-18)) ^ (w[i-15] >> 3) - +			v1 := w[i-2] +			t1 := (v1>>17 | v1<<(32-17)) ^ (v1>>19 | v1<<(32-19)) ^ (v1 >> 10) +			v2 := w[i-15] +			t2 := (v2>>7 | v2<<(32-7)) ^ (v2>>18 | v2<<(32-18)) ^ (v2 >> 3)  			w[i] = t1 + w[i-7] + t2 + w[i-16]  		} @@ -120,10 +119,8 @@ func _Block(dig *digest, p []byte) int {  		h6 += g  		h7 += h -		p = p[_Chunk:] -		n += _Chunk +		p = p[chunk:]  	}  	dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 -	return n  } diff --git a/src/pkg/crypto/sha512/sha512.go b/src/pkg/crypto/sha512/sha512.go index a245fd68e..4aec52938 100644 --- a/src/pkg/crypto/sha512/sha512.go +++ b/src/pkg/crypto/sha512/sha512.go @@ -26,29 +26,29 @@ const Size384 = 48  const BlockSize = 128  const ( -	_Chunk     = 128 -	_Init0     = 0x6a09e667f3bcc908 -	_Init1     = 0xbb67ae8584caa73b -	_Init2     = 0x3c6ef372fe94f82b -	_Init3     = 0xa54ff53a5f1d36f1 -	_Init4     = 0x510e527fade682d1 -	_Init5     = 0x9b05688c2b3e6c1f -	_Init6     = 0x1f83d9abfb41bd6b -	_Init7     = 0x5be0cd19137e2179 -	_Init0_384 = 0xcbbb9d5dc1059ed8 -	_Init1_384 = 0x629a292a367cd507 -	_Init2_384 = 0x9159015a3070dd17 -	_Init3_384 = 0x152fecd8f70e5939 -	_Init4_384 = 0x67332667ffc00b31 -	_Init5_384 = 0x8eb44a8768581511 -	_Init6_384 = 0xdb0c2e0d64f98fa7 -	_Init7_384 = 0x47b5481dbefa4fa4 +	chunk     = 128 +	init0     = 0x6a09e667f3bcc908 +	init1     = 0xbb67ae8584caa73b +	init2     = 0x3c6ef372fe94f82b +	init3     = 0xa54ff53a5f1d36f1 +	init4     = 0x510e527fade682d1 +	init5     = 0x9b05688c2b3e6c1f +	init6     = 0x1f83d9abfb41bd6b +	init7     = 0x5be0cd19137e2179 +	init0_384 = 0xcbbb9d5dc1059ed8 +	init1_384 = 0x629a292a367cd507 +	init2_384 = 0x9159015a3070dd17 +	init3_384 = 0x152fecd8f70e5939 +	init4_384 = 0x67332667ffc00b31 +	init5_384 = 0x8eb44a8768581511 +	init6_384 = 0xdb0c2e0d64f98fa7 +	init7_384 = 0x47b5481dbefa4fa4  )  // digest represents the partial evaluation of a checksum.  type digest struct {  	h     [8]uint64 -	x     [_Chunk]byte +	x     [chunk]byte  	nx    int  	len   uint64  	is384 bool // mark if this digest is SHA-384 @@ -56,23 +56,23 @@ type digest struct {  func (d *digest) Reset() {  	if !d.is384 { -		d.h[0] = _Init0 -		d.h[1] = _Init1 -		d.h[2] = _Init2 -		d.h[3] = _Init3 -		d.h[4] = _Init4 -		d.h[5] = _Init5 -		d.h[6] = _Init6 -		d.h[7] = _Init7 +		d.h[0] = init0 +		d.h[1] = init1 +		d.h[2] = init2 +		d.h[3] = init3 +		d.h[4] = init4 +		d.h[5] = init5 +		d.h[6] = init6 +		d.h[7] = init7  	} else { -		d.h[0] = _Init0_384 -		d.h[1] = _Init1_384 -		d.h[2] = _Init2_384 -		d.h[3] = _Init3_384 -		d.h[4] = _Init4_384 -		d.h[5] = _Init5_384 -		d.h[6] = _Init6_384 -		d.h[7] = _Init7_384 +		d.h[0] = init0_384 +		d.h[1] = init1_384 +		d.h[2] = init2_384 +		d.h[3] = init3_384 +		d.h[4] = init4_384 +		d.h[5] = init5_384 +		d.h[6] = init6_384 +		d.h[7] = init7_384  	}  	d.nx = 0  	d.len = 0 @@ -107,21 +107,24 @@ func (d *digest) Write(p []byte) (nn int, err error) {  	d.len += uint64(nn)  	if d.nx > 0 {  		n := len(p) -		if n > _Chunk-d.nx { -			n = _Chunk - d.nx +		if n > chunk-d.nx { +			n = chunk - d.nx  		}  		for i := 0; i < n; i++ {  			d.x[d.nx+i] = p[i]  		}  		d.nx += n -		if d.nx == _Chunk { -			_Block(d, d.x[0:]) +		if d.nx == chunk { +			block(d, d.x[0:])  			d.nx = 0  		}  		p = p[n:]  	} -	n := _Block(d, p) -	p = p[n:] +	if len(p) >= chunk { +		n := len(p) &^ (chunk - 1) +		block(d, p[:n]) +		p = p[n:] +	}  	if len(p) > 0 {  		d.nx = copy(d.x[:], p)  	} diff --git a/src/pkg/crypto/sha512/sha512_test.go b/src/pkg/crypto/sha512/sha512_test.go index a70f7c54e..6eafb1b5f 100644 --- a/src/pkg/crypto/sha512/sha512_test.go +++ b/src/pkg/crypto/sha512/sha512_test.go @@ -123,3 +123,28 @@ func TestGolden(t *testing.T) {  		}  	}  } + +var bench = New() +var buf = make([]byte, 8192) + +func benchmarkSize(b *testing.B, size int) { +	b.SetBytes(int64(size)) +	sum := make([]byte, bench.Size()) +	for i := 0; i < b.N; i++ { +		bench.Reset() +		bench.Write(buf[:size]) +		bench.Sum(sum[:0]) +	} +} + +func BenchmarkHash8Bytes(b *testing.B) { +	benchmarkSize(b, 8) +} + +func BenchmarkHash1K(b *testing.B) { +	benchmarkSize(b, 1024) +} + +func BenchmarkHash8K(b *testing.B) { +	benchmarkSize(b, 8192) +} diff --git a/src/pkg/crypto/sha512/sha512block.go b/src/pkg/crypto/sha512/sha512block.go index 6b7506287..3577b4f3d 100644 --- a/src/pkg/crypto/sha512/sha512block.go +++ b/src/pkg/crypto/sha512/sha512block.go @@ -91,20 +91,20 @@ var _K = []uint64{  	0x6c44198c4a475817,  } -func _Block(dig *digest, p []byte) int { +func block(dig *digest, p []byte) {  	var w [80]uint64 -	n := 0  	h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] -	for len(p) >= _Chunk { +	for len(p) >= chunk {  		for i := 0; i < 16; i++ {  			j := i * 8  			w[i] = uint64(p[j])<<56 | uint64(p[j+1])<<48 | uint64(p[j+2])<<40 | uint64(p[j+3])<<32 |  				uint64(p[j+4])<<24 | uint64(p[j+5])<<16 | uint64(p[j+6])<<8 | uint64(p[j+7])  		}  		for i := 16; i < 80; i++ { -			t1 := (w[i-2]>>19 | w[i-2]<<(64-19)) ^ (w[i-2]>>61 | w[i-2]<<(64-61)) ^ (w[i-2] >> 6) - -			t2 := (w[i-15]>>1 | w[i-15]<<(64-1)) ^ (w[i-15]>>8 | w[i-15]<<(64-8)) ^ (w[i-15] >> 7) +			v1 := w[i-2] +			t1 := (v1>>19 | v1<<(64-19)) ^ (v1>>61 | v1<<(64-61)) ^ (v1 >> 6) +			v2 := w[i-15] +			t2 := (v2>>1 | v2<<(64-1)) ^ (v2>>8 | v2<<(64-8)) ^ (v2 >> 7)  			w[i] = t1 + w[i-7] + t2 + w[i-16]  		} @@ -135,10 +135,8 @@ func _Block(dig *digest, p []byte) int {  		h6 += g  		h7 += h -		p = p[_Chunk:] -		n += _Chunk +		p = p[chunk:]  	}  	dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7 -	return n  } diff --git a/src/pkg/crypto/tls/cipher_suites.go b/src/pkg/crypto/tls/cipher_suites.go index 5039f319f..a647e19aa 100644 --- a/src/pkg/crypto/tls/cipher_suites.go +++ b/src/pkg/crypto/tls/cipher_suites.go @@ -55,9 +55,11 @@ var cipherSuites = []*cipherSuite{  	{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, false, cipherRC4, macSHA1},  	{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, false, cipher3DES, macSHA1},  	{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, false, cipherAES, macSHA1}, +	{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, false, cipherAES, macSHA1},  	{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1},  	{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, true, cipher3DES, macSHA1},  	{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1}, +	{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},  }  func cipherRC4(key, iv []byte, isRead bool) interface{} { @@ -182,7 +184,9 @@ const (  	TLS_RSA_WITH_RC4_128_SHA            uint16 = 0x0005  	TLS_RSA_WITH_3DES_EDE_CBC_SHA       uint16 = 0x000a  	TLS_RSA_WITH_AES_128_CBC_SHA        uint16 = 0x002f +	TLS_RSA_WITH_AES_256_CBC_SHA        uint16 = 0x0035  	TLS_ECDHE_RSA_WITH_RC4_128_SHA      uint16 = 0xc011  	TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012  	TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA  uint16 = 0xc013 +	TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA  uint16 = 0xc014  ) diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go index 4ba0bf874..a888df762 100644 --- a/src/pkg/crypto/tls/common.go +++ b/src/pkg/crypto/tls/common.go @@ -41,6 +41,7 @@ const (  const (  	typeClientHello        uint8 = 1  	typeServerHello        uint8 = 2 +	typeNewSessionTicket   uint8 = 4  	typeCertificate        uint8 = 11  	typeServerKeyExchange  uint8 = 12  	typeCertificateRequest uint8 = 13 @@ -63,6 +64,7 @@ var (  	extensionStatusRequest   uint16 = 5  	extensionSupportedCurves uint16 = 10  	extensionSupportedPoints uint16 = 11 +	extensionSessionTicket   uint16 = 35  	extensionNextProtoNeg    uint16 = 13172 // not IANA assigned  ) @@ -97,6 +99,7 @@ const (  // ConnectionState records basic TLS details about the connection.  type ConnectionState struct {  	HandshakeComplete          bool +	DidResume                  bool  	CipherSuite                uint16  	NegotiatedProtocol         string  	NegotiatedProtocolIsMutual bool @@ -180,6 +183,28 @@ type Config struct {  	// CipherSuites is a list of supported cipher suites. If CipherSuites  	// is nil, TLS uses a list of suites supported by the implementation.  	CipherSuites []uint16 + +	// PreferServerCipherSuites controls whether the server selects the +	// client's most preferred ciphersuite, or the server's most preferred +	// ciphersuite. If true then the server's preference, as expressed in +	// the order of elements in CipherSuites, is used. +	PreferServerCipherSuites bool + +	// SessionTicketsDisabled may be set to true to disable session ticket +	// (resumption) support. +	SessionTicketsDisabled bool + +	// SessionTicketKey is used by TLS servers to provide session +	// resumption. See RFC 5077. If zero, it will be filled with +	// random data before the first server handshake. +	// +	// If multiple servers are terminating connections for the same host +	// they should all have the same SessionTicketKey. If the +	// SessionTicketKey leaks, previously recorded and future TLS +	// connections using that key are compromised. +	SessionTicketKey [32]byte + +	serverInitOnce sync.Once  }  func (c *Config) rand() io.Reader { diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go index 2a5115dc6..d8c2be00a 100644 --- a/src/pkg/crypto/tls/conn.go +++ b/src/pkg/crypto/tls/conn.go @@ -31,6 +31,7 @@ type Conn struct {  	haveVers          bool       // version has been negotiated  	config            *Config    // configuration passed to constructor  	handshakeComplete bool +	didResume         bool // whether this connection was a session resumption  	cipherSuite       uint16  	ocspResponse      []byte // stapled OCSP response  	peerCertificates  []*x509.Certificate @@ -44,8 +45,7 @@ type Conn struct {  	clientProtocolFallback bool  	// first permanent error -	errMutex sync.Mutex -	err      error +	connErr  	// input/output  	in, out  halfConn     // in.Mutex < out.Mutex @@ -56,21 +56,25 @@ type Conn struct {  	tmp [16]byte  } -func (c *Conn) setError(err error) error { -	c.errMutex.Lock() -	defer c.errMutex.Unlock() +type connErr struct { +	mu    sync.Mutex +	value error +} + +func (e *connErr) setError(err error) error { +	e.mu.Lock() +	defer e.mu.Unlock() -	if c.err == nil { -		c.err = err +	if e.value == nil { +		e.value = err  	}  	return err  } -func (c *Conn) error() error { -	c.errMutex.Lock() -	defer c.errMutex.Unlock() - -	return c.err +func (e *connErr) error() error { +	e.mu.Lock() +	defer e.mu.Unlock() +	return e.value  }  // Access to net.Conn methods. @@ -487,6 +491,16 @@ Again:  		return err  	}  	typ := recordType(b.data[0]) + +	// No valid TLS record has a type of 0x80, however SSLv2 handshakes +	// start with a uint16 length where the MSB is set and the first record +	// is always < 256 bytes long. Therefore typ == 0x80 strongly suggests +	// an SSLv2 client. +	if want == recordTypeHandshake && typ == 0x80 { +		c.sendAlert(alertProtocolVersion) +		return errors.New("tls: unsupported SSLv2 handshake received") +	} +  	vers := uint16(b.data[1])<<8 | uint16(b.data[2])  	n := int(b.data[3])<<8 | int(b.data[4])  	if c.haveVers && vers != c.vers { @@ -499,7 +513,7 @@ Again:  		// First message, be extra suspicious:  		// this might not be a TLS client.  		// Bail out before reading a full 'body', if possible. -		// The current max version is 3.1.  +		// The current max version is 3.1.  		// If the version is >= 16.0, it's probably not real.  		// Similarly, a clientHello message encodes in  		// well under a kilobyte.  If the length is >= 12 kB, @@ -590,9 +604,11 @@ Again:  // sendAlert sends a TLS alert message.  // c.out.Mutex <= L.  func (c *Conn) sendAlertLocked(err alert) error { -	c.tmp[0] = alertLevelError -	if err == alertNoRenegotiation { +	switch err { +	case alertNoRenegotiation, alertCloseNotify:  		c.tmp[0] = alertLevelWarning +	default: +		c.tmp[0] = alertLevelError  	}  	c.tmp[1] = byte(err)  	c.writeRecord(recordTypeAlert, c.tmp[0:2]) @@ -650,8 +666,7 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {  			c.tmp[0] = alertLevelError  			c.tmp[1] = byte(err.(alert))  			c.writeRecord(recordTypeAlert, c.tmp[0:2]) -			c.err = &net.OpError{Op: "local error", Err: err} -			return n, c.err +			return n, c.setError(&net.OpError{Op: "local error", Err: err})  		}  	}  	return @@ -662,8 +677,8 @@ func (c *Conn) writeRecord(typ recordType, data []byte) (n int, err error) {  // c.in.Mutex < L; c.out.Mutex < L.  func (c *Conn) readHandshake() (interface{}, error) {  	for c.hand.Len() < 4 { -		if c.err != nil { -			return nil, c.err +		if err := c.error(); err != nil { +			return nil, err  		}  		if err := c.readRecord(recordTypeHandshake); err != nil {  			return nil, err @@ -674,11 +689,11 @@ func (c *Conn) readHandshake() (interface{}, error) {  	n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])  	if n > maxHandshake {  		c.sendAlert(alertInternalError) -		return nil, c.err +		return nil, c.error()  	}  	for c.hand.Len() < 4+n { -		if c.err != nil { -			return nil, c.err +		if err := c.error(); err != nil { +			return nil, err  		}  		if err := c.readRecord(recordTypeHandshake); err != nil {  			return nil, err @@ -728,12 +743,12 @@ func (c *Conn) readHandshake() (interface{}, error) {  // Write writes data to the connection.  func (c *Conn) Write(b []byte) (int, error) { -	if c.err != nil { -		return 0, c.err +	if err := c.error(); err != nil { +		return 0, err  	} -	if c.err = c.Handshake(); c.err != nil { -		return 0, c.err +	if err := c.Handshake(); err != nil { +		return 0, c.setError(err)  	}  	c.out.Lock() @@ -743,9 +758,28 @@ func (c *Conn) Write(b []byte) (int, error) {  		return 0, alertInternalError  	} -	var n int -	n, c.err = c.writeRecord(recordTypeApplicationData, b) -	return n, c.err +	// SSL 3.0 and TLS 1.0 are susceptible to a chosen-plaintext +	// attack when using block mode ciphers due to predictable IVs. +	// This can be prevented by splitting each Application Data +	// record into two records, effectively randomizing the IV. +	// +	// http://www.openssl.org/~bodo/tls-cbc.txt +	// https://bugzilla.mozilla.org/show_bug.cgi?id=665814 +	// http://www.imperialviolet.org/2012/01/15/beastfollowup.html + +	var m int +	if len(b) > 1 && c.vers <= versionTLS10 { +		if _, ok := c.out.cipher.(cipher.BlockMode); ok { +			n, err := c.writeRecord(recordTypeApplicationData, b[:1]) +			if err != nil { +				return n, c.setError(err) +			} +			m, b = 1, b[1:] +		} +	} + +	n, err := c.writeRecord(recordTypeApplicationData, b) +	return n + m, c.setError(err)  }  // Read can be made to time out and return a net.Error with Timeout() == true @@ -758,14 +792,14 @@ func (c *Conn) Read(b []byte) (n int, err error) {  	c.in.Lock()  	defer c.in.Unlock() -	for c.input == nil && c.err == nil { +	for c.input == nil && c.error() == nil {  		if err := c.readRecord(recordTypeApplicationData); err != nil {  			// Soft error, like EAGAIN  			return 0, err  		}  	} -	if c.err != nil { -		return 0, c.err +	if err := c.error(); err != nil { +		return 0, err  	}  	n, err = c.input.Read(b)  	if c.input.off >= len(c.input.data) { @@ -819,6 +853,7 @@ func (c *Conn) ConnectionState() ConnectionState {  	state.HandshakeComplete = c.handshakeComplete  	if c.handshakeComplete {  		state.NegotiatedProtocol = c.clientProtocol +		state.DidResume = c.didResume  		state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback  		state.CipherSuite = c.cipherSuite  		state.PeerCertificates = c.peerCertificates diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go index 84be5bfd8..215644d24 100644 --- a/src/pkg/crypto/tls/generate_cert.go +++ b/src/pkg/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/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go index 2877f1738..7db13bf70 100644 --- a/src/pkg/crypto/tls/handshake_client.go +++ b/src/pkg/crypto/tls/handshake_client.go @@ -278,8 +278,9 @@ func (c *Conn) clientHandshake() error {  		c.writeRecord(recordTypeHandshake, certVerify.marshal())  	} -	masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := -		keysFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen) +	masterSecret := masterFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random) +	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := +		keysFromMasterSecret(c.vers, masterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)  	clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */)  	clientHash := suite.mac(c.vers, clientMAC) @@ -306,8 +307,8 @@ func (c *Conn) clientHandshake() error {  	serverHash := suite.mac(c.vers, serverMAC)  	c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)  	c.readRecord(recordTypeChangeCipherSpec) -	if c.err != nil { -		return c.err +	if err := c.error(); err != nil { +		return err  	}  	msg, err = c.readHandshake() diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go index 8c56daaf6..9673947a4 100644 --- a/src/pkg/crypto/tls/handshake_client_test.go +++ b/src/pkg/crypto/tls/handshake_client_test.go @@ -9,6 +9,7 @@ import (  	"flag"  	"io"  	"net" +	"os"  	"testing"  ) @@ -39,7 +40,15 @@ func testClientScript(t *testing.T, name string, clientScript [][]byte, config *  }  func TestHandshakeClientRC4(t *testing.T) { -	testClientScript(t, "RC4", rc4ClientScript, testConfig) +	var config = *testConfig +	config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA} +	testClientScript(t, "RC4", rc4ClientScript, &config) +} + +func TestHandshakeClientECDHEAES(t *testing.T) { +	var config = *testConfig +	config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA} +	testClientScript(t, "ECDHE-AES", ecdheAESClientScript, &config)  }  var connect = flag.Bool("connect", false, "connect to a TLS server on :10443") @@ -49,25 +58,33 @@ func TestRunClient(t *testing.T) {  		return  	} -	testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} - -	conn, err := Dial("tcp", "127.0.0.1:10443", testConfig) +	tcpConn, err := net.Dial("tcp", "127.0.0.1:10443")  	if err != nil {  		t.Fatal(err)  	} +	record := &recordingConn{ +		Conn: tcpConn, +	} + +	config := GetTestConfig() +	conn := Client(record, config) +	if err := conn.Handshake(); err != nil { +		t.Fatalf("error from TLS handshake: %s", err) +	} +  	conn.Write([]byte("hello\n"))  	conn.Close() + +	record.WriteTo(os.Stdout)  }  // Script of interaction with gnutls implementation.  // The values for this test are obtained by building and running in client mode: -//   % go test -run "TestRunClient" -connect -// and then: -//   % gnutls-serv -p 10443 --debug 100 --x509keyfile key.pem --x509certfile cert.pem -a > /tmp/log 2>&1 -//   % python parse-gnutls-cli-debug-log.py < /tmp/log +//   % go test -test.run "TestRunClient" -connect +// The recorded bytes are written to stdout.  // -// Where key.pem is: +// The server private key is:  // -----BEGIN RSA PRIVATE KEY-----  // MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD  // TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu @@ -78,17 +95,20 @@ func TestRunClient(t *testing.T) {  // vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU=  // -----END RSA PRIVATE KEY-----  // -// and cert.pem is: +// and certificate is:  // -----BEGIN CERTIFICATE----- -// MIIBoDCCAUoCAQAwDQYJKoZIhvcNAQEEBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV -// BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD -// VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw05NzA5MDkwMzQxMjZa -// Fw05NzEwMDkwMzQxMjZaMF4xCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 -// YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFzAVBgNVBAMT -// DkVyaWMgdGhlIFlvdW5nMFEwCQYFKw4DAgwFAANEAAJBALVEqPODnpI4rShlY8S7 -// tB713JNvabvn6Gned7zylwLLiXQAo/PAT6mfdWPTyCX9RlId/Aroh1ou893BA32Q -// sggwDQYJKoZIhvcNAQEEBQADQQCU5SSgapJSdRXJoX+CpCvFy+JVh9HpSjCpSNKO -// 19raHv98hKAUJuP9HyM+SUsffO6mAIgitUaqW8/wDMePhEC3 +// MIICKzCCAdWgAwIBAgIJALE1E2URIMWSMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +// BAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBX +// aWRnaXRzIFB0eSBMdGQwHhcNMTIwNDA2MTcxMDEzWhcNMTUwNDA2MTcxMDEzWjBF +// MQswCQYDVQQGEwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50 +// ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJ+z +// w4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVDTGiXav6ooKXfX3j/ +// 7tdkuD8Ey2//Kv7+ue0CAwEAAaOBpzCBpDAdBgNVHQ4EFgQUeKaXmmO1xaGlM7oi +// fCNuWxt6zCswdQYDVR0jBG4wbIAUeKaXmmO1xaGlM7oifCNuWxt6zCuhSaRHMEUx +// CzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRl +// cm5ldCBXaWRnaXRzIFB0eSBMdGSCCQCxNRNlESDFkjAMBgNVHRMEBTADAQH/MA0G +// CSqGSIb3DQEBBQUAA0EAhTZAc8G7GtrUWZ8tonAxRnTsg26oyDxRrzms7EC86CJG +// HZnWRiok1IsFCEv7NRFukrt3uuQSu/TIXpyBqJdgTA==  // -----END CERTIFICATE-----  var rc4ClientScript = [][]byte{  	{ @@ -210,3 +230,179 @@ var rc4ClientScript = [][]byte{  		0x59, 0xac, 0xc6, 0xb5, 0x56, 0x55, 0x96,  	},  } + +var ecdheAESClientScript = [][]byte{ +	{ +		0x16, 0x03, 0x01, 0x00, 0x4a, 0x01, 0x00, 0x00, +		0x46, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xc0, 0x13, +		0x01, 0x00, 0x00, 0x1b, 0x00, 0x05, 0x00, 0x05, +		0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, +		0x08, 0x00, 0x06, 0x00, 0x17, 0x00, 0x18, 0x00, +		0x19, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, +	}, +	{ +		0x16, 0x03, 0x01, 0x00, 0x52, 0x02, 0x00, 0x00, +		0x4e, 0x03, 0x01, 0x50, 0xad, 0x72, 0xb1, 0x14, +		0x45, 0xce, 0x0a, 0x95, 0xf9, 0x63, 0xef, 0xa8, +		0xe5, 0x07, 0x34, 0x04, 0xe9, 0x08, 0x0f, 0x38, +		0xe4, 0x28, 0x27, 0x91, 0x07, 0x03, 0xe2, 0xfe, +		0xe3, 0x25, 0xf7, 0x20, 0x08, 0x42, 0xa2, 0x01, +		0x69, 0x53, 0xf0, 0xd9, 0x4c, 0xfa, 0x01, 0xa1, +		0xce, 0x4b, 0xf8, 0x28, 0x21, 0xad, 0x06, 0xbe, +		0xe0, 0x1b, 0x3b, 0xf7, 0xec, 0xd2, 0x52, 0xae, +		0x2a, 0x57, 0xb7, 0xa8, 0xc0, 0x13, 0x00, 0x00, +		0x06, 0x00, 0x0b, 0x00, 0x02, 0x01, 0x00, 0x16, +		0x03, 0x01, 0x02, 0x39, 0x0b, 0x00, 0x02, 0x35, +		0x00, 0x02, 0x32, 0x00, 0x02, 0x2f, 0x30, 0x82, +		0x02, 0x2b, 0x30, 0x82, 0x01, 0xd5, 0xa0, 0x03, +		0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0xb1, 0x35, +		0x13, 0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0d, +		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, +		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, +		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, +		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, +		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, +		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, +		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, +		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, +		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, +		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, +		0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, +		0x31, 0x32, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37, +		0x31, 0x30, 0x31, 0x33, 0x5a, 0x17, 0x0d, 0x31, +		0x35, 0x30, 0x34, 0x30, 0x36, 0x31, 0x37, 0x31, +		0x30, 0x31, 0x33, 0x5a, 0x30, 0x45, 0x31, 0x0b, +		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, +		0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, +		0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, +		0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, +		0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, +		0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, +		0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, +		0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, +		0x4c, 0x74, 0x64, 0x30, 0x5c, 0x30, 0x0d, 0x06, +		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, +		0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, +		0x48, 0x02, 0x41, 0x00, 0x9f, 0xb3, 0xc3, 0x84, +		0x27, 0x95, 0xff, 0x12, 0x31, 0x52, 0x0f, 0x15, +		0xef, 0x46, 0x11, 0xc4, 0xad, 0x80, 0xe6, 0x36, +		0x5b, 0x0f, 0xdd, 0x80, 0xd7, 0x61, 0x8d, 0xe0, +		0xfc, 0x72, 0x45, 0x09, 0x34, 0xfe, 0x55, 0x66, +		0x45, 0x43, 0x4c, 0x68, 0x97, 0x6a, 0xfe, 0xa8, +		0xa0, 0xa5, 0xdf, 0x5f, 0x78, 0xff, 0xee, 0xd7, +		0x64, 0xb8, 0x3f, 0x04, 0xcb, 0x6f, 0xff, 0x2a, +		0xfe, 0xfe, 0xb9, 0xed, 0x02, 0x03, 0x01, 0x00, +		0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, 0xa4, 0x30, +		0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, +		0x04, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63, 0xb5, +		0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c, 0x23, +		0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0x30, 0x75, +		0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x6e, 0x30, +		0x6c, 0x80, 0x14, 0x78, 0xa6, 0x97, 0x9a, 0x63, +		0xb5, 0xc5, 0xa1, 0xa5, 0x33, 0xba, 0x22, 0x7c, +		0x23, 0x6e, 0x5b, 0x1b, 0x7a, 0xcc, 0x2b, 0xa1, +		0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, 0x0b, 0x30, +		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, +		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, +		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, +		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, +		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, +		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, +		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, +		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, +		0x74, 0x64, 0x82, 0x09, 0x00, 0xb1, 0x35, 0x13, +		0x65, 0x11, 0x20, 0xc5, 0x92, 0x30, 0x0c, 0x06, +		0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, 0x30, 0x03, +		0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, 0x09, 0x2a, +		0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, +		0x05, 0x00, 0x03, 0x41, 0x00, 0x85, 0x36, 0x40, +		0x73, 0xc1, 0xbb, 0x1a, 0xda, 0xd4, 0x59, 0x9f, +		0x2d, 0xa2, 0x70, 0x31, 0x46, 0x74, 0xec, 0x83, +		0x6e, 0xa8, 0xc8, 0x3c, 0x51, 0xaf, 0x39, 0xac, +		0xec, 0x40, 0xbc, 0xe8, 0x22, 0x46, 0x1d, 0x99, +		0xd6, 0x46, 0x2a, 0x24, 0xd4, 0x8b, 0x05, 0x08, +		0x4b, 0xfb, 0x35, 0x11, 0x6e, 0x92, 0xbb, 0x77, +		0xba, 0xe4, 0x12, 0xbb, 0xf4, 0xc8, 0x5e, 0x9c, +		0x81, 0xa8, 0x97, 0x60, 0x4c, 0x16, 0x03, 0x01, +		0x00, 0x8b, 0x0c, 0x00, 0x00, 0x87, 0x03, 0x00, +		0x17, 0x41, 0x04, 0x1c, 0x8f, 0x9c, 0x6d, 0xe7, +		0xab, 0x3e, 0xf8, 0x0a, 0x5d, 0xe1, 0x86, 0xb4, +		0xe2, 0x8e, 0xb2, 0x1c, 0x3b, 0xd9, 0xb6, 0x08, +		0x80, 0x58, 0x21, 0xe9, 0x0e, 0xc6, 0x66, 0x67, +		0x97, 0xcb, 0xb9, 0x92, 0x07, 0x00, 0xc4, 0xe5, +		0xec, 0x5f, 0xb4, 0xe2, 0x20, 0xa9, 0xc9, 0x62, +		0xd0, 0x98, 0xd5, 0xe3, 0x53, 0xff, 0xd0, 0x0a, +		0x6e, 0x29, 0x69, 0x39, 0x2a, 0x4b, 0x5c, 0xd8, +		0x6c, 0xf5, 0xfe, 0x00, 0x40, 0x35, 0xa7, 0x26, +		0x2e, 0xc2, 0x48, 0x93, 0x32, 0xf7, 0x7d, 0x0f, +		0x0d, 0x77, 0x56, 0x9a, 0x85, 0x0c, 0xa6, 0x74, +		0x06, 0xb8, 0x3d, 0x90, 0x56, 0x12, 0x63, 0xff, +		0x00, 0x5e, 0x0f, 0xf7, 0x24, 0xf7, 0xdb, 0x48, +		0x71, 0xe9, 0x2e, 0x03, 0xd3, 0xfa, 0x3a, 0xae, +		0xa0, 0xc1, 0x77, 0x3c, 0x4c, 0x59, 0xce, 0x33, +		0x1a, 0xd2, 0x47, 0x83, 0xfa, 0xea, 0xd8, 0x1e, +		0x06, 0xe7, 0x7d, 0xa0, 0x9b, 0x16, 0x03, 0x01, +		0x00, 0x04, 0x0e, 0x00, 0x00, 0x00, +	}, +	{ +		0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00, +		0x42, 0x41, 0x04, 0x1e, 0x18, 0x37, 0xef, 0x0d, +		0x19, 0x51, 0x88, 0x35, 0x75, 0x71, 0xb5, 0xe5, +		0x54, 0x5b, 0x12, 0x2e, 0x8f, 0x09, 0x67, 0xfd, +		0xa7, 0x24, 0x20, 0x3e, 0xb2, 0x56, 0x1c, 0xce, +		0x97, 0x28, 0x5e, 0xf8, 0x2b, 0x2d, 0x4f, 0x9e, +		0xf1, 0x07, 0x9f, 0x6c, 0x4b, 0x5b, 0x83, 0x56, +		0xe2, 0x32, 0x42, 0xe9, 0x58, 0xb6, 0xd7, 0x49, +		0xa6, 0xb5, 0x68, 0x1a, 0x41, 0x03, 0x56, 0x6b, +		0xdc, 0x5a, 0x89, 0x14, 0x03, 0x01, 0x00, 0x01, +		0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0xd9, 0xa7, +		0x80, 0x56, 0x3f, 0xa3, 0x8f, 0x96, 0x72, 0x4e, +		0x4e, 0x6e, 0x23, 0x41, 0x8f, 0xda, 0x91, 0xb2, +		0x9e, 0x63, 0x23, 0x82, 0x64, 0xcd, 0x07, 0x24, +		0xd3, 0x40, 0x20, 0x22, 0x4c, 0xe3, 0xff, 0x38, +		0xbb, 0x43, 0x9d, 0x57, 0x11, 0xd5, 0x46, 0xa5, +		0x05, 0x29, 0x92, 0x02, 0xce, 0xdf, +	}, +	{ +		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, +		0x01, 0x00, 0x90, 0xe7, 0xba, 0x0e, 0xb1, 0xda, +		0x92, 0xb5, 0x77, 0x56, 0x38, 0xa6, 0x22, 0xc1, +		0x72, 0xeb, 0x8a, 0x68, 0x09, 0xb6, 0x74, 0xad, +		0xb3, 0x4a, 0xf2, 0xdd, 0x09, 0x9b, 0xc9, 0x4f, +		0x84, 0x73, 0x8b, 0xd6, 0x97, 0x50, 0x23, 0x1c, +		0xa0, 0xc2, 0x0c, 0x25, 0x18, 0xdd, 0x5e, 0x15, +		0x4d, 0xd9, 0xef, 0x4f, 0x6a, 0x43, 0x61, 0x9c, +		0x95, 0xde, 0x3c, 0x66, 0xc4, 0xc1, 0x33, 0x56, +		0xdd, 0x2f, 0x90, 0xaf, 0x68, 0x5c, 0x9c, 0xa4, +		0x90, 0x6d, 0xbf, 0x51, 0x1d, 0x68, 0xcb, 0x81, +		0x77, 0x52, 0xa0, 0x93, 0x2a, 0xf8, 0xc7, 0x61, +		0x87, 0x76, 0xca, 0x93, 0x9e, 0xd6, 0xee, 0x6f, +		0x3f, 0xeb, 0x7d, 0x06, 0xdd, 0x73, 0x4e, 0x27, +		0x16, 0x63, 0x92, 0xe4, 0xb2, 0x3f, 0x91, 0x23, +		0x21, 0x97, 0x90, 0xce, 0x53, 0xb8, 0xb0, 0x9d, +		0xbd, 0xbd, 0x33, 0x84, 0xad, 0x6b, 0x2e, 0x7b, +		0xf5, 0xeb, 0x1d, 0x64, 0x37, 0x2e, 0x29, 0x4e, +		0xb0, 0x93, 0xdb, 0x92, 0xc7, 0xaa, 0x94, 0xa5, +		0x3b, 0x64, 0xd0, +	}, +	{ +		0x17, 0x03, 0x01, 0x00, 0x20, 0x11, 0xd8, 0x6b, +		0x3c, 0xf6, 0xbe, 0xf4, 0x54, 0x87, 0xec, 0x75, +		0x0c, 0x44, 0xdb, 0x92, 0xfc, 0xde, 0x7e, 0x0f, +		0x9f, 0x87, 0x87, 0x9c, 0x03, 0xd5, 0x07, 0x84, +		0xe0, 0x3a, 0xf8, 0xae, 0x14, 0x17, 0x03, 0x01, +		0x00, 0x20, 0xba, 0x54, 0xef, 0x5b, 0xce, 0xfd, +		0x47, 0x76, 0x6d, 0xa1, 0x8b, 0xfd, 0x48, 0xde, +		0x6e, 0x26, 0xc1, 0x0c, 0x9d, 0x54, 0xbf, 0x98, +		0xf6, 0x1c, 0x80, 0xb9, 0xca, 0x93, 0x81, 0x0a, +		0x2e, 0x06, 0x15, 0x03, 0x01, 0x00, 0x20, 0x93, +		0x3e, 0x38, 0x17, 0xc9, 0x0a, 0xc3, 0xea, 0xd3, +		0x92, 0x75, 0xa6, 0x53, 0x37, 0x4d, 0x74, 0x94, +		0xbe, 0x01, 0xdc, 0x5c, 0x5a, 0x0f, 0x09, 0xf6, +		0x57, 0x33, 0xc3, 0xbc, 0x3f, 0x7a, 0x4d, +	}, +} diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go index 54c7a3e63..cdd491707 100644 --- a/src/pkg/crypto/tls/handshake_messages.go +++ b/src/pkg/crypto/tls/handshake_messages.go @@ -18,6 +18,8 @@ type clientHelloMsg struct {  	ocspStapling       bool  	supportedCurves    []uint16  	supportedPoints    []uint8 +	ticketSupported    bool +	sessionTicket      []uint8  }  func (m *clientHelloMsg) equal(i interface{}) bool { @@ -36,7 +38,9 @@ func (m *clientHelloMsg) equal(i interface{}) bool {  		m.serverName == m1.serverName &&  		m.ocspStapling == m1.ocspStapling &&  		eqUint16s(m.supportedCurves, m1.supportedCurves) && -		bytes.Equal(m.supportedPoints, m1.supportedPoints) +		bytes.Equal(m.supportedPoints, m1.supportedPoints) && +		m.ticketSupported == m1.ticketSupported && +		bytes.Equal(m.sessionTicket, m1.sessionTicket)  }  func (m *clientHelloMsg) marshal() []byte { @@ -66,6 +70,10 @@ func (m *clientHelloMsg) marshal() []byte {  		extensionsLength += 1 + len(m.supportedPoints)  		numExtensions++  	} +	if m.ticketSupported { +		extensionsLength += len(m.sessionTicket) +		numExtensions++ +	}  	if numExtensions > 0 {  		extensionsLength += 4 * numExtensions  		length += 2 + extensionsLength @@ -180,6 +188,17 @@ func (m *clientHelloMsg) marshal() []byte {  			z = z[1:]  		}  	} +	if m.ticketSupported { +		// http://tools.ietf.org/html/rfc5077#section-3.2 +		z[0] = byte(extensionSessionTicket >> 8) +		z[1] = byte(extensionSessionTicket) +		l := len(m.sessionTicket) +		z[2] = byte(l >> 8) +		z[3] = byte(l) +		z = z[4:] +		copy(z, m.sessionTicket) +		z = z[len(m.sessionTicket):] +	}  	m.raw = x @@ -228,6 +247,8 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {  	m.nextProtoNeg = false  	m.serverName = ""  	m.ocspStapling = false +	m.ticketSupported = false +	m.sessionTicket = nil  	if len(data) == 0 {  		// ClientHello is optionally followed by extension data @@ -311,6 +332,10 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {  			}  			m.supportedPoints = make([]uint8, l)  			copy(m.supportedPoints, data[1:]) +		case extensionSessionTicket: +			// http://tools.ietf.org/html/rfc5077#section-3.2 +			m.ticketSupported = true +			m.sessionTicket = data[:length]  		}  		data = data[length:]  	} @@ -328,6 +353,7 @@ type serverHelloMsg struct {  	nextProtoNeg      bool  	nextProtos        []string  	ocspStapling      bool +	ticketSupported   bool  }  func (m *serverHelloMsg) equal(i interface{}) bool { @@ -344,7 +370,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {  		m.compressionMethod == m1.compressionMethod &&  		m.nextProtoNeg == m1.nextProtoNeg &&  		eqStrings(m.nextProtos, m1.nextProtos) && -		m.ocspStapling == m1.ocspStapling +		m.ocspStapling == m1.ocspStapling && +		m.ticketSupported == m1.ticketSupported  }  func (m *serverHelloMsg) marshal() []byte { @@ -368,6 +395,9 @@ func (m *serverHelloMsg) marshal() []byte {  	if m.ocspStapling {  		numExtensions++  	} +	if m.ticketSupported { +		numExtensions++ +	}  	if numExtensions > 0 {  		extensionsLength += 4 * numExtensions  		length += 2 + extensionsLength @@ -416,6 +446,11 @@ func (m *serverHelloMsg) marshal() []byte {  		z[1] = byte(extensionStatusRequest)  		z = z[4:]  	} +	if m.ticketSupported { +		z[0] = byte(extensionSessionTicket >> 8) +		z[1] = byte(extensionSessionTicket) +		z = z[4:] +	}  	m.raw = x @@ -445,6 +480,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {  	m.nextProtoNeg = false  	m.nextProtos = nil  	m.ocspStapling = false +	m.ticketSupported = false  	if len(data) == 0 {  		// ServerHello is optionally followed by extension data @@ -474,14 +510,14 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {  		switch extension {  		case extensionNextProtoNeg:  			m.nextProtoNeg = true -			d := data +			d := data[:length]  			for len(d) > 0 {  				l := int(d[0])  				d = d[1:]  				if l == 0 || l > len(d) {  					return false  				} -				m.nextProtos = append(m.nextProtos, string(d[0:l])) +				m.nextProtos = append(m.nextProtos, string(d[:l]))  				d = d[l:]  			}  		case extensionStatusRequest: @@ -489,6 +525,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {  				return false  			}  			m.ocspStapling = true +		case extensionSessionTicket: +			if length > 0 { +				return false +			} +			m.ticketSupported = true  		}  		data = data[length:]  	} @@ -1030,6 +1071,65 @@ func (m *certificateVerifyMsg) unmarshal(data []byte) bool {  	return true  } +type newSessionTicketMsg struct { +	raw    []byte +	ticket []byte +} + +func (m *newSessionTicketMsg) equal(i interface{}) bool { +	m1, ok := i.(*newSessionTicketMsg) +	if !ok { +		return false +	} + +	return bytes.Equal(m.raw, m1.raw) && +		bytes.Equal(m.ticket, m1.ticket) +} + +func (m *newSessionTicketMsg) marshal() (x []byte) { +	if m.raw != nil { +		return m.raw +	} + +	// See http://tools.ietf.org/html/rfc5077#section-3.3 +	ticketLen := len(m.ticket) +	length := 2 + 4 + ticketLen +	x = make([]byte, 4+length) +	x[0] = typeNewSessionTicket +	x[1] = uint8(length >> 16) +	x[2] = uint8(length >> 8) +	x[3] = uint8(length) +	x[8] = uint8(ticketLen >> 8) +	x[9] = uint8(ticketLen) +	copy(x[10:], m.ticket) + +	m.raw = x + +	return +} + +func (m *newSessionTicketMsg) unmarshal(data []byte) bool { +	m.raw = data + +	if len(data) < 10 { +		return false +	} + +	length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) +	if uint32(len(data))-4 != length { +		return false +	} + +	ticketLen := int(data[8])<<8 + int(data[9]) +	if len(data)-10 != ticketLen { +		return false +	} + +	m.ticket = data[10:] + +	return true +} +  func eqUint16s(x, y []uint16) bool {  	if len(x) != len(y) {  		return false diff --git a/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go index e62a9d581..3434bad9f 100644 --- a/src/pkg/crypto/tls/handshake_messages_test.go +++ b/src/pkg/crypto/tls/handshake_messages_test.go @@ -22,6 +22,8 @@ var tests = []interface{}{  	&certificateStatusMsg{},  	&clientKeyExchangeMsg{},  	&nextProtoMsg{}, +	&newSessionTicketMsg{}, +	&sessionState{},  }  type testMessage interface { @@ -127,6 +129,12 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {  	for i := range m.supportedCurves {  		m.supportedCurves[i] = uint16(rand.Intn(30000))  	} +	if rand.Intn(10) > 5 { +		m.ticketSupported = true +		if rand.Intn(10) > 5 { +			m.sessionTicket = randomBytes(rand.Intn(300), rand) +		} +	}  	return reflect.ValueOf(m)  } @@ -149,6 +157,13 @@ func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {  		}  	} +	if rand.Intn(10) > 5 { +		m.ocspStapling = true +	} +	if rand.Intn(10) > 5 { +		m.ticketSupported = true +	} +  	return reflect.ValueOf(m)  } @@ -207,3 +222,22 @@ func (*nextProtoMsg) Generate(rand *rand.Rand, size int) reflect.Value {  	m.proto = randomString(rand.Intn(255), rand)  	return reflect.ValueOf(m)  } + +func (*newSessionTicketMsg) Generate(rand *rand.Rand, size int) reflect.Value { +	m := &newSessionTicketMsg{} +	m.ticket = randomBytes(rand.Intn(4), rand) +	return reflect.ValueOf(m) +} + +func (*sessionState) Generate(rand *rand.Rand, size int) reflect.Value { +	s := &sessionState{} +	s.vers = uint16(rand.Intn(10000)) +	s.cipherSuite = uint16(rand.Intn(10000)) +	s.masterSecret = randomBytes(rand.Intn(100), rand) +	numCerts := rand.Intn(20) +	s.certificates = make([][]byte, numCerts) +	for i := 0; i < numCerts; i++ { +		s.certificates[i] = randomBytes(rand.Intn(10)+1, rand) +	} +	return reflect.ValueOf(s) +} diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go index 76adc540c..730991016 100644 --- a/src/pkg/crypto/tls/handshake_server.go +++ b/src/pkg/crypto/tls/handshake_server.go @@ -13,31 +13,120 @@ import (  	"io"  ) +// serverHandshakeState contains details of a server handshake in progress. +// It's discarded once the handshake has completed. +type serverHandshakeState struct { +	c               *Conn +	clientHello     *clientHelloMsg +	hello           *serverHelloMsg +	suite           *cipherSuite +	ellipticOk      bool +	sessionState    *sessionState +	finishedHash    finishedHash +	masterSecret    []byte +	certsFromClient [][]byte +} + +// serverHandshake performs a TLS handshake as a server.  func (c *Conn) serverHandshake() error {  	config := c.config -	msg, err := c.readHandshake() + +	// 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 +		} +	}) + +	hs := serverHandshakeState{ +		c: c, +	} +	isResume, err := hs.readClientHello()  	if err != nil {  		return err  	} -	clientHello, ok := msg.(*clientHelloMsg) + +	// For an overview of TLS handshaking, see https://tools.ietf.org/html/rfc5246#section-7.3 +	if isResume { +		// The client has included a session ticket and so we do an abbreviated handshake. +		if err := hs.doResumeHandshake(); err != nil { +			return err +		} +		if err := hs.establishKeys(); err != nil { +			return err +		} +		if err := hs.sendFinished(); err != nil { +			return err +		} +		if err := hs.readFinished(); err != nil { +			return err +		} +		c.didResume = true +	} else { +		// The client didn't include a session ticket, or it wasn't +		// valid so we do a full handshake. +		if err := hs.doFullHandshake(); err != nil { +			return err +		} +		if err := hs.establishKeys(); err != nil { +			return err +		} +		if err := hs.readFinished(); err != nil { +			return err +		} +		if err := hs.sendSessionTicket(); err != nil { +			return err +		} +		if err := hs.sendFinished(); err != nil { +			return err +		} +	} +	c.handshakeComplete = true + +	return nil +} + +// readClientHello reads a ClientHello message from the client and decides +// whether we will perform session resumption. +func (hs *serverHandshakeState) readClientHello() (isResume bool, err error) { +	config := hs.c.config +	c := hs.c + +	msg, err := c.readHandshake() +	if err != nil { +		return false, err +	} +	var ok bool +	hs.clientHello, ok = msg.(*clientHelloMsg)  	if !ok { -		return c.sendAlert(alertUnexpectedMessage) +		return false, c.sendAlert(alertUnexpectedMessage)  	} -	vers, ok := mutualVersion(clientHello.vers) +	c.vers, ok = mutualVersion(hs.clientHello.vers)  	if !ok { -		return c.sendAlert(alertProtocolVersion) +		return false, c.sendAlert(alertProtocolVersion)  	} -	c.vers = vers  	c.haveVers = true -	finishedHash := newFinishedHash(vers) -	finishedHash.Write(clientHello.marshal()) +	hs.finishedHash = newFinishedHash(c.vers) +	hs.finishedHash.Write(hs.clientHello.marshal()) -	hello := new(serverHelloMsg) +	hs.hello = new(serverHelloMsg)  	supportedCurve := false  Curves: -	for _, curve := range clientHello.supportedCurves { +	for _, curve := range hs.clientHello.supportedCurves {  		switch curve {  		case curveP256, curveP384, curveP521:  			supportedCurve = true @@ -46,110 +135,182 @@ Curves:  	}  	supportedPointFormat := false -	for _, pointFormat := range clientHello.supportedPoints { +	for _, pointFormat := range hs.clientHello.supportedPoints {  		if pointFormat == pointFormatUncompressed {  			supportedPointFormat = true  			break  		}  	} - -	ellipticOk := supportedCurve && supportedPointFormat - -	var suite *cipherSuite -FindCipherSuite: -	for _, id := range clientHello.cipherSuites { -		for _, supported := range config.cipherSuites() { -			if id == supported { -				var candidate *cipherSuite - -				for _, s := range cipherSuites { -					if s.id == id { -						candidate = s -						break -					} -				} -				if candidate == nil { -					continue -				} -				// Don't select a ciphersuite which we can't -				// support for this client. -				if candidate.elliptic && !ellipticOk { -					continue -				} -				suite = candidate -				break FindCipherSuite -			} -		} -	} +	hs.ellipticOk = supportedCurve && supportedPointFormat  	foundCompression := false  	// We only support null compression, so check that the client offered it. -	for _, compression := range clientHello.compressionMethods { +	for _, compression := range hs.clientHello.compressionMethods {  		if compression == compressionNone {  			foundCompression = true  			break  		}  	} -	if suite == nil || !foundCompression { -		return c.sendAlert(alertHandshakeFailure) +	if !foundCompression { +		return false, c.sendAlert(alertHandshakeFailure)  	} -	hello.vers = vers -	hello.cipherSuite = suite.id +	hs.hello.vers = c.vers  	t := uint32(config.time().Unix()) -	hello.random = make([]byte, 32) -	hello.random[0] = byte(t >> 24) -	hello.random[1] = byte(t >> 16) -	hello.random[2] = byte(t >> 8) -	hello.random[3] = byte(t) -	_, err = io.ReadFull(config.rand(), hello.random[4:]) +	hs.hello.random = make([]byte, 32) +	hs.hello.random[0] = byte(t >> 24) +	hs.hello.random[1] = byte(t >> 16) +	hs.hello.random[2] = byte(t >> 8) +	hs.hello.random[3] = byte(t) +	_, err = io.ReadFull(config.rand(), hs.hello.random[4:])  	if err != nil { -		return c.sendAlert(alertInternalError) +		return false, c.sendAlert(alertInternalError) +	} +	hs.hello.compressionMethod = compressionNone +	if len(hs.clientHello.serverName) > 0 { +		c.serverName = hs.clientHello.serverName +	} +	if hs.clientHello.nextProtoNeg { +		hs.hello.nextProtoNeg = true +		hs.hello.nextProtos = config.NextProtos +	} + +	if hs.checkForResumption() { +		return true, nil +	} + +	var preferenceList, supportedList []uint16 +	if c.config.PreferServerCipherSuites { +		preferenceList = c.config.cipherSuites() +		supportedList = hs.clientHello.cipherSuites +	} else { +		preferenceList = hs.clientHello.cipherSuites +		supportedList = c.config.cipherSuites() +	} + +	for _, id := range preferenceList { +		if hs.suite = c.tryCipherSuite(id, supportedList, hs.ellipticOk); hs.suite != nil { +			break +		} +	} + +	if hs.suite == nil { +		return false, c.sendAlert(alertHandshakeFailure) +	} + +	return false, nil +} + +// checkForResumption returns true if we should perform resumption on this connection. +func (hs *serverHandshakeState) checkForResumption() bool { +	c := hs.c + +	var ok bool +	if hs.sessionState, ok = c.decryptTicket(hs.clientHello.sessionTicket); !ok { +		return false  	} -	hello.compressionMethod = compressionNone -	if clientHello.nextProtoNeg { -		hello.nextProtoNeg = true -		hello.nextProtos = config.NextProtos + +	if hs.sessionState.vers > hs.clientHello.vers { +		return false +	} +	if vers, ok := mutualVersion(hs.sessionState.vers); !ok || vers != hs.sessionState.vers { +		return false +	} + +	cipherSuiteOk := false +	// Check that the client is still offering the ciphersuite in the session. +	for _, id := range hs.clientHello.cipherSuites { +		if id == hs.sessionState.cipherSuite { +			cipherSuiteOk = true +			break +		} +	} +	if !cipherSuiteOk { +		return false +	} + +	// Check that we also support the ciphersuite from the session. +	hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, c.config.cipherSuites(), hs.ellipticOk) +	if hs.suite == nil { +		return false +	} + +	sessionHasClientCerts := len(hs.sessionState.certificates) != 0 +	needClientCerts := c.config.ClientAuth == RequireAnyClientCert || c.config.ClientAuth == RequireAndVerifyClientCert +	if needClientCerts && !sessionHasClientCerts { +		return false +	} +	if sessionHasClientCerts && c.config.ClientAuth == NoClientCert { +		return false  	} +	return true +} + +func (hs *serverHandshakeState) doResumeHandshake() error { +	c := hs.c + +	hs.hello.cipherSuite = hs.suite.id +	// We echo the client's session ID in the ServerHello to let it know +	// that we're doing a resumption. +	hs.hello.sessionId = hs.clientHello.sessionId +	hs.finishedHash.Write(hs.hello.marshal()) +	c.writeRecord(recordTypeHandshake, hs.hello.marshal()) + +	if len(hs.sessionState.certificates) > 0 { +		if _, err := hs.processCertsFromClient(hs.sessionState.certificates); err != nil { +			return err +		} +	} + +	hs.masterSecret = hs.sessionState.masterSecret + +	return nil +} + +func (hs *serverHandshakeState) doFullHandshake() error { +	config := hs.c.config +	c := hs.c +  	if len(config.Certificates) == 0 {  		return c.sendAlert(alertInternalError)  	}  	cert := &config.Certificates[0] -	if len(clientHello.serverName) > 0 { -		c.serverName = clientHello.serverName -		cert = config.getCertificateForName(clientHello.serverName) +	if len(hs.clientHello.serverName) > 0 { +		cert = config.getCertificateForName(hs.clientHello.serverName)  	} -	if clientHello.ocspStapling && len(cert.OCSPStaple) > 0 { -		hello.ocspStapling = true +	if hs.clientHello.ocspStapling && len(cert.OCSPStaple) > 0 { +		hs.hello.ocspStapling = true  	} -	finishedHash.Write(hello.marshal()) -	c.writeRecord(recordTypeHandshake, hello.marshal()) +	hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled +	hs.hello.cipherSuite = hs.suite.id +	hs.finishedHash.Write(hs.hello.marshal()) +	c.writeRecord(recordTypeHandshake, hs.hello.marshal())  	certMsg := new(certificateMsg)  	certMsg.certificates = cert.Certificate -	finishedHash.Write(certMsg.marshal()) +	hs.finishedHash.Write(certMsg.marshal())  	c.writeRecord(recordTypeHandshake, certMsg.marshal()) -	if hello.ocspStapling { +	if hs.hello.ocspStapling {  		certStatus := new(certificateStatusMsg)  		certStatus.statusType = statusTypeOCSP  		certStatus.response = cert.OCSPStaple -		finishedHash.Write(certStatus.marshal()) +		hs.finishedHash.Write(certStatus.marshal())  		c.writeRecord(recordTypeHandshake, certStatus.marshal())  	} -	keyAgreement := suite.ka() -	skx, err := keyAgreement.generateServerKeyExchange(config, cert, clientHello, hello) +	keyAgreement := hs.suite.ka() +	skx, err := keyAgreement.generateServerKeyExchange(config, cert, hs.clientHello, hs.hello)  	if err != nil {  		c.sendAlert(alertHandshakeFailure)  		return err  	}  	if skx != nil { -		finishedHash.Write(skx.marshal()) +		hs.finishedHash.Write(skx.marshal())  		c.writeRecord(recordTypeHandshake, skx.marshal())  	} @@ -166,28 +327,29 @@ FindCipherSuite:  		if config.ClientCAs != nil {  			certReq.certificateAuthorities = config.ClientCAs.Subjects()  		} -		finishedHash.Write(certReq.marshal()) +		hs.finishedHash.Write(certReq.marshal())  		c.writeRecord(recordTypeHandshake, certReq.marshal())  	}  	helloDone := new(serverHelloDoneMsg) -	finishedHash.Write(helloDone.marshal()) +	hs.finishedHash.Write(helloDone.marshal())  	c.writeRecord(recordTypeHandshake, helloDone.marshal())  	var pub *rsa.PublicKey // public key for client auth, if any -	msg, err = c.readHandshake() +	msg, err := c.readHandshake()  	if err != nil {  		return err  	} +	var ok bool  	// If we requested a client certificate, then the client must send a  	// certificate message, even if it's empty.  	if config.ClientAuth >= RequestClientCert {  		if certMsg, ok = msg.(*certificateMsg); !ok {  			return c.sendAlert(alertHandshakeFailure)  		} -		finishedHash.Write(certMsg.marshal()) +		hs.finishedHash.Write(certMsg.marshal())  		if len(certMsg.certificates) == 0 {  			// The client didn't actually send a certificate @@ -198,54 +360,9 @@ FindCipherSuite:  			}  		} -		certs := make([]*x509.Certificate, len(certMsg.certificates)) -		for i, asn1Data := range certMsg.certificates { -			if certs[i], err = x509.ParseCertificate(asn1Data); err != nil { -				c.sendAlert(alertBadCertificate) -				return errors.New("tls: failed to parse client certificate: " + err.Error()) -			} -		} - -		if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 { -			opts := x509.VerifyOptions{ -				Roots:         c.config.ClientCAs, -				CurrentTime:   c.config.time(), -				Intermediates: x509.NewCertPool(), -			} - -			for i, cert := range certs { -				if i == 0 { -					continue -				} -				opts.Intermediates.AddCert(cert) -			} - -			chains, err := certs[0].Verify(opts) -			if err != nil { -				c.sendAlert(alertBadCertificate) -				return errors.New("tls: failed to verify client's certificate: " + err.Error()) -			} - -			ok := false -			for _, ku := range certs[0].ExtKeyUsage { -				if ku == x509.ExtKeyUsageClientAuth { -					ok = true -					break -				} -			} -			if !ok { -				c.sendAlert(alertHandshakeFailure) -				return errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication") -			} - -			c.verifiedChains = chains -		} - -		if len(certs) > 0 { -			if pub, ok = certs[0].PublicKey.(*rsa.PublicKey); !ok { -				return c.sendAlert(alertUnsupportedCertificate) -			} -			c.peerCertificates = certs +		pub, err = hs.processCertsFromClient(certMsg.certificates) +		if err != nil { +			return err  		}  		msg, err = c.readHandshake() @@ -259,7 +376,7 @@ FindCipherSuite:  	if !ok {  		return c.sendAlert(alertUnexpectedMessage)  	} -	finishedHash.Write(ckx.marshal()) +	hs.finishedHash.Write(ckx.marshal())  	// If we received a client cert in response to our certificate request message,  	// the client will send us a certificateVerifyMsg immediately after the @@ -278,15 +395,15 @@ FindCipherSuite:  		}  		digest := make([]byte, 0, 36) -		digest = finishedHash.serverMD5.Sum(digest) -		digest = finishedHash.serverSHA1.Sum(digest) +		digest = hs.finishedHash.serverMD5.Sum(digest) +		digest = hs.finishedHash.serverSHA1.Sum(digest)  		err = rsa.VerifyPKCS1v15(pub, crypto.MD5SHA1, digest, certVerify.signature)  		if err != nil {  			c.sendAlert(alertBadCertificate)  			return errors.New("could not validate signature of connection nonces: " + err.Error())  		} -		finishedHash.Write(certVerify.marshal()) +		hs.finishedHash.Write(certVerify.marshal())  	}  	preMasterSecret, err := keyAgreement.processClientKeyExchange(config, cert, ckx, c.vers) @@ -294,20 +411,38 @@ FindCipherSuite:  		c.sendAlert(alertHandshakeFailure)  		return err  	} +	hs.masterSecret = masterFromPreMasterSecret(c.vers, preMasterSecret, hs.clientHello.random, hs.hello.random) + +	return nil +} + +func (hs *serverHandshakeState) establishKeys() error { +	c := hs.c -	masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := -		keysFromPreMasterSecret(c.vers, preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen) +	clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := +		keysFromMasterSecret(c.vers, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen) -	clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */) -	clientHash := suite.mac(c.vers, clientMAC) +	clientCipher := hs.suite.cipher(clientKey, clientIV, true /* for reading */) +	clientHash := hs.suite.mac(c.vers, clientMAC)  	c.in.prepareCipherSpec(c.vers, clientCipher, clientHash) + +	serverCipher := hs.suite.cipher(serverKey, serverIV, false /* not for reading */) +	serverHash := hs.suite.mac(c.vers, serverMAC) +	c.out.prepareCipherSpec(c.vers, serverCipher, serverHash) + +	return nil +} + +func (hs *serverHandshakeState) readFinished() error { +	c := hs.c +  	c.readRecord(recordTypeChangeCipherSpec)  	if err := c.error(); err != nil {  		return err  	} -	if hello.nextProtoNeg { -		msg, err = c.readHandshake() +	if hs.hello.nextProtoNeg { +		msg, err := c.readHandshake()  		if err != nil {  			return err  		} @@ -315,11 +450,11 @@ FindCipherSuite:  		if !ok {  			return c.sendAlert(alertUnexpectedMessage)  		} -		finishedHash.Write(nextProto.marshal()) +		hs.finishedHash.Write(nextProto.marshal())  		c.clientProtocol = nextProto.proto  	} -	msg, err = c.readHandshake() +	msg, err := c.readHandshake()  	if err != nil {  		return err  	} @@ -328,25 +463,142 @@ FindCipherSuite:  		return c.sendAlert(alertUnexpectedMessage)  	} -	verify := finishedHash.clientSum(masterSecret) +	verify := hs.finishedHash.clientSum(hs.masterSecret)  	if len(verify) != len(clientFinished.verifyData) ||  		subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {  		return c.sendAlert(alertHandshakeFailure)  	} -	finishedHash.Write(clientFinished.marshal()) +	hs.finishedHash.Write(clientFinished.marshal()) +	return nil +} + +func (hs *serverHandshakeState) sendSessionTicket() error { +	if !hs.hello.ticketSupported { +		return nil +	} + +	c := hs.c +	m := new(newSessionTicketMsg) + +	var err error +	state := sessionState{ +		vers:         c.vers, +		cipherSuite:  hs.suite.id, +		masterSecret: hs.masterSecret, +		certificates: hs.certsFromClient, +	} +	m.ticket, err = c.encryptTicket(&state) +	if err != nil { +		return err +	} + +	hs.finishedHash.Write(m.marshal()) +	c.writeRecord(recordTypeHandshake, m.marshal()) + +	return nil +} + +func (hs *serverHandshakeState) sendFinished() error { +	c := hs.c -	serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */) -	serverHash := suite.mac(c.vers, serverMAC) -	c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)  	c.writeRecord(recordTypeChangeCipherSpec, []byte{1})  	finished := new(finishedMsg) -	finished.verifyData = finishedHash.serverSum(masterSecret) +	finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret) +	hs.finishedHash.Write(finished.marshal())  	c.writeRecord(recordTypeHandshake, finished.marshal()) -	c.handshakeComplete = true -	c.cipherSuite = suite.id +	c.cipherSuite = hs.suite.id + +	return nil +} + +// processCertsFromClient takes a chain of client certificates either from a +// Certificates message or from a sessionState and verifies them. It returns +// the public key of the leaf certificate. +func (hs *serverHandshakeState) processCertsFromClient(certificates [][]byte) (*rsa.PublicKey, error) { +	c := hs.c + +	hs.certsFromClient = certificates +	certs := make([]*x509.Certificate, len(certificates)) +	var err error +	for i, asn1Data := range certificates { +		if certs[i], err = x509.ParseCertificate(asn1Data); err != nil { +			c.sendAlert(alertBadCertificate) +			return nil, errors.New("tls: failed to parse client certificate: " + err.Error()) +		} +	} + +	if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 { +		opts := x509.VerifyOptions{ +			Roots:         c.config.ClientCAs, +			CurrentTime:   c.config.time(), +			Intermediates: x509.NewCertPool(), +			KeyUsages:     []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, +		} + +		for _, cert := range certs[1:] { +			opts.Intermediates.AddCert(cert) +		} + +		chains, err := certs[0].Verify(opts) +		if err != nil { +			c.sendAlert(alertBadCertificate) +			return nil, errors.New("tls: failed to verify client's certificate: " + err.Error()) +		} + +		ok := false +		for _, ku := range certs[0].ExtKeyUsage { +			if ku == x509.ExtKeyUsageClientAuth { +				ok = true +				break +			} +		} +		if !ok { +			c.sendAlert(alertHandshakeFailure) +			return nil, errors.New("tls: client's certificate's extended key usage doesn't permit it to be used for client authentication") +		} + +		c.verifiedChains = chains +	} + +	if len(certs) > 0 { +		pub, ok := certs[0].PublicKey.(*rsa.PublicKey) +		if !ok { +			return nil, c.sendAlert(alertUnsupportedCertificate) +		} +		c.peerCertificates = certs +		return pub, nil +	} + +	return nil, nil +} + +// tryCipherSuite returns a cipherSuite with the given id if that cipher suite +// is acceptable to use. +func (c *Conn) tryCipherSuite(id uint16, supportedCipherSuites []uint16, ellipticOk bool) *cipherSuite { +	for _, supported := range supportedCipherSuites { +		if id == supported { +			var candidate *cipherSuite + +			for _, s := range cipherSuites { +				if s.id == id { +					candidate = s +					break +				} +			} +			if candidate == nil { +				continue +			} +			// Don't select a ciphersuite which we can't +			// support for this client. +			if candidate.elliptic && !ellipticOk { +				continue +			} +			return candidate +		} +	}  	return nil  } diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go index 7c1267101..bf8cbe3ae 100644 --- a/src/pkg/crypto/tls/handshake_server_test.go +++ b/src/pkg/crypto/tls/handshake_server_test.go @@ -11,12 +11,15 @@ import (  	"encoding/hex"  	"encoding/pem"  	"flag" +	"fmt"  	"io"  	"log"  	"math/big"  	"net" +	"os"  	"strconv"  	"strings" +	"sync"  	"testing"  	"time"  ) @@ -80,13 +83,20 @@ func TestRejectBadProtocolVersion(t *testing.T) {  }  func TestNoSuiteOverlap(t *testing.T) { -	clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, "", false, nil, nil} +	clientHello := &clientHelloMsg{ +		vers:               0x0301, +		cipherSuites:       []uint16{0xff00}, +		compressionMethods: []uint8{0}, +	}  	testClientHelloFailure(t, clientHello, alertHandshakeFailure) -  }  func TestNoCompressionOverlap(t *testing.T) { -	clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{TLS_RSA_WITH_RC4_128_SHA}, []uint8{0xff}, false, "", false, nil, nil} +	clientHello := &clientHelloMsg{ +		vers:               0x0301, +		cipherSuites:       []uint16{TLS_RSA_WITH_RC4_128_SHA}, +		compressionMethods: []uint8{0xff}, +	}  	testClientHelloFailure(t, clientHello, alertHandshakeFailure)  } @@ -115,6 +125,50 @@ func TestClose(t *testing.T) {  	}  } +func testHandshake(clientConfig, serverConfig *Config) (state ConnectionState, err error) { +	c, s := net.Pipe() +	go func() { +		cli := Client(c, clientConfig) +		cli.Handshake() +		c.Close() +	}() +	server := Server(s, serverConfig) +	err = server.Handshake() +	if err == nil { +		state = server.ConnectionState() +	} +	s.Close() +	return +} + +func TestCipherSuitePreference(t *testing.T) { +	serverConfig := &Config{ +		CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA}, +		Certificates: testConfig.Certificates, +	} +	clientConfig := &Config{ +		CipherSuites:       []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_RSA_WITH_RC4_128_SHA}, +		InsecureSkipVerify: true, +	} +	state, err := testHandshake(clientConfig, serverConfig) +	if err != nil { +		t.Fatalf("handshake failed: %s", err) +	} +	if state.CipherSuite != TLS_RSA_WITH_AES_128_CBC_SHA { +		// By default the server should use the client's preference. +		t.Fatalf("Client's preference was not used, got %x", state.CipherSuite) +	} + +	serverConfig.PreferServerCipherSuites = true +	state, err = testHandshake(clientConfig, serverConfig) +	if err != nil { +		t.Fatalf("handshake failed: %s", err) +	} +	if state.CipherSuite != TLS_RSA_WITH_RC4_128_SHA { +		t.Fatalf("Server's preference was not used, got %x", state.CipherSuite) +	} +} +  func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config, peers []*x509.Certificate) {  	c, s := net.Pipe()  	srv := Server(s, config) @@ -186,6 +240,11 @@ func TestHandshakeServerSNI(t *testing.T) {  	testServerScript(t, "SNI", selectCertificateBySNIScript, testConfig, nil)  } +func TestResumption(t *testing.T) { +	testServerScript(t, "IssueTicket", issueSessionTicketTest, testConfig, nil) +	testServerScript(t, "Resume", serverResumeTest, testConfig, nil) +} +  type clientauthTest struct {  	name       string  	clientauth ClientAuthType @@ -203,55 +262,133 @@ func TestClientAuth(t *testing.T) {  	}  } +// recordingConn is a net.Conn that records the traffic that passes through it. +// WriteTo can be used to produce Go code that contains the recorded traffic. +type recordingConn struct { +	net.Conn +	lock             sync.Mutex +	flows            [][]byte +	currentlyReading bool +} + +func (r *recordingConn) Read(b []byte) (n int, err error) { +	if n, err = r.Conn.Read(b); n == 0 { +		return +	} +	b = b[:n] + +	r.lock.Lock() +	defer r.lock.Unlock() + +	if l := len(r.flows); l == 0 || !r.currentlyReading { +		buf := make([]byte, len(b)) +		copy(buf, b) +		r.flows = append(r.flows, buf) +	} else { +		r.flows[l-1] = append(r.flows[l-1], b[:n]...) +	} +	r.currentlyReading = true +	return +} + +func (r *recordingConn) Write(b []byte) (n int, err error) { +	if n, err = r.Conn.Write(b); n == 0 { +		return +	} +	b = b[:n] + +	r.lock.Lock() +	defer r.lock.Unlock() + +	if l := len(r.flows); l == 0 || r.currentlyReading { +		buf := make([]byte, len(b)) +		copy(buf, b) +		r.flows = append(r.flows, buf) +	} else { +		r.flows[l-1] = append(r.flows[l-1], b[:n]...) +	} +	r.currentlyReading = false +	return +} + +// WriteTo writes Go source code to w that contains the recorded traffic. +func (r *recordingConn) WriteTo(w io.Writer) { +	fmt.Fprintf(w, "var changeMe = [][]byte {\n") +	for _, buf := range r.flows { +		fmt.Fprintf(w, "\t{") +		for i, b := range buf { +			if i%8 == 0 { +				fmt.Fprintf(w, "\n\t\t") +			} +			fmt.Fprintf(w, "0x%02x, ", b) +		} +		fmt.Fprintf(w, "\n\t},\n") +	} +	fmt.Fprintf(w, "}\n") +} +  var serve = flag.Bool("serve", false, "run a TLS server on :10443")  var testCipherSuites = flag.String("ciphersuites",  	"0x"+strconv.FormatInt(int64(TLS_RSA_WITH_RC4_128_SHA), 16),  	"cipher suites to accept in serving mode")  var testClientAuth = flag.Int("clientauth", 0, "value for tls.Config.ClientAuth") -func TestRunServer(t *testing.T) { -	if !*serve { -		return -	} - +func GetTestConfig() *Config { +	var config = *testConfig  	suites := strings.Split(*testCipherSuites, ",") -	testConfig.CipherSuites = make([]uint16, len(suites)) +	config.CipherSuites = make([]uint16, len(suites))  	for i := range suites {  		suite, err := strconv.ParseUint(suites[i], 0, 64)  		if err != nil {  			panic(err)  		} -		testConfig.CipherSuites[i] = uint16(suite) +		config.CipherSuites[i] = uint16(suite)  	} -	testConfig.ClientAuth = ClientAuthType(*testClientAuth) +	config.ClientAuth = ClientAuthType(*testClientAuth) +	return &config +} + +func TestRunServer(t *testing.T) { +	if !*serve { +		return +	} + +	config := GetTestConfig() -	l, err := Listen("tcp", ":10443", testConfig) +	const addr = ":10443" +	l, err := net.Listen("tcp", addr)  	if err != nil {  		t.Fatal(err)  	} +	log.Printf("Now listening for connections on %s", addr)  	for { -		c, err := l.Accept() +		tcpConn, err := l.Accept()  		if err != nil { +			log.Printf("error accepting connection: %s", err) +			break +		} + +		record := &recordingConn{ +			Conn: tcpConn, +		} + +		conn := Server(record, config) +		if err := conn.Handshake(); err != nil {  			log.Printf("error from TLS handshake: %s", err)  			break  		} -		_, err = c.Write([]byte("hello, world\n")) +		_, err = conn.Write([]byte("hello, world\n"))  		if err != nil { -			log.Printf("error from TLS: %s", err) +			log.Printf("error from Write: %s", err)  			continue  		} -		st := c.(*Conn).ConnectionState() -		if len(st.PeerCertificates) > 0 { -			log.Print("Handling request from client ", st.PeerCertificates[0].Subject.CommonName) -		} else { -			log.Print("Handling request from anon client") -		} +		conn.Close() -		c.Close() +		record.WriteTo(os.Stdout)  	}  } @@ -296,30 +433,23 @@ func loadPEMCert(in string) *x509.Certificate {  // Script of interaction with gnutls implementation.  // The values for this test are obtained by building and running in server mode: -//   % go test -run "TestRunServer" -serve -// and then: -//   % gnutls-cli --insecure --debug 100 -p 10443 localhost > /tmp/log 2>&1 -//   % python parse-gnutls-cli-debug-log.py < /tmp/log +//   % go test -test.run "TestRunServer" -serve +// The recorded bytes are written to stdout.  var rc4ServerScript = [][]byte{  	{ -		0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00, -		0x76, 0x03, 0x02, 0x4e, 0xdd, 0xe6, 0xa5, 0xf7, -		0x00, 0x36, 0xf7, 0x83, 0xec, 0x93, 0x7c, 0xd2, -		0x4d, 0xe7, 0x7b, 0xf5, 0x4c, 0xf7, 0xe3, 0x86, -		0xe8, 0xec, 0x3b, 0xbd, 0x2c, 0x9a, 0x3f, 0x57, -		0xf0, 0xa4, 0xd4, 0x00, 0x00, 0x34, 0x00, 0x33, -		0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, -		0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, -		0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, -		0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, -		0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, -		0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, -		0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09, -		0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, -		0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, -		0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, +		0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00, +		0x50, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xbd, 0x32, +		0x13, 0xd7, 0xea, 0x33, 0x65, 0x02, 0xb8, 0x70, +		0xb7, 0x84, 0xc4, 0x05, 0x1f, 0xa4, 0x24, 0xc4, +		0x91, 0x69, 0x04, 0x32, 0x96, 0xfe, 0x5b, 0x49, +		0x71, 0x60, 0x9a, 0x00, 0x00, 0x28, 0x00, 0x39, +		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13, +		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f, +		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12, +		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08, +		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01, +		0x00,  	}, -  	{  		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00,  		0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -418,86 +548,145 @@ var rc4ServerScript = [][]byte{  		0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e,  		0x00, 0x00, 0x00,  	}, -  	{  		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, -		0x82, 0x00, 0x80, 0x39, 0xe2, 0x0f, 0x49, 0xa0, -		0xe6, 0xe4, 0x3b, 0x0c, 0x5f, 0xce, 0x39, 0x97, -		0x6c, 0xb6, 0x41, 0xd9, 0xe1, 0x52, 0x8f, 0x43, -		0xb3, 0xc6, 0x4f, 0x9a, 0xe2, 0x1e, 0xb9, 0x3b, -		0xe3, 0x72, 0x17, 0x68, 0xb2, 0x0d, 0x7b, 0x71, -		0x33, 0x96, 0x5c, 0xf9, 0xfe, 0x18, 0x8f, 0x2f, -		0x2b, 0x82, 0xec, 0x03, 0xf2, 0x16, 0xa8, 0xf8, -		0x39, 0xf9, 0xbb, 0x5a, 0xd3, 0x0c, 0xc1, 0x2a, -		0x52, 0xa1, 0x90, 0x20, 0x6b, 0x24, 0xc9, 0x55, -		0xee, 0x05, 0xd8, 0xb3, 0x43, 0x58, 0xf6, 0x7f, -		0x68, 0x2d, 0xb3, 0xd1, 0x1b, 0x30, 0xaa, 0xdf, -		0xfc, 0x85, 0xf1, 0xab, 0x14, 0x51, 0x91, 0x78, -		0x29, 0x35, 0x65, 0xe0, 0x9c, 0xf6, 0xb7, 0x35, -		0x33, 0xdb, 0x28, 0x93, 0x4d, 0x86, 0xbc, 0xfe, -		0xaa, 0xd1, 0xc0, 0x2e, 0x4d, 0xec, 0xa2, 0x98, -		0xca, 0x08, 0xb2, 0x91, 0x14, 0xde, 0x97, 0x3a, -		0xc4, 0x6b, 0x49, 0x14, 0x03, 0x01, 0x00, 0x01, -		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x7a, 0xcb, -		0x3b, 0x0e, 0xbb, 0x7a, 0x56, 0x39, 0xaf, 0x83, -		0xae, 0xfd, 0x25, 0xfd, 0x64, 0xb4, 0x0c, 0x0c, -		0x17, 0x46, 0x54, 0x2c, 0x6a, 0x07, 0x83, 0xc6, -		0x46, 0x08, 0x0b, 0xcd, 0x15, 0x53, 0xef, 0x40, -		0x4e, 0x56, +		0x82, 0x00, 0x80, 0x2d, 0x09, 0x7c, 0x7f, 0xfc, +		0x84, 0xce, 0xb3, 0x30, 0x9b, 0xf9, 0xb7, 0xc8, +		0xc3, 0xff, 0xee, 0x6f, 0x20, 0x8a, 0xf4, 0xfb, +		0x86, 0x55, 0x1f, 0x6a, 0xb4, 0x81, 0x50, 0x3a, +		0x46, 0x1b, 0xd3, 0xca, 0x4b, 0x11, 0xff, 0xef, +		0x02, 0xbc, 0x18, 0xb8, 0x4a, 0x7d, 0x43, 0x23, +		0x96, 0x92, 0x27, 0x7c, 0xca, 0xcf, 0xe6, 0x91, +		0xe8, 0x14, 0x97, 0x68, 0xb4, 0xe5, 0xc0, 0xc9, +		0x23, 0xdd, 0x54, 0x07, 0xa6, 0x2e, 0x8c, 0x98, +		0xfc, 0xc6, 0x8c, 0x04, 0x6b, 0x1b, 0x5f, 0xd5, +		0x3d, 0x8b, 0x6c, 0x55, 0x4f, 0x7a, 0xe6, 0x6c, +		0x74, 0x2c, 0x1e, 0x34, 0xdb, 0xfb, 0x00, 0xb1, +		0x4e, 0x10, 0x21, 0x16, 0xe0, 0x3e, 0xc5, 0x64, +		0x84, 0x28, 0x2b, 0x2b, 0x29, 0x47, 0x51, 0x34, +		0x76, 0x15, 0x20, 0x71, 0x0b, 0x30, 0xa1, 0x85, +		0xd5, 0x15, 0x18, 0x14, 0x64, 0x4b, 0x40, 0x7c, +		0x4f, 0xb3, 0x7b, 0x14, 0x03, 0x01, 0x00, 0x01, +		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xab, 0xee, +		0xf5, 0x97, 0x5f, 0xc6, 0x78, 0xf3, 0xc6, 0x83, +		0x5b, 0x55, 0x4f, 0xcb, 0x45, 0x3f, 0xfa, 0xf7, +		0x05, 0x02, 0xc2, 0x63, 0x87, 0x18, 0xb5, 0x9a, +		0x62, 0xe2, 0x3f, 0x88, 0x5a, 0x60, 0x61, 0x72, +		0xfa, 0x9c,  	}, -  	{  		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, -		0x01, 0x00, 0x24, 0xd3, 0x72, 0xeb, 0x29, 0xb9, -		0x15, 0x29, 0xb5, 0xe5, 0xb7, 0xef, 0x5c, 0xb2, -		0x9d, 0xf6, 0xc8, 0x47, 0xd6, 0xa0, 0x84, 0xf0, -		0x8c, 0xcb, 0xe6, 0xbe, 0xbc, 0xfb, 0x38, 0x90, -		0x89, 0x60, 0xa2, 0xe8, 0xaa, 0xb3, 0x12, 0x17, -		0x03, 0x01, 0x00, 0x21, 0x67, 0x4a, 0x3d, 0x31, -		0x6c, 0x5a, 0x1c, 0xf9, 0x6e, 0xf1, 0xd8, 0x12, -		0x0e, 0xb9, 0xfd, 0xfc, 0x66, 0x91, 0xd1, 0x1d, -		0x6e, 0xe4, 0x55, 0xdd, 0x11, 0xb9, 0xb8, 0xa2, -		0x65, 0xa1, 0x95, 0x64, 0x1c, 0x15, 0x03, 0x01, -		0x00, 0x16, 0x9b, 0xa0, 0x24, 0xe3, 0xcb, 0xae, -		0xad, 0x51, 0xb3, 0x63, 0x59, 0x78, 0x49, 0x24, -		0x06, 0x6e, 0xee, 0x7a, 0xd7, 0x74, 0x53, 0x04, +		0x01, 0x00, 0x24, 0x72, 0xa4, 0xe4, 0xaa, 0xd2, +		0xc4, 0x39, 0x7e, 0x2a, 0xc1, 0x6f, 0x34, 0x42, +		0x28, 0xcb, 0x9d, 0x7a, 0x09, 0xca, 0x96, 0xad, +		0x0e, 0x11, 0x51, 0x8a, 0x06, 0xb0, 0xe9, 0xca, +		0xeb, 0xce, 0xe2, 0xd5, 0x2e, 0xc1, 0x8d, 0x17, +		0x03, 0x01, 0x00, 0x21, 0x2e, 0x61, 0x86, 0x17, +		0xdb, 0xa6, 0x30, 0xe2, 0x62, 0x06, 0x2a, 0x8b, +		0x75, 0x2c, 0x2d, 0xcf, 0xf5, 0x01, 0x11, 0x52, +		0x81, 0x38, 0xcf, 0xd5, 0xf7, 0xdc, 0x52, 0x31, +		0x1f, 0x97, 0x43, 0xc2, 0x71, 0x15, 0x03, 0x01, +		0x00, 0x16, 0xe0, 0x21, 0xfe, 0x36, 0x2e, 0x68, +		0x2c, 0xf1, 0xbe, 0x04, 0xec, 0xd4, 0xc6, 0xdd, +		0xac, 0x6f, 0x4c, 0x85, 0x32, 0x3f, 0x87, 0x1b,  	},  }  var des3ServerScript = [][]byte{  	{ -		0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00, -		0x76, 0x03, 0x02, 0x4e, 0x84, 0xf4, 0x3c, 0xe4, -		0xb8, 0xc7, 0xa0, 0x30, 0x55, 0x2a, 0xbc, 0xb7, -		0x04, 0x6b, 0x6f, 0x87, 0x93, 0x96, 0xbd, 0x1a, -		0x7a, 0x1e, 0xce, 0xd2, 0x0d, 0xf3, 0x01, 0x03, -		0xbe, 0x7b, 0x17, 0x00, 0x00, 0x34, 0x00, 0x33, -		0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, -		0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, -		0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, -		0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, -		0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, -		0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, -		0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09, -		0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, -		0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, -		0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, +		0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00, +		0xc1, 0x03, 0x03, 0x50, 0xae, 0x5d, 0x38, 0xec, +		0xaa, 0x2f, 0x41, 0xf9, 0xd2, 0x7b, 0xa1, 0xfd, +		0x0f, 0xff, 0x4e, 0x54, 0x0e, 0x15, 0x57, 0xaf, +		0x2c, 0x91, 0xb5, 0x35, 0x5b, 0x2e, 0xb0, 0xec, +		0x20, 0xe5, 0xd2, 0x00, 0x00, 0x50, 0xc0, 0x09, +		0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24, +		0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27, +		0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12, +		0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e, +		0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16, +		0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2, +		0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13, +		0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41, +		0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84, +		0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00, +		0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, +		0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, +		0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, +		0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17, +		0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, +		0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, +		0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01, +		0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01, +		0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, +		0x02, 0x03,  	}, -  	{ -		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, -		0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00, +		0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -		0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x16, -		0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, -		0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, -		0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, -		0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, -		0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, -		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, +		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01, +		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02, +		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0, +		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01, +		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, +		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09, +		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, +		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, +		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, +		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, +		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, +		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, +		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, +		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, +		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, +		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, +		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, +		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, +		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33, +		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, +		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, +		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, +		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, +		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, +		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, +		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, +		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, +		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, +		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, +		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, +		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79, +		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10, +		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43, +		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85, +		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c, +		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5, +		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c, +		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56, +		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26, +		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21, +		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf, +		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07, +		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39, +		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3, +		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf, +		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb, +		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03, +		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, +		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, +		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85, +		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23, +		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39, +		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, +		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2, +		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, +		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, +		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,  		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,  		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,  		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, @@ -506,172 +695,207 @@ var des3ServerScript = [][]byte{  		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,  		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,  		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, -		0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, -		0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, -		0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, -		0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, -		0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, -		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, -		0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, -		0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, -		0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, -		0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, -		0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, -		0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, -		0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, -		0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, -		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -		0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, -		0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, -		0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, -		0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, -		0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, -		0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, -		0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, -		0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, -		0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, -		0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, -		0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, -		0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, -		0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, -		0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, -		0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, -		0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, -		0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, -		0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, -		0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, -		0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, -		0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, -		0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, -		0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, -		0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, -		0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, -		0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, -		0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, -		0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, -		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, -		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, -		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, -		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, -		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, -		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, -		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, -		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, -		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, -		0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, -		0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, -		0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, -		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -		0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, -		0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, -		0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, -		0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, -		0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, -		0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, -		0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, -		0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, -		0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, -		0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, -		0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, -		0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, -		0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, -		0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, -		0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, -		0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, -		0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, -		0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, -		0x00, 0x00, 0x00, +		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85, +		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, +		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, +		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, +		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, +		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, +		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59, +		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7, +		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95, +		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66, +		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3, +		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13, +		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba, +		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31, +		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50, +		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f, +		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96, +		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f, +		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b, +		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70, +		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e, +		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9, +		0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, +		0x00,  	}, -  	{  		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, -		0x82, 0x00, 0x80, 0xae, 0xcf, 0x4f, 0x70, 0x0e, -		0xe5, 0xe7, 0xba, 0xef, 0x0c, 0x66, 0xe9, 0xae, -		0x76, 0xf4, 0xe0, 0xbc, 0x1c, 0x22, 0x5b, 0x72, -		0xc9, 0x68, 0x63, 0x44, 0xec, 0x72, 0xc2, 0xca, -		0xac, 0xc2, 0xf5, 0x5c, 0x28, 0xa1, 0xaf, 0xd0, -		0xc2, 0xf7, 0x79, 0x71, 0x32, 0x73, 0x86, 0xea, -		0x39, 0xf6, 0x04, 0x26, 0x19, 0x84, 0x1d, 0x7d, -		0xa1, 0x21, 0xa6, 0x88, 0xbf, 0x33, 0x5a, 0x64, -		0xb0, 0xc2, 0xcc, 0x19, 0x7a, 0x8b, 0x6e, 0x94, -		0x9e, 0x2e, 0x20, 0xbe, 0xdc, 0xe9, 0x8e, 0xae, -		0x5c, 0x39, 0xc8, 0xcd, 0x0e, 0x19, 0x9a, 0xa2, -		0xfc, 0x3f, 0x61, 0x9a, 0xca, 0x58, 0x69, 0x0d, -		0xa8, 0x7b, 0xbe, 0x98, 0x8f, 0xb9, 0x9d, 0x8b, -		0x68, 0x65, 0xa9, 0x74, 0xcc, 0x8d, 0x0c, 0xb2, -		0xc4, 0x0f, 0xdc, 0x56, 0x3e, 0x44, 0x61, 0x0a, -		0x26, 0x93, 0x99, 0xef, 0x67, 0xff, 0x6e, 0x73, -		0x01, 0xa1, 0x90, 0x14, 0x03, 0x01, 0x00, 0x01, -		0x01, 0x16, 0x03, 0x01, 0x00, 0x60, 0x49, 0x36, -		0xc8, 0x38, 0x95, 0xe4, 0x5d, 0x8e, 0x80, 0x10, -		0x26, 0x9f, 0x87, 0x7d, 0xcd, 0xb9, 0x32, 0x6c, -		0xff, 0xaa, 0xe0, 0x07, 0xec, 0x33, 0xe2, 0x36, -		0x9d, 0xd5, 0x83, 0x2c, 0xf0, 0x0a, 0xa0, 0xa8, -		0x12, 0x9f, 0xca, 0x72, 0xda, 0x70, 0x7d, 0x76, -		0x80, 0x12, 0x88, 0x07, 0xaa, 0x27, 0x62, 0x33, -		0xab, 0x55, 0xad, 0x3c, 0x2b, 0x54, 0xc4, 0x1c, -		0x91, 0xfd, 0x8f, 0x9c, 0xa7, 0x8b, 0x75, 0x10, -		0xa8, 0x6e, 0xfc, 0x30, 0x52, 0x8a, 0x61, 0x02, -		0xdb, 0x9c, 0x6f, 0xc8, 0x19, 0x93, 0x5d, 0x41, -		0x1d, 0x36, 0x68, 0x0b, 0xec, 0x30, 0xae, 0xfb, -		0x90, 0xdb, 0x6d, 0x83, 0xb0, 0xf2, +		0x82, 0x00, 0x80, 0x51, 0x04, 0xf1, 0x7a, 0xbf, +		0xe8, 0xa5, 0x86, 0x09, 0xa7, 0xf3, 0xcc, 0x93, +		0x00, 0x10, 0x5b, 0xb8, 0xc1, 0x51, 0x0d, 0x5b, +		0xcd, 0xed, 0x26, 0x01, 0x69, 0x73, 0xf4, 0x05, +		0x8a, 0x6a, 0xc3, 0xb1, 0x9e, 0x84, 0x4e, 0x39, +		0xcf, 0x5e, 0x55, 0xa9, 0x70, 0x19, 0x96, 0x91, +		0xcd, 0x2c, 0x78, 0x3c, 0xa2, 0x6d, 0xb0, 0x49, +		0x86, 0xf6, 0xd1, 0x3a, 0xde, 0x00, 0x4b, 0xa6, +		0x25, 0xbf, 0x85, 0x39, 0xce, 0xb1, 0xcf, 0xbc, +		0x16, 0xc7, 0x66, 0xac, 0xf8, 0xd2, 0x3b, 0xd1, +		0xcc, 0x16, 0xac, 0x63, 0x3c, 0xbe, 0xd9, 0xb6, +		0x6a, 0xe4, 0x13, 0x8a, 0xf4, 0x56, 0x2f, 0x92, +		0x54, 0xd8, 0xf0, 0x84, 0x01, 0x32, 0x1a, 0xa9, +		0x2d, 0xaf, 0x82, 0x0e, 0x00, 0xfa, 0x07, 0x88, +		0xd9, 0x87, 0xe7, 0xdc, 0x9e, 0xe9, 0x72, 0x49, +		0xb8, 0xfa, 0x8c, 0x7b, 0x07, 0x0b, 0x03, 0x7c, +		0x10, 0x8c, 0x8a, 0x14, 0x03, 0x01, 0x00, 0x01, +		0x01, 0x16, 0x03, 0x01, 0x00, 0xa8, 0x61, 0xa4, +		0xf4, 0x5f, 0x8a, 0x1f, 0x5c, 0x92, 0x3f, 0x8c, +		0xdb, 0xd6, 0x10, 0xcd, 0x9e, 0xe7, 0xf0, 0xc4, +		0x3c, 0xb6, 0x1c, 0x9a, 0x56, 0x73, 0x7f, 0xa6, +		0x14, 0x24, 0xcb, 0x96, 0x1f, 0xe0, 0xaf, 0xcd, +		0x3c, 0x66, 0x43, 0xb7, 0x37, 0x65, 0x34, 0x47, +		0xf8, 0x43, 0xf1, 0xcc, 0x15, 0xb8, 0xdc, 0x35, +		0xe0, 0xa4, 0x2d, 0x78, 0x94, 0xe0, 0x02, 0xf3, +		0x76, 0x46, 0xf7, 0x9b, 0x8d, 0x0d, 0x5d, 0x0b, +		0xd3, 0xdd, 0x9a, 0x9e, 0x62, 0x2e, 0xc5, 0x98, +		0x75, 0x63, 0x0c, 0xbf, 0x8e, 0x49, 0x33, 0x23, +		0x7c, 0x00, 0xcf, 0xfb, 0xcf, 0xba, 0x0f, 0x41, +		0x39, 0x89, 0xb9, 0xcc, 0x59, 0xd0, 0x2b, 0xb6, +		0xec, 0x04, 0xe2, 0xc0, 0x52, 0xc7, 0xcf, 0x71, +		0x47, 0xff, 0x70, 0x7e, 0xa9, 0xbd, 0x1c, 0xdd, +		0x17, 0xa5, 0x6c, 0xb7, 0x10, 0x4f, 0x42, 0x18, +		0x37, 0x69, 0xa9, 0xd2, 0xb3, 0x18, 0x84, 0x92, +		0xa7, 0x47, 0x21, 0xf6, 0x95, 0x63, 0x29, 0xd6, +		0xa5, 0xb6, 0xda, 0x65, 0x67, 0x69, 0xc4, 0x26, +		0xac, 0x8b, 0x08, 0x58, 0xdd, 0x3c, 0x31, 0x20, +		0xd5, 0x0c, 0x88, 0x72, 0x18, 0x16, 0x88, 0x1e, +		0x4a, 0x0f, 0xe1, 0xcf, 0x95, 0x24,  	}, -  	{ -		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, -		0x01, 0x00, 0x28, 0x07, 0xf3, 0x33, 0x84, 0xb1, -		0x5d, 0x2b, 0x52, 0xa4, 0x63, 0x3c, 0x32, 0xe0, -		0x0d, 0x22, 0xf5, 0x23, 0xec, 0xf9, 0xa6, 0xec, -		0xc0, 0x12, 0x69, 0x88, 0xf6, 0x7d, 0x37, 0xcd, -		0xc2, 0x74, 0x2f, 0xef, 0xf6, 0x49, 0x15, 0xea, -		0x88, 0x3f, 0x55, 0x17, 0x03, 0x01, 0x00, 0x28, -		0xaf, 0x00, 0x84, 0xff, 0x11, 0x01, 0x6d, 0xba, -		0x39, 0x5e, 0x45, 0xe1, 0x52, 0x5e, 0xc1, 0xab, -		0xde, 0x5b, 0x16, 0xdd, 0xd6, 0x61, 0x57, 0xb8, -		0x66, 0x8b, 0x2d, 0xde, 0x51, 0x41, 0xc5, 0x09, -		0xb3, 0x6a, 0x06, 0x43, 0xb4, 0x73, 0x5c, 0xf1, -		0x15, 0x03, 0x01, 0x00, 0x18, 0xbd, 0x65, 0xb2, -		0xce, 0x77, 0x2e, 0xf9, 0x11, 0xc4, 0x80, 0x43, -		0x5a, 0x73, 0x8b, 0x73, 0xdd, 0xf0, 0x54, 0x44, -		0x7c, 0x56, 0x19, 0x54, 0xda, +		0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00, +		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, +		0xe8, 0x4b, 0xde, 0xef, 0xba, 0x3e, 0x18, 0x1c, +		0x1e, 0x5e, 0xbc, 0x87, 0xf1, 0x87, 0x8d, 0x72, +		0xe3, 0xbe, 0x0f, 0xdf, 0xfd, 0xd0, 0xb2, 0x89, +		0xf8, 0x05, 0x9a, 0x52, 0x47, 0x77, 0x9e, 0xe8, +		0xb1, 0x1d, 0x18, 0xed, 0x6a, 0x4b, 0x63, 0x1d, +		0xf1, 0x62, 0xd2, 0x65, 0x21, 0x26, 0x73, 0xd4, +		0x35, 0x5b, 0x95, 0x89, 0x12, 0x59, 0x23, 0x8c, +		0xc3, 0xfc, 0xf9, 0x4d, 0x21, 0x79, 0xa0, 0xbd, +		0xff, 0x33, 0xa2, 0x3d, 0x0b, 0x6f, 0x89, 0xc9, +		0x23, 0xe4, 0xe7, 0x9f, 0x1d, 0x98, 0xf6, 0xed, +		0x02, 0x8d, 0xac, 0x1a, 0xf9, 0xcb, 0xa5, 0x14, +		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, +		0x00, 0x28, 0x91, 0x56, 0x80, 0xe2, 0x6d, 0x51, +		0x88, 0x03, 0xf8, 0x49, 0xe6, 0x6a, 0x5a, 0xfb, +		0x2f, 0x0b, 0xb5, 0xa1, 0x0d, 0x63, 0x83, 0xae, +		0xb9, 0xbc, 0x05, 0xf0, 0x81, 0x00, 0x61, 0x83, +		0x38, 0xda, 0x14, 0xf6, 0xea, 0xd8, 0x78, 0x65, +		0xc7, 0x26, 0x17, 0x03, 0x01, 0x00, 0x18, 0x81, +		0x30, 0x8b, 0x22, 0x5a, 0xd3, 0x7f, 0xc8, 0xf2, +		0x8a, 0x6b, 0xa3, 0xba, 0x4d, 0xe7, 0x6e, 0xd2, +		0xfd, 0xbf, 0xf2, 0xc5, 0x28, 0xa0, 0x62, 0x17, +		0x03, 0x01, 0x00, 0x28, 0x17, 0x83, 0x3c, 0x78, +		0x18, 0xfa, 0x8d, 0x58, 0x5c, 0xaa, 0x05, 0x7d, +		0x67, 0x96, 0x11, 0x60, 0x11, 0xc0, 0x1e, 0x0d, +		0x6a, 0x6e, 0x5f, 0x1d, 0x98, 0x4b, 0xff, 0x82, +		0xee, 0x21, 0x06, 0x29, 0xd3, 0x8b, 0x80, 0x78, +		0x39, 0x05, 0x34, 0x9b, 0x15, 0x03, 0x01, 0x00, +		0x18, 0xa9, 0x38, 0x18, 0x4f, 0x9d, 0x84, 0x75, +		0x88, 0x53, 0xd6, 0x85, 0xc2, 0x15, 0x4b, 0xe3, +		0xe3, 0x35, 0x9a, 0x74, 0xc9, 0x3e, 0x13, 0xc1, +		0x8c,  	},  }  var aesServerScript = [][]byte{  	{ -		0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00, -		0x7b, 0x03, 0x02, 0x4d, 0x08, 0x2d, 0x0b, 0xb3, -		0x57, 0x85, 0x71, 0x4b, 0xfb, 0x34, 0xab, 0x16, -		0xd4, 0x92, 0x50, 0x81, 0x16, 0x95, 0x11, 0x28, -		0x1a, 0xcb, 0xff, 0x09, 0x4d, 0x23, 0xa6, 0xfe, -		0x2e, 0xbb, 0x78, 0x00, 0x00, 0x34, 0x00, 0x33, -		0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, -		0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, -		0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, -		0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, -		0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, -		0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, -		0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09, -		0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, -		0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, -		0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff, -		0x01, 0x00, 0x01, 0x00, +		0x16, 0x03, 0x00, 0x00, 0xc5, 0x01, 0x00, 0x00, +		0xc1, 0x03, 0x03, 0x50, 0xae, 0x5c, 0xe9, 0x5e, +		0x31, 0x93, 0x82, 0xa5, 0x6f, 0x51, 0x82, 0xc8, +		0x55, 0x4f, 0x1f, 0x2e, 0x90, 0x98, 0x81, 0x13, +		0x27, 0x80, 0x68, 0xb4, 0x2d, 0xba, 0x3a, 0x76, +		0xd8, 0xd7, 0x2c, 0x00, 0x00, 0x50, 0xc0, 0x09, +		0xc0, 0x23, 0xc0, 0x2b, 0xc0, 0x0a, 0xc0, 0x24, +		0xc0, 0x2c, 0xc0, 0x08, 0xc0, 0x13, 0xc0, 0x27, +		0xc0, 0x2f, 0xc0, 0x14, 0xc0, 0x30, 0xc0, 0x12, +		0x00, 0x33, 0x00, 0x67, 0x00, 0x45, 0x00, 0x9e, +		0x00, 0x39, 0x00, 0x6b, 0x00, 0x88, 0x00, 0x16, +		0x00, 0x32, 0x00, 0x40, 0x00, 0x44, 0x00, 0xa2, +		0x00, 0x38, 0x00, 0x6a, 0x00, 0x87, 0x00, 0x13, +		0x00, 0x66, 0x00, 0x2f, 0x00, 0x3c, 0x00, 0x41, +		0x00, 0x9c, 0x00, 0x35, 0x00, 0x3d, 0x00, 0x84, +		0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x01, 0x00, +		0x00, 0x48, 0x00, 0x05, 0x00, 0x05, 0x01, 0x00, +		0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x01, 0x00, +		0x00, 0x23, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x0c, +		0x00, 0x0a, 0x00, 0x13, 0x00, 0x15, 0x00, 0x17, +		0x00, 0x18, 0x00, 0x19, 0x00, 0x0b, 0x00, 0x02, +		0x01, 0x00, 0x00, 0x0d, 0x00, 0x1c, 0x00, 0x1a, +		0x04, 0x01, 0x04, 0x02, 0x04, 0x03, 0x05, 0x01, +		0x05, 0x03, 0x06, 0x01, 0x06, 0x03, 0x03, 0x01, +		0x03, 0x02, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, +		0x02, 0x03,  	}, -  	{ -		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, -		0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00, +		0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -		0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x16, -		0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, -		0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, -		0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, -		0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, -		0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, -		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -		0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, +		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01, +		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02, +		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0, +		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01, +		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, +		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09, +		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, +		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, +		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, +		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, +		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, +		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, +		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, +		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, +		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, +		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, +		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, +		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, +		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33, +		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, +		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, +		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, +		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, +		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, +		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, +		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, +		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, +		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, +		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, +		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, +		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79, +		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10, +		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43, +		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85, +		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c, +		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5, +		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c, +		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56, +		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26, +		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21, +		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf, +		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07, +		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39, +		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3, +		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf, +		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb, +		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03, +		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, +		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, +		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85, +		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23, +		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39, +		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, +		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2, +		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, +		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, +		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31,  		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06,  		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11,  		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, @@ -680,136 +904,144 @@ var aesServerScript = [][]byte{  		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65,  		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64,  		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, -		0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, -		0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, -		0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, -		0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, -		0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, -		0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, -		0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, -		0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, -		0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, -		0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, -		0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, -		0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, -		0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, -		0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, -		0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -		0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, -		0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, -		0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, -		0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, -		0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, -		0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, -		0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, -		0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, -		0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, -		0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, -		0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, -		0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, -		0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, -		0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, -		0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, -		0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, -		0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, -		0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, -		0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, -		0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, -		0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, -		0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, -		0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, -		0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, -		0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, -		0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, -		0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, -		0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, -		0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, -		0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, -		0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, -		0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, -		0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, -		0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, -		0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, -		0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, -		0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, -		0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, -		0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, -		0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, -		0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -		0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, -		0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, -		0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, -		0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, -		0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, -		0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, -		0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, -		0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, -		0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, -		0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, -		0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, -		0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, -		0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, -		0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, -		0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, -		0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, -		0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, -		0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, -		0x00, 0x00, 0x00, +		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85, +		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, +		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, +		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, +		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, +		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, +		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59, +		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7, +		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95, +		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66, +		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3, +		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13, +		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba, +		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31, +		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50, +		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f, +		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96, +		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f, +		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b, +		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70, +		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e, +		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9, +		0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, +		0x00,  	}, -  	{  		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, -		0x82, 0x00, 0x80, 0x71, 0x9c, 0xe7, 0x23, 0xfc, -		0xb9, 0x19, 0x29, 0x82, 0xbf, 0xef, 0x08, 0xf7, -		0x99, 0x36, 0xc3, 0x4c, 0x6f, 0x05, 0xd2, 0x8b, -		0x62, 0x2b, 0x19, 0x9b, 0x7f, 0xc0, 0xcc, 0x48, -		0x30, 0x5f, 0xcd, 0xc3, 0x70, 0x55, 0x53, 0x73, -		0xfa, 0x79, 0x74, 0xf3, 0xa3, 0x76, 0x9f, 0xa1, -		0x7f, 0x98, 0xc2, 0xc0, 0xe3, 0xc5, 0xa0, 0x31, -		0x2f, 0xa6, 0xe8, 0x1e, 0x61, 0x46, 0xb3, 0x9b, -		0x4b, 0x16, 0xf1, 0x2d, 0xc7, 0x63, 0x7f, 0x79, -		0x22, 0x30, 0xd1, 0xf2, 0xfc, 0x77, 0x98, 0x0a, -		0x16, 0x11, 0x63, 0x71, 0x7f, 0x70, 0xef, 0x16, -		0xbb, 0x39, 0x87, 0x34, 0xac, 0x49, 0xbd, 0x07, -		0x67, 0xcb, 0x9c, 0xcc, 0xde, 0xef, 0xb1, 0xe0, -		0xdb, 0x01, 0xb5, 0x35, 0xa9, 0xb3, 0x10, 0x0c, -		0x4b, 0xee, 0xb3, 0x4e, 0xfd, 0xbe, 0x15, 0x27, -		0xf0, 0x46, 0xb2, 0x38, 0xba, 0x5f, 0xcc, 0x89, -		0xec, 0x29, 0x82, 0x14, 0x03, 0x01, 0x00, 0x01, -		0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x3c, 0xfb, -		0xa4, 0x12, 0xcb, 0x00, 0xf9, 0x57, 0x7e, 0x9b, -		0xc9, 0xdc, 0x0c, 0xba, 0x9a, 0x81, 0x62, 0xfb, -		0x26, 0x13, 0x53, 0xfe, 0xaa, 0xcc, 0x82, 0xbb, -		0xb6, 0x67, 0x7f, 0x39, 0xbe, 0x4d, 0xbb, 0xc0, -		0x6c, 0x24, 0x31, 0x83, 0xa5, 0x50, 0x3a, 0x75, -		0x32, 0x64, 0xb5, 0xdb, 0xbe, 0x0a, +		0x82, 0x00, 0x80, 0x51, 0x2e, 0xec, 0x0d, 0x86, +		0xf3, 0x9f, 0xf2, 0x77, 0x04, 0x27, 0x2b, 0x0e, +		0x9c, 0xab, 0x35, 0x84, 0x65, 0xff, 0x36, 0xef, +		0xc0, 0x08, 0xc9, 0x1d, 0x9f, 0x29, 0xae, 0x8d, +		0xc5, 0x66, 0x81, 0x31, 0x92, 0x5e, 0x3d, 0xac, +		0xaa, 0x37, 0x28, 0x2c, 0x06, 0x91, 0xa6, 0xc2, +		0xd0, 0x83, 0x34, 0x24, 0x1c, 0x88, 0xfc, 0x0a, +		0xcf, 0xbf, 0xc2, 0x94, 0xe2, 0xed, 0xa7, 0x6a, +		0xa8, 0x8d, 0x3d, 0xf7, 0x06, 0x7d, 0x69, 0xf8, +		0x0d, 0xb2, 0xf7, 0xe4, 0x45, 0xcb, 0x0a, 0x25, +		0xcb, 0xb2, 0x2e, 0x38, 0x9a, 0x84, 0x75, 0xe8, +		0xe1, 0x42, 0x39, 0xa2, 0x18, 0x0e, 0x48, 0xca, +		0x33, 0x16, 0x4e, 0xf6, 0x2f, 0xec, 0x07, 0xe7, +		0x57, 0xe1, 0x20, 0x40, 0x40, 0x6d, 0x4e, 0x29, +		0x04, 0x1a, 0x8c, 0x99, 0xfb, 0x19, 0x3c, 0xaa, +		0x75, 0x64, 0xd3, 0xa6, 0xe6, 0xed, 0x3f, 0x5a, +		0xd2, 0xc9, 0x80, 0x14, 0x03, 0x01, 0x00, 0x01, +		0x01, 0x16, 0x03, 0x01, 0x01, 0x10, 0xe9, 0x9e, +		0x06, 0x92, 0x18, 0xbf, 0x5e, 0xaf, 0x33, 0xc1, +		0xbf, 0x0e, 0x12, 0x07, 0x48, 0x4f, 0x6b, 0x6c, +		0xf5, 0x23, 0x5e, 0x87, 0xa7, 0xd3, 0x50, 0x79, +		0x38, 0xdc, 0xe0, 0x49, 0xd3, 0x81, 0x21, 0x12, +		0xd0, 0x3d, 0x9a, 0xfb, 0x83, 0xc1, 0x8b, 0xfc, +		0x14, 0xd5, 0xd5, 0xa7, 0xa3, 0x34, 0x14, 0x71, +		0xbe, 0xea, 0x37, 0x18, 0x12, 0x7f, 0x41, 0xfb, +		0xc5, 0x51, 0x17, 0x9d, 0x96, 0x58, 0x14, 0xfb, +		0x4f, 0xd7, 0xd3, 0x15, 0x0f, 0xec, 0x5a, 0x0d, +		0x35, 0xbb, 0x3c, 0x81, 0x5b, 0x3f, 0xdf, 0x52, +		0xa4, 0x4c, 0xcd, 0x13, 0xe1, 0x10, 0x37, 0x34, +		0xbf, 0xb4, 0x80, 0x1e, 0x8d, 0xe2, 0xc3, 0x7a, +		0x0f, 0x7b, 0x7d, 0x23, 0xeb, 0xd0, 0x99, 0x69, +		0xad, 0x0a, 0x2d, 0xb3, 0x6c, 0xd6, 0x80, 0x11, +		0x7f, 0x6c, 0xed, 0x1b, 0xcd, 0x08, 0x22, 0x56, +		0x90, 0x0e, 0xa4, 0xc3, 0x29, 0x33, 0x96, 0x30, +		0x34, 0x94, 0xa1, 0xeb, 0x9c, 0x1b, 0x5a, 0xd1, +		0x03, 0x61, 0xf9, 0xdd, 0xf3, 0x64, 0x8a, 0xfd, +		0x5f, 0x44, 0xdb, 0x2e, 0xa7, 0xfd, 0xe1, 0x1a, +		0x66, 0xc5, 0x01, 0x9c, 0xc7, 0xd1, 0xc4, 0xd3, +		0xea, 0x14, 0x3c, 0xed, 0x74, 0xbb, 0x1b, 0x97, +		0x8f, 0xf1, 0x29, 0x39, 0x33, 0x92, 0x93, 0x4e, +		0xf5, 0x87, 0x91, 0x61, 0x65, 0x8d, 0x27, 0x8d, +		0x76, 0xc1, 0xfa, 0x6a, 0x99, 0x80, 0xb1, 0x9b, +		0x29, 0x53, 0xce, 0x3e, 0xb6, 0x9a, 0xce, 0x3c, +		0x19, 0x5e, 0x48, 0x83, 0xaa, 0xa7, 0x66, 0x98, +		0x59, 0xf4, 0xbb, 0xf2, 0xbc, 0xd9, 0xc5, 0x9a, +		0xc8, 0x2c, 0x63, 0x58, 0xd5, 0xd4, 0xbc, 0x03, +		0xa9, 0x06, 0xa9, 0x80, 0x0d, 0xb3, 0x46, 0x2d, +		0xe3, 0xc6, 0xaf, 0x1a, 0x39, 0x18, 0x7e, 0x1e, +		0x83, 0x80, 0x46, 0x11, 0xd2, 0x13, 0x9f, 0xda, +		0xfc, 0x2d, 0x42, 0xaa, 0x5a, 0x1d, 0x4c, 0x31, +		0xe5, 0x58, 0x78, 0x5e, 0xe2, 0x04, 0xd6, 0x23, +		0x7f, 0x3f, 0x06, 0xc0, 0x54, 0xf8,  	}, -  	{ -		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, -		0x01, 0x00, 0x30, 0x43, 0x24, 0x42, 0x55, 0x08, -		0xe4, 0xc2, 0x15, 0xc9, 0xdb, 0x71, 0x69, 0xee, -		0x09, 0xc5, 0x1c, 0xfd, 0x46, 0x10, 0xa0, 0x68, -		0x21, 0xf2, 0x48, 0xac, 0x6c, 0xc0, 0x2b, 0x62, -		0x07, 0x8f, 0x48, 0x33, 0x0a, 0x6b, 0x62, 0x28, -		0x2e, 0x2c, 0xad, 0xcb, 0x34, 0x85, 0xca, 0x2e, -		0xcd, 0x84, 0xf0, +		0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00, +		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, +		0xe8, 0x4b, 0xfb, 0xef, 0xba, 0xed, 0xc5, 0x36, +		0xc8, 0x5a, 0x41, 0x3f, 0x05, 0xfa, 0xfe, 0x48, +		0xc3, 0x91, 0x12, 0x8b, 0xe8, 0x32, 0x6a, 0x9f, +		0xdc, 0x97, 0xe2, 0x77, 0xb9, 0x96, 0x2d, 0xd4, +		0xe5, 0xbd, 0xa1, 0xfd, 0x94, 0xbb, 0x74, 0x63, +		0xb1, 0x0c, 0x38, 0xbc, 0x6f, 0x69, 0xaf, 0xa3, +		0x46, 0x9c, 0x96, 0x41, 0xde, 0x59, 0x23, 0xff, +		0x15, 0x6b, 0x3a, 0xef, 0x91, 0x6d, 0x92, 0x44, +		0xdc, 0x72, 0x1f, 0x40, 0x3d, 0xb5, 0x34, 0x8f, +		0x2a, 0xac, 0x21, 0x69, 0x05, 0x6f, 0xb2, 0x60, +		0x32, 0x5d, 0x3d, 0x97, 0xb4, 0x24, 0x99, 0x14, +		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, +		0x00, 0x30, 0x68, 0x27, 0x97, 0xca, 0x63, 0x09, +		0x22, 0xed, 0x0e, 0x61, 0x7c, 0x76, 0x31, 0x9c, +		0xbe, 0x27, 0xc9, 0xe6, 0x09, 0xc3, 0xc3, 0xc2, +		0xf4, 0xa2, 0x32, 0xba, 0x7c, 0xf2, 0x0f, 0xb8, +		0x3d, 0xcb, 0xe2, 0x4c, 0xc0, 0x7d, 0x8e, 0x5b, +		0x5a, 0xed, 0x05, 0x5c, 0x15, 0x96, 0x69, 0xc2, +		0x6f, 0x5f, 0x17, 0x03, 0x01, 0x00, 0x20, 0x5a, +		0xfe, 0x0b, 0xe1, 0x6f, 0xa8, 0x54, 0x19, 0x78, +		0xca, 0xba, 0x2e, 0x1e, 0x2e, 0xe1, 0x5d, 0x17, +		0xe5, 0x97, 0x05, 0x2c, 0x08, 0x0c, 0xff, 0xa8, +		0x59, 0xa9, 0xde, 0x5e, 0x21, 0x34, 0x04, 0x17, +		0x03, 0x01, 0x00, 0x30, 0x86, 0xb1, 0x3f, 0x88, +		0x43, 0xf0, 0x07, 0xee, 0xa8, 0xf4, 0xbc, 0xe7, +		0x5f, 0xc6, 0x8c, 0x86, 0x4c, 0xca, 0x70, 0x88, +		0xcc, 0x6a, 0xb4, 0x3d, 0x40, 0xe8, 0x54, 0x89, +		0x19, 0x43, 0x1f, 0x76, 0xe2, 0xac, 0xb2, 0x5b, +		0x92, 0xf8, 0x57, 0x39, 0x2a, 0xc3, 0x6d, 0x13, +		0x45, 0xfa, 0x36, 0x9e, 0x15, 0x03, 0x01, 0x00, +		0x20, 0x6d, 0xed, 0x7b, 0x59, 0x28, 0x2a, 0x27, +		0x04, 0x15, 0x07, 0x4e, 0xeb, 0x13, 0x00, 0xe3, +		0x3a, 0x3f, 0xf8, 0xaa, 0x2b, 0x3b, 0x1a, 0x8c, +		0x12, 0xd6, 0x4c, 0xec, 0x2a, 0xaf, 0x33, 0x60, +		0xaf,  	},  }  var sslv3ServerScript = [][]byte{  	{ -		0x16, 0x03, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00, -		0x3d, 0x03, 0x00, 0x4e, 0x70, 0xe2, 0x18, 0x86, -		0xd6, 0xc6, 0x6f, 0xf3, 0xc8, 0xf4, 0x02, 0xd6, -		0x4d, 0xee, 0x17, 0x32, 0x4b, 0xd2, 0x78, 0xd8, -		0xa1, 0x03, 0x5d, 0x68, 0x82, 0x89, 0xbe, 0xfd, -		0x12, 0xb9, 0x06, 0x00, 0x00, 0x16, 0x00, 0x33, -		0x00, 0x39, 0x00, 0x16, 0x00, 0x32, 0x00, 0x38, -		0x00, 0x13, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, -		0x00, 0x05, 0x00, 0x04, 0x01, 0x00, +		0x16, 0x03, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, +		0x50, 0x03, 0x00, 0x50, 0x77, 0x3d, 0x42, 0xae, +		0x84, 0xbd, 0xc5, 0x07, 0xa5, 0xc4, 0xd6, 0x16, +		0x4e, 0xd5, 0xc5, 0xfa, 0x02, 0x7a, 0x0f, 0x1d, +		0xc1, 0xe1, 0xaa, 0xe3, 0x3b, 0x4b, 0x6f, 0x11, +		0xfa, 0x1a, 0xa4, 0x00, 0x00, 0x28, 0x00, 0x39, +		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13, +		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f, +		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12, +		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08, +		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01, +		0x00,  	}, -  	{  		0x16, 0x03, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00,  		0x26, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -908,74 +1140,71 @@ var sslv3ServerScript = [][]byte{  		0xbd, 0xd9, 0x16, 0x03, 0x00, 0x00, 0x04, 0x0e,  		0x00, 0x00, 0x00,  	}, -  	{  		0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00, -		0x80, 0x74, 0x0e, 0x3a, 0xcf, 0xba, 0x9f, 0x1a, -		0x9b, 0xb2, 0xa4, 0xc7, 0x5d, 0xf3, 0x0c, 0x80, -		0x06, 0x80, 0xf3, 0x57, 0xb2, 0xd9, 0x36, 0x24, -		0x6a, 0x06, 0x13, 0x40, 0xf9, 0x7c, 0xb9, 0x3e, -		0x4b, 0x68, 0x4f, 0x21, 0x90, 0x2d, 0xbd, 0xca, -		0xd4, 0x83, 0xf0, 0x7a, 0xeb, 0x7a, 0x74, 0x1b, -		0xcd, 0xfe, 0x69, 0xef, 0xc0, 0x86, 0xa0, 0x24, -		0x31, 0x65, 0x40, 0xd2, 0xdd, 0x6f, 0xb9, 0xd7, -		0x8d, 0xc1, 0x69, 0x60, 0x44, 0x7a, 0x75, 0xfb, -		0x42, 0x6a, 0x0f, 0x66, 0x45, 0x10, 0x73, 0xee, -		0x87, 0x28, 0x37, 0x83, 0x86, 0xd8, 0x5a, 0xc8, -		0x60, 0x87, 0xda, 0x33, 0x87, 0xaf, 0x34, 0x8b, -		0xf5, 0x61, 0x63, 0x7a, 0x5c, 0x60, 0x26, 0xb9, -		0xdb, 0xa1, 0xb7, 0xe3, 0x60, 0x38, 0x94, 0x5c, -		0x83, 0x23, 0xd6, 0x8d, 0xc2, 0x14, 0x4a, 0x0f, -		0x0e, 0x4f, 0xf9, 0x4e, 0x7b, 0x15, 0xcd, 0x18, -		0x04, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, -		0x03, 0x00, 0x00, 0x3c, 0xbd, 0xbc, 0xec, 0xdc, -		0x79, 0xb1, 0xae, 0x16, 0xc9, 0x26, 0x9a, 0xc0, -		0xc0, 0x2c, 0x33, 0x36, 0x13, 0x91, 0x58, 0x5d, -		0x7d, 0xee, 0x4e, 0xd8, 0x7e, 0xac, 0x88, 0x87, -		0x0a, 0x75, 0x66, 0xb1, 0x44, 0x79, 0x2f, 0x42, -		0xe8, 0x92, 0x74, 0x4c, 0xab, 0x36, 0xc8, 0x17, -		0x5f, 0x02, 0x8a, 0x20, 0x53, 0xe9, 0x1d, 0xb4, -		0xfe, 0x5c, 0x2b, 0xd9, 0x0a, 0xfb, 0xc6, 0x63, +		0x80, 0x4a, 0x8d, 0xc4, 0x38, 0x7a, 0x9c, 0xd6, +		0xe8, 0x72, 0x9e, 0xa3, 0xdf, 0x37, 0xb4, 0x6c, +		0x58, 0x33, 0x59, 0xd9, 0xc9, 0x4b, 0x50, 0x33, +		0x6c, 0xed, 0x73, 0x38, 0x2a, 0x46, 0x55, 0x31, +		0xa9, 0x8e, 0x8e, 0xfc, 0x0b, 0x5d, 0x5f, 0x3c, +		0x88, 0x28, 0x3f, 0x60, 0x51, 0x13, 0xf1, 0x59, +		0x0c, 0xa3, 0x5e, 0xe0, 0xa3, 0x35, 0x06, 0xb1, +		0x71, 0x59, 0x24, 0x4e, 0xed, 0x07, 0x15, 0x88, +		0x50, 0xef, 0xc2, 0xb2, 0x2a, 0x52, 0x30, 0x6a, +		0x7c, 0xbe, 0x2f, 0xc6, 0x8f, 0xa8, 0x83, 0xc5, +		0x80, 0x14, 0x62, 0x74, 0x7f, 0x96, 0x9f, 0x41, +		0x32, 0x74, 0xdd, 0x76, 0x2d, 0x7b, 0xeb, 0x7b, +		0xea, 0xd0, 0x4f, 0x0c, 0xcf, 0x9a, 0x9c, 0xc5, +		0x7a, 0xe4, 0xbc, 0xf8, 0xa6, 0xe1, 0x09, 0x8e, +		0x7c, 0x53, 0x3a, 0xe3, 0x30, 0x8f, 0x76, 0xee, +		0x58, 0xbb, 0xfd, 0x0b, 0x06, 0xb8, 0xdf, 0xb7, +		0x31, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, +		0x03, 0x00, 0x00, 0x3c, 0x13, 0x91, 0xc6, 0x4a, +		0x0c, 0x59, 0x25, 0xce, 0x54, 0xc0, 0x1d, 0xb9, +		0x2a, 0xff, 0x4d, 0xca, 0x26, 0x0c, 0x8c, 0x04, +		0x98, 0x7c, 0x7c, 0x38, 0xa3, 0xf5, 0xf9, 0x36, +		0x1c, 0x04, 0x32, 0x47, 0x2d, 0x48, 0x0e, 0x96, +		0xe8, 0x2b, 0x5e, 0x5a, 0xc6, 0x0a, 0x48, 0x41, +		0x34, 0x5e, 0x62, 0xd5, 0x68, 0x4e, 0x44, 0x1d, +		0xb2, 0xa1, 0x11, 0xad, 0x6e, 0x14, 0x85, 0x61,  	}, -  	{  		0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03, -		0x00, 0x00, 0x3c, 0xaa, 0xa1, 0x98, 0xc4, 0x6b, -		0x5a, 0x16, 0x3f, 0x5f, 0xa4, 0x96, 0x3e, 0x78, -		0xe4, 0x6f, 0x49, 0x05, 0x47, 0xc4, 0x05, 0x60, -		0xeb, 0x0b, 0x45, 0xe3, 0xbc, 0x50, 0x11, 0x24, -		0x5f, 0x01, 0xd7, 0xb8, 0x8f, 0x60, 0x63, 0x66, -		0xbd, 0x3e, 0xd9, 0xa8, 0x80, 0x43, 0x9f, 0x0b, -		0x51, 0x61, 0xed, 0x13, 0xc6, 0x21, 0xd0, 0xfe, -		0xbc, 0x17, 0x3c, 0x36, 0xb0, 0x82, 0x7f, 0x17, -		0x03, 0x00, 0x00, 0x21, 0xee, 0x44, 0xf3, 0xa6, -		0x88, 0x9d, 0x78, 0x44, 0xde, 0xdf, 0xeb, 0xc5, -		0xad, 0xc4, 0xcc, 0x56, 0x5c, 0x54, 0x96, 0x52, -		0x3f, 0xd9, 0x40, 0x6e, 0x79, 0xd8, 0x58, 0x78, -		0x4f, 0x5a, 0xe9, 0x06, 0xef, 0x15, 0x03, 0x00, -		0x00, 0x16, 0xd3, 0xc2, 0x52, 0x99, 0x2a, 0x84, -		0xc4, 0x52, 0x5f, 0x3b, 0x19, 0xe7, 0xfc, 0x65, -		0xaf, 0xd3, 0xb7, 0xa3, 0xcc, 0x4a, 0x1d, 0x2e, +		0x00, 0x00, 0x3c, 0x88, 0xae, 0xa9, 0xd4, 0xa8, +		0x10, 0x8d, 0x65, 0xa6, 0x3e, 0x1e, 0xed, 0xd2, +		0xfc, 0xc4, 0x7c, 0xa8, 0x94, 0x4f, 0x11, 0xaf, +		0xa6, 0x87, 0x09, 0x37, 0x54, 0xf7, 0x69, 0xd1, +		0xb5, 0x25, 0x6b, 0xb5, 0xed, 0xcb, 0x25, 0x39, +		0x73, 0xeb, 0x53, 0x6c, 0xc7, 0xb4, 0x29, 0x8f, +		0xd6, 0x49, 0xd1, 0x95, 0x59, 0x80, 0x9a, 0x67, +		0x5c, 0xb2, 0xe0, 0xbd, 0x1e, 0xff, 0xaa, 0x17, +		0x03, 0x00, 0x00, 0x21, 0x65, 0x7b, 0x99, 0x09, +		0x02, 0xc3, 0x9d, 0x54, 0xd6, 0xe7, 0x32, 0x62, +		0xab, 0xc1, 0x09, 0x91, 0x30, 0x0a, 0xc9, 0xfa, +		0x70, 0xec, 0x06, 0x7b, 0xa3, 0xe1, 0x5f, 0xb4, +		0x63, 0xe6, 0x5c, 0xba, 0x1f, 0x15, 0x03, 0x00, +		0x00, 0x16, 0x40, 0x70, 0xbe, 0xe6, 0xa6, 0xee, +		0x8f, 0xd0, 0x87, 0xa0, 0x43, 0xa1, 0x92, 0xd7, +		0xd0, 0x1a, 0x0c, 0x20, 0x7c, 0xbf, 0xa2, 0xb5,  	},  }  var selectCertificateBySNIScript = [][]byte{  	{ -		0x16, 0x03, 0x01, 0x00, 0x6e, 0x01, 0x00, 0x00, -		0x6a, 0x03, 0x01, 0x4f, 0x85, 0xc4, 0xc2, 0xb9, -		0x39, 0x80, 0x91, 0x66, 0x65, 0x56, 0x8e, 0xdd, -		0x48, 0xe9, 0xca, 0x34, 0x02, 0x3c, 0xaf, 0x0d, -		0x73, 0xb5, 0x2a, 0x05, 0x6e, 0xbd, 0x5e, 0x8f, -		0x38, 0xf9, 0xe5, 0x00, 0x00, 0x28, 0x00, 0x39, +		0x16, 0x03, 0x01, 0x00, 0x6a, 0x01, 0x00, 0x00, +		0x66, 0x03, 0x01, 0x50, 0x77, 0x3d, 0xfe, 0xfb, +		0x8d, 0xc2, 0x68, 0xeb, 0xf9, 0xfa, 0x54, 0x97, +		0x86, 0x45, 0xa2, 0xa3, 0xed, 0xb1, 0x91, 0xb8, +		0x28, 0xc0, 0x47, 0xaf, 0xfb, 0xcd, 0xdc, 0x0e, +		0xb3, 0xea, 0xa5, 0x00, 0x00, 0x28, 0x00, 0x39,  		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13,  		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f,  		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12,  		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08,  		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01, -		0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x10, 0x00, +		0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 0x10, 0x00,  		0x0e, 0x00, 0x00, 0x0b, 0x73, 0x6e, 0x69, 0x74, -		0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, -		0x23, 0x00, 0x00, +		0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d,  	},  	{  		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, @@ -1053,632 +1282,684 @@ var selectCertificateBySNIScript = [][]byte{  	},  	{  		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, -		0x82, 0x00, 0x80, 0x70, 0x1d, 0x34, 0x75, 0xa2, -		0xe7, 0xe3, 0x2f, 0x3d, 0xc1, 0x1d, 0xca, 0x0b, -		0xe3, 0x64, 0xb9, 0x1a, 0x00, 0x69, 0xc4, 0x14, -		0x05, 0x07, 0x7e, 0xc3, 0x51, 0x43, 0x52, 0x66, -		0xe3, 0xbd, 0xff, 0x1b, 0x1a, 0x6a, 0x84, 0xf2, -		0x07, 0x24, 0xd7, 0x12, 0xa8, 0x58, 0xcf, 0x8a, -		0x50, 0x30, 0xe8, 0xc8, 0xb2, 0xf9, 0x58, 0x1c, -		0x56, 0x53, 0x76, 0x21, 0xe0, 0x03, 0x7f, 0x77, -		0xa7, 0xf1, 0xad, 0x67, 0xd4, 0xe2, 0x8f, 0xa0, -		0x58, 0x6c, 0xe0, 0x28, 0x59, 0xf3, 0xd1, 0x53, -		0x2b, 0x21, 0xbd, 0xa3, 0x84, 0x31, 0x73, 0xbf, -		0x84, 0x0f, 0x83, 0xf4, 0xc4, 0xd0, 0xe5, 0x3c, -		0x2d, 0x3e, 0xf2, 0x8a, 0x1e, 0xe7, 0xe9, 0x1f, -		0x12, 0x13, 0xad, 0x29, 0xd6, 0x0c, 0xc7, 0xc6, -		0x05, 0x53, 0x7d, 0x5e, 0xc6, 0x92, 0x72, 0xba, -		0xd2, 0x93, 0x8f, 0x53, 0x84, 0x87, 0x44, 0x05, -		0x9f, 0x5d, 0x66, 0x14, 0x03, 0x01, 0x00, 0x01, -		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xfc, 0x71, -		0xaa, 0xa8, 0x37, 0xa8, 0xbd, 0x63, 0xb7, 0xbc, -		0x95, 0xef, 0x0c, 0xcf, 0x39, 0x31, 0x93, 0xe6, -		0x86, 0xbd, 0x3f, 0x56, 0x9d, 0xf0, 0xb2, 0xb5, -		0xd1, 0xa7, 0xc6, 0x45, 0x89, 0x18, 0xfb, 0xa0, -		0x7f, 0xc1, +		0x82, 0x00, 0x80, 0x69, 0xc3, 0xd4, 0x0e, 0xcc, +		0xdc, 0xbc, 0x5e, 0xc2, 0x64, 0xa6, 0xde, 0x3c, +		0x0c, 0x7e, 0x0c, 0x6b, 0x80, 0x0f, 0xd4, 0x8f, +		0x02, 0x4b, 0xb2, 0xba, 0x8d, 0x01, 0xeb, 0x6b, +		0xa1, 0x2e, 0x79, 0x37, 0xba, 0xae, 0x24, 0xc2, +		0x26, 0x72, 0x51, 0xe1, 0x82, 0x8e, 0x51, 0x41, +		0x1c, 0x54, 0xa4, 0x26, 0xbe, 0x13, 0xcd, 0x1b, +		0xc6, 0xed, 0x3d, 0x1f, 0xfd, 0x72, 0x80, 0x90, +		0xdb, 0xbf, 0xd6, 0x39, 0x94, 0x5f, 0x48, 0xfb, +		0x25, 0x5a, 0xc9, 0x60, 0x9b, 0xd7, 0xc6, 0x20, +		0xa8, 0x66, 0x64, 0x13, 0xf3, 0x65, 0xc8, 0xb1, +		0xd5, 0x33, 0x21, 0x0e, 0x73, 0x41, 0xc0, 0x18, +		0x1a, 0x37, 0xfe, 0xcf, 0x28, 0x2a, 0xcd, 0xe4, +		0x0b, 0xac, 0xdd, 0x25, 0x5e, 0xcb, 0x17, 0x51, +		0x69, 0xd5, 0x8c, 0xf4, 0xb6, 0x21, 0x98, 0xef, +		0x20, 0xdb, 0x14, 0x67, 0xf3, 0x7c, 0x95, 0x6a, +		0x48, 0x2a, 0x6a, 0x14, 0x03, 0x01, 0x00, 0x01, +		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0x36, 0x1b, +		0x09, 0xe5, 0xb9, 0xb9, 0x4d, 0x7d, 0xae, 0x87, +		0xb6, 0x0f, 0xaf, 0xec, 0x22, 0xba, 0x0d, 0xa5, +		0x96, 0x5e, 0x64, 0x65, 0xe7, 0xfb, 0xe3, 0xf3, +		0x6b, 0x72, 0xa8, 0xdb, 0xed, 0xd8, 0x69, 0x9c, +		0x08, 0xd8,  	},  	{  		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, -		0x01, 0x00, 0x24, 0xb8, 0x6d, 0x9a, 0x90, 0x3c, -		0x45, 0xe0, 0xff, 0x63, 0xba, 0xab, 0x3d, 0x7a, -		0xa6, 0x49, 0x5a, 0x13, 0xdc, 0x0e, 0xa3, 0xba, -		0x7f, 0x04, 0x19, 0x45, 0xfd, 0xfb, 0xbd, 0x00, -		0xa3, 0xa7, 0x78, 0x81, 0x38, 0x9f, 0x10, 0x17, -		0x03, 0x01, 0x00, 0x21, 0x43, 0xc3, 0x91, 0xb7, -		0xbf, 0x50, 0x0b, 0x04, 0xb4, 0x5d, 0xc6, 0x20, -		0x64, 0xb8, 0x01, 0x09, 0x25, 0x2c, 0x03, 0x30, -		0xc0, 0x77, 0xc9, 0x5e, 0xe6, 0xe0, 0x99, 0xdc, -		0xcd, 0x75, 0x9d, 0x51, 0x82, 0x15, 0x03, 0x01, -		0x00, 0x16, 0x2d, 0x7a, 0x89, 0x7b, 0x36, 0x85, -		0x2a, 0x93, 0xcb, 0x83, 0xa7, 0x2f, 0x9e, 0x91, -		0xfc, 0xad, 0x57, 0xca, 0xf5, 0xbc, 0x13, 0x2f, +		0x01, 0x00, 0x24, 0x60, 0xf7, 0x09, 0x5f, 0xd1, +		0xcb, 0xc9, 0xe1, 0x22, 0xb5, 0x2a, 0xcc, 0xde, +		0x7c, 0xa7, 0xb8, 0x85, 0x00, 0xbc, 0xfd, 0x85, +		0xe1, 0x91, 0x36, 0xbb, 0x07, 0x42, 0xad, 0x3d, +		0x29, 0x62, 0x69, 0xc1, 0x45, 0x92, 0x6f, 0x17, +		0x03, 0x01, 0x00, 0x21, 0x0d, 0xf9, 0xd5, 0x87, +		0xb9, 0x57, 0x3c, 0x50, 0x19, 0xe4, 0x3a, 0x50, +		0x45, 0xcc, 0x86, 0x89, 0xd4, 0x32, 0x79, 0x45, +		0x7c, 0x9f, 0x96, 0xd4, 0x54, 0x56, 0x0c, 0x63, +		0x72, 0x81, 0xc3, 0xd3, 0xe3, 0x15, 0x03, 0x01, +		0x00, 0x16, 0x84, 0xec, 0x2e, 0xf6, 0xaf, 0x4f, +		0xee, 0x48, 0x0f, 0xbe, 0xcd, 0x82, 0x5c, 0x56, +		0x16, 0xe4, 0xfb, 0x89, 0xc5, 0x57, 0x3e, 0x91,  	},  } -var clientauthTests = []clientauthTest{ -	// Server doesn't asks for cert -	// go test -run "TestRunServer" -serve -clientauth 0 -	// gnutls-cli --insecure --debug 100 -p 10443 localhost 2>&1 | -	//   python parse-gnutls-cli-debug-log.py -	{"NoClientCert", NoClientCert, nil, -		[][]byte{{ -			0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00, -			0x76, 0x03, 0x02, 0x4e, 0xe0, 0x92, 0x5d, 0xcd, -			0xfe, 0x0c, 0x69, 0xd4, 0x7d, 0x8e, 0xa6, 0x88, -			0xde, 0x72, 0x04, 0x29, 0x6a, 0x4a, 0x16, 0x23, -			0xd7, 0x8f, 0xbc, 0xfa, 0x80, 0x73, 0x2e, 0x12, -			0xb7, 0x0b, 0x39, 0x00, 0x00, 0x34, 0x00, 0x33, -			0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, -			0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, -			0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, -			0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, -			0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, -			0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, -			0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09, -			0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, -			0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, -			0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, -		}, +var issueSessionTicketTest = [][]byte{ +	{ +		0x16, 0x03, 0x01, 0x00, 0x5a, 0x01, 0x00, 0x00, +		0x56, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x49, 0x7a, +		0xb7, 0x86, 0x5c, 0x27, 0xd2, 0x97, 0x61, 0xe3, +		0x49, 0x41, 0x48, 0xe7, 0x0e, 0xaa, 0x7e, 0x4d, +		0xb8, 0xdc, 0x01, 0x97, 0xfb, 0xab, 0x53, 0xb2, +		0x5e, 0x36, 0xf6, 0x00, 0x00, 0x28, 0x00, 0x39, +		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13, +		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f, +		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12, +		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08, +		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01, +		0x00, 0x00, 0x04, 0x00, 0x23, 0x00, 0x00, +	}, +	{ +		0x16, 0x03, 0x01, 0x00, 0x30, 0x02, 0x00, 0x00, +		0x2c, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, +		0x04, 0x00, 0x23, 0x00, 0x00, 0x16, 0x03, 0x01, +		0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, 0x00, 0x02, +		0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, 0x02, 0xb0, +		0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, 0x02, 0x01, +		0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, 0xbb, 0xa4, +		0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, 0x06, 0x09, +		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +		0x05, 0x05, 0x00, 0x30, 0x45, 0x31, 0x0b, 0x30, +		0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, +		0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, +		0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, +		0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, +		0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, +		0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, +		0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, +		0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, +		0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, +		0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, +		0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, 0x31, 0x30, +		0x34, 0x32, 0x34, 0x30, 0x39, 0x30, 0x39, 0x33, +		0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, 0x30, 0x09, +		0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, +		0x55, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, +		0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, 0x6d, 0x65, +		0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, 0x31, 0x21, +		0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, +		0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x65, +		0x74, 0x20, 0x57, 0x69, 0x64, 0x67, 0x69, 0x74, +		0x73, 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, +		0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, +		0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +		0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, +		0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xbb, 0x79, +		0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, 0x46, 0x10, +		0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, 0x07, 0x43, +		0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, 0x43, 0x85, +		0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, 0x4c, 0x2c, +		0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, 0x82, 0xe5, +		0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, 0xa5, 0x2c, +		0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, 0x7a, 0x56, +		0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, 0x7b, 0x26, +		0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, 0xc9, 0x21, +		0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, 0x5a, 0xbf, +		0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, 0x99, 0x07, +		0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, 0x04, 0x39, +		0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, 0x7c, 0xe3, +		0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, 0xcf, 0xaf, +		0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, 0xdb, 0xdb, +		0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, 0x02, 0x03, +		0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, 0x30, 0x81, +		0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, +		0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, 0xe2, 0x85, +		0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, 0x23, +		0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, 0x39, +		0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, +		0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, 0xad, 0xe2, +		0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, 0xce, +		0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, 0x88, +		0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, 0x45, 0x31, +		0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, +		0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, +		0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, +		0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, +		0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, +		0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, +		0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, +		0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, +		0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, 0x00, 0x85, +		0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, +		0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x04, 0x05, +		0x30, 0x03, 0x01, 0x01, 0xff, 0x30, 0x0d, 0x06, +		0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, +		0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, +		0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, 0xb1, 0x59, +		0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, 0x14, 0xd7, +		0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, 0x5a, 0x95, +		0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, 0x12, 0x66, +		0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, 0x60, 0xd3, +		0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, 0x25, 0x13, +		0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, 0x1d, 0xba, +		0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, 0xd7, 0x31, +		0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, 0xea, 0x50, +		0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, 0x5a, 0x5f, +		0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, 0x90, 0x96, +		0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, 0x98, 0x1f, +		0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, 0xa3, 0x1b, +		0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, 0xe9, 0x70, +		0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, 0x26, 0x6e, +		0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, 0xbd, 0xd9, +		0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, +		0x00, +	}, +	{ +		0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, +		0x82, 0x00, 0x80, 0x68, 0x10, 0xdc, 0x80, 0xbc, +		0xb3, 0x5a, 0x10, 0x75, 0x89, 0xcc, 0xe5, 0x9f, +		0xbf, 0xe2, 0xce, 0xa4, 0x9f, 0x7f, 0x60, 0xc4, +		0xfe, 0x5c, 0xb5, 0x02, 0x2d, 0xa5, 0xa9, 0x1e, +		0x2c, 0x10, 0x79, 0x15, 0x0f, 0xed, 0x96, 0xb3, +		0xa8, 0x5e, 0x21, 0xbc, 0x5b, 0xdc, 0x58, 0x04, +		0x7d, 0x37, 0xdb, 0xa0, 0x31, 0xe8, 0x4f, 0x04, +		0xbc, 0x46, 0x7c, 0xdb, 0x2e, 0x93, 0x07, 0xaf, +		0xa6, 0x36, 0xd3, 0x39, 0x8d, 0x1d, 0x95, 0xa8, +		0x50, 0x4b, 0xc4, 0x2b, 0xde, 0xd7, 0x04, 0x6d, +		0x77, 0x6c, 0x4d, 0x70, 0x51, 0x88, 0x16, 0x31, +		0x40, 0xb5, 0xba, 0x90, 0x47, 0x64, 0x0c, 0x87, +		0xa5, 0x19, 0xf9, 0x89, 0x24, 0x3c, 0x5e, 0x4b, +		0xaa, 0xe0, 0x60, 0x47, 0x0f, 0x2e, 0xcc, 0xc2, +		0xd5, 0x21, 0xed, 0x72, 0xd0, 0xa9, 0xdd, 0x2a, +		0x2b, 0xef, 0x08, 0x3a, 0x65, 0xea, 0x8b, 0x52, +		0x77, 0x2d, 0xcc, 0x14, 0x03, 0x01, 0x00, 0x01, +		0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xe2, 0x95, +		0x62, 0x3c, 0x18, 0xe5, 0xc7, 0x2c, 0xda, 0x16, +		0x9b, 0x28, 0x0d, 0xf7, 0x88, 0x7b, 0x5d, 0x33, +		0x55, 0x3b, 0x01, 0x73, 0xf2, 0xc6, 0x4e, 0x96, +		0x01, 0x01, 0x83, 0x65, 0xd4, 0xef, 0x12, 0x13, +		0x1d, 0x42, +	}, +	{ +		0x16, 0x03, 0x01, 0x00, 0x72, 0x04, 0x00, 0x00, +		0x6e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, +		0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92, +		0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01, +		0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e, +		0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97, +		0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e, +		0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9, +		0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c, +		0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a, +		0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f, +		0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4, +		0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35, 0x14, +		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, +		0x00, 0x24, 0x3f, 0x66, 0xe4, 0x98, 0xc1, 0x3f, +		0xc6, 0x2c, 0x81, 0xfb, 0xa9, 0x9f, 0x27, 0xe9, +		0x63, 0x20, 0x1e, 0x0e, 0x4f, 0xfc, 0x5d, 0x12, +		0xee, 0x77, 0x73, 0xc6, 0x96, 0x51, 0xf2, 0x26, +		0x35, 0x3f, 0xce, 0x6a, 0xa9, 0xfd, 0x17, 0x03, +		0x01, 0x00, 0x21, 0x8d, 0xd5, 0x67, 0x60, 0x5d, +		0xa7, 0x93, 0xcc, 0x39, 0x78, 0x59, 0xab, 0xdb, +		0x10, 0x96, 0xf2, 0xad, 0xa2, 0x85, 0xe2, 0x93, +		0x43, 0x43, 0xcf, 0x82, 0xbd, 0x1f, 0xdc, 0x7a, +		0x72, 0xd6, 0x83, 0x3b, 0x15, 0x03, 0x01, 0x00, +		0x16, 0x89, 0x55, 0xf6, 0x42, 0x71, 0xa9, 0xe9, +		0x05, 0x68, 0xe8, 0xce, 0x0d, 0x21, 0xe9, 0xec, +		0xf2, 0x27, 0x67, 0xa7, 0x94, 0xf8, 0x34, +	}, +} +var serverResumeTest = [][]byte{ +	{ +		0x16, 0x03, 0x01, 0x00, 0xc2, 0x01, 0x00, 0x00, +		0xbe, 0x03, 0x01, 0x50, 0x77, 0x3e, 0x4f, 0x1f, +		0x6f, 0xa5, 0x81, 0xeb, 0xb8, 0x80, 0x55, 0xa4, +		0x76, 0xc2, 0x7f, 0x27, 0xf2, 0xe7, 0xc9, 0x7a, +		0x01, 0x3c, 0xd8, 0xc1, 0xde, 0x99, 0x1f, 0x7c, +		0xab, 0x35, 0x98, 0x00, 0x00, 0x28, 0x00, 0x39, +		0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13, +		0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f, +		0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12, +		0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08, +		0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01, +		0x00, 0x00, 0x6c, 0x00, 0x23, 0x00, 0x68, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, +		0xe8, 0x4b, 0xd1, 0xef, 0xba, 0xfb, 0x41, 0x92, +		0x6d, 0x37, 0x5f, 0xf8, 0x7d, 0x90, 0x0f, 0x01, +		0xf8, 0x8c, 0xee, 0xbc, 0xd9, 0x0c, 0x97, 0x7e, +		0x23, 0x46, 0xe2, 0x6b, 0x52, 0xc6, 0xc6, 0x97, +		0x1d, 0xab, 0xde, 0xa0, 0x86, 0x94, 0xc8, 0x2e, +		0x8b, 0x2e, 0x42, 0x5f, 0xc2, 0x70, 0x35, 0xc9, +		0xee, 0x37, 0xeb, 0x70, 0xaa, 0x59, 0x23, 0x6c, +		0xc8, 0xc1, 0x84, 0x89, 0x39, 0x87, 0x73, 0x0a, +		0x7e, 0xba, 0xca, 0xed, 0x63, 0xba, 0x4e, 0x4f, +		0xf3, 0x31, 0x4b, 0xf0, 0xee, 0x91, 0xa5, 0xb4, +		0x62, 0x01, 0x9e, 0xbd, 0xbc, 0xb3, 0x35, +	}, +	{ +		0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, +		0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +		0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x14, +		0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, +		0x00, 0x24, 0xc5, 0x35, 0x74, 0x19, 0x05, 0xc5, +		0x85, 0x68, 0x48, 0xe8, 0xb5, 0xe9, 0xaf, 0x78, +		0xbd, 0x35, 0x6f, 0xe9, 0x79, 0x34, 0x1b, 0xf0, +		0x35, 0xd4, 0x4e, 0x55, 0x2e, 0x3c, 0xd5, 0xaf, +		0xfc, 0xba, 0xf5, 0x1e, 0x83, 0x32, +	}, +	{ +		0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, +		0x01, 0x00, 0x24, 0x27, 0x28, 0x88, 0xe1, 0x7e, +		0x0d, 0x9c, 0x12, 0x50, 0xf6, 0x7a, 0xa7, 0x32, +		0x21, 0x68, 0xba, 0xd8, 0x0a, 0xdc, 0x39, 0xef, +		0x68, 0x95, 0x82, 0xae, 0xbd, 0x12, 0x79, 0xa1, +		0x99, 0xfd, 0xd0, 0x10, 0x8e, 0x4b, 0xd8, +	}, +	{ +		0x17, 0x03, 0x01, 0x00, 0x21, 0xc5, 0x7e, 0x0a, +		0x52, 0x6a, 0xb9, 0xaa, 0x1d, 0xae, 0x9e, 0x24, +		0x9c, 0x34, 0x1e, 0xdb, 0x50, 0x95, 0xee, 0x76, +		0xd7, 0x28, 0x88, 0x08, 0xe3, 0x2e, 0x58, 0xf7, +		0xdb, 0x34, 0x75, 0xa5, 0x7f, 0x9d, 0x15, 0x03, +		0x01, 0x00, 0x16, 0x2c, 0xc1, 0x29, 0x5f, 0x12, +		0x1d, 0x19, 0xab, 0xb3, 0xf4, 0x35, 0x1c, 0x62, +		0x6a, 0x80, 0x29, 0x0d, 0x0e, 0xef, 0x7d, 0x6e, +		0x50, +	}, +} -			{ -				0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, -				0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, -				0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, -				0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, -				0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, -				0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, -				0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, -				0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -				0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, -				0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, -				0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, -				0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, -				0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, -				0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, -				0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, -				0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, -				0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, -				0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, -				0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, -				0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, -				0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, -				0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, -				0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, -				0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, -				0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, -				0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, -				0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, -				0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, -				0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, -				0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, -				0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, -				0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -				0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, -				0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, -				0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, -				0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, -				0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, -				0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, -				0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, -				0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, -				0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, -				0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, -				0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, -				0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, -				0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, -				0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, -				0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, -				0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, -				0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, -				0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, -				0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, -				0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, -				0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, -				0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, -				0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, -				0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, -				0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, -				0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, -				0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, -				0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, -				0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, -				0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, -				0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, -				0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, -				0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, -				0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, -				0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, -				0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, -				0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, -				0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, -				0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, -				0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, -				0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -				0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, -				0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, -				0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, -				0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, -				0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, -				0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, -				0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, -				0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, -				0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, -				0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, -				0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, -				0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, -				0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, -				0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, -				0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, -				0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, -				0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, -				0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, -				0x00, 0x00, 0x00, -			}, - -			{ -				0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, -				0x82, 0x00, 0x80, 0x10, 0xe1, 0x00, 0x3d, 0x0a, -				0x6b, 0x02, 0x7f, 0x97, 0xde, 0xfb, 0x65, 0x46, -				0x1a, 0x50, 0x4e, 0x34, 0x9a, 0xae, 0x14, 0x7e, -				0xec, 0xef, 0x85, 0x15, 0x3b, 0x39, 0xc2, 0x45, -				0x04, 0x40, 0x92, 0x71, 0xd6, 0x7e, 0xf6, 0xfd, -				0x4d, 0x84, 0xf7, 0xc4, 0x77, 0x99, 0x3d, 0xe2, -				0xc3, 0x8d, 0xb0, 0x4c, 0x74, 0xc8, 0x51, 0xec, -				0xb2, 0xe8, 0x6b, 0xa1, 0xd2, 0x4d, 0xd8, 0x61, -				0x92, 0x7a, 0x24, 0x57, 0x44, 0x4f, 0xa2, 0x1e, -				0x74, 0x0b, 0x06, 0x4b, 0x80, 0x34, 0x8b, 0xfe, -				0xc2, 0x0e, 0xc1, 0xcd, 0xab, 0x0c, 0x3f, 0x54, -				0xe2, 0x44, 0xe9, 0x6c, 0x2b, 0xba, 0x7b, 0x64, -				0xf1, 0x93, 0x65, 0x75, 0xf2, 0x35, 0xff, 0x27, -				0x03, 0xd5, 0x64, 0xe6, 0x8e, 0xe7, 0x7b, 0x56, -				0xb6, 0x61, 0x73, 0xeb, 0xa2, 0xdc, 0xa4, 0x6e, -				0x52, 0xac, 0xbc, 0xba, 0x11, 0xa3, 0xd2, 0x61, -				0x4a, 0xe0, 0xbb, 0x14, 0x03, 0x01, 0x00, 0x01, -				0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xd2, 0x5a, -				0x0c, 0x2a, 0x27, 0x96, 0xba, 0xa9, 0x67, 0xd2, -				0x51, 0x68, 0x32, 0x68, 0x22, 0x1f, 0xb9, 0x27, -				0x79, 0x59, 0x28, 0xdf, 0x38, 0x1f, 0x92, 0x21, -				0x5d, 0x0f, 0xf4, 0xc0, 0xee, 0xb7, 0x10, 0x5a, -				0xa9, 0x45, -			}, - -			{ -				0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, -				0x01, 0x00, 0x24, 0x13, 0x6f, 0x6c, 0x71, 0x83, -				0x59, 0xcf, 0x32, 0x72, 0xe9, 0xce, 0xcc, 0x7a, -				0x6c, 0xf0, 0x72, 0x39, 0x16, 0xae, 0x40, 0x61, -				0xfa, 0x92, 0x4c, 0xe7, 0xf2, 0x1a, 0xd7, 0x0c, -				0x84, 0x76, 0x6c, 0xe9, 0x11, 0x43, 0x19, 0x17, -				0x03, 0x01, 0x00, 0x21, 0xc0, 0xa2, 0x13, 0x28, -				0x94, 0x8c, 0x5c, 0xd6, 0x79, 0xb9, 0xfe, 0xae, -				0x45, 0x4b, 0xc0, 0x7c, 0xae, 0x2d, 0xb4, 0x0d, -				0x31, 0xc4, 0xad, 0x22, 0xd7, 0x1e, 0x99, 0x1c, -				0x4c, 0x69, 0xab, 0x42, 0x61, 0x15, 0x03, 0x01, -				0x00, 0x16, 0xe1, 0x0c, 0x67, 0xf3, 0xf4, 0xb9, -				0x8e, 0x81, 0x8e, 0x01, 0xb8, 0xa0, 0x69, 0x8c, -				0x03, 0x11, 0x43, 0x3e, 0xee, 0xb7, 0x4d, 0x69, -			}}}, +var clientauthTests = []clientauthTest{  	// Server asks for cert with empty CA list, client doesn't give it.  	// go test -run "TestRunServer" -serve -clientauth 1 -	// gnutls-cli --insecure --debug 100 -p 10443 localhost -	{"RequestClientCert, none given", RequestClientCert, nil, -		[][]byte{{ -			0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00, -			0x76, 0x03, 0x02, 0x4e, 0xe0, 0x93, 0xe2, 0x47, -			0x06, 0xa0, 0x61, 0x0c, 0x51, 0xdd, 0xf0, 0xef, -			0xf4, 0x30, 0x72, 0xe1, 0xa6, 0x50, 0x68, 0x82, -			0x3c, 0xfb, 0xcb, 0x72, 0x5e, 0x73, 0x9d, 0xda, -			0x27, 0x35, 0x72, 0x00, 0x00, 0x34, 0x00, 0x33, -			0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, -			0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, -			0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, -			0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, -			0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, -			0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, -			0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09, -			0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, -			0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, -			0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, +	{"RequestClientCert, none given", RequestClientCert, nil, [][]byte{ +		{ +			0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00, +			0x50, 0x03, 0x01, 0x50, 0x77, 0x43, 0x9e, 0x31, +			0xe6, 0x36, 0x5e, 0x5e, 0x24, 0xe4, 0x0d, 0x26, +			0x34, 0xa7, 0x1c, 0x2e, 0x59, 0x6d, 0xa5, 0x3e, +			0x72, 0xf3, 0xa3, 0x1c, 0xbc, 0xb3, 0x27, 0xaf, +			0x92, 0x5b, 0x7d, 0x00, 0x00, 0x28, 0x00, 0x39, +			0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13, +			0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f, +			0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12, +			0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08, +			0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01, +			0x00,  		}, - -			{ -				0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, -				0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, -				0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, -				0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, -				0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, -				0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, -				0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, -				0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -				0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, -				0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, -				0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, -				0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, -				0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, -				0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, -				0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, -				0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, -				0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, -				0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, -				0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, -				0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, -				0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, -				0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, -				0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, -				0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, -				0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, -				0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, -				0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, -				0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, -				0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, -				0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, -				0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, -				0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -				0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, -				0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, -				0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, -				0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, -				0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, -				0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, -				0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, -				0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, -				0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, -				0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, -				0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, -				0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, -				0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, -				0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, -				0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, -				0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, -				0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, -				0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, -				0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, -				0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, -				0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, -				0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, -				0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, -				0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, -				0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, -				0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, -				0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, -				0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, -				0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, -				0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, -				0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, -				0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, -				0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, -				0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, -				0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, -				0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, -				0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, -				0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, -				0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, -				0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, -				0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -				0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, -				0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, -				0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, -				0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, -				0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, -				0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, -				0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, -				0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, -				0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, -				0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, -				0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, -				0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, -				0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, -				0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, -				0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, -				0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, -				0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, -				0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x08, 0x0d, -				0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00, 0x16, -				0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00, -			}, - -			{ -				0x16, 0x03, 0x01, 0x00, 0x07, 0x0b, 0x00, 0x00, -				0x03, 0x00, 0x00, 0x00, 0x16, 0x03, 0x01, 0x00, -				0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x64, -				0x28, 0xb9, 0x3f, 0x48, 0xaf, 0x06, 0x22, 0x39, -				0x56, 0xd8, 0x6f, 0x63, 0x5d, 0x03, 0x48, 0x63, -				0x01, 0x13, 0xa2, 0xd6, 0x76, 0xc0, 0xab, 0xda, -				0x25, 0x30, 0x75, 0x6c, 0xaa, 0xb4, 0xdc, 0x35, -				0x72, 0xdc, 0xf2, 0x43, 0xe4, 0x1d, 0x82, 0xfb, -				0x6c, 0x64, 0xe2, 0xa7, 0x8f, 0x32, 0x67, 0x6b, -				0xcd, 0xd2, 0xb2, 0x36, 0x94, 0xbc, 0x6f, 0x46, -				0x79, 0x29, 0x42, 0xe3, 0x1a, 0xbf, 0xfb, 0x41, -				0xd5, 0xe3, 0xb4, 0x2a, 0xf6, 0x95, 0x6f, 0x0c, -				0x87, 0xb9, 0x03, 0x18, 0xa1, 0xea, 0x4a, 0xe2, -				0x2e, 0x0f, 0x50, 0x00, 0xc1, 0xe8, 0x8c, 0xc8, -				0xa2, 0xf6, 0xa4, 0x05, 0xf4, 0x38, 0x3e, 0xd9, -				0x6e, 0x63, 0x96, 0x0c, 0x34, 0x73, 0x90, 0x03, -				0x55, 0xa6, 0x34, 0xb0, 0x5e, 0x8c, 0x48, 0x40, -				0x25, 0x45, 0x84, 0xa6, 0x21, 0x3f, 0x81, 0x97, -				0xa7, 0x11, 0x09, 0x14, 0x95, 0xa5, 0xe5, 0x14, -				0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, -				0x00, 0x24, 0x16, 0xaa, 0x01, 0x2c, 0xa8, 0xc1, -				0x28, 0xaf, 0x35, 0xc1, 0xc1, 0xf3, 0x0a, 0x25, -				0x66, 0x6e, 0x27, 0x11, 0xa3, 0xa4, 0xd9, 0xe9, -				0xea, 0x15, 0x09, 0x9d, 0x28, 0xe3, 0x5b, 0x2b, -				0xa6, 0x25, 0xa7, 0x14, 0x24, 0x3a, -			}, - -			{ -				0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, -				0x01, 0x00, 0x24, 0x9a, 0xa8, 0xd6, 0x77, 0x46, -				0x45, 0x68, 0x9d, 0x5d, 0xa9, 0x68, 0x03, 0xe5, -				0xaf, 0xe8, 0xc8, 0x21, 0xc5, 0xc6, 0xc1, 0x50, -				0xe0, 0xd8, 0x52, 0xce, 0xa3, 0x4f, 0x2d, 0xf4, -				0xe3, 0xa7, 0x7d, 0x35, 0x80, 0x84, 0x12, 0x17, -				0x03, 0x01, 0x00, 0x21, 0x8a, 0x82, 0x0c, 0x54, -				0x1b, 0xeb, 0x77, 0x90, 0x2c, 0x3e, 0xbc, 0xf0, -				0x23, 0xcc, 0xa8, 0x9f, 0x25, 0x08, 0x12, 0xed, -				0x43, 0xf1, 0xf9, 0x06, 0xad, 0xa9, 0x4b, 0x97, -				0x82, 0xb7, 0xc4, 0x0b, 0x4c, 0x15, 0x03, 0x01, -				0x00, 0x16, 0x05, 0x2d, 0x9d, 0x45, 0x03, 0xb7, -				0xc2, 0xd1, 0xb5, 0x1a, 0x43, 0xcf, 0x1a, 0x37, -				0xf4, 0x70, 0xcc, 0xb4, 0xed, 0x07, 0x76, 0x3a, -			}}}, +		{ +			0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, +			0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, +			0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, +			0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, +			0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, +			0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, +			0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, +			0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, +			0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, +			0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, +			0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, +			0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, +			0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, +			0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, +			0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, +			0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, +			0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, +			0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, +			0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, +			0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, +			0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, +			0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, +			0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, +			0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, +			0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, +			0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, +			0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, +			0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, +			0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, +			0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, +			0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, +			0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, +			0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, +			0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, +			0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, +			0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, +			0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, +			0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, +			0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, +			0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, +			0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, +			0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, +			0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, +			0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, +			0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, +			0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, +			0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, +			0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, +			0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, +			0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, +			0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, +			0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, +			0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, +			0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, +			0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, +			0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, +			0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, +			0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, +			0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, +			0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, +			0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, +			0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, +			0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, +			0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, +			0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, +			0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, +			0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, +			0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, +			0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, +			0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, +			0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, +			0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, +			0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, +			0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, +			0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, +			0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, +			0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, +			0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, +			0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, +			0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, +			0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, +			0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, +			0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, +			0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, +			0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, +			0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, +			0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, +			0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, +			0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, +			0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, +			0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x08, 0x0d, +			0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00, 0x16, +			0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00, +		}, +		{ +			0x16, 0x03, 0x01, 0x00, 0x07, 0x0b, 0x00, 0x00, +			0x03, 0x00, 0x00, 0x00, 0x16, 0x03, 0x01, 0x00, +			0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x04, +			0x58, 0x63, 0x26, 0x32, 0x1b, 0x34, 0xbe, 0x10, +			0xe4, 0xe4, 0x3e, 0xcd, 0x36, 0x7f, 0xa8, 0xa8, +			0xe0, 0x19, 0xe8, 0x94, 0x13, 0xd9, 0x35, 0xc4, +			0x71, 0xb4, 0x91, 0xd4, 0xbc, 0x74, 0x57, 0x9f, +			0x93, 0xb7, 0x5d, 0x3b, 0x9c, 0xff, 0x5d, 0x79, +			0xdb, 0x86, 0xfc, 0xdc, 0x74, 0x1e, 0x0c, 0xc6, +			0xe8, 0x93, 0xcf, 0xaf, 0xba, 0x1d, 0xfd, 0x8a, +			0xeb, 0xef, 0xbf, 0xfa, 0xa6, 0xe7, 0x53, 0x98, +			0x60, 0x4e, 0x0e, 0x60, 0x7d, 0xea, 0x40, 0x8d, +			0x1d, 0x8f, 0xa3, 0xc6, 0x83, 0xbc, 0xef, 0xb7, +			0x9a, 0x4a, 0xe7, 0x99, 0xee, 0x0b, 0xc7, 0x46, +			0x75, 0x45, 0x66, 0xe8, 0x5f, 0x4b, 0x08, 0xa4, +			0xc1, 0x36, 0xd0, 0x36, 0x2c, 0xf2, 0x9a, 0x44, +			0x1e, 0x5f, 0x22, 0xf4, 0xbe, 0x66, 0x66, 0x17, +			0xd8, 0xb6, 0x0a, 0x89, 0xed, 0x22, 0x80, 0xdb, +			0xad, 0x05, 0xd1, 0xb5, 0x93, 0xa1, 0x1c, 0x14, +			0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, +			0x00, 0x24, 0x62, 0x6f, 0x3d, 0x30, 0x56, 0x97, +			0xde, 0x03, 0x67, 0xa9, 0x63, 0x21, 0xb6, 0xe6, +			0x05, 0x69, 0x94, 0xfb, 0x50, 0xc1, 0x99, 0xdd, +			0xf6, 0xe8, 0x60, 0xbd, 0xe6, 0xba, 0xe3, 0x50, +			0x0a, 0xcd, 0xde, 0x14, 0x16, 0xc4, +		}, +		{ +			0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, +			0x01, 0x00, 0x24, 0xf0, 0x21, 0xf6, 0x84, 0x6a, +			0xe3, 0x6b, 0x8a, 0xc5, 0x46, 0x50, 0xca, 0x40, +			0xea, 0x4e, 0x82, 0xc1, 0x70, 0x25, 0xd8, 0x7d, +			0x60, 0xf5, 0x51, 0x7f, 0x64, 0x03, 0x9f, 0x53, +			0xec, 0xfb, 0x57, 0xa9, 0xfc, 0x26, 0x15, 0x17, +			0x03, 0x01, 0x00, 0x21, 0xa6, 0xc6, 0x94, 0x2b, +			0xa9, 0xcb, 0x93, 0xff, 0xb6, 0xa6, 0xe7, 0xc5, +			0x37, 0x86, 0x15, 0x37, 0x57, 0xce, 0xef, 0x54, +			0x96, 0x5d, 0x50, 0xa0, 0x50, 0x69, 0x5e, 0x82, +			0x61, 0x8d, 0x42, 0xfb, 0x78, 0x15, 0x03, 0x01, +			0x00, 0x16, 0x45, 0xd1, 0x86, 0x68, 0x59, 0xc1, +			0xaf, 0xac, 0x5c, 0x46, 0x8a, 0x68, 0x69, 0x0c, +			0xd7, 0x67, 0xbf, 0xf0, 0x3e, 0xee, 0x45, 0x55, +		}, +	}},  	// Server asks for cert with empty CA list, client gives one  	// go test -run "TestRunServer" -serve -clientauth 1 -	// gnutls-cli --insecure --debug 100 -p 10443 localhost -	{"RequestClientCert, client gives it", RequestClientCert, -		[]*x509.Certificate{clientCertificate}, -		[][]byte{{ -			0x16, 0x03, 0x02, 0x00, 0x7a, 0x01, 0x00, 0x00, -			0x76, 0x03, 0x02, 0x4e, 0xe7, 0x44, 0xda, 0x58, -			0x7d, 0x46, 0x4a, 0x48, 0x97, 0x9f, 0xe5, 0x91, -			0x11, 0x64, 0xa7, 0x1e, 0x4d, 0xb7, 0xfe, 0x9b, -			0xc6, 0x63, 0xf8, 0xa4, 0xb5, 0x0b, 0x18, 0xb5, -			0xbd, 0x19, 0xb3, 0x00, 0x00, 0x34, 0x00, 0x33, -			0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, -			0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, -			0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, -			0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, -			0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, -			0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, -			0x00, 0x8a, 0x01, 0x00, 0x00, 0x19, 0x00, 0x09, -			0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, -			0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, -			0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, +	{"RequestClientCert, client gives it", RequestClientCert, []*x509.Certificate{clientCertificate}, [][]byte{ +		{ +			0x16, 0x03, 0x01, 0x00, 0x54, 0x01, 0x00, 0x00, +			0x50, 0x03, 0x01, 0x50, 0x77, 0x43, 0x47, 0xfd, +			0x1d, 0xb0, 0x60, 0x4c, 0x25, 0x86, 0x45, 0x4a, +			0xe5, 0x3f, 0x80, 0x56, 0x18, 0x91, 0x5c, 0xe2, +			0x62, 0xc5, 0x77, 0xc2, 0x92, 0xdd, 0xdc, 0x39, +			0x23, 0x1d, 0xc5, 0x00, 0x00, 0x28, 0x00, 0x39, +			0x00, 0x38, 0x00, 0x35, 0x00, 0x16, 0x00, 0x13, +			0x00, 0x0a, 0x00, 0x33, 0x00, 0x32, 0x00, 0x2f, +			0x00, 0x05, 0x00, 0x04, 0x00, 0x15, 0x00, 0x12, +			0x00, 0x09, 0x00, 0x14, 0x00, 0x11, 0x00, 0x08, +			0x00, 0x06, 0x00, 0x03, 0x00, 0xff, 0x02, 0x01, +			0x00,  		}, - -			{ -				0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, -				0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -				0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, -				0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, -				0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, -				0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, -				0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, -				0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, -				0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -				0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, -				0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, -				0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, -				0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, -				0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, -				0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, -				0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, -				0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, -				0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, -				0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, -				0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, -				0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, -				0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, -				0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, -				0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, -				0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, -				0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, -				0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, -				0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, -				0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, -				0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, -				0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, -				0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, -				0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, -				0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, -				0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, -				0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, -				0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, -				0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, -				0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, -				0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, -				0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, -				0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, -				0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, -				0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, -				0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, -				0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, -				0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, -				0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, -				0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, -				0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, -				0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, -				0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, -				0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, -				0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, -				0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, -				0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, -				0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, -				0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, -				0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, -				0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, -				0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, -				0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, -				0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, -				0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, -				0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, -				0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, -				0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, -				0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, -				0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, -				0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, -				0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, -				0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, -				0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, -				0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -				0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, -				0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, -				0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, -				0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, -				0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, -				0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, -				0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, -				0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, -				0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, -				0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, -				0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, -				0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, -				0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, -				0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, -				0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, -				0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, -				0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, -				0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x08, 0x0d, -				0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00, 0x16, -				0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00, -			}, - -			{ -				0x16, 0x03, 0x01, 0x01, 0xfb, 0x0b, 0x00, 0x01, -				0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30, -				0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0, -				0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, -				0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -				0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10, -				0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, -				0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, -				0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, -				0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, -				0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d, -				0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37, -				0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31, -				0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30, -				0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10, -				0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, -				0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, -				0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, -				0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, -				0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30, -				0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -				0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00, -				0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0, -				0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0, -				0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33, -				0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84, -				0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d, -				0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5, -				0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c, -				0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87, -				0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec, -				0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01, -				0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab, -				0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e, -				0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b, -				0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec, -				0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c, -				0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13, -				0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03, -				0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30, -				0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, -				0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30, -				0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06, -				0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f, -				0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30, -				0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, -				0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, -				0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00, -				0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e, -				0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7, -				0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85, -				0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32, -				0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9, -				0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15, -				0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9, -				0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84, -				0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd, -				0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6, -				0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0, -				0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c, -				0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96, -				0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18, -				0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf, -				0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85, -				0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, -				0x82, 0x00, 0x80, 0xa7, 0x2f, 0xed, 0xfa, 0xc2, -				0xbd, 0x46, 0xa1, 0xf2, 0x69, 0xc5, 0x1d, 0xa1, -				0x34, 0xd6, 0xd0, 0x84, 0xf5, 0x5d, 0x8c, 0x82, -				0x8d, 0x98, 0x82, 0x9c, 0xd9, 0x07, 0xe0, 0xf7, -				0x55, 0x49, 0x4d, 0xa1, 0x48, 0x59, 0x02, 0xd3, -				0x84, 0x37, 0xaf, 0x01, 0xb3, 0x3a, 0xf4, 0xed, -				0x99, 0xbe, 0x67, 0x36, 0x19, 0x55, 0xf3, 0xf9, -				0xcb, 0x94, 0xe5, 0x7b, 0x8b, 0x77, 0xf2, 0x5f, -				0x4c, 0xfe, 0x01, 0x1f, 0x7b, 0xd7, 0x23, 0x49, -				0x0c, 0xcb, 0x6c, 0xb0, 0xe7, 0x77, 0xd6, 0xcf, -				0xa8, 0x7d, 0xdb, 0xa7, 0x14, 0xe2, 0xf5, 0xf3, -				0xff, 0xba, 0x23, 0xd2, 0x9a, 0x36, 0x14, 0x60, -				0x2a, 0x91, 0x5d, 0x2b, 0x35, 0x3b, 0xb6, 0xdd, -				0xcb, 0x6b, 0xdc, 0x18, 0xdc, 0x33, 0xb8, 0xb3, -				0xc7, 0x27, 0x7e, 0xfc, 0xd2, 0xf7, 0x97, 0x90, -				0x5e, 0x17, 0xac, 0x14, 0x8e, 0x0f, 0xca, 0xb5, -				0x6f, 0xc9, 0x2d, 0x16, 0x03, 0x01, 0x00, 0x86, -				0x0f, 0x00, 0x00, 0x82, 0x00, 0x80, 0x44, 0x7f, -				0xa2, 0x59, 0x60, 0x0b, 0x5a, 0xc4, 0xaf, 0x1e, -				0x60, 0xa5, 0x24, 0xea, 0xc1, 0xc3, 0x22, 0x21, -				0x6b, 0x22, 0x8b, 0x2a, 0x11, 0x82, 0x68, 0x7d, -				0xb9, 0xdd, 0x9c, 0x27, 0x4c, 0xc2, 0xc8, 0xa2, -				0x8b, 0x6b, 0x77, 0x8d, 0x3a, 0x2b, 0x8d, 0x2f, -				0x6a, 0x2b, 0x43, 0xd2, 0xd1, 0xc6, 0x41, 0x79, -				0xa2, 0x4f, 0x2b, 0xc2, 0xf7, 0xb2, 0x10, 0xad, -				0xa6, 0x01, 0x51, 0x51, 0x25, 0xe7, 0x58, 0x7a, -				0xcf, 0x3b, 0xc4, 0x29, 0xb5, 0xe5, 0xa7, 0x83, -				0xe6, 0xcb, 0x1e, 0xf3, 0x02, 0x0f, 0x53, 0x3b, -				0xb5, 0x39, 0xef, 0x9c, 0x42, 0xe0, 0xa6, 0x9b, -				0x2b, 0xdd, 0x60, 0xae, 0x0a, 0x73, 0x35, 0xbe, -				0x26, 0x10, 0x1b, 0xe9, 0xe9, 0x61, 0xab, 0x20, -				0xa5, 0x48, 0xc6, 0x60, 0xa6, 0x50, 0x3c, 0xfb, -				0xa7, 0xca, 0xb0, 0x80, 0x95, 0x1e, 0xce, 0xc7, -				0xbb, 0x68, 0x44, 0xdc, 0x0e, 0x0e, 0x14, 0x03, -				0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, -				0x24, 0xb6, 0xcd, 0x0c, 0x78, 0xfd, 0xd6, 0xff, -				0xbe, 0x97, 0xd5, 0x0a, 0x7d, 0x4f, 0xa1, 0x03, -				0x78, 0xc8, 0x61, 0x6f, 0xf2, 0x4b, 0xa8, 0x56, -				0x4f, 0x3c, 0xa2, 0xd9, 0xd0, 0x20, 0x13, 0x1b, -				0x8b, 0x36, 0xb7, 0x33, 0x9c, -			}, - -			{ -				0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, -				0x01, 0x00, 0x24, 0xa3, 0x43, 0x94, 0xe7, 0xdf, -				0xb6, 0xc3, 0x03, 0x9f, 0xc1, 0x59, 0x0c, 0xc3, -				0x13, 0xae, 0xed, 0xcf, 0xff, 0xf1, 0x80, 0xf3, -				0x13, 0x63, 0x1c, 0xf0, 0xca, 0xad, 0x9e, 0x71, -				0x46, 0x5f, 0x6b, 0xeb, 0x10, 0x3f, 0xe3, 0x17, -				0x03, 0x01, 0x00, 0x21, 0xe9, 0x80, 0x95, 0x6e, -				0x05, 0x55, 0x2f, 0xed, 0x4d, 0xde, 0x17, 0x3a, -				0x32, 0x9b, 0x2a, 0x74, 0x30, 0x4f, 0xe0, 0x9f, -				0x4e, 0xd3, 0x06, 0xbd, 0x3a, 0x43, 0x75, 0x8b, -				0x5b, 0x9a, 0xd8, 0x2e, 0x56, 0x15, 0x03, 0x01, -				0x00, 0x16, 0x53, 0xf5, 0xff, 0xe0, 0xa1, 0x6c, -				0x33, 0xf4, 0x4e, 0x89, 0x68, 0xe1, 0xf7, 0x61, -				0x13, 0xb3, 0x12, 0xa1, 0x8e, 0x5a, 0x7a, 0x02, -			}, +		{ +			0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, +			0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +			0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, +			0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, +			0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, +			0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, +			0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, +			0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, +			0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, +			0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, +			0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, +			0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, +			0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, +			0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, +			0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, +			0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, +			0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, +			0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, +			0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, +			0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, +			0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, +			0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, +			0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, +			0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, +			0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, +			0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, +			0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, +			0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, +			0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, +			0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, +			0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, +			0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, +			0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, +			0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, +			0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, +			0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, +			0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, +			0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, +			0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, +			0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, +			0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, +			0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, +			0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, +			0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, +			0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, +			0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, +			0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, +			0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, +			0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, +			0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, +			0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, +			0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, +			0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, +			0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, +			0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, +			0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, +			0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, +			0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, +			0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, +			0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, +			0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, +			0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, +			0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, +			0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, +			0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, +			0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, +			0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, +			0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, +			0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, +			0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, +			0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, +			0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, +			0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, +			0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, +			0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, +			0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, +			0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, +			0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, +			0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, +			0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, +			0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, +			0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, +			0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, +			0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, +			0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, +			0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, +			0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, +			0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, +			0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, +			0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, +			0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, +			0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x08, 0x0d, +			0x00, 0x00, 0x04, 0x01, 0x01, 0x00, 0x00, 0x16, +			0x03, 0x01, 0x00, 0x04, 0x0e, 0x00, 0x00, 0x00,  		}, -	}, +		{ +			0x16, 0x03, 0x01, 0x01, 0xfb, 0x0b, 0x00, 0x01, +			0xf7, 0x00, 0x01, 0xf4, 0x00, 0x01, 0xf1, 0x30, +			0x82, 0x01, 0xed, 0x30, 0x82, 0x01, 0x58, 0xa0, +			0x03, 0x02, 0x01, 0x02, 0x02, 0x01, 0x00, 0x30, +			0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, +			0x0d, 0x01, 0x01, 0x05, 0x30, 0x26, 0x31, 0x10, +			0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, +			0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, +			0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, +			0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, +			0x2e, 0x30, 0x2e, 0x31, 0x30, 0x1e, 0x17, 0x0d, +			0x31, 0x31, 0x31, 0x32, 0x30, 0x38, 0x30, 0x37, +			0x35, 0x35, 0x31, 0x32, 0x5a, 0x17, 0x0d, 0x31, +			0x32, 0x31, 0x32, 0x30, 0x37, 0x30, 0x38, 0x30, +			0x30, 0x31, 0x32, 0x5a, 0x30, 0x26, 0x31, 0x10, +			0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, +			0x07, 0x41, 0x63, 0x6d, 0x65, 0x20, 0x43, 0x6f, +			0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, +			0x03, 0x13, 0x09, 0x31, 0x32, 0x37, 0x2e, 0x30, +			0x2e, 0x30, 0x2e, 0x31, 0x30, 0x81, 0x9c, 0x30, +			0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, +			0x0d, 0x01, 0x01, 0x01, 0x03, 0x81, 0x8c, 0x00, +			0x30, 0x81, 0x88, 0x02, 0x81, 0x80, 0x4e, 0xd0, +			0x7b, 0x31, 0xe3, 0x82, 0x64, 0xd9, 0x59, 0xc0, +			0xc2, 0x87, 0xa4, 0x5e, 0x1e, 0x8b, 0x73, 0x33, +			0xc7, 0x63, 0x53, 0xdf, 0x66, 0x92, 0x06, 0x84, +			0xf6, 0x64, 0xd5, 0x8f, 0xe4, 0x36, 0xa7, 0x1d, +			0x2b, 0xe8, 0xb3, 0x20, 0x36, 0x45, 0x23, 0xb5, +			0xe3, 0x95, 0xae, 0xed, 0xe0, 0xf5, 0x20, 0x9c, +			0x8d, 0x95, 0xdf, 0x7f, 0x5a, 0x12, 0xef, 0x87, +			0xe4, 0x5b, 0x68, 0xe4, 0xe9, 0x0e, 0x74, 0xec, +			0x04, 0x8a, 0x7f, 0xde, 0x93, 0x27, 0xc4, 0x01, +			0x19, 0x7a, 0xbd, 0xf2, 0xdc, 0x3d, 0x14, 0xab, +			0xd0, 0x54, 0xca, 0x21, 0x0c, 0xd0, 0x4d, 0x6e, +			0x87, 0x2e, 0x5c, 0xc5, 0xd2, 0xbb, 0x4d, 0x4b, +			0x4f, 0xce, 0xb6, 0x2c, 0xf7, 0x7e, 0x88, 0xec, +			0x7c, 0xd7, 0x02, 0x91, 0x74, 0xa6, 0x1e, 0x0c, +			0x1a, 0xda, 0xe3, 0x4a, 0x5a, 0x2e, 0xde, 0x13, +			0x9c, 0x4c, 0x40, 0x88, 0x59, 0x93, 0x02, 0x03, +			0x01, 0x00, 0x01, 0xa3, 0x32, 0x30, 0x30, 0x30, +			0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, +			0xff, 0x04, 0x04, 0x03, 0x02, 0x00, 0xa0, 0x30, +			0x0d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x06, +			0x04, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, 0x0f, +			0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x08, 0x30, +			0x06, 0x80, 0x04, 0x01, 0x02, 0x03, 0x04, 0x30, +			0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, +			0x0d, 0x01, 0x01, 0x05, 0x03, 0x81, 0x81, 0x00, +			0x36, 0x1f, 0xb3, 0x7a, 0x0c, 0x75, 0xc9, 0x6e, +			0x37, 0x46, 0x61, 0x2b, 0xd5, 0xbd, 0xc0, 0xa7, +			0x4b, 0xcc, 0x46, 0x9a, 0x81, 0x58, 0x7c, 0x85, +			0x79, 0x29, 0xc8, 0xc8, 0xc6, 0x67, 0xdd, 0x32, +			0x56, 0x45, 0x2b, 0x75, 0xb6, 0xe9, 0x24, 0xa9, +			0x50, 0x9a, 0xbe, 0x1f, 0x5a, 0xfa, 0x1a, 0x15, +			0xd9, 0xcc, 0x55, 0x95, 0x72, 0x16, 0x83, 0xb9, +			0xc2, 0xb6, 0x8f, 0xfd, 0x88, 0x8c, 0x38, 0x84, +			0x1d, 0xab, 0x5d, 0x92, 0x31, 0x13, 0x4f, 0xfd, +			0x83, 0x3b, 0xc6, 0x9d, 0xf1, 0x11, 0x62, 0xb6, +			0x8b, 0xec, 0xab, 0x67, 0xbe, 0xc8, 0x64, 0xb0, +			0x11, 0x50, 0x46, 0x58, 0x17, 0x6b, 0x99, 0x1c, +			0xd3, 0x1d, 0xfc, 0x06, 0xf1, 0x0e, 0xe5, 0x96, +			0xa8, 0x0c, 0xf9, 0x78, 0x20, 0xb7, 0x44, 0x18, +			0x51, 0x8d, 0x10, 0x7e, 0x4f, 0x94, 0x67, 0xdf, +			0xa3, 0x4e, 0x70, 0x73, 0x8e, 0x90, 0x91, 0x85, +			0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, +			0x82, 0x00, 0x80, 0x81, 0x46, 0x43, 0xf9, 0xe7, +			0xda, 0x8c, 0x92, 0x3a, 0x78, 0x1a, 0x86, 0xb3, +			0xbe, 0x83, 0x22, 0xb6, 0xaa, 0x57, 0x37, 0x68, +			0x9e, 0x54, 0x3f, 0xd3, 0xce, 0x4d, 0x5e, 0x2a, +			0xdc, 0xb0, 0x49, 0x02, 0xbb, 0xc0, 0x45, 0x58, +			0x79, 0x10, 0xc7, 0x94, 0x60, 0x9f, 0x1b, 0x5f, +			0x18, 0x31, 0x37, 0x9c, 0xe0, 0xe6, 0xdf, 0x5e, +			0x70, 0x44, 0xf6, 0x8b, 0xdf, 0xf1, 0xf6, 0x43, +			0xc8, 0x2f, 0xd1, 0xce, 0xd0, 0xd6, 0x64, 0x4f, +			0xe8, 0x2b, 0xfa, 0xd3, 0xd0, 0xd1, 0x2e, 0xaa, +			0x9b, 0x1d, 0x13, 0x5c, 0xbe, 0x57, 0x41, 0x6c, +			0x5e, 0x8d, 0xea, 0xa9, 0x3c, 0x58, 0xa0, 0x30, +			0x92, 0x77, 0x7a, 0xed, 0x64, 0x58, 0xe5, 0x7f, +			0x6a, 0x93, 0x89, 0x66, 0x3d, 0x13, 0x16, 0x56, +			0xa0, 0xad, 0xdc, 0x68, 0x95, 0x87, 0x81, 0xd0, +			0x90, 0x4d, 0x5f, 0xfe, 0x3e, 0x83, 0x15, 0x2e, +			0x50, 0x3c, 0xdd, 0x16, 0x03, 0x01, 0x00, 0x86, +			0x0f, 0x00, 0x00, 0x82, 0x00, 0x80, 0x2b, 0xf8, +			0x56, 0x48, 0xbb, 0x02, 0x37, 0x15, 0x02, 0x74, +			0x33, 0x53, 0x65, 0xa7, 0x7c, 0x2f, 0xc6, 0x5d, +			0x80, 0x59, 0xc1, 0xc2, 0x3b, 0xa9, 0xde, 0x4e, +			0x70, 0x51, 0xd2, 0xde, 0x58, 0x7f, 0xd8, 0xb9, +			0xb6, 0x3b, 0xc8, 0xaa, 0xfc, 0x3d, 0x53, 0x2d, +			0x61, 0x4d, 0xf5, 0x60, 0x12, 0xc2, 0xa5, 0x39, +			0x0c, 0xa7, 0xc6, 0xac, 0x26, 0x4b, 0xf4, 0x5f, +			0xe9, 0xf4, 0xf2, 0x73, 0x48, 0xe4, 0x3b, 0xee, +			0xf2, 0xee, 0xc0, 0xee, 0xfb, 0x5b, 0x60, 0xc2, +			0x74, 0xe6, 0xf6, 0x43, 0x3e, 0xa4, 0xf7, 0x97, +			0x3d, 0xfc, 0xe9, 0x44, 0x21, 0x18, 0x46, 0x05, +			0x33, 0xf8, 0xfe, 0x35, 0x5b, 0xe6, 0x8f, 0xef, +			0x4d, 0x4c, 0x87, 0xf6, 0xb4, 0x6e, 0x6b, 0x39, +			0xd8, 0xaa, 0x1b, 0x33, 0xc9, 0x1c, 0x66, 0x48, +			0xbe, 0xfa, 0xb5, 0x92, 0x09, 0xfd, 0xb9, 0xb9, +			0xca, 0xe6, 0x6d, 0x71, 0xc6, 0x89, 0x14, 0x03, +			0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, 0x00, +			0x24, 0xe3, 0x2b, 0xef, 0x17, 0xd5, 0xa6, 0x4c, +			0x2e, 0x10, 0xac, 0x9c, 0xfe, 0x0f, 0x18, 0x43, +			0x95, 0x00, 0x81, 0xf7, 0x7c, 0x00, 0x5b, 0x89, +			0x52, 0x41, 0xe4, 0x8a, 0x8a, 0x34, 0x31, 0x09, +			0x48, 0x7c, 0xc5, 0xc3, 0x83, +		}, +		{ +			0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, +			0x01, 0x00, 0x24, 0x24, 0xaa, 0xaa, 0x56, 0x8b, +			0x41, 0x87, 0x01, 0xbe, 0x80, 0x05, 0x51, 0x36, +			0x08, 0xfc, 0xaf, 0xff, 0x7f, 0xf4, 0x74, 0x84, +			0x88, 0xdc, 0xb8, 0x8e, 0x70, 0x6c, 0x22, 0x04, +			0xee, 0x45, 0x8d, 0xda, 0xed, 0xc6, 0x05, 0x17, +			0x03, 0x01, 0x00, 0x21, 0x91, 0x49, 0x4b, 0xed, +			0xa3, 0x41, 0xe9, 0x88, 0x3b, 0xa3, 0x01, 0xee, +			0x77, 0x4e, 0x12, 0xb4, 0xcd, 0x5e, 0xcc, 0x45, +			0x02, 0x5a, 0x20, 0xd6, 0xe8, 0xac, 0xcb, 0x60, +			0xcb, 0x1b, 0xef, 0xf9, 0xc2, 0x15, 0x03, 0x01, +			0x00, 0x16, 0xd4, 0xcd, 0x92, 0x3c, 0x10, 0x93, +			0x68, 0xc3, 0xdd, 0xaf, 0xe9, 0xcb, 0x5d, 0x94, +			0x1a, 0x06, 0x81, 0xa7, 0x78, 0x0f, 0xc3, 0x03, +		}, +	}},  }  // cert.pem and key.pem were generated with generate_cert.go @@ -1703,7 +1984,7 @@ GFGNEH5PlGffo05wc46QkYU=  /* corresponding key.pem for cert.pem is:  -----BEGIN RSA PRIVATE KEY----- -MIICXAIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg +MIICWgIBAAKBgE7QezHjgmTZWcDCh6ReHotzM8djU99mkgaE9mTVj+Q2px0r6LMg  NkUjteOVru3g9SCcjZXff1oS74fkW2jk6Q507ASKf96TJ8QBGXq98tw9FKvQVMoh  DNBNbocuXMXSu01LT862LPd+iOx81wKRdKYeDBra40paLt4TnExAiFmTAgMBAAEC  gYBxvXd8yNteFTns8A/2yomEMC4yeosJJSpp1CsN3BJ7g8/qTnrVPxBy+RU+qr63 @@ -1715,6 +1996,6 @@ RkKVpenBHyrGg0oeN5La7URILWKj7CPXAkBKo6F+d+phNjwIFoN1Xb/RA32w/D1I  saG9sF+UEhRt9AxUfW/U/tIQ9V0ZHHcSg1XaCM5Nvp934brdKdvTOKnJAkBD5h/3  Rybatlvg/fzBEaJFyq09zhngkxlZOUtBVTqzl17RVvY2orgH02U4HbCHy4phxOn7  qTdQRYlHRftgnWK1AkANibn9PRYJ7mJyJ9Dyj2QeNcSkSTzrt0tPvUMf4+meJymN -1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvAMAA= +1Ntu5+S1DLLzfxlaljWG6ylW6DNxujCyuXIV2rvA  -----END RSA PRIVATE KEY-----  */ diff --git a/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py b/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py deleted file mode 100644 index 5692bd32f..000000000 --- a/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py +++ /dev/null @@ -1,57 +0,0 @@ -# Copyright 2010 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. - -# This code is used to parse the debug log from gnutls-cli and generate a -# script of the handshake. This script is included in handshake_server_test.go. -# See the comments there for details. - -import sys - -blocks = [] - -READ = 1 -WRITE = 2 - -currentBlockType = 0 -currentBlock = [] -for line in sys.stdin.readlines(): -        line = line[:-1] -        if line.startswith("|<7>| WRITE: "): -                if currentBlockType != WRITE: -                        if len(currentBlock) > 0: -                                blocks.append(currentBlock) -                        currentBlock = [] -                        currentBlockType = WRITE -        elif line.startswith("|<7>| READ: "): -                if currentBlockType != READ: -                        if len(currentBlock) > 0: -                                blocks.append(currentBlock) -                        currentBlock = [] -                        currentBlockType = READ -        elif line.startswith("|<7>| 0"): -                line = line[13:] -                line = line.strip() -                bs = line.split() -                for b in bs: -                        currentBlock.append(int(b, 16)) -	elif line.startswith("|<7>| RB-PEEK: Read 1 bytes"): -		currentBlock = currentBlock[:-1] - -if len(currentBlock) > 0: -        blocks.append(currentBlock) - -for block in blocks: -        sys.stdout.write("\t{\n") - -        i = 0 -        for b in block: -                if i % 8 == 0: -                        sys.stdout.write("\t\t") -                sys.stdout.write("0x%02x," % b) -                if i % 8 == 7: -                        sys.stdout.write("\n") -                else: -                        sys.stdout.write(" ") -                i += 1 -        sys.stdout.write("\n\t},\n\n") diff --git a/src/pkg/crypto/tls/prf.go b/src/pkg/crypto/tls/prf.go index 637ef03e2..df1eaad05 100644 --- a/src/pkg/crypto/tls/prf.go +++ b/src/pkg/crypto/tls/prf.go @@ -106,10 +106,9 @@ var keyExpansionLabel = []byte("key expansion")  var clientFinishedLabel = []byte("client finished")  var serverFinishedLabel = []byte("server finished") -// keysFromPreMasterSecret generates the connection keys from the pre master -// secret, given the lengths of the MAC key, cipher key and IV, as defined in -// RFC 2246, section 6.3. -func keysFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { +// masterFromPreMasterSecret generates the master secret from the pre-master +// secret. See http://tools.ietf.org/html/rfc5246#section-8.1 +func masterFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte) []byte {  	prf := pRF10  	if version == versionSSL30 {  		prf = pRF30 @@ -118,9 +117,21 @@ func keysFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serv  	var seed [tlsRandomLength * 2]byte  	copy(seed[0:len(clientRandom)], clientRandom)  	copy(seed[len(clientRandom):], serverRandom) -	masterSecret = make([]byte, masterSecretLength) +	masterSecret := make([]byte, masterSecretLength)  	prf(masterSecret, preMasterSecret, masterSecretLabel, seed[0:]) +	return masterSecret +} +// keysFromMasterSecret generates the connection keys from the master +// secret, given the lengths of the MAC key, cipher key and IV, as defined in +// RFC 2246, section 6.3. +func keysFromMasterSecret(version uint16, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { +	prf := pRF10 +	if version == versionSSL30 { +		prf = pRF30 +	} + +	var seed [tlsRandomLength * 2]byte  	copy(seed[0:len(clientRandom)], serverRandom)  	copy(seed[len(serverRandom):], clientRandom) diff --git a/src/pkg/crypto/tls/prf_test.go b/src/pkg/crypto/tls/prf_test.go index a32392cef..773a2b2ff 100644 --- a/src/pkg/crypto/tls/prf_test.go +++ b/src/pkg/crypto/tls/prf_test.go @@ -48,18 +48,23 @@ func TestKeysFromPreMasterSecret(t *testing.T) {  		in, _ := hex.DecodeString(test.preMasterSecret)  		clientRandom, _ := hex.DecodeString(test.clientRandom)  		serverRandom, _ := hex.DecodeString(test.serverRandom) -		master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret(test.version, in, clientRandom, serverRandom, test.macLen, test.keyLen, 0) -		masterString := hex.EncodeToString(master) + +		masterSecret := masterFromPreMasterSecret(test.version, in, clientRandom, serverRandom) +		if s := hex.EncodeToString(masterSecret); s != test.masterSecret { +			t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret) +			continue +		} + +		clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)  		clientMACString := hex.EncodeToString(clientMAC)  		serverMACString := hex.EncodeToString(serverMAC)  		clientKeyString := hex.EncodeToString(clientKey)  		serverKeyString := hex.EncodeToString(serverKey) -		if masterString != test.masterSecret || -			clientMACString != test.clientMAC || +		if clientMACString != test.clientMAC ||  			serverMACString != test.serverMAC ||  			clientKeyString != test.clientKey ||  			serverKeyString != test.serverKey { -			t.Errorf("#%d: got: (%s, %s, %s, %s, %s) want: (%s, %s, %s, %s, %s)", i, masterString, clientMACString, serverMACString, clientKeyString, serverKeyString, test.masterSecret, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey) +			t.Errorf("#%d: got: (%s, %s, %s, %s) want: (%s, %s, %s, %s)", i, clientMACString, serverMACString, clientKeyString, serverKeyString, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey)  		}  	}  } diff --git a/src/pkg/crypto/tls/root_test.go b/src/pkg/crypto/tls/root_test.go deleted file mode 100644 index e61c21851..000000000 --- a/src/pkg/crypto/tls/root_test.go +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2011 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package tls - -import ( -	"crypto/x509" -	"runtime" -	"testing" -) - -var tlsServers = []string{ -	"google.com", -	"github.com", -	"twitter.com", -} - -func TestOSCertBundles(t *testing.T) { -	if testing.Short() { -		t.Logf("skipping certificate tests in short mode") -		return -	} - -	for _, addr := range tlsServers { -		conn, err := Dial("tcp", addr+":443", &Config{ServerName: addr}) -		if err != nil { -			t.Errorf("unable to verify %v: %v", addr, err) -			continue -		} -		err = conn.Close() -		if err != nil { -			t.Error(err) -		} -	} -} - -func TestCertHostnameVerifyWindows(t *testing.T) { -	if runtime.GOOS != "windows" { -		return -	} - -	if testing.Short() { -		t.Logf("skipping certificate tests in short mode") -		return -	} - -	for _, addr := range tlsServers { -		cfg := &Config{ServerName: "example.com"} -		conn, err := Dial("tcp", addr+":443", cfg) -		if err == nil { -			conn.Close() -			t.Errorf("should fail to verify for example.com: %v", addr) -			continue -		} -		_, ok := err.(x509.HostnameError) -		if !ok { -			t.Errorf("error type mismatch, got: %v", err) -		} -	} -} diff --git a/src/pkg/crypto/tls/ticket.go b/src/pkg/crypto/tls/ticket.go new file mode 100644 index 000000000..4cfc5a53f --- /dev/null +++ b/src/pkg/crypto/tls/ticket.go @@ -0,0 +1,182 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( +	"bytes" +	"crypto/aes" +	"crypto/cipher" +	"crypto/hmac" +	"crypto/sha256" +	"crypto/subtle" +	"errors" +	"io" +) + +// sessionState contains the information that is serialized into a session +// ticket in order to later resume a connection. +type sessionState struct { +	vers         uint16 +	cipherSuite  uint16 +	masterSecret []byte +	certificates [][]byte +} + +func (s *sessionState) equal(i interface{}) bool { +	s1, ok := i.(*sessionState) +	if !ok { +		return false +	} + +	if s.vers != s1.vers || +		s.cipherSuite != s1.cipherSuite || +		!bytes.Equal(s.masterSecret, s1.masterSecret) { +		return false +	} + +	if len(s.certificates) != len(s1.certificates) { +		return false +	} + +	for i := range s.certificates { +		if !bytes.Equal(s.certificates[i], s1.certificates[i]) { +			return false +		} +	} + +	return true +} + +func (s *sessionState) marshal() []byte { +	length := 2 + 2 + 2 + len(s.masterSecret) + 2 +	for _, cert := range s.certificates { +		length += 4 + len(cert) +	} + +	ret := make([]byte, length) +	x := ret +	x[0] = byte(s.vers >> 8) +	x[1] = byte(s.vers) +	x[2] = byte(s.cipherSuite >> 8) +	x[3] = byte(s.cipherSuite) +	x[4] = byte(len(s.masterSecret) >> 8) +	x[5] = byte(len(s.masterSecret)) +	x = x[6:] +	copy(x, s.masterSecret) +	x = x[len(s.masterSecret):] + +	x[0] = byte(len(s.certificates) >> 8) +	x[1] = byte(len(s.certificates)) +	x = x[2:] + +	for _, cert := range s.certificates { +		x[0] = byte(len(cert) >> 24) +		x[1] = byte(len(cert) >> 16) +		x[2] = byte(len(cert) >> 8) +		x[3] = byte(len(cert)) +		copy(x[4:], cert) +		x = x[4+len(cert):] +	} + +	return ret +} + +func (s *sessionState) unmarshal(data []byte) bool { +	if len(data) < 8 { +		return false +	} + +	s.vers = uint16(data[0])<<8 | uint16(data[1]) +	s.cipherSuite = uint16(data[2])<<8 | uint16(data[3]) +	masterSecretLen := int(data[4])<<8 | int(data[5]) +	data = data[6:] +	if len(data) < masterSecretLen { +		return false +	} + +	s.masterSecret = data[:masterSecretLen] +	data = data[masterSecretLen:] + +	if len(data) < 2 { +		return false +	} + +	numCerts := int(data[0])<<8 | int(data[1]) +	data = data[2:] + +	s.certificates = make([][]byte, numCerts) +	for i := range s.certificates { +		if len(data) < 4 { +			return false +		} +		certLen := int(data[0])<<24 | int(data[1])<<16 | int(data[2])<<8 | int(data[3]) +		data = data[4:] +		if certLen < 0 { +			return false +		} +		if len(data) < certLen { +			return false +		} +		s.certificates[i] = data[:certLen] +		data = data[certLen:] +	} + +	if len(data) > 0 { +		return false +	} + +	return true +} + +func (c *Conn) encryptTicket(state *sessionState) ([]byte, error) { +	serialized := state.marshal() +	encrypted := make([]byte, aes.BlockSize+len(serialized)+sha256.Size) +	iv := encrypted[:aes.BlockSize] +	macBytes := encrypted[len(encrypted)-sha256.Size:] + +	if _, err := io.ReadFull(c.config.rand(), iv); err != nil { +		return nil, err +	} +	block, err := aes.NewCipher(c.config.SessionTicketKey[:16]) +	if err != nil { +		return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error()) +	} +	cipher.NewCTR(block, iv).XORKeyStream(encrypted[aes.BlockSize:], serialized) + +	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32]) +	mac.Write(encrypted[:len(encrypted)-sha256.Size]) +	mac.Sum(macBytes[:0]) + +	return encrypted, nil +} + +func (c *Conn) decryptTicket(encrypted []byte) (*sessionState, bool) { +	if len(encrypted) < aes.BlockSize+sha256.Size { +		return nil, false +	} + +	iv := encrypted[:aes.BlockSize] +	macBytes := encrypted[len(encrypted)-sha256.Size:] + +	mac := hmac.New(sha256.New, c.config.SessionTicketKey[16:32]) +	mac.Write(encrypted[:len(encrypted)-sha256.Size]) +	expected := mac.Sum(nil) + +	if subtle.ConstantTimeCompare(macBytes, expected) != 1 { +		return nil, false +	} + +	block, err := aes.NewCipher(c.config.SessionTicketKey[:16]) +	if err != nil { +		return nil, false +	} +	ciphertext := encrypted[aes.BlockSize : len(encrypted)-sha256.Size] +	plaintext := ciphertext +	cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext) + +	state := new(sessionState) +	ok := state.unmarshal(plaintext) +	return state, ok +} diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go index 09df5ad44..9230656d6 100644 --- a/src/pkg/crypto/tls/tls.go +++ b/src/pkg/crypto/tls/tls.go @@ -6,6 +6,8 @@  package tls  import ( +	"crypto" +	"crypto/ecdsa"  	"crypto/rsa"  	"crypto/x509"  	"encoding/pem" @@ -146,30 +148,22 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error)  		return  	} -	keyDERBlock, _ := pem.Decode(keyPEMBlock) -	if keyDERBlock == nil { -		err = errors.New("crypto/tls: failed to parse key PEM data") -		return -	} - -	// OpenSSL 0.9.8 generates PKCS#1 private keys by default, while -	// OpenSSL 1.0.0 generates PKCS#8 keys. We try both. -	var key *rsa.PrivateKey -	if key, err = x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes); err != nil { -		var privKey interface{} -		if privKey, err = x509.ParsePKCS8PrivateKey(keyDERBlock.Bytes); err != nil { -			err = errors.New("crypto/tls: failed to parse key: " + err.Error()) +	var keyDERBlock *pem.Block +	for { +		keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock) +		if keyDERBlock == nil { +			err = errors.New("crypto/tls: failed to parse key PEM data")  			return  		} - -		var ok bool -		if key, ok = privKey.(*rsa.PrivateKey); !ok { -			err = errors.New("crypto/tls: found non-RSA private key in PKCS#8 wrapping") -			return +		if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") { +			break  		}  	} -	cert.PrivateKey = key +	cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes) +	if err != nil { +		return +	}  	// We don't need to parse the public key for TLS, but we so do anyway  	// to check that it looks sane and matches the private key. @@ -178,10 +172,54 @@ func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (cert Certificate, err error)  		return  	} -	if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 { -		err = errors.New("crypto/tls: private key does not match public key") +	switch pub := x509Cert.PublicKey.(type) { +	case *rsa.PublicKey: +		priv, ok := cert.PrivateKey.(*rsa.PrivateKey) +		if !ok { +			err = errors.New("crypto/tls: private key type does not match public key type") +			return +		} +		if pub.N.Cmp(priv.N) != 0 { +			err = errors.New("crypto/tls: private key does not match public key") +			return +		} +	case *ecdsa.PublicKey: +		priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey) +		if !ok { +			err = errors.New("crypto/tls: private key type does not match public key type") +			return + +		} +		if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 { +			err = errors.New("crypto/tls: private key does not match public key") +			return +		} +	default: +		err = errors.New("crypto/tls: unknown public key algorithm")  		return  	}  	return  } + +// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates +// PKCS#1 private keys by default, while OpenSSL 1.0.0 generates PKCS#8 keys. +// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three. +func parsePrivateKey(der []byte) (crypto.PrivateKey, error) { +	if key, err := x509.ParsePKCS1PrivateKey(der); err == nil { +		return key, nil +	} +	if key, err := x509.ParsePKCS8PrivateKey(der); err == nil { +		switch key := key.(type) { +		case *rsa.PrivateKey, *ecdsa.PrivateKey: +			return key, nil +		default: +			return nil, errors.New("crypto/tls: found unknown private key type in PKCS#8 wrapping") +		} +	} +	if key, err := x509.ParseECPrivateKey(der); err == nil { +		return key, nil +	} + +	return nil, errors.New("crypto/tls: failed to parse private key") +} diff --git a/src/pkg/crypto/tls/tls_test.go b/src/pkg/crypto/tls/tls_test.go new file mode 100644 index 000000000..38229014c --- /dev/null +++ b/src/pkg/crypto/tls/tls_test.go @@ -0,0 +1,107 @@ +// Copyright 2012 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( +	"testing" +) + +var rsaCertPEM = `-----BEGIN CERTIFICATE----- +MIIB0zCCAX2gAwIBAgIJAI/M7BYjwB+uMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV +BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX +aWRnaXRzIFB0eSBMdGQwHhcNMTIwOTEyMjE1MjAyWhcNMTUwOTEyMjE1MjAyWjBF +MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50 +ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANLJ +hPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wok/4xIA+ui35/MmNa +rtNuC+BdZ1tMuVCPFZcCAwEAAaNQME4wHQYDVR0OBBYEFJvKs8RfJaXTH08W+SGv +zQyKn0H8MB8GA1UdIwQYMBaAFJvKs8RfJaXTH08W+SGvzQyKn0H8MAwGA1UdEwQF +MAMBAf8wDQYJKoZIhvcNAQEFBQADQQBJlffJHybjDGxRMqaRmDhX0+6v02TUKZsW +r5QuVbpQhH6u+0UgcW0jp9QwpxoPTLTWGXEWBBBurxFwiCBhkQ+V +-----END CERTIFICATE----- +` + +var rsaKeyPEM = `-----BEGIN RSA PRIVATE KEY----- +MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo +k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G +6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N +MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW +SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T +xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi +D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== +-----END RSA PRIVATE KEY----- +` + +// keyPEM is the same as rsaKeyPEM, but declares itself as just +// "PRIVATE KEY", not "RSA PRIVATE KEY".  http://golang.org/issue/4477 +var keyPEM = `-----BEGIN PRIVATE KEY----- +MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo +k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G +6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N +MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW +SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T +xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi +D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g== +-----END PRIVATE KEY----- +` + +var ecdsaCertPEM = `-----BEGIN CERTIFICATE----- +MIIB/jCCAWICCQDscdUxw16XFDAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw +EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0 +eSBMdGQwHhcNMTIxMTE0MTI0MDQ4WhcNMTUxMTE0MTI0MDQ4WjBFMQswCQYDVQQG +EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk +Z2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBY9+my9OoeSUR +lDQdV/x8LsOuLilthhiS1Tz4aGDHIPwC1mlvnf7fg5lecYpMCrLLhauAc1UJXcgl +01xoLuzgtAEAgv2P/jgytzRSpUYvgLBt1UA0leLYBy6mQQbrNEuqT3INapKIcUv8 +XxYP0xMEUksLPq6Ca+CRSqTtrd/23uTnapkwCQYHKoZIzj0EAQOBigAwgYYCQXJo +A7Sl2nLVf+4Iu/tAX/IF4MavARKC4PPHK3zfuGfPR3oCCcsAoz3kAzOeijvd0iXb +H5jBImIxPL4WxQNiBTexAkF8D1EtpYuWdlVQ80/h/f4pBcGiXPqX5h2PQSQY7hP1 ++jwM1FGS4fREIOvlBYr/SzzQRtwrvrzGYxDEDbsC0ZGRnA== +-----END CERTIFICATE----- +` + +var ecdsaKeyPEM = `-----BEGIN EC PARAMETERS----- +BgUrgQQAIw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MIHcAgEBBEIBrsoKp0oqcv6/JovJJDoDVSGWdirrkgCWxrprGlzB9o0X8fV675X0 +NwuBenXFfeZvVcwluO7/Q9wkYoPd/t3jGImgBwYFK4EEACOhgYkDgYYABAFj36bL +06h5JRGUNB1X/Hwuw64uKW2GGJLVPPhoYMcg/ALWaW+d/t+DmV5xikwKssuFq4Bz +VQldyCXTXGgu7OC0AQCC/Y/+ODK3NFKlRi+AsG3VQDSV4tgHLqZBBus0S6pPcg1q +kohxS/xfFg/TEwRSSws+roJr4JFKpO2t3/be5OdqmQ== +-----END EC PRIVATE KEY----- +` + +var keyPairTests = []struct { +	algo string +	cert string +	key  string +}{ +	{"ECDSA", ecdsaCertPEM, ecdsaKeyPEM}, +	{"RSA", rsaCertPEM, rsaKeyPEM}, +	{"RSA-untyped", rsaCertPEM, keyPEM}, // golang.org/issue/4477 +} + +func TestX509KeyPair(t *testing.T) { +	var pem []byte +	for _, test := range keyPairTests { +		pem = []byte(test.cert + test.key) +		if _, err := X509KeyPair(pem, pem); err != nil { +			t.Errorf("Failed to load %s cert followed by %s key: %s", test.algo, test.algo, err) +		} +		pem = []byte(test.key + test.cert) +		if _, err := X509KeyPair(pem, pem); err != nil { +			t.Errorf("Failed to load %s key followed by %s cert: %s", test.algo, test.algo, err) +		} +	} +} + +func TestX509MixedKeyPair(t *testing.T) { +	if _, err := X509KeyPair([]byte(rsaCertPEM), []byte(ecdsaKeyPEM)); err == nil { +		t.Error("Load of RSA certificate succeeded with ECDSA private key") +	} +	if _, err := X509KeyPair([]byte(ecdsaCertPEM), []byte(rsaKeyPEM)); err == nil { +		t.Error("Load of ECDSA certificate succeeded with RSA private key") +	} +} diff --git a/src/pkg/crypto/x509/cert_pool.go b/src/pkg/crypto/x509/cert_pool.go index 616a0b3c1..505f4d4f7 100644 --- a/src/pkg/crypto/x509/cert_pool.go +++ b/src/pkg/crypto/x509/cert_pool.go @@ -103,7 +103,7 @@ func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {  }  // Subjects returns a list of the DER-encoded subjects of -// all of the certificates in the pool.  +// all of the certificates in the pool.  func (s *CertPool) Subjects() (res [][]byte) {  	res = make([][]byte, len(s.certs))  	for i, c := range s.certs { diff --git a/src/pkg/crypto/x509/pem_decrypt.go b/src/pkg/crypto/x509/pem_decrypt.go new file mode 100644 index 000000000..194c81bf6 --- /dev/null +++ b/src/pkg/crypto/x509/pem_decrypt.go @@ -0,0 +1,233 @@ +// Copyright 2012 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 x509 + +// RFC 1423 describes the encryption of PEM blocks. The algorithm used to +// generate a key from the password was derived by looking at the OpenSSL +// implementation. + +import ( +	"crypto/aes" +	"crypto/cipher" +	"crypto/des" +	"crypto/md5" +	"encoding/hex" +	"encoding/pem" +	"errors" +	"io" +	"strings" +) + +type PEMCipher int + +// Possible values for the EncryptPEMBlock encryption algorithm. +const ( +	_ PEMCipher = iota +	PEMCipherDES +	PEMCipher3DES +	PEMCipherAES128 +	PEMCipherAES192 +	PEMCipherAES256 +) + +// rfc1423Algo holds a method for enciphering a PEM block. +type rfc1423Algo struct { +	cipher     PEMCipher +	name       string +	cipherFunc func(key []byte) (cipher.Block, error) +	keySize    int +	blockSize  int +} + +// rfc1423Algos holds a slice of the possible ways to encrypt a PEM +// block.  The ivSize numbers were taken from the OpenSSL source. +var rfc1423Algos = []rfc1423Algo{{ +	cipher:     PEMCipherDES, +	name:       "DES-CBC", +	cipherFunc: des.NewCipher, +	keySize:    8, +	blockSize:  des.BlockSize, +}, { +	cipher:     PEMCipher3DES, +	name:       "DES-EDE3-CBC", +	cipherFunc: des.NewTripleDESCipher, +	keySize:    24, +	blockSize:  des.BlockSize, +}, { +	cipher:     PEMCipherAES128, +	name:       "AES-128-CBC", +	cipherFunc: aes.NewCipher, +	keySize:    16, +	blockSize:  aes.BlockSize, +}, { +	cipher:     PEMCipherAES192, +	name:       "AES-192-CBC", +	cipherFunc: aes.NewCipher, +	keySize:    24, +	blockSize:  aes.BlockSize, +}, { +	cipher:     PEMCipherAES256, +	name:       "AES-256-CBC", +	cipherFunc: aes.NewCipher, +	keySize:    32, +	blockSize:  aes.BlockSize, +}, +} + +// deriveKey uses a key derivation function to stretch the password into a key +// with the number of bits our cipher requires. This algorithm was derived from +// the OpenSSL source. +func (c rfc1423Algo) deriveKey(password, salt []byte) []byte { +	hash := md5.New() +	out := make([]byte, c.keySize) +	var digest []byte + +	for i := 0; i < len(out); i += len(digest) { +		hash.Reset() +		hash.Write(digest) +		hash.Write(password) +		hash.Write(salt) +		digest = hash.Sum(digest[:0]) +		copy(out[i:], digest) +	} +	return out +} + +// IsEncryptedPEMBlock returns if the PEM block is password encrypted. +func IsEncryptedPEMBlock(b *pem.Block) bool { +	_, ok := b.Headers["DEK-Info"] +	return ok +} + +// IncorrectPasswordError is returned when an incorrect password is detected. +var IncorrectPasswordError = errors.New("x509: decryption password incorrect") + +// DecryptPEMBlock takes a password encrypted PEM block and the password used to +// encrypt it and returns a slice of decrypted DER encoded bytes. It inspects +// the DEK-Info header to determine the algorithm used for decryption. If no +// DEK-Info header is present, an error is returned. If an incorrect password +// is detected an IncorrectPasswordError is returned. +func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) { +	dek, ok := b.Headers["DEK-Info"] +	if !ok { +		return nil, errors.New("x509: no DEK-Info header in block") +	} + +	idx := strings.Index(dek, ",") +	if idx == -1 { +		return nil, errors.New("x509: malformed DEK-Info header") +	} + +	mode, hexIV := dek[:idx], dek[idx+1:] +	ciph := cipherByName(mode) +	if ciph == nil { +		return nil, errors.New("x509: unknown encryption mode") +	} +	iv, err := hex.DecodeString(hexIV) +	if err != nil { +		return nil, err +	} +	if len(iv) != ciph.blockSize { +		return nil, errors.New("x509: incorrect IV size") +	} + +	// Based on the OpenSSL implementation. The salt is the first 8 bytes +	// of the initialization vector. +	key := ciph.deriveKey(password, iv[:8]) +	block, err := ciph.cipherFunc(key) +	if err != nil { +		return nil, err +	} + +	data := make([]byte, len(b.Bytes)) +	dec := cipher.NewCBCDecrypter(block, iv) +	dec.CryptBlocks(data, b.Bytes) + +	// Blocks are padded using a scheme where the last n bytes of padding are all +	// equal to n. It can pad from 1 to blocksize bytes inclusive. See RFC 1423. +	// For example: +	//	[x y z 2 2] +	//	[x y 7 7 7 7 7 7 7] +	// If we detect a bad padding, we assume it is an invalid password. +	dlen := len(data) +	if dlen == 0 || dlen%ciph.blockSize != 0 { +		return nil, errors.New("x509: invalid padding") +	} +	last := int(data[dlen-1]) +	if dlen < last { +		return nil, IncorrectPasswordError +	} +	if last == 0 || last > ciph.blockSize { +		return nil, IncorrectPasswordError +	} +	for _, val := range data[dlen-last:] { +		if int(val) != last { +			return nil, IncorrectPasswordError +		} +	} +	return data[:dlen-last], nil +} + +// EncryptPEMBlock returns a PEM block of the specified type holding the +// given DER-encoded data encrypted with the specified algorithm and +// password. +func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) { +	ciph := cipherByKey(alg) +	if ciph == nil { +		return nil, errors.New("x509: unknown encryption mode") +	} +	iv := make([]byte, ciph.blockSize) +	if _, err := io.ReadFull(rand, iv); err != nil { +		return nil, errors.New("x509: cannot generate IV: " + err.Error()) +	} +	// The salt is the first 8 bytes of the initialization vector, +	// matching the key derivation in DecryptPEMBlock. +	key := ciph.deriveKey(password, iv[:8]) +	block, err := ciph.cipherFunc(key) +	if err != nil { +		return nil, err +	} +	enc := cipher.NewCBCEncrypter(block, iv) +	pad := ciph.blockSize - len(data)%ciph.blockSize +	encrypted := make([]byte, len(data), len(data)+pad) +	// We could save this copy by encrypting all the whole blocks in +	// the data separately, but it doesn't seem worth the additional +	// code. +	copy(encrypted, data) +	// See RFC 1423, section 1.1 +	for i := 0; i < pad; i++ { +		encrypted = append(encrypted, byte(pad)) +	} +	enc.CryptBlocks(encrypted, encrypted) + +	return &pem.Block{ +		Type: blockType, +		Headers: map[string]string{ +			"Proc-Type": "4,ENCRYPTED", +			"DEK-Info":  ciph.name + "," + hex.EncodeToString(iv), +		}, +		Bytes: encrypted, +	}, nil +} + +func cipherByName(name string) *rfc1423Algo { +	for i := range rfc1423Algos { +		alg := &rfc1423Algos[i] +		if alg.name == name { +			return alg +		} +	} +	return nil +} + +func cipherByKey(key PEMCipher) *rfc1423Algo { +	for i := range rfc1423Algos { +		alg := &rfc1423Algos[i] +		if alg.cipher == key { +			return alg +		} +	} +	return nil +} diff --git a/src/pkg/crypto/x509/pem_decrypt_test.go b/src/pkg/crypto/x509/pem_decrypt_test.go new file mode 100644 index 000000000..59ba6f900 --- /dev/null +++ b/src/pkg/crypto/x509/pem_decrypt_test.go @@ -0,0 +1,223 @@ +// Copyright 2012 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 x509 + +import ( +	"bytes" +	"crypto/rand" +	"encoding/base64" +	"encoding/pem" +	"testing" +) + +func TestDecrypt(t *testing.T) { +	for i, data := range testData { +		t.Logf("test %d. %s", i, data.kind) +		block, rest := pem.Decode(data.pemData) +		if len(rest) > 0 { +			t.Error("extra data") +		} +		der, err := DecryptPEMBlock(block, data.password) +		if err != nil { +			t.Error("decrypt failed: ", err) +			continue +		} +		if _, err := ParsePKCS1PrivateKey(der); err != nil { +			t.Error("invalid private key: ", err) +		} +		plainDER, err := base64.StdEncoding.DecodeString(data.plainDER) +		if err != nil { +			t.Fatal("cannot decode test DER data: ", err) +		} +		if !bytes.Equal(der, plainDER) { +			t.Error("data mismatch") +		} +	} +} + +func TestEncrypt(t *testing.T) { +	for i, data := range testData { +		t.Logf("test %d. %s", i, data.kind) +		plainDER, err := base64.StdEncoding.DecodeString(data.plainDER) +		if err != nil { +			t.Fatal("cannot decode test DER data: ", err) +		} +		password := []byte("kremvax1") +		block, err := EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", plainDER, password, data.kind) +		if err != nil { +			t.Error("encrypt: ", err) +			continue +		} +		if !IsEncryptedPEMBlock(block) { +			t.Error("PEM block does not appear to be encrypted") +		} +		if block.Type != "RSA PRIVATE KEY" { +			t.Errorf("unexpected block type; got %q want %q", block.Type, "RSA PRIVATE KEY") +		} +		if block.Headers["Proc-Type"] != "4,ENCRYPTED" { +			t.Errorf("block does not have correct Proc-Type header") +		} +		der, err := DecryptPEMBlock(block, password) +		if err != nil { +			t.Error("decrypt: ", err) +			continue +		} +		if !bytes.Equal(der, plainDER) { +			t.Errorf("data mismatch") +		} +	} +} + +var testData = []struct { +	kind     PEMCipher +	password []byte +	pemData  []byte +	plainDER string +}{ +	{ +		kind:     PEMCipherDES, +		password: []byte("asdf"), +		pemData: []byte(` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-CBC,34F09A4FC8DE22B5 + +WXxy8kbZdiZvANtKvhmPBLV7eVFj2A5z6oAxvI9KGyhG0ZK0skfnt00C24vfU7m5 +ICXeoqP67lzJ18xCzQfHjDaBNs53DSDT+Iz4e8QUep1xQ30+8QKX2NA2coee3nwc +6oM1cuvhNUDemBH2i3dKgMVkfaga0zQiiOq6HJyGSncCMSruQ7F9iWEfRbFcxFCx +qtHb1kirfGKEtgWTF+ynyco6+2gMXNu70L7nJcnxnV/RLFkHt7AUU1yrclxz7eZz +XOH9VfTjb52q/I8Suozq9coVQwg4tXfIoYUdT//O+mB7zJb9HI9Ps77b9TxDE6Gm +4C9brwZ3zg2vqXcwwV6QRZMtyll9rOpxkbw6NPlpfBqkc3xS51bbxivbO/Nve4KD +r12ymjFNF4stXCfJnNqKoZ50BHmEEUDu5Wb0fpVn82XrGw7CYc4iug== +-----END RSA PRIVATE KEY-----`), +		plainDER: ` +MIIBPAIBAAJBAPASZe+tCPU6p80AjHhDkVsLYa51D35e/YGa8QcZyooeZM8EHozo +KD0fNiKI+53bHdy07N+81VQ8/ejPcRoXPlsCAwEAAQJBAMTxIuSq27VpR+zZ7WJf +c6fvv1OBvpMZ0/d1pxL/KnOAgq2rD5hDtk9b0LGhTPgQAmrrMTKuSeGoIuYE+gKQ +QvkCIQD+GC1m+/do+QRurr0uo46Kx1LzLeSCrjBk34wiOp2+dwIhAPHfTLRXS2fv +7rljm0bYa4+eDZpz+E8RcXEgzhhvcQQ9AiAI5eHZJGOyml3MXnQjiPi55WcDOw0w +glcRgT6QCEtz2wIhANSyqaFtosIkHKqrDUGfz/bb5tqMYTAnBruVPaf/WEOBAiEA +9xORWeRG1tRpso4+dYy4KdDkuLPIO01KY6neYGm3BCM=`, +	}, +	{ +		kind:     PEMCipher3DES, +		password: []byte("asdf"), +		pemData: []byte(` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,C1F4A6A03682C2C7 + +0JqVdBEH6iqM7drTkj+e2W/bE3LqakaiWhb9WUVonFkhyu8ca/QzebY3b5gCvAZQ +YwBvDcT/GHospKqPx+cxDHJNsUASDZws6bz8ZXWJGwZGExKzr0+Qx5fgXn44Ms3x +8g1ENFuTXtxo+KoNK0zuAMAqp66Llcds3Fjl4XR18QaD0CrVNAfOdgATWZm5GJxk +Fgx5f84nT+/ovvreG+xeOzWgvtKo0UUZVrhGOgfKLpa57adumcJ6SkUuBtEFpZFB +ldw5w7WC7d13x2LsRkwo8ZrDKgIV+Y9GNvhuCCkTzNP0V3gNeJpd201HZHR+9n3w +3z0VjR/MGqsfcy1ziEWMNOO53At3zlG6zP05aHMnMcZoVXadEK6L1gz++inSSDCq +gI0UJP4e3JVB7AkgYymYAwiYALAkoEIuanxoc50njJk= +-----END RSA PRIVATE KEY-----`), +		plainDER: ` +MIIBOwIBAAJBANOCXKdoNS/iP/MAbl9cf1/SF3P+Ns7ZeNL27CfmDh0O6Zduaax5 +NBiumd2PmjkaCu7lQ5JOibHfWn+xJsc3kw0CAwEAAQJANX/W8d1Q/sCqzkuAn4xl +B5a7qfJWaLHndu1QRLNTRJPn0Ee7OKJ4H0QKOhQM6vpjRrz+P2u9thn6wUxoPsef +QQIhAP/jCkfejFcy4v15beqKzwz08/tslVjF+Yq41eJGejmxAiEA05pMoqfkyjcx +fyvGhpoOyoCp71vSGUfR2I9CR65oKh0CIC1Msjs66LlfJtQctRq6bCEtFCxEcsP+ +eEjYo/Sk6WphAiEAxpgWPMJeU/shFT28gS+tmhjPZLpEoT1qkVlC14u0b3ECIQDX +tZZZxCtPAm7shftEib0VU77Lk8MsXJcx2C4voRsjEw==`, +	}, +	{ +		kind:     PEMCipherAES128, +		password: []byte("asdf"), +		pemData: []byte(` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,D4492E793FC835CC038A728ED174F78A + +EyfQSzXSjv6BaNH+NHdXRlkHdimpF9izWlugVJAPApgXrq5YldPe2aGIOFXyJ+QE +ZIG20DYqaPzJRjTEbPNZ6Es0S2JJ5yCpKxwJuDkgJZKtF39Q2i36JeGbSZQIuWJE +GZbBpf1jDH/pr0iGonuAdl2PCCZUiy+8eLsD2tyviHUkFLOB+ykYoJ5t8ngZ/B6D +33U43LLb7+9zD4y3Q9OVHqBFGyHcxCY9+9Qh4ZnFp7DTf6RY5TNEvE3s4g6aDpBs +3NbvRVvYTgs8K9EPk4K+5R+P2kD8J8KvEIGxVa1vz8QoCJ/jr7Ka2rvNgPCex5/E +080LzLHPCrXKdlr/f50yhNWq08ZxMWQFkui+FDHPDUaEELKAXV8/5PDxw80Rtybo +AVYoCVIbZXZCuCO81op8UcOgEpTtyU5Lgh3Mw5scQL0= +-----END RSA PRIVATE KEY-----`), +		plainDER: ` +MIIBOgIBAAJBAMBlj5FxYtqbcy8wY89d/S7n0+r5MzD9F63BA/Lpl78vQKtdJ5dT +cDGh/rBt1ufRrNp0WihcmZi7Mpl/3jHjiWECAwEAAQJABNOHYnKhtDIqFYj1OAJ3 +k3GlU0OlERmIOoeY/cL2V4lgwllPBEs7r134AY4wMmZSBUj8UR/O4SNO668ElKPE +cQIhAOuqY7/115x5KCdGDMWi+jNaMxIvI4ETGwV40ykGzqlzAiEA0P9oEC3m9tHB +kbpjSTxaNkrXxDgdEOZz8X0uOUUwHNsCIAwzcSCiGLyYJTULUmP1ESERfW1mlV78 +XzzESaJpIM/zAiBQkSTcl9VhcJreQqvjn5BnPZLP4ZHS4gPwJAGdsj5J4QIhAOVR +B3WlRNTXR2WsJ5JdByezg9xzdXzULqmga0OE339a`, +	}, +	{ +		kind:     PEMCipherAES192, +		password: []byte("asdf"), +		pemData: []byte(` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-192-CBC,E2C9FB02BCA23ADE1829F8D8BC5F5369 + +cqVslvHqDDM6qwU6YjezCRifXmKsrgEev7ng6Qs7UmDJOpHDgJQZI9fwMFUhIyn5 +FbCu1SHkLMW52Ld3CuEqMnzWMlhPrW8tFvUOrMWPYSisv7nNq88HobZEJcUNL2MM +Y15XmHW6IJwPqhKyLHpWXyOCVEh4ODND2nV15PCoi18oTa475baxSk7+1qH7GuIs +Rb7tshNTMqHbCpyo9Rn3UxeFIf9efdl8YLiMoIqc7J8E5e9VlbeQSdLMQOgDAQJG +ReUtTw8exmKsY4gsSjhkg5uiw7/ZB1Ihto0qnfQJgjGc680qGkT1d6JfvOfeYAk6 +xn5RqS/h8rYAYm64KnepfC9vIujo4NqpaREDmaLdX5MJPQ+SlytITQvgUsUq3q/t +Ss85xjQEZH3hzwjQqdJvmA4hYP6SUjxYpBM+02xZ1Xw= +-----END RSA PRIVATE KEY-----`), +		plainDER: ` +MIIBOwIBAAJBAMGcRrZiNNmtF20zyS6MQ7pdGx17aFDl+lTl+qnLuJRUCMUG05xs +OmxmL/O1Qlf+bnqR8Bgg65SfKg21SYuLhiMCAwEAAQJBAL94uuHyO4wux2VC+qpj +IzPykjdU7XRcDHbbvksf4xokSeUFjjD3PB0Qa83M94y89ZfdILIqS9x5EgSB4/lX +qNkCIQD6cCIqLfzq/lYbZbQgAAjpBXeQVYsbvVtJrPrXJAlVVQIhAMXpDKMeFPMn +J0g2rbx1gngx0qOa5r5iMU5w/noN4W2XAiBjf+WzCG5yFvazD+dOx3TC0A8+4x3P +uZ3pWbaXf5PNuQIgAcdXarvhelH2w2piY1g3BPeFqhzBSCK/yLGxR82KIh8CIQDD ++qGKsd09NhQ/G27y/DARzOYtml1NvdmCQAgsDIIOLA==`, +	}, +	{ +		kind:     PEMCipherAES256, +		password: []byte("asdf"), +		pemData: []byte(` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-256-CBC,8E7ED5CD731902CE938957A886A5FFBD + +4Mxr+KIzRVwoOP0wwq6caSkvW0iS+GE2h2Ov/u+n9ZTMwL83PRnmjfjzBgfRZLVf +JFPXxUK26kMNpIdssNnqGOds+DhB+oSrsNKoxgxSl5OBoYv9eJTVYm7qOyAFIsjr +DRKAcjYCmzfesr7PVTowwy0RtHmYwyXMGDlAzzZrEvaiySFFmMyKKvtoavwaFoc7 +Pz3RZScwIuubzTGJ1x8EzdffYOsdCa9Mtgpp3L136+23dOd6L/qK2EG2fzrJSHs/ +2XugkleBFSMKzEp9mxXKRfa++uidQvMZTFLDK9w5YjrRvMBo/l2BoZIsq0jAIE1N +sv5Z/KwlX+3MDEpPQpUwGPlGGdLnjI3UZ+cjgqBcoMiNc6HfgbBgYJSU6aDSHuCk +clCwByxWkBNgJ2GrkwNrF26v+bGJJJNR4SKouY1jQf0= +-----END RSA PRIVATE KEY-----`), +		plainDER: ` +MIIBOgIBAAJBAKy3GFkstoCHIEeUU/qO8207m8WSrjksR+p9B4tf1w5k+2O1V/GY +AQ5WFCApItcOkQe/I0yZZJk/PmCqMzSxrc8CAwEAAQJAOCAz0F7AW9oNelVQSP8F +Sfzx7O1yom+qWyAQQJF/gFR11gpf9xpVnnyu1WxIRnDUh1LZwUsjwlDYb7MB74id +oQIhANPcOiLwOPT4sIUpRM5HG6BF1BI7L77VpyGVk8xNP7X/AiEA0LMHZtk4I+lJ +nClgYp4Yh2JZ1Znbu7IoQMCEJCjwKDECIGd8Dzm5tViTkUW6Hs3Tlf73nNs65duF +aRnSglss8I3pAiEAonEnKruawgD8RavDFR+fUgmQiPz4FnGGeVgfwpGG1JECIBYq +PXHYtPqxQIbD2pScR5qum7iGUh11lEUPkmt+2uqS`, +	}, +	{ +		// generated with: +		// openssl genrsa -aes128 -passout pass:asdf -out server.orig.key 128 +		kind:     PEMCipherAES128, +		password: []byte("asdf"), +		pemData: []byte(` +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7 + +6ei/MlytjE0FFgZOGQ+jrwomKfpl8kdefeE0NSt/DMRrw8OacHAzBNi3pPEa0eX3 +eND9l7C9meCirWovjj9QWVHrXyugFuDIqgdhQ8iHTgCfF3lrmcttVrbIfMDw+smD +hTP8O1mS/MHl92NE0nhv0w== +-----END RSA PRIVATE KEY-----`), +		plainDER: ` +MGMCAQACEQC6ssxmYuauuHGOCDAI54RdAgMBAAECEQCWIn6Yv2O+kBcDF7STctKB +AgkA8SEfu/2i3g0CCQDGNlXbBHX7kQIIK3Ww5o0cYbECCQDCimPb0dYGsQIIeQ7A +jryIst8=`, +	}, +} diff --git a/src/pkg/crypto/x509/pkcs8.go b/src/pkg/crypto/x509/pkcs8.go index 4d8e0518e..30caacb3c 100644 --- a/src/pkg/crypto/x509/pkcs8.go +++ b/src/pkg/crypto/x509/pkcs8.go @@ -11,8 +11,9 @@ import (  	"fmt"  ) -// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See  -// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn. +// pkcs8 reflects an ASN.1, PKCS#8 PrivateKey. See +// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn +// and RFC5208.  type pkcs8 struct {  	Version    int  	Algo       pkix.AlgorithmIdentifier @@ -21,19 +22,32 @@ type pkcs8 struct {  }  // ParsePKCS8PrivateKey parses an unencrypted, PKCS#8 private key. See -// http://www.rsa.com/rsalabs/node.asp?id=2130 +// http://www.rsa.com/rsalabs/node.asp?id=2130 and RFC5208.  func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) {  	var privKey pkcs8  	if _, err := asn1.Unmarshal(der, &privKey); err != nil {  		return nil, err  	}  	switch { -	case privKey.Algo.Algorithm.Equal(oidRSA): +	case privKey.Algo.Algorithm.Equal(oidPublicKeyRSA):  		key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)  		if err != nil {  			return nil, errors.New("crypto/x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())  		}  		return key, nil + +	case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA): +		bytes := privKey.Algo.Parameters.FullBytes +		namedCurveOID := new(asn1.ObjectIdentifier) +		if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil { +			namedCurveOID = nil +		} +		key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey) +		if err != nil { +			return nil, errors.New("crypto/x509: failed to parse EC private key embedded in PKCS#8: " + err.Error()) +		} +		return key, nil +  	default:  		return nil, fmt.Errorf("crypto/x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)  	} diff --git a/src/pkg/crypto/x509/pkcs8_test.go b/src/pkg/crypto/x509/pkcs8_test.go index 372005f90..4114efd0e 100644 --- a/src/pkg/crypto/x509/pkcs8_test.go +++ b/src/pkg/crypto/x509/pkcs8_test.go @@ -9,12 +9,20 @@ import (  	"testing"  ) -var pkcs8PrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031` +var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031` + +// Generated using: +//   openssl ecparam -genkey -name secp521r1 | openssl pkcs8 -topk8 -nocrypt +var pkcs8ECPrivateKeyHex = `3081ed020100301006072a8648ce3d020106052b810400230481d53081d20201010441850d81618c5da1aec74c2eed608ba816038506975e6427237c2def150c96a3b13efbfa1f89f1be15cdf4d0ac26422e680e65a0ddd4ad3541ad76165fbf54d6e34ba18189038186000400da97bcedba1eb6d30aeb93c9f9a1454598fa47278df27d6f60ea73eb672d8dc528a9b67885b5b5dcef93c9824f7449ab512ee6a27e76142f56b94b474cfd697e810046c8ca70419365245c1d7d44d0db82c334073835d002232714548abbae6e5700f5ef315ee08b929d8581383dcf2d1c98c2f8a9fccbf79c9579f7b2fd8a90115ac2`  func TestPKCS8(t *testing.T) { -	derBytes, _ := hex.DecodeString(pkcs8PrivateKeyHex) -	_, err := ParsePKCS8PrivateKey(derBytes) -	if err != nil { -		t.Errorf("failed to decode PKCS8 key: %s", err) +	derBytes, _ := hex.DecodeString(pkcs8RSAPrivateKeyHex) +	if _, err := ParsePKCS8PrivateKey(derBytes); err != nil { +		t.Errorf("failed to decode PKCS8 with RSA private key: %s", err) +	} + +	derBytes, _ = hex.DecodeString(pkcs8ECPrivateKeyHex) +	if _, err := ParsePKCS8PrivateKey(derBytes); err != nil { +		t.Errorf("failed to decode PKCS8 with EC private key: %s", err)  	}  } diff --git a/src/pkg/crypto/x509/root_darwin.go b/src/pkg/crypto/x509/root_darwin.go index 0f99581e8..ad3bfb4b4 100644 --- a/src/pkg/crypto/x509/root_darwin.go +++ b/src/pkg/crypto/x509/root_darwin.go @@ -70,11 +70,12 @@ func initSystemRoots() {  	var data C.CFDataRef = nil  	err := C.FetchPEMRoots(&data) -	if err != -1 { -		defer C.CFRelease(C.CFTypeRef(data)) -		buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) -		roots.AppendCertsFromPEM(buf) +	if err == -1 { +		return  	} +	defer C.CFRelease(C.CFTypeRef(data)) +	buf := C.GoBytes(unsafe.Pointer(C.CFDataGetBytePtr(data)), C.int(C.CFDataGetLength(data))) +	roots.AppendCertsFromPEM(buf)  	systemRoots = roots  } diff --git a/src/pkg/crypto/x509/root_plan9.go b/src/pkg/crypto/x509/root_plan9.go new file mode 100644 index 000000000..9965caade --- /dev/null +++ b/src/pkg/crypto/x509/root_plan9.go @@ -0,0 +1,33 @@ +// Copyright 2012 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 plan9 + +package x509 + +import "io/ioutil" + +// Possible certificate files; stop after finding one. +var certFiles = []string{ +	"/sys/lib/tls/ca.pem", +} + +func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) { +	return nil, nil +} + +func initSystemRoots() { +	roots := NewCertPool() +	for _, file := range certFiles { +		data, err := ioutil.ReadFile(file) +		if err == nil { +			roots.AppendCertsFromPEM(data) +			systemRoots = roots +			return +		} +	} + +	// All of the files failed to load. systemRoots will be nil which will +	// trigger a specific error at verification time. +} diff --git a/src/pkg/crypto/x509/root_stub.go b/src/pkg/crypto/x509/root_stub.go index 568004108..4c742ccc3 100644 --- a/src/pkg/crypto/x509/root_stub.go +++ b/src/pkg/crypto/x509/root_stub.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 plan9 darwin,!cgo +// +build darwin,!cgo  package x509 @@ -11,5 +11,4 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate  }  func initSystemRoots() { -	systemRoots = NewCertPool()  } diff --git a/src/pkg/crypto/x509/root_unix.go b/src/pkg/crypto/x509/root_unix.go index 76e79f494..1b25a94d0 100644 --- a/src/pkg/crypto/x509/root_unix.go +++ b/src/pkg/crypto/x509/root_unix.go @@ -27,9 +27,11 @@ func initSystemRoots() {  		data, err := ioutil.ReadFile(file)  		if err == nil {  			roots.AppendCertsFromPEM(data) -			break +			systemRoots = roots +			return  		}  	} -	systemRoots = roots +	// All of the files failed to load. systemRoots will be nil which will +	// trigger a specific error at verification time.  } diff --git a/src/pkg/crypto/x509/root_windows.go b/src/pkg/crypto/x509/root_windows.go index 7e8f2af4b..e8f70a49d 100644 --- a/src/pkg/crypto/x509/root_windows.go +++ b/src/pkg/crypto/x509/root_windows.go @@ -98,9 +98,13 @@ func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) e  // checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for  // use as a certificate chain for a SSL/TLS server.  func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error { +	servernamep, err := syscall.UTF16PtrFromString(opts.DNSName) +	if err != nil { +		return err +	}  	sslPara := &syscall.SSLExtraCertChainPolicyPara{  		AuthType:   syscall.AUTHTYPE_SERVER, -		ServerName: syscall.StringToUTF16Ptr(opts.DNSName), +		ServerName: servernamep,  	}  	sslPara.Size = uint32(unsafe.Sizeof(*sslPara)) @@ -110,7 +114,7 @@ func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContex  	para.Size = uint32(unsafe.Sizeof(*para))  	status := syscall.CertChainPolicyStatus{} -	err := syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status) +	err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)  	if err != nil {  		return err  	} @@ -222,5 +226,4 @@ func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate  }  func initSystemRoots() { -	systemRoots = NewCertPool()  } diff --git a/src/pkg/crypto/x509/sec1.go b/src/pkg/crypto/x509/sec1.go new file mode 100644 index 000000000..8a2840fbe --- /dev/null +++ b/src/pkg/crypto/x509/sec1.go @@ -0,0 +1,69 @@ +// Copyright 2012 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 x509 + +import ( +	"crypto/ecdsa" +	"crypto/elliptic" +	"encoding/asn1" +	"errors" +	"fmt" +	"math/big" +) + +const ecPrivKeyVersion = 1 + +// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure. +// References: +//   RFC5915 +//   SEC1 - http://www.secg.org/download/aid-780/sec1-v2.pdf +// Per RFC5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in +// most cases it is not. +type ecPrivateKey struct { +	Version       int +	PrivateKey    []byte +	NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"` +	PublicKey     asn1.BitString        `asn1:"optional,explicit,tag:1"` +} + +// ParseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. +func ParseECPrivateKey(der []byte) (key *ecdsa.PrivateKey, err error) { +	return parseECPrivateKey(nil, der) +} + +// parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure. +// The OID for the named curve may be provided from another source (such as +// the PKCS8 container) - if it is provided then use this instead of the OID +// that may exist in the EC private key structure. +func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) { +	var privKey ecPrivateKey +	if _, err := asn1.Unmarshal(der, &privKey); err != nil { +		return nil, errors.New("crypto/x509: failed to parse EC private key: " + err.Error()) +	} +	if privKey.Version != ecPrivKeyVersion { +		return nil, fmt.Errorf("crypto/x509: unknown EC private key version %d", privKey.Version) +	} + +	var curve elliptic.Curve +	if namedCurveOID != nil { +		curve = namedCurveFromOID(*namedCurveOID) +	} else { +		curve = namedCurveFromOID(privKey.NamedCurveOID) +	} +	if curve == nil { +		return nil, errors.New("crypto/x509: unknown elliptic curve") +	} + +	k := new(big.Int).SetBytes(privKey.PrivateKey) +	if k.Cmp(curve.Params().N) >= 0 { +		return nil, errors.New("crypto/x509: invalid elliptic curve private key value") +	} +	priv := new(ecdsa.PrivateKey) +	priv.Curve = curve +	priv.D = k +	priv.X, priv.Y = curve.ScalarBaseMult(privKey.PrivateKey) + +	return priv, nil +} diff --git a/src/pkg/crypto/x509/sec1_test.go b/src/pkg/crypto/x509/sec1_test.go new file mode 100644 index 000000000..7135699d2 --- /dev/null +++ b/src/pkg/crypto/x509/sec1_test.go @@ -0,0 +1,22 @@ +// Copyright 2012 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 x509 + +import ( +	"encoding/hex" +	"testing" +) + +// Generated using: +//   openssl ecparam -genkey -name secp384r1 -outform PEM +var ecPrivateKeyHex = `3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50` + +func TestParseECPrivateKey(t *testing.T) { +	derBytes, _ := hex.DecodeString(ecPrivateKeyHex) +	_, err := ParseECPrivateKey(derBytes) +	if err != nil { +		t.Errorf("failed to decode EC private key: %s", err) +	} +} diff --git a/src/pkg/crypto/x509/verify.go b/src/pkg/crypto/x509/verify.go index 307c5ef03..b29ddbc80 100644 --- a/src/pkg/crypto/x509/verify.go +++ b/src/pkg/crypto/x509/verify.go @@ -5,6 +5,7 @@  package x509  import ( +	"net"  	"runtime"  	"strings"  	"time" @@ -27,6 +28,9 @@ const (  	// TooManyIntermediates results when a path length constraint is  	// violated.  	TooManyIntermediates +	// IncompatibleUsage results when the certificate's key usage indicates +	// that it may only be used for a different purpose. +	IncompatibleUsage  )  // CertificateInvalidError results when an odd error occurs. Users of this @@ -39,13 +43,15 @@ type CertificateInvalidError struct {  func (e CertificateInvalidError) Error() string {  	switch e.Reason {  	case NotAuthorizedToSign: -		return "x509: certificate is not authorized to sign other other certificates" +		return "x509: certificate is not authorized to sign other certificates"  	case Expired:  		return "x509: certificate has expired or is not yet valid"  	case CANotAuthorizedForThisName:  		return "x509: a root or intermediate certificate is not authorized to sign in this domain"  	case TooManyIntermediates:  		return "x509: too many intermediates for path length constraint" +	case IncompatibleUsage: +		return "x509: certificate specifies an incompatible key usage"  	}  	return "x509: unknown error"  } @@ -58,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 @@ -77,6 +97,14 @@ func (e UnknownAuthorityError) Error() string {  	return "x509: certificate signed by unknown authority"  } +// SystemRootsError results when we fail to load the system root certificates. +type SystemRootsError struct { +} + +func (e SystemRootsError) Error() string { +	return "x509: failed to load system roots and no roots provided" +} +  // VerifyOptions contains parameters for Certificate.Verify. It's a structure  // because other PKIX verification APIs have ended up needing many options.  type VerifyOptions struct { @@ -84,6 +112,11 @@ type VerifyOptions struct {  	Intermediates *CertPool  	Roots         *CertPool // if nil, the system roots are used  	CurrentTime   time.Time // if zero, the current time is used +	// KeyUsage specifies which Extended Key Usage values are acceptable. +	// An empty list means ExtKeyUsageServerAuth. Key usage is considered a +	// constraint down the chain which mirrors Windows CryptoAPI behaviour, +	// but not the spec. To accept any key usage, include ExtKeyUsageAny. +	KeyUsages []ExtKeyUsage  }  const ( @@ -160,6 +193,9 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e  	if opts.Roots == nil {  		opts.Roots = systemRootsPool() +		if opts.Roots == nil { +			return nil, SystemRootsError{} +		}  	}  	err = c.isValid(leafCertificate, nil, &opts) @@ -174,7 +210,35 @@ func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err e  		}  	} -	return c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts) +	candidateChains, err := c.buildChains(make(map[int][][]*Certificate), []*Certificate{c}, &opts) +	if err != nil { +		return +	} + +	keyUsages := opts.KeyUsages +	if len(keyUsages) == 0 { +		keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth} +	} + +	// If any key usage is acceptable then we're done. +	for _, usage := range keyUsages { +		if usage == ExtKeyUsageAny { +			chains = candidateChains +			return +		} +	} + +	for _, candidate := range candidateChains { +		if checkChainForKeyUsage(candidate, keyUsages) { +			chains = append(chains, candidate) +		} +	} + +	if len(chains) == 0 { +		err = CertificateInvalidError{c, IncompatibleUsage} +	} + +	return  }  func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate { @@ -285,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 { @@ -300,3 +380,64 @@ func (c *Certificate) VerifyHostname(h string) error {  	return HostnameError{c, h}  } + +func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool { +	usages := make([]ExtKeyUsage, len(keyUsages)) +	copy(usages, keyUsages) + +	if len(chain) == 0 { +		return false +	} + +	usagesRemaining := len(usages) + +	// We walk down the list and cross out any usages that aren't supported +	// by each certificate. If we cross out all the usages, then the chain +	// is unacceptable. + +	for i := len(chain) - 1; i >= 0; i-- { +		cert := chain[i] +		if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 { +			// The certificate doesn't have any extended key usage specified. +			continue +		} + +		for _, usage := range cert.ExtKeyUsage { +			if usage == ExtKeyUsageAny { +				// The certificate is explicitly good for any usage. +				continue +			} +		} + +		const invalidUsage ExtKeyUsage = -1 + +	NextRequestedUsage: +		for i, requestedUsage := range usages { +			if requestedUsage == invalidUsage { +				continue +			} + +			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 +				} +			} + +			usages[i] = invalidUsage +			usagesRemaining-- +			if usagesRemaining == 0 { +				return false +			} +		} +	} + +	return true +} diff --git a/src/pkg/crypto/x509/verify_test.go b/src/pkg/crypto/x509/verify_test.go index 7b171b291..5103ed814 100644 --- a/src/pkg/crypto/x509/verify_test.go +++ b/src/pkg/crypto/x509/verify_test.go @@ -15,12 +15,14 @@ import (  )  type verifyTest struct { -	leaf          string -	intermediates []string -	roots         []string -	currentTime   int64 -	dnsName       string -	systemSkip    bool +	leaf                 string +	intermediates        []string +	roots                []string +	currentTime          int64 +	dnsName              string +	systemSkip           bool +	keyUsages            []ExtKeyUsage +	testSystemRootsError bool  	errorCallback  func(*testing.T, int, error) bool  	expectedChains [][]string @@ -28,6 +30,17 @@ type verifyTest struct {  var verifyTests = []verifyTest{  	{ +		leaf:                 googleLeaf, +		intermediates:        []string{thawteIntermediate}, +		currentTime:          1302726541, +		dnsName:              "www.google.com", +		testSystemRootsError: true, + +		// Without any roots specified we should get a system roots +		// error. +		errorCallback: expectSystemRootsError, +	}, +	{  		leaf:          googleLeaf,  		intermediates: []string{thawteIntermediate},  		roots:         []string{verisignRoot}, @@ -113,6 +126,51 @@ var verifyTests = []verifyTest{  			{"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority", "StartCom Certification Authority"},  		},  	}, +	{ +		// The default configuration should reject an S/MIME chain. +		leaf:        smimeLeaf, +		roots:       []string{smimeIntermediate}, +		currentTime: 1339436154, + +		// Key usage not implemented for Windows yet. +		systemSkip:    true, +		errorCallback: expectUsageError, +	}, +	{ +		leaf:        smimeLeaf, +		roots:       []string{smimeIntermediate}, +		currentTime: 1339436154, +		keyUsages:   []ExtKeyUsage{ExtKeyUsageServerAuth}, + +		// Key usage not implemented for Windows yet. +		systemSkip:    true, +		errorCallback: expectUsageError, +	}, +	{ +		leaf:        smimeLeaf, +		roots:       []string{smimeIntermediate}, +		currentTime: 1339436154, +		keyUsages:   []ExtKeyUsage{ExtKeyUsageEmailProtection}, + +		// Key usage not implemented for Windows yet. +		systemSkip: true, +		expectedChains: [][]string{ +			{"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) { @@ -131,6 +189,14 @@ func expectExpired(t *testing.T, i int, err error) (ok bool) {  	return true  } +func expectUsageError(t *testing.T, i int, err error) (ok bool) { +	if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != IncompatibleUsage { +		t.Errorf("#%d: error was not IncompatibleUsage: %s", i, err) +		return false +	} +	return true +} +  func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) {  	if _, ok := err.(UnknownAuthorityError); !ok {  		t.Errorf("#%d: error was not UnknownAuthorityError: %s", i, err) @@ -139,6 +205,14 @@ func expectAuthorityUnknown(t *testing.T, i int, err error) (ok bool) {  	return true  } +func expectSystemRootsError(t *testing.T, i int, err error) bool { +	if _, ok := err.(SystemRootsError); !ok { +		t.Errorf("#%d: error was not SystemRootsError: %s", i, err) +		return false +	} +	return true +} +  func certificateFromPEM(pemBytes string) (*Certificate, error) {  	block, _ := pem.Decode([]byte(pemBytes))  	if block == nil { @@ -152,11 +226,15 @@ func testVerify(t *testing.T, useSystemRoots bool) {  		if useSystemRoots && test.systemSkip {  			continue  		} +		if runtime.GOOS == "windows" && test.testSystemRootsError { +			continue +		}  		opts := VerifyOptions{  			Intermediates: NewCertPool(),  			DNSName:       test.dnsName,  			CurrentTime:   time.Unix(test.currentTime, 0), +			KeyUsages:     test.keyUsages,  		}  		if !useSystemRoots { @@ -184,8 +262,19 @@ func testVerify(t *testing.T, useSystemRoots bool) {  			return  		} +		var oldSystemRoots *CertPool +		if test.testSystemRootsError { +			oldSystemRoots = systemRootsPool() +			systemRoots = nil +			opts.Roots = nil +		} +  		chains, err := leaf.Verify(opts) +		if test.testSystemRootsError { +			systemRoots = oldSystemRoots +		} +  		if test.errorCallback == nil && err != nil {  			t.Errorf("#%d: unexpected error: %s", i, err)  		} @@ -233,8 +322,7 @@ func TestGoVerify(t *testing.T) {  func TestSystemVerify(t *testing.T) {  	if runtime.GOOS != "windows" { -		t.Logf("skipping verify test using system APIs on %q", runtime.GOOS) -		return +		t.Skipf("skipping verify test using system APIs on %q", runtime.GOOS)  	}  	testVerify(t, true) @@ -433,3 +521,145 @@ O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V  um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh  NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=  -----END CERTIFICATE-----` + +const smimeLeaf = `-----BEGIN CERTIFICATE----- +MIIFBjCCA+6gAwIBAgISESFvrjT8XcJTEe6rBlPptILlMA0GCSqGSIb3DQEBBQUA +MFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMSowKAYD +VQQDEyFHbG9iYWxTaWduIFBlcnNvbmFsU2lnbiAyIENBIC0gRzIwHhcNMTIwMTIz +MTYzNjU5WhcNMTUwMTIzMTYzNjU5WjCBlDELMAkGA1UEBhMCVVMxFjAUBgNVBAgT +DU5ldyBIYW1zcGhpcmUxEzARBgNVBAcTClBvcnRzbW91dGgxGTAXBgNVBAoTEEds +b2JhbFNpZ24sIEluYy4xEzARBgNVBAMTClJ5YW4gSHVyc3QxKDAmBgkqhkiG9w0B +CQEWGXJ5YW4uaHVyc3RAZ2xvYmFsc2lnbi5jb20wggEiMA0GCSqGSIb3DQEBAQUA +A4IBDwAwggEKAoIBAQC4ASSTvavmsFQAob60ukSSwOAL9nT/s99ltNUCAf5fPH5j +NceMKxaQse2miOmRRIXaykcq1p/TbI70Ztce38r2mbOwqDHHPVi13GxJEyUXWgaR +BteDMu5OGyWNG1kchVsGWpbstT0Z4v0md5m1BYFnxB20ebJyOR2lXDxsFK28nnKV ++5eMj76U8BpPQ4SCH7yTMG6y0XXsB3cCrBKr2o3TOYgEKv+oNnbaoMt3UxMt9nSf +9jyIshjqfnT5Aew3CUNMatO55g5FXXdIukAweg1YSb1ls05qW3sW00T3d7dQs9/7 +NuxCg/A2elmVJSoy8+MLR8JSFEf/aMgjO/TyLg/jAgMBAAGjggGPMIIBizAOBgNV +HQ8BAf8EBAMCBaAwTQYDVR0gBEYwRDBCBgorBgEEAaAyASgKMDQwMgYIKwYBBQUH +AgEWJmh0dHBzOi8vd3d3Lmdsb2JhbHNpZ24uY29tL3JlcG9zaXRvcnkvMCQGA1Ud +EQQdMBuBGXJ5YW4uaHVyc3RAZ2xvYmFsc2lnbi5jb20wCQYDVR0TBAIwADAdBgNV +HSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwQwYDVR0fBDwwOjA4oDagNIYyaHR0 +cDovL2NybC5nbG9iYWxzaWduLmNvbS9ncy9nc3BlcnNvbmFsc2lnbjJnMi5jcmww +VQYIKwYBBQUHAQEESTBHMEUGCCsGAQUFBzAChjlodHRwOi8vc2VjdXJlLmdsb2Jh +bHNpZ24uY29tL2NhY2VydC9nc3BlcnNvbmFsc2lnbjJnMi5jcnQwHQYDVR0OBBYE +FFWiECe0/L72eVYqcWYnLV6SSjzhMB8GA1UdIwQYMBaAFD8V0m18L+cxnkMKBqiU +bCw7xe5lMA0GCSqGSIb3DQEBBQUAA4IBAQAhQi6hLPeudmf3IBF4IDzCvRI0FaYd +BKfprSk/H0PDea4vpsLbWpA0t0SaijiJYtxKjlM4bPd+2chb7ejatDdyrZIzmDVy +q4c30/xMninGKokpYA11/Ve+i2dvjulu65qasrtQRGybAuuZ67lrp/K3OMFgjV5N +C3AHYLzvNU4Dwc4QQ1BaMOg6KzYSrKbABRZajfrpC9uiePsv7mDIXLx/toBPxWNl +a5vJm5DrZdn7uHdvBCE6kMykbOLN5pmEK0UIlwKh6Qi5XD0pzlVkEZliFkBMJgub +d/eF7xeg7TKPWC5xyOFp9SdMolJM7LTC3wnSO3frBAev+q/nGs9Xxyvs +-----END CERTIFICATE-----` + +const smimeIntermediate = `-----BEGIN CERTIFICATE----- +MIIEFjCCAv6gAwIBAgILBAAAAAABL07hL1IwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMTA0MTMxMDAw +MDBaFw0xOTA0MTMxMDAwMDBaMFQxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMSowKAYDVQQDEyFHbG9iYWxTaWduIFBlcnNvbmFsU2lnbiAy +IENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBa0H5Nez4 +En3dIlFpX7e5E0YndxQ74xOBbz7kdBd+DLX0LOQMjVPU3DAgKL9ujhH+ZhHkURbH +3X/94TQSUL/z2JjsaQvS0NqyZXHhM5eeuquzOJRzEQ8+odETzHg2G0Erv7yjSeww +gkwDWDJnYUDlOjYTDUEG6+i+8Mn425reo4I0E277wD542kmVWeW7+oHv5dZo9e1Q +yWwiKTEP6BEQVVSBgThXMG4traSSDRUt3T1eQTZx5EObpiBEBO4OTqiBTJfg4vEI +YgkXzKLpnfszTB6YMDpR9/QS6p3ANB3kfAb+t6udSO3WCst0DGrwHDLBFGDR4UeY +T5KGGnI7cWL7AgMBAAGjgeUwgeIwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQI +MAYBAf8CAQAwHQYDVR0OBBYEFD8V0m18L+cxnkMKBqiUbCw7xe5lMEcGA1UdIARA +MD4wPAYEVR0gADA0MDIGCCsGAQUFBwIBFiZodHRwczovL3d3dy5nbG9iYWxzaWdu +LmNvbS9yZXBvc2l0b3J5LzAzBgNVHR8ELDAqMCigJqAkhiJodHRwOi8vY3JsLmds +b2JhbHNpZ24ubmV0L3Jvb3QuY3JsMB8GA1UdIwQYMBaAFGB7ZhpFDZfKiVAvfQTN +NKj//P1LMA0GCSqGSIb3DQEBBQUAA4IBAQBDc3nMpMxJMQMcYUCB3+C73UpvwDE8 +eCOr7t2F/uaQKKcyqqstqLZc6vPwI/rcE9oDHugY5QEjQzIBIEaTnN6P0vege2IX +eCOr7t2F/uaQKKcyqqstqLZc6vPwI/rcE9oDHugY5QEjQzIBIEaTnN6P0vege2IX +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/src/pkg/crypto/x509/x509.go b/src/pkg/crypto/x509/x509.go index c4d85e67f..b802bf4eb 100644 --- a/src/pkg/crypto/x509/x509.go +++ b/src/pkg/crypto/x509/x509.go @@ -9,6 +9,8 @@ import (  	"bytes"  	"crypto"  	"crypto/dsa" +	"crypto/ecdsa" +	"crypto/elliptic"  	"crypto/rsa"  	"crypto/sha1"  	"crypto/x509/pkix" @@ -17,6 +19,8 @@ import (  	"errors"  	"io"  	"math/big" +	"net" +	"strconv"  	"time"  ) @@ -106,6 +110,8 @@ type dsaSignature struct {  	R, S *big.Int  } +type ecdsaSignature dsaSignature +  type validity struct {  	NotBefore, NotAfter time.Time  } @@ -133,6 +139,10 @@ const (  	SHA512WithRSA  	DSAWithSHA1  	DSAWithSHA256 +	ECDSAWithSHA1 +	ECDSAWithSHA256 +	ECDSAWithSHA384 +	ECDSAWithSHA512  )  type PublicKeyAlgorithm int @@ -141,14 +151,15 @@ const (  	UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota  	RSA  	DSA +	ECDSA  )  // OIDs for signature algorithms  //  // pkcs-1 OBJECT IDENTIFIER ::= {  //    iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } -//  -//  +// +//  // RFC 3279 2.2.1 RSA Signature Algorithms  //  // md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 } @@ -156,13 +167,19 @@ const (  // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }  //  // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } -//  +//  // dsaWithSha1 OBJECT IDENTIFIER ::= { -//    iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }  +//    iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } +// +// RFC 3279 2.2.3 ECDSA Signature Algorithm +// +// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { +// 	  iso(1) member-body(2) us(840) ansi-x962(10045) +//    signatures(4) ecdsa-with-SHA1(1)}  //  //  // RFC 4055 5 PKCS #1 Version 1.5 -//  +//  // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }  //  // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } @@ -176,15 +193,30 @@ const (  //    joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)  //    csor(3) algorithms(4) id-dsa-with-sha2(3) 2}  // +// RFC 5758 3.2 ECDSA Signature Algorithm +// +// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +//    us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } +// +// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +//    us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } +// +// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) +//    us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } +  var ( -	oidSignatureMD2WithRSA    = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} -	oidSignatureMD5WithRSA    = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} -	oidSignatureSHA1WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} -	oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} -	oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} -	oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} -	oidSignatureDSAWithSHA1   = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} -	oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2} +	oidSignatureMD2WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} +	oidSignatureMD5WithRSA      = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} +	oidSignatureSHA1WithRSA     = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} +	oidSignatureSHA256WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} +	oidSignatureSHA384WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} +	oidSignatureSHA512WithRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} +	oidSignatureDSAWithSHA1     = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} +	oidSignatureDSAWithSHA256   = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 4, 3, 2} +	oidSignatureECDSAWithSHA1   = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} +	oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} +	oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} +	oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}  )  func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm { @@ -205,6 +237,14 @@ func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm  		return DSAWithSHA1  	case oid.Equal(oidSignatureDSAWithSHA256):  		return DSAWithSHA256 +	case oid.Equal(oidSignatureECDSAWithSHA1): +		return ECDSAWithSHA1 +	case oid.Equal(oidSignatureECDSAWithSHA256): +		return ECDSAWithSHA256 +	case oid.Equal(oidSignatureECDSAWithSHA384): +		return ECDSAWithSHA384 +	case oid.Equal(oidSignatureECDSAWithSHA512): +		return ECDSAWithSHA512  	}  	return UnknownSignatureAlgorithm  } @@ -218,21 +258,81 @@ func getSignatureAlgorithmFromOID(oid asn1.ObjectIdentifier) SignatureAlgorithm  //  // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)  //    x9-57(10040) x9cm(4) 1 } +// +// RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters +// +// id-ecPublicKey OBJECT IDENTIFIER ::= { +//       iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }  var ( -	oidPublicKeyRsa = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} -	oidPublicKeyDsa = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} +	oidPublicKeyRSA   = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} +	oidPublicKeyDSA   = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} +	oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}  )  func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {  	switch { -	case oid.Equal(oidPublicKeyRsa): +	case oid.Equal(oidPublicKeyRSA):  		return RSA -	case oid.Equal(oidPublicKeyDsa): +	case oid.Equal(oidPublicKeyDSA):  		return DSA +	case oid.Equal(oidPublicKeyECDSA): +		return ECDSA  	}  	return UnknownPublicKeyAlgorithm  } +// RFC 5480, 2.1.1.1. Named Curve +// +// secp224r1 OBJECT IDENTIFIER ::= { +//   iso(1) identified-organization(3) certicom(132) curve(0) 33 } +// +// secp256r1 OBJECT IDENTIFIER ::= { +//   iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) +//   prime(1) 7 } +// +// secp384r1 OBJECT IDENTIFIER ::= { +//   iso(1) identified-organization(3) certicom(132) curve(0) 34 } +// +// secp521r1 OBJECT IDENTIFIER ::= { +//   iso(1) identified-organization(3) certicom(132) curve(0) 35 } +// +// NB: secp256r1 is equivalent to prime256v1 +var ( +	oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} +	oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} +	oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} +	oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} +) + +func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve { +	switch { +	case oid.Equal(oidNamedCurveP224): +		return elliptic.P224() +	case oid.Equal(oidNamedCurveP256): +		return elliptic.P256() +	case oid.Equal(oidNamedCurveP384): +		return elliptic.P384() +	case oid.Equal(oidNamedCurveP521): +		return elliptic.P521() +	} +	return nil +} + +func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) { +	switch curve { +	case elliptic.P224(): +		return oidNamedCurveP224, true +	case elliptic.P256(): +		return oidNamedCurveP256, true +	case elliptic.P384(): +		return oidNamedCurveP384, true +	case elliptic.P521(): +		return oidNamedCurveP521, true +	} + +	return nil, false +} +  // KeyUsage represents the set of actions that are valid for a given key. It's  // a bitmap of the KeyUsage* constants.  type KeyUsage int @@ -262,13 +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} -	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. @@ -281,10 +386,52 @@ const (  	ExtKeyUsageClientAuth  	ExtKeyUsageCodeSigning  	ExtKeyUsageEmailProtection +	ExtKeyUsageIPSECEndSystem +	ExtKeyUsageIPSECTunnel +	ExtKeyUsageIPSECUser  	ExtKeyUsageTimeStamping  	ExtKeyUsageOCSPSigning +	ExtKeyUsageMicrosoftServerGatedCrypto +	ExtKeyUsageNetscapeServerGatedCrypto  ) +// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. +var extKeyUsageOIDs = []struct { +	extKeyUsage ExtKeyUsage +	oid         asn1.ObjectIdentifier +}{ +	{ExtKeyUsageAny, oidExtKeyUsageAny}, +	{ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth}, +	{ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth}, +	{ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning}, +	{ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection}, +	{ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem}, +	{ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel}, +	{ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, +	{ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, +	{ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, +	{ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, +	{ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, +} + +func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) { +	for _, pair := range extKeyUsageOIDs { +		if oid.Equal(pair.oid) { +			return pair.extKeyUsage, true +		} +	} +	return +} + +func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) { +	for _, pair := range extKeyUsageOIDs { +		if eku == pair.extKeyUsage { +			return pair.oid, true +		} +	} +	return +} +  // A Certificate represents an X.509 certificate.  type Certificate struct {  	Raw                     []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). @@ -319,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. @@ -344,6 +492,55 @@ func (c *Certificate) Equal(other *Certificate) bool {  	return bytes.Equal(c.Raw, other.Raw)  } +// 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. +// We recognise this certificate by its SubjectPublicKeyInfo and exempt it +// from the Basic Constraints requirement. +// See http://www.entrust.net/knowledge-base/technote.cfm?tn=7869 +// +// TODO(agl): remove this hack once their reissued root is sufficiently +// widespread. +var entrustBrokenSPKI = []byte{ +	0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, +	0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, +	0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, +	0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, +	0x00, 0x97, 0xa3, 0x2d, 0x3c, 0x9e, 0xde, 0x05, +	0xda, 0x13, 0xc2, 0x11, 0x8d, 0x9d, 0x8e, 0xe3, +	0x7f, 0xc7, 0x4b, 0x7e, 0x5a, 0x9f, 0xb3, 0xff, +	0x62, 0xab, 0x73, 0xc8, 0x28, 0x6b, 0xba, 0x10, +	0x64, 0x82, 0x87, 0x13, 0xcd, 0x57, 0x18, 0xff, +	0x28, 0xce, 0xc0, 0xe6, 0x0e, 0x06, 0x91, 0x50, +	0x29, 0x83, 0xd1, 0xf2, 0xc3, 0x2a, 0xdb, 0xd8, +	0xdb, 0x4e, 0x04, 0xcc, 0x00, 0xeb, 0x8b, 0xb6, +	0x96, 0xdc, 0xbc, 0xaa, 0xfa, 0x52, 0x77, 0x04, +	0xc1, 0xdb, 0x19, 0xe4, 0xae, 0x9c, 0xfd, 0x3c, +	0x8b, 0x03, 0xef, 0x4d, 0xbc, 0x1a, 0x03, 0x65, +	0xf9, 0xc1, 0xb1, 0x3f, 0x72, 0x86, 0xf2, 0x38, +	0xaa, 0x19, 0xae, 0x10, 0x88, 0x78, 0x28, 0xda, +	0x75, 0xc3, 0x3d, 0x02, 0x82, 0x02, 0x9c, 0xb9, +	0xc1, 0x65, 0x77, 0x76, 0x24, 0x4c, 0x98, 0xf7, +	0x6d, 0x31, 0x38, 0xfb, 0xdb, 0xfe, 0xdb, 0x37, +	0x02, 0x76, 0xa1, 0x18, 0x97, 0xa6, 0xcc, 0xde, +	0x20, 0x09, 0x49, 0x36, 0x24, 0x69, 0x42, 0xf6, +	0xe4, 0x37, 0x62, 0xf1, 0x59, 0x6d, 0xa9, 0x3c, +	0xed, 0x34, 0x9c, 0xa3, 0x8e, 0xdb, 0xdc, 0x3a, +	0xd7, 0xf7, 0x0a, 0x6f, 0xef, 0x2e, 0xd8, 0xd5, +	0x93, 0x5a, 0x7a, 0xed, 0x08, 0x49, 0x68, 0xe2, +	0x41, 0xe3, 0x5a, 0x90, 0xc1, 0x86, 0x55, 0xfc, +	0x51, 0x43, 0x9d, 0xe0, 0xb2, 0xc4, 0x67, 0xb4, +	0xcb, 0x32, 0x31, 0x25, 0xf0, 0x54, 0x9f, 0x4b, +	0xd1, 0x6f, 0xdb, 0xd4, 0xdd, 0xfc, 0xaf, 0x5e, +	0x6c, 0x78, 0x90, 0x95, 0xde, 0xca, 0x3a, 0x48, +	0xb9, 0x79, 0x3c, 0x9b, 0x19, 0xd6, 0x75, 0x05, +	0xa0, 0xf9, 0x88, 0xd7, 0xc1, 0xe8, 0xa5, 0x09, +	0xe4, 0x1a, 0x15, 0xdc, 0x87, 0x23, 0xaa, 0xb2, +	0x75, 0x8c, 0x63, 0x25, 0x87, 0xd8, 0xf8, 0x3d, +	0xa6, 0xc2, 0xcc, 0x66, 0xff, 0xa5, 0x66, 0x68, +	0x55, 0x02, 0x03, 0x01, 0x00, 0x01, +} +  // CheckSignatureFrom verifies that the signature on c is a valid signature  // from parent.  func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) { @@ -352,8 +549,10 @@ func (c *Certificate) CheckSignatureFrom(parent *Certificate) (err error) {  	// certificate, or the extension is present but the cA boolean is not  	// asserted, then the certified public key MUST NOT be used to verify  	// certificate signatures." -	if parent.Version == 3 && !parent.BasicConstraintsValid || -		parent.BasicConstraintsValid && !parent.IsCA { +	// (except for Entrust, see comment above entrustBrokenSPKI) +	if (parent.Version == 3 && !parent.BasicConstraintsValid || +		parent.BasicConstraintsValid && !parent.IsCA) && +		!bytes.Equal(c.RawSubjectPublicKeyInfo, entrustBrokenSPKI) {  		return ConstraintViolationError{}  	} @@ -376,13 +575,13 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature  	var hashType crypto.Hash  	switch algo { -	case SHA1WithRSA, DSAWithSHA1: +	case SHA1WithRSA, DSAWithSHA1, ECDSAWithSHA1:  		hashType = crypto.SHA1 -	case SHA256WithRSA, DSAWithSHA256: +	case SHA256WithRSA, DSAWithSHA256, ECDSAWithSHA256:  		hashType = crypto.SHA256 -	case SHA384WithRSA: +	case SHA384WithRSA, ECDSAWithSHA384:  		hashType = crypto.SHA384 -	case SHA512WithRSA: +	case SHA512WithRSA, ECDSAWithSHA512:  		hashType = crypto.SHA512  	default:  		return ErrUnsupportedAlgorithm @@ -411,6 +610,18 @@ func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature  			return errors.New("DSA verification failure")  		}  		return +	case *ecdsa.PublicKey: +		ecdsaSig := new(ecdsaSignature) +		if _, err := asn1.Unmarshal(signature, ecdsaSig); err != nil { +			return err +		} +		if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 { +			return errors.New("crypto/x509: ECDSA signature contained zero or negative values") +		} +		if !ecdsa.Verify(pub, digest, ecdsaSig.R, ecdsaSig.S) { +			return errors.New("crypto/x509: ECDSA verification failure") +		} +		return  	}  	return ErrUnsupportedAlgorithm  } @@ -446,8 +657,6 @@ type nameConstraints struct {  type generalSubtree struct {  	Name string `asn1:"tag:2,optional,ia5"` -	Min  int    `asn1:"optional,tag:0"` -	Max  int    `asn1:"optional,tag:1"`  }  func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) { @@ -460,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, @@ -489,6 +705,27 @@ func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{  			Y: p,  		}  		return pub, nil +	case ECDSA: +		paramsData := keyData.Algorithm.Parameters.FullBytes +		namedCurveOID := new(asn1.ObjectIdentifier) +		_, err := asn1.Unmarshal(paramsData, namedCurveOID) +		if err != nil { +			return nil, err +		} +		namedCurve := namedCurveFromOID(*namedCurveOID) +		if namedCurve == nil { +			return nil, errors.New("crypto/x509: unsupported elliptic curve") +		} +		x, y := elliptic.Unmarshal(namedCurve, asn1Data) +		if x == nil { +			return nil, errors.New("crypto/x509: failed to unmarshal elliptic curve point") +		} +		pub := &ecdsa.PublicKey{ +			Curve: namedCurve, +			X:     x, +			Y:     y, +		} +		return pub, nil  	default:  		return nil, nil  	} @@ -607,6 +844,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))) +						}  					}  				} @@ -643,7 +887,7 @@ func parseCertificate(in *certificate) (*Certificate, error) {  				}  				for _, subtree := range constraints.Permitted { -					if subtree.Min > 0 || subtree.Max > 0 || len(subtree.Name) == 0 { +					if len(subtree.Name) == 0 {  						if e.Critical {  							return out, UnhandledCriticalExtension{}  						} @@ -679,22 +923,9 @@ func parseCertificate(in *certificate) (*Certificate, error) {  				}  				for _, u := range keyUsage { -					switch { -					case u.Equal(oidExtKeyUsageAny): -						out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageAny) -					case u.Equal(oidExtKeyUsageServerAuth): -						out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageServerAuth) -					case u.Equal(oidExtKeyUsageClientAuth): -						out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageClientAuth) -					case u.Equal(oidExtKeyUsageCodeSigning): -						out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageCodeSigning) -					case u.Equal(oidExtKeyUsageEmailProtection): -						out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageEmailProtection) -					case u.Equal(oidExtKeyUsageTimeStamping): -						out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageTimeStamping) -					case u.Equal(oidExtKeyUsageOCSPSigning): -						out.ExtKeyUsage = append(out.ExtKeyUsage, ExtKeyUsageOCSPSigning) -					default: +					if extKeyUsage, ok := extKeyUsageFromOID(u); ok { +						out.ExtKeyUsage = append(out.ExtKeyUsage, extKeyUsage) +					} else {  						out.UnknownExtKeyUsage = append(out.UnknownExtKeyUsage, u)  					}  				} @@ -783,6 +1014,7 @@ func reverseBitsInAByte(in byte) byte {  var (  	oidExtensionSubjectKeyId        = []int{2, 5, 29, 14}  	oidExtensionKeyUsage            = []int{2, 5, 29, 15} +	oidExtensionExtendedKeyUsage    = []int{2, 5, 29, 37}  	oidExtensionAuthorityKeyId      = []int{2, 5, 29, 35}  	oidExtensionBasicConstraints    = []int{2, 5, 29, 19}  	oidExtensionSubjectAltName      = []int{2, 5, 29, 17} @@ -791,7 +1023,7 @@ var (  )  func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { -	ret = make([]pkix.Extension, 7 /* maximum number of elements. */) +	ret = make([]pkix.Extension, 8 /* maximum number of elements. */)  	n := 0  	if template.KeyUsage != 0 { @@ -814,6 +1046,27 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {  		n++  	} +	if len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0 { +		ret[n].Id = oidExtensionExtendedKeyUsage + +		var oids []asn1.ObjectIdentifier +		for _, u := range template.ExtKeyUsage { +			if oid, ok := oidFromExtKeyUsage(u); ok { +				oids = append(oids, oid) +			} else { +				panic("internal error") +			} +		} + +		oids = append(oids, template.UnknownExtKeyUsage...) + +		ret[n].Value, err = asn1.Marshal(oids) +		if err != nil { +			return +		} +		n++ +	} +  	if template.BasicConstraintsValid {  		ret[n].Id = oidExtensionBasicConstraints  		ret[n].Value, err = asn1.Marshal(basicConstraints{template.IsCA, template.MaxPathLen}) @@ -842,11 +1095,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 { @@ -890,11 +1154,6 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) {  	return ret[0:n], nil  } -var ( -	oidSHA1WithRSA = []int{1, 2, 840, 113549, 1, 1, 5} -	oidRSA         = []int{1, 2, 840, 113549, 1, 1, 1} -) -  func subjectBytes(cert *Certificate) ([]byte, error) {  	if len(cert.RawSubject) > 0 {  		return cert.RawSubject, nil @@ -905,8 +1164,9 @@ func subjectBytes(cert *Certificate) ([]byte, error) {  // CreateCertificate creates a new certificate based on a template. The  // following members of template are used: SerialNumber, Subject, NotBefore, -// NotAfter, KeyUsage, BasicConstraintsValid, IsCA, MaxPathLen, SubjectKeyId, -// DNSNames, PermittedDNSDomainsCritical, PermittedDNSDomains. +// NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid, +// IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, +// PermittedDNSDomains.  //  // 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 @@ -914,23 +1174,61 @@ func subjectBytes(cert *Certificate) ([]byte, error) {  //  // The returned slice is the certificate in DER encoding.  // -// The only supported key type is RSA (*rsa.PublicKey for pub, *rsa.PrivateKey -// for priv). +// The only supported key types are RSA and ECDSA (*rsa.PublicKey or +// *ecdsa.PublicKey for pub, *rsa.PrivateKey or *ecdsa.PublicKey for priv).  func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interface{}, priv interface{}) (cert []byte, err error) { -	rsaPub, ok := pub.(*rsa.PublicKey) -	if !ok { -		return nil, errors.New("x509: non-RSA public keys not supported") +	var publicKeyBytes []byte +	var publicKeyAlgorithm pkix.AlgorithmIdentifier + +	switch pub := pub.(type) { +	case *rsa.PublicKey: +		publicKeyBytes, err = asn1.Marshal(rsaPublicKey{ +			N: pub.N, +			E: pub.E, +		}) +		publicKeyAlgorithm.Algorithm = oidPublicKeyRSA +	case *ecdsa.PublicKey: +		oid, ok := oidFromNamedCurve(pub.Curve) +		if !ok { +			return nil, errors.New("x509: unknown elliptic curve") +		} +		publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA +		var paramBytes []byte +		paramBytes, err = asn1.Marshal(oid) +		if err != nil { +			return +		} +		publicKeyAlgorithm.Parameters.FullBytes = paramBytes +		publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) +	default: +		return nil, errors.New("x509: only RSA and ECDSA public keys supported")  	} -	rsaPriv, ok := priv.(*rsa.PrivateKey) -	if !ok { -		return nil, errors.New("x509: non-RSA private keys not supported") +	var signatureAlgorithm pkix.AlgorithmIdentifier +	var hashFunc crypto.Hash + +	switch priv := priv.(type) { +	case *rsa.PrivateKey: +		signatureAlgorithm.Algorithm = oidSignatureSHA1WithRSA +		hashFunc = crypto.SHA1 +	case *ecdsa.PrivateKey: +		switch priv.Curve { +		case elliptic.P224(), elliptic.P256(): +			hashFunc = crypto.SHA256 +			signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA256 +		case elliptic.P384(): +			hashFunc = crypto.SHA384 +			signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA384 +		case elliptic.P521(): +			hashFunc = crypto.SHA512 +			signatureAlgorithm.Algorithm = oidSignatureECDSAWithSHA512 +		default: +			return nil, errors.New("x509: unknown elliptic curve") +		} +	default: +		return nil, errors.New("x509: only RSA and ECDSA private keys supported")  	} -	asn1PublicKey, err := asn1.Marshal(rsaPublicKey{ -		N: rsaPub.N, -		E: rsaPub.E, -	})  	if err != nil {  		return  	} @@ -954,15 +1252,15 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf  		return  	} -	encodedPublicKey := asn1.BitString{BitLength: len(asn1PublicKey) * 8, Bytes: asn1PublicKey} +	encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}  	c := tbsCertificate{  		Version:            2,  		SerialNumber:       template.SerialNumber, -		SignatureAlgorithm: pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA}, +		SignatureAlgorithm: signatureAlgorithm,  		Issuer:             asn1.RawValue{FullBytes: asn1Issuer}, -		Validity:           validity{template.NotBefore, template.NotAfter}, +		Validity:           validity{template.NotBefore.UTC(), template.NotAfter.UTC()},  		Subject:            asn1.RawValue{FullBytes: asn1Subject}, -		PublicKey:          publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey}, +		PublicKey:          publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},  		Extensions:         extensions,  	} @@ -973,11 +1271,24 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf  	c.Raw = tbsCertContents -	h := sha1.New() +	h := hashFunc.New()  	h.Write(tbsCertContents)  	digest := h.Sum(nil) -	signature, err := rsa.SignPKCS1v15(rand, rsaPriv, crypto.SHA1, digest) +	var signature []byte + +	switch priv := priv.(type) { +	case *rsa.PrivateKey: +		signature, err = rsa.SignPKCS1v15(rand, priv, hashFunc, digest) +	case *ecdsa.PrivateKey: +		var r, s *big.Int +		if r, s, err = ecdsa.Sign(rand, priv, digest); err == nil { +			signature, err = asn1.Marshal(ecdsaSignature{r, s}) +		} +	default: +		panic("internal error") +	} +  	if err != nil {  		return  	} @@ -985,7 +1296,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub interf  	cert, err = asn1.Marshal(certificate{  		nil,  		c, -		pkix.AlgorithmIdentifier{Algorithm: oidSHA1WithRSA}, +		signatureAlgorithm,  		asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},  	})  	return @@ -1037,8 +1348,8 @@ func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts [  			Algorithm: oidSignatureSHA1WithRSA,  		},  		Issuer:              c.Subject.ToRDNSequence(), -		ThisUpdate:          now, -		NextUpdate:          expiry, +		ThisUpdate:          now.UTC(), +		NextUpdate:          expiry.UTC(),  		RevokedCertificates: revokedCerts,  	} diff --git a/src/pkg/crypto/x509/x509_test.go b/src/pkg/crypto/x509/x509_test.go index f0327b012..abd4fe84d 100644 --- a/src/pkg/crypto/x509/x509_test.go +++ b/src/pkg/crypto/x509/x509_test.go @@ -7,14 +7,20 @@ package x509  import (  	"bytes"  	"crypto/dsa" +	"crypto/ecdsa" +	"crypto/elliptic"  	"crypto/rand"  	"crypto/rsa" +	_ "crypto/sha256" +	_ "crypto/sha512"  	"crypto/x509/pkix"  	"encoding/asn1"  	"encoding/base64"  	"encoding/hex"  	"encoding/pem"  	"math/big" +	"net" +	"reflect"  	"testing"  	"time"  ) @@ -169,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) @@ -237,65 +286,220 @@ func TestCreateSelfSignedCertificate(t *testing.T) {  	random := rand.Reader  	block, _ := pem.Decode([]byte(pemPrivateKey)) -	priv, err := ParsePKCS1PrivateKey(block.Bytes) +	rsaPriv, err := ParsePKCS1PrivateKey(block.Bytes)  	if err != nil { -		t.Errorf("Failed to parse private key: %s", err) -		return +		t.Fatalf("Failed to parse private key: %s", err)  	} -	commonName := "test.example.com" -	template := Certificate{ -		SerialNumber: big.NewInt(1), -		Subject: pkix.Name{ -			CommonName:   commonName, -			Organization: []string{"Acme Co"}, -		}, -		NotBefore: time.Unix(1000, 0), -		NotAfter:  time.Unix(100000, 0), +	ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) +	if err != nil { +		t.Fatalf("Failed to generate ECDSA key: %s", err) +	} -		SubjectKeyId: []byte{1, 2, 3, 4}, -		KeyUsage:     KeyUsageCertSign, +	tests := []struct { +		name      string +		pub, priv interface{} +		checkSig  bool +	}{ +		{"RSA/RSA", &rsaPriv.PublicKey, rsaPriv, true}, +		{"RSA/ECDSA", &rsaPriv.PublicKey, ecdsaPriv, false}, +		{"ECDSA/RSA", &ecdsaPriv.PublicKey, rsaPriv, false}, +		{"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true}, +	} -		BasicConstraintsValid: true, -		IsCA:                  true, -		DNSNames:              []string{"test.example.com"}, +	testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth} +	testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{3, 2, 1}} -		PolicyIdentifiers:   []asn1.ObjectIdentifier{[]int{1, 2, 3}}, -		PermittedDNSDomains: []string{".example.com", "example.com"}, -	} +	for _, test := range tests { +		commonName := "test.example.com" +		template := Certificate{ +			SerialNumber: big.NewInt(1), +			Subject: pkix.Name{ +				CommonName:   commonName, +				Organization: []string{"Σ Acme Co"}, +			}, +			NotBefore: time.Unix(1000, 0), +			NotAfter:  time.Unix(100000, 0), -	derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv) -	if err != nil { -		t.Errorf("Failed to create certificate: %s", err) -		return -	} +			SubjectKeyId: []byte{1, 2, 3, 4}, +			KeyUsage:     KeyUsageCertSign, -	cert, err := ParseCertificate(derBytes) -	if err != nil { -		t.Errorf("Failed to parse certificate: %s", err) -		return -	} +			ExtKeyUsage:        testExtKeyUsage, +			UnknownExtKeyUsage: testUnknownExtKeyUsage, -	if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) { -		t.Errorf("Failed to parse policy identifiers: got:%#v want:%#v", cert.PolicyIdentifiers, template.PolicyIdentifiers) -	} +			BasicConstraintsValid: true, +			IsCA: true, -	if len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" { -		t.Errorf("Failed to parse name constraints: %#v", cert.PermittedDNSDomains) -	} +			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")}, -	if cert.Subject.CommonName != commonName { -		t.Errorf("Subject wasn't correctly copied from the template. Got %s, want %s", cert.Subject.CommonName, commonName) -	} +			PolicyIdentifiers:   []asn1.ObjectIdentifier{[]int{1, 2, 3}}, +			PermittedDNSDomains: []string{".example.com", "example.com"}, +		} + +		derBytes, err := CreateCertificate(random, &template, &template, test.pub, test.priv) +		if err != nil { +			t.Errorf("%s: failed to create certificate: %s", test.name, err) +			continue +		} + +		cert, err := ParseCertificate(derBytes) +		if err != nil { +			t.Errorf("%s: failed to parse certificate: %s", test.name, err) +			continue +		} + +		if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) { +			t.Errorf("%s: failed to parse policy identifiers: got:%#v want:%#v", test.name, cert.PolicyIdentifiers, template.PolicyIdentifiers) +		} + +		if len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" { +			t.Errorf("%s: failed to parse name constraints: %#v", test.name, cert.PermittedDNSDomains) +		} + +		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) +		} + +		if cert.Issuer.CommonName != commonName { +			t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName) +		} + +		if !reflect.DeepEqual(cert.ExtKeyUsage, testExtKeyUsage) { +			t.Errorf("%s: extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.ExtKeyUsage, testExtKeyUsage) +		} -	if cert.Issuer.CommonName != commonName { -		t.Errorf("Issuer wasn't correctly copied from the template. Got %s, want %s", cert.Issuer.CommonName, commonName) +		if !reflect.DeepEqual(cert.UnknownExtKeyUsage, testUnknownExtKeyUsage) { +			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 { +				t.Errorf("%s: signature verification failed: %s", test.name, err) +			} +		}  	} +} -	err = cert.CheckSignatureFrom(cert) -	if err != nil { -		t.Errorf("Signature verification failed: %s", err) -		return +// Self-signed certificate using ECDSA with SHA1 & secp256r1 +var ecdsaSHA1CertPem = ` +-----BEGIN CERTIFICATE----- +MIICDjCCAbUCCQDF6SfN0nsnrjAJBgcqhkjOPQQBMIGPMQswCQYDVQQGEwJVUzET +MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMG +A1UECgwMR29vZ2xlLCBJbmMuMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG +CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIwMjAyMDUw +WhcNMjIwNTE4MjAyMDUwWjCBjzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm +b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTATBgNVBAoMDEdvb2dsZSwg +SW5jLjEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20xIzAhBgkqhkiG9w0BCQEWFGdv +bGFuZy1kZXZAZ21haWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/Wgn +WQDo5+bz71T0327ERgd5SDDXFbXLpzIZDXTkjpe8QTEbsF+ezsQfrekrpDPC4Cd3 +P9LY0tG+aI8IyVKdUjAJBgcqhkjOPQQBA0gAMEUCIGlsqMcRqWVIWTD6wXwe6Jk2 +DKxL46r/FLgJYnzBEH99AiEA3fBouObsvV1R3oVkb4BQYnD4/4LeId6lAT43YvyV +a/A= +-----END CERTIFICATE----- +` + +// Self-signed certificate using ECDSA with SHA256 & secp256r1 +var ecdsaSHA256p256CertPem = ` +-----BEGIN CERTIFICATE----- +MIICDzCCAbYCCQDlsuMWvgQzhTAKBggqhkjOPQQDAjCBjzELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT +BgNVBAoMDEdvb2dsZSwgSW5jLjEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20xIzAh +BgkqhkiG9w0BCQEWFGdvbGFuZy1kZXZAZ21haWwuY29tMB4XDTEyMDUyMTAwMTkx +NloXDTIyMDUxOTAwMTkxNlowgY8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp +Zm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYDVQQKDAxHb29nbGUs +IEluYy4xFzAVBgNVBAMMDnd3dy5nb29nbGUuY29tMSMwIQYJKoZIhvcNAQkBFhRn +b2xhbmctZGV2QGdtYWlsLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPMt +2ErhxAty5EJRu9yM+MTy+hUXm3pdW1ensAv382KoGExSXAFWP7pjJnNtHO+XSwVm +YNtqjcAGFKpweoN//kQwCgYIKoZIzj0EAwIDRwAwRAIgIYSaUA/IB81gjbIw/hUV +70twxJr5EcgOo0hLp3Jm+EYCIFDO3NNcgmURbJ1kfoS3N/0O+irUtoPw38YoNkqJ +h5wi +-----END CERTIFICATE----- +` + +// Self-signed certificate using ECDSA with SHA256 & secp384r1 +var ecdsaSHA256p384CertPem = ` +-----BEGIN CERTIFICATE----- +MIICSjCCAdECCQDje/no7mXkVzAKBggqhkjOPQQDAjCBjjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS +BgNVBAoMC0dvb2dsZSwgSW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG +CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIxMDYxMDM0 +WhcNMjIwNTE5MDYxMDM0WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm +b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSwg +SW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEGCSqGSIb3DQEJARYUZ29s +YW5nLWRldkBnbWFpbC5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARRuzRNIKRK +jIktEmXanNmrTR/q/FaHXLhWRZ6nHWe26Fw7Rsrbk+VjGy4vfWtNn7xSFKrOu5ze +qxKnmE0h5E480MNgrUiRkaGO2GMJJVmxx20aqkXOk59U8yGA4CghE6MwCgYIKoZI +zj0EAwIDZwAwZAIwBZEN8gvmRmfeP/9C1PRLzODIY4JqWub2PLRT4mv9GU+yw3Gr +PU9A3CHMdEcdw/MEAjBBO1lId8KOCh9UZunsSMfqXiVurpzmhWd6VYZ/32G+M+Mh +3yILeYQzllt/g0rKVRk= +-----END CERTIFICATE----- +` + +// Self-signed certificate using ECDSA with SHA384 & secp521r1 +var ecdsaSHA384p521CertPem = ` +-----BEGIN CERTIFICATE----- +MIICljCCAfcCCQDhp1AFD/ahKjAKBggqhkjOPQQDAzCBjjELMAkGA1UEBhMCVVMx +EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS +BgNVBAoMC0dvb2dsZSwgSW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG +CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIxMTUwNDI5 +WhcNMjIwNTE5MTUwNDI5WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm +b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSwg +SW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEGCSqGSIb3DQEJARYUZ29s +YW5nLWRldkBnbWFpbC5jb20wgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABACqx9Rv +IssRs1LWYcNN+WffwlHw4Tv3y8/LIAA9MF1ZScIonU9nRMxt4a2uGJVCPDw6JHpz +PaYc0E9puLoE9AfKpwFr59Jkot7dBg55SKPEFkddoip/rvmN7NPAWjMBirOwjOkm +8FPthvPhGPqsu9AvgVuHu3PosWiHGNrhh379pva8MzAKBggqhkjOPQQDAwOBjAAw +gYgCQgEHNmswkUdPpHqrVxp9PvLVl+xxPuHBkT+75z9JizyxtqykHQo9Uh6SWCYH +BF9KLolo01wMt8DjoYP5Fb3j5MH7xwJCAbWZzTOp4l4DPkIvAh4LeC4VWbwPPyqh +kBg71w/iEcSY3wUKgHGcJJrObZw7wys91I5kENljqw/Samdr3ka+jBJa +-----END CERTIFICATE----- +` + +var ecdsaTests = []struct { +	sigAlgo SignatureAlgorithm +	pemCert string +}{ +	{ECDSAWithSHA1, ecdsaSHA1CertPem}, +	{ECDSAWithSHA256, ecdsaSHA256p256CertPem}, +	{ECDSAWithSHA256, ecdsaSHA256p384CertPem}, +	{ECDSAWithSHA384, ecdsaSHA384p521CertPem}, +} + +func TestECDSA(t *testing.T) { +	for i, test := range ecdsaTests { +		pemBlock, _ := pem.Decode([]byte(test.pemCert)) +		cert, err := ParseCertificate(pemBlock.Bytes) +		if err != nil { +			t.Errorf("%d: failed to parse certificate: %s", i, err) +			continue +		} +		if sa := cert.SignatureAlgorithm; sa != test.sigAlgo { +			t.Errorf("%d: signature algorithm is %v, want %v", i, sa, test.sigAlgo) +		} +		if parsedKey, ok := cert.PublicKey.(*ecdsa.PublicKey); !ok { +			t.Errorf("%d: wanted an ECDSA public key but found: %#v", i, parsedKey) +		} +		if pka := cert.PublicKeyAlgorithm; pka != ECDSA { +			t.Errorf("%d: public key algorithm is %v, want ECDSA", i, pka) +		} +		if err = cert.CheckSignatureFrom(cert); err != nil { +			t.Errorf("%d: certificate verification failed: %s", i, err) +		}  	}  } @@ -374,7 +578,7 @@ func TestVerifyCertificateWithDSASignature(t *testing.T) {  	}  	// test cert is self-signed  	if err = cert.CheckSignatureFrom(cert); err != nil { -		t.Fatalf("DSA Certificate verfication failed: %s", err) +		t.Fatalf("DSA Certificate verification failed: %s", err)  	}  } | 
