@@ -82,30 +82,62 @@ ossl_pkey_new(EVP_PKEY *pkey)
82
82
#if OSSL_OPENSSL_PREREQ (3 , 0 , 0 )
83
83
# include <openssl/decoder.h>
84
84
85
- EVP_PKEY *
86
- ossl_pkey_read_generic (BIO * bio , VALUE pass )
85
+ static EVP_PKEY *
86
+ ossl_pkey_read (BIO * bio , const char * input_type , int selection , VALUE pass )
87
87
{
88
88
void * ppass = (void * )pass ;
89
89
OSSL_DECODER_CTX * dctx ;
90
90
EVP_PKEY * pkey = NULL ;
91
91
int pos = 0 , pos2 ;
92
92
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 );
94
95
if (!dctx )
95
96
goto out ;
96
- if (OSSL_DECODER_CTX_set_pem_password_cb (dctx , ossl_pem_passwd_cb , ppass ) != 1 )
97
- goto out ;
98
-
99
- /* First check DER */
100
- if (OSSL_DECODER_from_bio (dctx , bio ) == 1 )
97
+ if (OSSL_DECODER_CTX_set_pem_password_cb (dctx , ossl_pem_passwd_cb ,
98
+ ppass ) != 1 )
101
99
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 :
102
112
OSSL_BIO_reset (bio );
113
+ OSSL_DECODER_CTX_free (dctx );
114
+ return pkey ;
115
+ }
103
116
117
+ EVP_PKEY *
118
+ ossl_pkey_read_generic (BIO * bio , VALUE pass )
119
+ {
120
+ EVP_PKEY * pkey = NULL ;
121
+ /* First check DER, then check PEM. */
122
+ const char * input_types [] = {"DER" , "PEM" };
123
+ int input_type_num = (int )(sizeof (input_types ) / sizeof (char * ));
104
124
/*
105
- * Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed.
125
+ * Non-zero selections to try to decode.
126
+ *
127
+ * See EVP_PKEY_fromdata(3) - Selections to see all the selections.
106
128
*
107
- * First check for private key formats. This is to keep compatibility with
108
- * ruby/openssl < 3.0 which decoded the following as a private key.
129
+ * This is a workaround for the decoder failing to decode or returning
130
+ * bogus keys with selection 0, if a key management provider is different
131
+ * from a decoder provider. The workaround is to avoid using selection 0.
132
+ *
133
+ * Affected OpenSSL versions: >= 3.1.0, <= 3.1.2, or >= 3.0.0, <= 3.0.10
134
+ * Fixed OpenSSL versions: 3.2, next release of the 3.1.z and 3.0.z
135
+ *
136
+ * See https://github.com/openssl/openssl/pull/21519 for details.
137
+ *
138
+ * First check for private key formats (EVP_PKEY_KEYPAIR). This is to keep
139
+ * compatibility with ruby/openssl < 3.0 which decoded the following as a
140
+ * private key.
109
141
*
110
142
* $ openssl ecparam -name prime256v1 -genkey -outform PEM
111
143
* -----BEGIN EC PARAMETERS-----
@@ -126,50 +158,25 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
126
158
*
127
159
* Note that we need to create the OSSL_DECODER_CTX variable each time when
128
160
* we use the different selection as a workaround.
129
- * https://github.com/openssl/openssl/issues/20657
161
+ * See https://github.com/openssl/openssl/issues/20657 for details.
130
162
*/
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 )
138
- 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 ;
149
- }
150
-
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 )
161
- 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 ;
163
+ int selections [] = {
164
+ EVP_PKEY_KEYPAIR ,
165
+ EVP_PKEY_KEY_PARAMETERS ,
166
+ EVP_PKEY_PUBLIC_KEY
167
+ };
168
+ int selection_num = (int )(sizeof (selections ) / sizeof (int ));
169
+ int i , j ;
170
+
171
+ for (i = 0 ; i < input_type_num ; i ++ ) {
172
+ for (j = 0 ; j < selection_num ; j ++ ) {
173
+ pkey = ossl_pkey_read (bio , input_types [i ], selections [j ], pass );
174
+ if (pkey ) {
175
+ goto out ;
176
+ }
177
+ }
169
178
}
170
-
171
179
out :
172
- OSSL_DECODER_CTX_free (dctx );
173
180
return pkey ;
174
181
}
175
182
#else
0 commit comments