Line | Count | Source (jump to first uncovered line) |
1 | | #include "includes.h" |
2 | | #include "ecc.h" |
3 | | #include "dbutil.h" |
4 | | #include "bignum.h" |
5 | | |
6 | | #if DROPBEAR_ECC |
7 | | |
8 | | /* .dp members are filled out by dropbear_ecc_fill_dp() at startup */ |
9 | | #if DROPBEAR_ECC_256 |
10 | | struct dropbear_ecc_curve ecc_curve_nistp256 = { |
11 | | 32, /* .ltc_size */ |
12 | | NULL, /* .dp */ |
13 | | &sha256_desc, /* .hash_desc */ |
14 | | "nistp256" /* .name */ |
15 | | }; |
16 | | #endif |
17 | | #if DROPBEAR_ECC_384 |
18 | | struct dropbear_ecc_curve ecc_curve_nistp384 = { |
19 | | 48, /* .ltc_size */ |
20 | | NULL, /* .dp */ |
21 | | &sha384_desc, /* .hash_desc */ |
22 | | "nistp384" /* .name */ |
23 | | }; |
24 | | #endif |
25 | | #if DROPBEAR_ECC_521 |
26 | | struct dropbear_ecc_curve ecc_curve_nistp521 = { |
27 | | 66, /* .ltc_size */ |
28 | | NULL, /* .dp */ |
29 | | &sha512_desc, /* .hash_desc */ |
30 | | "nistp521" /* .name */ |
31 | | }; |
32 | | #endif |
33 | | |
34 | | struct dropbear_ecc_curve *dropbear_ecc_curves[] = { |
35 | | #if DROPBEAR_ECC_256 |
36 | | &ecc_curve_nistp256, |
37 | | #endif |
38 | | #if DROPBEAR_ECC_384 |
39 | | &ecc_curve_nistp384, |
40 | | #endif |
41 | | #if DROPBEAR_ECC_521 |
42 | | &ecc_curve_nistp521, |
43 | | #endif |
44 | | NULL |
45 | | }; |
46 | | |
47 | 20 | void dropbear_ecc_fill_dp() { |
48 | 20 | struct dropbear_ecc_curve **curve; |
49 | | /* libtomcrypt guarantees they're ordered by size */ |
50 | 20 | const ltc_ecc_set_type *dp = ltc_ecc_sets; |
51 | 80 | for (curve = dropbear_ecc_curves; *curve; curve++) { |
52 | 200 | for (;dp->size > 0; dp++) { |
53 | 200 | if (dp->size == (*curve)->ltc_size) { |
54 | 60 | (*curve)->dp = dp; |
55 | 60 | break; |
56 | 60 | } |
57 | 200 | } |
58 | 60 | if (!(*curve)->dp) { |
59 | 0 | dropbear_exit("Missing ECC params %s", (*curve)->name); |
60 | 0 | } |
61 | 60 | } |
62 | 20 | } |
63 | | |
64 | 11.0k | struct dropbear_ecc_curve* curve_for_dp(const ltc_ecc_set_type *dp) { |
65 | 11.0k | struct dropbear_ecc_curve **curve = NULL; |
66 | 11.5k | for (curve = dropbear_ecc_curves; *curve; curve++) { |
67 | 11.5k | if ((*curve)->dp == dp) { |
68 | 11.0k | break; |
69 | 11.0k | } |
70 | 11.5k | } |
71 | 11.0k | assert(*curve); |
72 | 11.0k | return *curve; |
73 | 11.0k | } |
74 | | |
75 | 1.06k | ecc_key * new_ecc_key(void) { |
76 | 1.06k | ecc_key *key = m_malloc(sizeof(*key)); |
77 | 1.06k | m_mp_alloc_init_multi((mp_int**)&key->pubkey.x, (mp_int**)&key->pubkey.y, |
78 | 1.06k | (mp_int**)&key->pubkey.z, (mp_int**)&key->k, NULL); |
79 | 1.06k | return key; |
80 | 1.06k | } |
81 | | |
82 | | /* Copied from libtomcrypt ecc_import.c (version there is static), modified |
83 | | for different mp_int pointer without LTC_SOURCE */ |
84 | | static int ecc_is_point(const ecc_key *key) |
85 | 1.06k | { |
86 | 1.06k | mp_int *prime, *b, *t1, *t2; |
87 | 1.06k | int err; |
88 | | |
89 | 1.06k | m_mp_alloc_init_multi(&prime, &b, &t1, &t2, NULL); |
90 | | |
91 | | /* load prime and b */ |
92 | 1.06k | if ((err = mp_read_radix(prime, key->dp->prime, 16)) != CRYPT_OK) { goto error; } |
93 | 1.06k | if ((err = mp_read_radix(b, key->dp->B, 16)) != CRYPT_OK) { goto error; } |
94 | | |
95 | | /* compute y^2 */ |
96 | 1.06k | if ((err = mp_sqr(key->pubkey.y, t1)) != CRYPT_OK) { goto error; } |
97 | | |
98 | | /* compute x^3 */ |
99 | 1.06k | if ((err = mp_sqr(key->pubkey.x, t2)) != CRYPT_OK) { goto error; } |
100 | 1.06k | if ((err = mp_mod(t2, prime, t2)) != CRYPT_OK) { goto error; } |
101 | 1.06k | if ((err = mp_mul(key->pubkey.x, t2, t2)) != CRYPT_OK) { goto error; } |
102 | | |
103 | | /* compute y^2 - x^3 */ |
104 | 1.06k | if ((err = mp_sub(t1, t2, t1)) != CRYPT_OK) { goto error; } |
105 | | |
106 | | /* compute y^2 - x^3 + 3x */ |
107 | 1.06k | if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; } |
108 | 1.06k | if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; } |
109 | 1.06k | if ((err = mp_add(t1, key->pubkey.x, t1)) != CRYPT_OK) { goto error; } |
110 | 1.06k | if ((err = mp_mod(t1, prime, t1)) != CRYPT_OK) { goto error; } |
111 | 1.06k | while (mp_cmp_d(t1, 0) == LTC_MP_LT) { |
112 | 0 | if ((err = mp_add(t1, prime, t1)) != CRYPT_OK) { goto error; } |
113 | 0 | } |
114 | 1.06k | while (mp_cmp(t1, prime) != LTC_MP_LT) { |
115 | 0 | if ((err = mp_sub(t1, prime, t1)) != CRYPT_OK) { goto error; } |
116 | 0 | } |
117 | | |
118 | | /* compare to b */ |
119 | 1.06k | if (mp_cmp(t1, b) != LTC_MP_EQ) { |
120 | 404 | err = CRYPT_INVALID_PACKET; |
121 | 661 | } else { |
122 | 661 | err = CRYPT_OK; |
123 | 661 | } |
124 | | |
125 | 1.06k | error: |
126 | 1.06k | mp_clear_multi(prime, b, t1, t2, NULL); |
127 | 1.06k | m_free(prime); |
128 | 1.06k | m_free(b); |
129 | 1.06k | m_free(t1); |
130 | 1.06k | m_free(t2); |
131 | 1.06k | return err; |
132 | 1.06k | } |
133 | | |
134 | | /* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */ |
135 | 8.31k | void buf_put_ecc_raw_pubkey_string(buffer *buf, ecc_key *key) { |
136 | 8.31k | unsigned long len = key->dp->size*2 + 1; |
137 | 8.31k | int err; |
138 | 8.31k | buf_putint(buf, len); |
139 | 8.31k | err = ecc_ansi_x963_export(key, buf_getwriteptr(buf, len), &len); |
140 | 8.31k | if (err != CRYPT_OK) { |
141 | 0 | dropbear_exit("ECC error"); |
142 | 0 | } |
143 | 8.31k | buf_incrwritepos(buf, len); |
144 | 8.31k | } |
145 | | |
146 | | /* For the "ephemeral public key octet string" in ECDH (rfc5656 section 4) */ |
147 | 1.56k | ecc_key * buf_get_ecc_raw_pubkey(buffer *buf, const struct dropbear_ecc_curve *curve) { |
148 | 1.56k | ecc_key *key = NULL; |
149 | 1.56k | int ret = DROPBEAR_FAILURE; |
150 | 1.56k | const unsigned int size = curve->dp->size; |
151 | 1.56k | unsigned char first; |
152 | | |
153 | 1.56k | TRACE(("enter buf_get_ecc_raw_pubkey")) |
154 | | |
155 | 1.56k | buf_setpos(buf, 0); |
156 | 1.56k | first = buf_getbyte(buf); |
157 | 1.56k | if (first == 2 || first == 3) { |
158 | 127 | dropbear_log(LOG_WARNING, "Dropbear doesn't support ECC point compression"); |
159 | 127 | return NULL; |
160 | 127 | } |
161 | 1.43k | if (first != 4 || buf->len != 1+2*size) { |
162 | 355 | TRACE(("leave, wrong size")) |
163 | 355 | return NULL; |
164 | 355 | } |
165 | | |
166 | 1.08k | key = new_ecc_key(); |
167 | 1.08k | key->dp = curve->dp; |
168 | | |
169 | 1.08k | if (mp_from_ubin(key->pubkey.x, buf_getptr(buf, size), size) != MP_OKAY) { |
170 | 0 | TRACE(("failed to read x")) |
171 | 0 | goto out; |
172 | 0 | } |
173 | 1.08k | buf_incrpos(buf, size); |
174 | | |
175 | 1.08k | if (mp_from_ubin(key->pubkey.y, buf_getptr(buf, size), size) != MP_OKAY) { |
176 | 0 | TRACE(("failed to read y")) |
177 | 0 | goto out; |
178 | 0 | } |
179 | 1.08k | buf_incrpos(buf, size); |
180 | | |
181 | 1.08k | mp_set(key->pubkey.z, 1); |
182 | | |
183 | 1.08k | if (ecc_is_point(key) != CRYPT_OK) { |
184 | 404 | TRACE(("failed, not a point")) |
185 | 404 | goto out; |
186 | 404 | } |
187 | | |
188 | | /* SEC1 3.2.3.1 Check that Q != 0 */ |
189 | 678 | if (mp_cmp_d(key->pubkey.x, 0) == LTC_MP_EQ) { |
190 | 0 | TRACE(("failed, x == 0")) |
191 | 0 | goto out; |
192 | 0 | } |
193 | 678 | if (mp_cmp_d(key->pubkey.y, 0) == LTC_MP_EQ) { |
194 | 0 | TRACE(("failed, y == 0")) |
195 | 0 | goto out; |
196 | 0 | } |
197 | | |
198 | 678 | ret = DROPBEAR_SUCCESS; |
199 | | |
200 | 1.06k | out: |
201 | 1.06k | if (ret == DROPBEAR_FAILURE) { |
202 | 404 | if (key) { |
203 | 404 | ecc_free(key); |
204 | 404 | m_free(key); |
205 | 404 | key = NULL; |
206 | 404 | } |
207 | 404 | } |
208 | | |
209 | 1.06k | return key; |
210 | | |
211 | 678 | } |
212 | | |
213 | | /* a modified version of libtomcrypt's "ecc_shared_secret" to output |
214 | | a mp_int instead. */ |
215 | | mp_int * dropbear_ecc_shared_secret(ecc_key *public_key, const ecc_key *private_key) |
216 | 266 | { |
217 | 266 | ecc_point *result = NULL; |
218 | 266 | mp_int *prime = NULL, *shared_secret = NULL; |
219 | 266 | int err = DROPBEAR_FAILURE; |
220 | | |
221 | | /* type valid? */ |
222 | 266 | if (private_key->type != PK_PRIVATE) { |
223 | 0 | goto out; |
224 | 0 | } |
225 | | |
226 | 266 | if (private_key->dp != public_key->dp) { |
227 | 1 | goto out; |
228 | 1 | } |
229 | | |
230 | | /* make new point */ |
231 | 265 | result = ltc_ecc_new_point(); |
232 | 265 | if (result == NULL) { |
233 | 0 | goto out; |
234 | 0 | } |
235 | | |
236 | 265 | prime = m_malloc(sizeof(*prime)); |
237 | 265 | m_mp_init(prime); |
238 | | |
239 | 265 | if (mp_read_radix(prime, (char *)private_key->dp->prime, 16) != CRYPT_OK) { |
240 | 0 | goto out; |
241 | 0 | } |
242 | 265 | if (ltc_mp.ecc_ptmul(private_key->k, &public_key->pubkey, result, prime, 1) != CRYPT_OK) { |
243 | 0 | goto out; |
244 | 0 | } |
245 | | |
246 | 265 | shared_secret = m_malloc(sizeof(*shared_secret)); |
247 | 265 | m_mp_init(shared_secret); |
248 | 265 | if (mp_copy(result->x, shared_secret) != CRYPT_OK) { |
249 | 0 | goto out; |
250 | 0 | } |
251 | | |
252 | 265 | mp_clear(prime); |
253 | 265 | m_free(prime); |
254 | 265 | ltc_ecc_del_point(result); |
255 | | |
256 | 265 | err = DROPBEAR_SUCCESS; |
257 | 266 | out: |
258 | 266 | if (err == DROPBEAR_FAILURE) { |
259 | 1 | dropbear_exit("ECC error"); |
260 | 1 | } |
261 | 265 | return shared_secret; |
262 | 266 | } |
263 | | |
264 | | #endif |