GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ospfd/auth.c Lines: 5 121 4.1 %
Date: 2017-11-13 Branches: 2 54 3.7 %

Line Branch Exec Source
1
/*	$OpenBSD: auth.c,v 1.20 2015/05/05 01:26:37 jsg Exp $ */
2
3
/*
4
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
5
 *
6
 * Permission to use, copy, modify, and distribute this software for any
7
 * purpose with or without fee is hereby granted, provided that the above
8
 * copyright notice and this permission notice appear in all copies.
9
 *
10
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17
 */
18
19
#include <sys/types.h>
20
#include <sys/socket.h>
21
#include <limits.h>
22
#include <md5.h>
23
#include <stdlib.h>
24
#include <string.h>
25
26
#include "ospfd.h"
27
#include "ospf.h"
28
#include "log.h"
29
#include "ospfe.h"
30
31
struct auth_md *md_list_find(struct auth_md_head *, u_int8_t);
32
33
int
34
auth_validate(void *buf, u_int16_t len, struct iface *iface, struct nbr *nbr)
35
{
36
	MD5_CTX		 hash;
37
	u_int8_t	 digest[MD5_DIGEST_LENGTH];
38
	u_int8_t	 recv_digest[MD5_DIGEST_LENGTH];
39
	struct ospf_hdr	*ospf_hdr = buf;
40
	struct auth_md	*md;
41
	char		*auth_data;
42
43
	if (ntohs(ospf_hdr->auth_type) != (u_int16_t)iface->auth_type) {
44
		log_debug("auth_validate: wrong auth type, interface %s",
45
		    iface->name);
46
		return (-1);
47
	}
48
49
	switch (iface->auth_type) {
50
	case AUTH_SIMPLE:
51
		if (memcmp(ospf_hdr->auth_key.simple, iface->auth_key,
52
		    sizeof(ospf_hdr->auth_key.simple))) {
53
			log_debug("auth_validate: wrong password, interface %s",
54
			    iface->name);
55
			return (-1);
56
		}
57
		/* FALLTHROUGH */
58
	case AUTH_NONE:
59
		/* clear the key before chksum */
60
		bzero(ospf_hdr->auth_key.simple,
61
		     sizeof(ospf_hdr->auth_key.simple));
62
63
		if (in_cksum(ospf_hdr, ntohs(ospf_hdr->len))) {
64
			log_debug("auth_validate: invalid checksum, "
65
			    "interface %s", iface->name);
66
			return (-1);
67
		}
68
		break;
69
	case AUTH_CRYPT:
70
		/*
71
		 * We must allow keys that are configured on the interface
72
		 * but not necessarily set as the transmit key
73
		 * (iface->auth_keyid). This allows for key rotation to new
74
		 * keys without taking down the network.
75
		 */
76
		if ((md = md_list_find(&iface->auth_md_list,
77
		    ospf_hdr->auth_key.crypt.keyid)) == NULL) {
78
			log_debug("auth_validate: keyid %d not configured, "
79
			    "interface %s", ospf_hdr->auth_key.crypt.keyid,
80
			    iface->name);
81
			return (-1);
82
		}
83
84
		if (nbr != NULL && ntohl(ospf_hdr->auth_key.crypt.seq_num) <
85
		    nbr->crypt_seq_num) {
86
			log_debug("auth_validate: decreasing seq num, "
87
			    "interface %s", iface->name);
88
			return (-1);
89
		}
90
91
		if (ospf_hdr->auth_key.crypt.len != MD5_DIGEST_LENGTH) {
92
			log_debug("auth_validate: invalid key length, "
93
			    "interface %s", iface->name);
94
			return (-1);
95
		}
96
97
		if (len - ntohs(ospf_hdr->len) < MD5_DIGEST_LENGTH) {
98
			log_debug("auth_validate: invalid key length, "
99
			    "interface %s", iface->name);
100
			return (-1);
101
		}
102
103
		auth_data = buf;
104
		auth_data += ntohs(ospf_hdr->len);
105
106
		/* save the received digest and clear it in the packet */
107
		memcpy(recv_digest, auth_data, sizeof(recv_digest));
108
		bzero(auth_data, MD5_DIGEST_LENGTH);
109
110
		/* insert plaintext key */
111
		bzero(digest, MD5_DIGEST_LENGTH);
112
		strncpy(digest, md->key, MD5_DIGEST_LENGTH);
113
114
		/* calculate MD5 digest */
115
		MD5Init(&hash);
116
		MD5Update(&hash, buf, ntohs(ospf_hdr->len));
117
		MD5Update(&hash, digest, MD5_DIGEST_LENGTH);
118
		MD5Final(digest, &hash);
119
120
		if (memcmp(recv_digest, digest, sizeof(digest))) {
121
			log_debug("auth_validate: invalid MD5 digest, "
122
			    "interface %s", iface->name);
123
			return (-1);
124
		}
125
126
		if (nbr != NULL)
127
			nbr->crypt_seq_num =
128
			    ntohl(ospf_hdr->auth_key.crypt.seq_num);
129
		break;
130
	default:
131
		log_debug("auth_validate: unknown auth type, interface %s",
132
		    iface->name);
133
		return (-1);
134
	}
135
136
	return (0);
137
}
138
139
int
140
auth_gen(struct ibuf *buf, struct iface *iface)
141
{
142
	MD5_CTX		 hash;
143
	u_int8_t	 digest[MD5_DIGEST_LENGTH];
144
	struct ospf_hdr	*ospf_hdr;
145
	struct auth_md	*md;
146
147
	if ((ospf_hdr = ibuf_seek(buf, 0, sizeof(*ospf_hdr))) == NULL)
148
		fatalx("auth_gen: buf_seek failed");
149
150
	/* update length */
151
	if (ibuf_size(buf) > USHRT_MAX)
152
		fatalx("auth_gen: resulting ospf packet too big");
153
	ospf_hdr->len = htons(ibuf_size(buf));
154
	/* clear auth_key field */
155
	bzero(ospf_hdr->auth_key.simple, sizeof(ospf_hdr->auth_key.simple));
156
157
	switch (iface->auth_type) {
158
	case AUTH_NONE:
159
		ospf_hdr->chksum = in_cksum(buf->buf, ibuf_size(buf));
160
		break;
161
	case AUTH_SIMPLE:
162
		ospf_hdr->chksum = in_cksum(buf->buf, ibuf_size(buf));
163
164
		strncpy(ospf_hdr->auth_key.simple, iface->auth_key,
165
		    sizeof(ospf_hdr->auth_key.simple));
166
		break;
167
	case AUTH_CRYPT:
168
		ospf_hdr->chksum = 0;
169
		ospf_hdr->auth_key.crypt.keyid = iface->auth_keyid;
170
		ospf_hdr->auth_key.crypt.seq_num = htonl(iface->crypt_seq_num);
171
		ospf_hdr->auth_key.crypt.len = MD5_DIGEST_LENGTH;
172
		iface->crypt_seq_num++;
173
174
		/* insert plaintext key */
175
		if ((md = md_list_find(&iface->auth_md_list,
176
		    iface->auth_keyid)) == NULL) {
177
			log_debug("auth_gen: keyid %d not configured, "
178
			    "interface %s", iface->auth_keyid, iface->name);
179
			return (-1);
180
		}
181
182
		bzero(digest, MD5_DIGEST_LENGTH);
183
		strncpy(digest, md->key, MD5_DIGEST_LENGTH);
184
185
		/* calculate MD5 digest */
186
		MD5Init(&hash);
187
		MD5Update(&hash, buf->buf, ibuf_size(buf));
188
		MD5Update(&hash, digest, MD5_DIGEST_LENGTH);
189
		MD5Final(digest, &hash);
190
191
		return (ibuf_add(buf, digest, MD5_DIGEST_LENGTH));
192
	default:
193
		log_debug("auth_gen: unknown auth type, interface %s",
194
		    iface->name);
195
		return (-1);
196
	}
197
198
	return (0);
199
}
200
201
/* md list */
202
void
203
md_list_add(struct auth_md_head *head, u_int8_t keyid, char *key)
204
{
205
	struct auth_md	*md;
206
207
	if ((md = md_list_find(head, keyid)) != NULL) {
208
		/* update key */
209
		strncpy(md->key, key, sizeof(md->key));
210
		return;
211
	}
212
213
	if ((md = calloc(1, sizeof(struct auth_md))) == NULL)
214
		fatalx("md_list_add");
215
216
	md->keyid = keyid;
217
	strncpy(md->key, key, sizeof(md->key));
218
	TAILQ_INSERT_TAIL(head, md, entry);
219
}
220
221
void
222
md_list_copy(struct auth_md_head *to, struct auth_md_head *from)
223
{
224
	struct auth_md	*m, *md;
225
226
144
	TAILQ_INIT(to);
227
228
144
	TAILQ_FOREACH(m, from, entry) {
229
		if ((md = calloc(1, sizeof(struct auth_md))) == NULL)
230
			fatalx("md_list_copy");
231
232
		md->keyid = m->keyid;
233
		strncpy(md->key, m->key, sizeof(md->key));
234
		TAILQ_INSERT_TAIL(to, md, entry);
235
	}
236
72
}
237
238
void
239
md_list_clr(struct auth_md_head *head)
240
{
241
	struct auth_md	*m;
242
243
288
	while ((m = TAILQ_FIRST(head)) != NULL) {
244
		TAILQ_REMOVE(head, m, entry);
245
		free(m);
246
	}
247
96
}
248
249
struct auth_md *
250
md_list_find(struct auth_md_head *head, u_int8_t keyid)
251
{
252
	struct auth_md	*m;
253
254
	TAILQ_FOREACH(m, head, entry)
255
		if (m->keyid == keyid)
256
			return (m);
257
258
	return (NULL);
259
}
260
261
int
262
md_list_send(struct auth_md_head *head, struct imsgev *to)
263
{
264
	struct auth_md	*m;
265
266
	TAILQ_FOREACH(m, head, entry)
267
		if (imsg_compose_event(to, IMSG_RECONF_AUTHMD, 0, 0, -1, m,
268
		    sizeof(*m)) == -1)
269
			return (-1);
270
271
	return (0);
272
}