mirror of
https://github.com/golang/go
synced 2024-11-25 08:07:57 -07:00
crypto/tls: add ECDHE support
(ECDHE is "Elliptic Curve Diffie Hellman Ephemeral") R=rsc CC=golang-dev https://golang.org/cl/3668042
This commit is contained in:
parent
2e8be52ff7
commit
4883b73982
@ -130,6 +130,9 @@ func nonZeroRandomBytes(s []byte, rand io.Reader) (err os.Error) {
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
// In tests, the PRNG may return all zeros so we do
|
||||
// this to break the loop.
|
||||
s[i] ^= 0x42
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -14,6 +14,7 @@ GOFILES=\
|
||||
handshake_client.go\
|
||||
handshake_messages.go\
|
||||
handshake_server.go\
|
||||
key_agreement.go\
|
||||
prf.go\
|
||||
tls.go\
|
||||
|
||||
|
@ -9,9 +9,30 @@ import (
|
||||
"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 {
|
||||
@ -19,13 +40,20 @@ type cipherSuite struct {
|
||||
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, cipherRC4, hmacSHA1},
|
||||
TLS_RSA_WITH_AES_128_CBC_SHA: &cipherSuite{16, 20, 16, cipherAES, hmacSHA1},
|
||||
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{} {
|
||||
@ -45,6 +73,14 @@ 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) {
|
||||
@ -61,4 +97,6 @@ func mutualCipherSuite(have []uint16, want uint16) (suite *cipherSuite, id uint1
|
||||
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
|
||||
)
|
||||
|
@ -38,6 +38,7 @@ const (
|
||||
typeClientHello uint8 = 1
|
||||
typeServerHello uint8 = 2
|
||||
typeCertificate uint8 = 11
|
||||
typeServerKeyExchange uint8 = 12
|
||||
typeCertificateRequest uint8 = 13
|
||||
typeServerHelloDone uint8 = 14
|
||||
typeCertificateVerify uint8 = 15
|
||||
@ -56,9 +57,25 @@ const (
|
||||
var (
|
||||
extensionServerName uint16 = 0
|
||||
extensionStatusRequest uint16 = 5
|
||||
extensionSupportedCurves uint16 = 10
|
||||
extensionSupportedPoints uint16 = 11
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
)
|
||||
|
||||
// TLS Elliptic Curves
|
||||
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8
|
||||
var (
|
||||
curveP256 uint16 = 23
|
||||
curveP384 uint16 = 24
|
||||
curveP521 uint16 = 25
|
||||
)
|
||||
|
||||
// TLS Elliptic Curve Point Formats
|
||||
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
|
||||
var (
|
||||
pointFormatUncompressed uint8 = 0
|
||||
)
|
||||
|
||||
// TLS CertificateStatusType (RFC 3546)
|
||||
const (
|
||||
statusTypeOCSP uint8 = 1
|
||||
|
@ -651,6 +651,8 @@ func (c *Conn) readHandshake() (interface{}, os.Error) {
|
||||
m = new(certificateRequestMsg)
|
||||
case typeCertificateStatus:
|
||||
m = new(certificateStatusMsg)
|
||||
case typeServerKeyExchange:
|
||||
m = new(serverKeyExchangeMsg)
|
||||
case typeServerHelloDone:
|
||||
m = new(serverHelloDoneMsg)
|
||||
case typeClientKeyExchange:
|
||||
|
@ -26,6 +26,8 @@ func (c *Conn) clientHandshake() os.Error {
|
||||
random: make([]byte, 32),
|
||||
ocspStapling: true,
|
||||
serverName: c.config.ServerName,
|
||||
supportedCurves: []uint16{curveP256, curveP384, curveP521},
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
}
|
||||
|
||||
t := uint32(c.config.time())
|
||||
@ -130,8 +132,7 @@ func (c *Conn) clientHandshake() os.Error {
|
||||
cur = parent
|
||||
}
|
||||
|
||||
pub, ok := certs[0].PublicKey.(*rsa.PublicKey)
|
||||
if !ok {
|
||||
if _, ok := certs[0].PublicKey.(*rsa.PublicKey); !ok {
|
||||
return c.sendAlert(alertUnsupportedCertificate)
|
||||
}
|
||||
|
||||
@ -158,6 +159,23 @@ func (c *Conn) clientHandshake() os.Error {
|
||||
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 {
|
||||
@ -215,22 +233,15 @@ func (c *Conn) clientHandshake() os.Error {
|
||||
c.writeRecord(recordTypeHandshake, certMsg.marshal())
|
||||
}
|
||||
|
||||
ckx := new(clientKeyExchangeMsg)
|
||||
preMasterSecret := make([]byte, 48)
|
||||
preMasterSecret[0] = byte(hello.vers >> 8)
|
||||
preMasterSecret[1] = byte(hello.vers)
|
||||
_, err = io.ReadFull(c.config.rand(), preMasterSecret[2:])
|
||||
preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hello, certs[0])
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
c.sendAlert(alertInternalError)
|
||||
return err
|
||||
}
|
||||
|
||||
ckx.ciphertext, err = rsa.EncryptPKCS1v15(c.config.rand(), pub, preMasterSecret)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
}
|
||||
|
||||
if ckx != nil {
|
||||
finishedHash.Write(ckx.marshal())
|
||||
c.writeRecord(recordTypeHandshake, ckx.marshal())
|
||||
}
|
||||
|
||||
if cert != nil {
|
||||
certVerify := new(certificateVerifyMsg)
|
||||
|
211
src/pkg/crypto/tls/handshake_client_test.go
Normal file
211
src/pkg/crypto/tls/handshake_client_test.go
Normal file
@ -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,
|
||||
},
|
||||
}
|
@ -14,6 +14,8 @@ type clientHelloMsg struct {
|
||||
nextProtoNeg bool
|
||||
serverName string
|
||||
ocspStapling bool
|
||||
supportedCurves []uint16
|
||||
supportedPoints []uint8
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) marshal() []byte {
|
||||
@ -35,6 +37,14 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
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
|
||||
@ -117,6 +127,38 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
// 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
|
||||
|
||||
@ -221,6 +263,33 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
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:]
|
||||
}
|
||||
@ -466,6 +535,36 @@ 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
|
||||
@ -542,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
|
||||
@ -558,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
|
||||
}
|
||||
|
||||
|
@ -115,6 +115,11 @@ func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
|
||||
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)
|
||||
}
|
||||
|
@ -34,12 +34,37 @@ func (c *Conn) serverHandshake() os.Error {
|
||||
|
||||
hello := new(serverHelloMsg)
|
||||
|
||||
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 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
|
||||
}
|
||||
@ -89,6 +114,18 @@ 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)
|
||||
@ -185,23 +222,12 @@ func (c *Conn) serverHandshake() os.Error {
|
||||
finishedHash.Write(certVerify.marshal())
|
||||
}
|
||||
|
||||
preMasterSecret := make([]byte, 48)
|
||||
_, err = io.ReadFull(config.rand(), preMasterSecret[2:])
|
||||
preMasterSecret, err := keyAgreement.processClientKeyExchange(config, ckx)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertInternalError)
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return err
|
||||
}
|
||||
|
||||
err = rsa.DecryptPKCS1v15SessionKey(config.rand(), config.Certificates[0].PrivateKey, ckx.ciphertext, preMasterSecret)
|
||||
if err != nil {
|
||||
return c.sendAlert(alertHandshakeFailure)
|
||||
}
|
||||
// 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, clientIV, serverIV :=
|
||||
keysFromPreMasterSecret10(preMasterSecret, clientHello.random, hello.random, suite.macLen, suite.keyLen, suite.ivLen)
|
||||
|
||||
|
246
src/pkg/crypto/tls/key_agreement.go
Normal file
246
src/pkg/crypto/tls/key_agreement.go
Normal file
@ -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
|
||||
}
|
Loading…
Reference in New Issue
Block a user