1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2010-2020. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 #include "engine.h"
22 
23 #ifdef HAS_ENGINE_SUPPORT
24 struct engine_ctx {
25     ENGINE *engine;
26     int is_functional;
27     char *id;
28 };
29 
30 #define ERROR_Term(Env, ReasonTerm) enif_make_tuple2((Env), atom_error, (ReasonTerm))
31 #define ERROR_Atom(Env, ReasonString) ERROR_Term((Env), enif_make_atom((Env),(ReasonString)))
32 
33 static ErlNifResourceType* engine_ctx_rtype;
34 
35 static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i);
36 static int zero_terminate(ErlNifBinary bin, char **buf);
37 
engine_ctx_dtor(ErlNifEnv * env,struct engine_ctx * ctx)38 static void engine_ctx_dtor(ErlNifEnv* env, struct engine_ctx* ctx) {
39     if (ctx == NULL)
40         return;
41 
42     PRINTF_ERR0("engine_ctx_dtor");
43     if(ctx->id) {
44         PRINTF_ERR1("  non empty ctx->id=%s", ctx->id);
45         enif_free(ctx->id);
46     } else
47          PRINTF_ERR0("  empty ctx->id=NULL");
48 
49     if (ctx->engine) {
50         if (ctx->is_functional)
51             ENGINE_finish(ctx->engine);
52         ENGINE_free(ctx->engine);
53     }
54 }
55 
get_engine_and_key_id(ErlNifEnv * env,ERL_NIF_TERM key,char ** id,ENGINE ** e)56 int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE **e)
57 {
58     ERL_NIF_TERM engine_res, key_id_term;
59     struct engine_ctx *ctx;
60     ErlNifBinary key_id_bin;
61 
62     if (!enif_get_map_value(env, key, atom_engine, &engine_res))
63         goto err;
64     if (!enif_get_resource(env, engine_res, engine_ctx_rtype, (void**)&ctx))
65         goto err;
66     if (!enif_get_map_value(env, key, atom_key_id, &key_id_term))
67         goto err;
68     if (!enif_inspect_binary(env, key_id_term, &key_id_bin))
69         goto err;
70 
71     *e = ctx->engine;
72     return zero_terminate(key_id_bin, id);
73 
74  err:
75     return 0;
76 }
77 
get_key_password(ErlNifEnv * env,ERL_NIF_TERM key)78 char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key) {
79     ERL_NIF_TERM tmp_term;
80     ErlNifBinary pwd_bin;
81     char *pwd = NULL;
82 
83     if (!enif_get_map_value(env, key, atom_password, &tmp_term))
84         goto err;
85     if (!enif_inspect_binary(env, tmp_term, &pwd_bin))
86         goto err;
87     if (!zero_terminate(pwd_bin, &pwd))
88         goto err;
89 
90     return pwd;
91 
92  err:
93     return NULL;
94 }
95 
zero_terminate(ErlNifBinary bin,char ** buf)96 static int zero_terminate(ErlNifBinary bin, char **buf) {
97     if ((*buf = enif_alloc(bin.size + 1)) == NULL)
98         goto err;
99 
100     memcpy(*buf, bin.data, bin.size);
101     *(*buf + bin.size) = 0;
102 
103     return 1;
104 
105  err:
106     return 0;
107 }
108 #endif /* HAS_ENGINE_SUPPORT */
109 
init_engine_ctx(ErlNifEnv * env)110 int init_engine_ctx(ErlNifEnv *env) {
111 #ifdef HAS_ENGINE_SUPPORT
112     engine_ctx_rtype = enif_open_resource_type(env, NULL, "ENGINE_CTX",
113                                                    (ErlNifResourceDtor*) engine_ctx_dtor,
114                                                    ERL_NIF_RT_CREATE|ERL_NIF_RT_TAKEOVER,
115                                                    NULL);
116     if (engine_ctx_rtype == NULL) {
117         PRINTF_ERR0("CRYPTO: Could not open resource type 'ENGINE_CTX'");
118         return 0;
119     }
120 #endif
121 
122     return 1;
123 }
124 
engine_by_id_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])125 ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
126 {/* (EngineId) */
127 #ifdef HAS_ENGINE_SUPPORT
128     ERL_NIF_TERM ret, result;
129     ErlNifBinary engine_id_bin;
130     char *engine_id = NULL;
131     ENGINE *engine;
132     struct engine_ctx *ctx = NULL;
133 
134     // Get Engine Id
135     ASSERT(argc == 1);
136 
137     if (!enif_inspect_binary(env, argv[0], &engine_id_bin))
138         goto bad_arg;
139 
140     if ((engine_id = enif_alloc(engine_id_bin.size+1)) == NULL)
141         goto err;
142     (void) memcpy(engine_id, engine_id_bin.data, engine_id_bin.size);
143     engine_id[engine_id_bin.size] = '\0';
144 
145     if ((engine = ENGINE_by_id(engine_id)) == NULL) {
146         PRINTF_ERR0("engine_by_id_nif Leaved: {error, bad_engine_id}");
147         ret = ERROR_Atom(env, "bad_engine_id");
148         goto done;
149     }
150 
151     if ((ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
152         goto err;
153     ctx->engine = engine;
154     ctx->is_functional = 0;
155     ctx->id = engine_id;
156     /* ctx now owns engine_id */
157     engine_id = NULL;
158 
159     result = enif_make_resource(env, ctx);
160     ret = enif_make_tuple2(env, atom_ok, result);
161     goto done;
162 
163  bad_arg:
164  err:
165     ret = enif_make_badarg(env);
166 
167  done:
168     if (engine_id)
169         enif_free(engine_id);
170     if (ctx)
171         enif_release_resource(ctx);
172     return ret;
173 
174 #else
175     return atom_notsup;
176 #endif
177 }
178 
engine_init_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])179 ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
180 {/* (Engine) */
181 #ifdef HAS_ENGINE_SUPPORT
182     struct engine_ctx *ctx;
183 
184     // Get Engine
185     ASSERT(argc == 1);
186 
187     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
188         goto bad_arg;
189 
190     if (!ENGINE_init(ctx->engine))
191         return ERROR_Atom(env, "engine_init_failed");
192     ctx->is_functional = 1;
193     return atom_ok;
194 
195  bad_arg:
196     return enif_make_badarg(env);
197 
198 #else
199     return atom_notsup;
200 #endif
201 }
202 
engine_free_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])203 ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
204 {/* (Engine) */
205 #ifdef HAS_ENGINE_SUPPORT
206     struct engine_ctx *ctx;
207 
208     // Get Engine
209     ASSERT(argc == 1);
210 
211     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx))
212         goto bad_arg;
213 
214     if (ctx->engine) {
215         if (ctx->is_functional) {
216             if (!ENGINE_finish(ctx->engine))
217                 goto err;
218             ctx->is_functional = 0;
219         }
220         if (!ENGINE_free(ctx->engine))
221             goto err;
222         ctx->engine = NULL;
223     }
224     else {
225         ASSERT(!ctx->is_functional);
226     }
227     return atom_ok;
228 
229  bad_arg:
230  err:
231     return enif_make_badarg(env);
232 #else
233     return atom_notsup;
234 #endif
235 }
236 
engine_load_dynamic_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])237 ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
238 {/* () */
239 #ifdef HAS_ENGINE_SUPPORT
240     ASSERT(argc == 0);
241 
242     ENGINE_load_dynamic();
243     return atom_ok;
244 #else
245     return atom_notsup;
246 #endif
247 }
248 
engine_ctrl_cmd_strings_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])249 ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
250 {/* (Engine, Commands, Optional) */
251 #ifdef HAS_ENGINE_SUPPORT
252     ERL_NIF_TERM ret;
253     unsigned int cmds_len = 0;
254     char **cmds = NULL;
255     struct engine_ctx *ctx;
256     unsigned int i;
257     int optional = 0;
258     int cmds_loaded = 0;
259 
260     // Get Engine
261     ASSERT(argc == 3);
262 
263     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
264         || !ctx->engine)
265         goto bad_arg;
266 
267     PRINTF_ERR1("Engine Id:  %s\r\n", ENGINE_get_id(ctx->engine));
268     // Get Command List
269     if (!enif_get_list_length(env, argv[1], &cmds_len))
270         goto bad_arg;
271 
272     if (cmds_len > (UINT_MAX / 2) - 1)
273         goto err;
274     cmds_len *= 2; // Key-Value list from erlang
275 
276     if ((size_t)cmds_len + 1 > SIZE_MAX / sizeof(char*))
277         goto err;
278     if ((cmds = enif_alloc((cmds_len + 1) * sizeof(char*))) == NULL)
279         goto err;
280     if (get_engine_load_cmd_list(env, argv[1], cmds, 0))
281         goto err;
282     cmds_loaded = 1;
283     if (!enif_get_int(env, argv[2], &optional))
284         goto err;
285 
286     for(i = 0; i < cmds_len; i+=2) {
287         PRINTF_ERR2("Cmd:  %s:%s\r\n",
288                    cmds[i] ? cmds[i] : "(NULL)",
289                    cmds[i+1] ? cmds[i+1] : "(NULL)");
290         if(!ENGINE_ctrl_cmd_string(ctx->engine, cmds[i], cmds[i+1], optional)) {
291             PRINTF_ERR2("Command failed:  %s:%s\r\n",
292                         cmds[i] ? cmds[i] : "(NULL)",
293                         cmds[i+1] ? cmds[i+1] : "(NULL)");
294             goto cmd_failed;
295         }
296     }
297     ret = atom_ok;
298     goto done;
299 
300  bad_arg:
301  err:
302     ret = enif_make_badarg(env);
303     goto done;
304 
305  cmd_failed:
306     ret = ERROR_Atom(env, "ctrl_cmd_failed");
307 
308  done:
309     if (cmds_loaded) {
310         for (i = 0; cmds != NULL && cmds[i] != NULL; i++)
311             enif_free(cmds[i]);
312     }
313 
314     if (cmds != NULL)
315         enif_free(cmds);
316 
317     return ret;
318 
319 #else
320     return atom_notsup;
321 #endif
322 }
323 
engine_add_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])324 ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
325 {/* (Engine) */
326 #ifdef HAS_ENGINE_SUPPORT
327     struct engine_ctx *ctx;
328 
329     // Get Engine
330     ASSERT(argc == 1);
331 
332     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
333         || !ctx->engine)
334         goto bad_arg;
335 
336     if (!ENGINE_add(ctx->engine))
337         goto failed;
338 
339     return atom_ok;
340 
341  bad_arg:
342     return enif_make_badarg(env);
343 
344  failed:
345     return ERROR_Atom(env, "add_engine_failed");
346 
347 #else
348     return atom_notsup;
349 #endif
350 }
351 
engine_remove_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])352 ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
353 {/* (Engine) */
354 #ifdef HAS_ENGINE_SUPPORT
355     struct engine_ctx *ctx;
356 
357     // Get Engine
358     ASSERT(argc == 1);
359 
360     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
361         || !ctx->engine)
362         goto bad_arg;
363 
364     if (!ENGINE_remove(ctx->engine))
365         goto failed;
366 
367     return atom_ok;
368 
369  bad_arg:
370     return enif_make_badarg(env);
371 
372  failed:
373     return ERROR_Atom(env, "remove_engine_failed");
374 #else
375     return atom_notsup;
376 #endif
377 }
378 
engine_register_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])379 ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
380 {/* (Engine, EngineMethod) */
381 #ifdef HAS_ENGINE_SUPPORT
382     struct engine_ctx *ctx;
383     unsigned int method;
384 
385     // Get Engine
386     ASSERT(argc == 2);
387 
388     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
389         || !ctx->engine)
390         goto bad_arg;
391     if (!enif_get_uint(env, argv[1], &method))
392         goto bad_arg;
393 
394     switch(method)
395     {
396 #ifdef ENGINE_METHOD_RSA
397     case ENGINE_METHOD_RSA:
398         if (!ENGINE_register_RSA(ctx->engine))
399             goto failed;
400         break;
401 #endif
402 #ifdef ENGINE_METHOD_DSA
403     case ENGINE_METHOD_DSA:
404         if (!ENGINE_register_DSA(ctx->engine))
405             goto failed;
406         break;
407 #endif
408 #ifdef ENGINE_METHOD_DH
409     case ENGINE_METHOD_DH:
410         if (!ENGINE_register_DH(ctx->engine))
411             goto failed;
412         break;
413 #endif
414 #ifdef ENGINE_METHOD_RAND
415     case ENGINE_METHOD_RAND:
416         if (!ENGINE_register_RAND(ctx->engine))
417             goto failed;
418         break;
419 #endif
420 #ifdef ENGINE_METHOD_ECDH
421     case ENGINE_METHOD_ECDH:
422         if (!ENGINE_register_ECDH(ctx->engine))
423             goto failed;
424         break;
425 #endif
426 #ifdef ENGINE_METHOD_ECDSA
427     case ENGINE_METHOD_ECDSA:
428         if (!ENGINE_register_ECDSA(ctx->engine))
429             goto failed;
430         break;
431 #endif
432 #ifdef ENGINE_METHOD_STORE
433     case ENGINE_METHOD_STORE:
434         if (!ENGINE_register_STORE(ctx->engine))
435             goto failed;
436         break;
437 #endif
438 #ifdef ENGINE_METHOD_CIPHERS
439     case ENGINE_METHOD_CIPHERS:
440         if (!ENGINE_register_ciphers(ctx->engine))
441             goto failed;
442         break;
443 #endif
444 #ifdef ENGINE_METHOD_DIGESTS
445     case ENGINE_METHOD_DIGESTS:
446         if (!ENGINE_register_digests(ctx->engine))
447             goto failed;
448         break;
449 #endif
450 #ifdef ENGINE_METHOD_PKEY_METHS
451     case ENGINE_METHOD_PKEY_METHS:
452         if (!ENGINE_register_pkey_meths(ctx->engine))
453             goto failed;
454         break;
455 #endif
456 #ifdef ENGINE_METHOD_PKEY_ASN1_METHS
457     case ENGINE_METHOD_PKEY_ASN1_METHS:
458         if (!ENGINE_register_pkey_asn1_meths(ctx->engine))
459             goto failed;
460         break;
461 #endif
462 #ifdef ENGINE_METHOD_EC
463     case ENGINE_METHOD_EC:
464         if (!ENGINE_register_EC(ctx->engine))
465             goto failed;
466         break;
467 #endif
468     default:
469         return ERROR_Atom(env, "engine_method_not_supported");
470     }
471 
472     return atom_ok;
473 
474  bad_arg:
475     return enif_make_badarg(env);
476 
477  failed:
478     return ERROR_Atom(env, "register_engine_failed");
479 
480 #else
481     return atom_notsup;
482 #endif
483 }
484 
engine_unregister_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])485 ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
486 {/* (Engine, EngineMethod) */
487 #ifdef HAS_ENGINE_SUPPORT
488     struct engine_ctx *ctx;
489     unsigned int method;
490 
491     // Get Engine
492     ASSERT(argc == 2);
493 
494     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
495         || !ctx->engine)
496         goto bad_arg;
497     if (!enif_get_uint(env, argv[1], &method))
498         goto bad_arg;
499 
500     switch(method)
501     {
502 #ifdef ENGINE_METHOD_RSA
503     case ENGINE_METHOD_RSA:
504         ENGINE_unregister_RSA(ctx->engine);
505         break;
506 #endif
507 #ifdef ENGINE_METHOD_DSA
508     case ENGINE_METHOD_DSA:
509         ENGINE_unregister_DSA(ctx->engine);
510         break;
511 #endif
512 #ifdef ENGINE_METHOD_DH
513     case ENGINE_METHOD_DH:
514         ENGINE_unregister_DH(ctx->engine);
515         break;
516 #endif
517 #ifdef ENGINE_METHOD_RAND
518     case ENGINE_METHOD_RAND:
519         ENGINE_unregister_RAND(ctx->engine);
520         break;
521 #endif
522 #ifdef ENGINE_METHOD_ECDH
523     case ENGINE_METHOD_ECDH:
524         ENGINE_unregister_ECDH(ctx->engine);
525         break;
526 #endif
527 #ifdef ENGINE_METHOD_ECDSA
528     case ENGINE_METHOD_ECDSA:
529         ENGINE_unregister_ECDSA(ctx->engine);
530         break;
531 #endif
532 #ifdef ENGINE_METHOD_STORE
533     case ENGINE_METHOD_STORE:
534         ENGINE_unregister_STORE(ctx->engine);
535         break;
536 #endif
537 #ifdef ENGINE_METHOD_CIPHERS
538     case ENGINE_METHOD_CIPHERS:
539         ENGINE_unregister_ciphers(ctx->engine);
540         break;
541 #endif
542 #ifdef ENGINE_METHOD_DIGESTS
543     case ENGINE_METHOD_DIGESTS:
544         ENGINE_unregister_digests(ctx->engine);
545         break;
546 #endif
547 #ifdef ENGINE_METHOD_PKEY_METHS
548     case ENGINE_METHOD_PKEY_METHS:
549         ENGINE_unregister_pkey_meths(ctx->engine);
550         break;
551 #endif
552 #ifdef ENGINE_METHOD_PKEY_ASN1_METHS
553     case ENGINE_METHOD_PKEY_ASN1_METHS:
554         ENGINE_unregister_pkey_asn1_meths(ctx->engine);
555         break;
556 #endif
557 #ifdef ENGINE_METHOD_EC
558     case ENGINE_METHOD_EC:
559         ENGINE_unregister_EC(ctx->engine);
560         break;
561 #endif
562     default:
563         break;
564     }
565 
566     return atom_ok;
567 
568  bad_arg:
569     return enif_make_badarg(env);
570 
571 #else
572     return atom_notsup;
573 #endif
574 }
575 
engine_get_first_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])576 ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
577 {/* () */
578 #ifdef HAS_ENGINE_SUPPORT
579     ERL_NIF_TERM ret, result;
580     ENGINE *engine;
581     ErlNifBinary engine_bin;
582     struct engine_ctx *ctx = NULL;
583 
584     ASSERT(argc == 0);
585 
586     if ((engine = ENGINE_get_first()) == NULL) {
587         if (!enif_alloc_binary(0, &engine_bin))
588             goto err;
589         engine_bin.size = 0;
590         return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
591     }
592 
593     if ((ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
594         goto err;
595     ctx->is_functional = 0;
596     ctx->engine = engine;
597     ctx->id = NULL;
598 
599     result = enif_make_resource(env, ctx);
600     ret = enif_make_tuple2(env, atom_ok, result);
601     goto done;
602 
603  err:
604     ret = enif_make_badarg(env);
605 
606  done:
607     if (ctx)
608         enif_release_resource(ctx);
609     return ret;
610 
611 #else
612     return atom_notsup;
613 #endif
614 }
615 
engine_get_next_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])616 ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
617 {/* (Engine) */
618 #ifdef HAS_ENGINE_SUPPORT
619     ERL_NIF_TERM ret, result;
620     ENGINE *engine;
621     ErlNifBinary engine_bin;
622     struct engine_ctx *ctx, *next_ctx = NULL;
623 
624     // Get Engine
625     ASSERT(argc == 1);
626 
627     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
628         || !ctx->engine)
629         goto bad_arg;
630 
631     if (ctx->is_functional) {
632         ENGINE_finish(ctx->engine);
633         ctx->is_functional = 0;
634     }
635     engine = ENGINE_get_next(ctx->engine);
636     ctx->engine = NULL;
637 
638     if (engine == NULL) {
639         if (!enif_alloc_binary(0, &engine_bin))
640             goto err;
641         engine_bin.size = 0;
642         return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
643     }
644 
645     if ((next_ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
646         goto err;
647     next_ctx->engine = engine;
648     next_ctx->is_functional = 0;
649     next_ctx->id = NULL;
650 
651     result = enif_make_resource(env, next_ctx);
652     ret = enif_make_tuple2(env, atom_ok, result);
653     goto done;
654 
655  bad_arg:
656  err:
657     ret = enif_make_badarg(env);
658 
659  done:
660     if (next_ctx)
661         enif_release_resource(next_ctx);
662     return ret;
663 
664 #else
665     return atom_notsup;
666 #endif
667 }
668 
engine_get_id_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])669 ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
670 {/* (Engine) */
671 #ifdef HAS_ENGINE_SUPPORT
672     ErlNifBinary engine_id_bin;
673     const char *engine_id;
674     size_t size;
675     struct engine_ctx *ctx = NULL;
676 
677     // Get Engine
678     ASSERT(argc == 1);
679 
680     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
681         || !ctx->engine)
682         goto bad_arg;
683 
684     if ((engine_id = ENGINE_get_id(ctx->engine)) == NULL) {
685         if (!enif_alloc_binary(0, &engine_id_bin))
686             goto err;
687         engine_id_bin.size = 0;
688         return enif_make_binary(env, &engine_id_bin);
689     }
690 
691     size = strlen(engine_id);
692     if (!enif_alloc_binary(size, &engine_id_bin))
693         goto err;
694     engine_id_bin.size = size;
695     memcpy(engine_id_bin.data, engine_id, size);
696 
697     return enif_make_binary(env, &engine_id_bin);
698 
699  bad_arg:
700  err:
701     return enif_make_badarg(env);
702 
703 #else
704     return atom_notsup;
705 #endif
706 }
707 
engine_get_name_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])708 ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
709 {/* (Engine) */
710 #ifdef HAS_ENGINE_SUPPORT
711     ErlNifBinary engine_name_bin;
712     const char *engine_name;
713     size_t size;
714     struct engine_ctx *ctx;
715 
716     // Get Engine
717     ASSERT(argc == 1);
718 
719     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
720         || !ctx->engine)
721         goto bad_arg;
722 
723     if ((engine_name = ENGINE_get_name(ctx->engine)) == NULL) {
724         if (!enif_alloc_binary(0, &engine_name_bin))
725             goto err;
726         engine_name_bin.size = 0;
727         return enif_make_binary(env, &engine_name_bin);
728     }
729 
730     size = strlen(engine_name);
731     if (!enif_alloc_binary(size, &engine_name_bin))
732         goto err;
733     engine_name_bin.size = size;
734     memcpy(engine_name_bin.data, engine_name, size);
735 
736     return enif_make_binary(env, &engine_name_bin);
737 
738  bad_arg:
739  err:
740     return enif_make_badarg(env);
741 
742 #else
743     return atom_notsup;
744 #endif
745 }
746 
747 #ifdef HAS_ENGINE_SUPPORT
get_engine_load_cmd_list(ErlNifEnv * env,const ERL_NIF_TERM term,char ** cmds,int i)748 static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i)
749 {
750     ERL_NIF_TERM head, tail;
751     const ERL_NIF_TERM *tmp_tuple;
752     ErlNifBinary tmpbin;
753     int arity;
754     char *tuple1 = NULL, *tuple2 = NULL;
755 
756     if (enif_is_empty_list(env, term)) {
757         cmds[i] = NULL;
758         return 0;
759     }
760 
761     if (!enif_get_list_cell(env, term, &head, &tail))
762         goto err;
763     if (!enif_get_tuple(env, head, &arity, &tmp_tuple))
764         goto err;
765     if (arity != 2)
766         goto err;
767     if (!enif_inspect_binary(env, tmp_tuple[0], &tmpbin))
768         goto err;
769 
770     if ((tuple1 = enif_alloc(tmpbin.size + 1)) == NULL)
771         goto err;
772 
773     (void) memcpy(tuple1, tmpbin.data, tmpbin.size);
774     tuple1[tmpbin.size] = '\0';
775     cmds[i] = tuple1;
776     i++;
777 
778     if (!enif_inspect_binary(env, tmp_tuple[1], &tmpbin))
779         goto err;
780 
781     if (tmpbin.size == 0) {
782         cmds[i] = NULL;
783     } else {
784         if ((tuple2 = enif_alloc(tmpbin.size + 1)) == NULL)
785             goto err;
786         (void) memcpy(tuple2, tmpbin.data, tmpbin.size);
787         tuple2[tmpbin.size] = '\0';
788         cmds[i] = tuple2;
789     }
790     i++;
791     return get_engine_load_cmd_list(env, tail, cmds, i);
792 
793  err:
794     if (tuple1 != NULL) {
795         i--;
796         enif_free(tuple1);
797     }
798     cmds[i] = NULL;
799     return -1;
800 }
801 #endif /* HAS_ENGINE_SUPPORT */
802 
engine_get_all_methods_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])803 ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
804 {/* () */
805 #ifdef HAS_ENGINE_SUPPORT
806     ERL_NIF_TERM method_array[12];
807     unsigned int i = 0;
808 
809     ASSERT(argc == 0);
810 
811 #ifdef ENGINE_METHOD_RSA
812     method_array[i++] = atom_engine_method_rsa;
813 #endif
814 #ifdef ENGINE_METHOD_DSA
815     method_array[i++] = atom_engine_method_dsa;
816 #endif
817 #ifdef ENGINE_METHOD_DH
818     method_array[i++] = atom_engine_method_dh;
819 #endif
820 #ifdef ENGINE_METHOD_RAND
821     method_array[i++] = atom_engine_method_rand;
822 #endif
823 #ifdef ENGINE_METHOD_ECDH
824     method_array[i++] = atom_engine_method_ecdh;
825 #endif
826 #ifdef ENGINE_METHOD_ECDSA
827     method_array[i++] = atom_engine_method_ecdsa;
828 #endif
829 #ifdef ENGINE_METHOD_STORE
830     method_array[i++] = atom_engine_method_store;
831 #endif
832 #ifdef ENGINE_METHOD_CIPHERS
833     method_array[i++] = atom_engine_method_ciphers;
834 #endif
835 #ifdef ENGINE_METHOD_DIGESTS
836     method_array[i++] = atom_engine_method_digests;
837 #endif
838 #ifdef ENGINE_METHOD_PKEY_METHS
839     method_array[i++] = atom_engine_method_pkey_meths;
840 #endif
841 #ifdef ENGINE_METHOD_PKEY_ASN1_METHS
842     method_array[i++] = atom_engine_method_pkey_asn1_meths;
843 #endif
844 #ifdef ENGINE_METHOD_EC
845     method_array[i++] = atom_engine_method_ec;
846 #endif
847 
848     return enif_make_list_from_array(env, method_array, i);
849 #else
850     return atom_notsup;
851 #endif
852 }
853