dropbear: update to 2013.62
[tomato.git] / release / src / router / dropbear / signkey.c
blob4ac40cbebf063d28ebe3c543246bf7e405f68b98
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:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
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. */
25 #include "includes.h"
26 #include "dbutil.h"
27 #include "signkey.h"
28 #include "buffer.h"
29 #include "ssh.h"
30 #include "ecdsa.h"
32 static const char *signkey_names[DROPBEAR_SIGNKEY_NUM_NAMED] = {
33 #ifdef DROPBEAR_RSA
34 "ssh-rsa",
35 #endif
36 #ifdef DROPBEAR_DSS
37 "ssh-dss",
38 #endif
39 #ifdef DROPBEAR_ECDSA
40 "ecdsa-sha2-nistp256",
41 "ecdsa-sha2-nistp384",
42 "ecdsa-sha2-nistp521"
43 #endif /* DROPBEAR_ECDSA */
46 /* malloc a new sign_key and set the dss and rsa keys to NULL */
47 sign_key * new_sign_key() {
49 sign_key * ret;
51 ret = (sign_key*)m_malloc(sizeof(sign_key));
52 ret->type = DROPBEAR_SIGNKEY_NONE;
53 ret->source = SIGNKEY_SOURCE_INVALID;
54 return ret;
57 /* Returns key name corresponding to the type. Exits fatally
58 * if the type is invalid */
59 const char* signkey_name_from_type(enum signkey_type type, unsigned int *namelen) {
60 if (type >= DROPBEAR_SIGNKEY_NUM_NAMED) {
61 dropbear_exit("Bad key type %d", type);
64 if (namelen) {
65 *namelen = strlen(signkey_names[type]);
67 return signkey_names[type];
70 /* Returns DROPBEAR_SIGNKEY_NONE if none match */
71 enum signkey_type signkey_type_from_name(const char* name, unsigned int namelen) {
72 int i;
73 for (i = 0; i < DROPBEAR_SIGNKEY_NUM_NAMED; i++) {
74 const char *fixed_name = signkey_names[i];
75 if (namelen == strlen(fixed_name)
76 && memcmp(fixed_name, name, namelen) == 0) {
78 #ifdef DROPBEAR_ECDSA
79 /* Some of the ECDSA key sizes are defined even if they're not compiled in */
80 if (0
81 #ifndef DROPBEAR_ECC_256
82 || i == DROPBEAR_SIGNKEY_ECDSA_NISTP256
83 #endif
84 #ifndef DROPBEAR_ECC_384
85 || i == DROPBEAR_SIGNKEY_ECDSA_NISTP384
86 #endif
87 #ifndef DROPBEAR_ECC_521
88 || i == DROPBEAR_SIGNKEY_ECDSA_NISTP521
89 #endif
90 ) {
91 TRACE(("attempt to use ecdsa type %d not compiled in", i))
92 return DROPBEAR_SIGNKEY_NONE;
94 #endif
96 return i;
100 TRACE(("signkey_type_from_name unexpected key type."))
102 return DROPBEAR_SIGNKEY_NONE;
105 /* Returns a pointer to the key part specific to "type" */
106 void **
107 signkey_key_ptr(sign_key *key, enum signkey_type type) {
108 switch (type) {
109 #ifdef DROPBEAR_ECC_256
110 case DROPBEAR_SIGNKEY_ECDSA_NISTP256:
111 return (void**)&key->ecckey256;
112 #endif
113 #ifdef DROPBEAR_ECC_384
114 case DROPBEAR_SIGNKEY_ECDSA_NISTP384:
115 return (void**)&key->ecckey384;
116 #endif
117 #ifdef DROPBEAR_ECC_521
118 case DROPBEAR_SIGNKEY_ECDSA_NISTP521:
119 return (void**)&key->ecckey521;
120 #endif
121 #ifdef DROPBEAR_RSA
122 case DROPBEAR_SIGNKEY_RSA:
123 return (void**)&key->rsakey;
124 #endif
125 #ifdef DROPBEAR_DSS
126 case DROPBEAR_SIGNKEY_DSS:
127 return (void**)&key->dsskey;
128 #endif
129 default:
130 return NULL;
134 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
135 * type should be set by the caller to specify the type to read, and
136 * on return is set to the type read (useful when type = _ANY) */
137 int buf_get_pub_key(buffer *buf, sign_key *key, enum signkey_type *type) {
139 unsigned char* ident;
140 unsigned int len;
141 int keytype;
142 int ret = DROPBEAR_FAILURE;
144 TRACE2(("enter buf_get_pub_key"))
146 ident = buf_getstring(buf, &len);
147 keytype = signkey_type_from_name(ident, len);
148 m_free(ident);
150 if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
151 TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype, *type))
152 return DROPBEAR_FAILURE;
155 TRACE2(("buf_get_pub_key keytype is %d", keytype))
157 *type = keytype;
159 /* Rewind the buffer back before "ssh-rsa" etc */
160 buf_incrpos(buf, -len - 4);
162 #ifdef DROPBEAR_DSS
163 if (keytype == DROPBEAR_SIGNKEY_DSS) {
164 dss_key_free(key->dsskey);
165 key->dsskey = m_malloc(sizeof(*key->dsskey));
166 ret = buf_get_dss_pub_key(buf, key->dsskey);
167 if (ret == DROPBEAR_FAILURE) {
168 m_free(key->dsskey);
171 #endif
172 #ifdef DROPBEAR_RSA
173 if (keytype == DROPBEAR_SIGNKEY_RSA) {
174 rsa_key_free(key->rsakey);
175 key->rsakey = m_malloc(sizeof(*key->rsakey));
176 ret = buf_get_rsa_pub_key(buf, key->rsakey);
177 if (ret == DROPBEAR_FAILURE) {
178 m_free(key->rsakey);
181 #endif
182 #ifdef DROPBEAR_ECDSA
183 if (signkey_is_ecdsa(keytype)) {
184 ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
185 if (eck) {
186 if (*eck) {
187 ecc_free(*eck);
188 *eck = NULL;
190 *eck = buf_get_ecdsa_pub_key(buf);
191 if (*eck) {
192 ret = DROPBEAR_SUCCESS;
196 #endif
198 TRACE2(("leave buf_get_pub_key"))
200 return ret;
204 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
205 * type should be set by the caller to specify the type to read, and
206 * on return is set to the type read (useful when type = _ANY) */
207 int buf_get_priv_key(buffer *buf, sign_key *key, enum signkey_type *type) {
209 unsigned char* ident;
210 unsigned int len;
211 int keytype;
212 int ret = DROPBEAR_FAILURE;
214 TRACE2(("enter buf_get_priv_key"))
216 ident = buf_getstring(buf, &len);
217 keytype = signkey_type_from_name(ident, len);
218 m_free(ident);
220 if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) {
221 TRACE(("wrong key type: %d %d", *type, keytype))
222 return DROPBEAR_FAILURE;
225 *type = keytype;
227 /* Rewind the buffer back before "ssh-rsa" etc */
228 buf_incrpos(buf, -len - 4);
230 #ifdef DROPBEAR_DSS
231 if (keytype == DROPBEAR_SIGNKEY_DSS) {
232 dss_key_free(key->dsskey);
233 key->dsskey = m_malloc(sizeof(*key->dsskey));
234 ret = buf_get_dss_priv_key(buf, key->dsskey);
235 if (ret == DROPBEAR_FAILURE) {
236 m_free(key->dsskey);
239 #endif
240 #ifdef DROPBEAR_RSA
241 if (keytype == DROPBEAR_SIGNKEY_RSA) {
242 rsa_key_free(key->rsakey);
243 key->rsakey = m_malloc(sizeof(*key->rsakey));
244 ret = buf_get_rsa_priv_key(buf, key->rsakey);
245 if (ret == DROPBEAR_FAILURE) {
246 m_free(key->rsakey);
249 #endif
250 #ifdef DROPBEAR_ECDSA
251 if (signkey_is_ecdsa(keytype)) {
252 ecc_key **eck = (ecc_key**)signkey_key_ptr(key, keytype);
253 if (eck) {
254 if (*eck) {
255 ecc_free(*eck);
256 *eck = NULL;
258 *eck = buf_get_ecdsa_priv_key(buf);
259 if (*eck) {
260 ret = DROPBEAR_SUCCESS;
264 #endif
266 TRACE2(("leave buf_get_priv_key"))
268 return ret;
272 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
273 void buf_put_pub_key(buffer* buf, sign_key *key, enum signkey_type type) {
275 buffer *pubkeys;
277 TRACE2(("enter buf_put_pub_key"))
278 pubkeys = buf_new(MAX_PUBKEY_SIZE);
280 #ifdef DROPBEAR_DSS
281 if (type == DROPBEAR_SIGNKEY_DSS) {
282 buf_put_dss_pub_key(pubkeys, key->dsskey);
284 #endif
285 #ifdef DROPBEAR_RSA
286 if (type == DROPBEAR_SIGNKEY_RSA) {
287 buf_put_rsa_pub_key(pubkeys, key->rsakey);
289 #endif
290 #ifdef DROPBEAR_ECDSA
291 if (signkey_is_ecdsa(type)) {
292 ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
293 if (eck) {
294 buf_put_ecdsa_pub_key(pubkeys, *eck);
297 #endif
298 if (pubkeys->len == 0) {
299 dropbear_exit("Bad key types in buf_put_pub_key");
302 buf_putbufstring(buf, pubkeys);
303 buf_free(pubkeys);
304 TRACE2(("leave buf_put_pub_key"))
307 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
308 void buf_put_priv_key(buffer* buf, sign_key *key, enum signkey_type type) {
310 TRACE(("enter buf_put_priv_key"))
311 TRACE(("type is %d", type))
313 #ifdef DROPBEAR_DSS
314 if (type == DROPBEAR_SIGNKEY_DSS) {
315 buf_put_dss_priv_key(buf, key->dsskey);
316 TRACE(("leave buf_put_priv_key: dss done"))
317 return;
319 #endif
320 #ifdef DROPBEAR_RSA
321 if (type == DROPBEAR_SIGNKEY_RSA) {
322 buf_put_rsa_priv_key(buf, key->rsakey);
323 TRACE(("leave buf_put_priv_key: rsa done"))
324 return;
326 #endif
327 #ifdef DROPBEAR_ECDSA
328 if (signkey_is_ecdsa(type)) {
329 ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
330 if (eck) {
331 buf_put_ecdsa_priv_key(buf, *eck);
332 TRACE(("leave buf_put_priv_key: ecdsa done"))
333 return;
336 #endif
337 dropbear_exit("Bad key types in put pub key");
340 void sign_key_free(sign_key *key) {
342 TRACE2(("enter sign_key_free"))
344 #ifdef DROPBEAR_DSS
345 dss_key_free(key->dsskey);
346 key->dsskey = NULL;
347 #endif
348 #ifdef DROPBEAR_RSA
349 rsa_key_free(key->rsakey);
350 key->rsakey = NULL;
351 #endif
352 #ifdef DROPBEAR_ECDSA
353 #ifdef DROPBEAR_ECC_256
354 if (key->ecckey256) {
355 ecc_free(key->ecckey256);
356 key->ecckey256 = NULL;
358 #endif
359 #ifdef DROPBEAR_ECC_384
360 if (key->ecckey384) {
361 ecc_free(key->ecckey384);
362 key->ecckey384 = NULL;
364 #endif
365 #ifdef DROPBEAR_ECC_521
366 if (key->ecckey521) {
367 ecc_free(key->ecckey521);
368 key->ecckey521 = NULL;
370 #endif
371 #endif
373 m_free(key->filename);
375 m_free(key);
376 TRACE2(("leave sign_key_free"))
379 static char hexdig(unsigned char x) {
380 if (x > 0xf)
381 return 'X';
383 if (x < 10)
384 return '0' + x;
385 else
386 return 'a' + x - 10;
389 /* Since we're not sure if we'll have md5 or sha1, we present both.
390 * MD5 is used in preference, but sha1 could still be useful */
391 #ifdef DROPBEAR_MD5_HMAC
392 static char * sign_key_md5_fingerprint(unsigned char* keyblob,
393 unsigned int keybloblen) {
395 char * ret;
396 hash_state hs;
397 unsigned char hash[MD5_HASH_SIZE];
398 unsigned int i;
399 unsigned int buflen;
401 md5_init(&hs);
403 /* skip the size int of the string - this is a bit messy */
404 md5_process(&hs, keyblob, keybloblen);
406 md5_done(&hs, hash);
408 /* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
409 buflen = 4 + 3*MD5_HASH_SIZE;
410 ret = (char*)m_malloc(buflen);
412 memset(ret, 'Z', buflen);
413 strcpy(ret, "md5 ");
415 for (i = 0; i < MD5_HASH_SIZE; i++) {
416 unsigned int pos = 4 + i*3;
417 ret[pos] = hexdig(hash[i] >> 4);
418 ret[pos+1] = hexdig(hash[i] & 0x0f);
419 ret[pos+2] = ':';
421 ret[buflen-1] = 0x0;
423 return ret;
426 #else /* use SHA1 rather than MD5 for fingerprint */
427 static char * sign_key_sha1_fingerprint(unsigned char* keyblob,
428 unsigned int keybloblen) {
430 char * ret;
431 hash_state hs;
432 unsigned char hash[SHA1_HASH_SIZE];
433 unsigned int i;
434 unsigned int buflen;
436 sha1_init(&hs);
438 /* skip the size int of the string - this is a bit messy */
439 sha1_process(&hs, keyblob, keybloblen);
441 sha1_done(&hs, hash);
443 /* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
444 buflen = 7 + 3*SHA1_HASH_SIZE;
445 ret = (char*)m_malloc(buflen);
447 strcpy(ret, "sha1!! ");
449 for (i = 0; i < SHA1_HASH_SIZE; i++) {
450 unsigned int pos = 7 + 3*i;
451 ret[pos] = hexdig(hash[i] >> 4);
452 ret[pos+1] = hexdig(hash[i] & 0x0f);
453 ret[pos+2] = ':';
455 ret[buflen-1] = 0x0;
457 return ret;
460 #endif /* MD5/SHA1 switch */
462 /* This will return a freshly malloced string, containing a fingerprint
463 * in either sha1 or md5 */
464 char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen) {
466 #ifdef DROPBEAR_MD5_HMAC
467 return sign_key_md5_fingerprint(keyblob, keybloblen);
468 #else
469 return sign_key_sha1_fingerprint(keyblob, keybloblen);
470 #endif
473 void buf_put_sign(buffer* buf, sign_key *key, enum signkey_type type,
474 buffer *data_buf) {
475 buffer *sigblob;
476 sigblob = buf_new(MAX_PUBKEY_SIZE);
478 #ifdef DROPBEAR_DSS
479 if (type == DROPBEAR_SIGNKEY_DSS) {
480 buf_put_dss_sign(sigblob, key->dsskey, data_buf);
482 #endif
483 #ifdef DROPBEAR_RSA
484 if (type == DROPBEAR_SIGNKEY_RSA) {
485 buf_put_rsa_sign(sigblob, key->rsakey, data_buf);
487 #endif
488 #ifdef DROPBEAR_ECDSA
489 if (signkey_is_ecdsa(type)) {
490 ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
491 if (eck) {
492 buf_put_ecdsa_sign(sigblob, *eck, data_buf);
495 #endif
496 if (sigblob->len == 0) {
497 dropbear_exit("Non-matching signing type");
499 buf_putbufstring(buf, sigblob);
500 buf_free(sigblob);
504 #ifdef DROPBEAR_SIGNKEY_VERIFY
505 /* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
506 * If FAILURE is returned, the position of
507 * buf is undefined. If SUCCESS is returned, buf will be positioned after the
508 * signature blob */
509 int buf_verify(buffer * buf, sign_key *key, buffer *data_buf) {
511 unsigned char * type_name = NULL;
512 unsigned int type_name_len = 0;
513 enum signkey_type type;
515 TRACE(("enter buf_verify"))
517 buf_getint(buf); /* blob length */
518 type_name = buf_getstring(buf, &type_name_len);
519 type = signkey_type_from_name(type_name, type_name_len);
520 m_free(type_name);
522 #ifdef DROPBEAR_DSS
523 if (type == DROPBEAR_SIGNKEY_DSS) {
524 if (key->dsskey == NULL) {
525 dropbear_exit("No DSS key to verify signature");
527 return buf_dss_verify(buf, key->dsskey, data_buf);
529 #endif
531 #ifdef DROPBEAR_RSA
532 if (type == DROPBEAR_SIGNKEY_RSA) {
533 if (key->rsakey == NULL) {
534 dropbear_exit("No RSA key to verify signature");
536 return buf_rsa_verify(buf, key->rsakey, data_buf);
538 #endif
539 #ifdef DROPBEAR_ECDSA
540 if (signkey_is_ecdsa(type)) {
541 ecc_key **eck = (ecc_key**)signkey_key_ptr(key, type);
542 if (eck) {
543 return buf_ecdsa_verify(buf, *eck, data_buf);
546 #endif
548 dropbear_exit("Non-matching signing type");
549 return DROPBEAR_FAILURE;
551 #endif /* DROPBEAR_SIGNKEY_VERIFY */
553 #ifdef DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
555 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing
556 * a key, a key, and a type. The buffer is positioned at the start of the
557 * base64 data, and contains no trailing data */
558 /* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint
559 of the key if it is successfully decoded */
560 int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen,
561 const unsigned char* algoname, unsigned int algolen,
562 buffer * line, char ** fingerprint) {
564 buffer * decodekey = NULL;
565 int ret = DROPBEAR_FAILURE;
566 unsigned int len, filealgolen;
567 unsigned long decodekeylen;
568 unsigned char* filealgo = NULL;
570 /* now we have the actual data */
571 len = line->len - line->pos;
572 decodekeylen = len * 2; /* big to be safe */
573 decodekey = buf_new(decodekeylen);
575 if (base64_decode(buf_getptr(line, len), len,
576 buf_getwriteptr(decodekey, decodekey->size),
577 &decodekeylen) != CRYPT_OK) {
578 TRACE(("checkpubkey: base64 decode failed"))
579 goto out;
581 TRACE(("checkpubkey: base64_decode success"))
582 buf_incrlen(decodekey, decodekeylen);
584 if (fingerprint) {
585 *fingerprint = sign_key_fingerprint(buf_getptr(decodekey, decodekeylen),
586 decodekeylen);
589 /* compare the keys */
590 if ( ( decodekeylen != keybloblen )
591 || memcmp( buf_getptr(decodekey, decodekey->len),
592 keyblob, decodekey->len) != 0) {
593 TRACE(("checkpubkey: compare failed"))
594 goto out;
597 /* ... and also check that the algo specified and the algo in the key
598 * itself match */
599 filealgolen = buf_getint(decodekey);
600 filealgo = buf_getptr(decodekey, filealgolen);
601 if (filealgolen != algolen || memcmp(filealgo, algoname, algolen) != 0) {
602 TRACE(("checkpubkey: algo match failed"))
603 goto out;
606 /* All checks passed */
607 ret = DROPBEAR_SUCCESS;
609 out:
610 buf_free(decodekey);
611 decodekey = NULL;
612 return ret;
614 #endif