1296853Sdes/* $OpenBSD: authfile.c,v 1.120 2015/12/11 04:21:11 mmcc Exp $ */
257429Smarkm/*
3262566Sdes * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
465674Skris *
565674Skris * Redistribution and use in source and binary forms, with or without
665674Skris * modification, are permitted provided that the following conditions
765674Skris * are met:
865674Skris * 1. Redistributions of source code must retain the above copyright
965674Skris *    notice, this list of conditions and the following disclaimer.
1065674Skris * 2. Redistributions in binary form must reproduce the above copyright
1165674Skris *    notice, this list of conditions and the following disclaimer in the
1265674Skris *    documentation and/or other materials provided with the distribution.
1365674Skris *
1465674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1565674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1665674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1765674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1865674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1965674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2065674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2165674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2265674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2365674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2457429Smarkm */
2557429Smarkm
2657429Smarkm#include "includes.h"
2757429Smarkm
28162856Sdes#include <sys/types.h>
29162856Sdes#include <sys/stat.h>
30162856Sdes#include <sys/uio.h>
31162856Sdes
32162856Sdes#include <errno.h>
33162856Sdes#include <fcntl.h>
34295367Sdes#include <stdio.h>
35162856Sdes#include <stdarg.h>
36162856Sdes#include <stdlib.h>
37162856Sdes#include <string.h>
38162856Sdes#include <unistd.h>
39295367Sdes#include <limits.h>
40162856Sdes
4176262Sgreen#include "cipher.h"
4257429Smarkm#include "ssh.h"
4376262Sgreen#include "log.h"
4476262Sgreen#include "authfile.h"
4592559Sdes#include "rsa.h"
46147005Sdes#include "misc.h"
47149753Sdes#include "atomicio.h"
48295367Sdes#include "sshkey.h"
49295367Sdes#include "sshbuf.h"
50295367Sdes#include "ssherr.h"
51295367Sdes#include "krl.h"
5257429Smarkm
53226046Sdes#define MAX_KEY_FILE_SIZE	(1024 * 1024)
54226046Sdes
55221420Sdes/* Save a key blob to a file */
56221420Sdesstatic int
57295367Sdessshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
58221420Sdes{
59295367Sdes	int fd, oerrno;
60221420Sdes
61295367Sdes	if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
62295367Sdes		return SSH_ERR_SYSTEM_ERROR;
63295367Sdes	if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
64295367Sdes	    sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
65295367Sdes		oerrno = errno;
66221420Sdes		close(fd);
67221420Sdes		unlink(filename);
68295367Sdes		errno = oerrno;
69295367Sdes		return SSH_ERR_SYSTEM_ERROR;
70221420Sdes	}
71221420Sdes	close(fd);
72295367Sdes	return 0;
73221420Sdes}
74221420Sdes
75221420Sdesint
76295367Sdessshkey_save_private(struct sshkey *key, const char *filename,
77295367Sdes    const char *passphrase, const char *comment,
78295367Sdes    int force_new_format, const char *new_format_cipher, int new_format_rounds)
79221420Sdes{
80295367Sdes	struct sshbuf *keyblob = NULL;
81295367Sdes	int r;
82221420Sdes
83295367Sdes	if ((keyblob = sshbuf_new()) == NULL)
84295367Sdes		return SSH_ERR_ALLOC_FAIL;
85295367Sdes	if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
86295367Sdes	    force_new_format, new_format_cipher, new_format_rounds)) != 0)
87221420Sdes		goto out;
88295367Sdes	if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
89221420Sdes		goto out;
90295367Sdes	r = 0;
91221420Sdes out:
92295367Sdes	sshbuf_free(keyblob);
93295367Sdes	return r;
94221420Sdes}
95221420Sdes
96226046Sdes/* Load a key from a fd into a buffer */
97226046Sdesint
98295367Sdessshkey_load_file(int fd, struct sshbuf *blob)
99221420Sdes{
100226046Sdes	u_char buf[1024];
101221420Sdes	size_t len;
102113911Sdes	struct stat st;
103295367Sdes	int r;
10457429Smarkm
105295367Sdes	if (fstat(fd, &st) < 0)
106295367Sdes		return SSH_ERR_SYSTEM_ERROR;
107226046Sdes	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
108295367Sdes	    st.st_size > MAX_KEY_FILE_SIZE)
109295367Sdes		return SSH_ERR_INVALID_FORMAT;
110226046Sdes	for (;;) {
111226046Sdes		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
112226046Sdes			if (errno == EPIPE)
113226046Sdes				break;
114295367Sdes			r = SSH_ERR_SYSTEM_ERROR;
115295367Sdes			goto out;
116226046Sdes		}
117295367Sdes		if ((r = sshbuf_put(blob, buf, len)) != 0)
118295367Sdes			goto out;
119295367Sdes		if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
120295367Sdes			r = SSH_ERR_INVALID_FORMAT;
121295367Sdes			goto out;
122226046Sdes		}
123226046Sdes	}
124226046Sdes	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
125295367Sdes	    st.st_size != (off_t)sshbuf_len(blob)) {
126295367Sdes		r = SSH_ERR_FILE_CHANGED;
127295367Sdes		goto out;
12857429Smarkm	}
129295367Sdes	r = 0;
130226046Sdes
131295367Sdes out:
132295367Sdes	explicit_bzero(buf, sizeof(buf));
133295367Sdes	if (r != 0)
134295367Sdes		sshbuf_reset(blob);
135295367Sdes	return r;
136221420Sdes}
13757429Smarkm
138295367Sdes#ifdef WITH_SSH1
139221420Sdes/*
140221420Sdes * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
141221420Sdes * encountered (the file does not exist or is not readable), and the key
142221420Sdes * otherwise.
143221420Sdes */
144295367Sdesstatic int
145295367Sdessshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
146221420Sdes{
147295367Sdes	struct sshbuf *b = NULL;
148295367Sdes	int r;
149221420Sdes
150295367Sdes	*keyp = NULL;
151255767Sdes	if (commentp != NULL)
152295367Sdes		*commentp = NULL;
15360576Skris
154295367Sdes	if ((b = sshbuf_new()) == NULL)
155295367Sdes		return SSH_ERR_ALLOC_FAIL;
156295367Sdes	if ((r = sshkey_load_file(fd, b)) != 0)
157295367Sdes		goto out;
158295367Sdes	if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
159295367Sdes		goto out;
160295367Sdes	r = 0;
161295367Sdes out:
162295367Sdes	sshbuf_free(b);
163295367Sdes	return r;
16460576Skris}
165295367Sdes#endif /* WITH_SSH1 */
16660576Skris
167295367Sdes/* XXX remove error() calls from here? */
168162856Sdesint
169295367Sdessshkey_perm_ok(int fd, const char *filename)
17060576Skris{
17160576Skris	struct stat st;
17260576Skris
17392559Sdes	if (fstat(fd, &st) < 0)
174295367Sdes		return SSH_ERR_SYSTEM_ERROR;
17592559Sdes	/*
17692559Sdes	 * if a key owned by the user is accessed, then we check the
17792559Sdes	 * permissions of the file. if the key owned by a different user,
17892559Sdes	 * then we don't care.
17992559Sdes	 */
18098941Sdes#ifdef HAVE_CYGWIN
18198941Sdes	if (check_ntsec(filename))
18298941Sdes#endif
18392559Sdes	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
18460576Skris		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
18560576Skris		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
18660576Skris		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
18792559Sdes		error("Permissions 0%3.3o for '%s' are too open.",
188124211Sdes		    (u_int)st.st_mode & 0777, filename);
189226046Sdes		error("It is required that your private key files are NOT accessible by others.");
19076262Sgreen		error("This private key will be ignored.");
191295367Sdes		return SSH_ERR_KEY_BAD_PERMISSIONS;
19260576Skris	}
193295367Sdes	return 0;
19476262Sgreen}
19576262Sgreen
196295367Sdes/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
197295367Sdesint
198295367Sdessshkey_load_private_type(int type, const char *filename, const char *passphrase,
199295367Sdes    struct sshkey **keyp, char **commentp, int *perm_ok)
200221420Sdes{
201295367Sdes	int fd, r;
202262566Sdes
203295367Sdes	*keyp = NULL;
204295367Sdes	if (commentp != NULL)
205295367Sdes		*commentp = NULL;
206221420Sdes
207295367Sdes	if ((fd = open(filename, O_RDONLY)) < 0) {
208204917Sdes		if (perm_ok != NULL)
209204917Sdes			*perm_ok = 0;
210295367Sdes		return SSH_ERR_SYSTEM_ERROR;
211204917Sdes	}
212295367Sdes	if (sshkey_perm_ok(fd, filename) != 0) {
213162856Sdes		if (perm_ok != NULL)
214162856Sdes			*perm_ok = 0;
215295367Sdes		r = SSH_ERR_KEY_BAD_PERMISSIONS;
216295367Sdes		goto out;
21776262Sgreen	}
218162856Sdes	if (perm_ok != NULL)
219162856Sdes		*perm_ok = 1;
220221420Sdes
221295367Sdes	r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
222295367Sdes out:
223221420Sdes	close(fd);
224295367Sdes	return r;
22560576Skris}
22665674Skris
227295367Sdesint
228295367Sdessshkey_load_private_type_fd(int fd, int type, const char *passphrase,
229295367Sdes    struct sshkey **keyp, char **commentp)
230226046Sdes{
231295367Sdes	struct sshbuf *buffer = NULL;
232295367Sdes	int r;
233226046Sdes
234295367Sdes	if ((buffer = sshbuf_new()) == NULL) {
235295367Sdes		r = SSH_ERR_ALLOC_FAIL;
236295367Sdes		goto out;
237226046Sdes	}
238295367Sdes	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
239295367Sdes	    (r = sshkey_parse_private_fileblob_type(buffer, type,
240295367Sdes	    passphrase, keyp, commentp)) != 0)
241295367Sdes		goto out;
242295367Sdes
243295367Sdes	/* success */
244295367Sdes	r = 0;
245295367Sdes out:
246296853Sdes	sshbuf_free(buffer);
247295367Sdes	return r;
248226046Sdes}
249226046Sdes
250295367Sdes/* XXX this is almost identical to sshkey_load_private_type() */
251295367Sdesint
252295367Sdessshkey_load_private(const char *filename, const char *passphrase,
253295367Sdes    struct sshkey **keyp, char **commentp)
25476262Sgreen{
255295367Sdes	struct sshbuf *buffer = NULL;
256295367Sdes	int r, fd;
25776262Sgreen
258295367Sdes	*keyp = NULL;
259295367Sdes	if (commentp != NULL)
260295367Sdes		*commentp = NULL;
261295367Sdes
262295367Sdes	if ((fd = open(filename, O_RDONLY)) < 0)
263295367Sdes		return SSH_ERR_SYSTEM_ERROR;
264295367Sdes	if (sshkey_perm_ok(fd, filename) != 0) {
265295367Sdes		r = SSH_ERR_KEY_BAD_PERMISSIONS;
266295367Sdes		goto out;
267204917Sdes	}
268221420Sdes
269295367Sdes	if ((buffer = sshbuf_new()) == NULL) {
270295367Sdes		r = SSH_ERR_ALLOC_FAIL;
271295367Sdes		goto out;
272221420Sdes	}
273295367Sdes	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
274296853Sdes	    (r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
275296853Sdes	    commentp)) != 0)
276295367Sdes		goto out;
277295367Sdes	r = 0;
278295367Sdes out:
279221420Sdes	close(fd);
280296853Sdes	sshbuf_free(buffer);
281295367Sdes	return r;
28276262Sgreen}
28376262Sgreen
28492559Sdesstatic int
285295367Sdessshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
28665674Skris{
28765674Skris	FILE *f;
288147005Sdes	char line[SSH_MAX_PUBKEY_BYTES];
28965674Skris	char *cp;
290147005Sdes	u_long linenum = 0;
291295367Sdes	int r;
29265674Skris
293295367Sdes	if (commentp != NULL)
294295367Sdes		*commentp = NULL;
295295367Sdes	if ((f = fopen(filename, "r")) == NULL)
296295367Sdes		return SSH_ERR_SYSTEM_ERROR;
297295367Sdes	while (read_keyfile_line(f, filename, line, sizeof(line),
298295367Sdes		    &linenum) != -1) {
299295367Sdes		cp = line;
300295367Sdes		switch (*cp) {
301295367Sdes		case '#':
302295367Sdes		case '\n':
303295367Sdes		case '\0':
304295367Sdes			continue;
305295367Sdes		}
306295367Sdes		/* Abort loading if this looks like a private key */
307295367Sdes		if (strncmp(cp, "-----BEGIN", 10) == 0 ||
308295367Sdes		    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
309295367Sdes			break;
310295367Sdes		/* Skip leading whitespace. */
311295367Sdes		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
312295367Sdes			;
313295367Sdes		if (*cp) {
314295367Sdes			if ((r = sshkey_read(k, &cp)) == 0) {
315295367Sdes				cp[strcspn(cp, "\r\n")] = '\0';
316295367Sdes				if (commentp) {
317295367Sdes					*commentp = strdup(*cp ?
318295367Sdes					    cp : filename);
319295367Sdes					if (*commentp == NULL)
320295367Sdes						r = SSH_ERR_ALLOC_FAIL;
32165674Skris				}
322295367Sdes				fclose(f);
323295367Sdes				return r;
32465674Skris			}
32565674Skris		}
32665674Skris	}
327295367Sdes	fclose(f);
328295367Sdes	return SSH_ERR_INVALID_FORMAT;
32965674Skris}
33065674Skris
33176262Sgreen/* load public key from ssh v1 private or any pubkey file */
332295367Sdesint
333295367Sdessshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
33465674Skris{
335295367Sdes	struct sshkey *pub = NULL;
336295367Sdes	char file[PATH_MAX];
337295367Sdes	int r, fd;
33865674Skris
339295367Sdes	if (keyp != NULL)
340295367Sdes		*keyp = NULL;
341295367Sdes	if (commentp != NULL)
342295367Sdes		*commentp = NULL;
343295367Sdes
344295367Sdes	/* XXX should load file once and attempt to parse each format */
345295367Sdes
346295367Sdes	if ((fd = open(filename, O_RDONLY)) < 0)
347295367Sdes		goto skip;
348295367Sdes#ifdef WITH_SSH1
349124211Sdes	/* try rsa1 private key */
350295367Sdes	r = sshkey_load_public_rsa1(fd, keyp, commentp);
351295367Sdes	close(fd);
352295367Sdes	switch (r) {
353295367Sdes	case SSH_ERR_INTERNAL_ERROR:
354295367Sdes	case SSH_ERR_ALLOC_FAIL:
355295367Sdes	case SSH_ERR_INVALID_ARGUMENT:
356295367Sdes	case SSH_ERR_SYSTEM_ERROR:
357295367Sdes	case 0:
358295367Sdes		return r;
359295367Sdes	}
360295367Sdes#else /* WITH_SSH1 */
361295367Sdes	close(fd);
362295367Sdes#endif /* WITH_SSH1 */
363124211Sdes
364295367Sdes	/* try ssh2 public key */
365295367Sdes	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
366295367Sdes		return SSH_ERR_ALLOC_FAIL;
367295367Sdes	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
368295367Sdes		if (keyp != NULL)
369295367Sdes			*keyp = pub;
370295367Sdes		return 0;
371295367Sdes	}
372295367Sdes	sshkey_free(pub);
373295367Sdes
374295367Sdes#ifdef WITH_SSH1
375124211Sdes	/* try rsa1 public key */
376295367Sdes	if ((pub = sshkey_new(KEY_RSA1)) == NULL)
377295367Sdes		return SSH_ERR_ALLOC_FAIL;
378295367Sdes	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
379295367Sdes		if (keyp != NULL)
380295367Sdes			*keyp = pub;
381295367Sdes		return 0;
382295367Sdes	}
383295367Sdes	sshkey_free(pub);
384295367Sdes#endif /* WITH_SSH1 */
385124211Sdes
386295367Sdes skip:
387295367Sdes	/* try .pub suffix */
388295367Sdes	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
389295367Sdes		return SSH_ERR_ALLOC_FAIL;
390295367Sdes	r = SSH_ERR_ALLOC_FAIL;	/* in case strlcpy or strlcat fail */
39176262Sgreen	if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
39276262Sgreen	    (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
393295367Sdes	    (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
394295367Sdes		if (keyp != NULL)
395295367Sdes			*keyp = pub;
396295367Sdes		return 0;
397295367Sdes	}
398295367Sdes	sshkey_free(pub);
399295367Sdes
400295367Sdes	return r;
40165674Skris}
402204917Sdes
403215116Sdes/* Load the certificate associated with the named private key */
404295367Sdesint
405295367Sdessshkey_load_cert(const char *filename, struct sshkey **keyp)
406215116Sdes{
407295367Sdes	struct sshkey *pub = NULL;
408295367Sdes	char *file = NULL;
409295367Sdes	int r = SSH_ERR_INTERNAL_ERROR;
410215116Sdes
411295367Sdes	*keyp = NULL;
412295367Sdes
413295367Sdes	if (asprintf(&file, "%s-cert.pub", filename) == -1)
414295367Sdes		return SSH_ERR_ALLOC_FAIL;
415295367Sdes
416295367Sdes	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
417295367Sdes		goto out;
418295367Sdes	}
419295367Sdes	if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
420295367Sdes		goto out;
421295367Sdes
422295367Sdes	*keyp = pub;
423295367Sdes	pub = NULL;
424295367Sdes	r = 0;
425295367Sdes
426295367Sdes out:
427296853Sdes	free(file);
428296853Sdes	sshkey_free(pub);
429295367Sdes	return r;
430215116Sdes}
431215116Sdes
432215116Sdes/* Load private key and certificate */
433295367Sdesint
434295367Sdessshkey_load_private_cert(int type, const char *filename, const char *passphrase,
435295367Sdes    struct sshkey **keyp, int *perm_ok)
436215116Sdes{
437295367Sdes	struct sshkey *key = NULL, *cert = NULL;
438295367Sdes	int r;
439215116Sdes
440295367Sdes	*keyp = NULL;
441295367Sdes
442215116Sdes	switch (type) {
443295367Sdes#ifdef WITH_OPENSSL
444215116Sdes	case KEY_RSA:
445215116Sdes	case KEY_DSA:
446221420Sdes	case KEY_ECDSA:
447295367Sdes#endif /* WITH_OPENSSL */
448262566Sdes	case KEY_ED25519:
449295367Sdes	case KEY_UNSPEC:
450215116Sdes		break;
451215116Sdes	default:
452295367Sdes		return SSH_ERR_KEY_TYPE_UNKNOWN;
453215116Sdes	}
454215116Sdes
455295367Sdes	if ((r = sshkey_load_private_type(type, filename,
456295367Sdes	    passphrase, &key, NULL, perm_ok)) != 0 ||
457295367Sdes	    (r = sshkey_load_cert(filename, &cert)) != 0)
458295367Sdes		goto out;
459215116Sdes
460215116Sdes	/* Make sure the private key matches the certificate */
461295367Sdes	if (sshkey_equal_public(key, cert) == 0) {
462295367Sdes		r = SSH_ERR_KEY_CERT_MISMATCH;
463295367Sdes		goto out;
464215116Sdes	}
465215116Sdes
466295367Sdes	if ((r = sshkey_to_certified(key)) != 0 ||
467295367Sdes	    (r = sshkey_cert_copy(cert, key)) != 0)
468295367Sdes		goto out;
469295367Sdes	r = 0;
470295367Sdes	*keyp = key;
471295367Sdes	key = NULL;
472295367Sdes out:
473296853Sdes	sshkey_free(key);
474296853Sdes	sshkey_free(cert);
475295367Sdes	return r;
476215116Sdes}
477215116Sdes
478204917Sdes/*
479295367Sdes * Returns success if the specified "key" is listed in the file "filename",
480295367Sdes * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
481295367Sdes * If "strict_type" is set then the key type must match exactly,
482204917Sdes * otherwise a comparison that ignores certficiate data is performed.
483295367Sdes * If "check_ca" is set and "key" is a certificate, then its CA key is
484295367Sdes * also checked and sshkey_in_file() will return success if either is found.
485204917Sdes */
486204917Sdesint
487295367Sdessshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
488295367Sdes    int check_ca)
489204917Sdes{
490204917Sdes	FILE *f;
491204917Sdes	char line[SSH_MAX_PUBKEY_BYTES];
492204917Sdes	char *cp;
493204917Sdes	u_long linenum = 0;
494295367Sdes	int r = 0;
495295367Sdes	struct sshkey *pub = NULL;
496295367Sdes	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
497295367Sdes	    strict_type ?  sshkey_equal : sshkey_equal_public;
498204917Sdes
499295367Sdes	if ((f = fopen(filename, "r")) == NULL)
500295367Sdes		return SSH_ERR_SYSTEM_ERROR;
501204917Sdes
502204917Sdes	while (read_keyfile_line(f, filename, line, sizeof(line),
503295367Sdes	    &linenum) != -1) {
504204917Sdes		cp = line;
505204917Sdes
506204917Sdes		/* Skip leading whitespace. */
507204917Sdes		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
508204917Sdes			;
509204917Sdes
510204917Sdes		/* Skip comments and empty lines */
511204917Sdes		switch (*cp) {
512204917Sdes		case '#':
513204917Sdes		case '\n':
514204917Sdes		case '\0':
515204917Sdes			continue;
516204917Sdes		}
517204917Sdes
518295367Sdes		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
519295367Sdes			r = SSH_ERR_ALLOC_FAIL;
520295367Sdes			goto out;
521204917Sdes		}
522295367Sdes		if ((r = sshkey_read(pub, &cp)) != 0)
523295367Sdes			goto out;
524295367Sdes		if (sshkey_compare(key, pub) ||
525295367Sdes		    (check_ca && sshkey_is_cert(key) &&
526295367Sdes		    sshkey_compare(key->cert->signature_key, pub))) {
527295367Sdes			r = 0;
528295367Sdes			goto out;
529204917Sdes		}
530295367Sdes		sshkey_free(pub);
531295367Sdes		pub = NULL;
532204917Sdes	}
533295367Sdes	r = SSH_ERR_KEY_NOT_FOUND;
534295367Sdes out:
535296853Sdes	sshkey_free(pub);
536204917Sdes	fclose(f);
537295367Sdes	return r;
538204917Sdes}
539295367Sdes
540295367Sdes/*
541295367Sdes * Checks whether the specified key is revoked, returning 0 if not,
542295367Sdes * SSH_ERR_KEY_REVOKED if it is or another error code if something
543295367Sdes * unexpected happened.
544295367Sdes * This will check both the key and, if it is a certificate, its CA key too.
545295367Sdes * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
546295367Sdes */
547295367Sdesint
548295367Sdessshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
549295367Sdes{
550295367Sdes	int r;
551295367Sdes
552295367Sdes	r = ssh_krl_file_contains_key(revoked_keys_file, key);
553295367Sdes	/* If this was not a KRL to begin with then continue below */
554295367Sdes	if (r != SSH_ERR_KRL_BAD_MAGIC)
555295367Sdes		return r;
556295367Sdes
557295367Sdes	/*
558295367Sdes	 * If the file is not a KRL or we can't handle KRLs then attempt to
559295367Sdes	 * parse the file as a flat list of keys.
560295367Sdes	 */
561295367Sdes	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
562295367Sdes	case 0:
563295367Sdes		/* Key found => revoked */
564295367Sdes		return SSH_ERR_KEY_REVOKED;
565295367Sdes	case SSH_ERR_KEY_NOT_FOUND:
566295367Sdes		/* Key not found => not revoked */
567295367Sdes		return 0;
568295367Sdes	default:
569295367Sdes		/* Some other error occurred */
570295367Sdes		return r;
571295367Sdes	}
572295367Sdes}
573295367Sdes
574