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 * This is a decoder that's completely internal to the 'file:' store
15 * implementation.  Only code in file_store.c know about this one.  Because
16 * of this close relationship, we can cut certain corners, such as making
17 * assumptions about the "provider context", which is currently simply the
18 * provider context that the file_store.c code operates within.
19 *
20 * All this does is to read known binary encodings (currently: DER, MSBLOB,
21 * PVK) from the input if it can, and passes it on to the data callback as
22 * an object abstraction, leaving it to the callback to figure out what it
23 * actually is.
24 *
25 * This MUST be made the last decoder in a chain, leaving it to other more
26 * specialized decoders to recognise and process their stuff first.
27 */
28
29#include <openssl/core_dispatch.h>
30#include <openssl/core_names.h>
31#include <openssl/core_object.h>
32#include <openssl/bio.h>
33#include <openssl/buffer.h>
34#include <openssl/err.h>
35#include <openssl/asn1err.h>
36#include <openssl/proverr.h>
37#include "internal/cryptlib.h"
38#include <openssl/params.h>
39#include "internal/asn1.h"
40#include "internal/sizes.h"
41#include "crypto/pem.h"          /* For internal PVK and "blob" headers */
42#include "prov/bio.h"
43#include "prov/file_store_local.h"
44
45/*
46 * newctx and freectx are not strictly necessary.  However, the method creator,
47 * ossl_decoder_from_algorithm(), demands that they exist, so we make sure to
48 * oblige.
49 */
50
51static OSSL_FUNC_decoder_newctx_fn any2obj_newctx;
52static OSSL_FUNC_decoder_freectx_fn any2obj_freectx;
53
54struct any2obj_ctx_st {
55    PROV_CTX *provctx;
56    char data_structure[OSSL_MAX_CODEC_STRUCT_SIZE];
57};
58
59static void *any2obj_newctx(void *provctx)
60{
61    struct any2obj_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
62
63    if (ctx != NULL)
64        ctx->provctx = provctx;
65    return ctx;
66}
67
68static void any2obj_freectx(void *ctx)
69{
70    OPENSSL_free(ctx);
71}
72
73{- produce_param_decoder('any2obj_set_ctx_params',
74                         (['OBJECT_PARAM_DATA_STRUCTURE', 'datastruct', 'utf8_string'],
75                         )); -}
76
77static int any2obj_set_ctx_params(void *vctx, const OSSL_PARAM params[])
78{
79    struct any2obj_ctx_st *ctx = vctx;
80    struct any2obj_set_ctx_params_st p;
81    char *str;
82
83    if (ctx == NULL || !any2obj_set_ctx_params_decoder(params, &p))
84        return 0;
85
86    str = ctx->data_structure;
87    if (p.datastruct != NULL
88        && !OSSL_PARAM_get_utf8_string(p.datastruct, &str,
89                                       sizeof(ctx->data_structure)))
90        return 0;
91
92    return 1;
93}
94
95static const OSSL_PARAM *any2obj_settable_ctx_params(ossl_unused void *provctx)
96{
97    return any2obj_set_ctx_params_list;
98}
99
100static int any2obj_decode_final(void *vctx, int objtype, const char *input_type,
101                                const char *data_type, BUF_MEM *mem,
102                                OSSL_CALLBACK *data_cb, void *data_cbarg)
103{
104    struct any2obj_ctx_st *ctx = vctx;
105    /*
106     * 1 indicates that we successfully decoded something, or not at all.
107     * Ending up "empty handed" is not an error.
108     */
109    int ok = 1;
110
111    if (mem != NULL) {
112        OSSL_PARAM params[6], *p = params;
113
114        if (data_type != NULL)
115            *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
116                                                    (char *)data_type, 0);
117        if (input_type != NULL)
118            *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_INPUT_TYPE,
119                                                    (char *)input_type, 0);
120        if (*ctx->data_structure != '\0')
121            *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
122                                                    (char *)ctx->data_structure, 0);
123        *p++ = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype);
124        *p++ = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA,
125                                                 mem->data, mem->length);
126        *p = OSSL_PARAM_construct_end();
127
128        ok = data_cb(params, data_cbarg);
129        BUF_MEM_free(mem);
130    }
131    return ok;
132}
133
134static OSSL_FUNC_decoder_decode_fn der2obj_decode;
135static int der2obj_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
136                          OSSL_CALLBACK *data_cb, void *data_cbarg,
137                          OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
138{
139    struct any2obj_ctx_st *ctx = vctx;
140    BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin);
141    BUF_MEM *mem = NULL;
142    int ok;
143
144    if (in == NULL)
145        return 0;
146
147    ERR_set_mark();
148    ok = (asn1_d2i_read_bio(in, &mem) >= 0);
149    ERR_pop_to_mark();
150    if (!ok && mem != NULL) {
151        BUF_MEM_free(mem);
152        mem = NULL;
153    }
154    BIO_free(in);
155
156    /* any2obj_decode_final() frees |mem| for us */
157    return any2obj_decode_final(ctx, OSSL_OBJECT_UNKNOWN, NULL, NULL, mem,
158                                data_cb, data_cbarg);
159}
160
161static OSSL_FUNC_decoder_decode_fn msblob2obj_decode;
162static int msblob2obj_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
163                             OSSL_CALLBACK *data_cb, void *data_cbarg,
164                             OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
165{
166    struct any2obj_ctx_st *ctx = vctx;
167    BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin);
168    BUF_MEM *mem = NULL;
169    size_t mem_len = 0, mem_want;
170    const unsigned char *p;
171    unsigned int bitlen, magic;
172    int isdss = -1;
173    int ispub = -1;
174    int ok = 0;
175
176    if (in == NULL)
177        goto err;
178
179    mem_want = 16;               /* The size of the MSBLOB header */
180    if ((mem = BUF_MEM_new()) == NULL
181        || !BUF_MEM_grow(mem, mem_want)) {
182        ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB);
183        goto err;
184    }
185
186    ERR_set_mark();
187    ok = BIO_read(in, &mem->data[0], (int)mem_want) == (int)mem_want;
188    mem_len += mem_want;
189    ERR_pop_to_mark();
190    if (!ok)
191        goto next;
192
193
194    ERR_set_mark();
195    p = (unsigned char *)&mem->data[0];
196    ok = ossl_do_blob_header(&p, 16, &magic, &bitlen, &isdss, &ispub) > 0;
197    ERR_pop_to_mark();
198    if (!ok)
199        goto next;
200
201    ok = 0;
202    mem_want = ossl_blob_length(bitlen, isdss, ispub);
203    if (!BUF_MEM_grow(mem, mem_len + mem_want)) {
204        ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB);
205        goto err;
206    }
207
208    ERR_set_mark();
209    ok = BIO_read(in, &mem->data[mem_len], (int)mem_want) == (int)mem_want;
210    mem_len += mem_want;
211    ERR_pop_to_mark();
212
213 next:
214    /* Free resources we no longer need. */
215    BIO_free(in);
216    if (!ok && mem != NULL) {
217        BUF_MEM_free(mem);
218        mem = NULL;
219    }
220
221    /* any2obj_decode_final() frees |mem| for us */
222    return any2obj_decode_final(ctx, OSSL_OBJECT_PKEY, "msblob",
223                                isdss ? "DSA" : "RSA", mem,
224                                data_cb, data_cbarg);
225
226 err:
227    BIO_free(in);
228    BUF_MEM_free(mem);
229    return 0;
230}
231
232static OSSL_FUNC_decoder_decode_fn pvk2obj_decode;
233static int pvk2obj_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
234                             OSSL_CALLBACK *data_cb, void *data_cbarg,
235                             OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
236{
237    struct any2obj_ctx_st *ctx = vctx;
238    BIO *in = ossl_bio_new_from_core_bio(ctx->provctx, cin);
239    BUF_MEM *mem = NULL;
240    size_t mem_len = 0, mem_want;
241    const unsigned char *p;
242    unsigned int saltlen, keylen;
243    int ok = 0, isdss = -1;
244
245    if (in == NULL)
246        goto err;
247
248    mem_want = 24;               /* The size of the PVK header */
249    if ((mem = BUF_MEM_new()) == NULL
250        || !BUF_MEM_grow(mem, mem_want)) {
251        ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB);
252        goto err;
253    }
254
255    ERR_set_mark();
256    ok = BIO_read(in, &mem->data[0], (int)mem_want) == (int)mem_want;
257    mem_len += mem_want;
258    ERR_pop_to_mark();
259    if (!ok)
260        goto next;
261
262
263    ERR_set_mark();
264    p = (unsigned char *)&mem->data[0];
265    ok = ossl_do_PVK_header(&p, 24, 0, &isdss, &saltlen, &keylen) > 0;
266    ERR_pop_to_mark();
267    if (!ok)
268        goto next;
269
270    ok = 0;
271    mem_want = saltlen + keylen;
272    if (!BUF_MEM_grow(mem, mem_len + mem_want)) {
273        ERR_raise(ERR_LIB_PEM, ERR_R_BUF_LIB);
274        goto err;
275    }
276
277    ERR_set_mark();
278    ok = BIO_read(in, &mem->data[mem_len], (int)mem_want) == (int)mem_want;
279    mem_len += mem_want;
280    ERR_pop_to_mark();
281
282 next:
283    /* Free resources we no longer need. */
284    BIO_free(in);
285    if (!ok && mem != NULL) {
286        BUF_MEM_free(mem);
287        mem = NULL;
288    }
289
290    /* any2obj_decode_final() frees |mem| for us */
291    return any2obj_decode_final(ctx, OSSL_OBJECT_PKEY, "pvk",
292                                ok ? (isdss ? "DSA" : "RSA") : NULL, mem,
293                                data_cb, data_cbarg);
294
295 err:
296    BIO_free(in);
297    BUF_MEM_free(mem);
298    return 0;
299}
300
301#define MAKE_DECODER(fromtype, objtype)                                      \
302    static const OSSL_DISPATCH fromtype##_to_obj_decoder_functions[] = {     \
303        { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))any2obj_newctx },        \
304        { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))any2obj_freectx },      \
305        { OSSL_FUNC_DECODER_DECODE, (void (*)(void))fromtype##2obj_decode }, \
306        { OSSL_FUNC_DECODER_SETTABLE_CTX_PARAMS,                             \
307          (void (*)(void))any2obj_settable_ctx_params },                     \
308        { OSSL_FUNC_DECODER_SET_CTX_PARAMS,                                  \
309          (void (*)(void))any2obj_set_ctx_params },                          \
310        OSSL_DISPATCH_END                                                    \
311    }
312
313MAKE_DECODER(der, OSSL_OBJECT_UNKNOWN);
314MAKE_DECODER(msblob, OSSL_OBJECT_PKEY);
315MAKE_DECODER(pvk, OSSL_OBJECT_PKEY);
316
317const OSSL_ALGORITHM ossl_any_to_obj_algorithm[] = {
318    { "obj", "input=DER", der_to_obj_decoder_functions },
319    { "obj", "input=MSBLOB", msblob_to_obj_decoder_functions },
320    { "obj", "input=PVK", pvk_to_obj_decoder_functions },
321    { NULL, }
322};
323