Created
May 15, 2010 23:11
-
-
Save mkrautz/402489 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
rsa/pkcs1v15.go | 5 ++ | |
tls/common.go | 25 +++++++++---- | |
tls/conn.go | 6 +++ | |
tls/handshake_messages.go | 87 ++++++++++++++++++++++++++++++++++++++++++++++ | |
tls/handshake_server.go | 59 +++++++++++++++++++++++++++++++ | |
5 files changed, 175 insertions(+), 7 deletions(-) | |
diff -r 17ded5ad443b src/pkg/crypto/rsa/pkcs1v15.go | |
--- a/src/pkg/crypto/rsa/pkcs1v15.go Wed May 05 12:12:04 2010 +1000 | |
+++ b/src/pkg/crypto/rsa/pkcs1v15.go Sun May 16 01:00:17 2010 +0200 | |
@@ -146,6 +146,7 @@ | |
HashSHA256 | |
HashSHA384 | |
HashSHA512 | |
+ HashMD5SHA1 | |
) | |
// These are ASN1 DER structures: | |
@@ -167,6 +168,8 @@ | |
[]byte{0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30}, | |
// HashSHA512 | |
[]byte{0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40}, | |
+ // HashMD5SHA1 | |
+ []byte{}, | |
} | |
// SignPKCS1v15 calcuates the signature of hashed using RSASSA-PSS-SIGN from RSA PKCS#1 v1.5. | |
@@ -252,6 +255,8 @@ | |
hashLen = 48 | |
case HashSHA512: | |
hashLen = 64 | |
+ case HashMD5SHA1: | |
+ hashLen = 36 | |
default: | |
return 0, nil, os.ErrorString("unknown hash function") | |
} | |
diff -r 17ded5ad443b src/pkg/crypto/tls/common.go | |
--- a/src/pkg/crypto/tls/common.go Wed May 05 12:12:04 2010 +1000 | |
+++ b/src/pkg/crypto/tls/common.go Sun May 16 01:00:17 2010 +0200 | |
@@ -35,13 +35,15 @@ | |
// 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 | |
+ typeCertificateRequest uint8 = 13 | |
+ typeServerHelloDone uint8 = 14 | |
+ typeCertificateVerify uint8 = 15 | |
+ typeClientKeyExchange uint8 = 16 | |
+ typeFinished uint8 = 20 | |
+ typeNextProtocol uint8 = 67 // Not IANA assigned | |
) | |
// TLS cipher suites. | |
@@ -60,6 +62,15 @@ | |
extensionNextProtoNeg uint16 = 13172 // not IANA assigned | |
) | |
+// 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 | |
+) | |
+ | |
type ConnectionState struct { | |
HandshakeComplete bool | |
CipherSuite string | |
diff -r 17ded5ad443b src/pkg/crypto/tls/conn.go | |
--- a/src/pkg/crypto/tls/conn.go Wed May 05 12:12:04 2010 +1000 | |
+++ b/src/pkg/crypto/tls/conn.go Sun May 16 01:00:17 2010 +0200 | |
@@ -5,6 +5,7 @@ | |
import ( | |
"bytes" | |
"crypto/subtle" | |
+ "crypto/x509" | |
"hash" | |
"io" | |
"net" | |
@@ -40,6 +41,9 @@ | |
hand bytes.Buffer // handshake data waiting to be read | |
tmp [16]byte | |
+ | |
+ // The certificate of the client (if any). | |
+ Certificate *x509.Certificate | |
} | |
func (c *Conn) setError(err os.Error) os.Error { | |
@@ -535,6 +539,8 @@ | |
m = new(serverHelloDoneMsg) | |
case typeClientKeyExchange: | |
m = new(clientKeyExchangeMsg) | |
+ case typeCertificateVerify: | |
+ m = new(certificateVerifyMsg) | |
case typeNextProtocol: | |
m = new(nextProtoMsg) | |
case typeFinished: | |
diff -r 17ded5ad443b src/pkg/crypto/tls/handshake_messages.go | |
--- a/src/pkg/crypto/tls/handshake_messages.go Wed May 05 12:12:04 2010 +1000 | |
+++ b/src/pkg/crypto/tls/handshake_messages.go Sun May 16 01:00:17 2010 +0200 | |
@@ -579,3 +579,90 @@ | |
return true | |
} | |
+ | |
+type certificateRequestMsg struct { | |
+ raw []byte | |
+ certificateTypes []byte | |
+ certificateAuthorities [][]byte | |
+} | |
+ | |
+func (m *certificateRequestMsg) marshal() (x []byte) { | |
+ if m.raw != nil { | |
+ return m.raw | |
+ } | |
+ | |
+ var i int | |
+ for _, slice := range m.certificateAuthorities { | |
+ i += len(slice) | |
+ } | |
+ | |
+ caOctets := 2*len(m.certificateAuthorities) + i | |
+ length := 1 + len(m.certificateTypes) + 2 + caOctets | |
+ | |
+ 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)) | |
+ | |
+ y := x[5:] | |
+ for i, octet := range m.certificateTypes { | |
+ y[i] = octet | |
+ } | |
+ | |
+ // Ignore certificateAuthorities for now... | |
+ | |
+ m.raw = x | |
+ | |
+ return | |
+} | |
+ | |
+func (m *certificateRequestMsg) unmarshal() (x []byte) { | |
+ return | |
+} | |
+ | |
+type certificateVerifyMsg struct { | |
+ raw []byte | |
+ signature []byte | |
+} | |
+ | |
+func (m *certificateVerifyMsg) marshal() (x []byte) { | |
+ if m.raw != nil { | |
+ return m.raw | |
+ } | |
+ | |
+ 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 | |
+ | |
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3]) | |
+ if uint32(len(data)-4) != length { | |
+ return false | |
+ } | |
+ | |
+ siglength := uint32(data[4])<<8 + uint32(data[5]) | |
+ if uint32(len(data)-6) != siglength { | |
+ return false | |
+ } | |
+ | |
+ m.signature = data[6:] | |
+ | |
+ return true | |
+} | |
diff -r 17ded5ad443b src/pkg/crypto/tls/handshake_server.go | |
--- a/src/pkg/crypto/tls/handshake_server.go Wed May 05 12:12:04 2010 +1000 | |
+++ b/src/pkg/crypto/tls/handshake_server.go Sun May 16 01:00:17 2010 +0200 | |
@@ -18,6 +18,7 @@ | |
"crypto/rsa" | |
"crypto/sha1" | |
"crypto/subtle" | |
+ "crypto/x509" | |
"io" | |
"os" | |
) | |
@@ -112,10 +113,43 @@ | |
finishedHash.Write(certMsg.marshal()) | |
c.writeRecord(recordTypeHandshake, certMsg.marshal()) | |
+ // Request a client certificate | |
+ certReq := new(certificateRequestMsg) | |
+ certReq.certificateTypes = []byte{certTypeRSASign} | |
+ | |
+ finishedHash.Write(certReq.marshal()) | |
+ c.writeRecord(recordTypeHandshake, certReq.marshal()) | |
+ | |
helloDone := new(serverHelloDoneMsg) | |
finishedHash.Write(helloDone.marshal()) | |
c.writeRecord(recordTypeHandshake, helloDone.marshal()) | |
+ // 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()) | |
+ | |
+ var pub *rsa.PublicKey | |
+ | |
+ // Check if the client sent a certificate in response to our | |
+ // certificate request. It may choose not to. | |
+ if len(certMsg.certificates) > 0 { | |
+ c.Certificate, err = x509.ParseCertificate(certMsg.certificates[0]) | |
+ if c.Certificate.PublicKeyAlgorithm == x509.RSA { | |
+ pub = c.Certificate.PublicKey.(*rsa.PublicKey) | |
+ } | |
+ if pub == nil { | |
+ return c.sendAlert(alertBadCertificate) | |
+ } | |
+ } | |
+ | |
+ // Get client key exchange | |
msg, err = c.readHandshake() | |
if err != nil { | |
return err | |
@@ -126,6 +160,31 @@ | |
} | |
finishedHash.Write(ckx.marshal()) | |
+ // If we received a client cert in response to our | |
+ // certificate request message, the client will send | |
+ // us a certificate verify message immediately after | |
+ // the the client key exchange message. | |
+ if c.Certificate != nil { | |
+ 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 { | |
+ return c.sendAlert(alertBadCertificate) | |
+ } | |
+ | |
+ finishedHash.Write(certVerify.marshal()) | |
+ } | |
+ | |
preMasterSecret := make([]byte, 48) | |
_, err = io.ReadFull(config.Rand, preMasterSecret[2:]) | |
if err != nil { |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment