1 /*
2 * %CopyrightBegin%
3 *
4 * Copyright Ericsson AB 2010-2020. All Rights Reserved.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * %CopyrightEnd%
19 */
20
21 #include "evp.h"
22
evp_compute_key_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])23 ERL_NIF_TERM evp_compute_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
24 /* (Curve, PeerBin, MyBin) */
25 {
26 #ifdef HAVE_EDDH
27 ERL_NIF_TERM ret;
28 int type;
29 EVP_PKEY_CTX *ctx = NULL;
30 ErlNifBinary peer_bin, my_bin, key_bin;
31 EVP_PKEY *peer_key = NULL, *my_key = NULL;
32 size_t max_size;
33 int key_bin_alloc = 0;
34
35 ASSERT(argc == 3);
36
37 if (argv[0] == atom_x25519)
38 type = EVP_PKEY_X25519;
39 else if (argv[0] == atom_x448)
40 type = EVP_PKEY_X448;
41 else
42 goto bad_arg;
43
44 if (!enif_inspect_binary(env, argv[1], &peer_bin))
45 goto bad_arg;
46 if (!enif_inspect_binary(env, argv[2], &my_bin))
47 goto bad_arg;
48
49 if ((my_key = EVP_PKEY_new_raw_private_key(type, NULL, my_bin.data, my_bin.size)) == NULL)
50 goto err;
51 if ((ctx = EVP_PKEY_CTX_new(my_key, NULL)) == NULL)
52 goto err;
53
54 if (EVP_PKEY_derive_init(ctx) != 1)
55 goto err;
56
57 if ((peer_key = EVP_PKEY_new_raw_public_key(type, NULL, peer_bin.data, peer_bin.size)) == NULL)
58 goto err;
59 if (EVP_PKEY_derive_set_peer(ctx, peer_key) != 1)
60 goto err;
61
62 if (EVP_PKEY_derive(ctx, NULL, &max_size) != 1)
63 goto err;
64
65 if (!enif_alloc_binary(max_size, &key_bin))
66 goto err;
67 key_bin_alloc = 1;
68 if (EVP_PKEY_derive(ctx, key_bin.data, &key_bin.size) != 1)
69 goto err;
70
71 if (key_bin.size < max_size) {
72 if (!enif_realloc_binary(&key_bin, (size_t)key_bin.size))
73 goto err;
74 }
75
76 ret = enif_make_binary(env, &key_bin);
77 key_bin_alloc = 0;
78 goto done;
79
80 bad_arg:
81 err:
82 if (key_bin_alloc)
83 enif_release_binary(&key_bin);
84 ret = enif_make_badarg(env);
85
86 done:
87 if (my_key)
88 EVP_PKEY_free(my_key);
89 if (peer_key)
90 EVP_PKEY_free(peer_key);
91 if (ctx)
92 EVP_PKEY_CTX_free(ctx);
93
94 return ret;
95
96 #else
97 return atom_notsup;
98 #endif
99 }
100
evp_generate_key_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])101 ERL_NIF_TERM evp_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
102 /* (Curve) */
103 {
104 #ifdef HAVE_EDDH
105 int type;
106 EVP_PKEY_CTX *ctx = NULL;
107 EVP_PKEY *pkey = NULL;
108 ERL_NIF_TERM ret_pub, ret_prv, ret;
109 ErlNifBinary prv_key;
110 size_t key_len;
111 unsigned char *out_pub = NULL, *out_priv = NULL;
112
113 if (argv[0] == atom_x25519)
114 type = EVP_PKEY_X25519;
115 else if (argv[0] == atom_x448)
116 type = EVP_PKEY_X448;
117 else if (argv[0] == atom_ed25519)
118 type = EVP_PKEY_ED25519;
119 else if (argv[0] == atom_ed448)
120 type = EVP_PKEY_ED448;
121 else
122 goto bad_arg;
123
124 if (argv[1] == atom_undefined) {
125 if ((ctx = EVP_PKEY_CTX_new_id(type, NULL)) == NULL)
126 goto bad_arg;
127 if (EVP_PKEY_keygen_init(ctx) != 1)
128 goto err;
129 if (EVP_PKEY_keygen(ctx, &pkey) != 1)
130 goto err;
131 } else {
132 if (!enif_inspect_binary(env, argv[1], &prv_key))
133 goto bad_arg;
134 if ((pkey = EVP_PKEY_new_raw_private_key(type, NULL, prv_key.data, prv_key.size)) == NULL)
135 goto bad_arg;
136 }
137
138 if (EVP_PKEY_get_raw_public_key(pkey, NULL, &key_len) != 1)
139 goto err;
140 if ((out_pub = enif_make_new_binary(env, key_len, &ret_pub)) == NULL)
141 goto err;
142 if (EVP_PKEY_get_raw_public_key(pkey, out_pub, &key_len) != 1)
143 goto err;
144
145 if (EVP_PKEY_get_raw_private_key(pkey, NULL, &key_len) != 1)
146 goto err;
147 if ((out_priv = enif_make_new_binary(env, key_len, &ret_prv)) == NULL)
148 goto err;
149 if (EVP_PKEY_get_raw_private_key(pkey, out_priv, &key_len) != 1)
150 goto err;
151
152 ret = enif_make_tuple2(env, ret_pub, ret_prv);
153 goto done;
154
155 bad_arg:
156 ret = enif_make_badarg(env);
157 goto done;
158
159 err:
160 ret = atom_error;
161
162 done:
163 if (pkey)
164 EVP_PKEY_free(pkey);
165 if (ctx)
166 EVP_PKEY_CTX_free(ctx);
167 return ret;
168
169 #else
170 return atom_notsup;
171 #endif
172 }
173
174