1 /* 2 * Copyright 2019-2021 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 #include <openssl/core_dispatch.h> 11 #include <openssl/pem.h> 12 #include <openssl/encoder.h> 13 14 /* 15 * Selectors, named according to the ASN.1 names used throughout libcrypto. 16 * 17 * Note that these are not absolutely mandatory, they are rather a wishlist 18 * of sorts. The provider implementations are free to make choices that 19 * make sense for them, based on these selectors. 20 * For example, the EC backend is likely to really just output the private 21 * key to a PKCS#8 structure, even thought PEM_SELECTION_PrivateKey specifies 22 * the public key as well. This is fine, as long as the corresponding 23 * decoding operation can return an object that contains what libcrypto 24 * expects. 25 */ 26 #define PEM_SELECTION_PUBKEY EVP_PKEY_PUBLIC_KEY 27 #define PEM_SELECTION_PrivateKey EVP_PKEY_KEYPAIR 28 #define PEM_SELECTION_Parameters EVP_PKEY_KEY_PARAMETERS 29 30 /* 31 * Properties, named according to the ASN.1 names used throughout libcrypto. 32 */ 33 #define PEM_STRUCTURE_PUBKEY "SubjectPublicKeyInfo" 34 #define PEM_STRUCTURE_PrivateKey "PrivateKeyInfo" 35 #define PEM_STRUCTURE_Parameters "type-specific" 36 37 #define PEM_STRUCTURE_RSAPrivateKey "type-specific" 38 #define PEM_STRUCTURE_RSAPublicKey "type-specific" 39 40 /* Alternative IMPLEMENT macros for provided encoders */ 41 42 #define IMPLEMENT_PEM_provided_write_body_vars(type, asn1, pq) \ 43 int ret = 0; \ 44 OSSL_ENCODER_CTX *ctx = OSSL_ENCODER_CTX_new_for_##type(x, PEM_SELECTION_##asn1, \ 45 "PEM", PEM_STRUCTURE_##asn1, \ 46 (pq)); \ 47 \ 48 if (OSSL_ENCODER_CTX_get_num_encoders(ctx) == 0) { \ 49 OSSL_ENCODER_CTX_free(ctx); \ 50 goto legacy; \ 51 } 52 #define IMPLEMENT_PEM_provided_write_body_pass() \ 53 ret = 1; \ 54 if (kstr == NULL && cb == NULL) { \ 55 if (u != NULL) { \ 56 kstr = u; \ 57 klen = strlen(u); \ 58 } else { \ 59 cb = PEM_def_callback; \ 60 } \ 61 } \ 62 if (enc != NULL) { \ 63 ret = 0; \ 64 if (OSSL_ENCODER_CTX_set_cipher(ctx, EVP_CIPHER_get0_name(enc), \ 65 NULL)) { \ 66 ret = 1; \ 67 if (kstr != NULL \ 68 && !OSSL_ENCODER_CTX_set_passphrase(ctx, kstr, klen)) \ 69 ret = 0; \ 70 else if (cb != NULL \ 71 && !OSSL_ENCODER_CTX_set_pem_password_cb(ctx, \ 72 cb, u)) \ 73 ret = 0; \ 74 } \ 75 } \ 76 if (!ret) { \ 77 OSSL_ENCODER_CTX_free(ctx); \ 78 return 0; \ 79 } 80 #define IMPLEMENT_PEM_provided_write_body_main(type, outtype) \ 81 ret = OSSL_ENCODER_to_##outtype(ctx, out); \ 82 OSSL_ENCODER_CTX_free(ctx); \ 83 return ret 84 #define IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 85 writename) \ 86 legacy: \ 87 return PEM_ASN1_##writename((i2d_of_void *)i2d_##asn1, str, out, \ 88 x, NULL, NULL, 0, NULL, NULL) 89 #define IMPLEMENT_PEM_provided_write_body_fallback_cb(str, asn1, \ 90 writename) \ 91 legacy: \ 92 return PEM_ASN1_##writename##((i2d_of_void *)i2d_##asn1, str, out, \ 93 x, enc, kstr, klen, cb, u) 94 95 #define IMPLEMENT_PEM_provided_write_to(name, TYPE, type, str, asn1, \ 96 OUTTYPE, outtype, writename) \ 97 PEM_write_fnsig(name, TYPE, OUTTYPE, writename) \ 98 { \ 99 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, NULL); \ 100 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 101 IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 102 writename); \ 103 } \ 104 PEM_write_ex_fnsig(name, TYPE, OUTTYPE, writename) \ 105 { \ 106 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, propq); \ 107 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 108 IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 109 writename); \ 110 } 111 112 #define IMPLEMENT_PEM_provided_write_cb_to(name, TYPE, type, str, asn1, \ 113 OUTTYPE, outtype, writename) \ 114 PEM_write_cb_fnsig(name, TYPE, OUTTYPE, writename) \ 115 { \ 116 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, NULL); \ 117 IMPLEMENT_PEM_provided_write_body_pass(); \ 118 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 119 IMPLEMENT_PEM_provided_write_body_fallback_cb(str, asn1, \ 120 writename); \ 121 } \ 122 PEM_write_ex_cb_fnsig(name, TYPE, OUTTYPE, writename) \ 123 { \ 124 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, propq); \ 125 IMPLEMENT_PEM_provided_write_body_pass(); \ 126 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 127 IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 128 writename); \ 129 } 130 131 #ifdef OPENSSL_NO_STDIO 132 133 #define IMPLEMENT_PEM_provided_write_fp(name, TYPE, type, str, asn1) 134 #define IMPLEMENT_PEM_provided_write_cb_fp(name, TYPE, type, str, asn1) 135 136 #else 137 138 #define IMPLEMENT_PEM_provided_write_fp(name, TYPE, type, str, asn1) \ 139 IMPLEMENT_PEM_provided_write_to(name, TYPE, type, str, asn1, FILE, fp, write) 140 #define IMPLEMENT_PEM_provided_write_cb_fp(name, TYPE, type, str, asn1) \ 141 IMPLEMENT_PEM_provided_write_cb_to(name, TYPE, type, str, asn1, FILE, fp, write) 142 143 #endif 144 145 #define IMPLEMENT_PEM_provided_write_bio(name, TYPE, type, str, asn1) \ 146 IMPLEMENT_PEM_provided_write_to(name, TYPE, type, str, asn1, BIO, bio, write_bio) 147 #define IMPLEMENT_PEM_provided_write_cb_bio(name, TYPE, type, str, asn1) \ 148 IMPLEMENT_PEM_provided_write_cb_to(name, TYPE, type, str, asn1, BIO, bio, write_bio) 149 150 #define IMPLEMENT_PEM_provided_write(name, TYPE, type, str, asn1) \ 151 IMPLEMENT_PEM_provided_write_bio(name, TYPE, type, str, asn1) \ 152 IMPLEMENT_PEM_provided_write_fp(name, TYPE, type, str, asn1) 153 154 #define IMPLEMENT_PEM_provided_write_cb(name, TYPE, type, str, asn1) \ 155 IMPLEMENT_PEM_provided_write_cb_bio(name, TYPE, type, str, asn1) \ 156 IMPLEMENT_PEM_provided_write_cb_fp(name, TYPE, type, str, asn1) 157 158 #define IMPLEMENT_PEM_provided_rw(name, TYPE, type, str, asn1) \ 159 IMPLEMENT_PEM_read(name, TYPE, str, asn1) \ 160 IMPLEMENT_PEM_provided_write(name, TYPE, type, str, asn1) 161 162 #define IMPLEMENT_PEM_provided_rw_cb(name, TYPE, type, str, asn1) \ 163 IMPLEMENT_PEM_read(name, TYPE, str, asn1) \ 164 IMPLEMENT_PEM_provided_write_cb(name, TYPE, type, str, asn1) 165