1511b41d2SMark Murray /* 2511b41d2SMark Murray * 3511b41d2SMark Murray * authfile.c 4511b41d2SMark Murray * 5511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 6511b41d2SMark Murray * 7511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 8511b41d2SMark Murray * All rights reserved 9511b41d2SMark Murray * 10511b41d2SMark Murray * Created: Mon Mar 27 03:52:05 1995 ylo 11511b41d2SMark Murray * 12511b41d2SMark Murray * This file contains functions for reading and writing identity files, and 13511b41d2SMark Murray * for reading the passphrase from the user. 14511b41d2SMark Murray * 1518a71195SBrian Feldman * $FreeBSD$ 16511b41d2SMark Murray */ 17511b41d2SMark Murray 18511b41d2SMark Murray #include "includes.h" 19e8aafc91SKris Kennaway RCSID("$Id: authfile.c,v 1.16 2000/04/26 21:28:32 markus Exp $"); 20511b41d2SMark Murray 2118a71195SBrian Feldman #include <openssl/bn.h> 22e8aafc91SKris Kennaway #include <openssl/dsa.h> 23e8aafc91SKris Kennaway #include <openssl/rsa.h> 24e8aafc91SKris Kennaway #include <openssl/pem.h> 25e8aafc91SKris Kennaway #include <openssl/evp.h> 26e8aafc91SKris Kennaway 27511b41d2SMark Murray #include "xmalloc.h" 28511b41d2SMark Murray #include "buffer.h" 29511b41d2SMark Murray #include "bufaux.h" 30511b41d2SMark Murray #include "cipher.h" 31511b41d2SMark Murray #include "ssh.h" 32e8aafc91SKris Kennaway #include "key.h" 33511b41d2SMark Murray 34511b41d2SMark Murray /* Version identification string for identity files. */ 35511b41d2SMark Murray #define AUTHFILE_ID_STRING "SSH PRIVATE KEY FILE FORMAT 1.1\n" 36511b41d2SMark Murray 37511b41d2SMark Murray /* 38511b41d2SMark Murray * Saves the authentication (private) key in a file, encrypting it with 39511b41d2SMark Murray * passphrase. The identification of the file (lowest 64 bits of n) will 40511b41d2SMark Murray * precede the key to provide identification of the key without needing a 41511b41d2SMark Murray * passphrase. 42511b41d2SMark Murray */ 43511b41d2SMark Murray 44511b41d2SMark Murray int 45e8aafc91SKris Kennaway save_private_key_rsa(const char *filename, const char *passphrase, 46511b41d2SMark Murray RSA *key, const char *comment) 47511b41d2SMark Murray { 48511b41d2SMark Murray Buffer buffer, encrypted; 49511b41d2SMark Murray char buf[100], *cp; 50511b41d2SMark Murray int fd, i; 51511b41d2SMark Murray CipherContext cipher; 52511b41d2SMark Murray int cipher_type; 53511b41d2SMark Murray u_int32_t rand; 54511b41d2SMark Murray 55511b41d2SMark Murray /* 56511b41d2SMark Murray * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting 57511b41d2SMark Murray * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. 58511b41d2SMark Murray */ 59511b41d2SMark Murray if (strcmp(passphrase, "") == 0) 60511b41d2SMark Murray cipher_type = SSH_CIPHER_NONE; 61511b41d2SMark Murray else 62511b41d2SMark Murray cipher_type = SSH_AUTHFILE_CIPHER; 63511b41d2SMark Murray 64511b41d2SMark Murray /* This buffer is used to built the secret part of the private key. */ 65511b41d2SMark Murray buffer_init(&buffer); 66511b41d2SMark Murray 67511b41d2SMark Murray /* Put checkbytes for checking passphrase validity. */ 68511b41d2SMark Murray rand = arc4random(); 69511b41d2SMark Murray buf[0] = rand & 0xff; 70511b41d2SMark Murray buf[1] = (rand >> 8) & 0xff; 71511b41d2SMark Murray buf[2] = buf[0]; 72511b41d2SMark Murray buf[3] = buf[1]; 73511b41d2SMark Murray buffer_append(&buffer, buf, 4); 74511b41d2SMark Murray 75511b41d2SMark Murray /* 76511b41d2SMark Murray * Store the private key (n and e will not be stored because they 77511b41d2SMark Murray * will be stored in plain text, and storing them also in encrypted 78511b41d2SMark Murray * format would just give known plaintext). 79511b41d2SMark Murray */ 80511b41d2SMark Murray buffer_put_bignum(&buffer, key->d); 81511b41d2SMark Murray buffer_put_bignum(&buffer, key->iqmp); 82511b41d2SMark Murray buffer_put_bignum(&buffer, key->q); /* reverse from SSL p */ 83511b41d2SMark Murray buffer_put_bignum(&buffer, key->p); /* reverse from SSL q */ 84511b41d2SMark Murray 85511b41d2SMark Murray /* Pad the part to be encrypted until its size is a multiple of 8. */ 86511b41d2SMark Murray while (buffer_len(&buffer) % 8 != 0) 87511b41d2SMark Murray buffer_put_char(&buffer, 0); 88511b41d2SMark Murray 89511b41d2SMark Murray /* This buffer will be used to contain the data in the file. */ 90511b41d2SMark Murray buffer_init(&encrypted); 91511b41d2SMark Murray 92511b41d2SMark Murray /* First store keyfile id string. */ 93511b41d2SMark Murray cp = AUTHFILE_ID_STRING; 94511b41d2SMark Murray for (i = 0; cp[i]; i++) 95511b41d2SMark Murray buffer_put_char(&encrypted, cp[i]); 96511b41d2SMark Murray buffer_put_char(&encrypted, 0); 97511b41d2SMark Murray 98511b41d2SMark Murray /* Store cipher type. */ 99511b41d2SMark Murray buffer_put_char(&encrypted, cipher_type); 100511b41d2SMark Murray buffer_put_int(&encrypted, 0); /* For future extension */ 101511b41d2SMark Murray 102511b41d2SMark Murray /* Store public key. This will be in plain text. */ 103511b41d2SMark Murray buffer_put_int(&encrypted, BN_num_bits(key->n)); 104511b41d2SMark Murray buffer_put_bignum(&encrypted, key->n); 105511b41d2SMark Murray buffer_put_bignum(&encrypted, key->e); 106511b41d2SMark Murray buffer_put_string(&encrypted, comment, strlen(comment)); 107511b41d2SMark Murray 108511b41d2SMark Murray /* Allocate space for the private part of the key in the buffer. */ 109511b41d2SMark Murray buffer_append_space(&encrypted, &cp, buffer_len(&buffer)); 110511b41d2SMark Murray 111e8aafc91SKris Kennaway cipher_set_key_string(&cipher, cipher_type, passphrase); 112511b41d2SMark Murray cipher_encrypt(&cipher, (unsigned char *) cp, 113511b41d2SMark Murray (unsigned char *) buffer_ptr(&buffer), 114511b41d2SMark Murray buffer_len(&buffer)); 115511b41d2SMark Murray memset(&cipher, 0, sizeof(cipher)); 116511b41d2SMark Murray 117511b41d2SMark Murray /* Destroy temporary data. */ 118511b41d2SMark Murray memset(buf, 0, sizeof(buf)); 119511b41d2SMark Murray buffer_free(&buffer); 120511b41d2SMark Murray 121511b41d2SMark Murray fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); 122511b41d2SMark Murray if (fd < 0) 123511b41d2SMark Murray return 0; 124511b41d2SMark Murray if (write(fd, buffer_ptr(&encrypted), buffer_len(&encrypted)) != 125511b41d2SMark Murray buffer_len(&encrypted)) { 126511b41d2SMark Murray debug("Write to key file %.200s failed: %.100s", filename, 127511b41d2SMark Murray strerror(errno)); 128511b41d2SMark Murray buffer_free(&encrypted); 129511b41d2SMark Murray close(fd); 130511b41d2SMark Murray remove(filename); 131511b41d2SMark Murray return 0; 132511b41d2SMark Murray } 133511b41d2SMark Murray close(fd); 134511b41d2SMark Murray buffer_free(&encrypted); 135511b41d2SMark Murray return 1; 136511b41d2SMark Murray } 137511b41d2SMark Murray 138e8aafc91SKris Kennaway /* save DSA key in OpenSSL PEM format */ 139e8aafc91SKris Kennaway 140e8aafc91SKris Kennaway int 141e8aafc91SKris Kennaway save_private_key_dsa(const char *filename, const char *passphrase, 142e8aafc91SKris Kennaway DSA *dsa, const char *comment) 143e8aafc91SKris Kennaway { 144e8aafc91SKris Kennaway FILE *fp; 145e8aafc91SKris Kennaway int fd; 146e8aafc91SKris Kennaway int success = 1; 147e8aafc91SKris Kennaway int len = strlen(passphrase); 148e8aafc91SKris Kennaway 149e8aafc91SKris Kennaway if (len > 0 && len <= 4) { 150e8aafc91SKris Kennaway error("passphrase too short: %d bytes", len); 151e8aafc91SKris Kennaway errno = 0; 152e8aafc91SKris Kennaway return 0; 153e8aafc91SKris Kennaway } 154e8aafc91SKris Kennaway fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600); 155e8aafc91SKris Kennaway if (fd < 0) { 156e8aafc91SKris Kennaway debug("open %s failed", filename); 157e8aafc91SKris Kennaway return 0; 158e8aafc91SKris Kennaway } 159e8aafc91SKris Kennaway fp = fdopen(fd, "w"); 160e8aafc91SKris Kennaway if (fp == NULL ) { 161e8aafc91SKris Kennaway debug("fdopen %s failed", filename); 162e8aafc91SKris Kennaway close(fd); 163e8aafc91SKris Kennaway return 0; 164e8aafc91SKris Kennaway } 165e8aafc91SKris Kennaway if (len > 0) { 166e8aafc91SKris Kennaway if (!PEM_write_DSAPrivateKey(fp, dsa, EVP_des_ede3_cbc(), 167e8aafc91SKris Kennaway (char *)passphrase, strlen(passphrase), NULL, NULL)) 168e8aafc91SKris Kennaway success = 0; 169e8aafc91SKris Kennaway } else { 170e8aafc91SKris Kennaway if (!PEM_write_DSAPrivateKey(fp, dsa, NULL, 171e8aafc91SKris Kennaway NULL, 0, NULL, NULL)) 172e8aafc91SKris Kennaway success = 0; 173e8aafc91SKris Kennaway } 174e8aafc91SKris Kennaway fclose(fp); 175e8aafc91SKris Kennaway return success; 176e8aafc91SKris Kennaway } 177e8aafc91SKris Kennaway 178e8aafc91SKris Kennaway int 179e8aafc91SKris Kennaway save_private_key(const char *filename, const char *passphrase, Key *key, 180e8aafc91SKris Kennaway const char *comment) 181e8aafc91SKris Kennaway { 182e8aafc91SKris Kennaway switch (key->type) { 183e8aafc91SKris Kennaway case KEY_RSA: 184e8aafc91SKris Kennaway return save_private_key_rsa(filename, passphrase, key->rsa, comment); 185e8aafc91SKris Kennaway break; 186e8aafc91SKris Kennaway case KEY_DSA: 187e8aafc91SKris Kennaway return save_private_key_dsa(filename, passphrase, key->dsa, comment); 188e8aafc91SKris Kennaway break; 189e8aafc91SKris Kennaway default: 190e8aafc91SKris Kennaway break; 191e8aafc91SKris Kennaway } 192e8aafc91SKris Kennaway return 0; 193e8aafc91SKris Kennaway } 194e8aafc91SKris Kennaway 195511b41d2SMark Murray /* 196511b41d2SMark Murray * Loads the public part of the key file. Returns 0 if an error was 197511b41d2SMark Murray * encountered (the file does not exist or is not readable), and non-zero 198511b41d2SMark Murray * otherwise. 199511b41d2SMark Murray */ 200511b41d2SMark Murray 201511b41d2SMark Murray int 202e8aafc91SKris Kennaway load_public_key_rsa(const char *filename, RSA * pub, char **comment_return) 203511b41d2SMark Murray { 204511b41d2SMark Murray int fd, i; 205511b41d2SMark Murray off_t len; 206511b41d2SMark Murray Buffer buffer; 207511b41d2SMark Murray char *cp; 208511b41d2SMark Murray 209511b41d2SMark Murray fd = open(filename, O_RDONLY); 210511b41d2SMark Murray if (fd < 0) 211511b41d2SMark Murray return 0; 212511b41d2SMark Murray len = lseek(fd, (off_t) 0, SEEK_END); 213511b41d2SMark Murray lseek(fd, (off_t) 0, SEEK_SET); 214511b41d2SMark Murray 215511b41d2SMark Murray buffer_init(&buffer); 216511b41d2SMark Murray buffer_append_space(&buffer, &cp, len); 217511b41d2SMark Murray 218511b41d2SMark Murray if (read(fd, cp, (size_t) len) != (size_t) len) { 219511b41d2SMark Murray debug("Read from key file %.200s failed: %.100s", filename, 220511b41d2SMark Murray strerror(errno)); 221511b41d2SMark Murray buffer_free(&buffer); 222511b41d2SMark Murray close(fd); 223511b41d2SMark Murray return 0; 224511b41d2SMark Murray } 225511b41d2SMark Murray close(fd); 226511b41d2SMark Murray 227511b41d2SMark Murray /* Check that it is at least big enought to contain the ID string. */ 228511b41d2SMark Murray if (len < strlen(AUTHFILE_ID_STRING) + 1) { 229511b41d2SMark Murray debug("Bad key file %.200s.", filename); 230511b41d2SMark Murray buffer_free(&buffer); 231511b41d2SMark Murray return 0; 232511b41d2SMark Murray } 233511b41d2SMark Murray /* 234511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 235511b41d2SMark Murray * from the buffer. 236511b41d2SMark Murray */ 237511b41d2SMark Murray for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) 238511b41d2SMark Murray if (buffer_get_char(&buffer) != (u_char) AUTHFILE_ID_STRING[i]) { 239511b41d2SMark Murray debug("Bad key file %.200s.", filename); 240511b41d2SMark Murray buffer_free(&buffer); 241511b41d2SMark Murray return 0; 242511b41d2SMark Murray } 243511b41d2SMark Murray /* Skip cipher type and reserved data. */ 244511b41d2SMark Murray (void) buffer_get_char(&buffer); /* cipher type */ 245511b41d2SMark Murray (void) buffer_get_int(&buffer); /* reserved */ 246511b41d2SMark Murray 247511b41d2SMark Murray /* Read the public key from the buffer. */ 248511b41d2SMark Murray buffer_get_int(&buffer); 249e8aafc91SKris Kennaway /* XXX alloc */ 250e8aafc91SKris Kennaway if (pub->n == NULL) 251511b41d2SMark Murray pub->n = BN_new(); 252511b41d2SMark Murray buffer_get_bignum(&buffer, pub->n); 253e8aafc91SKris Kennaway /* XXX alloc */ 254e8aafc91SKris Kennaway if (pub->e == NULL) 255511b41d2SMark Murray pub->e = BN_new(); 256511b41d2SMark Murray buffer_get_bignum(&buffer, pub->e); 257511b41d2SMark Murray if (comment_return) 258511b41d2SMark Murray *comment_return = buffer_get_string(&buffer, NULL); 259511b41d2SMark Murray /* The encrypted private part is not parsed by this function. */ 260511b41d2SMark Murray 261511b41d2SMark Murray buffer_free(&buffer); 262511b41d2SMark Murray 263511b41d2SMark Murray return 1; 264511b41d2SMark Murray } 265511b41d2SMark Murray 266e8aafc91SKris Kennaway int 267e8aafc91SKris Kennaway load_public_key(const char *filename, Key * key, char **comment_return) 268e8aafc91SKris Kennaway { 269e8aafc91SKris Kennaway switch (key->type) { 270e8aafc91SKris Kennaway case KEY_RSA: 271e8aafc91SKris Kennaway return load_public_key_rsa(filename, key->rsa, comment_return); 272e8aafc91SKris Kennaway break; 273e8aafc91SKris Kennaway case KEY_DSA: 274e8aafc91SKris Kennaway default: 275e8aafc91SKris Kennaway break; 276e8aafc91SKris Kennaway } 277e8aafc91SKris Kennaway return 0; 278e8aafc91SKris Kennaway } 279e8aafc91SKris Kennaway 280511b41d2SMark Murray /* 281511b41d2SMark Murray * Loads the private key from the file. Returns 0 if an error is encountered 282511b41d2SMark Murray * (file does not exist or is not readable, or passphrase is bad). This 283511b41d2SMark Murray * initializes the private key. 284511b41d2SMark Murray * Assumes we are called under uid of the owner of the file. 285511b41d2SMark Murray */ 286511b41d2SMark Murray 287511b41d2SMark Murray int 288e8aafc91SKris Kennaway load_private_key_rsa(int fd, const char *filename, 289e8aafc91SKris Kennaway const char *passphrase, RSA * prv, char **comment_return) 290511b41d2SMark Murray { 291e8aafc91SKris Kennaway int i, check1, check2, cipher_type; 292511b41d2SMark Murray off_t len; 293511b41d2SMark Murray Buffer buffer, decrypted; 294511b41d2SMark Murray char *cp; 295511b41d2SMark Murray CipherContext cipher; 296511b41d2SMark Murray BN_CTX *ctx; 297511b41d2SMark Murray BIGNUM *aux; 298511b41d2SMark Murray 299511b41d2SMark Murray len = lseek(fd, (off_t) 0, SEEK_END); 300511b41d2SMark Murray lseek(fd, (off_t) 0, SEEK_SET); 301511b41d2SMark Murray 302511b41d2SMark Murray buffer_init(&buffer); 303511b41d2SMark Murray buffer_append_space(&buffer, &cp, len); 304511b41d2SMark Murray 305511b41d2SMark Murray if (read(fd, cp, (size_t) len) != (size_t) len) { 306511b41d2SMark Murray debug("Read from key file %.200s failed: %.100s", filename, 307511b41d2SMark Murray strerror(errno)); 308511b41d2SMark Murray buffer_free(&buffer); 309511b41d2SMark Murray close(fd); 310511b41d2SMark Murray return 0; 311511b41d2SMark Murray } 312511b41d2SMark Murray close(fd); 313511b41d2SMark Murray 314511b41d2SMark Murray /* Check that it is at least big enought to contain the ID string. */ 315511b41d2SMark Murray if (len < strlen(AUTHFILE_ID_STRING) + 1) { 316511b41d2SMark Murray debug("Bad key file %.200s.", filename); 317511b41d2SMark Murray buffer_free(&buffer); 318511b41d2SMark Murray return 0; 319511b41d2SMark Murray } 320511b41d2SMark Murray /* 321511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 322511b41d2SMark Murray * from the buffer. 323511b41d2SMark Murray */ 324511b41d2SMark Murray for (i = 0; i < (unsigned int) strlen(AUTHFILE_ID_STRING) + 1; i++) 325511b41d2SMark Murray if (buffer_get_char(&buffer) != (unsigned char) AUTHFILE_ID_STRING[i]) { 326511b41d2SMark Murray debug("Bad key file %.200s.", filename); 327511b41d2SMark Murray buffer_free(&buffer); 328511b41d2SMark Murray return 0; 329511b41d2SMark Murray } 330511b41d2SMark Murray /* Read cipher type. */ 331511b41d2SMark Murray cipher_type = buffer_get_char(&buffer); 332511b41d2SMark Murray (void) buffer_get_int(&buffer); /* Reserved data. */ 333511b41d2SMark Murray 334511b41d2SMark Murray /* Read the public key from the buffer. */ 335511b41d2SMark Murray buffer_get_int(&buffer); 336511b41d2SMark Murray prv->n = BN_new(); 337511b41d2SMark Murray buffer_get_bignum(&buffer, prv->n); 338511b41d2SMark Murray prv->e = BN_new(); 339511b41d2SMark Murray buffer_get_bignum(&buffer, prv->e); 340511b41d2SMark Murray if (comment_return) 341511b41d2SMark Murray *comment_return = buffer_get_string(&buffer, NULL); 342511b41d2SMark Murray else 343511b41d2SMark Murray xfree(buffer_get_string(&buffer, NULL)); 344511b41d2SMark Murray 345511b41d2SMark Murray /* Check that it is a supported cipher. */ 346e8aafc91SKris Kennaway if (((cipher_mask1() | SSH_CIPHER_NONE | SSH_AUTHFILE_CIPHER) & 347511b41d2SMark Murray (1 << cipher_type)) == 0) { 348511b41d2SMark Murray debug("Unsupported cipher %.100s used in key file %.200s.", 349511b41d2SMark Murray cipher_name(cipher_type), filename); 350511b41d2SMark Murray buffer_free(&buffer); 351511b41d2SMark Murray goto fail; 352511b41d2SMark Murray } 353511b41d2SMark Murray /* Initialize space for decrypted data. */ 354511b41d2SMark Murray buffer_init(&decrypted); 355511b41d2SMark Murray buffer_append_space(&decrypted, &cp, buffer_len(&buffer)); 356511b41d2SMark Murray 357511b41d2SMark Murray /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 358e8aafc91SKris Kennaway cipher_set_key_string(&cipher, cipher_type, passphrase); 359511b41d2SMark Murray cipher_decrypt(&cipher, (unsigned char *) cp, 360511b41d2SMark Murray (unsigned char *) buffer_ptr(&buffer), 361511b41d2SMark Murray buffer_len(&buffer)); 362511b41d2SMark Murray 363511b41d2SMark Murray buffer_free(&buffer); 364511b41d2SMark Murray 365511b41d2SMark Murray check1 = buffer_get_char(&decrypted); 366511b41d2SMark Murray check2 = buffer_get_char(&decrypted); 367511b41d2SMark Murray if (check1 != buffer_get_char(&decrypted) || 368511b41d2SMark Murray check2 != buffer_get_char(&decrypted)) { 369511b41d2SMark Murray if (strcmp(passphrase, "") != 0) 370511b41d2SMark Murray debug("Bad passphrase supplied for key file %.200s.", filename); 371511b41d2SMark Murray /* Bad passphrase. */ 372511b41d2SMark Murray buffer_free(&decrypted); 373511b41d2SMark Murray fail: 374511b41d2SMark Murray BN_clear_free(prv->n); 375e8aafc91SKris Kennaway prv->n = NULL; 376511b41d2SMark Murray BN_clear_free(prv->e); 377e8aafc91SKris Kennaway prv->e = NULL; 378511b41d2SMark Murray if (comment_return) 379511b41d2SMark Murray xfree(*comment_return); 380511b41d2SMark Murray return 0; 381511b41d2SMark Murray } 382511b41d2SMark Murray /* Read the rest of the private key. */ 383511b41d2SMark Murray prv->d = BN_new(); 384511b41d2SMark Murray buffer_get_bignum(&decrypted, prv->d); 385511b41d2SMark Murray prv->iqmp = BN_new(); 386511b41d2SMark Murray buffer_get_bignum(&decrypted, prv->iqmp); /* u */ 387511b41d2SMark Murray /* in SSL and SSH p and q are exchanged */ 388511b41d2SMark Murray prv->q = BN_new(); 389511b41d2SMark Murray buffer_get_bignum(&decrypted, prv->q); /* p */ 390511b41d2SMark Murray prv->p = BN_new(); 391511b41d2SMark Murray buffer_get_bignum(&decrypted, prv->p); /* q */ 392511b41d2SMark Murray 393511b41d2SMark Murray ctx = BN_CTX_new(); 394511b41d2SMark Murray aux = BN_new(); 395511b41d2SMark Murray 396511b41d2SMark Murray BN_sub(aux, prv->q, BN_value_one()); 397511b41d2SMark Murray prv->dmq1 = BN_new(); 398511b41d2SMark Murray BN_mod(prv->dmq1, prv->d, aux, ctx); 399511b41d2SMark Murray 400511b41d2SMark Murray BN_sub(aux, prv->p, BN_value_one()); 401511b41d2SMark Murray prv->dmp1 = BN_new(); 402511b41d2SMark Murray BN_mod(prv->dmp1, prv->d, aux, ctx); 403511b41d2SMark Murray 404511b41d2SMark Murray BN_clear_free(aux); 405511b41d2SMark Murray BN_CTX_free(ctx); 406511b41d2SMark Murray 407511b41d2SMark Murray buffer_free(&decrypted); 408511b41d2SMark Murray 409511b41d2SMark Murray return 1; 410511b41d2SMark Murray } 411e8aafc91SKris Kennaway 412e8aafc91SKris Kennaway int 413e8aafc91SKris Kennaway load_private_key_dsa(int fd, const char *passphrase, Key *k, char **comment_return) 414e8aafc91SKris Kennaway { 415e8aafc91SKris Kennaway DSA *dsa; 416e8aafc91SKris Kennaway BIO *in; 417e8aafc91SKris Kennaway FILE *fp; 418e8aafc91SKris Kennaway 419e8aafc91SKris Kennaway in = BIO_new(BIO_s_file()); 420e8aafc91SKris Kennaway if (in == NULL) { 421e8aafc91SKris Kennaway error("BIO_new failed"); 422e8aafc91SKris Kennaway return 0; 423e8aafc91SKris Kennaway } 424e8aafc91SKris Kennaway fp = fdopen(fd, "r"); 425e8aafc91SKris Kennaway if (fp == NULL) { 426e8aafc91SKris Kennaway error("fdopen failed"); 427e8aafc91SKris Kennaway return 0; 428e8aafc91SKris Kennaway } 429e8aafc91SKris Kennaway BIO_set_fp(in, fp, BIO_NOCLOSE); 430e8aafc91SKris Kennaway dsa = PEM_read_bio_DSAPrivateKey(in, NULL, NULL, (char *)passphrase); 431e8aafc91SKris Kennaway if (dsa == NULL) { 432e8aafc91SKris Kennaway debug("PEM_read_bio_DSAPrivateKey failed"); 433e8aafc91SKris Kennaway } else { 434e8aafc91SKris Kennaway /* replace k->dsa with loaded key */ 435e8aafc91SKris Kennaway DSA_free(k->dsa); 436e8aafc91SKris Kennaway k->dsa = dsa; 437e8aafc91SKris Kennaway } 438e8aafc91SKris Kennaway BIO_free(in); 439e8aafc91SKris Kennaway fclose(fp); 440e8aafc91SKris Kennaway if (comment_return) 441e8aafc91SKris Kennaway *comment_return = xstrdup("dsa w/o comment"); 442e8aafc91SKris Kennaway debug("read DSA private key done"); 443e8aafc91SKris Kennaway #ifdef DEBUG_DSS 444e8aafc91SKris Kennaway DSA_print_fp(stderr, dsa, 8); 445e8aafc91SKris Kennaway #endif 446e8aafc91SKris Kennaway return dsa != NULL ? 1 : 0; 447e8aafc91SKris Kennaway } 448e8aafc91SKris Kennaway 449e8aafc91SKris Kennaway int 450e8aafc91SKris Kennaway load_private_key(const char *filename, const char *passphrase, Key *key, 451e8aafc91SKris Kennaway char **comment_return) 452e8aafc91SKris Kennaway { 453e8aafc91SKris Kennaway int fd; 454e8aafc91SKris Kennaway int ret = 0; 455e8aafc91SKris Kennaway struct stat st; 456e8aafc91SKris Kennaway 457e8aafc91SKris Kennaway fd = open(filename, O_RDONLY); 458e8aafc91SKris Kennaway if (fd < 0) 459e8aafc91SKris Kennaway return 0; 460e8aafc91SKris Kennaway 461e8aafc91SKris Kennaway /* check owner and modes */ 462e8aafc91SKris Kennaway if (fstat(fd, &st) < 0 || 463e8aafc91SKris Kennaway (st.st_uid != 0 && st.st_uid != getuid()) || 464e8aafc91SKris Kennaway (st.st_mode & 077) != 0) { 465e8aafc91SKris Kennaway close(fd); 466e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 467e8aafc91SKris Kennaway error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 468e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 469e8aafc91SKris Kennaway error("Bad ownership or mode(0%3.3o) for '%s'.", 470e8aafc91SKris Kennaway st.st_mode & 0777, filename); 471e8aafc91SKris Kennaway error("It is recommended that your private key files are NOT accessible by others."); 472e8aafc91SKris Kennaway return 0; 473e8aafc91SKris Kennaway } 474e8aafc91SKris Kennaway switch (key->type) { 475e8aafc91SKris Kennaway case KEY_RSA: 476e8aafc91SKris Kennaway if (key->rsa->e != NULL) { 477e8aafc91SKris Kennaway BN_clear_free(key->rsa->e); 478e8aafc91SKris Kennaway key->rsa->e = NULL; 479e8aafc91SKris Kennaway } 480e8aafc91SKris Kennaway if (key->rsa->n != NULL) { 481e8aafc91SKris Kennaway BN_clear_free(key->rsa->n); 482e8aafc91SKris Kennaway key->rsa->n = NULL; 483e8aafc91SKris Kennaway } 484e8aafc91SKris Kennaway ret = load_private_key_rsa(fd, filename, passphrase, 485e8aafc91SKris Kennaway key->rsa, comment_return); 486e8aafc91SKris Kennaway break; 487e8aafc91SKris Kennaway case KEY_DSA: 488e8aafc91SKris Kennaway ret = load_private_key_dsa(fd, passphrase, key, comment_return); 489e8aafc91SKris Kennaway default: 490e8aafc91SKris Kennaway break; 491e8aafc91SKris Kennaway } 492e8aafc91SKris Kennaway close(fd); 493e8aafc91SKris Kennaway return ret; 494e8aafc91SKris Kennaway } 495