Add some basic framework code preparatory to adding key export.
[u/mdw/putty] / import.c
CommitLineData
9dda6459 1/*
2 * Code for PuTTY to import and export private key files in other
3 * SSH clients' formats.
4 */
5
6#include <stdio.h>
7#include <stdlib.h>
8#include <assert.h>
9#include <ctype.h>
10
11#include "ssh.h"
12#include "misc.h"
13
14#define PUT_32BIT(cp, value) do { \
15 (cp)[3] = (value); \
16 (cp)[2] = (value) >> 8; \
17 (cp)[1] = (value) >> 16; \
18 (cp)[0] = (value) >> 24; } while (0)
19
20#define GET_32BIT(cp) \
21 (((unsigned long)(unsigned char)(cp)[0] << 24) | \
22 ((unsigned long)(unsigned char)(cp)[1] << 16) | \
23 ((unsigned long)(unsigned char)(cp)[2] << 8) | \
24 ((unsigned long)(unsigned char)(cp)[3]))
25
26int openssh_encrypted(char *filename);
27struct ssh2_userkey *openssh_read(char *filename, char *passphrase);
28
7b4ef1ae 29int sshcom_encrypted(char *filename, char **comment);
30struct ssh2_userkey *sshcom_read(char *filename, char *passphrase);
31
9dda6459 32/*
33 * Given a key type, determine whether we know how to import it.
34 */
35int import_possible(int type)
36{
37 if (type == SSH_KEYTYPE_OPENSSH)
38 return 1;
7b4ef1ae 39 if (type == SSH_KEYTYPE_SSHCOM)
40 return 1;
9dda6459 41 return 0;
42}
43
44/*
45 * Given a key type, determine what native key type
46 * (SSH_KEYTYPE_SSH1 or SSH_KEYTYPE_SSH2) it will come out as once
47 * we've imported it.
48 */
49int import_target_type(int type)
50{
51 /*
52 * There are no known foreign SSH1 key formats.
53 */
54 return SSH_KEYTYPE_SSH2;
55}
56
57/*
58 * Determine whether a foreign key is encrypted.
59 */
60int import_encrypted(char *filename, int type, char **comment)
61{
62 if (type == SSH_KEYTYPE_OPENSSH) {
63 *comment = filename; /* OpenSSH doesn't do key comments */
64 return openssh_encrypted(filename);
65 }
7b4ef1ae 66 if (type == SSH_KEYTYPE_SSHCOM) {
67 return sshcom_encrypted(filename, comment);
68 }
9dda6459 69 return 0;
70}
71
72/*
73 * Import an SSH1 key.
74 */
75int import_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase)
76{
77 return 0;
78}
79
80/*
81 * Import an SSH2 key.
82 */
83struct ssh2_userkey *import_ssh2(char *filename, int type, char *passphrase)
84{
85 if (type == SSH_KEYTYPE_OPENSSH)
86 return openssh_read(filename, passphrase);
7b4ef1ae 87 if (type == SSH_KEYTYPE_SSHCOM)
88 return sshcom_read(filename, passphrase);
9dda6459 89 return NULL;
90}
91
4801c01c 92/*
93 * Export an SSH1 key.
94 */
95int export_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase)
96{
97 return 0;
98}
99
100/*
101 * Export an SSH2 key.
102 */
103int export_ssh2(char *filename, int type,
104 struct ssh2_userkey *key, char *passphrase)
105{
106#if 0
107 if (type == SSH_KEYTYPE_OPENSSH)
108 return openssh_write(filename, key, passphrase);
109 if (type == SSH_KEYTYPE_SSHCOM)
110 return sshcom_write(filename, key, passphrase);
111#endif
112 return 0;
113}
114
9dda6459 115/* ----------------------------------------------------------------------
116 * Helper routines. (The base64 ones are defined in sshpubk.c.)
117 */
118
119#define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \
120 ((c) >= 'a' && (c) <= 'z') || \
121 ((c) >= '0' && (c) <= '9') || \
122 (c) == '+' || (c) == '/' || (c) == '=' \
123 )
124
125extern int base64_decode_atom(char *atom, unsigned char *out);
126extern int base64_lines(int datalen);
127extern void base64_encode_atom(unsigned char *data, int n, char *out);
128extern void base64_encode(FILE * fp, unsigned char *data, int datalen);
129
130/*
131 * Read an ASN.1/BER identifier and length pair.
132 *
133 * Flags are a combination of the #defines listed below.
134 *
135 * Returns -1 if unsuccessful; otherwise returns the number of
136 * bytes used out of the source data.
137 */
138
139/* ASN.1 tag classes. */
140#define ASN1_CLASS_UNIVERSAL (0 << 6)
141#define ASN1_CLASS_APPLICATION (1 << 6)
142#define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
143#define ASN1_CLASS_PRIVATE (3 << 6)
144#define ASN1_CLASS_MASK (3 << 6)
145
146/* Primitive versus constructed bit. */
147#define ASN1_CONSTRUCTED (1 << 5)
148
149int ber_read_id_len(void *source, int sourcelen,
150 int *id, int *length, int *flags)
151{
152 unsigned char *p = (unsigned char *) source;
153
154 if (sourcelen == 0)
155 return -1;
156
157 *flags = (*p & 0xE0);
158 if ((*p & 0x1F) == 0x1F) {
159 *id = 0;
160 while (*p & 0x80) {
161 *id = (*id << 7) | (*p & 0x7F);
162 p++, sourcelen--;
163 if (sourcelen == 0)
164 return -1;
165 }
166 *id = (*id << 7) | (*p & 0x7F);
167 p++, sourcelen--;
168 } else {
169 *id = *p & 0x1F;
170 p++, sourcelen--;
171 }
172
173 if (sourcelen == 0)
174 return -1;
175
176 if (*p & 0x80) {
177 int n = *p & 0x7F;
178 p++, sourcelen--;
179 if (sourcelen < n)
180 return -1;
181 *length = 0;
182 while (n--)
183 *length = (*length << 8) | (*p++);
184 sourcelen -= n;
185 } else {
186 *length = *p;
187 p++, sourcelen--;
188 }
189
190 return p - (unsigned char *) source;
191}
192
7b4ef1ae 193static int put_string(void *target, void *data, int len)
194{
195 unsigned char *d = (unsigned char *)target;
196
197 PUT_32BIT(d, len);
198 memcpy(d+4, data, len);
199 return len+4;
200}
201
202static int put_mp(void *target, void *data, int len)
203{
204 unsigned char *d = (unsigned char *)target;
205 unsigned char *i = (unsigned char *)data;
206
207 if (*i & 0x80) {
208 PUT_32BIT(d, len+1);
209 d[4] = 0;
210 memcpy(d+5, data, len);
211 return len+5;
212 } else {
213 PUT_32BIT(d, len);
214 memcpy(d+4, data, len);
215 return len+4;
216 }
217}
218
9dda6459 219/* ----------------------------------------------------------------------
220 * Code to read OpenSSH private keys.
221 */
222
223enum { OSSH_DSA, OSSH_RSA };
224struct openssh_key {
225 int type;
226 int encrypted;
227 char iv[32];
228 unsigned char *keyblob;
229 int keyblob_len, keyblob_size;
230};
231
232struct openssh_key *load_openssh_key(char *filename)
233{
234 struct openssh_key *ret;
235 FILE *fp;
236 char buffer[256];
237 char *errmsg, *p;
238 int headers_done;
ee5c1422 239 char base64_bit[4];
240 int base64_chars = 0;
9dda6459 241
242 ret = smalloc(sizeof(*ret));
243 ret->keyblob = NULL;
244 ret->keyblob_len = ret->keyblob_size = 0;
245 ret->encrypted = 0;
246 memset(ret->iv, 0, sizeof(ret->iv));
247
248 fp = fopen(filename, "r");
249 if (!fp) {
250 errmsg = "Unable to open key file";
251 goto error;
252 }
253 if (!fgets(buffer, sizeof(buffer), fp) ||
254 0 != strncmp(buffer, "-----BEGIN ", 11) ||
255 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) {
256 errmsg = "File does not begin with OpenSSH key header";
257 goto error;
258 }
259 if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n"))
260 ret->type = OSSH_RSA;
261 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
262 ret->type = OSSH_DSA;
263 else {
264 errmsg = "Unrecognised key type";
265 goto error;
266 }
267
268 headers_done = 0;
269 while (1) {
270 if (!fgets(buffer, sizeof(buffer), fp)) {
271 errmsg = "Unexpected end of file";
272 goto error;
273 }
274 if (0 == strncmp(buffer, "-----END ", 9) &&
275 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n"))
276 break; /* done */
277 if ((p = strchr(buffer, ':')) != NULL) {
278 if (headers_done) {
279 errmsg = "Header found in body of key data";
280 goto error;
281 }
282 *p++ = '\0';
283 while (*p && isspace((unsigned char)*p)) p++;
284 if (!strcmp(buffer, "Proc-Type")) {
285 if (p[0] != '4' || p[1] != ',') {
286 errmsg = "Proc-Type is not 4 (only 4 is supported)";
287 goto error;
288 }
289 p += 2;
290 if (!strcmp(p, "ENCRYPTED\n"))
291 ret->encrypted = 1;
292 } else if (!strcmp(buffer, "DEK-Info")) {
293 int i, j;
294
295 if (strncmp(p, "DES-EDE3-CBC,", 13)) {
296 errmsg = "Ciphers other than DES-EDE3-CBC not supported";
297 goto error;
298 }
299 p += 13;
300 for (i = 0; i < 8; i++) {
301 if (1 != sscanf(p, "%2x", &j))
302 break;
303 ret->iv[i] = j;
304 p += 2;
305 }
306 if (i < 8) {
307 errmsg = "Expected 16-digit iv in DEK-Info";
308 goto error;
309 }
310 }
311 } else {
312 headers_done = 1;
313
314 p = buffer;
ee5c1422 315 while (isbase64(*p)) {
316 base64_bit[base64_chars++] = *p;
317 if (base64_chars == 4) {
318 unsigned char out[3];
319 int len;
9dda6459 320
ee5c1422 321 base64_chars = 0;
9dda6459 322
ee5c1422 323 len = base64_decode_atom(base64_bit, out);
9dda6459 324
ee5c1422 325 if (len <= 0) {
326 errmsg = "Invalid base64 encoding";
327 goto error;
328 }
329
330 if (ret->keyblob_len + len > ret->keyblob_size) {
331 ret->keyblob_size = ret->keyblob_len + len + 256;
332 ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size);
333 }
9dda6459 334
ee5c1422 335 memcpy(ret->keyblob + ret->keyblob_len, out, len);
336 ret->keyblob_len += len;
9dda6459 337
ee5c1422 338 memset(out, 0, sizeof(out));
339 }
9dda6459 340
ee5c1422 341 p++;
9dda6459 342 }
343 }
344 }
345
346 if (ret->keyblob_len == 0 || !ret->keyblob) {
347 errmsg = "Key body not present";
348 goto error;
349 }
350
351 if (ret->encrypted && ret->keyblob_len % 8 != 0) {
352 errmsg = "Encrypted key blob is not a multiple of cipher block size";
353 goto error;
354 }
355
ee5c1422 356 memset(buffer, 0, sizeof(buffer));
357 memset(base64_bit, 0, sizeof(base64_bit));
9dda6459 358 return ret;
359
360 error:
ee5c1422 361 memset(buffer, 0, sizeof(buffer));
362 memset(base64_bit, 0, sizeof(base64_bit));
9dda6459 363 if (ret) {
ee5c1422 364 if (ret->keyblob) {
365 memset(ret->keyblob, 0, ret->keyblob_size);
366 sfree(ret->keyblob);
367 }
368 memset(&ret, 0, sizeof(ret));
9dda6459 369 sfree(ret);
370 }
371 return NULL;
372}
373
374int openssh_encrypted(char *filename)
375{
376 struct openssh_key *key = load_openssh_key(filename);
377 int ret;
378
379 if (!key)
380 return 0;
381 ret = key->encrypted;
ee5c1422 382 memset(key->keyblob, 0, key->keyblob_size);
9dda6459 383 sfree(key->keyblob);
ee5c1422 384 memset(&key, 0, sizeof(key));
9dda6459 385 sfree(key);
386 return ret;
387}
388
389struct ssh2_userkey *openssh_read(char *filename, char *passphrase)
390{
391 struct openssh_key *key = load_openssh_key(filename);
392 struct ssh2_userkey *retkey;
393 unsigned char *p;
394 int ret, id, len, flags;
395 int i, num_integers;
396 struct ssh2_userkey *retval = NULL;
397 char *errmsg;
398 unsigned char *blob;
ee5c1422 399 int blobsize, blobptr, privptr;
9dda6459 400 char *modptr;
401 int modlen;
402
403 if (!key)
404 return NULL;
405
406 if (key->encrypted) {
407 /*
408 * Derive encryption key from passphrase and iv/salt:
409 *
410 * - let block A equal MD5(passphrase || iv)
411 * - let block B equal MD5(A || passphrase || iv)
412 * - block C would be MD5(B || passphrase || iv) and so on
413 * - encryption key is the first N bytes of A || B
414 */
415 struct MD5Context md5c;
416 unsigned char keybuf[32];
417
418 MD5Init(&md5c);
419 MD5Update(&md5c, passphrase, strlen(passphrase));
420 MD5Update(&md5c, key->iv, 8);
421 MD5Final(keybuf, &md5c);
422
423 MD5Init(&md5c);
424 MD5Update(&md5c, keybuf, 16);
425 MD5Update(&md5c, passphrase, strlen(passphrase));
426 MD5Update(&md5c, key->iv, 8);
427 MD5Final(keybuf+16, &md5c);
428
429 /*
430 * Now decrypt the key blob.
431 */
432 des3_decrypt_pubkey_ossh(keybuf, key->iv,
433 key->keyblob, key->keyblob_len);
ee5c1422 434
435 memset(&md5c, 0, sizeof(md5c));
436 memset(keybuf, 0, sizeof(keybuf));
9dda6459 437 }
438
439 /*
440 * Now we have a decrypted key blob, which contains an ASN.1
441 * encoded private key. We must now untangle the ASN.1.
442 *
443 * We expect the whole key blob to be formatted as a SEQUENCE
444 * (0x30 followed by a length code indicating that the rest of
445 * the blob is part of the sequence). Within that SEQUENCE we
446 * expect to see a bunch of INTEGERs. What those integers mean
447 * depends on the key type:
448 *
449 * - For RSA, we expect the integers to be 0, n, e, d, p, q,
450 * dmp1, dmq1, iqmp in that order. (The last three are d mod
451 * (p-1), d mod (q-1), inverse of q mod p respectively.)
452 *
453 * - For DSA, we expect them to be 0, p, q, g, y, x in that
454 * order.
455 */
456
457 p = key->keyblob;
458
459 /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
460 ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
461 p += ret;
462 if (ret < 0 || id != 16) {
463 errmsg = "ASN.1 decoding failure";
464 retval = SSH2_WRONG_PASSPHRASE;
465 goto error;
466 }
467
468 /* Expect a load of INTEGERs. */
469 if (key->type == OSSH_RSA)
470 num_integers = 9;
471 else if (key->type == OSSH_DSA)
472 num_integers = 6;
473
474 /*
475 * Space to create key blob in.
476 */
ee5c1422 477 blobsize = 256+key->keyblob_len;
478 blob = smalloc(blobsize);
9dda6459 479 PUT_32BIT(blob, 7);
480 if (key->type == OSSH_DSA)
481 memcpy(blob+4, "ssh-dss", 7);
482 else if (key->type == OSSH_RSA)
483 memcpy(blob+4, "ssh-rsa", 7);
484 blobptr = 4+7;
485 privptr = -1;
486
487 for (i = 0; i < num_integers; i++) {
488 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
489 &id, &len, &flags);
490 p += ret;
491 if (ret < 0 || id != 2 ||
492 key->keyblob+key->keyblob_len-p < len) {
493 errmsg = "ASN.1 decoding failure";
494 goto error;
495 }
496
497 if (i == 0) {
498 /*
499 * The first integer should be zero always (I think
500 * this is some sort of version indication).
501 */
502 if (len != 1 || p[0] != 0) {
503 errmsg = "Version number mismatch";
504 goto error;
505 }
506 } else if (key->type == OSSH_RSA) {
507 /*
508 * Integers 1 and 2 go into the public blob but in the
509 * opposite order; integers 3, 4, 5 and 8 go into the
510 * private blob. The other two (6 and 7) are ignored.
511 */
512 if (i == 1) {
513 /* Save the details for after we deal with number 2. */
514 modptr = p;
515 modlen = len;
516 } else if (i != 6 && i != 7) {
517 PUT_32BIT(blob+blobptr, len);
518 memcpy(blob+blobptr+4, p, len);
519 blobptr += 4+len;
520 if (i == 2) {
521 PUT_32BIT(blob+blobptr, modlen);
522 memcpy(blob+blobptr+4, modptr, modlen);
523 blobptr += 4+modlen;
524 privptr = blobptr;
525 }
526 }
527 } else if (key->type == OSSH_DSA) {
528 /*
529 * Integers 1-4 go into the public blob; integer 5 goes
530 * into the private blob.
531 */
532 PUT_32BIT(blob+blobptr, len);
533 memcpy(blob+blobptr+4, p, len);
534 blobptr += 4+len;
535 if (i == 4)
536 privptr = blobptr;
537 }
538
539 /* Skip past the number. */
540 p += len;
541 }
542
543 /*
544 * Now put together the actual key. Simplest way to do this is
545 * to assemble our own key blobs and feed them to the createkey
546 * functions; this is a bit faffy but it does mean we get all
547 * the sanity checks for free.
548 */
549 assert(privptr > 0); /* should have bombed by now if not */
550 retkey = smalloc(sizeof(struct ssh2_userkey));
551 retkey->alg = (key->type == OSSH_RSA ? &ssh_rsa : &ssh_dss);
552 retkey->data = retkey->alg->createkey(blob, privptr,
553 blob+privptr, blobptr-privptr);
554 if (!retkey->data) {
555 sfree(retkey);
556 errmsg = "unable to create key data structure";
557 goto error;
558 }
559
560 retkey->comment = dupstr("imported-openssh-key");
ee5c1422 561 errmsg = NULL; /* no error */
562 retval = retkey;
9dda6459 563
564 error:
ee5c1422 565 if (blob) {
566 memset(blob, 0, blobsize);
567 sfree(blob);
568 }
569 memset(key->keyblob, 0, key->keyblob_size);
9dda6459 570 sfree(key->keyblob);
ee5c1422 571 memset(&key, 0, sizeof(key));
9dda6459 572 sfree(key);
573 return retval;
574}
7b4ef1ae 575
576/* ----------------------------------------------------------------------
577 * Code to read ssh.com private keys.
578 */
579
580/*
581 * The format of the base64 blob is largely ssh2-packet-formatted,
582 * except that mpints are a bit different: they're more like the
583 * old ssh1 mpint. You have a 32-bit bit count N, followed by
584 * (N+7)/8 bytes of data.
585 *
586 * So. The blob contains:
587 *
588 * - uint32 0x3f6ff9eb (magic number)
589 * - uint32 size (total blob size)
590 * - string key-type (see below)
591 * - string cipher-type (tells you if key is encrypted)
592 * - string encrypted-blob
593 *
594 * (The first size field includes the size field itself and the
595 * magic number before it. All other size fields are ordinary ssh2
596 * strings, so the size field indicates how much data is to
597 * _follow_.)
598 *
599 * The encrypted blob, once decrypted, contains a single string
600 * which in turn contains the payload. (This allows padding to be
601 * added after that string while still making it clear where the
602 * real payload ends. Also it probably makes for a reasonable
603 * decryption check.)
604 *
605 * The payload blob, for an RSA key, contains:
606 * - mpint e
607 * - mpint d
608 * - mpint n (yes, the public and private stuff is intermixed)
609 * - mpint u (presumably inverse of p mod q)
610 * - mpint p (p is the smaller prime)
611 * - mpint q (q is the larger)
612 *
613 * For a DSA key, the payload blob contains:
614 * - uint32 0
615 * - mpint p
616 * - mpint g
617 * - mpint q
618 * - mpint y
619 * - mpint x
620 *
621 * Alternatively, if the parameters are `predefined', that
622 * (0,p,g,q) sequence can be replaced by a uint32 1 and a string
623 * containing some predefined parameter specification. *shudder*,
624 * but I doubt we'll encounter this in real life.
625 *
626 * The key type strings are ghastly. The RSA key I looked at had a
627 * type string of
628 *
629 * `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
630 *
631 * and the DSA key wasn't much better:
632 *
633 * `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
634 *
635 * It isn't clear that these will always be the same. I think it
636 * might be wise just to look at the `if-modn{sign{rsa' and
637 * `dl-modp{sign{dsa' prefixes.
638 *
639 * Finally, the encryption. The cipher-type string appears to be
640 * either `none' or `3des-cbc'. Looks as if this is SSH2-style
641 * 3des-cbc (i.e. outer cbc rather than inner). The key is created
642 * from the passphrase by means of yet another hashing faff:
643 *
644 * - first 16 bytes are MD5(passphrase)
645 * - next 16 bytes are MD5(passphrase || first 16 bytes)
646 * - if there were more, they'd be MD5(passphrase || first 32),
647 * and so on.
648 */
649
650struct sshcom_key {
651 char comment[256]; /* allowing any length is overkill */
652 unsigned char *keyblob;
653 int keyblob_len, keyblob_size;
654};
655
656struct sshcom_key *load_sshcom_key(char *filename)
657{
658 struct sshcom_key *ret;
659 FILE *fp;
660 char buffer[256];
661 int len;
662 char *errmsg, *p;
663 int headers_done;
664 char base64_bit[4];
665 int base64_chars = 0;
666
667 ret = smalloc(sizeof(*ret));
668 ret->comment[0] = '\0';
669 ret->keyblob = NULL;
670 ret->keyblob_len = ret->keyblob_size = 0;
671
672 fp = fopen(filename, "r");
673 if (!fp) {
674 errmsg = "Unable to open key file";
675 goto error;
676 }
677 if (!fgets(buffer, sizeof(buffer), fp) ||
678 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
679 errmsg = "File does not begin with ssh.com key header";
680 goto error;
681 }
682
683 headers_done = 0;
684 while (1) {
685 if (!fgets(buffer, sizeof(buffer), fp)) {
686 errmsg = "Unexpected end of file";
687 goto error;
688 }
689 if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
690 break; /* done */
691 if ((p = strchr(buffer, ':')) != NULL) {
692 if (headers_done) {
693 errmsg = "Header found in body of key data";
694 goto error;
695 }
696 *p++ = '\0';
697 while (*p && isspace((unsigned char)*p)) p++;
698 /*
699 * Header lines can end in a trailing backslash for
700 * continuation.
701 */
702 while ((len = strlen(p)) > sizeof(buffer) - (p-buffer) -1 ||
703 p[len-1] != '\n' || p[len-2] == '\\') {
704 if (len > (p-buffer) + sizeof(buffer)-2) {
705 errmsg = "Header line too long to deal with";
706 goto error;
707 }
708 if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) {
709 errmsg = "Unexpected end of file";
710 goto error;
711 }
712 }
713 p[strcspn(p, "\n")] = '\0';
714 if (!strcmp(buffer, "Comment")) {
715 /* Strip quotes in comment if present. */
716 if (p[0] == '"' && p[strlen(p)-1] == '"') {
717 p++;
718 p[strlen(p)-1] = '\0';
719 }
720 strncpy(ret->comment, p, sizeof(ret->comment));
721 ret->comment[sizeof(ret->comment)-1] = '\0';
722 }
723 } else {
724 headers_done = 1;
725
726 p = buffer;
727 while (isbase64(*p)) {
728 base64_bit[base64_chars++] = *p;
729 if (base64_chars == 4) {
730 unsigned char out[3];
731
732 base64_chars = 0;
733
734 len = base64_decode_atom(base64_bit, out);
735
736 if (len <= 0) {
737 errmsg = "Invalid base64 encoding";
738 goto error;
739 }
740
741 if (ret->keyblob_len + len > ret->keyblob_size) {
742 ret->keyblob_size = ret->keyblob_len + len + 256;
743 ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size);
744 }
745
746 memcpy(ret->keyblob + ret->keyblob_len, out, len);
747 ret->keyblob_len += len;
748 }
749
750 p++;
751 }
752 }
753 }
754
755 if (ret->keyblob_len == 0 || !ret->keyblob) {
756 errmsg = "Key body not present";
757 goto error;
758 }
759
760 return ret;
761
762 error:
763 if (ret) {
ee5c1422 764 if (ret->keyblob) {
765 memset(ret->keyblob, 0, ret->keyblob_size);
766 sfree(ret->keyblob);
767 }
768 memset(&ret, 0, sizeof(ret));
7b4ef1ae 769 sfree(ret);
770 }
771 return NULL;
772}
773
774int sshcom_encrypted(char *filename, char **comment)
775{
776 struct sshcom_key *key = load_sshcom_key(filename);
777 int pos, len, answer;
778
779 *comment = NULL;
780 if (!key)
781 return 0;
782
783 /*
784 * Check magic number.
785 */
786 if (GET_32BIT(key->keyblob) != 0x3f6ff9eb)
787 return 0; /* key is invalid */
788
789 /*
790 * Find the cipher-type string.
791 */
792 answer = 0;
793 pos = 8;
794 if (key->keyblob_len < pos+4)
795 goto done; /* key is far too short */
796 pos += 4 + GET_32BIT(key->keyblob + pos); /* skip key type */
797 if (key->keyblob_len < pos+4)
798 goto done; /* key is far too short */
799 len = GET_32BIT(key->keyblob + pos); /* find cipher-type length */
800 if (key->keyblob_len < pos+4+len)
801 goto done; /* cipher type string is incomplete */
802 if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4))
803 answer = 1;
804
805 done:
806 *comment = dupstr(key->comment);
ee5c1422 807 memset(key->keyblob, 0, key->keyblob_size);
7b4ef1ae 808 sfree(key->keyblob);
ee5c1422 809 memset(&key, 0, sizeof(key));
7b4ef1ae 810 sfree(key);
811 return answer;
812}
813
814struct mpint_pos { void *start; int bytes; };
815
816int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret)
817{
818 int bits;
819 int bytes;
820 unsigned char *d = (unsigned char *) data;
821
822 if (len < 4)
823 goto error;
824 bits = GET_32BIT(d);
825
826 bytes = (bits + 7) / 8;
827 if (len < 4+bytes)
828 goto error;
829
830 ret->start = d + 4;
831 ret->bytes = bytes;
832 return bytes+4;
833
834 error:
835 ret->start = NULL;
836 ret->bytes = -1;
837 return len; /* ensure further calls fail as well */
838}
839
840struct ssh2_userkey *sshcom_read(char *filename, char *passphrase)
841{
842 struct sshcom_key *key = load_sshcom_key(filename);
843 char *errmsg;
844 int pos, len;
845 const char prefix_rsa[] = "if-modn{sign{rsa";
846 const char prefix_dsa[] = "dl-modp{sign{dsa";
847 enum { RSA, DSA } type;
848 int encrypted;
849 char *ciphertext;
850 int cipherlen;
851 struct ssh2_userkey *ret = NULL, *retkey;
852 const struct ssh_signkey *alg;
853 unsigned char *blob = NULL;
ee5c1422 854 int blobsize, publen, privlen;
7b4ef1ae 855
856 if (!key)
857 return NULL;
858
859 /*
860 * Check magic number.
861 */
862 if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) {
863 errmsg = "Key does not begin with magic number";
864 goto error;
865 }
866
867 /*
868 * Determine the key type.
869 */
870 pos = 8;
871 if (key->keyblob_len < pos+4 ||
872 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
873 errmsg = "Key blob does not contain a key type string";
874 goto error;
875 }
876 if (len > sizeof(prefix_rsa) - 1 &&
877 !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) {
878 type = RSA;
879 } else if (len > sizeof(prefix_dsa) - 1 &&
880 !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) {
881 type = DSA;
882 } else {
883 errmsg = "Key is of unknown type";
884 goto error;
885 }
886 pos += 4+len;
887
888 /*
889 * Determine the cipher type.
890 */
891 if (key->keyblob_len < pos+4 ||
892 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
893 errmsg = "Key blob does not contain a cipher type string";
894 goto error;
895 }
896 if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4))
897 encrypted = 0;
898 else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8))
899 encrypted = 1;
900 else {
901 errmsg = "Key encryption is of unknown type";
902 goto error;
903 }
904 pos += 4+len;
905
906 /*
907 * Get hold of the encrypted part of the key.
908 */
909 if (key->keyblob_len < pos+4 ||
910 (len = GET_32BIT(key->keyblob + pos)) > key->keyblob_len - pos - 4) {
911 errmsg = "Key blob does not contain actual key data";
912 goto error;
913 }
914 ciphertext = key->keyblob + pos + 4;
915 cipherlen = len;
916 if (cipherlen == 0) {
917 errmsg = "Length of key data is zero";
918 goto error;
919 }
920
921 /*
922 * Decrypt it if necessary.
923 */
924 if (encrypted) {
925 /*
926 * Derive encryption key from passphrase and iv/salt:
927 *
928 * - let block A equal MD5(passphrase)
929 * - let block B equal MD5(passphrase || A)
930 * - block C would be MD5(passphrase || A || B) and so on
931 * - encryption key is the first N bytes of A || B
932 */
933 struct MD5Context md5c;
934 unsigned char keybuf[32], iv[8];
935
936 if (cipherlen % 8 != 0) {
937 errmsg = "Encrypted part of key is not a multiple of cipher block"
938 " size";
939 goto error;
940 }
941
942 MD5Init(&md5c);
943 MD5Update(&md5c, passphrase, strlen(passphrase));
944 MD5Final(keybuf, &md5c);
945
946 MD5Init(&md5c);
947 MD5Update(&md5c, passphrase, strlen(passphrase));
948 MD5Update(&md5c, keybuf, 16);
949 MD5Final(keybuf+16, &md5c);
950
951 /*
952 * Now decrypt the key blob.
953 */
ee5c1422 954 memset(iv, 0, sizeof(iv));
7b4ef1ae 955 des3_decrypt_pubkey_ossh(keybuf, iv, ciphertext, cipherlen);
956
ee5c1422 957 memset(&md5c, 0, sizeof(md5c));
958 memset(keybuf, 0, sizeof(keybuf));
959
7b4ef1ae 960 /*
961 * Hereafter we return WRONG_PASSPHRASE for any parsing
ee5c1422 962 * error. (But only if we've just tried to decrypt it!
963 * Returning WRONG_PASSPHRASE for an unencrypted key is
964 * automatic doom.)
7b4ef1ae 965 */
966 if (encrypted)
967 ret = SSH2_WRONG_PASSPHRASE;
968 }
969
970 /*
971 * Strip away the containing string to get to the real meat.
972 */
973 len = GET_32BIT(ciphertext);
974 if (len > cipherlen-4) {
975 errmsg = "containing string was ill-formed";
976 goto error;
977 }
978 ciphertext += 4;
979 cipherlen = len;
980
981 /*
982 * Now we break down into RSA versus DSA. In either case we'll
983 * construct public and private blobs in our own format, and
984 * end up feeding them to alg->createkey().
985 */
ee5c1422 986 blobsize = cipherlen + 256;
987 blob = smalloc(blobsize);
7b4ef1ae 988 privlen = 0;
989 if (type == RSA) {
990 struct mpint_pos n, e, d, u, p, q;
991 int pos = 0;
992 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e);
993 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d);
994 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n);
995 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u);
996 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
997 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
998 if (!q.start) {
999 errmsg = "key data did not contain six integers";
1000 goto error;
1001 }
1002
1003 alg = &ssh_rsa;
1004 pos = 0;
1005 pos += put_string(blob+pos, "ssh-rsa", 7);
1006 pos += put_mp(blob+pos, e.start, e.bytes);
1007 pos += put_mp(blob+pos, n.start, n.bytes);
1008 publen = pos;
1009 pos += put_string(blob+pos, d.start, d.bytes);
1010 pos += put_mp(blob+pos, q.start, q.bytes);
1011 pos += put_mp(blob+pos, p.start, p.bytes);
1012 pos += put_mp(blob+pos, u.start, u.bytes);
1013 privlen = pos - publen;
1014 } else if (type == DSA) {
1015 struct mpint_pos p, q, g, x, y;
1016 int pos = 4;
1017 if (GET_32BIT(ciphertext) != 0) {
1018 errmsg = "predefined DSA parameters not supported";
1019 goto error;
1020 }
1021 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p);
1022 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g);
1023 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q);
1024 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y);
1025 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x);
1026 if (!x.start) {
1027 errmsg = "key data did not contain five integers";
1028 goto error;
1029 }
1030
1031 alg = &ssh_dss;
1032 pos = 0;
1033 pos += put_string(blob+pos, "ssh-dss", 7);
1034 pos += put_mp(blob+pos, p.start, p.bytes);
1035 pos += put_mp(blob+pos, q.start, q.bytes);
1036 pos += put_mp(blob+pos, g.start, g.bytes);
1037 pos += put_mp(blob+pos, y.start, y.bytes);
1038 publen = pos;
1039 pos += put_mp(blob+pos, x.start, x.bytes);
1040 privlen = pos - publen;
1041 }
1042
1043 assert(privlen > 0); /* should have bombed by now if not */
1044
1045 retkey = smalloc(sizeof(struct ssh2_userkey));
1046 retkey->alg = alg;
1047 retkey->data = alg->createkey(blob, publen, blob+publen, privlen);
1048 if (!retkey->data) {
1049 sfree(retkey);
1050 errmsg = "unable to create key data structure";
1051 goto error;
1052 }
1053 retkey->comment = dupstr(key->comment);
1054
1055 errmsg = NULL; /* no error */
1056 ret = retkey;
1057
1058 error:
ee5c1422 1059 if (blob) {
1060 memset(blob, 0, blobsize);
1061 sfree(blob);
1062 }
1063 memset(key->keyblob, 0, key->keyblob_size);
7b4ef1ae 1064 sfree(key->keyblob);
ee5c1422 1065 memset(&key, 0, sizeof(key));
7b4ef1ae 1066 sfree(key);
1067 return ret;
1068}