File 8656-crypto-pkey.c-error-ERR-error-ERR-FileInfo-Descripti.patch of Package erlang

From b70d8ad394b85e453a263b4c0d4f267fd75629b3 Mon Sep 17 00:00:00 2001
From: Hans Nilsson <hans@erlang.org>
Date: Fri, 11 Mar 2022 17:56:52 +0100
Subject: [PATCH 6/8] crypto: pkey.c error:ERR ->
 error:{ERR,FileInfo,Description}

---
 lib/crypto/c_src/pkey.c          | 939 +++++++++++++++----------------
 lib/crypto/doc/src/crypto.xml    |   6 +
 lib/crypto/src/crypto.erl        |  31 +-
 lib/crypto/test/crypto_SUITE.erl |  19 +-
 lib/crypto/test/engine_SUITE.erl |   2 +-
 5 files changed, 470 insertions(+), 527 deletions(-)

diff --git a/lib/crypto/c_src/pkey.c b/lib/crypto/c_src/pkey.c
index 0423fbd470..59632d86d3 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,7 +42,11 @@ typedef struct PKeySignOptions {
 } PKeySignOptions;
 
 
-static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM type,
+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,
@@ -60,9 +60,16 @@ static int get_pkey_sign_options(ErlNifEnv *env,
                                  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, 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_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,
@@ -72,7 +79,47 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
 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,
+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)
 {
@@ -80,23 +127,25 @@ static int get_pkey_digest_type(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_
     *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 (type == atom_undefined && algorithm == atom_eddsa)
+        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,
@@ -106,7 +155,7 @@ static int get_pkey_sign_digest(ErlNifEnv *env,
 				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;
@@ -120,21 +169,26 @@ static int get_pkey_sign_digest(ErlNifEnv *env,
     tbs = *tbsp;
     tbslen = *tbslenp;
 
-    if ((i = get_pkey_digest_type(env, argv[algorithm_arg_num], argv[type_arg_num], &md, err_return)) != 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, 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 */
@@ -142,28 +196,28 @@ static int get_pkey_sign_digest(ErlNifEnv *env,
 	tbslen = tbs_bin.size;
     } else if (md == NULL) {
         if (!enif_inspect_iolist_as_binary(env, argv[data_arg_num], &tbs_bin))
-            goto bad_arg;
+            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, argv[data_arg_num], &tbs_bin))
-            goto bad_arg;
+            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;
     }
@@ -172,13 +226,11 @@ static int get_pkey_sign_digest(ErlNifEnv *env,
     *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);
@@ -197,7 +249,7 @@ static int get_pkey_sign_options(ErlNifEnv *env,
     const EVP_MD *opt_md;
 
     if (!enif_is_list(env, argv[options_arg_num]))
-        goto bad_arg;
+        assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Expected a list"));
 
     /* defaults */
     if (argv[algorithm_arg_num] == atom_rsa) {
@@ -211,25 +263,26 @@ static int get_pkey_sign_options(ErlNifEnv *env,
     }
 
     if (enif_is_empty_list(env, argv[options_arg_num]))
-	return PKEY_OK;
+	return 1;
 
     if (argv[algorithm_arg_num] != atom_rsa)
-        goto bad_arg;
+        assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only RSA supports 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, argv[algorithm_arg_num], tpl_terms[1], &opt_md, err_return);
-            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) {
@@ -242,7 +295,7 @@ static int get_pkey_sign_options(ErlNifEnv *env,
                 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) {
@@ -252,157 +305,163 @@ static int get_pkey_sign_options(ErlNifEnv *env,
                 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)
 {
     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;
+        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, key);
+        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 (!get_rsa_private_key(env, key, pkey))
-            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 (!get_ec_private_key(env, key, pkey))
-            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, pkey))
-            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 (!get_dss_private_key(env, key, pkey))
-            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 (*pkey == NULL) {
-        return PKEY_BADARG;
-    } else {
-        *pkey = *pkey;
-        return PKEY_OK;
-    }
+    return ret;
 
  err:
     if (*pkey)
         EVP_PKEY_free(*pkey);
     *pkey = NULL;
-    goto free_and_return;
+    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)
 {
     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;
+        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, key);
+        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 (!get_rsa_public_key(env, key, pkey))
-            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 (!get_ec_public_key(env, key, pkey))
-            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, pkey))
-                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 (!get_dss_public_key(env, key, pkey))
-            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 (*pkey)
-        EVP_PKEY_free(*pkey);
-    *pkey = NULL;
+    ret = 1;
 
  done:
     if (password)
@@ -410,16 +469,18 @@ static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_T
     if (id)
         enif_free(id);
 
-    if (*pkey == NULL)
-        return PKEY_BADARG;
-    else
-        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 = atom_undefined;
     const EVP_MD *md = NULL;
@@ -446,61 +507,47 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 
 #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
-    i = get_pkey_sign_digest(env, argv, 0, 1, 2, md_value, &md, &tbs, &tbslen, &ret);
-    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, 4, md, &sig_opt, &ret);
-    switch (i) {
-    case PKEY_OK:
-        break;
-    case PKEY_NOTSUP:
-        goto notsup;
-    default:
-        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
     { /* EVP_MD_CTX */
-        if (get_pkey_private_key(env, argv[0], argv[3], &pkey) != PKEY_OK)
-            goto bad_arg;
+        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)
-            goto err;
+            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)
-                goto err;
+                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)
-                    goto err;
+                    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;
+                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)
-                        goto err;
+                        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)
-                        goto err;
+                        assign_goto(ret, err, EXCP_BADARG_N(env, 4, "Bad rsa_pss_saltlen"));
                 }
             }
 # endif
@@ -511,65 +558,58 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
             if (!FIPS_MODE()) {
                 EVP_MD_CTX *mdctx = NULL;
                 if ((mdctx = EVP_MD_CTX_new()) == NULL)
-                    goto err;
+                    assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new"));
 
                 if (EVP_DigestSignInit(mdctx, NULL, NULL, NULL, pkey) != 1)
-                    goto err;
+                    assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSignInit"));
                 if (EVP_DigestSign(mdctx, NULL, &siglen, tbs, tbslen) != 1)
-                    goto err;
+                    assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign"));
                 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) {
                     if (mdctx)
                         EVP_MD_CTX_free(mdctx);
-                    goto bad_key;
+                    assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestSign"));
                 }
                 if (mdctx)
                     EVP_MD_CTX_free(mdctx);
             }
             else
 # endif
-                goto notsup;
+                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)
-                goto err;
+                assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign"));
+
             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 (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;
+                assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_PKEY_sign"));
         }
 
     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:
     if (sig_bin_alloc)
         enif_release_binary(&sig_bin);
     if (ctx)
@@ -582,85 +622,73 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 #else
     /* Old interface - before EVP_PKEY_CTX */
     {
-        if (get_pkey_private_key(env, argv[0], argv[3], &pkey) != PKEY_OK)
-            goto bad_arg;
+        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)
-                goto err;
+                assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Not an RSA private key"));
             if ((len = RSA_size(rsa)) < 0)
-                goto err;
+                assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Bad RSA private key length"));
             if (!enif_alloc_binary((size_t)len, &sig_bin))
-                goto err;
+                assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary"));
             sig_bin_alloc = 1;
 
             if ((len = EVP_MD_size(md)) < 0)
-                goto err;
+                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)
-                goto bad_key;
+                assign_goto(ret, err, EXCP_ERROR(env, "Can't sign"));
+                            
         } else if (argv[0] == atom_dss) {
             if ((dsa = EVP_PKEY_get1_DSA(pkey)) == NULL)
-                goto err;
+                assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Not an DSA private key"));
             if ((len = DSA_size(dsa)) < 0)
-                goto err;
+                assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Bad DSA private key length"));
             if (!enif_alloc_binary((size_t)len, &sig_bin))
-                goto err;
+                assign_goto(ret, err, EXCP_ERROR(env, "Can't allocate binary"));
             sig_bin_alloc = 1;
 
             if ((len = EVP_MD_size(md)) < 0)
-                goto err;
+                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)
-                goto bad_key;
+                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)
-                goto err;
+                assign_goto(ret, err, EXCP_BADARG_N(env, 3, "Not an ECDSA private key"));
             if ((len = ECDSA_size(ec)) < 0)
-                goto err;
+                assign_goto(ret, err, EXCP_ERROR(env, "Can't get size"));
             if (!enif_alloc_binary((size_t)len, &sig_bin))
-                goto err;
+                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)
-                goto bad_key;
+                assign_goto(ret, err, EXCP_ERROR(env, "Can't sign"));
 # else
-            goto notsup;
+            assign_goto(ret, notsup, EXCP_NOTSUP_N(env, 0, "ecdsa not supported"));
 # endif /* HAVE_EC */
         } else {
-            goto bad_arg;
+            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))
-                goto err;
+                 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;
-        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:
         if (sig_bin_alloc)
             enif_release_binary(&sig_bin);
         if (rsa)
@@ -690,7 +718,6 @@ ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
 
 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];
@@ -715,68 +742,56 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
 
 
 #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, 1, 2, md_value, &md, &tbs, &tbslen, &ret);
-    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, 5, md, &sig_opt, &ret);
-    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 (!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
     /* EVP_PKEY_CTX */
     {
-        if (get_pkey_public_key(env, argv[0], argv[4], &pkey) != PKEY_OK)
-            goto bad_arg;
+        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)
-            goto err;
+            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)
-                goto err;
+                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)
-                    goto err;
+                    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;
+                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
+#  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
+                        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)
-                        goto err;
+                        assign_goto(ret, err, EXCP_BADARG_N(env, 5, "Bad rsa_pss_saltlen"));
                 }
             }
+# endif
         }
 
         if (argv[0] == atom_eddsa) {
@@ -784,10 +799,10 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
             EVP_MD_CTX *mdctx = NULL;
             if (!FIPS_MODE()) {
                 if ((mdctx = EVP_MD_CTX_new()) == NULL)
-                    goto err;
+                     assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_MD_CTX_new"));
 
                 if (EVP_DigestVerifyInit(mdctx, NULL, NULL, NULL, pkey) != 1)
-                    goto err;
+                    assign_goto(ret, err, EXCP_ERROR(env, "Can't EVP_DigestVerifyInit"));
 
                 result = EVP_DigestVerify(mdctx, sig_bin.data, sig_bin.size, tbs, tbslen);
                 if (mdctx)
@@ -795,7 +810,7 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
             }
             else
 # endif /* HAVE_EDDSA */
-                goto notsup;
+                assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "eddsa not supported"));
         } else {
             /* RSA or DSS */
             if (md != NULL) {
@@ -803,18 +818,10 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
             }
             result = EVP_PKEY_verify(ctx, sig_bin.data, sig_bin.size, tbs, tbslen);
         }
+
         ret = (result == 1 ? atom_true : atom_false);
-        goto done;
 
-    bad_arg:
     err:
-        ret = enif_make_badarg(env);
-        goto done;
-
-    notsup:
-        ret = atom_notsup;
-
-    done:
         if (ctx)
             EVP_PKEY_CTX_free(ctx);
         if (pkey)
@@ -826,42 +833,31 @@ ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[]
 #else
     /* Old interface - before EVP_PKEY_CTX */
     {
-        if (get_pkey_public_key(env, argv[0], argv[4], &pkey) != PKEY_OK)
-            goto bad_arg;
+        if (!get_pkey_public_key(env, argv, 0, 4, &pkey, &ret))
+            goto err; /* An exception is present in ret */
 
-        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;
+                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)
-                goto err;
+                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)
-                goto err;
+                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
-            goto notsup;
+            assign_goto(ret, err, EXCP_NOTSUP_N(env, 0, "ecdsa not supported"));
 # endif /* HAVE_EC */
         } else {
-            goto bad_arg;
+            assign_goto(ret, err, EXCP_BADARG_N(env, 0, "Unknown algorithm"));
         }
         ret = (result == 1 ? atom_true : atom_false);
-        goto done;
 
-    bad_arg:
     err:
-        ret = enif_make_badarg(env);
-        goto done;
-    notsup:
-        ret = atom_notsup;
-    done:
         if (rsa)
             RSA_free(rsa);
 # ifdef HAVE_DSA
@@ -894,7 +890,7 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
     const EVP_MD *opt_md;
 
     if (!enif_is_list(env, argv[options_arg_num]))
-        goto bad_arg;
+        assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Expected a list"));
 
     /* defaults */
     if (argv[algorithm_arg_num] == atom_rsa) {
@@ -914,17 +910,16 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
     }
 
     if (enif_is_empty_list(env, argv[options_arg_num]))
-        return PKEY_OK;
+        return 1; /* There are no options to fetch. Return OK */
 
     if (argv[algorithm_arg_num] != atom_rsa)
-        goto bad_arg;
+        assign_goto(*err_return, err, EXCP_BADARG_N(env, options_arg_num, "Only RSA supports 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 */
@@ -948,59 +943,62 @@ static int get_pkey_crypt_options(ErlNifEnv *env,
             } 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, argv[algorithm_arg_num], tpl_terms[1], &opt_md, err_return);
-            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, argv[algorithm_arg_num], tpl_terms[1], &opt_md, err_return);
-            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, argv[algorithm_arg_num], tpl_terms[1], &opt_md, err_return);
-            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
@@ -1023,7 +1021,6 @@ 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 = atom_undefined;
-    int i;
     int result = 0;
     int tmp_bin_alloc = 0;
     int out_bin_alloc = 0;
@@ -1041,74 +1038,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, 3, &crypt_opt, &ret);
-    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
@@ -1116,40 +1100,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;
 
@@ -1158,7 +1140,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;
             }
@@ -1166,105 +1148,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;
@@ -1277,12 +1231,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++;
@@ -1303,28 +1257,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)
@@ -1344,7 +1286,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) */
@@ -1353,17 +1295,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)
@@ -1400,18 +1345,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);
 
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 9ee2653c0c..d1876d6063 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -1253,6 +1253,7 @@ end
       <name name="private_decrypt" arity="4" since="OTP R16B01"/>
       <fsummary>Decrypts CipherText using the private Key.</fsummary>
       <desc>
+	<p>Uses the <seeerl marker="#error_3tup">3-tuple style</seeerl> for error handling.</p>
 	<p>Decrypts the <c>CipherText</c>, encrypted with
 	<seemfa marker="#public_encrypt/4">public_encrypt/4</seemfa> (or equivalent function)
 	  using the <c>PrivateKey</c>, and returns the
@@ -1267,6 +1268,7 @@ end
       <name name="private_encrypt" arity="4" since="OTP R16B01"/>
       <fsummary>Encrypts PlainText using the private Key.</fsummary>
       <desc>
+	<p>Uses the <seeerl marker="#error_3tup">3-tuple style</seeerl> for error handling.</p>
 	<p>Encrypts the <c>PlainText</c> using the <c>PrivateKey</c>
 	and returns the ciphertext. This is a low level signature operation
 	used for instance by older versions of the SSL protocol. See
@@ -1280,6 +1282,7 @@ end
       <name name="public_decrypt" arity="4" since="OTP R16B01"/>
       <fsummary>Decrypts CipherText using the public Key.</fsummary>
       <desc>
+	<p>Uses the <seeerl marker="#error_3tup">3-tuple style</seeerl> for error handling.</p>
 	<p>Decrypts the <c>CipherText</c>, encrypted with
 	<seemfa marker="#private_encrypt/4">private_encrypt/4</seemfa>(or equivalent function)
 	  using the <c>PrivateKey</c>, and returns the
@@ -1294,6 +1297,7 @@ end
       <name name="public_encrypt" arity="4" since="OTP R16B01"/>
       <fsummary>Encrypts PlainText using the public Key.</fsummary>
       <desc>
+	<p>Uses the <seeerl marker="#error_3tup">3-tuple style</seeerl> for error handling.</p>
 	<p>Encrypts the <c>PlainText</c> (message digest) using the <c>PublicKey</c>
 	and returns the <c>CipherText</c>. This is a low level signature operation
 	used for instance by older versions of the SSL protocol. See also <seemfa
@@ -1630,6 +1634,7 @@ FloatValue = rand:uniform().     % again
       <name name="sign" arity="5" since="OTP 20.1"/>
       <fsummary> Create digital signature.</fsummary>
       <desc>
+	<p>Uses the <seeerl marker="#error_3tup">3-tuple style</seeerl> for error handling.</p>
 	<p>Creates a digital signature.</p>
 	<p>The msg is either the binary "cleartext" data to be
 	signed or it is the hashed value of "cleartext" i.e. the
@@ -1645,6 +1650,7 @@ FloatValue = rand:uniform().     % again
       <name name="verify" arity="6" since="OTP 20.1"/>
       <fsummary>Verifies a digital signature.</fsummary>
       <desc>
+	<p>Uses the <seeerl marker="#error_3tup">3-tuple style</seeerl> for error handling.</p>
 	<p>Verifies a digital signature</p>
 	<p>The msg is either the binary "cleartext" data to be
 	signed or it is the hashed value of "cleartext" i.e. the
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index bffaacb043..fdf2cdfbf9 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -1424,11 +1424,9 @@ sign(Algorithm, Type, Data, Key) ->
 
 sign(Algorithm0, Type0, Data, Key, Options) ->
     {Algorithm, Type} = sign_verify_compatibility(Algorithm0, Type0, Data),
-    case pkey_sign_nif(Algorithm, Type, Data, format_pkey(Algorithm, Key), Options) of
-	error -> erlang:error(badkey, [Algorithm, Type, Data, Key, Options]);
-	notsup -> erlang:error(notsup);
-	Signature -> Signature
-    end.
+    ?nif_call(pkey_sign_nif(Algorithm, Type, Data, format_pkey(Algorithm, Key), Options),
+              {1, 2, 3, 4, 5},
+              [Algorithm0, Type0, Data, Key, Options]).
 
 pkey_sign_nif(_Algorithm, _Type, _Digest, _Key, _Options) -> ?nif_stub.
 
@@ -1473,10 +1471,9 @@ verify(Algorithm, Type, Data, Signature, Key) ->
 
 verify(Algorithm0, Type0, Data, Signature, Key, Options) ->
     {Algorithm, Type} = sign_verify_compatibility(Algorithm0, Type0, Data),
-    case pkey_verify_nif(Algorithm, Type, Data, Signature, format_pkey(Algorithm, Key), Options) of
-	notsup -> erlang:error(notsup);
-	Boolean -> Boolean
-    end.
+    ?nif_call(pkey_verify_nif(Algorithm, Type, Data, Signature, format_pkey(Algorithm, Key), Options),
+              {1,2,3,4,5},
+              [Algorithm0, Type0, Data, Signature, Key, Options]).
 
 pkey_verify_nif(_Algorithm, _Type, _Data, _Signature, _Key, _Options) -> ?nif_stub.
 
@@ -1562,12 +1559,7 @@ pkey_crypt(rsa, Text, Key, Padding, PubPriv, EncDec) when is_atom(Padding) ->
     pkey_crypt(rsa, Text, Key, [{rsa_padding, Padding}], PubPriv, EncDec);
 
 pkey_crypt(Alg, Text, Key, Options, PubPriv, EncDec) ->
-    case pkey_crypt_nif(Alg, Text, format_pkey(Alg,Key), Options, PubPriv, EncDec) of
-	error when EncDec==true  -> erlang:error(encrypt_failed, [Alg, Text, Key, Options]);
-	error when EncDec==false -> erlang:error(decrypt_failed, [Alg, Text, Key, Options]);
-	notsup -> erlang:error(notsup);
-	Out -> Out
-    end.
+    ?nif_call(pkey_crypt_nif(Alg, Text, format_pkey(Alg,Key), Options, PubPriv, EncDec)).
 
 pkey_crypt_nif(_Algorithm, _In, _Key, _Options, _IsPrivate, _IsEncrypt) -> ?nif_stub.
 
@@ -2305,16 +2297,15 @@ ec_curve(X) ->
                                                                      EnginePrivateKeyRef :: engine_key_ref(),
                                                                      PublicKey ::  rsa_public() | dss_public() .
 privkey_to_pubkey(Alg, EngineMap) when Alg == rsa; Alg == dss; Alg == ecdsa ->
-    try privkey_to_pubkey_nif(Alg, format_pkey(Alg,EngineMap))
-    of
+    try ?nif_call(privkey_to_pubkey_nif(Alg, format_pkey(Alg,EngineMap))) of
         [_|_]=L -> map_ensure_bin_as_int(L);
         X -> X
     catch
-        error:badarg when Alg==ecdsa ->
+        error:{badarg,_,_} when Alg==ecdsa ->
             {error, notsup};
-        error:badarg ->
+        error:{badarg,_,_} ->
             {error, not_found};
-        error:notsup ->
+        error:{notsup,_,_} ->
             {error, notsup}
     end.
 
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 0329ed992a..15ab9e735a 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -1584,6 +1584,13 @@ do_sign_verify({Type, Hash, Public, Private, Msg, Options}) ->
             ct:log("notsup but OK in old cryptolib crypto:sign(~p, ~p, ..., ..., ..., ~p)",
                    [Type,Hash,Options]),
             true;
+        error:{notsup,_,_} when NotSupLow == true,
+                          is_integer(LibVer),
+                          LibVer < 16#10001000 ->
+            %% Those opts where introduced in 1.0.1
+            ct:log("notsup but OK in old cryptolib crypto:sign(~p, ~p, ..., ..., ..., ~p)",
+                   [Type,Hash,Options]),
+            true;
         C:E ->
             ct:log("~p:~p  crypto:sign(~p, ~p, ..., ..., ..., ~p)", [C,E,Type,Hash,Options]),
             ct:fail({{crypto, sign_verify, [LibVer, Type, Hash, Msg, Public, Options]}})
@@ -4353,15 +4360,15 @@ bad_mac_name(_Config) ->
 
 bad_sign_name(_Config) ->
     ?chk_api_name(crypto:sign(rsa, foobar, "nothing", <<1:1024>>),
-                  error:badarg),
+                  error:{badarg, {"pkey.c",_}, "Bad digest type"}),
     ?chk_api_name(crypto:sign(foobar, sha, "nothing", <<1:1024>>),
-                  error:badarg).
+                  error:{badarg, {"pkey.c",_}, "Bad algorithm"}).
     
 bad_verify_name(_Config) ->
-    ?chk_api_name(crypto:verify(rsa, foobar, "nothing","nothing",  <<1:1024>>),
-                  error:badarg),
-    ?chk_api_name(crypto:verify(foobar, sha, "nothing", "nothing", <<1:1024>>),
-                  error:badarg).
+    ?chk_api_name(crypto:verify(rsa, foobar, "nothing", <<"nothing">>,  <<1:1024>>),
+                  error:{badarg,{"pkey.c",_},"Bad digest type"}),
+    ?chk_api_name(crypto:verify(foobar, sha, "nothing", <<"nothing">>, <<1:1024>>),
+                  error:{badarg, {"pkey.c",_}, "Bad algorithm"}).
 
 
 %%%----------------------------------------------------------------
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index cab519fdb9..91ed00cbab 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -833,7 +833,7 @@ sign_verify_rsa_pwd_bad_pwd(Config) ->
     try sign_verify(rsa, sha, Priv, Pub) of
         _ -> {fail, "PWD prot pubkey sign succeeded with no pwd!"}
     catch
-        error:badarg -> ok
+        error:{badarg,_,_} -> ok
     end.
 
 priv_encrypt_pub_decrypt_rsa(Config) ->
-- 
2.34.1

openSUSE Build Service is sponsored by