1/*
2 * Copyright 2020-2025 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{-
10use OpenSSL::paramnames qw(produce_param_decoder);
11-}
12
13/*
14 * RSA low level APIs are deprecated for public use, but still ok for
15 * internal use.
16 */
17#include "internal/deprecated.h"
18
19#include <string.h>
20
21#include <openssl/core_dispatch.h>
22#include <openssl/core_names.h>
23#include <openssl/core_object.h>
24#include <openssl/crypto.h>
25#include <openssl/err.h>
26#include <openssl/params.h>
27#include <openssl/pem.h>
28#include <openssl/proverr.h>
29#include "internal/cryptlib.h"
30#include "internal/nelem.h"
31#include "internal/sizes.h"
32#include "prov/bio.h"
33#include "prov/decoders.h"
34#include "prov/implementations.h"
35#include "prov/endecoder_local.h"
36
37static int read_pem(PROV_CTX *provctx, OSSL_CORE_BIO *cin,
38                    char **pem_name, char **pem_header,
39                    unsigned char **data, long *len)
40{
41    BIO *in = ossl_bio_new_from_core_bio(provctx, cin);
42    int ok;
43
44    if (in == NULL)
45        return 0;
46    ok = (PEM_read_bio(in, pem_name, pem_header, data, len) > 0);
47
48    BIO_free(in);
49    return ok;
50}
51
52static OSSL_FUNC_decoder_newctx_fn pem2der_newctx;
53static OSSL_FUNC_decoder_freectx_fn pem2der_freectx;
54static OSSL_FUNC_decoder_decode_fn pem2der_decode;
55
56/*
57 * Context used for PEM to DER decoding.
58 */
59struct pem2der_ctx_st {
60    PROV_CTX *provctx;
61    char data_structure[OSSL_MAX_CODEC_STRUCT_SIZE];
62    char propq[OSSL_MAX_PROPQUERY_SIZE];
63};
64
65static void *pem2der_newctx(void *provctx)
66{
67    struct pem2der_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
68
69    if (ctx != NULL)
70        ctx->provctx = provctx;
71    return ctx;
72}
73
74static void pem2der_freectx(void *vctx)
75{
76    struct pem2der_ctx_st *ctx = vctx;
77
78    OPENSSL_free(ctx);
79}
80
81{- produce_param_decoder('pem2der_set_ctx_params',
82                         (['DECODER_PARAM_PROPERTIES',    'propq', 'utf8_string'],
83                          ['OBJECT_PARAM_DATA_STRUCTURE', 'ds',    'utf8_string'],
84                         )); -}
85
86static const OSSL_PARAM *pem2der_settable_ctx_params(ossl_unused void *provctx)
87{
88    return pem2der_set_ctx_params_list;
89}
90
91static int pem2der_set_ctx_params(void *vctx, const OSSL_PARAM params[])
92{
93    struct pem2der_ctx_st *ctx = vctx;
94    struct pem2der_set_ctx_params_st p;
95    char *str;
96
97    if (ctx == NULL || !pem2der_set_ctx_params_decoder(params, &p))
98        return 0;
99
100    str = ctx->propq;
101    if (p.propq != NULL
102        && !OSSL_PARAM_get_utf8_string(p.propq, &str, sizeof(ctx->propq)))
103        return 0;
104
105    str = ctx->data_structure;
106    if (p.ds != NULL
107        && !OSSL_PARAM_get_utf8_string(p.ds, &str, sizeof(ctx->data_structure)))
108        return 0;
109
110    return 1;
111}
112
113/* pem_password_cb compatible function */
114struct pem2der_pass_data_st {
115    OSSL_PASSPHRASE_CALLBACK *cb;
116    void *cbarg;
117};
118
119static int pem2der_pass_helper(char *buf, int num, int w, void *data)
120{
121    struct pem2der_pass_data_st *pass_data = data;
122    size_t plen;
123
124    if (pass_data == NULL
125        || pass_data->cb == NULL
126        || !pass_data->cb(buf, num, &plen, NULL, pass_data->cbarg))
127        return -1;
128    return (int)plen;
129}
130
131static int pem2der_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
132                          OSSL_CALLBACK *data_cb, void *data_cbarg,
133                          OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
134{
135    /*
136     * PEM names we recognise.  Other PEM names should be recognised by
137     * other decoder implementations.
138     */
139    static struct pem_name_map_st {
140        const char *pem_name;
141        int object_type;
142        const char *data_type;
143        const char *data_structure;
144    } pem_name_map[] = {
145        /* PKCS#8 and SubjectPublicKeyInfo */
146        { PEM_STRING_PKCS8, OSSL_OBJECT_PKEY, NULL, "EncryptedPrivateKeyInfo" },
147        { PEM_STRING_PKCS8INF, OSSL_OBJECT_PKEY, NULL, "PrivateKeyInfo" },
148#define PKCS8_LAST_IDX 1
149        { PEM_STRING_PUBLIC, OSSL_OBJECT_PKEY, NULL, "SubjectPublicKeyInfo" },
150#define SPKI_LAST_IDX 2
151        /* Our set of type specific PEM types */
152        { PEM_STRING_DHPARAMS, OSSL_OBJECT_PKEY, "DH", "type-specific" },
153        { PEM_STRING_DHXPARAMS, OSSL_OBJECT_PKEY, "X9.42 DH", "type-specific" },
154        { PEM_STRING_DSA, OSSL_OBJECT_PKEY, "DSA", "type-specific" },
155        { PEM_STRING_DSA_PUBLIC, OSSL_OBJECT_PKEY, "DSA", "type-specific" },
156        { PEM_STRING_DSAPARAMS, OSSL_OBJECT_PKEY, "DSA", "type-specific" },
157        { PEM_STRING_ECPRIVATEKEY, OSSL_OBJECT_PKEY, "EC", "type-specific" },
158        { PEM_STRING_ECPARAMETERS, OSSL_OBJECT_PKEY, "EC", "type-specific" },
159        { PEM_STRING_SM2PRIVATEKEY, OSSL_OBJECT_PKEY, "SM2", "type-specific" },
160        { PEM_STRING_SM2PARAMETERS, OSSL_OBJECT_PKEY, "SM2", "type-specific" },
161        { PEM_STRING_RSA, OSSL_OBJECT_PKEY, "RSA", "type-specific" },
162        { PEM_STRING_RSA_PUBLIC, OSSL_OBJECT_PKEY, "RSA", "type-specific" },
163
164        /*
165         * A few others that there is at least have an object type for, even
166         * though there is no provider interface to handle such objects, yet.
167         * However, this is beneficial for the OSSL_STORE result handler.
168         */
169        { PEM_STRING_X509, OSSL_OBJECT_CERT, NULL, "Certificate" },
170        { PEM_STRING_X509_TRUSTED, OSSL_OBJECT_CERT, NULL, "Certificate" },
171        { PEM_STRING_X509_OLD, OSSL_OBJECT_CERT, NULL, "Certificate" },
172        { PEM_STRING_X509_CRL, OSSL_OBJECT_CRL, NULL, "CertificateList" }
173    };
174    struct pem2der_ctx_st *ctx = vctx;
175    char *pem_name = NULL, *pem_header = NULL;
176    size_t i;
177    unsigned char *der = NULL;
178    long der_len = 0;
179    int ok = 0;
180    int objtype = OSSL_OBJECT_UNKNOWN;
181
182    ok = read_pem(ctx->provctx, cin, &pem_name, &pem_header,
183                  &der, &der_len) > 0;
184    /* We return "empty handed".  This is not an error. */
185    if (!ok)
186        return 1;
187
188    /*
189     * 10 is the number of characters in "Proc-Type:", which
190     * PEM_get_EVP_CIPHER_INFO() requires to be present.
191     * If the PEM header has less characters than that, it's
192     * not worth spending cycles on it.
193     */
194    if (strlen(pem_header) > 10) {
195        EVP_CIPHER_INFO cipher;
196        struct pem2der_pass_data_st pass_data;
197
198        ok = 0;                  /* Assume that we fail */
199        pass_data.cb = pw_cb;
200        pass_data.cbarg = pw_cbarg;
201        if (!PEM_get_EVP_CIPHER_INFO(pem_header, &cipher)
202            || !PEM_do_header(&cipher, der, &der_len,
203                              pem2der_pass_helper, &pass_data))
204            goto end;
205    }
206
207    /*
208     * Indicated that we successfully decoded something, or not at all.
209     * Ending up "empty handed" is not an error.
210     */
211    ok = 1;
212
213    /* Have a look to see if we recognise anything */
214    for (i = 0; i < OSSL_NELEM(pem_name_map); i++)
215        if (strcmp(pem_name, pem_name_map[i].pem_name) == 0)
216            break;
217
218    if (i < OSSL_NELEM(pem_name_map)) {
219        OSSL_PARAM params[5], *p = params;
220        /* We expect these to be read only so casting away the const is ok */
221        char *data_type = (char *)pem_name_map[i].data_type;
222        char *data_structure = (char *)pem_name_map[i].data_structure;
223
224        /*
225         * Since this may perform decryption, we need to check the selection to
226         * avoid password prompts for objects of no interest.
227         */
228        if (i <= PKCS8_LAST_IDX
229            && ((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY)
230                || OPENSSL_strcasecmp(ctx->data_structure, "EncryptedPrivateKeyInfo") == 0
231                || OPENSSL_strcasecmp(ctx->data_structure, "PrivateKeyInfo") == 0)) {
232            ok = ossl_epki2pki_der_decode(der, der_len, selection, data_cb,
233                                          data_cbarg, pw_cb, pw_cbarg,
234                                          PROV_LIBCTX_OF(ctx->provctx),
235                                          ctx->propq);
236            goto end;
237        }
238
239        if (i <= SPKI_LAST_IDX
240            && ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY)
241                || OPENSSL_strcasecmp(ctx->data_structure, "SubjectPublicKeyInfo") == 0)) {
242            ok = ossl_spki2typespki_der_decode(der, der_len, selection, data_cb,
243                                               data_cbarg, pw_cb, pw_cbarg,
244                                               PROV_LIBCTX_OF(ctx->provctx),
245                                               ctx->propq);
246            goto end;
247        }
248
249        objtype = pem_name_map[i].object_type;
250        if (data_type != NULL)
251            *p++ =
252                OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
253                                                 data_type, 0);
254
255        /* We expect this to be read only so casting away the const is ok */
256        if (data_structure != NULL)
257            *p++ =
258                OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
259                                                 data_structure, 0);
260        *p++ =
261            OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
262                                              der, der_len);
263        *p++ =
264            OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype);
265
266        *p = OSSL_PARAM_construct_end();
267
268        ok = data_cb(params, data_cbarg);
269    }
270
271 end:
272    OPENSSL_free(pem_name);
273    OPENSSL_free(pem_header);
274    OPENSSL_free(der);
275    return ok;
276}
277
278const OSSL_DISPATCH ossl_pem_to_der_decoder_functions[] = {
279    { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))pem2der_newctx },
280    { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))pem2der_freectx },
281    { OSSL_FUNC_DECODER_DECODE, (void (*)(void))pem2der_decode },
282    { OSSL_FUNC_DECODER_SETTABLE_CTX_PARAMS,
283      (void (*)(void))pem2der_settable_ctx_params },
284    { OSSL_FUNC_DECODER_SET_CTX_PARAMS,
285      (void (*)(void))pem2der_set_ctx_params },
286    OSSL_DISPATCH_END
287};
288