1264377Sdes/* $OpenBSD: authfile.c,v 1.103 2014/02/02 03:44:31 djm Exp $ */ 257429Smarkm/* 357429Smarkm * Author: Tatu Ylonen <ylo@cs.hut.fi> 457429Smarkm * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 557429Smarkm * All rights reserved 657429Smarkm * This file contains functions for reading and writing identity files, and 757429Smarkm * for reading the passphrase from the user. 860576Skris * 965674Skris * As far as I am concerned, the code I have written for this software 1065674Skris * can be used freely for any purpose. Any derived versions of this 1165674Skris * software must be clearly marked as such, and if the derived work is 1265674Skris * incompatible with the protocol description in the RFC file, it must be 1365674Skris * called by a name other than "ssh" or "Secure Shell". 1465674Skris * 1565674Skris * 16262566Sdes * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. 1765674Skris * 1865674Skris * Redistribution and use in source and binary forms, with or without 1965674Skris * modification, are permitted provided that the following conditions 2065674Skris * are met: 2165674Skris * 1. Redistributions of source code must retain the above copyright 2265674Skris * notice, this list of conditions and the following disclaimer. 2365674Skris * 2. Redistributions in binary form must reproduce the above copyright 2465674Skris * notice, this list of conditions and the following disclaimer in the 2565674Skris * documentation and/or other materials provided with the distribution. 2665674Skris * 2765674Skris * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2865674Skris * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2965674Skris * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 3065674Skris * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3165674Skris * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3265674Skris * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3365674Skris * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3465674Skris * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3565674Skris * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3665674Skris * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3757429Smarkm */ 3857429Smarkm 3957429Smarkm#include "includes.h" 4057429Smarkm 41162856Sdes#include <sys/types.h> 42162856Sdes#include <sys/stat.h> 43162856Sdes#include <sys/param.h> 44162856Sdes#include <sys/uio.h> 45162856Sdes 4676262Sgreen#include <openssl/err.h> 4776262Sgreen#include <openssl/evp.h> 4860576Skris#include <openssl/pem.h> 4960576Skris 50204917Sdes/* compatibility with old or broken OpenSSL versions */ 51204917Sdes#include "openbsd-compat/openssl-compat.h" 52204917Sdes 53262566Sdes#include "crypto_api.h" 54262566Sdes 55162856Sdes#include <errno.h> 56162856Sdes#include <fcntl.h> 57162856Sdes#include <stdarg.h> 58162856Sdes#include <stdio.h> 59162856Sdes#include <stdlib.h> 60162856Sdes#include <string.h> 61162856Sdes#include <unistd.h> 62162856Sdes 63262566Sdes#ifdef HAVE_UTIL_H 64262566Sdes#include <util.h> 65262566Sdes#endif 66262566Sdes 67162856Sdes#include "xmalloc.h" 6876262Sgreen#include "cipher.h" 6957429Smarkm#include "buffer.h" 7076262Sgreen#include "key.h" 7157429Smarkm#include "ssh.h" 7276262Sgreen#include "log.h" 7376262Sgreen#include "authfile.h" 7492559Sdes#include "rsa.h" 75147005Sdes#include "misc.h" 76149753Sdes#include "atomicio.h" 77262566Sdes#include "uuencode.h" 7857429Smarkm 79262566Sdes/* openssh private key file format */ 80262566Sdes#define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" 81262566Sdes#define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" 82262566Sdes#define KDFNAME "bcrypt" 83262566Sdes#define AUTH_MAGIC "openssh-key-v1" 84262566Sdes#define SALT_LEN 16 85262566Sdes#define DEFAULT_CIPHERNAME "aes256-cbc" 86262566Sdes#define DEFAULT_ROUNDS 16 87262566Sdes 88226046Sdes#define MAX_KEY_FILE_SIZE (1024 * 1024) 89226046Sdes 9076262Sgreen/* Version identification string for SSH v1 identity files. */ 9176262Sgreenstatic const char authfile_id_string[] = 9276262Sgreen "SSH PRIVATE KEY FILE FORMAT 1.1\n"; 9357429Smarkm 94262566Sdesstatic int 95262566Sdeskey_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase, 96262566Sdes const char *comment, const char *ciphername, int rounds) 97262566Sdes{ 98262566Sdes u_char *key, *cp, salt[SALT_LEN]; 99262566Sdes size_t keylen, ivlen, blocksize, authlen; 100262566Sdes u_int len, check; 101262566Sdes int i, n; 102262566Sdes const Cipher *c; 103262566Sdes Buffer encoded, b, kdf; 104262566Sdes CipherContext ctx; 105262566Sdes const char *kdfname = KDFNAME; 106262566Sdes 107262566Sdes if (rounds <= 0) 108262566Sdes rounds = DEFAULT_ROUNDS; 109262566Sdes if (passphrase == NULL || !strlen(passphrase)) { 110262566Sdes ciphername = "none"; 111262566Sdes kdfname = "none"; 112262566Sdes } else if (ciphername == NULL) 113262566Sdes ciphername = DEFAULT_CIPHERNAME; 114262566Sdes else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) 115262566Sdes fatal("invalid cipher"); 116262566Sdes 117262566Sdes if ((c = cipher_by_name(ciphername)) == NULL) 118262566Sdes fatal("unknown cipher name"); 119262566Sdes buffer_init(&kdf); 120262566Sdes blocksize = cipher_blocksize(c); 121262566Sdes keylen = cipher_keylen(c); 122262566Sdes ivlen = cipher_ivlen(c); 123262566Sdes authlen = cipher_authlen(c); 124262566Sdes key = xcalloc(1, keylen + ivlen); 125262566Sdes if (strcmp(kdfname, "none") != 0) { 126262566Sdes arc4random_buf(salt, SALT_LEN); 127262566Sdes if (bcrypt_pbkdf(passphrase, strlen(passphrase), 128262566Sdes salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) 129262566Sdes fatal("bcrypt_pbkdf failed"); 130262566Sdes buffer_put_string(&kdf, salt, SALT_LEN); 131262566Sdes buffer_put_int(&kdf, rounds); 132262566Sdes } 133262566Sdes cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1); 134264377Sdes explicit_bzero(key, keylen + ivlen); 135262566Sdes free(key); 136262566Sdes 137262566Sdes buffer_init(&encoded); 138262566Sdes buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC)); 139262566Sdes buffer_put_cstring(&encoded, ciphername); 140262566Sdes buffer_put_cstring(&encoded, kdfname); 141262566Sdes buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf)); 142262566Sdes buffer_put_int(&encoded, 1); /* number of keys */ 143262566Sdes key_to_blob(prv, &cp, &len); /* public key */ 144262566Sdes buffer_put_string(&encoded, cp, len); 145262566Sdes 146264377Sdes explicit_bzero(cp, len); 147262566Sdes free(cp); 148262566Sdes 149262566Sdes buffer_free(&kdf); 150262566Sdes 151262566Sdes /* set up the buffer that will be encrypted */ 152262566Sdes buffer_init(&b); 153262566Sdes 154262566Sdes /* Random check bytes */ 155262566Sdes check = arc4random(); 156262566Sdes buffer_put_int(&b, check); 157262566Sdes buffer_put_int(&b, check); 158262566Sdes 159262566Sdes /* append private key and comment*/ 160262566Sdes key_private_serialize(prv, &b); 161262566Sdes buffer_put_cstring(&b, comment); 162262566Sdes 163262566Sdes /* padding */ 164262566Sdes i = 0; 165262566Sdes while (buffer_len(&b) % blocksize) 166262566Sdes buffer_put_char(&b, ++i & 0xff); 167262566Sdes 168262566Sdes /* length */ 169262566Sdes buffer_put_int(&encoded, buffer_len(&b)); 170262566Sdes 171262566Sdes /* encrypt */ 172262566Sdes cp = buffer_append_space(&encoded, buffer_len(&b) + authlen); 173262566Sdes if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0, 174262566Sdes authlen) != 0) 175262566Sdes fatal("%s: cipher_crypt failed", __func__); 176262566Sdes buffer_free(&b); 177262566Sdes cipher_cleanup(&ctx); 178262566Sdes 179262566Sdes /* uuencode */ 180262566Sdes len = 2 * buffer_len(&encoded); 181262566Sdes cp = xmalloc(len); 182262566Sdes n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded), 183262566Sdes (char *)cp, len); 184262566Sdes if (n < 0) 185262566Sdes fatal("%s: uuencode", __func__); 186262566Sdes 187262566Sdes buffer_clear(blob); 188262566Sdes buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1); 189262566Sdes for (i = 0; i < n; i++) { 190262566Sdes buffer_put_char(blob, cp[i]); 191262566Sdes if (i % 70 == 69) 192262566Sdes buffer_put_char(blob, '\n'); 193262566Sdes } 194262566Sdes if (i % 70 != 69) 195262566Sdes buffer_put_char(blob, '\n'); 196262566Sdes buffer_append(blob, MARK_END, sizeof(MARK_END) - 1); 197262566Sdes free(cp); 198262566Sdes 199262566Sdes return buffer_len(blob); 200262566Sdes} 201262566Sdes 202262566Sdesstatic Key * 203262566Sdeskey_parse_private2(Buffer *blob, int type, const char *passphrase, 204262566Sdes char **commentp) 205262566Sdes{ 206262566Sdes u_char *key = NULL, *cp, *salt = NULL, pad, last; 207262566Sdes char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp; 208262566Sdes u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys; 209262566Sdes u_int check1, check2, m1len, m2len; 210262566Sdes size_t authlen; 211262566Sdes const Cipher *c; 212262566Sdes Buffer b, encoded, copy, kdf; 213262566Sdes CipherContext ctx; 214262566Sdes Key *k = NULL; 215262566Sdes int dlen, ret, i; 216262566Sdes 217262566Sdes buffer_init(&b); 218262566Sdes buffer_init(&kdf); 219262566Sdes buffer_init(&encoded); 220262566Sdes buffer_init(©); 221262566Sdes 222262566Sdes /* uudecode */ 223262566Sdes m1len = sizeof(MARK_BEGIN) - 1; 224262566Sdes m2len = sizeof(MARK_END) - 1; 225262566Sdes cp = buffer_ptr(blob); 226262566Sdes len = buffer_len(blob); 227262566Sdes if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) { 228262566Sdes debug("%s: missing begin marker", __func__); 229262566Sdes goto out; 230262566Sdes } 231262566Sdes cp += m1len; 232262566Sdes len -= m1len; 233262566Sdes while (len) { 234262566Sdes if (*cp != '\n' && *cp != '\r') 235262566Sdes buffer_put_char(&encoded, *cp); 236262566Sdes last = *cp; 237262566Sdes len--; 238262566Sdes cp++; 239262566Sdes if (last == '\n') { 240262566Sdes if (len >= m2len && !memcmp(cp, MARK_END, m2len)) { 241262566Sdes buffer_put_char(&encoded, '\0'); 242262566Sdes break; 243262566Sdes } 244262566Sdes } 245262566Sdes } 246262566Sdes if (!len) { 247262566Sdes debug("%s: no end marker", __func__); 248262566Sdes goto out; 249262566Sdes } 250262566Sdes len = buffer_len(&encoded); 251262566Sdes if ((cp = buffer_append_space(©, len)) == NULL) { 252262566Sdes error("%s: buffer_append_space", __func__); 253262566Sdes goto out; 254262566Sdes } 255262566Sdes if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) { 256262566Sdes error("%s: uudecode failed", __func__); 257262566Sdes goto out; 258262566Sdes } 259262566Sdes if ((u_int)dlen > len) { 260262566Sdes error("%s: crazy uudecode length %d > %u", __func__, dlen, len); 261262566Sdes goto out; 262262566Sdes } 263262566Sdes buffer_consume_end(©, len - dlen); 264262566Sdes if (buffer_len(©) < sizeof(AUTH_MAGIC) || 265262566Sdes memcmp(buffer_ptr(©), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { 266262566Sdes error("%s: bad magic", __func__); 267262566Sdes goto out; 268262566Sdes } 269262566Sdes buffer_consume(©, sizeof(AUTH_MAGIC)); 270262566Sdes 271262566Sdes ciphername = buffer_get_cstring_ret(©, NULL); 272262566Sdes if (ciphername == NULL || 273262566Sdes (c = cipher_by_name(ciphername)) == NULL) { 274262566Sdes error("%s: unknown cipher name", __func__); 275262566Sdes goto out; 276262566Sdes } 277262566Sdes if ((passphrase == NULL || !strlen(passphrase)) && 278262566Sdes strcmp(ciphername, "none") != 0) { 279262566Sdes /* passphrase required */ 280262566Sdes goto out; 281262566Sdes } 282262566Sdes kdfname = buffer_get_cstring_ret(©, NULL); 283262566Sdes if (kdfname == NULL || 284262566Sdes (!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) { 285262566Sdes error("%s: unknown kdf name", __func__); 286262566Sdes goto out; 287262566Sdes } 288262566Sdes if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { 289262566Sdes error("%s: cipher %s requires kdf", __func__, ciphername); 290262566Sdes goto out; 291262566Sdes } 292262566Sdes /* kdf options */ 293262566Sdes kdfp = buffer_get_string_ptr_ret(©, &klen); 294262566Sdes if (kdfp == NULL) { 295262566Sdes error("%s: kdf options not set", __func__); 296262566Sdes goto out; 297262566Sdes } 298262566Sdes if (klen > 0) { 299262566Sdes if ((cp = buffer_append_space(&kdf, klen)) == NULL) { 300262566Sdes error("%s: kdf alloc failed", __func__); 301262566Sdes goto out; 302262566Sdes } 303262566Sdes memcpy(cp, kdfp, klen); 304262566Sdes } 305262566Sdes /* number of keys */ 306262566Sdes if (buffer_get_int_ret(&nkeys, ©) < 0) { 307262566Sdes error("%s: key counter missing", __func__); 308262566Sdes goto out; 309262566Sdes } 310262566Sdes if (nkeys != 1) { 311262566Sdes error("%s: only one key supported", __func__); 312262566Sdes goto out; 313262566Sdes } 314262566Sdes /* pubkey */ 315262566Sdes if ((cp = buffer_get_string_ret(©, &len)) == NULL) { 316262566Sdes error("%s: pubkey not found", __func__); 317262566Sdes goto out; 318262566Sdes } 319262566Sdes free(cp); /* XXX check pubkey against decrypted private key */ 320262566Sdes 321262566Sdes /* size of encrypted key blob */ 322262566Sdes len = buffer_get_int(©); 323262566Sdes blocksize = cipher_blocksize(c); 324262566Sdes authlen = cipher_authlen(c); 325262566Sdes if (len < blocksize) { 326262566Sdes error("%s: encrypted data too small", __func__); 327262566Sdes goto out; 328262566Sdes } 329262566Sdes if (len % blocksize) { 330262566Sdes error("%s: length not multiple of blocksize", __func__); 331262566Sdes goto out; 332262566Sdes } 333262566Sdes 334262566Sdes /* setup key */ 335262566Sdes keylen = cipher_keylen(c); 336262566Sdes ivlen = cipher_ivlen(c); 337262566Sdes key = xcalloc(1, keylen + ivlen); 338262566Sdes if (!strcmp(kdfname, "bcrypt")) { 339262566Sdes if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) { 340262566Sdes error("%s: salt not set", __func__); 341262566Sdes goto out; 342262566Sdes } 343262566Sdes if (buffer_get_int_ret(&rounds, &kdf) < 0) { 344262566Sdes error("%s: rounds not set", __func__); 345262566Sdes goto out; 346262566Sdes } 347262566Sdes if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, 348262566Sdes key, keylen + ivlen, rounds) < 0) { 349262566Sdes error("%s: bcrypt_pbkdf failed", __func__); 350262566Sdes goto out; 351262566Sdes } 352262566Sdes } 353262566Sdes 354262566Sdes cp = buffer_append_space(&b, len); 355262566Sdes cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0); 356262566Sdes ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(©), len, 0, authlen); 357262566Sdes cipher_cleanup(&ctx); 358262566Sdes buffer_consume(©, len); 359262566Sdes 360262566Sdes /* fail silently on decryption errors */ 361262566Sdes if (ret != 0) { 362262566Sdes debug("%s: decrypt failed", __func__); 363262566Sdes goto out; 364262566Sdes } 365262566Sdes 366262566Sdes if (buffer_len(©) != 0) { 367262566Sdes error("%s: key blob has trailing data (len = %u)", __func__, 368262566Sdes buffer_len(©)); 369262566Sdes goto out; 370262566Sdes } 371262566Sdes 372262566Sdes /* check bytes */ 373262566Sdes if (buffer_get_int_ret(&check1, &b) < 0 || 374262566Sdes buffer_get_int_ret(&check2, &b) < 0) { 375262566Sdes error("check bytes missing"); 376262566Sdes goto out; 377262566Sdes } 378262566Sdes if (check1 != check2) { 379262566Sdes debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__, 380262566Sdes check1, check2); 381262566Sdes goto out; 382262566Sdes } 383262566Sdes 384262566Sdes k = key_private_deserialize(&b); 385262566Sdes 386262566Sdes /* comment */ 387262566Sdes comment = buffer_get_cstring_ret(&b, NULL); 388262566Sdes 389262566Sdes i = 0; 390262566Sdes while (buffer_len(&b)) { 391262566Sdes if (buffer_get_char_ret(&pad, &b) == -1 || 392262566Sdes pad != (++i & 0xff)) { 393262566Sdes error("%s: bad padding", __func__); 394262566Sdes key_free(k); 395262566Sdes k = NULL; 396262566Sdes goto out; 397262566Sdes } 398262566Sdes } 399262566Sdes 400262566Sdes if (k && commentp) { 401262566Sdes *commentp = comment; 402262566Sdes comment = NULL; 403262566Sdes } 404262566Sdes 405262566Sdes /* XXX decode pubkey and check against private */ 406262566Sdes out: 407262566Sdes free(ciphername); 408262566Sdes free(kdfname); 409262566Sdes free(salt); 410262566Sdes free(comment); 411262566Sdes if (key) 412264377Sdes explicit_bzero(key, keylen + ivlen); 413262566Sdes free(key); 414262566Sdes buffer_free(&encoded); 415262566Sdes buffer_free(©); 416262566Sdes buffer_free(&kdf); 417262566Sdes buffer_free(&b); 418262566Sdes return k; 419262566Sdes} 420262566Sdes 42157429Smarkm/* 422221420Sdes * Serialises the authentication (private) key to a blob, encrypting it with 423221420Sdes * passphrase. The identification of the blob (lowest 64 bits of n) will 42457429Smarkm * precede the key to provide identification of the key without needing a 42557429Smarkm * passphrase. 42657429Smarkm */ 42792559Sdesstatic int 428221420Sdeskey_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, 42976262Sgreen const char *comment) 43057429Smarkm{ 43157429Smarkm Buffer buffer, encrypted; 43292559Sdes u_char buf[100], *cp; 433221420Sdes int i, cipher_num; 43469591Sgreen CipherContext ciphercontext; 435255767Sdes const Cipher *cipher; 436137019Sdes u_int32_t rnd; 43757429Smarkm 43857429Smarkm /* 43957429Smarkm * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting 44057429Smarkm * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. 44157429Smarkm */ 44292559Sdes cipher_num = (strcmp(passphrase, "") == 0) ? 44392559Sdes SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; 44492559Sdes if ((cipher = cipher_by_number(cipher_num)) == NULL) 44569591Sgreen fatal("save_private_key_rsa: bad cipher"); 44657429Smarkm 44757429Smarkm /* This buffer is used to built the secret part of the private key. */ 44857429Smarkm buffer_init(&buffer); 44957429Smarkm 45057429Smarkm /* Put checkbytes for checking passphrase validity. */ 451137019Sdes rnd = arc4random(); 452137019Sdes buf[0] = rnd & 0xff; 453137019Sdes buf[1] = (rnd >> 8) & 0xff; 45457429Smarkm buf[2] = buf[0]; 45557429Smarkm buf[3] = buf[1]; 45657429Smarkm buffer_append(&buffer, buf, 4); 45757429Smarkm 45857429Smarkm /* 45957429Smarkm * Store the private key (n and e will not be stored because they 46057429Smarkm * will be stored in plain text, and storing them also in encrypted 46157429Smarkm * format would just give known plaintext). 46257429Smarkm */ 46376262Sgreen buffer_put_bignum(&buffer, key->rsa->d); 46476262Sgreen buffer_put_bignum(&buffer, key->rsa->iqmp); 46576262Sgreen buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ 46676262Sgreen buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ 46757429Smarkm 46857429Smarkm /* Pad the part to be encrypted until its size is a multiple of 8. */ 46957429Smarkm while (buffer_len(&buffer) % 8 != 0) 47057429Smarkm buffer_put_char(&buffer, 0); 47157429Smarkm 47257429Smarkm /* This buffer will be used to contain the data in the file. */ 47357429Smarkm buffer_init(&encrypted); 47457429Smarkm 47557429Smarkm /* First store keyfile id string. */ 47676262Sgreen for (i = 0; authfile_id_string[i]; i++) 47776262Sgreen buffer_put_char(&encrypted, authfile_id_string[i]); 47857429Smarkm buffer_put_char(&encrypted, 0); 47957429Smarkm 48057429Smarkm /* Store cipher type. */ 48192559Sdes buffer_put_char(&encrypted, cipher_num); 48257429Smarkm buffer_put_int(&encrypted, 0); /* For future extension */ 48357429Smarkm 48457429Smarkm /* Store public key. This will be in plain text. */ 48576262Sgreen buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); 48676262Sgreen buffer_put_bignum(&encrypted, key->rsa->n); 48776262Sgreen buffer_put_bignum(&encrypted, key->rsa->e); 48892559Sdes buffer_put_cstring(&encrypted, comment); 48957429Smarkm 49057429Smarkm /* Allocate space for the private part of the key in the buffer. */ 49192559Sdes cp = buffer_append_space(&encrypted, buffer_len(&buffer)); 49257429Smarkm 49392559Sdes cipher_set_key_string(&ciphercontext, cipher, passphrase, 49492559Sdes CIPHER_ENCRYPT); 495262566Sdes if (cipher_crypt(&ciphercontext, 0, cp, 496262566Sdes buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0) 497262566Sdes fatal("%s: cipher_crypt failed", __func__); 49892559Sdes cipher_cleanup(&ciphercontext); 499264377Sdes explicit_bzero(&ciphercontext, sizeof(ciphercontext)); 50057429Smarkm 50157429Smarkm /* Destroy temporary data. */ 502264377Sdes explicit_bzero(buf, sizeof(buf)); 50357429Smarkm buffer_free(&buffer); 50457429Smarkm 505221420Sdes buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); 50657429Smarkm buffer_free(&encrypted); 507221420Sdes 50857429Smarkm return 1; 50957429Smarkm} 51057429Smarkm 511221420Sdes/* convert SSH v2 key in OpenSSL PEM format */ 51292559Sdesstatic int 513221420Sdeskey_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, 51476262Sgreen const char *comment) 51560576Skris{ 51676262Sgreen int success = 0; 517221420Sdes int blen, len = strlen(_passphrase); 51892559Sdes u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; 519204917Sdes#if (OPENSSL_VERSION_NUMBER < 0x00907000L) 52092559Sdes const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; 521204917Sdes#else 522204917Sdes const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; 523204917Sdes#endif 524221420Sdes const u_char *bptr; 525221420Sdes BIO *bio; 52660576Skris 52760576Skris if (len > 0 && len <= 4) { 52876262Sgreen error("passphrase too short: have %d bytes, need > 4", len); 52960576Skris return 0; 53060576Skris } 531221420Sdes if ((bio = BIO_new(BIO_s_mem())) == NULL) { 532221420Sdes error("%s: BIO_new failed", __func__); 53360576Skris return 0; 53460576Skris } 53576262Sgreen switch (key->type) { 53676262Sgreen case KEY_DSA: 537221420Sdes success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, 53876262Sgreen cipher, passphrase, len, NULL, NULL); 53976262Sgreen break; 540221420Sdes#ifdef OPENSSL_HAS_ECC 541221420Sdes case KEY_ECDSA: 542221420Sdes success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, 543221420Sdes cipher, passphrase, len, NULL, NULL); 544221420Sdes break; 545221420Sdes#endif 54676262Sgreen case KEY_RSA: 547221420Sdes success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, 54876262Sgreen cipher, passphrase, len, NULL, NULL); 54976262Sgreen break; 55060576Skris } 551221420Sdes if (success) { 552221420Sdes if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) 553221420Sdes success = 0; 554221420Sdes else 555221420Sdes buffer_append(blob, bptr, blen); 556221420Sdes } 557221420Sdes BIO_free(bio); 55860576Skris return success; 55960576Skris} 56060576Skris 561221420Sdes/* Save a key blob to a file */ 562221420Sdesstatic int 563221420Sdeskey_save_private_blob(Buffer *keybuf, const char *filename) 564221420Sdes{ 565221420Sdes int fd; 566221420Sdes 567221420Sdes if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { 568221420Sdes error("open %s failed: %s.", filename, strerror(errno)); 569221420Sdes return 0; 570221420Sdes } 571221420Sdes if (atomicio(vwrite, fd, buffer_ptr(keybuf), 572221420Sdes buffer_len(keybuf)) != buffer_len(keybuf)) { 573221420Sdes error("write to key file %s failed: %s", filename, 574221420Sdes strerror(errno)); 575221420Sdes close(fd); 576221420Sdes unlink(filename); 577221420Sdes return 0; 578221420Sdes } 579221420Sdes close(fd); 580221420Sdes return 1; 581221420Sdes} 582221420Sdes 583221420Sdes/* Serialise "key" to buffer "blob" */ 584221420Sdesstatic int 585221420Sdeskey_private_to_blob(Key *key, Buffer *blob, const char *passphrase, 586262566Sdes const char *comment, int force_new_format, const char *new_format_cipher, 587262566Sdes int new_format_rounds) 58860576Skris{ 58960576Skris switch (key->type) { 59076262Sgreen case KEY_RSA1: 591221420Sdes return key_private_rsa1_to_blob(key, blob, passphrase, comment); 59260576Skris case KEY_DSA: 593221420Sdes case KEY_ECDSA: 59476262Sgreen case KEY_RSA: 595262566Sdes if (force_new_format) { 596262566Sdes return key_private_to_blob2(key, blob, passphrase, 597262566Sdes comment, new_format_cipher, new_format_rounds); 598262566Sdes } 599221420Sdes return key_private_pem_to_blob(key, blob, passphrase, comment); 600262566Sdes case KEY_ED25519: 601262566Sdes return key_private_to_blob2(key, blob, passphrase, 602262566Sdes comment, new_format_cipher, new_format_rounds); 60360576Skris default: 604221420Sdes error("%s: cannot save key type %d", __func__, key->type); 605221420Sdes return 0; 60660576Skris } 60760576Skris} 60860576Skris 609221420Sdesint 610221420Sdeskey_save_private(Key *key, const char *filename, const char *passphrase, 611262566Sdes const char *comment, int force_new_format, const char *new_format_cipher, 612262566Sdes int new_format_rounds) 613221420Sdes{ 614221420Sdes Buffer keyblob; 615221420Sdes int success = 0; 616221420Sdes 617221420Sdes buffer_init(&keyblob); 618262566Sdes if (!key_private_to_blob(key, &keyblob, passphrase, comment, 619262566Sdes force_new_format, new_format_cipher, new_format_rounds)) 620221420Sdes goto out; 621221420Sdes if (!key_save_private_blob(&keyblob, filename)) 622221420Sdes goto out; 623221420Sdes success = 1; 624221420Sdes out: 625221420Sdes buffer_free(&keyblob); 626221420Sdes return success; 627221420Sdes} 628221420Sdes 62957429Smarkm/* 630221420Sdes * Parse the public, unencrypted portion of a RSA1 key. 63157429Smarkm */ 63292559Sdesstatic Key * 633221420Sdeskey_parse_public_rsa1(Buffer *blob, char **commentp) 63457429Smarkm{ 63576262Sgreen Key *pub; 636226046Sdes Buffer copy; 637221420Sdes 638221420Sdes /* Check that it is at least big enough to contain the ID string. */ 639221420Sdes if (buffer_len(blob) < sizeof(authfile_id_string)) { 640221420Sdes debug3("Truncated RSA1 identifier"); 641221420Sdes return NULL; 642221420Sdes } 643221420Sdes 644221420Sdes /* 645221420Sdes * Make sure it begins with the id string. Consume the id string 646221420Sdes * from the buffer. 647221420Sdes */ 648221420Sdes if (memcmp(buffer_ptr(blob), authfile_id_string, 649221420Sdes sizeof(authfile_id_string)) != 0) { 650221420Sdes debug3("Incorrect RSA1 identifier"); 651221420Sdes return NULL; 652221420Sdes } 653226046Sdes buffer_init(©); 654226046Sdes buffer_append(©, buffer_ptr(blob), buffer_len(blob)); 655226046Sdes buffer_consume(©, sizeof(authfile_id_string)); 656221420Sdes 657221420Sdes /* Skip cipher type and reserved data. */ 658226046Sdes (void) buffer_get_char(©); /* cipher type */ 659226046Sdes (void) buffer_get_int(©); /* reserved */ 660221420Sdes 661221420Sdes /* Read the public key from the buffer. */ 662226046Sdes (void) buffer_get_int(©); 663221420Sdes pub = key_new(KEY_RSA1); 664226046Sdes buffer_get_bignum(©, pub->rsa->n); 665226046Sdes buffer_get_bignum(©, pub->rsa->e); 666221420Sdes if (commentp) 667226046Sdes *commentp = buffer_get_string(©, NULL); 668221420Sdes /* The encrypted private part is not parsed by this function. */ 669226046Sdes buffer_free(©); 670221420Sdes 671221420Sdes return pub; 672221420Sdes} 673221420Sdes 674226046Sdes/* Load a key from a fd into a buffer */ 675226046Sdesint 676221420Sdeskey_load_file(int fd, const char *filename, Buffer *blob) 677221420Sdes{ 678226046Sdes u_char buf[1024]; 679221420Sdes size_t len; 680113911Sdes struct stat st; 68157429Smarkm 682113911Sdes if (fstat(fd, &st) < 0) { 683221420Sdes error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, 684221420Sdes filename == NULL ? "" : filename, 685221420Sdes filename == NULL ? "" : " ", 686221420Sdes strerror(errno)); 687221420Sdes return 0; 688113911Sdes } 689226046Sdes if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 690226046Sdes st.st_size > MAX_KEY_FILE_SIZE) { 691226046Sdes toobig: 692221420Sdes error("%s: key file %.200s%stoo large", __func__, 693221420Sdes filename == NULL ? "" : filename, 694221420Sdes filename == NULL ? "" : " "); 695221420Sdes return 0; 696147005Sdes } 697240075Sdes buffer_clear(blob); 698226046Sdes for (;;) { 699226046Sdes if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 700226046Sdes if (errno == EPIPE) 701226046Sdes break; 702226046Sdes debug("%s: read from key file %.200s%sfailed: %.100s", 703226046Sdes __func__, filename == NULL ? "" : filename, 704226046Sdes filename == NULL ? "" : " ", strerror(errno)); 705226046Sdes buffer_clear(blob); 706264377Sdes explicit_bzero(buf, sizeof(buf)); 707226046Sdes return 0; 708226046Sdes } 709226046Sdes buffer_append(blob, buf, len); 710226046Sdes if (buffer_len(blob) > MAX_KEY_FILE_SIZE) { 711226046Sdes buffer_clear(blob); 712264377Sdes explicit_bzero(buf, sizeof(buf)); 713226046Sdes goto toobig; 714226046Sdes } 715226046Sdes } 716264377Sdes explicit_bzero(buf, sizeof(buf)); 717226046Sdes if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 718226046Sdes st.st_size != buffer_len(blob)) { 719226046Sdes debug("%s: key file %.200s%schanged size while reading", 720226046Sdes __func__, filename == NULL ? "" : filename, 721226046Sdes filename == NULL ? "" : " "); 722221420Sdes buffer_clear(blob); 723221420Sdes return 0; 72457429Smarkm } 725226046Sdes 726221420Sdes return 1; 727221420Sdes} 72857429Smarkm 729221420Sdes/* 730221420Sdes * Loads the public part of the ssh v1 key file. Returns NULL if an error was 731221420Sdes * encountered (the file does not exist or is not readable), and the key 732221420Sdes * otherwise. 733221420Sdes */ 734221420Sdesstatic Key * 735221420Sdeskey_load_public_rsa1(int fd, const char *filename, char **commentp) 736221420Sdes{ 737221420Sdes Buffer buffer; 738221420Sdes Key *pub; 739221420Sdes 740221420Sdes buffer_init(&buffer); 741221420Sdes if (!key_load_file(fd, filename, &buffer)) { 74257429Smarkm buffer_free(&buffer); 74376262Sgreen return NULL; 74457429Smarkm } 74557429Smarkm 746221420Sdes pub = key_parse_public_rsa1(&buffer, commentp); 747221420Sdes if (pub == NULL) 748221420Sdes debug3("Could not load \"%s\" as a RSA1 public key", filename); 74957429Smarkm buffer_free(&buffer); 75076262Sgreen return pub; 75157429Smarkm} 75257429Smarkm 75376262Sgreen/* load public key from private-key file, works only for SSH v1 */ 75476262SgreenKey * 75576262Sgreenkey_load_public_type(int type, const char *filename, char **commentp) 75660576Skris{ 75776262Sgreen Key *pub; 75876262Sgreen int fd; 75976262Sgreen 76076262Sgreen if (type == KEY_RSA1) { 76176262Sgreen fd = open(filename, O_RDONLY); 76276262Sgreen if (fd < 0) 76376262Sgreen return NULL; 76476262Sgreen pub = key_load_public_rsa1(fd, filename, commentp); 76576262Sgreen close(fd); 76676262Sgreen return pub; 76760576Skris } 76876262Sgreen return NULL; 76960576Skris} 77060576Skris 77192559Sdesstatic Key * 772221420Sdeskey_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) 77357429Smarkm{ 774149753Sdes int check1, check2, cipher_type; 775221420Sdes Buffer decrypted; 77692559Sdes u_char *cp; 77769591Sgreen CipherContext ciphercontext; 778255767Sdes const Cipher *cipher; 77976262Sgreen Key *prv = NULL; 780226046Sdes Buffer copy; 78157429Smarkm 782221420Sdes /* Check that it is at least big enough to contain the ID string. */ 783221420Sdes if (buffer_len(blob) < sizeof(authfile_id_string)) { 784221420Sdes debug3("Truncated RSA1 identifier"); 785113911Sdes return NULL; 786113911Sdes } 78757429Smarkm 78857429Smarkm /* 78957429Smarkm * Make sure it begins with the id string. Consume the id string 79057429Smarkm * from the buffer. 79157429Smarkm */ 792221420Sdes if (memcmp(buffer_ptr(blob), authfile_id_string, 793221420Sdes sizeof(authfile_id_string)) != 0) { 794221420Sdes debug3("Incorrect RSA1 identifier"); 795221420Sdes return NULL; 796221420Sdes } 797226046Sdes buffer_init(©); 798226046Sdes buffer_append(©, buffer_ptr(blob), buffer_len(blob)); 799226046Sdes buffer_consume(©, sizeof(authfile_id_string)); 80076262Sgreen 80157429Smarkm /* Read cipher type. */ 802226046Sdes cipher_type = buffer_get_char(©); 803226046Sdes (void) buffer_get_int(©); /* Reserved data. */ 80457429Smarkm 80557429Smarkm /* Read the public key from the buffer. */ 806226046Sdes (void) buffer_get_int(©); 80776262Sgreen prv = key_new_private(KEY_RSA1); 80876262Sgreen 809226046Sdes buffer_get_bignum(©, prv->rsa->n); 810226046Sdes buffer_get_bignum(©, prv->rsa->e); 81176262Sgreen if (commentp) 812226046Sdes *commentp = buffer_get_string(©, NULL); 81357429Smarkm else 814226046Sdes (void)buffer_get_string_ptr(©, NULL); 81557429Smarkm 81657429Smarkm /* Check that it is a supported cipher. */ 81769591Sgreen cipher = cipher_by_number(cipher_type); 81869591Sgreen if (cipher == NULL) { 819221420Sdes debug("Unsupported RSA1 cipher %d", cipher_type); 820226046Sdes buffer_free(©); 82157429Smarkm goto fail; 82257429Smarkm } 82357429Smarkm /* Initialize space for decrypted data. */ 82457429Smarkm buffer_init(&decrypted); 825226046Sdes cp = buffer_append_space(&decrypted, buffer_len(©)); 82657429Smarkm 82757429Smarkm /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 82892559Sdes cipher_set_key_string(&ciphercontext, cipher, passphrase, 82992559Sdes CIPHER_DECRYPT); 830262566Sdes if (cipher_crypt(&ciphercontext, 0, cp, 831262566Sdes buffer_ptr(©), buffer_len(©), 0, 0) != 0) 832262566Sdes fatal("%s: cipher_crypt failed", __func__); 83392559Sdes cipher_cleanup(&ciphercontext); 834264377Sdes explicit_bzero(&ciphercontext, sizeof(ciphercontext)); 835226046Sdes buffer_free(©); 83657429Smarkm 83757429Smarkm check1 = buffer_get_char(&decrypted); 83857429Smarkm check2 = buffer_get_char(&decrypted); 83957429Smarkm if (check1 != buffer_get_char(&decrypted) || 84057429Smarkm check2 != buffer_get_char(&decrypted)) { 84157429Smarkm if (strcmp(passphrase, "") != 0) 842221420Sdes debug("Bad passphrase supplied for RSA1 key"); 84357429Smarkm /* Bad passphrase. */ 84457429Smarkm buffer_free(&decrypted); 84576262Sgreen goto fail; 84657429Smarkm } 84757429Smarkm /* Read the rest of the private key. */ 84876262Sgreen buffer_get_bignum(&decrypted, prv->rsa->d); 84976262Sgreen buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ 85076262Sgreen /* in SSL and SSH v1 p and q are exchanged */ 85176262Sgreen buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ 85276262Sgreen buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ 85357429Smarkm 85476262Sgreen /* calculate p-1 and q-1 */ 85592559Sdes rsa_generate_additional_parameters(prv->rsa); 85657429Smarkm 85757429Smarkm buffer_free(&decrypted); 858113911Sdes 859113911Sdes /* enable blinding */ 860113911Sdes if (RSA_blinding_on(prv->rsa, NULL) != 1) { 861221420Sdes error("%s: RSA_blinding_on failed", __func__); 862113911Sdes goto fail; 863113911Sdes } 86476262Sgreen return prv; 86557429Smarkm 86676262Sgreenfail: 867255767Sdes if (commentp != NULL) 868255767Sdes free(*commentp); 86976262Sgreen key_free(prv); 87076262Sgreen return NULL; 87157429Smarkm} 87260576Skris 873221420Sdesstatic Key * 874221420Sdeskey_parse_private_pem(Buffer *blob, int type, const char *passphrase, 87576262Sgreen char **commentp) 87660576Skris{ 87776262Sgreen EVP_PKEY *pk = NULL; 87876262Sgreen Key *prv = NULL; 87976262Sgreen char *name = "<no key>"; 880221420Sdes BIO *bio; 88160576Skris 882221420Sdes if ((bio = BIO_new_mem_buf(buffer_ptr(blob), 883221420Sdes buffer_len(blob))) == NULL) { 884221420Sdes error("%s: BIO_new_mem_buf failed", __func__); 88576262Sgreen return NULL; 88660576Skris } 887221420Sdes 888221420Sdes pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); 889221420Sdes BIO_free(bio); 89076262Sgreen if (pk == NULL) { 891221420Sdes debug("%s: PEM_read_PrivateKey failed", __func__); 89276262Sgreen (void)ERR_get_error(); 89376262Sgreen } else if (pk->type == EVP_PKEY_RSA && 89492559Sdes (type == KEY_UNSPEC||type==KEY_RSA)) { 89576262Sgreen prv = key_new(KEY_UNSPEC); 89676262Sgreen prv->rsa = EVP_PKEY_get1_RSA(pk); 89776262Sgreen prv->type = KEY_RSA; 89876262Sgreen name = "rsa w/o comment"; 89976262Sgreen#ifdef DEBUG_PK 90076262Sgreen RSA_print_fp(stderr, prv->rsa, 8); 90176262Sgreen#endif 902113911Sdes if (RSA_blinding_on(prv->rsa, NULL) != 1) { 903221420Sdes error("%s: RSA_blinding_on failed", __func__); 904113911Sdes key_free(prv); 905113911Sdes prv = NULL; 906113911Sdes } 90776262Sgreen } else if (pk->type == EVP_PKEY_DSA && 90892559Sdes (type == KEY_UNSPEC||type==KEY_DSA)) { 90976262Sgreen prv = key_new(KEY_UNSPEC); 91076262Sgreen prv->dsa = EVP_PKEY_get1_DSA(pk); 91176262Sgreen prv->type = KEY_DSA; 91276262Sgreen name = "dsa w/o comment"; 91376262Sgreen#ifdef DEBUG_PK 91476262Sgreen DSA_print_fp(stderr, prv->dsa, 8); 91576262Sgreen#endif 916221420Sdes#ifdef OPENSSL_HAS_ECC 917221420Sdes } else if (pk->type == EVP_PKEY_EC && 918221420Sdes (type == KEY_UNSPEC||type==KEY_ECDSA)) { 919221420Sdes prv = key_new(KEY_UNSPEC); 920221420Sdes prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); 921221420Sdes prv->type = KEY_ECDSA; 922221420Sdes if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || 923221420Sdes key_curve_nid_to_name(prv->ecdsa_nid) == NULL || 924221420Sdes key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), 925221420Sdes EC_KEY_get0_public_key(prv->ecdsa)) != 0 || 926221420Sdes key_ec_validate_private(prv->ecdsa) != 0) { 927221420Sdes error("%s: bad ECDSA key", __func__); 928221420Sdes key_free(prv); 929221420Sdes prv = NULL; 930221420Sdes } 931221420Sdes name = "ecdsa w/o comment"; 932221420Sdes#ifdef DEBUG_PK 933221420Sdes if (prv != NULL && prv->ecdsa != NULL) 934221420Sdes key_dump_ec_key(prv->ecdsa); 935221420Sdes#endif 936221420Sdes#endif /* OPENSSL_HAS_ECC */ 93760576Skris } else { 938221420Sdes error("%s: PEM_read_PrivateKey: mismatch or " 939221420Sdes "unknown EVP_PKEY save_type %d", __func__, pk->save_type); 94060576Skris } 94176262Sgreen if (pk != NULL) 94276262Sgreen EVP_PKEY_free(pk); 94376262Sgreen if (prv != NULL && commentp) 94476262Sgreen *commentp = xstrdup(name); 94576262Sgreen debug("read PEM private key done: type %s", 94676262Sgreen prv ? key_type(prv) : "<unknown>"); 94776262Sgreen return prv; 94860576Skris} 94960576Skris 950221420SdesKey * 951221420Sdeskey_load_private_pem(int fd, int type, const char *passphrase, 952221420Sdes char **commentp) 953221420Sdes{ 954221420Sdes Buffer buffer; 955221420Sdes Key *prv; 956221420Sdes 957221420Sdes buffer_init(&buffer); 958221420Sdes if (!key_load_file(fd, NULL, &buffer)) { 959221420Sdes buffer_free(&buffer); 960221420Sdes return NULL; 961221420Sdes } 962221420Sdes prv = key_parse_private_pem(&buffer, type, passphrase, commentp); 963221420Sdes buffer_free(&buffer); 964221420Sdes return prv; 965221420Sdes} 966221420Sdes 967162856Sdesint 96876262Sgreenkey_perm_ok(int fd, const char *filename) 96960576Skris{ 97060576Skris struct stat st; 97160576Skris 97292559Sdes if (fstat(fd, &st) < 0) 97392559Sdes return 0; 97492559Sdes /* 97592559Sdes * if a key owned by the user is accessed, then we check the 97692559Sdes * permissions of the file. if the key owned by a different user, 97792559Sdes * then we don't care. 97892559Sdes */ 97998941Sdes#ifdef HAVE_CYGWIN 98098941Sdes if (check_ntsec(filename)) 98198941Sdes#endif 98292559Sdes if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { 98360576Skris error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 98460576Skris error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 98560576Skris error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 98692559Sdes error("Permissions 0%3.3o for '%s' are too open.", 987124211Sdes (u_int)st.st_mode & 0777, filename); 988226046Sdes error("It is required that your private key files are NOT accessible by others."); 98976262Sgreen error("This private key will be ignored."); 99060576Skris return 0; 99160576Skris } 99276262Sgreen return 1; 99376262Sgreen} 99476262Sgreen 995221420Sdesstatic Key * 996221420Sdeskey_parse_private_type(Buffer *blob, int type, const char *passphrase, 997221420Sdes char **commentp) 998221420Sdes{ 999262566Sdes Key *k; 1000262566Sdes 1001221420Sdes switch (type) { 1002221420Sdes case KEY_RSA1: 1003221420Sdes return key_parse_private_rsa1(blob, passphrase, commentp); 1004221420Sdes case KEY_DSA: 1005221420Sdes case KEY_ECDSA: 1006221420Sdes case KEY_RSA: 1007262566Sdes return key_parse_private_pem(blob, type, passphrase, commentp); 1008262566Sdes case KEY_ED25519: 1009262566Sdes return key_parse_private2(blob, type, passphrase, commentp); 1010221420Sdes case KEY_UNSPEC: 1011262566Sdes if ((k = key_parse_private2(blob, type, passphrase, commentp))) 1012262566Sdes return k; 1013221420Sdes return key_parse_private_pem(blob, type, passphrase, commentp); 1014221420Sdes default: 1015226046Sdes error("%s: cannot parse key type %d", __func__, type); 1016221420Sdes break; 1017221420Sdes } 1018221420Sdes return NULL; 1019221420Sdes} 1020221420Sdes 102176262SgreenKey * 102276262Sgreenkey_load_private_type(int type, const char *filename, const char *passphrase, 1023162856Sdes char **commentp, int *perm_ok) 102476262Sgreen{ 102576262Sgreen int fd; 1026221420Sdes Key *ret; 1027221420Sdes Buffer buffer; 102876262Sgreen 102976262Sgreen fd = open(filename, O_RDONLY); 1030204917Sdes if (fd < 0) { 1031204917Sdes debug("could not open key file '%s': %s", filename, 1032204917Sdes strerror(errno)); 1033204917Sdes if (perm_ok != NULL) 1034204917Sdes *perm_ok = 0; 103576262Sgreen return NULL; 1036204917Sdes } 103776262Sgreen if (!key_perm_ok(fd, filename)) { 1038162856Sdes if (perm_ok != NULL) 1039162856Sdes *perm_ok = 0; 104076262Sgreen error("bad permissions: ignore key: %s", filename); 104176262Sgreen close(fd); 104276262Sgreen return NULL; 104376262Sgreen } 1044162856Sdes if (perm_ok != NULL) 1045162856Sdes *perm_ok = 1; 1046221420Sdes 1047221420Sdes buffer_init(&buffer); 1048221420Sdes if (!key_load_file(fd, filename, &buffer)) { 1049221420Sdes buffer_free(&buffer); 105076262Sgreen close(fd); 1051221420Sdes return NULL; 105260576Skris } 1053221420Sdes close(fd); 1054221420Sdes ret = key_parse_private_type(&buffer, type, passphrase, commentp); 1055221420Sdes buffer_free(&buffer); 1056221420Sdes return ret; 105760576Skris} 105865674Skris 105976262SgreenKey * 1060226046Sdeskey_parse_private(Buffer *buffer, const char *filename, 1061226046Sdes const char *passphrase, char **commentp) 1062226046Sdes{ 1063226046Sdes Key *pub, *prv; 1064226046Sdes 1065226046Sdes /* it's a SSH v1 key if the public key part is readable */ 1066226046Sdes pub = key_parse_public_rsa1(buffer, commentp); 1067226046Sdes if (pub == NULL) { 1068226046Sdes prv = key_parse_private_type(buffer, KEY_UNSPEC, 1069226046Sdes passphrase, NULL); 1070226046Sdes /* use the filename as a comment for PEM */ 1071226046Sdes if (commentp && prv) 1072226046Sdes *commentp = xstrdup(filename); 1073226046Sdes } else { 1074226046Sdes key_free(pub); 1075226046Sdes /* key_parse_public_rsa1() has already loaded the comment */ 1076226046Sdes prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, 1077226046Sdes NULL); 1078226046Sdes } 1079226046Sdes return prv; 1080226046Sdes} 1081226046Sdes 1082226046SdesKey * 108376262Sgreenkey_load_private(const char *filename, const char *passphrase, 108476262Sgreen char **commentp) 108576262Sgreen{ 1086226046Sdes Key *prv; 1087226046Sdes Buffer buffer; 108876262Sgreen int fd; 108976262Sgreen 109076262Sgreen fd = open(filename, O_RDONLY); 1091204917Sdes if (fd < 0) { 1092204917Sdes debug("could not open key file '%s': %s", filename, 1093204917Sdes strerror(errno)); 109476262Sgreen return NULL; 1095204917Sdes } 109676262Sgreen if (!key_perm_ok(fd, filename)) { 109776262Sgreen error("bad permissions: ignore key: %s", filename); 109876262Sgreen close(fd); 109976262Sgreen return NULL; 110076262Sgreen } 1101221420Sdes 1102221420Sdes buffer_init(&buffer); 1103221420Sdes if (!key_load_file(fd, filename, &buffer)) { 1104221420Sdes buffer_free(&buffer); 1105221420Sdes close(fd); 1106221420Sdes return NULL; 1107221420Sdes } 1108221420Sdes close(fd); 1109221420Sdes 1110226046Sdes prv = key_parse_private(&buffer, filename, passphrase, commentp); 1111221420Sdes buffer_free(&buffer); 111292559Sdes return prv; 111376262Sgreen} 111476262Sgreen 111592559Sdesstatic int 111676262Sgreenkey_try_load_public(Key *k, const char *filename, char **commentp) 111765674Skris{ 111865674Skris FILE *f; 1119147005Sdes char line[SSH_MAX_PUBKEY_BYTES]; 112065674Skris char *cp; 1121147005Sdes u_long linenum = 0; 112265674Skris 112365674Skris f = fopen(filename, "r"); 112465674Skris if (f != NULL) { 1125147005Sdes while (read_keyfile_line(f, filename, line, sizeof(line), 1126147005Sdes &linenum) != -1) { 112765674Skris cp = line; 112892559Sdes switch (*cp) { 112965674Skris case '#': 113065674Skris case '\n': 113165674Skris case '\0': 113265674Skris continue; 113365674Skris } 1134226046Sdes /* Abort loading if this looks like a private key */ 1135226046Sdes if (strncmp(cp, "-----BEGIN", 10) == 0) 1136226046Sdes break; 113765674Skris /* Skip leading whitespace. */ 113865674Skris for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 113965674Skris ; 114065674Skris if (*cp) { 114176262Sgreen if (key_read(k, &cp) == 1) { 1142226046Sdes cp[strcspn(cp, "\r\n")] = '\0'; 1143226046Sdes if (commentp) { 1144226046Sdes *commentp = xstrdup(*cp ? 1145226046Sdes cp : filename); 1146226046Sdes } 114765674Skris fclose(f); 114865674Skris return 1; 114965674Skris } 115065674Skris } 115165674Skris } 115265674Skris fclose(f); 115365674Skris } 115465674Skris return 0; 115565674Skris} 115665674Skris 115776262Sgreen/* load public key from ssh v1 private or any pubkey file */ 115876262SgreenKey * 115976262Sgreenkey_load_public(const char *filename, char **commentp) 116065674Skris{ 116176262Sgreen Key *pub; 116276262Sgreen char file[MAXPATHLEN]; 116365674Skris 1164124211Sdes /* try rsa1 private key */ 116576262Sgreen pub = key_load_public_type(KEY_RSA1, filename, commentp); 116676262Sgreen if (pub != NULL) 116776262Sgreen return pub; 1168124211Sdes 1169124211Sdes /* try rsa1 public key */ 1170124211Sdes pub = key_new(KEY_RSA1); 1171124211Sdes if (key_try_load_public(pub, filename, commentp) == 1) 1172124211Sdes return pub; 1173124211Sdes key_free(pub); 1174124211Sdes 1175124211Sdes /* try ssh2 public key */ 117676262Sgreen pub = key_new(KEY_UNSPEC); 117776262Sgreen if (key_try_load_public(pub, filename, commentp) == 1) 117876262Sgreen return pub; 117976262Sgreen if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && 118076262Sgreen (strlcat(file, ".pub", sizeof file) < sizeof(file)) && 118176262Sgreen (key_try_load_public(pub, file, commentp) == 1)) 118276262Sgreen return pub; 118376262Sgreen key_free(pub); 118476262Sgreen return NULL; 118565674Skris} 1186204917Sdes 1187215116Sdes/* Load the certificate associated with the named private key */ 1188215116SdesKey * 1189215116Sdeskey_load_cert(const char *filename) 1190215116Sdes{ 1191215116Sdes Key *pub; 1192215116Sdes char *file; 1193215116Sdes 1194215116Sdes pub = key_new(KEY_UNSPEC); 1195215116Sdes xasprintf(&file, "%s-cert.pub", filename); 1196215116Sdes if (key_try_load_public(pub, file, NULL) == 1) { 1197255767Sdes free(file); 1198215116Sdes return pub; 1199215116Sdes } 1200255767Sdes free(file); 1201215116Sdes key_free(pub); 1202215116Sdes return NULL; 1203215116Sdes} 1204215116Sdes 1205215116Sdes/* Load private key and certificate */ 1206215116SdesKey * 1207215116Sdeskey_load_private_cert(int type, const char *filename, const char *passphrase, 1208215116Sdes int *perm_ok) 1209215116Sdes{ 1210215116Sdes Key *key, *pub; 1211215116Sdes 1212215116Sdes switch (type) { 1213215116Sdes case KEY_RSA: 1214215116Sdes case KEY_DSA: 1215221420Sdes case KEY_ECDSA: 1216262566Sdes case KEY_ED25519: 1217215116Sdes break; 1218215116Sdes default: 1219215116Sdes error("%s: unsupported key type", __func__); 1220215116Sdes return NULL; 1221215116Sdes } 1222215116Sdes 1223215116Sdes if ((key = key_load_private_type(type, filename, 1224215116Sdes passphrase, NULL, perm_ok)) == NULL) 1225215116Sdes return NULL; 1226215116Sdes 1227215116Sdes if ((pub = key_load_cert(filename)) == NULL) { 1228215116Sdes key_free(key); 1229215116Sdes return NULL; 1230215116Sdes } 1231215116Sdes 1232215116Sdes /* Make sure the private key matches the certificate */ 1233215116Sdes if (key_equal_public(key, pub) == 0) { 1234215116Sdes error("%s: certificate does not match private key %s", 1235215116Sdes __func__, filename); 1236215116Sdes } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { 1237215116Sdes error("%s: key_to_certified failed", __func__); 1238215116Sdes } else { 1239215116Sdes key_cert_copy(pub, key); 1240215116Sdes key_free(pub); 1241215116Sdes return key; 1242215116Sdes } 1243215116Sdes 1244215116Sdes key_free(key); 1245215116Sdes key_free(pub); 1246215116Sdes return NULL; 1247215116Sdes} 1248215116Sdes 1249204917Sdes/* 1250204917Sdes * Returns 1 if the specified "key" is listed in the file "filename", 1251204917Sdes * 0 if the key is not listed or -1 on error. 1252204917Sdes * If strict_type is set then the key type must match exactly, 1253204917Sdes * otherwise a comparison that ignores certficiate data is performed. 1254204917Sdes */ 1255204917Sdesint 1256204917Sdeskey_in_file(Key *key, const char *filename, int strict_type) 1257204917Sdes{ 1258204917Sdes FILE *f; 1259204917Sdes char line[SSH_MAX_PUBKEY_BYTES]; 1260204917Sdes char *cp; 1261204917Sdes u_long linenum = 0; 1262204917Sdes int ret = 0; 1263204917Sdes Key *pub; 1264204917Sdes int (*key_compare)(const Key *, const Key *) = strict_type ? 1265204917Sdes key_equal : key_equal_public; 1266204917Sdes 1267204917Sdes if ((f = fopen(filename, "r")) == NULL) { 1268204917Sdes if (errno == ENOENT) { 1269204917Sdes debug("%s: keyfile \"%s\" missing", __func__, filename); 1270204917Sdes return 0; 1271204917Sdes } else { 1272204917Sdes error("%s: could not open keyfile \"%s\": %s", __func__, 1273204917Sdes filename, strerror(errno)); 1274204917Sdes return -1; 1275204917Sdes } 1276204917Sdes } 1277204917Sdes 1278204917Sdes while (read_keyfile_line(f, filename, line, sizeof(line), 1279204917Sdes &linenum) != -1) { 1280204917Sdes cp = line; 1281204917Sdes 1282204917Sdes /* Skip leading whitespace. */ 1283204917Sdes for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 1284204917Sdes ; 1285204917Sdes 1286204917Sdes /* Skip comments and empty lines */ 1287204917Sdes switch (*cp) { 1288204917Sdes case '#': 1289204917Sdes case '\n': 1290204917Sdes case '\0': 1291204917Sdes continue; 1292204917Sdes } 1293204917Sdes 1294204917Sdes pub = key_new(KEY_UNSPEC); 1295204917Sdes if (key_read(pub, &cp) != 1) { 1296204917Sdes key_free(pub); 1297204917Sdes continue; 1298204917Sdes } 1299204917Sdes if (key_compare(key, pub)) { 1300204917Sdes ret = 1; 1301204917Sdes key_free(pub); 1302204917Sdes break; 1303204917Sdes } 1304204917Sdes key_free(pub); 1305204917Sdes } 1306204917Sdes fclose(f); 1307204917Sdes return ret; 1308204917Sdes} 1309