blob: e93d8673860c2e1347cb1b01a8775fe798401bf1 [file] [log] [blame]
Damien Miller86687062014-07-02 15:28:02 +10001/* $OpenBSD: authfile.c,v 1.107 2014/06/24 01:13:21 djm Exp $ */
Damien Millerd4a8b7e1999-10-27 13:42:43 +10002/*
Damien Millerbcd00ab2013-12-07 10:41:55 +11003 * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
Damien Millere4340be2000-09-16 13:29:08 +11004 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Damien Miller95def091999-11-25 00:26:21 +110024 */
Damien Millerd4a8b7e1999-10-27 13:42:43 +100025
26#include "includes.h"
Damien Millerf17883e2006-03-15 11:45:54 +110027
28#include <sys/types.h>
29#include <sys/stat.h>
Damien Miller8dbffe72006-08-05 11:02:17 +100030#include <sys/param.h>
Damien Millerd7834352006-08-05 12:39:39 +100031#include <sys/uio.h>
Damien Millerd4a8b7e1999-10-27 13:42:43 +100032
Darren Tuckerba724052006-07-12 22:24:22 +100033#include <errno.h>
Damien Miller57cf6382006-07-10 21:13:46 +100034#include <fcntl.h>
Damien Millera7a73ee2006-08-05 11:37:59 +100035#include <stdio.h>
Damien Miller86687062014-07-02 15:28:02 +100036#include <stdarg.h>
Damien Millere7a1e5c2006-08-05 11:34:19 +100037#include <stdlib.h>
Damien Millere3476ed2006-07-24 14:13:33 +100038#include <string.h>
Damien Millere6b3b612006-07-24 14:01:23 +100039#include <unistd.h>
Damien Miller57cf6382006-07-10 21:13:46 +100040
Damien Millerd7834352006-08-05 12:39:39 +100041#include "cipher.h"
Damien Millereba71ba2000-04-29 23:57:08 +100042#include "key.h"
Ben Lindstrom226cfa02001-01-22 05:34:40 +000043#include "ssh.h"
44#include "log.h"
Ben Lindstrom31ca54a2001-02-09 02:11:24 +000045#include "authfile.h"
Damien Miller040b64f2002-01-22 23:10:04 +110046#include "rsa.h"
Darren Tuckerf0f90982004-12-11 13:39:50 +110047#include "misc.h"
Damien Millereccb9de2005-06-17 12:59:34 +100048#include "atomicio.h"
Damien Miller86687062014-07-02 15:28:02 +100049#include "sshbuf.h"
50#include "ssherr.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100051
Damien Miller2ce12ef2011-05-05 14:17:18 +100052#define MAX_KEY_FILE_SIZE (1024 * 1024)
53
Damien Millera2327922010-12-01 12:01:21 +110054/* Save a key blob to a file */
55static int
Damien Miller86687062014-07-02 15:28:02 +100056sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
Damien Millera2327922010-12-01 12:01:21 +110057{
Damien Miller86687062014-07-02 15:28:02 +100058 int fd, oerrno;
Damien Millera2327922010-12-01 12:01:21 +110059
Damien Miller86687062014-07-02 15:28:02 +100060 if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
61 return SSH_ERR_SYSTEM_ERROR;
62 if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
63 sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
64 oerrno = errno;
Damien Millera2327922010-12-01 12:01:21 +110065 close(fd);
66 unlink(filename);
Damien Miller86687062014-07-02 15:28:02 +100067 errno = oerrno;
68 return SSH_ERR_SYSTEM_ERROR;
Damien Millera2327922010-12-01 12:01:21 +110069 }
70 close(fd);
Damien Miller86687062014-07-02 15:28:02 +100071 return 0;
Damien Millera2327922010-12-01 12:01:21 +110072}
73
Damien Millereba71ba2000-04-29 23:57:08 +100074int
Damien Miller86687062014-07-02 15:28:02 +100075sshkey_save_private(struct sshkey *key, const char *filename,
76 const char *passphrase, const char *comment,
77 int force_new_format, const char *new_format_cipher, int new_format_rounds)
Damien Millereba71ba2000-04-29 23:57:08 +100078{
Damien Miller86687062014-07-02 15:28:02 +100079 struct sshbuf *keyblob = NULL;
80 int r;
Damien Millera2327922010-12-01 12:01:21 +110081
Damien Miller86687062014-07-02 15:28:02 +100082 if ((keyblob = sshbuf_new()) == NULL)
83 return SSH_ERR_ALLOC_FAIL;
84 if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
85 force_new_format, new_format_cipher, new_format_rounds)) != 0)
Damien Millera2327922010-12-01 12:01:21 +110086 goto out;
Damien Miller86687062014-07-02 15:28:02 +100087 if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
Damien Millera2327922010-12-01 12:01:21 +110088 goto out;
Damien Miller86687062014-07-02 15:28:02 +100089 r = 0;
Damien Millera2327922010-12-01 12:01:21 +110090 out:
Damien Miller86687062014-07-02 15:28:02 +100091 sshbuf_free(keyblob);
92 return r;
Damien Millera2327922010-12-01 12:01:21 +110093}
94
Damien Miller2ce12ef2011-05-05 14:17:18 +100095/* Load a key from a fd into a buffer */
96int
Damien Miller86687062014-07-02 15:28:02 +100097sshkey_load_file(int fd, const char *filename, struct sshbuf *blob)
Damien Millera2327922010-12-01 12:01:21 +110098{
Damien Miller2ce12ef2011-05-05 14:17:18 +100099 u_char buf[1024];
Damien Millera2327922010-12-01 12:01:21 +1100100 size_t len;
Damien Millera2327922010-12-01 12:01:21 +1100101 struct stat st;
Damien Miller86687062014-07-02 15:28:02 +1000102 int r;
Damien Millera2327922010-12-01 12:01:21 +1100103
Damien Miller86687062014-07-02 15:28:02 +1000104 if (fstat(fd, &st) < 0)
105 return SSH_ERR_SYSTEM_ERROR;
Damien Miller2ce12ef2011-05-05 14:17:18 +1000106 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
Damien Miller86687062014-07-02 15:28:02 +1000107 st.st_size > MAX_KEY_FILE_SIZE)
108 return SSH_ERR_INVALID_FORMAT;
Damien Miller2ce12ef2011-05-05 14:17:18 +1000109 for (;;) {
110 if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
111 if (errno == EPIPE)
112 break;
Damien Miller86687062014-07-02 15:28:02 +1000113 r = SSH_ERR_SYSTEM_ERROR;
114 goto out;
Damien Miller2ce12ef2011-05-05 14:17:18 +1000115 }
Damien Miller86687062014-07-02 15:28:02 +1000116 if ((r = sshbuf_put(blob, buf, len)) != 0)
117 goto out;
118 if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
119 r = SSH_ERR_INVALID_FORMAT;
120 goto out;
Damien Miller2ce12ef2011-05-05 14:17:18 +1000121 }
122 }
Damien Miller2ce12ef2011-05-05 14:17:18 +1000123 if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
Damien Miller86687062014-07-02 15:28:02 +1000124 st.st_size != (off_t)sshbuf_len(blob)) {
125 r = SSH_ERR_FILE_CHANGED;
126 goto out;
Damien Millera2327922010-12-01 12:01:21 +1100127 }
Damien Miller86687062014-07-02 15:28:02 +1000128 r = 0;
Damien Miller2ce12ef2011-05-05 14:17:18 +1000129
Damien Miller86687062014-07-02 15:28:02 +1000130 out:
131 explicit_bzero(buf, sizeof(buf));
132 if (r != 0)
133 sshbuf_reset(blob);
134 return r;
Damien Millereba71ba2000-04-29 23:57:08 +1000135}
136
Damien Miller1f0311c2014-05-15 14:24:09 +1000137#ifdef WITH_SSH1
Damien Miller5428f641999-11-25 11:54:57 +1100138/*
Ben Lindstromd0fca422001-03-26 13:44:06 +0000139 * Loads the public part of the ssh v1 key file. Returns NULL if an error was
140 * encountered (the file does not exist or is not readable), and the key
Damien Miller5428f641999-11-25 11:54:57 +1100141 * otherwise.
142 */
Damien Miller86687062014-07-02 15:28:02 +1000143static int
144sshkey_load_public_rsa1(int fd, const char *filename,
145 struct sshkey **keyp, char **commentp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000146{
Damien Miller86687062014-07-02 15:28:02 +1000147 struct sshbuf *b = NULL;
148 int r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000149
Damien Miller86687062014-07-02 15:28:02 +1000150 *keyp = NULL;
Darren Tuckera627d422013-06-02 07:31:17 +1000151 if (commentp != NULL)
Damien Miller86687062014-07-02 15:28:02 +1000152 *commentp = NULL;
153
154 if ((b = sshbuf_new()) == NULL)
155 return SSH_ERR_ALLOC_FAIL;
156 if ((r = sshkey_load_file(fd, filename, b)) != 0)
157 goto out;
158 if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
159 goto out;
160 r = 0;
161 out:
162 sshbuf_free(b);
163 return r;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000164}
Damien Miller86687062014-07-02 15:28:02 +1000165#endif /* WITH_SSH1 */
Damien Millereba71ba2000-04-29 23:57:08 +1000166
Damien Miller1f0311c2014-05-15 14:24:09 +1000167#ifdef WITH_OPENSSL
Damien Miller86687062014-07-02 15:28:02 +1000168/* XXX Deprecate? */
Damien Miller8275fad2006-03-15 12:06:23 +1100169int
Damien Miller86687062014-07-02 15:28:02 +1000170sshkey_load_private_pem(int fd, int type, const char *passphrase,
171 struct sshkey **keyp, char **commentp)
172{
173 struct sshbuf *buffer = NULL;
174 int r;
175
176 *keyp = NULL;
177 if (commentp != NULL)
178 *commentp = NULL;
179
180 if ((buffer = sshbuf_new()) == NULL)
181 return SSH_ERR_ALLOC_FAIL;
182 if ((r = sshkey_load_file(fd, NULL, buffer)) != 0)
183 goto out;
184 if ((r = sshkey_parse_private_pem_fileblob(buffer, type, passphrase,
185 keyp, commentp)) != 0)
186 goto out;
187 r = 0;
188 out:
189 sshbuf_free(buffer);
190 return r;
191}
192#endif /* WITH_OPENSSL */
193
194/* XXX remove error() calls from here? */
195int
196sshkey_perm_ok(int fd, const char *filename)
Damien Millereba71ba2000-04-29 23:57:08 +1000197{
Damien Millereba71ba2000-04-29 23:57:08 +1000198 struct stat st;
199
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000200 if (fstat(fd, &st) < 0)
Damien Miller86687062014-07-02 15:28:02 +1000201 return SSH_ERR_SYSTEM_ERROR;
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000202 /*
203 * if a key owned by the user is accessed, then we check the
204 * permissions of the file. if the key owned by a different user,
205 * then we don't care.
206 */
Damien Millerb70b61f2000-09-16 16:25:12 +1100207#ifdef HAVE_CYGWIN
Damien Millercb5e44a2000-09-29 12:12:36 +1100208 if (check_ntsec(filename))
Damien Millerb70b61f2000-09-16 16:25:12 +1100209#endif
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000210 if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
Damien Millereba71ba2000-04-29 23:57:08 +1000211 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
212 error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
213 error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
Ben Lindstrom7aff2612001-09-23 13:53:22 +0000214 error("Permissions 0%3.3o for '%s' are too open.",
Damien Miller04bd8b02003-05-25 14:38:33 +1000215 (u_int)st.st_mode & 0777, filename);
Damien Miller86687062014-07-02 15:28:02 +1000216 error("It is recommended that your private key files are NOT accessible by others.");
Ben Lindstromd0fca422001-03-26 13:44:06 +0000217 error("This private key will be ignored.");
Damien Miller86687062014-07-02 15:28:02 +1000218 return SSH_ERR_KEY_BAD_PERMISSIONS;
Damien Millere4340be2000-09-16 13:29:08 +1100219 }
220 return 0;
221}
222
Damien Miller86687062014-07-02 15:28:02 +1000223/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
224int
225sshkey_load_private_type(int type, const char *filename, const char *passphrase,
226 struct sshkey **keyp, char **commentp, int *perm_ok)
Damien Millere4340be2000-09-16 13:29:08 +1100227{
Damien Miller86687062014-07-02 15:28:02 +1000228 int fd, r;
229 struct sshbuf *buffer = NULL;
Damien Millere4340be2000-09-16 13:29:08 +1100230
Damien Miller86687062014-07-02 15:28:02 +1000231 *keyp = NULL;
232 if (commentp != NULL)
233 *commentp = NULL;
234
235 if ((fd = open(filename, O_RDONLY)) < 0) {
236 if (perm_ok != NULL)
237 *perm_ok = 0;
238 return SSH_ERR_SYSTEM_ERROR;
239 }
240 if (sshkey_perm_ok(fd, filename) != 0) {
241 if (perm_ok != NULL)
242 *perm_ok = 0;
243 r = SSH_ERR_KEY_BAD_PERMISSIONS;
244 goto out;
245 }
246 if (perm_ok != NULL)
247 *perm_ok = 1;
248
249 if ((buffer = sshbuf_new()) == NULL) {
250 r = SSH_ERR_ALLOC_FAIL;
251 goto out;
252 }
253 if ((r = sshkey_load_file(fd, filename, buffer)) != 0)
254 goto out;
255 if ((r = sshkey_parse_private_fileblob_type(buffer, type, passphrase,
256 keyp, commentp)) != 0)
257 goto out;
258 r = 0;
259 out:
260 close(fd);
261 if (buffer != NULL)
262 sshbuf_free(buffer);
263 return r;
264}
265
266/* XXX this is almost identical to sshkey_load_private_type() */
267int
268sshkey_load_private(const char *filename, const char *passphrase,
269 struct sshkey **keyp, char **commentp)
270{
271 struct sshbuf *buffer = NULL;
272 int r, fd;
273
274 *keyp = NULL;
275 if (commentp != NULL)
276 *commentp = NULL;
277
278 if ((fd = open(filename, O_RDONLY)) < 0)
279 return SSH_ERR_SYSTEM_ERROR;
280 if (sshkey_perm_ok(fd, filename) != 0) {
281 r = SSH_ERR_KEY_BAD_PERMISSIONS;
282 goto out;
283 }
284
285 if ((buffer = sshbuf_new()) == NULL) {
286 r = SSH_ERR_ALLOC_FAIL;
287 goto out;
288 }
289 if ((r = sshkey_load_file(fd, filename, buffer)) != 0 ||
290 (r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
291 keyp, commentp)) != 0)
292 goto out;
293 r = 0;
294 out:
295 close(fd);
296 if (buffer != NULL)
297 sshbuf_free(buffer);
298 return r;
299}
300
301static int
302sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
303{
304 FILE *f;
305 char line[SSH_MAX_PUBKEY_BYTES];
306 char *cp;
307 u_long linenum = 0;
308 int r;
309
310 if (commentp != NULL)
311 *commentp = NULL;
312 if ((f = fopen(filename, "r")) == NULL)
313 return SSH_ERR_SYSTEM_ERROR;
314 while (read_keyfile_line(f, filename, line, sizeof(line),
315 &linenum) != -1) {
316 cp = line;
317 switch (*cp) {
318 case '#':
319 case '\n':
320 case '\0':
321 continue;
322 }
323 /* Abort loading if this looks like a private key */
324 if (strncmp(cp, "-----BEGIN", 10) == 0 ||
325 strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
326 break;
327 /* Skip leading whitespace. */
328 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
329 ;
330 if (*cp) {
331 if ((r = sshkey_read(k, &cp)) == 0) {
332 cp[strcspn(cp, "\r\n")] = '\0';
333 if (commentp) {
334 *commentp = strdup(*cp ?
335 cp : filename);
336 if (*commentp == NULL)
337 r = SSH_ERR_ALLOC_FAIL;
338 }
339 fclose(f);
340 return r;
341 }
342 }
343 }
344 fclose(f);
345 return SSH_ERR_INVALID_FORMAT;
346}
347
348/* load public key from ssh v1 private or any pubkey file */
349int
350sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
351{
352 struct sshkey *pub = NULL;
353 char file[MAXPATHLEN];
354 int r, fd;
355
356 if (keyp != NULL)
357 *keyp = NULL;
358 if (commentp != NULL)
359 *commentp = NULL;
360
361 if ((fd = open(filename, O_RDONLY)) < 0)
362 goto skip;
Damien Miller1f0311c2014-05-15 14:24:09 +1000363#ifdef WITH_SSH1
Damien Millerdb274722003-05-14 13:45:22 +1000364 /* try rsa1 private key */
Damien Miller86687062014-07-02 15:28:02 +1000365 r = sshkey_load_public_rsa1(fd, filename, keyp, commentp);
366 close(fd);
367 switch (r) {
368 case SSH_ERR_INTERNAL_ERROR:
369 case SSH_ERR_ALLOC_FAIL:
370 case SSH_ERR_INVALID_ARGUMENT:
371 case SSH_ERR_SYSTEM_ERROR:
372 case 0:
373 return r;
374 }
375#endif /* WITH_SSH1 */
Damien Millerdb274722003-05-14 13:45:22 +1000376
377 /* try ssh2 public key */
Damien Miller86687062014-07-02 15:28:02 +1000378 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
379 return SSH_ERR_ALLOC_FAIL;
380 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
381 if (keyp != NULL)
382 *keyp = pub;
383 return 0;
384 }
385 sshkey_free(pub);
386
387#ifdef WITH_SSH1
388 /* try rsa1 public key */
389 if ((pub = sshkey_new(KEY_RSA1)) == NULL)
390 return SSH_ERR_ALLOC_FAIL;
391 if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
392 if (keyp != NULL)
393 *keyp = pub;
394 return 0;
395 }
396 sshkey_free(pub);
397#endif /* WITH_SSH1 */
398
399 skip:
400 /* try .pub suffix */
401 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
402 return SSH_ERR_ALLOC_FAIL;
403 r = SSH_ERR_ALLOC_FAIL; /* in case strlcpy or strlcat fail */
Ben Lindstromd0fca422001-03-26 13:44:06 +0000404 if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
405 (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
Damien Miller86687062014-07-02 15:28:02 +1000406 (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
407 if (keyp != NULL)
408 *keyp = pub;
409 return 0;
410 }
411 sshkey_free(pub);
412 return r;
Damien Millere4340be2000-09-16 13:29:08 +1100413}
Damien Miller1aed65e2010-03-04 21:53:35 +1100414
Damien Millerc1583312010-08-05 13:04:50 +1000415/* Load the certificate associated with the named private key */
Damien Miller86687062014-07-02 15:28:02 +1000416int
417sshkey_load_cert(const char *filename, struct sshkey **keyp)
Damien Millerc1583312010-08-05 13:04:50 +1000418{
Damien Miller86687062014-07-02 15:28:02 +1000419 struct sshkey *pub = NULL;
420 char *file = NULL;
421 int r = SSH_ERR_INTERNAL_ERROR;
Damien Millerc1583312010-08-05 13:04:50 +1000422
Damien Miller86687062014-07-02 15:28:02 +1000423 *keyp = NULL;
424
425 if (asprintf(&file, "%s-cert.pub", filename) == -1)
426 return SSH_ERR_ALLOC_FAIL;
427
428 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
429 goto out;
Damien Miller5458c4d2010-08-05 13:05:15 +1000430 }
Damien Miller86687062014-07-02 15:28:02 +1000431 if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
432 goto out;
433
434 *keyp = pub;
435 pub = NULL;
436 r = 0;
437
438 out:
439 if (file != NULL)
440 free(file);
441 if (pub != NULL)
442 sshkey_free(pub);
443 return r;
Damien Millerc1583312010-08-05 13:04:50 +1000444}
445
446/* Load private key and certificate */
Damien Miller86687062014-07-02 15:28:02 +1000447int
448sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
449 struct sshkey **keyp, int *perm_ok)
Damien Millerc1583312010-08-05 13:04:50 +1000450{
Damien Miller86687062014-07-02 15:28:02 +1000451 struct sshkey *key = NULL, *cert = NULL;
452 int r;
453
454 *keyp = NULL;
Damien Millerc1583312010-08-05 13:04:50 +1000455
456 switch (type) {
Damien Miller1f0311c2014-05-15 14:24:09 +1000457#ifdef WITH_OPENSSL
Damien Millerc1583312010-08-05 13:04:50 +1000458 case KEY_RSA:
459 case KEY_DSA:
Damien Millereb8b60e2010-08-31 22:41:14 +1000460 case KEY_ECDSA:
Damien Millerb9a95492013-12-29 17:50:15 +1100461 case KEY_ED25519:
Damien Miller86687062014-07-02 15:28:02 +1000462#endif /* WITH_OPENSSL */
463 case KEY_UNSPEC:
Damien Millerc1583312010-08-05 13:04:50 +1000464 break;
465 default:
Damien Miller86687062014-07-02 15:28:02 +1000466 return SSH_ERR_KEY_TYPE_UNKNOWN;
Damien Millerc1583312010-08-05 13:04:50 +1000467 }
468
Damien Miller86687062014-07-02 15:28:02 +1000469 if ((r = sshkey_load_private_type(type, filename,
470 passphrase, &key, NULL, perm_ok)) != 0 ||
471 (r = sshkey_load_cert(filename, &cert)) != 0)
472 goto out;
Damien Millerc1583312010-08-05 13:04:50 +1000473
474 /* Make sure the private key matches the certificate */
Damien Miller86687062014-07-02 15:28:02 +1000475 if (sshkey_equal_public(key, cert) == 0) {
476 r = SSH_ERR_KEY_CERT_MISMATCH;
477 goto out;
Damien Millerc1583312010-08-05 13:04:50 +1000478 }
479
Damien Miller86687062014-07-02 15:28:02 +1000480 if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 ||
481 (r = sshkey_cert_copy(cert, key)) != 0)
482 goto out;
483 r = 0;
484 *keyp = key;
485 key = NULL;
486 out:
487 if (key != NULL)
488 sshkey_free(key);
489 if (cert != NULL)
490 sshkey_free(cert);
491 return r;
Damien Millerc1583312010-08-05 13:04:50 +1000492}
493
Damien Miller1aed65e2010-03-04 21:53:35 +1100494/*
Damien Miller86687062014-07-02 15:28:02 +1000495 * Returns success if the specified "key" is listed in the file "filename",
496 * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
Damien Miller1aed65e2010-03-04 21:53:35 +1100497 * If strict_type is set then the key type must match exactly,
498 * otherwise a comparison that ignores certficiate data is performed.
499 */
500int
Damien Miller86687062014-07-02 15:28:02 +1000501sshkey_in_file(struct sshkey *key, const char *filename, int strict_type)
Damien Miller1aed65e2010-03-04 21:53:35 +1100502{
503 FILE *f;
504 char line[SSH_MAX_PUBKEY_BYTES];
505 char *cp;
506 u_long linenum = 0;
Damien Miller86687062014-07-02 15:28:02 +1000507 int r = 0;
508 struct sshkey *pub = NULL;
509 int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
510 strict_type ? sshkey_equal : sshkey_equal_public;
Damien Miller1aed65e2010-03-04 21:53:35 +1100511
512 if ((f = fopen(filename, "r")) == NULL) {
Damien Miller86687062014-07-02 15:28:02 +1000513 if (errno == ENOENT)
514 return SSH_ERR_KEY_NOT_FOUND;
515 else
516 return SSH_ERR_SYSTEM_ERROR;
Damien Miller1aed65e2010-03-04 21:53:35 +1100517 }
518
519 while (read_keyfile_line(f, filename, line, sizeof(line),
Damien Miller86687062014-07-02 15:28:02 +1000520 &linenum) != -1) {
Damien Miller1aed65e2010-03-04 21:53:35 +1100521 cp = line;
522
523 /* Skip leading whitespace. */
524 for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
525 ;
526
527 /* Skip comments and empty lines */
528 switch (*cp) {
529 case '#':
530 case '\n':
531 case '\0':
532 continue;
533 }
534
Damien Miller86687062014-07-02 15:28:02 +1000535 if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
536 r = SSH_ERR_ALLOC_FAIL;
537 goto out;
Damien Miller1aed65e2010-03-04 21:53:35 +1100538 }
Damien Miller86687062014-07-02 15:28:02 +1000539 if ((r = sshkey_read(pub, &cp)) != 0)
540 goto out;
541 if (sshkey_compare(key, pub)) {
542 r = 0;
543 goto out;
Damien Miller1aed65e2010-03-04 21:53:35 +1100544 }
Damien Miller86687062014-07-02 15:28:02 +1000545 sshkey_free(pub);
546 pub = NULL;
Damien Miller1aed65e2010-03-04 21:53:35 +1100547 }
Damien Miller86687062014-07-02 15:28:02 +1000548 r = SSH_ERR_KEY_NOT_FOUND;
549 out:
550 if (pub != NULL)
551 sshkey_free(pub);
Damien Miller1aed65e2010-03-04 21:53:35 +1100552 fclose(f);
Damien Miller86687062014-07-02 15:28:02 +1000553 return r;
Damien Miller1aed65e2010-03-04 21:53:35 +1100554}
Damien Miller86687062014-07-02 15:28:02 +1000555