1 /* $OpenBSD: auth.c,v 1.4 2006/11/27 15:02:34 stevesk Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it> 5 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <limits.h> 23 #include <md5.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "ripd.h" 28 #include "rip.h" 29 #include "log.h" 30 #include "ripe.h" 31 32 u_int32_t auth_calc_modulator(struct auth_md *md); 33 struct auth_md *md_list_find(struct auth_md_head *, u_int8_t); 34 void auth_trailer_header_gen(struct buf *); 35 u_int32_t auth_get_seq_num(struct auth_md*); 36 37 u_int32_t 38 auth_calc_modulator(struct auth_md *md) 39 { 40 u_int32_t r; 41 MD5_CTX md5ctx; 42 char digest[MD5_DIGEST_LENGTH]; 43 44 MD5Init(&md5ctx); 45 MD5Update(&md5ctx, (void *)&md->keyid, sizeof(md->keyid)); 46 MD5Update(&md5ctx, (void *)&md->key, MD5_DIGEST_LENGTH); 47 MD5Final(digest, &md5ctx); 48 49 bcopy(&digest, &r, sizeof(r)); 50 51 return ((r >> 1) - time(NULL)); 52 } 53 54 u_int32_t 55 auth_get_seq_num(struct auth_md *md) 56 { 57 return (time(NULL) + md->seq_modulator); 58 } 59 60 void 61 auth_trailer_header_gen(struct buf *buf) 62 { 63 u_int16_t field1 = 0xFFFF; 64 u_int16_t field2 = htons(0x01); 65 66 buf_add(buf, &field1, sizeof(field1)); 67 buf_add(buf, &field2, sizeof(field2)); 68 } 69 70 /* XXX add the support for key lifetime and rollover */ 71 int 72 auth_validate(char **buf, u_int16_t *len, struct iface *iface, struct nbr *nbr, 73 struct nbr_failed *nbr_failed, u_int32_t *crypt_seq_num) 74 { 75 MD5_CTX hash; 76 u_int8_t digest[MD5_DIGEST_LENGTH]; 77 u_int8_t recv_digest[MD5_DIGEST_LENGTH]; 78 char pwd[MAX_SIMPLE_AUTH_LEN]; 79 struct rip_auth *auth_head; 80 struct md5_auth *a; 81 struct auth_md *md; 82 char *auth_data; 83 char *b = *buf; 84 85 *buf += RIP_HDR_LEN; 86 *len -= RIP_HDR_LEN; 87 88 auth_head = (struct rip_auth *)(*buf); 89 90 if (auth_head->auth_fixed != AUTH) { 91 if (iface->auth_type != AUTH_NONE) { 92 log_debug("auth_validate: packet carrying no" 93 " authentication"); 94 return (-1); 95 } 96 return (0); 97 } else { 98 if (ntohs(auth_head->auth_type) != 99 (u_int16_t)iface->auth_type) { 100 log_debug("auth_validate: wrong auth type"); 101 return (-1); 102 } 103 } 104 105 switch (iface->auth_type) { 106 case AUTH_SIMPLE: 107 bcopy(*buf+sizeof(*auth_head), pwd, MAX_SIMPLE_AUTH_LEN); 108 if (bcmp(pwd, iface->auth_key, MAX_SIMPLE_AUTH_LEN)) { 109 log_debug("auth_validate: wrong password, " 110 "interface: %s", iface->name); 111 return (-1); 112 } 113 break; 114 case AUTH_CRYPT: 115 a = (struct md5_auth *)(*buf + sizeof(*auth_head)); 116 117 if ((md = md_list_find(&iface->auth_md_list, 118 a->auth_keyid)) == NULL) { 119 log_debug("auth_validate: keyid %d not configured, " 120 "interface %s", a->auth_keyid, 121 iface->name); 122 return (-1); 123 } 124 125 if (nbr != NULL) { 126 if (ntohl(a->auth_seq) < nbr->auth_seq_num) { 127 log_debug("auth_validate: decreasing seq num, " 128 "interface %s", iface->name); 129 return (-1); 130 } 131 } else if (nbr_failed != NULL) { 132 if (ntohl(a->auth_seq) < nbr_failed->auth_seq_num && 133 ntohl(a->auth_seq)) { 134 log_debug("auth_validate: decreasing seq num, " 135 "interface %s", iface->name); 136 return (-1); 137 } 138 } 139 140 /* XXX: maybe validate also the trailer header */ 141 if (a->auth_length != MD5_DIGEST_LENGTH + AUTH_TRLR_HDR_LEN) { 142 log_debug("auth_validate: invalid key length, " 143 "interface %s", iface->name); 144 return (-1); 145 } 146 147 auth_data = *buf; 148 auth_data += ntohs(a->auth_offset); 149 150 /* save the received digest and clear it in the packet */ 151 bcopy(auth_data, recv_digest, sizeof(recv_digest)); 152 bzero(auth_data, MD5_DIGEST_LENGTH); 153 154 /* insert plaintext key */ 155 bzero(digest, MD5_DIGEST_LENGTH); 156 strncpy(digest, md->key, MD5_DIGEST_LENGTH); 157 158 /* calculate MD5 digest */ 159 MD5Init(&hash); 160 MD5Update(&hash, b, ntohs(a->auth_offset) + RIP_HDR_LEN); 161 MD5Update(&hash, digest, MD5_DIGEST_LENGTH); 162 MD5Final(digest, &hash); 163 164 if (bcmp(recv_digest, digest, sizeof(digest))) { 165 log_debug("auth_validate: invalid MD5 digest, " 166 "interface %s", iface->name); 167 return (-1); 168 } 169 170 *crypt_seq_num = ntohl(a->auth_seq); 171 172 *len -= AUTH_TRLR_HDR_LEN + MD5_DIGEST_LENGTH; 173 174 break; 175 default: 176 log_debug("auth_validate: unknown auth type, interface %s", 177 iface->name); 178 return (-1); 179 } 180 181 *buf += RIP_ENTRY_LEN; 182 *len -= RIP_ENTRY_LEN; 183 184 return (0); 185 } 186 187 int 188 auth_gen(struct buf *buf, struct iface *iface) 189 { 190 struct rip_auth auth_head; 191 struct md5_auth a; 192 struct auth_md *md; 193 194 auth_head.auth_fixed = AUTH; 195 auth_head.auth_type = htons(iface->auth_type); 196 197 buf_add(buf, &auth_head, sizeof(auth_head)); 198 199 switch (iface->auth_type) { 200 case AUTH_SIMPLE: 201 return (buf_add(buf, &iface->auth_key, MAX_SIMPLE_AUTH_LEN)); 202 break; 203 case AUTH_CRYPT: 204 if ((md = md_list_find(&iface->auth_md_list, 205 iface->auth_keyid)) == NULL) { 206 log_debug("auth_gen: keyid %d not configured, " 207 "interface %s", iface->auth_keyid, iface->name); 208 return (-1); 209 } 210 bzero(&a, sizeof(a)); 211 a.auth_keyid = iface->auth_keyid; 212 a.auth_seq = htonl(auth_get_seq_num(md)); 213 a.auth_length = MD5_DIGEST_LENGTH + AUTH_TRLR_HDR_LEN; 214 215 return (buf_add(buf, &a, sizeof(a))); 216 break; 217 default: 218 /* NOTREACHED */ 219 break; 220 } 221 222 return (0); 223 } 224 225 int 226 auth_add_trailer(struct buf *buf, struct iface *iface) 227 { 228 MD5_CTX hash; 229 u_int8_t digest[MD5_DIGEST_LENGTH]; 230 struct auth_md *md; 231 struct md5_auth *a; 232 int pos; 233 234 pos = sizeof(struct rip_hdr) + sizeof(struct rip_auth); 235 236 /* add offset to header */ 237 a = buf_seek(buf, pos, sizeof(*a)); 238 a->auth_offset = htons(buf->wpos); 239 240 /* insert plaintext key */ 241 if ((md = md_list_find(&iface->auth_md_list, 242 iface->auth_keyid)) == NULL) { 243 log_debug("auth_add_trailer: keyid %d not configured, " 244 "interface %s", iface->auth_keyid, iface->name); 245 return (-1); 246 } 247 248 bzero(digest, MD5_DIGEST_LENGTH); 249 strncpy(digest, md->key, MD5_DIGEST_LENGTH); 250 251 auth_trailer_header_gen(buf); 252 253 /* calculate MD5 digest */ 254 MD5Init(&hash); 255 MD5Update(&hash, buf->buf, buf->wpos); 256 MD5Update(&hash, digest, MD5_DIGEST_LENGTH); 257 MD5Final(digest, &hash); 258 259 return (buf_add(buf, digest, MD5_DIGEST_LENGTH)); 260 } 261 262 /* md list */ 263 void 264 md_list_add(struct auth_md_head *head, u_int8_t keyid, char *key) 265 { 266 struct auth_md *md; 267 268 if ((md = md_list_find(head, keyid)) != NULL) { 269 /* update key */ 270 strncpy(md->key, key, sizeof(md->key)); 271 return; 272 } 273 274 if ((md = calloc(1, sizeof(struct auth_md))) == NULL) 275 fatalx("md_list_add"); 276 277 md->keyid = keyid; 278 strncpy(md->key, key, sizeof(md->key)); 279 md->seq_modulator = auth_calc_modulator(md); 280 TAILQ_INSERT_TAIL(head, md, entry); 281 } 282 283 void 284 md_list_copy(struct auth_md_head *to, struct auth_md_head *from) 285 { 286 struct auth_md *m, *md; 287 288 TAILQ_INIT(to); 289 290 TAILQ_FOREACH(m, from, entry) { 291 if ((md = calloc(1, sizeof(struct auth_md))) == NULL) 292 fatalx("md_list_copy"); 293 294 md->keyid = m->keyid; 295 strncpy(md->key, m->key, sizeof(md->key)); 296 md->seq_modulator = m->seq_modulator; 297 TAILQ_INSERT_TAIL(to, md, entry); 298 } 299 } 300 301 void 302 md_list_clr(struct auth_md_head *head) 303 { 304 struct auth_md *m; 305 306 while ((m = TAILQ_FIRST(head)) != NULL) { 307 TAILQ_REMOVE(head, m, entry); 308 free(m); 309 } 310 } 311 312 struct auth_md * 313 md_list_find(struct auth_md_head *head, u_int8_t keyid) 314 { 315 struct auth_md *m; 316 317 TAILQ_FOREACH(m, head, entry) 318 if (m->keyid == keyid) 319 return (m); 320 321 return (NULL); 322 } 323