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