1 /* $NetBSD: engine.c,v 1.4 2017/01/28 21:31:47 christos Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <config.h> 37 #include <krb5/roken.h> 38 39 #include <engine.h> 40 41 #ifdef HAVE_DLFCN_H 42 #include <dlfcn.h> 43 #ifndef RTLD_NOW 44 #define RTLD_NOW 0 45 #endif 46 #endif 47 48 struct hc_engine { 49 int references; 50 char *name; 51 char *id; 52 void (*destroy)(ENGINE *); 53 const RSA_METHOD *rsa; 54 const DH_METHOD *dh; 55 const RAND_METHOD *rand; 56 }; 57 58 ENGINE * 59 ENGINE_new(void) 60 { 61 ENGINE *engine; 62 63 engine = calloc(1, sizeof(*engine)); 64 engine->references = 1; 65 66 return engine; 67 } 68 69 int 70 ENGINE_free(ENGINE *engine) 71 { 72 return ENGINE_finish(engine); 73 } 74 75 int 76 ENGINE_finish(ENGINE *engine) 77 { 78 if (engine->references-- <= 0) 79 abort(); 80 if (engine->references > 0) 81 return 1; 82 83 if (engine->name) 84 free(engine->name); 85 if (engine->id) 86 free(engine->id); 87 if(engine->destroy) 88 (*engine->destroy)(engine); 89 90 memset(engine, 0, sizeof(*engine)); 91 engine->references = -1; 92 93 94 free(engine); 95 return 1; 96 } 97 98 int 99 ENGINE_up_ref(ENGINE *engine) 100 { 101 if (engine->references < 0) 102 abort(); 103 engine->references++; 104 return 1; 105 } 106 107 int 108 ENGINE_set_id(ENGINE *engine, const char *id) 109 { 110 engine->id = strdup(id); 111 return (engine->id == NULL) ? 0 : 1; 112 } 113 114 int 115 ENGINE_set_name(ENGINE *engine, const char *name) 116 { 117 engine->name = strdup(name); 118 return (engine->name == NULL) ? 0 : 1; 119 } 120 121 int 122 ENGINE_set_RSA(ENGINE *engine, const RSA_METHOD *method) 123 { 124 engine->rsa = method; 125 return 1; 126 } 127 128 int 129 ENGINE_set_DH(ENGINE *engine, const DH_METHOD *method) 130 { 131 engine->dh = method; 132 return 1; 133 } 134 135 int 136 ENGINE_set_destroy_function(ENGINE *e, void (*destroy)(ENGINE *)) 137 { 138 e->destroy = destroy; 139 return 1; 140 } 141 142 const char * 143 ENGINE_get_id(const ENGINE *engine) 144 { 145 return engine->id; 146 } 147 148 const char * 149 ENGINE_get_name(const ENGINE *engine) 150 { 151 return engine->name; 152 } 153 154 const RSA_METHOD * 155 ENGINE_get_RSA(const ENGINE *engine) 156 { 157 return engine->rsa; 158 } 159 160 const DH_METHOD * 161 ENGINE_get_DH(const ENGINE *engine) 162 { 163 return engine->dh; 164 } 165 166 const RAND_METHOD * 167 ENGINE_get_RAND(const ENGINE *engine) 168 { 169 return engine->rand; 170 } 171 172 /* 173 * 174 */ 175 176 #define SG_default_engine(type) \ 177 static ENGINE *type##_engine; \ 178 int \ 179 ENGINE_set_default_##type(ENGINE *engine) \ 180 { \ 181 if (type##_engine) \ 182 ENGINE_finish(type##_engine); \ 183 type##_engine = engine; \ 184 if (type##_engine) \ 185 ENGINE_up_ref(type##_engine); \ 186 return 1; \ 187 } \ 188 ENGINE * \ 189 ENGINE_get_default_##type(void) \ 190 { \ 191 if (type##_engine) \ 192 ENGINE_up_ref(type##_engine); \ 193 return type##_engine; \ 194 } 195 196 SG_default_engine(RSA) 197 SG_default_engine(DH) 198 199 #undef SG_default_engine 200 201 /* 202 * 203 */ 204 205 static ENGINE **engines; 206 static unsigned int num_engines; 207 208 static int 209 add_engine(ENGINE *engine) 210 { 211 ENGINE **d, *dup; 212 213 dup = ENGINE_by_id(engine->id); 214 if (dup) 215 return 0; 216 217 d = realloc(engines, (num_engines + 1) * sizeof(*engines)); 218 if (d == NULL) 219 return 1; 220 engines = d; 221 engines[num_engines++] = engine; 222 223 return 1; 224 } 225 226 void 227 ENGINE_load_builtin_engines(void) 228 { 229 ENGINE *engine; 230 int ret; 231 232 engine = ENGINE_new(); 233 if (engine == NULL) 234 return; 235 236 ENGINE_set_id(engine, "builtin"); 237 ENGINE_set_name(engine, 238 "Heimdal crypto builtin (ltm) engine version " PACKAGE_VERSION); 239 ENGINE_set_RSA(engine, RSA_ltm_method()); 240 ENGINE_set_DH(engine, DH_ltm_method()); 241 242 ret = add_engine(engine); 243 if (ret != 1) 244 ENGINE_finish(engine); 245 246 #ifdef USE_HCRYPTO_TFM 247 /* 248 * TFM 249 */ 250 251 engine = ENGINE_new(); 252 if (engine == NULL) 253 return; 254 255 ENGINE_set_id(engine, "tfm"); 256 ENGINE_set_name(engine, 257 "Heimdal crypto tfm engine version " PACKAGE_VERSION); 258 ENGINE_set_RSA(engine, RSA_tfm_method()); 259 ENGINE_set_DH(engine, DH_tfm_method()); 260 261 ret = add_engine(engine); 262 if (ret != 1) 263 ENGINE_finish(engine); 264 #endif /* USE_HCRYPTO_TFM */ 265 266 #ifdef USE_HCRYPTO_LTM 267 /* 268 * ltm 269 */ 270 271 engine = ENGINE_new(); 272 if (engine == NULL) 273 return; 274 275 ENGINE_set_id(engine, "ltm"); 276 ENGINE_set_name(engine, 277 "Heimdal crypto ltm engine version " PACKAGE_VERSION); 278 ENGINE_set_RSA(engine, RSA_ltm_method()); 279 ENGINE_set_DH(engine, DH_ltm_method()); 280 281 ret = add_engine(engine); 282 if (ret != 1) 283 ENGINE_finish(engine); 284 #endif 285 286 #ifdef HAVE_GMP 287 /* 288 * gmp 289 */ 290 291 engine = ENGINE_new(); 292 if (engine == NULL) 293 return; 294 295 ENGINE_set_id(engine, "gmp"); 296 ENGINE_set_name(engine, 297 "Heimdal crypto gmp engine version " PACKAGE_VERSION); 298 ENGINE_set_RSA(engine, RSA_gmp_method()); 299 300 ret = add_engine(engine); 301 if (ret != 1) 302 ENGINE_finish(engine); 303 #endif 304 } 305 306 ENGINE * 307 ENGINE_by_dso(const char *path, const char *id) 308 { 309 #ifdef HAVE_DLOPEN 310 ENGINE *engine; 311 void *handle; 312 int ret; 313 314 engine = calloc(1, sizeof(*engine)); 315 if (engine == NULL) 316 return NULL; 317 318 handle = dlopen(path, RTLD_NOW); 319 if (handle == NULL) { 320 /* printf("error: %s\n", dlerror()); */ 321 free(engine); 322 return NULL; 323 } 324 325 { 326 unsigned long version; 327 openssl_v_check v_check; 328 329 v_check = (openssl_v_check)dlsym(handle, "v_check"); 330 if (v_check == NULL) { 331 dlclose(handle); 332 free(engine); 333 return NULL; 334 } 335 336 version = (*v_check)(OPENSSL_DYNAMIC_VERSION); 337 if (version == 0) { 338 dlclose(handle); 339 free(engine); 340 return NULL; 341 } 342 } 343 344 { 345 openssl_bind_engine bind_engine; 346 347 bind_engine = (openssl_bind_engine)dlsym(handle, "bind_engine"); 348 if (bind_engine == NULL) { 349 dlclose(handle); 350 free(engine); 351 return NULL; 352 } 353 354 ret = (*bind_engine)(engine, id, NULL); /* XXX fix third arg */ 355 if (ret != 1) { 356 dlclose(handle); 357 free(engine); 358 return NULL; 359 } 360 } 361 362 ENGINE_up_ref(engine); 363 364 ret = add_engine(engine); 365 if (ret != 1) { 366 dlclose(handle); 367 ENGINE_finish(engine); 368 return NULL; 369 } 370 371 return engine; 372 #else 373 return NULL; 374 #endif 375 } 376 377 ENGINE * 378 ENGINE_by_id(const char *id) 379 { 380 int i; 381 382 for (i = 0; i < num_engines; i++) { 383 if (strcmp(id, engines[i]->id) == 0) { 384 ENGINE_up_ref(engines[i]); 385 return engines[i]; 386 } 387 } 388 return NULL; 389 } 390 391 void 392 ENGINE_add_conf_module(void) 393 { 394 } 395