1 |
/* $OpenBSD: authfile.c,v 1.103 2014/02/02 03:44:31 djm Exp $ */ |
2 |
/* |
3 |
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
4 |
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
5 |
* All rights reserved |
6 |
* This file contains functions for reading and writing identity files, and |
7 |
* for reading the passphrase from the user. |
8 |
* |
9 |
* As far as I am concerned, the code I have written for this software |
10 |
* can be used freely for any purpose. Any derived versions of this |
11 |
* software must be clearly marked as such, and if the derived work is |
12 |
* incompatible with the protocol description in the RFC file, it must be |
13 |
* called by a name other than "ssh" or "Secure Shell". |
14 |
* |
15 |
* |
16 |
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. |
17 |
* |
18 |
* Redistribution and use in source and binary forms, with or without |
19 |
* modification, are permitted provided that the following conditions |
20 |
* are met: |
21 |
* 1. Redistributions of source code must retain the above copyright |
22 |
* notice, this list of conditions and the following disclaimer. |
23 |
* 2. Redistributions in binary form must reproduce the above copyright |
24 |
* notice, this list of conditions and the following disclaimer in the |
25 |
* documentation and/or other materials provided with the distribution. |
26 |
* |
27 |
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
28 |
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
29 |
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
30 |
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
31 |
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
32 |
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
33 |
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
34 |
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
35 |
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
36 |
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
37 |
*/ |
38 |
|
39 |
#include "includes.h" |
40 |
|
41 |
#include <sys/types.h> |
42 |
#include <sys/stat.h> |
43 |
#include <sys/param.h> |
44 |
#include <sys/uio.h> |
45 |
|
46 |
#include <openssl/err.h> |
47 |
#include <openssl/evp.h> |
48 |
#include <openssl/pem.h> |
49 |
|
50 |
/* compatibility with old or broken OpenSSL versions */ |
51 |
#include "openbsd-compat/openssl-compat.h" |
52 |
|
53 |
#include "crypto_api.h" |
54 |
|
55 |
#include <errno.h> |
56 |
#include <fcntl.h> |
57 |
#include <stdarg.h> |
58 |
#include <stdio.h> |
59 |
#include <stdlib.h> |
60 |
#include <string.h> |
61 |
#include <unistd.h> |
62 |
|
63 |
#ifdef HAVE_UTIL_H |
64 |
#include <util.h> |
65 |
#endif |
66 |
|
67 |
#include "xmalloc.h" |
68 |
#include "cipher.h" |
69 |
#include "buffer.h" |
70 |
#include "key.h" |
71 |
#include "ssh.h" |
72 |
#include "log.h" |
73 |
#include "authfile.h" |
74 |
#include "rsa.h" |
75 |
#include "misc.h" |
76 |
#include "atomicio.h" |
77 |
#include "uuencode.h" |
78 |
|
79 |
/* openssh private key file format */ |
80 |
#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" |
81 |
#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" |
82 |
#define KDFNAME "bcrypt" |
83 |
#define AUTH_MAGIC "openssh-key-v1" |
84 |
#define SALT_LEN 16 |
85 |
#define DEFAULT_CIPHERNAME "aes256-cbc" |
86 |
#define DEFAULT_ROUNDS 16 |
87 |
|
88 |
#define MAX_KEY_FILE_SIZE (1024 * 1024) |
89 |
|
90 |
/* Version identification string for SSH v1 identity files. */ |
91 |
static const char authfile_id_string[] = |
92 |
"SSH PRIVATE KEY FILE FORMAT 1.1\n"; |
93 |
|
94 |
static int |
95 |
key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase, |
96 |
const char *comment, const char *ciphername, int rounds) |
97 |
{ |
98 |
u_char *key, *cp, salt[SALT_LEN]; |
99 |
size_t keylen, ivlen, blocksize, authlen; |
100 |
u_int len, check; |
101 |
int i, n; |
102 |
const Cipher *c; |
103 |
Buffer encoded, b, kdf; |
104 |
CipherContext ctx; |
105 |
const char *kdfname = KDFNAME; |
106 |
|
107 |
if (rounds <= 0) |
108 |
rounds = DEFAULT_ROUNDS; |
109 |
if (passphrase == NULL || !strlen(passphrase)) { |
110 |
ciphername = "none"; |
111 |
kdfname = "none"; |
112 |
} else if (ciphername == NULL) |
113 |
ciphername = DEFAULT_CIPHERNAME; |
114 |
else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) |
115 |
fatal("invalid cipher"); |
116 |
|
117 |
if ((c = cipher_by_name(ciphername)) == NULL) |
118 |
fatal("unknown cipher name"); |
119 |
buffer_init(&kdf); |
120 |
blocksize = cipher_blocksize(c); |
121 |
keylen = cipher_keylen(c); |
122 |
ivlen = cipher_ivlen(c); |
123 |
authlen = cipher_authlen(c); |
124 |
key = xcalloc(1, keylen + ivlen); |
125 |
if (strcmp(kdfname, "none") != 0) { |
126 |
arc4random_buf(salt, SALT_LEN); |
127 |
if (bcrypt_pbkdf(passphrase, strlen(passphrase), |
128 |
salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) |
129 |
fatal("bcrypt_pbkdf failed"); |
130 |
buffer_put_string(&kdf, salt, SALT_LEN); |
131 |
buffer_put_int(&kdf, rounds); |
132 |
} |
133 |
cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1); |
134 |
explicit_bzero(key, keylen + ivlen); |
135 |
free(key); |
136 |
|
137 |
buffer_init(&encoded); |
138 |
buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC)); |
139 |
buffer_put_cstring(&encoded, ciphername); |
140 |
buffer_put_cstring(&encoded, kdfname); |
141 |
buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf)); |
142 |
buffer_put_int(&encoded, 1); /* number of keys */ |
143 |
key_to_blob(prv, &cp, &len); /* public key */ |
144 |
buffer_put_string(&encoded, cp, len); |
145 |
|
146 |
explicit_bzero(cp, len); |
147 |
free(cp); |
148 |
|
149 |
buffer_free(&kdf); |
150 |
|
151 |
/* set up the buffer that will be encrypted */ |
152 |
buffer_init(&b); |
153 |
|
154 |
/* Random check bytes */ |
155 |
check = arc4random(); |
156 |
buffer_put_int(&b, check); |
157 |
buffer_put_int(&b, check); |
158 |
|
159 |
/* append private key and comment*/ |
160 |
key_private_serialize(prv, &b); |
161 |
buffer_put_cstring(&b, comment); |
162 |
|
163 |
/* padding */ |
164 |
i = 0; |
165 |
while (buffer_len(&b) % blocksize) |
166 |
buffer_put_char(&b, ++i & 0xff); |
167 |
|
168 |
/* length */ |
169 |
buffer_put_int(&encoded, buffer_len(&b)); |
170 |
|
171 |
/* encrypt */ |
172 |
cp = buffer_append_space(&encoded, buffer_len(&b) + authlen); |
173 |
if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0, |
174 |
authlen) != 0) |
175 |
fatal("%s: cipher_crypt failed", __func__); |
176 |
buffer_free(&b); |
177 |
cipher_cleanup(&ctx); |
178 |
|
179 |
/* uuencode */ |
180 |
len = 2 * buffer_len(&encoded); |
181 |
cp = xmalloc(len); |
182 |
n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded), |
183 |
(char *)cp, len); |
184 |
if (n < 0) |
185 |
fatal("%s: uuencode", __func__); |
186 |
|
187 |
buffer_clear(blob); |
188 |
buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1); |
189 |
for (i = 0; i < n; i++) { |
190 |
buffer_put_char(blob, cp[i]); |
191 |
if (i % 70 == 69) |
192 |
buffer_put_char(blob, '\n'); |
193 |
} |
194 |
if (i % 70 != 69) |
195 |
buffer_put_char(blob, '\n'); |
196 |
buffer_append(blob, MARK_END, sizeof(MARK_END) - 1); |
197 |
free(cp); |
198 |
|
199 |
return buffer_len(blob); |
200 |
} |
201 |
|
202 |
static Key * |
203 |
key_parse_private2(Buffer *blob, int type, const char *passphrase, |
204 |
char **commentp) |
205 |
{ |
206 |
u_char *key = NULL, *cp, *salt = NULL, pad, last; |
207 |
char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp; |
208 |
u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys; |
209 |
u_int check1, check2, m1len, m2len; |
210 |
size_t authlen; |
211 |
const Cipher *c; |
212 |
Buffer b, encoded, copy, kdf; |
213 |
CipherContext ctx; |
214 |
Key *k = NULL; |
215 |
int dlen, ret, i; |
216 |
|
217 |
buffer_init(&b); |
218 |
buffer_init(&kdf); |
219 |
buffer_init(&encoded); |
220 |
buffer_init(©); |
221 |
|
222 |
/* uudecode */ |
223 |
m1len = sizeof(MARK_BEGIN) - 1; |
224 |
m2len = sizeof(MARK_END) - 1; |
225 |
cp = buffer_ptr(blob); |
226 |
len = buffer_len(blob); |
227 |
if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) { |
228 |
debug("%s: missing begin marker", __func__); |
229 |
goto out; |
230 |
} |
231 |
cp += m1len; |
232 |
len -= m1len; |
233 |
while (len) { |
234 |
if (*cp != '\n' && *cp != '\r') |
235 |
buffer_put_char(&encoded, *cp); |
236 |
last = *cp; |
237 |
len--; |
238 |
cp++; |
239 |
if (last == '\n') { |
240 |
if (len >= m2len && !memcmp(cp, MARK_END, m2len)) { |
241 |
buffer_put_char(&encoded, '\0'); |
242 |
break; |
243 |
} |
244 |
} |
245 |
} |
246 |
if (!len) { |
247 |
debug("%s: no end marker", __func__); |
248 |
goto out; |
249 |
} |
250 |
len = buffer_len(&encoded); |
251 |
if ((cp = buffer_append_space(©, len)) == NULL) { |
252 |
error("%s: buffer_append_space", __func__); |
253 |
goto out; |
254 |
} |
255 |
if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) { |
256 |
error("%s: uudecode failed", __func__); |
257 |
goto out; |
258 |
} |
259 |
if ((u_int)dlen > len) { |
260 |
error("%s: crazy uudecode length %d > %u", __func__, dlen, len); |
261 |
goto out; |
262 |
} |
263 |
buffer_consume_end(©, len - dlen); |
264 |
if (buffer_len(©) < sizeof(AUTH_MAGIC) || |
265 |
memcmp(buffer_ptr(©), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { |
266 |
error("%s: bad magic", __func__); |
267 |
goto out; |
268 |
} |
269 |
buffer_consume(©, sizeof(AUTH_MAGIC)); |
270 |
|
271 |
ciphername = buffer_get_cstring_ret(©, NULL); |
272 |
if (ciphername == NULL || |
273 |
(c = cipher_by_name(ciphername)) == NULL) { |
274 |
error("%s: unknown cipher name", __func__); |
275 |
goto out; |
276 |
} |
277 |
if ((passphrase == NULL || !strlen(passphrase)) && |
278 |
strcmp(ciphername, "none") != 0) { |
279 |
/* passphrase required */ |
280 |
goto out; |
281 |
} |
282 |
kdfname = buffer_get_cstring_ret(©, NULL); |
283 |
if (kdfname == NULL || |
284 |
(!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) { |
285 |
error("%s: unknown kdf name", __func__); |
286 |
goto out; |
287 |
} |
288 |
if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { |
289 |
error("%s: cipher %s requires kdf", __func__, ciphername); |
290 |
goto out; |
291 |
} |
292 |
/* kdf options */ |
293 |
kdfp = buffer_get_string_ptr_ret(©, &klen); |
294 |
if (kdfp == NULL) { |
295 |
error("%s: kdf options not set", __func__); |
296 |
goto out; |
297 |
} |
298 |
if (klen > 0) { |
299 |
if ((cp = buffer_append_space(&kdf, klen)) == NULL) { |
300 |
error("%s: kdf alloc failed", __func__); |
301 |
goto out; |
302 |
} |
303 |
memcpy(cp, kdfp, klen); |
304 |
} |
305 |
/* number of keys */ |
306 |
if (buffer_get_int_ret(&nkeys, ©) < 0) { |
307 |
error("%s: key counter missing", __func__); |
308 |
goto out; |
309 |
} |
310 |
if (nkeys != 1) { |
311 |
error("%s: only one key supported", __func__); |
312 |
goto out; |
313 |
} |
314 |
/* pubkey */ |
315 |
if ((cp = buffer_get_string_ret(©, &len)) == NULL) { |
316 |
error("%s: pubkey not found", __func__); |
317 |
goto out; |
318 |
} |
319 |
free(cp); /* XXX check pubkey against decrypted private key */ |
320 |
|
321 |
/* size of encrypted key blob */ |
322 |
len = buffer_get_int(©); |
323 |
blocksize = cipher_blocksize(c); |
324 |
authlen = cipher_authlen(c); |
325 |
if (len < blocksize) { |
326 |
error("%s: encrypted data too small", __func__); |
327 |
goto out; |
328 |
} |
329 |
if (len % blocksize) { |
330 |
error("%s: length not multiple of blocksize", __func__); |
331 |
goto out; |
332 |
} |
333 |
|
334 |
/* setup key */ |
335 |
keylen = cipher_keylen(c); |
336 |
ivlen = cipher_ivlen(c); |
337 |
key = xcalloc(1, keylen + ivlen); |
338 |
if (!strcmp(kdfname, "bcrypt")) { |
339 |
if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) { |
340 |
error("%s: salt not set", __func__); |
341 |
goto out; |
342 |
} |
343 |
if (buffer_get_int_ret(&rounds, &kdf) < 0) { |
344 |
error("%s: rounds not set", __func__); |
345 |
goto out; |
346 |
} |
347 |
if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, |
348 |
key, keylen + ivlen, rounds) < 0) { |
349 |
error("%s: bcrypt_pbkdf failed", __func__); |
350 |
goto out; |
351 |
} |
352 |
} |
353 |
|
354 |
cp = buffer_append_space(&b, len); |
355 |
cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0); |
356 |
ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(©), len, 0, authlen); |
357 |
cipher_cleanup(&ctx); |
358 |
buffer_consume(©, len); |
359 |
|
360 |
/* fail silently on decryption errors */ |
361 |
if (ret != 0) { |
362 |
debug("%s: decrypt failed", __func__); |
363 |
goto out; |
364 |
} |
365 |
|
366 |
if (buffer_len(©) != 0) { |
367 |
error("%s: key blob has trailing data (len = %u)", __func__, |
368 |
buffer_len(©)); |
369 |
goto out; |
370 |
} |
371 |
|
372 |
/* check bytes */ |
373 |
if (buffer_get_int_ret(&check1, &b) < 0 || |
374 |
buffer_get_int_ret(&check2, &b) < 0) { |
375 |
error("check bytes missing"); |
376 |
goto out; |
377 |
} |
378 |
if (check1 != check2) { |
379 |
debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__, |
380 |
check1, check2); |
381 |
goto out; |
382 |
} |
383 |
|
384 |
k = key_private_deserialize(&b); |
385 |
|
386 |
/* comment */ |
387 |
comment = buffer_get_cstring_ret(&b, NULL); |
388 |
|
389 |
i = 0; |
390 |
while (buffer_len(&b)) { |
391 |
if (buffer_get_char_ret(&pad, &b) == -1 || |
392 |
pad != (++i & 0xff)) { |
393 |
error("%s: bad padding", __func__); |
394 |
key_free(k); |
395 |
k = NULL; |
396 |
goto out; |
397 |
} |
398 |
} |
399 |
|
400 |
if (k && commentp) { |
401 |
*commentp = comment; |
402 |
comment = NULL; |
403 |
} |
404 |
|
405 |
/* XXX decode pubkey and check against private */ |
406 |
out: |
407 |
free(ciphername); |
408 |
free(kdfname); |
409 |
free(salt); |
410 |
free(comment); |
411 |
if (key) |
412 |
explicit_bzero(key, keylen + ivlen); |
413 |
free(key); |
414 |
buffer_free(&encoded); |
415 |
buffer_free(©); |
416 |
buffer_free(&kdf); |
417 |
buffer_free(&b); |
418 |
return k; |
419 |
} |
420 |
|
421 |
/* |
422 |
* Serialises the authentication (private) key to a blob, encrypting it with |
423 |
* passphrase. The identification of the blob (lowest 64 bits of n) will |
424 |
* precede the key to provide identification of the key without needing a |
425 |
* passphrase. |
426 |
*/ |
427 |
static int |
428 |
key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, |
429 |
const char *comment) |
430 |
{ |
431 |
Buffer buffer, encrypted; |
432 |
u_char buf[100], *cp; |
433 |
int i, cipher_num; |
434 |
CipherContext ciphercontext; |
435 |
const Cipher *cipher; |
436 |
u_int32_t rnd; |
437 |
|
438 |
/* |
439 |
* If the passphrase is empty, use SSH_CIPHER_NONE to ease converting |
440 |
* to another cipher; otherwise use SSH_AUTHFILE_CIPHER. |
441 |
*/ |
442 |
cipher_num = (strcmp(passphrase, "") == 0) ? |
443 |
SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; |
444 |
if ((cipher = cipher_by_number(cipher_num)) == NULL) |
445 |
fatal("save_private_key_rsa: bad cipher"); |
446 |
|
447 |
/* This buffer is used to built the secret part of the private key. */ |
448 |
buffer_init(&buffer); |
449 |
|
450 |
/* Put checkbytes for checking passphrase validity. */ |
451 |
rnd = arc4random(); |
452 |
buf[0] = rnd & 0xff; |
453 |
buf[1] = (rnd >> 8) & 0xff; |
454 |
buf[2] = buf[0]; |
455 |
buf[3] = buf[1]; |
456 |
buffer_append(&buffer, buf, 4); |
457 |
|
458 |
/* |
459 |
* Store the private key (n and e will not be stored because they |
460 |
* will be stored in plain text, and storing them also in encrypted |
461 |
* format would just give known plaintext). |
462 |
*/ |
463 |
buffer_put_bignum(&buffer, key->rsa->d); |
464 |
buffer_put_bignum(&buffer, key->rsa->iqmp); |
465 |
buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ |
466 |
buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ |
467 |
|
468 |
/* Pad the part to be encrypted until its size is a multiple of 8. */ |
469 |
while (buffer_len(&buffer) % 8 != 0) |
470 |
buffer_put_char(&buffer, 0); |
471 |
|
472 |
/* This buffer will be used to contain the data in the file. */ |
473 |
buffer_init(&encrypted); |
474 |
|
475 |
/* First store keyfile id string. */ |
476 |
for (i = 0; authfile_id_string[i]; i++) |
477 |
buffer_put_char(&encrypted, authfile_id_string[i]); |
478 |
buffer_put_char(&encrypted, 0); |
479 |
|
480 |
/* Store cipher type. */ |
481 |
buffer_put_char(&encrypted, cipher_num); |
482 |
buffer_put_int(&encrypted, 0); /* For future extension */ |
483 |
|
484 |
/* Store public key. This will be in plain text. */ |
485 |
buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); |
486 |
buffer_put_bignum(&encrypted, key->rsa->n); |
487 |
buffer_put_bignum(&encrypted, key->rsa->e); |
488 |
buffer_put_cstring(&encrypted, comment); |
489 |
|
490 |
/* Allocate space for the private part of the key in the buffer. */ |
491 |
cp = buffer_append_space(&encrypted, buffer_len(&buffer)); |
492 |
|
493 |
cipher_set_key_string(&ciphercontext, cipher, passphrase, |
494 |
CIPHER_ENCRYPT); |
495 |
if (cipher_crypt(&ciphercontext, 0, cp, |
496 |
buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0) |
497 |
fatal("%s: cipher_crypt failed", __func__); |
498 |
cipher_cleanup(&ciphercontext); |
499 |
explicit_bzero(&ciphercontext, sizeof(ciphercontext)); |
500 |
|
501 |
/* Destroy temporary data. */ |
502 |
explicit_bzero(buf, sizeof(buf)); |
503 |
buffer_free(&buffer); |
504 |
|
505 |
buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); |
506 |
buffer_free(&encrypted); |
507 |
|
508 |
return 1; |
509 |
} |
510 |
|
511 |
/* convert SSH v2 key in OpenSSL PEM format */ |
512 |
static int |
513 |
key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, |
514 |
const char *comment) |
515 |
{ |
516 |
int success = 0; |
517 |
int blen, len = strlen(_passphrase); |
518 |
u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; |
519 |
#if (OPENSSL_VERSION_NUMBER < 0x00907000L) |
520 |
const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; |
521 |
#else |
522 |
const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; |
523 |
#endif |
524 |
const u_char *bptr; |
525 |
BIO *bio; |
526 |
|
527 |
if (len > 0 && len <= 4) { |
528 |
error("passphrase too short: have %d bytes, need > 4", len); |
529 |
return 0; |
530 |
} |
531 |
if ((bio = BIO_new(BIO_s_mem())) == NULL) { |
532 |
error("%s: BIO_new failed", __func__); |
533 |
return 0; |
534 |
} |
535 |
switch (key->type) { |
536 |
case KEY_DSA: |
537 |
success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, |
538 |
cipher, passphrase, len, NULL, NULL); |
539 |
break; |
540 |
#ifdef OPENSSL_HAS_ECC |
541 |
case KEY_ECDSA: |
542 |
success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, |
543 |
cipher, passphrase, len, NULL, NULL); |
544 |
break; |
545 |
#endif |
546 |
case KEY_RSA: |
547 |
success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, |
548 |
cipher, passphrase, len, NULL, NULL); |
549 |
break; |
550 |
} |
551 |
if (success) { |
552 |
if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) |
553 |
success = 0; |
554 |
else |
555 |
buffer_append(blob, bptr, blen); |
556 |
} |
557 |
BIO_free(bio); |
558 |
return success; |
559 |
} |
560 |
|
561 |
/* Save a key blob to a file */ |
562 |
static int |
563 |
key_save_private_blob(Buffer *keybuf, const char *filename) |
564 |
{ |
565 |
int fd; |
566 |
|
567 |
if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { |
568 |
error("open %s failed: %s.", filename, strerror(errno)); |
569 |
return 0; |
570 |
} |
571 |
if (atomicio(vwrite, fd, buffer_ptr(keybuf), |
572 |
buffer_len(keybuf)) != buffer_len(keybuf)) { |
573 |
error("write to key file %s failed: %s", filename, |
574 |
strerror(errno)); |
575 |
close(fd); |
576 |
unlink(filename); |
577 |
return 0; |
578 |
} |
579 |
close(fd); |
580 |
return 1; |
581 |
} |
582 |
|
583 |
/* Serialise "key" to buffer "blob" */ |
584 |
static int |
585 |
key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, |
586 |
const char *comment, int force_new_format, const char *new_format_cipher, |
587 |
int new_format_rounds) |
588 |
{ |
589 |
switch (key->type) { |
590 |
case KEY_RSA1: |
591 |
return key_private_rsa1_to_blob(key, blob, passphrase, comment); |
592 |
case KEY_DSA: |
593 |
case KEY_ECDSA: |
594 |
case KEY_RSA: |
595 |
if (force_new_format) { |
596 |
return key_private_to_blob2(key, blob, passphrase, |
597 |
comment, new_format_cipher, new_format_rounds); |
598 |
} |
599 |
return key_private_pem_to_blob(key, blob, passphrase, comment); |
600 |
case KEY_ED25519: |
601 |
return key_private_to_blob2(key, blob, passphrase, |
602 |
comment, new_format_cipher, new_format_rounds); |
603 |
default: |
604 |
error("%s: cannot save key type %d", __func__, key->type); |
605 |
return 0; |
606 |
} |
607 |
} |
608 |
|
609 |
int |
610 |
key_save_private(Key *key, const char *filename, const char *passphrase, |
611 |
const char *comment, int force_new_format, const char *new_format_cipher, |
612 |
int new_format_rounds) |
613 |
{ |
614 |
Buffer keyblob; |
615 |
int success = 0; |
616 |
|
617 |
buffer_init(&keyblob); |
618 |
if (!key_private_to_blob(key, &keyblob, passphrase, comment, |
619 |
force_new_format, new_format_cipher, new_format_rounds)) |
620 |
goto out; |
621 |
if (!key_save_private_blob(&keyblob, filename)) |
622 |
goto out; |
623 |
success = 1; |
624 |
out: |
625 |
buffer_free(&keyblob); |
626 |
return success; |
627 |
} |
628 |
|
629 |
/* |
630 |
* Parse the public, unencrypted portion of a RSA1 key. |
631 |
*/ |
632 |
static Key * |
633 |
key_parse_public_rsa1(Buffer *blob, char **commentp) |
634 |
{ |
635 |
Key *pub; |
636 |
Buffer copy; |
637 |
|
638 |
/* Check that it is at least big enough to contain the ID string. */ |
639 |
if (buffer_len(blob) < sizeof(authfile_id_string)) { |
640 |
debug3("Truncated RSA1 identifier"); |
641 |
return NULL; |
642 |
} |
643 |
|
644 |
/* |
645 |
* Make sure it begins with the id string. Consume the id string |
646 |
* from the buffer. |
647 |
*/ |
648 |
if (memcmp(buffer_ptr(blob), authfile_id_string, |
649 |
sizeof(authfile_id_string)) != 0) { |
650 |
debug3("Incorrect RSA1 identifier"); |
651 |
return NULL; |
652 |
} |
653 |
buffer_init(©); |
654 |
buffer_append(©, buffer_ptr(blob), buffer_len(blob)); |
655 |
buffer_consume(©, sizeof(authfile_id_string)); |
656 |
|
657 |
/* Skip cipher type and reserved data. */ |
658 |
(void) buffer_get_char(©); /* cipher type */ |
659 |
(void) buffer_get_int(©); /* reserved */ |
660 |
|
661 |
/* Read the public key from the buffer. */ |
662 |
(void) buffer_get_int(©); |
663 |
pub = key_new(KEY_RSA1); |
664 |
buffer_get_bignum(©, pub->rsa->n); |
665 |
buffer_get_bignum(©, pub->rsa->e); |
666 |
if (commentp) |
667 |
*commentp = buffer_get_string(©, NULL); |
668 |
/* The encrypted private part is not parsed by this function. */ |
669 |
buffer_free(©); |
670 |
|
671 |
return pub; |
672 |
} |
673 |
|
674 |
/* Load a key from a fd into a buffer */ |
675 |
int |
676 |
key_load_file(int fd, const char *filename, Buffer *blob) |
677 |
{ |
678 |
u_char buf[1024]; |
679 |
size_t len; |
680 |
struct stat st; |
681 |
|
682 |
if (fstat(fd, &st) < 0) { |
683 |
error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, |
684 |
filename == NULL ? "" : filename, |
685 |
filename == NULL ? "" : " ", |
686 |
strerror(errno)); |
687 |
return 0; |
688 |
} |
689 |
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && |
690 |
st.st_size > MAX_KEY_FILE_SIZE) { |
691 |
toobig: |
692 |
error("%s: key file %.200s%stoo large", __func__, |
693 |
filename == NULL ? "" : filename, |
694 |
filename == NULL ? "" : " "); |
695 |
return 0; |
696 |
} |
697 |
buffer_clear(blob); |
698 |
for (;;) { |
699 |
if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { |
700 |
if (errno == EPIPE) |
701 |
break; |
702 |
debug("%s: read from key file %.200s%sfailed: %.100s", |
703 |
__func__, filename == NULL ? "" : filename, |
704 |
filename == NULL ? "" : " ", strerror(errno)); |
705 |
buffer_clear(blob); |
706 |
explicit_bzero(buf, sizeof(buf)); |
707 |
return 0; |
708 |
} |
709 |
buffer_append(blob, buf, len); |
710 |
if (buffer_len(blob) > MAX_KEY_FILE_SIZE) { |
711 |
buffer_clear(blob); |
712 |
explicit_bzero(buf, sizeof(buf)); |
713 |
goto toobig; |
714 |
} |
715 |
} |
716 |
explicit_bzero(buf, sizeof(buf)); |
717 |
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && |
718 |
st.st_size != buffer_len(blob)) { |
719 |
debug("%s: key file %.200s%schanged size while reading", |
720 |
__func__, filename == NULL ? "" : filename, |
721 |
filename == NULL ? "" : " "); |
722 |
buffer_clear(blob); |
723 |
return 0; |
724 |
} |
725 |
|
726 |
return 1; |
727 |
} |
728 |
|
729 |
/* |
730 |
* Loads the public part of the ssh v1 key file. Returns NULL if an error was |
731 |
* encountered (the file does not exist or is not readable), and the key |
732 |
* otherwise. |
733 |
*/ |
734 |
static Key * |
735 |
key_load_public_rsa1(int fd, const char *filename, char **commentp) |
736 |
{ |
737 |
Buffer buffer; |
738 |
Key *pub; |
739 |
|
740 |
buffer_init(&buffer); |
741 |
if (!key_load_file(fd, filename, &buffer)) { |
742 |
buffer_free(&buffer); |
743 |
return NULL; |
744 |
} |
745 |
|
746 |
pub = key_parse_public_rsa1(&buffer, commentp); |
747 |
if (pub == NULL) |
748 |
debug3("Could not load \"%s\" as a RSA1 public key", filename); |
749 |
buffer_free(&buffer); |
750 |
return pub; |
751 |
} |
752 |
|
753 |
/* load public key from private-key file, works only for SSH v1 */ |
754 |
Key * |
755 |
key_load_public_type(int type, const char *filename, char **commentp) |
756 |
{ |
757 |
Key *pub; |
758 |
int fd; |
759 |
|
760 |
if (type == KEY_RSA1) { |
761 |
fd = open(filename, O_RDONLY); |
762 |
if (fd < 0) |
763 |
return NULL; |
764 |
pub = key_load_public_rsa1(fd, filename, commentp); |
765 |
close(fd); |
766 |
return pub; |
767 |
} |
768 |
return NULL; |
769 |
} |
770 |
|
771 |
static Key * |
772 |
key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) |
773 |
{ |
774 |
int check1, check2, cipher_type; |
775 |
Buffer decrypted; |
776 |
u_char *cp; |
777 |
CipherContext ciphercontext; |
778 |
const Cipher *cipher; |
779 |
Key *prv = NULL; |
780 |
Buffer copy; |
781 |
|
782 |
/* Check that it is at least big enough to contain the ID string. */ |
783 |
if (buffer_len(blob) < sizeof(authfile_id_string)) { |
784 |
debug3("Truncated RSA1 identifier"); |
785 |
return NULL; |
786 |
} |
787 |
|
788 |
/* |
789 |
* Make sure it begins with the id string. Consume the id string |
790 |
* from the buffer. |
791 |
*/ |
792 |
if (memcmp(buffer_ptr(blob), authfile_id_string, |
793 |
sizeof(authfile_id_string)) != 0) { |
794 |
debug3("Incorrect RSA1 identifier"); |
795 |
return NULL; |
796 |
} |
797 |
buffer_init(©); |
798 |
buffer_append(©, buffer_ptr(blob), buffer_len(blob)); |
799 |
buffer_consume(©, sizeof(authfile_id_string)); |
800 |
|
801 |
/* Read cipher type. */ |
802 |
cipher_type = buffer_get_char(©); |
803 |
(void) buffer_get_int(©); /* Reserved data. */ |
804 |
|
805 |
/* Read the public key from the buffer. */ |
806 |
(void) buffer_get_int(©); |
807 |
prv = key_new_private(KEY_RSA1); |
808 |
|
809 |
buffer_get_bignum(©, prv->rsa->n); |
810 |
buffer_get_bignum(©, prv->rsa->e); |
811 |
if (commentp) |
812 |
*commentp = buffer_get_string(©, NULL); |
813 |
else |
814 |
(void)buffer_get_string_ptr(©, NULL); |
815 |
|
816 |
/* Check that it is a supported cipher. */ |
817 |
cipher = cipher_by_number(cipher_type); |
818 |
if (cipher == NULL) { |
819 |
debug("Unsupported RSA1 cipher %d", cipher_type); |
820 |
buffer_free(©); |
821 |
goto fail; |
822 |
} |
823 |
/* Initialize space for decrypted data. */ |
824 |
buffer_init(&decrypted); |
825 |
cp = buffer_append_space(&decrypted, buffer_len(©)); |
826 |
|
827 |
/* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ |
828 |
cipher_set_key_string(&ciphercontext, cipher, passphrase, |
829 |
CIPHER_DECRYPT); |
830 |
if (cipher_crypt(&ciphercontext, 0, cp, |
831 |
buffer_ptr(©), buffer_len(©), 0, 0) != 0) |
832 |
fatal("%s: cipher_crypt failed", __func__); |
833 |
cipher_cleanup(&ciphercontext); |
834 |
explicit_bzero(&ciphercontext, sizeof(ciphercontext)); |
835 |
buffer_free(©); |
836 |
|
837 |
check1 = buffer_get_char(&decrypted); |
838 |
check2 = buffer_get_char(&decrypted); |
839 |
if (check1 != buffer_get_char(&decrypted) || |
840 |
check2 != buffer_get_char(&decrypted)) { |
841 |
if (strcmp(passphrase, "") != 0) |
842 |
debug("Bad passphrase supplied for RSA1 key"); |
843 |
/* Bad passphrase. */ |
844 |
buffer_free(&decrypted); |
845 |
goto fail; |
846 |
} |
847 |
/* Read the rest of the private key. */ |
848 |
buffer_get_bignum(&decrypted, prv->rsa->d); |
849 |
buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ |
850 |
/* in SSL and SSH v1 p and q are exchanged */ |
851 |
buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ |
852 |
buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ |
853 |
|
854 |
/* calculate p-1 and q-1 */ |
855 |
rsa_generate_additional_parameters(prv->rsa); |
856 |
|
857 |
buffer_free(&decrypted); |
858 |
|
859 |
/* enable blinding */ |
860 |
if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
861 |
error("%s: RSA_blinding_on failed", __func__); |
862 |
goto fail; |
863 |
} |
864 |
return prv; |
865 |
|
866 |
fail: |
867 |
if (commentp != NULL) |
868 |
free(*commentp); |
869 |
key_free(prv); |
870 |
return NULL; |
871 |
} |
872 |
|
873 |
static Key * |
874 |
key_parse_private_pem(Buffer *blob, int type, const char *passphrase, |
875 |
char **commentp) |
876 |
{ |
877 |
EVP_PKEY *pk = NULL; |
878 |
Key *prv = NULL; |
879 |
char *name = "<no key>"; |
880 |
BIO *bio; |
881 |
|
882 |
if ((bio = BIO_new_mem_buf(buffer_ptr(blob), |
883 |
buffer_len(blob))) == NULL) { |
884 |
error("%s: BIO_new_mem_buf failed", __func__); |
885 |
return NULL; |
886 |
} |
887 |
|
888 |
pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); |
889 |
BIO_free(bio); |
890 |
if (pk == NULL) { |
891 |
debug("%s: PEM_read_PrivateKey failed", __func__); |
892 |
(void)ERR_get_error(); |
893 |
} else if (pk->type == EVP_PKEY_RSA && |
894 |
(type == KEY_UNSPEC||type==KEY_RSA)) { |
895 |
prv = key_new(KEY_UNSPEC); |
896 |
prv->rsa = EVP_PKEY_get1_RSA(pk); |
897 |
prv->type = KEY_RSA; |
898 |
name = "rsa w/o comment"; |
899 |
#ifdef DEBUG_PK |
900 |
RSA_print_fp(stderr, prv->rsa, 8); |
901 |
#endif |
902 |
if (RSA_blinding_on(prv->rsa, NULL) != 1) { |
903 |
error("%s: RSA_blinding_on failed", __func__); |
904 |
key_free(prv); |
905 |
prv = NULL; |
906 |
} |
907 |
} else if (pk->type == EVP_PKEY_DSA && |
908 |
(type == KEY_UNSPEC||type==KEY_DSA)) { |
909 |
prv = key_new(KEY_UNSPEC); |
910 |
prv->dsa = EVP_PKEY_get1_DSA(pk); |
911 |
prv->type = KEY_DSA; |
912 |
name = "dsa w/o comment"; |
913 |
#ifdef DEBUG_PK |
914 |
DSA_print_fp(stderr, prv->dsa, 8); |
915 |
#endif |
916 |
#ifdef OPENSSL_HAS_ECC |
917 |
} else if (pk->type == EVP_PKEY_EC && |
918 |
(type == KEY_UNSPEC||type==KEY_ECDSA)) { |
919 |
prv = key_new(KEY_UNSPEC); |
920 |
prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); |
921 |
prv->type = KEY_ECDSA; |
922 |
if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || |
923 |
key_curve_nid_to_name(prv->ecdsa_nid) == NULL || |
924 |
key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), |
925 |
EC_KEY_get0_public_key(prv->ecdsa)) != 0 || |
926 |
key_ec_validate_private(prv->ecdsa) != 0) { |
927 |
error("%s: bad ECDSA key", __func__); |
928 |
key_free(prv); |
929 |
prv = NULL; |
930 |
} |
931 |
name = "ecdsa w/o comment"; |
932 |
#ifdef DEBUG_PK |
933 |
if (prv != NULL && prv->ecdsa != NULL) |
934 |
key_dump_ec_key(prv->ecdsa); |
935 |
#endif |
936 |
#endif /* OPENSSL_HAS_ECC */ |
937 |
} else { |
938 |
error("%s: PEM_read_PrivateKey: mismatch or " |
939 |
"unknown EVP_PKEY save_type %d", __func__, pk->save_type); |
940 |
} |
941 |
if (pk != NULL) |
942 |
EVP_PKEY_free(pk); |
943 |
if (prv != NULL && commentp) |
944 |
*commentp = xstrdup(name); |
945 |
debug("read PEM private key done: type %s", |
946 |
prv ? key_type(prv) : "<unknown>"); |
947 |
return prv; |
948 |
} |
949 |
|
950 |
Key * |
951 |
key_load_private_pem(int fd, int type, const char *passphrase, |
952 |
char **commentp) |
953 |
{ |
954 |
Buffer buffer; |
955 |
Key *prv; |
956 |
|
957 |
buffer_init(&buffer); |
958 |
if (!key_load_file(fd, NULL, &buffer)) { |
959 |
buffer_free(&buffer); |
960 |
return NULL; |
961 |
} |
962 |
prv = key_parse_private_pem(&buffer, type, passphrase, commentp); |
963 |
buffer_free(&buffer); |
964 |
return prv; |
965 |
} |
966 |
|
967 |
int |
968 |
key_perm_ok(int fd, const char *filename) |
969 |
{ |
970 |
struct stat st; |
971 |
|
972 |
if (fstat(fd, &st) < 0) |
973 |
return 0; |
974 |
/* |
975 |
* if a key owned by the user is accessed, then we check the |
976 |
* permissions of the file. if the key owned by a different user, |
977 |
* then we don't care. |
978 |
*/ |
979 |
#ifdef HAVE_CYGWIN |
980 |
if (check_ntsec(filename)) |
981 |
#endif |
982 |
if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { |
983 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
984 |
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); |
985 |
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); |
986 |
error("Permissions 0%3.3o for '%s' are too open.", |
987 |
(u_int)st.st_mode & 0777, filename); |
988 |
error("It is required that your private key files are NOT accessible by others."); |
989 |
error("This private key will be ignored."); |
990 |
return 0; |
991 |
} |
992 |
return 1; |
993 |
} |
994 |
|
995 |
static Key * |
996 |
key_parse_private_type(Buffer *blob, int type, const char *passphrase, |
997 |
char **commentp) |
998 |
{ |
999 |
Key *k; |
1000 |
|
1001 |
switch (type) { |
1002 |
case KEY_RSA1: |
1003 |
return key_parse_private_rsa1(blob, passphrase, commentp); |
1004 |
case KEY_DSA: |
1005 |
case KEY_ECDSA: |
1006 |
case KEY_RSA: |
1007 |
return key_parse_private_pem(blob, type, passphrase, commentp); |
1008 |
case KEY_ED25519: |
1009 |
return key_parse_private2(blob, type, passphrase, commentp); |
1010 |
case KEY_UNSPEC: |
1011 |
if ((k = key_parse_private2(blob, type, passphrase, commentp))) |
1012 |
return k; |
1013 |
return key_parse_private_pem(blob, type, passphrase, commentp); |
1014 |
default: |
1015 |
error("%s: cannot parse key type %d", __func__, type); |
1016 |
break; |
1017 |
} |
1018 |
return NULL; |
1019 |
} |
1020 |
|
1021 |
Key * |
1022 |
key_load_private_type(int type, const char *filename, const char *passphrase, |
1023 |
char **commentp, int *perm_ok) |
1024 |
{ |
1025 |
int fd; |
1026 |
Key *ret; |
1027 |
Buffer buffer; |
1028 |
|
1029 |
fd = open(filename, O_RDONLY); |
1030 |
if (fd < 0) { |
1031 |
debug("could not open key file '%s': %s", filename, |
1032 |
strerror(errno)); |
1033 |
if (perm_ok != NULL) |
1034 |
*perm_ok = 0; |
1035 |
return NULL; |
1036 |
} |
1037 |
if (!key_perm_ok(fd, filename)) { |
1038 |
if (perm_ok != NULL) |
1039 |
*perm_ok = 0; |
1040 |
error("bad permissions: ignore key: %s", filename); |
1041 |
close(fd); |
1042 |
return NULL; |
1043 |
} |
1044 |
if (perm_ok != NULL) |
1045 |
*perm_ok = 1; |
1046 |
|
1047 |
buffer_init(&buffer); |
1048 |
if (!key_load_file(fd, filename, &buffer)) { |
1049 |
buffer_free(&buffer); |
1050 |
close(fd); |
1051 |
return NULL; |
1052 |
} |
1053 |
close(fd); |
1054 |
ret = key_parse_private_type(&buffer, type, passphrase, commentp); |
1055 |
buffer_free(&buffer); |
1056 |
return ret; |
1057 |
} |
1058 |
|
1059 |
Key * |
1060 |
key_parse_private(Buffer *buffer, const char *filename, |
1061 |
const char *passphrase, char **commentp) |
1062 |
{ |
1063 |
Key *pub, *prv; |
1064 |
|
1065 |
/* it's a SSH v1 key if the public key part is readable */ |
1066 |
pub = key_parse_public_rsa1(buffer, commentp); |
1067 |
if (pub == NULL) { |
1068 |
prv = key_parse_private_type(buffer, KEY_UNSPEC, |
1069 |
passphrase, NULL); |
1070 |
/* use the filename as a comment for PEM */ |
1071 |
if (commentp && prv) |
1072 |
*commentp = xstrdup(filename); |
1073 |
} else { |
1074 |
key_free(pub); |
1075 |
/* key_parse_public_rsa1() has already loaded the comment */ |
1076 |
prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, |
1077 |
NULL); |
1078 |
} |
1079 |
return prv; |
1080 |
} |
1081 |
|
1082 |
Key * |
1083 |
key_load_private(const char *filename, const char *passphrase, |
1084 |
char **commentp) |
1085 |
{ |
1086 |
Key *prv; |
1087 |
Buffer buffer; |
1088 |
int fd; |
1089 |
|
1090 |
fd = open(filename, O_RDONLY); |
1091 |
if (fd < 0) { |
1092 |
debug("could not open key file '%s': %s", filename, |
1093 |
strerror(errno)); |
1094 |
return NULL; |
1095 |
} |
1096 |
if (!key_perm_ok(fd, filename)) { |
1097 |
error("bad permissions: ignore key: %s", filename); |
1098 |
close(fd); |
1099 |
return NULL; |
1100 |
} |
1101 |
|
1102 |
buffer_init(&buffer); |
1103 |
if (!key_load_file(fd, filename, &buffer)) { |
1104 |
buffer_free(&buffer); |
1105 |
close(fd); |
1106 |
return NULL; |
1107 |
} |
1108 |
close(fd); |
1109 |
|
1110 |
prv = key_parse_private(&buffer, filename, passphrase, commentp); |
1111 |
buffer_free(&buffer); |
1112 |
return prv; |
1113 |
} |
1114 |
|
1115 |
static int |
1116 |
key_try_load_public(Key *k, const char *filename, char **commentp) |
1117 |
{ |
1118 |
FILE *f; |
1119 |
char line[SSH_MAX_PUBKEY_BYTES]; |
1120 |
char *cp; |
1121 |
u_long linenum = 0; |
1122 |
|
1123 |
f = fopen(filename, "r"); |
1124 |
if (f != NULL) { |
1125 |
while (read_keyfile_line(f, filename, line, sizeof(line), |
1126 |
&linenum) != -1) { |
1127 |
cp = line; |
1128 |
switch (*cp) { |
1129 |
case '#': |
1130 |
case '\n': |
1131 |
case '\0': |
1132 |
continue; |
1133 |
} |
1134 |
/* Abort loading if this looks like a private key */ |
1135 |
if (strncmp(cp, "-----BEGIN", 10) == 0) |
1136 |
break; |
1137 |
/* Skip leading whitespace. */ |
1138 |
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) |
1139 |
; |
1140 |
if (*cp) { |
1141 |
if (key_read(k, &cp) == 1) { |
1142 |
cp[strcspn(cp, "\r\n")] = '\0'; |
1143 |
if (commentp) { |
1144 |
*commentp = xstrdup(*cp ? |
1145 |
cp : filename); |
1146 |
} |
1147 |
fclose(f); |
1148 |
return 1; |
1149 |
} |
1150 |
} |
1151 |
} |
1152 |
fclose(f); |
1153 |
} |
1154 |
return 0; |
1155 |
} |
1156 |
|
1157 |
/* load public key from ssh v1 private or any pubkey file */ |
1158 |
Key * |
1159 |
key_load_public(const char *filename, char **commentp) |
1160 |
{ |
1161 |
Key *pub; |
1162 |
char file[MAXPATHLEN]; |
1163 |
|
1164 |
/* try rsa1 private key */ |
1165 |
pub = key_load_public_type(KEY_RSA1, filename, commentp); |
1166 |
if (pub != NULL) |
1167 |
return pub; |
1168 |
|
1169 |
/* try rsa1 public key */ |
1170 |
pub = key_new(KEY_RSA1); |
1171 |
if (key_try_load_public(pub, filename, commentp) == 1) |
1172 |
return pub; |
1173 |
key_free(pub); |
1174 |
|
1175 |
/* try ssh2 public key */ |
1176 |
pub = key_new(KEY_UNSPEC); |
1177 |
if (key_try_load_public(pub, filename, commentp) == 1) |
1178 |
return pub; |
1179 |
if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && |
1180 |
(strlcat(file, ".pub", sizeof file) < sizeof(file)) && |
1181 |
(key_try_load_public(pub, file, commentp) == 1)) |
1182 |
return pub; |
1183 |
key_free(pub); |
1184 |
return NULL; |
1185 |
} |
1186 |
|
1187 |
/* Load the certificate associated with the named private key */ |
1188 |
Key * |
1189 |
key_load_cert(const char *filename) |
1190 |
{ |
1191 |
Key *pub; |
1192 |
char *file; |
1193 |
|
1194 |
pub = key_new(KEY_UNSPEC); |
1195 |
xasprintf(&file, "%s-cert.pub", filename); |
1196 |
if (key_try_load_public(pub, file, NULL) == 1) { |
1197 |
free(file); |
1198 |
return pub; |
1199 |
} |
1200 |
free(file); |
1201 |
key_free(pub); |
1202 |
return NULL; |
1203 |
} |
1204 |
|
1205 |
/* Load private key and certificate */ |
1206 |
Key * |
1207 |
key_load_private_cert(int type, const char *filename, const char *passphrase, |
1208 |
int *perm_ok) |
1209 |
{ |
1210 |
Key *key, *pub; |
1211 |
|
1212 |
switch (type) { |
1213 |
case KEY_RSA: |
1214 |
case KEY_DSA: |
1215 |
case KEY_ECDSA: |
1216 |
case KEY_ED25519: |
1217 |
break; |
1218 |
default: |
1219 |
error("%s: unsupported key type", __func__); |
1220 |
return NULL; |
1221 |
} |
1222 |
|
1223 |
if ((key = key_load_private_type(type, filename, |
1224 |
passphrase, NULL, perm_ok)) == NULL) |
1225 |
return NULL; |
1226 |
|
1227 |
if ((pub = key_load_cert(filename)) == NULL) { |
1228 |
key_free(key); |
1229 |
return NULL; |
1230 |
} |
1231 |
|
1232 |
/* Make sure the private key matches the certificate */ |
1233 |
if (key_equal_public(key, pub) == 0) { |
1234 |
error("%s: certificate does not match private key %s", |
1235 |
__func__, filename); |
1236 |
} else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { |
1237 |
error("%s: key_to_certified failed", __func__); |
1238 |
} else { |
1239 |
key_cert_copy(pub, key); |
1240 |
key_free(pub); |
1241 |
return key; |
1242 |
} |
1243 |
|
1244 |
key_free(key); |
1245 |
key_free(pub); |
1246 |
return NULL; |
1247 |
} |
1248 |
|
1249 |
/* |
1250 |
* Returns 1 if the specified "key" is listed in the file "filename", |
1251 |
* 0 if the key is not listed or -1 on error. |
1252 |
* If strict_type is set then the key type must match exactly, |
1253 |
* otherwise a comparison that ignores certficiate data is performed. |
1254 |
*/ |
1255 |
int |
1256 |
key_in_file(Key *key, const char *filename, int strict_type) |
1257 |
{ |
1258 |
FILE *f; |
1259 |
char line[SSH_MAX_PUBKEY_BYTES]; |
1260 |
char *cp; |
1261 |
u_long linenum = 0; |
1262 |
int ret = 0; |
1263 |
Key *pub; |
1264 |
int (*key_compare)(const Key *, const Key *) = strict_type ? |
1265 |
key_equal : key_equal_public; |
1266 |
|
1267 |
if ((f = fopen(filename, "r")) == NULL) { |
1268 |
if (errno == ENOENT) { |
1269 |
debug("%s: keyfile \"%s\" missing", __func__, filename); |
1270 |
return 0; |
1271 |
} else { |
1272 |
error("%s: could not open keyfile \"%s\": %s", __func__, |
1273 |
filename, strerror(errno)); |
1274 |
return -1; |
1275 |
} |
1276 |
} |
1277 |
|
1278 |
while (read_keyfile_line(f, filename, line, sizeof(line), |
1279 |
&linenum) != -1) { |
1280 |
cp = line; |
1281 |
|
1282 |
/* Skip leading whitespace. */ |
1283 |
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) |
1284 |
; |
1285 |
|
1286 |
/* Skip comments and empty lines */ |
1287 |
switch (*cp) { |
1288 |
case '#': |
1289 |
case '\n': |
1290 |
case '\0': |
1291 |
continue; |
1292 |
} |
1293 |
|
1294 |
pub = key_new(KEY_UNSPEC); |
1295 |
if (key_read(pub, &cp) != 1) { |
1296 |
key_free(pub); |
1297 |
continue; |
1298 |
} |
1299 |
if (key_compare(key, pub)) { |
1300 |
ret = 1; |
1301 |
key_free(pub); |
1302 |
break; |
1303 |
} |
1304 |
key_free(pub); |
1305 |
} |
1306 |
fclose(f); |
1307 |
return ret; |
1308 |
} |