diff options
Diffstat (limited to 'src/pkg/crypto/tls')
-rw-r--r-- | src/pkg/crypto/tls/Makefile | 4 | ||||
-rw-r--r-- | src/pkg/crypto/tls/ca_set.go | 50 | ||||
-rw-r--r-- | src/pkg/crypto/tls/cipher_suites.go | 102 | ||||
-rw-r--r-- | src/pkg/crypto/tls/common.go | 176 | ||||
-rw-r--r-- | src/pkg/crypto/tls/conn.go | 232 | ||||
-rw-r--r-- | src/pkg/crypto/tls/conn_test.go | 52 | ||||
-rw-r--r-- | src/pkg/crypto/tls/generate_cert.go | 70 | ||||
-rw-r--r-- | src/pkg/crypto/tls/handshake_client.go | 215 | ||||
-rw-r--r-- | src/pkg/crypto/tls/handshake_client_test.go | 211 | ||||
-rw-r--r-- | src/pkg/crypto/tls/handshake_messages.go | 367 | ||||
-rw-r--r-- | src/pkg/crypto/tls/handshake_messages_test.go | 37 | ||||
-rw-r--r-- | src/pkg/crypto/tls/handshake_server.go | 189 | ||||
-rw-r--r-- | src/pkg/crypto/tls/handshake_server_test.go | 443 | ||||
-rw-r--r-- | src/pkg/crypto/tls/key_agreement.go | 246 | ||||
-rw-r--r-- | src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py | 55 | ||||
-rw-r--r-- | src/pkg/crypto/tls/prf.go | 39 | ||||
-rw-r--r-- | src/pkg/crypto/tls/prf_test.go | 18 | ||||
-rw-r--r-- | src/pkg/crypto/tls/tls.go | 108 |
18 files changed, 2276 insertions, 338 deletions
diff --git a/src/pkg/crypto/tls/Makefile b/src/pkg/crypto/tls/Makefile index 5e25bd43a..f8ec1511a 100644 --- a/src/pkg/crypto/tls/Makefile +++ b/src/pkg/crypto/tls/Makefile @@ -2,17 +2,19 @@ # Use of this source code is governed by a BSD-style # license that can be found in the LICENSE file. -include ../../../Make.$(GOARCH) +include ../../../Make.inc TARG=crypto/tls GOFILES=\ alert.go\ ca_set.go\ + cipher_suites.go\ common.go\ conn.go\ handshake_client.go\ handshake_messages.go\ handshake_server.go\ + key_agreement.go\ prf.go\ tls.go\ diff --git a/src/pkg/crypto/tls/ca_set.go b/src/pkg/crypto/tls/ca_set.go index 7f7566e46..ae00ac558 100644 --- a/src/pkg/crypto/tls/ca_set.go +++ b/src/pkg/crypto/tls/ca_set.go @@ -7,32 +7,57 @@ package tls import ( "crypto/x509" "encoding/pem" + "strings" ) // A CASet is a set of certificates. type CASet struct { - bySubjectKeyId map[string]*x509.Certificate - byName map[string]*x509.Certificate + bySubjectKeyId map[string][]*x509.Certificate + byName map[string][]*x509.Certificate } +// NewCASet returns a new, empty CASet. func NewCASet() *CASet { return &CASet{ - make(map[string]*x509.Certificate), - make(map[string]*x509.Certificate), + make(map[string][]*x509.Certificate), + make(map[string][]*x509.Certificate), } } func nameToKey(name *x509.Name) string { - return name.Country + "/" + name.Organization + "/" + name.OrganizationalUnit + "/" + name.CommonName + return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName } -// FindParent attempts to find the certificate in s which signs the given -// certificate. If no such certificate can be found, it returns nil. -func (s *CASet) FindParent(cert *x509.Certificate) (parent *x509.Certificate) { +// FindVerifiedParent attempts to find the certificate in s which has signed +// the given certificate. If no such certificate can be found or the signature +// doesn't match, it returns nil. +func (s *CASet) FindVerifiedParent(cert *x509.Certificate) (parent *x509.Certificate) { + var candidates []*x509.Certificate + if len(cert.AuthorityKeyId) > 0 { - return s.bySubjectKeyId[string(cert.AuthorityKeyId)] + candidates = s.bySubjectKeyId[string(cert.AuthorityKeyId)] + } + if len(candidates) == 0 { + candidates = s.byName[nameToKey(&cert.Issuer)] + } + + for _, c := range candidates { + if cert.CheckSignatureFrom(c) == nil { + return c + } } - return s.byName[nameToKey(&cert.Issuer)] + + return nil +} + +// AddCert adds a certificate to the set +func (s *CASet) AddCert(cert *x509.Certificate) { + if len(cert.SubjectKeyId) > 0 { + keyId := string(cert.SubjectKeyId) + s.bySubjectKeyId[keyId] = append(s.bySubjectKeyId[keyId], cert) + } + name := nameToKey(&cert.Subject) + s.byName[name] = append(s.byName[name], cert) } // SetFromPEM attempts to parse a series of PEM encoded root certificates. It @@ -56,10 +81,7 @@ func (s *CASet) SetFromPEM(pemCerts []byte) (ok bool) { continue } - if len(cert.SubjectKeyId) > 0 { - s.bySubjectKeyId[string(cert.SubjectKeyId)] = cert - } - s.byName[nameToKey(&cert.Subject)] = cert + s.AddCert(cert) ok = true } diff --git a/src/pkg/crypto/tls/cipher_suites.go b/src/pkg/crypto/tls/cipher_suites.go new file mode 100644 index 000000000..bc7b0d32f --- /dev/null +++ b/src/pkg/crypto/tls/cipher_suites.go @@ -0,0 +1,102 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "crypto/aes" + "crypto/cipher" + "crypto/hmac" + "crypto/rc4" + "crypto/x509" + "hash" + "os" +) + +// a keyAgreement implements the client and server side of a TLS key agreement +// protocol by generating and processing key exchange messages. +type keyAgreement interface { + // On the server side, the first two methods are called in order. + + // In the case that the key agreement protocol doesn't use a + // ServerKeyExchange message, generateServerKeyExchange can return nil, + // nil. + generateServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) + processClientKeyExchange(*Config, *clientKeyExchangeMsg) ([]byte, os.Error) + + // On the client side, the next two methods are called in order. + + // This method may not be called if the server doesn't send a + // ServerKeyExchange message. + processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) os.Error + generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) +} + +// A cipherSuite is a specific combination of key agreement, cipher and MAC +// function. All cipher suites currently assume RSA key agreement. +type cipherSuite struct { + // the lengths, in bytes, of the key material needed for each component. + keyLen int + macLen int + ivLen int + ka func() keyAgreement + // If elliptic is set, a server will only consider this ciphersuite if + // the ClientHello indicated that the client supports an elliptic curve + // and point format that we can handle. + elliptic bool + cipher func(key, iv []byte, isRead bool) interface{} + mac func(macKey []byte) hash.Hash +} + +var cipherSuites = map[uint16]*cipherSuite{ + TLS_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, rsaKA, false, cipherRC4, hmacSHA1}, + TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, rsaKA, false, cipherAES, hmacSHA1}, + TLS_ECDHE_RSA_WITH_RC4_128_SHA: &cipherSuite{16, 20, 0, ecdheRSAKA, true, cipherRC4, hmacSHA1}, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, ecdheRSAKA, true, cipherAES, hmacSHA1}, +} + +func cipherRC4(key, iv []byte, isRead bool) interface{} { + cipher, _ := rc4.NewCipher(key) + return cipher +} + +func cipherAES(key, iv []byte, isRead bool) interface{} { + block, _ := aes.NewCipher(key) + if isRead { + return cipher.NewCBCDecrypter(block, iv) + } + return cipher.NewCBCEncrypter(block, iv) +} + +func hmacSHA1(key []byte) hash.Hash { + return hmac.NewSHA1(key) +} + +func rsaKA() keyAgreement { + return rsaKeyAgreement{} +} + +func ecdheRSAKA() keyAgreement { + return new(ecdheRSAKeyAgreement) +} + +// mutualCipherSuite returns a cipherSuite and its id given a list of supported +// ciphersuites and the id requested by the peer. +func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint16) { + for _, id := range have { + if id == want { + return cipherSuites[id], id + } + } + return +} + +// A list of the possible cipher suite ids. Taken from +// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml +const ( + TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005 + TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f + TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011 + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013 +) diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go index 56c22cf7d..7135f3d0f 100644 --- a/src/pkg/crypto/tls/common.go +++ b/src/pkg/crypto/tls/common.go @@ -9,7 +9,7 @@ import ( "crypto/rsa" "io" "io/ioutil" - "once" + "sync" "time" ) @@ -20,7 +20,7 @@ const ( maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB) minVersion = 0x0301 // minimum supported version - TLS 1.0 - maxVersion = 0x0302 // maximum supported version - TLS 1.1 + maxVersion = 0x0301 // maximum supported version - TLS 1.0 ) // TLS record types. @@ -35,35 +35,65 @@ const ( // TLS handshake message types. const ( - typeClientHello uint8 = 1 - typeServerHello uint8 = 2 - typeCertificate uint8 = 11 - typeServerHelloDone uint8 = 14 - typeClientKeyExchange uint8 = 16 - typeFinished uint8 = 20 - typeNextProtocol uint8 = 67 // Not IANA assigned + typeClientHello uint8 = 1 + typeServerHello uint8 = 2 + typeCertificate uint8 = 11 + typeServerKeyExchange uint8 = 12 + typeCertificateRequest uint8 = 13 + typeServerHelloDone uint8 = 14 + typeCertificateVerify uint8 = 15 + typeClientKeyExchange uint8 = 16 + typeFinished uint8 = 20 + typeCertificateStatus uint8 = 22 + typeNextProtocol uint8 = 67 // Not IANA assigned ) -// TLS cipher suites. +// TLS compression types. +const ( + compressionNone uint8 = 0 +) + +// TLS extension numbers var ( - TLS_RSA_WITH_RC4_128_SHA uint16 = 5 + extensionServerName uint16 = 0 + extensionStatusRequest uint16 = 5 + extensionSupportedCurves uint16 = 10 + extensionSupportedPoints uint16 = 11 + extensionNextProtoNeg uint16 = 13172 // not IANA assigned ) -// TLS compression types. +// TLS Elliptic Curves +// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8 var ( - compressionNone uint8 = 0 + curveP256 uint16 = 23 + curveP384 uint16 = 24 + curveP521 uint16 = 25 ) -// TLS extension numbers +// TLS Elliptic Curve Point Formats +// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9 var ( - extensionServerName uint16 = 0 - extensionNextProtoNeg uint16 = 13172 // not IANA assigned + pointFormatUncompressed uint8 = 0 +) + +// TLS CertificateStatusType (RFC 3546) +const ( + statusTypeOCSP uint8 = 1 ) +// Certificate types (for certificateRequestMsg) +const ( + certTypeRSASign = 1 // A certificate containing an RSA key + certTypeDSSSign = 2 // A certificate containing a DSA key + certTypeRSAFixedDH = 3 // A certificate containing a static DH key + certTypeDSSFixedDH = 4 // A certficiate containing a static DH key + // Rest of these are reserved by the TLS spec +) + +// ConnectionState records basic TLS details about the connection. type ConnectionState struct { HandshakeComplete bool - CipherSuite string - Error alert + CipherSuite uint16 NegotiatedProtocol string } @@ -71,16 +101,76 @@ type ConnectionState struct { // 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. + // If Rand is nil, TLS uses the cryptographic random reader in package + // crypto/rand. Rand io.Reader + // Time returns the current time as the number of seconds since the epoch. - Time func() int64 + // If Time is nil, TLS uses the system time.Seconds. + Time func() int64 + + // Certificates contains one or more certificate chains + // to present to the other side of the connection. + // Server configurations must include at least one certificate. Certificates []Certificate - RootCAs *CASet + + // RootCAs defines the set of root certificate authorities + // that clients use when verifying server certificates. + // If RootCAs is nil, TLS uses the host's root CA set. + RootCAs *CASet + // NextProtos is a list of supported, application level protocols. // Currently only server-side handling is supported. NextProtos []string + + // ServerName is included in the client's handshake to support virtual + // hosting. + ServerName string + + // AuthenticateClient controls whether a server will request a certificate + // from the client. It does not require that the client send a + // certificate nor does it require that the certificate sent be + // anything more than self-signed. + AuthenticateClient bool + + // CipherSuites is a list of supported cipher suites. If CipherSuites + // is nil, TLS uses a list of suites supported by the implementation. + CipherSuites []uint16 +} + +func (c *Config) rand() io.Reader { + r := c.Rand + if r == nil { + return rand.Reader + } + return r +} + +func (c *Config) time() int64 { + t := c.Time + if t == nil { + t = time.Seconds + } + return t() +} + +func (c *Config) rootCAs() *CASet { + s := c.RootCAs + if s == nil { + s = defaultRoots() + } + return s +} + +func (c *Config) cipherSuites() []uint16 { + s := c.CipherSuites + if s == nil { + s = defaultCipherSuites() + } + return s } +// A Certificate is a chain of one or more certificates, leaf first. type Certificate struct { Certificate [][]byte PrivateKey *rsa.PrivateKey @@ -98,11 +188,6 @@ type handshakeMessage interface { unmarshal([]byte) bool } -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(vers uint16) (uint16, bool) { @@ -115,12 +200,10 @@ func mutualVersion(vers uint16) (uint16, bool) { return vers, true } -// The defaultConfig is used in place of a nil *Config in the TLS server and client. -var varDefaultConfig *Config +var emptyConfig Config func defaultConfig() *Config { - once.Do(initDefaultConfig) - return varDefaultConfig + return &emptyConfig } // Possible certificate files; stop after finding one. @@ -132,7 +215,26 @@ var certFiles = []string{ "/usr/share/curl/curl-ca-bundle.crt", // OS X } -func initDefaultConfig() { +var once sync.Once + +func defaultRoots() *CASet { + once.Do(initDefaults) + return varDefaultRoots +} + +func defaultCipherSuites() []uint16 { + once.Do(initDefaults) + return varDefaultCipherSuites +} + +func initDefaults() { + initDefaultRoots() + initDefaultCipherSuites() +} + +var varDefaultRoots *CASet + +func initDefaultRoots() { roots := NewCASet() for _, file := range certFiles { data, err := ioutil.ReadFile(file) @@ -141,10 +243,16 @@ func initDefaultConfig() { break } } + varDefaultRoots = roots +} + +var varDefaultCipherSuites []uint16 - varDefaultConfig = &Config{ - Rand: rand.Reader, - Time: time.Seconds, - RootCAs: roots, +func initDefaultCipherSuites() { + varDefaultCipherSuites = make([]uint16, len(cipherSuites)) + i := 0 + for id, _ := range cipherSuites { + varDefaultCipherSuites[i] = id + i++ } } diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go index 0798e26f6..d203e8d51 100644 --- a/src/pkg/crypto/tls/conn.go +++ b/src/pkg/crypto/tls/conn.go @@ -1,10 +1,16 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + // TLS low level connection and record layer package tls import ( "bytes" + "crypto/cipher" "crypto/subtle" + "crypto/x509" "hash" "io" "net" @@ -26,6 +32,8 @@ type Conn struct { config *Config // configuration passed to constructor handshakeComplete bool cipherSuite uint16 + ocspResponse []byte // stapled OCSP response + peerCertificates []*x509.Certificate clientProtocol string @@ -96,31 +104,31 @@ func (c *Conn) SetWriteTimeout(nsec int64) os.Error { // connection, either sending or receiving. type halfConn struct { sync.Mutex - crypt encryptor // encryption state - mac hash.Hash // MAC algorithm - seq [8]byte // 64-bit sequence number - bfree *block // list of free blocks + cipher interface{} // cipher algorithm + mac hash.Hash // MAC algorithm + seq [8]byte // 64-bit sequence number + bfree *block // list of free blocks - nextCrypt encryptor // next encryption state - nextMac hash.Hash // next MAC algorithm + nextCipher interface{} // next encryption state + nextMac hash.Hash // next MAC algorithm } // prepareCipherSpec sets the encryption and MAC states // that a subsequent changeCipherSpec will use. -func (hc *halfConn) prepareCipherSpec(crypt encryptor, mac hash.Hash) { - hc.nextCrypt = crypt +func (hc *halfConn) prepareCipherSpec(cipher interface{}, mac hash.Hash) { + hc.nextCipher = cipher hc.nextMac = mac } // changeCipherSpec changes the encryption and MAC states // to the ones previously passed to prepareCipherSpec. func (hc *halfConn) changeCipherSpec() os.Error { - if hc.nextCrypt == nil { + if hc.nextCipher == nil { return alertInternalError } - hc.crypt = hc.nextCrypt + hc.cipher = hc.nextCipher hc.mac = hc.nextMac - hc.nextCrypt = nil + hc.nextCipher = nil hc.nextMac = nil return nil } @@ -147,27 +155,102 @@ func (hc *halfConn) resetSeq() { } } +// removePadding returns an unpadded slice, in constant time, which is a prefix +// of the input. It also returns a byte which is equal to 255 if the padding +// was valid and 0 otherwise. See RFC 2246, section 6.2.3.2 +func removePadding(payload []byte) ([]byte, byte) { + if len(payload) < 1 { + return payload, 0 + } + + paddingLen := payload[len(payload)-1] + t := uint(len(payload)-1) - uint(paddingLen) + // if len(payload) >= (paddingLen - 1) then the MSB of t is zero + good := byte(int32(^t) >> 31) + + toCheck := 255 // the maximum possible padding length + // The length of the padded data is public, so we can use an if here + if toCheck+1 > len(payload) { + toCheck = len(payload) - 1 + } + + for i := 0; i < toCheck; i++ { + t := uint(paddingLen) - uint(i) + // if i <= paddingLen then the MSB of t is zero + mask := byte(int32(^t) >> 31) + b := payload[len(payload)-1-i] + good &^= mask&paddingLen ^ mask&b + } + + // We AND together the bits of good and replicate the result across + // all the bits. + good &= good << 4 + good &= good << 2 + good &= good << 1 + good = uint8(int8(good) >> 7) + + toRemove := good&paddingLen + 1 + return payload[:len(payload)-int(toRemove)], good +} + +func roundUp(a, b int) int { + return a + (b-a%b)%b +} + // decrypt checks and strips the mac and decrypts the data in b. func (hc *halfConn) decrypt(b *block) (bool, alert) { // pull out payload payload := b.data[recordHeaderLen:] + macSize := 0 + if hc.mac != nil { + macSize = hc.mac.Size() + } + + paddingGood := byte(255) + // decrypt - if hc.crypt != nil { - hc.crypt.XORKeyStream(payload) + if hc.cipher != nil { + switch c := hc.cipher.(type) { + case cipher.Stream: + c.XORKeyStream(payload, payload) + case cipher.BlockMode: + blockSize := c.BlockSize() + + if len(payload)%blockSize != 0 || len(payload) < roundUp(macSize+1, blockSize) { + return false, alertBadRecordMAC + } + + c.CryptBlocks(payload, payload) + payload, paddingGood = removePadding(payload) + b.resize(recordHeaderLen + len(payload)) + + // note that we still have a timing side-channel in the + // MAC check, below. An attacker can align the record + // so that a correct padding will cause one less hash + // block to be calculated. Then they can iteratively + // decrypt a record by breaking each byte. See + // "Password Interception in a SSL/TLS Channel", Brice + // Canvel et al. + // + // However, our behaviour matches OpenSSL, so we leak + // only as much as they do. + default: + panic("unknown cipher type") + } } // check, strip mac if hc.mac != nil { - if len(payload) < hc.mac.Size() { + if len(payload) < macSize { return false, alertBadRecordMAC } // strip mac off payload, b.data - n := len(payload) - hc.mac.Size() + n := len(payload) - macSize b.data[3] = byte(n >> 8) b.data[4] = byte(n) - b.data = b.data[0 : recordHeaderLen+n] + b.resize(recordHeaderLen + n) remoteMAC := payload[n:] hc.mac.Reset() @@ -175,7 +258,7 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) { hc.incSeq() hc.mac.Write(b.data) - if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 { + if subtle.ConstantTimeCompare(hc.mac.Sum(), remoteMAC) != 1 || paddingGood != 255 { return false, alertBadRecordMAC } } @@ -183,6 +266,23 @@ func (hc *halfConn) decrypt(b *block) (bool, alert) { return true, 0 } +// padToBlockSize calculates the needed padding block, if any, for a payload. +// On exit, prefix aliases payload and extends to the end of the last full +// block of payload. finalBlock is a fresh slice which contains the contents of +// any suffix of payload as well as the needed padding to make finalBlock a +// full block. +func padToBlockSize(payload []byte, blockSize int) (prefix, finalBlock []byte) { + overrun := len(payload) % blockSize + paddingLen := blockSize - overrun + prefix = payload[:len(payload)-overrun] + finalBlock = make([]byte, blockSize) + copy(finalBlock, payload[len(payload)-overrun:]) + for i := overrun; i < blockSize; i++ { + finalBlock[i] = byte(paddingLen - 1) + } + return +} + // encrypt encrypts and macs the data in b. func (hc *halfConn) encrypt(b *block) (bool, alert) { // mac @@ -195,18 +295,30 @@ func (hc *halfConn) encrypt(b *block) (bool, alert) { n := len(b.data) b.resize(n + len(mac)) copy(b.data[n:], mac) - - // update length to include mac - n = len(b.data) - recordHeaderLen - b.data[3] = byte(n >> 8) - b.data[4] = byte(n) } + payload := b.data[recordHeaderLen:] + // encrypt - if hc.crypt != nil { - hc.crypt.XORKeyStream(b.data[recordHeaderLen:]) + if hc.cipher != nil { + switch c := hc.cipher.(type) { + case cipher.Stream: + c.XORKeyStream(payload, payload) + case cipher.BlockMode: + prefix, finalBlock := padToBlockSize(payload, c.BlockSize()) + b.resize(recordHeaderLen + len(prefix) + len(finalBlock)) + c.CryptBlocks(b.data[recordHeaderLen:], prefix) + c.CryptBlocks(b.data[recordHeaderLen+len(prefix):], finalBlock) + default: + panic("unknown cipher type") + } } + // update length to include MAC and any block padding needed. + n := len(b.data) - recordHeaderLen + b.data[3] = byte(n >> 8) + b.data[4] = byte(n) + return true, 0 } @@ -442,7 +554,11 @@ func (c *Conn) sendAlertLocked(err alert) os.Error { } c.tmp[1] = byte(err) c.writeRecord(recordTypeAlert, c.tmp[0:2]) - return c.setError(&net.OpError{Op: "local error", Error: err}) + // closeNotify is a special case in that it isn't an error: + if err != alertCloseNotify { + return c.setError(&net.OpError{Op: "local error", Error: err}) + } + return nil } // sendAlert sends a TLS alert message. @@ -531,10 +647,18 @@ func (c *Conn) readHandshake() (interface{}, os.Error) { m = new(serverHelloMsg) case typeCertificate: m = new(certificateMsg) + case typeCertificateRequest: + m = new(certificateRequestMsg) + case typeCertificateStatus: + m = new(certificateStatusMsg) + case typeServerKeyExchange: + m = new(serverKeyExchangeMsg) case typeServerHelloDone: m = new(serverHelloDoneMsg) case typeClientKeyExchange: m = new(clientKeyExchangeMsg) + case typeCertificateVerify: + m = new(certificateVerifyMsg) case typeNextProtocol: m = new(nextProtoMsg) case typeFinished: @@ -547,7 +671,7 @@ func (c *Conn) readHandshake() (interface{}, os.Error) { // The handshake message unmarshallers // expect to be able to keep references to data, // so pass in a fresh copy that won't be overwritten. - data = bytes.Add(nil, data) + data = append([]byte(nil), data...) if !m.unmarshal(data) { c.sendAlert(alertUnexpectedMessage) @@ -585,7 +709,10 @@ func (c *Conn) Read(b []byte) (n int, err os.Error) { defer c.in.Unlock() for c.input == nil && c.err == nil { - c.readRecord(recordTypeApplicationData) + if err := c.readRecord(recordTypeApplicationData); err != nil { + // Soft error, like EAGAIN + return 0, err + } } if c.err != nil { return 0, c.err @@ -608,7 +735,7 @@ func (c *Conn) Close() os.Error { // Handshake runs the client or server handshake // protocol if it has not yet been run. -// Most uses of this packge need not call Handshake +// Most uses of this package need not call Handshake // explicitly: the first Read or Write will call it automatically. func (c *Conn) Handshake() os.Error { c.handshakeMutex.Lock() @@ -625,11 +752,50 @@ func (c *Conn) Handshake() os.Error { return c.serverHandshake() } -// If c is a TLS server, ClientConnection returns the protocol -// requested by the client during the TLS handshake. -// Handshake must have been called already. -func (c *Conn) ClientConnection() string { +// ConnectionState returns basic TLS details about the connection. +func (c *Conn) ConnectionState() ConnectionState { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + var state ConnectionState + state.HandshakeComplete = c.handshakeComplete + if c.handshakeComplete { + state.NegotiatedProtocol = c.clientProtocol + state.CipherSuite = c.cipherSuite + } + + return state +} + +// OCSPResponse returns the stapled OCSP response from the TLS server, if +// any. (Only valid for client connections.) +func (c *Conn) OCSPResponse() []byte { c.handshakeMutex.Lock() defer c.handshakeMutex.Unlock() - return c.clientProtocol + + return c.ocspResponse +} + +// PeerCertificates returns the certificate chain that was presented by the +// other side. +func (c *Conn) PeerCertificates() []*x509.Certificate { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + + return c.peerCertificates +} + +// VerifyHostname checks that the peer certificate chain is valid for +// connecting to host. If so, it returns nil; if not, it returns an os.Error +// describing the problem. +func (c *Conn) VerifyHostname(host string) os.Error { + c.handshakeMutex.Lock() + defer c.handshakeMutex.Unlock() + if !c.isClient { + return os.ErrorString("VerifyHostname called on TLS server connection") + } + if !c.handshakeComplete { + return os.ErrorString("TLS handshake has not yet been performed") + } + return c.peerCertificates[0].VerifyHostname(host) } diff --git a/src/pkg/crypto/tls/conn_test.go b/src/pkg/crypto/tls/conn_test.go new file mode 100644 index 000000000..f44a50bed --- /dev/null +++ b/src/pkg/crypto/tls/conn_test.go @@ -0,0 +1,52 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "testing" +) + +func TestRoundUp(t *testing.T) { + if roundUp(0, 16) != 0 || + roundUp(1, 16) != 16 || + roundUp(15, 16) != 16 || + roundUp(16, 16) != 16 || + roundUp(17, 16) != 32 { + t.Error("roundUp broken") + } +} + +var paddingTests = []struct { + in []byte + good bool + expectedLen int +}{ + {[]byte{1, 2, 3, 4, 0}, true, 4}, + {[]byte{1, 2, 3, 4, 0, 1}, false, 0}, + {[]byte{1, 2, 3, 4, 99, 99}, false, 0}, + {[]byte{1, 2, 3, 4, 1, 1}, true, 4}, + {[]byte{1, 2, 3, 2, 2, 2}, true, 3}, + {[]byte{1, 2, 3, 3, 3, 3}, true, 2}, + {[]byte{1, 2, 3, 4, 3, 3}, false, 0}, + {[]byte{1, 4, 4, 4, 4, 4}, true, 1}, + {[]byte{5, 5, 5, 5, 5, 5}, true, 0}, + {[]byte{6, 6, 6, 6, 6, 6}, false, 0}, +} + +func TestRemovePadding(t *testing.T) { + for i, test := range paddingTests { + payload, good := removePadding(test.in) + expectedGood := byte(255) + if !test.good { + expectedGood = 0 + } + if good != expectedGood { + t.Errorf("#%d: wrong validity, want:%d got:%d", i, expectedGood, good) + } + if good == 255 && len(payload) != test.expectedLen { + t.Errorf("#%d: got %d, want %d", i, len(payload), test.expectedLen) + } + } +} diff --git a/src/pkg/crypto/tls/generate_cert.go b/src/pkg/crypto/tls/generate_cert.go new file mode 100644 index 000000000..3e0c63938 --- /dev/null +++ b/src/pkg/crypto/tls/generate_cert.go @@ -0,0 +1,70 @@ +// 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. + +// Generate a self-signed X.509 certificate for a TLS server. Outputs to +// 'cert.pem' and 'key.pem' and will overwrite existing files. + +package main + +import ( + "crypto/rsa" + "crypto/rand" + "crypto/x509" + "encoding/pem" + "flag" + "log" + "os" + "time" +) + +var hostName *string = flag.String("host", "127.0.0.1", "Hostname to generate a certificate for") + +func main() { + flag.Parse() + + priv, err := rsa.GenerateKey(rand.Reader, 1024) + if err != nil { + log.Exitf("failed to generate private key: %s", err) + return + } + + now := time.Seconds() + + template := x509.Certificate{ + SerialNumber: []byte{0}, + Subject: x509.Name{ + CommonName: *hostName, + Organization: []string{"Acme Co"}, + }, + NotBefore: time.SecondsToUTC(now - 300), + NotAfter: time.SecondsToUTC(now + 60*60*24*365), // valid for 1 year. + + SubjectKeyId: []byte{1, 2, 3, 4}, + KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, + } + + derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv) + if err != nil { + log.Exitf("Failed to create certificate: %s", err) + return + } + + certOut, err := os.Open("cert.pem", os.O_WRONLY|os.O_CREAT, 0644) + if err != nil { + log.Exitf("failed to open cert.pem for writing: %s", err) + return + } + pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}) + certOut.Close() + log.Print("written cert.pem\n") + + keyOut, err := os.Open("key.pem", os.O_WRONLY|os.O_CREAT, 0600) + if err != nil { + log.Print("failed to open key.pem for writing:", err) + return + } + pem.Encode(keyOut, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}) + keyOut.Close() + log.Print("written key.pem\n") +} diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go index dd3009802..1ca33f59d 100644 --- a/src/pkg/crypto/tls/handshake_client.go +++ b/src/pkg/crypto/tls/handshake_client.go @@ -5,10 +5,7 @@ package tls import ( - "crypto/hmac" - "crypto/rc4" "crypto/rsa" - "crypto/sha1" "crypto/subtle" "crypto/x509" "io" @@ -18,23 +15,30 @@ import ( func (c *Conn) clientHandshake() os.Error { finishedHash := newFinishedHash() - config := defaultConfig() + if c.config == nil { + c.config = defaultConfig() + } hello := &clientHelloMsg{ vers: maxVersion, - cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA}, + cipherSuites: c.config.cipherSuites(), compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), + ocspStapling: true, + serverName: c.config.ServerName, + supportedCurves: []uint16{curveP256, curveP384, curveP521}, + supportedPoints: []uint8{pointFormatUncompressed}, } - t := uint32(config.Time()) + t := uint32(c.config.time()) 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:]) + _, err := io.ReadFull(c.config.rand(), hello.random[4:]) if err != nil { - return c.sendAlert(alertInternalError) + c.sendAlert(alertInternalError) + return os.ErrorString("short read from Rand") } finishedHash.Write(hello.marshal()) @@ -57,11 +61,15 @@ func (c *Conn) clientHandshake() os.Error { c.vers = vers c.haveVers = true - if serverHello.cipherSuite != TLS_RSA_WITH_RC4_128_SHA || - serverHello.compressionMethod != compressionNone { + if serverHello.compressionMethod != compressionNone { return c.sendAlert(alertUnexpectedMessage) } + suite, suiteId := mutualCipherSuite(c.config.cipherSuites(), serverHello.cipherSuite) + if suite == nil { + return c.sendAlert(alertHandshakeFailure) + } + msg, err = c.readHandshake() if err != nil { return err @@ -73,71 +81,189 @@ func (c *Conn) clientHandshake() os.Error { finishedHash.Write(certMsg.marshal()) certs := make([]*x509.Certificate, len(certMsg.certificates)) + chain := NewCASet() for i, asn1Data := range certMsg.certificates { cert, err := x509.ParseCertificate(asn1Data) if err != nil { - return c.sendAlert(alertBadCertificate) + c.sendAlert(alertBadCertificate) + return os.ErrorString("failed to parse certificate from server: " + err.String()) } certs[i] = cert + chain.AddCert(cert) } - // TODO(agl): do better validation of certs: max path length, name restrictions etc. - for i := 1; i < len(certs); i++ { - if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil { - return c.sendAlert(alertBadCertificate) + // If we don't have a root CA set configured then anything is accepted. + // TODO(rsc): Find certificates for OS X 10.6. + for cur := certs[0]; c.config.RootCAs != nil; { + parent := c.config.RootCAs.FindVerifiedParent(cur) + if parent != nil { + break } - } - // TODO(rsc): Find certificates for OS X 10.6. - if false && config.RootCAs != nil { - root := config.RootCAs.FindParent(certs[len(certs)-1]) - if root == nil { - return c.sendAlert(alertBadCertificate) + parent = chain.FindVerifiedParent(cur) + if parent == nil { + c.sendAlert(alertBadCertificate) + return os.ErrorString("could not find root certificate for chain") } - if certs[len(certs)-1].CheckSignatureFrom(root) != nil { - return c.sendAlert(alertBadCertificate) + + if !parent.BasicConstraintsValid || !parent.IsCA { + c.sendAlert(alertBadCertificate) + return os.ErrorString("intermediate certificate does not have CA bit set") } + // KeyUsage status flags are ignored. From Engineering + // Security, Peter Gutmann: A European government CA marked its + // signing certificates as being valid for encryption only, but + // no-one noticed. Another European CA marked its signature + // keys as not being valid for signatures. A different CA + // marked its own trusted root certificate as being invalid for + // certificate signing. Another national CA distributed a + // certificate to be used to encrypt data for the country’s tax + // authority that was marked as only being usable for digital + // signatures but not for encryption. Yet another CA reversed + // the order of the bit flags in the keyUsage due to confusion + // over encoding endianness, essentially setting a random + // keyUsage in certificates that it issued. Another CA created + // a self-invalidating certificate by adding a certificate + // policy statement stipulating that the certificate had to be + // used strictly as specified in the keyUsage, and a keyUsage + // containing a flag indicating that the RSA encryption key + // could only be used for Diffie-Hellman key agreement. + + cur = parent } - pub, ok := certs[0].PublicKey.(*rsa.PublicKey) - if !ok { + if _, ok := certs[0].PublicKey.(*rsa.PublicKey); !ok { return c.sendAlert(alertUnsupportedCertificate) } + c.peerCertificates = certs + + if serverHello.certStatus { + msg, err = c.readHandshake() + if err != nil { + return err + } + cs, ok := msg.(*certificateStatusMsg) + if !ok { + return c.sendAlert(alertUnexpectedMessage) + } + finishedHash.Write(cs.marshal()) + + if cs.statusType == statusTypeOCSP { + c.ocspResponse = cs.response + } + } + msg, err = c.readHandshake() if err != nil { return err } + + keyAgreement := suite.ka() + + skx, ok := msg.(*serverKeyExchangeMsg) + if ok { + finishedHash.Write(skx.marshal()) + err = keyAgreement.processServerKeyExchange(c.config, hello, serverHello, certs[0], skx) + if err != nil { + c.sendAlert(alertUnexpectedMessage) + return err + } + + msg, err = c.readHandshake() + if err != nil { + return err + } + } + + transmitCert := false + certReq, ok := msg.(*certificateRequestMsg) + if ok { + // We only accept certificates with RSA keys. + rsaAvail := false + for _, certType := range certReq.certificateTypes { + if certType == certTypeRSASign { + rsaAvail = true + break + } + } + + // For now, only send a certificate back if the server gives us an + // empty list of certificateAuthorities. + // + // RFC 4346 on the certificateAuthorities field: + // A list of the distinguished names of acceptable certificate + // authorities. These distinguished names may specify a desired + // distinguished name for a root CA or for a subordinate CA; thus, + // this message can be used to describe both known roots and a + // desired authorization space. If the certificate_authorities + // list is empty then the client MAY send any certificate of the + // appropriate ClientCertificateType, unless there is some + // external arrangement to the contrary. + if rsaAvail && len(certReq.certificateAuthorities) == 0 { + transmitCert = true + } + + finishedHash.Write(certReq.marshal()) + + msg, err = c.readHandshake() + if err != nil { + return err + } + } + shd, ok := msg.(*serverHelloDoneMsg) if !ok { return c.sendAlert(alertUnexpectedMessage) } finishedHash.Write(shd.marshal()) - ckx := new(clientKeyExchangeMsg) - preMasterSecret := make([]byte, 48) - preMasterSecret[0] = byte(hello.vers >> 8) - preMasterSecret[1] = byte(hello.vers) - _, err = io.ReadFull(config.Rand, preMasterSecret[2:]) - if err != nil { - return c.sendAlert(alertInternalError) + var cert *x509.Certificate + if transmitCert { + certMsg = new(certificateMsg) + if len(c.config.Certificates) > 0 { + cert, err = x509.ParseCertificate(c.config.Certificates[0].Certificate[0]) + if err == nil && cert.PublicKeyAlgorithm == x509.RSA { + certMsg.certificates = c.config.Certificates[0].Certificate + } else { + cert = nil + } + } + finishedHash.Write(certMsg.marshal()) + c.writeRecord(recordTypeHandshake, certMsg.marshal()) } - ckx.ciphertext, err = rsa.EncryptPKCS1v15(config.Rand, pub, preMasterSecret) + preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0]) if err != nil { - return c.sendAlert(alertInternalError) + c.sendAlert(alertInternalError) + return err + } + if ckx != nil { + finishedHash.Write(ckx.marshal()) + c.writeRecord(recordTypeHandshake, ckx.marshal()) } - finishedHash.Write(ckx.marshal()) - c.writeRecord(recordTypeHandshake, ckx.marshal()) + if cert != nil { + certVerify := new(certificateVerifyMsg) + var digest [36]byte + copy(digest[0:16], finishedHash.serverMD5.Sum()) + copy(digest[16:36], finishedHash.serverSHA1.Sum()) + signed, err := rsa.SignPKCS1v15(c.config.rand(), c.config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, digest[0:]) + if err != nil { + return c.sendAlert(alertInternalError) + } + certVerify.signature = signed - suite := cipherSuites[0] - masterSecret, clientMAC, serverMAC, clientKey, serverKey := - keysFromPreMasterSecret11(preMasterSecret, hello.random, serverHello.random, suite.hashLength, suite.cipherKeyLength) + finishedHash.Write(certVerify.marshal()) + c.writeRecord(recordTypeHandshake, certVerify.marshal()) + } - cipher, _ := rc4.NewCipher(clientKey) + masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := + keysFromPreMasterSecret10(preMasterSecret, hello.random, serverHello.random, suite.macLen, suite.keyLen, suite.ivLen) - c.out.prepareCipherSpec(cipher, hmac.New(sha1.New(), clientMAC)) + clientCipher := suite.cipher(clientKey, clientIV, false /* not for reading */ ) + clientHash := suite.mac(clientMAC) + c.out.prepareCipherSpec(clientCipher, clientHash) c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) finished := new(finishedMsg) @@ -145,8 +271,9 @@ func (c *Conn) clientHandshake() os.Error { finishedHash.Write(finished.marshal()) c.writeRecord(recordTypeHandshake, finished.marshal()) - cipher2, _ := rc4.NewCipher(serverKey) - c.in.prepareCipherSpec(cipher2, hmac.New(sha1.New(), serverMAC)) + serverCipher := suite.cipher(serverKey, serverIV, true /* for reading */ ) + serverHash := suite.mac(serverMAC) + c.in.prepareCipherSpec(serverCipher, serverHash) c.readRecord(recordTypeChangeCipherSpec) if c.err != nil { return c.err @@ -168,6 +295,6 @@ func (c *Conn) clientHandshake() os.Error { } c.handshakeComplete = true - c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA + c.cipherSuite = suiteId return nil } diff --git a/src/pkg/crypto/tls/handshake_client_test.go b/src/pkg/crypto/tls/handshake_client_test.go new file mode 100644 index 000000000..e5c9684b9 --- /dev/null +++ b/src/pkg/crypto/tls/handshake_client_test.go @@ -0,0 +1,211 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "bytes" + "flag" + "io" + "net" + "testing" +) + +func testClientScript(t *testing.T, name string, clientScript [][]byte, config *Config) { + c, s := net.Pipe() + cli := Client(c, config) + go func() { + cli.Write([]byte("hello\n")) + cli.Close() + }() + + defer c.Close() + for i, b := range clientScript { + if i%2 == 1 { + s.Write(b) + continue + } + bb := make([]byte, len(b)) + _, err := io.ReadFull(s, bb) + if err != nil { + t.Fatalf("%s #%d: %s", name, i, err) + } + if !bytes.Equal(b, bb) { + t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b) + } + } +} + +func TestHandshakeClientRC4(t *testing.T) { + testClientScript(t, "RC4", rc4ClientScript, testConfig) +} + +var connect = flag.Bool("connect", false, "connect to a TLS server on :10443") + +func TestRunClient(t *testing.T) { + if !*connect { + return + } + + testConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA} + + conn, err := Dial("tcp", "", "127.0.0.1:10443", testConfig) + if err != nil { + t.Fatal(err) + } + + conn.Write([]byte("hello\n")) + conn.Close() +} + +// Script of interaction with gnutls implementation. +// The values for this test are obtained by building and running in client mode: +// % gotest -match "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 +// +// Where key.pem is: +// -----BEGIN RSA PRIVATE KEY----- +// MIIBPAIBAAJBAJ+zw4Qnlf8SMVIPFe9GEcStgOY2Ww/dgNdhjeD8ckUJNP5VZkVD +// TGiXav6ooKXfX3j/7tdkuD8Ey2//Kv7+ue0CAwEAAQJAN6W31vDEP2DjdqhzCDDu +// OA4NACqoiFqyblo7yc2tM4h4xMbC3Yx5UKMN9ZkCtX0gzrz6DyF47bdKcWBzNWCj +// gQIhANEoojVt7hq+SQ6MCN6FTAysGgQf56Q3TYoJMoWvdiXVAiEAw3e3rc+VJpOz +// rHuDo6bgpjUAAXM+v3fcpsfZSNO6V7kCIQCtbVjanpUwvZkMI9by02oUk9taki3b +// PzPfAfNPYAbCJQIhAJXNQDWyqwn/lGmR11cqY2y9nZ1+5w3yHGatLrcDnQHxAiEA +// vnlEGo8K85u+KwIOimM48ZG8oTk7iFdkqLJR1utT3aU= +// -----END RSA PRIVATE KEY----- +// +// and cert.pem is: +// -----BEGIN CERTIFICATE----- +// MIIBoDCCAUoCAQAwDQYJKoZIhvcNAQEEBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV +// BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD +// VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw05NzA5MDkwMzQxMjZa +// Fw05NzEwMDkwMzQxMjZaMF4xCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpTb21lLVN0 +// YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQxFzAVBgNVBAMT +// DkVyaWMgdGhlIFlvdW5nMFEwCQYFKw4DAgwFAANEAAJBALVEqPODnpI4rShlY8S7 +// tB713JNvabvn6Gned7zylwLLiXQAo/PAT6mfdWPTyCX9RlId/Aroh1ou893BA32Q +// sggwDQYJKoZIhvcNAQEEBQADQQCU5SSgapJSdRXJoX+CpCvFy+JVh9HpSjCpSNKO +// 19raHv98hKAUJuP9HyM+SUsffO6mAIgitUaqW8/wDMePhEC3 +// -----END CERTIFICATE----- +var rc4ClientScript = [][]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, 0x00, 0x05, + 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, 0x4a, 0x02, 0x00, 0x00, + 0x46, 0x03, 0x01, 0x4d, 0x0a, 0x56, 0x16, 0xb5, + 0x91, 0xd1, 0xcb, 0x80, 0x4d, 0xc7, 0x46, 0xf3, + 0x37, 0x0c, 0xef, 0xea, 0x64, 0x11, 0x14, 0x56, + 0x97, 0x9b, 0xc5, 0x67, 0x08, 0xb7, 0x13, 0xea, + 0xf8, 0xc9, 0xb3, 0x20, 0xe2, 0xfc, 0x41, 0xf6, + 0x96, 0x90, 0x9d, 0x43, 0x9b, 0xe9, 0x6e, 0xf8, + 0x41, 0x16, 0xcc, 0xf3, 0xc7, 0xde, 0xda, 0x5a, + 0xa1, 0x33, 0x69, 0xe2, 0xde, 0x5b, 0xaf, 0x2a, + 0x92, 0xe7, 0xd4, 0xa0, 0x00, 0x05, 0x00, 0x16, + 0x03, 0x01, 0x01, 0xf7, 0x0b, 0x00, 0x01, 0xf3, + 0x00, 0x01, 0xf0, 0x00, 0x01, 0xed, 0x30, 0x82, + 0x01, 0xe9, 0x30, 0x82, 0x01, 0x52, 0x02, 0x01, + 0x06, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, + 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, + 0x30, 0x5b, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, + 0x55, 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, + 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, + 0x13, 0x0a, 0x51, 0x75, 0x65, 0x65, 0x6e, 0x73, + 0x6c, 0x61, 0x6e, 0x64, 0x31, 0x1a, 0x30, 0x18, + 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x11, 0x43, + 0x72, 0x79, 0x70, 0x74, 0x53, 0x6f, 0x66, 0x74, + 0x20, 0x50, 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, + 0x31, 0x1b, 0x30, 0x19, 0x06, 0x03, 0x55, 0x04, + 0x03, 0x13, 0x12, 0x54, 0x65, 0x73, 0x74, 0x20, + 0x43, 0x41, 0x20, 0x28, 0x31, 0x30, 0x32, 0x34, + 0x20, 0x62, 0x69, 0x74, 0x29, 0x30, 0x1e, 0x17, + 0x0d, 0x30, 0x30, 0x31, 0x30, 0x31, 0x36, 0x32, + 0x32, 0x33, 0x31, 0x30, 0x33, 0x5a, 0x17, 0x0d, + 0x30, 0x33, 0x30, 0x31, 0x31, 0x34, 0x32, 0x32, + 0x33, 0x31, 0x30, 0x33, 0x5a, 0x30, 0x63, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x51, + 0x75, 0x65, 0x65, 0x6e, 0x73, 0x6c, 0x61, 0x6e, + 0x64, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x11, 0x43, 0x72, 0x79, 0x70, + 0x74, 0x53, 0x6f, 0x66, 0x74, 0x20, 0x50, 0x74, + 0x79, 0x20, 0x4c, 0x74, 0x64, 0x31, 0x23, 0x30, + 0x21, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x1a, + 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x74, + 0x65, 0x73, 0x74, 0x20, 0x63, 0x65, 0x72, 0x74, + 0x20, 0x28, 0x35, 0x31, 0x32, 0x20, 0x62, 0x69, + 0x74, 0x29, 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, + 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, + 0xf7, 0x0d, 0x01, 0x01, 0x04, 0x05, 0x00, 0x03, + 0x81, 0x81, 0x00, 0x93, 0xd2, 0x0a, 0xc5, 0x41, + 0xe6, 0x5a, 0xa9, 0x86, 0xf9, 0x11, 0x87, 0xe4, + 0xdb, 0x45, 0xe2, 0xc5, 0x95, 0x78, 0x1a, 0x6c, + 0x80, 0x6d, 0x73, 0x1f, 0xb4, 0x6d, 0x44, 0xa3, + 0xba, 0x86, 0x88, 0xc8, 0x58, 0xcd, 0x1c, 0x06, + 0x35, 0x6c, 0x44, 0x62, 0x88, 0xdf, 0xe4, 0xf6, + 0x64, 0x61, 0x95, 0xef, 0x4a, 0xa6, 0x7f, 0x65, + 0x71, 0xd7, 0x6b, 0x88, 0x39, 0xf6, 0x32, 0xbf, + 0xac, 0x93, 0x67, 0x69, 0x51, 0x8c, 0x93, 0xec, + 0x48, 0x5f, 0xc9, 0xb1, 0x42, 0xf9, 0x55, 0xd2, + 0x7e, 0x4e, 0xf4, 0xf2, 0x21, 0x6b, 0x90, 0x57, + 0xe6, 0xd7, 0x99, 0x9e, 0x41, 0xca, 0x80, 0xbf, + 0x1a, 0x28, 0xa2, 0xca, 0x5b, 0x50, 0x4a, 0xed, + 0x84, 0xe7, 0x82, 0xc7, 0xd2, 0xcf, 0x36, 0x9e, + 0x6a, 0x67, 0xb9, 0x88, 0xa7, 0xf3, 0x8a, 0xd0, + 0x04, 0xf8, 0xe8, 0xc6, 0x17, 0xe3, 0xc5, 0x29, + 0xbc, 0x17, 0xf1, 0x16, 0x03, 0x01, 0x00, 0x04, + 0x0e, 0x00, 0x00, 0x00, + }, + + { + 0x16, 0x03, 0x01, 0x00, 0x46, 0x10, 0x00, 0x00, + 0x42, 0x00, 0x40, 0x87, 0xa1, 0x1f, 0x14, 0xe1, + 0xfb, 0x91, 0xac, 0x58, 0x2e, 0xf3, 0x71, 0xce, + 0x01, 0x85, 0x2c, 0xc7, 0xfe, 0x84, 0x87, 0x82, + 0xb7, 0x57, 0xdb, 0x37, 0x4d, 0x46, 0x83, 0x67, + 0x52, 0x82, 0x51, 0x01, 0x95, 0x23, 0x68, 0x69, + 0x6b, 0xd0, 0xa7, 0xa7, 0xe5, 0x88, 0xd0, 0x47, + 0x71, 0xb8, 0xd2, 0x03, 0x05, 0x25, 0x56, 0x5c, + 0x10, 0x08, 0xc6, 0x9b, 0xd4, 0x67, 0xcd, 0x28, + 0xbe, 0x9c, 0x48, 0x14, 0x03, 0x01, 0x00, 0x01, + 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc1, 0xb8, + 0xd3, 0x7f, 0xc5, 0xc2, 0x5a, 0x1d, 0x6d, 0x5b, + 0x2d, 0x5c, 0x82, 0x87, 0xc2, 0x6f, 0x0d, 0x63, + 0x7b, 0x72, 0x2b, 0xda, 0x69, 0xc4, 0xfe, 0x3c, + 0x84, 0xa1, 0x5a, 0x62, 0x38, 0x37, 0xc6, 0x54, + 0x25, 0x2a, + }, + + { + 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, + 0x01, 0x00, 0x24, 0xea, 0x88, 0x9c, 0x00, 0xf6, + 0x35, 0xb8, 0x42, 0x7f, 0x15, 0x17, 0x76, 0x5e, + 0x4b, 0x24, 0xcb, 0x7e, 0xa0, 0x7b, 0xc3, 0x70, + 0x52, 0x0a, 0x88, 0x2a, 0x7a, 0x45, 0x59, 0x90, + 0x59, 0xac, 0xc6, 0xb5, 0x56, 0x55, 0x96, + }, +} diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go index f0a48c863..e5e856271 100644 --- a/src/pkg/crypto/tls/handshake_messages.go +++ b/src/pkg/crypto/tls/handshake_messages.go @@ -13,6 +13,9 @@ type clientHelloMsg struct { compressionMethods []uint8 nextProtoNeg bool serverName string + ocspStapling bool + supportedCurves []uint16 + supportedPoints []uint8 } func (m *clientHelloMsg) marshal() []byte { @@ -26,10 +29,22 @@ func (m *clientHelloMsg) marshal() []byte { if m.nextProtoNeg { numExtensions++ } + if m.ocspStapling { + extensionsLength += 1 + 2 + 2 + numExtensions++ + } if len(m.serverName) > 0 { extensionsLength += 5 + len(m.serverName) numExtensions++ } + if len(m.supportedCurves) > 0 { + extensionsLength += 2 + 2*len(m.supportedCurves) + numExtensions++ + } + if len(m.supportedPoints) > 0 { + extensionsLength += 1 + len(m.supportedPoints) + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -95,12 +110,55 @@ func (m *clientHelloMsg) marshal() []byte { // ServerName server_name_list<1..2^16-1> // } ServerNameList; - z[1] = 1 + z[0] = byte((len(m.serverName) + 3) >> 8) + z[1] = byte(len(m.serverName) + 3) z[3] = byte(len(m.serverName) >> 8) z[4] = byte(len(m.serverName)) copy(z[5:], []byte(m.serverName)) z = z[l:] } + if m.ocspStapling { + // RFC 4366, section 3.6 + z[0] = byte(extensionStatusRequest >> 8) + z[1] = byte(extensionStatusRequest) + z[2] = 0 + z[3] = 5 + z[4] = 1 // OCSP type + // Two zero valued uint16s for the two lengths. + z = z[9:] + } + if len(m.supportedCurves) > 0 { + // http://tools.ietf.org/html/rfc4492#section-5.5.1 + z[0] = byte(extensionSupportedCurves >> 8) + z[1] = byte(extensionSupportedCurves) + l := 2 + 2*len(m.supportedCurves) + z[2] = byte(l >> 8) + z[3] = byte(l) + l -= 2 + z[4] = byte(l >> 8) + z[5] = byte(l) + z = z[6:] + for _, curve := range m.supportedCurves { + z[0] = byte(curve >> 8) + z[1] = byte(curve) + z = z[2:] + } + } + if len(m.supportedPoints) > 0 { + // http://tools.ietf.org/html/rfc4492#section-5.5.2 + z[0] = byte(extensionSupportedPoints >> 8) + z[1] = byte(extensionSupportedPoints) + l := 1 + len(m.supportedPoints) + z[2] = byte(l >> 8) + z[3] = byte(l) + l-- + z[4] = byte(l) + z = z[5:] + for _, pointFormat := range m.supportedPoints { + z[0] = byte(pointFormat) + z = z[1:] + } + } m.raw = x @@ -148,6 +206,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { m.nextProtoNeg = false m.serverName = "" + m.ocspStapling = false if len(data) == 0 { // ClientHello is optionally followed by extension data @@ -202,6 +261,35 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool { return false } m.nextProtoNeg = true + case extensionStatusRequest: + m.ocspStapling = length > 0 && data[0] == statusTypeOCSP + case extensionSupportedCurves: + // http://tools.ietf.org/html/rfc4492#section-5.5.1 + if length < 2 { + return false + } + l := int(data[0])<<8 | int(data[1]) + if l%2 == 1 || length != l+2 { + return false + } + numCurves := l / 2 + m.supportedCurves = make([]uint16, numCurves) + d := data[2:] + for i := 0; i < numCurves; i++ { + m.supportedCurves[i] = uint16(d[0])<<8 | uint16(d[1]) + d = d[2:] + } + case extensionSupportedPoints: + // http://tools.ietf.org/html/rfc4492#section-5.5.2 + if length < 1 { + return false + } + l := int(data[0]) + if length != l+1 { + return false + } + m.supportedPoints = make([]uint8, l) + copy(m.supportedPoints, data[1:]) } data = data[length:] } @@ -218,6 +306,7 @@ type serverHelloMsg struct { compressionMethod uint8 nextProtoNeg bool nextProtos []string + certStatus bool } func (m *serverHelloMsg) marshal() []byte { @@ -238,6 +327,9 @@ func (m *serverHelloMsg) marshal() []byte { nextProtoLen += len(m.nextProtos) extensionsLength += nextProtoLen } + if m.certStatus { + numExtensions++ + } if numExtensions > 0 { extensionsLength += 4 * numExtensions length += 2 + extensionsLength @@ -281,25 +373,17 @@ func (m *serverHelloMsg) marshal() []byte { z = z[1+l:] } } + if m.certStatus { + z[0] = byte(extensionStatusRequest >> 8) + z[1] = byte(extensionStatusRequest) + z = z[4:] + } m.raw = x return x } -func append(slice []string, elem string) []string { - if len(slice) < cap(slice) { - slice = slice[0 : len(slice)+1] - slice[len(slice)-1] = elem - return slice - } - - fresh := make([]string, len(slice)+1, cap(slice)*2+1) - copy(fresh, slice) - fresh[len(slice)] = elem - return fresh -} - func (m *serverHelloMsg) unmarshal(data []byte) bool { if len(data) < 42 { return false @@ -322,6 +406,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { m.nextProtoNeg = false m.nextProtos = nil + m.certStatus = false if len(data) == 0 { // ServerHello is optionally followed by extension data @@ -361,6 +446,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool { m.nextProtos = append(m.nextProtos, string(d[0:l])) d = d[l:] } + case extensionStatusRequest: + if length > 0 { + return false + } + m.certStatus = true } data = data[length:] } @@ -445,6 +535,91 @@ func (m *certificateMsg) unmarshal(data []byte) bool { return true } +type serverKeyExchangeMsg struct { + raw []byte + key []byte +} + +func (m *serverKeyExchangeMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + length := len(m.key) + x := make([]byte, length+4) + x[0] = typeServerKeyExchange + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + copy(x[4:], m.key) + + m.raw = x + return x +} + +func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 4 { + return false + } + m.key = data[4:] + return true +} + +type certificateStatusMsg struct { + raw []byte + statusType uint8 + response []byte +} + +func (m *certificateStatusMsg) marshal() []byte { + if m.raw != nil { + return m.raw + } + + var x []byte + if m.statusType == statusTypeOCSP { + x = make([]byte, 4+4+len(m.response)) + x[0] = typeCertificateStatus + l := len(m.response) + 4 + x[1] = byte(l >> 16) + x[2] = byte(l >> 8) + x[3] = byte(l) + x[4] = statusTypeOCSP + + l -= 4 + x[5] = byte(l >> 16) + x[6] = byte(l >> 8) + x[7] = byte(l) + copy(x[8:], m.response) + } else { + x = []byte{typeCertificateStatus, 0, 0, 1, m.statusType} + } + + m.raw = x + return x +} + +func (m *certificateStatusMsg) unmarshal(data []byte) bool { + m.raw = data + if len(data) < 5 { + return false + } + m.statusType = data[4] + + m.response = nil + if m.statusType == statusTypeOCSP { + if len(data) < 8 { + return false + } + respLen := uint32(data[5])<<16 | uint32(data[6])<<8 | uint32(data[7]) + if uint32(len(data)) != 4+4+respLen { + return false + } + m.response = data[8:] + } + return true +} + type serverHelloDoneMsg struct{} func (m *serverHelloDoneMsg) marshal() []byte { @@ -466,15 +641,13 @@ func (m *clientKeyExchangeMsg) marshal() []byte { if m.raw != nil { return m.raw } - length := len(m.ciphertext) + 2 + length := len(m.ciphertext) x := make([]byte, length+4) x[0] = typeClientKeyExchange x[1] = uint8(length >> 16) x[2] = uint8(length >> 8) x[3] = uint8(length) - x[4] = uint8(len(m.ciphertext) >> 8) - x[5] = uint8(len(m.ciphertext)) - copy(x[6:], m.ciphertext) + copy(x[4:], m.ciphertext) m.raw = x return x @@ -482,14 +655,14 @@ func (m *clientKeyExchangeMsg) marshal() []byte { func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool { m.raw = data - if len(data) < 7 { + if len(data) < 4 { return false } - cipherTextLen := int(data[4])<<8 | int(data[5]) - if len(data) != 6+cipherTextLen { + l := int(data[1])<<16 | int(data[2])<<8 | int(data[3]) + if l != len(data)-4 { return false } - m.ciphertext = data[6:] + m.ciphertext = data[4:] return true } @@ -579,3 +752,153 @@ func (m *nextProtoMsg) unmarshal(data []byte) bool { return true } + +type certificateRequestMsg struct { + raw []byte + certificateTypes []byte + certificateAuthorities [][]byte +} + +func (m *certificateRequestMsg) marshal() (x []byte) { + if m.raw != nil { + return m.raw + } + + // See http://tools.ietf.org/html/rfc4346#section-7.4.4 + length := 1 + len(m.certificateTypes) + 2 + for _, ca := range m.certificateAuthorities { + length += 2 + len(ca) + } + + x = make([]byte, 4+length) + x[0] = typeCertificateRequest + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + + x[4] = uint8(len(m.certificateTypes)) + + copy(x[5:], m.certificateTypes) + y := x[5+len(m.certificateTypes):] + + numCA := len(m.certificateAuthorities) + y[0] = uint8(numCA >> 8) + y[1] = uint8(numCA) + y = y[2:] + for _, ca := range m.certificateAuthorities { + y[0] = uint8(len(ca) >> 8) + y[1] = uint8(len(ca)) + y = y[2:] + copy(y, ca) + y = y[len(ca):] + } + + m.raw = x + + return +} + +func (m *certificateRequestMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 5 { + return false + } + + length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + if uint32(len(data))-4 != length { + return false + } + + numCertTypes := int(data[4]) + data = data[5:] + if numCertTypes == 0 || len(data) <= numCertTypes { + return false + } + + m.certificateTypes = make([]byte, numCertTypes) + if copy(m.certificateTypes, data) != numCertTypes { + return false + } + + data = data[numCertTypes:] + if len(data) < 2 { + return false + } + + numCAs := uint16(data[0])<<16 | uint16(data[1]) + data = data[2:] + + m.certificateAuthorities = make([][]byte, numCAs) + for i := uint16(0); i < numCAs; i++ { + if len(data) < 2 { + return false + } + caLen := uint16(data[0])<<16 | uint16(data[1]) + + data = data[2:] + if len(data) < int(caLen) { + return false + } + + ca := make([]byte, caLen) + copy(ca, data) + m.certificateAuthorities[i] = ca + data = data[caLen:] + } + + if len(data) > 0 { + return false + } + + return true +} + +type certificateVerifyMsg struct { + raw []byte + signature []byte +} + +func (m *certificateVerifyMsg) marshal() (x []byte) { + if m.raw != nil { + return m.raw + } + + // See http://tools.ietf.org/html/rfc4346#section-7.4.8 + siglength := len(m.signature) + length := 2 + siglength + x = make([]byte, 4+length) + x[0] = typeCertificateVerify + x[1] = uint8(length >> 16) + x[2] = uint8(length >> 8) + x[3] = uint8(length) + x[4] = uint8(siglength >> 8) + x[5] = uint8(siglength) + copy(x[6:], m.signature) + + m.raw = x + + return +} + +func (m *certificateVerifyMsg) unmarshal(data []byte) bool { + m.raw = data + + if len(data) < 6 { + return false + } + + length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) + if uint32(len(data))-4 != length { + return false + } + + siglength := int(data[4])<<8 + int(data[5]) + if len(data)-6 != siglength { + return false + } + + m.signature = data[6:] + + return true +} diff --git a/src/pkg/crypto/tls/handshake_messages_test.go b/src/pkg/crypto/tls/handshake_messages_test.go index 2e422cc6a..21577dd0b 100644 --- a/src/pkg/crypto/tls/handshake_messages_test.go +++ b/src/pkg/crypto/tls/handshake_messages_test.go @@ -16,6 +16,9 @@ var tests = []interface{}{ &serverHelloMsg{}, &certificateMsg{}, + &certificateRequestMsg{}, + &certificateVerifyMsg{}, + &certificateStatusMsg{}, &clientKeyExchangeMsg{}, &finishedMsg{}, &nextProtoMsg{}, @@ -111,6 +114,12 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value { if rand.Intn(10) > 5 { m.serverName = randomString(rand.Intn(255), rand) } + m.ocspStapling = rand.Intn(10) > 5 + m.supportedPoints = randomBytes(rand.Intn(5)+1, rand) + m.supportedCurves = make([]uint16, rand.Intn(5)+1) + for i, _ := range m.supportedCurves { + m.supportedCurves[i] = uint16(rand.Intn(30000)) + } return reflect.NewValue(m) } @@ -146,6 +155,34 @@ func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value { return reflect.NewValue(m) } +func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value { + m := &certificateRequestMsg{} + m.certificateTypes = randomBytes(rand.Intn(5)+1, rand) + numCAs := rand.Intn(100) + m.certificateAuthorities = make([][]byte, numCAs) + for i := 0; i < numCAs; i++ { + m.certificateAuthorities[i] = randomBytes(rand.Intn(15)+1, rand) + } + return reflect.NewValue(m) +} + +func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value { + m := &certificateVerifyMsg{} + m.signature = randomBytes(rand.Intn(15)+1, rand) + return reflect.NewValue(m) +} + +func (*certificateStatusMsg) Generate(rand *rand.Rand, size int) reflect.Value { + m := &certificateStatusMsg{} + if rand.Intn(10) > 5 { + m.statusType = statusTypeOCSP + m.response = randomBytes(rand.Intn(10)+1, rand) + } else { + m.statusType = 42 + } + return reflect.NewValue(m) +} + func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value { m := &clientKeyExchangeMsg{} m.ciphertext = randomBytes(rand.Intn(1000)+1, rand) diff --git a/src/pkg/crypto/tls/handshake_server.go b/src/pkg/crypto/tls/handshake_server.go index ebf956763..955811ada 100644 --- a/src/pkg/crypto/tls/handshake_server.go +++ b/src/pkg/crypto/tls/handshake_server.go @@ -4,34 +4,14 @@ package tls -// The handshake goroutine reads handshake messages from the record processor -// and outputs messages to be written on another channel. It updates the record -// processor with the state of the connection via the control channel. In the -// case of handshake messages that need synchronous processing (because they -// affect the handling of the next record) the record processor knows about -// them and either waits for a control message (Finished) or includes a reply -// channel in the message (ChangeCipherSpec). - import ( - "crypto/hmac" - "crypto/rc4" "crypto/rsa" - "crypto/sha1" "crypto/subtle" + "crypto/x509" "io" "os" ) -type cipherSuite struct { - id uint16 // The number of this suite on the wire. - hashLength, cipherKeyLength int - // TODO(agl): need a method to create the cipher and hash interfaces. -} - -var cipherSuites = []cipherSuite{ - cipherSuite{TLS_RSA_WITH_RC4_128_SHA, 20, 16}, -} - func (c *Conn) serverHandshake() os.Error { config := c.config msg, err := c.readHandshake() @@ -54,16 +34,38 @@ func (c *Conn) serverHandshake() os.Error { hello := new(serverHelloMsg) - // We only support a single ciphersuite so we look for it in the list - // of client supported suites. - // - // TODO(agl): Add additional cipher suites. - var suite *cipherSuite + supportedCurve := false +Curves: + for _, curve := range clientHello.supportedCurves { + switch curve { + case curveP256, curveP384, curveP521: + supportedCurve = true + break Curves + } + } + supportedPointFormat := false + for _, pointFormat := range clientHello.supportedPoints { + if pointFormat == pointFormatUncompressed { + supportedPointFormat = true + break + } + } + + ellipticOk := supportedCurve && supportedPointFormat + + var suite *cipherSuite + var suiteId uint16 for _, id := range clientHello.cipherSuites { - for _, supported := range cipherSuites { - if supported.id == id { - suite = &supported + for _, supported := range config.cipherSuites() { + if id == supported { + suite = cipherSuites[id] + // Don't select a ciphersuite which we can't + // support for this client. + if suite.elliptic && !ellipticOk { + continue + } + suiteId = id break } } @@ -83,14 +85,14 @@ func (c *Conn) serverHandshake() os.Error { } hello.vers = vers - hello.cipherSuite = suite.id - t := uint32(config.Time()) + hello.cipherSuite = suiteId + t := uint32(config.time()) 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:]) + _, err = io.ReadFull(config.rand(), hello.random[4:]) if err != nil { return c.sendAlert(alertInternalError) } @@ -112,10 +114,76 @@ func (c *Conn) serverHandshake() os.Error { finishedHash.Write(certMsg.marshal()) c.writeRecord(recordTypeHandshake, certMsg.marshal()) + keyAgreement := suite.ka() + + skx, err := keyAgreement.generateServerKeyExchange(config, clientHello, hello) + if err != nil { + c.sendAlert(alertHandshakeFailure) + return err + } + if skx != nil { + finishedHash.Write(skx.marshal()) + c.writeRecord(recordTypeHandshake, skx.marshal()) + } + + if config.AuthenticateClient { + // Request a client certificate + certReq := new(certificateRequestMsg) + certReq.certificateTypes = []byte{certTypeRSASign} + // An empty list of certificateAuthorities signals to + // the client that it may send any certificate in response + // to our request. + + finishedHash.Write(certReq.marshal()) + c.writeRecord(recordTypeHandshake, certReq.marshal()) + } + helloDone := new(serverHelloDoneMsg) finishedHash.Write(helloDone.marshal()) c.writeRecord(recordTypeHandshake, helloDone.marshal()) + var pub *rsa.PublicKey + if config.AuthenticateClient { + // Get client certificate + msg, err = c.readHandshake() + if err != nil { + return err + } + certMsg, ok = msg.(*certificateMsg) + if !ok { + return c.sendAlert(alertUnexpectedMessage) + } + finishedHash.Write(certMsg.marshal()) + + certs := make([]*x509.Certificate, len(certMsg.certificates)) + for i, asn1Data := range certMsg.certificates { + cert, err := x509.ParseCertificate(asn1Data) + if err != nil { + c.sendAlert(alertBadCertificate) + return os.ErrorString("could not parse client's certificate: " + err.String()) + } + certs[i] = cert + } + + // TODO(agl): do better validation of certs: max path length, name restrictions etc. + for i := 1; i < len(certs); i++ { + if err := certs[i-1].CheckSignatureFrom(certs[i]); err != nil { + c.sendAlert(alertBadCertificate) + return os.ErrorString("could not validate certificate signature: " + err.String()) + } + } + + if len(certs) > 0 { + key, ok := certs[0].PublicKey.(*rsa.PublicKey) + if !ok { + return c.sendAlert(alertUnsupportedCertificate) + } + pub = key + c.peerCertificates = certs + } + } + + // Get client key exchange msg, err = c.readHandshake() if err != nil { return err @@ -126,28 +194,46 @@ func (c *Conn) serverHandshake() os.Error { } finishedHash.Write(ckx.marshal()) - preMasterSecret := make([]byte, 48) - _, err = io.ReadFull(config.Rand, preMasterSecret[2:]) - if err != nil { - return c.sendAlert(alertInternalError) + // If we received a client cert in response to our certificate request message, + // the client will send us a certificateVerifyMsg immediately after the + // clientKeyExchangeMsg. This message is a MD5SHA1 digest of all preceeding + // handshake-layer messages that is signed using the private key corresponding + // to the client's certificate. This allows us to verify that the client is in + // posession of the private key of the certificate. + if len(c.peerCertificates) > 0 { + msg, err = c.readHandshake() + if err != nil { + return err + } + certVerify, ok := msg.(*certificateVerifyMsg) + if !ok { + return c.sendAlert(alertUnexpectedMessage) + } + + digest := make([]byte, 36) + copy(digest[0:16], finishedHash.serverMD5.Sum()) + copy(digest[16:36], finishedHash.serverSHA1.Sum()) + err = rsa.VerifyPKCS1v15(pub, rsa.HashMD5SHA1, digest, certVerify.signature) + if err != nil { + c.sendAlert(alertBadCertificate) + return os.ErrorString("could not validate signature of connection nonces: " + err.String()) + } + + finishedHash.Write(certVerify.marshal()) } - err = rsa.DecryptPKCS1v15SessionKey(config.Rand, config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret) + preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx) if err != nil { - return c.sendAlert(alertHandshakeFailure) + c.sendAlert(alertHandshakeFailure) + return err } - // We don't check the version number in the premaster secret. For one, - // by checking it, we would leak information about the validity of the - // encrypted pre-master secret. Secondly, it provides only a small - // benefit against a downgrade attack and some implementations send the - // wrong version anyway. See the discussion at the end of section - // 7.4.7.1 of RFC 4346. - masterSecret, clientMAC, serverMAC, clientKey, serverKey := - keysFromPreMasterSecret11(preMasterSecret, clientHello.random, hello.random, suite.hashLength, suite.cipherKeyLength) + masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV := + keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen) - cipher, _ := rc4.NewCipher(clientKey) - c.in.prepareCipherSpec(cipher, hmac.New(sha1.New(), clientMAC)) + clientCipher := suite.cipher(clientKey, clientIV, true /* for reading */ ) + clientHash := suite.mac(clientMAC) + c.in.prepareCipherSpec(clientCipher, clientHash) c.readRecord(recordTypeChangeCipherSpec) if err := c.error(); err != nil { return err @@ -183,8 +269,9 @@ func (c *Conn) serverHandshake() os.Error { finishedHash.Write(clientFinished.marshal()) - cipher2, _ := rc4.NewCipher(serverKey) - c.out.prepareCipherSpec(cipher2, hmac.New(sha1.New(), serverMAC)) + serverCipher := suite.cipher(serverKey, serverIV, false /* not for reading */ ) + serverHash := suite.mac(serverMAC) + c.out.prepareCipherSpec(serverCipher, serverHash) c.writeRecord(recordTypeChangeCipherSpec, []byte{1}) finished := new(finishedMsg) @@ -192,7 +279,7 @@ func (c *Conn) serverHandshake() os.Error { c.writeRecord(recordTypeHandshake, finished.marshal()) c.handshakeComplete = true - c.cipherSuite = TLS_RSA_WITH_RC4_128_SHA + c.cipherSuite = suiteId return nil } diff --git a/src/pkg/crypto/tls/handshake_server_test.go b/src/pkg/crypto/tls/handshake_server_test.go index d31dc497e..5cf3ae049 100644 --- a/src/pkg/crypto/tls/handshake_server_test.go +++ b/src/pkg/crypto/tls/handshake_server_test.go @@ -5,8 +5,8 @@ package tls import ( - // "bytes" "big" + "bytes" "crypto/rsa" "encoding/hex" "flag" @@ -14,7 +14,6 @@ import ( "net" "os" "testing" - // "testing/script" ) type zeroSource struct{} @@ -36,6 +35,7 @@ func init() { testConfig.Certificates = make([]Certificate, 1) testConfig.Certificates[0].Certificate = [][]byte{testCertificate} testConfig.Certificates[0].PrivateKey = testPrivateKey + testConfig.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA} } func testClientHelloFailure(t *testing.T, m handshakeMessage, expected os.Error) { @@ -71,13 +71,13 @@ func TestRejectBadProtocolVersion(t *testing.T) { } func TestNoSuiteOverlap(t *testing.T) { - clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, ""} + clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{0xff00}, []uint8{0}, false, "", false, nil, nil} 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, ""} + clientHello := &clientHelloMsg{nil, 0x0301, nil, nil, []uint16{TLS_RSA_WITH_RC4_128_SHA}, []uint8{0xff}, false, "", false, nil, nil} testClientHelloFailure(t, clientHello, alertHandshakeFailure) } @@ -107,9 +107,9 @@ func TestClose(t *testing.T) { } -func TestHandshakeServer(t *testing.T) { +func testServerScript(t *testing.T, name string, serverScript [][]byte, config *Config) { c, s := net.Pipe() - srv := Server(s, testConfig) + srv := Server(s, config) go func() { srv.Write([]byte("hello, world\n")) srv.Close() @@ -124,15 +124,23 @@ func TestHandshakeServer(t *testing.T) { bb := make([]byte, len(b)) _, err := io.ReadFull(c, bb) if err != nil { - t.Fatalf("#%d: %s", i, err) + t.Fatalf("%s #%d: %s", name, i, err) + } + if !bytes.Equal(b, bb) { + t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", name, i, bb, b) } } +} - if !srv.haveVers || srv.vers != 0x0302 { - t.Errorf("server version incorrect: %v %v", srv.haveVers, srv.vers) - } +func TestHandshakeServerRC4(t *testing.T) { + testServerScript(t, "RC4", rc4ServerScript, testConfig) +} - // TODO: check protocol +func TestHandshakeServerAES(t *testing.T) { + aesConfig := new(Config) + *aesConfig = *testConfig + aesConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_CBC_SHA} + testServerScript(t, "AES", aesServerScript, aesConfig) } var serve = flag.Bool("serve", false, "run a TLS server on :10443") @@ -152,7 +160,11 @@ func TestRunServer(t *testing.T) { if err != nil { break } - c.Write([]byte("hello, world\n")) + _, err = c.Write([]byte("hello, world\n")) + if err != nil { + t.Errorf("error from TLS: %s", err) + break + } c.Close() } } @@ -181,113 +193,324 @@ var testPrivateKey = &rsa.PrivateKey{ } // Script of interaction with gnutls implementation. -// The values for this test are obtained by building a test binary (gotest) -// and then running 6.out -serve to start a server and then -// gnutls-cli --insecure --debug 100 -p 10443 localhost -// to dump a session. -var serverScript = [][]byte{ - // Alternate write and read. - []byte{ - 0x16, 0x03, 0x02, 0x00, 0x71, 0x01, 0x00, 0x00, 0x6d, 0x03, 0x02, 0x4b, 0xd4, 0xee, 0x6e, 0xab, - 0x0b, 0xc3, 0x01, 0xd6, 0x8d, 0xe0, 0x72, 0x7e, 0x6c, 0x04, 0xbe, 0x9a, 0x3c, 0xa3, 0xd8, 0x95, - 0x28, 0x00, 0xb2, 0xe8, 0x1f, 0xdd, 0xb0, 0xec, 0xca, 0x46, 0x1f, 0x00, 0x00, 0x28, 0x00, 0x33, - 0x00, 0x39, 0x00, 0x16, 0x00, 0x32, 0x00, 0x38, 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, - 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x35, 0x00, 0x0a, 0x00, 0x05, 0x00, 0x04, 0x00, 0x8c, - 0x00, 0x8d, 0x00, 0x8b, 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1c, 0x00, 0x09, 0x00, 0x03, 0x02, 0x00, - 0x01, 0x00, 0x00, 0x00, 0x11, 0x00, 0x0f, 0x00, 0x00, 0x0c, 0x31, 0x39, 0x32, 0x2e, 0x31, 0x36, - 0x38, 0x2e, 0x30, 0x2e, 0x31, 0x30, +// The values for this test are obtained by building and running in server mode: +// % gotest -match "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 +var rc4ServerScript = [][]byte{ + { + 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00, + 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x1f, 0x5a, 0x7a, + 0x0a, 0x92, 0x2f, 0xf0, 0x73, 0x16, 0x3a, 0x88, + 0x14, 0x85, 0x4c, 0x98, 0x15, 0x7b, 0x65, 0xe0, + 0x78, 0xd0, 0xed, 0xd0, 0xf3, 0x65, 0x20, 0xeb, + 0x80, 0xd1, 0x0b, 0x00, 0x00, 0x34, 0x00, 0x33, + 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, + 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, + 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, + 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, + 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, + 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09, + 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff, + 0x01, 0x00, 0x01, 0x00, }, - []byte{ - 0x16, 0x03, 0x02, 0x00, 0x2a, - 0x02, 0x00, 0x00, 0x26, 0x03, 0x02, 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, 0x02, 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, 0x02, 0x00, 0x04, - 0x0e, 0x00, 0x00, 0x00, + { + 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, + 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x16, + 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, + 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, + 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, + 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, + 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, + 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, + 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, + 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, + 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, + 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, + 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, + 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, + 0x20, 0x4c, 0x74, 0x64, 0x30, 0x1e, 0x17, 0x0d, + 0x31, 0x30, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, + 0x30, 0x39, 0x33, 0x38, 0x5a, 0x17, 0x0d, 0x31, + 0x31, 0x30, 0x34, 0x32, 0x34, 0x30, 0x39, 0x30, + 0x39, 0x33, 0x38, 0x5a, 0x30, 0x45, 0x31, 0x0b, + 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, + 0x02, 0x41, 0x55, 0x31, 0x13, 0x30, 0x11, 0x06, + 0x03, 0x55, 0x04, 0x08, 0x13, 0x0a, 0x53, 0x6f, + 0x6d, 0x65, 0x2d, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x31, 0x21, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x04, + 0x0a, 0x13, 0x18, 0x49, 0x6e, 0x74, 0x65, 0x72, + 0x6e, 0x65, 0x74, 0x20, 0x57, 0x69, 0x64, 0x67, + 0x69, 0x74, 0x73, 0x20, 0x50, 0x74, 0x79, 0x20, + 0x4c, 0x74, 0x64, 0x30, 0x81, 0x9f, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x81, 0x8d, + 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, + 0xbb, 0x79, 0xd6, 0xf5, 0x17, 0xb5, 0xe5, 0xbf, + 0x46, 0x10, 0xd0, 0xdc, 0x69, 0xbe, 0xe6, 0x2b, + 0x07, 0x43, 0x5a, 0xd0, 0x03, 0x2d, 0x8a, 0x7a, + 0x43, 0x85, 0xb7, 0x14, 0x52, 0xe7, 0xa5, 0x65, + 0x4c, 0x2c, 0x78, 0xb8, 0x23, 0x8c, 0xb5, 0xb4, + 0x82, 0xe5, 0xde, 0x1f, 0x95, 0x3b, 0x7e, 0x62, + 0xa5, 0x2c, 0xa5, 0x33, 0xd6, 0xfe, 0x12, 0x5c, + 0x7a, 0x56, 0xfc, 0xf5, 0x06, 0xbf, 0xfa, 0x58, + 0x7b, 0x26, 0x3f, 0xb5, 0xcd, 0x04, 0xd3, 0xd0, + 0xc9, 0x21, 0x96, 0x4a, 0xc7, 0xf4, 0x54, 0x9f, + 0x5a, 0xbf, 0xef, 0x42, 0x71, 0x00, 0xfe, 0x18, + 0x99, 0x07, 0x7f, 0x7e, 0x88, 0x7d, 0x7d, 0xf1, + 0x04, 0x39, 0xc4, 0xa2, 0x2e, 0xdb, 0x51, 0xc9, + 0x7c, 0xe3, 0xc0, 0x4c, 0x3b, 0x32, 0x66, 0x01, + 0xcf, 0xaf, 0xb1, 0x1d, 0xb8, 0x71, 0x9a, 0x1d, + 0xdb, 0xdb, 0x89, 0x6b, 0xae, 0xda, 0x2d, 0x79, + 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x81, 0xa7, + 0x30, 0x81, 0xa4, 0x30, 0x1d, 0x06, 0x03, 0x55, + 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0xb1, 0xad, + 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, 0x69, + 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, 0x18, + 0x88, 0x39, 0x30, 0x75, 0x06, 0x03, 0x55, 0x1d, + 0x23, 0x04, 0x6e, 0x30, 0x6c, 0x80, 0x14, 0xb1, + 0xad, 0xe2, 0x85, 0x5a, 0xcf, 0xcb, 0x28, 0xdb, + 0x69, 0xce, 0x23, 0x69, 0xde, 0xd3, 0x26, 0x8e, + 0x18, 0x88, 0x39, 0xa1, 0x49, 0xa4, 0x47, 0x30, + 0x45, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, + 0x04, 0x06, 0x13, 0x02, 0x41, 0x55, 0x31, 0x13, + 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x08, 0x13, + 0x0a, 0x53, 0x6f, 0x6d, 0x65, 0x2d, 0x53, 0x74, + 0x61, 0x74, 0x65, 0x31, 0x21, 0x30, 0x1f, 0x06, + 0x03, 0x55, 0x04, 0x0a, 0x13, 0x18, 0x49, 0x6e, + 0x74, 0x65, 0x72, 0x6e, 0x65, 0x74, 0x20, 0x57, + 0x69, 0x64, 0x67, 0x69, 0x74, 0x73, 0x20, 0x50, + 0x74, 0x79, 0x20, 0x4c, 0x74, 0x64, 0x82, 0x09, + 0x00, 0x85, 0xb0, 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, + 0xca, 0x30, 0x0c, 0x06, 0x03, 0x55, 0x1d, 0x13, + 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0xff, 0x30, + 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, + 0x81, 0x00, 0x08, 0x6c, 0x45, 0x24, 0xc7, 0x6b, + 0xb1, 0x59, 0xab, 0x0c, 0x52, 0xcc, 0xf2, 0xb0, + 0x14, 0xd7, 0x87, 0x9d, 0x7a, 0x64, 0x75, 0xb5, + 0x5a, 0x95, 0x66, 0xe4, 0xc5, 0x2b, 0x8e, 0xae, + 0x12, 0x66, 0x1f, 0xeb, 0x4f, 0x38, 0xb3, 0x6e, + 0x60, 0xd3, 0x92, 0xfd, 0xf7, 0x41, 0x08, 0xb5, + 0x25, 0x13, 0xb1, 0x18, 0x7a, 0x24, 0xfb, 0x30, + 0x1d, 0xba, 0xed, 0x98, 0xb9, 0x17, 0xec, 0xe7, + 0xd7, 0x31, 0x59, 0xdb, 0x95, 0xd3, 0x1d, 0x78, + 0xea, 0x50, 0x56, 0x5c, 0xd5, 0x82, 0x5a, 0x2d, + 0x5a, 0x5f, 0x33, 0xc4, 0xb6, 0xd8, 0xc9, 0x75, + 0x90, 0x96, 0x8c, 0x0f, 0x52, 0x98, 0xb5, 0xcd, + 0x98, 0x1f, 0x89, 0x20, 0x5f, 0xf2, 0xa0, 0x1c, + 0xa3, 0x1b, 0x96, 0x94, 0xdd, 0xa9, 0xfd, 0x57, + 0xe9, 0x70, 0xe8, 0x26, 0x6d, 0x71, 0x99, 0x9b, + 0x26, 0x6e, 0x38, 0x50, 0x29, 0x6c, 0x90, 0xa7, + 0xbd, 0xd9, 0x16, 0x03, 0x01, 0x00, 0x04, 0x0e, + 0x00, 0x00, 0x00, }, - []byte{ - 0x16, 0x03, 0x02, 0x00, 0x86, 0x10, 0x00, 0x00, 0x82, 0x00, 0x80, 0x3b, 0x7a, 0x9b, 0x05, 0xfd, - 0x1b, 0x0d, 0x81, 0xf0, 0xac, 0x59, 0x57, 0x4e, 0xb6, 0xf5, 0x81, 0xed, 0x52, 0x78, 0xc5, 0xff, - 0x36, 0x33, 0x9c, 0x94, 0x31, 0xc3, 0x14, 0x98, 0x5d, 0xa0, 0x49, 0x23, 0x11, 0x67, 0xdf, 0x73, - 0x1b, 0x81, 0x0b, 0xdd, 0x10, 0xda, 0xee, 0xb5, 0x68, 0x61, 0xa9, 0xb6, 0x15, 0xae, 0x1a, 0x11, - 0x31, 0x42, 0x2e, 0xde, 0x01, 0x4b, 0x81, 0x70, 0x03, 0xc8, 0x5b, 0xca, 0x21, 0x88, 0x25, 0xef, - 0x89, 0xf0, 0xb7, 0xff, 0x24, 0x32, 0xd3, 0x14, 0x76, 0xe2, 0x50, 0x5c, 0x2e, 0x75, 0x9d, 0x5c, - 0xa9, 0x80, 0x3d, 0x6f, 0xd5, 0x46, 0xd3, 0xdb, 0x42, 0x6e, 0x55, 0x81, 0x88, 0x42, 0x0e, 0x45, - 0xfe, 0x9e, 0xe4, 0x41, 0x79, 0xcf, 0x71, 0x0e, 0xed, 0x27, 0xa8, 0x20, 0x05, 0xe9, 0x7a, 0x42, - 0x4f, 0x05, 0x10, 0x2e, 0x52, 0x5d, 0x8c, 0x3c, 0x40, 0x49, 0x4c, - - 0x14, 0x03, 0x02, 0x00, 0x01, 0x01, - - 0x16, 0x03, 0x02, 0x00, 0x24, 0x8b, 0x12, 0x24, 0x06, 0xaa, 0x92, 0x74, 0xa1, 0x46, 0x6f, 0xc1, - 0x4e, 0x4a, 0xf7, 0x16, 0xdd, 0xd6, 0xe1, 0x2d, 0x37, 0x0b, 0x44, 0xba, 0xeb, 0xc4, 0x6c, 0xc7, - 0xa0, 0xb7, 0x8c, 0x9d, 0x24, 0xbd, 0x99, 0x33, 0x1e, + { + 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, + 0x82, 0x00, 0x80, 0x3c, 0x13, 0xd7, 0x12, 0xc1, + 0x6a, 0xf0, 0x3f, 0x8c, 0xa1, 0x35, 0x5d, 0xc5, + 0x89, 0x1e, 0x9e, 0xcd, 0x32, 0xc7, 0x9e, 0xe6, + 0xae, 0xd5, 0xf1, 0xbf, 0x70, 0xd7, 0xa9, 0xef, + 0x2c, 0x4c, 0xf4, 0x22, 0xbc, 0x17, 0x17, 0xaa, + 0x05, 0xf3, 0x9f, 0x80, 0xf2, 0xe9, 0x82, 0x2f, + 0x2a, 0x15, 0x54, 0x0d, 0x16, 0x0e, 0x77, 0x4c, + 0x28, 0x3c, 0x03, 0x2d, 0x2d, 0xd7, 0xc8, 0x64, + 0xd9, 0x59, 0x4b, 0x1c, 0xf4, 0xde, 0xff, 0x2f, + 0xbc, 0x94, 0xaf, 0x18, 0x26, 0x37, 0xce, 0x4f, + 0x84, 0x74, 0x2e, 0x45, 0x66, 0x7c, 0x0c, 0x54, + 0x46, 0x36, 0x5f, 0x65, 0x21, 0x7b, 0x83, 0x8c, + 0x6d, 0x76, 0xcd, 0x0d, 0x9f, 0xda, 0x1c, 0xa4, + 0x6e, 0xfe, 0xb1, 0xf7, 0x09, 0x0d, 0xfb, 0x74, + 0x66, 0x34, 0x99, 0x89, 0x7f, 0x5f, 0x77, 0x87, + 0x4a, 0x66, 0x4b, 0xa9, 0x59, 0x57, 0xe3, 0x56, + 0x0d, 0xdd, 0xd8, 0x14, 0x03, 0x01, 0x00, 0x01, + 0x01, 0x16, 0x03, 0x01, 0x00, 0x24, 0xc0, 0x4e, + 0xd3, 0x0f, 0xb5, 0xc0, 0x57, 0xa6, 0x18, 0x80, + 0x80, 0x6b, 0x49, 0xfe, 0xbd, 0x3a, 0x7a, 0x2c, + 0xef, 0x70, 0xb5, 0x1c, 0xd2, 0xdf, 0x5f, 0x78, + 0x5a, 0xd8, 0x4f, 0xa0, 0x95, 0xb4, 0xb3, 0xb5, + 0xaa, 0x3b, }, - []byte{ - 0x14, 0x03, 0x02, 0x00, 0x01, - 0x01, + { + 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, + 0x01, 0x00, 0x24, 0x9d, 0xc9, 0xda, 0xdf, 0xeb, + 0xc8, 0xdb, 0xf8, 0x94, 0xa5, 0xef, 0xd5, 0xfc, + 0x89, 0x01, 0x64, 0x30, 0x77, 0x5a, 0x18, 0x4b, + 0x16, 0x79, 0x9c, 0xf6, 0xf5, 0x09, 0x22, 0x12, + 0x4c, 0x3e, 0xa8, 0x8e, 0x91, 0xa5, 0x24, + }, +} - 0x16, 0x03, 0x02, 0x00, 0x24, - 0x6e, 0xd1, 0x3e, 0x49, 0x68, 0xc1, 0xa0, 0xa5, 0xb7, 0xaf, 0xb0, 0x7c, 0x52, 0x1f, 0xf7, 0x2d, - 0x51, 0xf3, 0xa5, 0xb6, 0xf6, 0xd4, 0x18, 0x4b, 0x7a, 0xd5, 0x24, 0x1d, 0x09, 0xb6, 0x41, 0x1c, - 0x1c, 0x98, 0xf6, 0x90, +var aesServerScript = [][]byte{ + { + 0x16, 0x03, 0x02, 0x00, 0x7f, 0x01, 0x00, 0x00, + 0x7b, 0x03, 0x02, 0x4d, 0x08, 0x2d, 0x0b, 0xb3, + 0x57, 0x85, 0x71, 0x4b, 0xfb, 0x34, 0xab, 0x16, + 0xd4, 0x92, 0x50, 0x81, 0x16, 0x95, 0x11, 0x28, + 0x1a, 0xcb, 0xff, 0x09, 0x4d, 0x23, 0xa6, 0xfe, + 0x2e, 0xbb, 0x78, 0x00, 0x00, 0x34, 0x00, 0x33, + 0x00, 0x45, 0x00, 0x39, 0x00, 0x88, 0x00, 0x16, + 0x00, 0x32, 0x00, 0x44, 0x00, 0x38, 0x00, 0x87, + 0x00, 0x13, 0x00, 0x66, 0x00, 0x90, 0x00, 0x91, + 0x00, 0x8f, 0x00, 0x8e, 0x00, 0x2f, 0x00, 0x41, + 0x00, 0x35, 0x00, 0x84, 0x00, 0x0a, 0x00, 0x05, + 0x00, 0x04, 0x00, 0x8c, 0x00, 0x8d, 0x00, 0x8b, + 0x00, 0x8a, 0x01, 0x00, 0x00, 0x1e, 0x00, 0x09, + 0x00, 0x03, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x0e, 0x00, 0x0c, 0x00, 0x00, 0x09, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x68, 0x6f, 0x73, 0x74, 0xff, + 0x01, 0x00, 0x01, 0x00, + }, - 0x17, 0x03, 0x02, 0x00, 0x21, - 0x50, 0xb7, 0x92, 0x4f, 0xd8, 0x78, 0x29, 0xa2, 0xe7, 0xa5, 0xa6, 0xbd, 0x1a, 0x0c, 0xf1, 0x5a, - 0x6e, 0x6c, 0xeb, 0x38, 0x99, 0x9b, 0x3c, 0xfd, 0xee, 0x53, 0xe8, 0x4d, 0x7b, 0xa5, 0x5b, 0x00, + { + 0x16, 0x03, 0x01, 0x00, 0x2a, 0x02, 0x00, 0x00, + 0x26, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x16, + 0x03, 0x01, 0x02, 0xbe, 0x0b, 0x00, 0x02, 0xba, + 0x00, 0x02, 0xb7, 0x00, 0x02, 0xb4, 0x30, 0x82, + 0x02, 0xb0, 0x30, 0x82, 0x02, 0x19, 0xa0, 0x03, + 0x02, 0x01, 0x02, 0x02, 0x09, 0x00, 0x85, 0xb0, + 0xbb, 0xa4, 0x8a, 0x7f, 0xb8, 0xca, 0x30, 0x0d, + 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, + 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x45, 0x31, + 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, + }, - 0xb9, + { + 0x16, 0x03, 0x01, 0x00, 0x86, 0x10, 0x00, 0x00, + 0x82, 0x00, 0x80, 0x71, 0x9c, 0xe7, 0x23, 0xfc, + 0xb9, 0x19, 0x29, 0x82, 0xbf, 0xef, 0x08, 0xf7, + 0x99, 0x36, 0xc3, 0x4c, 0x6f, 0x05, 0xd2, 0x8b, + 0x62, 0x2b, 0x19, 0x9b, 0x7f, 0xc0, 0xcc, 0x48, + 0x30, 0x5f, 0xcd, 0xc3, 0x70, 0x55, 0x53, 0x73, + 0xfa, 0x79, 0x74, 0xf3, 0xa3, 0x76, 0x9f, 0xa1, + 0x7f, 0x98, 0xc2, 0xc0, 0xe3, 0xc5, 0xa0, 0x31, + 0x2f, 0xa6, 0xe8, 0x1e, 0x61, 0x46, 0xb3, 0x9b, + 0x4b, 0x16, 0xf1, 0x2d, 0xc7, 0x63, 0x7f, 0x79, + 0x22, 0x30, 0xd1, 0xf2, 0xfc, 0x77, 0x98, 0x0a, + 0x16, 0x11, 0x63, 0x71, 0x7f, 0x70, 0xef, 0x16, + 0xbb, 0x39, 0x87, 0x34, 0xac, 0x49, 0xbd, 0x07, + 0x67, 0xcb, 0x9c, 0xcc, 0xde, 0xef, 0xb1, 0xe0, + 0xdb, 0x01, 0xb5, 0x35, 0xa9, 0xb3, 0x10, 0x0c, + 0x4b, 0xee, 0xb3, 0x4e, 0xfd, 0xbe, 0x15, 0x27, + 0xf0, 0x46, 0xb2, 0x38, 0xba, 0x5f, 0xcc, 0x89, + 0xec, 0x29, 0x82, 0x14, 0x03, 0x01, 0x00, 0x01, + 0x01, 0x16, 0x03, 0x01, 0x00, 0x30, 0x3c, 0xfb, + 0xa4, 0x12, 0xcb, 0x00, 0xf9, 0x57, 0x7e, 0x9b, + 0xc9, 0xdc, 0x0c, 0xba, 0x9a, 0x81, 0x62, 0xfb, + 0x26, 0x13, 0x53, 0xfe, 0xaa, 0xcc, 0x82, 0xbb, + 0xb6, 0x67, 0x7f, 0x39, 0xbe, 0x4d, 0xbb, 0xc0, + 0x6c, 0x24, 0x31, 0x83, 0xa5, 0x50, 0x3a, 0x75, + 0x32, 0x64, 0xb5, 0xdb, 0xbe, 0x0a, + }, - 0x15, 0x03, 0x02, 0x00, 0x16, - 0xc7, 0xc9, 0x5a, 0x72, 0xfb, 0x02, 0xa5, 0x93, 0xdd, 0x69, 0xeb, 0x30, 0x68, 0x5e, 0xbc, 0xe0, - 0x44, 0xb9, 0x59, 0x33, 0x68, 0xa9, + { + 0x14, 0x03, 0x01, 0x00, 0x01, 0x01, 0x16, 0x03, + 0x01, 0x00, 0x30, 0x43, 0x24, 0x42, 0x55, 0x08, + 0xe4, 0xc2, 0x15, 0xc9, 0xdb, 0x71, 0x69, 0xee, + 0x09, 0xc5, 0x1c, 0xfd, 0x46, 0x10, 0xa0, 0x68, + 0x21, 0xf2, 0x48, 0xac, 0x6c, 0xc0, 0x2b, 0x62, + 0x07, 0x8f, 0x48, 0x33, 0x0a, 0x6b, 0x62, 0x28, + 0x2e, 0x2c, 0xad, 0xcb, 0x34, 0x85, 0xca, 0x2e, + 0xcd, 0x84, 0xf0, }, } diff --git a/src/pkg/crypto/tls/key_agreement.go b/src/pkg/crypto/tls/key_agreement.go new file mode 100644 index 000000000..861c64f04 --- /dev/null +++ b/src/pkg/crypto/tls/key_agreement.go @@ -0,0 +1,246 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package tls + +import ( + "big" + "crypto/elliptic" + "crypto/md5" + "crypto/rsa" + "crypto/sha1" + "crypto/x509" + "io" + "os" +) + +// rsaKeyAgreement implements the standard TLS key agreement where the client +// encrypts the pre-master secret to the server's public key. +type rsaKeyAgreement struct{} + +func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) { + return nil, nil +} + +func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) { + preMasterSecret := make([]byte, 48) + _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) + if err != nil { + return nil, err + } + + if len(ckx.ciphertext) < 2 { + return nil, os.ErrorString("bad ClientKeyExchange") + } + ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1]) + if ciphertextLen != len(ckx.ciphertext)-2 { + return nil, os.ErrorString("bad ClientKeyExchange") + } + ciphertext := ckx.ciphertext[2:] + + err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ciphertext, preMasterSecret) + if err != nil { + return nil, err + } + // We don't check the version number in the premaster secret. For one, + // by checking it, we would leak information about the validity of the + // encrypted pre-master secret. Secondly, it provides only a small + // benefit against a downgrade attack and some implementations send the + // wrong version anyway. See the discussion at the end of section + // 7.4.7.1 of RFC 4346. + return preMasterSecret, nil +} + +func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error { + return os.ErrorString("unexpected ServerKeyExchange") +} + +func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) { + preMasterSecret := make([]byte, 48) + preMasterSecret[0] = byte(clientHello.vers >> 8) + preMasterSecret[1] = byte(clientHello.vers) + _, err := io.ReadFull(config.rand(), preMasterSecret[2:]) + if err != nil { + return nil, nil, err + } + + encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret) + if err != nil { + return nil, nil, err + } + ckx := new(clientKeyExchangeMsg) + ckx.ciphertext = make([]byte, len(encrypted)+2) + ckx.ciphertext[0] = byte(len(encrypted) >> 8) + ckx.ciphertext[1] = byte(len(encrypted)) + copy(ckx.ciphertext[2:], encrypted) + return preMasterSecret, ckx, nil +} + + +// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the +// concatenation of an MD5 and SHA1 hash. +func md5SHA1Hash(slices ...[]byte) []byte { + md5sha1 := make([]byte, md5.Size+sha1.Size) + hmd5 := md5.New() + for _, slice := range slices { + hmd5.Write(slice) + } + copy(md5sha1, hmd5.Sum()) + + hsha1 := sha1.New() + for _, slice := range slices { + hsha1.Write(slice) + } + copy(md5sha1[md5.Size:], hsha1.Sum()) + return md5sha1 +} + +// ecdheRSAKeyAgreement implements a TLS key agreement where the server +// generates a ephemeral EC public/private key pair and signs it. The +// pre-master secret is then calculated using ECDH. +type ecdheRSAKeyAgreement struct { + privateKey []byte + curve *elliptic.Curve + x, y *big.Int +} + +func (ka *ecdheRSAKeyAgreement) generateServerKeyExchange(config *Config, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, os.Error) { + var curveid uint16 + +Curve: + for _, c := range clientHello.supportedCurves { + switch c { + case curveP256: + ka.curve = elliptic.P256() + curveid = c + break Curve + case curveP384: + ka.curve = elliptic.P384() + curveid = c + break Curve + case curveP521: + ka.curve = elliptic.P521() + curveid = c + break Curve + } + } + + var x, y *big.Int + var err os.Error + ka.privateKey, x, y, err = ka.curve.GenerateKey(config.rand()) + if err != nil { + return nil, err + } + ecdhePublic := ka.curve.Marshal(x, y) + + // http://tools.ietf.org/html/rfc4492#section-5.4 + serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) + serverECDHParams[0] = 3 // named curve + serverECDHParams[1] = byte(curveid >> 8) + serverECDHParams[2] = byte(curveid) + serverECDHParams[3] = byte(len(ecdhePublic)) + copy(serverECDHParams[4:], ecdhePublic) + + md5sha1 := md5SHA1Hash(clientHello.random, hello.random, serverECDHParams) + sig, err := rsa.SignPKCS1v15(config.rand(), config.Certificates[0].PrivateKey, rsa.HashMD5SHA1, md5sha1) + if err != nil { + return nil, os.ErrorString("failed to sign ECDHE parameters: " + err.String()) + } + + skx := new(serverKeyExchangeMsg) + skx.key = make([]byte, len(serverECDHParams)+2+len(sig)) + copy(skx.key, serverECDHParams) + k := skx.key[len(serverECDHParams):] + k[0] = byte(len(sig) >> 8) + k[1] = byte(len(sig)) + copy(k[2:], sig) + + return skx, nil +} + +func (ka *ecdheRSAKeyAgreement) processClientKeyExchange(config *Config, ckx *clientKeyExchangeMsg) ([]byte, os.Error) { + if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { + return nil, os.ErrorString("bad ClientKeyExchange") + } + x, y := ka.curve.Unmarshal(ckx.ciphertext[1:]) + if x == nil { + return nil, os.ErrorString("bad ClientKeyExchange") + } + x, _ = ka.curve.ScalarMult(x, y, ka.privateKey) + preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3) + xBytes := x.Bytes() + copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) + + return preMasterSecret, nil +} + +func (ka *ecdheRSAKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) os.Error { + if len(skx.key) < 4 { + goto Error + } + if skx.key[0] != 3 { // named curve + return os.ErrorString("server selected unsupported curve") + } + curveid := uint16(skx.key[1])<<8 | uint16(skx.key[2]) + + switch curveid { + case curveP256: + ka.curve = elliptic.P256() + case curveP384: + ka.curve = elliptic.P384() + case curveP521: + ka.curve = elliptic.P521() + default: + return os.ErrorString("server selected unsupported curve") + } + + publicLen := int(skx.key[3]) + if publicLen+4 > len(skx.key) { + goto Error + } + ka.x, ka.y = ka.curve.Unmarshal(skx.key[4 : 4+publicLen]) + if ka.x == nil { + goto Error + } + serverECDHParams := skx.key[:4+publicLen] + + sig := skx.key[4+publicLen:] + if len(sig) < 2 { + goto Error + } + sigLen := int(sig[0])<<8 | int(sig[1]) + if sigLen+2 != len(sig) { + goto Error + } + sig = sig[2:] + + md5sha1 := md5SHA1Hash(clientHello.random, serverHello.random, serverECDHParams) + return rsa.VerifyPKCS1v15(cert.PublicKey.(*rsa.PublicKey), rsa.HashMD5SHA1, md5sha1, sig) + +Error: + return os.ErrorString("invalid ServerKeyExchange") +} + +func (ka *ecdheRSAKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, os.Error) { + if ka.curve == nil { + return nil, nil, os.ErrorString("missing ServerKeyExchange message") + } + priv, mx, my, err := ka.curve.GenerateKey(config.rand()) + if err != nil { + return nil, nil, err + } + x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv) + preMasterSecret := make([]byte, (ka.curve.BitSize+7)>>3) + xBytes := x.Bytes() + copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) + + serialised := ka.curve.Marshal(mx, my) + + ckx := new(clientKeyExchangeMsg) + ckx.ciphertext = make([]byte, 1+len(serialised)) + ckx.ciphertext[0] = byte(len(serialised)) + copy(ckx.ciphertext[1:], serialised) + + return preMasterSecret, ckx, nil +} diff --git a/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py b/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py new file mode 100644 index 000000000..c03eaa6ea --- /dev/null +++ b/src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py @@ -0,0 +1,55 @@ +# Copyright 2010 The Go Authors. All rights reserved. +# Use of this source code is governed by a BSD-style +# license that can be found in the LICENSE file. + +# This code is used to parse the debug log from gnutls-cli and generate a +# script of the handshake. This script is included in handshake_server_test.go. +# See the comments there for details. + +import sys + +blocks = [] + +READ = 1 +WRITE = 2 + +currentBlockType = 0 +currentBlock = [] +for line in sys.stdin.readlines(): + line = line[:-1] + if line.startswith("|<7>| WRITE: "): + if currentBlockType != WRITE: + if len(currentBlock) > 0: + blocks.append(currentBlock) + currentBlock = [] + currentBlockType = WRITE + elif line.startswith("|<7>| READ: "): + if currentBlockType != READ: + if len(currentBlock) > 0: + blocks.append(currentBlock) + currentBlock = [] + currentBlockType = READ + elif line.startswith("|<7>| 0"): + line = line[13:] + line = line.strip() + bs = line.split() + for b in bs: + currentBlock.append(int(b, 16)) + +if len(currentBlock) > 0: + blocks.append(currentBlock) + +for block in blocks: + sys.stdout.write("\t{\n") + + i = 0 + for b in block: + if i % 8 == 0: + sys.stdout.write("\t\t") + sys.stdout.write("0x%02x," % b) + if i % 8 == 7: + sys.stdout.write("\n") + else: + sys.stdout.write(" ") + i += 1 + sys.stdout.write("\n\t},\n\n") diff --git a/src/pkg/crypto/tls/prf.go b/src/pkg/crypto/tls/prf.go index ee6cb780b..478cf65f9 100644 --- a/src/pkg/crypto/tls/prf.go +++ b/src/pkg/crypto/tls/prf.go @@ -20,7 +20,7 @@ func splitPreMasterSecret(secret []byte) (s1, s2 []byte) { } // pHash implements the P_hash function, as defined in RFC 4346, section 5. -func pHash(result, secret, seed []byte, hash hash.Hash) { +func pHash(result, secret, seed []byte, hash func() hash.Hash) { h := hmac.New(hash, secret) h.Write(seed) a := h.Sum() @@ -44,10 +44,10 @@ func pHash(result, secret, seed []byte, hash hash.Hash) { } } -// 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() +// pRF10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, section 5. +func pRF10(result, secret, label, seed []byte) { + hashSHA1 := sha1.New + hashMD5 := md5.New labelAndSeed := make([]byte, len(label)+len(seed)) copy(labelAndSeed, label) @@ -75,25 +75,32 @@ 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 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) { +// secret, given the lengths of the MAC key, cipher key and IV, as defined in +// RFC 2246, section 6.3. +func keysFromPreMasterSecret10(preMasterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (masterSecret, clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) { var seed [tlsRandomLength * 2]byte copy(seed[0:len(clientRandom)], clientRandom) copy(seed[len(clientRandom):], serverRandom) masterSecret = make([]byte, masterSecretLength) - pRF11(masterSecret, preMasterSecret, masterSecretLabel, seed[0:]) + pRF10(masterSecret, preMasterSecret, masterSecretLabel, seed[0:]) copy(seed[0:len(clientRandom)], serverRandom) copy(seed[len(serverRandom):], clientRandom) - n := 2*macLen + 2*keyLen + n := 2*macLen + 2*keyLen + 2*ivLen keyMaterial := make([]byte, n) - pRF11(keyMaterial, masterSecret, keyExpansionLabel, seed[0:]) - clientMAC = keyMaterial[0:macLen] - serverMAC = keyMaterial[macLen : macLen*2] - clientKey = keyMaterial[macLen*2 : macLen*2+keyLen] - serverKey = keyMaterial[macLen*2+keyLen:] + pRF10(keyMaterial, masterSecret, keyExpansionLabel, seed[0:]) + clientMAC = keyMaterial[:macLen] + keyMaterial = keyMaterial[macLen:] + serverMAC = keyMaterial[:macLen] + keyMaterial = keyMaterial[macLen:] + clientKey = keyMaterial[:keyLen] + keyMaterial = keyMaterial[keyLen:] + serverKey = keyMaterial[:keyLen] + keyMaterial = keyMaterial[keyLen:] + clientIV = keyMaterial[:ivLen] + keyMaterial = keyMaterial[ivLen:] + serverIV = keyMaterial[:ivLen] return } @@ -125,7 +132,7 @@ func finishedSum(md5, sha1, label, masterSecret []byte) []byte { copy(seed, md5) copy(seed[len(md5):], sha1) out := make([]byte, finishedVerifyLength) - pRF11(out, masterSecret, label, seed) + pRF10(out, masterSecret, label, seed) return out } diff --git a/src/pkg/crypto/tls/prf_test.go b/src/pkg/crypto/tls/prf_test.go index 5c23f368d..f8c4acb9d 100644 --- a/src/pkg/crypto/tls/prf_test.go +++ b/src/pkg/crypto/tls/prf_test.go @@ -14,11 +14,11 @@ type testSplitPreMasterSecretTest struct { } var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{ - testSplitPreMasterSecretTest{"", "", ""}, - testSplitPreMasterSecretTest{"00", "00", "00"}, - testSplitPreMasterSecretTest{"0011", "00", "11"}, - testSplitPreMasterSecretTest{"001122", "0011", "1122"}, - testSplitPreMasterSecretTest{"00112233", "0011", "2233"}, + {"", "", ""}, + {"00", "00", "00"}, + {"0011", "00", "11"}, + {"001122", "0011", "1122"}, + {"00112233", "0011", "2233"}, } func TestSplitPreMasterSecret(t *testing.T) { @@ -47,7 +47,7 @@ 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 := keysFromPreMasterSecret11(in, clientRandom, serverRandom, test.macLen, test.keyLen) + master, clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromPreMasterSecret10(in, clientRandom, serverRandom, test.macLen, test.keyLen, 0) masterString := hex.EncodeToString(master) clientMACString := hex.EncodeToString(clientMAC) serverMACString := hex.EncodeToString(serverMAC) @@ -65,7 +65,7 @@ func TestKeysFromPreMasterSecret(t *testing.T) { // These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 ` var testKeysFromTests = []testKeysFromTest{ - testKeysFromTest{ + { "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5", "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558", "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db", @@ -77,7 +77,7 @@ var testKeysFromTests = []testKeysFromTest{ 20, 16, }, - testKeysFromTest{ + { "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890", "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106", "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c", @@ -89,7 +89,7 @@ var testKeysFromTests = []testKeysFromTest{ 20, 16, }, - testKeysFromTest{ + { "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1", "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e", "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e", diff --git a/src/pkg/crypto/tls/tls.go b/src/pkg/crypto/tls/tls.go index 1a5da3ac4..b11d3225d 100644 --- a/src/pkg/crypto/tls/tls.go +++ b/src/pkg/crypto/tls/tls.go @@ -6,23 +6,40 @@ package tls import ( - "os" + "crypto/rsa" + "crypto/x509" + "encoding/pem" + "io/ioutil" "net" + "os" + "strings" ) +// Server returns a new TLS server side connection +// using conn as the underlying transport. +// The configuration config must be non-nil and must have +// at least one certificate. func Server(conn net.Conn, config *Config) *Conn { return &Conn{conn: conn, config: config} } +// Client returns a new TLS client side connection +// using conn as the underlying transport. +// Client interprets a nil configuration as equivalent to +// the zero configuration; see the documentation of Config +// for the defaults. func Client(conn net.Conn, config *Config) *Conn { return &Conn{conn: conn, config: config, isClient: true} } +// A Listener implements a network listener (net.Listener) for TLS connections. type Listener struct { listener net.Listener config *Config } +// Accept waits for and returns the next incoming TLS connection. +// The returned connection c is a *tls.Conn. func (l *Listener) Accept() (c net.Conn, err os.Error) { c, err = l.listener.Accept() if err != nil { @@ -32,8 +49,10 @@ func (l *Listener) Accept() (c net.Conn, err os.Error) { return } +// Close closes the listener. func (l *Listener) Close() os.Error { return l.listener.Close() } +// Addr returns the listener's network address. func (l *Listener) Addr() net.Addr { return l.listener.Addr() } // NewListener creates a Listener which accepts connections from an inner @@ -47,7 +66,11 @@ func NewListener(listener net.Listener, config *Config) (l *Listener) { return } -func Listen(network, laddr string, config *Config) (net.Listener, os.Error) { +// Listen creates a TLS listener accepting connections on the +// given network address using net.Listen. +// The configuration config must be non-nil and must have +// at least one certificate. +func Listen(network, laddr string, config *Config) (*Listener, os.Error) { if config == nil || len(config.Certificates) == 0 { return nil, os.NewError("tls.Listen: no certificates in configuration") } @@ -58,10 +81,87 @@ func Listen(network, laddr string, config *Config) (net.Listener, os.Error) { return NewListener(l, config), nil } -func Dial(network, laddr, raddr string) (net.Conn, os.Error) { +// Dial connects to the given network address using net.Dial +// and then initiates a TLS handshake, returning the resulting +// TLS connection. +// Dial interprets a nil configuration as equivalent to +// the zero configuration; see the documentation of Config +// for the defaults. +func Dial(network, laddr, raddr string, config *Config) (*Conn, os.Error) { c, err := net.Dial(network, laddr, raddr) if err != nil { return nil, err } - return Client(c, nil), nil + + colonPos := strings.LastIndex(raddr, ":") + if colonPos == -1 { + colonPos = len(raddr) + } + hostname := raddr[:colonPos] + + if config == nil { + config = defaultConfig() + } + if config.ServerName != "" { + // Make a copy to avoid polluting argument or default. + c := *config + c.ServerName = hostname + config = &c + } + conn := Client(c, config) + if err = conn.Handshake(); err != nil { + c.Close() + return nil, err + } + return conn, nil +} + +// LoadX509KeyPair reads and parses a public/private key pair from a pair of +// files. The files must contain PEM encoded data. +func LoadX509KeyPair(certFile string, keyFile string) (cert Certificate, err os.Error) { + certPEMBlock, err := ioutil.ReadFile(certFile) + if err != nil { + return + } + + certDERBlock, _ := pem.Decode(certPEMBlock) + if certDERBlock == nil { + err = os.ErrorString("crypto/tls: failed to parse certificate PEM data") + return + } + + cert.Certificate = [][]byte{certDERBlock.Bytes} + + keyPEMBlock, err := ioutil.ReadFile(keyFile) + if err != nil { + return + } + + keyDERBlock, _ := pem.Decode(keyPEMBlock) + if keyDERBlock == nil { + err = os.ErrorString("crypto/tls: failed to parse key PEM data") + return + } + + key, err := x509.ParsePKCS1PrivateKey(keyDERBlock.Bytes) + if err != nil { + err = os.ErrorString("crypto/tls: failed to parse key") + return + } + + cert.PrivateKey = key + + // We don't need to parse the public key for TLS, but we so do anyway + // to check that it looks sane and matches the private key. + x509Cert, err := x509.ParseCertificate(certDERBlock.Bytes) + if err != nil { + return + } + + if x509Cert.PublicKeyAlgorithm != x509.RSA || x509Cert.PublicKey.(*rsa.PublicKey).N.Cmp(key.PublicKey.N) != 0 { + err = os.ErrorString("crypto/tls: private key does not match public key") + return + } + + return } |