1*f7167e0eSDag-Erling Smørgrav /* $OpenBSD: authfile.c,v 1.101 2013/12/29 04:35:50 djm Exp $ */ 2511b41d2SMark Murray /* 3511b41d2SMark Murray * Author: Tatu Ylonen <ylo@cs.hut.fi> 4511b41d2SMark Murray * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5511b41d2SMark Murray * All rights reserved 6511b41d2SMark Murray * This file contains functions for reading and writing identity files, and 7511b41d2SMark Murray * for reading the passphrase from the user. 8511b41d2SMark Murray * 9c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 10c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 11c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 12c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 13c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 14c2d3a559SKris Kennaway * 15c2d3a559SKris Kennaway * 16*f7167e0eSDag-Erling Smørgrav * Copyright (c) 2000, 2013 Markus Friedl. All rights reserved. 17c2d3a559SKris Kennaway * 18c2d3a559SKris Kennaway * Redistribution and use in source and binary forms, with or without 19c2d3a559SKris Kennaway * modification, are permitted provided that the following conditions 20c2d3a559SKris Kennaway * are met: 21c2d3a559SKris Kennaway * 1. Redistributions of source code must retain the above copyright 22c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer. 23c2d3a559SKris Kennaway * 2. Redistributions in binary form must reproduce the above copyright 24c2d3a559SKris Kennaway * notice, this list of conditions and the following disclaimer in the 25c2d3a559SKris Kennaway * documentation and/or other materials provided with the distribution. 26c2d3a559SKris Kennaway * 27c2d3a559SKris Kennaway * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28c2d3a559SKris Kennaway * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29c2d3a559SKris Kennaway * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30c2d3a559SKris Kennaway * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31c2d3a559SKris Kennaway * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32c2d3a559SKris Kennaway * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33c2d3a559SKris Kennaway * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34c2d3a559SKris Kennaway * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35c2d3a559SKris Kennaway * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36c2d3a559SKris Kennaway * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37511b41d2SMark Murray */ 38511b41d2SMark Murray 39511b41d2SMark Murray #include "includes.h" 40333ee039SDag-Erling Smørgrav 41333ee039SDag-Erling Smørgrav #include <sys/types.h> 42333ee039SDag-Erling Smørgrav #include <sys/stat.h> 43333ee039SDag-Erling Smørgrav #include <sys/param.h> 44333ee039SDag-Erling Smørgrav #include <sys/uio.h> 45511b41d2SMark Murray 46ca3176e7SBrian Feldman #include <openssl/err.h> 47e8aafc91SKris Kennaway #include <openssl/evp.h> 48ca3176e7SBrian Feldman #include <openssl/pem.h> 49e8aafc91SKris Kennaway 50b15c8340SDag-Erling Smørgrav /* compatibility with old or broken OpenSSL versions */ 51b15c8340SDag-Erling Smørgrav #include "openbsd-compat/openssl-compat.h" 52b15c8340SDag-Erling Smørgrav 53*f7167e0eSDag-Erling Smørgrav #include "crypto_api.h" 54*f7167e0eSDag-Erling Smørgrav 55333ee039SDag-Erling Smørgrav #include <errno.h> 56333ee039SDag-Erling Smørgrav #include <fcntl.h> 57333ee039SDag-Erling Smørgrav #include <stdarg.h> 58333ee039SDag-Erling Smørgrav #include <stdio.h> 59333ee039SDag-Erling Smørgrav #include <stdlib.h> 60333ee039SDag-Erling Smørgrav #include <string.h> 61333ee039SDag-Erling Smørgrav #include <unistd.h> 62333ee039SDag-Erling Smørgrav 63*f7167e0eSDag-Erling Smørgrav #ifdef HAVE_UTIL_H 64*f7167e0eSDag-Erling Smørgrav #include <util.h> 65*f7167e0eSDag-Erling Smørgrav #endif 66*f7167e0eSDag-Erling Smørgrav 67511b41d2SMark Murray #include "xmalloc.h" 68333ee039SDag-Erling Smørgrav #include "cipher.h" 69511b41d2SMark Murray #include "buffer.h" 70e8aafc91SKris Kennaway #include "key.h" 71ca3176e7SBrian Feldman #include "ssh.h" 72ca3176e7SBrian Feldman #include "log.h" 73ca3176e7SBrian Feldman #include "authfile.h" 74af12a3e7SDag-Erling Smørgrav #include "rsa.h" 75aa49c926SDag-Erling Smørgrav #include "misc.h" 76d4ecd108SDag-Erling Smørgrav #include "atomicio.h" 77*f7167e0eSDag-Erling Smørgrav #include "uuencode.h" 78*f7167e0eSDag-Erling Smørgrav 79*f7167e0eSDag-Erling Smørgrav /* openssh private key file format */ 80*f7167e0eSDag-Erling Smørgrav #define MARK_BEGIN "-----BEGIN OPENSSH PRIVATE KEY-----\n" 81*f7167e0eSDag-Erling Smørgrav #define MARK_END "-----END OPENSSH PRIVATE KEY-----\n" 82*f7167e0eSDag-Erling Smørgrav #define KDFNAME "bcrypt" 83*f7167e0eSDag-Erling Smørgrav #define AUTH_MAGIC "openssh-key-v1" 84*f7167e0eSDag-Erling Smørgrav #define SALT_LEN 16 85*f7167e0eSDag-Erling Smørgrav #define DEFAULT_CIPHERNAME "aes256-cbc" 86*f7167e0eSDag-Erling Smørgrav #define DEFAULT_ROUNDS 16 87511b41d2SMark Murray 88e146993eSDag-Erling Smørgrav #define MAX_KEY_FILE_SIZE (1024 * 1024) 89e146993eSDag-Erling Smørgrav 90ca3176e7SBrian Feldman /* Version identification string for SSH v1 identity files. */ 91ca3176e7SBrian Feldman static const char authfile_id_string[] = 92ca3176e7SBrian Feldman "SSH PRIVATE KEY FILE FORMAT 1.1\n"; 93511b41d2SMark Murray 94*f7167e0eSDag-Erling Smørgrav static int 95*f7167e0eSDag-Erling Smørgrav key_private_to_blob2(Key *prv, Buffer *blob, const char *passphrase, 96*f7167e0eSDag-Erling Smørgrav const char *comment, const char *ciphername, int rounds) 97*f7167e0eSDag-Erling Smørgrav { 98*f7167e0eSDag-Erling Smørgrav u_char *key, *cp, salt[SALT_LEN]; 99*f7167e0eSDag-Erling Smørgrav size_t keylen, ivlen, blocksize, authlen; 100*f7167e0eSDag-Erling Smørgrav u_int len, check; 101*f7167e0eSDag-Erling Smørgrav int i, n; 102*f7167e0eSDag-Erling Smørgrav const Cipher *c; 103*f7167e0eSDag-Erling Smørgrav Buffer encoded, b, kdf; 104*f7167e0eSDag-Erling Smørgrav CipherContext ctx; 105*f7167e0eSDag-Erling Smørgrav const char *kdfname = KDFNAME; 106*f7167e0eSDag-Erling Smørgrav 107*f7167e0eSDag-Erling Smørgrav if (rounds <= 0) 108*f7167e0eSDag-Erling Smørgrav rounds = DEFAULT_ROUNDS; 109*f7167e0eSDag-Erling Smørgrav if (passphrase == NULL || !strlen(passphrase)) { 110*f7167e0eSDag-Erling Smørgrav ciphername = "none"; 111*f7167e0eSDag-Erling Smørgrav kdfname = "none"; 112*f7167e0eSDag-Erling Smørgrav } else if (ciphername == NULL) 113*f7167e0eSDag-Erling Smørgrav ciphername = DEFAULT_CIPHERNAME; 114*f7167e0eSDag-Erling Smørgrav else if (cipher_number(ciphername) != SSH_CIPHER_SSH2) 115*f7167e0eSDag-Erling Smørgrav fatal("invalid cipher"); 116*f7167e0eSDag-Erling Smørgrav 117*f7167e0eSDag-Erling Smørgrav if ((c = cipher_by_name(ciphername)) == NULL) 118*f7167e0eSDag-Erling Smørgrav fatal("unknown cipher name"); 119*f7167e0eSDag-Erling Smørgrav buffer_init(&kdf); 120*f7167e0eSDag-Erling Smørgrav blocksize = cipher_blocksize(c); 121*f7167e0eSDag-Erling Smørgrav keylen = cipher_keylen(c); 122*f7167e0eSDag-Erling Smørgrav ivlen = cipher_ivlen(c); 123*f7167e0eSDag-Erling Smørgrav authlen = cipher_authlen(c); 124*f7167e0eSDag-Erling Smørgrav key = xcalloc(1, keylen + ivlen); 125*f7167e0eSDag-Erling Smørgrav if (strcmp(kdfname, "none") != 0) { 126*f7167e0eSDag-Erling Smørgrav arc4random_buf(salt, SALT_LEN); 127*f7167e0eSDag-Erling Smørgrav if (bcrypt_pbkdf(passphrase, strlen(passphrase), 128*f7167e0eSDag-Erling Smørgrav salt, SALT_LEN, key, keylen + ivlen, rounds) < 0) 129*f7167e0eSDag-Erling Smørgrav fatal("bcrypt_pbkdf failed"); 130*f7167e0eSDag-Erling Smørgrav buffer_put_string(&kdf, salt, SALT_LEN); 131*f7167e0eSDag-Erling Smørgrav buffer_put_int(&kdf, rounds); 132*f7167e0eSDag-Erling Smørgrav } 133*f7167e0eSDag-Erling Smørgrav cipher_init(&ctx, c, key, keylen, key + keylen , ivlen, 1); 134*f7167e0eSDag-Erling Smørgrav memset(key, 0, keylen + ivlen); 135*f7167e0eSDag-Erling Smørgrav free(key); 136*f7167e0eSDag-Erling Smørgrav 137*f7167e0eSDag-Erling Smørgrav buffer_init(&encoded); 138*f7167e0eSDag-Erling Smørgrav buffer_append(&encoded, AUTH_MAGIC, sizeof(AUTH_MAGIC)); 139*f7167e0eSDag-Erling Smørgrav buffer_put_cstring(&encoded, ciphername); 140*f7167e0eSDag-Erling Smørgrav buffer_put_cstring(&encoded, kdfname); 141*f7167e0eSDag-Erling Smørgrav buffer_put_string(&encoded, buffer_ptr(&kdf), buffer_len(&kdf)); 142*f7167e0eSDag-Erling Smørgrav buffer_put_int(&encoded, 1); /* number of keys */ 143*f7167e0eSDag-Erling Smørgrav key_to_blob(prv, &cp, &len); /* public key */ 144*f7167e0eSDag-Erling Smørgrav buffer_put_string(&encoded, cp, len); 145*f7167e0eSDag-Erling Smørgrav 146*f7167e0eSDag-Erling Smørgrav memset(cp, 0, len); 147*f7167e0eSDag-Erling Smørgrav free(cp); 148*f7167e0eSDag-Erling Smørgrav 149*f7167e0eSDag-Erling Smørgrav buffer_free(&kdf); 150*f7167e0eSDag-Erling Smørgrav 151*f7167e0eSDag-Erling Smørgrav /* set up the buffer that will be encrypted */ 152*f7167e0eSDag-Erling Smørgrav buffer_init(&b); 153*f7167e0eSDag-Erling Smørgrav 154*f7167e0eSDag-Erling Smørgrav /* Random check bytes */ 155*f7167e0eSDag-Erling Smørgrav check = arc4random(); 156*f7167e0eSDag-Erling Smørgrav buffer_put_int(&b, check); 157*f7167e0eSDag-Erling Smørgrav buffer_put_int(&b, check); 158*f7167e0eSDag-Erling Smørgrav 159*f7167e0eSDag-Erling Smørgrav /* append private key and comment*/ 160*f7167e0eSDag-Erling Smørgrav key_private_serialize(prv, &b); 161*f7167e0eSDag-Erling Smørgrav buffer_put_cstring(&b, comment); 162*f7167e0eSDag-Erling Smørgrav 163*f7167e0eSDag-Erling Smørgrav /* padding */ 164*f7167e0eSDag-Erling Smørgrav i = 0; 165*f7167e0eSDag-Erling Smørgrav while (buffer_len(&b) % blocksize) 166*f7167e0eSDag-Erling Smørgrav buffer_put_char(&b, ++i & 0xff); 167*f7167e0eSDag-Erling Smørgrav 168*f7167e0eSDag-Erling Smørgrav /* length */ 169*f7167e0eSDag-Erling Smørgrav buffer_put_int(&encoded, buffer_len(&b)); 170*f7167e0eSDag-Erling Smørgrav 171*f7167e0eSDag-Erling Smørgrav /* encrypt */ 172*f7167e0eSDag-Erling Smørgrav cp = buffer_append_space(&encoded, buffer_len(&b) + authlen); 173*f7167e0eSDag-Erling Smørgrav if (cipher_crypt(&ctx, 0, cp, buffer_ptr(&b), buffer_len(&b), 0, 174*f7167e0eSDag-Erling Smørgrav authlen) != 0) 175*f7167e0eSDag-Erling Smørgrav fatal("%s: cipher_crypt failed", __func__); 176*f7167e0eSDag-Erling Smørgrav buffer_free(&b); 177*f7167e0eSDag-Erling Smørgrav cipher_cleanup(&ctx); 178*f7167e0eSDag-Erling Smørgrav 179*f7167e0eSDag-Erling Smørgrav /* uuencode */ 180*f7167e0eSDag-Erling Smørgrav len = 2 * buffer_len(&encoded); 181*f7167e0eSDag-Erling Smørgrav cp = xmalloc(len); 182*f7167e0eSDag-Erling Smørgrav n = uuencode(buffer_ptr(&encoded), buffer_len(&encoded), 183*f7167e0eSDag-Erling Smørgrav (char *)cp, len); 184*f7167e0eSDag-Erling Smørgrav if (n < 0) 185*f7167e0eSDag-Erling Smørgrav fatal("%s: uuencode", __func__); 186*f7167e0eSDag-Erling Smørgrav 187*f7167e0eSDag-Erling Smørgrav buffer_clear(blob); 188*f7167e0eSDag-Erling Smørgrav buffer_append(blob, MARK_BEGIN, sizeof(MARK_BEGIN) - 1); 189*f7167e0eSDag-Erling Smørgrav for (i = 0; i < n; i++) { 190*f7167e0eSDag-Erling Smørgrav buffer_put_char(blob, cp[i]); 191*f7167e0eSDag-Erling Smørgrav if (i % 70 == 69) 192*f7167e0eSDag-Erling Smørgrav buffer_put_char(blob, '\n'); 193*f7167e0eSDag-Erling Smørgrav } 194*f7167e0eSDag-Erling Smørgrav if (i % 70 != 69) 195*f7167e0eSDag-Erling Smørgrav buffer_put_char(blob, '\n'); 196*f7167e0eSDag-Erling Smørgrav buffer_append(blob, MARK_END, sizeof(MARK_END) - 1); 197*f7167e0eSDag-Erling Smørgrav free(cp); 198*f7167e0eSDag-Erling Smørgrav 199*f7167e0eSDag-Erling Smørgrav return buffer_len(blob); 200*f7167e0eSDag-Erling Smørgrav } 201*f7167e0eSDag-Erling Smørgrav 202*f7167e0eSDag-Erling Smørgrav static Key * 203*f7167e0eSDag-Erling Smørgrav key_parse_private2(Buffer *blob, int type, const char *passphrase, 204*f7167e0eSDag-Erling Smørgrav char **commentp) 205*f7167e0eSDag-Erling Smørgrav { 206*f7167e0eSDag-Erling Smørgrav u_char *key = NULL, *cp, *salt = NULL, pad, last; 207*f7167e0eSDag-Erling Smørgrav char *comment = NULL, *ciphername = NULL, *kdfname = NULL, *kdfp; 208*f7167e0eSDag-Erling Smørgrav u_int keylen = 0, ivlen, blocksize, slen, klen, len, rounds, nkeys; 209*f7167e0eSDag-Erling Smørgrav u_int check1, check2, m1len, m2len; 210*f7167e0eSDag-Erling Smørgrav size_t authlen; 211*f7167e0eSDag-Erling Smørgrav const Cipher *c; 212*f7167e0eSDag-Erling Smørgrav Buffer b, encoded, copy, kdf; 213*f7167e0eSDag-Erling Smørgrav CipherContext ctx; 214*f7167e0eSDag-Erling Smørgrav Key *k = NULL; 215*f7167e0eSDag-Erling Smørgrav int dlen, ret, i; 216*f7167e0eSDag-Erling Smørgrav 217*f7167e0eSDag-Erling Smørgrav buffer_init(&b); 218*f7167e0eSDag-Erling Smørgrav buffer_init(&kdf); 219*f7167e0eSDag-Erling Smørgrav buffer_init(&encoded); 220*f7167e0eSDag-Erling Smørgrav buffer_init(©); 221*f7167e0eSDag-Erling Smørgrav 222*f7167e0eSDag-Erling Smørgrav /* uudecode */ 223*f7167e0eSDag-Erling Smørgrav m1len = sizeof(MARK_BEGIN) - 1; 224*f7167e0eSDag-Erling Smørgrav m2len = sizeof(MARK_END) - 1; 225*f7167e0eSDag-Erling Smørgrav cp = buffer_ptr(blob); 226*f7167e0eSDag-Erling Smørgrav len = buffer_len(blob); 227*f7167e0eSDag-Erling Smørgrav if (len < m1len || memcmp(cp, MARK_BEGIN, m1len)) { 228*f7167e0eSDag-Erling Smørgrav debug("%s: missing begin marker", __func__); 229*f7167e0eSDag-Erling Smørgrav goto out; 230*f7167e0eSDag-Erling Smørgrav } 231*f7167e0eSDag-Erling Smørgrav cp += m1len; 232*f7167e0eSDag-Erling Smørgrav len -= m1len; 233*f7167e0eSDag-Erling Smørgrav while (len) { 234*f7167e0eSDag-Erling Smørgrav if (*cp != '\n' && *cp != '\r') 235*f7167e0eSDag-Erling Smørgrav buffer_put_char(&encoded, *cp); 236*f7167e0eSDag-Erling Smørgrav last = *cp; 237*f7167e0eSDag-Erling Smørgrav len--; 238*f7167e0eSDag-Erling Smørgrav cp++; 239*f7167e0eSDag-Erling Smørgrav if (last == '\n') { 240*f7167e0eSDag-Erling Smørgrav if (len >= m2len && !memcmp(cp, MARK_END, m2len)) { 241*f7167e0eSDag-Erling Smørgrav buffer_put_char(&encoded, '\0'); 242*f7167e0eSDag-Erling Smørgrav break; 243*f7167e0eSDag-Erling Smørgrav } 244*f7167e0eSDag-Erling Smørgrav } 245*f7167e0eSDag-Erling Smørgrav } 246*f7167e0eSDag-Erling Smørgrav if (!len) { 247*f7167e0eSDag-Erling Smørgrav debug("%s: no end marker", __func__); 248*f7167e0eSDag-Erling Smørgrav goto out; 249*f7167e0eSDag-Erling Smørgrav } 250*f7167e0eSDag-Erling Smørgrav len = buffer_len(&encoded); 251*f7167e0eSDag-Erling Smørgrav if ((cp = buffer_append_space(©, len)) == NULL) { 252*f7167e0eSDag-Erling Smørgrav error("%s: buffer_append_space", __func__); 253*f7167e0eSDag-Erling Smørgrav goto out; 254*f7167e0eSDag-Erling Smørgrav } 255*f7167e0eSDag-Erling Smørgrav if ((dlen = uudecode(buffer_ptr(&encoded), cp, len)) < 0) { 256*f7167e0eSDag-Erling Smørgrav error("%s: uudecode failed", __func__); 257*f7167e0eSDag-Erling Smørgrav goto out; 258*f7167e0eSDag-Erling Smørgrav } 259*f7167e0eSDag-Erling Smørgrav if ((u_int)dlen > len) { 260*f7167e0eSDag-Erling Smørgrav error("%s: crazy uudecode length %d > %u", __func__, dlen, len); 261*f7167e0eSDag-Erling Smørgrav goto out; 262*f7167e0eSDag-Erling Smørgrav } 263*f7167e0eSDag-Erling Smørgrav buffer_consume_end(©, len - dlen); 264*f7167e0eSDag-Erling Smørgrav if (buffer_len(©) < sizeof(AUTH_MAGIC) || 265*f7167e0eSDag-Erling Smørgrav memcmp(buffer_ptr(©), AUTH_MAGIC, sizeof(AUTH_MAGIC))) { 266*f7167e0eSDag-Erling Smørgrav error("%s: bad magic", __func__); 267*f7167e0eSDag-Erling Smørgrav goto out; 268*f7167e0eSDag-Erling Smørgrav } 269*f7167e0eSDag-Erling Smørgrav buffer_consume(©, sizeof(AUTH_MAGIC)); 270*f7167e0eSDag-Erling Smørgrav 271*f7167e0eSDag-Erling Smørgrav ciphername = buffer_get_cstring_ret(©, NULL); 272*f7167e0eSDag-Erling Smørgrav if (ciphername == NULL || 273*f7167e0eSDag-Erling Smørgrav (c = cipher_by_name(ciphername)) == NULL) { 274*f7167e0eSDag-Erling Smørgrav error("%s: unknown cipher name", __func__); 275*f7167e0eSDag-Erling Smørgrav goto out; 276*f7167e0eSDag-Erling Smørgrav } 277*f7167e0eSDag-Erling Smørgrav if ((passphrase == NULL || !strlen(passphrase)) && 278*f7167e0eSDag-Erling Smørgrav strcmp(ciphername, "none") != 0) { 279*f7167e0eSDag-Erling Smørgrav /* passphrase required */ 280*f7167e0eSDag-Erling Smørgrav goto out; 281*f7167e0eSDag-Erling Smørgrav } 282*f7167e0eSDag-Erling Smørgrav kdfname = buffer_get_cstring_ret(©, NULL); 283*f7167e0eSDag-Erling Smørgrav if (kdfname == NULL || 284*f7167e0eSDag-Erling Smørgrav (!strcmp(kdfname, "none") && !strcmp(kdfname, "bcrypt"))) { 285*f7167e0eSDag-Erling Smørgrav error("%s: unknown kdf name", __func__); 286*f7167e0eSDag-Erling Smørgrav goto out; 287*f7167e0eSDag-Erling Smørgrav } 288*f7167e0eSDag-Erling Smørgrav if (!strcmp(kdfname, "none") && strcmp(ciphername, "none") != 0) { 289*f7167e0eSDag-Erling Smørgrav error("%s: cipher %s requires kdf", __func__, ciphername); 290*f7167e0eSDag-Erling Smørgrav goto out; 291*f7167e0eSDag-Erling Smørgrav } 292*f7167e0eSDag-Erling Smørgrav /* kdf options */ 293*f7167e0eSDag-Erling Smørgrav kdfp = buffer_get_string_ptr_ret(©, &klen); 294*f7167e0eSDag-Erling Smørgrav if (kdfp == NULL) { 295*f7167e0eSDag-Erling Smørgrav error("%s: kdf options not set", __func__); 296*f7167e0eSDag-Erling Smørgrav goto out; 297*f7167e0eSDag-Erling Smørgrav } 298*f7167e0eSDag-Erling Smørgrav if (klen > 0) { 299*f7167e0eSDag-Erling Smørgrav if ((cp = buffer_append_space(&kdf, klen)) == NULL) { 300*f7167e0eSDag-Erling Smørgrav error("%s: kdf alloc failed", __func__); 301*f7167e0eSDag-Erling Smørgrav goto out; 302*f7167e0eSDag-Erling Smørgrav } 303*f7167e0eSDag-Erling Smørgrav memcpy(cp, kdfp, klen); 304*f7167e0eSDag-Erling Smørgrav } 305*f7167e0eSDag-Erling Smørgrav /* number of keys */ 306*f7167e0eSDag-Erling Smørgrav if (buffer_get_int_ret(&nkeys, ©) < 0) { 307*f7167e0eSDag-Erling Smørgrav error("%s: key counter missing", __func__); 308*f7167e0eSDag-Erling Smørgrav goto out; 309*f7167e0eSDag-Erling Smørgrav } 310*f7167e0eSDag-Erling Smørgrav if (nkeys != 1) { 311*f7167e0eSDag-Erling Smørgrav error("%s: only one key supported", __func__); 312*f7167e0eSDag-Erling Smørgrav goto out; 313*f7167e0eSDag-Erling Smørgrav } 314*f7167e0eSDag-Erling Smørgrav /* pubkey */ 315*f7167e0eSDag-Erling Smørgrav if ((cp = buffer_get_string_ret(©, &len)) == NULL) { 316*f7167e0eSDag-Erling Smørgrav error("%s: pubkey not found", __func__); 317*f7167e0eSDag-Erling Smørgrav goto out; 318*f7167e0eSDag-Erling Smørgrav } 319*f7167e0eSDag-Erling Smørgrav free(cp); /* XXX check pubkey against decrypted private key */ 320*f7167e0eSDag-Erling Smørgrav 321*f7167e0eSDag-Erling Smørgrav /* size of encrypted key blob */ 322*f7167e0eSDag-Erling Smørgrav len = buffer_get_int(©); 323*f7167e0eSDag-Erling Smørgrav blocksize = cipher_blocksize(c); 324*f7167e0eSDag-Erling Smørgrav authlen = cipher_authlen(c); 325*f7167e0eSDag-Erling Smørgrav if (len < blocksize) { 326*f7167e0eSDag-Erling Smørgrav error("%s: encrypted data too small", __func__); 327*f7167e0eSDag-Erling Smørgrav goto out; 328*f7167e0eSDag-Erling Smørgrav } 329*f7167e0eSDag-Erling Smørgrav if (len % blocksize) { 330*f7167e0eSDag-Erling Smørgrav error("%s: length not multiple of blocksize", __func__); 331*f7167e0eSDag-Erling Smørgrav goto out; 332*f7167e0eSDag-Erling Smørgrav } 333*f7167e0eSDag-Erling Smørgrav 334*f7167e0eSDag-Erling Smørgrav /* setup key */ 335*f7167e0eSDag-Erling Smørgrav keylen = cipher_keylen(c); 336*f7167e0eSDag-Erling Smørgrav ivlen = cipher_ivlen(c); 337*f7167e0eSDag-Erling Smørgrav key = xcalloc(1, keylen + ivlen); 338*f7167e0eSDag-Erling Smørgrav if (!strcmp(kdfname, "bcrypt")) { 339*f7167e0eSDag-Erling Smørgrav if ((salt = buffer_get_string_ret(&kdf, &slen)) == NULL) { 340*f7167e0eSDag-Erling Smørgrav error("%s: salt not set", __func__); 341*f7167e0eSDag-Erling Smørgrav goto out; 342*f7167e0eSDag-Erling Smørgrav } 343*f7167e0eSDag-Erling Smørgrav if (buffer_get_int_ret(&rounds, &kdf) < 0) { 344*f7167e0eSDag-Erling Smørgrav error("%s: rounds not set", __func__); 345*f7167e0eSDag-Erling Smørgrav goto out; 346*f7167e0eSDag-Erling Smørgrav } 347*f7167e0eSDag-Erling Smørgrav if (bcrypt_pbkdf(passphrase, strlen(passphrase), salt, slen, 348*f7167e0eSDag-Erling Smørgrav key, keylen + ivlen, rounds) < 0) { 349*f7167e0eSDag-Erling Smørgrav error("%s: bcrypt_pbkdf failed", __func__); 350*f7167e0eSDag-Erling Smørgrav goto out; 351*f7167e0eSDag-Erling Smørgrav } 352*f7167e0eSDag-Erling Smørgrav } 353*f7167e0eSDag-Erling Smørgrav 354*f7167e0eSDag-Erling Smørgrav cp = buffer_append_space(&b, len); 355*f7167e0eSDag-Erling Smørgrav cipher_init(&ctx, c, key, keylen, key + keylen, ivlen, 0); 356*f7167e0eSDag-Erling Smørgrav ret = cipher_crypt(&ctx, 0, cp, buffer_ptr(©), len, 0, authlen); 357*f7167e0eSDag-Erling Smørgrav cipher_cleanup(&ctx); 358*f7167e0eSDag-Erling Smørgrav buffer_consume(©, len); 359*f7167e0eSDag-Erling Smørgrav 360*f7167e0eSDag-Erling Smørgrav /* fail silently on decryption errors */ 361*f7167e0eSDag-Erling Smørgrav if (ret != 0) { 362*f7167e0eSDag-Erling Smørgrav debug("%s: decrypt failed", __func__); 363*f7167e0eSDag-Erling Smørgrav goto out; 364*f7167e0eSDag-Erling Smørgrav } 365*f7167e0eSDag-Erling Smørgrav 366*f7167e0eSDag-Erling Smørgrav if (buffer_len(©) != 0) { 367*f7167e0eSDag-Erling Smørgrav error("%s: key blob has trailing data (len = %u)", __func__, 368*f7167e0eSDag-Erling Smørgrav buffer_len(©)); 369*f7167e0eSDag-Erling Smørgrav goto out; 370*f7167e0eSDag-Erling Smørgrav } 371*f7167e0eSDag-Erling Smørgrav 372*f7167e0eSDag-Erling Smørgrav /* check bytes */ 373*f7167e0eSDag-Erling Smørgrav if (buffer_get_int_ret(&check1, &b) < 0 || 374*f7167e0eSDag-Erling Smørgrav buffer_get_int_ret(&check2, &b) < 0) { 375*f7167e0eSDag-Erling Smørgrav error("check bytes missing"); 376*f7167e0eSDag-Erling Smørgrav goto out; 377*f7167e0eSDag-Erling Smørgrav } 378*f7167e0eSDag-Erling Smørgrav if (check1 != check2) { 379*f7167e0eSDag-Erling Smørgrav debug("%s: decrypt failed: 0x%08x != 0x%08x", __func__, 380*f7167e0eSDag-Erling Smørgrav check1, check2); 381*f7167e0eSDag-Erling Smørgrav goto out; 382*f7167e0eSDag-Erling Smørgrav } 383*f7167e0eSDag-Erling Smørgrav 384*f7167e0eSDag-Erling Smørgrav k = key_private_deserialize(&b); 385*f7167e0eSDag-Erling Smørgrav 386*f7167e0eSDag-Erling Smørgrav /* comment */ 387*f7167e0eSDag-Erling Smørgrav comment = buffer_get_cstring_ret(&b, NULL); 388*f7167e0eSDag-Erling Smørgrav 389*f7167e0eSDag-Erling Smørgrav i = 0; 390*f7167e0eSDag-Erling Smørgrav while (buffer_len(&b)) { 391*f7167e0eSDag-Erling Smørgrav if (buffer_get_char_ret(&pad, &b) == -1 || 392*f7167e0eSDag-Erling Smørgrav pad != (++i & 0xff)) { 393*f7167e0eSDag-Erling Smørgrav error("%s: bad padding", __func__); 394*f7167e0eSDag-Erling Smørgrav key_free(k); 395*f7167e0eSDag-Erling Smørgrav k = NULL; 396*f7167e0eSDag-Erling Smørgrav goto out; 397*f7167e0eSDag-Erling Smørgrav } 398*f7167e0eSDag-Erling Smørgrav } 399*f7167e0eSDag-Erling Smørgrav 400*f7167e0eSDag-Erling Smørgrav if (k && commentp) { 401*f7167e0eSDag-Erling Smørgrav *commentp = comment; 402*f7167e0eSDag-Erling Smørgrav comment = NULL; 403*f7167e0eSDag-Erling Smørgrav } 404*f7167e0eSDag-Erling Smørgrav 405*f7167e0eSDag-Erling Smørgrav /* XXX decode pubkey and check against private */ 406*f7167e0eSDag-Erling Smørgrav out: 407*f7167e0eSDag-Erling Smørgrav free(ciphername); 408*f7167e0eSDag-Erling Smørgrav free(kdfname); 409*f7167e0eSDag-Erling Smørgrav free(salt); 410*f7167e0eSDag-Erling Smørgrav free(comment); 411*f7167e0eSDag-Erling Smørgrav if (key) 412*f7167e0eSDag-Erling Smørgrav memset(key, 0, keylen + ivlen); 413*f7167e0eSDag-Erling Smørgrav free(key); 414*f7167e0eSDag-Erling Smørgrav buffer_free(&encoded); 415*f7167e0eSDag-Erling Smørgrav buffer_free(©); 416*f7167e0eSDag-Erling Smørgrav buffer_free(&kdf); 417*f7167e0eSDag-Erling Smørgrav buffer_free(&b); 418*f7167e0eSDag-Erling Smørgrav return k; 419*f7167e0eSDag-Erling Smørgrav } 420*f7167e0eSDag-Erling Smørgrav 421511b41d2SMark Murray /* 4224a421b63SDag-Erling Smørgrav * Serialises the authentication (private) key to a blob, encrypting it with 4234a421b63SDag-Erling Smørgrav * passphrase. The identification of the blob (lowest 64 bits of n) will 424511b41d2SMark Murray * precede the key to provide identification of the key without needing a 425511b41d2SMark Murray * passphrase. 426511b41d2SMark Murray */ 427af12a3e7SDag-Erling Smørgrav static int 4284a421b63SDag-Erling Smørgrav key_private_rsa1_to_blob(Key *key, Buffer *blob, const char *passphrase, 429ca3176e7SBrian Feldman const char *comment) 430511b41d2SMark Murray { 431511b41d2SMark Murray Buffer buffer, encrypted; 432af12a3e7SDag-Erling Smørgrav u_char buf[100], *cp; 4334a421b63SDag-Erling Smørgrav int i, cipher_num; 43409958426SBrian Feldman CipherContext ciphercontext; 435e4a9863fSDag-Erling Smørgrav const Cipher *cipher; 43621e764dfSDag-Erling Smørgrav u_int32_t rnd; 437511b41d2SMark Murray 438511b41d2SMark Murray /* 439511b41d2SMark Murray * If the passphrase is empty, use SSH_CIPHER_NONE to ease converting 440511b41d2SMark Murray * to another cipher; otherwise use SSH_AUTHFILE_CIPHER. 441511b41d2SMark Murray */ 442af12a3e7SDag-Erling Smørgrav cipher_num = (strcmp(passphrase, "") == 0) ? 443af12a3e7SDag-Erling Smørgrav SSH_CIPHER_NONE : SSH_AUTHFILE_CIPHER; 444af12a3e7SDag-Erling Smørgrav if ((cipher = cipher_by_number(cipher_num)) == NULL) 44509958426SBrian Feldman fatal("save_private_key_rsa: bad cipher"); 446511b41d2SMark Murray 447511b41d2SMark Murray /* This buffer is used to built the secret part of the private key. */ 448511b41d2SMark Murray buffer_init(&buffer); 449511b41d2SMark Murray 450511b41d2SMark Murray /* Put checkbytes for checking passphrase validity. */ 45121e764dfSDag-Erling Smørgrav rnd = arc4random(); 45221e764dfSDag-Erling Smørgrav buf[0] = rnd & 0xff; 45321e764dfSDag-Erling Smørgrav buf[1] = (rnd >> 8) & 0xff; 454511b41d2SMark Murray buf[2] = buf[0]; 455511b41d2SMark Murray buf[3] = buf[1]; 456511b41d2SMark Murray buffer_append(&buffer, buf, 4); 457511b41d2SMark Murray 458511b41d2SMark Murray /* 459511b41d2SMark Murray * Store the private key (n and e will not be stored because they 460511b41d2SMark Murray * will be stored in plain text, and storing them also in encrypted 461511b41d2SMark Murray * format would just give known plaintext). 462511b41d2SMark Murray */ 463ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->d); 464ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->iqmp); 465ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->q); /* reverse from SSL p */ 466ca3176e7SBrian Feldman buffer_put_bignum(&buffer, key->rsa->p); /* reverse from SSL q */ 467511b41d2SMark Murray 468511b41d2SMark Murray /* Pad the part to be encrypted until its size is a multiple of 8. */ 469511b41d2SMark Murray while (buffer_len(&buffer) % 8 != 0) 470511b41d2SMark Murray buffer_put_char(&buffer, 0); 471511b41d2SMark Murray 472511b41d2SMark Murray /* This buffer will be used to contain the data in the file. */ 473511b41d2SMark Murray buffer_init(&encrypted); 474511b41d2SMark Murray 475511b41d2SMark Murray /* First store keyfile id string. */ 476ca3176e7SBrian Feldman for (i = 0; authfile_id_string[i]; i++) 477ca3176e7SBrian Feldman buffer_put_char(&encrypted, authfile_id_string[i]); 478511b41d2SMark Murray buffer_put_char(&encrypted, 0); 479511b41d2SMark Murray 480511b41d2SMark Murray /* Store cipher type. */ 481af12a3e7SDag-Erling Smørgrav buffer_put_char(&encrypted, cipher_num); 482511b41d2SMark Murray buffer_put_int(&encrypted, 0); /* For future extension */ 483511b41d2SMark Murray 484511b41d2SMark Murray /* Store public key. This will be in plain text. */ 485ca3176e7SBrian Feldman buffer_put_int(&encrypted, BN_num_bits(key->rsa->n)); 486ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->n); 487ca3176e7SBrian Feldman buffer_put_bignum(&encrypted, key->rsa->e); 488af12a3e7SDag-Erling Smørgrav buffer_put_cstring(&encrypted, comment); 489511b41d2SMark Murray 490511b41d2SMark Murray /* Allocate space for the private part of the key in the buffer. */ 491af12a3e7SDag-Erling Smørgrav cp = buffer_append_space(&encrypted, buffer_len(&buffer)); 492511b41d2SMark Murray 493af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 494af12a3e7SDag-Erling Smørgrav CIPHER_ENCRYPT); 495*f7167e0eSDag-Erling Smørgrav if (cipher_crypt(&ciphercontext, 0, cp, 496*f7167e0eSDag-Erling Smørgrav buffer_ptr(&buffer), buffer_len(&buffer), 0, 0) != 0) 497*f7167e0eSDag-Erling Smørgrav fatal("%s: cipher_crypt failed", __func__); 498af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 49909958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 500511b41d2SMark Murray 501511b41d2SMark Murray /* Destroy temporary data. */ 502511b41d2SMark Murray memset(buf, 0, sizeof(buf)); 503511b41d2SMark Murray buffer_free(&buffer); 504511b41d2SMark Murray 5054a421b63SDag-Erling Smørgrav buffer_append(blob, buffer_ptr(&encrypted), buffer_len(&encrypted)); 5061ec0d754SDag-Erling Smørgrav buffer_free(&encrypted); 5074a421b63SDag-Erling Smørgrav 508511b41d2SMark Murray return 1; 509511b41d2SMark Murray } 510511b41d2SMark Murray 5114a421b63SDag-Erling Smørgrav /* convert SSH v2 key in OpenSSL PEM format */ 512af12a3e7SDag-Erling Smørgrav static int 5134a421b63SDag-Erling Smørgrav key_private_pem_to_blob(Key *key, Buffer *blob, const char *_passphrase, 514ca3176e7SBrian Feldman const char *comment) 515e8aafc91SKris Kennaway { 516ca3176e7SBrian Feldman int success = 0; 5174a421b63SDag-Erling Smørgrav int blen, len = strlen(_passphrase); 518af12a3e7SDag-Erling Smørgrav u_char *passphrase = (len > 0) ? (u_char *)_passphrase : NULL; 519b15c8340SDag-Erling Smørgrav #if (OPENSSL_VERSION_NUMBER < 0x00907000L) 520af12a3e7SDag-Erling Smørgrav const EVP_CIPHER *cipher = (len > 0) ? EVP_des_ede3_cbc() : NULL; 521b15c8340SDag-Erling Smørgrav #else 522b15c8340SDag-Erling Smørgrav const EVP_CIPHER *cipher = (len > 0) ? EVP_aes_128_cbc() : NULL; 523b15c8340SDag-Erling Smørgrav #endif 5244a421b63SDag-Erling Smørgrav const u_char *bptr; 5254a421b63SDag-Erling Smørgrav BIO *bio; 526e8aafc91SKris Kennaway 527e8aafc91SKris Kennaway if (len > 0 && len <= 4) { 528ca3176e7SBrian Feldman error("passphrase too short: have %d bytes, need > 4", len); 529e8aafc91SKris Kennaway return 0; 530e8aafc91SKris Kennaway } 5314a421b63SDag-Erling Smørgrav if ((bio = BIO_new(BIO_s_mem())) == NULL) { 5324a421b63SDag-Erling Smørgrav error("%s: BIO_new failed", __func__); 533e8aafc91SKris Kennaway return 0; 534e8aafc91SKris Kennaway } 535ca3176e7SBrian Feldman switch (key->type) { 536ca3176e7SBrian Feldman case KEY_DSA: 5374a421b63SDag-Erling Smørgrav success = PEM_write_bio_DSAPrivateKey(bio, key->dsa, 538ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 539ca3176e7SBrian Feldman break; 5404a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 5414a421b63SDag-Erling Smørgrav case KEY_ECDSA: 5424a421b63SDag-Erling Smørgrav success = PEM_write_bio_ECPrivateKey(bio, key->ecdsa, 5434a421b63SDag-Erling Smørgrav cipher, passphrase, len, NULL, NULL); 5444a421b63SDag-Erling Smørgrav break; 5454a421b63SDag-Erling Smørgrav #endif 546ca3176e7SBrian Feldman case KEY_RSA: 5474a421b63SDag-Erling Smørgrav success = PEM_write_bio_RSAPrivateKey(bio, key->rsa, 548ca3176e7SBrian Feldman cipher, passphrase, len, NULL, NULL); 549ca3176e7SBrian Feldman break; 550e8aafc91SKris Kennaway } 5514a421b63SDag-Erling Smørgrav if (success) { 5524a421b63SDag-Erling Smørgrav if ((blen = BIO_get_mem_data(bio, &bptr)) <= 0) 5534a421b63SDag-Erling Smørgrav success = 0; 5544a421b63SDag-Erling Smørgrav else 5554a421b63SDag-Erling Smørgrav buffer_append(blob, bptr, blen); 5564a421b63SDag-Erling Smørgrav } 5574a421b63SDag-Erling Smørgrav BIO_free(bio); 558e8aafc91SKris Kennaway return success; 559e8aafc91SKris Kennaway } 560e8aafc91SKris Kennaway 5614a421b63SDag-Erling Smørgrav /* Save a key blob to a file */ 5624a421b63SDag-Erling Smørgrav static int 5634a421b63SDag-Erling Smørgrav key_save_private_blob(Buffer *keybuf, const char *filename) 5644a421b63SDag-Erling Smørgrav { 5654a421b63SDag-Erling Smørgrav int fd; 5664a421b63SDag-Erling Smørgrav 5674a421b63SDag-Erling Smørgrav if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0) { 5684a421b63SDag-Erling Smørgrav error("open %s failed: %s.", filename, strerror(errno)); 5694a421b63SDag-Erling Smørgrav return 0; 5704a421b63SDag-Erling Smørgrav } 5714a421b63SDag-Erling Smørgrav if (atomicio(vwrite, fd, buffer_ptr(keybuf), 5724a421b63SDag-Erling Smørgrav buffer_len(keybuf)) != buffer_len(keybuf)) { 5734a421b63SDag-Erling Smørgrav error("write to key file %s failed: %s", filename, 5744a421b63SDag-Erling Smørgrav strerror(errno)); 5754a421b63SDag-Erling Smørgrav close(fd); 5764a421b63SDag-Erling Smørgrav unlink(filename); 5774a421b63SDag-Erling Smørgrav return 0; 5784a421b63SDag-Erling Smørgrav } 5794a421b63SDag-Erling Smørgrav close(fd); 5804a421b63SDag-Erling Smørgrav return 1; 5814a421b63SDag-Erling Smørgrav } 5824a421b63SDag-Erling Smørgrav 5834a421b63SDag-Erling Smørgrav /* Serialise "key" to buffer "blob" */ 5844a421b63SDag-Erling Smørgrav static int 5854a421b63SDag-Erling Smørgrav key_private_to_blob(Key *key, Buffer *blob, const char *passphrase, 586*f7167e0eSDag-Erling Smørgrav const char *comment, int force_new_format, const char *new_format_cipher, 587*f7167e0eSDag-Erling Smørgrav int new_format_rounds) 5884a421b63SDag-Erling Smørgrav { 5894a421b63SDag-Erling Smørgrav switch (key->type) { 5904a421b63SDag-Erling Smørgrav case KEY_RSA1: 5914a421b63SDag-Erling Smørgrav return key_private_rsa1_to_blob(key, blob, passphrase, comment); 5924a421b63SDag-Erling Smørgrav case KEY_DSA: 5934a421b63SDag-Erling Smørgrav case KEY_ECDSA: 5944a421b63SDag-Erling Smørgrav case KEY_RSA: 595*f7167e0eSDag-Erling Smørgrav if (force_new_format) { 596*f7167e0eSDag-Erling Smørgrav return key_private_to_blob2(key, blob, passphrase, 597*f7167e0eSDag-Erling Smørgrav comment, new_format_cipher, new_format_rounds); 598*f7167e0eSDag-Erling Smørgrav } 5994a421b63SDag-Erling Smørgrav return key_private_pem_to_blob(key, blob, passphrase, comment); 600*f7167e0eSDag-Erling Smørgrav case KEY_ED25519: 601*f7167e0eSDag-Erling Smørgrav return key_private_to_blob2(key, blob, passphrase, 602*f7167e0eSDag-Erling Smørgrav comment, new_format_cipher, new_format_rounds); 6034a421b63SDag-Erling Smørgrav default: 6044a421b63SDag-Erling Smørgrav error("%s: cannot save key type %d", __func__, key->type); 6054a421b63SDag-Erling Smørgrav return 0; 6064a421b63SDag-Erling Smørgrav } 6074a421b63SDag-Erling Smørgrav } 6084a421b63SDag-Erling Smørgrav 609e8aafc91SKris Kennaway int 610ca3176e7SBrian Feldman key_save_private(Key *key, const char *filename, const char *passphrase, 611*f7167e0eSDag-Erling Smørgrav const char *comment, int force_new_format, const char *new_format_cipher, 612*f7167e0eSDag-Erling Smørgrav int new_format_rounds) 613e8aafc91SKris Kennaway { 6144a421b63SDag-Erling Smørgrav Buffer keyblob; 6154a421b63SDag-Erling Smørgrav int success = 0; 6164a421b63SDag-Erling Smørgrav 6174a421b63SDag-Erling Smørgrav buffer_init(&keyblob); 618*f7167e0eSDag-Erling Smørgrav if (!key_private_to_blob(key, &keyblob, passphrase, comment, 619*f7167e0eSDag-Erling Smørgrav force_new_format, new_format_cipher, new_format_rounds)) 6204a421b63SDag-Erling Smørgrav goto out; 6214a421b63SDag-Erling Smørgrav if (!key_save_private_blob(&keyblob, filename)) 6224a421b63SDag-Erling Smørgrav goto out; 6234a421b63SDag-Erling Smørgrav success = 1; 6244a421b63SDag-Erling Smørgrav out: 6254a421b63SDag-Erling Smørgrav buffer_free(&keyblob); 6264a421b63SDag-Erling Smørgrav return success; 627e8aafc91SKris Kennaway } 6284a421b63SDag-Erling Smørgrav 6294a421b63SDag-Erling Smørgrav /* 6304a421b63SDag-Erling Smørgrav * Parse the public, unencrypted portion of a RSA1 key. 6314a421b63SDag-Erling Smørgrav */ 6324a421b63SDag-Erling Smørgrav static Key * 6334a421b63SDag-Erling Smørgrav key_parse_public_rsa1(Buffer *blob, char **commentp) 6344a421b63SDag-Erling Smørgrav { 6354a421b63SDag-Erling Smørgrav Key *pub; 636e146993eSDag-Erling Smørgrav Buffer copy; 6374a421b63SDag-Erling Smørgrav 6384a421b63SDag-Erling Smørgrav /* Check that it is at least big enough to contain the ID string. */ 6394a421b63SDag-Erling Smørgrav if (buffer_len(blob) < sizeof(authfile_id_string)) { 6404a421b63SDag-Erling Smørgrav debug3("Truncated RSA1 identifier"); 6414a421b63SDag-Erling Smørgrav return NULL; 6424a421b63SDag-Erling Smørgrav } 6434a421b63SDag-Erling Smørgrav 6444a421b63SDag-Erling Smørgrav /* 6454a421b63SDag-Erling Smørgrav * Make sure it begins with the id string. Consume the id string 6464a421b63SDag-Erling Smørgrav * from the buffer. 6474a421b63SDag-Erling Smørgrav */ 6484a421b63SDag-Erling Smørgrav if (memcmp(buffer_ptr(blob), authfile_id_string, 6494a421b63SDag-Erling Smørgrav sizeof(authfile_id_string)) != 0) { 6504a421b63SDag-Erling Smørgrav debug3("Incorrect RSA1 identifier"); 6514a421b63SDag-Erling Smørgrav return NULL; 6524a421b63SDag-Erling Smørgrav } 653e146993eSDag-Erling Smørgrav buffer_init(©); 654e146993eSDag-Erling Smørgrav buffer_append(©, buffer_ptr(blob), buffer_len(blob)); 655e146993eSDag-Erling Smørgrav buffer_consume(©, sizeof(authfile_id_string)); 6564a421b63SDag-Erling Smørgrav 6574a421b63SDag-Erling Smørgrav /* Skip cipher type and reserved data. */ 658e146993eSDag-Erling Smørgrav (void) buffer_get_char(©); /* cipher type */ 659e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); /* reserved */ 6604a421b63SDag-Erling Smørgrav 6614a421b63SDag-Erling Smørgrav /* Read the public key from the buffer. */ 662e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); 6634a421b63SDag-Erling Smørgrav pub = key_new(KEY_RSA1); 664e146993eSDag-Erling Smørgrav buffer_get_bignum(©, pub->rsa->n); 665e146993eSDag-Erling Smørgrav buffer_get_bignum(©, pub->rsa->e); 6664a421b63SDag-Erling Smørgrav if (commentp) 667e146993eSDag-Erling Smørgrav *commentp = buffer_get_string(©, NULL); 6684a421b63SDag-Erling Smørgrav /* The encrypted private part is not parsed by this function. */ 669e146993eSDag-Erling Smørgrav buffer_free(©); 6704a421b63SDag-Erling Smørgrav 6714a421b63SDag-Erling Smørgrav return pub; 6724a421b63SDag-Erling Smørgrav } 6734a421b63SDag-Erling Smørgrav 674e146993eSDag-Erling Smørgrav /* Load a key from a fd into a buffer */ 675e146993eSDag-Erling Smørgrav int 6764a421b63SDag-Erling Smørgrav key_load_file(int fd, const char *filename, Buffer *blob) 6774a421b63SDag-Erling Smørgrav { 678e146993eSDag-Erling Smørgrav u_char buf[1024]; 6794a421b63SDag-Erling Smørgrav size_t len; 6804a421b63SDag-Erling Smørgrav struct stat st; 6814a421b63SDag-Erling Smørgrav 6824a421b63SDag-Erling Smørgrav if (fstat(fd, &st) < 0) { 6834a421b63SDag-Erling Smørgrav error("%s: fstat of key file %.200s%sfailed: %.100s", __func__, 6844a421b63SDag-Erling Smørgrav filename == NULL ? "" : filename, 6854a421b63SDag-Erling Smørgrav filename == NULL ? "" : " ", 6864a421b63SDag-Erling Smørgrav strerror(errno)); 687e8aafc91SKris Kennaway return 0; 688e8aafc91SKris Kennaway } 689e146993eSDag-Erling Smørgrav if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 690e146993eSDag-Erling Smørgrav st.st_size > MAX_KEY_FILE_SIZE) { 691e146993eSDag-Erling Smørgrav toobig: 6924a421b63SDag-Erling Smørgrav error("%s: key file %.200s%stoo large", __func__, 6934a421b63SDag-Erling Smørgrav filename == NULL ? "" : filename, 6944a421b63SDag-Erling Smørgrav filename == NULL ? "" : " "); 6954a421b63SDag-Erling Smørgrav return 0; 6964a421b63SDag-Erling Smørgrav } 697462c32cbSDag-Erling Smørgrav buffer_clear(blob); 698e146993eSDag-Erling Smørgrav for (;;) { 699e146993eSDag-Erling Smørgrav if ((len = atomicio(read, fd, buf, sizeof(buf))) == 0) { 700e146993eSDag-Erling Smørgrav if (errno == EPIPE) 701e146993eSDag-Erling Smørgrav break; 702e146993eSDag-Erling Smørgrav debug("%s: read from key file %.200s%sfailed: %.100s", 703e146993eSDag-Erling Smørgrav __func__, filename == NULL ? "" : filename, 704e146993eSDag-Erling Smørgrav filename == NULL ? "" : " ", strerror(errno)); 7054a421b63SDag-Erling Smørgrav buffer_clear(blob); 706e146993eSDag-Erling Smørgrav bzero(buf, sizeof(buf)); 7074a421b63SDag-Erling Smørgrav return 0; 7084a421b63SDag-Erling Smørgrav } 709e146993eSDag-Erling Smørgrav buffer_append(blob, buf, len); 710e146993eSDag-Erling Smørgrav if (buffer_len(blob) > MAX_KEY_FILE_SIZE) { 711e146993eSDag-Erling Smørgrav buffer_clear(blob); 712e146993eSDag-Erling Smørgrav bzero(buf, sizeof(buf)); 713e146993eSDag-Erling Smørgrav goto toobig; 714e146993eSDag-Erling Smørgrav } 715e146993eSDag-Erling Smørgrav } 716e146993eSDag-Erling Smørgrav bzero(buf, sizeof(buf)); 717e146993eSDag-Erling Smørgrav if ((st.st_mode & (S_IFSOCK|S_IFCHR|S_IFIFO)) == 0 && 718e146993eSDag-Erling Smørgrav st.st_size != buffer_len(blob)) { 719e146993eSDag-Erling Smørgrav debug("%s: key file %.200s%schanged size while reading", 720e146993eSDag-Erling Smørgrav __func__, filename == NULL ? "" : filename, 721e146993eSDag-Erling Smørgrav filename == NULL ? "" : " "); 722e146993eSDag-Erling Smørgrav buffer_clear(blob); 723e146993eSDag-Erling Smørgrav return 0; 724e146993eSDag-Erling Smørgrav } 725e146993eSDag-Erling Smørgrav 7264a421b63SDag-Erling Smørgrav return 1; 7274a421b63SDag-Erling Smørgrav } 728e8aafc91SKris Kennaway 729511b41d2SMark Murray /* 730ca3176e7SBrian Feldman * Loads the public part of the ssh v1 key file. Returns NULL if an error was 731ca3176e7SBrian Feldman * encountered (the file does not exist or is not readable), and the key 732511b41d2SMark Murray * otherwise. 733511b41d2SMark Murray */ 734af12a3e7SDag-Erling Smørgrav static Key * 735ca3176e7SBrian Feldman key_load_public_rsa1(int fd, const char *filename, char **commentp) 736511b41d2SMark Murray { 737511b41d2SMark Murray Buffer buffer; 738ca3176e7SBrian Feldman Key *pub; 739511b41d2SMark Murray 740511b41d2SMark Murray buffer_init(&buffer); 7414a421b63SDag-Erling Smørgrav if (!key_load_file(fd, filename, &buffer)) { 742511b41d2SMark Murray buffer_free(&buffer); 743ca3176e7SBrian Feldman return NULL; 744511b41d2SMark Murray } 745511b41d2SMark Murray 7464a421b63SDag-Erling Smørgrav pub = key_parse_public_rsa1(&buffer, commentp); 7474a421b63SDag-Erling Smørgrav if (pub == NULL) 7484a421b63SDag-Erling Smørgrav debug3("Could not load \"%s\" as a RSA1 public key", filename); 749511b41d2SMark Murray buffer_free(&buffer); 750ca3176e7SBrian Feldman return pub; 751511b41d2SMark Murray } 752511b41d2SMark Murray 753ca3176e7SBrian Feldman /* load public key from private-key file, works only for SSH v1 */ 754ca3176e7SBrian Feldman Key * 755ca3176e7SBrian Feldman key_load_public_type(int type, const char *filename, char **commentp) 756e8aafc91SKris Kennaway { 757ca3176e7SBrian Feldman Key *pub; 758ca3176e7SBrian Feldman int fd; 759ca3176e7SBrian Feldman 760ca3176e7SBrian Feldman if (type == KEY_RSA1) { 761ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 762ca3176e7SBrian Feldman if (fd < 0) 763ca3176e7SBrian Feldman return NULL; 764ca3176e7SBrian Feldman pub = key_load_public_rsa1(fd, filename, commentp); 765ca3176e7SBrian Feldman close(fd); 766ca3176e7SBrian Feldman return pub; 767e8aafc91SKris Kennaway } 768ca3176e7SBrian Feldman return NULL; 769e8aafc91SKris Kennaway } 770e8aafc91SKris Kennaway 771af12a3e7SDag-Erling Smørgrav static Key * 7724a421b63SDag-Erling Smørgrav key_parse_private_rsa1(Buffer *blob, const char *passphrase, char **commentp) 773511b41d2SMark Murray { 774d4ecd108SDag-Erling Smørgrav int check1, check2, cipher_type; 7754a421b63SDag-Erling Smørgrav Buffer decrypted; 776af12a3e7SDag-Erling Smørgrav u_char *cp; 77709958426SBrian Feldman CipherContext ciphercontext; 778e4a9863fSDag-Erling Smørgrav const Cipher *cipher; 779ca3176e7SBrian Feldman Key *prv = NULL; 780e146993eSDag-Erling Smørgrav Buffer copy; 781511b41d2SMark Murray 782ca3176e7SBrian Feldman /* Check that it is at least big enough to contain the ID string. */ 7834a421b63SDag-Erling Smørgrav if (buffer_len(blob) < sizeof(authfile_id_string)) { 7844a421b63SDag-Erling Smørgrav debug3("Truncated RSA1 identifier"); 785ca3176e7SBrian Feldman return NULL; 786511b41d2SMark Murray } 7874a421b63SDag-Erling Smørgrav 788511b41d2SMark Murray /* 789511b41d2SMark Murray * Make sure it begins with the id string. Consume the id string 790511b41d2SMark Murray * from the buffer. 791511b41d2SMark Murray */ 7924a421b63SDag-Erling Smørgrav if (memcmp(buffer_ptr(blob), authfile_id_string, 7934a421b63SDag-Erling Smørgrav sizeof(authfile_id_string)) != 0) { 7944a421b63SDag-Erling Smørgrav debug3("Incorrect RSA1 identifier"); 795ca3176e7SBrian Feldman return NULL; 796511b41d2SMark Murray } 797e146993eSDag-Erling Smørgrav buffer_init(©); 798e146993eSDag-Erling Smørgrav buffer_append(©, buffer_ptr(blob), buffer_len(blob)); 799e146993eSDag-Erling Smørgrav buffer_consume(©, sizeof(authfile_id_string)); 800ca3176e7SBrian Feldman 801511b41d2SMark Murray /* Read cipher type. */ 802e146993eSDag-Erling Smørgrav cipher_type = buffer_get_char(©); 803e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); /* Reserved data. */ 804511b41d2SMark Murray 805511b41d2SMark Murray /* Read the public key from the buffer. */ 806e146993eSDag-Erling Smørgrav (void) buffer_get_int(©); 807ca3176e7SBrian Feldman prv = key_new_private(KEY_RSA1); 808ca3176e7SBrian Feldman 809e146993eSDag-Erling Smørgrav buffer_get_bignum(©, prv->rsa->n); 810e146993eSDag-Erling Smørgrav buffer_get_bignum(©, prv->rsa->e); 811ca3176e7SBrian Feldman if (commentp) 812e146993eSDag-Erling Smørgrav *commentp = buffer_get_string(©, NULL); 813511b41d2SMark Murray else 814e146993eSDag-Erling Smørgrav (void)buffer_get_string_ptr(©, NULL); 815511b41d2SMark Murray 816511b41d2SMark Murray /* Check that it is a supported cipher. */ 81709958426SBrian Feldman cipher = cipher_by_number(cipher_type); 81809958426SBrian Feldman if (cipher == NULL) { 8194a421b63SDag-Erling Smørgrav debug("Unsupported RSA1 cipher %d", cipher_type); 820e146993eSDag-Erling Smørgrav buffer_free(©); 821511b41d2SMark Murray goto fail; 822511b41d2SMark Murray } 823511b41d2SMark Murray /* Initialize space for decrypted data. */ 824511b41d2SMark Murray buffer_init(&decrypted); 825e146993eSDag-Erling Smørgrav cp = buffer_append_space(&decrypted, buffer_len(©)); 826511b41d2SMark Murray 827511b41d2SMark Murray /* Rest of the buffer is encrypted. Decrypt it using the passphrase. */ 828af12a3e7SDag-Erling Smørgrav cipher_set_key_string(&ciphercontext, cipher, passphrase, 829af12a3e7SDag-Erling Smørgrav CIPHER_DECRYPT); 830*f7167e0eSDag-Erling Smørgrav if (cipher_crypt(&ciphercontext, 0, cp, 831*f7167e0eSDag-Erling Smørgrav buffer_ptr(©), buffer_len(©), 0, 0) != 0) 832*f7167e0eSDag-Erling Smørgrav fatal("%s: cipher_crypt failed", __func__); 833af12a3e7SDag-Erling Smørgrav cipher_cleanup(&ciphercontext); 83409958426SBrian Feldman memset(&ciphercontext, 0, sizeof(ciphercontext)); 835e146993eSDag-Erling Smørgrav buffer_free(©); 836511b41d2SMark Murray 837511b41d2SMark Murray check1 = buffer_get_char(&decrypted); 838511b41d2SMark Murray check2 = buffer_get_char(&decrypted); 839511b41d2SMark Murray if (check1 != buffer_get_char(&decrypted) || 840511b41d2SMark Murray check2 != buffer_get_char(&decrypted)) { 841511b41d2SMark Murray if (strcmp(passphrase, "") != 0) 8424a421b63SDag-Erling Smørgrav debug("Bad passphrase supplied for RSA1 key"); 843511b41d2SMark Murray /* Bad passphrase. */ 844511b41d2SMark Murray buffer_free(&decrypted); 845ca3176e7SBrian Feldman goto fail; 846511b41d2SMark Murray } 847511b41d2SMark Murray /* Read the rest of the private key. */ 848ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->d); 849ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->iqmp); /* u */ 850ca3176e7SBrian Feldman /* in SSL and SSH v1 p and q are exchanged */ 851ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->q); /* p */ 852ca3176e7SBrian Feldman buffer_get_bignum(&decrypted, prv->rsa->p); /* q */ 853511b41d2SMark Murray 854ca3176e7SBrian Feldman /* calculate p-1 and q-1 */ 855af12a3e7SDag-Erling Smørgrav rsa_generate_additional_parameters(prv->rsa); 856511b41d2SMark Murray 857511b41d2SMark Murray buffer_free(&decrypted); 858e73e9afaSDag-Erling Smørgrav 859e73e9afaSDag-Erling Smørgrav /* enable blinding */ 860e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 8614a421b63SDag-Erling Smørgrav error("%s: RSA_blinding_on failed", __func__); 862e73e9afaSDag-Erling Smørgrav goto fail; 863e73e9afaSDag-Erling Smørgrav } 864ca3176e7SBrian Feldman return prv; 865511b41d2SMark Murray 866ca3176e7SBrian Feldman fail: 867e4a9863fSDag-Erling Smørgrav if (commentp != NULL) 868e4a9863fSDag-Erling Smørgrav free(*commentp); 869ca3176e7SBrian Feldman key_free(prv); 870ca3176e7SBrian Feldman return NULL; 871511b41d2SMark Murray } 872e8aafc91SKris Kennaway 8734a421b63SDag-Erling Smørgrav static Key * 8744a421b63SDag-Erling Smørgrav key_parse_private_pem(Buffer *blob, int type, const char *passphrase, 875ca3176e7SBrian Feldman char **commentp) 876e8aafc91SKris Kennaway { 877ca3176e7SBrian Feldman EVP_PKEY *pk = NULL; 878ca3176e7SBrian Feldman Key *prv = NULL; 879ca3176e7SBrian Feldman char *name = "<no key>"; 8804a421b63SDag-Erling Smørgrav BIO *bio; 881e8aafc91SKris Kennaway 8824a421b63SDag-Erling Smørgrav if ((bio = BIO_new_mem_buf(buffer_ptr(blob), 8834a421b63SDag-Erling Smørgrav buffer_len(blob))) == NULL) { 8844a421b63SDag-Erling Smørgrav error("%s: BIO_new_mem_buf failed", __func__); 885ca3176e7SBrian Feldman return NULL; 886e8aafc91SKris Kennaway } 8874a421b63SDag-Erling Smørgrav 8884a421b63SDag-Erling Smørgrav pk = PEM_read_bio_PrivateKey(bio, NULL, NULL, (char *)passphrase); 8894a421b63SDag-Erling Smørgrav BIO_free(bio); 890ca3176e7SBrian Feldman if (pk == NULL) { 8914a421b63SDag-Erling Smørgrav debug("%s: PEM_read_PrivateKey failed", __func__); 892ca3176e7SBrian Feldman (void)ERR_get_error(); 893ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_RSA && 894ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_RSA)) { 895ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 896ca3176e7SBrian Feldman prv->rsa = EVP_PKEY_get1_RSA(pk); 897ca3176e7SBrian Feldman prv->type = KEY_RSA; 898ca3176e7SBrian Feldman name = "rsa w/o comment"; 899ca3176e7SBrian Feldman #ifdef DEBUG_PK 900ca3176e7SBrian Feldman RSA_print_fp(stderr, prv->rsa, 8); 901e8aafc91SKris Kennaway #endif 902e73e9afaSDag-Erling Smørgrav if (RSA_blinding_on(prv->rsa, NULL) != 1) { 9034a421b63SDag-Erling Smørgrav error("%s: RSA_blinding_on failed", __func__); 904e73e9afaSDag-Erling Smørgrav key_free(prv); 905e73e9afaSDag-Erling Smørgrav prv = NULL; 906e73e9afaSDag-Erling Smørgrav } 907ca3176e7SBrian Feldman } else if (pk->type == EVP_PKEY_DSA && 908ca3176e7SBrian Feldman (type == KEY_UNSPEC||type==KEY_DSA)) { 909ca3176e7SBrian Feldman prv = key_new(KEY_UNSPEC); 910ca3176e7SBrian Feldman prv->dsa = EVP_PKEY_get1_DSA(pk); 911ca3176e7SBrian Feldman prv->type = KEY_DSA; 912ca3176e7SBrian Feldman name = "dsa w/o comment"; 913ca3176e7SBrian Feldman #ifdef DEBUG_PK 914ca3176e7SBrian Feldman DSA_print_fp(stderr, prv->dsa, 8); 915ca3176e7SBrian Feldman #endif 9164a421b63SDag-Erling Smørgrav #ifdef OPENSSL_HAS_ECC 9174a421b63SDag-Erling Smørgrav } else if (pk->type == EVP_PKEY_EC && 9184a421b63SDag-Erling Smørgrav (type == KEY_UNSPEC||type==KEY_ECDSA)) { 9194a421b63SDag-Erling Smørgrav prv = key_new(KEY_UNSPEC); 9204a421b63SDag-Erling Smørgrav prv->ecdsa = EVP_PKEY_get1_EC_KEY(pk); 9214a421b63SDag-Erling Smørgrav prv->type = KEY_ECDSA; 9224a421b63SDag-Erling Smørgrav if ((prv->ecdsa_nid = key_ecdsa_key_to_nid(prv->ecdsa)) == -1 || 9234a421b63SDag-Erling Smørgrav key_curve_nid_to_name(prv->ecdsa_nid) == NULL || 9244a421b63SDag-Erling Smørgrav key_ec_validate_public(EC_KEY_get0_group(prv->ecdsa), 9254a421b63SDag-Erling Smørgrav EC_KEY_get0_public_key(prv->ecdsa)) != 0 || 9264a421b63SDag-Erling Smørgrav key_ec_validate_private(prv->ecdsa) != 0) { 9274a421b63SDag-Erling Smørgrav error("%s: bad ECDSA key", __func__); 9284a421b63SDag-Erling Smørgrav key_free(prv); 9294a421b63SDag-Erling Smørgrav prv = NULL; 930ca3176e7SBrian Feldman } 9314a421b63SDag-Erling Smørgrav name = "ecdsa w/o comment"; 9324a421b63SDag-Erling Smørgrav #ifdef DEBUG_PK 9334a421b63SDag-Erling Smørgrav if (prv != NULL && prv->ecdsa != NULL) 9344a421b63SDag-Erling Smørgrav key_dump_ec_key(prv->ecdsa); 9354a421b63SDag-Erling Smørgrav #endif 9364a421b63SDag-Erling Smørgrav #endif /* OPENSSL_HAS_ECC */ 9374a421b63SDag-Erling Smørgrav } else { 9384a421b63SDag-Erling Smørgrav error("%s: PEM_read_PrivateKey: mismatch or " 9394a421b63SDag-Erling Smørgrav "unknown EVP_PKEY save_type %d", __func__, pk->save_type); 9404a421b63SDag-Erling Smørgrav } 941ca3176e7SBrian Feldman if (pk != NULL) 942ca3176e7SBrian Feldman EVP_PKEY_free(pk); 943ca3176e7SBrian Feldman if (prv != NULL && commentp) 944ca3176e7SBrian Feldman *commentp = xstrdup(name); 945ca3176e7SBrian Feldman debug("read PEM private key done: type %s", 946ca3176e7SBrian Feldman prv ? key_type(prv) : "<unknown>"); 947ca3176e7SBrian Feldman return prv; 948e8aafc91SKris Kennaway } 949e8aafc91SKris Kennaway 9504a421b63SDag-Erling Smørgrav Key * 9514a421b63SDag-Erling Smørgrav key_load_private_pem(int fd, int type, const char *passphrase, 9524a421b63SDag-Erling Smørgrav char **commentp) 9534a421b63SDag-Erling Smørgrav { 9544a421b63SDag-Erling Smørgrav Buffer buffer; 9554a421b63SDag-Erling Smørgrav Key *prv; 9564a421b63SDag-Erling Smørgrav 9574a421b63SDag-Erling Smørgrav buffer_init(&buffer); 9584a421b63SDag-Erling Smørgrav if (!key_load_file(fd, NULL, &buffer)) { 9594a421b63SDag-Erling Smørgrav buffer_free(&buffer); 9604a421b63SDag-Erling Smørgrav return NULL; 9614a421b63SDag-Erling Smørgrav } 9624a421b63SDag-Erling Smørgrav prv = key_parse_private_pem(&buffer, type, passphrase, commentp); 9634a421b63SDag-Erling Smørgrav buffer_free(&buffer); 9644a421b63SDag-Erling Smørgrav return prv; 9654a421b63SDag-Erling Smørgrav } 9664a421b63SDag-Erling Smørgrav 967333ee039SDag-Erling Smørgrav int 968ca3176e7SBrian Feldman key_perm_ok(int fd, const char *filename) 969e8aafc91SKris Kennaway { 970e8aafc91SKris Kennaway struct stat st; 971e8aafc91SKris Kennaway 972af12a3e7SDag-Erling Smørgrav if (fstat(fd, &st) < 0) 973af12a3e7SDag-Erling Smørgrav return 0; 974af12a3e7SDag-Erling Smørgrav /* 975af12a3e7SDag-Erling Smørgrav * if a key owned by the user is accessed, then we check the 976af12a3e7SDag-Erling Smørgrav * permissions of the file. if the key owned by a different user, 977af12a3e7SDag-Erling Smørgrav * then we don't care. 978af12a3e7SDag-Erling Smørgrav */ 979989dd127SDag-Erling Smørgrav #ifdef HAVE_CYGWIN 980989dd127SDag-Erling Smørgrav if (check_ntsec(filename)) 981989dd127SDag-Erling Smørgrav #endif 982af12a3e7SDag-Erling Smørgrav if ((st.st_uid == getuid()) && (st.st_mode & 077) != 0) { 983e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 984e8aafc91SKris Kennaway error("@ WARNING: UNPROTECTED PRIVATE KEY FILE! @"); 985e8aafc91SKris Kennaway error("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); 986af12a3e7SDag-Erling Smørgrav error("Permissions 0%3.3o for '%s' are too open.", 987cf2b5f3bSDag-Erling Smørgrav (u_int)st.st_mode & 0777, filename); 988e146993eSDag-Erling Smørgrav error("It is required that your private key files are NOT accessible by others."); 989ca3176e7SBrian Feldman error("This private key will be ignored."); 990e8aafc91SKris Kennaway return 0; 991e8aafc91SKris Kennaway } 992ca3176e7SBrian Feldman return 1; 993e8aafc91SKris Kennaway } 994ca3176e7SBrian Feldman 9954a421b63SDag-Erling Smørgrav static Key * 9964a421b63SDag-Erling Smørgrav key_parse_private_type(Buffer *blob, int type, const char *passphrase, 9974a421b63SDag-Erling Smørgrav char **commentp) 9984a421b63SDag-Erling Smørgrav { 999*f7167e0eSDag-Erling Smørgrav Key *k; 1000*f7167e0eSDag-Erling Smørgrav 10014a421b63SDag-Erling Smørgrav switch (type) { 10024a421b63SDag-Erling Smørgrav case KEY_RSA1: 10034a421b63SDag-Erling Smørgrav return key_parse_private_rsa1(blob, passphrase, commentp); 10044a421b63SDag-Erling Smørgrav case KEY_DSA: 10054a421b63SDag-Erling Smørgrav case KEY_ECDSA: 10064a421b63SDag-Erling Smørgrav case KEY_RSA: 1007*f7167e0eSDag-Erling Smørgrav return key_parse_private_pem(blob, type, passphrase, commentp); 1008*f7167e0eSDag-Erling Smørgrav case KEY_ED25519: 1009*f7167e0eSDag-Erling Smørgrav return key_parse_private2(blob, type, passphrase, commentp); 10104a421b63SDag-Erling Smørgrav case KEY_UNSPEC: 1011*f7167e0eSDag-Erling Smørgrav if ((k = key_parse_private2(blob, type, passphrase, commentp))) 1012*f7167e0eSDag-Erling Smørgrav return k; 10134a421b63SDag-Erling Smørgrav return key_parse_private_pem(blob, type, passphrase, commentp); 10144a421b63SDag-Erling Smørgrav default: 1015e146993eSDag-Erling Smørgrav error("%s: cannot parse key type %d", __func__, type); 10164a421b63SDag-Erling Smørgrav break; 10174a421b63SDag-Erling Smørgrav } 10184a421b63SDag-Erling Smørgrav return NULL; 10194a421b63SDag-Erling Smørgrav } 10204a421b63SDag-Erling Smørgrav 1021ca3176e7SBrian Feldman Key * 1022ca3176e7SBrian Feldman key_load_private_type(int type, const char *filename, const char *passphrase, 1023333ee039SDag-Erling Smørgrav char **commentp, int *perm_ok) 1024ca3176e7SBrian Feldman { 1025ca3176e7SBrian Feldman int fd; 10264a421b63SDag-Erling Smørgrav Key *ret; 10274a421b63SDag-Erling Smørgrav Buffer buffer; 1028ca3176e7SBrian Feldman 1029ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 1030b15c8340SDag-Erling Smørgrav if (fd < 0) { 1031b15c8340SDag-Erling Smørgrav debug("could not open key file '%s': %s", filename, 1032b15c8340SDag-Erling Smørgrav strerror(errno)); 1033b15c8340SDag-Erling Smørgrav if (perm_ok != NULL) 1034b15c8340SDag-Erling Smørgrav *perm_ok = 0; 1035ca3176e7SBrian Feldman return NULL; 1036b15c8340SDag-Erling Smørgrav } 1037ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 1038333ee039SDag-Erling Smørgrav if (perm_ok != NULL) 1039333ee039SDag-Erling Smørgrav *perm_ok = 0; 1040ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 1041ca3176e7SBrian Feldman close(fd); 1042ca3176e7SBrian Feldman return NULL; 1043e8aafc91SKris Kennaway } 1044333ee039SDag-Erling Smørgrav if (perm_ok != NULL) 1045333ee039SDag-Erling Smørgrav *perm_ok = 1; 10464a421b63SDag-Erling Smørgrav 10474a421b63SDag-Erling Smørgrav buffer_init(&buffer); 10484a421b63SDag-Erling Smørgrav if (!key_load_file(fd, filename, &buffer)) { 10494a421b63SDag-Erling Smørgrav buffer_free(&buffer); 1050ca3176e7SBrian Feldman close(fd); 1051ca3176e7SBrian Feldman return NULL; 1052ca3176e7SBrian Feldman } 10534a421b63SDag-Erling Smørgrav close(fd); 10544a421b63SDag-Erling Smørgrav ret = key_parse_private_type(&buffer, type, passphrase, commentp); 10554a421b63SDag-Erling Smørgrav buffer_free(&buffer); 10564a421b63SDag-Erling Smørgrav return ret; 10574a421b63SDag-Erling Smørgrav } 1058ca3176e7SBrian Feldman 1059ca3176e7SBrian Feldman Key * 1060e146993eSDag-Erling Smørgrav key_parse_private(Buffer *buffer, const char *filename, 1061e146993eSDag-Erling Smørgrav const char *passphrase, char **commentp) 1062e146993eSDag-Erling Smørgrav { 1063e146993eSDag-Erling Smørgrav Key *pub, *prv; 1064e146993eSDag-Erling Smørgrav 1065e146993eSDag-Erling Smørgrav /* it's a SSH v1 key if the public key part is readable */ 1066e146993eSDag-Erling Smørgrav pub = key_parse_public_rsa1(buffer, commentp); 1067e146993eSDag-Erling Smørgrav if (pub == NULL) { 1068e146993eSDag-Erling Smørgrav prv = key_parse_private_type(buffer, KEY_UNSPEC, 1069e146993eSDag-Erling Smørgrav passphrase, NULL); 1070e146993eSDag-Erling Smørgrav /* use the filename as a comment for PEM */ 1071e146993eSDag-Erling Smørgrav if (commentp && prv) 1072e146993eSDag-Erling Smørgrav *commentp = xstrdup(filename); 1073e146993eSDag-Erling Smørgrav } else { 1074e146993eSDag-Erling Smørgrav key_free(pub); 1075e146993eSDag-Erling Smørgrav /* key_parse_public_rsa1() has already loaded the comment */ 1076e146993eSDag-Erling Smørgrav prv = key_parse_private_type(buffer, KEY_RSA1, passphrase, 1077e146993eSDag-Erling Smørgrav NULL); 1078e146993eSDag-Erling Smørgrav } 1079e146993eSDag-Erling Smørgrav return prv; 1080e146993eSDag-Erling Smørgrav } 1081e146993eSDag-Erling Smørgrav 1082e146993eSDag-Erling Smørgrav Key * 1083ca3176e7SBrian Feldman key_load_private(const char *filename, const char *passphrase, 1084ca3176e7SBrian Feldman char **commentp) 1085ca3176e7SBrian Feldman { 1086e146993eSDag-Erling Smørgrav Key *prv; 1087e146993eSDag-Erling Smørgrav Buffer buffer; 1088ca3176e7SBrian Feldman int fd; 1089ca3176e7SBrian Feldman 1090ca3176e7SBrian Feldman fd = open(filename, O_RDONLY); 1091b15c8340SDag-Erling Smørgrav if (fd < 0) { 1092b15c8340SDag-Erling Smørgrav debug("could not open key file '%s': %s", filename, 1093b15c8340SDag-Erling Smørgrav strerror(errno)); 1094ca3176e7SBrian Feldman return NULL; 1095b15c8340SDag-Erling Smørgrav } 1096ca3176e7SBrian Feldman if (!key_perm_ok(fd, filename)) { 1097ca3176e7SBrian Feldman error("bad permissions: ignore key: %s", filename); 1098e8aafc91SKris Kennaway close(fd); 1099ca3176e7SBrian Feldman return NULL; 1100ca3176e7SBrian Feldman } 11014a421b63SDag-Erling Smørgrav 11024a421b63SDag-Erling Smørgrav buffer_init(&buffer); 11034a421b63SDag-Erling Smørgrav if (!key_load_file(fd, filename, &buffer)) { 11044a421b63SDag-Erling Smørgrav buffer_free(&buffer); 11054a421b63SDag-Erling Smørgrav close(fd); 11064a421b63SDag-Erling Smørgrav return NULL; 11074a421b63SDag-Erling Smørgrav } 11084a421b63SDag-Erling Smørgrav close(fd); 11094a421b63SDag-Erling Smørgrav 1110e146993eSDag-Erling Smørgrav prv = key_parse_private(&buffer, filename, passphrase, commentp); 11114a421b63SDag-Erling Smørgrav buffer_free(&buffer); 1112af12a3e7SDag-Erling Smørgrav return prv; 1113e8aafc91SKris Kennaway } 1114c2d3a559SKris Kennaway 1115af12a3e7SDag-Erling Smørgrav static int 1116ca3176e7SBrian Feldman key_try_load_public(Key *k, const char *filename, char **commentp) 1117c2d3a559SKris Kennaway { 1118c2d3a559SKris Kennaway FILE *f; 1119aa49c926SDag-Erling Smørgrav char line[SSH_MAX_PUBKEY_BYTES]; 1120c2d3a559SKris Kennaway char *cp; 1121aa49c926SDag-Erling Smørgrav u_long linenum = 0; 1122c2d3a559SKris Kennaway 1123c2d3a559SKris Kennaway f = fopen(filename, "r"); 1124c2d3a559SKris Kennaway if (f != NULL) { 1125aa49c926SDag-Erling Smørgrav while (read_keyfile_line(f, filename, line, sizeof(line), 1126aa49c926SDag-Erling Smørgrav &linenum) != -1) { 1127c2d3a559SKris Kennaway cp = line; 1128c2d3a559SKris Kennaway switch (*cp) { 1129c2d3a559SKris Kennaway case '#': 1130c2d3a559SKris Kennaway case '\n': 1131c2d3a559SKris Kennaway case '\0': 1132c2d3a559SKris Kennaway continue; 1133c2d3a559SKris Kennaway } 1134e146993eSDag-Erling Smørgrav /* Abort loading if this looks like a private key */ 1135e146993eSDag-Erling Smørgrav if (strncmp(cp, "-----BEGIN", 10) == 0) 1136e146993eSDag-Erling Smørgrav break; 1137c2d3a559SKris Kennaway /* Skip leading whitespace. */ 1138c2d3a559SKris Kennaway for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 1139c2d3a559SKris Kennaway ; 1140c2d3a559SKris Kennaway if (*cp) { 1141ca3176e7SBrian Feldman if (key_read(k, &cp) == 1) { 1142e146993eSDag-Erling Smørgrav cp[strcspn(cp, "\r\n")] = '\0'; 1143e146993eSDag-Erling Smørgrav if (commentp) { 1144e146993eSDag-Erling Smørgrav *commentp = xstrdup(*cp ? 1145e146993eSDag-Erling Smørgrav cp : filename); 1146e146993eSDag-Erling Smørgrav } 1147c2d3a559SKris Kennaway fclose(f); 1148c2d3a559SKris Kennaway return 1; 1149c2d3a559SKris Kennaway } 1150c2d3a559SKris Kennaway } 1151c2d3a559SKris Kennaway } 1152c2d3a559SKris Kennaway fclose(f); 1153c2d3a559SKris Kennaway } 1154c2d3a559SKris Kennaway return 0; 1155c2d3a559SKris Kennaway } 1156c2d3a559SKris Kennaway 1157ca3176e7SBrian Feldman /* load public key from ssh v1 private or any pubkey file */ 1158ca3176e7SBrian Feldman Key * 1159ca3176e7SBrian Feldman key_load_public(const char *filename, char **commentp) 1160c2d3a559SKris Kennaway { 1161ca3176e7SBrian Feldman Key *pub; 1162ca3176e7SBrian Feldman char file[MAXPATHLEN]; 1163c2d3a559SKris Kennaway 1164cf2b5f3bSDag-Erling Smørgrav /* try rsa1 private key */ 1165ca3176e7SBrian Feldman pub = key_load_public_type(KEY_RSA1, filename, commentp); 1166ca3176e7SBrian Feldman if (pub != NULL) 1167ca3176e7SBrian Feldman return pub; 1168cf2b5f3bSDag-Erling Smørgrav 1169cf2b5f3bSDag-Erling Smørgrav /* try rsa1 public key */ 1170cf2b5f3bSDag-Erling Smørgrav pub = key_new(KEY_RSA1); 1171cf2b5f3bSDag-Erling Smørgrav if (key_try_load_public(pub, filename, commentp) == 1) 1172cf2b5f3bSDag-Erling Smørgrav return pub; 1173cf2b5f3bSDag-Erling Smørgrav key_free(pub); 1174cf2b5f3bSDag-Erling Smørgrav 1175cf2b5f3bSDag-Erling Smørgrav /* try ssh2 public key */ 1176ca3176e7SBrian Feldman pub = key_new(KEY_UNSPEC); 1177ca3176e7SBrian Feldman if (key_try_load_public(pub, filename, commentp) == 1) 1178ca3176e7SBrian Feldman return pub; 1179ca3176e7SBrian Feldman if ((strlcpy(file, filename, sizeof file) < sizeof(file)) && 1180ca3176e7SBrian Feldman (strlcat(file, ".pub", sizeof file) < sizeof(file)) && 1181ca3176e7SBrian Feldman (key_try_load_public(pub, file, commentp) == 1)) 1182ca3176e7SBrian Feldman return pub; 1183ca3176e7SBrian Feldman key_free(pub); 1184ca3176e7SBrian Feldman return NULL; 1185c2d3a559SKris Kennaway } 1186b15c8340SDag-Erling Smørgrav 1187e2f6069cSDag-Erling Smørgrav /* Load the certificate associated with the named private key */ 1188e2f6069cSDag-Erling Smørgrav Key * 1189e2f6069cSDag-Erling Smørgrav key_load_cert(const char *filename) 1190e2f6069cSDag-Erling Smørgrav { 1191e2f6069cSDag-Erling Smørgrav Key *pub; 1192e2f6069cSDag-Erling Smørgrav char *file; 1193e2f6069cSDag-Erling Smørgrav 1194e2f6069cSDag-Erling Smørgrav pub = key_new(KEY_UNSPEC); 1195e2f6069cSDag-Erling Smørgrav xasprintf(&file, "%s-cert.pub", filename); 1196e2f6069cSDag-Erling Smørgrav if (key_try_load_public(pub, file, NULL) == 1) { 1197e4a9863fSDag-Erling Smørgrav free(file); 1198e2f6069cSDag-Erling Smørgrav return pub; 1199e2f6069cSDag-Erling Smørgrav } 1200e4a9863fSDag-Erling Smørgrav free(file); 1201e2f6069cSDag-Erling Smørgrav key_free(pub); 1202e2f6069cSDag-Erling Smørgrav return NULL; 1203e2f6069cSDag-Erling Smørgrav } 1204e2f6069cSDag-Erling Smørgrav 1205e2f6069cSDag-Erling Smørgrav /* Load private key and certificate */ 1206e2f6069cSDag-Erling Smørgrav Key * 1207e2f6069cSDag-Erling Smørgrav key_load_private_cert(int type, const char *filename, const char *passphrase, 1208e2f6069cSDag-Erling Smørgrav int *perm_ok) 1209e2f6069cSDag-Erling Smørgrav { 1210e2f6069cSDag-Erling Smørgrav Key *key, *pub; 1211e2f6069cSDag-Erling Smørgrav 1212e2f6069cSDag-Erling Smørgrav switch (type) { 1213e2f6069cSDag-Erling Smørgrav case KEY_RSA: 1214e2f6069cSDag-Erling Smørgrav case KEY_DSA: 12154a421b63SDag-Erling Smørgrav case KEY_ECDSA: 1216*f7167e0eSDag-Erling Smørgrav case KEY_ED25519: 1217e2f6069cSDag-Erling Smørgrav break; 1218e2f6069cSDag-Erling Smørgrav default: 1219e2f6069cSDag-Erling Smørgrav error("%s: unsupported key type", __func__); 1220e2f6069cSDag-Erling Smørgrav return NULL; 1221e2f6069cSDag-Erling Smørgrav } 1222e2f6069cSDag-Erling Smørgrav 1223e2f6069cSDag-Erling Smørgrav if ((key = key_load_private_type(type, filename, 1224e2f6069cSDag-Erling Smørgrav passphrase, NULL, perm_ok)) == NULL) 1225e2f6069cSDag-Erling Smørgrav return NULL; 1226e2f6069cSDag-Erling Smørgrav 1227e2f6069cSDag-Erling Smørgrav if ((pub = key_load_cert(filename)) == NULL) { 1228e2f6069cSDag-Erling Smørgrav key_free(key); 1229e2f6069cSDag-Erling Smørgrav return NULL; 1230e2f6069cSDag-Erling Smørgrav } 1231e2f6069cSDag-Erling Smørgrav 1232e2f6069cSDag-Erling Smørgrav /* Make sure the private key matches the certificate */ 1233e2f6069cSDag-Erling Smørgrav if (key_equal_public(key, pub) == 0) { 1234e2f6069cSDag-Erling Smørgrav error("%s: certificate does not match private key %s", 1235e2f6069cSDag-Erling Smørgrav __func__, filename); 1236e2f6069cSDag-Erling Smørgrav } else if (key_to_certified(key, key_cert_is_legacy(pub)) != 0) { 1237e2f6069cSDag-Erling Smørgrav error("%s: key_to_certified failed", __func__); 1238e2f6069cSDag-Erling Smørgrav } else { 1239e2f6069cSDag-Erling Smørgrav key_cert_copy(pub, key); 1240e2f6069cSDag-Erling Smørgrav key_free(pub); 1241e2f6069cSDag-Erling Smørgrav return key; 1242e2f6069cSDag-Erling Smørgrav } 1243e2f6069cSDag-Erling Smørgrav 1244e2f6069cSDag-Erling Smørgrav key_free(key); 1245e2f6069cSDag-Erling Smørgrav key_free(pub); 1246e2f6069cSDag-Erling Smørgrav return NULL; 1247e2f6069cSDag-Erling Smørgrav } 1248e2f6069cSDag-Erling Smørgrav 1249b15c8340SDag-Erling Smørgrav /* 1250b15c8340SDag-Erling Smørgrav * Returns 1 if the specified "key" is listed in the file "filename", 1251b15c8340SDag-Erling Smørgrav * 0 if the key is not listed or -1 on error. 1252b15c8340SDag-Erling Smørgrav * If strict_type is set then the key type must match exactly, 1253b15c8340SDag-Erling Smørgrav * otherwise a comparison that ignores certficiate data is performed. 1254b15c8340SDag-Erling Smørgrav */ 1255b15c8340SDag-Erling Smørgrav int 1256b15c8340SDag-Erling Smørgrav key_in_file(Key *key, const char *filename, int strict_type) 1257b15c8340SDag-Erling Smørgrav { 1258b15c8340SDag-Erling Smørgrav FILE *f; 1259b15c8340SDag-Erling Smørgrav char line[SSH_MAX_PUBKEY_BYTES]; 1260b15c8340SDag-Erling Smørgrav char *cp; 1261b15c8340SDag-Erling Smørgrav u_long linenum = 0; 1262b15c8340SDag-Erling Smørgrav int ret = 0; 1263b15c8340SDag-Erling Smørgrav Key *pub; 1264b15c8340SDag-Erling Smørgrav int (*key_compare)(const Key *, const Key *) = strict_type ? 1265b15c8340SDag-Erling Smørgrav key_equal : key_equal_public; 1266b15c8340SDag-Erling Smørgrav 1267b15c8340SDag-Erling Smørgrav if ((f = fopen(filename, "r")) == NULL) { 1268b15c8340SDag-Erling Smørgrav if (errno == ENOENT) { 1269b15c8340SDag-Erling Smørgrav debug("%s: keyfile \"%s\" missing", __func__, filename); 1270b15c8340SDag-Erling Smørgrav return 0; 1271b15c8340SDag-Erling Smørgrav } else { 1272b15c8340SDag-Erling Smørgrav error("%s: could not open keyfile \"%s\": %s", __func__, 1273b15c8340SDag-Erling Smørgrav filename, strerror(errno)); 1274b15c8340SDag-Erling Smørgrav return -1; 1275b15c8340SDag-Erling Smørgrav } 1276b15c8340SDag-Erling Smørgrav } 1277b15c8340SDag-Erling Smørgrav 1278b15c8340SDag-Erling Smørgrav while (read_keyfile_line(f, filename, line, sizeof(line), 1279b15c8340SDag-Erling Smørgrav &linenum) != -1) { 1280b15c8340SDag-Erling Smørgrav cp = line; 1281b15c8340SDag-Erling Smørgrav 1282b15c8340SDag-Erling Smørgrav /* Skip leading whitespace. */ 1283b15c8340SDag-Erling Smørgrav for (; *cp && (*cp == ' ' || *cp == '\t'); cp++) 1284b15c8340SDag-Erling Smørgrav ; 1285b15c8340SDag-Erling Smørgrav 1286b15c8340SDag-Erling Smørgrav /* Skip comments and empty lines */ 1287b15c8340SDag-Erling Smørgrav switch (*cp) { 1288b15c8340SDag-Erling Smørgrav case '#': 1289b15c8340SDag-Erling Smørgrav case '\n': 1290b15c8340SDag-Erling Smørgrav case '\0': 1291b15c8340SDag-Erling Smørgrav continue; 1292b15c8340SDag-Erling Smørgrav } 1293b15c8340SDag-Erling Smørgrav 1294b15c8340SDag-Erling Smørgrav pub = key_new(KEY_UNSPEC); 1295b15c8340SDag-Erling Smørgrav if (key_read(pub, &cp) != 1) { 1296b15c8340SDag-Erling Smørgrav key_free(pub); 1297b15c8340SDag-Erling Smørgrav continue; 1298b15c8340SDag-Erling Smørgrav } 1299b15c8340SDag-Erling Smørgrav if (key_compare(key, pub)) { 1300b15c8340SDag-Erling Smørgrav ret = 1; 1301b15c8340SDag-Erling Smørgrav key_free(pub); 1302b15c8340SDag-Erling Smørgrav break; 1303b15c8340SDag-Erling Smørgrav } 1304b15c8340SDag-Erling Smørgrav key_free(pub); 1305b15c8340SDag-Erling Smørgrav } 1306b15c8340SDag-Erling Smørgrav fclose(f); 1307b15c8340SDag-Erling Smørgrav return ret; 1308b15c8340SDag-Erling Smørgrav } 1309