1*e4a9863fSDag-Erling Smørgrav /* $OpenBSD: hostfile.c,v 1.52 2013/07/12 00:19:58 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" 604a421b63SDag-Erling Smørgrav 614a421b63SDag-Erling Smørgrav struct hostkeys { 624a421b63SDag-Erling Smørgrav struct hostkey_entry *entries; 634a421b63SDag-Erling Smørgrav u_int num_entries; 644a421b63SDag-Erling Smørgrav }; 65aa49c926SDag-Erling Smørgrav 66aa49c926SDag-Erling Smørgrav static int 67*e4a9863fSDag-Erling Smørgrav extract_salt(const char *s, u_int l, u_char *salt, size_t salt_len) 68aa49c926SDag-Erling Smørgrav { 69aa49c926SDag-Erling Smørgrav char *p, *b64salt; 70aa49c926SDag-Erling Smørgrav u_int b64len; 71aa49c926SDag-Erling Smørgrav int ret; 72aa49c926SDag-Erling Smørgrav 73aa49c926SDag-Erling Smørgrav if (l < sizeof(HASH_MAGIC) - 1) { 74aa49c926SDag-Erling Smørgrav debug2("extract_salt: string too short"); 75aa49c926SDag-Erling Smørgrav return (-1); 76aa49c926SDag-Erling Smørgrav } 77aa49c926SDag-Erling Smørgrav if (strncmp(s, HASH_MAGIC, sizeof(HASH_MAGIC) - 1) != 0) { 78aa49c926SDag-Erling Smørgrav debug2("extract_salt: invalid magic identifier"); 79aa49c926SDag-Erling Smørgrav return (-1); 80aa49c926SDag-Erling Smørgrav } 81aa49c926SDag-Erling Smørgrav s += sizeof(HASH_MAGIC) - 1; 82aa49c926SDag-Erling Smørgrav l -= sizeof(HASH_MAGIC) - 1; 83aa49c926SDag-Erling Smørgrav if ((p = memchr(s, HASH_DELIM, l)) == NULL) { 84aa49c926SDag-Erling Smørgrav debug2("extract_salt: missing salt termination character"); 85aa49c926SDag-Erling Smørgrav return (-1); 86aa49c926SDag-Erling Smørgrav } 87aa49c926SDag-Erling Smørgrav 88aa49c926SDag-Erling Smørgrav b64len = p - s; 89aa49c926SDag-Erling Smørgrav /* Sanity check */ 90aa49c926SDag-Erling Smørgrav if (b64len == 0 || b64len > 1024) { 91aa49c926SDag-Erling Smørgrav debug2("extract_salt: bad encoded salt length %u", b64len); 92aa49c926SDag-Erling Smørgrav return (-1); 93aa49c926SDag-Erling Smørgrav } 94aa49c926SDag-Erling Smørgrav b64salt = xmalloc(1 + b64len); 95aa49c926SDag-Erling Smørgrav memcpy(b64salt, s, b64len); 96aa49c926SDag-Erling Smørgrav b64salt[b64len] = '\0'; 97aa49c926SDag-Erling Smørgrav 98aa49c926SDag-Erling Smørgrav ret = __b64_pton(b64salt, salt, salt_len); 99*e4a9863fSDag-Erling Smørgrav free(b64salt); 100aa49c926SDag-Erling Smørgrav if (ret == -1) { 101aa49c926SDag-Erling Smørgrav debug2("extract_salt: salt decode error"); 102aa49c926SDag-Erling Smørgrav return (-1); 103aa49c926SDag-Erling Smørgrav } 104aa49c926SDag-Erling Smørgrav if (ret != SHA_DIGEST_LENGTH) { 105b74df5b2SDag-Erling Smørgrav debug2("extract_salt: expected salt len %d, got %d", 106b74df5b2SDag-Erling Smørgrav SHA_DIGEST_LENGTH, ret); 107aa49c926SDag-Erling Smørgrav return (-1); 108aa49c926SDag-Erling Smørgrav } 109aa49c926SDag-Erling Smørgrav 110aa49c926SDag-Erling Smørgrav return (0); 111aa49c926SDag-Erling Smørgrav } 112aa49c926SDag-Erling Smørgrav 113aa49c926SDag-Erling Smørgrav char * 114aa49c926SDag-Erling Smørgrav host_hash(const char *host, const char *name_from_hostfile, u_int src_len) 115aa49c926SDag-Erling Smørgrav { 116aa49c926SDag-Erling Smørgrav const EVP_MD *md = EVP_sha1(); 117aa49c926SDag-Erling Smørgrav HMAC_CTX mac_ctx; 118*e4a9863fSDag-Erling Smørgrav u_char salt[256], result[256]; 119*e4a9863fSDag-Erling Smørgrav char uu_salt[512], uu_result[512]; 120aa49c926SDag-Erling Smørgrav static char encoded[1024]; 121aa49c926SDag-Erling Smørgrav u_int i, len; 122aa49c926SDag-Erling Smørgrav 123aa49c926SDag-Erling Smørgrav len = EVP_MD_size(md); 124aa49c926SDag-Erling Smørgrav 125aa49c926SDag-Erling Smørgrav if (name_from_hostfile == NULL) { 126aa49c926SDag-Erling Smørgrav /* Create new salt */ 127aa49c926SDag-Erling Smørgrav for (i = 0; i < len; i++) 128aa49c926SDag-Erling Smørgrav salt[i] = arc4random(); 129aa49c926SDag-Erling Smørgrav } else { 130aa49c926SDag-Erling Smørgrav /* Extract salt from known host entry */ 131aa49c926SDag-Erling Smørgrav if (extract_salt(name_from_hostfile, src_len, salt, 132aa49c926SDag-Erling Smørgrav sizeof(salt)) == -1) 133aa49c926SDag-Erling Smørgrav return (NULL); 134aa49c926SDag-Erling Smørgrav } 135aa49c926SDag-Erling Smørgrav 136aa49c926SDag-Erling Smørgrav HMAC_Init(&mac_ctx, salt, len, md); 137*e4a9863fSDag-Erling Smørgrav HMAC_Update(&mac_ctx, (u_char *)host, strlen(host)); 138aa49c926SDag-Erling Smørgrav HMAC_Final(&mac_ctx, result, NULL); 139aa49c926SDag-Erling Smørgrav HMAC_cleanup(&mac_ctx); 140aa49c926SDag-Erling Smørgrav 141aa49c926SDag-Erling Smørgrav if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 || 142aa49c926SDag-Erling Smørgrav __b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1) 143aa49c926SDag-Erling Smørgrav fatal("host_hash: __b64_ntop failed"); 144aa49c926SDag-Erling Smørgrav 145aa49c926SDag-Erling Smørgrav snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt, 146aa49c926SDag-Erling Smørgrav HASH_DELIM, uu_result); 147aa49c926SDag-Erling Smørgrav 148aa49c926SDag-Erling Smørgrav return (encoded); 149aa49c926SDag-Erling Smørgrav } 150511b41d2SMark Murray 151511b41d2SMark Murray /* 152a8f6863aSKris Kennaway * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the 153a8f6863aSKris Kennaway * pointer over the key. Skips any whitespace at the beginning and at end. 154511b41d2SMark Murray */ 155511b41d2SMark Murray 156511b41d2SMark Murray int 157*e4a9863fSDag-Erling Smørgrav hostfile_read_key(char **cpp, int *bitsp, Key *ret) 158511b41d2SMark Murray { 159511b41d2SMark Murray char *cp; 160511b41d2SMark Murray 161511b41d2SMark Murray /* Skip leading whitespace. */ 162511b41d2SMark Murray for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 163511b41d2SMark Murray ; 164511b41d2SMark Murray 165ca3176e7SBrian Feldman if (key_read(ret, &cp) != 1) 166511b41d2SMark Murray return 0; 167511b41d2SMark Murray 168511b41d2SMark Murray /* Skip trailing whitespace. */ 169511b41d2SMark Murray for (; *cp == ' ' || *cp == '\t'; cp++) 170511b41d2SMark Murray ; 171511b41d2SMark Murray 172511b41d2SMark Murray /* Return results. */ 173511b41d2SMark Murray *cpp = cp; 174*e4a9863fSDag-Erling Smørgrav if (bitsp != NULL) { 175*e4a9863fSDag-Erling Smørgrav if ((*bitsp = key_size(ret)) <= 0) 176*e4a9863fSDag-Erling Smørgrav return 0; 177*e4a9863fSDag-Erling Smørgrav } 178511b41d2SMark Murray return 1; 179511b41d2SMark Murray } 180511b41d2SMark Murray 181af12a3e7SDag-Erling Smørgrav static int 1824a421b63SDag-Erling Smørgrav hostfile_check_key(int bits, const Key *key, const char *host, 1834a421b63SDag-Erling Smørgrav const char *filename, u_long linenum) 184511b41d2SMark Murray { 185ca3176e7SBrian Feldman if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL) 186a8f6863aSKris Kennaway return 1; 187a8f6863aSKris Kennaway if (bits != BN_num_bits(key->rsa->n)) { 1884a421b63SDag-Erling Smørgrav logit("Warning: %s, line %lu: keysize mismatch for host %s: " 189a8f6863aSKris Kennaway "actual %d vs. announced %d.", 190a8f6863aSKris Kennaway filename, linenum, host, BN_num_bits(key->rsa->n), bits); 1914a421b63SDag-Erling Smørgrav logit("Warning: replace %d with %d in %s, line %lu.", 192a8f6863aSKris Kennaway bits, BN_num_bits(key->rsa->n), filename, linenum); 193511b41d2SMark Murray } 194a8f6863aSKris Kennaway return 1; 195511b41d2SMark Murray } 196511b41d2SMark Murray 1974a421b63SDag-Erling Smørgrav static HostkeyMarker 198b15c8340SDag-Erling Smørgrav check_markers(char **cpp) 199b15c8340SDag-Erling Smørgrav { 200b15c8340SDag-Erling Smørgrav char marker[32], *sp, *cp = *cpp; 201b15c8340SDag-Erling Smørgrav int ret = MRK_NONE; 202b15c8340SDag-Erling Smørgrav 203b15c8340SDag-Erling Smørgrav while (*cp == '@') { 204b15c8340SDag-Erling Smørgrav /* Only one marker is allowed */ 205b15c8340SDag-Erling Smørgrav if (ret != MRK_NONE) 206b15c8340SDag-Erling Smørgrav return MRK_ERROR; 207b15c8340SDag-Erling Smørgrav /* Markers are terminated by whitespace */ 208b15c8340SDag-Erling Smørgrav if ((sp = strchr(cp, ' ')) == NULL && 209b15c8340SDag-Erling Smørgrav (sp = strchr(cp, '\t')) == NULL) 210b15c8340SDag-Erling Smørgrav return MRK_ERROR; 211b15c8340SDag-Erling Smørgrav /* Extract marker for comparison */ 212b15c8340SDag-Erling Smørgrav if (sp <= cp + 1 || sp >= cp + sizeof(marker)) 213b15c8340SDag-Erling Smørgrav return MRK_ERROR; 214b15c8340SDag-Erling Smørgrav memcpy(marker, cp, sp - cp); 215b15c8340SDag-Erling Smørgrav marker[sp - cp] = '\0'; 216b15c8340SDag-Erling Smørgrav if (strcmp(marker, CA_MARKER) == 0) 217b15c8340SDag-Erling Smørgrav ret = MRK_CA; 218b15c8340SDag-Erling Smørgrav else if (strcmp(marker, REVOKE_MARKER) == 0) 219b15c8340SDag-Erling Smørgrav ret = MRK_REVOKE; 220b15c8340SDag-Erling Smørgrav else 221b15c8340SDag-Erling Smørgrav return MRK_ERROR; 222b15c8340SDag-Erling Smørgrav 223b15c8340SDag-Erling Smørgrav /* Skip past marker and any whitespace that follows it */ 224b15c8340SDag-Erling Smørgrav cp = sp; 225b15c8340SDag-Erling Smørgrav for (; *cp == ' ' || *cp == '\t'; cp++) 226b15c8340SDag-Erling Smørgrav ; 227b15c8340SDag-Erling Smørgrav } 228b15c8340SDag-Erling Smørgrav *cpp = cp; 229b15c8340SDag-Erling Smørgrav return ret; 230b15c8340SDag-Erling Smørgrav } 231b15c8340SDag-Erling Smørgrav 2324a421b63SDag-Erling Smørgrav struct hostkeys * 2334a421b63SDag-Erling Smørgrav init_hostkeys(void) 2344a421b63SDag-Erling Smørgrav { 2354a421b63SDag-Erling Smørgrav struct hostkeys *ret = xcalloc(1, sizeof(*ret)); 236511b41d2SMark Murray 2374a421b63SDag-Erling Smørgrav ret->entries = NULL; 2384a421b63SDag-Erling Smørgrav return ret; 2394a421b63SDag-Erling Smørgrav } 2404a421b63SDag-Erling Smørgrav 2414a421b63SDag-Erling Smørgrav void 2424a421b63SDag-Erling Smørgrav load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path) 243511b41d2SMark Murray { 244511b41d2SMark Murray FILE *f; 245511b41d2SMark Murray char line[8192]; 2464a421b63SDag-Erling Smørgrav u_long linenum = 0, num_loaded = 0; 247aa49c926SDag-Erling Smørgrav char *cp, *cp2, *hashed_host; 2484a421b63SDag-Erling Smørgrav HostkeyMarker marker; 2494a421b63SDag-Erling Smørgrav Key *key; 2504a421b63SDag-Erling Smørgrav int kbits; 251511b41d2SMark Murray 2524a421b63SDag-Erling Smørgrav if ((f = fopen(path, "r")) == NULL) 2534a421b63SDag-Erling Smørgrav return; 2544a421b63SDag-Erling Smørgrav debug3("%s: loading entries for host \"%.100s\" from file \"%s\"", 2554a421b63SDag-Erling Smørgrav __func__, host, path); 2564a421b63SDag-Erling Smørgrav while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) { 257511b41d2SMark Murray cp = line; 258511b41d2SMark Murray 259511b41d2SMark Murray /* Skip any leading whitespace, comments and empty lines. */ 260511b41d2SMark Murray for (; *cp == ' ' || *cp == '\t'; cp++) 261511b41d2SMark Murray ; 262511b41d2SMark Murray if (!*cp || *cp == '#' || *cp == '\n') 263511b41d2SMark Murray continue; 264511b41d2SMark Murray 2654a421b63SDag-Erling Smørgrav if ((marker = check_markers(&cp)) == MRK_ERROR) { 2664a421b63SDag-Erling Smørgrav verbose("%s: invalid marker at %s:%lu", 2674a421b63SDag-Erling Smørgrav __func__, path, linenum); 268b15c8340SDag-Erling Smørgrav continue; 2694a421b63SDag-Erling Smørgrav } 270b15c8340SDag-Erling Smørgrav 271511b41d2SMark Murray /* Find the end of the host name portion. */ 272511b41d2SMark Murray for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++) 273511b41d2SMark Murray ; 274511b41d2SMark Murray 275511b41d2SMark Murray /* Check if the host name matches. */ 276aa49c926SDag-Erling Smørgrav if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) { 277aa49c926SDag-Erling Smørgrav if (*cp != HASH_DELIM) 278511b41d2SMark Murray continue; 279aa49c926SDag-Erling Smørgrav hashed_host = host_hash(host, cp, (u_int) (cp2 - cp)); 280aa49c926SDag-Erling Smørgrav if (hashed_host == NULL) { 2814a421b63SDag-Erling Smørgrav debug("Invalid hashed host line %lu of %s", 2824a421b63SDag-Erling Smørgrav linenum, path); 283aa49c926SDag-Erling Smørgrav continue; 284aa49c926SDag-Erling Smørgrav } 285aa49c926SDag-Erling Smørgrav if (strncmp(hashed_host, cp, (u_int) (cp2 - cp)) != 0) 286aa49c926SDag-Erling Smørgrav continue; 287aa49c926SDag-Erling Smørgrav } 288511b41d2SMark Murray 289511b41d2SMark Murray /* Got a match. Skip host name. */ 290511b41d2SMark Murray cp = cp2; 291511b41d2SMark Murray 292511b41d2SMark Murray /* 293511b41d2SMark Murray * Extract the key from the line. This will skip any leading 294511b41d2SMark Murray * whitespace. Ignore badly formatted lines. 295511b41d2SMark Murray */ 2964a421b63SDag-Erling Smørgrav key = key_new(KEY_UNSPEC); 2974a421b63SDag-Erling Smørgrav if (!hostfile_read_key(&cp, &kbits, key)) { 2984a421b63SDag-Erling Smørgrav key_free(key); 2994a421b63SDag-Erling Smørgrav key = key_new(KEY_RSA1); 3004a421b63SDag-Erling Smørgrav if (!hostfile_read_key(&cp, &kbits, key)) { 3014a421b63SDag-Erling Smørgrav key_free(key); 3024a421b63SDag-Erling Smørgrav continue; 3034a421b63SDag-Erling Smørgrav } 3044a421b63SDag-Erling Smørgrav } 3054a421b63SDag-Erling Smørgrav if (!hostfile_check_key(kbits, key, host, path, linenum)) 306a8f6863aSKris Kennaway continue; 307511b41d2SMark Murray 3084a421b63SDag-Erling Smørgrav debug3("%s: found %skey type %s in file %s:%lu", __func__, 3094a421b63SDag-Erling Smørgrav marker == MRK_NONE ? "" : 3104a421b63SDag-Erling Smørgrav (marker == MRK_CA ? "ca " : "revoked "), 3114a421b63SDag-Erling Smørgrav key_type(key), path, linenum); 3124a421b63SDag-Erling Smørgrav hostkeys->entries = xrealloc(hostkeys->entries, 3134a421b63SDag-Erling Smørgrav hostkeys->num_entries + 1, sizeof(*hostkeys->entries)); 3144a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].host = xstrdup(host); 3154a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].file = xstrdup(path); 3164a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].line = linenum; 3174a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].key = key; 3184a421b63SDag-Erling Smørgrav hostkeys->entries[hostkeys->num_entries].marker = marker; 3194a421b63SDag-Erling Smørgrav hostkeys->num_entries++; 3204a421b63SDag-Erling Smørgrav num_loaded++; 3214a421b63SDag-Erling Smørgrav } 3224a421b63SDag-Erling Smørgrav debug3("%s: loaded %lu keys", __func__, num_loaded); 323333ee039SDag-Erling Smørgrav fclose(f); 3244a421b63SDag-Erling Smørgrav return; 325f388f5efSDag-Erling Smørgrav } 326f388f5efSDag-Erling Smørgrav 3274a421b63SDag-Erling Smørgrav void 3284a421b63SDag-Erling Smørgrav free_hostkeys(struct hostkeys *hostkeys) 3294a421b63SDag-Erling Smørgrav { 3304a421b63SDag-Erling Smørgrav u_int i; 331f388f5efSDag-Erling Smørgrav 3324a421b63SDag-Erling Smørgrav for (i = 0; i < hostkeys->num_entries; i++) { 333*e4a9863fSDag-Erling Smørgrav free(hostkeys->entries[i].host); 334*e4a9863fSDag-Erling Smørgrav free(hostkeys->entries[i].file); 3354a421b63SDag-Erling Smørgrav key_free(hostkeys->entries[i].key); 3364a421b63SDag-Erling Smørgrav bzero(hostkeys->entries + i, sizeof(*hostkeys->entries)); 337b15c8340SDag-Erling Smørgrav } 338*e4a9863fSDag-Erling Smørgrav free(hostkeys->entries); 339*e4a9863fSDag-Erling Smørgrav bzero(hostkeys, sizeof(*hostkeys)); 340*e4a9863fSDag-Erling Smørgrav free(hostkeys); 341b15c8340SDag-Erling Smørgrav } 342b15c8340SDag-Erling Smørgrav 3434a421b63SDag-Erling Smørgrav static int 3444a421b63SDag-Erling Smørgrav check_key_not_revoked(struct hostkeys *hostkeys, Key *k) 3454a421b63SDag-Erling Smørgrav { 3464a421b63SDag-Erling Smørgrav int is_cert = key_is_cert(k); 3474a421b63SDag-Erling Smørgrav u_int i; 3484a421b63SDag-Erling Smørgrav 3494a421b63SDag-Erling Smørgrav for (i = 0; i < hostkeys->num_entries; i++) { 3504a421b63SDag-Erling Smørgrav if (hostkeys->entries[i].marker != MRK_REVOKE) 3514a421b63SDag-Erling Smørgrav continue; 3524a421b63SDag-Erling Smørgrav if (key_equal_public(k, hostkeys->entries[i].key)) 3534a421b63SDag-Erling Smørgrav return -1; 3544a421b63SDag-Erling Smørgrav if (is_cert && 3554a421b63SDag-Erling Smørgrav key_equal_public(k->cert->signature_key, 3564a421b63SDag-Erling Smørgrav hostkeys->entries[i].key)) 3574a421b63SDag-Erling Smørgrav return -1; 358511b41d2SMark Murray } 3594a421b63SDag-Erling Smørgrav return 0; 3604a421b63SDag-Erling Smørgrav } 3614a421b63SDag-Erling Smørgrav 362511b41d2SMark Murray /* 3634a421b63SDag-Erling Smørgrav * Match keys against a specified key, or look one up by key type. 3644a421b63SDag-Erling Smørgrav * 3654a421b63SDag-Erling Smørgrav * If looking for a keytype (key == NULL) and one is found then return 3664a421b63SDag-Erling Smørgrav * HOST_FOUND, otherwise HOST_NEW. 3674a421b63SDag-Erling Smørgrav * 3684a421b63SDag-Erling Smørgrav * If looking for a key (key != NULL): 3694a421b63SDag-Erling Smørgrav * 1. If the key is a cert and a matching CA is found, return HOST_OK 3704a421b63SDag-Erling Smørgrav * 2. If the key is not a cert and a matching key is found, return HOST_OK 3714a421b63SDag-Erling Smørgrav * 3. If no key matches but a key with a different type is found, then 3724a421b63SDag-Erling Smørgrav * return HOST_CHANGED 3734a421b63SDag-Erling Smørgrav * 4. If no matching keys are found, then return HOST_NEW. 3744a421b63SDag-Erling Smørgrav * 3754a421b63SDag-Erling Smørgrav * Finally, check any found key is not revoked. 376511b41d2SMark Murray */ 3774a421b63SDag-Erling Smørgrav static HostStatus 3784a421b63SDag-Erling Smørgrav check_hostkeys_by_key_or_type(struct hostkeys *hostkeys, 3794a421b63SDag-Erling Smørgrav Key *k, int keytype, const struct hostkey_entry **found) 3804a421b63SDag-Erling Smørgrav { 3814a421b63SDag-Erling Smørgrav u_int i; 3824a421b63SDag-Erling Smørgrav HostStatus end_return = HOST_NEW; 3834a421b63SDag-Erling Smørgrav int want_cert = key_is_cert(k); 3844a421b63SDag-Erling Smørgrav HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE; 3854a421b63SDag-Erling Smørgrav int proto = (k ? k->type : keytype) == KEY_RSA1 ? 1 : 2; 3864a421b63SDag-Erling Smørgrav 3874a421b63SDag-Erling Smørgrav if (found != NULL) 3884a421b63SDag-Erling Smørgrav *found = NULL; 3894a421b63SDag-Erling Smørgrav 3904a421b63SDag-Erling Smørgrav for (i = 0; i < hostkeys->num_entries; i++) { 3914a421b63SDag-Erling Smørgrav if (proto == 1 && hostkeys->entries[i].key->type != KEY_RSA1) 3924a421b63SDag-Erling Smørgrav continue; 3934a421b63SDag-Erling Smørgrav if (proto == 2 && hostkeys->entries[i].key->type == KEY_RSA1) 3944a421b63SDag-Erling Smørgrav continue; 3954a421b63SDag-Erling Smørgrav if (hostkeys->entries[i].marker != want_marker) 3964a421b63SDag-Erling Smørgrav continue; 3974a421b63SDag-Erling Smørgrav if (k == NULL) { 3984a421b63SDag-Erling Smørgrav if (hostkeys->entries[i].key->type != keytype) 3994a421b63SDag-Erling Smørgrav continue; 4004a421b63SDag-Erling Smørgrav end_return = HOST_FOUND; 4014a421b63SDag-Erling Smørgrav if (found != NULL) 4024a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 4034a421b63SDag-Erling Smørgrav k = hostkeys->entries[i].key; 4044a421b63SDag-Erling Smørgrav break; 4054a421b63SDag-Erling Smørgrav } 4064a421b63SDag-Erling Smørgrav if (want_cert) { 4074a421b63SDag-Erling Smørgrav if (key_equal_public(k->cert->signature_key, 4084a421b63SDag-Erling Smørgrav hostkeys->entries[i].key)) { 4094a421b63SDag-Erling Smørgrav /* A matching CA exists */ 4104a421b63SDag-Erling Smørgrav end_return = HOST_OK; 4114a421b63SDag-Erling Smørgrav if (found != NULL) 4124a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 4134a421b63SDag-Erling Smørgrav break; 4144a421b63SDag-Erling Smørgrav } 4154a421b63SDag-Erling Smørgrav } else { 4164a421b63SDag-Erling Smørgrav if (key_equal(k, hostkeys->entries[i].key)) { 4174a421b63SDag-Erling Smørgrav end_return = HOST_OK; 4184a421b63SDag-Erling Smørgrav if (found != NULL) 4194a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 4204a421b63SDag-Erling Smørgrav break; 4214a421b63SDag-Erling Smørgrav } 4224a421b63SDag-Erling Smørgrav /* A non-maching key exists */ 423511b41d2SMark Murray end_return = HOST_CHANGED; 4244a421b63SDag-Erling Smørgrav if (found != NULL) 4254a421b63SDag-Erling Smørgrav *found = hostkeys->entries + i; 426511b41d2SMark Murray } 4274a421b63SDag-Erling Smørgrav } 4284a421b63SDag-Erling Smørgrav if (check_key_not_revoked(hostkeys, k) != 0) { 4294a421b63SDag-Erling Smørgrav end_return = HOST_REVOKED; 4304a421b63SDag-Erling Smørgrav if (found != NULL) 4314a421b63SDag-Erling Smørgrav *found = NULL; 4324a421b63SDag-Erling Smørgrav } 433511b41d2SMark Murray return end_return; 434511b41d2SMark Murray } 435511b41d2SMark Murray 436f388f5efSDag-Erling Smørgrav HostStatus 4374a421b63SDag-Erling Smørgrav check_key_in_hostkeys(struct hostkeys *hostkeys, Key *key, 4384a421b63SDag-Erling Smørgrav const struct hostkey_entry **found) 439f388f5efSDag-Erling Smørgrav { 440f388f5efSDag-Erling Smørgrav if (key == NULL) 441f388f5efSDag-Erling Smørgrav fatal("no key to look up"); 4424a421b63SDag-Erling Smørgrav return check_hostkeys_by_key_or_type(hostkeys, key, 0, found); 443f388f5efSDag-Erling Smørgrav } 444f388f5efSDag-Erling Smørgrav 445f388f5efSDag-Erling Smørgrav int 4464a421b63SDag-Erling Smørgrav lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype, 4474a421b63SDag-Erling Smørgrav const struct hostkey_entry **found) 448f388f5efSDag-Erling Smørgrav { 4494a421b63SDag-Erling Smørgrav return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype, 4504a421b63SDag-Erling Smørgrav found) == HOST_FOUND); 451f388f5efSDag-Erling Smørgrav } 452f388f5efSDag-Erling Smørgrav 453511b41d2SMark Murray /* 454511b41d2SMark Murray * Appends an entry to the host file. Returns false if the entry could not 455511b41d2SMark Murray * be appended. 456511b41d2SMark Murray */ 457511b41d2SMark Murray 458511b41d2SMark Murray int 459aa49c926SDag-Erling Smørgrav add_host_to_hostfile(const char *filename, const char *host, const Key *key, 460aa49c926SDag-Erling Smørgrav int store_hash) 461511b41d2SMark Murray { 462511b41d2SMark Murray FILE *f; 463a8f6863aSKris Kennaway int success = 0; 464d4ecd108SDag-Erling Smørgrav char *hashed_host = NULL; 465aa49c926SDag-Erling Smørgrav 466a8f6863aSKris Kennaway if (key == NULL) 467e8aafc91SKris Kennaway return 1; /* XXX ? */ 468511b41d2SMark Murray f = fopen(filename, "a"); 469511b41d2SMark Murray if (!f) 470511b41d2SMark Murray return 0; 471aa49c926SDag-Erling Smørgrav 472aa49c926SDag-Erling Smørgrav if (store_hash) { 473aa49c926SDag-Erling Smørgrav if ((hashed_host = host_hash(host, NULL, 0)) == NULL) { 474aa49c926SDag-Erling Smørgrav error("add_host_to_hostfile: host_hash failed"); 475aa49c926SDag-Erling Smørgrav fclose(f); 476aa49c926SDag-Erling Smørgrav return 0; 477aa49c926SDag-Erling Smørgrav } 478aa49c926SDag-Erling Smørgrav } 479aa49c926SDag-Erling Smørgrav fprintf(f, "%s ", store_hash ? hashed_host : host); 480aa49c926SDag-Erling Smørgrav 481a8f6863aSKris Kennaway if (key_write(key, f)) { 482a8f6863aSKris Kennaway success = 1; 483a8f6863aSKris Kennaway } else { 484e8aafc91SKris Kennaway error("add_host_to_hostfile: saving key in %s failed", filename); 485511b41d2SMark Murray } 486e8aafc91SKris Kennaway fprintf(f, "\n"); 487511b41d2SMark Murray fclose(f); 488a8f6863aSKris Kennaway return success; 489511b41d2SMark Murray } 490