Home | History | Annotate | Line # | Download | only in pem
      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