LibCrypto: Use OpenSSL for SECPxxxr1 sign/verify operations

This commit is contained in:
devgianlu 2025-01-26 21:00:21 +01:00 committed by Ali Mohammad Pur
parent f2e530ec14
commit cf5ce8277f
Notes: github-actions[bot] 2025-01-27 11:26:07 +00:00
2 changed files with 132 additions and 150 deletions

View file

@ -21,8 +21,9 @@
#include <LibCrypto/OpenSSL.h>
#include <openssl/core_names.h>
#include <openssl/evp.h>
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/param_build.h>
namespace {
// Used by ASN1 macros
@ -365,72 +366,57 @@ public:
ErrorOr<bool> verify_point(ReadonlyBytes hash, SECPxxxr1Point pubkey, SECPxxxr1Signature signature)
{
static constexpr size_t expected_word_count = KEY_BIT_SIZE / 32;
if (signature.r.length() < expected_word_count || signature.s.length() < expected_word_count) {
auto ctx_import = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr)));
OPENSSL_TRY(EVP_PKEY_fromdata_init(ctx_import.ptr()));
auto* params_bld = OPENSSL_TRY_PTR(OSSL_PARAM_BLD_new());
ScopeGuard const free_params_bld = [&] { OSSL_PARAM_BLD_free(params_bld); };
OPENSSL_TRY(OSSL_PARAM_BLD_push_utf8_string(params_bld, OSSL_PKEY_PARAM_GROUP_NAME, CURVE_PARAMETERS.name, strlen(CURVE_PARAMETERS.name)));
auto pubkey_bytes = TRY(pubkey.to_uncompressed());
OPENSSL_TRY(OSSL_PARAM_BLD_push_octet_string(params_bld, OSSL_PKEY_PARAM_PUB_KEY, pubkey_bytes.data(), pubkey_bytes.size()));
auto* params = OPENSSL_TRY_PTR(OSSL_PARAM_BLD_to_param(params_bld));
ScopeGuard const free_params = [&] { OSSL_PARAM_free(params); };
auto key = TRY(OpenSSL_PKEY::wrap(EVP_PKEY_new()));
auto* key_ptr = key.ptr();
OPENSSL_TRY(EVP_PKEY_fromdata(ctx_import.ptr(), &key_ptr, EVP_PKEY_PUBLIC_KEY, params));
auto ctx = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_pkey(nullptr, key.ptr(), nullptr)));
OPENSSL_TRY(EVP_PKEY_verify_init(ctx.ptr()));
auto* sig_obj = OPENSSL_TRY_PTR(ECDSA_SIG_new());
ScopeGuard const free_sig_obj = [&] { ECDSA_SIG_free(sig_obj); };
auto r = TRY(unsigned_big_integer_to_openssl_bignum(signature.r));
auto s = TRY(unsigned_big_integer_to_openssl_bignum(signature.s));
// Let sig_obj own a copy of r and s
OPENSSL_TRY(ECDSA_SIG_set0(sig_obj, BN_dup(r.ptr()), BN_dup(s.ptr())));
u8* sig = nullptr;
ScopeGuard const free_sig = [&] { OPENSSL_free(sig); };
auto sig_len = TRY([&] -> ErrorOr<int> {
auto ret = i2d_ECDSA_SIG(sig_obj, &sig);
if (ret <= 0) {
OPENSSL_TRY(ret);
VERIFY_NOT_REACHED();
}
return ret;
}());
auto ret = EVP_PKEY_verify(ctx.ptr(), sig, sig_len, hash.data(), hash.size());
if (ret == 1)
return true;
if (ret == 0)
return false;
}
auto r = unsigned_big_integer_to_storage_type(signature.r);
auto s = unsigned_big_integer_to_storage_type(signature.s);
if (r.is_zero_constant_time() || s.is_zero_constant_time())
return false;
// z is the hash
StorageType z = 0u;
for (size_t i = 0; i < KEY_BYTE_SIZE && i < hash.size(); i++) {
z <<= 8;
z |= hash[i];
}
StorageType r_mo = to_montgomery_order(r);
StorageType s_mo = to_montgomery_order(s);
StorageType z_mo = to_montgomery_order(z);
StorageType s_inv = modular_inverse_order(s_mo);
StorageType u1 = modular_multiply_order(z_mo, s_inv);
StorageType u2 = modular_multiply_order(r_mo, s_inv);
u1 = from_montgomery_order(u1);
u2 = from_montgomery_order(u2);
JacobianPoint point1 = TRY(generate_public_key_internal(u1));
JacobianPoint point2 = TRY(compute_coordinate_internal(u2, JacobianPoint {
unsigned_big_integer_to_storage_type(pubkey.x),
unsigned_big_integer_to_storage_type(pubkey.y),
1u,
}));
// Convert the input point into Montgomery form
point1.x = to_montgomery(point1.x);
point1.y = to_montgomery(point1.y);
point1.z = to_montgomery(point1.z);
VERIFY(is_point_on_curve(point1));
// Convert the input point into Montgomery form
point2.x = to_montgomery(point2.x);
point2.y = to_montgomery(point2.y);
point2.z = to_montgomery(point2.z);
VERIFY(is_point_on_curve(point2));
JacobianPoint result = point_add(point1, point2);
// Convert from Jacobian coordinates back to Affine coordinates
convert_jacobian_to_affine(result);
// Make sure the resulting point is on the curve
VERIFY(is_point_on_curve(result));
// Convert the result back from Montgomery form
result.x = from_montgomery(result.x);
result.y = from_montgomery(result.y);
// Final modular reduction on the coordinates
result.x = modular_reduce(result.x);
result.y = modular_reduce(result.y);
return r.is_equal_to_constant_time(result.x);
OPENSSL_TRY(ret);
VERIFY_NOT_REACHED();
}
ErrorOr<bool> verify(ReadonlyBytes hash, ReadonlyBytes pubkey, SECPxxxr1Signature signature)
@ -441,51 +427,48 @@ public:
ErrorOr<SECPxxxr1Signature> sign_scalar(ReadonlyBytes hash, UnsignedBigInteger private_key)
{
auto d = unsigned_big_integer_to_storage_type(private_key);
auto ctx_import = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_name(nullptr, "EC", nullptr)));
auto k_int = TRY(generate_private_key_scalar());
auto k = unsigned_big_integer_to_storage_type(k_int);
auto k_mo = to_montgomery_order(k);
OPENSSL_TRY(EVP_PKEY_fromdata_init(ctx_import.ptr()));
auto kG = TRY(generate_public_key_internal(k));
auto r = kG.x;
auto d = TRY(unsigned_big_integer_to_openssl_bignum(private_key));
if (r.is_zero_constant_time()) {
// Retry with a new k
return sign_scalar(hash, private_key);
}
auto* params_bld = OPENSSL_TRY_PTR(OSSL_PARAM_BLD_new());
ScopeGuard const free_params_bld = [&] { OSSL_PARAM_BLD_free(params_bld); };
// Compute z from the hash
StorageType z = 0u;
for (size_t i = 0; i < KEY_BYTE_SIZE && i < hash.size(); i++) {
z <<= 8;
z |= hash[i];
}
OPENSSL_TRY(OSSL_PARAM_BLD_push_utf8_string(params_bld, OSSL_PKEY_PARAM_GROUP_NAME, CURVE_PARAMETERS.name, strlen(CURVE_PARAMETERS.name)));
OPENSSL_TRY(OSSL_PARAM_BLD_push_BN(params_bld, OSSL_PKEY_PARAM_PRIV_KEY, d.ptr()));
// s = k^-1 * (z + r * d) mod n
auto r_mo = to_montgomery_order(r);
auto z_mo = to_montgomery_order(z);
auto d_mo = to_montgomery_order(d);
auto* params = OPENSSL_TRY_PTR(OSSL_PARAM_BLD_to_param(params_bld));
ScopeGuard const free_params = [&] { OSSL_PARAM_free(params); };
// r * d mod n
auto rd_mo = modular_multiply_order(r_mo, d_mo);
auto key = TRY(OpenSSL_PKEY::wrap(EVP_PKEY_new()));
auto* key_ptr = key.ptr();
OPENSSL_TRY(EVP_PKEY_fromdata(ctx_import.ptr(), &key_ptr, EVP_PKEY_KEYPAIR, params));
// z + (r * d) mod n
auto z_plus_rd_mo = modular_add_order(z_mo, rd_mo);
auto ctx = TRY(OpenSSL_PKEY_CTX::wrap(EVP_PKEY_CTX_new_from_pkey(nullptr, key.ptr(), nullptr)));
// k^-1 mod n
auto k_inv_mo = modular_inverse_order(k_mo);
OPENSSL_TRY(EVP_PKEY_sign_init(ctx.ptr()));
// s = k^-1 * (z + r * d) mod n
auto s_mo = modular_multiply_order(z_plus_rd_mo, k_inv_mo);
auto s = from_montgomery_order(s_mo);
size_t sig_len = 0;
OPENSSL_TRY(EVP_PKEY_sign(ctx.ptr(), nullptr, &sig_len, hash.data(), hash.size()));
if (s.is_zero_constant_time()) {
// Retry with a new k
return sign_scalar(hash, private_key);
}
auto sig = TRY(ByteBuffer::create_uninitialized(sig_len));
OPENSSL_TRY(EVP_PKEY_sign(ctx.ptr(), sig.data(), &sig_len, hash.data(), hash.size()));
return SECPxxxr1Signature { storage_type_to_unsigned_big_integer(r), storage_type_to_unsigned_big_integer(s), KEY_BYTE_SIZE };
auto const* sig_data = sig.data();
auto* sig_obj = OPENSSL_TRY_PTR(d2i_ECDSA_SIG(nullptr, &sig_data, sig.size()));
ScopeGuard const free_sig_obj = [&] { ECDSA_SIG_free(sig_obj); };
// Duplicate r and s so that sig_obj can own them
auto r = TRY(OpenSSL_BN::wrap(BN_dup(OPENSSL_TRY_PTR(ECDSA_SIG_get0_r(sig_obj)))));
auto s = TRY(OpenSSL_BN::wrap(BN_dup(OPENSSL_TRY_PTR(ECDSA_SIG_get0_s(sig_obj)))));
return SECPxxxr1Signature {
TRY(openssl_bignum_to_unsigned_big_integer(r)),
TRY(openssl_bignum_to_unsigned_big_integer(s)),
KEY_BYTE_SIZE,
};
}
ErrorOr<SECPxxxr1Signature> sign(ReadonlyBytes hash, ReadonlyBytes private_key_bytes)

View file

@ -2,8 +2,7 @@ Harness status: OK
Found 253 tests
205 Pass
48 Fail
253 Pass
Pass setup
Pass ECDSA P-256 with SHA-1 verification
Pass ECDSA P-256 with SHA-256 verification
@ -13,10 +12,10 @@ Pass ECDSA P-384 with SHA-1 verification
Pass ECDSA P-384 with SHA-256 verification
Pass ECDSA P-384 with SHA-384 verification
Pass ECDSA P-384 with SHA-512 verification
Fail ECDSA P-521 with SHA-1 verification
Fail ECDSA P-521 with SHA-256 verification
Fail ECDSA P-521 with SHA-384 verification
Fail ECDSA P-521 with SHA-512 verification
Pass ECDSA P-521 with SHA-1 verification
Pass ECDSA P-521 with SHA-256 verification
Pass ECDSA P-521 with SHA-384 verification
Pass ECDSA P-521 with SHA-512 verification
Pass ECDSA P-256 with SHA-1 verification with altered signature after call
Pass ECDSA P-256 with SHA-256 verification with altered signature after call
Pass ECDSA P-256 with SHA-384 verification with altered signature after call
@ -25,10 +24,10 @@ Pass ECDSA P-384 with SHA-1 verification with altered signature after call
Pass ECDSA P-384 with SHA-256 verification with altered signature after call
Pass ECDSA P-384 with SHA-384 verification with altered signature after call
Pass ECDSA P-384 with SHA-512 verification with altered signature after call
Fail ECDSA P-521 with SHA-1 verification with altered signature after call
Fail ECDSA P-521 with SHA-256 verification with altered signature after call
Fail ECDSA P-521 with SHA-384 verification with altered signature after call
Fail ECDSA P-521 with SHA-512 verification with altered signature after call
Pass ECDSA P-521 with SHA-1 verification with altered signature after call
Pass ECDSA P-521 with SHA-256 verification with altered signature after call
Pass ECDSA P-521 with SHA-384 verification with altered signature after call
Pass ECDSA P-521 with SHA-512 verification with altered signature after call
Pass ECDSA P-256 with SHA-1 with altered plaintext after call
Pass ECDSA P-256 with SHA-256 with altered plaintext after call
Pass ECDSA P-256 with SHA-384 with altered plaintext after call
@ -37,10 +36,10 @@ Pass ECDSA P-384 with SHA-1 with altered plaintext after call
Pass ECDSA P-384 with SHA-256 with altered plaintext after call
Pass ECDSA P-384 with SHA-384 with altered plaintext after call
Pass ECDSA P-384 with SHA-512 with altered plaintext after call
Fail ECDSA P-521 with SHA-1 with altered plaintext after call
Fail ECDSA P-521 with SHA-256 with altered plaintext after call
Fail ECDSA P-521 with SHA-384 with altered plaintext after call
Fail ECDSA P-521 with SHA-512 with altered plaintext after call
Pass ECDSA P-521 with SHA-1 with altered plaintext after call
Pass ECDSA P-521 with SHA-256 with altered plaintext after call
Pass ECDSA P-521 with SHA-384 with altered plaintext after call
Pass ECDSA P-521 with SHA-512 with altered plaintext after call
Pass ECDSA P-256 with SHA-1 using privateKey to verify
Pass ECDSA P-256 with SHA-256 using privateKey to verify
Pass ECDSA P-256 with SHA-384 using privateKey to verify
@ -85,10 +84,10 @@ Pass ECDSA P-384 with SHA-1 round trip
Pass ECDSA P-384 with SHA-256 round trip
Pass ECDSA P-384 with SHA-384 round trip
Pass ECDSA P-384 with SHA-512 round trip
Fail ECDSA P-521 with SHA-1 round trip
Fail ECDSA P-521 with SHA-256 round trip
Fail ECDSA P-521 with SHA-384 round trip
Fail ECDSA P-521 with SHA-512 round trip
Pass ECDSA P-521 with SHA-1 round trip
Pass ECDSA P-521 with SHA-256 round trip
Pass ECDSA P-521 with SHA-384 round trip
Pass ECDSA P-521 with SHA-512 round trip
Pass ECDSA P-256 with SHA-1 signing with wrong algorithm name
Pass ECDSA P-256 with SHA-256 signing with wrong algorithm name
Pass ECDSA P-256 with SHA-384 signing with wrong algorithm name
@ -121,10 +120,10 @@ Pass ECDSA P-384 with SHA-1 verification failure due to altered signature
Pass ECDSA P-384 with SHA-256 verification failure due to altered signature
Pass ECDSA P-384 with SHA-384 verification failure due to altered signature
Pass ECDSA P-384 with SHA-512 verification failure due to altered signature
Fail ECDSA P-521 with SHA-1 verification failure due to altered signature
Fail ECDSA P-521 with SHA-256 verification failure due to altered signature
Fail ECDSA P-521 with SHA-384 verification failure due to altered signature
Fail ECDSA P-521 with SHA-512 verification failure due to altered signature
Pass ECDSA P-521 with SHA-1 verification failure due to altered signature
Pass ECDSA P-521 with SHA-256 verification failure due to altered signature
Pass ECDSA P-521 with SHA-384 verification failure due to altered signature
Pass ECDSA P-521 with SHA-512 verification failure due to altered signature
Pass ECDSA P-256 with SHA-1 verification failure due to wrong hash
Pass ECDSA P-256 with SHA-256 verification failure due to wrong hash
Pass ECDSA P-256 with SHA-384 verification failure due to wrong hash
@ -133,10 +132,10 @@ Pass ECDSA P-384 with SHA-1 verification failure due to wrong hash
Pass ECDSA P-384 with SHA-256 verification failure due to wrong hash
Pass ECDSA P-384 with SHA-384 verification failure due to wrong hash
Pass ECDSA P-384 with SHA-512 verification failure due to wrong hash
Fail ECDSA P-521 with SHA-1 verification failure due to wrong hash
Fail ECDSA P-521 with SHA-256 verification failure due to wrong hash
Fail ECDSA P-521 with SHA-384 verification failure due to wrong hash
Fail ECDSA P-521 with SHA-512 verification failure due to wrong hash
Pass ECDSA P-521 with SHA-1 verification failure due to wrong hash
Pass ECDSA P-521 with SHA-256 verification failure due to wrong hash
Pass ECDSA P-521 with SHA-384 verification failure due to wrong hash
Pass ECDSA P-521 with SHA-512 verification failure due to wrong hash
Pass ECDSA P-256 with SHA-1 verification failure due to bad hash name
Pass ECDSA P-256 with SHA-256 verification failure due to bad hash name
Pass ECDSA P-256 with SHA-384 verification failure due to bad hash name
@ -157,10 +156,10 @@ Pass ECDSA P-384 with SHA-1 verification failure due to shortened signature
Pass ECDSA P-384 with SHA-256 verification failure due to shortened signature
Pass ECDSA P-384 with SHA-384 verification failure due to shortened signature
Pass ECDSA P-384 with SHA-512 verification failure due to shortened signature
Fail ECDSA P-521 with SHA-1 verification failure due to shortened signature
Fail ECDSA P-521 with SHA-256 verification failure due to shortened signature
Fail ECDSA P-521 with SHA-384 verification failure due to shortened signature
Fail ECDSA P-521 with SHA-512 verification failure due to shortened signature
Pass ECDSA P-521 with SHA-1 verification failure due to shortened signature
Pass ECDSA P-521 with SHA-256 verification failure due to shortened signature
Pass ECDSA P-521 with SHA-384 verification failure due to shortened signature
Pass ECDSA P-521 with SHA-512 verification failure due to shortened signature
Pass ECDSA P-256 with SHA-1 verification failure due to altered plaintext
Pass ECDSA P-256 with SHA-256 verification failure due to altered plaintext
Pass ECDSA P-256 with SHA-384 verification failure due to altered plaintext
@ -169,10 +168,10 @@ Pass ECDSA P-384 with SHA-1 verification failure due to altered plaintext
Pass ECDSA P-384 with SHA-256 verification failure due to altered plaintext
Pass ECDSA P-384 with SHA-384 verification failure due to altered plaintext
Pass ECDSA P-384 with SHA-512 verification failure due to altered plaintext
Fail ECDSA P-521 with SHA-1 verification failure due to altered plaintext
Fail ECDSA P-521 with SHA-256 verification failure due to altered plaintext
Fail ECDSA P-521 with SHA-384 verification failure due to altered plaintext
Fail ECDSA P-521 with SHA-512 verification failure due to altered plaintext
Pass ECDSA P-521 with SHA-1 verification failure due to altered plaintext
Pass ECDSA P-521 with SHA-256 verification failure due to altered plaintext
Pass ECDSA P-521 with SHA-384 verification failure due to altered plaintext
Pass ECDSA P-521 with SHA-512 verification failure due to altered plaintext
Pass ECDSA P-256 with SHA-1 - The signature was truncated by 1 byte verification
Pass ECDSA P-256 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-256 verification
Pass ECDSA P-256 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-384 verification
@ -229,31 +228,31 @@ Pass ECDSA P-384 with SHA-512 - The signature was made using SHA-512, however ve
Pass ECDSA P-384 with SHA-512 - Signature has excess padding verification
Pass ECDSA P-384 with SHA-512 - The signature is empty verification
Pass ECDSA P-384 with SHA-512 - The signature is all zeroes verification
Fail ECDSA P-521 with SHA-1 - The signature was truncated by 1 byte verification
Fail ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-256 verification
Fail ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-384 verification
Fail ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-512 verification
Pass ECDSA P-521 with SHA-1 - The signature was truncated by 1 byte verification
Pass ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-256 verification
Pass ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-384 verification
Pass ECDSA P-521 with SHA-1 - The signature was made using SHA-1, however verification is being done using SHA-512 verification
Pass ECDSA P-521 with SHA-1 - Signature has excess padding verification
Pass ECDSA P-521 with SHA-1 - The signature is empty verification
Pass ECDSA P-521 with SHA-1 - The signature is all zeroes verification
Fail ECDSA P-521 with SHA-256 - The signature was truncated by 1 byte verification
Fail ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-1 verification
Fail ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-384 verification
Fail ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-512 verification
Pass ECDSA P-521 with SHA-256 - The signature was truncated by 1 byte verification
Pass ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-1 verification
Pass ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-384 verification
Pass ECDSA P-521 with SHA-256 - The signature was made using SHA-256, however verification is being done using SHA-512 verification
Pass ECDSA P-521 with SHA-256 - Signature has excess padding verification
Pass ECDSA P-521 with SHA-256 - The signature is empty verification
Pass ECDSA P-521 with SHA-256 - The signature is all zeroes verification
Fail ECDSA P-521 with SHA-384 - The signature was truncated by 1 byte verification
Fail ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-1 verification
Fail ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-256 verification
Fail ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-512 verification
Pass ECDSA P-521 with SHA-384 - The signature was truncated by 1 byte verification
Pass ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-1 verification
Pass ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-256 verification
Pass ECDSA P-521 with SHA-384 - The signature was made using SHA-384, however verification is being done using SHA-512 verification
Pass ECDSA P-521 with SHA-384 - Signature has excess padding verification
Pass ECDSA P-521 with SHA-384 - The signature is empty verification
Pass ECDSA P-521 with SHA-384 - The signature is all zeroes verification
Fail ECDSA P-521 with SHA-512 - The signature was truncated by 1 byte verification
Fail ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-1 verification
Fail ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-256 verification
Fail ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-384 verification
Pass ECDSA P-521 with SHA-512 - The signature was truncated by 1 byte verification
Pass ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-1 verification
Pass ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-256 verification
Pass ECDSA P-521 with SHA-512 - The signature was made using SHA-512, however verification is being done using SHA-384 verification
Pass ECDSA P-521 with SHA-512 - Signature has excess padding verification
Pass ECDSA P-521 with SHA-512 - The signature is empty verification
Pass ECDSA P-521 with SHA-512 - The signature is all zeroes verification