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