1*f7167e0eSDag-Erling Smørgrav /* $OpenBSD: hostfile.c,v 1.53 2014/01/09 23:20:00 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 * Functions for manipulating the known hosts files. 7511b41d2SMark Murray * 8c2d3a559SKris Kennaway * As far as I am concerned, the code I have written for this software 9c2d3a559SKris Kennaway * can be used freely for any purpose. Any derived versions of this 10c2d3a559SKris Kennaway * software must be clearly marked as such, and if the derived work is 11c2d3a559SKris Kennaway * incompatible with the protocol description in the RFC file, it must be 12c2d3a559SKris Kennaway * called by a name other than "ssh" or "Secure Shell". 13c2d3a559SKris Kennaway * 14c2d3a559SKris Kennaway * 15c2d3a559SKris Kennaway * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved. 16c2d3a559SKris Kennaway * Copyright (c) 1999 Niels Provos. 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" 40aa49c926SDag-Erling Smørgrav 41333ee039SDag-Erling Smørgrav #include <sys/types.h> 42333ee039SDag-Erling Smørgrav 43333ee039SDag-Erling Smørgrav #include <netinet/in.h> 44333ee039SDag-Erling Smørgrav 45aa49c926SDag-Erling Smørgrav #include <openssl/hmac.h> 46aa49c926SDag-Erling Smørgrav #include <openssl/sha.h> 47511b41d2SMark Murray 48333ee039SDag-Erling Smørgrav #include <resolv.h> 49333ee039SDag-Erling Smørgrav #include <stdarg.h> 50333ee039SDag-Erling Smørgrav #include <stdio.h> 51333ee039SDag-Erling Smørgrav #include <stdlib.h> 52333ee039SDag-Erling Smørgrav #include <string.h> 53333ee039SDag-Erling Smørgrav 54333ee039SDag-Erling Smørgrav #include "xmalloc.h" 55a8f6863aSKris Kennaway #include "match.h" 56a8f6863aSKris Kennaway #include "key.h" 57a8f6863aSKris Kennaway #include "hostfile.h" 58ca3176e7SBrian Feldman #include "log.h" 594a421b63SDag-Erling Smørgrav #include "misc.h" 60*f7167e0eSDag-Erling Smørgrav #include "digest.h" 614a421b63SDag-Erling Smørgrav 624a421b63SDag-Erling Smørgrav struct hostkeys { 634a421b63SDag-Erling Smørgrav struct hostkey_entry *entries; 644a421b63SDag-Erling Smørgrav u_int num_entries; 654a421b63SDag-Erling Smørgrav }; 66aa49c926SDag-Erling Smørgrav 67aa49c926SDag-Erling Smørgrav static int 68e4a9863fSDag-Erling Smørgrav extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len) 69aa49c926SDag-Erling Smørgrav { 70aa49c926SDag-Erling Smørgrav char *p, *b64salt; 71aa49c926SDag-Erling Smørgrav u_int b64len; 72aa49c926SDag-Erling Smørgrav int ret; 73aa49c926SDag-Erling Smørgrav 74aa49c926SDag-Erling Smørgrav if (l < sizeof(HASH_MAGIC) - 1) { 75aa49c926SDag-Erling Smørgrav debug2("extract_salt: string too short"); 76aa49c926SDag-Erling Smørgrav return (-1); 77aa49c926SDag-Erling Smørgrav } 78aa49c926SDag-Erling Smørgrav if (strncmp(s, HASH_MAGIC, sizeof(HASH_MAGIC) - 1) != 0) { 79aa49c926SDag-Erling Smørgrav debug2("extract_salt: invalid magic identifier"); 80aa49c926SDag-Erling Smørgrav return (-1); 81aa49c926SDag-Erling Smørgrav } 82aa49c926SDag-Erling Smørgrav s += sizeof(HASH_MAGIC) - 1; 83aa49c926SDag-Erling Smørgrav l -= sizeof(HASH_MAGIC) - 1; 84aa49c926SDag-Erling Smørgrav if ((p = memchr(s, HASH_DELIM, l)) == NULL) { 85aa49c926SDag-Erling Smørgrav debug2("extract_salt: missing salt termination character"); 86aa49c926SDag-Erling Smørgrav return (-1); 87aa49c926SDag-Erling Smørgrav } 88aa49c926SDag-Erling Smørgrav 89aa49c926SDag-Erling Smørgrav b64len = p - s; 90aa49c926SDag-Erling Smørgrav /* Sanity check */ 91aa49c926SDag-Erling Smørgrav if (b64len == 0 || b64len > 1024) { 92aa49c926SDag-Erling Smørgrav debug2("extract_salt: bad encoded salt length %u", b64len); 93aa49c926SDag-Erling Smørgrav return (-1); 94aa49c926SDag-Erling Smørgrav } 95aa49c926SDag-Erling Smørgrav b64salt = xmalloc(1 + b64len); 96aa49c926SDag-Erling Smørgrav memcpy(b64salt, s, b64len); 97aa49c926SDag-Erling Smørgrav b64salt[b64len] = '\0'; 98aa49c926SDag-Erling Smørgrav 99aa49c926SDag-Erling Smørgrav ret = __b64_pton(b64salt, salt, salt_len); 100e4a9863fSDag-Erling Smørgrav free(b64salt); 101aa49c926SDag-Erling Smørgrav if (ret == -1) { 102aa49c926SDag-Erling Smørgrav debug2("extract_salt: salt decode error"); 103aa49c926SDag-Erling Smørgrav return (-1); 104aa49c926SDag-Erling Smørgrav } 105aa49c926SDag-Erling Smørgrav if (ret != SHA_DIGEST_LENGTH) { 106b74df5b2SDag-Erling Smørgrav debug2("extract_salt: expected salt len %d, got %d", 107b74df5b2SDag-Erling Smørgrav SHA_DIGEST_LENGTH, ret); 108aa49c926SDag-Erling Smørgrav return (-1); 109aa49c926SDag-Erling Smørgrav } 110aa49c926SDag-Erling Smørgrav 111aa49c926SDag-Erling Smørgrav return (0); 112aa49c926SDag-Erling Smørgrav } 113aa49c926SDag-Erling Smørgrav 114aa49c926SDag-Erling Smørgrav char * 115aa49c926SDag-Erling Smørgrav host_hash(const char *host, const char *name_from_hostfile, u_int src_len) 116aa49c926SDag-Erling Smørgrav { 117aa49c926SDag-Erling Smørgrav const EVP_MD *md = EVP_sha1(); 118aa49c926SDag-Erling Smørgrav HMAC_CTX mac_ctx; 119e4a9863fSDag-Erling Smørgrav u_char salt[256], result[256]; 120e4a9863fSDag-Erling Smørgrav char uu_salt[512], uu_result[512]; 121aa49c926SDag-Erling Smørgrav static char encoded[1024]; 122aa49c926SDag-Erling Smørgrav u_int i, len; 123aa49c926SDag-Erling Smørgrav 124aa49c926SDag-Erling Smørgrav len = EVP_MD_size(md); 125aa49c926SDag-Erling Smørgrav 126aa49c926SDag-Erling Smørgrav if (name_from_hostfile == NULL) { 127aa49c926SDag-Erling Smørgrav /* Create new salt */ 128aa49c926SDag-Erling Smørgrav for (i = 0; i < len; i++) 129aa49c926SDag-Erling Smørgrav salt[i] = arc4random(); 130aa49c926SDag-Erling Smørgrav } else { 131aa49c926SDag-Erling Smørgrav /* Extract salt from known host entry */ 132aa49c926SDag-Erling Smørgrav if (extract_salt(name_from_hostfile, src_len, salt, 133aa49c926SDag-Erling Smørgrav sizeof(salt)) == -1) 134aa49c926SDag-Erling Smørgrav return (NULL); 135aa49c926SDag-Erling Smørgrav } 136aa49c926SDag-Erling Smørgrav 137aa49c926SDag-Erling Smørgrav HMAC_Init(&mac_ctx, salt, len, md); 138e4a9863fSDag-Erling Smørgrav HMAC_Update(&mac_ctx, (u_char *)host, strlen(host)); 139aa49c926SDag-Erling Smørgrav HMAC_Final(&mac_ctx, result, NULL); 140aa49c926SDag-Erling Smørgrav HMAC_cleanup(&mac_ctx); 141aa49c926SDag-Erling Smørgrav 142aa49c926SDag-Erling Smørgrav if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 || 143aa49c926SDag-Erling Smørgrav __b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1) 144aa49c926SDag-Erling Smørgrav fatal("host_hash: __b64_ntop failed"); 145aa49c926SDag-Erling Smørgrav 146aa49c926SDag-Erling Smørgrav snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt, 147aa49c926SDag-Erling Smørgrav HASH_DELIM, uu_result); 148aa49c926SDag-Erling Smørgrav 149aa49c926SDag-Erling Smørgrav return (encoded); 150aa49c926SDag-Erling Smørgrav } 151511b41d2SMark Murray 152511b41d2SMark Murray /* 153a8f6863aSKris Kennaway * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the 154a8f6863aSKris Kennaway * pointer over the key. Skips any whitespace at the beginning and at end. 155511b41d2SMark Murray */ 156511b41d2SMark Murray 157511b41d2SMark Murray int 158e4a9863fSDag-Erling Smørgrav hostfile_read_key(char **cpp, int *bitsp, Key *ret) 159511b41d2SMark Murray { 160511b41d2SMark Murray char *cp; 161511b41d2SMark Murray 162511b41d2SMark Murray /* Skip leading whitespace. */ 163511b41d2SMark Murray for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 164511b41d2SMark Murray ; 165511b41d2SMark Murray 166ca3176e7SBrian Feldman if (key_read(ret, &cp) != 1) 167511b41d2SMark Murray return 0; 168511b41d2SMark Murray 169511b41d2SMark Murray /* Skip trailing whitespace. */ 170511b41d2SMark Murray for (; *cp == ' ' || *cp == '\t'; cp++) 171511b41d2SMark Murray ; 172511b41d2SMark Murray 173511b41d2SMark Murray /* Return results. */ 174511b41d2SMark Murray *cpp = cp; 175e4a9863fSDag-Erling Smørgrav if (bitsp != NULL) { 176e4a9863fSDag-Erling Smørgrav if ((*bitsp = key_size(ret)) <= 0) 177e4a9863fSDag-Erling Smørgrav return 0; 178e4a9863fSDag-Erling Smørgrav } 179511b41d2SMark Murray return 1; 180511b41d2SMark Murray } 181511b41d2SMark Murray 182af12a3e7SDag-Erling Smørgrav static int 1834a421b63SDag-Erling Smørgrav hostfile_check_key(int bits, const Key *key, const char *host, 1844a421b63SDag-Erling Smørgrav const char *filename, u_long linenum) 185511b41d2SMark Murray { 186ca3176e7SBrian Feldman if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) 187a8f6863aSKris Kennaway return 1; 188a8f6863aSKris Kennaway if (bits != BN_num_bits(key->rsa->n)) { 1894a421b63SDag-Erling Smørgrav logit("Warning: %s, line %lu: keysize mismatch for host %s: " 190a8f6863aSKris Kennaway "actual %d vs. announced %d.", 191a8f6863aSKris Kennaway filename, linenum, host, BN_num_bits(key->rsa->n), bits); 1924a421b63SDag-Erling Smørgrav logit("Warning: replace %d with %d in %s, line %lu.", 193a8f6863aSKris Kennaway bits, BN_num_bits(key->rsa->n), filename, linenum); 194511b41d2SMark Murray } 195a8f6863aSKris Kennaway return 1; 196511b41d2SMark Murray } 197511b41d2SMark Murray 1984a421b63SDag-Erling Smørgrav static HostkeyMarker 199b15c8340SDag-Erling Smørgrav check_markers(char **cpp) 200b15c8340SDag-Erling Smørgrav { 201b15c8340SDag-Erling Smørgrav char marker[32], *sp, *cp = *cpp; 202b15c8340SDag-Erling Smørgrav int ret = MRK_NONE; 203b15c8340SDag-Erling Smørgrav 204b15c8340SDag-Erling Smørgrav while (*cp == '@') { 205b15c8340SDag-Erling Smørgrav /* Only one marker is allowed */ 206b15c8340SDag-Erling Smørgrav if (ret != MRK_NONE) 207b15c8340SDag-Erling Smørgrav return MRK_ERROR; 208b15c8340SDag-Erling Smørgrav /* Markers are terminated by whitespace */ 209b15c8340SDag-Erling Smørgrav if ((sp = strchr(cp, ' ')) == NULL && 210b15c8340SDag-Erling Smørgrav (sp = strchr(cp, '\t')) == NULL) 211b15c8340SDag-Erling Smørgrav return MRK_ERROR; 212b15c8340SDag-Erling Smørgrav /* Extract marker for comparison */ 213b15c8340SDag-Erling Smørgrav if (sp <= cp + 1 || sp >= cp + sizeof(marker)) 214b15c8340SDag-Erling Smørgrav return MRK_ERROR; 215b15c8340SDag-Erling Smørgrav memcpy(marker, cp, sp - cp); 216b15c8340SDag-Erling Smørgrav marker[sp - cp] = '\0'; 217b15c8340SDag-Erling Smørgrav if (strcmp(marker, CA_MARKER) == 0) 218b15c8340SDag-Erling Smørgrav ret = MRK_CA; 219b15c8340SDag-Erling Smørgrav else if (strcmp(marker, REVOKE_MARKER) == 0) 220b15c8340SDag-Erling Smørgrav ret = MRK_REVOKE; 221b15c8340SDag-Erling Smørgrav else 222b15c8340SDag-Erling Smørgrav return MRK_ERROR; 223b15c8340SDag-Erling Smørgrav 224b15c8340SDag-Erling Smørgrav /* Skip past marker and any whitespace that follows it */ 225b15c8340SDag-Erling Smørgrav cp = sp; 226b15c8340SDag-Erling Smørgrav for (; *cp == ' ' || *cp == '\t'; cp++) 227b15c8340SDag-Erling Smørgrav ; 228b15c8340SDag-Erling Smørgrav } 229b15c8340SDag-Erling Smørgrav *cpp = cp; 230b15c8340SDag-Erling Smørgrav return ret; 231b15c8340SDag-Erling Smørgrav } 232b15c8340SDag-Erling Smørgrav 2334a421b63SDag-Erling Smørgrav struct hostkeys * 2344a421b63SDag-Erling Smørgrav init_hostkeys(void) 2354a421b63SDag-Erling Smørgrav { 2364a421b63SDag-Erling Smørgrav struct hostkeys *ret = xcalloc(1, sizeof(*ret)); 237511b41d2SMark Murray 2384a421b63SDag-Erling Smørgrav ret->entries = NULL; 2394a421b63SDag-Erling Smørgrav return ret; 2404a421b63SDag-Erling Smørgrav } 2414a421b63SDag-Erling Smørgrav 2424a421b63SDag-Erling Smørgrav void 2434a421b63SDag-Erling Smørgrav load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path) 244511b41d2SMark Murray { 245511b41d2SMark Murray FILE *f; 246511b41d2SMark Murray char line[8192]; 2474a421b63SDag-Erling Smørgrav u_long linenum = 0, num_loaded = 0; 248aa49c926SDag-Erling Smørgrav char *cp, *cp2, *hashed_host; 2494a421b63SDag-Erling Smørgrav HostkeyMarker marker; 2504a421b63SDag-Erling Smørgrav Key *key; 2514a421b63SDag-Erling Smørgrav int kbits; 252511b41d2SMark Murray 2534a421b63SDag-Erling Smørgrav if ((f = fopen(path, "r")) == NULL) 2544a421b63SDag-Erling Smørgrav return; 2554a421b63SDag-Erling Smørgrav debug3("%s: loading entries for host \"%.100s\" from file \"%s\"", 2564a421b63SDag-Erling Smørgrav __func__, host, path); 2574a421b63SDag-Erling Smørgrav while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) { 258511b41d2SMark Murray cp = line; 259511b41d2SMark Murray 260511b41d2SMark Murray /* Skip any leading whitespace, comments and empty lines. */ 261511b41d2SMark Murray for (; *cp == ' ' || *cp == '\t'; cp++) 262511b41d2SMark Murray ; 263511b41d2SMark Murray if (!*cp || *cp == '#' || *cp == '\n') 264511b41d2SMark Murray continue; 265511b41d2SMark Murray 2664a421b63SDag-Erling Smørgrav if ((marker = check_markers(&cp)) == MRK_ERROR) { 2674a421b63SDag-Erling Smørgrav verbose("%s: invalid marker at %s:%lu", 2684a421b63SDag-Erling Smørgrav __func__, path, linenum); 269b15c8340SDag-Erling Smørgrav continue; 2704a421b63SDag-Erling Smørgrav } 271b15c8340SDag-Erling Smørgrav 272511b41d2SMark Murray /* Find the end of the host name portion. */ 273511b41d2SMark Murray for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) 274511b41d2SMark Murray ; 275511b41d2SMark Murray 276511b41d2SMark Murray /* Check if the host name matches. */ 277aa49c926SDag-Erling Smørgrav if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) { 278aa49c926SDag-Erling Smørgrav if (*cp != HASH_DELIM) 279511b41d2SMark Murray continue; 280aa49c926SDag-Erling Smørgrav hashed_host = host_hash(host, cp, (u_int) (cp2 - cp)); 281aa49c926SDag-Erling Smørgrav if (hashed_host == NULL) { 2824a421b63SDag-Erling Smørgrav debug("Invalid hashed host line %lu of %s", 2834a421b63SDag-Erling Smørgrav linenum, path); 284aa49c926SDag-Erling Smørgrav continue; 285aa49c926SDag-Erling Smørgrav } 286aa49c926SDag-Erling Smørgrav if (strncmp(hashed_host, cp, (u_int) (cp2 - cp)) != 0) 287aa49c926SDag-Erling Smørgrav continue; 288aa49c926SDag-Erling Smørgrav } 289511b41d2SMark Murray 290511b41d2SMark Murray /* Got a match. Skip host name. */ 291511b41d2SMark Murray cp = cp2; 292511b41d2SMark Murray 293511b41d2SMark Murray /* 294511b41d2SMark Murray * Extract the key from the line. This will skip any leading 295511b41d2SMark Murray * whitespace. Ignore badly formatted lines. 296511b41d2SMark Murray */ 2974a421b63SDag-Erling Smørgrav key = key_new(KEY_UNSPEC); 2984a421b63SDag-Erling Smørgrav if (!hostfile_read_key(&cp, &kbits, key)) { 2994a421b63SDag-Erling Smørgrav key_free(key); 3004a421b63SDag-Erling Smørgrav key = key_new(KEY_RSA1); 3014a421b63SDag-Erling Smørgrav if (!hostfile_read_key(&cp, &kbits, key)) { 3024a421b63SDag-Erling Smørgrav key_free(key); 3034a421b63SDag-Erling Smørgrav continue; 3044a421b63SDag-Erling Smørgrav } 3054a421b63SDag-Erling Smørgrav } 3064a421b63SDag-Erling Smørgrav if (!hostfile_check_key(kbits, key, host, path, linenum)) 307a8f6863aSKris Kennaway continue; 308511b41d2SMark Murray 3094a421b63SDag-Erling Smørgrav debug3("%s: found %skey type %s in file %s:%lu", __func__, 3104a421b63SDag-Erling Smørgrav marker == MRK_NONE ? "" : 3114a421b63SDag-Erling Smørgrav (marker == MRK_CA ? "ca " : "revoked "), 3124a421b63SDag-Erling Smørgrav key_type(key), path, linenum); 3134a421b63SDag-Erling Smørgrav hostkeys->entries = xrealloc(hostkeys->entries, 3144a421b63SDag-Erling Smørgrav hostkeys->num_entries + 1, sizeof(*hostkeys->entries)); 3154a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].host = xstrdup(host); 3164a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].file = xstrdup(path); 3174a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].line = linenum; 3184a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].key = key; 3194a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].marker = marker; 3204a421b63SDag-Erling Smørgrav hostkeys->num_entries++; 3214a421b63SDag-Erling Smørgrav num_loaded++; 3224a421b63SDag-Erling Smørgrav } 3234a421b63SDag-Erling Smørgrav debug3("%s: loaded %lu keys", __func__, num_loaded); 324333ee039SDag-Erling Smørgrav fclose(f); 3254a421b63SDag-Erling Smørgrav return; 326f388f5efSDag-Erling Smørgrav } 327f388f5efSDag-Erling Smørgrav 3284a421b63SDag-Erling Smørgrav void 3294a421b63SDag-Erling Smørgrav free_hostkeys(struct hostkeys *hostkeys) 3304a421b63SDag-Erling Smørgrav { 3314a421b63SDag-Erling Smørgrav u_int i; 332f388f5efSDag-Erling Smørgrav 3334a421b63SDag-Erling Smørgrav for (i = 0; i < hostkeys->num_entries; i++) { 334e4a9863fSDag-Erling Smørgrav free(hostkeys->entries[i].host); 335e4a9863fSDag-Erling Smørgrav free(hostkeys->entries[i].file); 3364a421b63SDag-Erling Smørgrav key_free(hostkeys->entries[i].key); 3374a421b63SDag-Erling Smørgrav bzero(hostkeys->entries + i, sizeof(*hostkeys->entries)); 338b15c8340SDag-Erling Smørgrav } 339e4a9863fSDag-Erling Smørgrav free(hostkeys->entries); 340e4a9863fSDag-Erling Smørgrav bzero(hostkeys, sizeof(*hostkeys)); 341e4a9863fSDag-Erling Smørgrav free(hostkeys); 342b15c8340SDag-Erling Smørgrav } 343b15c8340SDag-Erling Smørgrav 3444a421b63SDag-Erling Smørgrav static int 3454a421b63SDag-Erling Smørgrav check_key_not_revoked(struct hostkeys *hostkeys, Key *k) 3464a421b63SDag-Erling Smørgrav { 3474a421b63SDag-Erling Smørgrav int is_cert = key_is_cert(k); 3484a421b63SDag-Erling Smørgrav u_int i; 3494a421b63SDag-Erling Smørgrav 3504a421b63SDag-Erling Smørgrav for (i = 0; i < hostkeys->num_entries; i++) { 3514a421b63SDag-Erling Smørgrav if (hostkeys->entries[i].marker != MRK_REVOKE) 3524a421b63SDag-Erling Smørgrav continue; 3534a421b63SDag-Erling Smørgrav if (key_equal_public(k, hostkeys->entries[i].key)) 3544a421b63SDag-Erling Smørgrav return -1; 3554a421b63SDag-Erling Smørgrav if (is_cert && 3564a421b63SDag-Erling Smørgrav key_equal_public(k->cert->signature_key, 3574a421b63SDag-Erling Smørgrav hostkeys->entries[i].key)) 3584a421b63SDag-Erling Smørgrav return -1; 359511b41d2SMark Murray } 3604a421b63SDag-Erling Smørgrav return 0; 3614a421b63SDag-Erling Smørgrav } 3624a421b63SDag-Erling Smørgrav 363511b41d2SMark Murray /* 3644a421b63SDag-Erling Smørgrav * Match keys against a specified key, or look one up by key type. 3654a421b63SDag-Erling Smørgrav * 3664a421b63SDag-Erling Smørgrav * If looking for a keytype (key == NULL) and one is found then return 3674a421b63SDag-Erling Smørgrav * HOST_FOUND, otherwise HOST_NEW. 3684a421b63SDag-Erling Smørgrav * 3694a421b63SDag-Erling Smørgrav * If looking for a key (key != NULL): 3704a421b63SDag-Erling Smørgrav * 1. If the key is a cert and a matching CA is found, return HOST_OK 3714a421b63SDag-Erling Smørgrav * 2. If the key is not a cert and a matching key is found, return HOST_OK 3724a421b63SDag-Erling Smørgrav * 3. If no key matches but a key with a different type is found, then 3734a421b63SDag-Erling Smørgrav * return HOST_CHANGED 3744a421b63SDag-Erling Smørgrav * 4. If no matching keys are found, then return HOST_NEW. 3754a421b63SDag-Erling Smørgrav * 3764a421b63SDag-Erling Smørgrav * Finally, check any found key is not revoked. 377511b41d2SMark Murray */ 3784a421b63SDag-Erling Smørgrav static HostStatus 3794a421b63SDag-Erling Smørgrav check_hostkeys_by_key_or_type(struct hostkeys *hostkeys, 3804a421b63SDag-Erling Smørgrav Key *k, int keytype, const struct hostkey_entry **found) 3814a421b63SDag-Erling Smørgrav { 3824a421b63SDag-Erling Smørgrav u_int i; 3834a421b63SDag-Erling Smørgrav HostStatus end_return = HOST_NEW; 3844a421b63SDag-Erling Smørgrav int want_cert = key_is_cert(k); 3854a421b63SDag-Erling Smørgrav HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE; 3864a421b63SDag-Erling Smørgrav int proto = (k ? k->type : keytype) == KEY_RSA1 ? 1 : 2; 3874a421b63SDag-Erling Smørgrav 3884a421b63SDag-Erling Smørgrav if (found != NULL) 3894a421b63SDag-Erling Smørgrav *found = NULL; 3904a421b63SDag-Erling Smørgrav 3914a421b63SDag-Erling Smørgrav for (i = 0; i < hostkeys->num_entries; i++) { 3924a421b63SDag-Erling Smørgrav if (proto == 1 && hostkeys->entries[i].key->type != KEY_RSA1) 3934a421b63SDag-Erling Smørgrav continue; 3944a421b63SDag-Erling Smørgrav if (proto == 2 && hostkeys->entries[i].key->type == KEY_RSA1) 3954a421b63SDag-Erling Smørgrav continue; 3964a421b63SDag-Erling Smørgrav if (hostkeys->entries[i].marker != want_marker) 3974a421b63SDag-Erling Smørgrav continue; 3984a421b63SDag-Erling Smørgrav if (k == NULL) { 3994a421b63SDag-Erling Smørgrav if (hostkeys->entries[i].key->type != keytype) 4004a421b63SDag-Erling Smørgrav continue; 4014a421b63SDag-Erling Smørgrav end_return = HOST_FOUND; 4024a421b63SDag-Erling Smørgrav if (found != NULL) 4034a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 4044a421b63SDag-Erling Smørgrav k = hostkeys->entries[i].key; 4054a421b63SDag-Erling Smørgrav break; 4064a421b63SDag-Erling Smørgrav } 4074a421b63SDag-Erling Smørgrav if (want_cert) { 4084a421b63SDag-Erling Smørgrav if (key_equal_public(k->cert->signature_key, 4094a421b63SDag-Erling Smørgrav hostkeys->entries[i].key)) { 4104a421b63SDag-Erling Smørgrav /* A matching CA exists */ 4114a421b63SDag-Erling Smørgrav end_return = HOST_OK; 4124a421b63SDag-Erling Smørgrav if (found != NULL) 4134a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 4144a421b63SDag-Erling Smørgrav break; 4154a421b63SDag-Erling Smørgrav } 4164a421b63SDag-Erling Smørgrav } else { 4174a421b63SDag-Erling Smørgrav if (key_equal(k, hostkeys->entries[i].key)) { 4184a421b63SDag-Erling Smørgrav end_return = HOST_OK; 4194a421b63SDag-Erling Smørgrav if (found != NULL) 4204a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 4214a421b63SDag-Erling Smørgrav break; 4224a421b63SDag-Erling Smørgrav } 4234a421b63SDag-Erling Smørgrav /* A non-maching key exists */ 424511b41d2SMark Murray end_return = HOST_CHANGED; 4254a421b63SDag-Erling Smørgrav if (found != NULL) 4264a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 427511b41d2SMark Murray } 4284a421b63SDag-Erling Smørgrav } 4294a421b63SDag-Erling Smørgrav if (check_key_not_revoked(hostkeys, k) != 0) { 4304a421b63SDag-Erling Smørgrav end_return = HOST_REVOKED; 4314a421b63SDag-Erling Smørgrav if (found != NULL) 4324a421b63SDag-Erling Smørgrav *found = NULL; 4334a421b63SDag-Erling Smørgrav } 434511b41d2SMark Murray return end_return; 435511b41d2SMark Murray } 436511b41d2SMark Murray 437f388f5efSDag-Erling Smørgrav HostStatus 4384a421b63SDag-Erling Smørgrav check_key_in_hostkeys(struct hostkeys *hostkeys, Key *key, 4394a421b63SDag-Erling Smørgrav const struct hostkey_entry **found) 440f388f5efSDag-Erling Smørgrav { 441f388f5efSDag-Erling Smørgrav if (key == NULL) 442f388f5efSDag-Erling Smørgrav fatal("no key to look up"); 4434a421b63SDag-Erling Smørgrav return check_hostkeys_by_key_or_type(hostkeys, key, 0, found); 444f388f5efSDag-Erling Smørgrav } 445f388f5efSDag-Erling Smørgrav 446f388f5efSDag-Erling Smørgrav int 4474a421b63SDag-Erling Smørgrav lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, 4484a421b63SDag-Erling Smørgrav const struct hostkey_entry **found) 449f388f5efSDag-Erling Smørgrav { 4504a421b63SDag-Erling Smørgrav return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype, 4514a421b63SDag-Erling Smørgrav found) == HOST_FOUND); 452f388f5efSDag-Erling Smørgrav } 453f388f5efSDag-Erling Smørgrav 454511b41d2SMark Murray /* 455511b41d2SMark Murray * Appends an entry to the host file. Returns false if the entry could not 456511b41d2SMark Murray * be appended. 457511b41d2SMark Murray */ 458511b41d2SMark Murray 459511b41d2SMark Murray int 460aa49c926SDag-Erling Smørgrav add_host_to_hostfile(const char *filename, const char *host, const Key *key, 461aa49c926SDag-Erling Smørgrav int store_hash) 462511b41d2SMark Murray { 463511b41d2SMark Murray FILE *f; 464a8f6863aSKris Kennaway int success = 0; 465d4ecd108SDag-Erling Smørgrav char *hashed_host = NULL; 466aa49c926SDag-Erling Smørgrav 467a8f6863aSKris Kennaway if (key == NULL) 468e8aafc91SKris Kennaway return 1; /* XXX ? */ 469511b41d2SMark Murray f = fopen(filename, "a"); 470511b41d2SMark Murray if (!f) 471511b41d2SMark Murray return 0; 472aa49c926SDag-Erling Smørgrav 473aa49c926SDag-Erling Smørgrav if (store_hash) { 474aa49c926SDag-Erling Smørgrav if ((hashed_host = host_hash(host, NULL, 0)) == NULL) { 475aa49c926SDag-Erling Smørgrav error("add_host_to_hostfile: host_hash failed"); 476aa49c926SDag-Erling Smørgrav fclose(f); 477aa49c926SDag-Erling Smørgrav return 0; 478aa49c926SDag-Erling Smørgrav } 479aa49c926SDag-Erling Smørgrav } 480aa49c926SDag-Erling Smørgrav fprintf(f, "%s ", store_hash ? hashed_host : host); 481aa49c926SDag-Erling Smørgrav 482a8f6863aSKris Kennaway if (key_write(key, f)) { 483a8f6863aSKris Kennaway success = 1; 484a8f6863aSKris Kennaway } else { 485e8aafc91SKris Kennaway error("add_host_to_hostfile: saving key in %s failed", filename); 486511b41d2SMark Murray } 487e8aafc91SKris Kennaway fprintf(f, "\n"); 488511b41d2SMark Murray fclose(f); 489a8f6863aSKris Kennaway return success; 490511b41d2SMark Murray } 491