Commit a9ce0f96 authored by Adam Langley's avatar Adam Langley Committed by Brad Fitzpatrick

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: 's avatarBrad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 9e4a70e8
......@@ -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
......
......@@ -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
......
......@@ -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 {
......
......@@ -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 {
......
// 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
// 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
// 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()
}
// 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
}
// 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
// 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 (
"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)
}
}
......
......@@ -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",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment