ecdsa.mx raw

   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 := []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