1 /*
2 * Wi-Fi Protected Setup - attribute processing
3 * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "crypto/sha256.h"
13 #include "wps_i.h"
14
15
wps_process_authenticator(struct wps_data * wps,const u8 * authenticator,const struct wpabuf * msg)16 int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
17 const struct wpabuf *msg)
18 {
19 u8 hash[SHA256_MAC_LEN];
20 const u8 *addr[2];
21 size_t len[2];
22
23 if (authenticator == NULL) {
24 wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
25 "included");
26 return -1;
27 }
28
29 if (wps->last_msg == NULL) {
30 wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
31 "validating authenticator");
32 return -1;
33 }
34
35 /* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
36 * (M_curr* is M_curr without the Authenticator attribute)
37 */
38 addr[0] = wpabuf_head(wps->last_msg);
39 len[0] = wpabuf_len(wps->last_msg);
40 addr[1] = wpabuf_head(msg);
41 len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
42
43 if (hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, len,
44 hash) < 0 ||
45 os_memcmp_const(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
46 wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
47 return -1;
48 }
49
50 return 0;
51 }
52
53
wps_process_key_wrap_auth(struct wps_data * wps,struct wpabuf * msg,const u8 * key_wrap_auth)54 int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
55 const u8 *key_wrap_auth)
56 {
57 u8 hash[SHA256_MAC_LEN];
58 const u8 *head;
59 size_t len;
60
61 if (key_wrap_auth == NULL) {
62 wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
63 return -1;
64 }
65
66 head = wpabuf_head(msg);
67 len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
68 if (head + len != key_wrap_auth - 4) {
69 wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
70 "decrypted attribute");
71 return -1;
72 }
73
74 if (hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash) < 0 ||
75 os_memcmp_const(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
76 wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
77 return -1;
78 }
79
80 return 0;
81 }
82
83
wps_process_cred_network_idx(struct wps_credential * cred,const u8 * idx)84 static int wps_process_cred_network_idx(struct wps_credential *cred,
85 const u8 *idx)
86 {
87 if (idx == NULL) {
88 wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
89 "Network Index");
90 return -1;
91 }
92
93 wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx);
94
95 return 0;
96 }
97
98
wps_process_cred_ssid(struct wps_credential * cred,const u8 * ssid,size_t ssid_len)99 static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,
100 size_t ssid_len)
101 {
102 if (ssid == NULL) {
103 wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID");
104 return -1;
105 }
106
107 /* Remove zero-padding since some Registrar implementations seem to use
108 * hardcoded 32-octet length for this attribute */
109 while (ssid_len > 0 && ssid[ssid_len - 1] == 0)
110 ssid_len--;
111
112 wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len);
113 if (ssid_len <= sizeof(cred->ssid)) {
114 os_memcpy(cred->ssid, ssid, ssid_len);
115 cred->ssid_len = ssid_len;
116 }
117
118 return 0;
119 }
120
121
wps_process_cred_auth_type(struct wps_credential * cred,const u8 * auth_type)122 static int wps_process_cred_auth_type(struct wps_credential *cred,
123 const u8 *auth_type)
124 {
125 if (auth_type == NULL) {
126 wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
127 "Authentication Type");
128 return -1;
129 }
130
131 cred->auth_type = WPA_GET_BE16(auth_type);
132 wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x",
133 cred->auth_type);
134
135 return 0;
136 }
137
138
wps_process_cred_encr_type(struct wps_credential * cred,const u8 * encr_type)139 static int wps_process_cred_encr_type(struct wps_credential *cred,
140 const u8 *encr_type)
141 {
142 if (encr_type == NULL) {
143 wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
144 "Encryption Type");
145 return -1;
146 }
147
148 cred->encr_type = WPA_GET_BE16(encr_type);
149 wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x",
150 cred->encr_type);
151
152 return 0;
153 }
154
155
wps_process_cred_network_key_idx(struct wps_credential * cred,const u8 * key_idx)156 static int wps_process_cred_network_key_idx(struct wps_credential *cred,
157 const u8 *key_idx)
158 {
159 if (key_idx == NULL)
160 return 0; /* optional attribute */
161
162 wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
163 cred->key_idx = *key_idx;
164
165 return 0;
166 }
167
168
wps_process_cred_network_key(struct wps_credential * cred,const u8 * key,size_t key_len)169 static int wps_process_cred_network_key(struct wps_credential *cred,
170 const u8 *key, size_t key_len)
171 {
172 if (key == NULL) {
173 wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
174 "Network Key");
175 if (cred->auth_type == WPS_AUTH_OPEN &&
176 cred->encr_type == WPS_ENCR_NONE) {
177 wpa_printf(MSG_DEBUG, "WPS: Workaround - Allow "
178 "missing mandatory Network Key attribute "
179 "for open network");
180 return 0;
181 }
182 return -1;
183 }
184
185 wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
186 if (key_len <= sizeof(cred->key)) {
187 os_memcpy(cred->key, key, key_len);
188 cred->key_len = key_len;
189 }
190
191 return 0;
192 }
193
194
wps_process_cred_mac_addr(struct wps_credential * cred,const u8 * mac_addr)195 static int wps_process_cred_mac_addr(struct wps_credential *cred,
196 const u8 *mac_addr)
197 {
198 if (mac_addr == NULL) {
199 wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
200 "MAC Address");
201 return -1;
202 }
203
204 wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr));
205 os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN);
206
207 return 0;
208 }
209
210
wps_workaround_cred_key(struct wps_credential * cred)211 static int wps_workaround_cred_key(struct wps_credential *cred)
212 {
213 if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
214 cred->key_len > 8 && cred->key_len < 64 &&
215 cred->key[cred->key_len - 1] == 0) {
216 #ifdef CONFIG_WPS_STRICT
217 wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses "
218 "forbidden NULL termination");
219 wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
220 cred->key, cred->key_len);
221 return -1;
222 #else /* CONFIG_WPS_STRICT */
223 /*
224 * A deployed external registrar is known to encode ASCII
225 * passphrases incorrectly. Remove the extra NULL termination
226 * to fix the encoding.
227 */
228 wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
229 "termination from ASCII passphrase");
230 cred->key_len--;
231 #endif /* CONFIG_WPS_STRICT */
232 }
233
234
235 if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
236 (cred->key_len < 8 || has_ctrl_char(cred->key, cred->key_len))) {
237 wpa_printf(MSG_INFO, "WPS: Reject credential with invalid WPA/WPA2-Personal passphrase");
238 wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
239 cred->key, cred->key_len);
240 return -1;
241 }
242
243 return 0;
244 }
245
246
wps_process_cred(struct wps_parse_attr * attr,struct wps_credential * cred)247 int wps_process_cred(struct wps_parse_attr *attr,
248 struct wps_credential *cred)
249 {
250 wpa_printf(MSG_DEBUG, "WPS: Process Credential");
251
252 /* TODO: support multiple Network Keys */
253 if (wps_process_cred_network_idx(cred, attr->network_idx) ||
254 wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
255 wps_process_cred_auth_type(cred, attr->auth_type) ||
256 wps_process_cred_encr_type(cred, attr->encr_type) ||
257 wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
258 wps_process_cred_network_key(cred, attr->network_key,
259 attr->network_key_len) ||
260 wps_process_cred_mac_addr(cred, attr->mac_addr))
261 return -1;
262
263 return wps_workaround_cred_key(cred);
264 }
265
266
wps_process_ap_settings(struct wps_parse_attr * attr,struct wps_credential * cred)267 int wps_process_ap_settings(struct wps_parse_attr *attr,
268 struct wps_credential *cred)
269 {
270 wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings");
271 os_memset(cred, 0, sizeof(*cred));
272 /* TODO: optional attributes New Password and Device Password ID */
273 if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
274 wps_process_cred_auth_type(cred, attr->auth_type) ||
275 wps_process_cred_encr_type(cred, attr->encr_type) ||
276 wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
277 wps_process_cred_network_key(cred, attr->network_key,
278 attr->network_key_len) ||
279 wps_process_cred_mac_addr(cred, attr->mac_addr))
280 return -1;
281
282 return wps_workaround_cred_key(cred);
283 }
284