mirror of
https://github.com/refraction-networking/utls.git
synced 2025-04-03 20:17:36 +03:00
The crypto/tls record layer used a custom buffer implementation with its own semantics, freelist, and offset management. Replace it all with per-task bytes.Buffer, bytes.Reader and byte slices, along with a refactor of all the encrypt and decrypt code. The main quirk of *block was to do a best-effort read past the record boundary, so that if a closeNotify was waiting it would be peeked and surfaced along with the last Read. Address that with atLeastReader and ReadFrom to avoid a useless copy (instead of a LimitReader or CopyN). There was also an optimization to split blocks along record boundary lines without having to copy in and out the data. Replicate that by aliasing c.input into consumed c.rawInput (after an in-place decrypt operation). This is safe because c.rawInput is not used until c.input is drained. The benchmarks are noisy but look like an improvement across the board, which is a nice side effect :) name old time/op new time/op delta HandshakeServer/RSA-8 817µs ± 2% 797µs ± 2% -2.52% (p=0.000 n=10+9) HandshakeServer/ECDHE-P256-RSA-8 984µs ±11% 897µs ± 0% -8.89% (p=0.000 n=10+9) HandshakeServer/ECDHE-P256-ECDSA-P256-8 206µs ±10% 199µs ± 3% ~ (p=0.113 n=10+9) HandshakeServer/ECDHE-X25519-ECDSA-P256-8 204µs ± 3% 202µs ± 1% -1.06% (p=0.013 n=10+9) HandshakeServer/ECDHE-P521-ECDSA-P521-8 15.5ms ± 0% 15.6ms ± 1% ~ (p=0.095 n=9+10) Throughput/MaxPacket/1MB-8 5.35ms ±19% 5.39ms ±36% ~ (p=1.000 n=9+10) Throughput/MaxPacket/2MB-8 9.20ms ±15% 8.30ms ± 8% -9.79% (p=0.035 n=10+9) Throughput/MaxPacket/4MB-8 13.8ms ± 7% 13.6ms ± 8% ~ (p=0.315 n=10+10) Throughput/MaxPacket/8MB-8 25.1ms ± 3% 23.2ms ± 2% -7.66% (p=0.000 n=10+9) Throughput/MaxPacket/16MB-8 46.9ms ± 1% 43.0ms ± 3% -8.29% (p=0.000 n=9+10) Throughput/MaxPacket/32MB-8 88.9ms ± 2% 82.3ms ± 2% -7.40% (p=0.000 n=9+9) Throughput/MaxPacket/64MB-8 175ms ± 2% 164ms ± 4% -6.18% (p=0.000 n=10+10) Throughput/DynamicPacket/1MB-8 5.79ms ±26% 5.82ms ±22% ~ (p=0.912 n=10+10) Throughput/DynamicPacket/2MB-8 9.23ms ±14% 9.50ms ±23% ~ (p=0.971 n=10+10) Throughput/DynamicPacket/4MB-8 14.5ms ±11% 13.8ms ± 6% -4.66% (p=0.019 n=10+10) Throughput/DynamicPacket/8MB-8 25.6ms ± 4% 23.5ms ± 3% -8.33% (p=0.000 n=10+10) Throughput/DynamicPacket/16MB-8 47.3ms ± 3% 44.6ms ± 7% -5.65% (p=0.000 n=10+10) Throughput/DynamicPacket/32MB-8 91.9ms ±14% 85.0ms ± 4% -7.55% (p=0.000 n=10+10) Throughput/DynamicPacket/64MB-8 177ms ± 2% 168ms ± 4% -4.97% (p=0.000 n=8+10) Latency/MaxPacket/200kbps-8 694ms ± 0% 694ms ± 0% ~ (p=0.315 n=10+9) Latency/MaxPacket/500kbps-8 279ms ± 0% 279ms ± 0% ~ (p=0.447 n=9+10) Latency/MaxPacket/1000kbps-8 140ms ± 0% 140ms ± 0% ~ (p=0.661 n=9+10) Latency/MaxPacket/2000kbps-8 71.1ms ± 0% 71.1ms ± 0% +0.05% (p=0.019 n=9+9) Latency/MaxPacket/5000kbps-8 30.4ms ± 7% 30.5ms ± 4% ~ (p=0.720 n=9+10) Latency/DynamicPacket/200kbps-8 134ms ± 0% 134ms ± 0% ~ (p=0.075 n=10+10) Latency/DynamicPacket/500kbps-8 54.8ms ± 0% 54.8ms ± 0% ~ (p=0.631 n=10+10) Latency/DynamicPacket/1000kbps-8 28.5ms ± 0% 28.5ms ± 0% ~ (p=1.000 n=8+8) Latency/DynamicPacket/2000kbps-8 15.7ms ±12% 16.1ms ± 0% ~ (p=0.109 n=10+7) Latency/DynamicPacket/5000kbps-8 8.20ms ±26% 8.17ms ±13% ~ (p=1.000 n=9+9) name old speed new speed delta Throughput/MaxPacket/1MB-8 193MB/s ±14% 202MB/s ±30% ~ (p=0.897 n=8+10) Throughput/MaxPacket/2MB-8 230MB/s ±14% 249MB/s ±17% ~ (p=0.089 n=10+10) Throughput/MaxPacket/4MB-8 304MB/s ± 6% 309MB/s ± 7% ~ (p=0.315 n=10+10) Throughput/MaxPacket/8MB-8 334MB/s ± 3% 362MB/s ± 2% +8.29% (p=0.000 n=10+9) Throughput/MaxPacket/16MB-8 358MB/s ± 1% 390MB/s ± 3% +9.08% (p=0.000 n=9+10) Throughput/MaxPacket/32MB-8 378MB/s ± 2% 408MB/s ± 2% +8.00% (p=0.000 n=9+9) Throughput/MaxPacket/64MB-8 384MB/s ± 2% 410MB/s ± 4% +6.61% (p=0.000 n=10+10) Throughput/DynamicPacket/1MB-8 178MB/s ±24% 182MB/s ±24% ~ (p=0.604 n=9+10) Throughput/DynamicPacket/2MB-8 228MB/s ±13% 225MB/s ±20% ~ (p=0.971 n=10+10) Throughput/DynamicPacket/4MB-8 291MB/s ±10% 305MB/s ± 6% +4.83% (p=0.019 n=10+10) Throughput/DynamicPacket/8MB-8 327MB/s ± 4% 357MB/s ± 3% +9.08% (p=0.000 n=10+10) Throughput/DynamicPacket/16MB-8 355MB/s ± 3% 376MB/s ± 6% +6.07% (p=0.000 n=10+10) Throughput/DynamicPacket/32MB-8 366MB/s ±12% 395MB/s ± 4% +7.91% (p=0.000 n=10+10) Throughput/DynamicPacket/64MB-8 380MB/s ± 2% 400MB/s ± 4% +5.26% (p=0.000 n=8+10) Note that this reduced the buffer for the first read from 1024 to 5+512, so it triggered the issue described at #24198 when using a synchronous net.Pipe: the first server flight was not being consumed entirely by the first read anymore, causing a deadlock as both the client and the server were trying to send (the client a reply to the ServerHello, the server the rest of the buffer). Fixed by rebasing on top of CL 142817. Change-Id: Ie31b0a572b2ad37878469877798d5c6a5276f931 Reviewed-on: https://go-review.googlesource.com/c/142818 Run-TryBot: Filippo Valsorda <filippo@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Adam Langley <agl@golang.org>
400 lines
14 KiB
Go
400 lines
14 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/aes"
|
|
"crypto/cipher"
|
|
"crypto/des"
|
|
"crypto/hmac"
|
|
"crypto/rc4"
|
|
"crypto/sha1"
|
|
"crypto/sha256"
|
|
"crypto/x509"
|
|
"golang_org/x/crypto/chacha20poly1305"
|
|
"hash"
|
|
)
|
|
|
|
// 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)
|
|
}
|
|
|
|
const (
|
|
// suiteECDH 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
|
|
// suiteECDSA indicates that the cipher suite involves an ECDSA
|
|
// signature and therefore may only be selected when the server's
|
|
// certificate is ECDSA. If this is not set then the cipher suite is
|
|
// RSA based.
|
|
suiteECDSA
|
|
// 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
|
|
// suiteDefaultOff indicates that this cipher suite is not included by
|
|
// default.
|
|
suiteDefaultOff
|
|
)
|
|
|
|
// A cipherSuite is a specific combination of key agreement, cipher and MAC
|
|
// function. All cipher suites currently assume RSA key agreement.
|
|
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) interface{}
|
|
mac func(version uint16, macKey []byte) macFunction
|
|
aead func(key, fixedNonce []byte) cipher.AEAD
|
|
}
|
|
|
|
var cipherSuites = []*cipherSuite{
|
|
// Ciphersuite order is chosen so that ECDHE comes before plain RSA and
|
|
// AEADs are the top preference.
|
|
{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 | suiteECDSA | 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 | suiteECDSA | 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 | suiteECDSA | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
|
|
{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteDefaultOff, 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 | suiteECDSA | suiteTLS12 | suiteDefaultOff, cipherAES, macSHA256, nil},
|
|
{TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECDSA, 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 | suiteECDSA, 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 | suiteDefaultOff, 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},
|
|
|
|
// RC4-based cipher suites are disabled by default.
|
|
{TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, suiteDefaultOff, cipherRC4, macSHA1, nil},
|
|
{TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE | suiteDefaultOff, cipherRC4, macSHA1, nil},
|
|
{TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECDSA | suiteDefaultOff, cipherRC4, macSHA1, nil},
|
|
}
|
|
|
|
func cipherRC4(key, iv []byte, isRead bool) interface{} {
|
|
cipher, _ := rc4.NewCipher(key)
|
|
return cipher
|
|
}
|
|
|
|
func cipher3DES(key, iv []byte, isRead bool) interface{} {
|
|
block, _ := des.NewTripleDESCipher(key)
|
|
if isRead {
|
|
return cipher.NewCBCDecrypter(block, iv)
|
|
}
|
|
return cipher.NewCBCEncrypter(block, iv)
|
|
}
|
|
|
|
func cipherAES(key, iv []byte, isRead bool) interface{} {
|
|
block, _ := aes.NewCipher(key)
|
|
if isRead {
|
|
return cipher.NewCBCDecrypter(block, iv)
|
|
}
|
|
return cipher.NewCBCEncrypter(block, iv)
|
|
}
|
|
|
|
// macSHA1 returns a macFunction for the given protocol version.
|
|
func macSHA1(version uint16, key []byte) macFunction {
|
|
if version == VersionSSL30 {
|
|
mac := ssl30MAC{
|
|
h: sha1.New(),
|
|
key: make([]byte, len(key)),
|
|
}
|
|
copy(mac.key, key)
|
|
return mac
|
|
}
|
|
return tls10MAC{h: hmac.New(newConstantTimeHash(sha1.New), key)}
|
|
}
|
|
|
|
// macSHA256 returns a SHA-256 based MAC. These are only supported in TLS 1.2
|
|
// so the given version is ignored.
|
|
func macSHA256(version uint16, key []byte) macFunction {
|
|
return tls10MAC{h: hmac.New(sha256.New, key)}
|
|
}
|
|
|
|
type macFunction interface {
|
|
// Size returns the length of the MAC.
|
|
Size() int
|
|
// MAC appends the MAC of (seq, header, data) to out. The extra data is fed
|
|
// into the MAC after obtaining the result to normalize timing. The result
|
|
// is only valid until the next invocation of MAC as the buffer is reused.
|
|
MAC(seq, header, data, extra []byte) []byte
|
|
}
|
|
|
|
type aead interface {
|
|
cipher.AEAD
|
|
|
|
// explicitNonceLen returns the number of bytes of explicit nonce
|
|
// included in each record. This is eight for older AEADs and
|
|
// zero for modern ones.
|
|
explicitNonceLen() int
|
|
}
|
|
|
|
// fixedNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
|
|
// each call.
|
|
type fixedNonceAEAD struct {
|
|
// nonce contains the fixed part of the nonce in the first four bytes.
|
|
nonce [12]byte
|
|
aead cipher.AEAD
|
|
}
|
|
|
|
func (f *fixedNonceAEAD) NonceSize() int { return 8 }
|
|
func (f *fixedNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
|
func (f *fixedNonceAEAD) explicitNonceLen() int { return 8 }
|
|
|
|
func (f *fixedNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
|
copy(f.nonce[4:], nonce)
|
|
return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
|
|
}
|
|
|
|
func (f *fixedNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
|
|
copy(f.nonce[4:], nonce)
|
|
return f.aead.Open(out, f.nonce[:], plaintext, additionalData)
|
|
}
|
|
|
|
// xoredNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
|
|
// before each call.
|
|
type xorNonceAEAD struct {
|
|
nonceMask [12]byte
|
|
aead cipher.AEAD
|
|
}
|
|
|
|
func (f *xorNonceAEAD) NonceSize() int { return 8 }
|
|
func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
|
|
func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
|
|
|
|
func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func (f *xorNonceAEAD) Open(out, nonce, plaintext, additionalData []byte) ([]byte, error) {
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
result, err := f.aead.Open(out, f.nonceMask[:], plaintext, additionalData)
|
|
for i, b := range nonce {
|
|
f.nonceMask[4+i] ^= b
|
|
}
|
|
|
|
return result, err
|
|
}
|
|
|
|
func aeadAESGCM(key, fixedNonce []byte) cipher.AEAD {
|
|
aes, err := aes.NewCipher(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
aead, err := cipher.NewGCM(aes)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ret := &fixedNonceAEAD{aead: aead}
|
|
copy(ret.nonce[:], fixedNonce)
|
|
return ret
|
|
}
|
|
|
|
func aeadChaCha20Poly1305(key, fixedNonce []byte) cipher.AEAD {
|
|
aead, err := chacha20poly1305.New(key)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
ret := &xorNonceAEAD{aead: aead}
|
|
copy(ret.nonceMask[:], fixedNonce)
|
|
return ret
|
|
}
|
|
|
|
// ssl30MAC implements the SSLv3 MAC function, as defined in
|
|
// www.mozilla.org/projects/security/pki/nss/ssl/draft302.txt section 5.2.3.1
|
|
type ssl30MAC struct {
|
|
h hash.Hash
|
|
key []byte
|
|
buf []byte
|
|
}
|
|
|
|
func (s ssl30MAC) Size() int {
|
|
return s.h.Size()
|
|
}
|
|
|
|
var ssl30Pad1 = [48]byte{0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36}
|
|
|
|
var ssl30Pad2 = [48]byte{0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c, 0x5c}
|
|
|
|
// MAC does not offer constant timing guarantees for SSL v3.0, since it's deemed
|
|
// useless considering the similar, protocol-level POODLE vulnerability.
|
|
func (s ssl30MAC) MAC(seq, header, data, extra []byte) []byte {
|
|
padLength := 48
|
|
if s.h.Size() == 20 {
|
|
padLength = 40
|
|
}
|
|
|
|
s.h.Reset()
|
|
s.h.Write(s.key)
|
|
s.h.Write(ssl30Pad1[:padLength])
|
|
s.h.Write(seq)
|
|
s.h.Write(header[:1])
|
|
s.h.Write(header[3:5])
|
|
s.h.Write(data)
|
|
s.buf = s.h.Sum(s.buf[:0])
|
|
|
|
s.h.Reset()
|
|
s.h.Write(s.key)
|
|
s.h.Write(ssl30Pad2[:padLength])
|
|
s.h.Write(s.buf)
|
|
return s.h.Sum(s.buf[:0])
|
|
}
|
|
|
|
type constantTimeHash interface {
|
|
hash.Hash
|
|
ConstantTimeSum(b []byte) []byte
|
|
}
|
|
|
|
// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
|
|
// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
|
|
type cthWrapper struct {
|
|
h constantTimeHash
|
|
}
|
|
|
|
func (c *cthWrapper) Size() int { return c.h.Size() }
|
|
func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() }
|
|
func (c *cthWrapper) Reset() { c.h.Reset() }
|
|
func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
|
|
func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
|
|
|
|
func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
|
|
return func() hash.Hash {
|
|
return &cthWrapper{h().(constantTimeHash)}
|
|
}
|
|
}
|
|
|
|
// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
|
|
type tls10MAC struct {
|
|
h hash.Hash
|
|
buf []byte
|
|
}
|
|
|
|
func (s tls10MAC) Size() int {
|
|
return s.h.Size()
|
|
}
|
|
|
|
// MAC is guaranteed to take constant time, as long as
|
|
// len(seq)+len(header)+len(data)+len(extra) is constant. extra is not fed into
|
|
// the MAC, but is only provided to make the timing profile constant.
|
|
func (s tls10MAC) MAC(seq, header, data, extra []byte) []byte {
|
|
s.h.Reset()
|
|
s.h.Write(seq)
|
|
s.h.Write(header)
|
|
s.h.Write(data)
|
|
res := s.h.Sum(s.buf[:0])
|
|
if extra != nil {
|
|
s.h.Write(extra)
|
|
}
|
|
return res
|
|
}
|
|
|
|
func rsaKA(version uint16) keyAgreement {
|
|
return rsaKeyAgreement{}
|
|
}
|
|
|
|
func ecdheECDSAKA(version uint16) keyAgreement {
|
|
return &ecdheKeyAgreement{
|
|
isRSA: false,
|
|
version: version,
|
|
}
|
|
}
|
|
|
|
func ecdheRSAKA(version uint16) keyAgreement {
|
|
return &ecdheKeyAgreement{
|
|
isRSA: true,
|
|
version: version,
|
|
}
|
|
}
|
|
|
|
// mutualCipherSuite returns a cipherSuite given a list of supported
|
|
// ciphersuites and the id requested by the peer.
|
|
func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
|
|
for _, id := range have {
|
|
if id == want {
|
|
for _, suite := range cipherSuites {
|
|
if suite.id == want {
|
|
return suite
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// A list of cipher suite IDs that are, or have been, implemented by this
|
|
// package.
|
|
//
|
|
// Taken from https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
|
|
const (
|
|
TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
|
|
TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
|
|
TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
|
|
TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
|
|
TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
|
|
TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
|
|
TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
|
|
TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
|
|
TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
|
|
TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
|
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
|
|
TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
|
|
TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
|
|
TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
|
|
TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
|
|
TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
|
|
TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
|
|
TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca8
|
|
TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 uint16 = 0xcca9
|
|
|
|
// TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
|
|
// that the client is doing version fallback. See RFC 7507.
|
|
TLS_FALLBACK_SCSV uint16 = 0x5600
|
|
)
|