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 = \ 45 OSSL_ENCODER_CTX_new_for_##type(x, PEM_SELECTION_##asn1, \ 46 "PEM", PEM_STRUCTURE_##asn1, \ 47 (pq)); \ 48 \ 49 if (OSSL_ENCODER_CTX_get_num_encoders(ctx) == 0) { \ 50 OSSL_ENCODER_CTX_free(ctx); \ 51 goto legacy; \ 52 } 53 # define IMPLEMENT_PEM_provided_write_body_pass() \ 54 ret = 1; \ 55 if (kstr == NULL && cb == NULL) { \ 56 if (u != NULL) { \ 57 kstr = u; \ 58 klen = strlen(u); \ 59 } else { \ 60 cb = PEM_def_callback; \ 61 } \ 62 } \ 63 if (enc != NULL) { \ 64 ret = 0; \ 65 if (OSSL_ENCODER_CTX_set_cipher(ctx, EVP_CIPHER_get0_name(enc), \ 66 NULL)) { \ 67 ret = 1; \ 68 if (kstr != NULL \ 69 && !OSSL_ENCODER_CTX_set_passphrase(ctx, kstr, klen)) \ 70 ret = 0; \ 71 else if (cb != NULL \ 72 && !OSSL_ENCODER_CTX_set_pem_password_cb(ctx, \ 73 cb, u)) \ 74 ret = 0; \ 75 } \ 76 } \ 77 if (!ret) { \ 78 OSSL_ENCODER_CTX_free(ctx); \ 79 return 0; \ 80 } 81 # define IMPLEMENT_PEM_provided_write_body_main(type, outtype) \ 82 ret = OSSL_ENCODER_to_##outtype(ctx, out); \ 83 OSSL_ENCODER_CTX_free(ctx); \ 84 return ret 85 # define IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 86 writename) \ 87 legacy: \ 88 return PEM_ASN1_##writename((i2d_of_void *)i2d_##asn1, str, out, \ 89 x, NULL, NULL, 0, NULL, NULL) 90 # define IMPLEMENT_PEM_provided_write_body_fallback_cb(str, asn1, \ 91 writename) \ 92 legacy: \ 93 return PEM_ASN1_##writename##((i2d_of_void *)i2d_##asn1, str, out, \ 94 x, enc, kstr, klen, cb, u) 95 96 # define IMPLEMENT_PEM_provided_write_to(name, TYPE, type, str, asn1, \ 97 OUTTYPE, outtype, writename) \ 98 PEM_write_fnsig(name, TYPE, OUTTYPE, writename) \ 99 { \ 100 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, NULL); \ 101 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 102 IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 103 writename); \ 104 } \ 105 PEM_write_ex_fnsig(name, TYPE, OUTTYPE, writename) \ 106 { \ 107 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, propq); \ 108 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 109 IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 110 writename); \ 111 } 112 113 114 # define IMPLEMENT_PEM_provided_write_cb_to(name, TYPE, type, str, asn1, \ 115 OUTTYPE, outtype, writename) \ 116 PEM_write_cb_fnsig(name, TYPE, OUTTYPE, writename) \ 117 { \ 118 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, NULL); \ 119 IMPLEMENT_PEM_provided_write_body_pass(); \ 120 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 121 IMPLEMENT_PEM_provided_write_body_fallback_cb(str, asn1, \ 122 writename); \ 123 } \ 124 PEM_write_ex_cb_fnsig(name, TYPE, OUTTYPE, writename) \ 125 { \ 126 IMPLEMENT_PEM_provided_write_body_vars(type, asn1, propq); \ 127 IMPLEMENT_PEM_provided_write_body_pass(); \ 128 IMPLEMENT_PEM_provided_write_body_main(type, outtype); \ 129 IMPLEMENT_PEM_provided_write_body_fallback(str, asn1, \ 130 writename); \ 131 } 132 133 # ifdef OPENSSL_NO_STDIO 134 135 # define IMPLEMENT_PEM_provided_write_fp(name, TYPE, type, str, asn1) 136 # define IMPLEMENT_PEM_provided_write_cb_fp(name, TYPE, type, str, asn1) 137 138 # else 139 140 # define IMPLEMENT_PEM_provided_write_fp(name, TYPE, type, str, asn1) \ 141 IMPLEMENT_PEM_provided_write_to(name, TYPE, type, str, asn1, FILE, fp, write) 142 # define IMPLEMENT_PEM_provided_write_cb_fp(name, TYPE, type, str, asn1) \ 143 IMPLEMENT_PEM_provided_write_cb_to(name, TYPE, type, str, asn1, FILE, fp, write) 144 145 # endif 146 147 # define IMPLEMENT_PEM_provided_write_bio(name, TYPE, type, str, asn1) \ 148 IMPLEMENT_PEM_provided_write_to(name, TYPE, type, str, asn1, BIO, bio, write_bio) 149 # define IMPLEMENT_PEM_provided_write_cb_bio(name, TYPE, type, str, asn1) \ 150 IMPLEMENT_PEM_provided_write_cb_to(name, TYPE, type, str, asn1, BIO, bio, write_bio) 151 152 # define IMPLEMENT_PEM_provided_write(name, TYPE, type, str, asn1) \ 153 IMPLEMENT_PEM_provided_write_bio(name, TYPE, type, str, asn1) \ 154 IMPLEMENT_PEM_provided_write_fp(name, TYPE, type, str, asn1) 155 156 # define IMPLEMENT_PEM_provided_write_cb(name, TYPE, type, str, asn1) \ 157 IMPLEMENT_PEM_provided_write_cb_bio(name, TYPE, type, str, asn1) \ 158 IMPLEMENT_PEM_provided_write_cb_fp(name, TYPE, type, str, asn1) 159 160 # define IMPLEMENT_PEM_provided_rw(name, TYPE, type, str, asn1) \ 161 IMPLEMENT_PEM_read(name, TYPE, str, asn1) \ 162 IMPLEMENT_PEM_provided_write(name, TYPE, type, str, asn1) 163 164 # define IMPLEMENT_PEM_provided_rw_cb(name, TYPE, type, str, asn1) \ 165 IMPLEMENT_PEM_read(name, TYPE, str, asn1) \ 166 IMPLEMENT_PEM_provided_write_cb(name, TYPE, type, str, asn1) 167 168