]> Cypherpunks repositories - gostls13.git/commitdiff
crypto/{cipher,tls,internal/cryptohw}: prioritise AES-GCM when hardware support is...
authorAdam Langley <agl@golang.org>
Mon, 7 Nov 2016 18:25:57 +0000 (10:25 -0800)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 7 Nov 2016 20:01:18 +0000 (20:01 +0000)
Support for ChaCha20-Poly1305 ciphers was recently added to crypto/tls.
These ciphers are preferable in software, but they cannot beat hardware
support for AES-GCM, if present.

This change moves detection for hardware AES-GCM support into
cipher/internal/cipherhw so that it can be used from crypto/tls. Then,
when AES-GCM hardware is present, the AES-GCM cipher suites are
prioritised by default in crypto/tls. (Some servers, such as Google,
respect the client's preference between AES-GCM and ChaCha20-Poly1305.)

Fixes #17779.

Change-Id: I50de2be486f0b0b8052c4628d3e3205a1d54a646
Reviewed-on: https://go-review.googlesource.com/32871
Run-TryBot: Adam Langley <agl@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>

12 files changed:
src/crypto/aes/asm_amd64.s
src/crypto/aes/asm_s390x.s
src/crypto/aes/cipher_amd64.go
src/crypto/aes/cipher_s390x.go
src/crypto/internal/cipherhw/asm_amd64.s [new file with mode: 0644]
src/crypto/internal/cipherhw/asm_s390x.s [new file with mode: 0644]
src/crypto/internal/cipherhw/cipherhw_amd64.go [new file with mode: 0644]
src/crypto/internal/cipherhw/cipherhw_s390x.go [new file with mode: 0644]
src/crypto/internal/cipherhw/doc.go [new file with mode: 0644]
src/crypto/internal/cipherhw/generic.go [new file with mode: 0644]
src/crypto/tls/common.go
src/go/build/deps_test.go

index b2579987d8d25900ca30c5e374cf014d11a2ffab..ad871ec5dee57629b2274b002c6a658a3db173ef 100644 (file)
@@ -4,17 +4,6 @@
 
 #include "textflag.h"
 
-// func hasAsm() bool
-// returns whether AES-NI is supported
-TEXT ·hasAsm(SB),NOSPLIT,$0
-       XORQ AX, AX
-       INCL AX
-       CPUID
-       SHRQ $25, CX
-       ANDQ $1, CX
-       MOVB CX, ret+0(FP)
-       RET
-
 // func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
 TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
        MOVQ nr+0(FP), CX
index 6f2c932e0b7a79a7048b8f26a2c5907a6ae798c8..2cf3dddea88e8c917626f3841698befec49986f0 100644 (file)
@@ -4,43 +4,6 @@
 
 #include "textflag.h"
 
-// func hasAsm() bool
-TEXT ·hasAsm(SB),NOSPLIT,$16-1
-       XOR     R0, R0          // set function code to 0 (query)
-       LA      mask-16(SP), R1 // 16-byte stack variable for mask
-       MOVD    $(0x38<<40), R3 // mask for bits 18-20 (big endian)
-
-       // check for KM AES functions
-       WORD    $0xB92E0024 // cipher message (KM)
-       MOVD    mask-16(SP), R2
-       AND     R3, R2
-       CMPBNE  R2, R3, notfound
-
-       // check for KMC AES functions
-       WORD    $0xB92F0024 // cipher message with chaining (KMC)
-       MOVD    mask-16(SP), R2
-       AND     R3, R2
-       CMPBNE  R2, R3, notfound
-
-       // check for KMCTR AES functions
-       WORD    $0xB92D4024 // cipher message with counter (KMCTR)
-       MOVD    mask-16(SP), R2
-       AND     R3, R2
-       CMPBNE  R2, R3, notfound
-
-       // check for KIMD GHASH function
-       WORD    $0xB93E0024    // compute intermediate message digest (KIMD)
-       MOVD    mask-8(SP), R2 // bits 64-127
-       MOVD    $(1<<62), R5
-       AND     R5, R2
-       CMPBNE  R2, R5, notfound
-
-       MOVB    $1, ret+0(FP)
-       RET
-notfound:
-       MOVB    $0, ret+0(FP)
-       RET
-
 // func cryptBlocks(c code, key, dst, src *byte, length int)
 TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
        MOVD    key+8(FP), R1
index b33c8ff251ac7cbdf89f3c927e41fe9288241064..43de3bdffdd2be57f0d4db20b0a8b904d2618dc0 100644 (file)
@@ -6,10 +6,10 @@ package aes
 
 import (
        "crypto/cipher"
+       "crypto/internal/cipherhw"
 )
 
 // defined in asm_amd64.s
-func hasAsm() bool
 func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
 func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
 func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
@@ -18,7 +18,7 @@ type aesCipherAsm struct {
        aesCipher
 }
 
-var useAsm = hasAsm()
+var useAsm = cipherhw.AESGCMSupport()
 
 func newCipher(key []byte) (cipher.Block, error) {
        if !useAsm {
index bec59330132c52bf0f458ab83bf674afd2be7702..6030c25ee37b82a9ed8adc180958a1b54f307e78 100644 (file)
@@ -6,6 +6,7 @@ package aes
 
 import (
        "crypto/cipher"
+       "crypto/internal/cipherhw"
 )
 
 type code int
@@ -23,18 +24,13 @@ type aesCipherAsm struct {
        storage  [256]byte // array backing key slice
 }
 
-// hasAsm reports whether the AES-128, AES-192 and AES-256
-// cipher message (KM) function codes are supported.
-// Note: this function call is expensive.
-func hasAsm() bool
-
 // cryptBlocks invokes the cipher message (KM) instruction with
 // the given function code. This is equivalent to AES in ECB
 // mode. The length must be a multiple of BlockSize (16).
 //go:noesape
 func cryptBlocks(c code, key, dst, src *byte, length int)
 
-var useAsm = hasAsm()
+var useAsm = cipherhw.AESGCMSupport()
 
 func newCipher(key []byte) (cipher.Block, error) {
        if !useAsm {
diff --git a/src/crypto/internal/cipherhw/asm_amd64.s b/src/crypto/internal/cipherhw/asm_amd64.s
new file mode 100644 (file)
index 0000000..dd1afd4
--- /dev/null
@@ -0,0 +1,17 @@
+// Copyright 2016 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.
+
+// +build amd64,!gccgo,!appengine
+
+#include "textflag.h"
+
+// func hasAESNI() bool
+TEXT ·hasAESNI(SB),NOSPLIT,$0
+       XORQ AX, AX
+       INCL AX
+       CPUID
+       SHRQ $25, CX
+       ANDQ $1, CX
+       MOVB CX, ret+0(FP)
+       RET
diff --git a/src/crypto/internal/cipherhw/asm_s390x.s b/src/crypto/internal/cipherhw/asm_s390x.s
new file mode 100644 (file)
index 0000000..51dc1c6
--- /dev/null
@@ -0,0 +1,44 @@
+// Copyright 2016 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.
+
+// +build s390x,!gccgo,!appengine
+
+#include "textflag.h"
+
+// func hasHWSupport() bool
+TEXT ·hasHWSupport(SB),NOSPLIT,$16-1
+       XOR     R0, R0          // set function code to 0 (query)
+       LA      mask-16(SP), R1 // 16-byte stack variable for mask
+       MOVD    $(0x38<<40), R3 // mask for bits 18-20 (big endian)
+
+       // check for KM AES functions
+       WORD    $0xB92E0024 // cipher message (KM)
+       MOVD    mask-16(SP), R2
+       AND     R3, R2
+       CMPBNE  R2, R3, notfound
+
+       // check for KMC AES functions
+       WORD    $0xB92F0024 // cipher message with chaining (KMC)
+       MOVD    mask-16(SP), R2
+       AND     R3, R2
+       CMPBNE  R2, R3, notfound
+
+       // check for KMCTR AES functions
+       WORD    $0xB92D4024 // cipher message with counter (KMCTR)
+       MOVD    mask-16(SP), R2
+       AND     R3, R2
+       CMPBNE  R2, R3, notfound
+
+       // check for KIMD GHASH function
+       WORD    $0xB93E0024    // compute intermediate message digest (KIMD)
+       MOVD    mask-8(SP), R2 // bits 64-127
+       MOVD    $(1<<62), R5
+       AND     R5, R2
+       CMPBNE  R2, R5, notfound
+
+       MOVB    $1, ret+0(FP)
+       RET
+notfound:
+       MOVB    $0, ret+0(FP)
+       RET
diff --git a/src/crypto/internal/cipherhw/cipherhw_amd64.go b/src/crypto/internal/cipherhw/cipherhw_amd64.go
new file mode 100644 (file)
index 0000000..be0d490
--- /dev/null
@@ -0,0 +1,16 @@
+// Copyright 2016 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.
+
+// +build amd64,!gccgo,!appengine
+
+package cipherhw
+
+// defined in asm_amd64.s
+func hasAESNI() bool
+
+// AESGCMSupport returns true if the Go standard library supports AES-GCM in
+// hardware.
+func AESGCMSupport() bool {
+       return hasAESNI()
+}
diff --git a/src/crypto/internal/cipherhw/cipherhw_s390x.go b/src/crypto/internal/cipherhw/cipherhw_s390x.go
new file mode 100644 (file)
index 0000000..9cd7679
--- /dev/null
@@ -0,0 +1,18 @@
+// Copyright 2016 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.
+
+// +build s390x,!gccgo,!appengine
+
+package cipherhw
+
+// hasHWSupport reports whether the AES-128, AES-192 and AES-256 cipher message
+// (KM) function codes are supported. Note that this function is expensive.
+// defined in asm_s390x.s
+func hasHWSupport() bool
+
+var hwSupport = hasHWSupport()
+
+func AESGCMSupport() bool {
+       return hwSupport
+}
diff --git a/src/crypto/internal/cipherhw/doc.go b/src/crypto/internal/cipherhw/doc.go
new file mode 100644 (file)
index 0000000..a75fcf6
--- /dev/null
@@ -0,0 +1,7 @@
+// Copyright 2016 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 cipherhw exposes common functions for detecting whether hardware
+// support for certain ciphers and authenticators is present.
+package cipherhw
diff --git a/src/crypto/internal/cipherhw/generic.go b/src/crypto/internal/cipherhw/generic.go
new file mode 100644 (file)
index 0000000..64d90d3
--- /dev/null
@@ -0,0 +1,11 @@
+// Copyright 2016 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.
+
+// +build !amd64,!s390x gccgo appengine
+
+package cipherhw
+
+func AESGCMSupport() bool {
+       return false
+}
index 5b2c6664b2fb064b4adf929bd3127a356c65c0b1..276d1761ea04033672d5ad0354327fa36bd34a4c 100644 (file)
@@ -7,6 +7,7 @@ package tls
 import (
        "container/list"
        "crypto"
+       "crypto/internal/cipherhw"
        "crypto/rand"
        "crypto/sha512"
        "crypto/x509"
@@ -919,11 +920,46 @@ func defaultCipherSuites() []uint16 {
 }
 
 func initDefaultCipherSuites() {
+       var topCipherSuites []uint16
+       if cipherhw.AESGCMSupport() {
+               // If AES-GCM hardware is provided then prioritise AES-GCM
+               // cipher suites.
+               topCipherSuites = []uint16{
+                       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+                       TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+                       TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+                       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+                       TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+               }
+       } else {
+               // Without AES-GCM hardware, we put the ChaCha20-Poly1305
+               // cipher suites first.
+               topCipherSuites = []uint16{
+                       TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+                       TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+                       TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+                       TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+                       TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+                       TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+               }
+       }
+
        varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
+       for _, topCipher := range topCipherSuites {
+               varDefaultCipherSuites = append(varDefaultCipherSuites, topCipher)
+       }
+
+NextCipherSuite:
        for _, suite := range cipherSuites {
                if suite.flags&suiteDefaultOff != 0 {
                        continue
                }
+               for _, existing := range varDefaultCipherSuites {
+                       if existing == suite.id {
+                               continue NextCipherSuite
+                       }
+               }
                varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
        }
 }
index d4877f7aeb5f6643164166eee88e5d0c43cd83e4..5337891f8e69ab5fc627b0e98876857afe263dc9 100644 (file)
@@ -94,7 +94,7 @@ var pkgDeps = map[string][]string{
        // and interface definitions, but nothing that makes
        // system calls.
        "crypto":              {"L2", "hash"},          // interfaces
-       "crypto/cipher":       {"L2", "crypto/subtle"}, // interfaces
+       "crypto/cipher":       {"L2", "crypto/subtle"},
        "crypto/subtle":       {},
        "encoding/base32":     {"L2"},
        "encoding/base64":     {"L2"},
@@ -114,6 +114,7 @@ var pkgDeps = map[string][]string{
                "L2",
                "crypto",
                "crypto/cipher",
+               "crypto/internal/cipherhw",
                "crypto/subtle",
                "encoding/base32",
                "encoding/base64",