aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ext/openssl/ossl_pkey.c111
-rw-r--r--test/openssl/test_pkey.rb6
-rw-r--r--test/openssl/utils.rb16
3 files changed, 59 insertions, 74 deletions
diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c
index 6d73d259..013412c2 100644
--- a/ext/openssl/ossl_pkey.c
+++ b/ext/openssl/ossl_pkey.c
@@ -82,30 +82,62 @@ ossl_pkey_new(EVP_PKEY *pkey)
#if OSSL_OPENSSL_PREREQ(3, 0, 0)
# include <openssl/decoder.h>
-EVP_PKEY *
-ossl_pkey_read_generic(BIO *bio, VALUE pass)
+static EVP_PKEY *
+ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
{
void *ppass = (void *)pass;
OSSL_DECODER_CTX *dctx;
EVP_PKEY *pkey = NULL;
int pos = 0, pos2;
- dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL);
+ dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL,
+ selection, NULL, NULL);
if (!dctx)
goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
- goto out;
-
- /* First check DER */
- if (OSSL_DECODER_from_bio(dctx, bio) == 1)
+ if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
+ ppass) != 1)
goto out;
+ while (1) {
+ if (OSSL_DECODER_from_bio(dctx, bio) == 1)
+ goto out;
+ if (BIO_eof(bio))
+ break;
+ pos2 = BIO_tell(bio);
+ if (pos2 < 0 || pos2 <= pos)
+ break;
+ ossl_clear_error();
+ pos = pos2;
+ }
+ out:
OSSL_BIO_reset(bio);
+ OSSL_DECODER_CTX_free(dctx);
+ return pkey;
+}
+EVP_PKEY *
+ossl_pkey_read_generic(BIO *bio, VALUE pass)
+{
+ EVP_PKEY *pkey = NULL;
+ /* First check DER, then check PEM. */
+ const char *input_types[] = {"DER", "PEM"};
+ int input_type_num = (int)(sizeof(input_types) / sizeof(char *));
/*
- * Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed.
+ * Non-zero selections to try to decode.
+ *
+ * See EVP_PKEY_fromdata(3) - Selections to see all the selections.
*
- * First check for private key formats. This is to keep compatibility with
- * ruby/openssl < 3.0 which decoded the following as a private key.
+ * This is a workaround for the decoder failing to decode or returning
+ * bogus keys with selection 0, if a key management provider is different
+ * from a decoder provider. The workaround is to avoid using selection 0.
+ *
+ * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10
+ * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z
+ *
+ * See https://github.com/openssl/openssl/pull/21519 for details.
+ *
+ * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep
+ * compatibility with ruby/openssl < 3.0 which decoded the following as a
+ * private key.
*
* $ openssl ecparam -name prime256v1 -genkey -outform PEM
* -----BEGIN EC PARAMETERS-----
@@ -126,50 +158,25 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
*
* Note that we need to create the OSSL_DECODER_CTX variable each time when
* we use the different selection as a workaround.
- * https://github.com/openssl/openssl/issues/20657
+ * See https://github.com/openssl/openssl/issues/20657 for details.
*/
- OSSL_DECODER_CTX_free(dctx);
- dctx = NULL;
- dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, NULL,
- EVP_PKEY_KEYPAIR, NULL, NULL);
- if (!dctx)
- goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
- goto out;
- while (1) {
- if (OSSL_DECODER_from_bio(dctx, bio) == 1)
- goto out;
- if (BIO_eof(bio))
- break;
- pos2 = BIO_tell(bio);
- if (pos2 < 0 || pos2 <= pos)
- break;
- ossl_clear_error();
- pos = pos2;
- }
-
- OSSL_BIO_reset(bio);
- OSSL_DECODER_CTX_free(dctx);
- dctx = NULL;
- dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, NULL, 0, NULL, NULL);
- if (!dctx)
- goto out;
- if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
- goto out;
- while (1) {
- if (OSSL_DECODER_from_bio(dctx, bio) == 1)
- goto out;
- if (BIO_eof(bio))
- break;
- pos2 = BIO_tell(bio);
- if (pos2 < 0 || pos2 <= pos)
- break;
- ossl_clear_error();
- pos = pos2;
+ int selections[] = {
+ EVP_PKEY_KEYPAIR,
+ EVP_PKEY_KEY_PARAMETERS,
+ EVP_PKEY_PUBLIC_KEY
+ };
+ int selection_num = (int)(sizeof(selections) / sizeof(int));
+ int i, j;
+
+ for (i = 0; i < input_type_num; i++) {
+ for (j = 0; j < selection_num; j++) {
+ pkey = ossl_pkey_read(bio, input_types[i], selections[j], pass);
+ if (pkey) {
+ goto out;
+ }
+ }
}
-
out:
- OSSL_DECODER_CTX_free(dctx);
return pkey;
}
#else
diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb
index da3ae5d6..5fe37e2d 100644
--- a/test/openssl/test_pkey.rb
+++ b/test/openssl/test_pkey.rb
@@ -82,8 +82,6 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
end
def test_ed25519
- pend_on_openssl_issue_21493
-
# Test vector from RFC 8032 Section 7.1 TEST 2
priv_pem = <<~EOF
-----BEGIN PRIVATE KEY-----
@@ -148,8 +146,6 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
end
def test_x25519
- pend_on_openssl_issue_21493
-
# Test vector from RFC 7748 Section 6.1
alice_pem = <<~EOF
-----BEGIN PRIVATE KEY-----
@@ -202,8 +198,6 @@ class OpenSSL::TestPKey < OpenSSL::PKeyTestCase
end
def test_compare?
- pend_on_openssl_issue_21493
-
key1 = Fixtures.pkey("rsa1024")
key2 = Fixtures.pkey("rsa1024")
key3 = Fixtures.pkey("rsa2048")
diff --git a/test/openssl/utils.rb b/test/openssl/utils.rb
index b5ffbe1c..3d4d05fe 100644
--- a/test/openssl/utils.rb
+++ b/test/openssl/utils.rb
@@ -144,22 +144,6 @@ module OpenSSL::TestUtils
return false unless version
!major || (version.map(&:to_i) <=> [major, minor, fix]) >= 0
end
-
- # OpenSSL 3: x25519 a decode from and then encode to a pem file corrupts the
- # key if fips+base provider is used
- # This issue happens in OpenSSL between 3.0,0 and 3.0.10 or between 3.1.0 and
- # 3.1.2.
- # https://github.com/openssl/openssl/issues/21493
- # https://github.com/openssl/openssl/pull/21519
- def pend_on_openssl_issue_21493
- if OpenSSL.fips_mode &&
- (
- (openssl?(3, 0, 0, 0) && !openssl?(3, 0, 0, 11)) ||
- (openssl?(3, 1, 0, 0) && !openssl?(3, 1, 0, 3))
- )
- pend('See <https://github.com/openssl/openssl/issues/21493>')
- end
- end
end
class OpenSSL::TestCase < Test::Unit::TestCase