2 * Code for PuTTY to import and export private key files in other
3 * SSH clients' formats.
14 #define PUT_32BIT(cp, value) do { \
16 (cp)[2] = (value) >> 8; \
17 (cp)[1] = (value) >> 16; \
18 (cp)[0] = (value) >> 24; } while (0)
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]))
26 int openssh_encrypted(char *filename);
27 struct ssh2_userkey *openssh_read(char *filename, char *passphrase);
30 * Given a key type, determine whether we know how to import it.
32 int import_possible(int type)
34 if (type == SSH_KEYTYPE_OPENSSH)
40 * Given a key type, determine what native key type
41 * (SSH_KEYTYPE_SSH1 or SSH_KEYTYPE_SSH2) it will come out as once
44 int import_target_type(int type)
47 * There are no known foreign SSH1 key formats.
49 return SSH_KEYTYPE_SSH2;
53 * Determine whether a foreign key is encrypted.
55 int import_encrypted(char *filename, int type, char **comment)
57 if (type == SSH_KEYTYPE_OPENSSH) {
58 *comment = filename; /* OpenSSH doesn't do key comments */
59 return openssh_encrypted(filename);
67 int import_ssh1(char *filename, int type, struct RSAKey *key, char *passphrase)
75 struct ssh2_userkey *import_ssh2(char *filename, int type, char *passphrase)
77 if (type == SSH_KEYTYPE_OPENSSH)
78 return openssh_read(filename, passphrase);
82 /* ----------------------------------------------------------------------
83 * Helper routines. (The base64 ones are defined in sshpubk.c.)
86 #define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \
87 ((c) >= 'a' && (c) <= 'z') || \
88 ((c) >= '0' && (c) <= '9') || \
89 (c) == '+' || (c) == '/' || (c) == '=' \
92 extern int base64_decode_atom(char *atom, unsigned char *out);
93 extern int base64_lines(int datalen);
94 extern void base64_encode_atom(unsigned char *data, int n, char *out);
95 extern void base64_encode(FILE * fp, unsigned char *data, int datalen);
98 * Read an ASN.1/BER identifier and length pair.
100 * Flags are a combination of the #defines listed below.
102 * Returns -1 if unsuccessful; otherwise returns the number of
103 * bytes used out of the source data.
106 /* ASN.1 tag classes. */
107 #define ASN1_CLASS_UNIVERSAL (0 << 6)
108 #define ASN1_CLASS_APPLICATION (1 << 6)
109 #define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
110 #define ASN1_CLASS_PRIVATE (3 << 6)
111 #define ASN1_CLASS_MASK (3 << 6)
113 /* Primitive versus constructed bit. */
114 #define ASN1_CONSTRUCTED (1 << 5)
116 int ber_read_id_len(void *source, int sourcelen,
117 int *id, int *length, int *flags)
119 unsigned char *p = (unsigned char *) source;
124 *flags = (*p & 0xE0);
125 if ((*p & 0x1F) == 0x1F) {
128 *id = (*id << 7) | (*p & 0x7F);
133 *id = (*id << 7) | (*p & 0x7F);
150 *length = (*length << 8) | (*p++);
157 return p - (unsigned char *) source;
160 /* ----------------------------------------------------------------------
161 * Code to read OpenSSH private keys.
164 enum { OSSH_DSA, OSSH_RSA };
169 unsigned char *keyblob;
170 int keyblob_len, keyblob_size;
173 struct openssh_key *load_openssh_key(char *filename)
175 struct openssh_key *ret;
181 ret = smalloc(sizeof(*ret));
183 ret->keyblob_len = ret->keyblob_size = 0;
185 memset(ret->iv, 0, sizeof(ret->iv));
187 fp = fopen(filename, "r");
189 errmsg = "Unable to open key file";
192 if (!fgets(buffer, sizeof(buffer), fp) ||
193 0 != strncmp(buffer, "-----BEGIN ", 11) ||
194 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) {
195 errmsg = "File does not begin with OpenSSH key header";
198 if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n"))
199 ret->type = OSSH_RSA;
200 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n"))
201 ret->type = OSSH_DSA;
203 errmsg = "Unrecognised key type";
209 if (!fgets(buffer, sizeof(buffer), fp)) {
210 errmsg = "Unexpected end of file";
213 if (0 == strncmp(buffer, "-----END ", 9) &&
214 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n"))
216 if ((p = strchr(buffer, ':')) != NULL) {
218 errmsg = "Header found in body of key data";
222 while (*p && isspace((unsigned char)*p)) p++;
223 if (!strcmp(buffer, "Proc-Type")) {
224 if (p[0] != '4' || p[1] != ',') {
225 errmsg = "Proc-Type is not 4 (only 4 is supported)";
229 if (!strcmp(p, "ENCRYPTED\n"))
231 } else if (!strcmp(buffer, "DEK-Info")) {
234 if (strncmp(p, "DES-EDE3-CBC,", 13)) {
235 errmsg = "Ciphers other than DES-EDE3-CBC not supported";
239 for (i = 0; i < 8; i++) {
240 if (1 != sscanf(p, "%2x", &j))
246 errmsg = "Expected 16-digit iv in DEK-Info";
254 while (isbase64(p[0]) && isbase64(p[1]) &&
255 isbase64(p[2]) && isbase64(p[3])) {
257 unsigned char out[3];
259 len = base64_decode_atom(p, out);
262 errmsg = "Invalid base64 encoding";
266 if (ret->keyblob_len + len > ret->keyblob_size) {
267 ret->keyblob_size = ret->keyblob_len + len + 256;
268 ret->keyblob = srealloc(ret->keyblob, ret->keyblob_size);
271 memcpy(ret->keyblob + ret->keyblob_len, out, len);
272 ret->keyblob_len += len;
278 errmsg = "base64 characters left at end of line";
284 if (ret->keyblob_len == 0 || !ret->keyblob) {
285 errmsg = "Key body not present";
289 if (ret->encrypted && ret->keyblob_len % 8 != 0) {
290 errmsg = "Encrypted key blob is not a multiple of cipher block size";
298 if (ret->keyblob) sfree(ret->keyblob);
304 int openssh_encrypted(char *filename)
306 struct openssh_key *key = load_openssh_key(filename);
311 ret = key->encrypted;
317 struct ssh2_userkey *openssh_read(char *filename, char *passphrase)
319 struct openssh_key *key = load_openssh_key(filename);
320 struct ssh2_userkey *retkey;
322 int ret, id, len, flags;
324 struct ssh2_userkey *retval = NULL;
327 int blobptr, privptr;
334 if (key->encrypted) {
336 * Derive encryption key from passphrase and iv/salt:
338 * - let block A equal MD5(passphrase || iv)
339 * - let block B equal MD5(A || passphrase || iv)
340 * - block C would be MD5(B || passphrase || iv) and so on
341 * - encryption key is the first N bytes of A || B
343 struct MD5Context md5c;
344 unsigned char keybuf[32];
347 MD5Update(&md5c, passphrase, strlen(passphrase));
348 MD5Update(&md5c, key->iv, 8);
349 MD5Final(keybuf, &md5c);
352 MD5Update(&md5c, keybuf, 16);
353 MD5Update(&md5c, passphrase, strlen(passphrase));
354 MD5Update(&md5c, key->iv, 8);
355 MD5Final(keybuf+16, &md5c);
358 * Now decrypt the key blob.
360 des3_decrypt_pubkey_ossh(keybuf, key->iv,
361 key->keyblob, key->keyblob_len);
365 * Now we have a decrypted key blob, which contains an ASN.1
366 * encoded private key. We must now untangle the ASN.1.
368 * We expect the whole key blob to be formatted as a SEQUENCE
369 * (0x30 followed by a length code indicating that the rest of
370 * the blob is part of the sequence). Within that SEQUENCE we
371 * expect to see a bunch of INTEGERs. What those integers mean
372 * depends on the key type:
374 * - For RSA, we expect the integers to be 0, n, e, d, p, q,
375 * dmp1, dmq1, iqmp in that order. (The last three are d mod
376 * (p-1), d mod (q-1), inverse of q mod p respectively.)
378 * - For DSA, we expect them to be 0, p, q, g, y, x in that
384 /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
385 ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags);
387 if (ret < 0 || id != 16) {
388 errmsg = "ASN.1 decoding failure";
389 retval = SSH2_WRONG_PASSPHRASE;
393 /* Expect a load of INTEGERs. */
394 if (key->type == OSSH_RSA)
396 else if (key->type == OSSH_DSA)
400 * Space to create key blob in.
402 blob = smalloc(256+key->keyblob_len);
404 if (key->type == OSSH_DSA)
405 memcpy(blob+4, "ssh-dss", 7);
406 else if (key->type == OSSH_RSA)
407 memcpy(blob+4, "ssh-rsa", 7);
411 for (i = 0; i < num_integers; i++) {
412 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p,
415 if (ret < 0 || id != 2 ||
416 key->keyblob+key->keyblob_len-p < len) {
417 errmsg = "ASN.1 decoding failure";
423 * The first integer should be zero always (I think
424 * this is some sort of version indication).
426 if (len != 1 || p[0] != 0) {
427 errmsg = "Version number mismatch";
430 } else if (key->type == OSSH_RSA) {
432 * Integers 1 and 2 go into the public blob but in the
433 * opposite order; integers 3, 4, 5 and 8 go into the
434 * private blob. The other two (6 and 7) are ignored.
437 /* Save the details for after we deal with number 2. */
440 } else if (i != 6 && i != 7) {
441 PUT_32BIT(blob+blobptr, len);
442 memcpy(blob+blobptr+4, p, len);
445 PUT_32BIT(blob+blobptr, modlen);
446 memcpy(blob+blobptr+4, modptr, modlen);
451 } else if (key->type == OSSH_DSA) {
453 * Integers 1-4 go into the public blob; integer 5 goes
454 * into the private blob.
456 PUT_32BIT(blob+blobptr, len);
457 memcpy(blob+blobptr+4, p, len);
463 /* Skip past the number. */
468 * Now put together the actual key. Simplest way to do this is
469 * to assemble our own key blobs and feed them to the createkey
470 * functions; this is a bit faffy but it does mean we get all
471 * the sanity checks for free.
473 assert(privptr > 0); /* should have bombed by now if not */
474 retkey = smalloc(sizeof(struct ssh2_userkey));
475 retkey->alg = (key->type == OSSH_RSA ? &ssh_rsa : &ssh_dss);
476 retkey->data = retkey->alg->createkey(blob, privptr,
477 blob+privptr, blobptr-privptr);
480 errmsg = "unable to create key data structure";
484 retkey->comment = dupstr("imported-openssh-key");
485 if (blob) sfree(blob);
491 if (blob) sfree(blob);