cpu/esp32/esp_wifi: wpa_supplicant files for WPA2 Enterprise mode
Add all files of wpa_supplicant from ESP32 SDK that are required for WPA2 Enterprise mode.
This commit is contained in:
parent
202758f400
commit
3d1a895c5b
337
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/common.h
vendored
Normal file
337
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/common.h
vendored
Normal file
@ -0,0 +1,337 @@
|
|||||||
|
/*
|
||||||
|
* wpa_supplicant/hostapd / common helper functions, etc.
|
||||||
|
* Copyright (c) 2002-2007, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#if defined(__ets__)
|
||||||
|
#endif /* ets */
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
/* Define platform specific variable type macros */
|
||||||
|
#if defined(ESP_PLATFORM)
|
||||||
|
#include <stdint.h>
|
||||||
|
typedef uint64_t u64;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef int64_t s64;
|
||||||
|
typedef int32_t s32;
|
||||||
|
typedef int16_t s16;
|
||||||
|
typedef int8_t s8;
|
||||||
|
#endif /*ESP_PLATFORM*/
|
||||||
|
|
||||||
|
#if defined(__XTENSA__)
|
||||||
|
#include <machine/endian.h>
|
||||||
|
#define __BYTE_ORDER BYTE_ORDER
|
||||||
|
#define __LITTLE_ENDIAN LITTLE_ENDIAN
|
||||||
|
#define __BIG_ENDIAN BIG_ENDIAN
|
||||||
|
#endif /*__XTENSA__*/
|
||||||
|
|
||||||
|
#if defined(__linux__) || defined(__GLIBC__) || defined(__ets__)
|
||||||
|
#include <endian.h>
|
||||||
|
#include <byteswap.h>
|
||||||
|
#endif /* __linux__ */
|
||||||
|
|
||||||
|
/* Define platform specific byte swapping macros */
|
||||||
|
|
||||||
|
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
|
||||||
|
|
||||||
|
static inline unsigned short wpa_swap_16(unsigned short v)
|
||||||
|
{
|
||||||
|
return ((v & 0xff) << 8) | (v >> 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned int wpa_swap_32(unsigned int v)
|
||||||
|
{
|
||||||
|
return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
|
||||||
|
((v & 0xff0000) >> 8) | (v >> 24);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define le_to_host16(n) (n)
|
||||||
|
#define host_to_le16(n) (n)
|
||||||
|
#define be_to_host16(n) wpa_swap_16(n)
|
||||||
|
#define host_to_be16(n) wpa_swap_16(n)
|
||||||
|
#define le_to_host32(n) (n)
|
||||||
|
#define be_to_host32(n) wpa_swap_32(n)
|
||||||
|
#define host_to_be32(n) wpa_swap_32(n)
|
||||||
|
|
||||||
|
#define WPA_BYTE_SWAP_DEFINED
|
||||||
|
|
||||||
|
#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef WPA_BYTE_SWAP_DEFINED
|
||||||
|
|
||||||
|
#ifndef __BYTE_ORDER
|
||||||
|
#ifndef __LITTLE_ENDIAN
|
||||||
|
#ifndef __BIG_ENDIAN
|
||||||
|
#define __LITTLE_ENDIAN 1234
|
||||||
|
#define __BIG_ENDIAN 4321
|
||||||
|
#if defined(sparc)
|
||||||
|
#define __BYTE_ORDER __BIG_ENDIAN
|
||||||
|
#endif
|
||||||
|
#endif /* __BIG_ENDIAN */
|
||||||
|
#endif /* __LITTLE_ENDIAN */
|
||||||
|
#endif /* __BYTE_ORDER */
|
||||||
|
|
||||||
|
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||||
|
#define le_to_host16(n) ((__force u16) (le16) (n))
|
||||||
|
#define host_to_le16(n) ((__force le16) (u16) (n))
|
||||||
|
#define be_to_host16(n) __bswap_16((__force u16) (be16) (n))
|
||||||
|
#define host_to_be16(n) ((__force be16) __bswap_16((n)))
|
||||||
|
#define le_to_host32(n) ((__force u32) (le32) (n))
|
||||||
|
#define host_to_le32(n) ((__force le32) (u32) (n))
|
||||||
|
#define be_to_host32(n) __bswap_32((__force u32) (be32) (n))
|
||||||
|
#define host_to_be32(n) ((__force be32) __bswap_32((n)))
|
||||||
|
#define le_to_host64(n) ((__force u64) (le64) (n))
|
||||||
|
#define host_to_le64(n) ((__force le64) (u64) (n))
|
||||||
|
#define be_to_host64(n) __bswap_64((__force u64) (be64) (n))
|
||||||
|
#define host_to_be64(n) ((__force be64) bswap_64((n)))
|
||||||
|
#elif __BYTE_ORDER == __BIG_ENDIAN
|
||||||
|
#define le_to_host16(n) __bswap_16(n)
|
||||||
|
#define host_to_le16(n) __bswap_16(n)
|
||||||
|
#define be_to_host16(n) (n)
|
||||||
|
#define host_to_be16(n) (n)
|
||||||
|
#define le_to_host32(n) __bswap_32(n)
|
||||||
|
#define be_to_host32(n) (n)
|
||||||
|
#define host_to_be32(n) (n)
|
||||||
|
#define le_to_host64(n) __bswap_64(n)
|
||||||
|
#define host_to_le64(n) __bswap_64(n)
|
||||||
|
#define be_to_host64(n) (n)
|
||||||
|
#define host_to_be64(n) (n)
|
||||||
|
#ifndef WORDS_BIGENDIAN
|
||||||
|
#define WORDS_BIGENDIAN
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
#error Could not determine CPU byte order
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WPA_BYTE_SWAP_DEFINED
|
||||||
|
#endif /* !WPA_BYTE_SWAP_DEFINED */
|
||||||
|
|
||||||
|
|
||||||
|
/* Macros for handling unaligned memory accesses */
|
||||||
|
|
||||||
|
#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
|
||||||
|
#define WPA_PUT_BE16(a, val) \
|
||||||
|
do { \
|
||||||
|
(a)[0] = ((u16) (val)) >> 8; \
|
||||||
|
(a)[1] = ((u16) (val)) & 0xff; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
|
||||||
|
#define WPA_PUT_LE16(a, val) \
|
||||||
|
do { \
|
||||||
|
(a)[1] = ((u16) (val)) >> 8; \
|
||||||
|
(a)[0] = ((u16) (val)) & 0xff; \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
|
||||||
|
((u32) (a)[2]))
|
||||||
|
#define WPA_PUT_BE24(a, val) \
|
||||||
|
do { \
|
||||||
|
(a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff); \
|
||||||
|
(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
|
||||||
|
(a)[2] = (u8) (((u32) (val)) & 0xff); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
|
||||||
|
(((u32) (a)[2]) << 8) | ((u32) (a)[3]))
|
||||||
|
#define WPA_PUT_BE32(a, val) \
|
||||||
|
do { \
|
||||||
|
(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff); \
|
||||||
|
(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff); \
|
||||||
|
(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff); \
|
||||||
|
(a)[3] = (u8) (((u32) (val)) & 0xff); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
|
||||||
|
(((u32) (a)[1]) << 8) | ((u32) (a)[0]))
|
||||||
|
#define WPA_PUT_LE32(a, val) \
|
||||||
|
do { \
|
||||||
|
(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff); \
|
||||||
|
(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff); \
|
||||||
|
(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff); \
|
||||||
|
(a)[0] = (u8) (((u32) (val)) & 0xff); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
|
||||||
|
(((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
|
||||||
|
(((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
|
||||||
|
(((u64) (a)[6]) << 8) | ((u64) (a)[7]))
|
||||||
|
#define WPA_PUT_BE64(a, val) \
|
||||||
|
do { \
|
||||||
|
(a)[0] = (u8) (((u64) (val)) >> 56); \
|
||||||
|
(a)[1] = (u8) (((u64) (val)) >> 48); \
|
||||||
|
(a)[2] = (u8) (((u64) (val)) >> 40); \
|
||||||
|
(a)[3] = (u8) (((u64) (val)) >> 32); \
|
||||||
|
(a)[4] = (u8) (((u64) (val)) >> 24); \
|
||||||
|
(a)[5] = (u8) (((u64) (val)) >> 16); \
|
||||||
|
(a)[6] = (u8) (((u64) (val)) >> 8); \
|
||||||
|
(a)[7] = (u8) (((u64) (val)) & 0xff); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
|
||||||
|
(((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
|
||||||
|
(((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
|
||||||
|
(((u64) (a)[1]) << 8) | ((u64) (a)[0]))
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef ETH_ALEN
|
||||||
|
#define ETH_ALEN 6
|
||||||
|
#endif
|
||||||
|
//#ifndef IFNAMSIZ
|
||||||
|
//#define IFNAMSIZ 16
|
||||||
|
//#endif
|
||||||
|
#ifndef ETH_P_ALL
|
||||||
|
#define ETH_P_ALL 0x0003
|
||||||
|
#endif
|
||||||
|
#ifndef ETH_P_PAE
|
||||||
|
#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
|
||||||
|
#endif /* ETH_P_PAE */
|
||||||
|
#ifndef ETH_P_EAPOL
|
||||||
|
#define ETH_P_EAPOL ETH_P_PAE
|
||||||
|
#endif /* ETH_P_EAPOL */
|
||||||
|
#ifndef ETH_P_RSN_PREAUTH
|
||||||
|
#define ETH_P_RSN_PREAUTH 0x88c7
|
||||||
|
#endif /* ETH_P_RSN_PREAUTH */
|
||||||
|
#ifndef ETH_P_RRB
|
||||||
|
#define ETH_P_RRB 0x890D
|
||||||
|
#endif /* ETH_P_RRB */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
|
||||||
|
#define STRUCT_PACKED __attribute__ ((packed))
|
||||||
|
#else
|
||||||
|
#define PRINTF_FORMAT(a,b)
|
||||||
|
#define STRUCT_PACKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef CONFIG_ANSI_C_EXTRA
|
||||||
|
|
||||||
|
/* inline - define as __inline or just define it to be empty, if needed */
|
||||||
|
#ifdef CONFIG_NO_INLINE
|
||||||
|
#define inline
|
||||||
|
#else
|
||||||
|
#define inline __inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef __func__
|
||||||
|
#define __func__ "__func__ not defined"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef bswap_16
|
||||||
|
#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef bswap_32
|
||||||
|
#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
|
||||||
|
(((u32) (a) << 8) & 0xff0000) | \
|
||||||
|
(((u32) (a) >> 8) & 0xff00) | \
|
||||||
|
(((u32) (a) >> 24) & 0xff))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef MSG_DONTWAIT
|
||||||
|
#define MSG_DONTWAIT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _WIN32_WCE
|
||||||
|
void perror(const char *s);
|
||||||
|
#endif /* _WIN32_WCE */
|
||||||
|
|
||||||
|
#endif /* CONFIG_ANSI_C_EXTRA */
|
||||||
|
|
||||||
|
#ifndef MAC2STR
|
||||||
|
#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
|
||||||
|
#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef BIT
|
||||||
|
#define BIT(x) (1 << (x))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Definitions for sparse validation
|
||||||
|
* (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
|
||||||
|
*/
|
||||||
|
#ifdef __CHECKER__
|
||||||
|
#define __force __attribute__((force))
|
||||||
|
#define __bitwise __attribute__((bitwise))
|
||||||
|
#else
|
||||||
|
#define __force
|
||||||
|
#define __bitwise
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef u16 __bitwise be16;
|
||||||
|
typedef u16 __bitwise le16;
|
||||||
|
typedef u32 __bitwise be32;
|
||||||
|
typedef u32 __bitwise le32;
|
||||||
|
typedef u64 __bitwise be64;
|
||||||
|
typedef u64 __bitwise le64;
|
||||||
|
|
||||||
|
#ifndef __must_check
|
||||||
|
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
|
||||||
|
#define __must_check __attribute__((__warn_unused_result__))
|
||||||
|
#else
|
||||||
|
#define __must_check
|
||||||
|
#endif /* __GNUC__ */
|
||||||
|
#endif /* __must_check */
|
||||||
|
|
||||||
|
int hwaddr_aton(const char *txt, u8 *addr);
|
||||||
|
int hwaddr_aton2(const char *txt, u8 *addr);
|
||||||
|
int hexstr2bin(const char *hex, u8 *buf, size_t len);
|
||||||
|
void inc_byte_array(u8 *counter, size_t len);
|
||||||
|
void wpa_get_ntp_timestamp(u8 *buf);
|
||||||
|
int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
|
||||||
|
int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
#ifdef CONFIG_NATIVE_WINDOWS
|
||||||
|
void wpa_unicode2ascii_inplace(TCHAR *str);
|
||||||
|
TCHAR * wpa_strdup_tchar(const char *str);
|
||||||
|
#else /* CONFIG_NATIVE_WINDOWS */
|
||||||
|
#define wpa_unicode2ascii_inplace(s) do { } while (0)
|
||||||
|
#define wpa_strdup_tchar(s) strdup((s))
|
||||||
|
#endif /* CONFIG_NATIVE_WINDOWS */
|
||||||
|
|
||||||
|
const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
|
||||||
|
char * wpa_config_parse_string(const char *value, size_t *len);
|
||||||
|
|
||||||
|
static inline int is_zero_ether_addr(const u8 *a)
|
||||||
|
{
|
||||||
|
return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern const struct eth_addr ethbroadcast;
|
||||||
|
#define broadcast_ether_addr ðbroadcast
|
||||||
|
|
||||||
|
#include "wpabuf.h"
|
||||||
|
#include "wpa_debug.h"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gcc 4.4 ends up generating strict-aliasing warnings about some very common
|
||||||
|
* networking socket uses that do not really result in a real problem and
|
||||||
|
* cannot be easily avoided with union-based type-punning due to struct
|
||||||
|
* definitions including another struct in system header files. To avoid having
|
||||||
|
* to fully disable strict-aliasing warnings, provide a mechanism to hide the
|
||||||
|
* typecast from aliasing for now. A cleaner solution will hopefully be found
|
||||||
|
* in the future to handle these cases.
|
||||||
|
*/
|
||||||
|
void * __hide_aliasing_typecast(void *foo);
|
||||||
|
#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
|
||||||
|
|
||||||
|
#endif /* COMMON_H */
|
||||||
186
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/wpa.h
vendored
Normal file
186
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/wpa.h
vendored
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
* wpa_supplicant - WPA definitions
|
||||||
|
* Copyright (c) 2003-2007, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WPA_H
|
||||||
|
#define WPA_H
|
||||||
|
|
||||||
|
#include "rom/ets_sys.h"
|
||||||
|
#include "wpa/common.h"
|
||||||
|
#include "wpa/defs.h"
|
||||||
|
#include "wpa/wpa_common.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define WPA_SM_STATE(_sm) ((_sm)->wpa_state)
|
||||||
|
|
||||||
|
struct wpa_sm;
|
||||||
|
|
||||||
|
int wpa_sm_rx_eapol(u8 *src_addr, u8 *buf, u32 len);
|
||||||
|
|
||||||
|
#define WPA_ASSERT ASSERT
|
||||||
|
|
||||||
|
struct install_key {
|
||||||
|
int mic_errors_seen; /* Michael MIC errors with the current PTK */
|
||||||
|
int keys_cleared;
|
||||||
|
enum wpa_alg alg;
|
||||||
|
u8 addr[ETH_ALEN];
|
||||||
|
int key_idx;
|
||||||
|
int set_tx;
|
||||||
|
u8 seq[10];
|
||||||
|
u8 key[32];
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct wpa_sm - Internal WPA state machine data
|
||||||
|
*/
|
||||||
|
struct wpa_sm {
|
||||||
|
u8 pmk[PMK_LEN];
|
||||||
|
size_t pmk_len;
|
||||||
|
|
||||||
|
struct wpa_ptk ptk, tptk;
|
||||||
|
int ptk_set, tptk_set;
|
||||||
|
u8 snonce[WPA_NONCE_LEN];
|
||||||
|
u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
|
||||||
|
int renew_snonce;
|
||||||
|
u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
|
||||||
|
int rx_replay_counter_set;
|
||||||
|
u8 request_counter[WPA_REPLAY_COUNTER_LEN];
|
||||||
|
|
||||||
|
unsigned int pairwise_cipher;
|
||||||
|
unsigned int group_cipher;
|
||||||
|
unsigned int key_mgmt;
|
||||||
|
unsigned int mgmt_group_cipher;
|
||||||
|
|
||||||
|
int rsn_enabled; /* Whether RSN is enabled in configuration */
|
||||||
|
|
||||||
|
int countermeasures; /*TKIP countermeasures state flag, 1:in countermeasures state*/
|
||||||
|
ETSTimer cm_timer;
|
||||||
|
|
||||||
|
u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
|
||||||
|
size_t assoc_wpa_ie_len;
|
||||||
|
|
||||||
|
u8 eapol_version;
|
||||||
|
|
||||||
|
int wpa_ptk_rekey;
|
||||||
|
u8 own_addr[ETH_ALEN];
|
||||||
|
|
||||||
|
u8 bssid[ETH_ALEN];
|
||||||
|
|
||||||
|
unsigned int proto;
|
||||||
|
enum wpa_states wpa_state;
|
||||||
|
|
||||||
|
u8 *ap_wpa_ie, *ap_rsn_ie;
|
||||||
|
size_t ap_wpa_ie_len, ap_rsn_ie_len;
|
||||||
|
|
||||||
|
struct install_key install_ptk;
|
||||||
|
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)
|
||||||
|
|
||||||
|
struct pbuf *pb;
|
||||||
|
|
||||||
|
void (* sendto) (struct pbuf *pb);
|
||||||
|
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)(void);
|
||||||
|
struct wpa_gtk_data gd; //used for calllback save param
|
||||||
|
u16 key_info; //used for txcallback param
|
||||||
|
};
|
||||||
|
|
||||||
|
struct l2_ethhdr {
|
||||||
|
u8 h_dest[ETH_ALEN];
|
||||||
|
u8 h_source[ETH_ALEN];
|
||||||
|
be16 h_proto;
|
||||||
|
} STRUCT_PACKED;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* set_key - Configure encryption key
|
||||||
|
* @ifname: Interface name (for multi-SSID/VLAN support)
|
||||||
|
* @priv: private driver interface data
|
||||||
|
* @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
|
||||||
|
* %WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK);
|
||||||
|
* %WPA_ALG_NONE clears the key.
|
||||||
|
* @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
|
||||||
|
* broadcast/default keys
|
||||||
|
* @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
|
||||||
|
* IGTK
|
||||||
|
* @set_tx: configure this key as the default Tx key (only used when
|
||||||
|
* driver does not support separate unicast/individual key
|
||||||
|
* @seq: sequence number/packet number, seq_len octets, the next
|
||||||
|
* packet number to be used for in replay protection; configured
|
||||||
|
* for Rx keys (in most cases, this is only used with broadcast
|
||||||
|
* keys and set to zero for unicast keys)
|
||||||
|
* @seq_len: length of the seq, depends on the algorithm:
|
||||||
|
* TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
|
||||||
|
* @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
|
||||||
|
* 8-byte Rx Mic Key
|
||||||
|
* @key_len: length of the key buffer in octets (WEP: 5 or 13,
|
||||||
|
* TKIP: 32, CCMP: 16, IGTK: 16)
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on failure
|
||||||
|
*
|
||||||
|
* Configure the given key for the kernel driver. If the driver
|
||||||
|
* supports separate individual keys (4 default keys + 1 individual),
|
||||||
|
* addr can be used to determine whether the key is default or
|
||||||
|
* individual. If only 4 keys are supported, the default key with key
|
||||||
|
* index 0 is used as the individual key. STA must be configured to use
|
||||||
|
* it as the default Tx key (set_tx is set) and accept Rx for all the
|
||||||
|
* key indexes. In most cases, WPA uses only key indexes 1 and 2 for
|
||||||
|
* broadcast keys, so key index 0 is available for this kind of
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* Please note that TKIP keys include separate TX and RX MIC keys and
|
||||||
|
* some drivers may expect them in different order than wpa_supplicant
|
||||||
|
* is using. If the TX/RX keys are swapped, all TKIP encrypted packets
|
||||||
|
* will tricker Michael MIC errors. This can be fixed by changing the
|
||||||
|
* order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
|
||||||
|
* in driver_*.c set_key() implementation, see driver_ndis.c for an
|
||||||
|
* example on how this can be done.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* send_eapol - Optional function for sending EAPOL packets
|
||||||
|
* @priv: private driver interface data
|
||||||
|
* @dest: Destination MAC address
|
||||||
|
* @proto: Ethertype
|
||||||
|
* @data: EAPOL packet starting with IEEE 802.1X header
|
||||||
|
* @data_len: Size of the EAPOL packet
|
||||||
|
*
|
||||||
|
* Returns: 0 on success, -1 on failure
|
||||||
|
*
|
||||||
|
* This optional function can be used to override l2_packet operations
|
||||||
|
* with driver specific functionality. If this function pointer is set,
|
||||||
|
* l2_packet module is not used at all and the driver interface code is
|
||||||
|
* responsible for receiving and sending all EAPOL packets. The
|
||||||
|
* received EAPOL packets are sent to core code with EVENT_EAPOL_RX
|
||||||
|
* event. The driver interface is required to implement get_mac_addr()
|
||||||
|
* handler if send_eapol() is used.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define KEYENTRY_TABLE_MAP(key_entry_valid) ((key_entry_valid)%5)
|
||||||
|
|
||||||
|
void wpa_sm_set_state(enum wpa_states state);
|
||||||
|
|
||||||
|
char * dup_binstr(const void *src, size_t len);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WPA_H */
|
||||||
|
|
||||||
219
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/wpa_debug.h
vendored
Normal file
219
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/wpa_debug.h
vendored
Normal file
@ -0,0 +1,219 @@
|
|||||||
|
/*
|
||||||
|
* wpa_supplicant/hostapd / Debug prints
|
||||||
|
* Copyright (c) 2002-2007, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WPA_DEBUG_H
|
||||||
|
#define WPA_DEBUG_H
|
||||||
|
|
||||||
|
#include "wpabuf.h"
|
||||||
|
#include "esp_log.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#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 "
|
||||||
|
|
||||||
|
int wpa_debug_open_file(const char *path);
|
||||||
|
void wpa_debug_close_file(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_debug_printf_timestamp - Print timestamp for debug output
|
||||||
|
*
|
||||||
|
* This function prints a timestamp in seconds_from_1970.microsoconds
|
||||||
|
* format if debug output has been configured to include timestamps in debug
|
||||||
|
* messages.
|
||||||
|
*/
|
||||||
|
void wpa_debug_print_timestamp(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_printf - conditional printf
|
||||||
|
* @level: priority level (MSG_*) of the message
|
||||||
|
* @fmt: printf format string, followed by optional arguments
|
||||||
|
*
|
||||||
|
* This function is used to print conditional debugging and error messages. The
|
||||||
|
* output may be directed to stdout, stderr, and/or syslog based on
|
||||||
|
* configuration.
|
||||||
|
*
|
||||||
|
* Note: New line '\n' is added to the end of the text when printing to stdout.
|
||||||
|
*/
|
||||||
|
#define DEBUG_PRINT
|
||||||
|
#define MSG_PRINT
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_hexdump - conditional hex dump
|
||||||
|
* @level: priority level (MSG_*) of the message
|
||||||
|
* @title: title of for the message
|
||||||
|
* @buf: data buffer to be dumped
|
||||||
|
* @len: length of the buf
|
||||||
|
*
|
||||||
|
* This function is used to print conditional debugging and error messages. The
|
||||||
|
* output may be directed to stdout, stderr, and/or syslog based on
|
||||||
|
* configuration. The contents of buf is printed out has hex dump.
|
||||||
|
*/
|
||||||
|
#ifdef DEBUG_PRINT
|
||||||
|
#ifdef RIOT_VERSION
|
||||||
|
#define wpa_printf(level,fmt, args...) ESP_LOG_LEVEL_LOCAL(level, TAG, fmt "\n", ##args)
|
||||||
|
#else
|
||||||
|
#define wpa_printf(level,fmt, args...) ESP_LOG_LEVEL_LOCAL(level, TAG, fmt, ##args)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf, size_t len)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
|
||||||
|
|
||||||
|
static inline void wpa_hexdump_buf(int level, const char *title,
|
||||||
|
const struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
wpa_hexdump(level, title, wpabuf_head(buf), wpabuf_len(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_hexdump_key - conditional hex dump, hide keys
|
||||||
|
* @level: priority level (MSG_*) of the message
|
||||||
|
* @title: title of for the message
|
||||||
|
* @buf: data buffer to be dumped
|
||||||
|
* @len: length of the buf
|
||||||
|
*
|
||||||
|
* This function is used to print conditional debugging and error messages. The
|
||||||
|
* output may be directed to stdout, stderr, and/or syslog based on
|
||||||
|
* configuration. The contents of buf is printed out has hex dump. This works
|
||||||
|
* like wpa_hexdump(), but by default, does not include secret keys (passwords,
|
||||||
|
* etc.) in debug output.
|
||||||
|
*/
|
||||||
|
void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
|
||||||
|
|
||||||
|
|
||||||
|
static inline void wpa_hexdump_buf_key(int level, const char *title,
|
||||||
|
const struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
wpa_hexdump_key(level, title, wpabuf_head(buf), wpabuf_len(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_hexdump_ascii - conditional hex dump
|
||||||
|
* @level: priority level (MSG_*) of the message
|
||||||
|
* @title: title of for the message
|
||||||
|
* @buf: data buffer to be dumped
|
||||||
|
* @len: length of the buf
|
||||||
|
*
|
||||||
|
* This function is used to print conditional debugging and error messages. The
|
||||||
|
* output may be directed to stdout, stderr, and/or syslog based on
|
||||||
|
* configuration. The contents of buf is printed out has hex dump with both
|
||||||
|
* the hex numbers and ASCII characters (for printable range) are shown. 16
|
||||||
|
* bytes per line will be shown.
|
||||||
|
*/
|
||||||
|
void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_hexdump_ascii_key - conditional hex dump, hide keys
|
||||||
|
* @level: priority level (MSG_*) of the message
|
||||||
|
* @title: title of for the message
|
||||||
|
* @buf: data buffer to be dumped
|
||||||
|
* @len: length of the buf
|
||||||
|
*
|
||||||
|
* This function is used to print conditional debugging and error messages. The
|
||||||
|
* output may be directed to stdout, stderr, and/or syslog based on
|
||||||
|
* configuration. The contents of buf is printed out has hex dump with both
|
||||||
|
* the hex numbers and ASCII characters (for printable range) are shown. 16
|
||||||
|
* bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
|
||||||
|
* default, does not include secret keys (passwords, etc.) in debug output.
|
||||||
|
*/
|
||||||
|
void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
|
||||||
|
size_t len);
|
||||||
|
#else
|
||||||
|
#define wpa_printf(level,fmt, args...)
|
||||||
|
#define wpa_hexdump(...)
|
||||||
|
#define wpa_hexdump_buf(...)
|
||||||
|
#define wpa_hexdump_key(...)
|
||||||
|
#define wpa_hexdump_buf_key(...)
|
||||||
|
#define wpa_hexdump_ascii(...)
|
||||||
|
#define wpa_hexdump_ascii_key(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define wpa_auth_logger
|
||||||
|
#define wpa_auth_vlogger
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_msg - Conditional printf for default target and ctrl_iface monitors
|
||||||
|
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||||
|
* with struct wpa_driver_ops::init()
|
||||||
|
* @level: priority level (MSG_*) of the message
|
||||||
|
* @fmt: printf format string, followed by optional arguments
|
||||||
|
*
|
||||||
|
* This function is used to print conditional debugging and error messages. The
|
||||||
|
* output may be directed to stdout, stderr, and/or syslog based on
|
||||||
|
* configuration. This function is like wpa_printf(), but it also sends the
|
||||||
|
* same message to all attached ctrl_iface monitors.
|
||||||
|
*
|
||||||
|
* Note: New line '\n' is added to the end of the text when printing to stdout.
|
||||||
|
*/
|
||||||
|
void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
|
||||||
|
* @ctx: Pointer to context data; this is the ctx variable registered
|
||||||
|
* with struct wpa_driver_ops::init()
|
||||||
|
* @level: priority level (MSG_*) of the message
|
||||||
|
* @fmt: printf format string, followed by optional arguments
|
||||||
|
*
|
||||||
|
* This function is used to print conditional debugging and error messages.
|
||||||
|
* This function is like wpa_msg(), but it sends the output only to the
|
||||||
|
* attached ctrl_iface monitors. In other words, it can be used for frequent
|
||||||
|
* events that do not need to be sent to syslog.
|
||||||
|
*/
|
||||||
|
void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
|
||||||
|
PRINTF_FORMAT(3, 4);
|
||||||
|
|
||||||
|
typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
|
||||||
|
size_t len);
|
||||||
|
|
||||||
|
typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
|
||||||
|
|
||||||
|
int eloop_cancel_timeout(eloop_timeout_handler handler,
|
||||||
|
void *eloop_data, void *user_data);
|
||||||
|
|
||||||
|
int eloop_register_timeout(unsigned int secs, unsigned int usecs,
|
||||||
|
eloop_timeout_handler handler,
|
||||||
|
void *eloop_data, void *user_data);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WPA_DEBUG_H */
|
||||||
176
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/wpabuf.h
vendored
Normal file
176
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa/wpabuf.h
vendored
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* Dynamic data buffer
|
||||||
|
* Copyright (c) 2007-2009, 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WPABUF_H
|
||||||
|
#define WPABUF_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Internal data structure for wpabuf. Please do not touch this directly from
|
||||||
|
* elsewhere. This is only defined in header file to allow inline functions
|
||||||
|
* from this file to access data.
|
||||||
|
*/
|
||||||
|
struct wpabuf {
|
||||||
|
size_t size; /* total size of the allocated buffer */
|
||||||
|
size_t used; /* length of data in the buffer */
|
||||||
|
u8 *ext_data; /* pointer to external data; NULL if data follows
|
||||||
|
* struct wpabuf */
|
||||||
|
/* optionally followed by the allocated buffer */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
int wpabuf_resize(struct wpabuf **buf, size_t add_len);
|
||||||
|
struct wpabuf * wpabuf_alloc(size_t len);
|
||||||
|
struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
|
||||||
|
struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
|
||||||
|
struct wpabuf * wpabuf_dup(const struct wpabuf *src);
|
||||||
|
void wpabuf_free(struct wpabuf *buf);
|
||||||
|
void * wpabuf_put(struct wpabuf *buf, size_t len);
|
||||||
|
struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
|
||||||
|
struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
|
||||||
|
void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpabuf_size - Get the currently allocated size of a wpabuf buffer
|
||||||
|
* @buf: wpabuf buffer
|
||||||
|
* Returns: Currently allocated size of the buffer
|
||||||
|
*/
|
||||||
|
static inline size_t wpabuf_size(const struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
return buf->size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpabuf_len - Get the current length of a wpabuf buffer data
|
||||||
|
* @buf: wpabuf buffer
|
||||||
|
* Returns: Currently used length of the buffer
|
||||||
|
*/
|
||||||
|
static inline size_t wpabuf_len(const struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
return buf->used;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpabuf_tailroom - Get size of available tail room in the end of the buffer
|
||||||
|
* @buf: wpabuf buffer
|
||||||
|
* Returns: Tail room (in bytes) of available space in the end of the buffer
|
||||||
|
*/
|
||||||
|
static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
return buf->size - buf->used;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpabuf_head - Get pointer to the head of the buffer data
|
||||||
|
* @buf: wpabuf buffer
|
||||||
|
* Returns: Pointer to the head of the buffer data
|
||||||
|
*/
|
||||||
|
static inline const void * wpabuf_head(const struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
if (buf->ext_data)
|
||||||
|
return buf->ext_data;
|
||||||
|
return buf + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
return wpabuf_head(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* wpabuf_mhead - Get modifiable pointer to the head of the buffer data
|
||||||
|
* @buf: wpabuf buffer
|
||||||
|
* Returns: Pointer to the head of the buffer data
|
||||||
|
*/
|
||||||
|
static inline void * wpabuf_mhead(struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
if (buf->ext_data)
|
||||||
|
return buf->ext_data;
|
||||||
|
return buf + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
|
||||||
|
{
|
||||||
|
return wpabuf_mhead(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
|
||||||
|
{
|
||||||
|
u8 *pos = wpabuf_put(buf, 1);
|
||||||
|
*pos = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
|
||||||
|
{
|
||||||
|
u8 *pos = wpabuf_put(buf, 2);
|
||||||
|
WPA_PUT_LE16(pos, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
|
||||||
|
{
|
||||||
|
u8 *pos = wpabuf_put(buf, 4);
|
||||||
|
WPA_PUT_LE32(pos, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
|
||||||
|
{
|
||||||
|
u8 *pos = wpabuf_put(buf, 2);
|
||||||
|
WPA_PUT_BE16(pos, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
|
||||||
|
{
|
||||||
|
u8 *pos = wpabuf_put(buf, 3);
|
||||||
|
WPA_PUT_BE24(pos, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
|
||||||
|
{
|
||||||
|
u8 *pos = wpabuf_put(buf, 4);
|
||||||
|
WPA_PUT_BE32(pos, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,
|
||||||
|
size_t len)
|
||||||
|
{
|
||||||
|
if (data)
|
||||||
|
os_memcpy(wpabuf_put(buf, len), data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_buf(struct wpabuf *dst,
|
||||||
|
const struct wpabuf *src)
|
||||||
|
{
|
||||||
|
wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
buf->ext_data = (u8 *) data;
|
||||||
|
buf->size = buf->used = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)
|
||||||
|
{
|
||||||
|
wpabuf_put_data(dst, str, os_strlen(str));
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* WPABUF_H */
|
||||||
62
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa2/eap_peer/eap.h
vendored
Normal file
62
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa2/eap_peer/eap.h
vendored
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* EAP peer state machine functions (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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef EAP_H
|
||||||
|
#define EAP_H
|
||||||
|
|
||||||
|
#include "wpa/defs.h"
|
||||||
|
#include "wpa2/eap_peer/eap_defs.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct eap_sm;
|
||||||
|
|
||||||
|
struct eap_method_type {
|
||||||
|
int vendor;
|
||||||
|
EapType method;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern u8 *g_wpa_anonymous_identity;
|
||||||
|
extern int g_wpa_anonymous_identity_len;
|
||||||
|
extern u8 *g_wpa_username;
|
||||||
|
extern int g_wpa_username_len;
|
||||||
|
extern const u8 *g_wpa_client_cert;
|
||||||
|
extern int g_wpa_client_cert_len;
|
||||||
|
extern const u8 *g_wpa_private_key;
|
||||||
|
extern int g_wpa_private_key_len;
|
||||||
|
extern const u8 *g_wpa_private_key_passwd;
|
||||||
|
extern int g_wpa_private_key_passwd_len;
|
||||||
|
|
||||||
|
extern const u8 *g_wpa_ca_cert;
|
||||||
|
extern int g_wpa_ca_cert_len;
|
||||||
|
|
||||||
|
extern u8 *g_wpa_password;
|
||||||
|
extern int g_wpa_password_len;
|
||||||
|
|
||||||
|
extern u8 *g_wpa_new_password;
|
||||||
|
extern 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);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* EAP_H */
|
||||||
151
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa2/eap_peer/eap_i.h
vendored
Normal file
151
cpu/esp32/vendor/esp-idf/wpa_supplicant/include/wpa2/eap_peer/eap_i.h
vendored
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
/*
|
||||||
|
* EAP peer state machines internal structures (RFC 4137)
|
||||||
|
* 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_I_H
|
||||||
|
#define EAP_I_H
|
||||||
|
|
||||||
|
#include "wpa/wpabuf.h"
|
||||||
|
#include "wpa2/eap_peer/eap.h"
|
||||||
|
#include "wpa2/eap_peer/eap_common.h"
|
||||||
|
#include "wpa2/eap_peer/eap_config.h"
|
||||||
|
#include "esp_wpa2.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* RFC 4137 - EAP Peer state machine */
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC
|
||||||
|
} EapDecision;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE
|
||||||
|
} EapMethodState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eap_method_ret - EAP return values from struct eap_method::process()
|
||||||
|
*
|
||||||
|
* These structure contains OUT variables for the interface between peer state
|
||||||
|
* machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as
|
||||||
|
* the return value of struct eap_method::process() so it is not included in
|
||||||
|
* this structure.
|
||||||
|
*/
|
||||||
|
struct eap_method_ret {
|
||||||
|
/**
|
||||||
|
* ignore - Whether method decided to drop the current packed (OUT)
|
||||||
|
*/
|
||||||
|
Boolean ignore;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* methodState - Method-specific state (IN/OUT)
|
||||||
|
*/
|
||||||
|
EapMethodState methodState;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* decision - Authentication decision (OUT)
|
||||||
|
*/
|
||||||
|
EapDecision decision;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* allowNotifications - Whether method allows notifications (OUT)
|
||||||
|
*/
|
||||||
|
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 3
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct eap_sm - EAP state machine data
|
||||||
|
*/
|
||||||
|
struct eap_sm {
|
||||||
|
void *eap_method_priv;
|
||||||
|
|
||||||
|
void *ssl_ctx;
|
||||||
|
|
||||||
|
unsigned int workaround;
|
||||||
|
/////////////////////////////////////////////////
|
||||||
|
struct pbuf *outbuf;
|
||||||
|
struct wpa_config_blob blob[BLOB_NUM];
|
||||||
|
struct eap_peer_config config;
|
||||||
|
u8 current_identifier;
|
||||||
|
u8 ownaddr[ETH_ALEN];
|
||||||
|
#ifdef USE_WPA2_TASK
|
||||||
|
#define SIG_WPA2_NUM 2
|
||||||
|
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;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern 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);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* EAP_I_H */
|
||||||
27
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/chap.c
vendored
Normal file
27
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/chap.c
vendored
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 wpa_md5_vector(3, addr, len, response);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* CHAP_MD5 */
|
||||||
731
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap.c
vendored
Normal file
731
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap.c
vendored
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, m->method);
|
||||||
|
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_common.c
vendored
Normal file
205
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_common.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_mschapv2.c
vendored
Normal file
671
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_mschapv2.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_peap.c
vendored
Normal file
1357
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_peap.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
90
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_peap_common.c
vendored
Normal file
90
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_peap_common.c
vendored
Normal file
@ -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 (wpa_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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_tls.c
vendored
Normal file
232
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_tls.c
vendored
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 */
|
||||||
1064
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_tls_common.c
vendored
Normal file
1064
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_tls_common.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
1673
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c
vendored
Normal file
1673
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/eap_ttls.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
97
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c
vendored
Normal file
97
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/eap_peer/mschapv2.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/asn1.c
vendored
Normal file
207
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/asn1.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/bignum.c
vendored
Normal file
244
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/bignum.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/pkcs1.c
vendored
Normal file
195
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/pkcs1.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/pkcs5.c
vendored
Normal file
262
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/pkcs5.c
vendored
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 (wpa_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 (wpa_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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/pkcs8.c
vendored
Normal file
186
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/pkcs8.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/rsa.c
vendored
Normal file
353
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/rsa.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tls_internal.c
vendored
Normal file
716
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tls_internal.c
vendored
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--;
|
||||||
|
}
|
||||||
|
|
||||||
|
wpa_hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
|
||||||
|
wpa_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) {
|
||||||
|
wpa_hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
|
||||||
|
MD5_pos = 0;
|
||||||
|
wpa_hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
|
||||||
|
}
|
||||||
|
if (SHA1_pos == SHA1_MAC_LEN) {
|
||||||
|
wpa_hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
|
||||||
|
P_SHA1);
|
||||||
|
SHA1_pos = 0;
|
||||||
|
wpa_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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_client.c
vendored
Normal file
837
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_client.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_client_read.c
vendored
Normal file
1001
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_client_read.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
901
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_client_write.c
vendored
Normal file
901
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_client_write.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_common.c
vendored
Normal file
337
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_common.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_cred.c
vendored
Normal file
505
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_cred.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_record.c
vendored
Normal file
553
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_record.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_server.c
vendored
Normal file
656
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_server.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_server_read.c
vendored
Normal file
1278
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_server_read.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
819
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_server_write.c
vendored
Normal file
819
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/tlsv1_server_write.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/x509v3.c
vendored
Normal file
2013
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/tls/x509v3.c
vendored
Normal file
File diff suppressed because it is too large
Load Diff
155
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/utils/base64.c
vendored
Normal file
155
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/utils/base64.c
vendored
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
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/utils/ext_password.c
vendored
Normal file
114
cpu/esp32/vendor/esp-idf/wpa_supplicant/src/wpa2/utils/ext_password.c
vendored
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 */
|
||||||
Loading…
x
Reference in New Issue
Block a user