aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans Nilsson <[email protected]>2017-10-26 15:43:28 +0200
committerHans Nilsson <[email protected]>2017-11-10 12:20:31 +0100
commitf5c169e343c62e57c2a640186b1ff77ce7ce8620 (patch)
tree7be2ff5dd2b234116c1e5f77292bb8b2ec04879a
parent044b0dab40ad2501f84dfdee106b25749e9189a3 (diff)
downloadotp-f5c169e343c62e57c2a640186b1ff77ce7ce8620.tar.gz
otp-f5c169e343c62e57c2a640186b1ff77ce7ce8620.tar.bz2
otp-f5c169e343c62e57c2a640186b1ff77ce7ce8620.zip
crypto: Enable using pub/priv PKCS8 keys stored in an Engine
-rw-r--r--lib/crypto/c_src/crypto.c120
-rw-r--r--lib/crypto/src/crypto.erl19
2 files changed, 128 insertions, 11 deletions
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index 0f07a862d2..4d8854ad8b 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -499,6 +499,10 @@ static int term2point(ErlNifEnv* env, ERL_NIF_TERM term,
#endif
static ERL_NIF_TERM bin_from_bn(ErlNifEnv* env, const BIGNUM *bn);
+#ifdef HAS_ENGINE_SUPPORT
+static int zero_terminate(ErlNifBinary bin, char **buf);
+#endif
+
static int library_refc = 0; /* number of users of this dynamic library */
static ErlNifFunc nif_funcs[] = {
@@ -663,7 +667,12 @@ static ERL_NIF_TERM atom_engine_method_store;
static ERL_NIF_TERM atom_engine_method_pkey_meths;
static ERL_NIF_TERM atom_engine_method_pkey_asn1_meths;
static ERL_NIF_TERM atom_engine_method_ec;
+
+static ERL_NIF_TERM atom_engine;
+static ERL_NIF_TERM atom_key_id;
+static ERL_NIF_TERM atom_password;
#endif
+
static ErlNifResourceType* hmac_context_rtype;
struct hmac_context
{
@@ -1063,6 +1072,10 @@ static int initialize(ErlNifEnv* env, ERL_NIF_TERM load_info)
atom_engine_method_pkey_meths = enif_make_atom(env,"engine_method_pkey_meths");
atom_engine_method_pkey_asn1_meths = enif_make_atom(env,"engine_method_pkey_asn1_meths");
atom_engine_method_ec = enif_make_atom(env,"engine_method_ec");
+
+ atom_engine = enif_make_atom(env,"engine");
+ atom_key_id = enif_make_atom(env,"key_id");
+ atom_password = enif_make_atom(env,"password");
#endif
init_digest_types(env);
@@ -3920,9 +3933,69 @@ static int get_pkey_sign_options(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF
}
+#ifdef HAS_ENGINE_SUPPORT
+static int get_engine_and_key_id(ErlNifEnv *env, ERL_NIF_TERM key, char ** id, ENGINE **e)
+{
+ ERL_NIF_TERM engine_res, key_id_term;
+ struct engine_ctx *ctx;
+ ErlNifBinary key_id_bin;
+
+ if (!enif_get_map_value(env, key, atom_engine, &engine_res) ||
+ !enif_get_resource(env, engine_res, engine_ctx_rtype, (void**)&ctx) ||
+ !enif_get_map_value(env, key, atom_key_id, &key_id_term) ||
+ !enif_inspect_binary(env, key_id_term, &key_id_bin)) {
+ return 0;
+ }
+ else {
+ *e = ctx->engine;
+ return zero_terminate(key_id_bin, id);
+ }
+}
+
+
+static char *get_key_password(ErlNifEnv *env, ERL_NIF_TERM key) {
+ ERL_NIF_TERM tmp_term;
+ ErlNifBinary pwd_bin;
+ char *pwd;
+ if (enif_get_map_value(env, key, atom_password, &tmp_term) &&
+ enif_inspect_binary(env, tmp_term, &pwd_bin) &&
+ zero_terminate(pwd_bin, &pwd)
+ ) return pwd;
+
+ return NULL;
+}
+
+static int zero_terminate(ErlNifBinary bin, char **buf) {
+ *buf = enif_alloc(bin.size+1);
+ if (!*buf)
+ return 0;
+ memcpy(*buf, bin.data, bin.size);
+ *(*buf+bin.size) = 0;
+ return 1;
+}
+#endif
+
static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key, EVP_PKEY **pkey)
{
- if (algorithm == atom_rsa) {
+ if (enif_is_map(env, key)) {
+#ifdef HAS_ENGINE_SUPPORT
+ /* Use key stored in engine */
+ ENGINE *e;
+ char *id;
+ char *password;
+
+ if (!get_engine_and_key_id(env, key, &id, &e))
+ return PKEY_BADARG;
+ password = get_key_password(env, key);
+ *pkey = ENGINE_load_private_key(e, id, NULL, password);
+ if (!pkey)
+ return PKEY_BADARG;
+ enif_free(id);
+#else
+ return PKEY_BADARG;
+#endif
+ }
+ else if (algorithm == atom_rsa) {
RSA *rsa = RSA_new();
if (!get_rsa_private_key(env, key, rsa)) {
@@ -3983,7 +4056,24 @@ static int get_pkey_private_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_
static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_TERM key,
EVP_PKEY **pkey)
{
- if (algorithm == atom_rsa) {
+ if (enif_is_map(env, key)) {
+#ifdef HAS_ENGINE_SUPPORT
+ /* Use key stored in engine */
+ ENGINE *e;
+ char *id;
+ char *password;
+
+ if (!get_engine_and_key_id(env, key, &id, &e))
+ return PKEY_BADARG;
+ password = get_key_password(env, key);
+ *pkey = ENGINE_load_public_key(e, id, NULL, password);
+ if (!pkey)
+ return PKEY_BADARG;
+ enif_free(id);
+#else
+ return PKEY_BADARG;
+#endif
+ } else if (algorithm == atom_rsa) {
RSA *rsa = RSA_new();
if (!get_rsa_public_key(env, key, rsa)) {
@@ -4041,7 +4131,7 @@ static int get_pkey_public_key(ErlNifEnv *env, ERL_NIF_TERM algorithm, ERL_NIF_T
}
static ERL_NIF_TERM pkey_sign_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
-{/* (Algorithm, Type, Data|{digest,Digest}, Key, Options) */
+{/* (Algorithm, Type, Data|{digest,Digest}, Key|#{}, Options) */
int i;
const EVP_MD *md = NULL;
unsigned char md_value[EVP_MAX_MD_SIZE];
@@ -4061,6 +4151,13 @@ 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);
printf("\r\n");
*/
+
+#ifndef HAS_ENGINE_SUPPORT
+ if (enif_is_map(env, argv[3])) {
+ return atom_notsup;
+ }
+#endif
+
i = get_pkey_sign_digest(env, argv[0], argv[1], argv[2], md_value, &md, &tbs, &tbslen);
if (i != PKEY_OK) {
if (i == PKEY_NOTSUP)
@@ -4082,10 +4179,9 @@ printf("\r\n");
}
#ifdef HAS_EVP_PKEY_CTX
-/* printf("EVP interface\r\n");
- */
ctx = EVP_PKEY_CTX_new(pkey, NULL);
if (!ctx) goto badarg;
+
if (EVP_PKEY_sign_init(ctx) <= 0) goto badarg;
if (md != NULL && EVP_PKEY_CTX_set_signature_md(ctx, md) <= 0) goto badarg;
@@ -4187,6 +4283,12 @@ static ERL_NIF_TERM pkey_verify_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
unsigned char *tbs; /* data to be signed */
size_t tbslen;
+#ifndef HAS_ENGINE_SUPPORT
+ if (enif_is_map(env, argv[4])) {
+ return atom_notsup;
+ }
+#endif
+
if (!enif_inspect_binary(env, argv[3], &sig_bin)) {
return enif_make_badarg(env);
}
@@ -4397,7 +4499,13 @@ static ERL_NIF_TERM pkey_crypt_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM
int algo_init = 0;
/* char algo[1024]; */
-
+
+#ifndef HAS_ENGINE_SUPPORT
+ if (enif_is_map(env, argv[2])) {
+ return atom_notsup;
+ }
+#endif
+
if (!enif_inspect_binary(env, argv[1], &in_bin)) {
return enif_make_badarg(env);
}
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 9eba4561e1..90efbc9e9c 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -430,12 +430,13 @@ sign(Algorithm, Type, Data, Key, Options) ->
-type pk_algs() :: rsa | ecdsa | dss .
--type pk_opt() :: list() | rsa_padding() .
+-type pk_key() :: map() | [integer() | binary()] .
+-type pk_opt() :: list() | rsa_padding() .
--spec public_encrypt(pk_algs(), binary(), [binary()], pk_opt()) -> binary().
--spec public_decrypt(pk_algs(), binary(), [integer() | binary()], pk_opt()) -> binary().
--spec private_encrypt(pk_algs(), binary(), [integer() | binary()], pk_opt()) -> binary().
--spec private_decrypt(pk_algs(), binary(), [integer() | binary()], pk_opt()) -> binary().
+-spec public_encrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
+-spec public_decrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
+-spec private_encrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
+-spec private_decrypt(pk_algs(), binary(), pk_key(), pk_opt()) -> binary().
public_encrypt(Algorithm, In, Key, Options) when is_list(Options) ->
case pkey_crypt_nif(Algorithm, In, format_pkey(Algorithm, Key), Options, false, true) of
@@ -1107,6 +1108,11 @@ ensure_int_as_bin(Int) when is_integer(Int) ->
ensure_int_as_bin(Bin) ->
Bin.
+format_pkey(_Alg, #{engine:=_, key_id:=T}=M) when is_binary(T) -> format_pwd(M);
+format_pkey(_Alg, #{engine:=_, key_id:=T}=M) when is_list(T) -> format_pwd(M#{key_id:=list_to_binary(T)});
+format_pkey(_Alg, #{engine:=_ }=M) -> error({bad_key_id, M});
+format_pkey(_Alg, #{}=M) -> error({bad_engine_map, M});
+%%%
format_pkey(rsa, Key) ->
map_ensure_int_as_bin(Key);
format_pkey(ecdsa, [Key, Curve]) ->
@@ -1116,6 +1122,9 @@ format_pkey(dss, Key) ->
format_pkey(_, Key) ->
Key.
+format_pwd(#{password := Pwd}=M) when is_list(Pwd) -> M#{password := list_to_binary(Pwd)};
+format_pwd(M) -> M.
+
%%--------------------------------------------------------------------
%%
-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding' | 'rsa_no_padding'.