1/*
2 * Copyright 2020 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
10/*
11 * Here is a set of wrappers for the ENGINE API, which are no-ops when the
12 * ENGINE API is disabled / removed.
13 * We need to suppress deprecation warnings to make this work.
14 */
15#define OPENSSL_SUPPRESS_DEPRECATED
16
17#include <string.h> /* strcmp */
18
19#include <openssl/types.h> /* Ensure we have the ENGINE type, regardless */
20#include <openssl/err.h>
21#ifndef OPENSSL_NO_ENGINE
22# include <openssl/engine.h>
23#endif
24#include "apps.h"
25
26#ifndef OPENSSL_NO_ENGINE
27/* Try to load an engine in a shareable library */
28static ENGINE *try_load_engine(const char *engine)
29{
30    ENGINE *e = NULL;
31
32    if ((e = ENGINE_by_id("dynamic")) != NULL) {
33        if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0)
34            || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) {
35            ENGINE_free(e);
36            e = NULL;
37        }
38    }
39    return e;
40}
41#endif
42
43ENGINE *setup_engine_methods(const char *id, unsigned int methods, int debug)
44{
45    ENGINE *e = NULL;
46
47#ifndef OPENSSL_NO_ENGINE
48    if (id != NULL) {
49        if (strcmp(id, "auto") == 0) {
50            BIO_printf(bio_err, "Enabling auto ENGINE support\n");
51            ENGINE_register_all_complete();
52            return NULL;
53        }
54        if ((e = ENGINE_by_id(id)) == NULL
55            && (e = try_load_engine(id)) == NULL) {
56            BIO_printf(bio_err, "Invalid engine \"%s\"\n", id);
57            ERR_print_errors(bio_err);
58            return NULL;
59        }
60        if (debug)
61            (void)ENGINE_ctrl(e, ENGINE_CTRL_SET_LOGSTREAM, 0, bio_err, 0);
62        if (!ENGINE_ctrl_cmd(e, "SET_USER_INTERFACE", 0,
63                             (void *)get_ui_method(), 0, 1)
64                || !ENGINE_set_default(e, methods)) {
65            BIO_printf(bio_err, "Cannot use engine \"%s\"\n", ENGINE_get_id(e));
66            ERR_print_errors(bio_err);
67            ENGINE_free(e);
68            return NULL;
69        }
70
71        BIO_printf(bio_err, "Engine \"%s\" set.\n", ENGINE_get_id(e));
72    }
73#endif
74    return e;
75}
76
77void release_engine(ENGINE *e)
78{
79#ifndef OPENSSL_NO_ENGINE
80    /* Free our "structural" reference. */
81    ENGINE_free(e);
82#endif
83}
84
85int init_engine(ENGINE *e)
86{
87    int rv = 1;
88
89#ifndef OPENSSL_NO_ENGINE
90    rv = ENGINE_init(e);
91#endif
92    return rv;
93}
94
95int finish_engine(ENGINE *e)
96{
97    int rv = 1;
98
99#ifndef OPENSSL_NO_ENGINE
100    rv = ENGINE_finish(e);
101#endif
102    return rv;
103}
104
105char *make_engine_uri(ENGINE *e, const char *key_id, const char *desc)
106{
107    char *new_uri = NULL;
108
109#ifndef OPENSSL_NO_ENGINE
110    if (e == NULL) {
111        BIO_printf(bio_err, "No engine specified for loading %s\n", desc);
112    } else if (key_id == NULL) {
113        BIO_printf(bio_err, "No engine key id specified for loading %s\n", desc);
114    } else {
115        const char *engineid = ENGINE_get_id(e);
116        size_t uri_sz =
117            sizeof(ENGINE_SCHEME_COLON) - 1
118            + strlen(engineid)
119            + 1 /* : */
120            + strlen(key_id)
121            + 1 /* \0 */
122            ;
123
124        new_uri = OPENSSL_malloc(uri_sz);
125        if (new_uri != NULL) {
126            OPENSSL_strlcpy(new_uri, ENGINE_SCHEME_COLON, uri_sz);
127            OPENSSL_strlcat(new_uri, engineid, uri_sz);
128            OPENSSL_strlcat(new_uri, ":", uri_sz);
129            OPENSSL_strlcat(new_uri, key_id, uri_sz);
130        }
131    }
132#else
133    BIO_printf(bio_err, "Engines not supported for loading %s\n", desc);
134#endif
135    return new_uri;
136}
137
138int get_legacy_pkey_id(OSSL_LIB_CTX *libctx, const char *algname, ENGINE *e)
139{
140    const EVP_PKEY_ASN1_METHOD *ameth;
141    ENGINE *tmpeng = NULL;
142    int pkey_id = NID_undef;
143
144    ERR_set_mark();
145    ameth = EVP_PKEY_asn1_find_str(&tmpeng, algname, -1);
146
147#if !defined(OPENSSL_NO_ENGINE)
148    ENGINE_finish(tmpeng);
149
150    if (ameth == NULL && e != NULL)
151        ameth = ENGINE_get_pkey_asn1_meth_str(e, algname, -1);
152    else
153#endif
154    /* We're only interested if it comes from an ENGINE */
155    if (tmpeng == NULL)
156        ameth = NULL;
157
158    ERR_pop_to_mark();
159    if (ameth == NULL)
160        return NID_undef;
161
162    EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth);
163
164    return pkey_id;
165}
166
167const EVP_MD *get_digest_from_engine(const char *name)
168{
169#ifndef OPENSSL_NO_ENGINE
170    ENGINE *eng;
171
172    eng = ENGINE_get_digest_engine(OBJ_sn2nid(name));
173    if (eng != NULL) {
174        ENGINE_finish(eng);
175        return EVP_get_digestbyname(name);
176    }
177#endif
178    return NULL;
179}
180
181const EVP_CIPHER *get_cipher_from_engine(const char *name)
182{
183#ifndef OPENSSL_NO_ENGINE
184    ENGINE *eng;
185
186    eng = ENGINE_get_cipher_engine(OBJ_sn2nid(name));
187    if (eng != NULL) {
188        ENGINE_finish(eng);
189        return EVP_get_cipherbyname(name);
190    }
191#endif
192    return NULL;
193}
194