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