mirror of https://github.com/golang/go.git
crypto/{cipher,tls,internal/cryptohw}: prioritise AES-GCM when hardware support is present.
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>
This commit is contained in:
parent
9e4a70e8fd
commit
a9ce0f96e1
|
|
@ -4,17 +4,6 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#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)
|
// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
|
||||||
TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
|
TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
|
||||||
MOVQ nr+0(FP), CX
|
MOVQ nr+0(FP), CX
|
||||||
|
|
|
||||||
|
|
@ -4,43 +4,6 @@
|
||||||
|
|
||||||
#include "textflag.h"
|
#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)
|
// func cryptBlocks(c code, key, dst, src *byte, length int)
|
||||||
TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
|
TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
|
||||||
MOVD key+8(FP), R1
|
MOVD key+8(FP), R1
|
||||||
|
|
|
||||||
|
|
@ -6,10 +6,10 @@ package aes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/internal/cipherhw"
|
||||||
)
|
)
|
||||||
|
|
||||||
// defined in asm_amd64.s
|
// defined in asm_amd64.s
|
||||||
func hasAsm() bool
|
|
||||||
func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
|
func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
|
||||||
func decryptBlockAsm(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)
|
func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
|
||||||
|
|
@ -18,7 +18,7 @@ type aesCipherAsm struct {
|
||||||
aesCipher
|
aesCipher
|
||||||
}
|
}
|
||||||
|
|
||||||
var useAsm = hasAsm()
|
var useAsm = cipherhw.AESGCMSupport()
|
||||||
|
|
||||||
func newCipher(key []byte) (cipher.Block, error) {
|
func newCipher(key []byte) (cipher.Block, error) {
|
||||||
if !useAsm {
|
if !useAsm {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ package aes
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/cipher"
|
"crypto/cipher"
|
||||||
|
"crypto/internal/cipherhw"
|
||||||
)
|
)
|
||||||
|
|
||||||
type code int
|
type code int
|
||||||
|
|
@ -23,18 +24,13 @@ type aesCipherAsm struct {
|
||||||
storage [256]byte // array backing key slice
|
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
|
// cryptBlocks invokes the cipher message (KM) instruction with
|
||||||
// the given function code. This is equivalent to AES in ECB
|
// the given function code. This is equivalent to AES in ECB
|
||||||
// mode. The length must be a multiple of BlockSize (16).
|
// mode. The length must be a multiple of BlockSize (16).
|
||||||
//go:noesape
|
//go:noesape
|
||||||
func cryptBlocks(c code, key, dst, src *byte, length int)
|
func cryptBlocks(c code, key, dst, src *byte, length int)
|
||||||
|
|
||||||
var useAsm = hasAsm()
|
var useAsm = cipherhw.AESGCMSupport()
|
||||||
|
|
||||||
func newCipher(key []byte) (cipher.Block, error) {
|
func newCipher(key []byte) (cipher.Block, error) {
|
||||||
if !useAsm {
|
if !useAsm {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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()
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
@ -7,6 +7,7 @@ package tls
|
||||||
import (
|
import (
|
||||||
"container/list"
|
"container/list"
|
||||||
"crypto"
|
"crypto"
|
||||||
|
"crypto/internal/cipherhw"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/sha512"
|
"crypto/sha512"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
|
@ -919,11 +920,46 @@ func defaultCipherSuites() []uint16 {
|
||||||
}
|
}
|
||||||
|
|
||||||
func initDefaultCipherSuites() {
|
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))
|
varDefaultCipherSuites = make([]uint16, 0, len(cipherSuites))
|
||||||
|
for _, topCipher := range topCipherSuites {
|
||||||
|
varDefaultCipherSuites = append(varDefaultCipherSuites, topCipher)
|
||||||
|
}
|
||||||
|
|
||||||
|
NextCipherSuite:
|
||||||
for _, suite := range cipherSuites {
|
for _, suite := range cipherSuites {
|
||||||
if suite.flags&suiteDefaultOff != 0 {
|
if suite.flags&suiteDefaultOff != 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
for _, existing := range varDefaultCipherSuites {
|
||||||
|
if existing == suite.id {
|
||||||
|
continue NextCipherSuite
|
||||||
|
}
|
||||||
|
}
|
||||||
varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
|
varDefaultCipherSuites = append(varDefaultCipherSuites, suite.id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ var pkgDeps = map[string][]string{
|
||||||
// and interface definitions, but nothing that makes
|
// and interface definitions, but nothing that makes
|
||||||
// system calls.
|
// system calls.
|
||||||
"crypto": {"L2", "hash"}, // interfaces
|
"crypto": {"L2", "hash"}, // interfaces
|
||||||
"crypto/cipher": {"L2", "crypto/subtle"}, // interfaces
|
"crypto/cipher": {"L2", "crypto/subtle"},
|
||||||
"crypto/subtle": {},
|
"crypto/subtle": {},
|
||||||
"encoding/base32": {"L2"},
|
"encoding/base32": {"L2"},
|
||||||
"encoding/base64": {"L2"},
|
"encoding/base64": {"L2"},
|
||||||
|
|
@ -114,6 +114,7 @@ var pkgDeps = map[string][]string{
|
||||||
"L2",
|
"L2",
|
||||||
"crypto",
|
"crypto",
|
||||||
"crypto/cipher",
|
"crypto/cipher",
|
||||||
|
"crypto/internal/cipherhw",
|
||||||
"crypto/subtle",
|
"crypto/subtle",
|
||||||
"encoding/base32",
|
"encoding/base32",
|
||||||
"encoding/base64",
|
"encoding/base64",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue