PageRenderTime 43ms CodeModel.GetById 12ms RepoModel.GetById 0ms app.codeStats 0ms

/src/netbsd/src/crypto/external/bsd/openssh/dist/hostfile.c

https://bitbucket.org/killerpenguinassassins/open_distrib_devel
C | 488 lines | 354 code | 53 blank | 81 comment | 145 complexity | 657ace4defa7a3a337a674f5177f6e39 MD5 | raw file
Possible License(s): CC0-1.0, MIT, LGPL-2.0, LGPL-3.0, WTFPL, GPL-2.0, BSD-2-Clause, AGPL-3.0, CC-BY-SA-3.0, MPL-2.0, JSON, BSD-3-Clause-No-Nuclear-License-2014, LGPL-2.1, CPL-1.0, AGPL-1.0, 0BSD, ISC, Apache-2.0, GPL-3.0, IPL-1.0, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /* $NetBSD: hostfile.c,v 1.4 2011/07/25 03:03:10 christos Exp $ */
  2. /* $OpenBSD: hostfile.c,v 1.50 2010/12/04 13:31:37 djm Exp $ */
  3. /*
  4. * Author: Tatu Ylonen <ylo@cs.hut.fi>
  5. * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
  6. * All rights reserved
  7. * Functions for manipulating the known hosts files.
  8. *
  9. * As far as I am concerned, the code I have written for this software
  10. * can be used freely for any purpose. Any derived versions of this
  11. * software must be clearly marked as such, and if the derived work is
  12. * incompatible with the protocol description in the RFC file, it must be
  13. * called by a name other than "ssh" or "Secure Shell".
  14. *
  15. *
  16. * Copyright (c) 1999, 2000 Markus Friedl. All rights reserved.
  17. * Copyright (c) 1999 Niels Provos. All rights reserved.
  18. *
  19. * Redistribution and use in source and binary forms, with or without
  20. * modification, are permitted provided that the following conditions
  21. * are met:
  22. * 1. Redistributions of source code must retain the above copyright
  23. * notice, this list of conditions and the following disclaimer.
  24. * 2. Redistributions in binary form must reproduce the above copyright
  25. * notice, this list of conditions and the following disclaimer in the
  26. * documentation and/or other materials provided with the distribution.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  29. * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  31. * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  32. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  33. * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  34. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  35. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  36. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  37. * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. */
  39. #include "includes.h"
  40. __RCSID("$NetBSD: hostfile.c,v 1.4 2011/07/25 03:03:10 christos Exp $");
  41. #include <sys/types.h>
  42. #include <netinet/in.h>
  43. #include <openssl/hmac.h>
  44. #include <openssl/sha.h>
  45. #include <resolv.h>
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #include "xmalloc.h"
  50. #include "match.h"
  51. #include "key.h"
  52. #include "hostfile.h"
  53. #include "log.h"
  54. #include "misc.h"
  55. struct hostkeys {
  56. struct hostkey_entry *entries;
  57. u_int num_entries;
  58. };
  59. static int
  60. extract_salt(const char *s, u_int l, char *salt, size_t salt_len)
  61. {
  62. char *p, *b64salt;
  63. u_int b64len;
  64. int ret;
  65. if (l < sizeof(HASH_MAGIC) - 1) {
  66. debug2("extract_salt: string too short");
  67. return (-1);
  68. }
  69. if (strncmp(s, HASH_MAGIC, sizeof(HASH_MAGIC) - 1) != 0) {
  70. debug2("extract_salt: invalid magic identifier");
  71. return (-1);
  72. }
  73. s += sizeof(HASH_MAGIC) - 1;
  74. l -= sizeof(HASH_MAGIC) - 1;
  75. if ((p = memchr(s, HASH_DELIM, l)) == NULL) {
  76. debug2("extract_salt: missing salt termination character");
  77. return (-1);
  78. }
  79. b64len = p - s;
  80. /* Sanity check */
  81. if (b64len == 0 || b64len > 1024) {
  82. debug2("extract_salt: bad encoded salt length %u", b64len);
  83. return (-1);
  84. }
  85. b64salt = xmalloc(1 + b64len);
  86. memcpy(b64salt, s, b64len);
  87. b64salt[b64len] = '\0';
  88. ret = __b64_pton(b64salt, salt, salt_len);
  89. xfree(b64salt);
  90. if (ret == -1) {
  91. debug2("extract_salt: salt decode error");
  92. return (-1);
  93. }
  94. if (ret != SHA_DIGEST_LENGTH) {
  95. debug2("extract_salt: expected salt len %d, got %d",
  96. SHA_DIGEST_LENGTH, ret);
  97. return (-1);
  98. }
  99. return (0);
  100. }
  101. char *
  102. host_hash(const char *host, const char *name_from_hostfile, u_int src_len)
  103. {
  104. const EVP_MD *md = EVP_sha1();
  105. HMAC_CTX mac_ctx;
  106. char salt[256], result[256], uu_salt[512], uu_result[512];
  107. static char encoded[1024];
  108. u_int i, len;
  109. len = EVP_MD_size(md);
  110. if (name_from_hostfile == NULL) {
  111. /* Create new salt */
  112. for (i = 0; i < len; i++)
  113. salt[i] = arc4random();
  114. } else {
  115. /* Extract salt from known host entry */
  116. if (extract_salt(name_from_hostfile, src_len, salt,
  117. sizeof(salt)) == -1)
  118. return (NULL);
  119. }
  120. HMAC_Init(&mac_ctx, salt, len, md);
  121. HMAC_Update(&mac_ctx, host, strlen(host));
  122. HMAC_Final(&mac_ctx, result, NULL);
  123. HMAC_cleanup(&mac_ctx);
  124. if (__b64_ntop(salt, len, uu_salt, sizeof(uu_salt)) == -1 ||
  125. __b64_ntop(result, len, uu_result, sizeof(uu_result)) == -1)
  126. fatal("host_hash: __b64_ntop failed");
  127. snprintf(encoded, sizeof(encoded), "%s%s%c%s", HASH_MAGIC, uu_salt,
  128. HASH_DELIM, uu_result);
  129. return (encoded);
  130. }
  131. /*
  132. * Parses an RSA (number of bits, e, n) or DSA key from a string. Moves the
  133. * pointer over the key. Skips any whitespace at the beginning and at end.
  134. */
  135. int
  136. hostfile_read_key(char **cpp, u_int *bitsp, Key *ret)
  137. {
  138. char *cp;
  139. /* Skip leading whitespace. */
  140. for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++)
  141. ;
  142. if (key_read(ret, &cp) != 1)
  143. return 0;
  144. /* Skip trailing whitespace. */
  145. for (; *cp == ' ' || *cp == '\t'; cp++)
  146. ;
  147. /* Return results. */
  148. *cpp = cp;
  149. if (bitsp != NULL)
  150. *bitsp = key_size(ret);
  151. return 1;
  152. }
  153. static int
  154. hostfile_check_key(int bits, const Key *key, const char *host,
  155. const char *filename, u_long linenum)
  156. {
  157. if (key == NULL || key->type != KEY_RSA1 || key->rsa == NULL)
  158. return 1;
  159. if (bits != BN_num_bits(key->rsa->n)) {
  160. logit("Warning: %s, line %lu: keysize mismatch for host %s: "
  161. "actual %d vs. announced %d.",
  162. filename, linenum, host, BN_num_bits(key->rsa->n), bits);
  163. logit("Warning: replace %d with %d in %s, line %lu.",
  164. bits, BN_num_bits(key->rsa->n), filename, linenum);
  165. }
  166. return 1;
  167. }
  168. static HostkeyMarker
  169. check_markers(char **cpp)
  170. {
  171. char marker[32], *sp, *cp = *cpp;
  172. int ret = MRK_NONE;
  173. while (*cp == '@') {
  174. /* Only one marker is allowed */
  175. if (ret != MRK_NONE)
  176. return MRK_ERROR;
  177. /* Markers are terminated by whitespace */
  178. if ((sp = strchr(cp, ' ')) == NULL &&
  179. (sp = strchr(cp, '\t')) == NULL)
  180. return MRK_ERROR;
  181. /* Extract marker for comparison */
  182. if (sp <= cp + 1 || sp >= cp + sizeof(marker))
  183. return MRK_ERROR;
  184. memcpy(marker, cp, sp - cp);
  185. marker[sp - cp] = '\0';
  186. if (strcmp(marker, CA_MARKER) == 0)
  187. ret = MRK_CA;
  188. else if (strcmp(marker, REVOKE_MARKER) == 0)
  189. ret = MRK_REVOKE;
  190. else
  191. return MRK_ERROR;
  192. /* Skip past marker and any whitespace that follows it */
  193. cp = sp;
  194. for (; *cp == ' ' || *cp == '\t'; cp++)
  195. ;
  196. }
  197. *cpp = cp;
  198. return ret;
  199. }
  200. struct hostkeys *
  201. init_hostkeys(void)
  202. {
  203. struct hostkeys *ret = xcalloc(1, sizeof(*ret));
  204. ret->entries = NULL;
  205. return ret;
  206. }
  207. void
  208. load_hostkeys(struct hostkeys *hostkeys, const char *host, const char *path)
  209. {
  210. FILE *f;
  211. char line[8192];
  212. u_long linenum = 0, num_loaded = 0;
  213. char *cp, *cp2, *hashed_host;
  214. HostkeyMarker marker;
  215. Key *key;
  216. int kbits;
  217. if ((f = fopen(path, "r")) == NULL)
  218. return;
  219. debug3("%s: loading entries for host \"%.100s\" from file \"%s\"",
  220. __func__, host, path);
  221. while (read_keyfile_line(f, path, line, sizeof(line), &linenum) == 0) {
  222. cp = line;
  223. /* Skip any leading whitespace, comments and empty lines. */
  224. for (; *cp == ' ' || *cp == '\t'; cp++)
  225. ;
  226. if (!*cp || *cp == '#' || *cp == '\n')
  227. continue;
  228. if ((marker = check_markers(&cp)) == MRK_ERROR) {
  229. verbose("%s: invalid marker at %s:%lu",
  230. __func__, path, linenum);
  231. continue;
  232. }
  233. /* Find the end of the host name portion. */
  234. for (cp2 = cp; *cp2 && *cp2 != ' ' && *cp2 != '\t'; cp2++)
  235. ;
  236. /* Check if the host name matches. */
  237. if (match_hostname(host, cp, (u_int) (cp2 - cp)) != 1) {
  238. if (*cp != HASH_DELIM)
  239. continue;
  240. hashed_host = host_hash(host, cp, (u_int) (cp2 - cp));
  241. if (hashed_host == NULL) {
  242. debug("Invalid hashed host line %lu of %s",
  243. linenum, path);
  244. continue;
  245. }
  246. if (strncmp(hashed_host, cp, (u_int) (cp2 - cp)) != 0)
  247. continue;
  248. }
  249. /* Got a match. Skip host name. */
  250. cp = cp2;
  251. /*
  252. * Extract the key from the line. This will skip any leading
  253. * whitespace. Ignore badly formatted lines.
  254. */
  255. key = key_new(KEY_UNSPEC);
  256. if (!hostfile_read_key(&cp, &kbits, key)) {
  257. key_free(key);
  258. key = key_new(KEY_RSA1);
  259. if (!hostfile_read_key(&cp, &kbits, key)) {
  260. key_free(key);
  261. continue;
  262. }
  263. }
  264. if (!hostfile_check_key(kbits, key, host, path, linenum))
  265. continue;
  266. debug3("%s: found %skey type %s in file %s:%lu", __func__,
  267. marker == MRK_NONE ? "" :
  268. (marker == MRK_CA ? "ca " : "revoked "),
  269. key_type(key), path, linenum);
  270. hostkeys->entries = xrealloc(hostkeys->entries,
  271. hostkeys->num_entries + 1, sizeof(*hostkeys->entries));
  272. hostkeys->entries[hostkeys->num_entries].host = xstrdup(host);
  273. hostkeys->entries[hostkeys->num_entries].file = xstrdup(path);
  274. hostkeys->entries[hostkeys->num_entries].line = linenum;
  275. hostkeys->entries[hostkeys->num_entries].key = key;
  276. hostkeys->entries[hostkeys->num_entries].marker = marker;
  277. hostkeys->num_entries++;
  278. num_loaded++;
  279. }
  280. debug3("%s: loaded %lu keys", __func__, num_loaded);
  281. fclose(f);
  282. return;
  283. }
  284. void
  285. free_hostkeys(struct hostkeys *hostkeys)
  286. {
  287. u_int i;
  288. for (i = 0; i < hostkeys->num_entries; i++) {
  289. xfree(hostkeys->entries[i].host);
  290. xfree(hostkeys->entries[i].file);
  291. key_free(hostkeys->entries[i].key);
  292. bzero(hostkeys->entries + i, sizeof(*hostkeys->entries));
  293. }
  294. if (hostkeys->entries != NULL)
  295. xfree(hostkeys->entries);
  296. hostkeys->entries = NULL;
  297. hostkeys->num_entries = 0;
  298. xfree(hostkeys);
  299. }
  300. static int
  301. check_key_not_revoked(struct hostkeys *hostkeys, Key *k)
  302. {
  303. int is_cert = key_is_cert(k);
  304. u_int i;
  305. for (i = 0; i < hostkeys->num_entries; i++) {
  306. if (hostkeys->entries[i].marker != MRK_REVOKE)
  307. continue;
  308. if (key_equal_public(k, hostkeys->entries[i].key))
  309. return -1;
  310. if (is_cert &&
  311. key_equal_public(k->cert->signature_key,
  312. hostkeys->entries[i].key))
  313. return -1;
  314. }
  315. return 0;
  316. }
  317. /*
  318. * Match keys against a specified key, or look one up by key type.
  319. *
  320. * If looking for a keytype (key == NULL) and one is found then return
  321. * HOST_FOUND, otherwise HOST_NEW.
  322. *
  323. * If looking for a key (key != NULL):
  324. * 1. If the key is a cert and a matching CA is found, return HOST_OK
  325. * 2. If the key is not a cert and a matching key is found, return HOST_OK
  326. * 3. If no key matches but a key with a different type is found, then
  327. * return HOST_CHANGED
  328. * 4. If no matching keys are found, then return HOST_NEW.
  329. *
  330. * Finally, check any found key is not revoked.
  331. */
  332. static HostStatus
  333. check_hostkeys_by_key_or_type(struct hostkeys *hostkeys,
  334. Key *k, int keytype, const struct hostkey_entry **found)
  335. {
  336. u_int i;
  337. HostStatus end_return = HOST_NEW;
  338. int want_cert = key_is_cert(k);
  339. HostkeyMarker want_marker = want_cert ? MRK_CA : MRK_NONE;
  340. int proto = (k ? k->type : keytype) == KEY_RSA1 ? 1 : 2;
  341. if (found != NULL)
  342. *found = NULL;
  343. for (i = 0; i < hostkeys->num_entries; i++) {
  344. if (proto == 1 && hostkeys->entries[i].key->type != KEY_RSA1)
  345. continue;
  346. if (proto == 2 && hostkeys->entries[i].key->type == KEY_RSA1)
  347. continue;
  348. if (hostkeys->entries[i].marker != want_marker)
  349. continue;
  350. if (k == NULL) {
  351. if (hostkeys->entries[i].key->type != keytype)
  352. continue;
  353. end_return = HOST_FOUND;
  354. if (found != NULL)
  355. *found = hostkeys->entries + i;
  356. k = hostkeys->entries[i].key;
  357. break;
  358. }
  359. if (want_cert) {
  360. if (key_equal_public(k->cert->signature_key,
  361. hostkeys->entries[i].key)) {
  362. /* A matching CA exists */
  363. end_return = HOST_OK;
  364. if (found != NULL)
  365. *found = hostkeys->entries + i;
  366. break;
  367. }
  368. } else {
  369. if (key_equal(k, hostkeys->entries[i].key)) {
  370. end_return = HOST_OK;
  371. if (found != NULL)
  372. *found = hostkeys->entries + i;
  373. break;
  374. }
  375. /* A non-maching key exists */
  376. end_return = HOST_CHANGED;
  377. if (found != NULL)
  378. *found = hostkeys->entries + i;
  379. }
  380. }
  381. if (check_key_not_revoked(hostkeys, k) != 0) {
  382. end_return = HOST_REVOKED;
  383. if (found != NULL)
  384. *found = NULL;
  385. }
  386. return end_return;
  387. }
  388. HostStatus
  389. check_key_in_hostkeys(struct hostkeys *hostkeys, Key *key,
  390. const struct hostkey_entry **found)
  391. {
  392. if (key == NULL)
  393. fatal("no key to look up");
  394. return check_hostkeys_by_key_or_type(hostkeys, key, 0, found);
  395. }
  396. int
  397. lookup_key_in_hostkeys_by_type(struct hostkeys *hostkeys, int keytype,
  398. const struct hostkey_entry **found)
  399. {
  400. return (check_hostkeys_by_key_or_type(hostkeys, NULL, keytype,
  401. found) == HOST_FOUND);
  402. }
  403. /*
  404. * Appends an entry to the host file. Returns false if the entry could not
  405. * be appended.
  406. */
  407. int
  408. add_host_to_hostfile(const char *filename, const char *host, const Key *key,
  409. int store_hash)
  410. {
  411. FILE *f;
  412. int success = 0;
  413. char *hashed_host = NULL;
  414. if (key == NULL)
  415. return 1; /* XXX ? */
  416. f = fopen(filename, "a");
  417. if (!f)
  418. return 0;
  419. if (store_hash) {
  420. if ((hashed_host = host_hash(host, NULL, 0)) == NULL) {
  421. error("add_host_to_hostfile: host_hash failed");
  422. fclose(f);
  423. return 0;
  424. }
  425. }
  426. fprintf(f, "%s ", store_hash ? hashed_host : host);
  427. if (key_write(key, f)) {
  428. success = 1;
  429. } else {
  430. error("add_host_to_hostfile: saving key in %s failed", filename);
  431. }
  432. fprintf(f, "\n");
  433. fclose(f);
  434. return success;
  435. }