2 * Based on PuTTY's import.c for importing/exporting OpenSSH and SSH.com
5 * Modifications copyright 2003 Matt Johnston
7 * PuTTY is copyright 1997-2003 Simon Tatham.
9 * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
10 * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
11 * Justin Bradford, and CORE SDI S.A.
13 * Permission is hereby granted, free of charge, to any person
14 * obtaining a copy of this software and associated documentation files
15 * (the "Software"), to deal in the Software without restriction,
16 * including without limitation the rights to use, copy, modify, merge,
17 * publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so,
19 * subject to the following conditions:
21 * The above copyright notice and this permission notice shall be
22 * included in all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE
28 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
29 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 #include "keyimport.h"
39 static const unsigned char OID_SEC256R1_BLOB
[] = {0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07};
40 static const unsigned char OID_SEC384R1_BLOB
[] = {0x2b, 0x81, 0x04, 0x00, 0x22};
41 static const unsigned char OID_SEC521R1_BLOB
[] = {0x2b, 0x81, 0x04, 0x00, 0x23};
43 #define PUT_32BIT(cp, value) do { \
44 (cp)[3] = (unsigned char)(value); \
45 (cp)[2] = (unsigned char)((value) >> 8); \
46 (cp)[1] = (unsigned char)((value) >> 16); \
47 (cp)[0] = (unsigned char)((value) >> 24); } while (0)
49 #define GET_32BIT(cp) \
50 (((unsigned long)(unsigned char)(cp)[0] << 24) | \
51 ((unsigned long)(unsigned char)(cp)[1] << 16) | \
52 ((unsigned long)(unsigned char)(cp)[2] << 8) | \
53 ((unsigned long)(unsigned char)(cp)[3]))
55 static int openssh_encrypted(const char *filename
);
56 static sign_key
*openssh_read(const char *filename
, char *passphrase
);
57 static int openssh_write(const char *filename
, sign_key
*key
,
60 static int dropbear_write(const char*filename
, sign_key
* key
);
61 static sign_key
*dropbear_read(const char* filename
);
64 static int sshcom_encrypted(const char *filename
, char **comment
);
65 static struct ssh2_userkey
*sshcom_read(const char *filename
, char *passphrase
);
66 static int sshcom_write(const char *filename
, struct ssh2_userkey
*key
,
70 int import_encrypted(const char* filename
, int filetype
) {
72 if (filetype
== KEYFILE_OPENSSH
) {
73 return openssh_encrypted(filename
);
75 } else if (filetype
== KEYFILE_SSHCOM
) {
76 return sshcom_encrypted(filename
, NULL
);
82 sign_key
*import_read(const char *filename
, char *passphrase
, int filetype
) {
84 if (filetype
== KEYFILE_OPENSSH
) {
85 return openssh_read(filename
, passphrase
);
86 } else if (filetype
== KEYFILE_DROPBEAR
) {
87 return dropbear_read(filename
);
89 } else if (filetype
== KEYFILE_SSHCOM
) {
90 return sshcom_read(filename
, passphrase
);
96 int import_write(const char *filename
, sign_key
*key
, char *passphrase
,
99 if (filetype
== KEYFILE_OPENSSH
) {
100 return openssh_write(filename
, key
, passphrase
);
101 } else if (filetype
== KEYFILE_DROPBEAR
) {
102 return dropbear_write(filename
, key
);
104 } else if (filetype
== KEYFILE_SSHCOM
) {
105 return sshcom_write(filename
, key
, passphrase
);
111 static sign_key
*dropbear_read(const char* filename
) {
114 sign_key
*ret
= NULL
;
115 enum signkey_type type
;
117 buf
= buf_new(MAX_PRIVKEY_SIZE
);
118 if (buf_readfile(buf
, filename
) == DROPBEAR_FAILURE
) {
123 ret
= new_sign_key();
125 type
= DROPBEAR_SIGNKEY_ANY
;
126 if (buf_get_priv_key(buf
, ret
, &type
) == DROPBEAR_FAILURE
){
145 /* returns 0 on fail, 1 on success */
146 static int dropbear_write(const char*filename
, sign_key
* key
) {
153 buf
= buf_new(MAX_PRIVKEY_SIZE
);
154 buf_put_priv_key(buf
, key
, key
->type
);
156 fp
= fopen(filename
, "w");
164 len
= fwrite(buf_getptr(buf
, buf
->len
- buf
->pos
),
165 1, buf
->len
- buf
->pos
, fp
);
166 buf_incrpos(buf
, len
);
167 } while (len
> 0 && buf
->len
!= buf
->pos
);
171 if (buf
->pos
!= buf
->len
) {
182 /* ----------------------------------------------------------------------
183 * Helper routines. (The base64 ones are defined in sshpubk.c.)
186 #define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \
187 ((c) >= 'a' && (c) <= 'z') || \
188 ((c) >= '0' && (c) <= '9') || \
189 (c) == '+' || (c) == '/' || (c) == '=' \
192 /* cpl has to be less than 100 */
193 static void base64_encode_fp(FILE * fp
, unsigned char *data
,
194 int datalen
, int cpl
)
196 unsigned char out
[100];
198 unsigned long outlen
;
200 rawcpl
= cpl
* 3 / 4;
201 dropbear_assert((unsigned int)cpl
< sizeof(out
));
203 while (datalen
> 0) {
204 n
= (datalen
< rawcpl
? datalen
: rawcpl
);
205 outlen
= sizeof(out
);
206 base64_encode(data
, n
, out
, &outlen
);
209 fwrite(out
, 1, outlen
, fp
);
214 * Read an ASN.1/BER identifier and length pair.
216 * Flags are a combination of the #defines listed below.
218 * Returns -1 if unsuccessful; otherwise returns the number of
219 * bytes used out of the source data.
222 /* ASN.1 tag classes. */
223 #define ASN1_CLASS_UNIVERSAL (0 << 6)
224 #define ASN1_CLASS_APPLICATION (1 << 6)
225 #define ASN1_CLASS_CONTEXT_SPECIFIC (2 << 6)
226 #define ASN1_CLASS_PRIVATE (3 << 6)
227 #define ASN1_CLASS_MASK (3 << 6)
229 /* Primitive versus constructed bit. */
230 #define ASN1_CONSTRUCTED (1 << 5)
232 static int ber_read_id_len(void *source
, int sourcelen
,
233 int *id
, int *length
, int *flags
)
235 unsigned char *p
= (unsigned char *) source
;
240 *flags
= (*p
& 0xE0);
241 if ((*p
& 0x1F) == 0x1F) {
244 *id
= (*id
<< 7) | (*p
& 0x7F);
249 *id
= (*id
<< 7) | (*p
& 0x7F);
266 *length
= (*length
<< 8) | (*p
++);
273 return p
- (unsigned char *) source
;
277 * Write an ASN.1/BER identifier and length pair. Returns the
278 * number of bytes consumed. Assumes dest contains enough space.
279 * Will avoid writing anything if dest is NULL, but still return
280 * amount of space required.
282 static int ber_write_id_len(void *dest
, int id
, int length
, int flags
)
284 unsigned char *d
= (unsigned char *)dest
;
289 * Identifier is one byte.
292 if (d
) *d
++ = id
| flags
;
296 * Identifier is multiple bytes: the first byte is 11111
297 * plus the flags, and subsequent bytes encode the value of
298 * the identifier, 7 bits at a time, with the top bit of
299 * each byte 1 except the last one which is 0.
302 if (d
) *d
++ = 0x1F | flags
;
303 for (n
= 1; (id
>> (7*n
)) > 0; n
++)
304 continue; /* count the bytes */
307 if (d
) *d
++ = (n
? 0x80 : 0) | ((id
>> (7*n
)) & 0x7F);
313 * Length is one byte.
316 if (d
) *d
++ = length
;
320 * Length is multiple bytes. The first is 0x80 plus the
321 * number of subsequent bytes, and the subsequent bytes
322 * encode the actual length.
324 for (n
= 1; (length
>> (8*n
)) > 0; n
++)
325 continue; /* count the bytes */
327 if (d
) *d
++ = 0x80 | n
;
330 if (d
) *d
++ = (length
>> (8*n
)) & 0xFF;
338 /* Simple structure to point to an mp-int within a blob. */
339 struct mpint_pos
{ void *start
; int bytes
; };
341 /* ----------------------------------------------------------------------
342 * Code to read and write OpenSSH private keys.
345 enum { OSSH_DSA
, OSSH_RSA
, OSSH_EC
};
350 unsigned char *keyblob
;
351 unsigned int keyblob_len
, keyblob_size
;
354 static struct openssh_key
*load_openssh_key(const char *filename
)
356 struct openssh_key
*ret
;
359 char *errmsg
= NULL
, *p
= NULL
;
361 unsigned long len
, outlen
;
363 ret
= (struct openssh_key
*)m_malloc(sizeof(struct openssh_key
));
365 ret
->keyblob_len
= ret
->keyblob_size
= 0;
367 memset(ret
->iv
, 0, sizeof(ret
->iv
));
369 if (strlen(filename
) == 1 && filename
[0] == '-') {
372 fp
= fopen(filename
, "r");
375 errmsg
= "Unable to open key file";
378 if (!fgets(buffer
, sizeof(buffer
), fp
) ||
379 0 != strncmp(buffer
, "-----BEGIN ", 11) ||
380 0 != strcmp(buffer
+strlen(buffer
)-17, "PRIVATE KEY-----\n")) {
381 errmsg
= "File does not begin with OpenSSH key header";
384 if (!strcmp(buffer
, "-----BEGIN RSA PRIVATE KEY-----\n"))
385 ret
->type
= OSSH_RSA
;
386 else if (!strcmp(buffer
, "-----BEGIN DSA PRIVATE KEY-----\n"))
387 ret
->type
= OSSH_DSA
;
388 else if (!strcmp(buffer
, "-----BEGIN EC PRIVATE KEY-----\n"))
391 errmsg
= "Unrecognised key type";
397 if (!fgets(buffer
, sizeof(buffer
), fp
)) {
398 errmsg
= "Unexpected end of file";
401 if (0 == strncmp(buffer
, "-----END ", 9) &&
402 0 == strcmp(buffer
+strlen(buffer
)-17, "PRIVATE KEY-----\n"))
404 if ((p
= strchr(buffer
, ':')) != NULL
) {
406 errmsg
= "Header found in body of key data";
410 while (*p
&& isspace((unsigned char)*p
)) p
++;
411 if (!strcmp(buffer
, "Proc-Type")) {
412 if (p
[0] != '4' || p
[1] != ',') {
413 errmsg
= "Proc-Type is not 4 (only 4 is supported)";
417 if (!strcmp(p
, "ENCRYPTED\n"))
419 } else if (!strcmp(buffer
, "DEK-Info")) {
422 if (strncmp(p
, "DES-EDE3-CBC,", 13)) {
423 errmsg
= "Ciphers other than DES-EDE3-CBC not supported";
427 for (i
= 0; i
< 8; i
++) {
428 if (1 != sscanf(p
, "%2x", &j
))
434 errmsg
= "Expected 16-digit iv in DEK-Info";
440 len
= strlen(buffer
);
442 if (ret
->keyblob_len
+ outlen
> ret
->keyblob_size
) {
443 ret
->keyblob_size
= ret
->keyblob_len
+ outlen
+ 256;
444 ret
->keyblob
= (unsigned char*)m_realloc(ret
->keyblob
,
447 outlen
= ret
->keyblob_size
- ret
->keyblob_len
;
448 if (base64_decode((const unsigned char *)buffer
, len
,
449 ret
->keyblob
+ ret
->keyblob_len
, &outlen
) != CRYPT_OK
){
450 errmsg
= "Error decoding base64";
453 ret
->keyblob_len
+= outlen
;
457 if (ret
->keyblob_len
== 0 || !ret
->keyblob
) {
458 errmsg
= "Key body not present";
462 if (ret
->encrypted
&& ret
->keyblob_len
% 8 != 0) {
463 errmsg
= "Encrypted key blob is not a multiple of cipher block size";
467 m_burn(buffer
, sizeof(buffer
));
471 m_burn(buffer
, sizeof(buffer
));
474 m_burn(ret
->keyblob
, ret
->keyblob_size
);
475 m_free(ret
->keyblob
);
483 fprintf(stderr
, "Error: %s\n", errmsg
);
488 static int openssh_encrypted(const char *filename
)
490 struct openssh_key
*key
= load_openssh_key(filename
);
495 ret
= key
->encrypted
;
496 m_burn(key
->keyblob
, key
->keyblob_size
);
497 m_free(key
->keyblob
);
502 static sign_key
*openssh_read(const char *filename
, char * UNUSED(passphrase
))
504 struct openssh_key
*key
;
506 int ret
, id
, len
, flags
;
507 int i
, num_integers
= 0;
508 sign_key
*retval
= NULL
;
510 unsigned char *modptr
= NULL
;
512 enum signkey_type type
;
515 buffer
* blobbuf
= NULL
;
517 retkey
= new_sign_key();
519 key
= load_openssh_key(filename
);
524 if (key
->encrypted
) {
525 errmsg
= "encrypted keys not supported currently";
530 * Derive encryption key from passphrase and iv/salt:
532 * - let block A equal MD5(passphrase || iv)
533 * - let block B equal MD5(A || passphrase || iv)
534 * - block C would be MD5(B || passphrase || iv) and so on
535 * - encryption key is the first N bytes of A || B
537 struct MD5Context md5c
;
538 unsigned char keybuf
[32];
541 MD5Update(&md5c
, (unsigned char *)passphrase
, strlen(passphrase
));
542 MD5Update(&md5c
, (unsigned char *)key
->iv
, 8);
543 MD5Final(keybuf
, &md5c
);
546 MD5Update(&md5c
, keybuf
, 16);
547 MD5Update(&md5c
, (unsigned char *)passphrase
, strlen(passphrase
));
548 MD5Update(&md5c
, (unsigned char *)key
->iv
, 8);
549 MD5Final(keybuf
+16, &md5c
);
552 * Now decrypt the key blob.
554 des3_decrypt_pubkey_ossh(keybuf
, (unsigned char *)key
->iv
,
555 key
->keyblob
, key
->keyblob_len
);
557 memset(&md5c
, 0, sizeof(md5c
));
558 memset(keybuf
, 0, sizeof(keybuf
));
563 * Now we have a decrypted key blob, which contains an ASN.1
564 * encoded private key. We must now untangle the ASN.1.
566 * We expect the whole key blob to be formatted as a SEQUENCE
567 * (0x30 followed by a length code indicating that the rest of
568 * the blob is part of the sequence). Within that SEQUENCE we
569 * expect to see a bunch of INTEGERs. What those integers mean
570 * depends on the key type:
572 * - For RSA, we expect the integers to be 0, n, e, d, p, q,
573 * dmp1, dmq1, iqmp in that order. (The last three are d mod
574 * (p-1), d mod (q-1), inverse of q mod p respectively.)
576 * - For DSA, we expect them to be 0, p, q, g, y, x in that
582 /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */
583 ret
= ber_read_id_len(p
, key
->keyblob_len
, &id
, &len
, &flags
);
585 if (ret
< 0 || id
!= 16) {
586 errmsg
= "ASN.1 decoding failure - wrong password?";
590 /* Expect a load of INTEGERs. */
591 if (key
->type
== OSSH_RSA
)
593 else if (key
->type
== OSSH_DSA
)
595 else if (key
->type
== OSSH_EC
)
599 * Space to create key blob in.
601 blobbuf
= buf_new(3000);
604 if (key
->type
== OSSH_DSA
) {
605 buf_putstring(blobbuf
, "ssh-dss", 7);
606 retkey
->type
= DROPBEAR_SIGNKEY_DSS
;
610 if (key
->type
== OSSH_RSA
) {
611 buf_putstring(blobbuf
, "ssh-rsa", 7);
612 retkey
->type
= DROPBEAR_SIGNKEY_RSA
;
616 for (i
= 0; i
< num_integers
; i
++) {
617 ret
= ber_read_id_len(p
, key
->keyblob
+key
->keyblob_len
-p
,
620 if (ret
< 0 || id
!= 2 ||
621 key
->keyblob
+key
->keyblob_len
-p
< len
) {
622 errmsg
= "ASN.1 decoding failure";
627 /* First integer is a version indicator */
638 if (len
!= 1 || p
[0] != expected
) {
639 errmsg
= "Version number mismatch";
642 } else if (key
->type
== OSSH_RSA
) {
644 * OpenSSH key order is n, e, d, p, q, dmp1, dmq1, iqmp
645 * but we want e, n, d, p, q
648 /* Save the details for after we deal with number 2. */
651 } else if (i
>= 2 && i
<= 5) {
652 buf_putstring(blobbuf
, (const char*)p
, len
);
654 buf_putstring(blobbuf
, (const char*)modptr
, modlen
);
657 } else if (key
->type
== OSSH_DSA
) {
659 * OpenSSH key order is p, q, g, y, x,
662 buf_putstring(blobbuf
, (const char*)p
, len
);
665 /* Skip past the number. */
669 #ifdef DROPBEAR_ECDSA
670 if (key
->type
== OSSH_EC
) {
671 unsigned char* private_key_bytes
= NULL
;
672 int private_key_len
= 0;
673 unsigned char* public_key_bytes
= NULL
;
674 int public_key_len
= 0;
676 const struct dropbear_ecc_curve
*curve
= NULL
;
678 /* See SEC1 v2, Appendix C.4 */
679 /* OpenSSL (so OpenSSH) seems to include the optional parts. */
681 /* privateKey OCTET STRING, */
682 ret
= ber_read_id_len(p
, key
->keyblob
+key
->keyblob_len
-p
,
685 /* id==4 for octet string */
686 if (ret
< 0 || id
!= 4 ||
687 key
->keyblob
+key
->keyblob_len
-p
< len
) {
688 errmsg
= "ASN.1 decoding failure";
691 private_key_bytes
= p
;
692 private_key_len
= len
;
695 /* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, */
696 ret
= ber_read_id_len(p
, key
->keyblob
+key
->keyblob_len
-p
,
700 if (ret
< 0 || id
!= 0) {
701 errmsg
= "ASN.1 decoding failure";
705 ret
= ber_read_id_len(p
, key
->keyblob
+key
->keyblob_len
-p
,
708 /* id==6 for object */
709 if (ret
< 0 || id
!= 6 ||
710 key
->keyblob
+key
->keyblob_len
-p
< len
) {
711 errmsg
= "ASN.1 decoding failure";
716 #ifdef DROPBEAR_ECC_256
717 else if (len
== sizeof(OID_SEC256R1_BLOB
)
718 && memcmp(p
, OID_SEC256R1_BLOB
, len
) == 0) {
719 retkey
->type
= DROPBEAR_SIGNKEY_ECDSA_NISTP256
;
720 curve
= &ecc_curve_nistp256
;
723 #ifdef DROPBEAR_ECC_384
724 else if (len
== sizeof(OID_SEC384R1_BLOB
)
725 && memcmp(p
, OID_SEC384R1_BLOB
, len
) == 0) {
726 retkey
->type
= DROPBEAR_SIGNKEY_ECDSA_NISTP384
;
727 curve
= &ecc_curve_nistp384
;
730 #ifdef DROPBEAR_ECC_521
731 else if (len
== sizeof(OID_SEC521R1_BLOB
)
732 && memcmp(p
, OID_SEC521R1_BLOB
, len
) == 0) {
733 retkey
->type
= DROPBEAR_SIGNKEY_ECDSA_NISTP521
;
734 curve
= &ecc_curve_nistp521
;
738 errmsg
= "Unknown ECC key type";
743 /* publicKey [1] BIT STRING OPTIONAL */
744 ret
= ber_read_id_len(p
, key
->keyblob
+key
->keyblob_len
-p
,
748 if (ret
< 0 || id
!= 1) {
749 errmsg
= "ASN.1 decoding failure";
753 ret
= ber_read_id_len(p
, key
->keyblob
+key
->keyblob_len
-p
,
756 /* id==3 for bit string */
757 if (ret
< 0 || id
!= 3 ||
758 key
->keyblob
+key
->keyblob_len
-p
< len
) {
759 errmsg
= "ASN.1 decoding failure";
762 public_key_bytes
= p
+1;
763 public_key_len
= len
-1;
766 buf_putbytes(blobbuf
, public_key_bytes
, public_key_len
);
767 ecc
= buf_get_ecc_raw_pubkey(blobbuf
, curve
);
769 errmsg
= "Error parsing ECC key";
772 m_mp_alloc_init_multi((mp_int
**)&ecc
->k
, NULL
);
773 if (mp_read_unsigned_bin(ecc
->k
, private_key_bytes
, private_key_len
)
775 errmsg
= "Error parsing ECC key";
779 *signkey_key_ptr(retkey
, retkey
->type
) = ecc
;
781 #endif /* DROPBEAR_ECDSA */
784 * Now put together the actual key. Simplest way to do this is
785 * to assemble our own key blobs and feed them to the createkey
786 * functions; this is a bit faffy but it does mean we get all
787 * the sanity checks for free.
789 if (key
->type
== OSSH_RSA
|| key
->type
== OSSH_DSA
) {
790 buf_setpos(blobbuf
, 0);
791 type
= DROPBEAR_SIGNKEY_ANY
;
792 if (buf_get_priv_key(blobbuf
, retkey
, &type
)
793 != DROPBEAR_SUCCESS
) {
794 errmsg
= "unable to create key structure";
795 sign_key_free(retkey
);
801 errmsg
= NULL
; /* no error */
809 m_burn(key
->keyblob
, key
->keyblob_size
);
810 m_free(key
->keyblob
);
811 m_burn(key
, sizeof(*key
));
814 fprintf(stderr
, "Error: %s\n", errmsg
);
819 static int openssh_write(const char *filename
, sign_key
*key
,
822 buffer
* keyblob
= NULL
;
823 buffer
* extrablob
= NULL
; /* used for calculated values to write */
824 unsigned char *outblob
= NULL
;
826 struct mpint_pos numbers
[9];
827 int nnumbers
= -1, pos
= 0, len
= 0, seqlen
, i
;
828 char *header
= NULL
, *footer
= NULL
;
834 mp_int dmp1
, dmq1
, iqmp
, tmpval
; /* for rsa */
839 key
->type
== DROPBEAR_SIGNKEY_RSA
||
842 key
->type
== DROPBEAR_SIGNKEY_DSS
||
847 * Fetch the key blobs.
849 keyblob
= buf_new(3000);
850 buf_put_priv_key(keyblob
, key
, key
->type
);
852 buf_setpos(keyblob
, 0);
853 /* skip the "ssh-rsa" or "ssh-dss" header */
854 buf_incrpos(keyblob
, buf_getint(keyblob
));
857 * Find the sequence of integers to be encoded into the OpenSSH
858 * key blob, and also decide on the header line.
860 numbers
[0].start
= zero
; numbers
[0].bytes
= 1; zero
[0] = '\0';
863 if (key
->type
== DROPBEAR_SIGNKEY_RSA
) {
865 if (key
->rsakey
->p
== NULL
|| key
->rsakey
->q
== NULL
) {
866 fprintf(stderr
, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n");
871 numbers
[2].bytes
= buf_getint(keyblob
);
872 numbers
[2].start
= buf_getptr(keyblob
, numbers
[2].bytes
);
873 buf_incrpos(keyblob
, numbers
[2].bytes
);
876 numbers
[1].bytes
= buf_getint(keyblob
);
877 numbers
[1].start
= buf_getptr(keyblob
, numbers
[1].bytes
);
878 buf_incrpos(keyblob
, numbers
[1].bytes
);
881 numbers
[3].bytes
= buf_getint(keyblob
);
882 numbers
[3].start
= buf_getptr(keyblob
, numbers
[3].bytes
);
883 buf_incrpos(keyblob
, numbers
[3].bytes
);
886 numbers
[4].bytes
= buf_getint(keyblob
);
887 numbers
[4].start
= buf_getptr(keyblob
, numbers
[4].bytes
);
888 buf_incrpos(keyblob
, numbers
[4].bytes
);
891 numbers
[5].bytes
= buf_getint(keyblob
);
892 numbers
[5].start
= buf_getptr(keyblob
, numbers
[5].bytes
);
893 buf_incrpos(keyblob
, numbers
[5].bytes
);
895 /* now calculate some extra parameters: */
901 /* dmp1 = d mod (p-1) */
902 if (mp_sub_d(key
->rsakey
->p
, 1, &tmpval
) != MP_OKAY
) {
903 fprintf(stderr
, "Bignum error for p-1\n");
906 if (mp_mod(key
->rsakey
->d
, &tmpval
, &dmp1
) != MP_OKAY
) {
907 fprintf(stderr
, "Bignum error for dmp1\n");
911 /* dmq1 = d mod (q-1) */
912 if (mp_sub_d(key
->rsakey
->q
, 1, &tmpval
) != MP_OKAY
) {
913 fprintf(stderr
, "Bignum error for q-1\n");
916 if (mp_mod(key
->rsakey
->d
, &tmpval
, &dmq1
) != MP_OKAY
) {
917 fprintf(stderr
, "Bignum error for dmq1\n");
921 /* iqmp = (q^-1) mod p */
922 if (mp_invmod(key
->rsakey
->q
, key
->rsakey
->p
, &iqmp
) != MP_OKAY
) {
923 fprintf(stderr
, "Bignum error for iqmp\n");
927 extrablob
= buf_new(2000);
928 buf_putmpint(extrablob
, &dmp1
);
929 buf_putmpint(extrablob
, &dmq1
);
930 buf_putmpint(extrablob
, &iqmp
);
931 buf_setpos(extrablob
, 0);
938 numbers
[6].bytes
= buf_getint(extrablob
);
939 numbers
[6].start
= buf_getptr(extrablob
, numbers
[6].bytes
);
940 buf_incrpos(extrablob
, numbers
[6].bytes
);
943 numbers
[7].bytes
= buf_getint(extrablob
);
944 numbers
[7].start
= buf_getptr(extrablob
, numbers
[7].bytes
);
945 buf_incrpos(extrablob
, numbers
[7].bytes
);
948 numbers
[8].bytes
= buf_getint(extrablob
);
949 numbers
[8].start
= buf_getptr(extrablob
, numbers
[8].bytes
);
950 buf_incrpos(extrablob
, numbers
[8].bytes
);
953 header
= "-----BEGIN RSA PRIVATE KEY-----\n";
954 footer
= "-----END RSA PRIVATE KEY-----\n";
956 #endif /* DROPBEAR_RSA */
959 if (key
->type
== DROPBEAR_SIGNKEY_DSS
) {
962 numbers
[1].bytes
= buf_getint(keyblob
);
963 numbers
[1].start
= buf_getptr(keyblob
, numbers
[1].bytes
);
964 buf_incrpos(keyblob
, numbers
[1].bytes
);
967 numbers
[2].bytes
= buf_getint(keyblob
);
968 numbers
[2].start
= buf_getptr(keyblob
, numbers
[2].bytes
);
969 buf_incrpos(keyblob
, numbers
[2].bytes
);
972 numbers
[3].bytes
= buf_getint(keyblob
);
973 numbers
[3].start
= buf_getptr(keyblob
, numbers
[3].bytes
);
974 buf_incrpos(keyblob
, numbers
[3].bytes
);
977 numbers
[4].bytes
= buf_getint(keyblob
);
978 numbers
[4].start
= buf_getptr(keyblob
, numbers
[4].bytes
);
979 buf_incrpos(keyblob
, numbers
[4].bytes
);
982 numbers
[5].bytes
= buf_getint(keyblob
);
983 numbers
[5].start
= buf_getptr(keyblob
, numbers
[5].bytes
);
984 buf_incrpos(keyblob
, numbers
[5].bytes
);
987 header
= "-----BEGIN DSA PRIVATE KEY-----\n";
988 footer
= "-----END DSA PRIVATE KEY-----\n";
990 #endif /* DROPBEAR_DSS */
993 * Now count up the total size of the ASN.1 encoded integers,
994 * so as to determine the length of the containing SEQUENCE.
997 for (i
= 0; i
< nnumbers
; i
++) {
998 len
+= ber_write_id_len(NULL
, 2, numbers
[i
].bytes
, 0);
999 len
+= numbers
[i
].bytes
;
1002 /* Now add on the SEQUENCE header. */
1003 len
+= ber_write_id_len(NULL
, 16, seqlen
, ASN1_CONSTRUCTED
);
1004 /* Round up to the cipher block size, ensuring we have at least one
1005 * byte of padding (see below). */
1008 outlen
= (outlen
+8) &~ 7;
1011 * Now we know how big outblob needs to be. Allocate it.
1013 outblob
= (unsigned char*)m_malloc(outlen
);
1016 * And write the data into it.
1019 pos
+= ber_write_id_len(outblob
+pos
, 16, seqlen
, ASN1_CONSTRUCTED
);
1020 for (i
= 0; i
< nnumbers
; i
++) {
1021 pos
+= ber_write_id_len(outblob
+pos
, 2, numbers
[i
].bytes
, 0);
1022 memcpy(outblob
+pos
, numbers
[i
].start
, numbers
[i
].bytes
);
1023 pos
+= numbers
[i
].bytes
;
1025 } /* end RSA and DSS handling */
1027 #ifdef DROPBEAR_ECDSA
1028 if (key
->type
== DROPBEAR_SIGNKEY_ECDSA_NISTP256
1029 || key
->type
== DROPBEAR_SIGNKEY_ECDSA_NISTP384
1030 || key
->type
== DROPBEAR_SIGNKEY_ECDSA_NISTP521
) {
1032 /* SEC1 V2 appendix c.4
1033 ECPrivateKey ::= SEQUENCE {
1034 version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
1035 privateKey OCTET STRING,
1036 parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL,
1037 publicKey [1] BIT STRING OPTIONAL
1040 buffer
*seq_buf
= buf_new(400);
1041 ecc_key
**eck
= (ecc_key
**)signkey_key_ptr(key
, key
->type
);
1042 const long curve_size
= (*eck
)->dp
->size
;
1043 int curve_oid_len
= 0;
1044 const void* curve_oid
= NULL
;
1045 unsigned long pubkey_size
= 2*curve_size
+1;
1049 /* version. less than 10 bytes */
1050 buf_incrwritepos(seq_buf
,
1051 ber_write_id_len(buf_getwriteptr(seq_buf
, 10), 2, 1, 0));
1052 buf_putbyte(seq_buf
, 1);
1055 k_size
= mp_unsigned_bin_size((*eck
)->k
);
1056 dropbear_assert(k_size
<= curve_size
);
1057 buf_incrwritepos(seq_buf
,
1058 ber_write_id_len(buf_getwriteptr(seq_buf
, 10), 4, k_size
, 0));
1059 mp_to_unsigned_bin((*eck
)->k
, buf_getwriteptr(seq_buf
, k_size
));
1060 buf_incrwritepos(seq_buf
, k_size
);
1062 /* SECGCurveNames */
1065 case DROPBEAR_SIGNKEY_ECDSA_NISTP256
:
1066 curve_oid_len
= sizeof(OID_SEC256R1_BLOB
);
1067 curve_oid
= OID_SEC256R1_BLOB
;
1069 case DROPBEAR_SIGNKEY_ECDSA_NISTP384
:
1070 curve_oid_len
= sizeof(OID_SEC384R1_BLOB
);
1071 curve_oid
= OID_SEC384R1_BLOB
;
1073 case DROPBEAR_SIGNKEY_ECDSA_NISTP521
:
1074 curve_oid_len
= sizeof(OID_SEC521R1_BLOB
);
1075 curve_oid
= OID_SEC521R1_BLOB
;
1078 dropbear_exit("Internal error");
1081 buf_incrwritepos(seq_buf
,
1082 ber_write_id_len(buf_getwriteptr(seq_buf
, 10), 0, 2+curve_oid_len
, 0xa0));
1084 buf_incrwritepos(seq_buf
,
1085 ber_write_id_len(buf_getwriteptr(seq_buf
, 10), 6, curve_oid_len
, 0));
1086 buf_putbytes(seq_buf
, curve_oid
, curve_oid_len
);
1088 buf_incrwritepos(seq_buf
,
1089 ber_write_id_len(buf_getwriteptr(seq_buf
, 10), 1, 2+1+pubkey_size
, 0xa0));
1090 buf_incrwritepos(seq_buf
,
1091 ber_write_id_len(buf_getwriteptr(seq_buf
, 10), 3, 1+pubkey_size
, 0));
1092 buf_putbyte(seq_buf
, 0);
1093 err
= ecc_ansi_x963_export(*eck
, buf_getwriteptr(seq_buf
, pubkey_size
), &pubkey_size
);
1094 if (err
!= CRYPT_OK
) {
1095 dropbear_exit("ECC error");
1097 buf_incrwritepos(seq_buf
, pubkey_size
);
1099 buf_setpos(seq_buf
, 0);
1101 outblob
= (unsigned char*)m_malloc(1000);
1104 pos
+= ber_write_id_len(outblob
+pos
, 16, seq_buf
->len
, ASN1_CONSTRUCTED
);
1105 memcpy(&outblob
[pos
], seq_buf
->data
, seq_buf
->len
);
1106 pos
+= seq_buf
->len
;
1114 header
= "-----BEGIN EC PRIVATE KEY-----\n";
1115 footer
= "-----END EC PRIVATE KEY-----\n";
1120 * Padding on OpenSSH keys is deterministic. The number of
1121 * padding bytes is always more than zero, and always at most
1122 * the cipher block length. The value of each padding byte is
1123 * equal to the number of padding bytes. So a plaintext that's
1124 * an exact multiple of the block size will be padded with 08
1125 * 08 08 08 08 08 08 08 (assuming a 64-bit block cipher); a
1126 * plaintext one byte less than a multiple of the block size
1127 * will be padded with just 01.
1129 * This enables the OpenSSL key decryption function to strip
1130 * off the padding algorithmically and return the unpadded
1131 * plaintext to the next layer: it looks at the final byte, and
1132 * then expects to find that many bytes at the end of the data
1133 * with the same value. Those are all removed and the rest is
1136 dropbear_assert(pos
== len
);
1137 while (pos
< outlen
) {
1138 outblob
[pos
++] = outlen
- len
;
1145 fprintf(stderr
, "Encrypted keys aren't supported currently\n");
1150 * And save it. We'll use Unix line endings just in case it's
1151 * subsequently transferred in binary mode.
1153 if (strlen(filename
) == 1 && filename
[0] == '-') {
1156 fp
= fopen(filename
, "wb"); /* ensure Unix line endings */
1159 fprintf(stderr
, "Failed opening output file\n");
1163 base64_encode_fp(fp
, outblob
, outlen
, 64);
1170 memset(outblob
, 0, outlen
);
1178 buf_burn(extrablob
);
1179 buf_free(extrablob
);
1185 /* XXX TODO ssh.com stuff isn't going yet */
1187 /* ----------------------------------------------------------------------
1188 * Code to read ssh.com private keys.
1192 * The format of the base64 blob is largely ssh2-packet-formatted,
1193 * except that mpints are a bit different: they're more like the
1194 * old ssh1 mpint. You have a 32-bit bit count N, followed by
1195 * (N+7)/8 bytes of data.
1197 * So. The blob contains:
1199 * - uint32 0x3f6ff9eb (magic number)
1200 * - uint32 size (total blob size)
1201 * - string key-type (see below)
1202 * - string cipher-type (tells you if key is encrypted)
1203 * - string encrypted-blob
1205 * (The first size field includes the size field itself and the
1206 * magic number before it. All other size fields are ordinary ssh2
1207 * strings, so the size field indicates how much data is to
1210 * The encrypted blob, once decrypted, contains a single string
1211 * which in turn contains the payload. (This allows padding to be
1212 * added after that string while still making it clear where the
1213 * real payload ends. Also it probably makes for a reasonable
1214 * decryption check.)
1216 * The payload blob, for an RSA key, contains:
1219 * - mpint n (yes, the public and private stuff is intermixed)
1220 * - mpint u (presumably inverse of p mod q)
1221 * - mpint p (p is the smaller prime)
1222 * - mpint q (q is the larger)
1224 * For a DSA key, the payload blob contains:
1232 * Alternatively, if the parameters are `predefined', that
1233 * (0,p,g,q) sequence can be replaced by a uint32 1 and a string
1234 * containing some predefined parameter specification. *shudder*,
1235 * but I doubt we'll encounter this in real life.
1237 * The key type strings are ghastly. The RSA key I looked at had a
1240 * `if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}'
1242 * and the DSA key wasn't much better:
1244 * `dl-modp{sign{dsa-nist-sha1},dh{plain}}'
1246 * It isn't clear that these will always be the same. I think it
1247 * might be wise just to look at the `if-modn{sign{rsa' and
1248 * `dl-modp{sign{dsa' prefixes.
1250 * Finally, the encryption. The cipher-type string appears to be
1251 * either `none' or `3des-cbc'. Looks as if this is SSH2-style
1252 * 3des-cbc (i.e. outer cbc rather than inner). The key is created
1253 * from the passphrase by means of yet another hashing faff:
1255 * - first 16 bytes are MD5(passphrase)
1256 * - next 16 bytes are MD5(passphrase || first 16 bytes)
1257 * - if there were more, they'd be MD5(passphrase || first 32),
1261 #define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb
1264 char comment
[256]; /* allowing any length is overkill */
1265 unsigned char *keyblob
;
1266 int keyblob_len
, keyblob_size
;
1269 static struct sshcom_key
*load_sshcom_key(const char *filename
)
1271 struct sshcom_key
*ret
;
1278 int base64_chars
= 0;
1280 ret
= snew(struct sshcom_key
);
1281 ret
->comment
[0] = '\0';
1282 ret
->keyblob
= NULL
;
1283 ret
->keyblob_len
= ret
->keyblob_size
= 0;
1285 fp
= fopen(filename
, "r");
1287 errmsg
= "Unable to open key file";
1290 if (!fgets(buffer
, sizeof(buffer
), fp
) ||
1291 0 != strcmp(buffer
, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) {
1292 errmsg
= "File does not begin with ssh.com key header";
1298 if (!fgets(buffer
, sizeof(buffer
), fp
)) {
1299 errmsg
= "Unexpected end of file";
1302 if (!strcmp(buffer
, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n"))
1304 if ((p
= strchr(buffer
, ':')) != NULL
) {
1306 errmsg
= "Header found in body of key data";
1310 while (*p
&& isspace((unsigned char)*p
)) p
++;
1312 * Header lines can end in a trailing backslash for
1315 while ((len
= strlen(p
)) > (int)(sizeof(buffer
) - (p
-buffer
) -1) ||
1316 p
[len
-1] != '\n' || p
[len
-2] == '\\') {
1317 if (len
> (int)((p
-buffer
) + sizeof(buffer
)-2)) {
1318 errmsg
= "Header line too long to deal with";
1321 if (!fgets(p
+len
-2, sizeof(buffer
)-(p
-buffer
)-(len
-2), fp
)) {
1322 errmsg
= "Unexpected end of file";
1326 p
[strcspn(p
, "\n")] = '\0';
1327 if (!strcmp(buffer
, "Comment")) {
1328 /* Strip quotes in comment if present. */
1329 if (p
[0] == '"' && p
[strlen(p
)-1] == '"') {
1331 p
[strlen(p
)-1] = '\0';
1333 strncpy(ret
->comment
, p
, sizeof(ret
->comment
));
1334 ret
->comment
[sizeof(ret
->comment
)-1] = '\0';
1340 while (isbase64(*p
)) {
1341 base64_bit
[base64_chars
++] = *p
;
1342 if (base64_chars
== 4) {
1343 unsigned char out
[3];
1347 len
= base64_decode_atom(base64_bit
, out
);
1350 errmsg
= "Invalid base64 encoding";
1354 if (ret
->keyblob_len
+ len
> ret
->keyblob_size
) {
1355 ret
->keyblob_size
= ret
->keyblob_len
+ len
+ 256;
1356 ret
->keyblob
= sresize(ret
->keyblob
, ret
->keyblob_size
,
1360 memcpy(ret
->keyblob
+ ret
->keyblob_len
, out
, len
);
1361 ret
->keyblob_len
+= len
;
1369 if (ret
->keyblob_len
== 0 || !ret
->keyblob
) {
1370 errmsg
= "Key body not present";
1379 memset(ret
->keyblob
, 0, ret
->keyblob_size
);
1380 m_free(ret
->keyblob
);
1382 memset(&ret
, 0, sizeof(ret
));
1388 int sshcom_encrypted(const char *filename
, char **comment
)
1390 struct sshcom_key
*key
= load_sshcom_key(filename
);
1391 int pos
, len
, answer
;
1398 * Check magic number.
1400 if (GET_32BIT(key
->keyblob
) != 0x3f6ff9eb)
1401 return 0; /* key is invalid */
1404 * Find the cipher-type string.
1408 if (key
->keyblob_len
< pos
+4)
1409 goto done
; /* key is far too short */
1410 pos
+= 4 + GET_32BIT(key
->keyblob
+ pos
); /* skip key type */
1411 if (key
->keyblob_len
< pos
+4)
1412 goto done
; /* key is far too short */
1413 len
= GET_32BIT(key
->keyblob
+ pos
); /* find cipher-type length */
1414 if (key
->keyblob_len
< pos
+4+len
)
1415 goto done
; /* cipher type string is incomplete */
1416 if (len
!= 4 || 0 != memcmp(key
->keyblob
+ pos
+ 4, "none", 4))
1420 *comment
= dupstr(key
->comment
);
1421 memset(key
->keyblob
, 0, key
->keyblob_size
);
1422 m_free(key
->keyblob
);
1423 memset(&key
, 0, sizeof(key
));
1428 static int sshcom_read_mpint(void *data
, int len
, struct mpint_pos
*ret
)
1432 unsigned char *d
= (unsigned char *) data
;
1436 bits
= GET_32BIT(d
);
1438 bytes
= (bits
+ 7) / 8;
1449 return len
; /* ensure further calls fail as well */
1452 static int sshcom_put_mpint(void *target
, void *data
, int len
)
1454 unsigned char *d
= (unsigned char *)target
;
1455 unsigned char *i
= (unsigned char *)data
;
1456 int bits
= len
* 8 - 1;
1459 if (*i
& (1 << (bits
& 7)))
1465 PUT_32BIT(d
, bits
+1);
1466 memcpy(d
+4, i
, len
);
1470 sign_key
*sshcom_read(const char *filename
, char *passphrase
)
1472 struct sshcom_key
*key
= load_sshcom_key(filename
);
1475 const char prefix_rsa
[] = "if-modn{sign{rsa";
1476 const char prefix_dsa
[] = "dl-modp{sign{dsa";
1477 enum { RSA
, DSA
} type
;
1481 struct ssh2_userkey
*ret
= NULL
, *retkey
;
1482 const struct ssh_signkey
*alg
;
1483 unsigned char *blob
= NULL
;
1484 int blobsize
, publen
, privlen
;
1490 * Check magic number.
1492 if (GET_32BIT(key
->keyblob
) != SSHCOM_MAGIC_NUMBER
) {
1493 errmsg
= "Key does not begin with magic number";
1498 * Determine the key type.
1501 if (key
->keyblob_len
< pos
+4 ||
1502 (len
= GET_32BIT(key
->keyblob
+ pos
)) > key
->keyblob_len
- pos
- 4) {
1503 errmsg
= "Key blob does not contain a key type string";
1506 if (len
> sizeof(prefix_rsa
) - 1 &&
1507 !memcmp(key
->keyblob
+pos
+4, prefix_rsa
, sizeof(prefix_rsa
) - 1)) {
1509 } else if (len
> sizeof(prefix_dsa
) - 1 &&
1510 !memcmp(key
->keyblob
+pos
+4, prefix_dsa
, sizeof(prefix_dsa
) - 1)) {
1513 errmsg
= "Key is of unknown type";
1519 * Determine the cipher type.
1521 if (key
->keyblob_len
< pos
+4 ||
1522 (len
= GET_32BIT(key
->keyblob
+ pos
)) > key
->keyblob_len
- pos
- 4) {
1523 errmsg
= "Key blob does not contain a cipher type string";
1526 if (len
== 4 && !memcmp(key
->keyblob
+pos
+4, "none", 4))
1528 else if (len
== 8 && !memcmp(key
->keyblob
+pos
+4, "3des-cbc", 8))
1531 errmsg
= "Key encryption is of unknown type";
1537 * Get hold of the encrypted part of the key.
1539 if (key
->keyblob_len
< pos
+4 ||
1540 (len
= GET_32BIT(key
->keyblob
+ pos
)) > key
->keyblob_len
- pos
- 4) {
1541 errmsg
= "Key blob does not contain actual key data";
1544 ciphertext
= (char *)key
->keyblob
+ pos
+ 4;
1546 if (cipherlen
== 0) {
1547 errmsg
= "Length of key data is zero";
1552 * Decrypt it if necessary.
1556 * Derive encryption key from passphrase and iv/salt:
1558 * - let block A equal MD5(passphrase)
1559 * - let block B equal MD5(passphrase || A)
1560 * - block C would be MD5(passphrase || A || B) and so on
1561 * - encryption key is the first N bytes of A || B
1563 struct MD5Context md5c
;
1564 unsigned char keybuf
[32], iv
[8];
1566 if (cipherlen
% 8 != 0) {
1567 errmsg
= "Encrypted part of key is not a multiple of cipher block"
1573 MD5Update(&md5c
, (unsigned char *)passphrase
, strlen(passphrase
));
1574 MD5Final(keybuf
, &md5c
);
1577 MD5Update(&md5c
, (unsigned char *)passphrase
, strlen(passphrase
));
1578 MD5Update(&md5c
, keybuf
, 16);
1579 MD5Final(keybuf
+16, &md5c
);
1582 * Now decrypt the key blob.
1584 memset(iv
, 0, sizeof(iv
));
1585 des3_decrypt_pubkey_ossh(keybuf
, iv
, (unsigned char *)ciphertext
,
1588 memset(&md5c
, 0, sizeof(md5c
));
1589 memset(keybuf
, 0, sizeof(keybuf
));
1592 * Hereafter we return WRONG_PASSPHRASE for any parsing
1593 * error. (But only if we've just tried to decrypt it!
1594 * Returning WRONG_PASSPHRASE for an unencrypted key is
1598 ret
= SSH2_WRONG_PASSPHRASE
;
1602 * Strip away the containing string to get to the real meat.
1604 len
= GET_32BIT(ciphertext
);
1605 if (len
> cipherlen
-4) {
1606 errmsg
= "containing string was ill-formed";
1613 * Now we break down into RSA versus DSA. In either case we'll
1614 * construct public and private blobs in our own format, and
1615 * end up feeding them to alg->createkey().
1617 blobsize
= cipherlen
+ 256;
1618 blob
= snewn(blobsize
, unsigned char);
1621 struct mpint_pos n
, e
, d
, u
, p
, q
;
1623 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &e
);
1624 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &d
);
1625 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &n
);
1626 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &u
);
1627 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &p
);
1628 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &q
);
1630 errmsg
= "key data did not contain six integers";
1636 pos
+= put_string(blob
+pos
, "ssh-rsa", 7);
1637 pos
+= put_mp(blob
+pos
, e
.start
, e
.bytes
);
1638 pos
+= put_mp(blob
+pos
, n
.start
, n
.bytes
);
1640 pos
+= put_string(blob
+pos
, d
.start
, d
.bytes
);
1641 pos
+= put_mp(blob
+pos
, q
.start
, q
.bytes
);
1642 pos
+= put_mp(blob
+pos
, p
.start
, p
.bytes
);
1643 pos
+= put_mp(blob
+pos
, u
.start
, u
.bytes
);
1644 privlen
= pos
- publen
;
1645 } else if (type
== DSA
) {
1646 struct mpint_pos p
, q
, g
, x
, y
;
1648 if (GET_32BIT(ciphertext
) != 0) {
1649 errmsg
= "predefined DSA parameters not supported";
1652 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &p
);
1653 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &g
);
1654 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &q
);
1655 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &y
);
1656 pos
+= sshcom_read_mpint(ciphertext
+pos
, cipherlen
-pos
, &x
);
1658 errmsg
= "key data did not contain five integers";
1664 pos
+= put_string(blob
+pos
, "ssh-dss", 7);
1665 pos
+= put_mp(blob
+pos
, p
.start
, p
.bytes
);
1666 pos
+= put_mp(blob
+pos
, q
.start
, q
.bytes
);
1667 pos
+= put_mp(blob
+pos
, g
.start
, g
.bytes
);
1668 pos
+= put_mp(blob
+pos
, y
.start
, y
.bytes
);
1670 pos
+= put_mp(blob
+pos
, x
.start
, x
.bytes
);
1671 privlen
= pos
- publen
;
1674 dropbear_assert(privlen
> 0); /* should have bombed by now if not */
1676 retkey
= snew(struct ssh2_userkey
);
1678 retkey
->data
= alg
->createkey(blob
, publen
, blob
+publen
, privlen
);
1679 if (!retkey
->data
) {
1681 errmsg
= "unable to create key data structure";
1684 retkey
->comment
= dupstr(key
->comment
);
1686 errmsg
= NULL
; /* no error */
1691 memset(blob
, 0, blobsize
);
1694 memset(key
->keyblob
, 0, key
->keyblob_size
);
1695 m_free(key
->keyblob
);
1696 memset(&key
, 0, sizeof(key
));
1701 int sshcom_write(const char *filename
, sign_key
*key
,
1704 unsigned char *pubblob
, *privblob
;
1705 int publen
, privlen
;
1706 unsigned char *outblob
;
1708 struct mpint_pos numbers
[6];
1709 int nnumbers
, initial_zero
, pos
, lenpos
, i
;
1717 * Fetch the key blobs.
1719 pubblob
= key
->alg
->public_blob(key
->data
, &publen
);
1720 privblob
= key
->alg
->private_blob(key
->data
, &privlen
);
1724 * Find the sequence of integers to be encoded into the OpenSSH
1725 * key blob, and also decide on the header line.
1727 if (key
->alg
== &ssh_rsa
) {
1729 struct mpint_pos n
, e
, d
, p
, q
, iqmp
;
1731 pos
= 4 + GET_32BIT(pubblob
);
1732 pos
+= ssh2_read_mpint(pubblob
+pos
, publen
-pos
, &e
);
1733 pos
+= ssh2_read_mpint(pubblob
+pos
, publen
-pos
, &n
);
1735 pos
+= ssh2_read_mpint(privblob
+pos
, privlen
-pos
, &d
);
1736 pos
+= ssh2_read_mpint(privblob
+pos
, privlen
-pos
, &p
);
1737 pos
+= ssh2_read_mpint(privblob
+pos
, privlen
-pos
, &q
);
1738 pos
+= ssh2_read_mpint(privblob
+pos
, privlen
-pos
, &iqmp
);
1740 dropbear_assert(e
.start
&& iqmp
.start
); /* can't go wrong */
1751 type
= "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}";
1752 } else if (key
->alg
== &ssh_dss
) {
1754 struct mpint_pos p
, q
, g
, y
, x
;
1756 pos
= 4 + GET_32BIT(pubblob
);
1757 pos
+= ssh2_read_mpint(pubblob
+pos
, publen
-pos
, &p
);
1758 pos
+= ssh2_read_mpint(pubblob
+pos
, publen
-pos
, &q
);
1759 pos
+= ssh2_read_mpint(pubblob
+pos
, publen
-pos
, &g
);
1760 pos
+= ssh2_read_mpint(pubblob
+pos
, publen
-pos
, &y
);
1762 pos
+= ssh2_read_mpint(privblob
+pos
, privlen
-pos
, &x
);
1764 dropbear_assert(y
.start
&& x
.start
); /* can't go wrong */
1774 type
= "dl-modp{sign{dsa-nist-sha1},dh{plain}}";
1776 dropbear_assert(0); /* zoinks! */
1780 * Total size of key blob will be somewhere under 512 plus
1781 * combined length of integers. We'll calculate the more
1782 * precise size as we construct the blob.
1785 for (i
= 0; i
< nnumbers
; i
++)
1786 outlen
+= 4 + numbers
[i
].bytes
;
1787 outblob
= snewn(outlen
, unsigned char);
1790 * Create the unencrypted key blob.
1793 PUT_32BIT(outblob
+pos
, SSHCOM_MAGIC_NUMBER
); pos
+= 4;
1794 pos
+= 4; /* length field, fill in later */
1795 pos
+= put_string(outblob
+pos
, type
, strlen(type
));
1797 char *ciphertype
= passphrase
? "3des-cbc" : "none";
1798 pos
+= put_string(outblob
+pos
, ciphertype
, strlen(ciphertype
));
1800 lenpos
= pos
; /* remember this position */
1801 pos
+= 4; /* encrypted-blob size */
1802 pos
+= 4; /* encrypted-payload size */
1804 PUT_32BIT(outblob
+pos
, 0);
1807 for (i
= 0; i
< nnumbers
; i
++)
1808 pos
+= sshcom_put_mpint(outblob
+pos
,
1809 numbers
[i
].start
, numbers
[i
].bytes
);
1810 /* Now wrap up the encrypted payload. */
1811 PUT_32BIT(outblob
+lenpos
+4, pos
- (lenpos
+8));
1812 /* Pad encrypted blob to a multiple of cipher block size. */
1814 int padding
= -(pos
- (lenpos
+4)) & 7;
1816 outblob
[pos
++] = random_byte();
1818 ciphertext
= (char *)outblob
+lenpos
+4;
1819 cipherlen
= pos
- (lenpos
+4);
1820 dropbear_assert(!passphrase
|| cipherlen
% 8 == 0);
1821 /* Wrap up the encrypted blob string. */
1822 PUT_32BIT(outblob
+lenpos
, cipherlen
);
1823 /* And finally fill in the total length field. */
1824 PUT_32BIT(outblob
+4, pos
);
1826 dropbear_assert(pos
< outlen
);
1833 * Derive encryption key from passphrase and iv/salt:
1835 * - let block A equal MD5(passphrase)
1836 * - let block B equal MD5(passphrase || A)
1837 * - block C would be MD5(passphrase || A || B) and so on
1838 * - encryption key is the first N bytes of A || B
1840 struct MD5Context md5c
;
1841 unsigned char keybuf
[32], iv
[8];
1844 MD5Update(&md5c
, (unsigned char *)passphrase
, strlen(passphrase
));
1845 MD5Final(keybuf
, &md5c
);
1848 MD5Update(&md5c
, (unsigned char *)passphrase
, strlen(passphrase
));
1849 MD5Update(&md5c
, keybuf
, 16);
1850 MD5Final(keybuf
+16, &md5c
);
1853 * Now decrypt the key blob.
1855 memset(iv
, 0, sizeof(iv
));
1856 des3_encrypt_pubkey_ossh(keybuf
, iv
, (unsigned char *)ciphertext
,
1859 memset(&md5c
, 0, sizeof(md5c
));
1860 memset(keybuf
, 0, sizeof(keybuf
));
1864 * And save it. We'll use Unix line endings just in case it's
1865 * subsequently transferred in binary mode.
1867 fp
= fopen(filename
, "wb"); /* ensure Unix line endings */
1870 fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp
);
1871 fprintf(fp
, "Comment: \"");
1873 * Comment header is broken with backslash-newline if it goes
1874 * over 70 chars. Although it's surrounded by quotes, it
1875 * _doesn't_ escape backslashes or quotes within the string.
1876 * Don't ask me, I didn't design it.
1879 int slen
= 60; /* starts at 60 due to "Comment: " */
1880 char *c
= key
->comment
;
1881 while ((int)strlen(c
) > slen
) {
1882 fprintf(fp
, "%.*s\\\n", slen
, c
);
1884 slen
= 70; /* allow 70 chars on subsequent lines */
1886 fprintf(fp
, "%s\"\n", c
);
1888 base64_encode_fp(fp
, outblob
, pos
, 70);
1889 fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp
);
1895 memset(outblob
, 0, outlen
);
1899 memset(privblob
, 0, privlen
);
1903 memset(pubblob
, 0, publen
);
1908 #endif /* ssh.com stuff disabled */