1/* 2 * Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com 3 * keyfiles. 4 * 5 * The horribleness of the code is probably mine (matt). 6 * 7 * Modifications copyright 2003 Matt Johnston 8 * 9 * PuTTY is copyright 1997-2003 Simon Tatham. 10 * 11 * Portions copyright Robert de Bath, Joris van Rantwijk, Delian 12 * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry, 13 * Justin Bradford, and CORE SDI S.A. 14 * 15 * Permission is hereby granted, free of charge, to any person 16 * obtaining a copy of this software and associated documentation files 17 * (the "Software"), to deal in the Software without restriction, 18 * including without limitation the rights to use, copy, modify, merge, 19 * publish, distribute, sublicense, and/or sell copies of the Software, 20 * and to permit persons to whom the Software is furnished to do so, 21 * subject to the following conditions: 22 * 23 * The above copyright notice and this permission notice shall be 24 * included in all copies or substantial portions of the Software. 25 * 26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 27 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 28 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 29 * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE 30 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 31 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 32 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 33 */ 34 35#include "keyimport.h" 36#include "bignum.h" 37#include "buffer.h" 38#include "dbutil.h" 39 40#define PUT_32BIT(cp, value) do { \ 41 (cp)[3] = (unsigned char)(value); \ 42 (cp)[2] = (unsigned char)((value) >> 8); \ 43 (cp)[1] = (unsigned char)((value) >> 16); \ 44 (cp)[0] = (unsigned char)((value) >> 24); } while (0) 45 46#define GET_32BIT(cp) \ 47 (((unsigned long)(unsigned char)(cp)[0] << 24) | \ 48 ((unsigned long)(unsigned char)(cp)[1] << 16) | \ 49 ((unsigned long)(unsigned char)(cp)[2] << 8) | \ 50 ((unsigned long)(unsigned char)(cp)[3])) 51 52static int openssh_encrypted(const char *filename); 53static sign_key *openssh_read(const char *filename, char *passphrase); 54static int openssh_write(const char *filename, sign_key *key, 55 char *passphrase); 56 57static int dropbear_write(const char*filename, sign_key * key); 58static sign_key *dropbear_read(const char* filename); 59 60#if 0 61static int sshcom_encrypted(const char *filename, char **comment); 62static struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase); 63static int sshcom_write(const char *filename, struct ssh2_userkey *key, 64 char *passphrase); 65#endif 66 67int import_encrypted(const char* filename, int filetype) { 68 69 if (filetype == KEYFILE_OPENSSH) { 70 return openssh_encrypted(filename); 71#if 0 72 } else if (filetype == KEYFILE_SSHCOM) { 73 return sshcom_encrypted(filename, NULL); 74#endif 75 } 76 return 0; 77} 78 79sign_key *import_read(const char *filename, char *passphrase, int filetype) { 80 81 if (filetype == KEYFILE_OPENSSH) { 82 return openssh_read(filename, passphrase); 83 } else if (filetype == KEYFILE_DROPBEAR) { 84 return dropbear_read(filename); 85#if 0 86 } else if (filetype == KEYFILE_SSHCOM) { 87 return sshcom_read(filename, passphrase); 88#endif 89 } 90 return NULL; 91} 92 93int import_write(const char *filename, sign_key *key, char *passphrase, 94 int filetype) { 95 96 if (filetype == KEYFILE_OPENSSH) { 97 return openssh_write(filename, key, passphrase); 98 } else if (filetype == KEYFILE_DROPBEAR) { 99 return dropbear_write(filename, key); 100#if 0 101 } else if (filetype == KEYFILE_SSHCOM) { 102 return sshcom_write(filename, key, passphrase); 103#endif 104 } 105 return 0; 106} 107 108static sign_key *dropbear_read(const char* filename) { 109 110 buffer * buf = NULL; 111 sign_key *ret = NULL; 112 int type; 113 114 buf = buf_new(MAX_PRIVKEY_SIZE); 115 if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) { 116 goto error; 117 } 118 119 buf_setpos(buf, 0); 120 ret = new_sign_key(); 121 122 type = DROPBEAR_SIGNKEY_ANY; 123 if (buf_get_priv_key(buf, ret, &type) == DROPBEAR_FAILURE){ 124 goto error; 125 } 126 buf_free(buf); 127 128 return ret; 129 130error: 131 if (buf) { 132 buf_free(buf); 133 } 134 if (ret) { 135 sign_key_free(ret); 136 } 137 return NULL; 138} 139 140/* returns 0 on fail, 1 on success */ 141static int dropbear_write(const char*filename, sign_key * key) { 142 143 int keytype = -1; 144 buffer * buf; 145 FILE*fp; 146 int len; 147 int ret; 148 149#ifdef DROPBEAR_RSA 150 if (key->rsakey != NULL) { 151 keytype = DROPBEAR_SIGNKEY_RSA; 152 } 153#endif 154#ifdef DROPBEAR_DSS 155 if (key->dsskey != NULL) { 156 keytype = DROPBEAR_SIGNKEY_DSS; 157 } 158#endif 159 160 buf = buf_new(MAX_PRIVKEY_SIZE); 161 buf_put_priv_key(buf, key, keytype); 162 163 fp = fopen(filename, "w"); 164 if (!fp) { 165 ret = 0; 166 goto out; 167 } 168 169 buf_setpos(buf, 0); 170 do { 171 len = fwrite(buf_getptr(buf, buf->len - buf->pos), 172 1, buf->len - buf->pos, fp); 173 buf_incrpos(buf, len); 174 } while (len > 0 && buf->len != buf->pos); 175 176 fclose(fp); 177 178 if (buf->pos != buf->len) { 179 ret = 0; 180 } else { 181 ret = 1; 182 } 183out: 184 buf_free(buf); 185 return ret; 186} 187 188 189/* ---------------------------------------------------------------------- 190 * Helper routines. (The base64 ones are defined in sshpubk.c.) 191 */ 192 193#define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \ 194 ((c) >= 'a' && (c) <= 'z') || \ 195 ((c) >= '0' && (c) <= '9') || \ 196 (c) == '+' || (c) == '/' || (c) == '=' \ 197 ) 198 199/* cpl has to be less than 100 */ 200static void base64_encode_fp(FILE * fp, unsigned char *data, 201 int datalen, int cpl) 202{ 203 char out[100]; 204 int n; 205 unsigned long outlen; 206 int rawcpl; 207 rawcpl = cpl * 3 / 4; 208 dropbear_assert((unsigned int)cpl < sizeof(out)); 209 210 while (datalen > 0) { 211 n = (datalen < rawcpl ? datalen : rawcpl); 212 outlen = sizeof(out); 213 base64_encode(data, n, out, &outlen); 214 data += n; 215 datalen -= n; 216 fwrite(out, 1, outlen, fp); 217 fputc('\n', fp); 218 } 219} 220/* 221 * Read an ASN.1/BER identifier and length pair. 222 * 223 * Flags are a combination of the #defines listed below. 224 * 225 * Returns -1 if unsuccessful; otherwise returns the number of 226 * bytes used out of the source data. 227 */ 228 229/* ASN.1 tag classes. */ 230#define ASN1_CLASS_UNIVERSAL (0 << 6) 231#define ASN1_CLASS_APPLICATION (1 << 6) 232#define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6) 233#define ASN1_CLASS_PRIVATE (3 << 6) 234#define ASN1_CLASS_MASK (3 << 6) 235 236/* Primitive versus constructed bit. */ 237#define ASN1_CONSTRUCTED (1 << 5) 238 239static int ber_read_id_len(void *source, int sourcelen, 240 int *id, int *length, int *flags) 241{ 242 unsigned char *p = (unsigned char *) source; 243 244 if (sourcelen == 0) 245 return -1; 246 247 *flags = (*p & 0xE0); 248 if ((*p & 0x1F) == 0x1F) { 249 *id = 0; 250 while (*p & 0x80) { 251 *id = (*id << 7) | (*p & 0x7F); 252 p++, sourcelen--; 253 if (sourcelen == 0) 254 return -1; 255 } 256 *id = (*id << 7) | (*p & 0x7F); 257 p++, sourcelen--; 258 } else { 259 *id = *p & 0x1F; 260 p++, sourcelen--; 261 } 262 263 if (sourcelen == 0) 264 return -1; 265 266 if (*p & 0x80) { 267 int n = *p & 0x7F; 268 p++, sourcelen--; 269 if (sourcelen < n) 270 return -1; 271 *length = 0; 272 while (n--) 273 *length = (*length << 8) | (*p++); 274 sourcelen -= n; 275 } else { 276 *length = *p; 277 p++, sourcelen--; 278 } 279 280 return p - (unsigned char *) source; 281} 282 283/* 284 * Write an ASN.1/BER identifier and length pair. Returns the 285 * number of bytes consumed. Assumes dest contains enough space. 286 * Will avoid writing anything if dest is NULL, but still return 287 * amount of space required. 288 */ 289static int ber_write_id_len(void *dest, int id, int length, int flags) 290{ 291 unsigned char *d = (unsigned char *)dest; 292 int len = 0; 293 294 if (id <= 30) { 295 /* 296 * Identifier is one byte. 297 */ 298 len++; 299 if (d) *d++ = id | flags; 300 } else { 301 int n; 302 /* 303 * Identifier is multiple bytes: the first byte is 11111 304 * plus the flags, and subsequent bytes encode the value of 305 * the identifier, 7 bits at a time, with the top bit of 306 * each byte 1 except the last one which is 0. 307 */ 308 len++; 309 if (d) *d++ = 0x1F | flags; 310 for (n = 1; (id >> (7*n)) > 0; n++) 311 continue; /* count the bytes */ 312 while (n--) { 313 len++; 314 if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F); 315 } 316 } 317 318 if (length < 128) { 319 /* 320 * Length is one byte. 321 */ 322 len++; 323 if (d) *d++ = length; 324 } else { 325 int n; 326 /* 327 * Length is multiple bytes. The first is 0x80 plus the 328 * number of subsequent bytes, and the subsequent bytes 329 * encode the actual length. 330 */ 331 for (n = 1; (length >> (8*n)) > 0; n++) 332 continue; /* count the bytes */ 333 len++; 334 if (d) *d++ = 0x80 | n; 335 while (n--) { 336 len++; 337 if (d) *d++ = (length >> (8*n)) & 0xFF; 338 } 339 } 340 341 return len; 342} 343 344 345/* Simple structure to point to an mp-int within a blob. */ 346struct mpint_pos { void *start; int bytes; }; 347 348/* ---------------------------------------------------------------------- 349 * Code to read and write OpenSSH private keys. 350 */ 351 352enum { OSSH_DSA, OSSH_RSA }; 353struct openssh_key { 354 int type; 355 int encrypted; 356 char iv[32]; 357 unsigned char *keyblob; 358 unsigned int keyblob_len, keyblob_size; 359}; 360 361static struct openssh_key *load_openssh_key(const char *filename) 362{ 363 struct openssh_key *ret; 364 FILE *fp = NULL; 365 char buffer[256]; 366 char *errmsg = NULL, *p = NULL; 367 int headers_done; 368 unsigned long len, outlen; 369 370 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); 371 ret->keyblob = NULL; 372 ret->keyblob_len = ret->keyblob_size = 0; 373 ret->encrypted = 0; 374 memset(ret->iv, 0, sizeof(ret->iv)); 375 376 if (strlen(filename) == 1 && filename[0] == '-') { 377 fp = stdin; 378 } else { 379 fp = fopen(filename, "r"); 380 } 381 if (!fp) { 382 errmsg = "Unable to open key file"; 383 goto error; 384 } 385 if (!fgets(buffer, sizeof(buffer), fp) || 386 0 != strncmp(buffer, "-----BEGIN ", 11) || 387 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) { 388 errmsg = "File does not begin with OpenSSH key header"; 389 goto error; 390 } 391 if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) 392 ret->type = OSSH_RSA; 393 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) 394 ret->type = OSSH_DSA; 395 else { 396 errmsg = "Unrecognised key type"; 397 goto error; 398 } 399 400 headers_done = 0; 401 while (1) { 402 if (!fgets(buffer, sizeof(buffer), fp)) { 403 errmsg = "Unexpected end of file"; 404 goto error; 405 } 406 if (0 == strncmp(buffer, "-----END ", 9) && 407 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) 408 break; /* done */ 409 if ((p = strchr(buffer, ':')) != NULL) { 410 if (headers_done) { 411 errmsg = "Header found in body of key data"; 412 goto error; 413 } 414 *p++ = '\0'; 415 while (*p && isspace((unsigned char)*p)) p++; 416 if (!strcmp(buffer, "Proc-Type")) { 417 if (p[0] != '4' || p[1] != ',') { 418 errmsg = "Proc-Type is not 4 (only 4 is supported)"; 419 goto error; 420 } 421 p += 2; 422 if (!strcmp(p, "ENCRYPTED\n")) 423 ret->encrypted = 1; 424 } else if (!strcmp(buffer, "DEK-Info")) { 425 int i, j; 426 427 if (strncmp(p, "DES-EDE3-CBC,", 13)) { 428 errmsg = "Ciphers other than DES-EDE3-CBC not supported"; 429 goto error; 430 } 431 p += 13; 432 for (i = 0; i < 8; i++) { 433 if (1 != sscanf(p, "%2x", &j)) 434 break; 435 ret->iv[i] = j; 436 p += 2; 437 } 438 if (i < 8) { 439 errmsg = "Expected 16-digit iv in DEK-Info"; 440 goto error; 441 } 442 } 443 } else { 444 headers_done = 1; 445 len = strlen(buffer); 446 outlen = len*4/3; 447 if (ret->keyblob_len + outlen > ret->keyblob_size) { 448 ret->keyblob_size = ret->keyblob_len + outlen + 256; 449 ret->keyblob = (unsigned char*)m_realloc(ret->keyblob, 450 ret->keyblob_size); 451 } 452 outlen = ret->keyblob_size - ret->keyblob_len; 453 if (base64_decode(buffer, len, 454 ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){ 455 errmsg = "Error decoding base64"; 456 goto error; 457 } 458 ret->keyblob_len += outlen; 459 } 460 } 461 462 if (ret->keyblob_len == 0 || !ret->keyblob) { 463 errmsg = "Key body not present"; 464 goto error; 465 } 466 467 if (ret->encrypted && ret->keyblob_len % 8 != 0) { 468 errmsg = "Encrypted key blob is not a multiple of cipher block size"; 469 goto error; 470 } 471 472 memset(buffer, 0, sizeof(buffer)); 473 return ret; 474 475 error: 476 memset(buffer, 0, sizeof(buffer)); 477 if (ret) { 478 if (ret->keyblob) { 479 memset(ret->keyblob, 0, ret->keyblob_size); 480 m_free(ret->keyblob); 481 } 482 memset(&ret, 0, sizeof(ret)); 483 m_free(ret); 484 } 485 if (fp) { 486 fclose(fp); 487 } 488 if (errmsg) { 489 fprintf(stderr, "Error: %s\n", errmsg); 490 } 491 return NULL; 492} 493 494static int openssh_encrypted(const char *filename) 495{ 496 struct openssh_key *key = load_openssh_key(filename); 497 int ret; 498 499 if (!key) 500 return 0; 501 ret = key->encrypted; 502 memset(key->keyblob, 0, key->keyblob_size); 503 m_free(key->keyblob); 504 memset(&key, 0, sizeof(key)); 505 m_free(key); 506 return ret; 507} 508 509static sign_key *openssh_read(const char *filename, char *passphrase) 510{ 511 struct openssh_key *key; 512 unsigned char *p; 513 int ret, id, len, flags; 514 int i, num_integers = 0; 515 sign_key *retval = NULL; 516 char *errmsg; 517 char *modptr = NULL; 518 int modlen = -9999; 519 int type; 520 521 sign_key *retkey; 522 buffer * blobbuf = NULL; 523 524 key = load_openssh_key(filename); 525 526 if (!key) 527 return NULL; 528 529 if (key->encrypted) { 530 errmsg = "encrypted keys not supported currently"; 531 goto error; 532#if 0 533 /* matt TODO */ 534 /* 535 * Derive encryption key from passphrase and iv/salt: 536 * 537 * - let block A equal MD5(passphrase || iv) 538 * - let block B equal MD5(A || passphrase || iv) 539 * - block C would be MD5(B || passphrase || iv) and so on 540 * - encryption key is the first N bytes of A || B 541 */ 542 struct MD5Context md5c; 543 unsigned char keybuf[32]; 544 545 MD5Init(&md5c); 546 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); 547 MD5Update(&md5c, (unsigned char *)key->iv, 8); 548 MD5Final(keybuf, &md5c); 549 550 MD5Init(&md5c); 551 MD5Update(&md5c, keybuf, 16); 552 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); 553 MD5Update(&md5c, (unsigned char *)key->iv, 8); 554 MD5Final(keybuf+16, &md5c); 555 556 /* 557 * Now decrypt the key blob. 558 */ 559 des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv, 560 key->keyblob, key->keyblob_len); 561 562 memset(&md5c, 0, sizeof(md5c)); 563 memset(keybuf, 0, sizeof(keybuf)); 564#endif 565 } 566 567 /* 568 * Now we have a decrypted key blob, which contains an ASN.1 569 * encoded private key. We must now untangle the ASN.1. 570 * 571 * We expect the whole key blob to be formatted as a SEQUENCE 572 * (0x30 followed by a length code indicating that the rest of 573 * the blob is part of the sequence). Within that SEQUENCE we 574 * expect to see a bunch of INTEGERs. What those integers mean 575 * depends on the key type: 576 * 577 * - For RSA, we expect the integers to be 0, n, e, d, p, q, 578 * dmp1, dmq1, iqmp in that order. (The last three are d mod 579 * (p-1), d mod (q-1), inverse of q mod p respectively.) 580 * 581 * - For DSA, we expect them to be 0, p, q, g, y, x in that 582 * order. 583 */ 584 585 p = key->keyblob; 586 587 /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */ 588 ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); 589 p += ret; 590 if (ret < 0 || id != 16) { 591 errmsg = "ASN.1 decoding failure - wrong password?"; 592 goto error; 593 } 594 595 /* Expect a load of INTEGERs. */ 596 if (key->type == OSSH_RSA) 597 num_integers = 9; 598 else if (key->type == OSSH_DSA) 599 num_integers = 6; 600 601 /* 602 * Space to create key blob in. 603 */ 604 blobbuf = buf_new(3000); 605 606 if (key->type == OSSH_DSA) { 607 buf_putstring(blobbuf, "ssh-dss", 7); 608 } else if (key->type == OSSH_RSA) { 609 buf_putstring(blobbuf, "ssh-rsa", 7); 610 } 611 612 for (i = 0; i < num_integers; i++) { 613 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, 614 &id, &len, &flags); 615 p += ret; 616 if (ret < 0 || id != 2 || 617 key->keyblob+key->keyblob_len-p < len) { 618 errmsg = "ASN.1 decoding failure"; 619 goto error; 620 } 621 622 if (i == 0) { 623 /* 624 * The first integer should be zero always (I think 625 * this is some sort of version indication). 626 */ 627 if (len != 1 || p[0] != 0) { 628 errmsg = "Version number mismatch"; 629 goto error; 630 } 631 } else if (key->type == OSSH_RSA) { 632 /* 633 * OpenSSH key order is n, e, d, p, q, dmp1, dmq1, iqmp 634 * but we want e, n, d, p, q 635 */ 636 if (i == 1) { 637 /* Save the details for after we deal with number 2. */ 638 modptr = (char *)p; 639 modlen = len; 640 } else if (i >= 2 && i <= 5) { 641 buf_putstring(blobbuf, p, len); 642 if (i == 2) { 643 buf_putstring(blobbuf, modptr, modlen); 644 } 645 } 646 } else if (key->type == OSSH_DSA) { 647 /* 648 * OpenSSH key order is p, q, g, y, x, 649 * we want the same. 650 */ 651 buf_putstring(blobbuf, p, len); 652 } 653 654 /* Skip past the number. */ 655 p += len; 656 } 657 658 /* 659 * Now put together the actual key. Simplest way to do this is 660 * to assemble our own key blobs and feed them to the createkey 661 * functions; this is a bit faffy but it does mean we get all 662 * the sanity checks for free. 663 */ 664 retkey = new_sign_key(); 665 buf_setpos(blobbuf, 0); 666 type = DROPBEAR_SIGNKEY_ANY; 667 if (buf_get_priv_key(blobbuf, retkey, &type) 668 != DROPBEAR_SUCCESS) { 669 errmsg = "unable to create key structure"; 670 sign_key_free(retkey); 671 retkey = NULL; 672 goto error; 673 } 674 675 errmsg = NULL; /* no error */ 676 retval = retkey; 677 678 error: 679 if (blobbuf) { 680 buf_burn(blobbuf); 681 buf_free(blobbuf); 682 } 683 m_burn(key->keyblob, key->keyblob_size); 684 m_free(key->keyblob); 685 m_burn(key, sizeof(key)); 686 m_free(key); 687 if (errmsg) { 688 fprintf(stderr, "Error: %s\n", errmsg); 689 } 690 return retval; 691} 692 693static int openssh_write(const char *filename, sign_key *key, 694 char *passphrase) 695{ 696 buffer * keyblob = NULL; 697 buffer * extrablob = NULL; /* used for calculated values to write */ 698 unsigned char *outblob = NULL; 699 int outlen = -9999; 700 struct mpint_pos numbers[9]; 701 int nnumbers = -1, pos, len, seqlen, i; 702 char *header = NULL, *footer = NULL; 703 char zero[1]; 704 unsigned char iv[8]; 705 int ret = 0; 706 FILE *fp; 707 int keytype = -1; 708 709#ifdef DROPBEAR_RSA 710 mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */ 711 712 if (key->rsakey != NULL) { 713 keytype = DROPBEAR_SIGNKEY_RSA; 714 } 715#endif 716#ifdef DROPBEAR_DSS 717 if (key->dsskey != NULL) { 718 keytype = DROPBEAR_SIGNKEY_DSS; 719 } 720#endif 721 722 dropbear_assert(keytype != -1); 723 724 /* 725 * Fetch the key blobs. 726 */ 727 keyblob = buf_new(3000); 728 buf_put_priv_key(keyblob, key, keytype); 729 730 buf_setpos(keyblob, 0); 731 /* skip the "ssh-rsa" or "ssh-dss" header */ 732 buf_incrpos(keyblob, buf_getint(keyblob)); 733 734 /* 735 * Find the sequence of integers to be encoded into the OpenSSH 736 * key blob, and also decide on the header line. 737 */ 738 numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; 739 740#ifdef DROPBEAR_RSA 741 if (keytype == DROPBEAR_SIGNKEY_RSA) { 742 743 if (key->rsakey->p == NULL || key->rsakey->q == NULL) { 744 fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n"); 745 goto error; 746 } 747 748 /* e */ 749 numbers[2].bytes = buf_getint(keyblob); 750 numbers[2].start = buf_getptr(keyblob, numbers[2].bytes); 751 buf_incrpos(keyblob, numbers[2].bytes); 752 753 /* n */ 754 numbers[1].bytes = buf_getint(keyblob); 755 numbers[1].start = buf_getptr(keyblob, numbers[1].bytes); 756 buf_incrpos(keyblob, numbers[1].bytes); 757 758 /* d */ 759 numbers[3].bytes = buf_getint(keyblob); 760 numbers[3].start = buf_getptr(keyblob, numbers[3].bytes); 761 buf_incrpos(keyblob, numbers[3].bytes); 762 763 /* p */ 764 numbers[4].bytes = buf_getint(keyblob); 765 numbers[4].start = buf_getptr(keyblob, numbers[4].bytes); 766 buf_incrpos(keyblob, numbers[4].bytes); 767 768 /* q */ 769 numbers[5].bytes = buf_getint(keyblob); 770 numbers[5].start = buf_getptr(keyblob, numbers[5].bytes); 771 buf_incrpos(keyblob, numbers[5].bytes); 772 773 /* now calculate some extra parameters: */ 774 m_mp_init(&tmpval); 775 m_mp_init(&dmp1); 776 m_mp_init(&dmq1); 777 m_mp_init(&iqmp); 778 779 /* dmp1 = d mod (p-1) */ 780 if (mp_sub_d(key->rsakey->p, 1, &tmpval) != MP_OKAY) { 781 fprintf(stderr, "Bignum error for p-1\n"); 782 goto error; 783 } 784 if (mp_mod(key->rsakey->d, &tmpval, &dmp1) != MP_OKAY) { 785 fprintf(stderr, "Bignum error for dmp1\n"); 786 goto error; 787 } 788 789 /* dmq1 = d mod (q-1) */ 790 if (mp_sub_d(key->rsakey->q, 1, &tmpval) != MP_OKAY) { 791 fprintf(stderr, "Bignum error for q-1\n"); 792 goto error; 793 } 794 if (mp_mod(key->rsakey->d, &tmpval, &dmq1) != MP_OKAY) { 795 fprintf(stderr, "Bignum error for dmq1\n"); 796 goto error; 797 } 798 799 /* iqmp = (q^-1) mod p */ 800 if (mp_invmod(key->rsakey->q, key->rsakey->p, &iqmp) != MP_OKAY) { 801 fprintf(stderr, "Bignum error for iqmp\n"); 802 goto error; 803 } 804 805 extrablob = buf_new(2000); 806 buf_putmpint(extrablob, &dmp1); 807 buf_putmpint(extrablob, &dmq1); 808 buf_putmpint(extrablob, &iqmp); 809 buf_setpos(extrablob, 0); 810 mp_clear(&dmp1); 811 mp_clear(&dmq1); 812 mp_clear(&iqmp); 813 mp_clear(&tmpval); 814 815 /* dmp1 */ 816 numbers[6].bytes = buf_getint(extrablob); 817 numbers[6].start = buf_getptr(extrablob, numbers[6].bytes); 818 buf_incrpos(extrablob, numbers[6].bytes); 819 820 /* dmq1 */ 821 numbers[7].bytes = buf_getint(extrablob); 822 numbers[7].start = buf_getptr(extrablob, numbers[7].bytes); 823 buf_incrpos(extrablob, numbers[7].bytes); 824 825 /* iqmp */ 826 numbers[8].bytes = buf_getint(extrablob); 827 numbers[8].start = buf_getptr(extrablob, numbers[8].bytes); 828 buf_incrpos(extrablob, numbers[8].bytes); 829 830 nnumbers = 9; 831 header = "-----BEGIN RSA PRIVATE KEY-----\n"; 832 footer = "-----END RSA PRIVATE KEY-----\n"; 833 } 834#endif /* DROPBEAR_RSA */ 835 836#ifdef DROPBEAR_DSS 837 if (keytype == DROPBEAR_SIGNKEY_DSS) { 838 839 /* p */ 840 numbers[1].bytes = buf_getint(keyblob); 841 numbers[1].start = buf_getptr(keyblob, numbers[1].bytes); 842 buf_incrpos(keyblob, numbers[1].bytes); 843 844 /* q */ 845 numbers[2].bytes = buf_getint(keyblob); 846 numbers[2].start = buf_getptr(keyblob, numbers[2].bytes); 847 buf_incrpos(keyblob, numbers[2].bytes); 848 849 /* g */ 850 numbers[3].bytes = buf_getint(keyblob); 851 numbers[3].start = buf_getptr(keyblob, numbers[3].bytes); 852 buf_incrpos(keyblob, numbers[3].bytes); 853 854 /* y */ 855 numbers[4].bytes = buf_getint(keyblob); 856 numbers[4].start = buf_getptr(keyblob, numbers[4].bytes); 857 buf_incrpos(keyblob, numbers[4].bytes); 858 859 /* x */ 860 numbers[5].bytes = buf_getint(keyblob); 861 numbers[5].start = buf_getptr(keyblob, numbers[5].bytes); 862 buf_incrpos(keyblob, numbers[5].bytes); 863 864 nnumbers = 6; 865 header = "-----BEGIN DSA PRIVATE KEY-----\n"; 866 footer = "-----END DSA PRIVATE KEY-----\n"; 867 } 868#endif /* DROPBEAR_DSS */ 869 870 /* 871 * Now count up the total size of the ASN.1 encoded integers, 872 * so as to determine the length of the containing SEQUENCE. 873 */ 874 len = 0; 875 for (i = 0; i < nnumbers; i++) { 876 len += ber_write_id_len(NULL, 2, numbers[i].bytes, 0); 877 len += numbers[i].bytes; 878 } 879 seqlen = len; 880 /* Now add on the SEQUENCE header. */ 881 len += ber_write_id_len(NULL, 16, seqlen, ASN1_CONSTRUCTED); 882 /* Round up to the cipher block size, ensuring we have at least one 883 * byte of padding (see below). */ 884 outlen = len; 885 if (passphrase) 886 outlen = (outlen+8) &~ 7; 887 888 /* 889 * Now we know how big outblob needs to be. Allocate it. 890 */ 891 outblob = (unsigned char*)m_malloc(outlen); 892 893 /* 894 * And write the data into it. 895 */ 896 pos = 0; 897 pos += ber_write_id_len(outblob+pos, 16, seqlen, ASN1_CONSTRUCTED); 898 for (i = 0; i < nnumbers; i++) { 899 pos += ber_write_id_len(outblob+pos, 2, numbers[i].bytes, 0); 900 memcpy(outblob+pos, numbers[i].start, numbers[i].bytes); 901 pos += numbers[i].bytes; 902 } 903 904 /* 905 * Padding on OpenSSH keys is deterministic. The number of 906 * padding bytes is always more than zero, and always at most 907 * the cipher block length. The value of each padding byte is 908 * equal to the number of padding bytes. So a plaintext that's 909 * an exact multiple of the block size will be padded with 08 910 * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a 911 * plaintext one byte less than a multiple of the block size 912 * will be padded with just 01. 913 * 914 * This enables the OpenSSL key decryption function to strip 915 * off the padding algorithmically and return the unpadded 916 * plaintext to the next layer: it looks at the final byte, and 917 * then expects to find that many bytes at the end of the data 918 * with the same value. Those are all removed and the rest is 919 * returned. 920 */ 921 dropbear_assert(pos == len); 922 while (pos < outlen) { 923 outblob[pos++] = outlen - len; 924 } 925 926 /* 927 * Encrypt the key. 928 */ 929 if (passphrase) { 930 fprintf(stderr, "Encrypted keys aren't supported currently\n"); 931 goto error; 932 } 933 934 /* 935 * And save it. We'll use Unix line endings just in case it's 936 * subsequently transferred in binary mode. 937 */ 938 if (strlen(filename) == 1 && filename[0] == '-') { 939 fp = stdout; 940 } else { 941 fp = fopen(filename, "wb"); /* ensure Unix line endings */ 942 } 943 if (!fp) { 944 fprintf(stderr, "Failed opening output file\n"); 945 goto error; 946 } 947 fputs(header, fp); 948 base64_encode_fp(fp, outblob, outlen, 64); 949 fputs(footer, fp); 950 fclose(fp); 951 ret = 1; 952 953 error: 954 if (outblob) { 955 memset(outblob, 0, outlen); 956 m_free(outblob); 957 } 958 if (keyblob) { 959 buf_burn(keyblob); 960 buf_free(keyblob); 961 } 962 if (extrablob) { 963 buf_burn(extrablob); 964 buf_free(extrablob); 965 } 966 return ret; 967} 968 969#if 0 970/* XXX TODO ssh.com stuff isn't going yet */ 971 972/* ---------------------------------------------------------------------- 973 * Code to read ssh.com private keys. 974 */ 975 976/* 977 * The format of the base64 blob is largely ssh2-packet-formatted, 978 * except that mpints are a bit different: they're more like the 979 * old ssh1 mpint. You have a 32-bit bit count N, followed by 980 * (N+7)/8 bytes of data. 981 * 982 * So. The blob contains: 983 * 984 * - uint32 0x3f6ff9eb (magic number) 985 * - uint32 size (total blob size) 986 * - string key-type (see below) 987 * - string cipher-type (tells you if key is encrypted) 988 * - string encrypted-blob 989 * 990 * (The first size field includes the size field itself and the 991 * magic number before it. All other size fields are ordinary ssh2 992 * strings, so the size field indicates how much data is to 993 * _follow_.) 994 * 995 * The encrypted blob, once decrypted, contains a single string 996 * which in turn contains the payload. (This allows padding to be 997 * added after that string while still making it clear where the 998 * real payload ends. Also it probably makes for a reasonable 999 * decryption check.) 1000 * 1001 * The payload blob, for an RSA key, contains: 1002 * - mpint e 1003 * - mpint d 1004 * - mpint n (yes, the public and private stuff is intermixed) 1005 * - mpint u (presumably inverse of p mod q) 1006 * - mpint p (p is the smaller prime) 1007 * - mpint q (q is the larger) 1008 * 1009 * For a DSA key, the payload blob contains: 1010 * - uint32 0 1011 * - mpint p 1012 * - mpint g 1013 * - mpint q 1014 * - mpint y 1015 * - mpint x 1016 * 1017 * Alternatively, if the parameters are `predefined', that 1018 * (0,p,g,q) sequence can be replaced by a uint32 1 and a string 1019 * containing some predefined parameter specification. *shudder*, 1020 * but I doubt we'll encounter this in real life. 1021 * 1022 * The key type strings are ghastly. The RSA key I looked at had a 1023 * type string of 1024 * 1025 * `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}' 1026 * 1027 * and the DSA key wasn't much better: 1028 * 1029 * `dl-modp{sign{dsa-nist-sha1},dh{plain}}' 1030 * 1031 * It isn't clear that these will always be the same. I think it 1032 * might be wise just to look at the `if-modn{sign{rsa' and 1033 * `dl-modp{sign{dsa' prefixes. 1034 * 1035 * Finally, the encryption. The cipher-type string appears to be 1036 * either `none' or `3des-cbc'. Looks as if this is SSH2-style 1037 * 3des-cbc (i.e. outer cbc rather than inner). The key is created 1038 * from the passphrase by means of yet another hashing faff: 1039 * 1040 * - first 16 bytes are MD5(passphrase) 1041 * - next 16 bytes are MD5(passphrase || first 16 bytes) 1042 * - if there were more, they'd be MD5(passphrase || first 32), 1043 * and so on. 1044 */ 1045 1046#define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb 1047 1048struct sshcom_key { 1049 char comment[256]; /* allowing any length is overkill */ 1050 unsigned char *keyblob; 1051 int keyblob_len, keyblob_size; 1052}; 1053 1054static struct sshcom_key *load_sshcom_key(const char *filename) 1055{ 1056 struct sshcom_key *ret; 1057 FILE *fp; 1058 char buffer[256]; 1059 int len; 1060 char *errmsg, *p; 1061 int headers_done; 1062 char base64_bit[4]; 1063 int base64_chars = 0; 1064 1065 ret = snew(struct sshcom_key); 1066 ret->comment[0] = '\0'; 1067 ret->keyblob = NULL; 1068 ret->keyblob_len = ret->keyblob_size = 0; 1069 1070 fp = fopen(filename, "r"); 1071 if (!fp) { 1072 errmsg = "Unable to open key file"; 1073 goto error; 1074 } 1075 if (!fgets(buffer, sizeof(buffer), fp) || 1076 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) { 1077 errmsg = "File does not begin with ssh.com key header"; 1078 goto error; 1079 } 1080 1081 headers_done = 0; 1082 while (1) { 1083 if (!fgets(buffer, sizeof(buffer), fp)) { 1084 errmsg = "Unexpected end of file"; 1085 goto error; 1086 } 1087 if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n")) 1088 break; /* done */ 1089 if ((p = strchr(buffer, ':')) != NULL) { 1090 if (headers_done) { 1091 errmsg = "Header found in body of key data"; 1092 goto error; 1093 } 1094 *p++ = '\0'; 1095 while (*p && isspace((unsigned char)*p)) p++; 1096 /* 1097 * Header lines can end in a trailing backslash for 1098 * continuation. 1099 */ 1100 while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) || 1101 p[len-1] != '\n' || p[len-2] == '\\') { 1102 if (len > (int)((p-buffer) + sizeof(buffer)-2)) { 1103 errmsg = "Header line too long to deal with"; 1104 goto error; 1105 } 1106 if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) { 1107 errmsg = "Unexpected end of file"; 1108 goto error; 1109 } 1110 } 1111 p[strcspn(p, "\n")] = '\0'; 1112 if (!strcmp(buffer, "Comment")) { 1113 /* Strip quotes in comment if present. */ 1114 if (p[0] == '"' && p[strlen(p)-1] == '"') { 1115 p++; 1116 p[strlen(p)-1] = '\0'; 1117 } 1118 strncpy(ret->comment, p, sizeof(ret->comment)); 1119 ret->comment[sizeof(ret->comment)-1] = '\0'; 1120 } 1121 } else { 1122 headers_done = 1; 1123 1124 p = buffer; 1125 while (isbase64(*p)) { 1126 base64_bit[base64_chars++] = *p; 1127 if (base64_chars == 4) { 1128 unsigned char out[3]; 1129 1130 base64_chars = 0; 1131 1132 len = base64_decode_atom(base64_bit, out); 1133 1134 if (len <= 0) { 1135 errmsg = "Invalid base64 encoding"; 1136 goto error; 1137 } 1138 1139 if (ret->keyblob_len + len > ret->keyblob_size) { 1140 ret->keyblob_size = ret->keyblob_len + len + 256; 1141 ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, 1142 unsigned char); 1143 } 1144 1145 memcpy(ret->keyblob + ret->keyblob_len, out, len); 1146 ret->keyblob_len += len; 1147 } 1148 1149 p++; 1150 } 1151 } 1152 } 1153 1154 if (ret->keyblob_len == 0 || !ret->keyblob) { 1155 errmsg = "Key body not present"; 1156 goto error; 1157 } 1158 1159 return ret; 1160 1161 error: 1162 if (ret) { 1163 if (ret->keyblob) { 1164 memset(ret->keyblob, 0, ret->keyblob_size); 1165 m_free(ret->keyblob); 1166 } 1167 memset(&ret, 0, sizeof(ret)); 1168 m_free(ret); 1169 } 1170 return NULL; 1171} 1172 1173int sshcom_encrypted(const char *filename, char **comment) 1174{ 1175 struct sshcom_key *key = load_sshcom_key(filename); 1176 int pos, len, answer; 1177 1178 *comment = NULL; 1179 if (!key) 1180 return 0; 1181 1182 /* 1183 * Check magic number. 1184 */ 1185 if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) 1186 return 0; /* key is invalid */ 1187 1188 /* 1189 * Find the cipher-type string. 1190 */ 1191 answer = 0; 1192 pos = 8; 1193 if (key->keyblob_len < pos+4) 1194 goto done; /* key is far too short */ 1195 pos += 4 + GET_32BIT(key->keyblob + pos); /* skip key type */ 1196 if (key->keyblob_len < pos+4) 1197 goto done; /* key is far too short */ 1198 len = GET_32BIT(key->keyblob + pos); /* find cipher-type length */ 1199 if (key->keyblob_len < pos+4+len) 1200 goto done; /* cipher type string is incomplete */ 1201 if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) 1202 answer = 1; 1203 1204 done: 1205 *comment = dupstr(key->comment); 1206 memset(key->keyblob, 0, key->keyblob_size); 1207 m_free(key->keyblob); 1208 memset(&key, 0, sizeof(key)); 1209 m_free(key); 1210 return answer; 1211} 1212 1213static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) 1214{ 1215 int bits; 1216 int bytes; 1217 unsigned char *d = (unsigned char *) data; 1218 1219 if (len < 4) 1220 goto error; 1221 bits = GET_32BIT(d); 1222 1223 bytes = (bits + 7) / 8; 1224 if (len < 4+bytes) 1225 goto error; 1226 1227 ret->start = d + 4; 1228 ret->bytes = bytes; 1229 return bytes+4; 1230 1231 error: 1232 ret->start = NULL; 1233 ret->bytes = -1; 1234 return len; /* ensure further calls fail as well */ 1235} 1236 1237static int sshcom_put_mpint(void *target, void *data, int len) 1238{ 1239 unsigned char *d = (unsigned char *)target; 1240 unsigned char *i = (unsigned char *)data; 1241 int bits = len * 8 - 1; 1242 1243 while (bits > 0) { 1244 if (*i & (1 << (bits & 7))) 1245 break; 1246 if (!(bits-- & 7)) 1247 i++, len--; 1248 } 1249 1250 PUT_32BIT(d, bits+1); 1251 memcpy(d+4, i, len); 1252 return len+4; 1253} 1254 1255sign_key *sshcom_read(const char *filename, char *passphrase) 1256{ 1257 struct sshcom_key *key = load_sshcom_key(filename); 1258 char *errmsg; 1259 int pos, len; 1260 const char prefix_rsa[] = "if-modn{sign{rsa"; 1261 const char prefix_dsa[] = "dl-modp{sign{dsa"; 1262 enum { RSA, DSA } type; 1263 int encrypted; 1264 char *ciphertext; 1265 int cipherlen; 1266 struct ssh2_userkey *ret = NULL, *retkey; 1267 const struct ssh_signkey *alg; 1268 unsigned char *blob = NULL; 1269 int blobsize, publen, privlen; 1270 1271 if (!key) 1272 return NULL; 1273 1274 /* 1275 * Check magic number. 1276 */ 1277 if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) { 1278 errmsg = "Key does not begin with magic number"; 1279 goto error; 1280 } 1281 1282 /* 1283 * Determine the key type. 1284 */ 1285 pos = 8; 1286 if (key->keyblob_len < pos+4 || 1287 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { 1288 errmsg = "Key blob does not contain a key type string"; 1289 goto error; 1290 } 1291 if (len > sizeof(prefix_rsa) - 1 && 1292 !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) { 1293 type = RSA; 1294 } else if (len > sizeof(prefix_dsa) - 1 && 1295 !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { 1296 type = DSA; 1297 } else { 1298 errmsg = "Key is of unknown type"; 1299 goto error; 1300 } 1301 pos += 4+len; 1302 1303 /* 1304 * Determine the cipher type. 1305 */ 1306 if (key->keyblob_len < pos+4 || 1307 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { 1308 errmsg = "Key blob does not contain a cipher type string"; 1309 goto error; 1310 } 1311 if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) 1312 encrypted = 0; 1313 else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) 1314 encrypted = 1; 1315 else { 1316 errmsg = "Key encryption is of unknown type"; 1317 goto error; 1318 } 1319 pos += 4+len; 1320 1321 /* 1322 * Get hold of the encrypted part of the key. 1323 */ 1324 if (key->keyblob_len < pos+4 || 1325 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) { 1326 errmsg = "Key blob does not contain actual key data"; 1327 goto error; 1328 } 1329 ciphertext = (char *)key->keyblob + pos + 4; 1330 cipherlen = len; 1331 if (cipherlen == 0) { 1332 errmsg = "Length of key data is zero"; 1333 goto error; 1334 } 1335 1336 /* 1337 * Decrypt it if necessary. 1338 */ 1339 if (encrypted) { 1340 /* 1341 * Derive encryption key from passphrase and iv/salt: 1342 * 1343 * - let block A equal MD5(passphrase) 1344 * - let block B equal MD5(passphrase || A) 1345 * - block C would be MD5(passphrase || A || B) and so on 1346 * - encryption key is the first N bytes of A || B 1347 */ 1348 struct MD5Context md5c; 1349 unsigned char keybuf[32], iv[8]; 1350 1351 if (cipherlen % 8 != 0) { 1352 errmsg = "Encrypted part of key is not a multiple of cipher block" 1353 " size"; 1354 goto error; 1355 } 1356 1357 MD5Init(&md5c); 1358 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); 1359 MD5Final(keybuf, &md5c); 1360 1361 MD5Init(&md5c); 1362 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); 1363 MD5Update(&md5c, keybuf, 16); 1364 MD5Final(keybuf+16, &md5c); 1365 1366 /* 1367 * Now decrypt the key blob. 1368 */ 1369 memset(iv, 0, sizeof(iv)); 1370 des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, 1371 cipherlen); 1372 1373 memset(&md5c, 0, sizeof(md5c)); 1374 memset(keybuf, 0, sizeof(keybuf)); 1375 1376 /* 1377 * Hereafter we return WRONG_PASSPHRASE for any parsing 1378 * error. (But only if we've just tried to decrypt it! 1379 * Returning WRONG_PASSPHRASE for an unencrypted key is 1380 * automatic doom.) 1381 */ 1382 if (encrypted) 1383 ret = SSH2_WRONG_PASSPHRASE; 1384 } 1385 1386 /* 1387 * Strip away the containing string to get to the real meat. 1388 */ 1389 len = GET_32BIT(ciphertext); 1390 if (len > cipherlen-4) { 1391 errmsg = "containing string was ill-formed"; 1392 goto error; 1393 } 1394 ciphertext += 4; 1395 cipherlen = len; 1396 1397 /* 1398 * Now we break down into RSA versus DSA. In either case we'll 1399 * construct public and private blobs in our own format, and 1400 * end up feeding them to alg->createkey(). 1401 */ 1402 blobsize = cipherlen + 256; 1403 blob = snewn(blobsize, unsigned char); 1404 privlen = 0; 1405 if (type == RSA) { 1406 struct mpint_pos n, e, d, u, p, q; 1407 int pos = 0; 1408 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e); 1409 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d); 1410 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n); 1411 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u); 1412 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); 1413 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); 1414 if (!q.start) { 1415 errmsg = "key data did not contain six integers"; 1416 goto error; 1417 } 1418 1419 alg = &ssh_rsa; 1420 pos = 0; 1421 pos += put_string(blob+pos, "ssh-rsa", 7); 1422 pos += put_mp(blob+pos, e.start, e.bytes); 1423 pos += put_mp(blob+pos, n.start, n.bytes); 1424 publen = pos; 1425 pos += put_string(blob+pos, d.start, d.bytes); 1426 pos += put_mp(blob+pos, q.start, q.bytes); 1427 pos += put_mp(blob+pos, p.start, p.bytes); 1428 pos += put_mp(blob+pos, u.start, u.bytes); 1429 privlen = pos - publen; 1430 } else if (type == DSA) { 1431 struct mpint_pos p, q, g, x, y; 1432 int pos = 4; 1433 if (GET_32BIT(ciphertext) != 0) { 1434 errmsg = "predefined DSA parameters not supported"; 1435 goto error; 1436 } 1437 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); 1438 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g); 1439 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); 1440 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y); 1441 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x); 1442 if (!x.start) { 1443 errmsg = "key data did not contain five integers"; 1444 goto error; 1445 } 1446 1447 alg = &ssh_dss; 1448 pos = 0; 1449 pos += put_string(blob+pos, "ssh-dss", 7); 1450 pos += put_mp(blob+pos, p.start, p.bytes); 1451 pos += put_mp(blob+pos, q.start, q.bytes); 1452 pos += put_mp(blob+pos, g.start, g.bytes); 1453 pos += put_mp(blob+pos, y.start, y.bytes); 1454 publen = pos; 1455 pos += put_mp(blob+pos, x.start, x.bytes); 1456 privlen = pos - publen; 1457 } 1458 1459 dropbear_assert(privlen > 0); /* should have bombed by now if not */ 1460 1461 retkey = snew(struct ssh2_userkey); 1462 retkey->alg = alg; 1463 retkey->data = alg->createkey(blob, publen, blob+publen, privlen); 1464 if (!retkey->data) { 1465 m_free(retkey); 1466 errmsg = "unable to create key data structure"; 1467 goto error; 1468 } 1469 retkey->comment = dupstr(key->comment); 1470 1471 errmsg = NULL; /* no error */ 1472 ret = retkey; 1473 1474 error: 1475 if (blob) { 1476 memset(blob, 0, blobsize); 1477 m_free(blob); 1478 } 1479 memset(key->keyblob, 0, key->keyblob_size); 1480 m_free(key->keyblob); 1481 memset(&key, 0, sizeof(key)); 1482 m_free(key); 1483 return ret; 1484} 1485 1486int sshcom_write(const char *filename, sign_key *key, 1487 char *passphrase) 1488{ 1489 unsigned char *pubblob, *privblob; 1490 int publen, privlen; 1491 unsigned char *outblob; 1492 int outlen; 1493 struct mpint_pos numbers[6]; 1494 int nnumbers, initial_zero, pos, lenpos, i; 1495 char *type; 1496 char *ciphertext; 1497 int cipherlen; 1498 int ret = 0; 1499 FILE *fp; 1500 1501 /* 1502 * Fetch the key blobs. 1503 */ 1504 pubblob = key->alg->public_blob(key->data, &publen); 1505 privblob = key->alg->private_blob(key->data, &privlen); 1506 outblob = NULL; 1507 1508 /* 1509 * Find the sequence of integers to be encoded into the OpenSSH 1510 * key blob, and also decide on the header line. 1511 */ 1512 if (key->alg == &ssh_rsa) { 1513 int pos; 1514 struct mpint_pos n, e, d, p, q, iqmp; 1515 1516 pos = 4 + GET_32BIT(pubblob); 1517 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); 1518 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); 1519 pos = 0; 1520 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); 1521 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); 1522 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); 1523 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp); 1524 1525 dropbear_assert(e.start && iqmp.start); /* can't go wrong */ 1526 1527 numbers[0] = e; 1528 numbers[1] = d; 1529 numbers[2] = n; 1530 numbers[3] = iqmp; 1531 numbers[4] = q; 1532 numbers[5] = p; 1533 1534 nnumbers = 6; 1535 initial_zero = 0; 1536 type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; 1537 } else if (key->alg == &ssh_dss) { 1538 int pos; 1539 struct mpint_pos p, q, g, y, x; 1540 1541 pos = 4 + GET_32BIT(pubblob); 1542 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); 1543 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); 1544 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); 1545 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); 1546 pos = 0; 1547 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); 1548 1549 dropbear_assert(y.start && x.start); /* can't go wrong */ 1550 1551 numbers[0] = p; 1552 numbers[1] = g; 1553 numbers[2] = q; 1554 numbers[3] = y; 1555 numbers[4] = x; 1556 1557 nnumbers = 5; 1558 initial_zero = 1; 1559 type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; 1560 } else { 1561 dropbear_assert(0); /* zoinks! */ 1562 } 1563 1564 /* 1565 * Total size of key blob will be somewhere under 512 plus 1566 * combined length of integers. We'll calculate the more 1567 * precise size as we construct the blob. 1568 */ 1569 outlen = 512; 1570 for (i = 0; i < nnumbers; i++) 1571 outlen += 4 + numbers[i].bytes; 1572 outblob = snewn(outlen, unsigned char); 1573 1574 /* 1575 * Create the unencrypted key blob. 1576 */ 1577 pos = 0; 1578 PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4; 1579 pos += 4; /* length field, fill in later */ 1580 pos += put_string(outblob+pos, type, strlen(type)); 1581 { 1582 char *ciphertype = passphrase ? "3des-cbc" : "none"; 1583 pos += put_string(outblob+pos, ciphertype, strlen(ciphertype)); 1584 } 1585 lenpos = pos; /* remember this position */ 1586 pos += 4; /* encrypted-blob size */ 1587 pos += 4; /* encrypted-payload size */ 1588 if (initial_zero) { 1589 PUT_32BIT(outblob+pos, 0); 1590 pos += 4; 1591 } 1592 for (i = 0; i < nnumbers; i++) 1593 pos += sshcom_put_mpint(outblob+pos, 1594 numbers[i].start, numbers[i].bytes); 1595 /* Now wrap up the encrypted payload. */ 1596 PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8)); 1597 /* Pad encrypted blob to a multiple of cipher block size. */ 1598 if (passphrase) { 1599 int padding = -(pos - (lenpos+4)) & 7; 1600 while (padding--) 1601 outblob[pos++] = random_byte(); 1602 } 1603 ciphertext = (char *)outblob+lenpos+4; 1604 cipherlen = pos - (lenpos+4); 1605 dropbear_assert(!passphrase || cipherlen % 8 == 0); 1606 /* Wrap up the encrypted blob string. */ 1607 PUT_32BIT(outblob+lenpos, cipherlen); 1608 /* And finally fill in the total length field. */ 1609 PUT_32BIT(outblob+4, pos); 1610 1611 dropbear_assert(pos < outlen); 1612 1613 /* 1614 * Encrypt the key. 1615 */ 1616 if (passphrase) { 1617 /* 1618 * Derive encryption key from passphrase and iv/salt: 1619 * 1620 * - let block A equal MD5(passphrase) 1621 * - let block B equal MD5(passphrase || A) 1622 * - block C would be MD5(passphrase || A || B) and so on 1623 * - encryption key is the first N bytes of A || B 1624 */ 1625 struct MD5Context md5c; 1626 unsigned char keybuf[32], iv[8]; 1627 1628 MD5Init(&md5c); 1629 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); 1630 MD5Final(keybuf, &md5c); 1631 1632 MD5Init(&md5c); 1633 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); 1634 MD5Update(&md5c, keybuf, 16); 1635 MD5Final(keybuf+16, &md5c); 1636 1637 /* 1638 * Now decrypt the key blob. 1639 */ 1640 memset(iv, 0, sizeof(iv)); 1641 des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, 1642 cipherlen); 1643 1644 memset(&md5c, 0, sizeof(md5c)); 1645 memset(keybuf, 0, sizeof(keybuf)); 1646 } 1647 1648 /* 1649 * And save it. We'll use Unix line endings just in case it's 1650 * subsequently transferred in binary mode. 1651 */ 1652 fp = fopen(filename, "wb"); /* ensure Unix line endings */ 1653 if (!fp) 1654 goto error; 1655 fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); 1656 fprintf(fp, "Comment: \""); 1657 /* 1658 * Comment header is broken with backslash-newline if it goes 1659 * over 70 chars. Although it's surrounded by quotes, it 1660 * _doesn't_ escape backslashes or quotes within the string. 1661 * Don't ask me, I didn't design it. 1662 */ 1663 { 1664 int slen = 60; /* starts at 60 due to "Comment: " */ 1665 char *c = key->comment; 1666 while ((int)strlen(c) > slen) { 1667 fprintf(fp, "%.*s\\\n", slen, c); 1668 c += slen; 1669 slen = 70; /* allow 70 chars on subsequent lines */ 1670 } 1671 fprintf(fp, "%s\"\n", c); 1672 } 1673 base64_encode_fp(fp, outblob, pos, 70); 1674 fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); 1675 fclose(fp); 1676 ret = 1; 1677 1678 error: 1679 if (outblob) { 1680 memset(outblob, 0, outlen); 1681 m_free(outblob); 1682 } 1683 if (privblob) { 1684 memset(privblob, 0, privlen); 1685 m_free(privblob); 1686 } 1687 if (pubblob) { 1688 memset(pubblob, 0, publen); 1689 m_free(pubblob); 1690 } 1691 return ret; 1692} 1693#endif /* ssh.com stuff disabled */ 1694