blob: e38a3dd14dc7ba2e1baf55613573eb70430d3eda [file] [log] [blame]
Damien Millerbcd00ab2013-12-07 10:41:55 +11001/* $OpenBSD: authfile.c,v 1.99 2013/12/06 13:34:54 markus Exp $ */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002/*
Damien Miller95def091999-11-25 00:26:21 +11003 * Author: Tatu Ylonen <ylo@cs.hut.fi>
Damien Miller95def091999-11-25 00:26:21 +11004 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
5 * All rights reserved
Damien Miller95def091999-11-25 00:26:21 +11006 * This file contains functions for reading and writing identity files, and
7 * for reading the passphrase from the user.
Damien Miller4af51302000-04-16 11:18:38 +10008 *
Damien Millere4340be2000-09-16 13:29:08 +11009 * 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 *
Damien Millerbcd00ab2013-12-07 10:41:55 +110016 * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +110017 *
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.
Damien Miller95def091999-11-25 00:26:21 +110037 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100038
39#include "includes.h"
Damien Millerf17883e2006-03-15 11:45:54 +110040
41#include <sys/types.h>
42#include <sys/stat.h>
Damien Miller8dbffe72006-08-05 11:02:17 +100043#include <sys/param.h>
Damien Millerd7834352006-08-05 12:39:39 +100044#include <sys/uio.h>
Damien Millerd4a8b7e1999-10-27 13:42:43 +100045
Damien Miller0bc1bd82000-11-13 22:57:25 +110046#include <openssl/err.h>
Damien Millereba71ba2000-04-29 23:57:08 +100047#include <openssl/evp.h>
Ben Lindstrom226cfa02001-01-22 05:34:40 +000048#include <openssl/pem.h>
Damien Millereba71ba2000-04-29 23:57:08 +100049
Darren Tuckere89ed1c2009-11-05 20:43:16 +110050/* compatibility with old or broken OpenSSL versions */
51#include "openbsd-compat/openssl-compat.h"
52
Darren Tuckerba724052006-07-12 22:24:22 +100053#include <errno.h>
Damien Miller57cf6382006-07-10 21:13:46 +100054#include <fcntl.h>
Damien Millerded319c2006-09-01 15:38:36 +100055#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100056#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100057#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100058#include <string.h>
Damien Millere6b3b612006-07-24 14:01:23 +100059#include <unistd.h>
Damien Miller57cf6382006-07-10 21:13:46 +100060
Damien Millerbcd00ab2013-12-07 10:41:55 +110061#include <util.h>
62
Damien Millerd4a8b7e1999-10-27 13:42:43 +100063#include "xmalloc.h"
Damien Millerd7834352006-08-05 12:39:39 +100064#include "cipher.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100065#include "buffer.h"
Damien Millereba71ba2000-04-29 23:57:08 +100066#include "key.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000067#include "ssh.h"
68#include "log.h"
Ben Lindstrom31ca54a2001-02-09 02:11:24 +000069#include "authfile.h"
Damien Miller040b64f2002-01-22 23:10:04 +110070#include "rsa.h"
Darren Tuckerf0f90982004-12-11 13:39:50 +110071#include "misc.h"
Damien Millereccb9de2005-06-17 12:59:34 +100072#include "atomicio.h"
Damien Millerbcd00ab2013-12-07 10:41:55 +110073#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
Damien Millerd4a8b7e1999-10-27 13:42:43 +100083
Damien Miller2ce12ef2011-05-05 14:17:18 +100084#define MAX_KEY_FILE_SIZE (1024 * 1024)
85
Ben Lindstromd0fca422001-03-26 13:44:06 +000086/* Version identification string for SSH v1 identity files. */
Ben Lindstrom1170d712001-01-29 07:51:26 +000087static const char authfile_id_string[] =
88 "SSH PRIVATE KEY FILE FORMAT 1.1\n";
Damien Millerd4a8b7e1999-10-27 13:42:43 +100089
Damien Millerbcd00ab2013-12-07 10:41:55 +110090static int
91key_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
198static Key *
199key_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(&copy);
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(&copy, 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(&copy, len - dlen);
260 if (buffer_len(&copy) < sizeof(AUTH_MAGIC) ||
261 memcmp(buffer_ptr(&copy), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
262 error("%s: bad magic", __func__);
263 goto out;
264 }
265 buffer_consume(&copy, sizeof(AUTH_MAGIC));
266
267 ciphername = buffer_get_cstring_ret(&copy, 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(&copy, 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(&copy, &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, &copy) < 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(&copy, &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(&copy);
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(&copy), len, 0, authlen);
353 cipher_cleanup(&ctx);
354 buffer_consume(&copy, 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(&copy) != 0) {
363 error("%s: key blob has trailing data (len = %u)", __func__,
364 buffer_len(&copy));
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(&copy);
412 buffer_free(&kdf);
413 buffer_free(&b);
414 return k;
415}
416
Damien Miller5428f641999-11-25 11:54:57 +1100417/*
Damien Millera2327922010-12-01 12:01:21 +1100418 * Serialises the authentication (private) key to a blob, encrypting it with
419 * passphrase. The identification of the blob (lowest 64 bits of n) will
Damien Miller5428f641999-11-25 11:54:57 +1100420 * precede the key to provide identification of the key without needing a
421 * passphrase.
422 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000423static int
Damien Millera2327922010-12-01 12:01:21 +1100424key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
Ben Lindstromd0fca422001-03-26 13:44:06 +0000425 const char *comment)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000426{
Damien Miller95def091999-11-25 00:26:21 +1100427 Buffer buffer, encrypted;
Damien Miller708d21c2002-01-22 23:18:15 +1100428 u_char buf[100], *cp;
Damien Millera2327922010-12-01 12:01:21 +1100429 int i, cipher_num;
Damien Miller874d77b2000-10-14 16:23:11 +1100430 CipherContext ciphercontext;
Damien Millerea111192013-04-23 19:24:32 +1000431 const Cipher *cipher;
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000432 u_int32_t rnd;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000433
Damien Miller5428f641999-11-25 11:54:57 +1100434 /*
435 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
436 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
437 */
Damien Miller963f6b22002-02-19 15:21:23 +1100438 cipher_num = (strcmp(passphrase, "") == 0) ?
439 SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
440 if ((cipher = cipher_by_number(cipher_num)) == NULL)
Damien Miller874d77b2000-10-14 16:23:11 +1100441 fatal("save_private_key_rsa: bad cipher");
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000442
Damien Miller95def091999-11-25 00:26:21 +1100443 /* This buffer is used to built the secret part of the private key. */
444 buffer_init(&buffer);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000445
Damien Miller95def091999-11-25 00:26:21 +1100446 /* Put checkbytes for checking passphrase validity. */
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000447 rnd = arc4random();
448 buf[0] = rnd & 0xff;
449 buf[1] = (rnd >> 8) & 0xff;
Damien Miller95def091999-11-25 00:26:21 +1100450 buf[2] = buf[0];
451 buf[3] = buf[1];
452 buffer_append(&buffer, buf, 4);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000453
Damien Miller5428f641999-11-25 11:54:57 +1100454 /*
455 * Store the private key (n and e will not be stored because they
456 * will be stored in plain text, and storing them also in encrypted
457 * format would just give known plaintext).
458 */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000459 buffer_put_bignum(&buffer, key->rsa->d);
460 buffer_put_bignum(&buffer, key->rsa->iqmp);
461 buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
462 buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000463
Damien Miller95def091999-11-25 00:26:21 +1100464 /* Pad the part to be encrypted until its size is a multiple of 8. */
465 while (buffer_len(&buffer) % 8 != 0)
466 buffer_put_char(&buffer, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000467
Damien Miller95def091999-11-25 00:26:21 +1100468 /* This buffer will be used to contain the data in the file. */
469 buffer_init(&encrypted);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000470
Damien Miller95def091999-11-25 00:26:21 +1100471 /* First store keyfile id string. */
Ben Lindstrom1170d712001-01-29 07:51:26 +0000472 for (i = 0; authfile_id_string[i]; i++)
473 buffer_put_char(&encrypted, authfile_id_string[i]);
Damien Miller95def091999-11-25 00:26:21 +1100474 buffer_put_char(&encrypted, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000475
Damien Miller95def091999-11-25 00:26:21 +1100476 /* Store cipher type. */
Damien Miller963f6b22002-02-19 15:21:23 +1100477 buffer_put_char(&encrypted, cipher_num);
Damien Miller95def091999-11-25 00:26:21 +1100478 buffer_put_int(&encrypted, 0); /* For future extension */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000479
Damien Miller95def091999-11-25 00:26:21 +1100480 /* Store public key. This will be in plain text. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000481 buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
482 buffer_put_bignum(&encrypted, key->rsa->n);
483 buffer_put_bignum(&encrypted, key->rsa->e);
Ben Lindstrom664408d2001-06-09 01:42:01 +0000484 buffer_put_cstring(&encrypted, comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000485
Damien Miller95def091999-11-25 00:26:21 +1100486 /* Allocate space for the private part of the key in the buffer. */
Damien Miller5a6b4fe2001-12-21 14:56:54 +1100487 cp = buffer_append_space(&encrypted, buffer_len(&buffer));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000488
Damien Miller963f6b22002-02-19 15:21:23 +1100489 cipher_set_key_string(&ciphercontext, cipher, passphrase,
490 CIPHER_ENCRYPT);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100491 if (cipher_crypt(&ciphercontext, 0, cp,
492 buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0)
493 fatal("%s: cipher_crypt failed", __func__);
Damien Miller963f6b22002-02-19 15:21:23 +1100494 cipher_cleanup(&ciphercontext);
Damien Miller874d77b2000-10-14 16:23:11 +1100495 memset(&ciphercontext, 0, sizeof(ciphercontext));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000496
Damien Miller95def091999-11-25 00:26:21 +1100497 /* Destroy temporary data. */
498 memset(buf, 0, sizeof(buf));
499 buffer_free(&buffer);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000500
Damien Millera2327922010-12-01 12:01:21 +1100501 buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted));
Damien Miller95def091999-11-25 00:26:21 +1100502 buffer_free(&encrypted);
Damien Millera2327922010-12-01 12:01:21 +1100503
Damien Miller95def091999-11-25 00:26:21 +1100504 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000505}
506
Damien Millera2327922010-12-01 12:01:21 +1100507/* convert SSH v2 key in OpenSSL PEM format */
Ben Lindstrombba81212001-06-25 05:01:22 +0000508static int
Damien Millera2327922010-12-01 12:01:21 +1100509key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase,
Ben Lindstromd0fca422001-03-26 13:44:06 +0000510 const char *comment)
Damien Millereba71ba2000-04-29 23:57:08 +1000511{
Damien Miller0bc1bd82000-11-13 22:57:25 +1100512 int success = 0;
Damien Millera2327922010-12-01 12:01:21 +1100513 int blen, len = strlen(_passphrase);
Ben Lindstrom90fd8142002-02-26 18:09:42 +0000514 u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
Darren Tuckerdf6578b2009-11-07 16:03:14 +1100515#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
516 const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
517#else
Darren Tuckerdfb9b712009-10-24 11:46:43 +1100518 const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
Darren Tuckerdf6578b2009-11-07 16:03:14 +1100519#endif
Damien Millera2327922010-12-01 12:01:21 +1100520 const u_char *bptr;
521 BIO *bio;
Damien Millereba71ba2000-04-29 23:57:08 +1000522
523 if (len > 0 && len <= 4) {
Ben Lindstrom15f33862001-04-16 02:00:02 +0000524 error("passphrase too short: have %d bytes, need > 4", len);
Damien Millereba71ba2000-04-29 23:57:08 +1000525 return 0;
526 }
Damien Millera2327922010-12-01 12:01:21 +1100527 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
528 error("%s: BIO_new failed", __func__);
Damien Millereba71ba2000-04-29 23:57:08 +1000529 return 0;
530 }
Damien Miller0bc1bd82000-11-13 22:57:25 +1100531 switch (key->type) {
Ben Lindstromc1116602001-03-29 00:28:37 +0000532 case KEY_DSA:
Damien Millera2327922010-12-01 12:01:21 +1100533 success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
Ben Lindstromc1116602001-03-29 00:28:37 +0000534 cipher, passphrase, len, NULL, NULL);
535 break;
Damien Miller6af914a2010-09-10 11:39:26 +1000536#ifdef OPENSSL_HAS_ECC
Damien Millereb8b60e2010-08-31 22:41:14 +1000537 case KEY_ECDSA:
Damien Millera2327922010-12-01 12:01:21 +1100538 success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
Damien Millereb8b60e2010-08-31 22:41:14 +1000539 cipher, passphrase, len, NULL, NULL);
540 break;
Damien Miller6af914a2010-09-10 11:39:26 +1000541#endif
Ben Lindstromc1116602001-03-29 00:28:37 +0000542 case KEY_RSA:
Damien Millera2327922010-12-01 12:01:21 +1100543 success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
Ben Lindstromc1116602001-03-29 00:28:37 +0000544 cipher, passphrase, len, NULL, NULL);
545 break;
Damien Millereba71ba2000-04-29 23:57:08 +1000546 }
Damien Millera2327922010-12-01 12:01:21 +1100547 if (success) {
548 if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0)
549 success = 0;
550 else
551 buffer_append(blob, bptr, blen);
552 }
553 BIO_free(bio);
Damien Millereba71ba2000-04-29 23:57:08 +1000554 return success;
555}
556
Damien Millera2327922010-12-01 12:01:21 +1100557/* Save a key blob to a file */
558static int
559key_save_private_blob(Buffer *keybuf, const char *filename)
560{
561 int fd;
562
563 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
564 error("open %s failed: %s.", filename, strerror(errno));
565 return 0;
566 }
567 if (atomicio(vwrite, fd, buffer_ptr(keybuf),
568 buffer_len(keybuf)) != buffer_len(keybuf)) {
569 error("write to key file %s failed: %s", filename,
570 strerror(errno));
571 close(fd);
572 unlink(filename);
573 return 0;
574 }
575 close(fd);
576 return 1;
577}
578
579/* Serialise "key" to buffer "blob" */
580static int
581key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
Damien Millerbcd00ab2013-12-07 10:41:55 +1100582 const char *comment, int force_new_format, const char *new_format_cipher,
583 int new_format_rounds)
Damien Millera2327922010-12-01 12:01:21 +1100584{
585 switch (key->type) {
586 case KEY_RSA1:
587 return key_private_rsa1_to_blob(key, blob, passphrase, comment);
588 case KEY_DSA:
589 case KEY_ECDSA:
590 case KEY_RSA:
Damien Millerbcd00ab2013-12-07 10:41:55 +1100591 if (force_new_format) {
592 return key_private_to_blob2(key, blob, passphrase,
593 comment, new_format_cipher, new_format_rounds);
594 }
Damien Millera2327922010-12-01 12:01:21 +1100595 return key_private_pem_to_blob(key, blob, passphrase, comment);
596 default:
597 error("%s: cannot save key type %d", __func__, key->type);
598 return 0;
599 }
600}
601
Damien Millereba71ba2000-04-29 23:57:08 +1000602int
Ben Lindstromd0fca422001-03-26 13:44:06 +0000603key_save_private(Key *key, const char *filename, const char *passphrase,
Damien Millerbcd00ab2013-12-07 10:41:55 +1100604 const char *comment, int force_new_format, const char *new_format_cipher,
605 int new_format_rounds)
Damien Millereba71ba2000-04-29 23:57:08 +1000606{
Damien Millera2327922010-12-01 12:01:21 +1100607 Buffer keyblob;
608 int success = 0;
609
610 buffer_init(&keyblob);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100611 if (!key_private_to_blob(key, &keyblob, passphrase, comment,
612 force_new_format, new_format_cipher, new_format_rounds))
Damien Millera2327922010-12-01 12:01:21 +1100613 goto out;
614 if (!key_save_private_blob(&keyblob, filename))
615 goto out;
616 success = 1;
617 out:
618 buffer_free(&keyblob);
619 return success;
620}
621
622/*
623 * Parse the public, unencrypted portion of a RSA1 key.
624 */
625static Key *
626key_parse_public_rsa1(Buffer *blob, char **commentp)
627{
628 Key *pub;
Damien Millere7ac2bd2011-06-20 14:23:25 +1000629 Buffer copy;
Damien Millera2327922010-12-01 12:01:21 +1100630
631 /* Check that it is at least big enough to contain the ID string. */
632 if (buffer_len(blob) < sizeof(authfile_id_string)) {
633 debug3("Truncated RSA1 identifier");
634 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000635 }
Damien Millera2327922010-12-01 12:01:21 +1100636
637 /*
638 * Make sure it begins with the id string. Consume the id string
639 * from the buffer.
640 */
641 if (memcmp(buffer_ptr(blob), authfile_id_string,
642 sizeof(authfile_id_string)) != 0) {
643 debug3("Incorrect RSA1 identifier");
644 return NULL;
645 }
Damien Millere7ac2bd2011-06-20 14:23:25 +1000646 buffer_init(&copy);
647 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
648 buffer_consume(&copy, sizeof(authfile_id_string));
Damien Millera2327922010-12-01 12:01:21 +1100649
650 /* Skip cipher type and reserved data. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000651 (void) buffer_get_char(&copy); /* cipher type */
652 (void) buffer_get_int(&copy); /* reserved */
Damien Millera2327922010-12-01 12:01:21 +1100653
654 /* Read the public key from the buffer. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000655 (void) buffer_get_int(&copy);
Damien Millera2327922010-12-01 12:01:21 +1100656 pub = key_new(KEY_RSA1);
Damien Millere7ac2bd2011-06-20 14:23:25 +1000657 buffer_get_bignum(&copy, pub->rsa->n);
658 buffer_get_bignum(&copy, pub->rsa->e);
Damien Millera2327922010-12-01 12:01:21 +1100659 if (commentp)
Damien Millere7ac2bd2011-06-20 14:23:25 +1000660 *commentp = buffer_get_string(&copy, NULL);
Damien Millera2327922010-12-01 12:01:21 +1100661 /* The encrypted private part is not parsed by this function. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000662 buffer_free(&copy);
Damien Millera2327922010-12-01 12:01:21 +1100663
664 return pub;
665}
666
Damien Miller2ce12ef2011-05-05 14:17:18 +1000667/* Load a key from a fd into a buffer */
668int
Damien Millera2327922010-12-01 12:01:21 +1100669key_load_file(int fd, const char *filename, Buffer *blob)
670{
Damien Miller2ce12ef2011-05-05 14:17:18 +1000671 u_char buf[1024];
Damien Millera2327922010-12-01 12:01:21 +1100672 size_t len;
Damien Millera2327922010-12-01 12:01:21 +1100673 struct stat st;
674
675 if (fstat(fd, &st) < 0) {
676 error("%s: fstat of key file %.200s%sfailed: %.100s", __func__,
677 filename == NULL ? "" : filename,
678 filename == NULL ? "" : " ",
679 strerror(errno));
Damien Millera2327922010-12-01 12:01:21 +1100680 return 0;
681 }
Damien Miller2ce12ef2011-05-05 14:17:18 +1000682 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
683 st.st_size > MAX_KEY_FILE_SIZE) {
684 toobig:
Damien Millera2327922010-12-01 12:01:21 +1100685 error("%s: key file %.200s%stoo large", __func__,
686 filename == NULL ? "" : filename,
687 filename == NULL ? "" : " ");
Damien Millera2327922010-12-01 12:01:21 +1100688 return 0;
689 }
Damien Miller5d007702012-02-11 08:19:02 +1100690 buffer_clear(blob);
Damien Miller2ce12ef2011-05-05 14:17:18 +1000691 for (;;) {
692 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
693 if (errno == EPIPE)
694 break;
695 debug("%s: read from key file %.200s%sfailed: %.100s",
696 __func__, filename == NULL ? "" : filename,
697 filename == NULL ? "" : " ", strerror(errno));
698 buffer_clear(blob);
699 bzero(buf, sizeof(buf));
700 return 0;
701 }
702 buffer_append(blob, buf, len);
703 if (buffer_len(blob) > MAX_KEY_FILE_SIZE) {
704 buffer_clear(blob);
705 bzero(buf, sizeof(buf));
706 goto toobig;
707 }
708 }
709 bzero(buf, sizeof(buf));
710 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
711 st.st_size != buffer_len(blob)) {
712 debug("%s: key file %.200s%schanged size while reading",
713 __func__, filename == NULL ? "" : filename,
714 filename == NULL ? "" : " ");
Damien Millera2327922010-12-01 12:01:21 +1100715 buffer_clear(blob);
Damien Millera2327922010-12-01 12:01:21 +1100716 return 0;
717 }
Damien Miller2ce12ef2011-05-05 14:17:18 +1000718
Damien Millera2327922010-12-01 12:01:21 +1100719 return 1;
Damien Millereba71ba2000-04-29 23:57:08 +1000720}
721
Damien Miller5428f641999-11-25 11:54:57 +1100722/*
Ben Lindstromd0fca422001-03-26 13:44:06 +0000723 * Loads the public part of the ssh v1 key file. Returns NULL if an error was
724 * encountered (the file does not exist or is not readable), and the key
Damien Miller5428f641999-11-25 11:54:57 +1100725 * otherwise.
726 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000727static Key *
Ben Lindstromd0fca422001-03-26 13:44:06 +0000728key_load_public_rsa1(int fd, const char *filename, char **commentp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000729{
Damien Miller95def091999-11-25 00:26:21 +1100730 Buffer buffer;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000731 Key *pub;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000732
Damien Miller95def091999-11-25 00:26:21 +1100733 buffer_init(&buffer);
Damien Millera2327922010-12-01 12:01:21 +1100734 if (!key_load_file(fd, filename, &buffer)) {
Damien Miller95def091999-11-25 00:26:21 +1100735 buffer_free(&buffer);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000736 return NULL;
Damien Miller95def091999-11-25 00:26:21 +1100737 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000738
Damien Millera2327922010-12-01 12:01:21 +1100739 pub = key_parse_public_rsa1(&buffer, commentp);
740 if (pub == NULL)
741 debug3("Could not load \"%s\" as a RSA1 public key", filename);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000742 buffer_free(&buffer);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000743 return pub;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000744}
745
Ben Lindstromd0fca422001-03-26 13:44:06 +0000746/* load public key from private-key file, works only for SSH v1 */
747Key *
748key_load_public_type(int type, const char *filename, char **commentp)
Damien Millereba71ba2000-04-29 23:57:08 +1000749{
Ben Lindstromd0fca422001-03-26 13:44:06 +0000750 Key *pub;
751 int fd;
752
753 if (type == KEY_RSA1) {
754 fd = open(filename, O_RDONLY);
755 if (fd < 0)
756 return NULL;
757 pub = key_load_public_rsa1(fd, filename, commentp);
758 close(fd);
759 return pub;
Damien Millereba71ba2000-04-29 23:57:08 +1000760 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000761 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000762}
763
Ben Lindstrombba81212001-06-25 05:01:22 +0000764static Key *
Damien Millera2327922010-12-01 12:01:21 +1100765key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000766{
Damien Millereccb9de2005-06-17 12:59:34 +1000767 int check1, check2, cipher_type;
Damien Millera2327922010-12-01 12:01:21 +1100768 Buffer decrypted;
Damien Miller708d21c2002-01-22 23:18:15 +1100769 u_char *cp;
Damien Miller874d77b2000-10-14 16:23:11 +1100770 CipherContext ciphercontext;
Damien Millerea111192013-04-23 19:24:32 +1000771 const Cipher *cipher;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000772 Key *prv = NULL;
Damien Millere7ac2bd2011-06-20 14:23:25 +1000773 Buffer copy;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000774
Ben Lindstrom1170d712001-01-29 07:51:26 +0000775 /* Check that it is at least big enough to contain the ID string. */
Damien Millera2327922010-12-01 12:01:21 +1100776 if (buffer_len(blob) < sizeof(authfile_id_string)) {
777 debug3("Truncated RSA1 identifier");
Ben Lindstromd0fca422001-03-26 13:44:06 +0000778 return NULL;
Damien Miller95def091999-11-25 00:26:21 +1100779 }
Damien Millera2327922010-12-01 12:01:21 +1100780
Damien Miller5428f641999-11-25 11:54:57 +1100781 /*
782 * Make sure it begins with the id string. Consume the id string
783 * from the buffer.
784 */
Damien Millera2327922010-12-01 12:01:21 +1100785 if (memcmp(buffer_ptr(blob), authfile_id_string,
786 sizeof(authfile_id_string)) != 0) {
787 debug3("Incorrect RSA1 identifier");
788 return NULL;
789 }
Damien Millere7ac2bd2011-06-20 14:23:25 +1000790 buffer_init(&copy);
791 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
792 buffer_consume(&copy, sizeof(authfile_id_string));
Ben Lindstromb257cca2001-03-05 04:59:27 +0000793
Damien Miller95def091999-11-25 00:26:21 +1100794 /* Read cipher type. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000795 cipher_type = buffer_get_char(&copy);
796 (void) buffer_get_int(&copy); /* Reserved data. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000797
Damien Miller95def091999-11-25 00:26:21 +1100798 /* Read the public key from the buffer. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000799 (void) buffer_get_int(&copy);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000800 prv = key_new_private(KEY_RSA1);
801
Damien Millere7ac2bd2011-06-20 14:23:25 +1000802 buffer_get_bignum(&copy, prv->rsa->n);
803 buffer_get_bignum(&copy, prv->rsa->e);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000804 if (commentp)
Damien Millere7ac2bd2011-06-20 14:23:25 +1000805 *commentp = buffer_get_string(&copy, NULL);
Damien Miller95def091999-11-25 00:26:21 +1100806 else
Damien Millere7ac2bd2011-06-20 14:23:25 +1000807 (void)buffer_get_string_ptr(&copy, NULL);
Damien Miller95def091999-11-25 00:26:21 +1100808
809 /* Check that it is a supported cipher. */
Damien Miller874d77b2000-10-14 16:23:11 +1100810 cipher = cipher_by_number(cipher_type);
811 if (cipher == NULL) {
Damien Millera2327922010-12-01 12:01:21 +1100812 debug("Unsupported RSA1 cipher %d", cipher_type);
Damien Millere7ac2bd2011-06-20 14:23:25 +1000813 buffer_free(&copy);
Damien Miller95def091999-11-25 00:26:21 +1100814 goto fail;
815 }
816 /* Initialize space for decrypted data. */
817 buffer_init(&decrypted);
Damien Millere7ac2bd2011-06-20 14:23:25 +1000818 cp = buffer_append_space(&decrypted, buffer_len(&copy));
Damien Miller95def091999-11-25 00:26:21 +1100819
820 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
Damien Miller963f6b22002-02-19 15:21:23 +1100821 cipher_set_key_string(&ciphercontext, cipher, passphrase,
822 CIPHER_DECRYPT);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100823 if (cipher_crypt(&ciphercontext, 0, cp,
824 buffer_ptr(&copy), buffer_len(&copy), 0, 0) != 0)
825 fatal("%s: cipher_crypt failed", __func__);
Damien Miller963f6b22002-02-19 15:21:23 +1100826 cipher_cleanup(&ciphercontext);
Damien Miller874d77b2000-10-14 16:23:11 +1100827 memset(&ciphercontext, 0, sizeof(ciphercontext));
Damien Millere7ac2bd2011-06-20 14:23:25 +1000828 buffer_free(&copy);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000829
Damien Miller95def091999-11-25 00:26:21 +1100830 check1 = buffer_get_char(&decrypted);
831 check2 = buffer_get_char(&decrypted);
832 if (check1 != buffer_get_char(&decrypted) ||
833 check2 != buffer_get_char(&decrypted)) {
834 if (strcmp(passphrase, "") != 0)
Damien Millera2327922010-12-01 12:01:21 +1100835 debug("Bad passphrase supplied for RSA1 key");
Damien Miller95def091999-11-25 00:26:21 +1100836 /* Bad passphrase. */
837 buffer_free(&decrypted);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000838 goto fail;
Damien Miller95def091999-11-25 00:26:21 +1100839 }
840 /* Read the rest of the private key. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000841 buffer_get_bignum(&decrypted, prv->rsa->d);
842 buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
843 /* in SSL and SSH v1 p and q are exchanged */
844 buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
845 buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000846
Ben Lindstromd0fca422001-03-26 13:44:06 +0000847 /* calculate p-1 and q-1 */
Damien Millerda755162002-01-22 23:09:22 +1100848 rsa_generate_additional_parameters(prv->rsa);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000849
Damien Miller95def091999-11-25 00:26:21 +1100850 buffer_free(&decrypted);
Damien Millered33d3b2003-03-15 11:36:18 +1100851
852 /* enable blinding */
853 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
Damien Millera2327922010-12-01 12:01:21 +1100854 error("%s: RSA_blinding_on failed", __func__);
Damien Millered33d3b2003-03-15 11:36:18 +1100855 goto fail;
856 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000857 return prv;
858
859fail:
Darren Tuckera627d422013-06-02 07:31:17 +1000860 if (commentp != NULL)
861 free(*commentp);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000862 key_free(prv);
863 return NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000864}
Damien Millereba71ba2000-04-29 23:57:08 +1000865
Damien Millera2327922010-12-01 12:01:21 +1100866static Key *
867key_parse_private_pem(Buffer *blob, int type, const char *passphrase,
Ben Lindstromd0fca422001-03-26 13:44:06 +0000868 char **commentp)
Damien Millereba71ba2000-04-29 23:57:08 +1000869{
Damien Miller0bc1bd82000-11-13 22:57:25 +1100870 EVP_PKEY *pk = NULL;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000871 Key *prv = NULL;
Damien Miller0bc1bd82000-11-13 22:57:25 +1100872 char *name = "<no key>";
Damien Millera2327922010-12-01 12:01:21 +1100873 BIO *bio;
Damien Millereba71ba2000-04-29 23:57:08 +1000874
Damien Millera2327922010-12-01 12:01:21 +1100875 if ((bio = BIO_new_mem_buf(buffer_ptr(blob),
876 buffer_len(blob))) == NULL) {
877 error("%s: BIO_new_mem_buf failed", __func__);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000878 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000879 }
Damien Millera2327922010-12-01 12:01:21 +1100880
881 pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase);
882 BIO_free(bio);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100883 if (pk == NULL) {
Damien Millera2327922010-12-01 12:01:21 +1100884 debug("%s: PEM_read_PrivateKey failed", __func__);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100885 (void)ERR_get_error();
Ben Lindstromd0fca422001-03-26 13:44:06 +0000886 } else if (pk->type == EVP_PKEY_RSA &&
Damien Miller9f0f5c62001-12-21 14:45:46 +1100887 (type == KEY_UNSPEC||type==KEY_RSA)) {
Ben Lindstromd0fca422001-03-26 13:44:06 +0000888 prv = key_new(KEY_UNSPEC);
889 prv->rsa = EVP_PKEY_get1_RSA(pk);
890 prv->type = KEY_RSA;
891 name = "rsa w/o comment";
Damien Miller0bc1bd82000-11-13 22:57:25 +1100892#ifdef DEBUG_PK
Ben Lindstromd0fca422001-03-26 13:44:06 +0000893 RSA_print_fp(stderr, prv->rsa, 8);
Damien Millereba71ba2000-04-29 23:57:08 +1000894#endif
Damien Millered33d3b2003-03-15 11:36:18 +1100895 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
Damien Millera2327922010-12-01 12:01:21 +1100896 error("%s: RSA_blinding_on failed", __func__);
Damien Millered33d3b2003-03-15 11:36:18 +1100897 key_free(prv);
898 prv = NULL;
899 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000900 } else if (pk->type == EVP_PKEY_DSA &&
Damien Miller9f0f5c62001-12-21 14:45:46 +1100901 (type == KEY_UNSPEC||type==KEY_DSA)) {
Ben Lindstromd0fca422001-03-26 13:44:06 +0000902 prv = key_new(KEY_UNSPEC);
903 prv->dsa = EVP_PKEY_get1_DSA(pk);
904 prv->type = KEY_DSA;
905 name = "dsa w/o comment";
Damien Miller0bc1bd82000-11-13 22:57:25 +1100906#ifdef DEBUG_PK
Ben Lindstromd0fca422001-03-26 13:44:06 +0000907 DSA_print_fp(stderr, prv->dsa, 8);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100908#endif
Damien Miller6af914a2010-09-10 11:39:26 +1000909#ifdef OPENSSL_HAS_ECC
Damien Millereb8b60e2010-08-31 22:41:14 +1000910 } else if (pk->type == EVP_PKEY_EC &&
911 (type == KEY_UNSPEC||type==KEY_ECDSA)) {
912 prv = key_new(KEY_UNSPEC);
913 prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
914 prv->type = KEY_ECDSA;
Damien Millerb472a902010-11-05 10:19:49 +1100915 if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 ||
916 key_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
917 key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
Damien Millereb8b60e2010-08-31 22:41:14 +1000918 EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
919 key_ec_validate_private(prv->ecdsa) != 0) {
920 error("%s: bad ECDSA key", __func__);
921 key_free(prv);
922 prv = NULL;
923 }
Damien Millerbf0423e2010-09-10 11:20:38 +1000924 name = "ecdsa w/o comment";
Damien Millereb8b60e2010-08-31 22:41:14 +1000925#ifdef DEBUG_PK
Damien Millerb472a902010-11-05 10:19:49 +1100926 if (prv != NULL && prv->ecdsa != NULL)
Damien Millereb8b60e2010-08-31 22:41:14 +1000927 key_dump_ec_key(prv->ecdsa);
928#endif
Damien Miller6af914a2010-09-10 11:39:26 +1000929#endif /* OPENSSL_HAS_ECC */
Damien Miller0bc1bd82000-11-13 22:57:25 +1100930 } else {
Damien Millera2327922010-12-01 12:01:21 +1100931 error("%s: PEM_read_PrivateKey: mismatch or "
932 "unknown EVP_PKEY save_type %d", __func__, pk->save_type);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100933 }
Damien Miller0bc1bd82000-11-13 22:57:25 +1100934 if (pk != NULL)
935 EVP_PKEY_free(pk);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000936 if (prv != NULL && commentp)
937 *commentp = xstrdup(name);
938 debug("read PEM private key done: type %s",
939 prv ? key_type(prv) : "<unknown>");
940 return prv;
Damien Millereba71ba2000-04-29 23:57:08 +1000941}
942
Damien Millera2327922010-12-01 12:01:21 +1100943Key *
944key_load_private_pem(int fd, int type, const char *passphrase,
945 char **commentp)
946{
947 Buffer buffer;
948 Key *prv;
949
950 buffer_init(&buffer);
951 if (!key_load_file(fd, NULL, &buffer)) {
952 buffer_free(&buffer);
953 return NULL;
954 }
955 prv = key_parse_private_pem(&buffer, type, passphrase, commentp);
956 buffer_free(&buffer);
957 return prv;
958}
959
Damien Miller8275fad2006-03-15 12:06:23 +1100960int
Ben Lindstromd0fca422001-03-26 13:44:06 +0000961key_perm_ok(int fd, const char *filename)
Damien Millereba71ba2000-04-29 23:57:08 +1000962{
Damien Millereba71ba2000-04-29 23:57:08 +1000963 struct stat st;
964
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000965 if (fstat(fd, &st) < 0)
966 return 0;
967 /*
968 * if a key owned by the user is accessed, then we check the
969 * permissions of the file. if the key owned by a different user,
970 * then we don't care.
971 */
Damien Millerb70b61f2000-09-16 16:25:12 +1100972#ifdef HAVE_CYGWIN
Damien Millercb5e44a2000-09-29 12:12:36 +1100973 if (check_ntsec(filename))
Damien Millerb70b61f2000-09-16 16:25:12 +1100974#endif
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000975 if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
Damien Millereba71ba2000-04-29 23:57:08 +1000976 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
977 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
978 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000979 error("Permissions 0%3.3o for '%s' are too open.",
Damien Miller04bd8b02003-05-25 14:38:33 +1000980 (u_int)st.st_mode & 0777, filename);
Damien Millera10abe92011-04-12 15:39:35 +1000981 error("It is required that your private key files are NOT accessible by others.");
Ben Lindstromd0fca422001-03-26 13:44:06 +0000982 error("This private key will be ignored.");
Damien Millereba71ba2000-04-29 23:57:08 +1000983 return 0;
984 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000985 return 1;
986}
Ben Lindstromb257cca2001-03-05 04:59:27 +0000987
Damien Millera2327922010-12-01 12:01:21 +1100988static Key *
989key_parse_private_type(Buffer *blob, int type, const char *passphrase,
990 char **commentp)
991{
Damien Millerbcd00ab2013-12-07 10:41:55 +1100992 Key *k;
993
Damien Millera2327922010-12-01 12:01:21 +1100994 switch (type) {
995 case KEY_RSA1:
996 return key_parse_private_rsa1(blob, passphrase, commentp);
997 case KEY_DSA:
998 case KEY_ECDSA:
999 case KEY_RSA:
1000 case KEY_UNSPEC:
Damien Millerbcd00ab2013-12-07 10:41:55 +11001001 if ((k = key_parse_private2(blob, type, passphrase, commentp)))
1002 return k;
Damien Millera2327922010-12-01 12:01:21 +11001003 return key_parse_private_pem(blob, type, passphrase, commentp);
1004 default:
Damien Miller9d276b82011-05-15 08:51:43 +10001005 error("%s: cannot parse key type %d", __func__, type);
Damien Millera2327922010-12-01 12:01:21 +11001006 break;
1007 }
1008 return NULL;
1009}
1010
Ben Lindstromd0fca422001-03-26 13:44:06 +00001011Key *
1012key_load_private_type(int type, const char *filename, const char *passphrase,
Darren Tucker232b76f2006-05-06 17:41:51 +10001013 char **commentp, int *perm_ok)
Ben Lindstromd0fca422001-03-26 13:44:06 +00001014{
1015 int fd;
Damien Millera2327922010-12-01 12:01:21 +11001016 Key *ret;
1017 Buffer buffer;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001018
1019 fd = open(filename, O_RDONLY);
Darren Tuckerd4c86b12010-01-12 19:41:22 +11001020 if (fd < 0) {
1021 debug("could not open key file '%s': %s", filename,
1022 strerror(errno));
1023 if (perm_ok != NULL)
1024 *perm_ok = 0;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001025 return NULL;
Darren Tucker69c01b12010-01-12 19:42:29 +11001026 }
Ben Lindstromd0fca422001-03-26 13:44:06 +00001027 if (!key_perm_ok(fd, filename)) {
Darren Tucker232b76f2006-05-06 17:41:51 +10001028 if (perm_ok != NULL)
1029 *perm_ok = 0;
Ben Lindstrom15f33862001-04-16 02:00:02 +00001030 error("bad permissions: ignore key: %s", filename);
Ben Lindstromd0fca422001-03-26 13:44:06 +00001031 close(fd);
1032 return NULL;
1033 }
Darren Tucker232b76f2006-05-06 17:41:51 +10001034 if (perm_ok != NULL)
1035 *perm_ok = 1;
Damien Millera2327922010-12-01 12:01:21 +11001036
1037 buffer_init(&buffer);
1038 if (!key_load_file(fd, filename, &buffer)) {
1039 buffer_free(&buffer);
Ben Lindstromb257cca2001-03-05 04:59:27 +00001040 close(fd);
Damien Millera2327922010-12-01 12:01:21 +11001041 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +10001042 }
Damien Millera2327922010-12-01 12:01:21 +11001043 close(fd);
1044 ret = key_parse_private_type(&buffer, type, passphrase, commentp);
1045 buffer_free(&buffer);
1046 return ret;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001047}
1048
1049Key *
Damien Miller2ce12ef2011-05-05 14:17:18 +10001050key_parse_private(Buffer *buffer, const char *filename,
1051 const char *passphrase, char **commentp)
1052{
1053 Key *pub, *prv;
Damien Miller2ce12ef2011-05-05 14:17:18 +10001054
Damien Miller2ce12ef2011-05-05 14:17:18 +10001055 /* it's a SSH v1 key if the public key part is readable */
Damien Millere7ac2bd2011-06-20 14:23:25 +10001056 pub = key_parse_public_rsa1(buffer, commentp);
Damien Miller2ce12ef2011-05-05 14:17:18 +10001057 if (pub == NULL) {
1058 prv = key_parse_private_type(buffer, KEY_UNSPEC,
1059 passphrase, NULL);
1060 /* use the filename as a comment for PEM */
1061 if (commentp && prv)
1062 *commentp = xstrdup(filename);
1063 } else {
1064 key_free(pub);
1065 /* key_parse_public_rsa1() has already loaded the comment */
1066 prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
1067 NULL);
1068 }
1069 return prv;
1070}
1071
1072Key *
Ben Lindstromd0fca422001-03-26 13:44:06 +00001073key_load_private(const char *filename, const char *passphrase,
1074 char **commentp)
1075{
Damien Miller2ce12ef2011-05-05 14:17:18 +10001076 Key *prv;
1077 Buffer buffer;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001078 int fd;
1079
1080 fd = open(filename, O_RDONLY);
Darren Tuckerd4c86b12010-01-12 19:41:22 +11001081 if (fd < 0) {
1082 debug("could not open key file '%s': %s", filename,
1083 strerror(errno));
Ben Lindstromd0fca422001-03-26 13:44:06 +00001084 return NULL;
Darren Tuckerd4c86b12010-01-12 19:41:22 +11001085 }
Ben Lindstromd0fca422001-03-26 13:44:06 +00001086 if (!key_perm_ok(fd, filename)) {
Ben Lindstrom15f33862001-04-16 02:00:02 +00001087 error("bad permissions: ignore key: %s", filename);
Ben Lindstromd0fca422001-03-26 13:44:06 +00001088 close(fd);
1089 return NULL;
1090 }
Damien Millera2327922010-12-01 12:01:21 +11001091
1092 buffer_init(&buffer);
1093 if (!key_load_file(fd, filename, &buffer)) {
1094 buffer_free(&buffer);
1095 close(fd);
1096 return NULL;
1097 }
1098 close(fd);
1099
Damien Miller2ce12ef2011-05-05 14:17:18 +10001100 prv = key_parse_private(&buffer, filename, passphrase, commentp);
Damien Millera2327922010-12-01 12:01:21 +11001101 buffer_free(&buffer);
Ben Lindstrom322915d2001-06-05 20:46:32 +00001102 return prv;
Damien Millereba71ba2000-04-29 23:57:08 +10001103}
Damien Millere4340be2000-09-16 13:29:08 +11001104
Ben Lindstrombba81212001-06-25 05:01:22 +00001105static int
Ben Lindstromd0fca422001-03-26 13:44:06 +00001106key_try_load_public(Key *k, const char *filename, char **commentp)
Damien Millere4340be2000-09-16 13:29:08 +11001107{
1108 FILE *f;
Darren Tucker22cc7412004-12-06 22:47:41 +11001109 char line[SSH_MAX_PUBKEY_BYTES];
Damien Millere4340be2000-09-16 13:29:08 +11001110 char *cp;
Darren Tuckerf0f90982004-12-11 13:39:50 +11001111 u_long linenum = 0;
Damien Millere4340be2000-09-16 13:29:08 +11001112
1113 f = fopen(filename, "r");
1114 if (f != NULL) {
Darren Tucker22cc7412004-12-06 22:47:41 +11001115 while (read_keyfile_line(f, filename, line, sizeof(line),
1116 &linenum) != -1) {
Damien Millere4340be2000-09-16 13:29:08 +11001117 cp = line;
Ben Lindstrom1c37c6a2001-12-06 18:00:18 +00001118 switch (*cp) {
Damien Millere4340be2000-09-16 13:29:08 +11001119 case '#':
1120 case '\n':
1121 case '\0':
1122 continue;
1123 }
Damien Miller32198242011-05-15 08:50:32 +10001124 /* Abort loading if this looks like a private key */
1125 if (strncmp(cp, "-----BEGIN", 10) == 0)
1126 break;
Damien Millere4340be2000-09-16 13:29:08 +11001127 /* Skip leading whitespace. */
1128 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
1129 ;
1130 if (*cp) {
Damien Miller0bc1bd82000-11-13 22:57:25 +11001131 if (key_read(k, &cp) == 1) {
Damien Miller04bb56e2011-05-29 21:42:08 +10001132 cp[strcspn(cp, "\r\n")] = '\0';
1133 if (commentp) {
1134 *commentp = xstrdup(*cp ?
1135 cp : filename);
1136 }
Damien Millere4340be2000-09-16 13:29:08 +11001137 fclose(f);
1138 return 1;
1139 }
1140 }
1141 }
1142 fclose(f);
1143 }
1144 return 0;
1145}
1146
Ben Lindstromd0fca422001-03-26 13:44:06 +00001147/* load public key from ssh v1 private or any pubkey file */
1148Key *
1149key_load_public(const char *filename, char **commentp)
Damien Millere4340be2000-09-16 13:29:08 +11001150{
Ben Lindstromd0fca422001-03-26 13:44:06 +00001151 Key *pub;
1152 char file[MAXPATHLEN];
Damien Millere4340be2000-09-16 13:29:08 +11001153
Damien Millerdb274722003-05-14 13:45:22 +10001154 /* try rsa1 private key */
Ben Lindstromd0fca422001-03-26 13:44:06 +00001155 pub = key_load_public_type(KEY_RSA1, filename, commentp);
1156 if (pub != NULL)
1157 return pub;
Damien Millerdb274722003-05-14 13:45:22 +10001158
1159 /* try rsa1 public key */
1160 pub = key_new(KEY_RSA1);
1161 if (key_try_load_public(pub, filename, commentp) == 1)
1162 return pub;
1163 key_free(pub);
1164
1165 /* try ssh2 public key */
Ben Lindstromd0fca422001-03-26 13:44:06 +00001166 pub = key_new(KEY_UNSPEC);
1167 if (key_try_load_public(pub, filename, commentp) == 1)
1168 return pub;
1169 if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
1170 (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
1171 (key_try_load_public(pub, file, commentp) == 1))
1172 return pub;
1173 key_free(pub);
1174 return NULL;
Damien Millere4340be2000-09-16 13:29:08 +11001175}
Damien Miller1aed65e2010-03-04 21:53:35 +11001176
Damien Millerc1583312010-08-05 13:04:50 +10001177/* Load the certificate associated with the named private key */
1178Key *
1179key_load_cert(const char *filename)
1180{
1181 Key *pub;
Damien Miller5458c4d2010-08-05 13:05:15 +10001182 char *file;
Damien Millerc1583312010-08-05 13:04:50 +10001183
1184 pub = key_new(KEY_UNSPEC);
Damien Miller5458c4d2010-08-05 13:05:15 +10001185 xasprintf(&file, "%s-cert.pub", filename);
1186 if (key_try_load_public(pub, file, NULL) == 1) {
Darren Tuckera627d422013-06-02 07:31:17 +10001187 free(file);
Damien Millerc1583312010-08-05 13:04:50 +10001188 return pub;
Damien Miller5458c4d2010-08-05 13:05:15 +10001189 }
Darren Tuckera627d422013-06-02 07:31:17 +10001190 free(file);
Damien Millerc1583312010-08-05 13:04:50 +10001191 key_free(pub);
1192 return NULL;
1193}
1194
1195/* Load private key and certificate */
1196Key *
1197key_load_private_cert(int type, const char *filename, const char *passphrase,
1198 int *perm_ok)
1199{
1200 Key *key, *pub;
1201
1202 switch (type) {
1203 case KEY_RSA:
1204 case KEY_DSA:
Damien Millereb8b60e2010-08-31 22:41:14 +10001205 case KEY_ECDSA:
Damien Millerc1583312010-08-05 13:04:50 +10001206 break;
1207 default:
1208 error("%s: unsupported key type", __func__);
1209 return NULL;
1210 }
1211
1212 if ((key = key_load_private_type(type, filename,
1213 passphrase, NULL, perm_ok)) == NULL)
1214 return NULL;
1215
1216 if ((pub = key_load_cert(filename)) == NULL) {
1217 key_free(key);
1218 return NULL;
1219 }
1220
1221 /* Make sure the private key matches the certificate */
1222 if (key_equal_public(key, pub) == 0) {
1223 error("%s: certificate does not match private key %s",
1224 __func__, filename);
1225 } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) {
1226 error("%s: key_to_certified failed", __func__);
1227 } else {
1228 key_cert_copy(pub, key);
1229 key_free(pub);
1230 return key;
1231 }
1232
1233 key_free(key);
1234 key_free(pub);
1235 return NULL;
1236}
1237
Damien Miller1aed65e2010-03-04 21:53:35 +11001238/*
1239 * Returns 1 if the specified "key" is listed in the file "filename",
1240 * 0 if the key is not listed or -1 on error.
1241 * If strict_type is set then the key type must match exactly,
1242 * otherwise a comparison that ignores certficiate data is performed.
1243 */
1244int
1245key_in_file(Key *key, const char *filename, int strict_type)
1246{
1247 FILE *f;
1248 char line[SSH_MAX_PUBKEY_BYTES];
1249 char *cp;
1250 u_long linenum = 0;
1251 int ret = 0;
1252 Key *pub;
1253 int (*key_compare)(const Key *, const Key *) = strict_type ?
1254 key_equal : key_equal_public;
1255
1256 if ((f = fopen(filename, "r")) == NULL) {
1257 if (errno == ENOENT) {
1258 debug("%s: keyfile \"%s\" missing", __func__, filename);
1259 return 0;
1260 } else {
1261 error("%s: could not open keyfile \"%s\": %s", __func__,
1262 filename, strerror(errno));
1263 return -1;
1264 }
1265 }
1266
1267 while (read_keyfile_line(f, filename, line, sizeof(line),
1268 &linenum) != -1) {
1269 cp = line;
1270
1271 /* Skip leading whitespace. */
1272 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
1273 ;
1274
1275 /* Skip comments and empty lines */
1276 switch (*cp) {
1277 case '#':
1278 case '\n':
1279 case '\0':
1280 continue;
1281 }
1282
1283 pub = key_new(KEY_UNSPEC);
1284 if (key_read(pub, &cp) != 1) {
1285 key_free(pub);
1286 continue;
1287 }
1288 if (key_compare(key, pub)) {
1289 ret = 1;
1290 key_free(pub);
1291 break;
1292 }
1293 key_free(pub);
1294 }
1295 fclose(f);
1296 return ret;
1297}