diff options
Diffstat (limited to 'lib/crypto/c_src/pkey.c')
-rw-r--r-- | lib/crypto/c_src/pkey.c | 1437 |
1 files changed, 716 insertions, 721 deletions
diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c index 70c6d1bbe4..bfdcfe3553 100644 --- a/lib/crypto/c_src/pkey.c +++ b/lib/crypto/c_src/pkey.c @@ -27,10 +27,6 @@ #include "engine.h" #include "rsa.h" -#define PKEY_BADARG -1 -#define PKEY_NOTSUP 0 -#define PKEY_OK 1 - typedef struct PKeyCryptOptions { const EVP_MD *rsa_mgf1_md; ErlNifBinary rsa_oaep_label; @@ -46,55 +42,122 @@ typedef struct PKeySignOptions { } PKeySignOptions; -static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type, - const EVP_MD **md); -static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm, - ERL_NIF_TERM type, ERL_NIF_TERM data, +static int check_pkey_algorithm_type(ErlNifEnv *env, + int alg_arg_num, ERL_NIF_TERM algorithm, + ERL_NIF_TERM *err_return); +static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, + int type_arg_num, ERL_NIF_TERM type, + const EVP_MD **md, + ERL_NIF_TERM *err_return); +static int get_pkey_sign_digest(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int type_arg_num, int data_arg_num, unsigned char *md_value, const EVP_MD **mdp, - unsigned char **tbsp, size_t *tbslenp); -static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options, - const EVP_MD *md, PKeySignOptions *opt); -static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, EVP_PKEY **pkey); -static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, - EVP_PKEY **pkey); -static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options, - PKeyCryptOptions *opt); + unsigned char **tbsp, size_t *tbslenp, + ERL_NIF_TERM *err_return); +static int get_pkey_sign_options(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int options_arg_num, + const EVP_MD *md, PKeySignOptions *opt, + ERL_NIF_TERM *err_return); +static int get_pkey_private_key(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int key_arg_num, + EVP_PKEY **pkey, + ERL_NIF_TERM *err_return); +static int get_pkey_public_key(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int key_arg_num, + EVP_PKEY **pkey, + ERL_NIF_TERM *err_return); +static int get_pkey_crypt_options(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int options_arg_num, + PKeyCryptOptions *opt, + ERL_NIF_TERM *err_return); #ifdef HAVE_RSA_SSLV23_PADDING static size_t size_of_RSA(EVP_PKEY *pkey); #endif -static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type, - const EVP_MD **md) +static int check_pkey_algorithm_type(ErlNifEnv *env, + int alg_arg_num, ERL_NIF_TERM algorithm, + ERL_NIF_TERM *err_return) +{ + if ( +#ifndef HAVE_EDDSA + (algorithm == atom_eddsa) || +#endif + +#ifndef HAVE_DSA + (algorithm == atom_dss) || +#endif + +#ifndef HAVE_EC + (algorithm == atom_ecdsa) || +#endif + 0) + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, alg_arg_num, "Unsupported algorithm")); + + +#ifdef HAVE_EDDSA + if (FIPS_MODE()) + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, alg_arg_num, "Unsupported algorithm in FIPS mode")); +#endif + + if ((algorithm != atom_rsa) && + (algorithm != atom_dss) && + (algorithm != atom_ecdsa) && + (algorithm != atom_eddsa) + ) + assign_goto(*err_return, err, EXCP_BADARG_N(env, alg_arg_num, "Bad algorithm")); + + return 1; + + err: + return 0; +} + + +static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, + int type_arg_num, ERL_NIF_TERM type, + const EVP_MD **md, + ERL_NIF_TERM *err_return) { struct digest_type_t *digp = NULL; *md = NULL; if (type == atom_none && algorithm == atom_rsa) - return PKEY_OK; - if (algorithm == atom_eddsa) { -#ifdef HAVE_EDDSA - if (!FIPS_MODE()) return PKEY_OK; -#else - return PKEY_NOTSUP; -#endif - } + return 1; + + if (algorithm == atom_eddsa) /* Type was skipped for eddsa in < OTP-25 + For eddsa the RFC 8032 mandates sha512 in + the algorithm */ + return 1; + if ((digp = get_digest_type(type)) == NULL) - return PKEY_BADARG; + assign_goto(*err_return, notsup, EXCP_BADARG_N(env, type_arg_num, "Bad digest type")); + if (DIGEST_FORBIDDEN_IN_FIPS(digp)) - return PKEY_NOTSUP; + assign_goto(*err_return, notsup, EXCP_BADARG_N(env, type_arg_num, "Digest type forbidden in FIPS")); + if (digp->md.p == NULL) - return PKEY_NOTSUP; + assign_goto(*err_return, notsup, EXCP_BADARG_N(env, type_arg_num, "Digest type not supported")); *md = digp->md.p; - return PKEY_OK; + return 1; + + notsup: + return 0; } -static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm, - ERL_NIF_TERM type, ERL_NIF_TERM data, +static int get_pkey_sign_digest(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int type_arg_num, int data_arg_num, unsigned char *md_value, const EVP_MD **mdp, - unsigned char **tbsp, size_t *tbslenp) + unsigned char **tbsp, size_t *tbslenp, + ERL_NIF_TERM *err_return) { - int i, ret; + int ret; const ERL_NIF_TERM *tpl_terms; int tpl_arity; ErlNifBinary tbs_bin; @@ -108,50 +171,55 @@ static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm, tbs = *tbsp; tbslen = *tbslenp; - if ((i = get_pkey_digest_type(env, algorithm, type, &md)) != PKEY_OK) - return i; + if (!check_pkey_algorithm_type(env, algorithm_arg_num, argv[algorithm_arg_num], err_return)) + goto err; /* An exception is present in ret */ + + if (!get_pkey_digest_type(env, argv[algorithm_arg_num], + type_arg_num, argv[type_arg_num], + &md, err_return)) + goto err; /* An exception is present in ret */ - if (enif_get_tuple(env, data, &tpl_arity, &tpl_terms)) { + if (enif_get_tuple(env, argv[data_arg_num], &tpl_arity, &tpl_terms)) { if (tpl_arity != 2) - goto bad_arg; + assign_goto(*err_return, err, EXCP_BADARG_N(env, data_arg_num, "Bad list")); if (tpl_terms[0] != atom_digest) - goto bad_arg; + assign_goto(*err_return, err, EXCP_BADARG_N(env, data_arg_num, "Expected 'digest' as head")); if (!enif_inspect_iolist_as_binary(env, tpl_terms[1], &tbs_bin)) - goto bad_arg; + assign_goto(*err_return, err, EXCP_BADARG_N(env, data_arg_num, "Bad 2nd element in list")); if (tbs_bin.size > INT_MAX) - goto bad_arg; + assign_goto(*err_return, err, EXCP_BADARG_N(env, data_arg_num, "Too large binary")); if (md != NULL) { if ((int)tbs_bin.size != EVP_MD_size(md)) - goto bad_arg; + assign_goto(*err_return, err, EXCP_BADARG_N(env, data_arg_num, "Bad binary size for the algorithm")); } /* We have a digest (= hashed text) in tbs_bin */ tbs = tbs_bin.data; tbslen = tbs_bin.size; } else if (md == NULL) { - if (!enif_inspect_iolist_as_binary(env, data, &tbs_bin)) - goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[data_arg_num], &tbs_bin)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, data_arg_num, "Expected a binary or a list")); /* md == NULL, that is no hashing because DigestType argument was atom_none */ tbs = tbs_bin.data; tbslen = tbs_bin.size; } else { - if (!enif_inspect_iolist_as_binary(env, data, &tbs_bin)) - goto bad_arg; + if (!enif_inspect_iolist_as_binary(env, argv[data_arg_num], &tbs_bin)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, data_arg_num, "Expected a binary or a list")); /* We have the cleartext in tbs_bin and the hash algo info in md */ tbs = md_value; if ((mdctx = EVP_MD_CTX_create()) == NULL) - goto err; + assign_goto(*err_return, err, EXCP_ERROR(env, "Can't create MD_CTX")); /* Looks well, now hash the plain text into a digest according to md */ if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) - goto err; + assign_goto(*err_return, err, EXCP_ERROR(env, "Can't create EVP_DigestInit_ex")); if (EVP_DigestUpdate(mdctx, tbs_bin.data, tbs_bin.size) != 1) - goto err; + assign_goto(*err_return, err, EXCP_ERROR(env, "Can't create EVP_DigestUpdate")); if (EVP_DigestFinal_ex(mdctx, tbs, &tbsleni) != 1) - goto err; + assign_goto(*err_return, err, EXCP_ERROR(env, "Can't create EVP_DigestFinal_ex")); tbslen = (size_t)tbsleni; } @@ -160,32 +228,33 @@ static int get_pkey_sign_digest(ErlNifEnv *env, ERL_NIF_TERM algorithm, *tbsp = tbs; *tbslenp = tbslen; - ret = PKEY_OK; + ret = 1; goto done; - bad_arg: err: - ret = PKEY_BADARG; - + ret = 0; done: if (mdctx) EVP_MD_CTX_destroy(mdctx); return ret; } -static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options, - const EVP_MD *md, PKeySignOptions *opt) +static int get_pkey_sign_options(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int options_arg_num, + const EVP_MD *md, PKeySignOptions *opt, + ERL_NIF_TERM *err_return) { ERL_NIF_TERM head, tail; const ERL_NIF_TERM *tpl_terms; int tpl_arity; const EVP_MD *opt_md; - if (!enif_is_list(env, options)) - goto bad_arg; + if (!enif_is_list(env, argv[options_arg_num])) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Expected a list")); /* defaults */ - if (algorithm == atom_rsa) { + if (argv[algorithm_arg_num] == atom_rsa) { opt->rsa_mgf1_md = NULL; opt->rsa_padding = RSA_PKCS1_PADDING; opt->rsa_pss_saltlen = -2; @@ -195,26 +264,27 @@ static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF opt->rsa_pss_saltlen = 0; } - if (enif_is_empty_list(env, options)) - return PKEY_OK; + if (enif_is_empty_list(env, argv[options_arg_num])) + return 1; - if (algorithm != atom_rsa) - goto bad_arg; + if (argv[algorithm_arg_num] != atom_rsa) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only RSA supports Options")); - tail = options; + tail = argv[options_arg_num]; while (enif_get_list_cell(env, tail, &head, &tail)) { - if (!enif_get_tuple(env, head, &tpl_arity, &tpl_terms)) - goto bad_arg; - if (tpl_arity != 2) - goto bad_arg; - - if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) { - int result; - - result = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (result != PKEY_OK) - return result; - + if (!enif_get_tuple(env, head, &tpl_arity, &tpl_terms) || + (tpl_arity != 2)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Expects only two-tuples in the list")); + + if (tpl_terms[0] == atom_rsa_mgf1_md) { + if (!enif_is_atom(env, tpl_terms[1])) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Atom expected as argument to option rsa_mgf1_md")); + + if (!get_pkey_digest_type(env, argv[algorithm_arg_num], + options_arg_num, tpl_terms[1], + &opt_md, err_return)) + goto err; /* An exception is present in ret */ + opt->rsa_mgf1_md = opt_md; } else if (tpl_terms[0] == atom_rsa_padding) { @@ -227,7 +297,7 @@ static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF if (opt->rsa_mgf1_md == NULL) opt->rsa_mgf1_md = md; #else - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, options_arg_num, "rsa_pkcs1_pss_padding not supported")); #endif } else if (tpl_terms[1] == atom_rsa_x931_padding) { @@ -237,172 +307,163 @@ static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF opt->rsa_padding = RSA_NO_PADDING; } else { - goto bad_arg; + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Bad value in option rsa_padding")); } } else if (tpl_terms[0] == atom_rsa_pss_saltlen) { - if (!enif_get_int(env, tpl_terms[1], &(opt->rsa_pss_saltlen))) - goto bad_arg; - if (opt->rsa_pss_saltlen < -2) - goto bad_arg; + if (!enif_get_int(env, tpl_terms[1], &(opt->rsa_pss_saltlen)) || + (opt->rsa_pss_saltlen < -2) ) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Bad value in option rsa_pss_saltlen")); } else { - goto bad_arg; + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Bad option")); } } - return PKEY_OK; + return 1; - bad_arg: - return PKEY_BADARG; + err: + return 0; } -static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, EVP_PKEY **pkey) +static int get_pkey_private_key(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int key_arg_num, + EVP_PKEY **pkey, + ERL_NIF_TERM *err_return) { - EVP_PKEY *result = NULL; char *id = NULL; char *password = NULL; + int ret; - if (enif_is_map(env, key)) { + if (enif_is_map(env, argv[key_arg_num])) { #ifdef HAS_ENGINE_SUPPORT /* Use key stored in engine */ ENGINE *e; - if (!get_engine_and_key_id(env, key, &id, &e)) - goto err; - - password = get_key_password(env, key); - result = ENGINE_load_private_key(e, id, NULL, password); + if (!get_engine_and_key_id(env, argv[key_arg_num], &id, &e)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get engine and/or key id")); + password = get_key_password(env, argv[key_arg_num]); + *pkey = ENGINE_load_private_key(e, id, NULL, password); + if (!*pkey) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get private key from engine")); #else - return PKEY_BADARG; + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "No engine support")); #endif - } else if (algorithm == atom_rsa) { - if ((result = EVP_PKEY_new()) == NULL) - goto err; - if (!get_rsa_private_key(env, key, &result)) - goto err; + } else if (argv[algorithm_arg_num] == atom_rsa) { + if (!get_rsa_private_key(env, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get RSA private key")); - } else if (algorithm == atom_ecdsa) { + } else if (argv[algorithm_arg_num] == atom_ecdsa) { #if defined(HAVE_EC) - if ((result = EVP_PKEY_new()) == NULL) - goto err; - if (!get_ec_private_key(env, key, &result)) - goto err; + if (!get_ec_private_key(env, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get ECDSA private key")); #else - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "ECDSA not supported")); #endif - } else if (algorithm == atom_eddsa) { + } else if (argv[algorithm_arg_num] == atom_eddsa) { #ifdef HAVE_EDDSA - if (FIPS_MODE()) - return PKEY_NOTSUP; - if (!get_eddsa_key(env, 0, key, &result)) - goto err; + if (!FIPS_MODE()) { + if (!get_eddsa_key(env, 0, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get EDDSA private key")); + } else + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "EDDSA not supported in FIPS mode")); #else - return PKEY_NOTSUP; -#endif + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "EDDSA not supported")); +#endif - } else if (algorithm == atom_dss) { + } else if (argv[algorithm_arg_num] == atom_dss) { #ifdef HAVE_DSA - if ((result = EVP_PKEY_new()) == NULL) - goto err; - if (!get_dss_private_key(env, key, &result)) - goto err; + if (!get_dss_private_key(env, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get DSA private key")); #else - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "DSA not supported")); #endif } else - return PKEY_BADARG; - + assign_goto(*err_return, err, EXCP_BADARG_N(env, algorithm_arg_num, "Bad algorithm")); - free_and_return: + ret = 1; + done: if (password) enif_free(password); if (id) enif_free(id); - if (result == NULL) { - return PKEY_BADARG; - } else { - *pkey = result; - return PKEY_OK; - } + return ret; err: - if (result) - EVP_PKEY_free(result); - result = NULL; - goto free_and_return; + if (*pkey) + EVP_PKEY_free(*pkey); + *pkey = NULL; + ret = 0; + goto done; } -static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, - EVP_PKEY **pkey) +static int get_pkey_public_key(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int key_arg_num, + EVP_PKEY **pkey, + ERL_NIF_TERM *err_return) { - EVP_PKEY *result = NULL; char *id = NULL; char *password = NULL; + int ret; - if (enif_is_map(env, key)) { + if (enif_is_map(env, argv[key_arg_num])) { #ifdef HAS_ENGINE_SUPPORT /* Use key stored in engine */ ENGINE *e; - if (!get_engine_and_key_id(env, key, &id, &e)) - goto err; - - password = get_key_password(env, key); - result = ENGINE_load_public_key(e, id, NULL, password); + if (!get_engine_and_key_id(env, argv[key_arg_num], &id, &e)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get engine and/or key id")); + password = get_key_password(env, argv[key_arg_num]); + *pkey = ENGINE_load_public_key(e, id, NULL, password); + if (!pkey) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get public key from engine")); #else - return PKEY_BADARG; + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "No engine support")); #endif - } else if (algorithm == atom_rsa) { - if ((result = EVP_PKEY_new()) == NULL) - goto err; - if (!get_rsa_public_key(env, key, &result)) - goto err; - } else if (algorithm == atom_ecdsa) { + } else if (argv[algorithm_arg_num] == atom_rsa) { + if (!get_rsa_public_key(env, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get RSA public key")); + + } else if (argv[algorithm_arg_num] == atom_ecdsa) { #if defined(HAVE_EC) - if ((result = EVP_PKEY_new()) == NULL) - goto err; - if (!get_ec_public_key(env, key, &result)) - goto err; + if (!get_ec_public_key(env, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get ECDSA public key")); #else - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "ECDSA not supported")); #endif - } else if (algorithm == atom_eddsa) { + + } else if (argv[algorithm_arg_num] == atom_eddsa) { #ifdef HAVE_EDDSA if (!FIPS_MODE()) { - if (!get_eddsa_key(env, 1, key, &result)) - goto err; - } + if (!get_eddsa_key(env, 1, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get EDDSA public key")); + } else + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "EDDSA not supported in FIPS mode")); #else - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "EDDSA not supported")); #endif - } else if (algorithm == atom_dss) { + + } else if (argv[algorithm_arg_num] == atom_dss) { #ifdef HAVE_DSA - if ((result = EVP_PKEY_new()) == NULL) - goto err; - if (!get_dss_public_key(env, key, &result)) - goto err; + if (!get_dss_public_key(env, argv[key_arg_num], pkey)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, key_arg_num, "Couldn't get DSA public key")); #else - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, algorithm_arg_num, "DSA not supported")); #endif - } else { - return PKEY_BADARG; - } - - goto done; + } else + assign_goto(*err_return, err, EXCP_BADARG_N(env, algorithm_arg_num, "Bad algorithm")); - err: - if (result) - EVP_PKEY_free(result); - result = NULL; + ret = 1; done: if (password) @@ -410,440 +471,431 @@ static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_T if (id) enif_free(id); - if (result == NULL) { - return PKEY_BADARG; - } else { - *pkey = result; - return PKEY_OK; - } + return ret; + + err: + if (*pkey) + EVP_PKEY_free(*pkey); + *pkey = NULL; + ret = 0; + goto done; } ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {/* (Algorithm, Type, Data|{digest,Digest}, Key|#{}, Options) */ - int i; int sig_bin_alloc = 0; - ERL_NIF_TERM ret; + ERL_NIF_TERM ret = atom_undefined; const EVP_MD *md = NULL; unsigned char md_value[EVP_MAX_MD_SIZE]; EVP_PKEY *pkey = NULL; -#ifdef HAVE_EDDSA - EVP_MD_CTX *mdctx = NULL; -#endif #ifdef HAS_EVP_PKEY_CTX EVP_PKEY_CTX *ctx = NULL; size_t siglen; #else int len; unsigned int siglen; + RSA *rsa = NULL; +# ifdef HAVE_DSA + DSA *dsa = NULL; +# endif +# if defined(HAVE_EC) + EC_KEY *ec = NULL; +# endif #endif PKeySignOptions sig_opt; ErlNifBinary sig_bin; /* signature */ unsigned char *tbs = NULL; /* data to be signed */ size_t tbslen = 0; - RSA *rsa = NULL; -#ifdef HAVE_DSA - DSA *dsa = NULL; -#endif -#if defined(HAVE_EC) - EC_KEY *ec = NULL; -#endif -/*char buf[1024]; -enif_get_atom(env,argv[0],buf,1024,ERL_NIF_LATIN1); printf("algo=%s ",buf); -enif_get_atom(env,argv[1],buf,1024,ERL_NIF_LATIN1); printf("hash=%s ",buf); -*/ #ifndef HAS_ENGINE_SUPPORT if (enif_is_map(env, argv[3])) - return atom_notsup; + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "No engine support")); #endif + if (!get_pkey_sign_digest(env, argv, 0, 1, 2, md_value, &md, &tbs, &tbslen, &ret)) + goto err; /* An exception is present in ret */ - i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen); - switch (i) { - case PKEY_OK: - break; - case PKEY_NOTSUP: - goto notsup; - default: - goto bad_arg; - } - - i = get_pkey_sign_options(env, argv[0], argv[4], md, &sig_opt); - switch (i) { - case PKEY_OK: - break; - case PKEY_NOTSUP: - goto notsup; - default: - goto bad_arg; - } - - if (get_pkey_private_key(env, argv[0], argv[3], &pkey) != PKEY_OK) - goto bad_arg; + if (!get_pkey_sign_options(env, argv, 0, 4, md, &sig_opt, &ret)) + goto err; /* An exception is present in ret */ #ifdef HAS_EVP_PKEY_CTX - if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) - goto err; - - if (argv[0] != atom_eddsa) { - if (EVP_PKEY_sign_init(ctx) != 1) - goto err; - if (md != NULL) { - if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1) - goto err; + { /* EVP_MD_CTX */ + if (!get_pkey_private_key(env, argv, 0, 3, &pkey, &ret)) + goto err; /* An exception is present in ret */ + + if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate new EVP_PKEY_CTX")); + + if (argv[0] != atom_eddsa) { + if (EVP_PKEY_sign_init(ctx) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign_init")); + if (md != NULL) { + if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_signature_md")); + } } - } - if (argv[0] == atom_rsa) { - if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) != 1) - goto err; + if (argv[0] == atom_rsa) { + if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_rsa_padding")); # ifdef HAVE_RSA_PKCS1_PSS_PADDING - if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) { - if (sig_opt.rsa_mgf1_md != NULL) { + if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) { + if (sig_opt.rsa_mgf1_md != NULL) { # ifdef HAVE_RSA_MGF1_MD - if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) != 1) - goto err; + if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_rsa_mgf1_md")); # else - goto notsup; + assign_goto(ret, err, EXCP_NOTSUP_N(env, 4, "rsa_mgf1_md unavailable with this cryptolib")); # endif + } + if (sig_opt.rsa_pss_saltlen > -2) { + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) != 1) + assign_goto(ret, err, EXCP_BADARG_N(env, 4, "Bad rsa_pss_saltlen")); + } } - if (sig_opt.rsa_pss_saltlen > -2) { - if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) != 1) - goto err; - } - } # endif - } + } - if (argv[0] == atom_eddsa) { + if (argv[0] == atom_eddsa) { # ifdef HAVE_EDDSA - if (!FIPS_MODE()) { - if ((mdctx = EVP_MD_CTX_new()) == NULL) - goto err; + if (!FIPS_MODE()) { + EVP_MD_CTX *mdctx = NULL; + if ((mdctx = EVP_MD_CTX_new()) == NULL) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new")); + + if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSignInit")); + if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign")); + if (!enif_alloc_binary(siglen, &sig_bin)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); + sig_bin_alloc = 1; + + if (EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen) != 1) { + if (mdctx) + EVP_MD_CTX_free(mdctx); + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign")); + } + if (mdctx) + EVP_MD_CTX_free(mdctx); + } + else +# endif + assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "eddsa not supported")); + } else { + +# ifndef HAVE_DSA + if (argv[0] == atom_dss) assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "dsa not supported")); + } else { +# endif + if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign")); - if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1) - goto err; - if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1) - goto err; if (!enif_alloc_binary(siglen, &sig_bin)) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); sig_bin_alloc = 1; - if (EVP_DigestSign(mdctx, sig_bin.data, &siglen, tbs, tbslen) != 1) - goto bad_key; + if (md != NULL) { + ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md)); + } + if (EVP_PKEY_sign(ctx, sig_bin.data, &siglen, tbs, tbslen) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign")); } - else -# endif - goto notsup; - } else { - if (EVP_PKEY_sign(ctx, NULL, &siglen, tbs, tbslen) != 1) - goto err; - if (!enif_alloc_binary(siglen, &sig_bin)) - goto err; - sig_bin_alloc = 1; - - if (md != NULL) { - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md)); - } - if (EVP_PKEY_sign(ctx, sig_bin.data, &siglen, tbs, tbslen) != 1) - goto bad_key; - } -#else -/*printf("Old interface\r\n"); - */ - if (argv[0] == atom_rsa) { - if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) - goto err; - if ((len = RSA_size(rsa)) < 0) - goto err; - if (!enif_alloc_binary((size_t)len, &sig_bin)) - goto err; - sig_bin_alloc = 1; - - if ((len = EVP_MD_size(md)) < 0) - goto err; - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); - - if (RSA_sign(md->type, tbs, (unsigned int)len, sig_bin.data, &siglen, rsa) != 1) - goto bad_key; - } else if (argv[0] == atom_dss) { - if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL) - goto err; - if ((len = DSA_size(dsa)) < 0) - goto err; - if (!enif_alloc_binary((size_t)len, &sig_bin)) - goto err; - sig_bin_alloc = 1; - - if ((len = EVP_MD_size(md)) < 0) - goto err; - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); - - if (DSA_sign(md->type, tbs, len, sig_bin.data, &siglen, dsa) != 1) - goto bad_key; - } else if (argv[0] == atom_ecdsa) { -#if defined(HAVE_EC) - if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) - goto err; - if ((len = ECDSA_size(ec)) < 0) - goto err; - if (!enif_alloc_binary((size_t)len, &sig_bin)) - goto err; - sig_bin_alloc = 1; - - len = EVP_MD_size(md); - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); - - if (ECDSA_sign(md->type, tbs, len, sig_bin.data, &siglen, ec) != 1) - goto bad_key; -#else - goto notsup; -#endif - } else { - goto bad_arg; - } -#endif ERL_VALGRIND_MAKE_MEM_DEFINED(sig_bin.data, siglen); if (siglen != sig_bin.size) { if (!enif_realloc_binary(&sig_bin, siglen)) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Can't reallocate binary")); ERL_VALGRIND_ASSERT_MEM_DEFINED(sig_bin.data, siglen); } + ret = enif_make_binary(env, &sig_bin); sig_bin_alloc = 0; - goto done; - - bad_key: - ret = atom_error; - goto done; - - notsup: - ret = atom_notsup; - goto done; - - bad_arg: - err: - ret = enif_make_badarg(env); - goto done; - done: + err: if (sig_bin_alloc) enif_release_binary(&sig_bin); - if (rsa) - RSA_free(rsa); -#ifdef HAVE_DSA - if (dsa) - DSA_free(dsa); -#endif -#ifdef HAVE_EC - if (ec) - EC_KEY_free(ec); -#endif -#ifdef HAS_EVP_PKEY_CTX if (ctx) EVP_PKEY_CTX_free(ctx); -#endif if (pkey) EVP_PKEY_free(pkey); + return ret; + } + /* End of HAS_EVP_PKEY_CTX */ +#else + /* Old interface - before EVP_PKEY_CTX */ + { + if (!get_pkey_private_key(env, argv, 0, 3, &pkey, &ret)) + goto err; /* An exception is present in ret */ + + if (argv[0] == atom_rsa) { + if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Not an RSA private key")); + if ((len = RSA_size(rsa)) < 0) + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Bad RSA private key length")); + if (!enif_alloc_binary((size_t)len, &sig_bin)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); + sig_bin_alloc = 1; -#ifdef HAVE_EDDSA - if (mdctx) - EVP_MD_CTX_free(mdctx); + if ((len = EVP_MD_size(md)) < 0) + assign_goto(ret, err, EXCP_ERROR(env, "Can't get md length")); + ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); + + if (RSA_sign(md->type, tbs, (unsigned int)len, sig_bin.data, &siglen, rsa) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't sign")); + + } else if (argv[0] == atom_dss) { + if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL) + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Not an DSA private key")); + if ((len = DSA_size(dsa)) < 0) + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Bad DSA private key length")); + if (!enif_alloc_binary((size_t)len, &sig_bin)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); + sig_bin_alloc = 1; + + if ((len = EVP_MD_size(md)) < 0) + assign_goto(ret, err, EXCP_ERROR(env, "Can't get md length")); + ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); + + if (DSA_sign(md->type, tbs, len, sig_bin.data, &siglen, dsa) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't sign")); + } else if (argv[0] == atom_ecdsa) { +# if defined(HAVE_EC) + if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Not an ECDSA private key")); + if ((len = ECDSA_size(ec)) < 0) + assign_goto(ret, err, EXCP_ERROR(env, "Can't get size")); + if (!enif_alloc_binary((size_t)len, &sig_bin)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); + sig_bin_alloc = 1; + + len = EVP_MD_size(md); + ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, len); + + if (ECDSA_sign(md->type, tbs, len, sig_bin.data, &siglen, ec) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't sign")); +# else + assign_goto(ret, notsup, EXCP_NOTSUP_N(env, 0, "ecdsa not supported")); +# endif /* HAVE_EC */ + } else { + assign_goto(ret, notsup, EXCP_BADARG_N(env, 0, "Unknown algorithm")); + } + + ERL_VALGRIND_MAKE_MEM_DEFINED(sig_bin.data, siglen); + if (siglen != sig_bin.size) { + if (!enif_realloc_binary(&sig_bin, siglen)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't re-allocate binary")); + ERL_VALGRIND_ASSERT_MEM_DEFINED(sig_bin.data, siglen); + } + ret = enif_make_binary(env, &sig_bin); + sig_bin_alloc = 0; + + notsup: + err: + if (sig_bin_alloc) + enif_release_binary(&sig_bin); + if (rsa) + RSA_free(rsa); +# ifdef HAVE_DSA + if (dsa) + DSA_free(dsa); +# endif +# ifdef HAVE_EC + if (ec) + EC_KEY_free(ec); +# endif +# ifdef HAS_EVP_PKEY_CTX + if (ctx) + EVP_PKEY_CTX_free(ctx); +# endif + if (pkey) + EVP_PKEY_free(pkey); + + return ret; + } #endif - return ret; } + + ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {/* (Algorithm, Type, Data|{digest,Digest}, Signature, Key, Options) */ - int i; int result; const EVP_MD *md = NULL; unsigned char md_value[EVP_MAX_MD_SIZE]; EVP_PKEY *pkey = NULL; -#ifdef HAS_EVP_PKEY_CTX - EVP_PKEY_CTX *ctx = NULL; -#else -#endif PKeySignOptions sig_opt; ErlNifBinary sig_bin; /* signature */ unsigned char *tbs = NULL; /* data to be signed */ size_t tbslen = 0; - ERL_NIF_TERM ret; + ERL_NIF_TERM ret = atom_undefined; + +#ifdef HAS_EVP_PKEY_CTX + EVP_PKEY_CTX *ctx = NULL; +#else RSA *rsa = NULL; -#ifdef HAVE_DSA - DSA *dsa = NULL; -#endif -#ifdef HAVE_EC - EC_KEY *ec = NULL; -#endif -#ifdef HAVE_EDDSA - EVP_MD_CTX *mdctx = NULL; -#endif +# ifdef HAVE_DSA + DSA *dsa = NULL; +# endif +# ifdef HAVE_EC + EC_KEY *ec = NULL; +# endif +#endif // HAS_EVP_PKEY_CTX + #ifndef HAS_ENGINE_SUPPORT - if (enif_is_map(env, argv[4])) - return atom_notsup; + if (enif_is_map(env, argv[3])) + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "No engine support")); #endif - if (!enif_inspect_binary(env, argv[3], &sig_bin)) - return enif_make_badarg(env); - - i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen); - switch (i) { - case PKEY_OK: - break; - case PKEY_NOTSUP: - goto notsup; - default: - goto bad_arg; - } + if (!get_pkey_sign_digest(env, argv, 0, 1, 2, md_value, &md, &tbs, &tbslen, &ret)) + goto err; /* An exception is present in ret */ - i = get_pkey_sign_options(env, argv[0], argv[5], md, &sig_opt); - switch (i) { - case PKEY_OK: - break; - case PKEY_NOTSUP: - goto notsup; - default: - goto bad_arg; - } + if (!get_pkey_sign_options(env, argv, 0, 5, md, &sig_opt, &ret)) + goto err; /* An exception is present in ret */ - if (get_pkey_public_key(env, argv[0], argv[4], &pkey) != PKEY_OK) { - goto bad_arg; - } + if (!enif_inspect_binary(env, argv[3], &sig_bin)) + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Expected a binary")); #ifdef HAS_EVP_PKEY_CTX -/* printf("EVP interface\r\n"); - */ - if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) - goto err; - - if (argv[0] != atom_eddsa) { - if (EVP_PKEY_verify_init(ctx) != 1) - goto err; - if (md != NULL) { - if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1) - goto err; + /* EVP_PKEY_CTX */ + { + if (!get_pkey_public_key(env, argv, 0, 4, &pkey, &ret)) + goto err; /* An exception is present in ret */ + + if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate new EVP_PKEY_CTX")); + + if (argv[0] != atom_eddsa) { + if (EVP_PKEY_verify_init(ctx) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign_init")); + if (md != NULL) { + if (EVP_PKEY_CTX_set_signature_md(ctx, md) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_signature_md")); + } } - } - if (argv[0] == atom_rsa) { - if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) != 1) - goto err; - if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) { - if (sig_opt.rsa_mgf1_md != NULL) { -# ifdef HAVE_RSA_MGF1_MD - if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) != 1) - goto err; -# else - goto notsup; -# endif - } - if (sig_opt.rsa_pss_saltlen > -2) { - if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) != 1) - goto err; + if (argv[0] == atom_rsa) { + if (EVP_PKEY_CTX_set_rsa_padding(ctx, sig_opt.rsa_padding) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_rsa_padding")); +# ifdef HAVE_RSA_PKCS1_PSS_PADDING + if (sig_opt.rsa_padding == RSA_PKCS1_PSS_PADDING) { + if (sig_opt.rsa_mgf1_md != NULL) { +# ifdef HAVE_RSA_MGF1_MD + if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, sig_opt.rsa_mgf1_md) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_rsa_mgf1_md")); +# else + assign_goto(ret, err, EXCP_NOTSUP_N(env, 5, "rsa_mgf1_md unavailable with this cryptolib")); +# endif + } + if (sig_opt.rsa_pss_saltlen > -2) { + if (EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sig_opt.rsa_pss_saltlen) != 1) + assign_goto(ret, err, EXCP_BADARG_N(env, 5, "Bad rsa_pss_saltlen")); + } } +# endif } - } - if (argv[0] == atom_eddsa) { -#ifdef HAVE_EDDSA - if (!FIPS_MODE()) { - if ((mdctx = EVP_MD_CTX_new()) == NULL) - goto err; + if (argv[0] == atom_eddsa) { +# ifdef HAVE_EDDSA + EVP_MD_CTX *mdctx = NULL; + if (!FIPS_MODE()) { + if ((mdctx = EVP_MD_CTX_new()) == NULL) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new")); - if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) - goto err; + if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestVerifyInit")); - result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen); - } - else -#endif - goto notsup; - } else { - if (md != NULL) { - ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md)); + result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen); + if (mdctx) + EVP_MD_CTX_free(mdctx); + } + else +# endif /* HAVE_EDDSA */ + assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "eddsa not supported")); + } else { + /* RSA or DSS */ + if (md != NULL) { + ERL_VALGRIND_ASSERT_MEM_DEFINED(tbs, EVP_MD_size(md)); + } + result = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen); } - result = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen); - } -#else -/*printf("Old interface\r\n"); -*/ - if (tbslen > INT_MAX) - goto bad_arg; - if (sig_bin.size > INT_MAX) - goto bad_arg; - if (argv[0] == atom_rsa) { - if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) - goto err; - result = RSA_verify(md->type, tbs, (unsigned int)tbslen, sig_bin.data, (unsigned int)sig_bin.size, rsa); - } else if (argv[0] == atom_dss) { - if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL) - goto err; - result = DSA_verify(0, tbs, (int)tbslen, sig_bin.data, (int)sig_bin.size, dsa); - } else if (argv[0] == atom_ecdsa) { -#if defined(HAVE_EC) - if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) - goto err; - result = ECDSA_verify(EVP_MD_type(md), tbs, (int)tbslen, sig_bin.data, (int)sig_bin.size, ec); -#else - goto notsup; -#endif - } else { - goto bad_arg; - } -#endif - ret = (result == 1 ? atom_true : atom_false); - goto done; + ret = (result == 1 ? atom_true : atom_false); - bad_arg: - err: - ret = enif_make_badarg(env); - goto done; + err: + if (ctx) + EVP_PKEY_CTX_free(ctx); + if (pkey) + EVP_PKEY_free(pkey); - notsup: - ret = atom_notsup; + return ret; + } + /* End of HAS_EVP_PKEY_CTX */ +#else + /* Old interface - before EVP_PKEY_CTX */ + { + if (!get_pkey_public_key(env, argv, 0, 4, &pkey, &ret)) + goto err; /* An exception is present in ret */ + + if (argv[0] == atom_rsa) { + if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) + assign_goto(ret, err, EXCP_BADARG_N(env, 4, "Not an RSA public key")); + result = RSA_verify(md->type, tbs, (unsigned int)tbslen, sig_bin.data, (unsigned int)sig_bin.size, rsa); + } else if (argv[0] == atom_dss) { + if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL) + assign_goto(ret, err, EXCP_BADARG_N(env, 4, "Not an DSA public key")); + result = DSA_verify(0, tbs, (int)tbslen, sig_bin.data, (int)sig_bin.size, dsa); + } else if (argv[0] == atom_ecdsa) { +# if defined(HAVE_EC) + if ((ec = EVP_PKEY_get1_EC_KEY(pkey)) == NULL) + assign_goto(ret, err, EXCP_BADARG_N(env, 4, "Not an ECDSA private key")); + result = ECDSA_verify(EVP_MD_type(md), tbs, (int)tbslen, sig_bin.data, (int)sig_bin.size, ec); +# else + assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "ecdsa not supported")); +# endif /* HAVE_EC */ + } else { + assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Unknown algorithm")); + } + ret = (result == 1 ? atom_true : atom_false); + + err: + if (rsa) + RSA_free(rsa); +# ifdef HAVE_DSA + if (dsa) + DSA_free(dsa); +# endif +# ifdef HAVE_EC + if (ec) + EC_KEY_free(ec); +# endif + if (pkey) + EVP_PKEY_free(pkey); - done: -#ifdef HAS_EVP_PKEY_CTX - if (ctx) - EVP_PKEY_CTX_free(ctx); -#endif -#ifdef HAVE_EDDSA - if (mdctx) - EVP_MD_CTX_free(mdctx); -#endif - if (pkey) - EVP_PKEY_free(pkey); - if (rsa) - RSA_free(rsa); -#ifdef HAVE_DSA - if (dsa) - DSA_free(dsa); -#endif -#ifdef HAVE_EC - if (ec) - EC_KEY_free(ec); -#endif + return ret; + } +#endif /* Pre EVP_PKEY_CTX */ - return ret; } -static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM options, - PKeyCryptOptions *opt) + +static int get_pkey_crypt_options(ErlNifEnv *env, + const ERL_NIF_TERM argv[], + int algorithm_arg_num, int options_arg_num, + PKeyCryptOptions *opt, + ERL_NIF_TERM *err_return) { ERL_NIF_TERM head, tail; const ERL_NIF_TERM *tpl_terms; int tpl_arity; const EVP_MD *opt_md; - if (!enif_is_list(env, options)) - goto bad_arg; + if (!enif_is_list(env, argv[options_arg_num])) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Expected a list")); /* defaults */ - if (algorithm == atom_rsa) { + if (argv[algorithm_arg_num] == atom_rsa) { opt->rsa_mgf1_md = NULL; opt->rsa_oaep_label.data = NULL; opt->rsa_oaep_label.size = 0; @@ -859,18 +911,17 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI opt->signature_md = NULL; } - if (enif_is_empty_list(env, options)) - return PKEY_OK; + if (enif_is_empty_list(env, argv[options_arg_num])) + return 1; /* There are no options to fetch. Return OK */ - if (algorithm != atom_rsa) - goto bad_arg; + if (argv[algorithm_arg_num] != atom_rsa) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only RSA supports Options")); - tail = options; + tail = argv[options_arg_num]; while (enif_get_list_cell(env, tail, &head, &tail)) { - if (!enif_get_tuple(env, head, &tpl_arity, &tpl_terms)) - goto bad_arg; - if (tpl_arity != 2) - goto bad_arg; + if (!enif_get_tuple(env, head, &tpl_arity, &tpl_terms) || + (tpl_arity != 2)) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Expect only two-tuples in the list")); if (tpl_terms[0] == atom_rsa_padding || tpl_terms[0] == atom_rsa_pad /* Compatibility */ @@ -894,59 +945,62 @@ static int get_pkey_crypt_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NI } else if (tpl_terms[1] == atom_rsa_no_padding) { opt->rsa_padding = RSA_NO_PADDING; - } else { - goto bad_arg; - } + } else + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Bad padding type in option rsa_padding")); + + } else if (tpl_terms[0] == atom_signature_md) { + if (!enif_is_atom(env, tpl_terms[1])) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Atom expected as argument to option signature_md")); + + if (!get_pkey_digest_type(env, argv[algorithm_arg_num], + options_arg_num, tpl_terms[1], + &opt_md, err_return)) + goto err; /* An exception is present in ret */ - } else if (tpl_terms[0] == atom_signature_md && enif_is_atom(env, tpl_terms[1])) { - int i; - i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (i != PKEY_OK) { - return i; - } opt->signature_md = opt_md; - } else if (tpl_terms[0] == atom_rsa_mgf1_md && enif_is_atom(env, tpl_terms[1])) { - int i; + } else if (tpl_terms[0] == atom_rsa_mgf1_md) { + if (!enif_is_atom(env, tpl_terms[1])) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Atom expected as argument to option rsa_mgf1_md")); #ifndef HAVE_RSA_MGF1_MD if (tpl_terms[1] != atom_sha) - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only 'sha' is supported in option rsa_mgf1_md")); #endif - i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (i != PKEY_OK) { - return i; - } + if (!get_pkey_digest_type(env, argv[algorithm_arg_num], + options_arg_num, tpl_terms[1], + &opt_md, err_return)) + goto err; /* An exception is present in ret */ opt->rsa_mgf1_md = opt_md; - } else if (tpl_terms[0] == atom_rsa_oaep_label - && enif_inspect_binary(env, tpl_terms[1], &(opt->rsa_oaep_label))) { + } else if (tpl_terms[0] == atom_rsa_oaep_label) { #ifdef HAVE_RSA_OAEP_MD + if (!enif_inspect_binary(env, tpl_terms[1], &(opt->rsa_oaep_label))) + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Binary expected for option rsa_oaep_label")); continue; #else - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, options_arg_num, "Option rsa_oaep_label is not supported")); #endif - } else if (tpl_terms[0] == atom_rsa_oaep_md && enif_is_atom(env, tpl_terms[1])) { - int i; + } else if (tpl_terms[0] == atom_rsa_oaep_md) { + if (!enif_is_atom(env, tpl_terms[1])) + assign_goto(*err_return, err, EXCP_NOTSUP_N(env, options_arg_num, "Atom expected as argument to option rsa_oaep_md")); #ifndef HAVE_RSA_OAEP_MD if (tpl_terms[1] != atom_sha) - return PKEY_NOTSUP; + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only 'sha' is supported in option rsa_oaep_md")); #endif - i = get_pkey_digest_type(env, algorithm, tpl_terms[1], &opt_md); - if (i != PKEY_OK) { - return i; - } + if (!get_pkey_digest_type(env, argv[algorithm_arg_num], + options_arg_num, tpl_terms[1], + &opt_md, err_return)) + goto err; /* An exception is present in ret */ opt->rsa_oaep_md = opt_md; - - } else { - goto bad_arg; - } + } else + assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Unknown option")) } - return PKEY_OK; + return 1; - bad_arg: - return PKEY_BADARG; + err: + return 0; } #ifdef HAVE_RSA_SSLV23_PADDING @@ -968,8 +1022,7 @@ static size_t size_of_RSA(EVP_PKEY *pkey) { ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) {/* (Algorithm, Data, PublKey=[E,N]|[E,N,D]|[E,N,D,P1,P2,E1,E2,C], Options, IsPrivate, IsEncrypt) */ - ERL_NIF_TERM ret; - int i; + ERL_NIF_TERM ret = atom_undefined; int result = 0; int tmp_bin_alloc = 0; int out_bin_alloc = 0; @@ -987,74 +1040,61 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) size_t tmplen; #endif int is_private, is_encrypt; - int algo_init = 0; unsigned char *label_copy = NULL; - ASSERT(argc == 6); - is_private = (argv[4] == atom_true); is_encrypt = (argv[5] == atom_true); -/* char algo[1024]; */ + if (!check_pkey_algorithm_type(env, 0, argv[0], &ret)) + goto err; /* An exception is present in ret */ + + if (!enif_inspect_binary(env, argv[1], &in_bin)) + assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Binary expected")); #ifndef HAS_ENGINE_SUPPORT if (enif_is_map(env, argv[2])) - return atom_notsup; + assign_goto(ret, err, EXCP_BADARG_N(env, 2, "No engine support")); #endif - if (!enif_inspect_binary(env, argv[1], &in_bin)) - goto bad_arg; - - i = get_pkey_crypt_options(env, argv[0], argv[3], &crypt_opt); - switch (i) { - case PKEY_OK: - break; - case PKEY_NOTSUP: - goto notsup; - default: - goto bad_arg; - } - if (is_private) { - if (get_pkey_private_key(env, argv[0], argv[2], &pkey) != PKEY_OK) - goto bad_arg; + if (!get_pkey_private_key(env, argv, 0, 2, &pkey, &ret)) + goto err; /* An exception is present in ret */ } else { - if (get_pkey_public_key(env, argv[0], argv[2], &pkey) != PKEY_OK) - goto bad_arg; + if (!get_pkey_public_key(env, argv, 0, 2, &pkey, &ret)) + goto err; /* An exception is present in ret */ } + if (!get_pkey_crypt_options(env, argv, 0, 3, &crypt_opt, &ret)) + goto err; /* An exception is present in ret */ + #ifdef HAS_EVP_PKEY_CTX - if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) - goto err; + { + int algo_init = 0; -/* enif_get_atom(env,argv[0],algo,1024,ERL_NIF_LATIN1); */ + if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate new EVP_PKEY_CTX")); - if (is_private) { - if (is_encrypt) { - /* private encrypt */ - if ((algo_init = EVP_PKEY_sign_init(ctx)) != 1) - goto bad_arg; - } else { - /* private decrypt */ - if ((algo_init = EVP_PKEY_decrypt_init(ctx)) != 1) - goto bad_arg; - } - } else { - if (is_encrypt) { - /* public encrypt */ - if ((algo_init = EVP_PKEY_encrypt_init(ctx)) != 1) - goto bad_arg; - } else { - /* public decrypt */ - if ((algo_init = EVP_PKEY_verify_recover_init(ctx)) != 1) - goto bad_arg; - } + if (is_private) { + if (is_encrypt) + algo_init = EVP_PKEY_sign_init(ctx); + else + algo_init = EVP_PKEY_decrypt_init(ctx); + + } else { + if (is_encrypt) + algo_init = EVP_PKEY_encrypt_init(ctx); + else + algo_init = EVP_PKEY_verify_recover_init(ctx); + } + + if (algo_init != 1) + assign_goto(ret, err, EXCP_NOTSUP(env, "Can't initiate encrypt/decrypt")); } if (argv[0] == atom_rsa) { if (crypt_opt.signature_md != NULL) { if (EVP_PKEY_CTX_set_signature_md(ctx, crypt_opt.signature_md) != 1) - goto bad_arg; + assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_CTX_set_signature_md")); } # ifdef HAVE_RSA_SSLV23_PADDING @@ -1062,40 +1102,38 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) if (is_encrypt) { tmplen = size_of_RSA(pkey); if (tmplen < 1 || tmplen > INT_MAX) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 2, "RSA key of wrong size")); if (!enif_alloc_binary(tmplen, &tmp_bin)) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); tmp_bin_alloc = 1; if (in_bin.size > INT_MAX) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Binary too large")); if (!RSA_padding_add_SSLv23(tmp_bin.data, (int)tmplen, in_bin.data, (int)in_bin.size)) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't RSA_padding_add_SSLv23")); in_bin = tmp_bin; } if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) != 1) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't set RSA_NO_PADDING")); } else # endif - { if (EVP_PKEY_CTX_set_rsa_padding(ctx, crypt_opt.rsa_padding) != 1) - goto err; - } + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't set rsa padding")); # ifdef HAVE_RSA_OAEP_MD if (crypt_opt.rsa_padding == RSA_PKCS1_OAEP_PADDING) { if (crypt_opt.rsa_oaep_md != NULL) { if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, crypt_opt.rsa_oaep_md) != 1) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't EVP_PKEY_CTX_set_rsa_oaep_md")); } if (crypt_opt.rsa_mgf1_md != NULL) { if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, crypt_opt.rsa_mgf1_md) != 1) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't EVP_PKEY_CTX_set_rsa_mgf1_md")); } if (crypt_opt.rsa_oaep_label.data != NULL && crypt_opt.rsa_oaep_label.size > 0) { if (crypt_opt.rsa_oaep_label.size > INT_MAX) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "RSA oep label too large")); if ((label_copy = OPENSSL_malloc(crypt_opt.rsa_oaep_label.size)) == NULL) goto err; @@ -1104,7 +1142,7 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label_copy, (int)crypt_opt.rsa_oaep_label.size) != 1) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't set RSA oaep label")); /* On success, label_copy is owned by ctx */ label_copy = NULL; } @@ -1112,105 +1150,77 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) # endif } - if (is_private) { - if (is_encrypt) { - /* private_encrypt */ - result = EVP_PKEY_sign(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } else { - /* private_decrypt */ - result = EVP_PKEY_decrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } - } else { - if (is_encrypt) { - /* public_encrypt */ - result = EVP_PKEY_encrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } else { - /* public_decrypt */ - result = EVP_PKEY_verify_recover(ctx, NULL, &outlen, in_bin.data, in_bin.size); - } - } - + /* Get the size of the result */ + if (is_private) + result = + is_encrypt ? EVP_PKEY_sign(ctx, NULL, &outlen, in_bin.data, in_bin.size) + : EVP_PKEY_decrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size); + else + result = + is_encrypt ? EVP_PKEY_encrypt(ctx, NULL, &outlen, in_bin.data, in_bin.size) + : EVP_PKEY_verify_recover(ctx, NULL, &outlen, in_bin.data, in_bin.size); + + /* Check */ if (result != 1) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't get size of result")); + /* Allocate */ if (!enif_alloc_binary(outlen, &out_bin)) - goto err; - out_bin_alloc = 1; + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); - if (is_private) { - if (is_encrypt) { - /* private_encrypt */ - result = EVP_PKEY_sign(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } else { - /* private_decrypt */ - result = EVP_PKEY_decrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } - } else { - if (is_encrypt) { - /* public_encrypt */ - result = EVP_PKEY_encrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } else { - /* public_decrypt */ - result = EVP_PKEY_verify_recover(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); - } - } + out_bin_alloc = 1; /* Flag de-allocation */ + + /* Get the result into the newly allocated binary */ + if (is_private) + result = + is_encrypt ? EVP_PKEY_sign(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size) + : EVP_PKEY_decrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); + else + result= + is_encrypt ? EVP_PKEY_encrypt(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size) + : EVP_PKEY_verify_recover(ctx, out_bin.data, &outlen, in_bin.data, in_bin.size); + + if (result != 1) + assign_goto(ret, err, EXCP_ERROR(env, "Couldn't get the result")); #else - /* Non-EVP cryptolib. Only support RSA */ + /* Non-EVP cryptolib. Only supports RSA */ - if (argv[0] != atom_rsa) { - algo_init = -2; /* exitcode: notsup */ - goto bad_arg; - } + if (argv[0] != atom_rsa) + assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "Only RSA is supported")); if ((rsa = EVP_PKEY_get1_RSA(pkey)) == NULL) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 2, "Not RSA key")); if ((len = RSA_size(rsa)) < 0) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Bad RSA key length")); if (!enif_alloc_binary((size_t)len, &out_bin)) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); out_bin_alloc = 1; if (in_bin.size > INT_MAX) - goto err; - if (is_private) { - if (is_encrypt) { - /* non-evp rsa private encrypt */ - ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size); - result = RSA_private_encrypt((int)in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (result > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result); - } - } else { - /* non-evp rsa private decrypt */ - result = RSA_private_decrypt((int)in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (result > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result); - if (!enif_realloc_binary(&out_bin, (size_t)result)) - goto err; - } - } - } else { - if (is_encrypt) { - /* non-evp rsa public encrypt */ - ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size); - result = RSA_public_encrypt((int)in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (result > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result); - } - } else { - /* non-evp rsa public decrypt */ - result = RSA_public_decrypt((int)in_bin.size, in_bin.data, - out_bin.data, rsa, crypt_opt.rsa_padding); - if (result > 0) { - ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result); - if (!enif_realloc_binary(&out_bin, (size_t)result)) - goto err; - } - } + assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Bad indata length")); + + if (is_encrypt) { + ERL_VALGRIND_ASSERT_MEM_DEFINED(in_bin.data,in_bin.size); + } + + if (is_private) + result = + is_encrypt ? RSA_private_encrypt((int)in_bin.size, in_bin.data, + out_bin.data, rsa, crypt_opt.rsa_padding) + : RSA_private_decrypt((int)in_bin.size, in_bin.data, + out_bin.data, rsa, crypt_opt.rsa_padding); + else + result = + is_encrypt ? RSA_public_encrypt((int)in_bin.size, in_bin.data, + out_bin.data, rsa, crypt_opt.rsa_padding) + : RSA_public_decrypt((int)in_bin.size, in_bin.data, + out_bin.data, rsa, crypt_opt.rsa_padding); + if (result > 0) { + ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, result); + if (!is_encrypt && + !enif_realloc_binary(&out_bin, (size_t)result)) + assign_goto(ret, err, EXCP_ERROR(env, "Can't re-allocate binary")); } outlen = (size_t)result; @@ -1223,12 +1233,12 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) tmplen = size_of_RSA(pkey); if (tmplen < 1 || tmplen > INT_MAX) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 2, "RSA key of wrong size")); if (!enif_alloc_binary(tmplen, &tmp_bin)) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary")); tmp_bin_alloc = 1; if (out_bin.size > INT_MAX) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Result too large")); p = out_bin.data; p++; @@ -1249,28 +1259,16 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) ERL_VALGRIND_MAKE_MEM_DEFINED(out_bin.data, outlen); if (outlen != out_bin.size) { if (!enif_realloc_binary(&out_bin, outlen)) - goto err; + assign_goto(ret, err, EXCP_ERROR(env, "Can't re-allocate binary")); ERL_VALGRIND_ASSERT_MEM_DEFINED(out_bin.data, outlen); } ret = enif_make_binary(env, &out_bin); out_bin_alloc = 0; } else { - ret = atom_error; + assign_goto(ret, err, EXCP_ERROR(env, "RSA encrypt/decrypt failed")); } - goto done; - - notsup: - ret = atom_notsup; - goto done; - bad_arg: err: - if (algo_init == -2) - ret = atom_notsup; - else - ret = enif_make_badarg(env); - - done: if (out_bin_alloc) enif_release_binary(&out_bin); if (tmp_bin_alloc) @@ -1290,7 +1288,7 @@ ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]) OPENSSL_free(label_copy); return ret; -} + } ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { /* (Algorithm, PrivKey | KeyMap) */ @@ -1299,17 +1297,20 @@ ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM ASSERT(argc == 2); - if (get_pkey_private_key(env, argv[0], argv[1], &pkey) != PKEY_OK) // handles engine - goto bad_arg; + if (!check_pkey_algorithm_type(env, 0, argv[0], &ret)) + goto err; /* An exception is present in ret */ + + if (!get_pkey_private_key(env, argv, 0, 1, &pkey, &ret)) // handles engine + goto err; /* An exception is present in ret */ if (argv[0] == atom_rsa) { if (!rsa_privkey_to_pubkey(env, pkey, &ret)) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Couldn't get RSA public key from private key")); #ifdef HAVE_DSA } else if (argv[0] == atom_dss) { if (!dss_privkey_to_pubkey(env, pkey, &ret)) - goto err; + assign_goto(ret, err, EXCP_BADARG_N(env, 1, "Couldn't get DSA public key from private key")); #endif } else if (argv[0] == atom_ecdsa) { #if defined(HAVE_EC) @@ -1346,18 +1347,12 @@ ERL_NIF_TERM privkey_to_pubkey_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM return enif_make_list_from_array(env, ..., ...); */ #endif - goto bad_arg; + assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "ECDSA not implemented")); } else { - goto bad_arg; + ret = EXCP_BADARG_N(env, 0, "Bad algorithm"); } - goto done; - - bad_arg: err: - ret = enif_make_badarg(env); - - done: if (pkey) EVP_PKEY_free(pkey); |