diff options
author | Damien Miller <djm@mindrot.org> | 2013-12-07 10:41:55 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2013-12-07 10:41:55 +1100 |
commit | bcd00abd8451f36142ae2ee10cc657202149201e (patch) | |
tree | 946db23f1ec607d9260e46b9f6f2422e0e9c970c | |
parent | f0e9060d236c0e38bec2fa1c6579fb0a2ea6458d (diff) |
- markus@cvs.openbsd.org 2013/12/06 13:34:54
[authfile.c authfile.h cipher.c cipher.h key.c packet.c ssh-agent.c]
[ssh-keygen.c PROTOCOL.key] new private key format, bcrypt as KDF by
default; details in PROTOCOL.key; feedback and lots help from djm;
ok djm@
-rw-r--r-- | ChangeLog | 5 | ||||
-rw-r--r-- | PROTOCOL.key | 68 | ||||
-rw-r--r-- | authfile.c | 371 | ||||
-rw-r--r-- | authfile.h | 5 | ||||
-rw-r--r-- | cipher.c | 18 | ||||
-rw-r--r-- | cipher.h | 4 | ||||
-rw-r--r-- | key.c | 3 | ||||
-rw-r--r-- | packet.c | 27 | ||||
-rw-r--r-- | ssh-agent.c | 3 | ||||
-rw-r--r-- | ssh-keygen.c | 51 |
10 files changed, 505 insertions, 50 deletions
@@ -12,6 +12,11 @@ | |||
12 | - markus@cvs.openbsd.org 2013/12/06 13:30:08 | 12 | - markus@cvs.openbsd.org 2013/12/06 13:30:08 |
13 | [authfd.c key.c key.h ssh-agent.c] | 13 | [authfd.c key.c key.h ssh-agent.c] |
14 | move private key (de)serialization to key.c; ok djm | 14 | move private key (de)serialization to key.c; ok djm |
15 | - markus@cvs.openbsd.org 2013/12/06 13:34:54 | ||
16 | [authfile.c authfile.h cipher.c cipher.h key.c packet.c ssh-agent.c] | ||
17 | [ssh-keygen.c PROTOCOL.key] new private key format, bcrypt as KDF by | ||
18 | default; details in PROTOCOL.key; feedback and lots help from djm; | ||
19 | ok djm@ | ||
15 | 20 | ||
16 | 20131205 | 21 | 20131205 |
17 | - (djm) OpenBSD CVS Sync | 22 | - (djm) OpenBSD CVS Sync |
diff --git a/PROTOCOL.key b/PROTOCOL.key new file mode 100644 index 000000000..959bd7aee --- /dev/null +++ b/PROTOCOL.key | |||
@@ -0,0 +1,68 @@ | |||
1 | This document describes the private key format for OpenSSH. | ||
2 | |||
3 | 1. Overall format | ||
4 | |||
5 | The key consists of a header, a list of public keys, and | ||
6 | an encrypted list of matching private keys. | ||
7 | |||
8 | #define AUTH_MAGIC "openssh-key-v1" | ||
9 | |||
10 | byte[] AUTH_MAGIC | ||
11 | string ciphername | ||
12 | string kdfname | ||
13 | string kdfoptions | ||
14 | int number of keys N | ||
15 | string publickey1 | ||
16 | string publickey2 | ||
17 | ... | ||
18 | string publickeyN | ||
19 | string encrypted, padded list of private keys | ||
20 | |||
21 | 2. KDF options for kdfname "bcrypt" | ||
22 | |||
23 | The options: | ||
24 | |||
25 | string salt | ||
26 | uint32 rounds | ||
27 | |||
28 | are concatenated and represented as a string. | ||
29 | |||
30 | 3. Unencrypted list of N private keys | ||
31 | |||
32 | The list of privatekey/comment pairs is padded with the | ||
33 | bytes 1, 2, 3, ... until the total length is a multiple | ||
34 | of the cipher block size. | ||
35 | |||
36 | uint32 checkint | ||
37 | uint32 checkint | ||
38 | string privatekey1 | ||
39 | string comment1 | ||
40 | string privatekey2 | ||
41 | string comment2 | ||
42 | ... | ||
43 | string privatekeyN | ||
44 | string commentN | ||
45 | char 1 | ||
46 | char 2 | ||
47 | char 3 | ||
48 | ... | ||
49 | char padlen % 255 | ||
50 | |||
51 | Before the key is encrypted, a random integer is assigned | ||
52 | to both checkint fields so successful decryption can be | ||
53 | quickly checked by verifying that both checkint fields | ||
54 | hold the same value. | ||
55 | |||
56 | 4. Encryption | ||
57 | |||
58 | The KDF is used to derive a key, IV (and other values required by | ||
59 | the cipher) from the passphrase. These values are then used to | ||
60 | encrypt the unencrypted list of private keys. | ||
61 | |||
62 | 5. No encryption | ||
63 | |||
64 | For unencrypted keys the cipher "none" and the KDF "none" | ||
65 | are used with empty passphrases. The options if the KDF "none" | ||
66 | are the empty string. | ||
67 | |||
68 | $OpenBSD: PROTOCOL.key,v 1.1 2013/12/06 13:34:54 markus Exp $ | ||
diff --git a/authfile.c b/authfile.c index d0c1089eb..e38a3dd14 100644 --- a/authfile.c +++ b/authfile.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfile.c,v 1.98 2013/11/21 00:45:43 djm Exp $ */ | 1 | /* $OpenBSD: authfile.c,v 1.99 2013/12/06 13:34:54 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -13,7 +13,7 @@ | |||
13 | * called by a name other than "ssh" or "Secure Shell". | 13 | * called by a name other than "ssh" or "Secure Shell". |
14 | * | 14 | * |
15 | * | 15 | * |
16 | * Copyright (c) 2000 Markus Friedl. All rights reserved. | 16 | * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. |
17 | * | 17 | * |
18 | * Redistribution and use in source and binary forms, with or without | 18 | * Redistribution and use in source and binary forms, with or without |
19 | * modification, are permitted provided that the following conditions | 19 | * modification, are permitted provided that the following conditions |
@@ -58,6 +58,8 @@ | |||
58 | #include <string.h> | 58 | #include <string.h> |
59 | #include <unistd.h> | 59 | #include <unistd.h> |
60 | 60 | ||
61 | #include <util.h> | ||
62 | |||
61 | #include "xmalloc.h" | 63 | #include "xmalloc.h" |
62 | #include "cipher.h" | 64 | #include "cipher.h" |
63 | #include "buffer.h" | 65 | #include "buffer.h" |
@@ -68,6 +70,16 @@ | |||
68 | #include "rsa.h" | 70 | #include "rsa.h" |
69 | #include "misc.h" | 71 | #include "misc.h" |
70 | #include "atomicio.h" | 72 | #include "atomicio.h" |
73 | #include "uuencode.h" | ||
74 | |||
75 | /* openssh private key file format */ | ||
76 | #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" | ||
77 | #define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" | ||
78 | #define KDFNAME "bcrypt" | ||
79 | #define AUTH_MAGIC "openssh-key-v1" | ||
80 | #define SALT_LEN 16 | ||
81 | #define DEFAULT_CIPHERNAME "aes256-cbc" | ||
82 | #define DEFAULT_ROUNDS 16 | ||
71 | 83 | ||
72 | #define MAX_KEY_FILE_SIZE (1024 * 1024) | 84 | #define MAX_KEY_FILE_SIZE (1024 * 1024) |
73 | 85 | ||
@@ -75,6 +87,333 @@ | |||
75 | static const char authfile_id_string[] = | 87 | static const char authfile_id_string[] = |
76 | "SSH PRIVATE KEY FILE FORMAT 1.1\n"; | 88 | "SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
77 | 89 | ||
90 | static int | ||
91 | key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase, | ||
92 | const char *comment, const char *ciphername, int rounds) | ||
93 | { | ||
94 | u_char *key, *cp, salt[SALT_LEN]; | ||
95 | size_t keylen, ivlen, blocksize, authlen; | ||
96 | u_int len, check; | ||
97 | int i, n; | ||
98 | const Cipher *c; | ||
99 | Buffer encoded, b, kdf; | ||
100 | CipherContext ctx; | ||
101 | const char *kdfname = KDFNAME; | ||
102 | |||
103 | if (rounds <= 0) | ||
104 | rounds = DEFAULT_ROUNDS; | ||
105 | if (passphrase == NULL || !strlen(passphrase)) { | ||
106 | ciphername = "none"; | ||
107 | kdfname = "none"; | ||
108 | } else if (ciphername == NULL) | ||
109 | ciphername = DEFAULT_CIPHERNAME; | ||
110 | else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) | ||
111 | fatal("invalid cipher"); | ||
112 | |||
113 | if ((c = cipher_by_name(ciphername)) == NULL) | ||
114 | fatal("unknown cipher name"); | ||
115 | buffer_init(&kdf); | ||
116 | blocksize = cipher_blocksize(c); | ||
117 | keylen = cipher_keylen(c); | ||
118 | ivlen = cipher_ivlen(c); | ||
119 | authlen = cipher_authlen(c); | ||
120 | key = xcalloc(1, keylen + ivlen); | ||
121 | if (strcmp(kdfname, "none") != 0) { | ||
122 | arc4random_buf(salt, SALT_LEN); | ||
123 | if (bcrypt_pbkdf(passphrase, strlen(passphrase), | ||
124 | salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) | ||
125 | fatal("bcrypt_pbkdf failed"); | ||
126 | buffer_put_string(&kdf, salt, SALT_LEN); | ||
127 | buffer_put_int(&kdf, rounds); | ||
128 | } | ||
129 | cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1); | ||
130 | memset(key, 0, keylen + ivlen); | ||
131 | free(key); | ||
132 | |||
133 | buffer_init(&encoded); | ||
134 | buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC)); | ||
135 | buffer_put_cstring(&encoded, ciphername); | ||
136 | buffer_put_cstring(&encoded, kdfname); | ||
137 | buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf)); | ||
138 | buffer_put_int(&encoded, 1); /* number of keys */ | ||
139 | key_to_blob(prv, &cp, &len); /* public key */ | ||
140 | buffer_put_string(&encoded, cp, len); | ||
141 | |||
142 | memset(cp, 0, len); | ||
143 | free(cp); | ||
144 | |||
145 | buffer_free(&kdf); | ||
146 | |||
147 | /* set up the buffer that will be encrypted */ | ||
148 | buffer_init(&b); | ||
149 | |||
150 | /* Random check bytes */ | ||
151 | check = arc4random(); | ||
152 | buffer_put_int(&b, check); | ||
153 | buffer_put_int(&b, check); | ||
154 | |||
155 | /* append private key and comment*/ | ||
156 | key_private_serialize(prv, &b); | ||
157 | buffer_put_cstring(&b, comment); | ||
158 | |||
159 | /* padding */ | ||
160 | i = 0; | ||
161 | while (buffer_len(&b) % blocksize) | ||
162 | buffer_put_char(&b, ++i & 0xff); | ||
163 | |||
164 | /* length */ | ||
165 | buffer_put_int(&encoded, buffer_len(&b)); | ||
166 | |||
167 | /* encrypt */ | ||
168 | cp = buffer_append_space(&encoded, buffer_len(&b) + authlen); | ||
169 | if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0, | ||
170 | authlen) != 0) | ||
171 | fatal("%s: cipher_crypt failed", __func__); | ||
172 | buffer_free(&b); | ||
173 | cipher_cleanup(&ctx); | ||
174 | |||
175 | /* uuencode */ | ||
176 | len = 2 * buffer_len(&encoded); | ||
177 | cp = xmalloc(len); | ||
178 | n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded), | ||
179 | (char *)cp, len); | ||
180 | if (n < 0) | ||
181 | fatal("%s: uuencode", __func__); | ||
182 | |||
183 | buffer_clear(blob); | ||
184 | buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1); | ||
185 | for (i = 0; i < n; i++) { | ||
186 | buffer_put_char(blob, cp[i]); | ||
187 | if (i % 70 == 69) | ||
188 | buffer_put_char(blob, '\n'); | ||
189 | } | ||
190 | if (i % 70 != 69) | ||
191 | buffer_put_char(blob, '\n'); | ||
192 | buffer_append(blob, MARK_END, sizeof(MARK_END) - 1); | ||
193 | free(cp); | ||
194 | |||
195 | return buffer_len(blob); | ||
196 | } | ||
197 | |||
198 | static Key * | ||
199 | key_parse_private2(Buffer *blob, int type, const char *passphrase, | ||
200 | char **commentp) | ||
201 | { | ||
202 | u_char *key = NULL, *cp, *salt = NULL, pad, last; | ||
203 | char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp; | ||
204 | u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys; | ||
205 | u_int check1, check2, m1len, m2len; | ||
206 | size_t authlen; | ||
207 | const Cipher *c; | ||
208 | Buffer b, encoded, copy, kdf; | ||
209 | CipherContext ctx; | ||
210 | Key *k = NULL; | ||
211 | int dlen, ret, i; | ||
212 | |||
213 | buffer_init(&b); | ||
214 | buffer_init(&kdf); | ||
215 | buffer_init(&encoded); | ||
216 | buffer_init(©); | ||
217 | |||
218 | /* uudecode */ | ||
219 | m1len = sizeof(MARK_BEGIN) - 1; | ||
220 | m2len = sizeof(MARK_END) - 1; | ||
221 | cp = buffer_ptr(blob); | ||
222 | len = buffer_len(blob); | ||
223 | if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) { | ||
224 | debug("%s: missing begin marker", __func__); | ||
225 | goto out; | ||
226 | } | ||
227 | cp += m1len; | ||
228 | len -= m1len; | ||
229 | while (len) { | ||
230 | if (*cp != '\n' && *cp != '\r') | ||
231 | buffer_put_char(&encoded, *cp); | ||
232 | last = *cp; | ||
233 | len--; | ||
234 | cp++; | ||
235 | if (last == '\n') { | ||
236 | if (len >= m2len && !memcmp(cp, MARK_END, m2len)) { | ||
237 | buffer_put_char(&encoded, '\0'); | ||
238 | break; | ||
239 | } | ||
240 | } | ||
241 | } | ||
242 | if (!len) { | ||
243 | debug("%s: no end marker", __func__); | ||
244 | goto out; | ||
245 | } | ||
246 | len = buffer_len(&encoded); | ||
247 | if ((cp = buffer_append_space(©, len)) == NULL) { | ||
248 | error("%s: buffer_append_space", __func__); | ||
249 | goto out; | ||
250 | } | ||
251 | if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) { | ||
252 | error("%s: uudecode failed", __func__); | ||
253 | goto out; | ||
254 | } | ||
255 | if ((u_int)dlen > len) { | ||
256 | error("%s: crazy uudecode length %d > %u", __func__, dlen, len); | ||
257 | goto out; | ||
258 | } | ||
259 | buffer_consume_end(©, len - dlen); | ||
260 | if (buffer_len(©) < sizeof(AUTH_MAGIC) || | ||
261 | memcmp(buffer_ptr(©), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { | ||
262 | error("%s: bad magic", __func__); | ||
263 | goto out; | ||
264 | } | ||
265 | buffer_consume(©, sizeof(AUTH_MAGIC)); | ||
266 | |||
267 | ciphername = buffer_get_cstring_ret(©, NULL); | ||
268 | if (ciphername == NULL || | ||
269 | (c = cipher_by_name(ciphername)) == NULL) { | ||
270 | error("%s: unknown cipher name", __func__); | ||
271 | goto out; | ||
272 | } | ||
273 | if ((passphrase == NULL || !strlen(passphrase)) && | ||
274 | strcmp(ciphername, "none") != 0) { | ||
275 | /* passphrase required */ | ||
276 | goto out; | ||
277 | } | ||
278 | kdfname = buffer_get_cstring_ret(©, NULL); | ||
279 | if (kdfname == NULL || | ||
280 | (!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) { | ||
281 | error("%s: unknown kdf name", __func__); | ||
282 | goto out; | ||
283 | } | ||
284 | if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { | ||
285 | error("%s: cipher %s requires kdf", __func__, ciphername); | ||
286 | goto out; | ||
287 | } | ||
288 | /* kdf options */ | ||
289 | kdfp = buffer_get_string_ptr_ret(©, &klen); | ||
290 | if (kdfp == NULL) { | ||
291 | error("%s: kdf options not set", __func__); | ||
292 | goto out; | ||
293 | } | ||
294 | if (klen > 0) { | ||
295 | if ((cp = buffer_append_space(&kdf, klen)) == NULL) { | ||
296 | error("%s: kdf alloc failed", __func__); | ||
297 | goto out; | ||
298 | } | ||
299 | memcpy(cp, kdfp, klen); | ||
300 | } | ||
301 | /* number of keys */ | ||
302 | if (buffer_get_int_ret(&nkeys, ©) < 0) { | ||
303 | error("%s: key counter missing", __func__); | ||
304 | goto out; | ||
305 | } | ||
306 | if (nkeys != 1) { | ||
307 | error("%s: only one key supported", __func__); | ||
308 | goto out; | ||
309 | } | ||
310 | /* pubkey */ | ||
311 | if ((cp = buffer_get_string_ret(©, &len)) == NULL) { | ||
312 | error("%s: pubkey not found", __func__); | ||
313 | goto out; | ||
314 | } | ||
315 | free(cp); /* XXX check pubkey against decrypted private key */ | ||
316 | |||
317 | /* size of encrypted key blob */ | ||
318 | len = buffer_get_int(©); | ||
319 | blocksize = cipher_blocksize(c); | ||
320 | authlen = cipher_authlen(c); | ||
321 | if (len < blocksize) { | ||
322 | error("%s: encrypted data too small", __func__); | ||
323 | goto out; | ||
324 | } | ||
325 | if (len % blocksize) { | ||
326 | error("%s: length not multiple of blocksize", __func__); | ||
327 | goto out; | ||
328 | } | ||
329 | |||
330 | /* setup key */ | ||
331 | keylen = cipher_keylen(c); | ||
332 | ivlen = cipher_ivlen(c); | ||
333 | key = xcalloc(1, keylen + ivlen); | ||
334 | if (!strcmp(kdfname, "bcrypt")) { | ||
335 | if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) { | ||
336 | error("%s: salt not set", __func__); | ||
337 | goto out; | ||
338 | } | ||
339 | if (buffer_get_int_ret(&rounds, &kdf) < 0) { | ||
340 | error("%s: rounds not set", __func__); | ||
341 | goto out; | ||
342 | } | ||
343 | if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, | ||
344 | key, keylen + ivlen, rounds) < 0) { | ||
345 | error("%s: bcrypt_pbkdf failed", __func__); | ||
346 | goto out; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | cp = buffer_append_space(&b, len); | ||
351 | cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0); | ||
352 | ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(©), len, 0, authlen); | ||
353 | cipher_cleanup(&ctx); | ||
354 | buffer_consume(©, len); | ||
355 | |||
356 | /* fail silently on decryption errors */ | ||
357 | if (ret != 0) { | ||
358 | debug("%s: decrypt failed", __func__); | ||
359 | goto out; | ||
360 | } | ||
361 | |||
362 | if (buffer_len(©) != 0) { | ||
363 | error("%s: key blob has trailing data (len = %u)", __func__, | ||
364 | buffer_len(©)); | ||
365 | goto out; | ||
366 | } | ||
367 | |||
368 | /* check bytes */ | ||
369 | if (buffer_get_int_ret(&check1, &b) < 0 || | ||
370 | buffer_get_int_ret(&check2, &b) < 0) { | ||
371 | error("check bytes missing"); | ||
372 | goto out; | ||
373 | } | ||
374 | if (check1 != check2) { | ||
375 | debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__, | ||
376 | check1, check2); | ||
377 | goto out; | ||
378 | } | ||
379 | |||
380 | k = key_private_deserialize(&b); | ||
381 | |||
382 | /* comment */ | ||
383 | comment = buffer_get_cstring_ret(&b, NULL); | ||
384 | |||
385 | i = 0; | ||
386 | while (buffer_len(&b)) { | ||
387 | if (buffer_get_char_ret(&pad, &b) == -1 || | ||
388 | pad != (++i & 0xff)) { | ||
389 | error("%s: bad padding", __func__); | ||
390 | key_free(k); | ||
391 | k = NULL; | ||
392 | goto out; | ||
393 | } | ||
394 | } | ||
395 | |||
396 | if (k && commentp) { | ||
397 | *commentp = comment; | ||
398 | comment = NULL; | ||
399 | } | ||
400 | |||
401 | /* XXX decode pubkey and check against private */ | ||
402 | out: | ||
403 | free(ciphername); | ||
404 | free(kdfname); | ||
405 | free(salt); | ||
406 | free(comment); | ||
407 | if (key) | ||
408 | memset(key, 0, keylen + ivlen); | ||
409 | free(key); | ||
410 | buffer_free(&encoded); | ||
411 | buffer_free(©); | ||
412 | buffer_free(&kdf); | ||
413 | buffer_free(&b); | ||
414 | return k; | ||
415 | } | ||
416 | |||
78 | /* | 417 | /* |
79 | * Serialises the authentication (private) key to a blob, encrypting it with | 418 | * Serialises the authentication (private) key to a blob, encrypting it with |
80 | * passphrase. The identification of the blob (lowest 64 bits of n) will | 419 | * passphrase. The identification of the blob (lowest 64 bits of n) will |
@@ -149,8 +488,9 @@ key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, | |||
149 | 488 | ||
150 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | 489 | cipher_set_key_string(&ciphercontext, cipher, passphrase, |
151 | CIPHER_ENCRYPT); | 490 | CIPHER_ENCRYPT); |
152 | cipher_crypt(&ciphercontext, 0, cp, | 491 | if (cipher_crypt(&ciphercontext, 0, cp, |
153 | buffer_ptr(&buffer), buffer_len(&buffer), 0, 0); | 492 | buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0) |
493 | fatal("%s: cipher_crypt failed", __func__); | ||
154 | cipher_cleanup(&ciphercontext); | 494 | cipher_cleanup(&ciphercontext); |
155 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | 495 | memset(&ciphercontext, 0, sizeof(ciphercontext)); |
156 | 496 | ||
@@ -239,7 +579,8 @@ key_save_private_blob(Buffer *keybuf, const char *filename) | |||
239 | /* Serialise "key" to buffer "blob" */ | 579 | /* Serialise "key" to buffer "blob" */ |
240 | static int | 580 | static int |
241 | key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, | 581 | key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, |
242 | const char *comment) | 582 | const char *comment, int force_new_format, const char *new_format_cipher, |
583 | int new_format_rounds) | ||
243 | { | 584 | { |
244 | switch (key->type) { | 585 | switch (key->type) { |
245 | case KEY_RSA1: | 586 | case KEY_RSA1: |
@@ -247,6 +588,10 @@ key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, | |||
247 | case KEY_DSA: | 588 | case KEY_DSA: |
248 | case KEY_ECDSA: | 589 | case KEY_ECDSA: |
249 | case KEY_RSA: | 590 | case KEY_RSA: |
591 | if (force_new_format) { | ||
592 | return key_private_to_blob2(key, blob, passphrase, | ||
593 | comment, new_format_cipher, new_format_rounds); | ||
594 | } | ||
250 | return key_private_pem_to_blob(key, blob, passphrase, comment); | 595 | return key_private_pem_to_blob(key, blob, passphrase, comment); |
251 | default: | 596 | default: |
252 | error("%s: cannot save key type %d", __func__, key->type); | 597 | error("%s: cannot save key type %d", __func__, key->type); |
@@ -256,13 +601,15 @@ key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, | |||
256 | 601 | ||
257 | int | 602 | int |
258 | key_save_private(Key *key, const char *filename, const char *passphrase, | 603 | key_save_private(Key *key, const char *filename, const char *passphrase, |
259 | const char *comment) | 604 | const char *comment, int force_new_format, const char *new_format_cipher, |
605 | int new_format_rounds) | ||
260 | { | 606 | { |
261 | Buffer keyblob; | 607 | Buffer keyblob; |
262 | int success = 0; | 608 | int success = 0; |
263 | 609 | ||
264 | buffer_init(&keyblob); | 610 | buffer_init(&keyblob); |
265 | if (!key_private_to_blob(key, &keyblob, passphrase, comment)) | 611 | if (!key_private_to_blob(key, &keyblob, passphrase, comment, |
612 | force_new_format, new_format_cipher, new_format_rounds)) | ||
266 | goto out; | 613 | goto out; |
267 | if (!key_save_private_blob(&keyblob, filename)) | 614 | if (!key_save_private_blob(&keyblob, filename)) |
268 | goto out; | 615 | goto out; |
@@ -473,8 +820,9 @@ key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) | |||
473 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ | 820 | /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ |
474 | cipher_set_key_string(&ciphercontext, cipher, passphrase, | 821 | cipher_set_key_string(&ciphercontext, cipher, passphrase, |
475 | CIPHER_DECRYPT); | 822 | CIPHER_DECRYPT); |
476 | cipher_crypt(&ciphercontext, 0, cp, | 823 | if (cipher_crypt(&ciphercontext, 0, cp, |
477 | buffer_ptr(©), buffer_len(©), 0, 0); | 824 | buffer_ptr(©), buffer_len(©), 0, 0) != 0) |
825 | fatal("%s: cipher_crypt failed", __func__); | ||
478 | cipher_cleanup(&ciphercontext); | 826 | cipher_cleanup(&ciphercontext); |
479 | memset(&ciphercontext, 0, sizeof(ciphercontext)); | 827 | memset(&ciphercontext, 0, sizeof(ciphercontext)); |
480 | buffer_free(©); | 828 | buffer_free(©); |
@@ -641,6 +989,8 @@ static Key * | |||
641 | key_parse_private_type(Buffer *blob, int type, const char *passphrase, | 989 | key_parse_private_type(Buffer *blob, int type, const char *passphrase, |
642 | char **commentp) | 990 | char **commentp) |
643 | { | 991 | { |
992 | Key *k; | ||
993 | |||
644 | switch (type) { | 994 | switch (type) { |
645 | case KEY_RSA1: | 995 | case KEY_RSA1: |
646 | return key_parse_private_rsa1(blob, passphrase, commentp); | 996 | return key_parse_private_rsa1(blob, passphrase, commentp); |
@@ -648,6 +998,8 @@ key_parse_private_type(Buffer *blob, int type, const char *passphrase, | |||
648 | case KEY_ECDSA: | 998 | case KEY_ECDSA: |
649 | case KEY_RSA: | 999 | case KEY_RSA: |
650 | case KEY_UNSPEC: | 1000 | case KEY_UNSPEC: |
1001 | if ((k = key_parse_private2(blob, type, passphrase, commentp))) | ||
1002 | return k; | ||
651 | return key_parse_private_pem(blob, type, passphrase, commentp); | 1003 | return key_parse_private_pem(blob, type, passphrase, commentp); |
652 | default: | 1004 | default: |
653 | error("%s: cannot parse key type %d", __func__, type); | 1005 | error("%s: cannot parse key type %d", __func__, type); |
@@ -943,4 +1295,3 @@ key_in_file(Key *key, const char *filename, int strict_type) | |||
943 | fclose(f); | 1295 | fclose(f); |
944 | return ret; | 1296 | return ret; |
945 | } | 1297 | } |
946 | |||
diff --git a/authfile.h b/authfile.h index 78349beb5..8ba1c2dbe 100644 --- a/authfile.h +++ b/authfile.h | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: authfile.h,v 1.16 2011/05/04 21:15:29 djm Exp $ */ | 1 | /* $OpenBSD: authfile.h,v 1.17 2013/12/06 13:34:54 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -15,7 +15,8 @@ | |||
15 | #ifndef AUTHFILE_H | 15 | #ifndef AUTHFILE_H |
16 | #define AUTHFILE_H | 16 | #define AUTHFILE_H |
17 | 17 | ||
18 | int key_save_private(Key *, const char *, const char *, const char *); | 18 | int key_save_private(Key *, const char *, const char *, const char *, |
19 | int, const char *, int); | ||
19 | int key_load_file(int, const char *, Buffer *); | 20 | int key_load_file(int, const char *, Buffer *); |
20 | Key *key_load_cert(const char *); | 21 | Key *key_load_cert(const char *); |
21 | Key *key_load_public(const char *, char **); | 22 | Key *key_load_public(const char *, char **); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher.c,v 1.92 2013/12/02 03:13:14 djm Exp $ */ | 1 | /* $OpenBSD: cipher.c,v 1.93 2013/12/06 13:34:54 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -344,17 +344,16 @@ cipher_init(CipherContext *cc, const Cipher *cipher, | |||
344 | * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. | 344 | * Use 'authlen' bytes at offset 'len'+'aadlen' as the authentication tag. |
345 | * This tag is written on encryption and verified on decryption. | 345 | * This tag is written on encryption and verified on decryption. |
346 | * Both 'aadlen' and 'authlen' can be set to 0. | 346 | * Both 'aadlen' and 'authlen' can be set to 0. |
347 | * cipher_crypt() returns 0 on success and -1 if the decryption integrity | ||
348 | * check fails. | ||
347 | */ | 349 | */ |
348 | void | 350 | int |
349 | cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, | 351 | cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, |
350 | u_int len, u_int aadlen, u_int authlen) | 352 | u_int len, u_int aadlen, u_int authlen) |
351 | { | 353 | { |
352 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) { | 354 | if ((cc->cipher->flags & CFLAG_CHACHAPOLY) != 0) |
353 | if (chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, aadlen, | 355 | return chachapoly_crypt(&cc->cp_ctx, seqnr, dest, src, len, |
354 | authlen, cc->encrypt) != 0) | 356 | aadlen, authlen, cc->encrypt); |
355 | fatal("Decryption integrity check failed"); | ||
356 | return; | ||
357 | } | ||
358 | if (authlen) { | 357 | if (authlen) { |
359 | u_char lastiv[1]; | 358 | u_char lastiv[1]; |
360 | 359 | ||
@@ -387,13 +386,14 @@ cipher_crypt(CipherContext *cc, u_int seqnr, u_char *dest, const u_char *src, | |||
387 | if (cc->encrypt) | 386 | if (cc->encrypt) |
388 | fatal("%s: EVP_Cipher(final) failed", __func__); | 387 | fatal("%s: EVP_Cipher(final) failed", __func__); |
389 | else | 388 | else |
390 | fatal("Decryption integrity check failed"); | 389 | return -1; |
391 | } | 390 | } |
392 | if (cc->encrypt && | 391 | if (cc->encrypt && |
393 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, | 392 | !EVP_CIPHER_CTX_ctrl(&cc->evp, EVP_CTRL_GCM_GET_TAG, |
394 | authlen, dest + aadlen + len)) | 393 | authlen, dest + aadlen + len)) |
395 | fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__); | 394 | fatal("%s: EVP_CTRL_GCM_GET_TAG", __func__); |
396 | } | 395 | } |
396 | return 0; | ||
397 | } | 397 | } |
398 | 398 | ||
399 | /* Extract the packet length, including any decryption necessary beforehand */ | 399 | /* Extract the packet length, including any decryption necessary beforehand */ |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: cipher.h,v 1.42 2013/11/21 00:45:44 djm Exp $ */ | 1 | /* $OpenBSD: cipher.h,v 1.43 2013/12/06 13:34:54 markus Exp $ */ |
2 | 2 | ||
3 | /* | 3 | /* |
4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 4 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
@@ -81,7 +81,7 @@ int ciphers_valid(const char *); | |||
81 | char *cipher_alg_list(char, int); | 81 | char *cipher_alg_list(char, int); |
82 | void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, | 82 | void cipher_init(CipherContext *, const Cipher *, const u_char *, u_int, |
83 | const u_char *, u_int, int); | 83 | const u_char *, u_int, int); |
84 | void cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, | 84 | int cipher_crypt(CipherContext *, u_int, u_char *, const u_char *, |
85 | u_int, u_int, u_int); | 85 | u_int, u_int, u_int); |
86 | int cipher_get_length(CipherContext *, u_int *, u_int, | 86 | int cipher_get_length(CipherContext *, u_int *, u_int, |
87 | const u_char *, u_int); | 87 | const u_char *, u_int); |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: key.c,v 1.107 2013/12/06 13:30:08 markus Exp $ */ | 1 | /* $OpenBSD: key.c,v 1.108 2013/12/06 13:34:54 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * read_bignum(): | 3 | * read_bignum(): |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -1892,6 +1892,7 @@ key_certify(Key *k, Key *ca) | |||
1892 | if (!key_cert_is_legacy(k)) | 1892 | if (!key_cert_is_legacy(k)) |
1893 | buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); | 1893 | buffer_put_string(&k->cert->certblob, nonce, sizeof(nonce)); |
1894 | 1894 | ||
1895 | /* XXX this substantially duplicates to_blob(); refactor */ | ||
1895 | switch (k->type) { | 1896 | switch (k->type) { |
1896 | case KEY_DSA_CERT_V00: | 1897 | case KEY_DSA_CERT_V00: |
1897 | case KEY_DSA_CERT: | 1898 | case KEY_DSA_CERT: |
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: packet.c,v 1.190 2013/11/21 00:45:44 djm Exp $ */ | 1 | /* $OpenBSD: packet.c,v 1.191 2013/12/06 13:34:54 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -713,9 +713,10 @@ packet_send1(void) | |||
713 | buffer_append(&active_state->output, buf, 4); | 713 | buffer_append(&active_state->output, buf, 4); |
714 | cp = buffer_append_space(&active_state->output, | 714 | cp = buffer_append_space(&active_state->output, |
715 | buffer_len(&active_state->outgoing_packet)); | 715 | buffer_len(&active_state->outgoing_packet)); |
716 | cipher_crypt(&active_state->send_context, 0, cp, | 716 | if (cipher_crypt(&active_state->send_context, 0, cp, |
717 | buffer_ptr(&active_state->outgoing_packet), | 717 | buffer_ptr(&active_state->outgoing_packet), |
718 | buffer_len(&active_state->outgoing_packet), 0, 0); | 718 | buffer_len(&active_state->outgoing_packet), 0, 0) != 0) |
719 | fatal("%s: cipher_crypt failed", __func__); | ||
719 | 720 | ||
720 | #ifdef PACKET_DEBUG | 721 | #ifdef PACKET_DEBUG |
721 | fprintf(stderr, "encrypted: "); | 722 | fprintf(stderr, "encrypted: "); |
@@ -946,9 +947,10 @@ packet_send2_wrapped(void) | |||
946 | } | 947 | } |
947 | /* encrypt packet and append to output buffer. */ | 948 | /* encrypt packet and append to output buffer. */ |
948 | cp = buffer_append_space(&active_state->output, len + authlen); | 949 | cp = buffer_append_space(&active_state->output, len + authlen); |
949 | cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, | 950 | if (cipher_crypt(&active_state->send_context, active_state->p_send.seqnr, |
950 | cp, buffer_ptr(&active_state->outgoing_packet), | 951 | cp, buffer_ptr(&active_state->outgoing_packet), |
951 | len - aadlen, aadlen, authlen); | 952 | len - aadlen, aadlen, authlen) != 0) |
953 | fatal("%s: cipher_crypt failed", __func__); | ||
952 | /* append unencrypted MAC */ | 954 | /* append unencrypted MAC */ |
953 | if (mac && mac->enabled) { | 955 | if (mac && mac->enabled) { |
954 | if (mac->etm) { | 956 | if (mac->etm) { |
@@ -1208,8 +1210,9 @@ packet_read_poll1(void) | |||
1208 | /* Decrypt data to incoming_packet. */ | 1210 | /* Decrypt data to incoming_packet. */ |
1209 | buffer_clear(&active_state->incoming_packet); | 1211 | buffer_clear(&active_state->incoming_packet); |
1210 | cp = buffer_append_space(&active_state->incoming_packet, padded_len); | 1212 | cp = buffer_append_space(&active_state->incoming_packet, padded_len); |
1211 | cipher_crypt(&active_state->receive_context, 0, cp, | 1213 | if (cipher_crypt(&active_state->receive_context, 0, cp, |
1212 | buffer_ptr(&active_state->input), padded_len, 0, 0); | 1214 | buffer_ptr(&active_state->input), padded_len, 0, 0) != 0) |
1215 | fatal("%s: cipher_crypt failed", __func__); | ||
1213 | 1216 | ||
1214 | buffer_consume(&active_state->input, padded_len); | 1217 | buffer_consume(&active_state->input, padded_len); |
1215 | 1218 | ||
@@ -1304,9 +1307,10 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1304 | buffer_clear(&active_state->incoming_packet); | 1307 | buffer_clear(&active_state->incoming_packet); |
1305 | cp = buffer_append_space(&active_state->incoming_packet, | 1308 | cp = buffer_append_space(&active_state->incoming_packet, |
1306 | block_size); | 1309 | block_size); |
1307 | cipher_crypt(&active_state->receive_context, | 1310 | if (cipher_crypt(&active_state->receive_context, |
1308 | active_state->p_read.seqnr, cp, | 1311 | active_state->p_read.seqnr, cp, |
1309 | buffer_ptr(&active_state->input), block_size, 0, 0); | 1312 | buffer_ptr(&active_state->input), block_size, 0, 0) != 0) |
1313 | fatal("Decryption integrity check failed"); | ||
1310 | cp = buffer_ptr(&active_state->incoming_packet); | 1314 | cp = buffer_ptr(&active_state->incoming_packet); |
1311 | active_state->packlen = get_u32(cp); | 1315 | active_state->packlen = get_u32(cp); |
1312 | if (active_state->packlen < 1 + 4 || | 1316 | if (active_state->packlen < 1 + 4 || |
@@ -1360,9 +1364,10 @@ packet_read_poll2(u_int32_t *seqnr_p) | |||
1360 | macbuf = mac_compute(mac, active_state->p_read.seqnr, | 1364 | macbuf = mac_compute(mac, active_state->p_read.seqnr, |
1361 | buffer_ptr(&active_state->input), aadlen + need); | 1365 | buffer_ptr(&active_state->input), aadlen + need); |
1362 | cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); | 1366 | cp = buffer_append_space(&active_state->incoming_packet, aadlen + need); |
1363 | cipher_crypt(&active_state->receive_context, | 1367 | if (cipher_crypt(&active_state->receive_context, |
1364 | active_state->p_read.seqnr, cp, | 1368 | active_state->p_read.seqnr, cp, |
1365 | buffer_ptr(&active_state->input), need, aadlen, authlen); | 1369 | buffer_ptr(&active_state->input), need, aadlen, authlen) != 0) |
1370 | fatal("Decryption integrity check failed"); | ||
1366 | buffer_consume(&active_state->input, aadlen + need + authlen); | 1371 | buffer_consume(&active_state->input, aadlen + need + authlen); |
1367 | /* | 1372 | /* |
1368 | * compute MAC over seqnr and packet, | 1373 | * compute MAC over seqnr and packet, |
diff --git a/ssh-agent.c b/ssh-agent.c index 0196f8f6b..579ee3840 100644 --- a/ssh-agent.c +++ b/ssh-agent.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-agent.c,v 1.178 2013/12/06 13:30:08 markus Exp $ */ | 1 | /* $OpenBSD: ssh-agent.c,v 1.179 2013/12/06 13:34:54 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -484,7 +484,6 @@ process_add_identity(SocketEntry *e, int version) | |||
484 | /* Generate additional parameters */ | 484 | /* Generate additional parameters */ |
485 | rsa_generate_additional_parameters(k->rsa); | 485 | rsa_generate_additional_parameters(k->rsa); |
486 | 486 | ||
487 | /* enable blinding */ | ||
488 | if (RSA_blinding_on(k->rsa, NULL) != 1) { | 487 | if (RSA_blinding_on(k->rsa, NULL) != 1) { |
489 | error("process_add_identity: RSA_blinding_on failed"); | 488 | error("process_add_identity: RSA_blinding_on failed"); |
490 | key_free(k); | 489 | key_free(k); |
diff --git a/ssh-keygen.c b/ssh-keygen.c index e5e2f2f6c..533eed291 100644 --- a/ssh-keygen.c +++ b/ssh-keygen.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: ssh-keygen.c,v 1.236 2013/12/06 03:40:51 djm Exp $ */ | 1 | /* $OpenBSD: ssh-keygen.c,v 1.237 2013/12/06 13:34:54 markus Exp $ */ |
2 | /* | 2 | /* |
3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> | 3 | * Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | 4 | * Copyright (c) 1994 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
@@ -150,6 +150,18 @@ char *key_type_name = NULL; | |||
150 | /* Load key from this PKCS#11 provider */ | 150 | /* Load key from this PKCS#11 provider */ |
151 | char *pkcs11provider = NULL; | 151 | char *pkcs11provider = NULL; |
152 | 152 | ||
153 | /* Use new OpenSSH private key format when writing SSH2 keys instead of PEM */ | ||
154 | int use_new_format = 0; | ||
155 | |||
156 | /* Cipher for new-format private keys */ | ||
157 | char *new_format_cipher = NULL; | ||
158 | |||
159 | /* | ||
160 | * Number of KDF rounds to derive new format keys / | ||
161 | * number of primality trials when screening moduli. | ||
162 | */ | ||
163 | int rounds = 0; | ||
164 | |||
153 | /* argv0 */ | 165 | /* argv0 */ |
154 | extern char *__progname; | 166 | extern char *__progname; |
155 | 167 | ||
@@ -923,7 +935,8 @@ do_gen_all_hostkeys(struct passwd *pw) | |||
923 | public = key_from_private(private); | 935 | public = key_from_private(private); |
924 | snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, | 936 | snprintf(comment, sizeof comment, "%s@%s", pw->pw_name, |
925 | hostname); | 937 | hostname); |
926 | if (!key_save_private(private, identity_file, "", comment)) { | 938 | if (!key_save_private(private, identity_file, "", comment, |
939 | use_new_format, new_format_cipher, rounds)) { | ||
927 | printf("Saving the key failed: %s.\n", identity_file); | 940 | printf("Saving the key failed: %s.\n", identity_file); |
928 | key_free(private); | 941 | key_free(private); |
929 | key_free(public); | 942 | key_free(public); |
@@ -1275,7 +1288,8 @@ do_change_passphrase(struct passwd *pw) | |||
1275 | } | 1288 | } |
1276 | 1289 | ||
1277 | /* Save the file using the new passphrase. */ | 1290 | /* Save the file using the new passphrase. */ |
1278 | if (!key_save_private(private, identity_file, passphrase1, comment)) { | 1291 | if (!key_save_private(private, identity_file, passphrase1, comment, |
1292 | use_new_format, new_format_cipher, rounds)) { | ||
1279 | printf("Saving the key failed: %s.\n", identity_file); | 1293 | printf("Saving the key failed: %s.\n", identity_file); |
1280 | memset(passphrase1, 0, strlen(passphrase1)); | 1294 | memset(passphrase1, 0, strlen(passphrase1)); |
1281 | free(passphrase1); | 1295 | free(passphrase1); |
@@ -1385,7 +1399,8 @@ do_change_comment(struct passwd *pw) | |||
1385 | } | 1399 | } |
1386 | 1400 | ||
1387 | /* Save the file using the new passphrase. */ | 1401 | /* Save the file using the new passphrase. */ |
1388 | if (!key_save_private(private, identity_file, passphrase, new_comment)) { | 1402 | if (!key_save_private(private, identity_file, passphrase, new_comment, |
1403 | use_new_format, new_format_cipher, rounds)) { | ||
1389 | printf("Saving the key failed: %s.\n", identity_file); | 1404 | printf("Saving the key failed: %s.\n", identity_file); |
1390 | memset(passphrase, 0, strlen(passphrase)); | 1405 | memset(passphrase, 0, strlen(passphrase)); |
1391 | free(passphrase); | 1406 | free(passphrase); |
@@ -2132,7 +2147,7 @@ usage(void) | |||
2132 | fprintf(stderr, "usage: %s [options]\n", __progname); | 2147 | fprintf(stderr, "usage: %s [options]\n", __progname); |
2133 | fprintf(stderr, "Options:\n"); | 2148 | fprintf(stderr, "Options:\n"); |
2134 | fprintf(stderr, " -A Generate non-existent host keys for all key types.\n"); | 2149 | fprintf(stderr, " -A Generate non-existent host keys for all key types.\n"); |
2135 | fprintf(stderr, " -a trials Number of trials for screening DH-GEX moduli.\n"); | 2150 | fprintf(stderr, " -a number Number of KDF rounds for new key format or moduli primality tests.\n"); |
2136 | fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); | 2151 | fprintf(stderr, " -B Show bubblebabble digest of key file.\n"); |
2137 | fprintf(stderr, " -b bits Number of bits in the key to create.\n"); | 2152 | fprintf(stderr, " -b bits Number of bits in the key to create.\n"); |
2138 | fprintf(stderr, " -C comment Provide new comment.\n"); | 2153 | fprintf(stderr, " -C comment Provide new comment.\n"); |
@@ -2160,6 +2175,7 @@ usage(void) | |||
2160 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); | 2175 | fprintf(stderr, " -N phrase Provide new passphrase.\n"); |
2161 | fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); | 2176 | fprintf(stderr, " -n name,... User/host principal names to include in certificate\n"); |
2162 | fprintf(stderr, " -O option Specify a certificate option.\n"); | 2177 | fprintf(stderr, " -O option Specify a certificate option.\n"); |
2178 | fprintf(stderr, " -o Enforce new private key format.\n"); | ||
2163 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); | 2179 | fprintf(stderr, " -P phrase Provide old passphrase.\n"); |
2164 | fprintf(stderr, " -p Change passphrase of private key file.\n"); | 2180 | fprintf(stderr, " -p Change passphrase of private key file.\n"); |
2165 | fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n"); | 2181 | fprintf(stderr, " -Q Test whether key(s) are revoked in KRL.\n"); |
@@ -2176,6 +2192,7 @@ usage(void) | |||
2176 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); | 2192 | fprintf(stderr, " -W gen Generator to use for generating DH-GEX moduli.\n"); |
2177 | fprintf(stderr, " -y Read private key file and print public key.\n"); | 2193 | fprintf(stderr, " -y Read private key file and print public key.\n"); |
2178 | fprintf(stderr, " -z serial Specify a serial number.\n"); | 2194 | fprintf(stderr, " -z serial Specify a serial number.\n"); |
2195 | fprintf(stderr, " -Z cipher Specify a cipher for new private key format.\n"); | ||
2179 | 2196 | ||
2180 | exit(1); | 2197 | exit(1); |
2181 | } | 2198 | } |
@@ -2193,7 +2210,7 @@ main(int argc, char **argv) | |||
2193 | struct passwd *pw; | 2210 | struct passwd *pw; |
2194 | struct stat st; | 2211 | struct stat st; |
2195 | int opt, type, fd; | 2212 | int opt, type, fd; |
2196 | u_int32_t memory = 0, generator_wanted = 0, trials = 100; | 2213 | u_int32_t memory = 0, generator_wanted = 0; |
2197 | int do_gen_candidates = 0, do_screen_candidates = 0; | 2214 | int do_gen_candidates = 0, do_screen_candidates = 0; |
2198 | int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; | 2215 | int gen_all_hostkeys = 0, gen_krl = 0, update_krl = 0, check_krl = 0; |
2199 | unsigned long start_lineno = 0, lines_to_process = 0; | 2216 | unsigned long start_lineno = 0, lines_to_process = 0; |
@@ -2225,9 +2242,9 @@ main(int argc, char **argv) | |||
2225 | exit(1); | 2242 | exit(1); |
2226 | } | 2243 | } |
2227 | 2244 | ||
2228 | /* Remaining characters: EUYZdow */ | 2245 | /* Remaining characters: EUYdw */ |
2229 | while ((opt = getopt(argc, argv, "ABHLQXceghiklpquvxy" | 2246 | while ((opt = getopt(argc, argv, "ABHLQXceghiklopquvxy" |
2230 | "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:a:b:f:j:m:n:r:s:t:z:")) != -1) { | 2247 | "C:D:F:G:I:J:K:M:N:O:P:R:S:T:V:W:Z:a:b:f:g:j:m:n:r:s:t:z:")) != -1) { |
2231 | switch (opt) { | 2248 | switch (opt) { |
2232 | case 'A': | 2249 | case 'A': |
2233 | gen_all_hostkeys = 1; | 2250 | gen_all_hostkeys = 1; |
@@ -2285,6 +2302,9 @@ main(int argc, char **argv) | |||
2285 | case 'n': | 2302 | case 'n': |
2286 | cert_principals = optarg; | 2303 | cert_principals = optarg; |
2287 | break; | 2304 | break; |
2305 | case 'o': | ||
2306 | use_new_format = 1; | ||
2307 | break; | ||
2288 | case 'p': | 2308 | case 'p': |
2289 | change_passphrase = 1; | 2309 | change_passphrase = 1; |
2290 | break; | 2310 | break; |
@@ -2312,6 +2332,9 @@ main(int argc, char **argv) | |||
2312 | case 'O': | 2332 | case 'O': |
2313 | add_cert_option(optarg); | 2333 | add_cert_option(optarg); |
2314 | break; | 2334 | break; |
2335 | case 'Z': | ||
2336 | new_format_cipher = optarg; | ||
2337 | break; | ||
2315 | case 'C': | 2338 | case 'C': |
2316 | identity_comment = optarg; | 2339 | identity_comment = optarg; |
2317 | break; | 2340 | break; |
@@ -2370,9 +2393,9 @@ main(int argc, char **argv) | |||
2370 | optarg, errstr); | 2393 | optarg, errstr); |
2371 | break; | 2394 | break; |
2372 | case 'a': | 2395 | case 'a': |
2373 | trials = (u_int32_t)strtonum(optarg, 1, UINT_MAX, &errstr); | 2396 | rounds = (int)strtonum(optarg, 1, INT_MAX, &errstr); |
2374 | if (errstr) | 2397 | if (errstr) |
2375 | fatal("Invalid number of trials: %s (%s)", | 2398 | fatal("Invalid number: %s (%s)", |
2376 | optarg, errstr); | 2399 | optarg, errstr); |
2377 | break; | 2400 | break; |
2378 | case 'M': | 2401 | case 'M': |
@@ -2531,7 +2554,8 @@ main(int argc, char **argv) | |||
2531 | fatal("Couldn't open moduli file \"%s\": %s", | 2554 | fatal("Couldn't open moduli file \"%s\": %s", |
2532 | out_file, strerror(errno)); | 2555 | out_file, strerror(errno)); |
2533 | } | 2556 | } |
2534 | if (prime_test(in, out, trials, generator_wanted, checkpoint, | 2557 | if (prime_test(in, out, rounds == 0 ? 100 : rounds, |
2558 | generator_wanted, checkpoint, | ||
2535 | start_lineno, lines_to_process) != 0) | 2559 | start_lineno, lines_to_process) != 0) |
2536 | fatal("modulus screening failed"); | 2560 | fatal("modulus screening failed"); |
2537 | return (0); | 2561 | return (0); |
@@ -2623,7 +2647,8 @@ passphrase_again: | |||
2623 | } | 2647 | } |
2624 | 2648 | ||
2625 | /* Save the key with the given passphrase and comment. */ | 2649 | /* Save the key with the given passphrase and comment. */ |
2626 | if (!key_save_private(private, identity_file, passphrase1, comment)) { | 2650 | if (!key_save_private(private, identity_file, passphrase1, comment, |
2651 | use_new_format, new_format_cipher, rounds)) { | ||
2627 | printf("Saving the key failed: %s.\n", identity_file); | 2652 | printf("Saving the key failed: %s.\n", identity_file); |
2628 | memset(passphrase1, 0, strlen(passphrase1)); | 2653 | memset(passphrase1, 0, strlen(passphrase1)); |
2629 | free(passphrase1); | 2654 | free(passphrase1); |