/src/openssl30/crypto/pem/pem_pkey.c
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | /* | 
| 2 |  |  * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. | 
| 3 |  |  * | 
| 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 | 
| 8 |  |  */ | 
| 9 |  |  | 
| 10 |  | /* We need to use some deprecated APIs */ | 
| 11 |  | #define OPENSSL_SUPPRESS_DEPRECATED | 
| 12 |  |  | 
| 13 |  | #include <stdio.h> | 
| 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" | 
| 30 |  |  | 
| 31 |  | int ossl_pem_check_suffix(const char *pem_str, const char *suffix); | 
| 32 |  |  | 
| 33 |  | static EVP_PKEY *pem_read_bio_key_decoder(BIO *bp, EVP_PKEY **x, | 
| 34 |  |                                           pem_password_cb *cb, void *u, | 
| 35 |  |                                           OSSL_LIB_CTX *libctx, | 
| 36 |  |                                           const char *propq, | 
| 37 |  |                                           int selection) | 
| 38 | 20.3k | { | 
| 39 | 20.3k |     EVP_PKEY *pkey = NULL; | 
| 40 | 20.3k |     OSSL_DECODER_CTX *dctx = NULL; | 
| 41 | 20.3k |     int pos, newpos; | 
| 42 |  |  | 
| 43 | 20.3k |     if ((pos = BIO_tell(bp)) < 0) | 
| 44 |  |         /* We can depend on BIO_tell() thanks to the BIO_f_readbuffer() */ | 
| 45 | 0 |         return NULL; | 
| 46 |  |  | 
| 47 | 20.3k |     dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, NULL, | 
| 48 | 20.3k |                                          selection, libctx, propq); | 
| 49 |  |  | 
| 50 | 20.3k |     if (dctx == NULL) | 
| 51 | 0 |         return NULL; | 
| 52 |  |  | 
| 53 | 20.3k |     if (cb == NULL) | 
| 54 | 0 |         cb = PEM_def_callback; | 
| 55 |  |  | 
| 56 | 20.3k |     if (!OSSL_DECODER_CTX_set_pem_password_cb(dctx, cb, u)) | 
| 57 | 0 |         goto err; | 
| 58 |  |  | 
| 59 | 20.3k |     ERR_set_mark(); | 
| 60 | 20.3k |     while (!OSSL_DECODER_from_bio(dctx, bp) || pkey == NULL) | 
| 61 | 0 |         if (BIO_eof(bp) != 0 || (newpos = BIO_tell(bp)) < 0 || newpos <= pos) { | 
| 62 | 0 |             ERR_clear_last_mark(); | 
| 63 | 0 |             goto err; | 
| 64 | 0 |         } else { | 
| 65 | 0 |             if (ERR_GET_REASON(ERR_peek_error()) == ERR_R_UNSUPPORTED) { | 
| 66 |  |                 /* unsupported PEM data, try again */ | 
| 67 | 0 |                 ERR_pop_to_mark(); | 
| 68 | 0 |                 ERR_set_mark(); | 
| 69 | 0 |             } else { | 
| 70 |  |                 /* other error, bail out */ | 
| 71 | 0 |                 ERR_clear_last_mark(); | 
| 72 | 0 |                 goto err; | 
| 73 | 0 |             } | 
| 74 | 0 |             pos = newpos; | 
| 75 | 0 |         } | 
| 76 | 20.3k |     ERR_pop_to_mark(); | 
| 77 |  |  | 
| 78 |  |     /* if we were asked for private key, the public key is optional */ | 
| 79 | 20.3k |     if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) | 
| 80 | 20.3k |         selection = selection & ~OSSL_KEYMGMT_SELECT_PUBLIC_KEY; | 
| 81 |  |  | 
| 82 | 20.3k |     if (!evp_keymgmt_util_has(pkey, selection)) { | 
| 83 | 0 |         EVP_PKEY_free(pkey); | 
| 84 | 0 |         pkey = NULL; | 
| 85 | 0 |         ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_KEY_COMPONENTS); | 
| 86 | 0 |         goto err; | 
| 87 | 0 |     } | 
| 88 |  |  | 
| 89 | 20.3k |     if (x != NULL) { | 
| 90 | 0 |         EVP_PKEY_free(*x); | 
| 91 | 0 |         *x = pkey; | 
| 92 | 0 |     } | 
| 93 |  |  | 
| 94 | 20.3k |  err: | 
| 95 | 20.3k |     OSSL_DECODER_CTX_free(dctx); | 
| 96 | 20.3k |     return pkey; | 
| 97 | 20.3k | } | 
| 98 |  |  | 
| 99 |  | static EVP_PKEY *pem_read_bio_key_legacy(BIO *bp, EVP_PKEY **x, | 
| 100 |  |                                          pem_password_cb *cb, void *u, | 
| 101 |  |                                          OSSL_LIB_CTX *libctx, | 
| 102 |  |                                          const char *propq, | 
| 103 |  |                                          int selection) | 
| 104 | 0 | { | 
| 105 | 0 |     char *nm = NULL; | 
| 106 | 0 |     const unsigned char *p = NULL; | 
| 107 | 0 |     unsigned char *data = NULL; | 
| 108 | 0 |     long len; | 
| 109 | 0 |     int slen; | 
| 110 | 0 |     EVP_PKEY *ret = NULL; | 
| 111 |  | 
 | 
| 112 | 0 |     ERR_set_mark();  /* not interested in PEM read errors */ | 
| 113 | 0 |     if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0) { | 
| 114 | 0 |         if (!PEM_bytes_read_bio_secmem(&data, &len, &nm, | 
| 115 | 0 |                                        PEM_STRING_EVP_PKEY, | 
| 116 | 0 |                                        bp, cb, u)) { | 
| 117 | 0 |             ERR_pop_to_mark(); | 
| 118 | 0 |             return NULL; | 
| 119 | 0 |          } | 
| 120 | 0 |     } else { | 
| 121 | 0 |         const char *pem_string = PEM_STRING_PARAMETERS; | 
| 122 |  | 
 | 
| 123 | 0 |         if ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) | 
| 124 | 0 |             pem_string = PEM_STRING_PUBLIC; | 
| 125 | 0 |         if (!PEM_bytes_read_bio(&data, &len, &nm, | 
| 126 | 0 |                                 pem_string, | 
| 127 | 0 |                                 bp, cb, u)) { | 
| 128 | 0 |             ERR_pop_to_mark(); | 
| 129 | 0 |             return NULL; | 
| 130 | 0 |         } | 
| 131 | 0 |     } | 
| 132 | 0 |     ERR_clear_last_mark(); | 
| 133 | 0 |     p = data; | 
| 134 |  | 
 | 
| 135 | 0 |     if (strcmp(nm, PEM_STRING_PKCS8INF) == 0) { | 
| 136 | 0 |         PKCS8_PRIV_KEY_INFO *p8inf; | 
| 137 |  | 
 | 
| 138 | 0 |         if ((p8inf = d2i_PKCS8_PRIV_KEY_INFO(NULL, &p, len)) == NULL) | 
| 139 | 0 |             goto p8err; | 
| 140 | 0 |         ret = evp_pkcs82pkey_legacy(p8inf, libctx, propq); | 
| 141 | 0 |         if (x != NULL) { | 
| 142 | 0 |             EVP_PKEY_free(*x); | 
| 143 | 0 |             *x = ret; | 
| 144 | 0 |         } | 
| 145 | 0 |         PKCS8_PRIV_KEY_INFO_free(p8inf); | 
| 146 | 0 |     } else if (strcmp(nm, PEM_STRING_PKCS8) == 0) { | 
| 147 | 0 |         PKCS8_PRIV_KEY_INFO *p8inf; | 
| 148 | 0 |         X509_SIG *p8; | 
| 149 | 0 |         int klen; | 
| 150 | 0 |         char psbuf[PEM_BUFSIZE]; | 
| 151 |  | 
 | 
| 152 | 0 |         if ((p8 = d2i_X509_SIG(NULL, &p, len)) == NULL) | 
| 153 | 0 |             goto p8err; | 
| 154 | 0 |         if (cb != NULL) | 
| 155 | 0 |             klen = cb(psbuf, PEM_BUFSIZE, 0, u); | 
| 156 | 0 |         else | 
| 157 | 0 |             klen = PEM_def_callback(psbuf, PEM_BUFSIZE, 0, u); | 
| 158 | 0 |         if (klen < 0) { | 
| 159 | 0 |             ERR_raise(ERR_LIB_PEM, PEM_R_BAD_PASSWORD_READ); | 
| 160 | 0 |             X509_SIG_free(p8); | 
| 161 | 0 |             goto err; | 
| 162 | 0 |         } | 
| 163 | 0 |         p8inf = PKCS8_decrypt(p8, psbuf, klen); | 
| 164 | 0 |         X509_SIG_free(p8); | 
| 165 | 0 |         OPENSSL_cleanse(psbuf, klen); | 
| 166 | 0 |         if (p8inf == NULL) | 
| 167 | 0 |             goto p8err; | 
| 168 | 0 |         ret = evp_pkcs82pkey_legacy(p8inf, libctx, propq); | 
| 169 | 0 |         if (x != NULL) { | 
| 170 | 0 |             EVP_PKEY_free(*x); | 
| 171 | 0 |             *x = ret; | 
| 172 | 0 |         } | 
| 173 | 0 |         PKCS8_PRIV_KEY_INFO_free(p8inf); | 
| 174 | 0 |     } else if ((slen = ossl_pem_check_suffix(nm, "PRIVATE KEY")) > 0) { | 
| 175 | 0 |         const EVP_PKEY_ASN1_METHOD *ameth; | 
| 176 | 0 |         ameth = EVP_PKEY_asn1_find_str(NULL, nm, slen); | 
| 177 | 0 |         if (ameth == NULL || ameth->old_priv_decode == NULL) | 
| 178 | 0 |             goto p8err; | 
| 179 | 0 |         ret = ossl_d2i_PrivateKey_legacy(ameth->pkey_id, x, &p, len, libctx, | 
| 180 | 0 |                                          propq); | 
| 181 | 0 |     } else if ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) == 0 | 
| 182 | 0 |                && (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) { | 
| 183 |  |         /* Trying legacy PUBKEY decoding only if we do not want private key. */ | 
| 184 | 0 |         ret = ossl_d2i_PUBKEY_legacy(x, &p, len); | 
| 185 | 0 |     } else if ((selection & EVP_PKEY_KEYPAIR) == 0 | 
| 186 | 0 |                && (slen = ossl_pem_check_suffix(nm, "PARAMETERS")) > 0) { | 
| 187 |  |         /* Trying legacy params decoding only if we do not want a key. */ | 
| 188 | 0 |         ret = EVP_PKEY_new(); | 
| 189 | 0 |         if (ret == NULL) | 
| 190 | 0 |             goto err; | 
| 191 | 0 |         if (!EVP_PKEY_set_type_str(ret, nm, slen) | 
| 192 | 0 |             || !ret->ameth->param_decode | 
| 193 | 0 |             || !ret->ameth->param_decode(ret, &p, len)) { | 
| 194 | 0 |             EVP_PKEY_free(ret); | 
| 195 | 0 |             ret = NULL; | 
| 196 | 0 |             goto err; | 
| 197 | 0 |         } | 
| 198 | 0 |         if (x) { | 
| 199 | 0 |             EVP_PKEY_free(*x); | 
| 200 | 0 |             *x = ret; | 
| 201 | 0 |         } | 
| 202 | 0 |     } | 
| 203 |  |  | 
| 204 | 0 |  p8err: | 
| 205 | 0 |     if (ret == NULL && ERR_peek_last_error() == 0) | 
| 206 |  |         /* ensure some error is reported but do not hide the real one */ | 
| 207 | 0 |         ERR_raise(ERR_LIB_PEM, ERR_R_ASN1_LIB); | 
| 208 | 0 |  err: | 
| 209 | 0 |     OPENSSL_secure_free(nm); | 
| 210 | 0 |     OPENSSL_secure_clear_free(data, len); | 
| 211 | 0 |     return ret; | 
| 212 | 0 | } | 
| 213 |  |  | 
| 214 |  | static EVP_PKEY *pem_read_bio_key(BIO *bp, EVP_PKEY **x, | 
| 215 |  |                                   pem_password_cb *cb, void *u, | 
| 216 |  |                                   OSSL_LIB_CTX *libctx, | 
| 217 |  |                                   const char *propq, | 
| 218 |  |                                   int selection) | 
| 219 | 20.3k | { | 
| 220 | 20.3k |     EVP_PKEY *ret = NULL; | 
| 221 | 20.3k |     BIO *new_bio = NULL; | 
| 222 | 20.3k |     int pos; | 
| 223 | 20.3k |     struct ossl_passphrase_data_st pwdata = { 0 }; | 
| 224 |  |  | 
| 225 | 20.3k |     if ((pos = BIO_tell(bp)) < 0) { | 
| 226 | 0 |         new_bio = BIO_new(BIO_f_readbuffer()); | 
| 227 | 0 |         if (new_bio == NULL) | 
| 228 | 0 |             return NULL; | 
| 229 | 0 |         bp = BIO_push(new_bio, bp); | 
| 230 | 0 |         pos = BIO_tell(bp); | 
| 231 | 0 |     } | 
| 232 |  |  | 
| 233 | 20.3k |     if (cb == NULL) | 
| 234 | 20.3k |         cb = PEM_def_callback; | 
| 235 |  |  | 
| 236 | 20.3k |     if (!ossl_pw_set_pem_password_cb(&pwdata, cb, u) | 
| 237 | 20.3k |         || !ossl_pw_enable_passphrase_caching(&pwdata)) | 
| 238 | 0 |         goto err; | 
| 239 |  |  | 
| 240 | 20.3k |     ERR_set_mark(); | 
| 241 | 20.3k |     ret = pem_read_bio_key_decoder(bp, x, ossl_pw_pem_password, &pwdata, | 
| 242 | 20.3k |                                    libctx, propq, selection); | 
| 243 | 20.3k |     if (ret == NULL | 
| 244 | 20.3k |         && (BIO_seek(bp, pos) < 0 | 
| 245 | 0 |             || (ret = pem_read_bio_key_legacy(bp, x, | 
| 246 | 0 |                                               ossl_pw_pem_password, &pwdata, | 
| 247 | 0 |                                               libctx, propq, | 
| 248 | 0 |                                               selection)) == NULL)) | 
| 249 | 0 |         ERR_clear_last_mark(); | 
| 250 | 20.3k |     else | 
| 251 | 20.3k |         ERR_pop_to_mark(); | 
| 252 |  |  | 
| 253 | 20.3k |  err: | 
| 254 | 20.3k |     ossl_pw_clear_passphrase_data(&pwdata); | 
| 255 | 20.3k |     if (new_bio != NULL) { | 
| 256 | 0 |         BIO_pop(new_bio); | 
| 257 | 0 |         BIO_free(new_bio); | 
| 258 | 0 |     } | 
| 259 | 20.3k |     return ret; | 
| 260 | 20.3k | } | 
| 261 |  |  | 
| 262 |  | EVP_PKEY *PEM_read_bio_PUBKEY_ex(BIO *bp, EVP_PKEY **x, | 
| 263 |  |                                  pem_password_cb *cb, void *u, | 
| 264 |  |                                  OSSL_LIB_CTX *libctx, const char *propq) | 
| 265 | 0 | { | 
| 266 | 0 |     return pem_read_bio_key(bp, x, cb, u, libctx, propq, | 
| 267 | 0 |                             EVP_PKEY_PUBLIC_KEY); | 
| 268 | 0 | } | 
| 269 |  |  | 
| 270 |  | EVP_PKEY *PEM_read_bio_PUBKEY(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, | 
| 271 |  |                               void *u) | 
| 272 | 0 | { | 
| 273 | 0 |     return PEM_read_bio_PUBKEY_ex(bp, x, cb, u, NULL, NULL); | 
| 274 | 0 | } | 
| 275 |  |  | 
| 276 |  | #ifndef OPENSSL_NO_STDIO | 
| 277 |  | EVP_PKEY *PEM_read_PUBKEY_ex(FILE *fp, EVP_PKEY **x, | 
| 278 |  |                              pem_password_cb *cb, void *u, | 
| 279 |  |                              OSSL_LIB_CTX *libctx, const char *propq) | 
| 280 | 0 | { | 
| 281 | 0 |     BIO *b; | 
| 282 | 0 |     EVP_PKEY *ret; | 
| 283 |  | 
 | 
| 284 | 0 |     if ((b = BIO_new(BIO_s_file())) == NULL) { | 
| 285 | 0 |         ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); | 
| 286 | 0 |         return 0; | 
| 287 | 0 |     } | 
| 288 | 0 |     BIO_set_fp(b, fp, BIO_NOCLOSE); | 
| 289 | 0 |     ret = PEM_read_bio_PUBKEY_ex(b, x, cb, u, libctx, propq); | 
| 290 | 0 |     BIO_free(b); | 
| 291 | 0 |     return ret; | 
| 292 | 0 | } | 
| 293 |  |  | 
| 294 |  | EVP_PKEY *PEM_read_PUBKEY(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, void *u) | 
| 295 | 0 | { | 
| 296 | 0 |     return PEM_read_PUBKEY_ex(fp, x, cb, u, NULL, NULL); | 
| 297 | 0 | } | 
| 298 |  | #endif | 
| 299 |  |  | 
| 300 |  | EVP_PKEY *PEM_read_bio_PrivateKey_ex(BIO *bp, EVP_PKEY **x, | 
| 301 |  |                                      pem_password_cb *cb, void *u, | 
| 302 |  |                                      OSSL_LIB_CTX *libctx, const char *propq) | 
| 303 | 20.3k | { | 
| 304 | 20.3k |     return pem_read_bio_key(bp, x, cb, u, libctx, propq, | 
| 305 |  |                             /* we also want the public key, if available */ | 
| 306 | 20.3k |                             EVP_PKEY_KEYPAIR); | 
| 307 | 20.3k | } | 
| 308 |  |  | 
| 309 |  | EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, | 
| 310 |  |                                   void *u) | 
| 311 | 20.3k | { | 
| 312 | 20.3k |     return PEM_read_bio_PrivateKey_ex(bp, x, cb, u, NULL, NULL); | 
| 313 | 20.3k | } | 
| 314 |  |  | 
| 315 |  | PEM_write_cb_ex_fnsig(PrivateKey, EVP_PKEY, BIO, write_bio) | 
| 316 | 0 | { | 
| 317 | 0 |     IMPLEMENT_PEM_provided_write_body_vars(pkey, PrivateKey, propq); | 
| 318 |  | 
 | 
| 319 | 0 |     IMPLEMENT_PEM_provided_write_body_pass(); | 
| 320 | 0 |     IMPLEMENT_PEM_provided_write_body_main(pkey, bio); | 
| 321 |  |  | 
| 322 | 0 |  legacy: | 
| 323 | 0 |     if (x != NULL && (x->ameth == NULL || x->ameth->priv_encode != NULL)) | 
| 324 | 0 |         return PEM_write_bio_PKCS8PrivateKey(out, x, enc, | 
| 325 | 0 |                                              (const char *)kstr, klen, cb, u); | 
| 326 | 0 |     return PEM_write_bio_PrivateKey_traditional(out, x, enc, kstr, klen, cb, u); | 
| 327 | 0 | } | 
| 328 |  |  | 
| 329 |  | PEM_write_cb_fnsig(PrivateKey, EVP_PKEY, BIO, write_bio) | 
| 330 | 0 | { | 
| 331 | 0 |     return PEM_write_bio_PrivateKey_ex(out, x, enc, kstr, klen, cb, u, | 
| 332 | 0 |                                        NULL, NULL); | 
| 333 | 0 | } | 
| 334 |  |  | 
| 335 |  | /* | 
| 336 |  |  * Note: there is no way to tell a provided pkey encoder to use "traditional" | 
| 337 |  |  * encoding.  Therefore, if the pkey is provided, we try to take a copy  | 
| 338 |  |  */ | 
| 339 |  | int PEM_write_bio_PrivateKey_traditional(BIO *bp, const EVP_PKEY *x, | 
| 340 |  |                                          const EVP_CIPHER *enc, | 
| 341 |  |                                          const unsigned char *kstr, int klen, | 
| 342 |  |                                          pem_password_cb *cb, void *u) | 
| 343 | 0 | { | 
| 344 | 0 |     char pem_str[80]; | 
| 345 | 0 |     EVP_PKEY *copy = NULL; | 
| 346 | 0 |     int ret; | 
| 347 |  | 
 | 
| 348 | 0 |     if (x == NULL) | 
| 349 | 0 |         return 0; | 
| 350 |  |  | 
| 351 | 0 |     if (evp_pkey_is_assigned(x) | 
| 352 | 0 |         && evp_pkey_is_provided(x) | 
| 353 | 0 |         && evp_pkey_copy_downgraded(©, x)) | 
| 354 | 0 |         x = copy; | 
| 355 |  | 
 | 
| 356 | 0 |     if (x->ameth == NULL || x->ameth->old_priv_encode == NULL) { | 
| 357 | 0 |         ERR_raise(ERR_LIB_PEM, PEM_R_UNSUPPORTED_PUBLIC_KEY_TYPE); | 
| 358 | 0 |         EVP_PKEY_free(copy); | 
| 359 | 0 |         return 0; | 
| 360 | 0 |     } | 
| 361 | 0 |     BIO_snprintf(pem_str, 80, "%s PRIVATE KEY", x->ameth->pem_str); | 
| 362 | 0 |     ret = PEM_ASN1_write_bio((i2d_of_void *)i2d_PrivateKey, | 
| 363 | 0 |                              pem_str, bp, x, enc, kstr, klen, cb, u); | 
| 364 |  | 
 | 
| 365 | 0 |     EVP_PKEY_free(copy); | 
| 366 | 0 |     return ret; | 
| 367 | 0 | } | 
| 368 |  |  | 
| 369 |  | static int no_password_cb(char *buf, int num, int rwflag, void *userdata) | 
| 370 | 0 | { | 
| 371 | 0 |     return -1; | 
| 372 | 0 | } | 
| 373 |  |  | 
| 374 |  | EVP_PKEY *PEM_read_bio_Parameters_ex(BIO *bp, EVP_PKEY **x, | 
| 375 |  |                                      OSSL_LIB_CTX *libctx, const char *propq) | 
| 376 | 0 | { | 
| 377 |  |     /* | 
| 378 |  |      * PEM_read_bio_Parameters(_ex) should never ask for a password. Any attempt | 
| 379 |  |      * to get a password just fails. | 
| 380 |  |      */ | 
| 381 | 0 |     return pem_read_bio_key(bp, x, no_password_cb, NULL, libctx, propq, | 
| 382 | 0 |                             EVP_PKEY_KEY_PARAMETERS); | 
| 383 | 0 | } | 
| 384 |  |  | 
| 385 |  | EVP_PKEY *PEM_read_bio_Parameters(BIO *bp, EVP_PKEY **x) | 
| 386 | 0 | { | 
| 387 | 0 |     return PEM_read_bio_Parameters_ex(bp, x, NULL, NULL); | 
| 388 | 0 | } | 
| 389 |  |  | 
| 390 |  | PEM_write_fnsig(Parameters, EVP_PKEY, BIO, write_bio) | 
| 391 | 0 | { | 
| 392 | 0 |     char pem_str[80]; | 
| 393 | 0 |     IMPLEMENT_PEM_provided_write_body_vars(pkey, Parameters, NULL); | 
| 394 |  | 
 | 
| 395 | 0 |     IMPLEMENT_PEM_provided_write_body_main(pkey, bio); | 
| 396 |  |  | 
| 397 | 0 |  legacy: | 
| 398 | 0 |     if (!x->ameth || !x->ameth->param_encode) | 
| 399 | 0 |         return 0; | 
| 400 |  |  | 
| 401 | 0 |     BIO_snprintf(pem_str, 80, "%s PARAMETERS", x->ameth->pem_str); | 
| 402 | 0 |     return PEM_ASN1_write_bio((i2d_of_void *)x->ameth->param_encode, | 
| 403 | 0 |                               pem_str, out, x, NULL, NULL, 0, 0, NULL); | 
| 404 | 0 | } | 
| 405 |  |  | 
| 406 |  | #ifndef OPENSSL_NO_STDIO | 
| 407 |  | EVP_PKEY *PEM_read_PrivateKey_ex(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, | 
| 408 |  |                                  void *u, OSSL_LIB_CTX *libctx, | 
| 409 |  |                                  const char *propq) | 
| 410 | 0 | { | 
| 411 | 0 |     BIO *b; | 
| 412 | 0 |     EVP_PKEY *ret; | 
| 413 |  | 
 | 
| 414 | 0 |     if ((b = BIO_new(BIO_s_file())) == NULL) { | 
| 415 | 0 |         ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); | 
| 416 | 0 |         return 0; | 
| 417 | 0 |     } | 
| 418 | 0 |     BIO_set_fp(b, fp, BIO_NOCLOSE); | 
| 419 | 0 |     ret = PEM_read_bio_PrivateKey_ex(b, x, cb, u, libctx, propq); | 
| 420 | 0 |     BIO_free(b); | 
| 421 | 0 |     return ret; | 
| 422 | 0 | } | 
| 423 |  |  | 
| 424 |  | EVP_PKEY *PEM_read_PrivateKey(FILE *fp, EVP_PKEY **x, pem_password_cb *cb, | 
| 425 |  |                               void *u) | 
| 426 | 0 | { | 
| 427 | 0 |     return PEM_read_PrivateKey_ex(fp, x, cb, u, NULL, NULL); | 
| 428 | 0 | } | 
| 429 |  |  | 
| 430 |  | PEM_write_cb_ex_fnsig(PrivateKey, EVP_PKEY, FILE, write) | 
| 431 | 0 | { | 
| 432 | 0 |     BIO *b; | 
| 433 | 0 |     int ret; | 
| 434 |  | 
 | 
| 435 | 0 |     if ((b = BIO_new_fp(out, BIO_NOCLOSE)) == NULL) { | 
| 436 | 0 |         ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB); | 
| 437 | 0 |         return 0; | 
| 438 | 0 |     } | 
| 439 | 0 |     ret = PEM_write_bio_PrivateKey_ex(b, x, enc, kstr, klen, cb, u, | 
| 440 | 0 |                                       libctx, propq); | 
| 441 | 0 |     BIO_free(b); | 
| 442 | 0 |     return ret; | 
| 443 | 0 | } | 
| 444 |  |  | 
| 445 |  | PEM_write_cb_fnsig(PrivateKey, EVP_PKEY, FILE, write) | 
| 446 | 0 | { | 
| 447 | 0 |     return PEM_write_PrivateKey_ex(out, x, enc, kstr, klen, cb, u, NULL, NULL); | 
| 448 | 0 | } | 
| 449 |  | #endif |