1511b41d2SMark Murray /* 2511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 3511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 4511b41d2SMark Murray * All rights reserved 5511b41d2SMark Murray * This file contains functions for reading and writing identity files, and 6511b41d2SMark Murray * for reading the passphrase from the user. 7511b41d2SMark Murray * 8c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 9c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 10c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 11c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 12c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 13c2d3a559SKris Kennaway * 14c2d3a559SKris Kennaway * 15c2d3a559SKris Kennaway * Copyright (c) 2000 Markus Friedl. All rights reserved. 16c2d3a559SKris Kennaway * 17c2d3a559SKris Kennaway * Redistribution and use in source and binary forms, with or without 18c2d3a559SKris Kennaway * modification, are permitted provided that the following conditions 19c2d3a559SKris Kennaway * are met: 20c2d3a559SKris Kennaway * 1. Redistributions of source code must retain the above copyright 21c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer. 22c2d3a559SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 23c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer in the 24c2d3a559SKris Kennaway * documentation and/or other materials provided with the distribution. 25c2d3a559SKris Kennaway * 26c2d3a559SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27c2d3a559SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28c2d3a559SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29c2d3a559SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30c2d3a559SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31c2d3a559SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32c2d3a559SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33c2d3a559SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34c2d3a559SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35c2d3a559SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36511b41d2SMark Murray */ 37511b41d2SMark Murray 38511b41d2SMark Murray #include "includes.h" 39aa49c926SDag-Erling Smørgrav RCSID("$OpenBSD: authfile.c,v 1.60 2004/12/11 01:48:56 dtucker Exp $"); 40511b41d2SMark Murray 41ca3176e7SBrian Feldman #include <openssl/err.h> 42e8aafc91SKris Kennaway #include <openssl/evp.h> 43ca3176e7SBrian Feldman #include <openssl/pem.h> 44e8aafc91SKris Kennaway 45ca3176e7SBrian Feldman #include "cipher.h" 46511b41d2SMark Murray #include "xmalloc.h" 47511b41d2SMark Murray #include "buffer.h" 48511b41d2SMark Murray #include "bufaux.h" 49e8aafc91SKris Kennaway #include "key.h" 50ca3176e7SBrian Feldman #include "ssh.h" 51ca3176e7SBrian Feldman #include "log.h" 52ca3176e7SBrian Feldman #include "authfile.h" 53af12a3e7SDag-Erling Smørgrav #include "rsa.h" 54aa49c926SDag-Erling Smørgrav #include "misc.h" 55511b41d2SMark Murray 56ca3176e7SBrian Feldman /* Version identification string for SSH v1 identity files. */ 57ca3176e7SBrian Feldman static const char authfile_id_string[] = 58ca3176e7SBrian Feldman "SSH PRIVATE KEY FILE FORMAT 1.1\n"; 59511b41d2SMark Murray 60511b41d2SMark Murray /* 61511b41d2SMark Murray * Saves the authentication (private) key in a file, encrypting it with 62511b41d2SMark Murray * passphrase. The identification of the file (lowest 64 bits of n) will 63511b41d2SMark Murray * precede the key to provide identification of the key without needing a 64511b41d2SMark Murray * passphrase. 65511b41d2SMark Murray */ 66511b41d2SMark Murray 67af12a3e7SDag-Erling Smørgrav static int 68ca3176e7SBrian Feldman key_save_private_rsa1(Key *key, const char *filename, const char *passphrase, 69ca3176e7SBrian Feldman const char *comment) 70511b41d2SMark Murray { 71511b41d2SMark Murray Buffer buffer, encrypted; 72af12a3e7SDag-Erling Smørgrav u_char buf[100], *cp; 73af12a3e7SDag-Erling Smørgrav int fd, i, cipher_num; 7409958426SBrian Feldman CipherContext ciphercontext; 7509958426SBrian Feldman Cipher *cipher; 7621e764dfSDag-Erling Smørgrav u_int32_t rnd; 77511b41d2SMark Murray 78511b41d2SMark Murray /* 79511b41d2SMark Murray * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting 80511b41d2SMark Murray * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. 81511b41d2SMark Murray */ 82af12a3e7SDag-Erling Smørgrav cipher_num = (strcmp(passphrase, "") == 0) ? 83af12a3e7SDag-Erling Smørgrav SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; 84af12a3e7SDag-Erling Smørgrav if ((cipher = cipher_by_number(cipher_num)) == NULL) 8509958426SBrian Feldman fatal("save_private_key_rsa: bad cipher"); 86511b41d2SMark Murray 87511b41d2SMark Murray /* This buffer is used to built the secret part of the private key. */ 88511b41d2SMark Murray buffer_init(&buffer); 89511b41d2SMark Murray 90511b41d2SMark Murray /* Put checkbytes for checking passphrase validity. */ 9121e764dfSDag-Erling Smørgrav rnd = arc4random(); 9221e764dfSDag-Erling Smørgrav buf[0] = rnd & 0xff; 9321e764dfSDag-Erling Smørgrav buf[1] = (rnd >> 8) & 0xff; 94511b41d2SMark Murray buf[2] = buf[0]; 95511b41d2SMark Murray buf[3] = buf[1]; 96511b41d2SMark Murray buffer_append(&buffer, buf, 4); 97511b41d2SMark Murray 98511b41d2SMark Murray /* 99511b41d2SMark Murray * Store the private key (n and e will not be stored because they 100511b41d2SMark Murray * will be stored in plain text, and storing them also in encrypted 101511b41d2SMark Murray * format would just give known plaintext). 102511b41d2SMark Murray */ 103ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->d); 104ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->iqmp); 105ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ 106ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ 107511b41d2SMark Murray 108511b41d2SMark Murray /* Pad the part to be encrypted until its size is a multiple of 8. */ 109511b41d2SMark Murray while (buffer_len(&buffer) % 8 != 0) 110511b41d2SMark Murray buffer_put_char(&buffer, 0); 111511b41d2SMark Murray 112511b41d2SMark Murray /* This buffer will be used to contain the data in the file. */ 113511b41d2SMark Murray buffer_init(&encrypted); 114511b41d2SMark Murray 115511b41d2SMark Murray /* First store keyfile id string. */ 116ca3176e7SBrian Feldman for (i = 0; authfile_id_string[i]; i++) 117ca3176e7SBrian Feldman buffer_put_char(&encrypted, authfile_id_string[i]); 118511b41d2SMark Murray buffer_put_char(&encrypted, 0); 119511b41d2SMark Murray 120511b41d2SMark Murray /* Store cipher type. */ 121af12a3e7SDag-Erling Smørgrav buffer_put_char(&encrypted, cipher_num); 122511b41d2SMark Murray buffer_put_int(&encrypted, 0); /* For future extension */ 123511b41d2SMark Murray 124511b41d2SMark Murray /* Store public key. This will be in plain text. */ 125ca3176e7SBrian Feldman buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); 126ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->n); 127ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->e); 128af12a3e7SDag-Erling Smørgrav buffer_put_cstring(&encrypted, comment); 129511b41d2SMark Murray 130511b41d2SMark Murray /* Allocate space for the private part of the key in the buffer. */ 131af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&encrypted, buffer_len(&buffer)); 132511b41d2SMark Murray 133af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 134af12a3e7SDag-Erling Smørgrav CIPHER_ENCRYPT); 135af12a3e7SDag-Erling Smørgrav cipher_crypt(&ciphercontext, cp, 136af12a3e7SDag-Erling Smørgrav buffer_ptr(&buffer), buffer_len(&buffer)); 137af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 13809958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 139511b41d2SMark Murray 140511b41d2SMark Murray /* Destroy temporary data. */ 141511b41d2SMark Murray memset(buf, 0, sizeof(buf)); 142511b41d2SMark Murray buffer_free(&buffer); 143511b41d2SMark Murray 144511b41d2SMark Murray fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); 145ca3176e7SBrian Feldman if (fd < 0) { 146ca3176e7SBrian Feldman error("open %s failed: %s.", filename, strerror(errno)); 1471ec0d754SDag-Erling Smørgrav buffer_free(&encrypted); 148511b41d2SMark Murray return 0; 149ca3176e7SBrian Feldman } 150511b41d2SMark Murray if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) != 151511b41d2SMark Murray buffer_len(&encrypted)) { 152ca3176e7SBrian Feldman error("write to key file %s failed: %s", filename, 153511b41d2SMark Murray strerror(errno)); 154511b41d2SMark Murray buffer_free(&encrypted); 155511b41d2SMark Murray close(fd); 156ca3176e7SBrian Feldman unlink(filename); 157511b41d2SMark Murray return 0; 158511b41d2SMark Murray } 159511b41d2SMark Murray close(fd); 160511b41d2SMark Murray buffer_free(&encrypted); 161511b41d2SMark Murray return 1; 162511b41d2SMark Murray } 163511b41d2SMark Murray 164ca3176e7SBrian Feldman /* save SSH v2 key in OpenSSL PEM format */ 165af12a3e7SDag-Erling Smørgrav static int 166ca3176e7SBrian Feldman key_save_private_pem(Key *key, const char *filename, const char *_passphrase, 167ca3176e7SBrian Feldman const char *comment) 168e8aafc91SKris Kennaway { 169e8aafc91SKris Kennaway FILE *fp; 170e8aafc91SKris Kennaway int fd; 171ca3176e7SBrian Feldman int success = 0; 172ca3176e7SBrian Feldman int len = strlen(_passphrase); 173af12a3e7SDag-Erling Smørgrav u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; 174af12a3e7SDag-Erling Smørgrav const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; 175e8aafc91SKris Kennaway 176e8aafc91SKris Kennaway if (len > 0 && len <= 4) { 177ca3176e7SBrian Feldman error("passphrase too short: have %d bytes, need > 4", len); 178e8aafc91SKris Kennaway return 0; 179e8aafc91SKris Kennaway } 180e8aafc91SKris Kennaway fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); 181e8aafc91SKris Kennaway if (fd < 0) { 182ca3176e7SBrian Feldman error("open %s failed: %s.", filename, strerror(errno)); 183e8aafc91SKris Kennaway return 0; 184e8aafc91SKris Kennaway } 185e8aafc91SKris Kennaway fp = fdopen(fd, "w"); 186e8aafc91SKris Kennaway if (fp == NULL ) { 187ca3176e7SBrian Feldman error("fdopen %s failed: %s.", filename, strerror(errno)); 188e8aafc91SKris Kennaway close(fd); 189e8aafc91SKris Kennaway return 0; 190e8aafc91SKris Kennaway } 191ca3176e7SBrian Feldman switch (key->type) { 192ca3176e7SBrian Feldman case KEY_DSA: 193ca3176e7SBrian Feldman success = PEM_write_DSAPrivateKey(fp, key->dsa, 194ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 195ca3176e7SBrian Feldman break; 196ca3176e7SBrian Feldman case KEY_RSA: 197ca3176e7SBrian Feldman success = PEM_write_RSAPrivateKey(fp, key->rsa, 198ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 199ca3176e7SBrian Feldman break; 200e8aafc91SKris Kennaway } 201e8aafc91SKris Kennaway fclose(fp); 202e8aafc91SKris Kennaway return success; 203e8aafc91SKris Kennaway } 204e8aafc91SKris Kennaway 205e8aafc91SKris Kennaway int 206ca3176e7SBrian Feldman key_save_private(Key *key, const char *filename, const char *passphrase, 207e8aafc91SKris Kennaway const char *comment) 208e8aafc91SKris Kennaway { 209e8aafc91SKris Kennaway switch (key->type) { 210ca3176e7SBrian Feldman case KEY_RSA1: 211ca3176e7SBrian Feldman return key_save_private_rsa1(key, filename, passphrase, 212ca3176e7SBrian Feldman comment); 213e8aafc91SKris Kennaway break; 214e8aafc91SKris Kennaway case KEY_DSA: 215ca3176e7SBrian Feldman case KEY_RSA: 216ca3176e7SBrian Feldman return key_save_private_pem(key, filename, passphrase, 217ca3176e7SBrian Feldman comment); 218e8aafc91SKris Kennaway break; 219e8aafc91SKris Kennaway default: 220e8aafc91SKris Kennaway break; 221e8aafc91SKris Kennaway } 222ca3176e7SBrian Feldman error("key_save_private: cannot save key type %d", key->type); 223e8aafc91SKris Kennaway return 0; 224e8aafc91SKris Kennaway } 225e8aafc91SKris Kennaway 226511b41d2SMark Murray /* 227ca3176e7SBrian Feldman * Loads the public part of the ssh v1 key file. Returns NULL if an error was 228ca3176e7SBrian Feldman * encountered (the file does not exist or is not readable), and the key 229511b41d2SMark Murray * otherwise. 230511b41d2SMark Murray */ 231511b41d2SMark Murray 232af12a3e7SDag-Erling Smørgrav static Key * 233ca3176e7SBrian Feldman key_load_public_rsa1(int fd, const char *filename, char **commentp) 234511b41d2SMark Murray { 235511b41d2SMark Murray Buffer buffer; 236ca3176e7SBrian Feldman Key *pub; 237e73e9afaSDag-Erling Smørgrav struct stat st; 238511b41d2SMark Murray char *cp; 239ca3176e7SBrian Feldman int i; 24021e764dfSDag-Erling Smørgrav size_t len; 241511b41d2SMark Murray 242e73e9afaSDag-Erling Smørgrav if (fstat(fd, &st) < 0) { 243e73e9afaSDag-Erling Smørgrav error("fstat for key file %.200s failed: %.100s", 244e73e9afaSDag-Erling Smørgrav filename, strerror(errno)); 245e73e9afaSDag-Erling Smørgrav return NULL; 246e73e9afaSDag-Erling Smørgrav } 247aa49c926SDag-Erling Smørgrav if (st.st_size > 1*1024*1024) { 248aa49c926SDag-Erling Smørgrav error("key file %.200s too large", filename); 249aa49c926SDag-Erling Smørgrav return NULL; 250aa49c926SDag-Erling Smørgrav } 25121e764dfSDag-Erling Smørgrav len = (size_t)st.st_size; /* truncated */ 252511b41d2SMark Murray 253511b41d2SMark Murray buffer_init(&buffer); 254af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&buffer, len); 255511b41d2SMark Murray 256511b41d2SMark Murray if (read(fd, cp, (size_t) len) != (size_t) len) { 257511b41d2SMark Murray debug("Read from key file %.200s failed: %.100s", filename, 258511b41d2SMark Murray strerror(errno)); 259511b41d2SMark Murray buffer_free(&buffer); 260ca3176e7SBrian Feldman return NULL; 261511b41d2SMark Murray } 262511b41d2SMark Murray 263ca3176e7SBrian Feldman /* Check that it is at least big enough to contain the ID string. */ 264ca3176e7SBrian Feldman if (len < sizeof(authfile_id_string)) { 265af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 266511b41d2SMark Murray buffer_free(&buffer); 267ca3176e7SBrian Feldman return NULL; 268511b41d2SMark Murray } 269511b41d2SMark Murray /* 270511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 271511b41d2SMark Murray * from the buffer. 272511b41d2SMark Murray */ 273ca3176e7SBrian Feldman for (i = 0; i < sizeof(authfile_id_string); i++) 274ca3176e7SBrian Feldman if (buffer_get_char(&buffer) != authfile_id_string[i]) { 275af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 276511b41d2SMark Murray buffer_free(&buffer); 277ca3176e7SBrian Feldman return NULL; 278511b41d2SMark Murray } 279511b41d2SMark Murray /* Skip cipher type and reserved data. */ 280511b41d2SMark Murray (void) buffer_get_char(&buffer); /* cipher type */ 281511b41d2SMark Murray (void) buffer_get_int(&buffer); /* reserved */ 282511b41d2SMark Murray 283511b41d2SMark Murray /* Read the public key from the buffer. */ 284a82e551fSDag-Erling Smørgrav (void) buffer_get_int(&buffer); 285ca3176e7SBrian Feldman pub = key_new(KEY_RSA1); 286ca3176e7SBrian Feldman buffer_get_bignum(&buffer, pub->rsa->n); 287ca3176e7SBrian Feldman buffer_get_bignum(&buffer, pub->rsa->e); 288ca3176e7SBrian Feldman if (commentp) 289ca3176e7SBrian Feldman *commentp = buffer_get_string(&buffer, NULL); 290511b41d2SMark Murray /* The encrypted private part is not parsed by this function. */ 291511b41d2SMark Murray 292511b41d2SMark Murray buffer_free(&buffer); 293ca3176e7SBrian Feldman return pub; 294511b41d2SMark Murray } 295511b41d2SMark Murray 296ca3176e7SBrian Feldman /* load public key from private-key file, works only for SSH v1 */ 297ca3176e7SBrian Feldman Key * 298ca3176e7SBrian Feldman key_load_public_type(int type, const char *filename, char **commentp) 299e8aafc91SKris Kennaway { 300ca3176e7SBrian Feldman Key *pub; 301ca3176e7SBrian Feldman int fd; 302ca3176e7SBrian Feldman 303ca3176e7SBrian Feldman if (type == KEY_RSA1) { 304ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 305ca3176e7SBrian Feldman if (fd < 0) 306ca3176e7SBrian Feldman return NULL; 307ca3176e7SBrian Feldman pub = key_load_public_rsa1(fd, filename, commentp); 308ca3176e7SBrian Feldman close(fd); 309ca3176e7SBrian Feldman return pub; 310e8aafc91SKris Kennaway } 311ca3176e7SBrian Feldman return NULL; 312e8aafc91SKris Kennaway } 313e8aafc91SKris Kennaway 314511b41d2SMark Murray /* 315511b41d2SMark Murray * Loads the private key from the file. Returns 0 if an error is encountered 316511b41d2SMark Murray * (file does not exist or is not readable, or passphrase is bad). This 317511b41d2SMark Murray * initializes the private key. 318511b41d2SMark Murray * Assumes we are called under uid of the owner of the file. 319511b41d2SMark Murray */ 320511b41d2SMark Murray 321af12a3e7SDag-Erling Smørgrav static Key * 322ca3176e7SBrian Feldman key_load_private_rsa1(int fd, const char *filename, const char *passphrase, 323ca3176e7SBrian Feldman char **commentp) 324511b41d2SMark Murray { 325e8aafc91SKris Kennaway int i, check1, check2, cipher_type; 32621e764dfSDag-Erling Smørgrav size_t len; 327511b41d2SMark Murray Buffer buffer, decrypted; 328af12a3e7SDag-Erling Smørgrav u_char *cp; 32909958426SBrian Feldman CipherContext ciphercontext; 33009958426SBrian Feldman Cipher *cipher; 331ca3176e7SBrian Feldman Key *prv = NULL; 332e73e9afaSDag-Erling Smørgrav struct stat st; 333511b41d2SMark Murray 334e73e9afaSDag-Erling Smørgrav if (fstat(fd, &st) < 0) { 335e73e9afaSDag-Erling Smørgrav error("fstat for key file %.200s failed: %.100s", 336e73e9afaSDag-Erling Smørgrav filename, strerror(errno)); 337e73e9afaSDag-Erling Smørgrav close(fd); 338e73e9afaSDag-Erling Smørgrav return NULL; 339e73e9afaSDag-Erling Smørgrav } 34021e764dfSDag-Erling Smørgrav if (st.st_size > 1*1024*1024) { 341aa49c926SDag-Erling Smørgrav error("key file %.200s too large", filename); 34221e764dfSDag-Erling Smørgrav close(fd); 34321e764dfSDag-Erling Smørgrav return (NULL); 34421e764dfSDag-Erling Smørgrav } 34521e764dfSDag-Erling Smørgrav len = (size_t)st.st_size; /* truncated */ 346511b41d2SMark Murray 347511b41d2SMark Murray buffer_init(&buffer); 348af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&buffer, len); 349511b41d2SMark Murray 350511b41d2SMark Murray if (read(fd, cp, (size_t) len) != (size_t) len) { 351511b41d2SMark Murray debug("Read from key file %.200s failed: %.100s", filename, 352511b41d2SMark Murray strerror(errno)); 353511b41d2SMark Murray buffer_free(&buffer); 354511b41d2SMark Murray close(fd); 355ca3176e7SBrian Feldman return NULL; 356511b41d2SMark Murray } 357511b41d2SMark Murray 358ca3176e7SBrian Feldman /* Check that it is at least big enough to contain the ID string. */ 359ca3176e7SBrian Feldman if (len < sizeof(authfile_id_string)) { 360af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 361511b41d2SMark Murray buffer_free(&buffer); 362ca3176e7SBrian Feldman close(fd); 363ca3176e7SBrian Feldman return NULL; 364511b41d2SMark Murray } 365511b41d2SMark Murray /* 366511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 367511b41d2SMark Murray * from the buffer. 368511b41d2SMark Murray */ 369ca3176e7SBrian Feldman for (i = 0; i < sizeof(authfile_id_string); i++) 370ca3176e7SBrian Feldman if (buffer_get_char(&buffer) != authfile_id_string[i]) { 371af12a3e7SDag-Erling Smørgrav debug3("Not a RSA1 key file %.200s.", filename); 372511b41d2SMark Murray buffer_free(&buffer); 373ca3176e7SBrian Feldman close(fd); 374ca3176e7SBrian Feldman return NULL; 375511b41d2SMark Murray } 376ca3176e7SBrian Feldman 377511b41d2SMark Murray /* Read cipher type. */ 378511b41d2SMark Murray cipher_type = buffer_get_char(&buffer); 379511b41d2SMark Murray (void) buffer_get_int(&buffer); /* Reserved data. */ 380511b41d2SMark Murray 381511b41d2SMark Murray /* Read the public key from the buffer. */ 382a82e551fSDag-Erling Smørgrav (void) buffer_get_int(&buffer); 383ca3176e7SBrian Feldman prv = key_new_private(KEY_RSA1); 384ca3176e7SBrian Feldman 385ca3176e7SBrian Feldman buffer_get_bignum(&buffer, prv->rsa->n); 386ca3176e7SBrian Feldman buffer_get_bignum(&buffer, prv->rsa->e); 387ca3176e7SBrian Feldman if (commentp) 388ca3176e7SBrian Feldman *commentp = buffer_get_string(&buffer, NULL); 389511b41d2SMark Murray else 390511b41d2SMark Murray xfree(buffer_get_string(&buffer, NULL)); 391511b41d2SMark Murray 392511b41d2SMark Murray /* Check that it is a supported cipher. */ 39309958426SBrian Feldman cipher = cipher_by_number(cipher_type); 39409958426SBrian Feldman if (cipher == NULL) { 39509958426SBrian Feldman debug("Unsupported cipher %d used in key file %.200s.", 39609958426SBrian Feldman cipher_type, filename); 397511b41d2SMark Murray buffer_free(&buffer); 398511b41d2SMark Murray goto fail; 399511b41d2SMark Murray } 400511b41d2SMark Murray /* Initialize space for decrypted data. */ 401511b41d2SMark Murray buffer_init(&decrypted); 402af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&decrypted, buffer_len(&buffer)); 403511b41d2SMark Murray 404511b41d2SMark Murray /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 405af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 406af12a3e7SDag-Erling Smørgrav CIPHER_DECRYPT); 407af12a3e7SDag-Erling Smørgrav cipher_crypt(&ciphercontext, cp, 408af12a3e7SDag-Erling Smørgrav buffer_ptr(&buffer), buffer_len(&buffer)); 409af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 41009958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 411511b41d2SMark Murray buffer_free(&buffer); 412511b41d2SMark Murray 413511b41d2SMark Murray check1 = buffer_get_char(&decrypted); 414511b41d2SMark Murray check2 = buffer_get_char(&decrypted); 415511b41d2SMark Murray if (check1 != buffer_get_char(&decrypted) || 416511b41d2SMark Murray check2 != buffer_get_char(&decrypted)) { 417511b41d2SMark Murray if (strcmp(passphrase, "") != 0) 418ca3176e7SBrian Feldman debug("Bad passphrase supplied for key file %.200s.", 419ca3176e7SBrian Feldman filename); 420511b41d2SMark Murray /* Bad passphrase. */ 421511b41d2SMark Murray buffer_free(&decrypted); 422ca3176e7SBrian Feldman goto fail; 423511b41d2SMark Murray } 424511b41d2SMark Murray /* Read the rest of the private key. */ 425ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->d); 426ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ 427ca3176e7SBrian Feldman /* in SSL and SSH v1 p and q are exchanged */ 428ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ 429ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ 430511b41d2SMark Murray 431ca3176e7SBrian Feldman /* calculate p-1 and q-1 */ 432af12a3e7SDag-Erling Smørgrav rsa_generate_additional_parameters(prv->rsa); 433511b41d2SMark Murray 434511b41d2SMark Murray buffer_free(&decrypted); 435e73e9afaSDag-Erling Smørgrav 436e73e9afaSDag-Erling Smørgrav /* enable blinding */ 437e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 438e73e9afaSDag-Erling Smørgrav error("key_load_private_rsa1: RSA_blinding_on failed"); 439e73e9afaSDag-Erling Smørgrav goto fail; 440e73e9afaSDag-Erling Smørgrav } 441ca3176e7SBrian Feldman close(fd); 442ca3176e7SBrian Feldman return prv; 443511b41d2SMark Murray 444ca3176e7SBrian Feldman fail: 445ca3176e7SBrian Feldman if (commentp) 446ca3176e7SBrian Feldman xfree(*commentp); 447ca3176e7SBrian Feldman close(fd); 448ca3176e7SBrian Feldman key_free(prv); 449ca3176e7SBrian Feldman return NULL; 450511b41d2SMark Murray } 451e8aafc91SKris Kennaway 45280628bacSDag-Erling Smørgrav Key * 453ca3176e7SBrian Feldman key_load_private_pem(int fd, int type, const char *passphrase, 454ca3176e7SBrian Feldman char **commentp) 455e8aafc91SKris Kennaway { 456e8aafc91SKris Kennaway FILE *fp; 457ca3176e7SBrian Feldman EVP_PKEY *pk = NULL; 458ca3176e7SBrian Feldman Key *prv = NULL; 459ca3176e7SBrian Feldman char *name = "<no key>"; 460e8aafc91SKris Kennaway 461e8aafc91SKris Kennaway fp = fdopen(fd, "r"); 462e8aafc91SKris Kennaway if (fp == NULL) { 463ca3176e7SBrian Feldman error("fdopen failed: %s", strerror(errno)); 464ca3176e7SBrian Feldman close(fd); 465ca3176e7SBrian Feldman return NULL; 466e8aafc91SKris Kennaway } 467ca3176e7SBrian Feldman pk = PEM_read_PrivateKey(fp, NULL, NULL, (char *)passphrase); 468ca3176e7SBrian Feldman if (pk == NULL) { 469ca3176e7SBrian Feldman debug("PEM_read_PrivateKey failed"); 470ca3176e7SBrian Feldman (void)ERR_get_error(); 471ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_RSA && 472ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_RSA)) { 473ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 474ca3176e7SBrian Feldman prv->rsa = EVP_PKEY_get1_RSA(pk); 475ca3176e7SBrian Feldman prv->type = KEY_RSA; 476ca3176e7SBrian Feldman name = "rsa w/o comment"; 477ca3176e7SBrian Feldman #ifdef DEBUG_PK 478ca3176e7SBrian Feldman RSA_print_fp(stderr, prv->rsa, 8); 479e8aafc91SKris Kennaway #endif 480e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 481e73e9afaSDag-Erling Smørgrav error("key_load_private_pem: RSA_blinding_on failed"); 482e73e9afaSDag-Erling Smørgrav key_free(prv); 483e73e9afaSDag-Erling Smørgrav prv = NULL; 484e73e9afaSDag-Erling Smørgrav } 485ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_DSA && 486ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_DSA)) { 487ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 488ca3176e7SBrian Feldman prv->dsa = EVP_PKEY_get1_DSA(pk); 489ca3176e7SBrian Feldman prv->type = KEY_DSA; 490ca3176e7SBrian Feldman name = "dsa w/o comment"; 491ca3176e7SBrian Feldman #ifdef DEBUG_PK 492ca3176e7SBrian Feldman DSA_print_fp(stderr, prv->dsa, 8); 493ca3176e7SBrian Feldman #endif 494ca3176e7SBrian Feldman } else { 495ca3176e7SBrian Feldman error("PEM_read_PrivateKey: mismatch or " 496ca3176e7SBrian Feldman "unknown EVP_PKEY save_type %d", pk->save_type); 497ca3176e7SBrian Feldman } 498ca3176e7SBrian Feldman fclose(fp); 499ca3176e7SBrian Feldman if (pk != NULL) 500ca3176e7SBrian Feldman EVP_PKEY_free(pk); 501ca3176e7SBrian Feldman if (prv != NULL && commentp) 502ca3176e7SBrian Feldman *commentp = xstrdup(name); 503ca3176e7SBrian Feldman debug("read PEM private key done: type %s", 504ca3176e7SBrian Feldman prv ? key_type(prv) : "<unknown>"); 505ca3176e7SBrian Feldman return prv; 506e8aafc91SKris Kennaway } 507e8aafc91SKris Kennaway 508af12a3e7SDag-Erling Smørgrav static int 509ca3176e7SBrian Feldman key_perm_ok(int fd, const char *filename) 510e8aafc91SKris Kennaway { 511e8aafc91SKris Kennaway struct stat st; 512e8aafc91SKris Kennaway 513af12a3e7SDag-Erling Smørgrav if (fstat(fd, &st) < 0) 514af12a3e7SDag-Erling Smørgrav return 0; 515af12a3e7SDag-Erling Smørgrav /* 516af12a3e7SDag-Erling Smørgrav * if a key owned by the user is accessed, then we check the 517af12a3e7SDag-Erling Smørgrav * permissions of the file. if the key owned by a different user, 518af12a3e7SDag-Erling Smørgrav * then we don't care. 519af12a3e7SDag-Erling Smørgrav */ 520989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 521989dd127SDag-Erling Smørgrav if (check_ntsec(filename)) 522989dd127SDag-Erling Smørgrav #endif 523af12a3e7SDag-Erling Smørgrav if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { 524e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 525e8aafc91SKris Kennaway error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 526e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 527af12a3e7SDag-Erling Smørgrav error("Permissions 0%3.3o for '%s' are too open.", 528cf2b5f3bSDag-Erling Smørgrav (u_int)st.st_mode & 0777, filename); 529e8aafc91SKris Kennaway error("It is recommended that your private key files are NOT accessible by others."); 530ca3176e7SBrian Feldman error("This private key will be ignored."); 531e8aafc91SKris Kennaway return 0; 532e8aafc91SKris Kennaway } 533ca3176e7SBrian Feldman return 1; 534e8aafc91SKris Kennaway } 535ca3176e7SBrian Feldman 536ca3176e7SBrian Feldman Key * 537ca3176e7SBrian Feldman key_load_private_type(int type, const char *filename, const char *passphrase, 538ca3176e7SBrian Feldman char **commentp) 539ca3176e7SBrian Feldman { 540ca3176e7SBrian Feldman int fd; 541ca3176e7SBrian Feldman 542ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 543ca3176e7SBrian Feldman if (fd < 0) 544ca3176e7SBrian Feldman return NULL; 545ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 546ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 547ca3176e7SBrian Feldman close(fd); 548ca3176e7SBrian Feldman return NULL; 549e8aafc91SKris Kennaway } 550ca3176e7SBrian Feldman switch (type) { 551ca3176e7SBrian Feldman case KEY_RSA1: 552ca3176e7SBrian Feldman return key_load_private_rsa1(fd, filename, passphrase, 553ca3176e7SBrian Feldman commentp); 554ca3176e7SBrian Feldman /* closes fd */ 555e8aafc91SKris Kennaway break; 556e8aafc91SKris Kennaway case KEY_DSA: 557ca3176e7SBrian Feldman case KEY_RSA: 558ca3176e7SBrian Feldman case KEY_UNSPEC: 559ca3176e7SBrian Feldman return key_load_private_pem(fd, type, passphrase, commentp); 560ca3176e7SBrian Feldman /* closes fd */ 561ca3176e7SBrian Feldman break; 562e8aafc91SKris Kennaway default: 563ca3176e7SBrian Feldman close(fd); 564e8aafc91SKris Kennaway break; 565e8aafc91SKris Kennaway } 566ca3176e7SBrian Feldman return NULL; 567ca3176e7SBrian Feldman } 568ca3176e7SBrian Feldman 569ca3176e7SBrian Feldman Key * 570ca3176e7SBrian Feldman key_load_private(const char *filename, const char *passphrase, 571ca3176e7SBrian Feldman char **commentp) 572ca3176e7SBrian Feldman { 573af12a3e7SDag-Erling Smørgrav Key *pub, *prv; 574ca3176e7SBrian Feldman int fd; 575ca3176e7SBrian Feldman 576ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 577ca3176e7SBrian Feldman if (fd < 0) 578ca3176e7SBrian Feldman return NULL; 579ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 580ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 581e8aafc91SKris Kennaway close(fd); 582ca3176e7SBrian Feldman return NULL; 583ca3176e7SBrian Feldman } 584ca3176e7SBrian Feldman pub = key_load_public_rsa1(fd, filename, commentp); 585ca3176e7SBrian Feldman lseek(fd, (off_t) 0, SEEK_SET); /* rewind */ 586ca3176e7SBrian Feldman if (pub == NULL) { 587ca3176e7SBrian Feldman /* closes fd */ 588af12a3e7SDag-Erling Smørgrav prv = key_load_private_pem(fd, KEY_UNSPEC, passphrase, NULL); 589af12a3e7SDag-Erling Smørgrav /* use the filename as a comment for PEM */ 590af12a3e7SDag-Erling Smørgrav if (commentp && prv) 591af12a3e7SDag-Erling Smørgrav *commentp = xstrdup(filename); 592ca3176e7SBrian Feldman } else { 593ca3176e7SBrian Feldman /* it's a SSH v1 key if the public key part is readable */ 594ca3176e7SBrian Feldman key_free(pub); 595ca3176e7SBrian Feldman /* closes fd */ 596af12a3e7SDag-Erling Smørgrav prv = key_load_private_rsa1(fd, filename, passphrase, NULL); 597ca3176e7SBrian Feldman } 598af12a3e7SDag-Erling Smørgrav return prv; 599e8aafc91SKris Kennaway } 600c2d3a559SKris Kennaway 601af12a3e7SDag-Erling Smørgrav static int 602ca3176e7SBrian Feldman key_try_load_public(Key *k, const char *filename, char **commentp) 603c2d3a559SKris Kennaway { 604c2d3a559SKris Kennaway FILE *f; 605aa49c926SDag-Erling Smørgrav char line[SSH_MAX_PUBKEY_BYTES]; 606c2d3a559SKris Kennaway char *cp; 607aa49c926SDag-Erling Smørgrav u_long linenum = 0; 608c2d3a559SKris Kennaway 609c2d3a559SKris Kennaway f = fopen(filename, "r"); 610c2d3a559SKris Kennaway if (f != NULL) { 611aa49c926SDag-Erling Smørgrav while (read_keyfile_line(f, filename, line, sizeof(line), 612aa49c926SDag-Erling Smørgrav &linenum) != -1) { 613c2d3a559SKris Kennaway cp = line; 614c2d3a559SKris Kennaway switch (*cp) { 615c2d3a559SKris Kennaway case '#': 616c2d3a559SKris Kennaway case '\n': 617c2d3a559SKris Kennaway case '\0': 618c2d3a559SKris Kennaway continue; 619c2d3a559SKris Kennaway } 620c2d3a559SKris Kennaway /* Skip leading whitespace. */ 621c2d3a559SKris Kennaway for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 622c2d3a559SKris Kennaway ; 623c2d3a559SKris Kennaway if (*cp) { 624ca3176e7SBrian Feldman if (key_read(k, &cp) == 1) { 625c2d3a559SKris Kennaway if (commentp) 626c2d3a559SKris Kennaway *commentp=xstrdup(filename); 627c2d3a559SKris Kennaway fclose(f); 628c2d3a559SKris Kennaway return 1; 629c2d3a559SKris Kennaway } 630c2d3a559SKris Kennaway } 631c2d3a559SKris Kennaway } 632c2d3a559SKris Kennaway fclose(f); 633c2d3a559SKris Kennaway } 634c2d3a559SKris Kennaway return 0; 635c2d3a559SKris Kennaway } 636c2d3a559SKris Kennaway 637ca3176e7SBrian Feldman /* load public key from ssh v1 private or any pubkey file */ 638ca3176e7SBrian Feldman Key * 639ca3176e7SBrian Feldman key_load_public(const char *filename, char **commentp) 640c2d3a559SKris Kennaway { 641ca3176e7SBrian Feldman Key *pub; 642ca3176e7SBrian Feldman char file[MAXPATHLEN]; 643c2d3a559SKris Kennaway 644cf2b5f3bSDag-Erling Smørgrav /* try rsa1 private key */ 645ca3176e7SBrian Feldman pub = key_load_public_type(KEY_RSA1, filename, commentp); 646ca3176e7SBrian Feldman if (pub != NULL) 647ca3176e7SBrian Feldman return pub; 648cf2b5f3bSDag-Erling Smørgrav 649cf2b5f3bSDag-Erling Smørgrav /* try rsa1 public key */ 650cf2b5f3bSDag-Erling Smørgrav pub = key_new(KEY_RSA1); 651cf2b5f3bSDag-Erling Smørgrav if (key_try_load_public(pub, filename, commentp) == 1) 652cf2b5f3bSDag-Erling Smørgrav return pub; 653cf2b5f3bSDag-Erling Smørgrav key_free(pub); 654cf2b5f3bSDag-Erling Smørgrav 655cf2b5f3bSDag-Erling Smørgrav /* try ssh2 public key */ 656ca3176e7SBrian Feldman pub = key_new(KEY_UNSPEC); 657ca3176e7SBrian Feldman if (key_try_load_public(pub, filename, commentp) == 1) 658ca3176e7SBrian Feldman return pub; 659ca3176e7SBrian Feldman if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && 660ca3176e7SBrian Feldman (strlcat(file, ".pub", sizeof file) < sizeof(file)) && 661ca3176e7SBrian Feldman (key_try_load_public(pub, file, commentp) == 1)) 662ca3176e7SBrian Feldman return pub; 663ca3176e7SBrian Feldman key_free(pub); 664ca3176e7SBrian Feldman return NULL; 665c2d3a559SKris Kennaway } 666