Skip to content

Commit 161a0b9

Browse files
committed
ossl_pkey.c: Workaround: Decode with non-zero selections.
This is a workaround for the decoding issue in ossl_pkey_read_generic(). The issue happens in the case that a key management provider is different from a decoding provider. Try all the non-zero selections EVP_PKEY_KEY_PARAMETERS, EVP_PKEY_PUBLIC_KEY and EVP_PKEY_PUBLIC_KEY in order, instead of selection 0 for OpenSSL 3 to avoid the issue.
1 parent a74fbaf commit 161a0b9

File tree

1 file changed

+60
-44
lines changed

1 file changed

+60
-44
lines changed

ext/openssl/ossl_pkey.c

Lines changed: 60 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -83,23 +83,69 @@ ossl_pkey_new(EVP_PKEY *pkey)
8383
# include <openssl/decoder.h>
8484

8585
EVP_PKEY *
86-
ossl_pkey_read_generic(BIO *bio, VALUE pass)
86+
ossl_pkey_read(BIO *bio, const char *input_type, int selection, VALUE pass)
8787
{
8888
void *ppass = (void *)pass;
89-
OSSL_DECODER_CTX *dctx;
89+
OSSL_DECODER_CTX *dctx = NULL;
9090
EVP_PKEY *pkey = NULL;
91-
int pos = 0, pos2;
91+
int pos = 0, pos2 = 0;
9292

93-
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "DER", NULL, NULL, 0, NULL, NULL);
93+
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, input_type, NULL, NULL,
94+
selection, NULL, NULL);
9495
if (!dctx)
9596
goto out;
96-
if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
97+
if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb,
98+
ppass) != 1)
9799
goto out;
100+
while (1) {
101+
if (OSSL_DECODER_from_bio(dctx, bio) == 1)
102+
goto out;
103+
if (BIO_eof(bio))
104+
break;
105+
pos2 = BIO_tell(bio);
106+
if (pos2 < 0 || pos2 <= pos)
107+
break;
108+
ossl_clear_error();
109+
pos = pos2;
110+
}
111+
out:
112+
OSSL_BIO_reset(bio);
113+
OSSL_DECODER_CTX_free(dctx);
114+
return pkey;
115+
}
116+
117+
EVP_PKEY *
118+
ossl_pkey_read_generic(BIO *bio, VALUE pass)
119+
{
120+
EVP_PKEY *pkey = NULL;
121+
/* Non-zero selections to try to decode.
122+
*
123+
* See EVP_PKEY_fromdata(3) - Selections to see all the selections.
124+
*
125+
* This is a workaround for the decoder failing to decode or returning
126+
* bogus keys with selection 0, if a key management provider is different
127+
* from a decoder provider. The workaround is to avoid using selection 0.
128+
*
129+
* Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10
130+
* Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z
131+
*
132+
* See <https://github.com/openssl/openssl/pull/21519> for details.
133+
*/
134+
int selections[] = {
135+
EVP_PKEY_KEY_PARAMETERS,
136+
EVP_PKEY_PUBLIC_KEY,
137+
EVP_PKEY_KEYPAIR
138+
};
139+
int i = 0;
140+
int selection_num = sizeof(selections) / sizeof(int);
98141

99142
/* First check DER */
100-
if (OSSL_DECODER_from_bio(dctx, bio) == 1)
101-
goto out;
102-
OSSL_BIO_reset(bio);
143+
for (i = 0; i < selection_num; i++) {
144+
pkey = ossl_pkey_read(bio, "DER", selections[i], pass);
145+
if (pkey) {
146+
goto out;
147+
}
148+
}
103149

104150
/*
105151
* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed.
@@ -128,48 +174,18 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
128174
* we use the different selection as a workaround.
129175
* https://github.com/openssl/openssl/issues/20657
130176
*/
131-
OSSL_DECODER_CTX_free(dctx);
132-
dctx = NULL;
133-
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, NULL,
134-
EVP_PKEY_KEYPAIR, NULL, NULL);
135-
if (!dctx)
136-
goto out;
137-
if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
177+
pkey = ossl_pkey_read(bio, "PEM", EVP_PKEY_KEYPAIR, pass);
178+
if (pkey) {
138179
goto out;
139-
while (1) {
140-
if (OSSL_DECODER_from_bio(dctx, bio) == 1)
141-
goto out;
142-
if (BIO_eof(bio))
143-
break;
144-
pos2 = BIO_tell(bio);
145-
if (pos2 < 0 || pos2 <= pos)
146-
break;
147-
ossl_clear_error();
148-
pos = pos2;
149180
}
150181

151-
OSSL_BIO_reset(bio);
152-
OSSL_DECODER_CTX_free(dctx);
153-
dctx = NULL;
154-
dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, NULL, 0, NULL, NULL);
155-
if (!dctx)
156-
goto out;
157-
if (OSSL_DECODER_CTX_set_pem_password_cb(dctx, ossl_pem_passwd_cb, ppass) != 1)
158-
goto out;
159-
while (1) {
160-
if (OSSL_DECODER_from_bio(dctx, bio) == 1)
182+
for (i = 0; i < selection_num; i++) {
183+
pkey = ossl_pkey_read(bio, "PEM", selections[i], pass);
184+
if (pkey) {
161185
goto out;
162-
if (BIO_eof(bio))
163-
break;
164-
pos2 = BIO_tell(bio);
165-
if (pos2 < 0 || pos2 <= pos)
166-
break;
167-
ossl_clear_error();
168-
pos = pos2;
186+
}
169187
}
170-
171188
out:
172-
OSSL_DECODER_CTX_free(dctx);
173189
return pkey;
174190
}
175191
#else

0 commit comments

Comments
 (0)