diff options
Diffstat (limited to 'src/crypto/internal/boring')
23 files changed, 2722 insertions, 0 deletions
diff --git a/src/crypto/internal/boring/LICENSE b/src/crypto/internal/boring/LICENSE new file mode 100644 index 0000000000..58ce9601a3 --- /dev/null +++ b/src/crypto/internal/boring/LICENSE @@ -0,0 +1,200 @@ +The Go source code and supporting files in this directory +are covered by the usual Go license (see ../../../../LICENSE). + +The goboringcrypto_linux_amd64.syso object file is built +from BoringSSL source code by build/build.sh and is covered +by the BoringSSL license reproduced below and also at +https://boringssl.googlesource.com/boringssl/+/fips-20180730/LICENSE. + +BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL +licensing. Files that are completely new have a Google copyright and an ISC +license. This license is reproduced at the bottom of this file. + +Contributors to BoringSSL are required to follow the CLA rules for Chromium: +https://cla.developers.google.com/clas + +Some files from Intel are under yet another license, which is also included +underneath. + +The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the +OpenSSL License and the original SSLeay license apply to the toolkit. See below +for the actual license texts. Actually both licenses are BSD-style Open Source +licenses. In case of any license issues related to OpenSSL please contact +openssl-core@openssl.org. + +The following are Google-internal bug numbers where explicit permission from +some authors is recorded for use of their work. (This is purely for our own +record keeping.) + 27287199 + 27287880 + 27287883 + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + +ISC license used for completely new code in BoringSSL: + +/* Copyright (c) 2015, Google Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + + +Some files from Intel carry the following license: + +# Copyright (c) 2012, Intel Corporation +# +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the +# distribution. +# +# * Neither the name of the Intel Corporation nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# +# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/crypto/internal/boring/aes.go b/src/crypto/internal/boring/aes.go new file mode 100644 index 0000000000..504a841cd8 --- /dev/null +++ b/src/crypto/internal/boring/aes.go @@ -0,0 +1,391 @@ +// Copyright 2017 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 linux,amd64 +// +build !android +// +build !cmd_go_bootstrap +// +build !msan + +package boring + +/* + +#include "goboringcrypto.h" + +// These wrappers allocate out_len on the C stack, and check that it matches the expected +// value, to avoid having to pass a pointer from Go, which would escape to the heap. + +int EVP_AEAD_CTX_seal_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out, + size_t exp_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t out_len; + int ok = _goboringcrypto_EVP_AEAD_CTX_seal(ctx, out, &out_len, exp_out_len, + nonce, nonce_len, in, in_len, ad, ad_len); + if (out_len != exp_out_len) { + return 0; + } + return ok; +}; + +int EVP_AEAD_CTX_open_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out, + size_t exp_out_len, + const uint8_t *nonce, size_t nonce_len, + const uint8_t *in, size_t in_len, + const uint8_t *ad, size_t ad_len) { + size_t out_len; + int ok = _goboringcrypto_EVP_AEAD_CTX_open(ctx, out, &out_len, exp_out_len, + nonce, nonce_len, in, in_len, ad, ad_len); + if (out_len != exp_out_len) { + return 0; + } + return ok; +}; + +*/ +import "C" +import ( + "crypto/cipher" + "errors" + "runtime" + "strconv" + "unsafe" +) + +type aesKeySizeError int + +func (k aesKeySizeError) Error() string { + return "crypto/aes: invalid key size " + strconv.Itoa(int(k)) +} + +const aesBlockSize = 16 + +type aesCipher struct { + key []byte + enc C.GO_AES_KEY + dec C.GO_AES_KEY +} + +type extraModes interface { + // Copied out of crypto/aes/modes.go. + NewCBCEncrypter(iv []byte) cipher.BlockMode + NewCBCDecrypter(iv []byte) cipher.BlockMode + NewCTR(iv []byte) cipher.Stream + NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) + + // Invented for BoringCrypto. + NewGCMTLS() (cipher.AEAD, error) +} + +var _ extraModes = (*aesCipher)(nil) + +func NewAESCipher(key []byte) (cipher.Block, error) { + c := &aesCipher{key: make([]byte, len(key))} + copy(c.key, key) + // Note: 0 is success, contradicting the usual BoringCrypto convention. + if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 || + C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 { + return nil, aesKeySizeError(len(key)) + } + return c, nil +} + +func (c *aesCipher) BlockSize() int { return aesBlockSize } + +func (c *aesCipher) Encrypt(dst, src []byte) { + if inexactOverlap(dst, src) { + panic("crypto/cipher: invalid buffer overlap") + } + if len(src) < aesBlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < aesBlockSize { + panic("crypto/aes: output not full block") + } + C._goboringcrypto_AES_encrypt( + (*C.uint8_t)(unsafe.Pointer(&src[0])), + (*C.uint8_t)(unsafe.Pointer(&dst[0])), + &c.enc) +} + +func (c *aesCipher) Decrypt(dst, src []byte) { + if inexactOverlap(dst, src) { + panic("crypto/cipher: invalid buffer overlap") + } + if len(src) < aesBlockSize { + panic("crypto/aes: input not full block") + } + if len(dst) < aesBlockSize { + panic("crypto/aes: output not full block") + } + C._goboringcrypto_AES_decrypt( + (*C.uint8_t)(unsafe.Pointer(&src[0])), + (*C.uint8_t)(unsafe.Pointer(&dst[0])), + &c.dec) +} + +type aesCBC struct { + key *C.GO_AES_KEY + mode C.int + iv [aesBlockSize]byte +} + +func (x *aesCBC) BlockSize() int { return aesBlockSize } + +func (x *aesCBC) CryptBlocks(dst, src []byte) { + if inexactOverlap(dst, src) { + panic("crypto/cipher: invalid buffer overlap") + } + if len(src)%aesBlockSize != 0 { + panic("crypto/cipher: input not full blocks") + } + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if len(src) > 0 { + C._goboringcrypto_AES_cbc_encrypt( + (*C.uint8_t)(unsafe.Pointer(&src[0])), + (*C.uint8_t)(unsafe.Pointer(&dst[0])), + C.size_t(len(src)), x.key, + (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode) + } +} + +func (x *aesCBC) SetIV(iv []byte) { + if len(iv) != aesBlockSize { + panic("cipher: incorrect length IV") + } + copy(x.iv[:], iv) +} + +func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode { + x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT} + copy(x.iv[:], iv) + return x +} + +func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode { + x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT} + copy(x.iv[:], iv) + return x +} + +type aesCTR struct { + key *C.GO_AES_KEY + iv [aesBlockSize]byte + num C.uint + ecount_buf [16]C.uint8_t +} + +func (x *aesCTR) XORKeyStream(dst, src []byte) { + if inexactOverlap(dst, src) { + panic("crypto/cipher: invalid buffer overlap") + } + if len(dst) < len(src) { + panic("crypto/cipher: output smaller than input") + } + if len(src) == 0 { + return + } + C._goboringcrypto_AES_ctr128_encrypt( + (*C.uint8_t)(unsafe.Pointer(&src[0])), + (*C.uint8_t)(unsafe.Pointer(&dst[0])), + C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), + &x.ecount_buf[0], &x.num) +} + +func (c *aesCipher) NewCTR(iv []byte) cipher.Stream { + x := &aesCTR{key: &c.enc} + copy(x.iv[:], iv) + return x +} + +type aesGCM struct { + ctx C.GO_EVP_AEAD_CTX + aead *C.GO_EVP_AEAD +} + +const ( + gcmBlockSize = 16 + gcmTagSize = 16 + gcmStandardNonceSize = 12 +) + +type aesNonceSizeError int + +func (n aesNonceSizeError) Error() string { + return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n)) +} + +type noGCM struct { + cipher.Block +} + +func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) { + if nonceSize != gcmStandardNonceSize && tagSize != gcmTagSize { + return nil, errors.New("crypto/aes: GCM tag and nonce sizes can't be non-standard at the same time") + } + // Fall back to standard library for GCM with non-standard nonce or tag size. + if nonceSize != gcmStandardNonceSize { + return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize) + } + if tagSize != gcmTagSize { + return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize) + } + return c.newGCM(false) +} + +func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) { + return c.newGCM(true) +} + +func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) { + var aead *C.GO_EVP_AEAD + switch len(c.key) * 8 { + case 128: + if tls { + aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12() + } else { + aead = C._goboringcrypto_EVP_aead_aes_128_gcm() + } + case 256: + if tls { + aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12() + } else { + aead = C._goboringcrypto_EVP_aead_aes_256_gcm() + } + default: + // Fall back to standard library for GCM with non-standard key size. + return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize) + } + + g := &aesGCM{aead: aead} + if C._goboringcrypto_EVP_AEAD_CTX_init(&g.ctx, aead, (*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.size_t(len(c.key)), C.GO_EVP_AEAD_DEFAULT_TAG_LENGTH, nil) == 0 { + return nil, fail("EVP_AEAD_CTX_init") + } + // Note: Because of the finalizer, any time g.ctx is passed to cgo, + // that call must be followed by a call to runtime.KeepAlive(g), + // to make sure g is not collected (and finalized) before the cgo + // call returns. + runtime.SetFinalizer(g, (*aesGCM).finalize) + if g.NonceSize() != gcmStandardNonceSize { + panic("boringcrypto: internal confusion about nonce size") + } + if g.Overhead() != gcmTagSize { + panic("boringcrypto: internal confusion about tag size") + } + + return g, nil +} + +func (g *aesGCM) finalize() { + C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx) +} + +func (g *aesGCM) NonceSize() int { + return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead)) +} + +func (g *aesGCM) Overhead() int { + return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead)) +} + +// base returns the address of the underlying array in b, +// being careful not to panic when b has zero length. +func base(b []byte) *C.uint8_t { + if len(b) == 0 { + return nil + } + return (*C.uint8_t)(unsafe.Pointer(&b[0])) +} + +func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte { + if len(nonce) != gcmStandardNonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) { + panic("cipher: message too large for GCM") + } + if len(dst)+len(plaintext)+gcmTagSize < len(dst) { + panic("cipher: message too large for buffer") + } + + // Make room in dst to append plaintext+overhead. + n := len(dst) + for cap(dst) < n+len(plaintext)+gcmTagSize { + dst = append(dst[:cap(dst)], 0) + } + dst = dst[:n+len(plaintext)+gcmTagSize] + + // Check delayed until now to make sure len(dst) is accurate. + if inexactOverlap(dst[n:], plaintext) { + panic("cipher: invalid buffer overlap") + } + + outLen := C.size_t(len(plaintext) + gcmTagSize) + ok := C.EVP_AEAD_CTX_seal_wrapper( + &g.ctx, + (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen, + base(nonce), C.size_t(len(nonce)), + base(plaintext), C.size_t(len(plaintext)), + base(additionalData), C.size_t(len(additionalData))) + runtime.KeepAlive(g) + if ok == 0 { + panic(fail("EVP_AEAD_CTX_seal")) + } + return dst[:n+int(outLen)] +} + +var errOpen = errors.New("cipher: message authentication failed") + +func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) { + if len(nonce) != gcmStandardNonceSize { + panic("cipher: incorrect nonce length given to GCM") + } + if len(ciphertext) < gcmTagSize { + return nil, errOpen + } + if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize { + return nil, errOpen + } + + // Make room in dst to append ciphertext without tag. + n := len(dst) + for cap(dst) < n+len(ciphertext)-gcmTagSize { + dst = append(dst[:cap(dst)], 0) + } + dst = dst[:n+len(ciphertext)-gcmTagSize] + + // Check delayed until now to make sure len(dst) is accurate. + if inexactOverlap(dst[n:], ciphertext) { + panic("cipher: invalid buffer overlap") + } + + outLen := C.size_t(len(ciphertext) - gcmTagSize) + ok := C.EVP_AEAD_CTX_open_wrapper( + &g.ctx, + base(dst[n:]), outLen, + base(nonce), C.size_t(len(nonce)), + base(ciphertext), C.size_t(len(ciphertext)), + base(additionalData), C.size_t(len(additionalData))) + runtime.KeepAlive(g) + if ok == 0 { + return nil, errOpen + } + return dst[:n+int(outLen)], nil +} + +func anyOverlap(x, y []byte) bool { + return len(x) > 0 && len(y) > 0 && + uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) && + uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1])) +} + +func inexactOverlap(x, y []byte) bool { + if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] { + return false + } + return anyOverlap(x, y) +} diff --git a/src/crypto/internal/boring/boring.go b/src/crypto/internal/boring/boring.go new file mode 100644 index 0000000000..9ccad7eb5d --- /dev/null +++ b/src/crypto/internal/boring/boring.go @@ -0,0 +1,83 @@ +// Copyright 2017 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 linux,amd64 +// +build !android +// +build !cmd_go_bootstrap +// +build !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "crypto/internal/boring/sig" + "math/big" +) + +const available = true + +func init() { + C._goboringcrypto_BORINGSSL_bcm_power_on_self_test() + if C._goboringcrypto_FIPS_mode() != 1 { + panic("boringcrypto: not in FIPS mode") + } + sig.BoringCrypto() +} + +// Unreachable marks code that should be unreachable +// when BoringCrypto is in use. It panics. +func Unreachable() { + panic("boringcrypto: invalid code execution") +} + +// provided by runtime to avoid os import +func runtime_arg0() string + +func hasSuffix(s, t string) bool { + return len(s) > len(t) && s[len(s)-len(t):] == t +} + +// UnreachableExceptTests marks code that should be unreachable +// when BoringCrypto is in use. It panics. +func UnreachableExceptTests() { + name := runtime_arg0() + // If BoringCrypto ran on Windows we'd need to allow _test.exe and .test.exe as well. + if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") { + println("boringcrypto: unexpected code execution in", name) + panic("boringcrypto: invalid code execution") + } +} + +type fail string + +func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" } + +func bigToBN(x *big.Int) *C.GO_BIGNUM { + raw := x.Bytes() + return C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil) +} + +func bnToBig(bn *C.GO_BIGNUM) *big.Int { + raw := make([]byte, C._goboringcrypto_BN_num_bytes(bn)) + n := C._goboringcrypto_BN_bn2bin(bn, base(raw)) + return new(big.Int).SetBytes(raw[:n]) +} + +func bigToBn(bnp **C.GO_BIGNUM, b *big.Int) bool { + if *bnp != nil { + C._goboringcrypto_BN_free(*bnp) + *bnp = nil + } + if b == nil { + return true + } + raw := b.Bytes() + bn := C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil) + if bn == nil { + return false + } + *bnp = bn + return true +} diff --git a/src/crypto/internal/boring/boring_test.go b/src/crypto/internal/boring/boring_test.go new file mode 100644 index 0000000000..83bbbd3404 --- /dev/null +++ b/src/crypto/internal/boring/boring_test.go @@ -0,0 +1,34 @@ +// Copyright 2017 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. + +// Most functionality in this package is tested by replacing existing code +// and inheriting that code's tests. + +package boring + +import "testing" + +// Test that func init does not panic. +func TestInit(t *testing.T) {} + +// Test that Unreachable panics. +func TestUnreachable(t *testing.T) { + defer func() { + if Enabled { + if err := recover(); err == nil { + t.Fatal("expected Unreachable to panic") + } + } else { + if err := recover(); err != nil { + t.Fatalf("expected Unreachable to be a no-op") + } + } + }() + Unreachable() +} + +// Test that UnreachableExceptTests does not panic (this is a test). +func TestUnreachableExceptTests(t *testing.T) { + UnreachableExceptTests() +} diff --git a/src/crypto/internal/boring/build/README b/src/crypto/internal/boring/build/README new file mode 100644 index 0000000000..22ce944a44 --- /dev/null +++ b/src/crypto/internal/boring/build/README @@ -0,0 +1,6 @@ +This is not a Go package. The directory must not contain Go sources, +to prevent it from being considered a Go package. + +This directory holds the script for building ../goboringcrypto_*.syso. +Run build.sh on an Ubuntu system. +See the comment at the top of build.sh for details. diff --git a/src/crypto/internal/boring/build/build.sh b/src/crypto/internal/boring/build/build.sh new file mode 100755 index 0000000000..5afbb426e2 --- /dev/null +++ b/src/crypto/internal/boring/build/build.sh @@ -0,0 +1,64 @@ +#!/bin/bash +# Copyright 2017 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. + +# Run on Ubuntu system set up with: +# sudo apt-get install debootstrap +# sudo apt-get install squid-deb-proxy +# sudo /etc/init.d/squid-deb-proxy start +# +# The script sets up an Ubuntu chroot and then runs the build +# in that chroot, to make sure we know exactly what software +# is being used for the build. To repeat the script reusing the +# chroot installation, run build.sh -quick. This mode is useful +# if all you've modified is goboringcrypto.c and ../goboringcrypto.h +# (or some of the setup scripts in this directory). + +# Comment this setting out if not using squid-deb-proxy, +# but it will be much slower to repeat the script. +http_proxy=http://127.0.0.1:8000 + +chroot=/var/tmp/boringssl + +sudo umount -f $chroot/proc +sudo umount -f $chroot/sys +sudo umount -f $chroot/dev/pts +sudo umount -f $chroot/dev + +set -e +if [ "$1" != "-quick" ]; then + sudo rm -rf $chroot + sudo http_proxy=$http_proxy debootstrap --variant=minbase disco $chroot +fi + +sudo chown $(whoami) $chroot +sudo chmod u+w $chroot + +sudo mount -t proc proc $chroot/proc +sudo mount -t sysfs sys $chroot/sys +sudo mount -o bind /dev $chroot/dev +sudo mount -t devpts devpts $chroot/dev/pts + +sudo cp sources.list $chroot/etc/apt/sources.list + +cp *chroot.sh $chroot + +# Following https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3318.pdf page 19. +if [ ! -e $chroot/boringssl-66005f41fbc3529ffe8d007708756720529da20d.tar.xz ]; then + wget -O $chroot/boringssl-66005f41fbc3529ffe8d007708756720529da20d.tar.xz https://commondatastorage.googleapis.com/chromium-boringssl-docs/fips/boringssl-66005f41fbc3529ffe8d007708756720529da20d.tar.xz +fi +if [ "$(sha256sum $chroot/boringssl-66005f41fbc3529ffe8d007708756720529da20d.tar.xz | awk '{print $1}')" != b12ad676ee533824f698741bd127f6fbc82c46344398a6d78d25e62c6c418c73 ]; then + echo WRONG SHA256SUM + exit 2 +fi + +rm -rf $chroot/godriver +mkdir $chroot/godriver +cp ../goboringcrypto.h $chroot/godriver + +sudo http_proxy=$http_proxy chroot $chroot /root_setup_in_chroot.sh +sudo chroot --userspec=$(id -u):$(id -g) $chroot /build_in_chroot.sh +cp $chroot/godriver/goboringcrypto_linux_amd64.syso .. +sha256sum ../goboringcrypto_linux_amd64.syso +echo DONE diff --git a/src/crypto/internal/boring/build/build_in_chroot.sh b/src/crypto/internal/boring/build/build_in_chroot.sh new file mode 100755 index 0000000000..73597e11fd --- /dev/null +++ b/src/crypto/internal/boring/build/build_in_chroot.sh @@ -0,0 +1,198 @@ +#!/bin/bash +# Copyright 2017 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. + +set -e +echo running build_in_chroot.sh +id +date +export LANG=C +unset LANGUAGE + +# Build BoringCrypto libcrypto.a. +# Following https://csrc.nist.gov/CSRC/media/projects/cryptographic-module-validation-program/documents/security-policies/140sp3318.pdf page 19. +if ! [ -e ./boringssl/build/tool/bssl ]; then + export PATH=$PATH:/usr/lib/go-1.10/bin:/clangbin + + # Go requires -fPIC for linux/amd64 cgo builds. + # Setting -fPIC only affects the compilation of the non-module code in libcrypto.a, + # because the FIPS module itself is already built with -fPIC. + mkdir /clangbin + echo '#!/bin/bash + exec clang-6.0 -fPIC "$@" + ' >/clangbin/clang + echo '#!/bin/bash + exec clang++-6.0 -fPIC "$@" + ' >/clangbin/clang++ + chmod +x /clangbin/clang /clangbin/clang++ + + rm -rf boringssl + tar xJf ../boringssl-*z + cd boringssl + + # Verbatim instructions from BoringCrypto build docs. + printf "set(CMAKE_C_COMPILER \"clang\")\nset(CMAKE_CXX_COMPILER \"clang++\")\n" >${HOME}/toolchain + mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=1 -DCMAKE_BUILD_TYPE=Release .. + ninja + ninja run_tests + + cd ../.. +fi +if [ "$(./boringssl/build/tool/bssl isfips)" != 1 ]; then + echo "NOT FIPS" + exit 2 +fi + + +# Build and run test C++ program to make sure goboringcrypto.h matches openssl/*.h. +# Also collect list of checked symbols in syms.txt +set -x +set -e +cd godriver +cat >goboringcrypto.cc <<'EOF' +#include <cassert> +#include "goboringcrypto0.h" +#include "goboringcrypto1.h" +#define check_size(t) if(sizeof(t) != sizeof(GO_ ## t)) {printf("sizeof(" #t ")=%d, but sizeof(GO_" #t ")=%d\n", (int)sizeof(t), (int)sizeof(GO_ ## t)); ret=1;} +#define check_func(f) { auto x = f; x = _goboringcrypto_ ## f ; } +#define check_value(n, v) if(n != v) {printf(#n "=%d, but goboringcrypto.h defines it as %d\n", (int)n, (int)v); ret=1;} +int main() { +int ret = 0; +#include "goboringcrypto.x" +return ret; +} +EOF + +awk ' +BEGIN { + exitcode = 0 +} + +# Ignore comments, #includes, blank lines. +/^\/\// || /^#/ || NF == 0 { next } + +# Ignore unchecked declarations. +/\/\*unchecked/ { next } + +# Check enum values. +!enum && $1 == "enum" && $NF == "{" { + enum = 1 + next +} +enum && $1 == "};" { + enum = 0 + next +} +enum && NF == 3 && $2 == "=" { + name = $1 + sub(/^GO_/, "", name) + val = $3 + sub(/,$/, "", val) + print "check_value(" name ", " val ")" > "goboringcrypto.x" + next +} +enum { + print FILENAME ":" NR ": unexpected line in enum: " $0 > "/dev/stderr" + exitcode = 1 + next +} + +# Check struct sizes. +/^typedef struct / && $NF ~ /^GO_/ { + name = $NF + sub(/^GO_/, "", name) + sub(/;$/, "", name) + print "check_size(" name ")" > "goboringcrypto.x" + next +} + +# Check function prototypes. +/^(const )?[^ ]+ \**_goboringcrypto_.*\(/ { + name = $2 + if($1 == "const") + name = $3 + sub(/^\**_goboringcrypto_/, "", name) + sub(/\(.*/, "", name) + print "check_func(" name ")" > "goboringcrypto.x" + print name > "syms.txt" + next +} + +{ + print FILENAME ":" NR ": unexpected line: " $0 > "/dev/stderr" + exitcode = 1 +} + +END { + exit exitcode +} +' goboringcrypto.h + +cat goboringcrypto.h | awk ' + /^\/\/ #include/ {sub(/\/\//, ""); print > "goboringcrypto0.h"; next} + /typedef struct|enum ([a-z_]+ )?{|^[ \t]/ {print;next} + {gsub(/GO_/, ""); gsub(/enum go_/, "enum "); print} +' >goboringcrypto1.h +clang++-6.0 -std=c++11 -fPIC -I../boringssl/include -O2 -o a.out goboringcrypto.cc +./a.out || exit 2 + +# Prepare copy of libcrypto.a with only the checked functions renamed and exported. +# All other symbols are left alone and hidden. +echo BORINGSSL_bcm_power_on_self_test >>syms.txt +awk '{print "_goboringcrypto_" $0 }' syms.txt >globals.txt +awk '{print $0 " _goboringcrypto_" $0 }' syms.txt >renames.txt +objcopy --globalize-symbol=BORINGSSL_bcm_power_on_self_test ../boringssl/build/crypto/libcrypto.a libcrypto.a + +# clang implements u128 % u128 -> u128 by calling __umodti3, +# which is in libgcc. To make the result self-contained even if linking +# against a different compiler version, link our own __umodti3 into the syso. +# This one is specialized so it only expects divisors below 2^64, +# which is all BoringCrypto uses. (Otherwise it will seg fault.) +cat >umod.s <<'EOF' +# tu_int __umodti3(tu_int x, tu_int y) +# x is rsi:rdi, y is rcx:rdx, return result is rdx:rax. +.globl __umodti3 +__umodti3: + # specialized to u128 % u64, so verify that + test %rcx,%rcx + jne 1f + + # save divisor + movq %rdx, %r8 + + # reduce top 64 bits mod divisor + movq %rsi, %rax + xorl %edx, %edx + divq %r8 + + # reduce full 128-bit mod divisor + # quotient fits in 64 bits because top 64 bits have been reduced < divisor. + # (even though we only care about the remainder, divq also computes + # the quotient, and it will trap if the quotient is too large.) + movq %rdi, %rax + divq %r8 + + # expand remainder to 128 for return + movq %rdx, %rax + xorl %edx, %edx + ret + +1: + # crash - only want 64-bit divisor + xorl %ecx, %ecx + movl %ecx, 0(%ecx) + jmp 1b + +.section .note.GNU-stack,"",@progbits +EOF +clang-6.0 -c -o umod.o umod.s + +ld -r -nostdlib --whole-archive -o goboringcrypto.o libcrypto.a umod.o +echo __umodti3 _goboringcrypto___umodti3 >>renames.txt +objcopy --redefine-syms=renames.txt goboringcrypto.o goboringcrypto2.o +objcopy --keep-global-symbols=globals.txt goboringcrypto2.o goboringcrypto_linux_amd64.syso + +# Done! +ls -l goboringcrypto_linux_amd64.syso +sha256sum goboringcrypto_linux_amd64.syso diff --git a/src/crypto/internal/boring/build/root_setup_in_chroot.sh b/src/crypto/internal/boring/build/root_setup_in_chroot.sh new file mode 100755 index 0000000000..90f0f266c3 --- /dev/null +++ b/src/crypto/internal/boring/build/root_setup_in_chroot.sh @@ -0,0 +1,13 @@ +#!/bin/bash +# Copyright 2017 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. + +set -e +id +date +echo http_proxy=$http_proxy +export LANG=C +unset LANGUAGE +apt-get update +apt-get install --no-install-recommends -y cmake clang-6.0 golang-1.10-go ninja-build xz-utils diff --git a/src/crypto/internal/boring/build/sources.list b/src/crypto/internal/boring/build/sources.list new file mode 100644 index 0000000000..a5c31c0645 --- /dev/null +++ b/src/crypto/internal/boring/build/sources.list @@ -0,0 +1,10 @@ +deb http://archive.ubuntu.com/ubuntu/ disco main restricted +deb http://archive.ubuntu.com/ubuntu/ disco-updates main restricted +deb http://archive.ubuntu.com/ubuntu/ disco universe +deb http://archive.ubuntu.com/ubuntu/ disco-updates universe +deb http://archive.ubuntu.com/ubuntu/ disco multiverse +deb http://archive.ubuntu.com/ubuntu/ disco-updates multiverse +deb http://archive.ubuntu.com/ubuntu/ disco-backports main restricted universe multiverse +deb http://security.ubuntu.com/ubuntu disco-security main restricted +deb http://security.ubuntu.com/ubuntu disco-security universe +deb http://security.ubuntu.com/ubuntu disco-security multiverse diff --git a/src/crypto/internal/boring/doc.go b/src/crypto/internal/boring/doc.go new file mode 100644 index 0000000000..64f41e3c82 --- /dev/null +++ b/src/crypto/internal/boring/doc.go @@ -0,0 +1,14 @@ +// Copyright 2017 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 boring provides access to BoringCrypto implementation functions. +// Check the constant Enabled to find out whether BoringCrypto is available. +// If BoringCrypto is not available, the functions in this package all panic. +package boring + +// Enabled reports whether BoringCrypto is available. +// When enabled is false, all functions in this package panic. +// +// BoringCrypto is only available on linux/amd64 systems. +const Enabled = available diff --git a/src/crypto/internal/boring/ecdsa.go b/src/crypto/internal/boring/ecdsa.go new file mode 100644 index 0000000000..4fcba4be72 --- /dev/null +++ b/src/crypto/internal/boring/ecdsa.go @@ -0,0 +1,201 @@ +// Copyright 2017 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 linux,amd64 +// +build !android +// +build !cmd_go_bootstrap +// +build !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "encoding/asn1" + "errors" + "math/big" + "runtime" + "unsafe" +) + +type ecdsaSignature struct { + R, S *big.Int +} + +type PrivateKeyECDSA struct { + key *C.GO_EC_KEY +} + +func (k *PrivateKeyECDSA) finalize() { + C._goboringcrypto_EC_KEY_free(k.key) +} + +type PublicKeyECDSA struct { + key *C.GO_EC_KEY +} + +func (k *PublicKeyECDSA) finalize() { + C._goboringcrypto_EC_KEY_free(k.key) +} + +var errUnknownCurve = errors.New("boringcrypto: unknown elliptic curve") + +func curveNID(curve string) (C.int, error) { + switch curve { + case "P-224": + return C.GO_NID_secp224r1, nil + case "P-256": + return C.GO_NID_X9_62_prime256v1, nil + case "P-384": + return C.GO_NID_secp384r1, nil + case "P-521": + return C.GO_NID_secp521r1, nil + } + return 0, errUnknownCurve +} + +func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) { + key, err := newECKey(curve, X, Y) + if err != nil { + return nil, err + } + k := &PublicKeyECDSA{key} + // Note: Because of the finalizer, any time k.key is passed to cgo, + // that call must be followed by a call to runtime.KeepAlive(k), + // to make sure k is not collected (and finalized) before the cgo + // call returns. + runtime.SetFinalizer(k, (*PublicKeyECDSA).finalize) + return k, nil +} + +func newECKey(curve string, X, Y *big.Int) (*C.GO_EC_KEY, error) { + nid, err := curveNID(curve) + if err != nil { + return nil, err + } + key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid) + if key == nil { + return nil, fail("EC_KEY_new_by_curve_name") + } + group := C._goboringcrypto_EC_KEY_get0_group(key) + pt := C._goboringcrypto_EC_POINT_new(group) + if pt == nil { + C._goboringcrypto_EC_KEY_free(key) + return nil, fail("EC_POINT_new") + } + bx := bigToBN(X) + by := bigToBN(Y) + ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 && + C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0 + if bx != nil { + C._goboringcrypto_BN_free(bx) + } + if by != nil { + C._goboringcrypto_BN_free(by) + } + C._goboringcrypto_EC_POINT_free(pt) + if !ok { + C._goboringcrypto_EC_KEY_free(key) + return nil, fail("EC_POINT_set_affine_coordinates_GFp") + } + return key, nil +} + +func NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*PrivateKeyECDSA, error) { + key, err := newECKey(curve, X, Y) + if err != nil { + return nil, err + } + bd := bigToBN(D) + ok := bd != nil && C._goboringcrypto_EC_KEY_set_private_key(key, bd) != 0 + if bd != nil { + C._goboringcrypto_BN_free(bd) + } + if !ok { + C._goboringcrypto_EC_KEY_free(key) + return nil, fail("EC_KEY_set_private_key") + } + k := &PrivateKeyECDSA{key} + // Note: Because of the finalizer, any time k.key is passed to cgo, + // that call must be followed by a call to runtime.KeepAlive(k), + // to make sure k is not collected (and finalized) before the cgo + // call returns. + runtime.SetFinalizer(k, (*PrivateKeyECDSA).finalize) + return k, nil +} + +func SignECDSA(priv *PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) { + // We could use ECDSA_do_sign instead but would need to convert + // the resulting BIGNUMs to *big.Int form. If we're going to do a + // conversion, converting the ASN.1 form is more convenient and + // likely not much more expensive. + sig, err := SignMarshalECDSA(priv, hash) + if err != nil { + return nil, nil, err + } + var esig ecdsaSignature + if _, err := asn1.Unmarshal(sig, &esig); err != nil { + return nil, nil, err + } + return esig.R, esig.S, nil +} + +func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) { + size := C._goboringcrypto_ECDSA_size(priv.key) + sig := make([]byte, size) + var sigLen C.uint + if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) == 0 { + return nil, fail("ECDSA_sign") + } + runtime.KeepAlive(priv) + return sig[:sigLen], nil +} + +func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, r, s *big.Int) bool { + // We could use ECDSA_do_verify instead but would need to convert + // r and s to BIGNUM form. If we're going to do a conversion, marshaling + // to ASN.1 is more convenient and likely not much more expensive. + sig, err := asn1.Marshal(ecdsaSignature{r, s}) + if err != nil { + return false + } + ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.size_t(len(sig)), pub.key) != 0 + runtime.KeepAlive(pub) + return ok +} + +func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) { + nid, err := curveNID(curve) + if err != nil { + return nil, nil, nil, err + } + key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid) + if key == nil { + return nil, nil, nil, fail("EC_KEY_new_by_curve_name") + } + defer C._goboringcrypto_EC_KEY_free(key) + if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 { + return nil, nil, nil, fail("EC_KEY_generate_key_fips") + } + group := C._goboringcrypto_EC_KEY_get0_group(key) + pt := C._goboringcrypto_EC_KEY_get0_public_key(key) + bd := C._goboringcrypto_EC_KEY_get0_private_key(key) + if pt == nil || bd == nil { + return nil, nil, nil, fail("EC_KEY_get0_private_key") + } + bx := C._goboringcrypto_BN_new() + if bx == nil { + return nil, nil, nil, fail("BN_new") + } + defer C._goboringcrypto_BN_free(bx) + by := C._goboringcrypto_BN_new() + if by == nil { + return nil, nil, nil, fail("BN_new") + } + defer C._goboringcrypto_BN_free(by) + if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 { + return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp") + } + return bnToBig(bx), bnToBig(by), bnToBig(bd), nil +} diff --git a/src/crypto/internal/boring/fipstls/dummy.s b/src/crypto/internal/boring/fipstls/dummy.s new file mode 100644 index 0000000000..53bb7d9430 --- /dev/null +++ b/src/crypto/internal/boring/fipstls/dummy.s @@ -0,0 +1,10 @@ +// Copyright 2017 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. + +// runtime_arg0 is declared in tls.go without a body. +// It's provided by package runtime, +// but the go command doesn't know that. +// Having this assembly file keeps the go command +// from complaining about the missing body +// (because the implementation might be here). diff --git a/src/crypto/internal/boring/fipstls/tls.go b/src/crypto/internal/boring/fipstls/tls.go new file mode 100644 index 0000000000..4127533fbd --- /dev/null +++ b/src/crypto/internal/boring/fipstls/tls.go @@ -0,0 +1,49 @@ +// Copyright 2017 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 fipstls allows control over whether crypto/tls requires FIPS-approved settings. +// This package's effects are independent of the use of the BoringCrypto implementation. +package fipstls + +import "sync/atomic" + +var required uint32 + +// Force forces crypto/tls to restrict TLS configurations to FIPS-approved settings. +// By design, this call is impossible to undo (except in tests). +// +// Note that this call has an effect even in programs using +// standard crypto (that is, even when Enabled = false). +func Force() { + atomic.StoreUint32(&required, 1) +} + +// Abandon allows non-FIPS-approved settings. +// If called from a non-test binary, it panics. +func Abandon() { + // Note: Not using boring.UnreachableExceptTests because we want + // this test to happen even when boring.Enabled = false. + name := runtime_arg0() + // Allow _test for Go command, .test for Bazel, + // NaClMain for NaCl (where all binaries run as NaClMain), + // and empty string for Windows (where runtime_arg0 can't easily find the name). + // Since this is an internal package, testing that this isn't used on the + // other operating systems should suffice to catch any mistakes. + if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") && name != "NaClMain" && name != "" { + panic("fipstls: invalid use of Abandon in " + name) + } + atomic.StoreUint32(&required, 0) +} + +// provided by runtime +func runtime_arg0() string + +func hasSuffix(s, t string) bool { + return len(s) > len(t) && s[len(s)-len(t):] == t +} + +// Required reports whether FIPS-approved settings are required. +func Required() bool { + return atomic.LoadUint32(&required) != 0 +} diff --git a/src/crypto/internal/boring/goboringcrypto.h b/src/crypto/internal/boring/goboringcrypto.h new file mode 100644 index 0000000000..744496c6ef --- /dev/null +++ b/src/crypto/internal/boring/goboringcrypto.h @@ -0,0 +1,237 @@ +// Copyright 2017 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. + +// This header file describes the BoringCrypto ABI as built for use in Go. +// The BoringCrypto build for Go (which generates goboringcrypto_*.syso) +// takes the standard libcrypto.a from BoringCrypto and adds the prefix +// _goboringcrypto_ to every symbol, to avoid possible conflicts with +// code wrapping a different BoringCrypto or OpenSSL. +// +// To make this header standalone (so that building Go does not require +// having a full set of BoringCrypto headers), the struct details are not here. +// Instead, while building the syso, we compile and run a C++ program +// that checks that the sizes match. The program also checks (during compilation) +// that all the function prototypes match the BoringCrypto equivalents. +// The generation of the checking program depends on the declaration +// forms used below (one line for most, multiline for enums). + +#include <stdlib.h> // size_t +#include <stdint.h> // uint8_t + +// This symbol is hidden in BoringCrypto and marked as a constructor, +// but cmd/link's internal linking mode doesn't handle constructors. +// Until it does, we've exported the symbol and can call it explicitly. +// (If using external linking mode, it will therefore be called twice, +// once explicitly and once as a constructor, but that's OK.) +/*unchecked*/ void _goboringcrypto_BORINGSSL_bcm_power_on_self_test(void); + +// #include <openssl/crypto.h> +int _goboringcrypto_FIPS_mode(void); +void* _goboringcrypto_OPENSSL_malloc(size_t); + +// #include <openssl/rand.h> +int _goboringcrypto_RAND_bytes(uint8_t*, size_t); + +// #include <openssl/nid.h> +enum { + GO_NID_md5_sha1 = 114, + + GO_NID_secp224r1 = 713, + GO_NID_X9_62_prime256v1 = 415, + GO_NID_secp384r1 = 715, + GO_NID_secp521r1 = 716, + + GO_NID_sha224 = 675, + GO_NID_sha256 = 672, + GO_NID_sha384 = 673, + GO_NID_sha512 = 674, +}; + +// #include <openssl/sha.h> +typedef struct GO_SHA_CTX { char data[96]; } GO_SHA_CTX; +int _goboringcrypto_SHA1_Init(GO_SHA_CTX*); +int _goboringcrypto_SHA1_Update(GO_SHA_CTX*, const void*, size_t); +int _goboringcrypto_SHA1_Final(uint8_t*, GO_SHA_CTX*); + +typedef struct GO_SHA256_CTX { char data[48+64]; } GO_SHA256_CTX; +int _goboringcrypto_SHA224_Init(GO_SHA256_CTX*); +int _goboringcrypto_SHA224_Update(GO_SHA256_CTX*, const void*, size_t); +int _goboringcrypto_SHA224_Final(uint8_t*, GO_SHA256_CTX*); +int _goboringcrypto_SHA256_Init(GO_SHA256_CTX*); +int _goboringcrypto_SHA256_Update(GO_SHA256_CTX*, const void*, size_t); +int _goboringcrypto_SHA256_Final(uint8_t*, GO_SHA256_CTX*); + +typedef struct GO_SHA512_CTX { char data[88+128]; } GO_SHA512_CTX; +int _goboringcrypto_SHA384_Init(GO_SHA512_CTX*); +int _goboringcrypto_SHA384_Update(GO_SHA512_CTX*, const void*, size_t); +int _goboringcrypto_SHA384_Final(uint8_t*, GO_SHA512_CTX*); +int _goboringcrypto_SHA512_Init(GO_SHA512_CTX*); +int _goboringcrypto_SHA512_Update(GO_SHA512_CTX*, const void*, size_t); +int _goboringcrypto_SHA512_Final(uint8_t*, GO_SHA512_CTX*); + +// #include <openssl/digest.h> +/*unchecked (opaque)*/ typedef struct GO_EVP_MD { char data[1]; } GO_EVP_MD; +const GO_EVP_MD* _goboringcrypto_EVP_md4(void); +const GO_EVP_MD* _goboringcrypto_EVP_md5(void); +const GO_EVP_MD* _goboringcrypto_EVP_md5_sha1(void); +const GO_EVP_MD* _goboringcrypto_EVP_sha1(void); +const GO_EVP_MD* _goboringcrypto_EVP_sha224(void); +const GO_EVP_MD* _goboringcrypto_EVP_sha256(void); +const GO_EVP_MD* _goboringcrypto_EVP_sha384(void); +const GO_EVP_MD* _goboringcrypto_EVP_sha512(void); +int _goboringcrypto_EVP_MD_type(const GO_EVP_MD*); +size_t _goboringcrypto_EVP_MD_size(const GO_EVP_MD*); + +// #include <openssl/hmac.h> +typedef struct GO_HMAC_CTX { char data[104]; } GO_HMAC_CTX; +void _goboringcrypto_HMAC_CTX_init(GO_HMAC_CTX*); +void _goboringcrypto_HMAC_CTX_cleanup(GO_HMAC_CTX*); +int _goboringcrypto_HMAC_Init(GO_HMAC_CTX*, const void*, int, const GO_EVP_MD*); +int _goboringcrypto_HMAC_Update(GO_HMAC_CTX*, const uint8_t*, size_t); +int _goboringcrypto_HMAC_Final(GO_HMAC_CTX*, uint8_t*, unsigned int*); +size_t _goboringcrypto_HMAC_size(const GO_HMAC_CTX*); +int _goboringcrypto_HMAC_CTX_copy_ex(GO_HMAC_CTX *dest, const GO_HMAC_CTX *src); + +// #include <openssl/aes.h> +typedef struct GO_AES_KEY { char data[244]; } GO_AES_KEY; +int _goboringcrypto_AES_set_encrypt_key(const uint8_t*, unsigned int, GO_AES_KEY*); +int _goboringcrypto_AES_set_decrypt_key(const uint8_t*, unsigned int, GO_AES_KEY*); +void _goboringcrypto_AES_encrypt(const uint8_t*, uint8_t*, const GO_AES_KEY*); +void _goboringcrypto_AES_decrypt(const uint8_t*, uint8_t*, const GO_AES_KEY*); +void _goboringcrypto_AES_ctr128_encrypt(const uint8_t*, uint8_t*, size_t, const GO_AES_KEY*, uint8_t*, uint8_t*, unsigned int*); +enum { + GO_AES_ENCRYPT = 1, + GO_AES_DECRYPT = 0 +}; +void _goboringcrypto_AES_cbc_encrypt(const uint8_t*, uint8_t*, size_t, const GO_AES_KEY*, uint8_t*, const int); + +// #include <openssl/aead.h> +/*unchecked (opaque)*/ typedef struct GO_EVP_AEAD { char data[1]; } GO_EVP_AEAD; +/*unchecked (opaque)*/ typedef struct GO_ENGINE { char data[1]; } GO_ENGINE; +const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm(void); +const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm(void); +enum { + GO_EVP_AEAD_DEFAULT_TAG_LENGTH = 0 +}; +size_t _goboringcrypto_EVP_AEAD_key_length(const GO_EVP_AEAD*); +size_t _goboringcrypto_EVP_AEAD_nonce_length(const GO_EVP_AEAD*); +size_t _goboringcrypto_EVP_AEAD_max_overhead(const GO_EVP_AEAD*); +size_t _goboringcrypto_EVP_AEAD_max_tag_len(const GO_EVP_AEAD*); +typedef struct GO_EVP_AEAD_CTX { char data[24]; } GO_EVP_AEAD_CTX; +void _goboringcrypto_EVP_AEAD_CTX_zero(GO_EVP_AEAD_CTX*); +int _goboringcrypto_EVP_AEAD_CTX_init(GO_EVP_AEAD_CTX*, const GO_EVP_AEAD*, const uint8_t*, size_t, size_t, GO_ENGINE*); +void _goboringcrypto_EVP_AEAD_CTX_cleanup(GO_EVP_AEAD_CTX*); +int _goboringcrypto_EVP_AEAD_CTX_seal(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t); +int _goboringcrypto_EVP_AEAD_CTX_open(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t); +const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm_tls12(void); +const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm_tls12(void); +enum go_evp_aead_direction_t { + go_evp_aead_open = 0, + go_evp_aead_seal = 1 +}; +int _goboringcrypto_EVP_AEAD_CTX_init_with_direction(GO_EVP_AEAD_CTX*, const GO_EVP_AEAD*, const uint8_t*, size_t, size_t, enum go_evp_aead_direction_t); + +// #include <openssl/bn.h> +/*unchecked (opaque)*/ typedef struct GO_BN_CTX { char data[1]; } GO_BN_CTX; +typedef struct GO_BIGNUM { char data[24]; } GO_BIGNUM; +GO_BIGNUM* _goboringcrypto_BN_new(void); +void _goboringcrypto_BN_free(GO_BIGNUM*); +unsigned _goboringcrypto_BN_num_bits(const GO_BIGNUM*); +unsigned _goboringcrypto_BN_num_bytes(const GO_BIGNUM*); +int _goboringcrypto_BN_is_negative(const GO_BIGNUM*); +GO_BIGNUM* _goboringcrypto_BN_bin2bn(const uint8_t*, size_t, GO_BIGNUM*); +size_t _goboringcrypto_BN_bn2bin(const GO_BIGNUM*, uint8_t*); + +// #include <openssl/ec.h> +/*unchecked (opaque)*/ typedef struct GO_EC_GROUP { char data[1]; } GO_EC_GROUP; +GO_EC_GROUP* _goboringcrypto_EC_GROUP_new_by_curve_name(int); +void _goboringcrypto_EC_GROUP_free(GO_EC_GROUP*); + +/*unchecked (opaque)*/ typedef struct GO_EC_POINT { char data[1]; } GO_EC_POINT; +GO_EC_POINT* _goboringcrypto_EC_POINT_new(const GO_EC_GROUP*); +void _goboringcrypto_EC_POINT_free(GO_EC_POINT*); +int _goboringcrypto_EC_POINT_get_affine_coordinates_GFp(const GO_EC_GROUP*, const GO_EC_POINT*, GO_BIGNUM*, GO_BIGNUM*, GO_BN_CTX*); +int _goboringcrypto_EC_POINT_set_affine_coordinates_GFp(const GO_EC_GROUP*, GO_EC_POINT*, const GO_BIGNUM*, const GO_BIGNUM*, GO_BN_CTX*); + +// #include <openssl/ec_key.h> +/*unchecked (opaque)*/ typedef struct GO_EC_KEY { char data[1]; } GO_EC_KEY; +GO_EC_KEY* _goboringcrypto_EC_KEY_new(void); +GO_EC_KEY* _goboringcrypto_EC_KEY_new_by_curve_name(int); +void _goboringcrypto_EC_KEY_free(GO_EC_KEY*); +const GO_EC_GROUP* _goboringcrypto_EC_KEY_get0_group(const GO_EC_KEY*); +int _goboringcrypto_EC_KEY_generate_key_fips(GO_EC_KEY*); +int _goboringcrypto_EC_KEY_set_private_key(GO_EC_KEY*, const GO_BIGNUM*); +int _goboringcrypto_EC_KEY_set_public_key(GO_EC_KEY*, const GO_EC_POINT*); +int _goboringcrypto_EC_KEY_is_opaque(const GO_EC_KEY*); +const GO_BIGNUM* _goboringcrypto_EC_KEY_get0_private_key(const GO_EC_KEY*); +const GO_EC_POINT* _goboringcrypto_EC_KEY_get0_public_key(const GO_EC_KEY*); +// TODO: EC_KEY_check_fips? + +// #include <openssl/ecdsa.h> +typedef struct GO_ECDSA_SIG { char data[16]; } GO_ECDSA_SIG; +GO_ECDSA_SIG* _goboringcrypto_ECDSA_SIG_new(void); +void _goboringcrypto_ECDSA_SIG_free(GO_ECDSA_SIG*); +GO_ECDSA_SIG* _goboringcrypto_ECDSA_do_sign(const uint8_t*, size_t, const GO_EC_KEY*); +int _goboringcrypto_ECDSA_do_verify(const uint8_t*, size_t, const GO_ECDSA_SIG*, const GO_EC_KEY*); +int _goboringcrypto_ECDSA_sign(int, const uint8_t*, size_t, uint8_t*, unsigned int*, const GO_EC_KEY*); +size_t _goboringcrypto_ECDSA_size(const GO_EC_KEY*); +int _goboringcrypto_ECDSA_verify(int, const uint8_t*, size_t, const uint8_t*, size_t, const GO_EC_KEY*); + +// #include <openssl/rsa.h> + +// Note: order of struct fields here is unchecked. +typedef struct GO_RSA { void *meth; GO_BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; char data[160]; } GO_RSA; +/*unchecked (opaque)*/ typedef struct GO_BN_GENCB { char data[1]; } GO_BN_GENCB; +GO_RSA* _goboringcrypto_RSA_new(void); +void _goboringcrypto_RSA_free(GO_RSA*); +void _goboringcrypto_RSA_get0_key(const GO_RSA*, const GO_BIGNUM **n, const GO_BIGNUM **e, const GO_BIGNUM **d); +void _goboringcrypto_RSA_get0_factors(const GO_RSA*, const GO_BIGNUM **p, const GO_BIGNUM **q); +void _goboringcrypto_RSA_get0_crt_params(const GO_RSA*, const GO_BIGNUM **dmp1, const GO_BIGNUM **dmp2, const GO_BIGNUM **iqmp); +int _goboringcrypto_RSA_generate_key_ex(GO_RSA*, int, GO_BIGNUM*, GO_BN_GENCB*); +int _goboringcrypto_RSA_generate_key_fips(GO_RSA*, int, GO_BN_GENCB*); +enum { + GO_RSA_PKCS1_PADDING = 1, + GO_RSA_NO_PADDING = 3, + GO_RSA_PKCS1_OAEP_PADDING = 4, + GO_RSA_PKCS1_PSS_PADDING = 6, +}; +int _goboringcrypto_RSA_encrypt(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); +int _goboringcrypto_RSA_decrypt(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); +int _goboringcrypto_RSA_sign(int hash_nid, const uint8_t* in, unsigned int in_len, uint8_t *out, unsigned int *out_len, GO_RSA*); +int _goboringcrypto_RSA_sign_pss_mgf1(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, const GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len); +int _goboringcrypto_RSA_sign_raw(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); +int _goboringcrypto_RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len, GO_RSA*); +int _goboringcrypto_RSA_verify_pss_mgf1(GO_RSA*, const uint8_t *msg, size_t msg_len, const GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len, const uint8_t *sig, size_t sig_len); +int _goboringcrypto_RSA_verify_raw(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding); +unsigned _goboringcrypto_RSA_size(const GO_RSA*); +int _goboringcrypto_RSA_is_opaque(const GO_RSA*); +int _goboringcrypto_RSA_check_key(const GO_RSA*); +int _goboringcrypto_RSA_check_fips(GO_RSA*); +GO_RSA* _goboringcrypto_RSA_public_key_from_bytes(const uint8_t*, size_t); +GO_RSA* _goboringcrypto_RSA_private_key_from_bytes(const uint8_t*, size_t); +int _goboringcrypto_RSA_public_key_to_bytes(uint8_t**, size_t*, const GO_RSA*); +int _goboringcrypto_RSA_private_key_to_bytes(uint8_t**, size_t*, const GO_RSA*); + +// #include <openssl/evp.h> +/*unchecked (opaque)*/ typedef struct GO_EVP_PKEY { char data[1]; } GO_EVP_PKEY; +GO_EVP_PKEY* _goboringcrypto_EVP_PKEY_new(void); +void _goboringcrypto_EVP_PKEY_free(GO_EVP_PKEY*); +int _goboringcrypto_EVP_PKEY_set1_RSA(GO_EVP_PKEY*, GO_RSA*); + +/*unchecked (opaque)*/ typedef struct GO_EVP_PKEY_CTX { char data[1]; } GO_EVP_PKEY_CTX; + +GO_EVP_PKEY_CTX* _goboringcrypto_EVP_PKEY_CTX_new(GO_EVP_PKEY*, GO_ENGINE*); +void _goboringcrypto_EVP_PKEY_CTX_free(GO_EVP_PKEY_CTX*); +int _goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(GO_EVP_PKEY_CTX*, uint8_t*, size_t); +int _goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(GO_EVP_PKEY_CTX*, const GO_EVP_MD*); +int _goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(GO_EVP_PKEY_CTX*, int padding); +int _goboringcrypto_EVP_PKEY_decrypt(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t); +int _goboringcrypto_EVP_PKEY_encrypt(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t); +int _goboringcrypto_EVP_PKEY_decrypt_init(GO_EVP_PKEY_CTX*); +int _goboringcrypto_EVP_PKEY_encrypt_init(GO_EVP_PKEY_CTX*); +int _goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(GO_EVP_PKEY_CTX*, const GO_EVP_MD*); +int _goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(GO_EVP_PKEY_CTX*, int); +int _goboringcrypto_EVP_PKEY_sign_init(GO_EVP_PKEY_CTX*); +int _goboringcrypto_EVP_PKEY_verify_init(GO_EVP_PKEY_CTX*); +int _goboringcrypto_EVP_PKEY_sign(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t); diff --git a/src/crypto/internal/boring/goboringcrypto_linux_amd64.syso b/src/crypto/internal/boring/goboringcrypto_linux_amd64.syso Binary files differnew file mode 100644 index 0000000000..4e301cc60d --- /dev/null +++ b/src/crypto/internal/boring/goboringcrypto_linux_amd64.syso diff --git a/src/crypto/internal/boring/hmac.go b/src/crypto/internal/boring/hmac.go new file mode 100644 index 0000000000..01b5844e5f --- /dev/null +++ b/src/crypto/internal/boring/hmac.go @@ -0,0 +1,156 @@ +// Copyright 2017 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 linux,amd64 +// +build !android +// +build !cmd_go_bootstrap +// +build !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "crypto" + "hash" + "runtime" + "unsafe" +) + +// hashToMD converts a hash.Hash implementation from this package +// to a BoringCrypto *C.GO_EVP_MD. +func hashToMD(h hash.Hash) *C.GO_EVP_MD { + switch h.(type) { + case *sha1Hash: + return C._goboringcrypto_EVP_sha1() + case *sha224Hash: + return C._goboringcrypto_EVP_sha224() + case *sha256Hash: + return C._goboringcrypto_EVP_sha256() + case *sha384Hash: + return C._goboringcrypto_EVP_sha384() + case *sha512Hash: + return C._goboringcrypto_EVP_sha512() + } + return nil +} + +// cryptoHashToMD converts a crypto.Hash +// to a BoringCrypto *C.GO_EVP_MD. +func cryptoHashToMD(ch crypto.Hash) *C.GO_EVP_MD { + switch ch { + case crypto.MD5: + return C._goboringcrypto_EVP_md5() + case crypto.MD5SHA1: + return C._goboringcrypto_EVP_md5_sha1() + case crypto.SHA1: + return C._goboringcrypto_EVP_sha1() + case crypto.SHA224: + return C._goboringcrypto_EVP_sha224() + case crypto.SHA256: + return C._goboringcrypto_EVP_sha256() + case crypto.SHA384: + return C._goboringcrypto_EVP_sha384() + case crypto.SHA512: + return C._goboringcrypto_EVP_sha512() + } + return nil +} + +// NewHMAC returns a new HMAC using BoringCrypto. +// The function h must return a hash implemented by +// BoringCrypto (for example, h could be boring.NewSHA256). +// If h is not recognized, NewHMAC returns nil. +func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { + ch := h() + md := hashToMD(ch) + if md == nil { + return nil + } + + // Note: Could hash down long keys here using EVP_Digest. + hkey := make([]byte, len(key)) + copy(hkey, key) + hmac := &boringHMAC{ + md: md, + size: ch.Size(), + blockSize: ch.BlockSize(), + key: hkey, + } + hmac.Reset() + return hmac +} + +type boringHMAC struct { + md *C.GO_EVP_MD + ctx C.GO_HMAC_CTX + ctx2 C.GO_HMAC_CTX + size int + blockSize int + key []byte + sum []byte + needCleanup bool +} + +func (h *boringHMAC) Reset() { + if h.needCleanup { + C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx) + } else { + h.needCleanup = true + // Note: Because of the finalizer, any time h.ctx is passed to cgo, + // that call must be followed by a call to runtime.KeepAlive(h), + // to make sure h is not collected (and finalized) before the cgo + // call returns. + runtime.SetFinalizer(h, (*boringHMAC).finalize) + } + C._goboringcrypto_HMAC_CTX_init(&h.ctx) + + if C._goboringcrypto_HMAC_Init(&h.ctx, unsafe.Pointer(base(h.key)), C.int(len(h.key)), h.md) == 0 { + panic("boringcrypto: HMAC_Init failed") + } + if int(C._goboringcrypto_HMAC_size(&h.ctx)) != h.size { + println("boringcrypto: HMAC size:", C._goboringcrypto_HMAC_size(&h.ctx), "!=", h.size) + panic("boringcrypto: HMAC size mismatch") + } + runtime.KeepAlive(h) // Next line will keep h alive too; just making doubly sure. + h.sum = nil +} + +func (h *boringHMAC) finalize() { + C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx) +} + +func (h *boringHMAC) Write(p []byte) (int, error) { + if len(p) > 0 { + C._goboringcrypto_HMAC_Update(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&p[0])), C.size_t(len(p))) + } + runtime.KeepAlive(h) + return len(p), nil +} + +func (h *boringHMAC) Size() int { + return h.size +} + +func (h *boringHMAC) BlockSize() int { + return h.blockSize +} + +func (h *boringHMAC) Sum(in []byte) []byte { + if h.sum == nil { + size := h.Size() + h.sum = make([]byte, size) + } + // Make copy of context because Go hash.Hash mandates + // that Sum has no effect on the underlying stream. + // In particular it is OK to Sum, then Write more, then Sum again, + // and the second Sum acts as if the first didn't happen. + C._goboringcrypto_HMAC_CTX_init(&h.ctx2) + if C._goboringcrypto_HMAC_CTX_copy_ex(&h.ctx2, &h.ctx) == 0 { + panic("boringcrypto: HMAC_CTX_copy_ex failed") + } + C._goboringcrypto_HMAC_Final(&h.ctx2, (*C.uint8_t)(unsafe.Pointer(&h.sum[0])), nil) + C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx2) + return append(in, h.sum...) +} diff --git a/src/crypto/internal/boring/notboring.go b/src/crypto/internal/boring/notboring.go new file mode 100644 index 0000000000..c21cb3cd55 --- /dev/null +++ b/src/crypto/internal/boring/notboring.go @@ -0,0 +1,109 @@ +// Copyright 2017 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 !linux !amd64 !cgo android cmd_go_bootstrap msan + +package boring + +import ( + "crypto" + "crypto/cipher" + "crypto/internal/boring/sig" + "hash" + "math/big" +) + +const available = false + +// Unreachable marks code that should be unreachable +// when BoringCrypto is in use. It is a no-op without BoringCrypto. +func Unreachable() { + // Code that's unreachable when using BoringCrypto + // is exactly the code we want to detect for reporting + // standard Go crypto. + sig.StandardCrypto() +} + +// UnreachableExceptTests marks code that should be unreachable +// when BoringCrypto is in use. It is a no-op without BoringCrypto. +func UnreachableExceptTests() {} + +type randReader int + +func (randReader) Read(b []byte) (int, error) { panic("boringcrypto: not available") } + +const RandReader = randReader(0) + +func NewSHA1() hash.Hash { panic("boringcrypto: not available") } +func NewSHA224() hash.Hash { panic("boringcrypto: not available") } +func NewSHA256() hash.Hash { panic("boringcrypto: not available") } +func NewSHA384() hash.Hash { panic("boringcrypto: not available") } +func NewSHA512() hash.Hash { panic("boringcrypto: not available") } + +func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: not available") } + +func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") } + +type PublicKeyECDSA struct{ _ int } +type PrivateKeyECDSA struct{ _ int } + +func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) { + panic("boringcrypto: not available") +} +func NewPrivateKeyECDSA(curve string, X, Y, D *big.Int) (*PrivateKeyECDSA, error) { + panic("boringcrypto: not available") +} +func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) { + panic("boringcrypto: not available") +} +func SignECDSA(priv *PrivateKeyECDSA, hash []byte) (r, s *big.Int, err error) { + panic("boringcrypto: not available") +} +func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, r, s *big.Int) bool { + panic("boringcrypto: not available") +} + +type PublicKeyRSA struct{ _ int } +type PrivateKeyRSA struct{ _ int } + +func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { + panic("boringcrypto: not available") +} +func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) { + panic("boringcrypto: not available") +} +func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) { panic("boringcrypto: not available") } +func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { + panic("boringcrypto: not available") +} +func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { + panic("boringcrypto: not available") +} +func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { + panic("boringcrypto: not available") +} +func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { + panic("boringcrypto: not available") +} diff --git a/src/crypto/internal/boring/rand.go b/src/crypto/internal/boring/rand.go new file mode 100644 index 0000000000..c3fc27cc08 --- /dev/null +++ b/src/crypto/internal/boring/rand.go @@ -0,0 +1,27 @@ +// Copyright 2017 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 linux,amd64 +// +build !android +// +build !cmd_go_bootstrap +// +build !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import "unsafe" + +type randReader int + +func (randReader) Read(b []byte) (int, error) { + // Note: RAND_bytes should never fail; the return value exists only for historical reasons. + // We check it even so. + if len(b) > 0 && C._goboringcrypto_RAND_bytes((*C.uint8_t)(unsafe.Pointer(&b[0])), C.size_t(len(b))) == 0 { + return 0, fail("RAND_bytes") + } + return len(b), nil +} + +const RandReader = randReader(0) diff --git a/src/crypto/internal/boring/rsa.go b/src/crypto/internal/boring/rsa.go new file mode 100644 index 0000000000..a10831dd00 --- /dev/null +++ b/src/crypto/internal/boring/rsa.go @@ -0,0 +1,350 @@ +// Copyright 2017 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 linux,amd64 +// +build !android +// +build !cmd_go_bootstrap +// +build !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "crypto" + "crypto/subtle" + "errors" + "hash" + "math/big" + "runtime" + "strconv" + "unsafe" +) + +func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { + bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv *big.Int, err error) { + return nil, nil, nil, nil, nil, nil, nil, nil, e + } + + key := C._goboringcrypto_RSA_new() + if key == nil { + return bad(fail("RSA_new")) + } + defer C._goboringcrypto_RSA_free(key) + + if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 { + return bad(fail("RSA_generate_key_fips")) + } + + var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM + C._goboringcrypto_RSA_get0_key(key, &n, &e, &d) + C._goboringcrypto_RSA_get0_factors(key, &p, &q) + C._goboringcrypto_RSA_get0_crt_params(key, &dp, &dq, &qinv) + return bnToBig(n), bnToBig(e), bnToBig(d), bnToBig(p), bnToBig(q), bnToBig(dp), bnToBig(dq), bnToBig(qinv), nil +} + +type PublicKeyRSA struct { + // _key MUST NOT be accessed directly. Instead, use the withKey method. + _key *C.GO_RSA +} + +func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) { + key := C._goboringcrypto_RSA_new() + if key == nil { + return nil, fail("RSA_new") + } + if !bigToBn(&key.n, N) || + !bigToBn(&key.e, E) { + return nil, fail("BN_bin2bn") + } + k := &PublicKeyRSA{_key: key} + runtime.SetFinalizer(k, (*PublicKeyRSA).finalize) + return k, nil +} + +func (k *PublicKeyRSA) finalize() { + C._goboringcrypto_RSA_free(k._key) +} + +func (k *PublicKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int { + // Because of the finalizer, any time _key is passed to cgo, that call must + // be followed by a call to runtime.KeepAlive, to make sure k is not + // collected (and finalized) before the cgo call returns. + defer runtime.KeepAlive(k) + return f(k._key) +} + +type PrivateKeyRSA struct { + // _key MUST NOT be accessed directly. Instead, use the withKey method. + _key *C.GO_RSA +} + +func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) { + key := C._goboringcrypto_RSA_new() + if key == nil { + return nil, fail("RSA_new") + } + if !bigToBn(&key.n, N) || + !bigToBn(&key.e, E) || + !bigToBn(&key.d, D) || + !bigToBn(&key.p, P) || + !bigToBn(&key.q, Q) || + !bigToBn(&key.dmp1, Dp) || + !bigToBn(&key.dmq1, Dq) || + !bigToBn(&key.iqmp, Qinv) { + return nil, fail("BN_bin2bn") + } + k := &PrivateKeyRSA{_key: key} + runtime.SetFinalizer(k, (*PrivateKeyRSA).finalize) + return k, nil +} + +func (k *PrivateKeyRSA) finalize() { + C._goboringcrypto_RSA_free(k._key) +} + +func (k *PrivateKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int { + // Because of the finalizer, any time _key is passed to cgo, that call must + // be followed by a call to runtime.KeepAlive, to make sure k is not + // collected (and finalized) before the cgo call returns. + defer runtime.KeepAlive(k) + return f(k._key) +} + +func setupRSA(withKey func(func(*C.GO_RSA) C.int) C.int, + padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash, + init func(*C.GO_EVP_PKEY_CTX) C.int) (pkey *C.GO_EVP_PKEY, ctx *C.GO_EVP_PKEY_CTX, err error) { + defer func() { + if err != nil { + if pkey != nil { + C._goboringcrypto_EVP_PKEY_free(pkey) + pkey = nil + } + if ctx != nil { + C._goboringcrypto_EVP_PKEY_CTX_free(ctx) + ctx = nil + } + } + }() + + pkey = C._goboringcrypto_EVP_PKEY_new() + if pkey == nil { + return nil, nil, fail("EVP_PKEY_new") + } + if withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key) + }) == 0 { + return nil, nil, fail("EVP_PKEY_set1_RSA") + } + ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil) + if ctx == nil { + return nil, nil, fail("EVP_PKEY_CTX_new") + } + if init(ctx) == 0 { + return nil, nil, fail("EVP_PKEY_operation_init") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 { + return nil, nil, fail("EVP_PKEY_CTX_set_rsa_padding") + } + if padding == C.GO_RSA_PKCS1_OAEP_PADDING { + md := hashToMD(h) + if md == nil { + return nil, nil, errors.New("crypto/rsa: unsupported hash function") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 { + return nil, nil, fail("EVP_PKEY_set_rsa_oaep_md") + } + // ctx takes ownership of label, so malloc a copy for BoringCrypto to free. + clabel := (*C.uint8_t)(C._goboringcrypto_OPENSSL_malloc(C.size_t(len(label)))) + if clabel == nil { + return nil, nil, fail("OPENSSL_malloc") + } + copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label) + if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 { + return nil, nil, fail("EVP_PKEY_CTX_set0_rsa_oaep_label") + } + } + if padding == C.GO_RSA_PKCS1_PSS_PADDING { + if saltLen != 0 { + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 { + return nil, nil, fail("EVP_PKEY_set_rsa_pss_saltlen") + } + } + md := cryptoHashToMD(ch) + if md == nil { + return nil, nil, errors.New("crypto/rsa: unsupported hash function") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 { + return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md") + } + } + + return pkey, ctx, nil +} + +func cryptRSA(withKey func(func(*C.GO_RSA) C.int) C.int, + padding C.int, h hash.Hash, label []byte, saltLen int, ch crypto.Hash, + init func(*C.GO_EVP_PKEY_CTX) C.int, + crypt func(*C.GO_EVP_PKEY_CTX, *C.uint8_t, *C.size_t, *C.uint8_t, C.size_t) C.int, + in []byte) ([]byte, error) { + + pkey, ctx, err := setupRSA(withKey, padding, h, label, saltLen, ch, init) + if err != nil { + return nil, err + } + defer C._goboringcrypto_EVP_PKEY_free(pkey) + defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx) + + var outLen C.size_t + if crypt(ctx, nil, &outLen, base(in), C.size_t(len(in))) == 0 { + return nil, fail("EVP_PKEY_decrypt/encrypt") + } + out := make([]byte, outLen) + if crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))) == 0 { + return nil, fail("EVP_PKEY_decrypt/encrypt") + } + return out[:outLen], nil +} + +func DecryptRSAOAEP(h hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) { + return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, decryptInit, decrypt, ciphertext) +} + +func EncryptRSAOAEP(h hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) { + return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, label, 0, 0, encryptInit, encrypt, msg) +} + +func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { + return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext) +} + +func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) { + return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg) +} + +func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) { + return cryptRSA(priv.withKey, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, decryptInit, decrypt, ciphertext) +} + +func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) { + return cryptRSA(pub.withKey, C.GO_RSA_NO_PADDING, nil, nil, 0, 0, encryptInit, encrypt, msg) +} + +// These dumb wrappers work around the fact that cgo functions cannot be used as values directly. + +func decryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int { + return C._goboringcrypto_EVP_PKEY_decrypt_init(ctx) +} + +func decrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int { + return C._goboringcrypto_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen) +} + +func encryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int { + return C._goboringcrypto_EVP_PKEY_encrypt_init(ctx) +} + +func encrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int { + return C._goboringcrypto_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen) +} + +func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) { + md := cryptoHashToMD(h) + if md == nil { + return nil, errors.New("crypto/rsa: unsupported hash function") + } + if saltLen == 0 { + saltLen = -1 + } + var out []byte + var outLen C.size_t + if priv.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_sign_pss_mgf1(key, &outLen, base(out), C.size_t(len(out)), + base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen)) + }) == 0 { + return nil, fail("RSA_sign_pss_mgf1") + } + + return out[:outLen], nil +} + +func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { + md := cryptoHashToMD(h) + if md == nil { + return errors.New("crypto/rsa: unsupported hash function") + } + if saltLen == 0 { + saltLen = -2 // auto-recover + } + if pub.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_RSA_verify_pss_mgf1(key, base(hashed), C.size_t(len(hashed)), + md, nil, C.int(saltLen), base(sig), C.size_t(len(sig))) + }) == 0 { + return fail("RSA_verify_pss_mgf1") + } + return nil +} + +func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) { + if h == 0 { + // No hashing. + var out []byte + var outLen C.size_t + if priv.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_sign_raw(key, &outLen, base(out), C.size_t(len(out)), + base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING) + }) == 0 { + return nil, fail("RSA_sign_raw") + } + return out[:outLen], nil + } + + md := cryptoHashToMD(h) + if md == nil { + return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h))) + } + nid := C._goboringcrypto_EVP_MD_type(md) + var out []byte + var outLen C.uint + if priv.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)), + base(out), &outLen, key) + }) == 0 { + return nil, fail("RSA_sign") + } + return out[:outLen], nil +} + +func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error { + if h == 0 { + var out []byte + var outLen C.size_t + if pub.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + return C._goboringcrypto_RSA_verify_raw(key, &outLen, base(out), + C.size_t(len(out)), base(sig), C.size_t(len(sig)), C.GO_RSA_PKCS1_PADDING) + }) == 0 { + return fail("RSA_verify") + } + if subtle.ConstantTimeCompare(hashed, out[:outLen]) != 1 { + return fail("RSA_verify") + } + return nil + } + md := cryptoHashToMD(h) + if md == nil { + return errors.New("crypto/rsa: unsupported hash function") + } + nid := C._goboringcrypto_EVP_MD_type(md) + if pub.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)), + base(sig), C.size_t(len(sig)), key) + }) == 0 { + return fail("RSA_verify") + } + return nil +} diff --git a/src/crypto/internal/boring/sha.go b/src/crypto/internal/boring/sha.go new file mode 100644 index 0000000000..5ca158ca32 --- /dev/null +++ b/src/crypto/internal/boring/sha.go @@ -0,0 +1,480 @@ +// Copyright 2017 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 linux,amd64 +// +build !android +// +build !cmd_go_bootstrap +// +build !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "errors" + "hash" + "unsafe" +) + +// NewSHA1 returns a new SHA1 hash. +func NewSHA1() hash.Hash { + h := new(sha1Hash) + h.Reset() + return h +} + +type sha1Hash struct { + ctx C.GO_SHA_CTX + out [20]byte +} + +type sha1Ctx struct { + h [5]uint32 + nl, nh uint32 + x [64]byte + nx uint32 +} + +func (h *sha1Hash) Reset() { C._goboringcrypto_SHA1_Init(&h.ctx) } +func (h *sha1Hash) Size() int { return 20 } +func (h *sha1Hash) BlockSize() int { return 64 } +func (h *sha1Hash) Sum(in []byte) []byte { return append(in, h.sum()...) } + +func (h *sha1Hash) Write(p []byte) (int, error) { + if len(p) > 0 && C._goboringcrypto_SHA1_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 { + panic("boringcrypto: SHA1_Update failed") + } + return len(p), nil +} + +func (h0 *sha1Hash) sum() []byte { + h := *h0 // make copy so future Write+Sum is valid + if C._goboringcrypto_SHA1_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 { + panic("boringcrypto: SHA1_Final failed") + } + return h.out[:] +} + +const ( + sha1Magic = "sha\x01" + sha1MarshaledSize = len(sha1Magic) + 5*4 + 64 + 8 +) + +func (h *sha1Hash) MarshalBinary() ([]byte, error) { + d := (*sha1Ctx)(unsafe.Pointer(&h.ctx)) + b := make([]byte, 0, sha1MarshaledSize) + b = append(b, sha1Magic...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29) + return b, nil +} + +func (h *sha1Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic { + return errors.New("crypto/sha1: invalid hash state identifier") + } + if len(b) != sha1MarshaledSize { + return errors.New("crypto/sha1: invalid hash state size") + } + d := (*sha1Ctx)(unsafe.Pointer(&h.ctx)) + b = b[len(sha1Magic):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b = b[copy(d.x[:], b):] + b, n := consumeUint64(b) + d.nl = uint32(n << 3) + d.nh = uint32(n >> 29) + d.nx = uint32(n) % 64 + return nil +} + +// NewSHA224 returns a new SHA224 hash. +func NewSHA224() hash.Hash { + h := new(sha224Hash) + h.Reset() + return h +} + +type sha224Hash struct { + ctx C.GO_SHA256_CTX + out [224 / 8]byte +} + +func (h *sha224Hash) Reset() { C._goboringcrypto_SHA224_Init(&h.ctx) } +func (h *sha224Hash) Size() int { return 224 / 8 } +func (h *sha224Hash) BlockSize() int { return 64 } +func (h *sha224Hash) Sum(in []byte) []byte { return append(in, h.sum()...) } + +func (h *sha224Hash) Write(p []byte) (int, error) { + if len(p) > 0 && C._goboringcrypto_SHA224_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 { + panic("boringcrypto: SHA224_Update failed") + } + return len(p), nil +} + +func (h0 *sha224Hash) sum() []byte { + h := *h0 // make copy so future Write+Sum is valid + if C._goboringcrypto_SHA224_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 { + panic("boringcrypto: SHA224_Final failed") + } + return h.out[:] +} + +// NewSHA256 returns a new SHA256 hash. +func NewSHA256() hash.Hash { + h := new(sha256Hash) + h.Reset() + return h +} + +type sha256Hash struct { + ctx C.GO_SHA256_CTX + out [256 / 8]byte +} + +func (h *sha256Hash) Reset() { C._goboringcrypto_SHA256_Init(&h.ctx) } +func (h *sha256Hash) Size() int { return 256 / 8 } +func (h *sha256Hash) BlockSize() int { return 64 } +func (h *sha256Hash) Sum(in []byte) []byte { return append(in, h.sum()...) } + +func (h *sha256Hash) Write(p []byte) (int, error) { + if len(p) > 0 && C._goboringcrypto_SHA256_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 { + panic("boringcrypto: SHA256_Update failed") + } + return len(p), nil +} + +func (h0 *sha256Hash) sum() []byte { + h := *h0 // make copy so future Write+Sum is valid + if C._goboringcrypto_SHA256_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 { + panic("boringcrypto: SHA256_Final failed") + } + return h.out[:] +} + +const ( + magic224 = "sha\x02" + magic256 = "sha\x03" + marshaledSize256 = len(magic256) + 8*4 + 64 + 8 +) + +type sha256Ctx struct { + h [8]uint32 + nl, nh uint32 + x [64]byte + nx uint32 +} + +func (h *sha224Hash) MarshalBinary() ([]byte, error) { + d := (*sha256Ctx)(unsafe.Pointer(&h.ctx)) + b := make([]byte, 0, marshaledSize256) + b = append(b, magic224...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = appendUint32(b, d.h[5]) + b = appendUint32(b, d.h[6]) + b = appendUint32(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29) + return b, nil +} + +func (h *sha256Hash) MarshalBinary() ([]byte, error) { + d := (*sha256Ctx)(unsafe.Pointer(&h.ctx)) + b := make([]byte, 0, marshaledSize256) + b = append(b, magic256...) + b = appendUint32(b, d.h[0]) + b = appendUint32(b, d.h[1]) + b = appendUint32(b, d.h[2]) + b = appendUint32(b, d.h[3]) + b = appendUint32(b, d.h[4]) + b = appendUint32(b, d.h[5]) + b = appendUint32(b, d.h[6]) + b = appendUint32(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29) + return b, nil +} + +func (h *sha224Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic224) || string(b[:len(magic224)]) != magic224 { + return errors.New("crypto/sha256: invalid hash state identifier") + } + if len(b) != marshaledSize256 { + return errors.New("crypto/sha256: invalid hash state size") + } + d := (*sha256Ctx)(unsafe.Pointer(&h.ctx)) + b = b[len(magic224):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b, d.h[5] = consumeUint32(b) + b, d.h[6] = consumeUint32(b) + b, d.h[7] = consumeUint32(b) + b = b[copy(d.x[:], b):] + b, n := consumeUint64(b) + d.nl = uint32(n << 3) + d.nh = uint32(n >> 29) + d.nx = uint32(n) % 64 + return nil +} + +func (h *sha256Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic256) || string(b[:len(magic256)]) != magic256 { + return errors.New("crypto/sha256: invalid hash state identifier") + } + if len(b) != marshaledSize256 { + return errors.New("crypto/sha256: invalid hash state size") + } + d := (*sha256Ctx)(unsafe.Pointer(&h.ctx)) + b = b[len(magic256):] + b, d.h[0] = consumeUint32(b) + b, d.h[1] = consumeUint32(b) + b, d.h[2] = consumeUint32(b) + b, d.h[3] = consumeUint32(b) + b, d.h[4] = consumeUint32(b) + b, d.h[5] = consumeUint32(b) + b, d.h[6] = consumeUint32(b) + b, d.h[7] = consumeUint32(b) + b = b[copy(d.x[:], b):] + b, n := consumeUint64(b) + d.nl = uint32(n << 3) + d.nh = uint32(n >> 29) + d.nx = uint32(n) % 64 + return nil +} + +// NewSHA384 returns a new SHA384 hash. +func NewSHA384() hash.Hash { + h := new(sha384Hash) + h.Reset() + return h +} + +type sha384Hash struct { + ctx C.GO_SHA512_CTX + out [384 / 8]byte +} + +func (h *sha384Hash) Reset() { C._goboringcrypto_SHA384_Init(&h.ctx) } +func (h *sha384Hash) Size() int { return 384 / 8 } +func (h *sha384Hash) BlockSize() int { return 128 } +func (h *sha384Hash) Sum(in []byte) []byte { return append(in, h.sum()...) } + +func (h *sha384Hash) Write(p []byte) (int, error) { + if len(p) > 0 && C._goboringcrypto_SHA384_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 { + panic("boringcrypto: SHA384_Update failed") + } + return len(p), nil +} + +func (h0 *sha384Hash) sum() []byte { + h := *h0 // make copy so future Write+Sum is valid + if C._goboringcrypto_SHA384_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 { + panic("boringcrypto: SHA384_Final failed") + } + return h.out[:] +} + +// NewSHA512 returns a new SHA512 hash. +func NewSHA512() hash.Hash { + h := new(sha512Hash) + h.Reset() + return h +} + +type sha512Hash struct { + ctx C.GO_SHA512_CTX + out [512 / 8]byte +} + +func (h *sha512Hash) Reset() { C._goboringcrypto_SHA512_Init(&h.ctx) } +func (h *sha512Hash) Size() int { return 512 / 8 } +func (h *sha512Hash) BlockSize() int { return 128 } +func (h *sha512Hash) Sum(in []byte) []byte { return append(in, h.sum()...) } + +func (h *sha512Hash) Write(p []byte) (int, error) { + if len(p) > 0 && C._goboringcrypto_SHA512_Update(&h.ctx, unsafe.Pointer(&p[0]), C.size_t(len(p))) == 0 { + panic("boringcrypto: SHA512_Update failed") + } + return len(p), nil +} + +func (h0 *sha512Hash) sum() []byte { + h := *h0 // make copy so future Write+Sum is valid + if C._goboringcrypto_SHA512_Final((*C.uint8_t)(unsafe.Pointer(&h.out[0])), &h.ctx) == 0 { + panic("boringcrypto: SHA512_Final failed") + } + return h.out[:] +} + +type sha512Ctx struct { + h [8]uint64 + nl, nh uint64 + x [128]byte + nx uint32 +} + +const ( + magic384 = "sha\x04" + magic512_224 = "sha\x05" + magic512_256 = "sha\x06" + magic512 = "sha\x07" + marshaledSize512 = len(magic512) + 8*8 + 128 + 8 +) + +var zero [128]byte + +func (h *sha384Hash) MarshalBinary() ([]byte, error) { + d := (*sha512Ctx)(unsafe.Pointer(&h.ctx)) + b := make([]byte, 0, marshaledSize512) + b = append(b, magic384...) + b = appendUint64(b, d.h[0]) + b = appendUint64(b, d.h[1]) + b = appendUint64(b, d.h[2]) + b = appendUint64(b, d.h[3]) + b = appendUint64(b, d.h[4]) + b = appendUint64(b, d.h[5]) + b = appendUint64(b, d.h[6]) + b = appendUint64(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, d.nl>>3|d.nh<<61) + return b, nil +} + +func (h *sha512Hash) MarshalBinary() ([]byte, error) { + d := (*sha512Ctx)(unsafe.Pointer(&h.ctx)) + b := make([]byte, 0, marshaledSize512) + b = append(b, magic512...) + b = appendUint64(b, d.h[0]) + b = appendUint64(b, d.h[1]) + b = appendUint64(b, d.h[2]) + b = appendUint64(b, d.h[3]) + b = appendUint64(b, d.h[4]) + b = appendUint64(b, d.h[5]) + b = appendUint64(b, d.h[6]) + b = appendUint64(b, d.h[7]) + b = append(b, d.x[:d.nx]...) + b = b[:len(b)+len(d.x)-int(d.nx)] // already zero + b = appendUint64(b, d.nl>>3|d.nh<<61) + return b, nil +} + +func (h *sha384Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic512) { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if string(b[:len(magic384)]) != magic384 { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if len(b) != marshaledSize512 { + return errors.New("crypto/sha512: invalid hash state size") + } + d := (*sha512Ctx)(unsafe.Pointer(&h.ctx)) + b = b[len(magic512):] + b, d.h[0] = consumeUint64(b) + b, d.h[1] = consumeUint64(b) + b, d.h[2] = consumeUint64(b) + b, d.h[3] = consumeUint64(b) + b, d.h[4] = consumeUint64(b) + b, d.h[5] = consumeUint64(b) + b, d.h[6] = consumeUint64(b) + b, d.h[7] = consumeUint64(b) + b = b[copy(d.x[:], b):] + b, n := consumeUint64(b) + d.nl = n << 3 + d.nh = n >> 61 + d.nx = uint32(n) % 128 + return nil +} + +func (h *sha512Hash) UnmarshalBinary(b []byte) error { + if len(b) < len(magic512) { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if string(b[:len(magic512)]) != magic512 { + return errors.New("crypto/sha512: invalid hash state identifier") + } + if len(b) != marshaledSize512 { + return errors.New("crypto/sha512: invalid hash state size") + } + d := (*sha512Ctx)(unsafe.Pointer(&h.ctx)) + b = b[len(magic512):] + b, d.h[0] = consumeUint64(b) + b, d.h[1] = consumeUint64(b) + b, d.h[2] = consumeUint64(b) + b, d.h[3] = consumeUint64(b) + b, d.h[4] = consumeUint64(b) + b, d.h[5] = consumeUint64(b) + b, d.h[6] = consumeUint64(b) + b, d.h[7] = consumeUint64(b) + b = b[copy(d.x[:], b):] + b, n := consumeUint64(b) + d.nl = n << 3 + d.nh = n >> 61 + d.nx = uint32(n) % 128 + return nil +} + +func appendUint64(b []byte, x uint64) []byte { + var a [8]byte + putUint64(a[:], x) + return append(b, a[:]...) +} + +func appendUint32(b []byte, x uint32) []byte { + var a [4]byte + putUint32(a[:], x) + return append(b, a[:]...) +} + +func consumeUint64(b []byte) ([]byte, uint64) { + _ = b[7] + x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 | + uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 + return b[8:], x +} + +func consumeUint32(b []byte) ([]byte, uint32) { + _ = b[3] + x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24 + return b[4:], x +} + +func putUint64(x []byte, s uint64) { + _ = x[7] + x[0] = byte(s >> 56) + x[1] = byte(s >> 48) + x[2] = byte(s >> 40) + x[3] = byte(s >> 32) + x[4] = byte(s >> 24) + x[5] = byte(s >> 16) + x[6] = byte(s >> 8) + x[7] = byte(s) +} + +func putUint32(x []byte, s uint32) { + _ = x[3] + x[0] = byte(s >> 24) + x[1] = byte(s >> 16) + x[2] = byte(s >> 8) + x[3] = byte(s) +} diff --git a/src/crypto/internal/boring/sig/sig.go b/src/crypto/internal/boring/sig/sig.go new file mode 100644 index 0000000000..716c03c5e9 --- /dev/null +++ b/src/crypto/internal/boring/sig/sig.go @@ -0,0 +1,17 @@ +// Copyright 2017 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 sig holds “code signatures” that can be called +// and will result in certain code sequences being linked into +// the final binary. The functions themselves are no-ops. +package sig + +// BoringCrypto indicates that the BoringCrypto module is present. +func BoringCrypto() + +// FIPSOnly indicates that package crypto/tls/fipsonly is present. +func FIPSOnly() + +// StandardCrypto indicates that standard Go crypto is present. +func StandardCrypto() diff --git a/src/crypto/internal/boring/sig/sig_amd64.s b/src/crypto/internal/boring/sig/sig_amd64.s new file mode 100644 index 0000000000..64e3462e4e --- /dev/null +++ b/src/crypto/internal/boring/sig/sig_amd64.s @@ -0,0 +1,54 @@ +// Copyright 2017 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. + +#include "textflag.h" + +// These functions are no-ops, but you can search for their implementations +// to find out whether they are linked into a particular binary. +// +// Each function consists of a two-byte jump over the next 29-bytes, +// then a 5-byte indicator sequence unlikely to occur in real x86 instructions, +// then a randomly-chosen 24-byte sequence, and finally a return instruction +// (the target of the jump). +// +// These sequences are known to rsc.io/goversion. + +#define START \ + BYTE $0xEB; BYTE $0x1D; BYTE $0xF4; BYTE $0x48; BYTE $0xF4; BYTE $0x4B; BYTE $0xF4 + +#define END \ + BYTE $0xC3 + +// BoringCrypto indicates that BoringCrypto (in particular, its func init) is present. +TEXT ·BoringCrypto(SB),NOSPLIT,$0 + START + BYTE $0xB3; BYTE $0x32; BYTE $0xF5; BYTE $0x28; + BYTE $0x13; BYTE $0xA3; BYTE $0xB4; BYTE $0x50; + BYTE $0xD4; BYTE $0x41; BYTE $0xCC; BYTE $0x24; + BYTE $0x85; BYTE $0xF0; BYTE $0x01; BYTE $0x45; + BYTE $0x4E; BYTE $0x92; BYTE $0x10; BYTE $0x1B; + BYTE $0x1D; BYTE $0x2F; BYTE $0x19; BYTE $0x50; + END + +// StandardCrypto indicates that standard Go crypto is present. +TEXT ·StandardCrypto(SB),NOSPLIT,$0 + START + BYTE $0xba; BYTE $0xee; BYTE $0x4d; BYTE $0xfa; + BYTE $0x98; BYTE $0x51; BYTE $0xca; BYTE $0x56; + BYTE $0xa9; BYTE $0x11; BYTE $0x45; BYTE $0xe8; + BYTE $0x3e; BYTE $0x99; BYTE $0xc5; BYTE $0x9c; + BYTE $0xf9; BYTE $0x11; BYTE $0xcb; BYTE $0x8e; + BYTE $0x80; BYTE $0xda; BYTE $0xf1; BYTE $0x2f; + END + +// FIPSOnly indicates that crypto/tls/fipsonly is present. +TEXT ·FIPSOnly(SB),NOSPLIT,$0 + START + BYTE $0x36; BYTE $0x3C; BYTE $0xB9; BYTE $0xCE; + BYTE $0x9D; BYTE $0x68; BYTE $0x04; BYTE $0x7D; + BYTE $0x31; BYTE $0xF2; BYTE $0x8D; BYTE $0x32; + BYTE $0x5D; BYTE $0x5C; BYTE $0xA5; BYTE $0x87; + BYTE $0x3F; BYTE $0x5D; BYTE $0x80; BYTE $0xCA; + BYTE $0xF6; BYTE $0xD6; BYTE $0x15; BYTE $0x1B; + END diff --git a/src/crypto/internal/boring/sig/sig_other.s b/src/crypto/internal/boring/sig/sig_other.s new file mode 100644 index 0000000000..2eb31734ef --- /dev/null +++ b/src/crypto/internal/boring/sig/sig_other.s @@ -0,0 +1,19 @@ +// Copyright 2017 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. + +// These functions are no-ops. +// On amd64 they have recognizable implementations, so that you can +// search a particular binary to see if they are present. +// On other platforms (those using this source file), they don't. + +// +build !amd64 + +TEXT ·BoringCrypto(SB),$0 + RET + +TEXT ·FIPSOnly(SB),$0 + RET + +TEXT ·StandardCrypto(SB),$0 + RET |