diff --git a/scripts/check-diff.sh b/scripts/check-diff.sh new file mode 100755 index 00000000..7d1f007b --- /dev/null +++ b/scripts/check-diff.sh @@ -0,0 +1,15 @@ +#!/bin/bash + +trap cleanup EXIT + +function cleanup() { + rm scripts/generated-diffcheck.txt +} + +diff openssl v2/openssl > scripts/generated-diffcheck.txt + +DIFF_OUTPUT=$(diff scripts/generated-diff.txt scripts/generated-diffcheck.txt) +if [ "$DIFF_OUTPUT" ]; then + echo "Modifications have been made to the generated diff. Please review and update the diff." + exit 1 +fi \ No newline at end of file diff --git a/scripts/create-diff.sh b/scripts/create-diff.sh new file mode 100755 index 00000000..1d8778b1 --- /dev/null +++ b/scripts/create-diff.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -ex + +diff openssl v2/openssl > scripts/generated-diff.txt \ No newline at end of file diff --git a/scripts/generated-diff.txt b/scripts/generated-diff.txt new file mode 100644 index 00000000..6afd670c --- /dev/null +++ b/scripts/generated-diff.txt @@ -0,0 +1,189 @@ +diff openssl/aes.go v2/openssl/aes.go +365a366,371 +> // NewGCMTLS returns a GCM cipher specific to TLS +> // and should not be used for non-TLS purposes. +> func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { +> return c.(*aesCipher).NewGCMTLS() +> } +> +Only in v2/openssl: bbig +diff openssl/ecdh_test.go v2/openssl/ecdh_test.go +1c1 +< package openssl +--- +> package openssl_test +4a5,6 +> "github.com/golang-fips/openssl-fips/v2/openssl" +> "github.com/golang-fips/openssl-fips/v2/openssl/bbig" +10c12 +< if !Enabled() { +--- +> if !openssl.Enabled() { +56c58,60 +< priv, err := NewPrivateKeyECDH("P-256", x, y, k) +--- +> bx, by, bk := bbig.Enc(x), bbig.Enc(y), bbig.Enc(k) +> +> priv, err := openssl.NewPrivateKeyECDH("P-256", bx, by, bk) +61c65 +< derived, err := SharedKeyECDH(priv, peerPublicKey) +--- +> derived, err := openssl.SharedKeyECDH(priv, peerPublicKey) +diff openssl/ecdsa.go v2/openssl/ecdsa.go +13,14d12 +< "crypto" +< "encoding/asn1" +16d13 +< "math/big" +22c19 +< R, S *big.Int +--- +> R, S BigInt +61c58 +< func NewPublicKeyECDSA(curve string, X, Y *big.Int) (*PublicKeyECDSA, error) { +--- +> func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) { +75c72 +< func newECKey(curve string, X, Y *big.Int) (*C.GO_EC_KEY, error) { +--- +> func newECKey(curve string, X, Y BigInt) (*C.GO_EC_KEY, error) { +108c105 +< func NewPrivateKeyECDSA(curve string, X, Y *big.Int, D *big.Int) (*PrivateKeyECDSA, error) { +--- +> func NewPrivateKeyECDSA(curve string, X, Y BigInt, D BigInt) (*PrivateKeyECDSA, error) { +131,147c128 +< func SignECDSA(priv *PrivateKeyECDSA, hash []byte, h crypto.Hash) (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, h) +< 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, h crypto.Hash) ([]byte, error) { +--- +> func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) { +151,163c132,134 +< if h == crypto.Hash(0) { +< ok := C._goboringcrypto_internal_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) > 0 +< if !ok { +< return nil, NewOpenSSLError(("ECDSA_sign failed")) +< } +< } else { +< md := cryptoHashToMD(h) +< if md == nil { +< panic("boring: invalid hash") +< } +< if C._goboringcrypto_ECDSA_sign(md, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) == 0 { +< return nil, NewOpenSSLError("ECDSA_sign failed") +< } +--- +> ok := C._goboringcrypto_internal_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) > 0 +> if !ok { +> return nil, NewOpenSSLError(("ECDSA_sign failed")) +164a136 +> +168,186c140,141 +< +< func VerifyECDSA(pub *PublicKeyECDSA, msg []byte, r, s *big.Int, h crypto.Hash) 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 +< } +< if h == crypto.Hash(0) { +< ok := C._goboringcrypto_internal_ECDSA_verify(0, base(msg), C.size_t(len(msg)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.uint(len(sig)), pub.key) > 0 +< runtime.KeepAlive(pub) +< return ok +< } +< md := cryptoHashToMD(h) +< if md == nil { +< panic("boring: invalid hash") +< } +< ok := C._goboringcrypto_ECDSA_verify(md, base(msg), C.size_t(len(msg)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.uint(len(sig)), pub.key) > 0 +--- +> func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool { +> ok := C._goboringcrypto_internal_ECDSA_verify(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.uint(len(sig)), pub.key) > 0 +191c146 +< func GenerateKeyECDSA(curve string) (X, Y, D *big.Int, err error) { +--- +> func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) { +diff openssl/goopenssl.h v2/openssl/goopenssl.h +371a372,373 +> DEFINEFUNC(int, BN_bn2le_padded, (uint8_t *out, size_t len, const BIGNUM *in), (out, len, in)) +> DEFINEFUNC(GO_BIGNUM *, BN_le2bn, (const uint8_t *in, size_t len, BIGNUM *ret), (in, len, ret)) +diff openssl/openssl.go v2/openssl/openssl.go +19c19 +< "math/big" +--- +> "math/bits" +39a40,44 +> // A BigInt is the raw words from a BigInt. +> // This definition allows us to avoid importing math/big. +> // Conversion between BigInt and *big.Int is in crypto/internal/boring/bbig. +> type BigInt []uint +> +186,188c191,201 +< 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 wbase(b BigInt) *C.uint8_t { +> if len(b) == 0 { +> return nil +> } +> return (*C.uint8_t)(unsafe.Pointer(&b[0])) +> } +> +> const wordBytes = bits.UintSize / 8 +> +> func bigToBN(x BigInt) *C.GO_BIGNUM { +> return C._goboringcrypto_BN_le2bn(wbase(x), C.size_t(len(x)*wordBytes), nil) +191,194c204,209 +< 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 bnToBig(bn *C.GO_BIGNUM) BigInt { +> x := make(BigInt, (C._goboringcrypto_BN_num_bytes(bn)+wordBytes-1)/wordBytes) +> if C._goboringcrypto_BN_bn2le_padded(wbase(x), C.size_t(len(x)*wordBytes), bn) == 0 { +> panic("boringcrypto: bignum conversion failed") +> } +> return x +197c212 +< func bigToBn(bnp **C.GO_BIGNUM, b *big.Int) bool { +--- +> func bigToBn(bnp **C.GO_BIGNUM, b BigInt) bool { +205,206c220 +< raw := b.Bytes() +< bn := C._goboringcrypto_BN_bin2bn(base(raw), C.size_t(len(raw)), nil) +--- +> bn := bigToBN(b) +diff openssl/rsa.go v2/openssl/rsa.go +16d15 +< "math/big" +22,23c21,22 +< 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) { +--- +> func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { +> bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { +49c48 +< func NewPublicKeyRSA(N, E *big.Int) (*PublicKeyRSA, error) { +--- +> func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) { +80c79 +< func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv *big.Int) (*PrivateKeyRSA, error) { +--- +> func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) { diff --git a/v2/go.mod b/v2/go.mod new file mode 100644 index 00000000..00516c65 --- /dev/null +++ b/v2/go.mod @@ -0,0 +1,3 @@ +module github.com/golang-fips/openssl-fips/v2 + +go 1.18 diff --git a/v2/openssl/aes.go b/v2/openssl/aes.go new file mode 100644 index 00000000..079fc3c4 --- /dev/null +++ b/v2/openssl/aes.go @@ -0,0 +1,516 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +// #include "goopenssl.h" +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_ctx *C.EVP_CIPHER_CTX + dec_ctx *C.EVP_CIPHER_CTX + cipher *C.EVP_CIPHER +} + +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) + + switch len(c.key) * 8 { + case 128: + c.cipher = C._goboringcrypto_EVP_aes_128_ecb() + case 192: + c.cipher = C._goboringcrypto_EVP_aes_192_ecb() + case 256: + c.cipher = C._goboringcrypto_EVP_aes_256_ecb() + default: + return nil, errors.New("crypto/cipher: Invalid key size") + } + + runtime.SetFinalizer(c, (*aesCipher).finalize) + + return c, nil +} + +func (c *aesCipher) finalize() { + if c.enc_ctx != nil { + C._goboringcrypto_EVP_CIPHER_CTX_free(c.enc_ctx) + } + if c.dec_ctx != nil { + C._goboringcrypto_EVP_CIPHER_CTX_free(c.dec_ctx) + } +} + +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") + } + + if c.enc_ctx == nil { + c.enc_ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() + if c.enc_ctx == nil { + panic("cipher: unable to create EVP cipher ctx") + } + + k := (*C.uchar)(unsafe.Pointer(&c.key[0])) + + if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(c.enc_ctx, c.cipher, nil, k, nil, C.GO_AES_ENCRYPT) { + panic("cipher: unable to initialize EVP cipher ctx") + } + } + + outlen := C.int(0) + C._goboringcrypto_EVP_CipherUpdate(c.enc_ctx, (*C.uchar)(unsafe.Pointer(&dst[0])), &outlen, (*C.uchar)(unsafe.Pointer(&src[0])), C.int(aesBlockSize)) + runtime.KeepAlive(c) +} + +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") + } + if c.dec_ctx == nil { + c.dec_ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() + if c.dec_ctx == nil { + panic("cipher: unable to create EVP cipher ctx") + } + + k := (*C.uchar)(unsafe.Pointer(&c.key[0])) + + if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(c.dec_ctx, c.cipher, nil, k, nil, C.GO_AES_DECRYPT) { + panic("cipher: unable to initialize EVP cipher ctx") + } + } + // Workaround - padding detection is broken but we don't need it + // since we check for full blocks + if C._goboringcrypto_EVP_CIPHER_CTX_set_padding(c.dec_ctx, 0) != 1 { + panic("crypto/cipher: could not disable cipher padding") + } + outlen := C.int(0) + C._goboringcrypto_EVP_CipherUpdate(c.dec_ctx, (*C.uchar)(unsafe.Pointer(&dst[0])), &outlen, (*C.uchar)(unsafe.Pointer(&src[0])), C.int(aesBlockSize)) + runtime.KeepAlive(c) +} + +type aesCBC struct { + key []byte + mode C.int + iv [aesBlockSize]byte + ctx *C.EVP_CIPHER_CTX +} + +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 { + outlen := C.int(0) + // Workaround - padding detection is broken but we don't need it + // since we check for full blocks + if C._goboringcrypto_EVP_CIPHER_CTX_set_padding(x.ctx, 0) != 1 { + panic("crypto/cipher: could not disable cipher padding") + } + if C._goboringcrypto_EVP_CipherUpdate( + x.ctx, + base(dst), &outlen, + base(src), C.int(len(src)), + ) != 1 { + panic("crypto/cipher: CipherUpdate failed") + } + runtime.KeepAlive(x) + } +} + +func (x *aesCBC) SetIV(iv []byte) { + if len(iv) != aesBlockSize { + panic("cipher: incorrect length IV") + } + copy(x.iv[:], iv) + if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(x.ctx, nil, nil, nil, (*C.uchar)(unsafe.Pointer(&x.iv[0])), -1) { + panic("cipher: unable to initialize EVP cipher ctx") + } +} + +func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode { + x := &aesCBC{key: c.key, mode: C.GO_AES_ENCRYPT} + copy(x.iv[:], iv) + + x.ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() + if x.ctx == nil { + panic("cipher: unable to create EVP cipher ctx") + } + + k := (*C.uchar)(unsafe.Pointer(&x.key[0])) + vec := (*C.uchar)(unsafe.Pointer(&x.iv[0])) + + var cipher *C.EVP_CIPHER + switch len(c.key) * 8 { + case 128: + cipher = C._goboringcrypto_EVP_aes_128_cbc() + case 192: + cipher = C._goboringcrypto_EVP_aes_192_cbc() + case 256: + cipher = C._goboringcrypto_EVP_aes_256_cbc() + default: + panic("crypto/boring: unsupported key length") + } + if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(x.ctx, cipher, nil, k, vec, x.mode) { + panic("cipher: unable to initialize EVP cipher ctx") + } + + runtime.SetFinalizer(x, (*aesCBC).finalize) + + return x +} + +func (c *aesCBC) finalize() { + C._goboringcrypto_EVP_CIPHER_CTX_free(c.ctx) +} + +func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode { + x := &aesCBC{key: c.key, mode: C.GO_AES_DECRYPT} + copy(x.iv[:], iv) + + x.ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() + if x.ctx == nil { + panic("cipher: unable to create EVP cipher ctx") + } + + k := (*C.uchar)(unsafe.Pointer(&x.key[0])) + vec := (*C.uchar)(unsafe.Pointer(&x.iv[0])) + + var cipher *C.EVP_CIPHER + switch len(c.key) * 8 { + case 128: + cipher = C._goboringcrypto_EVP_aes_128_cbc() + case 192: + cipher = C._goboringcrypto_EVP_aes_192_cbc() + case 256: + cipher = C._goboringcrypto_EVP_aes_256_cbc() + default: + panic("crypto/boring: unsupported key length") + } + if C.int(1) != C._goboringcrypto_EVP_CipherInit_ex(x.ctx, cipher, nil, k, vec, x.mode) { + panic("cipher: unable to initialize EVP cipher ctx") + } + if C.int(1) != C._goboringcrypto_EVP_CIPHER_CTX_set_padding(x.ctx, 0) { + panic("cipher: unable to set padding") + } + + runtime.SetFinalizer(x, (*aesCBC).finalize) + return x +} + +type aesCTR struct { + key []byte + iv [aesBlockSize]byte + ctx *C.EVP_CIPHER_CTX + 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_EVP_AES_ctr128_enc( + x.ctx, + (*C.uint8_t)(unsafe.Pointer(&src[0])), + (*C.uint8_t)(unsafe.Pointer(&dst[0])), + C.size_t(len(src))) + runtime.KeepAlive(x) +} + +func (c *aesCipher) NewCTR(iv []byte) cipher.Stream { + x := &aesCTR{key: c.key} + copy(x.iv[:], iv) + + x.ctx = C._goboringcrypto_EVP_CIPHER_CTX_new() + if x.ctx == nil { + panic("cipher: unable to create EVP cipher ctx") + } + + k := (*C.uchar)(unsafe.Pointer(&x.key[0])) + vec := (*C.uchar)(unsafe.Pointer(&x.iv[0])) + + switch len(c.key) * 8 { + case 128: + if C.int(1) != C._goboringcrypto_EVP_EncryptInit_ex(x.ctx, C._goboringcrypto_EVP_aes_128_ctr(), nil, k, vec) { + panic("cipher: unable to initialize EVP cipher ctx") + } + case 192: + if C.int(1) != C._goboringcrypto_EVP_EncryptInit_ex(x.ctx, C._goboringcrypto_EVP_aes_192_ctr(), nil, k, vec) { + panic("cipher: unable to initialize EVP cipher ctx") + } + case 256: + if C.int(1) != C._goboringcrypto_EVP_EncryptInit_ex(x.ctx, C._goboringcrypto_EVP_aes_256_ctr(), nil, k, vec) { + panic("cipher: unable to initialize EVP cipher ctx") + } + } + + runtime.SetFinalizer(x, (*aesCTR).finalize) + + return x +} + +func (c *aesCTR) finalize() { + C._goboringcrypto_EVP_CIPHER_CTX_free(c.ctx) +} + +type aesGCM struct { + key []byte + tls bool +} + +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 !ExecutingTest() || IsStrictFips() { + if nonceSize != gcmStandardNonceSize { + return nil, errors.New("crypto/aes: GCM nonce size can't be non-standard") + } + if tagSize != gcmTagSize { + return nil, errors.New("crypto/aes: GCM tag size can't be non-standard") + } + } else { + // Be more lenient if we're running via a test binary so that + // we don't have to be as invasive with skipping tests in the standard + // library. + 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) +} + +// NewGCMTLS returns a GCM cipher specific to TLS +// and should not be used for non-TLS purposes. +func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) { + return c.(*aesCipher).NewGCMTLS() +} + +func (c *aesCipher) NewGCMTLS() (cipher.AEAD, error) { + return c.newGCM(true) +} + +func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) { + keyLen := len(c.key) * 8 + + if keyLen != 128 && keyLen != 256 { + if ExecutingTest() { + // Fall back to standard library for GCM with non-standard key size. + return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize) + } + // Return error for GCM with non-standard key size. + return nil, fail("GCM invoked with non-standard key size") + } + + g := &aesGCM{key: c.key, tls: tls} + 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) NonceSize() int { + return gcmStandardNonceSize +} + +func (g *aesGCM) Overhead() int { + return gcmTagSize +} + +// 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") + } + + var ciphertextLen C.size_t + + if ok := C._goboringcrypto_EVP_CIPHER_CTX_seal( + (*C.uint8_t)(unsafe.Pointer(&dst[n])), + base(nonce), base(additionalData), C.size_t(len(additionalData)), + base(plaintext), C.size_t(len(plaintext)), &ciphertextLen, + base(g.key), C.int(len(g.key)*8)); ok != 1 { + panic("boringcrypto: EVP_CIPHER_CTX_seal fail") + } + runtime.KeepAlive(g) + + if ciphertextLen != C.size_t(len(plaintext)+gcmTagSize) { + panic("boringcrypto: [seal] internal confusion about GCM tag size") + } + return dst[:n+int(ciphertextLen)] +} + +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") + } + + tag := ciphertext[len(ciphertext)-gcmTagSize:] + + var outLen C.size_t + + ok := C._goboringcrypto_EVP_CIPHER_CTX_open( + base(ciphertext), C.int(len(ciphertext)-gcmTagSize), + base(additionalData), C.int(len(additionalData)), + base(tag), base(g.key), C.int(len(g.key)*8), + base(nonce), C.int(len(nonce)), + base(dst[n:]), &outLen) + runtime.KeepAlive(g) + if ok == 0 { + // Zero output buffer on error. + for i := range dst { + dst[i] = 0 + } + return nil, errOpen + } + if outLen != C.size_t(len(ciphertext)-gcmTagSize) { + panic("boringcrypto: [open] internal confusion about GCM tag size") + } + 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/v2/openssl/aes_test.go b/v2/openssl/aes_test.go new file mode 100644 index 00000000..a13054a7 --- /dev/null +++ b/v2/openssl/aes_test.go @@ -0,0 +1,180 @@ +//go:build linux && !android && !no_openssl && !cmd_go_bootstrap && !msan && cgo +// +build linux,!android,!no_openssl,!cmd_go_bootstrap,!msan,cgo + +package openssl + +import ( + "bytes" + "crypto/cipher" + "os" + "testing" +) + +func TestNewGCMNonce(t *testing.T) { + origStrictFIPS := os.Getenv(GoStrictFipsEnv) + os.Setenv(GoStrictFipsEnv, "1") + defer os.Setenv(GoStrictFipsEnv, origStrictFIPS) + + // Should return an error for non-standard nonce size. + key := []byte("D249BF6DEC97B1EBD69BC4D6B3A3C49D") + ci, err := NewAESCipher(key) + if err != nil { + t.Fatal(err) + } + c := ci.(*aesCipher) + _, err = c.NewGCM(gcmStandardNonceSize-1, gcmTagSize) + if err == nil { + t.Error("expected error for non-standard nonce size, got none") + } + _, err = c.NewGCM(gcmStandardNonceSize, gcmTagSize-1) + if err == nil { + t.Error("expected error for non-standard tag size, got none") + } + _, err = c.NewGCM(gcmStandardNonceSize, gcmTagSize) + if err != nil { + t.Errorf("expected no error for standard tag / nonce size, got: %#v", err) + } +} + +func TestBlobEncryptBasicBlockEncryption(t *testing.T) { + key := []byte{0x24, 0xcd, 0x8b, 0x13, 0x37, 0xc5, 0xc1, 0xb1, 0x0, 0xbb, 0x27, 0x40, 0x4f, 0xab, 0x5f, 0x7b, 0x2d, 0x0, 0x20, 0xf5, 0x1, 0x84, 0x4, 0xbf, 0xe3, 0xbd, 0xa1, 0xc4, 0xbf, 0x61, 0x2f, 0xc5} + iv := []byte{0x91, 0xc7, 0xa7, 0x54, 0x52, 0xef, 0x10, 0xdb, 0x91, 0xa8, 0x6c, 0xf9, 0x79, 0xd5, 0xac, 0x74} + + block, err := NewAESCipher(key) + if err != nil { + t.Errorf("expected no error for aes.NewCipher, got: %s", err) + } + + blockSize := block.BlockSize() + if blockSize != 16 { + t.Errorf("unexpected block size, expected 16 got: %d", blockSize) + } + var encryptor cipher.BlockMode + if c, ok := block.(*aesCipher); ok { + encryptor = c.NewCBCEncrypter(iv) + if encryptor == nil { + t.Error("unable to create new CBC encrypter") + } + } + + encrypted := make([]byte, 32) + + // First block. 16 bytes. + srcBlock1 := bytes.Repeat([]byte{0x01}, 16) + encryptor.CryptBlocks(encrypted, srcBlock1) + if !bytes.Equal([]byte{ + 0x14, 0xb7, 0x3e, 0x2f, 0xd9, 0xe7, 0x69, 0x7e, 0xb7, 0xd2, 0xc3, 0x5b, 0x31, 0x9c, 0xf0, 0x59, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + }, encrypted) { + t.Error("unexpected CryptBlocks result for first block") + } + + // Second block. 16 bytes. + srcBlock2 := bytes.Repeat([]byte{0x02}, 16) + encryptor.CryptBlocks(encrypted[16:], srcBlock2) + if !bytes.Equal([]byte{ + 0x14, 0xb7, 0x3e, 0x2f, 0xd9, 0xe7, 0x69, 0x7e, 0xb7, 0xd2, 0xc3, 0x5b, 0x31, 0x9c, 0xf0, 0x59, + 0xbb, 0xd4, 0x95, 0x25, 0x21, 0x56, 0x87, 0x3b, 0xe6, 0x22, 0xe8, 0xd0, 0x19, 0xa8, 0xed, 0xcd, + }, encrypted) { + t.Error("unexpected CryptBlocks result for second block") + } + + var decrypter cipher.BlockMode + if c, ok := block.(*aesCipher); ok { + decrypter = c.NewCBCDecrypter(iv) + if decrypter == nil { + t.Error("unable to create new CBC decrypter") + } + } + plainText := append(srcBlock1, srcBlock2...) + decrypted := make([]byte, len(plainText)) + decrypter.CryptBlocks(decrypted, encrypted[:16]) + decrypter.CryptBlocks(decrypted[16:], encrypted[16:]) + if !bytes.Equal(decrypted, plainText) { + t.Errorf("unexpected decrypted result\ngot: %#v\nexp: %#v", decrypted, plainText) + } +} + +func TestDecryptSimple(t *testing.T) { + key := []byte{ + 0x24, 0xcd, 0x8b, 0x13, 0x37, 0xc5, 0xc1, 0xb1, + 0x0, 0xbb, 0x27, 0x40, 0x4f, 0xab, 0x5f, 0x7b, + 0x2d, 0x0, 0x20, 0xf5, 0x1, 0x84, 0x4, 0xbf, + 0xe3, 0xbd, 0xa1, 0xc4, 0xbf, 0x61, 0x2f, 0xc5, + } + block, err := NewAESCipher(key) + if err != nil { + panic(err) + } + iv := []byte{ + 0x91, 0xc7, 0xa7, 0x54, 0x52, 0xef, 0x10, 0xdb, + 0x91, 0xa8, 0x6c, 0xf9, 0x79, 0xd5, 0xac, 0x74, + } + + plainText := []byte{ + 0x54, 0x68, 0x65, 0x72, 0x65, 0x20, 0x69, 0x73, + 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x6f, 0x6e, + 0x65, 0x20, 0x4c, 0x6f, 0x72, 0x64, 0x20, 0x6f, + 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x52, 0x69, + 0x6e, 0x67, 0x2c, 0x20, 0x6f, 0x6e, 0x6c, 0x79, + 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x77, 0x68, 0x6f, + 0x20, 0x63, 0x61, 0x6e, 0x20, 0x62, 0x65, 0x6e, + 0x64, 0x20, 0x69, 0x74, 0x20, 0x74, 0x6f, 0x20, + 0x68, 0x69, 0x73, 0x20, 0x77, 0x69, 0x6c, 0x6c, + 0x2e, 0x20, 0x41, 0x6e, 0x64, 0x20, 0x68, 0x65, + 0x20, 0x64, 0x6f, 0x65, 0x73, 0x20, 0x6e, 0x6f, + 0x74, 0x20, 0x73, 0x68, 0x61, 0x72, 0x65, 0x20, + 0x70, 0x6f, 0x77, 0x65, 0x72, 0x2e, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + } + cipherText := make([]byte, len(plainText)) + var encrypter cipher.BlockMode + if c, ok := block.(*aesCipher); ok { + encrypter = c.NewCBCEncrypter(iv) + if encrypter == nil { + t.Error("unable to create new CBC encrypter") + } + } + encrypter.CryptBlocks(cipherText, plainText[:64]) + encrypter.CryptBlocks(cipherText[64:], plainText[64:]) + + expectedCipherText := []byte{ + 23, 51, 192, 210, 170, 124, 30, 218, + 176, 54, 70, 132, 141, 124, 3, 152, + 47, 3, 37, 81, 187, 101, 197, 94, + 11, 38, 128, 60, 112, 20, 235, 130, + 111, 236, 176, 99, 121, 6, 221, 181, + 190, 228, 150, 177, 218, 3, 196, 0, + 5, 141, 169, 151, 3, 161, 64, 244, + 231, 237, 252, 143, 111, 37, 68, 70, + 11, 137, 220, 243, 195, 90, 182, 83, + 96, 80, 122, 14, 93, 178, 62, 159, + 25, 162, 200, 155, 21, 150, 6, 101, + 21, 234, 12, 74, 190, 213, 159, 220, + 111, 184, 94, 169, 188, 93, 38, 150, + 3, 208, 185, 201, 212, 246, 238, 181, + } + if bytes.Compare(expectedCipherText, cipherText) != 0 { + t.Fail() + } + + var decrypter cipher.BlockMode + if c, ok := block.(*aesCipher); ok { + decrypter = c.NewCBCDecrypter(iv) + if decrypter == nil { + t.Error("unable to create new CBC decrypter") + } + } + decrypted := make([]byte, len(plainText)) + + decrypter.CryptBlocks(decrypted, cipherText[:64]) + decrypter.CryptBlocks(decrypted[64:], cipherText[64:]) + + if len(decrypted) != len(plainText) { + t.Fail() + } + + if bytes.Compare(plainText, decrypted) != 0 { + t.Errorf("decryption incorrect\nexp %v, got %v\n", plainText, decrypted) + } +} diff --git a/v2/openssl/bbig/big.go b/v2/openssl/bbig/big.go new file mode 100644 index 00000000..8ef6ec34 --- /dev/null +++ b/v2/openssl/bbig/big.go @@ -0,0 +1,38 @@ +// Copyright 2022 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 is a mirror of crypto/internal/boring/bbig/big.go. + +package bbig + +import ( + "math/big" + "unsafe" + + "github.com/golang-fips/openssl-fips/v2/openssl" +) + +func Enc(b *big.Int) openssl.BigInt { + if b == nil { + return nil + } + x := b.Bits() + if len(x) == 0 { + return openssl.BigInt{} + } + // TODO: Use unsafe.Slice((*uint)(&x[0]), len(x)) once go1.16 is no longer supported. + return (*(*[]uint)(unsafe.Pointer(&x)))[:len(x)] +} + +func Dec(b openssl.BigInt) *big.Int { + if b == nil { + return nil + } + if len(b) == 0 { + return new(big.Int) + } + // TODO: Use unsafe.Slice((*uint)(&b[0]), len(b)) once go1.16 is no longer supported. + x := (*(*[]big.Word)(unsafe.Pointer(&b)))[:len(b)] + return new(big.Int).SetBits(x) +} diff --git a/v2/openssl/doc.go b/v2/openssl/doc.go new file mode 100644 index 00000000..cdc7f6a4 --- /dev/null +++ b/v2/openssl/doc.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 openssl provides access to OpenSSL implementation functions. +package openssl + +// Enabled returns whether or not the boring package is enabled. When +// the boring package is enabled that means FIPS mode is enabled. +func Enabled() bool { + return enabled +} + +// A BigInt is the raw words from a BigInt. +// This definition allows us to avoid importing math/big. +// Conversion between BigInt and *big.Int is in crypto/internal/boring/bbig. +type BigInt []uint diff --git a/v2/openssl/ecdh.go b/v2/openssl/ecdh.go new file mode 100644 index 00000000..0b61e79b --- /dev/null +++ b/v2/openssl/ecdh.go @@ -0,0 +1,108 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +// #include "goopenssl.h" +import "C" +import "runtime" + +// ECDH keys are compatible with ECDSA +type PublicKeyECDH = PublicKeyECDSA +type PrivateKeyECDH = PrivateKeyECDSA + +var NewPublicKeyECDH = NewPublicKeyECDSA +var NewPrivateKeyECDH = NewPrivateKeyECDSA +var GenerateKeyECDH = GenerateKeyECDSA + +func (k *PrivateKeyECDH) withKey(f func(*C.GO_EC_KEY) 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 (k *PublicKeyECDH) withKey(f func(*C.GO_EC_KEY) 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 getPeerKey(priv *PrivateKeyECDH, pubBytes []byte) (*PublicKeyECDH, error) { + eckey := C._goboringcrypto_EC_KEY_new() + if priv.withKey(func(key *C.GO_EC_KEY) C.int { + group := C._goboringcrypto_EC_KEY_get0_group(key) + return C._goboringcrypto_EC_KEY_set_group(eckey, group) + }) != 1 { + return nil, NewOpenSSLError("EC_KEY_set_group") + } + if C._goboringcrypto_EC_KEY_oct2key(eckey, + base(pubBytes), C.size_t(len(pubBytes)), + nil) != 1 { + return nil, NewOpenSSLError("EC_KEY_oct2key") + } + k := &PublicKeyECDSA{eckey} + // 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, (*PublicKeyECDH).finalize) + return k, nil +} + +func SharedKeyECDH(priv *PrivateKeyECDH, peerPublicKey []byte) ([]byte, error) { + pkeyOurs := C._goboringcrypto_EVP_PKEY_new() + if pkeyOurs == nil { + return nil, NewOpenSSLError("EVP_PKEY_new failed") + } + defer C._goboringcrypto_EVP_PKEY_free(pkeyOurs) + if priv.withKey(func(key *C.GO_EC_KEY) C.int { + return C._goboringcrypto_EVP_PKEY_set1_EC_KEY(pkeyOurs, key) + }) != 1 { + return nil, NewOpenSSLError("EVP_PKEY_set1_EC_KEY") + } + + pub, err := getPeerKey(priv, peerPublicKey) + if err != nil { + return nil, err + } + + pkeyPeers := C._goboringcrypto_EVP_PKEY_new() + if pkeyPeers == nil { + return nil, NewOpenSSLError("EVP_PKEY_new failed") + } + defer C._goboringcrypto_EVP_PKEY_free(pkeyPeers) + if pub.withKey(func(key *C.GO_EC_KEY) C.int { + return C._goboringcrypto_EVP_PKEY_set1_EC_KEY(pkeyPeers, key) + }) != 1 { + return nil, NewOpenSSLError("EVP_PKEY_set1_EC_KEY") + } + + ctx := C._goboringcrypto_EVP_PKEY_CTX_new(pkeyOurs, nil) + if ctx == nil { + return nil, NewOpenSSLError("EVP_PKEY_CTX_new failed") + } + defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx) + if C._goboringcrypto_EVP_PKEY_derive_init(ctx) != 1 { + return nil, NewOpenSSLError("EVP_PKEY_derive_init failed") + } + if C._goboringcrypto_EVP_PKEY_derive_set_peer_ex(ctx, pkeyPeers, 1) != 1 { + return nil, NewOpenSSLError("EVP_PKEY_derive_set_peer_ex failed") + } + var outLen C.size_t + if C._goboringcrypto_EVP_PKEY_derive(ctx, nil, &outLen) != 1 { + return nil, NewOpenSSLError("EVP_PKEY_derive_init failed") + } + out := make([]byte, outLen) + if C._goboringcrypto_EVP_PKEY_derive(ctx, base(out), &outLen) != 1 { + return nil, NewOpenSSLError("EVP_PKEY_derive_init failed") + } + return out[:outLen], nil +} diff --git a/v2/openssl/ecdh_test.go b/v2/openssl/ecdh_test.go new file mode 100644 index 00000000..f0857484 --- /dev/null +++ b/v2/openssl/ecdh_test.go @@ -0,0 +1,74 @@ +package openssl_test + +import ( + "bytes" + "github.com/golang-fips/openssl-fips/v2/openssl" + "github.com/golang-fips/openssl-fips/v2/openssl/bbig" + "math/big" + "testing" +) + +func TestSharedKeyECDH(t *testing.T) { + if !openssl.Enabled() { + t.Skip("boringcrypto: skipping test, FIPS not enabled") + } + // Test vector from CAVS + x, ok := new(big.Int).SetString( + "ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230", + 16, + ) + if !ok { + panic("bad hex") + } + y, ok := new(big.Int).SetString( + "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141", + 16, + ) + if !ok { + panic("bad hex") + } + k, ok := new(big.Int).SetString( + "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534", + 16, + ) + if !ok { + panic("bad hex") + } + peerPublicKey := []byte{ + // uncompressed + 0x04, + // X + 0x70, 0x0c, 0x48, 0xf7, 0x7f, 0x56, 0x58, 0x4c, + 0x5c, 0xc6, 0x32, 0xca, 0x65, 0x64, 0x0d, 0xb9, + 0x1b, 0x6b, 0xac, 0xce, 0x3a, 0x4d, 0xf6, 0xb4, + 0x2c, 0xe7, 0xcc, 0x83, 0x88, 0x33, 0xd2, 0x87, + // Y + 0xdb, 0x71, 0xe5, 0x09, 0xe3, 0xfd, 0x9b, 0x06, + 0x0d, 0xdb, 0x20, 0xba, 0x5c, 0x51, 0xdc, 0xc5, + 0x94, 0x8d, 0x46, 0xfb, 0xf6, 0x40, 0xdf, 0xe0, + 0x44, 0x17, 0x82, 0xca, 0xb8, 0x5f, 0xa4, 0xac, + } + expected := []byte{ + 0x46, 0xfc, 0x62, 0x10, 0x64, 0x20, 0xff, 0x01, + 0x2e, 0x54, 0xa4, 0x34, 0xfb, 0xdd, 0x2d, 0x25, + 0xcc, 0xc5, 0x85, 0x20, 0x60, 0x56, 0x1e, 0x68, + 0x04, 0x0d, 0xd7, 0x77, 0x89, 0x97, 0xbd, 0x7b, + } + + bx, by, bk := bbig.Enc(x), bbig.Enc(y), bbig.Enc(k) + + priv, err := openssl.NewPrivateKeyECDH("P-256", bx, by, bk) + if err != nil { + t.Log("NewPrivateKeyECDH failed", err) + t.Fail() + } + derived, err := openssl.SharedKeyECDH(priv, peerPublicKey) + if err != nil { + t.Log("SharedKeyECDH failed", err) + t.Fail() + } + if !bytes.Equal(derived, expected) { + t.Log("derived shared secret doesn't match") + t.Fail() + } +} diff --git a/v2/openssl/ecdsa.go b/v2/openssl/ecdsa.go new file mode 100644 index 00000000..eb635079 --- /dev/null +++ b/v2/openssl/ecdsa.go @@ -0,0 +1,179 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +// #include "goopenssl.h" +import "C" +import ( + "errors" + "runtime" + "unsafe" +) + +type ecdsaSignature struct { + R, S BigInt +} + +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") +var errUnsupportedCurve = errors.New("boringcrypto: unsupported elliptic curve") + +func curveNID(curve string) (C.int, error) { + switch curve { + case "P-224": + if ExecutingTest() { + return C.GO_NID_secp224r1, nil + } + return 0, errUnsupportedCurve + 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 BigInt) (*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 BigInt) (*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, NewOpenSSLError("EC_KEY_new_by_curve_name failed") + } + 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, NewOpenSSLError("EC_POINT_new failed") + } + 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, NewOpenSSLError("EC_POINT_free failed") + } + return key, nil +} + +func NewPrivateKeyECDSA(curve string, X, Y BigInt, D BigInt) (*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, NewOpenSSLError("EC_KEY_set_private_key failed") + } + 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 SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) { + size := C._goboringcrypto_ECDSA_size(priv.key) + sig := make([]byte, size) + var sigLen C.uint + ok := C._goboringcrypto_internal_ECDSA_sign(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), &sigLen, priv.key) > 0 + if !ok { + return nil, NewOpenSSLError(("ECDSA_sign failed")) + } + + runtime.KeepAlive(priv) + return sig[:sigLen], nil +} +func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool { + ok := C._goboringcrypto_internal_ECDSA_verify(0, base(hash), C.size_t(len(hash)), (*C.uint8_t)(unsafe.Pointer(&sig[0])), C.uint(len(sig)), pub.key) > 0 + runtime.KeepAlive(pub) + return ok +} + +func GenerateKeyECDSA(curve string) (X, Y, D BigInt, 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, NewOpenSSLError("EC_KEY_new_by_curve_name failed") + } + defer C._goboringcrypto_EC_KEY_free(key) + if C._goboringcrypto_EC_KEY_generate_key(key) == 0 { + return nil, nil, nil, NewOpenSSLError("EC_KEY_generate_key failed") + } + 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, NewOpenSSLError("EC_KEY_get0_private_key failed") + } + bx := C._goboringcrypto_BN_new() + if bx == nil { + return nil, nil, nil, NewOpenSSLError("BN_new failed") + } + defer C._goboringcrypto_BN_free(bx) + by := C._goboringcrypto_BN_new() + if by == nil { + return nil, nil, nil, NewOpenSSLError("BN_new failed") + } + 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, NewOpenSSLError("EC_POINT_get_affine_coordinates_GFp failed") + } + return bnToBig(bx), bnToBig(by), bnToBig(bd), nil +} diff --git a/v2/openssl/goopenssl.h b/v2/openssl/goopenssl.h new file mode 100644 index 00000000..fae69930 --- /dev/null +++ b/v2/openssl/goopenssl.h @@ -0,0 +1,849 @@ +// 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 +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +// This header file describes the OpenSSL ABI as built for use in Go. + +#include <stdlib.h> // size_t +#include <stdint.h> // uint8_t + +#include <openssl/ossl_typ.h> + +#if OPENSSL_VERSION_NUMBER < 0x30000000 +#define OPENSSL_DLSYM_CALL(handle, func) dlsym(handle, func) +#else +#define __USE_GNU +#define OPENSSL_DLSYM_CALL(handle, func) dlvsym(handle, func, "OPENSSL_3.0.0") +#endif + +#include <dlfcn.h> + +#define unlikely(x) __builtin_expect(!!(x), 0) +#define DEFINEFUNC(ret, func, args, argscall) \ + typedef ret(*_goboringcrypto_PTR_##func) args; \ + static _goboringcrypto_PTR_##func _g_##func = 0; \ + static inline ret _goboringcrypto_##func args \ + { \ + if (unlikely(!_g_##func)) \ + { \ + _g_##func = OPENSSL_DLSYM_CALL(handle, #func); \ + } \ + return _g_##func argscall; \ + } + +#define DEFINEFUNCINTERNAL(ret, func, args, argscall) \ + typedef ret(*_goboringcrypto_internal_PTR_##func) args; \ + static _goboringcrypto_internal_PTR_##func _g_internal_##func = 0; \ + static inline ret _goboringcrypto_internal_##func args \ + { \ + if (unlikely(!_g_internal_##func)) \ + { \ + _g_internal_##func = OPENSSL_DLSYM_CALL(handle, #func); \ + } \ + return _g_internal_##func argscall; \ + } + +#define DEFINEMACRO(ret, func, args, argscall) \ + static inline ret _goboringcrypto_##func args \ + { \ + return func argscall; \ + } + + +static void* handle; +static void* +_goboringcrypto_DLOPEN_OPENSSL(void) +{ + if (handle) + { + return handle; + } +#if OPENSSL_VERSION_NUMBER < 0x10100000L + handle = dlopen("libcrypto.so.10", RTLD_NOW | RTLD_GLOBAL); +#elif OPENSSL_VERSION_NUMBER < 0x30000000L + handle = dlopen("libcrypto.so.1.1", RTLD_NOW | RTLD_GLOBAL); +#else + handle = dlopen("libcrypto.so.3", RTLD_NOW | RTLD_GLOBAL); +#endif + return handle; +} + +#include <openssl/opensslv.h> +#include <openssl/ssl.h> + +DEFINEFUNCINTERNAL(void, OPENSSL_init, (void), ()) + +static unsigned long _goboringcrypto_internal_OPENSSL_VERSION_NUMBER(void) { + return OPENSSL_VERSION_NUMBER; +} + +static void +_goboringcrypto_OPENSSL_setup(void) { + _goboringcrypto_internal_OPENSSL_init(); +} + +#include <openssl/err.h> +DEFINEFUNCINTERNAL(void, ERR_print_errors_fp, (FILE* fp), (fp)) +#if OPENSSL_VERSION_NUMBER < 0x30000000 +DEFINEFUNCINTERNAL(unsigned long, ERR_get_error_line_data, + (const char **file, int *line, const char **data, int *flags), + (file, line, data, flags)) +static inline unsigned long +_goboringcrypto_internal_ERR_get_error_all(const char **file, int *line, const char **func, const char **data, int *flags) +{ + unsigned long e = _goboringcrypto_internal_ERR_get_error_line_data(file, line, data, flags); + if (e == 0 && func != NULL) { + *func = "unknown"; + } + return e; +} +#else +DEFINEFUNCINTERNAL(unsigned long, ERR_get_error_all, + (const char **file, int *line, const char **func, const char **data, int *flags), + (file, line, func, data, flags)) +#endif +DEFINEFUNCINTERNAL(void, ERR_error_string_n, (unsigned long e, unsigned char *buf, size_t len), (e, buf, len)) + +#include <openssl/crypto.h> + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DEFINEFUNC(int, CRYPTO_num_locks, (void), ()) +#else +static inline int +_goboringcrypto_CRYPTO_num_locks(void) { + return CRYPTO_num_locks(); /* defined as macro */ +} +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DEFINEFUNC(void, CRYPTO_set_id_callback, (unsigned long (*id_function)(void)), (id_function)) +#else +static inline void +_goboringcrypto_CRYPTO_set_id_callback(unsigned long (*id_function)(void)) { + CRYPTO_set_id_callback(id_function); /* defined as macro */ +} +#endif +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DEFINEFUNC(void, CRYPTO_set_locking_callback, + (void (*locking_function)(int mode, int n, const char *file, int line)), + (locking_function)) +#else +static inline void +_goboringcrypto_CRYPTO_set_locking_callback(void (*locking_function)(int mode, int n, const char *file, int line)) { + CRYPTO_set_locking_callback(locking_function); /* defined as macro */ +} +#endif + +int _goboringcrypto_OPENSSL_thread_setup(void); + +#if OPENSSL_VERSION_NUMBER < 0x30000000L +DEFINEFUNC(int, FIPS_mode, (void), ()) +DEFINEFUNC(int, FIPS_mode_set, (int r), (r)) +#else +DEFINEFUNC(int, EVP_default_properties_is_fips_enabled, (OSSL_LIB_CTX *libctx), (libctx)) +static inline int _goboringcrypto_FIPS_mode(void) { + return _goboringcrypto_EVP_default_properties_is_fips_enabled(NULL); +} +#endif + +#include <openssl/rand.h> + +DEFINEFUNC(int, RAND_set_rand_method, (const RAND_METHOD *rand), (rand)) +DEFINEFUNC(const RAND_METHOD*, RAND_get_rand_method, (void), ()) +DEFINEFUNC(int, RAND_bytes, (uint8_t * arg0, size_t arg1), (arg0, arg1)) + +int _goboringcrypto_stub_openssl_rand(void); +int _goboringcrypto_restore_openssl_rand(void); +int fbytes(unsigned char *buf, int num); + + +#include <openssl/obj_mac.h> + +enum +{ + GO_NID_md5_sha1 = NID_md5_sha1, + + GO_NID_secp224r1 = NID_secp224r1, + GO_NID_X9_62_prime256v1 = NID_X9_62_prime256v1, + GO_NID_secp384r1 = NID_secp384r1, + GO_NID_secp521r1 = NID_secp521r1, + + GO_NID_sha224 = NID_sha224, + GO_NID_sha256 = NID_sha256, + GO_NID_sha384 = NID_sha384, + GO_NID_sha512 = NID_sha512, +}; + +#include <openssl/sha.h> + +typedef SHA_CTX GO_SHA_CTX; + +DEFINEFUNC(int, SHA1_Init, (GO_SHA_CTX * arg0), (arg0)) +DEFINEFUNC(int, SHA1_Update, (GO_SHA_CTX * arg0, const void *arg1, size_t arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, SHA1_Final, (uint8_t * arg0, GO_SHA_CTX *arg1), (arg0, arg1)) + +typedef SHA256_CTX GO_SHA256_CTX; + +DEFINEFUNC(int, SHA224_Init, (GO_SHA256_CTX * arg0), (arg0)) +DEFINEFUNC(int, SHA224_Update, (GO_SHA256_CTX * arg0, const void *arg1, size_t arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, SHA224_Final, (uint8_t * arg0, GO_SHA256_CTX *arg1), (arg0, arg1)) + +DEFINEFUNC(int, SHA256_Init, (GO_SHA256_CTX * arg0), (arg0)) +DEFINEFUNC(int, SHA256_Update, (GO_SHA256_CTX * arg0, const void *arg1, size_t arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, SHA256_Final, (uint8_t * arg0, GO_SHA256_CTX *arg1), (arg0, arg1)) + +typedef SHA512_CTX GO_SHA512_CTX; +DEFINEFUNC(int, SHA384_Init, (GO_SHA512_CTX * arg0), (arg0)) +DEFINEFUNC(int, SHA384_Update, (GO_SHA512_CTX * arg0, const void *arg1, size_t arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, SHA384_Final, (uint8_t * arg0, GO_SHA512_CTX *arg1), (arg0, arg1)) + +DEFINEFUNC(int, SHA512_Init, (GO_SHA512_CTX * arg0), (arg0)) +DEFINEFUNC(int, SHA512_Update, (GO_SHA512_CTX * arg0, const void *arg1, size_t arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, SHA512_Final, (uint8_t * arg0, GO_SHA512_CTX *arg1), (arg0, arg1)) + +#include <openssl/evp.h> + +typedef EVP_MD GO_EVP_MD; +DEFINEFUNC(const GO_EVP_MD *, EVP_md4, (void), ()) +DEFINEFUNC(const GO_EVP_MD *, EVP_md5, (void), ()) +DEFINEFUNC(const GO_EVP_MD *, EVP_sha1, (void), ()) +DEFINEFUNC(const GO_EVP_MD *, EVP_sha224, (void), ()) +DEFINEFUNC(const GO_EVP_MD *, EVP_sha256, (void), ()) +DEFINEFUNC(const GO_EVP_MD *, EVP_sha384, (void), ()) +DEFINEFUNC(const GO_EVP_MD *, EVP_sha512, (void), ()) +DEFINEFUNC(const GO_EVP_MD *, EVP_md_null, (void), ()) +#if OPENSSL_VERSION_NUMBER < 0x30000000L +DEFINEFUNCINTERNAL(int, EVP_MD_type, (const GO_EVP_MD *arg0), (arg0)) +#else +DEFINEFUNCINTERNAL(int, EVP_MD_get_type, (const GO_EVP_MD *arg0), (arg0)) +#endif +DEFINEFUNCINTERNAL(size_t, EVP_MD_size, (const GO_EVP_MD *arg0), (arg0)) +DEFINEFUNCINTERNAL(const GO_EVP_MD*, EVP_md5_sha1, (void), ()) + +# include <openssl/md5.h> +DEFINEFUNCINTERNAL(int, MD5_Init, (MD5_CTX *c), (c)) +DEFINEFUNCINTERNAL(int, MD5_Update, (MD5_CTX *c, const void *data, size_t len), (c, data, len)) +DEFINEFUNCINTERNAL(int, MD5_Final, (unsigned char *md, MD5_CTX *c), (md, c)) + +static inline int +_goboringcrypto_EVP_MD_type(const GO_EVP_MD *md) { +#if OPENSSL_VERSION_NUMBER < 0x30000000L + return _goboringcrypto_internal_EVP_MD_type(md); +#else + return _goboringcrypto_internal_EVP_MD_get_type(md); +#endif +} + +const GO_EVP_MD* _goboringcrypto_backport_EVP_md5_sha1(void); +static inline const GO_EVP_MD* +_goboringcrypto_EVP_md5_sha1(void) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + return _goboringcrypto_backport_EVP_md5_sha1(); +#else + return _goboringcrypto_internal_EVP_md5_sha1(); +#endif +} + +#include <openssl/hmac.h> + +typedef HMAC_CTX GO_HMAC_CTX; + +DEFINEFUNC(int, HMAC_Init_ex, + (GO_HMAC_CTX * arg0, const void *arg1, int arg2, const GO_EVP_MD *arg3, ENGINE *arg4), + (arg0, arg1, arg2, arg3, arg4)) +DEFINEFUNC(int, HMAC_Update, (GO_HMAC_CTX * arg0, const uint8_t *arg1, size_t arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, HMAC_Final, (GO_HMAC_CTX * arg0, uint8_t *arg1, unsigned int *arg2), (arg0, arg1, arg2)) +DEFINEFUNC(size_t, HMAC_CTX_copy, (GO_HMAC_CTX *dest, GO_HMAC_CTX *src), (dest, src)) + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DEFINEFUNCINTERNAL(void, HMAC_CTX_cleanup, (GO_HMAC_CTX * arg0), (arg0)) +static inline void +_goboringcrypto_HMAC_CTX_free(HMAC_CTX *ctx) { + if (ctx != NULL) { + _goboringcrypto_HMAC_CTX_cleanup(ctx); + free(ctx); + } +} +#else +DEFINEFUNC(void, HMAC_CTX_free, (GO_HMAC_CTX * arg0), (arg0)) +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static inline size_t +_goboringcrypto_HMAC_size(const GO_HMAC_CTX* arg0) { + return _goboringcrypto_internal_EVP_MD_size(arg0->md); +} +#else +DEFINEFUNCINTERNAL(const EVP_MD*, HMAC_CTX_get_md, (const GO_HMAC_CTX* ctx), (ctx)) +# if OPENSSL_VERSION_NUMBER < 0x30000000L +static inline size_t +_goboringcrypto_HMAC_size(const GO_HMAC_CTX* arg0) { + const EVP_MD* md; + md = _goboringcrypto_internal_HMAC_CTX_get_md(arg0); + return _goboringcrypto_internal_EVP_MD_size(md); +} +# else +DEFINEFUNCINTERNAL(size_t, EVP_MD_get_size, (const GO_EVP_MD *arg0), (arg0)) +static inline size_t +_goboringcrypto_HMAC_size(const GO_HMAC_CTX* arg0) { + const EVP_MD* md; + md = _goboringcrypto_internal_HMAC_CTX_get_md(arg0); + return _goboringcrypto_internal_EVP_MD_get_size(md); +} +# endif +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DEFINEFUNCINTERNAL(void, HMAC_CTX_init, (GO_HMAC_CTX * arg0), (arg0)) +static inline GO_HMAC_CTX* +_goboringcrypto_HMAC_CTX_new(void) { + GO_HMAC_CTX* ctx = malloc(sizeof(GO_HMAC_CTX)); + if (ctx != NULL) + _goboringcrypto_internal_HMAC_CTX_init(ctx); + return ctx; +} +#else +DEFINEFUNC(GO_HMAC_CTX*, HMAC_CTX_new, (void), ()) +#endif + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +static inline int +_goboringcrypto_HMAC_CTX_reset(GO_HMAC_CTX* ctx) { + _goboringcrypto_HMAC_CTX_cleanup(ctx); + _goboringcrypto_HMAC_CTX_init(ctx); + return 0; +} +#else +DEFINEFUNC(int, HMAC_CTX_reset, (GO_HMAC_CTX * arg0), (arg0)) +#endif + +int _goboringcrypto_HMAC_CTX_copy_ex(GO_HMAC_CTX *dest, const GO_HMAC_CTX *src); + +#include <openssl/evp.h> +#include <openssl/aes.h> + +DEFINEFUNC(EVP_CIPHER_CTX *, EVP_CIPHER_CTX_new, (void), ()) +DEFINEFUNC(int, EVP_CIPHER_CTX_set_padding, (EVP_CIPHER_CTX *x, int padding), (x, padding)) +DEFINEFUNC(int, EVP_CipherInit_ex, + (EVP_CIPHER_CTX * ctx, const EVP_CIPHER *type, ENGINE *impl, const unsigned char *key, const unsigned char *iv, int enc), + (ctx, type, impl, key, iv, enc)) +DEFINEFUNC(int, EVP_CipherUpdate, + (EVP_CIPHER_CTX * ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), + (ctx, out, outl, in, inl)) + +void _goboringcrypto_EVP_AES_ctr128_enc(EVP_CIPHER_CTX *ctx, const uint8_t *in, uint8_t *out, size_t len); + +int _goboringcrypto_EVP_AES_encrypt(EVP_CIPHER_CTX *ctx, const uint8_t *in, size_t in_len, uint8_t *out); + +enum +{ + GO_AES_ENCRYPT = 1, + GO_AES_DECRYPT = 0 +}; +void _goboringcrypto_EVP_AES_cbc_encrypt(EVP_CIPHER_CTX *ctx, const uint8_t *arg0, uint8_t *arg1, size_t arg2, const uint8_t *a, const int arg5); +DEFINEFUNC(void, AES_cbc_encrypt, + (const unsigned char *in, unsigned char *out, + size_t length, const AES_KEY *key, + unsigned char *ivec, const int enc), + (in, out, length, key, ivec, enc)) + +void EVP_AES_cbc_enc(EVP_CIPHER_CTX *ctx, const uint8_t *in, uint8_t *out, size_t len); + +void EVP_AES_cbc_dec(EVP_CIPHER_CTX *ctx, const uint8_t *in, uint8_t *out, size_t len); + +typedef ENGINE GO_ENGINE; + +#include <openssl/bn.h> + +typedef BN_CTX GO_BN_CTX; +typedef BIGNUM GO_BIGNUM; + +DEFINEFUNC(GO_BIGNUM *, BN_new, (void), ()) +DEFINEFUNC(void, BN_free, (GO_BIGNUM * arg0), (arg0)) +DEFINEFUNC(void, BN_clear_free, (GO_BIGNUM * arg0), (arg0)) +DEFINEFUNC(int, BN_set_word, (BIGNUM *a, BN_ULONG w), (a, w)) +DEFINEFUNC(unsigned int, BN_num_bits, (const GO_BIGNUM *arg0), (arg0)) +DEFINEFUNC(int, BN_is_negative, (const GO_BIGNUM *arg0), (arg0)) +DEFINEFUNC(GO_BIGNUM *, BN_bin2bn, (const uint8_t *arg0, size_t arg1, GO_BIGNUM *arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, BN_bn2le_padded, (uint8_t *out, size_t len, const BIGNUM *in), (out, len, in)) +DEFINEFUNC(GO_BIGNUM *, BN_le2bn, (const uint8_t *in, size_t len, BIGNUM *ret), (in, len, ret)) +DEFINEFUNC(size_t, BN_bn2bin, (const GO_BIGNUM *arg0, uint8_t *arg1), (arg0, arg1)) + +static inline unsigned int +_goboringcrypto_BN_num_bytes(const GO_BIGNUM* a) { + return ((_goboringcrypto_BN_num_bits(a)+7)/8); +} + +#include <openssl/ec.h> + +typedef EC_GROUP GO_EC_GROUP; + +DEFINEFUNC(GO_EC_GROUP *, EC_GROUP_new_by_curve_name, (int arg0), (arg0)) +DEFINEFUNC(void, EC_GROUP_free, (GO_EC_GROUP * arg0), (arg0)) + +typedef EC_POINT GO_EC_POINT; + +DEFINEFUNC(GO_EC_POINT *, EC_POINT_new, (const GO_EC_GROUP *arg0), (arg0)) +DEFINEFUNC(void, EC_POINT_free, (GO_EC_POINT * arg0), (arg0)) +DEFINEFUNC(int, EC_POINT_get_affine_coordinates_GFp, + (const GO_EC_GROUP *arg0, const GO_EC_POINT *arg1, GO_BIGNUM *arg2, GO_BIGNUM *arg3, GO_BN_CTX *arg4), + (arg0, arg1, arg2, arg3, arg4)) +DEFINEFUNC(int, EC_POINT_set_affine_coordinates_GFp, + (const GO_EC_GROUP *arg0, GO_EC_POINT *arg1, const GO_BIGNUM *arg2, const GO_BIGNUM *arg3, GO_BN_CTX *arg4), + (arg0, arg1, arg2, arg3, arg4)) + +typedef EC_KEY GO_EC_KEY; + +DEFINEFUNC(GO_EC_KEY *, EC_KEY_new, (void), ()) +DEFINEFUNC(GO_EC_KEY *, EC_KEY_new_by_curve_name, (int arg0), (arg0)) +DEFINEFUNC(int, EC_KEY_oct2key, (GO_EC_KEY *arg0, const unsigned char *arg1, size_t arg2, BN_CTX *arg3), (arg0, arg1, arg2, arg3)) +DEFINEFUNC(void, EC_KEY_free, (GO_EC_KEY * arg0), (arg0)) +DEFINEFUNC(const GO_EC_GROUP *, EC_KEY_get0_group, (const GO_EC_KEY *arg0), (arg0)) +DEFINEFUNC(int, EC_KEY_set_group, (GO_EC_KEY *arg0, const EC_GROUP *arg1), (arg0, arg1)) +DEFINEFUNC(int, EC_KEY_generate_key, (GO_EC_KEY * arg0), (arg0)) +DEFINEFUNC(int, EC_KEY_set_private_key, (GO_EC_KEY * arg0, const GO_BIGNUM *arg1), (arg0, arg1)) +DEFINEFUNC(int, EC_KEY_set_public_key, (GO_EC_KEY * arg0, const GO_EC_POINT *arg1), (arg0, arg1)) +DEFINEFUNC(const GO_BIGNUM *, EC_KEY_get0_private_key, (const GO_EC_KEY *arg0), (arg0)) +DEFINEFUNC(const GO_EC_POINT *, EC_KEY_get0_public_key, (const GO_EC_KEY *arg0), (arg0)) + +// TODO: EC_KEY_check_fips? + +#include <openssl/ecdsa.h> + +typedef ECDSA_SIG GO_ECDSA_SIG; + +DEFINEFUNC(GO_ECDSA_SIG *, ECDSA_SIG_new, (void), ()) +DEFINEFUNC(void, ECDSA_SIG_free, (GO_ECDSA_SIG * arg0), (arg0)) +DEFINEFUNC(GO_ECDSA_SIG *, ECDSA_do_sign, (const uint8_t *arg0, size_t arg1, const GO_EC_KEY *arg2), (arg0, arg1, arg2)) +DEFINEFUNC(int, ECDSA_do_verify, (const uint8_t *arg0, size_t arg1, const GO_ECDSA_SIG *arg2, const GO_EC_KEY *arg3), (arg0, arg1, arg2, arg3)) +DEFINEFUNC(size_t, ECDSA_size, (const GO_EC_KEY *arg0), (arg0)) + +DEFINEFUNCINTERNAL(int, ECDSA_sign, + (int type, const unsigned char *dgst, size_t dgstlen, unsigned char *sig, unsigned int *siglen, EC_KEY *eckey), + (type, dgst, dgstlen, sig, siglen, eckey)) + +DEFINEFUNCINTERNAL(int, ECDSA_verify, + (int type, const unsigned char *dgst, size_t dgstlen, const unsigned char *sig, unsigned int siglen, EC_KEY *eckey), + (type, dgst, dgstlen, sig, siglen, eckey)) + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DEFINEFUNC(EVP_MD_CTX*, EVP_MD_CTX_create, (void), ()) +#else +DEFINEFUNCINTERNAL(EVP_MD_CTX*, EVP_MD_CTX_new, (void), ()) +static inline EVP_MD_CTX* _goboringcrypto_EVP_MD_CTX_create(void) { + return _goboringcrypto_internal_EVP_MD_CTX_new(); +} +#endif + +DEFINEFUNCINTERNAL(int, EVP_PKEY_assign, + (EVP_PKEY *pkey, int type, void *eckey), + (pkey, type, eckey)) + +static inline int +_goboringcrypto_EVP_PKEY_assign_EC_KEY(EVP_PKEY *pkey, GO_EC_KEY *eckey) { + return _goboringcrypto_internal_EVP_PKEY_assign(pkey, EVP_PKEY_EC, (char *)(eckey)); +} + +static inline int +_goboringcrypto_EVP_PKEY_assign_RSA(EVP_PKEY *pkey, RSA *rsa) { + return _goboringcrypto_internal_EVP_PKEY_assign(pkey, EVP_PKEY_RSA, (char *)(rsa)); +} + +DEFINEFUNC(int, EVP_DigestSignInit, + (EVP_MD_CTX* ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, const EVP_PKEY *pkey), + (ctx, pctx, type, e, pkey)) + +DEFINEFUNC(int, EVP_DigestUpdate, + (EVP_MD_CTX* ctx, const void *d, size_t cnt), + (ctx, d, cnt)) +DEFINEFUNC(int, EVP_DigestSignFinal, + (EVP_MD_CTX* ctx, unsigned char *sig, unsigned int *siglen), + (ctx, sig, siglen)) + +DEFINEFUNC(int, EVP_DigestVerifyInit, + (EVP_MD_CTX* ctx, EVP_PKEY_CTX **pctx, const EVP_MD *type, ENGINE *e, const EVP_PKEY *pkey), + (ctx, pctx, type, e, pkey)) +DEFINEFUNC(int, EVP_DigestVerifyFinal, + (EVP_MD_CTX* ctx, const uint8_t *sig, unsigned int siglen), + (ctx, sig, siglen)) + +typedef RSA GO_RSA; +int _goboringcrypto_EVP_sign(EVP_MD* md, EVP_PKEY_CTX *ctx, const uint8_t *msg, size_t msgLen, uint8_t *sig, unsigned int *slen, EVP_PKEY *eckey); +int _goboringcrypto_EVP_sign_raw(EVP_MD *md, EVP_PKEY_CTX *ctx, const uint8_t *msg, + size_t msgLen, uint8_t *sig, size_t *slen, + GO_RSA *key); + +int _goboringcrypto_EVP_verify(EVP_MD* md, EVP_PKEY_CTX *ctx, const uint8_t *msg, size_t msgLen, const uint8_t *sig, unsigned int slen, EVP_PKEY *key); +int _goboringcrypto_EVP_verify_raw(const uint8_t *msg, size_t msgLen, + const uint8_t *sig, unsigned int slen, + GO_RSA *key); + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +DEFINEFUNC(void, EVP_MD_CTX_destroy, (EVP_MD_CTX *ctx), (ctx)) +#else +DEFINEFUNCINTERNAL(void, EVP_MD_CTX_free, (EVP_MD_CTX *ctx), (ctx)) +static inline void _goboringcrypto_EVP_MD_CTX_free(EVP_MD_CTX *ctx) { + return _goboringcrypto_internal_EVP_MD_CTX_free(ctx); +} +#endif + +int _goboringcrypto_ECDSA_sign(EVP_MD *md, const uint8_t *arg1, size_t arg2, uint8_t *arg3, unsigned int *arg4, GO_EC_KEY *arg5); +int _goboringcrypto_ECDSA_verify(EVP_MD *md, const uint8_t *arg1, size_t arg2, const uint8_t *arg3, unsigned int arg4, GO_EC_KEY *arg5); + +#include <openssl/rsa.h> + +// Note: order of struct fields here is unchecked. +typedef BN_GENCB GO_BN_GENCB; + +int _goboringcrypto_EVP_RSA_sign(EVP_MD* md, const uint8_t *msg, unsigned int msgLen, uint8_t *sig, unsigned int *slen, RSA *rsa); +int _goboringcrypto_EVP_RSA_verify(EVP_MD* md, const uint8_t *msg, unsigned int msgLen, const uint8_t *sig, unsigned int slen, GO_RSA *rsa); + +DEFINEFUNC(GO_RSA *, RSA_new, (void), ()) +DEFINEFUNC(void, RSA_free, (GO_RSA * arg0), (arg0)) +DEFINEFUNC(int, RSA_private_encrypt, + (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding), + (flen, from, to, rsa, padding)) +DEFINEFUNC(int, RSA_public_decrypt, + (int flen, const unsigned char *from, unsigned char *to, RSA *rsa, int padding), + (flen, from, to, rsa, padding)) +DEFINEFUNC(int, RSA_sign, + (int arg0, const uint8_t *arg1, unsigned int arg2, uint8_t *arg3, unsigned int *arg4, GO_RSA *arg5), + (arg0, arg1, arg2, arg3, arg4, arg5)) +DEFINEFUNC(int, RSA_verify, + (int arg0, const uint8_t *arg1, unsigned int arg2, const uint8_t *arg3, unsigned int arg4, GO_RSA *arg5), + (arg0, arg1, arg2, arg3, arg4, arg5)) +DEFINEFUNC(int, RSA_generate_key_ex, + (GO_RSA * arg0, int arg1, GO_BIGNUM *arg2, GO_BN_GENCB *arg3), + (arg0, arg1, arg2, arg3)) + +DEFINEFUNCINTERNAL(int, RSA_set0_factors, + (GO_RSA * rsa, GO_BIGNUM *p, GO_BIGNUM *q), + (rsa, p, q)) + +static inline int +_goboringcrypto_RSA_set0_factors(GO_RSA * r, GO_BIGNUM *p, GO_BIGNUM *q) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* If the fields p and q in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->p == NULL && p == NULL) + || (r->q == NULL && q == NULL)) + return 0; + + if (p != NULL) { + _goboringcrypto_BN_clear_free(r->p); + r->p = p; + } + if (q != NULL) { + _goboringcrypto_BN_clear_free(r->q); + r->q = q; + } + + return 1; +#else + return _goboringcrypto_internal_RSA_set0_factors(r, p, q); +#endif +} + +DEFINEFUNCINTERNAL(int, RSA_set0_crt_params, + (GO_RSA * rsa, GO_BIGNUM *dmp1, GO_BIGNUM *dmp2, GO_BIGNUM *iqmp), + (rsa, dmp1, dmp2, iqmp)) + +static inline int +_goboringcrypto_RSA_set0_crt_params(GO_RSA * r, GO_BIGNUM *dmp1, GO_BIGNUM *dmq1, GO_BIGNUM *iqmp) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* If the fields dmp1, dmq1 and iqmp in r are NULL, the corresponding input + * parameters MUST be non-NULL. + */ + if ((r->dmp1 == NULL && dmp1 == NULL) + || (r->dmq1 == NULL && dmq1 == NULL) + || (r->iqmp == NULL && iqmp == NULL)) + return 0; + + if (dmp1 != NULL) { + _goboringcrypto_BN_clear_free(r->dmp1); + r->dmp1 = dmp1; + } + if (dmq1 != NULL) { + _goboringcrypto_BN_clear_free(r->dmq1); + r->dmq1 = dmq1; + } + if (iqmp != NULL) { + _goboringcrypto_BN_clear_free(r->iqmp); + r->iqmp = iqmp; + } + + return 1; +#else + return _goboringcrypto_internal_RSA_set0_crt_params(r, dmp1, dmq1, iqmp); +#endif +} + +DEFINEFUNCINTERNAL(void, RSA_get0_crt_params, + (const GO_RSA *r, const GO_BIGNUM **dmp1, const GO_BIGNUM **dmq1, const GO_BIGNUM **iqmp), + (r, dmp1, dmq1, iqmp)) +static inline void +_goboringcrypto_RSA_get0_crt_params(const GO_RSA *r, const GO_BIGNUM **dmp1, const GO_BIGNUM **dmq1, const GO_BIGNUM **iqmp) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (dmp1 != NULL) + *dmp1 = r->dmp1; + if (dmq1 != NULL) + *dmq1 = r->dmq1; + if (iqmp != NULL) + *iqmp = r->iqmp; +#else + _goboringcrypto_internal_RSA_get0_crt_params(r, dmp1, dmq1, iqmp); +#endif +} + + +DEFINEFUNCINTERNAL(int, RSA_set0_key, + (GO_RSA * r, GO_BIGNUM *n, GO_BIGNUM *e, GO_BIGNUM *d), + (r, n, e, d)) +static inline int +_goboringcrypto_RSA_set0_key(GO_RSA * r, GO_BIGNUM *n, GO_BIGNUM *e, GO_BIGNUM *d) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + /* If the fields n and e in r are NULL, the corresponding input + * parameters MUST be non-NULL for n and e. d may be + * left NULL (in case only the public key is used). + */ + if ((r->n == NULL && n == NULL) + || (r->e == NULL && e == NULL)) + return 0; + + if (n != NULL) { + _goboringcrypto_BN_free(r->n); + r->n = n; + } + if (e != NULL) { + _goboringcrypto_BN_free(r->e); + r->e = e; + } + if (d != NULL) { + _goboringcrypto_BN_clear_free(r->d); + r->d = d; + } + + return 1; +#else + return _goboringcrypto_internal_RSA_set0_key(r, n, e, d); +#endif +} + +DEFINEFUNCINTERNAL(void, RSA_get0_factors, + (const GO_RSA *rsa, const GO_BIGNUM **p, const GO_BIGNUM **q), + (rsa, p, q)) +static inline void +_goboringcrypto_RSA_get0_factors(const GO_RSA *rsa, const GO_BIGNUM **p, const GO_BIGNUM **q) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (p) + *p = rsa->p; + if (q) + *q = rsa->q; +#else + _goboringcrypto_internal_RSA_get0_factors(rsa, p, q); +#endif +} + +DEFINEFUNCINTERNAL(void, RSA_get0_key, + (const GO_RSA *rsa, const GO_BIGNUM **n, const GO_BIGNUM **e, const GO_BIGNUM **d), + (rsa, n, e, d)) +static inline void +_goboringcrypto_RSA_get0_key(const GO_RSA *rsa, const GO_BIGNUM **n, const GO_BIGNUM **e, const GO_BIGNUM **d) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + if (n) + *n = rsa->n; + if (e) + *e = rsa->e; + if (d) + *d = rsa->d; +#else + _goboringcrypto_internal_RSA_get0_key(rsa, n, e, d); +#endif +} + +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_sign_pss_mgf1(GO_RSA *, unsigned int *out_len, uint8_t *out, unsigned int max_out, const uint8_t *in, unsigned int in_len, GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len); + +int _goboringcrypto_RSA_verify_pss_mgf1(GO_RSA *, const uint8_t *msg, unsigned int msg_len, GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len, const uint8_t *sig, unsigned int sig_len); + +DEFINEFUNC(unsigned int, RSA_size, (const GO_RSA *arg0), (arg0)) +DEFINEFUNC(int, RSA_check_key, (const GO_RSA *arg0), (arg0)) + +DEFINEFUNC(int, EVP_EncryptInit_ex, + (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, const unsigned char *key, const unsigned char *iv), + (ctx, type, impl, key, iv)) +DEFINEFUNC(int, EVP_EncryptUpdate, + (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), + (ctx, out, outl, in, inl)) +DEFINEFUNC(int, EVP_EncryptFinal_ex, + (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl), + (ctx, out, outl)) + +DEFINEFUNC(int, EVP_DecryptInit_ex, + (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, ENGINE *impl, const unsigned char *key, const unsigned char *iv), + (ctx, type, impl, key, iv)) +DEFINEFUNC(int, EVP_DecryptUpdate, + (EVP_CIPHER_CTX *ctx, unsigned char *out, int *outl, const unsigned char *in, int inl), + (ctx, out, outl, in, inl)) +DEFINEFUNC(int, EVP_DecryptFinal_ex, + (EVP_CIPHER_CTX *ctx, unsigned char *outm, int *outl), + (ctx, outm, outl)) + +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_128_gcm, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_128_cbc, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_128_ctr, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_128_ecb, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_192_cbc, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_192_ctr, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_192_ecb, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_192_gcm, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_256_cbc, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_256_ctr, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_256_ecb, (void), ()) +DEFINEFUNC(const EVP_CIPHER*, EVP_aes_256_gcm, (void), ()) + +DEFINEFUNC(void, EVP_CIPHER_CTX_free, (EVP_CIPHER_CTX* arg0), (arg0)) +DEFINEFUNC(int, EVP_CIPHER_CTX_ctrl, (EVP_CIPHER_CTX *ctx, int type, int arg, void *ptr), (ctx, type, arg, ptr)) + +int _goboringcrypto_EVP_CIPHER_CTX_seal( + uint8_t *out, uint8_t *nonce, + uint8_t *aad, size_t aad_len, + uint8_t *plaintext, size_t plaintext_len, + size_t *ciphertext_len, uint8_t *key, int key_size); + +int _goboringcrypto_EVP_CIPHER_CTX_open( + uint8_t *ciphertext, int ciphertext_len, + uint8_t *aad, int aad_len, + uint8_t *tag, uint8_t *key, int key_size, + uint8_t *nonce, int nonce_len, + uint8_t *plaintext, size_t *plaintext_len); + +typedef EVP_PKEY GO_EVP_PKEY; + +DEFINEFUNC(GO_EVP_PKEY *, EVP_PKEY_new, (void), ()) +DEFINEFUNC(void, EVP_PKEY_free, (GO_EVP_PKEY * arg0), (arg0)) +DEFINEFUNC(int, EVP_PKEY_set1_RSA, (GO_EVP_PKEY * arg0, GO_RSA *arg1), (arg0, arg1)) +DEFINEFUNC(int, EVP_PKEY_set1_EC_KEY, (GO_EVP_PKEY * arg0, GO_EC_KEY *arg1), (arg0, arg1)) +DEFINEFUNC(int, EVP_PKEY_verify, + (EVP_PKEY_CTX *ctx, const unsigned char *sig, unsigned int siglen, const unsigned char *tbs, size_t tbslen), + (ctx, sig, siglen, tbs, tbslen)) + +typedef EVP_PKEY_CTX GO_EVP_PKEY_CTX; + +DEFINEFUNC(GO_EVP_PKEY_CTX *, EVP_PKEY_CTX_new, (GO_EVP_PKEY * arg0, ENGINE *arg1), (arg0, arg1)) +DEFINEFUNC(void, EVP_PKEY_CTX_free, (GO_EVP_PKEY_CTX * arg0), (arg0)) +DEFINEFUNC(int, EVP_PKEY_CTX_ctrl, + (EVP_PKEY_CTX * ctx, int keytype, int optype, int cmd, int p1, void *p2), + (ctx, keytype, optype, cmd, p1, p2)) +DEFINEFUNCINTERNAL(int, RSA_pkey_ctx_ctrl, + (EVP_PKEY_CTX *ctx, int optype, int cmd, int p1, void *p2), + (ctx, optype, cmd, p1, p2)) + +static inline int +_goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(GO_EVP_PKEY_CTX* ctx, int pad) { +#if OPENSSL_VERSION_NUMBER < 0x10100000L + return _goboringcrypto_EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL); +#else + return _goboringcrypto_internal_RSA_pkey_ctx_ctrl(ctx, -1, EVP_PKEY_CTRL_RSA_PADDING, pad, NULL); +#endif +} + +#if OPENSSL_VERSION_NUMBER < 0x30000000 +static inline int +_goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(GO_EVP_PKEY_CTX *ctx, uint8_t *l, int llen) +{ + return _goboringcrypto_EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_OAEP_LABEL, llen, (void *)l); +} +#else +DEFINEFUNC(int, EVP_PKEY_CTX_set0_rsa_oaep_label, + (GO_EVP_PKEY_CTX *ctx, uint8_t *l, int llen), + (ctx, l, llen)) +#endif + +static inline int +_goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(GO_EVP_PKEY_CTX *ctx, const GO_EVP_MD *md) +{ + return _goboringcrypto_EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, EVP_PKEY_OP_TYPE_CRYPT, EVP_PKEY_CTRL_RSA_OAEP_MD, 0, (void *)md); +} + +static inline int +_goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(GO_EVP_PKEY_CTX * arg0, int arg1) { + return _goboringcrypto_EVP_PKEY_CTX_ctrl(arg0, EVP_PKEY_RSA, + (EVP_PKEY_OP_SIGN|EVP_PKEY_OP_VERIFY), + EVP_PKEY_CTRL_RSA_PSS_SALTLEN, + arg1, NULL); +} + +static inline int +_goboringcrypto_EVP_PKEY_CTX_set_signature_md(EVP_PKEY_CTX *ctx, const EVP_MD *md) { + return _goboringcrypto_EVP_PKEY_CTX_ctrl(ctx, -1, EVP_PKEY_OP_TYPE_SIG, EVP_PKEY_CTRL_MD, 0, (void *)md); +} + +static inline int +_goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(GO_EVP_PKEY_CTX * ctx, const GO_EVP_MD *md) { + return _goboringcrypto_EVP_PKEY_CTX_ctrl(ctx, EVP_PKEY_RSA, + EVP_PKEY_OP_TYPE_SIG | EVP_PKEY_OP_TYPE_CRYPT, + EVP_PKEY_CTRL_RSA_MGF1_MD, 0, (void *)md); +} + +DEFINEFUNC(int, EVP_PKEY_decrypt, + (GO_EVP_PKEY_CTX * arg0, uint8_t *arg1, unsigned int *arg2, const uint8_t *arg3, unsigned int arg4), + (arg0, arg1, arg2, arg3, arg4)) +DEFINEFUNC(int, EVP_PKEY_encrypt, + (GO_EVP_PKEY_CTX * arg0, uint8_t *arg1, unsigned int *arg2, const uint8_t *arg3, unsigned int arg4), + (arg0, arg1, arg2, arg3, arg4)) +DEFINEFUNC(int, EVP_PKEY_decrypt_init, (GO_EVP_PKEY_CTX * arg0), (arg0)) +DEFINEFUNC(int, EVP_PKEY_encrypt_init, (GO_EVP_PKEY_CTX * arg0), (arg0)) +DEFINEFUNC(int, EVP_PKEY_sign_init, (GO_EVP_PKEY_CTX * arg0), (arg0)) +DEFINEFUNC(int, EVP_PKEY_verify_init, (GO_EVP_PKEY_CTX * arg0), (arg0)) +DEFINEFUNC(int, EVP_PKEY_sign, + (GO_EVP_PKEY_CTX * arg0, uint8_t *arg1, size_t *arg2, const uint8_t *arg3, size_t arg4), + (arg0, arg1, arg2, arg3, arg4)) + +DEFINEFUNC(int, EVP_PKEY_derive_init, (GO_EVP_PKEY_CTX *arg0), (arg0)) +DEFINEFUNC(int, EVP_PKEY_derive, (GO_EVP_PKEY_CTX *arg0, unsigned char *arg1, size_t *arg2), (arg0, arg1, arg2)) +#if OPENSSL_VERSION_NUMBER >= 0x30000000L +DEFINEFUNC(int, EVP_PKEY_derive_set_peer_ex, (GO_EVP_PKEY_CTX *arg0, GO_EVP_PKEY *arg1, int arg2), (arg0, arg1, arg2)) +#else +DEFINEFUNC(int, EVP_PKEY_derive_set_peer, (GO_EVP_PKEY_CTX *arg0, GO_EVP_PKEY *arg1), (arg0, arg1)) + +# if OPENSSL_VERSION_NUMBER >= 0x10100000L +DEFINEFUNC(int, EVP_PKEY_public_check, (EVP_PKEY_CTX *arg0), (arg0)) + +static inline int +_goboringcrypto_EVP_PKEY_derive_set_peer_ex(GO_EVP_PKEY_CTX *ctx, GO_EVP_PKEY *key, int validate) +{ + EVP_PKEY_CTX *check_ctx = _goboringcrypto_EVP_PKEY_CTX_new(key, NULL); + if (check_ctx == NULL) { + return -1; + } + int ok = _goboringcrypto_EVP_PKEY_public_check(check_ctx); + _goboringcrypto_EVP_PKEY_CTX_free(check_ctx); + if (ok != 1) { + return -1; + } + return _goboringcrypto_EVP_PKEY_derive_set_peer(ctx, key); +} +# else +static inline int +_goboringcrypto_EVP_PKEY_derive_set_peer_ex(GO_EVP_PKEY_CTX *ctx, GO_EVP_PKEY *key, int validate) +{ + /* No way to validate public key in OpenSSL 1.0.2 */ + (void)validate; + return _goboringcrypto_EVP_PKEY_derive_set_peer(ctx, key); +} +# endif +#endif diff --git a/v2/openssl/hmac.go b/v2/openssl/hmac.go new file mode 100644 index 00000000..6f001777 --- /dev/null +++ b/v2/openssl/hmac.go @@ -0,0 +1,163 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +// #include "goopenssl.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 + } + + var hkey []byte + if key != nil && len(key) > 0 { + // Note: Could hash down long keys here using EVP_Digest. + hkey = make([]byte, len(key)) + copy(hkey, key) + } else { + // This is supported in BoringSSL/Standard lib and as such + // we must support it here. When using HMAC with a null key + // HMAC_Init will try and reuse the key from the ctx. This is + // not the bahavior previously implemented, so as a workaround + // we pass an "empty" key. + hkey = make([]byte, C.EVP_MAX_MD_SIZE) + } + hmac := &boringHMAC{ + md: md, + size: ch.Size(), + blockSize: ch.BlockSize(), + key: hkey, + ctx: C._goboringcrypto_HMAC_CTX_new(), + } + 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 { + 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_reset(h.ctx) + + if C._goboringcrypto_HMAC_Init_ex(h.ctx, unsafe.Pointer(base(h.key)), C.int(len(h.key)), h.md, nil) == 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_free(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. + h.ctx2 = C._goboringcrypto_HMAC_CTX_new() + 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_free(h.ctx2) + return append(in, h.sum...) +} diff --git a/v2/openssl/hmac_test.go b/v2/openssl/hmac_test.go new file mode 100644 index 00000000..cb88f691 --- /dev/null +++ b/v2/openssl/hmac_test.go @@ -0,0 +1,17 @@ +package openssl + +import ( + "testing" +) + +// Just tests that we can create an HMAC instance. +// Previously would cause panic because of incorrect +// stack allocation of opaque OpenSSL type. +func TestNewHMAC(t *testing.T) { + if !Enabled() { + t.Skip("boringcrypto: skipping test, FIPS not enabled") + } + mac := NewHMAC(NewSHA256, nil) + mac.Write([]byte("foo")) + t.Logf("%x\n", mac.Sum(nil)) +} diff --git a/v2/openssl/notboring.go b/v2/openssl/notboring.go new file mode 100644 index 00000000..ec095b4d --- /dev/null +++ b/v2/openssl/notboring.go @@ -0,0 +1,130 @@ +// 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. + +//go:build !linux || !cgo || android || cmd_go_bootstrap || msan || no_openssl +// +build !linux !cgo android cmd_go_bootstrap msan no_openssl + +package openssl + +import ( + "crypto" + "crypto/cipher" + "crypto/internal/boring/sig" + "hash" +) + +var enabled = 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() {} + +func ExecutingTest() bool { return false } + +// This is a noop withotu BoringCrytpo. +func PanicIfStrictFIPS(v interface{}) {} + +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 BigInt, err error) { + panic("boringcrypto: not available") +} +func NewPrivateKeyECDSA(curve string, X, Y, D BigInt) (*PrivateKeyECDSA, error) { + panic("boringcrypto: not available") +} +func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) { + panic("boringcrypto: not available") +} +func SignECDSA(priv *PrivateKeyECDSA, hash []byte, h crypto.Hash) (r, s BigInt, err error) { + panic("boringcrypto: not available") +} +func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte, h crypto.Hash) ([]byte, error) { + panic("boringcrypto: not available") +} +func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, r, s BigInt, h crypto.Hash) bool { + panic("boringcrypto: not available") +} + +type PublicKeyECDH struct{ _ int } +type PrivateKeyECDH struct{ _ int } + +func GenerateKeyECDH(curve string) (X, Y, D BigInt, err error) { + panic("boringcrypto: not available") +} +func NewPrivateKeyECDH(curve string, X, Y, D BigInt) (*PrivateKeyECDH, error) { + panic("boringcrypto: not available") +} +func NewPublicKeyECDH(curve string, X, Y BigInt) (*PublicKeyECDH, error) { + panic("boringcrypto: not available") +} +func SharedKeyECDH(priv *PrivateKeyECDH, peerPublicKey []byte) ([]byte, error) { + 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 BigInt, err error) { + panic("boringcrypto: not available") +} +func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) { + panic("boringcrypto: not available") +} +func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) { panic("boringcrypto: not available") } +func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, msgHashed bool) ([]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, msgHashed bool) 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/v2/openssl/openssl.go b/v2/openssl/openssl.go new file mode 100644 index 00000000..58cade7c --- /dev/null +++ b/v2/openssl/openssl.go @@ -0,0 +1,247 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +/* +#cgo LDFLAGS: -ldl + +#include "goopenssl.h" +*/ +import "C" +import ( + "errors" + "fmt" + "math/bits" + "os" + "runtime" + "unsafe" +) + +const ( + fipsOn = C.int(1) + fipsOff = C.int(0) +) + +const GoStrictFipsEnv = "GOLANG_STRICT_FIPS" + +const ( + OPENSSL_VERSION_1_1_0 = uint64(C.ulong(0x10100000)) + OPENSSL_VERSION_3_0_0 = uint64(C.ulong(0x30000000)) +) + +// Enabled controls whether FIPS crypto is enabled. +var enabled = false + +// When this variable is true, the go crypto API will panic when a caller +// tries to use the API in a non-compliant manner. When this is false, the +// go crypto API will allow existing go crypto APIs to be used even +// if they aren't FIPS compliant. However, all the underlying crypto operations +// will still be done by OpenSSL. +var strictFIPS = false + +func init() { + runtime.LockOSThread() + defer runtime.UnlockOSThread() + + // Check if we can `dlopen` OpenSSL + if C._goboringcrypto_DLOPEN_OPENSSL() == C.NULL { + return + } + + // Initialize the OpenSSL library. + C._goboringcrypto_OPENSSL_setup() + + // Check to see if the system is running in FIPS mode, if so + // enable "boring" mode to call into OpenSSL for FIPS compliance. + if fipsModeEnabled() { + enableBoringFIPSMode() + } +} + +func openSSLVersion() uint64 { + return uint64(C._goboringcrypto_internal_OPENSSL_VERSION_NUMBER()) +} + +func enableBoringFIPSMode() { + enabled = true + + if os.Getenv(GoStrictFipsEnv) == "1" { + strictFIPS = true + } + + if C._goboringcrypto_OPENSSL_thread_setup() != 1 { + panic("boringcrypto: OpenSSL thread setup failed") + } +} + +func fipsModeEnabled() bool { + // Due to the way providers work in openssl 3, the FIPS methods are not + // necessarily going to be available for us to load based on the GOLANG_FIPS + // environment variable alone. For now, we must rely on the config to tell + // us if the provider is configured and active. + fipsConfigured := C._goboringcrypto_FIPS_mode() == fipsOn + openSSLVersion := openSSLVersion() + if openSSLVersion >= OPENSSL_VERSION_3_0_0 { + if !fipsConfigured && os.Getenv("GOLANG_FIPS") == "1" { + panic("GOLANG_FIPS=1 specified but OpenSSL FIPS provider is not configured") + } + return fipsConfigured + + } else { + return os.Getenv("GOLANG_FIPS") == "1" || fipsConfigured + } +} + +var randstub bool + +func RandStubbed() bool { + return randstub +} + +func StubOpenSSLRand() { + if !randstub { + randstub = true + C._goboringcrypto_stub_openssl_rand() + } +} + +func RestoreOpenSSLRand() { + if randstub { + randstub = false + C._goboringcrypto_restore_openssl_rand() + } +} + +func hasSuffix(s, t string) bool { + return len(s) > len(t) && s[len(s)-len(t):] == t +} + +func PanicIfStrictFIPS(msg string) { + if IsStrictFips() { + panic(msg) + } +} + +func IsStrictFips() bool { + return os.Getenv(GoStrictFipsEnv) == "1" || strictFIPS +} + +func NewOpenSSLError(msg string) error { + var e C.ulong + message := fmt.Sprintf("\n%v\nopenssl error(s):", msg) + for { + var buf [256]C.char + var file, fnc, data *C.char + var line, flags C.int + e = C._goboringcrypto_internal_ERR_get_error_all(&file, &line, &fnc, &data, &flags) + if e == 0 { + break + } + + C._goboringcrypto_internal_ERR_error_string_n(e, (*C.uchar)(unsafe.Pointer(&buf[0])), C.size_t(len(buf))) + message = fmt.Sprintf( + "%v\nfile: %v\nline: %v\nfunction: %v\nflags: %v\nerror string: %s\n", + message, C.GoString(file), line, C.GoString(fnc), flags, C.GoString(&(buf[0]))) + + } + return errors.New(message) +} + +// Unreachable marks code that should be unreachable +// when FIPS mode. It panics only when +// the system is in FIPS mode. +func Unreachable() { + if Enabled() { + panic("openssl: invalid code execution") + } +} + +// UnreachableExceptTests marks code that should be unreachable +// when FIPS mode is active. It panics only when the system is in FIPS mode +// and not executing under tests. +func UnreachableExceptTests() { + name := os.Args[0] + if Enabled() && !ExecutingTest() { + println("openssl: unexpected code execution in", name) + panic("openssl: invalid code execution") + } +} + +// ExecutingTest returns a boolean indicating if we're +// executing under a test binary or not. +func ExecutingTest() bool { + name := os.Args[0] + return hasSuffix(name, "_test") || hasSuffix(name, ".test") +} + +type fail string + +func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" } + +func wbase(b BigInt) *C.uint8_t { + if len(b) == 0 { + return nil + } + return (*C.uint8_t)(unsafe.Pointer(&b[0])) +} + +const wordBytes = bits.UintSize / 8 + +func bigToBN(x BigInt) *C.GO_BIGNUM { + return C._goboringcrypto_BN_le2bn(wbase(x), C.size_t(len(x)*wordBytes), nil) +} + +func bnToBig(bn *C.GO_BIGNUM) BigInt { + x := make(BigInt, (C._goboringcrypto_BN_num_bytes(bn)+wordBytes-1)/wordBytes) + if C._goboringcrypto_BN_bn2le_padded(wbase(x), C.size_t(len(x)*wordBytes), bn) == 0 { + panic("boringcrypto: bignum conversion failed") + } + return x +} + +func bigToBn(bnp **C.GO_BIGNUM, b BigInt) bool { + if *bnp != nil { + C._goboringcrypto_BN_free(*bnp) + *bnp = nil + } + if b == nil { + return true + } + bn := bigToBN(b) + if bn == nil { + return false + } + *bnp = bn + return true +} + +// noescape hides a pointer from escape analysis. noescape is +// the identity function but escape analysis doesn't think the +// output depends on the input. noescape is inlined and currently +// compiles down to zero instructions. +// USE CAREFULLY! +// +//go:nosplit +func noescape(p unsafe.Pointer) unsafe.Pointer { + x := uintptr(p) + return unsafe.Pointer(x ^ 0) +} + +var zero byte + +// addr converts p to its base addr, including a noescape along the way. +// If p is nil, addr returns a non-nil pointer, so that the result can always +// be dereferenced. +// +//go:nosplit +func addr(p []byte) *byte { + if len(p) == 0 { + return &zero + } + return (*byte)(noescape(unsafe.Pointer(&p[0]))) +} diff --git a/v2/openssl/openssl_ecdsa_signature.c b/v2/openssl/openssl_ecdsa_signature.c new file mode 100644 index 00000000..2349db1f --- /dev/null +++ b/v2/openssl/openssl_ecdsa_signature.c @@ -0,0 +1,46 @@ +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" + +int _goboringcrypto_ECDSA_sign(EVP_MD *md, const uint8_t *msg, size_t msgLen, + uint8_t *sig, unsigned int *slen, + GO_EC_KEY *eckey) { + int result; + EVP_PKEY *key = _goboringcrypto_EVP_PKEY_new(); + if (!key) { + return 0; + } + if (!_goboringcrypto_EVP_PKEY_set1_EC_KEY(key, eckey)) { + result = 0; + goto err; + } + result = _goboringcrypto_EVP_sign(md, NULL, msg, msgLen, sig, slen, key); +err: + _goboringcrypto_EVP_PKEY_free(key); + return result; +} + +int _goboringcrypto_ECDSA_verify(EVP_MD *md, const uint8_t *msg, size_t msgLen, + const uint8_t *sig, unsigned int slen, + GO_EC_KEY *eckey) { + + int result; + EVP_PKEY *key = _goboringcrypto_EVP_PKEY_new(); + if (!key) { + return 0; + } + if (!_goboringcrypto_EVP_PKEY_set1_EC_KEY(key, eckey)) { + result = 0; + goto err; + } + + result = _goboringcrypto_EVP_verify(md, NULL, msg, msgLen, sig, slen, key); + +err: + _goboringcrypto_EVP_PKEY_free(key); + return result; +} diff --git a/v2/openssl/openssl_evp.c b/v2/openssl/openssl_evp.c new file mode 100644 index 00000000..43790198 --- /dev/null +++ b/v2/openssl/openssl_evp.c @@ -0,0 +1,128 @@ +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" + +int _goboringcrypto_EVP_sign(EVP_MD *md, EVP_PKEY_CTX *ctx, const uint8_t *msg, + size_t msgLen, uint8_t *sig, unsigned int *slen, + EVP_PKEY *key) { + EVP_MD_CTX *mdctx = NULL; + int ret = 0; + + if (!(mdctx = _goboringcrypto_EVP_MD_CTX_create())) + goto err; + + if (1 != _goboringcrypto_EVP_DigestSignInit(mdctx, &ctx, md, NULL, key)) + goto err; + + if (1 != _goboringcrypto_EVP_DigestUpdate(mdctx, msg, msgLen)) + goto err; + + /* Obtain the signature length */ + if (1 != _goboringcrypto_EVP_DigestSignFinal(mdctx, NULL, slen)) + goto err; + /* Obtain the signature */ + if (1 != _goboringcrypto_EVP_DigestSignFinal(mdctx, sig, slen)) + goto err; + + /* Success */ + ret = 1; + +err: + if (mdctx) + _goboringcrypto_EVP_MD_CTX_free(mdctx); + + return ret; +} + +int _goboringcrypto_EVP_sign_raw(EVP_MD *md, EVP_PKEY_CTX *ctx, const uint8_t *msg, + size_t msgLen, uint8_t *sig, size_t *slen, + GO_RSA *rsa_key) { + int ret = 0; + GO_EVP_PKEY *pk = _goboringcrypto_EVP_PKEY_new(); + _goboringcrypto_EVP_PKEY_assign_RSA(pk, rsa_key); + + if (!ctx && !(ctx = _goboringcrypto_EVP_PKEY_CTX_new(pk, NULL))) + goto err; + + if (1 != _goboringcrypto_EVP_PKEY_sign_init(ctx)) + goto err; + + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) + goto err; + + if (1 != _goboringcrypto_EVP_PKEY_sign(ctx, sig, slen, msg, msgLen)) + goto err; + + /* Success */ + ret = 1; + +err: + if (ctx) + _goboringcrypto_EVP_PKEY_CTX_free(ctx); + + return ret; +} + +int _goboringcrypto_EVP_verify(EVP_MD *md, EVP_PKEY_CTX *ctx, + const uint8_t *msg, size_t msgLen, + const uint8_t *sig, unsigned int slen, + EVP_PKEY *key) { + EVP_MD_CTX *mdctx = NULL; + int ret = 0; + + if (!(mdctx = _goboringcrypto_EVP_MD_CTX_create())) + goto err; + if (1 != _goboringcrypto_EVP_DigestVerifyInit(mdctx, &ctx, md, NULL, key)) + goto err; + + if (1 != _goboringcrypto_EVP_DigestUpdate(mdctx, msg, msgLen)) + goto err; + + if (1 != _goboringcrypto_EVP_DigestVerifyFinal(mdctx, sig, slen)) { + goto err; + } + + /* Success */ + ret = 1; + +err: + if (mdctx) + _goboringcrypto_EVP_MD_CTX_free(mdctx); + + return ret; +} + +int _goboringcrypto_EVP_verify_raw(const uint8_t *msg, size_t msgLen, + const uint8_t *sig, unsigned int slen, + GO_RSA *rsa_key) { + + int ret = 0; + EVP_PKEY_CTX *ctx; + GO_EVP_PKEY *pk = _goboringcrypto_EVP_PKEY_new(); + _goboringcrypto_EVP_PKEY_assign_RSA(pk, rsa_key); + + if (!(ctx = _goboringcrypto_EVP_PKEY_CTX_new(pk, NULL))) + goto err; + + if (1 != _goboringcrypto_EVP_PKEY_verify_init(ctx)) + goto err; + + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING) <= 0) + goto err; + + if (1 != _goboringcrypto_EVP_PKEY_verify(ctx, sig, slen, msg, msgLen)) + goto err; + + /* Success */ + ret = 1; + +err: + if (ctx) + _goboringcrypto_EVP_PKEY_CTX_free(ctx); + + return ret; +} diff --git a/v2/openssl/openssl_lock_setup.c b/v2/openssl/openssl_lock_setup.c new file mode 100644 index 00000000..49d40a74 --- /dev/null +++ b/v2/openssl/openssl_lock_setup.c @@ -0,0 +1,49 @@ +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" +#include <openssl/err.h> +#include <pthread.h> +#include <stdio.h> +#include <sys/syscall.h> +#include <sys/types.h> + +#define _GNU_SOURCE +#include <unistd.h> + +#define MUTEX_TYPE pthread_mutex_t +#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL) +#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x)) +#define MUTEX_LOCK(x) pthread_mutex_lock(&(x)) +#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x)) +#define THREAD_ID pthread_self() + +/* This array will store all of the mutexes available to OpenSSL. */ +static MUTEX_TYPE *mutex_buf = NULL; + +static void locking_function(int mode, int n, const char *file, int line) { + if (mode & CRYPTO_LOCK) + MUTEX_LOCK(mutex_buf[n]); + else + MUTEX_UNLOCK(mutex_buf[n]); +} + +static unsigned long id_function(void) { + return ((unsigned long)syscall(__NR_gettid)); +} + +int _goboringcrypto_OPENSSL_thread_setup(void) { + int i; + + mutex_buf = malloc(_goboringcrypto_CRYPTO_num_locks() * sizeof(MUTEX_TYPE)); + if (!mutex_buf) + return 0; + for (i = 0; i < _goboringcrypto_CRYPTO_num_locks(); i++) + MUTEX_SETUP(mutex_buf[i]); + _goboringcrypto_CRYPTO_set_id_callback(id_function); + _goboringcrypto_CRYPTO_set_locking_callback(locking_function); + return 1; +} diff --git a/v2/openssl/openssl_port_aead_gcm.c b/v2/openssl/openssl_port_aead_gcm.c new file mode 100644 index 00000000..7eb645ef --- /dev/null +++ b/v2/openssl/openssl_port_aead_gcm.c @@ -0,0 +1,171 @@ +// This file contains a port of the BoringSSL AEAD interface. +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" +#include <openssl/err.h> + +int _goboringcrypto_EVP_CIPHER_CTX_seal(uint8_t *out, uint8_t *iv, uint8_t *aad, + size_t aad_len, uint8_t *plaintext, + size_t plaintext_len, + size_t *ciphertext_len, uint8_t *key, + int key_size) { + + EVP_CIPHER_CTX *ctx; + int len; + int ret; + + if (plaintext_len == 0) { + plaintext = ""; + } + + if (aad_len == 0) { + aad = ""; + } + + // Create and initialise the context. + if (!(ctx = _goboringcrypto_EVP_CIPHER_CTX_new())) { + goto err; + } + + switch (key_size) { + case 128: + if (!_goboringcrypto_EVP_EncryptInit_ex( + ctx, _goboringcrypto_EVP_aes_128_gcm(), NULL, NULL, NULL)) { + goto err; + } + break; + case 256: + if (!_goboringcrypto_EVP_EncryptInit_ex( + ctx, _goboringcrypto_EVP_aes_256_gcm(), NULL, NULL, NULL)) { + goto err; + } + break; + default: + goto err; + } + + // Initialize IV. + if (!_goboringcrypto_EVP_EncryptInit_ex(ctx, NULL, NULL, key, NULL)) { + goto err; + } + if (!_goboringcrypto_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, 12, + 0)) { + goto err; + } + if (!_goboringcrypto_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IV_FIXED, -1, + iv)) { + goto err; + } + if (!_goboringcrypto_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_IV_GEN, 0, iv)) { + goto err; + } + + // Provide AAD data. + if (!_goboringcrypto_EVP_EncryptUpdate(ctx, NULL, &len, aad, aad_len)) { + goto err; + } + + if (!_goboringcrypto_EVP_EncryptUpdate(ctx, out, &len, plaintext, + plaintext_len)) { + goto err; + } + *ciphertext_len = len; + + if (!_goboringcrypto_EVP_EncryptFinal_ex(ctx, out + len, &len)) { + goto err; + } + *ciphertext_len += len; + + if (!_goboringcrypto_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, 16, + out + (*ciphertext_len))) { + goto err; + } + *ciphertext_len += 16; + ret = 1; + +err: + _goboringcrypto_EVP_CIPHER_CTX_free(ctx); + + if (ret > 0) { + return ret; + } else { + return 0; + } +} + +int _goboringcrypto_EVP_CIPHER_CTX_open(uint8_t *ciphertext, int ciphertext_len, + uint8_t *aad, int aad_len, uint8_t *tag, + uint8_t *key, int key_size, uint8_t *iv, + int iv_len, uint8_t *plaintext, + size_t *plaintext_len) { + + EVP_CIPHER_CTX *ctx; + int len; + int ret; + + if (aad_len == 0) { + aad = ""; + } + + // Create and initialise the context. + if (!(ctx = _goboringcrypto_EVP_CIPHER_CTX_new())) + return 0; + + switch (key_size) { + case 128: + if (!_goboringcrypto_EVP_DecryptInit_ex( + ctx, _goboringcrypto_EVP_aes_128_gcm(), NULL, NULL, NULL)) { + goto err; + } + break; + case 256: + if (!_goboringcrypto_EVP_DecryptInit_ex( + ctx, _goboringcrypto_EVP_aes_256_gcm(), NULL, NULL, NULL)) { + goto err; + } + break; + } + + // Initialize key and nonce. + if (!_goboringcrypto_EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv)) { + goto err; + } + + // Provide any AAD data. + if (!_goboringcrypto_EVP_DecryptUpdate(ctx, NULL, &len, aad, aad_len)) { + goto err; + } + + // Provide the message to be decrypted, and obtain the plaintext output. + if (!_goboringcrypto_EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, + ciphertext_len)) { + goto err; + } + *plaintext_len = len; + + // Set expected tag value. Works in OpenSSL 1.0.1d and later. + if (!_goboringcrypto_EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, 16, + tag)) { + goto err; + } + + // Finalise the decryption. A positive return value indicates success, + // anything else is a failure - the plaintext is not trustworthy. + ret = _goboringcrypto_EVP_DecryptFinal_ex(ctx, plaintext + len, &len); + +err: + _goboringcrypto_EVP_CIPHER_CTX_free(ctx); + + if (ret > 0) { + // Success + *plaintext_len += len; + return ret; + } else { + // Verify failed + return 0; + } +} diff --git a/v2/openssl/openssl_port_ctr128.c b/v2/openssl/openssl_port_ctr128.c new file mode 100644 index 00000000..df4ebe32 --- /dev/null +++ b/v2/openssl/openssl_port_ctr128.c @@ -0,0 +1,13 @@ +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" + +void _goboringcrypto_EVP_AES_ctr128_enc(EVP_CIPHER_CTX *ctx, const uint8_t *in, + uint8_t *out, size_t in_len) { + int len; + _goboringcrypto_EVP_EncryptUpdate(ctx, out, &len, in, in_len); +} diff --git a/v2/openssl/openssl_port_evp_md5_sha1.c b/v2/openssl/openssl_port_evp_md5_sha1.c new file mode 100644 index 00000000..2eedd5b8 --- /dev/null +++ b/v2/openssl/openssl_port_evp_md5_sha1.c @@ -0,0 +1,90 @@ +// This file contains a backport of the EVP_md5_sha1 method. +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +// The following is a partial backport of crypto/evp/m_md5_sha1.c, +// commit cbc8a839959418d8a2c2e3ec6bdf394852c9501e on the +// OpenSSL_1_1_0-stable branch. The ctrl function has been removed. + +#include "goopenssl.h" + +#if OPENSSL_VERSION_NUMBER < 0x10100000L +// New in OpenSSL 1.1. +static inline void * +_goboringcrypto_internal_EVP_MD_CTX_md_data(EVP_MD_CTX *ctx) { + return ctx->md_data; +} + +/* + * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the "License"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#if !defined(OPENSSL_NO_MD5) + +#include <openssl/evp.h> +#include <openssl/md5.h> +#include <openssl/objects.h> +#include <openssl/rsa.h> +#include <openssl/sha.h> +#include <openssl/x509.h> + +struct md5_sha1_ctx { + MD5_CTX md5; + SHA_CTX sha1; +}; + +static int _goboringcrypto_internal_init(EVP_MD_CTX *ctx) { + struct md5_sha1_ctx *mctx = _goboringcrypto_internal_EVP_MD_CTX_md_data(ctx); + if (!_goboringcrypto_internal_MD5_Init(&mctx->md5)) + return 0; + return _goboringcrypto_SHA1_Init(&mctx->sha1); +} + +static int _goboringcrypto_internal_update(EVP_MD_CTX *ctx, const void *data, + size_t count) { + struct md5_sha1_ctx *mctx = _goboringcrypto_internal_EVP_MD_CTX_md_data(ctx); + if (!_goboringcrypto_internal_MD5_Update(&mctx->md5, data, count)) + return 0; + return _goboringcrypto_SHA1_Update(&mctx->sha1, data, count); +} + +static int _goboringcrypto_internal_final(EVP_MD_CTX *ctx, unsigned char *md) { + struct md5_sha1_ctx *mctx = _goboringcrypto_internal_EVP_MD_CTX_md_data(ctx); + if (!_goboringcrypto_internal_MD5_Final(md, &mctx->md5)) + return 0; + return _goboringcrypto_SHA1_Final(md + MD5_DIGEST_LENGTH, &mctx->sha1); +} + +// Change: Removed: +// static int ctrl(EVP_MD_CTX *ctx, int cmd, int mslen, void *ms) + +static const EVP_MD md5_sha1_md = { + NID_md5_sha1, + NID_md5_sha1, + MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH, + 0, + _goboringcrypto_internal_init, + _goboringcrypto_internal_update, + _goboringcrypto_internal_final, + NULL, + NULL, + EVP_PKEY_NULL_method, // Change: inserted + MD5_CBLOCK, + sizeof(EVP_MD *) + sizeof(struct md5_sha1_ctx), + NULL, // Change: was ctrl +}; + +// Change: Apply name mangling. +const GO_EVP_MD *_goboringcrypto_backport_EVP_md5_sha1(void) { + return &md5_sha1_md; +} +#endif +#endif diff --git a/v2/openssl/openssl_port_hmac.c b/v2/openssl/openssl_port_hmac.c new file mode 100644 index 00000000..362d9e53 --- /dev/null +++ b/v2/openssl/openssl_port_hmac.c @@ -0,0 +1,16 @@ +// This file contains HMAC portability wrappers. +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" + +// Not in OpenSSL 1.1. However, HMAC_CTX_copy expects an initialized +// target in OpenSSL 1.1. +int _goboringcrypto_HMAC_CTX_copy_ex(GO_HMAC_CTX *dest, + const GO_HMAC_CTX *src) { + // HMAC_CTX_copy lacks the const qualifier for the second parameter. + return _goboringcrypto_HMAC_CTX_copy(dest, (GO_HMAC_CTX *)src); +} diff --git a/v2/openssl/openssl_port_rsa.c b/v2/openssl/openssl_port_rsa.c new file mode 100644 index 00000000..28241470 --- /dev/null +++ b/v2/openssl/openssl_port_rsa.c @@ -0,0 +1,219 @@ +// This file contains RSA portability wrappers. +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" + +// Only in BoringSSL. +int _goboringcrypto_RSA_generate_key_fips(GO_RSA *rsa, int size, + GO_BN_GENCB *cb) { + // BoringSSL's RSA_generate_key_fips hard-codes e to 65537. + BIGNUM *e = _goboringcrypto_BN_new(); + if (e == NULL) + return 0; + int ret = _goboringcrypto_BN_set_word(e, RSA_F4) && + _goboringcrypto_RSA_generate_key_ex(rsa, size, e, cb); + _goboringcrypto_BN_free(e); + return ret; +} + +int _goboringcrypto_RSA_digest_and_sign_pss_mgf1( + GO_RSA *rsa, unsigned int *out_len, uint8_t *out, size_t max_out, + const uint8_t *in, size_t in_len, EVP_MD *md, const EVP_MD *mgf1_md, + int salt_len) { + EVP_PKEY_CTX *ctx; + unsigned int siglen; + + int ret = 0; + EVP_PKEY *key = _goboringcrypto_EVP_PKEY_new(); + if (!key) { + goto err; + } + if (!_goboringcrypto_EVP_PKEY_set1_RSA(key, rsa)) + goto err; + ctx = _goboringcrypto_EVP_PKEY_CTX_new(key, NULL /* no engine */); + if (!ctx) + goto err; + + EVP_MD_CTX *mdctx = NULL; + if (!(mdctx = _goboringcrypto_EVP_MD_CTX_create())) + goto err; + + if (1 != _goboringcrypto_EVP_DigestSignInit(mdctx, &ctx, md, NULL, key)) + goto err; + + if (_goboringcrypto_EVP_PKEY_sign_init(ctx) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, + RSA_PKCS1_PSS_PADDING) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, salt_len) <= 0) + goto err; + if (mgf1_md) + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf1_md) <= 0) + goto err; + if (1 != _goboringcrypto_EVP_DigestUpdate(mdctx, in, in_len)) + goto err; + + /* Obtain the signature length */ + if (1 != _goboringcrypto_EVP_DigestSignFinal(mdctx, NULL, out_len)) + goto err; + /* Obtain the signature */ + if (1 != _goboringcrypto_EVP_DigestSignFinal(mdctx, out, out_len)) + goto err; + + ret = 1; + +err: + if (mdctx) + _goboringcrypto_EVP_MD_CTX_free(mdctx); + if (ctx) + _goboringcrypto_EVP_PKEY_CTX_free(ctx); + if (key) + _goboringcrypto_EVP_PKEY_free(key); + + return ret; +} + +int _goboringcrypto_RSA_sign_pss_mgf1(GO_RSA *rsa, unsigned int *out_len, + uint8_t *out, unsigned int max_out, + const uint8_t *in, unsigned int in_len, + EVP_MD *md, const EVP_MD *mgf1_md, + int salt_len) { + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey; + size_t siglen; + + int ret = 0; + pkey = _goboringcrypto_EVP_PKEY_new(); + if (!pkey) + goto err; + + if (_goboringcrypto_EVP_PKEY_set1_RSA(pkey, rsa) <= 0) + goto err; + + ctx = _goboringcrypto_EVP_PKEY_CTX_new(pkey, NULL /* no engine */); + if (!ctx) + goto err; + + if (_goboringcrypto_EVP_PKEY_sign_init(ctx) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, + RSA_PKCS1_PSS_PADDING) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, salt_len) <= 0) + goto err; + if (mgf1_md) + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf1_md) <= 0) + goto err; + /* Determine buffer length */ + if (_goboringcrypto_EVP_PKEY_sign(ctx, NULL, &siglen, in, in_len) <= 0) + goto err; + + if (max_out < siglen) + goto err; + + if (_goboringcrypto_EVP_PKEY_sign(ctx, out, &siglen, in, in_len) <= 0) + goto err; + + *out_len = siglen; + ret = 1; + +err: + if (ctx) + _goboringcrypto_EVP_PKEY_CTX_free(ctx); + if (pkey) + _goboringcrypto_EVP_PKEY_free(pkey); + + return ret; +} + +int _goboringcrypto_RSA_verify_pss_mgf1(RSA *rsa, const uint8_t *msg, + unsigned int msg_len, EVP_MD *md, + const EVP_MD *mgf1_md, int salt_len, + const uint8_t *sig, + unsigned int sig_len) { + EVP_PKEY_CTX *ctx; + EVP_PKEY *pkey; + + int ret = 0; + + pkey = _goboringcrypto_EVP_PKEY_new(); + if (!pkey) + goto err; + + if (_goboringcrypto_EVP_PKEY_set1_RSA(pkey, rsa) <= 0) + goto err; + + ctx = _goboringcrypto_EVP_PKEY_CTX_new(pkey, NULL /* no engine */); + if (!ctx) + goto err; + + if (_goboringcrypto_EVP_PKEY_verify_init(ctx) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, + RSA_PKCS1_PSS_PADDING) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, salt_len) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) + goto err; + if (mgf1_md) + if (_goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf1_md) <= 0) + goto err; + if (_goboringcrypto_EVP_PKEY_verify(ctx, sig, sig_len, msg, msg_len) <= 0) + goto err; + + ret = 1; + +err: + if (ctx) + _goboringcrypto_EVP_PKEY_CTX_free(ctx); + if (pkey) + _goboringcrypto_EVP_PKEY_free(pkey); + + return ret; +} + +int _goboringcrypto_EVP_RSA_sign(EVP_MD *md, const uint8_t *msg, + unsigned int msgLen, uint8_t *sig, + unsigned int *slen, RSA *rsa) { + int result; + EVP_PKEY *key = _goboringcrypto_EVP_PKEY_new(); + if (!key) { + return 0; + } + if (!_goboringcrypto_EVP_PKEY_set1_RSA(key, rsa)) { + result = 0; + goto err; + } + result = _goboringcrypto_EVP_sign(md, NULL, msg, msgLen, sig, slen, key); +err: + _goboringcrypto_EVP_PKEY_free(key); + return result; +} + +int _goboringcrypto_EVP_RSA_verify(EVP_MD *md, const uint8_t *msg, + unsigned int msgLen, const uint8_t *sig, + unsigned int slen, GO_RSA *rsa) { + int result; + EVP_PKEY *key = _goboringcrypto_EVP_PKEY_new(); + if (!key) { + return 0; + } + if (!_goboringcrypto_EVP_PKEY_set1_RSA(key, rsa)) { + result = 0; + goto err; + } + result = _goboringcrypto_EVP_verify(md, NULL, msg, msgLen, sig, slen, key); +err: + _goboringcrypto_EVP_PKEY_free(key); + return result; +} \ No newline at end of file diff --git a/v2/openssl/openssl_stub_rand.c b/v2/openssl/openssl_stub_rand.c new file mode 100644 index 00000000..22bd865a --- /dev/null +++ b/v2/openssl/openssl_stub_rand.c @@ -0,0 +1,45 @@ +// +build linux +// +build !android +// +build !no_openssl +// +build !cmd_go_bootstrap +// +build !msan + +#include "goopenssl.h" +#include <openssl/rand.h> + +static RAND_METHOD fake_rand; +static const RAND_METHOD *old_rand; + +int _goboringcrypto_stub_openssl_rand(void) { + /* save old rand method */ + if ((old_rand = _goboringcrypto_RAND_get_rand_method()) == NULL) + return 0; + + fake_rand.seed = old_rand->seed; + fake_rand.cleanup = old_rand->cleanup; + fake_rand.add = old_rand->add; + fake_rand.status = old_rand->status; + /* use own random function */ + fake_rand.bytes = fbytes; + fake_rand.pseudorand = old_rand->bytes; + /* set new RAND_METHOD */ + if (!_goboringcrypto_RAND_set_rand_method(&fake_rand)) + return 0; + return 1; +} + +int _goboringcrypto_restore_openssl_rand(void) { + if (!_goboringcrypto_RAND_set_rand_method(old_rand)) + return 0; + else + return 1; +} + +int fbytes(unsigned char *buf, int num) { + // return old_rand->bytes(buf, num); + int i; + for (i = 0; i < num; i++) { + buf[i] = 1; + } + return 1; +} diff --git a/v2/openssl/rand.go b/v2/openssl/rand.go new file mode 100644 index 00000000..b3668b88 --- /dev/null +++ b/v2/openssl/rand.go @@ -0,0 +1,25 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +// #include "goopenssl.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, NewOpenSSLError("RAND_bytes") + } + return len(b), nil +} + +const RandReader = randReader(0) diff --git a/v2/openssl/rsa.go b/v2/openssl/rsa.go new file mode 100644 index 00000000..915c8408 --- /dev/null +++ b/v2/openssl/rsa.go @@ -0,0 +1,411 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +// #include "goopenssl.h" +import "C" +import ( + "crypto" + "errors" + "hash" + "runtime" + "strconv" + "unsafe" +) + +func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { + bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) { + return nil, nil, nil, nil, nil, nil, nil, nil, e + } + + key := C._goboringcrypto_RSA_new() + if key == nil { + return bad(NewOpenSSLError("RSA_new failed")) + } + defer C._goboringcrypto_RSA_free(key) + + if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 { + return bad(NewOpenSSLError("RSA_generate_key_fips failed")) + } + + 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 BigInt) (*PublicKeyRSA, error) { + key := C._goboringcrypto_RSA_new() + if key == nil { + return nil, NewOpenSSLError("RSA_new failed") + } + var n, e *C.GO_BIGNUM + n = bigToBN(N) + e = bigToBN(E) + C._goboringcrypto_RSA_set0_key(key, n, e, nil) + 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 BigInt) (*PrivateKeyRSA, error) { + key := C._goboringcrypto_RSA_new() + if key == nil { + return nil, NewOpenSSLError("RSA_new failed") + } + var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM + n = bigToBN(N) + e = bigToBN(E) + d = bigToBN(D) + C._goboringcrypto_RSA_set0_key(key, n, e, d) + if P != nil && Q != nil { + p = bigToBN(P) + q = bigToBN(Q) + C._goboringcrypto_RSA_set0_factors(key, p, q) + } + if Dp != nil && Dq != nil && Qinv != nil { + dp = bigToBN(Dp) + dq = bigToBN(Dq) + qinv = bigToBN(Qinv) + C._goboringcrypto_RSA_set0_crt_params(key, dp, dq, qinv) + } + 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, NewOpenSSLError("EVP_PKEY_new failed") + } + 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, NewOpenSSLError("EVP_PKEY_CTX_new failed") + } + if init(ctx) == 0 { + return nil, nil, NewOpenSSLError("EVP_PKEY_operation_init failed") + } + if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 { + return nil, nil, NewOpenSSLError("EVP_PKEY_CTX_set_rsa_padding failed") + } + 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, NewOpenSSLError("EVP_PKEY_set_rsa_oaep_md failed") + } + // ctx takes ownership of label, so malloc a copy for BoringCrypto to free. + var clabel *C.uint8_t + clabel = nil + // OpenSSL 1.1.1 does not take ownership of the label if the length is zero. + // Depending on the malloc implementation, if clabel is allocated with malloc(0), + // metadata for the size-zero allocation is never cleaned up, which is a memory leak. + // As such, we must only allocate clabel if the label is of non zero length. + if (len(label) > 0) || (openSSLVersion() > OPENSSL_VERSION_3_0_0) { + clabel = (*C.uint8_t)(C.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.int(len(label))) != 1 { + if clabel != nil { + C.free(unsafe.Pointer(clabel)) + } + return nil, nil, NewOpenSSLError("EVP_PKEY_CTX_set0_rsa_oaep_label failed") + } + } + 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, NewOpenSSLError("EVP_PKEY_set_rsa_pss_saltlen failed") + } + } + 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, NewOpenSSLError("EVP_PKEY_set_rsa_mgf1_md failed") + } + } + + 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.uint, *C.uint8_t, C.uint) 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.uint + if crypt(ctx, nil, &outLen, base(in), C.uint(len(in))) == 0 { + return nil, NewOpenSSLError("EVP_PKEY_decrypt/encrypt failed") + } + out := make([]byte, outLen) + if crypt(ctx, base(out), &outLen, base(in), C.uint(len(in))) <= 0 { + return nil, NewOpenSSLError("EVP_PKEY_decrypt/encrypt failed") + } + 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.uint, in *C.uint8_t, inLen C.uint) 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.uint, in *C.uint8_t, inLen C.uint) 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.uint + 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.uint(len(out)), + base(hashed), C.uint(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.uint(len(hashed)), + md, nil, C.int(saltLen), base(sig), C.uint(len(sig))) + }) == 0 { + return fail("RSA_verify_pss_mgf1") + } + return nil +} + +func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, msg []byte, msgIsHashed bool) ([]byte, error) { + if h == 0 && ExecutingTest() { + return signRSAPKCS1v15Raw(priv, msg, C._goboringcrypto_EVP_md_null()) + } + + md := cryptoHashToMD(h) + if md == nil { + return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h))) + } + + if msgIsHashed { + var out []byte + var outLen C.uint + PanicIfStrictFIPS("You must provide a raw unhashed message for PKCS1v15 signing and use HashSignPKCS1v15 instead of SignPKCS1v15") + nid := C._goboringcrypto_EVP_MD_type(md) + 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(msg), C.uint(len(msg)), base(out), &outLen, key) + }) == 0 { + return nil, NewOpenSSLError("RSA_sign") + } + runtime.KeepAlive(priv) + return out[:outLen], nil + } + + var out []byte + var outLen C.uint + + if priv.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_EVP_RSA_sign(md, base(msg), C.uint(len(msg)), base(out), &outLen, key) + }) == 0 { + return nil, NewOpenSSLError("RSA_sign") + } + return out[:outLen], nil +} + +func signRSAPKCS1v15Raw(priv *PrivateKeyRSA, msg []byte, md *C.GO_EVP_MD) ([]byte, error) { + var out []byte + var outLen C.size_t + PanicIfStrictFIPS("You must provide a raw unhashed message for PKCS1v15 signing and use HashSignPKCS1v15 instead of SignPKCS1v15") + + if priv.withKey(func(key *C.GO_RSA) C.int { + out = make([]byte, C._goboringcrypto_RSA_size(key)) + outLen = C.size_t(len(out)) + return C._goboringcrypto_EVP_sign_raw(md, nil, base(msg), + C.size_t(len(msg)), base(out), &outLen, key) + }) == 0 { + return nil, NewOpenSSLError("RSA_sign") + } + runtime.KeepAlive(priv) + return out[:outLen], nil +} + +func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, msg, sig []byte, msgIsHashed bool) error { + if h == 0 && ExecutingTest() { + return verifyRSAPKCS1v15Raw(pub, msg, sig) + } + + md := cryptoHashToMD(h) + if md == nil { + return errors.New("crypto/rsa: unsupported hash function") + } + + if pub.withKey(func(key *C.GO_RSA) C.int { + size := int(C._goboringcrypto_RSA_size(key)) + if len(sig) < size { + return 0 + } + return 1 + }) == 0 { + return errors.New("crypto/rsa: verification error") + } + + if msgIsHashed { + PanicIfStrictFIPS("You must provide a raw unhashed message for PKCS1v15 verification and use HashVerifyPKCS1v15 instead of VerifyPKCS1v15") + nid := C._goboringcrypto_EVP_MD_type(md) + if pub.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_RSA_verify(nid, base(msg), C.uint(len(msg)), base(sig), C.uint(len(sig)), key) + }) == 0 { + return NewOpenSSLError("RSA_verify failed") + } + return nil + } + + if pub.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_EVP_RSA_verify(md, base(msg), C.uint(len(msg)), base(sig), C.uint(len(sig)), key) + }) == 0 { + return NewOpenSSLError("RSA_verify failed") + } + return nil +} + +func verifyRSAPKCS1v15Raw(pub *PublicKeyRSA, msg, sig []byte) error { + if pub.withKey(func(key *C.GO_RSA) C.int { + size := int(C._goboringcrypto_RSA_size(key)) + if len(sig) < size { + return 0 + } + return 1 + }) == 0 { + return errors.New("crypto/rsa: verification error") + } + if pub.withKey(func(key *C.GO_RSA) C.int { + return C._goboringcrypto_EVP_verify_raw(base(msg), C.size_t(len(msg)), base(sig), C.uint(len(sig)), key) + }) == 0 { + return NewOpenSSLError("RSA_verify failed") + } + return nil +} diff --git a/v2/openssl/sha.go b/v2/openssl/sha.go new file mode 100644 index 00000000..0b55cedc --- /dev/null +++ b/v2/openssl/sha.go @@ -0,0 +1,564 @@ +// 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. + +//go:build linux && !android && !cmd_go_bootstrap && !msan && !no_openssl +// +build linux,!android,!cmd_go_bootstrap,!msan,!no_openssl + +package openssl + +/* +#include "goopenssl.h" + +int +_goboringcrypto_gosha1(void *p, size_t n, void *out) +{ + GO_SHA_CTX ctx; + _goboringcrypto_SHA1_Init(&ctx); + return _goboringcrypto_SHA1_Update(&ctx, p, n) && + _goboringcrypto_SHA1_Final(out, &ctx); +} +int +_goboringcrypto_gosha224(void *p, size_t n, void *out) +{ + GO_SHA256_CTX ctx; + _goboringcrypto_SHA224_Init(&ctx); + return _goboringcrypto_SHA224_Update(&ctx, p, n) && + _goboringcrypto_SHA224_Final(out, &ctx); +} +int +_goboringcrypto_gosha256(void *p, size_t n, void *out) +{ + GO_SHA256_CTX ctx; + _goboringcrypto_SHA256_Init(&ctx); + return _goboringcrypto_SHA256_Update(&ctx, p, n) && + _goboringcrypto_SHA256_Final(out, &ctx); +} +int +_goboringcrypto_gosha384(void *p, size_t n, void *out) +{ + GO_SHA512_CTX ctx; + _goboringcrypto_SHA384_Init(&ctx); + return _goboringcrypto_SHA384_Update(&ctx, p, n) && + _goboringcrypto_SHA384_Final(out, &ctx); +} +int +_goboringcrypto_gosha512(void *p, size_t n, void *out) +{ + GO_SHA512_CTX ctx; + _goboringcrypto_SHA512_Init(&ctx); + return _goboringcrypto_SHA512_Update(&ctx, p, n) && + _goboringcrypto_SHA512_Final(out, &ctx); +} +*/ +import "C" +import ( + "errors" + "hash" + "unsafe" +) + +// NOTE: The cgo calls in this file are arranged to avoid marking the parameters as escaping. +// To do that, we call noescape (including via addr). +// We must also make sure that the data pointer arguments have the form unsafe.Pointer(&...) +// so that cgo does not annotate them with cgoCheckPointer calls. If it did that, it might look +// beyond the byte slice and find Go pointers in unprocessed parts of a larger allocation. +// To do both of these simultaneously, the idiom is unsafe.Pointer(&*addr(p)), +// where addr returns the base pointer of p, substituting a non-nil pointer for nil, +// and applying a noescape along the way. +// This is all to preserve compatibility with the allocation behavior of the non-boring implementations. + +func SHA1(p []byte) (sum [20]byte) { + if C._goboringcrypto_gosha1(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 { + panic("boringcrypto: SHA1 failed") + } + return +} + +func SHA224(p []byte) (sum [28]byte) { + if C._goboringcrypto_gosha224(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 { + panic("boringcrypto: SHA224 failed") + } + return +} + +func SHA256(p []byte) (sum [32]byte) { + if C._goboringcrypto_gosha256(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 { + panic("boringcrypto: SHA256 failed") + } + return +} + +func SHA384(p []byte) (sum [48]byte) { + if C._goboringcrypto_gosha384(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 { + panic("boringcrypto: SHA384 failed") + } + return +} + +func SHA512(p []byte) (sum [64]byte) { + if C._goboringcrypto_gosha512(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 { + panic("boringcrypto: SHA512 failed") + } + return +} + +// 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 +) + +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) +}