1*e146993eSDag-Erling Smørgrav /* $OpenBSD: authfile.c,v 1.92 2011/06/14 22:49:18 markus 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 72*e146993eSDag-Erling Smørgrav #define MAX_KEY_FILE_SIZE (1024 * 1024) 73*e146993eSDag-Erling Smørgrav 74ca3176e7SBrian Feldman /* Version identification string for SSH v1 identity files. */ 75ca3176e7SBrian Feldman static const char authfile_id_string[] = 76ca3176e7SBrian Feldman "SSH PRIVATE KEY FILE FORMAT 1.1\n"; 77511b41d2SMark Murray 78511b41d2SMark Murray /* 794a421b63SDag-Erling Smørgrav * Serialises the authentication (private) key to a blob, encrypting it with 804a421b63SDag-Erling Smørgrav * passphrase. The identification of the blob (lowest 64 bits of n) will 81511b41d2SMark Murray * precede the key to provide identification of the key without needing a 82511b41d2SMark Murray * passphrase. 83511b41d2SMark Murray */ 84af12a3e7SDag-Erling Smørgrav static int 854a421b63SDag-Erling Smørgrav key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, 86ca3176e7SBrian Feldman const char *comment) 87511b41d2SMark Murray { 88511b41d2SMark Murray Buffer buffer, encrypted; 89af12a3e7SDag-Erling Smørgrav u_char buf[100], *cp; 904a421b63SDag-Erling Smørgrav int i, cipher_num; 9109958426SBrian Feldman CipherContext ciphercontext; 9209958426SBrian Feldman Cipher *cipher; 9321e764dfSDag-Erling Smørgrav u_int32_t rnd; 94511b41d2SMark Murray 95511b41d2SMark Murray /* 96511b41d2SMark Murray * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting 97511b41d2SMark Murray * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. 98511b41d2SMark Murray */ 99af12a3e7SDag-Erling Smørgrav cipher_num = (strcmp(passphrase, "") == 0) ? 100af12a3e7SDag-Erling Smørgrav SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; 101af12a3e7SDag-Erling Smørgrav if ((cipher = cipher_by_number(cipher_num)) == NULL) 10209958426SBrian Feldman fatal("save_private_key_rsa: bad cipher"); 103511b41d2SMark Murray 104511b41d2SMark Murray /* This buffer is used to built the secret part of the private key. */ 105511b41d2SMark Murray buffer_init(&buffer); 106511b41d2SMark Murray 107511b41d2SMark Murray /* Put checkbytes for checking passphrase validity. */ 10821e764dfSDag-Erling Smørgrav rnd = arc4random(); 10921e764dfSDag-Erling Smørgrav buf[0] = rnd & 0xff; 11021e764dfSDag-Erling Smørgrav buf[1] = (rnd >> 8) & 0xff; 111511b41d2SMark Murray buf[2] = buf[0]; 112511b41d2SMark Murray buf[3] = buf[1]; 113511b41d2SMark Murray buffer_append(&buffer, buf, 4); 114511b41d2SMark Murray 115511b41d2SMark Murray /* 116511b41d2SMark Murray * Store the private key (n and e will not be stored because they 117511b41d2SMark Murray * will be stored in plain text, and storing them also in encrypted 118511b41d2SMark Murray * format would just give known plaintext). 119511b41d2SMark Murray */ 120ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->d); 121ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->iqmp); 122ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ 123ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ 124511b41d2SMark Murray 125511b41d2SMark Murray /* Pad the part to be encrypted until its size is a multiple of 8. */ 126511b41d2SMark Murray while (buffer_len(&buffer) % 8 != 0) 127511b41d2SMark Murray buffer_put_char(&buffer, 0); 128511b41d2SMark Murray 129511b41d2SMark Murray /* This buffer will be used to contain the data in the file. */ 130511b41d2SMark Murray buffer_init(&encrypted); 131511b41d2SMark Murray 132511b41d2SMark Murray /* First store keyfile id string. */ 133ca3176e7SBrian Feldman for (i = 0; authfile_id_string[i]; i++) 134ca3176e7SBrian Feldman buffer_put_char(&encrypted, authfile_id_string[i]); 135511b41d2SMark Murray buffer_put_char(&encrypted, 0); 136511b41d2SMark Murray 137511b41d2SMark Murray /* Store cipher type. */ 138af12a3e7SDag-Erling Smørgrav buffer_put_char(&encrypted, cipher_num); 139511b41d2SMark Murray buffer_put_int(&encrypted, 0); /* For future extension */ 140511b41d2SMark Murray 141511b41d2SMark Murray /* Store public key. This will be in plain text. */ 142ca3176e7SBrian Feldman buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); 143ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->n); 144ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->e); 145af12a3e7SDag-Erling Smørgrav buffer_put_cstring(&encrypted, comment); 146511b41d2SMark Murray 147511b41d2SMark Murray /* Allocate space for the private part of the key in the buffer. */ 148af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&encrypted, buffer_len(&buffer)); 149511b41d2SMark Murray 150af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 151af12a3e7SDag-Erling Smørgrav CIPHER_ENCRYPT); 152af12a3e7SDag-Erling Smørgrav cipher_crypt(&ciphercontext, cp, 153af12a3e7SDag-Erling Smørgrav buffer_ptr(&buffer), buffer_len(&buffer)); 154af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 15509958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 156511b41d2SMark Murray 157511b41d2SMark Murray /* Destroy temporary data. */ 158511b41d2SMark Murray memset(buf, 0, sizeof(buf)); 159511b41d2SMark Murray buffer_free(&buffer); 160511b41d2SMark Murray 1614a421b63SDag-Erling Smørgrav buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); 1621ec0d754SDag-Erling Smørgrav buffer_free(&encrypted); 1634a421b63SDag-Erling Smørgrav 164511b41d2SMark Murray return 1; 165511b41d2SMark Murray } 166511b41d2SMark Murray 1674a421b63SDag-Erling Smørgrav /* convert SSH v2 key in OpenSSL PEM format */ 168af12a3e7SDag-Erling Smørgrav static int 1694a421b63SDag-Erling Smørgrav key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, 170ca3176e7SBrian Feldman const char *comment) 171e8aafc91SKris Kennaway { 172ca3176e7SBrian Feldman int success = 0; 1734a421b63SDag-Erling Smørgrav int blen, len = strlen(_passphrase); 174af12a3e7SDag-Erling Smørgrav u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; 175b15c8340SDag-Erling Smørgrav #if (OPENSSL_VERSION_NUMBER < 0x00907000L) 176af12a3e7SDag-Erling Smørgrav const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; 177b15c8340SDag-Erling Smørgrav #else 178b15c8340SDag-Erling Smørgrav const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; 179b15c8340SDag-Erling Smørgrav #endif 1804a421b63SDag-Erling Smørgrav const u_char *bptr; 1814a421b63SDag-Erling Smørgrav BIO *bio; 182e8aafc91SKris Kennaway 183e8aafc91SKris Kennaway if (len > 0 && len <= 4) { 184ca3176e7SBrian Feldman error("passphrase too short: have %d bytes, need > 4", len); 185e8aafc91SKris Kennaway return 0; 186e8aafc91SKris Kennaway } 1874a421b63SDag-Erling Smørgrav if ((bio = BIO_new(BIO_s_mem())) == NULL) { 1884a421b63SDag-Erling Smørgrav error("%s: BIO_new failed", __func__); 189e8aafc91SKris Kennaway return 0; 190e8aafc91SKris Kennaway } 191ca3176e7SBrian Feldman switch (key->type) { 192ca3176e7SBrian Feldman case KEY_DSA: 1934a421b63SDag-Erling Smørgrav success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, 194ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 195ca3176e7SBrian Feldman break; 1964a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 1974a421b63SDag-Erling Smørgrav case KEY_ECDSA: 1984a421b63SDag-Erling Smørgrav success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, 1994a421b63SDag-Erling Smørgrav cipher, passphrase, len, NULL, NULL); 2004a421b63SDag-Erling Smørgrav break; 2014a421b63SDag-Erling Smørgrav #endif 202ca3176e7SBrian Feldman case KEY_RSA: 2034a421b63SDag-Erling Smørgrav success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, 204ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 205ca3176e7SBrian Feldman break; 206e8aafc91SKris Kennaway } 2074a421b63SDag-Erling Smørgrav if (success) { 2084a421b63SDag-Erling Smørgrav if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) 2094a421b63SDag-Erling Smørgrav success = 0; 2104a421b63SDag-Erling Smørgrav else 2114a421b63SDag-Erling Smørgrav buffer_append(blob, bptr, blen); 2124a421b63SDag-Erling Smørgrav } 2134a421b63SDag-Erling Smørgrav BIO_free(bio); 214e8aafc91SKris Kennaway return success; 215e8aafc91SKris Kennaway } 216e8aafc91SKris Kennaway 2174a421b63SDag-Erling Smørgrav /* Save a key blob to a file */ 2184a421b63SDag-Erling Smørgrav static int 2194a421b63SDag-Erling Smørgrav key_save_private_blob(Buffer *keybuf, const char *filename) 2204a421b63SDag-Erling Smørgrav { 2214a421b63SDag-Erling Smørgrav int fd; 2224a421b63SDag-Erling Smørgrav 2234a421b63SDag-Erling Smørgrav if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { 2244a421b63SDag-Erling Smørgrav error("open %s failed: %s.", filename, strerror(errno)); 2254a421b63SDag-Erling Smørgrav return 0; 2264a421b63SDag-Erling Smørgrav } 2274a421b63SDag-Erling Smørgrav if (atomicio(vwrite, fd, buffer_ptr(keybuf), 2284a421b63SDag-Erling Smørgrav buffer_len(keybuf)) != buffer_len(keybuf)) { 2294a421b63SDag-Erling Smørgrav error("write to key file %s failed: %s", filename, 2304a421b63SDag-Erling Smørgrav strerror(errno)); 2314a421b63SDag-Erling Smørgrav close(fd); 2324a421b63SDag-Erling Smørgrav unlink(filename); 2334a421b63SDag-Erling Smørgrav return 0; 2344a421b63SDag-Erling Smørgrav } 2354a421b63SDag-Erling Smørgrav close(fd); 2364a421b63SDag-Erling Smørgrav return 1; 2374a421b63SDag-Erling Smørgrav } 2384a421b63SDag-Erling Smørgrav 2394a421b63SDag-Erling Smørgrav /* Serialise "key" to buffer "blob" */ 2404a421b63SDag-Erling Smørgrav static int 2414a421b63SDag-Erling Smørgrav key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, 2424a421b63SDag-Erling Smørgrav const char *comment) 2434a421b63SDag-Erling Smørgrav { 2444a421b63SDag-Erling Smørgrav switch (key->type) { 2454a421b63SDag-Erling Smørgrav case KEY_RSA1: 2464a421b63SDag-Erling Smørgrav return key_private_rsa1_to_blob(key, blob, passphrase, comment); 2474a421b63SDag-Erling Smørgrav case KEY_DSA: 2484a421b63SDag-Erling Smørgrav case KEY_ECDSA: 2494a421b63SDag-Erling Smørgrav case KEY_RSA: 2504a421b63SDag-Erling Smørgrav return key_private_pem_to_blob(key, blob, passphrase, comment); 2514a421b63SDag-Erling Smørgrav default: 2524a421b63SDag-Erling Smørgrav error("%s: cannot save key type %d", __func__, key->type); 2534a421b63SDag-Erling Smørgrav return 0; 2544a421b63SDag-Erling Smørgrav } 2554a421b63SDag-Erling Smørgrav } 2564a421b63SDag-Erling Smørgrav 257e8aafc91SKris Kennaway int 258ca3176e7SBrian Feldman key_save_private(Key *key, const char *filename, const char *passphrase, 259e8aafc91SKris Kennaway const char *comment) 260e8aafc91SKris Kennaway { 2614a421b63SDag-Erling Smørgrav Buffer keyblob; 2624a421b63SDag-Erling Smørgrav int success = 0; 2634a421b63SDag-Erling Smørgrav 2644a421b63SDag-Erling Smørgrav buffer_init(&keyblob); 2654a421b63SDag-Erling Smørgrav if (!key_private_to_blob(key, &keyblob, passphrase, comment)) 2664a421b63SDag-Erling Smørgrav goto out; 2674a421b63SDag-Erling Smørgrav if (!key_save_private_blob(&keyblob, filename)) 2684a421b63SDag-Erling Smørgrav goto out; 2694a421b63SDag-Erling Smørgrav success = 1; 2704a421b63SDag-Erling Smørgrav out: 2714a421b63SDag-Erling Smørgrav buffer_free(&keyblob); 2724a421b63SDag-Erling Smørgrav return success; 273e8aafc91SKris Kennaway } 2744a421b63SDag-Erling Smørgrav 2754a421b63SDag-Erling Smørgrav /* 2764a421b63SDag-Erling Smørgrav * Parse the public, unencrypted portion of a RSA1 key. 2774a421b63SDag-Erling Smørgrav */ 2784a421b63SDag-Erling Smørgrav static Key * 2794a421b63SDag-Erling Smørgrav key_parse_public_rsa1(Buffer *blob, char **commentp) 2804a421b63SDag-Erling Smørgrav { 2814a421b63SDag-Erling Smørgrav Key *pub; 282*e146993eSDag-Erling Smørgrav Buffer copy; 2834a421b63SDag-Erling Smørgrav 2844a421b63SDag-Erling Smørgrav /* Check that it is at least big enough to contain the ID string. */ 2854a421b63SDag-Erling Smørgrav if (buffer_len(blob) < sizeof(authfile_id_string)) { 2864a421b63SDag-Erling Smørgrav debug3("Truncated RSA1 identifier"); 2874a421b63SDag-Erling Smørgrav return NULL; 2884a421b63SDag-Erling Smørgrav } 2894a421b63SDag-Erling Smørgrav 2904a421b63SDag-Erling Smørgrav /* 2914a421b63SDag-Erling Smørgrav * Make sure it begins with the id string. Consume the id string 2924a421b63SDag-Erling Smørgrav * from the buffer. 2934a421b63SDag-Erling Smørgrav */ 2944a421b63SDag-Erling Smørgrav if (memcmp(buffer_ptr(blob), authfile_id_string, 2954a421b63SDag-Erling Smørgrav sizeof(authfile_id_string)) != 0) { 2964a421b63SDag-Erling Smørgrav debug3("Incorrect RSA1 identifier"); 2974a421b63SDag-Erling Smørgrav return NULL; 2984a421b63SDag-Erling Smørgrav } 299*e146993eSDag-Erling Smørgrav buffer_init(©); 300*e146993eSDag-Erling Smørgrav buffer_append(©, buffer_ptr(blob), buffer_len(blob)); 301*e146993eSDag-Erling Smørgrav buffer_consume(©, sizeof(authfile_id_string)); 3024a421b63SDag-Erling Smørgrav 3034a421b63SDag-Erling Smørgrav /* Skip cipher type and reserved data. */ 304*e146993eSDag-Erling Smørgrav (void) buffer_get_char(©); /* cipher type */ 305*e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); /* reserved */ 3064a421b63SDag-Erling Smørgrav 3074a421b63SDag-Erling Smørgrav /* Read the public key from the buffer. */ 308*e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); 3094a421b63SDag-Erling Smørgrav pub = key_new(KEY_RSA1); 310*e146993eSDag-Erling Smørgrav buffer_get_bignum(©, pub->rsa->n); 311*e146993eSDag-Erling Smørgrav buffer_get_bignum(©, pub->rsa->e); 3124a421b63SDag-Erling Smørgrav if (commentp) 313*e146993eSDag-Erling Smørgrav *commentp = buffer_get_string(©, NULL); 3144a421b63SDag-Erling Smørgrav /* The encrypted private part is not parsed by this function. */ 315*e146993eSDag-Erling Smørgrav buffer_free(©); 3164a421b63SDag-Erling Smørgrav 3174a421b63SDag-Erling Smørgrav return pub; 3184a421b63SDag-Erling Smørgrav } 3194a421b63SDag-Erling Smørgrav 320*e146993eSDag-Erling Smørgrav /* Load a key from a fd into a buffer */ 321*e146993eSDag-Erling Smørgrav int 3224a421b63SDag-Erling Smørgrav key_load_file(int fd, const char *filename, Buffer *blob) 3234a421b63SDag-Erling Smørgrav { 324*e146993eSDag-Erling Smørgrav u_char buf[1024]; 3254a421b63SDag-Erling Smørgrav size_t len; 3264a421b63SDag-Erling Smørgrav struct stat st; 3274a421b63SDag-Erling Smørgrav 3284a421b63SDag-Erling Smørgrav if (fstat(fd, &st) < 0) { 3294a421b63SDag-Erling Smørgrav error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, 3304a421b63SDag-Erling Smørgrav filename == NULL ? "" : filename, 3314a421b63SDag-Erling Smørgrav filename == NULL ? "" : " ", 3324a421b63SDag-Erling Smørgrav strerror(errno)); 333e8aafc91SKris Kennaway return 0; 334e8aafc91SKris Kennaway } 335*e146993eSDag-Erling Smørgrav if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 336*e146993eSDag-Erling Smørgrav st.st_size > MAX_KEY_FILE_SIZE) { 337*e146993eSDag-Erling Smørgrav toobig: 3384a421b63SDag-Erling Smørgrav error("%s: key file %.200s%stoo large", __func__, 3394a421b63SDag-Erling Smørgrav filename == NULL ? "" : filename, 3404a421b63SDag-Erling Smørgrav filename == NULL ? "" : " "); 3414a421b63SDag-Erling Smørgrav return 0; 3424a421b63SDag-Erling Smørgrav } 3434a421b63SDag-Erling Smørgrav buffer_init(blob); 344*e146993eSDag-Erling Smørgrav for (;;) { 345*e146993eSDag-Erling Smørgrav if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 346*e146993eSDag-Erling Smørgrav if (errno == EPIPE) 347*e146993eSDag-Erling Smørgrav break; 348*e146993eSDag-Erling Smørgrav debug("%s: read from key file %.200s%sfailed: %.100s", 349*e146993eSDag-Erling Smørgrav __func__, filename == NULL ? "" : filename, 350*e146993eSDag-Erling Smørgrav filename == NULL ? "" : " ", strerror(errno)); 3514a421b63SDag-Erling Smørgrav buffer_clear(blob); 352*e146993eSDag-Erling Smørgrav bzero(buf, sizeof(buf)); 3534a421b63SDag-Erling Smørgrav return 0; 3544a421b63SDag-Erling Smørgrav } 355*e146993eSDag-Erling Smørgrav buffer_append(blob, buf, len); 356*e146993eSDag-Erling Smørgrav if (buffer_len(blob) > MAX_KEY_FILE_SIZE) { 357*e146993eSDag-Erling Smørgrav buffer_clear(blob); 358*e146993eSDag-Erling Smørgrav bzero(buf, sizeof(buf)); 359*e146993eSDag-Erling Smørgrav goto toobig; 360*e146993eSDag-Erling Smørgrav } 361*e146993eSDag-Erling Smørgrav } 362*e146993eSDag-Erling Smørgrav bzero(buf, sizeof(buf)); 363*e146993eSDag-Erling Smørgrav if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 364*e146993eSDag-Erling Smørgrav st.st_size != buffer_len(blob)) { 365*e146993eSDag-Erling Smørgrav debug("%s: key file %.200s%schanged size while reading", 366*e146993eSDag-Erling Smørgrav __func__, filename == NULL ? "" : filename, 367*e146993eSDag-Erling Smørgrav filename == NULL ? "" : " "); 368*e146993eSDag-Erling Smørgrav buffer_clear(blob); 369*e146993eSDag-Erling Smørgrav return 0; 370*e146993eSDag-Erling Smørgrav } 371*e146993eSDag-Erling Smørgrav 3724a421b63SDag-Erling Smørgrav return 1; 3734a421b63SDag-Erling Smørgrav } 374e8aafc91SKris Kennaway 375511b41d2SMark Murray /* 376ca3176e7SBrian Feldman * Loads the public part of the ssh v1 key file. Returns NULL if an error was 377ca3176e7SBrian Feldman * encountered (the file does not exist or is not readable), and the key 378511b41d2SMark Murray * otherwise. 379511b41d2SMark Murray */ 380af12a3e7SDag-Erling Smørgrav static Key * 381ca3176e7SBrian Feldman key_load_public_rsa1(int fd, const char *filename, char **commentp) 382511b41d2SMark Murray { 383511b41d2SMark Murray Buffer buffer; 384ca3176e7SBrian Feldman Key *pub; 385511b41d2SMark Murray 386511b41d2SMark Murray buffer_init(&buffer); 3874a421b63SDag-Erling Smørgrav if (!key_load_file(fd, filename, &buffer)) { 388511b41d2SMark Murray buffer_free(&buffer); 389ca3176e7SBrian Feldman return NULL; 390511b41d2SMark Murray } 391511b41d2SMark Murray 3924a421b63SDag-Erling Smørgrav pub = key_parse_public_rsa1(&buffer, commentp); 3934a421b63SDag-Erling Smørgrav if (pub == NULL) 3944a421b63SDag-Erling Smørgrav debug3("Could not load \"%s\" as a RSA1 public key", filename); 395511b41d2SMark Murray buffer_free(&buffer); 396ca3176e7SBrian Feldman return pub; 397511b41d2SMark Murray } 398511b41d2SMark Murray 399ca3176e7SBrian Feldman /* load public key from private-key file, works only for SSH v1 */ 400ca3176e7SBrian Feldman Key * 401ca3176e7SBrian Feldman key_load_public_type(int type, const char *filename, char **commentp) 402e8aafc91SKris Kennaway { 403ca3176e7SBrian Feldman Key *pub; 404ca3176e7SBrian Feldman int fd; 405ca3176e7SBrian Feldman 406ca3176e7SBrian Feldman if (type == KEY_RSA1) { 407ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 408ca3176e7SBrian Feldman if (fd < 0) 409ca3176e7SBrian Feldman return NULL; 410ca3176e7SBrian Feldman pub = key_load_public_rsa1(fd, filename, commentp); 411ca3176e7SBrian Feldman close(fd); 412ca3176e7SBrian Feldman return pub; 413e8aafc91SKris Kennaway } 414ca3176e7SBrian Feldman return NULL; 415e8aafc91SKris Kennaway } 416e8aafc91SKris Kennaway 417af12a3e7SDag-Erling Smørgrav static Key * 4184a421b63SDag-Erling Smørgrav key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) 419511b41d2SMark Murray { 420d4ecd108SDag-Erling Smørgrav int check1, check2, cipher_type; 4214a421b63SDag-Erling Smørgrav Buffer decrypted; 422af12a3e7SDag-Erling Smørgrav u_char *cp; 42309958426SBrian Feldman CipherContext ciphercontext; 42409958426SBrian Feldman Cipher *cipher; 425ca3176e7SBrian Feldman Key *prv = NULL; 426*e146993eSDag-Erling Smørgrav Buffer copy; 427511b41d2SMark Murray 428ca3176e7SBrian Feldman /* Check that it is at least big enough to contain the ID string. */ 4294a421b63SDag-Erling Smørgrav if (buffer_len(blob) < sizeof(authfile_id_string)) { 4304a421b63SDag-Erling Smørgrav debug3("Truncated RSA1 identifier"); 431ca3176e7SBrian Feldman return NULL; 432511b41d2SMark Murray } 4334a421b63SDag-Erling Smørgrav 434511b41d2SMark Murray /* 435511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 436511b41d2SMark Murray * from the buffer. 437511b41d2SMark Murray */ 4384a421b63SDag-Erling Smørgrav if (memcmp(buffer_ptr(blob), authfile_id_string, 4394a421b63SDag-Erling Smørgrav sizeof(authfile_id_string)) != 0) { 4404a421b63SDag-Erling Smørgrav debug3("Incorrect RSA1 identifier"); 441ca3176e7SBrian Feldman return NULL; 442511b41d2SMark Murray } 443*e146993eSDag-Erling Smørgrav buffer_init(©); 444*e146993eSDag-Erling Smørgrav buffer_append(©, buffer_ptr(blob), buffer_len(blob)); 445*e146993eSDag-Erling Smørgrav buffer_consume(©, sizeof(authfile_id_string)); 446ca3176e7SBrian Feldman 447511b41d2SMark Murray /* Read cipher type. */ 448*e146993eSDag-Erling Smørgrav cipher_type = buffer_get_char(©); 449*e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); /* Reserved data. */ 450511b41d2SMark Murray 451511b41d2SMark Murray /* Read the public key from the buffer. */ 452*e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); 453ca3176e7SBrian Feldman prv = key_new_private(KEY_RSA1); 454ca3176e7SBrian Feldman 455*e146993eSDag-Erling Smørgrav buffer_get_bignum(©, prv->rsa->n); 456*e146993eSDag-Erling Smørgrav buffer_get_bignum(©, prv->rsa->e); 457ca3176e7SBrian Feldman if (commentp) 458*e146993eSDag-Erling Smørgrav *commentp = buffer_get_string(©, NULL); 459511b41d2SMark Murray else 460*e146993eSDag-Erling Smørgrav (void)buffer_get_string_ptr(©, NULL); 461511b41d2SMark Murray 462511b41d2SMark Murray /* Check that it is a supported cipher. */ 46309958426SBrian Feldman cipher = cipher_by_number(cipher_type); 46409958426SBrian Feldman if (cipher == NULL) { 4654a421b63SDag-Erling Smørgrav debug("Unsupported RSA1 cipher %d", cipher_type); 466*e146993eSDag-Erling Smørgrav buffer_free(©); 467511b41d2SMark Murray goto fail; 468511b41d2SMark Murray } 469511b41d2SMark Murray /* Initialize space for decrypted data. */ 470511b41d2SMark Murray buffer_init(&decrypted); 471*e146993eSDag-Erling Smørgrav cp = buffer_append_space(&decrypted, buffer_len(©)); 472511b41d2SMark Murray 473511b41d2SMark Murray /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 474af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 475af12a3e7SDag-Erling Smørgrav CIPHER_DECRYPT); 476af12a3e7SDag-Erling Smørgrav cipher_crypt(&ciphercontext, cp, 477*e146993eSDag-Erling Smørgrav buffer_ptr(©), buffer_len(©)); 478af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 47909958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 480*e146993eSDag-Erling Smørgrav buffer_free(©); 481511b41d2SMark Murray 482511b41d2SMark Murray check1 = buffer_get_char(&decrypted); 483511b41d2SMark Murray check2 = buffer_get_char(&decrypted); 484511b41d2SMark Murray if (check1 != buffer_get_char(&decrypted) || 485511b41d2SMark Murray check2 != buffer_get_char(&decrypted)) { 486511b41d2SMark Murray if (strcmp(passphrase, "") != 0) 4874a421b63SDag-Erling Smørgrav debug("Bad passphrase supplied for RSA1 key"); 488511b41d2SMark Murray /* Bad passphrase. */ 489511b41d2SMark Murray buffer_free(&decrypted); 490ca3176e7SBrian Feldman goto fail; 491511b41d2SMark Murray } 492511b41d2SMark Murray /* Read the rest of the private key. */ 493ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->d); 494ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ 495ca3176e7SBrian Feldman /* in SSL and SSH v1 p and q are exchanged */ 496ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ 497ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ 498511b41d2SMark Murray 499ca3176e7SBrian Feldman /* calculate p-1 and q-1 */ 500af12a3e7SDag-Erling Smørgrav rsa_generate_additional_parameters(prv->rsa); 501511b41d2SMark Murray 502511b41d2SMark Murray buffer_free(&decrypted); 503e73e9afaSDag-Erling Smørgrav 504e73e9afaSDag-Erling Smørgrav /* enable blinding */ 505e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 5064a421b63SDag-Erling Smørgrav error("%s: RSA_blinding_on failed", __func__); 507e73e9afaSDag-Erling Smørgrav goto fail; 508e73e9afaSDag-Erling Smørgrav } 509ca3176e7SBrian Feldman return prv; 510511b41d2SMark Murray 511ca3176e7SBrian Feldman fail: 512ca3176e7SBrian Feldman if (commentp) 513ca3176e7SBrian Feldman xfree(*commentp); 514ca3176e7SBrian Feldman key_free(prv); 515ca3176e7SBrian Feldman return NULL; 516511b41d2SMark Murray } 517e8aafc91SKris Kennaway 5184a421b63SDag-Erling Smørgrav static Key * 5194a421b63SDag-Erling Smørgrav key_parse_private_pem(Buffer *blob, int type, const char *passphrase, 520ca3176e7SBrian Feldman char **commentp) 521e8aafc91SKris Kennaway { 522ca3176e7SBrian Feldman EVP_PKEY *pk = NULL; 523ca3176e7SBrian Feldman Key *prv = NULL; 524ca3176e7SBrian Feldman char *name = "<no key>"; 5254a421b63SDag-Erling Smørgrav BIO *bio; 526e8aafc91SKris Kennaway 5274a421b63SDag-Erling Smørgrav if ((bio = BIO_new_mem_buf(buffer_ptr(blob), 5284a421b63SDag-Erling Smørgrav buffer_len(blob))) == NULL) { 5294a421b63SDag-Erling Smørgrav error("%s: BIO_new_mem_buf failed", __func__); 530ca3176e7SBrian Feldman return NULL; 531e8aafc91SKris Kennaway } 5324a421b63SDag-Erling Smørgrav 5334a421b63SDag-Erling Smørgrav pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); 5344a421b63SDag-Erling Smørgrav BIO_free(bio); 535ca3176e7SBrian Feldman if (pk == NULL) { 5364a421b63SDag-Erling Smørgrav debug("%s: PEM_read_PrivateKey failed", __func__); 537ca3176e7SBrian Feldman (void)ERR_get_error(); 538ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_RSA && 539ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_RSA)) { 540ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 541ca3176e7SBrian Feldman prv->rsa = EVP_PKEY_get1_RSA(pk); 542ca3176e7SBrian Feldman prv->type = KEY_RSA; 543ca3176e7SBrian Feldman name = "rsa w/o comment"; 544ca3176e7SBrian Feldman #ifdef DEBUG_PK 545ca3176e7SBrian Feldman RSA_print_fp(stderr, prv->rsa, 8); 546e8aafc91SKris Kennaway #endif 547e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 5484a421b63SDag-Erling Smørgrav error("%s: RSA_blinding_on failed", __func__); 549e73e9afaSDag-Erling Smørgrav key_free(prv); 550e73e9afaSDag-Erling Smørgrav prv = NULL; 551e73e9afaSDag-Erling Smørgrav } 552ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_DSA && 553ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_DSA)) { 554ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 555ca3176e7SBrian Feldman prv->dsa = EVP_PKEY_get1_DSA(pk); 556ca3176e7SBrian Feldman prv->type = KEY_DSA; 557ca3176e7SBrian Feldman name = "dsa w/o comment"; 558ca3176e7SBrian Feldman #ifdef DEBUG_PK 559ca3176e7SBrian Feldman DSA_print_fp(stderr, prv->dsa, 8); 560ca3176e7SBrian Feldman #endif 5614a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 5624a421b63SDag-Erling Smørgrav } else if (pk->type == EVP_PKEY_EC && 5634a421b63SDag-Erling Smørgrav (type == KEY_UNSPEC||type==KEY_ECDSA)) { 5644a421b63SDag-Erling Smørgrav prv = key_new(KEY_UNSPEC); 5654a421b63SDag-Erling Smørgrav prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); 5664a421b63SDag-Erling Smørgrav prv->type = KEY_ECDSA; 5674a421b63SDag-Erling Smørgrav if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || 5684a421b63SDag-Erling Smørgrav key_curve_nid_to_name(prv->ecdsa_nid) == NULL || 5694a421b63SDag-Erling Smørgrav key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), 5704a421b63SDag-Erling Smørgrav EC_KEY_get0_public_key(prv->ecdsa)) != 0 || 5714a421b63SDag-Erling Smørgrav key_ec_validate_private(prv->ecdsa) != 0) { 5724a421b63SDag-Erling Smørgrav error("%s: bad ECDSA key", __func__); 5734a421b63SDag-Erling Smørgrav key_free(prv); 5744a421b63SDag-Erling Smørgrav prv = NULL; 575ca3176e7SBrian Feldman } 5764a421b63SDag-Erling Smørgrav name = "ecdsa w/o comment"; 5774a421b63SDag-Erling Smørgrav #ifdef DEBUG_PK 5784a421b63SDag-Erling Smørgrav if (prv != NULL && prv->ecdsa != NULL) 5794a421b63SDag-Erling Smørgrav key_dump_ec_key(prv->ecdsa); 5804a421b63SDag-Erling Smørgrav #endif 5814a421b63SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 5824a421b63SDag-Erling Smørgrav } else { 5834a421b63SDag-Erling Smørgrav error("%s: PEM_read_PrivateKey: mismatch or " 5844a421b63SDag-Erling Smørgrav "unknown EVP_PKEY save_type %d", __func__, pk->save_type); 5854a421b63SDag-Erling Smørgrav } 586ca3176e7SBrian Feldman if (pk != NULL) 587ca3176e7SBrian Feldman EVP_PKEY_free(pk); 588ca3176e7SBrian Feldman if (prv != NULL && commentp) 589ca3176e7SBrian Feldman *commentp = xstrdup(name); 590ca3176e7SBrian Feldman debug("read PEM private key done: type %s", 591ca3176e7SBrian Feldman prv ? key_type(prv) : "<unknown>"); 592ca3176e7SBrian Feldman return prv; 593e8aafc91SKris Kennaway } 594e8aafc91SKris Kennaway 5954a421b63SDag-Erling Smørgrav Key * 5964a421b63SDag-Erling Smørgrav key_load_private_pem(int fd, int type, const char *passphrase, 5974a421b63SDag-Erling Smørgrav char **commentp) 5984a421b63SDag-Erling Smørgrav { 5994a421b63SDag-Erling Smørgrav Buffer buffer; 6004a421b63SDag-Erling Smørgrav Key *prv; 6014a421b63SDag-Erling Smørgrav 6024a421b63SDag-Erling Smørgrav buffer_init(&buffer); 6034a421b63SDag-Erling Smørgrav if (!key_load_file(fd, NULL, &buffer)) { 6044a421b63SDag-Erling Smørgrav buffer_free(&buffer); 6054a421b63SDag-Erling Smørgrav return NULL; 6064a421b63SDag-Erling Smørgrav } 6074a421b63SDag-Erling Smørgrav prv = key_parse_private_pem(&buffer, type, passphrase, commentp); 6084a421b63SDag-Erling Smørgrav buffer_free(&buffer); 6094a421b63SDag-Erling Smørgrav return prv; 6104a421b63SDag-Erling Smørgrav } 6114a421b63SDag-Erling Smørgrav 612333ee039SDag-Erling Smørgrav int 613ca3176e7SBrian Feldman key_perm_ok(int fd, const char *filename) 614e8aafc91SKris Kennaway { 615e8aafc91SKris Kennaway struct stat st; 616e8aafc91SKris Kennaway 617af12a3e7SDag-Erling Smørgrav if (fstat(fd, &st) < 0) 618af12a3e7SDag-Erling Smørgrav return 0; 619af12a3e7SDag-Erling Smørgrav /* 620af12a3e7SDag-Erling Smørgrav * if a key owned by the user is accessed, then we check the 621af12a3e7SDag-Erling Smørgrav * permissions of the file. if the key owned by a different user, 622af12a3e7SDag-Erling Smørgrav * then we don't care. 623af12a3e7SDag-Erling Smørgrav */ 624989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 625989dd127SDag-Erling Smørgrav if (check_ntsec(filename)) 626989dd127SDag-Erling Smørgrav #endif 627af12a3e7SDag-Erling Smørgrav if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { 628e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 629e8aafc91SKris Kennaway error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 630e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 631af12a3e7SDag-Erling Smørgrav error("Permissions 0%3.3o for '%s' are too open.", 632cf2b5f3bSDag-Erling Smørgrav (u_int)st.st_mode & 0777, filename); 633*e146993eSDag-Erling Smørgrav error("It is required that your private key files are NOT accessible by others."); 634ca3176e7SBrian Feldman error("This private key will be ignored."); 635e8aafc91SKris Kennaway return 0; 636e8aafc91SKris Kennaway } 637ca3176e7SBrian Feldman return 1; 638e8aafc91SKris Kennaway } 639ca3176e7SBrian Feldman 6404a421b63SDag-Erling Smørgrav static Key * 6414a421b63SDag-Erling Smørgrav key_parse_private_type(Buffer *blob, int type, const char *passphrase, 6424a421b63SDag-Erling Smørgrav char **commentp) 6434a421b63SDag-Erling Smørgrav { 6444a421b63SDag-Erling Smørgrav switch (type) { 6454a421b63SDag-Erling Smørgrav case KEY_RSA1: 6464a421b63SDag-Erling Smørgrav return key_parse_private_rsa1(blob, passphrase, commentp); 6474a421b63SDag-Erling Smørgrav case KEY_DSA: 6484a421b63SDag-Erling Smørgrav case KEY_ECDSA: 6494a421b63SDag-Erling Smørgrav case KEY_RSA: 6504a421b63SDag-Erling Smørgrav case KEY_UNSPEC: 6514a421b63SDag-Erling Smørgrav return key_parse_private_pem(blob, type, passphrase, commentp); 6524a421b63SDag-Erling Smørgrav default: 653*e146993eSDag-Erling Smørgrav error("%s: cannot parse key type %d", __func__, type); 6544a421b63SDag-Erling Smørgrav break; 6554a421b63SDag-Erling Smørgrav } 6564a421b63SDag-Erling Smørgrav return NULL; 6574a421b63SDag-Erling Smørgrav } 6584a421b63SDag-Erling Smørgrav 659ca3176e7SBrian Feldman Key * 660ca3176e7SBrian Feldman key_load_private_type(int type, const char *filename, const char *passphrase, 661333ee039SDag-Erling Smørgrav char **commentp, int *perm_ok) 662ca3176e7SBrian Feldman { 663ca3176e7SBrian Feldman int fd; 6644a421b63SDag-Erling Smørgrav Key *ret; 6654a421b63SDag-Erling Smørgrav Buffer buffer; 666ca3176e7SBrian Feldman 667ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 668b15c8340SDag-Erling Smørgrav if (fd < 0) { 669b15c8340SDag-Erling Smørgrav debug("could not open key file '%s': %s", filename, 670b15c8340SDag-Erling Smørgrav strerror(errno)); 671b15c8340SDag-Erling Smørgrav if (perm_ok != NULL) 672b15c8340SDag-Erling Smørgrav *perm_ok = 0; 673ca3176e7SBrian Feldman return NULL; 674b15c8340SDag-Erling Smørgrav } 675ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 676333ee039SDag-Erling Smørgrav if (perm_ok != NULL) 677333ee039SDag-Erling Smørgrav *perm_ok = 0; 678ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 679ca3176e7SBrian Feldman close(fd); 680ca3176e7SBrian Feldman return NULL; 681e8aafc91SKris Kennaway } 682333ee039SDag-Erling Smørgrav if (perm_ok != NULL) 683333ee039SDag-Erling Smørgrav *perm_ok = 1; 6844a421b63SDag-Erling Smørgrav 6854a421b63SDag-Erling Smørgrav buffer_init(&buffer); 6864a421b63SDag-Erling Smørgrav if (!key_load_file(fd, filename, &buffer)) { 6874a421b63SDag-Erling Smørgrav buffer_free(&buffer); 688ca3176e7SBrian Feldman close(fd); 689ca3176e7SBrian Feldman return NULL; 690ca3176e7SBrian Feldman } 6914a421b63SDag-Erling Smørgrav close(fd); 6924a421b63SDag-Erling Smørgrav ret = key_parse_private_type(&buffer, type, passphrase, commentp); 6934a421b63SDag-Erling Smørgrav buffer_free(&buffer); 6944a421b63SDag-Erling Smørgrav return ret; 6954a421b63SDag-Erling Smørgrav } 696ca3176e7SBrian Feldman 697ca3176e7SBrian Feldman Key * 698*e146993eSDag-Erling Smørgrav key_parse_private(Buffer *buffer, const char *filename, 699*e146993eSDag-Erling Smørgrav const char *passphrase, char **commentp) 700*e146993eSDag-Erling Smørgrav { 701*e146993eSDag-Erling Smørgrav Key *pub, *prv; 702*e146993eSDag-Erling Smørgrav 703*e146993eSDag-Erling Smørgrav /* it's a SSH v1 key if the public key part is readable */ 704*e146993eSDag-Erling Smørgrav pub = key_parse_public_rsa1(buffer, commentp); 705*e146993eSDag-Erling Smørgrav if (pub == NULL) { 706*e146993eSDag-Erling Smørgrav prv = key_parse_private_type(buffer, KEY_UNSPEC, 707*e146993eSDag-Erling Smørgrav passphrase, NULL); 708*e146993eSDag-Erling Smørgrav /* use the filename as a comment for PEM */ 709*e146993eSDag-Erling Smørgrav if (commentp && prv) 710*e146993eSDag-Erling Smørgrav *commentp = xstrdup(filename); 711*e146993eSDag-Erling Smørgrav } else { 712*e146993eSDag-Erling Smørgrav key_free(pub); 713*e146993eSDag-Erling Smørgrav /* key_parse_public_rsa1() has already loaded the comment */ 714*e146993eSDag-Erling Smørgrav prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, 715*e146993eSDag-Erling Smørgrav NULL); 716*e146993eSDag-Erling Smørgrav } 717*e146993eSDag-Erling Smørgrav return prv; 718*e146993eSDag-Erling Smørgrav } 719*e146993eSDag-Erling Smørgrav 720*e146993eSDag-Erling Smørgrav Key * 721ca3176e7SBrian Feldman key_load_private(const char *filename, const char *passphrase, 722ca3176e7SBrian Feldman char **commentp) 723ca3176e7SBrian Feldman { 724*e146993eSDag-Erling Smørgrav Key *prv; 725*e146993eSDag-Erling Smørgrav Buffer buffer; 726ca3176e7SBrian Feldman int fd; 727ca3176e7SBrian Feldman 728ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 729b15c8340SDag-Erling Smørgrav if (fd < 0) { 730b15c8340SDag-Erling Smørgrav debug("could not open key file '%s': %s", filename, 731b15c8340SDag-Erling Smørgrav strerror(errno)); 732ca3176e7SBrian Feldman return NULL; 733b15c8340SDag-Erling Smørgrav } 734ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 735ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 736e8aafc91SKris Kennaway close(fd); 737ca3176e7SBrian Feldman return NULL; 738ca3176e7SBrian Feldman } 7394a421b63SDag-Erling Smørgrav 7404a421b63SDag-Erling Smørgrav buffer_init(&buffer); 7414a421b63SDag-Erling Smørgrav if (!key_load_file(fd, filename, &buffer)) { 7424a421b63SDag-Erling Smørgrav buffer_free(&buffer); 7434a421b63SDag-Erling Smørgrav close(fd); 7444a421b63SDag-Erling Smørgrav return NULL; 7454a421b63SDag-Erling Smørgrav } 7464a421b63SDag-Erling Smørgrav close(fd); 7474a421b63SDag-Erling Smørgrav 748*e146993eSDag-Erling Smørgrav prv = key_parse_private(&buffer, filename, passphrase, commentp); 7494a421b63SDag-Erling Smørgrav buffer_free(&buffer); 750af12a3e7SDag-Erling Smørgrav return prv; 751e8aafc91SKris Kennaway } 752c2d3a559SKris Kennaway 753af12a3e7SDag-Erling Smørgrav static int 754ca3176e7SBrian Feldman key_try_load_public(Key *k, const char *filename, char **commentp) 755c2d3a559SKris Kennaway { 756c2d3a559SKris Kennaway FILE *f; 757aa49c926SDag-Erling Smørgrav char line[SSH_MAX_PUBKEY_BYTES]; 758c2d3a559SKris Kennaway char *cp; 759aa49c926SDag-Erling Smørgrav u_long linenum = 0; 760c2d3a559SKris Kennaway 761c2d3a559SKris Kennaway f = fopen(filename, "r"); 762c2d3a559SKris Kennaway if (f != NULL) { 763aa49c926SDag-Erling Smørgrav while (read_keyfile_line(f, filename, line, sizeof(line), 764aa49c926SDag-Erling Smørgrav &linenum) != -1) { 765c2d3a559SKris Kennaway cp = line; 766c2d3a559SKris Kennaway switch (*cp) { 767c2d3a559SKris Kennaway case '#': 768c2d3a559SKris Kennaway case '\n': 769c2d3a559SKris Kennaway case '\0': 770c2d3a559SKris Kennaway continue; 771c2d3a559SKris Kennaway } 772*e146993eSDag-Erling Smørgrav /* Abort loading if this looks like a private key */ 773*e146993eSDag-Erling Smørgrav if (strncmp(cp, "-----BEGIN", 10) == 0) 774*e146993eSDag-Erling Smørgrav break; 775c2d3a559SKris Kennaway /* Skip leading whitespace. */ 776c2d3a559SKris Kennaway for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 777c2d3a559SKris Kennaway ; 778c2d3a559SKris Kennaway if (*cp) { 779ca3176e7SBrian Feldman if (key_read(k, &cp) == 1) { 780*e146993eSDag-Erling Smørgrav cp[strcspn(cp, "\r\n")] = '\0'; 781*e146993eSDag-Erling Smørgrav if (commentp) { 782*e146993eSDag-Erling Smørgrav *commentp = xstrdup(*cp ? 783*e146993eSDag-Erling Smørgrav cp : filename); 784*e146993eSDag-Erling Smørgrav } 785c2d3a559SKris Kennaway fclose(f); 786c2d3a559SKris Kennaway return 1; 787c2d3a559SKris Kennaway } 788c2d3a559SKris Kennaway } 789c2d3a559SKris Kennaway } 790c2d3a559SKris Kennaway fclose(f); 791c2d3a559SKris Kennaway } 792c2d3a559SKris Kennaway return 0; 793c2d3a559SKris Kennaway } 794c2d3a559SKris Kennaway 795ca3176e7SBrian Feldman /* load public key from ssh v1 private or any pubkey file */ 796ca3176e7SBrian Feldman Key * 797ca3176e7SBrian Feldman key_load_public(const char *filename, char **commentp) 798c2d3a559SKris Kennaway { 799ca3176e7SBrian Feldman Key *pub; 800ca3176e7SBrian Feldman char file[MAXPATHLEN]; 801c2d3a559SKris Kennaway 802cf2b5f3bSDag-Erling Smørgrav /* try rsa1 private key */ 803ca3176e7SBrian Feldman pub = key_load_public_type(KEY_RSA1, filename, commentp); 804ca3176e7SBrian Feldman if (pub != NULL) 805ca3176e7SBrian Feldman return pub; 806cf2b5f3bSDag-Erling Smørgrav 807cf2b5f3bSDag-Erling Smørgrav /* try rsa1 public key */ 808cf2b5f3bSDag-Erling Smørgrav pub = key_new(KEY_RSA1); 809cf2b5f3bSDag-Erling Smørgrav if (key_try_load_public(pub, filename, commentp) == 1) 810cf2b5f3bSDag-Erling Smørgrav return pub; 811cf2b5f3bSDag-Erling Smørgrav key_free(pub); 812cf2b5f3bSDag-Erling Smørgrav 813cf2b5f3bSDag-Erling Smørgrav /* try ssh2 public key */ 814ca3176e7SBrian Feldman pub = key_new(KEY_UNSPEC); 815ca3176e7SBrian Feldman if (key_try_load_public(pub, filename, commentp) == 1) 816ca3176e7SBrian Feldman return pub; 817ca3176e7SBrian Feldman if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && 818ca3176e7SBrian Feldman (strlcat(file, ".pub", sizeof file) < sizeof(file)) && 819ca3176e7SBrian Feldman (key_try_load_public(pub, file, commentp) == 1)) 820ca3176e7SBrian Feldman return pub; 821ca3176e7SBrian Feldman key_free(pub); 822ca3176e7SBrian Feldman return NULL; 823c2d3a559SKris Kennaway } 824b15c8340SDag-Erling Smørgrav 825e2f6069cSDag-Erling Smørgrav /* Load the certificate associated with the named private key */ 826e2f6069cSDag-Erling Smørgrav Key * 827e2f6069cSDag-Erling Smørgrav key_load_cert(const char *filename) 828e2f6069cSDag-Erling Smørgrav { 829e2f6069cSDag-Erling Smørgrav Key *pub; 830e2f6069cSDag-Erling Smørgrav char *file; 831e2f6069cSDag-Erling Smørgrav 832e2f6069cSDag-Erling Smørgrav pub = key_new(KEY_UNSPEC); 833e2f6069cSDag-Erling Smørgrav xasprintf(&file, "%s-cert.pub", filename); 834e2f6069cSDag-Erling Smørgrav if (key_try_load_public(pub, file, NULL) == 1) { 835e2f6069cSDag-Erling Smørgrav xfree(file); 836e2f6069cSDag-Erling Smørgrav return pub; 837e2f6069cSDag-Erling Smørgrav } 838e2f6069cSDag-Erling Smørgrav xfree(file); 839e2f6069cSDag-Erling Smørgrav key_free(pub); 840e2f6069cSDag-Erling Smørgrav return NULL; 841e2f6069cSDag-Erling Smørgrav } 842e2f6069cSDag-Erling Smørgrav 843e2f6069cSDag-Erling Smørgrav /* Load private key and certificate */ 844e2f6069cSDag-Erling Smørgrav Key * 845e2f6069cSDag-Erling Smørgrav key_load_private_cert(int type, const char *filename, const char *passphrase, 846e2f6069cSDag-Erling Smørgrav int *perm_ok) 847e2f6069cSDag-Erling Smørgrav { 848e2f6069cSDag-Erling Smørgrav Key *key, *pub; 849e2f6069cSDag-Erling Smørgrav 850e2f6069cSDag-Erling Smørgrav switch (type) { 851e2f6069cSDag-Erling Smørgrav case KEY_RSA: 852e2f6069cSDag-Erling Smørgrav case KEY_DSA: 8534a421b63SDag-Erling Smørgrav case KEY_ECDSA: 854e2f6069cSDag-Erling Smørgrav break; 855e2f6069cSDag-Erling Smørgrav default: 856e2f6069cSDag-Erling Smørgrav error("%s: unsupported key type", __func__); 857e2f6069cSDag-Erling Smørgrav return NULL; 858e2f6069cSDag-Erling Smørgrav } 859e2f6069cSDag-Erling Smørgrav 860e2f6069cSDag-Erling Smørgrav if ((key = key_load_private_type(type, filename, 861e2f6069cSDag-Erling Smørgrav passphrase, NULL, perm_ok)) == NULL) 862e2f6069cSDag-Erling Smørgrav return NULL; 863e2f6069cSDag-Erling Smørgrav 864e2f6069cSDag-Erling Smørgrav if ((pub = key_load_cert(filename)) == NULL) { 865e2f6069cSDag-Erling Smørgrav key_free(key); 866e2f6069cSDag-Erling Smørgrav return NULL; 867e2f6069cSDag-Erling Smørgrav } 868e2f6069cSDag-Erling Smørgrav 869e2f6069cSDag-Erling Smørgrav /* Make sure the private key matches the certificate */ 870e2f6069cSDag-Erling Smørgrav if (key_equal_public(key, pub) == 0) { 871e2f6069cSDag-Erling Smørgrav error("%s: certificate does not match private key %s", 872e2f6069cSDag-Erling Smørgrav __func__, filename); 873e2f6069cSDag-Erling Smørgrav } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { 874e2f6069cSDag-Erling Smørgrav error("%s: key_to_certified failed", __func__); 875e2f6069cSDag-Erling Smørgrav } else { 876e2f6069cSDag-Erling Smørgrav key_cert_copy(pub, key); 877e2f6069cSDag-Erling Smørgrav key_free(pub); 878e2f6069cSDag-Erling Smørgrav return key; 879e2f6069cSDag-Erling Smørgrav } 880e2f6069cSDag-Erling Smørgrav 881e2f6069cSDag-Erling Smørgrav key_free(key); 882e2f6069cSDag-Erling Smørgrav key_free(pub); 883e2f6069cSDag-Erling Smørgrav return NULL; 884e2f6069cSDag-Erling Smørgrav } 885e2f6069cSDag-Erling Smørgrav 886b15c8340SDag-Erling Smørgrav /* 887b15c8340SDag-Erling Smørgrav * Returns 1 if the specified "key" is listed in the file "filename", 888b15c8340SDag-Erling Smørgrav * 0 if the key is not listed or -1 on error. 889b15c8340SDag-Erling Smørgrav * If strict_type is set then the key type must match exactly, 890b15c8340SDag-Erling Smørgrav * otherwise a comparison that ignores certficiate data is performed. 891b15c8340SDag-Erling Smørgrav */ 892b15c8340SDag-Erling Smørgrav int 893b15c8340SDag-Erling Smørgrav key_in_file(Key *key, const char *filename, int strict_type) 894b15c8340SDag-Erling Smørgrav { 895b15c8340SDag-Erling Smørgrav FILE *f; 896b15c8340SDag-Erling Smørgrav char line[SSH_MAX_PUBKEY_BYTES]; 897b15c8340SDag-Erling Smørgrav char *cp; 898b15c8340SDag-Erling Smørgrav u_long linenum = 0; 899b15c8340SDag-Erling Smørgrav int ret = 0; 900b15c8340SDag-Erling Smørgrav Key *pub; 901b15c8340SDag-Erling Smørgrav int (*key_compare)(const Key *, const Key *) = strict_type ? 902b15c8340SDag-Erling Smørgrav key_equal : key_equal_public; 903b15c8340SDag-Erling Smørgrav 904b15c8340SDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) { 905b15c8340SDag-Erling Smørgrav if (errno == ENOENT) { 906b15c8340SDag-Erling Smørgrav debug("%s: keyfile \"%s\" missing", __func__, filename); 907b15c8340SDag-Erling Smørgrav return 0; 908b15c8340SDag-Erling Smørgrav } else { 909b15c8340SDag-Erling Smørgrav error("%s: could not open keyfile \"%s\": %s", __func__, 910b15c8340SDag-Erling Smørgrav filename, strerror(errno)); 911b15c8340SDag-Erling Smørgrav return -1; 912b15c8340SDag-Erling Smørgrav } 913b15c8340SDag-Erling Smørgrav } 914b15c8340SDag-Erling Smørgrav 915b15c8340SDag-Erling Smørgrav while (read_keyfile_line(f, filename, line, sizeof(line), 916b15c8340SDag-Erling Smørgrav &linenum) != -1) { 917b15c8340SDag-Erling Smørgrav cp = line; 918b15c8340SDag-Erling Smørgrav 919b15c8340SDag-Erling Smørgrav /* Skip leading whitespace. */ 920b15c8340SDag-Erling Smørgrav for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 921b15c8340SDag-Erling Smørgrav ; 922b15c8340SDag-Erling Smørgrav 923b15c8340SDag-Erling Smørgrav /* Skip comments and empty lines */ 924b15c8340SDag-Erling Smørgrav switch (*cp) { 925b15c8340SDag-Erling Smørgrav case '#': 926b15c8340SDag-Erling Smørgrav case '\n': 927b15c8340SDag-Erling Smørgrav case '\0': 928b15c8340SDag-Erling Smørgrav continue; 929b15c8340SDag-Erling Smørgrav } 930b15c8340SDag-Erling Smørgrav 931b15c8340SDag-Erling Smørgrav pub = key_new(KEY_UNSPEC); 932b15c8340SDag-Erling Smørgrav if (key_read(pub, &cp) != 1) { 933b15c8340SDag-Erling Smørgrav key_free(pub); 934b15c8340SDag-Erling Smørgrav continue; 935b15c8340SDag-Erling Smørgrav } 936b15c8340SDag-Erling Smørgrav if (key_compare(key, pub)) { 937b15c8340SDag-Erling Smørgrav ret = 1; 938b15c8340SDag-Erling Smørgrav key_free(pub); 939b15c8340SDag-Erling Smørgrav break; 940b15c8340SDag-Erling Smørgrav } 941b15c8340SDag-Erling Smørgrav key_free(pub); 942b15c8340SDag-Erling Smørgrav } 943b15c8340SDag-Erling Smørgrav fclose(f); 944b15c8340SDag-Erling Smørgrav return ret; 945b15c8340SDag-Erling Smørgrav } 946b15c8340SDag-Erling Smørgrav 947