PageRenderTime 131ms CodeModel.GetById 31ms RepoModel.GetById 1ms app.codeStats 0ms

/usr.sbin/ospfd/auth.c

https://bitbucket.org/kmv/aeriebsd-src
C | 271 lines | 195 code | 44 blank | 32 comment | 34 complexity | a88629a959e6489b52692c5685358be5 MD5 | raw file
  1. /*
  2. * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include <sys/types.h>
  17. #include <sys/socket.h>
  18. #include <limits.h>
  19. #include <md5.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include "ospfd.h"
  23. #include "ospf.h"
  24. #include "log.h"
  25. #include "ospfe.h"
  26. struct auth_md *md_list_find(struct auth_md_head *, u_int8_t);
  27. int
  28. auth_validate(void *buf, u_int16_t len, struct iface *iface, struct nbr *nbr)
  29. {
  30. MD5_CTX hash;
  31. u_int8_t digest[MD5_DIGEST_LENGTH];
  32. u_int8_t recv_digest[MD5_DIGEST_LENGTH];
  33. struct ospf_hdr *ospf_hdr = buf;
  34. struct auth_md *md;
  35. char *auth_data;
  36. if (ntohs(ospf_hdr->auth_type) != (u_int16_t)iface->auth_type) {
  37. log_debug("auth_validate: wrong auth type, interface %s",
  38. iface->name);
  39. return (-1);
  40. }
  41. switch (iface->auth_type) {
  42. case AUTH_SIMPLE:
  43. if (memcmp(ospf_hdr->auth_key.simple, iface->auth_key,
  44. sizeof(ospf_hdr->auth_key.simple))) {
  45. log_debug("auth_validate: wrong password, interface %s",
  46. iface->name);
  47. return (-1);
  48. }
  49. /* FALLTHROUGH */
  50. case AUTH_NONE:
  51. /* clear the key before chksum */
  52. bzero(ospf_hdr->auth_key.simple,
  53. sizeof(ospf_hdr->auth_key.simple));
  54. if (in_cksum(ospf_hdr, ntohs(ospf_hdr->len))) {
  55. log_debug("auth_validate: invalid checksum, "
  56. "interface %s", iface->name);
  57. return (-1);
  58. }
  59. break;
  60. case AUTH_CRYPT:
  61. /*
  62. * We must allow keys that are configured on the interface
  63. * but not necessarily set as the transmit key
  64. * (iface->auth_keyid). This allows for key rotation to new
  65. * keys without taking down the network.
  66. */
  67. if ((md = md_list_find(&iface->auth_md_list,
  68. ospf_hdr->auth_key.crypt.keyid)) == NULL) {
  69. log_debug("auth_validate: keyid %d not configured, "
  70. "interface %s", ospf_hdr->auth_key.crypt.keyid,
  71. iface->name);
  72. return (-1);
  73. }
  74. if (nbr != NULL && ntohl(ospf_hdr->auth_key.crypt.seq_num) <
  75. nbr->crypt_seq_num) {
  76. log_debug("auth_validate: decreasing seq num, "
  77. "interface %s", iface->name);
  78. return (-1);
  79. }
  80. if (ospf_hdr->auth_key.crypt.len != MD5_DIGEST_LENGTH) {
  81. log_debug("auth_validate: invalid key length, "
  82. "interface %s", iface->name);
  83. return (-1);
  84. }
  85. if (len - ntohs(ospf_hdr->len) < MD5_DIGEST_LENGTH) {
  86. log_debug("auth_validate: invalid key length, "
  87. "interface %s", iface->name);
  88. return (-1);
  89. }
  90. auth_data = buf;
  91. auth_data += ntohs(ospf_hdr->len);
  92. /* save the received digest and clear it in the packet */
  93. memcpy(recv_digest, auth_data, sizeof(recv_digest));
  94. bzero(auth_data, MD5_DIGEST_LENGTH);
  95. /* insert plaintext key */
  96. bzero(digest, MD5_DIGEST_LENGTH);
  97. strncpy(digest, md->key, MD5_DIGEST_LENGTH);
  98. /* calculate MD5 digest */
  99. MD5Init(&hash);
  100. MD5Update(&hash, buf, ntohs(ospf_hdr->len));
  101. MD5Update(&hash, digest, MD5_DIGEST_LENGTH);
  102. MD5Final(digest, &hash);
  103. if (memcmp(recv_digest, digest, sizeof(digest))) {
  104. log_debug("auth_validate: invalid MD5 digest, "
  105. "interface %s", iface->name);
  106. return (-1);
  107. }
  108. if (nbr != NULL)
  109. nbr->crypt_seq_num =
  110. ntohl(ospf_hdr->auth_key.crypt.seq_num);
  111. break;
  112. default:
  113. log_debug("auth_validate: unknown auth type, interface %s",
  114. iface->name);
  115. return (-1);
  116. }
  117. return (0);
  118. }
  119. int
  120. auth_gen(struct buf *buf, struct iface *iface)
  121. {
  122. MD5_CTX hash;
  123. u_int8_t digest[MD5_DIGEST_LENGTH];
  124. struct ospf_hdr *ospf_hdr;
  125. struct auth_md *md;
  126. if ((ospf_hdr = buf_seek(buf, 0, sizeof(ospf_hdr))) == NULL)
  127. fatalx("auth_gen: buf_seek failed");
  128. /* update length */
  129. if (buf->wpos > USHRT_MAX)
  130. fatalx("auth_gen: resulting ospf packet too big");
  131. ospf_hdr->len = htons((u_int16_t)buf->wpos);
  132. /* clear auth_key field */
  133. bzero(ospf_hdr->auth_key.simple, sizeof(ospf_hdr->auth_key.simple));
  134. switch (iface->auth_type) {
  135. case AUTH_NONE:
  136. ospf_hdr->chksum = in_cksum(buf->buf, buf->wpos);
  137. break;
  138. case AUTH_SIMPLE:
  139. ospf_hdr->chksum = in_cksum(buf->buf, buf->wpos);
  140. strncpy(ospf_hdr->auth_key.simple, iface->auth_key,
  141. sizeof(ospf_hdr->auth_key.simple));
  142. break;
  143. case AUTH_CRYPT:
  144. ospf_hdr->chksum = 0;
  145. ospf_hdr->auth_key.crypt.keyid = iface->auth_keyid;
  146. ospf_hdr->auth_key.crypt.seq_num = htonl(iface->crypt_seq_num);
  147. ospf_hdr->auth_key.crypt.len = MD5_DIGEST_LENGTH;
  148. iface->crypt_seq_num++;
  149. /* insert plaintext key */
  150. if ((md = md_list_find(&iface->auth_md_list,
  151. iface->auth_keyid)) == NULL) {
  152. log_debug("auth_gen: keyid %d not configured, "
  153. "interface %s", iface->auth_keyid, iface->name);
  154. return (-1);
  155. }
  156. bzero(digest, MD5_DIGEST_LENGTH);
  157. strncpy(digest, md->key, MD5_DIGEST_LENGTH);
  158. /* calculate MD5 digest */
  159. MD5Init(&hash);
  160. MD5Update(&hash, buf->buf, buf->wpos);
  161. MD5Update(&hash, digest, MD5_DIGEST_LENGTH);
  162. MD5Final(digest, &hash);
  163. return (buf_add(buf, digest, MD5_DIGEST_LENGTH));
  164. default:
  165. log_debug("auth_gen: unknown auth type, interface %s",
  166. iface->name);
  167. return (-1);
  168. }
  169. return (0);
  170. }
  171. /* md list */
  172. void
  173. md_list_add(struct auth_md_head *head, u_int8_t keyid, char *key)
  174. {
  175. struct auth_md *md;
  176. if ((md = md_list_find(head, keyid)) != NULL) {
  177. /* update key */
  178. strncpy(md->key, key, sizeof(md->key));
  179. return;
  180. }
  181. if ((md = calloc(1, sizeof(struct auth_md))) == NULL)
  182. fatalx("md_list_add");
  183. md->keyid = keyid;
  184. strncpy(md->key, key, sizeof(md->key));
  185. TAILQ_INSERT_TAIL(head, md, entry);
  186. }
  187. void
  188. md_list_copy(struct auth_md_head *to, struct auth_md_head *from)
  189. {
  190. struct auth_md *m, *md;
  191. TAILQ_INIT(to);
  192. TAILQ_FOREACH(m, from, entry) {
  193. if ((md = calloc(1, sizeof(struct auth_md))) == NULL)
  194. fatalx("md_list_copy");
  195. md->keyid = m->keyid;
  196. strncpy(md->key, m->key, sizeof(md->key));
  197. TAILQ_INSERT_TAIL(to, md, entry);
  198. }
  199. }
  200. void
  201. md_list_clr(struct auth_md_head *head)
  202. {
  203. struct auth_md *m;
  204. while ((m = TAILQ_FIRST(head)) != NULL) {
  205. TAILQ_REMOVE(head, m, entry);
  206. free(m);
  207. }
  208. }
  209. struct auth_md *
  210. md_list_find(struct auth_md_head *head, u_int8_t keyid)
  211. {
  212. struct auth_md *m;
  213. TAILQ_FOREACH(m, head, entry)
  214. if (m->keyid == keyid)
  215. return (m);
  216. return (NULL);
  217. }
  218. int
  219. md_list_send(struct auth_md_head *head, struct imsgbuf *to)
  220. {
  221. struct auth_md *m;
  222. TAILQ_FOREACH(m, head, entry)
  223. if (imsg_compose(to, IMSG_RECONF_AUTHMD, 0, 0, m,
  224. sizeof(*m)) == -1)
  225. return (-1);
  226. return (0);
  227. }