summaryrefslogtreecommitdiff
path: root/src/pkg/crypto/tls/handshake_client.go
diff options
context:
space:
mode:
authorOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
committerOndřej Surý <ondrej@sury.org>2011-01-17 12:40:45 +0100
commit3e45412327a2654a77944249962b3652e6142299 (patch)
treebc3bf69452afa055423cbe0c5cfa8ca357df6ccf /src/pkg/crypto/tls/handshake_client.go
parentc533680039762cacbc37db8dc7eed074c3e497be (diff)
downloadgolang-upstream/2011.01.12.tar.gz
Imported Upstream version 2011.01.12upstream/2011.01.12
Diffstat (limited to 'src/pkg/crypto/tls/handshake_client.go')
-rw-r--r--src/pkg/crypto/tls/handshake_client.go215
1 files changed, 171 insertions, 44 deletions
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
}