1 /* $OpenBSD: auth.c,v 1.9 2007/10/24 20:52:50 claudio 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 u_int8_t 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(u_int8_t **buf, u_int16_t *len, struct iface *iface, 73 struct nbr *nbr, 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 u_int8_t *auth_data; 83 u_int8_t *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 memcpy(digest, md->key, MD5_DIGEST_LENGTH); 156 157 /* calculate MD5 digest */ 158 MD5Init(&hash); 159 MD5Update(&hash, b, ntohs(a->auth_offset) + RIP_HDR_LEN); 160 MD5Update(&hash, digest, MD5_DIGEST_LENGTH); 161 MD5Final(digest, &hash); 162 163 if (bcmp(recv_digest, digest, sizeof(digest))) { 164 log_debug("auth_validate: invalid MD5 digest, " 165 "interface %s", iface->name); 166 return (-1); 167 } 168 169 *crypt_seq_num = ntohl(a->auth_seq); 170 171 *len -= AUTH_TRLR_HDR_LEN + MD5_DIGEST_LENGTH; 172 173 break; 174 default: 175 log_debug("auth_validate: unknown auth type, interface %s", 176 iface->name); 177 return (-1); 178 } 179 180 *buf += RIP_ENTRY_LEN; 181 *len -= RIP_ENTRY_LEN; 182 183 return (0); 184 } 185 186 int 187 auth_gen(struct buf *buf, struct iface *iface) 188 { 189 struct rip_auth auth_head; 190 struct md5_auth a; 191 struct auth_md *md; 192 193 auth_head.auth_fixed = AUTH; 194 auth_head.auth_type = htons(iface->auth_type); 195 196 buf_add(buf, &auth_head, sizeof(auth_head)); 197 198 switch (iface->auth_type) { 199 case AUTH_SIMPLE: 200 buf_add(buf, &iface->auth_key, MAX_SIMPLE_AUTH_LEN); 201 break; 202 case AUTH_CRYPT: 203 if ((md = md_list_find(&iface->auth_md_list, 204 iface->auth_keyid)) == NULL) { 205 log_debug("auth_gen: keyid %d not configured, " 206 "interface %s", iface->auth_keyid, iface->name); 207 return (-1); 208 } 209 bzero(&a, sizeof(a)); 210 a.auth_keyid = iface->auth_keyid; 211 a.auth_seq = htonl(auth_get_seq_num(md)); 212 a.auth_length = MD5_DIGEST_LENGTH + AUTH_TRLR_HDR_LEN; 213 214 buf_add(buf, &a, sizeof(a)); 215 break; 216 default: 217 log_debug("auth_gen: unknown auth type, interface %s", 218 iface->name); 219 return (-1); 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 memcpy(digest, md->key, MD5_DIGEST_LENGTH); 249 250 auth_trailer_header_gen(buf); 251 252 /* calculate MD5 digest */ 253 MD5Init(&hash); 254 MD5Update(&hash, buf->buf, buf->wpos); 255 MD5Update(&hash, digest, MD5_DIGEST_LENGTH); 256 MD5Final(digest, &hash); 257 258 return (buf_add(buf, digest, MD5_DIGEST_LENGTH)); 259 } 260 261 /* md list */ 262 int 263 md_list_add(struct auth_md_head *head, u_int8_t keyid, char *key) 264 { 265 struct auth_md *md; 266 267 if (strlen(key) > MD5_DIGEST_LENGTH) 268 return (-1); 269 270 if ((md = md_list_find(head, keyid)) != NULL) { 271 /* update key */ 272 bzero(md->key, sizeof(md->key)); 273 memcpy(md->key, key, strlen(key)); 274 return (0); 275 } 276 277 if ((md = calloc(1, sizeof(struct auth_md))) == NULL) 278 fatalx("md_list_add"); 279 280 md->keyid = keyid; 281 memcpy(md->key, key, strlen(key)); 282 md->seq_modulator = auth_calc_modulator(md); 283 TAILQ_INSERT_TAIL(head, md, entry); 284 285 return (0); 286 } 287 288 void 289 md_list_copy(struct auth_md_head *to, struct auth_md_head *from) 290 { 291 struct auth_md *m, *md; 292 293 TAILQ_INIT(to); 294 295 TAILQ_FOREACH(m, from, entry) { 296 if ((md = calloc(1, sizeof(struct auth_md))) == NULL) 297 fatalx("md_list_copy"); 298 299 md->keyid = m->keyid; 300 memcpy(md->key, m->key, sizeof(md->key)); 301 md->seq_modulator = m->seq_modulator; 302 TAILQ_INSERT_TAIL(to, md, entry); 303 } 304 } 305 306 void 307 md_list_clr(struct auth_md_head *head) 308 { 309 struct auth_md *m; 310 311 while ((m = TAILQ_FIRST(head)) != NULL) { 312 TAILQ_REMOVE(head, m, entry); 313 free(m); 314 } 315 } 316 317 struct auth_md * 318 md_list_find(struct auth_md_head *head, u_int8_t keyid) 319 { 320 struct auth_md *m; 321 322 TAILQ_FOREACH(m, head, entry) 323 if (m->keyid == keyid) 324 return (m); 325 326 return (NULL); 327 } 328