1d059297112922cabb0c674840589be8db821fd9aAdam Langley/* $OpenBSD: authfile.c,v 1.111 2015/02/23 16:55:51 djm Exp $ */
2bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
3d059297112922cabb0c674840589be8db821fd9aAdam Langley * Copyright (c) 2000, 2013 Markus Friedl.  All rights reserved.
4bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
5bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Redistribution and use in source and binary forms, with or without
6bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * modification, are permitted provided that the following conditions
7bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * are met:
8bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 1. Redistributions of source code must retain the above copyright
9bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer.
10bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * 2. Redistributions in binary form must reproduce the above copyright
11bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    notice, this list of conditions and the following disclaimer in the
12bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *    documentation and/or other materials provided with the distribution.
13bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman *
14bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
25bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
26bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "includes.h"
27bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
28bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/types.h>
29bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/stat.h>
30bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <sys/uio.h>
31bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
32bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <errno.h>
33bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <fcntl.h>
34bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdio.h>
35d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <stdarg.h>
36bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <stdlib.h>
37bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <string.h>
38bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include <unistd.h>
39d059297112922cabb0c674840589be8db821fd9aAdam Langley#include <limits.h>
40bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
41bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "cipher.h"
42bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "key.h"
43bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "ssh.h"
44bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "log.h"
45bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "authfile.h"
46bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "rsa.h"
47bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "misc.h"
48bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#include "atomicio.h"
49d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "sshbuf.h"
50d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "ssherr.h"
51d059297112922cabb0c674840589be8db821fd9aAdam Langley#include "krl.h"
52bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
53bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#define MAX_KEY_FILE_SIZE	(1024 * 1024)
54bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
55bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Save a key blob to a file */
56bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int
57d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
58bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
59d059297112922cabb0c674840589be8db821fd9aAdam Langley	int fd, oerrno;
60bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
61d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
62d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
63d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (atomicio(vwrite, fd, (u_char *)sshbuf_ptr(keybuf),
64d059297112922cabb0c674840589be8db821fd9aAdam Langley	    sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
65d059297112922cabb0c674840589be8db821fd9aAdam Langley		oerrno = errno;
66bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		close(fd);
67bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		unlink(filename);
68d059297112922cabb0c674840589be8db821fd9aAdam Langley		errno = oerrno;
69d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
70bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
71bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	close(fd);
72d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
73bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
74bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
75bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
76d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_save_private(struct sshkey *key, const char *filename,
77d059297112922cabb0c674840589be8db821fd9aAdam Langley    const char *passphrase, const char *comment,
78d059297112922cabb0c674840589be8db821fd9aAdam Langley    int force_new_format, const char *new_format_cipher, int new_format_rounds)
79bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
80d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *keyblob = NULL;
81d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
82bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
83d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((keyblob = sshbuf_new()) == NULL)
84d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
85d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
86d059297112922cabb0c674840589be8db821fd9aAdam Langley	    force_new_format, new_format_cipher, new_format_rounds)) != 0)
87bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		goto out;
88d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
89bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		goto out;
90d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
91bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman out:
92d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(keyblob);
93d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
94bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
95bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
96bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Load a key from a fd into a buffer */
97bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
98d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_file(int fd, struct sshbuf *blob)
99bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
100bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_char buf[1024];
101bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	size_t len;
102bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct stat st;
103d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
104bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
105d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (fstat(fd, &st) < 0)
106d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
107bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
108d059297112922cabb0c674840589be8db821fd9aAdam Langley	    st.st_size > MAX_KEY_FILE_SIZE)
109d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_INVALID_FORMAT;
110bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	for (;;) {
111bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
112bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			if (errno == EPIPE)
113bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				break;
114d059297112922cabb0c674840589be8db821fd9aAdam Langley			r = SSH_ERR_SYSTEM_ERROR;
115d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto out;
116bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
117d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshbuf_put(blob, buf, len)) != 0)
118d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto out;
119d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
120d059297112922cabb0c674840589be8db821fd9aAdam Langley			r = SSH_ERR_INVALID_FORMAT;
121d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto out;
122bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
123bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
124bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
125d059297112922cabb0c674840589be8db821fd9aAdam Langley	    st.st_size != (off_t)sshbuf_len(blob)) {
126d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_FILE_CHANGED;
127d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
128bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
129d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
130bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
131d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
132d059297112922cabb0c674840589be8db821fd9aAdam Langley	explicit_bzero(buf, sizeof(buf));
133d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (r != 0)
134d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshbuf_reset(blob);
135d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
136bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
137bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
138d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
139bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
140bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * Loads the public part of the ssh v1 key file.  Returns NULL if an error was
141bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * encountered (the file does not exist or is not readable), and the key
142bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * otherwise.
143bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
144d059297112922cabb0c674840589be8db821fd9aAdam Langleystatic int
145d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_public_rsa1(int fd, struct sshkey **keyp, char **commentp)
146bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
147d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *b = NULL;
148d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
149bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
150d059297112922cabb0c674840589be8db821fd9aAdam Langley	*keyp = NULL;
151d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (commentp != NULL)
152d059297112922cabb0c674840589be8db821fd9aAdam Langley		*commentp = NULL;
153bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
154d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((b = sshbuf_new()) == NULL)
155d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
156d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_load_file(fd, b)) != 0)
157d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
158d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_parse_public_rsa1_fileblob(b, keyp, commentp)) != 0)
159d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
160d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
161d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
162d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshbuf_free(b);
163d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
164bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
165d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
166bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
167d059297112922cabb0c674840589be8db821fd9aAdam Langley/* XXX remove error() calls from here? */
168bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
169d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_perm_ok(int fd, const char *filename)
170bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
171bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	struct stat st;
172bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
173bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (fstat(fd, &st) < 0)
174d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
175bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/*
176bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * if a key owned by the user is accessed, then we check the
177bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * permissions of the file. if the key owned by a different user,
178bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 * then we don't care.
179bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	 */
180bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#ifdef HAVE_CYGWIN
181bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (check_ntsec(filename))
182bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman#endif
183bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
184bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
185bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @");
186bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
187bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("Permissions 0%3.3o for '%s' are too open.",
188bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		    (u_int)st.st_mode & 0777, filename);
189d059297112922cabb0c674840589be8db821fd9aAdam Langley		error("It is recommended that your private key files are NOT accessible by others.");
190bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		error("This private key will be ignored.");
191d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_KEY_BAD_PERMISSIONS;
192bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
193d059297112922cabb0c674840589be8db821fd9aAdam Langley	return 0;
194bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
195bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
196d059297112922cabb0c674840589be8db821fd9aAdam Langley/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
197d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
198d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_private_type(int type, const char *filename, const char *passphrase,
199d059297112922cabb0c674840589be8db821fd9aAdam Langley    struct sshkey **keyp, char **commentp, int *perm_ok)
200bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
201d059297112922cabb0c674840589be8db821fd9aAdam Langley	int fd, r;
202bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
203d059297112922cabb0c674840589be8db821fd9aAdam Langley	*keyp = NULL;
204d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (commentp != NULL)
205d059297112922cabb0c674840589be8db821fd9aAdam Langley		*commentp = NULL;
206d059297112922cabb0c674840589be8db821fd9aAdam Langley
207d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((fd = open(filename, O_RDONLY)) < 0) {
208bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (perm_ok != NULL)
209bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			*perm_ok = 0;
210d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
211bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
212d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshkey_perm_ok(fd, filename) != 0) {
213bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		if (perm_ok != NULL)
214bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			*perm_ok = 0;
215d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_KEY_BAD_PERMISSIONS;
216d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
217bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
218bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if (perm_ok != NULL)
219bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		*perm_ok = 1;
220bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
221d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
222d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
223bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	close(fd);
224d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
225bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
226bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
227d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
228d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_private_type_fd(int fd, int type, const char *passphrase,
229d059297112922cabb0c674840589be8db821fd9aAdam Langley    struct sshkey **keyp, char **commentp)
230bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
231d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *buffer = NULL;
232d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
233d059297112922cabb0c674840589be8db821fd9aAdam Langley
234d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((buffer = sshbuf_new()) == NULL) {
235d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_ALLOC_FAIL;
236d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
237bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
238d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
239d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshkey_parse_private_fileblob_type(buffer, type,
240d059297112922cabb0c674840589be8db821fd9aAdam Langley	    passphrase, keyp, commentp)) != 0)
241d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
242d059297112922cabb0c674840589be8db821fd9aAdam Langley
243d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* success */
244d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
245d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
246d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (buffer != NULL)
247d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshbuf_free(buffer);
248d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
249bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
250bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
251d059297112922cabb0c674840589be8db821fd9aAdam Langley/* XXX this is almost identical to sshkey_load_private_type() */
252d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
253d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_private(const char *filename, const char *passphrase,
254d059297112922cabb0c674840589be8db821fd9aAdam Langley    struct sshkey **keyp, char **commentp)
255bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
256d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshbuf *buffer = NULL;
257d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, fd;
258d059297112922cabb0c674840589be8db821fd9aAdam Langley
259d059297112922cabb0c674840589be8db821fd9aAdam Langley	*keyp = NULL;
260d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (commentp != NULL)
261d059297112922cabb0c674840589be8db821fd9aAdam Langley		*commentp = NULL;
262d059297112922cabb0c674840589be8db821fd9aAdam Langley
263d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((fd = open(filename, O_RDONLY)) < 0)
264d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
265d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshkey_perm_ok(fd, filename) != 0) {
266d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_KEY_BAD_PERMISSIONS;
267d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
268bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
269bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
270d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((buffer = sshbuf_new()) == NULL) {
271d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_ALLOC_FAIL;
272d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
273bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
274d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_load_file(fd, buffer)) != 0 ||
275d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshkey_parse_private_fileblob(buffer, passphrase, filename,
276d059297112922cabb0c674840589be8db821fd9aAdam Langley	    keyp, commentp)) != 0)
277d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
278d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
279d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
280bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	close(fd);
281d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (buffer != NULL)
282d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshbuf_free(buffer);
283d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
284bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
285bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
286bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanstatic int
287d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
288bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
289bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	FILE *f;
290bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char line[SSH_MAX_PUBKEY_BYTES];
291bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *cp;
292bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_long linenum = 0;
293d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
294bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
295d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (commentp != NULL)
296d059297112922cabb0c674840589be8db821fd9aAdam Langley		*commentp = NULL;
297d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((f = fopen(filename, "r")) == NULL)
298d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
299d059297112922cabb0c674840589be8db821fd9aAdam Langley	while (read_keyfile_line(f, filename, line, sizeof(line),
300d059297112922cabb0c674840589be8db821fd9aAdam Langley		    &linenum) != -1) {
301d059297112922cabb0c674840589be8db821fd9aAdam Langley		cp = line;
302d059297112922cabb0c674840589be8db821fd9aAdam Langley		switch (*cp) {
303d059297112922cabb0c674840589be8db821fd9aAdam Langley		case '#':
304d059297112922cabb0c674840589be8db821fd9aAdam Langley		case '\n':
305d059297112922cabb0c674840589be8db821fd9aAdam Langley		case '\0':
306d059297112922cabb0c674840589be8db821fd9aAdam Langley			continue;
307d059297112922cabb0c674840589be8db821fd9aAdam Langley		}
308d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* Abort loading if this looks like a private key */
309d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (strncmp(cp, "-----BEGIN", 10) == 0 ||
310d059297112922cabb0c674840589be8db821fd9aAdam Langley		    strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
311d059297112922cabb0c674840589be8db821fd9aAdam Langley			break;
312d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* Skip leading whitespace. */
313d059297112922cabb0c674840589be8db821fd9aAdam Langley		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
314d059297112922cabb0c674840589be8db821fd9aAdam Langley			;
315d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (*cp) {
316d059297112922cabb0c674840589be8db821fd9aAdam Langley			if ((r = sshkey_read(k, &cp)) == 0) {
317d059297112922cabb0c674840589be8db821fd9aAdam Langley				cp[strcspn(cp, "\r\n")] = '\0';
318d059297112922cabb0c674840589be8db821fd9aAdam Langley				if (commentp) {
319d059297112922cabb0c674840589be8db821fd9aAdam Langley					*commentp = strdup(*cp ?
320d059297112922cabb0c674840589be8db821fd9aAdam Langley					    cp : filename);
321d059297112922cabb0c674840589be8db821fd9aAdam Langley					if (*commentp == NULL)
322d059297112922cabb0c674840589be8db821fd9aAdam Langley						r = SSH_ERR_ALLOC_FAIL;
323bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman				}
324d059297112922cabb0c674840589be8db821fd9aAdam Langley				fclose(f);
325d059297112922cabb0c674840589be8db821fd9aAdam Langley				return r;
326bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			}
327bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
328bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
329d059297112922cabb0c674840589be8db821fd9aAdam Langley	fclose(f);
330d059297112922cabb0c674840589be8db821fd9aAdam Langley	return SSH_ERR_INVALID_FORMAT;
331bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
332bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
333bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* load public key from ssh v1 private or any pubkey file */
334d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
335d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
336bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
337d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *pub = NULL;
338d059297112922cabb0c674840589be8db821fd9aAdam Langley	char file[PATH_MAX];
339d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r, fd;
340d059297112922cabb0c674840589be8db821fd9aAdam Langley
341d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (keyp != NULL)
342d059297112922cabb0c674840589be8db821fd9aAdam Langley		*keyp = NULL;
343d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (commentp != NULL)
344d059297112922cabb0c674840589be8db821fd9aAdam Langley		*commentp = NULL;
345bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
346d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* XXX should load file once and attempt to parse each format */
347d059297112922cabb0c674840589be8db821fd9aAdam Langley
348d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((fd = open(filename, O_RDONLY)) < 0)
349d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto skip;
350d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
351bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* try rsa1 private key */
352d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = sshkey_load_public_rsa1(fd, keyp, commentp);
353d059297112922cabb0c674840589be8db821fd9aAdam Langley	close(fd);
354d059297112922cabb0c674840589be8db821fd9aAdam Langley	switch (r) {
355d059297112922cabb0c674840589be8db821fd9aAdam Langley	case SSH_ERR_INTERNAL_ERROR:
356d059297112922cabb0c674840589be8db821fd9aAdam Langley	case SSH_ERR_ALLOC_FAIL:
357d059297112922cabb0c674840589be8db821fd9aAdam Langley	case SSH_ERR_INVALID_ARGUMENT:
358d059297112922cabb0c674840589be8db821fd9aAdam Langley	case SSH_ERR_SYSTEM_ERROR:
359d059297112922cabb0c674840589be8db821fd9aAdam Langley	case 0:
360d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
361d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
362d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
363d059297112922cabb0c674840589be8db821fd9aAdam Langley
364d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* try ssh2 public key */
365d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
366d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
367d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
368d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (keyp != NULL)
369d059297112922cabb0c674840589be8db821fd9aAdam Langley			*keyp = pub;
370d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
371d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
372d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_free(pub);
373bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
374d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_SSH1
375bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* try rsa1 public key */
376d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((pub = sshkey_new(KEY_RSA1)) == NULL)
377d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
378d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
379d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (keyp != NULL)
380d059297112922cabb0c674840589be8db821fd9aAdam Langley			*keyp = pub;
381d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
382d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
383d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_free(pub);
384d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_SSH1 */
385bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
386d059297112922cabb0c674840589be8db821fd9aAdam Langley skip:
387d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* try .pub suffix */
388d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
389d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
390d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = SSH_ERR_ALLOC_FAIL;	/* in case strlcpy or strlcat fail */
391bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	if ((strlcpy(file, filename, sizeof file) < sizeof(file)) &&
392bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	    (strlcat(file, ".pub", sizeof file) < sizeof(file)) &&
393d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshkey_try_load_public(pub, file, commentp)) == 0) {
394d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (keyp != NULL)
395d059297112922cabb0c674840589be8db821fd9aAdam Langley			*keyp = pub;
396d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
397d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
398d059297112922cabb0c674840589be8db821fd9aAdam Langley	sshkey_free(pub);
399d059297112922cabb0c674840589be8db821fd9aAdam Langley
400d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
401bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
402bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
403bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Load the certificate associated with the named private key */
404d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
405d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_cert(const char *filename, struct sshkey **keyp)
406bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
407d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *pub = NULL;
408d059297112922cabb0c674840589be8db821fd9aAdam Langley	char *file = NULL;
409d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r = SSH_ERR_INTERNAL_ERROR;
410d059297112922cabb0c674840589be8db821fd9aAdam Langley
411d059297112922cabb0c674840589be8db821fd9aAdam Langley	*keyp = NULL;
412d059297112922cabb0c674840589be8db821fd9aAdam Langley
413d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (asprintf(&file, "%s-cert.pub", filename) == -1)
414d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_ALLOC_FAIL;
415d059297112922cabb0c674840589be8db821fd9aAdam Langley
416d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
417d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
418bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
419d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
420d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
421d059297112922cabb0c674840589be8db821fd9aAdam Langley
422d059297112922cabb0c674840589be8db821fd9aAdam Langley	*keyp = pub;
423d059297112922cabb0c674840589be8db821fd9aAdam Langley	pub = NULL;
424d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
425d059297112922cabb0c674840589be8db821fd9aAdam Langley
426d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
427d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (file != NULL)
428d059297112922cabb0c674840589be8db821fd9aAdam Langley		free(file);
429d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (pub != NULL)
430d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(pub);
431d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
432bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
433bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
434bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/* Load private key and certificate */
435d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
436d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_load_private_cert(int type, const char *filename, const char *passphrase,
437d059297112922cabb0c674840589be8db821fd9aAdam Langley    struct sshkey **keyp, int *perm_ok)
438bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
439d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *key = NULL, *cert = NULL;
440d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
441d059297112922cabb0c674840589be8db821fd9aAdam Langley
442d059297112922cabb0c674840589be8db821fd9aAdam Langley	*keyp = NULL;
443bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
444bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	switch (type) {
445d059297112922cabb0c674840589be8db821fd9aAdam Langley#ifdef WITH_OPENSSL
446bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case KEY_RSA:
447bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case KEY_DSA:
448bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	case KEY_ECDSA:
449d059297112922cabb0c674840589be8db821fd9aAdam Langley	case KEY_ED25519:
450d059297112922cabb0c674840589be8db821fd9aAdam Langley#endif /* WITH_OPENSSL */
451d059297112922cabb0c674840589be8db821fd9aAdam Langley	case KEY_UNSPEC:
452bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		break;
453bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	default:
454d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_KEY_TYPE_UNKNOWN;
455bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
456bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
457d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_load_private_type(type, filename,
458d059297112922cabb0c674840589be8db821fd9aAdam Langley	    passphrase, &key, NULL, perm_ok)) != 0 ||
459d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshkey_load_cert(filename, &cert)) != 0)
460d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
461bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
462bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	/* Make sure the private key matches the certificate */
463d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (sshkey_equal_public(key, cert) == 0) {
464d059297112922cabb0c674840589be8db821fd9aAdam Langley		r = SSH_ERR_KEY_CERT_MISMATCH;
465d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
466bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
467bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
468d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((r = sshkey_to_certified(key, sshkey_cert_is_legacy(cert))) != 0 ||
469d059297112922cabb0c674840589be8db821fd9aAdam Langley	    (r = sshkey_cert_copy(cert, key)) != 0)
470d059297112922cabb0c674840589be8db821fd9aAdam Langley		goto out;
471d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = 0;
472d059297112922cabb0c674840589be8db821fd9aAdam Langley	*keyp = key;
473d059297112922cabb0c674840589be8db821fd9aAdam Langley	key = NULL;
474d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
475d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (key != NULL)
476d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(key);
477d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (cert != NULL)
478d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(cert);
479d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
480bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
481bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
482bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman/*
483d059297112922cabb0c674840589be8db821fd9aAdam Langley * Returns success if the specified "key" is listed in the file "filename",
484d059297112922cabb0c674840589be8db821fd9aAdam Langley * SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
485d059297112922cabb0c674840589be8db821fd9aAdam Langley * If "strict_type" is set then the key type must match exactly,
486bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman * otherwise a comparison that ignores certficiate data is performed.
487d059297112922cabb0c674840589be8db821fd9aAdam Langley * If "check_ca" is set and "key" is a certificate, then its CA key is
488d059297112922cabb0c674840589be8db821fd9aAdam Langley * also checked and sshkey_in_file() will return success if either is found.
489bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman */
490bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartmanint
491d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
492d059297112922cabb0c674840589be8db821fd9aAdam Langley    int check_ca)
493bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman{
494bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	FILE *f;
495bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char line[SSH_MAX_PUBKEY_BYTES];
496bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	char *cp;
497bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	u_long linenum = 0;
498d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r = 0;
499d059297112922cabb0c674840589be8db821fd9aAdam Langley	struct sshkey *pub = NULL;
500d059297112922cabb0c674840589be8db821fd9aAdam Langley	int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
501d059297112922cabb0c674840589be8db821fd9aAdam Langley	    strict_type ?  sshkey_equal : sshkey_equal_public;
502d059297112922cabb0c674840589be8db821fd9aAdam Langley
503d059297112922cabb0c674840589be8db821fd9aAdam Langley	if ((f = fopen(filename, "r")) == NULL)
504d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_SYSTEM_ERROR;
505bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
506bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	while (read_keyfile_line(f, filename, line, sizeof(line),
507d059297112922cabb0c674840589be8db821fd9aAdam Langley	    &linenum) != -1) {
508bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		cp = line;
509bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
510bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Skip leading whitespace. */
511bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
512bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			;
513bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
514bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		/* Skip comments and empty lines */
515bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		switch (*cp) {
516bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case '#':
517bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case '\n':
518bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		case '\0':
519bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman			continue;
520bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
521bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
522d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
523d059297112922cabb0c674840589be8db821fd9aAdam Langley			r = SSH_ERR_ALLOC_FAIL;
524d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto out;
525bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
526d059297112922cabb0c674840589be8db821fd9aAdam Langley		if ((r = sshkey_read(pub, &cp)) != 0)
527d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto out;
528d059297112922cabb0c674840589be8db821fd9aAdam Langley		if (sshkey_compare(key, pub) ||
529d059297112922cabb0c674840589be8db821fd9aAdam Langley		    (check_ca && sshkey_is_cert(key) &&
530d059297112922cabb0c674840589be8db821fd9aAdam Langley		    sshkey_compare(key->cert->signature_key, pub))) {
531d059297112922cabb0c674840589be8db821fd9aAdam Langley			r = 0;
532d059297112922cabb0c674840589be8db821fd9aAdam Langley			goto out;
533bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman		}
534d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(pub);
535d059297112922cabb0c674840589be8db821fd9aAdam Langley		pub = NULL;
536bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	}
537d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = SSH_ERR_KEY_NOT_FOUND;
538d059297112922cabb0c674840589be8db821fd9aAdam Langley out:
539d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (pub != NULL)
540d059297112922cabb0c674840589be8db821fd9aAdam Langley		sshkey_free(pub);
541bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman	fclose(f);
542d059297112922cabb0c674840589be8db821fd9aAdam Langley	return r;
543d059297112922cabb0c674840589be8db821fd9aAdam Langley}
544d059297112922cabb0c674840589be8db821fd9aAdam Langley
545d059297112922cabb0c674840589be8db821fd9aAdam Langley/*
546d059297112922cabb0c674840589be8db821fd9aAdam Langley * Checks whether the specified key is revoked, returning 0 if not,
547d059297112922cabb0c674840589be8db821fd9aAdam Langley * SSH_ERR_KEY_REVOKED if it is or another error code if something
548d059297112922cabb0c674840589be8db821fd9aAdam Langley * unexpected happened.
549d059297112922cabb0c674840589be8db821fd9aAdam Langley * This will check both the key and, if it is a certificate, its CA key too.
550d059297112922cabb0c674840589be8db821fd9aAdam Langley * "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
551d059297112922cabb0c674840589be8db821fd9aAdam Langley */
552d059297112922cabb0c674840589be8db821fd9aAdam Langleyint
553d059297112922cabb0c674840589be8db821fd9aAdam Langleysshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
554d059297112922cabb0c674840589be8db821fd9aAdam Langley{
555d059297112922cabb0c674840589be8db821fd9aAdam Langley	int r;
556d059297112922cabb0c674840589be8db821fd9aAdam Langley
557d059297112922cabb0c674840589be8db821fd9aAdam Langley	r = ssh_krl_file_contains_key(revoked_keys_file, key);
558d059297112922cabb0c674840589be8db821fd9aAdam Langley	/* If this was not a KRL to begin with then continue below */
559d059297112922cabb0c674840589be8db821fd9aAdam Langley	if (r != SSH_ERR_KRL_BAD_MAGIC)
560d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
561d059297112922cabb0c674840589be8db821fd9aAdam Langley
562d059297112922cabb0c674840589be8db821fd9aAdam Langley	/*
563d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * If the file is not a KRL or we can't handle KRLs then attempt to
564d059297112922cabb0c674840589be8db821fd9aAdam Langley	 * parse the file as a flat list of keys.
565d059297112922cabb0c674840589be8db821fd9aAdam Langley	 */
566d059297112922cabb0c674840589be8db821fd9aAdam Langley	switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
567d059297112922cabb0c674840589be8db821fd9aAdam Langley	case 0:
568d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* Key found => revoked */
569d059297112922cabb0c674840589be8db821fd9aAdam Langley		return SSH_ERR_KEY_REVOKED;
570d059297112922cabb0c674840589be8db821fd9aAdam Langley	case SSH_ERR_KEY_NOT_FOUND:
571d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* Key not found => not revoked */
572d059297112922cabb0c674840589be8db821fd9aAdam Langley		return 0;
573d059297112922cabb0c674840589be8db821fd9aAdam Langley	default:
574d059297112922cabb0c674840589be8db821fd9aAdam Langley		/* Some other error occurred */
575d059297112922cabb0c674840589be8db821fd9aAdam Langley		return r;
576d059297112922cabb0c674840589be8db821fd9aAdam Langley	}
577bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman}
578bd77cf78387b72b7b3ea870459077672bf75c3b5Greg Hartman
579