From 60e584f005c46acfe76a4a27c8c73997bd2638ee Mon Sep 17 00:00:00 2001
From: Anjan Chanda <anjan.chanda@iopsys.eu>
Date: Thu, 31 Dec 2020 16:14:01 +0100
Subject: [PATCH] add ap-autoconfig wsc cmdu handling
---
src/1905_tlvs.h | 7 +-
src/Makefile | 3 +
src/cmdu_input.c | 435 +++++++++++++++-
src/cryptutil.c | 809 ++++++++++++++++++++++++++++++
src/cryptutil.h | 34 ++
src/i1905.c | 71 +++
src/i1905.h | 31 ++
src/i1905_dm.h | 12 +
src/i1905_wsc.c | 1252 ++++++++++++++++++++++++++++++++++++++++++++++
src/i1905_wsc.h | 189 +++++++
10 files changed, 2835 insertions(+), 8 deletions(-)
create mode 100644 src/cryptutil.c
create mode 100644 src/cryptutil.h
create mode 100644 src/i1905_wsc.c
create mode 100644 src/i1905_wsc.h
diff --git a/src/1905_tlvs.h b/src/1905_tlvs.h
index ae836795..3498cab7 100644
--- a/src/1905_tlvs.h
+++ b/src/1905_tlvs.h
@@ -11,6 +11,9 @@
#define ETHERTYPE_1905 0x893a
#define ETHERTYPE_LLDP 0x88cc
+extern uint8_t MCAST_1905[];
+extern uint8_t MCAST_LLDP[];
+
/* 1905 CMDU types */
#define CMDU_TYPE_TOPOLOGY_DISCOVERY 0x0000
@@ -98,6 +101,7 @@
#define IEEE80211_FREQUENCY_BAND_2_4_GHZ (0x00)
#define IEEE80211_FREQUENCY_BAND_5_GHZ (0x01)
#define IEEE80211_FREQUENCY_BAND_60_GHZ (0x02)
+#define IEEE80211_FREQUENCY_BAND_UNKNOWN (0xff)
/* IEEE80211 roles */
@@ -293,8 +297,7 @@ struct tlv_supported_band {
/* TLV: wsc */
struct tlv_wsc {
- uint16_t framelen;
- uint8_t frame[];
+ uint8_t frame[0];
} __attribute__((packed));
diff --git a/src/Makefile b/src/Makefile
index da69bbe3..38b8fd66 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -6,9 +6,11 @@ OBJS = cmdu.o \
cmdu_input.o \
cmdu_output.o \
config.o \
+ cryptutil.o \
i1905.o \
i1905_dm.o \
i1905_al.o \
+ i1905_wsc.o \
i1905_extension.o \
i1905_ubus.o \
main.o \
@@ -24,6 +26,7 @@ LIBS += -leasy
LIBS += -lwifi-6
LIBS += -rdynamic -ldl
LIBS += -lnl-3 -lnl-genl-3 -lnl-route-3
+LIBS += -lssl -lcrypto
extmod_subdirs ?= $(wildcard extmodules/*)
diff --git a/src/cmdu_input.c b/src/cmdu_input.c
index b5585d37..5922f103 100644
--- a/src/cmdu_input.c
+++ b/src/cmdu_input.c
@@ -474,6 +474,239 @@ out_send:
return ret;
}
+int i1905_send_ap_autoconfig_search(struct i1905_interface_private *pif,
+ uint8_t freqband)
+{
+ struct i1905_interface *iface = i1905_interface_priv(pif);
+ struct i1905_selfdevice *self = (struct i1905_selfdevice *)iface->device;
+ struct i1905_interface *ifs;
+ bool forall_bands = true;
+
+
+
+ if (!IS_MEDIA_WIFI(iface->media)) {
+ fprintf(stderr, "%s is not a WiFi interface\n", iface->ifname);
+ return -1;
+ }
+
+ if (freqband >= IEEE80211_FREQUENCY_BAND_2_4_GHZ
+ && freqband <= IEEE80211_FREQUENCY_BAND_60_GHZ
+ /* && wifi_is_band_supported(iface->ifname, freqband) */) {
+
+ forall_bands = false;
+ }
+
+
+ //TODO: check if reliable mcast for search needed ????
+ list_for_each_entry(ifs, &self->iflist, list) {
+ struct cmdu_buff *frm = NULL;
+ struct tlv *t;
+ int ret = 0;
+
+
+ if (!strncmp(iface->ifname, ifs->ifname, 16) &&
+ !memcmp(iface->macaddr, ifs->macaddr, 6)) {
+
+ continue;
+ }
+
+
+ frm = cmdu_alloc_simple(CMDU_TYPE_AP_AUTOCONFIGURATION_SEARCH, 0);
+ if (!frm) {
+ fprintf(stderr, "%s: -ENOMEM\n", __func__);
+ return -1;
+ }
+
+ t = tlv_alloc(256);
+ if (!t) {
+ cmdu_free(frm);
+ fprintf(stderr, "%s: -ENOMEM\n", __func__);
+ return -1;
+ }
+
+ t->type = TLV_TYPE_AL_MAC_ADDRESS_TYPE;
+ t->len = 6;
+ memcpy(t->data, iface->aladdr, 6);
+
+ ret = cmdu_put_tlv(frm, t);
+ if (ret) {
+ fprintf(stderr, "%s: error: cmdu_put_tlv()\n", __func__);
+ cmdu_free(frm);
+ tlv_free_linear(t);
+ return -1;
+ }
+
+ tlv_zero(t); /* reuse the tlv buffer */
+
+ t->type = TLV_TYPE_SEARCHED_ROLE;
+ t->len = 1;
+ t->data[0] = 0x00;
+ ret = cmdu_put_tlv(frm, t);
+ if (ret) {
+ fprintf(stderr, "%s: error: cmdu_put_tlv()\n", __func__);
+ cmdu_free(frm);
+ tlv_free_linear(t);
+ return -1;
+ }
+
+ tlv_zero(t);
+
+ t->type = TLV_TYPE_AUTOCONFIG_FREQ_BAND;
+ t->len = 1;
+ t->data[0] = freqband;
+
+ ret = cmdu_put_tlv(frm, t);
+ if (ret) {
+ fprintf(stderr, "%s: error: cmdu_put_tlv()\n", __func__);
+ cmdu_free(frm);
+ tlv_free_linear(t);
+ return -1;
+ }
+
+ cmdu_put_eom(frm);
+
+ ret = i1905_send_cmdu(pif, MCAST_1905, iface->aladdr,
+ ETHERTYPE_1905, frm);
+ if (ret) {
+ fprintf(stderr, "Error sending AP_AUTOCONFIG_SEARCH\n");
+ }
+ }
+
+ return 0;
+}
+
+int i1905_send_ap_autoconfig_response(struct i1905_interface_private *pif,
+ uint8_t *dest, uint8_t band, uint16_t mid)
+{
+ struct i1905_interface *iface = i1905_interface_priv(pif);
+ //struct i1905_selfdevice *self = (struct i1905_selfdevice *)iface->device;
+ //struct i1905_device *rdev = NULL;
+ struct cmdu_buff *resp;
+ struct tlv *t;
+ int ret;
+
+
+
+ resp = cmdu_alloc_simple(CMDU_TYPE_AP_AUTOCONFIGURATION_RESPONSE, mid);
+ if (!resp) {
+ fprintf(stderr, "%s: -ENOMEM\n", __func__);
+ return -1;
+ }
+
+ t = tlv_alloc(256);
+ if (!t) {
+ cmdu_free(resp);
+ fprintf(stderr, "%s: -ENOMEM\n", __func__);
+ return -1;
+ }
+
+ t->type = TLV_TYPE_SUPPORTED_ROLE;
+ t->len = 1;
+ t->data[0] = 0x00;
+ ret = cmdu_put_tlv(resp, t);
+ if (ret) {
+ fprintf(stderr, "%s: error: cmdu_put_tlv()\n", __func__);
+ cmdu_free(resp);
+ tlv_free_linear(t);
+ return -1;
+ }
+
+ tlv_zero(t);
+
+ t->type = TLV_TYPE_SUPPORTED_FREQ_BAND;
+ t->len = 1;
+ t->data[0] = band;
+
+ ret = cmdu_put_tlv(resp, t);
+ if (ret) {
+ fprintf(stderr, "%s: error: cmdu_put_tlv()\n", __func__);
+ cmdu_free(resp);
+ tlv_free_linear(t);
+ return -1;
+ }
+
+ cmdu_put_eom(resp);
+
+ ret = i1905_send_cmdu(pif, dest, iface->aladdr, ETHERTYPE_1905, resp);
+ if (ret) {
+ fprintf(stderr, "Error sending AP_AUTOCONFIG_RESPONSE\n");
+ }
+
+ return ret;
+}
+
+int i1905_send_ap_autoconfig_wsc_m1(struct i1905_interface_private *pif,
+ uint8_t *dest)
+{
+ struct i1905_interface *iface = i1905_interface_priv(pif);
+ //struct i1905_selfdevice *self = (struct i1905_selfdevice *)iface->device;
+ //struct i1905_device *rdev = NULL;
+ struct cmdu_buff *frm;
+ struct tlv *t;
+ int ret;
+
+ uint8_t *m1;
+ uint16_t m1_size = 0;
+ void *key;
+ //uint8_t macaddr[6] = {0};
+ //uint16_t auth = WPA2PSK;
+ //uint16_t enc = CCMP;
+ struct wps_data wps;
+
+
+ frm = cmdu_alloc_simple(CMDU_TYPE_AP_AUTOCONFIGURATION_WSC, 0);
+ if (!frm) {
+ fprintf(stderr, "%s: -ENOMEM\n", __func__);
+ return -1;
+ }
+
+ wps.auth_types = pif->wsc->auth_types;
+ wps.enc_types = pif->wsc->enc_types;
+ wps.band = pif->wsc->band;
+
+ ret = wsc_build_m1(iface->ifname, &m1, &m1_size, &key, &wps);
+ if (ret) {
+ fprintf(stderr, "Failed to build WSC M1 frame!\n");
+ cmdu_free(frm);
+ return ret;
+ }
+
+ //TODO: improve wsc data and state -- maybe move to iface
+ if (pif->wsc) {
+ pif->wsc->last_msg = m1;
+ pif->wsc->last_msglen = m1_size;
+ pif->wsc->key = key;
+ }
+
+ //TODO: avoid following alloc and memcpy
+ t = tlv_alloc(FRAG_DATA_SIZE_TLV);
+ if (!t) {
+ cmdu_free(frm);
+ fprintf(stderr, "%s: -ENOMEM\n", __func__);
+ return -1;
+ }
+
+ t->type = TLV_TYPE_WSC;
+ t->len = m1_size;
+ memcpy(t->data, m1, m1_size);
+ ret = cmdu_put_tlv(frm, t);
+ if (ret) {
+ fprintf(stderr, "%s: error: cmdu_put_tlv()\n", __func__);
+ cmdu_free(frm);
+ tlv_free_linear(t);
+ return -1;
+ }
+
+ cmdu_put_eom(frm);
+
+ ret = i1905_send_cmdu(pif, dest, iface->aladdr, ETHERTYPE_1905, frm);
+ if (ret) {
+ fprintf(stderr, "Error sending AP_AUTOCONFIG_WSC_M1\n");
+ }
+
+ return ret;
+}
+
int i1905_handle_topology_discovery(struct i1905_interface_private *pif,
struct cmdu_buff *rxf)
{
@@ -757,15 +990,121 @@ int i1905_handle_link_metric_response(struct i1905_interface_private *pif,
int i1905_handle_ap_autoconfig_search(struct i1905_interface_private *pif,
struct cmdu_buff *rxf)
{
- //TODO
- return 0;
+ struct tlv_policy a_policy[] = {
+ [0] = { .type = TLV_TYPE_AL_MAC_ADDRESS_TYPE, .present = TLV_PRESENT_ONE },
+ [1] = { .type = TLV_TYPE_SEARCHED_ROLE, .present = TLV_PRESENT_ONE },
+ [2] = { .type = TLV_TYPE_AUTOCONFIG_FREQ_BAND, .present = TLV_PRESENT_ONE },
+ };
+ struct i1905_interface *iface = i1905_interface_priv(pif);
+ struct tlv_autoconfig_band *freq;
+ uint8_t aladdr_origin[6] = {0};
+ struct tlv *tv[3][16];
+ int ret;
+
+
+ fprintf(stderr, "%s -------------->\n", __func__);
+
+ cmdu_parse_tlvs(rxf, tv, a_policy, 3);
+
+ if (!tv[0][0] || !tv[1][0] || !tv[2][0])
+ return -1;
+
+
+ memcpy(aladdr_origin, tv[0][0]->data, tlv_length(tv[0][0]));
+ if (hwaddr_is_zero(aladdr_origin)) {
+ fprintf(stderr,
+ "%s: Discard ap-autoconfig search from aladdr = 0!\n",
+ __func__);
+
+ return -1;
+ }
+
+ if (tv[1][0]->data[0] != IEEE80211_ROLE_REGISTRAR) {
+ fprintf(stderr,
+ "%s: Discard ap-autoconfig search for role != registrar\n",
+ __func__);
+ return -1;
+ }
+
+ freq = (struct tlv_autoconfig_band *)tv[2][0]->data;
+ if (freq->band > IEEE80211_FREQUENCY_BAND_60_GHZ) {
+ fprintf(stderr,
+ "%s: Discard ap-autoconfig search for invalid WiFi band\n",
+ __func__);
+ return -1;
+ }
+
+ if (i1905_has_registrar(pif, freq->band)) {
+ ret = i1905_send_ap_autoconfig_response(pif, aladdr_origin,
+ freq->band,
+ cmdu_get_mid(rxf));
+ } else {
+ ret = i1905_send_cmdu(pif, MCAST_1905, iface->aladdr,
+ ETHERTYPE_1905, rxf);
+ if (ret)
+ fprintf(stderr, "Error sending AP_AUTOCONFIG_SEARCH\n");
+ }
+
+ return ret;
}
int i1905_handle_ap_autoconfig_response(struct i1905_interface_private *pif,
struct cmdu_buff *rxf)
{
- //TODO
- return 0;
+ struct tlv_policy a_policy[] = {
+ [0] = { .type = TLV_TYPE_SUPPORTED_ROLE, .present = TLV_PRESENT_ONE },
+ [1] = { .type = TLV_TYPE_SUPPORTED_FREQ_BAND, .present = TLV_PRESENT_ONE },
+ };
+ struct i1905_interface *iface = i1905_interface_priv(pif);
+ struct i1905_selfdevice *self = (struct i1905_selfdevice *)iface->device;
+ struct tlv_supported_band *freq;
+ struct i1905_interface *ifs;
+ struct tlv *tv[2][16];
+ int ret;
+
+
+ fprintf(stderr, "%s -------------->\n", __func__);
+
+ cmdu_parse_tlvs(rxf, tv, a_policy, 2);
+
+ if (!tv[0][0] || !tv[1][0])
+ return -1;
+
+
+ if (tv[0][0]->data[0] != IEEE80211_ROLE_REGISTRAR) {
+ fprintf(stderr,
+ "%s: Discard ap-autoconfig response for role != registrar\n",
+ __func__);
+ return -1;
+ }
+
+ freq = (struct tlv_supported_band *)tv[1][0]->data;
+ if (freq->band > IEEE80211_FREQUENCY_BAND_60_GHZ) {
+ fprintf(stderr,
+ "%s: Discard ap-autoconfig response for invalid WiFi band\n",
+ __func__);
+ return -1;
+ }
+
+ //TODO: ubus notify discovered registrar
+ //If this is in response to discover_registrar(), then set
+ //registrar_established.
+ //Else, send WSC-M1 for each unconfigured i1905 WiFi radios
+
+ list_for_each_entry(ifs, &self->iflist, list) {
+ if (IS_MEDIA_WIFI(ifs->media) &&
+ !((struct i1905_interface_private *)ifs->priv)->configured) {
+
+ //TODO: check band in supported-bands
+ ret = i1905_send_ap_autoconfig_wsc_m1(ifs->priv, rxf->origin);
+ if (ret) {
+ fprintf(stderr, "Error sending AP_AUTOCONFIG_WSC_M1\n");
+ break;
+ }
+ }
+ }
+
+ return ret;
}
int i1905_handle_ap_autoconfig_renew(struct i1905_interface_private *pif,
@@ -775,11 +1114,95 @@ int i1905_handle_ap_autoconfig_renew(struct i1905_interface_private *pif,
return 0;
}
+static int i1905_wsc_process_m1(struct i1905_interface_private *pif,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct i1905_interface *iface = i1905_interface_priv(pif);
+ //struct i1905_interface_private_wsc *wsc = pif->wsc;
+ int ret;
+ uint8_t *m2;
+ uint16_t m2_size;
+ struct wps_credential cred;
+
+
+ //ret = wsc_process_m1(iface->ifname, msg, msglen);
+
+ //TODO: get cred from config file
+ //i1905_interface_credential(&cred);
+
+
+ ret = wsc_build_m2(msg, msglen, &m2, &m2_size, &cred);
+ if (ret) {
+ fprintf(stderr, "Error sending WSC M2 for '%s'\n", iface->ifname);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int i1905_wsc_process_m2(struct i1905_interface_private *pif,
+ uint8_t *msg, uint16_t msglen)
+{
+ struct i1905_interface *iface = i1905_interface_priv(pif);
+ struct i1905_interface_private_wsc *wsc = pif->wsc;
+ struct wps_credential out = {0};
+ int ret;
+
+
+ ret = wsc_process_m2(iface->ifname, wsc->key, wsc->last_msg,
+ wsc->last_msglen, msg, msglen, &out);
+ if (ret) {
+ fprintf(stderr, "Error processing WSC M2 for '%s'\n", iface->ifname);
+ return ret;
+ }
+
+ /* TODO: update wireless config */
+
+
+ return 0;
+}
+
int i1905_handle_ap_autoconfig_wsc(struct i1905_interface_private *pif,
struct cmdu_buff *rxf)
{
- //TODO
- return 0;
+ struct tlv_policy a_policy[] = {
+ [0] = { .type = TLV_TYPE_WSC, .present = TLV_PRESENT_ONE },
+ };
+ //struct i1905_interface *iface = i1905_interface_priv(pif);
+ //struct i1905_selfdevice *self = (struct i1905_selfdevice *)iface->device;
+ struct tlv *tv[1][16];
+ uint8_t wsc_msgtype;
+ uint16_t msglen;
+ uint8_t *msg;
+ int ret = 0;
+
+
+ fprintf(stderr, "%s -------------->\n", __func__);
+
+ cmdu_parse_tlvs(rxf, tv, a_policy, 1);
+
+ if (!tv[0][0])
+ return -1;
+
+ msg = tv[0][0]->data;
+ msglen = tlv_length(tv[0][0]);
+
+ wsc_msgtype = wsc_get_message_type(msg, msglen);
+ switch (wsc_msgtype) {
+ case WPS_M1:
+ fprintf(stderr, "Received WPS M1\n");
+ ret = i1905_wsc_process_m1(pif, msg, msglen);
+ break;
+ case WPS_M2:
+ fprintf(stderr, "Received WPS M2\n");
+ ret = i1905_wsc_process_m2(pif, msg, msglen);
+ break;
+ default:
+ fprintf(stderr, "Received WPS msgtype %u\n", wsc_msgtype);
+ return -1;
+ }
+
+ return ret;
}
int i1905_handle_pbc_notification(struct i1905_interface_private *pif,
diff --git a/src/cryptutil.c b/src/cryptutil.c
new file mode 100644
index 00000000..7d470a6d
--- /dev/null
+++ b/src/cryptutil.c
@@ -0,0 +1,809 @@
+/*
+ * cryptutil.c - crypto utility functions
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <openssl/err.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/dh.h>
+#include <openssl/hmac.h>
+
+#include "cryptutil.h"
+
+#ifndef AES_BLOCK_SIZE
+#define AES_BLOCK_SIZE 16
+#endif
+
+static unsigned char dh1536_p[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2,
+ 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+ 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6,
+ 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+ 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D,
+ 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+ 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9,
+ 0xA6, 0x37, 0xED, 0x6B, 0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+ 0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5, 0xAE, 0x9F, 0x24, 0x11,
+ 0x7C, 0x4B, 0x1F, 0xE6, 0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+ 0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05, 0x98, 0xDA, 0x48, 0x36,
+ 0x1C, 0x55, 0xD3, 0x9A, 0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+ 0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96, 0x1C, 0x62, 0xF3, 0x56,
+ 0x20, 0x85, 0x52, 0xBB, 0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+ 0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04, 0xF1, 0x74, 0x6C, 0x08,
+ 0xCA, 0x23, 0x73, 0x27, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+};
+
+static unsigned char dh1536_g[] = { 0x02 };
+
+
+int PLATFORM_GENERATE_DH_KEY_PAIR(uint8_t **priv, uint16_t *priv_len,
+ uint8_t **pub, uint16_t *pub_len)
+{
+ DH *dh;
+
+ if (priv == NULL || priv_len == NULL || pub == NULL || pub_len == NULL) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+
+ dh = DH_new();
+ if (dh == NULL) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ // Convert binary to BIGNUM format
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ BIGNUM * dhp_bn, *dhg_bn;
+
+ dhp_bn = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ dhg_bn = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+
+ if (dhp_bn == NULL || dhg_bn == NULL || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {
+ DH_free(dh);
+ BN_free(dhp_bn);
+ BN_free(dhg_bn);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+#else
+ dh->p = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ if (dh->p == NULL) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ dh->g = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+ if (dh->g == NULL) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+#endif
+ // Obtain key pair
+ //
+ if (DH_generate_key(dh) == 0) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ const BIGNUM * pv = DH_get0_priv_key(dh);
+ *priv_len = BN_num_bytes(pv);
+ *priv = (uint8_t *) malloc(sizeof(uint8_t) * (*priv_len + 1));
+ if (*priv == NULL) {
+ fprintf(stderr, "Out of memory!");
+ exit(ENOMEM);
+ }
+ BN_bn2bin(pv, *priv);
+
+ const BIGNUM *pu = DH_get0_pub_key(dh);
+ *pub_len = BN_num_bytes(pu);
+ *pub = (uint8_t *) malloc(sizeof(uint8_t) * (*pub_len + 1));
+ if (*pub == NULL) {
+ fprintf(stderr, "Out of memory!");
+ exit(ENOMEM);
+ }
+
+ BN_bn2bin(pu, *pub);
+#else
+ *priv_len = BN_num_bytes(dh->priv_key);
+ *priv = (uint8_t *) malloc(*priv_len);
+ if (*priv == NULL) {
+ fprintf(stderr, "Out of memory!");
+ exit(ENOMEM);
+ }
+
+ BN_bn2bin(dh->priv_key, *priv);
+
+ *pub_len = BN_num_bytes(dh->pub_key);
+ *pub = (uint8_t *) malloc(*pub_len);
+ if (*pub == NULL) {
+ fprintf(stderr, "Out of memory!");
+ exit(ENOMEM);
+ }
+
+ BN_bn2bin(dh->pub_key, *pub);
+#endif
+ DH_free(dh);
+ // NOTE: This internally frees "dh->p" and "dh->q", thus no need for us
+ // to do anything else.
+
+ return 0;
+}
+
+int PLATFORM_COMPUTE_DH_SHARED_SECRET(uint8_t **shared_secret,
+ uint16_t *shared_secret_len,
+ uint8_t *remote_pub,
+ uint16_t remote_pub_len,
+ uint8_t *local_priv,
+ uint8_t local_priv_len)
+{
+ BIGNUM *pub_key;
+
+ size_t rlen;
+ int keylen;
+
+ DH *dh;
+
+ if (NULL == shared_secret || NULL == shared_secret_len || NULL == remote_pub || NULL == local_priv) {
+ fprintf(stderr, "#### problem detected");
+ return 0;
+ }
+
+ dh = DH_new();
+ if (dh == NULL) {
+ fprintf(stderr, "#### problem detected");
+ return 0;
+ }
+ // Convert binary to BIGNUM format
+ //
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ BIGNUM *dhp_bn, *dhg_bn, *priv_key;
+
+ dhp_bn = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ dhg_bn = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+
+ if (dhp_bn == NULL || dhg_bn == NULL || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {
+ DH_free(dh);
+ BN_free(dhp_bn);
+ BN_free(dhg_bn);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ pub_key = BN_bin2bn(remote_pub, remote_pub_len, NULL);
+ if (pub_key == NULL) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ priv_key = BN_bin2bn(local_priv, local_priv_len, NULL);
+ if (priv_key == NULL) {
+ BN_clear_free(priv_key);
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ DH_set0_key(dh, pub_key, priv_key);
+#else
+ dh->p = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ if (dh->p == NULL) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ dh->g = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+ if (dh->g == NULL) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ pub_key = BN_bin2bn(remote_pub, remote_pub_len, NULL);
+ if (pub_key == NULL) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ dh->priv_key = BN_bin2bn(local_priv, local_priv_len, NULL);
+ if (dh->priv_key == NULL) {
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return 0;
+ }
+#endif
+ // Allocate output buffer
+ //
+ rlen = DH_size(dh);
+ *shared_secret = (uint8_t *) malloc(rlen);
+ if (*shared_secret == NULL) {
+ fprintf(stderr, "Out of memory!");
+ exit(ENOMEM);
+ }
+
+
+ // Compute the shared secret and save it in the output buffer
+ //
+ keylen = DH_compute_key(*shared_secret, pub_key, dh);
+ if (keylen < 0) {
+ *shared_secret_len = 0;
+ free(*shared_secret);
+ *shared_secret = NULL;
+ BN_clear_free(pub_key);
+ DH_free(dh);
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ } else {
+ *shared_secret_len = (uint16_t) keylen;
+ }
+
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL
+ BN_clear_free(pub_key);
+#endif
+ DH_free(dh);
+
+ return 0;
+}
+
+int PLATFORM_SHA256(size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *digest)
+{
+ int res;
+ unsigned int mac_len;
+ EVP_MD_CTX *ctx;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ ctx = EVP_MD_CTX_new();
+ if (!ctx) {
+ fprintf(stderr, "#### problem detected");
+ return 0;
+ }
+#else
+ EVP_MD_CTX ctx_aux;
+
+ ctx = &ctx_aux;
+
+ EVP_MD_CTX_init(ctx);
+#endif
+
+ res = 1;
+
+ if (!EVP_DigestInit_ex(ctx, EVP_sha256(), NULL)) {
+ res = 0;
+ }
+
+ if (res == 1) {
+ size_t i;
+
+ for (i = 0; i < num_elem; i++) {
+ if (!EVP_DigestUpdate(ctx, addr[i], len[i])) {
+ res = 0;
+ break;
+ }
+ }
+ }
+
+ if (res == 1) {
+ if (!EVP_DigestFinal(ctx, digest, &mac_len)) {
+ res = 0;
+ }
+ }
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ EVP_MD_CTX_free(ctx);
+#endif
+
+ return !res;
+}
+
+
+int PLATFORM_HMAC_SHA256(const uint8_t *key, size_t keylen, size_t num_elem,
+ const uint8_t *addr[], const size_t *len, uint8_t *hmac)
+{
+ HMAC_CTX *ctx;
+ size_t i;
+ unsigned int mdlen = 32;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ ctx = HMAC_CTX_new();
+ if (!ctx) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+#else
+ HMAC_CTX ctx_aux;
+
+ ctx = &ctx_aux;
+
+ HMAC_CTX_init(ctx);
+#endif
+
+ HMAC_Init_ex(ctx, key, keylen, EVP_sha256(), NULL);
+
+ for (i = 0; i < num_elem; i++) {
+ HMAC_Update(ctx, addr[i], len[i]);
+ }
+
+ HMAC_Final(ctx, hmac, &mdlen);
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+ HMAC_CTX_free(ctx);
+#else
+ HMAC_CTX_cleanup(ctx);
+#endif
+
+ return 0;
+}
+
+int PLATFORM_AES_ENCRYPT(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ EVP_CIPHER_CTX * ctx;
+
+ int clen, len;
+ uint8_t buf[AES_BLOCK_SIZE];
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+
+ if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+
+ clen = data_len;
+ if (EVP_EncryptUpdate(ctx, data, &clen, data, data_len) != 1 || clen != (int)data_len) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+
+ len = sizeof(buf);
+ if (EVP_EncryptFinal_ex(ctx, buf, &len) != 1 || len != 0) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_free(ctx);
+#else
+ EVP_CIPHER_CTX ctx;
+
+ int clen, len;
+ uint8_t buf[AES_BLOCK_SIZE];
+
+ EVP_CIPHER_CTX_init(&ctx);
+
+ if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ clen = data_len;
+ if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 || clen != (int)data_len) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+
+ len = sizeof(buf);
+ if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_cleanup(&ctx);
+#endif
+
+ return 0;
+}
+
+int PLATFORM_AES_DECRYPT(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ EVP_CIPHER_CTX * ctx;
+
+ int plen, len;
+ uint8_t buf[AES_BLOCK_SIZE];
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+
+ if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_set_padding(ctx, 0);
+
+ plen = data_len;
+ if (EVP_DecryptUpdate(ctx, data, &plen, data, data_len) != 1 || plen != (int)data_len) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+
+ len = sizeof(buf);
+ if (EVP_DecryptFinal_ex(ctx, buf, &len) != 1 || len != 0) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_free(ctx);
+#else
+ EVP_CIPHER_CTX ctx;
+
+ int plen, len;
+ uint8_t buf[AES_BLOCK_SIZE];
+
+ EVP_CIPHER_CTX_init(&ctx);
+
+ if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ plen = data_len;
+ if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 || plen != (int)data_len) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+
+ len = sizeof(buf);
+ if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0) {
+ fprintf(stderr, "#### problem detected");
+ return -1;
+ }
+ EVP_CIPHER_CTX_cleanup(&ctx);
+#endif
+ return 0;
+}
+
+
+
+
+#if 0
+uint8_t PLATFORM_GENERATE_DH_KEY_PAIR(uint8_t **priv, uint16_t *priv_len,
+ uint8_t **pub, uint16_t *pub_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ BIGNUM *dhp_bn, *dhg_bn;
+ const BIGNUM *pv;
+ const BIGNUM *pu;
+#endif
+ DH *dh;
+
+
+ if (!priv || !priv_len || !pub || !pub_len) {
+ fprintf(stderr, stderr, "invalid args\n");
+ return -1;
+ }
+
+ dh = DH_new();
+ if (!dh) {
+ fprintf(stderr, stderr, "-ENOMEM\n");
+ return -1;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ dhp_bn = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ dhg_bn = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+
+ if (!dhp_bn || !dhg_bn || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {
+ fprintf(stderr, stderr, "error!\n");
+ DH_free(dh);
+ BN_free(dhp_bn);
+ BN_free(dhg_bn);
+ return -1;
+ }
+#else
+ dh->p = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ if (dh->p == NULL) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+
+ dh->g = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+ if (dh->g == NULL) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+#endif
+
+ if (DH_generate_key(dh) == 0) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ pv = DH_get0_priv_key(dh);
+ *priv_len = BN_num_bytes(pv);
+ *priv = calloc(*priv_len + 1, sizeof(uint8_t));
+ if (!*priv) {
+ fprintf(stderr, stderr, "-ENOMEM\n");
+ return -1;
+ }
+
+ BN_bn2bin(pv, *priv);
+
+ pu = DH_get0_pub_key(dh);
+ *pub_len = BN_num_bytes(pu);
+ *pub = calloc(*pub_len + 1, sizeof(uint8_t));
+ if (!*pub) {
+ fprintf(stderr, stderr, "-ENOMEM\n");
+ return -1;
+ }
+
+ BN_bn2bin(pu, *pub);
+#else
+ *priv_len = BN_num_bytes(dh->priv_key);
+ *priv = malloc(*priv_len);
+ if (!*priv) {
+ fprintf(stderr, stderr, "-ENOMEM\n");
+ return -1;
+ }
+
+ BN_bn2bin(dh->priv_key, *priv);
+
+ *pub_len = BN_num_bytes(dh->pub_key);
+ *pub = malloc(*pub_len);
+ if (!*pub) {
+ fprintf(stderr, stderr, "-ENOMEM\n");
+ return -1;
+ }
+
+ BN_bn2bin(dh->pub_key, *pub);
+#endif
+
+ DH_free(dh);
+
+ return 0;
+}
+
+//void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+int PLATFORM_COMPUTE_DH_SHARED_SECRET(uint8_t **shared_secret,
+ uint16_t *shared_secret_len,
+ uint8_t *remote_pub,
+ uint16_t remote_pub_len,
+ uint8_t *local_priv,
+ uint8_t local_priv_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ BIGNUM *dhp_bn, *dhg_bn, *priv_key;
+#endif
+ BIGNUM *pub_key;
+ size_t rlen;
+ int keylen;
+ DH *dh;
+
+
+ if (!shared_secret || !shared_secret_len || !remote_pub || !local_priv) {
+ fprintf(stderr, stderr, "invalid args\n");
+ return -EINVAL;
+ }
+
+ dh = DH_new();
+ if (!dh) {
+ fprintf(stderr, stderr, "-ENOMEM\n");
+ return -1;
+ }
+
+#if OPENSSL_VERSION_NUMBER >= 0x1010000fL
+ dhp_bn = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ dhg_bn = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+
+ if (!dhp_bn || !dhg_bn || !DH_set0_pqg(dh, dhp_bn, NULL, dhg_bn)) {
+ fprintf(stderr, stderr, "error!\n");
+ DH_free(dh);
+ BN_free(dhp_bn);
+ BN_free(dhg_bn);
+ return -1;
+ }
+
+ pub_key = BN_bin2bn(remote_pub, remote_pub_len, NULL);
+ if (pub_key == NULL) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+
+ priv_key = BN_bin2bn(local_priv, local_priv_len, NULL);
+ if (priv_key == NULL) {
+ BN_clear_free(priv_key);
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+
+ DH_set0_key(dh, pub_key, priv_key);
+#else
+ dh->p = BN_bin2bn(dh1536_p, sizeof(dh1536_p), NULL);
+ if (dh->p == NULL) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+
+ dh->g = BN_bin2bn(dh1536_g, sizeof(dh1536_g), NULL);
+ if (dh->g == NULL) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+ pub_key = BN_bin2bn(remote_pub, remote_pub_len, NULL);
+ if (pub_key == NULL) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+ dh->priv_key = BN_bin2bn(local_priv, local_priv_len, NULL);
+ if (dh->priv_key == NULL) {
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ }
+#endif
+ rlen = DH_size(dh);
+
+ *shared_secret = calloc(rlen, sizeof(uint8_t));
+ if (!*shared_secret) {
+ fprintf(stderr, stderr, "-ENOMEM\n");
+ return -1;
+ }
+
+ keylen = DH_compute_key(*shared_secret, pub_key, dh);
+ if (keylen < 0) {
+ *shared_secret_len = 0;
+ free(*shared_secret);
+ *shared_secret = NULL;
+ BN_clear_free(pub_key);
+ DH_free(dh);
+ fprintf(stderr, stderr, "error!\n");
+ return -1;
+ } else {
+ *shared_secret_len = (uint16_t)keylen;
+ }
+
+#if OPENSSL_VERSION_NUMBER < 0x1010000fL
+ BN_clear_free(pub_key);
+#endif
+ DH_free(dh);
+
+ return 0;
+}
+
+static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
+ const uint8_t *addr[], const size_t *len,
+ uint8_t *mac)
+{
+ EVP_MD_CTX *ctx;
+ size_t i;
+ unsigned int mac_len;
+
+
+
+ ctx = EVP_MD_CTX_new();
+ if (!ctx)
+ return -1;
+ if (!EVP_DigestInit_ex(ctx, type, NULL)) {
+ fprintf(stderr, stderr, "OpenSSL: EVP_DigestInit_ex failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
+ return -1;
+ }
+ for (i = 0; i < num_elem; i++) {
+ if (!EVP_DigestUpdate(ctx, addr[i], len[i])) {
+ fprintf(stderr, stderr, "OpenSSL: EVP_DigestUpdate failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
+ return -1;
+ }
+ }
+ if (!EVP_DigestFinal(ctx, mac, &mac_len)) {
+ fprintf(stderr, stderr, "OpenSSL: EVP_DigestFinal failed: %s",
+ ERR_error_string(ERR_get_error(), NULL));
+ EVP_MD_CTX_free(ctx);
+ return -1;
+ }
+ EVP_MD_CTX_free(ctx);
+
+ return 0;
+}
+
+//int sha256_vector(size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *mac)
+int PLATFORM_SHA256(size_t num_elem, const uint8_t *addr[], const size_t *len, uint8_t *mac)
+{
+
+ return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
+}
+
+static int openssl_hmac_vector(const EVP_MD *type, const uint8_t *key,
+ size_t key_len, size_t num_elem,
+ const uint8_t *addr[], const size_t *len,
+ uint8_t *mac, unsigned int mdlen)
+{
+ HMAC_CTX *ctx;
+ size_t i;
+ int res;
+
+ ctx = HMAC_CTX_new();
+ if (!ctx)
+ return -1;
+ res = HMAC_Init_ex(ctx, key, key_len, type, NULL);
+ if (res != 1)
+ goto done;
+
+ for (i = 0; i < num_elem; i++)
+ HMAC_Update(ctx, addr[i], len[i]);
+
+ res = HMAC_Final(ctx, mac, &mdlen);
+done:
+ HMAC_CTX_free(ctx);
+
+ return res == 1 ? 0 : -1;
+}
+
+//int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+int PLATFORM_HMAC_SHA256(const uint8_t *key, size_t key_len, size_t num_elem,
+ const uint8_t *addr[], const size_t *len, uint8_t *mac)
+{
+
+ return openssl_hmac_vector(EVP_sha256(), key, key_len, num_elem, addr,
+ len, mac, 32);
+
+}
+
+//int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+int PLATFORM_AES_ENCRYPT(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len)
+{
+ EVP_CIPHER_CTX *ctx;
+ uint8_t buf[16];
+ int clen, len;
+ int res = -1;
+
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
+ clen = data_len;
+ len = sizeof(buf);
+ if (EVP_EncryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_EncryptUpdate(ctx, data, &clen, data, data_len) == 1 &&
+ clen == (int) data_len &&
+ EVP_EncryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+ res = 0;
+ EVP_CIPHER_CTX_free(ctx);
+
+ return res;
+}
+
+//int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+int PLATFORM_AES_DECRYPT(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len)
+{
+ EVP_CIPHER_CTX *ctx;
+ uint8_t buf[16];
+ int plen, len;
+ int res = -1;
+
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (!ctx)
+ return -1;
+ plen = data_len;
+ len = sizeof(buf);
+ if (EVP_DecryptInit_ex(ctx, EVP_aes_128_cbc(), NULL, key, iv) == 1 &&
+ EVP_CIPHER_CTX_set_padding(ctx, 0) == 1 &&
+ EVP_DecryptUpdate(ctx, data, &plen, data, data_len) == 1 &&
+ plen == (int) data_len &&
+ EVP_DecryptFinal_ex(ctx, buf, &len) == 1 && len == 0)
+ res = 0;
+ EVP_CIPHER_CTX_free(ctx);
+
+ return res;
+}
+#endif // 0
diff --git a/src/cryptutil.h b/src/cryptutil.h
new file mode 100644
index 00000000..c24449c2
--- /dev/null
+++ b/src/cryptutil.h
@@ -0,0 +1,34 @@
+
+
+#ifndef CRYPT_UTIL_H
+#define CRYPT_UTIL_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+
+int PLATFORM_GENERATE_DH_KEY_PAIR(uint8_t **priv, uint16_t *priv_len,
+ uint8_t **pub, uint16_t *pub_len);
+
+int PLATFORM_COMPUTE_DH_SHARED_SECRET(uint8_t **shared_secret,
+ uint16_t *shared_secret_len,
+ uint8_t *remote_pub,
+ uint16_t remote_pub_len,
+ uint8_t *local_priv,
+ uint8_t local_priv_len);
+
+
+int PLATFORM_SHA256(size_t num_elem, const uint8_t *addr[], const size_t *len,
+ uint8_t *mac);
+
+
+
+int PLATFORM_HMAC_SHA256(const uint8_t *key, size_t key_len, size_t num_elem,
+ const uint8_t *addr[], const size_t *len, uint8_t *mac);
+
+
+int PLATFORM_AES_ENCRYPT(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len);
+int PLATFORM_AES_DECRYPT(uint8_t *key, uint8_t *iv, uint8_t *data, uint32_t data_len);
+
+
+#endif /* CRYPT_UTIL_H */
diff --git a/src/i1905.c b/src/i1905.c
index 47a1d4c3..f0feb2c8 100644
--- a/src/i1905.c
+++ b/src/i1905.c
@@ -712,6 +712,55 @@ static int i1905_destroy_al_interface(struct i1905_private *p)
return 0;
}
+static int i1905_init_interface_private_wsc(struct i1905_interface *n)
+{
+ struct i1905_interface_private *p =
+ (struct i1905_interface_private *)n->priv;
+ struct i1905_interface_private_wsc *wsc;
+ struct i1905_private *priv= (struct i1905_private *)p->i1905private;
+
+
+ wsc = calloc(1, sizeof(*wsc));
+ if (!wsc) {
+ fprintf(stderr, "%s: -ENOMEM\n", __func__);
+ return -ENOMEM;
+ }
+
+ p->wsc = wsc;
+
+ //TODO: get real data -
+ // auth_type, enc_type
+
+ //wifi_get_wps_device_info(n->ifname, struct wps_device *info)
+
+
+
+ snprintf(wsc->manufacturer, 64, "Unknown");
+ snprintf(wsc->device_name, 32, "Unknown");
+ snprintf(wsc->model_name, 32, "Unknown");
+ wsc->os_version = 0x00000001;
+
+ if (IS_MEDIA_WIFI_2GHZ(n->media)) {
+ p->wsc->band = WPS_RF_24GHZ;
+
+ if (priv->cfg.registrar_2g)
+ p->registrar = true;
+ }
+
+ if (IS_MEDIA_WIFI_5GHZ(n->media)) {
+ p->wsc->band |= WPS_RF_50GHZ;
+
+ if (priv->cfg.registrar_5g)
+ p->registrar = true;
+ }
+
+
+ // TODO: get 'enum wps_state' and decide
+ p->configured = false;
+
+ return 0;
+}
+
static int i1905_setup_interface_priv(struct i1905_interface *n)
{
struct i1905_interface_private *p =
@@ -732,6 +781,9 @@ static int i1905_setup_interface_priv(struct i1905_interface *n)
cmdu_ackq_init(&p->txack_q);
+ if (IS_MEDIA_WIFI(n->media))
+ i1905_init_interface_private_wsc(n);
+
i1905_init_interface_socket_1905(n, p);
i1905_init_interface_socket_lldp(n, p);
@@ -1073,6 +1125,25 @@ void topology_timer_cb(atimer_t *t)
timer_set(t, 60000);
}
+bool i1905_has_registrar(void *priv, uint8_t freqband)
+{
+ struct i1905_private *p = priv;
+
+ if (!p)
+ return false;
+
+ switch (freqband) {
+ case IEEE80211_FREQUENCY_BAND_2_4_GHZ:
+ return p->cfg.registrar_2g;
+ case IEEE80211_FREQUENCY_BAND_5_GHZ:
+ return p->cfg.registrar_5g;
+ case IEEE80211_FREQUENCY_BAND_60_GHZ:
+ default:
+ break;
+ }
+
+ return false;
+}
int i1905_init(void **priv, void *cfg)
{
diff --git a/src/i1905.h b/src/i1905.h
index 77a52292..90272fbb 100644
--- a/src/i1905.h
+++ b/src/i1905.h
@@ -4,6 +4,7 @@
#define I1905_H
+#include "i1905_wsc.h"
#define OBJECT_INVALID ((uint32_t)-1)
@@ -26,6 +27,30 @@ struct i1905_private {
};
+struct i1905_interface_private_wsc {
+ union {
+ enum { SEND_M1, RECV_M2 } e;
+ enum { RECV_M1, SEND_M2 } r;
+ } state;
+
+ uint8_t uuid[16];
+ char manufacturer[65]; /* with terminating '\0' */
+ char model_name[33];
+ char device_name[33];
+ uint8_t model_number[32];
+ uint8_t serial_number[32];
+ uint32_t os_version;
+ uint8_t macaddr[6];
+ uint8_t band;
+ uint16_t auth_types;
+ uint16_t enc_types;
+ //uint8_t nonce[WPS_NONCE_LEN]; //TODO
+ uint8_t *last_msg;
+ uint16_t last_msglen;
+ void *key;
+ struct wps_credential cred;
+};
+
struct i1905_interface_private {
int sock_1905;
int sock_lldp;
@@ -38,6 +63,10 @@ struct i1905_interface_private {
struct cmdu_ackq txack_q;
void *i1905private;
+ bool registrar;
+ bool configured; // XXX
+ struct i1905_interface_private_wsc *wsc;
+
void *iface; /* points to i1905_interface */
struct ubus_object obj;
struct ubus_object_type obj_type;
@@ -67,6 +96,8 @@ int i1905_start();
int i1905_stop(struct i1905_private *p);
int i1905_reconfig(struct i1905_config *cfg, const char *conffile);
+bool i1905_has_registrar(void *priv, uint8_t freqband);
+
int i1905_cmdu_tx(struct i1905_interface_private *ifp,
uint8_t *dst, uint8_t *src, uint16_t type,
uint16_t *mid, uint8_t *data, int datalen);
diff --git a/src/i1905_dm.h b/src/i1905_dm.h
index 26d4c5a8..c8a9dbd4 100644
--- a/src/i1905_dm.h
+++ b/src/i1905_dm.h
@@ -137,6 +137,18 @@ enum i1905_mediatype {
#define IS_MEDIA_WIFI(m) \
((m) >= I1905_802_11B_2_4_GHZ && (m) <= I1905_802_11AX)
+
+#define IS_MEDIA_WIFI_5GHZ(m) \
+ ((m) == I1905_802_11A_5_GHZ || \
+ (m) == I1905_802_11N_5_GHZ || \
+ (m) == I1905_802_11AC_5_GHZ)
+
+#define IS_MEDIA_WIFI_2GHZ(m) \
+ ((m) == I1905_802_11B_2_4_GHZ || \
+ (m) == I1905_802_11G_2_4_GHZ || \
+ (m) == I1905_802_11N_2_4_GHZ)
+
+
struct i1905_fwdrule {
struct list_head iflist; /* list of ifnames/macaddres FIXME */
uint32_t mask; /* bitmap of I1905_FWDRULE_* */
diff --git a/src/i1905_wsc.c b/src/i1905_wsc.c
new file mode 100644
index 00000000..bf8d0d13
--- /dev/null
+++ b/src/i1905_wsc.c
@@ -0,0 +1,1252 @@
+
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include "util.h"
+#include "bufutil.h"
+
+#include "cryptutil.h"
+#include "i1905_wsc.h"
+
+struct wsc_key {
+ uint8_t *key;
+ uint32_t keylen;
+ uint8_t nonce[16];
+ uint8_t macaddr[6];
+};
+
+
+#if 0
+struct wsc_context {
+ union {
+ enum { SEND_M1, RECV_M2 } e;
+ enum { RECV_M1, SEND_M2 } r;
+ } state;
+
+ uint8_t uuid[16];
+ uint8_t macaddr[6];
+ uint8_t nonce[16];
+
+ uint8_t *last_msg;
+ uint8_t *last_msglen;
+};
+#endif
+
+#if 0
+struct mdata {
+ union {
+ struct input {
+ uint8_t ssid[64];
+ uint8_t network_key[64];
+ uint16_t auth_types;
+ uint16_t enc_types;
+ uint8_t macaddr[6];
+ uint8_t band;
+ uint8_t mapie;
+ } input;
+
+ struct output {
+ uint8_t ssid[64];
+ uint8_t network_key[64];
+ uint16_t auth_types;
+ uint16_t enc_types;
+ uint8_t mapie;
+ uint8_t bssid[6];
+ uint8_t band;
+ } output;
+ };
+};
+#endif
+
+
+#define bufptr_put_u8(b, v) \
+do { \
+ *b = (uint8_t)v; \
+ b += 1; \
+} while(0)
+
+
+#define bufptr_put_be16(_b, v) \
+do { \
+ buf_put_be16(_b, v); \
+ _b += 2; \
+} while(0)
+
+
+#define bufptr_put_be32(_b, v) \
+do { \
+ buf_put_be32(_b, v); \
+ _b += 4; \
+} while(0)
+
+
+#define bufptr_put(b, v, s) \
+do { \
+ memcpy(b, v, s); \
+ b += s; \
+} while(0)
+
+
+#define bufptr_get(b, v, s) \
+do { \
+ memcpy(v, b, s); \
+ b += s; \
+} while(0)
+
+
+
+#define AES_BLOCK_SIZE 16
+#define SHA256_MAC_LEN 32
+
+#define WPS_AUTHKEY_LEN 32
+#define WPS_KEYWRAPKEY_LEN 16
+#define WPS_EMSK_LEN 32
+
+void wps_kdf(const uint8_t *key, const uint8_t *label_prefix,
+ size_t label_prefix_len, const char *label, uint8_t *res,
+ size_t res_len)
+{
+
+ uint8_t i_buf[4], key_bits[4];
+ const uint8_t *addr[4];
+ size_t len[4];
+ int i, iter;
+ uint8_t hash[SHA256_MAC_LEN], *opos;
+ size_t left;
+
+ buf_put_be32(key_bits, res_len * 8);
+
+ addr[0] = i_buf;
+ len[0] = sizeof(i_buf);
+ addr[1] = label_prefix;
+ len[1] = label_prefix_len;
+ addr[2] = (const uint8_t *) label;
+ len[2] = strlen(label);
+ addr[3] = key_bits;
+ len[3] = sizeof(key_bits);
+
+ iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
+ opos = res;
+ left = res_len;
+
+ for (i = 1; i <= iter; i++) {
+ buf_put_be32(i_buf, i);
+ PLATFORM_HMAC_SHA256(key, SHA256_MAC_LEN, 4, addr, len, hash);
+ if (i < iter) {
+ memcpy(opos, hash, SHA256_MAC_LEN);
+ opos += SHA256_MAC_LEN;
+ left -= SHA256_MAC_LEN;
+ } else
+ memcpy(opos, hash, left);
+ }
+}
+
+uint8_t wsc_get_message_type(uint8_t *m, uint16_t m_size)
+{
+ uint8_t *p = m;
+
+ while (abs(p - m) < m_size) {
+ uint16_t attr_type;
+ uint16_t attr_len;
+ uint8_t msg_type;
+
+ attr_type = buf_get_be16(p);
+ p += 2;
+ attr_len = buf_get_be16(p);
+ p += 2;
+
+
+ switch (attr_type) {
+ case ATTR_MSG_TYPE:
+ if (attr_len != 1) {
+ fprintf(stderr,
+ "Incorrect length (%d) for ATTR_MSG_TYPE\n", attr_len);
+ return -EINVAL;
+ }
+ bufptr_get(p, &msg_type, 1);
+ return msg_type;
+ default:
+ break;
+ }
+
+ p += attr_len;
+ }
+
+ return 0xff;
+}
+
+int wsc_build_m1(const char *ifname, uint8_t **m1, uint16_t *m1_size, void **key,
+ struct wps_data *in)
+{
+ uint8_t oui[4] = { 0x00, 0x50, 0xf2, 0x00 };
+ const char *serial_number = "00000000";
+ const char *model_number = "00000000";
+ const char *uuid = "0000000000000000";
+ const char *manufacturer = "Unknown";
+ const char *device_name = "Unknown";
+ const char *model = "Unknown";
+ uint32_t os_version = 0x00000001;
+ struct wsc_key *private_key;
+ uint8_t nonce_e[16];
+ uint8_t *buf;
+ uint8_t *p;
+
+
+ //TODO: pass m1 and key buffer and use them.
+
+ if (!ifname || !m1 || !m1_size || !key || !in) {
+ fprintf(stderr, "%s(): invalid args!\n", __func__);
+ return -EINVAL;
+ }
+
+ buf = calloc(1000, sizeof(uint8_t));
+ if (!buf)
+ return -ENOMEM;
+
+ p = buf;
+
+ /* version */
+ bufptr_put_be16(p, ATTR_VERSION);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, 0x10);
+
+
+ /* message type */
+ bufptr_put_be16(p, ATTR_MSG_TYPE);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, WPS_M1);
+
+
+ /* uuid-e */
+ bufptr_put_be16(p, ATTR_UUID_E);
+ bufptr_put_be16(p, 16);
+ bufptr_put(p, uuid, 16);
+
+
+ /* macaddress */
+ bufptr_put_be16(p, ATTR_MAC_ADDR);
+ bufptr_put_be16(p, 6);
+ bufptr_put(p, in->macaddr, 6);
+
+
+ /* enrollee nonce */
+ get_random_bytes(16, nonce_e);
+ bufptr_put_be16(p, ATTR_ENROLLEE_NONCE);
+ bufptr_put_be16(p, 16);
+ bufptr_put(p, nonce_e, 16);
+
+
+ /* public key */
+ uint8_t *priv, *pub;
+ uint16_t priv_len = 0, pub_len = 0;
+
+ PLATFORM_GENERATE_DH_KEY_PAIR(&priv, &priv_len, &pub, &pub_len);
+ fprintf(stderr, "M1 plen|%d| publen|%d|\n", priv_len, pub_len);
+
+ bufptr_put_be16(p, ATTR_PUBLIC_KEY);
+ bufptr_put_be16(p, pub_len);
+ bufptr_put(p, pub, pub_len);
+
+ private_key = calloc(1, sizeof(*private_key));
+ if (!private_key) {
+ fprintf(stderr, "-ENOMEM\n");
+ return -ENOMEM;
+ }
+
+ private_key->key = calloc(priv_len, sizeof(uint8_t));
+ if (!private_key->key) {
+ free(private_key);
+ fprintf(stderr, "-ENOMEM\n");
+ return -ENOMEM;
+ }
+ private_key->keylen = priv_len;
+ if (priv_len > 0)
+ memcpy(private_key->key, priv, priv_len);
+
+ memcpy(private_key->macaddr, in->macaddr, 6);
+ memcpy(private_key->nonce, nonce_e, 16);
+ free(pub);
+ free(priv);
+
+ /* authentication type flags */
+ bufptr_put_be16(p, ATTR_AUTH_TYPE_FLAGS);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, in->auth_types);
+
+
+ /* encryption type flags */
+ bufptr_put_be16(p, ATTR_ENCR_TYPE_FLAGS);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, in->enc_types);
+
+
+ /* connection type flags */
+ bufptr_put_be16(p, ATTR_CONN_TYPE_FLAGS);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, WPS_CONN_ESS);
+
+
+ /* configuration methods */
+ bufptr_put_be16(p, ATTR_CONFIG_METHODS);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, WPS_CONFIG_PHY_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON);
+
+
+ /* wps state */
+ bufptr_put_be16(p, ATTR_WPS_STATE);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, WPS_STATE_NOT_CONFIGURED);
+
+
+ /* manufacturer */
+ bufptr_put_be16(p, ATTR_MANUFACTURER);
+ bufptr_put_be16(p, strlen(manufacturer));
+ bufptr_put(p, manufacturer, strlen(manufacturer));
+
+
+ /* model name */
+ bufptr_put_be16(p, ATTR_MODEL_NAME);
+ bufptr_put_be16(p, strlen(model));
+ bufptr_put(p, model, strlen(model));
+
+
+ /* model number */
+ bufptr_put_be16(p, ATTR_MODEL_NUMBER);
+ bufptr_put_be16(p, strlen(model_number));
+ bufptr_put(p, model_number, strlen(model_number));
+
+
+ /* serial number */
+ bufptr_put_be16(p, ATTR_SERIAL_NUMBER);
+ bufptr_put_be16(p, strlen(serial_number));
+ bufptr_put(p, serial_number, strlen(serial_number));
+
+
+ /* primary device type */
+ bufptr_put_be16(p, ATTR_PRIMARY_DEV_TYPE);
+ bufptr_put_be16(p, 8);
+ bufptr_put_be16(p, WPS_DEV_NETWORK_INFRA);
+ bufptr_put(p, oui, 4);
+ bufptr_put_be16(p, WPS_DEV_NETWORK_INFRA_ROUTER);
+
+
+ /* device name */
+ bufptr_put_be16(p, ATTR_DEV_NAME);
+ bufptr_put_be16(p, strlen(device_name));
+ bufptr_put(p, device_name, strlen(device_name));
+
+
+ /* rf bands */
+ bufptr_put_be16(p, ATTR_RF_BANDS);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, in->band);
+
+
+ /* association state */
+ bufptr_put_be16(p, ATTR_ASSOC_STATE);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, WPS_ASSOC_NOT_ASSOC);
+
+
+ /* device password id */
+ bufptr_put_be16(p, ATTR_DEV_PASSWORD_ID);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, DEV_PW_PUSHBUTTON);
+
+
+ /* config error */
+ bufptr_put_be16(p, ATTR_CONFIG_ERROR);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, WPS_CFG_NO_ERROR);
+
+
+ /* os version */
+ bufptr_put_be16(p, ATTR_OS_VERSION);
+ bufptr_put_be16(p, 4);
+ bufptr_put_be32(p, 0x80000000 | os_version);
+
+
+ /* version2 - vendor extension */
+ bufptr_put_be16(p, ATTR_VENDOR_EXTENSION);
+ bufptr_put_be16(p, 6);
+ bufptr_put_be16(p, WPS_CFG_NO_ERROR);
+ bufptr_put_u8(p, WFA_VENDOR_ID_1);
+ bufptr_put_u8(p, WFA_VENDOR_ID_2);
+ bufptr_put_u8(p, WFA_VENDOR_ID_3);
+ bufptr_put_u8(p, WFA_ELEM_VERSION2);
+ bufptr_put_u8(p, 1);
+ bufptr_put_u8(p, WPS_VERSION);
+
+
+ *m1 = buf;
+ *m1_size = abs(p - buf);
+ *key = private_key;
+
+ return 0;
+}
+
+int wsc_build_m2(uint8_t *m1, uint16_t m1_size, uint8_t **m2, uint16_t *m2_size,
+ /* struct wps_data *in, */ struct wps_credential *cred)
+{
+ uint8_t *buffer;
+ uint8_t *p;
+
+ int i;
+
+ uint8_t *m1_macaddr = NULL;
+ uint8_t m1_macaddr_present = 0;
+ uint8_t *m1_nonce = NULL;
+ uint8_t m1_nonce_present = 0;
+ uint8_t *m1_pubkey = NULL;
+ uint8_t m1_pubkey_present = 0;
+ uint16_t m1_pubkey_len = 0;
+ uint8_t m1_rf_band = WPS_RF_24GHZ; // TODO: wsc_process_m1() at registrar
+
+ uint8_t *local_privkey;
+ uint16_t local_privkey_len;
+
+ uint8_t authkey[WPS_AUTHKEY_LEN];
+ uint8_t keywrapkey[WPS_KEYWRAPKEY_LEN];
+ uint8_t emsk[WPS_EMSK_LEN];
+
+ uint8_t uuid[16] = {0};
+ uint8_t nonce_r[16];
+ //uint8_t m2_mac[6] = {0};
+
+ uint8_t oui[4] = { 0x00, 0x50, 0xf2, 0x00 };
+ const char *manufacturer = "Unknown";
+ const char *serial_number = "00000000";
+ const char *model_number = "00000000";
+ const char *device_name = "Unknown";
+ uint32_t os_version = 0x00000001;
+ const char *model = "Unknown";
+ //uint16_t auth_types;
+
+
+
+ p = m1;
+
+ if (!cred) {
+ fprintf(stderr, "%s: cred = NULL\n", __func__);
+ return -EINVAL;
+ }
+
+ //if (cred && cred->macaddr)
+ //memcpy(m2_mac, cred->macaddr, 6);
+
+ while (abs(p - m1) < m1_size) {
+ uint16_t attr_type;
+ uint16_t attr_len;
+
+ attr_type = buf_get_be16(p);
+ p += 2;
+ attr_len = buf_get_be16(p);
+ p += 2;
+
+
+ switch (attr_type) {
+ case ATTR_MAC_ADDR:
+ if (attr_len != 6) {
+ fprintf(stderr, "Incorrect length (%d) for ATTR_MAC_ADDR\n", attr_len);
+ return -EINVAL;
+ }
+ m1_macaddr = p;
+ m1_macaddr_present = 1;
+ break;
+ case ATTR_ENROLLEE_NONCE:
+ if (attr_len != 16) {
+ fprintf(stderr, "Incorrect length (%d) for ATTR_ENROLLEE_NONCE\n", attr_len);
+ return -EINVAL;
+ }
+ m1_nonce = p;
+ m1_nonce_present = 1;
+ break;
+ case ATTR_PUBLIC_KEY:
+ m1_pubkey_len = attr_len;
+ m1_pubkey = p;
+ m1_pubkey_present = 1;
+ break;
+ case ATTR_RF_BANDS:
+ m1_rf_band = *p;
+ break;
+ default:
+ break;
+ }
+
+ p += attr_len;
+ }
+
+ if (!m1_pubkey_present || !m1_nonce_present || !m1_macaddr_present ||
+ !m1_rf_band) {
+
+ fprintf(stderr, "Required attr in M1 not present!\n");
+ return -1;
+ }
+
+ buffer = calloc(1000, sizeof(uint8_t));
+ if (!buffer) {
+ fprintf(stderr, "-ENOMEM\n");
+ return -ENOMEM;
+ }
+
+ p = buffer;
+
+ /* version */
+ bufptr_put_be16(p, ATTR_VERSION);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, 0x10);
+
+ /* message type */
+ bufptr_put_be16(p, ATTR_MSG_TYPE);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, WPS_M2);
+
+ /* enrollee nonce */
+ bufptr_put_be16(p, ATTR_ENROLLEE_NONCE);
+ bufptr_put_be16(p, 16);
+ bufptr_put(p, m1_nonce, 16);
+
+ /* registrar nonce */
+ get_random_bytes(16, nonce_r);
+ bufptr_put_be16(p, ATTR_REGISTRAR_NONCE);
+ bufptr_put_be16(p, 16);
+ bufptr_put(p, nonce_r, 16);
+
+ /* uuid-r */
+ bufptr_put_be16(p, ATTR_UUID_R);
+ bufptr_put_be16(p, 16);
+ bufptr_put(p, uuid, 16);
+
+
+ /* public key */
+ {
+ uint8_t *priv, *pub;
+ uint16_t priv_len = 0, pub_len = 0;
+
+ PLATFORM_GENERATE_DH_KEY_PAIR(&priv, &priv_len, &pub, &pub_len);
+ fprintf(stderr, "plen|%d|, publen|%d|\n", priv_len, pub_len);
+
+ bufptr_put_be16(p, ATTR_PUBLIC_KEY);
+ bufptr_put_be16(p, pub_len);
+ bufptr_put(p, pub, pub_len);
+
+ // We will use it later... save it.
+ local_privkey = priv;
+ local_privkey_len = priv_len;
+ free(pub);
+ }
+
+ /* derive keys - authkey, keywrapkey and emsk */
+ {
+ uint8_t *shared_secret;
+ uint16_t shared_secret_len;
+ const uint8_t *addr[3];
+ size_t len[3];
+ uint8_t dhkey[SHA256_MAC_LEN];
+ uint8_t kdk[SHA256_MAC_LEN];
+ uint8_t keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
+
+ /* DH shared secret = enrollee's public key from M1 + private
+ * key (generated above).
+ *
+ * The enrollee after receiving M2, will obtain the same DH shared
+ * secret using its private key and our public key (sent in M2).
+ */
+ PLATFORM_COMPUTE_DH_SHARED_SECRET(&shared_secret,
+ &shared_secret_len,
+ m1_pubkey,
+ m1_pubkey_len,
+ local_privkey,
+ local_privkey_len);
+
+ /* dhkey = SHA-256 digest of the DH shared secret. */
+ addr[0] = shared_secret;
+ len[0] = shared_secret_len;
+
+ PLATFORM_SHA256(1, addr, len, dhkey);
+
+ /* Derive KDK -
+ *
+ * KDK = HMAC-SHA-256_DHKey (N1 || EnrolleeMAC || N2), where
+ * N1 is enrollee's nonce from M1,
+ * N2 is registrar's nonce generated above.
+ *
+ */
+
+ /* Compute HMAC of the following using 'dhkey' -
+ * the enrollee's nonce from M1,
+ * the enrolle MAC address from M1, and
+ * the our nonce generated above.
+ */
+ addr[0] = m1_nonce;
+ addr[1] = m1_macaddr;
+ addr[2] = nonce_r;
+ len[0] = 16;
+ len[1] = 6;
+ len[2] = 16;
+
+ PLATFORM_HMAC_SHA256(dhkey, SHA256_MAC_LEN, 3, addr, len, kdk);
+
+ wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
+ keys, sizeof(keys));
+
+ memcpy(authkey, keys, WPS_AUTHKEY_LEN);
+ memcpy(keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
+ memcpy(emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, WPS_EMSK_LEN);
+
+ fprintf(stderr, "WPS keys: \n");
+ bufprintf(m1_pubkey, m1_pubkey_len, "Enrollee public key");
+ /* bufprintf(local_privkey, local_privkey_len, "Registrar private key"); */
+ /* bufprintf(shared_secret, shared_secret_len, "DH Shared secret"); */
+ bufprintf(dhkey, 32, "DH Key");
+ bufprintf(m1_nonce, 16, "Nonce-E");
+ bufprintf(nonce_r, 16, "Nonce-R");
+ bufprintf(kdk, 32, "KDK");
+ bufprintf(authkey, WPS_AUTHKEY_LEN, "WPS authkey");
+ bufprintf(keywrapkey, WPS_KEYWRAPKEY_LEN, "WPS keywrapkey");
+ bufprintf(emsk, WPS_EMSK_LEN, "WPS emsk");
+
+ free(shared_secret);
+ }
+
+
+ /* authentication type flags */
+ bufptr_put_be16(p, ATTR_AUTH_TYPE_FLAGS);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, cred->auth_type);
+
+ /* encryption type flags */
+ bufptr_put_be16(p, ATTR_ENCR_TYPE_FLAGS);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, cred->enc_type);
+
+ /* connection types */
+ bufptr_put_be16(p, ATTR_CONN_TYPE_FLAGS);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, WPS_CONN_ESS);
+
+ /* configuration methods */
+ bufptr_put_be16(p, ATTR_CONFIG_METHODS);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, WPS_CONFIG_PHY_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON);
+
+ /* manufacturer */
+ bufptr_put_be16(p, ATTR_MANUFACTURER);
+ bufptr_put_be16(p, strlen(manufacturer));
+ bufptr_put(p, manufacturer, strlen(manufacturer));
+
+ /* model name */
+ bufptr_put_be16(p, ATTR_MODEL_NAME);
+ bufptr_put_be16(p, strlen(model));
+ bufptr_put(p, model, strlen(model));
+
+ /* model number */
+ bufptr_put_be16(p, ATTR_MODEL_NUMBER);
+ bufptr_put_be16(p, strlen(model_number));
+ bufptr_put(p, model_number, strlen(model_number));
+
+ /* serial number */
+ bufptr_put_be16(p, ATTR_SERIAL_NUMBER);
+ bufptr_put_be16(p, strlen(serial_number));
+ bufptr_put(p, serial_number, strlen(serial_number));
+
+ /* primary device type */
+ bufptr_put_be16(p, ATTR_PRIMARY_DEV_TYPE);
+ bufptr_put_be16(p, 8);
+ bufptr_put_be16(p, WPS_DEV_NETWORK_INFRA);
+ bufptr_put(p, oui, 4);
+ bufptr_put_be16(p, WPS_DEV_NETWORK_INFRA_ROUTER);
+
+ /* device name */
+ bufptr_put_be16(p, ATTR_DEV_NAME);
+ bufptr_put_be16(p, strlen(device_name));
+ bufptr_put(p, device_name, strlen(device_name));
+
+ /* rf bands */
+ bufptr_put_be16(p, ATTR_RF_BANDS);
+ bufptr_put_be16(p, 1);
+ bufptr_put_u8(p, cred->band);
+
+ /* association state */
+ bufptr_put_be16(p, ATTR_ASSOC_STATE);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, WPS_ASSOC_CONN_SUCCESS);
+
+ /* configuration error */
+ bufptr_put_be16(p, ATTR_CONFIG_ERROR);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, WPS_CFG_NO_ERROR);
+
+ /* device password id */
+ bufptr_put_be16(p, ATTR_DEV_PASSWORD_ID);
+ bufptr_put_be16(p, 2);
+ bufptr_put_be16(p, DEV_PW_PUSHBUTTON);
+
+ /* os version */
+ bufptr_put_be16(p, ATTR_OS_VERSION);
+ bufptr_put_be16(p, 4);
+ bufptr_put_be32(p, 0x80000000 | os_version);
+
+ /* version2 - inside vendor extension */
+ bufptr_put_be16(p, ATTR_VENDOR_EXTENSION);
+ bufptr_put_be16(p, 6);
+ bufptr_put_u8(p, WFA_VENDOR_ID_1);
+ bufptr_put_u8(p, WFA_VENDOR_ID_2);
+ bufptr_put_u8(p, WFA_VENDOR_ID_3);
+ bufptr_put_u8(p, WFA_ELEM_VERSION2);
+ bufptr_put_u8(p, 1);
+ bufptr_put_u8(p, WPS_VERSION);
+
+
+ /* encrypted settings */
+ {
+ //char *ssid;
+ //char *key;
+ //int ssidlen, keylen;
+
+ uint8_t plain[200];
+ uint8_t hash[SHA256_MAC_LEN];
+ uint8_t *iv_start;
+ uint8_t *data_start;
+ uint8_t num_pad_bytes;
+ uint8_t *r;
+
+ const uint8_t *addr[1];
+ size_t len[1];
+
+ //ssid = (char *)cred->ssid;
+ //key = (char *)cred->key;
+ //ssidlen = strlen(ssid); // FIXME
+ //keylen = strlen(key);
+
+ r = plain;
+
+ /* ssid */
+ bufptr_put_be16(r, ATTR_SSID);
+ bufptr_put_be16(r, cred->ssidlen);
+ bufptr_put(r, cred->ssid, cred->ssidlen);
+
+ /* auth type */
+ bufptr_put_be16(r, ATTR_AUTH_TYPE);
+ bufptr_put_be16(r, 2);
+ bufptr_put_be16(r, cred->auth_type);
+
+ /* encryption type */
+ bufptr_put_be16(r, ATTR_ENCR_TYPE);
+ bufptr_put_be16(r, 2);
+ bufptr_put_be16(r, cred->enc_type);
+
+ /* key */
+ bufptr_put_be16(r, ATTR_NETWORK_KEY);
+ bufptr_put_be16(r, cred->keylen);
+ bufptr_put(r, cred->key, cred->keylen);
+
+ /* macaddr */
+ bufptr_put_be16(r, ATTR_MAC_ADDR);
+ bufptr_put_be16(r, 6);
+ bufptr_put(r, cred->macaddr, 6);
+
+
+ /* Version2 - vendor extension */ //TODO: revisit mapie
+ bufptr_put_be16(r, ATTR_VENDOR_EXTENSION);
+ bufptr_put_be16(r, 9);
+ bufptr_put_u8(r, WFA_VENDOR_ID_1);
+ bufptr_put_u8(r, WFA_VENDOR_ID_2);
+ bufptr_put_u8(r, WFA_VENDOR_ID_3);
+ bufptr_put_u8(r, WFA_ELEM_VERSION2);
+ bufptr_put_u8(r, 1);
+ bufptr_put_u8(r, WPS_VERSION);
+ bufptr_put_u8(r, WFA_MAP_EXT_ATTR); /* add multi-ap extension subelement */
+ bufptr_put_u8(r, 1);
+ bufptr_put_u8(r, cred->mapie);
+
+ fprintf(stderr, "AP configuration settings --->\n");
+ fprintf(stderr, "\tssid : %s\n", cred->ssid); // TODO: print_ssid()
+ fprintf(stderr, "\tbssid : " MACFMT "\n", MAC2STR(cred->macaddr));
+ fprintf(stderr, "\tauth_type : 0x%04x\n", cred->auth_type);
+ fprintf(stderr, "\tenc_type : 0x%04x\n", cred->enc_type);
+ fprintf(stderr, "\tkey : %s\n", cred->key); // TODO: print_key()
+ fprintf(stderr, "\tmap_extension : 0x%02x\n", cred->mapie);
+
+ /* compute HMAC of the settings buffer using "authkey" */
+ addr[0] = plain;
+ len[0] = abs(r - plain);
+ PLATFORM_HMAC_SHA256(authkey, WPS_AUTHKEY_LEN, 1, addr, len, hash);
+
+ /* append first 8 bytes of hash to settings buffer */
+ bufptr_put_be16(r, ATTR_KEY_WRAP_AUTH);
+ bufptr_put_be16(r, 8);
+ bufptr_put(r, hash, 8);
+
+
+ /* AES encrypt and add result to M2 as "ATTR_ENCR_SETTINGS" */
+
+ /* Pad length of the message to encrypt to a multiple of
+ * AES_BLOCK_SIZE. Each padded byte must have their value equal
+ * to the number of padded bytes (PKCS#5 v2.0 pad).
+ */
+ num_pad_bytes = AES_BLOCK_SIZE - (abs(r - plain) % AES_BLOCK_SIZE);
+ for (i = 0; i < num_pad_bytes; i++) {
+ bufptr_put_u8(r, num_pad_bytes);
+ }
+
+ /* Add "ATTR_ENCR_SETTINGS" attribute to the M2 buffer,
+ * followed by the IV and the settings data to encrypt.
+ */
+ uint32_t setting_len = abs(r - plain);
+
+ bufptr_put_be16(r, ATTR_ENCR_SETTINGS);
+ bufptr_put_be16(r, AES_BLOCK_SIZE + setting_len);
+ iv_start = p;
+ get_random_bytes(AES_BLOCK_SIZE, p);
+ p += AES_BLOCK_SIZE;
+ data_start = p;
+ memcpy(plain, p, setting_len);
+
+ /* Encrypt the data in-place.
+ * Note that the "ATTR_ENCR_SETTINGS" attribute containes both
+ * the IV and the encrypted data.
+ */
+ bufprintf(data_start, setting_len, "Cleartext AP settings");
+ bufprintf(iv_start, AES_BLOCK_SIZE, "IV");
+
+ PLATFORM_AES_ENCRYPT(keywrapkey, iv_start, data_start, setting_len);
+
+ bufprintf(data_start, setting_len, "Encrypted AP settings");
+ }
+
+ /* authenticator */
+ {
+ /* Concatenate M1 and M2 (everything in the M2 buffer up to
+ * this point) and calculate the HMAC.
+ * Finally, append it to M2 as a attribute.
+ */
+ uint8_t hash[SHA256_MAC_LEN];
+
+ const uint8_t *addr[2];
+ size_t len[2];
+
+ addr[0] = m1;
+ addr[1] = buffer;
+ len[0] = m1_size;
+ len[1] = abs(p - buffer);
+
+ PLATFORM_HMAC_SHA256(authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+ bufptr_put_be16(p, ATTR_AUTHENTICATOR);
+ bufptr_put_be16(p, 8);
+ bufptr_put(p, hash, 8);
+ }
+
+ *m2 = buffer;
+ *m2_size = abs(p - buffer);
+
+ free(local_privkey);
+
+ return 0;
+}
+
+int wsc_process_m2(const char *ifname, void *key, uint8_t *m1, uint16_t m1_size,
+ uint8_t *m2, uint16_t m2_size, struct wps_credential *out)
+{
+ uint8_t *p;
+ struct wsc_key *k;
+
+ uint8_t mapie = 0;
+ uint8_t ssid[33];
+ uint8_t ssid_present;
+ int ssidlen = 0;
+ uint8_t bssid[6];
+ uint8_t bssid_present;
+ uint16_t auth_type;
+ uint8_t auth_type_present;
+ uint16_t enc_type;
+ uint8_t enc_type_present;
+ uint8_t network_key[64];
+ int network_keylen = 0;
+ uint8_t network_key_present;
+ //uint8_t band = 0;
+
+ uint8_t authkey[WPS_AUTHKEY_LEN];
+ uint8_t keywrapkey[WPS_KEYWRAPKEY_LEN];
+ uint8_t emsk[WPS_EMSK_LEN];
+
+ uint8_t *m2_nonce = NULL;
+ uint8_t m2_nonce_present;
+ uint8_t *m2_pubkey = NULL;
+ uint8_t m2_pubkey_present;
+ uint16_t m2_pubkey_len = 0;
+ uint8_t *m2_encrypted_settings = NULL;
+ uint8_t m2_encrypted_settings_present;
+ uint16_t m2_encrypted_settings_len = 0;
+ uint8_t *m2_authenticator = NULL;
+ uint8_t m2_authenticator_present;
+
+ //uint8_t m1_nonce_present;
+ /*uint8_t *m1_pubkey; */
+ //uint8_t m1_pubkey_present;
+ //uint16_t m1_pubkey_len;
+
+ uint8_t *m1_privkey;
+ uint16_t m1_privkey_len;
+ uint8_t *m1_macaddr;
+ uint8_t *m1_nonce;
+
+
+
+ if (!key || !m1 || m1_size == 0) {
+ fprintf(stderr, "%p %p %hu\n", key, m1, m1_size);
+ fprintf(stderr, "Missing m1 or key\n");
+ return -1;
+ }
+
+ if (m2 == NULL || m2_size == 0) {
+ fprintf(stderr, "Missing m2\n");
+ return -1;
+ }
+
+
+ k = (struct wsc_key *)key;
+ m1_privkey = k->key;
+ m1_privkey_len = k->keylen;
+ m1_macaddr = k->macaddr;
+ m1_nonce = k->nonce;
+
+
+ m2_nonce_present = 0;
+ m2_pubkey_present = 0;
+ m2_encrypted_settings_present = 0;
+ m2_authenticator_present = 0;
+ p = m2;
+
+ while (abs(p - m2) < m2_size) {
+ uint16_t attr_type;
+ uint16_t attr_len;
+
+
+ attr_type = buf_get_be16(p);
+ p += 2;
+ attr_len = buf_get_be16(p);
+ p += 2;
+
+
+ switch (attr_type) {
+ case ATTR_REGISTRAR_NONCE:
+ if (attr_len != 16) {
+ fprintf(stderr,
+ "Incorrect length (%d) for ATTR_REGISTRAR_NONCE\n", attr_len);
+ return -EINVAL;
+ }
+ m2_nonce = p;
+ m2_nonce_present = 1;
+ break;
+ case ATTR_PUBLIC_KEY:
+ m2_pubkey_len = attr_len;
+ m2_pubkey = p;
+ m2_pubkey_present = 1;
+ break;
+ case ATTR_ENCR_SETTINGS:
+ m2_encrypted_settings_len = attr_len;
+ m2_encrypted_settings = p;
+ m2_encrypted_settings_present = 1;
+ break;
+ case ATTR_AUTHENTICATOR:
+ if (attr_len != 8) {
+ fprintf(stderr,
+ "Incorrect length (%d) for ATTR_AUTHENTICATOR\n", attr_len);
+ return 0;
+ }
+ m2_authenticator = p;
+ m2_authenticator_present = 1;
+ break;
+ default:
+ break;
+ }
+
+ p += attr_len;
+ }
+
+ if (0 == m2_nonce_present ||
+ 0 == m2_pubkey_present ||
+ 0 == m2_encrypted_settings_present ||
+ 0 == m2_authenticator_present) {
+
+ fprintf(stderr, "Missing attributes in the received M2 message\n");
+ return -EINVAL;
+ }
+
+#if 0
+ m1_nonce_present = 0;
+ m1_pubkey_present = 0;
+ p = m1;
+ while (abs(p - m1) < m1_size) {
+ uint16_t attr_type;
+ uint16_t attr_len;
+
+
+ attr_type = buf_get_be16(p);
+ p += 2;
+ attr_len = buf_get_be16(p);
+ p += 2;
+
+
+ switch (attr_type) {
+ case ATTR_ENROLLEE_NONCE:
+ if (attr_len != 16) {
+ fprintf(stderr,
+ "Incorrect length (%d) for ATTR_ENROLLEE_NONCE\n", attr_len);
+ return -EINVAL;
+ }
+ m1_nonce = p;
+ m1_nonce_present = 1;
+ break;
+ case ATTR_PUBLIC_KEY:
+ m1_pubkey_len = attr_len;
+ //m1_pubkey = p;
+ m1_pubkey_present = 1;
+ break;
+ case ATTR_RF_BANDS:
+ band = *p;
+ break;
+ default:
+ break;
+ }
+
+ p += attr_len;
+ }
+
+
+ if (0 == m1_nonce_present || 0 == m1_pubkey_present) {
+ fprintf(stderr, "Missing attributes in cached M1 message\n");
+ return -EINVAL;
+ }
+#endif
+
+ /* derive keys - authkey, keywrapkey and emsk */
+ {
+ uint8_t *shared_secret;
+ uint16_t shared_secret_len;
+ const uint8_t *addr[3];
+ size_t len[3];
+ uint8_t dhkey[SHA256_MAC_LEN];
+ uint8_t kdk[SHA256_MAC_LEN];
+ uint8_t keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
+
+
+ PLATFORM_COMPUTE_DH_SHARED_SECRET(&shared_secret,
+ &shared_secret_len,
+ m2_pubkey,
+ m2_pubkey_len,
+ m1_privkey,
+ m1_privkey_len);
+
+ addr[0] = shared_secret;
+ len[0] = shared_secret_len;
+
+ PLATFORM_SHA256(1, addr, len, dhkey);
+
+ addr[0] = m1_nonce;
+ addr[1] = m1_macaddr;
+ addr[2] = m2_nonce;
+ len[0] = 16;
+ len[1] = 6;
+ len[2] = 16;
+
+ PLATFORM_HMAC_SHA256(dhkey, SHA256_MAC_LEN, 3, addr, len, kdk);
+
+ wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
+ keys, sizeof(keys));
+
+ memcpy(authkey, keys, WPS_AUTHKEY_LEN);
+ memcpy(keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
+ memcpy(emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN, WPS_EMSK_LEN);
+
+ fprintf(stderr, "WPS keys: \n");
+ bufprintf(m2_pubkey, m2_pubkey_len, "Registrar public key");
+ /* bufprintf(m1_privkey, m1_privkey_len, "Enrollee private key"); */
+ /* bufprintf(shared_secret, shared_secret_len, "DH Shared secret"); */
+ bufprintf(dhkey, 32, "DH Key");
+ bufprintf(m1_nonce, 16, "Nonce-E");
+ bufprintf(m2_nonce, 16, "Nonce-R");
+ bufprintf(kdk, 32, "KDK");
+ bufprintf(authkey, WPS_AUTHKEY_LEN, "WPS authkey");
+ bufprintf(keywrapkey, WPS_KEYWRAPKEY_LEN, "WPS keywrapkey");
+ bufprintf(emsk, WPS_EMSK_LEN, "WPS emsk");
+
+ free(shared_secret);
+ }
+
+
+ /* Verify message authentication -
+ *
+ * Concatenate M1 and M2 (excluding the last 12 bytes, where the
+ * authenticator attribute is present) and calculate the HMAC.
+ * Check it against the actual authenticator attribute value.
+ */
+ {
+ uint8_t hash[SHA256_MAC_LEN];
+ const uint8_t *addr[2];
+ size_t len[2];
+
+ addr[0] = m1;
+ addr[1] = m2;
+ len[0] = m1_size;
+ len[1] = m2_size - 12;
+
+ PLATFORM_HMAC_SHA256(authkey, WPS_AUTHKEY_LEN, 2, addr, len, hash);
+
+ if (memcmp(m2_authenticator, hash, 8)) {
+ fprintf(stderr, "Message M2 authentication failed\n");
+ return -1;
+ }
+ }
+
+ /* Decrypt the message and check the keywrap */
+ {
+ uint8_t *plain;
+ uint32_t plain_len;
+ uint8_t m2_keywrap_present;
+
+ plain = m2_encrypted_settings + AES_BLOCK_SIZE;
+ plain_len = m2_encrypted_settings_len - AES_BLOCK_SIZE;
+
+ bufprintf(plain, plain_len, "Encrypted AP settings");
+ bufprintf(m2_encrypted_settings, AES_BLOCK_SIZE, "IV");
+
+ PLATFORM_AES_DECRYPT(keywrapkey, m2_encrypted_settings, plain, plain_len);
+
+ bufprintf(plain, plain_len, "Cleartext AP settings");
+ plain_len -= plain[plain_len - 1]; /* remove padding */
+
+ /* Parse contents of AP settings */
+ ssid_present = 0;
+ bssid_present = 0;
+ auth_type_present = 0;
+ enc_type_present = 0;
+ network_key_present = 0;
+ m2_keywrap_present = 0;
+ p = plain;
+
+ while ((uint32_t)(abs(p - plain)) < plain_len) {
+ uint16_t attr_type;
+ uint16_t attr_len;
+
+ attr_type = buf_get_be16(p);
+ p += 2;
+ attr_len = buf_get_be16(p);
+ p += 2;
+
+ switch (attr_type) {
+ case ATTR_SSID:
+ if (attr_len > 32)
+ break;
+
+ bufptr_get(p, ssid, attr_len);
+ ssidlen = attr_len;
+ //ssid[attr_len] = 0x00;
+ ssid_present = 1;
+ break;
+ case ATTR_AUTH_TYPE:
+ auth_type = buf_get_be16(p);
+ p += 2;
+ auth_type_present = 1;
+ break;
+ case ATTR_ENCR_TYPE:
+ enc_type = buf_get_be16(p);
+ p += 2;
+ enc_type_present = 1;
+ break;
+ case ATTR_NETWORK_KEY:
+ bufptr_get(p, network_key, attr_len);
+ network_keylen = attr_len;
+ //network_key[attr_len] = 0x00;
+ network_key_present = 1;
+ break;
+ case ATTR_MAC_ADDR:
+ bufptr_get(p, bssid, attr_len);
+ bssid_present = 1;
+ break;
+ case ATTR_KEY_WRAP_AUTH:
+ {
+ uint8_t *end_of_hmac;
+ uint8_t hash[SHA256_MAC_LEN];
+ const uint8_t *addr[1];
+ size_t len[1];
+
+ end_of_hmac = p - 4;
+ addr[0] = plain;
+ len[0] = abs(end_of_hmac - plain);
+
+ PLATFORM_HMAC_SHA256(authkey, WPS_AUTHKEY_LEN, 1, addr, len, hash);
+
+ if (memcmp(p, hash, 8)) {
+ fprintf(stderr, "M2 keywrap check failed\n");
+ return -1;
+ }
+ m2_keywrap_present = 1;
+ }
+ break;
+ case ATTR_VENDOR_EXTENSION:
+ {
+ uint8_t id[3];
+ uint8_t *end_of_mapie;
+ uint8_t subelem;
+ uint8_t len;
+
+ // May be one or more subelements (Section 12 of WSC spec)
+ end_of_mapie = p + attr_len;
+ bufptr_get(p, id, sizeof(id));
+
+ if (id[0] ^ WFA_VENDOR_ID_1
+ || id[1] ^ WFA_VENDOR_ID_2
+ || id[2] ^ WFA_VENDOR_ID_3) {
+
+ //p += (attr_len - sizeof(id));
+ p -= sizeof(id);
+ break;
+ }
+
+ while (p < end_of_mapie) {
+ bufptr_get(p, &subelem, 1);
+ bufptr_get(p, &len, 1);
+ if (!(subelem ^ WFA_MAP_EXT_ATTR)) {
+ /* MAP extension subelement is 1 byte */
+ bufptr_get(p, &mapie, 1);
+ } else {
+ p += len;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ p += attr_len;
+ }
+
+ if ( (ssid_present &
+ bssid_present &
+ auth_type_present &
+ enc_type_present &
+ network_key_present &
+ m2_keywrap_present) == 0) {
+ fprintf(stderr, "WSC M2 is missing settings attributes\n");
+ return -1;
+ }
+ }
+
+ memcpy(out->ssid, ssid, ssidlen);
+ memcpy(out->key, network_key, network_keylen);
+ out->auth_type = auth_type;
+ out->enc_type = enc_type;
+ out->mapie = mapie;
+ memcpy(out->macaddr, bssid, 6);
+ //out->output.band = band;
+
+ return 0;
+}
diff --git a/src/i1905_wsc.h b/src/i1905_wsc.h
new file mode 100644
index 00000000..92f88dc2
--- /dev/null
+++ b/src/i1905_wsc.h
@@ -0,0 +1,189 @@
+
+
+#ifndef I1905_WSC_H
+#define I1905_WSC_H
+
+
+#include <stdint.h>
+
+#define ATTR_VERSION (0x104a)
+#define ATTR_MSG_TYPE (0x1022)
+#define WPS_M1 (0x04)
+#define WPS_M2 (0x05)
+#define ATTR_UUID_E (0x1047)
+#define ATTR_UUID_R (0x1048)
+#define ATTR_MAC_ADDR (0x1020)
+#define ATTR_ENROLLEE_NONCE (0x101a)
+#define ATTR_REGISTRAR_NONCE (0x1039)
+#define ATTR_PUBLIC_KEY (0x1032)
+#define ATTR_AUTH_TYPE_FLAGS (0x1004)
+#define WPS_AUTH_OPEN (0x0001)
+#define WPS_AUTH_WPAPSK (0x0002)
+#define WPS_AUTH_SHARED (0x0004) /* deprecated */
+#define WPS_AUTH_WPA (0x0008)
+#define WPS_AUTH_WPA2 (0x0010)
+#define WPS_AUTH_WPA2PSK (0x0020)
+#define ATTR_ENCR_TYPE_FLAGS (0x1010)
+#define WPS_ENCR_NONE (0x0001)
+#define WPS_ENCR_WEP (0x0002) /* deprecated */
+#define WPS_ENCR_TKIP (0x0004)
+#define WPS_ENCR_AES (0x0008)
+#define ATTR_CONN_TYPE_FLAGS (0x100d)
+#define WPS_CONN_ESS (0x01)
+#define WPS_CONN_IBSS (0x02)
+#define ATTR_CONFIG_METHODS (0x1008)
+#define WPS_CONFIG_VIRT_PUSHBUTTON (0x0280)
+#define WPS_CONFIG_PHY_PUSHBUTTON (0x0480)
+#define ATTR_WPS_STATE (0x1044)
+#define WPS_STATE_NOT_CONFIGURED (1)
+#define WPS_STATE_CONFIGURED (2)
+#define ATTR_MANUFACTURER (0x1021)
+#define ATTR_MODEL_NAME (0x1023)
+#define ATTR_MODEL_NUMBER (0x1024)
+#define ATTR_SERIAL_NUMBER (0x1042)
+#define ATTR_PRIMARY_DEV_TYPE (0x1054)
+#define WPS_DEV_COMPUTER (1)
+#define WPS_DEV_COMPUTER_PC (1)
+#define WPS_DEV_COMPUTER_SERVER (2)
+#define WPS_DEV_COMPUTER_MEDIA_CENTER (3)
+#define WPS_DEV_COMPUTER_ULTRA_MOBILE (4)
+#define WPS_DEV_COMPUTER_NOTEBOOK (5)
+#define WPS_DEV_COMPUTER_DESKTOP (6)
+#define WPS_DEV_COMPUTER_MID (7)
+#define WPS_DEV_COMPUTER_NETBOOK (8)
+#define WPS_DEV_COMPUTER_TABLET (9)
+#define WPS_DEV_INPUT (2)
+#define WPS_DEV_INPUT_KEYBOARD (1)
+#define WPS_DEV_INPUT_MOUSE (2)
+#define WPS_DEV_INPUT_JOYSTICK (3)
+#define WPS_DEV_INPUT_TRACKBALL (4)
+#define WPS_DEV_INPUT_GAMING (5)
+#define WPS_DEV_INPUT_REMOTE (6)
+#define WPS_DEV_INPUT_TOUCHSCREEN (7)
+#define WPS_DEV_INPUT_BIOMETRIC_READER (8)
+#define WPS_DEV_INPUT_BARCODE_READER (9)
+#define WPS_DEV_PRINTER (3)
+#define WPS_DEV_PRINTER_PRINTER (1)
+#define WPS_DEV_PRINTER_SCANNER (2)
+#define WPS_DEV_PRINTER_FAX (3)
+#define WPS_DEV_PRINTER_COPIER (4)
+#define WPS_DEV_PRINTER_ALL_IN_ONE (5)
+#define WPS_DEV_CAMERA (4)
+#define WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA (1)
+#define WPS_DEV_CAMERA_VIDEO (2)
+#define WPS_DEV_CAMERA_WEB (3)
+#define WPS_DEV_CAMERA_SECURITY (4)
+#define WPS_DEV_STORAGE (5)
+#define WPS_DEV_STORAGE_NAS (1)
+#define WPS_DEV_NETWORK_INFRA (6)
+#define WPS_DEV_NETWORK_INFRA_AP (1)
+#define WPS_DEV_NETWORK_INFRA_ROUTER (2)
+#define WPS_DEV_NETWORK_INFRA_SWITCH (3)
+#define WPS_DEV_NETWORK_INFRA_GATEWAY (4)
+#define WPS_DEV_NETWORK_INFRA_BRIDGE (5)
+#define WPS_DEV_DISPLAY (7)
+#define WPS_DEV_DISPLAY_TV (1)
+#define WPS_DEV_DISPLAY_PICTURE_FRAME (2)
+#define WPS_DEV_DISPLAY_PROJECTOR (3)
+#define WPS_DEV_DISPLAY_MONITOR (4)
+#define WPS_DEV_MULTIMEDIA (8)
+#define WPS_DEV_MULTIMEDIA_DAR (1)
+#define WPS_DEV_MULTIMEDIA_PVR (2)
+#define WPS_DEV_MULTIMEDIA_MCX (3)
+#define WPS_DEV_MULTIMEDIA_SET_TOP_BOX (4)
+#define WPS_DEV_MULTIMEDIA_MEDIA_SERVER (5)
+#define WPS_DEV_MULTIMEDIA_PORTABLE_VIDEO_PLAYER (6)
+#define WPS_DEV_GAMING (9)
+#define WPS_DEV_GAMING_XBOX (1)
+#define WPS_DEV_GAMING_XBOX360 (2)
+#define WPS_DEV_GAMING_PLAYSTATION (3)
+#define WPS_DEV_GAMING_GAME_CONSOLE (4)
+#define WPS_DEV_GAMING_PORTABLE_DEVICE (5)
+#define WPS_DEV_PHONE (10)
+#define WPS_DEV_PHONE_WINDOWS_MOBILE (1)
+#define WPS_DEV_PHONE_SINGLE_MODE (2)
+#define WPS_DEV_PHONE_DUAL_MODE (3)
+#define WPS_DEV_PHONE_SP_SINGLE_MODE (4)
+#define WPS_DEV_PHONE_SP_DUAL_MODE (5)
+#define WPS_DEV_AUDIO (11)
+#define WPS_DEV_AUDIO_TUNER_RECV (1)
+#define WPS_DEV_AUDIO_SPEAKERS (2)
+#define WPS_DEV_AUDIO_PMP (3)
+#define WPS_DEV_AUDIO_HEADSET (4)
+#define WPS_DEV_AUDIO_HEADPHONES (5)
+#define WPS_DEV_AUDIO_MICROPHONE (6)
+#define WPS_DEV_AUDIO_HOME_THEATRE (7)
+#define ATTR_DEV_NAME (0x1011)
+#define ATTR_RF_BANDS (0x103c)
+#define WPS_RF_24GHZ (0x01)
+#define WPS_RF_50GHZ (0x02)
+#define WPS_RF_60GHZ (0x04)
+#define ATTR_ASSOC_STATE (0x1002)
+#define WPS_ASSOC_NOT_ASSOC (0)
+#define WPS_ASSOC_CONN_SUCCESS (1)
+#define ATTR_DEV_PASSWORD_ID (0x1012)
+#define DEV_PW_PUSHBUTTON (0x0004)
+#define ATTR_CONFIG_ERROR (0x1009)
+#define WPS_CFG_NO_ERROR (0)
+#define ATTR_OS_VERSION (0x102d)
+#define ATTR_VENDOR_EXTENSION (0x1049)
+#define WPS_VENDOR_ID_WFA_1 (0x00)
+#define WPS_VENDOR_ID_WFA_2 (0x37)
+#define WPS_VENDOR_ID_WFA_3 (0x2A)
+#define WFA_VENDOR_ID_1 WPS_VENDOR_ID_WFA_1
+#define WFA_VENDOR_ID_2 WPS_VENDOR_ID_WFA_2
+#define WFA_VENDOR_ID_3 WPS_VENDOR_ID_WFA_3
+
+#define WFA_ELEM_VERSION2 (0x00)
+#define WPS_VERSION (0x20)
+
+#define WFA_MAP_EXT_ATTR (0x06)
+
+
+#define ATTR_SSID (0x1045)
+#define ATTR_AUTH_TYPE (0x1003)
+#define ATTR_ENCR_TYPE (0x100f)
+#define ATTR_NETWORK_KEY (0x1027)
+#define ATTR_KEY_WRAP_AUTH (0x101e)
+#define ATTR_ENCR_SETTINGS (0x1018)
+#define ATTR_AUTHENTICATOR (0x1005)
+
+
+struct wps_credential {
+ uint8_t ssid[32];
+ size_t ssidlen;
+ uint16_t auth_type;
+ uint16_t enc_type;
+ uint8_t key[64];
+ size_t keylen;
+ uint8_t macaddr[6];
+ uint8_t band;
+ uint8_t mapie; // TODO: extra attr handling
+};
+
+struct wps_data {
+ uint8_t ssid[64];
+ uint8_t network_key[64];
+ uint16_t auth_types;
+ uint16_t enc_types;
+ uint8_t macaddr[6];
+ uint8_t band;
+ uint8_t mapie;
+};
+
+
+uint8_t wsc_get_message_type(uint8_t *m, uint16_t m_size);
+
+
+int wsc_build_m1(const char *ifname, uint8_t **m1, uint16_t *m1_size, void **key,
+ struct wps_data *in);
+
+int wsc_build_m2(uint8_t *m1, uint16_t m1_size, uint8_t **m2, uint16_t *m2_size,
+ struct wps_credential *in);
+
+int wsc_process_m2(const char *ifname, void *key, uint8_t *m1, uint16_t m1_size,
+ uint8_t *m2, uint16_t m2_size, struct wps_credential *out);
+
+
+
+#endif /* I1905_WSC_H */
--
GitLab