crypto/tls: support SSLv3
It would be nice not to have to support this since all the clients that we care about support TLSv1 by now. However, due to buggy implementations of SSLv3 on the Internet which can't do version negotiation correctly, browsers will sometimes switch to SSLv3. Since there's no good way for a browser tell a network problem from a buggy server, this downgrade can occur even if the server in question is actually working correctly. So we need to support SSLv3 for robustness :( Fixes #1703. R=bradfitz CC=golang-dev https://golang.org/cl/5018045
This commit is contained in:
parent
39082848cf
commit
76c2ff557a
@ -9,6 +9,7 @@ import (
|
|||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rc4"
|
"crypto/rc4"
|
||||||
|
"crypto/sha1"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"hash"
|
"hash"
|
||||||
"os"
|
"os"
|
||||||
@ -23,7 +24,7 @@ type keyAgreement interface {
|
|||||||
// ServerKeyExchange message, generateServerKeyExchange can return nil,
|
// ServerKeyExchange message, generateServerKeyExchange can return nil,
|
||||||
// nil.
|
// nil.
|
||||||
generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, os.Error)
|
generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, os.Error)
|
||||||
processClientKeyExchange(*Config, *clientKeyExchangeMsg) ([]byte, os.Error)
|
processClientKeyExchange(*Config, *clientKeyExchangeMsg, uint16) ([]byte, os.Error)
|
||||||
|
|
||||||
// On the client side, the next two methods are called in order.
|
// On the client side, the next two methods are called in order.
|
||||||
|
|
||||||
@ -46,14 +47,14 @@ type cipherSuite struct {
|
|||||||
// and point format that we can handle.
|
// and point format that we can handle.
|
||||||
elliptic bool
|
elliptic bool
|
||||||
cipher func(key, iv []byte, isRead bool) interface{}
|
cipher func(key, iv []byte, isRead bool) interface{}
|
||||||
mac func(macKey []byte) hash.Hash
|
mac func(version uint16, macKey []byte) macFunction
|
||||||
}
|
}
|
||||||
|
|
||||||
var cipherSuites = map[uint16]*cipherSuite{
|
var cipherSuites = map[uint16]*cipherSuite{
|
||||||
TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, hmacSHA1},
|
TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, macSHA1},
|
||||||
TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, hmacSHA1},
|
TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, macSHA1},
|
||||||
TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, hmacSHA1},
|
TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, macSHA1},
|
||||||
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, hmacSHA1},
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, macSHA1},
|
||||||
}
|
}
|
||||||
|
|
||||||
func cipherRC4(key, iv []byte, isRead bool) interface{} {
|
func cipherRC4(key, iv []byte, isRead bool) interface{} {
|
||||||
@ -69,8 +70,75 @@ func cipherAES(key, iv []byte, isRead bool) interface{} {
|
|||||||
return cipher.NewCBCEncrypter(block, iv)
|
return cipher.NewCBCEncrypter(block, iv)
|
||||||
}
|
}
|
||||||
|
|
||||||
func hmacSHA1(key []byte) hash.Hash {
|
// macSHA1 returns a macFunction for the given protocol version.
|
||||||
return hmac.NewSHA1(key)
|
func macSHA1(version uint16, key []byte) macFunction {
|
||||||
|
if version == versionSSL30 {
|
||||||
|
mac := ssl30MAC{
|
||||||
|
h: sha1.New(),
|
||||||
|
key: make([]byte, len(key)),
|
||||||
|
}
|
||||||
|
copy(mac.key, key)
|
||||||
|
return mac
|
||||||
|
}
|
||||||
|
return tls10MAC{hmac.NewSHA1(key)}
|
||||||
|
}
|
||||||
|
|
||||||
|
type macFunction interface {
|
||||||
|
Size() int
|
||||||
|
MAC(seq, data []byte) []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// ssl30MAC implements the SSLv3 MAC function, as defined in
|
||||||
|
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
|
||||||
|
type ssl30MAC struct {
|
||||||
|
h hash.Hash
|
||||||
|
key []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s ssl30MAC) Size() int {
|
||||||
|
return s.h.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
|
||||||
|
|
||||||
|
var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
|
||||||
|
|
||||||
|
func (s ssl30MAC) MAC(seq, record []byte) []byte {
|
||||||
|
padLength := 48
|
||||||
|
if s.h.Size() == 20 {
|
||||||
|
padLength = 40
|
||||||
|
}
|
||||||
|
|
||||||
|
s.h.Reset()
|
||||||
|
s.h.Write(s.key)
|
||||||
|
s.h.Write(ssl30Pad1[:padLength])
|
||||||
|
s.h.Write(seq)
|
||||||
|
s.h.Write(record[:1])
|
||||||
|
s.h.Write(record[3:5])
|
||||||
|
s.h.Write(record[recordHeaderLen:])
|
||||||
|
digest := s.h.Sum()
|
||||||
|
|
||||||
|
s.h.Reset()
|
||||||
|
s.h.Write(s.key)
|
||||||
|
s.h.Write(ssl30Pad2[:padLength])
|
||||||
|
s.h.Write(digest)
|
||||||
|
return s.h.Sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, section 6.2.3.
|
||||||
|
type tls10MAC struct {
|
||||||
|
h hash.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s tls10MAC) Size() int {
|
||||||
|
return s.h.Size()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s tls10MAC) MAC(seq, record []byte) []byte {
|
||||||
|
s.h.Reset()
|
||||||
|
s.h.Write(seq)
|
||||||
|
s.h.Write(record)
|
||||||
|
return s.h.Sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
func rsaKA() keyAgreement {
|
func rsaKA() keyAgreement {
|
||||||
|
@ -20,8 +20,11 @@ const (
|
|||||||
recordHeaderLen = 5 // record header length
|
recordHeaderLen = 5 // record header length
|
||||||
maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
|
maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
|
||||||
|
|
||||||
minVersion = 0x0301 // minimum supported version - TLS 1.0
|
versionSSL30 = 0x0300
|
||||||
maxVersion = 0x0301 // maximum supported version - TLS 1.0
|
versionTLS10 = 0x0301
|
||||||
|
|
||||||
|
minVersion = versionSSL30
|
||||||
|
maxVersion = versionTLS10
|
||||||
)
|
)
|
||||||
|
|
||||||
// TLS record types.
|
// TLS record types.
|
||||||
|
50
conn.go
50
conn.go
@ -11,7 +11,6 @@ import (
|
|||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
"crypto/subtle"
|
"crypto/subtle"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
"hash"
|
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
@ -108,18 +107,20 @@ func (c *Conn) SetWriteTimeout(nsec int64) os.Error {
|
|||||||
// connection, either sending or receiving.
|
// connection, either sending or receiving.
|
||||||
type halfConn struct {
|
type halfConn struct {
|
||||||
sync.Mutex
|
sync.Mutex
|
||||||
cipher interface{} // cipher algorithm
|
version uint16 // protocol version
|
||||||
mac hash.Hash // MAC algorithm
|
cipher interface{} // cipher algorithm
|
||||||
seq [8]byte // 64-bit sequence number
|
mac macFunction
|
||||||
bfree *block // list of free blocks
|
seq [8]byte // 64-bit sequence number
|
||||||
|
bfree *block // list of free blocks
|
||||||
|
|
||||||
nextCipher interface{} // next encryption state
|
nextCipher interface{} // next encryption state
|
||||||
nextMac hash.Hash // next MAC algorithm
|
nextMac macFunction // next MAC algorithm
|
||||||
}
|
}
|
||||||
|
|
||||||
// prepareCipherSpec sets the encryption and MAC states
|
// prepareCipherSpec sets the encryption and MAC states
|
||||||
// that a subsequent changeCipherSpec will use.
|
// that a subsequent changeCipherSpec will use.
|
||||||
func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) {
|
func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
|
||||||
|
hc.version = version
|
||||||
hc.nextCipher = cipher
|
hc.nextCipher = cipher
|
||||||
hc.nextMac = mac
|
hc.nextMac = mac
|
||||||
}
|
}
|
||||||
@ -197,6 +198,22 @@ func removePadding(payload []byte) ([]byte, byte) {
|
|||||||
return payload[:len(payload)-int(toRemove)], good
|
return payload[:len(payload)-int(toRemove)], good
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// removePaddingSSL30 is a replacement for removePadding in the case that the
|
||||||
|
// protocol version is SSLv3. In this version, the contents of the padding
|
||||||
|
// are random and cannot be checked.
|
||||||
|
func removePaddingSSL30(payload []byte) ([]byte, byte) {
|
||||||
|
if len(payload) < 1 {
|
||||||
|
return payload, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
paddingLen := int(payload[len(payload)-1]) + 1
|
||||||
|
if paddingLen > len(payload) {
|
||||||
|
return payload, 0
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload[:len(payload)-paddingLen], 255
|
||||||
|
}
|
||||||
|
|
||||||
func roundUp(a, b int) int {
|
func roundUp(a, b int) int {
|
||||||
return a + (b-a%b)%b
|
return a + (b-a%b)%b
|
||||||
}
|
}
|
||||||
@ -226,7 +243,11 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
c.CryptBlocks(payload, payload)
|
c.CryptBlocks(payload, payload)
|
||||||
payload, paddingGood = removePadding(payload)
|
if hc.version == versionSSL30 {
|
||||||
|
payload, paddingGood = removePaddingSSL30(payload)
|
||||||
|
} else {
|
||||||
|
payload, paddingGood = removePadding(payload)
|
||||||
|
}
|
||||||
b.resize(recordHeaderLen + len(payload))
|
b.resize(recordHeaderLen + len(payload))
|
||||||
|
|
||||||
// note that we still have a timing side-channel in the
|
// note that we still have a timing side-channel in the
|
||||||
@ -256,13 +277,10 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) {
|
|||||||
b.data[4] = byte(n)
|
b.data[4] = byte(n)
|
||||||
b.resize(recordHeaderLen + n)
|
b.resize(recordHeaderLen + n)
|
||||||
remoteMAC := payload[n:]
|
remoteMAC := payload[n:]
|
||||||
|
localMAC := hc.mac.MAC(hc.seq[0:], b.data)
|
||||||
hc.mac.Reset()
|
|
||||||
hc.mac.Write(hc.seq[0:])
|
|
||||||
hc.incSeq()
|
hc.incSeq()
|
||||||
hc.mac.Write(b.data)
|
|
||||||
|
|
||||||
if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 {
|
if subtle.ConstantTimeCompare(localMAC, remoteMAC) != 1 || paddingGood != 255 {
|
||||||
return false, alertBadRecordMAC
|
return false, alertBadRecordMAC
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -291,11 +309,9 @@ func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) {
|
|||||||
func (hc *halfConn) encrypt(b *block) (bool, alert) {
|
func (hc *halfConn) encrypt(b *block) (bool, alert) {
|
||||||
// mac
|
// mac
|
||||||
if hc.mac != nil {
|
if hc.mac != nil {
|
||||||
hc.mac.Reset()
|
mac := hc.mac.MAC(hc.seq[0:], b.data)
|
||||||
hc.mac.Write(hc.seq[0:])
|
|
||||||
hc.incSeq()
|
hc.incSeq()
|
||||||
hc.mac.Write(b.data)
|
|
||||||
mac := hc.mac.Sum()
|
|
||||||
n := len(b.data)
|
n := len(b.data)
|
||||||
b.resize(n + len(mac))
|
b.resize(n + len(mac))
|
||||||
copy(b.data[n:], mac)
|
copy(b.data[n:], mac)
|
||||||
|
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (c *Conn) clientHandshake() os.Error {
|
func (c *Conn) clientHandshake() os.Error {
|
||||||
finishedHash := newFinishedHash()
|
finishedHash := newFinishedHash(versionTLS10)
|
||||||
|
|
||||||
if c.config == nil {
|
if c.config == nil {
|
||||||
c.config = defaultConfig()
|
c.config = defaultConfig()
|
||||||
@ -247,11 +247,11 @@ func (c *Conn) clientHandshake() os.Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
||||||
keysFromPreMasterSecret10(preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
|
keysFromPreMasterSecret(c.vers, preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen)
|
||||||
|
|
||||||
clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
|
clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ )
|
||||||
clientHash := suite.mac(clientMAC)
|
clientHash := suite.mac(c.vers, clientMAC)
|
||||||
c.out.prepareCipherSpec(clientCipher, clientHash)
|
c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
|
||||||
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||||||
|
|
||||||
if serverHello.nextProtoNeg {
|
if serverHello.nextProtoNeg {
|
||||||
@ -271,8 +271,8 @@ func (c *Conn) clientHandshake() os.Error {
|
|||||||
c.writeRecord(recordTypeHandshake, finished.marshal())
|
c.writeRecord(recordTypeHandshake, finished.marshal())
|
||||||
|
|
||||||
serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
|
serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ )
|
||||||
serverHash := suite.mac(serverMAC)
|
serverHash := suite.mac(c.vers, serverMAC)
|
||||||
c.in.prepareCipherSpec(serverCipher, serverHash)
|
c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
|
||||||
c.readRecord(recordTypeChangeCipherSpec)
|
c.readRecord(recordTypeChangeCipherSpec)
|
||||||
if c.err != nil {
|
if c.err != nil {
|
||||||
return c.err
|
return c.err
|
||||||
|
@ -18,6 +18,7 @@ func testClientScript(t *testing.T, name string, clientScript [][]byte, config *
|
|||||||
go func() {
|
go func() {
|
||||||
cli.Write([]byte("hello\n"))
|
cli.Write([]byte("hello\n"))
|
||||||
cli.Close()
|
cli.Close()
|
||||||
|
c.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
|
@ -676,9 +676,9 @@ func (m *finishedMsg) marshal() (x []byte) {
|
|||||||
return m.raw
|
return m.raw
|
||||||
}
|
}
|
||||||
|
|
||||||
x = make([]byte, 16)
|
x = make([]byte, 4+len(m.verifyData))
|
||||||
x[0] = typeFinished
|
x[0] = typeFinished
|
||||||
x[3] = 12
|
x[3] = byte(len(m.verifyData))
|
||||||
copy(x[4:], m.verifyData)
|
copy(x[4:], m.verifyData)
|
||||||
m.raw = x
|
m.raw = x
|
||||||
return
|
return
|
||||||
@ -686,7 +686,7 @@ func (m *finishedMsg) marshal() (x []byte) {
|
|||||||
|
|
||||||
func (m *finishedMsg) unmarshal(data []byte) bool {
|
func (m *finishedMsg) unmarshal(data []byte) bool {
|
||||||
m.raw = data
|
m.raw = data
|
||||||
if len(data) != 4+12 {
|
if len(data) < 4 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
m.verifyData = data[4:]
|
m.verifyData = data[4:]
|
||||||
|
@ -14,13 +14,13 @@ import (
|
|||||||
var tests = []interface{}{
|
var tests = []interface{}{
|
||||||
&clientHelloMsg{},
|
&clientHelloMsg{},
|
||||||
&serverHelloMsg{},
|
&serverHelloMsg{},
|
||||||
|
&finishedMsg{},
|
||||||
|
|
||||||
&certificateMsg{},
|
&certificateMsg{},
|
||||||
&certificateRequestMsg{},
|
&certificateRequestMsg{},
|
||||||
&certificateVerifyMsg{},
|
&certificateVerifyMsg{},
|
||||||
&certificateStatusMsg{},
|
&certificateStatusMsg{},
|
||||||
&clientKeyExchangeMsg{},
|
&clientKeyExchangeMsg{},
|
||||||
&finishedMsg{},
|
|
||||||
&nextProtoMsg{},
|
&nextProtoMsg{},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,11 +59,12 @@ func TestMarshalUnmarshal(t *testing.T) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if i >= 2 {
|
if i >= 3 {
|
||||||
// The first two message types (ClientHello and
|
// The first three message types (ClientHello,
|
||||||
// ServerHello) are allowed to have parsable
|
// ServerHello and Finished) are allowed to
|
||||||
// prefixes because the extension data is
|
// have parsable prefixes because the extension
|
||||||
// optional.
|
// data is optional and the length of the
|
||||||
|
// Finished varies across versions.
|
||||||
for j := 0; j < len(marshaled); j++ {
|
for j := 0; j < len(marshaled); j++ {
|
||||||
if m2.unmarshal(marshaled[0:j]) {
|
if m2.unmarshal(marshaled[0:j]) {
|
||||||
t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1)
|
t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1)
|
||||||
|
@ -30,7 +30,7 @@ func (c *Conn) serverHandshake() os.Error {
|
|||||||
c.vers = vers
|
c.vers = vers
|
||||||
c.haveVers = true
|
c.haveVers = true
|
||||||
|
|
||||||
finishedHash := newFinishedHash()
|
finishedHash := newFinishedHash(vers)
|
||||||
finishedHash.Write(clientHello.marshal())
|
finishedHash.Write(clientHello.marshal())
|
||||||
|
|
||||||
hello := new(serverHelloMsg)
|
hello := new(serverHelloMsg)
|
||||||
@ -128,7 +128,6 @@ FindCipherSuite:
|
|||||||
}
|
}
|
||||||
|
|
||||||
keyAgreement := suite.ka()
|
keyAgreement := suite.ka()
|
||||||
|
|
||||||
skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello)
|
skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sendAlert(alertHandshakeFailure)
|
c.sendAlert(alertHandshakeFailure)
|
||||||
@ -235,18 +234,18 @@ FindCipherSuite:
|
|||||||
finishedHash.Write(certVerify.marshal())
|
finishedHash.Write(certVerify.marshal())
|
||||||
}
|
}
|
||||||
|
|
||||||
preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
|
preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx, c.vers)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.sendAlert(alertHandshakeFailure)
|
c.sendAlert(alertHandshakeFailure)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
|
||||||
keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
|
keysFromPreMasterSecret(c.vers, preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
|
||||||
|
|
||||||
clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
|
clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ )
|
||||||
clientHash := suite.mac(clientMAC)
|
clientHash := suite.mac(c.vers, clientMAC)
|
||||||
c.in.prepareCipherSpec(clientCipher, clientHash)
|
c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
|
||||||
c.readRecord(recordTypeChangeCipherSpec)
|
c.readRecord(recordTypeChangeCipherSpec)
|
||||||
if err := c.error(); err != nil {
|
if err := c.error(); err != nil {
|
||||||
return err
|
return err
|
||||||
@ -283,8 +282,8 @@ FindCipherSuite:
|
|||||||
finishedHash.Write(clientFinished.marshal())
|
finishedHash.Write(clientFinished.marshal())
|
||||||
|
|
||||||
serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
|
serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ )
|
||||||
serverHash := suite.mac(serverMAC)
|
serverHash := suite.mac(c.vers, serverMAC)
|
||||||
c.out.prepareCipherSpec(serverCipher, serverHash)
|
c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
|
||||||
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
c.writeRecord(recordTypeChangeCipherSpec, []byte{1})
|
||||||
|
|
||||||
finished := new(finishedMsg)
|
finished := new(finishedMsg)
|
||||||
|
@ -62,7 +62,7 @@ func TestSimpleError(t *testing.T) {
|
|||||||
testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
|
testClientHelloFailure(t, &serverHelloDoneMsg{}, alertUnexpectedMessage)
|
||||||
}
|
}
|
||||||
|
|
||||||
var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205, 0x0300}
|
var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205}
|
||||||
|
|
||||||
func TestRejectBadProtocolVersion(t *testing.T) {
|
func TestRejectBadProtocolVersion(t *testing.T) {
|
||||||
for _, v := range badProtocolVersions {
|
for _, v := range badProtocolVersions {
|
||||||
@ -112,6 +112,7 @@ func testServerScript(t *testing.T, name string, serverScript [][]byte, config *
|
|||||||
go func() {
|
go func() {
|
||||||
srv.Write([]byte("hello, world\n"))
|
srv.Write([]byte("hello, world\n"))
|
||||||
srv.Close()
|
srv.Close()
|
||||||
|
s.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
defer c.Close()
|
defer c.Close()
|
||||||
@ -121,9 +122,9 @@ func testServerScript(t *testing.T, name string, serverScript [][]byte, config *
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
bb := make([]byte, len(b))
|
bb := make([]byte, len(b))
|
||||||
_, err := io.ReadFull(c, bb)
|
n, err := io.ReadFull(c, bb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("%s #%d: %s", name, i, err)
|
t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", name, i, err, n, len(bb), bb[:n], b)
|
||||||
}
|
}
|
||||||
if !bytes.Equal(b, bb) {
|
if !bytes.Equal(b, bb) {
|
||||||
t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
|
t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b)
|
||||||
@ -142,50 +143,8 @@ func TestHandshakeServerAES(t *testing.T) {
|
|||||||
testServerScript(t, "AES", aesServerScript, aesConfig)
|
testServerScript(t, "AES", aesServerScript, aesConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestUnexpectedTLS(t *testing.T) {
|
func TestHandshakeServerSSLv3(t *testing.T) {
|
||||||
l, err := Listen("tcp", "127.0.0.1:0", testConfig)
|
testServerScript(t, "SSLv3", sslv3ServerScript, testConfig)
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
ch := make(chan os.Error, 1)
|
|
||||||
done := make(chan bool)
|
|
||||||
go func() {
|
|
||||||
// Simulate HTTP client trying to do unencrypted HTTP on TLS port.
|
|
||||||
c, err := net.Dial("tcp", l.Addr().String())
|
|
||||||
if err != nil {
|
|
||||||
ch <- err
|
|
||||||
<-done
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer func() {
|
|
||||||
<-done
|
|
||||||
c.Close()
|
|
||||||
}()
|
|
||||||
_, err = c.Write([]byte("GET / HTTP/1.0\r\nHost: www.google.com\r\n\r\n"))
|
|
||||||
if err != nil {
|
|
||||||
ch <- err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
ch <- nil
|
|
||||||
}()
|
|
||||||
|
|
||||||
c, err := l.Accept()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
buf := make([]byte, 100)
|
|
||||||
n, err := c.Read(buf)
|
|
||||||
if n > 0 || err == nil {
|
|
||||||
t.Errorf("TLS Read = %d, %v, want error", n, err)
|
|
||||||
}
|
|
||||||
t.Logf("%d, %v", n, err)
|
|
||||||
|
|
||||||
err = <-ch
|
|
||||||
done <- true
|
|
||||||
if err != nil {
|
|
||||||
t.Errorf("TLS Write: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var serve = flag.Bool("serve", false, "run a TLS server on :10443")
|
var serve = flag.Bool("serve", false, "run a TLS server on :10443")
|
||||||
@ -561,3 +520,165 @@ var aesServerScript = [][]byte{
|
|||||||
0xcd, 0x84, 0xf0,
|
0xcd, 0x84, 0xf0,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var sslv3ServerScript = [][]byte{
|
||||||
|
{
|
||||||
|
0x16, 0x03, 0x00, 0x00, 0x41, 0x01, 0x00, 0x00,
|
||||||
|
0x3d, 0x03, 0x00, 0x4e, 0x70, 0xe2, 0x18, 0x86,
|
||||||
|
0xd6, 0xc6, 0x6f, 0xf3, 0xc8, 0xf4, 0x02, 0xd6,
|
||||||
|
0x4d, 0xee, 0x17, 0x32, 0x4b, 0xd2, 0x78, 0xd8,
|
||||||
|
0xa1, 0x03, 0x5d, 0x68, 0x82, 0x89, 0xbe, 0xfd,
|
||||||
|
0x12, 0xb9, 0x06, 0x00, 0x00, 0x16, 0x00, 0x33,
|
||||||
|
0x00, 0x39, 0x00, 0x16, 0x00, 0x32, 0x00, 0x38,
|
||||||
|
0x00, 0x13, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a,
|
||||||
|
0x00, 0x05, 0x00, 0x04, 0x01, 0x00,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
0x16, 0x03, 0x00, 0x00, 0x2a, 0x02, 0x00, 0x00,
|
||||||
|
0x26, 0x03, 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, 0x00, 0x05, 0x00, 0x16,
|
||||||
|
0x03, 0x00, 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, 0x00, 0x00, 0x04, 0x0e,
|
||||||
|
0x00, 0x00, 0x00,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
0x16, 0x03, 0x00, 0x00, 0x84, 0x10, 0x00, 0x00,
|
||||||
|
0x80, 0x74, 0x0e, 0x3a, 0xcf, 0xba, 0x9f, 0x1a,
|
||||||
|
0x9b, 0xb2, 0xa4, 0xc7, 0x5d, 0xf3, 0x0c, 0x80,
|
||||||
|
0x06, 0x80, 0xf3, 0x57, 0xb2, 0xd9, 0x36, 0x24,
|
||||||
|
0x6a, 0x06, 0x13, 0x40, 0xf9, 0x7c, 0xb9, 0x3e,
|
||||||
|
0x4b, 0x68, 0x4f, 0x21, 0x90, 0x2d, 0xbd, 0xca,
|
||||||
|
0xd4, 0x83, 0xf0, 0x7a, 0xeb, 0x7a, 0x74, 0x1b,
|
||||||
|
0xcd, 0xfe, 0x69, 0xef, 0xc0, 0x86, 0xa0, 0x24,
|
||||||
|
0x31, 0x65, 0x40, 0xd2, 0xdd, 0x6f, 0xb9, 0xd7,
|
||||||
|
0x8d, 0xc1, 0x69, 0x60, 0x44, 0x7a, 0x75, 0xfb,
|
||||||
|
0x42, 0x6a, 0x0f, 0x66, 0x45, 0x10, 0x73, 0xee,
|
||||||
|
0x87, 0x28, 0x37, 0x83, 0x86, 0xd8, 0x5a, 0xc8,
|
||||||
|
0x60, 0x87, 0xda, 0x33, 0x87, 0xaf, 0x34, 0x8b,
|
||||||
|
0xf5, 0x61, 0x63, 0x7a, 0x5c, 0x60, 0x26, 0xb9,
|
||||||
|
0xdb, 0xa1, 0xb7, 0xe3, 0x60, 0x38, 0x94, 0x5c,
|
||||||
|
0x83, 0x23, 0xd6, 0x8d, 0xc2, 0x14, 0x4a, 0x0f,
|
||||||
|
0x0e, 0x4f, 0xf9, 0x4e, 0x7b, 0x15, 0xcd, 0x18,
|
||||||
|
0x04, 0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16,
|
||||||
|
0x03, 0x00, 0x00, 0x3c, 0xbd, 0xbc, 0xec, 0xdc,
|
||||||
|
0x79, 0xb1, 0xae, 0x16, 0xc9, 0x26, 0x9a, 0xc0,
|
||||||
|
0xc0, 0x2c, 0x33, 0x36, 0x13, 0x91, 0x58, 0x5d,
|
||||||
|
0x7d, 0xee, 0x4e, 0xd8, 0x7e, 0xac, 0x88, 0x87,
|
||||||
|
0x0a, 0x75, 0x66, 0xb1, 0x44, 0x79, 0x2f, 0x42,
|
||||||
|
0xe8, 0x92, 0x74, 0x4c, 0xab, 0x36, 0xc8, 0x17,
|
||||||
|
0x5f, 0x02, 0x8a, 0x20, 0x53, 0xe9, 0x1d, 0xb4,
|
||||||
|
0xfe, 0x5c, 0x2b, 0xd9, 0x0a, 0xfb, 0xc6, 0x63,
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
0x14, 0x03, 0x00, 0x00, 0x01, 0x01, 0x16, 0x03,
|
||||||
|
0x00, 0x00, 0x3c, 0xaa, 0xa1, 0x98, 0xc4, 0x6b,
|
||||||
|
0x5a, 0x16, 0x3f, 0x5f, 0xa4, 0x96, 0x3e, 0x78,
|
||||||
|
0xe4, 0x6f, 0x49, 0x05, 0x47, 0xc4, 0x05, 0x60,
|
||||||
|
0xeb, 0x0b, 0x45, 0xe3, 0xbc, 0x50, 0x11, 0x24,
|
||||||
|
0x5f, 0x01, 0xd7, 0xb8, 0x8f, 0x60, 0x63, 0x66,
|
||||||
|
0xbd, 0x3e, 0xd9, 0xa8, 0x80, 0x43, 0x9f, 0x0b,
|
||||||
|
0x51, 0x61, 0xed, 0x13, 0xc6, 0x21, 0xd0, 0xfe,
|
||||||
|
0xbc, 0x17, 0x3c, 0x36, 0xb0, 0x82, 0x7f, 0x17,
|
||||||
|
0x03, 0x00, 0x00, 0x21, 0xee, 0x44, 0xf3, 0xa6,
|
||||||
|
0x88, 0x9d, 0x78, 0x44, 0xde, 0xdf, 0xeb, 0xc5,
|
||||||
|
0xad, 0xc4, 0xcc, 0x56, 0x5c, 0x54, 0x96, 0x52,
|
||||||
|
0x3f, 0xd9, 0x40, 0x6e, 0x79, 0xd8, 0x58, 0x78,
|
||||||
|
0x4f, 0x5a, 0xe9, 0x06, 0xef, 0x15, 0x03, 0x00,
|
||||||
|
0x00, 0x16, 0xd3, 0xc2, 0x52, 0x99, 0x2a, 0x84,
|
||||||
|
0xc4, 0x52, 0x5f, 0x3b, 0x19, 0xe7, 0xfc, 0x65,
|
||||||
|
0xaf, 0xd3, 0xb7, 0xa3, 0xcc, 0x4a, 0x1d, 0x2e,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
@ -24,7 +24,7 @@ func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, clientHello
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
|
func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, os.Error) {
|
||||||
preMasterSecret := make([]byte, 48)
|
preMasterSecret := make([]byte, 48)
|
||||||
_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
|
_, err := io.ReadFull(config.rand(), preMasterSecret[2:])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -34,11 +34,15 @@ func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKe
|
|||||||
if len(ckx.ciphertext) < 2 {
|
if len(ckx.ciphertext) < 2 {
|
||||||
return nil, os.NewError("bad ClientKeyExchange")
|
return nil, os.NewError("bad ClientKeyExchange")
|
||||||
}
|
}
|
||||||
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
|
|
||||||
if ciphertextLen != len(ckx.ciphertext)-2 {
|
ciphertext := ckx.ciphertext
|
||||||
return nil, os.NewError("bad ClientKeyExchange")
|
if version != versionSSL30 {
|
||||||
|
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
|
||||||
|
if ciphertextLen != len(ckx.ciphertext)-2 {
|
||||||
|
return nil, os.NewError("bad ClientKeyExchange")
|
||||||
|
}
|
||||||
|
ciphertext = ckx.ciphertext[2:]
|
||||||
}
|
}
|
||||||
ciphertext := ckx.ciphertext[2:]
|
|
||||||
|
|
||||||
err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
|
err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -159,7 +163,7 @@ Curve:
|
|||||||
return skx, nil
|
return skx, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) {
|
func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg, version uint16) ([]byte, os.Error) {
|
||||||
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
|
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
|
||||||
return nil, os.NewError("bad ClientKeyExchange")
|
return nil, os.NewError("bad ClientKeyExchange")
|
||||||
}
|
}
|
||||||
|
107
prf.go
107
prf.go
@ -63,6 +63,39 @@ func pRF10(result, secret, label, seed []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pRF30 implements the SSL 3.0 pseudo-random function, as defined in
|
||||||
|
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 6.
|
||||||
|
func pRF30(result, secret, label, seed []byte) {
|
||||||
|
hashSHA1 := sha1.New()
|
||||||
|
hashMD5 := md5.New()
|
||||||
|
|
||||||
|
done := 0
|
||||||
|
i := 0
|
||||||
|
// RFC5246 section 6.3 says that the largest PRF output needed is 128
|
||||||
|
// bytes. Since no more ciphersuites will be added to SSLv3, this will
|
||||||
|
// remain true. Each iteration gives us 16 bytes so 10 iterations will
|
||||||
|
// be sufficient.
|
||||||
|
var b [11]byte
|
||||||
|
for done < len(result) {
|
||||||
|
for j := 0; j <= i; j++ {
|
||||||
|
b[j] = 'A' + byte(i)
|
||||||
|
}
|
||||||
|
|
||||||
|
hashSHA1.Reset()
|
||||||
|
hashSHA1.Write(b[:i+1])
|
||||||
|
hashSHA1.Write(secret)
|
||||||
|
hashSHA1.Write(seed)
|
||||||
|
digest := hashSHA1.Sum()
|
||||||
|
|
||||||
|
hashMD5.Reset()
|
||||||
|
hashMD5.Write(secret)
|
||||||
|
hashMD5.Write(digest)
|
||||||
|
|
||||||
|
done += copy(result[done:], hashMD5.Sum())
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
|
tlsRandomLength = 32 // Length of a random nonce in TLS 1.1.
|
||||||
masterSecretLength = 48 // Length of a master secret in TLS 1.1.
|
masterSecretLength = 48 // Length of a master secret in TLS 1.1.
|
||||||
@ -77,19 +110,24 @@ var serverFinishedLabel = []byte("server finished")
|
|||||||
// keysFromPreMasterSecret generates the connection keys from the pre master
|
// keysFromPreMasterSecret generates the connection keys from the pre master
|
||||||
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
|
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
|
||||||
// RFC 2246, section 6.3.
|
// RFC 2246, section 6.3.
|
||||||
func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
|
func keysFromPreMasterSecret(version uint16, preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
|
||||||
|
prf := pRF10
|
||||||
|
if version == versionSSL30 {
|
||||||
|
prf = pRF30
|
||||||
|
}
|
||||||
|
|
||||||
var seed [tlsRandomLength * 2]byte
|
var seed [tlsRandomLength * 2]byte
|
||||||
copy(seed[0:len(clientRandom)], clientRandom)
|
copy(seed[0:len(clientRandom)], clientRandom)
|
||||||
copy(seed[len(clientRandom):], serverRandom)
|
copy(seed[len(clientRandom):], serverRandom)
|
||||||
masterSecret = make([]byte, masterSecretLength)
|
masterSecret = make([]byte, masterSecretLength)
|
||||||
pRF10(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
|
prf(masterSecret, preMasterSecret, masterSecretLabel, seed[0:])
|
||||||
|
|
||||||
copy(seed[0:len(clientRandom)], serverRandom)
|
copy(seed[0:len(clientRandom)], serverRandom)
|
||||||
copy(seed[len(serverRandom):], clientRandom)
|
copy(seed[len(serverRandom):], clientRandom)
|
||||||
|
|
||||||
n := 2*macLen + 2*keyLen + 2*ivLen
|
n := 2*macLen + 2*keyLen + 2*ivLen
|
||||||
keyMaterial := make([]byte, n)
|
keyMaterial := make([]byte, n)
|
||||||
pRF10(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
|
prf(keyMaterial, masterSecret, keyExpansionLabel, seed[0:])
|
||||||
clientMAC = keyMaterial[:macLen]
|
clientMAC = keyMaterial[:macLen]
|
||||||
keyMaterial = keyMaterial[macLen:]
|
keyMaterial = keyMaterial[macLen:]
|
||||||
serverMAC = keyMaterial[:macLen]
|
serverMAC = keyMaterial[:macLen]
|
||||||
@ -104,6 +142,10 @@ func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byt
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newFinishedHash(version uint16) finishedHash {
|
||||||
|
return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New(), version}
|
||||||
|
}
|
||||||
|
|
||||||
// A finishedHash calculates the hash of a set of handshake messages suitable
|
// A finishedHash calculates the hash of a set of handshake messages suitable
|
||||||
// for including in a Finished message.
|
// for including in a Finished message.
|
||||||
type finishedHash struct {
|
type finishedHash struct {
|
||||||
@ -111,10 +153,7 @@ type finishedHash struct {
|
|||||||
clientSHA1 hash.Hash
|
clientSHA1 hash.Hash
|
||||||
serverMD5 hash.Hash
|
serverMD5 hash.Hash
|
||||||
serverSHA1 hash.Hash
|
serverSHA1 hash.Hash
|
||||||
}
|
version uint16
|
||||||
|
|
||||||
func newFinishedHash() finishedHash {
|
|
||||||
return finishedHash{md5.New(), sha1.New(), md5.New(), sha1.New()}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
|
func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
|
||||||
@ -125,9 +164,10 @@ func (h finishedHash) Write(msg []byte) (n int, err os.Error) {
|
|||||||
return len(msg), nil
|
return len(msg), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// finishedSum calculates the contents of the verify_data member of a Finished
|
// finishedSum10 calculates the contents of the verify_data member of a TLSv1
|
||||||
// message given the MD5 and SHA1 hashes of a set of handshake messages.
|
// Finished message given the MD5 and SHA1 hashes of a set of handshake
|
||||||
func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
|
// messages.
|
||||||
|
func finishedSum10(md5, sha1, label, masterSecret []byte) []byte {
|
||||||
seed := make([]byte, len(md5)+len(sha1))
|
seed := make([]byte, len(md5)+len(sha1))
|
||||||
copy(seed, md5)
|
copy(seed, md5)
|
||||||
copy(seed[len(md5):], sha1)
|
copy(seed[len(md5):], sha1)
|
||||||
@ -136,18 +176,61 @@ func finishedSum(md5, sha1, label, masterSecret []byte) []byte {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// finishedSum30 calculates the contents of the verify_data member of a SSLv3
|
||||||
|
// Finished message given the MD5 and SHA1 hashes of a set of handshake
|
||||||
|
// messages.
|
||||||
|
func finishedSum30(md5, sha1 hash.Hash, masterSecret []byte, magic [4]byte) []byte {
|
||||||
|
md5.Write(magic[:])
|
||||||
|
md5.Write(masterSecret)
|
||||||
|
md5.Write(ssl30Pad1[:])
|
||||||
|
md5Digest := md5.Sum()
|
||||||
|
|
||||||
|
md5.Reset()
|
||||||
|
md5.Write(masterSecret)
|
||||||
|
md5.Write(ssl30Pad2[:])
|
||||||
|
md5.Write(md5Digest)
|
||||||
|
md5Digest = md5.Sum()
|
||||||
|
|
||||||
|
sha1.Write(magic[:])
|
||||||
|
sha1.Write(masterSecret)
|
||||||
|
sha1.Write(ssl30Pad1[:40])
|
||||||
|
sha1Digest := sha1.Sum()
|
||||||
|
|
||||||
|
sha1.Reset()
|
||||||
|
sha1.Write(masterSecret)
|
||||||
|
sha1.Write(ssl30Pad2[:40])
|
||||||
|
sha1.Write(sha1Digest)
|
||||||
|
sha1Digest = sha1.Sum()
|
||||||
|
|
||||||
|
ret := make([]byte, len(md5Digest)+len(sha1Digest))
|
||||||
|
copy(ret, md5Digest)
|
||||||
|
copy(ret[len(md5Digest):], sha1Digest)
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
var ssl3ClientFinishedMagic = [4]byte{0x43, 0x4c, 0x4e, 0x54}
|
||||||
|
var ssl3ServerFinishedMagic = [4]byte{0x53, 0x52, 0x56, 0x52}
|
||||||
|
|
||||||
// clientSum returns the contents of the verify_data member of a client's
|
// clientSum returns the contents of the verify_data member of a client's
|
||||||
// Finished message.
|
// Finished message.
|
||||||
func (h finishedHash) clientSum(masterSecret []byte) []byte {
|
func (h finishedHash) clientSum(masterSecret []byte) []byte {
|
||||||
|
if h.version == versionSSL30 {
|
||||||
|
return finishedSum30(h.clientMD5, h.clientSHA1, masterSecret, ssl3ClientFinishedMagic)
|
||||||
|
}
|
||||||
|
|
||||||
md5 := h.clientMD5.Sum()
|
md5 := h.clientMD5.Sum()
|
||||||
sha1 := h.clientSHA1.Sum()
|
sha1 := h.clientSHA1.Sum()
|
||||||
return finishedSum(md5, sha1, clientFinishedLabel, masterSecret)
|
return finishedSum10(md5, sha1, clientFinishedLabel, masterSecret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// serverSum returns the contents of the verify_data member of a server's
|
// serverSum returns the contents of the verify_data member of a server's
|
||||||
// Finished message.
|
// Finished message.
|
||||||
func (h finishedHash) serverSum(masterSecret []byte) []byte {
|
func (h finishedHash) serverSum(masterSecret []byte) []byte {
|
||||||
|
if h.version == versionSSL30 {
|
||||||
|
return finishedSum30(h.serverMD5, h.serverSHA1, masterSecret, ssl3ServerFinishedMagic)
|
||||||
|
}
|
||||||
|
|
||||||
md5 := h.serverMD5.Sum()
|
md5 := h.serverMD5.Sum()
|
||||||
sha1 := h.serverSHA1.Sum()
|
sha1 := h.serverSHA1.Sum()
|
||||||
return finishedSum(md5, sha1, serverFinishedLabel, masterSecret)
|
return finishedSum10(md5, sha1, serverFinishedLabel, masterSecret)
|
||||||
}
|
}
|
||||||
|
21
prf_test.go
21
prf_test.go
@ -34,6 +34,7 @@ func TestSplitPreMasterSecret(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type testKeysFromTest struct {
|
type testKeysFromTest struct {
|
||||||
|
version uint16
|
||||||
preMasterSecret string
|
preMasterSecret string
|
||||||
clientRandom, serverRandom string
|
clientRandom, serverRandom string
|
||||||
masterSecret string
|
masterSecret string
|
||||||
@ -47,7 +48,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
|
|||||||
in, _ := hex.DecodeString(test.preMasterSecret)
|
in, _ := hex.DecodeString(test.preMasterSecret)
|
||||||
clientRandom, _ := hex.DecodeString(test.clientRandom)
|
clientRandom, _ := hex.DecodeString(test.clientRandom)
|
||||||
serverRandom, _ := hex.DecodeString(test.serverRandom)
|
serverRandom, _ := hex.DecodeString(test.serverRandom)
|
||||||
master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret10(in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
|
master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret(test.version, in, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
|
||||||
masterString := hex.EncodeToString(master)
|
masterString := hex.EncodeToString(master)
|
||||||
clientMACString := hex.EncodeToString(clientMAC)
|
clientMACString := hex.EncodeToString(clientMAC)
|
||||||
serverMACString := hex.EncodeToString(serverMAC)
|
serverMACString := hex.EncodeToString(serverMAC)
|
||||||
@ -58,7 +59,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
|
|||||||
serverMACString != test.serverMAC ||
|
serverMACString != test.serverMAC ||
|
||||||
clientKeyString != test.clientKey ||
|
clientKeyString != test.clientKey ||
|
||||||
serverKeyString != test.serverKey {
|
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)
|
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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -66,6 +67,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) {
|
|||||||
// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
|
// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
|
||||||
var testKeysFromTests = []testKeysFromTest{
|
var testKeysFromTests = []testKeysFromTest{
|
||||||
{
|
{
|
||||||
|
versionTLS10,
|
||||||
"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
|
"0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
|
||||||
"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
|
"4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
|
||||||
"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
|
"4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
|
||||||
@ -78,6 +80,7 @@ var testKeysFromTests = []testKeysFromTest{
|
|||||||
16,
|
16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
versionTLS10,
|
||||||
"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
|
"03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
|
||||||
"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
|
"4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
|
||||||
"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
|
"4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
|
||||||
@ -90,6 +93,7 @@ var testKeysFromTests = []testKeysFromTest{
|
|||||||
16,
|
16,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
versionTLS10,
|
||||||
"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
|
"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
|
||||||
"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
|
"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
|
||||||
"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
|
"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
|
||||||
@ -101,4 +105,17 @@ var testKeysFromTests = []testKeysFromTest{
|
|||||||
20,
|
20,
|
||||||
16,
|
16,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
versionSSL30,
|
||||||
|
"832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
|
||||||
|
"4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
|
||||||
|
"4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
|
||||||
|
"a614863e56299dcffeea2938f22c2ba023768dbe4b3f6877bc9c346c6ae529b51d9cb87ff9695ea4d01f2205584405b2",
|
||||||
|
"2c450d5b6f6e2013ac6bea6a0b32200d4e1ffb94",
|
||||||
|
"7a7a7438769536f2fb1ae49a61f0703b79b2dc53",
|
||||||
|
"f8f6b26c10f12855c9aafb1e0e839ccf",
|
||||||
|
"2b9d4b4a60cb7f396780ebff50650419",
|
||||||
|
20,
|
||||||
|
16,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user