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_ECC_256
110 case DROPBEAR_SIGNKEY_ECDSA_NISTP256
:
111 return (void**)&key
->ecckey256
;
113 #ifdef DROPBEAR_ECC_384
114 case DROPBEAR_SIGNKEY_ECDSA_NISTP384
:
115 return (void**)&key
->ecckey384
;
117 #ifdef DROPBEAR_ECC_521
118 case DROPBEAR_SIGNKEY_ECDSA_NISTP521
:
119 return (void**)&key
->ecckey521
;
122 case DROPBEAR_SIGNKEY_RSA
:
123 return (void**)&key
->rsakey
;
126 case DROPBEAR_SIGNKEY_DSS
:
127 return (void**)&key
->dsskey
;
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
;
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
);
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
))
159 /* Rewind the buffer back before "ssh-rsa" etc */
160 buf_incrpos(buf
, -len
- 4);
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
) {
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
) {
182 #ifdef DROPBEAR_ECDSA
183 if (signkey_is_ecdsa(keytype
)) {
184 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, keytype
);
190 *eck
= buf_get_ecdsa_pub_key(buf
);
192 ret
= DROPBEAR_SUCCESS
;
198 TRACE2(("leave buf_get_pub_key"))
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
;
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
);
220 if (*type
!= DROPBEAR_SIGNKEY_ANY
&& *type
!= keytype
) {
221 TRACE(("wrong key type: %d %d", *type
, keytype
))
222 return DROPBEAR_FAILURE
;
227 /* Rewind the buffer back before "ssh-rsa" etc */
228 buf_incrpos(buf
, -len
- 4);
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
) {
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
) {
250 #ifdef DROPBEAR_ECDSA
251 if (signkey_is_ecdsa(keytype
)) {
252 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, keytype
);
258 *eck
= buf_get_ecdsa_priv_key(buf
);
260 ret
= DROPBEAR_SUCCESS
;
266 TRACE2(("leave buf_get_priv_key"))
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
) {
277 TRACE2(("enter buf_put_pub_key"))
278 pubkeys
= buf_new(MAX_PUBKEY_SIZE
);
281 if (type
== DROPBEAR_SIGNKEY_DSS
) {
282 buf_put_dss_pub_key(pubkeys
, key
->dsskey
);
286 if (type
== DROPBEAR_SIGNKEY_RSA
) {
287 buf_put_rsa_pub_key(pubkeys
, key
->rsakey
);
290 #ifdef DROPBEAR_ECDSA
291 if (signkey_is_ecdsa(type
)) {
292 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
294 buf_put_ecdsa_pub_key(pubkeys
, *eck
);
298 if (pubkeys
->len
== 0) {
299 dropbear_exit("Bad key types in buf_put_pub_key");
302 buf_putbufstring(buf
, 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
))
314 if (type
== DROPBEAR_SIGNKEY_DSS
) {
315 buf_put_dss_priv_key(buf
, key
->dsskey
);
316 TRACE(("leave buf_put_priv_key: dss done"))
321 if (type
== DROPBEAR_SIGNKEY_RSA
) {
322 buf_put_rsa_priv_key(buf
, key
->rsakey
);
323 TRACE(("leave buf_put_priv_key: rsa done"))
327 #ifdef DROPBEAR_ECDSA
328 if (signkey_is_ecdsa(type
)) {
329 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
331 buf_put_ecdsa_priv_key(buf
, *eck
);
332 TRACE(("leave buf_put_priv_key: ecdsa done"))
337 dropbear_exit("Bad key types in put pub key");
340 void sign_key_free(sign_key
*key
) {
342 TRACE2(("enter sign_key_free"))
345 dss_key_free(key
->dsskey
);
349 rsa_key_free(key
->rsakey
);
352 #ifdef DROPBEAR_ECDSA
353 #ifdef DROPBEAR_ECC_256
354 if (key
->ecckey256
) {
355 ecc_free(key
->ecckey256
);
356 key
->ecckey256
= NULL
;
359 #ifdef DROPBEAR_ECC_384
360 if (key
->ecckey384
) {
361 ecc_free(key
->ecckey384
);
362 key
->ecckey384
= NULL
;
365 #ifdef DROPBEAR_ECC_521
366 if (key
->ecckey521
) {
367 ecc_free(key
->ecckey521
);
368 key
->ecckey521
= NULL
;
373 m_free(key
->filename
);
376 TRACE2(("leave sign_key_free"))
379 static char hexdig(unsigned char x
) {
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
) {
397 unsigned char hash
[MD5_HASH_SIZE
];
403 /* skip the size int of the string - this is a bit messy */
404 md5_process(&hs
, keyblob
, keybloblen
);
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
);
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);
426 #else /* use SHA1 rather than MD5 for fingerprint */
427 static char * sign_key_sha1_fingerprint(unsigned char* keyblob
,
428 unsigned int keybloblen
) {
432 unsigned char hash
[SHA1_HASH_SIZE
];
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);
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
);
469 return sign_key_sha1_fingerprint(keyblob
, keybloblen
);
473 void buf_put_sign(buffer
* buf
, sign_key
*key
, enum signkey_type type
,
476 sigblob
= buf_new(MAX_PUBKEY_SIZE
);
479 if (type
== DROPBEAR_SIGNKEY_DSS
) {
480 buf_put_dss_sign(sigblob
, key
->dsskey
, data_buf
);
484 if (type
== DROPBEAR_SIGNKEY_RSA
) {
485 buf_put_rsa_sign(sigblob
, key
->rsakey
, data_buf
);
488 #ifdef DROPBEAR_ECDSA
489 if (signkey_is_ecdsa(type
)) {
490 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
492 buf_put_ecdsa_sign(sigblob
, *eck
, data_buf
);
496 if (sigblob
->len
== 0) {
497 dropbear_exit("Non-matching signing type");
499 buf_putbufstring(buf
, 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
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
);
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
);
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
);
539 #ifdef DROPBEAR_ECDSA
540 if (signkey_is_ecdsa(type
)) {
541 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, type
);
543 return buf_ecdsa_verify(buf
, *eck
, data_buf
);
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"))
581 TRACE(("checkpubkey: base64_decode success"))
582 buf_incrlen(decodekey
, decodekeylen
);
585 *fingerprint
= sign_key_fingerprint(buf_getptr(decodekey
, 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"))
597 /* ... and also check that the algo specified and the algo in the key
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"))
606 /* All checks passed */
607 ret
= DROPBEAR_SUCCESS
;