WPS 2.0: Make WSC 2.0 support to be build option (CONFIG_WPS2)
[libeap.git] / src / wps / wps_enrollee.c
index 2629228..6e2b511 100644 (file)
@@ -664,7 +664,7 @@ static int wps_process_r_snonce2(struct wps_data *wps, const u8 *r_snonce2)
 
 
 static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
-                             size_t cred_len)
+                             size_t cred_len, int wps2)
 {
        struct wps_parse_attr attr;
        struct wpabuf msg;
@@ -689,8 +689,30 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
                 * reasons, allow this to be processed since we do not really
                 * use the MAC Address information for anything.
                 */
+#ifdef CONFIG_WPS_STRICT
+               if (wps2) {
+                       wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
+                                  "MAC Address in AP Settings");
+                       return -1;
+               }
+#endif /* CONFIG_WPS_STRICT */
        }
 
+#ifdef CONFIG_WPS2
+       if (!(wps->cred.encr_type &
+             (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES))) {
+               if (wps->cred.encr_type & WPS_ENCR_WEP) {
+                       wpa_printf(MSG_INFO, "WPS: Reject Credential "
+                                  "due to WEP configuration");
+                       return -2;
+               }
+
+               wpa_printf(MSG_INFO, "WPS: Reject Credential due to "
+                          "invalid encr_type 0x%x", wps->cred.encr_type);
+               return -1;
+       }
+#endif /* CONFIG_WPS2 */
+
        if (wps->wps->cred_cb) {
                wps->cred.cred_attr = cred - 4;
                wps->cred.cred_attr_len = cred_len + 4;
@@ -704,9 +726,10 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
 
 
 static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
-                            size_t cred_len[], size_t num_cred)
+                            size_t cred_len[], size_t num_cred, int wps2)
 {
        size_t i;
+       int ok = 0;
 
        if (wps->wps->ap)
                return 0;
@@ -718,17 +741,29 @@ static int wps_process_creds(struct wps_data *wps, const u8 *cred[],
        }
 
        for (i = 0; i < num_cred; i++) {
-               if (wps_process_cred_e(wps, cred[i], cred_len[i]))
+               int res;
+               res = wps_process_cred_e(wps, cred[i], cred_len[i], wps2);
+               if (res == 0)
+                       ok++;
+               else if (res == -2)
+                       wpa_printf(MSG_DEBUG, "WPS: WEP credential skipped");
+               else
                        return -1;
        }
 
+       if (ok == 0) {
+               wpa_printf(MSG_DEBUG, "WPS: No valid Credential attribute "
+                          "received");
+               return -1;
+       }
+
        return 0;
 }
 
 
 static int wps_process_ap_settings_e(struct wps_data *wps,
                                     struct wps_parse_attr *attr,
-                                    struct wpabuf *attrs)
+                                    struct wpabuf *attrs, int wps2)
 {
        struct wps_credential cred;
 
@@ -754,8 +789,59 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
                 * reasons, allow this to be processed since we do not really
                 * use the MAC Address information for anything.
                 */
+#ifdef CONFIG_WPS_STRICT
+               if (wps2) {
+                       wpa_printf(MSG_INFO, "WPS: Do not accept incorrect "
+                                  "MAC Address in AP Settings");
+                       return -1;
+               }
+#endif /* CONFIG_WPS_STRICT */
+       }
+
+#ifdef CONFIG_WPS2
+       if (!(cred.encr_type & (WPS_ENCR_NONE | WPS_ENCR_TKIP | WPS_ENCR_AES)))
+       {
+               if (cred.encr_type & WPS_ENCR_WEP) {
+                       wpa_printf(MSG_INFO, "WPS: Reject new AP settings "
+                                  "due to WEP configuration");
+                       return -1;
+               }
+
+               wpa_printf(MSG_INFO, "WPS: Reject new AP settings due to "
+                          "invalid encr_type 0x%x", cred.encr_type);
+               return -1;
+       }
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_WPS_STRICT
+       if (wps2) {
+               if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) ==
+                   WPS_ENCR_TKIP ||
+                   (cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+                   WPS_AUTH_WPAPSK) {
+                       wpa_printf(MSG_INFO, "WPS-STRICT: Invalid WSC 2.0 "
+                                  "AP Settings: WPA-Personal/TKIP only");
+                       return -1;
+               }
+       }
+#endif /* CONFIG_WPS_STRICT */
+
+#ifdef CONFIG_WPS2
+       if ((cred.encr_type & (WPS_ENCR_TKIP | WPS_ENCR_AES)) == WPS_ENCR_TKIP)
+       {
+               wpa_printf(MSG_DEBUG, "WPS: Upgrade encr_type TKIP -> "
+                          "TKIP+AES");
+               cred.encr_type |= WPS_ENCR_AES;
        }
 
+       if ((cred.auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) ==
+           WPS_AUTH_WPAPSK) {
+               wpa_printf(MSG_DEBUG, "WPS: Upgrade auth_type WPAPSK -> "
+                          "WPAPSK+WPA2PSK");
+               cred.auth_type |= WPS_AUTH_WPA2PSK;
+       }
+#endif /* CONFIG_WPS2 */
+
        if (wps->wps->cred_cb) {
                cred.cred_attr = wpabuf_head(attrs);
                cred.cred_attr_len = wpabuf_len(attrs);
@@ -895,6 +981,12 @@ static enum wps_process_res wps_process_m4(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m4_encr(decrypted) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -942,6 +1034,12 @@ static enum wps_process_res wps_process_m6(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m6_encr(decrypted) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
@@ -989,13 +1087,20 @@ static enum wps_process_res wps_process_m8(struct wps_data *wps,
                return WPS_CONTINUE;
        }
 
+       if (wps_validate_m8_encr(decrypted, wps->wps->ap) < 0) {
+               wpabuf_free(decrypted);
+               wps->state = SEND_WSC_NACK;
+               return WPS_CONTINUE;
+       }
+
        wpa_printf(MSG_DEBUG, "WPS: Processing decrypted Encrypted Settings "
                   "attribute");
        if (wps_parse_msg(decrypted, &eattr) < 0 ||
            wps_process_key_wrap_auth(wps, decrypted, eattr.key_wrap_auth) ||
            wps_process_creds(wps, eattr.cred, eattr.cred_len,
-                             eattr.num_cred) ||
-           wps_process_ap_settings_e(wps, &eattr, decrypted)) {
+                             eattr.num_cred, attr->version2 != NULL) ||
+           wps_process_ap_settings_e(wps, &eattr, decrypted,
+                                     attr->version2 != NULL)) {
                wpabuf_free(decrypted);
                wps->state = SEND_WSC_NACK;
                return WPS_CONTINUE;
@@ -1031,22 +1136,32 @@ static enum wps_process_res wps_process_wsc_msg(struct wps_data *wps,
 
        switch (*attr.msg_type) {
        case WPS_M2:
+               if (wps_validate_m2(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m2(wps, msg, &attr);
                break;
        case WPS_M2D:
+               if (wps_validate_m2d(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m2d(wps, &attr);
                break;
        case WPS_M4:
+               if (wps_validate_m4(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m4(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
                        wps_fail_event(wps->wps, WPS_M4);
                break;
        case WPS_M6:
+               if (wps_validate_m6(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m6(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
                        wps_fail_event(wps->wps, WPS_M6);
                break;
        case WPS_M8:
+               if (wps_validate_m8(msg) < 0)
+                       return WPS_FAILURE;
                ret = wps_process_m8(wps, msg, &attr);
                if (ret == WPS_FAILURE || wps->state == SEND_WSC_NACK)
                        wps_fail_event(wps->wps, WPS_M8);
@@ -1219,8 +1334,12 @@ enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
        case WSC_UPnP:
                return wps_process_wsc_msg(wps, msg);
        case WSC_ACK:
+               if (wps_validate_wsc_ack(msg) < 0)
+                       return WPS_FAILURE;
                return wps_process_wsc_ack(wps, msg);
        case WSC_NACK:
+               if (wps_validate_wsc_nack(msg) < 0)
+                       return WPS_FAILURE;
                return wps_process_wsc_nack(wps, msg);
        default:
                wpa_printf(MSG_DEBUG, "WPS: Unsupported op_code %d", op_code);