/* * %CopyrightBegin% * * Copyright Ericsson AB 2010-2018. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * %CopyrightEnd% */ #include "engine.h" #ifdef HAS_ENGINE_SUPPORT ErlNifResourceType* engine_ctx_rtype; static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i); static int zero_terminate(ErlNifBinary bin, char **buf); void engine_ctx_dtor(ErlNifEnv* env, struct engine_ctx* ctx) { PRINTF_ERR0("engine_ctx_dtor"); if(ctx->id) { PRINTF_ERR1(" non empty ctx->id=%s", ctx->id); enif_free(ctx->id); } else PRINTF_ERR0(" empty ctx->id=NULL"); } int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE **e) { ERL_NIF_TERM engine_res, key_id_term; struct engine_ctx *ctx; ErlNifBinary key_id_bin; if (!enif_get_map_value(env, key, atom_engine, &engine_res) || !enif_get_resource(env, engine_res, engine_ctx_rtype, (void**)&ctx) || !enif_get_map_value(env, key, atom_key_id, &key_id_term) || !enif_inspect_binary(env, key_id_term, &key_id_bin)) { return 0; } else { *e = ctx->engine; return zero_terminate(key_id_bin, id); } } char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key) { ERL_NIF_TERM tmp_term; ErlNifBinary pwd_bin; char *pwd = NULL; if (enif_get_map_value(env, key, atom_password, &tmp_term) && enif_inspect_binary(env, tmp_term, &pwd_bin) && zero_terminate(pwd_bin, &pwd) ) return pwd; return NULL; } static int zero_terminate(ErlNifBinary bin, char **buf) { *buf = enif_alloc(bin.size+1); if (!*buf) return 0; memcpy(*buf, bin.data, bin.size); *(*buf+bin.size) = 0; return 1; } #endif /* HAS_ENGINE_SUPPORT */ ERL_NIF_TERM engine_by_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (EngineId) */ #ifdef HAS_ENGINE_SUPPORT ERL_NIF_TERM ret; ErlNifBinary engine_id_bin; char *engine_id; ENGINE *engine; struct engine_ctx *ctx; // Get Engine Id if(!enif_inspect_binary(env, argv[0], &engine_id_bin)) { PRINTF_ERR0("engine_by_id_nif Leaved: badarg"); return enif_make_badarg(env); } else { engine_id = enif_alloc(engine_id_bin.size+1); (void) memcpy(engine_id, engine_id_bin.data, engine_id_bin.size); engine_id[engine_id_bin.size] = '\0'; } engine = ENGINE_by_id(engine_id); if(!engine) { enif_free(engine_id); PRINTF_ERR0("engine_by_id_nif Leaved: {error, bad_engine_id}"); return enif_make_tuple2(env, atom_error, atom_bad_engine_id); } ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx)); ctx->engine = engine; ctx->id = engine_id; ret = enif_make_resource(env, ctx); enif_release_resource(ctx); return enif_make_tuple2(env, atom_ok, ret); #else return atom_notsup; #endif } ERL_NIF_TERM engine_init_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT ERL_NIF_TERM ret = atom_ok; struct engine_ctx *ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_init_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } if (!ENGINE_init(ctx->engine)) { //ERR_print_errors_fp(stderr); PRINTF_ERR0("engine_init_nif Leaved: {error, engine_init_failed}"); return enif_make_tuple2(env, atom_error, atom_engine_init_failed); } return ret; #else return atom_notsup; #endif } ERL_NIF_TERM engine_free_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT struct engine_ctx *ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_free_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } ENGINE_free(ctx->engine); return atom_ok; #else return atom_notsup; #endif } ERL_NIF_TERM engine_finish_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT struct engine_ctx *ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_finish_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } ENGINE_finish(ctx->engine); return atom_ok; #else return atom_notsup; #endif } ERL_NIF_TERM engine_load_dynamic_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* () */ #ifdef HAS_ENGINE_SUPPORT ENGINE_load_dynamic(); return atom_ok; #else return atom_notsup; #endif } ERL_NIF_TERM engine_ctrl_cmd_strings_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine, Commands) */ #ifdef HAS_ENGINE_SUPPORT ERL_NIF_TERM ret = atom_ok; unsigned int cmds_len = 0; char **cmds = NULL; struct engine_ctx *ctx; int i, optional = 0; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } PRINTF_ERR1("Engine Id: %s\r\n", ENGINE_get_id(ctx->engine)); // Get Command List if(!enif_get_list_length(env, argv[1], &cmds_len)) { PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Bad Command List"); return enif_make_badarg(env); } else { cmds_len *= 2; // Key-Value list from erlang cmds = enif_alloc((cmds_len+1)*sizeof(char*)); if(get_engine_load_cmd_list(env, argv[1], cmds, 0)) { PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Couldn't read Command List"); ret = enif_make_badarg(env); goto error; } } if(!enif_get_int(env, argv[2], &optional)) { PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: Parameter optional not an integer"); return enif_make_badarg(env); } for(i = 0; i < cmds_len; i+=2) { PRINTF_ERR2("Cmd: %s:%s\r\n", cmds[i] ? cmds[i] : "(NULL)", cmds[i+1] ? cmds[i+1] : "(NULL)"); if(!ENGINE_ctrl_cmd_string(ctx->engine, cmds[i], cmds[i+1], optional)) { PRINTF_ERR2("Command failed: %s:%s\r\n", cmds[i] ? cmds[i] : "(NULL)", cmds[i+1] ? cmds[i+1] : "(NULL)"); //ENGINE_free(ctx->engine); ret = enif_make_tuple2(env, atom_error, atom_ctrl_cmd_failed); PRINTF_ERR0("engine_ctrl_cmd_strings_nif Leaved: {error, ctrl_cmd_failed}"); goto error; } } error: for(i = 0; cmds != NULL && cmds[i] != NULL; i++) enif_free(cmds[i]); enif_free(cmds); return ret; #else return atom_notsup; #endif } ERL_NIF_TERM engine_add_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT struct engine_ctx *ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_add_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } if (!ENGINE_add(ctx->engine)) { PRINTF_ERR0("engine_add_nif Leaved: {error, add_engine_failed}"); return enif_make_tuple2(env, atom_error, atom_add_engine_failed); } return atom_ok; #else return atom_notsup; #endif } ERL_NIF_TERM engine_remove_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT struct engine_ctx *ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_remove_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } if (!ENGINE_remove(ctx->engine)) { PRINTF_ERR0("engine_remove_nif Leaved: {error, remove_engine_failed}"); return enif_make_tuple2(env, atom_error, atom_remove_engine_failed); } return atom_ok; #else return atom_notsup; #endif } ERL_NIF_TERM engine_register_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine, EngineMethod) */ #ifdef HAS_ENGINE_SUPPORT struct engine_ctx *ctx; unsigned int method; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_register_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } // Get Method if (!enif_get_uint(env, argv[1], &method)) { PRINTF_ERR0("engine_register_nif Leaved: Parameter Method not an uint"); return enif_make_badarg(env); } switch(method) { #ifdef ENGINE_METHOD_RSA case ENGINE_METHOD_RSA: if (!ENGINE_register_RSA(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_DSA case ENGINE_METHOD_DSA: if (!ENGINE_register_DSA(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_DH case ENGINE_METHOD_DH: if (!ENGINE_register_DH(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_RAND case ENGINE_METHOD_RAND: if (!ENGINE_register_RAND(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_ECDH case ENGINE_METHOD_ECDH: if (!ENGINE_register_ECDH(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_ECDSA case ENGINE_METHOD_ECDSA: if (!ENGINE_register_ECDSA(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_STORE case ENGINE_METHOD_STORE: if (!ENGINE_register_STORE(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_CIPHERS case ENGINE_METHOD_CIPHERS: if (!ENGINE_register_ciphers(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_DIGESTS case ENGINE_METHOD_DIGESTS: if (!ENGINE_register_digests(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_PKEY_METHS case ENGINE_METHOD_PKEY_METHS: if (!ENGINE_register_pkey_meths(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_PKEY_ASN1_METHS case ENGINE_METHOD_PKEY_ASN1_METHS: if (!ENGINE_register_pkey_asn1_meths(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif #ifdef ENGINE_METHOD_EC case ENGINE_METHOD_EC: if (!ENGINE_register_EC(ctx->engine)) return enif_make_tuple2(env, atom_error, atom_register_engine_failed); break; #endif default: return enif_make_tuple2(env, atom_error, atom_engine_method_not_supported); break; } return atom_ok; #else return atom_notsup; #endif } ERL_NIF_TERM engine_unregister_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine, EngineMethod) */ #ifdef HAS_ENGINE_SUPPORT struct engine_ctx *ctx; unsigned int method; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_unregister_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } // Get Method if (!enif_get_uint(env, argv[1], &method)) { PRINTF_ERR0("engine_unregister_nif Leaved: Parameter Method not an uint"); return enif_make_badarg(env); } switch(method) { #ifdef ENGINE_METHOD_RSA case ENGINE_METHOD_RSA: ENGINE_unregister_RSA(ctx->engine); break; #endif #ifdef ENGINE_METHOD_DSA case ENGINE_METHOD_DSA: ENGINE_unregister_DSA(ctx->engine); break; #endif #ifdef ENGINE_METHOD_DH case ENGINE_METHOD_DH: ENGINE_unregister_DH(ctx->engine); break; #endif #ifdef ENGINE_METHOD_RAND case ENGINE_METHOD_RAND: ENGINE_unregister_RAND(ctx->engine); break; #endif #ifdef ENGINE_METHOD_ECDH case ENGINE_METHOD_ECDH: ENGINE_unregister_ECDH(ctx->engine); break; #endif #ifdef ENGINE_METHOD_ECDSA case ENGINE_METHOD_ECDSA: ENGINE_unregister_ECDSA(ctx->engine); break; #endif #ifdef ENGINE_METHOD_STORE case ENGINE_METHOD_STORE: ENGINE_unregister_STORE(ctx->engine); break; #endif #ifdef ENGINE_METHOD_CIPHERS case ENGINE_METHOD_CIPHERS: ENGINE_unregister_ciphers(ctx->engine); break; #endif #ifdef ENGINE_METHOD_DIGESTS case ENGINE_METHOD_DIGESTS: ENGINE_unregister_digests(ctx->engine); break; #endif #ifdef ENGINE_METHOD_PKEY_METHS case ENGINE_METHOD_PKEY_METHS: ENGINE_unregister_pkey_meths(ctx->engine); break; #endif #ifdef ENGINE_METHOD_PKEY_ASN1_METHS case ENGINE_METHOD_PKEY_ASN1_METHS: ENGINE_unregister_pkey_asn1_meths(ctx->engine); break; #endif #ifdef ENGINE_METHOD_EC case ENGINE_METHOD_EC: ENGINE_unregister_EC(ctx->engine); break; #endif default: break; } return atom_ok; #else return atom_notsup; #endif } ERL_NIF_TERM engine_get_first_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT ERL_NIF_TERM ret; ENGINE *engine; ErlNifBinary engine_bin; struct engine_ctx *ctx; engine = ENGINE_get_first(); if(!engine) { enif_alloc_binary(0, &engine_bin); engine_bin.size = 0; return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin)); } ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx)); ctx->engine = engine; ctx->id = NULL; ret = enif_make_resource(env, ctx); enif_release_resource(ctx); return enif_make_tuple2(env, atom_ok, ret); #else return atom_notsup; #endif } ERL_NIF_TERM engine_get_next_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT ERL_NIF_TERM ret; ENGINE *engine; ErlNifBinary engine_bin; struct engine_ctx *ctx, *next_ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_get_next_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } engine = ENGINE_get_next(ctx->engine); if (!engine) { enif_alloc_binary(0, &engine_bin); engine_bin.size = 0; return enif_make_tuple2(env, atom_ok, enif_make_binary(env, &engine_bin)); } next_ctx = enif_alloc_resource(engine_ctx_rtype, sizeof(struct engine_ctx)); next_ctx->engine = engine; next_ctx->id = NULL; ret = enif_make_resource(env, next_ctx); enif_release_resource(next_ctx); return enif_make_tuple2(env, atom_ok, ret); #else return atom_notsup; #endif } ERL_NIF_TERM engine_get_id_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT ErlNifBinary engine_id_bin; const char *engine_id; int size; struct engine_ctx *ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_get_id_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } engine_id = ENGINE_get_id(ctx->engine); if (!engine_id) { enif_alloc_binary(0, &engine_id_bin); engine_id_bin.size = 0; return enif_make_binary(env, &engine_id_bin); } size = strlen(engine_id); enif_alloc_binary(size, &engine_id_bin); engine_id_bin.size = size; memcpy(engine_id_bin.data, engine_id, size); return enif_make_binary(env, &engine_id_bin); #else return atom_notsup; #endif } ERL_NIF_TERM engine_get_name_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* (Engine) */ #ifdef HAS_ENGINE_SUPPORT ErlNifBinary engine_name_bin; const char *engine_name; int size; struct engine_ctx *ctx; // Get Engine if (!enif_get_resource(env, argv[0], engine_ctx_rtype, (void**)&ctx)) { PRINTF_ERR0("engine_get_id_nif Leaved: Parameter not an engine resource object"); return enif_make_badarg(env); } engine_name = ENGINE_get_name(ctx->engine); if (!engine_name) { enif_alloc_binary(0, &engine_name_bin); engine_name_bin.size = 0; return enif_make_binary(env, &engine_name_bin); } size = strlen(engine_name); enif_alloc_binary(size, &engine_name_bin); engine_name_bin.size = size; memcpy(engine_name_bin.data, engine_name, size); return enif_make_binary(env, &engine_name_bin); #else return atom_notsup; #endif } #ifdef HAS_ENGINE_SUPPORT static int get_engine_load_cmd_list(ErlNifEnv* env, const ERL_NIF_TERM term, char **cmds, int i) { ERL_NIF_TERM head, tail; const ERL_NIF_TERM *tmp_tuple; ErlNifBinary tmpbin; int arity; char* tmpstr; if(!enif_is_empty_list(env, term)) { if(!enif_get_list_cell(env, term, &head, &tail)) { cmds[i] = NULL; return -1; } else { if(!enif_get_tuple(env, head, &arity, &tmp_tuple) || arity != 2) { cmds[i] = NULL; return -1; } else { if(!enif_inspect_binary(env, tmp_tuple[0], &tmpbin)) { cmds[i] = NULL; return -1; } else { tmpstr = enif_alloc(tmpbin.size+1); (void) memcpy(tmpstr, tmpbin.data, tmpbin.size); tmpstr[tmpbin.size] = '\0'; cmds[i++] = tmpstr; } if(!enif_inspect_binary(env, tmp_tuple[1], &tmpbin)) { cmds[i] = NULL; return -1; } else { if(tmpbin.size == 0) cmds[i++] = NULL; else { tmpstr = enif_alloc(tmpbin.size+1); (void) memcpy(tmpstr, tmpbin.data, tmpbin.size); tmpstr[tmpbin.size] = '\0'; cmds[i++] = tmpstr; } } return get_engine_load_cmd_list(env, tail, cmds, i); } } } else { cmds[i] = NULL; return 0; } } #endif /* HAS_ENGINE_SUPPORT */ ERL_NIF_TERM engine_get_all_methods_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) {/* () */ #ifdef HAS_ENGINE_SUPPORT ERL_NIF_TERM method_array[12]; int i = 0; #ifdef ENGINE_METHOD_RSA method_array[i++] = atom_engine_method_rsa; #endif #ifdef ENGINE_METHOD_DSA method_array[i++] = atom_engine_method_dsa; #endif #ifdef ENGINE_METHOD_DH method_array[i++] = atom_engine_method_dh; #endif #ifdef ENGINE_METHOD_RAND method_array[i++] = atom_engine_method_rand; #endif #ifdef ENGINE_METHOD_ECDH method_array[i++] = atom_engine_method_ecdh; #endif #ifdef ENGINE_METHOD_ECDSA method_array[i++] = atom_engine_method_ecdsa; #endif #ifdef ENGINE_METHOD_STORE method_array[i++] = atom_engine_method_store; #endif #ifdef ENGINE_METHOD_CIPHERS method_array[i++] = atom_engine_method_ciphers; #endif #ifdef ENGINE_METHOD_DIGESTS method_array[i++] = atom_engine_method_digests; #endif #ifdef ENGINE_METHOD_PKEY_METHS method_array[i++] = atom_engine_method_pkey_meths; #endif #ifdef ENGINE_METHOD_PKEY_ASN1_METHS method_array[i++] = atom_engine_method_pkey_asn1_meths; #endif #ifdef ENGINE_METHOD_EC method_array[i++] = atom_engine_method_ec; #endif return enif_make_list_from_array(env, method_array, i); #else return atom_notsup; #endif }