aboutsummaryrefslogtreecommitdiff
path: root/src/crypto/internal
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2022-08-16 10:37:49 -0400
committerGopher Robot <gobot@golang.org>2022-11-11 01:42:03 +0000
commitd62f8d5f2becb765c6c6947bfc1858ced43c1cbb (patch)
treeb649bdcedfd31db39463cf68da71937ccc095983 /src/crypto/internal
parentffc4496306a93a5d95abd6b1ec7bb81ca02c0026 (diff)
downloadgo-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.go4
-rwxr-xr-xsrc/crypto/internal/boring/build-goboring.sh8
-rw-r--r--src/crypto/internal/boring/ecdh.go224
-rw-r--r--src/crypto/internal/boring/goboringcrypto.h16
-rw-r--r--src/crypto/internal/boring/notboring.go10
-rw-r--r--src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.sysobin2555552 -> 2555664 bytes
-rw-r--r--src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.sysobin1980184 -> 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
index fd982bff9d..6cea789355 100644
--- a/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso
+++ b/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso
Binary files differ
diff --git a/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso b/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso
index 46520b7592..9659aa1a5e 100644
--- a/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso
+++ b/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso
Binary files differ