1*c1d255d3SCy Schubert /*
2*c1d255d3SCy Schubert * SAE-PK
3*c1d255d3SCy Schubert * Copyright (c) 2020, The Linux Foundation
4*c1d255d3SCy Schubert *
5*c1d255d3SCy Schubert * This software may be distributed under the terms of the BSD license.
6*c1d255d3SCy Schubert * See README for more details.
7*c1d255d3SCy Schubert */
8*c1d255d3SCy Schubert
9*c1d255d3SCy Schubert #include "utils/includes.h"
10*c1d255d3SCy Schubert #include <stdint.h>
11*c1d255d3SCy Schubert
12*c1d255d3SCy Schubert #include "utils/common.h"
13*c1d255d3SCy Schubert #include "utils/base64.h"
14*c1d255d3SCy Schubert #include "common/ieee802_11_defs.h"
15*c1d255d3SCy Schubert #include "common/ieee802_11_common.h"
16*c1d255d3SCy Schubert #include "crypto/crypto.h"
17*c1d255d3SCy Schubert #include "crypto/aes.h"
18*c1d255d3SCy Schubert #include "crypto/aes_siv.h"
19*c1d255d3SCy Schubert #include "sae.h"
20*c1d255d3SCy Schubert
21*c1d255d3SCy Schubert
22*c1d255d3SCy Schubert /* RFC 4648 base 32 alphabet with lowercase characters */
23*c1d255d3SCy Schubert static const char *sae_pk_base32_table = "abcdefghijklmnopqrstuvwxyz234567";
24*c1d255d3SCy Schubert
25*c1d255d3SCy Schubert
26*c1d255d3SCy Schubert static const u8 d_mult_table[] = {
27*c1d255d3SCy Schubert 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
28*c1d255d3SCy Schubert 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
29*c1d255d3SCy Schubert 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0,
30*c1d255d3SCy Schubert 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16,
31*c1d255d3SCy Schubert 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1,
32*c1d255d3SCy Schubert 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17,
33*c1d255d3SCy Schubert 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2,
34*c1d255d3SCy Schubert 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18,
35*c1d255d3SCy Schubert 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3,
36*c1d255d3SCy Schubert 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19,
37*c1d255d3SCy Schubert 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4,
38*c1d255d3SCy Schubert 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20,
39*c1d255d3SCy Schubert 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5,
40*c1d255d3SCy Schubert 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21,
41*c1d255d3SCy Schubert 7, 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6,
42*c1d255d3SCy Schubert 23, 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22,
43*c1d255d3SCy Schubert 8, 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7,
44*c1d255d3SCy Schubert 24, 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23,
45*c1d255d3SCy Schubert 9, 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8,
46*c1d255d3SCy Schubert 25, 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24,
47*c1d255d3SCy Schubert 10, 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
48*c1d255d3SCy Schubert 26, 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
49*c1d255d3SCy Schubert 11, 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
50*c1d255d3SCy Schubert 27, 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
51*c1d255d3SCy Schubert 12, 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
52*c1d255d3SCy Schubert 28, 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
53*c1d255d3SCy Schubert 13, 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
54*c1d255d3SCy Schubert 29, 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28,
55*c1d255d3SCy Schubert 14, 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
56*c1d255d3SCy Schubert 30, 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
57*c1d255d3SCy Schubert 15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
58*c1d255d3SCy Schubert 31, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
59*c1d255d3SCy Schubert 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17,
60*c1d255d3SCy Schubert 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,
61*c1d255d3SCy Schubert 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18,
62*c1d255d3SCy Schubert 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
63*c1d255d3SCy Schubert 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19,
64*c1d255d3SCy Schubert 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3,
65*c1d255d3SCy Schubert 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20,
66*c1d255d3SCy Schubert 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4,
67*c1d255d3SCy Schubert 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21,
68*c1d255d3SCy Schubert 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5,
69*c1d255d3SCy Schubert 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22,
70*c1d255d3SCy Schubert 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6,
71*c1d255d3SCy Schubert 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24, 23,
72*c1d255d3SCy Schubert 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8, 7,
73*c1d255d3SCy Schubert 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25, 24,
74*c1d255d3SCy Schubert 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8,
75*c1d255d3SCy Schubert 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26, 25,
76*c1d255d3SCy Schubert 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9,
77*c1d255d3SCy Schubert 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27, 26,
78*c1d255d3SCy Schubert 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10,
79*c1d255d3SCy Schubert 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28, 27,
80*c1d255d3SCy Schubert 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11,
81*c1d255d3SCy Schubert 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29, 28,
82*c1d255d3SCy Schubert 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12,
83*c1d255d3SCy Schubert 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30, 29,
84*c1d255d3SCy Schubert 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13,
85*c1d255d3SCy Schubert 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31, 30,
86*c1d255d3SCy Schubert 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15, 14,
87*c1d255d3SCy Schubert 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 31,
88*c1d255d3SCy Schubert 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 15,
89*c1d255d3SCy Schubert 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16,
90*c1d255d3SCy Schubert 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0
91*c1d255d3SCy Schubert };
92*c1d255d3SCy Schubert
93*c1d255d3SCy Schubert static const u8 d_perm_table[] = {
94*c1d255d3SCy Schubert 7, 2, 1, 30, 16, 20, 27, 11, 31, 6, 8, 13, 29, 5, 10, 21,
95*c1d255d3SCy Schubert 22, 3, 24, 0, 23, 25, 12, 9, 28, 14, 4, 15, 17, 18, 19, 26
96*c1d255d3SCy Schubert };
97*c1d255d3SCy Schubert
98*c1d255d3SCy Schubert
d_permute(u8 val,unsigned int iter)99*c1d255d3SCy Schubert static u8 d_permute(u8 val, unsigned int iter)
100*c1d255d3SCy Schubert {
101*c1d255d3SCy Schubert if (iter == 0)
102*c1d255d3SCy Schubert return val;
103*c1d255d3SCy Schubert return d_permute(d_perm_table[val], iter - 1);
104*c1d255d3SCy Schubert }
105*c1d255d3SCy Schubert
106*c1d255d3SCy Schubert
d_invert(u8 val)107*c1d255d3SCy Schubert static u8 d_invert(u8 val)
108*c1d255d3SCy Schubert {
109*c1d255d3SCy Schubert if (val > 0 && val < 16)
110*c1d255d3SCy Schubert return 16 - val;
111*c1d255d3SCy Schubert return val;
112*c1d255d3SCy Schubert }
113*c1d255d3SCy Schubert
114*c1d255d3SCy Schubert
d_check_char(const char * str,size_t len)115*c1d255d3SCy Schubert static char d_check_char(const char *str, size_t len)
116*c1d255d3SCy Schubert {
117*c1d255d3SCy Schubert size_t i;
118*c1d255d3SCy Schubert u8 val = 0;
119*c1d255d3SCy Schubert u8 dtable[256];
120*c1d255d3SCy Schubert unsigned int iter = 1;
121*c1d255d3SCy Schubert int j;
122*c1d255d3SCy Schubert
123*c1d255d3SCy Schubert os_memset(dtable, 0x80, 256);
124*c1d255d3SCy Schubert for (i = 0; sae_pk_base32_table[i]; i++)
125*c1d255d3SCy Schubert dtable[(u8) sae_pk_base32_table[i]] = i;
126*c1d255d3SCy Schubert
127*c1d255d3SCy Schubert for (j = len - 1; j >= 0; j--) {
128*c1d255d3SCy Schubert u8 c, p;
129*c1d255d3SCy Schubert
130*c1d255d3SCy Schubert c = dtable[(u8) str[j]];
131*c1d255d3SCy Schubert if (c == 0x80)
132*c1d255d3SCy Schubert continue;
133*c1d255d3SCy Schubert p = d_permute(c, iter);
134*c1d255d3SCy Schubert iter++;
135*c1d255d3SCy Schubert val = d_mult_table[val * 32 + p];
136*c1d255d3SCy Schubert }
137*c1d255d3SCy Schubert
138*c1d255d3SCy Schubert return sae_pk_base32_table[d_invert(val)];
139*c1d255d3SCy Schubert }
140*c1d255d3SCy Schubert
141*c1d255d3SCy Schubert
sae_pk_valid_password(const char * pw)142*c1d255d3SCy Schubert bool sae_pk_valid_password(const char *pw)
143*c1d255d3SCy Schubert {
144*c1d255d3SCy Schubert int pos;
145*c1d255d3SCy Schubert size_t i, pw_len = os_strlen(pw);
146*c1d255d3SCy Schubert u8 sec_1b;
147*c1d255d3SCy Schubert u8 dtable[256];
148*c1d255d3SCy Schubert
149*c1d255d3SCy Schubert os_memset(dtable, 0x80, 256);
150*c1d255d3SCy Schubert for (i = 0; sae_pk_base32_table[i]; i++)
151*c1d255d3SCy Schubert dtable[(u8) sae_pk_base32_table[i]] = i;
152*c1d255d3SCy Schubert
153*c1d255d3SCy Schubert /* SAE-PK password has at least three four character components
154*c1d255d3SCy Schubert * separated by hyphens. */
155*c1d255d3SCy Schubert if (pw_len < 14 || pw_len % 5 != 4) {
156*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "SAE-PK: Not a valid password (length)");
157*c1d255d3SCy Schubert return false;
158*c1d255d3SCy Schubert }
159*c1d255d3SCy Schubert
160*c1d255d3SCy Schubert for (pos = 0; pw[pos]; pos++) {
161*c1d255d3SCy Schubert if (pos && pos % 5 == 4) {
162*c1d255d3SCy Schubert if (pw[pos] != '-') {
163*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
164*c1d255d3SCy Schubert "SAE-PK: Not a valid password (separator)");
165*c1d255d3SCy Schubert return false;
166*c1d255d3SCy Schubert }
167*c1d255d3SCy Schubert continue;
168*c1d255d3SCy Schubert }
169*c1d255d3SCy Schubert if (dtable[(u8) pw[pos]] == 0x80) {
170*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
171*c1d255d3SCy Schubert "SAE-PK: Not a valid password (character)");
172*c1d255d3SCy Schubert return false;
173*c1d255d3SCy Schubert }
174*c1d255d3SCy Schubert }
175*c1d255d3SCy Schubert
176*c1d255d3SCy Schubert /* Verify that the checksum character is valid */
177*c1d255d3SCy Schubert if (pw[pw_len - 1] != d_check_char(pw, pw_len - 1)) {
178*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
179*c1d255d3SCy Schubert "SAE-PK: Not a valid password (checksum)");
180*c1d255d3SCy Schubert return false;
181*c1d255d3SCy Schubert }
182*c1d255d3SCy Schubert
183*c1d255d3SCy Schubert /* Verify that Sec_1b bits match */
184*c1d255d3SCy Schubert sec_1b = dtable[(u8) pw[0]] & BIT(4);
185*c1d255d3SCy Schubert for (i = 5; i < pw_len; i += 5) {
186*c1d255d3SCy Schubert if (sec_1b != (dtable[(u8) pw[i]] & BIT(4))) {
187*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
188*c1d255d3SCy Schubert "SAE-PK: Not a valid password (Sec_1b)");
189*c1d255d3SCy Schubert return false;
190*c1d255d3SCy Schubert }
191*c1d255d3SCy Schubert }
192*c1d255d3SCy Schubert return true;
193*c1d255d3SCy Schubert }
194*c1d255d3SCy Schubert
195*c1d255d3SCy Schubert
add_char(const char * start,char * pos,u8 idx,size_t * bits)196*c1d255d3SCy Schubert static char * add_char(const char *start, char *pos, u8 idx, size_t *bits)
197*c1d255d3SCy Schubert {
198*c1d255d3SCy Schubert if (*bits == 0)
199*c1d255d3SCy Schubert return pos;
200*c1d255d3SCy Schubert if (*bits > 5)
201*c1d255d3SCy Schubert *bits -= 5;
202*c1d255d3SCy Schubert else
203*c1d255d3SCy Schubert *bits = 0;
204*c1d255d3SCy Schubert
205*c1d255d3SCy Schubert if ((pos - start) % 5 == 4)
206*c1d255d3SCy Schubert *pos++ = '-';
207*c1d255d3SCy Schubert *pos++ = sae_pk_base32_table[idx];
208*c1d255d3SCy Schubert return pos;
209*c1d255d3SCy Schubert }
210*c1d255d3SCy Schubert
211*c1d255d3SCy Schubert
212*c1d255d3SCy Schubert /* Base32 encode a password and add hyper separators and checksum */
sae_pk_base32_encode(const u8 * src,size_t len_bits)213*c1d255d3SCy Schubert char * sae_pk_base32_encode(const u8 *src, size_t len_bits)
214*c1d255d3SCy Schubert {
215*c1d255d3SCy Schubert char *out, *pos;
216*c1d255d3SCy Schubert size_t olen, extra_pad, i;
217*c1d255d3SCy Schubert u64 block = 0;
218*c1d255d3SCy Schubert u8 val;
219*c1d255d3SCy Schubert size_t len = (len_bits + 7) / 8;
220*c1d255d3SCy Schubert size_t left = len_bits;
221*c1d255d3SCy Schubert int j;
222*c1d255d3SCy Schubert
223*c1d255d3SCy Schubert if (len == 0 || len >= SIZE_MAX / 8)
224*c1d255d3SCy Schubert return NULL;
225*c1d255d3SCy Schubert olen = len * 8 / 5 + 1;
226*c1d255d3SCy Schubert olen += olen / 4; /* hyphen separators */
227*c1d255d3SCy Schubert pos = out = os_zalloc(olen + 2); /* include room for ChkSum and nul */
228*c1d255d3SCy Schubert if (!out)
229*c1d255d3SCy Schubert return NULL;
230*c1d255d3SCy Schubert
231*c1d255d3SCy Schubert extra_pad = (5 - len % 5) % 5;
232*c1d255d3SCy Schubert for (i = 0; i < len + extra_pad; i++) {
233*c1d255d3SCy Schubert val = i < len ? src[i] : 0;
234*c1d255d3SCy Schubert block <<= 8;
235*c1d255d3SCy Schubert block |= val;
236*c1d255d3SCy Schubert if (i % 5 == 4) {
237*c1d255d3SCy Schubert for (j = 7; j >= 0; j--)
238*c1d255d3SCy Schubert pos = add_char(out, pos,
239*c1d255d3SCy Schubert (block >> j * 5) & 0x1f, &left);
240*c1d255d3SCy Schubert block = 0;
241*c1d255d3SCy Schubert }
242*c1d255d3SCy Schubert }
243*c1d255d3SCy Schubert
244*c1d255d3SCy Schubert *pos = d_check_char(out, os_strlen(out));
245*c1d255d3SCy Schubert
246*c1d255d3SCy Schubert return out;
247*c1d255d3SCy Schubert }
248*c1d255d3SCy Schubert
249*c1d255d3SCy Schubert
sae_pk_base32_decode(const char * src,size_t len,size_t * out_len)250*c1d255d3SCy Schubert u8 * sae_pk_base32_decode(const char *src, size_t len, size_t *out_len)
251*c1d255d3SCy Schubert {
252*c1d255d3SCy Schubert u8 dtable[256], *out, *pos, tmp;
253*c1d255d3SCy Schubert u64 block = 0;
254*c1d255d3SCy Schubert size_t i, count, olen;
255*c1d255d3SCy Schubert int pad = 0;
256*c1d255d3SCy Schubert size_t extra_pad;
257*c1d255d3SCy Schubert
258*c1d255d3SCy Schubert os_memset(dtable, 0x80, 256);
259*c1d255d3SCy Schubert for (i = 0; sae_pk_base32_table[i]; i++)
260*c1d255d3SCy Schubert dtable[(u8) sae_pk_base32_table[i]] = i;
261*c1d255d3SCy Schubert dtable['='] = 0;
262*c1d255d3SCy Schubert
263*c1d255d3SCy Schubert count = 0;
264*c1d255d3SCy Schubert for (i = 0; i < len; i++) {
265*c1d255d3SCy Schubert if (dtable[(u8) src[i]] != 0x80)
266*c1d255d3SCy Schubert count++;
267*c1d255d3SCy Schubert }
268*c1d255d3SCy Schubert
269*c1d255d3SCy Schubert if (count == 0)
270*c1d255d3SCy Schubert return NULL;
271*c1d255d3SCy Schubert extra_pad = (8 - count % 8) % 8;
272*c1d255d3SCy Schubert
273*c1d255d3SCy Schubert olen = (count + extra_pad) / 8 * 5;
274*c1d255d3SCy Schubert pos = out = os_malloc(olen);
275*c1d255d3SCy Schubert if (!out)
276*c1d255d3SCy Schubert return NULL;
277*c1d255d3SCy Schubert
278*c1d255d3SCy Schubert count = 0;
279*c1d255d3SCy Schubert for (i = 0; i < len + extra_pad; i++) {
280*c1d255d3SCy Schubert u8 val;
281*c1d255d3SCy Schubert
282*c1d255d3SCy Schubert if (i >= len)
283*c1d255d3SCy Schubert val = '=';
284*c1d255d3SCy Schubert else
285*c1d255d3SCy Schubert val = src[i];
286*c1d255d3SCy Schubert tmp = dtable[val];
287*c1d255d3SCy Schubert if (tmp == 0x80)
288*c1d255d3SCy Schubert continue;
289*c1d255d3SCy Schubert
290*c1d255d3SCy Schubert if (val == '=')
291*c1d255d3SCy Schubert pad++;
292*c1d255d3SCy Schubert block <<= 5;
293*c1d255d3SCy Schubert block |= tmp;
294*c1d255d3SCy Schubert count++;
295*c1d255d3SCy Schubert if (count == 8) {
296*c1d255d3SCy Schubert *pos++ = (block >> 32) & 0xff;
297*c1d255d3SCy Schubert *pos++ = (block >> 24) & 0xff;
298*c1d255d3SCy Schubert *pos++ = (block >> 16) & 0xff;
299*c1d255d3SCy Schubert *pos++ = (block >> 8) & 0xff;
300*c1d255d3SCy Schubert *pos++ = block & 0xff;
301*c1d255d3SCy Schubert count = 0;
302*c1d255d3SCy Schubert block = 0;
303*c1d255d3SCy Schubert if (pad) {
304*c1d255d3SCy Schubert /* Leave in all the available bits with zero
305*c1d255d3SCy Schubert * padding to full octets from right. */
306*c1d255d3SCy Schubert pos -= pad * 5 / 8;
307*c1d255d3SCy Schubert break;
308*c1d255d3SCy Schubert }
309*c1d255d3SCy Schubert }
310*c1d255d3SCy Schubert }
311*c1d255d3SCy Schubert
312*c1d255d3SCy Schubert *out_len = pos - out;
313*c1d255d3SCy Schubert return out;
314*c1d255d3SCy Schubert }
315*c1d255d3SCy Schubert
316*c1d255d3SCy Schubert
sae_pk_get_be19(const u8 * buf)317*c1d255d3SCy Schubert u32 sae_pk_get_be19(const u8 *buf)
318*c1d255d3SCy Schubert {
319*c1d255d3SCy Schubert return (buf[0] << 11) | (buf[1] << 3) | (buf[2] >> 5);
320*c1d255d3SCy Schubert }
321*c1d255d3SCy Schubert
322*c1d255d3SCy Schubert
323*c1d255d3SCy Schubert /* shift left by two octets and three bits; fill in zeros from right;
324*c1d255d3SCy Schubert * len must be at least three */
sae_pk_buf_shift_left_19(u8 * buf,size_t len)325*c1d255d3SCy Schubert void sae_pk_buf_shift_left_19(u8 *buf, size_t len)
326*c1d255d3SCy Schubert {
327*c1d255d3SCy Schubert u8 *dst, *src, *end;
328*c1d255d3SCy Schubert
329*c1d255d3SCy Schubert dst = buf;
330*c1d255d3SCy Schubert src = buf + 2;
331*c1d255d3SCy Schubert end = buf + len;
332*c1d255d3SCy Schubert
333*c1d255d3SCy Schubert while (src + 1 < end) {
334*c1d255d3SCy Schubert *dst++ = (src[0] << 3) | (src[1] >> 5);
335*c1d255d3SCy Schubert src++;
336*c1d255d3SCy Schubert }
337*c1d255d3SCy Schubert *dst++ = *src << 3;
338*c1d255d3SCy Schubert *dst++ = 0;
339*c1d255d3SCy Schubert *dst++ = 0;
340*c1d255d3SCy Schubert }
341*c1d255d3SCy Schubert
342*c1d255d3SCy Schubert
sae_pk_buf_shift_left_1(u8 * buf,size_t len)343*c1d255d3SCy Schubert static void sae_pk_buf_shift_left_1(u8 *buf, size_t len)
344*c1d255d3SCy Schubert {
345*c1d255d3SCy Schubert u8 *dst, *src, *end;
346*c1d255d3SCy Schubert
347*c1d255d3SCy Schubert dst = buf;
348*c1d255d3SCy Schubert src = buf;
349*c1d255d3SCy Schubert end = buf + len;
350*c1d255d3SCy Schubert
351*c1d255d3SCy Schubert while (src + 1 < end) {
352*c1d255d3SCy Schubert *dst++ = (src[0] << 1) | (src[1] >> 7);
353*c1d255d3SCy Schubert src++;
354*c1d255d3SCy Schubert }
355*c1d255d3SCy Schubert *dst++ = *src << 1;
356*c1d255d3SCy Schubert }
357*c1d255d3SCy Schubert
358*c1d255d3SCy Schubert
sae_pk_set_password(struct sae_data * sae,const char * password)359*c1d255d3SCy Schubert int sae_pk_set_password(struct sae_data *sae, const char *password)
360*c1d255d3SCy Schubert {
361*c1d255d3SCy Schubert struct sae_temporary_data *tmp = sae->tmp;
362*c1d255d3SCy Schubert size_t len, pw_len;
363*c1d255d3SCy Schubert u8 *pw, *pos;
364*c1d255d3SCy Schubert int bits;
365*c1d255d3SCy Schubert u32 val = 0, val19;
366*c1d255d3SCy Schubert unsigned int val_bits = 0;
367*c1d255d3SCy Schubert
368*c1d255d3SCy Schubert if (!tmp)
369*c1d255d3SCy Schubert return -1;
370*c1d255d3SCy Schubert
371*c1d255d3SCy Schubert os_memset(tmp->fingerprint, 0, sizeof(tmp->fingerprint));
372*c1d255d3SCy Schubert tmp->fingerprint_bytes = tmp->fingerprint_bits = 0;
373*c1d255d3SCy Schubert
374*c1d255d3SCy Schubert len = os_strlen(password);
375*c1d255d3SCy Schubert if (len < 1 || !sae_pk_valid_password(password))
376*c1d255d3SCy Schubert return -1;
377*c1d255d3SCy Schubert
378*c1d255d3SCy Schubert pw = sae_pk_base32_decode(password, len, &pw_len);
379*c1d255d3SCy Schubert if (!pw)
380*c1d255d3SCy Schubert return -1;
381*c1d255d3SCy Schubert
382*c1d255d3SCy Schubert tmp->sec = (pw[0] & BIT(7)) ? 3 : 5;
383*c1d255d3SCy Schubert tmp->lambda = len - len / 5;
384*c1d255d3SCy Schubert tmp->fingerprint_bits = 8 * tmp->sec + 19 * tmp->lambda / 4 - 5;
385*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "SAE-PK: Sec=%u Lambda=%zu fingerprint_bits=%zu",
386*c1d255d3SCy Schubert tmp->sec, tmp->lambda, tmp->fingerprint_bits);
387*c1d255d3SCy Schubert
388*c1d255d3SCy Schubert /* Construct Fingerprint from PasswordBase by prefixing with Sec zero
389*c1d255d3SCy Schubert * octets and skipping the Sec_1b bits */
390*c1d255d3SCy Schubert pos = &tmp->fingerprint[tmp->sec];
391*c1d255d3SCy Schubert bits = tmp->fingerprint_bits - 8 * tmp->sec;
392*c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "SAE-PK: PasswordBase", pw, pw_len);
393*c1d255d3SCy Schubert while (bits > 0) {
394*c1d255d3SCy Schubert if (val_bits < 8) {
395*c1d255d3SCy Schubert sae_pk_buf_shift_left_1(pw, pw_len); /* Sec_1b */
396*c1d255d3SCy Schubert val19 = sae_pk_get_be19(pw);
397*c1d255d3SCy Schubert sae_pk_buf_shift_left_19(pw, pw_len);
398*c1d255d3SCy Schubert val = (val << 19) | val19;
399*c1d255d3SCy Schubert val_bits += 19;
400*c1d255d3SCy Schubert }
401*c1d255d3SCy Schubert if (val_bits >= 8) {
402*c1d255d3SCy Schubert if (bits < 8)
403*c1d255d3SCy Schubert break;
404*c1d255d3SCy Schubert *pos++ = (val >> (val_bits - 8)) & 0xff;
405*c1d255d3SCy Schubert val_bits -= 8;
406*c1d255d3SCy Schubert bits -= 8;
407*c1d255d3SCy Schubert }
408*c1d255d3SCy Schubert }
409*c1d255d3SCy Schubert if (bits > 0) {
410*c1d255d3SCy Schubert val >>= val_bits - bits;
411*c1d255d3SCy Schubert *pos++ = val << (8 - bits);
412*c1d255d3SCy Schubert }
413*c1d255d3SCy Schubert tmp->fingerprint_bytes = pos - tmp->fingerprint;
414*c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Fingerprint",
415*c1d255d3SCy Schubert tmp->fingerprint, tmp->fingerprint_bytes);
416*c1d255d3SCy Schubert bin_clear_free(pw, pw_len);
417*c1d255d3SCy Schubert return 0;
418*c1d255d3SCy Schubert }
419*c1d255d3SCy Schubert
420*c1d255d3SCy Schubert
sae_group_2_hash_len(int group)421*c1d255d3SCy Schubert static size_t sae_group_2_hash_len(int group)
422*c1d255d3SCy Schubert {
423*c1d255d3SCy Schubert switch (group) {
424*c1d255d3SCy Schubert case 19:
425*c1d255d3SCy Schubert return 32;
426*c1d255d3SCy Schubert case 20:
427*c1d255d3SCy Schubert return 48;
428*c1d255d3SCy Schubert case 21:
429*c1d255d3SCy Schubert return 64;
430*c1d255d3SCy Schubert }
431*c1d255d3SCy Schubert
432*c1d255d3SCy Schubert return 0;
433*c1d255d3SCy Schubert }
434*c1d255d3SCy Schubert
435*c1d255d3SCy Schubert
sae_deinit_pk(struct sae_pk * pk)436*c1d255d3SCy Schubert void sae_deinit_pk(struct sae_pk *pk)
437*c1d255d3SCy Schubert {
438*c1d255d3SCy Schubert if (pk) {
439*c1d255d3SCy Schubert wpabuf_free(pk->m);
440*c1d255d3SCy Schubert crypto_ec_key_deinit(pk->key);
441*c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
442*c1d255d3SCy Schubert crypto_ec_key_deinit(pk->sign_key_override);
443*c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
444*c1d255d3SCy Schubert wpabuf_free(pk->pubkey);
445*c1d255d3SCy Schubert os_free(pk);
446*c1d255d3SCy Schubert }
447*c1d255d3SCy Schubert }
448*c1d255d3SCy Schubert
449*c1d255d3SCy Schubert
sae_parse_pk(const char * val)450*c1d255d3SCy Schubert struct sae_pk * sae_parse_pk(const char *val)
451*c1d255d3SCy Schubert {
452*c1d255d3SCy Schubert struct sae_pk *pk;
453*c1d255d3SCy Schubert const char *pos;
454*c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
455*c1d255d3SCy Schubert const char *pos2;
456*c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
457*c1d255d3SCy Schubert size_t len;
458*c1d255d3SCy Schubert unsigned char *der;
459*c1d255d3SCy Schubert size_t der_len, b_len;
460*c1d255d3SCy Schubert
461*c1d255d3SCy Schubert /* <m-as-hexdump>:<base64-encoded-DER-encoded-key> */
462*c1d255d3SCy Schubert
463*c1d255d3SCy Schubert pos = os_strchr(val, ':');
464*c1d255d3SCy Schubert if (!pos || (pos - val) & 0x01)
465*c1d255d3SCy Schubert return NULL;
466*c1d255d3SCy Schubert len = (pos - val) / 2;
467*c1d255d3SCy Schubert if (len != SAE_PK_M_LEN) {
468*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "SAE: Unexpected Modifier M length %zu",
469*c1d255d3SCy Schubert len);
470*c1d255d3SCy Schubert return NULL;
471*c1d255d3SCy Schubert }
472*c1d255d3SCy Schubert
473*c1d255d3SCy Schubert pk = os_zalloc(sizeof(*pk));
474*c1d255d3SCy Schubert if (!pk)
475*c1d255d3SCy Schubert return NULL;
476*c1d255d3SCy Schubert pk->m = wpabuf_alloc(len);
477*c1d255d3SCy Schubert if (!pk->m || hexstr2bin(val, wpabuf_put(pk->m, len), len)) {
478*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "SAE: Failed to parse m");
479*c1d255d3SCy Schubert goto fail;
480*c1d255d3SCy Schubert }
481*c1d255d3SCy Schubert
482*c1d255d3SCy Schubert pos++;
483*c1d255d3SCy Schubert b_len = os_strlen(pos);
484*c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
485*c1d255d3SCy Schubert pos2 = os_strchr(pos, ':');
486*c1d255d3SCy Schubert if (pos2) {
487*c1d255d3SCy Schubert b_len = pos2 - pos;
488*c1d255d3SCy Schubert pos2++;
489*c1d255d3SCy Schubert }
490*c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
491*c1d255d3SCy Schubert der = base64_decode(pos, b_len, &der_len);
492*c1d255d3SCy Schubert if (!der) {
493*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "SAE: Failed to base64 decode PK key");
494*c1d255d3SCy Schubert goto fail;
495*c1d255d3SCy Schubert }
496*c1d255d3SCy Schubert
497*c1d255d3SCy Schubert pk->key = crypto_ec_key_parse_priv(der, der_len);
498*c1d255d3SCy Schubert bin_clear_free(der, der_len);
499*c1d255d3SCy Schubert if (!pk->key)
500*c1d255d3SCy Schubert goto fail;
501*c1d255d3SCy Schubert pk->group = crypto_ec_key_group(pk->key);
502*c1d255d3SCy Schubert pk->pubkey = crypto_ec_key_get_subject_public_key(pk->key);
503*c1d255d3SCy Schubert if (!pk->pubkey)
504*c1d255d3SCy Schubert goto fail;
505*c1d255d3SCy Schubert
506*c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
507*c1d255d3SCy Schubert if (pos2) {
508*c1d255d3SCy Schubert der = base64_decode(pos2, os_strlen(pos2), &der_len);
509*c1d255d3SCy Schubert if (!der) {
510*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
511*c1d255d3SCy Schubert "SAE: Failed to base64 decode PK key");
512*c1d255d3SCy Schubert goto fail;
513*c1d255d3SCy Schubert }
514*c1d255d3SCy Schubert
515*c1d255d3SCy Schubert pk->sign_key_override = crypto_ec_key_parse_priv(der, der_len);
516*c1d255d3SCy Schubert bin_clear_free(der, der_len);
517*c1d255d3SCy Schubert if (!pk->sign_key_override)
518*c1d255d3SCy Schubert goto fail;
519*c1d255d3SCy Schubert }
520*c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
521*c1d255d3SCy Schubert
522*c1d255d3SCy Schubert return pk;
523*c1d255d3SCy Schubert fail:
524*c1d255d3SCy Schubert sae_deinit_pk(pk);
525*c1d255d3SCy Schubert return NULL;
526*c1d255d3SCy Schubert }
527*c1d255d3SCy Schubert
528*c1d255d3SCy Schubert
sae_hash(size_t hash_len,const u8 * data,size_t len,u8 * hash)529*c1d255d3SCy Schubert int sae_hash(size_t hash_len, const u8 *data, size_t len, u8 *hash)
530*c1d255d3SCy Schubert {
531*c1d255d3SCy Schubert if (hash_len == 32)
532*c1d255d3SCy Schubert return sha256_vector(1, &data, &len, hash);
533*c1d255d3SCy Schubert #ifdef CONFIG_SHA384
534*c1d255d3SCy Schubert if (hash_len == 48)
535*c1d255d3SCy Schubert return sha384_vector(1, &data, &len, hash);
536*c1d255d3SCy Schubert #endif /* CONFIG_SHA384 */
537*c1d255d3SCy Schubert #ifdef CONFIG_SHA512
538*c1d255d3SCy Schubert if (hash_len == 64)
539*c1d255d3SCy Schubert return sha512_vector(1, &data, &len, hash);
540*c1d255d3SCy Schubert #endif /* CONFIG_SHA512 */
541*c1d255d3SCy Schubert return -1;
542*c1d255d3SCy Schubert }
543*c1d255d3SCy Schubert
544*c1d255d3SCy Schubert
sae_pk_hash_sig_data(struct sae_data * sae,size_t hash_len,bool ap,const u8 * m,size_t m_len,const u8 * pubkey,size_t pubkey_len,u8 * hash)545*c1d255d3SCy Schubert static int sae_pk_hash_sig_data(struct sae_data *sae, size_t hash_len,
546*c1d255d3SCy Schubert bool ap, const u8 *m, size_t m_len,
547*c1d255d3SCy Schubert const u8 *pubkey, size_t pubkey_len, u8 *hash)
548*c1d255d3SCy Schubert {
549*c1d255d3SCy Schubert struct sae_temporary_data *tmp = sae->tmp;
550*c1d255d3SCy Schubert struct wpabuf *sig_data;
551*c1d255d3SCy Schubert u8 *pos;
552*c1d255d3SCy Schubert int ret = -1;
553*c1d255d3SCy Schubert
554*c1d255d3SCy Schubert /* Signed data for KeyAuth: eleAP || eleSTA || scaAP || scaSTA ||
555*c1d255d3SCy Schubert * M || K_AP || AP-BSSID || STA-MAC */
556*c1d255d3SCy Schubert sig_data = wpabuf_alloc(tmp->prime_len * 6 + m_len + pubkey_len +
557*c1d255d3SCy Schubert 2 * ETH_ALEN);
558*c1d255d3SCy Schubert if (!sig_data)
559*c1d255d3SCy Schubert goto fail;
560*c1d255d3SCy Schubert pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
561*c1d255d3SCy Schubert if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->own_commit_element_ecc :
562*c1d255d3SCy Schubert tmp->peer_commit_element_ecc,
563*c1d255d3SCy Schubert pos, pos + tmp->prime_len) < 0)
564*c1d255d3SCy Schubert goto fail;
565*c1d255d3SCy Schubert pos = wpabuf_put(sig_data, 2 * tmp->prime_len);
566*c1d255d3SCy Schubert if (crypto_ec_point_to_bin(tmp->ec, ap ? tmp->peer_commit_element_ecc :
567*c1d255d3SCy Schubert tmp->own_commit_element_ecc,
568*c1d255d3SCy Schubert pos, pos + tmp->prime_len) < 0)
569*c1d255d3SCy Schubert goto fail;
570*c1d255d3SCy Schubert if (crypto_bignum_to_bin(ap ? tmp->own_commit_scalar :
571*c1d255d3SCy Schubert sae->peer_commit_scalar,
572*c1d255d3SCy Schubert wpabuf_put(sig_data, tmp->prime_len),
573*c1d255d3SCy Schubert tmp->prime_len, tmp->prime_len) < 0 ||
574*c1d255d3SCy Schubert crypto_bignum_to_bin(ap ? sae->peer_commit_scalar :
575*c1d255d3SCy Schubert tmp->own_commit_scalar,
576*c1d255d3SCy Schubert wpabuf_put(sig_data, tmp->prime_len),
577*c1d255d3SCy Schubert tmp->prime_len, tmp->prime_len) < 0)
578*c1d255d3SCy Schubert goto fail;
579*c1d255d3SCy Schubert wpabuf_put_data(sig_data, m, m_len);
580*c1d255d3SCy Schubert wpabuf_put_data(sig_data, pubkey, pubkey_len);
581*c1d255d3SCy Schubert wpabuf_put_data(sig_data, ap ? tmp->own_addr : tmp->peer_addr,
582*c1d255d3SCy Schubert ETH_ALEN);
583*c1d255d3SCy Schubert wpabuf_put_data(sig_data, ap ? tmp->peer_addr : tmp->own_addr,
584*c1d255d3SCy Schubert ETH_ALEN);
585*c1d255d3SCy Schubert wpa_hexdump_buf_key(MSG_DEBUG, "SAE-PK: Data to be signed for KeyAuth",
586*c1d255d3SCy Schubert sig_data);
587*c1d255d3SCy Schubert if (sae_hash(hash_len, wpabuf_head(sig_data), wpabuf_len(sig_data),
588*c1d255d3SCy Schubert hash) < 0)
589*c1d255d3SCy Schubert goto fail;
590*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: hash(data to be signed)",
591*c1d255d3SCy Schubert hash, hash_len);
592*c1d255d3SCy Schubert ret = 0;
593*c1d255d3SCy Schubert fail:
594*c1d255d3SCy Schubert wpabuf_free(sig_data);
595*c1d255d3SCy Schubert return ret;
596*c1d255d3SCy Schubert }
597*c1d255d3SCy Schubert
598*c1d255d3SCy Schubert
sae_write_confirm_pk(struct sae_data * sae,struct wpabuf * buf)599*c1d255d3SCy Schubert int sae_write_confirm_pk(struct sae_data *sae, struct wpabuf *buf)
600*c1d255d3SCy Schubert {
601*c1d255d3SCy Schubert struct sae_temporary_data *tmp = sae->tmp;
602*c1d255d3SCy Schubert struct wpabuf *sig = NULL;
603*c1d255d3SCy Schubert size_t need;
604*c1d255d3SCy Schubert int ret = -1;
605*c1d255d3SCy Schubert u8 *encr_mod;
606*c1d255d3SCy Schubert size_t encr_mod_len;
607*c1d255d3SCy Schubert const struct sae_pk *pk;
608*c1d255d3SCy Schubert u8 hash[SAE_MAX_HASH_LEN];
609*c1d255d3SCy Schubert size_t hash_len;
610*c1d255d3SCy Schubert struct crypto_ec_key *key;
611*c1d255d3SCy Schubert
612*c1d255d3SCy Schubert if (!tmp)
613*c1d255d3SCy Schubert return -1;
614*c1d255d3SCy Schubert
615*c1d255d3SCy Schubert pk = tmp->ap_pk;
616*c1d255d3SCy Schubert if (!sae->pk || !pk)
617*c1d255d3SCy Schubert return 0;
618*c1d255d3SCy Schubert
619*c1d255d3SCy Schubert key = pk->key;
620*c1d255d3SCy Schubert #ifdef CONFIG_TESTING_OPTIONS
621*c1d255d3SCy Schubert if (tmp->omit_pk_elem)
622*c1d255d3SCy Schubert return 0;
623*c1d255d3SCy Schubert if (pk->sign_key_override) {
624*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "TESTING: Override SAE-PK signing key");
625*c1d255d3SCy Schubert key = pk->sign_key_override;
626*c1d255d3SCy Schubert }
627*c1d255d3SCy Schubert #endif /* CONFIG_TESTING_OPTIONS */
628*c1d255d3SCy Schubert
629*c1d255d3SCy Schubert if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
630*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
631*c1d255d3SCy Schubert "SAE-PK: No KEK available for writing confirm");
632*c1d255d3SCy Schubert return -1;
633*c1d255d3SCy Schubert }
634*c1d255d3SCy Schubert
635*c1d255d3SCy Schubert if (!tmp->ec) {
636*c1d255d3SCy Schubert /* Only ECC groups are supported for SAE-PK in the current
637*c1d255d3SCy Schubert * implementation. */
638*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
639*c1d255d3SCy Schubert "SAE-PK: SAE commit did not use an ECC group");
640*c1d255d3SCy Schubert return -1;
641*c1d255d3SCy Schubert }
642*c1d255d3SCy Schubert
643*c1d255d3SCy Schubert hash_len = sae_group_2_hash_len(pk->group);
644*c1d255d3SCy Schubert if (sae_pk_hash_sig_data(sae, hash_len, true, wpabuf_head(pk->m),
645*c1d255d3SCy Schubert wpabuf_len(pk->m), wpabuf_head(pk->pubkey),
646*c1d255d3SCy Schubert wpabuf_len(pk->pubkey), hash) < 0)
647*c1d255d3SCy Schubert goto fail;
648*c1d255d3SCy Schubert sig = crypto_ec_key_sign(key, hash, hash_len);
649*c1d255d3SCy Schubert if (!sig)
650*c1d255d3SCy Schubert goto fail;
651*c1d255d3SCy Schubert wpa_hexdump_buf(MSG_DEBUG, "SAE-PK: KeyAuth = Sig_AP()", sig);
652*c1d255d3SCy Schubert
653*c1d255d3SCy Schubert /* TODO: fragmentation if any of the elements needs it for a group
654*c1d255d3SCy Schubert * using sufficiently large primes (none of the currently supported
655*c1d255d3SCy Schubert * ones do) */
656*c1d255d3SCy Schubert
657*c1d255d3SCy Schubert encr_mod_len = wpabuf_len(pk->m) + AES_BLOCK_SIZE;
658*c1d255d3SCy Schubert need = 4 + wpabuf_len(pk->pubkey) + 3 + wpabuf_len(sig) +
659*c1d255d3SCy Schubert 6 + encr_mod_len;
660*c1d255d3SCy Schubert if (wpabuf_tailroom(buf) < need) {
661*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
662*c1d255d3SCy Schubert "SAE-PK: No room in message buffer for SAE-PK elements (%zu < %zu)",
663*c1d255d3SCy Schubert wpabuf_tailroom(buf), need);
664*c1d255d3SCy Schubert goto fail;
665*c1d255d3SCy Schubert }
666*c1d255d3SCy Schubert
667*c1d255d3SCy Schubert /* FILS Public Key element */
668*c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
669*c1d255d3SCy Schubert wpabuf_put_u8(buf, 2 + wpabuf_len(pk->pubkey));
670*c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_PUBLIC_KEY);
671*c1d255d3SCy Schubert wpabuf_put_u8(buf, 2); /* Key Type: ECDSA public key */
672*c1d255d3SCy Schubert wpabuf_put_buf(buf, pk->pubkey);
673*c1d255d3SCy Schubert
674*c1d255d3SCy Schubert /* FILS Key Confirmation element (KeyAuth) */
675*c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXTENSION);
676*c1d255d3SCy Schubert wpabuf_put_u8(buf, 1 + wpabuf_len(sig));
677*c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_EXT_FILS_KEY_CONFIRM);
678*c1d255d3SCy Schubert /* KeyAuth = Sig_AP(eleAP || eleSTA || scaAP || scaSTA || M || K_AP ||
679*c1d255d3SCy Schubert * AP-BSSID || STA-MAC) */
680*c1d255d3SCy Schubert wpabuf_put_buf(buf, sig);
681*c1d255d3SCy Schubert
682*c1d255d3SCy Schubert /* SAE-PK element */
683*c1d255d3SCy Schubert wpabuf_put_u8(buf, WLAN_EID_VENDOR_SPECIFIC);
684*c1d255d3SCy Schubert wpabuf_put_u8(buf, 4 + encr_mod_len);
685*c1d255d3SCy Schubert wpabuf_put_be32(buf, SAE_PK_IE_VENDOR_TYPE);
686*c1d255d3SCy Schubert /* EncryptedModifier = AES-SIV-Q(M); no AAD */
687*c1d255d3SCy Schubert encr_mod = wpabuf_put(buf, encr_mod_len);
688*c1d255d3SCy Schubert if (aes_siv_encrypt(tmp->kek, tmp->kek_len,
689*c1d255d3SCy Schubert wpabuf_head(pk->m), wpabuf_len(pk->m),
690*c1d255d3SCy Schubert 0, NULL, NULL, encr_mod) < 0)
691*c1d255d3SCy Schubert goto fail;
692*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
693*c1d255d3SCy Schubert encr_mod, encr_mod_len);
694*c1d255d3SCy Schubert
695*c1d255d3SCy Schubert ret = 0;
696*c1d255d3SCy Schubert fail:
697*c1d255d3SCy Schubert wpabuf_free(sig);
698*c1d255d3SCy Schubert return ret;
699*c1d255d3SCy Schubert
700*c1d255d3SCy Schubert }
701*c1d255d3SCy Schubert
702*c1d255d3SCy Schubert
sae_pk_valid_fingerprint(struct sae_data * sae,const u8 * m,size_t m_len,const u8 * k_ap,size_t k_ap_len,int group)703*c1d255d3SCy Schubert static bool sae_pk_valid_fingerprint(struct sae_data *sae,
704*c1d255d3SCy Schubert const u8 *m, size_t m_len,
705*c1d255d3SCy Schubert const u8 *k_ap, size_t k_ap_len, int group)
706*c1d255d3SCy Schubert {
707*c1d255d3SCy Schubert struct sae_temporary_data *tmp = sae->tmp;
708*c1d255d3SCy Schubert u8 *hash_data, *pos;
709*c1d255d3SCy Schubert size_t hash_len, hash_data_len;
710*c1d255d3SCy Schubert u8 hash[SAE_MAX_HASH_LEN];
711*c1d255d3SCy Schubert int res;
712*c1d255d3SCy Schubert
713*c1d255d3SCy Schubert if (!tmp->fingerprint_bytes) {
714*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG,
715*c1d255d3SCy Schubert "SAE-PK: No PW available for K_AP fingerprint check");
716*c1d255d3SCy Schubert return false;
717*c1d255d3SCy Schubert }
718*c1d255d3SCy Schubert
719*c1d255d3SCy Schubert /* Fingerprint = L(Hash(SSID || M || K_AP), 0, 8*Sec + 19*Lambda/4 - 5)
720*c1d255d3SCy Schubert */
721*c1d255d3SCy Schubert
722*c1d255d3SCy Schubert hash_len = sae_group_2_hash_len(group);
723*c1d255d3SCy Schubert hash_data_len = tmp->ssid_len + m_len + k_ap_len;
724*c1d255d3SCy Schubert hash_data = os_malloc(hash_data_len);
725*c1d255d3SCy Schubert if (!hash_data)
726*c1d255d3SCy Schubert return false;
727*c1d255d3SCy Schubert pos = hash_data;
728*c1d255d3SCy Schubert os_memcpy(pos, tmp->ssid, tmp->ssid_len);
729*c1d255d3SCy Schubert pos += tmp->ssid_len;
730*c1d255d3SCy Schubert os_memcpy(pos, m, m_len);
731*c1d255d3SCy Schubert pos += m_len;
732*c1d255d3SCy Schubert os_memcpy(pos, k_ap, k_ap_len);
733*c1d255d3SCy Schubert
734*c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "SAE-PK: SSID || M || K_AP",
735*c1d255d3SCy Schubert hash_data, hash_data_len);
736*c1d255d3SCy Schubert res = sae_hash(hash_len, hash_data, hash_data_len, hash);
737*c1d255d3SCy Schubert bin_clear_free(hash_data, hash_data_len);
738*c1d255d3SCy Schubert if (res < 0)
739*c1d255d3SCy Schubert return false;
740*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: Hash(SSID || M || K_AP)",
741*c1d255d3SCy Schubert hash, hash_len);
742*c1d255d3SCy Schubert
743*c1d255d3SCy Schubert if (tmp->fingerprint_bits > hash_len * 8) {
744*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
745*c1d255d3SCy Schubert "SAE-PK: Not enough hash output bits for the fingerprint");
746*c1d255d3SCy Schubert return false;
747*c1d255d3SCy Schubert }
748*c1d255d3SCy Schubert if (tmp->fingerprint_bits % 8) {
749*c1d255d3SCy Schubert size_t extra;
750*c1d255d3SCy Schubert
751*c1d255d3SCy Schubert /* Zero out the extra bits in the last octet */
752*c1d255d3SCy Schubert extra = 8 - tmp->fingerprint_bits % 8;
753*c1d255d3SCy Schubert pos = &hash[tmp->fingerprint_bits / 8];
754*c1d255d3SCy Schubert *pos = (*pos >> extra) << extra;
755*c1d255d3SCy Schubert }
756*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: Fingerprint", hash,
757*c1d255d3SCy Schubert tmp->fingerprint_bytes);
758*c1d255d3SCy Schubert res = os_memcmp_const(hash, tmp->fingerprint, tmp->fingerprint_bytes);
759*c1d255d3SCy Schubert if (res) {
760*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "SAE-PK: K_AP fingerprint mismatch");
761*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: Expected fingerprint",
762*c1d255d3SCy Schubert tmp->fingerprint, tmp->fingerprint_bytes);
763*c1d255d3SCy Schubert return false;
764*c1d255d3SCy Schubert }
765*c1d255d3SCy Schubert
766*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "SAE-PK: Valid K_AP fingerprint");
767*c1d255d3SCy Schubert return true;
768*c1d255d3SCy Schubert }
769*c1d255d3SCy Schubert
770*c1d255d3SCy Schubert
sae_check_confirm_pk(struct sae_data * sae,const u8 * ies,size_t ies_len)771*c1d255d3SCy Schubert int sae_check_confirm_pk(struct sae_data *sae, const u8 *ies, size_t ies_len)
772*c1d255d3SCy Schubert {
773*c1d255d3SCy Schubert struct sae_temporary_data *tmp = sae->tmp;
774*c1d255d3SCy Schubert const u8 *k_ap;
775*c1d255d3SCy Schubert u8 m[SAE_PK_M_LEN];
776*c1d255d3SCy Schubert size_t k_ap_len;
777*c1d255d3SCy Schubert struct crypto_ec_key *key;
778*c1d255d3SCy Schubert int res;
779*c1d255d3SCy Schubert u8 hash[SAE_MAX_HASH_LEN];
780*c1d255d3SCy Schubert size_t hash_len;
781*c1d255d3SCy Schubert int group;
782*c1d255d3SCy Schubert struct ieee802_11_elems elems;
783*c1d255d3SCy Schubert
784*c1d255d3SCy Schubert if (!tmp)
785*c1d255d3SCy Schubert return -1;
786*c1d255d3SCy Schubert if (!sae->pk || tmp->ap_pk)
787*c1d255d3SCy Schubert return 0;
788*c1d255d3SCy Schubert
789*c1d255d3SCy Schubert if (tmp->kek_len != 32 && tmp->kek_len != 48 && tmp->kek_len != 64) {
790*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
791*c1d255d3SCy Schubert "SAE-PK: No KEK available for checking confirm");
792*c1d255d3SCy Schubert return -1;
793*c1d255d3SCy Schubert }
794*c1d255d3SCy Schubert
795*c1d255d3SCy Schubert if (!tmp->ec) {
796*c1d255d3SCy Schubert /* Only ECC groups are supported for SAE-PK in the current
797*c1d255d3SCy Schubert * implementation. */
798*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
799*c1d255d3SCy Schubert "SAE-PK: SAE commit did not use an ECC group");
800*c1d255d3SCy Schubert return -1;
801*c1d255d3SCy Schubert }
802*c1d255d3SCy Schubert
803*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: Received confirm IEs", ies, ies_len);
804*c1d255d3SCy Schubert if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
805*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "SAE-PK: Failed to parse confirm IEs");
806*c1d255d3SCy Schubert return -1;
807*c1d255d3SCy Schubert }
808*c1d255d3SCy Schubert if (!elems.fils_pk || !elems.fils_key_confirm || !elems.sae_pk) {
809*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
810*c1d255d3SCy Schubert "SAE-PK: Not all mandatory IEs included in confirm");
811*c1d255d3SCy Schubert return -1;
812*c1d255d3SCy Schubert }
813*c1d255d3SCy Schubert
814*c1d255d3SCy Schubert /* TODO: Fragment reassembly */
815*c1d255d3SCy Schubert
816*c1d255d3SCy Schubert if (elems.sae_pk_len < SAE_PK_M_LEN + AES_BLOCK_SIZE) {
817*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
818*c1d255d3SCy Schubert "SAE-PK: No room for EncryptedModifier in SAE-PK element");
819*c1d255d3SCy Schubert return -1;
820*c1d255d3SCy Schubert }
821*c1d255d3SCy Schubert
822*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: EncryptedModifier",
823*c1d255d3SCy Schubert elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE);
824*c1d255d3SCy Schubert
825*c1d255d3SCy Schubert if (aes_siv_decrypt(tmp->kek, tmp->kek_len,
826*c1d255d3SCy Schubert elems.sae_pk, SAE_PK_M_LEN + AES_BLOCK_SIZE,
827*c1d255d3SCy Schubert 0, NULL, NULL, m) < 0) {
828*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
829*c1d255d3SCy Schubert "SAE-PK: Failed to decrypt EncryptedModifier");
830*c1d255d3SCy Schubert return -1;
831*c1d255d3SCy Schubert }
832*c1d255d3SCy Schubert wpa_hexdump_key(MSG_DEBUG, "SAE-PK: Modifier M", m, SAE_PK_M_LEN);
833*c1d255d3SCy Schubert
834*c1d255d3SCy Schubert if (elems.fils_pk[0] != 2) {
835*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "SAE-PK: Unsupported public key type %u",
836*c1d255d3SCy Schubert elems.fils_pk[0]);
837*c1d255d3SCy Schubert return -1;
838*c1d255d3SCy Schubert }
839*c1d255d3SCy Schubert k_ap_len = elems.fils_pk_len - 1;
840*c1d255d3SCy Schubert k_ap = elems.fils_pk + 1;
841*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: Received K_AP", k_ap, k_ap_len);
842*c1d255d3SCy Schubert /* TODO: Check against the public key, if one is stored in the network
843*c1d255d3SCy Schubert * profile */
844*c1d255d3SCy Schubert
845*c1d255d3SCy Schubert key = crypto_ec_key_parse_pub(k_ap, k_ap_len);
846*c1d255d3SCy Schubert if (!key) {
847*c1d255d3SCy Schubert wpa_printf(MSG_INFO, "SAE-PK: Failed to parse K_AP");
848*c1d255d3SCy Schubert return -1;
849*c1d255d3SCy Schubert }
850*c1d255d3SCy Schubert
851*c1d255d3SCy Schubert group = crypto_ec_key_group(key);
852*c1d255d3SCy Schubert if (!sae_pk_valid_fingerprint(sae, m, SAE_PK_M_LEN, k_ap, k_ap_len,
853*c1d255d3SCy Schubert group)) {
854*c1d255d3SCy Schubert crypto_ec_key_deinit(key);
855*c1d255d3SCy Schubert return -1;
856*c1d255d3SCy Schubert }
857*c1d255d3SCy Schubert
858*c1d255d3SCy Schubert wpa_hexdump(MSG_DEBUG, "SAE-PK: Received KeyAuth",
859*c1d255d3SCy Schubert elems.fils_key_confirm, elems.fils_key_confirm_len);
860*c1d255d3SCy Schubert
861*c1d255d3SCy Schubert hash_len = sae_group_2_hash_len(group);
862*c1d255d3SCy Schubert if (sae_pk_hash_sig_data(sae, hash_len, false, m, SAE_PK_M_LEN,
863*c1d255d3SCy Schubert k_ap, k_ap_len, hash) < 0) {
864*c1d255d3SCy Schubert crypto_ec_key_deinit(key);
865*c1d255d3SCy Schubert return -1;
866*c1d255d3SCy Schubert }
867*c1d255d3SCy Schubert
868*c1d255d3SCy Schubert res = crypto_ec_key_verify_signature(key, hash, hash_len,
869*c1d255d3SCy Schubert elems.fils_key_confirm,
870*c1d255d3SCy Schubert elems.fils_key_confirm_len);
871*c1d255d3SCy Schubert crypto_ec_key_deinit(key);
872*c1d255d3SCy Schubert
873*c1d255d3SCy Schubert if (res != 1) {
874*c1d255d3SCy Schubert wpa_printf(MSG_INFO,
875*c1d255d3SCy Schubert "SAE-PK: Invalid or incorrect signature in KeyAuth");
876*c1d255d3SCy Schubert return -1;
877*c1d255d3SCy Schubert }
878*c1d255d3SCy Schubert
879*c1d255d3SCy Schubert wpa_printf(MSG_DEBUG, "SAE-PK: Valid KeyAuth signature received");
880*c1d255d3SCy Schubert
881*c1d255d3SCy Schubert /* TODO: Store validated public key into network profile */
882*c1d255d3SCy Schubert
883*c1d255d3SCy Schubert return 0;
884*c1d255d3SCy Schubert }
885