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