/src/dropbear/src/ecdsa.c
Line | Count | Source (jump to first uncovered line) |
1 | | #include "includes.h" |
2 | | #include "dbutil.h" |
3 | | #include "crypto_desc.h" |
4 | | #include "ecc.h" |
5 | | #include "ecdsa.h" |
6 | | #include "signkey.h" |
7 | | |
8 | | #if DROPBEAR_ECDSA |
9 | | |
10 | | int signkey_is_ecdsa(enum signkey_type type) |
11 | 196 | { |
12 | 196 | return type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 |
13 | 196 | || type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 |
14 | 196 | || type == DROPBEAR_SIGNKEY_ECDSA_NISTP521; |
15 | 196 | } |
16 | | |
17 | 0 | enum signkey_type ecdsa_signkey_type(const ecc_key * key) { |
18 | 0 | #if DROPBEAR_ECC_256 |
19 | 0 | if (key->dp == ecc_curve_nistp256.dp) { |
20 | 0 | return DROPBEAR_SIGNKEY_ECDSA_NISTP256; |
21 | 0 | } |
22 | 0 | #endif |
23 | 0 | #if DROPBEAR_ECC_384 |
24 | 0 | if (key->dp == ecc_curve_nistp384.dp) { |
25 | 0 | return DROPBEAR_SIGNKEY_ECDSA_NISTP384; |
26 | 0 | } |
27 | 0 | #endif |
28 | 0 | #if DROPBEAR_ECC_521 |
29 | 0 | if (key->dp == ecc_curve_nistp521.dp) { |
30 | 0 | return DROPBEAR_SIGNKEY_ECDSA_NISTP521; |
31 | 0 | } |
32 | 0 | #endif |
33 | 0 | return DROPBEAR_SIGNKEY_NONE; |
34 | 0 | } |
35 | | |
36 | 0 | ecc_key *gen_ecdsa_priv_key(unsigned int bit_size) { |
37 | 0 | const ltc_ecc_set_type *dp = NULL; /* curve domain parameters */ |
38 | 0 | ecc_key *new_key = NULL; |
39 | 0 | switch (bit_size) { |
40 | 0 | #if DROPBEAR_ECC_256 |
41 | 0 | case 256: |
42 | 0 | dp = ecc_curve_nistp256.dp; |
43 | 0 | break; |
44 | 0 | #endif |
45 | 0 | #if DROPBEAR_ECC_384 |
46 | 0 | case 384: |
47 | 0 | dp = ecc_curve_nistp384.dp; |
48 | 0 | break; |
49 | 0 | #endif |
50 | 0 | #if DROPBEAR_ECC_521 |
51 | 0 | case 521: |
52 | 0 | dp = ecc_curve_nistp521.dp; |
53 | 0 | break; |
54 | 0 | #endif |
55 | 0 | } |
56 | 0 | if (!dp) { |
57 | 0 | dropbear_exit("Key size %d isn't valid. Try " |
58 | 0 | #if DROPBEAR_ECC_256 |
59 | 0 | "256 " |
60 | 0 | #endif |
61 | 0 | #if DROPBEAR_ECC_384 |
62 | 0 | "384 " |
63 | 0 | #endif |
64 | 0 | #if DROPBEAR_ECC_521 |
65 | 0 | "521 " |
66 | 0 | #endif |
67 | 0 | , bit_size); |
68 | 0 | } |
69 | | |
70 | 0 | new_key = m_malloc(sizeof(*new_key)); |
71 | 0 | if (ecc_make_key_ex(NULL, dropbear_ltc_prng, new_key, dp) != CRYPT_OK) { |
72 | 0 | dropbear_exit("ECC error"); |
73 | 0 | } |
74 | 0 | return new_key; |
75 | 0 | } |
76 | | |
77 | 2 | ecc_key *buf_get_ecdsa_pub_key(buffer* buf) { |
78 | 2 | unsigned char *key_ident = NULL, *identifier = NULL; |
79 | 2 | unsigned int key_ident_len, identifier_len; |
80 | 2 | buffer *q_buf = NULL; |
81 | 2 | struct dropbear_ecc_curve **curve; |
82 | 2 | ecc_key *new_key = NULL; |
83 | | |
84 | | /* string "ecdsa-sha2-[identifier]" or "sk-ecdsa-sha2-nistp256@openssh.com" */ |
85 | 2 | key_ident = (unsigned char*)buf_getstring(buf, &key_ident_len); |
86 | | /* string "[identifier]" */ |
87 | 2 | identifier = (unsigned char*)buf_getstring(buf, &identifier_len); |
88 | | |
89 | 2 | if (strcmp (key_ident, "sk-ecdsa-sha2-nistp256@openssh.com") == 0) { |
90 | 0 | if (strcmp (identifier, "nistp256") != 0) { |
91 | 0 | TRACE(("mismatching identifiers")) |
92 | 0 | goto out; |
93 | 0 | } |
94 | 2 | } else { |
95 | 2 | if (key_ident_len != identifier_len + strlen ("ecdsa-sha2-")) { |
96 | 0 | TRACE(("Bad identifier lengths")) |
97 | 0 | goto out; |
98 | 0 | } |
99 | 2 | if (memcmp(&key_ident[strlen ("ecdsa-sha2-")], identifier, identifier_len) != 0) { |
100 | 0 | TRACE(("mismatching identifiers")) |
101 | 0 | goto out; |
102 | 0 | } |
103 | 2 | } |
104 | | |
105 | 2 | for (curve = dropbear_ecc_curves; *curve; curve++) { |
106 | 2 | if (memcmp(identifier, (char*)(*curve)->name, strlen((char*)(*curve)->name)) == 0) { |
107 | 2 | break; |
108 | 2 | } |
109 | 2 | } |
110 | 2 | if (!*curve) { |
111 | 0 | TRACE(("couldn't match ecc curve")) |
112 | 0 | goto out; |
113 | 0 | } |
114 | | |
115 | | /* string Q */ |
116 | 2 | q_buf = buf_getstringbuf(buf); |
117 | 2 | new_key = buf_get_ecc_raw_pubkey(q_buf, *curve); |
118 | | |
119 | 2 | out: |
120 | 2 | m_free(key_ident); |
121 | 2 | m_free(identifier); |
122 | 2 | if (q_buf) { |
123 | 2 | buf_free(q_buf); |
124 | 2 | q_buf = NULL; |
125 | 2 | } |
126 | 2 | TRACE(("leave buf_get_ecdsa_pub_key")) |
127 | 2 | return new_key; |
128 | 2 | } |
129 | | |
130 | 2 | ecc_key *buf_get_ecdsa_priv_key(buffer *buf) { |
131 | 2 | ecc_key *new_key = NULL; |
132 | 2 | TRACE(("enter buf_get_ecdsa_priv_key")) |
133 | 2 | new_key = buf_get_ecdsa_pub_key(buf); |
134 | 2 | if (!new_key) { |
135 | 0 | return NULL; |
136 | 0 | } |
137 | | |
138 | 2 | if (buf_getmpint(buf, new_key->k) != DROPBEAR_SUCCESS) { |
139 | 0 | ecc_free(new_key); |
140 | 0 | m_free(new_key); |
141 | 0 | return NULL; |
142 | 0 | } |
143 | | |
144 | 2 | return new_key; |
145 | 2 | } |
146 | | |
147 | 188 | void buf_put_ecdsa_pub_key(buffer *buf, ecc_key *key) { |
148 | 188 | struct dropbear_ecc_curve *curve = NULL; |
149 | 188 | char key_ident[30]; |
150 | | |
151 | 188 | curve = curve_for_dp(key->dp); |
152 | 188 | snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name); |
153 | 188 | buf_putstring(buf, key_ident, strlen(key_ident)); |
154 | 188 | buf_putstring(buf, curve->name, strlen(curve->name)); |
155 | 188 | buf_put_ecc_raw_pubkey_string(buf, key); |
156 | 188 | } |
157 | | |
158 | 0 | void buf_put_ecdsa_priv_key(buffer *buf, ecc_key *key) { |
159 | 0 | buf_put_ecdsa_pub_key(buf, key); |
160 | 0 | buf_putmpint(buf, key->k); |
161 | 0 | } |
162 | | |
163 | 0 | void buf_put_ecdsa_sign(buffer *buf, const ecc_key *key, const buffer *data_buf) { |
164 | | /* Based on libtomcrypt's ecc_sign_hash but without the asn1 */ |
165 | 0 | int err = DROPBEAR_FAILURE; |
166 | 0 | struct dropbear_ecc_curve *curve = NULL; |
167 | 0 | hash_state hs; |
168 | 0 | unsigned char hash[64]; |
169 | 0 | void *e = NULL, *p = NULL, *s = NULL, *r; |
170 | 0 | char key_ident[30]; |
171 | 0 | buffer *sigbuf = NULL; |
172 | |
|
173 | 0 | TRACE(("buf_put_ecdsa_sign")) |
174 | 0 | curve = curve_for_dp(key->dp); |
175 | |
|
176 | 0 | if (ltc_init_multi(&r, &s, &p, &e, NULL) != CRYPT_OK) { |
177 | 0 | goto out; |
178 | 0 | } |
179 | | |
180 | 0 | curve->hash_desc->init(&hs); |
181 | 0 | curve->hash_desc->process(&hs, data_buf->data, data_buf->len); |
182 | 0 | curve->hash_desc->done(&hs, hash); |
183 | |
|
184 | 0 | if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) { |
185 | 0 | goto out; |
186 | 0 | } |
187 | | |
188 | 0 | if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) { |
189 | 0 | goto out; |
190 | 0 | } |
191 | | |
192 | 0 | for (;;) { |
193 | 0 | ecc_key R_key; /* ephemeral key */ |
194 | 0 | if (ecc_make_key_ex(NULL, dropbear_ltc_prng, &R_key, key->dp) != CRYPT_OK) { |
195 | 0 | goto out; |
196 | 0 | } |
197 | 0 | if (ltc_mp.mpdiv(R_key.pubkey.x, p, NULL, r) != CRYPT_OK) { |
198 | 0 | goto out; |
199 | 0 | } |
200 | 0 | if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ) { |
201 | | /* try again */ |
202 | 0 | ecc_free(&R_key); |
203 | 0 | continue; |
204 | 0 | } |
205 | | /* k = 1/k */ |
206 | 0 | if (ltc_mp.invmod(R_key.k, p, R_key.k) != CRYPT_OK) { |
207 | 0 | goto out; |
208 | 0 | } |
209 | | /* s = xr */ |
210 | 0 | if (ltc_mp.mulmod(key->k, r, p, s) != CRYPT_OK) { |
211 | 0 | goto out; |
212 | 0 | } |
213 | | /* s = e + xr */ |
214 | 0 | if (ltc_mp.add(e, s, s) != CRYPT_OK) { |
215 | 0 | goto out; |
216 | 0 | } |
217 | 0 | if (ltc_mp.mpdiv(s, p, NULL, s) != CRYPT_OK) { |
218 | 0 | goto out; |
219 | 0 | } |
220 | | /* s = (e + xr)/k */ |
221 | 0 | if (ltc_mp.mulmod(s, R_key.k, p, s) != CRYPT_OK) { |
222 | 0 | goto out; |
223 | 0 | } |
224 | 0 | ecc_free(&R_key); |
225 | |
|
226 | 0 | if (ltc_mp.compare_d(s, 0) != LTC_MP_EQ) { |
227 | 0 | break; |
228 | 0 | } |
229 | 0 | } |
230 | | |
231 | 0 | snprintf(key_ident, sizeof(key_ident), "ecdsa-sha2-%s", curve->name); |
232 | 0 | buf_putstring(buf, key_ident, strlen(key_ident)); |
233 | | /* enough for nistp521 */ |
234 | 0 | sigbuf = buf_new(200); |
235 | 0 | buf_putmpint(sigbuf, (mp_int*)r); |
236 | 0 | buf_putmpint(sigbuf, (mp_int*)s); |
237 | 0 | buf_putbufstring(buf, sigbuf); |
238 | |
|
239 | 0 | err = DROPBEAR_SUCCESS; |
240 | |
|
241 | 0 | out: |
242 | 0 | if (r && s && p && e) { |
243 | 0 | ltc_deinit_multi(r, s, p, e, NULL); |
244 | 0 | } |
245 | |
|
246 | 0 | if (sigbuf) { |
247 | 0 | buf_free(sigbuf); |
248 | 0 | } |
249 | |
|
250 | 0 | if (err == DROPBEAR_FAILURE) { |
251 | 0 | dropbear_exit("ECC error"); |
252 | 0 | } |
253 | 0 | } |
254 | | |
255 | | /* returns values in s and r |
256 | | returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ |
257 | | static int buf_get_ecdsa_verify_params(buffer *buf, |
258 | 0 | void *r, void* s) { |
259 | 0 | int ret = DROPBEAR_FAILURE; |
260 | 0 | unsigned int sig_len; |
261 | 0 | unsigned int sig_pos; |
262 | |
|
263 | 0 | sig_len = buf_getint(buf); |
264 | 0 | sig_pos = buf->pos; |
265 | 0 | if (buf_getmpint(buf, r) != DROPBEAR_SUCCESS) { |
266 | 0 | goto out; |
267 | 0 | } |
268 | 0 | if (buf_getmpint(buf, s) != DROPBEAR_SUCCESS) { |
269 | 0 | goto out; |
270 | 0 | } |
271 | 0 | if (buf->pos - sig_pos != sig_len) { |
272 | 0 | goto out; |
273 | 0 | } |
274 | 0 | ret = DROPBEAR_SUCCESS; |
275 | |
|
276 | 0 | out: |
277 | 0 | return ret; |
278 | 0 | } |
279 | | |
280 | | |
281 | 0 | int buf_ecdsa_verify(buffer *buf, const ecc_key *key, const buffer *data_buf) { |
282 | | /* Based on libtomcrypt's ecc_verify_hash but without the asn1 */ |
283 | 0 | int ret = DROPBEAR_FAILURE; |
284 | 0 | hash_state hs; |
285 | 0 | struct dropbear_ecc_curve *curve = NULL; |
286 | 0 | unsigned char hash[64]; |
287 | 0 | ecc_point *mG = NULL, *mQ = NULL; |
288 | 0 | void *r = NULL, *s = NULL, *v = NULL, *w = NULL, *u1 = NULL, *u2 = NULL, |
289 | 0 | *e = NULL, *p = NULL, *m = NULL; |
290 | 0 | void *mp = NULL; |
291 | | |
292 | | /* verify |
293 | | * |
294 | | * w = s^-1 mod n |
295 | | * u1 = xw |
296 | | * u2 = rw |
297 | | * X = u1*G + u2*Q |
298 | | * v = X_x1 mod n |
299 | | * accept if v == r |
300 | | */ |
301 | |
|
302 | 0 | TRACE(("buf_ecdsa_verify")) |
303 | 0 | curve = curve_for_dp(key->dp); |
304 | |
|
305 | 0 | mG = ltc_ecc_new_point(); |
306 | 0 | mQ = ltc_ecc_new_point(); |
307 | 0 | if (ltc_init_multi(&r, &s, &v, &w, &u1, &u2, &p, &e, &m, NULL) != CRYPT_OK |
308 | 0 | || !mG |
309 | 0 | || !mQ) { |
310 | 0 | dropbear_exit("ECC error"); |
311 | 0 | } |
312 | | |
313 | 0 | if (buf_get_ecdsa_verify_params(buf, r, s) != DROPBEAR_SUCCESS) { |
314 | 0 | goto out; |
315 | 0 | } |
316 | | |
317 | 0 | curve->hash_desc->init(&hs); |
318 | 0 | curve->hash_desc->process(&hs, data_buf->data, data_buf->len); |
319 | 0 | curve->hash_desc->done(&hs, hash); |
320 | |
|
321 | 0 | if (ltc_mp.unsigned_read(e, hash, curve->hash_desc->hashsize) != CRYPT_OK) { |
322 | 0 | goto out; |
323 | 0 | } |
324 | | |
325 | | /* get the order */ |
326 | 0 | if (ltc_mp.read_radix(p, (char *)key->dp->order, 16) != CRYPT_OK) { |
327 | 0 | goto out; |
328 | 0 | } |
329 | | |
330 | | /* get the modulus */ |
331 | 0 | if (ltc_mp.read_radix(m, (char *)key->dp->prime, 16) != CRYPT_OK) { |
332 | 0 | goto out; |
333 | 0 | } |
334 | | |
335 | | /* check for zero */ |
336 | 0 | if (ltc_mp.compare_d(r, 0) == LTC_MP_EQ |
337 | 0 | || ltc_mp.compare_d(s, 0) == LTC_MP_EQ |
338 | 0 | || ltc_mp.compare(r, p) != LTC_MP_LT |
339 | 0 | || ltc_mp.compare(s, p) != LTC_MP_LT) { |
340 | 0 | goto out; |
341 | 0 | } |
342 | | |
343 | | /* w = s^-1 mod n */ |
344 | 0 | if (ltc_mp.invmod(s, p, w) != CRYPT_OK) { |
345 | 0 | goto out; |
346 | 0 | } |
347 | | |
348 | | /* u1 = ew */ |
349 | 0 | if (ltc_mp.mulmod(e, w, p, u1) != CRYPT_OK) { |
350 | 0 | goto out; |
351 | 0 | } |
352 | | |
353 | | /* u2 = rw */ |
354 | 0 | if (ltc_mp.mulmod(r, w, p, u2) != CRYPT_OK) { |
355 | 0 | goto out; |
356 | 0 | } |
357 | | |
358 | | /* find mG and mQ */ |
359 | 0 | if (ltc_mp.read_radix(mG->x, (char *)key->dp->Gx, 16) != CRYPT_OK) { |
360 | 0 | goto out; |
361 | 0 | } |
362 | 0 | if (ltc_mp.read_radix(mG->y, (char *)key->dp->Gy, 16) != CRYPT_OK) { |
363 | 0 | goto out; |
364 | 0 | } |
365 | 0 | if (ltc_mp.set_int(mG->z, 1) != CRYPT_OK) { |
366 | 0 | goto out; |
367 | 0 | } |
368 | | |
369 | 0 | if (ltc_mp.copy(key->pubkey.x, mQ->x) != CRYPT_OK |
370 | 0 | || ltc_mp.copy(key->pubkey.y, mQ->y) != CRYPT_OK |
371 | 0 | || ltc_mp.copy(key->pubkey.z, mQ->z) != CRYPT_OK) { |
372 | 0 | goto out; |
373 | 0 | } |
374 | | |
375 | | /* compute u1*mG + u2*mQ = mG */ |
376 | 0 | if (ltc_mp.ecc_mul2add == NULL) { |
377 | 0 | if (ltc_mp.ecc_ptmul(u1, mG, mG, m, 0) != CRYPT_OK) { |
378 | 0 | goto out; |
379 | 0 | } |
380 | 0 | if (ltc_mp.ecc_ptmul(u2, mQ, mQ, m, 0) != CRYPT_OK) { |
381 | 0 | goto out; |
382 | 0 | } |
383 | | |
384 | | /* find the montgomery mp */ |
385 | 0 | if (ltc_mp.montgomery_setup(m, &mp) != CRYPT_OK) { |
386 | 0 | goto out; |
387 | 0 | } |
388 | | |
389 | | /* add them */ |
390 | 0 | if (ltc_mp.ecc_ptadd(mQ, mG, mG, m, mp) != CRYPT_OK) { |
391 | 0 | goto out; |
392 | 0 | } |
393 | | |
394 | | /* reduce */ |
395 | 0 | if (ltc_mp.ecc_map(mG, m, mp) != CRYPT_OK) { |
396 | 0 | goto out; |
397 | 0 | } |
398 | 0 | } else { |
399 | | /* use Shamir's trick to compute u1*mG + u2*mQ using half of the doubles */ |
400 | 0 | if (ltc_mp.ecc_mul2add(mG, u1, mQ, u2, mG, m) != CRYPT_OK) { |
401 | 0 | goto out; |
402 | 0 | } |
403 | 0 | } |
404 | | |
405 | | /* v = X_x1 mod n */ |
406 | 0 | if (ltc_mp.mpdiv(mG->x, p, NULL, v) != CRYPT_OK) { |
407 | 0 | goto out; |
408 | 0 | } |
409 | | |
410 | | /* does v == r */ |
411 | 0 | if (ltc_mp.compare(v, r) == LTC_MP_EQ) { |
412 | 0 | ret = DROPBEAR_SUCCESS; |
413 | 0 | } |
414 | |
|
415 | 0 | out: |
416 | 0 | ltc_ecc_del_point(mG); |
417 | 0 | ltc_ecc_del_point(mQ); |
418 | 0 | ltc_deinit_multi(r, s, v, w, u1, u2, p, e, m, NULL); |
419 | 0 | if (mp != NULL) { |
420 | 0 | ltc_mp.montgomery_deinit(mp); |
421 | 0 | } |
422 | 0 | return ret; |
423 | 0 | } |
424 | | |
425 | | |
426 | | |
427 | | #endif /* DROPBEAR_ECDSA */ |