[ruby/openssl] Add support for raw private/public keys
(https://github.com/ruby/openssl/pull/646) Add OpenSSL::PKey.new_raw_private_key, #raw_private_key and public equivalents. These methods are useful for importing and exporting keys that support "raw private/public key". Currently, OpenSSL implements X25519/X448 and Ed25519/Ed448 keys. [rhe: rewrote commit message] https://github.com/ruby/openssl/commit/3f29525618 Co-authored-by: Bart de Water <bartdewater@gmail.com>
This commit is contained in:
parent
fb12522b00
commit
4b6d667c63
@ -628,6 +628,72 @@ ossl_pkey_initialize_copy(VALUE self, VALUE other)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
|
||||
/*
|
||||
* call-seq:
|
||||
* OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey
|
||||
*
|
||||
* See the OpenSSL documentation for EVP_PKEY_new_raw_private_key()
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
const EVP_PKEY_ASN1_METHOD *ameth;
|
||||
int pkey_id;
|
||||
size_t keylen;
|
||||
|
||||
StringValue(type);
|
||||
StringValue(key);
|
||||
ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
|
||||
if (!ameth)
|
||||
ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
|
||||
EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
|
||||
|
||||
keylen = RSTRING_LEN(key);
|
||||
|
||||
pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
|
||||
if (!pkey)
|
||||
ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key");
|
||||
|
||||
return ossl_pkey_new(pkey);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
|
||||
/*
|
||||
* call-seq:
|
||||
* OpenSSL::PKey.new_raw_public_key(algo, string) -> PKey
|
||||
*
|
||||
* See the OpenSSL documentation for EVP_PKEY_new_raw_public_key()
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
const EVP_PKEY_ASN1_METHOD *ameth;
|
||||
int pkey_id;
|
||||
size_t keylen;
|
||||
|
||||
StringValue(type);
|
||||
StringValue(key);
|
||||
ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type));
|
||||
if (!ameth)
|
||||
ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type);
|
||||
EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
|
||||
|
||||
keylen = RSTRING_LEN(key);
|
||||
|
||||
pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen);
|
||||
if (!pkey)
|
||||
ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key");
|
||||
|
||||
return ossl_pkey_new(pkey);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* pkey.oid -> string
|
||||
@ -816,6 +882,35 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self)
|
||||
return do_pkcs8_export(argc, argv, self, 0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
|
||||
/*
|
||||
* call-seq:
|
||||
* pkey.raw_private_key => string
|
||||
*
|
||||
* See the OpenSSL documentation for EVP_PKEY_get_raw_private_key()
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_raw_private_key(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE str;
|
||||
size_t len;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1)
|
||||
ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
|
||||
str = rb_str_new(NULL, len);
|
||||
|
||||
if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
|
||||
ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key");
|
||||
|
||||
rb_str_set_len(str, len);
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
VALUE
|
||||
ossl_pkey_export_spki(VALUE self, int to_der)
|
||||
{
|
||||
@ -865,6 +960,35 @@ ossl_pkey_public_to_pem(VALUE self)
|
||||
return ossl_pkey_export_spki(self, 0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
|
||||
/*
|
||||
* call-seq:
|
||||
* pkey.raw_public_key => string
|
||||
*
|
||||
* See the OpenSSL documentation for EVP_PKEY_get_raw_public_key()
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
ossl_pkey_raw_public_key(VALUE self)
|
||||
{
|
||||
EVP_PKEY *pkey;
|
||||
VALUE str;
|
||||
size_t len;
|
||||
|
||||
GetPKey(self, pkey);
|
||||
if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1)
|
||||
ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
|
||||
str = rb_str_new(NULL, len);
|
||||
|
||||
if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1)
|
||||
ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key");
|
||||
|
||||
rb_str_set_len(str, len);
|
||||
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* pkey.compare?(another_pkey) -> true | false
|
||||
@ -1602,6 +1726,10 @@ Init_ossl_pkey(void)
|
||||
rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1);
|
||||
rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1);
|
||||
rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1);
|
||||
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
|
||||
rb_define_module_function(mPKey, "new_raw_private_key", ossl_pkey_new_raw_private_key, 2);
|
||||
rb_define_module_function(mPKey, "new_raw_public_key", ossl_pkey_new_raw_public_key, 2);
|
||||
#endif
|
||||
|
||||
rb_define_alloc_func(cPKey, ossl_pkey_alloc);
|
||||
rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0);
|
||||
@ -1617,6 +1745,10 @@ Init_ossl_pkey(void)
|
||||
rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1);
|
||||
rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0);
|
||||
rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0);
|
||||
#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY
|
||||
rb_define_method(cPKey, "raw_private_key", ossl_pkey_raw_private_key, 0);
|
||||
rb_define_method(cPKey, "raw_public_key", ossl_pkey_raw_public_key, 0);
|
||||
#endif
|
||||
rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1);
|
||||
|
||||
rb_define_method(cPKey, "sign", ossl_pkey_sign, -1);
|
||||
|
@ -109,6 +109,19 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
|
||||
assert_equal pub_pem, priv.public_to_pem
|
||||
assert_equal pub_pem, pub.public_to_pem
|
||||
|
||||
begin
|
||||
assert_equal "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb",
|
||||
priv.raw_private_key.unpack1("H*")
|
||||
assert_equal OpenSSL::PKey.new_raw_private_key("ED25519", priv.raw_private_key).private_to_pem,
|
||||
priv.private_to_pem
|
||||
assert_equal "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c",
|
||||
priv.raw_public_key.unpack1("H*")
|
||||
assert_equal OpenSSL::PKey.new_raw_public_key("ED25519", priv.raw_public_key).public_to_pem,
|
||||
pub.public_to_pem
|
||||
rescue NoMethodError
|
||||
pend "running OpenSSL version does not have raw public key support"
|
||||
end
|
||||
|
||||
sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*")
|
||||
92a009a9f0d4cab8720e820b5f642540
|
||||
a2b27b5416503f8fb3762223ebdb69da
|
||||
@ -155,6 +168,32 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
|
||||
assert_equal alice_pem, alice.private_to_pem
|
||||
assert_equal bob_pem, bob.public_to_pem
|
||||
assert_equal [shared_secret].pack("H*"), alice.derive(bob)
|
||||
begin
|
||||
alice_private = OpenSSL::PKey.new_raw_private_key("X25519", alice.raw_private_key)
|
||||
bob_public = OpenSSL::PKey.new_raw_public_key("X25519", bob.raw_public_key)
|
||||
alice_private_raw = alice.raw_private_key.unpack1("H*")
|
||||
bob_public_raw = bob.raw_public_key.unpack1("H*")
|
||||
rescue NoMethodError
|
||||
# OpenSSL < 1.1.1
|
||||
pend "running OpenSSL version does not have raw public key support"
|
||||
end
|
||||
assert_equal alice_private.private_to_pem,
|
||||
alice.private_to_pem
|
||||
assert_equal bob_public.public_to_pem,
|
||||
bob.public_to_pem
|
||||
assert_equal "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
|
||||
alice_private_raw
|
||||
assert_equal "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
|
||||
bob_public_raw
|
||||
end
|
||||
|
||||
def raw_initialize
|
||||
pend "Ed25519 is not implemented" unless OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10101000 && # >= v1.1.1
|
||||
|
||||
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("foo123", "xxx") }
|
||||
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("ED25519", "xxx") }
|
||||
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("foo123", "xxx") }
|
||||
assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("ED25519", "xxx") }
|
||||
end
|
||||
|
||||
def test_compare?
|
||||
|
Loading…
x
Reference in New Issue
Block a user