blob: 7cb901133a42f0abf974c746875c147fcefa964a [file] [log] [blame]
Damien Miller1f0311c2014-05-15 14:24:09 +10001/* $OpenBSD: authfile.c,v 1.106 2014/04/29 18:01:49 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 Miller1f0311c2014-05-15 14:24:09 +100046#ifdef WITH_OPENSSL
Damien Miller0bc1bd82000-11-13 22:57:25 +110047#include <openssl/err.h>
Damien Millereba71ba2000-04-29 23:57:08 +100048#include <openssl/evp.h>
Ben Lindstrom226cfa02001-01-22 05:34:40 +000049#include <openssl/pem.h>
Damien Miller1f0311c2014-05-15 14:24:09 +100050#endif
Damien Millereba71ba2000-04-29 23:57:08 +100051
Darren Tuckere89ed1c2009-11-05 20:43:16 +110052/* compatibility with old or broken OpenSSL versions */
53#include "openbsd-compat/openssl-compat.h"
54
Damien Miller5be9d9e2013-12-07 11:24:01 +110055#include "crypto_api.h"
56
Darren Tuckerba724052006-07-12 22:24:22 +100057#include <errno.h>
Damien Miller57cf6382006-07-10 21:13:46 +100058#include <fcntl.h>
Damien Millerded319c2006-09-01 15:38:36 +100059#include <stdarg.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100060#include <stdio.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100061#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100062#include <string.h>
Damien Millere6b3b612006-07-24 14:01:23 +100063#include <unistd.h>
Damien Miller57cf6382006-07-10 21:13:46 +100064
Damien Miller42608282013-12-07 11:38:03 +110065#ifdef HAVE_UTIL_H
Damien Millerbcd00ab2013-12-07 10:41:55 +110066#include <util.h>
Damien Miller42608282013-12-07 11:38:03 +110067#endif
Damien Millerbcd00ab2013-12-07 10:41:55 +110068
Damien Millerd4a8b7e1999-10-27 13:42:43 +100069#include "xmalloc.h"
Damien Millerd7834352006-08-05 12:39:39 +100070#include "cipher.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100071#include "buffer.h"
Damien Millereba71ba2000-04-29 23:57:08 +100072#include "key.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000073#include "ssh.h"
74#include "log.h"
Ben Lindstrom31ca54a2001-02-09 02:11:24 +000075#include "authfile.h"
Damien Miller040b64f2002-01-22 23:10:04 +110076#include "rsa.h"
Darren Tuckerf0f90982004-12-11 13:39:50 +110077#include "misc.h"
Damien Millereccb9de2005-06-17 12:59:34 +100078#include "atomicio.h"
Damien Millerbcd00ab2013-12-07 10:41:55 +110079#include "uuencode.h"
80
81/* openssh private key file format */
82#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n"
83#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n"
84#define KDFNAME "bcrypt"
85#define AUTH_MAGIC "openssh-key-v1"
86#define SALT_LEN 16
87#define DEFAULT_CIPHERNAME "aes256-cbc"
88#define DEFAULT_ROUNDS 16
Damien Millerd4a8b7e1999-10-27 13:42:43 +100089
Damien Miller2ce12ef2011-05-05 14:17:18 +100090#define MAX_KEY_FILE_SIZE (1024 * 1024)
91
Ben Lindstromd0fca422001-03-26 13:44:06 +000092/* Version identification string for SSH v1 identity files. */
Ben Lindstrom1170d712001-01-29 07:51:26 +000093static const char authfile_id_string[] =
94 "SSH PRIVATE KEY FILE FORMAT 1.1\n";
Damien Millerd4a8b7e1999-10-27 13:42:43 +100095
Damien Millerbcd00ab2013-12-07 10:41:55 +110096static int
97key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase,
98 const char *comment, const char *ciphername, int rounds)
99{
100 u_char *key, *cp, salt[SALT_LEN];
101 size_t keylen, ivlen, blocksize, authlen;
102 u_int len, check;
103 int i, n;
104 const Cipher *c;
105 Buffer encoded, b, kdf;
106 CipherContext ctx;
107 const char *kdfname = KDFNAME;
108
109 if (rounds <= 0)
110 rounds = DEFAULT_ROUNDS;
111 if (passphrase == NULL || !strlen(passphrase)) {
112 ciphername = "none";
113 kdfname = "none";
114 } else if (ciphername == NULL)
115 ciphername = DEFAULT_CIPHERNAME;
116 else if (cipher_number(ciphername) != SSH_CIPHER_SSH2)
117 fatal("invalid cipher");
118
119 if ((c = cipher_by_name(ciphername)) == NULL)
120 fatal("unknown cipher name");
121 buffer_init(&kdf);
122 blocksize = cipher_blocksize(c);
123 keylen = cipher_keylen(c);
124 ivlen = cipher_ivlen(c);
125 authlen = cipher_authlen(c);
126 key = xcalloc(1, keylen + ivlen);
127 if (strcmp(kdfname, "none") != 0) {
128 arc4random_buf(salt, SALT_LEN);
129 if (bcrypt_pbkdf(passphrase, strlen(passphrase),
130 salt, SALT_LEN, key, keylen + ivlen, rounds) < 0)
131 fatal("bcrypt_pbkdf failed");
132 buffer_put_string(&kdf, salt, SALT_LEN);
133 buffer_put_int(&kdf, rounds);
134 }
135 cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1);
Damien Millera5103f42014-02-04 11:20:14 +1100136 explicit_bzero(key, keylen + ivlen);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100137 free(key);
138
139 buffer_init(&encoded);
140 buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC));
141 buffer_put_cstring(&encoded, ciphername);
142 buffer_put_cstring(&encoded, kdfname);
143 buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf));
144 buffer_put_int(&encoded, 1); /* number of keys */
145 key_to_blob(prv, &cp, &len); /* public key */
146 buffer_put_string(&encoded, cp, len);
147
Damien Millera5103f42014-02-04 11:20:14 +1100148 explicit_bzero(cp, len);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100149 free(cp);
150
151 buffer_free(&kdf);
152
153 /* set up the buffer that will be encrypted */
154 buffer_init(&b);
155
156 /* Random check bytes */
157 check = arc4random();
158 buffer_put_int(&b, check);
159 buffer_put_int(&b, check);
160
161 /* append private key and comment*/
162 key_private_serialize(prv, &b);
163 buffer_put_cstring(&b, comment);
164
165 /* padding */
166 i = 0;
167 while (buffer_len(&b) % blocksize)
168 buffer_put_char(&b, ++i & 0xff);
169
170 /* length */
171 buffer_put_int(&encoded, buffer_len(&b));
172
173 /* encrypt */
174 cp = buffer_append_space(&encoded, buffer_len(&b) + authlen);
175 if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0,
176 authlen) != 0)
177 fatal("%s: cipher_crypt failed", __func__);
178 buffer_free(&b);
179 cipher_cleanup(&ctx);
180
181 /* uuencode */
182 len = 2 * buffer_len(&encoded);
183 cp = xmalloc(len);
184 n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded),
185 (char *)cp, len);
186 if (n < 0)
187 fatal("%s: uuencode", __func__);
188
189 buffer_clear(blob);
190 buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1);
191 for (i = 0; i < n; i++) {
192 buffer_put_char(blob, cp[i]);
193 if (i % 70 == 69)
194 buffer_put_char(blob, '\n');
195 }
196 if (i % 70 != 69)
197 buffer_put_char(blob, '\n');
198 buffer_append(blob, MARK_END, sizeof(MARK_END) - 1);
199 free(cp);
200
201 return buffer_len(blob);
202}
203
204static Key *
205key_parse_private2(Buffer *blob, int type, const char *passphrase,
206 char **commentp)
207{
208 u_char *key = NULL, *cp, *salt = NULL, pad, last;
Damien Miller633de332014-05-15 13:48:26 +1000209 char *comment = NULL, *ciphername = NULL, *kdfname = NULL;
210 const u_char *kdfp;
Damien Millerbcd00ab2013-12-07 10:41:55 +1100211 u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys;
212 u_int check1, check2, m1len, m2len;
213 size_t authlen;
214 const Cipher *c;
215 Buffer b, encoded, copy, kdf;
216 CipherContext ctx;
217 Key *k = NULL;
218 int dlen, ret, i;
219
220 buffer_init(&b);
221 buffer_init(&kdf);
222 buffer_init(&encoded);
223 buffer_init(&copy);
224
225 /* uudecode */
226 m1len = sizeof(MARK_BEGIN) - 1;
227 m2len = sizeof(MARK_END) - 1;
228 cp = buffer_ptr(blob);
229 len = buffer_len(blob);
230 if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) {
231 debug("%s: missing begin marker", __func__);
232 goto out;
233 }
234 cp += m1len;
235 len -= m1len;
236 while (len) {
237 if (*cp != '\n' && *cp != '\r')
238 buffer_put_char(&encoded, *cp);
239 last = *cp;
240 len--;
241 cp++;
242 if (last == '\n') {
243 if (len >= m2len && !memcmp(cp, MARK_END, m2len)) {
244 buffer_put_char(&encoded, '\0');
245 break;
246 }
247 }
248 }
249 if (!len) {
250 debug("%s: no end marker", __func__);
251 goto out;
252 }
253 len = buffer_len(&encoded);
254 if ((cp = buffer_append_space(&copy, len)) == NULL) {
255 error("%s: buffer_append_space", __func__);
256 goto out;
257 }
258 if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) {
259 error("%s: uudecode failed", __func__);
260 goto out;
261 }
262 if ((u_int)dlen > len) {
263 error("%s: crazy uudecode length %d > %u", __func__, dlen, len);
264 goto out;
265 }
266 buffer_consume_end(&copy, len - dlen);
267 if (buffer_len(&copy) < sizeof(AUTH_MAGIC) ||
268 memcmp(buffer_ptr(&copy), AUTH_MAGIC, sizeof(AUTH_MAGIC))) {
269 error("%s: bad magic", __func__);
270 goto out;
271 }
272 buffer_consume(&copy, sizeof(AUTH_MAGIC));
273
274 ciphername = buffer_get_cstring_ret(&copy, NULL);
275 if (ciphername == NULL ||
276 (c = cipher_by_name(ciphername)) == NULL) {
277 error("%s: unknown cipher name", __func__);
278 goto out;
279 }
280 if ((passphrase == NULL || !strlen(passphrase)) &&
281 strcmp(ciphername, "none") != 0) {
282 /* passphrase required */
283 goto out;
284 }
285 kdfname = buffer_get_cstring_ret(&copy, NULL);
286 if (kdfname == NULL ||
Damien Miller38195192014-04-20 13:00:28 +1000287 (strcmp(kdfname, "none") != 0 && strcmp(kdfname, "bcrypt") != 0)) {
Damien Millerbcd00ab2013-12-07 10:41:55 +1100288 error("%s: unknown kdf name", __func__);
289 goto out;
290 }
291 if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) {
292 error("%s: cipher %s requires kdf", __func__, ciphername);
293 goto out;
294 }
295 /* kdf options */
296 kdfp = buffer_get_string_ptr_ret(&copy, &klen);
297 if (kdfp == NULL) {
298 error("%s: kdf options not set", __func__);
299 goto out;
300 }
301 if (klen > 0) {
302 if ((cp = buffer_append_space(&kdf, klen)) == NULL) {
303 error("%s: kdf alloc failed", __func__);
304 goto out;
305 }
306 memcpy(cp, kdfp, klen);
307 }
308 /* number of keys */
309 if (buffer_get_int_ret(&nkeys, &copy) < 0) {
310 error("%s: key counter missing", __func__);
311 goto out;
312 }
313 if (nkeys != 1) {
314 error("%s: only one key supported", __func__);
315 goto out;
316 }
317 /* pubkey */
318 if ((cp = buffer_get_string_ret(&copy, &len)) == NULL) {
319 error("%s: pubkey not found", __func__);
320 goto out;
321 }
322 free(cp); /* XXX check pubkey against decrypted private key */
323
324 /* size of encrypted key blob */
325 len = buffer_get_int(&copy);
326 blocksize = cipher_blocksize(c);
327 authlen = cipher_authlen(c);
328 if (len < blocksize) {
329 error("%s: encrypted data too small", __func__);
330 goto out;
331 }
332 if (len % blocksize) {
333 error("%s: length not multiple of blocksize", __func__);
334 goto out;
335 }
336
337 /* setup key */
338 keylen = cipher_keylen(c);
339 ivlen = cipher_ivlen(c);
340 key = xcalloc(1, keylen + ivlen);
341 if (!strcmp(kdfname, "bcrypt")) {
342 if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) {
343 error("%s: salt not set", __func__);
344 goto out;
345 }
346 if (buffer_get_int_ret(&rounds, &kdf) < 0) {
347 error("%s: rounds not set", __func__);
348 goto out;
349 }
350 if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen,
351 key, keylen + ivlen, rounds) < 0) {
352 error("%s: bcrypt_pbkdf failed", __func__);
353 goto out;
354 }
355 }
356
357 cp = buffer_append_space(&b, len);
358 cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0);
359 ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(&copy), len, 0, authlen);
360 cipher_cleanup(&ctx);
361 buffer_consume(&copy, len);
362
363 /* fail silently on decryption errors */
364 if (ret != 0) {
365 debug("%s: decrypt failed", __func__);
366 goto out;
367 }
368
369 if (buffer_len(&copy) != 0) {
370 error("%s: key blob has trailing data (len = %u)", __func__,
371 buffer_len(&copy));
372 goto out;
373 }
374
375 /* check bytes */
376 if (buffer_get_int_ret(&check1, &b) < 0 ||
377 buffer_get_int_ret(&check2, &b) < 0) {
378 error("check bytes missing");
379 goto out;
380 }
381 if (check1 != check2) {
382 debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__,
383 check1, check2);
384 goto out;
385 }
386
387 k = key_private_deserialize(&b);
388
389 /* comment */
390 comment = buffer_get_cstring_ret(&b, NULL);
391
392 i = 0;
393 while (buffer_len(&b)) {
394 if (buffer_get_char_ret(&pad, &b) == -1 ||
395 pad != (++i & 0xff)) {
396 error("%s: bad padding", __func__);
397 key_free(k);
398 k = NULL;
399 goto out;
400 }
401 }
402
403 if (k && commentp) {
404 *commentp = comment;
405 comment = NULL;
406 }
407
408 /* XXX decode pubkey and check against private */
409 out:
410 free(ciphername);
411 free(kdfname);
412 free(salt);
413 free(comment);
414 if (key)
Damien Millera5103f42014-02-04 11:20:14 +1100415 explicit_bzero(key, keylen + ivlen);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100416 free(key);
417 buffer_free(&encoded);
418 buffer_free(&copy);
419 buffer_free(&kdf);
420 buffer_free(&b);
421 return k;
422}
423
Damien Miller1f0311c2014-05-15 14:24:09 +1000424#ifdef WITH_SSH1
Damien Miller5428f641999-11-25 11:54:57 +1100425/*
Damien Millera2327922010-12-01 12:01:21 +1100426 * Serialises the authentication (private) key to a blob, encrypting it with
427 * passphrase. The identification of the blob (lowest 64 bits of n) will
Damien Miller5428f641999-11-25 11:54:57 +1100428 * precede the key to provide identification of the key without needing a
429 * passphrase.
430 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000431static int
Damien Millera2327922010-12-01 12:01:21 +1100432key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase,
Ben Lindstromd0fca422001-03-26 13:44:06 +0000433 const char *comment)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000434{
Damien Miller95def091999-11-25 00:26:21 +1100435 Buffer buffer, encrypted;
Damien Miller708d21c2002-01-22 23:18:15 +1100436 u_char buf[100], *cp;
Damien Millera2327922010-12-01 12:01:21 +1100437 int i, cipher_num;
Damien Miller874d77b2000-10-14 16:23:11 +1100438 CipherContext ciphercontext;
Damien Millerea111192013-04-23 19:24:32 +1000439 const Cipher *cipher;
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000440 u_int32_t rnd;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000441
Damien Miller5428f641999-11-25 11:54:57 +1100442 /*
443 * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting
444 * to another cipher; otherwise use SSH_AUTHFILE_CIPHER.
445 */
Damien Miller963f6b22002-02-19 15:21:23 +1100446 cipher_num = (strcmp(passphrase, "") == 0) ?
447 SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER;
448 if ((cipher = cipher_by_number(cipher_num)) == NULL)
Damien Miller874d77b2000-10-14 16:23:11 +1100449 fatal("save_private_key_rsa: bad cipher");
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000450
Damien Miller95def091999-11-25 00:26:21 +1100451 /* This buffer is used to built the secret part of the private key. */
452 buffer_init(&buffer);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000453
Damien Miller95def091999-11-25 00:26:21 +1100454 /* Put checkbytes for checking passphrase validity. */
Darren Tucker3f9fdc72004-06-22 12:56:01 +1000455 rnd = arc4random();
456 buf[0] = rnd & 0xff;
457 buf[1] = (rnd >> 8) & 0xff;
Damien Miller95def091999-11-25 00:26:21 +1100458 buf[2] = buf[0];
459 buf[3] = buf[1];
460 buffer_append(&buffer, buf, 4);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000461
Damien Miller5428f641999-11-25 11:54:57 +1100462 /*
463 * Store the private key (n and e will not be stored because they
464 * will be stored in plain text, and storing them also in encrypted
465 * format would just give known plaintext).
466 */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000467 buffer_put_bignum(&buffer, key->rsa->d);
468 buffer_put_bignum(&buffer, key->rsa->iqmp);
469 buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */
470 buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000471
Damien Miller95def091999-11-25 00:26:21 +1100472 /* Pad the part to be encrypted until its size is a multiple of 8. */
473 while (buffer_len(&buffer) % 8 != 0)
474 buffer_put_char(&buffer, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000475
Damien Miller95def091999-11-25 00:26:21 +1100476 /* This buffer will be used to contain the data in the file. */
477 buffer_init(&encrypted);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000478
Damien Miller95def091999-11-25 00:26:21 +1100479 /* First store keyfile id string. */
Ben Lindstrom1170d712001-01-29 07:51:26 +0000480 for (i = 0; authfile_id_string[i]; i++)
481 buffer_put_char(&encrypted, authfile_id_string[i]);
Damien Miller95def091999-11-25 00:26:21 +1100482 buffer_put_char(&encrypted, 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000483
Damien Miller95def091999-11-25 00:26:21 +1100484 /* Store cipher type. */
Damien Miller963f6b22002-02-19 15:21:23 +1100485 buffer_put_char(&encrypted, cipher_num);
Damien Miller95def091999-11-25 00:26:21 +1100486 buffer_put_int(&encrypted, 0); /* For future extension */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000487
Damien Miller95def091999-11-25 00:26:21 +1100488 /* Store public key. This will be in plain text. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000489 buffer_put_int(&encrypted, BN_num_bits(key->rsa->n));
490 buffer_put_bignum(&encrypted, key->rsa->n);
491 buffer_put_bignum(&encrypted, key->rsa->e);
Ben Lindstrom664408d2001-06-09 01:42:01 +0000492 buffer_put_cstring(&encrypted, comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000493
Damien Miller95def091999-11-25 00:26:21 +1100494 /* Allocate space for the private part of the key in the buffer. */
Damien Miller5a6b4fe2001-12-21 14:56:54 +1100495 cp = buffer_append_space(&encrypted, buffer_len(&buffer));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000496
Damien Miller963f6b22002-02-19 15:21:23 +1100497 cipher_set_key_string(&ciphercontext, cipher, passphrase,
498 CIPHER_ENCRYPT);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100499 if (cipher_crypt(&ciphercontext, 0, cp,
500 buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0)
501 fatal("%s: cipher_crypt failed", __func__);
Damien Miller963f6b22002-02-19 15:21:23 +1100502 cipher_cleanup(&ciphercontext);
Damien Millera5103f42014-02-04 11:20:14 +1100503 explicit_bzero(&ciphercontext, sizeof(ciphercontext));
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000504
Damien Miller95def091999-11-25 00:26:21 +1100505 /* Destroy temporary data. */
Damien Millera5103f42014-02-04 11:20:14 +1100506 explicit_bzero(buf, sizeof(buf));
Damien Miller95def091999-11-25 00:26:21 +1100507 buffer_free(&buffer);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000508
Damien Millera2327922010-12-01 12:01:21 +1100509 buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted));
Damien Miller95def091999-11-25 00:26:21 +1100510 buffer_free(&encrypted);
Damien Millera2327922010-12-01 12:01:21 +1100511
Damien Miller95def091999-11-25 00:26:21 +1100512 return 1;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000513}
Damien Miller1f0311c2014-05-15 14:24:09 +1000514#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000515
Damien Miller1f0311c2014-05-15 14:24:09 +1000516#ifdef WITH_OPENSSL
Damien Millera2327922010-12-01 12:01:21 +1100517/* convert SSH v2 key in OpenSSL PEM format */
Ben Lindstrombba81212001-06-25 05:01:22 +0000518static int
Damien Millera2327922010-12-01 12:01:21 +1100519key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase,
Ben Lindstromd0fca422001-03-26 13:44:06 +0000520 const char *comment)
Damien Millereba71ba2000-04-29 23:57:08 +1000521{
Damien Miller0bc1bd82000-11-13 22:57:25 +1100522 int success = 0;
Damien Millera2327922010-12-01 12:01:21 +1100523 int blen, len = strlen(_passphrase);
Ben Lindstrom90fd8142002-02-26 18:09:42 +0000524 u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL;
Darren Tuckerdf6578b2009-11-07 16:03:14 +1100525#if (OPENSSL_VERSION_NUMBER < 0x00907000L)
526 const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL;
527#else
Darren Tuckerdfb9b712009-10-24 11:46:43 +1100528 const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL;
Darren Tuckerdf6578b2009-11-07 16:03:14 +1100529#endif
Damien Millera2327922010-12-01 12:01:21 +1100530 const u_char *bptr;
531 BIO *bio;
Damien Millereba71ba2000-04-29 23:57:08 +1000532
533 if (len > 0 && len <= 4) {
Ben Lindstrom15f33862001-04-16 02:00:02 +0000534 error("passphrase too short: have %d bytes, need > 4", len);
Damien Millereba71ba2000-04-29 23:57:08 +1000535 return 0;
536 }
Damien Millera2327922010-12-01 12:01:21 +1100537 if ((bio = BIO_new(BIO_s_mem())) == NULL) {
538 error("%s: BIO_new failed", __func__);
Damien Millereba71ba2000-04-29 23:57:08 +1000539 return 0;
540 }
Damien Miller0bc1bd82000-11-13 22:57:25 +1100541 switch (key->type) {
Ben Lindstromc1116602001-03-29 00:28:37 +0000542 case KEY_DSA:
Damien Millera2327922010-12-01 12:01:21 +1100543 success = PEM_write_bio_DSAPrivateKey(bio, key->dsa,
Ben Lindstromc1116602001-03-29 00:28:37 +0000544 cipher, passphrase, len, NULL, NULL);
545 break;
Damien Miller6af914a2010-09-10 11:39:26 +1000546#ifdef OPENSSL_HAS_ECC
Damien Millereb8b60e2010-08-31 22:41:14 +1000547 case KEY_ECDSA:
Damien Millera2327922010-12-01 12:01:21 +1100548 success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa,
Damien Millereb8b60e2010-08-31 22:41:14 +1000549 cipher, passphrase, len, NULL, NULL);
550 break;
Damien Miller6af914a2010-09-10 11:39:26 +1000551#endif
Ben Lindstromc1116602001-03-29 00:28:37 +0000552 case KEY_RSA:
Damien Millera2327922010-12-01 12:01:21 +1100553 success = PEM_write_bio_RSAPrivateKey(bio, key->rsa,
Ben Lindstromc1116602001-03-29 00:28:37 +0000554 cipher, passphrase, len, NULL, NULL);
555 break;
Damien Millereba71ba2000-04-29 23:57:08 +1000556 }
Damien Millera2327922010-12-01 12:01:21 +1100557 if (success) {
558 if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0)
559 success = 0;
560 else
561 buffer_append(blob, bptr, blen);
562 }
563 BIO_free(bio);
Damien Millereba71ba2000-04-29 23:57:08 +1000564 return success;
565}
Damien Miller1f0311c2014-05-15 14:24:09 +1000566#endif
Damien Millereba71ba2000-04-29 23:57:08 +1000567
Damien Millera2327922010-12-01 12:01:21 +1100568/* Save a key blob to a file */
569static int
570key_save_private_blob(Buffer *keybuf, const char *filename)
571{
572 int fd;
573
574 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) {
575 error("open %s failed: %s.", filename, strerror(errno));
576 return 0;
577 }
578 if (atomicio(vwrite, fd, buffer_ptr(keybuf),
579 buffer_len(keybuf)) != buffer_len(keybuf)) {
580 error("write to key file %s failed: %s", filename,
581 strerror(errno));
582 close(fd);
583 unlink(filename);
584 return 0;
585 }
586 close(fd);
587 return 1;
588}
589
590/* Serialise "key" to buffer "blob" */
591static int
592key_private_to_blob(Key *key, Buffer *blob, const char *passphrase,
Damien Millerbcd00ab2013-12-07 10:41:55 +1100593 const char *comment, int force_new_format, const char *new_format_cipher,
594 int new_format_rounds)
Damien Millera2327922010-12-01 12:01:21 +1100595{
596 switch (key->type) {
Damien Miller1f0311c2014-05-15 14:24:09 +1000597#ifdef WITH_SSH1
Damien Millera2327922010-12-01 12:01:21 +1100598 case KEY_RSA1:
599 return key_private_rsa1_to_blob(key, blob, passphrase, comment);
Damien Miller1f0311c2014-05-15 14:24:09 +1000600#endif
601#ifdef WITH_OPENSSL
Damien Millera2327922010-12-01 12:01:21 +1100602 case KEY_DSA:
603 case KEY_ECDSA:
604 case KEY_RSA:
Damien Millerbcd00ab2013-12-07 10:41:55 +1100605 if (force_new_format) {
606 return key_private_to_blob2(key, blob, passphrase,
607 comment, new_format_cipher, new_format_rounds);
608 }
Damien Millera2327922010-12-01 12:01:21 +1100609 return key_private_pem_to_blob(key, blob, passphrase, comment);
Damien Miller1f0311c2014-05-15 14:24:09 +1000610#endif
Damien Miller5be9d9e2013-12-07 11:24:01 +1100611 case KEY_ED25519:
612 return key_private_to_blob2(key, blob, passphrase,
613 comment, new_format_cipher, new_format_rounds);
Damien Millera2327922010-12-01 12:01:21 +1100614 default:
615 error("%s: cannot save key type %d", __func__, key->type);
616 return 0;
617 }
618}
619
Damien Millereba71ba2000-04-29 23:57:08 +1000620int
Ben Lindstromd0fca422001-03-26 13:44:06 +0000621key_save_private(Key *key, const char *filename, const char *passphrase,
Damien Millerbcd00ab2013-12-07 10:41:55 +1100622 const char *comment, int force_new_format, const char *new_format_cipher,
623 int new_format_rounds)
Damien Millereba71ba2000-04-29 23:57:08 +1000624{
Damien Millera2327922010-12-01 12:01:21 +1100625 Buffer keyblob;
626 int success = 0;
627
628 buffer_init(&keyblob);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100629 if (!key_private_to_blob(key, &keyblob, passphrase, comment,
630 force_new_format, new_format_cipher, new_format_rounds))
Damien Millera2327922010-12-01 12:01:21 +1100631 goto out;
632 if (!key_save_private_blob(&keyblob, filename))
633 goto out;
634 success = 1;
635 out:
636 buffer_free(&keyblob);
637 return success;
638}
639
Damien Miller1f0311c2014-05-15 14:24:09 +1000640#ifdef WITH_SSH1
Damien Millera2327922010-12-01 12:01:21 +1100641/*
642 * Parse the public, unencrypted portion of a RSA1 key.
643 */
644static Key *
645key_parse_public_rsa1(Buffer *blob, char **commentp)
646{
647 Key *pub;
Damien Millere7ac2bd2011-06-20 14:23:25 +1000648 Buffer copy;
Damien Millera2327922010-12-01 12:01:21 +1100649
650 /* Check that it is at least big enough to contain the ID string. */
651 if (buffer_len(blob) < sizeof(authfile_id_string)) {
652 debug3("Truncated RSA1 identifier");
653 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000654 }
Damien Millera2327922010-12-01 12:01:21 +1100655
656 /*
657 * Make sure it begins with the id string. Consume the id string
658 * from the buffer.
659 */
660 if (memcmp(buffer_ptr(blob), authfile_id_string,
661 sizeof(authfile_id_string)) != 0) {
662 debug3("Incorrect RSA1 identifier");
663 return NULL;
664 }
Damien Millere7ac2bd2011-06-20 14:23:25 +1000665 buffer_init(&copy);
666 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
667 buffer_consume(&copy, sizeof(authfile_id_string));
Damien Millera2327922010-12-01 12:01:21 +1100668
669 /* Skip cipher type and reserved data. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000670 (void) buffer_get_char(&copy); /* cipher type */
671 (void) buffer_get_int(&copy); /* reserved */
Damien Millera2327922010-12-01 12:01:21 +1100672
673 /* Read the public key from the buffer. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000674 (void) buffer_get_int(&copy);
Damien Millera2327922010-12-01 12:01:21 +1100675 pub = key_new(KEY_RSA1);
Damien Millere7ac2bd2011-06-20 14:23:25 +1000676 buffer_get_bignum(&copy, pub->rsa->n);
677 buffer_get_bignum(&copy, pub->rsa->e);
Damien Millera2327922010-12-01 12:01:21 +1100678 if (commentp)
Damien Millere7ac2bd2011-06-20 14:23:25 +1000679 *commentp = buffer_get_string(&copy, NULL);
Damien Millera2327922010-12-01 12:01:21 +1100680 /* The encrypted private part is not parsed by this function. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000681 buffer_free(&copy);
Damien Millera2327922010-12-01 12:01:21 +1100682
683 return pub;
684}
Damien Miller1f0311c2014-05-15 14:24:09 +1000685#endif
Damien Millera2327922010-12-01 12:01:21 +1100686
Damien Miller2ce12ef2011-05-05 14:17:18 +1000687/* Load a key from a fd into a buffer */
688int
Damien Millera2327922010-12-01 12:01:21 +1100689key_load_file(int fd, const char *filename, Buffer *blob)
690{
Damien Miller2ce12ef2011-05-05 14:17:18 +1000691 u_char buf[1024];
Damien Millera2327922010-12-01 12:01:21 +1100692 size_t len;
Damien Millera2327922010-12-01 12:01:21 +1100693 struct stat st;
694
695 if (fstat(fd, &st) < 0) {
696 error("%s: fstat of key file %.200s%sfailed: %.100s", __func__,
697 filename == NULL ? "" : filename,
698 filename == NULL ? "" : " ",
699 strerror(errno));
Damien Millera2327922010-12-01 12:01:21 +1100700 return 0;
701 }
Damien Miller2ce12ef2011-05-05 14:17:18 +1000702 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
703 st.st_size > MAX_KEY_FILE_SIZE) {
704 toobig:
Damien Millera2327922010-12-01 12:01:21 +1100705 error("%s: key file %.200s%stoo large", __func__,
706 filename == NULL ? "" : filename,
707 filename == NULL ? "" : " ");
Damien Millera2327922010-12-01 12:01:21 +1100708 return 0;
709 }
Damien Miller5d007702012-02-11 08:19:02 +1100710 buffer_clear(blob);
Damien Miller2ce12ef2011-05-05 14:17:18 +1000711 for (;;) {
712 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
713 if (errno == EPIPE)
714 break;
715 debug("%s: read from key file %.200s%sfailed: %.100s",
716 __func__, filename == NULL ? "" : filename,
717 filename == NULL ? "" : " ", strerror(errno));
718 buffer_clear(blob);
Damien Miller1d2c4562014-02-04 11:18:20 +1100719 explicit_bzero(buf, sizeof(buf));
Damien Miller2ce12ef2011-05-05 14:17:18 +1000720 return 0;
721 }
722 buffer_append(blob, buf, len);
723 if (buffer_len(blob) > MAX_KEY_FILE_SIZE) {
724 buffer_clear(blob);
Damien Miller1d2c4562014-02-04 11:18:20 +1100725 explicit_bzero(buf, sizeof(buf));
Damien Miller2ce12ef2011-05-05 14:17:18 +1000726 goto toobig;
727 }
728 }
Damien Miller1d2c4562014-02-04 11:18:20 +1100729 explicit_bzero(buf, sizeof(buf));
Damien Miller2ce12ef2011-05-05 14:17:18 +1000730 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
731 st.st_size != buffer_len(blob)) {
732 debug("%s: key file %.200s%schanged size while reading",
733 __func__, filename == NULL ? "" : filename,
734 filename == NULL ? "" : " ");
Damien Millera2327922010-12-01 12:01:21 +1100735 buffer_clear(blob);
Damien Millera2327922010-12-01 12:01:21 +1100736 return 0;
737 }
Damien Miller2ce12ef2011-05-05 14:17:18 +1000738
Damien Millera2327922010-12-01 12:01:21 +1100739 return 1;
Damien Millereba71ba2000-04-29 23:57:08 +1000740}
741
Damien Miller1f0311c2014-05-15 14:24:09 +1000742#ifdef WITH_SSH1
Damien Miller5428f641999-11-25 11:54:57 +1100743/*
Ben Lindstromd0fca422001-03-26 13:44:06 +0000744 * Loads the public part of the ssh v1 key file. Returns NULL if an error was
745 * encountered (the file does not exist or is not readable), and the key
Damien Miller5428f641999-11-25 11:54:57 +1100746 * otherwise.
747 */
Ben Lindstrombba81212001-06-25 05:01:22 +0000748static Key *
Ben Lindstromd0fca422001-03-26 13:44:06 +0000749key_load_public_rsa1(int fd, const char *filename, char **commentp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000750{
Damien Miller95def091999-11-25 00:26:21 +1100751 Buffer buffer;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000752 Key *pub;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000753
Damien Miller95def091999-11-25 00:26:21 +1100754 buffer_init(&buffer);
Damien Millera2327922010-12-01 12:01:21 +1100755 if (!key_load_file(fd, filename, &buffer)) {
Damien Miller95def091999-11-25 00:26:21 +1100756 buffer_free(&buffer);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000757 return NULL;
Damien Miller95def091999-11-25 00:26:21 +1100758 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000759
Damien Millera2327922010-12-01 12:01:21 +1100760 pub = key_parse_public_rsa1(&buffer, commentp);
761 if (pub == NULL)
762 debug3("Could not load \"%s\" as a RSA1 public key", filename);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000763 buffer_free(&buffer);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000764 return pub;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000765}
766
Ben Lindstromd0fca422001-03-26 13:44:06 +0000767/* load public key from private-key file, works only for SSH v1 */
768Key *
769key_load_public_type(int type, const char *filename, char **commentp)
Damien Millereba71ba2000-04-29 23:57:08 +1000770{
Ben Lindstromd0fca422001-03-26 13:44:06 +0000771 Key *pub;
772 int fd;
773
774 if (type == KEY_RSA1) {
775 fd = open(filename, O_RDONLY);
776 if (fd < 0)
777 return NULL;
778 pub = key_load_public_rsa1(fd, filename, commentp);
779 close(fd);
780 return pub;
Damien Millereba71ba2000-04-29 23:57:08 +1000781 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000782 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000783}
784
Ben Lindstrombba81212001-06-25 05:01:22 +0000785static Key *
Damien Millera2327922010-12-01 12:01:21 +1100786key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000787{
Damien Millereccb9de2005-06-17 12:59:34 +1000788 int check1, check2, cipher_type;
Damien Millera2327922010-12-01 12:01:21 +1100789 Buffer decrypted;
Damien Miller708d21c2002-01-22 23:18:15 +1100790 u_char *cp;
Damien Miller874d77b2000-10-14 16:23:11 +1100791 CipherContext ciphercontext;
Damien Millerea111192013-04-23 19:24:32 +1000792 const Cipher *cipher;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000793 Key *prv = NULL;
Damien Millere7ac2bd2011-06-20 14:23:25 +1000794 Buffer copy;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000795
Ben Lindstrom1170d712001-01-29 07:51:26 +0000796 /* Check that it is at least big enough to contain the ID string. */
Damien Millera2327922010-12-01 12:01:21 +1100797 if (buffer_len(blob) < sizeof(authfile_id_string)) {
798 debug3("Truncated RSA1 identifier");
Ben Lindstromd0fca422001-03-26 13:44:06 +0000799 return NULL;
Damien Miller95def091999-11-25 00:26:21 +1100800 }
Damien Millera2327922010-12-01 12:01:21 +1100801
Damien Miller5428f641999-11-25 11:54:57 +1100802 /*
803 * Make sure it begins with the id string. Consume the id string
804 * from the buffer.
805 */
Damien Millera2327922010-12-01 12:01:21 +1100806 if (memcmp(buffer_ptr(blob), authfile_id_string,
807 sizeof(authfile_id_string)) != 0) {
808 debug3("Incorrect RSA1 identifier");
809 return NULL;
810 }
Damien Millere7ac2bd2011-06-20 14:23:25 +1000811 buffer_init(&copy);
812 buffer_append(&copy, buffer_ptr(blob), buffer_len(blob));
813 buffer_consume(&copy, sizeof(authfile_id_string));
Ben Lindstromb257cca2001-03-05 04:59:27 +0000814
Damien Miller95def091999-11-25 00:26:21 +1100815 /* Read cipher type. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000816 cipher_type = buffer_get_char(&copy);
817 (void) buffer_get_int(&copy); /* Reserved data. */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000818
Damien Miller95def091999-11-25 00:26:21 +1100819 /* Read the public key from the buffer. */
Damien Millere7ac2bd2011-06-20 14:23:25 +1000820 (void) buffer_get_int(&copy);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000821 prv = key_new_private(KEY_RSA1);
822
Damien Millere7ac2bd2011-06-20 14:23:25 +1000823 buffer_get_bignum(&copy, prv->rsa->n);
824 buffer_get_bignum(&copy, prv->rsa->e);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000825 if (commentp)
Damien Millere7ac2bd2011-06-20 14:23:25 +1000826 *commentp = buffer_get_string(&copy, NULL);
Damien Miller95def091999-11-25 00:26:21 +1100827 else
Damien Millere7ac2bd2011-06-20 14:23:25 +1000828 (void)buffer_get_string_ptr(&copy, NULL);
Damien Miller95def091999-11-25 00:26:21 +1100829
830 /* Check that it is a supported cipher. */
Damien Miller874d77b2000-10-14 16:23:11 +1100831 cipher = cipher_by_number(cipher_type);
832 if (cipher == NULL) {
Damien Millera2327922010-12-01 12:01:21 +1100833 debug("Unsupported RSA1 cipher %d", cipher_type);
Damien Millere7ac2bd2011-06-20 14:23:25 +1000834 buffer_free(&copy);
Damien Miller95def091999-11-25 00:26:21 +1100835 goto fail;
836 }
837 /* Initialize space for decrypted data. */
838 buffer_init(&decrypted);
Damien Millere7ac2bd2011-06-20 14:23:25 +1000839 cp = buffer_append_space(&decrypted, buffer_len(&copy));
Damien Miller95def091999-11-25 00:26:21 +1100840
841 /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */
Damien Miller963f6b22002-02-19 15:21:23 +1100842 cipher_set_key_string(&ciphercontext, cipher, passphrase,
843 CIPHER_DECRYPT);
Damien Millerbcd00ab2013-12-07 10:41:55 +1100844 if (cipher_crypt(&ciphercontext, 0, cp,
845 buffer_ptr(&copy), buffer_len(&copy), 0, 0) != 0)
846 fatal("%s: cipher_crypt failed", __func__);
Damien Miller963f6b22002-02-19 15:21:23 +1100847 cipher_cleanup(&ciphercontext);
Damien Millera5103f42014-02-04 11:20:14 +1100848 explicit_bzero(&ciphercontext, sizeof(ciphercontext));
Damien Millere7ac2bd2011-06-20 14:23:25 +1000849 buffer_free(&copy);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000850
Damien Miller95def091999-11-25 00:26:21 +1100851 check1 = buffer_get_char(&decrypted);
852 check2 = buffer_get_char(&decrypted);
853 if (check1 != buffer_get_char(&decrypted) ||
854 check2 != buffer_get_char(&decrypted)) {
855 if (strcmp(passphrase, "") != 0)
Damien Millera2327922010-12-01 12:01:21 +1100856 debug("Bad passphrase supplied for RSA1 key");
Damien Miller95def091999-11-25 00:26:21 +1100857 /* Bad passphrase. */
858 buffer_free(&decrypted);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000859 goto fail;
Damien Miller95def091999-11-25 00:26:21 +1100860 }
861 /* Read the rest of the private key. */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000862 buffer_get_bignum(&decrypted, prv->rsa->d);
863 buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */
864 /* in SSL and SSH v1 p and q are exchanged */
865 buffer_get_bignum(&decrypted, prv->rsa->q); /* p */
866 buffer_get_bignum(&decrypted, prv->rsa->p); /* q */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000867
Ben Lindstromd0fca422001-03-26 13:44:06 +0000868 /* calculate p-1 and q-1 */
Damien Millerda755162002-01-22 23:09:22 +1100869 rsa_generate_additional_parameters(prv->rsa);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000870
Damien Miller95def091999-11-25 00:26:21 +1100871 buffer_free(&decrypted);
Damien Millered33d3b2003-03-15 11:36:18 +1100872
873 /* enable blinding */
874 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
Damien Millera2327922010-12-01 12:01:21 +1100875 error("%s: RSA_blinding_on failed", __func__);
Damien Millered33d3b2003-03-15 11:36:18 +1100876 goto fail;
877 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000878 return prv;
879
880fail:
Darren Tuckera627d422013-06-02 07:31:17 +1000881 if (commentp != NULL)
882 free(*commentp);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000883 key_free(prv);
884 return NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000885}
Damien Miller1f0311c2014-05-15 14:24:09 +1000886#endif
Damien Millereba71ba2000-04-29 23:57:08 +1000887
Damien Miller1f0311c2014-05-15 14:24:09 +1000888#ifdef WITH_OPENSSL
Damien Millera2327922010-12-01 12:01:21 +1100889static Key *
890key_parse_private_pem(Buffer *blob, int type, const char *passphrase,
Ben Lindstromd0fca422001-03-26 13:44:06 +0000891 char **commentp)
Damien Millereba71ba2000-04-29 23:57:08 +1000892{
Damien Miller0bc1bd82000-11-13 22:57:25 +1100893 EVP_PKEY *pk = NULL;
Ben Lindstromd0fca422001-03-26 13:44:06 +0000894 Key *prv = NULL;
Damien Miller0bc1bd82000-11-13 22:57:25 +1100895 char *name = "<no key>";
Damien Millera2327922010-12-01 12:01:21 +1100896 BIO *bio;
Damien Millereba71ba2000-04-29 23:57:08 +1000897
Damien Millera2327922010-12-01 12:01:21 +1100898 if ((bio = BIO_new_mem_buf(buffer_ptr(blob),
899 buffer_len(blob))) == NULL) {
900 error("%s: BIO_new_mem_buf failed", __func__);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000901 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +1000902 }
Damien Millera2327922010-12-01 12:01:21 +1100903
904 pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase);
905 BIO_free(bio);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100906 if (pk == NULL) {
Damien Millera2327922010-12-01 12:01:21 +1100907 debug("%s: PEM_read_PrivateKey failed", __func__);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100908 (void)ERR_get_error();
Ben Lindstromd0fca422001-03-26 13:44:06 +0000909 } else if (pk->type == EVP_PKEY_RSA &&
Damien Miller9f0f5c62001-12-21 14:45:46 +1100910 (type == KEY_UNSPEC||type==KEY_RSA)) {
Ben Lindstromd0fca422001-03-26 13:44:06 +0000911 prv = key_new(KEY_UNSPEC);
912 prv->rsa = EVP_PKEY_get1_RSA(pk);
913 prv->type = KEY_RSA;
914 name = "rsa w/o comment";
Damien Miller0bc1bd82000-11-13 22:57:25 +1100915#ifdef DEBUG_PK
Ben Lindstromd0fca422001-03-26 13:44:06 +0000916 RSA_print_fp(stderr, prv->rsa, 8);
Damien Millereba71ba2000-04-29 23:57:08 +1000917#endif
Damien Millered33d3b2003-03-15 11:36:18 +1100918 if (RSA_blinding_on(prv->rsa, NULL) != 1) {
Damien Millera2327922010-12-01 12:01:21 +1100919 error("%s: RSA_blinding_on failed", __func__);
Damien Millered33d3b2003-03-15 11:36:18 +1100920 key_free(prv);
921 prv = NULL;
922 }
Ben Lindstromd0fca422001-03-26 13:44:06 +0000923 } else if (pk->type == EVP_PKEY_DSA &&
Damien Miller9f0f5c62001-12-21 14:45:46 +1100924 (type == KEY_UNSPEC||type==KEY_DSA)) {
Ben Lindstromd0fca422001-03-26 13:44:06 +0000925 prv = key_new(KEY_UNSPEC);
926 prv->dsa = EVP_PKEY_get1_DSA(pk);
927 prv->type = KEY_DSA;
928 name = "dsa w/o comment";
Damien Miller0bc1bd82000-11-13 22:57:25 +1100929#ifdef DEBUG_PK
Ben Lindstromd0fca422001-03-26 13:44:06 +0000930 DSA_print_fp(stderr, prv->dsa, 8);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100931#endif
Damien Miller6af914a2010-09-10 11:39:26 +1000932#ifdef OPENSSL_HAS_ECC
Damien Millereb8b60e2010-08-31 22:41:14 +1000933 } else if (pk->type == EVP_PKEY_EC &&
934 (type == KEY_UNSPEC||type==KEY_ECDSA)) {
935 prv = key_new(KEY_UNSPEC);
936 prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk);
937 prv->type = KEY_ECDSA;
Damien Millerb472a902010-11-05 10:19:49 +1100938 if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 ||
939 key_curve_nid_to_name(prv->ecdsa_nid) == NULL ||
940 key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa),
Damien Millereb8b60e2010-08-31 22:41:14 +1000941 EC_KEY_get0_public_key(prv->ecdsa)) != 0 ||
942 key_ec_validate_private(prv->ecdsa) != 0) {
943 error("%s: bad ECDSA key", __func__);
944 key_free(prv);
945 prv = NULL;
946 }
Damien Millerbf0423e2010-09-10 11:20:38 +1000947 name = "ecdsa w/o comment";
Damien Millereb8b60e2010-08-31 22:41:14 +1000948#ifdef DEBUG_PK
Damien Millerb472a902010-11-05 10:19:49 +1100949 if (prv != NULL && prv->ecdsa != NULL)
Damien Millereb8b60e2010-08-31 22:41:14 +1000950 key_dump_ec_key(prv->ecdsa);
951#endif
Damien Miller6af914a2010-09-10 11:39:26 +1000952#endif /* OPENSSL_HAS_ECC */
Damien Miller0bc1bd82000-11-13 22:57:25 +1100953 } else {
Damien Millera2327922010-12-01 12:01:21 +1100954 error("%s: PEM_read_PrivateKey: mismatch or "
955 "unknown EVP_PKEY save_type %d", __func__, pk->save_type);
Damien Miller0bc1bd82000-11-13 22:57:25 +1100956 }
Damien Miller0bc1bd82000-11-13 22:57:25 +1100957 if (pk != NULL)
958 EVP_PKEY_free(pk);
Ben Lindstromd0fca422001-03-26 13:44:06 +0000959 if (prv != NULL && commentp)
960 *commentp = xstrdup(name);
961 debug("read PEM private key done: type %s",
962 prv ? key_type(prv) : "<unknown>");
963 return prv;
Damien Millereba71ba2000-04-29 23:57:08 +1000964}
965
Damien Millera2327922010-12-01 12:01:21 +1100966Key *
967key_load_private_pem(int fd, int type, const char *passphrase,
968 char **commentp)
969{
970 Buffer buffer;
971 Key *prv;
972
973 buffer_init(&buffer);
974 if (!key_load_file(fd, NULL, &buffer)) {
975 buffer_free(&buffer);
976 return NULL;
977 }
978 prv = key_parse_private_pem(&buffer, type, passphrase, commentp);
979 buffer_free(&buffer);
980 return prv;
981}
Damien Miller1f0311c2014-05-15 14:24:09 +1000982#endif
Damien Millera2327922010-12-01 12:01:21 +1100983
Damien Miller8275fad2006-03-15 12:06:23 +1100984int
Ben Lindstromd0fca422001-03-26 13:44:06 +0000985key_perm_ok(int fd, const char *filename)
Damien Millereba71ba2000-04-29 23:57:08 +1000986{
Damien Millereba71ba2000-04-29 23:57:08 +1000987 struct stat st;
988
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000989 if (fstat(fd, &st) < 0)
990 return 0;
991 /*
992 * if a key owned by the user is accessed, then we check the
993 * permissions of the file. if the key owned by a different user,
994 * then we don't care.
995 */
Damien Millerb70b61f2000-09-16 16:25:12 +1100996#ifdef HAVE_CYGWIN
Damien Millercb5e44a2000-09-29 12:12:36 +1100997 if (check_ntsec(filename))
Damien Millerb70b61f2000-09-16 16:25:12 +1100998#endif
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000999 if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
Damien Millereba71ba2000-04-29 23:57:08 +10001000 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
1001 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
1002 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
Ben Lindstrom7aff2612001-09-23 13:53:22 +00001003 error("Permissions 0%3.3o for '%s' are too open.",
Damien Miller04bd8b02003-05-25 14:38:33 +10001004 (u_int)st.st_mode & 0777, filename);
Damien Millera10abe92011-04-12 15:39:35 +10001005 error("It is required that your private key files are NOT accessible by others.");
Ben Lindstromd0fca422001-03-26 13:44:06 +00001006 error("This private key will be ignored.");
Damien Millereba71ba2000-04-29 23:57:08 +10001007 return 0;
1008 }
Ben Lindstromd0fca422001-03-26 13:44:06 +00001009 return 1;
1010}
Ben Lindstromb257cca2001-03-05 04:59:27 +00001011
Damien Millera2327922010-12-01 12:01:21 +11001012static Key *
1013key_parse_private_type(Buffer *blob, int type, const char *passphrase,
1014 char **commentp)
1015{
Damien Millerbcd00ab2013-12-07 10:41:55 +11001016 Key *k;
1017
Damien Millera2327922010-12-01 12:01:21 +11001018 switch (type) {
Damien Miller1f0311c2014-05-15 14:24:09 +10001019#ifdef WITH_SSH1
Damien Millera2327922010-12-01 12:01:21 +11001020 case KEY_RSA1:
1021 return key_parse_private_rsa1(blob, passphrase, commentp);
Damien Miller1f0311c2014-05-15 14:24:09 +10001022#endif
1023#ifdef WITH_OPENSSL
Damien Millera2327922010-12-01 12:01:21 +11001024 case KEY_DSA:
1025 case KEY_ECDSA:
1026 case KEY_RSA:
Damien Miller5be9d9e2013-12-07 11:24:01 +11001027 return key_parse_private_pem(blob, type, passphrase, commentp);
Damien Miller1f0311c2014-05-15 14:24:09 +10001028#endif
Damien Miller5be9d9e2013-12-07 11:24:01 +11001029 case KEY_ED25519:
1030 return key_parse_private2(blob, type, passphrase, commentp);
Damien Millera2327922010-12-01 12:01:21 +11001031 case KEY_UNSPEC:
Damien Millerbcd00ab2013-12-07 10:41:55 +11001032 if ((k = key_parse_private2(blob, type, passphrase, commentp)))
1033 return k;
Damien Miller1f0311c2014-05-15 14:24:09 +10001034#ifdef WITH_OPENSSL
Damien Millera2327922010-12-01 12:01:21 +11001035 return key_parse_private_pem(blob, type, passphrase, commentp);
Damien Miller1f0311c2014-05-15 14:24:09 +10001036#endif
Damien Millera2327922010-12-01 12:01:21 +11001037 default:
Damien Miller9d276b82011-05-15 08:51:43 +10001038 error("%s: cannot parse key type %d", __func__, type);
Damien Millera2327922010-12-01 12:01:21 +11001039 break;
1040 }
1041 return NULL;
1042}
1043
Ben Lindstromd0fca422001-03-26 13:44:06 +00001044Key *
1045key_load_private_type(int type, const char *filename, const char *passphrase,
Darren Tucker232b76f2006-05-06 17:41:51 +10001046 char **commentp, int *perm_ok)
Ben Lindstromd0fca422001-03-26 13:44:06 +00001047{
1048 int fd;
Damien Millera2327922010-12-01 12:01:21 +11001049 Key *ret;
1050 Buffer buffer;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001051
1052 fd = open(filename, O_RDONLY);
Darren Tuckerd4c86b12010-01-12 19:41:22 +11001053 if (fd < 0) {
1054 debug("could not open key file '%s': %s", filename,
1055 strerror(errno));
1056 if (perm_ok != NULL)
1057 *perm_ok = 0;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001058 return NULL;
Darren Tucker69c01b12010-01-12 19:42:29 +11001059 }
Ben Lindstromd0fca422001-03-26 13:44:06 +00001060 if (!key_perm_ok(fd, filename)) {
Darren Tucker232b76f2006-05-06 17:41:51 +10001061 if (perm_ok != NULL)
1062 *perm_ok = 0;
Ben Lindstrom15f33862001-04-16 02:00:02 +00001063 error("bad permissions: ignore key: %s", filename);
Ben Lindstromd0fca422001-03-26 13:44:06 +00001064 close(fd);
1065 return NULL;
1066 }
Darren Tucker232b76f2006-05-06 17:41:51 +10001067 if (perm_ok != NULL)
1068 *perm_ok = 1;
Damien Millera2327922010-12-01 12:01:21 +11001069
1070 buffer_init(&buffer);
1071 if (!key_load_file(fd, filename, &buffer)) {
1072 buffer_free(&buffer);
Ben Lindstromb257cca2001-03-05 04:59:27 +00001073 close(fd);
Damien Millera2327922010-12-01 12:01:21 +11001074 return NULL;
Damien Millereba71ba2000-04-29 23:57:08 +10001075 }
Damien Millera2327922010-12-01 12:01:21 +11001076 close(fd);
1077 ret = key_parse_private_type(&buffer, type, passphrase, commentp);
1078 buffer_free(&buffer);
1079 return ret;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001080}
1081
1082Key *
Damien Miller2ce12ef2011-05-05 14:17:18 +10001083key_parse_private(Buffer *buffer, const char *filename,
1084 const char *passphrase, char **commentp)
1085{
Damien Miller1f0311c2014-05-15 14:24:09 +10001086#ifdef WITH_SSH1
Damien Miller2ce12ef2011-05-05 14:17:18 +10001087 Key *pub, *prv;
Damien Miller2ce12ef2011-05-05 14:17:18 +10001088
Damien Miller2ce12ef2011-05-05 14:17:18 +10001089 /* it's a SSH v1 key if the public key part is readable */
Damien Millere7ac2bd2011-06-20 14:23:25 +10001090 pub = key_parse_public_rsa1(buffer, commentp);
Damien Miller2ce12ef2011-05-05 14:17:18 +10001091 if (pub == NULL) {
1092 prv = key_parse_private_type(buffer, KEY_UNSPEC,
1093 passphrase, NULL);
1094 /* use the filename as a comment for PEM */
1095 if (commentp && prv)
1096 *commentp = xstrdup(filename);
1097 } else {
1098 key_free(pub);
1099 /* key_parse_public_rsa1() has already loaded the comment */
1100 prv = key_parse_private_type(buffer, KEY_RSA1, passphrase,
1101 NULL);
1102 }
1103 return prv;
Damien Miller1f0311c2014-05-15 14:24:09 +10001104#else
1105 return key_parse_private_type(buffer, KEY_UNSPEC,
1106 passphrase, commentp);
1107#endif
Damien Miller2ce12ef2011-05-05 14:17:18 +10001108}
1109
1110Key *
Ben Lindstromd0fca422001-03-26 13:44:06 +00001111key_load_private(const char *filename, const char *passphrase,
1112 char **commentp)
1113{
Damien Miller2ce12ef2011-05-05 14:17:18 +10001114 Key *prv;
1115 Buffer buffer;
Ben Lindstromd0fca422001-03-26 13:44:06 +00001116 int fd;
1117
1118 fd = open(filename, O_RDONLY);
Darren Tuckerd4c86b12010-01-12 19:41:22 +11001119 if (fd < 0) {
1120 debug("could not open key file '%s': %s", filename,
1121 strerror(errno));
Ben Lindstromd0fca422001-03-26 13:44:06 +00001122 return NULL;
Darren Tuckerd4c86b12010-01-12 19:41:22 +11001123 }
Ben Lindstromd0fca422001-03-26 13:44:06 +00001124 if (!key_perm_ok(fd, filename)) {
Ben Lindstrom15f33862001-04-16 02:00:02 +00001125 error("bad permissions: ignore key: %s", filename);
Ben Lindstromd0fca422001-03-26 13:44:06 +00001126 close(fd);
1127 return NULL;
1128 }
Damien Millera2327922010-12-01 12:01:21 +11001129
1130 buffer_init(&buffer);
1131 if (!key_load_file(fd, filename, &buffer)) {
1132 buffer_free(&buffer);
1133 close(fd);
1134 return NULL;
1135 }
1136 close(fd);
1137
Damien Miller2ce12ef2011-05-05 14:17:18 +10001138 prv = key_parse_private(&buffer, filename, passphrase, commentp);
Damien Millera2327922010-12-01 12:01:21 +11001139 buffer_free(&buffer);
Ben Lindstrom322915d2001-06-05 20:46:32 +00001140 return prv;
Damien Millereba71ba2000-04-29 23:57:08 +10001141}
Damien Millere4340be2000-09-16 13:29:08 +11001142
Ben Lindstrombba81212001-06-25 05:01:22 +00001143static int
Ben Lindstromd0fca422001-03-26 13:44:06 +00001144key_try_load_public(Key *k, const char *filename, char **commentp)
Damien Millere4340be2000-09-16 13:29:08 +11001145{
1146 FILE *f;
Darren Tucker22cc7412004-12-06 22:47:41 +11001147 char line[SSH_MAX_PUBKEY_BYTES];
Damien Millere4340be2000-09-16 13:29:08 +11001148 char *cp;
Darren Tuckerf0f90982004-12-11 13:39:50 +11001149 u_long linenum = 0;
Damien Millere4340be2000-09-16 13:29:08 +11001150
1151 f = fopen(filename, "r");
1152 if (f != NULL) {
Darren Tucker22cc7412004-12-06 22:47:41 +11001153 while (read_keyfile_line(f, filename, line, sizeof(line),
1154 &linenum) != -1) {
Damien Millere4340be2000-09-16 13:29:08 +11001155 cp = line;
Ben Lindstrom1c37c6a2001-12-06 18:00:18 +00001156 switch (*cp) {
Damien Millere4340be2000-09-16 13:29:08 +11001157 case '#':
1158 case '\n':
1159 case '\0':
1160 continue;
1161 }
Damien Miller32198242011-05-15 08:50:32 +10001162 /* Abort loading if this looks like a private key */
1163 if (strncmp(cp, "-----BEGIN", 10) == 0)
1164 break;
Damien Millere4340be2000-09-16 13:29:08 +11001165 /* Skip leading whitespace. */
1166 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
1167 ;
1168 if (*cp) {
Damien Miller0bc1bd82000-11-13 22:57:25 +11001169 if (key_read(k, &cp) == 1) {
Damien Miller04bb56e2011-05-29 21:42:08 +10001170 cp[strcspn(cp, "\r\n")] = '\0';
1171 if (commentp) {
1172 *commentp = xstrdup(*cp ?
1173 cp : filename);
1174 }
Damien Millere4340be2000-09-16 13:29:08 +11001175 fclose(f);
1176 return 1;
1177 }
1178 }
1179 }
1180 fclose(f);
1181 }
1182 return 0;
1183}
1184
Ben Lindstromd0fca422001-03-26 13:44:06 +00001185/* load public key from ssh v1 private or any pubkey file */
1186Key *
1187key_load_public(const char *filename, char **commentp)
Damien Millere4340be2000-09-16 13:29:08 +11001188{
Ben Lindstromd0fca422001-03-26 13:44:06 +00001189 Key *pub;
1190 char file[MAXPATHLEN];
Damien Millere4340be2000-09-16 13:29:08 +11001191
Damien Miller1f0311c2014-05-15 14:24:09 +10001192#ifdef WITH_SSH1
Damien Millerdb274722003-05-14 13:45:22 +10001193 /* try rsa1 private key */
Ben Lindstromd0fca422001-03-26 13:44:06 +00001194 pub = key_load_public_type(KEY_RSA1, filename, commentp);
1195 if (pub != NULL)
1196 return pub;
Damien Millerdb274722003-05-14 13:45:22 +10001197
1198 /* try rsa1 public key */
1199 pub = key_new(KEY_RSA1);
1200 if (key_try_load_public(pub, filename, commentp) == 1)
1201 return pub;
1202 key_free(pub);
Damien Miller1f0311c2014-05-15 14:24:09 +10001203#endif
Damien Millerdb274722003-05-14 13:45:22 +10001204
1205 /* try ssh2 public key */
Ben Lindstromd0fca422001-03-26 13:44:06 +00001206 pub = key_new(KEY_UNSPEC);
1207 if (key_try_load_public(pub, filename, commentp) == 1)
1208 return pub;
1209 if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
1210 (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
1211 (key_try_load_public(pub, file, commentp) == 1))
1212 return pub;
1213 key_free(pub);
1214 return NULL;
Damien Millere4340be2000-09-16 13:29:08 +11001215}
Damien Miller1aed65e2010-03-04 21:53:35 +11001216
Damien Millerc1583312010-08-05 13:04:50 +10001217/* Load the certificate associated with the named private key */
1218Key *
1219key_load_cert(const char *filename)
1220{
1221 Key *pub;
Damien Miller5458c4d2010-08-05 13:05:15 +10001222 char *file;
Damien Millerc1583312010-08-05 13:04:50 +10001223
1224 pub = key_new(KEY_UNSPEC);
Damien Miller5458c4d2010-08-05 13:05:15 +10001225 xasprintf(&file, "%s-cert.pub", filename);
1226 if (key_try_load_public(pub, file, NULL) == 1) {
Darren Tuckera627d422013-06-02 07:31:17 +10001227 free(file);
Damien Millerc1583312010-08-05 13:04:50 +10001228 return pub;
Damien Miller5458c4d2010-08-05 13:05:15 +10001229 }
Darren Tuckera627d422013-06-02 07:31:17 +10001230 free(file);
Damien Millerc1583312010-08-05 13:04:50 +10001231 key_free(pub);
1232 return NULL;
1233}
1234
1235/* Load private key and certificate */
1236Key *
1237key_load_private_cert(int type, const char *filename, const char *passphrase,
1238 int *perm_ok)
1239{
1240 Key *key, *pub;
1241
1242 switch (type) {
Damien Miller1f0311c2014-05-15 14:24:09 +10001243#ifdef WITH_OPENSSL
Damien Millerc1583312010-08-05 13:04:50 +10001244 case KEY_RSA:
1245 case KEY_DSA:
Damien Millereb8b60e2010-08-31 22:41:14 +10001246 case KEY_ECDSA:
Damien Miller1f0311c2014-05-15 14:24:09 +10001247#endif
Damien Millerb9a95492013-12-29 17:50:15 +11001248 case KEY_ED25519:
Damien Millerc1583312010-08-05 13:04:50 +10001249 break;
1250 default:
1251 error("%s: unsupported key type", __func__);
1252 return NULL;
1253 }
1254
1255 if ((key = key_load_private_type(type, filename,
1256 passphrase, NULL, perm_ok)) == NULL)
1257 return NULL;
1258
1259 if ((pub = key_load_cert(filename)) == NULL) {
1260 key_free(key);
1261 return NULL;
1262 }
1263
1264 /* Make sure the private key matches the certificate */
1265 if (key_equal_public(key, pub) == 0) {
1266 error("%s: certificate does not match private key %s",
1267 __func__, filename);
1268 } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) {
1269 error("%s: key_to_certified failed", __func__);
1270 } else {
1271 key_cert_copy(pub, key);
1272 key_free(pub);
1273 return key;
1274 }
1275
1276 key_free(key);
1277 key_free(pub);
1278 return NULL;
1279}
1280
Damien Miller1aed65e2010-03-04 21:53:35 +11001281/*
1282 * Returns 1 if the specified "key" is listed in the file "filename",
1283 * 0 if the key is not listed or -1 on error.
1284 * If strict_type is set then the key type must match exactly,
1285 * otherwise a comparison that ignores certficiate data is performed.
1286 */
1287int
1288key_in_file(Key *key, const char *filename, int strict_type)
1289{
1290 FILE *f;
1291 char line[SSH_MAX_PUBKEY_BYTES];
1292 char *cp;
1293 u_long linenum = 0;
1294 int ret = 0;
1295 Key *pub;
1296 int (*key_compare)(const Key *, const Key *) = strict_type ?
1297 key_equal : key_equal_public;
1298
1299 if ((f = fopen(filename, "r")) == NULL) {
1300 if (errno == ENOENT) {
1301 debug("%s: keyfile \"%s\" missing", __func__, filename);
1302 return 0;
1303 } else {
1304 error("%s: could not open keyfile \"%s\": %s", __func__,
1305 filename, strerror(errno));
1306 return -1;
1307 }
1308 }
1309
1310 while (read_keyfile_line(f, filename, line, sizeof(line),
1311 &linenum) != -1) {
1312 cp = line;
1313
1314 /* Skip leading whitespace. */
1315 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
1316 ;
1317
1318 /* Skip comments and empty lines */
1319 switch (*cp) {
1320 case '#':
1321 case '\n':
1322 case '\0':
1323 continue;
1324 }
1325
1326 pub = key_new(KEY_UNSPEC);
1327 if (key_read(pub, &cp) != 1) {
1328 key_free(pub);
1329 continue;
1330 }
1331 if (key_compare(key, pub)) {
1332 ret = 1;
1333 key_free(pub);
1334 break;
1335 }
1336 key_free(pub);
1337 }
1338 fclose(f);
1339 return ret;
1340}