Skip to content

Instantly share code, notes, and snippets.

@mkrautz
Created May 15, 2010 23:11
Show Gist options
  • Save mkrautz/402489 to your computer and use it in GitHub Desktop.
Save mkrautz/402489 to your computer and use it in GitHub Desktop.
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