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: 13 * 14 * The above copyright notice and this permission notice shall be included in 15 * all copies or substantial portions of the Software. 16 * 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. */ 24 25 #include "includes.h" 26 #include "dbutil.h" 27 #include "signkey.h" 28 #include "buffer.h" 29 #include "ssh.h" 30 31 /* malloc a new sign_key and set the dss and rsa keys to NULL */ 32 sign_key * new_sign_key() { 33 34 sign_key * ret; 35 36 ret = (sign_key*)m_malloc(sizeof(sign_key)); 37 #ifdef DROPBEAR_DSS 38 ret->dsskey = NULL; 39 #endif 40 #ifdef DROPBEAR_RSA 41 ret->rsakey = NULL; 42 #endif 43 return ret; 44 45 } 46 47 /* Returns "ssh-dss" or "ssh-rsa" corresponding to the type. Exits fatally 48 * if the type is invalid */ 49 const char* signkey_name_from_type(int type, int *namelen) { 50 51 #ifdef DROPBEAR_RSA 52 if (type == DROPBEAR_SIGNKEY_RSA) { 53 *namelen = SSH_SIGNKEY_RSA_LEN; 54 return SSH_SIGNKEY_RSA; 55 } 56 #endif 57 #ifdef DROPBEAR_DSS 58 if (type == DROPBEAR_SIGNKEY_DSS) { 59 *namelen = SSH_SIGNKEY_DSS_LEN; 60 return SSH_SIGNKEY_DSS; 61 } 62 #endif 63 dropbear_exit("bad key type %d", type); 64 return NULL; /* notreached */ 65 } 66 67 /* Returns DROPBEAR_SIGNKEY_RSA, DROPBEAR_SIGNKEY_DSS, 68 * or DROPBEAR_SIGNKEY_NONE */ 69 int signkey_type_from_name(const char* name, int namelen) { 70 71 #ifdef DROPBEAR_RSA 72 if (namelen == SSH_SIGNKEY_RSA_LEN 73 && memcmp(name, SSH_SIGNKEY_RSA, SSH_SIGNKEY_RSA_LEN) == 0) { 74 return DROPBEAR_SIGNKEY_RSA; 75 } 76 #endif 77 #ifdef DROPBEAR_DSS 78 if (namelen == SSH_SIGNKEY_DSS_LEN 79 && memcmp(name, SSH_SIGNKEY_DSS, SSH_SIGNKEY_DSS_LEN) == 0) { 80 return DROPBEAR_SIGNKEY_DSS; 81 } 82 #endif 83 84 return DROPBEAR_SIGNKEY_NONE; 85 } 86 87 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail. 88 * type should be set by the caller to specify the type to read, and 89 * on return is set to the type read (useful when type = _ANY) */ 90 int buf_get_pub_key(buffer *buf, sign_key *key, int *type) { 91 92 unsigned char* ident; 93 unsigned int len; 94 int keytype; 95 int ret = DROPBEAR_FAILURE; 96 97 TRACE(("enter buf_get_pub_key")) 98 99 ident = buf_getstring(buf, &len); 100 keytype = signkey_type_from_name(ident, len); 101 m_free(ident); 102 103 if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) { 104 return DROPBEAR_FAILURE; 105 } 106 107 *type = keytype; 108 109 /* Rewind the buffer back before "ssh-rsa" etc */ 110 buf_incrpos(buf, -len - 4); 111 112 #ifdef DROPBEAR_DSS 113 if (keytype == DROPBEAR_SIGNKEY_DSS) { 114 dss_key_free(key->dsskey); 115 key->dsskey = (dss_key*)m_malloc(sizeof(dss_key)); 116 ret = buf_get_dss_pub_key(buf, key->dsskey); 117 if (ret == DROPBEAR_FAILURE) { 118 m_free(key->dsskey); 119 } 120 } 121 #endif 122 #ifdef DROPBEAR_RSA 123 if (keytype == DROPBEAR_SIGNKEY_RSA) { 124 rsa_key_free(key->rsakey); 125 key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key)); 126 ret = buf_get_rsa_pub_key(buf, key->rsakey); 127 if (ret == DROPBEAR_FAILURE) { 128 m_free(key->rsakey); 129 } 130 } 131 #endif 132 133 TRACE(("leave buf_get_pub_key")) 134 135 return ret; 136 137 } 138 139 /* returns DROPBEAR_SUCCESS on success, DROPBEAR_FAILURE on fail. 140 * type should be set by the caller to specify the type to read, and 141 * on return is set to the type read (useful when type = _ANY) */ 142 int buf_get_priv_key(buffer *buf, sign_key *key, int *type) { 143 144 unsigned char* ident; 145 unsigned int len; 146 int keytype; 147 int ret = DROPBEAR_FAILURE; 148 149 TRACE(("enter buf_get_priv_key")) 150 151 ident = buf_getstring(buf, &len); 152 keytype = signkey_type_from_name(ident, len); 153 m_free(ident); 154 155 if (*type != DROPBEAR_SIGNKEY_ANY && *type != keytype) { 156 TRACE(("wrong key type: %d %d", *type, keytype)) 157 return DROPBEAR_FAILURE; 158 } 159 160 *type = keytype; 161 162 /* Rewind the buffer back before "ssh-rsa" etc */ 163 buf_incrpos(buf, -len - 4); 164 165 #ifdef DROPBEAR_DSS 166 if (keytype == DROPBEAR_SIGNKEY_DSS) { 167 dss_key_free(key->dsskey); 168 key->dsskey = (dss_key*)m_malloc(sizeof(dss_key)); 169 ret = buf_get_dss_priv_key(buf, key->dsskey); 170 if (ret == DROPBEAR_FAILURE) { 171 m_free(key->dsskey); 172 } 173 } 174 #endif 175 #ifdef DROPBEAR_RSA 176 if (keytype == DROPBEAR_SIGNKEY_RSA) { 177 rsa_key_free(key->rsakey); 178 key->rsakey = (rsa_key*)m_malloc(sizeof(rsa_key)); 179 ret = buf_get_rsa_priv_key(buf, key->rsakey); 180 if (ret == DROPBEAR_FAILURE) { 181 m_free(key->rsakey); 182 } 183 } 184 #endif 185 186 TRACE(("leave buf_get_priv_key")) 187 188 return ret; 189 190 } 191 192 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */ 193 void buf_put_pub_key(buffer* buf, sign_key *key, int type) { 194 195 buffer *pubkeys; 196 197 TRACE(("enter buf_put_pub_key")) 198 pubkeys = buf_new(MAX_PUBKEY_SIZE); 199 200 #ifdef DROPBEAR_DSS 201 if (type == DROPBEAR_SIGNKEY_DSS) { 202 buf_put_dss_pub_key(pubkeys, key->dsskey); 203 } 204 #endif 205 #ifdef DROPBEAR_RSA 206 if (type == DROPBEAR_SIGNKEY_RSA) { 207 buf_put_rsa_pub_key(pubkeys, key->rsakey); 208 } 209 #endif 210 if (pubkeys->len == 0) { 211 dropbear_exit("bad key types in buf_put_pub_key"); 212 } 213 214 buf_setpos(pubkeys, 0); 215 buf_putstring(buf, buf_getptr(pubkeys, pubkeys->len), 216 pubkeys->len); 217 218 buf_free(pubkeys); 219 TRACE(("leave buf_put_pub_key")) 220 } 221 222 /* type is either DROPBEAR_SIGNKEY_DSS or DROPBEAR_SIGNKEY_RSA */ 223 void buf_put_priv_key(buffer* buf, sign_key *key, int type) { 224 225 TRACE(("enter buf_put_priv_key")) 226 TRACE(("type is %d", type)) 227 228 #ifdef DROPBEAR_DSS 229 if (type == DROPBEAR_SIGNKEY_DSS) { 230 buf_put_dss_priv_key(buf, key->dsskey); 231 TRACE(("leave buf_put_priv_key: dss done")) 232 return; 233 } 234 #endif 235 #ifdef DROPBEAR_RSA 236 if (type == DROPBEAR_SIGNKEY_RSA) { 237 buf_put_rsa_priv_key(buf, key->rsakey); 238 TRACE(("leave buf_put_priv_key: rsa done")) 239 return; 240 } 241 #endif 242 dropbear_exit("bad key types in put pub key"); 243 } 244 245 void sign_key_free(sign_key *key) { 246 247 TRACE(("enter sign_key_free")) 248 249 #ifdef DROPBEAR_DSS 250 dss_key_free(key->dsskey); 251 key->dsskey = NULL; 252 #endif 253 #ifdef DROPBEAR_RSA 254 rsa_key_free(key->rsakey); 255 key->rsakey = NULL; 256 #endif 257 258 m_free(key); 259 TRACE(("leave sign_key_free")) 260 } 261 262 static char hexdig(unsigned char x) { 263 264 if (x > 0xf) 265 return 'X'; 266 267 if (x < 10) 268 return '0' + x; 269 else 270 return 'a' + x - 10; 271 } 272 273 /* Since we're not sure if we'll have md5 or sha1, we present both. 274 * MD5 is used in preference, but sha1 could still be useful */ 275 #ifdef DROPBEAR_MD5_HMAC 276 static char * sign_key_md5_fingerprint(unsigned char* keyblob, 277 unsigned int keybloblen) { 278 279 char * ret; 280 hash_state hs; 281 unsigned char hash[MD5_HASH_SIZE]; 282 unsigned int i; 283 unsigned int buflen; 284 285 md5_init(&hs); 286 287 /* skip the size int of the string - this is a bit messy */ 288 md5_process(&hs, keyblob, keybloblen); 289 290 md5_done(&hs, hash); 291 292 /* "md5 hexfingerprinthere\0", each hex digit is "AB:" etc */ 293 buflen = 4 + 3*MD5_HASH_SIZE; 294 ret = (char*)m_malloc(buflen); 295 296 memset(ret, 'Z', buflen); 297 strcpy(ret, "md5 "); 298 299 for (i = 0; i < MD5_HASH_SIZE; i++) { 300 unsigned int pos = 4 + i*3; 301 ret[pos] = hexdig(hash[i] >> 4); 302 ret[pos+1] = hexdig(hash[i] & 0x0f); 303 ret[pos+2] = ':'; 304 } 305 ret[buflen-1] = 0x0; 306 307 return ret; 308 } 309 310 #else /* use SHA1 rather than MD5 for fingerprint */ 311 static char * sign_key_sha1_fingerprint(unsigned char* keyblob, 312 unsigned int keybloblen) { 313 314 char * ret; 315 hash_state hs; 316 unsigned char hash[SHA1_HASH_SIZE]; 317 unsigned int i; 318 unsigned int buflen; 319 320 sha1_init(&hs); 321 322 /* skip the size int of the string - this is a bit messy */ 323 sha1_process(&hs, keyblob, keybloblen); 324 325 sha1_done(&hs, hash); 326 327 /* "sha1 hexfingerprinthere\0", each hex digit is "AB:" etc */ 328 buflen = 5 + 3*SHA1_HASH_SIZE; 329 ret = (char*)m_malloc(buflen); 330 331 strcpy(ret, "sha1 "); 332 333 for (i = 0; i < SHA1_HASH_SIZE; i++) { 334 unsigned int pos = 5 + 3*i; 335 ret[pos] = hexdig(hash[i] >> 4); 336 ret[pos+1] = hexdig(hash[i] & 0x0f); 337 ret[pos+2] = ':'; 338 } 339 ret[buflen-1] = 0x0; 340 341 return ret; 342 } 343 344 #endif /* MD5/SHA1 switch */ 345 346 /* This will return a freshly malloced string, containing a fingerprint 347 * in either sha1 or md5 */ 348 char * sign_key_fingerprint(unsigned char* keyblob, unsigned int keybloblen) { 349 350 #ifdef DROPBEAR_MD5_HMAC 351 return sign_key_md5_fingerprint(keyblob, keybloblen); 352 #else 353 return sign_key_sha1_fingerprint(keyblob, keybloblen); 354 #endif 355 } 356 357 void buf_put_sign(buffer* buf, sign_key *key, int type, 358 const unsigned char *data, unsigned int len) { 359 360 buffer *sigblob; 361 362 sigblob = buf_new(MAX_PUBKEY_SIZE); 363 364 #ifdef DROPBEAR_DSS 365 if (type == DROPBEAR_SIGNKEY_DSS) { 366 buf_put_dss_sign(sigblob, key->dsskey, data, len); 367 } 368 #endif 369 #ifdef DROPBEAR_RSA 370 if (type == DROPBEAR_SIGNKEY_RSA) { 371 buf_put_rsa_sign(sigblob, key->rsakey, data, len); 372 } 373 #endif 374 if (sigblob->len == 0) { 375 dropbear_exit("non-matching signing type"); 376 } 377 378 buf_setpos(sigblob, 0); 379 buf_putstring(buf, buf_getptr(sigblob, sigblob->len), 380 sigblob->len); 381 382 buf_free(sigblob); 383 384 } 385 386 #ifdef DROPBEAR_SIGNKEY_VERIFY 387 /* Return DROPBEAR_SUCCESS or DROPBEAR_FAILURE. 388 * If FAILURE is returned, the position of 389 * buf is undefined. If SUCCESS is returned, buf will be positioned after the 390 * signature blob */ 391 int buf_verify(buffer * buf, sign_key *key, const unsigned char *data, 392 unsigned int len) { 393 394 unsigned int bloblen; 395 unsigned char * ident = NULL; 396 unsigned int identlen = 0; 397 398 TRACE(("enter buf_verify")) 399 400 bloblen = buf_getint(buf); 401 ident = buf_getstring(buf, &identlen); 402 403 #ifdef DROPBEAR_DSS 404 if (bloblen == DSS_SIGNATURE_SIZE && 405 memcmp(ident, SSH_SIGNKEY_DSS, identlen) == 0) { 406 m_free(ident); 407 if (key->dsskey == NULL) { 408 dropbear_exit("no dss key to verify signature"); 409 } 410 return buf_dss_verify(buf, key->dsskey, data, len); 411 } 412 #endif 413 414 #ifdef DROPBEAR_RSA 415 if (memcmp(ident, SSH_SIGNKEY_RSA, identlen) == 0) { 416 m_free(ident); 417 if (key->rsakey == NULL) { 418 dropbear_exit("no rsa key to verify signature"); 419 } 420 return buf_rsa_verify(buf, key->rsakey, data, len); 421 } 422 #endif 423 424 m_free(ident); 425 dropbear_exit("non-matching signing type"); 426 return DROPBEAR_FAILURE; 427 } 428 #endif /* DROPBEAR_SIGNKEY_VERIFY */ 429 430 #ifdef DROPBEAR_KEY_LINES /* ie we're using authorized_keys or known_hosts */ 431 432 /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE when given a buffer containing 433 * a key, a key, and a type. The buffer is positioned at the start of the 434 * base64 data, and contains no trailing data */ 435 /* If fingerprint is non-NULL, it will be set to a malloc()ed fingerprint 436 of the key if it is successfully decoded */ 437 int cmp_base64_key(const unsigned char* keyblob, unsigned int keybloblen, 438 const unsigned char* algoname, unsigned int algolen, 439 buffer * line, char ** fingerprint) { 440 441 buffer * decodekey = NULL; 442 int ret = DROPBEAR_FAILURE; 443 unsigned int len, filealgolen; 444 unsigned long decodekeylen; 445 unsigned char* filealgo = NULL; 446 447 /* now we have the actual data */ 448 len = line->len - line->pos; 449 decodekeylen = len * 2; /* big to be safe */ 450 decodekey = buf_new(decodekeylen); 451 452 if (base64_decode(buf_getptr(line, len), len, 453 buf_getwriteptr(decodekey, decodekey->size), 454 &decodekeylen) != CRYPT_OK) { 455 TRACE(("checkpubkey: base64 decode failed")) 456 goto out; 457 } 458 TRACE(("checkpubkey: base64_decode success")) 459 buf_incrlen(decodekey, decodekeylen); 460 461 if (fingerprint) { 462 *fingerprint = sign_key_fingerprint(buf_getptr(decodekey, decodekeylen), 463 decodekeylen); 464 } 465 466 /* compare the keys */ 467 if ( ( decodekeylen != keybloblen ) 468 || memcmp( buf_getptr(decodekey, decodekey->len), 469 keyblob, decodekey->len) != 0) { 470 TRACE(("checkpubkey: compare failed")) 471 goto out; 472 } 473 474 /* ... and also check that the algo specified and the algo in the key 475 * itself match */ 476 filealgolen = buf_getint(decodekey); 477 filealgo = buf_getptr(decodekey, filealgolen); 478 if (filealgolen != algolen || memcmp(filealgo, algoname, algolen) != 0) { 479 TRACE(("checkpubkey: algo match failed")) 480 goto out; 481 } 482 483 /* All checks passed */ 484 ret = DROPBEAR_SUCCESS; 485 486 out: 487 buf_free(decodekey); 488 decodekey = NULL; 489 return ret; 490 } 491 #endif 492