Browse Source

WPS NFC: Update NFC connection handover design

The new Device Password ID 7 is used to indicate that NFC connection
handover is used with DH public key hash from both devices being
exchanged over the NFC connection handover messages. This allows an
abbreviated M1-M2 handshake to be used since Device Password does not
need to be used when DH is authenticated with the out-of-band
information (validation of the public key against the hash).

Signed-hostap: Jouni Malinen <jouni@qca.qualcomm.com>
Jouni Malinen 12 years ago
parent
commit
975491793b
7 changed files with 131 additions and 16 deletions
  1. 4 0
      src/wps/wps.c
  2. 4 0
      src/wps/wps.h
  3. 10 5
      src/wps/wps_attr_build.c
  4. 6 3
      src/wps/wps_attr_parse.c
  5. 86 0
      src/wps/wps_common.c
  6. 2 1
      src/wps/wps_defs.h
  7. 19 7
      src/wps/wps_registrar.c

+ 4 - 0
src/wps/wps.c

@@ -58,6 +58,10 @@ struct wps_data * wps_init(const struct wps_config *cfg)
 	}
 
 #ifdef CONFIG_WPS_NFC
+	if (cfg->pin == NULL &&
+	    cfg->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
+		data->dev_pw_id = cfg->dev_pw_id;
+
 	if (cfg->wps->ap && !cfg->registrar && cfg->wps->ap_nfc_dev_pw_id) {
 		/* Keep AP PIN as alternative Device Password */
 		data->alt_dev_pw_id = data->dev_pw_id;

+ 4 - 0
src/wps/wps.h

@@ -859,6 +859,10 @@ struct wpabuf * wps_nfc_token_build(int ndef, int id, struct wpabuf *pubkey,
 struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 				  struct wpabuf **privkey,
 				  struct wpabuf **dev_pw);
+struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey);
+struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey);
 
 /* ndef.c */
 struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);

+ 10 - 5
src/wps/wps_attr_build.c

@@ -38,8 +38,11 @@ int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg)
 		wps->wps->dh_ctx = NULL;
 		pubkey = wpabuf_dup(wps->wps->dh_pubkey);
 #ifdef CONFIG_WPS_NFC
-	} else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
-		   wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
+	} else if ((wps->dev_pw_id >= 0x10 ||
+		    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) &&
+		   wps->wps->ap &&
+		   (wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id ||
+		    wps->wps->ap_nfc_dh_pubkey)) {
 		wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
 		if (wps->wps->ap_nfc_dh_privkey == NULL) {
 			wpa_printf(MSG_DEBUG,
@@ -399,9 +402,11 @@ int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
 		    pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
 	wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
 	wpabuf_put_be16(msg, dev_pw_id);
-	wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
-			dev_pw, dev_pw_len);
-	wpabuf_put_data(msg, dev_pw, dev_pw_len);
+	if (dev_pw) {
+		wpa_hexdump_key(MSG_DEBUG, "WPS: OOB Device Password",
+				dev_pw, dev_pw_len);
+		wpabuf_put_data(msg, dev_pw, dev_pw_len);
+	}
 
 	return 0;
 }

+ 6 - 3
src/wps/wps_attr_parse.c

@@ -263,10 +263,13 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
 		attr->dev_password_id = pos;
 		break;
 	case ATTR_OOB_DEVICE_PASSWORD:
-		if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
-		    WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+		if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
 		    len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
-		    WPS_OOB_DEVICE_PASSWORD_LEN) {
+		    WPS_OOB_DEVICE_PASSWORD_LEN ||
+		    (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
+		     WPS_OOB_DEVICE_PASSWORD_MIN_LEN &&
+		     WPA_GET_BE16(pos + WPS_OOB_PUBKEY_HASH_LEN) !=
+		     DEV_PW_NFC_CONNECTION_HANDOVER)) {
 			wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
 				   "Password length %u", len);
 			return -1;

+ 86 - 0
src/wps/wps_common.c

@@ -671,4 +671,90 @@ struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
 	return wps_nfc_token_build(ndef, *id, *pubkey, *dev_pw);
 }
 
+
+struct wpabuf * wps_build_nfc_handover_req(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey)
+{
+	struct wpabuf *msg;
+	void *len;
+
+	if (ctx == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+		   "handover request");
+
+	if (nfc_dh_pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+			   "configured");
+		return NULL;
+	}
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return msg;
+	len = wpabuf_put(msg, 2);
+
+	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
+				 nfc_dh_pubkey, NULL, 0) ||
+	    wps_build_uuid_e(msg, ctx->uuid) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
+
+	return msg;
+}
+
+
+static int wps_build_ssid(struct wpabuf *msg, struct wps_context *wps)
+{
+	wpa_printf(MSG_DEBUG, "WPS:  * SSID");
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID in Connection Handover Select",
+			  wps->ssid, wps->ssid_len);
+	wpabuf_put_be16(msg, ATTR_SSID);
+	wpabuf_put_be16(msg, wps->ssid_len);
+	wpabuf_put_data(msg, wps->ssid, wps->ssid_len);
+	return 0;
+}
+
+
+struct wpabuf * wps_build_nfc_handover_sel(struct wps_context *ctx,
+					   struct wpabuf *nfc_dh_pubkey)
+{
+	struct wpabuf *msg;
+	void *len;
+
+	if (ctx == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPS: Building attributes for NFC connection "
+		   "handover select");
+
+	if (nfc_dh_pubkey == NULL) {
+		wpa_printf(MSG_DEBUG, "WPS: No NFC OOB Device Password "
+			   "configured");
+		return NULL;
+	}
+
+	msg = wpabuf_alloc(1000);
+	if (msg == NULL)
+		return msg;
+	len = wpabuf_put(msg, 2);
+
+	if (wps_build_oob_dev_pw(msg, DEV_PW_NFC_CONNECTION_HANDOVER,
+				 nfc_dh_pubkey, NULL, 0) ||
+	    wps_build_ssid(msg, ctx) ||
+	    wps_build_wfa_ext(msg, 0, NULL, 0)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	WPA_PUT_BE16(len, wpabuf_len(msg) - 2);
+
+	return msg;
+}
+
 #endif /* CONFIG_WPS_NFC */

+ 2 - 1
src/wps/wps_defs.h

@@ -155,7 +155,8 @@ enum wps_dev_password_id {
 	DEV_PW_MACHINE_SPECIFIED = 0x0002,
 	DEV_PW_REKEY = 0x0003,
 	DEV_PW_PUSHBUTTON = 0x0004,
-	DEV_PW_REGISTRAR_SPECIFIED = 0x0005
+	DEV_PW_REGISTRAR_SPECIFIED = 0x0005,
+	DEV_PW_NFC_CONNECTION_HANDOVER = 0x0007
 };
 
 /* Message Type */

+ 19 - 7
src/wps/wps_registrar.c

@@ -1361,6 +1361,13 @@ static int wps_get_dev_password(struct wps_data *wps)
 		pin_len = 8;
 #ifdef CONFIG_WPS_NFC
 	} else if (wps->nfc_pw_token) {
+		if (wps->nfc_pw_token->pw_id == DEV_PW_NFC_CONNECTION_HANDOVER)
+		{
+			wpa_printf(MSG_DEBUG, "WPS: Using NFC connection "
+				   "handover and abbreviated WPS handshake "
+				   "without Device Password");
+			return 0;
+		}
 		wpa_printf(MSG_DEBUG, "WPS: Use OOB Device Password from NFC "
 			   "Password Token");
 		pin = wps->nfc_pw_token->dev_pw;
@@ -2556,6 +2563,9 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
 	    wps->dev_pw_id != DEV_PW_USER_SPECIFIED &&
 	    wps->dev_pw_id != DEV_PW_MACHINE_SPECIFIED &&
 	    wps->dev_pw_id != DEV_PW_REGISTRAR_SPECIFIED &&
+#ifdef CONFIG_WPS_NFC
+	    wps->dev_pw_id != DEV_PW_NFC_CONNECTION_HANDOVER &&
+#endif /* CONFIG_WPS_NFC */
 	    (wps->dev_pw_id != DEV_PW_PUSHBUTTON ||
 	     !wps->wps->registrar->pbc)) {
 		wpa_printf(MSG_DEBUG, "WPS: Unsupported Device Password ID %d",
@@ -2565,7 +2575,8 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
 	}
 
 #ifdef CONFIG_WPS_NFC
-	if (wps->dev_pw_id >= 0x10) {
+	if (wps->dev_pw_id >= 0x10 ||
+	    wps->dev_pw_id == DEV_PW_NFC_CONNECTION_HANDOVER) {
 		struct wps_nfc_pw_token *token;
 		const u8 *addr[1];
 		u8 hash[WPS_HASH_LEN];
@@ -3541,10 +3552,12 @@ int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
 	os_memcpy(token->pubkey_hash, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
 	token->pw_id = pw_id;
 	token->pk_hash_provided_oob = pk_hash_provided_oob;
-	wpa_snprintf_hex_uppercase((char *) token->dev_pw,
-				   sizeof(token->dev_pw),
-				   dev_pw, dev_pw_len);
-	token->dev_pw_len = dev_pw_len * 2;
+	if (dev_pw) {
+		wpa_snprintf_hex_uppercase((char *) token->dev_pw,
+					   sizeof(token->dev_pw),
+					   dev_pw, dev_pw_len);
+		token->dev_pw_len = dev_pw_len * 2;
+	}
 
 	dl_list_add(&reg->nfc_pw_tokens, &token->list);
 
@@ -3573,8 +3586,7 @@ int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
 	u16 id;
 	size_t dev_pw_len;
 
-	if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
-	    WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
+	if (oob_dev_pw_len < WPS_OOB_PUBKEY_HASH_LEN + 2 ||
 	    oob_dev_pw_len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
 	    WPS_OOB_DEVICE_PASSWORD_LEN)
 		return -1;