summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/tls
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/crypto/tls')
-rw-r--r--src/pkg/crypto/tls/Makefile4
-rw-r--r--src/pkg/crypto/tls/ca_set.go50
-rw-r--r--src/pkg/crypto/tls/cipher_suites.go102
-rw-r--r--src/pkg/crypto/tls/common.go176
-rw-r--r--src/pkg/crypto/tls/conn.go232
-rw-r--r--src/pkg/crypto/tls/conn_test.go52
-rw-r--r--src/pkg/crypto/tls/generate_cert.go70
-rw-r--r--src/pkg/crypto/tls/handshake_client.go215
-rw-r--r--src/pkg/crypto/tls/handshake_client_test.go211
-rw-r--r--src/pkg/crypto/tls/handshake_messages.go367
-rw-r--r--src/pkg/crypto/tls/handshake_messages_test.go37
-rw-r--r--src/pkg/crypto/tls/handshake_server.go189
-rw-r--r--src/pkg/crypto/tls/handshake_server_test.go443
-rw-r--r--src/pkg/crypto/tls/key_agreement.go246
-rw-r--r--src/pkg/crypto/tls/parse-gnutls-cli-debug-log.py55
-rw-r--r--src/pkg/crypto/tls/prf.go39
-rw-r--r--src/pkg/crypto/tls/prf_test.go18
-rw-r--r--src/pkg/crypto/tls/tls.go108
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
}