1 /*
2 * Copyright 1999-2001 The OpenSSL Project Authors. All Rights Reserved.
3 * Written by Geoff Thorpe (geoff@geoffthorpe.net) for the OpenSSL
4 * project 2000.
5 * Portions Copyright (c) 2003 Kevin Stefanik (kstef@mtppi.org)
6 * Copied/modified by Kevin Stefanik (kstef@mtppi.org) for the OpenSC
7 * project 2003.
8 * Copyright (c) 2016-2018 Michał Trojnara <Michal.Trojnara@stunnel.org>
9 *
10 * Licensed under the OpenSSL license (the "License"). You may not use
11 * this file except in compliance with the License. You can obtain a copy
12 * in the file LICENSE in the source distribution or at
13 * https://www.openssl.org/source/license.html
14 */
15
16 #include "engine.h"
17 #include <stdio.h>
18 #include <string.h>
19 #include <openssl/opensslconf.h>
20 #include <openssl/opensslv.h>
21 #include <openssl/crypto.h>
22 #include <openssl/objects.h>
23 #include <openssl/engine.h>
24 #ifndef ENGINE_CMD_BASE
25 #error did not get engine.h
26 #endif
27
28 #define PKCS11_ENGINE_ID "pkcs11"
29 #define PKCS11_ENGINE_NAME "pkcs11 engine"
30
31 static int pkcs11_idx = -1;
32
33 /* The definitions for control commands specific to this engine */
34
35 /* need to add function to pass in reader id? or user reader:key as key id string? */
36
37 static const ENGINE_CMD_DEFN engine_cmd_defns[] = {
38 {CMD_SO_PATH,
39 "SO_PATH",
40 "Specifies the path to the 'pkcs11' engine shared library",
41 ENGINE_CMD_FLAG_STRING},
42 {CMD_MODULE_PATH,
43 "MODULE_PATH",
44 "Specifies the path to the PKCS#11 module shared library",
45 ENGINE_CMD_FLAG_STRING},
46 {CMD_PIN,
47 "PIN",
48 "Specifies the pin code",
49 ENGINE_CMD_FLAG_STRING},
50 {CMD_VERBOSE,
51 "VERBOSE",
52 "Print additional details",
53 ENGINE_CMD_FLAG_NO_INPUT},
54 {CMD_QUIET,
55 "QUIET",
56 "Remove additional details",
57 ENGINE_CMD_FLAG_NO_INPUT},
58 {CMD_LOAD_CERT_CTRL,
59 "LOAD_CERT_CTRL",
60 "Get the certificate from card",
61 ENGINE_CMD_FLAG_INTERNAL},
62 {CMD_INIT_ARGS,
63 "INIT_ARGS",
64 "Specifies additional initialization arguments to the PKCS#11 module",
65 ENGINE_CMD_FLAG_STRING},
66 {CMD_SET_USER_INTERFACE,
67 "SET_USER_INTERFACE",
68 "Set the global user interface (internal)",
69 ENGINE_CMD_FLAG_INTERNAL},
70 {CMD_SET_CALLBACK_DATA,
71 "SET_CALLBACK_DATA",
72 "Set the global user interface extra data (internal)",
73 ENGINE_CMD_FLAG_INTERNAL},
74 {CMD_FORCE_LOGIN,
75 "FORCE_LOGIN",
76 "Force login to the PKCS#11 module",
77 ENGINE_CMD_FLAG_NO_INPUT},
78 {0, NULL, NULL, 0}
79 };
80
get_ctx(ENGINE * engine)81 static ENGINE_CTX *get_ctx(ENGINE *engine)
82 {
83 ENGINE_CTX *ctx;
84
85 if (pkcs11_idx < 0) {
86 pkcs11_idx = ENGINE_get_ex_new_index(0, "pkcs11", NULL, NULL, 0);
87 if (pkcs11_idx < 0)
88 return NULL;
89 ctx = NULL;
90 } else {
91 ctx = ENGINE_get_ex_data(engine, pkcs11_idx);
92 }
93 if (!ctx) {
94 ctx = ctx_new();
95 ENGINE_set_ex_data(engine, pkcs11_idx, ctx);
96 }
97 return ctx;
98 }
99
100 /* Destroy the context allocated with ctx_new() */
engine_destroy(ENGINE * engine)101 static int engine_destroy(ENGINE *engine)
102 {
103 ENGINE_CTX *ctx;
104 int rv = 1;
105
106 ctx = get_ctx(engine);
107 if (!ctx)
108 return 0;
109
110 /* ENGINE_remove() invokes our engine_destroy() function with
111 * CRYPTO_LOCK_ENGINE / global_engine_lock acquired.
112 * Any attempt to re-acquire the lock either by directly
113 * invoking OpenSSL functions, or indirectly via PKCS#11 modules
114 * that use OpenSSL engines, causes a deadlock. */
115 /* Our workaround is to skip ctx_finish() entirely, as a memory
116 * leak is better than a deadlock. */
117 #if 0
118 rv &= ctx_finish(ctx);
119 #endif
120
121 rv &= ctx_destroy(ctx);
122 ENGINE_set_ex_data(engine, pkcs11_idx, NULL);
123 ERR_unload_ENG_strings();
124 return rv;
125 }
126
engine_init(ENGINE * engine)127 static int engine_init(ENGINE *engine)
128 {
129 ENGINE_CTX *ctx;
130
131 ctx = get_ctx(engine);
132 if (!ctx)
133 return 0;
134 return ctx_init(ctx);
135 }
136
137 /* Finish engine operations initialized with ctx_init() */
engine_finish(ENGINE * engine)138 static int engine_finish(ENGINE *engine)
139 {
140 ENGINE_CTX *ctx;
141 int rv = 1;
142
143 ctx = get_ctx(engine);
144 if (!ctx)
145 return 0;
146
147 /* ENGINE_cleanup() used by OpenSSL versions before 1.1.0 invokes
148 * our engine_finish() function with CRYPTO_LOCK_ENGINE acquired.
149 * Any attempt to re-acquire CRYPTO_LOCK_ENGINE either by directly
150 * invoking OpenSSL functions, or indirectly via PKCS#11 modules
151 * that use OpenSSL engines, causes a deadlock. */
152 /* Our workaround is to skip ctx_finish() for the affected OpenSSL
153 * versions, as a memory leak is better than a deadlock. */
154 /* We cannot simply temporarily release CRYPTO_LOCK_ENGINE here, as
155 * engine_finish() is also executed from ENGINE_finish() without
156 * acquired CRYPTO_LOCK_ENGINE, and there is no way with to check
157 * whether a lock is already acquired with OpenSSL < 1.1.0 API. */
158 #if OPENSSL_VERSION_NUMBER >= 0x10100005L && !defined(LIBRESSL_VERSION_NUMBER)
159 rv &= ctx_finish(ctx);
160 #endif
161
162 return rv;
163 }
164
load_pubkey(ENGINE * engine,const char * s_key_id,UI_METHOD * ui_method,void * callback_data)165 static EVP_PKEY *load_pubkey(ENGINE *engine, const char *s_key_id,
166 UI_METHOD *ui_method, void *callback_data)
167 {
168 ENGINE_CTX *ctx;
169
170 ctx = get_ctx(engine);
171 if (!ctx)
172 return 0;
173 return ctx_load_pubkey(ctx, s_key_id, ui_method, callback_data);
174 }
175
load_privkey(ENGINE * engine,const char * s_key_id,UI_METHOD * ui_method,void * callback_data)176 static EVP_PKEY *load_privkey(ENGINE *engine, const char *s_key_id,
177 UI_METHOD *ui_method, void *callback_data)
178 {
179 ENGINE_CTX *ctx;
180 EVP_PKEY *pkey;
181
182 ctx = get_ctx(engine);
183 if (!ctx)
184 return 0;
185 pkey = ctx_load_privkey(ctx, s_key_id, ui_method, callback_data);
186 #ifdef EVP_F_EVP_PKEY_SET1_ENGINE
187 /* EVP_PKEY_set1_engine() is required for OpenSSL 1.1.x,
188 * but otherwise setting pkey->engine breaks OpenSSL 1.0.2 */
189 if (pkey && !EVP_PKEY_set1_engine(pkey, engine)) {
190 EVP_PKEY_free(pkey);
191 pkey = NULL;
192 }
193 #endif /* EVP_F_EVP_PKEY_SET1_ENGINE */
194 return pkey;
195 }
196
engine_ctrl(ENGINE * engine,int cmd,long i,void * p,void (* f)())197 static int engine_ctrl(ENGINE *engine, int cmd, long i, void *p, void (*f) ())
198 {
199 ENGINE_CTX *ctx;
200
201 ctx = get_ctx(engine);
202 if (!ctx)
203 return 0;
204 return ctx_engine_ctrl(ctx, cmd, i, p, f);
205 }
206
207 /* This internal function is used by ENGINE_pkcs11() and possibly by the
208 * "dynamic" ENGINE support too */
bind_helper(ENGINE * e)209 static int bind_helper(ENGINE *e)
210 {
211 if (!ENGINE_set_id(e, PKCS11_ENGINE_ID) ||
212 !ENGINE_set_destroy_function(e, engine_destroy) ||
213 !ENGINE_set_init_function(e, engine_init) ||
214 !ENGINE_set_finish_function(e, engine_finish) ||
215 !ENGINE_set_ctrl_function(e, engine_ctrl) ||
216 !ENGINE_set_cmd_defns(e, engine_cmd_defns) ||
217 !ENGINE_set_name(e, PKCS11_ENGINE_NAME) ||
218 #ifndef OPENSSL_NO_RSA
219 !ENGINE_set_RSA(e, PKCS11_get_rsa_method()) ||
220 #endif
221 #if OPENSSL_VERSION_NUMBER >= 0x10100002L
222 #ifndef OPENSSL_NO_EC
223 /* PKCS11_get_ec_key_method combines ECDSA and ECDH */
224 !ENGINE_set_EC(e, PKCS11_get_ec_key_method()) ||
225 #endif /* OPENSSL_NO_EC */
226 #else /* OPENSSL_VERSION_NUMBER */
227 #ifndef OPENSSL_NO_ECDSA
228 !ENGINE_set_ECDSA(e, PKCS11_get_ecdsa_method()) ||
229 #endif
230 #ifndef OPENSSL_NO_ECDH
231 !ENGINE_set_ECDH(e, PKCS11_get_ecdh_method()) ||
232 #endif
233 #endif /* OPENSSL_VERSION_NUMBER */
234 !ENGINE_set_pkey_meths(e, PKCS11_pkey_meths) ||
235 !ENGINE_set_load_pubkey_function(e, load_pubkey) ||
236 !ENGINE_set_load_privkey_function(e, load_privkey)) {
237 return 0;
238 } else {
239 ERR_load_ENG_strings();
240 return 1;
241 }
242 }
243
bind_fn(ENGINE * e,const char * id)244 static int bind_fn(ENGINE *e, const char *id)
245 {
246 if (id && (strcmp(id, PKCS11_ENGINE_ID) != 0)) {
247 fprintf(stderr, "bad engine id\n");
248 return 0;
249 }
250 if (!bind_helper(e)) {
251 fprintf(stderr, "bind failed\n");
252 return 0;
253 }
254 return 1;
255 }
256
257 IMPLEMENT_DYNAMIC_CHECK_FN()
258 IMPLEMENT_DYNAMIC_BIND_FN(bind_fn)
259
260 /* vim: set noexpandtab: */
261