From patchwork Tue Oct 31 18:47:42 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442178 Received: from mail-qk1-f174.google.com (mail-qk1-f174.google.com [209.85.222.174]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 273041DFE0 for ; Tue, 31 Oct 2023 18:47:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="muHa/xpg" Received: by mail-qk1-f174.google.com with SMTP id af79cd13be357-77896da2118so399843085a.1 for ; Tue, 31 Oct 2023 11:47:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778079; x=1699382879; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=m0MlWvCYhCwlsmNdvrzrAosY7P3OZncO6qdkvW2lwOQ=; b=muHa/xpgEY/hmzadOA/qKNVWpVbAkfnqieCovpghGBQ+l6IThfUeRaWCAybE395fGc iWW2oijaq6ml7uJhYyoA5xL51XVK5c/V2W/6ofhmjpLV/VRMPTucsZW8Qeu+I4rOxsKl 4MiLNMwXEViotyRoWw17Zp9gttEwjWetKOv05cbj66kCc6x9w/kc7DQYtZEdRKMgStNg tzdNeEBvfOKXF4RVGqM3IzwkORt2oAk4TJ9c+8dBsgjWiP3f048xPMiinzrmbNBO2XQ+ 3BJk4TibnmjNdpogfK87f8VHc0JuFQkSiWn997OC2ORMI7guVuYcG5snAgtGiyqahGbO GiDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778079; x=1699382879; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=m0MlWvCYhCwlsmNdvrzrAosY7P3OZncO6qdkvW2lwOQ=; b=jxjadQRGN/y1T3PhezaXRyVlhDD4zq4D1eavL7BOd6608sKMC5K0mely4QOie+KmQv KkNdH1gcW+6awCGyhGcvVFZRh6Shf451G2TvVDCVzAtgwI1V09fTLQB4KXGuZfDsMmBq ksI5B1Sr8QdL+DOcKFQVFpzEy6kBUGMZXqhE0QbiuNzA1WQY/TQMnMHaK9ZVy5vgZedH +ho6PqYBJU+JMzAyKMu4NCq3WdoZUVwGfjkeArVSAFLaqgqCAxNA3NBVZfeBjtjIzw6B tQ0dzAxXZES1zedONT1XcCkecrAbiFF+paxG7KM++HtZD9GIlqouujRGwe3TWsqN7Swh CdHw== X-Gm-Message-State: AOJu0Yzom1UZACY6l8Kr4ZEjJUUq0bWwMACOFeMxjpVHc3Ab41cmTdRb hxSjTksZkeLaYxW8JOtVKNokNbm1MJ0= X-Google-Smtp-Source: AGHT+IF8IK5R7RfDKKsCkMxe+6gaLfV6wtrun7FhDI8o7imZ8uJw4N/ivcN1P3t7m9Cxlqf8vt1GrA== X-Received: by 2002:a05:620a:2448:b0:779:e352:6db9 with SMTP id h8-20020a05620a244800b00779e3526db9mr16013523qkn.30.1698778078911; Tue, 31 Oct 2023 11:47:58 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.47.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:47:58 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 1/9] dpp: remove scan_periodic_stop calls Date: Tue, 31 Oct 2023 11:47:42 -0700 Message-Id: <20231031184750.722404-2-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Stopping periodic scans and not restarting them prevents autoconnect from working again if DPP (or the post-DPP connect) fails. Since the DPP offchannel work is at a higher priority than scanning (and since new offchannels are queue'd before canceling) there is no risk of a scan happening during DPP so its safe to leave periodic scans running. --- src/dpp.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/dpp.c b/src/dpp.c index 638d65e0..cfdfaa38 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -2553,8 +2553,6 @@ static struct l_dbus_message *dpp_dbus_start_enrollee(struct l_dbus *dbus, */ dpp_start_presence(dpp, &freq, 1); - scan_periodic_stop(dpp->wdev_id); - dpp_property_changed_notify(dpp); return NULL; @@ -2685,8 +2683,6 @@ static struct l_dbus_message *dpp_start_configurator_common( network_get_ssid(network), hs->akm_suite); - scan_periodic_stop(dpp->wdev_id); - dpp_property_changed_notify(dpp); l_debug("DPP Start Configurator: %s", dpp->uri); From patchwork Tue Oct 31 18:47:43 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442179 Received: from mail-qv1-f50.google.com (mail-qv1-f50.google.com [209.85.219.50]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C7BFB200C8 for ; Tue, 31 Oct 2023 18:48:01 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="mqjs2FqD" Received: by mail-qv1-f50.google.com with SMTP id 6a1803df08f44-66cfd874520so34747876d6.2 for ; Tue, 31 Oct 2023 11:48:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778080; x=1699382880; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=Nptuvb3rG4jOCkKSF1uD1bV7MqUOnFAipdBaz37VPN4=; b=mqjs2FqDOlaAFaT5KQODUJC1sEZcyPwRBc/iahTv1IZlZ29vmPy1Jbis0oaGkafm3p kjcC0ccI3uUGar6q+JCjxsNsUw9yRGme9t+8YkvXzymHiYeUnMpS3fM5/rhV7bHc91LL 9qpx7xUfcHvpRWOEw7awOx51H43jvqUwd2NPz8FgAcjbd1AMl9SXLmSKX+t7+cFKIDdi IHZ7/xbJV8vI4JtNj2xn43fBclgMK8IR6D5JMClxd3kzFtrCP+KjShMGV40wBI1yJX08 70oj7zbAGcq/3zqb7zH407N3bmByGs+nd0csgvCdpo5RUshZsOkaTu9KX1pjkNZ+NLrC L74A== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778080; x=1699382880; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=Nptuvb3rG4jOCkKSF1uD1bV7MqUOnFAipdBaz37VPN4=; b=sx00lL02FA3WncjzqpPPb8GL7xNsC+6L0AdhPbbvXpDmLNIGjYiUjd3TLChKG0RZIm 0QW68+6lX7ASVwkslvwvKWM6IpQZgbipu6MKkhYJPrXudP8o89ZzEe4wVf3/BtyO6ar1 +aKM8KcK1UxQnSJxuegendhV8qNVfrhtQ9f8RxF3eKDiJxCXjLmaPk9Ii+z+qOF9v3P4 9CTEUKAHnK6I3R4v4aSPPDy91lW9HOTj+B8YfWwLeN/yxvyhiqMGIXdKAPCdLGzp1yJ/ XehwnD4DAg8VRUpXAqvO0Asvl5y9fMD6reJy/gaXs5F7DEz4P7HwkYR7amAI8M1wYNh3 AM7w== X-Gm-Message-State: AOJu0Ywl/YT2AB87GP2I0bYSeZxjg26Agu3tWjZoV08rvsHboRbC20Hz v1KVgNDB0tMGQJwKncw7ClKcM33sQGg= X-Google-Smtp-Source: AGHT+IEZZWMkqJRQ+W2InY0LMWF+GW4AOWKNS1XFxsCz5SVJpjudSWnILvaikX5982yC+OKTHyxrXA== X-Received: by 2002:ad4:5c8c:0:b0:66d:3548:9c1a with SMTP id o12-20020ad45c8c000000b0066d35489c1amr18100835qvh.54.1698778080379; Tue, 31 Oct 2023 11:48:00 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.47.59 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:00 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 2/9] dpp: fix config request header check Date: Tue, 31 Oct 2023 11:47:43 -0700 Message-Id: <20231031184750.722404-3-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The check for the header was incorrect according to the spec. Table 58 indicates that the "Query Response Info" should be set to 0x00 for the configuration request. The frame handler was expecting 0x7f which is the value for the config response frame. Unfortunately wpa_supplicant also gets this wrong and uses 0x7f in all cases which is likely why this value was set incorrectly in IWD. The issue is that IWD's config request is correct which means IWD<->IWD configuration is broken. (and wpa_supplicant as a configurator likely doesn't validate the config request). Fix this by checking both 0x7f and 0x00 to handle both supplicants. --- src/dpp.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/dpp.c b/src/dpp.c index cfdfaa38..dcf5953f 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -920,6 +920,21 @@ static void dpp_send_config_response(struct dpp_sm *dpp, uint8_t status) dpp_send_frame(dpp, iov, 2, dpp->current_freq); } +static bool dpp_check_config_header(const uint8_t *ptr) +{ + /* + * Table 58. General Format of DPP Configuration Request frame + * + * Unfortunately wpa_supplicant hard codes 0x7f as the Query Response + * Info so we need to handle both cases. + */ + return ptr[0] == IE_TYPE_ADVERTISEMENT_PROTOCOL && + ptr[1] == 0x08 && + (ptr[2] == 0x7f || ptr[2] == 0x00) && + ptr[3] == IE_TYPE_VENDOR_SPECIFIC && + ptr[4] == 5; +} + static void dpp_handle_config_request_frame(const struct mmpdu_header *frame, const void *body, size_t body_len, int rssi, void *user_data) @@ -937,8 +952,6 @@ static void dpp_handle_config_request_frame(const struct mmpdu_header *frame, const uint8_t *e_nonce = NULL; size_t wrapped_len = 0; _auto_(l_free) uint8_t *unwrapped = NULL; - uint8_t hdr_check[] = { IE_TYPE_ADVERTISEMENT_PROTOCOL, 0x08, 0x7f, - IE_TYPE_VENDOR_SPECIFIC, 5 }; struct json_iter jsiter; _auto_(l_free) char *tech = NULL; _auto_(l_free) char *role = NULL; @@ -965,10 +978,10 @@ static void dpp_handle_config_request_frame(const struct mmpdu_header *frame, dpp->diag_token = *ptr++; - if (memcmp(ptr, hdr_check, sizeof(hdr_check))) + if (!dpp_check_config_header(ptr)) return; - ptr += sizeof(hdr_check); + ptr += 5; if (memcmp(ptr, wifi_alliance_oui, sizeof(wifi_alliance_oui))) return; From patchwork Tue Oct 31 18:47:44 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442180 Received: from mail-yw1-f169.google.com (mail-yw1-f169.google.com [209.85.128.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 078C21DFE0 for ; Tue, 31 Oct 2023 18:48:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Aeb2ctLH" Received: by mail-yw1-f169.google.com with SMTP id 00721157ae682-5afabb23900so49534217b3.2 for ; Tue, 31 Oct 2023 11:48:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778082; x=1699382882; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=1THlJ04vIb0fySHMf9Vww6qxLSn99GPGcL4C1Oqq6b0=; b=Aeb2ctLHdWSAqFUKGCmk1KuLM8n794aky4tbp4qZ7E5cKWpDjVTq3VdnXAvYrjDTmA ScEXQKqiytmax6e3Sqz79aGdyN21oIKpHS/q1QR6krDq3xS3hgR+YwE9aRYkTUcJZ0j6 S/59zKzt5JpzMuZpopTczLfepKhxip2ENPIrOawPKLrAhE2QjhZkpShUhIx7pSG2aLWz qoJRSpXQg1WdGL+QS5uLUO3E5q3b0khp7bdYPKpWD2jZAaYHzFKB96NLe06YqSf38dcj sodN5q4zvzmhyuqmnN6+AMIV3QXOmiFY5NN2aHGIX6KQfFFObdtrc3VKqrbJxZY9wtTG 1MZQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778082; x=1699382882; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=1THlJ04vIb0fySHMf9Vww6qxLSn99GPGcL4C1Oqq6b0=; b=wtNYwWf311loGx3+f9f59kxxvNkmUq8cG8/DOsJjTe8VS8LKG+YUdOEI5xYb+aj6Pc 9vsdb4QsJFdp2ndJLcURJjcjGXkj5cP8aFcJx6Nej0rS98Mk8wf/JBik85crSvW1e9hx 4Ex2yFsFJCbwLdfVnbL+6OeMcnQSK1KjUFT3cv2fnukph710aM5VO3d4LGxzc1CLUVy4 vgbaYJr0pBCQdCWeo6yTS3NpfbWjGHTsXxAwZQHMuvox8PXE+lmB7CZiDcHCoF9fV2KQ xPfRkL/W8wadCe7TYDwj6ttRX0GAjGKde6dtuovyCY7oipVZ8NQV44o9aXAyo+tiZdhg ki/g== X-Gm-Message-State: AOJu0YzYpPV3NH2OkH5vWeoHISH2Wi3bhCT+98uL+8kHx3K/WR4fyMnG f6cV27mjSgBgJJGd7jk8P9A4TyDqX9s= X-Google-Smtp-Source: AGHT+IHJhWznI8ZlpT3TaCzCSSTnDVXIb38ARew5fMtor3eqRgCf2FFDQXGRZwKm0MphzWB0S+s6uQ== X-Received: by 2002:a81:4f90:0:b0:59f:5361:d18c with SMTP id d138-20020a814f90000000b0059f5361d18cmr15308817ywb.41.1698778081893; Tue, 31 Oct 2023 11:48:01 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.48.00 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:01 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 3/9] dpp: allow enrollee to be authentication initiator Date: Tue, 31 Oct 2023 11:47:44 -0700 Message-Id: <20231031184750.722404-4-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Until now IWD only supported enrollees as responders (configurators could do both). For PKEX it makes sense for the enrollee to be the initiator because configurators in the area are already on their operating channel and going off is inefficient. For PKEX, whoever initiates also initiates authentication so for this reason the authentication path is being opened up to allow enrollees to initiate. --- src/dpp.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/dpp.c b/src/dpp.c index dcf5953f..e5e1b3fa 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -1468,7 +1468,7 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp) struct scan_bss *bss = station_get_connected_bss(station); /* Got disconnected by the time the peer was discovered */ - if (!bss) { + if (dpp->role == DPP_CAPABILITY_CONFIGURATOR && !bss) { dpp_reset(dpp); return false; } @@ -1489,7 +1489,8 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp) i_proto_key, dpp->key_len * 2); ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION, &version, 1); - if (dpp->current_freq != bss->frequency) { + if (dpp->role == DPP_CAPABILITY_CONFIGURATOR && + dpp->current_freq != bss->frequency) { uint8_t pair[2] = { 81, band_freq_to_channel(bss->frequency, NULL) }; @@ -1926,9 +1927,6 @@ static void authenticate_response(struct dpp_sm *dpp, const uint8_t *from, if (dpp->state != DPP_STATE_AUTHENTICATING) return; - if (dpp->role != DPP_CAPABILITY_CONFIGURATOR) - return; - if (!dpp->freqs) return; @@ -2082,6 +2080,10 @@ static void authenticate_response(struct dpp_sm *dpp, const uint8_t *from, dpp->current_freq = dpp->new_freq; dpp_send_authenticate_confirm(dpp); + + if (dpp->role == DPP_CAPABILITY_ENROLLEE) + dpp_configuration_start(dpp, from); + } static void dpp_handle_presence_announcement(struct dpp_sm *dpp, From patchwork Tue Oct 31 18:47:45 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442181 Received: from mail-oi1-f172.google.com (mail-oi1-f172.google.com [209.85.167.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 415F81F945 for ; Tue, 31 Oct 2023 18:48:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="iXTmDS2J" Received: by mail-oi1-f172.google.com with SMTP id 5614622812f47-3b5714439b3so328367b6e.3 for ; Tue, 31 Oct 2023 11:48:04 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778083; x=1699382883; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=LoiuoFcTxzf6VnkSfNm0cWT+3q4sx5F2qqAR8TJx2Ag=; b=iXTmDS2JI+3QTjofPHlzA81JIj7TetL25wvpgA4LucOn0XPovYMsb2IWuxu+RaHBhK lyg1q56cNL57aQavLpgCGWe2DsOeejvXm2gowwksO9HeNw1hzXSBNfnN8553e97j55bZ LbHKlu8E7yIMwdYdpT6NuERioIK+UPLEesvAt2iPbSoUJV1dnpxNpvWnGqrRBPZMI6DH eEeZMksBav0DG9pZWsLi2+AghTpsAmNdTtapr0ZcKiNHf6UkEbFzsE7oUmt4PV7RDjTi V4gCnv9VmIj5JGEuX8QHY3j2AFMzGNBO/41JcoeLxw8lLC5PI+8B5sT5W2MTjD/1lBMP yAhw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778083; x=1699382883; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=LoiuoFcTxzf6VnkSfNm0cWT+3q4sx5F2qqAR8TJx2Ag=; b=jd903//EIuEdfi802Y1jI+DmYlRsjIzJtNJf7Fv+gWAaVUwYP3/4YYFv9fNrYJMU0T SahGAcUINZ/JFZfYRadceecQaNRejOVnjzGAcMErZJeJiYeZwOIHftZ+AIjXmbZNTZTs tDSI/Ssh5juSQCKZIHVZ1BCL5giydlJSvDGvyPbFNeGt9rdM6IJ+LoZiFBXDGWUwNyBD PrzC+bPRtL38AI5uNBoShX5/dDi7M9XQ2sQ6vPvoChUiSTNg6oABB2wD08bL/gNvAOK/ 3hkemwJJav7vcC4DAGfByFeXPekILYGA6bVTnCrUR7gP5QyY629QZID7/iKwDDvQdqHW UmaA== X-Gm-Message-State: AOJu0YzH8gIOstO6+Eprq6Ylllt62VCNAKlUOIuD8jYdVXoSuFMtj4xz ICekAOTUBwvGlQwuKz0MFQHguY2r+rM= X-Google-Smtp-Source: AGHT+IHk2caivqTAw5NoOkFt3BGB1rNPlzj+0pv9xiv+H/0ZxMqInfCu7szfEhPuBr4e++QkiiXyWA== X-Received: by 2002:aca:1c03:0:b0:3a0:38c2:2654 with SMTP id c3-20020aca1c03000000b003a038c22654mr11605543oic.58.1698778083007; Tue, 31 Oct 2023 11:48:03 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.48.02 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:02 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 4/9] dbus: add net.connman.iwd.SharedCodeAgent DBus interface Date: Tue, 31 Oct 2023 11:47:45 -0700 Message-Id: <20231031184750.722404-5-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 --- src/dbus.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dbus.h b/src/dbus.h index cff64ae2..b43412d7 100644 --- a/src/dbus.h +++ b/src/dbus.h @@ -47,6 +47,7 @@ #define IWD_DPP_PKEX_INTERFACE "net.connman.iwd.SharedCodeDeviceProvisioning" #define IWD_NETCONFIG_AGENT_INTERFACE \ "net.connman.iwd.NetworkConfigurationAgent" +#define IWD_SHARED_CODE_AGENT_INTERFACE "net.connman.iwd.SharedCodeAgent" #define IWD_BASE_PATH "/net/connman/iwd" #define IWD_AGENT_MANAGER_PATH IWD_BASE_PATH From patchwork Tue Oct 31 18:47:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442182 Received: from mail-qv1-f45.google.com (mail-qv1-f45.google.com [209.85.219.45]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9A9341E530 for ; Tue, 31 Oct 2023 18:48:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="ZVM7mbt1" Received: by mail-qv1-f45.google.com with SMTP id 6a1803df08f44-67131800219so21769746d6.3 for ; Tue, 31 Oct 2023 11:48:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778084; x=1699382884; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=OUCpVo4hvLbvW9owbr/nYYc5HPo8z6nB2C41Jvf3Dnw=; b=ZVM7mbt12dXHj3sQaZRBHrFMcZ54tP6Gc8f1h8B+BXbswt6MwV+1MXM2tGWYf+gJSU uy9tDdfU5RuGH54ypbHNhy6CoHQPAubVYVwjXvXVMCsZbGnR0XZKdT+TPXTG0MOYuibX MhZnlXTlWqRdo5Gpz8WfNjYvWFNPup6J5G3ASGdczVqemOJyEYKP3I1boiWlow/c4wiy DyHLKUe3wB5ecdxxM90x3sZn1UisNHc8lI//K1CD98wtpc1kAs1YXsRfi+MOEpfUQssx wlTvi7AFEkuofYJGPl+S4WQztvBmCcorwiP/LlkbfBcqEerfBJDVw3XLuT4X50ep/OeP ccYQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778084; x=1699382884; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=OUCpVo4hvLbvW9owbr/nYYc5HPo8z6nB2C41Jvf3Dnw=; b=CsxzrVgQeUfqqRLP6LIQ+hIyyj3QOX61FgGrVnKte19Rwod5ECBbPAg2OGYxcGnLSz 05o52d43MbngGaR1h0ns7JhBpRE0KiA90E/uI86TvBTeFV0IMnl3rhKq29BNtb3NBSGi oGaTCFAdQZ9DRjhFKddJPjFgF0eirDIDHbD+GhMJCMMcS2T2oCEXFZbAcZkpq7P7oHOq EGxJUCd7r3yKXDIsnyRY3Q5T+ovr28wq3Umghhk+CsjiO/s0Ja2xsviUz73MQmx1ehBm PNS8iPhJdLFTG7Y4if1MjQ+FVwxD1eREFln3a+y0zhPNtO+cqZsYgr901ALMXqDkjOBs V82g== X-Gm-Message-State: AOJu0YyipntOZ3wWyLcBpRUSEYkYL5ElVsW1EGVNoO4zgXuK7R4H1jTd VW1FefRKAKC5S+tjLL9Gh+85xpRgXKc= X-Google-Smtp-Source: AGHT+IG6PrhCj/ZqB7sCspJ+mbWm8PO4E3k7ZKYeo2i8d2zMe92KyV4nfhvAVwnzKgTjRuE0ma3GkQ== X-Received: by 2002:a05:6214:2506:b0:658:26d7:72e0 with SMTP id gf6-20020a056214250600b0065826d772e0mr250064qvb.4.1698778084142; Tue, 31 Oct 2023 11:48:04 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.48.03 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:03 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 5/9] station: provide new state in __station_connect_network Date: Tue, 31 Oct 2023 11:47:46 -0700 Message-Id: <20231031184750.722404-6-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This is being done to allow the DPP module to work correctl. DPP currently uses __station_connect_network incorrectly since it does not (and cannot) change the state after calling. The only way to connect with a state change is via station_connect_network which requires a DBus method that triggered the connection; DPP does not have this due to its potentially long run time. To support DPP there are a few options: 1. Pass a state into __station_connect_network (this patch) 2. Support a NULL DBus message in station_connect_network. This would require several NULL checks and adding all that to only support DPP just didn't feel right. 3. A 3rd connect API in station which wraps __station_connect_network and changes the state. And again, an entirely new API for only DPP felt wrong (I guess we did this for network_autoconnect though...) Its about 50/50 between call sites that changed state after calling and those that do not. Changing the state inside __station_connect_network felt useful enough to cover the cases that could benefit and the remaining cases could handle it easily enough: - network_autoconnect(), and the state is changed by station after calling so it more or less follows the same pattern just routes through network. This will now pass the CONNECTING_AUTO state from within network vs station. - The disconnect/reconnect path. Here the state is changed to ROAMING prior in order to avoid multiple state changes. Knowing this the same ROAMING state can be passed which won't trigger a state change. - Retrying after a failed BSS. The state changes on the first call then remains the same for each connection attempt. To support this the current station->state is passed to avoid a state change. --- src/dpp.c | 3 ++- src/network.c | 3 ++- src/station.c | 23 +++++++++++------------ src/station.h | 2 +- 4 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/dpp.c b/src/dpp.c index e5e1b3fa..b0a79361 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -833,7 +833,8 @@ static void dpp_handle_config_response_frame(const struct mmpdu_header *frame, offchannel_cancel(dpp->wdev_id, dpp->offchannel_id); if (network && bss) - __station_connect_network(station, network, bss); + __station_connect_network(station, network, bss, + STATION_STATE_CONNECTING); else if (station) { dpp->connect_scan_id = scan_active(dpp->wdev_id, NULL, 0, dpp_scan_triggered, diff --git a/src/network.c b/src/network.c index 3099d102..f203834c 100644 --- a/src/network.c +++ b/src/network.c @@ -991,7 +991,8 @@ int network_autoconnect(struct network *network, struct scan_bss *bss) return -ENOTSUP; } - return __station_connect_network(station, network, bss); + return __station_connect_network(station, network, bss, + STATION_STATE_CONNECTING_AUTO); close_settings: network_settings_close(network); diff --git a/src/station.c b/src/station.c index d4eb0cd8..3da02b06 100644 --- a/src/station.c +++ b/src/station.c @@ -280,9 +280,6 @@ static int station_autoconnect_next(struct station *station) r = network_autoconnect(network, bss); if (!r) { - station_enter_state(station, - STATION_STATE_CONNECTING_AUTO); - if (station->quick_scan_id) { scan_cancel(netdev_get_wdev_id(station->netdev), station->quick_scan_id); @@ -3084,7 +3081,7 @@ static bool station_try_next_bss(struct station *station) return false; ret = __station_connect_network(station, station->connected_network, - next); + next, station->state); if (ret < 0) return false; @@ -3421,7 +3418,7 @@ static void station_netdev_event(struct netdev *netdev, enum netdev_event event, } int __station_connect_network(struct station *station, struct network *network, - struct scan_bss *bss) + struct scan_bss *bss, enum station_state state) { struct handshake_state *hs; int r; @@ -3448,6 +3445,9 @@ int __station_connect_network(struct station *station, struct network *network, station->connected_bss = bss; station->connected_network = network; + if (station->state != state) + station_enter_state(station, state); + return 0; } @@ -3461,7 +3461,8 @@ static void station_disconnect_onconnect_cb(struct netdev *netdev, bool success, err = __station_connect_network(station, station->connect_pending_network, - station->connect_pending_bss); + station->connect_pending_bss, + STATION_STATE_CONNECTING); station->connect_pending_network = NULL; station->connect_pending_bss = NULL; @@ -3472,8 +3473,6 @@ static void station_disconnect_onconnect_cb(struct netdev *netdev, bool success, station->connect_pending)); return; } - - station_enter_state(station, STATION_STATE_CONNECTING); } static void station_disconnect_onconnect(struct station *station, @@ -3531,12 +3530,11 @@ void station_connect_network(struct station *station, struct network *network, return; } - err = __station_connect_network(station, network, bss); + err = __station_connect_network(station, network, bss, + STATION_STATE_CONNECTING); if (err < 0) goto error; - station_enter_state(station, STATION_STATE_CONNECTING); - station->connect_pending = l_dbus_message_ref(message); station_set_autoconnect(station, true); @@ -3746,7 +3744,8 @@ static void station_disconnect_reconnect_cb(struct netdev *netdev, bool success, struct station *station = user_data; if (__station_connect_network(station, station->connected_network, - station->connected_bss) < 0) + station->connected_bss, + STATION_STATE_ROAMING) < 0) station_disassociated(station); } diff --git a/src/station.h b/src/station.h index 24fab321..0d502a08 100644 --- a/src/station.h +++ b/src/station.h @@ -89,7 +89,7 @@ void station_remove_event_watch(uint32_t id); bool station_set_autoconnect(struct station *station, bool autoconnect); int __station_connect_network(struct station *station, struct network *network, - struct scan_bss *bss); + struct scan_bss *bss, enum station_state state); void station_connect_network(struct station *station, struct network *network, struct scan_bss *bss, struct l_dbus_message *message); From patchwork Tue Oct 31 18:47:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442183 Received: from mail-qk1-f172.google.com (mail-qk1-f172.google.com [209.85.222.172]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 94AE81F945 for ; Tue, 31 Oct 2023 18:48:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="a+tNfEvz" Received: by mail-qk1-f172.google.com with SMTP id af79cd13be357-77784edc2edso392317485a.1 for ; Tue, 31 Oct 2023 11:48:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778085; x=1699382885; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=qXVowolFU2g+s91gNdM54EsdOkLlJgHR7YHOdFGNnM8=; b=a+tNfEvzYUeT7T/BWfqLkbhSUYfffR11ZNPr0jkDY2y/bNMngrpH5QdrLou3ecQMiX L8/ZcXq5ye6xbpK2hPFI6zZnRLNkfx9rFLLJm16jr0P+nZGANCWljQ2OCKnMnd9NN82B 66tDC3KYe/5qjLR0N2+CS1eAYEbBtVmdTTgV6OUsfLuCotEDhV9Z1XztFjphS7TdvjE9 dkN7Y9kufEP39458QozHL2b9xC7diUE91+VUv5JoYO1H2O3znE4RsJStNZd8o65H7dWl 1rx/4C0jXd1o4Jza5uSVgtC3ZIMDUwV21d7GfQdyfiUg9y+VjHpSlbh7s5mynX3e6a+A id0Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778085; x=1699382885; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=qXVowolFU2g+s91gNdM54EsdOkLlJgHR7YHOdFGNnM8=; b=OyAORWjMXMF9pyjx+f8eB3UsrPwvoUJnf9wUGIzGMhu0yYXpYGD1YfYM14hn/q91kH IpytJF6xl6fLUDv49L0kuldN8aaAJjZqeWMXPSVsu/kaOeZbmtXiJVMc1ecI+CbZak3G J2PSi0kqm3lsPggv6QjPNl3Gb+QXvo3vHT1IxJzwVucL2PsXaApeUJpTAoV6HDDgIPYg Sy3jffoEONZpU6MJJ7Qwaezu9Ca0AnwCyespEThpbrzrEa8Wb5VIAv+X/WTWB4XHYkAx SDL7GtaR8uZx9dvNs+a9WVTtXeTKJny3aQ6T6z8lAs4U1ZbPhGI2qmYJrS/JUXMLukFP ngfQ== X-Gm-Message-State: AOJu0YzmfZIJ8iBPrKRMgpqTZ0imyEwjltWX7oNoF+XDyUtPQ4qo33VK Yi8kCFwLm0PsnByTBKjSoQ7n+kETKw8= X-Google-Smtp-Source: AGHT+IE7RLrPQq2fHBj8+rU4Jqp+vs+OMX+PfqhoVTzxeLQ93iHjcoTbDncG7SnoKaiLrFzNKkNbIg== X-Received: by 2002:a05:620a:404e:b0:774:35da:75ac with SMTP id i14-20020a05620a404e00b0077435da75acmr15528162qko.55.1698778085352; Tue, 31 Oct 2023 11:48:05 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.48.04 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:05 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 6/9] doc: PKEX support for DPP Date: Tue, 31 Oct 2023 11:47:47 -0700 Message-Id: <20231031184750.722404-7-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 PKEX is part of the WFA EasyConnect specification and is an additional boostrapping method (like QR codes) for exchanging public keys between a configurator and enrollee. PKEX operates over wifi and requires a key/code be exchanged prior to the protocol. The key is used to encrypt the exchange of the boostrapping information, then DPP authentication is started immediately aftewards. This can be useful for devices which don't have the ability to scan a QR code, or even as a more convenient way to share wireless credentials if the PSK is very secure (i.e. not a human readable string). PKEX would be used via the three DBus APIs on a new interface SharedCodeDeviceProvisioning. ConfigureEnrollee(a{sv}) will start a configurator with a static shared code (optionally identifier) passed in as the argument to this method. StartEnrollee(a{sv}) will start a PKEX enrollee using a static shared code (optionally identifier) passed as the argument to the method. StartConfigurator() will start a PKEX configurator (should be already registered) which will query an agent for an enrollees shared code. Enrollees are distinguished by the identifier. After the PKEX protocol is finished, DPP bootstrapping keys have been exchanged and DPP Authentication will start, followed by configuration. --- doc/device-provisioning-api.txt | 149 ++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/doc/device-provisioning-api.txt b/doc/device-provisioning-api.txt index ac204f46..3c6fc74e 100644 --- a/doc/device-provisioning-api.txt +++ b/doc/device-provisioning-api.txt @@ -71,3 +71,152 @@ Properties boolean Started [readonly] Indicates the DPP URI. This property is only available when Started is true. + + +Interface net.connman.iwd.SharedCodeDeviceProvisioning [Experimental] +Object path /net/connman/iwd/{phy0,phy1,...}/{1,2,...} + + ConfigureEnrollee(a{sv}) + + Starts a DPP configurator using a shared code (and + optionally identifier) set in the dictionary argument. + Valid dictionary keys are: + + string Code + The shared code to use. The code used by both + parties (configurator and enrollee) must match. + + string Identifier + An optional identifier. The identifier used by + both parties must match. Per the DPP spec the + identifier "shall be a UTF-8 string not greater + than eighty (80) octets" + + As with the DeviceProvisioning interface, configurators + must be connected to the network they wish to configure + in order to start. + + Once started a configurator (acting as a responder) will + listen on the currently connected channel for an + enrollee's initial exchange request which will kick off + the shared code bootstrapping protocol (PKEX). Once + completed DPP will start automatically. Only one + enrollee can be configured per call to + ConfigureEnrollee, i.e. once PKEX/DPP is has finished + (including failure) the configurator will stop. + + The SharedCode methods have an eventual timeout and will + stop automatically after 2 minutes. + + Possible errors: net.connman.iwd.Busy + net.connman.iwd.NotConnected + net.connman.InvalidArguments + + StartEnrollee(a{sv}) + + Starts a DPP enrollee using a shared code (and + optionally identifier) set in the dictionary argument + (described above in ConfigureEnrollee). + + As with the device provisioning interface, enrollees + must be disconnected in order to start. + + Once started an enrollee (acting as an initiator) will + iterate channels sending out broadcast exchange requests + waiting for a response from a configurator. A response + will kick off the shared code bootstrapping protocol + (PKEX), followed by DPP if successful. Once the + protocols have completed, or failed, the enrollee will + stop. If failed, StartEnrollee will need to be called + again to retry. + + Possible errors: net.connman.iwd.Busy + net.connman.iwd.InvalidArguments + + StartConfigurator() + + Start a shared code configurator using an agent to + obtain the shared code. This method is meant for an + automated use case where a configurator is capable of + configuring multiple enrollees, and distinguishing + between them by their identifier. + + Prior to calling, a SharedCodeAgent must be registered + using RegisterSharedCodeAgent. Only a single agent can + be registered per SharedCodeInterface. + + This method behaves nearly the same as ConfigureEnrollee + except upon receiving an enrollees first exchange + request the registered agent will be asked for the + shared code using the RequestSharedCode method. + + Though the agent can provide shared codes for multiple + enrollees, this method will only configure a single + enrollee at a time. Once completed it will need to be + called again to configure additional enrollees. + + Possible errors: net.connman.iwd.Busy + net.connman.iwd.NotConnected + net.connman.iwd.NoAgent + + void RegisterSharedCodeAgent(object path) + + Register the agent object for servicing shared code + requests on the net.connman.iwd.SharedCodeAgent + interface. There may only be one agent registered at a + time per SharedCodeDeviceProvisioning interface. + + Possible Errors: [service].Error.InvalidArguments + [service].Error.AlreadyExists + + void UnregisterSharedCodeAgent() + + Unregister an existing agent. + + Possible Errors: [service].Error.NotFound + +Properties boolean Started [readonly] + + True if shared code device provisioning is currently + active. (configurator or enrollee is started) + + string Role [readonly, optional] + + Indicates the DPP role. Possible values are "enrollee" + or "configurator". This property is only available when + Started is true. + +SharedCodeAgent hierarchy +========================= + +Service unique name +Interface net.connman.iwd.SharedCodeAgent [Experimental] +Object path freely definable + +Methods void Release() [noreply] + + This method gets called when the service daemon + unregisters the agent. + + string RequestSharedCode(object network, string identifier) + + This method gets called when a shared code is requested + for a particular enrollee, distingushed by the + identifier. The shared code agent should lookup the + identifier and return the shared code, or return an + error if not found. + + Possible Errors: [service].Error.Canceled + [service].Error.NotFound + + void Cancel(string reason) [noreply] + + This method gets called to indicate that the agent + request failed before a reply was returned. The + argument will indicate why the request is being + cancelled and may be "user-canceled", "timed-out" or + "shutdown". + +Examples Requesting a shared code for an enrollee identified by "foo" + + RequestSharedCode("foo") ==> "super_secret_code" From patchwork Tue Oct 31 18:47:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442184 Received: from mail-qk1-f169.google.com (mail-qk1-f169.google.com [209.85.222.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 08E2220332 for ; Tue, 31 Oct 2023 18:48:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="aG7KtwtX" Received: by mail-qk1-f169.google.com with SMTP id af79cd13be357-77891f362cfso10742385a.1 for ; Tue, 31 Oct 2023 11:48:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778086; x=1699382886; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=dHWGQ0O3ysE606k3XcqdDR+69PqOBoxjxafEmFI6L9g=; b=aG7KtwtXGVUrHdD/rIECRLgrJrcdqotZZWdeARnaosCy91Ar1OQTQUw3RfFCKI3KrI uyzMl9NFGdT4OlDVL3SeWwoOwUDCKwDB3XfWAyQGSu1scAaiIkWaCqt8n3lHcE/Z5ntF TpOitpZlgoSJdkwxQAFC2fqD00SPsq/HyrfkTMXaM7zbHWfOY0c3ebfs+G5zDrLFsjPw Hf6piDvTNuS4CEPWtxgoBnGV3RqIJqMvzPiyGjvHTjwtwWcjlMmMhSvFS4jFugDeqqOr RRfSe4C0KBoSPZEWAphYPvNbFaouABjyuvIdcOZLUc0AokM7X1G1uRSmCc7WhUyRRJoE 5Ndg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778086; x=1699382886; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=dHWGQ0O3ysE606k3XcqdDR+69PqOBoxjxafEmFI6L9g=; b=ZM9GgsHf+jgTVdlZeOyIT6iKad0qV6+bd73YjqBthqPMiZbm4hha3+eQQ9oKTgVxHX ACAZc6i8n6Jk8uDwbnT2VsT0CNJv/mhfCu3nyYnH/+ZBUxxNmjc432pv10VMnt9BXJZG 7jkLe55ph1G99MGfID3ynR5BrCFINH0VAhOSnavX9Z5BHa/MY27l2DaIpvmhZaPvlDZp QKVHd8EE0uZ3wGzJQ2dVCrsRTT0ENMZZDfDrdwfL6RI4RjeZXiFN3qpCvK2pgz7o6CoG 2PRRaM1VcYgejm8E56MQXlcEUMTx+tPN79aF51b+4+mjIZC37sw8tuyqAenSdLFqWiG4 biYQ== X-Gm-Message-State: AOJu0YzwZttmlnfcnLrl3jw4Rz+P2w29aJK2yvUM9sh6Ob7Nh7cUiSf7 fFe9juWw9UzxoZrTStzp0O/WUwdcBoU= X-Google-Smtp-Source: AGHT+IFxmV6EuHe4HDcE+mC9xig2AbN51h2eOh/4jiPspHLeOyA/sQpuSklQwR7hj06rvO8ef5MtMg== X-Received: by 2002:a05:620a:4492:b0:773:ac84:3f57 with SMTP id x18-20020a05620a449200b00773ac843f57mr5047304qkp.5.1698778086614; Tue, 31 Oct 2023 11:48:06 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.48.05 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:06 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 7/9] dpp: SharedCode interface, {Register,Unregister}SharedCodeAgent Date: Tue, 31 Oct 2023 11:47:48 -0700 Message-Id: <20231031184750.722404-8-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This adds the SharedCodeDeviceProvisioning interface as well as the two agent methods. After the PKEX configurator role is added it will need this to request a shared code from a registered agent. --- src/dpp.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 100 insertions(+) diff --git a/src/dpp.c b/src/dpp.c index b0a79361..57024a26 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -79,6 +79,13 @@ enum dpp_capability { DPP_CAPABILITY_CONFIGURATOR = 0x02, }; +struct pkex_agent { + char *owner; + char *path; + unsigned int disconnect_watch; + uint32_t pending_id; +}; + struct dpp_sm { struct netdev *netdev; char *uri; @@ -101,6 +108,8 @@ struct dpp_sm { enum dpp_state state; + struct pkex_agent *agent; + /* * List of frequencies to jump between. The presence of this list is * also used to signify that a configurator is an initiator vs responder @@ -335,6 +344,16 @@ static void dpp_reset(struct dpp_sm *dpp) dpp_property_changed_notify(dpp); } +static void pkex_agent_free(void *data) +{ + struct pkex_agent *agent = data; + + l_free(agent->owner); + l_free(agent->path); + l_dbus_remove_watch(dbus_get_bus(), agent->disconnect_watch); + l_free(agent); +} + static void dpp_free(struct dpp_sm *dpp) { dpp_reset(dpp); @@ -354,6 +373,11 @@ static void dpp_free(struct dpp_sm *dpp) dpp->boot_private = NULL; } + if (dpp->agent) { + pkex_agent_free(dpp->agent); + dpp->agent = NULL; + } + l_free(dpp); } @@ -2753,6 +2777,79 @@ static void dpp_setup_interface(struct l_dbus_interface *interface) l_dbus_interface_property(interface, "URI", 0, "s", dpp_get_uri, NULL); } +static void pkex_agent_disconnect(struct l_dbus *dbus, void *user_data) +{ + struct dpp_sm *dpp = user_data; + + l_debug("SharedCodeAgent %s disconnected", dpp->agent->path); + + if (dpp->agent->pending_id) + l_dbus_cancel(dbus_get_bus(), dpp->agent->pending_id); + + pkex_agent_free(dpp->agent); + dpp->agent = NULL; +} + +static struct l_dbus_message *dpp_dbus_pkex_register_agent( + struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + const char *sender = l_dbus_message_get_sender(message); + const char *path; + + if (dpp->agent) + return dbus_error_already_exists(message); + + if (!l_dbus_message_get_arguments(message, "o", &path)) + return dbus_error_invalid_args(message); + + dpp->agent = l_new(struct pkex_agent, 1); + dpp->agent->owner = l_strdup(sender); + dpp->agent->path = l_strdup(path); + dpp->agent->disconnect_watch = l_dbus_add_disconnect_watch(dbus, sender, + pkex_agent_disconnect, + dpp, NULL); + + l_debug("%s registered a SharedCodeAgent on path %s", sender, path); + + return l_dbus_message_new_method_return(message); +} + +static struct l_dbus_message *dpp_dbus_pkex_unregister_agent( + struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + + if (!dpp->agent) + return dbus_error_not_found(message); + + if (strcmp(dpp->agent->owner, l_dbus_message_get_sender(message))) + return dbus_error_not_found(message); + + l_debug("%s unregistered SharedCodeAgent on path %s", dpp->agent->owner, + dpp->agent->path); + + if (dpp->agent->pending_id) + l_dbus_cancel(dbus_get_bus(), dpp->agent->pending_id); + + pkex_agent_free(dpp->agent); + dpp->agent = NULL; + + return l_dbus_message_new_method_return(message); +} + +static void dpp_setup_pkex_interface(struct l_dbus_interface *interface) +{ + l_dbus_interface_method(interface, "RegisterSharedCodeAgent", 0, + dpp_dbus_pkex_register_agent, "", "o", "path"); + l_dbus_interface_method(interface, "UnregisterSharedCodeAgent", 0, + dpp_dbus_pkex_unregister_agent, "", ""); +} + static void dpp_destroy_interface(void *user_data) { struct dpp_sm *dpp = user_data; @@ -2775,6 +2872,9 @@ static int dpp_init(void) l_dbus_register_interface(dbus_get_bus(), IWD_DPP_INTERFACE, dpp_setup_interface, dpp_destroy_interface, false); + l_dbus_register_interface(dbus_get_bus(), IWD_DPP_PKEX_INTERFACE, + dpp_setup_pkex_interface, + NULL, false); mlme_watch = l_genl_family_register(nl80211, "mlme", dpp_mlme_notify, NULL, NULL); From patchwork Tue Oct 31 18:47:49 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442185 Received: from mail-qk1-f177.google.com (mail-qk1-f177.google.com [209.85.222.177]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7F8321F945 for ; Tue, 31 Oct 2023 18:48:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="eUiqgnHm" Received: by mail-qk1-f177.google.com with SMTP id af79cd13be357-7789cc5c8ccso11750285a.0 for ; Tue, 31 Oct 2023 11:48:09 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778088; x=1699382888; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=h47ZK1hDwILiNSpBWBDe/z3dw7PJEJ4JSS6ujC2K7aI=; b=eUiqgnHm1wUU251CECUK2HTJGFJweX12mN1uaFtdeutQbHVklnGJO4FxCN4n4CGLxK K1yonwgdOQaIP+nDMV69AFw0TOYLpqTOl2WnUFAYUgbCN5JzQmPyf8GeMZtlsViBsyps 7HzqkcAwFT6Lgf49V7abPFAyHpP8Ctl5wdmA+uwNRkEU/eQk6ky3yC6OXq9w28niNg2/ o4aMQvvlGQZiK3FGXKiw6pJzQUUhi1s46Hy6R0O1PYJdNeddDxuKPkMyZLjLsEXANACY JEhN+Nz8bzvljUvlYIueTWhT5kdhvbflSitufbhGAZvOQihuQTJxsUsBkNSo2zY3Kexw oGlw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778088; x=1699382888; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=h47ZK1hDwILiNSpBWBDe/z3dw7PJEJ4JSS6ujC2K7aI=; b=haC/A6HWlMc5aAqZhmCXRmmmXi2kx3oumWOhNNBuWmFOV/QUhDvut+Che2zY4s5mEF tLBwmXKXR6C9BXEb40v+UzAbOl3rIvfru9kfGLGjq2+YinlObK3B/RQ57cMxx5wDBQBu ekqALJEJ4f2vQVUyqVdQl0JbyClUJ0Isx17r9M1Hz3pGJnuXqUw2CqD/oAAAaEONTQiO Tdp1ivveVSylDUoZYp8RS2bOPmZInfVk06dHpVl56Pz9Mt9PpK+8j6wSFVE77fCVxTAu P0VRfPjKWKO9CPC0bcoaCN6vDtgm7P3D82Fqgy8ZePoE38j0DD9zfJA8IbCykqheMXPF /l1g== X-Gm-Message-State: AOJu0YzqK9z5/q67/h1mjsfV63x7WAbQ6mYhitEaJQ9rPhYt9aW1pOBI HhFnKT4yXkZi6b6ZmaWLfnAGLrW0lME= X-Google-Smtp-Source: AGHT+IGqWllWA7+ujE1soCTqNT87MBS8RLWAgJ2KSxDk9CmeyZKeXBwxPM2qtA+buIcUk0+UwllTFw== X-Received: by 2002:a05:620a:86cd:b0:778:969e:3a0c with SMTP id pr13-20020a05620a86cd00b00778969e3a0cmr5103395qkn.27.1698778088032; Tue, 31 Oct 2023 11:48:08 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.48.06 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:07 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 8/9] dpp: initial version of PKEX enrollee support Date: Tue, 31 Oct 2023 11:47:49 -0700 Message-Id: <20231031184750.722404-9-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 This is the initial support for PKEX enrollees acting as the initiator. A PKEX initiator starts the protocol by broadcasting the PKEX exchange request. This request contains a key encrypted with the pre-shared PKEX code. If accepted the peer sends back the exchange response with its own encrypted key. The enrollee decrypts this and performs some crypto/hashing in order to establish an ephemeral key used to encrypt its own boostrapping key. The boostrapping key is encrypted and sent to the peer in the PKEX commit-reveal request. The peer then does the same thing, encrypting its own bootstrapping key and sending to the initiator as the PKEX commit-reveal response. After this, both peers have exchanged their boostrapping keys securely and can begin DPP authentication, then configuration. For now the enrollee will only iterate the default channel list from the Easy Connect spec. Future upates will need to include some way of discovering non-default channel configurators, but the protocol needs to be ironed out first. --- src/dpp.c | 765 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 761 insertions(+), 4 deletions(-) diff --git a/src/dpp.c b/src/dpp.c index 57024a26..8b47be5c 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -53,10 +53,12 @@ #include "src/network.h" #include "src/handshake.h" #include "src/nl80211util.h" +#include "src/agent.h" #define DPP_FRAME_MAX_RETRIES 5 #define DPP_FRAME_RETRY_TIMEOUT 1 #define DPP_AUTH_PROTO_TIMEOUT 10 +#define DPP_PKEX_PROTO_TIMEOUT 120 static uint32_t netdev_watch; static struct l_genl_family *nl80211; @@ -70,6 +72,8 @@ static uint8_t dpp_prefix[] = { 0x04, 0x09, 0x50, 0x6f, 0x9a, 0x1a, 0x01 }; enum dpp_state { DPP_STATE_NOTHING, DPP_STATE_PRESENCE, + DPP_STATE_PKEX_EXCHANGE, + DPP_STATE_PKEX_COMMIT_REVEAL, DPP_STATE_AUTHENTICATING, DPP_STATE_CONFIGURING, }; @@ -156,19 +160,66 @@ struct dpp_sm { struct l_dbus_message *pending; + /* PKEX-specific values */ + char *pkex_id; + char *pkex_key; + uint8_t pkex_version; + struct l_ecc_point *pkex_m; + /* Ephemeral key Y' or X' for enrollee or configurator */ + struct l_ecc_point *y_or_x; + /* Ephemeral key pair y/Y or x/X */ + struct l_ecc_point *pkex_public; + struct l_ecc_scalar *pkex_private; + uint8_t z[L_ECC_SCALAR_MAX_BYTES]; + size_t z_len; + uint8_t u[L_ECC_SCALAR_MAX_BYTES]; + size_t u_len; + bool mcast_support : 1; bool roc_started : 1; bool channel_switch : 1; bool mutual_auth : 1; }; +static bool dpp_pkex_get_started(struct l_dbus *dbus, + struct l_dbus_message *message, + struct l_dbus_message_builder *builder, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + bool started = false; + + switch (dpp->state) { + case DPP_STATE_PKEX_EXCHANGE: + case DPP_STATE_PKEX_COMMIT_REVEAL: + started = true; + break; + default: + break; + } + + l_dbus_message_builder_append_basic(builder, 'b', &started); + + return true; +} + static bool dpp_get_started(struct l_dbus *dbus, struct l_dbus_message *message, struct l_dbus_message_builder *builder, void *user_data) { struct dpp_sm *dpp = user_data; - bool started = (dpp->state != DPP_STATE_NOTHING); + bool started = false; + + switch (dpp->state) { + case DPP_STATE_PRESENCE: + case DPP_STATE_AUTHENTICATING: + case DPP_STATE_CONFIGURING: + started = true; + break; + default: + break; + } l_dbus_message_builder_append_basic(builder, 'b', &started); @@ -208,7 +259,9 @@ static bool dpp_get_uri(struct l_dbus *dbus, { struct dpp_sm *dpp = user_data; - if (dpp->state == DPP_STATE_NOTHING) + if (dpp->state == DPP_STATE_NOTHING || + dpp->state == DPP_STATE_PKEX_EXCHANGE || + dpp->state == DPP_STATE_PKEX_COMMIT_REVEAL) return false; l_dbus_message_builder_append_basic(builder, 's', dpp->uri); @@ -227,6 +280,16 @@ static void dpp_property_changed_notify(struct dpp_sm *dpp) "URI"); } +static void dpp_pkex_property_changed_notify(struct dpp_sm *dpp) +{ + const char *path = netdev_get_path(dpp->netdev); + + l_dbus_property_changed(dbus_get_bus(), path, IWD_DPP_PKEX_INTERFACE, + "Started"); + l_dbus_property_changed(dbus_get_bus(), path, IWD_DPP_PKEX_INTERFACE, + "Role"); +} + static void *dpp_serialize_iovec(struct iovec *iov, size_t iov_len, size_t *out_len) { @@ -277,6 +340,27 @@ static void dpp_free_auth_data(struct dpp_sm *dpp) l_ecc_scalar_free(dpp->m); dpp->m = NULL; } + + if (dpp->pkex_m) { + l_ecc_point_free(dpp->pkex_m); + dpp->pkex_m = NULL; + } + + if (dpp->y_or_x) { + l_ecc_point_free(dpp->y_or_x); + dpp->y_or_x = NULL; + } + + if (dpp->pkex_public) { + l_ecc_point_free(dpp->pkex_public); + dpp->pkex_public = NULL; + } + + if (dpp->pkex_private) { + l_ecc_scalar_free(dpp->pkex_private); + dpp->pkex_private = NULL; + } + } static void dpp_reset(struct dpp_sm *dpp) @@ -338,10 +422,24 @@ static void dpp_reset(struct dpp_sm *dpp) explicit_bzero(dpp->k1, dpp->key_len); explicit_bzero(dpp->k2, dpp->key_len); explicit_bzero(dpp->auth_tag, dpp->key_len); + explicit_bzero(dpp->z, dpp->key_len); + explicit_bzero(dpp->u, dpp->u_len); + + if (dpp->pkex_key) { + explicit_bzero(dpp->pkex_key, strlen(dpp->pkex_key)); + l_free(dpp->pkex_key); + dpp->pkex_key = NULL; + } + + if (dpp->pkex_id) { + l_free(dpp->pkex_id); + dpp->pkex_id = NULL; + } dpp_free_auth_data(dpp); dpp_property_changed_notify(dpp); + dpp_pkex_property_changed_notify(dpp); } static void pkex_agent_free(void *data) @@ -381,6 +479,23 @@ static void dpp_free(struct dpp_sm *dpp) l_free(dpp); } +static bool dpp_check_pkex_identifier(const char *id) +{ + const char *end; + + if (!id) + return true; + + /* + * "If an optional code identifier is used, it shall be a UTF-8 string + * not greater than eighty (80) octets" + */ + if (!l_utf8_validate(id, strlen(id), &end) || end - id > 80) + return false; + + return true; +} + static void dpp_send_frame_cb(struct l_genl_msg *msg, void *user_data) { struct dpp_sm *dpp = user_data; @@ -1536,6 +1651,71 @@ static bool dpp_send_authenticate_request(struct dpp_sm *dpp) return true; } +static void dpp_send_pkex_exchange_request(struct dpp_sm *dpp) +{ + uint8_t hdr[32]; + uint8_t attrs[256]; + uint8_t *ptr = attrs; + uint64_t m_data[L_ECC_MAX_DIGITS * 2]; + uint16_t group; + struct iovec iov[2]; + const uint8_t *own_mac = netdev_get_address(dpp->netdev); + + l_put_le16(l_ecc_curve_get_ike_group(dpp->curve), &group); + + iov[0].iov_len = dpp_build_header(own_mac, broadcast, + DPP_FRAME_PKEX_VERSION1_XCHG_REQUST, hdr); + iov[0].iov_base = hdr; + + ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION, + &dpp->pkex_version, 1); + ptr += dpp_append_attr(ptr, DPP_ATTR_FINITE_CYCLIC_GROUP, + &group, 2); + + if (dpp->pkex_id) + ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER, + dpp->pkex_id, strlen(dpp->pkex_id)); + + l_ecc_point_get_data(dpp->pkex_m, m_data, sizeof(m_data)); + + ptr += dpp_append_attr(ptr, DPP_ATTR_ENCRYPTED_KEY, + m_data, dpp->key_len * 2); + + iov[1].iov_base = attrs; + iov[1].iov_len = ptr - attrs; + + dpp_send_frame(dpp, iov, 2, dpp->current_freq); +} + +static void dpp_send_commit_reveal_request(struct dpp_sm *dpp) +{ + struct iovec iov[2]; + uint8_t hdr[41]; + uint8_t attrs[512]; + uint8_t *ptr = attrs; + uint8_t zero = 0; + uint8_t a_pub[L_ECC_POINT_MAX_BYTES]; + ssize_t a_len; + + a_len = l_ecc_point_get_data(dpp->boot_public, a_pub, sizeof(a_pub)); + + iov[0].iov_len = dpp_build_header(netdev_get_address(dpp->netdev), + dpp->peer_addr, + DPP_FRAME_PKEX_COMMIT_REVEAL_REQUEST, + hdr); + iov[0].iov_base = hdr; + + ptr += dpp_append_wrapped_data(hdr + 26, 6, &zero, 1, ptr, + sizeof(attrs), dpp->z, dpp->z_len, 2, + DPP_ATTR_BOOTSTRAPPING_KEY, a_len, a_pub, + DPP_ATTR_INITIATOR_AUTH_TAG, dpp->u_len, dpp->u); + + iov[1].iov_base = attrs; + iov[1].iov_len = ptr - attrs; + + dpp_send_frame(dpp, iov, 2, dpp->current_freq); +} + static void dpp_roc_started(void *user_data) { struct dpp_sm *dpp = user_data; @@ -1599,6 +1779,16 @@ static void dpp_roc_started(void *user_data) send_authenticate_response(dpp); } + break; + case DPP_STATE_PKEX_EXCHANGE: + if (dpp->role == DPP_CAPABILITY_ENROLLEE) + dpp_send_pkex_exchange_request(dpp); + + break; + case DPP_STATE_PKEX_COMMIT_REVEAL: + if (dpp->role == DPP_CAPABILITY_ENROLLEE) + dpp_send_commit_reveal_request(dpp); + break; default: break; @@ -1627,6 +1817,7 @@ static void dpp_offchannel_timeout(int error, void *user_data) goto protocol_failed; switch (dpp->state) { + case DPP_STATE_PKEX_EXCHANGE: case DPP_STATE_PRESENCE: break; case DPP_STATE_NOTHING: @@ -1634,6 +1825,7 @@ static void dpp_offchannel_timeout(int error, void *user_data) return; case DPP_STATE_AUTHENTICATING: case DPP_STATE_CONFIGURING: + case DPP_STATE_PKEX_COMMIT_REVEAL: goto next_roc; } @@ -2196,6 +2388,382 @@ static void dpp_handle_presence_announcement(struct dpp_sm *dpp, dpp->channel_switch = true; } +static void dpp_pkex_bad_group(struct dpp_sm *dpp, uint16_t group) +{ + uint16_t own_group = l_ecc_curve_get_ike_group(dpp->curve); + + /* + * TODO: The spec allows group negotiation, but it is not yet + * implemented. + */ + if (!group) + return; + /* + * Section 5.6.2 + * "If the Responder's offered group offers less security + * than the Initiator's offered group, then the Initiator should + * ignore this message" + */ + if (group < own_group) { + l_debug("Offered group %u is less secure, ignoring", + group); + return; + } + /* + * Section 5.6.2 + * "If the Responder's offered group offers equivalent or better + * security than the Initiator's offered group, then the + * Initiator may choose to abort its original request and try + * another exchange using the group offered by the Responder" + */ + if (group >= own_group) { + l_debug("Offered group %u is the same or more secure, " + " but group negotiation is not supported", group); + return; + } +} + +static void dpp_pkex_bad_code(struct dpp_sm *dpp) +{ + _auto_(l_ecc_point_free) struct l_ecc_point *qr = NULL; + + qr = dpp_derive_qr(dpp->curve, dpp->pkex_key, dpp->pkex_id, + netdev_get_address(dpp->netdev)); + if (!qr || l_ecc_point_is_infinity(qr)) { + l_debug("Qr computed to zero, new code should be provisioned"); + return; + } + + l_debug("Qr computed successfully but responder indicated otherwise"); +} + +static void dpp_handle_pkex_exchange_response(struct dpp_sm *dpp, + const uint8_t *from, + const uint8_t *body, size_t body_len) +{ + struct dpp_attr_iter iter; + enum dpp_attribute_type type; + size_t len; + const uint8_t *data; + const uint8_t *status = NULL; + uint8_t version = 0; + const char *identifier = NULL; + size_t identifier_len = 0; + const void *key = NULL; + size_t key_len = 0; + uint16_t group = 0; + _auto_(l_ecc_point_free) struct l_ecc_point *n = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *j = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *qr = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *k = NULL; + const uint8_t *own_addr = netdev_get_address(dpp->netdev); + + l_debug("PKEX response "MAC, MAC_STR(from)); + + if (dpp->state != DPP_STATE_PKEX_EXCHANGE) + return; + + if (dpp->role != DPP_CAPABILITY_ENROLLEE) + return; + + memcpy(dpp->peer_addr, from, 6); + + dpp_attr_iter_init(&iter, body + 8, body_len - 8); + + while (dpp_attr_iter_next(&iter, &type, &len, &data)) { + switch (type) { + case DPP_ATTR_STATUS: + if (len != 1) + return; + + status = data; + break; + case DPP_ATTR_PROTOCOL_VERSION: + if (len != 1) + return; + + version = l_get_u8(data); + break; + case DPP_ATTR_CODE_IDENTIFIER: + identifier = (char *) data; + identifier_len = len; + break; + case DPP_ATTR_ENCRYPTED_KEY: + if (len != dpp->key_len * 2) + return; + + key = data; + key_len = len; + break; + case DPP_ATTR_FINITE_CYCLIC_GROUP: + if (len != 2) + return; + + group = l_get_le16(data); + break; + default: + break; + } + } + + if (!status) { + l_debug("No status attribute, ignoring"); + return; + } + + if (!key) { + l_debug("No encrypted key, ignoring"); + return; + } + + if (*status != DPP_STATUS_OK) + goto handle_status; + + if (dpp->pkex_id) { + if (!identifier || identifier_len != strlen(dpp->pkex_id) || + strncmp(dpp->pkex_id, identifier, + identifier_len)) { + l_debug("mismatch identifier, ignoring"); + return; + } + } + + if (version && version != dpp->pkex_version) { + l_debug("PKEX version does not match, igoring"); + return; + } + + n = l_ecc_point_from_data(dpp->curve, L_ECC_POINT_TYPE_FULL, + key, key_len); + if (!n) { + l_debug("failed to parse peers encrypted key"); + goto failed; + } + + qr = dpp_derive_qr(dpp->curve, dpp->pkex_key, dpp->pkex_id, + dpp->peer_addr); + if (!qr) + goto failed; + + dpp->y_or_x = l_ecc_point_new(dpp->curve); + + /* Y' = N - Qr */ + l_ecc_point_inverse(qr); + l_ecc_point_add(dpp->y_or_x, n, qr); + + /* + * "The resulting ephemeral key, denoted Y’, is then checked whether it + * is the point-at-infinity. If it is not valid, the protocol ends + * unsuccessfully" + */ + if (l_ecc_point_is_infinity(dpp->y_or_x)) { + l_debug("Y' computed to infinity, failing"); + goto failed; + } + + k = l_ecc_point_new(dpp->curve); + + /* K = Y' * x */ + l_ecc_point_multiply(k, dpp->pkex_private, dpp->y_or_x); + + dpp_derive_z(own_addr, dpp->peer_addr, n, dpp->pkex_m, k, + dpp->pkex_key, dpp->pkex_id, + dpp->z, &dpp->z_len); + + /* J = a * Y' */ + j = l_ecc_point_new(dpp->curve); + + l_ecc_point_multiply(j, dpp->boot_private, dpp->y_or_x); + + if (!dpp_derive_u(j, own_addr, dpp->boot_public, dpp->y_or_x, + dpp->pkex_public, dpp->u, &dpp->u_len)) { + l_debug("failed to compute u"); + goto failed; + } + + /* + * Now that a response was successfully received, start another + * offchannel with more time for the remainder of the protocol. After + * PKEX, authentication will begin which handles the protocol timeout. + * If the remainder of PKEX (commit-reveal exchange) cannot complete in + * this time it will fail. + */ + dpp->dwell = (dpp->max_roc < 2000) ? dpp->max_roc : 2000; + dpp->state = DPP_STATE_PKEX_COMMIT_REVEAL; + + dpp_pkex_property_changed_notify(dpp); + + dpp_start_offchannel(dpp, dpp->current_freq); + + return; + +handle_status: + switch (*status) { + case DPP_STATUS_BAD_GROUP: + dpp_pkex_bad_group(dpp, group); + break; + case DPP_STATUS_BAD_CODE: + dpp_pkex_bad_code(dpp); + break; + default: + l_debug("Unhandled status %u", *status); + break; + } + +failed: + dpp_reset(dpp); +} + +static bool dpp_pkex_start_authentication(struct dpp_sm *dpp) +{ + dpp->uri = dpp_generate_uri(dpp->own_asn1, dpp->own_asn1_len, 2, + netdev_get_address(dpp->netdev), + &dpp->current_freq, 1, NULL, NULL); + + l_ecdh_generate_key_pair(dpp->curve, &dpp->proto_private, + &dpp->own_proto_public); + + l_getrandom(dpp->i_nonce, dpp->nonce_len); + + dpp->peer_asn1 = dpp_point_to_asn1(dpp->peer_boot_public, + &dpp->peer_asn1_len); + + dpp->m = dpp_derive_k1(dpp->peer_boot_public, dpp->proto_private, + dpp->k1); + + dpp_hash(L_CHECKSUM_SHA256, dpp->peer_boot_hash, 1, dpp->peer_asn1, + dpp->peer_asn1_len); + + dpp->state = DPP_STATE_AUTHENTICATING; + dpp->mutual_auth = true; + + dpp_pkex_property_changed_notify(dpp); + + if (dpp->role == DPP_CAPABILITY_ENROLLEE) { + dpp->new_freq = dpp->current_freq; + + return dpp_send_authenticate_request(dpp); + } + + return true; +} + +static void dpp_handle_pkex_commit_reveal_response(struct dpp_sm *dpp, + const uint8_t *from, + const uint8_t *body, size_t body_len) +{ + struct dpp_attr_iter iter; + enum dpp_attribute_type type; + size_t len; + const uint8_t *data; + const uint8_t *wrapped = NULL; + size_t wrapped_len = 0; + uint8_t one = 1; + _auto_(l_free) uint8_t *unwrapped = NULL; + size_t unwrapped_len = 0; + const uint8_t *boot_key = NULL; + size_t boot_key_len = 0; + const uint8_t *r_auth = NULL; + uint8_t v[L_ECC_SCALAR_MAX_BYTES]; + size_t v_len; + _auto_(l_ecc_point_free) struct l_ecc_point *l = NULL; + + l_debug("PKEX commit reveal "MAC, MAC_STR(from)); + + if (dpp->state != DPP_STATE_PKEX_COMMIT_REVEAL) + return; + + if (dpp->role != DPP_CAPABILITY_ENROLLEE) + return; + + /* + * The URI may not have contained a MAC address, if this announcement + * verifies set peer_addr then. + */ + if (memcmp(from, dpp->peer_addr, 6)) { + l_debug("Unexpected source "MAC" expected "MAC, MAC_STR(from), + MAC_STR(dpp->peer_addr)); + return; + } + + dpp_attr_iter_init(&iter, body + 8, body_len - 8); + + while (dpp_attr_iter_next(&iter, &type, &len, &data)) { + switch (type) { + case DPP_ATTR_WRAPPED_DATA: + wrapped = data; + wrapped_len = len; + break; + default: + break; + } + } + + if (!wrapped) { + l_debug("No wrapped data"); + return; + } + + unwrapped = dpp_unwrap_attr(body + 2, 6, &one, 1, dpp->z, dpp->z_len, + wrapped, wrapped_len, &unwrapped_len); + if (!unwrapped) { + l_debug("Failed to unwrap Reveal-Commit message"); + return; + } + + dpp_attr_iter_init(&iter, unwrapped, unwrapped_len); + + while (dpp_attr_iter_next(&iter, &type, &len, &data)) { + switch (type) { + case DPP_ATTR_BOOTSTRAPPING_KEY: + if (len != dpp->key_len * 2) + return; + + boot_key = data; + boot_key_len = len; + break; + case DPP_ATTR_RESPONDER_AUTH_TAG: + if (len != 32) + return; + + r_auth = data; + break; + default: + break; + } + } + + dpp->peer_boot_public = l_ecc_point_from_data(dpp->curve, + L_ECC_POINT_TYPE_FULL, + boot_key, boot_key_len); + if (!dpp->peer_boot_public) { + l_debug("Peer public bootstrapping key was invalid"); + goto failed; + } + + /* L = b * X' */ + l = l_ecc_point_new(dpp->curve); + + l_ecc_point_multiply(l, dpp->pkex_private, dpp->peer_boot_public); + + if (!dpp_derive_v(l, dpp->peer_addr, dpp->peer_boot_public, + dpp->pkex_public, dpp->y_or_x, v, &v_len)) { + l_debug("Failed to derive v"); + goto failed; + } + + if (memcmp(v, r_auth, v_len)) { + l_debug("Bootstrapping data did not verify"); + goto failed; + } + + if (dpp_pkex_start_authentication(dpp)) + return; + +failed: + dpp_reset(dpp); +} + static void dpp_handle_frame(struct dpp_sm *dpp, const struct mmpdu_header *frame, const void *body, size_t body_len) @@ -2230,6 +2798,14 @@ static void dpp_handle_frame(struct dpp_sm *dpp, dpp_handle_presence_announcement(dpp, frame->address_2, body, body_len); break; + case DPP_FRAME_PKEX_XCHG_RESPONSE: + dpp_handle_pkex_exchange_response(dpp, frame->address_2, body, + body_len); + break; + case DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE: + dpp_handle_pkex_commit_reveal_response(dpp, frame->address_2, + body, body_len); + break; default: l_debug("Unhandled DPP frame %u", *ptr); break; @@ -2286,10 +2862,16 @@ static void dpp_mlme_notify(struct l_genl_msg *msg, void *user_data) if (!dpp) return; - if (dpp->state <= DPP_STATE_PRESENCE) + /* + * Don't retransmit for presence or PKEX exchange if an enrollee, both + * are broadcast frames which don't expect an ack. + */ + if (dpp->state == DPP_STATE_NOTHING || + dpp->state == DPP_STATE_PRESENCE || + (dpp->state == DPP_STATE_PKEX_EXCHANGE && + dpp->role == DPP_CAPABILITY_ENROLLEE)) return; - if (dpp->frame_cookie != cookie) return; @@ -2459,6 +3041,8 @@ static void dpp_create(struct netdev *netdev) l_dbus_object_add_interface(dbus, netdev_get_path(netdev), IWD_DPP_INTERFACE, dpp); + l_dbus_object_add_interface(dbus, netdev_get_path(netdev), + IWD_DPP_PKEX_INTERFACE, dpp); dpp_frame_watch(dpp, 0x00d0, dpp_prefix, sizeof(dpp_prefix)); @@ -2759,6 +3343,171 @@ static struct l_dbus_message *dpp_dbus_stop(struct l_dbus *dbus, return l_dbus_message_new_method_return(message); } +/* + * Section 5.6.1 + * In lieu of specific channel information obtained in a manner outside + * the scope of this specification, PKEX responders shall select one of + * the following channels: + * - 2.4 GHz: Channel 6 (2.437 GHz) + * - 5 GHz: Channel 44 (5.220 GHz) if local regulations permit + * operation only in the 5.150 – 5.250 GHz band and Channel + * 149 (5.745 GHz) otherwise + */ +static uint32_t *dpp_default_freqs(struct dpp_sm *dpp, size_t *out_len) +{ + struct wiphy *wiphy = wiphy_find_by_wdev(dpp->wdev_id); + const uint32_t default_channels[] = { 2437, 5220, 5745 }; + uint32_t *freqs_out; + size_t i; + size_t len = 1; + + if (wiphy_get_supported_bands(wiphy) & BAND_FREQ_5_GHZ) + len += 2; + + freqs_out = l_new(uint32_t, len); + + for (i = 0; i < 3; i++) + freqs_out[i] = default_channels[i]; + + *out_len = len; + return freqs_out; +} + +static bool dpp_start_pkex_enrollee(struct dpp_sm *dpp, const char *key, + const char *identifier) +{ + struct station *station = station_find(netdev_get_ifindex(dpp->netdev)); + _auto_(l_ecc_point_free) struct l_ecc_point *qi = NULL; + + if (station && station_get_connected_network(station)) { + l_debug("Already connected, disconnect before enrolling"); + return false; + } + + if (identifier) + dpp->pkex_id = l_strdup(identifier); + + dpp->pkex_key = l_strdup(key); + memcpy(dpp->peer_addr, broadcast, 6); + dpp->role = DPP_CAPABILITY_ENROLLEE; + dpp->state = DPP_STATE_PKEX_EXCHANGE; + /* + * In theory a driver could support a lesser duration than 200ms. This + * complicates things since we would need to tack on additional + * offchannel requests to meet the 200ms requirement. This could be done + * but for now use max_roc or 200ms, whichever is less. + */ + dpp->dwell = (dpp->max_roc < 200) ? dpp->max_roc : 200; + /* "DPP R2 devices are expected to use PKEXv1 by default" */ + dpp->pkex_version = 1; + + if (!l_ecdh_generate_key_pair(dpp->curve, &dpp->pkex_private, + &dpp->pkex_public)) + goto failed; + + /* + * "If Qi is the point-at-infinity, the code shall be deleted and the + * user should be notified to provision a new code" + */ + qi = dpp_derive_qi(dpp->curve, dpp->pkex_key, dpp->pkex_id, + netdev_get_address(dpp->netdev)); + if (!qi || l_ecc_point_is_infinity(qi)) { + l_debug("Cannot derive Qi, provision a new code"); + goto failed; + } + + dpp->pkex_m = l_ecc_point_new(dpp->curve); + + if (!l_ecc_point_add(dpp->pkex_m, dpp->pkex_public, qi)) + goto failed; + + dpp_pkex_property_changed_notify(dpp); + + dpp->freqs = dpp_default_freqs(dpp, &dpp->freqs_len); + if (!dpp->freqs) + goto failed; + + dpp->current_freq = dpp->freqs[dpp->freqs_idx]; + + dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT); + + l_debug("PKEX start enrollee (id=%s)", dpp->pkex_id ?: "unset"); + + dpp_start_offchannel(dpp, dpp->current_freq); + + return true; + +failed: + dpp_reset(dpp); + return false; +} + +static bool dpp_parse_pkex_args(struct l_dbus_message *message, + const char **key_out, + const char **id_out) +{ + struct l_dbus_message_iter iter; + struct l_dbus_message_iter variant; + const char *dict_key; + const char *key = NULL; + const char *id = NULL; + + if (!l_dbus_message_get_arguments(message, "a{sv}", &iter)) + return false; + + while (l_dbus_message_iter_next_entry(&iter, &dict_key, &variant)) { + if (!strcmp(dict_key, "Code")) { + if (!l_dbus_message_iter_get_variant(&variant, "s", + &key)) + return false; + } else if (!strcmp(dict_key, "Identifier")) { + if (!l_dbus_message_iter_get_variant(&variant, "s", + &id)) + return false; + } + } + + if (!key) + return false; + + if (id && !dpp_check_pkex_identifier(id)) + return false; + + *key_out = key; + *id_out = id; + + return true; +} + +static struct l_dbus_message *dpp_dbus_pkex_start_enrollee(struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + const char *key; + const char *id; + struct station *station = station_find(netdev_get_ifindex(dpp->netdev)); + + l_debug(""); + + if (dpp->state != DPP_STATE_NOTHING) + return dbus_error_busy(message); + + if (station_get_connected_network(station)) + return dbus_error_busy(message); + + if (!dpp_parse_pkex_args(message, &key, &id)) + goto invalid_args; + + if (!dpp_start_pkex_enrollee(dpp, key, id)) + goto invalid_args; + + return l_dbus_message_new_method_return(message); + +invalid_args: + return dbus_error_invalid_args(message); +} + static void dpp_setup_interface(struct l_dbus_interface *interface) { l_dbus_interface_method(interface, "StartEnrollee", 0, @@ -2848,6 +3597,14 @@ static void dpp_setup_pkex_interface(struct l_dbus_interface *interface) dpp_dbus_pkex_register_agent, "", "o", "path"); l_dbus_interface_method(interface, "UnregisterSharedCodeAgent", 0, dpp_dbus_pkex_unregister_agent, "", ""); + l_dbus_interface_method(interface, "StartEnrollee", 0, + dpp_dbus_pkex_start_enrollee, "", "a{sv}", "args"); + l_dbus_interface_method(interface, "Stop", 0, dpp_dbus_stop, "", ""); + + l_dbus_interface_property(interface, "Started", 0, "b", + dpp_pkex_get_started, NULL); + l_dbus_interface_property(interface, "Role", 0, "s", dpp_get_role, + NULL); } static void dpp_destroy_interface(void *user_data) From patchwork Tue Oct 31 18:47:50 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: James Prestwood X-Patchwork-Id: 13442186 Received: from mail-qk1-f175.google.com (mail-qk1-f175.google.com [209.85.222.175]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B073820332 for ; Tue, 31 Oct 2023 18:48:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JeL00ADj" Received: by mail-qk1-f175.google.com with SMTP id af79cd13be357-7789cc5c8ccso11751585a.0 for ; Tue, 31 Oct 2023 11:48:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1698778089; x=1699382889; darn=lists.linux.dev; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=GUZym1BOEGPM5UV9nE1+c01dkvpGGmKhausHLDpKdGc=; b=JeL00ADjKZs0Xj3yht6alW34q8Az+f3jLRX+BHhcTnsmuRAJof00j2uVZFQYSLds7x XOeC9t7b/mJAu/1l5xA7DXFwoxu+PRTUAub1sH6hl900umNzNKO0d23AMkol1dCiKnwN UgwBasfxFEaXzXByBR37c6/Lo9OunOyb2r4DVB9dpM1RJLr4gU4sSK4wq9k8doW57hP/ ZW/2WuJOvpmJ/xkDhMn7ky3MhSO+mTG2Hb3tuJ49Fg4C6DP/aVIe+IdjttIkx+3qm62D kSuGlaaO24QCzJuwQVAsgBVlRMKOHo404k0U2t5oWYHDZ1Vz6DuwQKtEf13mtRqIkTB6 ISJg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1698778089; x=1699382889; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=GUZym1BOEGPM5UV9nE1+c01dkvpGGmKhausHLDpKdGc=; b=DGTzitSFkXZ0x9VskKJoLpcvPnbve8lW0scL6XSvyoVetW0Xr1dSOzK7rpB/lvhKY1 O+1r6DhttmVMlZqKyf2l61YarLUL33zoWF3JoJTyTDdGHkgOTl5xNGFioe28akS63y0b wVam+8gjphULoUZoSNlZ86PQjec/E3sPjqWSWcq8Y4OiFhTAe/HIzjpmb1QVp+NSvRwh B7EXK/CkQz8+xTpGJdNSB+MMA0SS+Wiml2hb9R2rzlgI6DoBGFz/gsq0y/+aDrUFs3n3 Ob5tcAMZLXmZnUYgxQCvdNwz0SCrhDTHtgj+4htzVmETK02lOgIm7/DcZavRmeYWylEa AZIA== X-Gm-Message-State: AOJu0Yy2nlSVxWdL90EeG20CbB/DiK2Y24/oEuKaNErMqmAYNaZwUYYi imQ5LXmjqUZpijf/uZko1jSl19TKcXw= X-Google-Smtp-Source: AGHT+IEYm1wGQ3A8+7j29UD6XUuB/biqjWBvxl7aMmGE48dorucLSXQUs8a0OhPmm5ziW2mjLyoPkA== X-Received: by 2002:a05:620a:3905:b0:76c:ea67:38e4 with SMTP id qr5-20020a05620a390500b0076cea6738e4mr5836950qkn.12.1698778089384; Tue, 31 Oct 2023 11:48:09 -0700 (PDT) Received: from LOCLAP699.rst-02.locus (50-78-19-50-static.hfc.comcastbusiness.net. [50.78.19.50]) by smtp.gmail.com with ESMTPSA id bj30-20020a05620a191e00b00774292e636dsm736351qkb.63.2023.10.31.11.48.08 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 11:48:09 -0700 (PDT) From: James Prestwood To: iwd@lists.linux.dev Cc: James Prestwood Subject: [PATCH v3 9/9] dpp: initial version of PKEX configurator support Date: Tue, 31 Oct 2023 11:47:50 -0700 Message-Id: <20231031184750.722404-10-prestwoj@gmail.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231031184750.722404-1-prestwoj@gmail.com> References: <20231031184750.722404-1-prestwoj@gmail.com> Precedence: bulk X-Mailing-List: iwd@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The PKEX configurator role is currently limited to being a responder. When started the configurator will listen on its current operating channel for a PKEX exchange request. Once received it and the encrypted key is properly decrypted it treats this peer as the enrollee and won't allow configurations from other peers unless PKEX is restarted. The configurator will encrypt and send its encrypted ephemeral key in the PKEX exchange response. The enrollee then sends its encrypted bootstrapping key (as commit-reveal request) then the same for the configurator (as commit-reveal response). After this, PKEX authentication begins. The enrollee is expected to send the authenticate request, since its the initiator. --- src/dpp.c | 640 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 635 insertions(+), 5 deletions(-) diff --git a/src/dpp.c b/src/dpp.c index 8b47be5c..e48d695b 100644 --- a/src/dpp.c +++ b/src/dpp.c @@ -164,6 +164,7 @@ struct dpp_sm { char *pkex_id; char *pkex_key; uint8_t pkex_version; + struct l_ecc_point *peer_encr_key; struct l_ecc_point *pkex_m; /* Ephemeral key Y' or X' for enrollee or configurator */ struct l_ecc_point *y_or_x; @@ -314,6 +315,26 @@ static void *dpp_serialize_iovec(struct iovec *iov, size_t iov_len, return ret; } +static void dpp_free_pending_pkex_data(struct dpp_sm *dpp) +{ + if (dpp->agent && dpp->agent->pending_id) { + l_dbus_cancel(dbus_get_bus(), dpp->agent->pending_id); + dpp->agent->pending_id = 0; + } + + if (dpp->pkex_id) { + l_free(dpp->pkex_id); + dpp->pkex_id = NULL; + } + + if (dpp->peer_encr_key) { + l_ecc_point_free(dpp->peer_encr_key); + dpp->peer_encr_key = NULL; + } + + memset(dpp->peer_addr, 0, sizeof(dpp->peer_addr)); +} + static void dpp_free_auth_data(struct dpp_sm *dpp) { if (dpp->own_proto_public) { @@ -431,10 +452,7 @@ static void dpp_reset(struct dpp_sm *dpp) dpp->pkex_key = NULL; } - if (dpp->pkex_id) { - l_free(dpp->pkex_id); - dpp->pkex_id = NULL; - } + dpp_free_pending_pkex_data(dpp); dpp_free_auth_data(dpp); @@ -1818,6 +1836,18 @@ static void dpp_offchannel_timeout(int error, void *user_data) switch (dpp->state) { case DPP_STATE_PKEX_EXCHANGE: + if (dpp->role != DPP_CAPABILITY_CONFIGURATOR || !dpp->agent) + break; + + /* + * We have a pending agent request but it did not arrive in + * time, we cant assume the enrollee will be waiting around + * for our response so cancel the request and continue waiting + * for another request + */ + if (dpp->agent->pending_id) + dpp_free_pending_pkex_data(dpp); + /* Fall through */ case DPP_STATE_PRESENCE: break; case DPP_STATE_NOTHING: @@ -1905,7 +1935,8 @@ static void authenticate_request(struct dpp_sm *dpp, const uint8_t *from, if (util_is_broadcast_address(from)) return; - if (dpp->state != DPP_STATE_PRESENCE) + if (dpp->state != DPP_STATE_PRESENCE && + dpp->state != DPP_STATE_AUTHENTICATING) return; l_debug("authenticate request"); @@ -2764,6 +2795,516 @@ failed: dpp_reset(dpp); } +static void dpp_send_bad_group(struct dpp_sm *dpp, const uint8_t *addr) +{ + uint8_t hdr[32]; + uint8_t attrs[256]; + uint8_t *ptr = attrs; + uint16_t group; + uint8_t status = DPP_STATUS_BAD_GROUP; + struct iovec iov[2]; + const uint8_t *own_mac = netdev_get_address(dpp->netdev); + + l_put_le16(l_ecc_curve_get_ike_group(dpp->curve), &group); + + iov[0].iov_len = dpp_build_header(own_mac, addr, + DPP_FRAME_PKEX_XCHG_RESPONSE, hdr); + iov[0].iov_base = hdr; + + ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1); + ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION, + &dpp->pkex_version, 1); + ptr += dpp_append_attr(ptr, DPP_ATTR_FINITE_CYCLIC_GROUP, &group, 2); + + iov[1].iov_base = attrs; + iov[1].iov_len = ptr - attrs; + + dpp_send_frame(dpp, iov, 2, dpp->current_freq); +} + +static void dpp_send_bad_code(struct dpp_sm *dpp, const uint8_t *addr) +{ + uint8_t hdr[32]; + uint8_t attrs[256]; + uint8_t *ptr = attrs; + uint8_t status = DPP_STATUS_BAD_CODE; + struct iovec iov[2]; + const uint8_t *own_mac = netdev_get_address(dpp->netdev); + + iov[0].iov_len = dpp_build_header(own_mac, addr, + DPP_FRAME_PKEX_XCHG_RESPONSE, hdr); + iov[0].iov_base = hdr; + + ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1); + ptr += dpp_append_attr(ptr, DPP_ATTR_PROTOCOL_VERSION, + &dpp->pkex_version, 1); + if (dpp->pkex_id) + ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER, + dpp->pkex_id, strlen(dpp->pkex_id)); + + iov[1].iov_base = attrs; + iov[1].iov_len = ptr - attrs; + + dpp_send_frame(dpp, iov, 2, dpp->current_freq); +} + +static void dpp_send_pkex_exchange_response(struct dpp_sm *dpp, + struct l_ecc_point *n) +{ + uint8_t hdr[32]; + uint8_t attrs[256]; + uint8_t *ptr = attrs; + uint64_t n_data[L_ECC_MAX_DIGITS * 2]; + uint16_t group; + uint8_t status = DPP_STATUS_OK; + struct iovec iov[2]; + const uint8_t *own_mac = netdev_get_address(dpp->netdev); + + l_put_le16(l_ecc_curve_get_ike_group(dpp->curve), &group); + + iov[0].iov_len = dpp_build_header(own_mac, dpp->peer_addr, + DPP_FRAME_PKEX_XCHG_RESPONSE, hdr); + iov[0].iov_base = hdr; + + ptr += dpp_append_attr(ptr, DPP_ATTR_STATUS, &status, 1); + + if (dpp->pkex_id) + ptr += dpp_append_attr(ptr, DPP_ATTR_CODE_IDENTIFIER, + dpp->pkex_id, strlen(dpp->pkex_id)); + + l_ecc_point_get_data(n, n_data, sizeof(n_data)); + + ptr += dpp_append_attr(ptr, DPP_ATTR_ENCRYPTED_KEY, + n_data, dpp->key_len * 2); + + iov[1].iov_base = attrs; + iov[1].iov_len = ptr - attrs; + + dpp->state = DPP_STATE_PKEX_COMMIT_REVEAL; + + dpp_pkex_property_changed_notify(dpp); + + dpp_send_frame(dpp, iov, 2, dpp->current_freq); +} + +static void dpp_process_pkex_exchange_request(struct dpp_sm *dpp, + struct l_ecc_point *m) +{ + _auto_(l_ecc_point_free) struct l_ecc_point *n = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *qr = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *qi = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *k = NULL; + const uint8_t *own_addr = netdev_get_address(dpp->netdev); + + /* Qi = H(MAC-Initiator | [identifier | ] code) * Pi */ + qi = dpp_derive_qi(dpp->curve, dpp->pkex_key, dpp->pkex_id, + dpp->peer_addr); + if (!qi) { + l_debug("could not derive Qi"); + return; + } + + /* X' = M - Qi */ + dpp->y_or_x = l_ecc_point_new(dpp->curve); + + l_ecc_point_inverse(qi); + l_ecc_point_add(dpp->y_or_x, m, qi); + + /* + * "The resulting ephemeral key, denoted X’, is checked whether it is + * the point-at-infinity. If it is not valid, the protocol silently + * fails" + */ + if (l_ecc_point_is_infinity(dpp->y_or_x)) { + l_debug("X' is at infinity, ignore message"); + dpp_reset(dpp); + return; + } + + qr = dpp_derive_qr(dpp->curve, dpp->pkex_key, dpp->pkex_id, own_addr); + if (!qr || l_ecc_point_is_infinity(qr)) { + l_debug("Qr did not derive"); + l_ecc_point_free(dpp->y_or_x); + dpp->y_or_x = NULL; + goto bad_code; + } + + /* + * "The Responder then generates a random ephemeral keypair, y/Y, + * encrypts Y with Qr to obtain the result, denoted N." + */ + l_ecdh_generate_key_pair(dpp->curve, &dpp->pkex_private, + &dpp->pkex_public); + + /* N = Y + Qr */ + n = l_ecc_point_new(dpp->curve); + + l_ecc_point_add(n, dpp->pkex_public, qr); + + /* K = y * X' */ + + k = l_ecc_point_new(dpp->curve); + + l_ecc_point_multiply(k, dpp->pkex_private, dpp->y_or_x); + + /* z = HKDF(<>, info | M.x | N.x | code, K.x) */ + dpp_derive_z(dpp->peer_addr, own_addr, n, m, k, dpp->pkex_key, + dpp->pkex_id, dpp->z, &dpp->z_len); + + dpp_send_pkex_exchange_response(dpp, n); + + return; + +bad_code: + dpp_send_bad_code(dpp, dpp->peer_addr); + return; +} + +static void dpp_pkex_agent_reply(struct l_dbus_message *message, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + const char *error, *text; + const char *code; + + dpp->agent->pending_id = 0; + + l_debug("SharedCodeAgent %s path %s replied", dpp->agent->owner, + dpp->agent->path); + + if (l_dbus_message_get_error(message, &error, &text)) { + l_error("RequestSharedCode(%s) returned %s(\"%s\")", + dpp->pkex_id, error, text); + goto reset; + } + + if (!l_dbus_message_get_arguments(message, "s", &code)) { + l_debug("Invalid arguments, check SharedCodeAgent!"); + goto reset; + } + + dpp->pkex_key = l_strdup(code); + dpp_process_pkex_exchange_request(dpp, dpp->peer_encr_key); + + return; + +reset: + dpp_free_pending_pkex_data(dpp); +} + +static bool dpp_pkex_agent_request(struct dpp_sm *dpp) +{ + struct l_dbus_message *msg; + + if (!dpp->agent) + return false; + + if (L_WARN_ON(dpp->agent->pending_id)) + return false; + + msg = l_dbus_message_new_method_call(dbus_get_bus(), + dpp->agent->owner, + dpp->agent->path, + IWD_SHARED_CODE_AGENT_INTERFACE, + "RequestSharedCode"); + l_dbus_message_set_arguments(msg, "s", dpp->pkex_id); + + + dpp->agent->pending_id = l_dbus_send_with_reply(dbus_get_bus(), + msg, + dpp_pkex_agent_reply, + dpp, NULL); + return dpp->agent->pending_id != 0; +} + +static void dpp_handle_pkex_exchange_request(struct dpp_sm *dpp, + const uint8_t *from, + const uint8_t *body, size_t body_len) +{ + struct dpp_attr_iter iter; + enum dpp_attribute_type type; + size_t len; + const uint8_t *data; + uint8_t version = 0; + uint16_t group = 0; + const char *id = NULL; + size_t id_len = 0; + const void *key = NULL; + size_t key_len = 0; + _auto_(l_ecc_point_free) struct l_ecc_point *m = NULL; + + l_debug("PKEX exchange request "MAC, MAC_STR(from)); + + if (dpp->state != DPP_STATE_PKEX_EXCHANGE) + return; + + if (dpp->role != DPP_CAPABILITY_CONFIGURATOR) + return; + + if (!l_memeqzero(dpp->peer_addr, 6)) { + l_debug("Already configuring enrollee, ignoring"); + return; + } + + dpp_attr_iter_init(&iter, body + 8, body_len - 8); + + while (dpp_attr_iter_next(&iter, &type, &len, &data)) { + switch (type) { + case DPP_ATTR_PROTOCOL_VERSION: + if (len != 1) + return; + + version = l_get_u8(data); + break; + case DPP_ATTR_FINITE_CYCLIC_GROUP: + if (len != 2) + return; + + group = l_get_le16(data); + break; + case DPP_ATTR_CODE_IDENTIFIER: + id = (char *) data; + id_len = len; + break; + case DPP_ATTR_ENCRYPTED_KEY: + key = data; + key_len = len; + break; + default: + break; + } + } + + if (!key || !group) { + l_debug("initiator did not provide group or key, ignoring"); + return; + } + + if (group != l_ecc_curve_get_ike_group(dpp->curve)) { + l_debug("initiator is not using the same group"); + goto bad_group; + } + + /* + * If the group isn't the same the key length won't match, so check + * this here after we've determined the groups are equal + */ + if (key_len != dpp->key_len * 2) { + l_debug("Unexpected encrypted key length"); + return; + } + + if (version && version != dpp->pkex_version) { + l_debug("initiator is not using the same version, ignoring"); + return; + } + + if (dpp->pkex_id) { + if (!id || !dpp_check_pkex_identifier(id) || + id_len != strlen(dpp->pkex_id) || + strncmp(dpp->pkex_id, id, id_len)) { + l_debug("mismatch identifier, ignoring"); + return; + } + } + + m = l_ecc_point_from_data(dpp->curve, L_ECC_POINT_TYPE_FULL, + key, key_len); + if (!m) { + l_debug("could not parse key from initiator, ignoring"); + return; + } + + memcpy(dpp->peer_addr, from, 6); + + if (!dpp->pkex_key) { + if (!id) { + l_debug("Configurator started with agent but enrollee " + "sent no identifier, ignoring"); + return; + } + + dpp->pkex_id = l_strndup(id, id_len); + + /* Need to obtain code from agent */ + if (!dpp_pkex_agent_request(dpp)) { + l_debug("Failed to request code from agent!"); + dpp_free_pending_pkex_data(dpp); + return; + } + + /* Save the encrypted key/identifier for the agent callback */ + + dpp->peer_encr_key = l_steal_ptr(m); + + return; + } + + dpp_process_pkex_exchange_request(dpp, m); + + return; + +bad_group: + dpp_send_bad_group(dpp, from); +} + +static void dpp_send_commit_reveal_response(struct dpp_sm *dpp, + const uint8_t *v, size_t v_len) +{ + uint8_t hdr[32]; + uint8_t attrs[256]; + uint8_t *ptr = attrs; + uint8_t one = 1; + struct iovec iov[2]; + const uint8_t *own_mac = netdev_get_address(dpp->netdev); + uint8_t b_pub[L_ECC_POINT_MAX_BYTES]; + size_t b_len; + + b_len = l_ecc_point_get_data(dpp->boot_public, b_pub, sizeof(b_pub)); + + + iov[0].iov_len = dpp_build_header(own_mac, dpp->peer_addr, + DPP_FRAME_PKEX_COMMIT_REVEAL_RESPONSE, hdr); + iov[0].iov_base = hdr; + + ptr += dpp_append_wrapped_data(hdr + 26, 6, &one, 1, ptr, + sizeof(attrs), dpp->z, dpp->z_len, 2, + DPP_ATTR_BOOTSTRAPPING_KEY, b_len, b_pub, + DPP_ATTR_RESPONDER_AUTH_TAG, v_len, v); + + iov[1].iov_base = attrs; + iov[1].iov_len = ptr - attrs; + + dpp_send_frame(dpp, iov, 2, dpp->current_freq); +} + +static void dpp_handle_pkex_commit_reveal_request(struct dpp_sm *dpp, + const uint8_t *from, + const uint8_t *body, size_t body_len) +{ + struct dpp_attr_iter iter; + enum dpp_attribute_type type; + size_t len; + const uint8_t *data; + const void *wrapped = NULL; + size_t wrapped_len = 0; + _auto_(l_free) uint8_t *unwrapped = NULL; + size_t unwrapped_len; + uint8_t zero = 0; + const void *key = 0; + size_t key_len = 0; + const void *i_auth = NULL; + size_t i_auth_len = 0; + _auto_(l_ecc_point_free) struct l_ecc_point *j = NULL; + _auto_(l_ecc_point_free) struct l_ecc_point *l = NULL; + uint8_t u[L_ECC_SCALAR_MAX_BYTES]; + size_t u_len = 0; + uint8_t v[L_ECC_SCALAR_MAX_BYTES]; + size_t v_len = 0; + const uint8_t *own_addr = netdev_get_address(dpp->netdev); + + l_debug("PKEX commit-reveal request "MAC, MAC_STR(from)); + + if (dpp->state != DPP_STATE_PKEX_COMMIT_REVEAL) + return; + + if (dpp->role != DPP_CAPABILITY_CONFIGURATOR) + return; + + dpp_attr_iter_init(&iter, body + 8, body_len - 8); + + while (dpp_attr_iter_next(&iter, &type, &len, &data)) { + switch (type) { + case DPP_ATTR_WRAPPED_DATA: + wrapped = data; + wrapped_len = len; + break; + default: + break; + } + } + + if (!wrapped) { + l_debug("No wrapped data"); + return; + } + + unwrapped = dpp_unwrap_attr(body + 2, 6, &zero, 1, dpp->z, dpp->z_len, + wrapped, wrapped_len, &unwrapped_len); + if (!unwrapped) { + l_debug("Failed to unwrap attributes"); + return; + } + + dpp_attr_iter_init(&iter, unwrapped, unwrapped_len); + + while (dpp_attr_iter_next(&iter, &type, &len, &data)) { + switch (type) { + case DPP_ATTR_BOOTSTRAPPING_KEY: + if (len != dpp->key_len * 2) + return; + + key = data; + key_len = len; + break; + case DPP_ATTR_INITIATOR_AUTH_TAG: + if (len != 32) + return; + + i_auth = data; + i_auth_len = len; + break; + default: + break; + } + } + + if (!key || !i_auth) { + l_debug("missing attributes"); + return; + } + + dpp->peer_boot_public = l_ecc_point_from_data(dpp->curve, + L_ECC_POINT_TYPE_FULL, key, key_len); + if (!dpp->peer_boot_public) { + l_debug("peers boostrapping key did not validate"); + goto failed; + } + + /* J' = y * A' */ + j = l_ecc_point_new(dpp->curve); + + l_ecc_point_multiply(j, dpp->pkex_private, dpp->peer_boot_public); + + dpp_derive_u(j, dpp->peer_addr, dpp->peer_boot_public, dpp->pkex_public, + dpp->y_or_x, u, &u_len); + + if (memcmp(u, i_auth, i_auth_len)) { + l_debug("Initiator auth tag did not verify"); + goto failed; + } + + /* L' = x * B' */ + l = l_ecc_point_new(dpp->curve); + + l_ecc_point_multiply(l, dpp->boot_private, dpp->y_or_x); + + if (!dpp_derive_v(l, own_addr, dpp->boot_public, dpp->y_or_x, + dpp->pkex_public, v, &v_len)) { + l_debug("Failed to derive v"); + goto failed; + } + + dpp_send_commit_reveal_response(dpp, v, v_len); + + dpp_pkex_start_authentication(dpp); + + return; + +failed: + dpp_reset(dpp); +} + static void dpp_handle_frame(struct dpp_sm *dpp, const struct mmpdu_header *frame, const void *body, size_t body_len) @@ -2806,6 +3347,14 @@ static void dpp_handle_frame(struct dpp_sm *dpp, dpp_handle_pkex_commit_reveal_response(dpp, frame->address_2, body, body_len); break; + case DPP_FRAME_PKEX_VERSION1_XCHG_REQUST: + dpp_handle_pkex_exchange_request(dpp, frame->address_2, body, + body_len); + break; + case DPP_FRAME_PKEX_COMMIT_REVEAL_REQUEST: + dpp_handle_pkex_commit_reveal_request(dpp, frame->address_2, + body, body_len); + break; default: l_debug("Unhandled DPP frame %u", *ptr); break; @@ -3508,6 +4057,83 @@ invalid_args: return dbus_error_invalid_args(message); } +static struct l_dbus_message *dpp_start_pkex_configurator(struct dpp_sm *dpp, + const char *key, const char *identifier, + struct l_dbus_message *message) +{ + struct handshake_state *hs = netdev_get_handshake(dpp->netdev); + struct station *station = station_find(netdev_get_ifindex(dpp->netdev)); + struct network *network = station_get_connected_network(station); + struct scan_bss *bss = station_get_connected_bss(station); + const struct l_settings *settings; + + if (dpp->state != DPP_STATE_NOTHING) + return dbus_error_busy(message); + + if (!network || !bss) + return dbus_error_not_connected(message); + + settings = network_get_settings(network); + if (!settings) { + l_debug("No settings for network, is this a known network?"); + return dbus_error_not_configured(message); + } + + if (identifier) + dpp->pkex_id = l_strdup(identifier); + + if (key) + dpp->pkex_key = l_strdup(key); + + dpp->role = DPP_CAPABILITY_CONFIGURATOR; + dpp->state = DPP_STATE_PKEX_EXCHANGE; + dpp->current_freq = bss->frequency; + dpp->pkex_version = 1; + dpp->config = dpp_configuration_new(network_get_settings(network), + network_get_ssid(network), + hs->akm_suite); + + dpp_reset_protocol_timer(dpp, DPP_PKEX_PROTO_TIMEOUT); + dpp_pkex_property_changed_notify(dpp); + + if (dpp->pkex_key) + l_debug("Starting PKEX configurator for single enrollee"); + else + l_debug("Starting PKEX configurator with agent"); + + return l_dbus_message_new_method_return(message); +} + +static struct l_dbus_message *dpp_dbus_pkex_configure_enrollee( + struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + const char *key; + const char *id; + + l_debug(""); + + if (!dpp_parse_pkex_args(message, &key, &id)) + return dbus_error_invalid_args(message); + + return dpp_start_pkex_configurator(dpp, key, id, message); +} + +static struct l_dbus_message *dpp_dbus_pkex_start_configurator( + struct l_dbus *dbus, + struct l_dbus_message *message, + void *user_data) +{ + struct dpp_sm *dpp = user_data; + + if (!dpp->agent) + return dbus_error_no_agent(message); + + return dpp_start_pkex_configurator(dpp, NULL, NULL, message); +} + static void dpp_setup_interface(struct l_dbus_interface *interface) { l_dbus_interface_method(interface, "StartEnrollee", 0, @@ -3599,6 +4225,10 @@ static void dpp_setup_pkex_interface(struct l_dbus_interface *interface) dpp_dbus_pkex_unregister_agent, "", ""); l_dbus_interface_method(interface, "StartEnrollee", 0, dpp_dbus_pkex_start_enrollee, "", "a{sv}", "args"); + l_dbus_interface_method(interface, "ConfigureEnrollee", 0, + dpp_dbus_pkex_configure_enrollee, "", "a{sv}", "args"); + l_dbus_interface_method(interface, "StartConfigurator", 0, + dpp_dbus_pkex_start_configurator, "", ""); l_dbus_interface_method(interface, "Stop", 0, dpp_dbus_stop, "", ""); l_dbus_interface_property(interface, "Started", 0, "b",