summaryrefslogtreecommitdiffstats
path: root/src/crypto/internal/boring/ecdsa.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 19:23:18 +0000
commit43a123c1ae6613b3efeed291fa552ecd909d3acf (patch)
treefd92518b7024bc74031f78a1cf9e454b65e73665 /src/crypto/internal/boring/ecdsa.go
parentInitial commit. (diff)
downloadgolang-1.20-upstream.tar.xz
golang-1.20-upstream.zip
Adding upstream version 1.20.14.upstream/1.20.14upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/crypto/internal/boring/ecdsa.go')
-rw-r--r--src/crypto/internal/boring/ecdsa.go172
1 files changed, 172 insertions, 0 deletions
diff --git a/src/crypto/internal/boring/ecdsa.go b/src/crypto/internal/boring/ecdsa.go
new file mode 100644
index 0000000..e15f368
--- /dev/null
+++ b/src/crypto/internal/boring/ecdsa.go
@@ -0,0 +1,172 @@
+// 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 boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "errors"
+ "runtime"
+)
+
+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")
+
+func curveNID(curve string) (C.int, error) {
+ switch curve {
+ case "P-224":
+ return C.GO_NID_secp224r1, nil
+ case "P-256":
+ return C.GO_NID_X9_62_prime256v1, nil
+ case "P-384":
+ return C.GO_NID_secp384r1, nil
+ case "P-521":
+ return C.GO_NID_secp521r1, nil
+ }
+ return 0, errUnknownCurve
+}
+
+func NewPublicKeyECDSA(curve string, X, Y 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, fail("EC_KEY_new_by_curve_name")
+ }
+ group := C._goboringcrypto_EC_KEY_get0_group(key)
+ pt := C._goboringcrypto_EC_POINT_new(group)
+ if pt == nil {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_POINT_new")
+ }
+ bx := bigToBN(X)
+ by := bigToBN(Y)
+ ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 &&
+ C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0
+ if bx != nil {
+ C._goboringcrypto_BN_free(bx)
+ }
+ if by != nil {
+ C._goboringcrypto_BN_free(by)
+ }
+ C._goboringcrypto_EC_POINT_free(pt)
+ if !ok {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_POINT_set_affine_coordinates_GFp")
+ }
+ return key, nil
+}
+
+func NewPrivateKeyECDSA(curve string, X, Y 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, fail("EC_KEY_set_private_key")
+ }
+ k := &PrivateKeyECDSA{key}
+ // Note: Because of the finalizer, any time k.key is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(k),
+ // to make sure k is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(k, (*PrivateKeyECDSA).finalize)
+ return k, nil
+}
+
+func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
+ size := C._goboringcrypto_ECDSA_size(priv.key)
+ sig := make([]byte, size)
+ var sigLen C.uint
+ if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), base(sig), &sigLen, priv.key) == 0 {
+ return nil, fail("ECDSA_sign")
+ }
+ runtime.KeepAlive(priv)
+ return sig[:sigLen], nil
+}
+
+func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool {
+ ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), base(sig), C.size_t(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, fail("EC_KEY_new_by_curve_name")
+ }
+ defer C._goboringcrypto_EC_KEY_free(key)
+ if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
+ return nil, nil, nil, fail("EC_KEY_generate_key_fips")
+ }
+ group := C._goboringcrypto_EC_KEY_get0_group(key)
+ pt := C._goboringcrypto_EC_KEY_get0_public_key(key)
+ bd := C._goboringcrypto_EC_KEY_get0_private_key(key)
+ if pt == nil || bd == nil {
+ return nil, nil, nil, fail("EC_KEY_get0_private_key")
+ }
+ bx := C._goboringcrypto_BN_new()
+ if bx == nil {
+ return nil, nil, nil, fail("BN_new")
+ }
+ defer C._goboringcrypto_BN_free(bx)
+ by := C._goboringcrypto_BN_new()
+ if by == nil {
+ return nil, nil, nil, fail("BN_new")
+ }
+ defer C._goboringcrypto_BN_free(by)
+ if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 {
+ return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp")
+ }
+ return bnToBig(bx), bnToBig(by), bnToBig(bd), nil
+}