Merge branch 'feature/put_supplicant_source_code_from_VNC_to_IDF' into 'master'
wpa_supplicant: move part of codes to IDF See merge request idf/esp-idf!2272
This commit is contained in:
commit
b9aee83d9b
64 changed files with 30799 additions and 105 deletions
|
@ -15,6 +15,8 @@
|
|||
#ifndef ESP_WPA2_H
|
||||
#define ESP_WPA2_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_wifi_crypto_types.h"
|
||||
|
||||
|
@ -121,7 +123,7 @@ void esp_wifi_sta_wpa2_ent_clear_password(void);
|
|||
* @attention 1. The API only passes the parameter password to the global pointer variable in wpa2 enterprise module.
|
||||
* @attention 2. The new password is used to substitute the old password when eap-mschapv2 failure request message with error code ERROR_PASSWD_EXPIRED is received.
|
||||
*
|
||||
* @param password: point to address where stores the password;
|
||||
* @param new_password: point to address where stores the password;
|
||||
* @param len: length of password
|
||||
*
|
||||
* @return
|
||||
|
@ -130,7 +132,7 @@ void esp_wifi_sta_wpa2_ent_clear_password(void);
|
|||
* - ESP_ERR_NO_MEM: fail(internal memory malloc fail)
|
||||
*/
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *password, int len);
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *new_password, int len);
|
||||
|
||||
/**
|
||||
* @brief Clear new password for MSCHAPv2 method..
|
||||
|
@ -144,12 +146,12 @@ void esp_wifi_sta_wpa2_ent_clear_new_password(void);
|
|||
* @attention 2. The ca_cert should be zero terminated.
|
||||
*
|
||||
* @param ca_cert: point to address where stores the CA certificate;
|
||||
* @param len: length of ca_cert
|
||||
* @param ca_cert_len: length of ca_cert
|
||||
*
|
||||
* @return
|
||||
* - ESP_OK: succeed
|
||||
*/
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int len);
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len);
|
||||
|
||||
/**
|
||||
* @brief Clear CA certificate for PEAP/TTLS method.
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit f46327a4c68b1e4e6a3fb3febd3ba3312df16ff1
|
||||
Subproject commit 92a091649f7c8476580177e2a769b15d9c4c191f
|
|
@ -1,4 +1,4 @@
|
|||
COMPONENT_ADD_INCLUDEDIRS := include port/include ../esp32/include
|
||||
COMPONENT_SRCDIRS := src/crypto port src/fast_crypto
|
||||
COMPONENT_SRCDIRS := src/crypto port src/fast_crypto src/wpa2/eap_peer src/wpa2/tls src/wpa2/utils src/wps
|
||||
|
||||
CFLAGS += -DEMBEDDED_SUPP -D__ets__ -Wno-strict-aliasing
|
||||
CFLAGS += -DEMBEDDED_SUPP -DIEEE8021X_EAPOL -DEAP_PEER_METHOD -DEAP_MSCHAPv2 -DEAP_TTLS -DEAP_TLS -DEAP_PEAP -DUSE_WPA2_TASK -DCONFIG_WPS2 -DCONFIG_WPS_PIN -DUSE_WPS_TASK -DESPRESSIF_USE -DESP32_WORKAROUND -D__ets__ -Wno-strict-aliasing
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#ifndef LIST_H
|
||||
#define LIST_H
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
/**
|
||||
* struct dl_list - Doubly-linked list
|
||||
*/
|
||||
|
|
|
@ -15,15 +15,11 @@
|
|||
#ifndef WPA_H
|
||||
#define WPA_H
|
||||
|
||||
#include "c_types.h"
|
||||
#include "os_type.h"
|
||||
#include "rom/ets_sys.h"
|
||||
#include "common.h"
|
||||
#include "ets_sys.h"
|
||||
#include "wpa/defs.h"
|
||||
#include "wpa/wpa_common.h"
|
||||
|
||||
//#include "net80211/ieee80211_var.h"
|
||||
//#include "net80211/ieee80211_node.h"
|
||||
|
||||
#define WPA_SM_STATE(_sm) ((_sm)->wpa_state)
|
||||
|
||||
|
@ -51,10 +47,6 @@ struct wpa_sm {
|
|||
u8 pmk[PMK_LEN];
|
||||
size_t pmk_len;
|
||||
|
||||
// char *passphrase; //wlan password
|
||||
// u8 *ssid; //wlan network name
|
||||
// size_t ssid_len;
|
||||
|
||||
struct wpa_ptk ptk, tptk;
|
||||
int ptk_set, tptk_set;
|
||||
u8 snonce[WPA_NONCE_LEN];
|
||||
|
@ -64,8 +56,6 @@ struct wpa_sm {
|
|||
int rx_replay_counter_set;
|
||||
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
|
||||
|
||||
// void *network_ctx;
|
||||
|
||||
unsigned int pairwise_cipher;
|
||||
unsigned int group_cipher;
|
||||
unsigned int key_mgmt;
|
||||
|
@ -74,7 +64,7 @@ struct wpa_sm {
|
|||
int rsn_enabled; /* Whether RSN is enabled in configuration */
|
||||
|
||||
int countermeasures; /*TKIP countermeasures state flag, 1:in countermeasures state*/
|
||||
os_timer_t cm_timer;
|
||||
ETSTimer cm_timer;
|
||||
|
||||
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
|
||||
size_t assoc_wpa_ie_len;
|
||||
|
@ -96,20 +86,16 @@ struct wpa_sm {
|
|||
struct install_key install_gtk;
|
||||
int key_entry_valid; //present current avaliable entry for bssid, for pairkey:0,5,10,15,20, gtk: pairkey_no+i (i:1~4)
|
||||
|
||||
// char *msg; //send eapol msg buff
|
||||
// size_t msg_len; //msg length:6 + sizeof(eth) + data_len
|
||||
|
||||
// struct netif *ifp;
|
||||
struct pbuf *pb;
|
||||
|
||||
void (* sendto) (struct pbuf *pb);
|
||||
void (*config_assoc_ie) (uint8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len);
|
||||
void (*install_ppkey) (enum wpa_alg alg, uint8 *addr, int key_idx, int set_tx,
|
||||
uint8 *seq, size_t seq_len, uint8 *key, size_t key_len, int key_entry_valid);
|
||||
void (*wpa_deauthenticate)(uint8 reason_code);
|
||||
void (*config_assoc_ie) (u8 proto, u8 *assoc_buf, u32 assoc_wpa_ie_len);
|
||||
void (*install_ppkey) (enum wpa_alg alg, u8 *addr, int key_idx, int set_tx,
|
||||
u8 *seq, unsigned int seq_len, u8 *key, unsigned int key_len, int key_entry_valid);
|
||||
void (*wpa_deauthenticate)(u8 reason_code);
|
||||
void (*wpa_neg_complete)();
|
||||
struct wpa_gtk_data gd; //used for calllback save param
|
||||
uint16 key_info; //used for txcallback param
|
||||
u16 key_info; //used for txcallback param
|
||||
};
|
||||
|
||||
struct l2_ethhdr {
|
||||
|
@ -185,9 +171,9 @@ struct l2_ethhdr {
|
|||
|
||||
#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5)
|
||||
|
||||
void pp_michael_mic_failure(uint16 isunicast);
|
||||
|
||||
void wpa_sm_set_state(enum wpa_states state);
|
||||
|
||||
char * dup_binstr(const void *src, size_t len);
|
||||
|
||||
#endif /* WPA_H */
|
||||
|
||||
|
|
|
@ -15,8 +15,22 @@
|
|||
#ifndef WPA_DEBUG_H
|
||||
#define WPA_DEBUG_H
|
||||
|
||||
#include "wpabuf.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#ifdef ESPRESSIF_USE
|
||||
|
||||
#define TAG "wpa"
|
||||
|
||||
#define MSG_ERROR ESP_LOG_ERROR
|
||||
#define MSG_WARNING ESP_LOG_WARN
|
||||
#define MSG_INFO ESP_LOG_INFO
|
||||
#define MSG_DEBUG ESP_LOG_DEBUG
|
||||
#define MSG_MSGDUMP ESP_LOG_VERBOSE
|
||||
|
||||
#else
|
||||
enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
|
||||
#endif
|
||||
|
||||
/** EAP authentication completed successfully */
|
||||
#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
|
||||
|
@ -44,8 +58,8 @@ void wpa_debug_print_timestamp(void);
|
|||
*
|
||||
* Note: New line '\n' is added to the end of the text when printing to stdout.
|
||||
*/
|
||||
//#define DEBUG_PRINT
|
||||
//#define MSG_PRINT
|
||||
#define DEBUG_PRINT
|
||||
#define MSG_PRINT
|
||||
|
||||
/**
|
||||
* wpa_hexdump - conditional hex dump
|
||||
|
@ -59,7 +73,7 @@ void wpa_debug_print_timestamp(void);
|
|||
* configuration. The contents of buf is printed out has hex dump.
|
||||
*/
|
||||
#ifdef DEBUG_PRINT
|
||||
#define wpa_printf(level,fmt, args...) ets_printf(fmt,## args)
|
||||
#define wpa_printf(level,fmt, args...) ESP_LOG_LEVEL_LOCAL(level, TAG, fmt, ##args)
|
||||
|
||||
static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
|
||||
{
|
||||
|
|
|
@ -10,15 +10,45 @@
|
|||
#define EAP_H
|
||||
|
||||
#include "wpa/defs.h"
|
||||
#include "eap/eap_defs.h"
|
||||
#include "wpa2/eap_peer/eap_defs.h"
|
||||
|
||||
struct eap_sm;
|
||||
|
||||
struct eap_method_type {
|
||||
int vendor;
|
||||
u32 method;
|
||||
EapType method;
|
||||
};
|
||||
|
||||
u8 *g_wpa_anonymous_identity;
|
||||
int g_wpa_anonymous_identity_len;
|
||||
u8 *g_wpa_username;
|
||||
int g_wpa_username_len;
|
||||
const u8 *g_wpa_client_cert;
|
||||
int g_wpa_client_cert_len;
|
||||
const u8 *g_wpa_private_key;
|
||||
int g_wpa_private_key_len;
|
||||
const u8 *g_wpa_private_key_passwd;
|
||||
int g_wpa_private_key_passwd_len;
|
||||
|
||||
const u8 *g_wpa_ca_cert;
|
||||
int g_wpa_ca_cert_len;
|
||||
|
||||
u8 *g_wpa_password;
|
||||
int g_wpa_password_len;
|
||||
|
||||
u8 *g_wpa_new_password;
|
||||
int g_wpa_new_password_len;
|
||||
|
||||
const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
|
||||
void eap_deinit_prev_method(struct eap_sm *sm, const char *txt);
|
||||
struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id);
|
||||
int eap_peer_blob_init(struct eap_sm *sm);
|
||||
void eap_peer_blob_deinit(struct eap_sm *sm);
|
||||
int eap_peer_config_init(
|
||||
struct eap_sm *sm, u8 *private_key_passwd,
|
||||
int private_key_passwd_len);
|
||||
void eap_peer_config_deinit(struct eap_sm *sm);
|
||||
void eap_sm_abort(struct eap_sm *sm);
|
||||
int eap_peer_register_methods(void);
|
||||
|
||||
#endif /* EAP_H */
|
||||
|
|
|
@ -26,6 +26,10 @@ struct eap_peer_config {
|
|||
*/
|
||||
size_t identity_len;
|
||||
|
||||
u8 *anonymous_identity;
|
||||
|
||||
size_t anonymous_identity_len;
|
||||
|
||||
/**
|
||||
* password - Password string for EAP
|
||||
*
|
||||
|
@ -139,8 +143,29 @@ struct eap_peer_config {
|
|||
*/
|
||||
u8 *private_key_passwd;
|
||||
|
||||
/**
|
||||
* Phase 2
|
||||
*/
|
||||
u8 *ca_cert2;
|
||||
|
||||
u8 *ca_path2;
|
||||
|
||||
u8 *client_cert2;
|
||||
|
||||
u8 *private_key2;
|
||||
|
||||
u8 *private_key2_password;
|
||||
|
||||
/**
|
||||
* eap_methods - Allowed EAP methods
|
||||
*/
|
||||
struct eap_method_type *eap_methods;
|
||||
|
||||
|
||||
char *phase1;
|
||||
|
||||
char *phase2;
|
||||
|
||||
/**
|
||||
* pin - PIN for USIM, GSM SIM, and smartcards
|
||||
*
|
||||
|
@ -152,6 +177,10 @@ struct eap_peer_config {
|
|||
*/
|
||||
char *pin;
|
||||
|
||||
int mschapv2_retry;
|
||||
u8 *new_password;
|
||||
size_t new_password_len;
|
||||
|
||||
/**
|
||||
* fragment_size - Maximum EAP fragment size in bytes (default 1398)
|
||||
*
|
||||
|
@ -204,7 +233,7 @@ struct wpa_config_blob {
|
|||
/**
|
||||
* data - Pointer to binary data
|
||||
*/
|
||||
u8 *data;
|
||||
const u8 *data;
|
||||
|
||||
/**
|
||||
* len - Length of binary data
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "eap.h"
|
||||
#include "eap_common.h"
|
||||
#include "eap_config.h"
|
||||
#include "esp_wpa2.h"
|
||||
|
||||
/* RFC 4137 - EAP Peer state machine */
|
||||
|
||||
|
@ -54,11 +55,48 @@ struct eap_method_ret {
|
|||
Boolean allowNotifications;
|
||||
};
|
||||
|
||||
struct eap_sm;
|
||||
|
||||
struct eap_method {
|
||||
/**
|
||||
* vendor -EAP Vendor-ID
|
||||
*/
|
||||
int vendor;
|
||||
|
||||
/**
|
||||
* method - EAP type number
|
||||
*/
|
||||
EapType method;
|
||||
|
||||
/**
|
||||
* name - Name of the method (e.g., "TLS")
|
||||
*/
|
||||
const char *name;
|
||||
|
||||
struct eap_method *next;
|
||||
|
||||
void * (*init)(struct eap_sm *sm);
|
||||
void (*deinit)(struct eap_sm *sm, void *priv);
|
||||
struct wpabuf * (*process)(struct eap_sm *sm, void *priv,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData);
|
||||
bool (*isKeyAvailable)(struct eap_sm *sm, void *priv);
|
||||
u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
|
||||
size_t buflen, int verbose);
|
||||
const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
void (*free)(struct eap_method *method);
|
||||
bool (*has_reauth_data)(struct eap_sm *sm, void *priv);
|
||||
void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
|
||||
void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
|
||||
u8 * (*getSessionId)(struct eap_sm *sm, void *priv, size_t *len);
|
||||
};
|
||||
|
||||
#define CLIENT_CERT_NAME "CLC"
|
||||
#define CA_CERT_NAME "CAC"
|
||||
#define PRIVATE_KEY_NAME "PVK"
|
||||
#define BLOB_NAME_LEN 3
|
||||
#define BLOB_NUM 2
|
||||
#define BLOB_NUM 3
|
||||
|
||||
/**
|
||||
* struct eap_sm - EAP state machine data
|
||||
|
@ -80,9 +118,26 @@ struct eap_sm {
|
|||
u8 wpa2_sig_cnt[SIG_WPA2_NUM];
|
||||
#endif
|
||||
u8 finish_state;
|
||||
|
||||
int init_phase2;
|
||||
bool peap_done;
|
||||
|
||||
u8 *eapKeyData;
|
||||
size_t eapKeyDataLen;
|
||||
struct wpabuf *lastRespData;
|
||||
const struct eap_method *m;
|
||||
};
|
||||
|
||||
wpa2_crypto_funcs_t wpa2_crypto_funcs;
|
||||
|
||||
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
|
||||
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len);
|
||||
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
|
||||
const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
|
||||
struct eap_peer_config * eap_get_config(struct eap_sm *sm);
|
||||
const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm, const char *name);
|
||||
bool wifi_sta_get_enterprise_disable_time_check(void);
|
||||
|
||||
struct wpabuf * eap_sm_build_identity_resp(struct eap_sm *sm, u8 id, int encrypted);
|
||||
|
||||
#endif /* EAP_I_H */
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* EAP peer: Method registration
|
||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_METHODS_H
|
||||
#define EAP_METHODS_H
|
||||
|
||||
#include "eap_defs.h"
|
||||
|
||||
const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
|
||||
const struct eap_method * eap_peer_get_methods(size_t *count);
|
||||
|
||||
u32 eap_get_phase2_type(const char *name, int *vendor);
|
||||
struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
|
||||
size_t *count);
|
||||
|
||||
struct eap_method * eap_peer_method_alloc(int verdor, EapType method,
|
||||
const char *name);
|
||||
|
||||
void eap_peer_method_free(struct eap_method *method);
|
||||
int eap_peer_method_register(struct eap_method *method);
|
||||
|
||||
void eap_peer_unregister_methods(void);
|
||||
|
||||
//int eap_peer_md5_register(void);
|
||||
int eap_peer_tls_register(void);
|
||||
int eap_peer_peap_register(void);
|
||||
int eap_peer_ttls_register(void);
|
||||
int eap_peer_mschapv2_register(void);
|
||||
|
||||
#endif /* EAP_METHODS_H */
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* EAP-PEAP common routines
|
||||
* Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_PEAP_COMMON_H
|
||||
#define EAP_PEAP_COMMON_H
|
||||
|
||||
int peap_prfplus(int version, const u8 *key, size_t key_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *buf, size_t buf_len);
|
||||
|
||||
#endif /* EAP_PEAP_COMMON_H */
|
112
components/wpa_supplicant/include/wpa2/eap_peer/eap_tlv_common.h
Normal file
112
components/wpa_supplicant/include/wpa2/eap_peer/eap_tlv_common.h
Normal file
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
|
||||
* Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_TLV_COMMON_H
|
||||
#define EAP_TLV_COMMON_H
|
||||
|
||||
/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */
|
||||
#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
|
||||
#define EAP_TLV_NAK_TLV 4
|
||||
#define EAP_TLV_ERROR_CODE_TLV 5
|
||||
#define EAP_TLV_CONNECTION_BINDING_TLV 6
|
||||
#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
|
||||
#define EAP_TLV_URI_TLV 8
|
||||
#define EAP_TLV_EAP_PAYLOAD_TLV 9
|
||||
#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
|
||||
#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */
|
||||
#define EAP_TLV_CRYPTO_BINDING_TLV 12
|
||||
#define EAP_TLV_CALLING_STATION_ID_TLV 13
|
||||
#define EAP_TLV_CALLED_STATION_ID_TLV 14
|
||||
#define EAP_TLV_NAS_PORT_TYPE_TLV 15
|
||||
#define EAP_TLV_SERVER_IDENTIFIER_TLV 16
|
||||
#define EAP_TLV_IDENTITY_TYPE_TLV 17
|
||||
#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
|
||||
#define EAP_TLV_REQUEST_ACTION_TLV 19
|
||||
#define EAP_TLV_PKCS7_TLV 20
|
||||
|
||||
#define EAP_TLV_RESULT_SUCCESS 1
|
||||
#define EAP_TLV_RESULT_FAILURE 2
|
||||
|
||||
#define EAP_TLV_TYPE_MANDATORY 0x8000
|
||||
#define EAP_TLV_TYPE_MASK 0x3fff
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(push, 1)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
struct eap_tlv_hdr {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct eap_tlv_nak_tlv {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be32 vendor_id;
|
||||
be16 nak_type;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct eap_tlv_result_tlv {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be16 status;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
|
||||
struct eap_tlv_intermediate_result_tlv {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be16 status;
|
||||
/* Followed by optional TLVs */
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
|
||||
struct eap_tlv_crypto_binding_tlv {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
u8 reserved;
|
||||
u8 version;
|
||||
u8 received_version;
|
||||
u8 subtype;
|
||||
u8 nonce[32];
|
||||
u8 compound_mac[20];
|
||||
} STRUCT_PACKED;
|
||||
|
||||
struct eap_tlv_pac_ack_tlv {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be16 pac_type;
|
||||
be16 pac_len;
|
||||
be16 result;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* RFC 4851, Section 4.2.9 - Request-Action TLV */
|
||||
struct eap_tlv_request_action_tlv {
|
||||
be16 tlv_type;
|
||||
be16 length;
|
||||
be16 action;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
|
||||
struct eap_tlv_pac_type_tlv {
|
||||
be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
|
||||
be16 length;
|
||||
be16 pac_type;
|
||||
} STRUCT_PACKED;
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
|
||||
#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
|
||||
|
||||
#define EAP_TLV_ACTION_PROCESS_TLV 1
|
||||
#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
|
||||
|
||||
#endif /* EAP_TLV_COMMON_H */
|
65
components/wpa_supplicant/include/wpa2/eap_peer/eap_ttls.h
Normal file
65
components/wpa_supplicant/include/wpa2/eap_peer/eap_ttls.h
Normal file
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* EAP server/peer: EAP-TTLS (RFC 5281)
|
||||
* Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef EAP_TTLS_H
|
||||
#define EAP_TTLS_H
|
||||
|
||||
struct ttls_avp {
|
||||
be32 avp_code;
|
||||
be32 avp_length; /* 8-bit flags, 24-bit length;
|
||||
* length includes AVP header */
|
||||
/* optional 32-bit Vendor-ID */
|
||||
/* Data */
|
||||
};
|
||||
|
||||
struct ttls_avp_vendor {
|
||||
be32 avp_code;
|
||||
be32 avp_length; /* 8-bit flags, 24-bit length;
|
||||
* length includes AVP header */
|
||||
be32 vendor_id;
|
||||
/* Data */
|
||||
};
|
||||
|
||||
#define AVP_FLAGS_VENDOR 0x80
|
||||
#define AVP_FLAGS_MANDATORY 0x40
|
||||
|
||||
#define AVP_PAD(start, pos) \
|
||||
do { \
|
||||
int __pad; \
|
||||
__pad = (4 - (((pos) - (start)) & 3)) & 3; \
|
||||
os_memset((pos), 0, __pad); \
|
||||
pos += __pad; \
|
||||
} while (0)
|
||||
|
||||
|
||||
/* RFC 2865 */
|
||||
#define RADIUS_ATTR_USER_NAME 1
|
||||
#define RADIUS_ATTR_USER_PASSWORD 2
|
||||
#define RADIUS_ATTR_CHAP_PASSWORD 3
|
||||
#define RADIUS_ATTR_REPLY_MESSAGE 18
|
||||
#define RADIUS_ATTR_CHAP_CHALLENGE 60
|
||||
#define RADIUS_ATTR_EAP_MESSAGE 79
|
||||
|
||||
/* RFC 2548 */
|
||||
#define RADIUS_VENDOR_ID_MICROSOFT 311
|
||||
#define RADIUS_ATTR_MS_CHAP_RESPONSE 1
|
||||
#define RADIUS_ATTR_MS_CHAP_ERROR 2
|
||||
#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6
|
||||
#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11
|
||||
#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25
|
||||
#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26
|
||||
#define RADIUS_ATTR_MS_CHAP2_CPW 27
|
||||
|
||||
#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16
|
||||
#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50
|
||||
#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8
|
||||
#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50
|
||||
#define EAP_TTLS_CHAP_CHALLENGE_LEN 16
|
||||
#define EAP_TTLS_CHAP_PASSWORD_LEN 16
|
||||
|
||||
#endif /* EAP_TTLS_H */
|
24
components/wpa_supplicant/include/wpa2/eap_peer/mschapv2.h
Normal file
24
components/wpa_supplicant/include/wpa2/eap_peer/mschapv2.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* MSCHAPV2
|
||||
*/
|
||||
|
||||
|
||||
#ifndef MSCHAPV2_H
|
||||
#define MSCHAPV2_H
|
||||
|
||||
#define MSCHAPV2_CHAL_LEN 16
|
||||
#define MSCHAPV2_NT_RESPONSE_LEN 24
|
||||
#define MSCHAPV2_AUTH_RESPONSE_LEN 20
|
||||
#define MSCHAPV2_MASTER_KEY_LEN 16
|
||||
|
||||
const u8 * mschapv2_remove_domain(const u8 *username, size_t *len);
|
||||
int mschapv2_derive_response(const u8 *username, size_t username_len,
|
||||
const u8 *password, size_t password_len,
|
||||
int pwhash,
|
||||
const u8 *auth_challenge,
|
||||
const u8 *peer_challenge,
|
||||
u8 *nt_response, u8 *auth_response,
|
||||
u8 *master_key);
|
||||
int mschapv2_verify_auth_response(const u8 *auth_response,
|
||||
const u8 *buf, size_t buf_len);
|
||||
#endif /* MSCHAPV2_H */
|
|
@ -13,7 +13,6 @@
|
|||
* If CONFIG_INTERNAL_LIBTOMMATH is defined, bignum.c includes this
|
||||
* libtommath.c file instead of using the external LibTomMath library.
|
||||
*/
|
||||
#include "c_types.h"
|
||||
#include "os.h"
|
||||
#include "stdarg.h"
|
||||
|
||||
|
@ -193,7 +192,7 @@ static int mp_mul_d (mp_int * a, mp_digit b, mp_int * c);
|
|||
|
||||
|
||||
/* reverse an array, used for radix code */
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
bn_reverse (unsigned char *s, int len)
|
||||
{
|
||||
int ix, iy;
|
||||
|
@ -212,7 +211,7 @@ bn_reverse (unsigned char *s, int len)
|
|||
|
||||
|
||||
/* low level addition, based on HAC pp.594, Algorithm 14.7 */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
s_mp_add (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
mp_int *x;
|
||||
|
@ -301,7 +300,7 @@ s_mp_add (mp_int * a, mp_int * b, mp_int * c)
|
|||
|
||||
|
||||
/* low level subtraction (assumes |a| > |b|), HAC pp.595 Algorithm 14.9 */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
int olduse, res, min, max;
|
||||
|
@ -369,7 +368,7 @@ s_mp_sub (mp_int * a, mp_int * b, mp_int * c)
|
|||
|
||||
|
||||
/* init a new mp_int */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_init (mp_int * a)
|
||||
{
|
||||
int i;
|
||||
|
@ -396,7 +395,7 @@ mp_init (mp_int * a)
|
|||
|
||||
|
||||
/* clear one (frees) */
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
mp_clear (mp_int * a)
|
||||
{
|
||||
int i;
|
||||
|
@ -420,7 +419,7 @@ mp_clear (mp_int * a)
|
|||
|
||||
|
||||
/* high level addition (handles signs) */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_add (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
int sa, sb, res;
|
||||
|
@ -453,7 +452,7 @@ mp_add (mp_int * a, mp_int * b, mp_int * c)
|
|||
|
||||
|
||||
/* high level subtraction (handles signs) */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_sub (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
int sa, sb, res;
|
||||
|
@ -491,7 +490,7 @@ mp_sub (mp_int * a, mp_int * b, mp_int * c)
|
|||
|
||||
|
||||
/* high level multiplication (handles sign) */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_mul (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
int res, neg;
|
||||
|
@ -539,7 +538,7 @@ mp_mul (mp_int * a, mp_int * b, mp_int * c)
|
|||
|
||||
|
||||
/* d = a * b (mod c) */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
|
||||
{
|
||||
int res;
|
||||
|
@ -560,7 +559,7 @@ mp_mulmod (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
|
|||
|
||||
|
||||
/* c = a mod b, 0 <= c < b */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_mod (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
mp_int t;
|
||||
|
@ -592,10 +591,12 @@ mp_mod (mp_int * a, mp_int * b, mp_int * c)
|
|||
* embedded in the normal function but that wasted a lot of stack space
|
||||
* for nothing (since 99% of the time the Montgomery code would be called)
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
|
||||
{
|
||||
int dr;
|
||||
#if defined(BN_MP_DR_IS_MODULUS_C)||defined(BN_MP_REDUCE_IS_2K_C)||defined(BN_MP_EXPTMOD_FAST_C)
|
||||
int dr = 0;
|
||||
#endif
|
||||
|
||||
/* modulus P must be positive */
|
||||
if (P->sign == MP_NEG) {
|
||||
|
@ -652,9 +653,6 @@ mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
|
|||
#ifdef BN_MP_DR_IS_MODULUS_C
|
||||
/* is it a DR modulus? */
|
||||
dr = mp_dr_is_modulus(P);
|
||||
#else
|
||||
/* default to no */
|
||||
dr = 0;
|
||||
#endif
|
||||
|
||||
#ifdef BN_MP_REDUCE_IS_2K_C
|
||||
|
@ -685,7 +683,7 @@ mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y)
|
|||
|
||||
|
||||
/* compare two ints (signed)*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_cmp (mp_int * a, mp_int * b)
|
||||
{
|
||||
/* compare based on sign */
|
||||
|
@ -708,7 +706,7 @@ mp_cmp (mp_int * a, mp_int * b)
|
|||
|
||||
|
||||
/* compare a digit */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_cmp_d(mp_int * a, mp_digit b)
|
||||
{
|
||||
/* compare based on sign */
|
||||
|
@ -734,7 +732,7 @@ mp_cmp_d(mp_int * a, mp_digit b)
|
|||
|
||||
#ifndef LTM_NO_NEG_EXP
|
||||
/* hac 14.61, pp608 */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_invmod (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
/* b cannot be negative */
|
||||
|
@ -764,7 +762,7 @@ mp_invmod (mp_int * a, mp_int * b, mp_int * c)
|
|||
|
||||
|
||||
/* get the size for an unsigned equivalent */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_unsigned_bin_size (mp_int * a)
|
||||
{
|
||||
int size = mp_count_bits (a);
|
||||
|
@ -774,7 +772,7 @@ mp_unsigned_bin_size (mp_int * a)
|
|||
|
||||
#ifndef LTM_NO_NEG_EXP
|
||||
/* hac 14.61, pp608 */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_invmod_slow (mp_int * a, mp_int * b, mp_int * c)
|
||||
{
|
||||
mp_int x, y, u, v, A, B, C, D;
|
||||
|
@ -931,7 +929,7 @@ LBL_ERR:mp_clear_multi (&x, &y, &u, &v, &A, &B, &C, &D, NULL);
|
|||
|
||||
|
||||
/* compare maginitude of two ints (unsigned) */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_cmp_mag (mp_int * a, mp_int * b)
|
||||
{
|
||||
int n;
|
||||
|
@ -967,7 +965,7 @@ mp_cmp_mag (mp_int * a, mp_int * b)
|
|||
|
||||
|
||||
/* reads a unsigned char array, assumes the msb is stored first [big endian] */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
|
||||
{
|
||||
int res;
|
||||
|
@ -1003,7 +1001,7 @@ mp_read_unsigned_bin (mp_int * a, const unsigned char *b, int c)
|
|||
|
||||
|
||||
/* store in unsigned [big endian] format */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_to_unsigned_bin (mp_int * a, unsigned char *b)
|
||||
{
|
||||
int x, res;
|
||||
|
@ -1032,7 +1030,7 @@ mp_to_unsigned_bin (mp_int * a, unsigned char *b)
|
|||
|
||||
|
||||
/* shift right by a certain bit count (store quotient in c, optional remainder in d) */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
|
||||
{
|
||||
mp_digit D, r, rr;
|
||||
|
@ -1109,7 +1107,7 @@ mp_div_2d (mp_int * a, int b, mp_int * c, mp_int * d)
|
|||
}
|
||||
|
||||
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_init_copy (mp_int * a, mp_int * b)
|
||||
{
|
||||
int res;
|
||||
|
@ -1122,7 +1120,7 @@ mp_init_copy (mp_int * a, mp_int * b)
|
|||
|
||||
|
||||
/* set to zero */
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
mp_zero (mp_int * a)
|
||||
{
|
||||
int n;
|
||||
|
@ -1139,7 +1137,7 @@ mp_zero (mp_int * a)
|
|||
|
||||
|
||||
/* copy, b = a */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_copy (mp_int * a, mp_int * b)
|
||||
{
|
||||
int res, n;
|
||||
|
@ -1187,7 +1185,7 @@ mp_copy (mp_int * a, mp_int * b)
|
|||
|
||||
|
||||
/* shift right a certain amount of digits */
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
mp_rshd (mp_int * a, int b)
|
||||
{
|
||||
int x;
|
||||
|
@ -1242,7 +1240,7 @@ mp_rshd (mp_int * a, int b)
|
|||
/* swap the elements of two integers, for cases where you can't simply swap the
|
||||
* mp_int pointers around
|
||||
*/
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
mp_exch (mp_int * a, mp_int * b)
|
||||
{
|
||||
mp_int t;
|
||||
|
@ -1260,7 +1258,7 @@ mp_exch (mp_int * a, mp_int * b)
|
|||
* Typically very fast. Also fixes the sign if there
|
||||
* are no more leading digits
|
||||
*/
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
mp_clamp (mp_int * a)
|
||||
{
|
||||
/* decrease used while the most significant digit is
|
||||
|
@ -1278,7 +1276,7 @@ mp_clamp (mp_int * a)
|
|||
|
||||
|
||||
/* grow as required */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_grow (mp_int * a, int size)
|
||||
{
|
||||
int i;
|
||||
|
@ -1320,7 +1318,7 @@ mp_grow (mp_int * a, int size)
|
|||
*
|
||||
* Simple function copies the input and fixes the sign to positive
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_abs (mp_int * a, mp_int * b)
|
||||
{
|
||||
int res;
|
||||
|
@ -1341,7 +1339,7 @@ mp_abs (mp_int * a, mp_int * b)
|
|||
|
||||
|
||||
/* set to a digit */
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
mp_set (mp_int * a, mp_digit b)
|
||||
{
|
||||
mp_zero (a);
|
||||
|
@ -1352,7 +1350,7 @@ mp_set (mp_int * a, mp_digit b)
|
|||
|
||||
#ifndef LTM_NO_NEG_EXP
|
||||
/* b = a/2 */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_div_2(mp_int * a, mp_int * b)
|
||||
{
|
||||
int x, res, oldused;
|
||||
|
@ -1402,7 +1400,7 @@ mp_div_2(mp_int * a, mp_int * b)
|
|||
|
||||
|
||||
/* shift left by a certain bit count */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_mul_2d (mp_int * a, int b, mp_int * c)
|
||||
{
|
||||
mp_digit d;
|
||||
|
@ -1468,7 +1466,7 @@ mp_mul_2d (mp_int * a, int b, mp_int * c)
|
|||
|
||||
|
||||
#ifdef BN_MP_INIT_MULTI_C
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_init_multi(mp_int *mp, ...)
|
||||
{
|
||||
mp_err res = MP_OKAY; /* Assume ok until proven otherwise */
|
||||
|
@ -1508,7 +1506,7 @@ mp_init_multi(mp_int *mp, ...)
|
|||
|
||||
|
||||
#ifdef BN_MP_CLEAR_MULTI_C
|
||||
static void ICACHE_FLASH_ATTR
|
||||
static void
|
||||
mp_clear_multi(mp_int *mp, ...)
|
||||
{
|
||||
mp_int* next_mp = mp;
|
||||
|
@ -1524,7 +1522,7 @@ mp_clear_multi(mp_int *mp, ...)
|
|||
|
||||
|
||||
/* shift left a certain amount of digits */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_lshd (mp_int * a, int b)
|
||||
{
|
||||
int x, res;
|
||||
|
@ -1572,7 +1570,7 @@ mp_lshd (mp_int * a, int b)
|
|||
|
||||
|
||||
/* returns the number of bits in an int */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_count_bits (mp_int * a)
|
||||
{
|
||||
int r;
|
||||
|
@ -1597,7 +1595,7 @@ mp_count_bits (mp_int * a)
|
|||
|
||||
|
||||
/* calc a value mod 2**b */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_mod_2d (mp_int * a, int b, mp_int * c)
|
||||
{
|
||||
int x, res;
|
||||
|
@ -1634,7 +1632,7 @@ mp_mod_2d (mp_int * a, int b, mp_int * c)
|
|||
#ifdef BN_MP_DIV_SMALL
|
||||
|
||||
/* slower bit-bang division... also smaller */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_div(mp_int * a, mp_int * b, mp_int * c, mp_int * d)
|
||||
{
|
||||
mp_int ta, tb, tq, q;
|
||||
|
@ -1717,7 +1715,7 @@ LBL_ERR:
|
|||
* The overall algorithm is as described as
|
||||
* 14.20 from HAC but fixed to treat these cases.
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_div (mp_int * a, mp_int * b, mp_int * c, mp_int * d)
|
||||
{
|
||||
mp_int q, x, y, t1, t2;
|
||||
|
@ -1910,7 +1908,7 @@ LBL_Q:mp_clear (&q);
|
|||
#define TAB_SIZE 256
|
||||
#endif
|
||||
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
s_mp_exptmod (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
|
||||
{
|
||||
mp_int M[TAB_SIZE], res, mu;
|
||||
|
@ -2139,7 +2137,7 @@ LBL_M:
|
|||
|
||||
|
||||
/* computes b = a*a */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_sqr (mp_int * a, mp_int * b)
|
||||
{
|
||||
int res;
|
||||
|
@ -2181,7 +2179,7 @@ if (a->used >= KARATSUBA_SQR_CUTOFF) {
|
|||
This differs from reduce_2k since "d" can be larger
|
||||
than a single digit.
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_reduce_2k_l(mp_int *a, mp_int *n, mp_int *d)
|
||||
{
|
||||
mp_int q;
|
||||
|
@ -2220,7 +2218,7 @@ ERR:
|
|||
|
||||
|
||||
/* determines the setup value */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_reduce_2k_setup_l(mp_int *a, mp_int *d)
|
||||
{
|
||||
int res;
|
||||
|
@ -2249,7 +2247,7 @@ ERR:
|
|||
* Simple algorithm which zeroes the int, grows it then just sets one bit
|
||||
* as required.
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_2expt (mp_int * a, int b)
|
||||
{
|
||||
int res;
|
||||
|
@ -2275,7 +2273,7 @@ mp_2expt (mp_int * a, int b)
|
|||
/* pre-calculate the value required for Barrett reduction
|
||||
* For a given modulus "b" it calulates the value required in "a"
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_reduce_setup (mp_int * a, mp_int * b)
|
||||
{
|
||||
int res;
|
||||
|
@ -2291,7 +2289,7 @@ mp_reduce_setup (mp_int * a, mp_int * b)
|
|||
* precomputed via mp_reduce_setup.
|
||||
* From HAC pp.604 Algorithm 14.42
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_reduce (mp_int * x, mp_int * m, mp_int * mu)
|
||||
{
|
||||
mp_int q;
|
||||
|
@ -2375,7 +2373,7 @@ CLEANUP:
|
|||
* HAC pp. 595, Algorithm 14.12 Modified so you can control how
|
||||
* many digits of output are created.
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
|
||||
{
|
||||
mp_int t;
|
||||
|
@ -2458,7 +2456,7 @@ s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
|
|||
* Based on Algorithm 14.12 on pp.595 of HAC.
|
||||
*
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
|
||||
{
|
||||
int olduse, res, pa, ix, iz;
|
||||
|
@ -2531,7 +2529,7 @@ fast_s_mp_mul_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
|
|||
|
||||
|
||||
/* init an mp_init for a given size */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_init_size (mp_int * a, int size)
|
||||
{
|
||||
int x;
|
||||
|
@ -2560,7 +2558,7 @@ mp_init_size (mp_int * a, int size)
|
|||
|
||||
|
||||
/* low level squaring, b = a*a, HAC pp.596-597, Algorithm 14.16 */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
s_mp_sqr (mp_int * a, mp_int * b)
|
||||
{
|
||||
mp_int t;
|
||||
|
@ -2627,7 +2625,7 @@ s_mp_sqr (mp_int * a, mp_int * b)
|
|||
/* multiplies |a| * |b| and does not compute the lower digs digits
|
||||
* [meant to get the higher part of the product]
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
|
||||
{
|
||||
mp_int t;
|
||||
|
@ -2687,7 +2685,7 @@ s_mp_mul_high_digs (mp_int * a, mp_int * b, mp_int * c, int digs)
|
|||
|
||||
#ifdef BN_MP_MONTGOMERY_SETUP_C
|
||||
/* setups the montgomery reduction stuff */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_montgomery_setup (mp_int * n, mp_digit * rho)
|
||||
{
|
||||
mp_digit x, b;
|
||||
|
@ -2735,7 +2733,7 @@ mp_montgomery_setup (mp_int * n, mp_digit * rho)
|
|||
*
|
||||
* Based on Algorithm 14.32 on pp.601 of HAC.
|
||||
*/
|
||||
int ICACHE_FLASH_ATTR
|
||||
int
|
||||
fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
|
||||
{
|
||||
int ix, res, olduse;
|
||||
|
@ -2883,7 +2881,7 @@ fast_mp_montgomery_reduce (mp_int * x, mp_int * n, mp_digit rho)
|
|||
|
||||
#ifdef BN_MP_MUL_2_C
|
||||
/* b = a*2 */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_mul_2(mp_int * a, mp_int * b)
|
||||
{
|
||||
int x, res, oldused;
|
||||
|
@ -2953,7 +2951,7 @@ mp_mul_2(mp_int * a, mp_int * b)
|
|||
* The method is slightly modified to shift B unconditionally up to just under
|
||||
* the leading bit of b. This saves a lot of multiple precision shifting.
|
||||
*/
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
|
||||
{
|
||||
int x, bits, res;
|
||||
|
@ -2997,7 +2995,7 @@ mp_montgomery_calc_normalization (mp_int * a, mp_int * b)
|
|||
* Uses Montgomery or Diminished Radix reduction [whichever appropriate]
|
||||
*/
|
||||
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_exptmod_fast (mp_int * G, mp_int * X, mp_int * P, mp_int * Y, int redmode)
|
||||
{
|
||||
mp_int M[TAB_SIZE], res;
|
||||
|
@ -3296,7 +3294,7 @@ LBL_M:
|
|||
After that loop you do the squares and add them in.
|
||||
*/
|
||||
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
fast_s_mp_sqr (mp_int * a, mp_int * b)
|
||||
{
|
||||
int olduse, res, pa, ix, iz;
|
||||
|
@ -3384,7 +3382,7 @@ fast_s_mp_sqr (mp_int * a, mp_int * b)
|
|||
|
||||
#ifdef BN_MP_MUL_D_C
|
||||
/* multiply by a digit */
|
||||
static int ICACHE_FLASH_ATTR
|
||||
static int
|
||||
mp_mul_d (mp_int * a, mp_digit b, mp_int * c)
|
||||
{
|
||||
mp_digit u, *tmpa, *tmpc;
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#ifndef BASE64_H
|
||||
#define BASE64_H
|
||||
|
||||
unsigned char * _base64_encode(const unsigned char *src, size_t len,
|
||||
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,
|
||||
unsigned char * base64_decode(const unsigned char *src, size_t len,
|
||||
size_t *out_len);
|
||||
|
||||
#endif /* BASE64_H */
|
||||
|
|
|
@ -23,10 +23,10 @@ void ext_password_free(struct wpabuf *pw);
|
|||
|
||||
#else /* CONFIG_EXT_PASSWORD */
|
||||
|
||||
#define ext_password_init(b, p) ((void *) 1)
|
||||
#define ext_password_deinit(d) do { } while (0)
|
||||
#define ext_password_get(d, n) (NULL)
|
||||
#define ext_password_free(p) do { } while (0)
|
||||
#define ext_password_init(b, p)
|
||||
#define ext_password_deinit(d)
|
||||
#define ext_password_get(d, n)
|
||||
#define ext_password_free(p)
|
||||
|
||||
#endif /* CONFIG_EXT_PASSWORD */
|
||||
|
||||
|
|
18
components/wpa_supplicant/include/wps/utils/uuid.h
Normal file
18
components/wpa_supplicant/include/wps/utils/uuid.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Universally Unique IDentifier (UUID)
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef UUID_H
|
||||
#define UUID_H
|
||||
|
||||
#define UUID_LEN 16
|
||||
|
||||
int uuid_str2bin(const char *str, u8 *bin);
|
||||
int uuid_bin2str(const u8 *bin, char *str, size_t max_len);
|
||||
int is_nil_uuid(const u8 *uuid);
|
||||
|
||||
#endif /* UUID_H */
|
1067
components/wpa_supplicant/include/wps/wps.h
Normal file
1067
components/wpa_supplicant/include/wps/wps.h
Normal file
File diff suppressed because it is too large
Load diff
108
components/wpa_supplicant/include/wps/wps_attr_parse.h
Normal file
108
components/wpa_supplicant/include/wps/wps_attr_parse.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - attribute parsing
|
||||
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPS_ATTR_PARSE_H
|
||||
#define WPS_ATTR_PARSE_H
|
||||
|
||||
#include "wps/wps.h"
|
||||
|
||||
struct wps_parse_attr {
|
||||
/* fixed length fields */
|
||||
const u8 *version; /* 1 octet */
|
||||
const u8 *version2; /* 1 octet */
|
||||
const u8 *msg_type; /* 1 octet */
|
||||
const u8 *enrollee_nonce; /* WPS_NONCE_LEN (16) octets */
|
||||
const u8 *registrar_nonce; /* WPS_NONCE_LEN (16) octets */
|
||||
const u8 *uuid_r; /* WPS_UUID_LEN (16) octets */
|
||||
const u8 *uuid_e; /* WPS_UUID_LEN (16) octets */
|
||||
const u8 *auth_type_flags; /* 2 octets */
|
||||
const u8 *encr_type_flags; /* 2 octets */
|
||||
const u8 *conn_type_flags; /* 1 octet */
|
||||
const u8 *config_methods; /* 2 octets */
|
||||
const u8 *sel_reg_config_methods; /* 2 octets */
|
||||
const u8 *primary_dev_type; /* 8 octets */
|
||||
const u8 *rf_bands; /* 1 octet */
|
||||
const u8 *assoc_state; /* 2 octets */
|
||||
const u8 *config_error; /* 2 octets */
|
||||
const u8 *dev_password_id; /* 2 octets */
|
||||
const u8 *os_version; /* 4 octets */
|
||||
const u8 *wps_state; /* 1 octet */
|
||||
const u8 *authenticator; /* WPS_AUTHENTICATOR_LEN (8) octets */
|
||||
const u8 *r_hash1; /* WPS_HASH_LEN (32) octets */
|
||||
const u8 *r_hash2; /* WPS_HASH_LEN (32) octets */
|
||||
const u8 *e_hash1; /* WPS_HASH_LEN (32) octets */
|
||||
const u8 *e_hash2; /* WPS_HASH_LEN (32) octets */
|
||||
const u8 *r_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
|
||||
const u8 *r_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
|
||||
const u8 *e_snonce1; /* WPS_SECRET_NONCE_LEN (16) octets */
|
||||
const u8 *e_snonce2; /* WPS_SECRET_NONCE_LEN (16) octets */
|
||||
const u8 *key_wrap_auth; /* WPS_KWA_LEN (8) octets */
|
||||
const u8 *auth_type; /* 2 octets */
|
||||
const u8 *encr_type; /* 2 octets */
|
||||
const u8 *network_idx; /* 1 octet */
|
||||
const u8 *network_key_idx; /* 1 octet */
|
||||
const u8 *mac_addr; /* ETH_ALEN (6) octets */
|
||||
const u8 *key_prov_auto; /* 1 octet (Bool) */
|
||||
const u8 *dot1x_enabled; /* 1 octet (Bool) */
|
||||
const u8 *selected_registrar; /* 1 octet (Bool) */
|
||||
const u8 *request_type; /* 1 octet */
|
||||
const u8 *response_type; /* 1 octet */
|
||||
const u8 *ap_setup_locked; /* 1 octet */
|
||||
const u8 *settings_delay_time; /* 1 octet */
|
||||
const u8 *network_key_shareable; /* 1 octet (Bool) */
|
||||
const u8 *request_to_enroll; /* 1 octet (Bool) */
|
||||
const u8 *ap_channel; /* 2 octets */
|
||||
|
||||
/* variable length fields */
|
||||
const u8 *manufacturer;
|
||||
size_t manufacturer_len;
|
||||
const u8 *model_name;
|
||||
size_t model_name_len;
|
||||
const u8 *model_number;
|
||||
size_t model_number_len;
|
||||
const u8 *serial_number;
|
||||
size_t serial_number_len;
|
||||
const u8 *dev_name;
|
||||
size_t dev_name_len;
|
||||
const u8 *public_key;
|
||||
size_t public_key_len;
|
||||
const u8 *encr_settings;
|
||||
size_t encr_settings_len;
|
||||
const u8 *ssid; /* <= 32 octets */
|
||||
size_t ssid_len;
|
||||
const u8 *network_key; /* <= 64 octets */
|
||||
size_t network_key_len;
|
||||
const u8 *eap_type; /* <= 8 octets */
|
||||
size_t eap_type_len;
|
||||
const u8 *eap_identity; /* <= 64 octets */
|
||||
size_t eap_identity_len;
|
||||
const u8 *authorized_macs; /* <= 30 octets */
|
||||
size_t authorized_macs_len;
|
||||
const u8 *sec_dev_type_list; /* <= 128 octets */
|
||||
size_t sec_dev_type_list_len;
|
||||
const u8 *oob_dev_password; /* 38..54 octets */
|
||||
size_t oob_dev_password_len;
|
||||
|
||||
/* attributes that can occur multiple times */
|
||||
#define MAX_CRED_COUNT 10
|
||||
const u8 *cred[MAX_CRED_COUNT];
|
||||
size_t cred_len[MAX_CRED_COUNT];
|
||||
size_t num_cred;
|
||||
|
||||
#define MAX_REQ_DEV_TYPE_COUNT 10
|
||||
const u8 *req_dev_type[MAX_REQ_DEV_TYPE_COUNT];
|
||||
size_t num_req_dev_type;
|
||||
|
||||
const u8 *vendor_ext[MAX_WPS_PARSE_VENDOR_EXT];
|
||||
size_t vendor_ext_len[MAX_WPS_PARSE_VENDOR_EXT];
|
||||
size_t num_vendor_ext;
|
||||
};
|
||||
|
||||
int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
|
||||
|
||||
#endif /* WPS_ATTR_PARSE_H */
|
342
components/wpa_supplicant/include/wps/wps_defs.h
Normal file
342
components/wpa_supplicant/include/wps/wps_defs.h
Normal file
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - message definitions
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPS_DEFS_H
|
||||
#define WPS_DEFS_H
|
||||
|
||||
#ifdef CONFIG_WPS_TESTING
|
||||
|
||||
extern int wps_version_number;
|
||||
extern int wps_testing_dummy_cred;
|
||||
#define WPS_VERSION wps_version_number
|
||||
|
||||
#else /* CONFIG_WPS_TESTING */
|
||||
|
||||
#ifdef CONFIG_WPS2
|
||||
#define WPS_VERSION 0x20
|
||||
#else /* CONFIG_WPS2 */
|
||||
#define WPS_VERSION 0x10
|
||||
#endif /* CONFIG_WPS2 */
|
||||
|
||||
#endif /* CONFIG_WPS_TESTING */
|
||||
|
||||
#define CONFIG_WPS_STRICT
|
||||
|
||||
/* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */
|
||||
#define WPS_DH_GROUP 5
|
||||
|
||||
#define WPS_UUID_LEN 16
|
||||
#define WPS_NONCE_LEN 16
|
||||
#define WPS_AUTHENTICATOR_LEN 8
|
||||
#define WPS_AUTHKEY_LEN 32
|
||||
#define WPS_KEYWRAPKEY_LEN 16
|
||||
#define WPS_EMSK_LEN 32
|
||||
#define WPS_PSK_LEN 16
|
||||
#define WPS_SECRET_NONCE_LEN 16
|
||||
#define WPS_HASH_LEN 32
|
||||
#define WPS_KWA_LEN 8
|
||||
#define WPS_MGMTAUTHKEY_LEN 32
|
||||
#define WPS_MGMTENCKEY_LEN 16
|
||||
#define WPS_MGMT_KEY_ID_LEN 16
|
||||
#define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16
|
||||
#define WPS_OOB_DEVICE_PASSWORD_LEN 32
|
||||
#define WPS_OOB_PUBKEY_HASH_LEN 20
|
||||
|
||||
/* Attribute Types */
|
||||
enum wps_attribute {
|
||||
ATTR_AP_CHANNEL = 0x1001,
|
||||
ATTR_ASSOC_STATE = 0x1002,
|
||||
ATTR_AUTH_TYPE = 0x1003,
|
||||
ATTR_AUTH_TYPE_FLAGS = 0x1004,
|
||||
ATTR_AUTHENTICATOR = 0x1005,
|
||||
ATTR_CONFIG_METHODS = 0x1008,
|
||||
ATTR_CONFIG_ERROR = 0x1009,
|
||||
ATTR_CONFIRM_URL4 = 0x100a,
|
||||
ATTR_CONFIRM_URL6 = 0x100b,
|
||||
ATTR_CONN_TYPE = 0x100c,
|
||||
ATTR_CONN_TYPE_FLAGS = 0x100d,
|
||||
ATTR_CRED = 0x100e,
|
||||
ATTR_ENCR_TYPE = 0x100f,
|
||||
ATTR_ENCR_TYPE_FLAGS = 0x1010,
|
||||
ATTR_DEV_NAME = 0x1011,
|
||||
ATTR_DEV_PASSWORD_ID = 0x1012,
|
||||
ATTR_E_HASH1 = 0x1014,
|
||||
ATTR_E_HASH2 = 0x1015,
|
||||
ATTR_E_SNONCE1 = 0x1016,
|
||||
ATTR_E_SNONCE2 = 0x1017,
|
||||
ATTR_ENCR_SETTINGS = 0x1018,
|
||||
ATTR_ENROLLEE_NONCE = 0x101a,
|
||||
ATTR_FEATURE_ID = 0x101b,
|
||||
ATTR_IDENTITY = 0x101c,
|
||||
ATTR_IDENTITY_PROOF = 0x101d,
|
||||
ATTR_KEY_WRAP_AUTH = 0x101e,
|
||||
ATTR_KEY_ID = 0x101f,
|
||||
ATTR_MAC_ADDR = 0x1020,
|
||||
ATTR_MANUFACTURER = 0x1021,
|
||||
ATTR_MSG_TYPE = 0x1022,
|
||||
ATTR_MODEL_NAME = 0x1023,
|
||||
ATTR_MODEL_NUMBER = 0x1024,
|
||||
ATTR_NETWORK_INDEX = 0x1026,
|
||||
ATTR_NETWORK_KEY = 0x1027,
|
||||
ATTR_NETWORK_KEY_INDEX = 0x1028,
|
||||
ATTR_NEW_DEVICE_NAME = 0x1029,
|
||||
ATTR_NEW_PASSWORD = 0x102a,
|
||||
ATTR_OOB_DEVICE_PASSWORD = 0x102c,
|
||||
ATTR_OS_VERSION = 0x102d,
|
||||
ATTR_POWER_LEVEL = 0x102f,
|
||||
ATTR_PSK_CURRENT = 0x1030,
|
||||
ATTR_PSK_MAX = 0x1031,
|
||||
ATTR_PUBLIC_KEY = 0x1032,
|
||||
ATTR_RADIO_ENABLE = 0x1033,
|
||||
ATTR_REBOOT = 0x1034,
|
||||
ATTR_REGISTRAR_CURRENT = 0x1035,
|
||||
ATTR_REGISTRAR_ESTABLISHED = 0x1036,
|
||||
ATTR_REGISTRAR_LIST = 0x1037,
|
||||
ATTR_REGISTRAR_MAX = 0x1038,
|
||||
ATTR_REGISTRAR_NONCE = 0x1039,
|
||||
ATTR_REQUEST_TYPE = 0x103a,
|
||||
ATTR_RESPONSE_TYPE = 0x103b,
|
||||
ATTR_RF_BANDS = 0x103c,
|
||||
ATTR_R_HASH1 = 0x103d,
|
||||
ATTR_R_HASH2 = 0x103e,
|
||||
ATTR_R_SNONCE1 = 0x103f,
|
||||
ATTR_R_SNONCE2 = 0x1040,
|
||||
ATTR_SELECTED_REGISTRAR = 0x1041,
|
||||
ATTR_SERIAL_NUMBER = 0x1042,
|
||||
ATTR_WPS_STATE = 0x1044,
|
||||
ATTR_SSID = 0x1045,
|
||||
ATTR_TOTAL_NETWORKS = 0x1046,
|
||||
ATTR_UUID_E = 0x1047,
|
||||
ATTR_UUID_R = 0x1048,
|
||||
ATTR_VENDOR_EXT = 0x1049,
|
||||
ATTR_VERSION = 0x104a,
|
||||
ATTR_X509_CERT_REQ = 0x104b,
|
||||
ATTR_X509_CERT = 0x104c,
|
||||
ATTR_EAP_IDENTITY = 0x104d,
|
||||
ATTR_MSG_COUNTER = 0x104e,
|
||||
ATTR_PUBKEY_HASH = 0x104f,
|
||||
ATTR_REKEY_KEY = 0x1050,
|
||||
ATTR_KEY_LIFETIME = 0x1051,
|
||||
ATTR_PERMITTED_CFG_METHODS = 0x1052,
|
||||
ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053,
|
||||
ATTR_PRIMARY_DEV_TYPE = 0x1054,
|
||||
ATTR_SECONDARY_DEV_TYPE_LIST = 0x1055,
|
||||
ATTR_PORTABLE_DEV = 0x1056,
|
||||
ATTR_AP_SETUP_LOCKED = 0x1057,
|
||||
ATTR_APPLICATION_EXT = 0x1058,
|
||||
ATTR_EAP_TYPE = 0x1059,
|
||||
ATTR_IV = 0x1060,
|
||||
ATTR_KEY_PROVIDED_AUTO = 0x1061,
|
||||
ATTR_802_1X_ENABLED = 0x1062,
|
||||
ATTR_APPSESSIONKEY = 0x1063,
|
||||
ATTR_WEPTRANSMITKEY = 0x1064,
|
||||
ATTR_REQUESTED_DEV_TYPE = 0x106a,
|
||||
ATTR_EXTENSIBILITY_TEST = 0x10fa /* _NOT_ defined in the spec */
|
||||
};
|
||||
|
||||
#define WPS_VENDOR_ID_WFA 14122
|
||||
|
||||
/* WFA Vendor Extension subelements */
|
||||
enum {
|
||||
WFA_ELEM_VERSION2 = 0x00,
|
||||
WFA_ELEM_AUTHORIZEDMACS = 0x01,
|
||||
WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
|
||||
WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
|
||||
WFA_ELEM_SETTINGS_DELAY_TIME = 0x04
|
||||
};
|
||||
|
||||
/* Device Password ID */
|
||||
enum wps_dev_password_id {
|
||||
DEV_PW_DEFAULT = 0x0000,
|
||||
DEV_PW_USER_SPECIFIED = 0x0001,
|
||||
DEV_PW_MACHINE_SPECIFIED = 0x0002,
|
||||
DEV_PW_REKEY = 0x0003,
|
||||
DEV_PW_PUSHBUTTON = 0x0004,
|
||||
DEV_PW_REGISTRAR_SPECIFIED = 0x0005
|
||||
};
|
||||
|
||||
/* WPS message flag */
|
||||
enum wps_msg_flag {
|
||||
WPS_MSG_FLAG_MORE = 0x01,
|
||||
WPS_MSG_FLAG_LEN = 0x02
|
||||
};
|
||||
|
||||
/* Message Type */
|
||||
enum wps_msg_type {
|
||||
WPS_Beacon = 0x01,
|
||||
WPS_ProbeRequest = 0x02,
|
||||
WPS_ProbeResponse = 0x03,
|
||||
WPS_M1 = 0x04,
|
||||
WPS_M2 = 0x05,
|
||||
WPS_M2D = 0x06,
|
||||
WPS_M3 = 0x07,
|
||||
WPS_M4 = 0x08,
|
||||
WPS_M5 = 0x09,
|
||||
WPS_M6 = 0x0a,
|
||||
WPS_M7 = 0x0b,
|
||||
WPS_M8 = 0x0c,
|
||||
WPS_WSC_ACK = 0x0d,
|
||||
WPS_WSC_NACK = 0x0e,
|
||||
WPS_WSC_DONE = 0x0f
|
||||
};
|
||||
|
||||
/* Authentication Type Flags */
|
||||
#define WPS_WIFI_AUTH_OPEN 0x0001
|
||||
#define WPS_AUTH_WPAPSK 0x0002
|
||||
#define WPS_AUTH_SHARED 0x0004
|
||||
#define WPS_AUTH_WPA 0x0008
|
||||
#define WPS_AUTH_WPA2 0x0010
|
||||
#define WPS_AUTH_WPA2PSK 0x0020
|
||||
#define WPS_AUTH_TYPES (WPS_WIFI_AUTH_OPEN | WPS_AUTH_WPAPSK | WPS_AUTH_SHARED | \
|
||||
WPS_AUTH_WPA | WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)
|
||||
|
||||
/* Encryption Type Flags */
|
||||
#define WPS_ENCR_NONE 0x0001
|
||||
#define WPS_ENCR_WEP 0x0002
|
||||
#define WPS_ENCR_TKIP 0x0004
|
||||
#define WPS_ENCR_AES 0x0008
|
||||
#define WPS_ENCR_TYPES (WPS_ENCR_NONE | WPS_ENCR_WEP | WPS_ENCR_TKIP | \
|
||||
WPS_ENCR_AES)
|
||||
|
||||
/* Configuration Error */
|
||||
enum wps_config_error {
|
||||
WPS_CFG_NO_ERROR = 0,
|
||||
WPS_CFG_OOB_IFACE_READ_ERROR = 1,
|
||||
WPS_CFG_DECRYPTION_CRC_FAILURE = 2,
|
||||
WPS_CFG_24_CHAN_NOT_SUPPORTED = 3,
|
||||
WPS_CFG_50_CHAN_NOT_SUPPORTED = 4,
|
||||
WPS_CFG_SIGNAL_TOO_WEAK = 5,
|
||||
WPS_CFG_NETWORK_AUTH_FAILURE = 6,
|
||||
WPS_CFG_NETWORK_ASSOC_FAILURE = 7,
|
||||
WPS_CFG_NO_DHCP_RESPONSE = 8,
|
||||
WPS_CFG_FAILED_DHCP_CONFIG = 9,
|
||||
WPS_CFG_IP_ADDR_CONFLICT = 10,
|
||||
WPS_CFG_NO_CONN_TO_REGISTRAR = 11,
|
||||
WPS_CFG_MULTIPLE_PBC_DETECTED = 12,
|
||||
WPS_CFG_ROGUE_SUSPECTED = 13,
|
||||
WPS_CFG_DEVICE_BUSY = 14,
|
||||
WPS_CFG_SETUP_LOCKED = 15,
|
||||
WPS_CFG_MSG_TIMEOUT = 16,
|
||||
WPS_CFG_REG_SESS_TIMEOUT = 17,
|
||||
WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
|
||||
};
|
||||
|
||||
/* Vendor specific Error Indication for WPS event messages */
|
||||
enum wps_error_indication {
|
||||
WPS_EI_NO_ERROR,
|
||||
WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,
|
||||
WPS_EI_SECURITY_WEP_PROHIBITED,
|
||||
NUM_WPS_EI_VALUES
|
||||
};
|
||||
|
||||
/* RF Bands */
|
||||
#define WPS_RF_24GHZ 0x01
|
||||
#define WPS_RF_50GHZ 0x02
|
||||
|
||||
/* Config Methods */
|
||||
#define WPS_CONFIG_USBA 0x0001
|
||||
#define WPS_CONFIG_ETHERNET 0x0002
|
||||
#define WPS_CONFIG_LABEL 0x0004
|
||||
#define WPS_CONFIG_DISPLAY 0x0008
|
||||
#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
|
||||
#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
|
||||
#define WPS_CONFIG_NFC_INTERFACE 0x0040
|
||||
#define WPS_CONFIG_PUSHBUTTON 0x0080
|
||||
#define WPS_CONFIG_KEYPAD 0x0100
|
||||
#ifdef CONFIG_WPS2
|
||||
#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
|
||||
#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
|
||||
#define WPS_CONFIG_VIRT_DISPLAY 0x2008
|
||||
#define WPS_CONFIG_PHY_DISPLAY 0x4008
|
||||
#endif /* CONFIG_WPS2 */
|
||||
|
||||
/* Connection Type Flags */
|
||||
#define WPS_CONN_ESS 0x01
|
||||
#define WPS_CONN_IBSS 0x02
|
||||
|
||||
/* Wi-Fi Protected Setup State */
|
||||
enum wps_state {
|
||||
WPS_STATE_NOT_CONFIGURED = 1,
|
||||
WPS_STATE_CONFIGURED = 2
|
||||
};
|
||||
|
||||
/* Association State */
|
||||
enum wps_assoc_state {
|
||||
WPS_ASSOC_NOT_ASSOC = 0,
|
||||
WPS_ASSOC_CONN_SUCCESS = 1,
|
||||
WPS_ASSOC_CFG_FAILURE = 2,
|
||||
WPS_ASSOC_FAILURE = 3,
|
||||
WPS_ASSOC_IP_FAILURE = 4
|
||||
};
|
||||
|
||||
|
||||
#define WPS_DEV_OUI_WFA 0x0050f204
|
||||
|
||||
enum wps_dev_categ {
|
||||
WPS_DEV_COMPUTER = 1,
|
||||
WPS_DEV_INPUT = 2,
|
||||
WPS_DEV_PRINTER = 3,
|
||||
WPS_DEV_CAMERA = 4,
|
||||
WPS_DEV_STORAGE = 5,
|
||||
WPS_DEV_NETWORK_INFRA = 6,
|
||||
WPS_DEV_DISPLAY = 7,
|
||||
WPS_DEV_MULTIMEDIA = 8,
|
||||
WPS_DEV_GAMING = 9,
|
||||
WPS_DEV_PHONE = 10
|
||||
};
|
||||
|
||||
enum wps_dev_subcateg {
|
||||
WPS_DEV_COMPUTER_PC = 1,
|
||||
WPS_DEV_COMPUTER_SERVER = 2,
|
||||
WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
|
||||
WPS_DEV_PRINTER_PRINTER = 1,
|
||||
WPS_DEV_PRINTER_SCANNER = 2,
|
||||
WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
|
||||
WPS_DEV_STORAGE_NAS = 1,
|
||||
WPS_DEV_NETWORK_INFRA_AP = 1,
|
||||
WPS_DEV_NETWORK_INFRA_ROUTER = 2,
|
||||
WPS_DEV_NETWORK_INFRA_SWITCH = 3,
|
||||
WPS_DEV_DISPLAY_TV = 1,
|
||||
WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
|
||||
WPS_DEV_DISPLAY_PROJECTOR = 3,
|
||||
WPS_DEV_MULTIMEDIA_DAR = 1,
|
||||
WPS_DEV_MULTIMEDIA_PVR = 2,
|
||||
WPS_DEV_MULTIMEDIA_MCX = 3,
|
||||
WPS_DEV_GAMING_XBOX = 1,
|
||||
WPS_DEV_GAMING_XBOX360 = 2,
|
||||
WPS_DEV_GAMING_PLAYSTATION = 3,
|
||||
WPS_DEV_PHONE_WINDOWS_MOBILE = 1
|
||||
};
|
||||
|
||||
|
||||
/* Request Type */
|
||||
enum wps_request_type {
|
||||
WPS_REQ_ENROLLEE_INFO = 0,
|
||||
WPS_REQ_ENROLLEE = 1,
|
||||
WPS_REQ_REGISTRAR = 2,
|
||||
WPS_REQ_WLAN_MANAGER_REGISTRAR = 3
|
||||
};
|
||||
|
||||
/* Response Type */
|
||||
enum wps_response_type {
|
||||
WPS_RESP_ENROLLEE_INFO = 0,
|
||||
WPS_RESP_ENROLLEE = 1,
|
||||
WPS_RESP_REGISTRAR = 2,
|
||||
WPS_RESP_AP = 3
|
||||
};
|
||||
|
||||
/* Walk Time for push button configuration (in seconds) */
|
||||
#define WPS_PBC_WALK_TIME 120
|
||||
|
||||
#define WPS_MAX_AUTHORIZED_MACS 5
|
||||
|
||||
#define WPS_IGNORE_SEL_REG_MAX_CNT 4
|
||||
|
||||
#define WPS_MAX_DIS_AP_NUM 10
|
||||
|
||||
#endif /* WPS_DEFS_H */
|
39
components/wpa_supplicant/include/wps/wps_dev_attr.h
Normal file
39
components/wpa_supplicant/include/wps/wps_dev_attr.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - device attributes
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPS_DEV_ATTR_H
|
||||
#define WPS_DEV_ATTR_H
|
||||
|
||||
struct wps_parse_attr;
|
||||
|
||||
int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_primary_dev_type(struct wps_device_data *dev,
|
||||
struct wpabuf *msg);
|
||||
int wps_build_secondary_dev_type(struct wps_device_data *dev,
|
||||
struct wpabuf *msg);
|
||||
int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_process_device_attrs(struct wps_device_data *dev,
|
||||
struct wps_parse_attr *attr);
|
||||
int wps_process_os_version(struct wps_device_data *dev, const u8 *ver);
|
||||
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands);
|
||||
void wps_device_data_dup(struct wps_device_data *dst,
|
||||
const struct wps_device_data *src);
|
||||
void wps_device_data_free(struct wps_device_data *dev);
|
||||
int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg);
|
||||
int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
|
||||
unsigned int num_req_dev_types,
|
||||
const u8 *req_dev_types);
|
||||
|
||||
#endif /* WPS_DEV_ATTR_H */
|
217
components/wpa_supplicant/include/wps/wps_i.h
Normal file
217
components/wpa_supplicant/include/wps/wps_i.h
Normal file
|
@ -0,0 +1,217 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - internal definitions
|
||||
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifndef WPS_I_H
|
||||
#define WPS_I_H
|
||||
|
||||
#include "wps.h"
|
||||
#include "wps_attr_parse.h"
|
||||
#include "esp_wifi_crypto_types.h"
|
||||
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
struct wps_nfc_pw_token;
|
||||
#endif
|
||||
/**
|
||||
* struct wps_data - WPS registration protocol data
|
||||
*
|
||||
* This data is stored at the EAP-WSC server/peer method and it is kept for a
|
||||
* single registration protocol run.
|
||||
*/
|
||||
struct wps_data {
|
||||
/**
|
||||
* wps - Pointer to long term WPS context
|
||||
*/
|
||||
struct wps_context *wps;
|
||||
|
||||
/**
|
||||
* registrar - Whether this end is a Registrar
|
||||
*/
|
||||
int registrar;
|
||||
|
||||
/**
|
||||
* er - Whether the local end is an external registrar
|
||||
*/
|
||||
int er;
|
||||
|
||||
enum {
|
||||
/* Enrollee states */
|
||||
SEND_M1, RECV_M2, SEND_M3, RECV_M4, SEND_M5, RECV_M6, SEND_M7,
|
||||
RECV_M8, RECEIVED_M2D, WPS_MSG_DONE, RECV_ACK, WPS_FINISHED,
|
||||
SEND_WSC_NACK,
|
||||
|
||||
/* Registrar states */
|
||||
RECV_M1, SEND_M2, RECV_M3, SEND_M4, RECV_M5, SEND_M6,
|
||||
RECV_M7, SEND_M8, RECV_DONE, SEND_M2D, RECV_M2D_ACK
|
||||
} state;
|
||||
|
||||
u8 uuid_e[WPS_UUID_LEN];
|
||||
u8 uuid_r[WPS_UUID_LEN];
|
||||
u8 mac_addr_e[ETH_ALEN];
|
||||
u8 nonce_e[WPS_NONCE_LEN];
|
||||
u8 nonce_r[WPS_NONCE_LEN];
|
||||
u8 psk1[WPS_PSK_LEN];
|
||||
u8 psk2[WPS_PSK_LEN];
|
||||
u8 snonce[2 * WPS_SECRET_NONCE_LEN];
|
||||
u8 peer_hash1[WPS_HASH_LEN];
|
||||
u8 peer_hash2[WPS_HASH_LEN];
|
||||
|
||||
struct wpabuf *dh_privkey;
|
||||
struct wpabuf *dh_pubkey_e;
|
||||
struct wpabuf *dh_pubkey_r;
|
||||
u8 authkey[WPS_AUTHKEY_LEN];
|
||||
u8 keywrapkey[WPS_KEYWRAPKEY_LEN];
|
||||
u8 emsk[WPS_EMSK_LEN];
|
||||
|
||||
struct wpabuf *last_msg;
|
||||
|
||||
u8 *dev_password;
|
||||
size_t dev_password_len;
|
||||
u16 dev_pw_id;
|
||||
int pbc;
|
||||
|
||||
/**
|
||||
* request_type - Request Type attribute from (Re)AssocReq
|
||||
*/
|
||||
u8 request_type;
|
||||
|
||||
/**
|
||||
* encr_type - Available encryption types
|
||||
*/
|
||||
u16 encr_type;
|
||||
|
||||
/**
|
||||
* auth_type - Available authentication types
|
||||
*/
|
||||
u16 auth_type;
|
||||
|
||||
u8 *new_psk;
|
||||
size_t new_psk_len;
|
||||
|
||||
int wps_pin_revealed;
|
||||
struct wps_credential cred;
|
||||
|
||||
struct wps_device_data peer_dev;
|
||||
|
||||
/**
|
||||
* config_error - Configuration Error value to be used in NACK
|
||||
*/
|
||||
u16 config_error;
|
||||
u16 error_indication;
|
||||
|
||||
int ext_reg;
|
||||
int int_reg;
|
||||
|
||||
struct wps_credential *new_ap_settings;
|
||||
|
||||
void *dh_ctx;
|
||||
|
||||
void (*ap_settings_cb)(void *ctx, const struct wps_credential *cred);
|
||||
void *ap_settings_cb_ctx;
|
||||
|
||||
struct wps_credential *use_cred;
|
||||
|
||||
int use_psk_key;
|
||||
u8 p2p_dev_addr[ETH_ALEN]; /* P2P Device Address of the client or
|
||||
* 00:00:00:00:00:00 if not a P2p client */
|
||||
int pbc_in_m1;
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
struct wps_nfc_pw_token *nfc_pw_token;
|
||||
#endif
|
||||
};
|
||||
|
||||
wps_crypto_funcs_t wps_crypto_funcs;
|
||||
|
||||
/* wps_common.c */
|
||||
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
|
||||
const char *label, u8 *res, size_t res_len);
|
||||
int wps_derive_keys(struct wps_data *wps);
|
||||
void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
|
||||
size_t dev_passwd_len);
|
||||
struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
|
||||
size_t encr_len);
|
||||
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
|
||||
u16 config_error, u16 error_indication);
|
||||
void wps_success_event(struct wps_context *wps);
|
||||
void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
|
||||
void wps_pbc_overlap_event(struct wps_context *wps);
|
||||
void wps_pbc_timeout_event(struct wps_context *wps);
|
||||
|
||||
struct wpabuf * wps_build_wsc_ack(struct wps_data *wps);
|
||||
struct wpabuf * wps_build_wsc_nack(struct wps_data *wps);
|
||||
|
||||
typedef enum wps_calc_key_mode {
|
||||
WPS_CALC_KEY_NORMAL = 0,
|
||||
WPS_CALC_KEY_NO_CALC,
|
||||
WPS_CALC_KEY_PRE_CALC,
|
||||
WPS_CALC_KEY_MAX,
|
||||
} wps_key_mode_t;
|
||||
|
||||
/* wps_attr_build.c */
|
||||
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg, wps_key_mode_t mode);
|
||||
int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type);
|
||||
int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type);
|
||||
int wps_build_config_methods(struct wpabuf *msg, u16 methods);
|
||||
int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid);
|
||||
int wps_build_dev_password_id(struct wpabuf *msg, u16 id);
|
||||
int wps_build_config_error(struct wpabuf *msg, u16 err);
|
||||
int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
|
||||
struct wpabuf *plain);
|
||||
int wps_build_version(struct wpabuf *msg);
|
||||
int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
|
||||
const u8 *auth_macs, size_t auth_macs_count);
|
||||
int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type);
|
||||
int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
|
||||
const struct wpabuf *pubkey, const u8 *dev_pw,
|
||||
size_t dev_pw_len);
|
||||
struct wpabuf * wps_ie_encapsulate(struct wpabuf *data);
|
||||
|
||||
/* wps_attr_process.c */
|
||||
int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
|
||||
const struct wpabuf *msg);
|
||||
int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
|
||||
const u8 *key_wrap_auth);
|
||||
int wps_process_cred(struct wps_parse_attr *attr,
|
||||
struct wps_credential *cred);
|
||||
int wps_process_ap_settings(struct wps_parse_attr *attr,
|
||||
struct wps_credential *cred);
|
||||
|
||||
/* wps_enrollee.c */
|
||||
struct wpabuf * wps_enrollee_get_msg(struct wps_data *wps,
|
||||
enum wsc_op_code *op_code);
|
||||
enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
|
||||
enum wsc_op_code op_code,
|
||||
const struct wpabuf *msg);
|
||||
|
||||
/* wps_registrar.c */
|
||||
struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
|
||||
enum wsc_op_code *op_code);
|
||||
enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
|
||||
enum wsc_op_code op_code,
|
||||
const struct wpabuf *msg);
|
||||
int wps_build_cred(struct wps_data *wps, struct wpabuf *msg);
|
||||
int wps_device_store(struct wps_registrar *reg,
|
||||
struct wps_device_data *dev, const u8 *uuid);
|
||||
void wps_registrar_selected_registrar_changed(struct wps_registrar *reg);
|
||||
const u8 * wps_authorized_macs(struct wps_registrar *reg, size_t *count);
|
||||
int wps_registrar_pbc_overlap(struct wps_registrar *reg,
|
||||
const u8 *addr, const u8 *uuid_e);
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
|
||||
void wps_registrar_remove_nfc_pw_token(struct wps_registrar *reg,
|
||||
struct wps_nfc_pw_token *token);
|
||||
#endif
|
||||
|
||||
#endif /* WPS_I_H */
|
|
@ -18,6 +18,7 @@
|
|||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "esp_err.h"
|
||||
#include "rom/ets_sys.h"
|
||||
|
||||
typedef long os_time_t;
|
||||
|
@ -201,6 +202,10 @@ char * os_readfile(const char *name, size_t *len);
|
|||
#define os_free(p) free((p))
|
||||
#endif
|
||||
|
||||
#ifndef os_bzero
|
||||
#define os_bzero(s, n) bzero(s, n)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef os_strdup
|
||||
#ifdef _MSC_VER
|
||||
|
|
27
components/wpa_supplicant/src/wpa2/eap_peer/chap.c
Normal file
27
components/wpa_supplicant/src/wpa2/eap_peer/chap.c
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* CHAP-MD5
|
||||
*
|
||||
*/
|
||||
#ifdef CHAP_MD5
|
||||
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "wpa2/eap_peer/chap.h"
|
||||
|
||||
int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
|
||||
size_t challenge_len, u8 *response)
|
||||
{
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
|
||||
addr[0] = &id;
|
||||
len[0] = 1;
|
||||
addr[1] = secret;
|
||||
len[1] = secret_len;
|
||||
addr[2] = challenge;
|
||||
len[2] = challenge_len;
|
||||
return md5_vector(3, addr, len, response);
|
||||
}
|
||||
|
||||
#endif /* CHAP_MD5 */
|
731
components/wpa_supplicant/src/wpa2/eap_peer/eap.c
Normal file
731
components/wpa_supplicant/src/wpa2/eap_peer/eap.c
Normal file
|
@ -0,0 +1,731 @@
|
|||
/*
|
||||
* EAP peer state machines (RFC 4137)
|
||||
* Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*
|
||||
* This file implements the Peer State Machine as defined in RFC 4137. The used
|
||||
* states and state transitions match mostly with the RFC. However, there are
|
||||
* couple of additional transitions for working around small issues noticed
|
||||
* during testing. These exceptions are explained in comments within the
|
||||
* functions in this file. The method functions, m.func(), are similar to the
|
||||
* ones used in RFC 4137, but some small changes have used here to optimize
|
||||
* operations and to add functionality needed for fast re-authentication
|
||||
* (session resumption).
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "esp_err.h"
|
||||
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/common.h"
|
||||
#include "wpa/wpa_debug.h"
|
||||
#include "wpa/eapol_common.h"
|
||||
#include "wpa/ieee802_11_defs.h"
|
||||
#include "wpa/state_machine.h"
|
||||
#include "wpa/wpa.h"
|
||||
|
||||
#include "crypto/crypto.h"
|
||||
|
||||
#include "wpa2/utils/ext_password.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
#include "wpa2/eap_peer/eap_config.h"
|
||||
#include "wpa2/eap_peer/eap.h"
|
||||
#include "wpa2/eap_peer/eap_tls.h"
|
||||
#ifdef EAP_PEER_METHOD
|
||||
#include "wpa2/eap_peer/eap_methods.h"
|
||||
#endif
|
||||
|
||||
|
||||
static bool gl_disable_time_check = true;
|
||||
void eap_peer_config_deinit(struct eap_sm *sm);
|
||||
void eap_peer_blob_deinit(struct eap_sm *sm);
|
||||
void eap_deinit_prev_method(struct eap_sm *sm, const char *txt);
|
||||
|
||||
extern bool ieee80211_unregister_wpa2_cb(void);
|
||||
|
||||
#ifdef EAP_PEER_METHOD
|
||||
static struct eap_method *eap_methods = NULL;
|
||||
|
||||
const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
|
||||
{
|
||||
struct eap_method *m;
|
||||
for (m = eap_methods; m; m = m->next) {
|
||||
if (m->vendor == vendor && m->method == method)
|
||||
return m;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct eap_method * eap_peer_get_methods(size_t *count)
|
||||
{
|
||||
int c = 0;
|
||||
struct eap_method *m;
|
||||
|
||||
for (m = eap_methods; m; m = m->next)
|
||||
c++;
|
||||
|
||||
*count = c;
|
||||
return eap_methods;
|
||||
}
|
||||
|
||||
EapType eap_peer_get_type(const char *name, int *vendor)
|
||||
{
|
||||
struct eap_method *m;
|
||||
for (m = eap_methods; m; m = m->next) {
|
||||
if (os_strcmp(m->name, name) == 0) {
|
||||
*vendor = m->vendor;
|
||||
return m->method;
|
||||
}
|
||||
}
|
||||
*vendor = EAP_VENDOR_IETF;
|
||||
return EAP_TYPE_NONE;
|
||||
}
|
||||
|
||||
static int
|
||||
eap_allowed_phase2_type(int vendor, int type)
|
||||
{
|
||||
if (vendor != EAP_VENDOR_IETF)
|
||||
return 0;
|
||||
return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
|
||||
type != EAP_TYPE_FAST;
|
||||
}
|
||||
|
||||
u32 eap_get_phase2_type(const char *name, int *vendor)
|
||||
{
|
||||
int v;
|
||||
u8 type = eap_peer_get_type(name, &v);
|
||||
if (eap_allowed_phase2_type(v, type)) {
|
||||
*vendor = v;
|
||||
return type;
|
||||
}
|
||||
*vendor = EAP_VENDOR_IETF;
|
||||
return EAP_TYPE_NONE;
|
||||
}
|
||||
|
||||
struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
|
||||
size_t *count)
|
||||
{
|
||||
struct eap_method_type *buf;
|
||||
u32 method;
|
||||
int vendor;
|
||||
size_t mcount;
|
||||
const struct eap_method *methods, *m;
|
||||
|
||||
methods = eap_peer_get_methods(&mcount);
|
||||
if (methods == NULL)
|
||||
return NULL;
|
||||
*count = 0;
|
||||
buf = os_malloc(mcount * sizeof(struct eap_method_type));
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
for (m = methods; m; m = m->next) {
|
||||
vendor = m->vendor;
|
||||
method = m->method;
|
||||
if (eap_allowed_phase2_type(vendor, method)) {
|
||||
if (vendor == EAP_VENDOR_IETF &&
|
||||
method == EAP_TYPE_TLS && config &&
|
||||
config->private_key2 == NULL)
|
||||
continue;
|
||||
buf[*count].vendor = vendor;
|
||||
buf[*count].method = method;
|
||||
(*count)++;
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
struct eap_method * eap_peer_method_alloc(int vendor, EapType method,
|
||||
const char *name)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
eap = (struct eap_method *)os_zalloc(sizeof(*eap));
|
||||
if (eap == NULL)
|
||||
return NULL;
|
||||
eap->vendor = vendor;
|
||||
eap->method = method;
|
||||
eap->name = name;
|
||||
return eap;
|
||||
}
|
||||
|
||||
void eap_peer_method_free(struct eap_method *method)
|
||||
{
|
||||
os_free(method);
|
||||
}
|
||||
|
||||
int eap_peer_method_register(struct eap_method *method)
|
||||
{
|
||||
struct eap_method *m, *last = NULL;
|
||||
|
||||
if (method == NULL || method->name == NULL)
|
||||
return -1;
|
||||
for (m = eap_methods; m; m = m->next) {
|
||||
if (m->vendor == method->vendor &&
|
||||
m->method == method->method &&
|
||||
os_strcmp(m->name, method->name))
|
||||
return -2;
|
||||
last = m;
|
||||
}
|
||||
if (last)
|
||||
last->next = method;
|
||||
else
|
||||
eap_methods = method;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void eap_peer_unregister_methods(void)
|
||||
{
|
||||
struct eap_method *m;
|
||||
while (eap_methods) {
|
||||
m = eap_methods;
|
||||
eap_methods = eap_methods->next;
|
||||
|
||||
if (m->free)
|
||||
m->free(m);
|
||||
else
|
||||
eap_peer_method_free(m);
|
||||
}
|
||||
}
|
||||
|
||||
int eap_peer_register_methods(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
#ifdef EAP_MD5
|
||||
if (ret == 0)
|
||||
ret = eap_peer_md5_register();
|
||||
#endif
|
||||
|
||||
#ifdef EAP_TLS
|
||||
if (ret == 0)
|
||||
ret = eap_peer_tls_register();
|
||||
#endif
|
||||
|
||||
#ifdef EAP_MSCHAPv2
|
||||
if (ret == 0)
|
||||
ret = eap_peer_mschapv2_register();
|
||||
#endif
|
||||
|
||||
#ifdef EAP_PEAP
|
||||
if (ret == 0)
|
||||
ret = eap_peer_peap_register();
|
||||
#endif
|
||||
|
||||
#ifdef EAP_TTLS
|
||||
if (ret == 0)
|
||||
ret = eap_peer_ttls_register();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
|
||||
{
|
||||
if (sm->m == NULL || sm->eap_method_priv == NULL)
|
||||
return;
|
||||
sm->m->deinit(sm, sm->eap_method_priv);
|
||||
sm->eap_method_priv = NULL;
|
||||
sm->m = NULL;
|
||||
}
|
||||
|
||||
struct wpabuf * eap_sm_build_identity_resp(struct eap_sm *sm, u8 id, int encrypted)
|
||||
{
|
||||
const u8 *identity;
|
||||
size_t identity_len;
|
||||
struct wpabuf *eap_buf = NULL;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
if (config == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP: Build Identity Resp-> configuration was not available\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sm->m && sm->m->get_identity) {
|
||||
identity = sm->m->get_identity(sm,
|
||||
sm->eap_method_priv,
|
||||
&identity_len);
|
||||
} else if (!encrypted && config->anonymous_identity) {
|
||||
identity = config->anonymous_identity;
|
||||
identity_len = config->anonymous_identity_len;
|
||||
} else {
|
||||
identity = config->identity;
|
||||
identity_len = config->identity_len;
|
||||
}
|
||||
|
||||
if (identity == NULL) {
|
||||
wpa_printf(MSG_ERROR, "EAP: Build Identity Resp-> identity was not available\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eap_buf = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
|
||||
identity_len, EAP_CODE_RESPONSE, id);
|
||||
if (!eap_buf) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpabuf_put_data(eap_buf, identity, identity_len);
|
||||
return eap_buf;
|
||||
}
|
||||
|
||||
struct wpabuf * eap_sm_build_nak(struct eap_sm *sm, EapType type, u8 id)
|
||||
{
|
||||
size_t count = 0;
|
||||
int found = 0;
|
||||
struct wpabuf *resp;
|
||||
const struct eap_method *methods, *m;
|
||||
|
||||
methods = eap_peer_get_methods(&count);
|
||||
if (methods == NULL)
|
||||
return NULL;
|
||||
|
||||
if (type == EAP_TYPE_EXPANDED) {
|
||||
/*Build Expanded NAK*/
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
|
||||
8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
wpabuf_put_be24(resp, EAP_VENDOR_IETF);
|
||||
wpabuf_put_be32(resp, EAP_TYPE_NAK);
|
||||
} else {
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
|
||||
sizeof(struct eap_hdr) + 1 + count + 1,
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
wpabuf_put(resp, 0);
|
||||
}
|
||||
|
||||
for (m = methods; m; m = m->next) {
|
||||
if (type == EAP_TYPE_EXPANDED) {
|
||||
wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
|
||||
wpabuf_put_be24(resp, m->vendor);
|
||||
wpabuf_put_be32(resp, m->method);
|
||||
} else
|
||||
wpabuf_put_u8(resp, EAP_TYPE_NONE);
|
||||
found++;
|
||||
}
|
||||
if (!found) {
|
||||
if (type == EAP_TYPE_EXPANDED) {
|
||||
wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
|
||||
wpabuf_put_be24(resp, EAP_VENDOR_IETF);
|
||||
wpabuf_put_be32(resp, EAP_TYPE_NONE);
|
||||
} else
|
||||
wpabuf_put_u8(resp, EAP_TYPE_NONE);
|
||||
}
|
||||
eap_update_len(resp);
|
||||
return resp;
|
||||
}
|
||||
#endif
|
||||
|
||||
int eap_peer_config_init(
|
||||
struct eap_sm *sm, u8 *private_key_passwd,
|
||||
int private_key_passwd_len)
|
||||
{
|
||||
if (!sm)
|
||||
return -1;
|
||||
|
||||
sm->config.anonymous_identity = NULL;
|
||||
sm->config.identity = NULL;
|
||||
sm->config.password = NULL;
|
||||
sm->config.new_password = NULL;
|
||||
|
||||
sm->config.private_key_passwd = private_key_passwd;
|
||||
sm->config.client_cert = (u8 *)sm->blob[0].name;
|
||||
sm->config.private_key = (u8 *)sm->blob[1].name;
|
||||
sm->config.ca_cert = (u8 *)sm->blob[2].name;
|
||||
|
||||
sm->config.ca_path = NULL;
|
||||
|
||||
sm->config.fragment_size = 1400; /* fragment size */
|
||||
|
||||
/* anonymous identity */
|
||||
if (g_wpa_anonymous_identity && g_wpa_anonymous_identity_len > 0) {
|
||||
sm->config.anonymous_identity_len = g_wpa_anonymous_identity_len;
|
||||
sm->config.anonymous_identity = (u8 *)os_zalloc(sm->config.anonymous_identity_len);
|
||||
if (sm->config.anonymous_identity == NULL)
|
||||
return -2;
|
||||
os_memcpy(sm->config.anonymous_identity, g_wpa_anonymous_identity, g_wpa_anonymous_identity_len);
|
||||
}
|
||||
|
||||
/* Configre identity */
|
||||
if (g_wpa_username && g_wpa_username_len > 0) {
|
||||
sm->config.identity_len = g_wpa_username_len;
|
||||
sm->config.identity = (u8 *)os_zalloc(sm->config.identity_len);
|
||||
if (sm->config.identity == NULL) {
|
||||
return -2;
|
||||
}
|
||||
os_memcpy(sm->config.identity, g_wpa_username, g_wpa_username_len);
|
||||
}
|
||||
|
||||
if (g_wpa_password && g_wpa_password_len) {
|
||||
sm->config.password_len = g_wpa_password_len;
|
||||
sm->config.password = (u8 *)os_zalloc(sm->config.password_len);
|
||||
if (sm->config.password == NULL)
|
||||
return -2;
|
||||
os_memcpy(sm->config.password, g_wpa_password, sm->config.password_len);
|
||||
}
|
||||
|
||||
if (g_wpa_new_password && g_wpa_new_password_len) {
|
||||
sm->config.new_password_len = g_wpa_new_password_len;
|
||||
sm->config.new_password = (u8 *)os_zalloc(sm->config.new_password_len);
|
||||
if (sm->config.new_password == NULL)
|
||||
return -2;
|
||||
os_memcpy(sm->config.new_password, g_wpa_new_password,
|
||||
sm->config.new_password_len);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void eap_peer_config_deinit(struct eap_sm *sm)
|
||||
{
|
||||
if (!sm)
|
||||
return;
|
||||
|
||||
os_free(sm->config.anonymous_identity);
|
||||
os_free(sm->config.identity);
|
||||
os_free(sm->config.password);
|
||||
os_free(sm->config.new_password);
|
||||
os_bzero(&sm->config, sizeof(struct eap_peer_config));
|
||||
}
|
||||
|
||||
int eap_peer_blob_init(struct eap_sm *sm)
|
||||
{
|
||||
int i, ret;
|
||||
|
||||
if (!sm)
|
||||
return -1;
|
||||
|
||||
if (g_wpa_client_cert && g_wpa_client_cert_len) {
|
||||
sm->blob[0].name = (char *)os_zalloc(BLOB_NAME_LEN+1);
|
||||
if (sm->blob[0].name == NULL) {
|
||||
ret = -2;
|
||||
goto _out;
|
||||
}
|
||||
os_strncpy(sm->blob[0].name, CLIENT_CERT_NAME, BLOB_NAME_LEN);
|
||||
sm->blob[0].len = g_wpa_client_cert_len;
|
||||
sm->blob[0].data = g_wpa_client_cert;
|
||||
}
|
||||
|
||||
if (g_wpa_private_key && g_wpa_private_key_len) {
|
||||
sm->blob[1].name = (char *)os_zalloc(BLOB_NAME_LEN+1);
|
||||
if (sm->blob[1].name == NULL) {
|
||||
ret = -2;
|
||||
goto _out;
|
||||
}
|
||||
os_strncpy(sm->blob[1].name, PRIVATE_KEY_NAME, BLOB_NAME_LEN);
|
||||
sm->blob[1].len = g_wpa_private_key_len;
|
||||
sm->blob[1].data = g_wpa_private_key;
|
||||
}
|
||||
|
||||
if (g_wpa_ca_cert && g_wpa_ca_cert_len) {
|
||||
sm->blob[2].name = (char *)os_zalloc(BLOB_NAME_LEN+1);
|
||||
if (sm->blob[2].name == NULL) {
|
||||
ret = -2;
|
||||
goto _out;
|
||||
}
|
||||
os_strncpy(sm->blob[2].name, CA_CERT_NAME, BLOB_NAME_LEN);
|
||||
sm->blob[2].len = g_wpa_ca_cert_len;
|
||||
sm->blob[2].data = g_wpa_ca_cert;
|
||||
}
|
||||
|
||||
return 0;
|
||||
_out:
|
||||
for (i = 0; i < BLOB_NUM; i++) {
|
||||
if (sm->blob[i].name) {
|
||||
os_free(sm->blob[i].name);
|
||||
sm->blob[i].name = NULL;
|
||||
}
|
||||
}
|
||||
os_bzero(&sm->blob[0], sizeof(struct wpa_config_blob)*BLOB_NUM);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void eap_peer_blob_deinit(struct eap_sm *sm)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < BLOB_NUM; i++) {
|
||||
if (sm->blob[i].name) {
|
||||
os_free(sm->blob[i].name);
|
||||
sm->blob[i].name = NULL;
|
||||
}
|
||||
}
|
||||
os_bzero(&sm->blob[0], sizeof(struct wpa_config_blob)*BLOB_NUM);
|
||||
|
||||
sm->config.client_cert = NULL;
|
||||
sm->config.private_key = NULL;
|
||||
sm->config.ca_cert = NULL;
|
||||
}
|
||||
|
||||
void eap_sm_abort(struct eap_sm *sm)
|
||||
{
|
||||
wpabuf_free(sm->lastRespData);
|
||||
sm->lastRespData = NULL;
|
||||
//os_free(sm->eapKeyData);
|
||||
//sm->eapKeyData = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* eap_get_config - Get current network configuration
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* Returns: Pointer to the current network configuration or %NULL if not found
|
||||
*
|
||||
* EAP peer methods should avoid using this function if they can use other
|
||||
* access functions, like eap_get_config_identity() and
|
||||
* eap_get_config_password(), that do not require direct access to
|
||||
* struct eap_peer_config.
|
||||
*/
|
||||
struct eap_peer_config * eap_get_config(struct eap_sm *sm)
|
||||
{
|
||||
return &sm->config;
|
||||
}
|
||||
|
||||
const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config == NULL)
|
||||
return NULL;
|
||||
*len = config->identity_len;
|
||||
return config->identity;
|
||||
}
|
||||
|
||||
const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config == NULL)
|
||||
return NULL;
|
||||
*len = config->password_len;
|
||||
return config->password;
|
||||
}
|
||||
|
||||
const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config == NULL)
|
||||
return NULL;
|
||||
|
||||
*len = config->password_len;
|
||||
if (hash)
|
||||
*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
|
||||
return config->password;
|
||||
}
|
||||
|
||||
const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config == NULL)
|
||||
return NULL;
|
||||
*len = config->new_password_len;
|
||||
return config->new_password;
|
||||
}
|
||||
/**
|
||||
* eap_get_config_blob - Get a named configuration blob
|
||||
* @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
|
||||
* @name: Name of the blob
|
||||
* Returns: Pointer to blob data or %NULL if not found
|
||||
*/
|
||||
const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
|
||||
const char *name)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!sm)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < BLOB_NUM; i++) {
|
||||
if (sm->blob[i].name == NULL)
|
||||
continue;
|
||||
if (os_strncmp(name, sm->blob[i].name, BLOB_NAME_LEN) == 0) {
|
||||
return &sm->blob[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_cert_key(const unsigned char *client_cert, int client_cert_len, const unsigned char *private_key, int private_key_len, const unsigned char *private_key_passwd, int private_key_passwd_len)
|
||||
{
|
||||
if (client_cert && client_cert_len > 0) {
|
||||
g_wpa_client_cert = client_cert;
|
||||
g_wpa_client_cert_len = client_cert_len;
|
||||
}
|
||||
if (private_key && private_key_len > 0) {
|
||||
g_wpa_private_key = private_key;
|
||||
g_wpa_private_key_len = private_key_len;
|
||||
}
|
||||
if (private_key_passwd && private_key_passwd_len > 0) {
|
||||
g_wpa_private_key_passwd = private_key_passwd;
|
||||
g_wpa_private_key_passwd_len = private_key_passwd_len;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wifi_sta_wpa2_ent_clear_cert_key(void)
|
||||
{
|
||||
ieee80211_unregister_wpa2_cb();
|
||||
|
||||
g_wpa_client_cert = NULL;
|
||||
g_wpa_client_cert_len = 0;
|
||||
g_wpa_private_key = NULL;
|
||||
g_wpa_private_key_len = 0;
|
||||
g_wpa_private_key_passwd = NULL;
|
||||
g_wpa_private_key_passwd_len = 0;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_ca_cert(const unsigned char *ca_cert, int ca_cert_len)
|
||||
{
|
||||
if (ca_cert && ca_cert_len > 0) {
|
||||
g_wpa_ca_cert = ca_cert;
|
||||
g_wpa_ca_cert_len = ca_cert_len;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wifi_sta_wpa2_ent_clear_ca_cert(void)
|
||||
{
|
||||
g_wpa_ca_cert = NULL;
|
||||
g_wpa_ca_cert_len = 0;
|
||||
}
|
||||
|
||||
#define ANONYMOUS_ID_LEN_MAX 128
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_identity(const unsigned char *identity, int len)
|
||||
{
|
||||
if (len <= 0 || len > ANONYMOUS_ID_LEN_MAX) {
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (g_wpa_anonymous_identity) {
|
||||
os_free(g_wpa_anonymous_identity);
|
||||
g_wpa_anonymous_identity = NULL;
|
||||
}
|
||||
|
||||
g_wpa_anonymous_identity = (u8 *)os_zalloc(len);
|
||||
if (g_wpa_anonymous_identity == NULL) {
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
os_memcpy(g_wpa_anonymous_identity, identity, len);
|
||||
g_wpa_anonymous_identity_len = len;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wifi_sta_wpa2_ent_clear_identity(void)
|
||||
{
|
||||
if (g_wpa_anonymous_identity)
|
||||
os_free(g_wpa_anonymous_identity);
|
||||
|
||||
g_wpa_anonymous_identity = NULL;
|
||||
g_wpa_anonymous_identity_len = 0;
|
||||
}
|
||||
|
||||
#define USERNAME_LEN_MAX 128
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_username(const unsigned char *username, int len)
|
||||
{
|
||||
if (len <= 0 || len > USERNAME_LEN_MAX)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
if (g_wpa_username) {
|
||||
os_free(g_wpa_username);
|
||||
g_wpa_username = NULL;
|
||||
}
|
||||
|
||||
g_wpa_username = (u8 *)os_zalloc(len);
|
||||
if (g_wpa_username == NULL)
|
||||
return ESP_ERR_NO_MEM;
|
||||
|
||||
os_memcpy(g_wpa_username, username, len);
|
||||
g_wpa_username_len = len;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wifi_sta_wpa2_ent_clear_username(void)
|
||||
{
|
||||
if (g_wpa_username)
|
||||
os_free(g_wpa_username);
|
||||
|
||||
g_wpa_username = NULL;
|
||||
g_wpa_username_len = 0;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_password(const unsigned char *password, int len)
|
||||
{
|
||||
if (len <= 0)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
if (g_wpa_password) {
|
||||
os_free(g_wpa_password);
|
||||
g_wpa_password = NULL;
|
||||
}
|
||||
|
||||
g_wpa_password = (u8 *)os_zalloc(len);
|
||||
if (g_wpa_password == NULL)
|
||||
return ESP_ERR_NO_MEM;
|
||||
|
||||
os_memcpy(g_wpa_password, password, len);
|
||||
g_wpa_password_len = len;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wifi_sta_wpa2_ent_clear_password(void)
|
||||
{
|
||||
if (g_wpa_password)
|
||||
os_free(g_wpa_password);
|
||||
g_wpa_password = NULL;
|
||||
g_wpa_password_len = 0;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_new_password(const unsigned char *new_password, int len)
|
||||
{
|
||||
if (len <= 0)
|
||||
return ESP_ERR_INVALID_ARG;
|
||||
|
||||
if (g_wpa_new_password) {
|
||||
os_free(g_wpa_new_password);
|
||||
g_wpa_new_password = NULL;
|
||||
}
|
||||
|
||||
g_wpa_new_password = (u8 *)os_zalloc(len);
|
||||
if (g_wpa_new_password == NULL)
|
||||
return ESP_ERR_NO_MEM;
|
||||
|
||||
os_memcpy(g_wpa_new_password, new_password, len);
|
||||
g_wpa_password_len = len;
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void esp_wifi_sta_wpa2_ent_clear_new_password(void)
|
||||
{
|
||||
if (g_wpa_new_password)
|
||||
os_free(g_wpa_new_password);
|
||||
g_wpa_new_password = NULL;
|
||||
g_wpa_new_password_len = 0;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_set_disable_time_check(bool disable)
|
||||
{
|
||||
gl_disable_time_check = disable;
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
bool wifi_sta_get_enterprise_disable_time_check(void)
|
||||
{
|
||||
return gl_disable_time_check;
|
||||
}
|
||||
|
||||
esp_err_t esp_wifi_sta_wpa2_ent_get_disable_time_check(bool *disable)
|
||||
{
|
||||
*disable = wifi_sta_get_enterprise_disable_time_check();
|
||||
return ESP_OK;
|
||||
}
|
||||
|
205
components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c
Normal file
205
components/wpa_supplicant/src/wpa2/eap_peer/eap_common.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* EAP common peer/server definitions
|
||||
* Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/eap_peer/eap_defs.h"
|
||||
#include "wpa2/eap_peer/eap_common.h"
|
||||
|
||||
/**
|
||||
* eap_hdr_len_valid - Validate EAP header length field
|
||||
* @msg: EAP frame (starting with EAP header)
|
||||
* @min_payload: Minimum payload length needed
|
||||
* Returns: 1 for valid header, 0 for invalid
|
||||
*
|
||||
* This is a helper function that does minimal validation of EAP messages. The
|
||||
* length field is verified to be large enough to include the header and not
|
||||
* too large to go beyond the end of the buffer.
|
||||
*/
|
||||
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
|
||||
{
|
||||
const struct eap_hdr *hdr;
|
||||
size_t len;
|
||||
|
||||
if (msg == NULL)
|
||||
return 0;
|
||||
|
||||
hdr = wpabuf_head(msg);
|
||||
|
||||
if (wpabuf_len(msg) < sizeof(*hdr)) {
|
||||
wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = be_to_host16(hdr->length);
|
||||
if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_hdr_validate - Validate EAP header
|
||||
* @vendor: Expected EAP Vendor-Id (0 = IETF)
|
||||
* @eap_type: Expected EAP type number
|
||||
* @msg: EAP frame (starting with EAP header)
|
||||
* @plen: Pointer to variable to contain the returned payload length
|
||||
* Returns: Pointer to EAP payload (after type field), or %NULL on failure
|
||||
*
|
||||
* This is a helper function for EAP method implementations. This is usually
|
||||
* called in the beginning of struct eap_method::process() function to verify
|
||||
* that the received EAP request packet has a valid header. This function is
|
||||
* able to process both legacy and expanded EAP headers and in most cases, the
|
||||
* caller can just use the returned payload pointer (into *plen) for processing
|
||||
* the payload regardless of whether the packet used the expanded EAP header or
|
||||
* not.
|
||||
*/
|
||||
const u8 * eap_hdr_validate(int vendor, EapType eap_type,
|
||||
const struct wpabuf *msg, size_t *plen)
|
||||
{
|
||||
const struct eap_hdr *hdr;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
if (!eap_hdr_len_valid(msg, 1))
|
||||
return NULL;
|
||||
|
||||
hdr = wpabuf_head(msg);
|
||||
len = be_to_host16(hdr->length);
|
||||
pos = (const u8 *) (hdr + 1);
|
||||
|
||||
if (*pos == EAP_TYPE_EXPANDED) {
|
||||
int exp_vendor;
|
||||
u32 exp_type;
|
||||
if (len < sizeof(*hdr) + 8) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
|
||||
"length");
|
||||
return NULL;
|
||||
}
|
||||
pos++;
|
||||
exp_vendor = WPA_GET_BE24(pos);
|
||||
pos += 3;
|
||||
exp_type = WPA_GET_BE32(pos);
|
||||
pos += 4;
|
||||
if (exp_vendor != vendor || exp_type != (u32) eap_type) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
|
||||
"type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*plen = len - sizeof(*hdr) - 8;
|
||||
return pos;
|
||||
} else {
|
||||
if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid frame type");
|
||||
return NULL;
|
||||
}
|
||||
*plen = len - sizeof(*hdr) - 1;
|
||||
return pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_msg_alloc - Allocate a buffer for an EAP message
|
||||
* @vendor: Vendor-Id (0 = IETF)
|
||||
* @type: EAP type
|
||||
* @payload_len: Payload length in bytes (data after Type)
|
||||
* @code: Message Code (EAP_CODE_*)
|
||||
* @identifier: Identifier
|
||||
* Returns: Pointer to the allocated message buffer or %NULL on error
|
||||
*
|
||||
* This function can be used to allocate a buffer for an EAP message and fill
|
||||
* in the EAP header. This function is automatically using expanded EAP header
|
||||
* if the selected Vendor-Id is not IETF. In other words, most EAP methods do
|
||||
* not need to separately select which header type to use when using this
|
||||
* function to allocate the message buffers. The returned buffer has room for
|
||||
* payload_len bytes and has the EAP header and Type field already filled in.
|
||||
*/
|
||||
struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
|
||||
u8 code, u8 identifier)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
struct eap_hdr *hdr;
|
||||
size_t len;
|
||||
|
||||
len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
|
||||
payload_len;
|
||||
buf = wpabuf_alloc(len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
hdr = wpabuf_put(buf, sizeof(*hdr));
|
||||
hdr->code = code;
|
||||
hdr->identifier = identifier;
|
||||
hdr->length = host_to_be16(len);
|
||||
|
||||
if (vendor == EAP_VENDOR_IETF) {
|
||||
wpabuf_put_u8(buf, type);
|
||||
} else {
|
||||
wpabuf_put_u8(buf, EAP_TYPE_EXPANDED);
|
||||
wpabuf_put_be24(buf, vendor);
|
||||
wpabuf_put_be32(buf, type);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_update_len - Update EAP header length
|
||||
* @msg: EAP message from eap_msg_alloc
|
||||
*
|
||||
* This function updates the length field in the EAP header to match with the
|
||||
* current length for the buffer. This allows eap_msg_alloc() to be used to
|
||||
* allocate a larger buffer than the exact message length (e.g., if exact
|
||||
* message length is not yet known).
|
||||
*/
|
||||
void eap_update_len(struct wpabuf *msg)
|
||||
{
|
||||
struct eap_hdr *hdr;
|
||||
hdr = wpabuf_mhead(msg);
|
||||
if (wpabuf_len(msg) < sizeof(*hdr))
|
||||
return;
|
||||
hdr->length = host_to_be16(wpabuf_len(msg));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_id - Get EAP Identifier from wpabuf
|
||||
* @msg: Buffer starting with an EAP header
|
||||
* Returns: The Identifier field from the EAP header
|
||||
*/
|
||||
u8 eap_get_id(const struct wpabuf *msg)
|
||||
{
|
||||
const struct eap_hdr *eap;
|
||||
|
||||
if (wpabuf_len(msg) < sizeof(*eap))
|
||||
return 0;
|
||||
|
||||
eap = wpabuf_head(msg);
|
||||
return eap->identifier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_id - Get EAP Type from wpabuf
|
||||
* @msg: Buffer starting with an EAP header
|
||||
* Returns: The EAP Type after the EAP header
|
||||
*/
|
||||
EapType eap_get_type(const struct wpabuf *msg)
|
||||
{
|
||||
if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
|
||||
return EAP_TYPE_NONE;
|
||||
|
||||
return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
|
||||
}
|
671
components/wpa_supplicant/src/wpa2/eap_peer/eap_mschapv2.c
Normal file
671
components/wpa_supplicant/src/wpa2/eap_peer/eap_mschapv2.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
|
||||
* Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef EAP_MSCHAPv2
|
||||
|
||||
#include "wpa/wpa.h"
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/ms_funcs.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
#include "wpa2/eap_peer/eap_defs.h"
|
||||
#include "wpa2/eap_peer/eap_tls_common.h"
|
||||
#include "wpa2/eap_peer/eap_config.h"
|
||||
#include "wpa2/eap_peer/mschapv2.h"
|
||||
#include "wpa2/eap_peer/eap_methods.h"
|
||||
|
||||
#define MSCHAPV2_OP_CHALLENGE 1
|
||||
#define MSCHAPV2_OP_RESPONSE 2
|
||||
#define MSCHAPV2_OP_SUCCESS 3
|
||||
#define MSCHAPV2_OP_FAILURE 4
|
||||
#define MSCHAPV2_OP_CHANGE_PASSWORD 7
|
||||
|
||||
#define PASSWD_CHANGE_CHAL_LEN 16
|
||||
#define MSCHAPV2_KEY_LEN 16
|
||||
|
||||
#define ERROR_RESTRICTED_LOGON_HOURS 646
|
||||
#define ERROR_ACCT_DISABLED 647
|
||||
#define ERROR_PASSWD_EXPIRED 648
|
||||
#define ERROR_NO_DIALIN_PERMISSION 649
|
||||
#define ERROR_AUTHENTICATION_FAILURE 691
|
||||
#define ERROR_CHANGING_PASSWORD 709
|
||||
|
||||
struct eap_mschapv2_hdr {
|
||||
u8 op_code;
|
||||
u8 mschapv2_id;
|
||||
u8 ms_length[2];
|
||||
} __packed;
|
||||
|
||||
struct ms_response {
|
||||
u8 peer_challenge[MSCHAPV2_CHAL_LEN];
|
||||
u8 reserved[8];
|
||||
u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
|
||||
u8 flags;
|
||||
} __packed;
|
||||
|
||||
struct ms_change_password {
|
||||
u8 encr_password[516];
|
||||
u8 encr_hash[16];
|
||||
u8 peer_challenge[MSCHAPV2_CHAL_LEN];
|
||||
u8 reserved[8];
|
||||
u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
|
||||
u8 flags[2];
|
||||
} __packed;
|
||||
|
||||
struct eap_mschapv2_data {
|
||||
u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
|
||||
int auth_response_valid;
|
||||
|
||||
int prev_error;
|
||||
u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
|
||||
int passwd_change_challenge_valid;
|
||||
int passwd_change_version;
|
||||
|
||||
u8 *peer_challenge;
|
||||
u8 *auth_challenge;
|
||||
|
||||
int phase2;
|
||||
u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
|
||||
int master_key_valid;
|
||||
int success;
|
||||
|
||||
struct wpabuf *prev_challenge;
|
||||
};
|
||||
|
||||
static void
|
||||
eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_mschapv2_data *data = priv;
|
||||
|
||||
os_free(data->peer_challenge);
|
||||
os_free(data->auth_challenge);
|
||||
wpabuf_free(data->prev_challenge);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
static void *
|
||||
eap_mschapv2_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_mschapv2_data *data;
|
||||
data = (struct eap_mschapv2_data *)os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
data->phase2 = sm->init_phase2;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_challenge_reply(
|
||||
struct eap_sm *sm, struct eap_mschapv2_data *data,
|
||||
u8 id, u8 mschapv2_id, const u8 *auth_challenge)
|
||||
{
|
||||
struct wpabuf *resp;
|
||||
struct eap_mschapv2_hdr *ms;
|
||||
u8 *peer_challenge;
|
||||
int ms_len;
|
||||
struct ms_response *r;
|
||||
size_t identity_len, password_len;
|
||||
const u8 *identity, *password;
|
||||
int pwhash;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generate Challenge Response\n");
|
||||
|
||||
identity = eap_get_config_identity(sm, &identity_len);
|
||||
password = eap_get_config_password2(sm, &password_len, &pwhash);
|
||||
if (identity == NULL || password == NULL)
|
||||
return NULL;
|
||||
|
||||
ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
|
||||
ms_len, EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
|
||||
ms = wpabuf_put(resp, sizeof(*ms));
|
||||
ms->op_code = MSCHAPV2_OP_RESPONSE;
|
||||
ms->mschapv2_id = mschapv2_id;
|
||||
if (data->prev_error)
|
||||
ms->mschapv2_id++;
|
||||
WPA_PUT_BE16(ms->ms_length, ms_len);
|
||||
wpabuf_put_u8(resp, sizeof(*r));
|
||||
|
||||
/* Response */
|
||||
r = wpabuf_put(resp, sizeof(*r));
|
||||
peer_challenge = r->peer_challenge;
|
||||
if (data->peer_challenge) {
|
||||
peer_challenge = data->peer_challenge;
|
||||
os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
|
||||
} else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) {
|
||||
wpabuf_free(resp);
|
||||
return NULL;
|
||||
}
|
||||
os_memset(r->reserved, 0, 8);
|
||||
if (data->auth_challenge)
|
||||
auth_challenge = data->auth_challenge;
|
||||
if (mschapv2_derive_response(identity, identity_len, password,
|
||||
password_len, pwhash, auth_challenge,
|
||||
peer_challenge, r->nt_response,
|
||||
data->auth_response, data->master_key)) {
|
||||
wpabuf_free(resp);
|
||||
return NULL;
|
||||
}
|
||||
data->auth_response_valid = 1;
|
||||
data->master_key_valid = 1;
|
||||
|
||||
r->flags = 0;
|
||||
|
||||
wpabuf_put_data(resp, identity, identity_len);
|
||||
return resp;
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_challenge(
|
||||
struct eap_sm *sm, struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
|
||||
size_t req_len, u8 id)
|
||||
{
|
||||
size_t len, challenge_len;
|
||||
const u8 *pos, *challenge;
|
||||
|
||||
if (eap_get_config_identity(sm, &len) == NULL ||
|
||||
eap_get_config_password(sm, &len) == NULL)
|
||||
return NULL;
|
||||
|
||||
if (req_len < sizeof(*req) + 1) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
pos = (const u8 *)(req + 1);
|
||||
challenge_len = *pos++;
|
||||
len = req_len - sizeof(*req) - 1;
|
||||
if (challenge_len != MSCHAPV2_CHAL_LEN) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (len < challenge_len) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data->passwd_change_challenge_valid)
|
||||
challenge = data->passwd_change_challenge;
|
||||
else
|
||||
challenge = pos;
|
||||
pos += challenge_len;
|
||||
len -= challenge_len;
|
||||
|
||||
ret->ignore = false;
|
||||
ret->methodState = METHOD_MAY_CONT;
|
||||
ret->decision = DECISION_FAIL;
|
||||
ret->allowNotifications = true;
|
||||
|
||||
return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
|
||||
challenge);
|
||||
}
|
||||
|
||||
static void
|
||||
eap_mschapv2_password_changed(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config && config->new_password) {
|
||||
data->prev_error = 0;
|
||||
os_free(config->password);
|
||||
if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
|
||||
} else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
|
||||
config->password = os_malloc(16);
|
||||
config->password_len = 16;
|
||||
if (config->password) {
|
||||
nt_password_hash(config->new_password,
|
||||
config->new_password_len,
|
||||
config->password);
|
||||
}
|
||||
os_free(config->new_password);
|
||||
} else {
|
||||
config->password = config->new_password;
|
||||
config->password_len = config->new_password_len;
|
||||
}
|
||||
config->new_password = NULL;
|
||||
config->new_password_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_success(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
const struct eap_mschapv2_hdr *req,
|
||||
size_t req_len, u8 id)
|
||||
{
|
||||
struct wpabuf *resp;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
len = req_len - sizeof(*req);
|
||||
pos = (const u8 *)(req + 1);
|
||||
if (!data->auth_response_valid ||
|
||||
mschapv2_verify_auth_response(data->auth_response, pos, len)) {
|
||||
ret->methodState = METHOD_NONE;
|
||||
ret->decision = DECISION_FAIL;
|
||||
return NULL;
|
||||
}
|
||||
pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
|
||||
len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
|
||||
while (len > 0 && *pos == ' ') {
|
||||
pos++;
|
||||
len--;
|
||||
}
|
||||
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS);
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_UNCOND_SUCC;
|
||||
ret->allowNotifications = false;
|
||||
data->success = 1;
|
||||
|
||||
if (data->prev_error == ERROR_PASSWD_EXPIRED)
|
||||
eap_mschapv2_password_changed(sm, data);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
static int
|
||||
eap_mschapv2_failure_txt(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data, char *txt)
|
||||
{
|
||||
char *pos;
|
||||
//char *msg = "";
|
||||
int retry = 1;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
pos = txt;
|
||||
|
||||
if (pos && os_strncmp(pos, "E=", 2) == 0) {
|
||||
pos += 2;
|
||||
data->prev_error = atoi(pos);
|
||||
pos = (char *)os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos && os_strncmp(pos, "R=", 2) == 0) {
|
||||
pos += 2;
|
||||
retry = atoi(pos);
|
||||
pos = (char *)os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos && os_strncmp(pos, "C=", 2) == 0) {
|
||||
int hex_len;
|
||||
pos += 2;
|
||||
hex_len = (char *)os_strchr(pos, ' ') - (char *)pos;
|
||||
if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
|
||||
if (hexstr2bin(pos, data->passwd_change_challenge,
|
||||
PASSWD_CHANGE_CHAL_LEN)) {
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: invalid failure challenge\n");
|
||||
} else {
|
||||
data->passwd_change_challenge_valid = 1;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: required challenge field "
|
||||
"was not present in failure message\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (pos && os_strncmp(pos, "V=", 2) == 0) {
|
||||
pos += 2;
|
||||
data->passwd_change_version = atoi(pos);
|
||||
pos = (char *)os_strchr(pos, ' ');
|
||||
if (pos)
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos && os_strncmp(pos, "M=", 2) == 0) {
|
||||
pos += 2;
|
||||
//msg = pos;
|
||||
}
|
||||
#if 0
|
||||
wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error %d)",
|
||||
msg, retry == 1? "" : "not ", data->prev_error);
|
||||
#endif
|
||||
if (data->prev_error == ERROR_PASSWD_EXPIRED &&
|
||||
data->passwd_change_version == 3 && config) {
|
||||
if (config->new_password == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Password expired - "
|
||||
"password change reqired\n");
|
||||
//eap_sm_request_new_password(sm);
|
||||
}
|
||||
} else if (retry == 1 && config) {
|
||||
if (!config->mschapv2_retry)
|
||||
//eap_sm_request_identity(sm);
|
||||
//eap_sm_request_password(sm);
|
||||
config->mschapv2_retry = 1;
|
||||
} else if (config) {
|
||||
config->mschapv2_retry = 0;
|
||||
}
|
||||
|
||||
return retry == 1;
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_change_password(
|
||||
struct eap_sm *sm, struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
|
||||
{
|
||||
struct wpabuf *resp;
|
||||
int ms_len;
|
||||
const u8 *username, *password, *new_password;
|
||||
size_t username_len, password_len, new_password_len;
|
||||
struct eap_mschapv2_hdr *ms;
|
||||
struct ms_change_password *cp;
|
||||
u8 password_hash[16], password_hash_hash[16];
|
||||
int pwhash;
|
||||
|
||||
username = eap_get_config_identity(sm, &username_len);
|
||||
password = eap_get_config_password2(sm, &password_len, &pwhash);
|
||||
new_password = eap_get_config_new_password(sm, &new_password_len);
|
||||
if (username == NULL || password == NULL || new_password == NULL)
|
||||
return NULL;
|
||||
|
||||
username = mschapv2_remove_domain(username, &username_len);
|
||||
|
||||
ret->ignore = false;
|
||||
ret->methodState = METHOD_MAY_CONT;
|
||||
ret->decision = DECISION_COND_SUCC;
|
||||
ret->allowNotifications = TRUE;
|
||||
|
||||
ms_len = sizeof(*ms) + sizeof(*cp);
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
ms = wpabuf_put(resp, sizeof(*ms));
|
||||
ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
|
||||
ms->mschapv2_id = req->mschapv2_id + 1;
|
||||
WPA_PUT_BE16(ms->ms_length, ms_len);
|
||||
cp = wpabuf_put(resp, sizeof(*cp));
|
||||
|
||||
if (pwhash) {
|
||||
if (encrypt_pw_block_with_password_hash(
|
||||
new_password, new_password_len,
|
||||
password, cp->encr_password))
|
||||
goto fail;
|
||||
} else {
|
||||
if (new_password_encrypted_with_old_nt_password_hash(
|
||||
new_password, new_password_len,
|
||||
password, password_len, cp->encr_password))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (pwhash) {
|
||||
u8 new_password_hash[16];
|
||||
nt_password_hash(new_password, new_password_len,
|
||||
new_password_hash);
|
||||
nt_password_hash_encrypted_with_block(password,
|
||||
new_password_hash,
|
||||
cp->encr_hash);
|
||||
} else {
|
||||
old_nt_password_hash_encrypted_with_new_nt_password_hash(
|
||||
new_password, new_password_len,
|
||||
password, password_len, cp->encr_hash);
|
||||
}
|
||||
|
||||
if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
|
||||
goto fail;
|
||||
|
||||
os_memset(cp->reserved, 0, 8);
|
||||
|
||||
generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
|
||||
username, username_len, new_password,
|
||||
new_password_len, cp->nt_response);
|
||||
|
||||
generate_authenticator_response(new_password, new_password_len,
|
||||
cp->peer_challenge,
|
||||
data->passwd_change_challenge,
|
||||
username, username_len,
|
||||
cp->nt_response, data->auth_response);
|
||||
data->auth_response_valid = 1;
|
||||
|
||||
nt_password_hash(new_password, new_password_len, password_hash);
|
||||
hash_nt_password_hash(password_hash, password_hash_hash);
|
||||
get_master_key(password_hash_hash, cp->nt_response, data->master_key);
|
||||
data->master_key_valid = 1;
|
||||
|
||||
os_memset(cp->flags, 0, 2);
|
||||
|
||||
return resp;
|
||||
|
||||
fail:
|
||||
wpabuf_free(resp);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_failure(struct eap_sm *sm,
|
||||
struct eap_mschapv2_data *data,
|
||||
struct eap_method_ret *ret,
|
||||
const struct eap_mschapv2_hdr *req,
|
||||
size_t req_len, u8 id)
|
||||
{
|
||||
struct wpabuf *resp;
|
||||
const u8 *msdata = (const u8 *)(req + 1);
|
||||
char *buf;
|
||||
size_t len = req_len - sizeof(*req);
|
||||
int retry = 0;
|
||||
|
||||
buf = (char *)dup_binstr(msdata, len);
|
||||
if (buf) {
|
||||
retry = eap_mschapv2_failure_txt(sm, data, buf);
|
||||
os_free(buf);
|
||||
}
|
||||
|
||||
ret->ignore = false;
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_FAIL;
|
||||
ret->allowNotifications = false;
|
||||
|
||||
if (data->prev_error == ERROR_PASSWD_EXPIRED &&
|
||||
data->passwd_change_version == 3) {
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config && config->new_password)
|
||||
return eap_mschapv2_change_password(sm, data, ret,
|
||||
req, id);
|
||||
//if (config && config->pending_req_new_password)
|
||||
// return NULL;
|
||||
} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
|
||||
EAP_CODE_RESPONSE, id);
|
||||
if (resp == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE);
|
||||
return resp;
|
||||
}
|
||||
|
||||
static int
|
||||
eap_mschapv2_check_config(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
if (config == NULL)
|
||||
return -1;
|
||||
|
||||
if (config->identity == NULL ||
|
||||
config->identity_len == 0) {
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: idetity not configured\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (config->password == NULL ||
|
||||
config->password_len == 0) {
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Password not configured\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
|
||||
const struct eap_mschapv2_hdr *ms)
|
||||
{
|
||||
size_t ms_len = WPA_GET_BE16(ms->ms_length);
|
||||
|
||||
if (ms_len == len)
|
||||
return 0;
|
||||
|
||||
if (sm->workaround) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Workaround, ignore Invalid"
|
||||
" header len=%lu ms_len=%lu\n",
|
||||
(unsigned long)len, (unsigned long)ms_len);
|
||||
return 0;
|
||||
}
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Invalid header len=%lu ms_len=%lu\n",
|
||||
(unsigned long)len, (unsigned long)ms_len);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
|
||||
const struct wpabuf *reqData)
|
||||
{
|
||||
wpabuf_free(data->prev_challenge);
|
||||
data->prev_challenge = wpabuf_dup(reqData);
|
||||
}
|
||||
|
||||
static struct wpabuf *
|
||||
eap_mschapv2_process(struct eap_sm *sm, void *priv,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData)
|
||||
{
|
||||
u8 id;
|
||||
size_t len;
|
||||
const u8 *pos;
|
||||
int using_prev_challenge = 0;
|
||||
const struct eap_mschapv2_hdr *ms;
|
||||
struct eap_mschapv2_data *data = priv;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
|
||||
if (eap_mschapv2_check_config(sm)) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (config->mschapv2_retry && data->prev_challenge &&
|
||||
data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
|
||||
reqData = data->prev_challenge;
|
||||
using_prev_challenge = 1;
|
||||
config->mschapv2_retry = 0;
|
||||
}
|
||||
|
||||
pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
|
||||
reqData, &len);
|
||||
if (pos == NULL || len < sizeof(*ms) + 1) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ms = (const struct eap_mschapv2_hdr *)pos;
|
||||
if (eap_mschapv2_check_mslen(sm, len, ms)) {
|
||||
ret->ignore = true;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
id = eap_get_id(reqData);
|
||||
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d\n",
|
||||
id, ms->mschapv2_id);
|
||||
switch (ms->op_code) {
|
||||
case MSCHAPV2_OP_CHALLENGE:
|
||||
if (!using_prev_challenge)
|
||||
eap_mschapv2_copy_challenge(data, reqData);
|
||||
return eap_mschapv2_challenge(sm, data, ret, ms, len, id);
|
||||
case MSCHAPV2_OP_SUCCESS:
|
||||
return eap_mschapv2_success(sm, data, ret, ms, len, id);
|
||||
case MSCHAPV2_OP_FAILURE:
|
||||
return eap_mschapv2_failure(sm, data, ret, ms, len, id);
|
||||
default:
|
||||
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Unknow op code %d -ignored\n",
|
||||
ms->op_code);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_mschapv2_data *data = priv;
|
||||
return data->success && data->master_key_valid;
|
||||
}
|
||||
|
||||
static u8 *
|
||||
eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_mschapv2_data *data = priv;
|
||||
u8 *key;
|
||||
int key_len;
|
||||
|
||||
if (!data->master_key_valid || !data->success)
|
||||
return NULL;
|
||||
|
||||
key_len = 2 * MSCHAPV2_KEY_LEN;
|
||||
|
||||
key = os_malloc(key_len);
|
||||
|
||||
/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key,
|
||||
* peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
|
||||
get_asymetric_start_key(data->master_key, key,
|
||||
MSCHAPV2_KEY_LEN, 1, 0);
|
||||
get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
|
||||
MSCHAPV2_KEY_LEN, 0, 0);
|
||||
|
||||
*len = key_len;
|
||||
return key;
|
||||
}
|
||||
|
||||
int
|
||||
eap_peer_mschapv2_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
||||
eap = eap_peer_method_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
|
||||
"MSCHAPV2");
|
||||
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_mschapv2_init;
|
||||
eap->deinit = eap_mschapv2_deinit;
|
||||
eap->process = eap_mschapv2_process;
|
||||
eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
|
||||
eap->getKey = eap_mschapv2_getKey;
|
||||
|
||||
ret = eap_peer_method_register(eap);
|
||||
if (ret)
|
||||
eap_peer_method_free(eap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* EAP_MSCHAPv2 */
|
1357
components/wpa_supplicant/src/wpa2/eap_peer/eap_peap.c
Normal file
1357
components/wpa_supplicant/src/wpa2/eap_peer/eap_peap.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* EAP-PEAP common routines
|
||||
* Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#ifdef EAP_PEAP
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "wpa2/eap_peer/eap_peap_common.h"
|
||||
|
||||
int
|
||||
peap_prfplus(int version, const u8 *key, size_t key_len,
|
||||
const char *label, const u8 *seed, size_t seed_len,
|
||||
u8 *buf, size_t buf_len)
|
||||
{
|
||||
unsigned char counter = 0;
|
||||
size_t pos, plen;
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
size_t label_len = os_strlen(label);
|
||||
u8 extra[2];
|
||||
const unsigned char *addr[5];
|
||||
size_t len[5];
|
||||
|
||||
addr[0] = hash;
|
||||
len[0] = 0;
|
||||
addr[1] = (unsigned char *) label;
|
||||
len[1] = label_len;
|
||||
addr[2] = seed;
|
||||
len[2] = seed_len;
|
||||
|
||||
if (version == 0) {
|
||||
/*
|
||||
* PRF+(K, S, LEN) = T1 | T2 | ... | Tn
|
||||
* T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
|
||||
* T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
|
||||
* ...
|
||||
* Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
|
||||
*/
|
||||
|
||||
extra[0] = 0;
|
||||
extra[1] = 0;
|
||||
|
||||
addr[3] = &counter;
|
||||
len[3] = 1;
|
||||
addr[4] = extra;
|
||||
len[4] = 2;
|
||||
} else {
|
||||
/*
|
||||
* PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
|
||||
* T1 = HMAC-SHA1(K, S | LEN | 0x01)
|
||||
* T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
|
||||
* T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
|
||||
* T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
|
||||
* ...
|
||||
*/
|
||||
|
||||
extra[0] = buf_len & 0xff;
|
||||
|
||||
addr[3] = extra;
|
||||
len[3] = 1;
|
||||
addr[4] = &counter;
|
||||
len[4] = 1;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
while (pos < buf_len) {
|
||||
counter++;
|
||||
plen = buf_len - pos;
|
||||
if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
|
||||
return -1;
|
||||
if (plen >= SHA1_MAC_LEN) {
|
||||
os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
|
||||
pos += SHA1_MAC_LEN;
|
||||
} else {
|
||||
os_memcpy(&buf[pos], hash, plen);
|
||||
break;
|
||||
}
|
||||
len[0] = SHA1_MAC_LEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* EAP_PEAP */
|
232
components/wpa_supplicant/src/wpa2/eap_peer/eap_tls.c
Normal file
232
components/wpa_supplicant/src/wpa2/eap_peer/eap_tls.c
Normal file
|
@ -0,0 +1,232 @@
|
|||
/*
|
||||
* EAP peer method: EAP-TLS (RFC 2716)
|
||||
* Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#ifdef EAP_TLS
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
#include "wpa2/eap_peer/eap_defs.h"
|
||||
#include "wpa2/eap_peer/eap_tls_common.h"
|
||||
#include "wpa2/eap_peer/eap_config.h"
|
||||
#include "wpa2/eap_peer/eap_methods.h"
|
||||
|
||||
struct eap_tls_data {
|
||||
struct eap_ssl_data ssl;
|
||||
u8 *key_data;
|
||||
u8 *session_id;
|
||||
size_t id_len;
|
||||
void *ssl_ctx;
|
||||
u8 eap_type;
|
||||
};
|
||||
|
||||
|
||||
|
||||
static void eap_tls_deinit(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
if (data == NULL)
|
||||
return;
|
||||
eap_peer_tls_ssl_deinit(sm, &data->ssl);
|
||||
os_free(data->key_data);
|
||||
os_free(data->session_id);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
static void * eap_tls_init(struct eap_sm *sm)
|
||||
{
|
||||
struct eap_tls_data *data;
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config == NULL ||
|
||||
config->private_key == 0) {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = (struct eap_tls_data *)os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
data->ssl_ctx = sm->ssl_ctx;
|
||||
|
||||
if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
|
||||
eap_tls_deinit(sm, data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->eap_type = EAP_TYPE_TLS;
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
|
||||
struct eap_tls_data *data,
|
||||
struct eap_method_ret *ret, int res,
|
||||
struct wpabuf *resp, u8 id)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
|
||||
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_FAIL;
|
||||
|
||||
if (res == -1) {
|
||||
struct eap_peer_config *config = eap_get_config(sm);
|
||||
if (config) {
|
||||
/*
|
||||
* The TLS handshake failed. So better forget the old
|
||||
* PIN. It may be wrong, we cannot be sure but trying
|
||||
* the wrong one again might block it on the card--so
|
||||
* better ask the user again.
|
||||
*/
|
||||
os_free(config->pin);
|
||||
config->pin = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (resp) {
|
||||
/*
|
||||
* This is likely an alert message, so send it instead of just
|
||||
* ACKing the error.
|
||||
*/
|
||||
return resp;
|
||||
}
|
||||
|
||||
return eap_peer_tls_build_ack(id, data->eap_type, 0);
|
||||
}
|
||||
|
||||
|
||||
static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
|
||||
struct eap_method_ret *ret)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
|
||||
|
||||
ret->methodState = METHOD_DONE;
|
||||
ret->decision = DECISION_UNCOND_SUCC;
|
||||
|
||||
os_free(data->key_data);
|
||||
data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
|
||||
"client EAP encryption",
|
||||
EAP_TLS_KEY_LEN +
|
||||
EAP_EMSK_LEN);
|
||||
if (data->key_data) {
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
|
||||
data->key_data, EAP_TLS_KEY_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
|
||||
data->key_data + EAP_TLS_KEY_LEN,
|
||||
EAP_EMSK_LEN);
|
||||
} else {
|
||||
wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
|
||||
}
|
||||
|
||||
os_free(data->session_id);
|
||||
data->session_id = eap_peer_tls_derive_session_id(sm, &data->ssl,
|
||||
EAP_TYPE_TLS,
|
||||
&data->id_len);
|
||||
if (data->session_id) {
|
||||
wpa_hexdump(MSG_DEBUG, "EAP-TLS: Derived Session-Id",
|
||||
data->session_id, data->id_len);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "EAP-TLS: Failed to derive Session-Id");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
|
||||
struct eap_method_ret *ret,
|
||||
const struct wpabuf *reqData)
|
||||
{
|
||||
size_t left;
|
||||
int res;
|
||||
struct wpabuf *resp;
|
||||
u8 flags, id;
|
||||
const u8 *pos;
|
||||
struct eap_tls_data *data = priv;
|
||||
|
||||
pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
|
||||
reqData, &left, &flags);
|
||||
if (pos == NULL)
|
||||
return NULL;
|
||||
id = eap_get_id(reqData);
|
||||
|
||||
if (flags & EAP_TLS_FLAGS_START) {
|
||||
wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
|
||||
left = 0; /* make sure that this frame is empty, even though it
|
||||
* should always be, anyway */
|
||||
}
|
||||
|
||||
resp = NULL;
|
||||
res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0,
|
||||
id, pos, left, &resp);
|
||||
|
||||
if (res < 0) {
|
||||
return eap_tls_failure(sm, data, ret, res, resp, id);
|
||||
}
|
||||
|
||||
if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
|
||||
eap_tls_success(sm, data, ret);
|
||||
|
||||
if (res == 1) {
|
||||
wpabuf_free(resp);
|
||||
return eap_peer_tls_build_ack(id, data->eap_type, 0);
|
||||
}
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
static bool eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
|
||||
return data->key_data != NULL;
|
||||
}
|
||||
static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
|
||||
{
|
||||
struct eap_tls_data *data = priv;
|
||||
u8 *key;
|
||||
|
||||
if (data->key_data == NULL)
|
||||
return NULL;
|
||||
|
||||
key = os_malloc(EAP_TLS_KEY_LEN);
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
*len = EAP_TLS_KEY_LEN;
|
||||
os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
int eap_peer_tls_register(void)
|
||||
{
|
||||
struct eap_method *eap;
|
||||
int ret;
|
||||
|
||||
eap = eap_peer_method_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLS,
|
||||
"TLS");
|
||||
|
||||
if (eap == NULL)
|
||||
return -1;
|
||||
|
||||
eap->init = eap_tls_init;
|
||||
eap->deinit = eap_tls_deinit;
|
||||
eap->process = eap_tls_process;
|
||||
eap->isKeyAvailable = eap_tls_isKeyAvailable;
|
||||
eap->getKey = eap_tls_getKey;
|
||||
|
||||
ret = eap_peer_method_register(eap);
|
||||
if (ret)
|
||||
eap_peer_method_free(eap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
#endif /* EAP_TLS */
|
1063
components/wpa_supplicant/src/wpa2/eap_peer/eap_tls_common.c
Normal file
1063
components/wpa_supplicant/src/wpa2/eap_peer/eap_tls_common.c
Normal file
File diff suppressed because it is too large
Load diff
1673
components/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c
Normal file
1673
components/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c
Normal file
File diff suppressed because it is too large
Load diff
97
components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c
Normal file
97
components/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c
Normal file
|
@ -0,0 +1,97 @@
|
|||
/*
|
||||
* MSCHAPV2
|
||||
*/
|
||||
|
||||
#ifdef EAP_MSCHAPv2
|
||||
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/ms_funcs.h"
|
||||
#include "wpa2/eap_peer/mschapv2.h"
|
||||
|
||||
const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
/*
|
||||
* MSCHAPV2 does not include optional domain name in the
|
||||
* challenge-response calculation, so remove domain prefix
|
||||
* (if present)
|
||||
*/
|
||||
for (i = 0; i < *len; i++) {
|
||||
if (username[i] == '\\') {
|
||||
*len -= i + 1;
|
||||
return username + i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
int mschapv2_derive_response(const u8 *identity, size_t identity_len,
|
||||
const u8 *password, size_t password_len,
|
||||
int pwhash,
|
||||
const u8 *auth_challenge,
|
||||
const u8 *peer_challenge,
|
||||
u8 *nt_response, u8 *auth_response,
|
||||
u8 *master_key)
|
||||
{
|
||||
const u8 *username;
|
||||
size_t username_len;
|
||||
u8 password_hash[16], password_hash_hash[16];
|
||||
|
||||
username_len = identity_len;
|
||||
username = mschapv2_remove_domain(identity, &username_len);
|
||||
|
||||
if (pwhash) {
|
||||
if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
|
||||
username, username_len,
|
||||
password, nt_response) ||
|
||||
generate_authenticator_response_pwhash(
|
||||
password, peer_challenge, auth_challenge,
|
||||
username, username_len, nt_response,
|
||||
auth_response))
|
||||
return -1;
|
||||
} else {
|
||||
if (generate_nt_response(auth_challenge, peer_challenge,
|
||||
username, username_len,
|
||||
password, password_len,
|
||||
nt_response) ||
|
||||
generate_authenticator_response(password, password_len,
|
||||
peer_challenge,
|
||||
auth_challenge,
|
||||
username, username_len,
|
||||
nt_response,
|
||||
auth_response))
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pwhash) {
|
||||
if (hash_nt_password_hash(password, password_hash_hash))
|
||||
return -1;
|
||||
} else {
|
||||
if (nt_password_hash(password, password_len, password_hash) ||
|
||||
hash_nt_password_hash(password_hash, password_hash_hash))
|
||||
return -1;
|
||||
}
|
||||
if (get_master_key(password_hash_hash, nt_response, master_key))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int mschapv2_verify_auth_response(const u8 *auth_response,
|
||||
const u8 *buf, size_t buf_len)
|
||||
{
|
||||
u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
|
||||
if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
|
||||
buf[0] != 'S' || buf[1] != '=' ||
|
||||
hexstr2bin((char *)(buf + 2), recv_response,
|
||||
MSCHAPV2_AUTH_RESPONSE_LEN) ||
|
||||
os_memcmp(auth_response, recv_response,
|
||||
MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* EAP_MSCHAPv2 */
|
207
components/wpa_supplicant/src/wpa2/tls/asn1.c
Normal file
207
components/wpa_supplicant/src/wpa2/tls/asn1.c
Normal file
|
@ -0,0 +1,207 @@
|
|||
/*
|
||||
* ASN.1 DER parsing
|
||||
* Copyright (c) 2006, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/tls/asn1.h"
|
||||
|
||||
int asn1_get_next(const u8 *buf, size_t len, struct asn1_hdr *hdr)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u8 tmp;
|
||||
|
||||
os_memset(hdr, 0, sizeof(*hdr));
|
||||
pos = buf;
|
||||
end = buf + len;
|
||||
|
||||
hdr->identifier = *pos++;
|
||||
hdr->class = hdr->identifier >> 6;
|
||||
hdr->constructed = !!(hdr->identifier & (1 << 5));
|
||||
|
||||
if ((hdr->identifier & 0x1f) == 0x1f) {
|
||||
hdr->tag = 0;
|
||||
do {
|
||||
if (pos >= end) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Identifier "
|
||||
"underflow");
|
||||
return -1;
|
||||
}
|
||||
tmp = *pos++;
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Extended tag data: "
|
||||
"0x%02x", tmp);
|
||||
hdr->tag = (hdr->tag << 7) | (tmp & 0x7f);
|
||||
} while (tmp & 0x80);
|
||||
} else
|
||||
hdr->tag = hdr->identifier & 0x1f;
|
||||
|
||||
tmp = *pos++;
|
||||
if (tmp & 0x80) {
|
||||
if (tmp == 0xff) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Reserved length "
|
||||
"value 0xff used");
|
||||
return -1;
|
||||
}
|
||||
tmp &= 0x7f; /* number of subsequent octets */
|
||||
hdr->length = 0;
|
||||
if (tmp > 4) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Too long length field");
|
||||
return -1;
|
||||
}
|
||||
while (tmp--) {
|
||||
if (pos >= end) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Length "
|
||||
"underflow");
|
||||
return -1;
|
||||
}
|
||||
hdr->length = (hdr->length << 8) | *pos++;
|
||||
}
|
||||
} else {
|
||||
/* Short form - length 0..127 in one octet */
|
||||
hdr->length = tmp;
|
||||
}
|
||||
|
||||
if (end < pos || hdr->length > (unsigned int) (end - pos)) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Contents underflow");
|
||||
return -1;
|
||||
}
|
||||
|
||||
hdr->payload = pos;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int asn1_parse_oid(const u8 *buf, size_t len, struct asn1_oid *oid)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
unsigned long val;
|
||||
u8 tmp;
|
||||
|
||||
os_memset(oid, 0, sizeof(*oid));
|
||||
|
||||
pos = buf;
|
||||
end = buf + len;
|
||||
|
||||
while (pos < end) {
|
||||
val = 0;
|
||||
|
||||
do {
|
||||
if (pos >= end)
|
||||
return -1;
|
||||
tmp = *pos++;
|
||||
val = (val << 7) | (tmp & 0x7f);
|
||||
} while (tmp & 0x80);
|
||||
|
||||
if (oid->len >= ASN1_MAX_OID_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Too long OID value");
|
||||
return -1;
|
||||
}
|
||||
if (oid->len == 0) {
|
||||
/*
|
||||
* The first octet encodes the first two object
|
||||
* identifier components in (X*40) + Y formula.
|
||||
* X = 0..2.
|
||||
*/
|
||||
oid->oid[0] = val / 40;
|
||||
if (oid->oid[0] > 2)
|
||||
oid->oid[0] = 2;
|
||||
oid->oid[1] = val - oid->oid[0] * 40;
|
||||
oid->len = 2;
|
||||
} else
|
||||
oid->oid[oid->len++] = val;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int asn1_get_oid(const u8 *buf, size_t len, struct asn1_oid *oid,
|
||||
const u8 **next)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
|
||||
if (asn1_get_next(buf, len, &hdr) < 0 || hdr.length == 0)
|
||||
return -1;
|
||||
|
||||
if (hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_OID) {
|
||||
wpa_printf(MSG_DEBUG, "ASN.1: Expected OID - found class %d "
|
||||
"tag 0x%x", hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*next = hdr.payload + hdr.length;
|
||||
|
||||
return asn1_parse_oid(hdr.payload, hdr.length, oid);
|
||||
}
|
||||
|
||||
|
||||
void asn1_oid_to_str(struct asn1_oid *oid, char *buf, size_t len)
|
||||
{
|
||||
char *pos = buf;
|
||||
size_t i;
|
||||
int ret;
|
||||
|
||||
if (len == 0)
|
||||
return;
|
||||
|
||||
buf[0] = '\0';
|
||||
|
||||
for (i = 0; i < oid->len; i++) {
|
||||
//ret = os_snprintf(pos, buf + len - pos,
|
||||
ret = sprintf(pos,
|
||||
"%s%lu",
|
||||
i == 0 ? "" : ".", oid->oid[i]);
|
||||
if (ret < 0 || ret >= buf + len - pos)
|
||||
break;
|
||||
pos += ret;
|
||||
}
|
||||
buf[len - 1] = '\0';
|
||||
}
|
||||
|
||||
|
||||
static u8 rotate_bits(u8 octet)
|
||||
{
|
||||
int i;
|
||||
u8 res;
|
||||
|
||||
res = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
res <<= 1;
|
||||
if (octet & 1)
|
||||
res |= 1;
|
||||
octet >>= 1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
unsigned long asn1_bit_string_to_long(const u8 *buf, size_t len)
|
||||
{
|
||||
unsigned long val = 0;
|
||||
const u8 *pos = buf;
|
||||
|
||||
/* BER requires that unused bits are zero, so we can ignore the number
|
||||
* of unused bits */
|
||||
pos++;
|
||||
|
||||
if (len >= 2)
|
||||
val |= rotate_bits(*pos++);
|
||||
if (len >= 3)
|
||||
val |= ((unsigned long) rotate_bits(*pos++)) << 8;
|
||||
if (len >= 4)
|
||||
val |= ((unsigned long) rotate_bits(*pos++)) << 16;
|
||||
if (len >= 5)
|
||||
val |= ((unsigned long) rotate_bits(*pos++)) << 24;
|
||||
if (len >= 6)
|
||||
wpa_printf(MSG_DEBUG, "X509: %s - some bits ignored "
|
||||
"(BIT STRING length %lu)",
|
||||
__func__, (unsigned long) len);
|
||||
|
||||
return val;
|
||||
}
|
244
components/wpa_supplicant/src/wpa2/tls/bignum.c
Normal file
244
components/wpa_supplicant/src/wpa2/tls/bignum.c
Normal file
|
@ -0,0 +1,244 @@
|
|||
/*
|
||||
* Big number math
|
||||
* Copyright (c) 2006, 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.
|
||||
*/
|
||||
|
||||
#include "crypto/includes.h"
|
||||
#include "crypto/common.h"
|
||||
#include "wpa/wpabuf.h"
|
||||
#include "wpa/wpa_debug.h"
|
||||
#include "wpa2/tls/bignum.h"
|
||||
|
||||
#define CONFIG_INTERNAL_LIBTOMMATH
|
||||
#ifdef CONFIG_INTERNAL_LIBTOMMATH
|
||||
#include "wpa2/tls/libtommath.h"
|
||||
#else /* CONFIG_INTERNAL_LIBTOMMATH */
|
||||
#include <tommath.h>
|
||||
#endif /* CONFIG_INTERNAL_LIBTOMMATH */
|
||||
|
||||
|
||||
/*
|
||||
* The current version is just a wrapper for LibTomMath library, so
|
||||
* struct bignum is just typecast to mp_int.
|
||||
*/
|
||||
|
||||
/**
|
||||
* bignum_init - Allocate memory for bignum
|
||||
* Returns: Pointer to allocated bignum or %NULL on failure
|
||||
*/
|
||||
struct bignum *
|
||||
bignum_init(void)
|
||||
{
|
||||
struct bignum *n = (struct bignum *)os_zalloc(sizeof(mp_int));
|
||||
if (n == NULL)
|
||||
return NULL;
|
||||
if (mp_init((mp_int *) n) != MP_OKAY) {
|
||||
os_free(n);
|
||||
n = NULL;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_deinit - Free bignum
|
||||
* @n: Bignum from bignum_init()
|
||||
*/
|
||||
void
|
||||
bignum_deinit(struct bignum *n)
|
||||
{
|
||||
if (n) {
|
||||
mp_clear((mp_int *) n);
|
||||
os_free(n);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_get_unsigned_bin - Get length of bignum as an unsigned binary buffer
|
||||
* @n: Bignum from bignum_init()
|
||||
* Returns: Length of n if written to a binary buffer
|
||||
*/
|
||||
size_t
|
||||
bignum_get_unsigned_bin_len(struct bignum *n)
|
||||
{
|
||||
return mp_unsigned_bin_size((mp_int *) n);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_get_unsigned_bin - Set binary buffer to unsigned bignum
|
||||
* @n: Bignum from bignum_init()
|
||||
* @buf: Buffer for the binary number
|
||||
* @len: Length of the buffer, can be %NULL if buffer is known to be long
|
||||
* enough. Set to used buffer length on success if not %NULL.
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_get_unsigned_bin(const struct bignum *n, u8 *buf, size_t *len)
|
||||
{
|
||||
size_t need = mp_unsigned_bin_size((mp_int *) n);
|
||||
if (len && need > *len) {
|
||||
*len = need;
|
||||
return -1;
|
||||
}
|
||||
if (mp_to_unsigned_bin((mp_int *) n, buf) != MP_OKAY) {
|
||||
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
if (len)
|
||||
*len = need;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_set_unsigned_bin - Set bignum based on unsigned binary buffer
|
||||
* @n: Bignum from bignum_init(); to be set to the given value
|
||||
* @buf: Buffer with unsigned binary value
|
||||
* @len: Length of buf in octets
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_set_unsigned_bin(struct bignum *n, const u8 *buf, size_t len)
|
||||
{
|
||||
if (mp_read_unsigned_bin((mp_int *) n, (u8 *) buf, len) != MP_OKAY) {
|
||||
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_cmp - Signed comparison
|
||||
* @a: Bignum from bignum_init()
|
||||
* @b: Bignum from bignum_init()
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_cmp(const struct bignum *a, const struct bignum *b)
|
||||
{
|
||||
return mp_cmp((mp_int *) a, (mp_int *) b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_cmd_d - Compare bignum to standard integer
|
||||
* @a: Bignum from bignum_init()
|
||||
* @b: Small integer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_cmp_d(const struct bignum *a, unsigned long b)
|
||||
{
|
||||
return mp_cmp_d((mp_int *) a, b);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_add - c = a + b
|
||||
* @a: Bignum from bignum_init()
|
||||
* @b: Bignum from bignum_init()
|
||||
* @c: Bignum from bignum_init(); used to store the result of a + b
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_add(const struct bignum *a, const struct bignum *b,
|
||||
struct bignum *c)
|
||||
{
|
||||
if (mp_add((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
|
||||
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_sub - c = a - b
|
||||
* @a: Bignum from bignum_init()
|
||||
* @b: Bignum from bignum_init()
|
||||
* @c: Bignum from bignum_init(); used to store the result of a - b
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_sub(const struct bignum *a, const struct bignum *b,
|
||||
struct bignum *c)
|
||||
{
|
||||
if (mp_sub((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
|
||||
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_mul - c = a * b
|
||||
* @a: Bignum from bignum_init()
|
||||
* @b: Bignum from bignum_init()
|
||||
* @c: Bignum from bignum_init(); used to store the result of a * b
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_mul(const struct bignum *a, const struct bignum *b,
|
||||
struct bignum *c)
|
||||
{
|
||||
if (mp_mul((mp_int *) a, (mp_int *) b, (mp_int *) c) != MP_OKAY) {
|
||||
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_mulmod - d = a * b (mod c)
|
||||
* @a: Bignum from bignum_init()
|
||||
* @b: Bignum from bignum_init()
|
||||
* @c: Bignum from bignum_init(); modulus
|
||||
* @d: Bignum from bignum_init(); used to store the result of a * b (mod c)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_mulmod(const struct bignum *a, const struct bignum *b,
|
||||
const struct bignum *c, struct bignum *d)
|
||||
{
|
||||
if (mp_mulmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
|
||||
!= MP_OKAY) {
|
||||
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* bignum_exptmod - Modular exponentiation: d = a^b (mod c)
|
||||
* @a: Bignum from bignum_init(); base
|
||||
* @b: Bignum from bignum_init(); exponent
|
||||
* @c: Bignum from bignum_init(); modulus
|
||||
* @d: Bignum from bignum_init(); used to store the result of a^b (mod c)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int
|
||||
bignum_exptmod(const struct bignum *a, const struct bignum *b,
|
||||
const struct bignum *c, struct bignum *d)
|
||||
{
|
||||
if (mp_exptmod((mp_int *) a, (mp_int *) b, (mp_int *) c, (mp_int *) d)
|
||||
!= MP_OKAY) {
|
||||
wpa_printf(MSG_DEBUG, "BIGNUM: %s failed", __func__);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
195
components/wpa_supplicant/src/wpa2/tls/pkcs1.c
Normal file
195
components/wpa_supplicant/src/wpa2/tls/pkcs1.c
Normal file
|
@ -0,0 +1,195 @@
|
|||
/*
|
||||
* PKCS #1 (RSA Encryption)
|
||||
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/tls/rsa.h"
|
||||
#include "wpa2/tls/pkcs1.h"
|
||||
|
||||
|
||||
static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
|
||||
const u8 *in, size_t inlen,
|
||||
u8 *out, size_t *outlen)
|
||||
{
|
||||
size_t ps_len;
|
||||
u8 *pos;
|
||||
|
||||
/*
|
||||
* PKCS #1 v1.5, 8.1:
|
||||
*
|
||||
* EB = 00 || BT || PS || 00 || D
|
||||
* BT = 00 or 01 for private-key operation; 02 for public-key operation
|
||||
* PS = k-3-||D||; at least eight octets
|
||||
* (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
|
||||
* k = length of modulus in octets (modlen)
|
||||
*/
|
||||
|
||||
if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
|
||||
"lengths (modlen=%lu outlen=%lu inlen=%lu)",
|
||||
__func__, (unsigned long) modlen,
|
||||
(unsigned long) *outlen,
|
||||
(unsigned long) inlen);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = out;
|
||||
*pos++ = 0x00;
|
||||
*pos++ = block_type; /* BT */
|
||||
ps_len = modlen - inlen - 3;
|
||||
switch (block_type) {
|
||||
case 0:
|
||||
os_memset(pos, 0x00, ps_len);
|
||||
pos += ps_len;
|
||||
break;
|
||||
case 1:
|
||||
os_memset(pos, 0xff, ps_len);
|
||||
pos += ps_len;
|
||||
break;
|
||||
case 2:
|
||||
if (os_get_random(pos, ps_len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
|
||||
"random data for PS", __func__);
|
||||
return -1;
|
||||
}
|
||||
while (ps_len--) {
|
||||
if (*pos == 0x00)
|
||||
*pos = 0x01;
|
||||
pos++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
|
||||
"%d", __func__, block_type);
|
||||
return -1;
|
||||
}
|
||||
*pos++ = 0x00;
|
||||
os_memcpy(pos, in, inlen); /* D */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pkcs1_encrypt(int block_type, struct crypto_rsa_key *key,
|
||||
int use_private, const u8 *in, size_t inlen,
|
||||
u8 *out, size_t *outlen)
|
||||
{
|
||||
size_t modlen;
|
||||
|
||||
modlen = crypto_rsa_get_modulus_len(key);
|
||||
|
||||
if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
|
||||
out, outlen) < 0)
|
||||
return -1;
|
||||
|
||||
return crypto_rsa_exptmod(out, modlen, out, outlen, key, use_private);
|
||||
}
|
||||
|
||||
|
||||
int pkcs1_v15_private_key_decrypt(struct crypto_rsa_key *key,
|
||||
const u8 *in, size_t inlen,
|
||||
u8 *out, size_t *outlen)
|
||||
{
|
||||
int res;
|
||||
u8 *pos, *end;
|
||||
|
||||
res = crypto_rsa_exptmod(in, inlen, out, outlen, key, 1);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
if (*outlen < 2 || out[0] != 0 || out[1] != 2)
|
||||
return -1;
|
||||
|
||||
/* Skip PS (pseudorandom non-zero octets) */
|
||||
pos = out + 2;
|
||||
end = out + *outlen;
|
||||
while (*pos && pos < end)
|
||||
pos++;
|
||||
if (pos == end)
|
||||
return -1;
|
||||
pos++;
|
||||
|
||||
*outlen -= pos - out;
|
||||
|
||||
/* Strip PKCS #1 header */
|
||||
os_memmove(out, pos, *outlen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int pkcs1_decrypt_public_key(struct crypto_rsa_key *key,
|
||||
const u8 *crypt, size_t crypt_len,
|
||||
u8 *plain, size_t *plain_len)
|
||||
{
|
||||
size_t len;
|
||||
u8 *pos;
|
||||
|
||||
len = *plain_len;
|
||||
if (crypto_rsa_exptmod(crypt, crypt_len, plain, &len, key, 0) < 0)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* PKCS #1 v1.5, 8.1:
|
||||
*
|
||||
* EB = 00 || BT || PS || 00 || D
|
||||
* BT = 00 or 01
|
||||
* PS = k-3-||D|| times (00 if BT=00) or (FF if BT=01)
|
||||
* k = length of modulus in octets
|
||||
*/
|
||||
|
||||
if (len < 3 + 8 + 16 /* min hash len */ ||
|
||||
plain[0] != 0x00 || (plain[1] != 0x00 && plain[1] != 0x01)) {
|
||||
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
|
||||
"structure");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos = plain + 3;
|
||||
if (plain[1] == 0x00) {
|
||||
/* BT = 00 */
|
||||
if (plain[2] != 0x00) {
|
||||
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
|
||||
"PS (BT=00)");
|
||||
return -1;
|
||||
}
|
||||
while (pos + 1 < plain + len && *pos == 0x00 && pos[1] == 0x00)
|
||||
pos++;
|
||||
} else {
|
||||
/* BT = 01 */
|
||||
if (plain[2] != 0xff) {
|
||||
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature "
|
||||
"PS (BT=01)");
|
||||
return -1;
|
||||
}
|
||||
while (pos < plain + len && *pos == 0xff)
|
||||
pos++;
|
||||
}
|
||||
|
||||
if (pos - plain - 2 < 8) {
|
||||
/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
|
||||
wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
|
||||
"padding");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
|
||||
wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
|
||||
"structure (2)");
|
||||
return -1;
|
||||
}
|
||||
pos++;
|
||||
len -= pos - plain;
|
||||
|
||||
/* Strip PKCS #1 header */
|
||||
os_memmove(plain, pos, len);
|
||||
*plain_len = len;
|
||||
|
||||
return 0;
|
||||
}
|
262
components/wpa_supplicant/src/wpa2/tls/pkcs5.c
Normal file
262
components/wpa_supplicant/src/wpa2/tls/pkcs5.c
Normal file
|
@ -0,0 +1,262 @@
|
|||
/*
|
||||
* PKCS #5 (Password-based Encryption)
|
||||
* Copyright (c) 2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "wpa2/tls/asn1.h"
|
||||
#include "wpa2/tls/pkcs5.h"
|
||||
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
|
||||
struct pkcs5_params {
|
||||
enum pkcs5_alg {
|
||||
PKCS5_ALG_UNKNOWN,
|
||||
PKCS5_ALG_MD5_DES_CBC
|
||||
} alg;
|
||||
u8 salt[8];
|
||||
size_t salt_len;
|
||||
unsigned int iter_count;
|
||||
};
|
||||
|
||||
|
||||
static enum pkcs5_alg pkcs5_get_alg(struct asn1_oid *oid)
|
||||
{
|
||||
if (oid->len == 7 &&
|
||||
oid->oid[0] == 1 /* iso */ &&
|
||||
oid->oid[1] == 2 /* member-body */ &&
|
||||
oid->oid[2] == 840 /* us */ &&
|
||||
oid->oid[3] == 113549 /* rsadsi */ &&
|
||||
oid->oid[4] == 1 /* pkcs */ &&
|
||||
oid->oid[5] == 5 /* pkcs-5 */ &&
|
||||
oid->oid[6] == 3 /* pbeWithMD5AndDES-CBC */)
|
||||
return PKCS5_ALG_MD5_DES_CBC;
|
||||
|
||||
return PKCS5_ALG_UNKNOWN;
|
||||
}
|
||||
|
||||
|
||||
static int pkcs5_get_params(const u8 *enc_alg, size_t enc_alg_len,
|
||||
struct pkcs5_params *params)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *enc_alg_end, *pos, *end;
|
||||
struct asn1_oid oid;
|
||||
char obuf[80];
|
||||
|
||||
/* AlgorithmIdentifier */
|
||||
|
||||
enc_alg_end = enc_alg + enc_alg_len;
|
||||
|
||||
os_memset(params, 0, sizeof(*params));
|
||||
|
||||
if (asn1_get_oid(enc_alg, enc_alg_end - enc_alg, &oid, &pos)) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Failed to parse OID "
|
||||
"(algorithm)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
asn1_oid_to_str(&oid, obuf, sizeof(obuf));
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: encryption algorithm %s", obuf);
|
||||
params->alg = pkcs5_get_alg(&oid);
|
||||
if (params->alg == PKCS5_ALG_UNKNOWN) {
|
||||
wpa_printf(MSG_INFO, "PKCS #5: unsupported encryption "
|
||||
"algorithm %s", obuf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* PKCS#5, Section 8
|
||||
* PBEParameter ::= SEQUENCE {
|
||||
* salt OCTET STRING SIZE(8),
|
||||
* iterationCount INTEGER }
|
||||
*/
|
||||
|
||||
if (asn1_get_next(pos, enc_alg_end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Expected SEQUENCE "
|
||||
"(PBEParameter) - found class %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
end = hdr.payload + hdr.length;
|
||||
|
||||
/* salt OCTET STRING SIZE(8) */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_OCTETSTRING ||
|
||||
hdr.length != 8) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Expected OCTETSTRING SIZE(8) "
|
||||
"(salt) - found class %d tag 0x%x size %d",
|
||||
hdr.class, hdr.tag, hdr.length);
|
||||
return -1;
|
||||
}
|
||||
pos = hdr.payload + hdr.length;
|
||||
os_memcpy(params->salt, hdr.payload, hdr.length);
|
||||
params->salt_len = hdr.length;
|
||||
wpa_hexdump(MSG_DEBUG, "PKCS #5: salt",
|
||||
params->salt, params->salt_len);
|
||||
|
||||
/* iterationCount INTEGER */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Expected INTEGER - found "
|
||||
"class %d tag 0x%x", hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
if (hdr.length == 1)
|
||||
params->iter_count = *hdr.payload;
|
||||
else if (hdr.length == 2)
|
||||
params->iter_count = WPA_GET_BE16(hdr.payload);
|
||||
else if (hdr.length == 4)
|
||||
params->iter_count = WPA_GET_BE32(hdr.payload);
|
||||
else {
|
||||
wpa_hexdump(MSG_DEBUG, "PKCS #5: Unsupported INTEGER value "
|
||||
" (iterationCount)",
|
||||
hdr.payload, hdr.length);
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: iterationCount=0x%x",
|
||||
params->iter_count);
|
||||
if (params->iter_count == 0 || params->iter_count > 0xffff) {
|
||||
wpa_printf(MSG_INFO, "PKCS #5: Unsupported "
|
||||
"iterationCount=0x%x", params->iter_count);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static struct crypto_cipher * pkcs5_crypto_init(struct pkcs5_params *params,
|
||||
const char *passwd)
|
||||
{
|
||||
unsigned int i;
|
||||
u8 hash[MD5_MAC_LEN];
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
|
||||
if (params->alg != PKCS5_ALG_MD5_DES_CBC) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
addr[0] = (const u8 *) passwd;
|
||||
len[0] = os_strlen(passwd);
|
||||
addr[1] = params->salt;
|
||||
len[1] = params->salt_len;
|
||||
if (md5_vector(2, addr, len, hash) < 0)
|
||||
return NULL;
|
||||
addr[0] = hash;
|
||||
len[0] = MD5_MAC_LEN;
|
||||
for (i = 1; i < params->iter_count; i++) {
|
||||
if (md5_vector(1, addr, len, hash) < 0)
|
||||
return NULL;
|
||||
}
|
||||
/* TODO: DES key parity bits(?) */
|
||||
wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES key", hash, 8);
|
||||
wpa_hexdump_key(MSG_DEBUG, "PKCS #5: DES IV", hash + 8, 8);
|
||||
|
||||
if (wpa2_crypto_funcs.crypto_cipher_init) {
|
||||
return wpa2_crypto_funcs.crypto_cipher_init(CRYPTO_CIPHER_ALG_DES, hash + 8, hash, 8);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_cipher_init function! \r\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
u8 * pkcs5_decrypt(const u8 *enc_alg, size_t enc_alg_len,
|
||||
const u8 *enc_data, size_t enc_data_len,
|
||||
const char *passwd, size_t *data_len)
|
||||
{
|
||||
struct crypto_cipher *ctx = NULL;
|
||||
u8 *eb, pad;
|
||||
struct pkcs5_params params;
|
||||
unsigned int i;
|
||||
|
||||
if (pkcs5_get_params(enc_alg, enc_alg_len, ¶ms) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Unsupported parameters");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ctx = pkcs5_crypto_init(¶ms, passwd);
|
||||
|
||||
if (ctx == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Failed to initialize crypto");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* PKCS #5, Section 7 - Decryption process */
|
||||
if (enc_data_len < 16 || enc_data_len % 8) {
|
||||
wpa_printf(MSG_INFO, "PKCS #5: invalid length of ciphertext "
|
||||
"%d", (int) enc_data_len);
|
||||
if (wpa2_crypto_funcs.crypto_cipher_deinit) {
|
||||
wpa2_crypto_funcs.crypto_cipher_deinit(ctx);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n");
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eb = os_malloc(enc_data_len);
|
||||
if (eb == NULL) {
|
||||
if (wpa2_crypto_funcs.crypto_cipher_deinit) {
|
||||
wpa2_crypto_funcs.crypto_cipher_deinit(ctx);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n");
|
||||
return NULL;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wpa2_crypto_funcs.crypto_cipher_decrypt) {
|
||||
if ((int)wpa2_crypto_funcs.crypto_cipher_decrypt(ctx, enc_data, eb, enc_data_len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #5: Failed to decrypt EB");
|
||||
wpa2_crypto_funcs.crypto_cipher_deinit(ctx);
|
||||
os_free(eb);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto cipher decrypt function.\r\n");
|
||||
wpa2_crypto_funcs.crypto_cipher_deinit(ctx);
|
||||
os_free(eb);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wpa2_crypto_funcs.crypto_cipher_deinit) {
|
||||
wpa2_crypto_funcs.crypto_cipher_deinit(ctx);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pad = eb[enc_data_len - 1];
|
||||
if (pad > 8) {
|
||||
wpa_printf(MSG_INFO, "PKCS #5: Invalid PS octet 0x%x", pad);
|
||||
os_free(eb);
|
||||
return NULL;
|
||||
}
|
||||
for (i = enc_data_len - pad; i < enc_data_len; i++) {
|
||||
if (eb[i] != pad) {
|
||||
wpa_hexdump(MSG_INFO, "PKCS #5: Invalid PS",
|
||||
eb + enc_data_len - pad, pad);
|
||||
os_free(eb);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "PKCS #5: message M (encrypted key)",
|
||||
eb, enc_data_len - pad);
|
||||
|
||||
*data_len = enc_data_len - pad;
|
||||
return eb;
|
||||
}
|
186
components/wpa_supplicant/src/wpa2/tls/pkcs8.c
Normal file
186
components/wpa_supplicant/src/wpa2/tls/pkcs8.c
Normal file
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* PKCS #8 (Private-key information syntax)
|
||||
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/tls/asn1.h"
|
||||
#include "wpa2/tls/bignum.h"
|
||||
#include "wpa2/tls/rsa.h"
|
||||
#include "wpa2/tls/pkcs5.h"
|
||||
#include "wpa2/tls/pkcs8.h"
|
||||
|
||||
struct crypto_private_key * pkcs8_key_import(const u8 *buf, size_t len)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *pos, *end;
|
||||
struct bignum *zero;
|
||||
struct asn1_oid oid;
|
||||
char obuf[80];
|
||||
|
||||
/* PKCS #8, Chapter 6 */
|
||||
|
||||
/* PrivateKeyInfo ::= SEQUENCE */
|
||||
if (asn1_get_next(buf, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
|
||||
"header (SEQUENCE); assume PKCS #8 not used");
|
||||
return NULL;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
end = pos + hdr.length;
|
||||
|
||||
/* version Version (Version ::= INTEGER) */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Expected INTEGER - found "
|
||||
"class %d tag 0x%x; assume PKCS #8 not used",
|
||||
hdr.class, hdr.tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
zero = bignum_init();
|
||||
if (zero == NULL)
|
||||
return NULL;
|
||||
|
||||
if (bignum_set_unsigned_bin(zero, hdr.payload, hdr.length) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse INTEGER");
|
||||
bignum_deinit(zero);
|
||||
return NULL;
|
||||
}
|
||||
pos = hdr.payload + hdr.length;
|
||||
|
||||
if (bignum_cmp_d(zero, 0) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Expected zero INTEGER in the "
|
||||
"beginning of private key; not found; assume "
|
||||
"PKCS #8 not used");
|
||||
bignum_deinit(zero);
|
||||
return NULL;
|
||||
}
|
||||
bignum_deinit(zero);
|
||||
|
||||
/* privateKeyAlgorithm PrivateKeyAlgorithmIdentifier
|
||||
* (PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier) */
|
||||
if (asn1_get_next(pos, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
|
||||
"(AlgorithmIdentifier) - found class %d tag 0x%x; "
|
||||
"assume PKCS #8 not used",
|
||||
hdr.class, hdr.tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (asn1_get_oid(hdr.payload, hdr.length, &oid, &pos)) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Failed to parse OID "
|
||||
"(algorithm); assume PKCS #8 not used");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
asn1_oid_to_str(&oid, obuf, sizeof(obuf));
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: algorithm=%s", obuf);
|
||||
|
||||
if (oid.len != 7 ||
|
||||
oid.oid[0] != 1 /* iso */ ||
|
||||
oid.oid[1] != 2 /* member-body */ ||
|
||||
oid.oid[2] != 840 /* us */ ||
|
||||
oid.oid[3] != 113549 /* rsadsi */ ||
|
||||
oid.oid[4] != 1 /* pkcs */ ||
|
||||
oid.oid[5] != 1 /* pkcs-1 */ ||
|
||||
oid.oid[6] != 1 /* rsaEncryption */) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Unsupported private key "
|
||||
"algorithm %s", obuf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = hdr.payload + hdr.length;
|
||||
|
||||
/* privateKey PrivateKey (PrivateKey ::= OCTET STRING) */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_OCTETSTRING) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
|
||||
"(privateKey) - found class %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
return NULL;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Try to parse RSAPrivateKey");
|
||||
|
||||
return (struct crypto_private_key *)
|
||||
crypto_rsa_import_private_key(hdr.payload, hdr.length);
|
||||
}
|
||||
|
||||
|
||||
struct crypto_private_key *
|
||||
pkcs8_enc_key_import(const u8 *buf, size_t len, const char *passwd)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *pos, *end, *enc_alg;
|
||||
size_t enc_alg_len;
|
||||
u8 *data;
|
||||
size_t data_len;
|
||||
|
||||
if (passwd == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* PKCS #8, Chapter 7
|
||||
* EncryptedPrivateKeyInfo ::= SEQUENCE {
|
||||
* encryptionAlgorithm EncryptionAlgorithmIdentifier,
|
||||
* encryptedData EncryptedData }
|
||||
* EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
|
||||
* EncryptedData ::= OCTET STRING
|
||||
*/
|
||||
|
||||
if (asn1_get_next(buf, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Does not start with PKCS #8 "
|
||||
"header (SEQUENCE); assume encrypted PKCS #8 not "
|
||||
"used");
|
||||
return NULL;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
end = pos + hdr.length;
|
||||
|
||||
/* encryptionAlgorithm EncryptionAlgorithmIdentifier */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Expected SEQUENCE "
|
||||
"(AlgorithmIdentifier) - found class %d tag 0x%x; "
|
||||
"assume encrypted PKCS #8 not used",
|
||||
hdr.class, hdr.tag);
|
||||
return NULL;
|
||||
}
|
||||
enc_alg = hdr.payload;
|
||||
enc_alg_len = hdr.length;
|
||||
pos = hdr.payload + hdr.length;
|
||||
|
||||
/* encryptedData EncryptedData */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_OCTETSTRING) {
|
||||
wpa_printf(MSG_DEBUG, "PKCS #8: Expected OCTETSTRING "
|
||||
"(encryptedData) - found class %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data = pkcs5_decrypt(enc_alg, enc_alg_len, hdr.payload, hdr.length,
|
||||
passwd, &data_len);
|
||||
if (data) {
|
||||
struct crypto_private_key *key;
|
||||
key = pkcs8_key_import(data, data_len);
|
||||
os_free(data);
|
||||
return key;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
353
components/wpa_supplicant/src/wpa2/tls/rsa.c
Normal file
353
components/wpa_supplicant/src/wpa2/tls/rsa.c
Normal file
|
@ -0,0 +1,353 @@
|
|||
/*
|
||||
* RSA
|
||||
* Copyright (c) 2006, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/tls/asn1.h"
|
||||
#include "wpa2/tls/bignum.h"
|
||||
#include "wpa2/tls/rsa.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
||||
struct crypto_rsa_key {
|
||||
int private_key; /* whether private key is set */
|
||||
struct bignum *n; /* modulus (p * q) */
|
||||
struct bignum *e; /* public exponent */
|
||||
/* The following parameters are available only if private_key is set */
|
||||
struct bignum *d; /* private exponent */
|
||||
struct bignum *p; /* prime p (factor of n) */
|
||||
struct bignum *q; /* prime q (factor of n) */
|
||||
struct bignum *dmp1; /* d mod (p - 1); CRT exponent */
|
||||
struct bignum *dmq1; /* d mod (q - 1); CRT exponent */
|
||||
struct bignum *iqmp; /* 1 / q mod p; CRT coefficient */
|
||||
};
|
||||
|
||||
|
||||
static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
|
||||
struct bignum *num)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
|
||||
if (pos == NULL)
|
||||
return NULL;
|
||||
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL || hdr.tag != ASN1_TAG_INTEGER) {
|
||||
wpa_printf(MSG_DEBUG, "RSA: Expected INTEGER - found class %d "
|
||||
"tag 0x%x", hdr.class, hdr.tag);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bignum_set_unsigned_bin(num, hdr.payload, hdr.length) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "RSA: Failed to parse INTEGER");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return hdr.payload + hdr.length;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* crypto_rsa_import_public_key - Import an RSA public key
|
||||
* @buf: Key buffer (DER encoded RSA public key)
|
||||
* @len: Key buffer length in bytes
|
||||
* Returns: Pointer to the public key or %NULL on failure
|
||||
*/
|
||||
struct crypto_rsa_key *
|
||||
crypto_rsa_import_public_key(const u8 *buf, size_t len)
|
||||
{
|
||||
struct crypto_rsa_key *key;
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *pos, *end;
|
||||
|
||||
key = (struct crypto_rsa_key *)os_zalloc(sizeof(*key));
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
key->n = bignum_init();
|
||||
key->e = bignum_init();
|
||||
if (key->n == NULL || key->e == NULL) {
|
||||
crypto_rsa_free(key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* PKCS #1, 7.1:
|
||||
* RSAPublicKey ::= SEQUENCE {
|
||||
* modulus INTEGER, -- n
|
||||
* publicExponent INTEGER -- e
|
||||
* }
|
||||
*/
|
||||
|
||||
if (asn1_get_next(buf, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
|
||||
"(public key) - found class %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
goto error;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
end = pos + hdr.length;
|
||||
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->n);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->e);
|
||||
|
||||
if (pos == NULL)
|
||||
goto error;
|
||||
|
||||
if (pos != end) {
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"RSA: Extra data in public key SEQUENCE",
|
||||
pos, end - pos);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
error:
|
||||
crypto_rsa_free(key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* crypto_rsa_import_private_key - Import an RSA private key
|
||||
* @buf: Key buffer (DER encoded RSA private key)
|
||||
* @len: Key buffer length in bytes
|
||||
* Returns: Pointer to the private key or %NULL on failure
|
||||
*/
|
||||
struct crypto_rsa_key *
|
||||
crypto_rsa_import_private_key(const u8 *buf, size_t len)
|
||||
{
|
||||
struct crypto_rsa_key *key;
|
||||
struct bignum *zero;
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *pos, *end;
|
||||
|
||||
key = (struct crypto_rsa_key *)os_zalloc(sizeof(*key));
|
||||
if (key == NULL)
|
||||
return NULL;
|
||||
|
||||
key->private_key = 1;
|
||||
|
||||
key->n = bignum_init();
|
||||
key->e = bignum_init();
|
||||
key->d = bignum_init();
|
||||
key->p = bignum_init();
|
||||
key->q = bignum_init();
|
||||
key->dmp1 = bignum_init();
|
||||
key->dmq1 = bignum_init();
|
||||
key->iqmp = bignum_init();
|
||||
|
||||
if (key->n == NULL || key->e == NULL || key->d == NULL ||
|
||||
key->p == NULL || key->q == NULL || key->dmp1 == NULL ||
|
||||
key->dmq1 == NULL || key->iqmp == NULL) {
|
||||
crypto_rsa_free(key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* PKCS #1, 7.2:
|
||||
* RSAPrivateKey ::= SEQUENCE {
|
||||
* version Version,
|
||||
* modulus INTEGER, -- n
|
||||
* publicExponent INTEGER, -- e
|
||||
* privateExponent INTEGER, -- d
|
||||
* prime1 INTEGER, -- p
|
||||
* prime2 INTEGER, -- q
|
||||
* exponent1 INTEGER, -- d mod (p-1)
|
||||
* exponent2 INTEGER, -- d mod (q-1)
|
||||
* coefficient INTEGER -- (inverse of q) mod p
|
||||
* }
|
||||
*
|
||||
* Version ::= INTEGER -- shall be 0 for this version of the standard
|
||||
*/
|
||||
if (asn1_get_next(buf, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "RSA: Expected SEQUENCE "
|
||||
"(public key) - found class %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
goto error;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
end = pos + hdr.length;
|
||||
|
||||
zero = bignum_init();
|
||||
if (zero == NULL)
|
||||
goto error;
|
||||
pos = crypto_rsa_parse_integer(pos, end, zero);
|
||||
if (pos == NULL || bignum_cmp_d(zero, 0) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "RSA: Expected zero INTEGER in the "
|
||||
"beginning of private key; not found");
|
||||
bignum_deinit(zero);
|
||||
goto error;
|
||||
}
|
||||
bignum_deinit(zero);
|
||||
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->n);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->e);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->d);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->p);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->q);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->dmp1);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->dmq1);
|
||||
pos = crypto_rsa_parse_integer(pos, end, key->iqmp);
|
||||
|
||||
if (pos == NULL)
|
||||
goto error;
|
||||
|
||||
if (pos != end) {
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"RSA: Extra data in public key SEQUENCE",
|
||||
pos, end - pos);
|
||||
goto error;
|
||||
}
|
||||
|
||||
return key;
|
||||
|
||||
error:
|
||||
crypto_rsa_free(key);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* crypto_rsa_get_modulus_len - Get the modulus length of the RSA key
|
||||
* @key: RSA key
|
||||
* Returns: Modulus length of the key
|
||||
*/
|
||||
size_t crypto_rsa_get_modulus_len(struct crypto_rsa_key *key)
|
||||
{
|
||||
return bignum_get_unsigned_bin_len(key->n);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* crypto_rsa_exptmod - RSA modular exponentiation
|
||||
* @in: Input data
|
||||
* @inlen: Input data length
|
||||
* @out: Buffer for output data
|
||||
* @outlen: Maximum size of the output buffer and used size on success
|
||||
* @key: RSA key
|
||||
* @use_private: 1 = Use RSA private key, 0 = Use RSA public key
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int crypto_rsa_exptmod(const u8 *in, size_t inlen, u8 *out, size_t *outlen,
|
||||
struct crypto_rsa_key *key, int use_private)
|
||||
{
|
||||
struct bignum *tmp, *a = NULL, *b = NULL;
|
||||
int ret = -1;
|
||||
size_t modlen;
|
||||
|
||||
if (use_private && !key->private_key)
|
||||
return -1;
|
||||
|
||||
tmp = bignum_init();
|
||||
if (tmp == NULL)
|
||||
return -1;
|
||||
|
||||
if (bignum_set_unsigned_bin(tmp, in, inlen) < 0)
|
||||
goto error;
|
||||
if (bignum_cmp(key->n, tmp) < 0) {
|
||||
/* Too large input value for the RSA key modulus */
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (use_private) {
|
||||
/*
|
||||
* Decrypt (or sign) using Chinese remainer theorem to speed
|
||||
* up calculation. This is equivalent to tmp = tmp^d mod n
|
||||
* (which would require more CPU to calculate directly).
|
||||
*
|
||||
* dmp1 = (1/e) mod (p-1)
|
||||
* dmq1 = (1/e) mod (q-1)
|
||||
* iqmp = (1/q) mod p, where p > q
|
||||
* m1 = c^dmp1 mod p
|
||||
* m2 = c^dmq1 mod q
|
||||
* h = q^-1 (m1 - m2) mod p
|
||||
* m = m2 + hq
|
||||
*/
|
||||
a = bignum_init();
|
||||
b = bignum_init();
|
||||
if (a == NULL || b == NULL)
|
||||
goto error;
|
||||
|
||||
/* a = tmp^dmp1 mod p */
|
||||
if (bignum_exptmod(tmp, key->dmp1, key->p, a) < 0)
|
||||
goto error;
|
||||
|
||||
/* b = tmp^dmq1 mod q */
|
||||
if (bignum_exptmod(tmp, key->dmq1, key->q, b) < 0)
|
||||
goto error;
|
||||
|
||||
/* tmp = (a - b) * (1/q mod p) (mod p) */
|
||||
if (bignum_sub(a, b, tmp) < 0 ||
|
||||
bignum_mulmod(tmp, key->iqmp, key->p, tmp) < 0)
|
||||
goto error;
|
||||
|
||||
/* tmp = b + q * tmp */
|
||||
if (bignum_mul(tmp, key->q, tmp) < 0 ||
|
||||
bignum_add(tmp, b, tmp) < 0)
|
||||
goto error;
|
||||
} else {
|
||||
/* Encrypt (or verify signature) */
|
||||
/* tmp = tmp^e mod N */
|
||||
if (bignum_exptmod(tmp, key->e, key->n, tmp) < 0)
|
||||
goto error;
|
||||
}
|
||||
|
||||
modlen = crypto_rsa_get_modulus_len(key);
|
||||
if (modlen > *outlen) {
|
||||
*outlen = modlen;
|
||||
goto error;
|
||||
}
|
||||
|
||||
if (bignum_get_unsigned_bin_len(tmp) > modlen)
|
||||
goto error; /* should never happen */
|
||||
|
||||
*outlen = modlen;
|
||||
os_memset(out, 0, modlen);
|
||||
if (bignum_get_unsigned_bin(
|
||||
tmp, out +
|
||||
(modlen - bignum_get_unsigned_bin_len(tmp)), NULL) < 0)
|
||||
goto error;
|
||||
|
||||
ret = 0;
|
||||
|
||||
error:
|
||||
|
||||
bignum_deinit(tmp);
|
||||
bignum_deinit(a);
|
||||
bignum_deinit(b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* crypto_rsa_free - Free RSA key
|
||||
* @key: RSA key to be freed
|
||||
*
|
||||
* This function frees an RSA key imported with either
|
||||
* crypto_rsa_import_public_key() or crypto_rsa_import_private_key().
|
||||
*/
|
||||
void crypto_rsa_free(struct crypto_rsa_key *key)
|
||||
{
|
||||
if (key) {
|
||||
bignum_deinit(key->n);
|
||||
bignum_deinit(key->e);
|
||||
bignum_deinit(key->d);
|
||||
bignum_deinit(key->p);
|
||||
bignum_deinit(key->q);
|
||||
bignum_deinit(key->dmp1);
|
||||
bignum_deinit(key->dmq1);
|
||||
bignum_deinit(key->iqmp);
|
||||
os_free(key);
|
||||
}
|
||||
}
|
716
components/wpa_supplicant/src/wpa2/tls/tls_internal.c
Normal file
716
components/wpa_supplicant/src/wpa2/tls/tls_internal.c
Normal file
|
@ -0,0 +1,716 @@
|
|||
/*
|
||||
* TLS interface functions and an internal TLS implementation
|
||||
* Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*
|
||||
* This file interface functions for hostapd/wpa_supplicant to use the
|
||||
* integrated TLSv1 implementation.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/tls/tlsv1_client.h"
|
||||
#include "wpa2/tls/tlsv1_server.h"
|
||||
|
||||
#ifndef CONFIG_TLS_INTERNAL_CLIENT
|
||||
#define CONFIG_TLS_INTERNAL_CLIENT
|
||||
#endif
|
||||
|
||||
static int tls_ref_count = 0;
|
||||
|
||||
struct tls_global {
|
||||
int server;
|
||||
struct tlsv1_credentials *server_cred;
|
||||
int check_crl;
|
||||
};
|
||||
|
||||
struct tls_connection {
|
||||
struct tlsv1_client *client;
|
||||
struct tlsv1_server *server;
|
||||
};
|
||||
|
||||
|
||||
void * tls_init(void)
|
||||
{
|
||||
struct tls_global *global;
|
||||
|
||||
if (tls_ref_count == 0) {
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (tlsv1_client_global_init())
|
||||
return NULL;
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (tlsv1_server_global_init())
|
||||
return NULL;
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
}
|
||||
tls_ref_count++;
|
||||
|
||||
global = (struct tls_global *)os_zalloc(sizeof(*global));
|
||||
if (global == NULL)
|
||||
return NULL;
|
||||
|
||||
return global;
|
||||
}
|
||||
|
||||
void tls_deinit(void *ssl_ctx)
|
||||
{
|
||||
struct tls_global *global = ssl_ctx;
|
||||
tls_ref_count--;
|
||||
if (tls_ref_count == 0) {
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
tlsv1_client_global_deinit();
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
tlsv1_cred_free(global->server_cred);
|
||||
tlsv1_server_global_deinit();
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
}
|
||||
os_free(global);
|
||||
}
|
||||
|
||||
|
||||
int tls_get_errors(void *tls_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct tls_connection * tls_connection_init(void *tls_ctx)
|
||||
{
|
||||
struct tls_connection *conn;
|
||||
struct tls_global *global = tls_ctx;
|
||||
|
||||
conn = (struct tls_connection *)os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (!global->server) {
|
||||
conn->client = tlsv1_client_init();
|
||||
if (conn->client == NULL) {
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (global->server) {
|
||||
conn->server = tlsv1_server_init(global->server_cred);
|
||||
if (conn->server == NULL) {
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
if (conn == NULL)
|
||||
return;
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
tlsv1_client_deinit(conn->client);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
tlsv1_server_deinit(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
os_free(conn);
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
return tlsv1_client_established(conn->client);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_established(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
return tlsv1_client_shutdown(conn->client);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_shutdown(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
|
||||
const struct tls_connection_params *params)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
struct tlsv1_credentials *cred;
|
||||
|
||||
if (conn->client == NULL)
|
||||
return -1;
|
||||
|
||||
cred = tlsv1_cred_alloc();
|
||||
if (cred == NULL)
|
||||
return -1;
|
||||
|
||||
if (tlsv1_set_ca_cert(cred, params->ca_cert,
|
||||
params->ca_cert_blob, params->ca_cert_blob_len,
|
||||
params->ca_path)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
|
||||
"certificates");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_set_cert(cred, params->client_cert,
|
||||
params->client_cert_blob,
|
||||
params->client_cert_blob_len)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to configure client "
|
||||
"certificate");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_set_private_key(cred, params->private_key,
|
||||
params->private_key_passwd,
|
||||
params->private_key_blob,
|
||||
params->private_key_blob_len)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_client_set_cred(conn->client, cred) < 0) {
|
||||
tlsv1_cred_free(cred);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlsv1_client_set_time_checks(
|
||||
conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
|
||||
//conn->client, !(TLS_CONN_DISABLE_TIME_CHECKS)); //snake
|
||||
|
||||
return 0;
|
||||
#else /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
return -1;
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_params(void *tls_ctx,
|
||||
const struct tls_connection_params *params)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
struct tls_global *global = tls_ctx;
|
||||
struct tlsv1_credentials *cred;
|
||||
|
||||
/* Currently, global parameters are only set when running in server
|
||||
* mode. */
|
||||
global->server = 1;
|
||||
tlsv1_cred_free(global->server_cred);
|
||||
global->server_cred = cred = tlsv1_cred_alloc();
|
||||
if (cred == NULL)
|
||||
return -1;
|
||||
|
||||
if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
|
||||
params->ca_cert_blob_len, params->ca_path)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
|
||||
"certificates");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
|
||||
params->client_cert_blob_len)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to configure server "
|
||||
"certificate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_set_private_key(cred, params->private_key,
|
||||
params->private_key_passwd,
|
||||
params->private_key_blob,
|
||||
params->private_key_blob_len)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to load private key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
|
||||
params->dh_blob_len)) {
|
||||
wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
#else /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
}
|
||||
|
||||
|
||||
int tls_global_set_verify(void *tls_ctx, int check_crl)
|
||||
{
|
||||
struct tls_global *global = tls_ctx;
|
||||
global->check_crl = check_crl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
|
||||
int verify_peer)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_set_verify(conn->server, verify_peer);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
|
||||
struct tls_keys *keys)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
return tlsv1_client_get_keys(conn->client, keys);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_get_keys(conn->server, keys);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
|
||||
const char *label, int server_random_first,
|
||||
u8 *out, size_t out_len)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client) {
|
||||
return tlsv1_client_prf(conn->client, label,
|
||||
server_random_first,
|
||||
out, out_len);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server) {
|
||||
return tlsv1_server_prf(conn->server, label,
|
||||
server_random_first,
|
||||
out, out_len);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_handshake(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
struct wpabuf **appl_data)
|
||||
{
|
||||
return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_handshake2(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
struct wpabuf **appl_data,
|
||||
int *need_more_data)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
u8 *res, *ad;
|
||||
size_t res_len, ad_len;
|
||||
struct wpabuf *out;
|
||||
|
||||
if (conn->client == NULL)
|
||||
return NULL;
|
||||
|
||||
ad = NULL;
|
||||
res = tlsv1_client_handshake(conn->client,
|
||||
in_data ? wpabuf_head(in_data) : NULL,
|
||||
in_data ? wpabuf_len(in_data) : 0,
|
||||
&res_len, &ad, &ad_len, need_more_data);
|
||||
if (res == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
out = wpabuf_alloc_ext_data(res, res_len);
|
||||
if (out == NULL) {
|
||||
os_free(res);
|
||||
os_free(ad);
|
||||
return NULL;
|
||||
}
|
||||
if (appl_data) {
|
||||
if (ad) {
|
||||
*appl_data = wpabuf_alloc_ext_data(ad, ad_len);
|
||||
if (*appl_data == NULL)
|
||||
os_free(ad);
|
||||
} else
|
||||
*appl_data = NULL;
|
||||
} else
|
||||
os_free(ad);
|
||||
|
||||
return out;
|
||||
#else /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
return NULL;
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
struct wpabuf **appl_data)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
u8 *res;
|
||||
size_t res_len;
|
||||
struct wpabuf *out;
|
||||
|
||||
if (conn->server == NULL)
|
||||
return NULL;
|
||||
|
||||
if (appl_data)
|
||||
*appl_data = NULL;
|
||||
|
||||
res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data),
|
||||
wpabuf_len(in_data), &res_len);
|
||||
if (res == NULL && tlsv1_server_established(conn->server))
|
||||
return wpabuf_alloc(0);
|
||||
if (res == NULL)
|
||||
return NULL;
|
||||
out = wpabuf_alloc_ext_data(res, res_len);
|
||||
if (out == NULL) {
|
||||
os_free(res);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return out;
|
||||
#else /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return NULL;
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_encrypt(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client) {
|
||||
struct wpabuf *buf;
|
||||
int res;
|
||||
buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data),
|
||||
wpabuf_len(in_data),
|
||||
wpabuf_mhead(buf),
|
||||
wpabuf_size(buf));
|
||||
if (res < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put(buf, res);
|
||||
return buf;
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server) {
|
||||
struct wpabuf *buf;
|
||||
int res;
|
||||
buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data),
|
||||
wpabuf_len(in_data),
|
||||
wpabuf_mhead(buf),
|
||||
wpabuf_size(buf));
|
||||
if (res < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put(buf, res);
|
||||
return buf;
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_decrypt(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data)
|
||||
{
|
||||
return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
const struct wpabuf *in_data,
|
||||
int *need_more_data)
|
||||
{
|
||||
if (need_more_data)
|
||||
*need_more_data = 0;
|
||||
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client) {
|
||||
return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
|
||||
wpabuf_len(in_data),
|
||||
need_more_data);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server) {
|
||||
struct wpabuf *buf;
|
||||
int res;
|
||||
buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data),
|
||||
wpabuf_len(in_data),
|
||||
wpabuf_mhead(buf),
|
||||
wpabuf_size(buf));
|
||||
if (res < 0) {
|
||||
wpabuf_free(buf);
|
||||
return NULL;
|
||||
}
|
||||
wpabuf_put(buf, res);
|
||||
return buf;
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
return tlsv1_client_resumed(conn->client);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_resumed(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
|
||||
u8 *ciphers)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
return tlsv1_client_set_cipher_list(conn->client, ciphers);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_set_cipher_list(conn->server, ciphers);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
|
||||
char *buf, size_t buflen)
|
||||
{
|
||||
if (conn == NULL)
|
||||
return -1;
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
return tlsv1_client_get_cipher(conn->client, buf, buflen);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_get_cipher(conn->server, buf, buflen);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_enable_workaround(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
|
||||
int ext_type, const u8 *data,
|
||||
size_t data_len)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client) {
|
||||
return tlsv1_client_hello_ext(conn->client, ext_type,
|
||||
data, data_len);
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_write_alerts(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_get_keyblock_size(void *tls_ctx,
|
||||
struct tls_connection *conn)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client)
|
||||
return tlsv1_client_get_keyblock_size(conn->client);
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server)
|
||||
return tlsv1_server_get_keyblock_size(conn->server);
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
unsigned int tls_capabilities(void *tls_ctx)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_connection_set_session_ticket_cb(void *tls_ctx,
|
||||
struct tls_connection *conn,
|
||||
tls_session_ticket_cb cb,
|
||||
void *ctx)
|
||||
{
|
||||
#ifdef CONFIG_TLS_INTERNAL_CLIENT
|
||||
if (conn->client) {
|
||||
tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_CLIENT */
|
||||
#ifdef CONFIG_TLS_INTERNAL_SERVER
|
||||
if (conn->server) {
|
||||
tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TLS_INTERNAL_SERVER */
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
|
||||
* @secret: Key for PRF
|
||||
* @secret_len: Length of the key in bytes
|
||||
* @label: A unique label for each purpose of the PRF
|
||||
* @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 TLS. This PRF is defined in RFC 2246, Chapter 5.
|
||||
*/
|
||||
int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
|
||||
{
|
||||
size_t L_S1, L_S2, i;
|
||||
const u8 *S1, *S2;
|
||||
u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
|
||||
u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
|
||||
int MD5_pos, SHA1_pos;
|
||||
const u8 *MD5_addr[3];
|
||||
size_t MD5_len[3];
|
||||
const unsigned char *SHA1_addr[3];
|
||||
size_t SHA1_len[3];
|
||||
|
||||
if (secret_len & 1)
|
||||
return -1;
|
||||
|
||||
MD5_addr[0] = A_MD5;
|
||||
MD5_len[0] = MD5_MAC_LEN;
|
||||
MD5_addr[1] = (unsigned char *) label;
|
||||
MD5_len[1] = os_strlen(label);
|
||||
MD5_addr[2] = seed;
|
||||
MD5_len[2] = seed_len;
|
||||
|
||||
SHA1_addr[0] = A_SHA1;
|
||||
SHA1_len[0] = SHA1_MAC_LEN;
|
||||
SHA1_addr[1] = (unsigned char *) label;
|
||||
SHA1_len[1] = os_strlen(label);
|
||||
SHA1_addr[2] = seed;
|
||||
SHA1_len[2] = seed_len;
|
||||
|
||||
/* RFC 2246, Chapter 5
|
||||
* A(0) = seed, A(i) = HMAC(secret, A(i-1))
|
||||
* P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
|
||||
* PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
|
||||
*/
|
||||
|
||||
L_S1 = L_S2 = (secret_len + 1) / 2;
|
||||
S1 = secret;
|
||||
S2 = secret + L_S1;
|
||||
if (secret_len & 1) {
|
||||
/* The last byte of S1 will be shared with S2 */
|
||||
S2--;
|
||||
}
|
||||
|
||||
hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
|
||||
hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
|
||||
|
||||
MD5_pos = MD5_MAC_LEN;
|
||||
SHA1_pos = SHA1_MAC_LEN;
|
||||
for (i = 0; i < outlen; i++) {
|
||||
if (MD5_pos == MD5_MAC_LEN) {
|
||||
hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
|
||||
MD5_pos = 0;
|
||||
hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
|
||||
}
|
||||
if (SHA1_pos == SHA1_MAC_LEN) {
|
||||
hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
|
||||
P_SHA1);
|
||||
SHA1_pos = 0;
|
||||
hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
|
||||
}
|
||||
|
||||
out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
|
||||
|
||||
MD5_pos++;
|
||||
SHA1_pos++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
837
components/wpa_supplicant/src/wpa2/tls/tlsv1_client.c
Normal file
837
components/wpa_supplicant/src/wpa2/tls/tlsv1_client.c
Normal file
|
@ -0,0 +1,837 @@
|
|||
/*
|
||||
* TLS v1.0/v1.1/v1.2 client (RFC 2246, RFC 4346, RFC 5246)
|
||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/tls/tlsv1_common.h"
|
||||
#include "wpa2/tls/tlsv1_record.h"
|
||||
#include "wpa2/tls/tlsv1_client.h"
|
||||
#include "wpa2/tls/tlsv1_client_i.h"
|
||||
|
||||
/* TODO:
|
||||
* Support for a message fragmented across several records (RFC 2246, 6.2.1)
|
||||
*/
|
||||
|
||||
|
||||
void tls_alert(struct tlsv1_client *conn, u8 level, u8 description)
|
||||
{
|
||||
conn->alert_level = level;
|
||||
conn->alert_description = description;
|
||||
}
|
||||
|
||||
|
||||
void tlsv1_client_free_dh(struct tlsv1_client *conn)
|
||||
{
|
||||
os_free(conn->dh_p);
|
||||
os_free(conn->dh_g);
|
||||
os_free(conn->dh_ys);
|
||||
conn->dh_p = conn->dh_g = conn->dh_ys = NULL;
|
||||
}
|
||||
|
||||
|
||||
int tls_derive_pre_master_secret(u8 *pre_master_secret)
|
||||
{
|
||||
WPA_PUT_BE16(pre_master_secret, TLS_VERSION);
|
||||
if (os_get_random(pre_master_secret + 2,
|
||||
TLS_PRE_MASTER_SECRET_LEN - 2))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_derive_keys(struct tlsv1_client *conn,
|
||||
const u8 *pre_master_secret, size_t pre_master_secret_len)
|
||||
{
|
||||
u8 seed[2 * TLS_RANDOM_LEN];
|
||||
u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
|
||||
u8 *pos;
|
||||
size_t key_block_len;
|
||||
|
||||
if (pre_master_secret) {
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
|
||||
pre_master_secret, pre_master_secret_len);
|
||||
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
|
||||
TLS_RANDOM_LEN);
|
||||
if (tls_prf(conn->rl.tls_version,
|
||||
pre_master_secret, pre_master_secret_len,
|
||||
"master secret", seed, 2 * TLS_RANDOM_LEN,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
|
||||
"master_secret");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN);
|
||||
}
|
||||
|
||||
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
|
||||
key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len);
|
||||
if (conn->rl.tls_version == TLS_VERSION_1)
|
||||
key_block_len += 2 * conn->rl.iv_size;
|
||||
if (tls_prf(conn->rl.tls_version,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN,
|
||||
"key expansion", seed, 2 * TLS_RANDOM_LEN,
|
||||
key_block, key_block_len)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
|
||||
key_block, key_block_len);
|
||||
|
||||
pos = key_block;
|
||||
|
||||
/* client_write_MAC_secret */
|
||||
os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
|
||||
pos += conn->rl.hash_size;
|
||||
/* server_write_MAC_secret */
|
||||
os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
|
||||
pos += conn->rl.hash_size;
|
||||
|
||||
/* client_write_key */
|
||||
os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
|
||||
pos += conn->rl.key_material_len;
|
||||
/* server_write_key */
|
||||
os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
|
||||
pos += conn->rl.key_material_len;
|
||||
|
||||
if (conn->rl.tls_version == TLS_VERSION_1) {
|
||||
/* client_write_IV */
|
||||
os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
|
||||
pos += conn->rl.iv_size;
|
||||
/* server_write_IV */
|
||||
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
|
||||
pos += conn->rl.iv_size;
|
||||
} else {
|
||||
/*
|
||||
* Use IV field to set the mask value for TLS v1.1. A fixed
|
||||
* mask of zero is used per the RFC 4346, 6.2.3.2 CBC Block
|
||||
* Cipher option 2a.
|
||||
*/
|
||||
os_memset(conn->rl.write_iv, 0, conn->rl.iv_size);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_handshake - Process TLS handshake
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @in_data: Input data from TLS peer
|
||||
* @in_len: Input data length
|
||||
* @out_len: Length of the output buffer.
|
||||
* @appl_data: Pointer to application data pointer, or %NULL if dropped
|
||||
* @appl_data_len: Pointer to variable that is set to appl_data length
|
||||
* @need_more_data: Set to 1 if more data would be needed to complete
|
||||
* processing
|
||||
* Returns: Pointer to output data, %NULL on failure
|
||||
*/
|
||||
u8 * tlsv1_client_handshake(struct tlsv1_client *conn,
|
||||
const u8 *in_data, size_t in_len,
|
||||
size_t *out_len, u8 **appl_data,
|
||||
size_t *appl_data_len, int *need_more_data)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u8 *msg = NULL, *in_msg = NULL, *in_pos, *in_end, alert, ct;
|
||||
size_t in_msg_len;
|
||||
int no_appl_data;
|
||||
int used;
|
||||
|
||||
if (need_more_data)
|
||||
*need_more_data = 0;
|
||||
|
||||
if (conn->state == CLIENT_HELLO) {
|
||||
if (in_len)
|
||||
return NULL;
|
||||
return tls_send_client_hello(conn, out_len);
|
||||
}
|
||||
|
||||
if (conn->partial_input) {
|
||||
if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
|
||||
"memory for pending record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
goto failed;
|
||||
}
|
||||
wpabuf_put_data(conn->partial_input, in_data, in_len);
|
||||
in_data = wpabuf_head(conn->partial_input);
|
||||
in_len = wpabuf_len(conn->partial_input);
|
||||
}
|
||||
|
||||
if (in_data == NULL || in_len == 0)
|
||||
return NULL;
|
||||
|
||||
pos = in_data;
|
||||
end = in_data + in_len;
|
||||
in_msg = os_malloc(in_len);
|
||||
if (in_msg == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Each received packet may include multiple records */
|
||||
while (pos < end) {
|
||||
in_msg_len = in_len;
|
||||
used = tlsv1_record_receive(&conn->rl, pos, end - pos,
|
||||
in_msg, &in_msg_len, &alert);
|
||||
if (used < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
|
||||
"record failed");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
|
||||
goto failed;
|
||||
}
|
||||
if (used == 0) {
|
||||
struct wpabuf *partial;
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
|
||||
partial = wpabuf_alloc_copy(pos, end - pos);
|
||||
wpabuf_free(conn->partial_input);
|
||||
conn->partial_input = partial;
|
||||
if (conn->partial_input == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
|
||||
"allocate memory for pending "
|
||||
"record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
goto failed;
|
||||
}
|
||||
os_free(in_msg);
|
||||
if (need_more_data)
|
||||
*need_more_data = 1;
|
||||
return NULL;
|
||||
}
|
||||
ct = pos[0];
|
||||
|
||||
in_pos = in_msg;
|
||||
in_end = in_msg + in_msg_len;
|
||||
|
||||
/* Each received record may include multiple messages of the
|
||||
* same ContentType. */
|
||||
while (in_pos < in_end) {
|
||||
in_msg_len = in_end - in_pos;
|
||||
if (tlsv1_client_process_handshake(conn, ct, in_pos,
|
||||
&in_msg_len,
|
||||
appl_data,
|
||||
appl_data_len) < 0)
|
||||
goto failed;
|
||||
in_pos += in_msg_len;
|
||||
}
|
||||
|
||||
pos += used;
|
||||
}
|
||||
|
||||
os_free(in_msg);
|
||||
in_msg = NULL;
|
||||
|
||||
no_appl_data = appl_data == NULL || *appl_data == NULL;
|
||||
msg = tlsv1_client_handshake_write(conn, out_len, no_appl_data);
|
||||
|
||||
failed:
|
||||
os_free(in_msg);
|
||||
if (conn->alert_level) {
|
||||
wpabuf_free(conn->partial_input);
|
||||
conn->partial_input = NULL;
|
||||
conn->state = FAILED;
|
||||
os_free(msg);
|
||||
msg = tlsv1_client_send_alert(conn, conn->alert_level,
|
||||
conn->alert_description,
|
||||
out_len);
|
||||
} else if (msg == NULL) {
|
||||
msg = (u8 *)os_zalloc(1);
|
||||
*out_len = 0;
|
||||
}
|
||||
|
||||
if (need_more_data == NULL || !(*need_more_data)) {
|
||||
wpabuf_free(conn->partial_input);
|
||||
conn->partial_input = NULL;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_encrypt - Encrypt data into TLS tunnel
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @in_data: Pointer to plaintext data to be encrypted
|
||||
* @in_len: Input buffer length
|
||||
* @out_data: Pointer to output buffer (encrypted TLS data)
|
||||
* @out_len: Maximum out_data length
|
||||
* Returns: Number of bytes written to out_data, -1 on failure
|
||||
*
|
||||
* This function is used after TLS handshake has been completed successfully to
|
||||
* send data in the encrypted tunnel.
|
||||
*/
|
||||
int tlsv1_client_encrypt(struct tlsv1_client *conn,
|
||||
const u8 *in_data, size_t in_len,
|
||||
u8 *out_data, size_t out_len)
|
||||
{
|
||||
size_t rlen;
|
||||
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
|
||||
in_data, in_len);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
|
||||
out_data, out_len, in_data, in_len, &rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_decrypt - Decrypt data from TLS tunnel
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @in_data: Pointer to input buffer (encrypted TLS data)
|
||||
* @in_len: Input buffer length
|
||||
* @need_more_data: Set to 1 if more data would be needed to complete
|
||||
* processing
|
||||
* Returns: Decrypted data or %NULL on failure
|
||||
*
|
||||
* This function is used after TLS handshake has been completed successfully to
|
||||
* receive data from the encrypted tunnel.
|
||||
*/
|
||||
struct wpabuf * tlsv1_client_decrypt(struct tlsv1_client *conn,
|
||||
const u8 *in_data, size_t in_len,
|
||||
int *need_more_data)
|
||||
{
|
||||
const u8 *in_end, *pos;
|
||||
int used;
|
||||
u8 alert, *out_pos, ct;
|
||||
size_t olen;
|
||||
struct wpabuf *buf = NULL;
|
||||
|
||||
if (need_more_data)
|
||||
*need_more_data = 0;
|
||||
|
||||
if (conn->partial_input) {
|
||||
if (wpabuf_resize(&conn->partial_input, in_len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
|
||||
"memory for pending record");
|
||||
alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
wpabuf_put_data(conn->partial_input, in_data, in_len);
|
||||
in_data = wpabuf_head(conn->partial_input);
|
||||
in_len = wpabuf_len(conn->partial_input);
|
||||
}
|
||||
|
||||
pos = in_data;
|
||||
in_end = in_data + in_len;
|
||||
|
||||
while (pos < in_end) {
|
||||
ct = pos[0];
|
||||
if (wpabuf_resize(&buf, in_end - pos) < 0) {
|
||||
alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
out_pos = wpabuf_put(buf, 0);
|
||||
olen = wpabuf_tailroom(buf);
|
||||
used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
|
||||
out_pos, &olen, &alert);
|
||||
if (used < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
|
||||
"failed");
|
||||
goto fail;
|
||||
}
|
||||
if (used == 0) {
|
||||
struct wpabuf *partial;
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Need more data");
|
||||
partial = wpabuf_alloc_copy(pos, in_end - pos);
|
||||
wpabuf_free(conn->partial_input);
|
||||
conn->partial_input = partial;
|
||||
if (conn->partial_input == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
|
||||
"allocate memory for pending "
|
||||
"record");
|
||||
alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
if (need_more_data)
|
||||
*need_more_data = 1;
|
||||
return buf;
|
||||
}
|
||||
|
||||
if (ct == TLS_CONTENT_TYPE_ALERT) {
|
||||
if (olen < 2) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Alert "
|
||||
"underflow");
|
||||
alert = TLS_ALERT_DECODE_ERROR;
|
||||
goto fail;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
|
||||
out_pos[0], out_pos[1]);
|
||||
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
|
||||
/* Continue processing */
|
||||
pos += used;
|
||||
continue;
|
||||
}
|
||||
|
||||
alert = out_pos[1];
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
|
||||
"0x%x when decrypting application data",
|
||||
pos[0]);
|
||||
alert = TLS_ALERT_UNEXPECTED_MESSAGE;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
wpabuf_put(buf, olen);
|
||||
|
||||
pos += used;
|
||||
}
|
||||
|
||||
wpabuf_free(conn->partial_input);
|
||||
conn->partial_input = NULL;
|
||||
return buf;
|
||||
|
||||
fail:
|
||||
wpabuf_free(buf);
|
||||
wpabuf_free(conn->partial_input);
|
||||
conn->partial_input = NULL;
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_global_init - Initialize TLSv1 client
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function must be called before using any other TLSv1 client functions.
|
||||
*/
|
||||
int tlsv1_client_global_init(void)
|
||||
{
|
||||
return crypto_global_init();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_global_deinit - Deinitialize TLSv1 client
|
||||
*
|
||||
* This function can be used to deinitialize the TLSv1 client that was
|
||||
* initialized by calling tlsv1_client_global_init(). No TLSv1 client functions
|
||||
* can be called after this before calling tlsv1_client_global_init() again.
|
||||
*/
|
||||
void tlsv1_client_global_deinit(void)
|
||||
{
|
||||
crypto_global_deinit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_init - Initialize TLSv1 client connection
|
||||
* Returns: Pointer to TLSv1 client connection data or %NULL on failure
|
||||
*/
|
||||
struct tlsv1_client * tlsv1_client_init(void)
|
||||
{
|
||||
struct tlsv1_client *conn;
|
||||
size_t count;
|
||||
u16 *suites;
|
||||
|
||||
conn = (struct tlsv1_client *)os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
|
||||
conn->state = CLIENT_HELLO;
|
||||
|
||||
if (tls_verify_hash_init(&conn->verify) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
|
||||
"hash");
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
suites = conn->cipher_suites;
|
||||
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA256;
|
||||
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA256;
|
||||
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
|
||||
conn->num_cipher_suites = count;
|
||||
|
||||
conn->rl.tls_version = TLS_VERSION;
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_deinit - Deinitialize TLSv1 client connection
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
*/
|
||||
void tlsv1_client_deinit(struct tlsv1_client *conn)
|
||||
{
|
||||
crypto_public_key_free(conn->server_rsa_key);
|
||||
tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
|
||||
tlsv1_record_change_write_cipher(&conn->rl);
|
||||
tlsv1_record_change_read_cipher(&conn->rl);
|
||||
tls_verify_hash_free(&conn->verify);
|
||||
os_free(conn->client_hello_ext);
|
||||
tlsv1_client_free_dh(conn);
|
||||
tlsv1_cred_free(conn->cred);
|
||||
wpabuf_free(conn->partial_input);
|
||||
os_free(conn);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_established - Check whether connection has been established
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* Returns: 1 if connection is established, 0 if not
|
||||
*/
|
||||
int tlsv1_client_established(struct tlsv1_client *conn)
|
||||
{
|
||||
return conn->state == ESTABLISHED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_prf - Use TLS-PRF to derive keying material
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @label: Label (e.g., description of the key) for PRF
|
||||
* @server_random_first: seed is 0 = client_random|server_random,
|
||||
* 1 = server_random|client_random
|
||||
* @out: Buffer for output data from TLS-PRF
|
||||
* @out_len: Length of the output buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_client_prf(struct tlsv1_client *conn, const char *label,
|
||||
int server_random_first, u8 *out, size_t out_len)
|
||||
{
|
||||
u8 seed[2 * TLS_RANDOM_LEN];
|
||||
|
||||
if (conn->state != ESTABLISHED)
|
||||
return -1;
|
||||
|
||||
if (server_random_first) {
|
||||
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
|
||||
TLS_RANDOM_LEN);
|
||||
} else {
|
||||
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
|
||||
TLS_RANDOM_LEN);
|
||||
}
|
||||
|
||||
return tls_prf(conn->rl.tls_version,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN,
|
||||
label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_get_cipher - Get current cipher name
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @buf: Buffer for the cipher name
|
||||
* @buflen: buf size
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Get the name of the currently used cipher.
|
||||
*/
|
||||
int tlsv1_client_get_cipher(struct tlsv1_client *conn, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
#ifndef ESPRESSIF_USE
|
||||
char *cipher;
|
||||
|
||||
switch (conn->rl.cipher_suite) {
|
||||
case TLS_RSA_WITH_RC4_128_MD5:
|
||||
cipher = "RC4-MD5";
|
||||
break;
|
||||
case TLS_RSA_WITH_RC4_128_SHA:
|
||||
cipher = "RC4-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_DES_CBC_SHA:
|
||||
cipher = "DES-CBC-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
cipher = "DES-CBC3-SHA";
|
||||
break;
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
|
||||
cipher = "ADH-AES-128-SHA256";
|
||||
break;
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
|
||||
cipher = "ADH-AES-128-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||
cipher = "AES-256-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA256:
|
||||
cipher = "AES-256-SHA256";
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA:
|
||||
cipher = "AES-128-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA256:
|
||||
cipher = "AES-128-SHA256";
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
char cipher[20];
|
||||
|
||||
switch (conn->rl.cipher_suite) {
|
||||
case TLS_RSA_WITH_RC4_128_MD5:
|
||||
strcpy(cipher, "RC4-MD5");
|
||||
break;
|
||||
case TLS_RSA_WITH_RC4_128_SHA:
|
||||
strcpy(cipher, "RC4-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_DES_CBC_SHA:
|
||||
strcpy(cipher, "DES-CBC-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
strcpy(cipher, "DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
|
||||
strcpy(cipher, "ADH-AES-128-SHA256");
|
||||
break;
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
|
||||
strcpy(cipher, "ADH-AES-128-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||
strcpy(cipher, "AES-256-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA256:
|
||||
strcpy(cipher, "AES-256-SHA256");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA:
|
||||
strcpy(cipher, "AES-128-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA256:
|
||||
strcpy(cipher, "AES-128-SHA256");
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_shutdown - Shutdown TLS connection
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_client_shutdown(struct tlsv1_client *conn)
|
||||
{
|
||||
conn->state = CLIENT_HELLO;
|
||||
|
||||
if (tls_verify_hash_init(&conn->verify) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
|
||||
"hash");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
|
||||
tlsv1_record_change_write_cipher(&conn->rl);
|
||||
tlsv1_record_change_read_cipher(&conn->rl);
|
||||
|
||||
conn->certificate_requested = 0;
|
||||
crypto_public_key_free(conn->server_rsa_key);
|
||||
conn->server_rsa_key = NULL;
|
||||
conn->session_resumed = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_resumed - Was session resumption used
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* Returns: 1 if current session used session resumption, 0 if not
|
||||
*/
|
||||
int tlsv1_client_resumed(struct tlsv1_client *conn)
|
||||
{
|
||||
return !!conn->session_resumed;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_hello_ext - Set TLS extension for ClientHello
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @ext_type: Extension type
|
||||
* @data: Extension payload (%NULL to remove extension)
|
||||
* @data_len: Extension payload length
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_client_hello_ext(struct tlsv1_client *conn, int ext_type,
|
||||
const u8 *data, size_t data_len)
|
||||
{
|
||||
u8 *pos;
|
||||
|
||||
conn->session_ticket_included = 0;
|
||||
os_free(conn->client_hello_ext);
|
||||
conn->client_hello_ext = NULL;
|
||||
conn->client_hello_ext_len = 0;
|
||||
|
||||
if (data == NULL || data_len == 0)
|
||||
return 0;
|
||||
|
||||
pos = conn->client_hello_ext = os_malloc(6 + data_len);
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
|
||||
WPA_PUT_BE16(pos, 4 + data_len);
|
||||
pos += 2;
|
||||
WPA_PUT_BE16(pos, ext_type);
|
||||
pos += 2;
|
||||
WPA_PUT_BE16(pos, data_len);
|
||||
pos += 2;
|
||||
os_memcpy(pos, data, data_len);
|
||||
conn->client_hello_ext_len = 6 + data_len;
|
||||
|
||||
if (ext_type == TLS_EXT_PAC_OPAQUE) {
|
||||
conn->session_ticket_included = 1;
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Using session ticket");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_get_keys - Get master key and random data from TLS connection
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @keys: Structure of key/random data (filled on success)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_client_get_keys(struct tlsv1_client *conn, struct tls_keys *keys)
|
||||
{
|
||||
os_memset(keys, 0, sizeof(*keys));
|
||||
if (conn->state == CLIENT_HELLO)
|
||||
return -1;
|
||||
|
||||
keys->client_random = conn->client_random;
|
||||
keys->client_random_len = TLS_RANDOM_LEN;
|
||||
|
||||
if (conn->state != SERVER_HELLO) {
|
||||
keys->server_random = conn->server_random;
|
||||
keys->server_random_len = TLS_RANDOM_LEN;
|
||||
keys->master_key = conn->master_secret;
|
||||
keys->master_key_len = TLS_MASTER_SECRET_LEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_get_keyblock_size - Get TLS key_block size
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
|
||||
* failure
|
||||
*/
|
||||
int tlsv1_client_get_keyblock_size(struct tlsv1_client *conn)
|
||||
{
|
||||
if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
|
||||
return -1;
|
||||
|
||||
return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
|
||||
conn->rl.iv_size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_set_cipher_list - Configure acceptable cipher suites
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
|
||||
* (TLS_CIPHER_*).
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
|
||||
{
|
||||
size_t count;
|
||||
u16 *suites;
|
||||
|
||||
/* TODO: implement proper configuration of cipher suites */
|
||||
if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
|
||||
count = 0;
|
||||
suites = conn->cipher_suites;
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA256;
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA256;
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
|
||||
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
|
||||
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
|
||||
suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
|
||||
|
||||
/*
|
||||
* Cisco AP (at least 350 and 1200 series) local authentication
|
||||
* server does not know how to search cipher suites from the
|
||||
* list and seem to require that the last entry in the list is
|
||||
* the one that it wants to use. However, TLS specification
|
||||
* requires the list to be in the client preference order. As a
|
||||
* workaround, add anon-DH AES-128-SHA1 again at the end of the
|
||||
* list to allow the Cisco code to find it.
|
||||
*/
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
|
||||
conn->num_cipher_suites = count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_client_set_cred - Set client credentials
|
||||
* @conn: TLSv1 client connection data from tlsv1_client_init()
|
||||
* @cred: Credentials from tlsv1_cred_alloc()
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* On success, the client takes ownership of the credentials block and caller
|
||||
* must not free it. On failure, caller is responsible for freeing the
|
||||
* credential block.
|
||||
*/
|
||||
int tlsv1_client_set_cred(struct tlsv1_client *conn,
|
||||
struct tlsv1_credentials *cred)
|
||||
{
|
||||
tlsv1_cred_free(conn->cred);
|
||||
conn->cred = cred;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void tlsv1_client_set_time_checks(struct tlsv1_client *conn, int enabled)
|
||||
{
|
||||
conn->disable_time_checks = !enabled;
|
||||
}
|
||||
|
||||
|
||||
void tlsv1_client_set_session_ticket_cb(struct tlsv1_client *conn,
|
||||
tlsv1_client_session_ticket_cb cb,
|
||||
void *ctx)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
|
||||
cb, ctx);
|
||||
conn->session_ticket_cb = cb;
|
||||
conn->session_ticket_cb_ctx = ctx;
|
||||
}
|
1001
components/wpa_supplicant/src/wpa2/tls/tlsv1_client_read.c
Normal file
1001
components/wpa_supplicant/src/wpa2/tls/tlsv1_client_read.c
Normal file
File diff suppressed because it is too large
Load diff
901
components/wpa_supplicant/src/wpa2/tls/tlsv1_client_write.c
Normal file
901
components/wpa_supplicant/src/wpa2/tls/tlsv1_client_write.c
Normal file
|
@ -0,0 +1,901 @@
|
|||
/*
|
||||
* TLSv1 client - write handshake message
|
||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/tls/x509v3.h"
|
||||
#include "wpa2/tls/tlsv1_common.h"
|
||||
#include "wpa2/tls/tlsv1_record.h"
|
||||
#include "wpa2/tls/tlsv1_client.h"
|
||||
#include "wpa2/tls/tlsv1_client_i.h"
|
||||
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
|
||||
static size_t tls_client_cert_chain_der_len(struct tlsv1_client *conn)
|
||||
{
|
||||
size_t len = 0;
|
||||
struct x509_certificate *cert;
|
||||
|
||||
if (conn->cred == NULL)
|
||||
return 0;
|
||||
|
||||
cert = conn->cred->cert;
|
||||
while (cert) {
|
||||
len += 3 + cert->cert_len;
|
||||
if (x509_certificate_self_signed(cert))
|
||||
break;
|
||||
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
|
||||
&cert->issuer);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
u8 * tls_send_client_hello(struct tlsv1_client *conn, size_t *out_len)
|
||||
{
|
||||
u8 *hello, *end, *pos, *hs_length, *hs_start, *rhdr;
|
||||
struct os_time now;
|
||||
size_t len, i;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ClientHello");
|
||||
*out_len = 0;
|
||||
|
||||
os_get_time(&now);
|
||||
WPA_PUT_BE32(conn->client_random, now.sec);
|
||||
if (random_get_bytes(conn->client_random + 4, TLS_RANDOM_LEN - 4)) {
|
||||
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
|
||||
"client_random");
|
||||
return NULL;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: client_random",
|
||||
conn->client_random, TLS_RANDOM_LEN);
|
||||
|
||||
len = 100 + conn->num_cipher_suites * 2 + conn->client_hello_ext_len;
|
||||
hello = os_malloc(len);
|
||||
if (hello == NULL)
|
||||
return NULL;
|
||||
end = hello + len;
|
||||
|
||||
rhdr = hello;
|
||||
pos = rhdr + TLS_RECORD_HEADER_LEN;
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_HELLO;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
/* body - ClientHello */
|
||||
/* ProtocolVersion client_version */
|
||||
WPA_PUT_BE16(pos, TLS_VERSION);
|
||||
pos += 2;
|
||||
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
|
||||
os_memcpy(pos, conn->client_random, TLS_RANDOM_LEN);
|
||||
pos += TLS_RANDOM_LEN;
|
||||
/* SessionID session_id */
|
||||
*pos++ = conn->session_id_len;
|
||||
os_memcpy(pos, conn->session_id, conn->session_id_len);
|
||||
pos += conn->session_id_len;
|
||||
/* CipherSuite cipher_suites<2..2^16-1> */
|
||||
WPA_PUT_BE16(pos, 2 * conn->num_cipher_suites);
|
||||
pos += 2;
|
||||
for (i = 0; i < conn->num_cipher_suites; i++) {
|
||||
WPA_PUT_BE16(pos, conn->cipher_suites[i]);
|
||||
pos += 2;
|
||||
}
|
||||
/* CompressionMethod compression_methods<1..2^8-1> */
|
||||
*pos++ = 1;
|
||||
*pos++ = TLS_COMPRESSION_NULL;
|
||||
|
||||
if (conn->client_hello_ext) {
|
||||
os_memcpy(pos, conn->client_hello_ext,
|
||||
conn->client_hello_ext_len);
|
||||
pos += conn->client_hello_ext_len;
|
||||
}
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
out_len) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(hello);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
conn->state = SERVER_HELLO;
|
||||
|
||||
return hello;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_client_certificate(struct tlsv1_client *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
|
||||
size_t rlen;
|
||||
struct x509_certificate *cert;
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
/* body - Certificate */
|
||||
/* uint24 length (to be filled) */
|
||||
cert_start = pos;
|
||||
pos += 3;
|
||||
cert = conn->cred ? conn->cred->cert : NULL;
|
||||
while (cert) {
|
||||
if (pos + 3 + cert->cert_len > end) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
|
||||
"for Certificate (cert_len=%lu left=%lu)",
|
||||
(unsigned long) cert->cert_len,
|
||||
(unsigned long) (end - pos));
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE24(pos, cert->cert_len);
|
||||
pos += 3;
|
||||
os_memcpy(pos, cert->cert_start, cert->cert_len);
|
||||
pos += cert->cert_len;
|
||||
|
||||
if (x509_certificate_self_signed(cert))
|
||||
break;
|
||||
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
|
||||
&cert->issuer);
|
||||
}
|
||||
if (conn->cred == NULL || cert == conn->cred->cert || cert == NULL) {
|
||||
/*
|
||||
* Client was not configured with all the needed certificates
|
||||
* to form a full certificate chain. The server may fail to
|
||||
* validate the chain unless it is configured with all the
|
||||
* missing CA certificates.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Full client certificate chain "
|
||||
"not configured - validation may fail");
|
||||
}
|
||||
WPA_PUT_BE24(cert_start, pos - cert_start - 3);
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
pos = rhdr + rlen;
|
||||
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
*msgpos = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tlsv1_key_x_anon_dh(struct tlsv1_client *conn, u8 **pos, u8 *end)
|
||||
{
|
||||
/* ClientDiffieHellmanPublic */
|
||||
u8 *csecret, *csecret_start, *dh_yc, *shared;
|
||||
size_t csecret_len, dh_yc_len, shared_len;
|
||||
|
||||
csecret_len = conn->dh_p_len;
|
||||
csecret = os_malloc(csecret_len);
|
||||
if (csecret == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
|
||||
"memory for Yc (Diffie-Hellman)");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if (random_get_bytes(csecret, csecret_len)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
|
||||
"data for Diffie-Hellman");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_memcmp(csecret, conn->dh_p, csecret_len) > 0)
|
||||
csecret[0] = 0; /* make sure Yc < p */
|
||||
|
||||
csecret_start = csecret;
|
||||
while (csecret_len > 1 && *csecret_start == 0) {
|
||||
csecret_start++;
|
||||
csecret_len--;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH client's secret value",
|
||||
csecret_start, csecret_len);
|
||||
|
||||
/* Yc = g^csecret mod p */
|
||||
dh_yc_len = conn->dh_p_len;
|
||||
dh_yc = os_malloc(dh_yc_len);
|
||||
if (dh_yc == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
|
||||
"memory for Diffie-Hellman");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
return -1;
|
||||
}
|
||||
if (wpa2_crypto_funcs.crypto_mod_exp) {
|
||||
if(wpa2_crypto_funcs.crypto_mod_exp(conn->dh_g, conn->dh_g_len,
|
||||
csecret_start, csecret_len,
|
||||
conn->dh_p, conn->dh_p_len,
|
||||
dh_yc, &dh_yc_len)) {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
os_free(dh_yc);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
os_free(dh_yc);
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto_mod_exp function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Yc (client's public value)",
|
||||
dh_yc, dh_yc_len);
|
||||
|
||||
WPA_PUT_BE16(*pos, dh_yc_len);
|
||||
*pos += 2;
|
||||
if (*pos + dh_yc_len > end) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough room in the "
|
||||
"message buffer for Yc");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
os_free(dh_yc);
|
||||
return -1;
|
||||
}
|
||||
os_memcpy(*pos, dh_yc, dh_yc_len);
|
||||
*pos += dh_yc_len;
|
||||
os_free(dh_yc);
|
||||
|
||||
shared_len = conn->dh_p_len;
|
||||
shared = os_malloc(shared_len);
|
||||
if (shared == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Could not allocate memory for "
|
||||
"DH");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* shared = Ys^csecret mod p */
|
||||
if (wpa2_crypto_funcs.crypto_mod_exp) {
|
||||
if(wpa2_crypto_funcs.crypto_mod_exp(conn->dh_ys, conn->dh_ys_len,
|
||||
csecret_start, csecret_len,
|
||||
conn->dh_p, conn->dh_p_len,
|
||||
shared, &shared_len)) {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
os_free(shared);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(csecret);
|
||||
os_free(shared);
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto_mod_exp function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "TLSv1: Shared secret from DH key exchange",
|
||||
shared, shared_len);
|
||||
|
||||
os_memset(csecret_start, 0, csecret_len);
|
||||
os_free(csecret);
|
||||
if (tls_derive_keys(conn, shared, shared_len)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(shared);
|
||||
return -1;
|
||||
}
|
||||
os_memset(shared, 0, shared_len);
|
||||
os_free(shared);
|
||||
tlsv1_client_free_dh(conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tlsv1_key_x_rsa(struct tlsv1_client *conn, u8 **pos, u8 *end)
|
||||
{
|
||||
u8 pre_master_secret[TLS_PRE_MASTER_SECRET_LEN];
|
||||
size_t clen;
|
||||
int res;
|
||||
|
||||
if (tls_derive_pre_master_secret(pre_master_secret) < 0 ||
|
||||
tls_derive_keys(conn, pre_master_secret,
|
||||
TLS_PRE_MASTER_SECRET_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive keys");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* EncryptedPreMasterSecret */
|
||||
if (conn->server_rsa_key == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No server RSA key to "
|
||||
"use for encrypting pre-master secret");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* RSA encrypted value is encoded with PKCS #1 v1.5 block type 2. */
|
||||
*pos += 2;
|
||||
clen = end - *pos;
|
||||
res = crypto_public_key_encrypt_pkcs1_v15(
|
||||
conn->server_rsa_key,
|
||||
pre_master_secret, TLS_PRE_MASTER_SECRET_LEN,
|
||||
*pos, &clen);
|
||||
os_memset(pre_master_secret, 0, TLS_PRE_MASTER_SECRET_LEN);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: RSA encryption failed");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE16(*pos - 2, clen);
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Encrypted pre_master_secret",
|
||||
*pos, clen);
|
||||
*pos += clen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_client_key_exchange(struct tlsv1_client *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length;
|
||||
size_t rlen;
|
||||
tls_key_exchange keyx;
|
||||
const struct tls_cipher_suite *suite;
|
||||
|
||||
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
|
||||
if (suite == NULL)
|
||||
keyx = TLS_KEY_X_NULL;
|
||||
else
|
||||
keyx = suite->key_exchange;
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ClientKeyExchange");
|
||||
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_CLIENT_KEY_EXCHANGE;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
/* body - ClientKeyExchange */
|
||||
if (keyx == TLS_KEY_X_DH_anon) {
|
||||
if (tlsv1_key_x_anon_dh(conn, &pos, end) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
if (tlsv1_key_x_rsa(conn, &pos, end) < 0)
|
||||
return -1;
|
||||
}
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
pos = rhdr + rlen;
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
*msgpos = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_client_certificate_verify(struct tlsv1_client *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length, *signed_start;
|
||||
size_t rlen, hlen, clen;
|
||||
u8 hash[100], *hpos;
|
||||
enum { SIGN_ALG_RSA, SIGN_ALG_DSA } alg = SIGN_ALG_RSA;
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateVerify");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_VERIFY;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
|
||||
/*
|
||||
* RFC 2246: 7.4.3 and 7.4.8:
|
||||
* Signature signature
|
||||
*
|
||||
* RSA:
|
||||
* digitally-signed struct {
|
||||
* opaque md5_hash[16];
|
||||
* opaque sha_hash[20];
|
||||
* };
|
||||
*
|
||||
* DSA:
|
||||
* digitally-signed struct {
|
||||
* opaque sha_hash[20];
|
||||
* };
|
||||
*
|
||||
* The hash values are calculated over all handshake messages sent or
|
||||
* received starting at ClientHello up to, but not including, this
|
||||
* CertificateVerify message, including the type and length fields of
|
||||
* the handshake messages.
|
||||
*/
|
||||
|
||||
hpos = hash;
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (conn->rl.tls_version == TLS_VERSION_1_2) {
|
||||
hlen = SHA256_MAC_LEN;
|
||||
if (wpa2_crypto_funcs.crypto_hash_finish) {
|
||||
if (conn->verify.sha256_cert == NULL ||
|
||||
wpa2_crypto_funcs.crypto_hash_finish(conn->verify.sha256_cert, hpos, &hlen) <
|
||||
0) {
|
||||
conn->verify.sha256_cert = NULL;
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
conn->verify.sha256_cert = NULL;
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
conn->verify.sha256_cert = NULL;
|
||||
|
||||
/*
|
||||
* RFC 3447, A.2.4 RSASSA-PKCS1-v1_5
|
||||
*
|
||||
* DigestInfo ::= SEQUENCE {
|
||||
* digestAlgorithm DigestAlgorithm,
|
||||
* digest OCTET STRING
|
||||
* }
|
||||
*
|
||||
* SHA-256 OID: sha256WithRSAEncryption ::= {pkcs-1 11}
|
||||
*
|
||||
* DER encoded DigestInfo for SHA256 per RFC 3447:
|
||||
* 30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 ||
|
||||
* H
|
||||
*/
|
||||
os_memmove(hash + 19, hash, hlen);
|
||||
hlen += 19;
|
||||
os_memcpy(hash, "\x30\x31\x30\x0d\x06\x09\x60\x86\x48\x01\x65"
|
||||
"\x03\x04\x02\x01\x05\x00\x04\x20", 19);
|
||||
} else {
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
if (alg == SIGN_ALG_RSA) {
|
||||
hlen = MD5_MAC_LEN;
|
||||
if (conn->verify.md5_cert == NULL ||
|
||||
crypto_hash_finish(conn->verify.md5_cert, hpos, &hlen) < 0)
|
||||
{
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
conn->verify.md5_cert = NULL;
|
||||
crypto_hash_finish(conn->verify.sha1_cert, NULL, NULL);
|
||||
conn->verify.sha1_cert = NULL;
|
||||
return -1;
|
||||
}
|
||||
hpos += MD5_MAC_LEN;
|
||||
} else
|
||||
crypto_hash_finish(conn->verify.md5_cert, NULL, NULL);
|
||||
|
||||
conn->verify.md5_cert = NULL;
|
||||
hlen = SHA1_MAC_LEN;
|
||||
if (conn->verify.sha1_cert == NULL ||
|
||||
crypto_hash_finish(conn->verify.sha1_cert, hpos, &hlen) < 0) {
|
||||
conn->verify.sha1_cert = NULL;
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
conn->verify.sha1_cert = NULL;
|
||||
|
||||
if (alg == SIGN_ALG_RSA)
|
||||
hlen += MD5_MAC_LEN;
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: CertificateVerify hash", hash, hlen);
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (conn->rl.tls_version >= TLS_VERSION_1_2) {
|
||||
/*
|
||||
* RFC 5246, 4.7:
|
||||
* TLS v1.2 adds explicit indication of the used signature and
|
||||
* hash algorithms.
|
||||
*
|
||||
* struct {
|
||||
* HashAlgorithm hash;
|
||||
* SignatureAlgorithm signature;
|
||||
* } SignatureAndHashAlgorithm;
|
||||
*/
|
||||
*pos++ = TLS_HASH_ALG_SHA256;
|
||||
*pos++ = TLS_SIGN_ALG_RSA;
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
/*
|
||||
* RFC 2246, 4.7:
|
||||
* In digital signing, one-way hash functions are used as input for a
|
||||
* signing algorithm. A digitally-signed element is encoded as an
|
||||
* opaque vector <0..2^16-1>, where the length is specified by the
|
||||
* signing algorithm and key.
|
||||
*
|
||||
* In RSA signing, a 36-byte structure of two hashes (one SHA and one
|
||||
* MD5) is signed (encrypted with the private key). It is encoded with
|
||||
* PKCS #1 block type 0 or type 1 as described in [PKCS1].
|
||||
*/
|
||||
signed_start = pos; /* length to be filled */
|
||||
pos += 2;
|
||||
clen = end - pos;
|
||||
if (conn->cred == NULL ||
|
||||
crypto_private_key_sign_pkcs1(conn->cred->key, hash, hlen,
|
||||
pos, &clen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to sign hash (PKCS #1)");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE16(signed_start, clen);
|
||||
|
||||
pos += clen;
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
pos = rhdr + rlen;
|
||||
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
*msgpos = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_client_change_cipher_spec(struct tlsv1_client *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
size_t rlen;
|
||||
u8 payload[1];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
|
||||
|
||||
payload[0] = TLS_CHANGE_CIPHER_SPEC;
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
|
||||
*msgpos, end - *msgpos, payload, sizeof(payload),
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
|
||||
"record layer");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*msgpos += rlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_client_finished(struct tlsv1_client *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *hs_start;
|
||||
size_t rlen, hlen;
|
||||
u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
|
||||
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
|
||||
|
||||
/* Encrypted Handshake Message: Finished */
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (conn->rl.tls_version >= TLS_VERSION_1_2) {
|
||||
hlen = SHA256_MAC_LEN;
|
||||
if (wpa2_crypto_funcs.crypto_hash_finish) {
|
||||
if (conn->verify.sha256_client == NULL ||
|
||||
wpa2_crypto_funcs.crypto_hash_finish(conn->verify.sha256_client, hash, &hlen)
|
||||
< 0) {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
conn->verify.sha256_client = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
conn->verify.sha256_client = NULL;
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
conn->verify.sha256_client = NULL;
|
||||
} else {
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
hlen = MD5_MAC_LEN;
|
||||
if (conn->verify.md5_client == NULL ||
|
||||
crypto_hash_finish(conn->verify.md5_client, hash, &hlen) < 0) {
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
conn->verify.md5_client = NULL;
|
||||
crypto_hash_finish(conn->verify.sha1_client, NULL, NULL);
|
||||
conn->verify.sha1_client = NULL;
|
||||
return -1;
|
||||
}
|
||||
conn->verify.md5_client = NULL;
|
||||
hlen = SHA1_MAC_LEN;
|
||||
if (conn->verify.sha1_client == NULL ||
|
||||
crypto_hash_finish(conn->verify.sha1_client, hash + MD5_MAC_LEN,
|
||||
&hlen) < 0) {
|
||||
conn->verify.sha1_client = NULL;
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
conn->verify.sha1_client = NULL;
|
||||
hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
if (tls_prf(conn->rl.tls_version,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN,
|
||||
"client finished", hash, hlen,
|
||||
verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (client)",
|
||||
verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
|
||||
|
||||
/* Handshake */
|
||||
pos = hs_start = verify_data;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
|
||||
/* uint24 length */
|
||||
WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
|
||||
pos += 3;
|
||||
pos += TLS_VERIFY_DATA_LEN; /* verify_data already in place */
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
*msgpos, end - *msgpos, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
|
||||
tls_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*msgpos += rlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u8 * tls_send_client_key_exchange(struct tlsv1_client *conn,
|
||||
size_t *out_len)
|
||||
{
|
||||
u8 *msg, *end, *pos;
|
||||
size_t msglen;
|
||||
|
||||
*out_len = 0;
|
||||
|
||||
msglen = 2000;
|
||||
if (conn->certificate_requested)
|
||||
msglen += tls_client_cert_chain_der_len(conn);
|
||||
|
||||
msg = os_malloc(msglen);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = msg;
|
||||
end = msg + msglen;
|
||||
|
||||
if (conn->certificate_requested) {
|
||||
if (tls_write_client_certificate(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (tls_write_client_key_exchange(conn, &pos, end) < 0 ||
|
||||
(conn->certificate_requested && conn->cred && conn->cred->key &&
|
||||
tls_write_client_certificate_verify(conn, &pos, end) < 0) ||
|
||||
tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
|
||||
tls_write_client_finished(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out_len = pos - msg;
|
||||
conn->state = SERVER_CHANGE_CIPHER_SPEC;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
static u8 * tls_send_change_cipher_spec(struct tlsv1_client *conn,
|
||||
size_t *out_len)
|
||||
{
|
||||
u8 *msg, *end, *pos;
|
||||
|
||||
*out_len = 0;
|
||||
|
||||
msg = os_malloc(1000);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = msg;
|
||||
end = msg + 1000;
|
||||
|
||||
if (tls_write_client_change_cipher_spec(conn, &pos, end) < 0 ||
|
||||
tls_write_client_finished(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Session resumption completed "
|
||||
"successfully");
|
||||
|
||||
conn->state = ESTABLISHED;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
u8 * tlsv1_client_handshake_write(struct tlsv1_client *conn, size_t *out_len,
|
||||
int no_appl_data)
|
||||
{
|
||||
switch (conn->state) {
|
||||
case CLIENT_KEY_EXCHANGE:
|
||||
return tls_send_client_key_exchange(conn, out_len);
|
||||
case CHANGE_CIPHER_SPEC:
|
||||
return tls_send_change_cipher_spec(conn, out_len);
|
||||
case ACK_FINISHED:
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed "
|
||||
"successfully");
|
||||
conn->state = ESTABLISHED;
|
||||
*out_len = 0;
|
||||
if (no_appl_data) {
|
||||
/* Need to return something to get final TLS ACK. */
|
||||
return os_malloc(1);
|
||||
}
|
||||
return NULL;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
|
||||
"generating reply", conn->state);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u8 * tlsv1_client_send_alert(struct tlsv1_client *conn, u8 level,
|
||||
u8 description, size_t *out_len)
|
||||
{
|
||||
u8 *alert, *pos, *length;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
|
||||
*out_len = 0;
|
||||
|
||||
alert = os_malloc(10);
|
||||
if (alert == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = alert;
|
||||
|
||||
/* TLSPlaintext */
|
||||
/* ContentType type */
|
||||
*pos++ = TLS_CONTENT_TYPE_ALERT;
|
||||
/* ProtocolVersion version */
|
||||
WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
|
||||
TLS_VERSION);
|
||||
pos += 2;
|
||||
/* uint16 length (to be filled) */
|
||||
length = pos;
|
||||
pos += 2;
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Alert */
|
||||
/* AlertLevel level */
|
||||
*pos++ = level;
|
||||
/* AlertDescription description */
|
||||
*pos++ = description;
|
||||
|
||||
WPA_PUT_BE16(length, pos - length - 2);
|
||||
*out_len = pos - alert;
|
||||
|
||||
return alert;
|
||||
}
|
337
components/wpa_supplicant/src/wpa2/tls/tlsv1_common.c
Normal file
337
components/wpa_supplicant/src/wpa2/tls/tlsv1_common.c
Normal file
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
* TLSv1 common routines
|
||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/tls/x509v3.h"
|
||||
#include "wpa2/tls/tlsv1_common.h"
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
|
||||
|
||||
/*
|
||||
* TODO:
|
||||
* RFC 2246 Section 9: Mandatory to implement TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
|
||||
* Add support for commonly used cipher suites; don't bother with exportable
|
||||
* suites.
|
||||
*/
|
||||
|
||||
static const struct tls_cipher_suite tls_cipher_suites[] = {
|
||||
{ TLS_NULL_WITH_NULL_NULL, TLS_KEY_X_NULL, TLS_CIPHER_NULL,
|
||||
TLS_HASH_NULL },
|
||||
{ TLS_RSA_WITH_RC4_128_MD5, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
|
||||
TLS_HASH_MD5 },
|
||||
{ TLS_RSA_WITH_RC4_128_SHA, TLS_KEY_X_RSA, TLS_CIPHER_RC4_128,
|
||||
TLS_HASH_SHA },
|
||||
{ TLS_RSA_WITH_DES_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_DES_CBC,
|
||||
TLS_HASH_SHA },
|
||||
{ TLS_RSA_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_RSA,
|
||||
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
|
||||
{ TLS_DH_anon_WITH_RC4_128_MD5, TLS_KEY_X_DH_anon,
|
||||
TLS_CIPHER_RC4_128, TLS_HASH_MD5 },
|
||||
{ TLS_DH_anon_WITH_DES_CBC_SHA, TLS_KEY_X_DH_anon,
|
||||
TLS_CIPHER_DES_CBC, TLS_HASH_SHA },
|
||||
{ TLS_DH_anon_WITH_3DES_EDE_CBC_SHA, TLS_KEY_X_DH_anon,
|
||||
TLS_CIPHER_3DES_EDE_CBC, TLS_HASH_SHA },
|
||||
{ TLS_RSA_WITH_AES_128_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_128_CBC,
|
||||
TLS_HASH_SHA },
|
||||
{ TLS_DH_anon_WITH_AES_128_CBC_SHA, TLS_KEY_X_DH_anon,
|
||||
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA },
|
||||
{ TLS_RSA_WITH_AES_256_CBC_SHA, TLS_KEY_X_RSA, TLS_CIPHER_AES_256_CBC,
|
||||
TLS_HASH_SHA },
|
||||
{ TLS_DH_anon_WITH_AES_256_CBC_SHA, TLS_KEY_X_DH_anon,
|
||||
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA },
|
||||
{ TLS_RSA_WITH_AES_128_CBC_SHA256, TLS_KEY_X_RSA,
|
||||
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
||||
{ TLS_RSA_WITH_AES_256_CBC_SHA256, TLS_KEY_X_RSA,
|
||||
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 },
|
||||
{ TLS_DH_anon_WITH_AES_128_CBC_SHA256, TLS_KEY_X_DH_anon,
|
||||
TLS_CIPHER_AES_128_CBC, TLS_HASH_SHA256 },
|
||||
{ TLS_DH_anon_WITH_AES_256_CBC_SHA256, TLS_KEY_X_DH_anon,
|
||||
TLS_CIPHER_AES_256_CBC, TLS_HASH_SHA256 }
|
||||
};
|
||||
|
||||
#define NUM_ELEMS(a) (sizeof(a) / sizeof((a)[0]))
|
||||
#define NUM_TLS_CIPHER_SUITES NUM_ELEMS(tls_cipher_suites)
|
||||
|
||||
|
||||
static const struct tls_cipher_data tls_ciphers[] = {
|
||||
{ TLS_CIPHER_NULL, TLS_CIPHER_STREAM, 0, 0, 0,
|
||||
CRYPTO_CIPHER_NULL },
|
||||
{ TLS_CIPHER_IDEA_CBC, TLS_CIPHER_BLOCK, 16, 16, 8,
|
||||
CRYPTO_CIPHER_NULL },
|
||||
{ TLS_CIPHER_RC2_CBC_40, TLS_CIPHER_BLOCK, 5, 16, 0,
|
||||
CRYPTO_CIPHER_ALG_RC2 },
|
||||
{ TLS_CIPHER_RC4_40, TLS_CIPHER_STREAM, 5, 16, 0,
|
||||
CRYPTO_CIPHER_ALG_RC4 },
|
||||
{ TLS_CIPHER_RC4_128, TLS_CIPHER_STREAM, 16, 16, 0,
|
||||
CRYPTO_CIPHER_ALG_RC4 },
|
||||
{ TLS_CIPHER_DES40_CBC, TLS_CIPHER_BLOCK, 5, 8, 8,
|
||||
CRYPTO_CIPHER_ALG_DES },
|
||||
{ TLS_CIPHER_DES_CBC, TLS_CIPHER_BLOCK, 8, 8, 8,
|
||||
CRYPTO_CIPHER_ALG_DES },
|
||||
{ TLS_CIPHER_3DES_EDE_CBC, TLS_CIPHER_BLOCK, 24, 24, 8,
|
||||
CRYPTO_CIPHER_ALG_3DES },
|
||||
{ TLS_CIPHER_AES_128_CBC, TLS_CIPHER_BLOCK, 16, 16, 16,
|
||||
CRYPTO_CIPHER_ALG_AES },
|
||||
{ TLS_CIPHER_AES_256_CBC, TLS_CIPHER_BLOCK, 32, 32, 16,
|
||||
CRYPTO_CIPHER_ALG_AES }
|
||||
};
|
||||
|
||||
#define NUM_TLS_CIPHER_DATA NUM_ELEMS(tls_ciphers)
|
||||
|
||||
|
||||
/**
|
||||
* tls_get_cipher_suite - Get TLS cipher suite
|
||||
* @suite: Cipher suite identifier
|
||||
* Returns: Pointer to the cipher data or %NULL if not found
|
||||
*/
|
||||
const struct tls_cipher_suite * tls_get_cipher_suite(u16 suite)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < NUM_TLS_CIPHER_SUITES; i++)
|
||||
if (tls_cipher_suites[i].suite == suite)
|
||||
return &tls_cipher_suites[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
const struct tls_cipher_data * tls_get_cipher_data(tls_cipher cipher)
|
||||
{
|
||||
size_t i;
|
||||
for (i = 0; i < NUM_TLS_CIPHER_DATA; i++)
|
||||
if (tls_ciphers[i].cipher == cipher)
|
||||
return &tls_ciphers[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int tls_server_key_exchange_allowed(tls_cipher cipher)
|
||||
{
|
||||
const struct tls_cipher_suite *suite;
|
||||
|
||||
/* RFC 2246, Section 7.4.3 */
|
||||
suite = tls_get_cipher_suite(cipher);
|
||||
if (suite == NULL)
|
||||
return 0;
|
||||
|
||||
switch (suite->key_exchange) {
|
||||
case TLS_KEY_X_DHE_DSS:
|
||||
case TLS_KEY_X_DHE_DSS_EXPORT:
|
||||
case TLS_KEY_X_DHE_RSA:
|
||||
case TLS_KEY_X_DHE_RSA_EXPORT:
|
||||
case TLS_KEY_X_DH_anon_EXPORT:
|
||||
case TLS_KEY_X_DH_anon:
|
||||
return 1;
|
||||
case TLS_KEY_X_RSA_EXPORT:
|
||||
return 1 /* FIX: public key len > 512 bits */;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tls_parse_cert - Parse DER encoded X.509 certificate and get public key
|
||||
* @buf: ASN.1 DER encoded certificate
|
||||
* @len: Length of the buffer
|
||||
* @pk: Buffer for returning the allocated public key
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This functions parses an ASN.1 DER encoded X.509 certificate and retrieves
|
||||
* the public key from it. The caller is responsible for freeing the public key
|
||||
* by calling crypto_public_key_free().
|
||||
*/
|
||||
int tls_parse_cert(const u8 *buf, size_t len, struct crypto_public_key **pk)
|
||||
{
|
||||
struct x509_certificate *cert;
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Parse ASN.1 DER certificate",
|
||||
buf, len);
|
||||
|
||||
*pk = crypto_public_key_from_cert(buf, len);
|
||||
if (*pk)
|
||||
return 0;
|
||||
|
||||
cert = x509_certificate_parse(buf, len);
|
||||
if (cert == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to parse X.509 "
|
||||
"certificate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TODO
|
||||
* verify key usage (must allow encryption)
|
||||
*
|
||||
* All certificate profiles, key and cryptographic formats are
|
||||
* defined by the IETF PKIX working group [PKIX]. When a key
|
||||
* usage extension is present, the digitalSignature bit must be
|
||||
* set for the key to be eligible for signing, as described
|
||||
* above, and the keyEncipherment bit must be present to allow
|
||||
* encryption, as described above. The keyAgreement bit must be
|
||||
* set on Diffie-Hellman certificates. (PKIX: RFC 3280)
|
||||
*/
|
||||
|
||||
*pk = crypto_public_key_import(cert->public_key, cert->public_key_len);
|
||||
x509_certificate_free(cert);
|
||||
|
||||
if (*pk == NULL) {
|
||||
wpa_printf(MSG_ERROR, "TLSv1: Failed to import "
|
||||
"server public key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tls_verify_hash_init(struct tls_verify_hash *verify)
|
||||
{
|
||||
tls_verify_hash_free(verify);
|
||||
verify->md5_client = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
|
||||
verify->md5_server = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
|
||||
verify->md5_cert = crypto_hash_init(CRYPTO_HASH_ALG_MD5, NULL, 0);
|
||||
verify->sha1_client = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
|
||||
verify->sha1_server = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
|
||||
verify->sha1_cert = crypto_hash_init(CRYPTO_HASH_ALG_SHA1, NULL, 0);
|
||||
if (verify->md5_client == NULL || verify->md5_server == NULL ||
|
||||
verify->md5_cert == NULL || verify->sha1_client == NULL ||
|
||||
verify->sha1_server == NULL || verify->sha1_cert == NULL) {
|
||||
tls_verify_hash_free(verify);
|
||||
return -1;
|
||||
}
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (wpa2_crypto_funcs.crypto_hash_init) {
|
||||
verify->sha256_client = wpa2_crypto_funcs.crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
|
||||
verify->sha256_server = wpa2_crypto_funcs.crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
|
||||
verify->sha256_cert = wpa2_crypto_funcs.crypto_hash_init(CRYPTO_HASH_ALG_SHA256, NULL, 0);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash init function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
if (verify->sha256_client == NULL ||
|
||||
verify->sha256_server == NULL ||
|
||||
verify->sha256_cert == NULL) {
|
||||
tls_verify_hash_free(verify);
|
||||
return -1;
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void tls_verify_hash_add(struct tls_verify_hash *verify, const u8 *buf,
|
||||
size_t len)
|
||||
{
|
||||
if (verify->md5_client && verify->sha1_client) {
|
||||
crypto_hash_update(verify->md5_client, buf, len);
|
||||
crypto_hash_update(verify->sha1_client, buf, len);
|
||||
}
|
||||
if (verify->md5_server && verify->sha1_server) {
|
||||
crypto_hash_update(verify->md5_server, buf, len);
|
||||
crypto_hash_update(verify->sha1_server, buf, len);
|
||||
}
|
||||
if (verify->md5_cert && verify->sha1_cert) {
|
||||
crypto_hash_update(verify->md5_cert, buf, len);
|
||||
crypto_hash_update(verify->sha1_cert, buf, len);
|
||||
}
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (wpa2_crypto_funcs.crypto_hash_update) {
|
||||
if (verify->sha256_client)
|
||||
wpa2_crypto_funcs.crypto_hash_update(verify->sha256_client, buf, len);
|
||||
if (verify->sha256_server)
|
||||
wpa2_crypto_funcs.crypto_hash_update(verify->sha256_server, buf, len);
|
||||
if (verify->sha256_cert)
|
||||
wpa2_crypto_funcs.crypto_hash_update(verify->sha256_cert, buf, len);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash update function!\r\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
}
|
||||
|
||||
|
||||
void tls_verify_hash_free(struct tls_verify_hash *verify)
|
||||
{
|
||||
crypto_hash_finish(verify->md5_client, NULL, NULL);
|
||||
crypto_hash_finish(verify->md5_server, NULL, NULL);
|
||||
crypto_hash_finish(verify->md5_cert, NULL, NULL);
|
||||
crypto_hash_finish(verify->sha1_client, NULL, NULL);
|
||||
crypto_hash_finish(verify->sha1_server, NULL, NULL);
|
||||
crypto_hash_finish(verify->sha1_cert, NULL, NULL);
|
||||
verify->md5_client = NULL;
|
||||
verify->md5_server = NULL;
|
||||
verify->md5_cert = NULL;
|
||||
verify->sha1_client = NULL;
|
||||
verify->sha1_server = NULL;
|
||||
verify->sha1_cert = NULL;
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (wpa2_crypto_funcs.crypto_hash_finish) {
|
||||
wpa2_crypto_funcs.crypto_hash_finish(verify->sha256_client, NULL, NULL);
|
||||
wpa2_crypto_funcs.crypto_hash_finish(verify->sha256_server, NULL, NULL);
|
||||
wpa2_crypto_funcs.crypto_hash_finish(verify->sha256_cert, NULL, NULL);
|
||||
verify->sha256_client = NULL;
|
||||
verify->sha256_server = NULL;
|
||||
verify->sha256_cert = NULL;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash finish function!\r\n", __FUNCTION__);
|
||||
return;
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
}
|
||||
|
||||
|
||||
int tls_version_ok(u16 ver)
|
||||
{
|
||||
if (ver == TLS_VERSION_1)
|
||||
return 1;
|
||||
#ifdef CONFIG_TLSV11
|
||||
if (ver == TLS_VERSION_1_1)
|
||||
return 1;
|
||||
#endif /* CONFIG_TLSV11 */
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (ver == TLS_VERSION_1_2)
|
||||
return 1;
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const char * tls_version_str(u16 ver)
|
||||
{
|
||||
switch (ver) {
|
||||
case TLS_VERSION_1:
|
||||
return "1.0";
|
||||
case TLS_VERSION_1_1:
|
||||
return "1.1";
|
||||
case TLS_VERSION_1_2:
|
||||
return "1.2";
|
||||
}
|
||||
|
||||
return "?";
|
||||
}
|
||||
|
||||
|
||||
int tls_prf(u16 ver, const u8 *secret, size_t secret_len, const char *label,
|
||||
const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
|
||||
{
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (ver >= TLS_VERSION_1_2) {
|
||||
tls_prf_sha256(secret, secret_len, label, seed, seed_len,
|
||||
out, outlen);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
return tls_prf_sha1_md5(secret, secret_len, label, seed, seed_len, out,
|
||||
outlen);
|
||||
}
|
505
components/wpa_supplicant/src/wpa2/tls/tlsv1_cred.c
Normal file
505
components/wpa_supplicant/src/wpa2/tls/tlsv1_cred.c
Normal file
|
@ -0,0 +1,505 @@
|
|||
/*
|
||||
* TLSv1 credentials
|
||||
* Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/utils/base64.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "wpa2/tls/x509v3.h"
|
||||
#include "wpa2/tls/tlsv1_cred.h"
|
||||
|
||||
struct tlsv1_credentials * tlsv1_cred_alloc(void)
|
||||
{
|
||||
struct tlsv1_credentials *cred;
|
||||
cred = (struct tlsv1_credentials *)os_zalloc(sizeof(*cred));
|
||||
return cred;
|
||||
}
|
||||
|
||||
|
||||
void tlsv1_cred_free(struct tlsv1_credentials *cred)
|
||||
{
|
||||
if (cred == NULL)
|
||||
return;
|
||||
|
||||
x509_certificate_chain_free(cred->trusted_certs);
|
||||
x509_certificate_chain_free(cred->cert);
|
||||
crypto_private_key_free(cred->key);
|
||||
os_free(cred->dh_p);
|
||||
os_free(cred->dh_g);
|
||||
os_free(cred);
|
||||
}
|
||||
|
||||
|
||||
static int tlsv1_add_cert_der(struct x509_certificate **chain,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
struct x509_certificate *cert, *p;
|
||||
char name[128];
|
||||
|
||||
cert = x509_certificate_parse(buf, len);
|
||||
if (cert == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: %s - failed to parse certificate",
|
||||
__func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
p = *chain;
|
||||
while (p && p->next)
|
||||
p = p->next;
|
||||
if (p && x509_name_compare(&cert->subject, &p->issuer) == 0) {
|
||||
/*
|
||||
* The new certificate is the issuer of the last certificate in
|
||||
* the chain - add the new certificate to the end.
|
||||
*/
|
||||
p->next = cert;
|
||||
} else {
|
||||
/* Add to the beginning of the chain */
|
||||
cert->next = *chain;
|
||||
*chain = cert;
|
||||
}
|
||||
|
||||
x509_name_string(&cert->subject, name, sizeof(name));
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Added certificate: %s", name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
|
||||
static const char *pem_cert_end = "-----END CERTIFICATE-----";
|
||||
static const char *pem_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
|
||||
static const char *pem_key_end = "-----END RSA PRIVATE KEY-----";
|
||||
static const char *pem_key2_begin = "-----BEGIN PRIVATE KEY-----";
|
||||
static const char *pem_key2_end = "-----END PRIVATE KEY-----";
|
||||
static const char *pem_key_enc_begin = "-----BEGIN ENCRYPTED PRIVATE KEY-----";
|
||||
static const char *pem_key_enc_end = "-----END ENCRYPTED PRIVATE KEY-----";
|
||||
|
||||
|
||||
static const u8 * search_tag(const char *tag, const u8 *buf, size_t len)
|
||||
{
|
||||
size_t i, plen;
|
||||
|
||||
plen = os_strlen(tag);
|
||||
if (len < plen)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < len - plen; i++) {
|
||||
if (os_memcmp(buf + i, tag, plen) == 0)
|
||||
return buf + i;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static int tlsv1_add_cert(struct x509_certificate **chain,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
unsigned char *der;
|
||||
size_t der_len;
|
||||
|
||||
pos = search_tag(pem_cert_begin, buf, len);
|
||||
if (!pos) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No PEM certificate tag found - "
|
||||
"assume DER format");
|
||||
return tlsv1_add_cert_der(chain, buf, len);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format certificate into "
|
||||
"DER format");
|
||||
|
||||
while (pos) {
|
||||
pos += os_strlen(pem_cert_begin);
|
||||
end = search_tag(pem_cert_end, pos, buf + len - pos);
|
||||
if (end == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not find PEM "
|
||||
"certificate end tag (%s)", pem_cert_end);
|
||||
return -1;
|
||||
}
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
if (der == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM "
|
||||
"certificate");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_add_cert_der(chain, der, der_len) < 0) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM "
|
||||
"certificate after DER conversion");
|
||||
os_free(der);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(der);
|
||||
|
||||
end += os_strlen(pem_cert_end);
|
||||
pos = search_tag(pem_cert_begin, end, buf + len - end);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tlsv1_set_cert_chain(struct x509_certificate **chain,
|
||||
const char *cert, const u8 *cert_blob,
|
||||
size_t cert_blob_len)
|
||||
{
|
||||
if (cert_blob)
|
||||
return tlsv1_add_cert(chain, cert_blob, cert_blob_len);
|
||||
|
||||
if (cert) {
|
||||
u8 *buf = NULL;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
//buf = (u8 *) os_readfile(cert, &len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
|
||||
cert);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = tlsv1_add_cert(chain, buf, len);
|
||||
os_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_set_ca_cert - Set trusted CA certificate(s)
|
||||
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
|
||||
* @cert: File or reference name for X.509 certificate in PEM or DER format
|
||||
* @cert_blob: cert as inlined data or %NULL if not used
|
||||
* @cert_blob_len: ca_cert_blob length
|
||||
* @path: Path to CA certificates (not yet supported)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_set_ca_cert(struct tlsv1_credentials *cred, const char *cert,
|
||||
const u8 *cert_blob, size_t cert_blob_len,
|
||||
const char *path)
|
||||
{
|
||||
if (tlsv1_set_cert_chain(&cred->trusted_certs, cert,
|
||||
cert_blob, cert_blob_len) < 0)
|
||||
return -1;
|
||||
|
||||
if (path) {
|
||||
/* TODO: add support for reading number of certificate files */
|
||||
wpa_printf(MSG_INFO, "TLSv1: Use of CA certificate directory "
|
||||
"not yet supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_set_cert - Set certificate
|
||||
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
|
||||
* @cert: File or reference name for X.509 certificate in PEM or DER format
|
||||
* @cert_blob: cert as inlined data or %NULL if not used
|
||||
* @cert_blob_len: cert_blob length
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_set_cert(struct tlsv1_credentials *cred, const char *cert,
|
||||
const u8 *cert_blob, size_t cert_blob_len)
|
||||
{
|
||||
return tlsv1_set_cert_chain(&cred->cert, cert,
|
||||
cert_blob, cert_blob_len);
|
||||
}
|
||||
|
||||
|
||||
static struct crypto_private_key * tlsv1_set_key_pem(const u8 *key, size_t len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
unsigned char *der;
|
||||
size_t der_len;
|
||||
struct crypto_private_key *pkey;
|
||||
|
||||
pos = search_tag(pem_key_begin, key, len);
|
||||
if (!pos) {
|
||||
pos = search_tag(pem_key2_begin, key, len);
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos += os_strlen(pem_key2_begin);
|
||||
end = search_tag(pem_key2_end, pos, key + len - pos);
|
||||
if (!end)
|
||||
return NULL;
|
||||
} else {
|
||||
const u8 *pos2;
|
||||
pos += os_strlen(pem_key_begin);
|
||||
end = search_tag(pem_key_end, pos, key + len - pos);
|
||||
if (!end)
|
||||
return NULL;
|
||||
pos2 = search_tag("Proc-Type: 4,ENCRYPTED", pos, end - pos);
|
||||
if (pos2) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Unsupported private key "
|
||||
"format (Proc-Type/DEK-Info)");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
if (!der)
|
||||
return NULL;
|
||||
pkey = crypto_private_key_import(der, der_len, NULL);
|
||||
os_free(der);
|
||||
return pkey;
|
||||
}
|
||||
|
||||
|
||||
static struct crypto_private_key * tlsv1_set_key_enc_pem(const u8 *key,
|
||||
size_t len,
|
||||
const char *passwd)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
unsigned char *der;
|
||||
size_t der_len;
|
||||
struct crypto_private_key *pkey;
|
||||
|
||||
if (passwd == NULL)
|
||||
return NULL;
|
||||
pos = search_tag(pem_key_enc_begin, key, len);
|
||||
if (!pos)
|
||||
return NULL;
|
||||
pos += os_strlen(pem_key_enc_begin);
|
||||
end = search_tag(pem_key_enc_end, pos, key + len - pos);
|
||||
if (!end)
|
||||
return NULL;
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
if (!der)
|
||||
return NULL;
|
||||
pkey = crypto_private_key_import(der, der_len, passwd);
|
||||
os_free(der);
|
||||
return pkey;
|
||||
}
|
||||
|
||||
|
||||
static int tlsv1_set_key(struct tlsv1_credentials *cred,
|
||||
const u8 *key, size_t len, const char *passwd)
|
||||
{
|
||||
cred->key = crypto_private_key_import(key, len, passwd);
|
||||
if (cred->key == NULL)
|
||||
cred->key = tlsv1_set_key_pem(key, len);
|
||||
if (cred->key == NULL)
|
||||
cred->key = tlsv1_set_key_enc_pem(key, len, passwd);
|
||||
if (cred->key == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to parse private key");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_set_private_key - Set private key
|
||||
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
|
||||
* @private_key: File or reference name for the key in PEM or DER format
|
||||
* @private_key_passwd: Passphrase for decrypted private key, %NULL if no
|
||||
* passphrase is used.
|
||||
* @private_key_blob: private_key as inlined data or %NULL if not used
|
||||
* @private_key_blob_len: private_key_blob length
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_set_private_key(struct tlsv1_credentials *cred,
|
||||
const char *private_key,
|
||||
const char *private_key_passwd,
|
||||
const u8 *private_key_blob,
|
||||
size_t private_key_blob_len)
|
||||
{
|
||||
crypto_private_key_free(cred->key);
|
||||
cred->key = NULL;
|
||||
|
||||
if (private_key_blob)
|
||||
return tlsv1_set_key(cred, private_key_blob,
|
||||
private_key_blob_len,
|
||||
private_key_passwd);
|
||||
|
||||
if (private_key) {
|
||||
u8 *buf = NULL;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
//buf = (u8 *) os_readfile(private_key, &len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
|
||||
private_key);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = tlsv1_set_key(cred, buf, len, private_key_passwd);
|
||||
os_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tlsv1_set_dhparams_der(struct tlsv1_credentials *cred,
|
||||
const u8 *dh, size_t len)
|
||||
{
|
||||
struct asn1_hdr hdr;
|
||||
const u8 *pos, *end;
|
||||
|
||||
pos = dh;
|
||||
end = dh + len;
|
||||
|
||||
/*
|
||||
* DHParameter ::= SEQUENCE {
|
||||
* prime INTEGER, -- p
|
||||
* base INTEGER, -- g
|
||||
* privateValueLength INTEGER OPTIONAL }
|
||||
*/
|
||||
|
||||
/* DHParamer ::= SEQUENCE */
|
||||
if (asn1_get_next(pos, len, &hdr) < 0 ||
|
||||
hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_SEQUENCE) {
|
||||
wpa_printf(MSG_DEBUG, "DH: DH parameters did not start with a "
|
||||
"valid SEQUENCE - found class %d tag 0x%x",
|
||||
hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
pos = hdr.payload;
|
||||
|
||||
/* prime INTEGER */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0)
|
||||
return -1;
|
||||
|
||||
if (hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_INTEGER) {
|
||||
wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for p; "
|
||||
"class=%d tag=0x%x", hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "DH: prime (p)", hdr.payload, hdr.length);
|
||||
if (hdr.length == 0)
|
||||
return -1;
|
||||
os_free(cred->dh_p);
|
||||
cred->dh_p = os_malloc(hdr.length);
|
||||
if (cred->dh_p == NULL)
|
||||
return -1;
|
||||
os_memcpy(cred->dh_p, hdr.payload, hdr.length);
|
||||
cred->dh_p_len = hdr.length;
|
||||
pos = hdr.payload + hdr.length;
|
||||
|
||||
/* base INTEGER */
|
||||
if (asn1_get_next(pos, end - pos, &hdr) < 0)
|
||||
return -1;
|
||||
|
||||
if (hdr.class != ASN1_CLASS_UNIVERSAL ||
|
||||
hdr.tag != ASN1_TAG_INTEGER) {
|
||||
wpa_printf(MSG_DEBUG, "DH: No INTEGER tag found for g; "
|
||||
"class=%d tag=0x%x", hdr.class, hdr.tag);
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "DH: base (g)", hdr.payload, hdr.length);
|
||||
if (hdr.length == 0)
|
||||
return -1;
|
||||
os_free(cred->dh_g);
|
||||
cred->dh_g = os_malloc(hdr.length);
|
||||
if (cred->dh_g == NULL)
|
||||
return -1;
|
||||
os_memcpy(cred->dh_g, hdr.payload, hdr.length);
|
||||
cred->dh_g_len = hdr.length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char *pem_dhparams_begin = "-----BEGIN DH PARAMETERS-----";
|
||||
static const char *pem_dhparams_end = "-----END DH PARAMETERS-----";
|
||||
|
||||
|
||||
static int tlsv1_set_dhparams_blob(struct tlsv1_credentials *cred,
|
||||
const u8 *buf, size_t len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
unsigned char *der;
|
||||
size_t der_len;
|
||||
|
||||
pos = search_tag(pem_dhparams_begin, buf, len);
|
||||
if (!pos) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No PEM dhparams tag found - "
|
||||
"assume DER format");
|
||||
return tlsv1_set_dhparams_der(cred, buf, len);
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Converting PEM format dhparams into DER "
|
||||
"format");
|
||||
|
||||
pos += os_strlen(pem_dhparams_begin);
|
||||
end = search_tag(pem_dhparams_end, pos, buf + len - pos);
|
||||
if (end == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not find PEM dhparams end "
|
||||
"tag (%s)", pem_dhparams_end);
|
||||
return -1;
|
||||
}
|
||||
|
||||
der = base64_decode(pos, end - pos, &der_len);
|
||||
if (der == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Could not decode PEM dhparams");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_set_dhparams_der(cred, der, der_len) < 0) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to parse PEM dhparams "
|
||||
"DER conversion");
|
||||
os_free(der);
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(der);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_set_dhparams - Set Diffie-Hellman parameters
|
||||
* @cred: TLSv1 credentials from tlsv1_cred_alloc()
|
||||
* @dh_file: File or reference name for the DH params in PEM or DER format
|
||||
* @dh_blob: DH params as inlined data or %NULL if not used
|
||||
* @dh_blob_len: dh_blob length
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_set_dhparams(struct tlsv1_credentials *cred, const char *dh_file,
|
||||
const u8 *dh_blob, size_t dh_blob_len)
|
||||
{
|
||||
if (dh_blob)
|
||||
return tlsv1_set_dhparams_blob(cred, dh_blob, dh_blob_len);
|
||||
|
||||
if (dh_file) {
|
||||
u8 *buf = NULL;
|
||||
size_t len;
|
||||
int ret;
|
||||
|
||||
//buf = (u8 *) os_readfile(dh_file, &len);
|
||||
if (buf == NULL) {
|
||||
wpa_printf(MSG_INFO, "TLSv1: Failed to read '%s'",
|
||||
dh_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = tlsv1_set_dhparams_blob(cred, buf, len);
|
||||
os_free(buf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
553
components/wpa_supplicant/src/wpa2/tls/tlsv1_record.c
Normal file
553
components/wpa_supplicant/src/wpa2/tls/tlsv1_record.c
Normal file
|
@ -0,0 +1,553 @@
|
|||
/*
|
||||
* TLSv1 Record Protocol
|
||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "wpa2/tls/tlsv1_common.h"
|
||||
#include "wpa2/tls/tlsv1_record.h"
|
||||
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
|
||||
/**
|
||||
* tlsv1_record_set_cipher_suite - TLS record layer: Set cipher suite
|
||||
* @rl: Pointer to TLS record layer data
|
||||
* @cipher_suite: New cipher suite
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function is used to prepare TLS record layer for cipher suite change.
|
||||
* tlsv1_record_change_write_cipher() and
|
||||
* tlsv1_record_change_read_cipher() functions can then be used to change the
|
||||
* currently used ciphers.
|
||||
*/
|
||||
int tlsv1_record_set_cipher_suite(struct tlsv1_record_layer *rl,
|
||||
u16 cipher_suite)
|
||||
{
|
||||
const struct tls_cipher_suite *suite;
|
||||
const struct tls_cipher_data *data;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Selected cipher suite: 0x%04x",
|
||||
cipher_suite);
|
||||
rl->cipher_suite = cipher_suite;
|
||||
|
||||
suite = tls_get_cipher_suite(cipher_suite);
|
||||
if (suite == NULL)
|
||||
return -1;
|
||||
|
||||
if (suite->hash == TLS_HASH_MD5) {
|
||||
rl->hash_alg = CRYPTO_HASH_ALG_HMAC_MD5;
|
||||
rl->hash_size = MD5_MAC_LEN;
|
||||
} else if (suite->hash == TLS_HASH_SHA) {
|
||||
rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA1;
|
||||
rl->hash_size = SHA1_MAC_LEN;
|
||||
} else if (suite->hash == TLS_HASH_SHA256) {
|
||||
rl->hash_alg = CRYPTO_HASH_ALG_HMAC_SHA256;
|
||||
rl->hash_size = SHA256_MAC_LEN;
|
||||
}
|
||||
|
||||
data = tls_get_cipher_data(suite->cipher);
|
||||
if (data == NULL)
|
||||
return -1;
|
||||
|
||||
rl->key_material_len = data->key_material;
|
||||
rl->iv_size = data->block_size;
|
||||
rl->cipher_alg = data->alg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_record_change_write_cipher - TLS record layer: Change write cipher
|
||||
* @rl: Pointer to TLS record layer data
|
||||
* Returns: 0 on success (cipher changed), -1 on failure
|
||||
*
|
||||
* This function changes TLS record layer to use the new cipher suite
|
||||
* configured with tlsv1_record_set_cipher_suite() for writing.
|
||||
*/
|
||||
int tlsv1_record_change_write_cipher(struct tlsv1_record_layer *rl)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New write cipher suite "
|
||||
"0x%04x", rl->cipher_suite);
|
||||
rl->write_cipher_suite = rl->cipher_suite;
|
||||
os_memset(rl->write_seq_num, 0, TLS_SEQ_NUM_LEN);
|
||||
|
||||
if (rl->write_cbc) {
|
||||
if (wpa2_crypto_funcs.crypto_cipher_deinit) {
|
||||
wpa2_crypto_funcs.crypto_cipher_deinit(rl->write_cbc);
|
||||
rl->write_cbc = NULL;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
|
||||
if (wpa2_crypto_funcs.crypto_cipher_init) {
|
||||
rl->write_cbc = wpa2_crypto_funcs.crypto_cipher_init(rl->cipher_alg,
|
||||
rl->write_iv, rl->write_key,
|
||||
rl->key_material_len);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto_cipher_init function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rl->write_cbc == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
|
||||
"cipher");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_record_change_read_cipher - TLS record layer: Change read cipher
|
||||
* @rl: Pointer to TLS record layer data
|
||||
* Returns: 0 on success (cipher changed), -1 on failure
|
||||
*
|
||||
* This function changes TLS record layer to use the new cipher suite
|
||||
* configured with tlsv1_record_set_cipher_suite() for reading.
|
||||
*/
|
||||
int tlsv1_record_change_read_cipher(struct tlsv1_record_layer *rl)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - New read cipher suite "
|
||||
"0x%04x \n", rl->cipher_suite);
|
||||
rl->read_cipher_suite = rl->cipher_suite;
|
||||
os_memset(rl->read_seq_num, 0, TLS_SEQ_NUM_LEN);
|
||||
|
||||
if (rl->read_cbc) {
|
||||
if (wpa2_crypto_funcs.crypto_cipher_deinit) {
|
||||
wpa2_crypto_funcs.crypto_cipher_deinit(rl->read_cbc);
|
||||
rl->read_cbc = NULL;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto cipher deinit function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (rl->cipher_alg != CRYPTO_CIPHER_NULL) {
|
||||
if(wpa2_crypto_funcs.crypto_cipher_init) {
|
||||
rl->read_cbc = wpa2_crypto_funcs.crypto_cipher_init(rl->cipher_alg,
|
||||
rl->read_iv, rl->read_key,
|
||||
rl->key_material_len);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto_cipher_init function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
if (rl->read_cbc == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize "
|
||||
"cipher");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_record_send - TLS record layer: Send a message
|
||||
* @rl: Pointer to TLS record layer data
|
||||
* @content_type: Content type (TLS_CONTENT_TYPE_*)
|
||||
* @buf: Buffer for the generated TLS message (needs to have extra space for
|
||||
* header, IV (TLS v1.1), and HMAC)
|
||||
* @buf_size: Maximum buf size
|
||||
* @payload: Payload to be sent
|
||||
* @payload_len: Length of the payload
|
||||
* @out_len: Buffer for returning the used buf length
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function fills in the TLS record layer header, adds HMAC, and encrypts
|
||||
* the data using the current write cipher.
|
||||
*/
|
||||
int tlsv1_record_send(struct tlsv1_record_layer *rl, u8 content_type, u8 *buf,
|
||||
size_t buf_size, const u8 *payload, size_t payload_len,
|
||||
size_t *out_len)
|
||||
{
|
||||
u8 *pos, *ct_start, *length, *cpayload;
|
||||
struct crypto_hash *hmac = NULL;
|
||||
size_t clen;
|
||||
int explicit_iv;
|
||||
|
||||
pos = buf;
|
||||
if (pos + TLS_RECORD_HEADER_LEN > buf + buf_size)
|
||||
return -1;
|
||||
|
||||
/* ContentType type */
|
||||
ct_start = pos;
|
||||
*pos++ = content_type;
|
||||
/* ProtocolVersion version */
|
||||
WPA_PUT_BE16(pos, rl->tls_version);
|
||||
pos += 2;
|
||||
/* uint16 length */
|
||||
length = pos;
|
||||
WPA_PUT_BE16(length, payload_len);
|
||||
pos += 2;
|
||||
|
||||
cpayload = pos;
|
||||
explicit_iv = rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL &&
|
||||
rl->iv_size && rl->tls_version >= TLS_VERSION_1_1;
|
||||
if (explicit_iv) {
|
||||
/* opaque IV[Cipherspec.block_length] */
|
||||
if (pos + rl->iv_size > buf + buf_size)
|
||||
return -1;
|
||||
|
||||
/*
|
||||
* Use random number R per the RFC 4346, 6.2.3.2 CBC Block
|
||||
* Cipher option 2a.
|
||||
*/
|
||||
|
||||
if (os_get_random(pos, rl->iv_size))
|
||||
return -1;
|
||||
pos += rl->iv_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* opaque fragment[TLSPlaintext.length]
|
||||
* (opaque content[TLSCompressed.length] in GenericBlockCipher)
|
||||
*/
|
||||
if (pos + payload_len > buf + buf_size)
|
||||
return -1;
|
||||
os_memmove(pos, payload, payload_len);
|
||||
pos += payload_len;
|
||||
|
||||
if (rl->write_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
|
||||
/*
|
||||
* MAC calculated over seq_num + TLSCompressed.type +
|
||||
* TLSCompressed.version + TLSCompressed.length +
|
||||
* TLSCompressed.fragment
|
||||
*/
|
||||
if (wpa2_crypto_funcs.crypto_hash_init) {
|
||||
hmac = wpa2_crypto_funcs.crypto_hash_init(rl->hash_alg, rl->write_mac_secret, rl->hash_size);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash init!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
if (hmac == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
|
||||
"to initialize HMAC");
|
||||
return -1;
|
||||
}
|
||||
if (wpa2_crypto_funcs.crypto_hash_update) {
|
||||
wpa2_crypto_funcs.crypto_hash_update(hmac, rl->write_seq_num, TLS_SEQ_NUM_LEN);
|
||||
/* type + version + length + fragment */
|
||||
wpa2_crypto_funcs.crypto_hash_update(hmac, ct_start, TLS_RECORD_HEADER_LEN);
|
||||
wpa2_crypto_funcs.crypto_hash_update(hmac, payload, payload_len);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash update!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
clen = buf + buf_size - pos;
|
||||
if (clen < rl->hash_size) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Not "
|
||||
"enough room for MAC");
|
||||
if (wpa2_crypto_funcs.crypto_hash_finish) {
|
||||
wpa2_crypto_funcs.crypto_hash_finish(hmac, NULL, NULL);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash finish function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa2_crypto_funcs.crypto_hash_finish) {
|
||||
if ((int)wpa2_crypto_funcs.crypto_hash_finish(hmac, pos, (int *)&clen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC");
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n",__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Write HMAC",
|
||||
pos, clen);
|
||||
pos += clen;
|
||||
if (rl->iv_size) {
|
||||
size_t len = pos - cpayload;
|
||||
size_t pad;
|
||||
pad = (len + 1) % rl->iv_size;
|
||||
if (pad)
|
||||
pad = rl->iv_size - pad;
|
||||
if (pos + pad + 1 > buf + buf_size) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No room for "
|
||||
"block cipher padding");
|
||||
return -1;
|
||||
}
|
||||
os_memset(pos, pad, pad + 1);
|
||||
pos += pad + 1;
|
||||
}
|
||||
|
||||
if (wpa2_crypto_funcs.crypto_cipher_encrypt) {
|
||||
if ((int)wpa2_crypto_funcs.crypto_cipher_encrypt(rl->write_cbc, cpayload,
|
||||
cpayload, pos - cpayload) < 0)
|
||||
return -1;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto_cipher_encrypt function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
WPA_PUT_BE16(length, pos - length - 2);
|
||||
inc_byte_array(rl->write_seq_num, TLS_SEQ_NUM_LEN);
|
||||
|
||||
*out_len = pos - buf;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_record_receive - TLS record layer: Process a received message
|
||||
* @rl: Pointer to TLS record layer data
|
||||
* @in_data: Received data
|
||||
* @in_len: Length of the received data
|
||||
* @out_data: Buffer for output data (must be at least as long as in_data)
|
||||
* @out_len: Set to maximum out_data length by caller; used to return the
|
||||
* length of the used data
|
||||
* @alert: Buffer for returning an alert value on failure
|
||||
* Returns: Number of bytes used from in_data on success, 0 if record was not
|
||||
* complete (more data needed), or -1 on failure
|
||||
*
|
||||
* This function decrypts the received message, verifies HMAC and TLS record
|
||||
* layer header.
|
||||
*/
|
||||
int tlsv1_record_receive(struct tlsv1_record_layer *rl,
|
||||
const u8 *in_data, size_t in_len,
|
||||
u8 *out_data, size_t *out_len, u8 *alert)
|
||||
{
|
||||
size_t i, rlen, hlen;
|
||||
u8 padlen;
|
||||
struct crypto_hash *hmac = NULL;
|
||||
u8 len[2], hash[100];
|
||||
int force_mac_error = 0;
|
||||
u8 ct;
|
||||
|
||||
if (in_len < TLS_RECORD_HEADER_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Too short record (in_len=%lu) - "
|
||||
"need more data",
|
||||
(unsigned long) in_len);
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
|
||||
in_data, in_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ct = in_data[0];
|
||||
rlen = WPA_GET_BE16(in_data + 3);
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Received content type %d version %d.%d "
|
||||
"length %d", ct, in_data[1], in_data[2], (int) rlen);
|
||||
|
||||
/*
|
||||
* TLS v1.0 and v1.1 RFCs were not exactly clear on the use of the
|
||||
* protocol version in record layer. As such, accept any {03,xx} value
|
||||
* to remain compatible with existing implementations.
|
||||
*/
|
||||
if (in_data[1] != 0x03) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected protocol version "
|
||||
"%u.%u", in_data[1], in_data[2]);
|
||||
*alert = TLS_ALERT_PROTOCOL_VERSION;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* TLSCiphertext must not be more than 2^14+2048 bytes */
|
||||
if (TLS_RECORD_HEADER_LEN + rlen > 18432) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
|
||||
(unsigned long) (TLS_RECORD_HEADER_LEN + rlen));
|
||||
*alert = TLS_ALERT_RECORD_OVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
in_data += TLS_RECORD_HEADER_LEN;
|
||||
in_len -= TLS_RECORD_HEADER_LEN;
|
||||
|
||||
if (rlen > in_len) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not all record data included "
|
||||
"(rlen=%lu > in_len=%lu)",
|
||||
(unsigned long) rlen, (unsigned long) in_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: Record Layer - Received",
|
||||
in_data, rlen);
|
||||
|
||||
if (ct != TLS_CONTENT_TYPE_HANDSHAKE &&
|
||||
ct != TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC &&
|
||||
ct != TLS_CONTENT_TYPE_ALERT &&
|
||||
ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Ignore record with unknown "
|
||||
"content type 0x%x", ct);
|
||||
*alert = TLS_ALERT_UNEXPECTED_MESSAGE;
|
||||
return -1;
|
||||
}
|
||||
|
||||
in_len = rlen;
|
||||
|
||||
if (*out_len < in_len) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough output buffer for "
|
||||
"processing received record");
|
||||
*alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (rl->read_cipher_suite != TLS_NULL_WITH_NULL_NULL) {
|
||||
size_t plen;
|
||||
if (wpa2_crypto_funcs.crypto_cipher_decrypt) {
|
||||
if ((int)wpa2_crypto_funcs.crypto_cipher_decrypt(rl->read_cbc, in_data,
|
||||
out_data, in_len) < 0) {
|
||||
*alert = TLS_ALERT_DECRYPTION_FAILED;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto cipher decrypt function. \r\n");
|
||||
*alert = TLS_ALERT_DECRYPTION_FAILED;
|
||||
return -1;
|
||||
}
|
||||
plen = in_len;
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - Decrypted "
|
||||
"data", out_data, plen);
|
||||
|
||||
if (rl->iv_size) {
|
||||
/*
|
||||
* TLS v1.0 defines different alert values for various
|
||||
* failures. That may information to aid in attacks, so
|
||||
* use the same bad_record_mac alert regardless of the
|
||||
* issues.
|
||||
*
|
||||
* In addition, instead of returning immediately on
|
||||
* error, run through the MAC check to make timing
|
||||
* attacks more difficult.
|
||||
*/
|
||||
|
||||
if (rl->tls_version >= TLS_VERSION_1_1) {
|
||||
/* Remove opaque IV[Cipherspec.block_length] */
|
||||
if (plen < rl->iv_size) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1.1: Not "
|
||||
"enough room for IV");
|
||||
force_mac_error = 1;
|
||||
goto check_mac;
|
||||
}
|
||||
os_memmove(out_data, out_data + rl->iv_size,
|
||||
plen - rl->iv_size);
|
||||
plen -= rl->iv_size;
|
||||
}
|
||||
|
||||
/* Verify and remove padding */
|
||||
if (plen == 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Too short record"
|
||||
" (no pad)");
|
||||
force_mac_error = 1;
|
||||
goto check_mac;
|
||||
}
|
||||
padlen = out_data[plen - 1];
|
||||
if (padlen >= plen) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Incorrect pad "
|
||||
"length (%u, plen=%lu) in "
|
||||
"received record",
|
||||
padlen, (unsigned long) plen);
|
||||
force_mac_error = 1;
|
||||
goto check_mac;
|
||||
}
|
||||
for (i = plen - padlen - 1; i < plen - 1; i++) {
|
||||
if (out_data[i] != padlen) {
|
||||
wpa_hexdump(MSG_DEBUG,
|
||||
"TLSv1: Invalid pad in "
|
||||
"received record",
|
||||
out_data + plen - padlen -
|
||||
1, padlen + 1);
|
||||
force_mac_error = 1;
|
||||
goto check_mac;
|
||||
}
|
||||
}
|
||||
|
||||
plen -= padlen + 1;
|
||||
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Record Layer - "
|
||||
"Decrypted data with IV and padding "
|
||||
"removed", out_data, plen);
|
||||
}
|
||||
|
||||
check_mac:
|
||||
if (plen < rl->hash_size) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Too short record; no "
|
||||
"hash value");
|
||||
*alert = TLS_ALERT_BAD_RECORD_MAC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
plen -= rl->hash_size;
|
||||
|
||||
if (wpa2_crypto_funcs.crypto_hash_init) {
|
||||
hmac = wpa2_crypto_funcs.crypto_hash_init(rl->hash_alg, rl->read_mac_secret, rl->hash_size);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_init function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (hmac == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed "
|
||||
"to initialize HMAC");
|
||||
*alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wpa2_crypto_funcs.crypto_hash_update) {
|
||||
wpa2_crypto_funcs.crypto_hash_update(hmac, rl->read_seq_num, TLS_SEQ_NUM_LEN);
|
||||
/* type + version + length + fragment */
|
||||
wpa2_crypto_funcs.crypto_hash_update(hmac, in_data - TLS_RECORD_HEADER_LEN, 3);
|
||||
WPA_PUT_BE16(len, plen);
|
||||
wpa2_crypto_funcs.crypto_hash_update(hmac, len, 2);
|
||||
wpa2_crypto_funcs.crypto_hash_update(hmac, out_data, plen);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto hash update function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
hlen = sizeof(hash);
|
||||
if (wpa2_crypto_funcs.crypto_hash_finish) {
|
||||
if ((int)wpa2_crypto_funcs.crypto_hash_finish(hmac, hash, (int *)&hlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record Layer - Failed to calculate HMAC");
|
||||
*alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__);
|
||||
*alert = TLS_ALERT_INTERNAL_ERROR;
|
||||
return -1;
|
||||
}
|
||||
if (hlen != rl->hash_size ||
|
||||
os_memcmp(hash, out_data + plen, hlen) != 0 ||
|
||||
force_mac_error) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Invalid HMAC value in "
|
||||
"received message (force_mac_error=%d)",
|
||||
force_mac_error);
|
||||
*alert = TLS_ALERT_BAD_RECORD_MAC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*out_len = plen;
|
||||
} else {
|
||||
os_memcpy(out_data, in_data, in_len);
|
||||
*out_len = in_len;
|
||||
}
|
||||
|
||||
/* TLSCompressed must not be more than 2^14+1024 bytes */
|
||||
if (TLS_RECORD_HEADER_LEN + *out_len > 17408) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record overflow (len=%lu)",
|
||||
(unsigned long) (TLS_RECORD_HEADER_LEN + *out_len));
|
||||
*alert = TLS_ALERT_RECORD_OVERFLOW;
|
||||
return -1;
|
||||
}
|
||||
|
||||
inc_byte_array(rl->read_seq_num, TLS_SEQ_NUM_LEN);
|
||||
|
||||
return TLS_RECORD_HEADER_LEN + rlen;
|
||||
}
|
656
components/wpa_supplicant/src/wpa2/tls/tlsv1_server.c
Normal file
656
components/wpa_supplicant/src/wpa2/tls/tlsv1_server.c
Normal file
|
@ -0,0 +1,656 @@
|
|||
/*
|
||||
* TLS v1.0/v1.1/v1.2 server (RFC 2246, RFC 4346, RFC 5246)
|
||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/tls/tlsv1_common.h"
|
||||
#include "wpa2/tls/tlsv1_record.h"
|
||||
#include "wpa2/tls/tlsv1_server.h"
|
||||
#include "wpa2/tls/tlsv1_server_i.h"
|
||||
|
||||
/* TODO:
|
||||
* Support for a message fragmented across several records (RFC 2246, 6.2.1)
|
||||
*/
|
||||
|
||||
|
||||
void tlsv1_server_alert(struct tlsv1_server *conn, u8 level, u8 description)
|
||||
{
|
||||
conn->alert_level = level;
|
||||
conn->alert_description = description;
|
||||
}
|
||||
|
||||
|
||||
int tlsv1_server_derive_keys(struct tlsv1_server *conn,
|
||||
const u8 *pre_master_secret,
|
||||
size_t pre_master_secret_len)
|
||||
{
|
||||
u8 seed[2 * TLS_RANDOM_LEN];
|
||||
u8 key_block[TLS_MAX_KEY_BLOCK_LEN];
|
||||
u8 *pos;
|
||||
size_t key_block_len;
|
||||
|
||||
if (pre_master_secret) {
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: pre_master_secret",
|
||||
pre_master_secret, pre_master_secret_len);
|
||||
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
|
||||
TLS_RANDOM_LEN);
|
||||
if (tls_prf(conn->rl.tls_version,
|
||||
pre_master_secret, pre_master_secret_len,
|
||||
"master secret", seed, 2 * TLS_RANDOM_LEN,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive "
|
||||
"master_secret");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: master_secret",
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN);
|
||||
}
|
||||
|
||||
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random, TLS_RANDOM_LEN);
|
||||
key_block_len = 2 * (conn->rl.hash_size + conn->rl.key_material_len +
|
||||
conn->rl.iv_size);
|
||||
if (tls_prf(conn->rl.tls_version,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN,
|
||||
"key expansion", seed, 2 * TLS_RANDOM_LEN,
|
||||
key_block, key_block_len)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to derive key_block");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: key_block",
|
||||
key_block, key_block_len);
|
||||
|
||||
pos = key_block;
|
||||
|
||||
/* client_write_MAC_secret */
|
||||
os_memcpy(conn->rl.read_mac_secret, pos, conn->rl.hash_size);
|
||||
pos += conn->rl.hash_size;
|
||||
/* server_write_MAC_secret */
|
||||
os_memcpy(conn->rl.write_mac_secret, pos, conn->rl.hash_size);
|
||||
pos += conn->rl.hash_size;
|
||||
|
||||
/* client_write_key */
|
||||
os_memcpy(conn->rl.read_key, pos, conn->rl.key_material_len);
|
||||
pos += conn->rl.key_material_len;
|
||||
/* server_write_key */
|
||||
os_memcpy(conn->rl.write_key, pos, conn->rl.key_material_len);
|
||||
pos += conn->rl.key_material_len;
|
||||
|
||||
/* client_write_IV */
|
||||
os_memcpy(conn->rl.read_iv, pos, conn->rl.iv_size);
|
||||
pos += conn->rl.iv_size;
|
||||
/* server_write_IV */
|
||||
os_memcpy(conn->rl.write_iv, pos, conn->rl.iv_size);
|
||||
pos += conn->rl.iv_size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_handshake - Process TLS handshake
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @in_data: Input data from TLS peer
|
||||
* @in_len: Input data length
|
||||
* @out_len: Length of the output buffer.
|
||||
* Returns: Pointer to output data, %NULL on failure
|
||||
*/
|
||||
u8 * tlsv1_server_handshake(struct tlsv1_server *conn,
|
||||
const u8 *in_data, size_t in_len,
|
||||
size_t *out_len)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u8 *msg = NULL, *in_msg, *in_pos, *in_end, alert, ct;
|
||||
size_t in_msg_len;
|
||||
int used;
|
||||
|
||||
if (in_data == NULL || in_len == 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No input data to server");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = in_data;
|
||||
end = in_data + in_len;
|
||||
in_msg = os_malloc(in_len);
|
||||
if (in_msg == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Each received packet may include multiple records */
|
||||
while (pos < end) {
|
||||
in_msg_len = in_len;
|
||||
used = tlsv1_record_receive(&conn->rl, pos, end - pos,
|
||||
in_msg, &in_msg_len, &alert);
|
||||
if (used < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Processing received "
|
||||
"record failed");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
|
||||
goto failed;
|
||||
}
|
||||
if (used == 0) {
|
||||
/* need more data */
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
|
||||
"yet supported");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
|
||||
goto failed;
|
||||
}
|
||||
ct = pos[0];
|
||||
|
||||
in_pos = in_msg;
|
||||
in_end = in_msg + in_msg_len;
|
||||
|
||||
/* Each received record may include multiple messages of the
|
||||
* same ContentType. */
|
||||
while (in_pos < in_end) {
|
||||
in_msg_len = in_end - in_pos;
|
||||
if (tlsv1_server_process_handshake(conn, ct, in_pos,
|
||||
&in_msg_len) < 0)
|
||||
goto failed;
|
||||
in_pos += in_msg_len;
|
||||
}
|
||||
|
||||
pos += used;
|
||||
}
|
||||
|
||||
os_free(in_msg);
|
||||
in_msg = NULL;
|
||||
|
||||
msg = tlsv1_server_handshake_write(conn, out_len);
|
||||
|
||||
failed:
|
||||
os_free(in_msg);
|
||||
if (conn->alert_level) {
|
||||
if (conn->state == FAILED) {
|
||||
/* Avoid alert loops */
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Drop alert loop");
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
conn->state = FAILED;
|
||||
os_free(msg);
|
||||
msg = tlsv1_server_send_alert(conn, conn->alert_level,
|
||||
conn->alert_description,
|
||||
out_len);
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_encrypt - Encrypt data into TLS tunnel
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @in_data: Pointer to plaintext data to be encrypted
|
||||
* @in_len: Input buffer length
|
||||
* @out_data: Pointer to output buffer (encrypted TLS data)
|
||||
* @out_len: Maximum out_data length
|
||||
* Returns: Number of bytes written to out_data, -1 on failure
|
||||
*
|
||||
* This function is used after TLS handshake has been completed successfully to
|
||||
* send data in the encrypted tunnel.
|
||||
*/
|
||||
int tlsv1_server_encrypt(struct tlsv1_server *conn,
|
||||
const u8 *in_data, size_t in_len,
|
||||
u8 *out_data, size_t out_len)
|
||||
{
|
||||
size_t rlen;
|
||||
|
||||
wpa_hexdump_key(MSG_MSGDUMP, "TLSv1: Plaintext AppData",
|
||||
in_data, in_len);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_APPLICATION_DATA,
|
||||
out_data, out_len, in_data, in_len, &rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return rlen;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_decrypt - Decrypt data from TLS tunnel
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @in_data: Pointer to input buffer (encrypted TLS data)
|
||||
* @in_len: Input buffer length
|
||||
* @out_data: Pointer to output buffer (decrypted data from TLS tunnel)
|
||||
* @out_len: Maximum out_data length
|
||||
* Returns: Number of bytes written to out_data, -1 on failure
|
||||
*
|
||||
* This function is used after TLS handshake has been completed successfully to
|
||||
* receive data from the encrypted tunnel.
|
||||
*/
|
||||
int tlsv1_server_decrypt(struct tlsv1_server *conn,
|
||||
const u8 *in_data, size_t in_len,
|
||||
u8 *out_data, size_t out_len)
|
||||
{
|
||||
const u8 *in_end, *pos;
|
||||
int used;
|
||||
u8 alert, *out_end, *out_pos, ct;
|
||||
size_t olen;
|
||||
|
||||
pos = in_data;
|
||||
in_end = in_data + in_len;
|
||||
out_pos = out_data;
|
||||
out_end = out_data + out_len;
|
||||
|
||||
while (pos < in_end) {
|
||||
ct = pos[0];
|
||||
olen = out_end - out_pos;
|
||||
used = tlsv1_record_receive(&conn->rl, pos, in_end - pos,
|
||||
out_pos, &olen, &alert);
|
||||
if (used < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Record layer processing "
|
||||
"failed");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
|
||||
return -1;
|
||||
}
|
||||
if (used == 0) {
|
||||
/* need more data */
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Partial processing not "
|
||||
"yet supported");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL, alert);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ct == TLS_CONTENT_TYPE_ALERT) {
|
||||
if (olen < 2) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Alert "
|
||||
"underflow");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_DECODE_ERROR);
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Received alert %d:%d",
|
||||
out_pos[0], out_pos[1]);
|
||||
if (out_pos[0] == TLS_ALERT_LEVEL_WARNING) {
|
||||
/* Continue processing */
|
||||
pos += used;
|
||||
continue;
|
||||
}
|
||||
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
out_pos[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ct != TLS_CONTENT_TYPE_APPLICATION_DATA) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected content type "
|
||||
"0x%x", pos[0]);
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_UNEXPECTED_MESSAGE);
|
||||
return -1;
|
||||
}
|
||||
|
||||
out_pos += olen;
|
||||
if (out_pos > out_end) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Buffer not large enough "
|
||||
"for processing the received record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos += used;
|
||||
}
|
||||
|
||||
return out_pos - out_data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_global_init - Initialize TLSv1 server
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* This function must be called before using any other TLSv1 server functions.
|
||||
*/
|
||||
int tlsv1_server_global_init(void)
|
||||
{
|
||||
return crypto_global_init();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_global_deinit - Deinitialize TLSv1 server
|
||||
*
|
||||
* This function can be used to deinitialize the TLSv1 server that was
|
||||
* initialized by calling tlsv1_server_global_init(). No TLSv1 server functions
|
||||
* can be called after this before calling tlsv1_server_global_init() again.
|
||||
*/
|
||||
void tlsv1_server_global_deinit(void)
|
||||
{
|
||||
crypto_global_deinit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_init - Initialize TLSv1 server connection
|
||||
* @cred: Pointer to server credentials from tlsv1_server_cred_alloc()
|
||||
* Returns: Pointer to TLSv1 server connection data or %NULL on failure
|
||||
*/
|
||||
struct tlsv1_server * tlsv1_server_init(struct tlsv1_credentials *cred)
|
||||
{
|
||||
struct tlsv1_server *conn;
|
||||
size_t count;
|
||||
u16 *suites;
|
||||
|
||||
conn = (struct tlsv1_server *)os_zalloc(sizeof(*conn));
|
||||
if (conn == NULL)
|
||||
return NULL;
|
||||
|
||||
conn->cred = cred;
|
||||
|
||||
conn->state = CLIENT_HELLO;
|
||||
|
||||
if (tls_verify_hash_init(&conn->verify) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to initialize verify "
|
||||
"hash");
|
||||
os_free(conn);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
suites = conn->cipher_suites;
|
||||
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
|
||||
conn->num_cipher_suites = count;
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
static void tlsv1_server_clear_data(struct tlsv1_server *conn)
|
||||
{
|
||||
tlsv1_record_set_cipher_suite(&conn->rl, TLS_NULL_WITH_NULL_NULL);
|
||||
tlsv1_record_change_write_cipher(&conn->rl);
|
||||
tlsv1_record_change_read_cipher(&conn->rl);
|
||||
tls_verify_hash_free(&conn->verify);
|
||||
|
||||
crypto_public_key_free(conn->client_rsa_key);
|
||||
conn->client_rsa_key = NULL;
|
||||
|
||||
os_free(conn->session_ticket);
|
||||
conn->session_ticket = NULL;
|
||||
conn->session_ticket_len = 0;
|
||||
conn->use_session_ticket = 0;
|
||||
|
||||
os_free(conn->dh_secret);
|
||||
conn->dh_secret = NULL;
|
||||
conn->dh_secret_len = 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_deinit - Deinitialize TLSv1 server connection
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
*/
|
||||
void tlsv1_server_deinit(struct tlsv1_server *conn)
|
||||
{
|
||||
tlsv1_server_clear_data(conn);
|
||||
os_free(conn);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_established - Check whether connection has been established
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* Returns: 1 if connection is established, 0 if not
|
||||
*/
|
||||
int tlsv1_server_established(struct tlsv1_server *conn)
|
||||
{
|
||||
return conn->state == ESTABLISHED;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_prf - Use TLS-PRF to derive keying material
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @label: Label (e.g., description of the key) for PRF
|
||||
* @server_random_first: seed is 0 = client_random|server_random,
|
||||
* 1 = server_random|client_random
|
||||
* @out: Buffer for output data from TLS-PRF
|
||||
* @out_len: Length of the output buffer
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_server_prf(struct tlsv1_server *conn, const char *label,
|
||||
int server_random_first, u8 *out, size_t out_len)
|
||||
{
|
||||
u8 seed[2 * TLS_RANDOM_LEN];
|
||||
|
||||
if (conn->state != ESTABLISHED)
|
||||
return -1;
|
||||
|
||||
if (server_random_first) {
|
||||
os_memcpy(seed, conn->server_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->client_random,
|
||||
TLS_RANDOM_LEN);
|
||||
} else {
|
||||
os_memcpy(seed, conn->client_random, TLS_RANDOM_LEN);
|
||||
os_memcpy(seed + TLS_RANDOM_LEN, conn->server_random,
|
||||
TLS_RANDOM_LEN);
|
||||
}
|
||||
|
||||
return tls_prf(conn->rl.tls_version,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN,
|
||||
label, seed, 2 * TLS_RANDOM_LEN, out, out_len);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_get_cipher - Get current cipher name
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @buf: Buffer for the cipher name
|
||||
* @buflen: buf size
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*
|
||||
* Get the name of the currently used cipher.
|
||||
*/
|
||||
int tlsv1_server_get_cipher(struct tlsv1_server *conn, char *buf,
|
||||
size_t buflen)
|
||||
{
|
||||
#ifndef ESPRESSIF_USE
|
||||
char *cipher;
|
||||
|
||||
switch (conn->rl.cipher_suite) {
|
||||
case TLS_RSA_WITH_RC4_128_MD5:
|
||||
cipher = "RC4-MD5";
|
||||
break;
|
||||
case TLS_RSA_WITH_RC4_128_SHA:
|
||||
cipher = "RC4-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_DES_CBC_SHA:
|
||||
cipher = "DES-CBC-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
cipher = "DES-CBC3-SHA";
|
||||
break;
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
|
||||
cipher = "ADH-AES-128-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||
cipher = "AES-256-SHA";
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA:
|
||||
cipher = "AES-128-SHA";
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
|
||||
//if (os_strlcpy(buf, cipher, buflen) >= buflen)
|
||||
// return -1;
|
||||
|
||||
os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
|
||||
|
||||
return 0;
|
||||
#else
|
||||
char cipher[20];
|
||||
|
||||
switch (conn->rl.cipher_suite) {
|
||||
case TLS_RSA_WITH_RC4_128_MD5:
|
||||
strcpy(cipher, "RC4-MD5");
|
||||
break;
|
||||
case TLS_RSA_WITH_RC4_128_SHA:
|
||||
strcpy(cipher, "RC4-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_DES_CBC_SHA:
|
||||
strcpy(cipher, "DES-CBC-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
|
||||
strcpy(cipher, "DES-CBC3-SHA");
|
||||
break;
|
||||
case TLS_DH_anon_WITH_AES_128_CBC_SHA:
|
||||
strcpy(cipher, "ADH-AES-128-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_256_CBC_SHA:
|
||||
strcpy(cipher, "AES-256-SHA");
|
||||
break;
|
||||
case TLS_RSA_WITH_AES_128_CBC_SHA:
|
||||
strcpy(cipher, "AES-128-SHA");
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
}
|
||||
os_memcpy((u8 *)buf, (u8 *)cipher, buflen);
|
||||
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_shutdown - Shutdown TLS connection
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_server_shutdown(struct tlsv1_server *conn)
|
||||
{
|
||||
conn->state = CLIENT_HELLO;
|
||||
|
||||
if (tls_verify_hash_init(&conn->verify) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to re-initialize verify "
|
||||
"hash");
|
||||
return -1;
|
||||
}
|
||||
|
||||
tlsv1_server_clear_data(conn);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_resumed - Was session resumption used
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* Returns: 1 if current session used session resumption, 0 if not
|
||||
*/
|
||||
int tlsv1_server_resumed(struct tlsv1_server *conn)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_get_keys - Get master key and random data from TLS connection
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @keys: Structure of key/random data (filled on success)
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_server_get_keys(struct tlsv1_server *conn, struct tls_keys *keys)
|
||||
{
|
||||
os_memset(keys, 0, sizeof(*keys));
|
||||
if (conn->state == CLIENT_HELLO)
|
||||
return -1;
|
||||
|
||||
keys->client_random = conn->client_random;
|
||||
keys->client_random_len = TLS_RANDOM_LEN;
|
||||
|
||||
if (conn->state != SERVER_HELLO) {
|
||||
keys->server_random = conn->server_random;
|
||||
keys->server_random_len = TLS_RANDOM_LEN;
|
||||
keys->master_key = conn->master_secret;
|
||||
keys->master_key_len = TLS_MASTER_SECRET_LEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_get_keyblock_size - Get TLS key_block size
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* Returns: Size of the key_block for the negotiated cipher suite or -1 on
|
||||
* failure
|
||||
*/
|
||||
int tlsv1_server_get_keyblock_size(struct tlsv1_server *conn)
|
||||
{
|
||||
if (conn->state == CLIENT_HELLO || conn->state == SERVER_HELLO)
|
||||
return -1;
|
||||
|
||||
return 2 * (conn->rl.hash_size + conn->rl.key_material_len +
|
||||
conn->rl.iv_size);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* tlsv1_server_set_cipher_list - Configure acceptable cipher suites
|
||||
* @conn: TLSv1 server connection data from tlsv1_server_init()
|
||||
* @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
|
||||
* (TLS_CIPHER_*).
|
||||
* Returns: 0 on success, -1 on failure
|
||||
*/
|
||||
int tlsv1_server_set_cipher_list(struct tlsv1_server *conn, u8 *ciphers)
|
||||
{
|
||||
size_t count;
|
||||
u16 *suites;
|
||||
|
||||
/* TODO: implement proper configuration of cipher suites */
|
||||
if (ciphers[0] == TLS_CIPHER_ANON_DH_AES128_SHA) {
|
||||
count = 0;
|
||||
suites = conn->cipher_suites;
|
||||
suites[count++] = TLS_RSA_WITH_AES_256_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_AES_128_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_3DES_EDE_CBC_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_RC4_128_SHA;
|
||||
suites[count++] = TLS_RSA_WITH_RC4_128_MD5;
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_256_CBC_SHA;
|
||||
suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
|
||||
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
|
||||
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
|
||||
suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
|
||||
conn->num_cipher_suites = count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tlsv1_server_set_verify(struct tlsv1_server *conn, int verify_peer)
|
||||
{
|
||||
conn->verify_peer = verify_peer;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void tlsv1_server_set_session_ticket_cb(struct tlsv1_server *conn,
|
||||
tlsv1_server_session_ticket_cb cb,
|
||||
void *ctx)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback set %p (ctx %p)",
|
||||
cb, ctx);
|
||||
conn->session_ticket_cb = cb;
|
||||
conn->session_ticket_cb_ctx = ctx;
|
||||
}
|
1278
components/wpa_supplicant/src/wpa2/tls/tlsv1_server_read.c
Normal file
1278
components/wpa_supplicant/src/wpa2/tls/tlsv1_server_read.c
Normal file
File diff suppressed because it is too large
Load diff
819
components/wpa_supplicant/src/wpa2/tls/tlsv1_server_write.c
Normal file
819
components/wpa_supplicant/src/wpa2/tls/tlsv1_server_write.c
Normal file
|
@ -0,0 +1,819 @@
|
|||
/*
|
||||
* TLSv1 server - write handshake message
|
||||
* Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/md5.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
#include "wpa2/tls/tls.h"
|
||||
#include "wpa2/tls/x509v3.h"
|
||||
#include "wpa2/tls/tlsv1_common.h"
|
||||
#include "wpa2/tls/tlsv1_record.h"
|
||||
#include "wpa2/tls/tlsv1_server.h"
|
||||
#include "wpa2/tls/tlsv1_server_i.h"
|
||||
|
||||
#include "wpa2/eap_peer/eap_i.h"
|
||||
|
||||
static size_t tls_server_cert_chain_der_len(struct tlsv1_server *conn)
|
||||
{
|
||||
size_t len = 0;
|
||||
struct x509_certificate *cert;
|
||||
|
||||
cert = conn->cred->cert;
|
||||
while (cert) {
|
||||
len += 3 + cert->cert_len;
|
||||
if (x509_certificate_self_signed(cert))
|
||||
break;
|
||||
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
|
||||
&cert->issuer);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_server_hello(struct tlsv1_server *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length;
|
||||
struct os_time now;
|
||||
size_t rlen;
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHello");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
os_get_time(&now);
|
||||
WPA_PUT_BE32(conn->server_random, now.sec);
|
||||
if (random_get_bytes(conn->server_random + 4, TLS_RANDOM_LEN - 4)) {
|
||||
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
|
||||
"server_random");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: server_random",
|
||||
conn->server_random, TLS_RANDOM_LEN);
|
||||
|
||||
conn->session_id_len = TLS_SESSION_ID_MAX_LEN;
|
||||
if (random_get_bytes(conn->session_id, conn->session_id_len)) {
|
||||
wpa_printf(MSG_ERROR, "TLSv1: Could not generate "
|
||||
"session_id");
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump(MSG_MSGDUMP, "TLSv1: session_id",
|
||||
conn->session_id, conn->session_id_len);
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
/* body - ServerHello */
|
||||
/* ProtocolVersion server_version */
|
||||
WPA_PUT_BE16(pos, conn->rl.tls_version);
|
||||
pos += 2;
|
||||
/* Random random: uint32 gmt_unix_time, opaque random_bytes */
|
||||
os_memcpy(pos, conn->server_random, TLS_RANDOM_LEN);
|
||||
pos += TLS_RANDOM_LEN;
|
||||
/* SessionID session_id */
|
||||
*pos++ = conn->session_id_len;
|
||||
os_memcpy(pos, conn->session_id, conn->session_id_len);
|
||||
pos += conn->session_id_len;
|
||||
/* CipherSuite cipher_suite */
|
||||
WPA_PUT_BE16(pos, conn->cipher_suite);
|
||||
pos += 2;
|
||||
/* CompressionMethod compression_method */
|
||||
*pos++ = TLS_COMPRESSION_NULL;
|
||||
|
||||
if (conn->session_ticket && conn->session_ticket_cb) {
|
||||
int res = conn->session_ticket_cb(
|
||||
conn->session_ticket_cb_ctx,
|
||||
conn->session_ticket, conn->session_ticket_len,
|
||||
conn->client_random, conn->server_random,
|
||||
conn->master_secret);
|
||||
if (res < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: SessionTicket callback "
|
||||
"indicated failure");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_HANDSHAKE_FAILURE);
|
||||
return -1;
|
||||
}
|
||||
conn->use_session_ticket = res;
|
||||
|
||||
if (conn->use_session_ticket) {
|
||||
if (tlsv1_server_derive_keys(conn, NULL, 0) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to "
|
||||
"derive keys");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* RFC 4507 specifies that server would include an empty
|
||||
* SessionTicket extension in ServerHello and a
|
||||
* NewSessionTicket message after the ServerHello. However,
|
||||
* EAP-FAST (RFC 4851), i.e., the only user of SessionTicket
|
||||
* extension at the moment, does not use such extensions.
|
||||
*
|
||||
* TODO: Add support for configuring RFC 4507 behavior and make
|
||||
* EAP-FAST disable it.
|
||||
*/
|
||||
}
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create TLS record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
pos = rhdr + rlen;
|
||||
|
||||
*msgpos = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_server_certificate(struct tlsv1_server *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length, *cert_start;
|
||||
size_t rlen;
|
||||
struct x509_certificate *cert;
|
||||
const struct tls_cipher_suite *suite;
|
||||
|
||||
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
|
||||
if (suite && suite->key_exchange == TLS_KEY_X_DH_anon) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Do not send Certificate when "
|
||||
"using anonymous DH");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send Certificate");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
/* body - Certificate */
|
||||
/* uint24 length (to be filled) */
|
||||
cert_start = pos;
|
||||
pos += 3;
|
||||
cert = conn->cred->cert;
|
||||
while (cert) {
|
||||
if (pos + 3 + cert->cert_len > end) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space "
|
||||
"for Certificate (cert_len=%lu left=%lu)",
|
||||
(unsigned long) cert->cert_len,
|
||||
(unsigned long) (end - pos));
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE24(pos, cert->cert_len);
|
||||
pos += 3;
|
||||
os_memcpy(pos, cert->cert_start, cert->cert_len);
|
||||
pos += cert->cert_len;
|
||||
|
||||
if (x509_certificate_self_signed(cert))
|
||||
break;
|
||||
cert = x509_certificate_get_subject(conn->cred->trusted_certs,
|
||||
&cert->issuer);
|
||||
}
|
||||
if (cert == conn->cred->cert || cert == NULL) {
|
||||
/*
|
||||
* Server was not configured with all the needed certificates
|
||||
* to form a full certificate chain. The client may fail to
|
||||
* validate the chain unless it is configured with all the
|
||||
* missing CA certificates.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Full server certificate chain "
|
||||
"not configured - validation may fail");
|
||||
}
|
||||
WPA_PUT_BE24(cert_start, pos - cert_start - 3);
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
pos = rhdr + rlen;
|
||||
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
*msgpos = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_server_key_exchange(struct tlsv1_server *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
tls_key_exchange keyx;
|
||||
const struct tls_cipher_suite *suite;
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length;
|
||||
size_t rlen;
|
||||
u8 *dh_ys;
|
||||
size_t dh_ys_len;
|
||||
|
||||
suite = tls_get_cipher_suite(conn->rl.cipher_suite);
|
||||
if (suite == NULL)
|
||||
keyx = TLS_KEY_X_NULL;
|
||||
else
|
||||
keyx = suite->key_exchange;
|
||||
|
||||
if (!tls_server_key_exchange_allowed(conn->rl.cipher_suite)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No ServerKeyExchange needed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (keyx != TLS_KEY_X_DH_anon) {
|
||||
/* TODO? */
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: ServerKeyExchange not yet "
|
||||
"supported with key exchange type %d", keyx);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conn->cred == NULL || conn->cred->dh_p == NULL ||
|
||||
conn->cred->dh_g == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No DH parameters available for "
|
||||
"ServerKeyExhcange");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_free(conn->dh_secret);
|
||||
conn->dh_secret_len = conn->cred->dh_p_len;
|
||||
conn->dh_secret = os_malloc(conn->dh_secret_len);
|
||||
if (conn->dh_secret == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate "
|
||||
"memory for secret (Diffie-Hellman)");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if (random_get_bytes(conn->dh_secret, conn->dh_secret_len)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to get random "
|
||||
"data for Diffie-Hellman");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(conn->dh_secret);
|
||||
conn->dh_secret = NULL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (os_memcmp(conn->dh_secret, conn->cred->dh_p, conn->dh_secret_len) >
|
||||
0)
|
||||
conn->dh_secret[0] = 0; /* make sure secret < p */
|
||||
|
||||
pos = conn->dh_secret;
|
||||
while (pos + 1 < conn->dh_secret + conn->dh_secret_len && *pos == 0)
|
||||
pos++;
|
||||
if (pos != conn->dh_secret) {
|
||||
os_memmove(conn->dh_secret, pos,
|
||||
conn->dh_secret_len - (pos - conn->dh_secret));
|
||||
conn->dh_secret_len -= pos - conn->dh_secret;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "TLSv1: DH server's secret value",
|
||||
conn->dh_secret, conn->dh_secret_len);
|
||||
|
||||
/* Ys = g^secret mod p */
|
||||
dh_ys_len = conn->cred->dh_p_len;
|
||||
dh_ys = os_malloc(dh_ys_len);
|
||||
if (dh_ys == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to allocate memory for "
|
||||
"Diffie-Hellman");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
if(wpa2_crypto_funcs.crypto_mod_exp) {
|
||||
if (wpa2_crypto_funcs.crypto_mod_exp(conn->cred->dh_g, conn->cred->dh_g_len,
|
||||
conn->dh_secret, conn->dh_secret_len,
|
||||
conn->cred->dh_p, conn->cred->dh_p_len,
|
||||
dh_ys, &dh_ys_len)) {
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(dh_ys);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(dh_ys);
|
||||
wpa_printf(MSG_ERROR, "Fail to register crypto_mod_exp function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "TLSv1: DH Ys (server's public value)",
|
||||
dh_ys, dh_ys_len);
|
||||
|
||||
/*
|
||||
* struct {
|
||||
* select (KeyExchangeAlgorithm) {
|
||||
* case diffie_hellman:
|
||||
* ServerDHParams params;
|
||||
* Signature signed_params;
|
||||
* case rsa:
|
||||
* ServerRSAParams params;
|
||||
* Signature signed_params;
|
||||
* };
|
||||
* } ServerKeyExchange;
|
||||
*
|
||||
* struct {
|
||||
* opaque dh_p<1..2^16-1>;
|
||||
* opaque dh_g<1..2^16-1>;
|
||||
* opaque dh_Ys<1..2^16-1>;
|
||||
* } ServerDHParams;
|
||||
*/
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerKeyExchange");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_SERVER_KEY_EXCHANGE;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
|
||||
/* body - ServerDHParams */
|
||||
/* dh_p */
|
||||
if (pos + 2 + conn->cred->dh_p_len > end) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
|
||||
"dh_p");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(dh_ys);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE16(pos, conn->cred->dh_p_len);
|
||||
pos += 2;
|
||||
os_memcpy(pos, conn->cred->dh_p, conn->cred->dh_p_len);
|
||||
pos += conn->cred->dh_p_len;
|
||||
|
||||
/* dh_g */
|
||||
if (pos + 2 + conn->cred->dh_g_len > end) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
|
||||
"dh_g");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(dh_ys);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE16(pos, conn->cred->dh_g_len);
|
||||
pos += 2;
|
||||
os_memcpy(pos, conn->cred->dh_g, conn->cred->dh_g_len);
|
||||
pos += conn->cred->dh_g_len;
|
||||
|
||||
/* dh_Ys */
|
||||
if (pos + 2 + dh_ys_len > end) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Not enough buffer space for "
|
||||
"dh_Ys");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
os_free(dh_ys);
|
||||
return -1;
|
||||
}
|
||||
WPA_PUT_BE16(pos, dh_ys_len);
|
||||
pos += 2;
|
||||
os_memcpy(pos, dh_ys, dh_ys_len);
|
||||
pos += dh_ys_len;
|
||||
os_free(dh_ys);
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
pos = rhdr + rlen;
|
||||
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
*msgpos = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_server_certificate_request(struct tlsv1_server *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *rhdr, *hs_start, *hs_length;
|
||||
size_t rlen;
|
||||
|
||||
if (!conn->verify_peer) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: No CertificateRequest needed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send CertificateRequest");
|
||||
rhdr = pos;
|
||||
pos += TLS_RECORD_HEADER_LEN;
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
hs_start = pos;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_CERTIFICATE_REQUEST;
|
||||
/* uint24 length (to be filled) */
|
||||
hs_length = pos;
|
||||
pos += 3;
|
||||
/* body - CertificateRequest */
|
||||
|
||||
/*
|
||||
* enum {
|
||||
* rsa_sign(1), dss_sign(2), rsa_fixed_dh(3), dss_fixed_dh(4),
|
||||
* (255)
|
||||
* } ClientCertificateType;
|
||||
* ClientCertificateType certificate_types<1..2^8-1>
|
||||
*/
|
||||
*pos++ = 1;
|
||||
*pos++ = 1; /* rsa_sign */
|
||||
|
||||
/*
|
||||
* opaque DistinguishedName<1..2^16-1>
|
||||
* DistinguishedName certificate_authorities<3..2^16-1>
|
||||
*/
|
||||
/* TODO: add support for listing DNs for trusted CAs */
|
||||
WPA_PUT_BE16(pos, 0);
|
||||
pos += 2;
|
||||
|
||||
WPA_PUT_BE24(hs_length, pos - hs_length - 3);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
rhdr, end - rhdr, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
pos = rhdr + rlen;
|
||||
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
*msgpos = pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_server_hello_done(struct tlsv1_server *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos;
|
||||
size_t rlen;
|
||||
u8 payload[4];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ServerHelloDone");
|
||||
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Handshake */
|
||||
pos = payload;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_SERVER_HELLO_DONE;
|
||||
/* uint24 length */
|
||||
WPA_PUT_BE24(pos, 0);
|
||||
pos += 3;
|
||||
/* body - ServerHelloDone (empty) */
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
*msgpos, end - *msgpos, payload, pos - payload,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate a record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
tls_verify_hash_add(&conn->verify, payload, pos - payload);
|
||||
|
||||
*msgpos += rlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_server_change_cipher_spec(struct tlsv1_server *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
size_t rlen;
|
||||
u8 payload[1];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send ChangeCipherSpec");
|
||||
|
||||
payload[0] = TLS_CHANGE_CIPHER_SPEC;
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC,
|
||||
*msgpos, end - *msgpos, payload, sizeof(payload),
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (tlsv1_record_change_write_cipher(&conn->rl) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to set write cipher for "
|
||||
"record layer");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*msgpos += rlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int tls_write_server_finished(struct tlsv1_server *conn,
|
||||
u8 **msgpos, u8 *end)
|
||||
{
|
||||
u8 *pos, *hs_start;
|
||||
size_t rlen, hlen;
|
||||
u8 verify_data[1 + 3 + TLS_VERIFY_DATA_LEN];
|
||||
u8 hash[MD5_MAC_LEN + SHA1_MAC_LEN];
|
||||
|
||||
pos = *msgpos;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send Finished");
|
||||
|
||||
/* Encrypted Handshake Message: Finished */
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
if (conn->rl.tls_version >= TLS_VERSION_1_2) {
|
||||
hlen = SHA256_MAC_LEN;
|
||||
if (wpa2_crypto_funcs.crypto_hash_finish) {
|
||||
if (conn->verify.sha256_server == NULL ||
|
||||
wpa2_crypto_funcs.crypto_hash_finish(conn->verify.sha256_server, hash, &hlen)
|
||||
< 0) {
|
||||
conn->verify.sha256_server = NULL;
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
conn->verify.sha256_server = NULL;
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register crypto_hash_finish function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
conn->verify.sha256_server = NULL;
|
||||
} else {
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
hlen = MD5_MAC_LEN;
|
||||
if (conn->verify.md5_server == NULL ||
|
||||
crypto_hash_finish(conn->verify.md5_server, hash, &hlen) < 0) {
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
conn->verify.md5_server = NULL;
|
||||
crypto_hash_finish(conn->verify.sha1_server, NULL, NULL);
|
||||
conn->verify.sha1_server = NULL;
|
||||
return -1;
|
||||
}
|
||||
conn->verify.md5_server = NULL;
|
||||
hlen = SHA1_MAC_LEN;
|
||||
if (conn->verify.sha1_server == NULL ||
|
||||
crypto_hash_finish(conn->verify.sha1_server, hash + MD5_MAC_LEN,
|
||||
&hlen) < 0) {
|
||||
conn->verify.sha1_server = NULL;
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
conn->verify.sha1_server = NULL;
|
||||
hlen = MD5_MAC_LEN + SHA1_MAC_LEN;
|
||||
|
||||
#ifdef CONFIG_TLSV12
|
||||
}
|
||||
#endif /* CONFIG_TLSV12 */
|
||||
|
||||
if (tls_prf(conn->rl.tls_version,
|
||||
conn->master_secret, TLS_MASTER_SECRET_LEN,
|
||||
"server finished", hash, hlen,
|
||||
verify_data + 1 + 3, TLS_VERIFY_DATA_LEN)) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to generate verify_data");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "TLSv1: verify_data (server)",
|
||||
verify_data + 1 + 3, TLS_VERIFY_DATA_LEN);
|
||||
|
||||
/* Handshake */
|
||||
pos = hs_start = verify_data;
|
||||
/* HandshakeType msg_type */
|
||||
*pos++ = TLS_HANDSHAKE_TYPE_FINISHED;
|
||||
/* uint24 length */
|
||||
WPA_PUT_BE24(pos, TLS_VERIFY_DATA_LEN);
|
||||
pos += 3;
|
||||
pos += TLS_VERIFY_DATA_LEN;
|
||||
tls_verify_hash_add(&conn->verify, hs_start, pos - hs_start);
|
||||
|
||||
if (tlsv1_record_send(&conn->rl, TLS_CONTENT_TYPE_HANDSHAKE,
|
||||
*msgpos, end - *msgpos, hs_start, pos - hs_start,
|
||||
&rlen) < 0) {
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Failed to create a record");
|
||||
tlsv1_server_alert(conn, TLS_ALERT_LEVEL_FATAL,
|
||||
TLS_ALERT_INTERNAL_ERROR);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*msgpos += rlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static u8 * tls_send_server_hello(struct tlsv1_server *conn, size_t *out_len)
|
||||
{
|
||||
u8 *msg, *end, *pos;
|
||||
size_t msglen;
|
||||
|
||||
*out_len = 0;
|
||||
|
||||
msglen = 1000 + tls_server_cert_chain_der_len(conn);
|
||||
|
||||
msg = os_malloc(msglen);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = msg;
|
||||
end = msg + msglen;
|
||||
|
||||
if (tls_write_server_hello(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (conn->use_session_ticket) {
|
||||
/* Abbreviated handshake using session ticket; RFC 4507 */
|
||||
if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
|
||||
tls_write_server_finished(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
conn->state = CHANGE_CIPHER_SPEC;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
/* Full handshake */
|
||||
if (tls_write_server_certificate(conn, &pos, end) < 0 ||
|
||||
tls_write_server_key_exchange(conn, &pos, end) < 0 ||
|
||||
tls_write_server_certificate_request(conn, &pos, end) < 0 ||
|
||||
tls_write_server_hello_done(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
conn->state = CLIENT_CERTIFICATE;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
static u8 * tls_send_change_cipher_spec(struct tlsv1_server *conn,
|
||||
size_t *out_len)
|
||||
{
|
||||
u8 *msg, *end, *pos;
|
||||
|
||||
*out_len = 0;
|
||||
|
||||
msg = os_malloc(1000);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = msg;
|
||||
end = msg + 1000;
|
||||
|
||||
if (tls_write_server_change_cipher_spec(conn, &pos, end) < 0 ||
|
||||
tls_write_server_finished(conn, &pos, end) < 0) {
|
||||
os_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*out_len = pos - msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Handshake completed successfully");
|
||||
conn->state = ESTABLISHED;
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
u8 * tlsv1_server_handshake_write(struct tlsv1_server *conn, size_t *out_len)
|
||||
{
|
||||
switch (conn->state) {
|
||||
case SERVER_HELLO:
|
||||
return tls_send_server_hello(conn, out_len);
|
||||
case SERVER_CHANGE_CIPHER_SPEC:
|
||||
return tls_send_change_cipher_spec(conn, out_len);
|
||||
default:
|
||||
if (conn->state == ESTABLISHED && conn->use_session_ticket) {
|
||||
/* Abbreviated handshake was already completed. */
|
||||
return NULL;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Unexpected state %d while "
|
||||
"generating reply", conn->state);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
u8 * tlsv1_server_send_alert(struct tlsv1_server *conn, u8 level,
|
||||
u8 description, size_t *out_len)
|
||||
{
|
||||
u8 *alert, *pos, *length;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "TLSv1: Send Alert(%d:%d)", level, description);
|
||||
*out_len = 0;
|
||||
|
||||
alert = os_malloc(10);
|
||||
if (alert == NULL)
|
||||
return NULL;
|
||||
|
||||
pos = alert;
|
||||
|
||||
/* TLSPlaintext */
|
||||
/* ContentType type */
|
||||
*pos++ = TLS_CONTENT_TYPE_ALERT;
|
||||
/* ProtocolVersion version */
|
||||
WPA_PUT_BE16(pos, conn->rl.tls_version ? conn->rl.tls_version :
|
||||
TLS_VERSION);
|
||||
pos += 2;
|
||||
/* uint16 length (to be filled) */
|
||||
length = pos;
|
||||
pos += 2;
|
||||
/* opaque fragment[TLSPlaintext.length] */
|
||||
|
||||
/* Alert */
|
||||
/* AlertLevel level */
|
||||
*pos++ = level;
|
||||
/* AlertDescription description */
|
||||
*pos++ = description;
|
||||
|
||||
WPA_PUT_BE16(length, pos - length - 2);
|
||||
*out_len = pos - alert;
|
||||
|
||||
return alert;
|
||||
}
|
2013
components/wpa_supplicant/src/wpa2/tls/x509v3.c
Normal file
2013
components/wpa_supplicant/src/wpa2/tls/x509v3.c
Normal file
File diff suppressed because it is too large
Load diff
155
components/wpa_supplicant/src/wpa2/utils/base64.c
Normal file
155
components/wpa_supplicant/src/wpa2/utils/base64.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/*
|
||||
* Base64 encoding/decoding (RFC1341)
|
||||
* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "os.h"
|
||||
#include "wpa2/utils/base64.h"
|
||||
|
||||
static const unsigned char base64_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)
|
||||
{
|
||||
unsigned char *out, *pos;
|
||||
const unsigned char *end, *in;
|
||||
size_t olen;
|
||||
int line_len;
|
||||
|
||||
olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
|
||||
olen += olen / 72; /* line feeds */
|
||||
olen++; /* nul termination */
|
||||
if (olen < len)
|
||||
return NULL; /* integer overflow */
|
||||
out = os_malloc(olen);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
end = src + len;
|
||||
in = src;
|
||||
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];
|
||||
in += 3;
|
||||
line_len += 4;
|
||||
if (line_len >= 72) {
|
||||
*pos++ = '\n';
|
||||
line_len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (end - in) {
|
||||
*pos++ = base64_table[in[0] >> 2];
|
||||
if (end - in == 1) {
|
||||
*pos++ = base64_table[(in[0] & 0x03) << 4];
|
||||
*pos++ = '=';
|
||||
} else {
|
||||
*pos++ = base64_table[((in[0] & 0x03) << 4) |
|
||||
(in[1] >> 4)];
|
||||
*pos++ = base64_table[(in[1] & 0x0f) << 2];
|
||||
}
|
||||
*pos++ = '=';
|
||||
line_len += 4;
|
||||
}
|
||||
|
||||
if (line_len)
|
||||
*pos++ = '\n';
|
||||
|
||||
*pos = '\0';
|
||||
if (out_len)
|
||||
*out_len = pos - out;
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
unsigned char dtable[256], *out, *pos, block[4], tmp;
|
||||
size_t i, count, olen;
|
||||
int pad = 0;
|
||||
|
||||
os_memset(dtable, 0x80, 256);
|
||||
for (i = 0; i < sizeof(base64_table) - 1; i++)
|
||||
dtable[base64_table[i]] = (unsigned char) i;
|
||||
dtable['='] = 0;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
if (dtable[src[i]] != 0x80)
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0 || count % 4)
|
||||
return NULL;
|
||||
|
||||
olen = count / 4 * 3;
|
||||
pos = out = os_malloc(olen);
|
||||
if (out == NULL)
|
||||
return NULL;
|
||||
|
||||
count = 0;
|
||||
for (i = 0; i < len; i++) {
|
||||
tmp = dtable[src[i]];
|
||||
if (tmp == 0x80)
|
||||
continue;
|
||||
|
||||
if (src[i] == '=')
|
||||
pad++;
|
||||
block[count] = tmp;
|
||||
count++;
|
||||
if (count == 4) {
|
||||
*pos++ = (block[0] << 2) | (block[1] >> 4);
|
||||
*pos++ = (block[1] << 4) | (block[2] >> 2);
|
||||
*pos++ = (block[2] << 6) | block[3];
|
||||
count = 0;
|
||||
if (pad) {
|
||||
if (pad == 1)
|
||||
pos--;
|
||||
else if (pad == 2)
|
||||
pos -= 2;
|
||||
else {
|
||||
/* Invalid padding */
|
||||
os_free(out);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*out_len = pos - out;
|
||||
return out;
|
||||
}
|
114
components/wpa_supplicant/src/wpa2/utils/ext_password.c
Normal file
114
components/wpa_supplicant/src/wpa2/utils/ext_password.c
Normal file
|
@ -0,0 +1,114 @@
|
|||
/*
|
||||
* External password backend
|
||||
* Copyright (c) 2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/utils/ext_password_i.h"
|
||||
|
||||
#ifdef CONFIG_EXT_PASSWORD_TEST
|
||||
extern struct ext_password_backend ext_password_test;
|
||||
#endif /* CONFIG_EXT_PASSWORD_TEST */
|
||||
|
||||
#ifdef CONFIG_EXT_PASSWORD
|
||||
static const struct ext_password_backend *backends[] = {
|
||||
#ifdef CONFIG_EXT_PASSWORD_TEST
|
||||
&ext_password_test,
|
||||
#endif /* CONFIG_EXT_PASSWORD_TEST */
|
||||
NULL
|
||||
};
|
||||
#endif
|
||||
|
||||
struct ext_password_data {
|
||||
const struct ext_password_backend *backend;
|
||||
void *priv;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_EXT_PASSWORD
|
||||
struct ext_password_data * ext_password_init(const char *backend,
|
||||
const char *params)
|
||||
{
|
||||
struct ext_password_data *data;
|
||||
int i;
|
||||
|
||||
data = (struct ext_password_data *)os_zalloc(sizeof(*data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; backends[i]; i++) {
|
||||
if (os_strcmp(backends[i]->name, backend) == 0) {
|
||||
data->backend = backends[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!data->backend) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
data->priv = data->backend->init(params);
|
||||
if (data->priv == NULL) {
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
void ext_password_deinit(struct ext_password_data *data)
|
||||
{
|
||||
if (data && data->backend && data->priv)
|
||||
data->backend->deinit(data->priv);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * ext_password_get(struct ext_password_data *data,
|
||||
const char *name)
|
||||
{
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
return data->backend->get(data->priv, name);
|
||||
}
|
||||
#endif /* CONFIG_EXT_PASSWORD */
|
||||
|
||||
struct wpabuf * ext_password_alloc(size_t len)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
|
||||
buf = wpabuf_alloc(len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
#ifdef __linux__
|
||||
if (mlock(wpabuf_head(buf), wpabuf_len(buf)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "EXT PW: mlock failed: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_EXT_PASSWORD
|
||||
void ext_password_free(struct wpabuf *pw)
|
||||
{
|
||||
if (pw == NULL)
|
||||
return;
|
||||
os_memset(wpabuf_mhead(pw), 0, wpabuf_len(pw));
|
||||
#ifdef __linux__
|
||||
if (munlock(wpabuf_head(pw), wpabuf_len(pw)) < 0) {
|
||||
wpa_printf(MSG_ERROR, "EXT PW: munlock failed: %s",
|
||||
strerror(errno));
|
||||
}
|
||||
#endif /* __linux__ */
|
||||
wpabuf_free(pw);
|
||||
}
|
||||
#endif /* CONFIG_EXT_PASSWORD */
|
205
components/wpa_supplicant/src/wps/eap_common.c
Normal file
205
components/wpa_supplicant/src/wps/eap_common.c
Normal file
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* EAP common peer/server definitions
|
||||
* Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wpa2/eap_peer/eap_defs.h"
|
||||
#include "wpa2/eap_peer/eap_common.h"
|
||||
|
||||
/**
|
||||
* eap_hdr_len_valid - Validate EAP header length field
|
||||
* @msg: EAP frame (starting with EAP header)
|
||||
* @min_payload: Minimum payload length needed
|
||||
* Returns: 1 for valid header, 0 for invalid
|
||||
*
|
||||
* This is a helper function that does minimal validation of EAP messages. The
|
||||
* length field is verified to be large enough to include the header and not
|
||||
* too large to go beyond the end of the buffer.
|
||||
*/
|
||||
int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
|
||||
{
|
||||
const struct eap_hdr *hdr;
|
||||
size_t len;
|
||||
|
||||
if (msg == NULL)
|
||||
return 0;
|
||||
|
||||
hdr = wpabuf_head(msg);
|
||||
|
||||
if (wpabuf_len(msg) < sizeof(*hdr)) {
|
||||
wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
|
||||
return 0;
|
||||
}
|
||||
|
||||
len = be_to_host16(hdr->length);
|
||||
if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_hdr_validate - Validate EAP header
|
||||
* @vendor: Expected EAP Vendor-Id (0 = IETF)
|
||||
* @eap_type: Expected EAP type number
|
||||
* @msg: EAP frame (starting with EAP header)
|
||||
* @plen: Pointer to variable to contain the returned payload length
|
||||
* Returns: Pointer to EAP payload (after type field), or %NULL on failure
|
||||
*
|
||||
* This is a helper function for EAP method implementations. This is usually
|
||||
* called in the beginning of struct eap_method::process() function to verify
|
||||
* that the received EAP request packet has a valid header. This function is
|
||||
* able to process both legacy and expanded EAP headers and in most cases, the
|
||||
* caller can just use the returned payload pointer (into *plen) for processing
|
||||
* the payload regardless of whether the packet used the expanded EAP header or
|
||||
* not.
|
||||
*/
|
||||
const u8 * eap_hdr_validate(int vendor, EapType eap_type,
|
||||
const struct wpabuf *msg, size_t *plen)
|
||||
{
|
||||
const struct eap_hdr *hdr;
|
||||
const u8 *pos;
|
||||
size_t len;
|
||||
|
||||
if (!eap_hdr_len_valid(msg, 1))
|
||||
return NULL;
|
||||
|
||||
hdr = wpabuf_head(msg);
|
||||
len = be_to_host16(hdr->length);
|
||||
pos = (const u8 *) (hdr + 1);
|
||||
|
||||
if (*pos == EAP_TYPE_EXPANDED) {
|
||||
int exp_vendor;
|
||||
u32 exp_type;
|
||||
if (len < sizeof(*hdr) + 8) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
|
||||
"length");
|
||||
return NULL;
|
||||
}
|
||||
pos++;
|
||||
exp_vendor = WPA_GET_BE24(pos);
|
||||
pos += 3;
|
||||
exp_type = WPA_GET_BE32(pos);
|
||||
pos += 4;
|
||||
if (exp_vendor != vendor || exp_type != (u32) eap_type) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
|
||||
"type");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*plen = len - sizeof(*hdr) - 8;
|
||||
return pos;
|
||||
} else {
|
||||
if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
|
||||
wpa_printf(MSG_INFO, "EAP: Invalid frame type");
|
||||
return NULL;
|
||||
}
|
||||
*plen = len - sizeof(*hdr) - 1;
|
||||
return pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_msg_alloc - Allocate a buffer for an EAP message
|
||||
* @vendor: Vendor-Id (0 = IETF)
|
||||
* @type: EAP type
|
||||
* @payload_len: Payload length in bytes (data after Type)
|
||||
* @code: Message Code (EAP_CODE_*)
|
||||
* @identifier: Identifier
|
||||
* Returns: Pointer to the allocated message buffer or %NULL on error
|
||||
*
|
||||
* This function can be used to allocate a buffer for an EAP message and fill
|
||||
* in the EAP header. This function is automatically using expanded EAP header
|
||||
* if the selected Vendor-Id is not IETF. In other words, most EAP methods do
|
||||
* not need to separately select which header type to use when using this
|
||||
* function to allocate the message buffers. The returned buffer has room for
|
||||
* payload_len bytes and has the EAP header and Type field already filled in.
|
||||
*/
|
||||
struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
|
||||
u8 code, u8 identifier)
|
||||
{
|
||||
struct wpabuf *buf;
|
||||
struct eap_hdr *hdr;
|
||||
size_t len;
|
||||
|
||||
len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
|
||||
payload_len;
|
||||
buf = wpabuf_alloc(len);
|
||||
if (buf == NULL)
|
||||
return NULL;
|
||||
|
||||
hdr = wpabuf_put(buf, sizeof(*hdr));
|
||||
hdr->code = code;
|
||||
hdr->identifier = identifier;
|
||||
hdr->length = host_to_be16(len);
|
||||
|
||||
if (vendor == EAP_VENDOR_IETF) {
|
||||
wpabuf_put_u8(buf, type);
|
||||
} else {
|
||||
wpabuf_put_u8(buf, EAP_TYPE_EXPANDED);
|
||||
wpabuf_put_be24(buf, vendor);
|
||||
wpabuf_put_be32(buf, type);
|
||||
}
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_update_len - Update EAP header length
|
||||
* @msg: EAP message from eap_msg_alloc
|
||||
*
|
||||
* This function updates the length field in the EAP header to match with the
|
||||
* current length for the buffer. This allows eap_msg_alloc() to be used to
|
||||
* allocate a larger buffer than the exact message length (e.g., if exact
|
||||
* message length is not yet known).
|
||||
*/
|
||||
void eap_update_len(struct wpabuf *msg)
|
||||
{
|
||||
struct eap_hdr *hdr;
|
||||
hdr = wpabuf_mhead(msg);
|
||||
if (wpabuf_len(msg) < sizeof(*hdr))
|
||||
return;
|
||||
hdr->length = host_to_be16(wpabuf_len(msg));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_id - Get EAP Identifier from wpabuf
|
||||
* @msg: Buffer starting with an EAP header
|
||||
* Returns: The Identifier field from the EAP header
|
||||
*/
|
||||
u8 eap_get_id(const struct wpabuf *msg)
|
||||
{
|
||||
const struct eap_hdr *eap;
|
||||
|
||||
if (wpabuf_len(msg) < sizeof(*eap))
|
||||
return 0;
|
||||
|
||||
eap = wpabuf_head(msg);
|
||||
return eap->identifier;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* eap_get_id - Get EAP Type from wpabuf
|
||||
* @msg: Buffer starting with an EAP header
|
||||
* Returns: The EAP Type after the EAP header
|
||||
*/
|
||||
EapType eap_get_type(const struct wpabuf *msg)
|
||||
{
|
||||
if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
|
||||
return EAP_TYPE_NONE;
|
||||
|
||||
return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
|
||||
}
|
71
components/wpa_supplicant/src/wps/uuid.c
Normal file
71
components/wpa_supplicant/src/wps/uuid.c
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Universally Unique IDentifier (UUID)
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wps/utils/uuid.h"
|
||||
|
||||
int uuid_str2bin(const char *str, u8 *bin)
|
||||
{
|
||||
const char *pos;
|
||||
u8 *opos;
|
||||
|
||||
pos = str;
|
||||
opos = bin;
|
||||
|
||||
if (hexstr2bin(pos, opos, 4))
|
||||
return -1;
|
||||
pos += 8;
|
||||
opos += 4;
|
||||
|
||||
if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
|
||||
return -1;
|
||||
pos += 4;
|
||||
opos += 2;
|
||||
|
||||
if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
|
||||
return -1;
|
||||
pos += 4;
|
||||
opos += 2;
|
||||
|
||||
if (*pos++ != '-' || hexstr2bin(pos, opos, 2))
|
||||
return -1;
|
||||
pos += 4;
|
||||
opos += 2;
|
||||
|
||||
if (*pos++ != '-' || hexstr2bin(pos, opos, 6))
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int uuid_bin2str(const u8 *bin, char *str, size_t max_len)
|
||||
{
|
||||
int len;
|
||||
len = snprintf(str, max_len, "%02x%02x%02x%02x-%02x%02x-%02x%02x-"
|
||||
"%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
bin[0], bin[1], bin[2], bin[3],
|
||||
bin[4], bin[5], bin[6], bin[7],
|
||||
bin[8], bin[9], bin[10], bin[11],
|
||||
bin[12], bin[13], bin[14], bin[15]);
|
||||
if (len < 0 || (size_t) len >= max_len)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int is_nil_uuid(const u8 *uuid)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < UUID_LEN; i++)
|
||||
if (uuid[i])
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
641
components/wpa_supplicant/src/wps/wps.c
Normal file
641
components/wpa_supplicant/src/wps/wps.c
Normal file
|
@ -0,0 +1,641 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup
|
||||
* Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/wpa.h"
|
||||
#include "wpa/common.h"
|
||||
#include "wpa/eapol_common.h"
|
||||
#include "wpa/wpa_debug.h"
|
||||
#include "wpa/ieee802_11_defs.h"
|
||||
|
||||
#include "crypto/dh_group5.h"
|
||||
|
||||
#include "wps/wps_i.h"
|
||||
#include "wps/wps_dev_attr.h"
|
||||
|
||||
#include "wpa2/eap_peer/eap_defs.h"
|
||||
#include "wpa2/eap_peer/eap_common.h"
|
||||
|
||||
|
||||
/**
|
||||
* wps_process_msg - Process a WPS message
|
||||
* @wps: WPS Registration protocol data from wps_init()
|
||||
* @op_code: Message OP Code
|
||||
* @msg: Message data
|
||||
* Returns: Processing result
|
||||
*
|
||||
* This function is used to process WPS messages with OP Codes WSC_ACK,
|
||||
* WSC_NACK, WSC_MSG, and WSC_Done. The caller (e.g., EAP server/peer) is
|
||||
* responsible for reassembling the messages before calling this function.
|
||||
* Response to this message is built by calling wps_get_msg().
|
||||
*/
|
||||
enum wps_process_res wps_process_msg(struct wps_data *wps,
|
||||
enum wsc_op_code op_code,
|
||||
const struct wpabuf *msg)
|
||||
{
|
||||
if (wps->registrar)
|
||||
return wps_registrar_process_msg(wps, op_code, msg);
|
||||
else
|
||||
return wps_enrollee_process_msg(wps, op_code, msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_get_msg - Build a WPS message
|
||||
* @wps: WPS Registration protocol data from wps_init()
|
||||
* @op_code: Buffer for returning message OP Code
|
||||
* Returns: The generated WPS message or %NULL on failure
|
||||
*
|
||||
* This function is used to build a response to a message processed by calling
|
||||
* wps_process_msg(). The caller is responsible for freeing the buffer.
|
||||
*/
|
||||
struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code)
|
||||
{
|
||||
if (wps->registrar)
|
||||
return wps_registrar_get_msg(wps, op_code);
|
||||
else
|
||||
return wps_enrollee_get_msg(wps, op_code);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_is_selected_pbc_registrar - Check whether WPS IE indicates active PBC
|
||||
* @msg: WPS IE contents from Beacon or Probe Response frame
|
||||
* Returns: 1 if PBC Registrar is active, 0 if not
|
||||
*/
|
||||
int wps_is_selected_pbc_registrar(const struct wpabuf *msg, u8 *bssid)
|
||||
{
|
||||
struct wps_sm *sm = wps_sm_get();
|
||||
struct wps_parse_attr *attr = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
int i = 0;
|
||||
|
||||
/*
|
||||
* In theory, this could also verify that attr.sel_reg_config_methods
|
||||
* includes WPS_CONFIG_PUSHBUTTON, but some deployed AP implementations
|
||||
* do not set Selected Registrar Config Methods attribute properly, so
|
||||
* it is safer to just use Device Password ID here.
|
||||
*/
|
||||
|
||||
if (wps_parse_msg(msg, attr) < 0) {
|
||||
os_free(attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!attr->selected_registrar || *attr->selected_registrar == 0) {
|
||||
if (sm->ignore_sel_reg == false) {
|
||||
os_free(attr);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < WPS_MAX_DIS_AP_NUM; i++) {
|
||||
if (0 == os_memcmp(sm->dis_ap_list[i].bssid, bssid, 6)) {
|
||||
wpa_printf(MSG_DEBUG, "discard ap bssid[%02x:%02x:%02x:%02x:%02x:%02x]\n", \
|
||||
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
|
||||
os_free(attr);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!attr->dev_password_id ||
|
||||
WPA_GET_BE16(attr->dev_password_id) != DEV_PW_PUSHBUTTON) {
|
||||
os_free(attr);
|
||||
return 0;
|
||||
}
|
||||
#if 0
|
||||
#ifdef CONFIG_WPS_STRICT
|
||||
if (!attr->sel_reg_config_methods ||
|
||||
!(WPA_GET_BE16(attr->sel_reg_config_methods) &
|
||||
WPS_CONFIG_PUSHBUTTON)) {
|
||||
os_free(attr);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
#endif
|
||||
os_free(attr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WPS_PIN
|
||||
|
||||
static int is_selected_pin_registrar(struct wps_parse_attr *attr, u8 *bssid)
|
||||
{
|
||||
struct wps_sm *sm = wps_sm_get();
|
||||
int i = 0;
|
||||
|
||||
if (!sm || !bssid){
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* In theory, this could also verify that attr.sel_reg_config_methods
|
||||
* includes WPS_CONFIG_LABEL, WPS_CONFIG_DISPLAY, or WPS_CONFIG_KEYPAD,
|
||||
* but some deployed AP implementations do not set Selected Registrar
|
||||
* Config Methods attribute properly, so it is safer to just use
|
||||
* Device Password ID here.
|
||||
*/
|
||||
|
||||
if (!attr->selected_registrar || *attr->selected_registrar == 0) {
|
||||
if (sm->ignore_sel_reg == false) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
for (i = 0; i < WPS_MAX_DIS_AP_NUM; i++) {
|
||||
if (0 == os_memcmp(sm->dis_ap_list[i].bssid, bssid, 6)) {
|
||||
wpa_printf(MSG_DEBUG, "discard ap bssid[%02x:%02x:%02x:%02x:%02x:%02x]\n", \
|
||||
bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5]);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (attr->dev_password_id != NULL &&
|
||||
WPA_GET_BE16(attr->dev_password_id) == DEV_PW_PUSHBUTTON) {
|
||||
return 0;
|
||||
}
|
||||
#ifdef CONFIG_WPS_STRICT
|
||||
if (!attr->sel_reg_config_methods)// ||
|
||||
//!(WPA_GET_BE16(attr->sel_reg_config_methods) &
|
||||
//(WPS_CONFIG_LABEL | WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD)))
|
||||
return 0;
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_is_selected_pin_registrar - Check whether WPS IE indicates active PIN
|
||||
* @msg: WPS IE contents from Beacon or Probe Response frame
|
||||
* Returns: 1 if PIN Registrar is active, 0 if not
|
||||
*/
|
||||
int wps_is_selected_pin_registrar(const struct wpabuf *msg, u8 *bssid)
|
||||
{
|
||||
struct wps_parse_attr *attr;
|
||||
int ret;
|
||||
|
||||
attr = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
if (attr == NULL)
|
||||
return -99;
|
||||
|
||||
if (wps_parse_msg(msg, attr) < 0) {
|
||||
os_free(attr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = is_selected_pin_registrar(attr, bssid);
|
||||
os_free(attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* wps_is_addr_authorized - Check whether WPS IE authorizes MAC address
|
||||
* @msg: WPS IE contents from Beacon or Probe Response frame
|
||||
* @addr: MAC address to search for
|
||||
* @ver1_compat: Whether to use version 1 compatibility mode
|
||||
* Returns: 2 if the specified address is explicit authorized, 1 if address is
|
||||
* authorized (broadcast), 0 if not
|
||||
*/
|
||||
int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
|
||||
int ver1_compat)
|
||||
{
|
||||
struct wps_sm *sm = wps_sm_get();
|
||||
struct wps_parse_attr *attr;
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
const u8 *pos;
|
||||
const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
|
||||
if (!sm){
|
||||
return -10;
|
||||
}
|
||||
|
||||
attr = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
if (attr == NULL) {
|
||||
ret = -99;
|
||||
goto _out;
|
||||
}
|
||||
|
||||
if (wps_parse_msg(msg, attr) < 0) {
|
||||
ret = 0;
|
||||
goto _out;
|
||||
}
|
||||
|
||||
if (!attr->version2 && ver1_compat) {
|
||||
/*
|
||||
* Version 1.0 AP - AuthorizedMACs not used, so revert back to
|
||||
* old mechanism of using SelectedRegistrar.
|
||||
*/
|
||||
#ifdef CONFIG_WPS_PIN
|
||||
|
||||
ret = is_selected_pin_registrar(attr, sm->config.bssid);
|
||||
goto _out;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!attr->authorized_macs) {
|
||||
ret = 0;
|
||||
goto _out;
|
||||
}
|
||||
|
||||
pos = attr->authorized_macs;
|
||||
for (i = 0; i < attr->authorized_macs_len / ETH_ALEN; i++) {
|
||||
if (os_memcmp(pos, addr, ETH_ALEN) == 0) {
|
||||
ret = 2;
|
||||
goto _out;
|
||||
}
|
||||
if (os_memcmp(pos, bcast, ETH_ALEN) == 0) {
|
||||
ret = 1;
|
||||
goto _out;
|
||||
}
|
||||
pos += ETH_ALEN;
|
||||
}
|
||||
_out:
|
||||
if (attr)
|
||||
os_free(attr);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_ap_priority_compar - Prioritize WPS IE from two APs
|
||||
* @wps_a: WPS IE contents from Beacon or Probe Response frame
|
||||
* @wps_b: WPS IE contents from Beacon or Probe Response frame
|
||||
* Returns: 1 if wps_b is considered more likely selection for WPS
|
||||
* provisioning, -1 if wps_a is considered more like, or 0 if no preference
|
||||
*/
|
||||
int wps_ap_priority_compar(const struct wpabuf *wps_a,
|
||||
const struct wpabuf *wps_b)
|
||||
{
|
||||
struct wps_parse_attr *attr_a, *attr_b;
|
||||
int sel_a, sel_b;
|
||||
int ret = 0;
|
||||
|
||||
attr_a = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
attr_b = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
|
||||
if (attr_a == NULL || attr_b == NULL) {
|
||||
ret = 0;
|
||||
goto _out;
|
||||
}
|
||||
|
||||
if (wps_a == NULL || wps_parse_msg(wps_a, attr_a) < 0)
|
||||
return 1;
|
||||
if (wps_b == NULL || wps_parse_msg(wps_b, attr_b) < 0)
|
||||
return -1;
|
||||
|
||||
sel_a = attr_a->selected_registrar && *attr_a->selected_registrar != 0;
|
||||
sel_b = attr_b->selected_registrar && *attr_b->selected_registrar != 0;
|
||||
|
||||
if (sel_a && !sel_b) {
|
||||
ret = -1;
|
||||
goto _out;
|
||||
}
|
||||
if (!sel_a && sel_b) {
|
||||
ret = 1;
|
||||
goto _out;
|
||||
}
|
||||
|
||||
_out:
|
||||
if (attr_a)
|
||||
os_free(attr_a);
|
||||
if (attr_b)
|
||||
os_free(attr_b);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_get_uuid_e - Get UUID-E from WPS IE
|
||||
* @msg: WPS IE contents from Beacon or Probe Response frame
|
||||
* Returns: Pointer to UUID-E or %NULL if not included
|
||||
*
|
||||
* The returned pointer is to the msg contents and it remains valid only as
|
||||
* long as the msg buffer is valid.
|
||||
*/
|
||||
const u8 * wps_get_uuid_e(const struct wpabuf *msg)
|
||||
{
|
||||
struct wps_parse_attr *attr;
|
||||
const u8 *uuid_e;
|
||||
|
||||
attr = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
if (attr == NULL)
|
||||
return NULL;
|
||||
|
||||
if (wps_parse_msg(msg, attr) < 0) {
|
||||
uuid_e = NULL;
|
||||
} else {
|
||||
uuid_e = attr->uuid_e;
|
||||
}
|
||||
os_free(attr);
|
||||
return uuid_e;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_is_20 - Check whether WPS attributes claim support for WPS 2.0
|
||||
*/
|
||||
int wps_is_20(const struct wpabuf *msg)
|
||||
{
|
||||
struct wps_parse_attr *attr;
|
||||
int ret;
|
||||
|
||||
attr = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
if (attr == NULL)
|
||||
return 0;
|
||||
|
||||
if (msg == NULL || wps_parse_msg(msg, attr) < 0) {
|
||||
ret = 0;
|
||||
} else {
|
||||
ret = (attr->version2 != NULL);
|
||||
}
|
||||
os_free(attr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_build_assoc_req_ie - Build WPS IE for (Re)Association Request
|
||||
* @req_type: Value for Request Type attribute
|
||||
* Returns: WPS IE or %NULL on failure
|
||||
*
|
||||
* The caller is responsible for freeing the buffer.
|
||||
*/
|
||||
struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type)
|
||||
{
|
||||
struct wpabuf *ie;
|
||||
u8 *len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
|
||||
"Request");
|
||||
ie = wpabuf_alloc(100);
|
||||
if (ie == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
|
||||
len = wpabuf_put(ie, 1);
|
||||
wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
|
||||
|
||||
if (wps_build_version(ie) ||
|
||||
wps_build_req_type(ie, req_type) ||
|
||||
wps_build_wfa_ext(ie, 0, NULL, 0)) {
|
||||
wpabuf_free(ie);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = wpabuf_len(ie) - 2;
|
||||
|
||||
return ie;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_build_assoc_resp_ie - Build WPS IE for (Re)Association Response
|
||||
* Returns: WPS IE or %NULL on failure
|
||||
*
|
||||
* The caller is responsible for freeing the buffer.
|
||||
*/
|
||||
struct wpabuf * wps_build_assoc_resp_ie(void)
|
||||
{
|
||||
struct wpabuf *ie;
|
||||
u8 *len;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for (Re)Association "
|
||||
"Response");
|
||||
ie = wpabuf_alloc(100);
|
||||
if (ie == NULL)
|
||||
return NULL;
|
||||
|
||||
wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
|
||||
len = wpabuf_put(ie, 1);
|
||||
wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
|
||||
|
||||
if (wps_build_version(ie) ||
|
||||
wps_build_resp_type(ie, WPS_RESP_AP) ||
|
||||
wps_build_wfa_ext(ie, 0, NULL, 0)) {
|
||||
wpabuf_free(ie);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*len = wpabuf_len(ie) - 2;
|
||||
|
||||
return ie;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_build_probe_req_ie - Build WPS IE for Probe Request
|
||||
* @pw_id: Password ID (DEV_PW_PUSHBUTTON for active PBC and DEV_PW_DEFAULT for
|
||||
* most other use cases)
|
||||
* @dev: Device attributes
|
||||
* @uuid: Own UUID
|
||||
* @req_type: Value for Request Type attribute
|
||||
* @num_req_dev_types: Number of requested device types
|
||||
* @req_dev_types: Requested device types (8 * num_req_dev_types octets) or
|
||||
* %NULL if none
|
||||
* Returns: WPS IE or %NULL on failure
|
||||
*
|
||||
* The caller is responsible for freeing the buffer.
|
||||
*/
|
||||
struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
|
||||
const u8 *uuid,
|
||||
enum wps_request_type req_type,
|
||||
unsigned int num_req_dev_types,
|
||||
const u8 *req_dev_types)
|
||||
{
|
||||
struct wpabuf *ie;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Building WPS IE for Probe Request\n");
|
||||
|
||||
ie = wpabuf_alloc(400);
|
||||
if (ie == NULL) {
|
||||
wpa_printf(MSG_ERROR, "WPS: ie alloc failed.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (wps_build_version(ie) ||
|
||||
wps_build_req_type(ie, req_type) ||
|
||||
wps_build_config_methods(ie, dev->config_methods) ||
|
||||
wps_build_uuid_e(ie, uuid) ||
|
||||
wps_build_primary_dev_type(dev, ie) ||
|
||||
wps_build_rf_bands(dev, ie) ||
|
||||
wps_build_assoc_state(NULL, ie) ||
|
||||
wps_build_config_error(ie, WPS_CFG_NO_ERROR) ||
|
||||
wps_build_dev_password_id(ie, pw_id) ||
|
||||
#ifdef CONFIG_WPS2
|
||||
wps_build_manufacturer(dev, ie) ||
|
||||
wps_build_model_name(dev, ie) ||
|
||||
wps_build_model_number(dev, ie) ||
|
||||
wps_build_dev_name(dev, ie) ||
|
||||
wps_build_wfa_ext(ie, req_type == WPS_REQ_ENROLLEE, NULL, 0) ||
|
||||
#endif /* CONFIG_WPS2 */
|
||||
wps_build_req_dev_type(dev, ie, num_req_dev_types, req_dev_types)
|
||||
||
|
||||
wps_build_secondary_dev_type(dev, ie)
|
||||
) {
|
||||
wpabuf_free(ie);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifndef CONFIG_WPS2
|
||||
if (dev->p2p && wps_build_dev_name(dev, ie)) {
|
||||
wpabuf_free(ie);
|
||||
return NULL;
|
||||
}
|
||||
#endif /* CONFIG_WPS2 */
|
||||
|
||||
return wps_ie_encapsulate(ie);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WPS_UPNP
|
||||
|
||||
void wps_free_pending_msgs(struct upnp_pending_message *msgs)
|
||||
{
|
||||
struct upnp_pending_message *p, *prev;
|
||||
p = msgs;
|
||||
while (p) {
|
||||
prev = p;
|
||||
p = p->next;
|
||||
wpabuf_free(prev->msg);
|
||||
os_free(prev);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int wps_attr_text(struct wpabuf *data, char *buf, char *end)
|
||||
{
|
||||
struct wps_parse_attr *attr;
|
||||
char *pos = buf;
|
||||
int ret;
|
||||
|
||||
attr = (struct wps_parse_attr *)os_zalloc(sizeof(struct wps_parse_attr));
|
||||
if (attr == NULL)
|
||||
return -99;
|
||||
|
||||
if (wps_parse_msg(data, attr) < 0) {
|
||||
ret = -1;
|
||||
goto _out;
|
||||
}
|
||||
|
||||
if (attr->wps_state) {
|
||||
if (*attr->wps_state == WPS_STATE_NOT_CONFIGURED)
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_state=unconfigured\n");
|
||||
else if (*attr->wps_state == WPS_STATE_CONFIGURED)
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_state=configured\n");
|
||||
else
|
||||
ret = 0;
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (attr->ap_setup_locked && *attr->ap_setup_locked) {
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_ap_setup_locked=1\n");
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (attr->selected_registrar && *attr->selected_registrar) {
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_selected_registrar=1\n");
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (attr->dev_password_id) {
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_device_password_id=%u\n",
|
||||
WPA_GET_BE16(attr->dev_password_id));
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (attr->sel_reg_config_methods) {
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_selected_registrar_config_methods="
|
||||
"0x%04x\n",
|
||||
WPA_GET_BE16(attr->sel_reg_config_methods));
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (attr->primary_dev_type) {
|
||||
char devtype[WPS_DEV_TYPE_BUFSIZE];
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_primary_device_type=%s\n",
|
||||
wps_dev_type_bin2str(attr->primary_dev_type,
|
||||
devtype,
|
||||
sizeof(devtype)));
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (attr->dev_name) {
|
||||
char *str = (char *)os_malloc(attr->dev_name_len + 1);
|
||||
size_t i;
|
||||
if (str == NULL) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
for (i = 0; i < attr->dev_name_len; i++) {
|
||||
if (attr->dev_name[i] < 32)
|
||||
str[i] = '_';
|
||||
else
|
||||
str[i] = attr->dev_name[i];
|
||||
}
|
||||
str[i] = '\0';
|
||||
ret = snprintf(pos, end - pos, "wps_device_name=%s\n", str);
|
||||
os_free(str);
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
if (attr->config_methods) {
|
||||
ret = snprintf(pos, end - pos,
|
||||
"wps_config_methods=0x%04x\n",
|
||||
WPA_GET_BE16(attr->config_methods));
|
||||
if (ret < 0 || ret >= end - pos) {
|
||||
ret = pos - buf;
|
||||
goto _out;
|
||||
}
|
||||
pos += ret;
|
||||
}
|
||||
|
||||
ret = pos - buf;
|
||||
_out:
|
||||
if (attr)
|
||||
os_free(attr);
|
||||
return ret;
|
||||
}
|
438
components/wpa_supplicant/src/wps/wps_attr_build.c
Normal file
438
components/wpa_supplicant/src/wps/wps_attr_build.c
Normal file
|
@ -0,0 +1,438 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - attribute building
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/common.h"
|
||||
#include "wpa/wpa_debug.h"
|
||||
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/dh_group5.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
|
||||
#include "wpa/ieee802_11_defs.h"
|
||||
#include "wps/wps_i.h"
|
||||
#include "soc/dport_reg.h"
|
||||
|
||||
int wps_build_public_key(struct wps_data *wps, struct wpabuf *msg, wps_key_mode_t mode)
|
||||
{
|
||||
struct wpabuf *pubkey;
|
||||
|
||||
if (mode != WPS_CALC_KEY_NO_CALC) {
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Public Key");
|
||||
wpabuf_free(wps->dh_privkey);
|
||||
if (wps->dev_pw_id != DEV_PW_DEFAULT && wps->wps->dh_privkey) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Using pre-configured DH keys");
|
||||
wps->dh_privkey = wpabuf_dup(wps->wps->dh_privkey);
|
||||
wps->dh_ctx = wps->wps->dh_ctx;
|
||||
wps->wps->dh_ctx = NULL;
|
||||
pubkey = wpabuf_dup(wps->wps->dh_pubkey);
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
} else if (wps->dev_pw_id >= 0x10 && wps->wps->ap &&
|
||||
wps->dev_pw_id == wps->wps->ap_nfc_dev_pw_id) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Using NFC password token DH keys");
|
||||
wps->dh_privkey = wpabuf_dup(wps->wps->ap_nfc_dh_privkey);
|
||||
pubkey = wpabuf_dup(wps->wps->ap_nfc_dh_pubkey);
|
||||
wps->dh_ctx = dh5_init_fixed(wps->dh_privkey, pubkey);
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
} else {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Generate new DH keys");
|
||||
wps->dh_privkey = NULL;
|
||||
dh5_free(wps->dh_ctx);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "build public key start\n");
|
||||
|
||||
wps->dh_ctx = dh5_init(&wps->dh_privkey, &pubkey);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "build public key finish\n");
|
||||
|
||||
pubkey = wpabuf_zeropad(pubkey, 192);
|
||||
}
|
||||
if (wps->dh_ctx == NULL || wps->dh_privkey == NULL || pubkey == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Failed to initialize "
|
||||
"Diffie-Hellman handshake");
|
||||
wpabuf_free(pubkey);
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "WPS: DH own Public Key", pubkey);
|
||||
|
||||
if (wps->registrar) {
|
||||
wpabuf_free(wps->dh_pubkey_r);
|
||||
wps->dh_pubkey_r = pubkey;
|
||||
} else {
|
||||
wpabuf_free(wps->dh_pubkey_e);
|
||||
wps->dh_pubkey_e = pubkey;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (mode != WPS_CALC_KEY_PRE_CALC) {
|
||||
if (wps->registrar)
|
||||
pubkey = wps->dh_pubkey_r;
|
||||
else
|
||||
pubkey = wps->dh_pubkey_e;
|
||||
|
||||
wpabuf_put_be16(msg, ATTR_PUBLIC_KEY);
|
||||
wpabuf_put_be16(msg, wpabuf_len(pubkey));
|
||||
wpabuf_put_buf(msg, pubkey);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_req_type(struct wpabuf *msg, enum wps_request_type type)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Request Type");
|
||||
wpabuf_put_be16(msg, ATTR_REQUEST_TYPE);
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_resp_type(struct wpabuf *msg, enum wps_response_type type)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Response Type (%d)", type);
|
||||
wpabuf_put_be16(msg, ATTR_RESPONSE_TYPE);
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_config_methods(struct wpabuf *msg, u16 methods)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Config Methods (%x)", methods);
|
||||
wpabuf_put_be16(msg, ATTR_CONFIG_METHODS);
|
||||
wpabuf_put_be16(msg, 2);
|
||||
wpabuf_put_be16(msg, methods);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_uuid_e(struct wpabuf *msg, const u8 *uuid)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * UUID-E");
|
||||
wpabuf_put_be16(msg, ATTR_UUID_E);
|
||||
wpabuf_put_be16(msg, WPS_UUID_LEN);
|
||||
wpabuf_put_data(msg, uuid, WPS_UUID_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_dev_password_id(struct wpabuf *msg, u16 id)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Device Password ID (%d)", id);
|
||||
wpabuf_put_be16(msg, ATTR_DEV_PASSWORD_ID);
|
||||
wpabuf_put_be16(msg, 2);
|
||||
wpabuf_put_be16(msg, id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_config_error(struct wpabuf *msg, u16 err)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Configuration Error (%d)", err);
|
||||
wpabuf_put_be16(msg, ATTR_CONFIG_ERROR);
|
||||
wpabuf_put_be16(msg, 2);
|
||||
wpabuf_put_be16(msg, err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_authenticator(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
|
||||
if (wps->last_msg == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
|
||||
"building authenticator");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
|
||||
* (M_curr* is M_curr without the Authenticator attribute)
|
||||
*/
|
||||
addr[0] = wpabuf_head(wps->last_msg);
|
||||
len[0] = wpabuf_len(wps->last_msg);
|
||||
addr[1] = wpabuf_head(msg);
|
||||
len[1] = wpabuf_len(msg);
|
||||
if (wps_crypto_funcs.hmac_sha256_vector) {
|
||||
wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, (int *)len, hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register hmac sha256 vector!\r\n");
|
||||
return -1;
|
||||
}
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Authenticator");
|
||||
wpabuf_put_be16(msg, ATTR_AUTHENTICATOR);
|
||||
wpabuf_put_be16(msg, WPS_AUTHENTICATOR_LEN);
|
||||
wpabuf_put_data(msg, hash, WPS_AUTHENTICATOR_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_version(struct wpabuf *msg)
|
||||
{
|
||||
/*
|
||||
* Note: This attribute is deprecated and set to hardcoded 0x10 for
|
||||
* backwards compatibility reasons. The real version negotiation is
|
||||
* done with Version2.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Version (hardcoded 0x10)");
|
||||
wpabuf_put_be16(msg, ATTR_VERSION);
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, 0x10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_wfa_ext(struct wpabuf *msg, int req_to_enroll,
|
||||
const u8 *auth_macs, size_t auth_macs_count)
|
||||
{
|
||||
#ifdef CONFIG_WPS2
|
||||
u8 *len;
|
||||
|
||||
wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
|
||||
len = wpabuf_put(msg, 2); /* to be filled */
|
||||
wpabuf_put_be24(msg, WPS_VENDOR_ID_WFA);
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Version2 (0x%x)", WPS_VERSION);
|
||||
wpabuf_put_u8(msg, WFA_ELEM_VERSION2);
|
||||
wpabuf_put_u8(msg, 1);
|
||||
wpabuf_put_u8(msg, WPS_VERSION);
|
||||
|
||||
if (req_to_enroll) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Request to Enroll (1)");
|
||||
wpabuf_put_u8(msg, WFA_ELEM_REQUEST_TO_ENROLL);
|
||||
wpabuf_put_u8(msg, 1);
|
||||
wpabuf_put_u8(msg, 1);
|
||||
}
|
||||
|
||||
if (auth_macs && auth_macs_count) {
|
||||
size_t i;
|
||||
wpa_printf(MSG_DEBUG, "WPS: * AuthorizedMACs (count=%d)",
|
||||
(int) auth_macs_count);
|
||||
wpabuf_put_u8(msg, WFA_ELEM_AUTHORIZEDMACS);
|
||||
wpabuf_put_u8(msg, auth_macs_count * ETH_ALEN);
|
||||
wpabuf_put_data(msg, auth_macs, auth_macs_count * ETH_ALEN);
|
||||
for (i = 0; i < auth_macs_count; i++)
|
||||
wpa_printf(MSG_DEBUG, "WPS: AuthorizedMAC: " MACSTR,
|
||||
MAC2STR(&auth_macs[i * ETH_ALEN]));
|
||||
}
|
||||
|
||||
WPA_PUT_BE16(len, (u8 *) wpabuf_put(msg, 0) - len - 2);
|
||||
#endif /* CONFIG_WPS2 */
|
||||
|
||||
#ifdef CONFIG_WPS_TESTING
|
||||
if (WPS_VERSION > 0x20) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Extensibility Testing - extra "
|
||||
"attribute");
|
||||
wpabuf_put_be16(msg, ATTR_EXTENSIBILITY_TEST);
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, 42);
|
||||
}
|
||||
#endif /* CONFIG_WPS_TESTING */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_msg_type(struct wpabuf *msg, enum wps_msg_type msg_type)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Message Type (%d)", msg_type);
|
||||
wpabuf_put_be16(msg, ATTR_MSG_TYPE);
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, msg_type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_enrollee_nonce(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Enrollee Nonce");
|
||||
wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
|
||||
wpabuf_put_be16(msg, WPS_NONCE_LEN);
|
||||
wpabuf_put_data(msg, wps->nonce_e, WPS_NONCE_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_registrar_nonce(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Registrar Nonce");
|
||||
wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
|
||||
wpabuf_put_be16(msg, WPS_NONCE_LEN);
|
||||
wpabuf_put_data(msg, wps->nonce_r, WPS_NONCE_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_auth_type_flags(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
u16 auth_types = WPS_AUTH_TYPES;
|
||||
#ifdef CONFIG_WPS2
|
||||
auth_types &= ~WPS_AUTH_SHARED;
|
||||
#endif /* CONFIG_WPS2 */
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Authentication Type Flags");
|
||||
wpabuf_put_be16(msg, ATTR_AUTH_TYPE_FLAGS);
|
||||
wpabuf_put_be16(msg, 2);
|
||||
wpabuf_put_be16(msg, auth_types);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_encr_type_flags(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
u16 encr_types = WPS_ENCR_TYPES;
|
||||
#ifdef CONFIG_WPS2
|
||||
encr_types &= ~WPS_ENCR_WEP;
|
||||
#endif /* CONFIG_WPS2 */
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Encryption Type Flags");
|
||||
wpabuf_put_be16(msg, ATTR_ENCR_TYPE_FLAGS);
|
||||
wpabuf_put_be16(msg, 2);
|
||||
wpabuf_put_be16(msg, encr_types);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_conn_type_flags(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Connection Type Flags");
|
||||
wpabuf_put_be16(msg, ATTR_CONN_TYPE_FLAGS);
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, WPS_CONN_ESS);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_assoc_state(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Association State");
|
||||
wpabuf_put_be16(msg, ATTR_ASSOC_STATE);
|
||||
wpabuf_put_be16(msg, 2);
|
||||
wpabuf_put_be16(msg, WPS_ASSOC_NOT_ASSOC);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Key Wrap Authenticator");
|
||||
if (wps_crypto_funcs.hmac_sha256) {
|
||||
wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, wpabuf_head(msg),
|
||||
wpabuf_len(msg), hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register hmac sha256 function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
wpabuf_put_be16(msg, ATTR_KEY_WRAP_AUTH);
|
||||
wpabuf_put_be16(msg, WPS_KWA_LEN);
|
||||
wpabuf_put_data(msg, hash, WPS_KWA_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_encr_settings(struct wps_data *wps, struct wpabuf *msg,
|
||||
struct wpabuf *plain)
|
||||
{
|
||||
size_t pad_len;
|
||||
const size_t block_size = 16;
|
||||
u8 *iv, *data;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Encrypted Settings");
|
||||
|
||||
/* PKCS#5 v2.0 pad */
|
||||
pad_len = block_size - wpabuf_len(plain) % block_size;
|
||||
os_memset(wpabuf_put(plain, pad_len), pad_len, pad_len);
|
||||
|
||||
wpabuf_put_be16(msg, ATTR_ENCR_SETTINGS);
|
||||
wpabuf_put_be16(msg, block_size + wpabuf_len(plain));
|
||||
|
||||
iv = wpabuf_put(msg, block_size);
|
||||
if (random_get_bytes(iv, block_size) < 0)
|
||||
return -1;
|
||||
|
||||
data = wpabuf_put(msg, 0);
|
||||
wpabuf_put_buf(msg, plain);
|
||||
wpa_printf(MSG_DEBUG, "WPS: * AES 128 Encrypted Settings");
|
||||
if (wps_crypto_funcs.aes_128_encrypt) {
|
||||
if (wps_crypto_funcs.aes_128_encrypt(wps->keywrapkey, iv, data, wpabuf_len(plain)))
|
||||
return -1;
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register aes_128_encrypt function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WPS_OOB
|
||||
int wps_build_oob_dev_pw(struct wpabuf *msg, u16 dev_pw_id,
|
||||
const struct wpabuf *pubkey, const u8 *dev_pw,
|
||||
size_t dev_pw_len)
|
||||
{
|
||||
size_t hash_len;
|
||||
const u8 *addr[1];
|
||||
u8 pubkey_hash[WPS_HASH_LEN];
|
||||
|
||||
addr[0] = wpabuf_head(pubkey);
|
||||
hash_len = wpabuf_len(pubkey);
|
||||
if (wps_crypto_funcs.sha256_vector) {
|
||||
wps_crypto_funcs.sha256_vector(1, addr, &hash_len, pubkey_hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register sha256 vector function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
wpabuf_put_be16(msg, ATTR_OOB_DEVICE_PASSWORD);
|
||||
wpabuf_put_be16(msg, WPS_OOB_PUBKEY_HASH_LEN + 2 + dev_pw_len);
|
||||
wpabuf_put_data(msg, pubkey_hash, WPS_OOB_PUBKEY_HASH_LEN);
|
||||
wpabuf_put_be16(msg, dev_pw_id);
|
||||
wpabuf_put_data(msg, dev_pw, dev_pw_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS_OOB */
|
||||
|
||||
|
||||
/* Encapsulate WPS IE data with one (or more, if needed) IE headers */
|
||||
struct wpabuf * wps_ie_encapsulate(struct wpabuf *data)
|
||||
{
|
||||
struct wpabuf *ie;
|
||||
const u8 *pos, *end;
|
||||
|
||||
ie = wpabuf_alloc(wpabuf_len(data) + 100);
|
||||
if (ie == NULL) {
|
||||
wpabuf_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
pos = wpabuf_head(data);
|
||||
end = pos + wpabuf_len(data);
|
||||
|
||||
while (end > pos) {
|
||||
size_t frag_len = end - pos;
|
||||
if (frag_len > 251)
|
||||
frag_len = 251;
|
||||
wpabuf_put_u8(ie, WLAN_EID_VENDOR_SPECIFIC);
|
||||
wpabuf_put_u8(ie, 4 + frag_len);
|
||||
wpabuf_put_be32(ie, WPS_DEV_OUI_WFA);
|
||||
wpabuf_put_data(ie, pos, frag_len);
|
||||
pos += frag_len;
|
||||
}
|
||||
|
||||
wpabuf_free(data);
|
||||
|
||||
return ie;
|
||||
}
|
640
components/wpa_supplicant/src/wps/wps_attr_parse.c
Normal file
640
components/wpa_supplicant/src/wps/wps_attr_parse.c
Normal file
|
@ -0,0 +1,640 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - attribute parsing
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "wps/wps_defs.h"
|
||||
#include "wps/wps_attr_parse.h"
|
||||
|
||||
#ifndef CONFIG_WPS_STRICT
|
||||
#define WPS_WORKAROUNDS
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
|
||||
|
||||
static int wps_set_vendor_ext_wfa_subelem(struct wps_parse_attr *attr,
|
||||
u8 id, u8 len, const u8 *pos)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: WFA subelement id=%u len=%u",
|
||||
id, len);
|
||||
switch (id) {
|
||||
case WFA_ELEM_VERSION2:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Version2 length "
|
||||
"%u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->version2 = pos;
|
||||
break;
|
||||
case WFA_ELEM_AUTHORIZEDMACS:
|
||||
attr->authorized_macs = pos;
|
||||
attr->authorized_macs_len = len;
|
||||
break;
|
||||
case WFA_ELEM_NETWORK_KEY_SHAREABLE:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key "
|
||||
"Shareable length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->network_key_shareable = pos;
|
||||
break;
|
||||
case WFA_ELEM_REQUEST_TO_ENROLL:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Request to Enroll "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->request_to_enroll = pos;
|
||||
break;
|
||||
case WFA_ELEM_SETTINGS_DELAY_TIME:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Settings Delay "
|
||||
"Time length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->settings_delay_time = pos;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "WPS: Skipped unknown WFA Vendor "
|
||||
"Extension subelement %u", id);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_parse_vendor_ext_wfa(struct wps_parse_attr *attr, const u8 *pos,
|
||||
u16 len)
|
||||
{
|
||||
const u8 *end = pos + len;
|
||||
u8 id, elen;
|
||||
|
||||
while (pos + 2 < end) {
|
||||
id = *pos++;
|
||||
elen = *pos++;
|
||||
if (pos + elen > end)
|
||||
break;
|
||||
if (wps_set_vendor_ext_wfa_subelem(attr, id, elen, pos) < 0)
|
||||
return -1;
|
||||
pos += elen;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_parse_vendor_ext(struct wps_parse_attr *attr, const u8 *pos,
|
||||
u16 len)
|
||||
{
|
||||
u32 vendor_id;
|
||||
|
||||
if (len < 3) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Skip invalid Vendor Extension");
|
||||
return 0;
|
||||
}
|
||||
|
||||
vendor_id = WPA_GET_BE24(pos);
|
||||
switch (vendor_id) {
|
||||
case WPS_VENDOR_ID_WFA:
|
||||
return wps_parse_vendor_ext_wfa(attr, pos + 3, len - 3);
|
||||
}
|
||||
|
||||
/* Handle unknown vendor extensions */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Unknown Vendor Extension (Vendor ID %u)",
|
||||
vendor_id);
|
||||
|
||||
if (len > WPS_MAX_VENDOR_EXT_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Too long Vendor Extension (%u)",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (attr->num_vendor_ext >= MAX_WPS_PARSE_VENDOR_EXT) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Skipped Vendor Extension "
|
||||
"attribute (max %d vendor extensions)",
|
||||
MAX_WPS_PARSE_VENDOR_EXT);
|
||||
return -1;
|
||||
}
|
||||
attr->vendor_ext[attr->num_vendor_ext] = pos;
|
||||
attr->vendor_ext_len[attr->num_vendor_ext] = len;
|
||||
attr->num_vendor_ext++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
|
||||
const u8 *pos, u16 len)
|
||||
{
|
||||
switch (type) {
|
||||
case ATTR_VERSION:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Version length %u",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
attr->version = pos;
|
||||
break;
|
||||
case ATTR_MSG_TYPE:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Message Type "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->msg_type = pos;
|
||||
break;
|
||||
case ATTR_ENROLLEE_NONCE:
|
||||
if (len != WPS_NONCE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Enrollee Nonce "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->enrollee_nonce = pos;
|
||||
break;
|
||||
case ATTR_REGISTRAR_NONCE:
|
||||
if (len != WPS_NONCE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Registrar Nonce "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->registrar_nonce = pos;
|
||||
break;
|
||||
case ATTR_UUID_E:
|
||||
if (len != WPS_UUID_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-E length %u",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
attr->uuid_e = pos;
|
||||
break;
|
||||
case ATTR_UUID_R:
|
||||
if (len != WPS_UUID_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid UUID-R length %u",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
attr->uuid_r = pos;
|
||||
break;
|
||||
case ATTR_AUTH_TYPE_FLAGS:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
|
||||
"Type Flags length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->auth_type_flags = pos;
|
||||
break;
|
||||
case ATTR_ENCR_TYPE_FLAGS:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption Type "
|
||||
"Flags length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->encr_type_flags = pos;
|
||||
break;
|
||||
case ATTR_CONN_TYPE_FLAGS:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Connection Type "
|
||||
"Flags length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->conn_type_flags = pos;
|
||||
break;
|
||||
case ATTR_CONFIG_METHODS:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Config Methods "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->config_methods = pos;
|
||||
break;
|
||||
case ATTR_SELECTED_REGISTRAR_CONFIG_METHODS:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Selected "
|
||||
"Registrar Config Methods length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->sel_reg_config_methods = pos;
|
||||
break;
|
||||
case ATTR_PRIMARY_DEV_TYPE:
|
||||
if (len != WPS_DEV_TYPE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Primary Device "
|
||||
"Type length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->primary_dev_type = pos;
|
||||
break;
|
||||
case ATTR_RF_BANDS:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid RF Bands length "
|
||||
"%u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->rf_bands = pos;
|
||||
break;
|
||||
case ATTR_ASSOC_STATE:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Association State "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->assoc_state = pos;
|
||||
break;
|
||||
case ATTR_CONFIG_ERROR:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Configuration "
|
||||
"Error length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->config_error = pos;
|
||||
break;
|
||||
case ATTR_DEV_PASSWORD_ID:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Device Password "
|
||||
"ID length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->dev_password_id = pos;
|
||||
break;
|
||||
case ATTR_OOB_DEVICE_PASSWORD:
|
||||
if (len < WPS_OOB_PUBKEY_HASH_LEN + 2 +
|
||||
WPS_OOB_DEVICE_PASSWORD_MIN_LEN ||
|
||||
len > WPS_OOB_PUBKEY_HASH_LEN + 2 +
|
||||
WPS_OOB_DEVICE_PASSWORD_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid OOB Device "
|
||||
"Password length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->oob_dev_password = pos;
|
||||
attr->oob_dev_password_len = len;
|
||||
break;
|
||||
case ATTR_OS_VERSION:
|
||||
if (len != 4) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid OS Version length "
|
||||
"%u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->os_version = pos;
|
||||
break;
|
||||
case ATTR_WPS_STATE:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Wi-Fi Protected "
|
||||
"Setup State length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->wps_state = pos;
|
||||
break;
|
||||
case ATTR_AUTHENTICATOR:
|
||||
if (len != WPS_AUTHENTICATOR_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Authenticator "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->authenticator = pos;
|
||||
break;
|
||||
case ATTR_R_HASH1:
|
||||
if (len != WPS_HASH_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash1 length %u",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
attr->r_hash1 = pos;
|
||||
break;
|
||||
case ATTR_R_HASH2:
|
||||
if (len != WPS_HASH_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid R-Hash2 length %u",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
attr->r_hash2 = pos;
|
||||
break;
|
||||
case ATTR_E_HASH1:
|
||||
if (len != WPS_HASH_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash1 length %u",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
attr->e_hash1 = pos;
|
||||
break;
|
||||
case ATTR_E_HASH2:
|
||||
if (len != WPS_HASH_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid E-Hash2 length %u",
|
||||
len);
|
||||
return -1;
|
||||
}
|
||||
attr->e_hash2 = pos;
|
||||
break;
|
||||
case ATTR_R_SNONCE1:
|
||||
if (len != WPS_SECRET_NONCE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce1 length "
|
||||
"%u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->r_snonce1 = pos;
|
||||
break;
|
||||
case ATTR_R_SNONCE2:
|
||||
if (len != WPS_SECRET_NONCE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid R-SNonce2 length "
|
||||
"%u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->r_snonce2 = pos;
|
||||
break;
|
||||
case ATTR_E_SNONCE1:
|
||||
if (len != WPS_SECRET_NONCE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce1 length "
|
||||
"%u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->e_snonce1 = pos;
|
||||
break;
|
||||
case ATTR_E_SNONCE2:
|
||||
if (len != WPS_SECRET_NONCE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid E-SNonce2 length "
|
||||
"%u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->e_snonce2 = pos;
|
||||
break;
|
||||
case ATTR_KEY_WRAP_AUTH:
|
||||
if (len != WPS_KWA_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Key Wrap "
|
||||
"Authenticator length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->key_wrap_auth = pos;
|
||||
break;
|
||||
case ATTR_AUTH_TYPE:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Authentication "
|
||||
"Type length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->auth_type = pos;
|
||||
break;
|
||||
case ATTR_ENCR_TYPE:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Encryption "
|
||||
"Type length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->encr_type = pos;
|
||||
break;
|
||||
case ATTR_NETWORK_INDEX:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Network Index "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->network_idx = pos;
|
||||
break;
|
||||
case ATTR_NETWORK_KEY_INDEX:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Network Key Index "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->network_key_idx = pos;
|
||||
break;
|
||||
case ATTR_MAC_ADDR:
|
||||
if (len != ETH_ALEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid MAC Address "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->mac_addr = pos;
|
||||
break;
|
||||
case ATTR_KEY_PROVIDED_AUTO:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Key Provided "
|
||||
"Automatically length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->key_prov_auto = pos;
|
||||
break;
|
||||
case ATTR_802_1X_ENABLED:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid 802.1X Enabled "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->dot1x_enabled = pos;
|
||||
break;
|
||||
case ATTR_SELECTED_REGISTRAR:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Selected Registrar"
|
||||
" length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->selected_registrar = pos;
|
||||
break;
|
||||
case ATTR_REQUEST_TYPE:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Request Type "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->request_type = pos;
|
||||
break;
|
||||
case ATTR_RESPONSE_TYPE:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Response Type "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->response_type = pos;
|
||||
break;
|
||||
case ATTR_MANUFACTURER:
|
||||
attr->manufacturer = pos;
|
||||
attr->manufacturer_len = len;
|
||||
break;
|
||||
case ATTR_MODEL_NAME:
|
||||
attr->model_name = pos;
|
||||
attr->model_name_len = len;
|
||||
break;
|
||||
case ATTR_MODEL_NUMBER:
|
||||
attr->model_number = pos;
|
||||
attr->model_number_len = len;
|
||||
break;
|
||||
case ATTR_SERIAL_NUMBER:
|
||||
attr->serial_number = pos;
|
||||
attr->serial_number_len = len;
|
||||
break;
|
||||
case ATTR_DEV_NAME:
|
||||
attr->dev_name = pos;
|
||||
attr->dev_name_len = len;
|
||||
break;
|
||||
case ATTR_PUBLIC_KEY:
|
||||
attr->public_key = pos;
|
||||
attr->public_key_len = len;
|
||||
break;
|
||||
case ATTR_ENCR_SETTINGS:
|
||||
attr->encr_settings = pos;
|
||||
attr->encr_settings_len = len;
|
||||
break;
|
||||
case ATTR_CRED:
|
||||
if (attr->num_cred >= MAX_CRED_COUNT) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Skipped Credential "
|
||||
"attribute (max %d credentials)",
|
||||
MAX_CRED_COUNT);
|
||||
break;
|
||||
}
|
||||
attr->cred[attr->num_cred] = pos;
|
||||
attr->cred_len[attr->num_cred] = len;
|
||||
attr->num_cred++;
|
||||
break;
|
||||
case ATTR_SSID:
|
||||
attr->ssid = pos;
|
||||
attr->ssid_len = len;
|
||||
break;
|
||||
case ATTR_NETWORK_KEY:
|
||||
attr->network_key = pos;
|
||||
attr->network_key_len = len;
|
||||
break;
|
||||
case ATTR_EAP_TYPE:
|
||||
attr->eap_type = pos;
|
||||
attr->eap_type_len = len;
|
||||
break;
|
||||
case ATTR_EAP_IDENTITY:
|
||||
attr->eap_identity = pos;
|
||||
attr->eap_identity_len = len;
|
||||
break;
|
||||
case ATTR_AP_SETUP_LOCKED:
|
||||
if (len != 1) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->ap_setup_locked = pos;
|
||||
break;
|
||||
case ATTR_REQUESTED_DEV_TYPE:
|
||||
if (len != WPS_DEV_TYPE_LEN) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Requested Device "
|
||||
"Type length %u", len);
|
||||
return -1;
|
||||
}
|
||||
if (attr->num_req_dev_type >= MAX_REQ_DEV_TYPE_COUNT) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Skipped Requested Device "
|
||||
"Type attribute (max %u types)",
|
||||
MAX_REQ_DEV_TYPE_COUNT);
|
||||
break;
|
||||
}
|
||||
attr->req_dev_type[attr->num_req_dev_type] = pos;
|
||||
attr->num_req_dev_type++;
|
||||
break;
|
||||
case ATTR_SECONDARY_DEV_TYPE_LIST:
|
||||
if (len > WPS_SEC_DEV_TYPE_MAX_LEN ||
|
||||
(len % WPS_DEV_TYPE_LEN) > 0) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid Secondary Device "
|
||||
"Type length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->sec_dev_type_list = pos;
|
||||
attr->sec_dev_type_list_len = len;
|
||||
break;
|
||||
case ATTR_VENDOR_EXT:
|
||||
if (wps_parse_vendor_ext(attr, pos, len) < 0)
|
||||
return -1;
|
||||
break;
|
||||
case ATTR_AP_CHANNEL:
|
||||
if (len != 2) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid AP Channel "
|
||||
"length %u", len);
|
||||
return -1;
|
||||
}
|
||||
attr->ap_channel = pos;
|
||||
break;
|
||||
default:
|
||||
wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
|
||||
"len=%u", type, len);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr)
|
||||
{
|
||||
const u8 *pos, *end;
|
||||
u16 type, len;
|
||||
#ifdef WPS_WORKAROUNDS
|
||||
u16 prev_type = 0;
|
||||
#endif /* WPS_WORKAROUNDS */
|
||||
|
||||
os_memset(attr, 0, sizeof(*attr));
|
||||
pos = wpabuf_head(msg);
|
||||
end = pos + wpabuf_len(msg);
|
||||
|
||||
while (pos < end) {
|
||||
if (end - pos < 4) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid message - "
|
||||
"%lu bytes remaining",
|
||||
(unsigned long) (end - pos));
|
||||
return -1;
|
||||
}
|
||||
|
||||
type = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
len = WPA_GET_BE16(pos);
|
||||
pos += 2;
|
||||
wpa_printf(MSG_DEBUG, "WPS: attr type=0x%x len=%u",
|
||||
type, len);
|
||||
if (len > end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Attribute overflow");
|
||||
wpa_hexdump_buf(MSG_MSGDUMP, "WPS: Message data", msg);
|
||||
#ifdef WPS_WORKAROUNDS
|
||||
/*
|
||||
* Some deployed APs seem to have a bug in encoding of
|
||||
* Network Key attribute in the Credential attribute
|
||||
* where they add an extra octet after the Network Key
|
||||
* attribute at least when open network is being
|
||||
* provisioned.
|
||||
*/
|
||||
if ((type & 0xff00) != 0x1000 &&
|
||||
prev_type == ATTR_NETWORK_KEY) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Workaround - try "
|
||||
"to skip unexpected octet after "
|
||||
"Network Key");
|
||||
pos -= 3;
|
||||
continue;
|
||||
}
|
||||
#endif /* WPS_WORKAROUNDS */
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef WPS_WORKAROUNDS
|
||||
if (type == 0 && len == 0) {
|
||||
/*
|
||||
* Mac OS X 10.6 seems to be adding 0x00 padding to the
|
||||
* end of M1. Skip those to avoid interop issues.
|
||||
*/
|
||||
int i;
|
||||
for (i = 0; i < end - pos; i++) {
|
||||
if (pos[i])
|
||||
break;
|
||||
}
|
||||
if (i == end - pos) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Workaround - skip "
|
||||
"unexpected message padding");
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif /* WPS_WORKAROUNDS */
|
||||
|
||||
if (wps_set_attr(attr, type, pos, len) < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef WPS_WORKAROUNDS
|
||||
prev_type = type;
|
||||
#endif /* WPS_WORKAROUNDS */
|
||||
pos += len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
351
components/wpa_supplicant/src/wps/wps_attr_process.c
Normal file
351
components/wpa_supplicant/src/wps/wps_attr_process.c
Normal file
|
@ -0,0 +1,351 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - attribute processing
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#include "wpa/includes.h"
|
||||
|
||||
#include "wpa/common.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "wps/wps_i.h"
|
||||
|
||||
|
||||
int wps_process_authenticator(struct wps_data *wps, const u8 *authenticator,
|
||||
const struct wpabuf *msg)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
|
||||
if (authenticator == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Authenticator attribute "
|
||||
"included");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wps->last_msg == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Last message not available for "
|
||||
"validating authenticator");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Authenticator = HMAC-SHA256_AuthKey(M_prev || M_curr*)
|
||||
* (M_curr* is M_curr without the Authenticator attribute)
|
||||
*/
|
||||
addr[0] = wpabuf_head(wps->last_msg);
|
||||
len[0] = wpabuf_len(wps->last_msg);
|
||||
addr[1] = wpabuf_head(msg);
|
||||
len[1] = wpabuf_len(msg) - 4 - WPS_AUTHENTICATOR_LEN;
|
||||
if (wps_crypto_funcs.hmac_sha256_vector) {
|
||||
wps_crypto_funcs.hmac_sha256_vector(wps->authkey, WPS_AUTHKEY_LEN, 2, addr, (int *)len, hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register hmac_sha256_vector function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
if (os_memcmp(hash, authenticator, WPS_AUTHENTICATOR_LEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Incorrect Authenticator");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_process_key_wrap_auth(struct wps_data *wps, struct wpabuf *msg,
|
||||
const u8 *key_wrap_auth)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
const u8 *head;
|
||||
size_t len;
|
||||
|
||||
if (key_wrap_auth == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No KWA in decrypted attribute");
|
||||
return -1;
|
||||
}
|
||||
|
||||
head = wpabuf_head(msg);
|
||||
len = wpabuf_len(msg) - 4 - WPS_KWA_LEN;
|
||||
if (head + len != key_wrap_auth - 4) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: KWA not in the end of the "
|
||||
"decrypted attribute");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (wps_crypto_funcs.hmac_sha256) {
|
||||
wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, head, len, hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "Fail to register hmac sha256 function!\r\n");
|
||||
return -1;
|
||||
}
|
||||
if (os_memcmp(hash, key_wrap_auth, WPS_KWA_LEN) != 0) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid KWA");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_network_idx(struct wps_credential *cred,
|
||||
const u8 *idx)
|
||||
{
|
||||
if (idx == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
|
||||
"Network Index");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Network Index: %d", *idx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_ssid(struct wps_credential *cred, const u8 *ssid,
|
||||
size_t ssid_len)
|
||||
{
|
||||
if (ssid == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Credential did not include SSID");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove zero-padding since some Registrar implementations seem to use
|
||||
* hardcoded 32-octet length for this attribute */
|
||||
while (ssid_len > 0 && ssid[ssid_len - 1] == 0)
|
||||
ssid_len--;
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", ssid, ssid_len);
|
||||
if (ssid_len <= sizeof(cred->ssid)) {
|
||||
os_memcpy(cred->ssid, ssid, ssid_len);
|
||||
cred->ssid_len = ssid_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_auth_type(struct wps_credential *cred,
|
||||
const u8 *auth_type)
|
||||
{
|
||||
if (auth_type == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
|
||||
"Authentication Type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cred->auth_type = WPA_GET_BE16(auth_type);
|
||||
wpa_printf(MSG_DEBUG, "WPS: Authentication Type: 0x%x",
|
||||
cred->auth_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_encr_type(struct wps_credential *cred,
|
||||
const u8 *encr_type)
|
||||
{
|
||||
if (encr_type == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
|
||||
"Encryption Type");
|
||||
return -1;
|
||||
}
|
||||
|
||||
cred->encr_type = WPA_GET_BE16(encr_type);
|
||||
wpa_printf(MSG_DEBUG, "WPS: Encryption Type: 0x%x",
|
||||
cred->encr_type);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_network_key_idx(struct wps_credential *cred,
|
||||
const u8 *key_idx)
|
||||
{
|
||||
if (key_idx == NULL)
|
||||
return 0; /* optional attribute */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Network Key Index: %d", *key_idx);
|
||||
cred->key_idx = *key_idx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_network_key(struct wps_credential *cred,
|
||||
const u8 *key, size_t key_len)
|
||||
{
|
||||
if (key == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
|
||||
"Network Key");
|
||||
if (cred->auth_type == WPS_WIFI_AUTH_OPEN &&
|
||||
cred->encr_type == WPS_ENCR_NONE) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Workaround - Allow "
|
||||
"missing mandatory Network Key attribute "
|
||||
"for open network");
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key", key, key_len);
|
||||
if (key_len <= sizeof(cred->key)) {
|
||||
os_memcpy(cred->key, key, key_len);
|
||||
cred->key_len = key_len;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_mac_addr(struct wps_credential *cred,
|
||||
const u8 *mac_addr)
|
||||
{
|
||||
if (mac_addr == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Credential did not include "
|
||||
"MAC Address");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR, MAC2STR(mac_addr));
|
||||
os_memcpy(cred->mac_addr, mac_addr, ETH_ALEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_eap_type(struct wps_credential *cred,
|
||||
const u8 *eap_type, size_t eap_type_len)
|
||||
{
|
||||
if (eap_type == NULL)
|
||||
return 0; /* optional attribute */
|
||||
|
||||
wpa_hexdump(MSG_DEBUG, "WPS: EAP Type", eap_type, eap_type_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_eap_identity(struct wps_credential *cred,
|
||||
const u8 *identity,
|
||||
size_t identity_len)
|
||||
{
|
||||
if (identity == NULL)
|
||||
return 0; /* optional attribute */
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "WPS: EAP Identity",
|
||||
identity, identity_len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_key_prov_auto(struct wps_credential *cred,
|
||||
const u8 *key_prov_auto)
|
||||
{
|
||||
if (key_prov_auto == NULL)
|
||||
return 0; /* optional attribute */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Key Provided Automatically: %d",
|
||||
*key_prov_auto);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_802_1x_enabled(struct wps_credential *cred,
|
||||
const u8 *dot1x_enabled)
|
||||
{
|
||||
if (dot1x_enabled == NULL)
|
||||
return 0; /* optional attribute */
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: 802.1X Enabled: %d", *dot1x_enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_cred_ap_channel(struct wps_credential *cred,
|
||||
const u8 *ap_channel)
|
||||
{
|
||||
if (ap_channel == NULL)
|
||||
return 0; /* optional attribute */
|
||||
|
||||
cred->ap_channel = WPA_GET_BE16(ap_channel);
|
||||
wpa_printf(MSG_DEBUG, "WPS: AP Channel: %u", cred->ap_channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_workaround_cred_key(struct wps_credential *cred)
|
||||
{
|
||||
if (cred->auth_type & (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK) &&
|
||||
cred->key_len > 8 && cred->key_len < 64 &&
|
||||
cred->key[cred->key_len - 1] == 0) {
|
||||
#ifdef CONFIG_WPS_STRICT
|
||||
wpa_printf(MSG_INFO, "WPS: WPA/WPA2-Personal passphrase uses "
|
||||
"forbidden NULL termination");
|
||||
wpa_hexdump_ascii_key(MSG_INFO, "WPS: Network Key",
|
||||
cred->key, cred->key_len);
|
||||
return -1;
|
||||
#else /* CONFIG_WPS_STRICT */
|
||||
/*
|
||||
* A deployed external registrar is known to encode ASCII
|
||||
* passphrases incorrectly. Remove the extra NULL termination
|
||||
* to fix the encoding.
|
||||
*/
|
||||
wpa_printf(MSG_DEBUG, "WPS: Workaround - remove NULL "
|
||||
"termination from ASCII passphrase");
|
||||
cred->key_len--;
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_process_cred(struct wps_parse_attr *attr,
|
||||
struct wps_credential *cred)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: Process Credential");
|
||||
|
||||
/* TODO: support multiple Network Keys */
|
||||
if (wps_process_cred_network_idx(cred, attr->network_idx) ||
|
||||
wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
|
||||
wps_process_cred_auth_type(cred, attr->auth_type) ||
|
||||
wps_process_cred_encr_type(cred, attr->encr_type) ||
|
||||
wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
|
||||
wps_process_cred_network_key(cred, attr->network_key,
|
||||
attr->network_key_len) ||
|
||||
wps_process_cred_mac_addr(cred, attr->mac_addr) ||
|
||||
wps_process_cred_eap_type(cred, attr->eap_type,
|
||||
attr->eap_type_len) ||
|
||||
wps_process_cred_eap_identity(cred, attr->eap_identity,
|
||||
attr->eap_identity_len) ||
|
||||
wps_process_cred_key_prov_auto(cred, attr->key_prov_auto) ||
|
||||
wps_process_cred_802_1x_enabled(cred, attr->dot1x_enabled) ||
|
||||
wps_process_cred_ap_channel(cred, attr->ap_channel))
|
||||
return -1;
|
||||
|
||||
return wps_workaround_cred_key(cred);
|
||||
}
|
||||
|
||||
|
||||
int wps_process_ap_settings(struct wps_parse_attr *attr,
|
||||
struct wps_credential *cred)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: Processing AP Settings");
|
||||
os_memset(cred, 0, sizeof(*cred));
|
||||
/* TODO: optional attributes New Password and Device Password ID */
|
||||
if (wps_process_cred_ssid(cred, attr->ssid, attr->ssid_len) ||
|
||||
wps_process_cred_auth_type(cred, attr->auth_type) ||
|
||||
wps_process_cred_encr_type(cred, attr->encr_type) ||
|
||||
wps_process_cred_network_key_idx(cred, attr->network_key_idx) ||
|
||||
wps_process_cred_network_key(cred, attr->network_key,
|
||||
attr->network_key_len) ||
|
||||
wps_process_cred_mac_addr(cred, attr->mac_addr))
|
||||
return -1;
|
||||
|
||||
return wps_workaround_cred_key(cred);
|
||||
}
|
671
components/wpa_supplicant/src/wps/wps_common.c
Normal file
671
components/wpa_supplicant/src/wps/wps_common.c
Normal file
|
@ -0,0 +1,671 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - common functionality
|
||||
* Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#include <string.h>
|
||||
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/common.h"
|
||||
|
||||
#include "crypto/aes_wrap.h"
|
||||
#include "crypto/crypto.h"
|
||||
#include "crypto/dh_group5.h"
|
||||
#include "crypto/sha1.h"
|
||||
#include "crypto/sha256.h"
|
||||
#include "crypto/random.h"
|
||||
|
||||
#include "wps/wps_i.h"
|
||||
|
||||
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
|
||||
const char *label, u8 *res, size_t res_len)
|
||||
{
|
||||
u8 i_buf[4], key_bits[4];
|
||||
const u8 *addr[4];
|
||||
size_t len[4];
|
||||
int i, iter;
|
||||
u8 hash[SHA256_MAC_LEN], *opos;
|
||||
size_t left;
|
||||
|
||||
WPA_PUT_BE32(key_bits, res_len * 8);
|
||||
|
||||
addr[0] = i_buf;
|
||||
len[0] = sizeof(i_buf);
|
||||
addr[1] = label_prefix;
|
||||
len[1] = label_prefix_len;
|
||||
addr[2] = (const u8 *) label;
|
||||
len[2] = os_strlen(label);
|
||||
addr[3] = key_bits;
|
||||
len[3] = sizeof(key_bits);
|
||||
|
||||
iter = (res_len + SHA256_MAC_LEN - 1) / SHA256_MAC_LEN;
|
||||
opos = res;
|
||||
left = res_len;
|
||||
|
||||
for (i = 1; i <= iter; i++) {
|
||||
WPA_PUT_BE32(i_buf, i);
|
||||
if (wps_crypto_funcs.hmac_sha256_vector) {
|
||||
wps_crypto_funcs.hmac_sha256_vector(key, SHA256_MAC_LEN, 4, addr, (int *)len, hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to reigster hmac sha256 vector function!\r\n", __FUNCTION__);
|
||||
return ;
|
||||
}
|
||||
if (i < iter) {
|
||||
os_memcpy(opos, hash, SHA256_MAC_LEN);
|
||||
opos += SHA256_MAC_LEN;
|
||||
left -= SHA256_MAC_LEN;
|
||||
} else
|
||||
os_memcpy(opos, hash, left);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int wps_derive_keys(struct wps_data *wps)
|
||||
{
|
||||
struct wpabuf *pubkey, *dh_shared;
|
||||
u8 dhkey[SHA256_MAC_LEN], kdk[SHA256_MAC_LEN];
|
||||
const u8 *addr[3];
|
||||
size_t len[3];
|
||||
u8 keys[WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN + WPS_EMSK_LEN];
|
||||
|
||||
if (wps->dh_privkey == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Own DH private key not available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pubkey = wps->registrar ? wps->dh_pubkey_e : wps->dh_pubkey_r;
|
||||
if (pubkey == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Peer DH public key not available");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH Private Key", wps->dh_privkey);
|
||||
wpa_hexdump_buf(MSG_DEBUG, "WPS: DH peer Public Key", pubkey);
|
||||
dh_shared = dh5_derive_shared(wps->dh_ctx, pubkey, wps->dh_privkey);
|
||||
dh5_free(wps->dh_ctx);
|
||||
wps->dh_ctx = NULL;
|
||||
dh_shared = wpabuf_zeropad(dh_shared, 192);
|
||||
if (dh_shared == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Failed to derive DH shared key");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Own DH private key is not needed anymore */
|
||||
/*
|
||||
* due to the public key calculated when wps start, it will not calculate anymore even when we build M1 message, also calculate the key need take a long time
|
||||
* which would cause WPS fail, so we clean the key after WPS finished .
|
||||
*/
|
||||
#ifndef ESP32_WORKAROUND
|
||||
wpabuf_free(wps->dh_privkey);
|
||||
wps->dh_privkey = NULL;
|
||||
#endif //ESP32_WORKAROUND
|
||||
|
||||
wpa_hexdump_buf_key(MSG_DEBUG, "WPS: DH shared key", dh_shared);
|
||||
|
||||
/* DHKey = SHA-256(g^AB mod p) */
|
||||
addr[0] = wpabuf_head(dh_shared);
|
||||
len[0] = wpabuf_len(dh_shared);
|
||||
|
||||
if (wps_crypto_funcs.sha256_vector) {
|
||||
wps_crypto_funcs.sha256_vector(1, addr, (int *)len, dhkey);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, Fail to register sha256 vector function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: DHKey", dhkey, sizeof(dhkey));
|
||||
wpabuf_free(dh_shared);
|
||||
|
||||
/* KDK = HMAC-SHA-256_DHKey(N1 || EnrolleeMAC || N2) */
|
||||
addr[0] = wps->nonce_e;
|
||||
len[0] = WPS_NONCE_LEN;
|
||||
addr[1] = wps->mac_addr_e;
|
||||
len[1] = ETH_ALEN;
|
||||
addr[2] = wps->nonce_r;
|
||||
len[2] = WPS_NONCE_LEN;
|
||||
if (wps_crypto_funcs.hmac_sha256_vector) {
|
||||
wps_crypto_funcs.hmac_sha256_vector(dhkey, sizeof(dhkey), 3, addr, (int *)len, kdk);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, Fail to register hmac sha256 vector function!\r\n", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: KDK", kdk, sizeof(kdk));
|
||||
|
||||
wps_kdf(kdk, NULL, 0, "Wi-Fi Easy and Secure Key Derivation",
|
||||
keys, sizeof(keys));
|
||||
os_memcpy(wps->authkey, keys, WPS_AUTHKEY_LEN);
|
||||
os_memcpy(wps->keywrapkey, keys + WPS_AUTHKEY_LEN, WPS_KEYWRAPKEY_LEN);
|
||||
os_memcpy(wps->emsk, keys + WPS_AUTHKEY_LEN + WPS_KEYWRAPKEY_LEN,
|
||||
WPS_EMSK_LEN);
|
||||
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: AuthKey",
|
||||
wps->authkey, WPS_AUTHKEY_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: KeyWrapKey",
|
||||
wps->keywrapkey, WPS_KEYWRAPKEY_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: EMSK", wps->emsk, WPS_EMSK_LEN);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
|
||||
size_t dev_passwd_len)
|
||||
{
|
||||
u8 hash[SHA256_MAC_LEN];
|
||||
|
||||
if (wps_crypto_funcs.hmac_sha256) {
|
||||
wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN, dev_passwd,
|
||||
(dev_passwd_len + 1) / 2, hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256 function!\r\n", __FUNCTION__);
|
||||
return ;
|
||||
}
|
||||
os_memcpy(wps->psk1, hash, WPS_PSK_LEN);
|
||||
if (wps_crypto_funcs.hmac_sha256) {
|
||||
wps_crypto_funcs.hmac_sha256(wps->authkey, WPS_AUTHKEY_LEN,
|
||||
dev_passwd + (dev_passwd_len + 1) / 2,
|
||||
dev_passwd_len / 2, hash);
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register hmac_sha256 function!\r\n", __FUNCTION__);
|
||||
return ;
|
||||
}
|
||||
os_memcpy(wps->psk2, hash, WPS_PSK_LEN);
|
||||
|
||||
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: Device Password",
|
||||
dev_passwd, dev_passwd_len);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: PSK1", wps->psk1, WPS_PSK_LEN);
|
||||
wpa_hexdump_key(MSG_DEBUG, "WPS: PSK2", wps->psk2, WPS_PSK_LEN);
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
|
||||
size_t encr_len)
|
||||
{
|
||||
struct wpabuf *decrypted;
|
||||
const size_t block_size = 16;
|
||||
size_t i;
|
||||
u8 pad;
|
||||
const u8 *pos;
|
||||
|
||||
/* AES-128-CBC */
|
||||
if (encr == NULL || encr_len < 2 * block_size || encr_len % block_size)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Encrypted Settings received");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
decrypted = wpabuf_alloc(encr_len - block_size);
|
||||
if (decrypted == NULL)
|
||||
return NULL;
|
||||
|
||||
wpa_hexdump(MSG_MSGDUMP, "WPS: Encrypted Settings", encr, encr_len);
|
||||
wpabuf_put_data(decrypted, encr + block_size, encr_len - block_size);
|
||||
wpa_printf(MSG_DEBUG, "WPS: AES Decrypt setting");
|
||||
if (wps_crypto_funcs.aes_128_decrypt) {
|
||||
if (wps_crypto_funcs.aes_128_decrypt(wps->keywrapkey, encr, wpabuf_mhead(decrypted),
|
||||
wpabuf_len(decrypted))) {
|
||||
wpabuf_free(decrypted);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
wpa_printf(MSG_ERROR, "In function %s, fail to register aes 128 decrypt function!\r\n", __FUNCTION__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
wpa_hexdump_buf_key(MSG_MSGDUMP, "WPS: Decrypted Encrypted Settings",
|
||||
decrypted);
|
||||
|
||||
pos = wpabuf_head_u8(decrypted) + wpabuf_len(decrypted) - 1;
|
||||
pad = *pos;
|
||||
if (pad > wpabuf_len(decrypted)) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad value");
|
||||
wpabuf_free(decrypted);
|
||||
return NULL;
|
||||
}
|
||||
for (i = 0; i < pad; i++) {
|
||||
if (*pos-- != pad) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: Invalid PKCS#5 v2.0 pad "
|
||||
"string");
|
||||
wpabuf_free(decrypted);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
decrypted->used -= pad;
|
||||
|
||||
return decrypted;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WPS_PIN
|
||||
/**
|
||||
* wps_pin_checksum - Compute PIN checksum
|
||||
* @pin: Seven digit PIN (i.e., eight digit PIN without the checksum digit)
|
||||
* Returns: Checksum digit
|
||||
*/
|
||||
unsigned int wps_pin_checksum(unsigned int pin)
|
||||
{
|
||||
unsigned int accum = 0;
|
||||
while (pin) {
|
||||
accum += 3 * (pin % 10);
|
||||
pin /= 10;
|
||||
accum += pin % 10;
|
||||
pin /= 10;
|
||||
}
|
||||
|
||||
return (10 - accum % 10) % 10;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_pin_valid - Check whether a PIN has a valid checksum
|
||||
* @pin: Eight digit PIN (i.e., including the checksum digit)
|
||||
* Returns: 1 if checksum digit is valid, or 0 if not
|
||||
*/
|
||||
unsigned int wps_pin_valid(unsigned int pin)
|
||||
{
|
||||
return wps_pin_checksum(pin / 10) == (pin % 10);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* wps_generate_pin - Generate a random PIN
|
||||
* Returns: Eight digit PIN (i.e., including the checksum digit)
|
||||
*/
|
||||
unsigned int wps_generate_pin(void)
|
||||
{
|
||||
unsigned int val;
|
||||
|
||||
/* Generate seven random digits for the PIN */
|
||||
if (random_get_bytes((unsigned char *) &val, sizeof(val)) < 0) {
|
||||
return -1;
|
||||
}
|
||||
val %= 10000000;
|
||||
|
||||
/* Append checksum digit */
|
||||
return val * 10 + wps_pin_checksum(val);
|
||||
}
|
||||
|
||||
|
||||
int wps_pin_str_valid(const char *pin)
|
||||
{
|
||||
const char *p;
|
||||
size_t len;
|
||||
|
||||
p = pin;
|
||||
while (*p >= '0' && *p <= '9')
|
||||
p++;
|
||||
if (*p != '\0')
|
||||
return 0;
|
||||
|
||||
len = p - pin;
|
||||
return len == 4 || len == 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg,
|
||||
u16 config_error, u16 error_indication)
|
||||
{
|
||||
union wps_event_data *data;
|
||||
|
||||
data = (union wps_event_data *)os_zalloc(sizeof(union wps_event_data));
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
if (wps->event_cb == NULL) {
|
||||
os_free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
os_memset(data, 0, sizeof(union wps_event_data));
|
||||
data->fail.msg = msg;
|
||||
data->fail.config_error = config_error;
|
||||
data->fail.error_indication = error_indication;
|
||||
wps->event_cb(wps->cb_ctx, WPS_EV_FAIL, data);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
void wps_success_event(struct wps_context *wps)
|
||||
{
|
||||
if (wps->event_cb == NULL)
|
||||
return;
|
||||
|
||||
wps->event_cb(wps->cb_ctx, WPS_EV_SUCCESS, NULL);
|
||||
}
|
||||
|
||||
|
||||
void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
|
||||
{
|
||||
union wps_event_data *data;
|
||||
|
||||
data = (union wps_event_data *)os_zalloc(sizeof(union wps_event_data));
|
||||
if (data == NULL)
|
||||
return;
|
||||
|
||||
if (wps->event_cb == NULL) {
|
||||
os_free(data);
|
||||
return;
|
||||
}
|
||||
|
||||
os_memset(data, 0, sizeof(union wps_event_data));
|
||||
data->pwd_auth_fail.enrollee = enrollee;
|
||||
data->pwd_auth_fail.part = part;
|
||||
wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, data);
|
||||
os_free(data);
|
||||
}
|
||||
|
||||
|
||||
void wps_pbc_overlap_event(struct wps_context *wps)
|
||||
{
|
||||
if (wps->event_cb == NULL)
|
||||
return;
|
||||
|
||||
wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
|
||||
}
|
||||
|
||||
|
||||
void wps_pbc_timeout_event(struct wps_context *wps)
|
||||
{
|
||||
if (wps->event_cb == NULL)
|
||||
return;
|
||||
|
||||
wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WPS_OOB
|
||||
|
||||
struct wpabuf * wps_get_oob_cred(struct wps_context *wps)
|
||||
{
|
||||
struct wps_data *data;
|
||||
struct wpabuf *plain;
|
||||
|
||||
data = (struct wps_data *)os_zalloc(sizeof(struct wps_data));
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
plain = wpabuf_alloc(500);
|
||||
if (plain == NULL) {
|
||||
os_free(data);
|
||||
wpa_printf(MSG_ERROR, "WPS: Failed to allocate memory for OOB "
|
||||
"credential");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_memset(data, 0, sizeof(struct wps_data));
|
||||
data->wps = wps;
|
||||
data->auth_type = wps->auth_types;
|
||||
data->encr_type = wps->encr_types;
|
||||
if (wps_build_version(plain) ||
|
||||
wps_build_cred(data, plain) ||
|
||||
wps_build_wfa_ext(plain, 0, NULL, 0)) {
|
||||
wpabuf_free(plain);
|
||||
os_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
os_free(data);
|
||||
return plain;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
|
||||
struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
|
||||
const struct wpabuf *pubkey,
|
||||
const struct wpabuf *dev_pw)
|
||||
{
|
||||
struct wpabuf *data;
|
||||
|
||||
data = wpabuf_alloc(200);
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
if (wps_build_version(data) ||
|
||||
wps_build_oob_dev_pw(data, dev_pw_id, pubkey,
|
||||
wpabuf_head(dev_pw), wpabuf_len(dev_pw)) ||
|
||||
wps_build_wfa_ext(data, 0, NULL, 0)) {
|
||||
wpa_printf(MSG_ERROR, "WPS: Failed to build NFC password "
|
||||
"token");
|
||||
wpabuf_free(data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr)
|
||||
{
|
||||
struct wpabuf msg;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < attr->num_cred; i++) {
|
||||
struct wps_credential local_cred;
|
||||
struct wps_parse_attr cattr;
|
||||
|
||||
os_memset(&local_cred, 0, sizeof(local_cred));
|
||||
wpabuf_set(&msg, attr->cred[i], attr->cred_len[i]);
|
||||
if (wps_parse_msg(&msg, &cattr) < 0 ||
|
||||
wps_process_cred(&cattr, &local_cred)) {
|
||||
wpa_printf(MSG_ERROR, "WPS: Failed to parse OOB "
|
||||
"credential");
|
||||
return -1;
|
||||
}
|
||||
wps->cred_cb(wps->cb_ctx, &local_cred);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_WPS_OOB */
|
||||
|
||||
|
||||
int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN])
|
||||
{
|
||||
const char *pos;
|
||||
|
||||
/* <categ>-<OUI>-<subcateg> */
|
||||
WPA_PUT_BE16(dev_type, atoi(str));
|
||||
pos = (char *)os_strchr(str, '-');
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
pos++;
|
||||
if (hexstr2bin(pos, &dev_type[2], 4))
|
||||
return -1;
|
||||
pos = (char *)os_strchr(pos, '-');
|
||||
if (pos == NULL)
|
||||
return -1;
|
||||
pos++;
|
||||
WPA_PUT_BE16(&dev_type[6], atoi(pos));
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
|
||||
size_t buf_len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = snprintf(buf, buf_len, "%u-%08X-%u",
|
||||
WPA_GET_BE16(dev_type), WPA_GET_BE32(&dev_type[2]),
|
||||
WPA_GET_BE16(&dev_type[6]));
|
||||
if (ret < 0 || (unsigned int) ret >= buf_len)
|
||||
return NULL;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid)
|
||||
{
|
||||
const u8 *addr[2];
|
||||
size_t len[2];
|
||||
u8 hash[SHA1_MAC_LEN];
|
||||
u8 nsid[16] = {
|
||||
0x52, 0x64, 0x80, 0xf8,
|
||||
0xc9, 0x9b,
|
||||
0x4b, 0xe5,
|
||||
0xa6, 0x55,
|
||||
0x58, 0xed, 0x5f, 0x5d, 0x60, 0x84
|
||||
};
|
||||
|
||||
addr[0] = nsid;
|
||||
len[0] = sizeof(nsid);
|
||||
addr[1] = mac_addr;
|
||||
len[1] = 6;
|
||||
sha1_vector(2, addr, len, hash);
|
||||
os_memcpy(uuid, hash, 16);
|
||||
|
||||
/* Version: 5 = named-based version using SHA-1 */
|
||||
uuid[6] = (5 << 4) | (uuid[6] & 0x0f);
|
||||
|
||||
/* Variant specified in RFC 4122 */
|
||||
uuid[8] = 0x80 | (uuid[8] & 0x3f);
|
||||
}
|
||||
|
||||
|
||||
u16 wps_config_methods_str2bin(const char *str)
|
||||
{
|
||||
u16 methods = 0;
|
||||
|
||||
if (str == NULL) {
|
||||
/* Default to enabling methods based on build configuration */
|
||||
methods |= WPS_CONFIG_DISPLAY | WPS_CONFIG_KEYPAD;
|
||||
#ifdef CONFIG_WPS2
|
||||
methods |= WPS_CONFIG_VIRT_DISPLAY;
|
||||
#endif /* CONFIG_WPS2 */
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
methods |= WPS_CONFIG_NFC_INTERFACE;
|
||||
#endif /* CONFIG_WPS_NFC */
|
||||
} else {
|
||||
if (os_strstr(str, "ethernet"))
|
||||
methods |= WPS_CONFIG_ETHERNET;
|
||||
if (os_strstr(str, "label"))
|
||||
methods |= WPS_CONFIG_LABEL;
|
||||
if (os_strstr(str, "display"))
|
||||
methods |= WPS_CONFIG_DISPLAY;
|
||||
if (os_strstr(str, "ext_nfc_token"))
|
||||
methods |= WPS_CONFIG_EXT_NFC_TOKEN;
|
||||
if (os_strstr(str, "int_nfc_token"))
|
||||
methods |= WPS_CONFIG_INT_NFC_TOKEN;
|
||||
if (os_strstr(str, "nfc_interface"))
|
||||
methods |= WPS_CONFIG_NFC_INTERFACE;
|
||||
if (os_strstr(str, "push_button"))
|
||||
methods |= WPS_CONFIG_PUSHBUTTON;
|
||||
if (os_strstr(str, "keypad"))
|
||||
methods |= WPS_CONFIG_KEYPAD;
|
||||
#ifdef CONFIG_WPS2
|
||||
if (os_strstr(str, "virtual_display"))
|
||||
methods |= WPS_CONFIG_VIRT_DISPLAY;
|
||||
if (os_strstr(str, "physical_display"))
|
||||
methods |= WPS_CONFIG_PHY_DISPLAY;
|
||||
if (os_strstr(str, "virtual_push_button"))
|
||||
methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
|
||||
if (os_strstr(str, "physical_push_button"))
|
||||
methods |= WPS_CONFIG_PHY_PUSHBUTTON;
|
||||
#endif /* CONFIG_WPS2 */
|
||||
}
|
||||
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * wps_build_wsc_ack(struct wps_data *wps)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_ACK");
|
||||
|
||||
msg = wpabuf_alloc(1000);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
if (wps_build_version(msg) ||
|
||||
wps_build_msg_type(msg, WPS_WSC_ACK) ||
|
||||
wps_build_enrollee_nonce(wps, msg) ||
|
||||
wps_build_registrar_nonce(wps, msg) ||
|
||||
wps_build_wfa_ext(msg, 0, NULL, 0)) {
|
||||
wpabuf_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
struct wpabuf * wps_build_wsc_nack(struct wps_data *wps)
|
||||
{
|
||||
struct wpabuf *msg;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: Building Message WSC_NACK");
|
||||
|
||||
msg = wpabuf_alloc(1000);
|
||||
if (msg == NULL)
|
||||
return NULL;
|
||||
|
||||
if (wps_build_version(msg) ||
|
||||
wps_build_msg_type(msg, WPS_WSC_NACK) ||
|
||||
wps_build_enrollee_nonce(wps, msg) ||
|
||||
wps_build_registrar_nonce(wps, msg) ||
|
||||
wps_build_config_error(msg, wps->config_error) ||
|
||||
wps_build_wfa_ext(msg, 0, NULL, 0)) {
|
||||
wpabuf_free(msg);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_WPS_NFC
|
||||
struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
|
||||
struct wpabuf **privkey,
|
||||
struct wpabuf **dev_pw)
|
||||
{
|
||||
struct wpabuf *priv = NULL, *pub = NULL, *pw, *ret;
|
||||
void *dh_ctx;
|
||||
u16 val;
|
||||
|
||||
pw = wpabuf_alloc(WPS_OOB_DEVICE_PASSWORD_LEN);
|
||||
if (pw == NULL)
|
||||
return NULL;
|
||||
|
||||
if (random_get_bytes(wpabuf_put(pw, WPS_OOB_DEVICE_PASSWORD_LEN),
|
||||
WPS_OOB_DEVICE_PASSWORD_LEN) ||
|
||||
random_get_bytes((u8 *) &val, sizeof(val))) {
|
||||
wpabuf_free(pw);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dh_ctx = dh5_init(&priv, &pub);
|
||||
if (dh_ctx == NULL) {
|
||||
wpabuf_free(pw);
|
||||
return NULL;
|
||||
}
|
||||
dh5_free(dh_ctx);
|
||||
|
||||
*id = 0x10 + val % 0xfff0;
|
||||
wpabuf_free(*pubkey);
|
||||
*pubkey = pub;
|
||||
wpabuf_free(*privkey);
|
||||
*privkey = priv;
|
||||
wpabuf_free(*dev_pw);
|
||||
*dev_pw = pw;
|
||||
|
||||
ret = wps_build_nfc_pw_token(*id, *pubkey, *dev_pw);
|
||||
if (ndef && ret) {
|
||||
struct wpabuf *tmp;
|
||||
tmp = ndef_build_wifi(ret);
|
||||
wpabuf_free(ret);
|
||||
if (tmp == NULL)
|
||||
return NULL;
|
||||
ret = tmp;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_WPS_NFC */
|
451
components/wpa_supplicant/src/wps/wps_dev_attr.c
Normal file
451
components/wpa_supplicant/src/wps/wps_dev_attr.c
Normal file
|
@ -0,0 +1,451 @@
|
|||
/*
|
||||
* Wi-Fi Protected Setup - device attributes
|
||||
* Copyright (c) 2008, Jouni Malinen <j@w1.fi>
|
||||
*
|
||||
* This software may be distributed under the terms of the BSD license.
|
||||
* See README for more details.
|
||||
*/
|
||||
#include "wpa/includes.h"
|
||||
#include "wpa/common.h"
|
||||
|
||||
#include "wps/wps_i.h"
|
||||
#include "wps/wps_dev_attr.h"
|
||||
|
||||
int wps_build_manufacturer(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
size_t len;
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Manufacturer");
|
||||
wpabuf_put_be16(msg, ATTR_MANUFACTURER);
|
||||
len = dev->manufacturer ? os_strlen(dev->manufacturer) : 0;
|
||||
#ifndef CONFIG_WPS_STRICT
|
||||
if (len == 0) {
|
||||
/*
|
||||
* Some deployed WPS implementations fail to parse zero-length
|
||||
* attributes. As a workaround, send a space character if the
|
||||
* device attribute string is empty.
|
||||
*/
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, ' ');
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
wpabuf_put_be16(msg, len);
|
||||
wpabuf_put_data(msg, dev->manufacturer, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_model_name(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
size_t len;
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Model Name");
|
||||
wpabuf_put_be16(msg, ATTR_MODEL_NAME);
|
||||
len = dev->model_name ? os_strlen(dev->model_name) : 0;
|
||||
#ifndef CONFIG_WPS_STRICT
|
||||
if (len == 0) {
|
||||
/*
|
||||
* Some deployed WPS implementations fail to parse zero-length
|
||||
* attributes. As a workaround, send a space character if the
|
||||
* device attribute string is empty.
|
||||
*/
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, ' ');
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
wpabuf_put_be16(msg, len);
|
||||
wpabuf_put_data(msg, dev->model_name, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_model_number(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
size_t len;
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Model Number");
|
||||
wpabuf_put_be16(msg, ATTR_MODEL_NUMBER);
|
||||
len = dev->model_number ? os_strlen(dev->model_number) : 0;
|
||||
#ifndef CONFIG_WPS_STRICT
|
||||
if (len == 0) {
|
||||
/*
|
||||
* Some deployed WPS implementations fail to parse zero-length
|
||||
* attributes. As a workaround, send a space character if the
|
||||
* device attribute string is empty.
|
||||
*/
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, ' ');
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
wpabuf_put_be16(msg, len);
|
||||
wpabuf_put_data(msg, dev->model_number, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_build_serial_number(struct wps_device_data *dev,
|
||||
struct wpabuf *msg)
|
||||
{
|
||||
size_t len;
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Serial Number");
|
||||
wpabuf_put_be16(msg, ATTR_SERIAL_NUMBER);
|
||||
len = dev->serial_number ? os_strlen(dev->serial_number) : 0;
|
||||
#ifndef CONFIG_WPS_STRICT
|
||||
if (len == 0) {
|
||||
/*
|
||||
* Some deployed WPS implementations fail to parse zero-length
|
||||
* attributes. As a workaround, send a space character if the
|
||||
* device attribute string is empty.
|
||||
*/
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, ' ');
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
wpabuf_put_be16(msg, len);
|
||||
wpabuf_put_data(msg, dev->serial_number, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_primary_dev_type(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Primary Device Type");
|
||||
wpabuf_put_be16(msg, ATTR_PRIMARY_DEV_TYPE);
|
||||
wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
|
||||
wpabuf_put_data(msg, dev->pri_dev_type, WPS_DEV_TYPE_LEN);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_secondary_dev_type(struct wps_device_data *dev,
|
||||
struct wpabuf *msg)
|
||||
{
|
||||
if (!dev->num_sec_dev_types)
|
||||
return 0;
|
||||
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Secondary Device Type");
|
||||
wpabuf_put_be16(msg, ATTR_SECONDARY_DEV_TYPE_LIST);
|
||||
wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
|
||||
wpabuf_put_data(msg, dev->sec_dev_type,
|
||||
WPS_DEV_TYPE_LEN * dev->num_sec_dev_types);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_req_dev_type(struct wps_device_data *dev, struct wpabuf *msg,
|
||||
unsigned int num_req_dev_types,
|
||||
const u8 *req_dev_types)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num_req_dev_types; i++) {
|
||||
wpa_hexdump(MSG_DEBUG, "WPS: * Requested Device Type",
|
||||
req_dev_types + i * WPS_DEV_TYPE_LEN,
|
||||
WPS_DEV_TYPE_LEN);
|
||||
wpabuf_put_be16(msg, ATTR_REQUESTED_DEV_TYPE);
|
||||
wpabuf_put_be16(msg, WPS_DEV_TYPE_LEN);
|
||||
wpabuf_put_data(msg, req_dev_types + i * WPS_DEV_TYPE_LEN,
|
||||
WPS_DEV_TYPE_LEN);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_dev_name(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
size_t len;
|
||||
wpa_printf(MSG_DEBUG, "WPS: * Device Name");
|
||||
wpabuf_put_be16(msg, ATTR_DEV_NAME);
|
||||
len = dev->device_name ? os_strlen(dev->device_name) : 0;
|
||||
#ifndef CONFIG_WPS_STRICT
|
||||
if (len == 0) {
|
||||
/*
|
||||
* Some deployed WPS implementations fail to parse zero-length
|
||||
* attributes. As a workaround, send a space character if the
|
||||
* device attribute string is empty.
|
||||
*/
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, ' ');
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_WPS_STRICT */
|
||||
wpabuf_put_be16(msg, len);
|
||||
wpabuf_put_data(msg, dev->device_name, len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_device_attrs(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
if (wps_build_manufacturer(dev, msg) ||
|
||||
wps_build_model_name(dev, msg) ||
|
||||
wps_build_model_number(dev, msg) ||
|
||||
wps_build_serial_number(dev, msg) ||
|
||||
wps_build_primary_dev_type(dev, msg) ||
|
||||
wps_build_dev_name(dev, msg))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_os_version(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * OS Version");
|
||||
wpabuf_put_be16(msg, ATTR_OS_VERSION);
|
||||
wpabuf_put_be16(msg, 4);
|
||||
wpabuf_put_be32(msg, 0x80000000 | dev->os_version);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_vendor_ext_m1(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
if (dev->vendor_ext_m1 != NULL) {
|
||||
wpa_hexdump(MSG_DEBUG, "WPS: * Vendor Extension M1",
|
||||
wpabuf_head_u8(dev->vendor_ext_m1),
|
||||
wpabuf_len(dev->vendor_ext_m1));
|
||||
wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
|
||||
wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext_m1));
|
||||
wpabuf_put_buf(msg, dev->vendor_ext_m1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_rf_bands(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
wpa_printf(MSG_DEBUG, "WPS: * RF Bands (%x)", dev->rf_bands);
|
||||
wpabuf_put_be16(msg, ATTR_RF_BANDS);
|
||||
wpabuf_put_be16(msg, 1);
|
||||
wpabuf_put_u8(msg, dev->rf_bands);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_build_vendor_ext(struct wps_device_data *dev, struct wpabuf *msg)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
|
||||
if (dev->vendor_ext[i] == NULL)
|
||||
continue;
|
||||
wpa_hexdump(MSG_DEBUG, "WPS: * Vendor Extension",
|
||||
wpabuf_head_u8(dev->vendor_ext[i]),
|
||||
wpabuf_len(dev->vendor_ext[i]));
|
||||
wpabuf_put_be16(msg, ATTR_VENDOR_EXT);
|
||||
wpabuf_put_be16(msg, wpabuf_len(dev->vendor_ext[i]));
|
||||
wpabuf_put_buf(msg, dev->vendor_ext[i]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_manufacturer(struct wps_device_data *dev, const u8 *str,
|
||||
size_t str_len)
|
||||
{
|
||||
if (str == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Manufacturer received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Manufacturer", str, str_len);
|
||||
|
||||
os_free(dev->manufacturer);
|
||||
dev->manufacturer = (char *)os_malloc(str_len + 1);
|
||||
if (dev->manufacturer == NULL)
|
||||
return -1;
|
||||
os_memcpy(dev->manufacturer, str, str_len);
|
||||
dev->manufacturer[str_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_model_name(struct wps_device_data *dev, const u8 *str,
|
||||
size_t str_len)
|
||||
{
|
||||
if (str == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Model Name received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Name", str, str_len);
|
||||
|
||||
os_free(dev->model_name);
|
||||
dev->model_name = (char *)os_malloc(str_len + 1);
|
||||
if (dev->model_name == NULL)
|
||||
return -1;
|
||||
os_memcpy(dev->model_name, str, str_len);
|
||||
dev->model_name[str_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_model_number(struct wps_device_data *dev, const u8 *str,
|
||||
size_t str_len)
|
||||
{
|
||||
if (str == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Model Number received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Model Number", str, str_len);
|
||||
|
||||
os_free(dev->model_number);
|
||||
dev->model_number = (char *)os_malloc(str_len + 1);
|
||||
if (dev->model_number == NULL)
|
||||
return -1;
|
||||
os_memcpy(dev->model_number, str, str_len);
|
||||
dev->model_number[str_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_serial_number(struct wps_device_data *dev,
|
||||
const u8 *str, size_t str_len)
|
||||
{
|
||||
if (str == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Serial Number received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Serial Number", str, str_len);
|
||||
|
||||
os_free(dev->serial_number);
|
||||
dev->serial_number = (char *)os_malloc(str_len + 1);
|
||||
if (dev->serial_number == NULL)
|
||||
return -1;
|
||||
os_memcpy(dev->serial_number, str, str_len);
|
||||
dev->serial_number[str_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_dev_name(struct wps_device_data *dev, const u8 *str,
|
||||
size_t str_len)
|
||||
{
|
||||
if (str == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Device Name received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
wpa_hexdump_ascii(MSG_DEBUG, "WPS: Device Name", str, str_len);
|
||||
|
||||
os_free(dev->device_name);
|
||||
dev->device_name = (char *)os_malloc(str_len + 1);
|
||||
if (dev->device_name == NULL)
|
||||
return -1;
|
||||
os_memcpy(dev->device_name, str, str_len);
|
||||
dev->device_name[str_len] = '\0';
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int wps_process_primary_dev_type(struct wps_device_data *dev,
|
||||
const u8 *dev_type)
|
||||
{
|
||||
#if 0
|
||||
#ifndef CONFIG_NO_STDOUT_DEBUG
|
||||
char devtype[WPS_DEV_TYPE_BUFSIZE];
|
||||
#endif /* CONFIG_NO_STDOUT_DEBUG */
|
||||
#endif
|
||||
if (dev_type == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No Primary Device Type received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
os_memcpy(dev->pri_dev_type, dev_type, WPS_DEV_TYPE_LEN);
|
||||
//wpa_printf(MSG_DEBUG, "WPS: Primary Device Type: %s",
|
||||
// wps_dev_type_bin2str(dev->pri_dev_type, devtype,
|
||||
// sizeof(devtype)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_process_device_attrs(struct wps_device_data *dev,
|
||||
struct wps_parse_attr *attr)
|
||||
{
|
||||
if (wps_process_manufacturer(dev, attr->manufacturer,
|
||||
attr->manufacturer_len) ||
|
||||
wps_process_model_name(dev, attr->model_name,
|
||||
attr->model_name_len) ||
|
||||
wps_process_model_number(dev, attr->model_number,
|
||||
attr->model_number_len) ||
|
||||
wps_process_serial_number(dev, attr->serial_number,
|
||||
attr->serial_number_len) ||
|
||||
wps_process_primary_dev_type(dev, attr->primary_dev_type) ||
|
||||
wps_process_dev_name(dev, attr->dev_name, attr->dev_name_len))
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_process_os_version(struct wps_device_data *dev, const u8 *ver)
|
||||
{
|
||||
if (ver == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No OS Version received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->os_version = WPA_GET_BE32(ver);
|
||||
wpa_printf(MSG_DEBUG, "WPS: OS Version %08x", dev->os_version);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int wps_process_rf_bands(struct wps_device_data *dev, const u8 *bands)
|
||||
{
|
||||
if (bands == NULL) {
|
||||
wpa_printf(MSG_DEBUG, "WPS: No RF Bands received");
|
||||
return -1;
|
||||
}
|
||||
|
||||
dev->rf_bands = *bands;
|
||||
wpa_printf(MSG_DEBUG, "WPS: Enrollee RF Bands 0x%x", dev->rf_bands);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void wps_device_data_dup(struct wps_device_data *dst,
|
||||
const struct wps_device_data *src)
|
||||
{
|
||||
if (src->device_name)
|
||||
dst->device_name = os_strdup(src->device_name);
|
||||
if (src->manufacturer)
|
||||
dst->manufacturer = os_strdup(src->manufacturer);
|
||||
if (src->model_name)
|
||||
dst->model_name = os_strdup(src->model_name);
|
||||
if (src->model_number)
|
||||
dst->model_number = os_strdup(src->model_number);
|
||||
if (src->serial_number)
|
||||
dst->serial_number = os_strdup(src->serial_number);
|
||||
os_memcpy(dst->pri_dev_type, src->pri_dev_type, WPS_DEV_TYPE_LEN);
|
||||
dst->os_version = src->os_version;
|
||||
dst->rf_bands = src->rf_bands;
|
||||
}
|
||||
|
||||
|
||||
void wps_device_data_free(struct wps_device_data *dev)
|
||||
{
|
||||
os_free(dev->device_name);
|
||||
dev->device_name = NULL;
|
||||
os_free(dev->manufacturer);
|
||||
dev->manufacturer = NULL;
|
||||
os_free(dev->model_name);
|
||||
dev->model_name = NULL;
|
||||
os_free(dev->model_number);
|
||||
dev->model_number = NULL;
|
||||
os_free(dev->serial_number);
|
||||
dev->serial_number = NULL;
|
||||
}
|
1574
components/wpa_supplicant/src/wps/wps_enrollee.c
Normal file
1574
components/wpa_supplicant/src/wps/wps_enrollee.c
Normal file
File diff suppressed because it is too large
Load diff
3635
components/wpa_supplicant/src/wps/wps_registrar.c
Normal file
3635
components/wpa_supplicant/src/wps/wps_registrar.c
Normal file
File diff suppressed because it is too large
Load diff
2375
components/wpa_supplicant/src/wps/wps_validate.c
Normal file
2375
components/wpa_supplicant/src/wps/wps_validate.c
Normal file
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue