Mercurial > dropbear
comparison keyimport.c @ 1308:8678e2cc1e53
make indenting consistent
author | Matt Johnston <matt@ucc.asn.au> |
---|---|
date | Tue, 12 Jul 2016 23:33:15 +0800 |
parents | ad9c40aca3bc |
children | 2c9dac2d6707 |
comparison
equal
deleted
inserted
replaced
1307:ad9c40aca3bc | 1308:8678e2cc1e53 |
---|---|
45 (cp)[2] = (unsigned char)((value) >> 8); \ | 45 (cp)[2] = (unsigned char)((value) >> 8); \ |
46 (cp)[1] = (unsigned char)((value) >> 16); \ | 46 (cp)[1] = (unsigned char)((value) >> 16); \ |
47 (cp)[0] = (unsigned char)((value) >> 24); } while (0) | 47 (cp)[0] = (unsigned char)((value) >> 24); } while (0) |
48 | 48 |
49 #define GET_32BIT(cp) \ | 49 #define GET_32BIT(cp) \ |
50 (((unsigned long)(unsigned char)(cp)[0] << 24) | \ | 50 (((unsigned long)(unsigned char)(cp)[0] << 24) | \ |
51 ((unsigned long)(unsigned char)(cp)[1] << 16) | \ | 51 ((unsigned long)(unsigned char)(cp)[1] << 16) | \ |
52 ((unsigned long)(unsigned char)(cp)[2] << 8) | \ | 52 ((unsigned long)(unsigned char)(cp)[2] << 8) | \ |
53 ((unsigned long)(unsigned char)(cp)[3])) | 53 ((unsigned long)(unsigned char)(cp)[3])) |
54 | 54 |
55 static int openssh_encrypted(const char *filename); | 55 static int openssh_encrypted(const char *filename); |
56 static sign_key *openssh_read(const char *filename, char *passphrase); | 56 static sign_key *openssh_read(const char *filename, char *passphrase); |
57 static int openssh_write(const char *filename, sign_key *key, | 57 static int openssh_write(const char *filename, sign_key *key, |
58 char *passphrase); | 58 char *passphrase); |
59 | 59 |
60 static int dropbear_write(const char*filename, sign_key * key); | 60 static int dropbear_write(const char*filename, sign_key * key); |
61 static sign_key *dropbear_read(const char* filename); | 61 static sign_key *dropbear_read(const char* filename); |
62 | 62 |
63 static int toint(unsigned u); | 63 static int toint(unsigned u); |
64 | 64 |
65 #if 0 | 65 #if 0 |
66 static int sshcom_encrypted(const char *filename, char **comment); | 66 static int sshcom_encrypted(const char *filename, char **comment); |
67 static struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase); | 67 static struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase); |
68 static int sshcom_write(const char *filename, struct ssh2_userkey *key, | 68 static int sshcom_write(const char *filename, struct ssh2_userkey *key, |
69 char *passphrase); | 69 char *passphrase); |
70 #endif | 70 #endif |
71 | 71 |
72 int import_encrypted(const char* filename, int filetype) { | 72 int import_encrypted(const char* filename, int filetype) { |
73 | 73 |
74 if (filetype == KEYFILE_OPENSSH) { | 74 if (filetype == KEYFILE_OPENSSH) { |
75 return openssh_encrypted(filename); | 75 return openssh_encrypted(filename); |
76 #if 0 | 76 #if 0 |
77 } else if (filetype == KEYFILE_SSHCOM) { | 77 } else if (filetype == KEYFILE_SSHCOM) { |
78 return sshcom_encrypted(filename, NULL); | 78 return sshcom_encrypted(filename, NULL); |
79 #endif | 79 #endif |
80 } | 80 } |
81 return 0; | 81 return 0; |
82 } | 82 } |
83 | 83 |
84 sign_key *import_read(const char *filename, char *passphrase, int filetype) { | 84 sign_key *import_read(const char *filename, char *passphrase, int filetype) { |
85 | 85 |
86 if (filetype == KEYFILE_OPENSSH) { | 86 if (filetype == KEYFILE_OPENSSH) { |
87 return openssh_read(filename, passphrase); | 87 return openssh_read(filename, passphrase); |
88 } else if (filetype == KEYFILE_DROPBEAR) { | 88 } else if (filetype == KEYFILE_DROPBEAR) { |
89 return dropbear_read(filename); | 89 return dropbear_read(filename); |
90 #if 0 | 90 #if 0 |
91 } else if (filetype == KEYFILE_SSHCOM) { | 91 } else if (filetype == KEYFILE_SSHCOM) { |
92 return sshcom_read(filename, passphrase); | 92 return sshcom_read(filename, passphrase); |
93 #endif | 93 #endif |
94 } | 94 } |
95 return NULL; | |
96 } | |
97 | |
98 int import_write(const char *filename, sign_key *key, char *passphrase, | |
99 int filetype) { | |
100 | |
101 if (filetype == KEYFILE_OPENSSH) { | |
102 return openssh_write(filename, key, passphrase); | |
103 } else if (filetype == KEYFILE_DROPBEAR) { | |
104 return dropbear_write(filename, key); | |
105 #if 0 | |
106 } else if (filetype == KEYFILE_SSHCOM) { | |
107 return sshcom_write(filename, key, passphrase); | |
108 #endif | |
109 } | |
110 return 0; | |
111 } | |
112 | |
113 static sign_key *dropbear_read(const char* filename) { | |
114 | |
115 buffer * buf = NULL; | |
116 sign_key *ret = NULL; | |
117 enum signkey_type type; | |
118 | |
119 buf = buf_new(MAX_PRIVKEY_SIZE); | |
120 if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) { | |
121 goto error; | |
122 } | |
123 | |
124 buf_setpos(buf, 0); | |
125 ret = new_sign_key(); | |
126 | |
127 type = DROPBEAR_SIGNKEY_ANY; | |
128 if (buf_get_priv_key(buf, ret, &type) == DROPBEAR_FAILURE){ | |
129 goto error; | |
130 } | |
131 buf_free(buf); | |
132 | |
133 ret->type = type; | |
134 | |
135 return ret; | |
136 | |
137 error: | |
138 if (buf) { | |
139 buf_free(buf); | |
140 } | |
141 if (ret) { | |
142 sign_key_free(ret); | |
143 } | |
144 return NULL; | 95 return NULL; |
145 } | 96 } |
146 | 97 |
98 int import_write(const char *filename, sign_key *key, char *passphrase, | |
99 int filetype) { | |
100 | |
101 if (filetype == KEYFILE_OPENSSH) { | |
102 return openssh_write(filename, key, passphrase); | |
103 } else if (filetype == KEYFILE_DROPBEAR) { | |
104 return dropbear_write(filename, key); | |
105 #if 0 | |
106 } else if (filetype == KEYFILE_SSHCOM) { | |
107 return sshcom_write(filename, key, passphrase); | |
108 #endif | |
109 } | |
110 return 0; | |
111 } | |
112 | |
113 static sign_key *dropbear_read(const char* filename) { | |
114 | |
115 buffer * buf = NULL; | |
116 sign_key *ret = NULL; | |
117 enum signkey_type type; | |
118 | |
119 buf = buf_new(MAX_PRIVKEY_SIZE); | |
120 if (buf_readfile(buf, filename) == DROPBEAR_FAILURE) { | |
121 goto error; | |
122 } | |
123 | |
124 buf_setpos(buf, 0); | |
125 ret = new_sign_key(); | |
126 | |
127 type = DROPBEAR_SIGNKEY_ANY; | |
128 if (buf_get_priv_key(buf, ret, &type) == DROPBEAR_FAILURE){ | |
129 goto error; | |
130 } | |
131 buf_free(buf); | |
132 | |
133 ret->type = type; | |
134 | |
135 return ret; | |
136 | |
137 error: | |
138 if (buf) { | |
139 buf_free(buf); | |
140 } | |
141 if (ret) { | |
142 sign_key_free(ret); | |
143 } | |
144 return NULL; | |
145 } | |
146 | |
147 /* returns 0 on fail, 1 on success */ | 147 /* returns 0 on fail, 1 on success */ |
148 static int dropbear_write(const char*filename, sign_key * key) { | 148 static int dropbear_write(const char*filename, sign_key * key) { |
149 | 149 |
150 buffer * buf; | 150 buffer * buf; |
151 FILE*fp; | 151 FILE*fp; |
152 int len; | 152 int len; |
153 int ret; | 153 int ret; |
154 | 154 |
155 buf = buf_new(MAX_PRIVKEY_SIZE); | 155 buf = buf_new(MAX_PRIVKEY_SIZE); |
156 buf_put_priv_key(buf, key, key->type); | 156 buf_put_priv_key(buf, key, key->type); |
157 | 157 |
158 fp = fopen(filename, "w"); | 158 fp = fopen(filename, "w"); |
159 if (!fp) { | 159 if (!fp) { |
160 ret = 0; | 160 ret = 0; |
161 goto out; | 161 goto out; |
162 } | 162 } |
163 | 163 |
164 buf_setpos(buf, 0); | 164 buf_setpos(buf, 0); |
165 do { | 165 do { |
166 len = fwrite(buf_getptr(buf, buf->len - buf->pos), | 166 len = fwrite(buf_getptr(buf, buf->len - buf->pos), |
167 1, buf->len - buf->pos, fp); | 167 1, buf->len - buf->pos, fp); |
168 buf_incrpos(buf, len); | 168 buf_incrpos(buf, len); |
169 } while (len > 0 && buf->len != buf->pos); | 169 } while (len > 0 && buf->len != buf->pos); |
170 | 170 |
171 fclose(fp); | 171 fclose(fp); |
172 | 172 |
173 if (buf->pos != buf->len) { | 173 if (buf->pos != buf->len) { |
174 ret = 0; | 174 ret = 0; |
175 } else { | 175 } else { |
176 ret = 1; | 176 ret = 1; |
177 } | 177 } |
178 out: | 178 out: |
179 buf_free(buf); | 179 buf_free(buf); |
180 return ret; | 180 return ret; |
181 } | 181 } |
182 | 182 |
183 | 183 |
184 /* ---------------------------------------------------------------------- | 184 /* ---------------------------------------------------------------------- |
185 * Helper routines. (The base64 ones are defined in sshpubk.c.) | 185 * Helper routines. (The base64 ones are defined in sshpubk.c.) |
186 */ | 186 */ |
187 | 187 |
188 #define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \ | 188 #define isbase64(c) ( ((c) >= 'A' && (c) <= 'Z') || \ |
189 ((c) >= 'a' && (c) <= 'z') || \ | 189 ((c) >= 'a' && (c) <= 'z') || \ |
190 ((c) >= '0' && (c) <= '9') || \ | 190 ((c) >= '0' && (c) <= '9') || \ |
191 (c) == '+' || (c) == '/' || (c) == '=' \ | 191 (c) == '+' || (c) == '/' || (c) == '=' \ |
192 ) | 192 ) |
193 | 193 |
194 /* cpl has to be less than 100 */ | 194 /* cpl has to be less than 100 */ |
195 static void base64_encode_fp(FILE * fp, unsigned char *data, | 195 static void base64_encode_fp(FILE * fp, unsigned char *data, |
196 int datalen, int cpl) | 196 int datalen, int cpl) |
197 { | 197 { |
198 unsigned char out[100]; | 198 unsigned char out[100]; |
199 int n; | 199 int n; |
200 unsigned long outlen; | 200 unsigned long outlen; |
201 int rawcpl; | 201 int rawcpl; |
202 rawcpl = cpl * 3 / 4; | 202 rawcpl = cpl * 3 / 4; |
203 dropbear_assert((unsigned int)cpl < sizeof(out)); | 203 dropbear_assert((unsigned int)cpl < sizeof(out)); |
204 | 204 |
205 while (datalen > 0) { | 205 while (datalen > 0) { |
206 n = (datalen < rawcpl ? datalen : rawcpl); | 206 n = (datalen < rawcpl ? datalen : rawcpl); |
207 outlen = sizeof(out); | 207 outlen = sizeof(out); |
208 base64_encode(data, n, out, &outlen); | 208 base64_encode(data, n, out, &outlen); |
209 data += n; | 209 data += n; |
210 datalen -= n; | 210 datalen -= n; |
211 fwrite(out, 1, outlen, fp); | 211 fwrite(out, 1, outlen, fp); |
212 fputc('\n', fp); | 212 fputc('\n', fp); |
213 } | 213 } |
214 } | 214 } |
215 /* | 215 /* |
216 * Read an ASN.1/BER identifier and length pair. | 216 * Read an ASN.1/BER identifier and length pair. |
217 * | 217 * |
218 * Flags are a combination of the #defines listed below. | 218 * Flags are a combination of the #defines listed below. |
230 | 230 |
231 /* Primitive versus constructed bit. */ | 231 /* Primitive versus constructed bit. */ |
232 #define ASN1_CONSTRUCTED (1 << 5) | 232 #define ASN1_CONSTRUCTED (1 << 5) |
233 | 233 |
234 static int ber_read_id_len(void *source, int sourcelen, | 234 static int ber_read_id_len(void *source, int sourcelen, |
235 int *id, int *length, int *flags) | 235 int *id, int *length, int *flags) |
236 { | 236 { |
237 unsigned char *p = (unsigned char *) source; | 237 unsigned char *p = (unsigned char *) source; |
238 | 238 |
239 if (sourcelen == 0) | 239 if (sourcelen == 0) |
240 return -1; | |
241 | |
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; | 240 return -1; |
249 *id = (*id << 7) | (*p & 0x7F); | 241 |
250 } | 242 *flags = (*p & 0xE0); |
251 p++, sourcelen--; | 243 if ((*p & 0x1F) == 0x1F) { |
252 } else { | 244 *id = 0; |
253 *id = *p & 0x1F; | 245 while (*p & 0x80) { |
254 p++, sourcelen--; | 246 p++, sourcelen--; |
255 } | 247 if (sourcelen == 0) |
256 | 248 return -1; |
257 if (sourcelen == 0) | 249 *id = (*id << 7) | (*p & 0x7F); |
258 return -1; | 250 } |
259 | 251 p++, sourcelen--; |
260 if (*p & 0x80) { | 252 } else { |
261 unsigned len; | 253 *id = *p & 0x1F; |
262 int n = *p & 0x7F; | 254 p++, sourcelen--; |
263 p++, sourcelen--; | 255 } |
264 if (sourcelen < n) | 256 |
265 return -1; | 257 if (sourcelen == 0) |
266 len = 0; | 258 return -1; |
267 while (n--) | 259 |
268 len = (len << 8) | (*p++); | 260 if (*p & 0x80) { |
269 sourcelen -= n; | 261 unsigned len; |
270 *length = toint(len); | 262 int n = *p & 0x7F; |
271 } else { | 263 p++, sourcelen--; |
272 *length = *p; | 264 if (sourcelen < n) |
273 p++, sourcelen--; | 265 return -1; |
274 } | 266 len = 0; |
275 | 267 while (n--) |
276 if (*length < 0) { | 268 len = (len << 8) | (*p++); |
277 printf("Negative ASN.1 length\n"); | 269 sourcelen -= n; |
278 return -1; | 270 *length = toint(len); |
279 } | 271 } else { |
280 | 272 *length = *p; |
281 return p - (unsigned char *) source; | 273 p++, sourcelen--; |
274 } | |
275 | |
276 if (*length < 0) { | |
277 printf("Negative ASN.1 length\n"); | |
278 return -1; | |
279 } | |
280 | |
281 return p - (unsigned char *) source; | |
282 } | 282 } |
283 | 283 |
284 /* | 284 /* |
285 * Write an ASN.1/BER identifier and length pair. Returns the | 285 * Write an ASN.1/BER identifier and length pair. Returns the |
286 * number of bytes consumed. Assumes dest contains enough space. | 286 * number of bytes consumed. Assumes dest contains enough space. |
287 * Will avoid writing anything if dest is NULL, but still return | 287 * Will avoid writing anything if dest is NULL, but still return |
288 * amount of space required. | 288 * amount of space required. |
289 */ | 289 */ |
290 static int ber_write_id_len(void *dest, int id, int length, int flags) | 290 static int ber_write_id_len(void *dest, int id, int length, int flags) |
291 { | 291 { |
292 unsigned char *d = (unsigned char *)dest; | 292 unsigned char *d = (unsigned char *)dest; |
293 int len = 0; | 293 int len = 0; |
294 | 294 |
295 if (id <= 30) { | 295 if (id <= 30) { |
296 /* | 296 /* |
297 * Identifier is one byte. | 297 * Identifier is one byte. |
298 */ | 298 */ |
299 len++; | 299 len++; |
300 if (d) *d++ = id | flags; | 300 if (d) *d++ = id | flags; |
301 } else { | 301 } else { |
302 int n; | 302 int n; |
303 /* | 303 /* |
304 * Identifier is multiple bytes: the first byte is 11111 | 304 * Identifier is multiple bytes: the first byte is 11111 |
305 * plus the flags, and subsequent bytes encode the value of | 305 * plus the flags, and subsequent bytes encode the value of |
306 * the identifier, 7 bits at a time, with the top bit 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. | 307 * each byte 1 except the last one which is 0. |
308 */ | 308 */ |
309 len++; | 309 len++; |
310 if (d) *d++ = 0x1F | flags; | 310 if (d) *d++ = 0x1F | flags; |
311 for (n = 1; (id >> (7*n)) > 0; n++) | 311 for (n = 1; (id >> (7*n)) > 0; n++) |
312 continue; /* count the bytes */ | 312 continue; /* count the bytes */ |
313 while (n--) { | 313 while (n--) { |
314 len++; | 314 len++; |
315 if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F); | 315 if (d) *d++ = (n ? 0x80 : 0) | ((id >> (7*n)) & 0x7F); |
316 } | 316 } |
317 } | 317 } |
318 | 318 |
319 if (length < 128) { | 319 if (length < 128) { |
320 /* | 320 /* |
321 * Length is one byte. | 321 * Length is one byte. |
322 */ | 322 */ |
323 len++; | 323 len++; |
324 if (d) *d++ = length; | 324 if (d) *d++ = length; |
325 } else { | 325 } else { |
326 int n; | 326 int n; |
327 /* | 327 /* |
328 * Length is multiple bytes. The first is 0x80 plus the | 328 * Length is multiple bytes. The first is 0x80 plus the |
329 * number of subsequent bytes, and the subsequent bytes | 329 * number of subsequent bytes, and the subsequent bytes |
330 * encode the actual length. | 330 * encode the actual length. |
331 */ | 331 */ |
332 for (n = 1; (length >> (8*n)) > 0; n++) | 332 for (n = 1; (length >> (8*n)) > 0; n++) |
333 continue; /* count the bytes */ | 333 continue; /* count the bytes */ |
334 len++; | 334 len++; |
335 if (d) *d++ = 0x80 | n; | 335 if (d) *d++ = 0x80 | n; |
336 while (n--) { | 336 while (n--) { |
337 len++; | 337 len++; |
338 if (d) *d++ = (length >> (8*n)) & 0xFF; | 338 if (d) *d++ = (length >> (8*n)) & 0xFF; |
339 } | 339 } |
340 } | 340 } |
341 | 341 |
342 return len; | 342 return len; |
343 } | 343 } |
344 | 344 |
345 | 345 |
346 /* Simple structure to point to an mp-int within a blob. */ | 346 /* Simple structure to point to an mp-int within a blob. */ |
347 struct mpint_pos { void *start; int bytes; }; | 347 struct mpint_pos { void *start; int bytes; }; |
350 * Code to read and write OpenSSH private keys. | 350 * Code to read and write OpenSSH private keys. |
351 */ | 351 */ |
352 | 352 |
353 enum { OSSH_DSA, OSSH_RSA, OSSH_EC }; | 353 enum { OSSH_DSA, OSSH_RSA, OSSH_EC }; |
354 struct openssh_key { | 354 struct openssh_key { |
355 int type; | 355 int type; |
356 int encrypted; | 356 int encrypted; |
357 char iv[32]; | 357 char iv[32]; |
358 unsigned char *keyblob; | 358 unsigned char *keyblob; |
359 unsigned int keyblob_len, keyblob_size; | 359 unsigned int keyblob_len, keyblob_size; |
360 }; | 360 }; |
361 | 361 |
362 static struct openssh_key *load_openssh_key(const char *filename) | 362 static struct openssh_key *load_openssh_key(const char *filename) |
363 { | 363 { |
364 struct openssh_key *ret; | 364 struct openssh_key *ret; |
365 FILE *fp = NULL; | 365 FILE *fp = NULL; |
366 char buffer[256]; | 366 char buffer[256]; |
367 char *errmsg = NULL, *p = NULL; | 367 char *errmsg = NULL, *p = NULL; |
368 int headers_done; | 368 int headers_done; |
369 unsigned long len, outlen; | 369 unsigned long len, outlen; |
370 | 370 |
371 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); | 371 ret = (struct openssh_key*)m_malloc(sizeof(struct openssh_key)); |
372 ret->keyblob = NULL; | 372 ret->keyblob = NULL; |
373 ret->keyblob_len = ret->keyblob_size = 0; | 373 ret->keyblob_len = ret->keyblob_size = 0; |
374 ret->encrypted = 0; | 374 ret->encrypted = 0; |
375 memset(ret->iv, 0, sizeof(ret->iv)); | 375 memset(ret->iv, 0, sizeof(ret->iv)); |
376 | 376 |
377 if (strlen(filename) == 1 && filename[0] == '-') { | 377 if (strlen(filename) == 1 && filename[0] == '-') { |
378 fp = stdin; | 378 fp = stdin; |
379 } else { | 379 } else { |
380 fp = fopen(filename, "r"); | 380 fp = fopen(filename, "r"); |
381 } | 381 } |
382 if (!fp) { | 382 if (!fp) { |
383 errmsg = "Unable to open key file"; | 383 errmsg = "Unable to open key file"; |
384 goto error; | 384 goto error; |
385 } | 385 } |
386 if (!fgets(buffer, sizeof(buffer), fp) || | 386 if (!fgets(buffer, sizeof(buffer), fp) || |
387 0 != strncmp(buffer, "-----BEGIN ", 11) || | 387 0 != strncmp(buffer, "-----BEGIN ", 11) || |
388 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) { | 388 0 != strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) { |
389 errmsg = "File does not begin with OpenSSH key header"; | 389 errmsg = "File does not begin with OpenSSH key header"; |
390 goto error; | 390 goto error; |
391 } | 391 } |
392 if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) | 392 if (!strcmp(buffer, "-----BEGIN RSA PRIVATE KEY-----\n")) |
393 ret->type = OSSH_RSA; | 393 ret->type = OSSH_RSA; |
394 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) | 394 else if (!strcmp(buffer, "-----BEGIN DSA PRIVATE KEY-----\n")) |
395 ret->type = OSSH_DSA; | 395 ret->type = OSSH_DSA; |
396 else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) | 396 else if (!strcmp(buffer, "-----BEGIN EC PRIVATE KEY-----\n")) |
397 ret->type = OSSH_EC; | 397 ret->type = OSSH_EC; |
398 else { | 398 else { |
399 errmsg = "Unrecognised key type"; | 399 errmsg = "Unrecognised key type"; |
400 goto error; | 400 goto error; |
401 } | 401 } |
402 | 402 |
403 headers_done = 0; | 403 headers_done = 0; |
404 while (1) { | 404 while (1) { |
405 if (!fgets(buffer, sizeof(buffer), fp)) { | 405 if (!fgets(buffer, sizeof(buffer), fp)) { |
406 errmsg = "Unexpected end of file"; | 406 errmsg = "Unexpected end of file"; |
407 goto error; | 407 goto error; |
408 } | 408 } |
409 if (0 == strncmp(buffer, "-----END ", 9) && | 409 if (0 == strncmp(buffer, "-----END ", 9) && |
410 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) | 410 0 == strcmp(buffer+strlen(buffer)-17, "PRIVATE KEY-----\n")) |
411 break; /* done */ | 411 break; /* done */ |
412 if ((p = strchr(buffer, ':')) != NULL) { | 412 if ((p = strchr(buffer, ':')) != NULL) { |
413 if (headers_done) { | 413 if (headers_done) { |
414 errmsg = "Header found in body of key data"; | 414 errmsg = "Header found in body of key data"; |
415 goto error; | 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; | |
429 | |
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 } | 416 } |
455 outlen = ret->keyblob_size - ret->keyblob_len; | 417 *p++ = '\0'; |
456 if (base64_decode((const unsigned char *)buffer, len, | 418 while (*p && isspace((unsigned char)*p)) p++; |
457 ret->keyblob + ret->keyblob_len, &outlen) != CRYPT_OK){ | 419 if (!strcmp(buffer, "Proc-Type")) { |
458 errmsg = "Error decoding base64"; | 420 if (p[0] != '4' || p[1] != ',') { |
459 goto error; | 421 errmsg = "Proc-Type is not 4 (only 4 is supported)"; |
460 } | 422 goto error; |
461 ret->keyblob_len += outlen; | 423 } |
462 } | 424 p += 2; |
463 } | 425 if (!strcmp(p, "ENCRYPTED\n")) |
464 | 426 ret->encrypted = 1; |
465 if (ret->keyblob_len == 0 || !ret->keyblob) { | 427 } else if (!strcmp(buffer, "DEK-Info")) { |
466 errmsg = "Key body not present"; | 428 int i, j; |
467 goto error; | 429 |
468 } | 430 if (strncmp(p, "DES-EDE3-CBC,", 13)) { |
469 | 431 errmsg = "Ciphers other than DES-EDE3-CBC not supported"; |
470 if (ret->encrypted && ret->keyblob_len % 8 != 0) { | 432 goto error; |
471 errmsg = "Encrypted key blob is not a multiple of cipher block size"; | 433 } |
472 goto error; | 434 p += 13; |
473 } | 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 } | |
474 | 474 |
475 m_burn(buffer, sizeof(buffer)); | 475 m_burn(buffer, sizeof(buffer)); |
476 return ret; | 476 return ret; |
477 | 477 |
478 error: | 478 error: |
479 m_burn(buffer, sizeof(buffer)); | 479 m_burn(buffer, sizeof(buffer)); |
480 if (ret) { | 480 if (ret) { |
481 if (ret->keyblob) { | 481 if (ret->keyblob) { |
482 m_burn(ret->keyblob, ret->keyblob_size); | 482 m_burn(ret->keyblob, ret->keyblob_size); |
483 m_free(ret->keyblob); | 483 m_free(ret->keyblob); |
484 } | 484 } |
485 m_free(ret); | 485 m_free(ret); |
486 } | 486 } |
487 if (fp) { | 487 if (fp) { |
488 fclose(fp); | 488 fclose(fp); |
489 } | 489 } |
490 if (errmsg) { | 490 if (errmsg) { |
491 fprintf(stderr, "Error: %s\n", errmsg); | 491 fprintf(stderr, "Error: %s\n", errmsg); |
492 } | 492 } |
493 return NULL; | 493 return NULL; |
494 } | 494 } |
495 | 495 |
496 static int openssh_encrypted(const char *filename) | 496 static int openssh_encrypted(const char *filename) |
497 { | 497 { |
498 struct openssh_key *key = load_openssh_key(filename); | 498 struct openssh_key *key = load_openssh_key(filename); |
499 int ret; | 499 int ret; |
500 | 500 |
501 if (!key) | 501 if (!key) |
502 return 0; | 502 return 0; |
503 ret = key->encrypted; | 503 ret = key->encrypted; |
504 m_burn(key->keyblob, key->keyblob_size); | 504 m_burn(key->keyblob, key->keyblob_size); |
505 m_free(key->keyblob); | 505 m_free(key->keyblob); |
506 m_free(key); | 506 m_free(key); |
507 return ret; | 507 return ret; |
508 } | 508 } |
509 | 509 |
510 static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) | 510 static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) |
511 { | 511 { |
512 struct openssh_key *key; | 512 struct openssh_key *key; |
513 unsigned char *p; | 513 unsigned char *p; |
514 int ret, id, len, flags; | 514 int ret, id, len, flags; |
515 int i, num_integers = 0; | 515 int i, num_integers = 0; |
516 sign_key *retval = NULL; | 516 sign_key *retval = NULL; |
517 char *errmsg; | 517 char *errmsg; |
518 unsigned char *modptr = NULL; | 518 unsigned char *modptr = NULL; |
519 int modlen = -9999; | 519 int modlen = -9999; |
520 enum signkey_type type; | 520 enum signkey_type type; |
521 | 521 |
522 sign_key *retkey; | 522 sign_key *retkey; |
523 buffer * blobbuf = NULL; | 523 buffer * blobbuf = NULL; |
524 | 524 |
525 retkey = new_sign_key(); | 525 retkey = new_sign_key(); |
526 | 526 |
527 key = load_openssh_key(filename); | 527 key = load_openssh_key(filename); |
528 | 528 |
529 if (!key) | 529 if (!key) |
530 return NULL; | 530 return NULL; |
531 | 531 |
532 if (key->encrypted) { | 532 if (key->encrypted) { |
533 errmsg = "encrypted keys not supported currently"; | 533 errmsg = "encrypted keys not supported currently"; |
534 goto error; | 534 goto error; |
535 #if 0 | 535 #if 0 |
536 /* matt TODO */ | 536 /* matt TODO */ |
537 /* | 537 /* |
538 * Derive encryption key from passphrase and iv/salt: | 538 * Derive encryption key from passphrase and iv/salt: |
539 * | 539 * |
540 * - let block A equal MD5(passphrase || iv) | 540 * - let block A equal MD5(passphrase || iv) |
541 * - let block B equal MD5(A || passphrase || iv) | 541 * - let block B equal MD5(A || passphrase || iv) |
542 * - block C would be MD5(B || passphrase || iv) and so on | 542 * - block C would be MD5(B || passphrase || iv) and so on |
543 * - encryption key is the first N bytes of A || B | 543 * - encryption key is the first N bytes of A || B |
544 */ | 544 */ |
545 struct MD5Context md5c; | 545 struct MD5Context md5c; |
546 unsigned char keybuf[32]; | 546 unsigned char keybuf[32]; |
547 | 547 |
548 MD5Init(&md5c); | 548 MD5Init(&md5c); |
549 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | 549 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); |
550 MD5Update(&md5c, (unsigned char *)key->iv, 8); | 550 MD5Update(&md5c, (unsigned char *)key->iv, 8); |
551 MD5Final(keybuf, &md5c); | 551 MD5Final(keybuf, &md5c); |
552 | 552 |
553 MD5Init(&md5c); | 553 MD5Init(&md5c); |
554 MD5Update(&md5c, keybuf, 16); | 554 MD5Update(&md5c, keybuf, 16); |
555 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | 555 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); |
556 MD5Update(&md5c, (unsigned char *)key->iv, 8); | 556 MD5Update(&md5c, (unsigned char *)key->iv, 8); |
557 MD5Final(keybuf+16, &md5c); | 557 MD5Final(keybuf+16, &md5c); |
558 | 558 |
559 /* | 559 /* |
560 * Now decrypt the key blob. | 560 * Now decrypt the key blob. |
561 */ | 561 */ |
562 des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv, | 562 des3_decrypt_pubkey_ossh(keybuf, (unsigned char *)key->iv, |
563 key->keyblob, key->keyblob_len); | 563 key->keyblob, key->keyblob_len); |
564 | 564 |
565 memset(&md5c, 0, sizeof(md5c)); | 565 memset(&md5c, 0, sizeof(md5c)); |
566 memset(keybuf, 0, sizeof(keybuf)); | 566 memset(keybuf, 0, sizeof(keybuf)); |
567 #endif | 567 #endif |
568 } | 568 } |
569 | 569 |
570 /* | 570 /* |
571 * Now we have a decrypted key blob, which contains an ASN.1 | 571 * Now we have a decrypted key blob, which contains an ASN.1 |
572 * encoded private key. We must now untangle the ASN.1. | 572 * encoded private key. We must now untangle the ASN.1. |
573 * | 573 * |
574 * We expect the whole key blob to be formatted as a SEQUENCE | 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 | 575 * (0x30 followed by a length code indicating that the rest of |
576 * the blob is part of the sequence). Within that SEQUENCE we | 576 * the blob is part of the sequence). Within that SEQUENCE we |
577 * expect to see a bunch of INTEGERs. What those integers mean | 577 * expect to see a bunch of INTEGERs. What those integers mean |
578 * depends on the key type: | 578 * depends on the key type: |
579 * | 579 * |
580 * - For RSA, we expect the integers to be 0, n, e, d, p, q, | 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 | 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.) | 582 * (p-1), d mod (q-1), inverse of q mod p respectively.) |
583 * | 583 * |
584 * - For DSA, we expect them to be 0, p, q, g, y, x in that | 584 * - For DSA, we expect them to be 0, p, q, g, y, x in that |
585 * order. | 585 * order. |
586 */ | 586 */ |
587 | 587 |
588 p = key->keyblob; | 588 p = key->keyblob; |
589 | 589 |
590 /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */ | 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); | 591 ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); |
592 p += ret; | 592 p += ret; |
593 if (ret < 0 || id != 16 || len < 0 || | 593 if (ret < 0 || id != 16 || len < 0 || |
594 key->keyblob+key->keyblob_len-p < len) { | 594 key->keyblob+key->keyblob_len-p < len) { |
595 errmsg = "ASN.1 decoding failure"; | 595 errmsg = "ASN.1 decoding failure"; |
596 goto error; | 596 goto error; |
597 } | 597 } |
598 | 598 |
599 /* Expect a load of INTEGERs. */ | 599 /* Expect a load of INTEGERs. */ |
600 if (key->type == OSSH_RSA) | 600 if (key->type == OSSH_RSA) |
601 num_integers = 9; | 601 num_integers = 9; |
602 else if (key->type == OSSH_DSA) | 602 else if (key->type == OSSH_DSA) |
603 num_integers = 6; | 603 num_integers = 6; |
604 else if (key->type == OSSH_EC) | 604 else if (key->type == OSSH_EC) |
605 num_integers = 1; | 605 num_integers = 1; |
606 | 606 |
607 /* | 607 /* |
608 * Space to create key blob in. | 608 * Space to create key blob in. |
609 */ | 609 */ |
610 blobbuf = buf_new(3000); | 610 blobbuf = buf_new(3000); |
611 | 611 |
612 #ifdef DROPBEAR_DSS | 612 #ifdef DROPBEAR_DSS |
613 if (key->type == OSSH_DSA) { | 613 if (key->type == OSSH_DSA) { |
614 buf_putstring(blobbuf, "ssh-dss", 7); | 614 buf_putstring(blobbuf, "ssh-dss", 7); |
615 retkey->type = DROPBEAR_SIGNKEY_DSS; | 615 retkey->type = DROPBEAR_SIGNKEY_DSS; |
616 } | 616 } |
617 #endif | 617 #endif |
618 #ifdef DROPBEAR_RSA | 618 #ifdef DROPBEAR_RSA |
619 if (key->type == OSSH_RSA) { | 619 if (key->type == OSSH_RSA) { |
620 buf_putstring(blobbuf, "ssh-rsa", 7); | 620 buf_putstring(blobbuf, "ssh-rsa", 7); |
621 retkey->type = DROPBEAR_SIGNKEY_RSA; | 621 retkey->type = DROPBEAR_SIGNKEY_RSA; |
622 } | 622 } |
623 #endif | 623 #endif |
624 | 624 |
625 for (i = 0; i < num_integers; i++) { | 625 for (i = 0; i < num_integers; i++) { |
626 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, | |
627 &id, &len, &flags); | |
628 p += ret; | |
629 if (ret < 0 || id != 2 || len < 0 || | |
630 key->keyblob+key->keyblob_len-p < len) { | |
631 errmsg = "ASN.1 decoding failure"; | |
632 goto error; | |
633 } | |
634 | |
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); | |
672 } | |
673 | |
674 /* Skip past the number. */ | |
675 p += len; | |
676 } | |
677 | |
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, | 626 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, |
692 &id, &len, &flags); | 627 &id, &len, &flags); |
693 p += ret; | 628 p += ret; |
694 /* id==4 for octet string */ | 629 if (ret < 0 || id != 2 || len < 0 || |
695 if (ret < 0 || id != 4 || len < 0 || | |
696 key->keyblob+key->keyblob_len-p < len) { | 630 key->keyblob+key->keyblob_len-p < len) { |
697 errmsg = "ASN.1 decoding failure"; | 631 errmsg = "ASN.1 decoding failure"; |
698 goto error; | 632 goto error; |
699 } | 633 } |
700 private_key_bytes = p; | 634 |
701 private_key_len = len; | 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); | |
672 } | |
673 | |
674 /* Skip past the number. */ | |
702 p += len; | 675 p += len; |
703 | 676 } |
704 /* parameters [0] ECDomainParameters {{ SECGCurveNames }} OPTIONAL, */ | 677 |
705 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, | 678 #ifdef DROPBEAR_ECDSA |
706 &id, &len, &flags); | 679 if (key->type == OSSH_EC) { |
707 p += ret; | 680 unsigned char* private_key_bytes = NULL; |
708 /* id==0 */ | 681 int private_key_len = 0; |
709 if (ret < 0 || id != 0 || len < 0) { | 682 unsigned char* public_key_bytes = NULL; |
710 errmsg = "ASN.1 decoding failure"; | 683 int public_key_len = 0; |
711 goto error; | 684 ecc_key *ecc = NULL; |
712 } | 685 const struct dropbear_ecc_curve *curve = NULL; |
713 | 686 |
714 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, | 687 /* See SEC1 v2, Appendix C.4 */ |
715 &id, &len, &flags); | 688 /* OpenSSL (so OpenSSH) seems to include the optional parts. */ |
716 p += ret; | 689 |
717 /* id==6 for object */ | 690 /* privateKey OCTET STRING, */ |
718 if (ret < 0 || id != 6 || len < 0 || | 691 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, |
719 key->keyblob+key->keyblob_len-p < len) { | 692 &id, &len, &flags); |
720 errmsg = "ASN.1 decoding failure"; | 693 p += ret; |
721 goto error; | 694 /* id==4 for octet string */ |
722 } | 695 if (ret < 0 || id != 4 || len < 0 || |
723 | 696 key->keyblob+key->keyblob_len-p < len) { |
724 if (0) {} | 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 | 725 #ifdef DROPBEAR_ECC_256 |
726 else if (len == sizeof(OID_SEC256R1_BLOB) | 726 else if (len == sizeof(OID_SEC256R1_BLOB) |
727 && memcmp(p, OID_SEC256R1_BLOB, len) == 0) { | 727 && memcmp(p, OID_SEC256R1_BLOB, len) == 0) { |
728 retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256; | 728 retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP256; |
729 curve = &ecc_curve_nistp256; | 729 curve = &ecc_curve_nistp256; |
730 } | 730 } |
731 #endif | 731 #endif |
732 #ifdef DROPBEAR_ECC_384 | 732 #ifdef DROPBEAR_ECC_384 |
733 else if (len == sizeof(OID_SEC384R1_BLOB) | 733 else if (len == sizeof(OID_SEC384R1_BLOB) |
734 && memcmp(p, OID_SEC384R1_BLOB, len) == 0) { | 734 && memcmp(p, OID_SEC384R1_BLOB, len) == 0) { |
735 retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384; | 735 retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP384; |
736 curve = &ecc_curve_nistp384; | 736 curve = &ecc_curve_nistp384; |
737 } | 737 } |
738 #endif | 738 #endif |
739 #ifdef DROPBEAR_ECC_521 | 739 #ifdef DROPBEAR_ECC_521 |
740 else if (len == sizeof(OID_SEC521R1_BLOB) | 740 else if (len == sizeof(OID_SEC521R1_BLOB) |
741 && memcmp(p, OID_SEC521R1_BLOB, len) == 0) { | 741 && memcmp(p, OID_SEC521R1_BLOB, len) == 0) { |
742 retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521; | 742 retkey->type = DROPBEAR_SIGNKEY_ECDSA_NISTP521; |
743 curve = &ecc_curve_nistp521; | 743 curve = &ecc_curve_nistp521; |
744 } | 744 } |
745 #endif | 745 #endif |
746 else { | 746 else { |
747 errmsg = "Unknown ECC key type"; | 747 errmsg = "Unknown ECC key type"; |
748 goto error; | 748 goto error; |
749 } | 749 } |
750 p += len; | 750 p += len; |
751 | 751 |
752 /* publicKey [1] BIT STRING OPTIONAL */ | 752 /* publicKey [1] BIT STRING OPTIONAL */ |
753 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, | 753 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, |
754 &id, &len, &flags); | 754 &id, &len, &flags); |
755 p += ret; | 755 p += ret; |
756 /* id==1 */ | 756 /* id==1 */ |
757 if (ret < 0 || id != 1 || len < 0) { | 757 if (ret < 0 || id != 1 || len < 0) { |
758 errmsg = "ASN.1 decoding failure"; | 758 errmsg = "ASN.1 decoding failure"; |
759 goto error; | 759 goto error; |
760 } | 760 } |
761 | 761 |
762 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, | 762 ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, |
763 &id, &len, &flags); | 763 &id, &len, &flags); |
764 p += ret; | 764 p += ret; |
765 /* id==3 for bit string */ | 765 /* id==3 for bit string */ |
766 if (ret < 0 || id != 3 || len < 0 || | 766 if (ret < 0 || id != 3 || len < 0 || |
767 key->keyblob+key->keyblob_len-p < len) { | 767 key->keyblob+key->keyblob_len-p < len) { |
768 errmsg = "ASN.1 decoding failure"; | 768 errmsg = "ASN.1 decoding failure"; |
769 goto error; | 769 goto error; |
770 } | 770 } |
771 public_key_bytes = p+1; | 771 public_key_bytes = p+1; |
772 public_key_len = len-1; | 772 public_key_len = len-1; |
773 p += len; | 773 p += len; |
774 | 774 |
775 buf_putbytes(blobbuf, public_key_bytes, public_key_len); | 775 buf_putbytes(blobbuf, public_key_bytes, public_key_len); |
776 ecc = buf_get_ecc_raw_pubkey(blobbuf, curve); | 776 ecc = buf_get_ecc_raw_pubkey(blobbuf, curve); |
777 if (!ecc) { | 777 if (!ecc) { |
778 errmsg = "Error parsing ECC key"; | 778 errmsg = "Error parsing ECC key"; |
779 goto error; | 779 goto error; |
780 } | 780 } |
781 m_mp_alloc_init_multi((mp_int**)&ecc->k, NULL); | 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) | 782 if (mp_read_unsigned_bin(ecc->k, private_key_bytes, private_key_len) |
783 != MP_OKAY) { | 783 != MP_OKAY) { |
784 errmsg = "Error parsing ECC key"; | 784 errmsg = "Error parsing ECC key"; |
785 goto error; | 785 goto error; |
786 } | 786 } |
787 | 787 |
788 *signkey_key_ptr(retkey, retkey->type) = ecc; | 788 *signkey_key_ptr(retkey, retkey->type) = ecc; |
789 } | 789 } |
790 #endif /* DROPBEAR_ECDSA */ | 790 #endif /* DROPBEAR_ECDSA */ |
791 | 791 |
792 /* | 792 /* |
793 * Now put together the actual key. Simplest way to do this is | 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 | 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 | 795 * functions; this is a bit faffy but it does mean we get all |
796 * the sanity checks for free. | 796 * the sanity checks for free. |
797 */ | 797 */ |
798 if (key->type == OSSH_RSA || key->type == OSSH_DSA) { | 798 if (key->type == OSSH_RSA || key->type == OSSH_DSA) { |
799 buf_setpos(blobbuf, 0); | 799 buf_setpos(blobbuf, 0); |
800 type = DROPBEAR_SIGNKEY_ANY; | 800 type = DROPBEAR_SIGNKEY_ANY; |
801 if (buf_get_priv_key(blobbuf, retkey, &type) | 801 if (buf_get_priv_key(blobbuf, retkey, &type) |
802 != DROPBEAR_SUCCESS) { | 802 != DROPBEAR_SUCCESS) { |
803 errmsg = "unable to create key structure"; | 803 errmsg = "unable to create key structure"; |
804 sign_key_free(retkey); | 804 sign_key_free(retkey); |
805 retkey = NULL; | 805 retkey = NULL; |
806 goto error; | 806 goto error; |
807 } | 807 } |
808 } | 808 } |
809 | 809 |
810 errmsg = NULL; /* no error */ | 810 errmsg = NULL; /* no error */ |
811 retval = retkey; | 811 retval = retkey; |
812 | 812 |
813 error: | 813 error: |
814 if (blobbuf) { | 814 if (blobbuf) { |
815 buf_burn(blobbuf); | 815 buf_burn(blobbuf); |
816 buf_free(blobbuf); | 816 buf_free(blobbuf); |
817 } | 817 } |
818 m_burn(key->keyblob, key->keyblob_size); | 818 m_burn(key->keyblob, key->keyblob_size); |
819 m_free(key->keyblob); | 819 m_free(key->keyblob); |
820 m_burn(key, sizeof(*key)); | 820 m_burn(key, sizeof(*key)); |
821 m_free(key); | 821 m_free(key); |
822 if (errmsg) { | 822 if (errmsg) { |
823 fprintf(stderr, "Error: %s\n", errmsg); | 823 fprintf(stderr, "Error: %s\n", errmsg); |
824 } | 824 } |
825 return retval; | 825 return retval; |
826 } | 826 } |
827 | 827 |
828 static int openssh_write(const char *filename, sign_key *key, | 828 static int openssh_write(const char *filename, sign_key *key, |
829 char *passphrase) | 829 char *passphrase) |
830 { | 830 { |
831 buffer * keyblob = NULL; | 831 buffer * keyblob = NULL; |
832 buffer * extrablob = NULL; /* used for calculated values to write */ | 832 buffer * extrablob = NULL; /* used for calculated values to write */ |
833 unsigned char *outblob = NULL; | 833 unsigned char *outblob = NULL; |
834 int outlen = -9999; | 834 int outlen = -9999; |
835 struct mpint_pos numbers[9]; | 835 struct mpint_pos numbers[9]; |
836 int nnumbers = -1, pos = 0, len = 0, seqlen, i; | 836 int nnumbers = -1, pos = 0, len = 0, seqlen, i; |
837 char *header = NULL, *footer = NULL; | 837 char *header = NULL, *footer = NULL; |
838 char zero[1]; | 838 char zero[1]; |
839 int ret = 0; | 839 int ret = 0; |
840 FILE *fp; | 840 FILE *fp; |
841 | 841 |
842 #ifdef DROPBEAR_RSA | 842 #ifdef DROPBEAR_RSA |
843 mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */ | 843 mp_int dmp1, dmq1, iqmp, tmpval; /* for rsa */ |
844 #endif | 844 #endif |
845 | 845 |
846 if ( | 846 if ( |
847 #ifdef DROPBEAR_RSA | 847 #ifdef DROPBEAR_RSA |
848 key->type == DROPBEAR_SIGNKEY_RSA || | 848 key->type == DROPBEAR_SIGNKEY_RSA || |
849 #endif | 849 #endif |
850 #ifdef DROPBEAR_DSS | 850 #ifdef DROPBEAR_DSS |
851 key->type == DROPBEAR_SIGNKEY_DSS || | 851 key->type == DROPBEAR_SIGNKEY_DSS || |
852 #endif | 852 #endif |
853 0) | 853 0) |
854 { | 854 { |
855 /* | 855 /* |
856 * Fetch the key blobs. | 856 * Fetch the key blobs. |
857 */ | 857 */ |
858 keyblob = buf_new(3000); | 858 keyblob = buf_new(3000); |
859 buf_put_priv_key(keyblob, key, key->type); | 859 buf_put_priv_key(keyblob, key, key->type); |
860 | 860 |
861 buf_setpos(keyblob, 0); | 861 buf_setpos(keyblob, 0); |
862 /* skip the "ssh-rsa" or "ssh-dss" header */ | 862 /* skip the "ssh-rsa" or "ssh-dss" header */ |
863 buf_incrpos(keyblob, buf_getint(keyblob)); | 863 buf_incrpos(keyblob, buf_getint(keyblob)); |
864 | 864 |
865 /* | 865 /* |
866 * Find the sequence of integers to be encoded into the OpenSSH | 866 * Find the sequence of integers to be encoded into the OpenSSH |
867 * key blob, and also decide on the header line. | 867 * key blob, and also decide on the header line. |
868 */ | 868 */ |
869 numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; | 869 numbers[0].start = zero; numbers[0].bytes = 1; zero[0] = '\0'; |
870 | 870 |
871 #ifdef DROPBEAR_RSA | 871 #ifdef DROPBEAR_RSA |
872 if (key->type == DROPBEAR_SIGNKEY_RSA) { | 872 if (key->type == DROPBEAR_SIGNKEY_RSA) { |
873 | 873 |
874 if (key->rsakey->p == NULL || key->rsakey->q == NULL) { | 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"); | 875 fprintf(stderr, "Pre-0.33 Dropbear keys cannot be converted to OpenSSH keys.\n"); |
876 goto error; | |
877 } | |
878 | |
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); | |
883 | |
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); | |
888 | |
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); | |
893 | |
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); | |
903 | |
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); | |
909 | |
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 } | |
919 | |
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 } | |
929 | |
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 } | |
935 | |
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); | |
960 | |
961 nnumbers = 9; | |
962 header = "-----BEGIN RSA PRIVATE KEY-----\n"; | |
963 footer = "-----END RSA PRIVATE KEY-----\n"; | |
964 } | |
965 #endif /* DROPBEAR_RSA */ | |
966 | |
967 #ifdef DROPBEAR_DSS | |
968 if (key->type == DROPBEAR_SIGNKEY_DSS) { | |
969 | |
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); | |
974 | |
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); | |
979 | |
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); | |
984 | |
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); | |
989 | |
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); | |
994 | |
995 nnumbers = 6; | |
996 header = "-----BEGIN DSA PRIVATE KEY-----\n"; | |
997 footer = "-----END DSA PRIVATE KEY-----\n"; | |
998 } | |
999 #endif /* DROPBEAR_DSS */ | |
1000 | |
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; | |
1018 | |
1019 /* | |
1020 * Now we know how big outblob needs to be. Allocate it. | |
1021 */ | |
1022 outblob = (unsigned char*)m_malloc(outlen); | |
1023 | |
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 */ | |
1035 | |
1036 #ifdef DROPBEAR_ECDSA | |
1037 if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 | |
1038 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 | |
1039 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { | |
1040 | |
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; | |
1057 | |
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); | |
1062 | |
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); | |
1070 | |
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 } | |
1089 | |
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); | |
1096 | |
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); | |
1107 | |
1108 buf_setpos(seq_buf, 0); | |
1109 | |
1110 outblob = (unsigned char*)m_malloc(1000); | |
1111 | |
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; | |
1118 | |
1119 buf_burn(seq_buf); | |
1120 buf_free(seq_buf); | |
1121 seq_buf = NULL; | |
1122 | |
1123 header = "-----BEGIN EC PRIVATE KEY-----\n"; | |
1124 footer = "-----END EC PRIVATE KEY-----\n"; | |
1125 } | |
1126 #endif | |
1127 | |
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 } | |
1149 | |
1150 /* | |
1151 * Encrypt the key. | |
1152 */ | |
1153 if (passphrase) { | |
1154 fprintf(stderr, "Encrypted keys aren't supported currently\n"); | |
876 goto error; | 1155 goto error; |
877 } | 1156 } |
878 | 1157 |
879 /* e */ | 1158 /* |
880 numbers[2].bytes = buf_getint(keyblob); | 1159 * And save it. We'll use Unix line endings just in case it's |
881 numbers[2].start = buf_getptr(keyblob, numbers[2].bytes); | 1160 * subsequently transferred in binary mode. |
882 buf_incrpos(keyblob, numbers[2].bytes); | 1161 */ |
883 | 1162 if (strlen(filename) == 1 && filename[0] == '-') { |
884 /* n */ | 1163 fp = stdout; |
885 numbers[1].bytes = buf_getint(keyblob); | 1164 } else { |
886 numbers[1].start = buf_getptr(keyblob, numbers[1].bytes); | 1165 fp = fopen(filename, "wb"); /* ensure Unix line endings */ |
887 buf_incrpos(keyblob, numbers[1].bytes); | 1166 } |
888 | 1167 if (!fp) { |
889 /* d */ | 1168 fprintf(stderr, "Failed opening output file\n"); |
890 numbers[3].bytes = buf_getint(keyblob); | 1169 goto error; |
891 numbers[3].start = buf_getptr(keyblob, numbers[3].bytes); | 1170 } |
892 buf_incrpos(keyblob, numbers[3].bytes); | 1171 fputs(header, fp); |
893 | 1172 base64_encode_fp(fp, outblob, outlen, 64); |
894 /* p */ | 1173 fputs(footer, fp); |
895 numbers[4].bytes = buf_getint(keyblob); | 1174 fclose(fp); |
896 numbers[4].start = buf_getptr(keyblob, numbers[4].bytes); | 1175 ret = 1; |
897 buf_incrpos(keyblob, numbers[4].bytes); | 1176 |
898 | 1177 error: |
899 /* q */ | 1178 if (outblob) { |
900 numbers[5].bytes = buf_getint(keyblob); | 1179 memset(outblob, 0, outlen); |
901 numbers[5].start = buf_getptr(keyblob, numbers[5].bytes); | |
902 buf_incrpos(keyblob, numbers[5].bytes); | |
903 | |
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); | |
909 | |
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 } | |
919 | |
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 } | |
929 | |
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 } | |
935 | |
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); | |
960 | |
961 nnumbers = 9; | |
962 header = "-----BEGIN RSA PRIVATE KEY-----\n"; | |
963 footer = "-----END RSA PRIVATE KEY-----\n"; | |
964 } | |
965 #endif /* DROPBEAR_RSA */ | |
966 | |
967 #ifdef DROPBEAR_DSS | |
968 if (key->type == DROPBEAR_SIGNKEY_DSS) { | |
969 | |
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); | |
974 | |
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); | |
979 | |
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); | |
984 | |
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); | |
989 | |
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); | |
994 | |
995 nnumbers = 6; | |
996 header = "-----BEGIN DSA PRIVATE KEY-----\n"; | |
997 footer = "-----END DSA PRIVATE KEY-----\n"; | |
998 } | |
999 #endif /* DROPBEAR_DSS */ | |
1000 | |
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; | |
1018 | |
1019 /* | |
1020 * Now we know how big outblob needs to be. Allocate it. | |
1021 */ | |
1022 outblob = (unsigned char*)m_malloc(outlen); | |
1023 | |
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 */ | |
1035 | |
1036 #ifdef DROPBEAR_ECDSA | |
1037 if (key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP256 | |
1038 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP384 | |
1039 || key->type == DROPBEAR_SIGNKEY_ECDSA_NISTP521) { | |
1040 | |
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; | |
1057 | |
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); | |
1062 | |
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); | |
1070 | |
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 } | |
1089 | |
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); | |
1096 | |
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); | |
1107 | |
1108 buf_setpos(seq_buf, 0); | |
1109 | |
1110 outblob = (unsigned char*)m_malloc(1000); | |
1111 | |
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; | |
1118 | |
1119 buf_burn(seq_buf); | |
1120 buf_free(seq_buf); | |
1121 seq_buf = NULL; | |
1122 | |
1123 header = "-----BEGIN EC PRIVATE KEY-----\n"; | |
1124 footer = "-----END EC PRIVATE KEY-----\n"; | |
1125 } | |
1126 #endif | |
1127 | |
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 } | |
1149 | |
1150 /* | |
1151 * Encrypt the key. | |
1152 */ | |
1153 if (passphrase) { | |
1154 fprintf(stderr, "Encrypted keys aren't supported currently\n"); | |
1155 goto error; | |
1156 } | |
1157 | |
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); | 1180 m_free(outblob); |
1181 } | 1181 } |
1182 if (keyblob) { | 1182 if (keyblob) { |
1183 buf_burn(keyblob); | 1183 buf_burn(keyblob); |
1184 buf_free(keyblob); | 1184 buf_free(keyblob); |
1185 } | 1185 } |
1186 if (extrablob) { | 1186 if (extrablob) { |
1187 buf_burn(extrablob); | 1187 buf_burn(extrablob); |
1188 buf_free(extrablob); | 1188 buf_free(extrablob); |
1189 } | 1189 } |
1190 return ret; | 1190 return ret; |
1191 } | 1191 } |
1192 | 1192 |
1193 #if 0 | 1193 #if 0 |
1194 /* XXX TODO ssh.com stuff isn't going yet */ | 1194 /* XXX TODO ssh.com stuff isn't going yet */ |
1195 | 1195 |
1268 */ | 1268 */ |
1269 | 1269 |
1270 #define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb | 1270 #define SSHCOM_MAGIC_NUMBER 0x3f6ff9eb |
1271 | 1271 |
1272 struct sshcom_key { | 1272 struct sshcom_key { |
1273 char comment[256]; /* allowing any length is overkill */ | 1273 char comment[256]; /* allowing any length is overkill */ |
1274 unsigned char *keyblob; | 1274 unsigned char *keyblob; |
1275 int keyblob_len, keyblob_size; | 1275 int keyblob_len, keyblob_size; |
1276 }; | 1276 }; |
1277 | 1277 |
1278 static struct sshcom_key *load_sshcom_key(const char *filename) | 1278 static struct sshcom_key *load_sshcom_key(const char *filename) |
1279 { | 1279 { |
1280 struct sshcom_key *ret; | 1280 struct sshcom_key *ret; |
1281 FILE *fp; | 1281 FILE *fp; |
1282 char buffer[256]; | 1282 char buffer[256]; |
1283 int len; | 1283 int len; |
1284 char *errmsg, *p; | 1284 char *errmsg, *p; |
1285 int headers_done; | 1285 int headers_done; |
1286 char base64_bit[4]; | 1286 char base64_bit[4]; |
1287 int base64_chars = 0; | 1287 int base64_chars = 0; |
1288 | 1288 |
1289 ret = snew(struct sshcom_key); | 1289 ret = snew(struct sshcom_key); |
1290 ret->comment[0] = '\0'; | 1290 ret->comment[0] = '\0'; |
1291 ret->keyblob = NULL; | 1291 ret->keyblob = NULL; |
1292 ret->keyblob_len = ret->keyblob_size = 0; | 1292 ret->keyblob_len = ret->keyblob_size = 0; |
1293 | 1293 |
1294 fp = fopen(filename, "r"); | 1294 fp = fopen(filename, "r"); |
1295 if (!fp) { | 1295 if (!fp) { |
1296 errmsg = "Unable to open key file"; | 1296 errmsg = "Unable to open key file"; |
1297 goto error; | 1297 goto error; |
1298 } | 1298 } |
1299 if (!fgets(buffer, sizeof(buffer), fp) || | 1299 if (!fgets(buffer, sizeof(buffer), fp) || |
1300 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) { | 1300 0 != strcmp(buffer, "---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n")) { |
1301 errmsg = "File does not begin with ssh.com key header"; | 1301 errmsg = "File does not begin with ssh.com key header"; |
1302 goto error; | 1302 goto error; |
1303 } | 1303 } |
1304 | 1304 |
1305 headers_done = 0; | 1305 headers_done = 0; |
1306 while (1) { | 1306 while (1) { |
1307 if (!fgets(buffer, sizeof(buffer), fp)) { | 1307 if (!fgets(buffer, sizeof(buffer), fp)) { |
1308 errmsg = "Unexpected end of file"; | 1308 errmsg = "Unexpected end of file"; |
1309 goto error; | 1309 goto error; |
1310 } | 1310 } |
1311 if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n")) | 1311 if (!strcmp(buffer, "---- END SSH2 ENCRYPTED PRIVATE KEY ----\n")) |
1312 break; /* done */ | 1312 break; /* done */ |
1313 if ((p = strchr(buffer, ':')) != NULL) { | 1313 if ((p = strchr(buffer, ':')) != NULL) { |
1314 if (headers_done) { | 1314 if (headers_done) { |
1315 errmsg = "Header found in body of key data"; | 1315 errmsg = "Header found in body of key data"; |
1316 goto error; | 1316 goto error; |
1317 } | 1317 } |
1318 *p++ = '\0'; | 1318 *p++ = '\0'; |
1319 while (*p && isspace((unsigned char)*p)) p++; | 1319 while (*p && isspace((unsigned char)*p)) p++; |
1320 /* | 1320 /* |
1321 * Header lines can end in a trailing backslash for | 1321 * Header lines can end in a trailing backslash for |
1322 * continuation. | 1322 * continuation. |
1323 */ | 1323 */ |
1324 while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) || | 1324 while ((len = strlen(p)) > (int)(sizeof(buffer) - (p-buffer) -1) || |
1325 p[len-1] != '\n' || p[len-2] == '\\') { | 1325 p[len-1] != '\n' || p[len-2] == '\\') { |
1326 if (len > (int)((p-buffer) + sizeof(buffer)-2)) { | 1326 if (len > (int)((p-buffer) + sizeof(buffer)-2)) { |
1327 errmsg = "Header line too long to deal with"; | 1327 errmsg = "Header line too long to deal with"; |
1328 goto error; | 1328 goto error; |
1329 } | 1329 } |
1330 if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) { | 1330 if (!fgets(p+len-2, sizeof(buffer)-(p-buffer)-(len-2), fp)) { |
1331 errmsg = "Unexpected end of file"; | 1331 errmsg = "Unexpected end of file"; |
1332 goto error; | 1332 goto error; |
1333 } | 1333 } |
1334 } | 1334 } |
1335 p[strcspn(p, "\n")] = '\0'; | 1335 p[strcspn(p, "\n")] = '\0'; |
1336 if (!strcmp(buffer, "Comment")) { | 1336 if (!strcmp(buffer, "Comment")) { |
1337 /* Strip quotes in comment if present. */ | 1337 /* Strip quotes in comment if present. */ |
1338 if (p[0] == '"' && p[strlen(p)-1] == '"') { | 1338 if (p[0] == '"' && p[strlen(p)-1] == '"') { |
1339 p++; | 1339 p++; |
1340 p[strlen(p)-1] = '\0'; | 1340 p[strlen(p)-1] = '\0'; |
1341 } | 1341 } |
1342 strncpy(ret->comment, p, sizeof(ret->comment)); | 1342 strncpy(ret->comment, p, sizeof(ret->comment)); |
1343 ret->comment[sizeof(ret->comment)-1] = '\0'; | 1343 ret->comment[sizeof(ret->comment)-1] = '\0'; |
1344 } | 1344 } |
1345 } else { | 1345 } else { |
1346 headers_done = 1; | 1346 headers_done = 1; |
1347 | 1347 |
1348 p = buffer; | 1348 p = buffer; |
1349 while (isbase64(*p)) { | 1349 while (isbase64(*p)) { |
1350 base64_bit[base64_chars++] = *p; | 1350 base64_bit[base64_chars++] = *p; |
1351 if (base64_chars == 4) { | 1351 if (base64_chars == 4) { |
1352 unsigned char out[3]; | 1352 unsigned char out[3]; |
1353 | 1353 |
1354 base64_chars = 0; | 1354 base64_chars = 0; |
1355 | 1355 |
1356 len = base64_decode_atom(base64_bit, out); | 1356 len = base64_decode_atom(base64_bit, out); |
1357 | 1357 |
1358 if (len <= 0) { | 1358 if (len <= 0) { |
1359 errmsg = "Invalid base64 encoding"; | 1359 errmsg = "Invalid base64 encoding"; |
1360 goto error; | 1360 goto error; |
1361 } | 1361 } |
1362 | 1362 |
1363 if (ret->keyblob_len + len > ret->keyblob_size) { | 1363 if (ret->keyblob_len + len > ret->keyblob_size) { |
1364 ret->keyblob_size = ret->keyblob_len + len + 256; | 1364 ret->keyblob_size = ret->keyblob_len + len + 256; |
1365 ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, | 1365 ret->keyblob = sresize(ret->keyblob, ret->keyblob_size, |
1366 unsigned char); | 1366 unsigned char); |
1367 } | 1367 } |
1368 | 1368 |
1369 memcpy(ret->keyblob + ret->keyblob_len, out, len); | 1369 memcpy(ret->keyblob + ret->keyblob_len, out, len); |
1370 ret->keyblob_len += len; | 1370 ret->keyblob_len += len; |
1371 } | 1371 } |
1372 | 1372 |
1373 p++; | 1373 p++; |
1374 } | 1374 } |
1375 } | 1375 } |
1376 } | 1376 } |
1377 | 1377 |
1378 if (ret->keyblob_len == 0 || !ret->keyblob) { | 1378 if (ret->keyblob_len == 0 || !ret->keyblob) { |
1379 errmsg = "Key body not present"; | 1379 errmsg = "Key body not present"; |
1380 goto error; | 1380 goto error; |
1381 } | 1381 } |
1382 | 1382 |
1383 return ret; | 1383 return ret; |
1384 | 1384 |
1385 error: | 1385 error: |
1386 if (ret) { | 1386 if (ret) { |
1387 if (ret->keyblob) { | 1387 if (ret->keyblob) { |
1388 memset(ret->keyblob, 0, ret->keyblob_size); | 1388 memset(ret->keyblob, 0, ret->keyblob_size); |
1389 m_free(ret->keyblob); | 1389 m_free(ret->keyblob); |
1390 } | 1390 } |
1391 memset(ret, 0, sizeof(*ret)); | 1391 memset(ret, 0, sizeof(*ret)); |
1392 m_free(ret); | 1392 m_free(ret); |
1393 } | 1393 } |
1394 return NULL; | 1394 return NULL; |
1395 } | 1395 } |
1396 | 1396 |
1397 int sshcom_encrypted(const char *filename, char **comment) | 1397 int sshcom_encrypted(const char *filename, char **comment) |
1398 { | 1398 { |
1399 struct sshcom_key *key = load_sshcom_key(filename); | 1399 struct sshcom_key *key = load_sshcom_key(filename); |
1400 int pos, len, answer; | 1400 int pos, len, answer; |
1401 | 1401 |
1402 *comment = NULL; | 1402 *comment = NULL; |
1403 if (!key) | 1403 if (!key) |
1404 return 0; | 1404 return 0; |
1405 | 1405 |
1406 /* | 1406 /* |
1407 * Check magic number. | 1407 * Check magic number. |
1408 */ | 1408 */ |
1409 if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) | 1409 if (GET_32BIT(key->keyblob) != 0x3f6ff9eb) |
1410 return 0; /* key is invalid */ | 1410 return 0; /* key is invalid */ |
1411 | 1411 |
1412 /* | 1412 /* |
1413 * Find the cipher-type string. | 1413 * Find the cipher-type string. |
1414 */ | 1414 */ |
1415 answer = 0; | 1415 answer = 0; |
1416 pos = 8; | 1416 pos = 8; |
1417 if (key->keyblob_len < pos+4) | 1417 if (key->keyblob_len < pos+4) |
1418 goto done; /* key is far too short */ | 1418 goto done; /* key is far too short */ |
1419 len = toint(GET_32BIT(key->keyblob + pos)); | 1419 len = toint(GET_32BIT(key->keyblob + pos)); |
1420 if (len < 0 || len > key->keyblob_len - pos - 4) | 1420 if (len < 0 || len > key->keyblob_len - pos - 4) |
1421 goto done; /* key is far too short */ | 1421 goto done; /* key is far too short */ |
1422 pos += 4 + len; /* skip key type */ | 1422 pos += 4 + len; /* skip key type */ |
1423 len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */ | 1423 len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */ |
1424 if (len < 0 || len > key->keyblob_len - pos - 4) | 1424 if (len < 0 || len > key->keyblob_len - pos - 4) |
1425 goto done; /* cipher type string is incomplete */ | 1425 goto done; /* cipher type string is incomplete */ |
1426 if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) | 1426 if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) |
1427 answer = 1; | 1427 answer = 1; |
1428 | 1428 |
1429 done: | 1429 done: |
1430 *comment = dupstr(key->comment); | 1430 *comment = dupstr(key->comment); |
1431 memset(key->keyblob, 0, key->keyblob_size); | 1431 memset(key->keyblob, 0, key->keyblob_size); |
1432 m_free(key->keyblob); | 1432 m_free(key->keyblob); |
1433 memset(key, 0, sizeof(*key)); | 1433 memset(key, 0, sizeof(*key)); |
1434 m_free(key); | 1434 m_free(key); |
1435 return answer; | 1435 return answer; |
1436 } | 1436 } |
1437 | 1437 |
1438 static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) | 1438 static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) |
1439 { | 1439 { |
1440 unsigned bits, bytes; | 1440 unsigned bits, bytes; |
1441 unsigned char *d = (unsigned char *) data; | 1441 unsigned char *d = (unsigned char *) data; |
1442 | 1442 |
1443 if (len < 4) | 1443 if (len < 4) |
1444 goto error; | 1444 goto error; |
1445 bits = GET_32BIT(d); | 1445 bits = GET_32BIT(d); |
1446 | 1446 |
1447 bytes = (bits + 7) / 8; | 1447 bytes = (bits + 7) / 8; |
1448 if (len < 4+bytes) | 1448 if (len < 4+bytes) |
1449 goto error; | 1449 goto error; |
1450 | 1450 |
1451 ret->start = d + 4; | 1451 ret->start = d + 4; |
1452 ret->bytes = bytes; | 1452 ret->bytes = bytes; |
1453 return bytes+4; | 1453 return bytes+4; |
1454 | 1454 |
1455 error: | 1455 error: |
1456 ret->start = NULL; | 1456 ret->start = NULL; |
1457 ret->bytes = -1; | 1457 ret->bytes = -1; |
1458 return len; /* ensure further calls fail as well */ | 1458 return len; /* ensure further calls fail as well */ |
1459 } | 1459 } |
1460 | 1460 |
1461 static int sshcom_put_mpint(void *target, void *data, int len) | 1461 static int sshcom_put_mpint(void *target, void *data, int len) |
1462 { | 1462 { |
1463 unsigned char *d = (unsigned char *)target; | 1463 unsigned char *d = (unsigned char *)target; |
1464 unsigned char *i = (unsigned char *)data; | 1464 unsigned char *i = (unsigned char *)data; |
1465 int bits = len * 8 - 1; | 1465 int bits = len * 8 - 1; |
1466 | 1466 |
1467 while (bits > 0) { | 1467 while (bits > 0) { |
1468 if (*i & (1 << (bits & 7))) | 1468 if (*i & (1 << (bits & 7))) |
1469 break; | 1469 break; |
1470 if (!(bits-- & 7)) | 1470 if (!(bits-- & 7)) |
1471 i++, len--; | 1471 i++, len--; |
1472 } | 1472 } |
1473 | 1473 |
1474 PUT_32BIT(d, bits+1); | 1474 PUT_32BIT(d, bits+1); |
1475 memcpy(d+4, i, len); | 1475 memcpy(d+4, i, len); |
1476 return len+4; | 1476 return len+4; |
1477 } | 1477 } |
1478 | 1478 |
1479 sign_key *sshcom_read(const char *filename, char *passphrase) | 1479 sign_key *sshcom_read(const char *filename, char *passphrase) |
1480 { | 1480 { |
1481 struct sshcom_key *key = load_sshcom_key(filename); | 1481 struct sshcom_key *key = load_sshcom_key(filename); |
1482 char *errmsg; | 1482 char *errmsg; |
1483 int pos, len; | 1483 int pos, len; |
1484 const char prefix_rsa[] = "if-modn{sign{rsa"; | 1484 const char prefix_rsa[] = "if-modn{sign{rsa"; |
1485 const char prefix_dsa[] = "dl-modp{sign{dsa"; | 1485 const char prefix_dsa[] = "dl-modp{sign{dsa"; |
1486 enum { RSA, DSA } type; | 1486 enum { RSA, DSA } type; |
1487 int encrypted; | 1487 int encrypted; |
1488 char *ciphertext; | 1488 char *ciphertext; |
1489 int cipherlen; | 1489 int cipherlen; |
1490 struct ssh2_userkey *ret = NULL, *retkey; | 1490 struct ssh2_userkey *ret = NULL, *retkey; |
1491 const struct ssh_signkey *alg; | 1491 const struct ssh_signkey *alg; |
1492 unsigned char *blob = NULL; | 1492 unsigned char *blob = NULL; |
1493 int blobsize = 0, publen, privlen; | 1493 int blobsize = 0, publen, privlen; |
1494 | 1494 |
1495 if (!key) | 1495 if (!key) |
1496 return NULL; | 1496 return NULL; |
1497 | 1497 |
1498 /* | 1498 /* |
1499 * Check magic number. | 1499 * Check magic number. |
1500 */ | 1500 */ |
1501 if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) { | 1501 if (GET_32BIT(key->keyblob) != SSHCOM_MAGIC_NUMBER) { |
1502 errmsg = "Key does not begin with magic number"; | 1502 errmsg = "Key does not begin with magic number"; |
1503 goto error; | 1503 goto error; |
1504 } | 1504 } |
1505 | 1505 |
1506 /* | 1506 /* |
1507 * Determine the key type. | 1507 * Determine the key type. |
1508 */ | 1508 */ |
1509 pos = 8; | 1509 pos = 8; |
1510 if (key->keyblob_len < pos+4 || | 1510 if (key->keyblob_len < pos+4 || |
1511 (len = GET_32BIT(key->keyblob + pos)) > 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"; | 1512 errmsg = "Key blob does not contain a key type string"; |
1513 goto error; | 1513 goto error; |
1514 } | 1514 } |
1515 if (len > sizeof(prefix_rsa) - 1 && | 1515 if (len > sizeof(prefix_rsa) - 1 && |
1516 !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) { | 1516 !memcmp(key->keyblob+pos+4, prefix_rsa, sizeof(prefix_rsa) - 1)) { |
1517 type = RSA; | 1517 type = RSA; |
1518 } else if (len > sizeof(prefix_dsa) - 1 && | 1518 } else if (len > sizeof(prefix_dsa) - 1 && |
1519 !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { | 1519 !memcmp(key->keyblob+pos+4, prefix_dsa, sizeof(prefix_dsa) - 1)) { |
1520 type = DSA; | 1520 type = DSA; |
1521 } else { | 1521 } else { |
1522 errmsg = "Key is of unknown type"; | 1522 errmsg = "Key is of unknown type"; |
1523 goto error; | 1523 goto error; |
1524 } | 1524 } |
1525 pos += 4+len; | 1525 pos += 4+len; |
1526 | 1526 |
1527 /* | 1527 /* |
1528 * Determine the cipher type. | 1528 * Determine the cipher type. |
1529 */ | 1529 */ |
1530 if (key->keyblob_len < pos+4 || | 1530 if (key->keyblob_len < pos+4 || |
1531 (len = GET_32BIT(key->keyblob + pos)) > 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"; | 1532 errmsg = "Key blob does not contain a cipher type string"; |
1533 goto error; | 1533 goto error; |
1534 } | 1534 } |
1535 if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) | 1535 if (len == 4 && !memcmp(key->keyblob+pos+4, "none", 4)) |
1536 encrypted = 0; | 1536 encrypted = 0; |
1537 else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) | 1537 else if (len == 8 && !memcmp(key->keyblob+pos+4, "3des-cbc", 8)) |
1538 encrypted = 1; | 1538 encrypted = 1; |
1539 else { | 1539 else { |
1540 errmsg = "Key encryption is of unknown type"; | 1540 errmsg = "Key encryption is of unknown type"; |
1541 goto error; | 1541 goto error; |
1542 } | 1542 } |
1543 pos += 4+len; | 1543 pos += 4+len; |
1544 | 1544 |
1545 /* | 1545 /* |
1546 * Get hold of the encrypted part of the key. | 1546 * Get hold of the encrypted part of the key. |
1547 */ | 1547 */ |
1548 if (key->keyblob_len < pos+4 || | 1548 if (key->keyblob_len < pos+4 || |
1549 (len = GET_32BIT(key->keyblob + pos)) > 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"; | 1550 errmsg = "Key blob does not contain actual key data"; |
1551 goto error; | 1551 goto error; |
1552 } | 1552 } |
1553 ciphertext = (char *)key->keyblob + pos + 4; | 1553 ciphertext = (char *)key->keyblob + pos + 4; |
1554 cipherlen = len; | 1554 cipherlen = len; |
1555 if (cipherlen == 0) { | 1555 if (cipherlen == 0) { |
1556 errmsg = "Length of key data is zero"; | 1556 errmsg = "Length of key data is zero"; |
1557 goto error; | 1557 goto error; |
1558 } | 1558 } |
1559 | 1559 |
1560 /* | 1560 /* |
1561 * Decrypt it if necessary. | 1561 * Decrypt it if necessary. |
1562 */ | 1562 */ |
1563 if (encrypted) { | 1563 if (encrypted) { |
1564 /* | 1564 /* |
1565 * Derive encryption key from passphrase and iv/salt: | 1565 * Derive encryption key from passphrase and iv/salt: |
1566 * | 1566 * |
1567 * - let block A equal MD5(passphrase) | 1567 * - let block A equal MD5(passphrase) |
1568 * - let block B equal MD5(passphrase || A) | 1568 * - let block B equal MD5(passphrase || A) |
1569 * - block C would be MD5(passphrase || A || B) and so on | 1569 * - block C would be MD5(passphrase || A || B) and so on |
1570 * - encryption key is the first N bytes of A || B | 1570 * - encryption key is the first N bytes of A || B |
1571 */ | 1571 */ |
1572 struct MD5Context md5c; | 1572 struct MD5Context md5c; |
1573 unsigned char keybuf[32], iv[8]; | 1573 unsigned char keybuf[32], iv[8]; |
1574 | 1574 |
1575 if (cipherlen % 8 != 0) { | 1575 if (cipherlen % 8 != 0) { |
1576 errmsg = "Encrypted part of key is not a multiple of cipher block" | 1576 errmsg = "Encrypted part of key is not a multiple of cipher block" |
1577 " size"; | 1577 " size"; |
1578 goto error; | 1578 goto error; |
1579 } | 1579 } |
1580 | 1580 |
1581 MD5Init(&md5c); | 1581 MD5Init(&md5c); |
1582 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | 1582 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); |
1583 MD5Final(keybuf, &md5c); | 1583 MD5Final(keybuf, &md5c); |
1584 | 1584 |
1585 MD5Init(&md5c); | 1585 MD5Init(&md5c); |
1586 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | 1586 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); |
1587 MD5Update(&md5c, keybuf, 16); | 1587 MD5Update(&md5c, keybuf, 16); |
1588 MD5Final(keybuf+16, &md5c); | 1588 MD5Final(keybuf+16, &md5c); |
1589 | 1589 |
1590 /* | 1590 /* |
1591 * Now decrypt the key blob. | 1591 * Now decrypt the key blob. |
1592 */ | 1592 */ |
1593 memset(iv, 0, sizeof(iv)); | 1593 memset(iv, 0, sizeof(iv)); |
1594 des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, | 1594 des3_decrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, |
1595 cipherlen); | 1595 cipherlen); |
1596 | 1596 |
1597 memset(&md5c, 0, sizeof(md5c)); | 1597 memset(&md5c, 0, sizeof(md5c)); |
1598 memset(keybuf, 0, sizeof(keybuf)); | 1598 memset(keybuf, 0, sizeof(keybuf)); |
1599 | 1599 |
1600 /* | 1600 /* |
1601 * Hereafter we return WRONG_PASSPHRASE for any parsing | 1601 * Hereafter we return WRONG_PASSPHRASE for any parsing |
1602 * error. (But only if we've just tried to decrypt it! | 1602 * error. (But only if we've just tried to decrypt it! |
1603 * Returning WRONG_PASSPHRASE for an unencrypted key is | 1603 * Returning WRONG_PASSPHRASE for an unencrypted key is |
1604 * automatic doom.) | 1604 * automatic doom.) |
1605 */ | 1605 */ |
1606 if (encrypted) | 1606 if (encrypted) |
1607 ret = SSH2_WRONG_PASSPHRASE; | 1607 ret = SSH2_WRONG_PASSPHRASE; |
1608 } | 1608 } |
1609 | 1609 |
1610 /* | 1610 /* |
1611 * Strip away the containing string to get to the real meat. | 1611 * Strip away the containing string to get to the real meat. |
1612 */ | 1612 */ |
1613 len = toint(GET_32BIT(ciphertext)); | 1613 len = toint(GET_32BIT(ciphertext)); |
1614 if (len < 0 || len > cipherlen-4) { | 1614 if (len < 0 || len > cipherlen-4) { |
1615 errmsg = "containing string was ill-formed"; | 1615 errmsg = "containing string was ill-formed"; |
1616 goto error; | 1616 goto error; |
1617 } | 1617 } |
1618 ciphertext += 4; | 1618 ciphertext += 4; |
1619 cipherlen = len; | 1619 cipherlen = len; |
1620 | 1620 |
1621 /* | 1621 /* |
1622 * Now we break down into RSA versus DSA. In either case we'll | 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 | 1623 * construct public and private blobs in our own format, and |
1624 * end up feeding them to alg->createkey(). | 1624 * end up feeding them to alg->createkey(). |
1625 */ | 1625 */ |
1626 blobsize = cipherlen + 256; | 1626 blobsize = cipherlen + 256; |
1627 blob = snewn(blobsize, unsigned char); | 1627 blob = snewn(blobsize, unsigned char); |
1628 privlen = 0; | 1628 privlen = 0; |
1629 if (type == RSA) { | 1629 if (type == RSA) { |
1630 struct mpint_pos n, e, d, u, p, q; | 1630 struct mpint_pos n, e, d, u, p, q; |
1631 int pos = 0; | 1631 int pos = 0; |
1632 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e); | 1632 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &e); |
1633 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d); | 1633 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &d); |
1634 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n); | 1634 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &n); |
1635 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u); | 1635 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &u); |
1636 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); | 1636 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); |
1637 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); | 1637 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); |
1638 if (!q.start) { | 1638 if (!q.start) { |
1639 errmsg = "key data did not contain six integers"; | 1639 errmsg = "key data did not contain six integers"; |
1640 goto error; | 1640 goto error; |
1641 } | 1641 } |
1642 | 1642 |
1643 alg = &ssh_rsa; | 1643 alg = &ssh_rsa; |
1644 pos = 0; | 1644 pos = 0; |
1645 pos += put_string(blob+pos, "ssh-rsa", 7); | 1645 pos += put_string(blob+pos, "ssh-rsa", 7); |
1646 pos += put_mp(blob+pos, e.start, e.bytes); | 1646 pos += put_mp(blob+pos, e.start, e.bytes); |
1647 pos += put_mp(blob+pos, n.start, n.bytes); | 1647 pos += put_mp(blob+pos, n.start, n.bytes); |
1648 publen = pos; | 1648 publen = pos; |
1649 pos += put_string(blob+pos, d.start, d.bytes); | 1649 pos += put_string(blob+pos, d.start, d.bytes); |
1650 pos += put_mp(blob+pos, q.start, q.bytes); | 1650 pos += put_mp(blob+pos, q.start, q.bytes); |
1651 pos += put_mp(blob+pos, p.start, p.bytes); | 1651 pos += put_mp(blob+pos, p.start, p.bytes); |
1652 pos += put_mp(blob+pos, u.start, u.bytes); | 1652 pos += put_mp(blob+pos, u.start, u.bytes); |
1653 privlen = pos - publen; | 1653 privlen = pos - publen; |
1654 } else if (type == DSA) { | 1654 } else if (type == DSA) { |
1655 struct mpint_pos p, q, g, x, y; | 1655 struct mpint_pos p, q, g, x, y; |
1656 int pos = 4; | 1656 int pos = 4; |
1657 if (GET_32BIT(ciphertext) != 0) { | 1657 if (GET_32BIT(ciphertext) != 0) { |
1658 errmsg = "predefined DSA parameters not supported"; | 1658 errmsg = "predefined DSA parameters not supported"; |
1659 goto error; | 1659 goto error; |
1660 } | 1660 } |
1661 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); | 1661 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &p); |
1662 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g); | 1662 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &g); |
1663 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); | 1663 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &q); |
1664 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y); | 1664 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &y); |
1665 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x); | 1665 pos += sshcom_read_mpint(ciphertext+pos, cipherlen-pos, &x); |
1666 if (!x.start) { | 1666 if (!x.start) { |
1667 errmsg = "key data did not contain five integers"; | 1667 errmsg = "key data did not contain five integers"; |
1668 goto error; | 1668 goto error; |
1669 } | 1669 } |
1670 | 1670 |
1671 alg = &ssh_dss; | 1671 alg = &ssh_dss; |
1672 pos = 0; | 1672 pos = 0; |
1673 pos += put_string(blob+pos, "ssh-dss", 7); | 1673 pos += put_string(blob+pos, "ssh-dss", 7); |
1674 pos += put_mp(blob+pos, p.start, p.bytes); | 1674 pos += put_mp(blob+pos, p.start, p.bytes); |
1675 pos += put_mp(blob+pos, q.start, q.bytes); | 1675 pos += put_mp(blob+pos, q.start, q.bytes); |
1676 pos += put_mp(blob+pos, g.start, g.bytes); | 1676 pos += put_mp(blob+pos, g.start, g.bytes); |
1677 pos += put_mp(blob+pos, y.start, y.bytes); | 1677 pos += put_mp(blob+pos, y.start, y.bytes); |
1678 publen = pos; | 1678 publen = pos; |
1679 pos += put_mp(blob+pos, x.start, x.bytes); | 1679 pos += put_mp(blob+pos, x.start, x.bytes); |
1680 privlen = pos - publen; | 1680 privlen = pos - publen; |
1681 } else | 1681 } else |
1682 return NULL; | 1682 return NULL; |
1683 | 1683 |
1684 dropbear_assert(privlen > 0); /* should have bombed by now if not */ | 1684 dropbear_assert(privlen > 0); /* should have bombed by now if not */ |
1685 | 1685 |
1686 retkey = snew(struct ssh2_userkey); | 1686 retkey = snew(struct ssh2_userkey); |
1687 retkey->alg = alg; | 1687 retkey->alg = alg; |
1688 retkey->data = alg->createkey(blob, publen, blob+publen, privlen); | 1688 retkey->data = alg->createkey(blob, publen, blob+publen, privlen); |
1689 if (!retkey->data) { | 1689 if (!retkey->data) { |
1690 m_free(retkey); | 1690 m_free(retkey); |
1691 errmsg = "unable to create key data structure"; | 1691 errmsg = "unable to create key data structure"; |
1692 goto error; | 1692 goto error; |
1693 } | 1693 } |
1694 retkey->comment = dupstr(key->comment); | 1694 retkey->comment = dupstr(key->comment); |
1695 | 1695 |
1696 errmsg = NULL; /* no error */ | 1696 errmsg = NULL; /* no error */ |
1697 ret = retkey; | 1697 ret = retkey; |
1698 | 1698 |
1699 error: | 1699 error: |
1700 if (blob) { | 1700 if (blob) { |
1701 memset(blob, 0, blobsize); | 1701 memset(blob, 0, blobsize); |
1702 m_free(blob); | 1702 m_free(blob); |
1703 } | 1703 } |
1704 memset(key->keyblob, 0, key->keyblob_size); | 1704 memset(key->keyblob, 0, key->keyblob_size); |
1705 m_free(key->keyblob); | 1705 m_free(key->keyblob); |
1706 memset(key, 0, sizeof(*key)); | 1706 memset(key, 0, sizeof(*key)); |
1707 m_free(key); | 1707 m_free(key); |
1708 return ret; | 1708 return ret; |
1709 } | 1709 } |
1710 | 1710 |
1711 int sshcom_write(const char *filename, sign_key *key, | 1711 int sshcom_write(const char *filename, sign_key *key, |
1712 char *passphrase) | 1712 char *passphrase) |
1713 { | 1713 { |
1714 unsigned char *pubblob, *privblob; | 1714 unsigned char *pubblob, *privblob; |
1715 int publen, privlen; | 1715 int publen, privlen; |
1716 unsigned char *outblob; | 1716 unsigned char *outblob; |
1717 int outlen; | 1717 int outlen; |
1718 struct mpint_pos numbers[6]; | 1718 struct mpint_pos numbers[6]; |
1719 int nnumbers, initial_zero, pos, lenpos, i; | 1719 int nnumbers, initial_zero, pos, lenpos, i; |
1720 char *type; | 1720 char *type; |
1721 char *ciphertext; | 1721 char *ciphertext; |
1722 int cipherlen; | 1722 int cipherlen; |
1723 int ret = 0; | 1723 int ret = 0; |
1724 FILE *fp; | 1724 FILE *fp; |
1725 | 1725 |
1726 /* | 1726 /* |
1727 * Fetch the key blobs. | 1727 * Fetch the key blobs. |
1728 */ | 1728 */ |
1729 pubblob = key->alg->public_blob(key->data, &publen); | 1729 pubblob = key->alg->public_blob(key->data, &publen); |
1730 privblob = key->alg->private_blob(key->data, &privlen); | 1730 privblob = key->alg->private_blob(key->data, &privlen); |
1731 outblob = NULL; | 1731 outblob = NULL; |
1732 | 1732 |
1733 /* | 1733 /* |
1734 * Find the sequence of integers to be encoded into the OpenSSH | 1734 * Find the sequence of integers to be encoded into the OpenSSH |
1735 * key blob, and also decide on the header line. | 1735 * key blob, and also decide on the header line. |
1736 */ | 1736 */ |
1737 if (key->alg == &ssh_rsa) { | 1737 if (key->alg == &ssh_rsa) { |
1738 int pos; | 1738 int pos; |
1739 struct mpint_pos n, e, d, p, q, iqmp; | 1739 struct mpint_pos n, e, d, p, q, iqmp; |
1740 | 1740 |
1741 pos = 4 + GET_32BIT(pubblob); | 1741 pos = 4 + GET_32BIT(pubblob); |
1742 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); | 1742 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &e); |
1743 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); | 1743 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &n); |
1744 pos = 0; | 1744 pos = 0; |
1745 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); | 1745 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &d); |
1746 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); | 1746 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &p); |
1747 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); | 1747 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &q); |
1748 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp); | 1748 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &iqmp); |
1749 | 1749 |
1750 dropbear_assert(e.start && iqmp.start); /* can't go wrong */ | 1750 dropbear_assert(e.start && iqmp.start); /* can't go wrong */ |
1751 | 1751 |
1752 numbers[0] = e; | 1752 numbers[0] = e; |
1753 numbers[1] = d; | 1753 numbers[1] = d; |
1754 numbers[2] = n; | 1754 numbers[2] = n; |
1755 numbers[3] = iqmp; | 1755 numbers[3] = iqmp; |
1756 numbers[4] = q; | 1756 numbers[4] = q; |
1757 numbers[5] = p; | 1757 numbers[5] = p; |
1758 | 1758 |
1759 nnumbers = 6; | 1759 nnumbers = 6; |
1760 initial_zero = 0; | 1760 initial_zero = 0; |
1761 type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; | 1761 type = "if-modn{sign{rsa-pkcs1-sha1},encrypt{rsa-pkcs1v2-oaep}}"; |
1762 } else if (key->alg == &ssh_dss) { | 1762 } else if (key->alg == &ssh_dss) { |
1763 int pos; | 1763 int pos; |
1764 struct mpint_pos p, q, g, y, x; | 1764 struct mpint_pos p, q, g, y, x; |
1765 | 1765 |
1766 pos = 4 + GET_32BIT(pubblob); | 1766 pos = 4 + GET_32BIT(pubblob); |
1767 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); | 1767 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &p); |
1768 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); | 1768 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &q); |
1769 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); | 1769 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &g); |
1770 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); | 1770 pos += ssh2_read_mpint(pubblob+pos, publen-pos, &y); |
1771 pos = 0; | 1771 pos = 0; |
1772 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); | 1772 pos += ssh2_read_mpint(privblob+pos, privlen-pos, &x); |
1773 | 1773 |
1774 dropbear_assert(y.start && x.start); /* can't go wrong */ | 1774 dropbear_assert(y.start && x.start); /* can't go wrong */ |
1775 | 1775 |
1776 numbers[0] = p; | 1776 numbers[0] = p; |
1777 numbers[1] = g; | 1777 numbers[1] = g; |
1778 numbers[2] = q; | 1778 numbers[2] = q; |
1779 numbers[3] = y; | 1779 numbers[3] = y; |
1780 numbers[4] = x; | 1780 numbers[4] = x; |
1781 | 1781 |
1782 nnumbers = 5; | 1782 nnumbers = 5; |
1783 initial_zero = 1; | 1783 initial_zero = 1; |
1784 type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; | 1784 type = "dl-modp{sign{dsa-nist-sha1},dh{plain}}"; |
1785 } else { | 1785 } else { |
1786 dropbear_assert(0); /* zoinks! */ | 1786 dropbear_assert(0); /* zoinks! */ |
1787 } | 1787 } |
1788 | 1788 |
1789 /* | 1789 /* |
1790 * Total size of key blob will be somewhere under 512 plus | 1790 * Total size of key blob will be somewhere under 512 plus |
1791 * combined length of integers. We'll calculate the more | 1791 * combined length of integers. We'll calculate the more |
1792 * precise size as we construct the blob. | 1792 * precise size as we construct the blob. |
1793 */ | 1793 */ |
1794 outlen = 512; | 1794 outlen = 512; |
1795 for (i = 0; i < nnumbers; i++) | 1795 for (i = 0; i < nnumbers; i++) |
1796 outlen += 4 + numbers[i].bytes; | 1796 outlen += 4 + numbers[i].bytes; |
1797 outblob = snewn(outlen, unsigned char); | 1797 outblob = snewn(outlen, unsigned char); |
1798 | 1798 |
1799 /* | 1799 /* |
1800 * Create the unencrypted key blob. | 1800 * Create the unencrypted key blob. |
1801 */ | 1801 */ |
1802 pos = 0; | 1802 pos = 0; |
1803 PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4; | 1803 PUT_32BIT(outblob+pos, SSHCOM_MAGIC_NUMBER); pos += 4; |
1804 pos += 4; /* length field, fill in later */ | 1804 pos += 4; /* length field, fill in later */ |
1805 pos += put_string(outblob+pos, type, strlen(type)); | 1805 pos += put_string(outblob+pos, type, strlen(type)); |
1806 { | 1806 { |
1807 char *ciphertype = passphrase ? "3des-cbc" : "none"; | 1807 char *ciphertype = passphrase ? "3des-cbc" : "none"; |
1808 pos += put_string(outblob+pos, ciphertype, strlen(ciphertype)); | 1808 pos += put_string(outblob+pos, ciphertype, strlen(ciphertype)); |
1809 } | 1809 } |
1810 lenpos = pos; /* remember this position */ | 1810 lenpos = pos; /* remember this position */ |
1811 pos += 4; /* encrypted-blob size */ | 1811 pos += 4; /* encrypted-blob size */ |
1812 pos += 4; /* encrypted-payload size */ | 1812 pos += 4; /* encrypted-payload size */ |
1813 if (initial_zero) { | 1813 if (initial_zero) { |
1814 PUT_32BIT(outblob+pos, 0); | 1814 PUT_32BIT(outblob+pos, 0); |
1815 pos += 4; | 1815 pos += 4; |
1816 } | 1816 } |
1817 for (i = 0; i < nnumbers; i++) | 1817 for (i = 0; i < nnumbers; i++) |
1818 pos += sshcom_put_mpint(outblob+pos, | 1818 pos += sshcom_put_mpint(outblob+pos, |
1819 numbers[i].start, numbers[i].bytes); | 1819 numbers[i].start, numbers[i].bytes); |
1820 /* Now wrap up the encrypted payload. */ | 1820 /* Now wrap up the encrypted payload. */ |
1821 PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8)); | 1821 PUT_32BIT(outblob+lenpos+4, pos - (lenpos+8)); |
1822 /* Pad encrypted blob to a multiple of cipher block size. */ | 1822 /* Pad encrypted blob to a multiple of cipher block size. */ |
1823 if (passphrase) { | 1823 if (passphrase) { |
1824 int padding = -(pos - (lenpos+4)) & 7; | 1824 int padding = -(pos - (lenpos+4)) & 7; |
1825 while (padding--) | 1825 while (padding--) |
1826 outblob[pos++] = random_byte(); | 1826 outblob[pos++] = random_byte(); |
1827 } | 1827 } |
1828 ciphertext = (char *)outblob+lenpos+4; | 1828 ciphertext = (char *)outblob+lenpos+4; |
1829 cipherlen = pos - (lenpos+4); | 1829 cipherlen = pos - (lenpos+4); |
1830 dropbear_assert(!passphrase || cipherlen % 8 == 0); | 1830 dropbear_assert(!passphrase || cipherlen % 8 == 0); |
1831 /* Wrap up the encrypted blob string. */ | 1831 /* Wrap up the encrypted blob string. */ |
1832 PUT_32BIT(outblob+lenpos, cipherlen); | 1832 PUT_32BIT(outblob+lenpos, cipherlen); |
1833 /* And finally fill in the total length field. */ | 1833 /* And finally fill in the total length field. */ |
1834 PUT_32BIT(outblob+4, pos); | 1834 PUT_32BIT(outblob+4, pos); |
1835 | 1835 |
1836 dropbear_assert(pos < outlen); | 1836 dropbear_assert(pos < outlen); |
1837 | 1837 |
1838 /* | 1838 /* |
1839 * Encrypt the key. | 1839 * Encrypt the key. |
1840 */ | 1840 */ |
1841 if (passphrase) { | 1841 if (passphrase) { |
1842 /* | 1842 /* |
1843 * Derive encryption key from passphrase and iv/salt: | 1843 * Derive encryption key from passphrase and iv/salt: |
1844 * | 1844 * |
1845 * - let block A equal MD5(passphrase) | 1845 * - let block A equal MD5(passphrase) |
1846 * - let block B equal MD5(passphrase || A) | 1846 * - let block B equal MD5(passphrase || A) |
1847 * - block C would be MD5(passphrase || A || B) and so on | 1847 * - block C would be MD5(passphrase || A || B) and so on |
1848 * - encryption key is the first N bytes of A || B | 1848 * - encryption key is the first N bytes of A || B |
1849 */ | 1849 */ |
1850 struct MD5Context md5c; | 1850 struct MD5Context md5c; |
1851 unsigned char keybuf[32], iv[8]; | 1851 unsigned char keybuf[32], iv[8]; |
1852 | 1852 |
1853 MD5Init(&md5c); | 1853 MD5Init(&md5c); |
1854 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | 1854 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); |
1855 MD5Final(keybuf, &md5c); | 1855 MD5Final(keybuf, &md5c); |
1856 | 1856 |
1857 MD5Init(&md5c); | 1857 MD5Init(&md5c); |
1858 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); | 1858 MD5Update(&md5c, (unsigned char *)passphrase, strlen(passphrase)); |
1859 MD5Update(&md5c, keybuf, 16); | 1859 MD5Update(&md5c, keybuf, 16); |
1860 MD5Final(keybuf+16, &md5c); | 1860 MD5Final(keybuf+16, &md5c); |
1861 | 1861 |
1862 /* | 1862 /* |
1863 * Now decrypt the key blob. | 1863 * Now decrypt the key blob. |
1864 */ | 1864 */ |
1865 memset(iv, 0, sizeof(iv)); | 1865 memset(iv, 0, sizeof(iv)); |
1866 des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, | 1866 des3_encrypt_pubkey_ossh(keybuf, iv, (unsigned char *)ciphertext, |
1867 cipherlen); | 1867 cipherlen); |
1868 | 1868 |
1869 memset(&md5c, 0, sizeof(md5c)); | 1869 memset(&md5c, 0, sizeof(md5c)); |
1870 memset(keybuf, 0, sizeof(keybuf)); | 1870 memset(keybuf, 0, sizeof(keybuf)); |
1871 } | 1871 } |
1872 | 1872 |
1873 /* | 1873 /* |
1874 * And save it. We'll use Unix line endings just in case it's | 1874 * And save it. We'll use Unix line endings just in case it's |
1875 * subsequently transferred in binary mode. | 1875 * subsequently transferred in binary mode. |
1876 */ | 1876 */ |
1877 fp = fopen(filename, "wb"); /* ensure Unix line endings */ | 1877 fp = fopen(filename, "wb"); /* ensure Unix line endings */ |
1878 if (!fp) | 1878 if (!fp) |
1879 goto error; | 1879 goto error; |
1880 fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); | 1880 fputs("---- BEGIN SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); |
1881 fprintf(fp, "Comment: \""); | 1881 fprintf(fp, "Comment: \""); |
1882 /* | 1882 /* |
1883 * Comment header is broken with backslash-newline if it goes | 1883 * Comment header is broken with backslash-newline if it goes |
1884 * over 70 chars. Although it's surrounded by quotes, it | 1884 * over 70 chars. Although it's surrounded by quotes, it |
1885 * _doesn't_ escape backslashes or quotes within the string. | 1885 * _doesn't_ escape backslashes or quotes within the string. |
1886 * Don't ask me, I didn't design it. | 1886 * Don't ask me, I didn't design it. |
1887 */ | 1887 */ |
1888 { | 1888 { |
1889 int slen = 60; /* starts at 60 due to "Comment: " */ | 1889 int slen = 60; /* starts at 60 due to "Comment: " */ |
1890 char *c = key->comment; | 1890 char *c = key->comment; |
1891 while ((int)strlen(c) > slen) { | 1891 while ((int)strlen(c) > slen) { |
1892 fprintf(fp, "%.*s\\\n", slen, c); | 1892 fprintf(fp, "%.*s\\\n", slen, c); |
1893 c += slen; | 1893 c += slen; |
1894 slen = 70; /* allow 70 chars on subsequent lines */ | 1894 slen = 70; /* allow 70 chars on subsequent lines */ |
1895 } | 1895 } |
1896 fprintf(fp, "%s\"\n", c); | 1896 fprintf(fp, "%s\"\n", c); |
1897 } | 1897 } |
1898 base64_encode_fp(fp, outblob, pos, 70); | 1898 base64_encode_fp(fp, outblob, pos, 70); |
1899 fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); | 1899 fputs("---- END SSH2 ENCRYPTED PRIVATE KEY ----\n", fp); |
1900 fclose(fp); | 1900 fclose(fp); |
1901 ret = 1; | 1901 ret = 1; |
1902 | 1902 |
1903 error: | 1903 error: |
1904 if (outblob) { | 1904 if (outblob) { |
1905 memset(outblob, 0, outlen); | 1905 memset(outblob, 0, outlen); |
1906 m_free(outblob); | 1906 m_free(outblob); |
1907 } | 1907 } |
1908 if (privblob) { | 1908 if (privblob) { |
1909 memset(privblob, 0, privlen); | 1909 memset(privblob, 0, privlen); |
1910 m_free(privblob); | 1910 m_free(privblob); |
1911 } | 1911 } |
1912 if (pubblob) { | 1912 if (pubblob) { |
1913 memset(pubblob, 0, publen); | 1913 memset(pubblob, 0, publen); |
1914 m_free(pubblob); | 1914 m_free(pubblob); |
1915 } | 1915 } |
1916 return ret; | 1916 return ret; |
1917 } | 1917 } |
1918 #endif /* ssh.com stuff disabled */ | 1918 #endif /* ssh.com stuff disabled */ |
1919 | 1919 |
1920 /* From PuTTY misc.c */ | 1920 /* From PuTTY misc.c */ |
1921 static int toint(unsigned u) | 1921 static int toint(unsigned u) |
1922 { | 1922 { |
1923 /* | 1923 /* |
1924 * Convert an unsigned to an int, without running into the | 1924 * Convert an unsigned to an int, without running into the |
1925 * undefined behaviour which happens by the strict C standard if | 1925 * undefined behaviour which happens by the strict C standard if |
1926 * the value overflows. You'd hope that sensible compilers would | 1926 * the value overflows. You'd hope that sensible compilers would |
1927 * do the sensible thing in response to a cast, but actually I | 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 | 1928 * don't trust modern compilers not to do silly things like |
1929 * assuming that _obviously_ you wouldn't have caused an overflow | 1929 * assuming that _obviously_ you wouldn't have caused an overflow |
1930 * and so they can elide an 'if (i < 0)' test immediately after | 1930 * and so they can elide an 'if (i < 0)' test immediately after |
1931 * the cast. | 1931 * the cast. |
1932 * | 1932 * |
1933 * Sensible compilers ought of course to optimise this entire | 1933 * Sensible compilers ought of course to optimise this entire |
1934 * function into 'just return the input value'! | 1934 * function into 'just return the input value'! |
1935 */ | 1935 */ |
1936 if (u <= (unsigned)INT_MAX) | 1936 if (u <= (unsigned)INT_MAX) |
1937 return (int)u; | 1937 return (int)u; |
1938 else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */ | 1938 else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */ |
1939 return INT_MIN + (int)(u - (unsigned)INT_MIN); | 1939 return INT_MIN + (int)(u - (unsigned)INT_MIN); |
1940 else | 1940 else |
1941 return INT_MIN; /* fallback; should never occur on binary machines */ | 1941 return INT_MIN; /* fallback; should never occur on binary machines */ |
1942 } | 1942 } |