Source file src/crypto/internal/boring/ecdsa.go

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build boringcrypto && linux && (amd64 || arm64) && !android && !msan
     6  
     7  package boring
     8  
     9  // #include "goboringcrypto.h"
    10  import "C"
    11  import (
    12  	"errors"
    13  	"runtime"
    14  )
    15  
    16  type ecdsaSignature struct {
    17  	R, S BigInt
    18  }
    19  
    20  type PrivateKeyECDSA struct {
    21  	key *C.GO_EC_KEY
    22  }
    23  
    24  func (k *PrivateKeyECDSA) finalize() {
    25  	C._goboringcrypto_EC_KEY_free(k.key)
    26  }
    27  
    28  type PublicKeyECDSA struct {
    29  	key *C.GO_EC_KEY
    30  }
    31  
    32  func (k *PublicKeyECDSA) finalize() {
    33  	C._goboringcrypto_EC_KEY_free(k.key)
    34  }
    35  
    36  var errUnknownCurve = errors.New("boringcrypto: unknown elliptic curve")
    37  
    38  func curveNID(curve string) (C.int, error) {
    39  	switch curve {
    40  	case "P-224":
    41  		return C.GO_NID_secp224r1, nil
    42  	case "P-256":
    43  		return C.GO_NID_X9_62_prime256v1, nil
    44  	case "P-384":
    45  		return C.GO_NID_secp384r1, nil
    46  	case "P-521":
    47  		return C.GO_NID_secp521r1, nil
    48  	}
    49  	return 0, errUnknownCurve
    50  }
    51  
    52  func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) {
    53  	key, err := newECKey(curve, X, Y)
    54  	if err != nil {
    55  		return nil, err
    56  	}
    57  	k := &PublicKeyECDSA{key}
    58  	// Note: Because of the finalizer, any time k.key is passed to cgo,
    59  	// that call must be followed by a call to runtime.KeepAlive(k),
    60  	// to make sure k is not collected (and finalized) before the cgo
    61  	// call returns.
    62  	runtime.SetFinalizer(k, (*PublicKeyECDSA).finalize)
    63  	return k, nil
    64  }
    65  
    66  func newECKey(curve string, X, Y BigInt) (*C.GO_EC_KEY, error) {
    67  	nid, err := curveNID(curve)
    68  	if err != nil {
    69  		return nil, err
    70  	}
    71  	key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
    72  	if key == nil {
    73  		return nil, fail("EC_KEY_new_by_curve_name")
    74  	}
    75  	group := C._goboringcrypto_EC_KEY_get0_group(key)
    76  	pt := C._goboringcrypto_EC_POINT_new(group)
    77  	if pt == nil {
    78  		C._goboringcrypto_EC_KEY_free(key)
    79  		return nil, fail("EC_POINT_new")
    80  	}
    81  	bx := bigToBN(X)
    82  	by := bigToBN(Y)
    83  	ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 &&
    84  		C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0
    85  	if bx != nil {
    86  		C._goboringcrypto_BN_free(bx)
    87  	}
    88  	if by != nil {
    89  		C._goboringcrypto_BN_free(by)
    90  	}
    91  	C._goboringcrypto_EC_POINT_free(pt)
    92  	if !ok {
    93  		C._goboringcrypto_EC_KEY_free(key)
    94  		return nil, fail("EC_POINT_set_affine_coordinates_GFp")
    95  	}
    96  	return key, nil
    97  }
    98  
    99  func NewPrivateKeyECDSA(curve string, X, Y BigInt, D BigInt) (*PrivateKeyECDSA, error) {
   100  	key, err := newECKey(curve, X, Y)
   101  	if err != nil {
   102  		return nil, err
   103  	}
   104  	bd := bigToBN(D)
   105  	ok := bd != nil && C._goboringcrypto_EC_KEY_set_private_key(key, bd) != 0
   106  	if bd != nil {
   107  		C._goboringcrypto_BN_free(bd)
   108  	}
   109  	if !ok {
   110  		C._goboringcrypto_EC_KEY_free(key)
   111  		return nil, fail("EC_KEY_set_private_key")
   112  	}
   113  	k := &PrivateKeyECDSA{key}
   114  	// Note: Because of the finalizer, any time k.key is passed to cgo,
   115  	// that call must be followed by a call to runtime.KeepAlive(k),
   116  	// to make sure k is not collected (and finalized) before the cgo
   117  	// call returns.
   118  	runtime.SetFinalizer(k, (*PrivateKeyECDSA).finalize)
   119  	return k, nil
   120  }
   121  
   122  func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
   123  	size := C._goboringcrypto_ECDSA_size(priv.key)
   124  	sig := make([]byte, size)
   125  	var sigLen C.uint
   126  	if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), base(sig), &sigLen, priv.key) == 0 {
   127  		return nil, fail("ECDSA_sign")
   128  	}
   129  	runtime.KeepAlive(priv)
   130  	return sig[:sigLen], nil
   131  }
   132  
   133  func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool {
   134  	ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), base(sig), C.size_t(len(sig)), pub.key) != 0
   135  	runtime.KeepAlive(pub)
   136  	return ok
   137  }
   138  
   139  func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) {
   140  	nid, err := curveNID(curve)
   141  	if err != nil {
   142  		return nil, nil, nil, err
   143  	}
   144  	key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
   145  	if key == nil {
   146  		return nil, nil, nil, fail("EC_KEY_new_by_curve_name")
   147  	}
   148  	defer C._goboringcrypto_EC_KEY_free(key)
   149  	if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
   150  		return nil, nil, nil, fail("EC_KEY_generate_key_fips")
   151  	}
   152  	group := C._goboringcrypto_EC_KEY_get0_group(key)
   153  	pt := C._goboringcrypto_EC_KEY_get0_public_key(key)
   154  	bd := C._goboringcrypto_EC_KEY_get0_private_key(key)
   155  	if pt == nil || bd == nil {
   156  		return nil, nil, nil, fail("EC_KEY_get0_private_key")
   157  	}
   158  	bx := C._goboringcrypto_BN_new()
   159  	if bx == nil {
   160  		return nil, nil, nil, fail("BN_new")
   161  	}
   162  	defer C._goboringcrypto_BN_free(bx)
   163  	by := C._goboringcrypto_BN_new()
   164  	if by == nil {
   165  		return nil, nil, nil, fail("BN_new")
   166  	}
   167  	defer C._goboringcrypto_BN_free(by)
   168  	if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 {
   169  		return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp")
   170  	}
   171  	return bnToBig(bx), bnToBig(by), bnToBig(bd), nil
   172  }
   173  

View as plain text