@@ -99,17 +99,56 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
99
99
/* First check DER */
100
100
if (OSSL_DECODER_from_bio (dctx , bio ) == 1 )
101
101
goto out ;
102
+ OSSL_BIO_reset (bio );
102
103
103
104
/* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */
104
- OSSL_BIO_reset (bio );
105
105
if (OSSL_DECODER_CTX_set_input_type (dctx , "PEM" ) != 1 )
106
106
goto out ;
107
- while (OSSL_DECODER_from_bio (dctx , bio ) != 1 ) {
108
- if (BIO_eof (bio ))
107
+ /*
108
+ * First check for private key formats. This is to keep compatibility with
109
+ * ruby/openssl < 3.0 which decoded the following as a private key.
110
+ *
111
+ * $ openssl ecparam -name prime256v1 -genkey -outform PEM
112
+ * -----BEGIN EC PARAMETERS-----
113
+ * BggqhkjOPQMBBw==
114
+ * -----END EC PARAMETERS-----
115
+ * -----BEGIN EC PRIVATE KEY-----
116
+ * MHcCAQEEIAG8ugBbA5MHkqnZ9ujQF93OyUfL9tk8sxqM5Wv5tKg5oAoGCCqGSM49
117
+ * AwEHoUQDQgAEVcjhJfkwqh5C7kGuhAf8XaAjVuG5ADwb5ayg/cJijCgs+GcXeedj
118
+ * 86avKpGH84DXUlB23C/kPt+6fXYlitUmXQ==
119
+ * -----END EC PRIVATE KEY-----
120
+ *
121
+ * While the first PEM block is a proper encoding of ECParameters, thus
122
+ * OSSL_DECODER_from_bio() would pick it up, ruby/openssl used to return
123
+ * the latter instead. Existing applications expect this behavior.
124
+ *
125
+ * Note that normally, the input is supposed to contain a single decodable
126
+ * PEM block only, so this special handling should not create a new problem.
127
+ */
128
+ OSSL_DECODER_CTX_set_selection (dctx , EVP_PKEY_KEYPAIR );
129
+ while (1 ) {
130
+ if (OSSL_DECODER_from_bio (dctx , bio ) == 1 )
109
131
goto out ;
132
+ if (BIO_eof (bio ))
133
+ break ;
110
134
pos2 = BIO_tell (bio );
111
135
if (pos2 < 0 || pos2 <= pos )
136
+ break ;
137
+ ossl_clear_error ();
138
+ pos = pos2 ;
139
+ }
140
+
141
+ OSSL_BIO_reset (bio );
142
+ OSSL_DECODER_CTX_set_selection (dctx , 0 );
143
+ while (1 ) {
144
+ if (OSSL_DECODER_from_bio (dctx , bio ) == 1 )
112
145
goto out ;
146
+ if (BIO_eof (bio ))
147
+ break ;
148
+ pos2 = BIO_tell (bio );
149
+ if (pos2 < 0 || pos2 <= pos )
150
+ break ;
151
+ ossl_clear_error ();
113
152
pos = pos2 ;
114
153
}
115
154
0 commit comments