comparison keyimport.c @ 4:fe6bca95afa7

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