freebsd-skq/crypto/openssh/authfile.c

539 lines
13 KiB
C
Raw Normal View History

2019-02-05 15:03:53 +00:00
/* $OpenBSD: authfile.c,v 1.131 2018/09/21 12:20:12 djm Exp $ */
/*
2014-01-30 10:56:49 +00:00
* Copyright (c) 2000, 2013 Markus Friedl. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
2015-01-05 16:09:55 +00:00
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
2015-07-02 13:15:34 +00:00
#include <limits.h>
#include "cipher.h"
#include "ssh.h"
#include "log.h"
#include "authfile.h"
#include "misc.h"
#include "atomicio.h"
2015-08-26 09:25:17 +00:00
#include "sshkey.h"
2015-01-05 16:09:55 +00:00
#include "sshbuf.h"
#include "ssherr.h"
2015-07-02 13:15:34 +00:00
#include "krl.h"
2011-09-28 08:14:41 +00:00
#define MAX_KEY_FILE_SIZE (1024 * 1024)
2011-02-17 11:47:40 +00:00
/* Save a key blob to a file */
static int
2015-01-05 16:09:55 +00:00
sshkey_save_private_blob(struct sshbuf *keybuf, const char *filename)
2011-02-17 11:47:40 +00:00
{
2015-01-05 16:09:55 +00:00
int fd, oerrno;
2011-02-17 11:47:40 +00:00
2015-01-05 16:09:55 +00:00
if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)
return SSH_ERR_SYSTEM_ERROR;
2018-08-28 10:47:58 +00:00
if (atomicio(vwrite, fd, sshbuf_mutable_ptr(keybuf),
2015-01-05 16:09:55 +00:00
sshbuf_len(keybuf)) != sshbuf_len(keybuf)) {
oerrno = errno;
2011-02-17 11:47:40 +00:00
close(fd);
unlink(filename);
2015-01-05 16:09:55 +00:00
errno = oerrno;
return SSH_ERR_SYSTEM_ERROR;
2011-02-17 11:47:40 +00:00
}
close(fd);
2015-01-05 16:09:55 +00:00
return 0;
2011-02-17 11:47:40 +00:00
}
int
2015-01-05 16:09:55 +00:00
sshkey_save_private(struct sshkey *key, const char *filename,
const char *passphrase, const char *comment,
int force_new_format, const char *new_format_cipher, int new_format_rounds)
2011-02-17 11:47:40 +00:00
{
2015-01-05 16:09:55 +00:00
struct sshbuf *keyblob = NULL;
int r;
2011-02-17 11:47:40 +00:00
2015-01-05 16:09:55 +00:00
if ((keyblob = sshbuf_new()) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_private_to_fileblob(key, keyblob, passphrase, comment,
force_new_format, new_format_cipher, new_format_rounds)) != 0)
2011-02-17 11:47:40 +00:00
goto out;
2015-01-05 16:09:55 +00:00
if ((r = sshkey_save_private_blob(keyblob, filename)) != 0)
2011-02-17 11:47:40 +00:00
goto out;
2015-01-05 16:09:55 +00:00
r = 0;
2011-02-17 11:47:40 +00:00
out:
2015-01-05 16:09:55 +00:00
sshbuf_free(keyblob);
return r;
2011-02-17 11:47:40 +00:00
}
2011-09-28 08:14:41 +00:00
/* Load a key from a fd into a buffer */
int
2015-07-02 13:15:34 +00:00
sshkey_load_file(int fd, struct sshbuf *blob)
2011-02-17 11:47:40 +00:00
{
2011-09-28 08:14:41 +00:00
u_char buf[1024];
size_t len;
2011-02-17 11:47:40 +00:00
struct stat st;
2018-05-06 12:24:45 +00:00
int r;
2015-01-05 16:09:55 +00:00
if (fstat(fd, &st) < 0)
return SSH_ERR_SYSTEM_ERROR;
2011-09-28 08:14:41 +00:00
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
2015-01-05 16:09:55 +00:00
st.st_size > MAX_KEY_FILE_SIZE)
return SSH_ERR_INVALID_FORMAT;
2011-09-28 08:14:41 +00:00
for (;;) {
if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) {
if (errno == EPIPE)
break;
2015-01-05 16:09:55 +00:00
r = SSH_ERR_SYSTEM_ERROR;
goto out;
2011-09-28 08:14:41 +00:00
}
2015-01-05 16:09:55 +00:00
if ((r = sshbuf_put(blob, buf, len)) != 0)
goto out;
if (sshbuf_len(blob) > MAX_KEY_FILE_SIZE) {
r = SSH_ERR_INVALID_FORMAT;
goto out;
2011-09-28 08:14:41 +00:00
}
}
if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 &&
2015-01-05 16:09:55 +00:00
st.st_size != (off_t)sshbuf_len(blob)) {
r = SSH_ERR_FILE_CHANGED;
goto out;
}
2015-01-05 16:09:55 +00:00
r = 0;
2011-09-28 08:14:41 +00:00
2015-01-05 16:09:55 +00:00
out:
explicit_bzero(buf, sizeof(buf));
if (r != 0)
sshbuf_reset(blob);
return r;
2011-02-17 11:47:40 +00:00
}
2015-01-05 16:09:55 +00:00
/* XXX remove error() calls from here? */
int
2015-01-05 16:09:55 +00:00
sshkey_perm_ok(int fd, const char *filename)
{
struct stat st;
if (fstat(fd, &st) < 0)
2015-01-05 16:09:55 +00:00
return SSH_ERR_SYSTEM_ERROR;
/*
* if a key owned by the user is accessed, then we check the
* permissions of the file. if the key owned by a different user,
* then we don't care.
*/
#ifdef HAVE_CYGWIN
if (check_ntsec(filename))
#endif
if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) {
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @");
error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
error("Permissions 0%3.3o for '%s' are too open.",
(u_int)st.st_mode & 0777, filename);
2015-07-02 13:18:50 +00:00
error("It is required that your private key files are NOT accessible by others.");
error("This private key will be ignored.");
2015-01-05 16:09:55 +00:00
return SSH_ERR_KEY_BAD_PERMISSIONS;
}
2015-01-05 16:09:55 +00:00
return 0;
}
2015-01-05 16:09:55 +00:00
/* XXX kill perm_ok now that we have SSH_ERR_KEY_BAD_PERMISSIONS? */
int
sshkey_load_private_type(int type, const char *filename, const char *passphrase,
struct sshkey **keyp, char **commentp, int *perm_ok)
2011-02-17 11:47:40 +00:00
{
2015-01-05 16:09:55 +00:00
int fd, r;
2014-01-30 10:56:49 +00:00
2017-01-31 12:29:48 +00:00
if (keyp != NULL)
*keyp = NULL;
2015-01-05 16:09:55 +00:00
if (commentp != NULL)
*commentp = NULL;
2015-01-05 16:09:55 +00:00
if ((fd = open(filename, O_RDONLY)) < 0) {
2010-03-08 11:19:52 +00:00
if (perm_ok != NULL)
*perm_ok = 0;
2015-01-05 16:09:55 +00:00
return SSH_ERR_SYSTEM_ERROR;
2010-03-08 11:19:52 +00:00
}
2015-01-05 16:09:55 +00:00
if (sshkey_perm_ok(fd, filename) != 0) {
if (perm_ok != NULL)
*perm_ok = 0;
2015-01-05 16:09:55 +00:00
r = SSH_ERR_KEY_BAD_PERMISSIONS;
goto out;
}
if (perm_ok != NULL)
*perm_ok = 1;
2011-02-17 11:47:40 +00:00
2015-07-02 13:15:34 +00:00
r = sshkey_load_private_type_fd(fd, type, passphrase, keyp, commentp);
2018-05-06 12:27:04 +00:00
if (r == 0 && keyp && *keyp)
r = sshkey_set_filename(*keyp, filename);
2015-07-02 13:15:34 +00:00
out:
close(fd);
return r;
}
int
sshkey_load_private_type_fd(int fd, int type, const char *passphrase,
struct sshkey **keyp, char **commentp)
{
struct sshbuf *buffer = NULL;
int r;
2017-01-31 12:29:48 +00:00
if (keyp != NULL)
*keyp = NULL;
2015-01-05 16:09:55 +00:00
if ((buffer = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
2015-07-02 13:15:34 +00:00
if ((r = sshkey_load_file(fd, buffer)) != 0 ||
(r = sshkey_parse_private_fileblob_type(buffer, type,
passphrase, keyp, commentp)) != 0)
2015-01-05 16:09:55 +00:00
goto out;
2015-07-02 13:15:34 +00:00
/* success */
2015-01-05 16:09:55 +00:00
r = 0;
out:
2016-03-10 20:10:25 +00:00
sshbuf_free(buffer);
2015-01-05 16:09:55 +00:00
return r;
}
2015-01-05 16:09:55 +00:00
/* XXX this is almost identical to sshkey_load_private_type() */
int
sshkey_load_private(const char *filename, const char *passphrase,
struct sshkey **keyp, char **commentp)
2011-09-28 08:14:41 +00:00
{
2015-01-05 16:09:55 +00:00
struct sshbuf *buffer = NULL;
int r, fd;
2011-09-28 08:14:41 +00:00
2017-01-31 12:29:48 +00:00
if (keyp != NULL)
*keyp = NULL;
2015-01-05 16:09:55 +00:00
if (commentp != NULL)
*commentp = NULL;
2015-01-05 16:09:55 +00:00
if ((fd = open(filename, O_RDONLY)) < 0)
return SSH_ERR_SYSTEM_ERROR;
if (sshkey_perm_ok(fd, filename) != 0) {
r = SSH_ERR_KEY_BAD_PERMISSIONS;
goto out;
}
2011-02-17 11:47:40 +00:00
2015-01-05 16:09:55 +00:00
if ((buffer = sshbuf_new()) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
2011-02-17 11:47:40 +00:00
}
2015-07-02 13:15:34 +00:00
if ((r = sshkey_load_file(fd, buffer)) != 0 ||
2016-03-10 20:10:25 +00:00
(r = sshkey_parse_private_fileblob(buffer, passphrase, keyp,
commentp)) != 0)
2015-01-05 16:09:55 +00:00
goto out;
2018-05-06 12:27:04 +00:00
if (keyp && *keyp &&
(r = sshkey_set_filename(*keyp, filename)) != 0)
goto out;
2015-01-05 16:09:55 +00:00
r = 0;
out:
2011-02-17 11:47:40 +00:00
close(fd);
2016-03-10 20:10:25 +00:00
sshbuf_free(buffer);
2015-01-05 16:09:55 +00:00
return r;
}
static int
2015-01-05 16:09:55 +00:00
sshkey_try_load_public(struct sshkey *k, const char *filename, char **commentp)
{
FILE *f;
2018-08-28 10:47:58 +00:00
char *line = NULL, *cp;
size_t linesize = 0;
2015-01-05 16:09:55 +00:00
int r;
2015-01-05 16:09:55 +00:00
if (commentp != NULL)
*commentp = NULL;
if ((f = fopen(filename, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
2018-08-28 10:47:58 +00:00
while (getline(&line, &linesize, f) != -1) {
2015-01-05 16:09:55 +00:00
cp = line;
switch (*cp) {
case '#':
case '\n':
case '\0':
continue;
}
/* Abort loading if this looks like a private key */
if (strncmp(cp, "-----BEGIN", 10) == 0 ||
strcmp(cp, "SSH PRIVATE KEY FILE") == 0)
break;
/* Skip leading whitespace. */
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
;
if (*cp) {
if ((r = sshkey_read(k, &cp)) == 0) {
cp[strcspn(cp, "\r\n")] = '\0';
if (commentp) {
*commentp = strdup(*cp ?
cp : filename);
if (*commentp == NULL)
r = SSH_ERR_ALLOC_FAIL;
}
2018-08-28 10:47:58 +00:00
free(line);
2015-01-05 16:09:55 +00:00
fclose(f);
return r;
}
}
}
2018-08-28 10:47:58 +00:00
free(line);
2015-01-05 16:09:55 +00:00
fclose(f);
return SSH_ERR_INVALID_FORMAT;
}
2018-05-06 12:24:45 +00:00
/* load public key from any pubkey file */
2015-01-05 16:09:55 +00:00
int
sshkey_load_public(const char *filename, struct sshkey **keyp, char **commentp)
{
2015-01-05 16:09:55 +00:00
struct sshkey *pub = NULL;
2018-05-06 12:24:45 +00:00
char *file = NULL;
int r;
2015-01-05 16:09:55 +00:00
if (keyp != NULL)
*keyp = NULL;
if (commentp != NULL)
*commentp = NULL;
2015-01-05 16:09:55 +00:00
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL)
return SSH_ERR_ALLOC_FAIL;
if ((r = sshkey_try_load_public(pub, filename, commentp)) == 0) {
2018-05-06 12:24:45 +00:00
if (keyp != NULL) {
2015-01-05 16:09:55 +00:00
*keyp = pub;
2018-05-06 12:24:45 +00:00
pub = NULL;
}
r = 0;
goto out;
2015-01-05 16:09:55 +00:00
}
sshkey_free(pub);
2015-01-05 16:09:55 +00:00
/* try .pub suffix */
2018-05-06 12:24:45 +00:00
if (asprintf(&file, "%s.pub", filename) == -1)
2015-01-05 16:09:55 +00:00
return SSH_ERR_ALLOC_FAIL;
2018-05-06 12:24:45 +00:00
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
}
if ((r = sshkey_try_load_public(pub, file, commentp)) == 0) {
if (keyp != NULL) {
2015-01-05 16:09:55 +00:00
*keyp = pub;
2018-05-06 12:24:45 +00:00
pub = NULL;
}
r = 0;
2015-01-05 16:09:55 +00:00
}
2018-05-06 12:24:45 +00:00
out:
free(file);
2015-01-05 16:09:55 +00:00
sshkey_free(pub);
return r;
}
2010-03-08 11:19:52 +00:00
2010-11-08 10:45:44 +00:00
/* Load the certificate associated with the named private key */
2015-01-05 16:09:55 +00:00
int
sshkey_load_cert(const char *filename, struct sshkey **keyp)
2010-11-08 10:45:44 +00:00
{
2015-01-05 16:09:55 +00:00
struct sshkey *pub = NULL;
char *file = NULL;
int r = SSH_ERR_INTERNAL_ERROR;
2010-11-08 10:45:44 +00:00
2017-01-31 12:29:48 +00:00
if (keyp != NULL)
*keyp = NULL;
2015-01-05 16:09:55 +00:00
if (asprintf(&file, "%s-cert.pub", filename) == -1)
return SSH_ERR_ALLOC_FAIL;
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
goto out;
2010-11-08 10:45:44 +00:00
}
2015-01-05 16:09:55 +00:00
if ((r = sshkey_try_load_public(pub, file, NULL)) != 0)
goto out;
2017-01-31 12:29:48 +00:00
/* success */
if (keyp != NULL) {
*keyp = pub;
pub = NULL;
}
2015-01-05 16:09:55 +00:00
r = 0;
out:
2016-03-10 20:10:25 +00:00
free(file);
sshkey_free(pub);
2015-01-05 16:09:55 +00:00
return r;
2010-11-08 10:45:44 +00:00
}
/* Load private key and certificate */
2015-01-05 16:09:55 +00:00
int
sshkey_load_private_cert(int type, const char *filename, const char *passphrase,
struct sshkey **keyp, int *perm_ok)
2010-11-08 10:45:44 +00:00
{
2015-01-05 16:09:55 +00:00
struct sshkey *key = NULL, *cert = NULL;
int r;
2017-01-31 12:29:48 +00:00
if (keyp != NULL)
*keyp = NULL;
2010-11-08 10:45:44 +00:00
switch (type) {
2015-01-05 16:09:55 +00:00
#ifdef WITH_OPENSSL
2010-11-08 10:45:44 +00:00
case KEY_RSA:
case KEY_DSA:
2011-02-17 11:47:40 +00:00
case KEY_ECDSA:
2015-01-05 16:09:55 +00:00
#endif /* WITH_OPENSSL */
2015-08-26 09:25:17 +00:00
case KEY_ED25519:
2018-05-06 12:27:04 +00:00
case KEY_XMSS:
2015-01-05 16:09:55 +00:00
case KEY_UNSPEC:
2010-11-08 10:45:44 +00:00
break;
default:
2015-01-05 16:09:55 +00:00
return SSH_ERR_KEY_TYPE_UNKNOWN;
2010-11-08 10:45:44 +00:00
}
2015-01-05 16:09:55 +00:00
if ((r = sshkey_load_private_type(type, filename,
passphrase, &key, NULL, perm_ok)) != 0 ||
(r = sshkey_load_cert(filename, &cert)) != 0)
goto out;
2010-11-08 10:45:44 +00:00
/* Make sure the private key matches the certificate */
2015-01-05 16:09:55 +00:00
if (sshkey_equal_public(key, cert) == 0) {
r = SSH_ERR_KEY_CERT_MISMATCH;
goto out;
2010-11-08 10:45:44 +00:00
}
2015-08-26 09:25:17 +00:00
if ((r = sshkey_to_certified(key)) != 0 ||
2015-01-05 16:09:55 +00:00
(r = sshkey_cert_copy(cert, key)) != 0)
goto out;
r = 0;
2017-01-31 12:29:48 +00:00
if (keyp != NULL) {
*keyp = key;
key = NULL;
}
2015-01-05 16:09:55 +00:00
out:
2016-03-10 20:10:25 +00:00
sshkey_free(key);
sshkey_free(cert);
2015-01-05 16:09:55 +00:00
return r;
2010-11-08 10:45:44 +00:00
}
2010-03-08 11:19:52 +00:00
/*
2015-01-05 16:09:55 +00:00
* Returns success if the specified "key" is listed in the file "filename",
* SSH_ERR_KEY_NOT_FOUND: if the key is not listed or another error.
2015-07-02 13:15:34 +00:00
* If "strict_type" is set then the key type must match exactly,
2010-03-08 11:19:52 +00:00
* otherwise a comparison that ignores certficiate data is performed.
2015-07-02 13:15:34 +00:00
* If "check_ca" is set and "key" is a certificate, then its CA key is
* also checked and sshkey_in_file() will return success if either is found.
2010-03-08 11:19:52 +00:00
*/
int
2015-07-02 13:15:34 +00:00
sshkey_in_file(struct sshkey *key, const char *filename, int strict_type,
int check_ca)
2010-03-08 11:19:52 +00:00
{
FILE *f;
2018-08-28 10:47:58 +00:00
char *line = NULL, *cp;
size_t linesize = 0;
2015-01-05 16:09:55 +00:00
int r = 0;
struct sshkey *pub = NULL;
2018-08-28 10:47:58 +00:00
2015-01-05 16:09:55 +00:00
int (*sshkey_compare)(const struct sshkey *, const struct sshkey *) =
strict_type ? sshkey_equal : sshkey_equal_public;
2010-03-08 11:19:52 +00:00
2015-07-02 13:15:34 +00:00
if ((f = fopen(filename, "r")) == NULL)
return SSH_ERR_SYSTEM_ERROR;
2010-03-08 11:19:52 +00:00
2018-08-28 10:47:58 +00:00
while (getline(&line, &linesize, f) != -1) {
2019-02-05 15:03:53 +00:00
sshkey_free(pub);
pub = NULL;
2010-03-08 11:19:52 +00:00
cp = line;
/* Skip leading whitespace. */
for (; *cp && (*cp == ' ' || *cp == '\t'); cp++)
;
/* Skip comments and empty lines */
switch (*cp) {
case '#':
case '\n':
case '\0':
continue;
}
2015-01-05 16:09:55 +00:00
if ((pub = sshkey_new(KEY_UNSPEC)) == NULL) {
r = SSH_ERR_ALLOC_FAIL;
goto out;
2010-03-08 11:19:52 +00:00
}
2019-02-05 15:03:53 +00:00
switch (r = sshkey_read(pub, &cp)) {
case 0:
break;
case SSH_ERR_KEY_LENGTH:
continue;
default:
2015-01-05 16:09:55 +00:00
goto out;
2019-02-05 15:03:53 +00:00
}
2015-07-02 13:15:34 +00:00
if (sshkey_compare(key, pub) ||
(check_ca && sshkey_is_cert(key) &&
sshkey_compare(key->cert->signature_key, pub))) {
2015-01-05 16:09:55 +00:00
r = 0;
goto out;
2010-03-08 11:19:52 +00:00
}
}
2015-01-05 16:09:55 +00:00
r = SSH_ERR_KEY_NOT_FOUND;
out:
2018-08-28 10:47:58 +00:00
free(line);
2016-03-10 20:10:25 +00:00
sshkey_free(pub);
2010-03-08 11:19:52 +00:00
fclose(f);
2015-01-05 16:09:55 +00:00
return r;
2010-03-08 11:19:52 +00:00
}
2015-01-05 16:09:55 +00:00
2015-07-02 13:15:34 +00:00
/*
* Checks whether the specified key is revoked, returning 0 if not,
* SSH_ERR_KEY_REVOKED if it is or another error code if something
* unexpected happened.
* This will check both the key and, if it is a certificate, its CA key too.
* "revoked_keys_file" may be a KRL or a one-per-line list of public keys.
*/
int
sshkey_check_revoked(struct sshkey *key, const char *revoked_keys_file)
{
int r;
r = ssh_krl_file_contains_key(revoked_keys_file, key);
/* If this was not a KRL to begin with then continue below */
if (r != SSH_ERR_KRL_BAD_MAGIC)
return r;
/*
* If the file is not a KRL or we can't handle KRLs then attempt to
* parse the file as a flat list of keys.
*/
switch ((r = sshkey_in_file(key, revoked_keys_file, 0, 1))) {
case 0:
/* Key found => revoked */
return SSH_ERR_KEY_REVOKED;
case SSH_ERR_KEY_NOT_FOUND:
/* Key not found => not revoked */
return 0;
default:
/* Some other error occurred */
return r;
}
}