@@ -99,17 +99,56 @@ ossl_pkey_read_generic(BIO *bio, VALUE pass)
9999 /* First check DER */
100100 if (OSSL_DECODER_from_bio (dctx , bio ) == 1 )
101101 goto out ;
102+ OSSL_BIO_reset (bio );
102103
103104 /* Then check PEM; multiple OSSL_DECODER_from_bio() calls may be needed */
104- OSSL_BIO_reset (bio );
105105 if (OSSL_DECODER_CTX_set_input_type (dctx , "PEM" ) != 1 )
106106 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 )
109131 goto out ;
132+ if (BIO_eof (bio ))
133+ break ;
110134 pos2 = BIO_tell (bio );
111135 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 )
112145 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 ();
113152 pos = pos2 ;
114153 }
115154
0 commit comments