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"))
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
);
299 if (md5_done(&hs
, hash
) != CRYPT_OK
)
302 /* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */
303 buflen
= 4 + 3*MD5_HASH_SIZE
;
304 ret
= (char*)m_malloc(buflen
);
306 memset(ret
, 'Z', buflen
);
309 for (i
= 0; i
< MD5_HASH_SIZE
; i
++) {
310 unsigned int pos
= 4 + i
*3;
311 ret
[pos
] = hexdig(hash
[i
] >> 4);
312 ret
[pos
+1] = hexdig(hash
[i
] & 0x0f);
320 #else /* use SHA1 rather than MD5 for fingerprint */
321 static char * sign_key_sha1_fingerprint(unsigned char* keyblob
,
322 unsigned int keybloblen
) {
326 unsigned char hash
[SHA1_HASH_SIZE
];
332 /* skip the size int of the string - this is a bit messy */
333 sha1_process(&hs
, keyblob
, keybloblen
);
335 sha1_done(&hs
, hash
);
337 /* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */
338 buflen
= 5 + 3*SHA1_HASH_SIZE
;
339 ret
= (char*)m_malloc(buflen
);
341 strcpy(ret
, "sha1 ");
343 for (i
= 0; i
< SHA1_HASH_SIZE
; i
++) {
344 unsigned int pos
= 5 + 3*i
;
345 ret
[pos
] = hexdig(hash
[i
] >> 4);
346 ret
[pos
+1] = hexdig(hash
[i
] & 0x0f);
354 #endif /* MD5/SHA1 switch */
356 /* This will return a freshly malloced string, containing a fingerprint
357 * in either sha1 or md5 */
358 char * sign_key_fingerprint(unsigned char* keyblob
, unsigned int keybloblen
) {
360 #ifdef DROPBEAR_MD5_HMAC
361 return sign_key_md5_fingerprint(keyblob
, keybloblen
);
363 return sign_key_sha1_fingerprint(keyblob
, keybloblen
);
367 void buf_put_sign(buffer
* buf
, sign_key
*key
, int type
,
368 const unsigned char *data
, unsigned int len
) {
371 sigblob
= buf_new(MAX_PUBKEY_SIZE
);
374 if (type
== DROPBEAR_SIGNKEY_DSS
) {
375 buf_put_dss_sign(sigblob
, key
->dsskey
, data
, len
);
379 if (type
== DROPBEAR_SIGNKEY_RSA
) {
380 buf_put_rsa_sign(sigblob
, key
->rsakey
, data
, len
);
383 if (sigblob
->len
== 0) {
384 dropbear_exit("Non-matching signing type");
386 buf_setpos(sigblob
, 0);
387 buf_putstring(buf
, buf_getptr(sigblob
, sigblob
->len
),
394 #ifdef DROPBEAR_SIGNKEY_VERIFY
395 /* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE.
396 * If FAILURE is returned, the position of
397 * buf is undefined. If SUCCESS is returned, buf will be positioned after the
399 int buf_verify(buffer
* buf
, sign_key
*key
, const unsigned char *data
,
402 unsigned int bloblen
;
403 unsigned char * ident
= NULL
;
404 unsigned int identlen
= 0;
406 TRACE(("enter buf_verify"))
408 bloblen
= buf_getint(buf
);
409 ident
= buf_getstring(buf
, &identlen
);
412 if (bloblen
== DSS_SIGNATURE_SIZE
&&
413 memcmp(ident
, SSH_SIGNKEY_DSS
, identlen
) == 0) {
415 if (key
->dsskey
== NULL
) {
416 dropbear_exit("No DSS key to verify signature");
418 return buf_dss_verify(buf
, key
->dsskey
, data
, len
);
423 if (memcmp(ident
, SSH_SIGNKEY_RSA
, identlen
) == 0) {
425 if (key
->rsakey
== NULL
) {
426 dropbear_exit("No RSA key to verify signature");
428 return buf_rsa_verify(buf
, key
->rsakey
, data
, len
);
433 dropbear_exit("Non-matching signing type");
434 return DROPBEAR_FAILURE
;
436 #endif /* DROPBEAR_SIGNKEY_VERIFY */
438 #ifdef DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */
440 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing
441 * a key, a key, and a type. The buffer is positioned at the start of the
442 * base64 data, and contains no trailing data */
443 /* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint
444 of the key if it is successfully decoded */
445 int cmp_base64_key(const unsigned char* keyblob
, unsigned int keybloblen
,
446 const unsigned char* algoname
, unsigned int algolen
,
447 buffer
* line
, char ** fingerprint
) {
449 buffer
* decodekey
= NULL
;
450 int ret
= DROPBEAR_FAILURE
;
451 unsigned int len
, filealgolen
;
452 unsigned long decodekeylen
;
453 unsigned char* filealgo
= NULL
;
455 /* now we have the actual data */
456 len
= line
->len
- line
->pos
;
457 decodekeylen
= len
* 2; /* big to be safe */
458 decodekey
= buf_new(decodekeylen
);
460 if (base64_decode(buf_getptr(line
, len
), len
,
461 buf_getwriteptr(decodekey
, decodekey
->size
),
462 &decodekeylen
) != CRYPT_OK
) {
463 TRACE(("checkpubkey: base64 decode failed"))
466 TRACE(("checkpubkey: base64_decode success"))
467 buf_incrlen(decodekey
, decodekeylen
);
470 *fingerprint
= sign_key_fingerprint(buf_getptr(decodekey
, decodekeylen
),
474 /* compare the keys */
475 if ( ( decodekeylen
!= keybloblen
)
476 || memcmp( buf_getptr(decodekey
, decodekey
->len
),
477 keyblob
, decodekey
->len
) != 0) {
478 TRACE(("checkpubkey: compare failed"))
482 /* ... and also check that the algo specified and the algo in the key
484 filealgolen
= buf_getint(decodekey
);
485 filealgo
= buf_getptr(decodekey
, filealgolen
);
486 if (filealgolen
!= algolen
|| memcmp(filealgo
, algoname
, algolen
) != 0) {
487 TRACE(("checkpubkey: algo match failed"))
491 /* All checks passed */
492 ret
= DROPBEAR_SUCCESS
;