/src/dropbear/src/signkey.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Dropbear - a SSH2 server |
3 | | * |
4 | | * Copyright (c) 2002,2003 Matt Johnston |
5 | | * All rights reserved. |
6 | | * |
7 | | * Permission is hereby granted, free of charge, to any person obtaining a copy |
8 | | * of this software and associated documentation files (the "Software"), to deal |
9 | | * in the Software without restriction, including without limitation the rights |
10 | | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
11 | | * copies of the Software, and to permit persons to whom the Software is |
12 | | * furnished to do so, subject to the following conditions: |
13 | | * |
14 | | * The above copyright notice and this permission notice shall be included in |
15 | | * all copies or substantial portions of the Software. |
16 | | * |
17 | | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
18 | | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
19 | | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
20 | | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
21 | | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
22 | | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
23 | | * SOFTWARE. */ |
24 | | |
25 | | #include "includes.h" |
26 | | #include "dbutil.h" |
27 | | #include "signkey.h" |
28 | | #include "buffer.h" |
29 | | #include "ssh.h" |
30 | | #include "ecdsa.h" |
31 | | #include "sk-ecdsa.h" |
32 | | #include "sk-ed25519.h" |
33 | | #include "rsa.h" |
34 | | #include "dss.h" |
35 | | #include "ed25519.h" |
36 | | |
37 | | static const char * const signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = { |
38 | | #if DROPBEAR_RSA |
39 | | "ssh-rsa", |
40 | | #endif |
41 | | #if DROPBEAR_DSS |
42 | | "ssh-dss", |
43 | | #endif |
44 | | #if DROPBEAR_ECDSA |
45 | | "ecdsa-sha2-nistp256", |
46 | | "ecdsa-sha2-nistp384", |
47 | | "ecdsa-sha2-nistp521", |
48 | | #if DROPBEAR_SK_ECDSA |
49 | | "sk-ecdsa-sha2-nistp256@openssh.com", |
50 | | #endif /* DROPBEAR_SK_ECDSA */ |
51 | | #endif /* DROPBEAR_ECDSA */ |
52 | | #if DROPBEAR_ED25519 |
53 | | "ssh-ed25519", |
54 | | #if DROPBEAR_SK_ED25519 |
55 | | "sk-ssh-ed25519@openssh.com", |
56 | | #endif /* DROPBEAR_SK_ED25519 */ |
57 | | #endif /* DROPBEAR_ED25519 */ |
58 | | /* "rsa-sha2-256" is special-cased below since it is only a signature name, not key type */ |
59 | | }; |
60 | | |
61 | | /* malloc a new sign_key and set the dss and rsa keys to NULL */ |
62 | 2 | sign_key * new_sign_key() { |
63 | | |
64 | 2 | sign_key * ret; |
65 | | |
66 | 2 | ret = (sign_key*)m_malloc(sizeof(sign_key)); |
67 | 2 | ret->type = DROPBEAR_SIGNKEY_NONE; |
68 | 2 | ret->source = SIGNKEY_SOURCE_INVALID; |
69 | 2 | return ret; |
70 | 2 | } |
71 | | |
72 | | /* Returns key name corresponding to the type. Exits fatally |
73 | | * if the type is invalid */ |
74 | 0 | const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen) { |
75 | 0 | if (type >= DROPBEAR_SIGNKEY_NUM_NAMED) { |
76 | 0 | dropbear_exit("Bad key type %d", type); |
77 | 0 | } |
78 | | |
79 | 0 | if (namelen) { |
80 | 0 | *namelen = strlen(signkey_names[type]); |
81 | 0 | } |
82 | 0 | return signkey_names[type]; |
83 | 0 | } |
84 | | |
85 | | /* Returns DROPBEAR_SIGNKEY_NONE if none match */ |
86 | 8 | enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) { |
87 | 8 | int i; |
88 | 26 | for (i = 0; i < DROPBEAR_SIGNKEY_NUM_NAMED; i++) { |
89 | 26 | const char *fixed_name = signkey_names[i]; |
90 | 26 | if (namelen == strlen(fixed_name) |
91 | 26 | && memcmp(fixed_name, name, namelen) == 0) { |
92 | | |
93 | 8 | #if DROPBEAR_ECDSA |
94 | | /* Some of the ECDSA key sizes are defined even if they're not compiled in */ |
95 | 8 | if (0 |
96 | | #if !DROPBEAR_ECC_256 |
97 | | || i == DROPBEAR_SIGNKEY_ECDSA_NISTP256 |
98 | | #endif |
99 | | #if !DROPBEAR_ECC_384 |
100 | | || i == DROPBEAR_SIGNKEY_ECDSA_NISTP384 |
101 | | #endif |
102 | | #if !DROPBEAR_ECC_521 |
103 | | || i == DROPBEAR_SIGNKEY_ECDSA_NISTP521 |
104 | | #endif |
105 | 8 | ) { |
106 | 0 | TRACE(("attempt to use ecdsa type %d not compiled in", i)) |
107 | 0 | return DROPBEAR_SIGNKEY_NONE; |
108 | 0 | } |
109 | 8 | #endif |
110 | | |
111 | 8 | return (enum signkey_type)i; |
112 | 8 | } |
113 | 26 | } |
114 | | |
115 | 0 | TRACE(("signkey_type_from_name unexpected key type.")) |
116 | | |
117 | 0 | return DROPBEAR_SIGNKEY_NONE; |
118 | 8 | } |
119 | | |
120 | | /* Special case for rsa-sha2-256. This could be generalised if more |
121 | | signature names are added that aren't 1-1 with public key names */ |
122 | 0 | const char* signature_name_from_type(enum signature_type type, unsigned int *namelen) { |
123 | 0 | #if DROPBEAR_RSA |
124 | 0 | #if DROPBEAR_RSA_SHA256 |
125 | 0 | if (type == DROPBEAR_SIGNATURE_RSA_SHA256) { |
126 | 0 | if (namelen) { |
127 | 0 | *namelen = strlen(SSH_SIGNATURE_RSA_SHA256); |
128 | 0 | } |
129 | 0 | return SSH_SIGNATURE_RSA_SHA256; |
130 | 0 | } |
131 | 0 | #endif |
132 | 0 | #if DROPBEAR_RSA_SHA1 |
133 | 0 | if (type == DROPBEAR_SIGNATURE_RSA_SHA1) { |
134 | 0 | if (namelen) { |
135 | 0 | *namelen = strlen(SSH_SIGNKEY_RSA); |
136 | 0 | } |
137 | 0 | return SSH_SIGNKEY_RSA; |
138 | 0 | } |
139 | 0 | #endif |
140 | 0 | #endif /* DROPBEAR_RSA */ |
141 | 0 | return signkey_name_from_type((enum signkey_type)type, namelen); |
142 | 0 | } |
143 | | |
144 | | /* Returns DROPBEAR_SIGNATURE_NONE if none match */ |
145 | 0 | enum signature_type signature_type_from_name(const char* name, unsigned int namelen) { |
146 | 0 | #if DROPBEAR_RSA |
147 | 0 | #if DROPBEAR_RSA_SHA256 |
148 | 0 | if (namelen == strlen(SSH_SIGNATURE_RSA_SHA256) |
149 | 0 | && memcmp(name, SSH_SIGNATURE_RSA_SHA256, namelen) == 0) { |
150 | 0 | return DROPBEAR_SIGNATURE_RSA_SHA256; |
151 | 0 | } |
152 | 0 | #endif |
153 | 0 | #if DROPBEAR_RSA_SHA1 |
154 | 0 | if (namelen == strlen(SSH_SIGNKEY_RSA) |
155 | 0 | && memcmp(name, SSH_SIGNKEY_RSA, namelen) == 0) { |
156 | 0 | return DROPBEAR_SIGNATURE_RSA_SHA1; |
157 | 0 | } |
158 | 0 | #endif |
159 | 0 | #endif /* DROPBEAR_RSA */ |
160 | 0 | return (enum signature_type)signkey_type_from_name(name, namelen); |
161 | 0 | } |
162 | | |
163 | | /* Returns the signature type from a key type. Must not be called |
164 | | with RSA keytype */ |
165 | 0 | enum signature_type signature_type_from_signkey(enum signkey_type keytype) { |
166 | 0 | #if DROPBEAR_RSA |
167 | 0 | assert(keytype != DROPBEAR_SIGNKEY_RSA); |
168 | 0 | #endif |
169 | 0 | assert(keytype < DROPBEAR_SIGNKEY_NUM_NAMED); |
170 | 0 | return (enum signature_type)keytype; |
171 | 0 | } |
172 | | |
173 | 0 | enum signkey_type signkey_type_from_signature(enum signature_type sigtype) { |
174 | 0 | #if DROPBEAR_RSA |
175 | 0 | #if DROPBEAR_RSA_SHA256 |
176 | 0 | if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA256) { |
177 | 0 | return DROPBEAR_SIGNKEY_RSA; |
178 | 0 | } |
179 | 0 | #endif |
180 | 0 | #if DROPBEAR_RSA_SHA1 |
181 | 0 | if (sigtype == DROPBEAR_SIGNATURE_RSA_SHA1) { |
182 | 0 | return DROPBEAR_SIGNKEY_RSA; |
183 | 0 | } |
184 | 0 | #endif |
185 | 0 | #endif /* DROPBEAR_RSA */ |
186 | 0 | assert((int)sigtype < (int)DROPBEAR_SIGNKEY_NUM_NAMED); |
187 | 0 | return (enum signkey_type)sigtype; |
188 | 0 | } |
189 | | |
190 | | /* Returns a pointer to the key part specific to "type". |
191 | | Be sure to check both (ret != NULL) and (*ret != NULL) */ |
192 | | void ** |
193 | 180 | signkey_key_ptr(sign_key *key, enum signkey_type type) { |
194 | 180 | switch (type) { |
195 | 0 | #if DROPBEAR_ED25519 |
196 | 0 | case DROPBEAR_SIGNKEY_ED25519: |
197 | 0 | #if DROPBEAR_SK_ED25519 |
198 | 0 | case DROPBEAR_SIGNKEY_SK_ED25519: |
199 | 0 | #endif |
200 | 0 | return (void**)&key->ed25519key; |
201 | 0 | #endif |
202 | 0 | #if DROPBEAR_ECDSA |
203 | 0 | #if DROPBEAR_ECC_256 |
204 | 180 | case DROPBEAR_SIGNKEY_ECDSA_NISTP256: |
205 | 180 | #if DROPBEAR_SK_ECDSA |
206 | 180 | case DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256: |
207 | 180 | #endif |
208 | 180 | return (void**)&key->ecckey256; |
209 | 0 | #endif |
210 | 0 | #if DROPBEAR_ECC_384 |
211 | 0 | case DROPBEAR_SIGNKEY_ECDSA_NISTP384: |
212 | 0 | return (void**)&key->ecckey384; |
213 | 0 | #endif |
214 | 0 | #if DROPBEAR_ECC_521 |
215 | 0 | case DROPBEAR_SIGNKEY_ECDSA_NISTP521: |
216 | 0 | return (void**)&key->ecckey521; |
217 | 0 | #endif |
218 | 0 | #endif /* DROPBEAR_ECDSA */ |
219 | 0 | #if DROPBEAR_RSA |
220 | 0 | case DROPBEAR_SIGNKEY_RSA: |
221 | 0 | return (void**)&key->rsakey; |
222 | 0 | #endif |
223 | 0 | #if DROPBEAR_DSS |
224 | 0 | case DROPBEAR_SIGNKEY_DSS: |
225 | 0 | return (void**)&key->dsskey; |
226 | 0 | #endif |
227 | 0 | default: |
228 | 0 | return NULL; |
229 | 180 | } |
230 | 180 | } |
231 | | |
232 | | /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail. |
233 | | * type should be set by the caller to specify the type to read, and |
234 | | * on return is set to the type read (useful when type = _ANY) */ |
235 | 0 | int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) { |
236 | |
|
237 | 0 | char *ident; |
238 | 0 | unsigned int len; |
239 | 0 | enum signkey_type keytype; |
240 | 0 | int ret = DROPBEAR_FAILURE; |
241 | |
|
242 | 0 | TRACE2(("enter buf_get_pub_key")) |
243 | |
|
244 | 0 | ident = buf_getstring(buf, &len); |
245 | 0 | keytype = signkey_type_from_name(ident, len); |
246 | 0 | m_free(ident); |
247 | |
|
248 | 0 | if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) { |
249 | 0 | TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, *type)) |
250 | 0 | return DROPBEAR_FAILURE; |
251 | 0 | } |
252 | | |
253 | 0 | TRACE2(("buf_get_pub_key keytype is %d", keytype)) |
254 | | |
255 | 0 | *type = keytype; |
256 | | |
257 | | /* Rewind the buffer back before "ssh-rsa" etc */ |
258 | 0 | buf_decrpos(buf, len + 4); |
259 | |
|
260 | 0 | #if DROPBEAR_DSS |
261 | 0 | if (keytype == DROPBEAR_SIGNKEY_DSS) { |
262 | 0 | dss_key_free(key->dsskey); |
263 | 0 | key->dsskey = m_malloc(sizeof(*key->dsskey)); |
264 | 0 | ret = buf_get_dss_pub_key(buf, key->dsskey); |
265 | 0 | if (ret == DROPBEAR_FAILURE) { |
266 | 0 | dss_key_free(key->dsskey); |
267 | 0 | key->dsskey = NULL; |
268 | 0 | } |
269 | 0 | } |
270 | 0 | #endif |
271 | 0 | #if DROPBEAR_RSA |
272 | 0 | if (keytype == DROPBEAR_SIGNKEY_RSA) { |
273 | 0 | rsa_key_free(key->rsakey); |
274 | 0 | key->rsakey = m_malloc(sizeof(*key->rsakey)); |
275 | 0 | ret = buf_get_rsa_pub_key(buf, key->rsakey); |
276 | 0 | if (ret == DROPBEAR_FAILURE) { |
277 | 0 | rsa_key_free(key->rsakey); |
278 | 0 | key->rsakey = NULL; |
279 | 0 | } |
280 | 0 | } |
281 | 0 | #endif |
282 | 0 | #if DROPBEAR_ECDSA |
283 | 0 | if (signkey_is_ecdsa(keytype) |
284 | 0 | #if DROPBEAR_SK_ECDSA |
285 | 0 | || keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256 |
286 | 0 | #endif |
287 | 0 | ) { |
288 | 0 | ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); |
289 | 0 | if (eck) { |
290 | 0 | if (*eck) { |
291 | 0 | ecc_free(*eck); |
292 | 0 | m_free(*eck); |
293 | 0 | *eck = NULL; |
294 | 0 | } |
295 | 0 | *eck = buf_get_ecdsa_pub_key(buf); |
296 | 0 | if (*eck) { |
297 | 0 | ret = DROPBEAR_SUCCESS; |
298 | 0 | } |
299 | 0 | } |
300 | 0 | } |
301 | 0 | #endif |
302 | 0 | #if DROPBEAR_ED25519 |
303 | 0 | if (keytype == DROPBEAR_SIGNKEY_ED25519 |
304 | 0 | #if DROPBEAR_SK_ED25519 |
305 | 0 | || keytype == DROPBEAR_SIGNKEY_SK_ED25519 |
306 | 0 | #endif |
307 | 0 | ) { |
308 | 0 | ed25519_key_free(key->ed25519key); |
309 | 0 | key->ed25519key = m_malloc(sizeof(*key->ed25519key)); |
310 | 0 | ret = buf_get_ed25519_pub_key(buf, key->ed25519key, keytype); |
311 | 0 | if (ret == DROPBEAR_FAILURE) { |
312 | 0 | m_free(key->ed25519key); |
313 | 0 | key->ed25519key = NULL; |
314 | 0 | } |
315 | 0 | } |
316 | 0 | #endif |
317 | |
|
318 | 0 | #if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519 |
319 | 0 | if (0 |
320 | 0 | #if DROPBEAR_SK_ED25519 |
321 | 0 | || keytype == DROPBEAR_SIGNKEY_SK_ED25519 |
322 | 0 | #endif |
323 | 0 | #if DROPBEAR_SK_ECDSA |
324 | 0 | || keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256 |
325 | 0 | #endif |
326 | 0 | ) { |
327 | 0 | key->sk_app = buf_getstring(buf, &key->sk_applen); |
328 | 0 | } |
329 | 0 | #endif |
330 | |
|
331 | 0 | TRACE2(("leave buf_get_pub_key")) |
332 | |
|
333 | 0 | return ret; |
334 | 0 | } |
335 | | |
336 | | /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail. |
337 | | * type should be set by the caller to specify the type to read, and |
338 | | * on return is set to the type read (useful when type = _ANY) */ |
339 | 8 | int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) { |
340 | | |
341 | 8 | char *ident; |
342 | 8 | unsigned int len; |
343 | 8 | enum signkey_type keytype; |
344 | 8 | int ret = DROPBEAR_FAILURE; |
345 | | |
346 | 8 | TRACE2(("enter buf_get_priv_key")) |
347 | | |
348 | 8 | ident = buf_getstring(buf, &len); |
349 | 8 | keytype = signkey_type_from_name(ident, len); |
350 | 8 | m_free(ident); |
351 | | |
352 | 8 | if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) { |
353 | 0 | TRACE(("wrong key type: %d %d", *type, keytype)) |
354 | 0 | return DROPBEAR_FAILURE; |
355 | 0 | } |
356 | | |
357 | 8 | *type = keytype; |
358 | | |
359 | | /* Rewind the buffer back before "ssh-rsa" etc */ |
360 | 8 | buf_decrpos(buf, len + 4); |
361 | | |
362 | 8 | #if DROPBEAR_DSS |
363 | 8 | if (keytype == DROPBEAR_SIGNKEY_DSS) { |
364 | 2 | dss_key_free(key->dsskey); |
365 | 2 | key->dsskey = m_malloc(sizeof(*key->dsskey)); |
366 | 2 | ret = buf_get_dss_priv_key(buf, key->dsskey); |
367 | 2 | if (ret == DROPBEAR_FAILURE) { |
368 | 0 | dss_key_free(key->dsskey); |
369 | 0 | key->dsskey = NULL; |
370 | 0 | } |
371 | 2 | } |
372 | 8 | #endif |
373 | 8 | #if DROPBEAR_RSA |
374 | 8 | if (keytype == DROPBEAR_SIGNKEY_RSA) { |
375 | 2 | rsa_key_free(key->rsakey); |
376 | 2 | key->rsakey = m_malloc(sizeof(*key->rsakey)); |
377 | 2 | ret = buf_get_rsa_priv_key(buf, key->rsakey); |
378 | 2 | if (ret == DROPBEAR_FAILURE) { |
379 | 0 | rsa_key_free(key->rsakey); |
380 | 0 | key->rsakey = NULL; |
381 | 0 | } |
382 | 2 | } |
383 | 8 | #endif |
384 | 8 | #if DROPBEAR_ECDSA |
385 | 8 | if (signkey_is_ecdsa(keytype)) { |
386 | 2 | ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); |
387 | 2 | if (eck) { |
388 | 2 | if (*eck) { |
389 | 0 | ecc_free(*eck); |
390 | 0 | m_free(*eck); |
391 | 0 | *eck = NULL; |
392 | 0 | } |
393 | 2 | *eck = buf_get_ecdsa_priv_key(buf); |
394 | 2 | if (*eck) { |
395 | 2 | ret = DROPBEAR_SUCCESS; |
396 | 2 | } |
397 | 2 | } |
398 | 2 | } |
399 | 8 | #endif |
400 | 8 | #if DROPBEAR_ED25519 |
401 | 8 | if (keytype == DROPBEAR_SIGNKEY_ED25519) { |
402 | 2 | ed25519_key_free(key->ed25519key); |
403 | 2 | key->ed25519key = m_malloc(sizeof(*key->ed25519key)); |
404 | 2 | ret = buf_get_ed25519_priv_key(buf, key->ed25519key); |
405 | 2 | if (ret == DROPBEAR_FAILURE) { |
406 | 0 | m_free(key->ed25519key); |
407 | 0 | key->ed25519key = NULL; |
408 | 0 | } |
409 | 2 | } |
410 | 8 | #endif |
411 | | |
412 | 8 | TRACE2(("leave buf_get_priv_key")) |
413 | | |
414 | 8 | return ret; |
415 | | |
416 | 8 | } |
417 | | |
418 | | /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */ |
419 | 178 | void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) { |
420 | | |
421 | 178 | buffer *pubkeys; |
422 | | |
423 | 178 | TRACE2(("enter buf_put_pub_key")) |
424 | 178 | pubkeys = buf_new(MAX_PUBKEY_SIZE); |
425 | | |
426 | 178 | #if DROPBEAR_DSS |
427 | 178 | if (type == DROPBEAR_SIGNKEY_DSS) { |
428 | 0 | buf_put_dss_pub_key(pubkeys, key->dsskey); |
429 | 0 | } |
430 | 178 | #endif |
431 | 178 | #if DROPBEAR_RSA |
432 | 178 | if (type == DROPBEAR_SIGNKEY_RSA) { |
433 | 0 | buf_put_rsa_pub_key(pubkeys, key->rsakey); |
434 | 0 | } |
435 | 178 | #endif |
436 | 178 | #if DROPBEAR_ECDSA |
437 | 178 | if (signkey_is_ecdsa(type)) { |
438 | 178 | ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type); |
439 | 178 | if (eck && *eck) { |
440 | 178 | buf_put_ecdsa_pub_key(pubkeys, *eck); |
441 | 178 | } |
442 | 178 | } |
443 | 178 | #endif |
444 | 178 | #if DROPBEAR_ED25519 |
445 | 178 | if (type == DROPBEAR_SIGNKEY_ED25519 |
446 | 178 | #if DROPBEAR_SK_ED25519 |
447 | 178 | || type == DROPBEAR_SIGNKEY_SK_ED25519 |
448 | 178 | #endif |
449 | 178 | ) { |
450 | 0 | buf_put_ed25519_pub_key(pubkeys, key->ed25519key); |
451 | 0 | } |
452 | 178 | #endif |
453 | 178 | if (pubkeys->len == 0) { |
454 | 0 | dropbear_exit("Bad key types in buf_put_pub_key"); |
455 | 0 | } |
456 | | |
457 | 178 | buf_putbufstring(buf, pubkeys); |
458 | 178 | buf_free(pubkeys); |
459 | 178 | TRACE2(("leave buf_put_pub_key")) |
460 | 178 | } |
461 | | |
462 | | /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */ |
463 | 0 | void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) { |
464 | |
|
465 | 0 | TRACE(("enter buf_put_priv_key")) |
466 | 0 | TRACE(("type is %d", type)) |
467 | |
|
468 | 0 | #if DROPBEAR_DSS |
469 | 0 | if (type == DROPBEAR_SIGNKEY_DSS) { |
470 | 0 | buf_put_dss_priv_key(buf, key->dsskey); |
471 | 0 | TRACE(("leave buf_put_priv_key: dss done")) |
472 | 0 | return; |
473 | 0 | } |
474 | 0 | #endif |
475 | 0 | #if DROPBEAR_RSA |
476 | 0 | if (type == DROPBEAR_SIGNKEY_RSA) { |
477 | 0 | buf_put_rsa_priv_key(buf, key->rsakey); |
478 | 0 | TRACE(("leave buf_put_priv_key: rsa done")) |
479 | 0 | return; |
480 | 0 | } |
481 | 0 | #endif |
482 | 0 | #if DROPBEAR_ECDSA |
483 | 0 | if (signkey_is_ecdsa(type)) { |
484 | 0 | ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type); |
485 | 0 | if (eck && *eck) { |
486 | 0 | buf_put_ecdsa_priv_key(buf, *eck); |
487 | 0 | TRACE(("leave buf_put_priv_key: ecdsa done")) |
488 | 0 | return; |
489 | 0 | } |
490 | 0 | } |
491 | 0 | #endif |
492 | 0 | #if DROPBEAR_ED25519 |
493 | 0 | if (type == DROPBEAR_SIGNKEY_ED25519) { |
494 | 0 | buf_put_ed25519_priv_key(buf, key->ed25519key); |
495 | 0 | TRACE(("leave buf_put_priv_key: ed25519 done")) |
496 | 0 | return; |
497 | 0 | } |
498 | 0 | #endif |
499 | 0 | dropbear_exit("Bad key types in put pub key"); |
500 | 0 | } |
501 | | |
502 | 0 | void sign_key_free(sign_key *key) { |
503 | |
|
504 | 0 | TRACE2(("enter sign_key_free")) |
505 | |
|
506 | 0 | #if DROPBEAR_DSS |
507 | 0 | dss_key_free(key->dsskey); |
508 | 0 | key->dsskey = NULL; |
509 | 0 | #endif |
510 | 0 | #if DROPBEAR_RSA |
511 | 0 | rsa_key_free(key->rsakey); |
512 | 0 | key->rsakey = NULL; |
513 | 0 | #endif |
514 | 0 | #if DROPBEAR_ECDSA |
515 | 0 | #if DROPBEAR_ECC_256 |
516 | 0 | if (key->ecckey256) { |
517 | 0 | ecc_free(key->ecckey256); |
518 | 0 | m_free(key->ecckey256); |
519 | 0 | key->ecckey256 = NULL; |
520 | 0 | } |
521 | 0 | #endif |
522 | 0 | #if DROPBEAR_ECC_384 |
523 | 0 | if (key->ecckey384) { |
524 | 0 | ecc_free(key->ecckey384); |
525 | 0 | m_free(key->ecckey384); |
526 | 0 | key->ecckey384 = NULL; |
527 | 0 | } |
528 | 0 | #endif |
529 | 0 | #if DROPBEAR_ECC_521 |
530 | 0 | if (key->ecckey521) { |
531 | 0 | ecc_free(key->ecckey521); |
532 | 0 | m_free(key->ecckey521); |
533 | 0 | key->ecckey521 = NULL; |
534 | 0 | } |
535 | 0 | #endif |
536 | 0 | #endif |
537 | 0 | #if DROPBEAR_ED25519 |
538 | 0 | ed25519_key_free(key->ed25519key); |
539 | 0 | key->ed25519key = NULL; |
540 | 0 | #endif |
541 | |
|
542 | 0 | m_free(key->filename); |
543 | 0 | #if DROPBEAR_SK_ECDSA || DROPBEAR_SK_ED25519 |
544 | 0 | if (key->sk_app) { |
545 | 0 | m_free(key->sk_app); |
546 | 0 | } |
547 | 0 | #endif |
548 | |
|
549 | 0 | m_free(key); |
550 | 0 | TRACE2(("leave sign_key_free")) |
551 | 0 | } |
552 | | |
553 | | static char * sign_key_sha256_fingerprint(const unsigned char* keyblob, |
554 | 0 | unsigned int keybloblen) { |
555 | |
|
556 | 0 | char * ret; |
557 | 0 | hash_state hs; |
558 | 0 | unsigned char hash[SHA256_HASH_SIZE]; |
559 | 0 | unsigned int b64chars, start; |
560 | 0 | unsigned long b64size; |
561 | 0 | const char *prefix = "SHA256:"; |
562 | 0 | int err; |
563 | |
|
564 | 0 | sha256_init(&hs); |
565 | 0 | sha256_process(&hs, keyblob, keybloblen); |
566 | 0 | sha256_done(&hs, hash); |
567 | | |
568 | | /* eg "SHA256:P9szN0L2ls6KxkVv7Bppv3asnZCn03rY7Msm/c8+ZgA" |
569 | | * 256/6 = 42.66 => 43 base64 chars. OpenSSH discards |
570 | | * base64 padding output. */ |
571 | 0 | start = strlen(prefix); |
572 | 0 | b64chars = 43; |
573 | | /* space for discarded b64 padding and null terminator */ |
574 | 0 | b64size = b64chars + 4; |
575 | 0 | ret = m_malloc(start + b64size); |
576 | |
|
577 | 0 | memcpy(ret, prefix, start); |
578 | 0 | err = base64_encode(hash, SHA256_HASH_SIZE, &ret[start], &b64size); |
579 | 0 | if (err != CRYPT_OK) { |
580 | 0 | dropbear_exit("base64 failed"); |
581 | 0 | } |
582 | 0 | ret[start + b64chars] = '\0'; |
583 | 0 | return ret; |
584 | 0 | } |
585 | | |
586 | | /* This will return a freshly malloced string */ |
587 | 0 | char * sign_key_fingerprint(const unsigned char* keyblob, unsigned int keybloblen) { |
588 | 0 | return sign_key_sha256_fingerprint(keyblob, keybloblen); |
589 | 0 | } |
590 | | |
591 | | void buf_put_sign(buffer* buf, sign_key *key, enum signature_type sigtype, |
592 | 0 | const buffer *data_buf) { |
593 | 0 | buffer *sigblob = buf_new(MAX_PUBKEY_SIZE); |
594 | 0 | enum signkey_type keytype = signkey_type_from_signature(sigtype); |
595 | |
|
596 | | #if DEBUG_TRACE > DROPBEAR_VERBOSE_LEVEL |
597 | | { |
598 | | const char* signame = signature_name_from_type(sigtype, NULL); |
599 | | TRACE(("buf_put_sign type %d %s", sigtype, signame)); |
600 | | } |
601 | | #endif |
602 | | |
603 | |
|
604 | 0 | #if DROPBEAR_DSS |
605 | 0 | if (keytype == DROPBEAR_SIGNKEY_DSS) { |
606 | 0 | buf_put_dss_sign(sigblob, key->dsskey, data_buf); |
607 | 0 | } |
608 | 0 | #endif |
609 | 0 | #if DROPBEAR_RSA |
610 | 0 | if (keytype == DROPBEAR_SIGNKEY_RSA) { |
611 | 0 | buf_put_rsa_sign(sigblob, key->rsakey, sigtype, data_buf); |
612 | 0 | } |
613 | 0 | #endif |
614 | 0 | #if DROPBEAR_ECDSA |
615 | 0 | if (signkey_is_ecdsa(keytype)) { |
616 | 0 | ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); |
617 | 0 | if (eck && *eck) { |
618 | 0 | buf_put_ecdsa_sign(sigblob, *eck, data_buf); |
619 | 0 | } |
620 | 0 | } |
621 | 0 | #endif |
622 | 0 | #if DROPBEAR_ED25519 |
623 | 0 | if (keytype == DROPBEAR_SIGNKEY_ED25519) { |
624 | 0 | buf_put_ed25519_sign(sigblob, key->ed25519key, data_buf); |
625 | 0 | } |
626 | 0 | #endif |
627 | 0 | if (sigblob->len == 0) { |
628 | 0 | dropbear_exit("Non-matching signing type"); |
629 | 0 | } |
630 | 0 | buf_putbufstring(buf, sigblob); |
631 | 0 | buf_free(sigblob); |
632 | |
|
633 | 0 | } |
634 | | |
635 | | #if DROPBEAR_SIGNKEY_VERIFY |
636 | | |
637 | | /* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE. |
638 | | * If FAILURE is returned, the position of |
639 | | * buf is undefined. If SUCCESS is returned, buf will be positioned after the |
640 | | * signature blob */ |
641 | 0 | int buf_verify(buffer * buf, sign_key *key, enum signature_type expect_sigtype, const buffer *data_buf) { |
642 | | |
643 | 0 | char *type_name = NULL; |
644 | 0 | unsigned int type_name_len = 0; |
645 | 0 | enum signature_type sigtype; |
646 | 0 | enum signkey_type keytype; |
647 | |
|
648 | 0 | TRACE(("enter buf_verify")) |
649 | |
|
650 | 0 | buf_getint(buf); /* blob length */ |
651 | 0 | type_name = buf_getstring(buf, &type_name_len); |
652 | 0 | sigtype = signature_type_from_name(type_name, type_name_len); |
653 | 0 | m_free(type_name); |
654 | |
|
655 | 0 | if (expect_sigtype != sigtype) { |
656 | 0 | dropbear_exit("Non-matching signing type"); |
657 | 0 | } |
658 | | |
659 | 0 | keytype = signkey_type_from_signature(sigtype); |
660 | 0 | #if DROPBEAR_DSS |
661 | 0 | if (keytype == DROPBEAR_SIGNKEY_DSS) { |
662 | 0 | if (key->dsskey == NULL) { |
663 | 0 | dropbear_exit("No DSS key to verify signature"); |
664 | 0 | } |
665 | 0 | return buf_dss_verify(buf, key->dsskey, data_buf); |
666 | 0 | } |
667 | 0 | #endif |
668 | | |
669 | 0 | #if DROPBEAR_RSA |
670 | 0 | if (keytype == DROPBEAR_SIGNKEY_RSA) { |
671 | 0 | if (key->rsakey == NULL) { |
672 | 0 | dropbear_exit("No RSA key to verify signature"); |
673 | 0 | } |
674 | 0 | return buf_rsa_verify(buf, key->rsakey, sigtype, data_buf); |
675 | 0 | } |
676 | 0 | #endif |
677 | 0 | #if DROPBEAR_ECDSA |
678 | 0 | if (signkey_is_ecdsa(keytype)) { |
679 | 0 | ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); |
680 | 0 | if (eck && *eck) { |
681 | 0 | return buf_ecdsa_verify(buf, *eck, data_buf); |
682 | 0 | } |
683 | 0 | } |
684 | 0 | #endif |
685 | 0 | #if DROPBEAR_ED25519 |
686 | 0 | if (keytype == DROPBEAR_SIGNKEY_ED25519) { |
687 | 0 | if (key->ed25519key == NULL) { |
688 | 0 | dropbear_exit("No Ed25519 key to verify signature"); |
689 | 0 | } |
690 | 0 | return buf_ed25519_verify(buf, key->ed25519key, data_buf); |
691 | 0 | } |
692 | 0 | #endif |
693 | 0 | #if DROPBEAR_SK_ECDSA |
694 | 0 | if (keytype == DROPBEAR_SIGNKEY_SK_ECDSA_NISTP256) { |
695 | 0 | ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype); |
696 | 0 | if (eck && *eck) { |
697 | 0 | return buf_sk_ecdsa_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen, key->sk_flags_mask); |
698 | 0 | } |
699 | 0 | } |
700 | 0 | #endif |
701 | 0 | #if DROPBEAR_SK_ED25519 |
702 | 0 | if (keytype == DROPBEAR_SIGNKEY_SK_ED25519) { |
703 | 0 | dropbear_ed25519_key **eck = (dropbear_ed25519_key**)signkey_key_ptr(key, keytype); |
704 | 0 | if (eck && *eck) { |
705 | 0 | return buf_sk_ed25519_verify(buf, *eck, data_buf, key->sk_app, key->sk_applen, key->sk_flags_mask); |
706 | 0 | } |
707 | 0 | } |
708 | 0 | #endif |
709 | | |
710 | 0 | dropbear_exit("Non-matching signing type"); |
711 | 0 | return DROPBEAR_FAILURE; |
712 | 0 | } |
713 | | #endif /* DROPBEAR_SIGNKEY_VERIFY */ |
714 | | |
715 | | #if DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */ |
716 | | |
717 | | /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing |
718 | | * a key, a key, and a type. The buffer is positioned at the start of the |
719 | | * base64 data, and contains no trailing data */ |
720 | | /* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint |
721 | | of the key if it is successfully decoded */ |
722 | | int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, |
723 | | const unsigned char* algoname, unsigned int algolen, |
724 | 0 | const buffer * line, char ** fingerprint) { |
725 | |
|
726 | 0 | buffer * decodekey = NULL; |
727 | 0 | int ret = DROPBEAR_FAILURE; |
728 | 0 | unsigned int len, filealgolen; |
729 | 0 | unsigned long decodekeylen; |
730 | 0 | unsigned char* filealgo = NULL; |
731 | | |
732 | | /* now we have the actual data */ |
733 | 0 | len = line->len - line->pos; |
734 | 0 | if (len == 0) { |
735 | | /* base64_decode doesn't like NULL argument */ |
736 | 0 | return DROPBEAR_FAILURE; |
737 | 0 | } |
738 | 0 | decodekeylen = len * 2; /* big to be safe */ |
739 | 0 | decodekey = buf_new(decodekeylen); |
740 | |
|
741 | 0 | if (base64_decode(buf_getptr(line, len), len, |
742 | 0 | buf_getwriteptr(decodekey, decodekey->size), |
743 | 0 | &decodekeylen) != CRYPT_OK) { |
744 | 0 | TRACE(("checkpubkey: base64 decode failed")) |
745 | 0 | goto out; |
746 | 0 | } |
747 | 0 | TRACE(("checkpubkey: base64_decode success")) |
748 | 0 | buf_incrlen(decodekey, decodekeylen); |
749 | | |
750 | 0 | if (fingerprint) { |
751 | 0 | *fingerprint = sign_key_fingerprint(buf_getptr(decodekey, decodekeylen), |
752 | 0 | decodekeylen); |
753 | 0 | } |
754 | | |
755 | | /* compare the keys */ |
756 | 0 | if ( ( decodekeylen != keybloblen ) |
757 | 0 | || memcmp( buf_getptr(decodekey, decodekey->len), |
758 | 0 | keyblob, decodekey->len) != 0) { |
759 | 0 | TRACE(("checkpubkey: compare failed")) |
760 | 0 | goto out; |
761 | 0 | } |
762 | | |
763 | | /* ... and also check that the algo specified and the algo in the key |
764 | | * itself match */ |
765 | 0 | filealgolen = buf_getint(decodekey); |
766 | 0 | filealgo = buf_getptr(decodekey, filealgolen); |
767 | 0 | if (filealgolen != algolen || memcmp(filealgo, algoname, algolen) != 0) { |
768 | 0 | TRACE(("checkpubkey: algo match failed")) |
769 | 0 | goto out; |
770 | 0 | } |
771 | | |
772 | | /* All checks passed */ |
773 | 0 | ret = DROPBEAR_SUCCESS; |
774 | |
|
775 | 0 | out: |
776 | 0 | buf_free(decodekey); |
777 | 0 | decodekey = NULL; |
778 | 0 | return ret; |
779 | 0 | } |
780 | | #endif |
781 | | |
782 | | #if DROPBEAR_FUZZ |
783 | | const char * const * fuzz_signkey_names = signkey_names; |
784 | | |
785 | | #endif |