// 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
+ mac func(key []byte) hash.Hash
aead func(key, fixedNonce []byte) aead
}
return cipher.NewCBCEncrypter(block, iv)
}
-// macSHA1 returns a macFunction for the given protocol version.
-func macSHA1(version uint16, key []byte) macFunction {
- return tls10MAC{h: hmac.New(newConstantTimeHash(sha1.New), key)}
+// macSHA1 returns a SHA-1 based constant time MAC.
+func macSHA1(key []byte) hash.Hash {
+ return 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
+// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
+// is currently only used in disabled-by-default cipher suites.
+func macSHA256(key []byte) hash.Hash {
+ return hmac.New(sha256.New, key)
}
type aead interface {
}
// 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])
+func tls10MAC(h hash.Hash, out, seq, header, data, extra []byte) []byte {
+ h.Reset()
+ h.Write(seq)
+ h.Write(header)
+ h.Write(data)
+ res := h.Sum(out)
if extra != nil {
- s.h.Write(extra)
+ h.Write(extra)
}
return res
}
"crypto/x509"
"errors"
"fmt"
+ "hash"
"io"
"net"
"sync"
type halfConn struct {
sync.Mutex
- err error // first permanent error
- version uint16 // protocol version
- cipher interface{} // cipher algorithm
- mac macFunction
- seq [8]byte // 64-bit sequence number
- additionalData [13]byte // to avoid allocs; interface method args escape
+ err error // first permanent error
+ version uint16 // protocol version
+ cipher interface{} // cipher algorithm
+ mac hash.Hash
+ seq [8]byte // 64-bit sequence number
+
+ scratchBuf [13]byte // to avoid allocs; interface method args escape
nextCipher interface{} // next encryption state
- nextMac macFunction // next MAC algorithm
+ nextMac hash.Hash // next MAC algorithm
trafficSecret []byte // current TLS 1.3 traffic secret
}
// prepareCipherSpec sets the encryption and MAC states
// that a subsequent changeCipherSpec will use.
-func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac macFunction) {
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher interface{}, mac hash.Hash) {
hc.version = version
hc.nextCipher = cipher
hc.nextMac = mac
}
payload = payload[explicitNonceLen:]
- additionalData := hc.additionalData[:]
+ var additionalData []byte
if hc.version == VersionTLS13 {
additionalData = record[:recordHeaderLen]
} else {
- copy(additionalData, hc.seq[:])
- copy(additionalData[8:], record[:3])
+ additionalData = append(hc.scratchBuf[:0], hc.seq[:]...)
+ additionalData = append(additionalData, record[:3]...)
n := len(payload) - c.Overhead()
- additionalData[11] = byte(n >> 8)
- additionalData[12] = byte(n)
+ additionalData = append(additionalData, byte(n>>8), byte(n))
}
var err error
record[3] = byte(n >> 8)
record[4] = byte(n)
remoteMAC := payload[n : n+macSize]
- localMAC := hc.mac.MAC(hc.seq[0:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
+ localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
// This is equivalent to checking the MACs and paddingGood
// separately, but in constant-time to prevent distinguishing
}
// encrypt encrypts payload, adding the appropriate nonce and/or MAC, and
-// appends it to record, which contains the record header.
+// appends it to record, which must already contain the record header.
func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) {
if hc.cipher == nil {
return append(record, payload...), nil
// an 8 bytes nonce but its nonces must be unpredictable (see RFC
// 5246, Appendix F.3), forcing us to use randomness. That's not
// 3DES' biggest problem anyway because the birthday bound on block
- // collision is reached first due to its simlarly small block size
+ // collision is reached first due to its similarly small block size
// (see the Sweet32 attack).
copy(explicitNonce, hc.seq[:])
} else {
}
}
- var mac []byte
- if hc.mac != nil {
- mac = hc.mac.MAC(hc.seq[:], record[:recordHeaderLen], payload, nil)
- }
-
var dst []byte
switch c := hc.cipher.(type) {
case cipher.Stream:
+ mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
record, dst = sliceForAppend(record, len(payload)+len(mac))
c.XORKeyStream(dst[:len(payload)], payload)
c.XORKeyStream(dst[len(payload):], mac)
record = c.Seal(record[:recordHeaderLen],
nonce, record[recordHeaderLen:], record[:recordHeaderLen])
} else {
- copy(hc.additionalData[:], hc.seq[:])
- copy(hc.additionalData[8:], record)
- record = c.Seal(record, nonce, payload, hc.additionalData[:])
+ additionalData := append(hc.scratchBuf[:0], hc.seq[:]...)
+ additionalData = append(additionalData, record[:recordHeaderLen]...)
+ record = c.Seal(record, nonce, payload, additionalData)
}
case cbcMode:
+ mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
blockSize := c.BlockSize()
plaintextLen := len(payload) + len(mac)
paddingLen := blockSize - plaintextLen%blockSize
"crypto/x509"
"errors"
"fmt"
+ "hash"
"io"
"net"
"strings"
clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
var clientCipher, serverCipher interface{}
- var clientHash, serverHash macFunction
+ var clientHash, serverHash hash.Hash
if hs.suite.cipher != nil {
clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
- clientHash = hs.suite.mac(c.vers, clientMAC)
+ clientHash = hs.suite.mac(clientMAC)
serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
- serverHash = hs.suite.mac(c.vers, serverMAC)
+ serverHash = hs.suite.mac(serverMAC)
} else {
clientCipher = hs.suite.aead(clientKey, clientIV)
serverCipher = hs.suite.aead(serverKey, serverIV)
"crypto/x509"
"errors"
"fmt"
+ "hash"
"io"
"sync/atomic"
"time"
keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
var clientCipher, serverCipher interface{}
- var clientHash, serverHash macFunction
+ var clientHash, serverHash hash.Hash
if hs.suite.aead == nil {
clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
- clientHash = hs.suite.mac(c.vers, clientMAC)
+ clientHash = hs.suite.mac(clientMAC)
serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
- serverHash = hs.suite.mac(c.vers, serverMAC)
+ serverHash = hs.suite.mac(serverMAC)
} else {
clientCipher = hs.suite.aead(clientKey, clientIV)
serverCipher = hs.suite.aead(serverKey, serverIV)