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