Merge branch 'feature/asio_ssl_support' into 'master'

asio: basic support of SSL/TLS transport

Closes IDFGH-1085 and IDFGH-2138

See merge request espressif/esp-idf!8797
This commit is contained in:
David Čermák
2020-07-15 19:51:47 +08:00
51 changed files with 2483 additions and 151 deletions

View File

@@ -1,3 +1,33 @@
idf_component_register(SRCS "asio/asio/src/asio.cpp" set(asio_sources "asio/asio/src/asio.cpp")
if (CONFIG_ASIO_SSL_SUPPORT)
if(CONFIG_ASIO_USE_ESP_OPENSSL)
list(APPEND asio_sources
"asio/asio/src/asio_ssl.cpp"
"port/src/esp_asio_openssl_stubs.c")
endif()
if(CONFIG_ASIO_USE_ESP_WOLFSSL)
list(APPEND asio_sources
"asio/asio/src/asio_ssl.cpp")
endif()
endif()
idf_component_register(SRCS ${asio_sources}
INCLUDE_DIRS "asio/asio/include" "port/include" INCLUDE_DIRS "asio/asio/include" "port/include"
REQUIRES lwip) REQUIRES lwip)
if (CONFIG_ASIO_SSL_SUPPORT)
if(CONFIG_ASIO_USE_ESP_WOLFSSL)
idf_component_get_property(wolflib esp-wolfssl COMPONENT_LIB)
idf_component_get_property(wolfdir esp-wolfssl COMPONENT_DIR)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${wolflib})
target_include_directories(${COMPONENT_LIB} PUBLIC ${wolfdir}/wolfssl/wolfssl)
endif()
if(CONFIG_ASIO_USE_ESP_OPENSSL)
idf_component_get_property(esp_openssl openssl COMPONENT_LIB)
target_link_libraries(${COMPONENT_LIB} PUBLIC ${esp_openssl})
endif()
endif()

25
components/asio/Kconfig Normal file
View File

@@ -0,0 +1,25 @@
menu "ESP-ASIO"
config ASIO_SSL_SUPPORT
bool "Enable SSL/TLS support of ASIO"
default n
help
Enable support for basic SSL/TLS features, available for mbedTLS/OpenSSL
as well as wolfSSL TLS library.
choice ASIO_SSL_LIBRARY_CHOICE
prompt "Choose SSL/TLS library for ESP-TLS (See help for more Info)"
default ASIO_USE_ESP_OPENSSL
depends on ASIO_SSL_SUPPORT
help
The ASIO support multiple backend TLS libraries. Currently the mbedTLS with a thin ESP-OpenSSL
port layer (default choice) and WolfSSL are supported.
Different TLS libraries may support different features and have different resource
usage. Consult the ESP-TLS documentation in ESP-IDF Programming guide for more details.
config ASIO_USE_ESP_OPENSSL
bool "esp-openssl"
config ASIO_USE_ESP_WOLFSSL
depends on TLS_STACK_WOLFSSL
bool "wolfSSL (License info in wolfSSL directory README)"
endchoice
endmenu

View File

@@ -1,6 +1,9 @@
COMPONENT_ADD_INCLUDEDIRS := asio/asio/include port/include COMPONENT_ADD_INCLUDEDIRS := asio/asio/include port/include
COMPONENT_PRIV_INCLUDEDIRS := private_include COMPONENT_PRIV_INCLUDEDIRS := private_include
COMPONENT_SRCDIRS := asio/asio/src COMPONENT_SRCDIRS := asio/asio/src port/src
COMPONENT_OBJEXCLUDE := asio/asio/src/asio_ssl.o
ifeq ($(CONFIG_ASIO_SSL_SUPPORT), )
COMPONENT_OBJEXCLUDE := asio/asio/src/asio_ssl.o port/src/esp_asio_openssl_stubs.o
endif
COMPONENT_SUBMODULES += asio COMPONENT_SUBMODULES += asio

View File

@@ -40,4 +40,11 @@
# define ASIO_STANDALONE # define ASIO_STANDALONE
# define ASIO_HAS_PTHREADS # define ASIO_HAS_PTHREADS
# ifdef CONFIG_ASIO_USE_ESP_OPENSSL
# define ASIO_USE_ESP_OPENSSL
# define OPENSSL_NO_ENGINE
# elif CONFIG_ASIO_USE_ESP_WOLFSSL
# define ASIO_USE_WOLFSSL
# endif // CONFIG_ASIO_USE_ESP_OPENSSL
#endif // _ESP_ASIO_CONFIG_H_ #endif // _ESP_ASIO_CONFIG_H_

View File

@@ -0,0 +1,26 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_ASIO_OPENSSL_CONF_H
#define _ESP_ASIO_OPENSSL_CONF_H
#include "esp_asio_config.h"
#include "openssl/esp_asio_openssl_stubs.h"
#if defined(ASIO_USE_WOLFSSL)
// SSLv3 Methods not present in current wolfSSL library
#define OPENSSL_NO_SSL3
#include_next "openssl/conf.h"
#endif // ASIO_USE_WOLFSSL
#endif // _ESP_ASIO_OPENSSL_CONF_H

View File

@@ -0,0 +1,23 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_ASIO_OPENSSL_DH_STUB_H
#define _ESP_ASIO_OPENSSL_DH_STUB_H
// Dummy header needed for ASIO compilation with esp-openssl
#if defined(ASIO_USE_WOLFSSL)
#include_next "openssl/dh.h"
#endif // ASIO_USE_WOLFSSL
#endif // _ESP_ASIO_OPENSSL_DH_STUB_H

View File

@@ -0,0 +1,209 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_ASIO_OPENSSL_STUBS_H
#define _ESP_ASIO_OPENSSL_STUBS_H
/**
* @note This header contains openssl API which are NOT implemented, and are only provided
* as stubs or no-operations to get the ASIO library compiled and working with most
* practical use cases as an embedded application on ESP platform
*/
#if defined(ASIO_USE_WOLFSSL)
#include "wolfssl/ssl.h"
// esp-wolfssl disables filesystem by default, but the ssl filesystem functions are needed for the ASIO to compile
// - so we could either configure wolfSSL to use filesystem
// - or use the default wolfSSL and declare the filesystem functions -- preferred option, as whenever
// the filesystem functions are used from app code (potential security impact if private keys in a filesystem)
// compilation fails with linking errors.
#if defined(NO_FILESYSTEM)
// WolfSSL methods that are not included in standard esp-wolfssl config, must be defined here
// as function stubs, so ASIO compiles, but would get link errors, if these functions were used.
#ifdef __cplusplus
extern "C" {
#endif
typedef struct WOLFSSL_CTX WOLFSSL_CTX;
void wolfSSL_CTX_set_verify_depth(WOLFSSL_CTX *ctx,int depth);
int SSL_CTX_load_verify_locations(WOLFSSL_CTX*, const char*, const char*);
int SSL_CTX_use_certificate_file(WOLFSSL_CTX*, const char*, int);
int SSL_CTX_use_certificate_chain_file(WOLFSSL_CTX*, const char*);
int SSL_CTX_use_PrivateKey_file(WOLFSSL_CTX*, const char*, int);
int SSL_CTX_use_RSAPrivateKey_file(WOLFSSL_CTX*, const char*, int);
#if defined(__cplusplus)
} /* extern C */
#endif
#endif // NO_FILESYSTEM
#elif defined(ASIO_USE_ESP_OPENSSL)
#include "internal/ssl_x509.h"
#include "internal/ssl_pkey.h"
#include "mbedtls/pem.h"
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// The most applicable OpenSSL version wrtt ASIO usage
#define OPENSSL_VERSION_NUMBER 0x10100001L
// SSLv2 methods not supported
// OpenSSL port supports: TLS_ANY, TLS_1, TLS_1_1, TLS_1_2, SSL_3
#define OPENSSL_NO_SSL2
#define SSL2_VERSION 0x0002
#define SSL_R_SHORT_READ 219
#define SSL_OP_ALL 0
#define SSL_OP_SINGLE_DH_USE 0
#define SSL_OP_NO_COMPRESSION 0
// Translates mbedTLS PEM parse error, used by ASIO
#define PEM_R_NO_START_LINE -MBEDTLS_ERR_PEM_NO_HEADER_FOOTER_PRESENT
#define SSL_OP_NO_SSLv2 0x01000000L
#define SSL_OP_NO_SSLv3 0x02000000L
#define SSL_OP_NO_TLSv1 0x04000000L
#define X509_FILETYPE_PEM 1
#define X509_FILETYPE_ASN1 2
#define SSL_FILETYPE_ASN1 X509_FILETYPE_ASN1
#define SSL_FILETYPE_PEM X509_FILETYPE_PEM
#define NID_subject_alt_name 85
#define GEN_DNS 2
#define GEN_IPADD 7
#define V_ASN1_OCTET_STRING 4
#define V_ASN1_IA5STRING 22
#define NID_commonName 13
#define SSL_CTX_get_app_data(ctx) ((void*)SSL_CTX_get_ex_data(ctx, 0))
/**
* @brief Frees DH object -- not implemented
*
* Current implementation calls SSL_ASSERT
*
* @param r DH object
*/
void DH_free(DH *r);
/**
* @brief Frees GENERAL_NAMES -- not implemented
*
* Current implementation calls SSL_ASSERT
*
* @param r GENERAL_NAMES object
*/
void GENERAL_NAMES_free(GENERAL_NAMES * gens);
/**
* @brief Returns subject name from X509 -- not implemented
*
* Current implementation calls SSL_ASSERT
*
* @param r X509 object
*/
X509_NAME *X509_get_subject_name(X509 *a);
/**
* @brief API provaded as declaration only
*
*/
int X509_STORE_CTX_get_error_depth(X509_STORE_CTX *ctx);
/**
* @brief API provaded as declaration only
*
*/
int X509_NAME_get_index_by_NID(X509_NAME *name, int nid, int lastpos);
/**
* @brief API provaded as declaration only
*
*/
X509_NAME_ENTRY *X509_NAME_get_entry(X509_NAME *name, int loc);
/**
* @brief API provaded as declaration only
*
*/
ASN1_STRING *X509_NAME_ENTRY_get_data(X509_NAME_ENTRY *ne);
/**
* @brief API provaded as declaration only
*
*/
void *X509_get_ext_d2i(X509 *x, int nid, int *crit, int *idx);
/**
* @brief API provaded as declaration only
*
*/
X509 * X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
/**
* @brief Reads DH params from a bio object -- not implemented
*
* Current implementation calls SSL_ASSERT
*/
DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u);
/**
* @brief API provaded as declaration only
*
*/
void * X509_STORE_CTX_get_ex_data(X509_STORE_CTX *ctx,int idx);
/**
* @brief Sets DH params to ssl ctx -- not implemented
*
* Current implementation calls SSL_ASSERT
*/
int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh);
/**
* @brief API provaded as declaration only
*
*/
void SSL_CTX_set_default_passwd_cb_userdata(SSL_CTX *ctx, void *data);
/**
* @brief API provaded as declaration only
*
*/
void SSL_CTX_set_default_passwd_cb(SSL_CTX *ctx, pem_password_cb *cb);
/**
* @brief Clears any existing chain associated with the current certificate of ctx.
*
*/
int SSL_CTX_clear_chain_certs(SSL_CTX *ctx);
#if defined(__cplusplus)
} /* extern C */
#endif
#endif /* ASIO_USE_ESP_OPENSSL, ASIO_USE_WOLFSSL */
#endif /* _ESP_ASIO_OPENSSL_STUBS_H */

View File

@@ -0,0 +1,23 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_ASIO_OPENSSL_RSA_STUB_H
#define _ESP_ASIO_OPENSSL_RSA_STUB_H
// Dummy header needed for ASIO compilation with esp-openssl
#if defined(ASIO_USE_WOLFSSL)
#include_next "openssl/rsa.h"
#endif // ASIO_USE_WOLFSSL
#endif // _ESP_ASIO_OPENSSL_RSA_STUB_H

View File

@@ -0,0 +1,23 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _ESP_ASIO_OPENSSL_X509V3_STUB_H
#define _ESP_ASIO_OPENSSL_X509V3_STUB_H
// Dummy header needed for ASIO compilation with esp-openssl
#if defined(ASIO_USE_WOLFSSL)
#include_next "openssl/x509v3.h"
#endif // ASIO_USE_WOLFSSL
#endif // _ESP_ASIO_OPENSSL_X509V3_STUB_H

View File

@@ -0,0 +1,55 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "esp_asio_config.h"
#include "internal/ssl_dbg.h"
#include "openssl/esp_asio_openssl_stubs.h"
// Unsupported features as macros to make the assertions more readable
#define ESP_OPENSSL_DH_IS_SUPPORTED 0
#define ESP_OPENSSL_GENERAL_NAMES_IS_SUPPORTED 0
void DH_free (DH *r)
{
SSL_ASSERT3(ESP_OPENSSL_DH_IS_SUPPORTED);
}
DH *PEM_read_bio_DHparams(BIO *bp, DH **x, pem_password_cb *cb, void *u)
{
SSL_ASSERT2(ESP_OPENSSL_DH_IS_SUPPORTED);
return NULL;
}
int SSL_CTX_set_tmp_dh(SSL_CTX *ctx, const DH *dh)
{
SSL_ASSERT1(ESP_OPENSSL_DH_IS_SUPPORTED);
return -1;
}
void GENERAL_NAMES_free(GENERAL_NAMES * gens)
{
SSL_ASSERT3(ESP_OPENSSL_GENERAL_NAMES_IS_SUPPORTED);
}
X509_NAME *X509_get_subject_name(X509 *a)
{
SSL_ASSERT2(ESP_OPENSSL_GENERAL_NAMES_IS_SUPPORTED);
return NULL;
}
int SSL_CTX_clear_chain_certs(SSL_CTX *ctx)
{
return 1;
}

View File

@@ -2,6 +2,8 @@ idf_component_register(SRCS "library/ssl_cert.c"
"library/ssl_lib.c" "library/ssl_lib.c"
"library/ssl_methods.c" "library/ssl_methods.c"
"library/ssl_pkey.c" "library/ssl_pkey.c"
"library/ssl_bio.c"
"library/ssl_err.c"
"library/ssl_stack.c" "library/ssl_stack.c"
"library/ssl_x509.c" "library/ssl_x509.c"
"platform/ssl_pm.c" "platform/ssl_pm.c"

View File

@@ -8,6 +8,12 @@ menu "OpenSSL"
If the option is enabled, "SSL_DEBUG" works. If the option is enabled, "SSL_DEBUG" works.
config OPENSSL_ERROR_STACK
bool "Enable OpenSSL error structure"
default y
help
Enable OpenSSL Error reporting
config OPENSSL_DEBUG_LEVEL config OPENSSL_DEBUG_LEVEL
int "OpenSSL debugging level" int "OpenSSL debugging level"
default 0 default 0

View File

@@ -12,8 +12,8 @@ Chapter Introduction
==================== ====================
- Chapter 1. SSL Context Method Create - Chapter 1. SSL Context Method Create
- Chapter 2. SSL Context Fucntion - Chapter 2. SSL Context Function
- Chapter 3. SSL Fucntion - Chapter 3. SSL Function
- Chapter 4. SSL X509 Certification and Private Key Function - Chapter 4. SSL X509 Certification and Private Key Function

View File

@@ -23,6 +23,10 @@
#include "tls1.h" #include "tls1.h"
#include "x509_vfy.h" #include "x509_vfy.h"
/* Used in SSL_set_mode() -- supported mode when using BIO */
#define SSL_MODE_ENABLE_PARTIAL_WRITE 0x00000001L
#define SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER 0x00000002L
/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ /* Used in SSL_set_shutdown()/SSL_get_shutdown(); */
# define SSL_SENT_SHUTDOWN 1 # define SSL_SENT_SHUTDOWN 1
# define SSL_RECEIVED_SHUTDOWN 2 # define SSL_RECEIVED_SHUTDOWN 2

View File

@@ -55,6 +55,52 @@ EVP_PKEY* d2i_PrivateKey(int type,
const unsigned char **pp, const unsigned char **pp,
long length); long length);
/**
* @brief decodes and load a buffer BIO into a EVP key context. If '*a' is pointed to the
* private key, then load key into it. Or create a new private key object
*
* @param bp BIO object containing the key
* @param a Pointer to an existing EVP_KEY or NULL if a new key shall be created
*
* @return Created or updated EVP_PKEY
*/
EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a);
/**
* @brief Same as d2i_PrivateKey_bio
*
* @param bp BIO object containing the key
* @param a Pointer to an existing EVP_KEY or NULL if a new key shall be created
*
* @return Created or updated EVP_PKEY
*/
RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **rsa);
/**
* @brief loads a private key in PEM format from BIO object
*
* @param bp BIO object containing the key
* @param x Pointer to an existent PKEY or NULL if a new key shall be created
* @param cb Password callback (not used)
* @param u User context (not used)
*
* @return Created or updated EVP_PKEY
*/
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **x, pem_password_cb *cb, void *u);
/**
* @brief RSA key in PEM format from BIO object
*
* @param bp BIO object containing the key
* @param x Pointer to an existent PKEY or NULL if a new key shall be created
* @param cb Password callback (not used)
* @param u User context (not used)
*
* @return Created or updated EVP_PKEY
*/
RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **rsa, pem_password_cb *cb, void *u);
/** /**
* @brief free a private key object * @brief free a private key object
* *

View File

@@ -17,6 +17,49 @@
} \ } \
#define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) #define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t)
typedef struct asn1_string_st ASN1_OCTET_STRING;
struct stack_st_GENERAL_NAME;
typedef struct GENERAL_NAME_st {
int type;
union {
char *ptr;
struct asn1_string_st* dNSName;
ASN1_OCTET_STRING* iPAddress;
} d;
} GENERAL_NAME;
typedef struct asn1_string_st ASN1_OCTET_STRING;
typedef struct X509_name_st X509_NAME;
typedef struct asn1_string_st ASN1_STRING;
typedef struct X509_name_entry_st X509_NAME_ENTRY;
typedef struct asn1_string_st {
int type;
int length;
void *data;
} ASN1_IA5STRING;
typedef STACK_OF(GENERAL_NAME) GENERAL_NAMES;
/**
* @brief get nr of stack items
*
* @param sk Stack structure pointer
*
* @return number of items in the stack
*/
size_t sk_GENERAL_NAME_num(const struct stack_st_GENERAL_NAME *sk);
/**
* @brief get GENERAL_NAME value from the stack
*
* @param sk Stack structure pointer
* @param i Index to stack item
*
* @return GENERAL_NAME object pointer
*/
GENERAL_NAME *sk_GENERAL_NAME_value(const struct stack_st_GENERAL_NAME *sk, size_t i);
/** /**
* @brief create a openssl stack object * @brief create a openssl stack object

View File

@@ -20,6 +20,8 @@
#endif #endif
#include "ssl_code.h" #include "ssl_code.h"
#include <stddef.h>
#include <stdint.h>
typedef void SSL_CIPHER; typedef void SSL_CIPHER;
@@ -30,6 +32,8 @@ typedef void RSA;
typedef void STACK; typedef void STACK;
typedef void DH;
#define ossl_inline inline #define ossl_inline inline
#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__) #define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__)
@@ -37,7 +41,7 @@ typedef void STACK;
#define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__) #define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__)
typedef int (*OPENSSL_sk_compfunc)(const void *, const void *); typedef int (*OPENSSL_sk_compfunc)(const void *, const void *);
typedef int (*openssl_verify_callback)(int, X509_STORE_CTX *);
struct stack_st; struct stack_st;
typedef struct stack_st OPENSSL_STACK; typedef struct stack_st OPENSSL_STACK;
@@ -100,6 +104,8 @@ struct evp_pkey_st {
void *pkey_pm; void *pkey_pm;
const PKEY_METHOD *method; const PKEY_METHOD *method;
int ref_counter;
}; };
struct x509_st { struct x509_st {
@@ -152,8 +158,16 @@ struct X509_VERIFY_PARAM_st {
}; };
struct bio_st { struct bio_st {
const unsigned char * data;
unsigned char * data;
int dlen; int dlen;
BIO* peer;
size_t offset;
size_t roffset;
size_t size;
size_t flags;
size_t type;
}; };
typedef enum { ALPN_INIT, ALPN_ENABLE, ALPN_DISABLE, ALPN_ERROR } ALPN_STATUS; typedef enum { ALPN_INIT, ALPN_ENABLE, ALPN_DISABLE, ALPN_ERROR } ALPN_STATUS;
@@ -166,6 +180,9 @@ struct ssl_alpn_st {
const char *alpn_list[ALPN_LIST_MAX]; const char *alpn_list[ALPN_LIST_MAX];
}; };
typedef int pem_password_cb(char *buf, int size, int rwflag, void *userdata);
struct ssl_ctx_st struct ssl_ctx_st
{ {
int version; int version;
@@ -193,6 +210,16 @@ struct ssl_ctx_st
int read_buffer_len; int read_buffer_len;
X509_VERIFY_PARAM param; X509_VERIFY_PARAM param;
void *default_passwd_callback_userdata;
pem_password_cb *default_passwd_callback;
struct stack_st_X509 *extra_certs;
int max_version;
int min_version;
}; };
struct ssl_st struct ssl_st
@@ -230,12 +257,13 @@ struct ssl_st
X509_VERIFY_PARAM param; X509_VERIFY_PARAM param;
int err; uint32_t mode;
void (*info_callback) (const SSL *ssl, int type, int val); void (*info_callback) (const SSL *ssl, int type, int val);
/* SSL low-level system arch point */ /* SSL low-level system arch point */
void *ssl_pm; void *ssl_pm;
void *bio;
}; };
struct ssl_method_st { struct ssl_method_st {
@@ -299,6 +327,13 @@ struct pkey_method_st {
int (*pkey_load)(EVP_PKEY *pkey, const unsigned char *buf, int len); int (*pkey_load)(EVP_PKEY *pkey, const unsigned char *buf, int len);
}; };
struct bio_method_st {
unsigned type;
unsigned size;
};
typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out,
unsigned char *outlen, const unsigned char *in, unsigned char *outlen, const unsigned char *in,

View File

@@ -114,23 +114,6 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d);
*/ */
int X509_STORE_add_cert(X509_STORE *store, X509 *x); int X509_STORE_add_cert(X509_STORE *store, X509 *x);
/**
* @brief load data in BIO
*
* Normally BIO_write should append data but that doesn't happen here, and
* 'data' cannot be freed after the function is called, it should remain valid
* until BIO object is in use.
*
* @param b - pointer to BIO
* @param data - pointer to data
* @param dlen - data bytes
*
* @return result
* 0 : failed
* 1 : OK
*/
int BIO_write(BIO *b, const void *data, int dlen);
/** /**
* @brief load a character certification context into system context. * @brief load a character certification context into system context.
* *
@@ -145,28 +128,22 @@ int BIO_write(BIO *b, const void *data, int dlen);
* *
* @return X509 certification object point * @return X509 certification object point
*/ */
X509 * PEM_read_bio_X509(BIO *bp, X509 **x, void *cb, void *u); X509 * PEM_read_bio_X509(BIO *bp, X509 **x, pem_password_cb cb, void *u);
/** /**
* @brief create a BIO object * @brief load a character certification context into system context.
*
* @param method - pointer to BIO_METHOD
* *
* @return pointer to BIO object * Current implementation directly calls PEM_read_bio_X509
*/
BIO *BIO_new(void * method);
/**
* @brief get the memory BIO method function
*/
void *BIO_s_mem(void);
/**
* @brief free a BIO object
* *
* @param x - pointer to BIO object * @param bp - pointer to BIO
* @param buffer - pointer to the certification context memory
* @param cb - pointer to the callback (not implemented)
* @param u - pointer to arbitrary data (not implemented)
*
* @return X509 certification object point
*/ */
void BIO_free(BIO *b); X509 *PEM_read_bio_X509_AUX(BIO *bp, X509 **cert, pem_password_cb *cb, void *u);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -0,0 +1,179 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _OPENSSL_BIO_H
#define _OPENSSL_BIO_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/* These are the 'types' of BIOs */
#define BIO_TYPE_NONE 0
#define BIO_TYPE_MEM (1 | 0x0400)
#define BIO_TYPE_BIO (19 | 0x0400) /* (half a) BIO pair */
/* Bio object flags */
#define BIO_FLAGS_READ 0x01
#define BIO_FLAGS_WRITE 0x02
#define BIO_should_read(a) BIO_test_flags(a, BIO_FLAGS_READ)
#define BIO_should_write(a) BIO_test_flags(a, BIO_FLAGS_WRITE)
typedef struct bio_st BIO;
typedef struct bio_method_st BIO_METHOD;
/**
* @brief Create a BIO object as a file type
* Current implementation return NULL as file types are discouraged on ESP platform
*
* @param filename Filename
* @param mode Mode
*
* @return BIO object
*/
BIO *BIO_new_file(const char *filename, const char *mode);
/**
* @brief Create a BIO object as a membuf type
* Current implementation takes a shallow copy of the buffer
*
* @param buf Pointer to the buffer
* @param len Length of the buffer
*
* @return BIO object
*/
BIO *BIO_new_mem_buf(void *buf, int len);
/**
* @brief create a BIO object
*
* @param method - pointer to BIO_METHOD
*
* @return pointer to BIO object
*/
BIO *BIO_new(BIO_METHOD * method);
/**
* @brief get the memory BIO method function
*/
void *BIO_s_mem(void);
/**
* @brief free a BIO object
*
* @param x - pointer to BIO object
*/
void BIO_free(BIO *b);
/**
* @brief Create a connected pair of BIOs bio1, bio2 with write buffer sizes writebuf1 and writebuf2
*
* @param out1 pointer to BIO1
* @param writebuf1 write size of BIO1 (0 means default size will be used)
* @param out2 pointer to BIO2
* @param writebuf2 write size of BIO2 (0 means default size will be used)
*
* @return result
* 0 : failed
* 1 : OK
*/
int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, size_t writebuf2);
/**
* @brief Write data to BIO
*
* BIO_TYPE_BIO behaves the same way as OpenSSL bio object, other BIO types mock
* this functionality to avoid excessive allocation/copy, so the 'data' cannot
* be freed after the function is called, it should remain valid until BIO object is in use.
*
* @param b - pointer to BIO
* @param data - pointer to data
* @param dlen - data bytes
*
* @return result
* -1, 0 : failed
* 1 : OK
*/
int BIO_write(BIO *b, const void *data, int dlen);
/**
* @brief Read data from BIO
*
* BIO_TYPE_BIO behaves the same way as OpenSSL bio object.
* Other types just hold pointer
*
* @param b - pointer to BIO
* @param data - pointer to data
* @param dlen - data bytes
*
* @return result
* -1, 0 : failed
* 1 : OK
*/
int BIO_read(BIO *bio, void *data, int len);
/**
* @brief Get number of pending characters in the BIOs write buffers.
*
* @param b Pointer to BIO
*
* @return Amount of pending data
*/
size_t BIO_wpending(const BIO *bio);
/**
* @brief Get number of pending characters in the BIOs read buffers.
*
* @param b Pointer to BIO
*
* @return Amount of pending data
*/
size_t BIO_ctrl_pending(const BIO *bio);
/**
* @brief Get the maximum length of data that can be currently written to the BIO
*
* @param b Pointer to BIO
*
* @return Max length of writable data
*/
size_t BIO_ctrl_get_write_guarantee(BIO *bio);
/**
* @brief Returns the type of a BIO.
*
* @param b Pointer to BIO
*
* @return Type of the BIO object
*/
int BIO_method_type(const BIO *b);
/**
* @brief Test flags of a BIO.
*
* @param b Pointer to BIO
* @param flags Flags
*
* @return BIO object flags masked with the supplied flags
*/
int BIO_test_flags(const BIO *b, int flags);
#ifdef __cplusplus
}
#endif
#endif //_OPENSSL_BIO_H

View File

@@ -0,0 +1,228 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _OPENSSL_ERR_H
#define _OPENSSL_ERR_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @note This file contains a very simple implementation of error stack
* for ESP APIs stubs to OpenSSL
*/
#define OPENSSL_PUT_SYSTEM_ERROR() \
ERR_put_error(ERR_LIB_SYS, 0, 0, __FILE__, __LINE__);
#define OPENSSL_PUT_LIB_ERROR(lib, code) \
ERR_put_error(lib, 0, code, __FILE__, __LINE__);
#define ERR_GET_LIB(packed_error) ((int)(((packed_error) >> 24) & 0xff))
#define ERR_GET_REASON(packed_error) ((int)((packed_error) & 0xffff))
#define ERR_R_PEM_LIB ERR_LIB_PEM
/* inherent openssl errors */
# define ERR_R_FATAL 64
# define ERR_R_MALLOC_FAILURE (1|ERR_R_FATAL)
# define ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED (2|ERR_R_FATAL)
# define ERR_R_PASSED_NULL_PARAMETER (3|ERR_R_FATAL)
# define ERR_R_INTERNAL_ERROR (4|ERR_R_FATAL)
# define ERR_R_DISABLED (5|ERR_R_FATAL)
# define ERR_R_INIT_FAIL (6|ERR_R_FATAL)
# define ERR_R_PASSED_INVALID_ARGUMENT (7)
# define ERR_R_OPERATION_FAIL (8|ERR_R_FATAL)
# define ERR_R_INVALID_PROVIDER_FUNCTIONS (9|ERR_R_FATAL)
# define ERR_R_INTERRUPTED_OR_CANCELLED (10)
enum {
ERR_LIB_NONE = 1,
ERR_LIB_SYS,
ERR_LIB_BN,
ERR_LIB_RSA,
ERR_LIB_DH,
ERR_LIB_EVP,
ERR_LIB_BUF,
ERR_LIB_OBJ,
ERR_LIB_PEM,
ERR_LIB_DSA,
ERR_LIB_X509,
ERR_LIB_ASN1,
ERR_LIB_CONF,
ERR_LIB_CRYPTO,
ERR_LIB_EC,
ERR_LIB_SSL,
ERR_LIB_BIO,
ERR_LIB_PKCS7,
ERR_LIB_PKCS8,
ERR_LIB_X509V3,
ERR_LIB_RAND,
ERR_LIB_ENGINE,
ERR_LIB_OCSP,
ERR_LIB_UI,
ERR_LIB_COMP,
ERR_LIB_ECDSA,
ERR_LIB_ECDH,
ERR_LIB_HMAC,
ERR_LIB_DIGEST,
ERR_LIB_CIPHER,
ERR_LIB_HKDF,
ERR_LIB_USER,
ERR_NUM_LIBS
};
/**
* @brief clear the SSL error code
*
* @param none
*
* @return none
*/
void ERR_clear_error(void);
/**
* @brief get the current SSL error code
*
* @param none
*
* @return current SSL error number
*/
uint32_t ERR_get_error(void);
/**
* @brief peek the current SSL error code, not clearing it
*
* @param none
*
* @return current SSL error number
*/
uint32_t ERR_peek_error(void);
/**
* @brief peek the last SSL error code, not clearing it
*
* @param none
*
* @return current SSL error number
*/
uint32_t ERR_peek_last_error(void);
/**
* @brief register the SSL error strings
*
* @param none
*
* @return none
*/
void ERR_load_SSL_strings(void);
/**
* @brief clear the SSL error code
*
* @param none
*
* @return none
*/
void ERR_clear_error(void);
/**
* @brief peek the current SSL error code, not clearing it
*
* @param none
*
* @return current SSL error number
*/
uint32_t ERR_peek_error(void);
/**
* @brief peek the last SSL error code, not clearing it
*
* @param none
*
* @return current SSL error number
*/
uint32_t ERR_peek_last_error(void);
/**
* @brief capture the current error to the error structure
*
* @param library Related library
* @param unused Not used (used for compliant function prototype)
* @param reason The actual error code
* @param file File name of the error report
* @param line Line number of the error report
*
*/
void ERR_put_error(int library, int unused, int reason, const char *file, unsigned line);
/**
* @brief Peek the current SSL error, not clearing it
*
* @param file file name of the reported error
* @param line line number of the reported error
* @param data Associated data to the reported error
* @param flags Flags associated to the error
*
* @return current SSL error number
*/
uint32_t ERR_peek_error_line_data(const char **file, int *line,
const char **data, int *flags);
/**
* @brief Get the current SSL error
*
* @param file file name of the reported error
* @param line line number of the reported error
* @param data Associated data to the reported error
* @param flags Flags associated to the error
*
* @return current SSL error number
*/
uint32_t ERR_get_error_line_data(const char **file, int *line,
const char **data, int *flags);
/**
* @brief API provided as a declaration only
*
*/
void SSL_load_error_strings(void);
/**
* @brief API provided as a declaration only
*
*/
void ERR_free_strings(void);
/**
* @brief API provided as a declaration only
*
*/
void ERR_remove_state(unsigned long pid);
/**
* @brief Returns error string -- Not implemented
*
* @param packed_error Packed error code
*
* @return NULL
*/
const char *ERR_reason_error_string(uint32_t packed_error);
#ifdef __cplusplus
}
#endif
#endif // _OPENSSL_ERR_H

View File

@@ -21,6 +21,8 @@
#include "internal/ssl_x509.h" #include "internal/ssl_x509.h"
#include "internal/ssl_pkey.h" #include "internal/ssl_pkey.h"
#include "openssl/bio.h"
#include "openssl/err.h"
/* /*
{ {
@@ -297,6 +299,67 @@ const SSL_METHOD* SSLv3_server_method(void);
*/ */
const SSL_METHOD* TLS_server_method(void); const SSL_METHOD* TLS_server_method(void);
/**
* @brief create the target SSL context method
*
* @return the TLS any version SSL context method
*/
const SSL_METHOD* TLS_method(void);
/**
* @brief create the target SSL context method
*
* @return the TLS1.2 version SSL context method
*/
const SSL_METHOD* TLSv1_2_method(void);
/**
* @brief create the target SSL context method
*
* @return the TLS1.1 version SSL context method
*/
const SSL_METHOD* TLSv1_1_method(void);
/**
* @brief create the target SSL context method
*
* @return the TLS1.0 version SSL context method
*/
const SSL_METHOD* TLSv1_method(void);
/**
* @brief create the target SSL context method
*
* @return the SSLV3.0 version SSL context method
*/
const SSL_METHOD* SSLv3_method(void);
/**
* @brief create the target SSL context method
*
* @param none
*
* @return the SSLV2.3 version SSL context method
*/
const SSL_METHOD* SSLv23_method(void);
/**
* @brief Set minimum protocol version for defined context
*
* @param ctx SSL context
*
* @return 1 on success
*/
int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version);
/**
* @brief Set maximum protocol version for defined context
*
* @param ctx SSL context
*
* @return 1 on success
*/
int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version);
/** /**
* @brief set the SSL context ALPN select callback function * @brief set the SSL context ALPN select callback function
@@ -348,43 +411,6 @@ void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx,
void *arg), void *arg),
void *arg); void *arg);
/**
* @brief get SSL error code
*
* @param ssl - SSL point
* @param ret_code - SSL return code
*
* @return SSL error number
*/
int SSL_get_error(const SSL *ssl, int ret_code);
/**
* @brief clear the SSL error code
*
* @param none
*
* @return none
*/
void ERR_clear_error(void);
/**
* @brief get the current SSL error code
*
* @param none
*
* @return current SSL error number
*/
int ERR_get_error(void);
/**
* @brief register the SSL error strings
*
* @param none
*
* @return none
*/
void ERR_load_SSL_strings(void);
/** /**
* @brief initialize the SSL library * @brief initialize the SSL library
* *
@@ -1399,7 +1425,17 @@ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl);
* *
* @return application data * @return application data
*/ */
char *SSL_get_app_data(SSL *ssl); void *SSL_get_app_data(SSL *ssl);
/**
* @brief get SSL error code
*
* @param ssl - SSL point
* @param ret_code - SSL return code
*
* @return SSL error number
*/
int SSL_get_error(const SSL *ssl, int ret_code);
/** /**
* @brief get SSL cipher bits * @brief get SSL cipher bits
@@ -1667,7 +1703,7 @@ void SSL_set_accept_state(SSL *ssl);
* *
* @return none * @return none
*/ */
void SSL_set_app_data(SSL *ssl, char *arg); void SSL_set_app_data(SSL *ssl, void *arg);
/** /**
* @brief set SSL BIO * @brief set SSL BIO
@@ -1756,7 +1792,7 @@ void SSL_set_timeout(SSL *ssl, long t);
* *
* @return SSL statement string * @return SSL statement string
*/ */
char *SSL_state_string(const SSL *ssl); const char *SSL_state_string(const SSL *ssl);
/** /**
* @brief get SSL statement long string * @brief get SSL statement long string
@@ -1815,6 +1851,52 @@ const char *SSL_get_psk_identity_hint(SSL *ssl);
*/ */
const char *SSL_get_psk_identity(SSL *ssl); const char *SSL_get_psk_identity(SSL *ssl);
/**
* @brief set the SSL verify depth of the SSL
*
* @param ssl - SSL context
* @param depth - Depth level to verify
*
*/
void SSL_set_verify_depth(SSL *ssl, int depth);
/**
* @brief Get default verify callback
*
* @param ctx - SSL context
* @return verify_callback - verifying callback function
*
*/
openssl_verify_callback SSL_CTX_get_verify_callback(const SSL_CTX *ctx);
/**
* @brief Get default verify callback
*
* @param ctx - SSL context
* @return verify_callback - verifying callback function
*
*/
openssl_verify_callback SSL_get_verify_callback(const SSL *s);
/**
* @brief Frees RSA object
*
* Current implementation calls directly EVP_PKEY free
*
* @param r RSA object
*
*/
void RSA_free(RSA *r);
/**
* @brief Sets SSL mode, partially implemented
*
* @param ssl SSL context
*
* @return the new mode bitmask after adding mode
*/
uint32_t SSL_set_mode(SSL *ssl, uint32_t mode);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View File

@@ -0,0 +1,210 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ssl_lib.h"
#include "openssl/bio.h"
#include "ssl_dbg.h"
#include "openssl/err.h"
#define DEFAULT_BIO_SIZE 1024
BIO *BIO_new_mem_buf(void *buf, int len)
{
BIO_METHOD m = { .type = BIO_TYPE_MEM, .size = 0 };
BIO *b = BIO_new(&m);
if (b) {
b->dlen = len;
b->data = buf;
}
return b;
}
/**
* @brief create a BIO object
*/
BIO *BIO_new(BIO_METHOD * method)
{
BIO *b = (BIO *)ssl_mem_zalloc(sizeof(BIO));
if (!b) {
OPENSSL_PUT_LIB_ERROR(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
goto err;
}
if (method) {
b->size = method->size;
b->type = method->type;
} else {
b->type = BIO_TYPE_NONE;
}
if ((b->type & BIO_TYPE_BIO) && b->size) {
b->data = ssl_mem_zalloc(b->size);
if (!b->data) {
OPENSSL_PUT_LIB_ERROR(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
goto err;
}
}
return b;
err:
if (b && (b->type&BIO_TYPE_BIO)) {
ssl_mem_free(b->data);
}
ssl_mem_free(b);
return NULL;
}
/**
* @brief free a BIO object
*/
void BIO_free(BIO *b)
{
if (b && (b->type&BIO_TYPE_BIO)) {
ssl_mem_free(b->data);
}
ssl_mem_free(b);
}
int BIO_new_bio_pair(BIO **out1, size_t writebuf1, BIO **out2, size_t writebuf2)
{
BIO *bio1 = NULL;
BIO *bio2 = NULL;
if (!writebuf1) {
writebuf1 = DEFAULT_BIO_SIZE;
}
if (!writebuf2) {
writebuf2 = DEFAULT_BIO_SIZE;
}
BIO_METHOD m1 = {
.size = writebuf1,
.type = BIO_TYPE_BIO,
};
BIO_METHOD m2 = {
.size = writebuf1,
.type = BIO_TYPE_BIO,
};
bio1 = BIO_new(&m1);
if (!bio1) {
goto err;
}
bio2 = BIO_new(&m2);
if (!bio2) {
goto err;
}
*out1 = bio1;
*out2 = bio2;
bio1->peer = bio2;
bio1->size = writebuf1;
bio2->peer = bio1;
bio2->size = writebuf2;
return 1;
err:
if (bio1)
{
BIO_free(bio1);
*out1 = NULL;
}
if (bio2)
{
BIO_free(bio2);
*out2 = NULL;
}
return 0;
}
/**
* @brief get the memory BIO method function
*/
void *BIO_s_mem(void)
{
return NULL;
}
int BIO_method_type(const BIO *b)
{
SSL_ASSERT1(b);
return b->type;
}
/**
* @brief load data into BIO.
*
*/
int BIO_write(BIO *b, const void * data, int dlen)
{
SSL_ASSERT1(b);
int remaining = b->size - b->offset;
if (remaining <= 0) {
b->flags |= BIO_FLAGS_WRITE;
return -1;
}
int len_to_write = dlen > remaining?remaining:dlen;
memcpy(b->data + b->offset, data, len_to_write);
b->offset += len_to_write;
b->dlen = b->offset;
if (len_to_write == dlen) {
b->flags &= ~BIO_FLAGS_WRITE;
}
return len_to_write;
}
/**
* @brief Read from BIO.
*
*/
int BIO_read(BIO *bio, void *data, int len)
{
SSL_ASSERT1(bio);
BIO *peer = bio->peer;
int remaining = peer->dlen - peer->roffset;
if (remaining <= 0) {
bio->flags |= BIO_FLAGS_READ;
return -1;
}
int len_to_read = remaining > len ? len : remaining;
memcpy(data, peer->data + peer->roffset, len_to_read);
peer->roffset += len_to_read;
if (len_to_read == len) {
bio->flags &= ~BIO_FLAGS_READ;
}
if (peer->offset) {
// shift data back to the beginning of the buffer
memmove(peer->data, peer->data+peer->roffset, peer->offset - peer->roffset);
peer->offset -= peer->roffset;
peer->roffset = 0;
peer->dlen = peer->offset;
}
return len_to_read;
}
size_t BIO_wpending(const BIO *bio)
{
return bio->dlen - bio->roffset;
}
size_t BIO_ctrl_pending(const BIO *bio)
{
return bio->peer->dlen - bio->peer->roffset;
}
size_t BIO_ctrl_get_write_guarantee(BIO *b)
{
return (long)b->size - b->dlen;
}
int BIO_test_flags(const BIO *b, int flags)
{
return (b->flags & flags);
}

View File

@@ -0,0 +1,120 @@
// Copyright 2020 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "ssl_dbg.h"
struct err_error_st {
/* file contains the filename where the error occurred. */
const char *file;
/* packed contains the error library and reason, as packed by ERR_PACK. */
uint32_t packed;
/* line contains the line number where the error occurred. */
uint32_t line;
};
#define ERR_NUM_ERRORS 4
typedef struct err_state_st {
/* errors contains the ERR_NUM_ERRORS most recent errors, organised as a ring
* buffer. */
struct err_error_st errors[ERR_NUM_ERRORS];
/* top contains the index one past the most recent error. If |top| equals
* |bottom| then the queue is empty. */
unsigned top;
/* bottom contains the index of the last error in the queue. */
unsigned bottom;
} ERR_STATE;
#if CONFIG_OPENSSL_ERROR_STACK
static ERR_STATE s_err_state = { 0 };
#endif
void ERR_clear_error(void)
{
#if CONFIG_OPENSSL_ERROR_STACK
memset(&s_err_state.errors[0], 0, sizeof(struct err_state_st));
s_err_state.top = s_err_state.bottom = 0;
#endif
}
static uint32_t ERR_get_peek_error_internal(const char **file, int *line, bool peak)
{
#if CONFIG_OPENSSL_ERROR_STACK
if (s_err_state.top == s_err_state.bottom) {
return 0;
}
unsigned new_bottom = (s_err_state.bottom + 1) % ERR_NUM_ERRORS;
int err = s_err_state.errors[new_bottom].packed;
if (file) {
*file = s_err_state.errors[new_bottom].file;
}
if (line) {
*line = s_err_state.errors[new_bottom].line;
}
if (peak == false) {
memset(&s_err_state.errors[new_bottom], 0, sizeof(struct err_error_st));
s_err_state.bottom = new_bottom;
}
return err;
#else
return 0;
#endif
}
uint32_t ERR_get_error(void)
{
return ERR_get_peek_error_internal(NULL, NULL, false);
}
uint32_t ERR_peek_error(void)
{
return ERR_get_peek_error_internal(NULL, NULL, true);
}
uint32_t ERR_peek_last_error(void)
{
return ERR_get_peek_error_internal(NULL, NULL, true);
}
uint32_t ERR_peek_error_line_data(const char **file, int *line, const char **data, int *flags)
{
return ERR_get_peek_error_internal(file, line, true);
}
uint32_t ERR_get_error_line_data(const char **file, int *line, const char **data, int *flags)
{
return ERR_get_peek_error_internal(file, line, false);
}
const char *ERR_reason_error_string(uint32_t packed_error)
{
return NULL;
}
void ERR_put_error(int library, int unused, int reason, const char *file, unsigned line)
{
#if CONFIG_OPENSSL_ERROR_STACK
s_err_state.top = (s_err_state.top + 1) % ERR_NUM_ERRORS;
if (s_err_state.top == s_err_state.bottom) {
s_err_state.bottom = (s_err_state.bottom + 1) % ERR_NUM_ERRORS;
}
s_err_state.errors[s_err_state.top].packed = (uint32_t)library<<24 | abs(reason);
s_err_state.errors[s_err_state.top].file = file;
s_err_state.errors[s_err_state.top].line = line;
#endif
}

View File

@@ -1476,6 +1476,46 @@ long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx)
return ctx->read_ahead; return ctx->read_ahead;
} }
char *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx)
{
SSL_ASSERT2(ctx);
return NULL;
}
int SSL_CTX_set_app_data(SSL_CTX *ctx, void *arg)
{
SSL_ASSERT1(ctx);
return 0;
}
void *SSL_get_app_data(SSL *ssl)
{
SSL_ASSERT2(ssl);
return NULL;
}
void SSL_set_app_data(SSL *ssl, void *arg)
{
SSL_ASSERT3(ssl);
}
void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio)
{
SSL_ASSERT3(ssl);
ssl->bio = rbio;
}
int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file)
{
SSL_ASSERT1(1)
return -1;
}
/** /**
* @brief set SSL session time * @brief set SSL session time
*/ */
@@ -1550,12 +1590,16 @@ void SSL_set_verify_depth(SSL *ssl, int depth)
ssl->param.depth = depth; ssl->param.depth = depth;
} }
#define ESP_OPENSSL_VERIFYCB_IS_SUPPORTED 0
/** /**
* @brief set the SSL context verifying of the SSL context * @brief set the SSL context verifying of the SSL context
*/ */
void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *))
{ {
SSL_ASSERT3(ctx); SSL_ASSERT3(ctx);
if (verify_callback) {
SSL_ASSERT3(ESP_OPENSSL_VERIFYCB_IS_SUPPORTED);
}
ctx->verify_mode = mode; ctx->verify_mode = mode;
ctx->default_verify_callback = verify_callback; ctx->default_verify_callback = verify_callback;
@@ -1567,11 +1611,34 @@ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509
void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *))
{ {
SSL_ASSERT3(ssl); SSL_ASSERT3(ssl);
if (verify_callback) {
SSL_ASSERT3(ESP_OPENSSL_VERIFYCB_IS_SUPPORTED);
}
ssl->verify_mode = mode; ssl->verify_mode = mode;
ssl->verify_callback = verify_callback; ssl->verify_callback = verify_callback;
} }
/**
* @brief get the SSL verify callback from the context
*/
openssl_verify_callback SSL_CTX_get_verify_callback(const SSL_CTX *ctx)
{
SSL_ASSERT2(ctx);
return ctx->default_verify_callback;
}
/**
* @brief get the SSL verify callback from ssl pointer
*/
openssl_verify_callback SSL_get_verify_callback(const SSL *ssl)
{
SSL_ASSERT2(ssl);
return ssl->verify_callback;
}
/** /**
* @brief set the ALPN protocols in the preferred order. SSL APIs require the * @brief set the ALPN protocols in the preferred order. SSL APIs require the
* protocols in a <length><value><length2><value2> format. mbedtls doesn't need * protocols in a <length><value><length2><value2> format. mbedtls doesn't need
@@ -1607,3 +1674,11 @@ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, unsigned
return 0; return 0;
} }
/**
* @brief Set the mode, but might assert if the related mode is not supported once session starts
*/
uint32_t SSL_set_mode(SSL *ssl, uint32_t mode)
{
ssl->mode |= mode;
return ssl->mode;
}

View File

@@ -49,7 +49,7 @@ IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 1, TLS_method_func, TLSv1_1_server_method);
IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 1, TLS_method_func, TLSv1_2_server_method); IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 1, TLS_method_func, TLSv1_2_server_method);
IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_server_method); IMPLEMENT_TLS_METHOD(TLS1_VERSION, 1, TLS_method_func, TLSv1_server_method);
IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method);
@@ -58,11 +58,11 @@ IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method);
*/ */
IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, -1, TLS_method_func, TLS_method); IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, -1, TLS_method_func, TLS_method);
IMPLEMENT_SSL_METHOD(TLS1_2_VERSION, -1, TLS_method_func, TLSv1_2_method); IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, -1, TLS_method_func, TLSv1_2_method);
IMPLEMENT_SSL_METHOD(TLS1_1_VERSION, -1, TLS_method_func, TLSv1_1_method); IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, -1, TLS_method_func, TLSv1_1_method);
IMPLEMENT_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method); IMPLEMENT_TLS_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method);
IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method);
@@ -79,3 +79,33 @@ IMPLEMENT_X509_METHOD(X509_method,
IMPLEMENT_PKEY_METHOD(EVP_PKEY_method, IMPLEMENT_PKEY_METHOD(EVP_PKEY_method,
pkey_pm_new, pkey_pm_free, pkey_pm_new, pkey_pm_free,
pkey_pm_load); pkey_pm_load);
/**
* @brief Generic SSL/TLS methods
*/
const SSL_METHOD *SSLv23_method(void)
{
return TLS_method();
}
const SSL_METHOD *SSLv23_server_method(void)
{
return TLS_server_method();
}
const SSL_METHOD *SSLv23_client_method(void)
{
return TLS_client_method();
}
int SSL_CTX_set_min_proto_version(SSL_CTX *ctx, int version)
{
ctx->min_version = version;
return 1;
}
int SSL_CTX_set_max_proto_version(SSL_CTX *ctx, int version)
{
ctx->max_version = version;
return 1;
}

View File

@@ -16,6 +16,7 @@
#include "ssl_methods.h" #include "ssl_methods.h"
#include "ssl_dbg.h" #include "ssl_dbg.h"
#include "ssl_port.h" #include "ssl_port.h"
#include "openssl/bio.h"
/** /**
* @brief create a private key object according to input private key * @brief create a private key object according to input private key
@@ -31,6 +32,8 @@ EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk)
goto no_mem; goto no_mem;
} }
pkey->ref_counter = 1;
if (ipk) { if (ipk) {
pkey->method = ipk->method; pkey->method = ipk->method;
} else { } else {
@@ -66,6 +69,10 @@ void EVP_PKEY_free(EVP_PKEY *pkey)
{ {
SSL_ASSERT3(pkey); SSL_ASSERT3(pkey);
if (--pkey->ref_counter > 0) {
return;
}
EVP_PKEY_METHOD_CALL(free, pkey); EVP_PKEY_METHOD_CALL(free, pkey);
ssl_mem_free(pkey); ssl_mem_free(pkey);
@@ -118,6 +125,60 @@ failed1:
return NULL; return NULL;
} }
EVP_PKEY *d2i_PrivateKey_bio(BIO *bp, EVP_PKEY **a)
{
return d2i_PrivateKey(0, a, (const unsigned char **)&bp->data, bp->dlen);
}
RSA *d2i_RSAPrivateKey_bio(BIO *bp,RSA **a)
{
return d2i_PrivateKey_bio(bp, (EVP_PKEY**)a);
}
RSA *PEM_read_bio_RSAPrivateKey(BIO *bp, RSA **x, pem_password_cb *cb, void *u)
{
return PEM_read_bio_PrivateKey(bp, (EVP_PKEY**)x, cb, u);
}
EVP_PKEY *PEM_read_bio_PrivateKey(BIO *bp, EVP_PKEY **pk, pem_password_cb *cb, void *u)
{
int m = 0;
int ret;
EVP_PKEY *x;
SSL_ASSERT2(BIO_method_type(bp) & BIO_TYPE_MEM);
if (bp->data == NULL || bp->dlen == 0) {
return NULL;
}
if (pk && *pk) {
x = *pk;
} else {
x = EVP_PKEY_new();
if (!x) {
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_new() return NULL");
goto failed;
}
m = 1;
}
ret = EVP_PKEY_METHOD_CALL(load, x, bp->data, bp->dlen);
if (ret) {
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "EVP_PKEY_METHOD_CALL(load) return %d", ret);
goto failed;
}
// If buffer successfully created a EVP_PKEY from the bio, mark the buffer as consumed
bp->data = NULL;
bp->dlen = 0;
return x;
failed:
if (m) {
EVP_PKEY_free(x);
}
return NULL;}
/** /**
* @brief set the SSL context private key * @brief set the SSL context private key
*/ */
@@ -132,6 +193,7 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey)
if (ctx->cert->pkey) if (ctx->cert->pkey)
EVP_PKEY_free(ctx->cert->pkey); EVP_PKEY_free(ctx->cert->pkey);
pkey->ref_counter++;
ctx->cert->pkey = pkey; ctx->cert->pkey = pkey;
return 1; return 1;
@@ -214,12 +276,15 @@ failed1:
return 0; return 0;
} }
#define ESP_OPENSSL_FILES_IS_SUPPORTED 0
/** /**
* @brief load the private key file into SSL context * @brief load the private key file into SSL context
*/ */
int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
{ {
return 0; // Using file name as private key is discouraged
SSL_ASSERT1(ESP_OPENSSL_FILES_IS_SUPPORTED);
return -1;
} }
/** /**
@@ -227,7 +292,9 @@ int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
*/ */
int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type)
{ {
return 0; // Using file name as private key is discouraged
SSL_ASSERT1(ESP_OPENSSL_FILES_IS_SUPPORTED);
return -1;
} }
/** /**
@@ -237,3 +304,8 @@ int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long le
{ {
return SSL_CTX_use_PrivateKey_ASN1(0, ctx, d, len); return SSL_CTX_use_PrivateKey_ASN1(0, ctx, d, len);
} }
void RSA_free (RSA *r)
{
EVP_PKEY_free(r);
}

View File

@@ -25,6 +25,29 @@
/** /**
* @brief create a openssl stack object * @brief create a openssl stack object
*/ */
typedef struct stack_st_tag {
size_t num;
void **data;
} _STACK;
GENERAL_NAME *sk_GENERAL_NAME_value(const struct stack_st_GENERAL_NAME *sk, size_t i)
{
if (!sk || i >= ((_STACK*)sk)->num) {
return NULL;
}
return ((_STACK*)sk)->data[i];
}
size_t sk_GENERAL_NAME_num(const struct stack_st_GENERAL_NAME *sk)
{
if (sk == NULL) {
return 0;
}
return ((_STACK*)sk)->num;
}
OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c)
{ {
OPENSSL_STACK *stack; OPENSSL_STACK *stack;

View File

@@ -42,7 +42,7 @@ X509* __X509_new(X509 *ix)
x->ref_counter = 1; x->ref_counter = 1;
if (ix) if (ix && ix->method)
x->method = ix->method; x->method = ix->method;
else else
x->method = X509_method(); x->method = X509_method();
@@ -205,6 +205,7 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x)
X509_free(ctx->cert->x509); X509_free(ctx->cert->x509);
ctx->cert->x509 = x; ctx->cert->x509 = x;
x->ref_counter++;
return 1; return 1;
} }
@@ -227,6 +228,11 @@ int SSL_use_certificate(SSL *ssl, X509 *x)
return 1; return 1;
} }
long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *x)
{
return SSL_CTX_use_certificate(ctx, x);
}
/** /**
* @brief get the SSL certification point * @brief get the SSL certification point
*/ */
@@ -252,12 +258,13 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len,
goto failed1; goto failed1;
} }
ret = SSL_CTX_use_certificate(ctx, x); ret = SSL_CTX_use_certificate(ctx, x); // This uses the "x" so increments ref_count
if (!ret) { if (!ret) {
SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_certificate() return %d", ret); SSL_DEBUG(SSL_PKEY_ERROR_LEVEL, "SSL_CTX_use_certificate() return %d", ret);
goto failed2; goto failed2;
} }
X509_free(x); // decrements ref_count, so in case of happy flow doesn't free the "x"
return 1; return 1;
failed2: failed2:
@@ -344,41 +351,21 @@ int X509_STORE_add_cert(X509_STORE *store, X509 *x) {
return 1; return 1;
} }
/**
* @brief create a BIO object
*/
BIO *BIO_new(void *method) {
BIO *b = (BIO *)malloc(sizeof(BIO));
return b;
}
/**
* @brief load data into BIO.
*
* Normally BIO_write should append data but doesn't happen here, and
* 'data' cannot be freed after the function is called, it should remain valid
* until BIO object is in use.
*/
int BIO_write(BIO *b, const void * data, int dlen) {
b->data = data;
b->dlen = dlen;
return 1;
}
/** /**
* @brief load a character certification context into system context. * @brief load a character certification context into system context.
* *
* If '*cert' is pointed to the certification, then load certification * If '*cert' is pointed to the certification, then load certification
* into it, or create a new X509 certification object. * into it, or create a new X509 certification object.
*/ */
X509 * PEM_read_bio_X509(BIO *bp, X509 **cert, void *cb, void *u) { X509 * PEM_read_bio_X509(BIO *bp, X509 **cert, pem_password_cb cb, void *u) {
int m = 0; int m = 0;
int ret; int ret;
X509 *x; X509 *x;
SSL_ASSERT2(bp->data); SSL_ASSERT2(BIO_method_type(bp) & BIO_TYPE_MEM);
SSL_ASSERT2(bp->dlen); if (bp->data == NULL || bp->dlen == 0) {
return NULL;
}
if (cert && *cert) { if (cert && *cert) {
x = *cert; x = *cert;
} else { } else {
@@ -396,6 +383,9 @@ X509 * PEM_read_bio_X509(BIO *bp, X509 **cert, void *cb, void *u) {
goto failed; goto failed;
} }
// If buffer successfully created a X509 from the bio, mark the buffer as consumed
bp->data = NULL;
bp->dlen = 0;
return x; return x;
failed: failed:
@@ -406,11 +396,9 @@ failed:
return NULL; return NULL;
} }
/** X509 *PEM_read_bio_X509_AUX(BIO *bp, X509 **cert, pem_password_cb *cb, void *u)
* @brief get the memory BIO method function {
*/ return PEM_read_bio_X509(bp, cert, cb, u);
void *BIO_s_mem(void) {
return NULL;
} }
/** /**
@@ -419,10 +407,3 @@ void *BIO_s_mem(void) {
X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) { X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx) {
return (X509_STORE *)ctx; return (X509_STORE *)ctx;
} }
/**
* @brief free a BIO object
*/
void BIO_free(BIO *b) {
free(b);
}

View File

@@ -24,6 +24,8 @@
#include "mbedtls/ctr_drbg.h" #include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h" #include "mbedtls/error.h"
#include "mbedtls/certs.h" #include "mbedtls/certs.h"
#include "openssl/bio.h"
#include "openssl/err.h"
#define X509_INFO_STRING_LENGTH 8192 #define X509_INFO_STRING_LENGTH 8192
@@ -87,6 +89,39 @@ static void ssl_platform_debug(void *ctx, int level,
} }
#endif #endif
static int mbedtls_bio_send(void *ctx, const unsigned char *buf, size_t len )
{
BIO *bio = ctx;
int written = BIO_write(bio, buf, len);
if (written <= 0 && BIO_should_write(bio)) {
return MBEDTLS_ERR_SSL_WANT_WRITE;
}
return written;
}
static int mbedtls_bio_recv(void *ctx, unsigned char *buf, size_t len )
{
BIO *bio = ctx;
int read = BIO_read(bio, buf, len);
if (read <= 0 && BIO_should_read(bio)) {
return MBEDTLS_ERR_SSL_WANT_READ;
}
return read;
}
static int ssl_pm_reload_crt(SSL *ssl);
static int get_mbedtls_minor_ssl_version(int openssl_version_nr)
{
if (TLS1_2_VERSION == openssl_version_nr)
return MBEDTLS_SSL_MINOR_VERSION_3;
if (TLS1_1_VERSION ==openssl_version_nr)
return MBEDTLS_SSL_MINOR_VERSION_2;
if (TLS1_VERSION == openssl_version_nr)
return MBEDTLS_SSL_MINOR_VERSION_1;
// SSLv3.0 otherwise
return MBEDTLS_SSL_MINOR_VERSION_0;
}
/** /**
* @brief create SSL low-level object * @brief create SSL low-level object
*/ */
@@ -99,13 +134,13 @@ int ssl_pm_new(SSL *ssl)
size_t pers_len = sizeof(pers); size_t pers_len = sizeof(pers);
int endpoint; int endpoint;
int version;
const SSL_METHOD *method = ssl->method; const SSL_METHOD *method = ssl->method;
ssl_pm = ssl_mem_zalloc(sizeof(struct ssl_pm)); ssl_pm = ssl_mem_zalloc(sizeof(struct ssl_pm));
if (!ssl_pm) { if (!ssl_pm) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (ssl_pm)"); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (ssl_pm)");
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_MALLOC_FAILURE);
goto no_mem; goto no_mem;
} }
@@ -122,6 +157,7 @@ int ssl_pm_new(SSL *ssl)
ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len); ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len);
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ctr_drbg_seed() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ctr_drbg_seed() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_RAND, ret);
goto mbedtls_err1; goto mbedtls_err1;
} }
@@ -133,21 +169,16 @@ int ssl_pm_new(SSL *ssl)
ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_config_defaults() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_config_defaults() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_CONF, ret);
goto mbedtls_err2; goto mbedtls_err2;
} }
if (TLS_ANY_VERSION != ssl->version) { if (TLS_ANY_VERSION != ssl->version) {
if (TLS1_2_VERSION == ssl->version) int min_version = ssl->ctx->min_version ? ssl->ctx->min_version : ssl->version;
version = MBEDTLS_SSL_MINOR_VERSION_3; int max_version = ssl->ctx->max_version ? ssl->ctx->max_version : ssl->version;
else if (TLS1_1_VERSION == ssl->version)
version = MBEDTLS_SSL_MINOR_VERSION_2;
else if (TLS1_VERSION == ssl->version)
version = MBEDTLS_SSL_MINOR_VERSION_1;
else
version = MBEDTLS_SSL_MINOR_VERSION_0;
mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version); mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, get_mbedtls_minor_ssl_version(max_version));
mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version); mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, get_mbedtls_minor_ssl_version(min_version));
} else { } else {
mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3); mbedtls_ssl_conf_max_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_3);
mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0); mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, MBEDTLS_SSL_MINOR_VERSION_0);
@@ -158,6 +189,7 @@ int ssl_pm_new(SSL *ssl)
mbedtls_ssl_conf_alpn_protocols( &ssl_pm->conf, ssl->ctx->ssl_alpn.alpn_list ); mbedtls_ssl_conf_alpn_protocols( &ssl_pm->conf, ssl->ctx->ssl_alpn.alpn_list );
#else #else
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "CONFIG_MBEDTLS_SSL_ALPN must be enabled to use ALPN", -1); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "CONFIG_MBEDTLS_SSL_ALPN must be enabled to use ALPN", -1);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_FATAL);
#endif // MBEDTLS_SSL_ALPN #endif // MBEDTLS_SSL_ALPN
} }
mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg);
@@ -172,12 +204,16 @@ int ssl_pm_new(SSL *ssl)
ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf);
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_setup() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_setup() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_CONF, ret);
goto mbedtls_err2; goto mbedtls_err2;
} }
mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL);
ssl->ssl_pm = ssl_pm; ssl->ssl_pm = ssl_pm;
ret = ssl_pm_reload_crt(ssl);
if (ret)
return 0;
return 0; return 0;
@@ -213,21 +249,36 @@ void ssl_pm_free(SSL *ssl)
static int ssl_pm_reload_crt(SSL *ssl) static int ssl_pm_reload_crt(SSL *ssl)
{ {
int ret; int ret;
int mode; int mode = MBEDTLS_SSL_VERIFY_UNSET;
struct ssl_pm *ssl_pm = ssl->ssl_pm; struct ssl_pm *ssl_pm = ssl->ssl_pm;
struct x509_pm *ca_pm = (struct x509_pm *)ssl->client_CA->x509_pm; struct x509_pm *ca_pm = (struct x509_pm *)ssl->client_CA->x509_pm;
struct pkey_pm *pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; struct pkey_pm *pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm;
struct x509_pm *crt_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; struct x509_pm *crt_pm = (struct x509_pm *)ssl->cert->x509->x509_pm;
if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT) /* OpenSSL verification modes outline (see `man SSL_set_verify` for more details)
mode = MBEDTLS_SSL_VERIFY_REQUIRED; *
else if (ssl->verify_mode & SSL_VERIFY_PEER) * | openssl mode | Server | Client |
mode = MBEDTLS_SSL_VERIFY_OPTIONAL; * | SSL_VERIFY_NONE | will not send a client certificate request | server certificate which will be checked |
else if (ssl->verify_mode & SSL_VERIFY_CLIENT_ONCE) * handshake will be continued regardless |
mode = MBEDTLS_SSL_VERIFY_UNSET; * | SSL_VERIFY_PEER | depends on SSL_VERIFY_FAIL_IF_NO_PEER_CERT | handshake is terminated if verify fails |
else * (unless anonymous ciphers--not supported |
mode = MBEDTLS_SSL_VERIFY_NONE; * | SSL_VERIFY_FAIL_IF_NO_PEER_CERT | handshake is terminated if | ignored |
* client cert verify fails | |
*/
if (ssl->method->endpoint == MBEDTLS_SSL_IS_SERVER) {
if (ssl->verify_mode & SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
else if (ssl->verify_mode & SSL_VERIFY_PEER)
mode = MBEDTLS_SSL_VERIFY_OPTIONAL;
else if (ssl->verify_mode == SSL_VERIFY_NONE)
mode = MBEDTLS_SSL_VERIFY_NONE;
} else if (ssl->method->endpoint == MBEDTLS_SSL_IS_CLIENT) {
if (ssl->verify_mode & SSL_VERIFY_PEER)
mode = MBEDTLS_SSL_VERIFY_REQUIRED;
else if (ssl->verify_mode == SSL_VERIFY_NONE)
mode = MBEDTLS_SSL_VERIFY_NONE;
}
mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode);
@@ -247,6 +298,7 @@ static int ssl_pm_reload_crt(SSL *ssl)
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_conf_own_cert() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_conf_own_cert() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_X509, ret);
ret = -1; ret = -1;
} }
@@ -278,6 +330,15 @@ int ssl_pm_handshake(SSL *ssl)
int ret; int ret;
struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm;
if (ssl->bio) {
// if using BIO, make sure the mode is supported
SSL_ASSERT1(ssl->mode & (SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER));
mbedtls_ssl_set_bio(&ssl_pm->ssl, ssl->bio, mbedtls_bio_send, mbedtls_bio_recv, NULL);
} else {
// defaults to SSL_read/write using a file descriptor -- expects default mode
SSL_ASSERT1(ssl->mode == 0);
}
ret = ssl_pm_reload_crt(ssl); ret = ssl_pm_reload_crt(ssl);
if (ret) if (ret)
return 0; return 0;
@@ -286,14 +347,24 @@ int ssl_pm_handshake(SSL *ssl)
while((ret = mbedtls_handshake(&ssl_pm->ssl)) != 0) { while((ret = mbedtls_handshake(&ssl_pm->ssl)) != 0) {
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
// exit handshake in case of any other error
break; break;
} else if (ssl->bio) {
// exit even if wanted read/write if BIO used
if (ret == MBEDTLS_ERR_SSL_WANT_READ) {
ssl->rwstate = SSL_READING;
} else if (ret == MBEDTLS_ERR_SSL_WANT_WRITE) {
ssl->rwstate = SSL_WRITING;
}
return ret;
} }
} }
ssl_speed_up_exit(); ssl_speed_up_exit();
ssl->rwstate = SSL_NOTHING;
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_handshake() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_handshake() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SSL, ret);
ret = 0; ret = 0;
} else { } else {
struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm;
@@ -313,6 +384,7 @@ int ssl_pm_shutdown(SSL *ssl)
ret = mbedtls_ssl_close_notify(&ssl_pm->ssl); ret = mbedtls_ssl_close_notify(&ssl_pm->ssl);
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_close_notify() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_close_notify() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SSL, ret);
ret = -1; ret = -1;
} else { } else {
struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm;
@@ -337,6 +409,7 @@ int ssl_pm_read(SSL *ssl, void *buffer, int len)
ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len); ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len);
if (ret < 0) { if (ret < 0) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_read() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_read() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SSL, ret);
ret = -1; ret = -1;
} }
@@ -351,6 +424,7 @@ int ssl_pm_send(SSL *ssl, const void *buffer, int len)
ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len); ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len);
if (ret < 0) { if (ret < 0) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_write() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_write() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SSL, ret);
ret = -1; ret = -1;
} }
@@ -463,12 +537,14 @@ int x509_pm_show_info(X509 *x)
buf = ssl_mem_malloc(X509_INFO_STRING_LENGTH); buf = ssl_mem_malloc(X509_INFO_STRING_LENGTH);
if (!buf) { if (!buf) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (buf)"); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (buf)");
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_MALLOC_FAILURE);
goto no_mem; goto no_mem;
} }
ret = mbedtls_x509_crt_info(buf, X509_INFO_STRING_LENGTH - 1, "", x509_crt); ret = mbedtls_x509_crt_info(buf, X509_INFO_STRING_LENGTH - 1, "", x509_crt);
if (ret <= 0) { if (ret <= 0) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_info() return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_info() return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_X509, ret);
goto mbedtls_err1; goto mbedtls_err1;
} }
@@ -493,6 +569,7 @@ int x509_pm_new(X509 *x, X509 *m_x)
x509_pm = ssl_mem_zalloc(sizeof(struct x509_pm)); x509_pm = ssl_mem_zalloc(sizeof(struct x509_pm));
if (!x509_pm) { if (!x509_pm) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm)"); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm)");
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_MALLOC_FAILURE);
goto failed1; goto failed1;
} }
@@ -538,6 +615,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len)
x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt)); x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt));
if (!x509_pm->x509_crt) { if (!x509_pm->x509_crt) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm->x509_crt)"); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (x509_pm->x509_crt)");
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_MALLOC_FAILURE);
goto no_mem; goto no_mem;
} }
} }
@@ -545,6 +623,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len)
load_buf = ssl_mem_malloc(len + 1); load_buf = ssl_mem_malloc(len + 1);
if (!load_buf) { if (!load_buf) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)"); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)");
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_MALLOC_FAILURE);
goto failed; goto failed;
} }
@@ -558,6 +637,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len)
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_parse return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_x509_crt_parse return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_X509, ret);
goto failed; goto failed;
} }
@@ -618,6 +698,7 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len)
pkey_pm->pkey = ssl_mem_malloc(sizeof(mbedtls_pk_context)); pkey_pm->pkey = ssl_mem_malloc(sizeof(mbedtls_pk_context));
if (!pkey_pm->pkey) { if (!pkey_pm->pkey) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (pkey_pm->pkey)"); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (pkey_pm->pkey)");
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_MALLOC_FAILURE);
goto no_mem; goto no_mem;
} }
} }
@@ -625,6 +706,7 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len)
load_buf = ssl_mem_malloc(len + 1); load_buf = ssl_mem_malloc(len + 1);
if (!load_buf) { if (!load_buf) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)"); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "no enough memory > (load_buf)");
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SYS, ERR_R_MALLOC_FAILURE);
goto failed; goto failed;
} }
@@ -638,6 +720,7 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len)
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_pk_parse_key return -0x%x", -ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_pk_parse_key return -0x%x", -ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_PKCS8, ret);
goto failed; goto failed;
} }
@@ -667,6 +750,7 @@ long ssl_pm_get_verify_result(const SSL *ssl)
ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl); ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl);
if (ret) { if (ret) {
SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_get_verify_result() return 0x%x", ret); SSL_DEBUG(SSL_PLATFORM_ERROR_LEVEL, "mbedtls_ssl_get_verify_result() return 0x%x", ret);
OPENSSL_PUT_LIB_ERROR(ERR_LIB_SSL, ret);
verify_result = X509_V_ERR_UNSPECIFIED; verify_result = X509_V_ERR_UNSPECIFIED;
} else } else
verify_result = X509_V_OK; verify_result = X509_V_OK;

View File

@@ -0,0 +1,2 @@
idf_component_register(SRC_DIRS "."
PRIV_REQUIRES unity test_utils openssl)

View File

@@ -0,0 +1,4 @@
#
#Component Makefile
#
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive

View File

@@ -0,0 +1,152 @@
/* Copyright (c) 2014, Google Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
#include "test_utils.h"
#include "openssl/ssl.h"
#include "unity.h"
/**
* @brief This simple test suite is taken from OpenSSL err_test.cc and bio_test.cc, the relevant test
* cases were adopted to the supported fraction of OpenSSL port in esp-idf
*/
//
// Basic error stack support and test
//
#define ERR_NUM_ERRORS 4
TEST_CASE("ErrTest, Overflow", "[openssl]")
{
for (unsigned i = 0; i < ERR_NUM_ERRORS*2; i++) {
ERR_put_error(1, 0 /* unused */, i+1, "test", 1);
}
for (unsigned i = 0; i < ERR_NUM_ERRORS - 1; i++) {
uint32_t err = ERR_get_error();
/* Errors are returned in order they were pushed, with the least recent ones
* removed, up to |ERR_NUM_ERRORS - 1| errors. So the errors returned are
* |ERR_NUM_ERRORS + 2| through |ERR_NUM_ERRORS * 2|, inclusive. */
TEST_ASSERT_NOT_EQUAL(0u, err);
TEST_ASSERT_EQUAL(i + ERR_NUM_ERRORS + 2, ERR_GET_REASON(err));
}
TEST_ASSERT_EQUAL(0u, ERR_get_error());
}
TEST_CASE("ErrTest, PutError", "[openssl]")
{
TEST_ASSERT_EQUAL(0u, ERR_get_error()); // ERR_get_error returned value before an error was added.
ERR_put_error(1, 0 /* unused */, 2, "test", 4);
int peeked_line, line, peeked_flags, flags;
const char *peeked_file, *file, *peeked_data, *data;
uint32_t peeked_packed_error =
ERR_peek_error_line_data(&peeked_file, &peeked_line, &peeked_data,
&peeked_flags);
uint32_t packed_error = ERR_get_error_line_data(&file, &line, &data, &flags);
TEST_ASSERT_EQUAL(peeked_packed_error, packed_error);
TEST_ASSERT_EQUAL(peeked_file, file);
TEST_ASSERT_EQUAL_STRING("test", file);
TEST_ASSERT_EQUAL(4, line);
TEST_ASSERT_EQUAL(1, ERR_GET_LIB(packed_error));
TEST_ASSERT_EQUAL(2, ERR_GET_REASON(packed_error));
}
TEST_CASE("ErrTest, ClearError", "[openssl]")
{
TEST_ASSERT_EQUAL(0u, ERR_get_error()); // ERR_get_error returned value before an error was added.
ERR_put_error(1, 0 /* unused */, 2, "test", 4);
ERR_clear_error();
// The error queue should be cleared.
TEST_ASSERT_EQUAL(0u, ERR_get_error());
}
//
// Simplified BIO support and check
//
TEST_CASE("BioTest, TestPair", "[openssl]")
{
BIO *bio1, *bio2;
TEST_ASSERT_NOT_EQUAL(0, BIO_new_bio_pair(&bio1, 10, &bio2, 10));
TEST_ASSERT_EQUAL(BIO_ctrl_get_write_guarantee(bio1), 10);
// Data written in one end may be read out the other.
char buf[20];
TEST_ASSERT_EQUAL(5, BIO_write(bio1, "12345", 5));
TEST_ASSERT_EQUAL(5, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(5, BIO_read(bio2, buf, sizeof(buf)));
TEST_ASSERT_EQUAL_UINT8_ARRAY("12345", buf, 5);
TEST_ASSERT_EQUAL(10, BIO_ctrl_get_write_guarantee(bio1));
// Attempting to write more than 10 bytes will write partially.
TEST_ASSERT_EQUAL(10, BIO_write(bio1, "1234567890___", 13));
TEST_ASSERT_EQUAL(0, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(-1, BIO_write(bio1, "z", 1));
TEST_ASSERT_TRUE(BIO_should_write(bio1));
TEST_ASSERT_EQUAL(10, BIO_read(bio2, buf, sizeof(buf)));
TEST_ASSERT_EQUAL_UINT8_ARRAY("1234567890", buf, 10);
TEST_ASSERT_EQUAL(10, BIO_ctrl_get_write_guarantee(bio1));
// Unsuccessful reads update the read request.
TEST_ASSERT_EQUAL(-1, BIO_read(bio2, buf, 5));
TEST_ASSERT_TRUE(BIO_should_read(bio2));
// The read request is clamped to the size of the buffer.
TEST_ASSERT_EQUAL(-1, BIO_read(bio2, buf, 20));
TEST_ASSERT_TRUE(BIO_should_read(bio2));
// Data may be written and read in chunks.
TEST_ASSERT_EQUAL(BIO_write(bio1, "12345", 5), 5);
TEST_ASSERT_EQUAL(5, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(5, BIO_write(bio1, "67890___", 8));
TEST_ASSERT_EQUAL(0, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(3, BIO_read(bio2, buf, 3));
TEST_ASSERT_EQUAL_UINT8_ARRAY("123", buf, 3);
TEST_ASSERT_EQUAL(3, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(7, BIO_read(bio2, buf, sizeof(buf)));
TEST_ASSERT_EQUAL_UINT8_ARRAY("4567890", buf, 7);
TEST_ASSERT_EQUAL(10, BIO_ctrl_get_write_guarantee(bio1));
// Test writes and reads starting in the middle of the ring buffer and
// wrapping to front.
TEST_ASSERT_EQUAL(8, BIO_write(bio1, "abcdefgh", 8));
TEST_ASSERT_EQUAL(2, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(3, BIO_read(bio2, buf, 3));
TEST_ASSERT_EQUAL_UINT8_ARRAY("abc", buf, 3);
TEST_ASSERT_EQUAL(5, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(5, BIO_write(bio1, "ijklm___", 8));
TEST_ASSERT_EQUAL(0, BIO_ctrl_get_write_guarantee(bio1));
TEST_ASSERT_EQUAL(10, BIO_read(bio2, buf, sizeof(buf)));
TEST_ASSERT_EQUAL_UINT8_ARRAY("defghijklm", buf, 10);
TEST_ASSERT_EQUAL(10, BIO_ctrl_get_write_guarantee(bio1));
// Data may flow from both ends in parallel.
TEST_ASSERT_EQUAL(5, BIO_write(bio1, "12345", 5));
TEST_ASSERT_EQUAL(5, BIO_write(bio2, "67890", 5));
TEST_ASSERT_EQUAL(5, BIO_read(bio2, buf, sizeof(buf)));
TEST_ASSERT_EQUAL_UINT8_ARRAY("12345", buf, 5);
TEST_ASSERT_EQUAL(5, BIO_read(bio1, buf, sizeof(buf)));
TEST_ASSERT_EQUAL_UINT8_ARRAY("67890", buf, 5);
// Other tests below not imported since BIO_shutdown_wr() not supported
// - Closing the write end causes an EOF on the read half, after draining.
// - A closed write end may not be written to.
// - The other end is still functional.
}

View File

@@ -13,7 +13,18 @@ Asio also comes with a number of examples which could be find under Documentatio
Supported features Supported features
^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
ESP platform port currently supports only network asynchronous socket operations; does not support serial port and ssl. ESP platform port currently supports only network asynchronous socket operations; does not support serial port.
SSL/TLS support is disabled by default and could be enabled in component configuration menu by choosing TLS library from
- mbedTLS with OpenSSL translation layer (default option)
- wolfSSL
SSL support is very basic at this stage and it does include following features:
- Verification callbacks
- DH property files
- Certificates/private keys file APIs
Internal asio settings for ESP include Internal asio settings for ESP include
- EXCEPTIONS are enabled in ASIO if enabled in menuconfig - EXCEPTIONS are enabled in ASIO if enabled in menuconfig
@@ -27,5 +38,6 @@ ESP examples are based on standard asio :example:`protocols/asio`:
- :example:`protocols/asio/tcp_echo_server` - :example:`protocols/asio/tcp_echo_server`
- :example:`protocols/asio/chat_client` - :example:`protocols/asio/chat_client`
- :example:`protocols/asio/chat_server` - :example:`protocols/asio/chat_server`
- :example:`protocols/asio/ssl_client_server`
Please refer to the specific example README.md for details Please refer to the specific example README.md for details

View File

@@ -177,6 +177,7 @@ menu "Example Connection Configuration"
config EXAMPLE_CONNECT_IPV6 config EXAMPLE_CONNECT_IPV6
bool "Obtain IPv6 address" bool "Obtain IPv6 address"
default y default y
depends on EXAMPLE_CONNECT_WIFI || EXAMPLE_CONNECT_ETHERNET
help help
By default, examples will wait until IPv4 and IPv6 local link addresses are obtained. By default, examples will wait until IPv4 and IPv6 local link addresses are obtained.
Disable this option if the network does not support IPv6. Disable this option if the network does not support IPv6.

View File

@@ -43,9 +43,10 @@
#define NR_OF_IP_ADDRESSES_TO_WAIT_FOR (s_active_interfaces) #define NR_OF_IP_ADDRESSES_TO_WAIT_FOR (s_active_interfaces)
#endif #endif
#define EXAMPLE_DO_CONNECT CONFIG_EXAMPLE_CONNECT_WIFI || CONFIG_EXAMPLE_CONNECT_ETHERNET
static int s_active_interfaces = 0; static int s_active_interfaces = 0;
static xSemaphoreHandle s_semph_get_ip_addrs; static xSemaphoreHandle s_semph_get_ip_addrs;
static esp_ip4_addr_t s_ip_addr;
static esp_netif_t *s_example_esp_netif = NULL; static esp_netif_t *s_example_esp_netif = NULL;
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6 #ifdef CONFIG_EXAMPLE_CONNECT_IPV6
@@ -102,7 +103,11 @@ static void start(void)
s_example_esp_netif = NULL; s_example_esp_netif = NULL;
#endif #endif
#if EXAMPLE_DO_CONNECT
/* create semaphore if at least one interface is active */
s_semph_get_ip_addrs = xSemaphoreCreateCounting(NR_OF_IP_ADDRESSES_TO_WAIT_FOR, 0); s_semph_get_ip_addrs = xSemaphoreCreateCounting(NR_OF_IP_ADDRESSES_TO_WAIT_FOR, 0);
#endif
} }
/* tear down connection, release resources */ /* tear down connection, release resources */
@@ -119,6 +124,9 @@ static void stop(void)
#endif #endif
} }
#if EXAMPLE_DO_CONNECT
static esp_ip4_addr_t s_ip_addr;
static void on_got_ip(void *arg, esp_event_base_t event_base, static void on_got_ip(void *arg, esp_event_base_t event_base,
int32_t event_id, void *event_data) int32_t event_id, void *event_data)
{ {
@@ -131,6 +139,7 @@ static void on_got_ip(void *arg, esp_event_base_t event_base,
memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr)); memcpy(&s_ip_addr, &event->ip_info.ip, sizeof(s_ip_addr));
xSemaphoreGive(s_semph_get_ip_addrs); xSemaphoreGive(s_semph_get_ip_addrs);
} }
#endif
#ifdef CONFIG_EXAMPLE_CONNECT_IPV6 #ifdef CONFIG_EXAMPLE_CONNECT_IPV6
@@ -155,9 +164,11 @@ static void on_got_ipv6(void *arg, esp_event_base_t event_base,
esp_err_t example_connect(void) esp_err_t example_connect(void)
{ {
#if EXAMPLE_DO_CONNECT
if (s_semph_get_ip_addrs != NULL) { if (s_semph_get_ip_addrs != NULL) {
return ESP_ERR_INVALID_STATE; return ESP_ERR_INVALID_STATE;
} }
#endif
start(); start();
ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop)); ESP_ERROR_CHECK(esp_register_shutdown_handler(&stop));
ESP_LOGI(TAG, "Waiting for IP(s)"); ESP_LOGI(TAG, "Waiting for IP(s)");

View File

@@ -24,6 +24,11 @@ extern "C" {
#define EXAMPLE_INTERFACE get_example_netif() #define EXAMPLE_INTERFACE get_example_netif()
#endif #endif
#if !defined (CONFIG_EXAMPLE_CONNECT_ETHERNET) && !defined (CONFIG_EXAMPLE_CONNECT_WIFI)
// This is useful for some tests which do not need a network connection
#define EXAMPLE_INTERFACE NULL
#endif
/** /**
* @brief Configure Wi-Fi or Ethernet, connect, wait for IP * @brief Configure Wi-Fi or Ethernet, connect, wait for IP
* *

View File

@@ -0,0 +1,10 @@
# The following lines of boilerplate have to be in your project's CMakeLists
# in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
# (Not part of the boilerplate)
# This example uses an extra component for common functions such as Wi-Fi and Ethernet connection.
set(EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(asio_ssl_client_server)

View File

@@ -0,0 +1,9 @@
#
# This is a project Makefile. It is assumed the directory this Makefile resides in is a
# project subdirectory.
#
PROJECT_NAME := asio_ssl_client_server
EXTRA_COMPONENT_DIRS = $(IDF_PATH)/examples/common_components/protocol_examples_common
include $(IDF_PATH)/make/project.mk

View File

@@ -0,0 +1,85 @@
# Asio SSL client/server example
Simple Asio client and server with SSL/TLS transport
## How to Use Example
### Hardware Required
This example can be executed on any ESP platform board. No external connection is required, it is recommended though
to connect to internet or a local network via WiFi or Ethernet to easily exercise features of this example.
### Configure the project
* Open the project configuration menu (`idf.py menuconfig`)
* Configure Wi-Fi or Ethernet under "Example Connection Configuration" menu. See "Establishing Wi-Fi or Ethernet Connection" section in [examples/protocols/README.md](../../README.md) for more details.
* Enable the ASIO client and set server's host name to examine client's functionality.
The ASIO client connects to the configured server and sends default payload string "GET / HTTP/1.1"
* Enable the ASIO server to examine server's functionality. The ASIO server listens to connection and echos back what was received.
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py -p PORT flash monitor
```
(To exit the serial monitor, type ``Ctrl-]``.)
See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.
## Example Output
### Client connecting to public server
The below output illustrates the client connecting to a public https server.
```
I (1267) example_connect: Waiting for IP(s)
I (2587) wifi:new:<11,0>, old:<1,0>, ap:<255,255>, sta:<11,0>, prof:1
I (3367) wifi:state: init -> auth (b0)
I (3377) wifi:state: auth -> assoc (0)
I (3387) wifi:state: assoc -> run (10)
I (3397) wifi:security type: 3, phy: bgn, rssi: -49
I (3397) wifi:pm start, type: 1
I (3457) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (4747) example_connect: Got IPv6 event: Interface "example_connect: sta" address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
I (5247) esp_netif_handlers: example_connect: sta ip: 192.168.32.69, mask: 255.255.252.0, gw: 192.168.32.3
I (5247) example_connect: Got IPv4 event: Interface "example_connect: sta" address: 192.168.32.69
I (5257) example_connect: Connected to example_connect: sta
I (5257) example_connect: - IPv4 address: 192.168.32.69
I (5267) example_connect: - IPv6 address: fe80:0000:0000:0000:260a:xxxx:xxxx:xxxx, type: ESP_IP6_ADDR_IS_LINK_LOCAL
W (5277) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
W (5297) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
Reply: HTTP/1.1 200 OK
D
```
### Both server and client enabled
The below output demonstrates the client connecting to the ASIO server via loopback interface, so no WiFi, nor Ethernet connection
was established.
```
I (0) cpu_start: App cpu up.
I (495) heap_init: Initializing. RAM available for dynamic allocation:
I (502) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM
I (508) heap_init: At 3FFB5400 len 0002AC00 (171 KiB): DRAM
I (515) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM
I (521) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM
I (527) heap_init: At 4008BB80 len 00014480 (81 KiB): IRAM
I (534) cpu_start: Pro cpu start user code
I (556) spi_flash: detected chip: gd
I (556) spi_flash: flash io: dio
W (556) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.
I (566) cpu_start: Starting scheduler on PRO CPU.
I (0) cpu_start: Starting scheduler on APP CPU.
I (600) example_connect: Waiting for IP(s)
W (600) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
W (1610) esp32_asio_pthread: pthread_condattr_setclock: not yet supported!
Server received: GET / HTTP/1.1
Reply: GET / HTTP/1.1
```
See the README.md file in the upper level 'examples' directory for more information about examples.

View File

@@ -0,0 +1,15 @@
from __future__ import unicode_literals
import ttfw_idf
@ttfw_idf.idf_example_test(env_tag='Example_GENERIC')
def test_examples_asio_ssl(env, extra_data):
dut = env.get_dut('asio_ssl_client_server', 'examples/protocols/asio/ssl_client_server')
dut.start_app()
dut.expect('Reply: GET / HTTP/1.1')
if __name__ == '__main__':
test_examples_asio_ssl()

View File

@@ -0,0 +1,3 @@
idf_component_register(SRCS "asio_ssl_main.cpp"
INCLUDE_DIRS "."
EMBED_TXTFILES ca.crt server.key srv.crt)

View File

@@ -0,0 +1,36 @@
menu "Example Configuration"
config EXAMPLE_CLIENT
bool "Enable TLS client"
default y
help
Choose this option to use ASIO TLS/SSL client functionality
config EXAMPLE_PORT
string "ASIO port number"
default "443"
help
Port number used by ASIO example.
config EXAMPLE_SERVER
bool "Enable TLS server"
default n
help
Choose this option to use ASIO TLS/SSL server functionality
config EXAMPLE_SERVER_NAME
string "ASIO server name or IP"
default "www.google.com"
depends on EXAMPLE_CLIENT
help
Asio example server ip for the ASIO client to connect to.
config EXAMPLE_CLIENT_VERIFY_PEER
bool "Client to verify peer"
default n
depends on EXAMPLE_CLIENT
help
This option sets client's mode to verify peer, default is
verify-none
endmenu

View File

@@ -0,0 +1,272 @@
//
// Copyright (c) 2003-2019 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include <string>
#include "protocol_examples_common.h"
#include "esp_event.h"
#include "nvs_flash.h"
#include <cstdlib>
#include <iostream>
#include <chrono>
#include <thread>
#include "asio.hpp"
#include "asio/ssl.hpp"
#include "asio/buffer.hpp"
#include "esp_pthread.h"
extern const unsigned char server_pem_start[] asm("_binary_srv_crt_start");
extern const unsigned char server_pem_end[] asm("_binary_srv_crt_end");
extern const unsigned char cacert_pem_start[] asm("_binary_ca_crt_start");
extern const unsigned char cacert_pem_end[] asm("_binary_ca_crt_end");
extern const unsigned char prvtkey_pem_start[] asm("_binary_server_key_start");
extern const unsigned char prvtkey_pem_end[] asm("_binary_server_key_end");
static const asio::const_buffer cert_chain(cacert_pem_start, cacert_pem_end - cacert_pem_start);
static const asio::const_buffer privkey(prvtkey_pem_start, prvtkey_pem_end - prvtkey_pem_start);
static const asio::const_buffer server_cert(server_pem_start, server_pem_end - server_pem_start);
using asio::ip::tcp;
static const std::size_t max_length = 1024;
class Client {
public:
Client(asio::io_context &io_context,
asio::ssl::context &context,
const tcp::resolver::results_type &endpoints)
: socket_(io_context, context)
{
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
socket_.set_verify_mode(asio::ssl::verify_peer);
#else
socket_.set_verify_mode(asio::ssl::verify_none);
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
connect(endpoints);
}
private:
void connect(const tcp::resolver::results_type &endpoints)
{
asio::async_connect(socket_.lowest_layer(), endpoints,
[this](const std::error_code & error,
const tcp::endpoint & /*endpoint*/) {
if (!error) {
handshake();
} else {
std::cout << "Connect failed: " << error.message() << "\n";
}
});
}
void handshake()
{
socket_.async_handshake(asio::ssl::stream_base::client,
[this](const std::error_code & error) {
if (!error) {
send_request();
} else {
std::cout << "Handshake failed: " << error.message() << "\n";
}
});
}
void send_request()
{
size_t request_length = std::strlen(request_);
asio::async_write(socket_,
asio::buffer(request_, request_length),
[this](const std::error_code & error, std::size_t length) {
if (!error) {
receive_response(length);
} else {
std::cout << "Write failed: " << error.message() << "\n";
}
});
}
void receive_response(std::size_t length)
{
asio::async_read(socket_,
asio::buffer(reply_, length),
[this](const std::error_code & error, std::size_t length) {
if (!error) {
std::cout << "Reply: ";
std::cout.write(reply_, length);
std::cout << "\n";
} else {
std::cout << "Read failed: " << error.message() << "\n";
}
});
}
asio::ssl::stream<tcp::socket> socket_;
char request_[max_length] = "GET / HTTP/1.1\r\n\r\n";
char reply_[max_length];
};
class Session : public std::enable_shared_from_this<Session> {
public:
Session(tcp::socket socket, asio::ssl::context &context)
: socket_(std::move(socket), context)
{
}
void start()
{
do_handshake();
}
private:
void do_handshake()
{
auto self(shared_from_this());
socket_.async_handshake(asio::ssl::stream_base::server,
[this, self](const std::error_code & error) {
if (!error) {
do_read();
}
});
}
void do_read()
{
auto self(shared_from_this());
socket_.async_read_some(asio::buffer(data_),
[this, self](const std::error_code & ec, std::size_t length) {
if (!ec) {
std::cout << "Server received: ";
std::cout.write(data_, length);
std::cout << std::endl;
do_write(length);
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(socket_, asio::buffer(data_, length),
[this, self](const std::error_code & ec,
std::size_t /*length*/) {
if (!ec) {
do_read();
}
});
}
asio::ssl::stream<tcp::socket> socket_;
char data_[max_length];
};
class Server {
public:
Server(asio::io_context &io_context, unsigned short port)
: acceptor_(io_context, tcp::endpoint(tcp::v4(), port)),
context_(asio::ssl::context::tls_server)
{
context_.set_options(
asio::ssl::context::default_workarounds
| asio::ssl::context::no_sslv2);
context_.use_certificate_chain(server_cert);
context_.use_private_key(privkey, asio::ssl::context::pem);
do_accept();
}
private:
void do_accept()
{
acceptor_.async_accept(
[this](const std::error_code & error, tcp::socket socket) {
if (!error) {
std::make_shared<Session>(std::move(socket), context_)->start();
}
do_accept();
});
}
tcp::acceptor acceptor_;
asio::ssl::context context_;
};
void set_thread_config(const char *name, int stack, int prio)
{
auto cfg = esp_pthread_get_default_config();
cfg.thread_name = name;
cfg.stack_size = stack;
cfg.prio = prio;
esp_pthread_set_cfg(&cfg);
}
void ssl_server_thread()
{
asio::io_context io_context;
Server s(io_context, 443);
io_context.run();
}
void ssl_client_thread()
{
asio::io_context io_context;
tcp::resolver resolver(io_context);
std::string server_ip = CONFIG_EXAMPLE_SERVER_NAME;
std::string server_port = CONFIG_EXAMPLE_PORT;
auto endpoints = resolver.resolve(server_ip, server_port);
asio::ssl::context ctx(asio::ssl::context::tls_client);
#if CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
ctx.add_certificate_authority(cert_chain);
#endif // CONFIG_EXAMPLE_CLIENT_VERIFY_PEER
Client c(io_context, ctx, endpoints);
io_context.run();
}
extern "C" void app_main(void)
{
ESP_ERROR_CHECK(nvs_flash_init());
esp_netif_init();
ESP_ERROR_CHECK(esp_event_loop_create_default());
/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());
/* This helper function configures blocking UART I/O */
ESP_ERROR_CHECK(example_configure_stdin_stdout());
std::vector<std::thread> work_threads;
#if CONFIG_EXAMPLE_SERVER
set_thread_config("Server", 16 * 1024, 5);
work_threads.emplace_back(std::thread(ssl_server_thread));
std::this_thread::sleep_for(std::chrono::seconds(1));
#endif // CONFIG_EXAMPLE_SERVER
#if CONFIG_EXAMPLE_CLIENT
set_thread_config("Client", 16 * 1024, 5);
work_threads.emplace_back(ssl_client_thread);
#endif // CONFIG_EXAMPLE_CLIENT
for (auto &t : work_threads) {
t.join();
}
}

View File

@@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIUNI5wldYysh6rtCzYmda6H414aRswDQYJKoZIhvcNAQEL
BQAwWTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMB4X
DTIwMDEyMTA5MDk0NloXDTI1MDEyMDA5MDk0NlowWTELMAkGA1UEBhMCQVUxEzAR
BgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5
IEx0ZDESMBAGA1UEAwwJRXNwcmVzc2lmMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAyadSpRnIQBVbEAsbpkrKrOMlBOMIUmA8AfNyOYPLfv0Oa5lBiMAV
3OQDu5tYyFYKwkCUqq65iAm50fPbSH71w1tkja6nZ1yAIM+TvpMlM/WiFGrhY+Tc
kAcLcKUJyPxrv/glzoVslbqUgIhuhCSKA8uk1+ILcn3nWzPcbcowLx31+AHeZj8h
bIAdj6vjqxMCFStp4IcA+ikmCk75LCN4vkkifdkebb/ZDNYCZZhpCBnCHyFAjPc4
7C+FDVGT3/UUeeTy+Mtn+MqUAhB+W0sPDm1n2h59D4Z/MFm0hl6GQCAKeMJPzssU
BBsRm6zoyPQ4VTqG0uwfNNbORyIfKONMUwIDAQABo1MwUTAdBgNVHQ4EFgQUGYLV
EkgWzxjpltE6texha7zZVxowHwYDVR0jBBgwFoAUGYLVEkgWzxjpltE6texha7zZ
VxowDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAb2EF4Zg2XWNb
eZHnzupCDd9jAhwPqkt7F1OXvxJa/RFUSB9+2izGvikGGhuKY4f0iLuqF+bhExD9
sapDcdFO2Suh4J3onbwEvmKvsv56K3xhapYg8WwPofpkVirnkwFjpQXGzrYxPujg
BPmSy3psQrhvOr/WH7SefJv2qr4ikaugfE+3enY4PL+C1dSQAuNo1QGgWsZIu0c8
TZybNZ13vNVMA+tgj2CM8FR3Etaabwtu3TTcAnO7aoBTix/bLBTuZoczhN8/MhG3
GylmDzFI8a6aKxQL3Fi4PsM82hRKWu3gfs39sR1Ci4V22v8uO5EWBPK0QZvDSc1a
KwwxI4zA0w==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,12 @@
#
# Main component makefile.
#
# This Makefile can be left empty. By default, it will take the sources in the
# src/ directory, compile them and link them into lib(subdirectory_name).a
# in the build directory. This behaviour is entirely configurable,
# please read the ESP-IDF documents if you need to do this.
#
COMPONENT_EMBED_TXTFILES := ca.crt
COMPONENT_EMBED_TXTFILES += server.key
COMPONENT_EMBED_TXTFILES += srv.crt

View File

@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAlUCywNhVv4RO2y9h/XGKZ1azzk3jzHpSBzIGO9LoiA8trC/p
1ykGaUfYPJllYK4HMhC4fUyE3J7tVL2Eskzl26LNPLbEoaBWZM9NhV3iA1/1EtOu
p6umLx+y3sDfvK35YAOUbjdAlBfhnJ4r8h7oTsxl3J5jZ18zgjJnJi2NEFq/yTpO
MiwHLWPjy25fDFixfV9UzSvbgt1JaGPmC7c4QkhHzjyp0+ikuvRIw0p9BBNeqBV2
da3qBMB5FtodUJTAz6o6OKWbTalLjQi6C1H6z9TnY7IrJBUOy/FWkQH/sEsLdscD
hHa1Dz2oT203QjhzyOSfnNF95D/1MdNcMt6l0wIDAQABAoIBAC1JJTOoMFRc48RT
myrYQYNbZlEphv3q+2qdfhC2zMFDwbrmCtCy7PQSzYSNkpoEE8DYG/JAvmtmeWJl
4pZrCK9ctWM/nWfhC3WpBL97nfEiM20T94F+bn0L5Cz8XqaULv839th+QUTt/hGU
WIctY5VNJXcMQ+MAmtNdUbjex1d3iuxiKHUo4nDoZ8digKFNdtdP5B5nlMq5chCL
mxNRcsGsx2dDAxbGUapdTVPWHPJKpLOBoSkluDsfd2KZADFU2R1SJpAX9+RYh3HM
5FTUdHTUaISxbKkgeDKlEM0lqk2TtGUwCyEj098ewi7Wzsu9w60IplPPUJx5FRG6
jp3wzLkCgYEAxKp5T20rf/7ysX7x053I7VCjDXUxAaWOEj1uS3AhOkl0NaZg7Di+
y53fWNkcHdkt2n2LqMt/43UgMYq3TVVcq2eunPNF11e1bJw8CjDafwDs4omwwyVn
lYhPuB4dK2OAib+vU5Zqpp0kZMoxk2MZVgon8z+s8DW/zmB6aFqAWeUCgYEAwkhC
OgmXKMdjOCVy5t2f5UbY8Y9rV3w8eUATuJ47MMwLr4pGYnKoEn9JB4ltWrHv/u5S
fOv3tIrrCEvnCoCbOILwCsY5LqTNXgqova8FB6RpMUQCzhDd8LHuvdHv0WMnMzX1
3PKuqwh8JS55m4WqZRhzr5BFKG4fHPVs4IcaJVcCgYAzzCaJSdqUKqTnJOUydDNQ
ddWMHNqccWs62J0tF0pZHLGT089hSAzQejMyJnSmU+Ykzr4y5e44DUg+ZCelIZ93
saYmxlgVwI8THQ8fLADQRIEfpV4996MRmkZM2vmZzOo03Zyi6lIKsga82Rg3lnk8
1Q3ynknBNpbfF0AGLhfyFQKBgBYlxJ73HutAJ5hr9HhLBYJOnEaVUehMOlycKGNg
bmD2sdJWEgYBChXpurqIORYguLo4EuE4ySkkuPxeIr14wbkkfBbOWBBwKxUwY+IT
xKAFZxR9q1AwbgyVTCEJgKw/AGX/HcMNS0omEnjunmBTUYRq0C1QZgHg490aQUor
PJjLAoGAevzdTpFlVeuKeYh1oDubGO1LinyXpBv7fPFjl+zu4AVbjojcU6yC4OO6
QvqopE6SyAECKy8kAOFcESPsGc9Lta2XUvI203z7pIVlNVEcJ0+90mQh3Mn1U46l
sZ49PdRvNwNb5wvkh1UqNsMlGFbRlzMbIk45ou4311kCobowZek=
-----END RSA PRIVATE KEY-----

View File

@@ -0,0 +1,18 @@
-----BEGIN CERTIFICATE-----
MIIC9DCCAdwCFA1lSIcHwYKdB2UqOrZxZnVgPObTMA0GCSqGSIb3DQEBCwUAMFkx
CzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRl
cm5ldCBXaWRnaXRzIFB0eSBMdGQxEjAQBgNVBAMMCUVzcHJlc3NpZjAeFw0yMDA2
MTIwNjA0MTNaFw0yMjA2MDIwNjA0MTNaMBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCC
ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJVAssDYVb+ETtsvYf1ximdW
s85N48x6UgcyBjvS6IgPLawv6dcpBmlH2DyZZWCuBzIQuH1MhNye7VS9hLJM5dui
zTy2xKGgVmTPTYVd4gNf9RLTrqerpi8fst7A37yt+WADlG43QJQX4ZyeK/Ie6E7M
ZdyeY2dfM4IyZyYtjRBav8k6TjIsBy1j48tuXwxYsX1fVM0r24LdSWhj5gu3OEJI
R848qdPopLr0SMNKfQQTXqgVdnWt6gTAeRbaHVCUwM+qOjilm02pS40IugtR+s/U
52OyKyQVDsvxVpEB/7BLC3bHA4R2tQ89qE9tN0I4c8jkn5zRfeQ/9THTXDLepdMC
AwEAATANBgkqhkiG9w0BAQsFAAOCAQEAnMYGW+idt37bEE4WPgrRorKWuplR+zHD
wJFz53DQzyIZJHmJ2hR5U0jNcHy/nMq7tbdz9LZPrVF4lZJ3TJhnmkOKjMFPCQE8
YcmsP3il6eXgtGqg53InOi/uJqEQ9TfM54cbpp6xKbnmpwk4uprISBRQt7u2ZLk2
40ED6zgjFPDTYmSjSpb2AN6KUB6PflgVs+4p9ViHNq4U3AlYV/BM0+3G4aMX2wNl
ZIpQfOyuaYD5MU50mY+O+gDiiypkpYf6a6S4YJ1sMbavDsP7bW5UMnP0jKYR549q
5hF1fdkXq52DfJ9ya2kl3mANFkKssQV+1KCBMxGoeqfakmJfa03xXA==
-----END CERTIFICATE-----

View File

@@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
# Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
nvs, data, nvs, 0x9000, 0x6000,
phy_init, data, phy, 0xf000, 0x1000,
factory, app, factory, 0x10000, 1400000,
1 # Name, Type, SubType, Offset, Size, Flags
2 # Note: if you have increased the bootloader size, make sure to update the offsets to avoid overlap
3 nvs, data, nvs, 0x9000, 0x6000,
4 phy_init, data, phy, 0xf000, 0x1000,
5 factory, app, factory, 0x10000, 1400000,

View File

@@ -0,0 +1,6 @@
CONFIG_EXAMPLE_CLIENT=y
CONFIG_EXAMPLE_SERVER=y
CONFIG_EXAMPLE_SERVER_NAME="localhost"
CONFIG_EXAMPLE_CONNECT_WIFI=n
CONFIG_EXAMPLE_CONNECT_ETHERNET=n
CONFIG_EXAMPLE_CLIENT_VERIFY_PEER=y

View File

@@ -0,0 +1,4 @@
CONFIG_ASIO_SSL_SUPPORT=y
CONFIG_PARTITION_TABLE_CUSTOM=y
CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
CONFIG_PARTITION_TABLE_FILENAME="partitions.csv"