1e1051a39Sopenharmony_ci/*
2e1051a39Sopenharmony_ci * Copyright 2006-2022 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/* We need to use some engine deprecated APIs */
11e1051a39Sopenharmony_ci#define OPENSSL_SUPPRESS_DEPRECATED
12e1051a39Sopenharmony_ci
13e1051a39Sopenharmony_ci#include "e_os.h"
14e1051a39Sopenharmony_ci#include "eng_local.h"
15e1051a39Sopenharmony_ci#include <openssl/evp.h>
16e1051a39Sopenharmony_ci#include "crypto/asn1.h"
17e1051a39Sopenharmony_ci
18e1051a39Sopenharmony_ci/*
19e1051a39Sopenharmony_ci * If this symbol is defined then ENGINE_get_pkey_asn1_meth_engine(), the
20e1051a39Sopenharmony_ci * function that is used by EVP to hook in pkey_asn1_meth code and cache
21e1051a39Sopenharmony_ci * defaults (etc), will display brief debugging summaries to stderr with the
22e1051a39Sopenharmony_ci * 'nid'.
23e1051a39Sopenharmony_ci */
24e1051a39Sopenharmony_ci/* #define ENGINE_PKEY_ASN1_METH_DEBUG */
25e1051a39Sopenharmony_ci
26e1051a39Sopenharmony_cistatic ENGINE_TABLE *pkey_asn1_meth_table = NULL;
27e1051a39Sopenharmony_ci
28e1051a39Sopenharmony_civoid ENGINE_unregister_pkey_asn1_meths(ENGINE *e)
29e1051a39Sopenharmony_ci{
30e1051a39Sopenharmony_ci    engine_table_unregister(&pkey_asn1_meth_table, e);
31e1051a39Sopenharmony_ci}
32e1051a39Sopenharmony_ci
33e1051a39Sopenharmony_cistatic void engine_unregister_all_pkey_asn1_meths(void)
34e1051a39Sopenharmony_ci{
35e1051a39Sopenharmony_ci    engine_table_cleanup(&pkey_asn1_meth_table);
36e1051a39Sopenharmony_ci}
37e1051a39Sopenharmony_ci
38e1051a39Sopenharmony_ciint ENGINE_register_pkey_asn1_meths(ENGINE *e)
39e1051a39Sopenharmony_ci{
40e1051a39Sopenharmony_ci    if (e->pkey_asn1_meths) {
41e1051a39Sopenharmony_ci        const int *nids;
42e1051a39Sopenharmony_ci        int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
43e1051a39Sopenharmony_ci        if (num_nids > 0)
44e1051a39Sopenharmony_ci            return engine_table_register(&pkey_asn1_meth_table,
45e1051a39Sopenharmony_ci                                         engine_unregister_all_pkey_asn1_meths,
46e1051a39Sopenharmony_ci                                         e, nids, num_nids, 0);
47e1051a39Sopenharmony_ci    }
48e1051a39Sopenharmony_ci    return 1;
49e1051a39Sopenharmony_ci}
50e1051a39Sopenharmony_ci
51e1051a39Sopenharmony_civoid ENGINE_register_all_pkey_asn1_meths(void)
52e1051a39Sopenharmony_ci{
53e1051a39Sopenharmony_ci    ENGINE *e;
54e1051a39Sopenharmony_ci
55e1051a39Sopenharmony_ci    for (e = ENGINE_get_first(); e; e = ENGINE_get_next(e))
56e1051a39Sopenharmony_ci        ENGINE_register_pkey_asn1_meths(e);
57e1051a39Sopenharmony_ci}
58e1051a39Sopenharmony_ci
59e1051a39Sopenharmony_ciint ENGINE_set_default_pkey_asn1_meths(ENGINE *e)
60e1051a39Sopenharmony_ci{
61e1051a39Sopenharmony_ci    if (e->pkey_asn1_meths) {
62e1051a39Sopenharmony_ci        const int *nids;
63e1051a39Sopenharmony_ci        int num_nids = e->pkey_asn1_meths(e, NULL, &nids, 0);
64e1051a39Sopenharmony_ci        if (num_nids > 0)
65e1051a39Sopenharmony_ci            return engine_table_register(&pkey_asn1_meth_table,
66e1051a39Sopenharmony_ci                                         engine_unregister_all_pkey_asn1_meths,
67e1051a39Sopenharmony_ci                                         e, nids, num_nids, 1);
68e1051a39Sopenharmony_ci    }
69e1051a39Sopenharmony_ci    return 1;
70e1051a39Sopenharmony_ci}
71e1051a39Sopenharmony_ci
72e1051a39Sopenharmony_ci/*
73e1051a39Sopenharmony_ci * Exposed API function to get a functional reference from the implementation
74e1051a39Sopenharmony_ci * table (ie. try to get a functional reference from the tabled structural
75e1051a39Sopenharmony_ci * references) for a given pkey_asn1_meth 'nid'
76e1051a39Sopenharmony_ci */
77e1051a39Sopenharmony_ciENGINE *ENGINE_get_pkey_asn1_meth_engine(int nid)
78e1051a39Sopenharmony_ci{
79e1051a39Sopenharmony_ci    return ossl_engine_table_select(&pkey_asn1_meth_table, nid,
80e1051a39Sopenharmony_ci                                    OPENSSL_FILE, OPENSSL_LINE);
81e1051a39Sopenharmony_ci}
82e1051a39Sopenharmony_ci
83e1051a39Sopenharmony_ci/*
84e1051a39Sopenharmony_ci * Obtains a pkey_asn1_meth implementation from an ENGINE functional
85e1051a39Sopenharmony_ci * reference
86e1051a39Sopenharmony_ci */
87e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth(ENGINE *e, int nid)
88e1051a39Sopenharmony_ci{
89e1051a39Sopenharmony_ci    EVP_PKEY_ASN1_METHOD *ret;
90e1051a39Sopenharmony_ci    ENGINE_PKEY_ASN1_METHS_PTR fn = ENGINE_get_pkey_asn1_meths(e);
91e1051a39Sopenharmony_ci    if (!fn || !fn(e, &ret, NULL, nid)) {
92e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ENGINE, ENGINE_R_UNIMPLEMENTED_PUBLIC_KEY_METHOD);
93e1051a39Sopenharmony_ci        return NULL;
94e1051a39Sopenharmony_ci    }
95e1051a39Sopenharmony_ci    return ret;
96e1051a39Sopenharmony_ci}
97e1051a39Sopenharmony_ci
98e1051a39Sopenharmony_ci/* Gets the pkey_asn1_meth callback from an ENGINE structure */
99e1051a39Sopenharmony_ciENGINE_PKEY_ASN1_METHS_PTR ENGINE_get_pkey_asn1_meths(const ENGINE *e)
100e1051a39Sopenharmony_ci{
101e1051a39Sopenharmony_ci    return e->pkey_asn1_meths;
102e1051a39Sopenharmony_ci}
103e1051a39Sopenharmony_ci
104e1051a39Sopenharmony_ci/* Sets the pkey_asn1_meth callback in an ENGINE structure */
105e1051a39Sopenharmony_ciint ENGINE_set_pkey_asn1_meths(ENGINE *e, ENGINE_PKEY_ASN1_METHS_PTR f)
106e1051a39Sopenharmony_ci{
107e1051a39Sopenharmony_ci    e->pkey_asn1_meths = f;
108e1051a39Sopenharmony_ci    return 1;
109e1051a39Sopenharmony_ci}
110e1051a39Sopenharmony_ci
111e1051a39Sopenharmony_ci/*
112e1051a39Sopenharmony_ci * Internal function to free up EVP_PKEY_ASN1_METHOD structures before an
113e1051a39Sopenharmony_ci * ENGINE is destroyed
114e1051a39Sopenharmony_ci */
115e1051a39Sopenharmony_ci
116e1051a39Sopenharmony_civoid engine_pkey_asn1_meths_free(ENGINE *e)
117e1051a39Sopenharmony_ci{
118e1051a39Sopenharmony_ci    int i;
119e1051a39Sopenharmony_ci    EVP_PKEY_ASN1_METHOD *pkm;
120e1051a39Sopenharmony_ci    if (e->pkey_asn1_meths) {
121e1051a39Sopenharmony_ci        const int *pknids;
122e1051a39Sopenharmony_ci        int npknids;
123e1051a39Sopenharmony_ci        npknids = e->pkey_asn1_meths(e, NULL, &pknids, 0);
124e1051a39Sopenharmony_ci        for (i = 0; i < npknids; i++) {
125e1051a39Sopenharmony_ci            if (e->pkey_asn1_meths(e, &pkm, NULL, pknids[i])) {
126e1051a39Sopenharmony_ci                EVP_PKEY_asn1_free(pkm);
127e1051a39Sopenharmony_ci            }
128e1051a39Sopenharmony_ci        }
129e1051a39Sopenharmony_ci    }
130e1051a39Sopenharmony_ci}
131e1051a39Sopenharmony_ci
132e1051a39Sopenharmony_ci/*
133e1051a39Sopenharmony_ci * Find a method based on a string. This does a linear search through all
134e1051a39Sopenharmony_ci * implemented algorithms. This is OK in practice because only a small number
135e1051a39Sopenharmony_ci * of algorithms are likely to be implemented in an engine and it is not used
136e1051a39Sopenharmony_ci * for speed critical operations.
137e1051a39Sopenharmony_ci */
138e1051a39Sopenharmony_ci
139e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD *ENGINE_get_pkey_asn1_meth_str(ENGINE *e,
140e1051a39Sopenharmony_ci                                                          const char *str,
141e1051a39Sopenharmony_ci                                                          int len)
142e1051a39Sopenharmony_ci{
143e1051a39Sopenharmony_ci    int i, nidcount;
144e1051a39Sopenharmony_ci    const int *nids;
145e1051a39Sopenharmony_ci    EVP_PKEY_ASN1_METHOD *ameth;
146e1051a39Sopenharmony_ci    if (!e->pkey_asn1_meths)
147e1051a39Sopenharmony_ci        return NULL;
148e1051a39Sopenharmony_ci    if (len == -1)
149e1051a39Sopenharmony_ci        len = strlen(str);
150e1051a39Sopenharmony_ci    nidcount = e->pkey_asn1_meths(e, NULL, &nids, 0);
151e1051a39Sopenharmony_ci    for (i = 0; i < nidcount; i++) {
152e1051a39Sopenharmony_ci        e->pkey_asn1_meths(e, &ameth, NULL, nids[i]);
153e1051a39Sopenharmony_ci        if (ameth != NULL
154e1051a39Sopenharmony_ci            && ((int)strlen(ameth->pem_str) == len)
155e1051a39Sopenharmony_ci            && OPENSSL_strncasecmp(ameth->pem_str, str, len) == 0)
156e1051a39Sopenharmony_ci            return ameth;
157e1051a39Sopenharmony_ci    }
158e1051a39Sopenharmony_ci    return NULL;
159e1051a39Sopenharmony_ci}
160e1051a39Sopenharmony_ci
161e1051a39Sopenharmony_citypedef struct {
162e1051a39Sopenharmony_ci    ENGINE *e;
163e1051a39Sopenharmony_ci    const EVP_PKEY_ASN1_METHOD *ameth;
164e1051a39Sopenharmony_ci    const char *str;
165e1051a39Sopenharmony_ci    int len;
166e1051a39Sopenharmony_ci} ENGINE_FIND_STR;
167e1051a39Sopenharmony_ci
168e1051a39Sopenharmony_cistatic void look_str_cb(int nid, STACK_OF(ENGINE) *sk, ENGINE *def, void *arg)
169e1051a39Sopenharmony_ci{
170e1051a39Sopenharmony_ci    ENGINE_FIND_STR *lk = arg;
171e1051a39Sopenharmony_ci    int i;
172e1051a39Sopenharmony_ci    if (lk->ameth)
173e1051a39Sopenharmony_ci        return;
174e1051a39Sopenharmony_ci    for (i = 0; i < sk_ENGINE_num(sk); i++) {
175e1051a39Sopenharmony_ci        ENGINE *e = sk_ENGINE_value(sk, i);
176e1051a39Sopenharmony_ci        EVP_PKEY_ASN1_METHOD *ameth;
177e1051a39Sopenharmony_ci        e->pkey_asn1_meths(e, &ameth, NULL, nid);
178e1051a39Sopenharmony_ci        if (ameth != NULL
179e1051a39Sopenharmony_ci                && ((int)strlen(ameth->pem_str) == lk->len)
180e1051a39Sopenharmony_ci                && OPENSSL_strncasecmp(ameth->pem_str, lk->str, lk->len) == 0) {
181e1051a39Sopenharmony_ci            lk->e = e;
182e1051a39Sopenharmony_ci            lk->ameth = ameth;
183e1051a39Sopenharmony_ci            return;
184e1051a39Sopenharmony_ci        }
185e1051a39Sopenharmony_ci    }
186e1051a39Sopenharmony_ci}
187e1051a39Sopenharmony_ci
188e1051a39Sopenharmony_ciconst EVP_PKEY_ASN1_METHOD *ENGINE_pkey_asn1_find_str(ENGINE **pe,
189e1051a39Sopenharmony_ci                                                      const char *str,
190e1051a39Sopenharmony_ci                                                      int len)
191e1051a39Sopenharmony_ci{
192e1051a39Sopenharmony_ci    ENGINE_FIND_STR fstr;
193e1051a39Sopenharmony_ci    fstr.e = NULL;
194e1051a39Sopenharmony_ci    fstr.ameth = NULL;
195e1051a39Sopenharmony_ci    fstr.str = str;
196e1051a39Sopenharmony_ci    fstr.len = len;
197e1051a39Sopenharmony_ci
198e1051a39Sopenharmony_ci    if (!RUN_ONCE(&engine_lock_init, do_engine_lock_init)) {
199e1051a39Sopenharmony_ci        ERR_raise(ERR_LIB_ENGINE, ERR_R_MALLOC_FAILURE);
200e1051a39Sopenharmony_ci        return NULL;
201e1051a39Sopenharmony_ci    }
202e1051a39Sopenharmony_ci
203e1051a39Sopenharmony_ci    if (!CRYPTO_THREAD_write_lock(global_engine_lock))
204e1051a39Sopenharmony_ci        return NULL;
205e1051a39Sopenharmony_ci    engine_table_doall(pkey_asn1_meth_table, look_str_cb, &fstr);
206e1051a39Sopenharmony_ci    /* If found obtain a structural reference to engine */
207e1051a39Sopenharmony_ci    if (fstr.e) {
208e1051a39Sopenharmony_ci        fstr.e->struct_ref++;
209e1051a39Sopenharmony_ci        ENGINE_REF_PRINT(fstr.e, 0, 1);
210e1051a39Sopenharmony_ci    }
211e1051a39Sopenharmony_ci    *pe = fstr.e;
212e1051a39Sopenharmony_ci    CRYPTO_THREAD_unlock(global_engine_lock);
213e1051a39Sopenharmony_ci    return fstr.ameth;
214e1051a39Sopenharmony_ci}
215