xref: /freebsd/contrib/wpa/src/crypto/milenage.c (revision 5b9c547c)
1e28a4053SRui Paulo /*
2e28a4053SRui Paulo  * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
3e28a4053SRui Paulo  * Copyright (c) 2006-2007 <j@w1.fi>
4e28a4053SRui Paulo  *
5f05cddf9SRui Paulo  * This software may be distributed under the terms of the BSD license.
6f05cddf9SRui Paulo  * See README for more details.
7e28a4053SRui Paulo  *
8e28a4053SRui Paulo  * This file implements an example authentication algorithm defined for 3GPP
9e28a4053SRui Paulo  * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
10e28a4053SRui Paulo  * EAP-AKA to be tested properly with real USIM cards.
11e28a4053SRui Paulo  *
12e28a4053SRui Paulo  * This implementations assumes that the r1..r5 and c1..c5 constants defined in
13e28a4053SRui Paulo  * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
14e28a4053SRui Paulo  * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
15e28a4053SRui Paulo  * be AES (Rijndael).
16e28a4053SRui Paulo  */
17e28a4053SRui Paulo 
18e28a4053SRui Paulo #include "includes.h"
19e28a4053SRui Paulo 
20e28a4053SRui Paulo #include "common.h"
21e28a4053SRui Paulo #include "crypto/aes_wrap.h"
22e28a4053SRui Paulo #include "milenage.h"
23e28a4053SRui Paulo 
24e28a4053SRui Paulo 
25e28a4053SRui Paulo /**
26e28a4053SRui Paulo  * milenage_f1 - Milenage f1 and f1* algorithms
27e28a4053SRui Paulo  * @opc: OPc = 128-bit value derived from OP and K
28e28a4053SRui Paulo  * @k: K = 128-bit subscriber key
29e28a4053SRui Paulo  * @_rand: RAND = 128-bit random challenge
30e28a4053SRui Paulo  * @sqn: SQN = 48-bit sequence number
31e28a4053SRui Paulo  * @amf: AMF = 16-bit authentication management field
32e28a4053SRui Paulo  * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
33e28a4053SRui Paulo  * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
34e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
35e28a4053SRui Paulo  */
milenage_f1(const u8 * opc,const u8 * k,const u8 * _rand,const u8 * sqn,const u8 * amf,u8 * mac_a,u8 * mac_s)36e28a4053SRui Paulo int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
37e28a4053SRui Paulo 		const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
38e28a4053SRui Paulo {
39e28a4053SRui Paulo 	u8 tmp1[16], tmp2[16], tmp3[16];
40e28a4053SRui Paulo 	int i;
41e28a4053SRui Paulo 
42e28a4053SRui Paulo 	/* tmp1 = TEMP = E_K(RAND XOR OP_C) */
43e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
44e28a4053SRui Paulo 		tmp1[i] = _rand[i] ^ opc[i];
45e28a4053SRui Paulo 	if (aes_128_encrypt_block(k, tmp1, tmp1))
46e28a4053SRui Paulo 		return -1;
47e28a4053SRui Paulo 
48e28a4053SRui Paulo 	/* tmp2 = IN1 = SQN || AMF || SQN || AMF */
49e28a4053SRui Paulo 	os_memcpy(tmp2, sqn, 6);
50e28a4053SRui Paulo 	os_memcpy(tmp2 + 6, amf, 2);
51e28a4053SRui Paulo 	os_memcpy(tmp2 + 8, tmp2, 8);
52e28a4053SRui Paulo 
53e28a4053SRui Paulo 	/* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
54e28a4053SRui Paulo 
55e28a4053SRui Paulo 	/* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
56e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
57e28a4053SRui Paulo 		tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
58e28a4053SRui Paulo 	/* XOR with TEMP = E_K(RAND XOR OP_C) */
59e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
60e28a4053SRui Paulo 		tmp3[i] ^= tmp1[i];
61e28a4053SRui Paulo 	/* XOR with c1 (= ..00, i.e., NOP) */
62e28a4053SRui Paulo 
63e28a4053SRui Paulo 	/* f1 || f1* = E_K(tmp3) XOR OP_c */
64e28a4053SRui Paulo 	if (aes_128_encrypt_block(k, tmp3, tmp1))
65e28a4053SRui Paulo 		return -1;
66e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
67e28a4053SRui Paulo 		tmp1[i] ^= opc[i];
68e28a4053SRui Paulo 	if (mac_a)
69e28a4053SRui Paulo 		os_memcpy(mac_a, tmp1, 8); /* f1 */
70e28a4053SRui Paulo 	if (mac_s)
71e28a4053SRui Paulo 		os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */
72e28a4053SRui Paulo 	return 0;
73e28a4053SRui Paulo }
74e28a4053SRui Paulo 
75e28a4053SRui Paulo 
76e28a4053SRui Paulo /**
77e28a4053SRui Paulo  * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
78e28a4053SRui Paulo  * @opc: OPc = 128-bit value derived from OP and K
79e28a4053SRui Paulo  * @k: K = 128-bit subscriber key
80e28a4053SRui Paulo  * @_rand: RAND = 128-bit random challenge
81e28a4053SRui Paulo  * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
82e28a4053SRui Paulo  * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
83e28a4053SRui Paulo  * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
84e28a4053SRui Paulo  * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
85e28a4053SRui Paulo  * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
86e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
87e28a4053SRui Paulo  */
milenage_f2345(const u8 * opc,const u8 * k,const u8 * _rand,u8 * res,u8 * ck,u8 * ik,u8 * ak,u8 * akstar)88e28a4053SRui Paulo int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
89e28a4053SRui Paulo 		   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
90e28a4053SRui Paulo {
91e28a4053SRui Paulo 	u8 tmp1[16], tmp2[16], tmp3[16];
92e28a4053SRui Paulo 	int i;
93e28a4053SRui Paulo 
94e28a4053SRui Paulo 	/* tmp2 = TEMP = E_K(RAND XOR OP_C) */
95e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
96e28a4053SRui Paulo 		tmp1[i] = _rand[i] ^ opc[i];
97e28a4053SRui Paulo 	if (aes_128_encrypt_block(k, tmp1, tmp2))
98e28a4053SRui Paulo 		return -1;
99e28a4053SRui Paulo 
100e28a4053SRui Paulo 	/* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
101e28a4053SRui Paulo 	/* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
102e28a4053SRui Paulo 	/* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
103e28a4053SRui Paulo 	/* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
104e28a4053SRui Paulo 
105e28a4053SRui Paulo 	/* f2 and f5 */
106e28a4053SRui Paulo 	/* rotate by r2 (= 0, i.e., NOP) */
107e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
108e28a4053SRui Paulo 		tmp1[i] = tmp2[i] ^ opc[i];
109e28a4053SRui Paulo 	tmp1[15] ^= 1; /* XOR c2 (= ..01) */
110e28a4053SRui Paulo 	/* f5 || f2 = E_K(tmp1) XOR OP_c */
111e28a4053SRui Paulo 	if (aes_128_encrypt_block(k, tmp1, tmp3))
112e28a4053SRui Paulo 		return -1;
113e28a4053SRui Paulo 	for (i = 0; i < 16; i++)
114e28a4053SRui Paulo 		tmp3[i] ^= opc[i];
115e28a4053SRui Paulo 	if (res)
116e28a4053SRui Paulo 		os_memcpy(res, tmp3 + 8, 8); /* f2 */
117e28a4053SRui Paulo 	if (ak)
118e28a4053SRui Paulo 		os_memcpy(ak, tmp3, 6); /* f5 */
119e28a4053SRui Paulo 
120e28a4053SRui Paulo 	/* f3 */
121e28a4053SRui Paulo 	if (ck) {
122e28a4053SRui Paulo 		/* rotate by r3 = 0x20 = 4 bytes */
123e28a4053SRui Paulo 		for (i = 0; i < 16; i++)
124e28a4053SRui Paulo 			tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
125e28a4053SRui Paulo 		tmp1[15] ^= 2; /* XOR c3 (= ..02) */
126e28a4053SRui Paulo 		if (aes_128_encrypt_block(k, tmp1, ck))
127e28a4053SRui Paulo 			return -1;
128e28a4053SRui Paulo 		for (i = 0; i < 16; i++)
129e28a4053SRui Paulo 			ck[i] ^= opc[i];
130e28a4053SRui Paulo 	}
131e28a4053SRui Paulo 
132e28a4053SRui Paulo 	/* f4 */
133e28a4053SRui Paulo 	if (ik) {
134e28a4053SRui Paulo 		/* rotate by r4 = 0x40 = 8 bytes */
135e28a4053SRui Paulo 		for (i = 0; i < 16; i++)
136e28a4053SRui Paulo 			tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
137e28a4053SRui Paulo 		tmp1[15] ^= 4; /* XOR c4 (= ..04) */
138e28a4053SRui Paulo 		if (aes_128_encrypt_block(k, tmp1, ik))
139e28a4053SRui Paulo 			return -1;
140e28a4053SRui Paulo 		for (i = 0; i < 16; i++)
141e28a4053SRui Paulo 			ik[i] ^= opc[i];
142e28a4053SRui Paulo 	}
143e28a4053SRui Paulo 
144e28a4053SRui Paulo 	/* f5* */
145e28a4053SRui Paulo 	if (akstar) {
146e28a4053SRui Paulo 		/* rotate by r5 = 0x60 = 12 bytes */
147e28a4053SRui Paulo 		for (i = 0; i < 16; i++)
148e28a4053SRui Paulo 			tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
149e28a4053SRui Paulo 		tmp1[15] ^= 8; /* XOR c5 (= ..08) */
150e28a4053SRui Paulo 		if (aes_128_encrypt_block(k, tmp1, tmp1))
151e28a4053SRui Paulo 			return -1;
152e28a4053SRui Paulo 		for (i = 0; i < 6; i++)
153e28a4053SRui Paulo 			akstar[i] = tmp1[i] ^ opc[i];
154e28a4053SRui Paulo 	}
155e28a4053SRui Paulo 
156e28a4053SRui Paulo 	return 0;
157e28a4053SRui Paulo }
158e28a4053SRui Paulo 
159e28a4053SRui Paulo 
160e28a4053SRui Paulo /**
161e28a4053SRui Paulo  * milenage_generate - Generate AKA AUTN,IK,CK,RES
162e28a4053SRui Paulo  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
163e28a4053SRui Paulo  * @amf: AMF = 16-bit authentication management field
164e28a4053SRui Paulo  * @k: K = 128-bit subscriber key
165e28a4053SRui Paulo  * @sqn: SQN = 48-bit sequence number
166e28a4053SRui Paulo  * @_rand: RAND = 128-bit random challenge
167e28a4053SRui Paulo  * @autn: Buffer for AUTN = 128-bit authentication token
168e28a4053SRui Paulo  * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
169e28a4053SRui Paulo  * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
170e28a4053SRui Paulo  * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
171e28a4053SRui Paulo  * @res_len: Max length for res; set to used length or 0 on failure
172e28a4053SRui Paulo  */
milenage_generate(const u8 * opc,const u8 * amf,const u8 * k,const u8 * sqn,const u8 * _rand,u8 * autn,u8 * ik,u8 * ck,u8 * res,size_t * res_len)173e28a4053SRui Paulo void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
174e28a4053SRui Paulo 		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
175e28a4053SRui Paulo 		       u8 *ck, u8 *res, size_t *res_len)
176e28a4053SRui Paulo {
177e28a4053SRui Paulo 	int i;
178e28a4053SRui Paulo 	u8 mac_a[8], ak[6];
179e28a4053SRui Paulo 
180e28a4053SRui Paulo 	if (*res_len < 8) {
181e28a4053SRui Paulo 		*res_len = 0;
182e28a4053SRui Paulo 		return;
183e28a4053SRui Paulo 	}
184e28a4053SRui Paulo 	if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
185e28a4053SRui Paulo 	    milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) {
186e28a4053SRui Paulo 		*res_len = 0;
187e28a4053SRui Paulo 		return;
188e28a4053SRui Paulo 	}
189e28a4053SRui Paulo 	*res_len = 8;
190e28a4053SRui Paulo 
191e28a4053SRui Paulo 	/* AUTN = (SQN ^ AK) || AMF || MAC */
192e28a4053SRui Paulo 	for (i = 0; i < 6; i++)
193e28a4053SRui Paulo 		autn[i] = sqn[i] ^ ak[i];
194e28a4053SRui Paulo 	os_memcpy(autn + 6, amf, 2);
195e28a4053SRui Paulo 	os_memcpy(autn + 8, mac_a, 8);
196e28a4053SRui Paulo }
197e28a4053SRui Paulo 
198e28a4053SRui Paulo 
199e28a4053SRui Paulo /**
200e28a4053SRui Paulo  * milenage_auts - Milenage AUTS validation
201e28a4053SRui Paulo  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
202e28a4053SRui Paulo  * @k: K = 128-bit subscriber key
203e28a4053SRui Paulo  * @_rand: RAND = 128-bit random challenge
204e28a4053SRui Paulo  * @auts: AUTS = 112-bit authentication token from client
205e28a4053SRui Paulo  * @sqn: Buffer for SQN = 48-bit sequence number
206e28a4053SRui Paulo  * Returns: 0 = success (sqn filled), -1 on failure
207e28a4053SRui Paulo  */
milenage_auts(const u8 * opc,const u8 * k,const u8 * _rand,const u8 * auts,u8 * sqn)208e28a4053SRui Paulo int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
209e28a4053SRui Paulo 		  u8 *sqn)
210e28a4053SRui Paulo {
211e28a4053SRui Paulo 	u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
212e28a4053SRui Paulo 	u8 ak[6], mac_s[8];
213e28a4053SRui Paulo 	int i;
214e28a4053SRui Paulo 
215e28a4053SRui Paulo 	if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
216e28a4053SRui Paulo 		return -1;
217e28a4053SRui Paulo 	for (i = 0; i < 6; i++)
218e28a4053SRui Paulo 		sqn[i] = auts[i] ^ ak[i];
219e28a4053SRui Paulo 	if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
220*5b9c547cSRui Paulo 	    os_memcmp_const(mac_s, auts + 6, 8) != 0)
221e28a4053SRui Paulo 		return -1;
222e28a4053SRui Paulo 	return 0;
223e28a4053SRui Paulo }
224e28a4053SRui Paulo 
225e28a4053SRui Paulo 
226e28a4053SRui Paulo /**
227e28a4053SRui Paulo  * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
228e28a4053SRui Paulo  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
229e28a4053SRui Paulo  * @k: K = 128-bit subscriber key
230e28a4053SRui Paulo  * @_rand: RAND = 128-bit random challenge
231e28a4053SRui Paulo  * @sres: Buffer for SRES = 32-bit SRES
232e28a4053SRui Paulo  * @kc: Buffer for Kc = 64-bit Kc
233e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure
234e28a4053SRui Paulo  */
gsm_milenage(const u8 * opc,const u8 * k,const u8 * _rand,u8 * sres,u8 * kc)235e28a4053SRui Paulo int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc)
236e28a4053SRui Paulo {
237e28a4053SRui Paulo 	u8 res[8], ck[16], ik[16];
238e28a4053SRui Paulo 	int i;
239e28a4053SRui Paulo 
240e28a4053SRui Paulo 	if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
241e28a4053SRui Paulo 		return -1;
242e28a4053SRui Paulo 
243e28a4053SRui Paulo 	for (i = 0; i < 8; i++)
244e28a4053SRui Paulo 		kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
245e28a4053SRui Paulo 
246e28a4053SRui Paulo #ifdef GSM_MILENAGE_ALT_SRES
247e28a4053SRui Paulo 	os_memcpy(sres, res, 4);
248e28a4053SRui Paulo #else /* GSM_MILENAGE_ALT_SRES */
249e28a4053SRui Paulo 	for (i = 0; i < 4; i++)
250e28a4053SRui Paulo 		sres[i] = res[i] ^ res[i + 4];
251e28a4053SRui Paulo #endif /* GSM_MILENAGE_ALT_SRES */
252e28a4053SRui Paulo 	return 0;
253e28a4053SRui Paulo }
254e28a4053SRui Paulo 
255e28a4053SRui Paulo 
256e28a4053SRui Paulo /**
257e28a4053SRui Paulo  * milenage_generate - Generate AKA AUTN,IK,CK,RES
258e28a4053SRui Paulo  * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
259e28a4053SRui Paulo  * @k: K = 128-bit subscriber key
260e28a4053SRui Paulo  * @sqn: SQN = 48-bit sequence number
261e28a4053SRui Paulo  * @_rand: RAND = 128-bit random challenge
262e28a4053SRui Paulo  * @autn: AUTN = 128-bit authentication token
263e28a4053SRui Paulo  * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
264e28a4053SRui Paulo  * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
265e28a4053SRui Paulo  * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
266e28a4053SRui Paulo  * @res_len: Variable that will be set to RES length
267e28a4053SRui Paulo  * @auts: 112-bit buffer for AUTS
268e28a4053SRui Paulo  * Returns: 0 on success, -1 on failure, or -2 on synchronization failure
269e28a4053SRui Paulo  */
milenage_check(const u8 * opc,const u8 * k,const u8 * sqn,const u8 * _rand,const u8 * autn,u8 * ik,u8 * ck,u8 * res,size_t * res_len,u8 * auts)270e28a4053SRui Paulo int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
271e28a4053SRui Paulo 		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
272e28a4053SRui Paulo 		   u8 *auts)
273e28a4053SRui Paulo {
274e28a4053SRui Paulo 	int i;
275e28a4053SRui Paulo 	u8 mac_a[8], ak[6], rx_sqn[6];
276e28a4053SRui Paulo 	const u8 *amf;
277e28a4053SRui Paulo 
278e28a4053SRui Paulo 	wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
279e28a4053SRui Paulo 	wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);
280e28a4053SRui Paulo 
281e28a4053SRui Paulo 	if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
282e28a4053SRui Paulo 		return -1;
283e28a4053SRui Paulo 
284e28a4053SRui Paulo 	*res_len = 8;
285e28a4053SRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
286e28a4053SRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
287e28a4053SRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
288e28a4053SRui Paulo 	wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);
289e28a4053SRui Paulo 
290e28a4053SRui Paulo 	/* AUTN = (SQN ^ AK) || AMF || MAC */
291e28a4053SRui Paulo 	for (i = 0; i < 6; i++)
292e28a4053SRui Paulo 		rx_sqn[i] = autn[i] ^ ak[i];
293e28a4053SRui Paulo 	wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);
294e28a4053SRui Paulo 
295e28a4053SRui Paulo 	if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
296e28a4053SRui Paulo 		u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
297e28a4053SRui Paulo 		if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
298e28a4053SRui Paulo 			return -1;
299e28a4053SRui Paulo 		wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
300e28a4053SRui Paulo 		for (i = 0; i < 6; i++)
301e28a4053SRui Paulo 			auts[i] = sqn[i] ^ ak[i];
302e28a4053SRui Paulo 		if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
303e28a4053SRui Paulo 			return -1;
304e28a4053SRui Paulo 		wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
305e28a4053SRui Paulo 		return -2;
306e28a4053SRui Paulo 	}
307e28a4053SRui Paulo 
308e28a4053SRui Paulo 	amf = autn + 6;
309e28a4053SRui Paulo 	wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
310e28a4053SRui Paulo 	if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
311e28a4053SRui Paulo 		return -1;
312e28a4053SRui Paulo 
313e28a4053SRui Paulo 	wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
314e28a4053SRui Paulo 
315*5b9c547cSRui Paulo 	if (os_memcmp_const(mac_a, autn + 8, 8) != 0) {
316e28a4053SRui Paulo 		wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
317e28a4053SRui Paulo 		wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
318e28a4053SRui Paulo 			    autn + 8, 8);
319e28a4053SRui Paulo 		return -1;
320e28a4053SRui Paulo 	}
321e28a4053SRui Paulo 
322e28a4053SRui Paulo 	return 0;
323e28a4053SRui Paulo }
324