diff options
author | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-10-23 04:31:11 +0000 |
---|---|---|
committer | ian <ian@138bc75d-0d04-0410-961f-82ee72b054a4> | 2012-10-23 04:31:11 +0000 |
commit | fb08d0057f91d420b6f48c112264fc87dc91b532 (patch) | |
tree | 46bb86f514fbf6bad82da48e69a18fb09d878834 /libgo/go/crypto | |
parent | f507227a181bb31fa87d23a082485f99f3ef9183 (diff) | |
download | gcc-fb08d0057f91d420b6f48c112264fc87dc91b532.tar.gz |
libgo: Update to current sources.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@192704 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/crypto')
52 files changed, 3689 insertions, 986 deletions
diff --git a/libgo/go/crypto/aes/aes_test.go b/libgo/go/crypto/aes/aes_test.go index e500c666d97..6261dd09fb5 100644 --- a/libgo/go/crypto/aes/aes_test.go +++ b/libgo/go/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/libgo/go/crypto/aes/block.go b/libgo/go/crypto/aes/block.go index b930787cec7..57a7e9e25f2 100644 --- a/libgo/go/crypto/aes/block.go +++ b/libgo/go/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/libgo/go/crypto/aes/cipher.go b/libgo/go/crypto/aes/cipher.go index 7d307c93a0b..d931134a70e 100644 --- a/libgo/go/crypto/aes/cipher.go +++ b/libgo/go/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/libgo/go/crypto/aes/cipher_asm.go b/libgo/go/crypto/aes/cipher_asm.go new file mode 100644 index 00000000000..21369fc382c --- /dev/null +++ b/libgo/go/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/libgo/go/crypto/aes/cipher_generic.go b/libgo/go/crypto/aes/cipher_generic.go new file mode 100644 index 00000000000..1714e0f1e5c --- /dev/null +++ b/libgo/go/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/libgo/go/crypto/ecdsa/ecdsa.go b/libgo/go/crypto/ecdsa/ecdsa.go index 8508e3b4f8d..512d20c635c 100644 --- a/libgo/go/crypto/ecdsa/ecdsa.go +++ b/libgo/go/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/libgo/go/crypto/ecdsa/ecdsa_test.go b/libgo/go/crypto/ecdsa/ecdsa_test.go index 3a2b3efbab3..0c064319324 100644 --- a/libgo/go/crypto/ecdsa/ecdsa_test.go +++ b/libgo/go/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/libgo/go/crypto/elliptic/elliptic.go b/libgo/go/crypto/elliptic/elliptic.go index a3990891be3..7a4ff6614c1 100644 --- a/libgo/go/crypto/elliptic/elliptic.go +++ b/libgo/go/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) } diff --git a/libgo/go/crypto/elliptic/elliptic_test.go b/libgo/go/crypto/elliptic/elliptic_test.go index 1e3407ee0e7..58f903966ce 100644 --- a/libgo/go/crypto/elliptic/elliptic_test.go +++ b/libgo/go/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/libgo/go/crypto/elliptic/p224.go b/libgo/go/crypto/elliptic/p224.go index 17571c25288..1f7ff3f9da6 100644 --- a/libgo/go/crypto/elliptic/p224.go +++ b/libgo/go/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/libgo/go/crypto/md5/gen.go b/libgo/go/crypto/md5/gen.go new file mode 100644 index 00000000000..1a9c4ab33dd --- /dev/null +++ b/libgo/go/crypto/md5/gen.go @@ -0,0 +1,298 @@ +// 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 { + 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/libgo/go/crypto/md5/md5.go b/libgo/go/crypto/md5/md5.go index cfb728c9441..825e5c8a282 100644 --- a/libgo/go/crypto/md5/md5.go +++ b/libgo/go/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/libgo/go/crypto/md5/md5_test.go b/libgo/go/crypto/md5/md5_test.go index aae875464f9..b474a90d5a3 100644 --- a/libgo/go/crypto/md5/md5_test.go +++ b/libgo/go/crypto/md5/md5_test.go @@ -78,3 +78,28 @@ func ExampleNew() { fmt.Printf("%x", h.Sum(nil)) // Output: e2c569be17396eca2a2e3c11578123ed } + +var bench = md5.New() +var buf = makeBuf() + +func makeBuf() []byte { + b := make([]byte, 8<<10) + for i := range b { + b[i] = byte(i) + } + return b +} + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkHash8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} diff --git a/libgo/go/crypto/md5/md5block.go b/libgo/go/crypto/md5/md5block.go index a887e2e05ed..5dbdf5606b1 100644 --- a/libgo/go/crypto/md5/md5block.go +++ b/libgo/go/crypto/md5/md5block.go @@ -1,172 +1,246 @@ -// 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. - -// MD5 block step. -// In its own file so that a faster assembly or C version -// can be substituted easily. - package md5 -// 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, -} +import ( + "runtime" + "unsafe" +) -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 _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 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 { + 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/libgo/go/crypto/rand/rand_unix.go b/libgo/go/crypto/rand/rand_unix.go index 5eb4cda2b3a..18f482472d3 100644 --- a/libgo/go/crypto/rand/rand_unix.go +++ b/libgo/go/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/libgo/go/crypto/rsa/pkcs1v15.go b/libgo/go/crypto/rsa/pkcs1v15.go index f39a48a6af6..28ca5d73b39 100644 --- a/libgo/go/crypto/rsa/pkcs1v15.go +++ b/libgo/go/crypto/rsa/pkcs1v15.go @@ -19,6 +19,9 @@ 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 @@ -47,6 +50,9 @@ func EncryptPKCS1v15(rand io.Reader, pub *PublicKey, msg []byte) (out []byte, er // 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 @@ -69,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 @@ -238,11 +247,11 @@ 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 } diff --git a/libgo/go/crypto/rsa/rsa.go b/libgo/go/crypto/rsa/rsa.go index ec77e68696b..7faae674304 100644 --- a/libgo/go/crypto/rsa/rsa.go +++ b/libgo/go/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. @@ -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) @@ -220,6 +244,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 +433,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/libgo/go/crypto/rsa/rsa_test.go b/libgo/go/crypto/rsa/rsa_test.go index 0fb9875d044..62bbdc4aec3 100644 --- a/libgo/go/crypto/rsa/rsa_test.go +++ b/libgo/go/crypto/rsa/rsa_test.go @@ -50,6 +50,24 @@ func Test4PrimeKeyGeneration(t *testing.T) { testKeyBasics(t, priv) } +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) diff --git a/libgo/go/crypto/sha1/sha1.go b/libgo/go/crypto/sha1/sha1.go index 876e7992a3a..7cfde47dc07 100644 --- a/libgo/go/crypto/sha1/sha1.go +++ b/libgo/go/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/libgo/go/crypto/sha1/sha1_test.go b/libgo/go/crypto/sha1/sha1_test.go index 2dc14ac9868..e3d03e52a31 100644 --- a/libgo/go/crypto/sha1/sha1_test.go +++ b/libgo/go/crypto/sha1/sha1_test.go @@ -79,3 +79,28 @@ func ExampleNew() { fmt.Printf("% x", h.Sum(nil)) // Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd } + +var bench = sha1.New() +var buf = makeBuf() + +func makeBuf() []byte { + b := make([]byte, 8<<10) + for i := range b { + b[i] = byte(i) + } + return b +} + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkHash8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} diff --git a/libgo/go/crypto/sha1/sha1block.go b/libgo/go/crypto/sha1/sha1block.go index b5d32af7094..b9fe21d9e3d 100644 --- a/libgo/go/crypto/sha1/sha1block.go +++ b/libgo/go/crypto/sha1/sha1block.go @@ -15,12 +15,11 @@ const ( _K3 = 0xCA62C1D6 ) -func _Block(dig *digest, p []byte) int { +func block(dig *digest, p []byte) { var w [80]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++ { @@ -72,10 +71,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/libgo/go/crypto/sha256/sha256.go b/libgo/go/crypto/sha256/sha256.go index a61e30b4251..dc0e18f50df 100644 --- a/libgo/go/crypto/sha256/sha256.go +++ b/libgo/go/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/libgo/go/crypto/sha256/sha256_test.go b/libgo/go/crypto/sha256/sha256_test.go index a6efb375456..8e66b4b306d 100644 --- a/libgo/go/crypto/sha256/sha256_test.go +++ b/libgo/go/crypto/sha256/sha256_test.go @@ -123,3 +123,28 @@ func TestGolden(t *testing.T) { } } } + +var bench = New() +var buf = makeBuf() + +func makeBuf() []byte { + b := make([]byte, 8<<10) + for i := range b { + b[i] = byte(i) + } + return b +} + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkHash8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} diff --git a/libgo/go/crypto/sha256/sha256block.go b/libgo/go/crypto/sha256/sha256block.go index 7b0f5544453..2ac49100ac6 100644 --- a/libgo/go/crypto/sha256/sha256block.go +++ b/libgo/go/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/libgo/go/crypto/sha512/sha512.go b/libgo/go/crypto/sha512/sha512.go index a245fd68e55..4aec5293858 100644 --- a/libgo/go/crypto/sha512/sha512.go +++ b/libgo/go/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/libgo/go/crypto/sha512/sha512_test.go b/libgo/go/crypto/sha512/sha512_test.go index a70f7c54e39..977655ddb41 100644 --- a/libgo/go/crypto/sha512/sha512_test.go +++ b/libgo/go/crypto/sha512/sha512_test.go @@ -123,3 +123,28 @@ func TestGolden(t *testing.T) { } } } + +var bench = New() +var buf = makeBuf() + +func makeBuf() []byte { + b := make([]byte, 8<<10) + for i := range b { + b[i] = byte(i) + } + return b +} + +func BenchmarkHash1K(b *testing.B) { + b.SetBytes(1024) + for i := 0; i < b.N; i++ { + bench.Write(buf[:1024]) + } +} + +func BenchmarkHash8K(b *testing.B) { + b.SetBytes(int64(len(buf))) + for i := 0; i < b.N; i++ { + bench.Write(buf) + } +} diff --git a/libgo/go/crypto/sha512/sha512block.go b/libgo/go/crypto/sha512/sha512block.go index 6b7506287e2..3577b4f3df1 100644 --- a/libgo/go/crypto/sha512/sha512block.go +++ b/libgo/go/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/libgo/go/crypto/tls/cipher_suites.go b/libgo/go/crypto/tls/cipher_suites.go index 5039f319f59..a647e19aa19 100644 --- a/libgo/go/crypto/tls/cipher_suites.go +++ b/libgo/go/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/libgo/go/crypto/tls/common.go b/libgo/go/crypto/tls/common.go index 4ba0bf87481..cfe2f2227fb 100644 --- a/libgo/go/crypto/tls/common.go +++ b/libgo/go/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,22 @@ 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 + + // 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/libgo/go/crypto/tls/conn.go b/libgo/go/crypto/tls/conn.go index 455910af415..fd2ef1ecfa8 100644 --- a/libgo/go/crypto/tls/conn.go +++ b/libgo/go/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. @@ -660,8 +664,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 @@ -672,8 +675,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 @@ -684,11 +687,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 @@ -738,12 +741,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() @@ -753,9 +756,8 @@ 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 + n, err := c.writeRecord(recordTypeApplicationData, b) + return n, c.setError(err) } // Read can be made to time out and return a net.Error with Timeout() == true @@ -768,14 +770,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) { @@ -829,6 +831,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/libgo/go/crypto/tls/handshake_client.go b/libgo/go/crypto/tls/handshake_client.go index 2877f17387d..7db13bf70d8 100644 --- a/libgo/go/crypto/tls/handshake_client.go +++ b/libgo/go/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/libgo/go/crypto/tls/handshake_client_test.go b/libgo/go/crypto/tls/handshake_client_test.go index 8c56daaf619..e127049bb05 100644 --- a/libgo/go/crypto/tls/handshake_client_test.go +++ b/libgo/go/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,163 @@ 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, 0x54, 0x02, 0x00, 0x00, + 0x50, 0x03, 0x01, 0x4f, 0x7f, 0x24, 0x25, 0x10, + 0xa8, 0x9d, 0xb1, 0x33, 0xd6, 0x53, 0x81, 0xce, + 0xb0, 0x69, 0xed, 0x1b, 0x9c, 0x5e, 0x40, 0x3a, + 0x4d, 0x06, 0xbc, 0xc7, 0x84, 0x51, 0x5a, 0x30, + 0x40, 0x50, 0x48, 0x20, 0xcd, 0x91, 0x80, 0x08, + 0xff, 0x82, 0x38, 0xc6, 0x03, 0x2d, 0x45, 0x4c, + 0x91, 0xbb, 0xcc, 0x27, 0x3d, 0x58, 0xff, 0x0d, + 0x26, 0x34, 0x7b, 0x48, 0x7a, 0xce, 0x25, 0x20, + 0x90, 0x0f, 0x35, 0x9f, 0xc0, 0x13, 0x00, 0x00, + 0x08, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, + 0x02, 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, 0x0b, 0xe5, 0x39, + 0xde, 0x17, 0x7a, 0xaf, 0x96, 0xd5, 0x16, 0x01, + 0xa8, 0x06, 0x80, 0x98, 0x75, 0x52, 0x56, 0x92, + 0x15, 0xf9, 0x8d, 0xc0, 0x98, 0x62, 0xed, 0x54, + 0xb7, 0xef, 0x03, 0x11, 0x34, 0x82, 0x65, 0xd1, + 0xde, 0x25, 0x15, 0x4c, 0xf3, 0xdf, 0x4d, 0xbd, + 0x6c, 0xed, 0x3d, 0xd6, 0x04, 0xcc, 0xd1, 0xf7, + 0x6d, 0x32, 0xb1, 0x1c, 0x59, 0xca, 0xfb, 0xbc, + 0x61, 0xeb, 0x4b, 0xe6, 0x00, 0x00, 0x40, 0x3e, + 0xe6, 0x23, 0x54, 0x61, 0x3f, 0x63, 0x16, 0xeb, + 0x5c, 0xc3, 0xba, 0x8a, 0x19, 0x13, 0x60, 0x9f, + 0x23, 0xbf, 0x36, 0x1a, 0x32, 0x7a, 0xae, 0x34, + 0x7f, 0x2f, 0x89, 0x85, 0xe1, 0x0e, 0x93, 0xd7, + 0xf0, 0xab, 0xa1, 0x0d, 0x54, 0x95, 0x79, 0x0b, + 0xb4, 0xf1, 0x1c, 0x1d, 0x0f, 0x8c, 0x16, 0xec, + 0x82, 0x60, 0xee, 0xa3, 0x71, 0x2f, 0xaf, 0x3e, + 0xf1, 0xbd, 0xb5, 0x1b, 0x7f, 0xe0, 0xd2, 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, 0x09, 0xac, + 0xbe, 0x94, 0x75, 0x4d, 0x73, 0x45, 0xbd, 0xa8, + 0x0c, 0xe3, 0x5f, 0x72, 0x0b, 0x40, 0x4f, 0xd0, + 0xd2, 0xcb, 0x16, 0x50, 0xfe, 0xdd, 0x1a, 0x33, + 0x5c, 0x18, 0x37, 0x98, 0x42, 0xfc, 0x25, 0x42, + 0x33, 0xce, 0x60, 0xcf, 0x8e, 0x95, 0x6e, 0x48, + 0xed, 0x00, 0x35, 0x50, 0x26, 0x7f, + }, + { + 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, + 0x01, 0x00, 0x30, 0xf6, 0x6a, 0xdb, 0x83, 0xd4, + 0x3c, 0x77, 0x52, 0xad, 0xc0, 0x0f, 0x3a, 0x2c, + 0x42, 0xb9, 0x60, 0x4b, 0xb2, 0xf6, 0x84, 0xfd, + 0x4e, 0x96, 0xfc, 0x15, 0xe7, 0x94, 0x25, 0xb0, + 0x59, 0x9f, 0xdd, 0xb6, 0x58, 0x03, 0x13, 0x8d, + 0xeb, 0xb0, 0xad, 0x30, 0x31, 0x58, 0x6c, 0xa0, + 0x8f, 0x57, 0x50, + }, + { + 0x17, 0x03, 0x01, 0x00, 0x20, 0xab, 0x64, 0x3d, + 0x79, 0x69, 0x3e, 0xba, 0xc4, 0x24, 0x7b, 0xe5, + 0xe5, 0x23, 0x66, 0x6f, 0x32, 0xdf, 0x50, 0x7c, + 0x06, 0x2a, 0x02, 0x82, 0x79, 0x40, 0xdb, 0xb1, + 0x04, 0xc0, 0x2b, 0xdc, 0x3a, 0x15, 0x03, 0x01, + 0x00, 0x20, 0xf8, 0xad, 0xca, 0xd7, 0x96, 0xf0, + 0xd6, 0xa3, 0x62, 0xe1, 0x03, 0x44, 0xdb, 0xd0, + 0xc9, 0x63, 0x3e, 0x1b, 0x70, 0x41, 0x57, 0x0c, + 0xd8, 0x8e, 0x71, 0x49, 0x68, 0xe3, 0x04, 0x53, + 0x5a, 0xbe, + }, +} diff --git a/libgo/go/crypto/tls/handshake_messages.go b/libgo/go/crypto/tls/handshake_messages.go index 54c7a3e6316..cdd49170777 100644 --- a/libgo/go/crypto/tls/handshake_messages.go +++ b/libgo/go/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/libgo/go/crypto/tls/handshake_messages_test.go b/libgo/go/crypto/tls/handshake_messages_test.go index e62a9d581b3..3434bad9fba 100644 --- a/libgo/go/crypto/tls/handshake_messages_test.go +++ b/libgo/go/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/libgo/go/crypto/tls/handshake_server.go b/libgo/go/crypto/tls/handshake_server.go index 76adc540c71..d8410345020 100644 --- a/libgo/go/crypto/tls/handshake_server.go +++ b/libgo/go/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,173 @@ 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 + } + + for _, id := range hs.clientHello.cipherSuites { + if hs.suite = c.tryCipherSuite(id, 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 + } + + 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 + } } - hello.compressionMethod = compressionNone - if clientHello.nextProtoNeg { - hello.nextProtoNeg = true - hello.nextProtos = config.NextProtos + if !cipherSuiteOk { + return false } + // Check that we also support the ciphersuite from the session. + hs.suite = c.tryCipherSuite(hs.sessionState.cipherSuite, 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 +318,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 +351,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 +367,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 +386,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 +402,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 +441,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 +454,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, ellipticOk bool) *cipherSuite { + for _, supported := range c.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 + } + return candidate + } + } return nil } diff --git a/libgo/go/crypto/tls/handshake_server_test.go b/libgo/go/crypto/tls/handshake_server_test.go index 7c1267101cf..8ca3c2cf191 100644 --- a/libgo/go/crypto/tls/handshake_server_test.go +++ b/libgo/go/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) } @@ -186,6 +196,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 +218,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 +} - l, err := Listen("tcp", ":10443", testConfig) +func TestRunServer(t *testing.T) { + if !*serve { + return + } + + config := GetTestConfig() + + 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,10 +389,8 @@ 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, @@ -961,21 +1052,37 @@ var sslv3ServerScript = [][]byte{ 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, - 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, - 0x0e, 0x00, 0x00, 0x0b, 0x73, 0x6e, 0x69, 0x74, - 0x65, 0x73, 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, - 0x23, 0x00, 0x00, + 0x16, 0x03, 0x01, 0x00, 0xed, 0x01, 0x00, 0x00, + 0xe9, 0x03, 0x02, 0x50, 0x5a, 0x1c, 0x90, 0x2b, + 0xc8, 0xf1, 0xd9, 0x4b, 0xd0, 0x18, 0x69, 0xed, + 0x5a, 0xbd, 0x68, 0xf6, 0xf7, 0xe3, 0xf0, 0x6e, + 0xd1, 0xcc, 0xf1, 0x2d, 0x94, 0xa4, 0x01, 0x63, + 0x91, 0xbe, 0xd0, 0x00, 0x00, 0x66, 0xc0, 0x14, + 0xc0, 0x0a, 0xc0, 0x22, 0xc0, 0x21, 0x00, 0x39, + 0x00, 0x38, 0x00, 0x88, 0x00, 0x87, 0xc0, 0x0f, + 0xc0, 0x05, 0x00, 0x35, 0x00, 0x84, 0xc0, 0x12, + 0xc0, 0x08, 0xc0, 0x1c, 0xc0, 0x1b, 0x00, 0x16, + 0x00, 0x13, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, + 0xc0, 0x13, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x1e, + 0x00, 0x33, 0x00, 0x32, 0x00, 0x9a, 0x00, 0x99, + 0x00, 0x45, 0x00, 0x44, 0xc0, 0x0e, 0xc0, 0x04, + 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0xc0, 0x11, + 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02, 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, + 0x59, 0x00, 0x00, 0x00, 0x10, 0x00, 0x0e, 0x00, + 0x00, 0x0b, 0x73, 0x6e, 0x69, 0x74, 0x65, 0x73, + 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x00, 0x0b, 0x00, + 0x04, 0x03, 0x00, 0x01, 0x02, 0x00, 0x0a, 0x00, + 0x34, 0x00, 0x32, 0x00, 0x0e, 0x00, 0x0d, 0x00, + 0x19, 0x00, 0x0b, 0x00, 0x0c, 0x00, 0x18, 0x00, + 0x09, 0x00, 0x0a, 0x00, 0x16, 0x00, 0x17, 0x00, + 0x08, 0x00, 0x06, 0x00, 0x07, 0x00, 0x14, 0x00, + 0x15, 0x00, 0x04, 0x00, 0x05, 0x00, 0x12, 0x00, + 0x13, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00, + 0x0f, 0x00, 0x10, 0x00, 0x11, 0x00, 0x0f, 0x00, + 0x01, 0x01, }, { 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, @@ -1053,45 +1160,323 @@ 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, 0x45, 0x6d, 0x68, 0x61, 0xb9, + 0x1a, 0xe5, 0xeb, 0x67, 0x22, 0x3b, 0x87, 0x19, + 0x52, 0x86, 0x31, 0x91, 0xee, 0xcd, 0x17, 0x75, + 0xc6, 0x44, 0xaf, 0x23, 0xef, 0xd9, 0xfa, 0xd2, + 0x0b, 0xa2, 0xbb, 0xbf, 0x8b, 0x4b, 0x34, 0x50, + 0xf6, 0x2e, 0x05, 0x09, 0x7e, 0xbf, 0xb3, 0xa6, + 0x10, 0xe3, 0xc3, 0x49, 0x55, 0xa8, 0xdf, 0x6c, + 0xaa, 0xab, 0x11, 0x4c, 0x80, 0x0a, 0x45, 0xf8, + 0x37, 0xbb, 0xd3, 0x18, 0x4e, 0xec, 0x51, 0xbf, + 0x1a, 0xf6, 0x11, 0x1b, 0xcf, 0x2c, 0xaf, 0x5f, + 0x0b, 0x52, 0x4e, 0x92, 0x0c, 0x7a, 0xb2, 0x5d, + 0xe2, 0x1f, 0x83, 0xbe, 0xf5, 0xbf, 0x05, 0xbf, + 0x99, 0xd6, 0x9c, 0x86, 0x47, 0x5e, 0xb4, 0xff, + 0xe7, 0xac, 0xad, 0x1e, 0x3c, 0xaa, 0x91, 0x39, + 0xca, 0xad, 0xc5, 0x54, 0x64, 0x7e, 0xc2, 0x8a, + 0x48, 0xee, 0xb6, 0x4e, 0xf9, 0x33, 0x82, 0x52, + 0xe8, 0xed, 0x48, 0x14, 0x03, 0x01, 0x00, 0x01, + 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc1, 0x2f, + 0x34, 0x03, 0x2a, 0xf2, 0xfd, 0x83, 0x69, 0x23, + 0x8c, 0x9e, 0x66, 0x3b, 0xbb, 0xd1, 0xab, 0xbb, + 0x51, 0x89, 0x27, 0x88, 0x0f, 0x08, 0x3e, 0x00, + 0xdc, 0xc7, 0x47, 0x82, 0x13, 0x34, 0xec, 0xca, + 0x68, 0x6a, + }, + { + 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, + 0x01, 0x00, 0x24, 0xda, 0x61, 0x76, 0x9f, 0x7a, + 0x8a, 0xd0, 0x5f, 0x9b, 0x3d, 0xa7, 0xd5, 0xdd, + 0x95, 0x4b, 0xd4, 0x64, 0x2d, 0x2d, 0x6a, 0x98, + 0x9e, 0xfe, 0x77, 0x76, 0xe3, 0x02, 0x05, 0x0c, + 0xb2, 0xa6, 0x15, 0x82, 0x28, 0x25, 0xc5, 0x17, + 0x03, 0x01, 0x00, 0x21, 0x4e, 0x66, 0x2d, 0x50, + 0x00, 0xa2, 0x44, 0x4d, 0xee, 0x5f, 0x81, 0x67, + 0x21, 0x5d, 0x94, 0xc0, 0xfb, 0xdc, 0xbd, 0xf6, + 0xa8, 0x32, 0x8e, 0x2c, 0x22, 0x58, 0x37, 0xb6, + 0xa3, 0x1e, 0xf8, 0xdd, 0x83, 0x15, 0x03, 0x01, + 0x00, 0x16, 0x68, 0x3b, 0x3a, 0xd0, 0x1e, 0xc4, + 0x5e, 0x97, 0x6a, 0x47, 0x38, 0xfe, 0x17, 0x8e, + 0xc0, 0xb6, 0x4a, 0x94, 0x00, 0xb5, 0x91, 0xbf, + }, +} + +var issueSessionTicketTest = [][]byte{ + { + 0x16, 0x03, 0x01, 0x00, 0xdd, 0x01, 0x00, 0x00, + 0xd9, 0x03, 0x02, 0x50, 0x5a, 0x32, 0xb6, 0x36, + 0x0e, 0x94, 0x63, 0x57, 0x93, 0xd7, 0x1e, 0xb2, + 0xa7, 0xd3, 0x20, 0x24, 0x30, 0x3f, 0x46, 0xf9, + 0xfe, 0x22, 0x02, 0xa1, 0xff, 0x57, 0xf8, 0x8f, + 0x95, 0x4c, 0xdd, 0x00, 0x00, 0x66, 0xc0, 0x14, + 0xc0, 0x0a, 0xc0, 0x22, 0xc0, 0x21, 0x00, 0x39, + 0x00, 0x38, 0x00, 0x88, 0x00, 0x87, 0xc0, 0x0f, + 0xc0, 0x05, 0x00, 0x35, 0x00, 0x84, 0xc0, 0x12, + 0xc0, 0x08, 0xc0, 0x1c, 0xc0, 0x1b, 0x00, 0x16, + 0x00, 0x13, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, + 0xc0, 0x13, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x1e, + 0x00, 0x33, 0x00, 0x32, 0x00, 0x9a, 0x00, 0x99, + 0x00, 0x45, 0x00, 0x44, 0xc0, 0x0e, 0xc0, 0x04, + 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0xc0, 0x11, + 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02, 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, + 0x49, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, + 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32, 0x00, + 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b, 0x00, + 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a, 0x00, + 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06, 0x00, + 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10, 0x00, + 0x11, 0x00, 0x23, 0x00, 0x00, 0x00, 0x0f, 0x00, + 0x01, 0x01, + }, + { + 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, 0x92, 0x3f, 0xcc, 0x4d, 0x2f, + 0xb2, 0x12, 0xc4, 0xf5, 0x72, 0xf3, 0x5a, 0x3c, + 0x5a, 0xbb, 0x99, 0x89, 0xe6, 0x21, 0x0f, 0xdf, + 0xf3, 0xa3, 0xd0, 0xce, 0x76, 0x55, 0xfd, 0xec, + 0x38, 0x80, 0xf0, 0x46, 0x0b, 0xfa, 0x61, 0x7c, + 0xc2, 0xb5, 0xe2, 0x89, 0x7b, 0xeb, 0xcf, 0x3e, + 0x97, 0xab, 0x72, 0xf6, 0xfd, 0xcf, 0x10, 0x82, + 0x3a, 0x05, 0x55, 0x7c, 0x2d, 0x7f, 0x44, 0x38, + 0x9d, 0xeb, 0xa4, 0x7e, 0x53, 0x35, 0xda, 0xe0, + 0x7c, 0x24, 0x66, 0x42, 0x5d, 0x85, 0xcf, 0xa6, + 0x98, 0x81, 0xec, 0x42, 0x94, 0x4e, 0x25, 0xb1, + 0x64, 0xac, 0x89, 0x98, 0x74, 0xd2, 0xeb, 0x51, + 0x5a, 0xb3, 0xbd, 0x14, 0xf6, 0xc6, 0xec, 0x0b, + 0xdd, 0x8b, 0x89, 0xdc, 0xde, 0xf3, 0xd6, 0x62, + 0xee, 0xe3, 0xcf, 0xf5, 0x39, 0x23, 0x46, 0x4f, + 0xb8, 0xef, 0x14, 0x39, 0x06, 0x36, 0xad, 0x84, + 0x42, 0xb9, 0xd7, 0x14, 0x03, 0x01, 0x00, 0x01, + 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xa1, 0xf0, + 0x68, 0xf5, 0x29, 0x7e, 0x78, 0xaa, 0xbd, 0x59, + 0xdc, 0x32, 0xab, 0x8e, 0x25, 0x54, 0x64, 0x9e, + 0x2b, 0x08, 0xf9, 0xb8, 0xe3, 0x89, 0x09, 0xa4, + 0xfd, 0x05, 0x78, 0x59, 0xcb, 0x33, 0xfc, 0x66, + 0xb5, 0x73, + }, + { + 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, 0xfc, 0x00, 0xd4, + 0x2f, 0xf5, 0x6f, 0xba, 0xdc, 0xb7, 0xd7, 0x87, + 0x59, 0x58, 0x05, 0x06, 0x36, 0x8f, 0x47, 0xc7, + 0x9e, 0x4c, 0xf8, 0xb5, 0xd7, 0x55, 0x84, 0x64, + 0x0b, 0x4c, 0x0b, 0xad, 0x8d, 0x9b, 0x79, 0x4d, + 0xd7, 0x61, 0xf7, 0x2b, 0x89, 0x46, 0x2b, 0x52, + 0x1a, 0x3f, 0x51, 0x58, 0xce, 0x59, 0x23, 0xef, + 0x60, 0x55, 0x07, 0xc0, 0x46, 0x97, 0xad, 0x0a, + 0xe3, 0x55, 0x10, 0x06, 0xff, 0x57, 0x0c, 0xb1, + 0x49, 0xac, 0x80, 0xc6, 0xc3, 0x95, 0x5f, 0x12, + 0xe2, 0xe5, 0xaa, 0x9f, 0x78, 0xc2, 0x20, 0x14, + 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, + 0x00, 0x24, 0x47, 0x51, 0xf1, 0x13, 0xc8, 0xa6, + 0xd2, 0x2c, 0xad, 0x35, 0xff, 0x53, 0xe2, 0x72, + 0x01, 0xcb, 0x33, 0xcd, 0xf4, 0xa0, 0x9c, 0x03, + 0x47, 0xfe, 0xcd, 0xc1, 0x46, 0x8d, 0x41, 0x5e, + 0x54, 0xf7, 0xc3, 0x85, 0x2b, 0x2f, 0x17, 0x03, + 0x01, 0x00, 0x21, 0xf4, 0xbf, 0x94, 0x3e, 0x93, + 0x0b, 0x1b, 0x75, 0x3a, 0xd9, 0xd0, 0x57, 0x75, + 0xf3, 0xa7, 0x82, 0xc9, 0x6b, 0x9e, 0x43, 0x98, + 0x44, 0x9e, 0x9f, 0xad, 0x03, 0xa8, 0xb9, 0xa3, + 0x0a, 0xd1, 0xc4, 0xb4, 0x15, 0x03, 0x01, 0x00, + 0x16, 0xee, 0x57, 0xbd, 0xd3, 0xb7, 0x20, 0x29, + 0xd1, 0x24, 0xe2, 0xdc, 0x24, 0xc3, 0x73, 0x86, + 0x81, 0x8e, 0x40, 0xc3, 0x6e, 0x99, 0x9e, + }, +} + +var serverResumeTest = [][]byte{ + { + 0x16, 0x03, 0x01, 0x01, 0x65, 0x01, 0x00, 0x01, + 0x61, 0x03, 0x01, 0x50, 0x5a, 0x32, 0xe2, 0xde, + 0x19, 0x5c, 0xb6, 0x51, 0x87, 0xa4, 0x30, 0x2e, + 0x95, 0x26, 0xd6, 0xed, 0xbf, 0xbf, 0x24, 0xbb, + 0xd1, 0x1a, 0x29, 0x9f, 0x37, 0xfd, 0xfb, 0xae, + 0xc2, 0xba, 0x2b, 0x20, 0xb5, 0x7a, 0x00, 0x96, + 0x92, 0x51, 0xfc, 0x41, 0x16, 0x29, 0xc0, 0x54, + 0x5e, 0xa7, 0xa9, 0x1f, 0xf8, 0xbf, 0x79, 0xfa, + 0x49, 0x5a, 0x15, 0x28, 0x72, 0x9a, 0x59, 0xf9, + 0x9b, 0xc4, 0x3a, 0xa8, 0x00, 0x66, 0xc0, 0x14, + 0xc0, 0x0a, 0xc0, 0x22, 0xc0, 0x21, 0x00, 0x39, + 0x00, 0x38, 0x00, 0x88, 0x00, 0x87, 0xc0, 0x0f, + 0xc0, 0x05, 0x00, 0x35, 0x00, 0x84, 0xc0, 0x12, + 0xc0, 0x08, 0xc0, 0x1c, 0xc0, 0x1b, 0x00, 0x16, + 0x00, 0x13, 0xc0, 0x0d, 0xc0, 0x03, 0x00, 0x0a, + 0xc0, 0x13, 0xc0, 0x09, 0xc0, 0x1f, 0xc0, 0x1e, + 0x00, 0x33, 0x00, 0x32, 0x00, 0x9a, 0x00, 0x99, + 0x00, 0x45, 0x00, 0x44, 0xc0, 0x0e, 0xc0, 0x04, + 0x00, 0x2f, 0x00, 0x96, 0x00, 0x41, 0xc0, 0x11, + 0xc0, 0x07, 0xc0, 0x0c, 0xc0, 0x02, 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, + 0xb1, 0x00, 0x0b, 0x00, 0x04, 0x03, 0x00, 0x01, + 0x02, 0x00, 0x0a, 0x00, 0x34, 0x00, 0x32, 0x00, + 0x0e, 0x00, 0x0d, 0x00, 0x19, 0x00, 0x0b, 0x00, + 0x0c, 0x00, 0x18, 0x00, 0x09, 0x00, 0x0a, 0x00, + 0x16, 0x00, 0x17, 0x00, 0x08, 0x00, 0x06, 0x00, + 0x07, 0x00, 0x14, 0x00, 0x15, 0x00, 0x04, 0x00, + 0x05, 0x00, 0x12, 0x00, 0x13, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x03, 0x00, 0x0f, 0x00, 0x10, 0x00, + 0x11, 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, 0xfc, 0x00, 0xd4, 0x2f, 0xf5, + 0x6f, 0xba, 0xdc, 0xb7, 0xd7, 0x87, 0x59, 0x58, + 0x05, 0x06, 0x36, 0x8f, 0x47, 0xc7, 0x9e, 0x4c, + 0xf8, 0xb5, 0xd7, 0x55, 0x84, 0x64, 0x0b, 0x4c, + 0x0b, 0xad, 0x8d, 0x9b, 0x79, 0x4d, 0xd7, 0x61, + 0xf7, 0x2b, 0x89, 0x46, 0x2b, 0x52, 0x1a, 0x3f, + 0x51, 0x58, 0xce, 0x59, 0x23, 0xef, 0x60, 0x55, + 0x07, 0xc0, 0x46, 0x97, 0xad, 0x0a, 0xe3, 0x55, + 0x10, 0x06, 0xff, 0x57, 0x0c, 0xb1, 0x49, 0xac, + 0x80, 0xc6, 0xc3, 0x95, 0x5f, 0x12, 0xe2, 0xe5, + 0xaa, 0x9f, 0x78, 0xc2, 0x20, 0x00, 0x0f, 0x00, + 0x01, 0x01, + }, + { + 0x16, 0x03, 0x01, 0x00, 0x4a, 0x02, 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, 0x20, 0xb5, 0x7a, 0x00, 0x96, + 0x92, 0x51, 0xfc, 0x41, 0x16, 0x29, 0xc0, 0x54, + 0x5e, 0xa7, 0xa9, 0x1f, 0xf8, 0xbf, 0x79, 0xfa, + 0x49, 0x5a, 0x15, 0x28, 0x72, 0x9a, 0x59, 0xf9, + 0x9b, 0xc4, 0x3a, 0xa8, 0x00, 0x05, 0x00, 0x14, + 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, 0x01, + 0x00, 0x24, 0x2c, 0x86, 0xdd, 0x85, 0x21, 0xa7, + 0xda, 0x25, 0xf5, 0x55, 0x62, 0x2d, 0x82, 0x6b, + 0x9d, 0x67, 0x22, 0x28, 0xf4, 0x55, 0x33, 0xd0, + 0x77, 0xc0, 0x9e, 0xb7, 0xf4, 0x96, 0x07, 0x8c, + 0xf5, 0xea, 0x5b, 0x50, 0xa4, 0xb7, }, { 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, 0x15, 0x14, 0x9c, 0x21, 0xdd, + 0x47, 0x61, 0x52, 0xf9, 0x22, 0x15, 0x55, 0x3c, + 0xbd, 0xd7, 0xff, 0xf9, 0xbd, 0x84, 0xec, 0x97, + 0x2d, 0x4e, 0xa9, 0x6a, 0xb9, 0x9b, 0x96, 0xc6, + 0x9e, 0x5c, 0x77, 0xa8, 0x5d, 0x7a, 0x08, + }, + { + 0x17, 0x03, 0x01, 0x00, 0x21, 0x04, 0xab, 0x0f, + 0x7c, 0x54, 0x20, 0xab, 0x34, 0xa3, 0x73, 0x92, + 0xc5, 0xaa, 0xdd, 0x5b, 0xf5, 0x0c, 0xe4, 0x4f, + 0xf1, 0x93, 0x07, 0xe5, 0xe8, 0x72, 0xc2, 0x03, + 0x60, 0xfa, 0x64, 0x01, 0x00, 0x25, 0x15, 0x03, + 0x01, 0x00, 0x16, 0xc7, 0xd9, 0xff, 0x67, 0xfc, + 0x7a, 0xac, 0x8a, 0xe6, 0x23, 0xfe, 0x32, 0xbf, + 0x84, 0xe1, 0xe2, 0xf5, 0x6a, 0xc8, 0xda, 0x30, + 0x8f, }, } diff --git a/libgo/go/crypto/tls/prf.go b/libgo/go/crypto/tls/prf.go index 637ef03e2d7..df1eaad0586 100644 --- a/libgo/go/crypto/tls/prf.go +++ b/libgo/go/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/libgo/go/crypto/tls/prf_test.go b/libgo/go/crypto/tls/prf_test.go index a32392cef79..ce6e36de8a1 100644 --- a/libgo/go/crypto/tls/prf_test.go +++ b/libgo/go/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", 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/libgo/go/crypto/tls/root_test.go b/libgo/go/crypto/tls/root_test.go deleted file mode 100644 index e61c2185126..00000000000 --- a/libgo/go/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/libgo/go/crypto/tls/ticket.go b/libgo/go/crypto/tls/ticket.go new file mode 100644 index 00000000000..4cfc5a53ffe --- /dev/null +++ b/libgo/go/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/libgo/go/crypto/tls/tls.go b/libgo/go/crypto/tls/tls.go index 09df5ad445c..80f852edf7b 100644 --- a/libgo/go/crypto/tls/tls.go +++ b/libgo/go/crypto/tls/tls.go @@ -146,10 +146,16 @@ 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 + 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 + } + if keyDERBlock.Type != "CERTIFICATE" { + break + } } // OpenSSL 0.9.8 generates PKCS#1 private keys by default, while diff --git a/libgo/go/crypto/tls/tls_test.go b/libgo/go/crypto/tls/tls_test.go new file mode 100644 index 00000000000..5df43c385fd --- /dev/null +++ b/libgo/go/crypto/tls/tls_test.go @@ -0,0 +1,47 @@ +// 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 certPEM = `-----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 keyPEM = `-----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----- +` + +func TestX509KeyPair(t *testing.T) { + _, err := X509KeyPair([]byte(keyPEM+certPEM), []byte(keyPEM+certPEM)) + if err != nil { + t.Errorf("Failed to load key followed by cert: %s", err) + } + + _, err = X509KeyPair([]byte(certPEM+keyPEM), []byte(certPEM+keyPEM)) + if err != nil { + t.Errorf("Failed to load cert followed by key: %s", err) + println(err.Error()) + } +} diff --git a/libgo/go/crypto/x509/pem_decrypt.go b/libgo/go/crypto/x509/pem_decrypt.go new file mode 100644 index 00000000000..21f62e5d76b --- /dev/null +++ b/libgo/go/crypto/x509/pem_decrypt.go @@ -0,0 +1,133 @@ +// 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" + "strings" +) + +// rfc1423Algos represents how to create a block cipher for a decryption mode. +type rfc1423Algo struct { + cipherFunc func([]byte) (cipher.Block, error) + keySize int +} + +// 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 +} + +// rfc1423Algos is a mapping of encryption algorithm to an rfc1423Algo that can +// create block ciphers for that mode. +var rfc1423Algos = map[string]rfc1423Algo{ + "DES-CBC": {des.NewCipher, 8}, + "DES-EDE3-CBC": {des.NewTripleDESCipher, 24}, + "AES-128-CBC": {aes.NewCipher, 16}, + "AES-192-CBC": {aes.NewCipher, 24}, + "AES-256-CBC": {aes.NewCipher, 32}, +} + +// 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:] + iv, err := hex.DecodeString(hexIV) + if err != nil { + return nil, err + } + if len(iv) < 8 { + return nil, errors.New("x509: not enough bytes in IV") + } + + ciph, ok := rfc1423Algos[mode] + if !ok { + return nil, errors.New("x509: unknown encryption mode") + } + + // 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 8 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 { + return nil, errors.New("x509: invalid padding") + } + last := data[dlen-1] + if dlen < int(last) { + return nil, IncorrectPasswordError + } + if last == 0 || last > 8 { + return nil, IncorrectPasswordError + } + for _, val := range data[dlen-int(last):] { + if val != last { + return nil, IncorrectPasswordError + } + } + + return data[:dlen-int(last)], nil +} diff --git a/libgo/go/crypto/x509/pem_decrypt_test.go b/libgo/go/crypto/x509/pem_decrypt_test.go new file mode 100644 index 00000000000..2cb99836eae --- /dev/null +++ b/libgo/go/crypto/x509/pem_decrypt_test.go @@ -0,0 +1,119 @@ +// 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/pem" + "testing" +) + +func TestDecrypt(t *testing.T) { + for _, data := range testData { + block, rest := pem.Decode(data.pemData) + if len(rest) > 0 { + t.Error(data.kind, "extra data") + } + der, err := DecryptPEMBlock(block, data.password) + if err != nil { + t.Error(data.kind, err) + continue + } + if _, err := ParsePKCS1PrivateKey(der); err != nil { + t.Error(data.kind, "Invalid private key") + } + } +} + +var testData = []struct { + kind string + password []byte + pemData []byte +}{ + { + kind: "DES-CBC", + 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-----`), + }, + { + kind: "DES-EDE3-CBC", + 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-----`), + }, + { + kind: "AES-128-CBC", + 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-----`), + }, + { + kind: "AES-192-CBC", + 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-----`), + }, + { + kind: "AES-256-CBC", + 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-----`), + }, +} diff --git a/libgo/go/crypto/x509/pkcs8.go b/libgo/go/crypto/x509/pkcs8.go index 4d8e0518e02..8c3b65f8078 100644 --- a/libgo/go/crypto/x509/pkcs8.go +++ b/libgo/go/crypto/x509/pkcs8.go @@ -28,7 +28,7 @@ func ParsePKCS8PrivateKey(der []byte) (key interface{}, err error) { 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()) diff --git a/libgo/go/crypto/x509/root_plan9.go b/libgo/go/crypto/x509/root_plan9.go new file mode 100644 index 00000000000..677927a3b63 --- /dev/null +++ b/libgo/go/crypto/x509/root_plan9.go @@ -0,0 +1,31 @@ +// 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) + break + } + } + + systemRoots = roots +} diff --git a/libgo/go/crypto/x509/root_stub.go b/libgo/go/crypto/x509/root_stub.go index 568004108b5..756732f7d4f 100644 --- a/libgo/go/crypto/x509/root_stub.go +++ b/libgo/go/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 diff --git a/libgo/go/crypto/x509/root_windows.go b/libgo/go/crypto/x509/root_windows.go index 7e8f2af4b0e..96ca57b420d 100644 --- a/libgo/go/crypto/x509/root_windows.go +++ b/libgo/go/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 } diff --git a/libgo/go/crypto/x509/verify.go b/libgo/go/crypto/x509/verify.go index 28814539d13..68929c7bb68 100644 --- a/libgo/go/crypto/x509/verify.go +++ b/libgo/go/crypto/x509/verify.go @@ -27,6 +27,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 @@ -46,6 +49,8 @@ func (e CertificateInvalidError) Error() string { 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" } @@ -84,6 +89,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 ( @@ -174,7 +184,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 { @@ -300,3 +338,56 @@ 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 + } + } + + usages[i] = invalidUsage + usagesRemaining-- + if usagesRemaining == 0 { + return false + } + } + } + + return true +} diff --git a/libgo/go/crypto/x509/verify_test.go b/libgo/go/crypto/x509/verify_test.go index 7b171b291a4..510a119ff7c 100644 --- a/libgo/go/crypto/x509/verify_test.go +++ b/libgo/go/crypto/x509/verify_test.go @@ -21,6 +21,7 @@ type verifyTest struct { currentTime int64 dnsName string systemSkip bool + keyUsages []ExtKeyUsage errorCallback func(*testing.T, int, error) bool expectedChains [][]string @@ -113,6 +114,38 @@ 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"}, + }, + }, } func expectHostnameError(t *testing.T, i int, err error) (ok bool) { @@ -131,6 +164,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) @@ -157,6 +198,7 @@ func testVerify(t *testing.T, useSystemRoots bool) { Intermediates: NewCertPool(), DNSName: test.dnsName, CurrentTime: time.Unix(test.currentTime, 0), + KeyUsages: test.keyUsages, } if !useSystemRoots { @@ -433,3 +475,58 @@ 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-----` diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index e6b0c58eef5..cfefbc5acec 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -9,6 +9,8 @@ import ( "bytes" "crypto" "crypto/dsa" + "crypto/ecdsa" + "crypto/elliptic" "crypto/rsa" "crypto/sha1" "crypto/x509/pkix" @@ -106,6 +108,8 @@ type dsaSignature struct { R, S *big.Int } +type ecdsaSignature dsaSignature + type validity struct { NotBefore, NotAfter time.Time } @@ -133,6 +137,10 @@ const ( SHA512WithRSA DSAWithSHA1 DSAWithSHA256 + ECDSAWithSHA1 + ECDSAWithSHA256 + ECDSAWithSHA384 + ECDSAWithSHA512 ) type PublicKeyAlgorithm int @@ -141,6 +149,7 @@ const ( UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota RSA DSA + ECDSA ) // OIDs for signature algorithms @@ -160,6 +169,12 @@ const ( // dsaWithSha1 OBJECT IDENTIFIER ::= { // 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 // @@ -176,15 +191,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 +235,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 +256,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 @@ -267,6 +365,9 @@ var ( 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} ) @@ -281,10 +382,48 @@ const ( ExtKeyUsageClientAuth ExtKeyUsageCodeSigning ExtKeyUsageEmailProtection + ExtKeyUsageIPSECEndSystem + ExtKeyUsageIPSECTunnel + ExtKeyUsageIPSECUser ExtKeyUsageTimeStamping ExtKeyUsageOCSPSigning ) +// 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}, +} + +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). @@ -427,13 +566,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 @@ -462,6 +601,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 } @@ -497,8 +648,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) { @@ -540,6 +689,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 } @@ -694,7 +864,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{} } @@ -730,22 +900,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) } } @@ -834,6 +991,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} @@ -842,7 +1000,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 { @@ -865,6 +1023,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}) @@ -941,11 +1120,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 @@ -956,8 +1130,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 @@ -965,23 +1140,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 } @@ -1005,15 +1218,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}, Subject: asn1.RawValue{FullBytes: asn1Subject}, - PublicKey: publicKeyInfo{nil, pkix.AlgorithmIdentifier{Algorithm: oidRSA}, encodedPublicKey}, + PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}, Extensions: extensions, } @@ -1024,11 +1237,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 } @@ -1036,7 +1262,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 diff --git a/libgo/go/crypto/x509/x509_test.go b/libgo/go/crypto/x509/x509_test.go index f0327b0124d..a13f4598d58 100644 --- a/libgo/go/crypto/x509/x509_test.go +++ b/libgo/go/crypto/x509/x509_test.go @@ -7,14 +7,19 @@ 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" + "reflect" "testing" "time" ) @@ -237,65 +242,205 @@ 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) + } + + 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}, + } + + testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth} + testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{3, 2, 1}} + + 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), + + SubjectKeyId: []byte{1, 2, 3, 4}, + KeyUsage: KeyUsageCertSign, + + ExtKeyUsage: testExtKeyUsage, + UnknownExtKeyUsage: testUnknownExtKeyUsage, + + BasicConstraintsValid: true, + IsCA: true, + DNSNames: []string{"test.example.com"}, + + PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, + PermittedDNSDomains: []string{".example.com", "example.com"}, + } - SubjectKeyId: []byte{1, 2, 3, 4}, - KeyUsage: KeyUsageCertSign, + 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 + } - BasicConstraintsValid: true, - IsCA: true, - DNSNames: []string{"test.example.com"}, + cert, err := ParseCertificate(derBytes) + if err != nil { + t.Errorf("%s: failed to parse certificate: %s", test.name, err) + continue + } - PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}}, - PermittedDNSDomains: []string{".example.com", "example.com"}, - } + 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) + } - derBytes, err := CreateCertificate(random, &template, &template, &priv.PublicKey, priv) - if err != nil { - t.Errorf("Failed to create certificate: %s", err) - return - } + 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) + } - cert, err := ParseCertificate(derBytes) - if err != nil { - t.Errorf("Failed to parse certificate: %s", err) - return - } + 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 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) - } + 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 len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" { - t.Errorf("Failed to parse name constraints: %#v", cert.PermittedDNSDomains) - } + 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.Subject.CommonName != commonName { - t.Errorf("Subject wasn't correctly copied from the template. Got %s, want %s", cert.Subject.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 cert.Issuer.CommonName != commonName { - t.Errorf("Issuer wasn't correctly copied from the template. Got %s, want %s", cert.Issuer.CommonName, commonName) + 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 verfication failed: %s", i, err) + } } } |