xref: /openbsd-src/usr.sbin/ripd/auth.c (revision e6c7c102cf5d9891f32552a42895134a59937045)
1*e6c7c102Sjsg /*	$OpenBSD: auth.c,v 1.14 2024/04/23 13:34:51 jsg Exp $ */
2ddeeec14Snorby 
3ddeeec14Snorby /*
4ddeeec14Snorby  * Copyright (c) 2006 Michele Marchetto <mydecay@openbeer.it>
5ddeeec14Snorby  * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
6ddeeec14Snorby  *
7ddeeec14Snorby  * Permission to use, copy, modify, and distribute this software for any
8ddeeec14Snorby  * purpose with or without fee is hereby granted, provided that the above
9ddeeec14Snorby  * copyright notice and this permission notice appear in all copies.
10ddeeec14Snorby  *
11ddeeec14Snorby  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12ddeeec14Snorby  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13ddeeec14Snorby  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14ddeeec14Snorby  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15ddeeec14Snorby  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16ddeeec14Snorby  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17ddeeec14Snorby  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18ddeeec14Snorby  */
19ddeeec14Snorby 
20ddeeec14Snorby #include <sys/types.h>
21ddeeec14Snorby #include <sys/socket.h>
22ddeeec14Snorby #include <limits.h>
23ddeeec14Snorby #include <md5.h>
24eaa1bd4eSclaudio #include <stddef.h>
25ddeeec14Snorby #include <stdlib.h>
26ddeeec14Snorby #include <string.h>
27ddeeec14Snorby 
28ddeeec14Snorby #include "ripd.h"
29ddeeec14Snorby #include "rip.h"
30ddeeec14Snorby #include "log.h"
31ddeeec14Snorby #include "ripe.h"
32ddeeec14Snorby 
33652c17a6Smcbride u_int32_t	 auth_calc_modulator(struct auth_md *md);
34ddeeec14Snorby struct auth_md	*md_list_find(struct auth_md_head *, u_int8_t);
35e39620e5Snicm void		 auth_trailer_header_gen(struct ibuf *);
36652c17a6Smcbride u_int32_t	 auth_get_seq_num(struct auth_md*);
37ddeeec14Snorby 
38ddeeec14Snorby u_int32_t
auth_calc_modulator(struct auth_md * md)39652c17a6Smcbride auth_calc_modulator(struct auth_md *md)
40ddeeec14Snorby {
41652c17a6Smcbride 	u_int32_t		r;
42652c17a6Smcbride 	MD5_CTX			md5ctx;
43cea1eb29Sderaadt 	u_int8_t		digest[MD5_DIGEST_LENGTH];
44652c17a6Smcbride 
45652c17a6Smcbride 	MD5Init(&md5ctx);
46652c17a6Smcbride 	MD5Update(&md5ctx, (void *)&md->keyid, sizeof(md->keyid));
47652c17a6Smcbride 	MD5Update(&md5ctx, (void *)&md->key, MD5_DIGEST_LENGTH);
48652c17a6Smcbride 	MD5Final(digest, &md5ctx);
49652c17a6Smcbride 
50652c17a6Smcbride 	bcopy(&digest, &r, sizeof(r));
51652c17a6Smcbride 
52652c17a6Smcbride 	return ((r >> 1) - time(NULL));
53652c17a6Smcbride }
54652c17a6Smcbride 
55652c17a6Smcbride u_int32_t
auth_get_seq_num(struct auth_md * md)56652c17a6Smcbride auth_get_seq_num(struct auth_md *md)
57652c17a6Smcbride {
58652c17a6Smcbride 	return (time(NULL) + md->seq_modulator);
59ddeeec14Snorby }
60ddeeec14Snorby 
61ddeeec14Snorby void
auth_trailer_header_gen(struct ibuf * buf)62e39620e5Snicm auth_trailer_header_gen(struct ibuf *buf)
63ddeeec14Snorby {
64ddeeec14Snorby 	u_int16_t	 field1 = 0xFFFF;
65ddeeec14Snorby 	u_int16_t	 field2 = htons(0x01);
66ddeeec14Snorby 
67e39620e5Snicm 	ibuf_add(buf, &field1, sizeof(field1));
68e39620e5Snicm 	ibuf_add(buf, &field2, sizeof(field2));
69ddeeec14Snorby }
70ddeeec14Snorby 
71ddeeec14Snorby /* XXX add the support for key lifetime and rollover */
72ddeeec14Snorby int
auth_validate(u_int8_t ** buf,u_int16_t * len,struct iface * iface,struct nbr * nbr,struct nbr_failed * nbr_failed,u_int32_t * crypt_seq_num)7387feb355Sclaudio auth_validate(u_int8_t **buf, u_int16_t *len, struct iface *iface,
7487feb355Sclaudio     struct nbr *nbr, struct nbr_failed *nbr_failed, u_int32_t *crypt_seq_num)
75ddeeec14Snorby {
76ddeeec14Snorby 	MD5_CTX			 hash;
77ddeeec14Snorby 	u_int8_t		 digest[MD5_DIGEST_LENGTH];
78ddeeec14Snorby 	u_int8_t		 recv_digest[MD5_DIGEST_LENGTH];
79ddeeec14Snorby 	char			 pwd[MAX_SIMPLE_AUTH_LEN];
80ddeeec14Snorby 	struct rip_auth		*auth_head;
81ddeeec14Snorby 	struct md5_auth		*a;
82ddeeec14Snorby 	struct auth_md		*md;
8387feb355Sclaudio 	u_int8_t		*auth_data;
8487feb355Sclaudio 	u_int8_t		*b = *buf;
85ddeeec14Snorby 
86ddeeec14Snorby 	*buf += RIP_HDR_LEN;
87ddeeec14Snorby 	*len -= RIP_HDR_LEN;
88ddeeec14Snorby 
89ddeeec14Snorby 	auth_head = (struct rip_auth *)(*buf);
90ddeeec14Snorby 
91ddeeec14Snorby 	if (auth_head->auth_fixed != AUTH) {
92ddeeec14Snorby 		if (iface->auth_type != AUTH_NONE) {
93ddeeec14Snorby 			log_debug("auth_validate: packet carrying no"
94ddeeec14Snorby 			    " authentication");
95ddeeec14Snorby 			return (-1);
96ddeeec14Snorby 		}
97ddeeec14Snorby 		return (0);
98ddeeec14Snorby 	} else {
99ddeeec14Snorby 		if (ntohs(auth_head->auth_type) !=
100ddeeec14Snorby 		    (u_int16_t)iface->auth_type) {
101ddeeec14Snorby 			log_debug("auth_validate: wrong auth type");
102ddeeec14Snorby 			return (-1);
103ddeeec14Snorby 		}
104ddeeec14Snorby 	}
105ddeeec14Snorby 
106ddeeec14Snorby 	switch (iface->auth_type) {
107ddeeec14Snorby 	case AUTH_SIMPLE:
108ddeeec14Snorby 		bcopy(*buf+sizeof(*auth_head), pwd, MAX_SIMPLE_AUTH_LEN);
109ddeeec14Snorby 		if (bcmp(pwd, iface->auth_key, MAX_SIMPLE_AUTH_LEN)) {
110ddeeec14Snorby 			log_debug("auth_validate: wrong password, "
111ddeeec14Snorby 			    "interface: %s", iface->name);
112ddeeec14Snorby 			return (-1);
113ddeeec14Snorby 		}
114ddeeec14Snorby 		break;
115ddeeec14Snorby 	case AUTH_CRYPT:
116ddeeec14Snorby 		a = (struct md5_auth *)(*buf + sizeof(*auth_head));
117ddeeec14Snorby 
118ddeeec14Snorby 		if ((md = md_list_find(&iface->auth_md_list,
119ddeeec14Snorby 		    a->auth_keyid)) == NULL) {
120ddeeec14Snorby 			log_debug("auth_validate: keyid %d not configured, "
121ddeeec14Snorby 			    "interface %s", a->auth_keyid,
122ddeeec14Snorby 			    iface->name);
123ddeeec14Snorby 			return (-1);
124ddeeec14Snorby 		}
125ddeeec14Snorby 
126ddeeec14Snorby 		if (nbr != NULL) {
127ddeeec14Snorby 			if (ntohl(a->auth_seq) < nbr->auth_seq_num) {
128ddeeec14Snorby 				log_debug("auth_validate: decreasing seq num, "
129ddeeec14Snorby 				    "interface %s", iface->name);
130ddeeec14Snorby 				return (-1);
131ddeeec14Snorby 			}
132ddeeec14Snorby 		} else if (nbr_failed != NULL) {
133ddeeec14Snorby 			if (ntohl(a->auth_seq) < nbr_failed->auth_seq_num &&
134ddeeec14Snorby 			    ntohl(a->auth_seq)) {
135ddeeec14Snorby 				log_debug("auth_validate: decreasing seq num, "
136ddeeec14Snorby 				    "interface %s", iface->name);
137ddeeec14Snorby 				return (-1);
138ddeeec14Snorby 			}
139ddeeec14Snorby 		}
140ddeeec14Snorby 
141ddeeec14Snorby 		/* XXX: maybe validate also the trailer header */
142ddeeec14Snorby 		if (a->auth_length != MD5_DIGEST_LENGTH + AUTH_TRLR_HDR_LEN) {
143ddeeec14Snorby 			log_debug("auth_validate: invalid key length, "
144ddeeec14Snorby 			    "interface %s", iface->name);
145ddeeec14Snorby 			return (-1);
146ddeeec14Snorby 		}
147ddeeec14Snorby 
148228f7562Sremi 		if (ntohs(a->auth_offset) != *len + RIP_HDR_LEN -
149228f7562Sremi 		    AUTH_TRLR_HDR_LEN - MD5_DIGEST_LENGTH) {
150228f7562Sremi 			log_debug("auth_validate: invalid authentication data "
151228f7562Sremi 			    "offset %hu, interface %s", ntohs(a->auth_offset),
152228f7562Sremi 			    iface->name);
153228f7562Sremi 			return (-1);
154228f7562Sremi 		}
155228f7562Sremi 
156ddeeec14Snorby 		auth_data = *buf;
157ddeeec14Snorby 		auth_data += ntohs(a->auth_offset);
158ddeeec14Snorby 
159ddeeec14Snorby 		/* save the received digest and clear it in the packet */
160ddeeec14Snorby 		bcopy(auth_data, recv_digest, sizeof(recv_digest));
161ddeeec14Snorby 		bzero(auth_data, MD5_DIGEST_LENGTH);
162ddeeec14Snorby 
163ddeeec14Snorby 		/* insert plaintext key */
164d1c9c145Sclaudio 		memcpy(digest, md->key, MD5_DIGEST_LENGTH);
165ddeeec14Snorby 
166ddeeec14Snorby 		/* calculate MD5 digest */
167ddeeec14Snorby 		MD5Init(&hash);
168ddeeec14Snorby 		MD5Update(&hash, b, ntohs(a->auth_offset) + RIP_HDR_LEN);
169ddeeec14Snorby 		MD5Update(&hash, digest, MD5_DIGEST_LENGTH);
170ddeeec14Snorby 		MD5Final(digest, &hash);
171ddeeec14Snorby 
172ddeeec14Snorby 		if (bcmp(recv_digest, digest, sizeof(digest))) {
173ddeeec14Snorby 			log_debug("auth_validate: invalid MD5 digest, "
174ddeeec14Snorby 			    "interface %s", iface->name);
175ddeeec14Snorby 			return (-1);
176ddeeec14Snorby 		}
177ddeeec14Snorby 
178ddeeec14Snorby 		*crypt_seq_num = ntohl(a->auth_seq);
179ddeeec14Snorby 
180ddeeec14Snorby 		*len -= AUTH_TRLR_HDR_LEN + MD5_DIGEST_LENGTH;
181ddeeec14Snorby 
182ddeeec14Snorby 		break;
183ddeeec14Snorby 	default:
184ddeeec14Snorby 		log_debug("auth_validate: unknown auth type, interface %s",
185ddeeec14Snorby 		    iface->name);
186ddeeec14Snorby 		return (-1);
187ddeeec14Snorby 	}
188ddeeec14Snorby 
189ddeeec14Snorby 	*buf += RIP_ENTRY_LEN;
190ddeeec14Snorby 	*len -= RIP_ENTRY_LEN;
191ddeeec14Snorby 
192ddeeec14Snorby 	return (0);
193ddeeec14Snorby }
194ddeeec14Snorby 
195ddeeec14Snorby int
auth_gen(struct ibuf * buf,struct iface * iface)196e39620e5Snicm auth_gen(struct ibuf *buf, struct iface *iface)
197ddeeec14Snorby {
198ddeeec14Snorby 	struct rip_auth		 auth_head;
199ddeeec14Snorby 	struct md5_auth		 a;
200652c17a6Smcbride 	struct auth_md		 *md;
201ddeeec14Snorby 
202ddeeec14Snorby 	auth_head.auth_fixed = AUTH;
203ddeeec14Snorby 	auth_head.auth_type = htons(iface->auth_type);
204ddeeec14Snorby 
205e39620e5Snicm 	ibuf_add(buf, &auth_head, sizeof(auth_head));
206ddeeec14Snorby 
207ddeeec14Snorby 	switch (iface->auth_type) {
208ddeeec14Snorby 	case AUTH_SIMPLE:
209e39620e5Snicm 		ibuf_add(buf, &iface->auth_key, MAX_SIMPLE_AUTH_LEN);
210ddeeec14Snorby 		break;
211ddeeec14Snorby 	case AUTH_CRYPT:
212652c17a6Smcbride 		if ((md = md_list_find(&iface->auth_md_list,
213652c17a6Smcbride 		    iface->auth_keyid)) == NULL) {
214652c17a6Smcbride 			log_debug("auth_gen: keyid %d not configured, "
215652c17a6Smcbride 			    "interface %s", iface->auth_keyid, iface->name);
216652c17a6Smcbride 			return (-1);
217652c17a6Smcbride 		}
218ddeeec14Snorby 		bzero(&a, sizeof(a));
219ddeeec14Snorby 		a.auth_keyid = iface->auth_keyid;
220652c17a6Smcbride 		a.auth_seq = htonl(auth_get_seq_num(md));
221ddeeec14Snorby 		a.auth_length = MD5_DIGEST_LENGTH + AUTH_TRLR_HDR_LEN;
222ddeeec14Snorby 
223e39620e5Snicm 		ibuf_add(buf, &a, sizeof(a));
224ddeeec14Snorby 		break;
225ddeeec14Snorby 	default:
226badfb5d1Smichele 		log_debug("auth_gen: unknown auth type, interface %s",
227badfb5d1Smichele 		    iface->name);
228badfb5d1Smichele 		return (-1);
229ddeeec14Snorby 	}
230ddeeec14Snorby 
231ddeeec14Snorby 	return (0);
232ddeeec14Snorby }
233ddeeec14Snorby 
234ddeeec14Snorby int
auth_add_trailer(struct ibuf * buf,struct iface * iface)235e39620e5Snicm auth_add_trailer(struct ibuf *buf, struct iface *iface)
236ddeeec14Snorby {
237ddeeec14Snorby 	MD5_CTX			 hash;
238ddeeec14Snorby 	u_int8_t		 digest[MD5_DIGEST_LENGTH];
239ddeeec14Snorby 	struct auth_md		*md;
240eaa1bd4eSclaudio 	size_t			 pos;
241ddeeec14Snorby 
242eaa1bd4eSclaudio 	pos = sizeof(struct rip_hdr) + sizeof(struct rip_auth) +
243eaa1bd4eSclaudio 	    offsetof(struct md5_auth, auth_offset);
244ddeeec14Snorby 
245ddeeec14Snorby 	/* add offset to header */
246eaa1bd4eSclaudio 	if (ibuf_set_n16(buf, pos, ibuf_size(buf)) == -1)
247eaa1bd4eSclaudio 		return (-1);
248ddeeec14Snorby 
249ddeeec14Snorby 	/* insert plaintext key */
250ddeeec14Snorby 	if ((md = md_list_find(&iface->auth_md_list,
251ddeeec14Snorby 	    iface->auth_keyid)) == NULL) {
25211981efdSmcbride 		log_debug("auth_add_trailer: keyid %d not configured, "
253ddeeec14Snorby 		    "interface %s", iface->auth_keyid, iface->name);
254ddeeec14Snorby 		return (-1);
255ddeeec14Snorby 	}
256ddeeec14Snorby 
257d1c9c145Sclaudio 	memcpy(digest, md->key, MD5_DIGEST_LENGTH);
258ddeeec14Snorby 
259ddeeec14Snorby 	auth_trailer_header_gen(buf);
260ddeeec14Snorby 
261ddeeec14Snorby 	/* calculate MD5 digest */
262ddeeec14Snorby 	MD5Init(&hash);
263eaa1bd4eSclaudio 	MD5Update(&hash, ibuf_data(buf), ibuf_size(buf));
264ddeeec14Snorby 	MD5Update(&hash, digest, MD5_DIGEST_LENGTH);
265ddeeec14Snorby 	MD5Final(digest, &hash);
266ddeeec14Snorby 
267e39620e5Snicm 	return (ibuf_add(buf, digest, MD5_DIGEST_LENGTH));
268ddeeec14Snorby }
269ddeeec14Snorby 
270ddeeec14Snorby /* md list */
271d1c9c145Sclaudio int
md_list_add(struct auth_md_head * head,u_int8_t keyid,char * key)272ddeeec14Snorby md_list_add(struct auth_md_head *head, u_int8_t keyid, char *key)
273ddeeec14Snorby {
274ddeeec14Snorby 	struct auth_md	*md;
275ddeeec14Snorby 
276d1c9c145Sclaudio 	if (strlen(key) > MD5_DIGEST_LENGTH)
277d1c9c145Sclaudio 		return (-1);
278d1c9c145Sclaudio 
279ddeeec14Snorby 	if ((md = md_list_find(head, keyid)) != NULL) {
280ddeeec14Snorby 		/* update key */
281d1c9c145Sclaudio 		bzero(md->key, sizeof(md->key));
282d1c9c145Sclaudio 		memcpy(md->key, key, strlen(key));
283d1c9c145Sclaudio 		return (0);
284ddeeec14Snorby 	}
285ddeeec14Snorby 
286ddeeec14Snorby 	if ((md = calloc(1, sizeof(struct auth_md))) == NULL)
287ddeeec14Snorby 		fatalx("md_list_add");
288ddeeec14Snorby 
289ddeeec14Snorby 	md->keyid = keyid;
290d1c9c145Sclaudio 	memcpy(md->key, key, strlen(key));
291652c17a6Smcbride 	md->seq_modulator = auth_calc_modulator(md);
292ddeeec14Snorby 	TAILQ_INSERT_TAIL(head, md, entry);
293d1c9c145Sclaudio 
294d1c9c145Sclaudio 	return (0);
295ddeeec14Snorby }
296ddeeec14Snorby 
297ddeeec14Snorby void
md_list_copy(struct auth_md_head * to,struct auth_md_head * from)298ddeeec14Snorby md_list_copy(struct auth_md_head *to, struct auth_md_head *from)
299ddeeec14Snorby {
300ddeeec14Snorby 	struct auth_md	*m, *md;
301ddeeec14Snorby 
302ddeeec14Snorby 	TAILQ_INIT(to);
303ddeeec14Snorby 
304ddeeec14Snorby 	TAILQ_FOREACH(m, from, entry) {
305ddeeec14Snorby 		if ((md = calloc(1, sizeof(struct auth_md))) == NULL)
30688efd76bSstevesk 			fatalx("md_list_copy");
307ddeeec14Snorby 
308ddeeec14Snorby 		md->keyid = m->keyid;
309d1c9c145Sclaudio 		memcpy(md->key, m->key, sizeof(md->key));
310652c17a6Smcbride 		md->seq_modulator = m->seq_modulator;
311ddeeec14Snorby 		TAILQ_INSERT_TAIL(to, md, entry);
312ddeeec14Snorby 	}
313ddeeec14Snorby }
314ddeeec14Snorby 
315ddeeec14Snorby void
md_list_clr(struct auth_md_head * head)316ddeeec14Snorby md_list_clr(struct auth_md_head *head)
317ddeeec14Snorby {
318ddeeec14Snorby 	struct auth_md	*m;
319ddeeec14Snorby 
320ddeeec14Snorby 	while ((m = TAILQ_FIRST(head)) != NULL) {
321ddeeec14Snorby 		TAILQ_REMOVE(head, m, entry);
322ddeeec14Snorby 		free(m);
323ddeeec14Snorby 	}
324ddeeec14Snorby }
325ddeeec14Snorby 
326ddeeec14Snorby struct auth_md *
md_list_find(struct auth_md_head * head,u_int8_t keyid)327ddeeec14Snorby md_list_find(struct auth_md_head *head, u_int8_t keyid)
328ddeeec14Snorby {
329ddeeec14Snorby 	struct auth_md	*m;
330ddeeec14Snorby 
331ddeeec14Snorby 	TAILQ_FOREACH(m, head, entry)
332ddeeec14Snorby 		if (m->keyid == keyid)
333ddeeec14Snorby 			return (m);
334ddeeec14Snorby 
335ddeeec14Snorby 	return (NULL);
336ddeeec14Snorby }
337