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         || ctx->is_functional)
213         goto bad_arg;
214 
215     if (!ENGINE_free(ctx->engine))
216         goto err;
217     ctx->engine = NULL;
218     return atom_ok;
219 
220  bad_arg:
221  err:
222     return enif_make_badarg(env);
223 #else
224     return atom_notsup;
225 #endif
226 }
227 
engine_finish_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])228 ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
229 {/* (Engine) */
230 #ifdef HAS_ENGINE_SUPPORT
231     struct engine_ctx *ctx;
232 
233     // Get Engine
234     ASSERT(argc == 1);
235 
236     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
237         || !ctx->is_functional)
238         goto bad_arg;
239 
240     if (!ENGINE_finish(ctx->engine))
241         goto err;
242     ctx->is_functional = 0;
243     return atom_ok;
244 
245  bad_arg:
246  err:
247     return enif_make_badarg(env);
248 
249 #else
250     return atom_notsup;
251 #endif
252 }
253 
engine_load_dynamic_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])254 ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
255 {/* () */
256 #ifdef HAS_ENGINE_SUPPORT
257     ASSERT(argc == 0);
258 
259     ENGINE_load_dynamic();
260     return atom_ok;
261 #else
262     return atom_notsup;
263 #endif
264 }
265 
engine_ctrl_cmd_strings_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])266 ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
267 {/* (Engine, Commands, Optional) */
268 #ifdef HAS_ENGINE_SUPPORT
269     ERL_NIF_TERM ret;
270     unsigned int cmds_len = 0;
271     char **cmds = NULL;
272     struct engine_ctx *ctx;
273     unsigned int i;
274     int optional = 0;
275     int cmds_loaded = 0;
276 
277     // Get Engine
278     ASSERT(argc == 3);
279 
280     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
281         || !ctx->engine)
282         goto bad_arg;
283 
284     PRINTF_ERR1("Engine Id:  %s\r\n", ENGINE_get_id(ctx->engine));
285     // Get Command List
286     if (!enif_get_list_length(env, argv[1], &cmds_len))
287         goto bad_arg;
288 
289     if (cmds_len > (UINT_MAX / 2) - 1)
290         goto err;
291     cmds_len *= 2; // Key-Value list from erlang
292 
293     if ((size_t)cmds_len + 1 > SIZE_MAX / sizeof(char*))
294         goto err;
295     if ((cmds = enif_alloc((cmds_len + 1) * sizeof(char*))) == NULL)
296         goto err;
297     if (get_engine_load_cmd_list(env, argv[1], cmds, 0))
298         goto err;
299     cmds_loaded = 1;
300     if (!enif_get_int(env, argv[2], &optional))
301         goto err;
302 
303     for(i = 0; i < cmds_len; i+=2) {
304         PRINTF_ERR2("Cmd:  %s:%s\r\n",
305                    cmds[i] ? cmds[i] : "(NULL)",
306                    cmds[i+1] ? cmds[i+1] : "(NULL)");
307         if(!ENGINE_ctrl_cmd_string(ctx->engine, cmds[i], cmds[i+1], optional)) {
308             PRINTF_ERR2("Command failed:  %s:%s\r\n",
309                         cmds[i] ? cmds[i] : "(NULL)",
310                         cmds[i+1] ? cmds[i+1] : "(NULL)");
311             goto cmd_failed;
312         }
313     }
314     ret = atom_ok;
315     goto done;
316 
317  bad_arg:
318  err:
319     ret = enif_make_badarg(env);
320     goto done;
321 
322  cmd_failed:
323     ret = ERROR_Atom(env, "ctrl_cmd_failed");
324 
325  done:
326     if (cmds_loaded) {
327         for (i = 0; cmds != NULL && cmds[i] != NULL; i++)
328             enif_free(cmds[i]);
329     }
330 
331     if (cmds != NULL)
332         enif_free(cmds);
333 
334     return ret;
335 
336 #else
337     return atom_notsup;
338 #endif
339 }
340 
engine_add_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])341 ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
342 {/* (Engine) */
343 #ifdef HAS_ENGINE_SUPPORT
344     struct engine_ctx *ctx;
345 
346     // Get Engine
347     ASSERT(argc == 1);
348 
349     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
350         || !ctx->engine)
351         goto bad_arg;
352 
353     if (!ENGINE_add(ctx->engine))
354         goto failed;
355 
356     return atom_ok;
357 
358  bad_arg:
359     return enif_make_badarg(env);
360 
361  failed:
362     return ERROR_Atom(env, "add_engine_failed");
363 
364 #else
365     return atom_notsup;
366 #endif
367 }
368 
engine_remove_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])369 ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
370 {/* (Engine) */
371 #ifdef HAS_ENGINE_SUPPORT
372     struct engine_ctx *ctx;
373 
374     // Get Engine
375     ASSERT(argc == 1);
376 
377     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
378         || !ctx->engine)
379         goto bad_arg;
380 
381     if (!ENGINE_remove(ctx->engine))
382         goto failed;
383 
384     return atom_ok;
385 
386  bad_arg:
387     return enif_make_badarg(env);
388 
389  failed:
390     return ERROR_Atom(env, "remove_engine_failed");
391 #else
392     return atom_notsup;
393 #endif
394 }
395 
engine_register_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])396 ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
397 {/* (Engine, EngineMethod) */
398 #ifdef HAS_ENGINE_SUPPORT
399     struct engine_ctx *ctx;
400     unsigned int method;
401 
402     // Get Engine
403     ASSERT(argc == 2);
404 
405     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
406         || !ctx->engine)
407         goto bad_arg;
408     if (!enif_get_uint(env, argv[1], &method))
409         goto bad_arg;
410 
411     switch(method)
412     {
413 #ifdef ENGINE_METHOD_RSA
414     case ENGINE_METHOD_RSA:
415         if (!ENGINE_register_RSA(ctx->engine))
416             goto failed;
417         break;
418 #endif
419 #ifdef ENGINE_METHOD_DSA
420     case ENGINE_METHOD_DSA:
421         if (!ENGINE_register_DSA(ctx->engine))
422             goto failed;
423         break;
424 #endif
425 #ifdef ENGINE_METHOD_DH
426     case ENGINE_METHOD_DH:
427         if (!ENGINE_register_DH(ctx->engine))
428             goto failed;
429         break;
430 #endif
431 #ifdef ENGINE_METHOD_RAND
432     case ENGINE_METHOD_RAND:
433         if (!ENGINE_register_RAND(ctx->engine))
434             goto failed;
435         break;
436 #endif
437 #ifdef ENGINE_METHOD_ECDH
438     case ENGINE_METHOD_ECDH:
439         if (!ENGINE_register_ECDH(ctx->engine))
440             goto failed;
441         break;
442 #endif
443 #ifdef ENGINE_METHOD_ECDSA
444     case ENGINE_METHOD_ECDSA:
445         if (!ENGINE_register_ECDSA(ctx->engine))
446             goto failed;
447         break;
448 #endif
449 #ifdef ENGINE_METHOD_STORE
450     case ENGINE_METHOD_STORE:
451         if (!ENGINE_register_STORE(ctx->engine))
452             goto failed;
453         break;
454 #endif
455 #ifdef ENGINE_METHOD_CIPHERS
456     case ENGINE_METHOD_CIPHERS:
457         if (!ENGINE_register_ciphers(ctx->engine))
458             goto failed;
459         break;
460 #endif
461 #ifdef ENGINE_METHOD_DIGESTS
462     case ENGINE_METHOD_DIGESTS:
463         if (!ENGINE_register_digests(ctx->engine))
464             goto failed;
465         break;
466 #endif
467 #ifdef ENGINE_METHOD_PKEY_METHS
468     case ENGINE_METHOD_PKEY_METHS:
469         if (!ENGINE_register_pkey_meths(ctx->engine))
470             goto failed;
471         break;
472 #endif
473 #ifdef ENGINE_METHOD_PKEY_ASN1_METHS
474     case ENGINE_METHOD_PKEY_ASN1_METHS:
475         if (!ENGINE_register_pkey_asn1_meths(ctx->engine))
476             goto failed;
477         break;
478 #endif
479 #ifdef ENGINE_METHOD_EC
480     case ENGINE_METHOD_EC:
481         if (!ENGINE_register_EC(ctx->engine))
482             goto failed;
483         break;
484 #endif
485     default:
486         return ERROR_Atom(env, "engine_method_not_supported");
487     }
488 
489     return atom_ok;
490 
491  bad_arg:
492     return enif_make_badarg(env);
493 
494  failed:
495     return ERROR_Atom(env, "register_engine_failed");
496 
497 #else
498     return atom_notsup;
499 #endif
500 }
501 
engine_unregister_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])502 ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
503 {/* (Engine, EngineMethod) */
504 #ifdef HAS_ENGINE_SUPPORT
505     struct engine_ctx *ctx;
506     unsigned int method;
507 
508     // Get Engine
509     ASSERT(argc == 2);
510 
511     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
512         || !ctx->engine)
513         goto bad_arg;
514     if (!enif_get_uint(env, argv[1], &method))
515         goto bad_arg;
516 
517     switch(method)
518     {
519 #ifdef ENGINE_METHOD_RSA
520     case ENGINE_METHOD_RSA:
521         ENGINE_unregister_RSA(ctx->engine);
522         break;
523 #endif
524 #ifdef ENGINE_METHOD_DSA
525     case ENGINE_METHOD_DSA:
526         ENGINE_unregister_DSA(ctx->engine);
527         break;
528 #endif
529 #ifdef ENGINE_METHOD_DH
530     case ENGINE_METHOD_DH:
531         ENGINE_unregister_DH(ctx->engine);
532         break;
533 #endif
534 #ifdef ENGINE_METHOD_RAND
535     case ENGINE_METHOD_RAND:
536         ENGINE_unregister_RAND(ctx->engine);
537         break;
538 #endif
539 #ifdef ENGINE_METHOD_ECDH
540     case ENGINE_METHOD_ECDH:
541         ENGINE_unregister_ECDH(ctx->engine);
542         break;
543 #endif
544 #ifdef ENGINE_METHOD_ECDSA
545     case ENGINE_METHOD_ECDSA:
546         ENGINE_unregister_ECDSA(ctx->engine);
547         break;
548 #endif
549 #ifdef ENGINE_METHOD_STORE
550     case ENGINE_METHOD_STORE:
551         ENGINE_unregister_STORE(ctx->engine);
552         break;
553 #endif
554 #ifdef ENGINE_METHOD_CIPHERS
555     case ENGINE_METHOD_CIPHERS:
556         ENGINE_unregister_ciphers(ctx->engine);
557         break;
558 #endif
559 #ifdef ENGINE_METHOD_DIGESTS
560     case ENGINE_METHOD_DIGESTS:
561         ENGINE_unregister_digests(ctx->engine);
562         break;
563 #endif
564 #ifdef ENGINE_METHOD_PKEY_METHS
565     case ENGINE_METHOD_PKEY_METHS:
566         ENGINE_unregister_pkey_meths(ctx->engine);
567         break;
568 #endif
569 #ifdef ENGINE_METHOD_PKEY_ASN1_METHS
570     case ENGINE_METHOD_PKEY_ASN1_METHS:
571         ENGINE_unregister_pkey_asn1_meths(ctx->engine);
572         break;
573 #endif
574 #ifdef ENGINE_METHOD_EC
575     case ENGINE_METHOD_EC:
576         ENGINE_unregister_EC(ctx->engine);
577         break;
578 #endif
579     default:
580         break;
581     }
582 
583     return atom_ok;
584 
585  bad_arg:
586     return enif_make_badarg(env);
587 
588 #else
589     return atom_notsup;
590 #endif
591 }
592 
engine_get_first_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])593 ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
594 {/* () */
595 #ifdef HAS_ENGINE_SUPPORT
596     ERL_NIF_TERM ret, result;
597     ENGINE *engine;
598     ErlNifBinary engine_bin;
599     struct engine_ctx *ctx = NULL;
600 
601     ASSERT(argc == 0);
602 
603     if ((engine = ENGINE_get_first()) == NULL) {
604         if (!enif_alloc_binary(0, &engine_bin))
605             goto err;
606         engine_bin.size = 0;
607         return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
608     }
609 
610     if ((ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
611         goto err;
612     ctx->is_functional = 0;
613     ctx->engine = engine;
614     ctx->id = NULL;
615 
616     result = enif_make_resource(env, ctx);
617     ret = enif_make_tuple2(env, atom_ok, result);
618     goto done;
619 
620  err:
621     ret = enif_make_badarg(env);
622 
623  done:
624     if (ctx)
625         enif_release_resource(ctx);
626     return ret;
627 
628 #else
629     return atom_notsup;
630 #endif
631 }
632 
engine_get_next_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])633 ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
634 {/* (Engine) */
635 #ifdef HAS_ENGINE_SUPPORT
636     ERL_NIF_TERM ret, result;
637     ENGINE *engine;
638     ErlNifBinary engine_bin;
639     struct engine_ctx *ctx, *next_ctx = NULL;
640 
641     // Get Engine
642     ASSERT(argc == 1);
643 
644     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
645         || !ctx->engine)
646         goto bad_arg;
647 
648     engine = ENGINE_get_next(ctx->engine);
649     ctx->engine = NULL;
650 
651     if (engine == NULL) {
652         if (!enif_alloc_binary(0, &engine_bin))
653             goto err;
654         engine_bin.size = 0;
655         return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin));
656     }
657 
658     if ((next_ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx))) == NULL)
659         goto err;
660     next_ctx->engine = engine;
661     next_ctx->is_functional = 0;
662     next_ctx->id = NULL;
663 
664     result = enif_make_resource(env, next_ctx);
665     ret = enif_make_tuple2(env, atom_ok, result);
666     goto done;
667 
668  bad_arg:
669  err:
670     ret = enif_make_badarg(env);
671 
672  done:
673     if (next_ctx)
674         enif_release_resource(next_ctx);
675     return ret;
676 
677 #else
678     return atom_notsup;
679 #endif
680 }
681 
engine_get_id_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])682 ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
683 {/* (Engine) */
684 #ifdef HAS_ENGINE_SUPPORT
685     ErlNifBinary engine_id_bin;
686     const char *engine_id;
687     size_t size;
688     struct engine_ctx *ctx = NULL;
689 
690     // Get Engine
691     ASSERT(argc == 1);
692 
693     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
694         || !ctx->engine)
695         goto bad_arg;
696 
697     if ((engine_id = ENGINE_get_id(ctx->engine)) == NULL) {
698         if (!enif_alloc_binary(0, &engine_id_bin))
699             goto err;
700         engine_id_bin.size = 0;
701         return enif_make_binary(env, &engine_id_bin);
702     }
703 
704     size = strlen(engine_id);
705     if (!enif_alloc_binary(size, &engine_id_bin))
706         goto err;
707     engine_id_bin.size = size;
708     memcpy(engine_id_bin.data, engine_id, size);
709 
710     return enif_make_binary(env, &engine_id_bin);
711 
712  bad_arg:
713  err:
714     return enif_make_badarg(env);
715 
716 #else
717     return atom_notsup;
718 #endif
719 }
720 
engine_get_name_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])721 ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
722 {/* (Engine) */
723 #ifdef HAS_ENGINE_SUPPORT
724     ErlNifBinary engine_name_bin;
725     const char *engine_name;
726     size_t size;
727     struct engine_ctx *ctx;
728 
729     // Get Engine
730     ASSERT(argc == 1);
731 
732     if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)
733         || !ctx->engine)
734         goto bad_arg;
735 
736     if ((engine_name = ENGINE_get_name(ctx->engine)) == NULL) {
737         if (!enif_alloc_binary(0, &engine_name_bin))
738             goto err;
739         engine_name_bin.size = 0;
740         return enif_make_binary(env, &engine_name_bin);
741     }
742 
743     size = strlen(engine_name);
744     if (!enif_alloc_binary(size, &engine_name_bin))
745         goto err;
746     engine_name_bin.size = size;
747     memcpy(engine_name_bin.data, engine_name, size);
748 
749     return enif_make_binary(env, &engine_name_bin);
750 
751  bad_arg:
752  err:
753     return enif_make_badarg(env);
754 
755 #else
756     return atom_notsup;
757 #endif
758 }
759 
760 #ifdef HAS_ENGINE_SUPPORT
get_engine_load_cmd_list(ErlNifEnv * env,const ERL_NIF_TERM term,char ** cmds,int i)761 static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i)
762 {
763     ERL_NIF_TERM head, tail;
764     const ERL_NIF_TERM *tmp_tuple;
765     ErlNifBinary tmpbin;
766     int arity;
767     char *tuple1 = NULL, *tuple2 = NULL;
768 
769     if (enif_is_empty_list(env, term)) {
770         cmds[i] = NULL;
771         return 0;
772     }
773 
774     if (!enif_get_list_cell(env, term, &head, &tail))
775         goto err;
776     if (!enif_get_tuple(env, head, &arity, &tmp_tuple))
777         goto err;
778     if (arity != 2)
779         goto err;
780     if (!enif_inspect_binary(env, tmp_tuple[0], &tmpbin))
781         goto err;
782 
783     if ((tuple1 = enif_alloc(tmpbin.size + 1)) == NULL)
784         goto err;
785 
786     (void) memcpy(tuple1, tmpbin.data, tmpbin.size);
787     tuple1[tmpbin.size] = '\0';
788     cmds[i] = tuple1;
789     i++;
790 
791     if (!enif_inspect_binary(env, tmp_tuple[1], &tmpbin))
792         goto err;
793 
794     if (tmpbin.size == 0) {
795         cmds[i] = NULL;
796     } else {
797         if ((tuple2 = enif_alloc(tmpbin.size + 1)) == NULL)
798             goto err;
799         (void) memcpy(tuple2, tmpbin.data, tmpbin.size);
800         tuple2[tmpbin.size] = '\0';
801         cmds[i] = tuple2;
802     }
803     i++;
804     return get_engine_load_cmd_list(env, tail, cmds, i);
805 
806  err:
807     if (tuple1 != NULL) {
808         i--;
809         enif_free(tuple1);
810     }
811     cmds[i] = NULL;
812     return -1;
813 }
814 #endif /* HAS_ENGINE_SUPPORT */
815 
engine_get_all_methods_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])816 ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
817 {/* () */
818 #ifdef HAS_ENGINE_SUPPORT
819     ERL_NIF_TERM method_array[12];
820     unsigned int i = 0;
821 
822     ASSERT(argc == 0);
823 
824 #ifdef ENGINE_METHOD_RSA
825     method_array[i++] = atom_engine_method_rsa;
826 #endif
827 #ifdef ENGINE_METHOD_DSA
828     method_array[i++] = atom_engine_method_dsa;
829 #endif
830 #ifdef ENGINE_METHOD_DH
831     method_array[i++] = atom_engine_method_dh;
832 #endif
833 #ifdef ENGINE_METHOD_RAND
834     method_array[i++] = atom_engine_method_rand;
835 #endif
836 #ifdef ENGINE_METHOD_ECDH
837     method_array[i++] = atom_engine_method_ecdh;
838 #endif
839 #ifdef ENGINE_METHOD_ECDSA
840     method_array[i++] = atom_engine_method_ecdsa;
841 #endif
842 #ifdef ENGINE_METHOD_STORE
843     method_array[i++] = atom_engine_method_store;
844 #endif
845 #ifdef ENGINE_METHOD_CIPHERS
846     method_array[i++] = atom_engine_method_ciphers;
847 #endif
848 #ifdef ENGINE_METHOD_DIGESTS
849     method_array[i++] = atom_engine_method_digests;
850 #endif
851 #ifdef ENGINE_METHOD_PKEY_METHS
852     method_array[i++] = atom_engine_method_pkey_meths;
853 #endif
854 #ifdef ENGINE_METHOD_PKEY_ASN1_METHS
855     method_array[i++] = atom_engine_method_pkey_asn1_meths;
856 #endif
857 #ifdef ENGINE_METHOD_EC
858     method_array[i++] = atom_engine_method_ec;
859 #endif
860 
861     return enif_make_list_from_array(env, method_array, i);
862 #else
863     return atom_notsup;
864 #endif
865 }
866