2 * Dropbear - a SSH2 server
4 * Copyright (c) 2002,2003 Matt Johnston
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
32 static const char *signkey_names
[DROPBEAR_SIGNKEY_NUM_NAMED
] = {
40 "ecdsa-sha2-nistp256",
41 "ecdsa-sha2-nistp384",
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() {
51 ret
= (sign_key
*)m_malloc(sizeof(sign_key
));
52 ret
->type
= DROPBEAR_SIGNKEY_NONE
;
53 ret
->source
= SIGNKEY_SOURCE_INVALID
;
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
);
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
) {
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) {
79 /* Some of the ECDSA key sizes are defined even if they're not compiled in */
81 #ifndef DROPBEAR_ECC_256
82 || i
== DROPBEAR_SIGNKEY_ECDSA_NISTP256
84 #ifndef DROPBEAR_ECC_384
85 || i
== DROPBEAR_SIGNKEY_ECDSA_NISTP384
87 #ifndef DROPBEAR_ECC_521
88 || i
== DROPBEAR_SIGNKEY_ECDSA_NISTP521
91 TRACE(("attempt to use ecdsa type %d not compiled in", i
))
92 return DROPBEAR_SIGNKEY_NONE
;
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" */
107 signkey_key_ptr(sign_key
*key
, enum signkey_type type
) {
109 #ifdef DROPBEAR_ECDSA
110 #ifdef DROPBEAR_ECC_256
111 case DROPBEAR_SIGNKEY_ECDSA_NISTP256
:
112 return (void**)&key
->ecckey256
;
114 #ifdef DROPBEAR_ECC_384
115 case DROPBEAR_SIGNKEY_ECDSA_NISTP384
:
116 return (void**)&key
->ecckey384
;
118 #ifdef DROPBEAR_ECC_521
119 case DROPBEAR_SIGNKEY_ECDSA_NISTP521
:
120 return (void**)&key
->ecckey521
;
122 #endif /* DROPBEAR_ECDSA */
124 case DROPBEAR_SIGNKEY_RSA
:
125 return (void**)&key
->rsakey
;
128 case DROPBEAR_SIGNKEY_DSS
:
129 return (void**)&key
->dsskey
;
136 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
137 * type should be set by the caller to specify the type to read, and
138 * on return is set to the type read (useful when type = _ANY) */
139 int buf_get_pub_key(buffer
*buf
, sign_key
*key
, enum signkey_type
*type
) {
143 enum signkey_type keytype
;
144 int ret
= DROPBEAR_FAILURE
;
146 TRACE2(("enter buf_get_pub_key"))
148 ident
= buf_getstring(buf
, &len
);
149 keytype
= signkey_type_from_name(ident
, len
);
152 if (*type
!= DROPBEAR_SIGNKEY_ANY
&& *type
!= keytype
) {
153 TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype
, *type
))
154 return DROPBEAR_FAILURE
;
157 TRACE2(("buf_get_pub_key keytype is %d", keytype
))
161 /* Rewind the buffer back before "ssh-rsa" etc */
162 buf_incrpos(buf
, -len
- 4);
165 if (keytype
== DROPBEAR_SIGNKEY_DSS
) {
166 dss_key_free(key
->dsskey
);
167 key
->dsskey
= m_malloc(sizeof(*key
->dsskey
));
168 ret
= buf_get_dss_pub_key(buf
, key
->dsskey
);
169 if (ret
== DROPBEAR_FAILURE
) {
175 if (keytype
== DROPBEAR_SIGNKEY_RSA
) {
176 rsa_key_free(key
->rsakey
);
177 key
->rsakey
= m_malloc(sizeof(*key
->rsakey
));
178 ret
= buf_get_rsa_pub_key(buf
, key
->rsakey
);
179 if (ret
== DROPBEAR_FAILURE
) {
184 #ifdef DROPBEAR_ECDSA
185 if (signkey_is_ecdsa(keytype
)) {
186 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, keytype
);
193 *eck
= buf_get_ecdsa_pub_key(buf
);
195 ret
= DROPBEAR_SUCCESS
;
201 TRACE2(("leave buf_get_pub_key"))
207 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
208 * type should be set by the caller to specify the type to read, and
209 * on return is set to the type read (useful when type = _ANY) */
210 int buf_get_priv_key(buffer
*buf
, sign_key
*key
, enum signkey_type
*type
) {
214 enum signkey_type keytype
;
215 int ret
= DROPBEAR_FAILURE
;
217 TRACE2(("enter buf_get_priv_key"))
219 ident
= buf_getstring(buf
, &len
);
220 keytype
= signkey_type_from_name(ident
, len
);
223 if (*type
!= DROPBEAR_SIGNKEY_ANY
&& *type
!= keytype
) {
224 TRACE(("wrong key type: %d %d", *type
, keytype
))
225 return DROPBEAR_FAILURE
;
230 /* Rewind the buffer back before "ssh-rsa" etc */
231 buf_incrpos(buf
, -len
- 4);
234 if (keytype
== DROPBEAR_SIGNKEY_DSS
) {
235 dss_key_free(key
->dsskey
);
236 key
->dsskey
= m_malloc(sizeof(*key
->dsskey
));
237 ret
= buf_get_dss_priv_key(buf
, key
->dsskey
);
238 if (ret
== DROPBEAR_FAILURE
) {
244 if (keytype
== DROPBEAR_SIGNKEY_RSA
) {
245 rsa_key_free(key
->rsakey
);
246 key
->rsakey
= m_malloc(sizeof(*key
->rsakey
));
247 ret
= buf_get_rsa_priv_key(buf
, key
->rsakey
);
248 if (ret
== DROPBEAR_FAILURE
) {
253 #ifdef DROPBEAR_ECDSA
254 if (signkey_is_ecdsa(keytype
)) {
255 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, keytype
);
262 *eck
= buf_get_ecdsa_priv_key(buf
);
264 ret
= DROPBEAR_SUCCESS
;
270 TRACE2(("leave buf_get_priv_key"))
276 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
277 void buf_put_pub_key(buffer
* buf
, sign_key
*key
, enum signkey_type type
) {
281 TRACE2(("enter buf_put_pub_key"))
282 pubkeys
= buf_new(MAX_PUBKEY_SIZE
);
285 if (type
== DROPBEAR_SIGNKEY_DSS
) {
286 buf_put_dss_pub_key(pubkeys
, key
->dsskey
);
290 if (type
== DROPBEAR_SIGNKEY_RSA
) {
291 buf_put_rsa_pub_key(pubkeys
, key
->rsakey
);
294 #ifdef DROPBEAR_ECDSA
295 if (signkey_is_ecdsa(type
)) {
296 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
298 buf_put_ecdsa_pub_key(pubkeys
, *eck
);
302 if (pubkeys
->len
== 0) {
303 dropbear_exit("Bad key types in buf_put_pub_key");
306 buf_putbufstring(buf
, pubkeys
);
308 TRACE2(("leave buf_put_pub_key"))
311 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
312 void buf_put_priv_key(buffer
* buf
, sign_key
*key
, enum signkey_type type
) {
314 TRACE(("enter buf_put_priv_key"))
315 TRACE(("type is %d", type
))
318 if (type
== DROPBEAR_SIGNKEY_DSS
) {
319 buf_put_dss_priv_key(buf
, key
->dsskey
);
320 TRACE(("leave buf_put_priv_key: dss done"))
325 if (type
== DROPBEAR_SIGNKEY_RSA
) {
326 buf_put_rsa_priv_key(buf
, key
->rsakey
);
327 TRACE(("leave buf_put_priv_key: rsa done"))
331 #ifdef DROPBEAR_ECDSA
332 if (signkey_is_ecdsa(type
)) {
333 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
335 buf_put_ecdsa_priv_key(buf
, *eck
);
336 TRACE(("leave buf_put_priv_key: ecdsa done"))
341 dropbear_exit("Bad key types in put pub key");
344 void sign_key_free(sign_key
*key
) {
346 TRACE2(("enter sign_key_free"))
349 dss_key_free(key
->dsskey
);
353 rsa_key_free(key
->rsakey
);
356 #ifdef DROPBEAR_ECDSA
357 #ifdef DROPBEAR_ECC_256
358 if (key
->ecckey256
) {
359 ecc_free(key
->ecckey256
);
360 m_free(key
->ecckey256
);
361 key
->ecckey256
= NULL
;
364 #ifdef DROPBEAR_ECC_384
365 if (key
->ecckey384
) {
366 ecc_free(key
->ecckey384
);
367 m_free(key
->ecckey384
);
368 key
->ecckey384
= NULL
;
371 #ifdef DROPBEAR_ECC_521
372 if (key
->ecckey521
) {
373 ecc_free(key
->ecckey521
);
374 m_free(key
->ecckey521
);
375 key
->ecckey521
= NULL
;
380 m_free(key
->filename
);
383 TRACE2(("leave sign_key_free"))
386 static char hexdig(unsigned char x
) {
396 /* Since we're not sure if we'll have md5 or sha1, we present both.
397 * MD5 is used in preference, but sha1 could still be useful */
398 #ifdef DROPBEAR_MD5_HMAC
399 static char * sign_key_md5_fingerprint(unsigned char* keyblob
,
400 unsigned int keybloblen
) {
404 unsigned char hash
[MD5_HASH_SIZE
];
410 /* skip the size int of the string - this is a bit messy */
411 md5_process(&hs
, keyblob
, keybloblen
);
415 /* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
416 buflen
= 4 + 3*MD5_HASH_SIZE
;
417 ret
= (char*)m_malloc(buflen
);
419 memset(ret
, 'Z', buflen
);
422 for (i
= 0; i
< MD5_HASH_SIZE
; i
++) {
423 unsigned int pos
= 4 + i
*3;
424 ret
[pos
] = hexdig(hash
[i
] >> 4);
425 ret
[pos
+1] = hexdig(hash
[i
] & 0x0f);
433 #else /* use SHA1 rather than MD5 for fingerprint */
434 static char * sign_key_sha1_fingerprint(unsigned char* keyblob
,
435 unsigned int keybloblen
) {
439 unsigned char hash
[SHA1_HASH_SIZE
];
445 /* skip the size int of the string - this is a bit messy */
446 sha1_process(&hs
, keyblob
, keybloblen
);
448 sha1_done(&hs
, hash
);
450 /* "sha1!! hexfingerprinthere\0", each hex digit is "AB:" etc */
451 buflen
= 7 + 3*SHA1_HASH_SIZE
;
452 ret
= (char*)m_malloc(buflen
);
454 strcpy(ret
, "sha1!! ");
456 for (i
= 0; i
< SHA1_HASH_SIZE
; i
++) {
457 unsigned int pos
= 7 + 3*i
;
458 ret
[pos
] = hexdig(hash
[i
] >> 4);
459 ret
[pos
+1] = hexdig(hash
[i
] & 0x0f);
467 #endif /* MD5/SHA1 switch */
469 /* This will return a freshly malloced string, containing a fingerprint
470 * in either sha1 or md5 */
471 char * sign_key_fingerprint(unsigned char* keyblob
, unsigned int keybloblen
) {
473 #ifdef DROPBEAR_MD5_HMAC
474 return sign_key_md5_fingerprint(keyblob
, keybloblen
);
476 return sign_key_sha1_fingerprint(keyblob
, keybloblen
);
480 void buf_put_sign(buffer
* buf
, sign_key
*key
, enum signkey_type type
,
483 sigblob
= buf_new(MAX_PUBKEY_SIZE
);
486 if (type
== DROPBEAR_SIGNKEY_DSS
) {
487 buf_put_dss_sign(sigblob
, key
->dsskey
, data_buf
);
491 if (type
== DROPBEAR_SIGNKEY_RSA
) {
492 buf_put_rsa_sign(sigblob
, key
->rsakey
, data_buf
);
495 #ifdef DROPBEAR_ECDSA
496 if (signkey_is_ecdsa(type
)) {
497 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
499 buf_put_ecdsa_sign(sigblob
, *eck
, data_buf
);
503 if (sigblob
->len
== 0) {
504 dropbear_exit("Non-matching signing type");
506 buf_putbufstring(buf
, sigblob
);
511 #ifdef DROPBEAR_SIGNKEY_VERIFY
512 /* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
513 * If FAILURE is returned, the position of
514 * buf is undefined. If SUCCESS is returned, buf will be positioned after the
516 int buf_verify(buffer
* buf
, sign_key
*key
, buffer
*data_buf
) {
518 char *type_name
= NULL
;
519 unsigned int type_name_len
= 0;
520 enum signkey_type type
;
522 TRACE(("enter buf_verify"))
524 buf_getint(buf
); /* blob length */
525 type_name
= buf_getstring(buf
, &type_name_len
);
526 type
= signkey_type_from_name(type_name
, type_name_len
);
530 if (type
== DROPBEAR_SIGNKEY_DSS
) {
531 if (key
->dsskey
== NULL
) {
532 dropbear_exit("No DSS key to verify signature");
534 return buf_dss_verify(buf
, key
->dsskey
, data_buf
);
539 if (type
== DROPBEAR_SIGNKEY_RSA
) {
540 if (key
->rsakey
== NULL
) {
541 dropbear_exit("No RSA key to verify signature");
543 return buf_rsa_verify(buf
, key
->rsakey
, data_buf
);
546 #ifdef DROPBEAR_ECDSA
547 if (signkey_is_ecdsa(type
)) {
548 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
550 return buf_ecdsa_verify(buf
, *eck
, data_buf
);
555 dropbear_exit("Non-matching signing type");
556 return DROPBEAR_FAILURE
;
558 #endif /* DROPBEAR_SIGNKEY_VERIFY */
560 #ifdef DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
562 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing
563 * a key, a key, and a type. The buffer is positioned at the start of the
564 * base64 data, and contains no trailing data */
565 /* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint
566 of the key if it is successfully decoded */
567 int cmp_base64_key(const unsigned char* keyblob
, unsigned int keybloblen
,
568 const unsigned char* algoname
, unsigned int algolen
,
569 buffer
* line
, char ** fingerprint
) {
571 buffer
* decodekey
= NULL
;
572 int ret
= DROPBEAR_FAILURE
;
573 unsigned int len
, filealgolen
;
574 unsigned long decodekeylen
;
575 unsigned char* filealgo
= NULL
;
577 /* now we have the actual data */
578 len
= line
->len
- line
->pos
;
579 decodekeylen
= len
* 2; /* big to be safe */
580 decodekey
= buf_new(decodekeylen
);
582 if (base64_decode(buf_getptr(line
, len
), len
,
583 buf_getwriteptr(decodekey
, decodekey
->size
),
584 &decodekeylen
) != CRYPT_OK
) {
585 TRACE(("checkpubkey: base64 decode failed"))
588 TRACE(("checkpubkey: base64_decode success"))
589 buf_incrlen(decodekey
, decodekeylen
);
592 *fingerprint
= sign_key_fingerprint(buf_getptr(decodekey
, decodekeylen
),
596 /* compare the keys */
597 if ( ( decodekeylen
!= keybloblen
)
598 || memcmp( buf_getptr(decodekey
, decodekey
->len
),
599 keyblob
, decodekey
->len
) != 0) {
600 TRACE(("checkpubkey: compare failed"))
604 /* ... and also check that the algo specified and the algo in the key
606 filealgolen
= buf_getint(decodekey
);
607 filealgo
= buf_getptr(decodekey
, filealgolen
);
608 if (filealgolen
!= algolen
|| memcmp(filealgo
, algoname
, algolen
) != 0) {
609 TRACE(("checkpubkey: algo match failed"))
613 /* All checks passed */
614 ret
= DROPBEAR_SUCCESS
;