
44 changed files with 11652 additions and 57 deletions
@ -0,0 +1,9 @@
|
||||
//go:build !windows
|
||||
|
||||
package quic |
||||
|
||||
const ( |
||||
MaxDatagramFrameSize = 1350 |
||||
// maxDatagramPayloadSize is the maximum packet size allowed by warp client
|
||||
maxDatagramPayloadSize = 1280 |
||||
) |
@ -0,0 +1,11 @@
|
||||
//go:build windows
|
||||
|
||||
package quic |
||||
|
||||
const ( |
||||
// Due to https://github.com/lucas-clemente/quic-go/issues/3273, MTU discovery is disabled on Windows
|
||||
// 1220 is the default value https://github.com/lucas-clemente/quic-go/blob/84e03e59760ceee37359688871bb0688fcc4e98f/internal/protocol/params.go#L138
|
||||
MaxDatagramFrameSize = 1220 |
||||
// 3 more bytes are reserved at https://github.com/lucas-clemente/quic-go/blob/v0.24.0/internal/wire/datagram_frame.go#L61
|
||||
maxDatagramPayloadSize = MaxDatagramFrameSize - 3 - sessionIDLen |
||||
) |
@ -0,0 +1,6 @@
|
||||
//go:build go1.19
|
||||
// +build go1.19
|
||||
|
||||
package qtls |
||||
|
||||
var _ int = "quic-go doesn't build on Go 1.19 yet." |
@ -1,4 +1,4 @@
|
||||
package logging |
||||
|
||||
//go:generate sh -c "mockgen -package logging -self_package github.com/lucas-clemente/quic-go/logging -destination mock_connection_tracer_test.go github.com/lucas-clemente/quic-go/logging ConnectionTracer && goimports -w mock_connection_tracer_test.go"
|
||||
//go:generate sh -c "mockgen -package logging -self_package github.com/lucas-clemente/quic-go/logging -destination mock_tracer_test.go github.com/lucas-clemente/quic-go/logging Tracer && goimports -w mock_tracer_test.go"
|
||||
//go:generate sh -c "mockgen -package logging -self_package github.com/lucas-clemente/quic-go/logging -destination mock_connection_tracer_test.go github.com/lucas-clemente/quic-go/logging ConnectionTracer"
|
||||
//go:generate sh -c "mockgen -package logging -self_package github.com/lucas-clemente/quic-go/logging -destination mock_tracer_test.go github.com/lucas-clemente/quic-go/logging Tracer"
|
||||
|
@ -0,0 +1,27 @@
|
||||
Copyright (c) 2009 The Go Authors. All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are |
||||
met: |
||||
|
||||
* Redistributions of source code must retain the above copyright |
||||
notice, this list of conditions and the following disclaimer. |
||||
* Redistributions in binary form must reproduce the above |
||||
copyright notice, this list of conditions and the following disclaimer |
||||
in the documentation and/or other materials provided with the |
||||
distribution. |
||||
* Neither the name of Google Inc. nor the names of its |
||||
contributors may be used to endorse or promote products derived from |
||||
this software without specific prior written permission. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,6 @@
|
||||
# qtls |
||||
|
||||
[](https://pkg.go.dev/github.com/marten-seemann/qtls-go1-17) |
||||
[](https://github.com/marten-seemann/qtls-go1-17/actions/workflows/go-test.yml) |
||||
|
||||
This repository contains a modified version of the standard library's TLS implementation, modified for the QUIC protocol. It is used by [quic-go](https://github.com/lucas-clemente/quic-go). |
@ -0,0 +1,102 @@
|
||||
// Copyright 2009 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 qtls |
||||
|
||||
import "strconv" |
||||
|
||||
type alert uint8 |
||||
|
||||
// Alert is a TLS alert
|
||||
type Alert = alert |
||||
|
||||
const ( |
||||
// alert level
|
||||
alertLevelWarning = 1 |
||||
alertLevelError = 2 |
||||
) |
||||
|
||||
const ( |
||||
alertCloseNotify alert = 0 |
||||
alertUnexpectedMessage alert = 10 |
||||
alertBadRecordMAC alert = 20 |
||||
alertDecryptionFailed alert = 21 |
||||
alertRecordOverflow alert = 22 |
||||
alertDecompressionFailure alert = 30 |
||||
alertHandshakeFailure alert = 40 |
||||
alertBadCertificate alert = 42 |
||||
alertUnsupportedCertificate alert = 43 |
||||
alertCertificateRevoked alert = 44 |
||||
alertCertificateExpired alert = 45 |
||||
alertCertificateUnknown alert = 46 |
||||
alertIllegalParameter alert = 47 |
||||
alertUnknownCA alert = 48 |
||||
alertAccessDenied alert = 49 |
||||
alertDecodeError alert = 50 |
||||
alertDecryptError alert = 51 |
||||
alertExportRestriction alert = 60 |
||||
alertProtocolVersion alert = 70 |
||||
alertInsufficientSecurity alert = 71 |
||||
alertInternalError alert = 80 |
||||
alertInappropriateFallback alert = 86 |
||||
alertUserCanceled alert = 90 |
||||
alertNoRenegotiation alert = 100 |
||||
alertMissingExtension alert = 109 |
||||
alertUnsupportedExtension alert = 110 |
||||
alertCertificateUnobtainable alert = 111 |
||||
alertUnrecognizedName alert = 112 |
||||
alertBadCertificateStatusResponse alert = 113 |
||||
alertBadCertificateHashValue alert = 114 |
||||
alertUnknownPSKIdentity alert = 115 |
||||
alertCertificateRequired alert = 116 |
||||
alertNoApplicationProtocol alert = 120 |
||||
) |
||||
|
||||
var alertText = map[alert]string{ |
||||
alertCloseNotify: "close notify", |
||||
alertUnexpectedMessage: "unexpected message", |
||||
alertBadRecordMAC: "bad record MAC", |
||||
alertDecryptionFailed: "decryption failed", |
||||
alertRecordOverflow: "record overflow", |
||||
alertDecompressionFailure: "decompression failure", |
||||
alertHandshakeFailure: "handshake failure", |
||||
alertBadCertificate: "bad certificate", |
||||
alertUnsupportedCertificate: "unsupported certificate", |
||||
alertCertificateRevoked: "revoked certificate", |
||||
alertCertificateExpired: "expired certificate", |
||||
alertCertificateUnknown: "unknown certificate", |
||||
alertIllegalParameter: "illegal parameter", |
||||
alertUnknownCA: "unknown certificate authority", |
||||
alertAccessDenied: "access denied", |
||||
alertDecodeError: "error decoding message", |
||||
alertDecryptError: "error decrypting message", |
||||
alertExportRestriction: "export restriction", |
||||
alertProtocolVersion: "protocol version not supported", |
||||
alertInsufficientSecurity: "insufficient security level", |
||||
alertInternalError: "internal error", |
||||
alertInappropriateFallback: "inappropriate fallback", |
||||
alertUserCanceled: "user canceled", |
||||
alertNoRenegotiation: "no renegotiation", |
||||
alertMissingExtension: "missing extension", |
||||
alertUnsupportedExtension: "unsupported extension", |
||||
alertCertificateUnobtainable: "certificate unobtainable", |
||||
alertUnrecognizedName: "unrecognized name", |
||||
alertBadCertificateStatusResponse: "bad certificate status response", |
||||
alertBadCertificateHashValue: "bad certificate hash value", |
||||
alertUnknownPSKIdentity: "unknown PSK identity", |
||||
alertCertificateRequired: "certificate required", |
||||
alertNoApplicationProtocol: "no application protocol", |
||||
} |
||||
|
||||
func (e alert) String() string { |
||||
s, ok := alertText[e] |
||||
if ok { |
||||
return "tls: " + s |
||||
} |
||||
return "tls: alert(" + strconv.Itoa(int(e)) + ")" |
||||
} |
||||
|
||||
func (e alert) Error() string { |
||||
return e.String() |
||||
} |
@ -0,0 +1,289 @@
|
||||
// Copyright 2017 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 qtls |
||||
|
||||
import ( |
||||
"bytes" |
||||
"crypto" |
||||
"crypto/ecdsa" |
||||
"crypto/ed25519" |
||||
"crypto/elliptic" |
||||
"crypto/rsa" |
||||
"errors" |
||||
"fmt" |
||||
"hash" |
||||
"io" |
||||
) |
||||
|
||||
// verifyHandshakeSignature verifies a signature against pre-hashed
|
||||
// (if required) handshake contents.
|
||||
func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error { |
||||
switch sigType { |
||||
case signatureECDSA: |
||||
pubKey, ok := pubkey.(*ecdsa.PublicKey) |
||||
if !ok { |
||||
return fmt.Errorf("expected an ECDSA public key, got %T", pubkey) |
||||
} |
||||
if !ecdsa.VerifyASN1(pubKey, signed, sig) { |
||||
return errors.New("ECDSA verification failure") |
||||
} |
||||
case signatureEd25519: |
||||
pubKey, ok := pubkey.(ed25519.PublicKey) |
||||
if !ok { |
||||
return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey) |
||||
} |
||||
if !ed25519.Verify(pubKey, signed, sig) { |
||||
return errors.New("Ed25519 verification failure") |
||||
} |
||||
case signaturePKCS1v15: |
||||
pubKey, ok := pubkey.(*rsa.PublicKey) |
||||
if !ok { |
||||
return fmt.Errorf("expected an RSA public key, got %T", pubkey) |
||||
} |
||||
if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil { |
||||
return err |
||||
} |
||||
case signatureRSAPSS: |
||||
pubKey, ok := pubkey.(*rsa.PublicKey) |
||||
if !ok { |
||||
return fmt.Errorf("expected an RSA public key, got %T", pubkey) |
||||
} |
||||
signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash} |
||||
if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil { |
||||
return err |
||||
} |
||||
default: |
||||
return errors.New("internal error: unknown signature type") |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
const ( |
||||
serverSignatureContext = "TLS 1.3, server CertificateVerify\x00" |
||||
clientSignatureContext = "TLS 1.3, client CertificateVerify\x00" |
||||
) |
||||
|
||||
var signaturePadding = []byte{ |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, |
||||
} |
||||
|
||||
// signedMessage returns the pre-hashed (if necessary) message to be signed by
|
||||
// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3.
|
||||
func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte { |
||||
if sigHash == directSigning { |
||||
b := &bytes.Buffer{} |
||||
b.Write(signaturePadding) |
||||
io.WriteString(b, context) |
||||
b.Write(transcript.Sum(nil)) |
||||
return b.Bytes() |
||||
} |
||||
h := sigHash.New() |
||||
h.Write(signaturePadding) |
||||
io.WriteString(h, context) |
||||
h.Write(transcript.Sum(nil)) |
||||
return h.Sum(nil) |
||||
} |
||||
|
||||
// typeAndHashFromSignatureScheme returns the corresponding signature type and
|
||||
// crypto.Hash for a given TLS SignatureScheme.
|
||||
func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) { |
||||
switch signatureAlgorithm { |
||||
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512: |
||||
sigType = signaturePKCS1v15 |
||||
case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512: |
||||
sigType = signatureRSAPSS |
||||
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512: |
||||
sigType = signatureECDSA |
||||
case Ed25519: |
||||
sigType = signatureEd25519 |
||||
default: |
||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) |
||||
} |
||||
switch signatureAlgorithm { |
||||
case PKCS1WithSHA1, ECDSAWithSHA1: |
||||
hash = crypto.SHA1 |
||||
case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256: |
||||
hash = crypto.SHA256 |
||||
case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384: |
||||
hash = crypto.SHA384 |
||||
case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512: |
||||
hash = crypto.SHA512 |
||||
case Ed25519: |
||||
hash = directSigning |
||||
default: |
||||
return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm) |
||||
} |
||||
return sigType, hash, nil |
||||
} |
||||
|
||||
// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for
|
||||
// a given public key used with TLS 1.0 and 1.1, before the introduction of
|
||||
// signature algorithm negotiation.
|
||||
func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) { |
||||
switch pub.(type) { |
||||
case *rsa.PublicKey: |
||||
return signaturePKCS1v15, crypto.MD5SHA1, nil |
||||
case *ecdsa.PublicKey: |
||||
return signatureECDSA, crypto.SHA1, nil |
||||
case ed25519.PublicKey: |
||||
// RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1,
|
||||
// but it requires holding on to a handshake transcript to do a
|
||||
// full signature, and not even OpenSSL bothers with the
|
||||
// complexity, so we can't even test it properly.
|
||||
return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2") |
||||
default: |
||||
return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub) |
||||
} |
||||
} |
||||
|
||||
var rsaSignatureSchemes = []struct { |
||||
scheme SignatureScheme |
||||
minModulusBytes int |
||||
maxVersion uint16 |
||||
}{ |
||||
// RSA-PSS is used with PSSSaltLengthEqualsHash, and requires
|
||||
// emLen >= hLen + sLen + 2
|
||||
{PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13}, |
||||
{PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13}, |
||||
{PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13}, |
||||
// PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires
|
||||
// emLen >= len(prefix) + hLen + 11
|
||||
// TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS.
|
||||
{PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12}, |
||||
{PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12}, |
||||
{PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12}, |
||||
{PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12}, |
||||
} |
||||
|
||||
// signatureSchemesForCertificate returns the list of supported SignatureSchemes
|
||||
// for a given certificate, based on the public key and the protocol version,
|
||||
// and optionally filtered by its explicit SupportedSignatureAlgorithms.
|
||||
//
|
||||
// This function must be kept in sync with supportedSignatureAlgorithms.
|
||||
func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme { |
||||
priv, ok := cert.PrivateKey.(crypto.Signer) |
||||
if !ok { |
||||
return nil |
||||
} |
||||
|
||||
var sigAlgs []SignatureScheme |
||||
switch pub := priv.Public().(type) { |
||||
case *ecdsa.PublicKey: |
||||
if version != VersionTLS13 { |
||||
// In TLS 1.2 and earlier, ECDSA algorithms are not
|
||||
// constrained to a single curve.
|
||||
sigAlgs = []SignatureScheme{ |
||||
ECDSAWithP256AndSHA256, |
||||
ECDSAWithP384AndSHA384, |
||||
ECDSAWithP521AndSHA512, |
||||
ECDSAWithSHA1, |
||||
} |
||||
break |
||||
} |
||||
switch pub.Curve { |
||||
case elliptic.P256(): |
||||
sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256} |
||||
case elliptic.P384(): |
||||
sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384} |
||||
case elliptic.P521(): |
||||
sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512} |
||||
default: |
||||
return nil |
||||
} |
||||
case *rsa.PublicKey: |
||||
size := pub.Size() |
||||
sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes)) |
||||
for _, candidate := range rsaSignatureSchemes { |
||||
if size >= candidate.minModulusBytes && version <= candidate.maxVersion { |
||||
sigAlgs = append(sigAlgs, candidate.scheme) |
||||
} |
||||
} |
||||
case ed25519.PublicKey: |
||||
sigAlgs = []SignatureScheme{Ed25519} |
||||
default: |
||||
return nil |
||||
} |
||||
|
||||
if cert.SupportedSignatureAlgorithms != nil { |
||||
var filteredSigAlgs []SignatureScheme |
||||
for _, sigAlg := range sigAlgs { |
||||
if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) { |
||||
filteredSigAlgs = append(filteredSigAlgs, sigAlg) |
||||
} |
||||
} |
||||
return filteredSigAlgs |
||||
} |
||||
return sigAlgs |
||||
} |
||||
|
||||
// selectSignatureScheme picks a SignatureScheme from the peer's preference list
|
||||
// that works with the selected certificate. It's only called for protocol
|
||||
// versions that support signature algorithms, so TLS 1.2 and 1.3.
|
||||
func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) { |
||||
supportedAlgs := signatureSchemesForCertificate(vers, c) |
||||
if len(supportedAlgs) == 0 { |
||||
return 0, unsupportedCertificateError(c) |
||||
} |
||||
if len(peerAlgs) == 0 && vers == VersionTLS12 { |
||||
// For TLS 1.2, if the client didn't send signature_algorithms then we
|
||||
// can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
|
||||
peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1} |
||||
} |
||||
// Pick signature scheme in the peer's preference order, as our
|
||||
// preference order is not configurable.
|
||||
for _, preferredAlg := range peerAlgs { |
||||
if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) { |
||||
return preferredAlg, nil |
||||
} |
||||
} |
||||
return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms") |
||||
} |
||||
|
||||
// unsupportedCertificateError returns a helpful error for certificates with
|
||||
// an unsupported private key.
|
||||
func unsupportedCertificateError(cert *Certificate) error { |
||||
switch cert.PrivateKey.(type) { |
||||
case rsa.PrivateKey, ecdsa.PrivateKey: |
||||
return fmt.Errorf("tls: unsupported certificate: private key is %T, expected *%T", |
||||
cert.PrivateKey, cert.PrivateKey) |
||||
case *ed25519.PrivateKey: |
||||
return fmt.Errorf("tls: unsupported certificate: private key is *ed25519.PrivateKey, expected ed25519.PrivateKey") |
||||
} |
||||
|
||||
signer, ok := cert.PrivateKey.(crypto.Signer) |
||||
if !ok { |
||||
return fmt.Errorf("tls: certificate private key (%T) does not implement crypto.Signer", |
||||
cert.PrivateKey) |
||||
} |
||||
|
||||
switch pub := signer.Public().(type) { |
||||
case *ecdsa.PublicKey: |
||||
switch pub.Curve { |
||||
case elliptic.P256(): |
||||
case elliptic.P384(): |
||||
case elliptic.P521(): |
||||
default: |
||||
return fmt.Errorf("tls: unsupported certificate curve (%s)", pub.Curve.Params().Name) |
||||
} |
||||
case *rsa.PublicKey: |
||||
return fmt.Errorf("tls: certificate RSA key size too small for supported signature algorithms") |
||||
case ed25519.PublicKey: |
||||
default: |
||||
return fmt.Errorf("tls: unsupported certificate key (%T)", pub) |
||||
} |
||||
|
||||
if cert.SupportedSignatureAlgorithms != nil { |
||||
return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms") |
||||
} |
||||
|
||||
return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey) |
||||
} |
@ -0,0 +1,705 @@
|
||||
// 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 qtls |
||||
|
||||
import ( |
||||
"crypto" |
||||
"crypto/aes" |
||||
"crypto/cipher" |
||||
"crypto/des" |
||||
"crypto/hmac" |
||||
"crypto/rc4" |
||||
"crypto/sha1" |
||||
"crypto/sha256" |
||||
"fmt" |
||||
"hash" |
||||
"runtime" |
||||
|
||||
"golang.org/x/crypto/chacha20poly1305" |
||||
"golang.org/x/sys/cpu" |
||||
) |
||||
|
||||
// CipherSuite is a TLS cipher suite. Note that most functions in this package
|
||||
// accept and expose cipher suite IDs instead of this type.
|
||||
type CipherSuite struct { |
||||
ID uint16 |
||||
Name string |
||||
|
||||
// Supported versions is the list of TLS protocol versions that can
|
||||
// negotiate this cipher suite.
|
||||
SupportedVersions []uint16 |
||||
|
||||
// Insecure is true if the cipher suite has known security issues
|
||||
// due to its primitives, design, or implementation.
|
||||
Insecure bool |
||||
} |
||||
|
||||
var ( |
||||
supportedUpToTLS12 = []uint16{VersionTLS10, VersionTLS11, VersionTLS12} |
||||
supportedOnlyTLS12 = []uint16{VersionTLS12} |
||||
supportedOnlyTLS13 = []uint16{VersionTLS13} |
||||
) |
||||
|
||||
// CipherSuites returns a list of cipher suites currently implemented by this
|
||||
// package, excluding those with security issues, which are returned by
|
||||
// InsecureCipherSuites.
|
||||
//
|
||||
// The list is sorted by ID. Note that the default cipher suites selected by
|
||||
// this package might depend on logic that can't be captured by a static list,
|
||||
// and might not match those returned by this function.
|
||||
func CipherSuites() []*CipherSuite { |
||||
return []*CipherSuite{ |
||||
{TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, |
||||
{TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, |
||||
{TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, |
||||
{TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, |
||||
|
||||
{TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", supportedOnlyTLS13, false}, |
||||
{TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", supportedOnlyTLS13, false}, |
||||
{TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", supportedOnlyTLS13, false}, |
||||
|
||||
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, |
||||
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false}, |
||||
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, |
||||
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false}, |
||||
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false}, |
||||
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false}, |
||||
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false}, |
||||
} |
||||
} |
||||
|
||||
// InsecureCipherSuites returns a list of cipher suites currently implemented by
|
||||
// this package and which have security issues.
|
||||
//
|
||||
// Most applications should not use the cipher suites in this list, and should
|
||||
// only use those returned by CipherSuites.
|
||||
func InsecureCipherSuites() []*CipherSuite { |
||||
// This list includes RC4, CBC_SHA256, and 3DES cipher suites. See
|
||||
// cipherSuitesPreferenceOrder for details.
|
||||
return []*CipherSuite{ |
||||
{TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, |
||||
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true}, |
||||
{TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, |
||||
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, |
||||
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true}, |
||||
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, |
||||
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true}, |
||||
} |
||||
} |
||||
|
||||
// CipherSuiteName returns the standard name for the passed cipher suite ID
|
||||
// (e.g. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), or a fallback representation
|
||||
// of the ID value if the cipher suite is not implemented by this package.
|
||||
func CipherSuiteName(id uint16) string { |
||||
for _, c := range CipherSuites() { |
||||
if c.ID == id { |
||||
return c.Name |
||||
} |
||||
} |
||||
for _, c := range InsecureCipherSuites() { |
||||
if c.ID == id { |
||||
return c.Name |
||||
} |
||||
} |
||||
return fmt.Sprintf("0x%04X", id) |
||||
} |
||||
|
||||
const ( |
||||
// suiteECDHE indicates that the cipher suite involves elliptic curve
|
||||
// Diffie-Hellman. This means that it should only be selected when the
|
||||
// client indicates that it supports ECC with a curve and point format
|
||||
// that we're happy with.
|
||||
suiteECDHE = 1 << iota |
||||
// suiteECSign indicates that the cipher suite involves an ECDSA or
|
||||
// EdDSA signature and therefore may only be selected when the server's
|
||||
// certificate is ECDSA or EdDSA. If this is not set then the cipher suite
|
||||
// is RSA based.
|
||||
suiteECSign |
||||
// suiteTLS12 indicates that the cipher suite should only be advertised
|
||||
// and accepted when using TLS 1.2.
|
||||
suiteTLS12 |
||||
// suiteSHA384 indicates that the cipher suite uses SHA384 as the
|
||||
// handshake hash.
|
||||
suiteSHA384 |
||||
) |
||||
|
||||
// A cipherSuite is a TLS 1.0–1.2 cipher suite, and defines the key exchange
|
||||
// mechanism, as well as the cipher+MAC pair or the AEAD.
|
||||
type cipherSuite struct { |
||||
id uint16 |
||||
// the lengths, in bytes, of the key material needed for each component.
|
||||
keyLen int |
||||
macLen int |
||||
ivLen int |
||||
ka func(version uint16) keyAgreement |
||||
// flags is a bitmask of the suite* values, above.
|
||||
flags int |
||||
cipher func(key, iv []byte, isRead bool) any |
||||
mac func(key []byte) hash.Hash |
||||
aead func(key, fixedNonce []byte) aead |
||||
} |
||||
|
||||
var cipherSuites = []*cipherSuite{ // TODO: replace with a map, since the order doesn't matter.
|
||||
{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, |
||||
{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305}, |
||||
{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM}, |
||||
{TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, |
||||
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil}, |
||||
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, cipherAES, macSHA256, nil}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil}, |
||||
{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil}, |
||||
{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil}, |
||||
{TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM}, |
||||
{TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM}, |
||||
{TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil}, |
||||
{TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, |
||||
{TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil}, |
||||
{TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil}, |
||||
{TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil}, |
||||
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil}, |
||||
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil}, |
||||
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherRC4, macSHA1, nil}, |
||||
} |
||||
|
||||
// selectCipherSuite returns the first TLS 1.0–1.2 cipher suite from ids which
|
||||
// is also in supportedIDs and passes the ok filter.
|
||||
func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite { |
||||
for _, id := range ids { |
||||
candidate := cipherSuiteByID(id) |
||||
if candidate == nil || !ok(candidate) { |
||||
continue |
||||
} |
||||
|
||||
for _, suppID := range supportedIDs { |
||||
if id == suppID { |
||||
return candidate |
||||
} |
||||
} |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash
|
||||
// algorithm to be used with HKDF. See RFC 8446, Appendix B.4.
|
||||
type cipherSuiteTLS13 struct { |
||||
id uint16 |
||||
keyLen int |
||||
aead func(key, fixedNonce []byte) aead |
||||
hash crypto.Hash |
||||
} |
||||
|
||||
type CipherSuiteTLS13 struct { |
||||
ID uint16 |
||||
KeyLen int |
||||
Hash crypto.Hash |
||||
AEAD func(key, fixedNonce []byte) cipher.AEAD |
||||
} |
||||
|
||||
func (c *CipherSuiteTLS13) IVLen() int { |
||||
return aeadNonceLength |
||||
} |
||||
|
||||
var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map.
|
||||
{TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256}, |
||||
{TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256}, |
||||
{TLS_AES_256_GCM_SHA384, 32, aeadAESGCMTLS13, crypto.SHA384}, |
||||
} |
||||
|
||||
// cipherSuitesPreferenceOrder is the order in which we'll select (on the
|
||||
// server) or advertise (on the client) TLS 1.0–1.2 cipher suites.
|
||||
//
|
||||
// Cipher suites are filtered but not reordered based on the application and
|
||||
// peer's preferences, meaning we'll never select a suite lower in this list if
|
||||
// any higher one is available. This makes it more defensible to keep weaker
|
||||
// cipher suites enabled, especially on the server side where we get the last
|
||||
// word, since there are no known downgrade attacks on cipher suites selection.
|
||||
//
|
||||
// The list is sorted by applying the following priority rules, stopping at the
|
||||
// first (most important) applicable one:
|
||||
//
|
||||
// - Anything else comes before RC4
|
||||
//
|
||||
// RC4 has practically exploitable biases. See https://www.rc4nomore.com.
|
||||
//
|
||||
// - Anything else comes before CBC_SHA256
|
||||
//
|
||||
// SHA-256 variants of the CBC ciphersuites don't implement any Lucky13
|
||||
// countermeasures. See http://www.isg.rhul.ac.uk/tls/Lucky13.html and
|
||||
// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
|
||||
//
|
||||
// - Anything else comes before 3DES
|
||||
//
|
||||
// 3DES has 64-bit blocks, which makes it fundamentally susceptible to
|
||||
// birthday attacks. See https://sweet32.info.
|
||||
//
|
||||
// - ECDHE comes before anything else
|
||||
//
|
||||
// Once we got the broken stuff out of the way, the most important
|
||||
// property a cipher suite can have is forward secrecy. We don't
|
||||
// implement FFDHE, so that means ECDHE.
|
||||
//
|
||||
// - AEADs come before CBC ciphers
|
||||
//
|
||||
// Even with Lucky13 countermeasures, MAC-then-Encrypt CBC cipher suites
|
||||
// are fundamentally fragile, and suffered from an endless sequence of
|
||||
// padding oracle attacks. See https://eprint.iacr.org/2015/1129,
|
||||
// https://www.imperialviolet.org/2014/12/08/poodleagain.html, and
|
||||
// https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/.
|
||||
//
|
||||
// - AES comes before ChaCha20
|
||||
//
|
||||
// When AES hardware is available, AES-128-GCM and AES-256-GCM are faster
|
||||
// than ChaCha20Poly1305.
|
||||
//
|
||||
// When AES hardware is not available, AES-128-GCM is one or more of: much
|
||||
// slower, way more complex, and less safe (because not constant time)
|
||||
// than ChaCha20Poly1305.
|
||||
//
|
||||
// We use this list if we think both peers have AES hardware, and
|
||||
// cipherSuitesPreferenceOrderNoAES otherwise.
|
||||