diff options
Diffstat (limited to 'src/ssl/test/runner/key_agreement.go')
-rw-r--r-- | src/ssl/test/runner/key_agreement.go | 207 |
1 files changed, 144 insertions, 63 deletions
diff --git a/src/ssl/test/runner/key_agreement.go b/src/ssl/test/runner/key_agreement.go index 3a9b899..4f399d9 100644 --- a/src/ssl/test/runner/key_agreement.go +++ b/src/ssl/test/runner/key_agreement.go @@ -12,11 +12,15 @@ import ( "crypto/rand" "crypto/rsa" "crypto/sha1" + "crypto/subtle" "crypto/x509" "encoding/asn1" "errors" + "fmt" "io" "math/big" + + "./curve25519" ) var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message") @@ -137,10 +141,11 @@ func (ka *rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello } func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) { + bad := config.Bugs.BadRSAClientKeyExchange preMasterSecret := make([]byte, 48) vers := clientHello.vers - if config.Bugs.RsaClientKeyExchangeVersion != 0 { - vers = config.Bugs.RsaClientKeyExchangeVersion + if bad == RSABadValueWrongVersion { + vers ^= 1 } vers = versionToWire(vers, clientHello.isDTLS) preMasterSecret[0] = byte(vers >> 8) @@ -150,12 +155,25 @@ func (ka *rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello return nil, nil, err } - encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), preMasterSecret) + sentPreMasterSecret := preMasterSecret + if bad == RSABadValueTooLong { + sentPreMasterSecret = make([]byte, len(sentPreMasterSecret)+1) + copy(sentPreMasterSecret, preMasterSecret) + } else if bad == RSABadValueTooShort { + sentPreMasterSecret = sentPreMasterSecret[:len(sentPreMasterSecret)-1] + } + + encrypted, err := rsa.EncryptPKCS1v15(config.rand(), cert.PublicKey.(*rsa.PublicKey), sentPreMasterSecret) if err != nil { return nil, nil, err } + if bad == RSABadValueCorrupt { + encrypted[len(encrypted)-1] ^= 1 + // Clear the high byte to ensure |encrypted| is still below the RSA modulus. + encrypted[0] = 0 + } ckx := new(clientKeyExchangeMsg) - if clientHello.vers != VersionSSL30 && !config.Bugs.SSL3RSAKeyExchange { + if clientHello.vers != VersionSSL30 { ckx.ciphertext = make([]byte, len(encrypted)+2) ckx.ciphertext[0] = byte(len(encrypted) >> 8) ckx.ciphertext[1] = byte(len(encrypted)) @@ -232,16 +250,90 @@ func pickTLS12HashForSignature(sigType uint8, clientList, serverList []signature return 0, errors.New("tls: client doesn't support any common hash functions") } -func curveForCurveID(id CurveID) (elliptic.Curve, bool) { +// A ecdhCurve is an instance of ECDH-style key agreement for TLS. +type ecdhCurve interface { + // generateKeypair generates a keypair using rand. It returns the + // encoded public key. + generateKeypair(rand io.Reader) (publicKey []byte, err error) + + // computeSecret performs a key exchange against peerKey and returns + // the resulting shared secret. + computeSecret(peerKey []byte) (preMasterSecret []byte, err error) +} + +// ellipticECDHCurve implements ecdhCurve with an elliptic.Curve. +type ellipticECDHCurve struct { + curve elliptic.Curve + privateKey []byte +} + +func (e *ellipticECDHCurve) generateKeypair(rand io.Reader) (publicKey []byte, err error) { + var x, y *big.Int + e.privateKey, x, y, err = elliptic.GenerateKey(e.curve, rand) + if err != nil { + return nil, err + } + return elliptic.Marshal(e.curve, x, y), nil +} + +func (e *ellipticECDHCurve) computeSecret(peerKey []byte) (preMasterSecret []byte, err error) { + x, y := elliptic.Unmarshal(e.curve, peerKey) + if x == nil { + return nil, errors.New("tls: invalid peer key") + } + x, _ = e.curve.ScalarMult(x, y, e.privateKey) + preMasterSecret = make([]byte, (e.curve.Params().BitSize+7)>>3) + xBytes := x.Bytes() + copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) + + return preMasterSecret, nil +} + +// x25519ECDHCurve implements ecdhCurve with X25519. +type x25519ECDHCurve struct { + privateKey [32]byte +} + +func (e *x25519ECDHCurve) generateKeypair(rand io.Reader) (publicKey []byte, err error) { + _, err = io.ReadFull(rand, e.privateKey[:]) + if err != nil { + return + } + var out [32]byte + curve25519.ScalarBaseMult(&out, &e.privateKey) + return out[:], nil +} + +func (e *x25519ECDHCurve) computeSecret(peerKey []byte) (preMasterSecret []byte, err error) { + if len(peerKey) != 32 { + return nil, errors.New("tls: invalid peer key") + } + var out, peerKeyCopy [32]byte + copy(peerKeyCopy[:], peerKey) + curve25519.ScalarMult(&out, &e.privateKey, &peerKeyCopy) + + // Per draft-irtf-cfrg-curves-11, reject the all-zero value in constant + // time. + var zeros [32]byte + if subtle.ConstantTimeCompare(zeros[:], out[:]) == 1 { + return nil, errors.New("tls: X25519 value with wrong order") + } + + return out[:], nil +} + +func curveForCurveID(id CurveID) (ecdhCurve, bool) { switch id { case CurveP224: - return elliptic.P224(), true + return &ellipticECDHCurve{curve: elliptic.P224()}, true case CurveP256: - return elliptic.P256(), true + return &ellipticECDHCurve{curve: elliptic.P256()}, true case CurveP384: - return elliptic.P384(), true + return &ellipticECDHCurve{curve: elliptic.P384()}, true case CurveP521: - return elliptic.P521(), true + return &ellipticECDHCurve{curve: elliptic.P521()}, true + case CurveX25519: + return &x25519ECDHCurve{}, true default: return nil, false } @@ -269,6 +361,24 @@ func (ka *nilKeyAgreementAuthentication) verifyParameters(config *Config, client return nil } +func maybeCorruptECDSAValue(n *big.Int, typeOfCorruption BadValue, limit *big.Int) *big.Int { + switch typeOfCorruption { + case BadValueNone: + return n + case BadValueNegative: + return new(big.Int).Neg(n) + case BadValueZero: + return big.NewInt(0) + case BadValueLimit: + return limit + case BadValueLarge: + bad := new(big.Int).Set(limit) + return bad.Lsh(bad, 20) + default: + panic("unknown BadValue type") + } +} + // signedKeyAgreement signs the ServerKeyExchange parameters with the // server's private key. type signedKeyAgreement struct { @@ -414,28 +524,9 @@ func (ka *signedKeyAgreement) verifyParameters(config *Config, clientHello *clie // pre-master secret is then calculated using ECDH. The signature may // either be ECDSA or RSA. type ecdheKeyAgreement struct { - auth keyAgreementAuthentication - privateKey []byte - curve elliptic.Curve - x, y *big.Int -} - -func maybeCorruptECDSAValue(n *big.Int, typeOfCorruption BadValue, limit *big.Int) *big.Int { - switch typeOfCorruption { - case BadValueNone: - return n - case BadValueNegative: - return new(big.Int).Neg(n) - case BadValueZero: - return big.NewInt(0) - case BadValueLimit: - return limit - case BadValueLarge: - bad := new(big.Int).Set(limit) - return bad.Lsh(bad, 20) - default: - panic("unknown BadValue type") - } + auth keyAgreementAuthentication + curve ecdhCurve + peerKey []byte } func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) { @@ -461,24 +552,21 @@ NextCandidate: return nil, errors.New("tls: preferredCurves includes unsupported curve") } - var x, y *big.Int - var err error - ka.privateKey, x, y, err = elliptic.GenerateKey(ka.curve, config.rand()) + publicKey, err := ka.curve.generateKeypair(config.rand()) if err != nil { return nil, err } - ecdhePublic := elliptic.Marshal(ka.curve, x, y) // http://tools.ietf.org/html/rfc4492#section-5.4 - serverECDHParams := make([]byte, 1+2+1+len(ecdhePublic)) + serverECDHParams := make([]byte, 1+2+1+len(publicKey)) serverECDHParams[0] = 3 // named curve serverECDHParams[1] = byte(curveid >> 8) serverECDHParams[2] = byte(curveid) if config.Bugs.InvalidSKXCurve { serverECDHParams[2] ^= 0xff } - serverECDHParams[3] = byte(len(ecdhePublic)) - copy(serverECDHParams[4:], ecdhePublic) + serverECDHParams[3] = byte(len(publicKey)) + copy(serverECDHParams[4:], publicKey) return ka.auth.signParameters(config, cert, clientHello, hello, serverECDHParams) } @@ -487,16 +575,7 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 { return nil, errClientKeyExchange } - x, y := elliptic.Unmarshal(ka.curve, ckx.ciphertext[1:]) - if x == nil { - return nil, errClientKeyExchange - } - x, _ = ka.curve.ScalarMult(x, y, ka.privateKey) - preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) - xBytes := x.Bytes() - copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) - - return preMasterSecret, nil + return ka.curve.computeSecret(ckx.ciphertext[1:]) } func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error { @@ -517,13 +596,12 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell if publicLen+4 > len(skx.key) { return errServerKeyExchange } - ka.x, ka.y = elliptic.Unmarshal(ka.curve, skx.key[4:4+publicLen]) - if ka.x == nil { - return errServerKeyExchange - } + // Save the peer key for later. + ka.peerKey = skx.key[4 : 4+publicLen] + + // Check the signature. serverECDHParams := skx.key[:4+publicLen] sig := skx.key[4+publicLen:] - return ka.auth.verifyParameters(config, clientHello, serverHello, cert, serverECDHParams, sig) } @@ -531,21 +609,20 @@ func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHel if ka.curve == nil { return nil, nil, errors.New("missing ServerKeyExchange message") } - priv, mx, my, err := elliptic.GenerateKey(ka.curve, config.rand()) + + publicKey, err := ka.curve.generateKeypair(config.rand()) + if err != nil { + return nil, nil, err + } + preMasterSecret, err := ka.curve.computeSecret(ka.peerKey) if err != nil { return nil, nil, err } - x, _ := ka.curve.ScalarMult(ka.x, ka.y, priv) - preMasterSecret := make([]byte, (ka.curve.Params().BitSize+7)>>3) - xBytes := x.Bytes() - copy(preMasterSecret[len(preMasterSecret)-len(xBytes):], xBytes) - - serialized := elliptic.Marshal(ka.curve, mx, my) ckx := new(clientKeyExchangeMsg) - ckx.ciphertext = make([]byte, 1+len(serialized)) - ckx.ciphertext[0] = byte(len(serialized)) - copy(ckx.ciphertext[1:], serialized) + ckx.ciphertext = make([]byte, 1+len(publicKey)) + ckx.ciphertext[0] = byte(len(publicKey)) + copy(ckx.ciphertext[1:], publicKey) return preMasterSecret, ckx, nil } @@ -652,6 +729,10 @@ func (ka *dheKeyAgreement) processServerKeyExchange(config *Config, clientHello return errServerKeyExchange } + if l := config.Bugs.RequireDHPublicValueLen; l != 0 && l != yLen { + return fmt.Errorf("RequireDHPublicValueLen set to %d, but server's public value was %d bytes on the wire and %d bytes if minimal", l, yLen, (ka.yTheirs.BitLen()+7)/8) + } + sig := k serverDHParams := skx.key[:len(skx.key)-len(sig)] |