comparison OrthancFramework/Sources/Pkcs11.cpp @ 4044:d25f4c0fa160 framework

splitting code into OrthancFramework and OrthancServer
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 10 Jun 2020 20:30:34 +0200
parents Core/Pkcs11.cpp@cc6d4edfe8fe
children bf7b9edf6b81
comparison
equal deleted inserted replaced
4043:6c6239aec462 4044:d25f4c0fa160
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #include "PrecompiledHeaders.h"
35 #include "Pkcs11.h"
36
37
38 #if defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_ECDH)
39 # error OpenSSL was compiled without support for RSA, EC, ECDSA or ECDH
40 #endif
41
42
43 #include "Logging.h"
44 #include "OrthancException.h"
45 #include "SystemToolbox.h"
46
47 extern "C"
48 {
49 # include <libp11/engine.h> // This is P11's "engine.h"
50 # include <libp11/libp11.h>
51 }
52
53 #include <openssl/engine.h>
54
55
56 namespace Orthanc
57 {
58 namespace Pkcs11
59 {
60 static const char* PKCS11_ENGINE_ID = "pkcs11";
61 static const char* PKCS11_ENGINE_NAME = "PKCS#11 for Orthanc";
62 static const ENGINE_CMD_DEFN PKCS11_ENGINE_COMMANDS[] =
63 {
64 {
65 CMD_MODULE_PATH,
66 "MODULE_PATH",
67 "Specifies the path to the PKCS#11 module shared library",
68 ENGINE_CMD_FLAG_STRING
69 },
70 {
71 CMD_PIN,
72 "PIN",
73 "Specifies the pin code",
74 ENGINE_CMD_FLAG_STRING
75 },
76 {
77 CMD_VERBOSE,
78 "VERBOSE",
79 "Print additional details",
80 ENGINE_CMD_FLAG_NO_INPUT
81 },
82 {
83 CMD_LOAD_CERT_CTRL,
84 "LOAD_CERT_CTRL",
85 "Get the certificate from card",
86 ENGINE_CMD_FLAG_INTERNAL
87 },
88 {
89 0,
90 NULL,
91 NULL,
92 0
93 }
94 };
95
96
97 static bool pkcs11Initialized_ = false;
98 static ENGINE_CTX *context_ = NULL;
99
100 static int EngineInitialize(ENGINE* engine)
101 {
102 if (context_ == NULL)
103 {
104 return 0;
105 }
106 else
107 {
108 return pkcs11_init(context_);
109 }
110 }
111
112
113 static int EngineFinalize(ENGINE* engine)
114 {
115 if (context_ == NULL)
116 {
117 return 0;
118 }
119 else
120 {
121 return pkcs11_finish(context_);
122 }
123 }
124
125
126 static int EngineDestroy(ENGINE* engine)
127 {
128 return (context_ == NULL ? 0 : 1);
129 }
130
131
132 static int EngineControl(ENGINE *engine,
133 int command,
134 long i,
135 void *p,
136 void (*f) ())
137 {
138 if (context_ == NULL)
139 {
140 return 0;
141 }
142 else
143 {
144 return pkcs11_engine_ctrl(context_, command, i, p, f);
145 }
146 }
147
148
149 static EVP_PKEY *EngineLoadPublicKey(ENGINE *engine,
150 const char *s_key_id,
151 UI_METHOD *ui_method,
152 void *callback_data)
153 {
154 if (context_ == NULL)
155 {
156 return 0;
157 }
158 else
159 {
160 return pkcs11_load_public_key(context_, s_key_id, ui_method, callback_data);
161 }
162 }
163
164
165 static EVP_PKEY *EngineLoadPrivateKey(ENGINE *engine,
166 const char *s_key_id,
167 UI_METHOD *ui_method,
168 void *callback_data)
169 {
170 if (context_ == NULL)
171 {
172 return 0;
173 }
174 else
175 {
176 return pkcs11_load_private_key(context_, s_key_id, ui_method, callback_data);
177 }
178 }
179
180
181 static ENGINE* LoadEngine()
182 {
183 // This function creates an engine for PKCS#11 and inspired by
184 // the "ENGINE_load_dynamic" function from OpenSSL, in file
185 // "crypto/engine/eng_dyn.c"
186
187 ENGINE* engine = ENGINE_new();
188 if (!engine)
189 {
190 throw OrthancException(ErrorCode_InternalError,
191 "Cannot create an OpenSSL engine for PKCS#11");
192 }
193
194 // Create a PKCS#11 context using libp11
195 context_ = pkcs11_new();
196 if (!context_)
197 {
198 ENGINE_free(engine);
199 throw OrthancException(ErrorCode_InternalError,
200 "Cannot create a libp11 context for PKCS#11");
201 }
202
203 if (!ENGINE_set_id(engine, PKCS11_ENGINE_ID) ||
204 !ENGINE_set_name(engine, PKCS11_ENGINE_NAME) ||
205 !ENGINE_set_cmd_defns(engine, PKCS11_ENGINE_COMMANDS) ||
206
207 // Register the callback functions
208 !ENGINE_set_init_function(engine, EngineInitialize) ||
209 !ENGINE_set_finish_function(engine, EngineFinalize) ||
210 !ENGINE_set_destroy_function(engine, EngineDestroy) ||
211 !ENGINE_set_ctrl_function(engine, EngineControl) ||
212 !ENGINE_set_load_pubkey_function(engine, EngineLoadPublicKey) ||
213 !ENGINE_set_load_privkey_function(engine, EngineLoadPrivateKey) ||
214
215 !ENGINE_set_RSA(engine, PKCS11_get_rsa_method()) ||
216
217 #if OPENSSL_VERSION_NUMBER < 0x10100000L // OpenSSL 1.0.2
218 !ENGINE_set_ECDSA(engine, PKCS11_get_ecdsa_method()) ||
219 !ENGINE_set_ECDH(engine, PKCS11_get_ecdh_method()) ||
220 #else
221 !ENGINE_set_EC(engine, PKCS11_get_ec_key_method()) ||
222 #endif
223
224 // Make OpenSSL know about our PKCS#11 engine
225 !ENGINE_add(engine))
226 {
227 pkcs11_finish(context_);
228 ENGINE_free(engine);
229 throw OrthancException(ErrorCode_InternalError,
230 "Cannot initialize the OpenSSL engine for PKCS#11");
231 }
232
233 // If the "ENGINE_add" worked, it gets a structural
234 // reference. We release our just-created reference.
235 ENGINE_free(engine);
236
237 return ENGINE_by_id(PKCS11_ENGINE_ID);
238 }
239
240
241 bool IsInitialized()
242 {
243 return pkcs11Initialized_;
244 }
245
246 const char* GetEngineIdentifier()
247 {
248 return PKCS11_ENGINE_ID;
249 }
250
251 void Initialize(const std::string& module,
252 const std::string& pin,
253 bool verbose)
254 {
255 if (pkcs11Initialized_)
256 {
257 throw OrthancException(ErrorCode_BadSequenceOfCalls,
258 "The PKCS#11 engine has already been initialized");
259 }
260
261 if (module.empty() ||
262 !SystemToolbox::IsRegularFile(module))
263 {
264 throw OrthancException(
265 ErrorCode_InexistentFile,
266 "The PKCS#11 module must be a path to one shared library (DLL or .so)");
267 }
268
269 ENGINE* engine = LoadEngine();
270 if (!engine)
271 {
272 throw OrthancException(ErrorCode_InternalError,
273 "Cannot create an OpenSSL engine for PKCS#11");
274 }
275
276 if (!ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", module.c_str(), 0))
277 {
278 throw OrthancException(ErrorCode_InternalError,
279 "Cannot configure the OpenSSL dynamic engine for PKCS#11");
280 }
281
282 if (verbose)
283 {
284 ENGINE_ctrl_cmd_string(engine, "VERBOSE", NULL, 0);
285 }
286
287 if (!pin.empty() &&
288 !ENGINE_ctrl_cmd_string(engine, "PIN", pin.c_str(), 0))
289 {
290 throw OrthancException(ErrorCode_InternalError,
291 "Cannot set the PIN code for PKCS#11");
292 }
293
294 if (!ENGINE_init(engine))
295 {
296 throw OrthancException(ErrorCode_InternalError,
297 "Cannot initialize the OpenSSL dynamic engine for PKCS#11");
298 }
299
300 LOG(WARNING) << "The PKCS#11 engine has been successfully initialized";
301 pkcs11Initialized_ = true;
302 }
303
304
305 void Finalize()
306 {
307 // Nothing to do, the unregistration of the engine is
308 // automatically done by OpenSSL
309 }
310 }
311 }