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
31 /* malloc a new sign_key and set the dss and rsa keys to NULL */
32 sign_key
* new_sign_key() {
36 ret
= (sign_key
*)m_malloc(sizeof(sign_key
));
44 ret
->type
= DROPBEAR_SIGNKEY_NONE
;
45 ret
->source
= SIGNKEY_SOURCE_INVALID
;
49 /* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally
50 * if the type is invalid */
51 const char* signkey_name_from_type(int type
, int *namelen
) {
54 if (type
== DROPBEAR_SIGNKEY_RSA
) {
55 *namelen
= SSH_SIGNKEY_RSA_LEN
;
56 return SSH_SIGNKEY_RSA
;
60 if (type
== DROPBEAR_SIGNKEY_DSS
) {
61 *namelen
= SSH_SIGNKEY_DSS_LEN
;
62 return SSH_SIGNKEY_DSS
;
65 dropbear_exit("Bad key type %d", type
);
66 return NULL
; /* notreached */
69 /* Returns DROPBEAR_SIGNKEY_RSA, DROPBEAR_SIGNKEY_DSS,
70 * or DROPBEAR_SIGNKEY_NONE */
71 int signkey_type_from_name(const char* name
, int namelen
) {
74 if (namelen
== SSH_SIGNKEY_RSA_LEN
75 && memcmp(name
, SSH_SIGNKEY_RSA
, SSH_SIGNKEY_RSA_LEN
) == 0) {
76 return DROPBEAR_SIGNKEY_RSA
;
80 if (namelen
== SSH_SIGNKEY_DSS_LEN
81 && memcmp(name
, SSH_SIGNKEY_DSS
, SSH_SIGNKEY_DSS_LEN
) == 0) {
82 return DROPBEAR_SIGNKEY_DSS
;
86 TRACE(("signkey_type_from_name unexpected key type."))
88 return DROPBEAR_SIGNKEY_NONE
;
91 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
92 * type should be set by the caller to specify the type to read, and
93 * on return is set to the type read (useful when type = _ANY) */
94 int buf_get_pub_key(buffer
*buf
, sign_key
*key
, int *type
) {
99 int ret
= DROPBEAR_FAILURE
;
101 TRACE(("enter buf_get_pub_key"))
103 ident
= buf_getstring(buf
, &len
);
104 keytype
= signkey_type_from_name(ident
, len
);
107 if (*type
!= DROPBEAR_SIGNKEY_ANY
&& *type
!= keytype
) {
108 TRACE(("buf_get_pub_key bad type - got %d, expected %d", keytype
, *type
))
109 return DROPBEAR_FAILURE
;
112 TRACE(("buf_get_pub_key keytype is %d", keytype
))
116 /* Rewind the buffer back before "ssh-rsa" etc */
117 buf_incrpos(buf
, -len
- 4);
120 if (keytype
== DROPBEAR_SIGNKEY_DSS
) {
121 dss_key_free(key
->dsskey
);
122 key
->dsskey
= m_malloc(sizeof(*key
->dsskey
));
123 ret
= buf_get_dss_pub_key(buf
, key
->dsskey
);
124 if (ret
== DROPBEAR_FAILURE
) {
130 if (keytype
== DROPBEAR_SIGNKEY_RSA
) {
131 rsa_key_free(key
->rsakey
);
132 key
->rsakey
= m_malloc(sizeof(*key
->rsakey
));
133 ret
= buf_get_rsa_pub_key(buf
, key
->rsakey
);
134 if (ret
== DROPBEAR_FAILURE
) {
140 TRACE(("leave buf_get_pub_key"))
146 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail.
147 * type should be set by the caller to specify the type to read, and
148 * on return is set to the type read (useful when type = _ANY) */
149 int buf_get_priv_key(buffer
*buf
, sign_key
*key
, int *type
) {
151 unsigned char* ident
;
154 int ret
= DROPBEAR_FAILURE
;
156 TRACE(("enter buf_get_priv_key"))
158 ident
= buf_getstring(buf
, &len
);
159 keytype
= signkey_type_from_name(ident
, len
);
162 if (*type
!= DROPBEAR_SIGNKEY_ANY
&& *type
!= keytype
) {
163 TRACE(("wrong key type: %d %d", *type
, keytype
))
164 return DROPBEAR_FAILURE
;
169 /* Rewind the buffer back before "ssh-rsa" etc */
170 buf_incrpos(buf
, -len
- 4);
173 if (keytype
== DROPBEAR_SIGNKEY_DSS
) {
174 dss_key_free(key
->dsskey
);
175 key
->dsskey
= m_malloc(sizeof(*key
->dsskey
));
176 ret
= buf_get_dss_priv_key(buf
, key
->dsskey
);
177 if (ret
== DROPBEAR_FAILURE
) {
183 if (keytype
== DROPBEAR_SIGNKEY_RSA
) {
184 rsa_key_free(key
->rsakey
);
185 key
->rsakey
= m_malloc(sizeof(*key
->rsakey
));
186 ret
= buf_get_rsa_priv_key(buf
, key
->rsakey
);
187 if (ret
== DROPBEAR_FAILURE
) {
193 TRACE(("leave buf_get_priv_key"))
199 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
200 void buf_put_pub_key(buffer
* buf
, sign_key
*key
, int type
) {
204 TRACE(("enter buf_put_pub_key"))
205 pubkeys
= buf_new(MAX_PUBKEY_SIZE
);
208 if (type
== DROPBEAR_SIGNKEY_DSS
) {
209 buf_put_dss_pub_key(pubkeys
, key
->dsskey
);
213 if (type
== DROPBEAR_SIGNKEY_RSA
) {
214 buf_put_rsa_pub_key(pubkeys
, key
->rsakey
);
217 if (pubkeys
->len
== 0) {
218 dropbear_exit("Bad key types in buf_put_pub_key");
221 buf_setpos(pubkeys
, 0);
222 buf_putstring(buf
, buf_getptr(pubkeys
, pubkeys
->len
),
226 TRACE(("leave buf_put_pub_key"))
229 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */
230 void buf_put_priv_key(buffer
* buf
, sign_key
*key
, int type
) {
232 TRACE(("enter buf_put_priv_key"))
233 TRACE(("type is %d", type
))
236 if (type
== DROPBEAR_SIGNKEY_DSS
) {
237 buf_put_dss_priv_key(buf
, key
->dsskey
);
238 TRACE(("leave buf_put_priv_key: dss done"))
243 if (type
== DROPBEAR_SIGNKEY_RSA
) {
244 buf_put_rsa_priv_key(buf
, key
->rsakey
);
245 TRACE(("leave buf_put_priv_key: rsa done"))
249 dropbear_exit("Bad key types in put pub key");
252 void sign_key_free(sign_key
*key
) {
254 TRACE(("enter sign_key_free"))
257 dss_key_free(key
->dsskey
);
261 rsa_key_free(key
->rsakey
);
265 m_free(key
->filename
);
268 TRACE(("leave sign_key_free"))
271 static char hexdig(unsigned char x
) {
282 /* Since we're not sure if we'll have md5 or sha1, we present both.
283 * MD5 is used in preference, but sha1 could still be useful */
284 #ifdef DROPBEAR_MD5_HMAC
285 static char * sign_key_md5_fingerprint(unsigned char* keyblob
,
286 unsigned int keybloblen
) {
290 unsigned char hash
[MD5_HASH_SIZE
];
296 /* skip the size int of the string - this is a bit messy */
297 md5_process(&hs
, keyblob
, keybloblen
);
301 /* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
302 buflen
= 4 + 3*MD5_HASH_SIZE
;
303 ret
= (char*)m_malloc(buflen
);
305 memset(ret
, 'Z', buflen
);
308 for (i
= 0; i
< MD5_HASH_SIZE
; i
++) {
309 unsigned int pos
= 4 + i
*3;
310 ret
[pos
] = hexdig(hash
[i
] >> 4);
311 ret
[pos
+1] = hexdig(hash
[i
] & 0x0f);
319 #else /* use SHA1 rather than MD5 for fingerprint */
320 static char * sign_key_sha1_fingerprint(unsigned char* keyblob
,
321 unsigned int keybloblen
) {
325 unsigned char hash
[SHA1_HASH_SIZE
];
331 /* skip the size int of the string - this is a bit messy */
332 sha1_process(&hs
, keyblob
, keybloblen
);
334 sha1_done(&hs
, hash
);
336 /* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
337 buflen
= 5 + 3*SHA1_HASH_SIZE
;
338 ret
= (char*)m_malloc(buflen
);
340 strcpy(ret
, "sha1 ");
342 for (i
= 0; i
< SHA1_HASH_SIZE
; i
++) {
343 unsigned int pos
= 5 + 3*i
;
344 ret
[pos
] = hexdig(hash
[i
] >> 4);
345 ret
[pos
+1] = hexdig(hash
[i
] & 0x0f);
353 #endif /* MD5/SHA1 switch */
355 /* This will return a freshly malloced string, containing a fingerprint
356 * in either sha1 or md5 */
357 char * sign_key_fingerprint(unsigned char* keyblob
, unsigned int keybloblen
) {
359 #ifdef DROPBEAR_MD5_HMAC
360 return sign_key_md5_fingerprint(keyblob
, keybloblen
);
362 return sign_key_sha1_fingerprint(keyblob
, keybloblen
);
366 void buf_put_sign(buffer
* buf
, sign_key
*key
, int type
,
367 const unsigned char *data
, unsigned int len
) {
370 sigblob
= buf_new(MAX_PUBKEY_SIZE
);
373 if (type
== DROPBEAR_SIGNKEY_DSS
) {
374 buf_put_dss_sign(sigblob
, key
->dsskey
, data
, len
);
378 if (type
== DROPBEAR_SIGNKEY_RSA
) {
379 buf_put_rsa_sign(sigblob
, key
->rsakey
, data
, len
);
382 if (sigblob
->len
== 0) {
383 dropbear_exit("Non-matching signing type");
385 buf_setpos(sigblob
, 0);
386 buf_putstring(buf
, buf_getptr(sigblob
, sigblob
->len
),
393 #ifdef DROPBEAR_SIGNKEY_VERIFY
394 /* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
395 * If FAILURE is returned, the position of
396 * buf is undefined. If SUCCESS is returned, buf will be positioned after the
398 int buf_verify(buffer
* buf
, sign_key
*key
, const unsigned char *data
,
401 unsigned int bloblen
;
402 unsigned char * ident
= NULL
;
403 unsigned int identlen
= 0;
405 TRACE(("enter buf_verify"))
407 bloblen
= buf_getint(buf
);
408 ident
= buf_getstring(buf
, &identlen
);
411 if (bloblen
== DSS_SIGNATURE_SIZE
&&
412 memcmp(ident
, SSH_SIGNKEY_DSS
, identlen
) == 0) {
414 if (key
->dsskey
== NULL
) {
415 dropbear_exit("No DSS key to verify signature");
417 return buf_dss_verify(buf
, key
->dsskey
, data
, len
);
422 if (memcmp(ident
, SSH_SIGNKEY_RSA
, identlen
) == 0) {
424 if (key
->rsakey
== NULL
) {
425 dropbear_exit("No RSA key to verify signature");
427 return buf_rsa_verify(buf
, key
->rsakey
, data
, len
);
432 dropbear_exit("Non-matching signing type");
433 return DROPBEAR_FAILURE
;
435 #endif /* DROPBEAR_SIGNKEY_VERIFY */
437 #ifdef DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
439 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing
440 * a key, a key, and a type. The buffer is positioned at the start of the
441 * base64 data, and contains no trailing data */
442 /* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint
443 of the key if it is successfully decoded */
444 int cmp_base64_key(const unsigned char* keyblob
, unsigned int keybloblen
,
445 const unsigned char* algoname
, unsigned int algolen
,
446 buffer
* line
, char ** fingerprint
) {
448 buffer
* decodekey
= NULL
;
449 int ret
= DROPBEAR_FAILURE
;
450 unsigned int len
, filealgolen
;
451 unsigned long decodekeylen
;
452 unsigned char* filealgo
= NULL
;
454 /* now we have the actual data */
455 len
= line
->len
- line
->pos
;
456 decodekeylen
= len
* 2; /* big to be safe */
457 decodekey
= buf_new(decodekeylen
);
459 if (base64_decode(buf_getptr(line
, len
), len
,
460 buf_getwriteptr(decodekey
, decodekey
->size
),
461 &decodekeylen
) != CRYPT_OK
) {
462 TRACE(("checkpubkey: base64 decode failed"))
465 TRACE(("checkpubkey: base64_decode success"))
466 buf_incrlen(decodekey
, decodekeylen
);
469 *fingerprint
= sign_key_fingerprint(buf_getptr(decodekey
, decodekeylen
),
473 /* compare the keys */
474 if ( ( decodekeylen
!= keybloblen
)
475 || memcmp( buf_getptr(decodekey
, decodekey
->len
),
476 keyblob
, decodekey
->len
) != 0) {
477 TRACE(("checkpubkey: compare failed"))
481 /* ... and also check that the algo specified and the algo in the key
483 filealgolen
= buf_getint(decodekey
);
484 filealgo
= buf_getptr(decodekey
, filealgolen
);
485 if (filealgolen
!= algolen
|| memcmp(filealgo
, algoname
, algolen
) != 0) {
486 TRACE(("checkpubkey: algo match failed"))
490 /* All checks passed */
491 ret
= DROPBEAR_SUCCESS
;