forked from espressif/esp-idf
Merge branch 'feature/dpp_porting' into 'master'
wpa_supplicant: Port DPP crypto functionality from mainline supplicant repository. See merge request espressif/esp-idf!7513
This commit is contained in:
@@ -5,6 +5,10 @@ set(srcs "port/os_xtensa.c"
|
||||
"src/ap/wpa_auth_ie.c"
|
||||
"src/common/sae.c"
|
||||
"src/common/wpa_common.c"
|
||||
"src/common/dpp.c"
|
||||
"src/crypto/aes-ctr.c"
|
||||
"src/crypto/aes-siv.c"
|
||||
"src/crypto/sha256-kdf.c"
|
||||
"src/crypto/aes-cbc.c"
|
||||
"src/crypto/aes-ccm.c"
|
||||
"src/crypto/aes-internal-dec.c"
|
||||
@@ -17,7 +21,8 @@ set(srcs "port/os_xtensa.c"
|
||||
"src/crypto/sha256-tlsprf.c"
|
||||
"src/crypto/bignum.c"
|
||||
"src/crypto/ccmp.c"
|
||||
"src/crypto/crypto_mbedtls.c"
|
||||
"src/crypto/crypto_mbedtls-bignum.c"
|
||||
"src/crypto/crypto_mbedtls-ec.c"
|
||||
"src/crypto/crypto_ops.c"
|
||||
"src/crypto/crypto_internal-cipher.c"
|
||||
"src/crypto/crypto_internal-modexp.c"
|
||||
@@ -78,6 +83,7 @@ set(srcs "port/os_xtensa.c"
|
||||
"src/utils/uuid.c"
|
||||
"src/utils/wpabuf.c"
|
||||
"src/utils/wpa_debug.c"
|
||||
"src/utils/json.c"
|
||||
"src/wps/wps.c"
|
||||
"src/wps/wps_attr_build.c"
|
||||
"src/wps/wps_attr_parse.c"
|
||||
@@ -114,4 +120,5 @@ target_compile_definitions(${COMPONENT_LIB} PRIVATE
|
||||
CONFIG_WPA3_SAE
|
||||
CONFIG_TLSV12
|
||||
CONFIG_SHA256
|
||||
CONFIG_DPP
|
||||
)
|
||||
|
@@ -17,4 +17,11 @@ menu "Supplicant"
|
||||
Enabling this could increase the build size ~60kb
|
||||
depending on the project logging level.
|
||||
|
||||
config WPA_TESTING_OPTIONS
|
||||
bool "Add DPP testing code"
|
||||
default n
|
||||
help
|
||||
Select this to enable unity test for DPP.
|
||||
|
||||
|
||||
endmenu
|
||||
|
@@ -2,4 +2,4 @@ COMPONENT_ADD_INCLUDEDIRS := include port/include include/esp_supplicant
|
||||
COMPONENT_PRIV_INCLUDEDIRS := src
|
||||
COMPONENT_SRCDIRS := port src/ap src/common src/crypto src/eap_peer src/rsn_supp src/tls src/utils src/esp_supplicant src/wps
|
||||
|
||||
CFLAGS += -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing
|
||||
CFLAGS += -DCONFIG_DPP -DCONFIG_WPA3_SAE -DCONFIG_IEEE80211W -DESP_SUPPLICANT -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_TLS -DEAP_TTLS -DEAP_PEAP -DEAP_MSCHAPv2 -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -DCONFIG_ECC -D__ets__ -Wno-strict-aliasing
|
||||
|
@@ -38,7 +38,7 @@ void wpabuf_free(struct wpabuf *buf);
|
||||
void * wpabuf_put(struct wpabuf *buf, size_t len);
|
||||
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
|
||||
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
|
||||
void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
|
||||
void wpabuf_printf(struct wpabuf *buf, const char *fmt, ...) PRINTF_FORMAT(2, 3);
|
||||
|
||||
|
||||
/**
|
||||
|
@@ -35,6 +35,15 @@ struct os_time {
|
||||
suseconds_t usec;
|
||||
};
|
||||
|
||||
struct os_tm {
|
||||
int sec; /* 0..59 or 60 for leap seconds */
|
||||
int min; /* 0..59 */
|
||||
int hour; /* 0..23 */
|
||||
int day; /* 1..31 */
|
||||
int month; /* 1..12 */
|
||||
int year; /* Four digit year */
|
||||
};
|
||||
|
||||
/**
|
||||
* os_get_time - Get current time (sec, usec)
|
||||
* @t: Pointer to buffer for the time
|
||||
@@ -76,6 +85,7 @@ int os_get_time(struct os_time *t);
|
||||
int os_mktime(int year, int month, int day, int hour, int min, int sec,
|
||||
os_time_t *t);
|
||||
|
||||
int os_gmtime(os_time_t t, struct os_tm *tm);
|
||||
|
||||
/**
|
||||
* os_daemonize - Run in the background (detach from the controlling terminal)
|
||||
@@ -293,7 +303,4 @@ static inline int os_snprintf_error(size_t size, int res)
|
||||
* This function matches in behavior with the strlcpy(3) function in OpenBSD.
|
||||
*/
|
||||
size_t os_strlcpy(char *dest, const char *src, size_t siz);
|
||||
|
||||
|
||||
|
||||
#endif /* OS_H */
|
||||
|
6398
components/wpa_supplicant/src/common/dpp.c
Normal file
6398
components/wpa_supplicant/src/common/dpp.c
Normal file
File diff suppressed because it is too large
Load Diff
594
components/wpa_supplicant/src/common/dpp.h
Normal file
594
components/wpa_supplicant/src/common/dpp.h
Normal file
@@ -0,0 +1,594 @@
|
||||
/*
|
||||
* DPP functionality shared between hostapd and wpa_supplicant
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
* Copyright (c) 2018-2019, The Linux Foundation
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef DPP_H
|
||||
#define DPP_H
|
||||
|
||||
#ifdef CONFIG_DPP
|
||||
|
||||
#include "utils/list.h"
|
||||
#include "common/wpa_common.h"
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
struct crypto_ecdh;
|
||||
struct hostapd_ip_addr;
|
||||
struct dpp_global;
|
||||
|
||||
#define DPP_HDR_LEN (4 + 2) /* OUI, OUI Type, Crypto Suite, DPP frame type */
|
||||
#define DPP_TCP_PORT 7871
|
||||
#define SSID_MAX_LEN 32
|
||||
#define PMKID_LEN 16
|
||||
#define PMK_LEN 32
|
||||
#define PMK_LEN_SUITE_B_192 48
|
||||
#define PMK_LEN_MAX 64
|
||||
|
||||
/* DPP events */
|
||||
#define DPP_EVENT_AUTH_SUCCESS "DPP-AUTH-SUCCESS "
|
||||
#define DPP_EVENT_AUTH_INIT_FAILED "DPP-AUTH-INIT-FAILED "
|
||||
#define DPP_EVENT_NOT_COMPATIBLE "DPP-NOT-COMPATIBLE "
|
||||
#define DPP_EVENT_RESPONSE_PENDING "DPP-RESPONSE-PENDING "
|
||||
#define DPP_EVENT_SCAN_PEER_QR_CODE "DPP-SCAN-PEER-QR-CODE "
|
||||
#define DPP_EVENT_AUTH_DIRECTION "DPP-AUTH-DIRECTION "
|
||||
#define DPP_EVENT_CONF_RECEIVED "DPP-CONF-RECEIVED "
|
||||
#define DPP_EVENT_CONF_SENT "DPP-CONF-SENT "
|
||||
#define DPP_EVENT_CONF_FAILED "DPP-CONF-FAILED "
|
||||
#define DPP_EVENT_CONN_STATUS_RESULT "DPP-CONN-STATUS-RESULT "
|
||||
#define DPP_EVENT_CONFOBJ_AKM "DPP-CONFOBJ-AKM "
|
||||
#define DPP_EVENT_CONFOBJ_SSID "DPP-CONFOBJ-SSID "
|
||||
#define DPP_EVENT_CONFOBJ_SSID_CHARSET "DPP-CONFOBJ-SSID-CHARSET "
|
||||
#define DPP_EVENT_CONFOBJ_PASS "DPP-CONFOBJ-PASS "
|
||||
#define DPP_EVENT_CONFOBJ_PSK "DPP-CONFOBJ-PSK "
|
||||
#define DPP_EVENT_CONNECTOR "DPP-CONNECTOR "
|
||||
#define DPP_EVENT_C_SIGN_KEY "DPP-C-SIGN-KEY "
|
||||
#define DPP_EVENT_NET_ACCESS_KEY "DPP-NET-ACCESS-KEY "
|
||||
#define DPP_EVENT_MISSING_CONNECTOR "DPP-MISSING-CONNECTOR "
|
||||
#define DPP_EVENT_NETWORK_ID "DPP-NETWORK-ID "
|
||||
#define DPP_EVENT_RX "DPP-RX "
|
||||
#define DPP_EVENT_TX "DPP-TX "
|
||||
#define DPP_EVENT_TX_STATUS "DPP-TX-STATUS "
|
||||
#define DPP_EVENT_FAIL "DPP-FAIL "
|
||||
#define DPP_EVENT_PKEX_T_LIMIT "DPP-PKEX-T-LIMIT "
|
||||
#define DPP_EVENT_INTRO "DPP-INTRO "
|
||||
#define DPP_EVENT_CONF_REQ_RX "DPP-CONF-REQ-RX "
|
||||
|
||||
|
||||
#define WLAN_ACTION_PUBLIC 4
|
||||
#define WLAN_PA_VENDOR_SPECIFIC 9
|
||||
#define OUI_WFA 0x506f9a
|
||||
#define DPP_OUI_TYPE 0x1A
|
||||
|
||||
#define WLAN_EID_ADV_PROTO 108
|
||||
#define WLAN_EID_VENDOR_SPECIFIC 221
|
||||
|
||||
#define WLAN_PA_GAS_INITIAL_REQ 10
|
||||
|
||||
enum dpp_public_action_frame_type {
|
||||
DPP_PA_AUTHENTICATION_REQ = 0,
|
||||
DPP_PA_AUTHENTICATION_RESP = 1,
|
||||
DPP_PA_AUTHENTICATION_CONF = 2,
|
||||
DPP_PA_PEER_DISCOVERY_REQ = 5,
|
||||
DPP_PA_PEER_DISCOVERY_RESP = 6,
|
||||
DPP_PA_PKEX_EXCHANGE_REQ = 7,
|
||||
DPP_PA_PKEX_EXCHANGE_RESP = 8,
|
||||
DPP_PA_PKEX_COMMIT_REVEAL_REQ = 9,
|
||||
DPP_PA_PKEX_COMMIT_REVEAL_RESP = 10,
|
||||
DPP_PA_CONFIGURATION_RESULT = 11,
|
||||
DPP_PA_CONNECTION_STATUS_RESULT = 12,
|
||||
};
|
||||
|
||||
enum dpp_attribute_id {
|
||||
DPP_ATTR_STATUS = 0x1000,
|
||||
DPP_ATTR_I_BOOTSTRAP_KEY_HASH = 0x1001,
|
||||
DPP_ATTR_R_BOOTSTRAP_KEY_HASH = 0x1002,
|
||||
DPP_ATTR_I_PROTOCOL_KEY = 0x1003,
|
||||
DPP_ATTR_WRAPPED_DATA = 0x1004,
|
||||
DPP_ATTR_I_NONCE = 0x1005,
|
||||
DPP_ATTR_I_CAPABILITIES = 0x1006,
|
||||
DPP_ATTR_R_NONCE = 0x1007,
|
||||
DPP_ATTR_R_CAPABILITIES = 0x1008,
|
||||
DPP_ATTR_R_PROTOCOL_KEY = 0x1009,
|
||||
DPP_ATTR_I_AUTH_TAG = 0x100A,
|
||||
DPP_ATTR_R_AUTH_TAG = 0x100B,
|
||||
DPP_ATTR_CONFIG_OBJ = 0x100C,
|
||||
DPP_ATTR_CONNECTOR = 0x100D,
|
||||
DPP_ATTR_CONFIG_ATTR_OBJ = 0x100E,
|
||||
DPP_ATTR_BOOTSTRAP_KEY = 0x100F,
|
||||
DPP_ATTR_OWN_NET_NK_HASH = 0x1011,
|
||||
DPP_ATTR_FINITE_CYCLIC_GROUP = 0x1012,
|
||||
DPP_ATTR_ENCRYPTED_KEY = 0x1013,
|
||||
DPP_ATTR_ENROLLEE_NONCE = 0x1014,
|
||||
DPP_ATTR_CODE_IDENTIFIER = 0x1015,
|
||||
DPP_ATTR_TRANSACTION_ID = 0x1016,
|
||||
DPP_ATTR_BOOTSTRAP_INFO = 0x1017,
|
||||
DPP_ATTR_CHANNEL = 0x1018,
|
||||
DPP_ATTR_PROTOCOL_VERSION = 0x1019,
|
||||
DPP_ATTR_ENVELOPED_DATA = 0x101A,
|
||||
DPP_ATTR_SEND_CONN_STATUS = 0x101B,
|
||||
DPP_ATTR_CONN_STATUS = 0x101C,
|
||||
};
|
||||
|
||||
enum dpp_status_error {
|
||||
DPP_STATUS_OK = 0,
|
||||
DPP_STATUS_NOT_COMPATIBLE = 1,
|
||||
DPP_STATUS_AUTH_FAILURE = 2,
|
||||
DPP_STATUS_UNWRAP_FAILURE = 3,
|
||||
DPP_STATUS_BAD_GROUP = 4,
|
||||
DPP_STATUS_CONFIGURE_FAILURE = 5,
|
||||
DPP_STATUS_RESPONSE_PENDING = 6,
|
||||
DPP_STATUS_INVALID_CONNECTOR = 7,
|
||||
DPP_STATUS_NO_MATCH = 8,
|
||||
DPP_STATUS_CONFIG_REJECTED = 9,
|
||||
DPP_STATUS_NO_AP = 10,
|
||||
};
|
||||
|
||||
#define DPP_CAPAB_ENROLLEE BIT(0)
|
||||
#define DPP_CAPAB_CONFIGURATOR BIT(1)
|
||||
#define DPP_CAPAB_ROLE_MASK (BIT(0) | BIT(1))
|
||||
|
||||
#define DPP_BOOTSTRAP_MAX_FREQ 30
|
||||
#define DPP_MAX_NONCE_LEN 32
|
||||
#define DPP_MAX_HASH_LEN 64
|
||||
#define DPP_MAX_SHARED_SECRET_LEN 66
|
||||
|
||||
struct dpp_curve_params {
|
||||
const char *name;
|
||||
size_t hash_len;
|
||||
size_t aes_siv_key_len;
|
||||
size_t nonce_len;
|
||||
size_t prime_len;
|
||||
const char *jwk_crv;
|
||||
u16 ike_group;
|
||||
const char *jws_alg;
|
||||
};
|
||||
|
||||
enum dpp_bootstrap_type {
|
||||
DPP_BOOTSTRAP_QR_CODE,
|
||||
DPP_BOOTSTRAP_PKEX,
|
||||
DPP_BOOTSTRAP_NFC_URI,
|
||||
};
|
||||
|
||||
struct dpp_bootstrap_info {
|
||||
struct dl_list list;
|
||||
unsigned int id;
|
||||
enum dpp_bootstrap_type type;
|
||||
char *uri;
|
||||
u8 mac_addr[ETH_ALEN];
|
||||
char *info;
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
unsigned int num_freq;
|
||||
int own;
|
||||
struct crypto_key *pubkey;
|
||||
u8 pubkey_hash[SHA256_MAC_LEN];
|
||||
const struct dpp_curve_params *curve;
|
||||
unsigned int pkex_t; /* number of failures before dpp_pkex
|
||||
* instantiation */
|
||||
};
|
||||
|
||||
#define PKEX_COUNTER_T_LIMIT 5
|
||||
|
||||
struct dpp_pkex {
|
||||
void *msg_ctx;
|
||||
unsigned int initiator:1;
|
||||
unsigned int exchange_done:1;
|
||||
unsigned int failed:1;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
u8 own_mac[ETH_ALEN];
|
||||
u8 peer_mac[ETH_ALEN];
|
||||
char *identifier;
|
||||
char *code;
|
||||
struct crypto_key *x;
|
||||
struct crypto_key *y;
|
||||
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
u8 z[DPP_MAX_HASH_LEN];
|
||||
struct crypto_key *peer_bootstrap_key;
|
||||
struct wpabuf *exchange_req;
|
||||
struct wpabuf *exchange_resp;
|
||||
unsigned int t; /* number of failures on code use */
|
||||
unsigned int exch_req_wait_time;
|
||||
unsigned int exch_req_tries;
|
||||
unsigned int freq;
|
||||
};
|
||||
|
||||
enum dpp_akm {
|
||||
DPP_AKM_UNKNOWN,
|
||||
DPP_AKM_DPP,
|
||||
DPP_AKM_PSK,
|
||||
DPP_AKM_SAE,
|
||||
DPP_AKM_PSK_SAE,
|
||||
DPP_AKM_SAE_DPP,
|
||||
DPP_AKM_PSK_SAE_DPP,
|
||||
};
|
||||
|
||||
enum dpp_netrole {
|
||||
DPP_NETROLE_STA,
|
||||
DPP_NETROLE_AP,
|
||||
DPP_NETROLE_CONFIGURATOR,
|
||||
};
|
||||
|
||||
struct dpp_configuration {
|
||||
u8 ssid[32];
|
||||
size_t ssid_len;
|
||||
int ssid_charset;
|
||||
enum dpp_akm akm;
|
||||
enum dpp_netrole netrole;
|
||||
|
||||
/* For DPP configuration (connector) */
|
||||
os_time_t netaccesskey_expiry;
|
||||
|
||||
/* TODO: groups */
|
||||
char *group_id;
|
||||
|
||||
/* For legacy configuration */
|
||||
char *passphrase;
|
||||
u8 psk[32];
|
||||
int psk_set;
|
||||
};
|
||||
|
||||
#define DPP_MAX_CONF_OBJ 10
|
||||
|
||||
struct dpp_authentication {
|
||||
void *msg_ctx;
|
||||
u8 peer_version;
|
||||
const struct dpp_curve_params *curve;
|
||||
struct dpp_bootstrap_info *peer_bi;
|
||||
struct dpp_bootstrap_info *own_bi;
|
||||
struct dpp_bootstrap_info *tmp_own_bi;
|
||||
u8 waiting_pubkey_hash[SHA256_MAC_LEN];
|
||||
int response_pending;
|
||||
enum dpp_status_error auth_resp_status;
|
||||
enum dpp_status_error conf_resp_status;
|
||||
u8 peer_mac_addr[ETH_ALEN];
|
||||
u8 i_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 r_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 e_nonce[DPP_MAX_NONCE_LEN];
|
||||
u8 i_capab;
|
||||
u8 r_capab;
|
||||
struct crypto_key *own_protocol_key;
|
||||
struct crypto_key *peer_protocol_key;
|
||||
struct wpabuf *req_msg;
|
||||
struct wpabuf *resp_msg;
|
||||
/* Intersection of possible frequencies for initiating DPP
|
||||
* Authentication exchange */
|
||||
unsigned int freq[DPP_BOOTSTRAP_MAX_FREQ];
|
||||
unsigned int num_freq, freq_idx;
|
||||
unsigned int curr_freq;
|
||||
unsigned int neg_freq;
|
||||
unsigned int num_freq_iters;
|
||||
size_t secret_len;
|
||||
u8 Mx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Mx_len;
|
||||
u8 Nx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Nx_len;
|
||||
u8 Lx[DPP_MAX_SHARED_SECRET_LEN];
|
||||
size_t Lx_len;
|
||||
u8 k1[DPP_MAX_HASH_LEN];
|
||||
u8 k2[DPP_MAX_HASH_LEN];
|
||||
u8 ke[DPP_MAX_HASH_LEN];
|
||||
int initiator;
|
||||
int waiting_auth_resp;
|
||||
int waiting_auth_conf;
|
||||
int auth_req_ack;
|
||||
unsigned int auth_resp_tries;
|
||||
u8 allowed_roles;
|
||||
int configurator;
|
||||
int remove_on_tx_status;
|
||||
int connect_on_tx_status;
|
||||
int waiting_conf_result;
|
||||
int waiting_conn_status_result;
|
||||
int auth_success;
|
||||
struct wpabuf *conf_req;
|
||||
const struct wpabuf *conf_resp; /* owned by GAS server */
|
||||
struct dpp_configuration *conf_ap;
|
||||
struct dpp_configuration *conf2_ap;
|
||||
struct dpp_configuration *conf_sta;
|
||||
struct dpp_configuration *conf2_sta;
|
||||
struct dpp_configurator *conf;
|
||||
struct dpp_config_obj {
|
||||
char *connector; /* received signedConnector */
|
||||
u8 ssid[SSID_MAX_LEN];
|
||||
u8 ssid_len;
|
||||
int ssid_charset;
|
||||
char passphrase[64];
|
||||
u8 psk[PMK_LEN];
|
||||
int psk_set;
|
||||
enum dpp_akm akm;
|
||||
struct wpabuf *c_sign_key;
|
||||
} conf_obj[DPP_MAX_CONF_OBJ];
|
||||
unsigned int num_conf_obj;
|
||||
struct wpabuf *net_access_key;
|
||||
os_time_t net_access_key_expiry;
|
||||
int send_conn_status;
|
||||
int conn_status_requested;
|
||||
int akm_use_selector;
|
||||
#ifdef CONFIG_WPA_TESTING_OPTIONS
|
||||
char *config_obj_override;
|
||||
char *discovery_override;
|
||||
char *groups_override;
|
||||
unsigned int ignore_netaccesskey_mismatch:1;
|
||||
#endif /* CONFIG_WPA_TESTING_OPTIONS */
|
||||
};
|
||||
|
||||
struct dpp_configurator {
|
||||
struct dl_list list;
|
||||
unsigned int id;
|
||||
int own;
|
||||
struct crypto_key *csign;
|
||||
char *kid;
|
||||
const struct dpp_curve_params *curve;
|
||||
};
|
||||
|
||||
struct dpp_introduction {
|
||||
u8 pmkid[PMKID_LEN];
|
||||
u8 pmk[PMK_LEN_MAX];
|
||||
size_t pmk_len;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_WPA_TESTING_OPTIONS
|
||||
enum dpp_test_behavior {
|
||||
DPP_TEST_DISABLED = 0,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_AUTH_REQ = 1,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_AUTH_RESP = 2,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_AUTH_CONF = 3,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_REQ = 4,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_PKEX_CR_RESP = 5,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_CONF_REQ = 6,
|
||||
DPP_TEST_AFTER_WRAPPED_DATA_CONF_RESP = 7,
|
||||
DPP_TEST_ZERO_I_CAPAB = 8,
|
||||
DPP_TEST_ZERO_R_CAPAB = 9,
|
||||
DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 10,
|
||||
DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 11,
|
||||
DPP_TEST_NO_I_PROTO_KEY_AUTH_REQ = 12,
|
||||
DPP_TEST_NO_I_NONCE_AUTH_REQ = 13,
|
||||
DPP_TEST_NO_I_CAPAB_AUTH_REQ = 14,
|
||||
DPP_TEST_NO_WRAPPED_DATA_AUTH_REQ = 15,
|
||||
DPP_TEST_NO_STATUS_AUTH_RESP = 16,
|
||||
DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 17,
|
||||
DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 18,
|
||||
DPP_TEST_NO_R_PROTO_KEY_AUTH_RESP = 19,
|
||||
DPP_TEST_NO_R_NONCE_AUTH_RESP = 20,
|
||||
DPP_TEST_NO_I_NONCE_AUTH_RESP = 21,
|
||||
DPP_TEST_NO_R_CAPAB_AUTH_RESP = 22,
|
||||
DPP_TEST_NO_R_AUTH_AUTH_RESP = 23,
|
||||
DPP_TEST_NO_WRAPPED_DATA_AUTH_RESP = 24,
|
||||
DPP_TEST_NO_STATUS_AUTH_CONF = 25,
|
||||
DPP_TEST_NO_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 26,
|
||||
DPP_TEST_NO_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 27,
|
||||
DPP_TEST_NO_I_AUTH_AUTH_CONF = 28,
|
||||
DPP_TEST_NO_WRAPPED_DATA_AUTH_CONF = 29,
|
||||
DPP_TEST_I_NONCE_MISMATCH_AUTH_RESP = 30,
|
||||
DPP_TEST_INCOMPATIBLE_R_CAPAB_AUTH_RESP = 31,
|
||||
DPP_TEST_R_AUTH_MISMATCH_AUTH_RESP = 32,
|
||||
DPP_TEST_I_AUTH_MISMATCH_AUTH_CONF = 33,
|
||||
DPP_TEST_NO_FINITE_CYCLIC_GROUP_PKEX_EXCHANGE_REQ = 34,
|
||||
DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 35,
|
||||
DPP_TEST_NO_STATUS_PKEX_EXCHANGE_RESP = 36,
|
||||
DPP_TEST_NO_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 37,
|
||||
DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_REQ = 38,
|
||||
DPP_TEST_NO_I_AUTH_TAG_PKEX_CR_REQ = 39,
|
||||
DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_REQ = 40,
|
||||
DPP_TEST_NO_BOOTSTRAP_KEY_PKEX_CR_RESP = 41,
|
||||
DPP_TEST_NO_R_AUTH_TAG_PKEX_CR_RESP = 42,
|
||||
DPP_TEST_NO_WRAPPED_DATA_PKEX_CR_RESP = 43,
|
||||
DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_REQ = 44,
|
||||
DPP_TEST_INVALID_ENCRYPTED_KEY_PKEX_EXCHANGE_RESP = 45,
|
||||
DPP_TEST_INVALID_STATUS_PKEX_EXCHANGE_RESP = 46,
|
||||
DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_REQ = 47,
|
||||
DPP_TEST_INVALID_BOOTSTRAP_KEY_PKEX_CR_RESP = 48,
|
||||
DPP_TEST_I_AUTH_TAG_MISMATCH_PKEX_CR_REQ = 49,
|
||||
DPP_TEST_R_AUTH_TAG_MISMATCH_PKEX_CR_RESP = 50,
|
||||
DPP_TEST_NO_E_NONCE_CONF_REQ = 51,
|
||||
DPP_TEST_NO_CONFIG_ATTR_OBJ_CONF_REQ = 52,
|
||||
DPP_TEST_NO_WRAPPED_DATA_CONF_REQ = 53,
|
||||
DPP_TEST_NO_E_NONCE_CONF_RESP = 54,
|
||||
DPP_TEST_NO_CONFIG_OBJ_CONF_RESP = 55,
|
||||
DPP_TEST_NO_STATUS_CONF_RESP = 56,
|
||||
DPP_TEST_NO_WRAPPED_DATA_CONF_RESP = 57,
|
||||
DPP_TEST_INVALID_STATUS_CONF_RESP = 58,
|
||||
DPP_TEST_E_NONCE_MISMATCH_CONF_RESP = 59,
|
||||
DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_REQ = 60,
|
||||
DPP_TEST_NO_CONNECTOR_PEER_DISC_REQ = 61,
|
||||
DPP_TEST_NO_TRANSACTION_ID_PEER_DISC_RESP = 62,
|
||||
DPP_TEST_NO_STATUS_PEER_DISC_RESP = 63,
|
||||
DPP_TEST_NO_CONNECTOR_PEER_DISC_RESP = 64,
|
||||
DPP_TEST_AUTH_RESP_IN_PLACE_OF_CONF = 65,
|
||||
DPP_TEST_INVALID_I_PROTO_KEY_AUTH_REQ = 66,
|
||||
DPP_TEST_INVALID_R_PROTO_KEY_AUTH_RESP = 67,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_REQ = 68,
|
||||
DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_REQ = 69,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_RESP = 70,
|
||||
DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_RESP = 71,
|
||||
DPP_TEST_INVALID_R_BOOTSTRAP_KEY_HASH_AUTH_CONF = 72,
|
||||
DPP_TEST_INVALID_I_BOOTSTRAP_KEY_HASH_AUTH_CONF = 73,
|
||||
DPP_TEST_INVALID_STATUS_AUTH_RESP = 74,
|
||||
DPP_TEST_INVALID_STATUS_AUTH_CONF = 75,
|
||||
DPP_TEST_INVALID_CONFIG_ATTR_OBJ_CONF_REQ = 76,
|
||||
DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_RESP = 77,
|
||||
DPP_TEST_INVALID_STATUS_PEER_DISC_RESP = 78,
|
||||
DPP_TEST_INVALID_CONNECTOR_PEER_DISC_RESP = 79,
|
||||
DPP_TEST_INVALID_CONNECTOR_PEER_DISC_REQ = 80,
|
||||
DPP_TEST_INVALID_I_NONCE_AUTH_REQ = 81,
|
||||
DPP_TEST_INVALID_TRANSACTION_ID_PEER_DISC_REQ = 82,
|
||||
DPP_TEST_INVALID_E_NONCE_CONF_REQ = 83,
|
||||
DPP_TEST_STOP_AT_PKEX_EXCHANGE_RESP = 84,
|
||||
DPP_TEST_STOP_AT_PKEX_CR_REQ = 85,
|
||||
DPP_TEST_STOP_AT_PKEX_CR_RESP = 86,
|
||||
DPP_TEST_STOP_AT_AUTH_REQ = 87,
|
||||
DPP_TEST_STOP_AT_AUTH_RESP = 88,
|
||||
DPP_TEST_STOP_AT_AUTH_CONF = 89,
|
||||
DPP_TEST_STOP_AT_CONF_REQ = 90,
|
||||
DPP_TEST_REJECT_CONFIG = 91,
|
||||
};
|
||||
|
||||
extern enum dpp_test_behavior dpp_test;
|
||||
extern u8 dpp_pkex_own_mac_override[ETH_ALEN];
|
||||
extern u8 dpp_pkex_peer_mac_override[ETH_ALEN];
|
||||
extern u8 dpp_pkex_ephemeral_key_override[600];
|
||||
extern size_t dpp_pkex_ephemeral_key_override_len;
|
||||
extern u8 dpp_protocol_key_override[600];
|
||||
extern size_t dpp_protocol_key_override_len;
|
||||
extern u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
|
||||
extern size_t dpp_nonce_override_len;
|
||||
#endif /* CONFIG_WPA_TESTING_OPTIONS */
|
||||
|
||||
void dpp_bootstrap_info_free(struct dpp_bootstrap_info *info);
|
||||
const char * dpp_bootstrap_type_txt(enum dpp_bootstrap_type type);
|
||||
int dpp_bootstrap_key_hash(struct dpp_bootstrap_info *bi);
|
||||
int dpp_parse_uri_chan_list(struct dpp_bootstrap_info *bi,
|
||||
const char *chan_list);
|
||||
int dpp_parse_uri_mac(struct dpp_bootstrap_info *bi, const char *mac);
|
||||
int dpp_parse_uri_info(struct dpp_bootstrap_info *bi, const char *info);
|
||||
char * dpp_keygen(struct dpp_bootstrap_info *bi, const char *curve,
|
||||
u8 *privkey, size_t privkey_len);
|
||||
struct hostapd_hw_modes;
|
||||
struct dpp_authentication * dpp_auth_init(void *msg_ctx,
|
||||
struct dpp_bootstrap_info *peer_bi,
|
||||
struct dpp_bootstrap_info *own_bi,
|
||||
u8 dpp_allowed_roles,
|
||||
unsigned int neg_freq,
|
||||
struct hostapd_hw_modes *own_modes,
|
||||
u16 num_modes);
|
||||
struct dpp_authentication *
|
||||
dpp_auth_req_rx(void *msg_ctx, u8 dpp_allowed_roles, int qr_mutual,
|
||||
struct dpp_bootstrap_info *peer_bi,
|
||||
struct dpp_bootstrap_info *own_bi,
|
||||
unsigned int freq, const u8 *hdr, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
struct wpabuf *
|
||||
dpp_auth_resp_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
struct wpabuf * dpp_build_conf_req(struct dpp_authentication *auth,
|
||||
const char *json);
|
||||
struct wpabuf * dpp_build_conf_req_helper(struct dpp_authentication *auth,
|
||||
const char *name,
|
||||
enum dpp_netrole netrole,
|
||||
const char *mud_url, int *opclasses);
|
||||
int dpp_auth_conf_rx(struct dpp_authentication *auth, const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
int dpp_notify_new_qr_code(struct dpp_authentication *auth,
|
||||
struct dpp_bootstrap_info *peer_bi);
|
||||
struct dpp_configuration * dpp_configuration_alloc(const char *type);
|
||||
int dpp_akm_psk(enum dpp_akm akm);
|
||||
int dpp_akm_sae(enum dpp_akm akm);
|
||||
int dpp_akm_legacy(enum dpp_akm akm);
|
||||
int dpp_akm_dpp(enum dpp_akm akm);
|
||||
int dpp_akm_ver2(enum dpp_akm akm);
|
||||
int dpp_configuration_valid(const struct dpp_configuration *conf);
|
||||
void dpp_configuration_free(struct dpp_configuration *conf);
|
||||
int dpp_set_configurator(struct dpp_global *dpp, void *msg_ctx,
|
||||
struct dpp_authentication *auth,
|
||||
const char *cmd);
|
||||
void dpp_auth_deinit(struct dpp_authentication *auth);
|
||||
struct wpabuf *
|
||||
dpp_conf_req_rx(struct dpp_authentication *auth, const u8 *attr_start,
|
||||
size_t attr_len);
|
||||
int dpp_conf_resp_rx(struct dpp_authentication *auth,
|
||||
const struct wpabuf *resp);
|
||||
enum dpp_status_error dpp_conf_result_rx(struct dpp_authentication *auth,
|
||||
const u8 *hdr,
|
||||
const u8 *attr_start, size_t attr_len);
|
||||
struct wpabuf * dpp_build_conf_result(struct dpp_authentication *auth,
|
||||
enum dpp_status_error status);
|
||||
enum dpp_status_error dpp_conn_status_result_rx(struct dpp_authentication *auth,
|
||||
const u8 *hdr,
|
||||
const u8 *attr_start,
|
||||
size_t attr_len,
|
||||
u8 *ssid, size_t *ssid_len,
|
||||
char **channel_list);
|
||||
struct wpabuf * dpp_build_conn_status_result(struct dpp_authentication *auth,
|
||||
enum dpp_status_error result,
|
||||
const u8 *ssid, size_t ssid_len,
|
||||
const char *channel_list);
|
||||
struct wpabuf * dpp_alloc_msg(enum dpp_public_action_frame_type type,
|
||||
size_t len);
|
||||
const u8 * dpp_get_attr(const u8 *buf, size_t len, u16 req_id, u16 *ret_len);
|
||||
int dpp_check_attrs(const u8 *buf, size_t len);
|
||||
int dpp_key_expired(const char *timestamp, os_time_t *expiry);
|
||||
const char * dpp_akm_str(enum dpp_akm akm);
|
||||
const char * dpp_akm_selector_str(enum dpp_akm akm);
|
||||
int dpp_configurator_get_key(const struct dpp_configurator *conf, char *buf,
|
||||
size_t buflen);
|
||||
void dpp_configurator_free(struct dpp_configurator *conf);
|
||||
struct dpp_configurator *
|
||||
dpp_keygen_configurator(const char *curve, u8 *privkey,
|
||||
size_t privkey_len);
|
||||
int dpp_configurator_own_config(struct dpp_authentication *auth,
|
||||
const char *curve, int ap);
|
||||
enum dpp_status_error
|
||||
dpp_peer_intro(struct dpp_introduction *intro, const char *own_connector,
|
||||
const u8 *net_access_key, size_t net_access_key_len,
|
||||
const u8 *csign_key, size_t csign_key_len,
|
||||
const u8 *peer_connector, size_t peer_connector_len,
|
||||
os_time_t *expiry);
|
||||
struct dpp_pkex * dpp_pkex_init(void *msg_ctx, struct dpp_bootstrap_info *bi,
|
||||
const u8 *own_mac,
|
||||
const char *identifier,
|
||||
const char *code);
|
||||
struct dpp_pkex * dpp_pkex_rx_exchange_req(void *msg_ctx,
|
||||
struct dpp_bootstrap_info *bi,
|
||||
const u8 *own_mac,
|
||||
const u8 *peer_mac,
|
||||
const char *identifier,
|
||||
const char *code,
|
||||
const u8 *buf, size_t len);
|
||||
struct wpabuf * dpp_pkex_rx_exchange_resp(struct dpp_pkex *pkex,
|
||||
const u8 *peer_mac,
|
||||
const u8 *buf, size_t len);
|
||||
struct wpabuf * dpp_pkex_rx_commit_reveal_req(struct dpp_pkex *pkex,
|
||||
const u8 *hdr,
|
||||
const u8 *buf, size_t len);
|
||||
int dpp_pkex_rx_commit_reveal_resp(struct dpp_pkex *pkex, const u8 *hdr,
|
||||
const u8 *buf, size_t len);
|
||||
void dpp_pkex_free(struct dpp_pkex *pkex);
|
||||
|
||||
char * dpp_corrupt_connector_signature(const char *connector);
|
||||
|
||||
|
||||
struct dpp_pfs {
|
||||
struct crypto_ecdh *ecdh;
|
||||
const struct dpp_curve_params *curve;
|
||||
struct wpabuf *ie;
|
||||
struct wpabuf *secret;
|
||||
};
|
||||
|
||||
struct dpp_pfs * dpp_pfs_init(const u8 *net_access_key,
|
||||
size_t net_access_key_len);
|
||||
int dpp_pfs_process(struct dpp_pfs *pfs, const u8 *peer_ie, size_t peer_ie_len);
|
||||
void dpp_pfs_free(struct dpp_pfs *pfs);
|
||||
|
||||
struct dpp_bootstrap_info * dpp_add_qr_code(struct dpp_global *dpp,
|
||||
const char *uri);
|
||||
struct dpp_bootstrap_info * dpp_add_nfc_uri(struct dpp_global *dpp,
|
||||
const char *uri);
|
||||
int dpp_bootstrap_gen(struct dpp_global *dpp, const char *cmd);
|
||||
struct dpp_bootstrap_info *
|
||||
dpp_bootstrap_get_id(struct dpp_global *dpp, unsigned int id);
|
||||
int dpp_bootstrap_remove(struct dpp_global *dpp, const char *id);
|
||||
struct dpp_bootstrap_info *
|
||||
dpp_pkex_finish(struct dpp_global *dpp, struct dpp_pkex *pkex, const u8 *peer,
|
||||
unsigned int freq);
|
||||
const char * dpp_bootstrap_get_uri(struct dpp_global *dpp, unsigned int id);
|
||||
int dpp_bootstrap_info(struct dpp_global *dpp, int id,
|
||||
char *reply, int reply_size);
|
||||
void dpp_bootstrap_find_pair(struct dpp_global *dpp, const u8 *i_bootstrap,
|
||||
const u8 *r_bootstrap,
|
||||
struct dpp_bootstrap_info **own_bi,
|
||||
struct dpp_bootstrap_info **peer_bi);
|
||||
struct dpp_global_config {
|
||||
void *msg_ctx;
|
||||
void *cb_ctx;
|
||||
int (*process_conf_obj)(void *ctx, struct dpp_authentication *auth);
|
||||
};
|
||||
|
||||
struct dpp_global * dpp_global_init(struct dpp_global_config *config);
|
||||
void dpp_global_clear(struct dpp_global *dpp);
|
||||
void dpp_global_deinit(struct dpp_global *dpp);
|
||||
|
||||
#endif /* CONFIG_DPP */
|
||||
#endif /* DPP_H */
|
@@ -27,14 +27,6 @@ void wpabuf_clear_free(struct wpabuf *buf)
|
||||
}
|
||||
}
|
||||
|
||||
void bin_clear_free(void *bin, size_t len)
|
||||
{
|
||||
if (bin) {
|
||||
os_memset(bin, 0, len);
|
||||
os_free(bin);
|
||||
}
|
||||
}
|
||||
|
||||
int sae_set_group(struct sae_data *sae, int group)
|
||||
{
|
||||
struct sae_temporary_data *tmp;
|
||||
|
89
components/wpa_supplicant/src/crypto/aes-ctr.c
Normal file
89
components/wpa_supplicant/src/crypto/aes-ctr.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* AES-128/192/256 CTR
|
||||
*
|
||||
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
#ifdef USE_MBEDTLS_CRYPTO
|
||||
#include "mbedtls/aes.h"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* aes_ctr_encrypt - AES-128/192/256 CTR mode encryption
|
||||
* @key: Key for encryption (key_len bytes)
|
||||
* @key_len: Length of the key (16, 24, or 32 bytes)
|
||||
* @nonce: Nonce for counter mode (16 bytes)
|
||||
* @data: Data to encrypt in-place
|
||||
* @data_len: Length of data in bytes
|
||||
* Returns: 0 on success, Negative value on failure
|
||||
*/
|
||||
int aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
|
||||
u8 *data, size_t data_len)
|
||||
{
|
||||
#ifdef USE_MBEDTLS_CRYPTO
|
||||
int ret;
|
||||
mbedtls_aes_context ctx;
|
||||
uint8_t stream_block[AES_BLOCK_SIZE];
|
||||
size_t offset = 0;
|
||||
|
||||
mbedtls_aes_init(&ctx);
|
||||
ret = mbedtls_aes_setkey_enc(&ctx, key, key_len * 8);
|
||||
if (ret < 0)
|
||||
goto cleanup;
|
||||
ret = mbedtls_aes_crypt_ctr(&ctx, data_len, &offset, (u8 *)nonce, stream_block, data, data);
|
||||
cleanup:
|
||||
mbedtls_aes_free(&ctx);
|
||||
return ret;
|
||||
#else
|
||||
void *ctx;
|
||||
size_t j, len, left = data_len;
|
||||
int i;
|
||||
u8 *pos = data;
|
||||
u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
|
||||
|
||||
ctx = aes_encrypt_init(key, key_len);
|
||||
if (ctx == NULL)
|
||||
return -1;
|
||||
os_memcpy(counter, nonce, AES_BLOCK_SIZE);
|
||||
|
||||
while (left > 0) {
|
||||
aes_encrypt(ctx, counter, buf);
|
||||
|
||||
len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
|
||||
for (j = 0; j < len; j++)
|
||||
pos[j] ^= buf[j];
|
||||
pos += len;
|
||||
left -= len;
|
||||
|
||||
for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
|
||||
counter[i]++;
|
||||
if (counter[i])
|
||||
break;
|
||||
}
|
||||
}
|
||||
aes_encrypt_deinit(ctx);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* aes_128_ctr_encrypt - AES-128 CTR mode encryption
|
||||
* @key: Key for encryption (key_len bytes)
|
||||
* @nonce: Nonce for counter mode (16 bytes)
|
||||
* @data: Data to encrypt in-place
|
||||
* @data_len: Length of data in bytes
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
|
||||
u8 *data, size_t data_len)
|
||||
{
|
||||
return aes_ctr_encrypt(key, 16, nonce, data, data_len);
|
||||
}
|
208
components/wpa_supplicant/src/crypto/aes-siv.c
Normal file
208
components/wpa_supplicant/src/crypto/aes-siv.c
Normal file
@@ -0,0 +1,208 @@
|
||||
/*
|
||||
* AES SIV (RFC 5297)
|
||||
* Copyright (c) 2013 Cozybit, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
|
||||
#include "crypto/aes.h"
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "crypto/aes_siv.h"
|
||||
|
||||
|
||||
static const u8 zero[AES_BLOCK_SIZE];
|
||||
|
||||
|
||||
static void dbl(u8 *pad)
|
||||
{
|
||||
int i, carry;
|
||||
|
||||
carry = pad[0] & 0x80;
|
||||
for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
|
||||
pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
|
||||
pad[AES_BLOCK_SIZE - 1] <<= 1;
|
||||
if (carry)
|
||||
pad[AES_BLOCK_SIZE - 1] ^= 0x87;
|
||||
}
|
||||
|
||||
|
||||
static void xor(u8 *a, const u8 *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < AES_BLOCK_SIZE; i++)
|
||||
*a++ ^= *b++;
|
||||
}
|
||||
|
||||
|
||||
static void xorend(u8 *a, int alen, const u8 *b, int blen)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (alen < blen)
|
||||
return;
|
||||
|
||||
for (i = 0; i < blen; i++)
|
||||
a[alen - blen + i] ^= b[i];
|
||||
}
|
||||
|
||||
|
||||
static void pad_block(u8 *pad, const u8 *addr, size_t len)
|
||||
{
|
||||
os_memset(pad, 0, AES_BLOCK_SIZE);
|
||||
os_memcpy(pad, addr, len);
|
||||
|
||||
if (len < AES_BLOCK_SIZE)
|
||||
pad[len] = 0x80;
|
||||
}
|
||||
|
||||
|
||||
static int aes_s2v(const u8 *key, size_t key_len,
|
||||
size_t num_elem, const u8 *addr[], size_t *len, u8 *mac)
|
||||
{
|
||||
u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
|
||||
u8 *buf = NULL;
|
||||
int ret;
|
||||
size_t i;
|
||||
const u8 *data[1];
|
||||
size_t data_len[1];
|
||||
|
||||
if (!num_elem) {
|
||||
os_memcpy(tmp, zero, sizeof(zero));
|
||||
tmp[AES_BLOCK_SIZE - 1] = 1;
|
||||
data[0] = tmp;
|
||||
data_len[0] = sizeof(tmp);
|
||||
return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
|
||||
}
|
||||
|
||||
data[0] = zero;
|
||||
data_len[0] = sizeof(zero);
|
||||
ret = omac1_aes_vector(key, key_len, 1, data, data_len, tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < num_elem - 1; i++) {
|
||||
ret = omac1_aes_vector(key, key_len, 1, &addr[i], &len[i],
|
||||
tmp2);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
dbl(tmp);
|
||||
xor(tmp, tmp2);
|
||||
}
|
||||
if (len[i] >= AES_BLOCK_SIZE) {
|
||||
buf = os_memdup(addr[i], len[i]);
|
||||
if (!buf)
|
||||
return -1;
|
||||
|
||||
xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
|
||||
data[0] = buf;
|
||||
ret = omac1_aes_vector(key, key_len, 1, data, &len[i], mac);
|
||||
bin_clear_free(buf, len[i]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
dbl(tmp);
|
||||
pad_block(tmp2, addr[i], len[i]);
|
||||
xor(tmp, tmp2);
|
||||
|
||||
data[0] = tmp;
|
||||
data_len[0] = sizeof(tmp);
|
||||
return omac1_aes_vector(key, key_len, 1, data, data_len, mac);
|
||||
}
|
||||
|
||||
|
||||
int aes_siv_encrypt(const u8 *key, size_t key_len,
|
||||
const u8 *pw, size_t pwlen,
|
||||
size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *out)
|
||||
{
|
||||
const u8 *_addr[6];
|
||||
size_t _len[6];
|
||||
const u8 *k1, *k2;
|
||||
u8 v[AES_BLOCK_SIZE];
|
||||
size_t i;
|
||||
u8 *iv, *crypt_pw;
|
||||
|
||||
if (num_elem > ARRAY_SIZE(_addr) - 1 ||
|
||||
(key_len != 32 && key_len != 48 && key_len != 64))
|
||||
return -1;
|
||||
|
||||
key_len /= 2;
|
||||
k1 = key;
|
||||
k2 = key + key_len;
|
||||
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
_addr[i] = addr[i];
|
||||
_len[i] = len[i];
|
||||
}
|
||||
_addr[num_elem] = pw;
|
||||
_len[num_elem] = pwlen;
|
||||
|
||||
if (aes_s2v(k1, key_len, num_elem + 1, _addr, _len, v))
|
||||
return -1;
|
||||
|
||||
iv = out;
|
||||
crypt_pw = out + AES_BLOCK_SIZE;
|
||||
|
||||
os_memcpy(iv, v, AES_BLOCK_SIZE);
|
||||
os_memcpy(crypt_pw, pw, pwlen);
|
||||
|
||||
/* zero out 63rd and 31st bits of ctr (from right) */
|
||||
v[8] &= 0x7f;
|
||||
v[12] &= 0x7f;
|
||||
return aes_ctr_encrypt(k2, key_len, v, crypt_pw, pwlen);
|
||||
}
|
||||
|
||||
|
||||
int aes_siv_decrypt(const u8 *key, size_t key_len,
|
||||
const u8 *iv_crypt, size_t iv_c_len,
|
||||
size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *out)
|
||||
{
|
||||
const u8 *_addr[6];
|
||||
size_t _len[6];
|
||||
const u8 *k1, *k2;
|
||||
size_t crypt_len;
|
||||
size_t i;
|
||||
int ret;
|
||||
u8 iv[AES_BLOCK_SIZE];
|
||||
u8 check[AES_BLOCK_SIZE];
|
||||
|
||||
if (iv_c_len < AES_BLOCK_SIZE || num_elem > ARRAY_SIZE(_addr) - 1 ||
|
||||
(key_len != 32 && key_len != 48 && key_len != 64))
|
||||
return -1;
|
||||
crypt_len = iv_c_len - AES_BLOCK_SIZE;
|
||||
key_len /= 2;
|
||||
k1 = key;
|
||||
k2 = key + key_len;
|
||||
|
||||
for (i = 0; i < num_elem; i++) {
|
||||
_addr[i] = addr[i];
|
||||
_len[i] = len[i];
|
||||
}
|
||||
_addr[num_elem] = out;
|
||||
_len[num_elem] = crypt_len;
|
||||
|
||||
os_memcpy(iv, iv_crypt, AES_BLOCK_SIZE);
|
||||
os_memcpy(out, iv_crypt + AES_BLOCK_SIZE, crypt_len);
|
||||
|
||||
iv[8] &= 0x7f;
|
||||
iv[12] &= 0x7f;
|
||||
|
||||
ret = aes_ctr_encrypt(k2, key_len, iv, out, crypt_len);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = aes_s2v(k1, key_len, num_elem + 1, _addr, _len, check);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (os_memcmp(check, iv_crypt, AES_BLOCK_SIZE) == 0)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
21
components/wpa_supplicant/src/crypto/aes_siv.h
Normal file
21
components/wpa_supplicant/src/crypto/aes_siv.h
Normal file
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* AES SIV (RFC 5297)
|
||||
* Copyright (c) 2013 Cozybit, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef AES_SIV_H
|
||||
#define AES_SIV_H
|
||||
|
||||
int aes_siv_encrypt(const u8 *key, size_t key_len,
|
||||
const u8 *pw, size_t pwlen,
|
||||
size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *out);
|
||||
int aes_siv_decrypt(const u8 *key, size_t key_len,
|
||||
const u8 *iv_crypt, size_t iv_c_len,
|
||||
size_t num_elem, const u8 *addr[], const size_t *len,
|
||||
u8 *out);
|
||||
|
||||
#endif /* AES_SIV_H */
|
@@ -35,6 +35,8 @@ int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
|
||||
int __must_check omac1_aes_256(const u8 *key, const u8 *data, size_t data_len,
|
||||
u8 *mac);
|
||||
int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
|
||||
int __must_check aes_ctr_encrypt(const u8 *key, size_t key_len, const u8 *nonce,
|
||||
u8 *data, size_t data_len);
|
||||
int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
|
||||
u8 *data, size_t data_len);
|
||||
int __must_check aes_128_eax_encrypt(const u8 *key,
|
||||
|
@@ -468,18 +468,6 @@ int rc4_skip(const u8 *key, size_t keylen, size_t skip,
|
||||
u8 *data, size_t data_len);
|
||||
|
||||
|
||||
/**
|
||||
* crypto_get_random - Generate cryptographically strong pseudy-random bytes
|
||||
* @buf: Buffer for data
|
||||
* @len: Number of bytes to generate
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* If the PRNG does not have enough entropy to ensure unpredictable byte
|
||||
* sequence, this functions must return -1.
|
||||
*/
|
||||
int crypto_get_random(void *buf, size_t len);
|
||||
|
||||
|
||||
/**
|
||||
* struct crypto_bignum - bignum
|
||||
*
|
||||
@@ -488,6 +476,14 @@ int crypto_get_random(void *buf, size_t len);
|
||||
*/
|
||||
struct crypto_bignum;
|
||||
|
||||
/**
|
||||
* struct crypto_key - key
|
||||
*
|
||||
* Internal data structure for ssl key. The contents is specific
|
||||
* to the used crypto library.
|
||||
*/
|
||||
struct crypto_key;
|
||||
|
||||
/**
|
||||
* crypto_bignum_init - Allocate memory for bignum
|
||||
* Returns: Pointer to allocated bignum or %NULL on failure
|
||||
@@ -825,5 +821,217 @@ int crypto_ec_point_cmp(const struct crypto_ec *e,
|
||||
const struct crypto_ec_point *a,
|
||||
const struct crypto_ec_point *b);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_publickey_buf - Write EC public key to buffer
|
||||
* @key: crypto key
|
||||
* @key_buf: key buffer
|
||||
* @len: length of buffer
|
||||
* Returns: 0 on success, non-zero otherwise
|
||||
*/
|
||||
int crypto_ec_get_publickey_buf(struct crypto_key *key, u8 *key_buf, int len);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_group_from_key - Write EC group from key
|
||||
* @key: crypto key
|
||||
* Returns: EC group
|
||||
*/
|
||||
struct crypto_ec_group *crypto_ec_get_group_from_key(struct crypto_key *key);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_private_key - Get EC private key (in bignum format)
|
||||
* @key: crypto key
|
||||
* Returns: Private key
|
||||
*/
|
||||
struct crypto_bignum *crypto_ec_get_private_key(struct crypto_key *key);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_key - Read key from character stream
|
||||
* @privkey: Private key
|
||||
* @privkey_len: private key len
|
||||
* Returns: Crypto key
|
||||
*/
|
||||
struct crypto_key *crypto_ec_get_key(const u8 *privkey, size_t privkey_len);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_mbedtls_to_nist_group_id - get nist group from mbedtls internal group
|
||||
* @id: mbedtls group
|
||||
* Returns: NIST group
|
||||
*/
|
||||
unsigned int crypto_ec_get_mbedtls_to_nist_group_id(int id);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_curve_id - get curve id from ec group
|
||||
* @group: EC group
|
||||
* Returns: curve ID
|
||||
*/
|
||||
int crypto_ec_get_curve_id(const struct crypto_ec_group *group);
|
||||
|
||||
/**
|
||||
* crypto_ecdh: crypto ecdh
|
||||
* @key_own: own key
|
||||
* @key_peer: peer key
|
||||
* @secret: secret
|
||||
* @secret_len: secret len
|
||||
* Returns: 0 if success else negative value
|
||||
*/
|
||||
int crypto_ecdh(struct crypto_key *key_own, struct crypto_key *key_peer,
|
||||
u8 *secret, size_t *secret_len);
|
||||
|
||||
/**
|
||||
* crypto_ecdsa_get_sign: get crypto ecdsa signed hash
|
||||
* @hash: signed hash
|
||||
* @r: ecdsa r
|
||||
* @s: ecdsa s
|
||||
* @csign: csign
|
||||
* @hash_len: length of hash
|
||||
* Return: 0 if success else negative value
|
||||
*/
|
||||
int crypto_ecdsa_get_sign(unsigned char *hash,
|
||||
const struct crypto_bignum *r, const struct crypto_bignum *s,
|
||||
struct crypto_key *csign, int hash_len);
|
||||
|
||||
/**
|
||||
* crypto_edcsa_sign_verify: verify crypto ecdsa signed hash
|
||||
* @hash: signed hash
|
||||
* @r: ecdsa r
|
||||
* @s: ecdsa s
|
||||
* @csign: csign
|
||||
* @hlen: length of hash
|
||||
* Return: 0 if success else negative value
|
||||
*/
|
||||
int crypto_edcsa_sign_verify(const unsigned char *hash, const struct crypto_bignum *r,
|
||||
const struct crypto_bignum *s, struct crypto_key *csign, int hlen);
|
||||
|
||||
/**
|
||||
* crypto_ec_parse_subpub_key: get EC key context from sub public key
|
||||
* @p: data
|
||||
* @len: data len
|
||||
* Return: crypto_key
|
||||
*/
|
||||
struct crypto_key *crypto_ec_parse_subpub_key(const unsigned char *p, size_t len);
|
||||
|
||||
/**
|
||||
* crypto_is_ec_key: check whether a key is EC key or not
|
||||
* @key: crypto key
|
||||
* Return: true if key else false
|
||||
*/
|
||||
int crypto_is_ec_key(struct crypto_key *key);
|
||||
|
||||
/**
|
||||
* crypto_ec_gen_keypair: generate crypto ec keypair
|
||||
* @ike_group: grpup
|
||||
* Return: crypto key
|
||||
*/
|
||||
struct crypto_key * crypto_ec_gen_keypair(u16 ike_group);
|
||||
|
||||
/**
|
||||
* crypto_ec_write_pub_key: return public key in charater buffer
|
||||
* @key: crypto key
|
||||
* @der_len: buffer len
|
||||
* Return: public key buffer
|
||||
*/
|
||||
int crypto_ec_write_pub_key(struct crypto_key *key, unsigned char **key_buf);
|
||||
|
||||
/**
|
||||
* crypto_ec_set_pubkey_point: set bignum point on ec curve
|
||||
* @group: ec group
|
||||
* @buf: x,y coordinate
|
||||
* @len: length of x and y coordiate
|
||||
* Return : crypto key
|
||||
*/
|
||||
struct crypto_key * crypto_ec_set_pubkey_point(const struct crypto_ec_group *group,
|
||||
const u8 *buf, size_t len);
|
||||
/**
|
||||
* crypto_ec_free_key: free crypto key
|
||||
* Return : None
|
||||
*/
|
||||
void crypto_ec_free_key(struct crypto_key *key);
|
||||
/**
|
||||
* crypto_debug_print_ec_key: print ec key
|
||||
* @title: title
|
||||
* @key: crypto key
|
||||
* Return: None
|
||||
*/
|
||||
void crypto_debug_print_ec_key(const char *title, struct crypto_key *key);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_public_key: Public key from crypto key
|
||||
* @key: crypto key
|
||||
* Return : Public key
|
||||
*/
|
||||
struct crypto_ec_point *crypto_ec_get_public_key(struct crypto_key *key);
|
||||
|
||||
/**
|
||||
* crypto_get_order: free crypto key
|
||||
* Return : None
|
||||
*/
|
||||
int crypto_get_order(struct crypto_ec_group *group, struct crypto_bignum *x);
|
||||
|
||||
/**
|
||||
* crypto_bignum_addmod: a = (b + c) mod d
|
||||
* Return : 0 in success
|
||||
*/
|
||||
int crypto_bignum_addmod(struct crypto_bignum *a,
|
||||
struct crypto_bignum *b,
|
||||
struct crypto_bignum *c,
|
||||
struct crypto_bignum *d);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_affine_coordinates : get affine corrdinate of ec curve
|
||||
* @e: ec curve
|
||||
* @pt: point
|
||||
* @x: x coordinate
|
||||
* @y: y coordinate
|
||||
* Return : 0 if success
|
||||
*/
|
||||
int crypto_ec_get_affine_coordinates(struct crypto_ec *e, struct crypto_ec_point *pt,
|
||||
struct crypto_bignum *x, struct crypto_bignum *y);
|
||||
|
||||
/**
|
||||
* crypto_ec_get_group_byname: get ec curve group by name
|
||||
* @name: ec curve name
|
||||
* Return : EC group
|
||||
*/
|
||||
struct crypto_ec_group *crypto_ec_get_group_byname(const char *name);
|
||||
|
||||
/**
|
||||
* crypto_key_compare: check whether two keys belong to same
|
||||
* Return : 1 if yes else 0
|
||||
*/
|
||||
int crypto_key_compare(struct crypto_key *key1, struct crypto_key *key2);
|
||||
|
||||
/*
|
||||
* crypto_write_pubkey_der: get public key in der format
|
||||
* @csign: key
|
||||
* @key_buf: key buffer in charater format
|
||||
* Return : len of char buffer if success
|
||||
*/
|
||||
int crypto_write_pubkey_der(struct crypto_key *csign, unsigned char **key_buf);
|
||||
|
||||
/**
|
||||
* crypto_free_buffer: free buffer allocated by crypto API
|
||||
* @buf: buffer pointer
|
||||
* Return : None
|
||||
*/
|
||||
void crypto_free_buffer(unsigned char *buf);
|
||||
|
||||
/**
|
||||
* @crypto_ec_get_priv_key_der: get private key in der format
|
||||
* @key: key structure
|
||||
* @key_data: key data in charater buffer
|
||||
* @key_len = key lenght of charater buffer
|
||||
* Return : 0 if success
|
||||
*/
|
||||
int crypto_ec_get_priv_key_der(struct crypto_key *key, unsigned char **key_data, int *key_len);
|
||||
|
||||
/**
|
||||
* crypto_bignum_to_string: get big number in ascii format
|
||||
* @a: big number
|
||||
* @buf: buffer in which number will written to
|
||||
* @buflen: buffer length
|
||||
* @padlen: padding length
|
||||
* Return : 0 if success
|
||||
*/
|
||||
int crypto_bignum_to_string(const struct crypto_bignum *a,
|
||||
u8 *buf, size_t buflen, size_t padlen);
|
||||
#endif /* CRYPTO_H */
|
||||
|
277
components/wpa_supplicant/src/crypto/crypto_mbedtls-bignum.c
Normal file
277
components/wpa_supplicant/src/crypto/crypto_mbedtls-bignum.c
Normal file
@@ -0,0 +1,277 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_system.h"
|
||||
#include "mbedtls/bignum.h"
|
||||
#endif
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "crypto.h"
|
||||
#include "random.h"
|
||||
#include "sha256.h"
|
||||
#include "mbedtls/pk.h"
|
||||
|
||||
struct crypto_bignum *crypto_bignum_init(void)
|
||||
{
|
||||
mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi));
|
||||
if (bn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(bn);
|
||||
|
||||
return (struct crypto_bignum *)bn;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi));
|
||||
if (bn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(bn, buf, len));
|
||||
return (struct crypto_bignum *) bn;
|
||||
|
||||
cleanup:
|
||||
os_free(bn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
|
||||
{
|
||||
mbedtls_mpi_free((mbedtls_mpi *)n);
|
||||
os_free((mbedtls_mpi *)n);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_to_bin(const struct crypto_bignum *a,
|
||||
u8 *buf, size_t buflen, size_t padlen)
|
||||
{
|
||||
int num_bytes, offset;
|
||||
|
||||
if (padlen > buflen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_bytes = mbedtls_mpi_size((mbedtls_mpi *) a);
|
||||
|
||||
if ((size_t) num_bytes > buflen) {
|
||||
return -1;
|
||||
}
|
||||
if (padlen > (size_t) num_bytes) {
|
||||
offset = padlen - num_bytes;
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
os_memset(buf, 0, offset);
|
||||
mbedtls_mpi_write_binary((mbedtls_mpi *) a, buf + offset, mbedtls_mpi_size((mbedtls_mpi *)a) );
|
||||
|
||||
return num_bytes + offset;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_add(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_add_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ?
|
||||
-1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_mod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_mod_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_exptmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
const struct crypto_bignum *c,
|
||||
struct crypto_bignum *d)
|
||||
{
|
||||
return mbedtls_mpi_exp_mod((mbedtls_mpi *) d, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b, (const mbedtls_mpi *) c, NULL) ? -1 : 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_inverse(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_inv_mod((mbedtls_mpi *) c, (const mbedtls_mpi *) a,
|
||||
(const mbedtls_mpi *) b) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_sub(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_sub_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ?
|
||||
-1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_div(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_div_mpi((mbedtls_mpi *) c, NULL, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ?
|
||||
-1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_mulmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
const struct crypto_bignum *c,
|
||||
struct crypto_bignum *d)
|
||||
{
|
||||
int res;
|
||||
#if ALLOW_EVEN_MOD // Must enable this macro if c is even.
|
||||
mbedtls_mpi temp;
|
||||
mbedtls_mpi_init(&temp);
|
||||
|
||||
res = mbedtls_mpi_mul_mpi(&temp, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b);
|
||||
if (res) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = mbedtls_mpi_mod_mpi((mbedtls_mpi *) d, &temp, (mbedtls_mpi *) c);
|
||||
|
||||
mbedtls_mpi_free(&temp);
|
||||
#else
|
||||
// Works with odd modulus only, but it is faster with HW acceleration
|
||||
res = esp_mpi_mul_mpi_mod((mbedtls_mpi *) d, (mbedtls_mpi *) a, (mbedtls_mpi *) b, (mbedtls_mpi *) c);
|
||||
#endif
|
||||
return res ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_cmp(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b)
|
||||
{
|
||||
return mbedtls_mpi_cmp_mpi((const mbedtls_mpi *) a, (const mbedtls_mpi *) b);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_bits(const struct crypto_bignum *a)
|
||||
{
|
||||
return mbedtls_mpi_bitlen((const mbedtls_mpi *) a);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_is_zero(const struct crypto_bignum *a)
|
||||
{
|
||||
return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 0) == 0);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_is_one(const struct crypto_bignum *a)
|
||||
{
|
||||
return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 1) == 0);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_legendre(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *p)
|
||||
{
|
||||
mbedtls_mpi exp, tmp;
|
||||
int res = -2, ret;
|
||||
|
||||
mbedtls_mpi_init(&exp);
|
||||
mbedtls_mpi_init(&tmp);
|
||||
|
||||
/* exp = (p-1) / 2 */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *) p, 1));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 1));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&tmp, (const mbedtls_mpi *) a, &exp, (const mbedtls_mpi *) p, NULL));
|
||||
|
||||
if (mbedtls_mpi_cmp_int(&tmp, 1) == 0) {
|
||||
res = 1;
|
||||
} else if (mbedtls_mpi_cmp_int(&tmp, 0) == 0
|
||||
/* The below check is workaround for the case where HW
|
||||
* does not behave properly for X ^ A mod M when X is
|
||||
* power of M. Instead of returning value 0, value M is
|
||||
* returned.*/
|
||||
|| mbedtls_mpi_cmp_mpi(&tmp, (const mbedtls_mpi *)p) == 0) {
|
||||
res = 0;
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&tmp);
|
||||
mbedtls_mpi_free(&exp);
|
||||
return res;
|
||||
}
|
||||
|
||||
int crypto_bignum_to_string(const struct crypto_bignum *a,
|
||||
u8 *buf, size_t buflen, size_t padlen)
|
||||
{
|
||||
int num_bytes, offset;
|
||||
size_t outlen;
|
||||
|
||||
if (padlen > buflen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_bytes = mbedtls_mpi_size((mbedtls_mpi *) a);
|
||||
|
||||
if (padlen > (size_t) num_bytes) {
|
||||
offset = padlen - num_bytes;
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
os_memset(buf, 0, offset);
|
||||
mbedtls_mpi_write_string((mbedtls_mpi *) a, 16, (char *)(buf + offset),
|
||||
mbedtls_mpi_size((mbedtls_mpi *)a), &outlen);
|
||||
|
||||
return outlen;
|
||||
}
|
||||
|
||||
int crypto_bignum_addmod(struct crypto_bignum *a,
|
||||
struct crypto_bignum *b,
|
||||
struct crypto_bignum *c,
|
||||
struct crypto_bignum *d)
|
||||
{
|
||||
struct crypto_bignum *tmp = crypto_bignum_init();
|
||||
int ret = -1;
|
||||
|
||||
if (mbedtls_mpi_add_mpi((mbedtls_mpi *) tmp, (const mbedtls_mpi *) b, (const mbedtls_mpi *) c) < 0)
|
||||
goto fail;
|
||||
|
||||
if (mbedtls_mpi_mod_mpi( (mbedtls_mpi *) a, (const mbedtls_mpi *) tmp, (const mbedtls_mpi *) d) < 0)
|
||||
goto fail;
|
||||
|
||||
ret = 0;
|
||||
fail:
|
||||
crypto_bignum_deinit(tmp, 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void crypto_free_buffer(unsigned char *buf)
|
||||
{
|
||||
os_free(buf);
|
||||
}
|
987
components/wpa_supplicant/src/crypto/crypto_mbedtls-ec.c
Normal file
987
components/wpa_supplicant/src/crypto/crypto_mbedtls-ec.c
Normal file
@@ -0,0 +1,987 @@
|
||||
// Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_system.h"
|
||||
#include "mbedtls/bignum.h"
|
||||
#endif
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "crypto.h"
|
||||
#include "sha256.h"
|
||||
#include "random.h"
|
||||
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
|
||||
#include "mbedtls/pk.h"
|
||||
#include "mbedtls/ecdh.h"
|
||||
#include "mbedtls/sha256.h"
|
||||
#include "mbedtls/asn1write.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/oid.h"
|
||||
|
||||
#define ECP_PRV_DER_MAX_BYTES 29 + 3 * MBEDTLS_ECP_MAX_BYTES
|
||||
|
||||
#ifdef CONFIG_ECC
|
||||
struct crypto_ec {
|
||||
mbedtls_ecp_group group;
|
||||
};
|
||||
|
||||
int crypto_rng_wrapper(void *ctx, unsigned char *buf, size_t len)
|
||||
{
|
||||
return random_get_bytes(buf, len);
|
||||
}
|
||||
|
||||
struct crypto_ec *crypto_ec_init(int group)
|
||||
{
|
||||
struct crypto_ec *e;
|
||||
|
||||
mbedtls_ecp_group_id grp_id;
|
||||
|
||||
/* IANA registry to mbedtls internal mapping*/
|
||||
switch (group) {
|
||||
case IANA_SECP256R1:
|
||||
/* For now just support NIST-P256.
|
||||
* This is of type "short Weierstrass".
|
||||
*/
|
||||
grp_id = MBEDTLS_ECP_DP_SECP256R1;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
|
||||
}
|
||||
e = os_zalloc(sizeof(*e));
|
||||
if (e == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_ecp_group_init(&e->group);
|
||||
|
||||
if (mbedtls_ecp_group_load(&e->group, grp_id)) {
|
||||
crypto_ec_deinit(e);
|
||||
e = NULL;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void crypto_ec_deinit(struct crypto_ec *e)
|
||||
{
|
||||
if (e == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
mbedtls_ecp_group_free(&e->group);
|
||||
os_free(e);
|
||||
}
|
||||
|
||||
|
||||
struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e)
|
||||
{
|
||||
mbedtls_ecp_point *pt;
|
||||
if (e == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pt = os_zalloc(sizeof(mbedtls_ecp_point));
|
||||
|
||||
if( pt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_ecp_point_init(pt);
|
||||
|
||||
return (struct crypto_ec_point *) pt;
|
||||
}
|
||||
|
||||
|
||||
size_t crypto_ec_prime_len(struct crypto_ec *e)
|
||||
{
|
||||
return mbedtls_mpi_size(&e->group.P);
|
||||
}
|
||||
|
||||
|
||||
size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
|
||||
{
|
||||
return mbedtls_mpi_bitlen(&e->group.P);
|
||||
}
|
||||
struct crypto_ec_group *crypto_ec_get_group_byname(const char *name)
|
||||
{
|
||||
struct crypto_ec *e;
|
||||
const mbedtls_ecp_curve_info *curve = mbedtls_ecp_curve_info_from_name(name);
|
||||
|
||||
e = os_zalloc(sizeof(*e));
|
||||
if (e == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_ecp_group_init( &e->group );
|
||||
|
||||
if (mbedtls_ecp_group_load(&e->group, curve->grp_id)) {
|
||||
crypto_ec_deinit(e);
|
||||
e = NULL;
|
||||
}
|
||||
|
||||
return (struct crypto_ec_group *) &e->group;
|
||||
}
|
||||
|
||||
const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e)
|
||||
{
|
||||
return (const struct crypto_bignum *) &e->group.P;
|
||||
}
|
||||
|
||||
|
||||
const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e)
|
||||
{
|
||||
return (const struct crypto_bignum *) &e->group.N;
|
||||
}
|
||||
|
||||
|
||||
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
|
||||
{
|
||||
mbedtls_ecp_point_free((mbedtls_ecp_point *) p);
|
||||
os_free(p);
|
||||
}
|
||||
|
||||
int crypto_ec_point_to_bin(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *point, u8 *x, u8 *y)
|
||||
{
|
||||
int len = mbedtls_mpi_size(&e->group.P);
|
||||
|
||||
if (x) {
|
||||
if(crypto_bignum_to_bin((struct crypto_bignum *) & ((mbedtls_ecp_point *) point)->X,
|
||||
x, len, len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (y) {
|
||||
if(crypto_bignum_to_bin((struct crypto_bignum *) & ((mbedtls_ecp_point *) point)->Y,
|
||||
y, len, len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int crypto_ec_get_affine_coordinates(struct crypto_ec *e, struct crypto_ec_point *pt,
|
||||
struct crypto_bignum *x, struct crypto_bignum *y)
|
||||
{
|
||||
int ret = -1;
|
||||
mbedtls_ecp_point *point = (mbedtls_ecp_point *)pt;
|
||||
|
||||
if (!mbedtls_ecp_is_zero(point) && (mbedtls_mpi_cmp_int( &point->Z, 1 ) == 0 )) {
|
||||
// Affine coordinates mean that z should be 1,
|
||||
wpa_printf(MSG_ERROR, "Z coordinate is neither 0 or 1");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (x) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_copy((mbedtls_mpi*) x, &((mbedtls_ecp_point* )point)->X));
|
||||
}
|
||||
if (y) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_copy((mbedtls_mpi*) y, &((mbedtls_ecp_point* )point)->Y));
|
||||
}
|
||||
return 0;
|
||||
cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct crypto_ec_point *crypto_ec_point_from_bin(struct crypto_ec *e,
|
||||
const u8 *val)
|
||||
{
|
||||
mbedtls_ecp_point *pt;
|
||||
int len, ret;
|
||||
|
||||
if (e == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = mbedtls_mpi_size(&e->group.P);
|
||||
|
||||
pt = os_zalloc(sizeof(mbedtls_ecp_point));
|
||||
mbedtls_ecp_point_init(pt);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, val, len));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->Y, val + len, len));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset((&pt->Z), 1));
|
||||
|
||||
return (struct crypto_ec_point *) pt;
|
||||
|
||||
cleanup:
|
||||
mbedtls_ecp_point_free(pt);
|
||||
os_free(pt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
|
||||
const struct crypto_ec_point *b,
|
||||
struct crypto_ec_point *c)
|
||||
{
|
||||
int ret;
|
||||
mbedtls_mpi one;
|
||||
|
||||
mbedtls_mpi_init(&one);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &one, 1 ));
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&e->group, (mbedtls_ecp_point *) c, &one, (const mbedtls_ecp_point *)a , &one, (const mbedtls_ecp_point *)b));
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&one);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_ec_point *res)
|
||||
{
|
||||
int ret;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||
NULL, 0));
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&e->group,
|
||||
(mbedtls_ecp_point *) res,
|
||||
(const mbedtls_mpi *)b,
|
||||
(const mbedtls_ecp_point *)p,
|
||||
mbedtls_ctr_drbg_random,
|
||||
&ctr_drbg));
|
||||
cleanup:
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/* Currently mbedtls does not have any function for inverse
|
||||
* This function calculates inverse of a point.
|
||||
* Set R = -P
|
||||
*/
|
||||
static int ecp_opp(const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Copy */
|
||||
if (R != P) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P));
|
||||
}
|
||||
|
||||
/* In-place opposite */
|
||||
if (mbedtls_mpi_cmp_int(&R->Y, 0) != 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&R->Y, &grp->P, &R->Y));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return (ret );
|
||||
}
|
||||
|
||||
int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
|
||||
{
|
||||
return ecp_opp(&e->group, (mbedtls_ecp_point *) p, (mbedtls_ecp_point *) p) ? -1 : 0;
|
||||
}
|
||||
|
||||
int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
|
||||
struct crypto_ec_point *p,
|
||||
const struct crypto_bignum *x, int y_bit)
|
||||
{
|
||||
mbedtls_mpi temp;
|
||||
mbedtls_mpi *y_sqr, *y;
|
||||
mbedtls_mpi_init(&temp);
|
||||
int ret = 0;
|
||||
|
||||
y = &((mbedtls_ecp_point *)p)->Y;
|
||||
|
||||
/* Faster way to find sqrt
|
||||
* Works only with curves having prime p
|
||||
* such that p ≡ 3 (mod 4)
|
||||
* y_ = (y2 ^ ((p+1)/4)) mod p
|
||||
*
|
||||
* if LSB of both x and y are same: y = y_
|
||||
* else y = p - y_
|
||||
* y_bit is LSB of x
|
||||
*/
|
||||
y_bit = (y_bit != 0);
|
||||
|
||||
y_sqr = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, x);
|
||||
|
||||
if (y_sqr) {
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&temp, &e->group.P, 1));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(&temp, NULL, &temp, 4));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(y, y_sqr, &temp, &e->group.P, NULL));
|
||||
|
||||
if (y_bit != mbedtls_mpi_get_bit(y, 0))
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y));
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&((mbedtls_ecp_point* )p)->X, (const mbedtls_mpi*) x));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&((mbedtls_ecp_point *)p)->Z, 1));
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&temp);
|
||||
mbedtls_mpi_free(y_sqr);
|
||||
os_free(y_sqr);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
int crypto_get_order(struct crypto_ec_group *group, struct crypto_bignum *x)
|
||||
{
|
||||
return mbedtls_mpi_copy((mbedtls_mpi *) x, &((mbedtls_ecp_group *)group)->N);
|
||||
}
|
||||
|
||||
struct crypto_bignum *crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
|
||||
const struct crypto_bignum *x)
|
||||
{
|
||||
mbedtls_mpi temp, temp2, num;
|
||||
int ret = 0;
|
||||
|
||||
mbedtls_mpi *y_sqr = os_zalloc(sizeof(mbedtls_mpi));
|
||||
if (y_sqr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(&temp);
|
||||
mbedtls_mpi_init(&temp2);
|
||||
mbedtls_mpi_init(&num);
|
||||
mbedtls_mpi_init(y_sqr);
|
||||
|
||||
/* y^2 = x^3 + ax + b mod P*/
|
||||
/* mbedtls does not have mod-add or mod-mul apis.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Calculate x^3 mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, 3));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&temp, (const mbedtls_mpi *) x, &num, &e->group.P, NULL));
|
||||
|
||||
/* Calculate ax mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, -3));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *) x, &num));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P));
|
||||
|
||||
/* Calculate ax + b mod P. Note that b is already < P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &e->group.B));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P));
|
||||
|
||||
/* Calculate x^3 + ax + b mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &temp));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(y_sqr, &temp2, &e->group.P));
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&temp);
|
||||
mbedtls_mpi_free(&temp2);
|
||||
mbedtls_mpi_free(&num);
|
||||
if (ret) {
|
||||
mbedtls_mpi_free(y_sqr);
|
||||
os_free(y_sqr);
|
||||
return NULL;
|
||||
} else {
|
||||
return (struct crypto_bignum *) y_sqr;
|
||||
}
|
||||
}
|
||||
|
||||
int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *p)
|
||||
{
|
||||
return mbedtls_ecp_is_zero((mbedtls_ecp_point *) p);
|
||||
}
|
||||
|
||||
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *p)
|
||||
{
|
||||
mbedtls_mpi y_sqr_lhs, *y_sqr_rhs = NULL, two;
|
||||
int ret = 0, on_curve = 0;
|
||||
|
||||
mbedtls_mpi_init(&y_sqr_lhs);
|
||||
mbedtls_mpi_init(&two);
|
||||
|
||||
/* Calculate y^2 mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&two, 2));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&y_sqr_lhs, &((const mbedtls_ecp_point *)p)->Y , &two, &e->group.P, NULL));
|
||||
|
||||
y_sqr_rhs = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, (const struct crypto_bignum *) & ((const mbedtls_ecp_point *)p)->X);
|
||||
|
||||
if (y_sqr_rhs && (mbedtls_mpi_cmp_mpi(y_sqr_rhs, &y_sqr_lhs) == 0)) {
|
||||
on_curve = 1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&y_sqr_lhs);
|
||||
mbedtls_mpi_free(y_sqr_rhs);
|
||||
os_free(y_sqr_rhs);
|
||||
return (ret == 0) && (on_curve == 1);
|
||||
}
|
||||
|
||||
int crypto_ec_point_cmp(const struct crypto_ec *e,
|
||||
const struct crypto_ec_point *a,
|
||||
const struct crypto_ec_point *b)
|
||||
{
|
||||
return mbedtls_ecp_point_cmp((const mbedtls_ecp_point *) a,
|
||||
(const mbedtls_ecp_point *) b);
|
||||
}
|
||||
int crypto_key_compare(struct crypto_key *key1, struct crypto_key *key2)
|
||||
{
|
||||
if (mbedtls_pk_check_pair((mbedtls_pk_context *)key1, (mbedtls_pk_context *)key2) < 0)
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void crypto_debug_print_point(const char *title, struct crypto_ec *e,
|
||||
const struct crypto_ec_point *point)
|
||||
{
|
||||
u8 x[32], y[32];
|
||||
|
||||
if (crypto_ec_point_to_bin(e, point, x, y) < 0) {
|
||||
wpa_printf(MSG_ERROR, "error: failed to get corrdinates\n");
|
||||
return;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_ERROR, "x:", x, 32);
|
||||
wpa_hexdump(MSG_ERROR, "y:", y, 32);
|
||||
}
|
||||
|
||||
static struct crypto_key *crypto_alloc_key(void)
|
||||
{
|
||||
mbedtls_pk_context *key = os_malloc(sizeof(*key));
|
||||
|
||||
if (!key) {
|
||||
wpa_printf(MSG_ERROR, "%s: memory allocation failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
mbedtls_pk_init(key);
|
||||
|
||||
return (struct crypto_key *)key;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_key * crypto_ec_set_pubkey_point(const struct crypto_ec_group *group,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
mbedtls_ecp_point *point = NULL;
|
||||
struct crypto_key *pkey = NULL;
|
||||
int ret;
|
||||
mbedtls_pk_context *key = (mbedtls_pk_context *)crypto_alloc_key();
|
||||
|
||||
if (!key) {
|
||||
wpa_printf(MSG_ERROR, "%s: memory allocation failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
point = (mbedtls_ecp_point *)crypto_ec_point_from_bin((struct crypto_ec *)group, buf);
|
||||
if (crypto_ec_point_is_at_infinity((struct crypto_ec *)group, (struct crypto_ec_point *)point)) {
|
||||
wpa_printf(MSG_ERROR, "Point is at infinity");
|
||||
goto fail;
|
||||
}
|
||||
if (!crypto_ec_point_is_on_curve((struct crypto_ec *)group, (struct crypto_ec_point *)point)) {
|
||||
wpa_printf(MSG_ERROR, "Point not on curve");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (mbedtls_ecp_check_pubkey((mbedtls_ecp_group *)group, point) < 0) { //typecast
|
||||
// ideally should have failed in upper condition, duplicate code??
|
||||
wpa_printf(MSG_ERROR, "Invalid key");
|
||||
goto fail;
|
||||
}
|
||||
mbedtls_ecp_keypair *ecp_key = malloc(sizeof (*ecp_key));
|
||||
if (!ecp_key) {
|
||||
wpa_printf(MSG_ERROR, "key allocation failed");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Init keypair */
|
||||
mbedtls_ecp_keypair_init(ecp_key);
|
||||
// TODO Is it needed? check?
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_copy(&ecp_key->Q, point));
|
||||
|
||||
/* Assign values */
|
||||
if( ( ret = mbedtls_pk_setup( key,
|
||||
mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY) ) ) != 0 )
|
||||
goto fail;
|
||||
|
||||
if (key->pk_ctx)
|
||||
os_free(key->pk_ctx);
|
||||
key->pk_ctx = ecp_key;
|
||||
mbedtls_ecp_copy(&mbedtls_pk_ec(*key)->Q, point);
|
||||
mbedtls_ecp_group_load(&mbedtls_pk_ec(*key)->grp, MBEDTLS_ECP_DP_SECP256R1);
|
||||
|
||||
pkey = (struct crypto_key *)key;
|
||||
cleanup:
|
||||
crypto_ec_point_deinit((struct crypto_ec_point *)point, 0);
|
||||
return pkey;
|
||||
fail:
|
||||
if (point)
|
||||
crypto_ec_point_deinit((struct crypto_ec_point *)point, 0);
|
||||
if (key)
|
||||
mbedtls_pk_free(key);
|
||||
pkey = NULL;
|
||||
return pkey;
|
||||
}
|
||||
|
||||
|
||||
void crypto_ec_free_key(struct crypto_key *key)
|
||||
{
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
|
||||
mbedtls_pk_free(pkey);
|
||||
os_free(key);
|
||||
}
|
||||
|
||||
struct crypto_ec_point *crypto_ec_get_public_key(struct crypto_key *key)
|
||||
{
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
|
||||
|
||||
return (struct crypto_ec_point *)&mbedtls_pk_ec(*pkey)->Q;
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_get_priv_key_der(struct crypto_key *key, unsigned char **key_data, int *key_len)
|
||||
{
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
|
||||
char der_data[ECP_PRV_DER_MAX_BYTES];
|
||||
|
||||
*key_len = mbedtls_pk_write_key_der(pkey, (unsigned char *)der_data, ECP_PRV_DER_MAX_BYTES);
|
||||
if (!*key_len)
|
||||
return -1;
|
||||
|
||||
*key_data = os_malloc(*key_len);
|
||||
|
||||
if (!*key_data) {
|
||||
wpa_printf(MSG_ERROR, "memory allocation failed\n");
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(*key_data, der_data, *key_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct crypto_ec_group *crypto_ec_get_group_from_key(struct crypto_key *key)
|
||||
{
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
|
||||
|
||||
return (struct crypto_ec_group *)&(mbedtls_pk_ec(*pkey)->grp);
|
||||
}
|
||||
|
||||
struct crypto_bignum *crypto_ec_get_private_key(struct crypto_key *key)
|
||||
{
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
|
||||
|
||||
return ((struct crypto_bignum *)&(mbedtls_pk_ec(*pkey)->d));
|
||||
}
|
||||
|
||||
int crypto_ec_get_publickey_buf(struct crypto_key *key, u8 *key_buf, int len)
|
||||
{
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
|
||||
unsigned char buf[MBEDTLS_MPI_MAX_SIZE + 10]; /* tag, length + MPI */
|
||||
unsigned char *c = buf + sizeof(buf );
|
||||
size_t pk_len = 0;
|
||||
|
||||
memset(buf, 0, sizeof(buf) );
|
||||
pk_len = mbedtls_pk_write_pubkey( &c, buf, pkey);
|
||||
|
||||
if (!pk_len)
|
||||
return -1;
|
||||
|
||||
if (len == 0)
|
||||
return pk_len;
|
||||
|
||||
os_memcpy(key_buf, buf + MBEDTLS_MPI_MAX_SIZE + 10 - pk_len, pk_len);
|
||||
|
||||
return pk_len;
|
||||
}
|
||||
|
||||
int crypto_write_pubkey_der(struct crypto_key *key, unsigned char **key_buf)
|
||||
{
|
||||
unsigned char output_buf[1600] = {0};
|
||||
int len = mbedtls_pk_write_pubkey_der((mbedtls_pk_context *)key, output_buf, 1600);
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
|
||||
*key_buf = os_malloc(len);
|
||||
if (!*key_buf) {
|
||||
return 0;
|
||||
}
|
||||
os_memcpy(*key_buf, output_buf + 1600 - len, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
struct crypto_key *crypto_ec_get_key(const u8 *privkey, size_t privkey_len)
|
||||
{
|
||||
int ret;
|
||||
mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key();
|
||||
|
||||
if (!kctx) {
|
||||
wpa_printf(MSG_ERROR, "memory allocation failed\n");
|
||||
return NULL;
|
||||
}
|
||||
ret = mbedtls_pk_parse_key(kctx, privkey, privkey_len, NULL, 0);
|
||||
|
||||
if (ret < 0) {
|
||||
//crypto_print_error_string(ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return (struct crypto_key *)kctx;
|
||||
|
||||
fail:
|
||||
mbedtls_pk_free(kctx);
|
||||
os_free(kctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned int crypto_ec_get_mbedtls_to_nist_group_id(int id)
|
||||
{
|
||||
unsigned int nist_grpid = 0;
|
||||
switch (id) {
|
||||
case MBEDTLS_ECP_DP_SECP256R1:
|
||||
nist_grpid = 19;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_SECP384R1:
|
||||
nist_grpid = 20;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_SECP521R1:
|
||||
nist_grpid = 21;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_BP256R1:
|
||||
nist_grpid = 28;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_BP384R1:
|
||||
nist_grpid = 29;
|
||||
break;
|
||||
case MBEDTLS_ECP_DP_BP512R1:
|
||||
nist_grpid = 30;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return nist_grpid;
|
||||
}
|
||||
|
||||
int crypto_ec_get_curve_id(const struct crypto_ec_group *group)
|
||||
{
|
||||
mbedtls_ecp_group *grp = (mbedtls_ecp_group *)group;
|
||||
return (crypto_ec_get_mbedtls_to_nist_group_id(grp->id));
|
||||
}
|
||||
|
||||
int crypto_ecdh(struct crypto_key *key_own, struct crypto_key *key_peer,
|
||||
u8 *secret, size_t *secret_len)
|
||||
{
|
||||
mbedtls_ecdh_context *ctx;
|
||||
mbedtls_pk_context *own = (mbedtls_pk_context *)key_own;
|
||||
mbedtls_pk_context *peer = (mbedtls_pk_context *)key_peer;
|
||||
|
||||
int ret = -1;
|
||||
|
||||
*secret_len = 0;
|
||||
ctx = os_malloc(sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
wpa_printf(MSG_ERROR, "DPP: EVP_PKEY_CTX_new failed: %s",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
mbedtls_ecdh_init(ctx);
|
||||
/* No need to setup, done through mbedtls_ecdh_get_params */
|
||||
|
||||
/* set params from our key */
|
||||
if (mbedtls_ecdh_get_params(ctx, mbedtls_pk_ec(*own), MBEDTLS_ECDH_OURS) < 0) {
|
||||
wpa_printf(MSG_ERROR, "failed to set our ecdh params\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
#ifndef DPP_MAX_SHARED_SECRET_LEN
|
||||
#define DPP_MAX_SHARED_SECRET_LEN 66
|
||||
#endif
|
||||
/* set params from peers key */
|
||||
if (mbedtls_ecdh_get_params(ctx, mbedtls_pk_ec(*peer), MBEDTLS_ECDH_THEIRS) < 0) {
|
||||
wpa_printf(MSG_ERROR, "failed to set peer's ecdh params\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (mbedtls_ecdh_calc_secret(ctx, secret_len, secret, DPP_MAX_SHARED_SECRET_LEN, NULL, NULL) < 0) {
|
||||
wpa_printf(MSG_ERROR, "failed to calculate secret\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (*secret_len > DPP_MAX_SHARED_SECRET_LEN) {
|
||||
wpa_printf(MSG_ERROR, "secret len=%d is too big\n", *secret_len);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
fail:
|
||||
mbedtls_ecdh_free(ctx);
|
||||
os_free(ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int crypto_ecdsa_get_sign(unsigned char *hash,
|
||||
const struct crypto_bignum *r, const struct crypto_bignum *s, struct crypto_key *csign, int hash_len)
|
||||
{
|
||||
int ret = -1;
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)csign;
|
||||
|
||||
mbedtls_ecdsa_context *ctx = os_malloc(sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
wpa_printf(MSG_ERROR,"failed to allcate memory\n");
|
||||
return -1;
|
||||
}
|
||||
mbedtls_ecdsa_init(ctx);
|
||||
|
||||
if (mbedtls_ecdsa_from_keypair(ctx, mbedtls_pk_ec(*pkey)) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
ret = mbedtls_ecdsa_sign(&ctx->grp, (mbedtls_mpi *)r, (mbedtls_mpi *)s,
|
||||
&ctx->d, hash, SHA256_MAC_LEN, crypto_rng_wrapper, NULL);
|
||||
|
||||
fail:
|
||||
mbedtls_ecdsa_free(ctx);
|
||||
os_free(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int crypto_edcsa_sign_verify(const unsigned char *hash,
|
||||
const struct crypto_bignum *r, const struct crypto_bignum *s, struct crypto_key *csign, int hlen)
|
||||
{
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)csign;
|
||||
int ret = 0;
|
||||
|
||||
mbedtls_ecdsa_context *ctx = os_malloc(sizeof(*ctx));
|
||||
if (!ctx) {
|
||||
wpa_printf(MSG_ERROR, "failed to allcate memory\n");
|
||||
return ret;
|
||||
}
|
||||
mbedtls_ecdsa_init(ctx);
|
||||
|
||||
if (mbedtls_ecdsa_from_keypair(ctx, mbedtls_pk_ec(*pkey)) < 0)
|
||||
return ret;
|
||||
|
||||
if((ret = mbedtls_ecdsa_verify(&ctx->grp, hash, hlen,
|
||||
&ctx->Q, (mbedtls_mpi *)r, (mbedtls_mpi *)s)) != 0){
|
||||
wpa_printf(MSG_ERROR, "ecdsa verification failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
mbedtls_ecdsa_free(ctx);
|
||||
os_free(ctx);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void crypto_debug_print_ec_key(const char *title, struct crypto_key *key)
|
||||
{
|
||||
#ifdef DEBUG_PRINT
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)key;
|
||||
mbedtls_ecp_keypair *ecp = mbedtls_pk_ec( *pkey );
|
||||
u8 x[32], y[32], d[32];
|
||||
wpa_printf(MSG_ERROR, "curve: %s\n",
|
||||
mbedtls_ecp_curve_info_from_grp_id( ecp->grp.id )->name );
|
||||
int len = mbedtls_mpi_size((mbedtls_mpi *)crypto_ec_get_prime((struct crypto_ec *)crypto_ec_get_group_from_key(key)));
|
||||
|
||||
wpa_printf(MSG_ERROR, "prime len is %d\n", len);
|
||||
crypto_ec_point_to_bin((struct crypto_ec *)crypto_ec_get_group_from_key(key), crypto_ec_get_public_key(key), x, y);
|
||||
crypto_bignum_to_bin(crypto_ec_get_private_key(key),
|
||||
d, len, len);
|
||||
wpa_hexdump(MSG_ERROR, "Q_x:", x, 32);
|
||||
wpa_hexdump(MSG_ERROR, "Q_y:", y, 32);
|
||||
wpa_hexdump(MSG_ERROR, "d: ", d , 32);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct crypto_key *crypto_ec_parse_subpub_key(const unsigned char *p, size_t len)
|
||||
{
|
||||
int ret;
|
||||
mbedtls_pk_context *pkey = (mbedtls_pk_context *)crypto_alloc_key();
|
||||
ret = mbedtls_pk_parse_subpubkey((unsigned char **)&p, p + len, pkey);
|
||||
|
||||
if (ret < 0) {
|
||||
os_free(pkey);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (struct crypto_key *)pkey;
|
||||
}
|
||||
|
||||
int crypto_is_ec_key(struct crypto_key *key)
|
||||
{
|
||||
int ret = mbedtls_pk_can_do((mbedtls_pk_context *)key, MBEDTLS_PK_ECKEY);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct crypto_key * crypto_ec_gen_keypair(u16 ike_group)
|
||||
{
|
||||
mbedtls_pk_context *kctx = (mbedtls_pk_context *)crypto_alloc_key();
|
||||
|
||||
if (!kctx) {
|
||||
wpa_printf(MSG_ERROR, "%s: memory allocation failed\n", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(mbedtls_pk_setup(kctx,
|
||||
mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) != 0 )
|
||||
goto fail;
|
||||
|
||||
mbedtls_ecp_gen_key(MBEDTLS_ECP_DP_SECP256R1, mbedtls_pk_ec(*kctx), //get this from argument
|
||||
crypto_rng_wrapper, NULL);
|
||||
|
||||
return (struct crypto_key *)kctx;
|
||||
fail:
|
||||
mbedtls_pk_free(kctx);
|
||||
os_free(kctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* ECParameters ::= CHOICE {
|
||||
* namedCurve OBJECT IDENTIFIER
|
||||
* }
|
||||
*/
|
||||
static int pk_write_ec_param( unsigned char **p, unsigned char *start,
|
||||
mbedtls_ecp_keypair *ec )
|
||||
{
|
||||
int ret;
|
||||
size_t len = 0;
|
||||
const char *oid;
|
||||
size_t oid_len;
|
||||
|
||||
if( ( ret = mbedtls_oid_get_oid_by_ec_grp( ec->grp.id, &oid, &oid_len ) ) != 0 )
|
||||
return( ret );
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_oid( p, start, oid, oid_len ) );
|
||||
|
||||
return( (int) len );
|
||||
}
|
||||
|
||||
static int pk_write_ec_pubkey_formatted( unsigned char **p, unsigned char *start,
|
||||
mbedtls_ecp_keypair *ec, int format )
|
||||
{
|
||||
int ret;
|
||||
size_t len = 0;
|
||||
unsigned char buf[MBEDTLS_ECP_MAX_PT_LEN];
|
||||
|
||||
if( ( ret = mbedtls_ecp_point_write_binary( &ec->grp, &ec->Q,
|
||||
format,
|
||||
&len, buf, sizeof( buf ) ) ) != 0 )
|
||||
{
|
||||
return( ret );
|
||||
}
|
||||
|
||||
if( *p < start || (size_t)( *p - start ) < len )
|
||||
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
|
||||
|
||||
*p -= len;
|
||||
memcpy( *p, buf, len );
|
||||
|
||||
return( (int) len );
|
||||
}
|
||||
|
||||
int mbedtls_pk_write_pubkey_formatted( unsigned char **p, unsigned char *start,
|
||||
const mbedtls_pk_context *key, int format )
|
||||
{
|
||||
int ret;
|
||||
size_t len = 0;
|
||||
|
||||
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY )
|
||||
MBEDTLS_ASN1_CHK_ADD( len, pk_write_ec_pubkey_formatted( p, start, mbedtls_pk_ec( *key ), format ) );
|
||||
else
|
||||
return( MBEDTLS_ERR_PK_FEATURE_UNAVAILABLE );
|
||||
|
||||
return( (int) len );
|
||||
}
|
||||
|
||||
int crypto_pk_write_formatted_pubkey_der(mbedtls_pk_context *key, unsigned char *buf, size_t size, int format)
|
||||
{
|
||||
int ret;
|
||||
unsigned char *c;
|
||||
size_t len = 0, par_len = 0, oid_len;
|
||||
const char *oid;
|
||||
|
||||
if( size == 0 )
|
||||
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
|
||||
|
||||
c = buf + size;
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_pk_write_pubkey_formatted( &c, buf, key, format) );
|
||||
|
||||
if( c - buf < 1 )
|
||||
return( MBEDTLS_ERR_ASN1_BUF_TOO_SMALL );
|
||||
|
||||
/*
|
||||
* SubjectPublicKeyInfo ::= SEQUENCE {
|
||||
* algorithm AlgorithmIdentifier,
|
||||
* subjectPublicKey BIT STRING }
|
||||
*/
|
||||
*--c = 0;
|
||||
len += 1;
|
||||
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
|
||||
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_BIT_STRING ) );
|
||||
|
||||
if( ( ret = mbedtls_oid_get_oid_by_pk_alg( mbedtls_pk_get_type( key ),
|
||||
&oid, &oid_len ) ) != 0 )
|
||||
{
|
||||
return( ret );
|
||||
}
|
||||
|
||||
if( mbedtls_pk_get_type( key ) == MBEDTLS_PK_ECKEY )
|
||||
{
|
||||
MBEDTLS_ASN1_CHK_ADD( par_len, pk_write_ec_param( &c, buf, mbedtls_pk_ec( *key ) ) );
|
||||
}
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_algorithm_identifier( &c, buf, oid, oid_len,
|
||||
par_len ) );
|
||||
|
||||
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_len( &c, buf, len ) );
|
||||
MBEDTLS_ASN1_CHK_ADD( len, mbedtls_asn1_write_tag( &c, buf, MBEDTLS_ASN1_CONSTRUCTED |
|
||||
MBEDTLS_ASN1_SEQUENCE ) );
|
||||
|
||||
return( (int) len );
|
||||
}
|
||||
|
||||
int crypto_ec_write_pub_key(struct crypto_key *key, unsigned char **key_buf)
|
||||
{
|
||||
unsigned char output_buf[1600] = {0};
|
||||
int len = crypto_pk_write_formatted_pubkey_der((mbedtls_pk_context *)key, output_buf, 1600, 1);
|
||||
if (len <= 0)
|
||||
return 0;
|
||||
|
||||
*key_buf = os_malloc(len);
|
||||
if (!*key_buf) {
|
||||
wpa_printf(MSG_ERROR, "%s: memory allocation failed\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
os_memcpy(*key_buf, output_buf + 1600 - len, len);
|
||||
|
||||
return len;
|
||||
}
|
||||
#endif /* CONFIG_ECC */
|
@@ -1,605 +0,0 @@
|
||||
// Copyright 2015-2018 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_system.h"
|
||||
#include "mbedtls/bignum.h"
|
||||
#endif
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
#include "crypto.h"
|
||||
|
||||
#include "mbedtls/ecp.h"
|
||||
#include "mbedtls/entropy.h"
|
||||
#include "mbedtls/ctr_drbg.h"
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
int crypto_get_random(void *buf, size_t len)
|
||||
{
|
||||
if (!buf) {
|
||||
return -1;
|
||||
}
|
||||
esp_fill_random(buf, len);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct crypto_bignum *crypto_bignum_init(void)
|
||||
{
|
||||
mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi));
|
||||
if (bn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(bn);
|
||||
|
||||
return (struct crypto_bignum *)bn;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_bignum *crypto_bignum_init_set(const u8 *buf, size_t len)
|
||||
{
|
||||
int ret = 0;
|
||||
mbedtls_mpi *bn = os_zalloc(sizeof(mbedtls_mpi));
|
||||
if (bn == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(bn, buf, len));
|
||||
return (struct crypto_bignum *) bn;
|
||||
|
||||
cleanup:
|
||||
os_free(bn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void crypto_bignum_deinit(struct crypto_bignum *n, int clear)
|
||||
{
|
||||
mbedtls_mpi_free((mbedtls_mpi *)n);
|
||||
os_free((mbedtls_mpi *)n);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_to_bin(const struct crypto_bignum *a,
|
||||
u8 *buf, size_t buflen, size_t padlen)
|
||||
{
|
||||
int num_bytes, offset;
|
||||
|
||||
if (padlen > buflen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
num_bytes = mbedtls_mpi_size((mbedtls_mpi *) a);
|
||||
|
||||
if ((size_t) num_bytes > buflen) {
|
||||
return -1;
|
||||
}
|
||||
if (padlen > (size_t) num_bytes) {
|
||||
offset = padlen - num_bytes;
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
os_memset(buf, 0, offset);
|
||||
mbedtls_mpi_write_binary((mbedtls_mpi *) a, buf + offset, mbedtls_mpi_size((mbedtls_mpi *)a) );
|
||||
|
||||
return num_bytes + offset;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_add(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_add_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ?
|
||||
-1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_mod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_mod_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_exptmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
const struct crypto_bignum *c,
|
||||
struct crypto_bignum *d)
|
||||
{
|
||||
return mbedtls_mpi_exp_mod((mbedtls_mpi *) d, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b, (const mbedtls_mpi *) c, NULL) ? -1 : 0;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_inverse(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_inv_mod((mbedtls_mpi *) c, (const mbedtls_mpi *) a,
|
||||
(const mbedtls_mpi *) b) ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_sub(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_sub_mpi((mbedtls_mpi *) c, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ?
|
||||
-1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_div(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
return mbedtls_mpi_div_mpi((mbedtls_mpi *) c, NULL, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b) ?
|
||||
-1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_mulmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
const struct crypto_bignum *c,
|
||||
struct crypto_bignum *d)
|
||||
{
|
||||
int res;
|
||||
#if ALLOW_EVEN_MOD // Must enable this macro if c is even.
|
||||
mbedtls_mpi temp;
|
||||
mbedtls_mpi_init(&temp);
|
||||
|
||||
res = mbedtls_mpi_mul_mpi(&temp, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b);
|
||||
if (res) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = mbedtls_mpi_mod_mpi((mbedtls_mpi *) d, &temp, (mbedtls_mpi *) c);
|
||||
|
||||
mbedtls_mpi_free(&temp);
|
||||
#else
|
||||
// Works with odd modulus only, but it is faster with HW acceleration
|
||||
res = esp_mpi_mul_mpi_mod((mbedtls_mpi *) d, (mbedtls_mpi *) a, (mbedtls_mpi *) b, (mbedtls_mpi *) c);
|
||||
#endif
|
||||
return res ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_cmp(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b)
|
||||
{
|
||||
return mbedtls_mpi_cmp_mpi((const mbedtls_mpi *) a, (const mbedtls_mpi *) b);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_bits(const struct crypto_bignum *a)
|
||||
{
|
||||
return mbedtls_mpi_bitlen((const mbedtls_mpi *) a);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_is_zero(const struct crypto_bignum *a)
|
||||
{
|
||||
return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 0) == 0);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_is_one(const struct crypto_bignum *a)
|
||||
{
|
||||
return (mbedtls_mpi_cmp_int((const mbedtls_mpi *) a, 1) == 0);
|
||||
}
|
||||
|
||||
|
||||
int crypto_bignum_legendre(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *p)
|
||||
{
|
||||
mbedtls_mpi exp, tmp;
|
||||
int res = -2, ret;
|
||||
|
||||
mbedtls_mpi_init(&exp);
|
||||
mbedtls_mpi_init(&tmp);
|
||||
|
||||
/* exp = (p-1) / 2 */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_int(&exp, (const mbedtls_mpi *) p, 1));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&exp, 1));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&tmp, (const mbedtls_mpi *) a, &exp, (const mbedtls_mpi *) p, NULL));
|
||||
|
||||
if (mbedtls_mpi_cmp_int(&tmp, 1) == 0) {
|
||||
res = 1;
|
||||
} else if (mbedtls_mpi_cmp_int(&tmp, 0) == 0
|
||||
/* The below check is workaround for the case where HW
|
||||
* does not behave properly for X ^ A mod M when X is
|
||||
* power of M. Instead of returning value 0, value M is
|
||||
* returned.*/
|
||||
|| mbedtls_mpi_cmp_mpi(&tmp, (const mbedtls_mpi *)p) == 0) {
|
||||
res = 0;
|
||||
} else {
|
||||
res = -1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&tmp);
|
||||
mbedtls_mpi_free(&exp);
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_ECC
|
||||
struct crypto_ec {
|
||||
mbedtls_ecp_group group;
|
||||
};
|
||||
|
||||
struct crypto_ec *crypto_ec_init(int group)
|
||||
{
|
||||
struct crypto_ec *e;
|
||||
|
||||
mbedtls_ecp_group_id grp_id;
|
||||
|
||||
/* IANA registry to mbedtls internal mapping*/
|
||||
switch (group) {
|
||||
case IANA_SECP256R1:
|
||||
/* For now just support NIST-P256.
|
||||
* This is of type "short Weierstrass".
|
||||
*/
|
||||
grp_id = MBEDTLS_ECP_DP_SECP256R1;
|
||||
break;
|
||||
default:
|
||||
return NULL;
|
||||
|
||||
}
|
||||
e = os_zalloc(sizeof(*e));
|
||||
if (e == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_ecp_group_init(&e->group);
|
||||
|
||||
if (mbedtls_ecp_group_load(&e->group, grp_id)) {
|
||||
crypto_ec_deinit(e);
|
||||
e = NULL;
|
||||
}
|
||||
|
||||
return e;
|
||||
}
|
||||
|
||||
|
||||
void crypto_ec_deinit(struct crypto_ec *e)
|
||||
{
|
||||
if (e == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
mbedtls_ecp_group_free(&e->group);
|
||||
os_free(e);
|
||||
}
|
||||
|
||||
|
||||
struct crypto_ec_point *crypto_ec_point_init(struct crypto_ec *e)
|
||||
{
|
||||
mbedtls_ecp_point *pt;
|
||||
if (e == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pt = os_zalloc(sizeof(mbedtls_ecp_point));
|
||||
|
||||
if( pt == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_ecp_point_init(pt);
|
||||
|
||||
return (struct crypto_ec_point *) pt;
|
||||
}
|
||||
|
||||
|
||||
size_t crypto_ec_prime_len(struct crypto_ec *e)
|
||||
{
|
||||
return mbedtls_mpi_size(&e->group.P);
|
||||
}
|
||||
|
||||
|
||||
size_t crypto_ec_prime_len_bits(struct crypto_ec *e)
|
||||
{
|
||||
return mbedtls_mpi_bitlen(&e->group.P);
|
||||
}
|
||||
|
||||
|
||||
const struct crypto_bignum *crypto_ec_get_prime(struct crypto_ec *e)
|
||||
{
|
||||
return (const struct crypto_bignum *) &e->group.P;
|
||||
}
|
||||
|
||||
|
||||
const struct crypto_bignum *crypto_ec_get_order(struct crypto_ec *e)
|
||||
{
|
||||
return (const struct crypto_bignum *) &e->group.N;
|
||||
}
|
||||
|
||||
|
||||
void crypto_ec_point_deinit(struct crypto_ec_point *p, int clear)
|
||||
{
|
||||
mbedtls_ecp_point_free((mbedtls_ecp_point *) p);
|
||||
os_free(p);
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_point_to_bin(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *point, u8 *x, u8 *y)
|
||||
{
|
||||
int len = mbedtls_mpi_size(&e->group.P);
|
||||
|
||||
if (x) {
|
||||
if(crypto_bignum_to_bin((struct crypto_bignum *) & ((mbedtls_ecp_point *) point)->X,
|
||||
x, len, len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (y) {
|
||||
if(crypto_bignum_to_bin((struct crypto_bignum *) & ((mbedtls_ecp_point *) point)->Y,
|
||||
y, len, len) < 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct crypto_ec_point *crypto_ec_point_from_bin(struct crypto_ec *e,
|
||||
const u8 *val)
|
||||
{
|
||||
mbedtls_ecp_point *pt;
|
||||
int len, ret;
|
||||
|
||||
if (e == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
len = mbedtls_mpi_size(&e->group.P);
|
||||
|
||||
pt = os_zalloc(sizeof(mbedtls_ecp_point));
|
||||
mbedtls_ecp_point_init(pt);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->X, val, len));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary(&pt->Y, val + len, len));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset((&pt->Z), 1));
|
||||
|
||||
return (struct crypto_ec_point *) pt;
|
||||
|
||||
cleanup:
|
||||
mbedtls_ecp_point_free(pt);
|
||||
os_free(pt);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
|
||||
const struct crypto_ec_point *b,
|
||||
struct crypto_ec_point *c)
|
||||
{
|
||||
int ret;
|
||||
mbedtls_mpi one;
|
||||
|
||||
mbedtls_mpi_init(&one);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &one, 1 ));
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_muladd(&e->group, (mbedtls_ecp_point *) c, &one, (const mbedtls_ecp_point *)a , &one, (const mbedtls_ecp_point *)b));
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&one);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_ec_point *res)
|
||||
{
|
||||
int ret;
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||
NULL, 0));
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_mul(&e->group,
|
||||
(mbedtls_ecp_point *) res,
|
||||
(const mbedtls_mpi *)b,
|
||||
(const mbedtls_ecp_point *)p,
|
||||
mbedtls_ctr_drbg_random,
|
||||
&ctr_drbg));
|
||||
cleanup:
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
|
||||
/* Currently mbedtls does not have any function for inverse
|
||||
* This function calculates inverse of a point.
|
||||
* Set R = -P
|
||||
*/
|
||||
static int ecp_opp( const mbedtls_ecp_group *grp, mbedtls_ecp_point *R, const mbedtls_ecp_point *P)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
/* Copy */
|
||||
if (R != P) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_copy(R, P));
|
||||
}
|
||||
|
||||
/* In-place opposite */
|
||||
if (mbedtls_mpi_cmp_int( &R->Y, 0) != 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&R->Y, &grp->P, &R->Y));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
return ( ret );
|
||||
}
|
||||
|
||||
int crypto_ec_point_invert(struct crypto_ec *e, struct crypto_ec_point *p)
|
||||
{
|
||||
return ecp_opp(&e->group, (mbedtls_ecp_point *) p, (mbedtls_ecp_point *) p) ? -1 : 0;
|
||||
}
|
||||
|
||||
int crypto_ec_point_solve_y_coord(struct crypto_ec *e,
|
||||
struct crypto_ec_point *p,
|
||||
const struct crypto_bignum *x, int y_bit)
|
||||
{
|
||||
mbedtls_mpi temp;
|
||||
mbedtls_mpi *y_sqr, *y;
|
||||
mbedtls_mpi_init(&temp);
|
||||
int ret = 0;
|
||||
|
||||
y = &((mbedtls_ecp_point *)p)->Y;
|
||||
|
||||
/* Faster way to find sqrt
|
||||
* Works only with curves having prime p
|
||||
* such that p ≡ 3 (mod 4)
|
||||
* y_ = (y2 ^ ((p+1)/4)) mod p
|
||||
*
|
||||
* if LSB of both x and y are same: y = y_
|
||||
* else y = p - y_
|
||||
* y_bit is LSB of x
|
||||
*/
|
||||
y_bit = (y_bit != 0);
|
||||
|
||||
y_sqr = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, x);
|
||||
|
||||
if (y_sqr) {
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_int(&temp, &e->group.P, 1));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_div_int(&temp, NULL, &temp, 4));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(y, y_sqr, &temp, &e->group.P, NULL));
|
||||
|
||||
if (y_bit != mbedtls_mpi_get_bit(y, 0))
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y, &e->group.P, y));
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&((mbedtls_ecp_point* )p)->X, (const mbedtls_mpi*) x));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&((mbedtls_ecp_point *)p)->Z, 1));
|
||||
} else {
|
||||
ret = 1;
|
||||
}
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&temp);
|
||||
mbedtls_mpi_free(y_sqr);
|
||||
os_free(y_sqr);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
struct crypto_bignum *
|
||||
crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
|
||||
const struct crypto_bignum *x)
|
||||
{
|
||||
mbedtls_mpi temp, temp2, num;
|
||||
int ret = 0;
|
||||
|
||||
mbedtls_mpi *y_sqr = os_zalloc(sizeof(mbedtls_mpi));
|
||||
if (y_sqr == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(&temp);
|
||||
mbedtls_mpi_init(&temp2);
|
||||
mbedtls_mpi_init(&num);
|
||||
mbedtls_mpi_init(y_sqr);
|
||||
|
||||
/* y^2 = x^3 + ax + b mod P*/
|
||||
/* mbedtls does not have mod-add or mod-mul apis.
|
||||
*
|
||||
*/
|
||||
|
||||
/* Calculate x^3 mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &num, 3));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&temp, (const mbedtls_mpi *) x, &num, &e->group.P, NULL));
|
||||
|
||||
/* Calculate ax mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &num, -3));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *) x, &num));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P));
|
||||
|
||||
/* Calculate ax + b mod P. Note that b is already < P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &e->group.B));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &e->group.P));
|
||||
|
||||
/* Calculate x^3 + ax + b mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &temp));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(y_sqr, &temp2, &e->group.P));
|
||||
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&temp);
|
||||
mbedtls_mpi_free(&temp2);
|
||||
mbedtls_mpi_free(&num);
|
||||
if (ret) {
|
||||
mbedtls_mpi_free(y_sqr);
|
||||
os_free(y_sqr);
|
||||
return NULL;
|
||||
} else {
|
||||
return (struct crypto_bignum *) y_sqr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *p)
|
||||
{
|
||||
return mbedtls_ecp_is_zero((mbedtls_ecp_point *) p);
|
||||
}
|
||||
|
||||
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *p)
|
||||
{
|
||||
mbedtls_mpi y_sqr_lhs, *y_sqr_rhs = NULL, two;
|
||||
int ret = 0, on_curve = 0;
|
||||
|
||||
mbedtls_mpi_init(&y_sqr_lhs);
|
||||
mbedtls_mpi_init(&two);
|
||||
|
||||
/* Calculate y^2 mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset( &two, 2));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&y_sqr_lhs, &((const mbedtls_ecp_point *)p)->Y , &two, &e->group.P, NULL));
|
||||
|
||||
y_sqr_rhs = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, (const struct crypto_bignum *) & ((const mbedtls_ecp_point *)p)->X);
|
||||
|
||||
if (y_sqr_rhs && (mbedtls_mpi_cmp_mpi(y_sqr_rhs, &y_sqr_lhs) == 0)) {
|
||||
on_curve = 1;
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&y_sqr_lhs);
|
||||
mbedtls_mpi_free(y_sqr_rhs);
|
||||
os_free(y_sqr_rhs);
|
||||
return (ret == 0) && (on_curve == 1);
|
||||
}
|
||||
|
||||
int crypto_ec_point_cmp(const struct crypto_ec *e,
|
||||
const struct crypto_ec_point *a,
|
||||
const struct crypto_ec_point *b)
|
||||
{
|
||||
return mbedtls_ecp_point_cmp((const mbedtls_ecp_point *) a,
|
||||
(const mbedtls_ecp_point *) b);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_ECC */
|
87
components/wpa_supplicant/src/crypto/sha256-kdf.c
Normal file
87
components/wpa_supplicant/src/crypto/sha256-kdf.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* HMAC-SHA256 KDF (RFC 5295) and HKDF-Expand(SHA256) (RFC 5869)
|
||||
* Copyright (c) 2014-2017, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "utils/common.h"
|
||||
|
||||
#include "crypto/sha256.h"
|
||||
|
||||
|
||||
/**
|
||||
* hmac_sha256_kdf - HMAC-SHA256 based KDF (RFC 5295)
|
||||
* @secret: Key for KDF
|
||||
* @secret_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the KDF or %NULL to select
|
||||
* RFC 5869 HKDF-Expand() with arbitrary seed (= info)
|
||||
* @seed: Seed value to bind into the key
|
||||
* @seed_len: Length of the seed
|
||||
* @out: Buffer for the generated pseudo-random key
|
||||
* @outlen: Number of bytes of key to generate
|
||||
* Returns: 0 on success, -1 on failure.
|
||||
*
|
||||
* This function is used to derive new, cryptographically separate keys from a
|
||||
* given key in ERP. This KDF is defined in RFC 5295, Chapter 3.1.2. When used
|
||||
* with label = NULL and seed = info, this matches HKDF-Expand() defined in
|
||||
* RFC 5869, Chapter 2.3.
|
||||
*/
|
||||
int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *out, size_t outlen)
|
||||
{
|
||||
u8 T[SHA256_MAC_LEN];
|
||||
u8 iter = 1;
|
||||
const unsigned char *addr[4];
|
||||
size_t len[4];
|
||||
size_t pos, clen;
|
||||
|
||||
addr[0] = T;
|
||||
len[0] = SHA256_MAC_LEN;
|
||||
if (label) {
|
||||
addr[1] = (const unsigned char *) label;
|
||||
len[1] = os_strlen(label) + 1;
|
||||
} else {
|
||||
addr[1] = (const u8 *) "";
|
||||
len[1] = 0;
|
||||
}
|
||||
addr[2] = seed;
|
||||
len[2] = seed_len;
|
||||
addr[3] = &iter;
|
||||
len[3] = 1;
|
||||
|
||||
if (hmac_sha256_vector(secret, secret_len, 3, &addr[1], &len[1], T) < 0)
|
||||
return -1;
|
||||
|
||||
pos = 0;
|
||||
for (;;) {
|
||||
clen = outlen - pos;
|
||||
if (clen > SHA256_MAC_LEN)
|
||||
clen = SHA256_MAC_LEN;
|
||||
os_memcpy(out + pos, T, clen);
|
||||
pos += clen;
|
||||
|
||||
if (pos == outlen)
|
||||
break;
|
||||
|
||||
if (iter == 255) {
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA256_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
iter++;
|
||||
|
||||
if (hmac_sha256_vector(secret, secret_len, 4, addr, len, T) < 0)
|
||||
{
|
||||
os_memset(out, 0, outlen);
|
||||
os_memset(T, 0, SHA256_MAC_LEN);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
os_memset(T, 0, SHA256_MAC_LEN);
|
||||
return 0;
|
||||
}
|
@@ -116,11 +116,11 @@ int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
* @data_len: Length of the data area
|
||||
* @mac: Buffer for the hash (20 bytes)
|
||||
*/
|
||||
void
|
||||
int
|
||||
hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
|
||||
size_t data_len, u8 *mac)
|
||||
{
|
||||
hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
|
||||
return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@@ -19,7 +19,7 @@
|
||||
|
||||
int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
|
||||
const u8 *addr[], const size_t *len, u8 *mac);
|
||||
void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
|
||||
int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
|
||||
size_t data_len, u8 *mac);
|
||||
int sha256_prf(const u8 *key, size_t key_len, const char *label,
|
||||
const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
|
||||
@@ -30,4 +30,8 @@ void tls_prf_sha256(const u8 *secret, size_t secret_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *out, size_t outlen);
|
||||
|
||||
int hmac_sha256_kdf(const u8 *secret, size_t secret_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *out, size_t outlen);
|
||||
|
||||
#endif /* SHA256_H */
|
||||
|
@@ -124,7 +124,7 @@ static int tlsv1_add_cert(struct x509_certificate **chain,
|
||||
return -1;
|
||||
}
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
|
||||
if (der == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
|
||||
"certificate");
|
||||
@@ -249,7 +249,7 @@ static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
|
||||
if (!der)
|
||||
return NULL;
|
||||
pkey = crypto_private_key_import(der, der_len, NULL);
|
||||
@@ -277,7 +277,7 @@ static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
|
||||
if (!end)
|
||||
return NULL;
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
|
||||
if (!der)
|
||||
return NULL;
|
||||
pkey = crypto_private_key_import(der, der_len, passwd);
|
||||
@@ -449,7 +449,7 @@ static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
|
||||
return -1;
|
||||
}
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
der = (unsigned char *)base64_decode((const char *)pos, end - pos, &der_len);
|
||||
if (der == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
|
||||
return -1;
|
||||
|
@@ -1365,7 +1365,6 @@ static int x509_digest_oid(struct asn1_oid *oid)
|
||||
oid->oid[4] == 2 /* digestAlgorithm */;
|
||||
}
|
||||
|
||||
|
||||
static int x509_sha1_oid(struct asn1_oid *oid)
|
||||
{
|
||||
return oid->len == 6 &&
|
||||
@@ -1377,7 +1376,6 @@ static int x509_sha1_oid(struct asn1_oid *oid)
|
||||
oid->oid[5] == 26 /* id-sha1 */;
|
||||
}
|
||||
|
||||
|
||||
static int x509_sha256_oid(struct asn1_oid *oid)
|
||||
{
|
||||
return oid->len == 9 &&
|
||||
|
@@ -1,40 +1,35 @@
|
||||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
|
||||
* Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "utils/includes.h"
|
||||
#include "includes.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#include "os.h"
|
||||
#include "base64.h"
|
||||
|
||||
static const unsigned char base64_table[65] =
|
||||
static const char base64_table[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
static const char base64_url_table[65] =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
|
||||
|
||||
/**
|
||||
* base64_encode - Base64 encode
|
||||
* @src: Data to be encoded
|
||||
* @len: Length of the data to be encoded
|
||||
* @out_len: Pointer to output length variable, or %NULL if not used
|
||||
* Returns: Allocated buffer of out_len bytes of encoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer. Returned buffer is
|
||||
* nul terminated to make it easier to use as a C string. The nul terminator is
|
||||
* not included in out_len.
|
||||
*/
|
||||
unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len)
|
||||
|
||||
static char * base64_gen_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len, const char *table, int add_pad)
|
||||
{
|
||||
unsigned char *out, *pos;
|
||||
char *out, *pos;
|
||||
const unsigned char *end, *in;
|
||||
size_t olen;
|
||||
int line_len;
|
||||
|
||||
if (len >= SIZE_MAX / 4)
|
||||
return NULL;
|
||||
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
|
||||
if (add_pad)
|
||||
olen += olen / 72; /* line feeds */
|
||||
olen++; /* nul termination */
|
||||
if (olen < len)
|
||||
@@ -48,33 +43,35 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
pos = out;
|
||||
line_len = 0;
|
||||
while (end - in >= 3) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
|
||||
*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
|
||||
*pos++ = base64_table[in[2] & 0x3f];
|
||||
*pos++ = table[(in[0] >> 2) & 0x3f];
|
||||
*pos++ = table[(((in[0] & 0x03) << 4) | (in[1] >> 4)) & 0x3f];
|
||||
*pos++ = table[(((in[1] & 0x0f) << 2) | (in[2] >> 6)) & 0x3f];
|
||||
*pos++ = table[in[2] & 0x3f];
|
||||
in += 3;
|
||||
line_len += 4;
|
||||
if (line_len >= 72) {
|
||||
if (add_pad && line_len >= 72) {
|
||||
*pos++ = '\n';
|
||||
line_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (end - in) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
*pos++ = table[(in[0] >> 2) & 0x3f];
|
||||
if (end - in == 1) {
|
||||
*pos++ = base64_table[(in[0] & 0x03) << 4];
|
||||
*pos++ = table[((in[0] & 0x03) << 4) & 0x3f];
|
||||
if (add_pad)
|
||||
*pos++ = '=';
|
||||
} else {
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) |
|
||||
(in[1] >> 4)];
|
||||
*pos++ = base64_table[(in[1] & 0x0f) << 2];
|
||||
*pos++ = table[(((in[0] & 0x03) << 4) |
|
||||
(in[1] >> 4)) & 0x3f];
|
||||
*pos++ = table[((in[1] & 0x0f) << 2) & 0x3f];
|
||||
}
|
||||
if (add_pad)
|
||||
*pos++ = '=';
|
||||
line_len += 4;
|
||||
}
|
||||
|
||||
if (line_len)
|
||||
if (add_pad && line_len)
|
||||
*pos++ = '\n';
|
||||
|
||||
*pos = '\0';
|
||||
@@ -84,49 +81,47 @@ unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_decode - Base64 decode
|
||||
* @src: Data to be decoded
|
||||
* @len: Length of the data to be decoded
|
||||
* @out_len: Pointer to output length variable
|
||||
* Returns: Allocated buffer of out_len bytes of decoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer.
|
||||
*/
|
||||
unsigned char * base64_decode(const unsigned char *src, size_t len,
|
||||
size_t *out_len)
|
||||
static unsigned char * base64_gen_decode(const char *src, size_t len,
|
||||
size_t *out_len, const char *table)
|
||||
{
|
||||
unsigned char dtable[256], *out, *pos, block[4], tmp;
|
||||
size_t i, count, olen;
|
||||
int pad = 0;
|
||||
size_t extra_pad;
|
||||
|
||||
os_memset(dtable, 0x80, 256);
|
||||
for (i = 0; i < sizeof(base64_table) - 1; i++)
|
||||
dtable[base64_table[i]] = (unsigned char) i;
|
||||
dtable[(unsigned char) table[i]] = (unsigned char) i;
|
||||
dtable['='] = 0;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (dtable[src[i]] != 0x80)
|
||||
if (dtable[(unsigned char) src[i]] != 0x80)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0 || count % 4)
|
||||
if (count == 0)
|
||||
return NULL;
|
||||
extra_pad = (4 - count % 4) % 4;
|
||||
|
||||
olen = count / 4 * 3;
|
||||
olen = (count + extra_pad) / 4 * 3;
|
||||
pos = out = os_malloc(olen);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
tmp = dtable[src[i]];
|
||||
for (i = 0; i < len + extra_pad; i++) {
|
||||
unsigned char val;
|
||||
|
||||
if (i >= len)
|
||||
val = '=';
|
||||
else
|
||||
val = src[i];
|
||||
tmp = dtable[val];
|
||||
if (tmp == 0x80)
|
||||
continue;
|
||||
|
||||
if (src[i] == '=')
|
||||
if (val == '=')
|
||||
pad++;
|
||||
block[count] = tmp;
|
||||
count++;
|
||||
@@ -153,3 +148,49 @@ unsigned char * base64_decode(const unsigned char *src, size_t len,
|
||||
*out_len = pos - out;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_encode - Base64 encode
|
||||
* @src: Data to be encoded
|
||||
* @len: Length of the data to be encoded
|
||||
* @out_len: Pointer to output length variable, or %NULL if not used
|
||||
* Returns: Allocated buffer of out_len bytes of encoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer. Returned buffer is
|
||||
* nul terminated to make it easier to use as a C string. The nul terminator is
|
||||
* not included in out_len.
|
||||
*/
|
||||
char * base64_encode(const void *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_encode(src, len, out_len, base64_table, 1);
|
||||
}
|
||||
|
||||
|
||||
char * base64_url_encode(const void *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_encode(src, len, out_len, base64_url_table, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* base64_decode - Base64 decode
|
||||
* @src: Data to be decoded
|
||||
* @len: Length of the data to be decoded
|
||||
* @out_len: Pointer to output length variable
|
||||
* Returns: Allocated buffer of out_len bytes of decoded data,
|
||||
* or %NULL on failure
|
||||
*
|
||||
* Caller is responsible for freeing the returned buffer.
|
||||
*/
|
||||
unsigned char * base64_decode(const char *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_decode(src, len, out_len, base64_table);
|
||||
}
|
||||
|
||||
|
||||
unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len)
|
||||
{
|
||||
return base64_gen_decode(src, len, out_len, base64_url_table);
|
||||
}
|
||||
|
@@ -2,22 +2,16 @@
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Alternatively, this software may be distributed under the terms of BSD
|
||||
* license.
|
||||
*
|
||||
* See README and COPYING for more details.
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
unsigned char * base64_encode(const unsigned char *src, size_t len,
|
||||
size_t *out_len);
|
||||
unsigned char * base64_decode(const unsigned char *src, size_t len,
|
||||
size_t *out_len);
|
||||
char * base64_encode(const void *src, size_t len, size_t *out_len);
|
||||
unsigned char * base64_decode(const char *src, size_t len, size_t *out_len);
|
||||
char * base64_url_encode(const void *src, size_t len, size_t *out_len);
|
||||
unsigned char * base64_url_decode(const char *src, size_t len, size_t *out_len);
|
||||
|
||||
#endif /* BASE64_H */
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include "utils/includes.h"
|
||||
|
||||
#include "utils/common.h"
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* inc_byte_array - Increment arbitrary length byte array by one
|
||||
@@ -365,4 +366,128 @@ void wpa_bin_clear_free(void *bin, size_t len)
|
||||
}
|
||||
}
|
||||
|
||||
int int_array_len(const int *a)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; a && a[i]; i++)
|
||||
;
|
||||
return i;
|
||||
}
|
||||
|
||||
void bin_clear_free(void *bin, size_t len)
|
||||
{
|
||||
if (bin) {
|
||||
os_memset(bin, 0, len);
|
||||
os_free(bin);
|
||||
}
|
||||
}
|
||||
|
||||
void str_clear_free(char *str)
|
||||
{
|
||||
if (str) {
|
||||
size_t len = os_strlen(str);
|
||||
os_memset(str, 0, len);
|
||||
os_free(str);
|
||||
}
|
||||
}
|
||||
|
||||
int os_gmtime(os_time_t t, struct os_tm *tm)
|
||||
{
|
||||
struct tm *tm2;
|
||||
time_t t2 = t;
|
||||
|
||||
tm2 = gmtime(&t2);
|
||||
if (tm2 == NULL)
|
||||
return -1;
|
||||
tm->sec = tm2->tm_sec;
|
||||
tm->min = tm2->tm_min;
|
||||
tm->hour = tm2->tm_hour;
|
||||
tm->day = tm2->tm_mday;
|
||||
tm->month = tm2->tm_mon + 1;
|
||||
tm->year = tm2->tm_year + 1900;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int os_mktime(int year, int month, int day, int hour, int min, int sec,
|
||||
os_time_t *t)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
|
||||
hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
|
||||
sec > 60)
|
||||
return -1;
|
||||
|
||||
os_memset(&tm, 0, sizeof(tm));
|
||||
tm.tm_year = year - 1900;
|
||||
tm.tm_mon = month - 1;
|
||||
tm.tm_mday = day;
|
||||
tm.tm_hour = hour;
|
||||
tm.tm_min = min;
|
||||
tm.tm_sec = sec;
|
||||
|
||||
*t = (os_time_t) mktime(&tm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char * get_param(const char *cmd, const char *param)
|
||||
{
|
||||
const char *pos, *end;
|
||||
char *val;
|
||||
size_t len;
|
||||
|
||||
pos = os_strstr(cmd, param);
|
||||
if (!pos)
|
||||
return NULL;
|
||||
|
||||
pos += os_strlen(param);
|
||||
end = os_strchr(pos, ' ');
|
||||
if (end)
|
||||
len = end - pos;
|
||||
else
|
||||
len = os_strlen(pos);
|
||||
val = os_malloc(len + 1);
|
||||
if (!val)
|
||||
return NULL;
|
||||
os_memcpy(val, pos, len);
|
||||
val[len] = '\0';
|
||||
return val;
|
||||
}
|
||||
|
||||
void * os_memdup(const void *src, size_t len)
|
||||
{
|
||||
void *r = os_malloc(len);
|
||||
|
||||
if (r && src)
|
||||
os_memcpy(r, src, len);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
|
||||
* @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
|
||||
* @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
|
||||
* Returns: Characters used (> 0) on success, -1 on failure
|
||||
*/
|
||||
int hwaddr_aton2(const char *txt, u8 *addr)
|
||||
{
|
||||
int i;
|
||||
const char *pos = txt;
|
||||
|
||||
for (i = 0; i < 6; i++) {
|
||||
int a, b;
|
||||
|
||||
while (*pos == ':' || *pos == '.' || *pos == '-')
|
||||
pos++;
|
||||
|
||||
a = hex2num(*pos++);
|
||||
if (a < 0)
|
||||
return -1;
|
||||
b = hex2num(*pos++);
|
||||
if (b < 0)
|
||||
return -1;
|
||||
*addr++ = (a << 4) | b;
|
||||
}
|
||||
|
||||
return pos - txt;
|
||||
}
|
||||
|
@@ -434,6 +434,11 @@ struct wpa_freq_range_list {
|
||||
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
|
||||
|
||||
void wpa_bin_clear_free(void *bin, size_t len);
|
||||
int int_array_len(const int *a);
|
||||
void bin_clear_free(void *bin, size_t len);
|
||||
void str_clear_free(char *str);
|
||||
char * get_param(const char *cmd, const char *param);
|
||||
void * os_memdup(const void *src, size_t len);
|
||||
|
||||
/*
|
||||
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
|
||||
|
654
components/wpa_supplicant/src/utils/json.c
Normal file
654
components/wpa_supplicant/src/utils/json.c
Normal file
@@ -0,0 +1,654 @@
|
||||
/*
|
||||
* JavaScript Object Notation (JSON) parser (RFC7159)
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "base64.h"
|
||||
#include "json.h"
|
||||
|
||||
#define JSON_MAX_DEPTH 10
|
||||
#define JSON_MAX_TOKENS 500
|
||||
|
||||
|
||||
void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len)
|
||||
{
|
||||
char *end = txt + maxlen;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (txt + 4 >= end)
|
||||
break;
|
||||
|
||||
switch (data[i]) {
|
||||
case '\"':
|
||||
*txt++ = '\\';
|
||||
*txt++ = '\"';
|
||||
break;
|
||||
case '\\':
|
||||
*txt++ = '\\';
|
||||
*txt++ = '\\';
|
||||
break;
|
||||
case '\n':
|
||||
*txt++ = '\\';
|
||||
*txt++ = 'n';
|
||||
break;
|
||||
case '\r':
|
||||
*txt++ = '\\';
|
||||
*txt++ = 'r';
|
||||
break;
|
||||
case '\t':
|
||||
*txt++ = '\\';
|
||||
*txt++ = 't';
|
||||
break;
|
||||
default:
|
||||
if (data[i] >= 32 && data[i] <= 126) {
|
||||
*txt++ = data[i];
|
||||
} else {
|
||||
txt += os_snprintf(txt, end - txt, "\\u%04x",
|
||||
(unsigned char) data[i]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*txt = '\0';
|
||||
}
|
||||
|
||||
|
||||
static char * json_parse_string(const char **json_pos, const char *end)
|
||||
{
|
||||
const char *pos = *json_pos;
|
||||
char *str, *spos, *s_end;
|
||||
size_t max_len, buf_len;
|
||||
u8 bin[2];
|
||||
|
||||
pos++; /* skip starting quote */
|
||||
|
||||
max_len = end - pos + 1;
|
||||
buf_len = max_len > 10 ? 10 : max_len;
|
||||
str = os_malloc(buf_len);
|
||||
if (!str)
|
||||
return NULL;
|
||||
spos = str;
|
||||
s_end = str + buf_len;
|
||||
|
||||
for (; pos < end; pos++) {
|
||||
if (buf_len < max_len && s_end - spos < 3) {
|
||||
char *tmp;
|
||||
int idx;
|
||||
|
||||
idx = spos - str;
|
||||
buf_len *= 2;
|
||||
if (buf_len > max_len)
|
||||
buf_len = max_len;
|
||||
tmp = os_realloc(str, buf_len);
|
||||
if (!tmp)
|
||||
goto fail;
|
||||
str = tmp;
|
||||
spos = str + idx;
|
||||
s_end = str + buf_len;
|
||||
}
|
||||
|
||||
switch (*pos) {
|
||||
case '\"': /* end string */
|
||||
*spos = '\0';
|
||||
/* caller will move to the next position */
|
||||
*json_pos = pos;
|
||||
return str;
|
||||
case '\\':
|
||||
pos++;
|
||||
if (pos >= end) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Truncated \\ escape");
|
||||
goto fail;
|
||||
}
|
||||
switch (*pos) {
|
||||
case '"':
|
||||
case '\\':
|
||||
case '/':
|
||||
*spos++ = *pos;
|
||||
break;
|
||||
case 'n':
|
||||
*spos++ = '\n';
|
||||
break;
|
||||
case 'r':
|
||||
*spos++ = '\r';
|
||||
break;
|
||||
case 't':
|
||||
*spos++ = '\t';
|
||||
break;
|
||||
case 'u':
|
||||
if (end - pos < 5 ||
|
||||
hexstr2bin(pos + 1, bin, 2) < 0 ||
|
||||
bin[1] == 0x00) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid \\u escape");
|
||||
goto fail;
|
||||
}
|
||||
if (bin[0] == 0x00) {
|
||||
*spos++ = bin[1];
|
||||
} else {
|
||||
*spos++ = bin[0];
|
||||
*spos++ = bin[1];
|
||||
}
|
||||
pos += 4;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Unknown escape '%c'", *pos);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*spos++ = *pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
os_free(str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int json_parse_number(const char **json_pos, const char *end,
|
||||
int *ret_val)
|
||||
{
|
||||
const char *pos = *json_pos;
|
||||
size_t len;
|
||||
char *str;
|
||||
|
||||
for (; pos < end; pos++) {
|
||||
if (*pos != '-' && (*pos < '0' || *pos > '9')) {
|
||||
pos--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pos == end)
|
||||
pos--;
|
||||
if (pos < *json_pos)
|
||||
return -1;
|
||||
len = pos - *json_pos + 1;
|
||||
str = os_malloc(len + 1);
|
||||
if (!str)
|
||||
return -1;
|
||||
os_memcpy(str, *json_pos, len);
|
||||
str[len] = '\0';
|
||||
|
||||
*ret_val = atoi(str);
|
||||
os_free(str);
|
||||
*json_pos = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int json_check_tree_state(struct json_token *token)
|
||||
{
|
||||
if (!token)
|
||||
return 0;
|
||||
if (json_check_tree_state(token->child) < 0 ||
|
||||
json_check_tree_state(token->sibling) < 0)
|
||||
return -1;
|
||||
if (token->state != JSON_COMPLETED) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Unexpected token state %d (name=%s type=%d)",
|
||||
token->state, token->name ? token->name : "N/A",
|
||||
token->type);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct json_token * json_alloc_token(unsigned int *tokens)
|
||||
{
|
||||
(*tokens)++;
|
||||
if (*tokens > JSON_MAX_TOKENS) {
|
||||
wpa_printf(MSG_DEBUG, "JSON: Maximum token limit exceeded");
|
||||
return NULL;
|
||||
}
|
||||
return os_zalloc(sizeof(struct json_token));
|
||||
}
|
||||
|
||||
|
||||
struct json_token * json_parse(const char *data, size_t data_len)
|
||||
{
|
||||
struct json_token *root = NULL, *curr_token = NULL, *token = NULL;
|
||||
const char *pos, *end;
|
||||
char *str;
|
||||
int num;
|
||||
unsigned int depth = 0;
|
||||
unsigned int tokens = 0;
|
||||
|
||||
pos = data;
|
||||
end = data + data_len;
|
||||
|
||||
for (; pos < end; pos++) {
|
||||
switch (*pos) {
|
||||
case '[': /* start array */
|
||||
case '{': /* start object */
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token)
|
||||
goto fail;
|
||||
if (!root)
|
||||
root = token;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
token = curr_token;
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
token = curr_token;
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for start array/object");
|
||||
goto fail;
|
||||
}
|
||||
depth++;
|
||||
if (depth > JSON_MAX_DEPTH) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Max depth exceeded");
|
||||
goto fail;
|
||||
}
|
||||
token->type = *pos == '[' ? JSON_ARRAY : JSON_OBJECT;
|
||||
token->state = JSON_STARTED;
|
||||
token->child = json_alloc_token(&tokens);
|
||||
if (!token->child)
|
||||
goto fail;
|
||||
curr_token = token->child;
|
||||
curr_token->parent = token;
|
||||
curr_token->state = JSON_EMPTY;
|
||||
break;
|
||||
case ']': /* end array */
|
||||
case '}': /* end object */
|
||||
if (!curr_token || !curr_token->parent ||
|
||||
curr_token->parent->state != JSON_STARTED) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for end array/object");
|
||||
goto fail;
|
||||
}
|
||||
depth--;
|
||||
curr_token = curr_token->parent;
|
||||
if ((*pos == ']' &&
|
||||
curr_token->type != JSON_ARRAY) ||
|
||||
(*pos == '}' &&
|
||||
curr_token->type != JSON_OBJECT)) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Array/Object mismatch");
|
||||
goto fail;
|
||||
}
|
||||
if (curr_token->child->state == JSON_EMPTY &&
|
||||
!curr_token->child->child &&
|
||||
!curr_token->child->sibling) {
|
||||
/* Remove pending child token since the
|
||||
* array/object was empty. */
|
||||
json_free(curr_token->child);
|
||||
curr_token->child = NULL;
|
||||
}
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
break;
|
||||
case '\"': /* string */
|
||||
str = json_parse_string(&pos, end);
|
||||
if (!str)
|
||||
goto fail;
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token) {
|
||||
os_free(str);
|
||||
goto fail;
|
||||
}
|
||||
token->type = JSON_STRING;
|
||||
token->string = str;
|
||||
token->state = JSON_COMPLETED;
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
curr_token->string = str;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_STRING;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: String value: '%s'",
|
||||
curr_token->string);
|
||||
} else if (curr_token->state == JSON_EMPTY) {
|
||||
curr_token->type = JSON_VALUE;
|
||||
curr_token->name = str;
|
||||
curr_token->state = JSON_STARTED;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
curr_token->string = str;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_STRING;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: String value: '%s' = '%s'",
|
||||
curr_token->name,
|
||||
curr_token->string);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for a string");
|
||||
os_free(str);
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
/* ignore whitespace */
|
||||
break;
|
||||
case ':': /* name/value separator */
|
||||
if (!curr_token || curr_token->state != JSON_STARTED)
|
||||
goto fail;
|
||||
curr_token->state = JSON_WAITING_VALUE;
|
||||
break;
|
||||
case ',': /* member separator */
|
||||
if (!curr_token)
|
||||
goto fail;
|
||||
curr_token->sibling = json_alloc_token(&tokens);
|
||||
if (!curr_token->sibling)
|
||||
goto fail;
|
||||
curr_token->sibling->parent = curr_token->parent;
|
||||
curr_token = curr_token->sibling;
|
||||
curr_token->state = JSON_EMPTY;
|
||||
break;
|
||||
case 't': /* true */
|
||||
case 'f': /* false */
|
||||
case 'n': /* null */
|
||||
if (!((end - pos >= 4 &&
|
||||
os_strncmp(pos, "true", 4) == 0) ||
|
||||
(end - pos >= 5 &&
|
||||
os_strncmp(pos, "false", 5) == 0) ||
|
||||
(end - pos >= 4 &&
|
||||
os_strncmp(pos, "null", 4) == 0))) {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid literal name");
|
||||
goto fail;
|
||||
}
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token)
|
||||
goto fail;
|
||||
curr_token = token;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Literal name: '%s' = %c",
|
||||
curr_token->name, *pos);
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Literal name: %c", *pos);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for a literal name");
|
||||
goto fail;
|
||||
}
|
||||
switch (*pos) {
|
||||
case 't':
|
||||
curr_token->type = JSON_BOOLEAN;
|
||||
curr_token->number = 1;
|
||||
pos += 3;
|
||||
break;
|
||||
case 'f':
|
||||
curr_token->type = JSON_BOOLEAN;
|
||||
curr_token->number = 0;
|
||||
pos += 4;
|
||||
break;
|
||||
case 'n':
|
||||
curr_token->type = JSON_NULL;
|
||||
pos += 3;
|
||||
break;
|
||||
}
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
break;
|
||||
case '-':
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
/* number */
|
||||
if (json_parse_number(&pos, end, &num) < 0)
|
||||
goto fail;
|
||||
if (!curr_token) {
|
||||
token = json_alloc_token(&tokens);
|
||||
if (!token)
|
||||
goto fail;
|
||||
token->type = JSON_NUMBER;
|
||||
token->number = num;
|
||||
token->state = JSON_COMPLETED;
|
||||
} else if (curr_token->state == JSON_WAITING_VALUE) {
|
||||
curr_token->number = num;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_NUMBER;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Number value: '%s' = '%d'",
|
||||
curr_token->name,
|
||||
curr_token->number);
|
||||
} else if (curr_token->parent &&
|
||||
curr_token->parent->type == JSON_ARRAY &&
|
||||
curr_token->parent->state == JSON_STARTED &&
|
||||
curr_token->state == JSON_EMPTY) {
|
||||
curr_token->number = num;
|
||||
curr_token->state = JSON_COMPLETED;
|
||||
curr_token->type = JSON_NUMBER;
|
||||
wpa_printf(MSG_MSGDUMP,
|
||||
"JSON: Number value: %d",
|
||||
curr_token->number);
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Invalid state for a number");
|
||||
goto fail;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG,
|
||||
"JSON: Unexpected JSON character: %c", *pos);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!root)
|
||||
root = token;
|
||||
if (!curr_token)
|
||||
curr_token = token;
|
||||
}
|
||||
|
||||
if (json_check_tree_state(root) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "JSON: Incomplete token in the tree");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return root;
|
||||
fail:
|
||||
wpa_printf(MSG_DEBUG, "JSON: Parsing failed");
|
||||
json_free(root);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void json_free(struct json_token *json)
|
||||
{
|
||||
if (!json)
|
||||
return;
|
||||
json_free(json->child);
|
||||
json_free(json->sibling);
|
||||
os_free(json->name);
|
||||
os_free(json->string);
|
||||
os_free(json);
|
||||
}
|
||||
|
||||
|
||||
struct json_token * json_get_member(struct json_token *json, const char *name)
|
||||
{
|
||||
struct json_token *token, *ret = NULL;
|
||||
|
||||
if (!json || json->type != JSON_OBJECT)
|
||||
return NULL;
|
||||
/* Return last matching entry */
|
||||
for (token = json->child; token; token = token->sibling) {
|
||||
if (token->name && os_strcmp(token->name, name) == 0)
|
||||
ret = token;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * json_get_member_base64url(struct json_token *json,
|
||||
const char *name)
|
||||
{
|
||||
struct json_token *token;
|
||||
unsigned char *buf;
|
||||
size_t buflen;
|
||||
struct wpabuf *ret;
|
||||
|
||||
token = json_get_member(json, name);
|
||||
if (!token || token->type != JSON_STRING)
|
||||
return NULL;
|
||||
buf = base64_url_decode(token->string, os_strlen(token->string),
|
||||
&buflen);
|
||||
if (!buf)
|
||||
return NULL;
|
||||
ret = wpabuf_alloc_ext_data(buf, buflen);
|
||||
if (!ret)
|
||||
os_free(buf);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static const char * json_type_str(enum json_type type)
|
||||
{
|
||||
switch (type) {
|
||||
case JSON_VALUE:
|
||||
return "VALUE";
|
||||
case JSON_OBJECT:
|
||||
return "OBJECT";
|
||||
case JSON_ARRAY:
|
||||
return "ARRAY";
|
||||
case JSON_STRING:
|
||||
return "STRING";
|
||||
case JSON_NUMBER:
|
||||
return "NUMBER";
|
||||
case JSON_BOOLEAN:
|
||||
return "BOOLEAN";
|
||||
case JSON_NULL:
|
||||
return "NULL";
|
||||
}
|
||||
return "??";
|
||||
}
|
||||
|
||||
|
||||
static void json_print_token(struct json_token *token, int depth,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
if (!token)
|
||||
return;
|
||||
len = os_strlen(buf);
|
||||
ret = os_snprintf(buf + len, buflen - len, "[%d:%s:%s]",
|
||||
depth, json_type_str(token->type),
|
||||
token->name ? token->name : "");
|
||||
if (os_snprintf_error(buflen - len, ret)) {
|
||||
buf[len] = '\0';
|
||||
return;
|
||||
}
|
||||
json_print_token(token->child, depth + 1, buf, buflen);
|
||||
json_print_token(token->sibling, depth, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
void json_print_tree(struct json_token *root, char *buf, size_t buflen)
|
||||
{
|
||||
buf[0] = '\0';
|
||||
json_print_token(root, 1, buf, buflen);
|
||||
}
|
||||
|
||||
|
||||
void json_add_int(struct wpabuf *json, const char *name, int val)
|
||||
{
|
||||
wpabuf_printf(json, "\"%s\":%d", name, val);
|
||||
}
|
||||
|
||||
|
||||
void json_add_string(struct wpabuf *json, const char *name, const char *val)
|
||||
{
|
||||
wpabuf_printf(json, "\"%s\":\"%s\"", name, val);
|
||||
}
|
||||
|
||||
|
||||
int json_add_string_escape(struct wpabuf *json, const char *name,
|
||||
const void *val, size_t len)
|
||||
{
|
||||
char *tmp;
|
||||
size_t tmp_len = 6 * len + 1;
|
||||
|
||||
tmp = os_malloc(tmp_len);
|
||||
if (!tmp)
|
||||
return -1;
|
||||
json_escape_string(tmp, tmp_len, val, len);
|
||||
json_add_string(json, name, tmp);
|
||||
bin_clear_free(tmp, tmp_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
|
||||
size_t len)
|
||||
{
|
||||
char *b64;
|
||||
|
||||
b64 = base64_url_encode(val, len, NULL);
|
||||
if (!b64)
|
||||
return -1;
|
||||
json_add_string(json, name, b64);
|
||||
os_free(b64);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void json_start_object(struct wpabuf *json, const char *name)
|
||||
{
|
||||
if (name)
|
||||
wpabuf_printf(json, "\"%s\":", name);
|
||||
wpabuf_put_u8(json, '{');
|
||||
}
|
||||
|
||||
|
||||
void json_end_object(struct wpabuf *json)
|
||||
{
|
||||
wpabuf_put_u8(json, '}');
|
||||
}
|
||||
|
||||
|
||||
void json_start_array(struct wpabuf *json, const char *name)
|
||||
{
|
||||
if (name)
|
||||
wpabuf_printf(json, "\"%s\":", name);
|
||||
wpabuf_put_u8(json, '[');
|
||||
}
|
||||
|
||||
|
||||
void json_end_array(struct wpabuf *json)
|
||||
{
|
||||
wpabuf_put_u8(json, ']');
|
||||
}
|
||||
|
||||
|
||||
void json_value_sep(struct wpabuf *json)
|
||||
{
|
||||
wpabuf_put_u8(json, ',');
|
||||
}
|
53
components/wpa_supplicant/src/utils/json.h
Normal file
53
components/wpa_supplicant/src/utils/json.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* JavaScript Object Notation (JSON) parser (RFC7159)
|
||||
* Copyright (c) 2017, Qualcomm Atheros, Inc.
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef JSON_H
|
||||
#define JSON_H
|
||||
|
||||
struct json_token {
|
||||
enum json_type {
|
||||
JSON_VALUE,
|
||||
JSON_OBJECT,
|
||||
JSON_ARRAY,
|
||||
JSON_STRING,
|
||||
JSON_NUMBER,
|
||||
JSON_BOOLEAN,
|
||||
JSON_NULL,
|
||||
} type;
|
||||
enum json_parsing_state {
|
||||
JSON_EMPTY,
|
||||
JSON_STARTED,
|
||||
JSON_WAITING_VALUE,
|
||||
JSON_COMPLETED,
|
||||
} state;
|
||||
char *name;
|
||||
char *string;
|
||||
int number;
|
||||
struct json_token *parent, *child, *sibling;
|
||||
};
|
||||
|
||||
void json_escape_string(char *txt, size_t maxlen, const char *data, size_t len);
|
||||
struct json_token * json_parse(const char *data, size_t data_len);
|
||||
void json_free(struct json_token *json);
|
||||
struct json_token * json_get_member(struct json_token *json, const char *name);
|
||||
struct wpabuf * json_get_member_base64url(struct json_token *json,
|
||||
const char *name);
|
||||
void json_print_tree(struct json_token *root, char *buf, size_t buflen);
|
||||
void json_add_int(struct wpabuf *json, const char *name, int val);
|
||||
void json_add_string(struct wpabuf *json, const char *name, const char *val);
|
||||
int json_add_string_escape(struct wpabuf *json, const char *name,
|
||||
const void *val, size_t len);
|
||||
int json_add_base64url(struct wpabuf *json, const char *name, const void *val,
|
||||
size_t len);
|
||||
void json_start_object(struct wpabuf *json, const char *name);
|
||||
void json_end_object(struct wpabuf *json);
|
||||
void json_start_array(struct wpabuf *json, const char *name);
|
||||
void json_end_array(struct wpabuf *json);
|
||||
void json_value_sep(struct wpabuf *json);
|
||||
|
||||
#endif /* JSON_H */
|
@@ -133,7 +133,6 @@ struct wpabuf * wpabuf_alloc(size_t len)
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
|
||||
{
|
||||
#ifdef WPA_TRACE
|
||||
@@ -285,7 +284,7 @@ struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
|
||||
void wpabuf_printf(struct wpabuf *buf, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
|
||||
|
@@ -11,3 +11,4 @@ string(SUBSTRING "${WIFI_SUPPLICANT_MD5}" 0 7 WIFI_SUPPLICANT_MD5)
|
||||
|
||||
add_definitions(-DWIFI_SUPPLICANT_MD5=\"${WIFI_SUPPLICANT_MD5}\")
|
||||
add_definitions(-DCONFIG_WPA3_SAE)
|
||||
add_definitions(-DCONFIG_DPP)
|
||||
|
@@ -8,3 +8,4 @@ COMPONENT_SRCDIRS := .
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
|
||||
CFLAGS+= -DCONFIG_WPA3_SAE
|
||||
CFLAGS+= -DCONFIG_DPP
|
||||
|
@@ -34,7 +34,7 @@ TEST_CASE("Test crypto lib bignum apis", "[wpa_crypto]")
|
||||
crypto_bignum_deinit(bn, 1);
|
||||
|
||||
/* BN - Binary to bignum & bignum to binary*/
|
||||
TEST_ASSERT(!crypto_get_random(buf, 32));
|
||||
TEST_ASSERT(!os_get_random(buf, 32));
|
||||
|
||||
bn = crypto_bignum_init_set(buf, 32);
|
||||
TEST_ASSERT_NOT_NULL(bn);
|
||||
@@ -366,7 +366,7 @@ TEST_CASE("Test crypto lib ECC apis", "[wpa_crypto]")
|
||||
|
||||
/* Note this is just testing coversion & not whether point is
|
||||
* in the group or not*/
|
||||
TEST_ASSERT(!crypto_get_random(pt1, 64));
|
||||
TEST_ASSERT(!os_get_random(pt1, 64));
|
||||
|
||||
p = crypto_ec_point_from_bin(e, pt1);
|
||||
|
||||
|
177
components/wpa_supplicant/test/test_dpp.c
Normal file
177
components/wpa_supplicant/test/test_dpp.c
Normal file
@@ -0,0 +1,177 @@
|
||||
/* Copyright 2015-2020 Espressif Systems (Shanghai) PTE LTD
|
||||
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
#include "unity.h"
|
||||
#include <string.h>
|
||||
#include "crypto/crypto.h"
|
||||
#include "../src/common/defs.h"
|
||||
#include "../src/common/dpp.h"
|
||||
|
||||
#ifdef CONFIG_WPA_TESTING_OPTIONS
|
||||
struct dpp_global {
|
||||
void *msg_ctx;
|
||||
struct dl_list bootstrap; /* struct dpp_bootstrap_info */
|
||||
struct dl_list configurator; /* struct dpp_configurator */
|
||||
};
|
||||
|
||||
extern u8 dpp_protocol_key_override[600];
|
||||
extern size_t dpp_protocol_key_override_len;
|
||||
extern u8 dpp_nonce_override[DPP_MAX_NONCE_LEN];
|
||||
extern size_t dpp_nonce_override_len;
|
||||
#define MAX_FRAME_SIZE 1200
|
||||
|
||||
TEST_CASE("Test vectors DPP responder p256", "[wpa_dpp]")
|
||||
{
|
||||
/* Global variables */
|
||||
char command[1200] = {0};
|
||||
const u8 *frame;
|
||||
int len = 0;
|
||||
struct dpp_authentication *auth_instance = NULL;
|
||||
u8 auth[MAX_FRAME_SIZE] = {0};
|
||||
char prefix[] = "30310201010420";
|
||||
char postfix[] = "a00a06082a8648ce3d030107";
|
||||
size_t hex_len;
|
||||
int ret = 0;
|
||||
int id;
|
||||
|
||||
/* DPP global config initialization */
|
||||
struct dpp_global_config dpp_conf;
|
||||
memset(&dpp_conf, 0, sizeof(dpp_conf));
|
||||
struct dpp_global *dpp = dpp_global_init(&dpp_conf);
|
||||
|
||||
/* bootstrap generation test */
|
||||
ESP_LOGI("DPP Test", "bootstrap generation test");
|
||||
{
|
||||
char key[1000] = {0};
|
||||
const char *uri;
|
||||
|
||||
char private_bootstrap_key[] = "54ce181a98525f217216f59b245f60e9df30ac7f6b26c939418cfc3c42d1afa0";
|
||||
char bootstrap_info[] = "DPP:K:MDkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDIgACCcWFqRtN+f0loEUgGIXDnMXPrjl92u2pV97Ff6DjUD8=;;";
|
||||
|
||||
sprintf(key, "%s%s%s", prefix, private_bootstrap_key, postfix);
|
||||
|
||||
sprintf(command, "type=qrcode key=%s", key);
|
||||
id = dpp_bootstrap_gen(dpp, command);
|
||||
uri = dpp_bootstrap_get_uri(dpp, id);
|
||||
printf("uri is =%s\n", uri);
|
||||
printf("is be =%s\n", bootstrap_info);
|
||||
TEST_ASSERT((strcmp(uri, bootstrap_info) == 0));
|
||||
}
|
||||
ESP_LOGI("DPP Test", "bootstap generation passed");
|
||||
ESP_LOGI("DPP Test", "Overwrite Protocol key, responder nounce");
|
||||
{
|
||||
char protocol_key[] = "f798ed2e19286f6a6efe210b1863badb99af2a14b497634dbfd2a97394fb5aa5";
|
||||
char nounce[] = "3d0cfb011ca916d796f7029ff0b43393";
|
||||
|
||||
/* Overwrite protocol key */
|
||||
memset(command, 0, 1200);
|
||||
sprintf(command, "%s%s%s", prefix, protocol_key, postfix);
|
||||
|
||||
hex_len = os_strlen(command);
|
||||
ret = 0;
|
||||
|
||||
if (hex_len > 2 * sizeof(dpp_protocol_key_override))
|
||||
ret = -1;
|
||||
else if (hexstr2bin(command, dpp_protocol_key_override,
|
||||
hex_len / 2))
|
||||
ret = -1;
|
||||
else
|
||||
dpp_protocol_key_override_len = hex_len / 2;
|
||||
|
||||
TEST_ASSERT(ret == 0);
|
||||
|
||||
/* Overwrite nounce */
|
||||
hex_len = os_strlen(nounce);
|
||||
|
||||
if (hex_len > 2 * sizeof(dpp_nonce_override))
|
||||
ret = -1;
|
||||
else if (hexstr2bin(nounce, dpp_nonce_override, hex_len / 2))
|
||||
ret = -1;
|
||||
else
|
||||
dpp_nonce_override_len = hex_len / 2;
|
||||
|
||||
TEST_ASSERT(ret == 0);
|
||||
|
||||
}
|
||||
ESP_LOGI("DPP Test", "Overwritten Protocol key, responder nounce.. ");
|
||||
ESP_LOGI("DPP Test", "Enqueue Auth request");
|
||||
{
|
||||
char auth_req[] = "d00012001ac459c40d649f8664c1b8771ac459c40d6400120409506f9a1a010002102000922ddd7a3ed69f46125d772bbe6017cd4e03870dc014509e38b54628e157a87d011020005d467a09760292fc15d31792b0a5b050db8bf6ad807d71b2d93f4d1c2e65d8810310400050a532ae2a07207276418d2fa630295d45569be425aa634f02014d00a7d1f61ae14f35a5a858bccad90d126c46594c49ef82655e78888e15a32d916ac217249118100200510104102900868f478fc599ac3fa8152b975eff8be4e71b189dbefbc3185b1d7f3864e896f913cba3d9601326f278";
|
||||
|
||||
char auth_resp[] = "d00012349f8664c1b8771ac459c40d649f8664c1b87712340409506f9a1a0101001001000002102000922ddd7a3ed69f46125d772bbe6017cd4e03870dc014509e38b54628e157a87d091040005e3fb3576884887f17c3203d8a3a6c2fac722ef0e2201b61ac73bc655c709a902d4b030669fb9eff8b0a79fa7c1a172ac2a92c626256963f9274dc90682c81e504107500da553cdf80da3e27054c5e1f809ac303c63948b9bb5690ad12f357d75dfbc362cbae89e472dd6851925534024310aff5ae403831e98a7efc7deb9516164329c227039ae73c509147d156ae085f56c242bf7decc1f3b68d81697c6197453cb6faff7b062f7861073148052db539895bc6583d08b4aa";
|
||||
u8 *tmp;
|
||||
|
||||
hex_len = os_strlen(auth_req);
|
||||
if (hex_len > 2 * MAX_FRAME_SIZE)
|
||||
ret = -1;
|
||||
else if (hexstr2bin(auth_req, auth, hex_len / 2))
|
||||
ret = -1;
|
||||
else
|
||||
len = hex_len / 2;
|
||||
frame = auth;
|
||||
frame += 26;
|
||||
len -= 26;
|
||||
auth_instance = dpp_auth_req_rx(NULL, 1, 0 , NULL,
|
||||
dpp_bootstrap_get_id(dpp, id), 2412, frame, frame+6, len-6);
|
||||
|
||||
/* auth response u8 */
|
||||
hex_len = os_strlen(auth_resp);
|
||||
if (hex_len > 2 * MAX_FRAME_SIZE)
|
||||
ret = -1;
|
||||
else if (hexstr2bin(auth_resp, auth, hex_len / 2))
|
||||
ret = -1;
|
||||
else
|
||||
len = hex_len / 2;
|
||||
tmp = auth;
|
||||
tmp += 26;
|
||||
len -= 26;
|
||||
|
||||
frame = wpabuf_head_u8(auth_instance->resp_msg);
|
||||
len = wpabuf_len(auth_instance->resp_msg);
|
||||
|
||||
TEST_ASSERT(memcmp(frame + 28, tmp + 26, len - 26) == 0);
|
||||
}
|
||||
ESP_LOGI("DPP Test", "Auth request parsing passed");
|
||||
ESP_LOGI("DPP Test", "Enqueue Auth confirm parsing passed");
|
||||
{
|
||||
char auth_confirm[] = "d00012341ac459c40d649f8664c1b8771ac459c40d6412340409506f9a1a0102001001000002102000922ddd7a3ed69f46125d772bbe6017cd4e03870dc014509e38b54628e157a87d0410340054e07e62c74526dfd97e029dc781e0771e573ebc73c94227b5de8350fc6a1974b40f54c9fe1a1c9288a91fce4ee6c1f2ff069741";
|
||||
hex_len = os_strlen(auth_confirm);
|
||||
os_memset(auth, 0, 1200);
|
||||
if (hex_len > 2 * MAX_FRAME_SIZE)
|
||||
ret = -1;
|
||||
else if (hexstr2bin(auth_confirm, auth, hex_len / 2))
|
||||
ret = -1;
|
||||
else
|
||||
len = hex_len / 2;
|
||||
frame = auth;
|
||||
frame = auth + 26;
|
||||
len = len - 26;
|
||||
dpp_auth_conf_rx(auth_instance, frame, frame+6, len-6);
|
||||
TEST_ASSERT(auth_instance->auth_success == 1);
|
||||
}
|
||||
ESP_LOGI("DPP Test", "Auth confirm parsing passed");
|
||||
/* deinit for memory passing */
|
||||
{
|
||||
dpp_auth_deinit(auth_instance);
|
||||
dpp_global_deinit(dpp);
|
||||
}
|
||||
ESP_LOGI("DPP Test", "Test case passed");
|
||||
}
|
||||
#endif
|
Reference in New Issue
Block a user