mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-03 20:17:36 +03:00
* sync: Go 1.21rc3, QUIC support added (#207) * sync: merge with upstream tag/go-1.21rc3 (#11) * fix: all tests pass * impl: UQUIC Transport * deps: bump up min Go version * new: uquic * fix: add QUICTransportParameter * deprecated: Go 1.19 no longer supported Go 1.19 will fail to build or pass the test once we bump up to the new version. * sync: crypto/tls: restrict RSA keys in certificates to <= 8192 bits (#209) * [release-branch.go1.21] crypto/tls: restrict RSA keys in certificates to <= 8192 bits Extremely large RSA keys in certificate chains can cause a client/server to expend significant CPU time verifying signatures. Limit this by restricting the size of RSA keys transmitted during handshakes to <= 8192 bits. Based on a survey of publicly trusted RSA keys, there are currently only three certificates in circulation with keys larger than this, and all three appear to be test certificates that are not actively deployed. It is possible there are larger keys in use in private PKIs, but we target the web PKI, so causing breakage here in the interests of increasing the default safety of users of crypto/tls seems reasonable. Thanks to Mateusz Poliwczak for reporting this issue. Fixes CVE-2023-29409 * build: [ci skip] boring not included * fix: typo [ci skip] * docs: replenish readme [ci skip] replace old build status badge with new ones, bump up required version noted in docs, update developer contact to reflect current status.
366 lines
12 KiB
Go
366 lines
12 KiB
Go
// 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 (
|
|
"crypto"
|
|
"crypto/ecdh"
|
|
"crypto/md5"
|
|
"crypto/rsa"
|
|
"crypto/sha1"
|
|
"crypto/x509"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
// 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, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
|
|
processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, 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) error
|
|
generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
|
|
}
|
|
|
|
var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
|
|
var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
|
|
|
|
// 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, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
|
|
if len(ckx.ciphertext) < 2 {
|
|
return nil, errClientKeyExchange
|
|
}
|
|
ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
|
|
if ciphertextLen != len(ckx.ciphertext)-2 {
|
|
return nil, errClientKeyExchange
|
|
}
|
|
ciphertext := ckx.ciphertext[2:]
|
|
|
|
priv, ok := cert.PrivateKey.(crypto.Decrypter)
|
|
if !ok {
|
|
return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
|
|
}
|
|
// Perform constant time RSA PKCS #1 v1.5 decryption
|
|
preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
|
|
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) error {
|
|
return errors.New("tls: unexpected ServerKeyExchange")
|
|
}
|
|
|
|
func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, 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
|
|
}
|
|
|
|
rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
|
|
if !ok {
|
|
return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
|
|
}
|
|
encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, 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
|
|
}
|
|
|
|
// sha1Hash calculates a SHA1 hash over the given byte slices.
|
|
func sha1Hash(slices [][]byte) []byte {
|
|
hsha1 := sha1.New()
|
|
for _, slice := range slices {
|
|
hsha1.Write(slice)
|
|
}
|
|
return hsha1.Sum(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(nil))
|
|
copy(md5sha1[md5.Size:], sha1Hash(slices))
|
|
return md5sha1
|
|
}
|
|
|
|
// hashForServerKeyExchange hashes the given slices and returns their digest
|
|
// using the given hash function (for >= TLS 1.2) or using a default based on
|
|
// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't
|
|
// do pre-hashing, it returns the concatenation of the slices.
|
|
func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte {
|
|
if sigType == signatureEd25519 {
|
|
var signed []byte
|
|
for _, slice := range slices {
|
|
signed = append(signed, slice...)
|
|
}
|
|
return signed
|
|
}
|
|
if version >= VersionTLS12 {
|
|
h := hashFunc.New()
|
|
for _, slice := range slices {
|
|
h.Write(slice)
|
|
}
|
|
digest := h.Sum(nil)
|
|
return digest
|
|
}
|
|
if sigType == signatureECDSA {
|
|
return sha1Hash(slices)
|
|
}
|
|
return md5SHA1Hash(slices)
|
|
}
|
|
|
|
// ecdheKeyAgreement implements a TLS key agreement where the server
|
|
// generates an ephemeral EC public/private key pair and signs it. The
|
|
// pre-master secret is then calculated using ECDH. The signature may
|
|
// be ECDSA, Ed25519 or RSA.
|
|
type ecdheKeyAgreement struct {
|
|
version uint16
|
|
isRSA bool
|
|
key *ecdh.PrivateKey
|
|
|
|
// ckx and preMasterSecret are generated in processServerKeyExchange
|
|
// and returned in generateClientKeyExchange.
|
|
ckx *clientKeyExchangeMsg
|
|
preMasterSecret []byte
|
|
}
|
|
|
|
func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
|
|
var curveID CurveID
|
|
for _, c := range clientHello.supportedCurves {
|
|
if config.supportsCurve(c) {
|
|
curveID = c
|
|
break
|
|
}
|
|
}
|
|
|
|
if curveID == 0 {
|
|
return nil, errors.New("tls: no supported elliptic curves offered")
|
|
}
|
|
if _, ok := curveForCurveID(curveID); !ok {
|
|
return nil, errors.New("tls: CurvePreferences includes unsupported curve")
|
|
}
|
|
|
|
key, err := generateECDHEKey(config.rand(), curveID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ka.key = key
|
|
|
|
// See RFC 4492, Section 5.4.
|
|
ecdhePublic := key.PublicKey().Bytes()
|
|
serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
|
|
serverECDHEParams[0] = 3 // named curve
|
|
serverECDHEParams[1] = byte(curveID >> 8)
|
|
serverECDHEParams[2] = byte(curveID)
|
|
serverECDHEParams[3] = byte(len(ecdhePublic))
|
|
copy(serverECDHEParams[4:], ecdhePublic)
|
|
|
|
priv, ok := cert.PrivateKey.(crypto.Signer)
|
|
if !ok {
|
|
return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey)
|
|
}
|
|
|
|
var signatureAlgorithm SignatureScheme
|
|
var sigType uint8
|
|
var sigHash crypto.Hash
|
|
if ka.version >= VersionTLS12 {
|
|
signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
} else {
|
|
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
|
|
return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
|
|
}
|
|
|
|
signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams)
|
|
|
|
signOpts := crypto.SignerOpts(sigHash)
|
|
if sigType == signatureRSAPSS {
|
|
signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
|
|
}
|
|
sig, err := priv.Sign(config.rand(), signed, signOpts)
|
|
if err != nil {
|
|
return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
|
|
}
|
|
|
|
skx := new(serverKeyExchangeMsg)
|
|
sigAndHashLen := 0
|
|
if ka.version >= VersionTLS12 {
|
|
sigAndHashLen = 2
|
|
}
|
|
skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig))
|
|
copy(skx.key, serverECDHEParams)
|
|
k := skx.key[len(serverECDHEParams):]
|
|
if ka.version >= VersionTLS12 {
|
|
k[0] = byte(signatureAlgorithm >> 8)
|
|
k[1] = byte(signatureAlgorithm)
|
|
k = k[2:]
|
|
}
|
|
k[0] = byte(len(sig) >> 8)
|
|
k[1] = byte(len(sig))
|
|
copy(k[2:], sig)
|
|
|
|
return skx, nil
|
|
}
|
|
|
|
func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
|
|
if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
|
|
return nil, errClientKeyExchange
|
|
}
|
|
|
|
peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:])
|
|
if err != nil {
|
|
return nil, errClientKeyExchange
|
|
}
|
|
preMasterSecret, err := ka.key.ECDH(peerKey)
|
|
if err != nil {
|
|
return nil, errClientKeyExchange
|
|
}
|
|
|
|
return preMasterSecret, nil
|
|
}
|
|
|
|
func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
|
|
if len(skx.key) < 4 {
|
|
return errServerKeyExchange
|
|
}
|
|
if skx.key[0] != 3 { // named curve
|
|
return errors.New("tls: server selected unsupported curve")
|
|
}
|
|
curveID := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
|
|
|
|
publicLen := int(skx.key[3])
|
|
if publicLen+4 > len(skx.key) {
|
|
return errServerKeyExchange
|
|
}
|
|
serverECDHEParams := skx.key[:4+publicLen]
|
|
publicKey := serverECDHEParams[4:]
|
|
|
|
sig := skx.key[4+publicLen:]
|
|
if len(sig) < 2 {
|
|
return errServerKeyExchange
|
|
}
|
|
|
|
if _, ok := curveForCurveID(curveID); !ok {
|
|
return errors.New("tls: server selected unsupported curve")
|
|
}
|
|
|
|
key, err := generateECDHEKey(config.rand(), curveID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ka.key = key
|
|
|
|
peerKey, err := key.Curve().NewPublicKey(publicKey)
|
|
if err != nil {
|
|
return errServerKeyExchange
|
|
}
|
|
ka.preMasterSecret, err = key.ECDH(peerKey)
|
|
if err != nil {
|
|
return errServerKeyExchange
|
|
}
|
|
|
|
ourPublicKey := key.PublicKey().Bytes()
|
|
ka.ckx = new(clientKeyExchangeMsg)
|
|
ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey))
|
|
ka.ckx.ciphertext[0] = byte(len(ourPublicKey))
|
|
copy(ka.ckx.ciphertext[1:], ourPublicKey)
|
|
|
|
var sigType uint8
|
|
var sigHash crypto.Hash
|
|
if ka.version >= VersionTLS12 {
|
|
signatureAlgorithm := SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
|
|
sig = sig[2:]
|
|
if len(sig) < 2 {
|
|
return errServerKeyExchange
|
|
}
|
|
|
|
if !isSupportedSignatureAlgorithm(signatureAlgorithm, clientHello.supportedSignatureAlgorithms) {
|
|
return errors.New("tls: certificate used with invalid signature algorithm")
|
|
}
|
|
sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
} else {
|
|
sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
|
|
return errServerKeyExchange
|
|
}
|
|
|
|
sigLen := int(sig[0])<<8 | int(sig[1])
|
|
if sigLen+2 != len(sig) {
|
|
return errServerKeyExchange
|
|
}
|
|
sig = sig[2:]
|
|
|
|
signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams)
|
|
if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil {
|
|
return errors.New("tls: invalid signature by the server certificate: " + err.Error())
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
|
|
if ka.ckx == nil {
|
|
return nil, nil, errors.New("tls: missing ServerKeyExchange message")
|
|
}
|
|
|
|
return ka.preMasterSecret, ka.ckx, nil
|
|
}
|