GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: sbin/iked/eap.c Lines: 0 233 0.0 %
Date: 2016-12-06 Branches: 0 143 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: eap.c,v 1.14 2015/08/21 11:59:27 reyk Exp $	*/
2
3
/*
4
 * Copyright (c) 2010-2013 Reyk Floeter <reyk@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/queue.h>
20
#include <sys/socket.h>
21
#include <sys/wait.h>
22
#include <sys/uio.h>
23
24
#include <netinet/in.h>
25
#include <arpa/inet.h>
26
27
#include <stdlib.h>
28
#include <stdio.h>
29
#include <unistd.h>
30
#include <string.h>
31
#include <signal.h>
32
#include <errno.h>
33
#include <err.h>
34
#include <pwd.h>
35
#include <event.h>
36
37
#include <openssl/sha.h>
38
#include <openssl/evp.h>
39
40
#include "iked.h"
41
#include "ikev2.h"
42
#include "eap.h"
43
#include "chap_ms.h"
44
45
char	*eap_identity_response(struct eap_message *);
46
int	 eap_challenge_request(struct iked *env, struct iked_sa *,
47
	    struct eap_header *);
48
int	 eap_success(struct iked *, struct iked_sa *, struct eap_header *);
49
int	 eap_mschap(struct iked *, struct iked_sa *, struct eap_message *);
50
51
ssize_t
52
eap_identity_request(struct ibuf *e)
53
{
54
	struct eap_message		*eap;
55
56
	if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL)
57
		return (-1);
58
	eap->eap_code = EAP_CODE_REQUEST;
59
	eap->eap_id = 0;
60
	eap->eap_length = htobe16(sizeof(*eap));
61
	eap->eap_type = EAP_TYPE_IDENTITY;
62
63
	return (sizeof(*eap));
64
}
65
66
char *
67
eap_identity_response(struct eap_message *eap)
68
{
69
	size_t			 len;
70
	char			*str;
71
	uint8_t			*ptr = (uint8_t *)eap;
72
73
	len = betoh16(eap->eap_length) - sizeof(*eap);
74
	ptr += sizeof(*eap);
75
76
	if (len == 0 || (str = get_string(ptr, len)) == NULL) {
77
		log_info("%s: invalid identity response, length %zu",
78
		    __func__, len);
79
		return (NULL);
80
	}
81
	log_debug("%s: identity '%s' length %zd", __func__, str, len);
82
	return (str);
83
}
84
85
int
86
eap_challenge_request(struct iked *env, struct iked_sa *sa,
87
    struct eap_header *hdr)
88
{
89
	struct eap_message		*eap;
90
	struct eap_mschap_challenge	*ms;
91
	const char			*name;
92
	int				 ret = -1;
93
	struct ibuf			*e;
94
95
	if ((e = ibuf_static()) == NULL)
96
		return (-1);
97
98
	if ((eap = ibuf_advance(e, sizeof(*eap))) == NULL)
99
		goto done;
100
	eap->eap_code = EAP_CODE_REQUEST;
101
	eap->eap_id = hdr->eap_id + 1;
102
	eap->eap_type = sa->sa_policy->pol_auth.auth_eap;
103
104
	switch (sa->sa_policy->pol_auth.auth_eap) {
105
	case EAP_TYPE_MSCHAP_V2:
106
		name = IKED_USER;	/* XXX should be user-configurable */
107
		eap->eap_length = htobe16(sizeof(*eap) +
108
		    sizeof(*ms) + strlen(name));
109
110
		if ((ms = ibuf_advance(e, sizeof(*ms))) == NULL)
111
			return (-1);
112
		ms->msc_opcode = EAP_MSOPCODE_CHALLENGE;
113
		ms->msc_id = eap->eap_id;
114
		ms->msc_length = htobe16(sizeof(*ms) + strlen(name));
115
		ms->msc_valuesize = sizeof(ms->msc_challenge);
116
		arc4random_buf(ms->msc_challenge, sizeof(ms->msc_challenge));
117
		if (ibuf_add(e, name, strlen(name)) == -1)
118
			goto done;
119
120
		/* Store the EAP challenge value */
121
		sa->sa_eap.id_type = eap->eap_type;
122
		if ((sa->sa_eap.id_buf = ibuf_new(ms->msc_challenge,
123
		    sizeof(ms->msc_challenge))) == NULL)
124
			goto done;
125
		break;
126
	default:
127
		log_debug("%s: unsupported EAP type %s", __func__,
128
		    print_map(eap->eap_type, eap_type_map));
129
		goto done;
130
	}
131
132
	ret = ikev2_send_ike_e(env, sa, e,
133
	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
134
135
 done:
136
	ibuf_release(e);
137
138
	return (ret);
139
}
140
141
int
142
eap_success(struct iked *env, struct iked_sa *sa, struct eap_header *hdr)
143
{
144
	struct eap_header		*resp;
145
	int				 ret = -1;
146
	struct ibuf			*e;
147
148
	if ((e = ibuf_static()) == NULL)
149
		return (-1);
150
151
	if ((resp = ibuf_advance(e, sizeof(*resp))) == NULL)
152
		goto done;
153
	resp->eap_code = EAP_CODE_SUCCESS;
154
	resp->eap_id = hdr->eap_id;
155
	resp->eap_length = htobe16(sizeof(*resp));
156
157
	ret = ikev2_send_ike_e(env, sa, e,
158
	    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
159
160
 done:
161
	ibuf_release(e);
162
163
	return (ret);
164
}
165
166
int
167
eap_mschap(struct iked *env, struct iked_sa *sa, struct eap_message *eap)
168
{
169
	struct iked_user		*usr;
170
	struct eap_message		*resp;
171
	struct eap_mschap_response	*msr;
172
	struct eap_mschap_peer		*msp;
173
	struct eap_mschap		*ms;
174
	struct eap_mschap_success	*mss;
175
	uint8_t				*ptr, *pass;
176
	size_t				 len, passlen;
177
	char				*name, *msg;
178
	uint8_t				 ntresponse[EAP_MSCHAP_NTRESPONSE_SZ];
179
	uint8_t				 successmsg[EAP_MSCHAP_SUCCESS_SZ];
180
	struct ibuf			*eapmsg = NULL;
181
	int				 ret = -1;
182
183
	if (!sa_stateok(sa, IKEV2_STATE_EAP)) {
184
		log_debug("%s: unexpected EAP", __func__);
185
		return (0);	/* ignore */
186
	}
187
188
	if (sa->sa_hdr.sh_initiator) {
189
		log_debug("%s: initiator EAP not supported", __func__);
190
		return (-1);
191
	}
192
193
	/* Only MSCHAP-V2 */
194
	if (eap->eap_type != EAP_TYPE_MSCHAP_V2) {
195
		log_debug("%s: unsupported type EAP-%s", __func__,
196
		    print_map(eap->eap_type, eap_type_map));
197
		return (-1);
198
	}
199
200
	if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*ms))) {
201
		log_debug("%s: short message", __func__);
202
		return (-1);
203
	}
204
205
	ms = (struct eap_mschap *)(eap + 1);
206
	ptr = (uint8_t *)(eap + 1);
207
208
	switch (ms->ms_opcode) {
209
	case EAP_MSOPCODE_RESPONSE:
210
		msr = (struct eap_mschap_response *)ms;
211
		if (betoh16(eap->eap_length) < (sizeof(*eap) + sizeof(*msr))) {
212
			log_debug("%s: short response", __func__);
213
			return (-1);
214
		}
215
		ptr += sizeof(*msr);
216
		len = betoh16(eap->eap_length) -
217
		    sizeof(*eap) - sizeof(*msr);
218
		if (len == 0 && sa->sa_eapid != NULL)
219
			name = strdup(sa->sa_eapid);
220
		else
221
			name = get_string(ptr, len);
222
		if (name == NULL) {
223
			log_debug("%s: invalid response name", __func__);
224
			return (-1);
225
		}
226
		if ((usr = user_lookup(env, name)) == NULL) {
227
			log_debug("%s: unknown user '%s'", __func__, name);
228
			free(name);
229
			return (-1);
230
		}
231
		free(name);
232
233
		if ((pass = string2unicode(usr->usr_pass, &passlen)) == NULL)
234
			return (-1);
235
236
		msp = &msr->msr_response.resp_peer;
237
		mschap_nt_response(ibuf_data(sa->sa_eap.id_buf),
238
		    msp->msp_challenge, usr->usr_name, strlen(usr->usr_name),
239
		    pass, passlen, ntresponse);
240
241
		if (memcmp(ntresponse, msp->msp_ntresponse,
242
		    sizeof(ntresponse)) != 0) {
243
			log_debug("%s: '%s' authentication failed", __func__,
244
			    usr->usr_name);
245
			free(pass);
246
247
			/* XXX should we send an EAP failure packet? */
248
			return (-1);
249
		}
250
251
		bzero(&successmsg, sizeof(successmsg));
252
		mschap_auth_response(pass, passlen,
253
		    ntresponse, ibuf_data(sa->sa_eap.id_buf),
254
		    msp->msp_challenge, usr->usr_name, strlen(usr->usr_name),
255
		    successmsg);
256
		if ((sa->sa_eapmsk = ibuf_new(NULL, MSCHAP_MSK_SZ)) == NULL) {
257
			log_debug("%s: failed to get MSK", __func__);
258
			free(pass);
259
			return (-1);
260
		}
261
		mschap_msk(pass, passlen, ntresponse,
262
		    ibuf_data(sa->sa_eapmsk));
263
		free(pass);
264
265
		log_info("%s: '%s' authenticated", __func__, usr->usr_name);
266
267
268
		if ((eapmsg = ibuf_static()) == NULL)
269
			return (-1);
270
271
		msg = " M=Welcome";
272
273
		if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL)
274
			goto done;
275
		resp->eap_code = EAP_CODE_REQUEST;
276
		resp->eap_id = eap->eap_id + 1;
277
		resp->eap_length = htobe16(sizeof(*resp) + sizeof(*mss) +
278
		    sizeof(successmsg) + strlen(msg));
279
		resp->eap_type = EAP_TYPE_MSCHAP_V2;
280
281
		if ((mss = ibuf_advance(eapmsg, sizeof(*mss))) == NULL)
282
			goto done;
283
		mss->mss_opcode = EAP_MSOPCODE_SUCCESS;
284
		mss->mss_id = msr->msr_id;
285
		mss->mss_length = htobe16(sizeof(*mss) +
286
		    sizeof(successmsg) + strlen(msg));
287
		if (ibuf_add(eapmsg, successmsg, sizeof(successmsg)) != 0)
288
			goto done;
289
		if (ibuf_add(eapmsg, msg, strlen(msg)) != 0)
290
			goto done;
291
		break;
292
	case EAP_MSOPCODE_SUCCESS:
293
		if ((eapmsg = ibuf_static()) == NULL)
294
			return (-1);
295
		if ((resp = ibuf_advance(eapmsg, sizeof(*resp))) == NULL)
296
			goto done;
297
		resp->eap_code = EAP_CODE_RESPONSE;
298
		resp->eap_id = eap->eap_id;
299
		resp->eap_length = htobe16(sizeof(*resp) + sizeof(*ms));
300
		resp->eap_type = EAP_TYPE_MSCHAP_V2;
301
		if ((ms = ibuf_advance(eapmsg, sizeof(*ms))) == NULL)
302
			goto done;
303
		ms->ms_opcode = EAP_MSOPCODE_SUCCESS;
304
		break;
305
	case EAP_MSOPCODE_FAILURE:
306
	case EAP_MSOPCODE_CHANGE_PASSWORD:
307
	case EAP_MSOPCODE_CHALLENGE:
308
	default:
309
		log_debug("%s: EAP-%s unsupported "
310
		    "responder operation %s", __func__,
311
		    print_map(eap->eap_type, eap_type_map),
312
		    print_map(ms->ms_opcode, eap_msopcode_map));
313
		return (-1);
314
	}
315
316
	if (eapmsg != NULL)
317
		ret = ikev2_send_ike_e(env, sa, eapmsg,
318
		    IKEV2_PAYLOAD_EAP, IKEV2_EXCHANGE_IKE_AUTH, 1);
319
320
	if (ret == 0)
321
		sa_state(env, sa, IKEV2_STATE_AUTH_SUCCESS);
322
323
 done:
324
	ibuf_release(eapmsg);
325
	return (ret);
326
}
327
328
int
329
eap_parse(struct iked *env, struct iked_sa *sa, void *data, int response)
330
{
331
	struct eap_header		*hdr = data;
332
	struct eap_message		*eap = data;
333
	size_t				 len;
334
	uint8_t				*ptr;
335
	struct eap_mschap		*ms;
336
	struct eap_mschap_challenge	*msc;
337
	struct eap_mschap_response	*msr;
338
	struct eap_mschap_success	*mss;
339
	struct eap_mschap_failure	*msf;
340
	char				*str;
341
342
	/* length is already verified by the caller */
343
	len = betoh16(hdr->eap_length);
344
	ptr = (uint8_t *)(eap + 1);
345
346
	switch (hdr->eap_code) {
347
	case EAP_CODE_REQUEST:
348
	case EAP_CODE_RESPONSE:
349
		if (len < sizeof(*eap)) {
350
			log_debug("%s: short message", __func__);
351
			return (-1);
352
		}
353
		break;
354
	case EAP_CODE_SUCCESS:
355
		return (0);
356
	case EAP_CODE_FAILURE:
357
		if (response)
358
			return (0);
359
		return (-1);
360
	default:
361
		log_debug("%s: unsupported EAP code %s", __func__,
362
		    print_map(hdr->eap_code, eap_code_map));
363
		return (-1);
364
	}
365
366
	switch (eap->eap_type) {
367
	case EAP_TYPE_IDENTITY:
368
		if (eap->eap_code == EAP_CODE_REQUEST)
369
			break;
370
		if ((str = eap_identity_response(eap)) == NULL)
371
			return (-1);
372
		if (response) {
373
			free(str);
374
			break;
375
		}
376
		if (sa->sa_eapid != NULL) {
377
			free(str);
378
			log_debug("%s: EAP identity already known", __func__);
379
			return (0);
380
		}
381
		sa->sa_eapid = str;
382
		return (eap_challenge_request(env, sa, hdr));
383
	case EAP_TYPE_MSCHAP_V2:
384
		ms = (struct eap_mschap *)ptr;
385
		switch (ms->ms_opcode) {
386
		case EAP_MSOPCODE_CHALLENGE:
387
			msc = (struct eap_mschap_challenge *)ptr;
388
			ptr += sizeof(*msc);
389
			len = betoh16(eap->eap_length) -
390
			    sizeof(*eap) - sizeof(*msc);
391
			if ((str = get_string(ptr, len)) == NULL) {
392
				log_debug("%s: invalid challenge name",
393
				    __func__);
394
				return (-1);
395
			}
396
			log_info("%s: %s %s id %d "
397
			    "length %d valuesize %d name '%s' length %zu",
398
			    __func__,
399
			    print_map(eap->eap_type, eap_type_map),
400
			    print_map(ms->ms_opcode, eap_msopcode_map),
401
			    msc->msc_id, betoh16(msc->msc_length),
402
			    msc->msc_valuesize, str, len);
403
			free(str);
404
			print_hex(msc->msc_challenge, 0,
405
			    sizeof(msc->msc_challenge));
406
			break;
407
		case EAP_MSOPCODE_RESPONSE:
408
			msr = (struct eap_mschap_response *)ptr;
409
			ptr += sizeof(*msr);
410
			len = betoh16(eap->eap_length) -
411
			    sizeof(*eap) - sizeof(*msr);
412
			if ((str = get_string(ptr, len)) == NULL) {
413
				log_debug("%s: invalid response name",
414
				    __func__);
415
				return (-1);
416
			}
417
			log_info("%s: %s %s id %d "
418
			    "length %d valuesize %d name '%s' name-length %zu",
419
			    __func__,
420
			    print_map(eap->eap_type, eap_type_map),
421
			    print_map(ms->ms_opcode, eap_msopcode_map),
422
			    msr->msr_id, betoh16(msr->msr_length),
423
			    msr->msr_valuesize, str, len);
424
			free(str);
425
			print_hex(msr->msr_response.resp_data, 0,
426
			    sizeof(msr->msr_response.resp_data));
427
			break;
428
		case EAP_MSOPCODE_SUCCESS:
429
			if (eap->eap_code == EAP_CODE_REQUEST) {
430
				mss = (struct eap_mschap_success *)ptr;
431
				ptr += sizeof(*mss);
432
				len = betoh16(eap->eap_length) -
433
				    sizeof(*eap) - sizeof(*mss);
434
				if ((str = get_string(ptr, len)) == NULL) {
435
					log_debug("%s: invalid response name",
436
					    __func__);
437
					return (-1);
438
				}
439
				log_info("%s: %s %s request id %d "
440
				    "length %d message '%s' message-len %zu",
441
				    __func__,
442
				    print_map(eap->eap_type, eap_type_map),
443
				    print_map(ms->ms_opcode, eap_msopcode_map),
444
				    mss->mss_id, betoh16(mss->mss_length),
445
				    str, len);
446
				free(str);
447
			} else {
448
				ms = (struct eap_mschap *)ptr;
449
				log_info("%s: %s %s response", __func__,
450
				    print_map(eap->eap_type, eap_type_map),
451
				    print_map(ms->ms_opcode, eap_msopcode_map));
452
				if (response)
453
					break;
454
				if (!sa_stateok(sa, IKEV2_STATE_AUTH_SUCCESS))
455
					return (-1);
456
457
				return (eap_success(env, sa, hdr));
458
			}
459
			break;
460
		case EAP_MSOPCODE_FAILURE:
461
			msf = (struct eap_mschap_failure *)ptr;
462
			ptr += sizeof(*msf);
463
			len = betoh16(eap->eap_length) -
464
			    sizeof(*eap) - sizeof(*msf);
465
			if ((str = get_string(ptr, len)) == NULL) {
466
				log_debug("%s: invalid failure message",
467
				    __func__);
468
				return (-1);
469
			}
470
			log_info("%s: %s %s id %d "
471
			    "length %d message '%s'", __func__,
472
			    print_map(eap->eap_type, eap_type_map),
473
			    print_map(ms->ms_opcode, eap_msopcode_map),
474
			    msf->msf_id, betoh16(msf->msf_length), str);
475
			free(str);
476
			break;
477
		default:
478
			log_info("%s: unknown ms opcode %d", __func__,
479
			    ms->ms_opcode);
480
			return (-1);
481
		}
482
		if (response)
483
			break;
484
485
		return (eap_mschap(env, sa, eap));
486
	default:
487
		log_debug("%s: unsupported EAP type %s", __func__,
488
		    print_map(eap->eap_type, eap_type_map));
489
		return (-1);
490
	}
491
492
	return (0);
493
}