diff --git a/vlib/crypto/ecdsa/ecdsa.c.v b/vlib/crypto/ecdsa/ecdsa.c.v index 4e155606cf..5720322b53 100644 --- a/vlib/crypto/ecdsa/ecdsa.c.v +++ b/vlib/crypto/ecdsa/ecdsa.c.v @@ -18,10 +18,14 @@ module ecdsa #include #include #include +#include #include #include #include +// The following header is available on OpenSSL 3.0, but not in OpenSSL 1.1.1f +//#include + // The new opaque of public key pair high level API @[typedef] struct C.EVP_PKEY {} @@ -73,6 +77,8 @@ fn C.BIO_write(b &C.BIO, buf &u8, length int) int fn C.PEM_read_bio_PrivateKey(bp &C.BIO, x &&C.EVP_PKEY, cb int, u &voidptr) &C.EVP_PKEY fn C.PEM_read_bio_PUBKEY(bp &C.BIO, x &&C.EVP_PKEY, cb int, u &voidptr) &C.EVP_PKEY fn C.d2i_PUBKEY(k &&C.EVP_PKEY, pp &&u8, length u32) &C.EVP_PKEY +fn C.i2d_PUBKEY_bio(bo &C.BIO, pkey &C.EVP_PKEY) int +fn C.d2i_PUBKEY_bio(bo &C.BIO, key &&C.EVP_PKEY) &C.EVP_PKEY // Elliptic curve point related declarations. @[typedef] diff --git a/vlib/crypto/ecdsa/ecdsa.v b/vlib/crypto/ecdsa/ecdsa.v index ce1e36513e..0fe198e79c 100644 --- a/vlib/crypto/ecdsa/ecdsa.v +++ b/vlib/crypto/ecdsa/ecdsa.v @@ -81,58 +81,18 @@ enum KeyFlag { // generate_key generates a new key pair. If opt was not provided, its default to prime256v1 curve. // If you want another curve, use in the following manner: `pubkey, pivkey := ecdsa.generate_key(nid: .secp384r1)!` pub fn generate_key(opt CurveOptions) !(PublicKey, PrivateKey) { - // creates new empty key - ec_key := new_curve(opt) - if ec_key == 0 { - C.EC_KEY_free(ec_key) - return error('Failed to create new EC_KEY') - } - // we duplicate the empty ec_key and shares similiar curve infos - // and used this as public key - pbkey := C.EC_KEY_dup(ec_key) - if pbkey == 0 { - C.EC_KEY_free(ec_key) - C.EC_KEY_free(pbkey) - return error('Failed on EC_KEY_dup') - } - res := C.EC_KEY_generate_key(ec_key) - if res != 1 { - C.EC_KEY_free(ec_key) - C.EC_KEY_free(pbkey) - return error('Failed to generate EC_KEY') - } - // we take public key bits from above generated key - // and stored in duplicated public key object before. - pubkey_point := voidptr(C.EC_KEY_get0_public_key(ec_key)) - if pubkey_point == 0 { - C.EC_POINT_free(pubkey_point) - C.EC_KEY_free(ec_key) - C.EC_KEY_free(pbkey) - return error('Failed to get public key BIGNUM') - } - np := C.EC_KEY_set_public_key(pbkey, pubkey_point) - if np != 1 { - C.EC_POINT_free(pubkey_point) - C.EC_KEY_free(ec_key) - C.EC_KEY_free(pbkey) - return error('Failed to set public key') - } - // when using default generate_key, its using underlying curve key size - // and discarded opt.fixed_size flag when its not set. - priv_key := PrivateKey{ - key: ec_key - ks_flag: .fixed - } - pub_key := PublicKey{ - key: pbkey - } - return pub_key, priv_key + // This can be simplified to just more simpler one + pv := PrivateKey.new(opt)! + pb := pv.public_key()! + + return pb, pv } // new_key_from_seed creates a new private key from the seed bytes. If opt was not provided, // its default to prime256v1 curve. // // Notes on the seed: +// // You should make sure, the seed bytes come from a cryptographically secure random generator, // likes the `crypto.rand` or other trusted sources. // Internally, the seed size's would be checked to not exceed the key size of underlying curve, @@ -366,16 +326,17 @@ fn (priv_key PrivateKey) sign_message(message []u8) ![]u8 { } // bytes represent private key as bytes. -pub fn (priv_key PrivateKey) bytes() ![]u8 { - bn := voidptr(C.EC_KEY_get0_private_key(priv_key.key)) +pub fn (pv PrivateKey) bytes() ![]u8 { + // This is the old one + bn := voidptr(C.EC_KEY_get0_private_key(pv.key)) if bn == 0 { return error('Failed to get private key BIGNUM') } num_bytes := (C.BN_num_bits(bn) + 7) / 8 // Get the buffer size to store the seed. - size := if priv_key.ks_flag == .flexible { + size := if pv.ks_flag == .flexible { // should be non zero - priv_key.ks_size + pv.ks_size } else { num_bytes } @@ -390,19 +351,46 @@ pub fn (priv_key PrivateKey) bytes() ![]u8 { // seed gets the seed (private key bytes). It will be deprecated. // Use `PrivateKey.bytes()` instead. @[deprecated: 'use PrivateKey.bytes() instead'] -pub fn (priv_key PrivateKey) seed() ![]u8 { - return priv_key.bytes() +pub fn (pv PrivateKey) seed() ![]u8 { + return pv.bytes() } -// Get the public key from private key. -pub fn (priv_key PrivateKey) public_key() !PublicKey { +// public_key gets the PublicKey from private key. +pub fn (pv PrivateKey) public_key() !PublicKey { + // Check if EVP_PKEY opaque was availables or not. + // TODO: removes this check when its ready + if pv.evpkey != unsafe { nil } { + bo := C.BIO_new(C.BIO_s_mem()) + n := C.i2d_PUBKEY_bio(bo, pv.evpkey) + assert n != 0 + // stores this bio as another key + pbkey := C.d2i_PUBKEY_bio(bo, 0) + + // TODO: removes this when its ready to obsolete. + eckey := C.EVP_PKEY_get1_EC_KEY(pbkey) + if eckey == 0 { + C.EC_KEY_free(eckey) + C.EVP_PKEY_free(pbkey) + C.BIO_free_all(bo) + return error('EVP_PKEY_get1_EC_KEY failed') + } + C.BIO_free_all(bo) + + return PublicKey{ + evpkey: pbkey + key: eckey + } + } + // Otherwise, use the old EC_KEY opaque. + // TODO: removes this when its ready to obsolete + // // There are some issues concerned when returning PublicKey directly using underlying // `PrivateKey.key`. This private key containing sensitive information inside it, so return // this without care maybe can lead to some serious security impact. // See https://discord.com/channels/592103645835821068/592320321995014154/1329261267965448253 // So, we instead return a new EC_KEY opaque based information availables on private key object // without private key bits has been set on this new opaque. - group := voidptr(C.EC_KEY_get0_group(priv_key.key)) + group := voidptr(C.EC_KEY_get0_group(pv.key)) if group == 0 { return error('Failed to load group from priv_key') } @@ -411,7 +399,7 @@ pub fn (priv_key PrivateKey) public_key() !PublicKey { return error('Get unsupported curve nid') } // get public key point from private key opaque - pubkey_point := voidptr(C.EC_KEY_get0_public_key(priv_key.key)) + pubkey_point := voidptr(C.EC_KEY_get0_public_key(pv.key)) if pubkey_point == 0 { // C.EC_POINT_free(pubkey_point) // todo: maybe its not set, just calculates new one @@ -652,8 +640,3 @@ fn calc_digest(key &C.EC_KEY, message []u8, opt SignerOpts) ![]u8 { } return error('Not should be here') } - -// Clear allocated memory for key -fn key_free(ec_key &C.EC_KEY) { - C.EC_KEY_free(ec_key) -} diff --git a/vlib/crypto/ecdsa/ecdsa_test.v b/vlib/crypto/ecdsa/ecdsa_test.v index 74536fec51..bb4ccbc1e7 100644 --- a/vlib/crypto/ecdsa/ecdsa_test.v +++ b/vlib/crypto/ecdsa/ecdsa_test.v @@ -12,8 +12,9 @@ fn test_ecdsa() { is_valid := pub_key.verify(message, signature) or { panic(err) } println('Signature valid: ${is_valid}') assert is_valid - key_free(priv_key.key) - key_free(pub_key.key) + + priv_key.free() + pub_key.free() } fn test_ecdsa_signing_with_recommended_hash_options() { @@ -27,9 +28,9 @@ fn test_ecdsa_signing_with_recommended_hash_options() { // Verify the signature is_valid := pub_key.verify(message, signature) or { panic(err) } println('Signature valid: ${is_valid}') - key_free(pub_key.key) - key_free(priv_key.key) assert is_valid + pub_key.free() + priv_key.free() } fn test_generate_key() ! { @@ -37,26 +38,27 @@ fn test_generate_key() ! { pub_key, priv_key := generate_key() or { panic(err) } assert pub_key.key != unsafe { nil } assert priv_key.key != unsafe { nil } - key_free(priv_key.key) - key_free(pub_key.key) + + priv_key.free() + pub_key.free() } fn test_new_key_from_seed() ! { // Test generating a key from a seed seed := [u8(1), 2, 3, 4, 5] priv_key := new_key_from_seed(seed) or { panic(err) } - retrieved_seed := priv_key.seed() or { panic(err) } + retrieved_seed := priv_key.bytes() or { panic(err) } assert seed == retrieved_seed - key_free(priv_key.key) + priv_key.free() } fn test_new_key_from_seed_with_leading_zeros_bytes() ! { // Test generating a key from a seed seed := [u8(0), u8(1), 2, 3, 4, 5] priv_key := new_key_from_seed(seed) or { panic(err) } - retrieved_seed := priv_key.seed() or { panic(err) } + retrieved_seed := priv_key.bytes() or { panic(err) } assert seed == retrieved_seed - key_free(priv_key.key) + priv_key.free() } fn test_sign_and_verify() ! { @@ -66,17 +68,18 @@ fn test_sign_and_verify() ! { signature := priv_key.sign(message) or { panic(err) } is_valid := pub_key.verify(message, signature) or { panic(err) } assert is_valid - key_free(priv_key.key) - key_free(pub_key.key) + + priv_key.free() + pub_key.free() } fn test_seed() ! { // Test retrieving the seed from a private key pub_key, priv_key := generate_key() or { panic(err) } - seed := priv_key.seed() or { panic(err) } + seed := priv_key.bytes() or { panic(err) } assert seed.len > 0 - key_free(priv_key.key) - key_free(pub_key.key) + priv_key.free() + pub_key.free() } fn test_public_key() ! { @@ -85,34 +88,36 @@ fn test_public_key() ! { pub_key1 := priv_key.public_key() or { panic(err) } pub_key2, privkk := generate_key() or { panic(err) } assert !pub_key1.equal(pub_key2) - key_free(pubkk.key) - key_free(privkk.key) - key_free(priv_key.key) - key_free(pub_key1.key) - key_free(pub_key2.key) + + pubkk.free() + privkk.free() + priv_key.free() + pub_key1.free() + pub_key2.free() } fn test_private_key_equal() ! { // Test private key equality pbk, priv_key1 := generate_key() or { panic(err) } - seed := priv_key1.seed() or { panic(err) } + seed := priv_key1.bytes() or { panic(err) } priv_key2 := new_key_from_seed(seed) or { panic(err) } assert priv_key1.equal(priv_key2) - key_free(pbk.key) - key_free(priv_key1.key) - key_free(priv_key2.key) + + pbk.free() + priv_key1.free() + priv_key2.free() } fn test_private_key_equality_on_different_curve() ! { // default group pbk, priv_key1 := generate_key() or { panic(err) } - seed := priv_key1.seed() or { panic(err) } + seed := priv_key1.bytes() or { panic(err) } // using different group priv_key2 := new_key_from_seed(seed, nid: .secp384r1) or { panic(err) } assert !priv_key1.equal(priv_key2) - key_free(pbk.key) - key_free(priv_key1.key) - key_free(priv_key2.key) + pbk.free() + priv_key1.free() + priv_key2.free() } fn test_public_key_equal() ! { @@ -121,10 +126,10 @@ fn test_public_key_equal() ! { pub_key1 := priv_key.public_key() or { panic(err) } pub_key2 := priv_key.public_key() or { panic(err) } assert pub_key1.equal(pub_key2) - key_free(pbk.key) - key_free(priv_key.key) - key_free(pub_key1.key) - key_free(pub_key2.key) + pbk.free() + priv_key.free() + pub_key1.free() + pub_key2.free() } fn test_sign_with_new_key_from_seed() ! { @@ -136,8 +141,8 @@ fn test_sign_with_new_key_from_seed() ! { pub_key := priv_key.public_key() or { panic(err) } is_valid := pub_key.verify(message, signature) or { panic(err) } assert is_valid - key_free(priv_key.key) - key_free(pub_key.key) + priv_key.free() + pub_key.free() } fn test_invalid_signature() ! { @@ -148,13 +153,13 @@ fn test_invalid_signature() ! { result := pub_key.verify(message, invalid_signature) or { // Expecting verification to fail assert err.msg() == 'Failed to verify signature' - key_free(pub_key.key) - key_free(pvk.key) + pub_key.free() + pvk.free() return } assert !result - key_free(pub_key.key) - key_free(pvk.key) + pub_key.free() + pvk.free() } fn test_different_keys_not_equal() ! { @@ -162,10 +167,10 @@ fn test_different_keys_not_equal() ! { pbk1, priv_key1 := generate_key() or { panic(err) } pbk2, priv_key2 := generate_key() or { panic(err) } assert !priv_key1.equal(priv_key2) - key_free(pbk1.key) - key_free(pbk2.key) - key_free(priv_key1.key) - key_free(priv_key2.key) + pbk1.free() + pbk2.free() + priv_key1.free() + priv_key2.free() } fn test_private_key_new() ! { @@ -181,7 +186,7 @@ fn test_private_key_new() ! { assert is_valid // new private key - seed := priv_key.seed()! + seed := priv_key.bytes()! priv_key2 := new_key_from_seed(seed)! pubkey2 := priv_key2.public_key()! assert priv_key.equal(priv_key2) diff --git a/vlib/crypto/ecdsa/util_test.v b/vlib/crypto/ecdsa/util_test.v index f0499e9710..b4d7f8ad92 100644 --- a/vlib/crypto/ecdsa/util_test.v +++ b/vlib/crypto/ecdsa/util_test.v @@ -38,7 +38,7 @@ fn test_load_pubkey_from_der_serialized_bytes() ! { // expected signature was comes from hashed message with sha384 status_with_hashed := pbkey.verify(message_tobe_signed, expected_signature)! assert status_with_hashed == true - key_free(pbkey.key) + pbkey.free() } fn test_for_pubkey_bytes() ! { @@ -50,8 +50,8 @@ fn test_for_pubkey_bytes() ! { assert pvkey.seed()!.hex() == pv pbkey := pvkey.public_key()! assert pbkey.bytes()!.hex() == pb - key_free(pbkey.key) - key_free(pvkey.key) + pbkey.free() + pvkey.free() } // above pem-formatted private key read with