1*e2f6069cSDag-Erling Smørgrav /* $OpenBSD: authfile.c,v 1.82 2010/08/04 05:49:22 djm Exp $ */ 2511b41d2SMark Murray /* 3511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 4511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5511b41d2SMark Murray * All rights reserved 6511b41d2SMark Murray * This file contains functions for reading and writing identity files, and 7511b41d2SMark Murray * for reading the passphrase from the user. 8511b41d2SMark Murray * 9c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 10c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 11c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 12c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 13c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 14c2d3a559SKris Kennaway * 15c2d3a559SKris Kennaway * 16c2d3a559SKris Kennaway * Copyright (c) 2000 Markus Friedl. All rights reserved. 17c2d3a559SKris Kennaway * 18c2d3a559SKris Kennaway * Redistribution and use in source and binary forms, with or without 19c2d3a559SKris Kennaway * modification, are permitted provided that the following conditions 20c2d3a559SKris Kennaway * are met: 21c2d3a559SKris Kennaway * 1. Redistributions of source code must retain the above copyright 22c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer. 23c2d3a559SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 24c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer in the 25c2d3a559SKris Kennaway * documentation and/or other materials provided with the distribution. 26c2d3a559SKris Kennaway * 27c2d3a559SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28c2d3a559SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29c2d3a559SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30c2d3a559SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31c2d3a559SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32c2d3a559SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33c2d3a559SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34c2d3a559SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35c2d3a559SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36c2d3a559SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37511b41d2SMark Murray */ 38511b41d2SMark Murray 39511b41d2SMark Murray #include "includes.h" 40333ee039SDag-Erling Smørgrav 41333ee039SDag-Erling Smørgrav #include <sys/types.h> 42333ee039SDag-Erling Smørgrav #include <sys/stat.h> 43333ee039SDag-Erling Smørgrav #include <sys/param.h> 44333ee039SDag-Erling Smørgrav #include <sys/uio.h> 45511b41d2SMark Murray 46ca3176e7SBrian Feldman #include <openssl/err.h> 47e8aafc91SKris Kennaway #include <openssl/evp.h> 48ca3176e7SBrian Feldman #include <openssl/pem.h> 49e8aafc91SKris Kennaway 50b15c8340SDag-Erling Smørgrav /* compatibility with old or broken OpenSSL versions */ 51b15c8340SDag-Erling Smørgrav #include "openbsd-compat/openssl-compat.h" 52b15c8340SDag-Erling Smørgrav 53333ee039SDag-Erling Smørgrav #include <errno.h> 54333ee039SDag-Erling Smørgrav #include <fcntl.h> 55333ee039SDag-Erling Smørgrav #include <stdarg.h> 56333ee039SDag-Erling Smørgrav #include <stdio.h> 57333ee039SDag-Erling Smørgrav #include <stdlib.h> 58333ee039SDag-Erling Smørgrav #include <string.h> 59333ee039SDag-Erling Smørgrav #include <unistd.h> 60333ee039SDag-Erling Smørgrav 61511b41d2SMark Murray #include "xmalloc.h" 62333ee039SDag-Erling Smørgrav #include "cipher.h" 63511b41d2SMark Murray #include "buffer.h" 64e8aafc91SKris Kennaway #include "key.h" 65ca3176e7SBrian Feldman #include "ssh.h" 66ca3176e7SBrian Feldman #include "log.h" 67ca3176e7SBrian Feldman #include "authfile.h" 68af12a3e7SDag-Erling Smørgrav #include "rsa.h" 69aa49c926SDag-Erling Smørgrav #include "misc.h" 70d4ecd108SDag-Erling Smørgrav #include "atomicio.h" 71511b41d2SMark Murray 72ca3176e7SBrian Feldman /* Version identification string for SSH v1 identity files. */ 73ca3176e7SBrian Feldman static const char authfile_id_string[] = 74ca3176e7SBrian Feldman "SSH PRIVATE KEY FILE FORMAT 1.1\n"; 75511b41d2SMark Murray 76511b41d2SMark Murray /* 77511b41d2SMark Murray * Saves the authentication (private) key in a file, encrypting it with 78511b41d2SMark Murray * passphrase. The identification of the file (lowest 64 bits of n) will 79511b41d2SMark Murray * precede the key to provide identification of the key without needing a 80511b41d2SMark Murray * passphrase. 81511b41d2SMark Murray */ 82511b41d2SMark Murray 83af12a3e7SDag-Erling Smørgrav static int 84ca3176e7SBrian Feldman key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, 85ca3176e7SBrian Feldman const char *comment) 86511b41d2SMark Murray { 87511b41d2SMark Murray Buffer buffer, encrypted; 88af12a3e7SDag-Erling Smørgrav u_char buf[100], *cp; 89af12a3e7SDag-Erling Smørgrav int fd, i, cipher_num; 9009958426SBrian Feldman CipherContext ciphercontext; 9109958426SBrian Feldman Cipher *cipher; 9221e764dfSDag-Erling Smørgrav u_int32_t rnd; 93511b41d2SMark Murray 94511b41d2SMark Murray /* 95511b41d2SMark Murray * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting 96511b41d2SMark Murray * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. 97511b41d2SMark Murray */ 98af12a3e7SDag-Erling Smørgrav cipher_num = (strcmp(passphrase, "") == 0) ? 99af12a3e7SDag-Erling Smørgrav SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; 100af12a3e7SDag-Erling Smørgrav if ((cipher = cipher_by_number(cipher_num)) == NULL) 10109958426SBrian Feldman fatal("save_private_key_rsa: bad cipher"); 102511b41d2SMark Murray 103511b41d2SMark Murray /* This buffer is used to built the secret part of the private key. */ 104511b41d2SMark Murray buffer_init(&buffer); 105511b41d2SMark Murray 106511b41d2SMark Murray /* Put checkbytes for checking passphrase validity. */ 10721e764dfSDag-Erling Smørgrav rnd = arc4random(); 10821e764dfSDag-Erling Smørgrav buf[0] = rnd & 0xff; 10921e764dfSDag-Erling Smørgrav buf[1] = (rnd >> 8) & 0xff; 110511b41d2SMark Murray buf[2] = buf[0]; 111511b41d2SMark Murray buf[3] = buf[1]; 112511b41d2SMark Murray buffer_append(&buffer, buf, 4); 113511b41d2SMark Murray 114511b41d2SMark Murray /* 115511b41d2SMark Murray * Store the private key (n and e will not be stored because they 116511b41d2SMark Murray * will be stored in plain text, and storing them also in encrypted 117511b41d2SMark Murray * format would just give known plaintext). 118511b41d2SMark Murray */ 119ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->d); 120ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->iqmp); 121ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ 122ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ 123511b41d2SMark Murray 124511b41d2SMark Murray /* Pad the part to be encrypted until its size is a multiple of 8. */ 125511b41d2SMark Murray while (buffer_len(&buffer) % 8 != 0) 126511b41d2SMark Murray buffer_put_char(&buffer, 0); 127511b41d2SMark Murray 128511b41d2SMark Murray /* This buffer will be used to contain the data in the file. */ 129511b41d2SMark Murray buffer_init(&encrypted); 130511b41d2SMark Murray 131511b41d2SMark Murray /* First store keyfile id string. */ 132ca3176e7SBrian Feldman for (i = 0; authfile_id_string[i]; i++) 133ca3176e7SBrian Feldman buffer_put_char(&encrypted, authfile_id_string[i]); 134511b41d2SMark Murray buffer_put_char(&encrypted, 0); 135511b41d2SMark Murray 136511b41d2SMark Murray /* Store cipher type. */ 137af12a3e7SDag-Erling Smørgrav buffer_put_char(&encrypted, cipher_num); 138511b41d2SMark Murray buffer_put_int(&encrypted, 0); /* For future extension */ 139511b41d2SMark Murray 140511b41d2SMark Murray /* Store public key. This will be in plain text. */ 141ca3176e7SBrian Feldman buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); 142ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->n); 143ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->e); 144af12a3e7SDag-Erling Smørgrav buffer_put_cstring(&encrypted, comment); 145511b41d2SMark Murray 146511b41d2SMark Murray /* Allocate space for the private part of the key in the buffer. */ 147af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&encrypted, buffer_len(&buffer)); 148511b41d2SMark Murray 149af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 150af12a3e7SDag-Erling Smørgrav CIPHER_ENCRYPT); 151af12a3e7SDag-Erling Smørgrav cipher_crypt(&ciphercontext, cp, 152af12a3e7SDag-Erling Smørgrav buffer_ptr(&buffer), buffer_len(&buffer)); 153af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 15409958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 155511b41d2SMark Murray 156511b41d2SMark Murray /* Destroy temporary data. */ 157511b41d2SMark Murray memset(buf, 0, sizeof(buf)); 158511b41d2SMark Murray buffer_free(&buffer); 159511b41d2SMark Murray 160511b41d2SMark Murray fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); 161ca3176e7SBrian Feldman if (fd < 0) { 162ca3176e7SBrian Feldman error("open %s failed: %s.", filename, strerror(errno)); 1631ec0d754SDag-Erling Smørgrav buffer_free(&encrypted); 164511b41d2SMark Murray return 0; 165ca3176e7SBrian Feldman } 166d4ecd108SDag-Erling Smørgrav if (atomicio(vwrite, fd, buffer_ptr(&encrypted), 167d4ecd108SDag-Erling Smørgrav buffer_len(&encrypted)) != buffer_len(&encrypted)) { 168ca3176e7SBrian Feldman error("write to key file %s failed: %s", filename, 169511b41d2SMark Murray strerror(errno)); 170511b41d2SMark Murray buffer_free(&encrypted); 171511b41d2SMark Murray close(fd); 172ca3176e7SBrian Feldman unlink(filename); 173511b41d2SMark Murray return 0; 174511b41d2SMark Murray } 175511b41d2SMark Murray close(fd); 176511b41d2SMark Murray buffer_free(&encrypted); 177511b41d2SMark Murray return 1; 178511b41d2SMark Murray } 179511b41d2SMark Murray 180ca3176e7SBrian Feldman /* save SSH v2 key in OpenSSL PEM format */ 181af12a3e7SDag-Erling Smørgrav static int 182ca3176e7SBrian Feldman key_save_private_pem(Key *key, const char *filename, const char *_passphrase, 183ca3176e7SBrian Feldman const char *comment) 184e8aafc91SKris Kennaway { 185e8aafc91SKris Kennaway FILE *fp; 186e8aafc91SKris Kennaway int fd; 187ca3176e7SBrian Feldman int success = 0; 188ca3176e7SBrian Feldman int len = strlen(_passphrase); 189af12a3e7SDag-Erling Smørgrav u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; 190b15c8340SDag-Erling Smørgrav #if (OPENSSL_VERSION_NUMBER < 0x00907000L) 191af12a3e7SDag-Erling Smørgrav const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; 192b15c8340SDag-Erling Smørgrav #else 193b15c8340SDag-Erling Smørgrav const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; 194b15c8340SDag-Erling Smørgrav #endif 195e8aafc91SKris Kennaway 196e8aafc91SKris Kennaway if (len > 0 && len <= 4) { 197ca3176e7SBrian Feldman error("passphrase too short: have %d bytes, need > 4", len); 198e8aafc91SKris Kennaway return 0; 199e8aafc91SKris Kennaway } 200e8aafc91SKris Kennaway fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); 201e8aafc91SKris Kennaway if (fd < 0) { 202ca3176e7SBrian Feldman error("open %s failed: %s.", filename, strerror(errno)); 203e8aafc91SKris Kennaway return 0; 204e8aafc91SKris Kennaway } 205e8aafc91SKris Kennaway fp = fdopen(fd, "w"); 206e8aafc91SKris Kennaway if (fp == NULL) { 207ca3176e7SBrian Feldman error("fdopen %s failed: %s.", filename, strerror(errno)); 208e8aafc91SKris Kennaway close(fd); 209e8aafc91SKris Kennaway return 0; 210e8aafc91SKris Kennaway } 211ca3176e7SBrian Feldman switch (key->type) { 212ca3176e7SBrian Feldman case KEY_DSA: 213ca3176e7SBrian Feldman success = PEM_write_DSAPrivateKey(fp, key->dsa, 214ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 215ca3176e7SBrian Feldman break; 216ca3176e7SBrian Feldman case KEY_RSA: 217ca3176e7SBrian Feldman success = PEM_write_RSAPrivateKey(fp, key->rsa, 218ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 219ca3176e7SBrian Feldman break; 220e8aafc91SKris Kennaway } 221e8aafc91SKris Kennaway fclose(fp); 222e8aafc91SKris Kennaway return success; 223e8aafc91SKris Kennaway } 224e8aafc91SKris Kennaway 225e8aafc91SKris Kennaway int 226ca3176e7SBrian Feldman key_save_private(Key *key, const char *filename, const char *passphrase, 227e8aafc91SKris Kennaway const char *comment) 228e8aafc91SKris Kennaway { 229e8aafc91SKris Kennaway switch (key->type) { 230ca3176e7SBrian Feldman case KEY_RSA1: 231ca3176e7SBrian Feldman return key_save_private_rsa1(key, filename, passphrase, 232ca3176e7SBrian Feldman comment); 233e8aafc91SKris Kennaway case KEY_DSA: 234ca3176e7SBrian Feldman case KEY_RSA: 235ca3176e7SBrian Feldman return key_save_private_pem(key, filename, passphrase, 236ca3176e7SBrian Feldman comment); 237e8aafc91SKris Kennaway default: 238e8aafc91SKris Kennaway break; 239e8aafc91SKris Kennaway } 240ca3176e7SBrian Feldman error("key_save_private: cannot save key type %d", key->type); 241e8aafc91SKris Kennaway return 0; 242e8aafc91SKris Kennaway } 243e8aafc91SKris Kennaway 244511b41d2SMark Murray /* 245ca3176e7SBrian Feldman * Loads the public part of the ssh v1 key file. Returns NULL if an error was 246ca3176e7SBrian Feldman * encountered (the file does not exist or is not readable), and the key 247511b41d2SMark Murray * otherwise. 248511b41d2SMark Murray */ 249511b41d2SMark Murray 250af12a3e7SDag-Erling Smørgrav static Key * 251ca3176e7SBrian Feldman key_load_public_rsa1(int fd, const char *filename, char **commentp) 252511b41d2SMark Murray { 253511b41d2SMark Murray Buffer buffer; 254ca3176e7SBrian Feldman Key *pub; 255e73e9afaSDag-Erling Smørgrav struct stat st; 256511b41d2SMark Murray char *cp; 257d4ecd108SDag-Erling Smørgrav u_int i; 25821e764dfSDag-Erling Smørgrav size_t len; 259511b41d2SMark Murray 260e73e9afaSDag-Erling Smørgrav if (fstat(fd, &st) < 0) { 261e73e9afaSDag-Erling Smørgrav error("fstat for key file %.200s failed: %.100s", 262e73e9afaSDag-Erling Smørgrav filename, strerror(errno)); 263e73e9afaSDag-Erling Smørgrav return NULL; 264e73e9afaSDag-Erling Smørgrav } 265aa49c926SDag-Erling Smørgrav if (st.st_size > 1*1024*1024) { 266aa49c926SDag-Erling Smørgrav error("key file %.200s too large", filename); 267aa49c926SDag-Erling Smørgrav return NULL; 268aa49c926SDag-Erling Smørgrav } 26921e764dfSDag-Erling Smørgrav len = (size_t)st.st_size; /* truncated */ 270511b41d2SMark Murray 271511b41d2SMark Murray buffer_init(&buffer); 272af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&buffer, len); 273511b41d2SMark Murray 274d4ecd108SDag-Erling Smørgrav if (atomicio(read, fd, cp, len) != len) { 275511b41d2SMark Murray debug("Read from key file %.200s failed: %.100s", filename, 276511b41d2SMark Murray strerror(errno)); 277511b41d2SMark Murray buffer_free(&buffer); 278ca3176e7SBrian Feldman return NULL; 279511b41d2SMark Murray } 280511b41d2SMark Murray 281ca3176e7SBrian Feldman /* Check that it is at least big enough to contain the ID string. */ 282ca3176e7SBrian Feldman if (len < sizeof(authfile_id_string)) { 283af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 284511b41d2SMark Murray buffer_free(&buffer); 285ca3176e7SBrian Feldman return NULL; 286511b41d2SMark Murray } 287511b41d2SMark Murray /* 288511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 289511b41d2SMark Murray * from the buffer. 290511b41d2SMark Murray */ 291ca3176e7SBrian Feldman for (i = 0; i < sizeof(authfile_id_string); i++) 292ca3176e7SBrian Feldman if (buffer_get_char(&buffer) != authfile_id_string[i]) { 293af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 294511b41d2SMark Murray buffer_free(&buffer); 295ca3176e7SBrian Feldman return NULL; 296511b41d2SMark Murray } 297511b41d2SMark Murray /* Skip cipher type and reserved data. */ 298511b41d2SMark Murray (void) buffer_get_char(&buffer); /* cipher type */ 299511b41d2SMark Murray (void) buffer_get_int(&buffer); /* reserved */ 300511b41d2SMark Murray 301511b41d2SMark Murray /* Read the public key from the buffer. */ 302a82e551fSDag-Erling Smørgrav (void) buffer_get_int(&buffer); 303ca3176e7SBrian Feldman pub = key_new(KEY_RSA1); 304ca3176e7SBrian Feldman buffer_get_bignum(&buffer, pub->rsa->n); 305ca3176e7SBrian Feldman buffer_get_bignum(&buffer, pub->rsa->e); 306ca3176e7SBrian Feldman if (commentp) 307ca3176e7SBrian Feldman *commentp = buffer_get_string(&buffer, NULL); 308511b41d2SMark Murray /* The encrypted private part is not parsed by this function. */ 309511b41d2SMark Murray 310511b41d2SMark Murray buffer_free(&buffer); 311ca3176e7SBrian Feldman return pub; 312511b41d2SMark Murray } 313511b41d2SMark Murray 314ca3176e7SBrian Feldman /* load public key from private-key file, works only for SSH v1 */ 315ca3176e7SBrian Feldman Key * 316ca3176e7SBrian Feldman key_load_public_type(int type, const char *filename, char **commentp) 317e8aafc91SKris Kennaway { 318ca3176e7SBrian Feldman Key *pub; 319ca3176e7SBrian Feldman int fd; 320ca3176e7SBrian Feldman 321ca3176e7SBrian Feldman if (type == KEY_RSA1) { 322ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 323ca3176e7SBrian Feldman if (fd < 0) 324ca3176e7SBrian Feldman return NULL; 325ca3176e7SBrian Feldman pub = key_load_public_rsa1(fd, filename, commentp); 326ca3176e7SBrian Feldman close(fd); 327ca3176e7SBrian Feldman return pub; 328e8aafc91SKris Kennaway } 329ca3176e7SBrian Feldman return NULL; 330e8aafc91SKris Kennaway } 331e8aafc91SKris Kennaway 332511b41d2SMark Murray /* 333511b41d2SMark Murray * Loads the private key from the file. Returns 0 if an error is encountered 334511b41d2SMark Murray * (file does not exist or is not readable, or passphrase is bad). This 335511b41d2SMark Murray * initializes the private key. 336511b41d2SMark Murray * Assumes we are called under uid of the owner of the file. 337511b41d2SMark Murray */ 338511b41d2SMark Murray 339af12a3e7SDag-Erling Smørgrav static Key * 340ca3176e7SBrian Feldman key_load_private_rsa1(int fd, const char *filename, const char *passphrase, 341ca3176e7SBrian Feldman char **commentp) 342511b41d2SMark Murray { 343d4ecd108SDag-Erling Smørgrav u_int i; 344d4ecd108SDag-Erling Smørgrav int check1, check2, cipher_type; 34521e764dfSDag-Erling Smørgrav size_t len; 346511b41d2SMark Murray Buffer buffer, decrypted; 347af12a3e7SDag-Erling Smørgrav u_char *cp; 34809958426SBrian Feldman CipherContext ciphercontext; 34909958426SBrian Feldman Cipher *cipher; 350ca3176e7SBrian Feldman Key *prv = NULL; 351e73e9afaSDag-Erling Smørgrav struct stat st; 352511b41d2SMark Murray 353e73e9afaSDag-Erling Smørgrav if (fstat(fd, &st) < 0) { 354e73e9afaSDag-Erling Smørgrav error("fstat for key file %.200s failed: %.100s", 355e73e9afaSDag-Erling Smørgrav filename, strerror(errno)); 356e73e9afaSDag-Erling Smørgrav close(fd); 357e73e9afaSDag-Erling Smørgrav return NULL; 358e73e9afaSDag-Erling Smørgrav } 35921e764dfSDag-Erling Smørgrav if (st.st_size > 1*1024*1024) { 360aa49c926SDag-Erling Smørgrav error("key file %.200s too large", filename); 36121e764dfSDag-Erling Smørgrav close(fd); 36221e764dfSDag-Erling Smørgrav return (NULL); 36321e764dfSDag-Erling Smørgrav } 36421e764dfSDag-Erling Smørgrav len = (size_t)st.st_size; /* truncated */ 365511b41d2SMark Murray 366511b41d2SMark Murray buffer_init(&buffer); 367af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&buffer, len); 368511b41d2SMark Murray 369d4ecd108SDag-Erling Smørgrav if (atomicio(read, fd, cp, len) != len) { 370511b41d2SMark Murray debug("Read from key file %.200s failed: %.100s", filename, 371511b41d2SMark Murray strerror(errno)); 372511b41d2SMark Murray buffer_free(&buffer); 373511b41d2SMark Murray close(fd); 374ca3176e7SBrian Feldman return NULL; 375511b41d2SMark Murray } 376511b41d2SMark Murray 377ca3176e7SBrian Feldman /* Check that it is at least big enough to contain the ID string. */ 378ca3176e7SBrian Feldman if (len < sizeof(authfile_id_string)) { 379af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 380511b41d2SMark Murray buffer_free(&buffer); 381ca3176e7SBrian Feldman close(fd); 382ca3176e7SBrian Feldman return NULL; 383511b41d2SMark Murray } 384511b41d2SMark Murray /* 385511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 386511b41d2SMark Murray * from the buffer. 387511b41d2SMark Murray */ 388ca3176e7SBrian Feldman for (i = 0; i < sizeof(authfile_id_string); i++) 389ca3176e7SBrian Feldman if (buffer_get_char(&buffer) != authfile_id_string[i]) { 390af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 391511b41d2SMark Murray buffer_free(&buffer); 392ca3176e7SBrian Feldman close(fd); 393ca3176e7SBrian Feldman return NULL; 394511b41d2SMark Murray } 395ca3176e7SBrian Feldman 396511b41d2SMark Murray /* Read cipher type. */ 397511b41d2SMark Murray cipher_type = buffer_get_char(&buffer); 398511b41d2SMark Murray (void) buffer_get_int(&buffer); /* Reserved data. */ 399511b41d2SMark Murray 400511b41d2SMark Murray /* Read the public key from the buffer. */ 401a82e551fSDag-Erling Smørgrav (void) buffer_get_int(&buffer); 402ca3176e7SBrian Feldman prv = key_new_private(KEY_RSA1); 403ca3176e7SBrian Feldman 404ca3176e7SBrian Feldman buffer_get_bignum(&buffer, prv->rsa->n); 405ca3176e7SBrian Feldman buffer_get_bignum(&buffer, prv->rsa->e); 406ca3176e7SBrian Feldman if (commentp) 407ca3176e7SBrian Feldman *commentp = buffer_get_string(&buffer, NULL); 408511b41d2SMark Murray else 409511b41d2SMark Murray xfree(buffer_get_string(&buffer, NULL)); 410511b41d2SMark Murray 411511b41d2SMark Murray /* Check that it is a supported cipher. */ 41209958426SBrian Feldman cipher = cipher_by_number(cipher_type); 41309958426SBrian Feldman if (cipher == NULL) { 41409958426SBrian Feldman debug("Unsupported cipher %d used in key file %.200s.", 41509958426SBrian Feldman cipher_type, filename); 416511b41d2SMark Murray buffer_free(&buffer); 417511b41d2SMark Murray goto fail; 418511b41d2SMark Murray } 419511b41d2SMark Murray /* Initialize space for decrypted data. */ 420511b41d2SMark Murray buffer_init(&decrypted); 421af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&decrypted, buffer_len(&buffer)); 422511b41d2SMark Murray 423511b41d2SMark Murray /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 424af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 425af12a3e7SDag-Erling Smørgrav CIPHER_DECRYPT); 426af12a3e7SDag-Erling Smørgrav cipher_crypt(&ciphercontext, cp, 427af12a3e7SDag-Erling Smørgrav buffer_ptr(&buffer), buffer_len(&buffer)); 428af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 42909958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 430511b41d2SMark Murray buffer_free(&buffer); 431511b41d2SMark Murray 432511b41d2SMark Murray check1 = buffer_get_char(&decrypted); 433511b41d2SMark Murray check2 = buffer_get_char(&decrypted); 434511b41d2SMark Murray if (check1 != buffer_get_char(&decrypted) || 435511b41d2SMark Murray check2 != buffer_get_char(&decrypted)) { 436511b41d2SMark Murray if (strcmp(passphrase, "") != 0) 437ca3176e7SBrian Feldman debug("Bad passphrase supplied for key file %.200s.", 438ca3176e7SBrian Feldman filename); 439511b41d2SMark Murray /* Bad passphrase. */ 440511b41d2SMark Murray buffer_free(&decrypted); 441ca3176e7SBrian Feldman goto fail; 442511b41d2SMark Murray } 443511b41d2SMark Murray /* Read the rest of the private key. */ 444ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->d); 445ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ 446ca3176e7SBrian Feldman /* in SSL and SSH v1 p and q are exchanged */ 447ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ 448ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ 449511b41d2SMark Murray 450ca3176e7SBrian Feldman /* calculate p-1 and q-1 */ 451af12a3e7SDag-Erling Smørgrav rsa_generate_additional_parameters(prv->rsa); 452511b41d2SMark Murray 453511b41d2SMark Murray buffer_free(&decrypted); 454e73e9afaSDag-Erling Smørgrav 455e73e9afaSDag-Erling Smørgrav /* enable blinding */ 456e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 457e73e9afaSDag-Erling Smørgrav error("key_load_private_rsa1: RSA_blinding_on failed"); 458e73e9afaSDag-Erling Smørgrav goto fail; 459e73e9afaSDag-Erling Smørgrav } 460ca3176e7SBrian Feldman close(fd); 461ca3176e7SBrian Feldman return prv; 462511b41d2SMark Murray 463ca3176e7SBrian Feldman fail: 464ca3176e7SBrian Feldman if (commentp) 465ca3176e7SBrian Feldman xfree(*commentp); 466ca3176e7SBrian Feldman close(fd); 467ca3176e7SBrian Feldman key_free(prv); 468ca3176e7SBrian Feldman return NULL; 469511b41d2SMark Murray } 470e8aafc91SKris Kennaway 47180628bacSDag-Erling Smørgrav Key * 472ca3176e7SBrian Feldman key_load_private_pem(int fd, int type, const char *passphrase, 473ca3176e7SBrian Feldman char **commentp) 474e8aafc91SKris Kennaway { 475e8aafc91SKris Kennaway FILE *fp; 476ca3176e7SBrian Feldman EVP_PKEY *pk = NULL; 477ca3176e7SBrian Feldman Key *prv = NULL; 478ca3176e7SBrian Feldman char *name = "<no key>"; 479e8aafc91SKris Kennaway 480e8aafc91SKris Kennaway fp = fdopen(fd, "r"); 481e8aafc91SKris Kennaway if (fp == NULL) { 482ca3176e7SBrian Feldman error("fdopen failed: %s", strerror(errno)); 483ca3176e7SBrian Feldman close(fd); 484ca3176e7SBrian Feldman return NULL; 485e8aafc91SKris Kennaway } 486ca3176e7SBrian Feldman pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); 487ca3176e7SBrian Feldman if (pk == NULL) { 488ca3176e7SBrian Feldman debug("PEM_read_PrivateKey failed"); 489ca3176e7SBrian Feldman (void)ERR_get_error(); 490ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_RSA && 491ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_RSA)) { 492ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 493ca3176e7SBrian Feldman prv->rsa = EVP_PKEY_get1_RSA(pk); 494ca3176e7SBrian Feldman prv->type = KEY_RSA; 495ca3176e7SBrian Feldman name = "rsa w/o comment"; 496ca3176e7SBrian Feldman #ifdef DEBUG_PK 497ca3176e7SBrian Feldman RSA_print_fp(stderr, prv->rsa, 8); 498e8aafc91SKris Kennaway #endif 499e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 500e73e9afaSDag-Erling Smørgrav error("key_load_private_pem: RSA_blinding_on failed"); 501e73e9afaSDag-Erling Smørgrav key_free(prv); 502e73e9afaSDag-Erling Smørgrav prv = NULL; 503e73e9afaSDag-Erling Smørgrav } 504ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_DSA && 505ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_DSA)) { 506ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 507ca3176e7SBrian Feldman prv->dsa = EVP_PKEY_get1_DSA(pk); 508ca3176e7SBrian Feldman prv->type = KEY_DSA; 509ca3176e7SBrian Feldman name = "dsa w/o comment"; 510ca3176e7SBrian Feldman #ifdef DEBUG_PK 511ca3176e7SBrian Feldman DSA_print_fp(stderr, prv->dsa, 8); 512ca3176e7SBrian Feldman #endif 513ca3176e7SBrian Feldman } else { 514ca3176e7SBrian Feldman error("PEM_read_PrivateKey: mismatch or " 515ca3176e7SBrian Feldman "unknown EVP_PKEY save_type %d", pk->save_type); 516ca3176e7SBrian Feldman } 517ca3176e7SBrian Feldman fclose(fp); 518ca3176e7SBrian Feldman if (pk != NULL) 519ca3176e7SBrian Feldman EVP_PKEY_free(pk); 520ca3176e7SBrian Feldman if (prv != NULL && commentp) 521ca3176e7SBrian Feldman *commentp = xstrdup(name); 522ca3176e7SBrian Feldman debug("read PEM private key done: type %s", 523ca3176e7SBrian Feldman prv ? key_type(prv) : "<unknown>"); 524ca3176e7SBrian Feldman return prv; 525e8aafc91SKris Kennaway } 526e8aafc91SKris Kennaway 527333ee039SDag-Erling Smørgrav int 528ca3176e7SBrian Feldman key_perm_ok(int fd, const char *filename) 529e8aafc91SKris Kennaway { 530e8aafc91SKris Kennaway struct stat st; 531e8aafc91SKris Kennaway 532af12a3e7SDag-Erling Smørgrav if (fstat(fd, &st) < 0) 533af12a3e7SDag-Erling Smørgrav return 0; 534af12a3e7SDag-Erling Smørgrav /* 535af12a3e7SDag-Erling Smørgrav * if a key owned by the user is accessed, then we check the 536af12a3e7SDag-Erling Smørgrav * permissions of the file. if the key owned by a different user, 537af12a3e7SDag-Erling Smørgrav * then we don't care. 538af12a3e7SDag-Erling Smørgrav */ 539989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 540989dd127SDag-Erling Smørgrav if (check_ntsec(filename)) 541989dd127SDag-Erling Smørgrav #endif 542af12a3e7SDag-Erling Smørgrav if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { 543e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 544e8aafc91SKris Kennaway error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 545e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 546af12a3e7SDag-Erling Smørgrav error("Permissions 0%3.3o for '%s' are too open.", 547cf2b5f3bSDag-Erling Smørgrav (u_int)st.st_mode & 0777, filename); 548e8aafc91SKris Kennaway error("It is recommended that your private key files are NOT accessible by others."); 549ca3176e7SBrian Feldman error("This private key will be ignored."); 550e8aafc91SKris Kennaway return 0; 551e8aafc91SKris Kennaway } 552ca3176e7SBrian Feldman return 1; 553e8aafc91SKris Kennaway } 554ca3176e7SBrian Feldman 555ca3176e7SBrian Feldman Key * 556ca3176e7SBrian Feldman key_load_private_type(int type, const char *filename, const char *passphrase, 557333ee039SDag-Erling Smørgrav char **commentp, int *perm_ok) 558ca3176e7SBrian Feldman { 559ca3176e7SBrian Feldman int fd; 560ca3176e7SBrian Feldman 561ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 562b15c8340SDag-Erling Smørgrav if (fd < 0) { 563b15c8340SDag-Erling Smørgrav debug("could not open key file '%s': %s", filename, 564b15c8340SDag-Erling Smørgrav strerror(errno)); 565b15c8340SDag-Erling Smørgrav if (perm_ok != NULL) 566b15c8340SDag-Erling Smørgrav *perm_ok = 0; 567ca3176e7SBrian Feldman return NULL; 568b15c8340SDag-Erling Smørgrav } 569ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 570333ee039SDag-Erling Smørgrav if (perm_ok != NULL) 571333ee039SDag-Erling Smørgrav *perm_ok = 0; 572ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 573ca3176e7SBrian Feldman close(fd); 574ca3176e7SBrian Feldman return NULL; 575e8aafc91SKris Kennaway } 576333ee039SDag-Erling Smørgrav if (perm_ok != NULL) 577333ee039SDag-Erling Smørgrav *perm_ok = 1; 578ca3176e7SBrian Feldman switch (type) { 579ca3176e7SBrian Feldman case KEY_RSA1: 580ca3176e7SBrian Feldman return key_load_private_rsa1(fd, filename, passphrase, 581ca3176e7SBrian Feldman commentp); 582ca3176e7SBrian Feldman /* closes fd */ 583e8aafc91SKris Kennaway case KEY_DSA: 584ca3176e7SBrian Feldman case KEY_RSA: 585ca3176e7SBrian Feldman case KEY_UNSPEC: 586ca3176e7SBrian Feldman return key_load_private_pem(fd, type, passphrase, commentp); 587ca3176e7SBrian Feldman /* closes fd */ 588e8aafc91SKris Kennaway default: 589ca3176e7SBrian Feldman close(fd); 590e8aafc91SKris Kennaway break; 591e8aafc91SKris Kennaway } 592ca3176e7SBrian Feldman return NULL; 593ca3176e7SBrian Feldman } 594ca3176e7SBrian Feldman 595ca3176e7SBrian Feldman Key * 596ca3176e7SBrian Feldman key_load_private(const char *filename, const char *passphrase, 597ca3176e7SBrian Feldman char **commentp) 598ca3176e7SBrian Feldman { 599af12a3e7SDag-Erling Smørgrav Key *pub, *prv; 600ca3176e7SBrian Feldman int fd; 601ca3176e7SBrian Feldman 602ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 603b15c8340SDag-Erling Smørgrav if (fd < 0) { 604b15c8340SDag-Erling Smørgrav debug("could not open key file '%s': %s", filename, 605b15c8340SDag-Erling Smørgrav strerror(errno)); 606ca3176e7SBrian Feldman return NULL; 607b15c8340SDag-Erling Smørgrav } 608ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 609ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 610e8aafc91SKris Kennaway close(fd); 611ca3176e7SBrian Feldman return NULL; 612ca3176e7SBrian Feldman } 613ca3176e7SBrian Feldman pub = key_load_public_rsa1(fd, filename, commentp); 614ca3176e7SBrian Feldman lseek(fd, (off_t) 0, SEEK_SET); /* rewind */ 615ca3176e7SBrian Feldman if (pub == NULL) { 616ca3176e7SBrian Feldman /* closes fd */ 617af12a3e7SDag-Erling Smørgrav prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); 618af12a3e7SDag-Erling Smørgrav /* use the filename as a comment for PEM */ 619af12a3e7SDag-Erling Smørgrav if (commentp && prv) 620af12a3e7SDag-Erling Smørgrav *commentp = xstrdup(filename); 621ca3176e7SBrian Feldman } else { 622ca3176e7SBrian Feldman /* it's a SSH v1 key if the public key part is readable */ 623ca3176e7SBrian Feldman key_free(pub); 624ca3176e7SBrian Feldman /* closes fd */ 625af12a3e7SDag-Erling Smørgrav prv = key_load_private_rsa1(fd, filename, passphrase, NULL); 626ca3176e7SBrian Feldman } 627af12a3e7SDag-Erling Smørgrav return prv; 628e8aafc91SKris Kennaway } 629c2d3a559SKris Kennaway 630af12a3e7SDag-Erling Smørgrav static int 631ca3176e7SBrian Feldman key_try_load_public(Key *k, const char *filename, char **commentp) 632c2d3a559SKris Kennaway { 633c2d3a559SKris Kennaway FILE *f; 634aa49c926SDag-Erling Smørgrav char line[SSH_MAX_PUBKEY_BYTES]; 635c2d3a559SKris Kennaway char *cp; 636aa49c926SDag-Erling Smørgrav u_long linenum = 0; 637c2d3a559SKris Kennaway 638c2d3a559SKris Kennaway f = fopen(filename, "r"); 639c2d3a559SKris Kennaway if (f != NULL) { 640aa49c926SDag-Erling Smørgrav while (read_keyfile_line(f, filename, line, sizeof(line), 641aa49c926SDag-Erling Smørgrav &linenum) != -1) { 642c2d3a559SKris Kennaway cp = line; 643c2d3a559SKris Kennaway switch (*cp) { 644c2d3a559SKris Kennaway case '#': 645c2d3a559SKris Kennaway case '\n': 646c2d3a559SKris Kennaway case '\0': 647c2d3a559SKris Kennaway continue; 648c2d3a559SKris Kennaway } 649c2d3a559SKris Kennaway /* Skip leading whitespace. */ 650c2d3a559SKris Kennaway for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 651c2d3a559SKris Kennaway ; 652c2d3a559SKris Kennaway if (*cp) { 653ca3176e7SBrian Feldman if (key_read(k, &cp) == 1) { 654c2d3a559SKris Kennaway if (commentp) 655c2d3a559SKris Kennaway *commentp=xstrdup(filename); 656c2d3a559SKris Kennaway fclose(f); 657c2d3a559SKris Kennaway return 1; 658c2d3a559SKris Kennaway } 659c2d3a559SKris Kennaway } 660c2d3a559SKris Kennaway } 661c2d3a559SKris Kennaway fclose(f); 662c2d3a559SKris Kennaway } 663c2d3a559SKris Kennaway return 0; 664c2d3a559SKris Kennaway } 665c2d3a559SKris Kennaway 666ca3176e7SBrian Feldman /* load public key from ssh v1 private or any pubkey file */ 667ca3176e7SBrian Feldman Key * 668ca3176e7SBrian Feldman key_load_public(const char *filename, char **commentp) 669c2d3a559SKris Kennaway { 670ca3176e7SBrian Feldman Key *pub; 671ca3176e7SBrian Feldman char file[MAXPATHLEN]; 672c2d3a559SKris Kennaway 673cf2b5f3bSDag-Erling Smørgrav /* try rsa1 private key */ 674ca3176e7SBrian Feldman pub = key_load_public_type(KEY_RSA1, filename, commentp); 675ca3176e7SBrian Feldman if (pub != NULL) 676ca3176e7SBrian Feldman return pub; 677cf2b5f3bSDag-Erling Smørgrav 678cf2b5f3bSDag-Erling Smørgrav /* try rsa1 public key */ 679cf2b5f3bSDag-Erling Smørgrav pub = key_new(KEY_RSA1); 680cf2b5f3bSDag-Erling Smørgrav if (key_try_load_public(pub, filename, commentp) == 1) 681cf2b5f3bSDag-Erling Smørgrav return pub; 682cf2b5f3bSDag-Erling Smørgrav key_free(pub); 683cf2b5f3bSDag-Erling Smørgrav 684cf2b5f3bSDag-Erling Smørgrav /* try ssh2 public key */ 685ca3176e7SBrian Feldman pub = key_new(KEY_UNSPEC); 686ca3176e7SBrian Feldman if (key_try_load_public(pub, filename, commentp) == 1) 687ca3176e7SBrian Feldman return pub; 688ca3176e7SBrian Feldman if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && 689ca3176e7SBrian Feldman (strlcat(file, ".pub", sizeof file) < sizeof(file)) && 690ca3176e7SBrian Feldman (key_try_load_public(pub, file, commentp) == 1)) 691ca3176e7SBrian Feldman return pub; 692ca3176e7SBrian Feldman key_free(pub); 693ca3176e7SBrian Feldman return NULL; 694c2d3a559SKris Kennaway } 695b15c8340SDag-Erling Smørgrav 696*e2f6069cSDag-Erling Smørgrav /* Load the certificate associated with the named private key */ 697*e2f6069cSDag-Erling Smørgrav Key * 698*e2f6069cSDag-Erling Smørgrav key_load_cert(const char *filename) 699*e2f6069cSDag-Erling Smørgrav { 700*e2f6069cSDag-Erling Smørgrav Key *pub; 701*e2f6069cSDag-Erling Smørgrav char *file; 702*e2f6069cSDag-Erling Smørgrav 703*e2f6069cSDag-Erling Smørgrav pub = key_new(KEY_UNSPEC); 704*e2f6069cSDag-Erling Smørgrav xasprintf(&file, "%s-cert.pub", filename); 705*e2f6069cSDag-Erling Smørgrav if (key_try_load_public(pub, file, NULL) == 1) { 706*e2f6069cSDag-Erling Smørgrav xfree(file); 707*e2f6069cSDag-Erling Smørgrav return pub; 708*e2f6069cSDag-Erling Smørgrav } 709*e2f6069cSDag-Erling Smørgrav xfree(file); 710*e2f6069cSDag-Erling Smørgrav key_free(pub); 711*e2f6069cSDag-Erling Smørgrav return NULL; 712*e2f6069cSDag-Erling Smørgrav } 713*e2f6069cSDag-Erling Smørgrav 714*e2f6069cSDag-Erling Smørgrav /* Load private key and certificate */ 715*e2f6069cSDag-Erling Smørgrav Key * 716*e2f6069cSDag-Erling Smørgrav key_load_private_cert(int type, const char *filename, const char *passphrase, 717*e2f6069cSDag-Erling Smørgrav int *perm_ok) 718*e2f6069cSDag-Erling Smørgrav { 719*e2f6069cSDag-Erling Smørgrav Key *key, *pub; 720*e2f6069cSDag-Erling Smørgrav 721*e2f6069cSDag-Erling Smørgrav switch (type) { 722*e2f6069cSDag-Erling Smørgrav case KEY_RSA: 723*e2f6069cSDag-Erling Smørgrav case KEY_DSA: 724*e2f6069cSDag-Erling Smørgrav break; 725*e2f6069cSDag-Erling Smørgrav default: 726*e2f6069cSDag-Erling Smørgrav error("%s: unsupported key type", __func__); 727*e2f6069cSDag-Erling Smørgrav return NULL; 728*e2f6069cSDag-Erling Smørgrav } 729*e2f6069cSDag-Erling Smørgrav 730*e2f6069cSDag-Erling Smørgrav if ((key = key_load_private_type(type, filename, 731*e2f6069cSDag-Erling Smørgrav passphrase, NULL, perm_ok)) == NULL) 732*e2f6069cSDag-Erling Smørgrav return NULL; 733*e2f6069cSDag-Erling Smørgrav 734*e2f6069cSDag-Erling Smørgrav if ((pub = key_load_cert(filename)) == NULL) { 735*e2f6069cSDag-Erling Smørgrav key_free(key); 736*e2f6069cSDag-Erling Smørgrav return NULL; 737*e2f6069cSDag-Erling Smørgrav } 738*e2f6069cSDag-Erling Smørgrav 739*e2f6069cSDag-Erling Smørgrav /* Make sure the private key matches the certificate */ 740*e2f6069cSDag-Erling Smørgrav if (key_equal_public(key, pub) == 0) { 741*e2f6069cSDag-Erling Smørgrav error("%s: certificate does not match private key %s", 742*e2f6069cSDag-Erling Smørgrav __func__, filename); 743*e2f6069cSDag-Erling Smørgrav } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { 744*e2f6069cSDag-Erling Smørgrav error("%s: key_to_certified failed", __func__); 745*e2f6069cSDag-Erling Smørgrav } else { 746*e2f6069cSDag-Erling Smørgrav key_cert_copy(pub, key); 747*e2f6069cSDag-Erling Smørgrav key_free(pub); 748*e2f6069cSDag-Erling Smørgrav return key; 749*e2f6069cSDag-Erling Smørgrav } 750*e2f6069cSDag-Erling Smørgrav 751*e2f6069cSDag-Erling Smørgrav key_free(key); 752*e2f6069cSDag-Erling Smørgrav key_free(pub); 753*e2f6069cSDag-Erling Smørgrav return NULL; 754*e2f6069cSDag-Erling Smørgrav } 755*e2f6069cSDag-Erling Smørgrav 756b15c8340SDag-Erling Smørgrav /* 757b15c8340SDag-Erling Smørgrav * Returns 1 if the specified "key" is listed in the file "filename", 758b15c8340SDag-Erling Smørgrav * 0 if the key is not listed or -1 on error. 759b15c8340SDag-Erling Smørgrav * If strict_type is set then the key type must match exactly, 760b15c8340SDag-Erling Smørgrav * otherwise a comparison that ignores certficiate data is performed. 761b15c8340SDag-Erling Smørgrav */ 762b15c8340SDag-Erling Smørgrav int 763b15c8340SDag-Erling Smørgrav key_in_file(Key *key, const char *filename, int strict_type) 764b15c8340SDag-Erling Smørgrav { 765b15c8340SDag-Erling Smørgrav FILE *f; 766b15c8340SDag-Erling Smørgrav char line[SSH_MAX_PUBKEY_BYTES]; 767b15c8340SDag-Erling Smørgrav char *cp; 768b15c8340SDag-Erling Smørgrav u_long linenum = 0; 769b15c8340SDag-Erling Smørgrav int ret = 0; 770b15c8340SDag-Erling Smørgrav Key *pub; 771b15c8340SDag-Erling Smørgrav int (*key_compare)(const Key *, const Key *) = strict_type ? 772b15c8340SDag-Erling Smørgrav key_equal : key_equal_public; 773b15c8340SDag-Erling Smørgrav 774b15c8340SDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) { 775b15c8340SDag-Erling Smørgrav if (errno == ENOENT) { 776b15c8340SDag-Erling Smørgrav debug("%s: keyfile \"%s\" missing", __func__, filename); 777b15c8340SDag-Erling Smørgrav return 0; 778b15c8340SDag-Erling Smørgrav } else { 779b15c8340SDag-Erling Smørgrav error("%s: could not open keyfile \"%s\": %s", __func__, 780b15c8340SDag-Erling Smørgrav filename, strerror(errno)); 781b15c8340SDag-Erling Smørgrav return -1; 782b15c8340SDag-Erling Smørgrav } 783b15c8340SDag-Erling Smørgrav } 784b15c8340SDag-Erling Smørgrav 785b15c8340SDag-Erling Smørgrav while (read_keyfile_line(f, filename, line, sizeof(line), 786b15c8340SDag-Erling Smørgrav &linenum) != -1) { 787b15c8340SDag-Erling Smørgrav cp = line; 788b15c8340SDag-Erling Smørgrav 789b15c8340SDag-Erling Smørgrav /* Skip leading whitespace. */ 790b15c8340SDag-Erling Smørgrav for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 791b15c8340SDag-Erling Smørgrav ; 792b15c8340SDag-Erling Smørgrav 793b15c8340SDag-Erling Smørgrav /* Skip comments and empty lines */ 794b15c8340SDag-Erling Smørgrav switch (*cp) { 795b15c8340SDag-Erling Smørgrav case '#': 796b15c8340SDag-Erling Smørgrav case '\n': 797b15c8340SDag-Erling Smørgrav case '\0': 798b15c8340SDag-Erling Smørgrav continue; 799b15c8340SDag-Erling Smørgrav } 800b15c8340SDag-Erling Smørgrav 801b15c8340SDag-Erling Smørgrav pub = key_new(KEY_UNSPEC); 802b15c8340SDag-Erling Smørgrav if (key_read(pub, &cp) != 1) { 803b15c8340SDag-Erling Smørgrav key_free(pub); 804b15c8340SDag-Erling Smørgrav continue; 805b15c8340SDag-Erling Smørgrav } 806b15c8340SDag-Erling Smørgrav if (key_compare(key, pub)) { 807b15c8340SDag-Erling Smørgrav ret = 1; 808b15c8340SDag-Erling Smørgrav key_free(pub); 809b15c8340SDag-Erling Smørgrav break; 810b15c8340SDag-Erling Smørgrav } 811b15c8340SDag-Erling Smørgrav key_free(pub); 812b15c8340SDag-Erling Smørgrav } 813b15c8340SDag-Erling Smørgrav fclose(f); 814b15c8340SDag-Erling Smørgrav return ret; 815b15c8340SDag-Erling Smørgrav } 816b15c8340SDag-Erling Smørgrav 817