From 7be849d4a6bb8771ac2914e9166a8e10c7d7300c Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Wed, 21 Jul 2010 11:36:01 -0400 Subject: [PATCH] crypto/tls: add client-side SNI support and PeerCertificates. SNI (Server Name Indication) is a way for a TLS client to indicate to the server which name it knows the server by. This allows the server to have several names and return the correct certificate for each (virtual hosting). PeerCertificates returns the list of certificates presented by server. R=r CC=golang-dev https://golang.org/cl/1741053 --- src/pkg/crypto/tls/common.go | 3 +++ src/pkg/crypto/tls/conn.go | 11 +++++++++++ src/pkg/crypto/tls/handshake_client.go | 3 +++ src/pkg/crypto/tls/handshake_messages.go | 3 ++- 4 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/pkg/crypto/tls/common.go b/src/pkg/crypto/tls/common.go index 7c6940aa32b..717ae0a8153 100644 --- a/src/pkg/crypto/tls/common.go +++ b/src/pkg/crypto/tls/common.go @@ -85,6 +85,9 @@ type Config struct { // 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 } type Certificate struct { diff --git a/src/pkg/crypto/tls/conn.go b/src/pkg/crypto/tls/conn.go index aa224e49d22..7f5d97d4be9 100644 --- a/src/pkg/crypto/tls/conn.go +++ b/src/pkg/crypto/tls/conn.go @@ -5,6 +5,7 @@ package tls import ( "bytes" "crypto/subtle" + "crypto/x509" "hash" "io" "net" @@ -27,6 +28,7 @@ type Conn struct { handshakeComplete bool cipherSuite uint16 ocspResponse []byte // stapled OCSP response + peerCertificates []*x509.Certificate clientProtocol string @@ -651,3 +653,12 @@ func (c *Conn) OCSPResponse() []byte { 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 +} diff --git a/src/pkg/crypto/tls/handshake_client.go b/src/pkg/crypto/tls/handshake_client.go index b3b597327fc..324c02f701c 100644 --- a/src/pkg/crypto/tls/handshake_client.go +++ b/src/pkg/crypto/tls/handshake_client.go @@ -28,6 +28,7 @@ func (c *Conn) clientHandshake() os.Error { compressionMethods: []uint8{compressionNone}, random: make([]byte, 32), ocspStapling: true, + serverName: c.config.ServerName, } t := uint32(c.config.Time()) @@ -107,6 +108,8 @@ func (c *Conn) clientHandshake() os.Error { return c.sendAlert(alertUnsupportedCertificate) } + c.peerCertificates = certs + if serverHello.certStatus { msg, err = c.readHandshake() if err != nil { diff --git a/src/pkg/crypto/tls/handshake_messages.go b/src/pkg/crypto/tls/handshake_messages.go index 13c05fe574d..6d4e5c70944 100644 --- a/src/pkg/crypto/tls/handshake_messages.go +++ b/src/pkg/crypto/tls/handshake_messages.go @@ -100,7 +100,8 @@ 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))