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