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 "rsa.h"
22 #include "bn.h"
23
24 static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
25 static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa);
26 static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt);
27
get_rsa_private_key(ErlNifEnv * env,ERL_NIF_TERM key,RSA * rsa)28 int get_rsa_private_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
29 {
30 /* key=[E,N,D]|[E,N,D,P1,P2,E1,E2,C] */
31 ERL_NIF_TERM head, tail;
32 BIGNUM *e = NULL, *n = NULL, *d = NULL;
33 BIGNUM *p = NULL, *q = NULL;
34 BIGNUM *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
35
36 if (!enif_get_list_cell(env, key, &head, &tail))
37 goto bad_arg;
38 if (!get_bn_from_bin(env, head, &e))
39 goto bad_arg;
40 if (!enif_get_list_cell(env, tail, &head, &tail))
41 goto bad_arg;
42 if (!get_bn_from_bin(env, head, &n))
43 goto bad_arg;
44 if (!enif_get_list_cell(env, tail, &head, &tail))
45 goto bad_arg;
46 if (!get_bn_from_bin(env, head, &d))
47 goto bad_arg;
48
49 if (!RSA_set0_key(rsa, n, e, d))
50 goto err;
51 /* rsa now owns n, e, and d */
52 n = NULL;
53 e = NULL;
54 d = NULL;
55
56 if (enif_is_empty_list(env, tail))
57 return 1;
58
59 if (!enif_get_list_cell(env, tail, &head, &tail))
60 goto bad_arg;
61 if (!get_bn_from_bin(env, head, &p))
62 goto bad_arg;
63 if (!enif_get_list_cell(env, tail, &head, &tail))
64 goto bad_arg;
65 if (!get_bn_from_bin(env, head, &q))
66 goto bad_arg;
67 if (!enif_get_list_cell(env, tail, &head, &tail))
68 goto bad_arg;
69 if (!get_bn_from_bin(env, head, &dmp1))
70 goto bad_arg;
71 if (!enif_get_list_cell(env, tail, &head, &tail))
72 goto bad_arg;
73 if (!get_bn_from_bin(env, head, &dmq1))
74 goto bad_arg;
75 if (!enif_get_list_cell(env, tail, &head, &tail))
76 goto bad_arg;
77 if (!get_bn_from_bin(env, head, &iqmp))
78 goto bad_arg;
79 if (!enif_is_empty_list(env, tail))
80 goto bad_arg;
81
82 if (!RSA_set0_factors(rsa, p, q))
83 goto err;
84 /* rsa now owns p and q */
85 p = NULL;
86 q = NULL;
87
88 if (!RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp))
89 goto err;
90 /* rsa now owns dmp1, dmq1, and iqmp */
91 dmp1 = NULL;
92 dmq1 = NULL;
93 iqmp = NULL;
94
95 return 1;
96
97 bad_arg:
98 err:
99 if (e)
100 BN_free(e);
101 if (n)
102 BN_free(n);
103 if (d)
104 BN_free(d);
105 if (p)
106 BN_free(p);
107 if (q)
108 BN_free(q);
109 if (dmp1)
110 BN_free(dmp1);
111 if (dmq1)
112 BN_free(dmq1);
113 if (iqmp)
114 BN_free(iqmp);
115
116 return 0;
117 }
118
get_rsa_public_key(ErlNifEnv * env,ERL_NIF_TERM key,RSA * rsa)119 int get_rsa_public_key(ErlNifEnv* env, ERL_NIF_TERM key, RSA *rsa)
120 {
121 /* key=[E,N] */
122 ERL_NIF_TERM head, tail;
123 BIGNUM *e = NULL, *n = NULL;
124
125 if (!enif_get_list_cell(env, key, &head, &tail))
126 goto bad_arg;
127 if (!get_bn_from_bin(env, head, &e))
128 goto bad_arg;
129 if (!enif_get_list_cell(env, tail, &head, &tail))
130 goto bad_arg;
131 if (!get_bn_from_bin(env, head, &n))
132 goto bad_arg;
133 if (!enif_is_empty_list(env, tail))
134 goto bad_arg;
135
136 if (!RSA_set0_key(rsa, n, e, NULL))
137 goto err;
138 /* rsa now owns n and e */
139 n = NULL;
140 e = NULL;
141
142 return 1;
143
144 bad_arg:
145 err:
146 if (e)
147 BN_free(e);
148 if (n)
149 BN_free(n);
150
151 return 0;
152 }
153
154 /* Creates a term which can be parsed by get_rsa_private_key(). This is a list of plain integer binaries (not mpints). */
put_rsa_private_key(ErlNifEnv * env,const RSA * rsa)155 static ERL_NIF_TERM put_rsa_private_key(ErlNifEnv* env, const RSA *rsa)
156 {
157 ERL_NIF_TERM result[8];
158 const BIGNUM *n = NULL, *e = NULL, *d = NULL, *p = NULL, *q = NULL, *dmp1 = NULL, *dmq1 = NULL, *iqmp = NULL;
159
160 /* Return at least [E,N,D] */
161 RSA_get0_key(rsa, &n, &e, &d);
162
163 if ((result[0] = bin_from_bn(env, e)) == atom_error) // Exponent E
164 goto err;
165 if ((result[1] = bin_from_bn(env, n)) == atom_error) // Modulus N = p*q
166 goto err;
167 if ((result[2] = bin_from_bn(env, d)) == atom_error) // Exponent D
168 goto err;
169
170 /* Check whether the optional additional parameters are available */
171 RSA_get0_factors(rsa, &p, &q);
172 RSA_get0_crt_params(rsa, &dmp1, &dmq1, &iqmp);
173
174 if (p && q && dmp1 && dmq1 && iqmp) {
175 if ((result[3] = bin_from_bn(env, p)) == atom_error) // Factor p
176 goto err;
177 if ((result[4] = bin_from_bn(env, q)) == atom_error) // Factor q
178 goto err;
179 if ((result[5] = bin_from_bn(env, dmp1)) == atom_error) // D mod (p-1)
180 goto err;
181 if ((result[6] = bin_from_bn(env, dmq1)) == atom_error) // D mod (q-1)
182 goto err;
183 if ((result[7] = bin_from_bn(env, iqmp)) == atom_error) // (1/q) mod p
184 goto err;
185
186 return enif_make_list_from_array(env, result, 8);
187 } else {
188 return enif_make_list_from_array(env, result, 3);
189 }
190
191 err:
192 return enif_make_badarg(env);
193 }
194
check_erlang_interrupt(int maj,int min,BN_GENCB * ctxt)195 static int check_erlang_interrupt(int maj, int min, BN_GENCB *ctxt)
196 {
197 ErlNifEnv *env = BN_GENCB_get_arg(ctxt);
198
199 if (!enif_is_current_process_alive(env)) {
200 return 0;
201 } else {
202 return 1;
203 }
204 }
205
rsa_generate_key(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])206 static ERL_NIF_TERM rsa_generate_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
207 {/* (ModulusSize, PublicExponent) */
208 ERL_NIF_TERM ret;
209 int modulus_bits;
210 BIGNUM *pub_exp = NULL, *three = NULL;
211 RSA *rsa = NULL;
212 BN_GENCB *intr_cb = NULL;
213 #ifndef HAVE_OPAQUE_BN_GENCB
214 BN_GENCB intr_cb_buf;
215 #endif
216
217 ASSERT(argc == 2);
218
219 if (!enif_get_int(env, argv[0], &modulus_bits))
220 goto bad_arg;
221 if (modulus_bits < 256)
222 goto bad_arg;
223 if (!get_bn_from_bin(env, argv[1], &pub_exp))
224 goto bad_arg;
225
226 /* Make sure the public exponent is large enough (at least 3).
227 * Without this, RSA_generate_key_ex() can run forever. */
228 if ((three = BN_new()) == NULL)
229 goto err;
230 if (!BN_set_word(three, 3))
231 goto err;
232 if (BN_cmp(pub_exp, three) < 0)
233 goto err;
234
235 /* For large keys, prime generation can take many seconds. Set up
236 * the callback which we use to test whether the process has been
237 * interrupted. */
238 #ifdef HAVE_OPAQUE_BN_GENCB
239 if ((intr_cb = BN_GENCB_new()) == NULL)
240 goto err;
241 #else
242 intr_cb = &intr_cb_buf;
243 #endif
244 BN_GENCB_set(intr_cb, check_erlang_interrupt, env);
245
246 if ((rsa = RSA_new()) == NULL)
247 goto err;
248
249 if (!RSA_generate_key_ex(rsa, modulus_bits, pub_exp, intr_cb))
250 goto err;
251
252 ret = put_rsa_private_key(env, rsa);
253 goto done;
254
255 bad_arg:
256 return enif_make_badarg(env);
257
258 err:
259 ret = atom_error;
260
261 done:
262 if (pub_exp)
263 BN_free(pub_exp);
264 if (three)
265 BN_free(three);
266 #ifdef HAVE_OPAQUE_BN_GENCB
267 if (intr_cb)
268 BN_GENCB_free(intr_cb);
269 #endif
270 if (rsa)
271 RSA_free(rsa);
272 return ret;
273 }
274
rsa_generate_key_nif(ErlNifEnv * env,int argc,const ERL_NIF_TERM argv[])275 ERL_NIF_TERM rsa_generate_key_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
276 {
277 /* RSA key generation can take a long time (>1 sec for a large
278 * modulus), so schedule it as a CPU-bound operation. */
279 return enif_schedule_nif(env, "rsa_generate_key",
280 ERL_NIF_DIRTY_JOB_CPU_BOUND,
281 rsa_generate_key, argc, argv);
282 }
283