1 /* $OpenBSD: auth.c,v 1.12 2019/12/19 16:47:14 remi 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 ibuf *); 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 ibuf *buf) 62 { 63 u_int16_t field1 = 0xFFFF; 64 u_int16_t field2 = htons(0x01); 65 66 ibuf_add(buf, &field1, sizeof(field1)); 67 ibuf_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 if (ntohs(a->auth_offset) != *len + RIP_HDR_LEN - 148 AUTH_TRLR_HDR_LEN - MD5_DIGEST_LENGTH) { 149 log_debug("auth_validate: invalid authentication data " 150 "offset %hu, interface %s", ntohs(a->auth_offset), 151 iface->name); 152 return (-1); 153 } 154 155 auth_data = *buf; 156 auth_data += ntohs(a->auth_offset); 157 158 /* save the received digest and clear it in the packet */ 159 bcopy(auth_data, recv_digest, sizeof(recv_digest)); 160 bzero(auth_data, MD5_DIGEST_LENGTH); 161 162 /* insert plaintext key */ 163 memcpy(digest, md->key, MD5_DIGEST_LENGTH); 164 165 /* calculate MD5 digest */ 166 MD5Init(&hash); 167 MD5Update(&hash, b, ntohs(a->auth_offset) + RIP_HDR_LEN); 168 MD5Update(&hash, digest, MD5_DIGEST_LENGTH); 169 MD5Final(digest, &hash); 170 171 if (bcmp(recv_digest, digest, sizeof(digest))) { 172 log_debug("auth_validate: invalid MD5 digest, " 173 "interface %s", iface->name); 174 return (-1); 175 } 176 177 *crypt_seq_num = ntohl(a->auth_seq); 178 179 *len -= AUTH_TRLR_HDR_LEN + MD5_DIGEST_LENGTH; 180 181 break; 182 default: 183 log_debug("auth_validate: unknown auth type, interface %s", 184 iface->name); 185 return (-1); 186 } 187 188 *buf += RIP_ENTRY_LEN; 189 *len -= RIP_ENTRY_LEN; 190 191 return (0); 192 } 193 194 int 195 auth_gen(struct ibuf *buf, struct iface *iface) 196 { 197 struct rip_auth auth_head; 198 struct md5_auth a; 199 struct auth_md *md; 200 201 auth_head.auth_fixed = AUTH; 202 auth_head.auth_type = htons(iface->auth_type); 203 204 ibuf_add(buf, &auth_head, sizeof(auth_head)); 205 206 switch (iface->auth_type) { 207 case AUTH_SIMPLE: 208 ibuf_add(buf, &iface->auth_key, MAX_SIMPLE_AUTH_LEN); 209 break; 210 case AUTH_CRYPT: 211 if ((md = md_list_find(&iface->auth_md_list, 212 iface->auth_keyid)) == NULL) { 213 log_debug("auth_gen: keyid %d not configured, " 214 "interface %s", iface->auth_keyid, iface->name); 215 return (-1); 216 } 217 bzero(&a, sizeof(a)); 218 a.auth_keyid = iface->auth_keyid; 219 a.auth_seq = htonl(auth_get_seq_num(md)); 220 a.auth_length = MD5_DIGEST_LENGTH + AUTH_TRLR_HDR_LEN; 221 222 ibuf_add(buf, &a, sizeof(a)); 223 break; 224 default: 225 log_debug("auth_gen: unknown auth type, interface %s", 226 iface->name); 227 return (-1); 228 } 229 230 return (0); 231 } 232 233 int 234 auth_add_trailer(struct ibuf *buf, struct iface *iface) 235 { 236 MD5_CTX hash; 237 u_int8_t digest[MD5_DIGEST_LENGTH]; 238 struct auth_md *md; 239 struct md5_auth *a; 240 int pos; 241 242 pos = sizeof(struct rip_hdr) + sizeof(struct rip_auth); 243 244 /* add offset to header */ 245 a = ibuf_seek(buf, pos, sizeof(*a)); 246 a->auth_offset = htons(buf->wpos); 247 248 /* insert plaintext key */ 249 if ((md = md_list_find(&iface->auth_md_list, 250 iface->auth_keyid)) == NULL) { 251 log_debug("auth_add_trailer: keyid %d not configured, " 252 "interface %s", iface->auth_keyid, iface->name); 253 return (-1); 254 } 255 256 memcpy(digest, md->key, MD5_DIGEST_LENGTH); 257 258 auth_trailer_header_gen(buf); 259 260 /* calculate MD5 digest */ 261 MD5Init(&hash); 262 MD5Update(&hash, buf->buf, buf->wpos); 263 MD5Update(&hash, digest, MD5_DIGEST_LENGTH); 264 MD5Final(digest, &hash); 265 266 return (ibuf_add(buf, digest, MD5_DIGEST_LENGTH)); 267 } 268 269 /* md list */ 270 int 271 md_list_add(struct auth_md_head *head, u_int8_t keyid, char *key) 272 { 273 struct auth_md *md; 274 275 if (strlen(key) > MD5_DIGEST_LENGTH) 276 return (-1); 277 278 if ((md = md_list_find(head, keyid)) != NULL) { 279 /* update key */ 280 bzero(md->key, sizeof(md->key)); 281 memcpy(md->key, key, strlen(key)); 282 return (0); 283 } 284 285 if ((md = calloc(1, sizeof(struct auth_md))) == NULL) 286 fatalx("md_list_add"); 287 288 md->keyid = keyid; 289 memcpy(md->key, key, strlen(key)); 290 md->seq_modulator = auth_calc_modulator(md); 291 TAILQ_INSERT_TAIL(head, md, entry); 292 293 return (0); 294 } 295 296 void 297 md_list_copy(struct auth_md_head *to, struct auth_md_head *from) 298 { 299 struct auth_md *m, *md; 300 301 TAILQ_INIT(to); 302 303 TAILQ_FOREACH(m, from, entry) { 304 if ((md = calloc(1, sizeof(struct auth_md))) == NULL) 305 fatalx("md_list_copy"); 306 307 md->keyid = m->keyid; 308 memcpy(md->key, m->key, sizeof(md->key)); 309 md->seq_modulator = m->seq_modulator; 310 TAILQ_INSERT_TAIL(to, md, entry); 311 } 312 } 313 314 void 315 md_list_clr(struct auth_md_head *head) 316 { 317 struct auth_md *m; 318 319 while ((m = TAILQ_FIRST(head)) != NULL) { 320 TAILQ_REMOVE(head, m, entry); 321 free(m); 322 } 323 } 324 325 struct auth_md * 326 md_list_find(struct auth_md_head *head, u_int8_t keyid) 327 { 328 struct auth_md *m; 329 330 TAILQ_FOREACH(m, head, entry) 331 if (m->keyid == keyid) 332 return (m); 333 334 return (NULL); 335 } 336