2 * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 /* We need to use some deprecated APIs */
11 #define OPENSSL_SUPPRESS_DEPRECATED
14 #include <openssl/buffer.h>
15 #include <openssl/objects.h>
16 #include <openssl/evp.h>
17 #include <openssl/x509.h>
18 #include <openssl/pkcs12.h>
19 #include <openssl/pem.h>
20 #include <openssl/engine.h>
21 #include <openssl/dh.h>
22 #include <openssl/decoder.h>
23 #include <openssl/ui.h>
24 #include "internal/cryptlib.h"
25 #include "internal/passphrase.h"
26 #include "crypto/asn1.h"
27 #include "crypto/x509.h"
28 #include "crypto/evp.h"
29 #include "pem_local.h"
31 int ossl_pem_check_suffix(const char *pem_str
, const char *suffix
);
33 static EVP_PKEY
*pem_read_bio_key_decoder(BIO
*bp
, EVP_PKEY
**x
,
34 pem_password_cb
*cb
, void *u
,
39 EVP_PKEY
*pkey
= NULL
;
40 OSSL_DECODER_CTX
*dctx
= NULL
;
43 if ((pos
= BIO_tell(bp
)) < 0)
44 /* We can depend on BIO_tell() thanks to the BIO_f_readbuffer() */
47 dctx
= OSSL_DECODER_CTX_new_for_pkey(&pkey
, "PEM", NULL
, NULL
,
48 selection
, libctx
, propq
);
54 cb
= PEM_def_callback
;
56 if (!OSSL_DECODER_CTX_set_pem_password_cb(dctx
, cb
, u
))
60 while (!OSSL_DECODER_from_bio(dctx
, bp
) || pkey
== NULL
)
61 if (BIO_eof(bp
) != 0 || (newpos
= BIO_tell(bp
)) < 0 || newpos
<= pos
) {
62 ERR_clear_last_mark();
65 if (ERR_GET_REASON(ERR_peek_error()) == ERR_R_UNSUPPORTED
) {
66 /* unsupported PEM data, try again */
70 /* other error, bail out */
71 ERR_clear_last_mark();
78 if (!evp_keymgmt_util_has(pkey
, selection
)) {
81 ERR_raise(ERR_LIB_PEM
, PEM_R_UNSUPPORTED_KEY_COMPONENTS
);
91 OSSL_DECODER_CTX_free(dctx
);
95 static EVP_PKEY
*pem_read_bio_key_legacy(BIO
*bp
, EVP_PKEY
**x
,
96 pem_password_cb
*cb
, void *u
,
102 const unsigned char *p
= NULL
;
103 unsigned char *data
= NULL
;
106 EVP_PKEY
*ret
= NULL
;
108 ERR_set_mark(); /* not interested in PEM read errors */
109 if (selection
& OSSL_KEYMGMT_SELECT_PRIVATE_KEY
) {
110 if (!PEM_bytes_read_bio_secmem(&data
, &len
, &nm
,
117 const char *pem_string
= PEM_STRING_PARAMETERS
;
119 if (selection
& OSSL_KEYMGMT_SELECT_PUBLIC_KEY
)
120 pem_string
= PEM_STRING_PUBLIC
;
121 if (!PEM_bytes_read_bio(&data
, &len
, &nm
,
128 ERR_clear_last_mark();
131 if (strcmp(nm
, PEM_STRING_PKCS8INF
) == 0) {
132 PKCS8_PRIV_KEY_INFO
*p8inf
;
134 if ((p8inf
= d2i_PKCS8_PRIV_KEY_INFO(NULL
, &p
, len
)) == NULL
)
136 ret
= evp_pkcs82pkey_legacy(p8inf
, libctx
, propq
);
141 PKCS8_PRIV_KEY_INFO_free(p8inf
);
142 } else if (strcmp(nm
, PEM_STRING_PKCS8
) == 0) {
143 PKCS8_PRIV_KEY_INFO
*p8inf
;
146 char psbuf
[PEM_BUFSIZE
];
148 if ((p8
= d2i_X509_SIG(NULL
, &p
, len
)) == NULL
)
151 klen
= cb(psbuf
, PEM_BUFSIZE
, 0, u
);
153 klen
= PEM_def_callback(psbuf
, PEM_BUFSIZE
, 0, u
);
155 ERR_raise(ERR_LIB_PEM
, PEM_R_BAD_PASSWORD_READ
);
159 p8inf
= PKCS8_decrypt(p8
, psbuf
, klen
);
161 OPENSSL_cleanse(psbuf
, klen
);
164 ret
= evp_pkcs82pkey_legacy(p8inf
, libctx
, propq
);
169 PKCS8_PRIV_KEY_INFO_free(p8inf
);
170 } else if ((slen
= ossl_pem_check_suffix(nm
, "PRIVATE KEY")) > 0) {
171 const EVP_PKEY_ASN1_METHOD
*ameth
;
172 ameth
= EVP_PKEY_asn1_find_str(NULL
, nm
, slen
);
173 if (ameth
== NULL
|| ameth
->old_priv_decode
== NULL
)
175 ret
= ossl_d2i_PrivateKey_legacy(ameth
->pkey_id
, x
, &p
, len
, libctx
,
177 } else if (selection
& OSSL_KEYMGMT_SELECT_PUBLIC_KEY
) {
178 ret
= ossl_d2i_PUBKEY_legacy(x
, &p
, len
);
179 } else if ((slen
= ossl_pem_check_suffix(nm
, "PARAMETERS")) > 0) {
180 ret
= EVP_PKEY_new();
183 if (!EVP_PKEY_set_type_str(ret
, nm
, slen
)
184 || !ret
->ameth
->param_decode
185 || !ret
->ameth
->param_decode(ret
, &p
, len
)) {
197 if (ret
== NULL
&& ERR_peek_last_error() == 0)
198 /* ensure some error is reported but do not hide the real one */
199 ERR_raise(ERR_LIB_PEM
, ERR_R_ASN1_LIB
);
201 OPENSSL_secure_free(nm
);
202 OPENSSL_secure_clear_free(data
, len
);
206 static EVP_PKEY
*pem_read_bio_key(BIO
*bp
, EVP_PKEY
**x
,
207 pem_password_cb
*cb
, void *u
,
208 OSSL_LIB_CTX
*libctx
,
212 EVP_PKEY
*ret
= NULL
;
215 struct ossl_passphrase_data_st pwdata
= { 0 };
217 if ((pos
= BIO_tell(bp
)) < 0) {
218 new_bio
= BIO_new(BIO_f_readbuffer());
221 bp
= BIO_push(new_bio
, bp
);
226 cb
= PEM_def_callback
;
228 if (!ossl_pw_set_pem_password_cb(&pwdata
, cb
, u
)
229 || !ossl_pw_enable_passphrase_caching(&pwdata
))
233 ret
= pem_read_bio_key_decoder(bp
, x
, ossl_pw_pem_password
, &pwdata
,
234 libctx
, propq
, selection
);
236 && (BIO_seek(bp
, pos
) < 0
237 || (ret
= pem_read_bio_key_legacy(bp
, x
,
238 ossl_pw_pem_password
, &pwdata
,
240 selection
)) == NULL
))
241 ERR_clear_last_mark();
246 ossl_pw_clear_passphrase_data(&pwdata
);
247 if (new_bio
!= NULL
) {
254 EVP_PKEY
*PEM_read_bio_PUBKEY_ex(BIO
*bp
, EVP_PKEY
**x
,
255 pem_password_cb
*cb
, void *u
,
256 OSSL_LIB_CTX
*libctx
, const char *propq
)
258 return pem_read_bio_key(bp
, x
, cb
, u
, libctx
, propq
,
259 EVP_PKEY_PUBLIC_KEY
);
262 EVP_PKEY
*PEM_read_bio_PUBKEY(BIO
*bp
, EVP_PKEY
**x
, pem_password_cb
*cb
,
265 return PEM_read_bio_PUBKEY_ex(bp
, x
, cb
, u
, NULL
, NULL
);
268 #ifndef OPENSSL_NO_STDIO
269 EVP_PKEY
*PEM_read_PUBKEY_ex(FILE *fp
, EVP_PKEY
**x
,
270 pem_password_cb
*cb
, void *u
,
271 OSSL_LIB_CTX
*libctx
, const char *propq
)
276 if ((b
= BIO_new(BIO_s_file())) == NULL
) {
277 ERR_raise(ERR_LIB_PEM
, ERR_R_BUF_LIB
);
280 BIO_set_fp(b
, fp
, BIO_NOCLOSE
);
281 ret
= PEM_read_bio_PUBKEY_ex(b
, x
, cb
, u
, libctx
, propq
);
286 EVP_PKEY
*PEM_read_PUBKEY(FILE *fp
, EVP_PKEY
**x
, pem_password_cb
*cb
, void *u
)
288 return PEM_read_PUBKEY_ex(fp
, x
, cb
, u
, NULL
, NULL
);
292 EVP_PKEY
*PEM_read_bio_PrivateKey_ex(BIO
*bp
, EVP_PKEY
**x
,
293 pem_password_cb
*cb
, void *u
,
294 OSSL_LIB_CTX
*libctx
, const char *propq
)
296 return pem_read_bio_key(bp
, x
, cb
, u
, libctx
, propq
,
300 EVP_PKEY
*PEM_read_bio_PrivateKey(BIO
*bp
, EVP_PKEY
**x
, pem_password_cb
*cb
,
303 return PEM_read_bio_PrivateKey_ex(bp
, x
, cb
, u
, NULL
, NULL
);
306 PEM_write_cb_ex_fnsig(PrivateKey
, EVP_PKEY
, BIO
, write_bio
)
308 IMPLEMENT_PEM_provided_write_body_vars(pkey
, PrivateKey
, propq
);
310 IMPLEMENT_PEM_provided_write_body_pass();
311 IMPLEMENT_PEM_provided_write_body_main(pkey
, bio
);
314 if (x
->ameth
== NULL
|| x
->ameth
->priv_encode
!= NULL
)
315 return PEM_write_bio_PKCS8PrivateKey(out
, x
, enc
,
316 (const char *)kstr
, klen
, cb
, u
);
317 return PEM_write_bio_PrivateKey_traditional(out
, x
, enc
, kstr
, klen
, cb
, u
);
320 PEM_write_cb_fnsig(PrivateKey
, EVP_PKEY
, BIO
, write_bio
)
322 return PEM_write_bio_PrivateKey_ex(out
, x
, enc
, kstr
, klen
, cb
, u
,
327 * Note: there is no way to tell a provided pkey encoder to use "traditional"
328 * encoding. Therefore, if the pkey is provided, we try to take a copy
330 int PEM_write_bio_PrivateKey_traditional(BIO
*bp
, const EVP_PKEY
*x
,
331 const EVP_CIPHER
*enc
,
332 const unsigned char *kstr
, int klen
,
333 pem_password_cb
*cb
, void *u
)
336 EVP_PKEY
*copy
= NULL
;
339 if (evp_pkey_is_assigned(x
)
340 && evp_pkey_is_provided(x
)
341 && evp_pkey_copy_downgraded(©
, x
))
344 if (x
->ameth
== NULL
|| x
->ameth
->old_priv_encode
== NULL
) {
345 ERR_raise(ERR_LIB_PEM
, PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE
);
349 BIO_snprintf(pem_str
, 80, "%s PRIVATE KEY", x
->ameth
->pem_str
);
350 ret
= PEM_ASN1_write_bio((i2d_of_void
*)i2d_PrivateKey
,
351 pem_str
, bp
, x
, enc
, kstr
, klen
, cb
, u
);
357 EVP_PKEY
*PEM_read_bio_Parameters_ex(BIO
*bp
, EVP_PKEY
**x
,
358 OSSL_LIB_CTX
*libctx
, const char *propq
)
360 return pem_read_bio_key(bp
, x
, NULL
, NULL
, libctx
, propq
,
361 EVP_PKEY_KEY_PARAMETERS
);
364 EVP_PKEY
*PEM_read_bio_Parameters(BIO
*bp
, EVP_PKEY
**x
)
366 return PEM_read_bio_Parameters_ex(bp
, x
, NULL
, NULL
);
369 PEM_write_fnsig(Parameters
, EVP_PKEY
, BIO
, write_bio
)
372 IMPLEMENT_PEM_provided_write_body_vars(pkey
, Parameters
, NULL
);
374 IMPLEMENT_PEM_provided_write_body_main(pkey
, bio
);
377 if (!x
->ameth
|| !x
->ameth
->param_encode
)
380 BIO_snprintf(pem_str
, 80, "%s PARAMETERS", x
->ameth
->pem_str
);
381 return PEM_ASN1_write_bio((i2d_of_void
*)x
->ameth
->param_encode
,
382 pem_str
, out
, x
, NULL
, NULL
, 0, 0, NULL
);
385 #ifndef OPENSSL_NO_STDIO
386 EVP_PKEY
*PEM_read_PrivateKey_ex(FILE *fp
, EVP_PKEY
**x
, pem_password_cb
*cb
,
387 void *u
, OSSL_LIB_CTX
*libctx
,
393 if ((b
= BIO_new(BIO_s_file())) == NULL
) {
394 ERR_raise(ERR_LIB_PEM
, ERR_R_BUF_LIB
);
397 BIO_set_fp(b
, fp
, BIO_NOCLOSE
);
398 ret
= PEM_read_bio_PrivateKey_ex(b
, x
, cb
, u
, libctx
, propq
);
403 EVP_PKEY
*PEM_read_PrivateKey(FILE *fp
, EVP_PKEY
**x
, pem_password_cb
*cb
,
406 return PEM_read_PrivateKey_ex(fp
, x
, cb
, u
, NULL
, NULL
);
409 PEM_write_cb_ex_fnsig(PrivateKey
, EVP_PKEY
, FILE, write
)
414 if ((b
= BIO_new_fp(out
, BIO_NOCLOSE
)) == NULL
) {
415 ERR_raise(ERR_LIB_PEM
, ERR_R_BUF_LIB
);
418 ret
= PEM_write_bio_PrivateKey_ex(b
, x
, enc
, kstr
, klen
, cb
, u
,
424 PEM_write_cb_fnsig(PrivateKey
, EVP_PKEY
, FILE, write
)
426 return PEM_write_PrivateKey_ex(out
, x
, enc
, kstr
, klen
, cb
, u
, NULL
, NULL
);