From f1db5c88a22a002d8685997fdd496564c34f86b2 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Mon, 4 Nov 2024 08:41:19 -0800 Subject: [PATCH 1/3] Check for compatible openssl versions earlier test_pkey wasn't checking for libressl as is done elsewhere. Note the libressl version check is different when testing pkey, because PKey#sign relies on EVP_PKey_sign, whereas signing an X509 cert/request/crl relies on ASN1_item_sign. --- test/openssl/test_pkey.rb | 13 ++++--------- test/openssl/test_x509cert.rb | 17 ++--------------- 2 files changed, 6 insertions(+), 24 deletions(-) diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index 811d5103d..aae6b7e07 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -90,6 +90,8 @@ def test_hmac_sign_verify def test_ed25519 # Ed25519 is not FIPS-approved. omit_on_fips + # See EVP_PKEY_sign in Changelog for 3.7.0: https://github.com/libressl/portable/blob/master/ChangeLog + omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 7, 0) # Test vector from RFC 8032 Section 7.1 TEST 2 priv_pem = <<~EOF @@ -102,15 +104,8 @@ def test_ed25519 MCowBQYDK2VwAyEAPUAXw+hDiVqStwqnTRt+vJyYLM8uxJaMwM1V8Sr0Zgw= -----END PUBLIC KEY----- EOF - begin - priv = OpenSSL::PKey.read(priv_pem) - pub = OpenSSL::PKey.read(pub_pem) - rescue OpenSSL::PKey::PKeyError => e - # OpenSSL < 1.1.1 - pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) - - raise e - end + priv = OpenSSL::PKey.read(priv_pem) + pub = OpenSSL::PKey.read(pub_pem) assert_instance_of OpenSSL::PKey::PKey, priv assert_instance_of OpenSSL::PKey::PKey, pub assert_equal priv_pem, priv.private_to_pem diff --git a/test/openssl/test_x509cert.rb b/test/openssl/test_x509cert.rb index 76359552e..6c16218f3 100644 --- a/test/openssl/test_x509cert.rb +++ b/test/openssl/test_x509cert.rb @@ -292,24 +292,11 @@ def test_sign_and_verify_dsa_md5 end def test_sign_and_verify_ed25519 - # See test_ed25519 in test_pkey.rb - # Ed25519 is not FIPS-approved. omit_on_fips - - begin - ed25519 = OpenSSL::PKey::generate_key("ED25519") - rescue OpenSSL::PKey::PKeyError => e - # OpenSSL < 1.1.1 - # - pend "Ed25519 is not implemented" unless openssl?(1, 1, 1) - - raise e - end - # See ASN1_item_sign_ctx in ChangeLog for 3.8.1: https://github.com/libressl/portable/blob/master/ChangeLog - pend 'ASN1 signing with Ed25519 not yet working' unless openssl? or libressl?(3, 8, 1) - + omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 8, 1) + ed25519 = OpenSSL::PKey::generate_key("ED25519") cert = issue_cert(@ca, ed25519, 1, [], nil, nil, digest: nil) assert_equal(true, cert.verify(ed25519)) end From d96090320d7d9bdb5b4466faf17e556767d6b1a8 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Tue, 8 Oct 2024 11:52:11 -0700 Subject: [PATCH 2/3] Support signing requests using Ed25519 Allow requests to be signed using Ed25519 private keys by passing a nil digest. This is similar to commit b0fc100091207d7eab20a349433ccbd8260c6ddd when signing certs. Calling PKey#public_key is deprecated and does not work for Ed25519. The same can be accomplished by passing the private key. --- ext/openssl/ossl_x509req.c | 6 +++++- test/openssl/test_x509req.rb | 25 ++++++++++++++++++++----- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ext/openssl/ossl_x509req.c b/ext/openssl/ossl_x509req.c index 37ba03728..4a4d3f286 100644 --- a/ext/openssl/ossl_x509req.c +++ b/ext/openssl/ossl_x509req.c @@ -312,7 +312,11 @@ ossl_x509req_sign(VALUE self, VALUE key, VALUE digest) GetX509Req(self, req); pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = ossl_evp_get_digestbyname(digest); + if (NIL_P(digest)) { + md = NULL; /* needed for some key types, e.g. Ed25519 */ + } else { + md = ossl_evp_get_digestbyname(digest); + } if (!X509_REQ_sign(req, pkey, md)) { ossl_raise(eX509ReqError, NULL); } diff --git a/test/openssl/test_x509req.rb b/test/openssl/test_x509req.rb index b98754b8c..1bf457ecf 100644 --- a/test/openssl/test_x509req.rb +++ b/test/openssl/test_x509req.rb @@ -17,21 +17,21 @@ def issue_csr(ver, dn, key, digest) req = OpenSSL::X509::Request.new req.version = ver req.subject = dn - req.public_key = key.public_key + req.public_key = key req.sign(key, digest) req end def test_public_key req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) - assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + assert_equal(@rsa1024.public_to_der, req.public_key.public_to_der) req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(@rsa1024.public_key.to_der, req.public_key.to_der) + assert_equal(@rsa1024.public_to_der, req.public_key.public_to_der) req = issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('SHA256')) - assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + assert_equal(@dsa512.public_to_der, req.public_key.public_to_der) req = OpenSSL::X509::Request.new(req.to_der) - assert_equal(@dsa512.public_key.to_der, req.public_key.to_der) + assert_equal(@dsa512.public_to_der, req.public_key.public_to_der) end def test_version @@ -132,6 +132,21 @@ def test_sign_and_verify_dsa_md5 issue_csr(0, @dn, @dsa512, OpenSSL::Digest.new('MD5')) } end + def test_sign_and_verify_ed25519 + # Ed25519 is not FIPS-approved. + omit_on_fips + # See ASN1_item_sign_ctx in ChangeLog for 3.8.1: https://github.com/libressl/portable/blob/master/ChangeLog + omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 8, 1) + ed25519 = OpenSSL::PKey::generate_key("ED25519") + req = issue_csr(0, @dn, ed25519, nil) + assert_equal(false, request_error_returns_false { req.verify(@rsa1024) }) + assert_equal(false, request_error_returns_false { req.verify(@rsa2048) }) + assert_equal(false, req.verify(OpenSSL::PKey::generate_key("ED25519"))) + assert_equal(true, req.verify(ed25519)) + req.public_key = @rsa1024.public_key + assert_equal(false, req.verify(ed25519)) + end + def test_dup req = issue_csr(0, @dn, @rsa1024, OpenSSL::Digest.new('SHA256')) assert_equal(req.to_der, req.dup.to_der) From b62375bcdedea7140eed7babae73353ccb9d6d02 Mon Sep 17 00:00:00 2001 From: Josh Cooper Date: Tue, 29 Oct 2024 14:18:32 -0700 Subject: [PATCH 3/3] Support signing CRLs using Ed25519 Allow CRLs to be signed using Ed25519 private keys by passing a nil digest. --- ext/openssl/ossl_x509crl.c | 6 +++++- test/openssl/test_x509crl.rb | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/ext/openssl/ossl_x509crl.c b/ext/openssl/ossl_x509crl.c index 368270ce1..4f3177bfb 100644 --- a/ext/openssl/ossl_x509crl.c +++ b/ext/openssl/ossl_x509crl.c @@ -350,7 +350,11 @@ ossl_x509crl_sign(VALUE self, VALUE key, VALUE digest) GetX509CRL(self, crl); pkey = GetPrivPKeyPtr(key); /* NO NEED TO DUP */ - md = ossl_evp_get_digestbyname(digest); + if (NIL_P(digest)) { + md = NULL; /* needed for some key types, e.g. Ed25519 */ + } else { + md = ossl_evp_get_digestbyname(digest); + } if (!X509_CRL_sign(crl, pkey, md)) { ossl_raise(eX509CRLError, NULL); } diff --git a/test/openssl/test_x509crl.rb b/test/openssl/test_x509crl.rb index 146ee0730..e5fa6f998 100644 --- a/test/openssl/test_x509crl.rb +++ b/test/openssl/test_x509crl.rb @@ -204,6 +204,23 @@ def test_sign_and_verify assert_equal(false, crl.verify(@dsa512)) end + def test_sign_and_verify_ed25519 + # Ed25519 is not FIPS-approved. + omit_on_fips + # See ASN1_item_sign_ctx in ChangeLog for 3.8.1: https://github.com/libressl/portable/blob/master/ChangeLog + omit "Ed25519 not supported" unless openssl?(1, 1, 1) || libressl?(3, 8, 1) + ed25519 = OpenSSL::PKey::generate_key("ED25519") + cert = issue_cert(@ca, ed25519, 1, [], nil, nil, digest: nil) + crl = issue_crl([], 1, Time.now, Time.now+1600, [], + cert, ed25519, nil) + assert_equal(false, crl_error_returns_false { crl.verify(@rsa1024) }) + assert_equal(false, crl_error_returns_false { crl.verify(@rsa2048) }) + assert_equal(false, crl.verify(OpenSSL::PKey::generate_key("ED25519"))) + assert_equal(true, crl.verify(ed25519)) + crl.version = 0 + assert_equal(false, crl.verify(ed25519)) + end + def test_revoked_to_der # revokedCertificates SEQUENCE OF SEQUENCE { # userCertificate CertificateSerialNumber,