]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/tls: drop macFunction abstraction
authorFilippo Valsorda <filippo@golang.org>
Mon, 31 Aug 2020 21:09:57 +0000 (17:09 -0400)
committerFilippo Valsorda <filippo@golang.org>
Mon, 9 Nov 2020 19:00:00 +0000 (19:00 +0000)
Since we dropped SSLv3, there is only one MAC scheme, and it doesn't
need any state beyond a keyed HMAC, so we can replace the macFunction
with the hash.Hash it wraps.

Pointed out by mtp@.

Change-Id: I5545be0e6ccb34a3055fad7f6cb5f628ff748e9f
Reviewed-on: https://go-review.googlesource.com/c/go/+/251859
Run-TryBot: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Roland Shoemaker <roland@golang.org>
Trust: Roland Shoemaker <roland@golang.org>
Trust: Filippo Valsorda <filippo@golang.org>

src/crypto/tls/cipher_suites.go
src/crypto/tls/conn.go
src/crypto/tls/handshake_client.go
src/crypto/tls/handshake_server.go

index ea16ef95bf05c7f5ffd3d6907f0b5965fa9f44e3..9a356758fbfc5dc09835bc6db3c1cee86983f5f1 100644 (file)
@@ -160,7 +160,7 @@ type cipherSuite struct {
        // 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
 }
 
@@ -247,24 +247,15 @@ func cipherAES(key, iv []byte, isRead bool) interface{} {
        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 {
@@ -412,26 +403,14 @@ func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
 }
 
 // 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
 }
index 2f5d4303c251672ac4b6c7ebddc6714a54fe02cf..2788c3c3934d2144217ea285fddb20a50ded485a 100644 (file)
@@ -14,6 +14,7 @@ import (
        "crypto/x509"
        "errors"
        "fmt"
+       "hash"
        "io"
        "net"
        "sync"
@@ -155,15 +156,16 @@ func (c *Conn) SetWriteDeadline(t time.Time) error {
 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
 }
@@ -188,7 +190,7 @@ func (hc *halfConn) setErrorLocked(err error) error {
 
 // 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
@@ -350,15 +352,14 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
                        }
                        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
@@ -424,7 +425,7 @@ func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, 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
@@ -460,7 +461,7 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) {
 }
 
 // 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
@@ -477,7 +478,7 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
                        // 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 {
@@ -487,14 +488,10 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
                }
        }
 
-       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)
@@ -518,11 +515,12 @@ func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, err
                        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
index d09a8c8ccfd90a7227df8ce7f5b65cb02f864c0a..123df7b07a096143c841da84754cdfaec41cc3f7 100644 (file)
@@ -15,6 +15,7 @@ import (
        "crypto/x509"
        "errors"
        "fmt"
+       "hash"
        "io"
        "net"
        "strings"
@@ -651,12 +652,12 @@ func (hs *clientHandshakeState) establishKeys() error {
        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)
index 1fe026ae0e09682169d169aa99d949242d182a4b..73df19d10f5dbc2a853c6c45f20f745144568287 100644 (file)
@@ -14,6 +14,7 @@ import (
        "crypto/x509"
        "errors"
        "fmt"
+       "hash"
        "io"
        "sync/atomic"
        "time"
@@ -645,13 +646,13 @@ func (hs *serverHandshakeState) establishKeys() error {
                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)