diff options
| author | Russ Cox <rsc@golang.org> | 2022-08-16 10:37:49 -0400 |
|---|---|---|
| committer | Gopher Robot <gobot@golang.org> | 2022-11-11 01:42:03 +0000 |
| commit | d62f8d5f2becb765c6c6947bfc1858ced43c1cbb (patch) | |
| tree | b649bdcedfd31db39463cf68da71937ccc095983 /src/crypto/internal | |
| parent | ffc4496306a93a5d95abd6b1ec7bb81ca02c0026 (diff) | |
| download | go-d62f8d5f2becb765c6c6947bfc1858ced43c1cbb.tar.xz | |
crypto/ecdh: add boringcrypto support
Update crypto/ecdh to use boringcrypto when enabled.
Change-Id: Idd0ce06a22b1a62289b383c46893800621c7d97b
Reviewed-on: https://go-review.googlesource.com/c/go/+/423363
Run-TryBot: Russ Cox <rsc@golang.org>
Auto-Submit: Russ Cox <rsc@golang.org>
Reviewed-by: Cherry Mui <cherryyz@google.com>
Reviewed-by: Filippo Valsorda <filippo@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Diffstat (limited to 'src/crypto/internal')
| -rw-r--r-- | src/crypto/internal/boring/boring.go | 4 | ||||
| -rwxr-xr-x | src/crypto/internal/boring/build-goboring.sh | 8 | ||||
| -rw-r--r-- | src/crypto/internal/boring/ecdh.go | 224 | ||||
| -rw-r--r-- | src/crypto/internal/boring/goboringcrypto.h | 16 | ||||
| -rw-r--r-- | src/crypto/internal/boring/notboring.go | 10 | ||||
| -rw-r--r-- | src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso | bin | 2555552 -> 2555664 bytes | |||
| -rw-r--r-- | src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso | bin | 1980184 -> 1980296 bytes |
7 files changed, 260 insertions, 2 deletions
diff --git a/src/crypto/internal/boring/boring.go b/src/crypto/internal/boring/boring.go index d6b8e37b72..7ea438d3a7 100644 --- a/src/crypto/internal/boring/boring.go +++ b/src/crypto/internal/boring/boring.go @@ -71,6 +71,10 @@ func bigToBN(x BigInt) *C.GO_BIGNUM { return C._goboringcrypto_BN_le2bn(wbase(x), C.size_t(len(x)*wordBytes), nil) } +func bytesToBN(x []byte) *C.GO_BIGNUM { + return C._goboringcrypto_BN_bin2bn((*C.uint8_t)(&x[0]), C.size_t(len(x)), 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 { diff --git a/src/crypto/internal/boring/build-goboring.sh b/src/crypto/internal/boring/build-goboring.sh index 5c0b74e074..4938b5eac3 100755 --- a/src/crypto/internal/boring/build-goboring.sh +++ b/src/crypto/internal/boring/build-goboring.sh @@ -55,7 +55,7 @@ BEGIN { /\/\*unchecked/ { next } # Check enum values. -!enum && $1 == "enum" && $NF == "{" { +!enum && ($1 == "enum" || $2 == "enum") && $NF == "{" { enum = 1 next } @@ -63,6 +63,10 @@ enum && $1 == "};" { enum = 0 next } +enum && /^}.*;$/ { + enum = 0 + next +} enum && NF == 3 && $2 == "=" { name = $1 sub(/^GO_/, "", name) @@ -111,7 +115,7 @@ EOF cat >boringh.awk <<'EOF' /^\/\/ #include/ {sub(/\/\//, ""); print > "goboringcrypto0.h"; next} /typedef struct|enum ([a-z_]+ )?{|^[ \t]/ {print >"goboringcrypto1.h";next} -{gsub(/GO_/, ""); gsub(/enum go_/, "enum "); print >"goboringcrypto1.h"} +{gsub(/GO_/, ""); gsub(/enum go_/, "enum "); gsub(/go_point_conv/, "point_conv"); print >"goboringcrypto1.h"} EOF awk -f boringx.awk goboringcrypto.h # writes goboringcrypto.x diff --git a/src/crypto/internal/boring/ecdh.go b/src/crypto/internal/boring/ecdh.go new file mode 100644 index 0000000000..8f46d8146f --- /dev/null +++ b/src/crypto/internal/boring/ecdh.go @@ -0,0 +1,224 @@ +// 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. + +//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan + +package boring + +// #include "goboringcrypto.h" +import "C" +import ( + "errors" + "runtime" + "unsafe" +) + +type PublicKeyECDH struct { + curve string + key *C.GO_EC_POINT + group *C.GO_EC_GROUP + bytes []byte +} + +func (k *PublicKeyECDH) finalize() { + C._goboringcrypto_EC_POINT_free(k.key) +} + +type PrivateKeyECDH struct { + curve string + key *C.GO_EC_KEY +} + +func (k *PrivateKeyECDH) finalize() { + C._goboringcrypto_EC_KEY_free(k.key) +} + +func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) { + if len(bytes) < 1 { + return nil, errors.New("NewPublicKeyECDH: missing key") + } + + nid, err := curveNID(curve) + if err != nil { + return nil, err + } + + group := C._goboringcrypto_EC_GROUP_new_by_curve_name(nid) + if group == nil { + return nil, fail("EC_GROUP_new_by_curve_name") + } + defer C._goboringcrypto_EC_GROUP_free(group) + key := C._goboringcrypto_EC_POINT_new(group) + if key == nil { + return nil, fail("EC_POINT_new") + } + ok := C._goboringcrypto_EC_POINT_oct2point(group, key, (*C.uint8_t)(unsafe.Pointer(&bytes[0])), C.size_t(len(bytes)), nil) != 0 + if !ok { + C._goboringcrypto_EC_POINT_free(key) + return nil, errors.New("point not on curve") + } + + k := &PublicKeyECDH{curve, key, group, append([]byte(nil), bytes...)} + // 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 (k *PublicKeyECDH) Bytes() []byte { return k.bytes } + +func NewPrivateKeyECDH(curve string, bytes []byte) (*PrivateKeyECDH, error) { + nid, err := curveNID(curve) + if err != nil { + return nil, err + } + key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid) + if key == nil { + return nil, fail("EC_KEY_new_by_curve_name") + } + b := bytesToBN(bytes) + ok := b != nil && C._goboringcrypto_EC_KEY_set_private_key(key, b) != 0 + if b != nil { + C._goboringcrypto_BN_free(b) + } + if !ok { + C._goboringcrypto_EC_KEY_free(key) + return nil, fail("EC_KEY_set_private_key") + } + k := &PrivateKeyECDH{curve, key} + // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. + runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize) + return k, nil +} + +func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { + defer runtime.KeepAlive(k) + + group := C._goboringcrypto_EC_KEY_get0_group(k.key) + if group == nil { + return nil, fail("EC_KEY_get0_group") + } + kbig := C._goboringcrypto_EC_KEY_get0_private_key(k.key) + if kbig == nil { + return nil, fail("EC_KEY_get0_private_key") + } + pt := C._goboringcrypto_EC_POINT_new(group) + if pt == nil { + return nil, fail("EC_POINT_new") + } + if C._goboringcrypto_EC_POINT_mul(group, pt, kbig, nil, nil, nil) == 0 { + C._goboringcrypto_EC_POINT_free(pt) + return nil, fail("EC_POINT_mul") + } + bytes, err := pointBytesECDH(k.curve, group, pt) + if err != nil { + C._goboringcrypto_EC_POINT_free(pt) + return nil, err + } + pub := &PublicKeyECDH{k.curve, pt, group, bytes} + // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. + runtime.SetFinalizer(pub, (*PublicKeyECDH).finalize) + return pub, nil +} + +func pointBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) { + out := make([]byte, 1+2*curveSize(curve)) + n := C._goboringcrypto_EC_POINT_point2oct(group, pt, C.GO_POINT_CONVERSION_UNCOMPRESSED, (*C.uint8_t)(unsafe.Pointer(&out[0])), C.size_t(len(out)), nil) + if int(n) != len(out) { + return nil, fail("EC_POINT_point2oct") + } + return out, nil +} + +func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) { + group := C._goboringcrypto_EC_KEY_get0_group(priv.key) + if group == nil { + return nil, fail("EC_KEY_get0_group") + } + privBig := C._goboringcrypto_EC_KEY_get0_private_key(priv.key) + if privBig == nil { + return nil, fail("EC_KEY_get0_private_key") + } + pt := C._goboringcrypto_EC_POINT_new(group) + if pt == nil { + return nil, fail("EC_POINT_new") + } + defer C._goboringcrypto_EC_POINT_free(pt) + if C._goboringcrypto_EC_POINT_mul(group, pt, nil, pub.key, privBig, nil) == 0 { + return nil, fail("EC_POINT_mul") + } + out, err := xCoordBytesECDH(priv.curve, group, pt) + if err != nil { + return nil, err + } + return out, nil +} + +func xCoordBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) { + big := C._goboringcrypto_BN_new() + defer C._goboringcrypto_BN_free(big) + if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, big, nil, nil) == 0 { + return nil, fail("EC_POINT_get_affine_coordinates_GFp") + } + return bigBytesECDH(curve, big) +} + +func bigBytesECDH(curve string, big *C.GO_BIGNUM) ([]byte, error) { + out := make([]byte, curveSize(curve)) + if C._goboringcrypto_BN_bn2bin_padded((*C.uint8_t)(&out[0]), C.size_t(len(out)), big) == 0 { + return nil, fail("BN_bn2bin_padded") + } + return out, nil +} + +func curveSize(curve string) int { + switch curve { + default: + panic("crypto/internal/boring: unknown curve " + curve) + case "P-256": + return 256 / 8 + case "P-384": + return 384 / 8 + case "P-521": + return (521 + 7) / 8 + } +} + +func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) { + nid, err := curveNID(curve) + if err != nil { + return nil, nil, err + } + key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid) + if key == nil { + return nil, nil, fail("EC_KEY_new_by_curve_name") + } + if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 { + C._goboringcrypto_EC_KEY_free(key) + return nil, nil, fail("EC_KEY_generate_key_fips") + } + + group := C._goboringcrypto_EC_KEY_get0_group(key) + if group == nil { + C._goboringcrypto_EC_KEY_free(key) + return nil, nil, fail("EC_KEY_get0_group") + } + b := C._goboringcrypto_EC_KEY_get0_private_key(key) + if b == nil { + C._goboringcrypto_EC_KEY_free(key) + return nil, nil, fail("EC_KEY_get0_private_key") + } + bytes, err := bigBytesECDH(curve, b) + if err != nil { + C._goboringcrypto_EC_KEY_free(key) + return nil, nil, err + } + + k := &PrivateKeyECDH{curve, key} + // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive. + runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize) + return k, bytes, nil +} diff --git a/src/crypto/internal/boring/goboringcrypto.h b/src/crypto/internal/boring/goboringcrypto.h index a5f4e0aac2..2b11049728 100644 --- a/src/crypto/internal/boring/goboringcrypto.h +++ b/src/crypto/internal/boring/goboringcrypto.h @@ -144,6 +144,7 @@ GO_BIGNUM* _goboringcrypto_BN_bin2bn(const uint8_t*, size_t, GO_BIGNUM*); GO_BIGNUM* _goboringcrypto_BN_le2bn(const uint8_t*, size_t, GO_BIGNUM*); size_t _goboringcrypto_BN_bn2bin(const GO_BIGNUM*, uint8_t*); int _goboringcrypto_BN_bn2le_padded(uint8_t*, size_t, const GO_BIGNUM*); +int _goboringcrypto_BN_bn2bin_padded(uint8_t*, size_t, const GO_BIGNUM*); // #include <openssl/ec.h> /*unchecked (opaque)*/ typedef struct GO_EC_GROUP { char data[1]; } GO_EC_GROUP; @@ -152,9 +153,21 @@ void _goboringcrypto_EC_GROUP_free(GO_EC_GROUP*); /*unchecked (opaque)*/ typedef struct GO_EC_POINT { char data[1]; } GO_EC_POINT; GO_EC_POINT* _goboringcrypto_EC_POINT_new(const GO_EC_GROUP*); +int _goboringcrypto_EC_POINT_mul(const GO_EC_GROUP*, GO_EC_POINT*, const GO_BIGNUM*, const GO_EC_POINT*, const GO_BIGNUM*, GO_BN_CTX*); void _goboringcrypto_EC_POINT_free(GO_EC_POINT*); int _goboringcrypto_EC_POINT_get_affine_coordinates_GFp(const GO_EC_GROUP*, const GO_EC_POINT*, GO_BIGNUM*, GO_BIGNUM*, GO_BN_CTX*); int _goboringcrypto_EC_POINT_set_affine_coordinates_GFp(const GO_EC_GROUP*, GO_EC_POINT*, const GO_BIGNUM*, const GO_BIGNUM*, GO_BN_CTX*); +int _goboringcrypto_EC_POINT_oct2point(const GO_EC_GROUP*, GO_EC_POINT*, const uint8_t*, size_t, GO_BN_CTX*); +GO_EC_POINT* _goboringcrypto_EC_POINT_dup(const GO_EC_POINT*, const GO_EC_GROUP*); +int _goboringcrypto_EC_POINT_is_on_curve(const GO_EC_GROUP*, const GO_EC_POINT*, GO_BN_CTX*); +#ifndef OPENSSL_HEADER_EC_H +typedef enum { + GO_POINT_CONVERSION_COMPRESSED = 2, + GO_POINT_CONVERSION_UNCOMPRESSED = 4, + GO_POINT_CONVERSION_HYBRID = 6, +} go_point_conversion_form_t; +#endif +size_t _goboringcrypto_EC_POINT_point2oct(const GO_EC_GROUP*, const GO_EC_POINT*, go_point_conversion_form_t, uint8_t*, size_t, GO_BN_CTX*); // #include <openssl/ec_key.h> /*unchecked (opaque)*/ typedef struct GO_EC_KEY { char data[1]; } GO_EC_KEY; @@ -170,6 +183,9 @@ const GO_BIGNUM* _goboringcrypto_EC_KEY_get0_private_key(const GO_EC_KEY*); const GO_EC_POINT* _goboringcrypto_EC_KEY_get0_public_key(const GO_EC_KEY*); // TODO: EC_KEY_check_fips? +// #include <openssl/ecdh.h> +int _goboringcrypto_ECDH_compute_key_fips(uint8_t*, size_t, const GO_EC_POINT*, const GO_EC_KEY*); + // #include <openssl/ecdsa.h> typedef struct GO_ECDSA_SIG { char data[16]; } GO_ECDSA_SIG; GO_ECDSA_SIG* _goboringcrypto_ECDSA_SIG_new(void); diff --git a/src/crypto/internal/boring/notboring.go b/src/crypto/internal/boring/notboring.go index 2fa5eaf30f..1c5e4c742d 100644 --- a/src/crypto/internal/boring/notboring.go +++ b/src/crypto/internal/boring/notboring.go @@ -110,3 +110,13 @@ func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) err func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error { panic("boringcrypto: not available") } + +type PublicKeyECDH struct{} +type PrivateKeyECDH struct{} + +func ECDH(*PrivateKeyECDH, *PublicKeyECDH) ([]byte, error) { panic("boringcrypto: not available") } +func GenerateKeyECDH(string) (*PrivateKeyECDH, []byte, error) { panic("boringcrypto: not available") } +func NewPrivateKeyECDH(string, []byte) (*PrivateKeyECDH, error) { panic("boringcrypto: not available") } +func NewPublicKeyECDH(string, []byte) (*PublicKeyECDH, error) { panic("boringcrypto: not available") } +func (*PublicKeyECDH) Bytes() []byte { panic("boringcrypto: not available") } +func (*PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { panic("boringcrypto: not available") } diff --git a/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso b/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso Binary files differindex fd982bff9d..6cea789355 100644 --- a/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso +++ b/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso diff --git a/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso b/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso Binary files differindex 46520b7592..9659aa1a5e 100644 --- a/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso +++ b/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso |
