crypto/ecdh: new package

We use crypto/internal/edwards25519/field to implement X25519 directly,
so that golang.org/x/crypto/curve25519 can be dropped from the src
module dependencies, and eventually replaced with a crypto/ecdh wrapper,
removing the need to keep golang.org/x/crypto/curve25519/internal/field
in sync with crypto/internal/edwards25519/field.

In crypto/internal/nistec, we add BytesX to serialize only the x
coordinate, which we'll need for the horrible ECDSA x-coord-to-scalar
operation, too.

In crypto/tls, we replace the ECDHE implementation with crypto/ecdh,
dropping the X25519 special cases and related scaffolding.

Finally, FINALLY, we deprecate the ~white whale~ big.Int-based APIs of
the crypto/elliptic package.   •_•)   ( •_•)>⌐■-■   (⌐■_■)

Fixes #52182
Fixes #34648
Fixes #52221

Change-Id: Iccdda210319cc892e96bb28a0e7b7123551982c7
Reviewed-on: https://go-review.googlesource.com/c/go/+/398914
Reviewed-by: Fernando Lobato Meeser <felobato@google.com>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Filippo Valsorda 2022-04-07 15:15:31 -04:00
parent 8011ffeccb
commit f80ca9c941
6 changed files with 85 additions and 121 deletions

View file

@ -6,6 +6,7 @@ package tls
import (
"crypto"
"crypto/ecdh"
"crypto/md5"
"crypto/rsa"
"crypto/sha1"
@ -157,7 +158,7 @@ func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint1
type ecdheKeyAgreement struct {
version uint16
isRSA bool
params ecdheParameters
key *ecdh.PrivateKey
// ckx and preMasterSecret are generated in processServerKeyExchange
// and returned in generateClientKeyExchange.
@ -177,18 +178,18 @@ func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Cer
if curveID == 0 {
return nil, errors.New("tls: no supported elliptic curves offered")
}
if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
if _, ok := curveForCurveID(curveID); !ok {
return nil, errors.New("tls: CurvePreferences includes unsupported curve")
}
params, err := generateECDHEParameters(config.rand(), curveID)
key, err := generateECDHEKey(config.rand(), curveID)
if err != nil {
return nil, err
}
ka.params = params
ka.key = key
// See RFC 4492, Section 5.4.
ecdhePublic := params.PublicKey()
ecdhePublic := key.PublicKey().Bytes()
serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
serverECDHEParams[0] = 3 // named curve
serverECDHEParams[1] = byte(curveID >> 8)
@ -259,8 +260,12 @@ func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Cert
return nil, errClientKeyExchange
}
preMasterSecret := ka.params.SharedKey(ckx.ciphertext[1:])
if preMasterSecret == nil {
peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:])
if err != nil {
return nil, errClientKeyExchange
}
preMasterSecret, err := ka.key.Curve().ECDH(ka.key, peerKey)
if err != nil {
return nil, errClientKeyExchange
}
@ -288,22 +293,26 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
return errServerKeyExchange
}
if _, ok := curveForCurveID(curveID); curveID != X25519 && !ok {
if _, ok := curveForCurveID(curveID); !ok {
return errors.New("tls: server selected unsupported curve")
}
params, err := generateECDHEParameters(config.rand(), curveID)
key, err := generateECDHEKey(config.rand(), curveID)
if err != nil {
return err
}
ka.params = params
ka.key = key
ka.preMasterSecret = params.SharedKey(publicKey)
if ka.preMasterSecret == nil {
peerKey, err := key.Curve().NewPublicKey(publicKey)
if err != nil {
return errServerKeyExchange
}
ka.preMasterSecret, err = key.Curve().ECDH(key, peerKey)
if err != nil {
return errServerKeyExchange
}
ourPublicKey := params.PublicKey()
ourPublicKey := key.PublicKey().Bytes()
ka.ckx = new(clientKeyExchangeMsg)
ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey))
ka.ckx.ciphertext[0] = byte(len(ourPublicKey))