diff --git a/src/1905_tlvs.h b/src/1905_tlvs.h index ae83679522cca5ab6d23b7d3e228beca85747fb8..3498cab7c622487e5e09689bc556217dac9c570b 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 da69bbe3fbaedefcf2a9d2ed6efa09ab48a561e9..38b8fd66cda7af20b7d7897d02c28bf53142374b 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 b5585d37dfc1976731c57fd03be1023516228d6b..5922f103fafaf83cd18619e527b4f429fcad2b8d 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 0000000000000000000000000000000000000000..7d470a6d5fc0de757d4fdea556373dd68205063e --- /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 0000000000000000000000000000000000000000..c24449c2d4f3e5f92c00c54dc2fe9ebb0b770c8e --- /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 47a1d4c3f4f0901d6a8b3a836387fb1c56ad0913..f0feb2c801c7d2f1f686ed58fb510de3637e6fa3 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 77a5229236e208640262b86438a123485374b6e1..90272fbbbe862c02e22d38746b8c4373373d0359 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 26d4c5a81a536ebeb98078a6082cf0fa35b28bc3..c8a9dbd4992bc1643dd33c1054fb0a2c95c51c72 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 0000000000000000000000000000000000000000..bf8d0d139d807408b00fb4877bebcff3a42fc280 --- /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 0000000000000000000000000000000000000000..92f88dc286f873d5c9691506bd09cfdee2c51d73 --- /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 */