GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ripd/auth.c Lines: 0 148 0.0 %
Date: 2017-11-13 Branches: 0 52 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: auth.c,v 1.11 2010/05/26 13:56:08 nicm 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
		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 ibuf *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
	ibuf_add(buf, &auth_head, sizeof(auth_head));
197
198
	switch (iface->auth_type) {
199
	case AUTH_SIMPLE:
200
		ibuf_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
		ibuf_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 ibuf *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 = ibuf_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 (ibuf_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
}