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#include <string.h>
14#include <openssl/asn1t.h>
15#include <openssl/core_names.h>
16#include <openssl/core_object.h>
17#include <openssl/params.h>
18#include <openssl/proverr.h>
19#include <openssl/x509.h>
20#include "internal/cryptlib.h"
21#include "internal/sizes.h"
22#include "crypto/x509.h"
23#include "crypto/ec.h"
24#include "prov/bio.h"
25#include "prov/decoders.h"
26#include "prov/implementations.h"
27#include "prov/endecoder_local.h"
28
29static OSSL_FUNC_decoder_newctx_fn spki2typespki_newctx;
30static OSSL_FUNC_decoder_freectx_fn spki2typespki_freectx;
31static OSSL_FUNC_decoder_decode_fn spki2typespki_decode;
32static OSSL_FUNC_decoder_settable_ctx_params_fn spki2typespki_settable_ctx_params;
33static OSSL_FUNC_decoder_set_ctx_params_fn spki2typespki_set_ctx_params;
34
35/*
36 * Context used for SubjectPublicKeyInfo to Type specific SubjectPublicKeyInfo
37 * decoding.
38 */
39struct spki2typespki_ctx_st {
40    PROV_CTX *provctx;
41    char propq[OSSL_MAX_PROPQUERY_SIZE];
42};
43
44static void *spki2typespki_newctx(void *provctx)
45{
46    struct spki2typespki_ctx_st *ctx = OPENSSL_zalloc(sizeof(*ctx));
47
48    if (ctx != NULL)
49        ctx->provctx = provctx;
50    return ctx;
51}
52
53static void spki2typespki_freectx(void *vctx)
54{
55    struct spki2typespki_ctx_st *ctx = vctx;
56
57    OPENSSL_free(ctx);
58}
59
60{- produce_param_decoder('spki2typespki_set_ctx_params',
61                         (['DECODER_PARAM_PROPERTIES', 'propq', 'utf8_string'],
62                         )); -}
63
64static const OSSL_PARAM *spki2typespki_settable_ctx_params(ossl_unused void *provctx)
65{
66    return spki2typespki_set_ctx_params_list;
67}
68
69static int spki2typespki_set_ctx_params(void *vctx, const OSSL_PARAM params[])
70{
71    struct spki2typespki_ctx_st *ctx = vctx;
72    struct spki2typespki_set_ctx_params_st p;
73    char *str;
74
75    if (ctx == NULL || !spki2typespki_set_ctx_params_decoder(params, &p))
76        return 0;
77
78    str = ctx->propq;
79    if (p.propq != NULL
80            && !OSSL_PARAM_get_utf8_string(p.propq, &str, sizeof(ctx->propq)))
81        return 0;
82
83    return 1;
84}
85
86static int spki2typespki_decode(void *vctx, OSSL_CORE_BIO *cin, int selection,
87                                OSSL_CALLBACK *data_cb, void *data_cbarg,
88                                OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg)
89{
90    struct spki2typespki_ctx_st *ctx = vctx;
91    unsigned char *der;
92    long len;
93    int ok = 0;
94
95    if (!ossl_read_der(ctx->provctx, cin, &der, &len))
96        return 1;
97
98    ok = ossl_spki2typespki_der_decode(der, len, selection, data_cb, data_cbarg,
99                                       pw_cb, pw_cbarg,
100                                       PROV_LIBCTX_OF(ctx->provctx), ctx->propq);
101    OPENSSL_free(der);
102    return ok;
103}
104
105int ossl_spki2typespki_der_decode(unsigned char *der, long len, int selection,
106                                  OSSL_CALLBACK *data_cb, void *data_cbarg,
107                                  OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg,
108                                  OSSL_LIB_CTX *libctx, const char *propq)
109{
110    const unsigned char *derp = der;
111    X509_PUBKEY *xpub = NULL;
112    X509_ALGOR *algor = NULL;
113    const ASN1_OBJECT *oid = NULL;
114    char dataname[OSSL_MAX_NAME_SIZE];
115    OSSL_PARAM params[6], *p = params;
116    int objtype = OSSL_OBJECT_PKEY;
117    int ok = 0;
118
119    xpub = ossl_d2i_X509_PUBKEY_INTERNAL(&derp, len, libctx, propq);
120
121    if (xpub == NULL) {
122        /* We return "empty handed".  This is not an error. */
123        ok = 1;
124        goto end;
125    }
126
127    if (!X509_PUBKEY_get0_param(NULL, NULL, NULL, &algor, xpub))
128        goto end;
129    X509_ALGOR_get0(&oid, NULL, NULL, algor);
130
131#ifndef OPENSSL_NO_EC
132    /* SM2 abuses the EC oid, so this could actually be SM2 */
133    if (OBJ_obj2nid(oid) == NID_X9_62_id_ecPublicKey
134            && ossl_x509_algor_is_sm2(algor))
135        strcpy(dataname, "SM2");
136    else
137#endif
138    if (OBJ_obj2txt(dataname, sizeof(dataname), oid, 0) <= 0)
139        goto end;
140
141    ossl_X509_PUBKEY_INTERNAL_free(xpub);
142    xpub = NULL;
143
144    *p++ =
145        OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE,
146                                            dataname, 0);
147
148    *p++ = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_INPUT_TYPE,
149                                            "DER", 0);
150
151    *p++ =
152        OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_STRUCTURE,
153                                            "SubjectPublicKeyInfo",
154                                            0);
155    *p++ =
156        OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, der, len);
157    *p++ =
158        OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &objtype);
159
160    *p = OSSL_PARAM_construct_end();
161
162    ok = data_cb(params, data_cbarg);
163
164 end:
165    ossl_X509_PUBKEY_INTERNAL_free(xpub);
166    return ok;
167}
168
169const OSSL_DISPATCH ossl_SubjectPublicKeyInfo_der_to_der_decoder_functions[] = {
170    { OSSL_FUNC_DECODER_NEWCTX, (void (*)(void))spki2typespki_newctx },
171    { OSSL_FUNC_DECODER_FREECTX, (void (*)(void))spki2typespki_freectx },
172    { OSSL_FUNC_DECODER_DECODE, (void (*)(void))spki2typespki_decode },
173    { OSSL_FUNC_DECODER_SETTABLE_CTX_PARAMS,
174      (void (*)(void))spki2typespki_settable_ctx_params },
175    { OSSL_FUNC_DECODER_SET_CTX_PARAMS,
176      (void (*)(void))spki2typespki_set_ctx_params },
177    OSSL_DISPATCH_END
178};
179