Rather than drop everything into a single, huge review, I've included some simple bits of code here. R=rsc CC=go-dev http://go/go-review/1016029v1.2.3
@@ -0,0 +1,43 @@ | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
type alertLevel int | |||
type alertType int | |||
const ( | |||
alertLevelWarning alertLevel = 1; | |||
alertLevelError alertLevel = 2; | |||
) | |||
const ( | |||
alertCloseNotify alertType = 0; | |||
alertUnexpectedMessage alertType = 10; | |||
alertBadRecordMAC alertType = 20; | |||
alertDecryptionFailed alertType = 21; | |||
alertRecordOverflow alertType = 22; | |||
alertDecompressionFailure alertType = 30; | |||
alertHandshakeFailure alertType = 40; | |||
alertBadCertificate alertType = 42; | |||
alertUnsupportedCertificate alertType = 43; | |||
alertCertificateRevoked alertType = 44; | |||
alertCertificateExpired alertType = 45; | |||
alertCertificateUnknown alertType = 46; | |||
alertIllegalParameter alertType = 47; | |||
alertUnknownCA alertType = 48; | |||
alertAccessDenied alertType = 49; | |||
alertDecodeError alertType = 50; | |||
alertDecryptError alertType = 51; | |||
alertProtocolVersion alertType = 70; | |||
alertInsufficientSecurity alertType = 71; | |||
alertInternalError alertType = 80; | |||
alertUserCanceled alertType = 90; | |||
alertNoRenegotiation alertType = 100; | |||
) | |||
type alert struct { | |||
level alertLevel; | |||
error alertType; | |||
} |
@@ -0,0 +1,123 @@ | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
import ( | |||
"crypto/rsa"; | |||
"io"; | |||
"os"; | |||
) | |||
const ( | |||
// maxTLSCiphertext is the maximum length of a plaintext payload. | |||
maxTLSPlaintext = 16384; | |||
// maxTLSCiphertext is the maximum length payload after compression and encryption. | |||
maxTLSCiphertext = 16384+2048; | |||
// maxHandshakeMsg is the largest single handshake message that we'll buffer. | |||
maxHandshakeMsg = 65536; | |||
) | |||
// TLS record types. | |||
type recordType uint8 | |||
const ( | |||
recordTypeChangeCipherSpec recordType = 20; | |||
recordTypeAlert recordType = 21; | |||
recordTypeHandshake recordType = 22; | |||
recordTypeApplicationData recordType = 23; | |||
) | |||
// TLS handshake message types. | |||
const ( | |||
typeClientHello uint8 = 1; | |||
typeServerHello uint8 = 2; | |||
typeCertificate uint8 = 11; | |||
typeServerHelloDone uint8 = 14; | |||
typeClientKeyExchange uint8 = 16; | |||
typeFinished uint8 = 20; | |||
) | |||
// TLS cipher suites. | |||
var ( | |||
TLS_RSA_WITH_RC4_128_SHA uint16 = 5; | |||
) | |||
// TLS compression types. | |||
var ( | |||
compressionNone uint8 = 0; | |||
) | |||
type ConnectionState struct { | |||
HandshakeComplete bool; | |||
CipherSuite string; | |||
Error alertType; | |||
} | |||
// A Config structure is used to configure a TLS client or server. After one | |||
// has been passed to a TLS function it must not be modified. | |||
type Config struct { | |||
// Rand provides the source of entropy for nonces and RSA blinding. | |||
Rand io.Reader; | |||
// Time returns the current time as the number of seconds since the epoch. | |||
Time func() int64; | |||
Certificates []Certificate; | |||
} | |||
type Certificate struct { | |||
Certificate [][]byte; | |||
PrivateKey *rsa.PrivateKey; | |||
} | |||
// A TLS record. | |||
type record struct { | |||
contentType recordType; | |||
major, minor uint8; | |||
payload []byte; | |||
} | |||
type handshakeMessage interface { | |||
marshal() []byte; | |||
} | |||
type encryptor interface { | |||
// XORKeyStream xors the contents of the slice with bytes from the key stream. | |||
XORKeyStream(buf []byte); | |||
} | |||
// mutualVersion returns the protocol version to use given the advertised | |||
// version of the peer. | |||
func mutualVersion(theirMajor, theirMinor uint8) (major, minor uint8, ok bool) { | |||
// We don't deal with peers < TLS 1.0 (aka version 3.1). | |||
if theirMajor < 3 || theirMajor == 3 && theirMinor < 1 { | |||
return 0, 0, false; | |||
} | |||
major = 3; | |||
minor = 2; | |||
if theirMinor < minor { | |||
minor = theirMinor; | |||
} | |||
ok = true; | |||
return; | |||
} | |||
// A nop implements the NULL encryption and MAC algorithms. | |||
type nop struct{} | |||
func (nop) XORKeyStream(buf []byte) {} | |||
func (nop) Write(buf []byte) (int, os.Error) { | |||
return len(buf), nil; | |||
} | |||
func (nop) Sum() []byte { | |||
return nil; | |||
} | |||
func (nop) Reset() {} | |||
func (nop) Size() int { | |||
return 0; | |||
} |
@@ -0,0 +1,148 @@ | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
import ( | |||
"bytes"; | |||
"crypto/hmac"; | |||
"crypto/md5"; | |||
"crypto/sha1"; | |||
"hash"; | |||
"os"; | |||
"strings"; | |||
) | |||
// Split a premaster secret in two as specified in RFC 4346, section 5. | |||
func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { | |||
s1 = secret[0 : (len(secret)+1)/2]; | |||
s2 = secret[len(secret)/2 : len(secret)]; | |||
return; | |||
} | |||
// pHash implements the P_hash function, as defined in RFC 4346, section 5. | |||
func pHash(result, secret, seed []byte, hash hash.Hash) { | |||
h := hmac.New(hash, secret); | |||
h.Write(seed); | |||
a := h.Sum(); | |||
j := 0; | |||
for j < len(result) { | |||
h.Reset(); | |||
h.Write(a); | |||
h.Write(seed); | |||
b := h.Sum(); | |||
todo := len(b); | |||
if j+todo > len(result) { | |||
todo = len(result)-j; | |||
} | |||
bytes.Copy(result[j : j+todo], b); | |||
j += todo; | |||
h.Reset(); | |||
h.Write(a); | |||
a = h.Sum(); | |||
} | |||
} | |||
// pRF11 implements the TLS 1.1 pseudo-random function, as defined in RFC 4346, section 5. | |||
func pRF11(result, secret, label, seed []byte) { | |||
hashSHA1 := sha1.New(); | |||
hashMD5 := md5.New(); | |||
labelAndSeed := make([]byte, len(label)+len(seed)); | |||
bytes.Copy(labelAndSeed, label); | |||
bytes.Copy(labelAndSeed[len(label):len(labelAndSeed)], seed); | |||
s1, s2 := splitPreMasterSecret(secret); | |||
pHash(result, s1, labelAndSeed, hashMD5); | |||
result2 := make([]byte, len(result)); | |||
pHash(result2, s2, labelAndSeed, hashSHA1); | |||
for i, b := range result2 { | |||
result[i] ^= b; | |||
} | |||
} | |||
const ( | |||
tlsRandomLength = 32; // Length of a random nonce in TLS 1.1. | |||
masterSecretLength = 48; // Length of a master secret in TLS 1.1. | |||
finishedVerifyLength = 12; // Length of verify_data in a Finished message. | |||
) | |||
var masterSecretLabel = strings.Bytes("master secret") | |||
var keyExpansionLabel = strings.Bytes("key expansion") | |||
var clientFinishedLabel = strings.Bytes("client finished") | |||
var serverFinishedLabel = strings.Bytes("server finished") | |||
// keysFromPreMasterSecret generates the connection keys from the pre master | |||
// secret, given the lengths of the MAC and cipher keys, as defined in RFC | |||
// 4346, section 6.3. | |||
func keysFromPreMasterSecret11(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey []byte) { | |||
var seed [tlsRandomLength * 2]byte; | |||
bytes.Copy(seed[0:len(clientRandom)], clientRandom); | |||
bytes.Copy(seed[len(clientRandom):len(seed)], serverRandom); | |||
masterSecret = make([]byte, masterSecretLength); | |||
pRF11(masterSecret, preMasterSecret, masterSecretLabel, seed[0:len(seed)]); | |||
bytes.Copy(seed[0:len(clientRandom)], serverRandom); | |||
bytes.Copy(seed[len(serverRandom):len(seed)], clientRandom); | |||
n := 2*macLen + 2*keyLen; | |||
keyMaterial := make([]byte, n); | |||
pRF11(keyMaterial, masterSecret, keyExpansionLabel, seed[0:len(seed)]); | |||
clientMAC = keyMaterial[0:macLen]; | |||
serverMAC = keyMaterial[macLen : macLen*2]; | |||
clientKey = keyMaterial[macLen*2 : macLen*2 + keyLen]; | |||
serverKey = keyMaterial[macLen*2 + keyLen : len(keyMaterial)]; | |||
return; | |||
} | |||
// A finishedHash calculates the hash of a set of handshake messages suitable | |||
// for including in a Finished message. | |||
type finishedHash struct { | |||
clientMD5 hash.Hash; | |||
clientSHA1 hash.Hash; | |||
serverMD5 hash.Hash; | |||
serverSHA1 hash.Hash; | |||
} | |||
func newFinishedHash() finishedHash { | |||
return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New()}; | |||
} | |||
func (h finishedHash) Write(msg []byte) (n int, err os.Error) { | |||
h.clientMD5.Write(msg); | |||
h.clientSHA1.Write(msg); | |||
h.serverMD5.Write(msg); | |||
h.serverSHA1.Write(msg); | |||
return len(msg), nil; | |||
} | |||
// finishedSum calculates the contents of the verify_data member of a Finished | |||
// message given the MD5 and SHA1 hashes of a set of handshake messages. | |||
func finishedSum(md5, sha1, label, masterSecret []byte) []byte { | |||
seed := make([]byte, len(md5)+len(sha1)); | |||
bytes.Copy(seed, md5); | |||
bytes.Copy(seed[len(md5):len(seed)], sha1); | |||
out := make([]byte, finishedVerifyLength); | |||
pRF11(out, masterSecret, label, seed); | |||
return out; | |||
} | |||
// clientSum returns the contents of the verify_data member of a client's | |||
// Finished message. | |||
func (h finishedHash) clientSum(masterSecret []byte) []byte { | |||
md5 := h.clientMD5.Sum(); | |||
sha1 := h.clientSHA1.Sum(); | |||
return finishedSum(md5, sha1, clientFinishedLabel, masterSecret); | |||
} | |||
// serverSum returns the contents of the verify_data member of a server's | |||
// Finished message. | |||
func (h finishedHash) serverSum(masterSecret []byte) []byte { | |||
md5 := h.serverMD5.Sum(); | |||
sha1 := h.serverSHA1.Sum(); | |||
return finishedSum(md5, sha1, serverFinishedLabel, masterSecret); | |||
} |
@@ -0,0 +1,104 @@ | |||
// Copyright 2009 The Go Authors. All rights reserved. | |||
// Use of this source code is governed by a BSD-style | |||
// license that can be found in the LICENSE file. | |||
package tls | |||
import ( | |||
"encoding/hex"; | |||
"testing"; | |||
) | |||
type testSplitPreMasterSecretTest struct { | |||
in, out1, out2 string; | |||
} | |||
var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{ | |||
testSplitPreMasterSecretTest{"", "", ""}, | |||
testSplitPreMasterSecretTest{"00", "00", "00"}, | |||
testSplitPreMasterSecretTest{"0011", "00", "11"}, | |||
testSplitPreMasterSecretTest{"001122", "0011", "1122"}, | |||
testSplitPreMasterSecretTest{"00112233", "0011", "2233"}, | |||
} | |||
func TestSplitPreMasterSecret(t *testing.T) { | |||
for i, test := range testSplitPreMasterSecretTests { | |||
in, _ := hex.DecodeString(test.in); | |||
out1, out2 := splitPreMasterSecret(in); | |||
s1 := hex.EncodeToString(out1); | |||
s2 := hex.EncodeToString(out2); | |||
if s1 != test.out1 || s2 != test.out2 { | |||
t.Errorf("#%d: got: (%s, %s) want: (%s, %s)", i, s1, s2, test.out1, test.out2); | |||
} | |||
} | |||
} | |||
type testKeysFromTest struct { | |||
preMasterSecret string; | |||
clientRandom, serverRandom string; | |||
masterSecret string; | |||
clientMAC, serverMAC string; | |||
clientKey, serverKey string; | |||
macLen, keyLen int; | |||
} | |||
func TestKeysFromPreMasterSecret(t *testing.T) { | |||
for i, test := range testKeysFromTests { | |||
in, _ := hex.DecodeString(test.preMasterSecret); | |||
clientRandom, _ := hex.DecodeString(test.clientRandom); | |||
serverRandom, _ := hex.DecodeString(test.serverRandom); | |||
master, clientMAC, serverMAC, clientKey, serverKey := keysFromPreMasterSecret11(in, clientRandom, serverRandom, test.macLen, test.keyLen); | |||
masterString := hex.EncodeToString(master); | |||
clientMACString := hex.EncodeToString(clientMAC); | |||
serverMACString := hex.EncodeToString(serverMAC); | |||
clientKeyString := hex.EncodeToString(clientKey); | |||
serverKeyString := hex.EncodeToString(serverKey); | |||
if masterString != test.masterSecret || | |||
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, serverMACString, test.masterSecret, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey); | |||
} | |||
} | |||
} | |||
// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 ` | |||
var testKeysFromTests = []testKeysFromTest{ | |||
testKeysFromTest{ | |||
"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5", | |||
"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558", | |||
"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db", | |||
"3d851bab6e5556e959a16bc36d66cfae32f672bfa9ecdef6096cbb1b23472df1da63dbbd9827606413221d149ed08ceb", | |||
"805aaa19b3d2c0a0759a4b6c9959890e08480119", | |||
"2d22f9fe519c075c16448305ceee209fc24ad109", | |||
"d50b5771244f850cd8117a9ccafe2cf1", | |||
"e076e33206b30507a85c32855acd0919", | |||
20, | |||
16, | |||
}, | |||
testKeysFromTest{ | |||
"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890", | |||
"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106", | |||
"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c", | |||
"7d64be7c80c59b740200b4b9c26d0baaa1c5ae56705acbcf2307fe62beb4728c19392c83f20483801cce022c77645460", | |||
"97742ed60a0554ca13f04f97ee193177b971e3b0", | |||
"37068751700400e03a8477a5c7eec0813ab9e0dc", | |||
"207cddbc600d2a200abac6502053ee5c", | |||
"df3f94f6e1eacc753b815fe16055cd43", | |||
20, | |||
16, | |||
}, | |||
testKeysFromTest{ | |||
"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1", | |||
"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e", | |||
"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e", | |||
"1aff2e7a2c4279d0126f57a65a77a8d9d0087cf2733366699bec27eb53d5740705a8574bb1acc2abbe90e44f0dd28d6c", | |||
"3c7647c93c1379a31a609542aa44e7f117a70085", | |||
"0d73102994be74a575a3ead8532590ca32a526d4", | |||
"ac7581b0b6c10d85bbd905ffbf36c65e", | |||
"ff07edde49682b45466bd2e39464b306", | |||
20, | |||
16, | |||
}, | |||
} |