From db2da43fc178a5a9e1bb2c2a13681d5be919533e Mon Sep 17 00:00:00 2001 From: dongheng Date: Wed, 14 Sep 2016 19:39:24 +0800 Subject: [PATCH 01/95] components/openssl: add API header for openssl compatibility layer --- components/openssl/include/openssl/ssl.h | 1651 ++++++++++++++++++++++ 1 file changed, 1651 insertions(+) create mode 100644 components/openssl/include/openssl/ssl.h diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h new file mode 100644 index 0000000000..b7b784fe71 --- /dev/null +++ b/components/openssl/include/openssl/ssl.h @@ -0,0 +1,1651 @@ +#ifndef HEADER_SSL_H +#define HEADER_SSL_H + +#include "ssl_types.h" + +/* +{ +*/ + +/* + * SSL_CTX_new - create a SSL context + * + * @param method - the SSL context method point + * + * @return the context point, if create failed return NULL + */ +SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); + +/* + * SSL_CTX_free - free a SSL context + * + * @param method - the SSL context point + * + * @return none + */ +void SSL_CTX_free(SSL_CTX *ctx); + +/* + * SSL_new - create a SSL + * + * @param ctx - the SSL context point + * + * @return the SSL point or NULL if failed + */ +SSL* SSL_new(SSL_CTX *ctx); + +/* + * SSL_free - free the SSL + * + * @param ssl - the SSL point + * + * @return none + */ +void SSL_free(SSL *ssl); + +/* + * SSL_connect - connect to the remote SSL server + * + * @param ssl - the SSL point + * + * @return + * 1 : OK + * -1 : failed + */ +int SSL_connect(SSL *ssl); + +/* + * SSL_accept - accept the remote connection + * + * @param ssl - the SSL point + * + * @return + * 1 : OK + * -1 : failed + */ +int SSL_accept(SSL *ssl); + +/* + * SSL_read - read data from to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the received data buffer point + * @param len - the received data length + * + * @return + * > 0 : OK, and return received data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_read(SSL *ssl, void *buffer, int len); + +/* + * SSL_write - send the data to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the send data buffer point + * @param len - the send data length + * + * @return + * > 0 : OK, and return sent data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_write(SSL *ssl, const void *buffer, int len); + +/* + * SSL_get_verify_result - get the verifying result of the SSL certification + * + * @param ssl - the SSL point + * + * @return the result of verifying + */ +long SSL_get_verify_result(const SSL *ssl); + +/* + * SSL_shutdown - shutdown the connection + * + * @param ssl - the SSL point + * + * @return + * 1 : OK + * 0 : shutdown is not finished + * -1 : an error catch + */ +int SSL_shutdown(SSL *ssl); + +/* + * SSL_set_fd - bind the socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_set_fd(SSL *ssl, int fd); + +/* + * SSL_CTX_use_PrivateKey - These functions load the private key into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - private key object point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + +/* + * SSL_CTX_use_PrivateKey - These functions load the certification into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - certification object point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); + +/* + * SSLv23_client_method - create the target SSL context client method + * + * @param none + * + * @return the SSLV2.3 version SSL context client method + */ +const SSL_METHOD* SSLv23_client_method(void); + +/* + * TLSv1_client_method - create the target SSL context client method + * + * @param none + * + * @return the TLSV1.0 version SSL context client method + */ +const SSL_METHOD* TLSv1_client_method(void); + +/* + * SSLv3_client_method - create the target SSL context client method + * + * @param none + * + * @return the SSLV1.0 version SSL context client method + */ +const SSL_METHOD* SSLv3_client_method(void); + +/* + * TLSv1_1_client_method - create the target SSL context client method + * + * @param none + * + * @return the TLSV1.1 version SSL context client method + */ +const SSL_METHOD* TLSv1_1_client_method(void); + + +/* + * SSLv23_server_method - create the target SSL context server method + * + * @param none + * + * @return the SSLV2.3 version SSL context server method + */ +const SSL_METHOD* SSLv23_server_method(void); + +/* + * TLSv1_1_server_method - create the target SSL context server method + * + * @param none + * + * @return the TLSV1.1 version SSL context server method + */ +const SSL_METHOD* TLSv1_1_server_method(void); + +/* + * TLSv1_server_method - create the target SSL context server method + * + * @param none + * + * @return the TLSV1.0 version SSL context server method + */ +const SSL_METHOD* TLSv1_server_method(void); + +/* + * SSLv3_server_method - create the target SSL context server method + * + * @param none + * + * @return the SSLV3.0 version SSL context server method + */ +const SSL_METHOD* SSLv3_server_method(void); + +/* + * SSL_CTX_set_alpn_select_cb - set the SSL context ALPN select callback function + * + * @param ctx - SSL context point + * @param cb - ALPN select callback function + * @param arg - ALPN select callback function entry private data point + * + * @return none + */ +void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + const unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), + void *arg); + + +/* + * SSL_CTX_set_alpn_protos - set the SSL context ALPN select protocol + * + * @param ctx - SSL context point + * @param protos - ALPN protocol name + * @param protos_len - ALPN protocol name bytes + * + * @return + * 0 : OK + * 1 : failed + */ +int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, unsigned int protos_len); + +/* + * SSL_CTX_set_next_proto_select_cb - set the SSL context next ALPN select callback function + * + * @param ctx - SSL context point + * @param cb - ALPN select callback function + * @param arg - ALPN select callback function entry private data point + * + * @return none + */ +void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, + int (*cb) (SSL *ssl, + unsigned char **out, + unsigned char *outlen, + const unsigned char *in, + unsigned int inlen, + void *arg), + void *arg); + +/* + * SSL_get_error - 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); + +/* + * ERR_clear_error - clear the SSL error code + * + * @param none + * + * @return none + */ +void ERR_clear_error(void); + +/* + * ERR_get_error - get the current SSL error code + * + * @param none + * + * @return current SSL error number + */ +int ERR_get_error(void); + +/* + * ERR_load_SSL_strings - register the SSL error strings + * + * @param none + * + * @return none + */ +void ERR_load_SSL_strings(void); + +/* + * SSL_library_init - initialize the SSL library + * + * @param none + * + * @return none + */ +void SSL_library_init(void); + +/* + * ERR_error_string - generates a human-readable string representing the error code e + * and store it into the "ret" point memory + * + * @param e - error code + * @param ret - memory point to store the string + * + * @return the result string point + */ +char *ERR_error_string(unsigned long e, char *ret); + +/* + * SSL_CTX_set_options - add the SSL context option + * + * @param ctx - SSL context point + * @param opt - new SSL context option + * + * @return the SSL context option + */ +unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt); + +/* + * SSL_CTX_set_options - add the SSL context mode + * + * @param ctx - SSL context point + * @param mod - new SSL context mod + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_mode(SSL_CTX *ctx, int mod); + +/* +} +*/ + +/* + * SSL_do_handshake - perform the SSL handshake + * + * @param ssl - SSL point + * + * @return + * 1 : OK + * 0 : failed + * -1 : a error catch + */ +int SSL_do_handshake(SSL *ssl); + +/* + * SSL_get_version - get the SSL current version + * + * @param ssl - SSL point + * + * @return the version string + */ +const char *SSL_get_version(const SSL *ssl); + +/* + * SSL_CTX_set_ssl_version - set the SSL context version + * + * @param ctx - SSL context point + * @param meth - SSL method point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + +/* + * SSL_CTX_get_ssl_method - get the SSL context current method + * + * @param ctx - SSL context point + * + * @return the SSL context current method + */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); + +/* + * SSL_CTX_get_ssl_method - get the SSL current method + * + * @param ssl - SSL point + * + * @return the SSL current method + */ +const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); + +/* + * SSL_set_ssl_method - set the SSL method + * + * @param ssl - SSL point + * @param meth - SSL method point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); + +/* + * SSL_add_client_CA - add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - CA certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_add_client_CA(SSL *ssl, X509 *x); + +/* + * SSL_add_client_CA - add CA client certification into the SSL context + * + * @param ctx - SSL context point + * @param x - CA certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +/* + * SSL_set_client_CA_list - set the SSL CA certification list + * + * @param ssl - SSL point + * @param name_list - CA certification list + * + * @return none + */ +void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list); + +/* + * SSL_CTX_set_client_CA_list - set the SSL context CA certification list + * + * @param ctx - SSL context point + * @param name_list - CA certification list + * + * @return none + */ +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); + +/* + * SSL_get_client_CA_list - get the SSL CA certification list + * + * @param ssl - SSL point + * + * @return CA certification list + */ +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl); + +/* + * SSL_CTX_get_client_CA_list - get the SSL context CA certification list + * + * @param ctx - SSL context point + * + * @return CA certification list + */ +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx); + +/* + * SSL_get_certificate - get the SSL certification point + * + * @param ssl - SSL point + * + * @return SSL certification point + */ +X509 *SSL_get_certificate(const SSL *ssl); + +/* + * SSL_get_privatekey - get the SSL private key point + * + * @param ssl - SSL point + * + * @return SSL private key point + */ +EVP_PKEY *SSL_get_privatekey(const SSL *ssl); + +/* + * SSL_set_info_callback - set the SSL information callback function + * + * @param ssl - SSL point + * @param cb - information callback function + * + * @return none + */ +void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)); + +/* + * SSL_get_state - get the SSL state + * + * @param ssl - SSL point + * + * @return SSL state + */ +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); + +/* + * SSL_CTX_set_default_read_buffer_len - set the SSL context read buffer length + * + * @param ctx - SSL context point + * @param len - read buffer length + * + * @return none + */ +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); + +/* + * SSL_set_default_read_buffer_len - set the SSL read buffer length + * + * @param ssl - SSL point + * @param len - read buffer length + * + * @return none + */ +void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); + +/* + * SSL_set_security_level - set the SSL security level + * + * @param ssl - SSL point + * @param level - security level + * + * @return none + */ +void SSL_set_security_level(SSL *ssl, int level); + +/* + * SSL_get_security_level - get the SSL security level + * + * @param ssl - SSL point + * + * @return security level + */ +int SSL_get_security_level(const SSL *ssl); + +/* + * SSL_CTX_get_verify_mode - get the SSL verifying mode of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying mode + */ +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); + +/* + * SSL_CTX_get_verify_depth - get the SSL verifying depth of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying depth + */ +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); + +/* + * SSL_CTX_set_verify - set the SSL context verifying of the SSL context + * + * @param ctx - SSL context point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); + +/* + * SSL_set_verify - set the SSL verifying of the SSL context + * + * @param ctx - SSL point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_set_verify(SSL *s, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); + +/* + * SSL_CTX_set_verify_depth - set the SSL verify depth of the SSL context + * + * @param ctx - SSL context point + * @param depth - verifying depth + * + * @return one + */ +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); + +/* + * verify_callback - certification verifying callback function + * + * @param preverify_ok - verifying result + * @param x509_ctx - X509 certification point + * + * @return verifying result + */ +int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx); + +/* + * SSL_CTX_set_timeout - set the session timeout time + * + * @param ctx - SSL context point + * @param t - new session timeout time + * + * @return old session timeout time + */ +long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); + +/* + * SSL_CTX_get_timeout - get the session timeout time + * + * @param ctx - SSL context point + * + * @return current session timeout time + */ +long SSL_CTX_get_timeout(const SSL_CTX *ctx); + +/* + * SSL_CTX_set_cipher_list - set the SSL context cipher through the list string + * + * @param ctx - SSL context point + * @param str - cipher controller list string + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); + +/* + * SSL_set_cipher_list - set the SSL cipher through the list string + * + * @param ssl - SSL point + * @param str - cipher controller list string + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_set_cipher_list(SSL *ssl, const char *str); + +/* + * SSL_get_cipher_list - get the SSL cipher list string + * + * @param ssl - SSL point + * + * @return cipher controller list string + */ +const char *SSL_get_cipher_list(const SSL *ssl, int n); + +/* + * SSL_get_current_cipher - get the SSL cipher + * + * @param ssl - SSL point + * + * @return current cipher + */ +const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl); + +/* + * SSL_get_cipher - get the SSL cipher string + * + * @param ssl - SSL point + * + * @return cipher string + */ +const char *SSL_get_cipher(const SSL *ssl); + +/* + * SSL_CTX_get_cert_store - get the SSL context object X509 certification storage + * + * @param ctx - SSL context point + * + * @return x509 certification storage + */ +X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); + +/* + * SSL_CTX_set_cert_store - set the SSL context object X509 certification store + * + * @param ctx - SSL context point + * @param store - X509 certification store + * + * @return none + */ +void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store); + +/* + * SSL_want - get the SSL specifical statement + * + * @param ssl - SSL point + * + * @return specifical statement + */ +int SSL_want(const SSL *ssl); + +/* + * SSL_want_x509_lookup - check if the SSL is SSL_X509_LOOKUP state + * + * @param ssl - SSL point + * + * @return + * 1 : yes + * 0 : no + */ +int SSL_want_x509_lookup(const SSL *ssl); + +/* + * SSL_clear - reset the SSL + * + * @param ssl - SSL point + * + * @return + * 1 : yes + * 0 : no + */ +int SSL_clear(SSL *ssl); + +/* + * SSL_get_fd - get the socket handle of the SSL + * + * @param ssl - SSL point + * + * @return + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_fd(const SSL *ssl); + +/* + * SSL_get_rfd - get the read only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_rfd(const SSL *ssl); + +/* + * SSL_get_wfd - get the write only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_wfd(const SSL *ssl); + +/* + * SSL_set_read_ahead - set the SSL if we can read as many as data + * + * @param ssl - SSL point + * @param yes - enbale the function + * + * @return none + */ +void SSL_set_read_ahead(SSL *s, int yes); + +/* + * SSL_set_read_ahead - set the SSL context if we can read as many as data + * + * @param ctx - SSL context point + * @param yes - enbale the function + * + * @return none + */ +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); + +/* + * SSL_set_read_ahead - get the SSL ahead signal if we can read as many as data + * + * @param ssl - SSL point + * + * @return SSL context ahead signal + */ +int SSL_get_read_ahead(const SSL *ssl); + +/* + * SSL_set_read_ahead - get the SSL context ahead signal if we can read as many as data + * + * @param ctx - SSL context point + * + * @return SSL context ahead signal + */ +long SSL_CTX_get_read_ahead(SSL_CTX *ctx); + +/* + * SSL_has_pending - check if some data can be read + * + * @param ssl - SSL point + * + * @return SSL context ahead signal + */ +int SSL_has_pending(const SSL *ssl); + +/* + * SSL_CTX_use_certificate - load the X509 certification into SSL context + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);//loads the certificate x into ctx + +/* + * SSL_CTX_use_certificate_ASN1 - load the ASN1 certification into SSL context + * + * @param ctx - SSL context point + * @param len - certification length + * @param d - data point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d); + +/* + * SSL_CTX_use_certificate_file - load the certification file into SSL context + * + * @param ctx - SSL context point + * @param file - certification file name + * @param type - certification encoding type + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); + +/* + * SSL_CTX_use_certificate_chain_file - load the certification chain file into SSL context + * + * @param ctx - SSL context point + * @param file - certification chain file name + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); + + +/* + * SSL_CTX_use_certificate_ASN1 - load the ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - private key length + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, unsigned char *d, long len);//adds the private key of type pk stored at memory location d (length len) to ctx + +/* + * SSL_CTX_use_certificate_file - load the private key file into SSL context + * + * @param ctx - SSL context point + * @param file - private key file name + * @param type - private key encoding type + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);//adds the first private key found in file to ctx, The formatting type of the certificate must be specified from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1. + +/* + * SSL_CTX_use_certificate - load the RSA private key into SSL context + * + * @param ctx - SSL context point + * @param x - RSA private key point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); + +/* + * SSL_CTX_use_certificate_ASN1 - load the RSA ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - RSA private key length + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, unsigned char *d, long len); + +/* + * SSL_CTX_use_certificate_file - load the RSA private key file into SSL context + * + * @param ctx - SSL context point + * @param file - RSA private key file name + * @param type - private key encoding type + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); + + +/* + * SSL_CTX_check_private_key - check if the private key and certification is matched + * + * @param ctx - SSL context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_check_private_key(const SSL_CTX *ctx); + +/* + * SSL_CTX_use_serverinfo - set the SSL context server information + * + * @param ctx - SSL context point + * @param serverinfo - server information string + * @param serverinfo_length - server information length + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, size_t serverinfo_length); + +/* + * SSL_CTX_use_serverinfo - load the SSL context server infomation file into SSL context + * + * @param ctx - SSL context point + * @param file - server information file + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file); + +/* + * SSL_select_next_proto - SSL select next function + * + * @param out - point of output data point + * @param outlen - output data length + * @param in - input data + * @param inlen - input data length + * @param client - client data point + * @param client_len -client data length + * + * @return + * OPENSSL_NPN_UNSUPPORTED : not support + * OPENSSL_NPN_NEGOTIATED : negotiated + * OPENSSL_NPN_NO_OVERLAP : no overlap + */ +int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, + const unsigned char *in, unsigned int inlen, + const unsigned char *client, unsigned int client_len); + +/* + * SSL_CTX_add_extra_chain_cert - load the extra certification chain into the SSL context + * + * @param ctx - SSL context point + * @param x509 - X509 certification + * + * @return + * 1 : OK + * 0 : failed + */ +long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *); + +/* + * SSL_CTX_ctrl - control the SSL context + * + * @param ctx - SSL context point + * @param cmd - command + * @param larg - parameter length + * @param parg - parameter point + * + * @return + * 1 : OK + * 0 : failed + */ +long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg); + +/* + * SSL_CTX_get_ciphers - get the SSL context cipher + * + * @param ctx - SSL context point + * + * @return SSL context cipher + */ +STACK *SSL_CTX_get_ciphers(const SSL_CTX *ctx); + +/* + * SSL_CTX_get_ciphers - check if the SSL context can read as many as data + * + * @param ctx - SSL context point + * + * @return + * 1 : Yes + * 0 : No + */ +long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx); + +/* + * SSL_CTX_get_ex_data - get the SSL context extra data + * + * @param ctx - SSL context point + * @param idx - index + * + * @return data point + */ +char *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx); + +/* + * SSL_CTX_get_quiet_shutdown - get the SSL context quiet shutdown option + * + * @param ctx - SSL context point + * + * @return quiet shutdown option + */ +int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); + +/* + * SSL_CTX_get_quiet_shutdown - load the SSL context CA file + * + * @param ctx - SSL context point + * @param CAfile - CA certification file + * @param CApath - CA certification file path + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath); + +/* + * SSL_CTX_up_ref - add SSL context reference count by '1' + * + * @param ctx - SSL context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_up_ref(SSL_CTX *ctx); + +/* + * SSL_CTX_set_app_data - set SSL context application private data + * + * @param ctx - SSL context point + * @param arg - private data + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_app_data(SSL_CTX *ctx, void *arg); + +/* + * SSL_CTX_set_client_cert_cb - set SSL context client certification callback function + * + * @param ctx - SSL context point + * @param cb - callback function + * + * @return none + */ +void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); + +/* + * SSL_CTX_set_default_read_ahead - set the SSL context if we can read as many as data + * + * @param ctx - SSL context point + * @param m - enable the fuction + * + * @return none + */ +void SSL_CTX_set_default_read_ahead(SSL_CTX *ctx, int m); + +/* + * SSL_CTX_set_default_verify_paths - set SSL context default verifying path + * + * @param ctx - SSL context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); + +/* + * SSL_CTX_set_default_verify_paths - set SSL context default verifying directory + * + * @param ctx - SSL context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_dir(SSL_CTX *ctx); + +/* + * SSL_CTX_set_default_verify_paths - set SSL context default verifying file + * + * @param ctx - SSL context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_default_verify_file(SSL_CTX *ctx); + +/* + * SSL_CTX_set_ex_data - set SSL context extra data + * + * @param ctx - SSL context point + * @param idx - data index + * @param arg - data point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, char *arg); + +/* + * SSL_CTX_clear_options - clear the SSL context option bit of "op" + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op); + +/* + * SSL_CTX_clear_options - get the SSL context option + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_get_options(SSL_CTX *ctx); + +/* + * SSL_CTX_set_quiet_shutdown - set the SSL context quiet shutdown mode + * + * @param ctx - SSL context point + * @param mode - mode + * + * @return none + */ +void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); + +/* + * SSL_CTX_get0_certificate - get the SSL context X509 certification + * + * @param ctx - SSL context point + * + * @return X509 certification + */ +X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); + +/* + * SSL_CTX_get0_certificate - get the SSL context private key + * + * @param ctx - SSL context point + * + * @return private key + */ +EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); + +/* + * SSL_CTX_use_psk_identity_hint - set SSL context PSK identity hint + * + * @param ctx - SSL context point + * @param hint - PSK identity hint + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint); + +/* + * SSL_CTX_set_psk_server_callback - set SSL context PSK server callback function + * + * @param ctx - SSL context point + * @param callback - callback function + * + */ +void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, + unsigned int (*callback)(SSL *ssl, + const char *identity, + unsigned char *psk, + int max_psk_len)); +/* + * SSL_alert_desc_string - get alert description string + * + * @param value - alert value + * + * @return alert description string + */ +const char *SSL_alert_desc_string(int value); + +/* + * SSL_alert_desc_string - get alert description long string + * + * @param value - alert value + * + * @return alert description long string + */ +const char *SSL_alert_desc_string_long(int value); + +/* + * SSL_alert_type_string - get alert type string + * + * @param value - alert value + * + * @return alert type string + */ +const char *SSL_alert_type_string(int value); + +/* + * SSL_alert_type_string_long - get alert type long string + * + * @param value - alert value + * + * @return alert type long string + */ +const char *SSL_alert_type_string_long(int value); + +/* + * SSL_get_SSL_CTX - get SSL context of the SSL + * + * @param ssl - SSL point + * + * @return SSL context + */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); + +/* + * SSL_get_app_data - get SSL application data + * + * @param ssl - SSL point + * + * @return application data + */ +char *SSL_get_app_data(SSL *ssl); + +/* + * SSL_get_cipher_bits - get SSL cipher bits + * + * @param ssl - SSL point + * @param alg_bits - algorithm bits + * + * @return strength bits + */ +int SSL_get_cipher_bits(const SSL *ssl, int *alg_bits); + +/* + * SSL_get_cipher_name - get SSL cipher name + * + * @param ssl - SSL point + * + * @return SSL cipher name + */ +char *SSL_get_cipher_name(const SSL *ssl); + +/* + * SSL_get_cipher_version - get SSL cipher version + * + * @param ssl - SSL point + * + * @return SSL cipher version + */ +char *SSL_get_cipher_version(const SSL *ssl); + +/* + * SSL_get_ex_data - get SSL extra data + * + * @param ssl - SSL point + * @param idx - data index + * + * @return extra data + */ +char *SSL_get_ex_data(const SSL *ssl, int idx); + +/* + * SSL_get_ex_data_X509_STORE_CTX_idx - get index of the SSL extra data X509 storage context + * + * @param none + * + * @return data index + */ +int SSL_get_ex_data_X509_STORE_CTX_idx(void); + +/* + * SSL_get_peer_cert_chain - get peer certification chain + * + * @param ssl - SSL point + * + * @return certification chain + */ +STACK *SSL_get_peer_cert_chain(const SSL *ssl); + +/* + * SSL_get_peer_certificate - get peer certification + * + * @param ssl - SSL point + * + * @return certification + */ +X509 *SSL_get_peer_certificate(const SSL *ssl); + +/* + * SSL_get_quiet_shutdown - get SSL quiet shutdown mode + * + * @param ssl - SSL point + * + * @return quiet shutdown mode + */ +int SSL_get_quiet_shutdown(const SSL *ssl); + +/* + * SSL_get_rbio - get SSL read only IO handle + * + * @param ssl - SSL point + * + * @return IO handle + */ +BIO *SSL_get_rbio(const SSL *ssl); + +/* + * SSL_get_shared_ciphers - get SSL shared ciphers + * + * @param ssl - SSL point + * @param buf - buffer to store the ciphers + * @param len - buffer len + * + * @return shared ciphers or NULL if failed + */ +char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len); + +/* + * SSL_get_shutdown - get SSL shutdown mode + * + * @param ssl - SSL point + * + * @return shutdown mode + */ +int SSL_get_shutdown(const SSL *ssl); + +/* + * SSL_get_time - get SSL session time + * + * @param ssl - SSL point + * + * @return session time + */ +long SSL_get_time(const SSL *ssl); + +/* + * SSL_get_timeout - get SSL session timeout time + * + * @param ssl - SSL point + * + * @return session timeout time + */ +long SSL_get_timeout(const SSL *ssl); + +/* + * SSL_get_verify_mode - get SSL verifying mode + * + * @param ssl - SSL point + * + * @return verifying mode + */ +int SSL_get_verify_mode(const SSL *ssl); + +/* + * SSL_get_wbio - get SSL write only IO handle + * + * @param ssl - SSL point + * + * @return IO handle + */ +BIO *SSL_get_wbio(const SSL *ssl); + +/* + * SSL_load_client_CA_file - load SSL client CA certification file + * + * @param file - file name + * + * @return certification loading object + */ +STACK *SSL_load_client_CA_file(const char *file); + +/* + * SSL_up_ref - add SSL reference by '1' + * + * @param ssl - SSL point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_up_ref(SSL *ssl); + +/* + * SSL_peek - read and put data into buf, but not clear the SSL low-level storage + * + * @param ssl - SSL point + * @param buf - storage buffer point + * @param num - data bytes + * + * @return + * > 0 : OK, and return read bytes + * = 0 : connect is closed + * < 0 : a error catch + */ +int SSL_peek(SSL *ssl, void *buf, int num); + +/* + * SSL_renegotiate - make SSL renegotiate + * + * @param ssl - SSL point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_renegotiate(SSL *ssl); + +/* + * SSL_rstate_string - get the state string where SSL is reading + * + * @param ssl - SSL point + * + * @return state string + */ +const char *SSL_rstate_string(SSL *ssl); + +/* + * SSL_rstate_string_long - get the statement long string where SSL is reading + * + * @param ssl - SSL point + * + * @return statement long string + */ +const char *SSL_rstate_string_long(SSL *ssl); + +/* + * SSL_set_accept_state - set SSL accept statement + * + * @param ssl - SSL point + * + * @return none + */ +void SSL_set_accept_state(SSL *ssl); + +/* + * SSL_set_app_data - set SSL application data + * + * @param ssl - SSL point + * @param arg - SSL application data point + * + * @return none + */ +void SSL_set_app_data(SSL *ssl, char *arg); + +/* + * SSL_set_bio - set SSL BIO + * + * @param ssl - SSL point + * @param rbio - read only IO + * @param wbio - write only IO + * + * @return none + */ +void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); + +/* + * SSL_clear_options - clear SSL option + * + * @param ssl - SSL point + * @param op - clear option + * + * @return SSL option + */ +unsigned long SSL_clear_options(SSL *ssl, unsigned long op); + +/* + * SSL_clear_options - get SSL option + * + * @param ssl - SSL point + * + * @return SSL option + */ +unsigned long SSL_get_options(SSL *ssl); + +/* + * SSL_clear_options - clear SSL option + * + * @param ssl - SSL point + * @param op - setting option + * + * @return SSL option + */ +unsigned long SSL_set_options(SSL *ssl, unsigned long op); + +/* + * SSL_set_quiet_shutdown - set SSL quiet shutdown mode + * + * @param ssl - SSL point + * @param mode - quiet shutdown mode + * + * @return none + */ +void SSL_set_quiet_shutdown(SSL *ssl, int mode); + +/* + * SSL_set_quiet_shutdown - set SSL shutdown mode + * + * @param ssl - SSL point + * @param mode - shutdown mode + * + * @return none + */ +void SSL_set_shutdown(SSL *ssl, int mode); + +/* + * SSL_set_time - set SSL session time + * + * @param ssl - SSL point + * @param t - session time + * + * @return session time + */ +void SSL_set_time(SSL *ssl, long t); + +/* + * SSL_set_time - set SSL session timeout time + * + * @param ssl - SSL point + * @param t - session timeout time + * + * @return session timeout time + */ +void SSL_set_timeout(SSL *ssl, long t); + +/* + * SSL_state_string - get SSL statement string + * + * @param ssl - SSL point + * + * @return SSL statement string + */ +char *SSL_state_string(const SSL *ssl); + +/* + * SSL_state_string_long - get SSL statement long string + * + * @param ssl - SSL point + * + * @return SSL statement long string + */ +char *SSL_state_string_long(const SSL *ssl); + +/* + * SSL_total_renegotiations - get SSL renegotiation count + * + * @param ssl - SSL point + * + * @return renegotiation count + */ +long SSL_total_renegotiations(SSL *ssl); + +/* + * SSL_version - get SSL version + * + * @param ssl - SSL point + * + * @return SSL version + */ +int SSL_version(const SSL *ssl); + +/* + * SSL_use_psk_identity_hint - set SSL PSK identity hint + * + * @param ssl - SSL point + * @param hint - identity hint + * + * @return + * 1 : oK + * 0 : failed + */ +int SSL_use_psk_identity_hint(SSL *ssl, const char *hint); + +/* + * SSL_get_psk_identity_hint - get SSL PSK identity hint + * + * @param ssl - SSL point + * + * @return identity hint + */ +const char *SSL_get_psk_identity_hint(SSL *ssl); + +/* + * SSL_get_psk_identity - get SSL PSK identity + * + * @param ssl - SSL point + * + * @return identity + */ +const char *SSL_get_psk_identity(SSL *ssl); + +#endif From 44c466c0ea077a28fa138edfdaed400c2b3bd416 Mon Sep 17 00:00:00 2001 From: dongheng Date: Tue, 20 Sep 2016 16:58:46 +0800 Subject: [PATCH 02/95] components/openssl: add base function version --- components/openssl/Makefile | 50 + components/openssl/include/internal/ssl3.h | 22 + .../openssl/include/internal/ssl_cert.h | 11 + .../openssl/include/internal/ssl_code.h | 95 + components/openssl/include/internal/ssl_dbg.h | 33 + components/openssl/include/internal/ssl_lib.h | 11 + .../openssl/include/internal/ssl_methods.h | 46 + .../openssl/include/internal/ssl_pkey.h | 11 + components/openssl/include/internal/ssl_rsa.h | 14 + .../openssl/include/internal/ssl_types.h | 190 ++ .../openssl/include/internal/ssl_x509.h | 12 + components/openssl/include/internal/tls1.h | 33 + components/openssl/include/openssl/ssl.h | 31 +- components/openssl/include/platform/ssl_pm.h | 41 + components/openssl/library/Makefile | 46 + components/openssl/library/ssl_cert.c | 28 + components/openssl/library/ssl_lib.c | 1622 +++++++++++++++++ components/openssl/library/ssl_methods.c | 43 + components/openssl/library/ssl_pkey.c | 50 + components/openssl/library/ssl_rsa.c | 70 + components/openssl/library/ssl_x509.c | 54 + components/openssl/platform/Makefile | 46 + components/openssl/platform/ssl_pm.c | 422 +++++ 23 files changed, 2976 insertions(+), 5 deletions(-) create mode 100644 components/openssl/Makefile create mode 100644 components/openssl/include/internal/ssl3.h create mode 100644 components/openssl/include/internal/ssl_cert.h create mode 100644 components/openssl/include/internal/ssl_code.h create mode 100644 components/openssl/include/internal/ssl_dbg.h create mode 100644 components/openssl/include/internal/ssl_lib.h create mode 100644 components/openssl/include/internal/ssl_methods.h create mode 100644 components/openssl/include/internal/ssl_pkey.h create mode 100644 components/openssl/include/internal/ssl_rsa.h create mode 100644 components/openssl/include/internal/ssl_types.h create mode 100644 components/openssl/include/internal/ssl_x509.h create mode 100644 components/openssl/include/internal/tls1.h create mode 100644 components/openssl/include/platform/ssl_pm.h create mode 100644 components/openssl/library/Makefile create mode 100644 components/openssl/library/ssl_cert.c create mode 100644 components/openssl/library/ssl_lib.c create mode 100644 components/openssl/library/ssl_methods.c create mode 100644 components/openssl/library/ssl_pkey.c create mode 100644 components/openssl/library/ssl_rsa.c create mode 100644 components/openssl/library/ssl_x509.c create mode 100644 components/openssl/platform/Makefile create mode 100644 components/openssl/platform/ssl_pm.c diff --git a/components/openssl/Makefile b/components/openssl/Makefile new file mode 100644 index 0000000000..bdd8a0e932 --- /dev/null +++ b/components/openssl/Makefile @@ -0,0 +1,50 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +UP_EXTRACT_DIR = .. +GEN_LIBS = libopenssl.a +COMPONENTS_libopenssl = library/liblibrary.a platform/libplatform.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include -I $(PDIR)include/platform -I $(PDIR)include/internal +INCLUDES += -I ./inlcude +INCLUDES += -I $(SDK_PATH)/include/openssl/internal +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/components/openssl/include/internal/ssl3.h b/components/openssl/include/internal/ssl3.h new file mode 100644 index 0000000000..d7c254563b --- /dev/null +++ b/components/openssl/include/internal/ssl3.h @@ -0,0 +1,22 @@ +#ifndef _SSL3_H_ +#define _SSL3_H_ + +# define SSL3_AD_CLOSE_NOTIFY 0 +# define SSL3_AD_UNEXPECTED_MESSAGE 10/* fatal */ +# define SSL3_AD_BAD_RECORD_MAC 20/* fatal */ +# define SSL3_AD_DECOMPRESSION_FAILURE 30/* fatal */ +# define SSL3_AD_HANDSHAKE_FAILURE 40/* fatal */ +# define SSL3_AD_NO_CERTIFICATE 41 +# define SSL3_AD_BAD_CERTIFICATE 42 +# define SSL3_AD_UNSUPPORTED_CERTIFICATE 43 +# define SSL3_AD_CERTIFICATE_REVOKED 44 +# define SSL3_AD_CERTIFICATE_EXPIRED 45 +# define SSL3_AD_CERTIFICATE_UNKNOWN 46 +# define SSL3_AD_ILLEGAL_PARAMETER 47/* fatal */ + +# define SSL3_AL_WARNING 1 +# define SSL3_AL_FATAL 2 + +#define SSL3_VERSION 0x0300 + +#endif diff --git a/components/openssl/include/internal/ssl_cert.h b/components/openssl/include/internal/ssl_cert.h new file mode 100644 index 0000000000..e0b3ea75dc --- /dev/null +++ b/components/openssl/include/internal/ssl_cert.h @@ -0,0 +1,11 @@ +#ifndef _SSL_CERT_H_ +#define _SSL_CERT_H_ + +#include "ssl_pkey.h" +#include "ssl_x509.h" + +CERT *ssl_cert_new(void); + +void ssl_cert_free(CERT *c); + +#endif diff --git a/components/openssl/include/internal/ssl_code.h b/components/openssl/include/internal/ssl_code.h new file mode 100644 index 0000000000..d45abff680 --- /dev/null +++ b/components/openssl/include/internal/ssl_code.h @@ -0,0 +1,95 @@ +#ifndef _SSL_CODE_H_ +#define _SSL_CODE_H_ + +#include "ssl3.h" +#include "tls1.h" + +/* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ +# define SSL_SENT_SHUTDOWN 1 +# define SSL_RECEIVED_SHUTDOWN 2 + +/* + * The following 3 states are kept in ssl->rlayer.rstate when reads fail, you + * should not need these + */ +# define SSL_ST_READ_HEADER 0xF0 +# define SSL_ST_READ_BODY 0xF1 +# define SSL_ST_READ_DONE 0xF2 + +# define SSL_NOTHING 1 +# define SSL_WRITING 2 +# define SSL_READING 3 +# define SSL_X509_LOOKUP 4 +# define SSL_ASYNC_PAUSED 5 +# define SSL_ASYNC_NO_JOBS 6 + + +# define SSL_ERROR_NONE 0 +# define SSL_ERROR_SSL 1 +# define SSL_ERROR_WANT_READ 2 +# define SSL_ERROR_WANT_WRITE 3 +# define SSL_ERROR_WANT_X509_LOOKUP 4 +# define SSL_ERROR_SYSCALL 5/* look at error stack/return value/errno */ +# define SSL_ERROR_ZERO_RETURN 6 +# define SSL_ERROR_WANT_CONNECT 7 +# define SSL_ERROR_WANT_ACCEPT 8 +# define SSL_ERROR_WANT_ASYNC 9 +# define SSL_ERROR_WANT_ASYNC_JOB 10 + +/* Message flow states */ +typedef enum { + /* No handshake in progress */ + MSG_FLOW_UNINITED, + /* A permanent error with this connection */ + MSG_FLOW_ERROR, + /* We are about to renegotiate */ + MSG_FLOW_RENEGOTIATE, + /* We are reading messages */ + MSG_FLOW_READING, + /* We are writing messages */ + MSG_FLOW_WRITING, + /* Handshake has finished */ + MSG_FLOW_FINISHED +} MSG_FLOW_STATE; + +typedef enum { + TLS_ST_BEFORE, + TLS_ST_OK, + DTLS_ST_CR_HELLO_VERIFY_REQUEST, + TLS_ST_CR_SRVR_HELLO, + TLS_ST_CR_CERT, + TLS_ST_CR_CERT_STATUS, + TLS_ST_CR_KEY_EXCH, + TLS_ST_CR_CERT_REQ, + TLS_ST_CR_SRVR_DONE, + TLS_ST_CR_SESSION_TICKET, + TLS_ST_CR_CHANGE, + TLS_ST_CR_FINISHED, + TLS_ST_CW_CLNT_HELLO, + TLS_ST_CW_CERT, + TLS_ST_CW_KEY_EXCH, + TLS_ST_CW_CERT_VRFY, + TLS_ST_CW_CHANGE, + TLS_ST_CW_NEXT_PROTO, + TLS_ST_CW_FINISHED, + TLS_ST_SW_HELLO_REQ, + TLS_ST_SR_CLNT_HELLO, + DTLS_ST_SW_HELLO_VERIFY_REQUEST, + TLS_ST_SW_SRVR_HELLO, + TLS_ST_SW_CERT, + TLS_ST_SW_KEY_EXCH, + TLS_ST_SW_CERT_REQ, + TLS_ST_SW_SRVR_DONE, + TLS_ST_SR_CERT, + TLS_ST_SR_KEY_EXCH, + TLS_ST_SR_CERT_VRFY, + TLS_ST_SR_NEXT_PROTO, + TLS_ST_SR_CHANGE, + TLS_ST_SR_FINISHED, + TLS_ST_SW_SESSION_TICKET, + TLS_ST_SW_CERT_STATUS, + TLS_ST_SW_CHANGE, + TLS_ST_SW_FINISHED +} OSSL_HANDSHAKE_STATE; + +#endif diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h new file mode 100644 index 0000000000..436d33132f --- /dev/null +++ b/components/openssl/include/internal/ssl_dbg.h @@ -0,0 +1,33 @@ +#ifndef _SSL_DEBUG_H_ +#define _SSL_DEBUG_H_ + +#define SSL_DEBUG_ENBALE 0 +#define SSL_DEBUG_LEVEL 0 +#define SSL_ASSERT_ENABLE 1 +#define SSL_DEBUG_LOCATION_ENABLE 1 + +#if SSL_DEBUG_ENBALE + #define SSL_PRINT os_printf +#else + #define SSL_PRINT(...) +#endif + +#if SSL_DEBUG_LOCATION_ENABLE + #define SSL_DEBUG_LOCATION() SSL_PRINT("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__) +#else + #define SSL_DEBUG_LOCATION() +#endif + +#if SSL_ASSERT_ENABLE + #define SSL_ASSERT(s) { if (!(s)) { SSL_DEBUG_LOCATION(); } } +#else + #define SSL_ASSERT(s) +#endif + +#define SSL_ERR(err, go, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(__VA_ARGS__); ret = err; goto go; } + +#define SSL_RET(go, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(__VA_ARGS__); goto go; } + +#define SSL_DEBUG(level, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT(__VA_ARGS__);} } + +#endif diff --git a/components/openssl/include/internal/ssl_lib.h b/components/openssl/include/internal/ssl_lib.h new file mode 100644 index 0000000000..d95d219556 --- /dev/null +++ b/components/openssl/include/internal/ssl_lib.h @@ -0,0 +1,11 @@ +#ifndef _SSL_LIB_H_ +#define _SSL_LIB_H_ + +#include "ssl_types.h" + +#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) +#define SSL_want_read(s) (SSL_want(s) == SSL_READING) +#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) +#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_WRITING) + +#endif diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h new file mode 100644 index 0000000000..e2806f177a --- /dev/null +++ b/components/openssl/include/internal/ssl_methods.h @@ -0,0 +1,46 @@ +#ifndef _SSL_METHODS_H_ +#define _SSL_METHODS_H_ + +#define IMPLEMENT_TLS_METHOD_FUNC(func_name, \ + new, free, \ + handshake, shutdown, clear, \ + read, send, pending, \ + set_fd, get_fd, \ + set_bufflen, \ + get_state) \ + static const SSL_METHOD_FUNC func_name = { \ + new, \ + free, \ + handshake, \ + shutdown, \ + clear, \ + read, \ + send, \ + pending, \ + set_fd, \ + get_fd, \ + set_bufflen, \ + get_state \ + }; + +#define IMPLEMENT_TLS_METHOD(ver, mode, fun, func_name) \ + const SSL_METHOD* func_name(void) { \ + static const SSL_METHOD func_name##_data = { \ + ver, \ + mode, \ + &(fun), \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_SSL_METHOD(ver, mode, fun, func_name) \ + const SSL_METHOD* func_name(void) { \ + static const SSL_METHOD func_name##_data = { \ + ver, \ + mode, \ + &(fun), \ + }; \ + return &func_name##_data; \ + } + +#endif diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h new file mode 100644 index 0000000000..cc870e18ed --- /dev/null +++ b/components/openssl/include/internal/ssl_pkey.h @@ -0,0 +1,11 @@ +#ifndef _SSL_PKEY_H_ +#define _SSL_PKEY_H_ + +#include "ssl_types.h" + +EVP_PKEY *d2i_PrivateKey(int type, + EVP_PKEY **a, + const unsigned char **pp, + long length); + +#endif diff --git a/components/openssl/include/internal/ssl_rsa.h b/components/openssl/include/internal/ssl_rsa.h new file mode 100644 index 0000000000..7530bde734 --- /dev/null +++ b/components/openssl/include/internal/ssl_rsa.h @@ -0,0 +1,14 @@ +#ifndef _SSL_RSA_H_ +#define _SSL_RSA_H_ + +#include "ssl_lib.h" + +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d); + +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, + const unsigned char *d, long len); + +#endif diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h new file mode 100644 index 0000000000..19eb6cb165 --- /dev/null +++ b/components/openssl/include/internal/ssl_types.h @@ -0,0 +1,190 @@ +#ifndef _SSL_TYPES_H_ +#define _SSL_TYPES_H_ + +#include "ssl_code.h" +#include + +typedef void SSL_CIPHER; + +typedef void X509_STORE_CTX; +typedef void X509_NAME; +typedef void X509_STORE; + +typedef void RSA; + +typedef void STACK; +typedef void BIO; + +#define STACK_OF(x) x + +struct ssl_method_st; +typedef struct ssl_method_st SSL_METHOD; + +struct ssl_method_func_st; +typedef struct ssl_method_func_st SSL_METHOD_FUNC; + +struct record_layer_st; +typedef struct record_layer_st RECORD_LAYER; + +struct ossl_statem_st; +typedef struct ossl_statem_st OSSL_STATEM; + +struct ssl_session_st; +typedef struct ssl_session_st SSL_SESSION; + +struct ssl_ctx_st; +typedef struct ssl_ctx_st SSL_CTX; + +struct ssl_st; +typedef struct ssl_st SSL; + +struct cert_st; +typedef struct cert_st CERT; + +struct x509_st; +typedef struct x509_st X509; + +struct evp_pkey_st; +typedef struct evp_pkey_st EVP_PKEY; + +struct evp_pkey_st { + + void *pkey_pm; +}; + +struct x509_st { + + /* X509 certification platform private point */ + void *x509_pm; +}; + +struct cert_st { + + int sec_level; + + X509 *x509; + + EVP_PKEY *pkey; + +}; + +struct ossl_statem_st { + MSG_FLOW_STATE state; + + int hand_state; +}; + +struct record_layer_st { + + int rstate; + + int read_ahead; +}; + +struct ssl_session_st { + + long timeout; + + long time; +}; + +struct ssl_ctx_st +{ + int version; + + int references; + + unsigned long options; + + #if 0 + struct alpn_protocols alpn_protocol; + #endif + + const SSL_METHOD *method; + + CERT *cert; + + X509 *client_CA; + + int verify_mode; + + long session_timeout; + + int read_ahead; +}; + +struct ssl_st +{ + /* protocol version(one of SSL3.0, TLS1.0, etc.) */ + int version; + + unsigned long options; + + /* shut things down(0x01 : sent, 0x02 : received) */ + int shutdown; + + CERT *cert; + + SSL_CTX *ctx; + + const SSL_METHOD *method; + + RECORD_LAYER rlayer; + + /* where we are */ + OSSL_STATEM statem; + + SSL_SESSION session; + + int rwstate; + + int err; + + void (*info_callback) (const SSL *ssl, int type, int val); + + /* SSL low-level system arch point */ + void *ssl_pm; +}; + +struct ssl_method_st { + /* protocol version(one of SSL3.0, TLS1.0, etc.) */ + int version; + + /* SSL mode(client(0) , server(1), not known(-1)) */ + int endpoint; + + const SSL_METHOD_FUNC *func; +}; + +struct ssl_method_func_st { + + int (*ssl_new)(SSL *ssl); + + void (*ssl_free)(SSL *ssl); + + int (*ssl_handshake)(SSL *ssl); + + int (*ssl_shutdown)(SSL *ssl); + + int (*ssl_clear)(SSL *ssl); + + int (*ssl_read)(SSL *ssl, void *buffer, int len); + + int (*ssl_send)(SSL *ssl, const void *buffer, int len); + + int (*ssl_pending)(const SSL *ssl); + + void (*ssl_set_fd)(SSL *ssl, int fd, int mode); + + int (*ssl_get_fd)(const SSL *ssl, int mode); + + void (*ssl_set_bufflen)(SSL *ssl, int len); + + OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl); +}; + +typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, + unsigned char *outlen, const unsigned char *in, + unsigned int inlen, void *arg); + +#endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h new file mode 100644 index 0000000000..28a7baf513 --- /dev/null +++ b/components/openssl/include/internal/ssl_x509.h @@ -0,0 +1,12 @@ +#ifndef _SSL_X509_H_ +#define _SSL_X509_H_ + +#include "ssl_types.h" + +X509* sk_X509_NAME_new_null(void); + +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); + +void X509_free(X509 *cert); + +#endif diff --git a/components/openssl/include/internal/tls1.h b/components/openssl/include/internal/tls1.h new file mode 100644 index 0000000000..70de22bb5b --- /dev/null +++ b/components/openssl/include/internal/tls1.h @@ -0,0 +1,33 @@ +#ifndef _TLS1_H_ +#define _TLS1_H_ + +# define TLS1_AD_DECRYPTION_FAILED 21 +# define TLS1_AD_RECORD_OVERFLOW 22 +# define TLS1_AD_UNKNOWN_CA 48/* fatal */ +# define TLS1_AD_ACCESS_DENIED 49/* fatal */ +# define TLS1_AD_DECODE_ERROR 50/* fatal */ +# define TLS1_AD_DECRYPT_ERROR 51 +# define TLS1_AD_EXPORT_RESTRICTION 60/* fatal */ +# define TLS1_AD_PROTOCOL_VERSION 70/* fatal */ +# define TLS1_AD_INSUFFICIENT_SECURITY 71/* fatal */ +# define TLS1_AD_INTERNAL_ERROR 80/* fatal */ +# define TLS1_AD_INAPPROPRIATE_FALLBACK 86/* fatal */ +# define TLS1_AD_USER_CANCELLED 90 +# define TLS1_AD_NO_RENEGOTIATION 100 +/* codes 110-114 are from RFC3546 */ +# define TLS1_AD_UNSUPPORTED_EXTENSION 110 +# define TLS1_AD_CERTIFICATE_UNOBTAINABLE 111 +# define TLS1_AD_UNRECOGNIZED_NAME 112 +# define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 +# define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 +# define TLS1_AD_UNKNOWN_PSK_IDENTITY 115/* fatal */ +# define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */ + +/* Special value for method supporting multiple versions */ +#define TLS_ANY_VERSION 0x10000 + +#define TLS1_VERSION 0x0301 +#define TLS1_1_VERSION 0x0302 +#define TLS1_2_VERSION 0x0303 + +#endif diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index b7b784fe71..89cb5bb9f7 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -1,7 +1,7 @@ #ifndef HEADER_SSL_H #define HEADER_SSL_H -#include "ssl_types.h" +#include "internal/ssl_types.h" /* { @@ -186,6 +186,15 @@ const SSL_METHOD* SSLv3_client_method(void); */ const SSL_METHOD* TLSv1_1_client_method(void); +/* + * TLSv1_1_client_method - create the target SSL context client method + * + * @param none + * + * @return the TLSV1.2 version SSL context client method + */ +const SSL_METHOD* TLSv1_2_client_method(void); + /* * SSLv23_server_method - create the target SSL context server method @@ -205,6 +214,15 @@ const SSL_METHOD* SSLv23_server_method(void); */ const SSL_METHOD* TLSv1_1_server_method(void); +/* + * TLSv1_1_server_method - create the target SSL context server method + * + * @param none + * + * @return the TLSV1.2 version SSL context server method + */ +const SSL_METHOD* TLSv1_2_server_method(void); + /* * TLSv1_server_method - create the target SSL context server method * @@ -774,7 +792,7 @@ int SSL_get_wfd(const SSL *ssl); * SSL_set_read_ahead - set the SSL if we can read as many as data * * @param ssl - SSL point - * @param yes - enbale the function + * @param yes - enable the function * * @return none */ @@ -813,7 +831,9 @@ long SSL_CTX_get_read_ahead(SSL_CTX *ctx); * * @param ssl - SSL point * - * @return SSL context ahead signal + * @return + * 1 : there are bytes to be read + * 0 : no data */ int SSL_has_pending(const SSL *ssl); @@ -840,7 +860,7 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);//loads the certificate x int * 1 : OK * 0 : failed */ -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, unsigned char *d); +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); /* * SSL_CTX_use_certificate_file - load the certification file into SSL context @@ -879,7 +899,7 @@ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); * 1 : OK * 0 : failed */ -int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, unsigned char *d, long len);//adds the private key of type pk stored at memory location d (length len) to ctx +int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len);//adds the private key of type pk stored at memory location d (length len) to ctx /* * SSL_CTX_use_certificate_file - load the private key file into SSL context @@ -1648,4 +1668,5 @@ const char *SSL_get_psk_identity_hint(SSL *ssl); */ const char *SSL_get_psk_identity(SSL *ssl); + #endif diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h new file mode 100644 index 0000000000..c75ae95af5 --- /dev/null +++ b/components/openssl/include/platform/ssl_pm.h @@ -0,0 +1,41 @@ +#ifndef _SSL_PM_H_ +#define _SSL_PM_H_ + +#include "ssl_types.h" +#include "esp_common.h" + +void* ssl_zalloc(size_t size); +void *ssl_malloc(size_t size); +void ssl_free(void *p); +void* ssl_memcpy(void *to, const void *from, size_t size); + +int ssl_pm_new(SSL *ssl); +void ssl_pm_free(SSL *ssl); + +int ssl_pm_handshake(SSL *ssl); +int ssl_pm_shutdown(SSL *ssl); +int ssl_pm_clear(SSL *ssl); + +int ssl_pm_read(SSL *ssl, void *buffer, int len); +int ssl_pm_send(SSL *ssl, const void *buffer, int len); +int ssl_pm_pending(const SSL *ssl); + +void ssl_pm_set_fd(SSL *ssl, int fd, int mode); +int ssl_pm_get_fd(const SSL *ssl, int mode); + +OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl); + +void ssl_pm_set_bufflen(SSL *ssl, int len); + +void* x509_pm_new(void); +void x509_pm_free(void *pm); +int x509_pm_load_crt(void *pm, const unsigned char *buffer, int len); +void x509_pm_unload_crt(void *pm); +void x509_pm_start_ca(void *ssl, void *pm); + +void* pkey_pm_new(void); +void pkey_pm_free(void *pm); +int pkey_pm_load_crt(void *pm, const unsigned char *buffer, int len); +void pkey_pm_unload_crt(void *pm); + +#endif diff --git a/components/openssl/library/Makefile b/components/openssl/library/Makefile new file mode 100644 index 0000000000..10f4067c64 --- /dev/null +++ b/components/openssl/library/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = liblibrary.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c new file mode 100644 index 0000000000..10f723bfcb --- /dev/null +++ b/components/openssl/library/ssl_cert.c @@ -0,0 +1,28 @@ +#include "ssl_cert.h" +#include "ssl_pm.h" + +CERT *ssl_cert_new(void) +{ + return ssl_zalloc(sizeof(CERT)); +} + +void ssl_cert_free(CERT *c) +{ + if (c->x509) + X509_free(c->x509); + + if (c->pkey) + EVP_PKEY_free(c->pkey); + + ssl_free(c); +} + +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + ctx->client_CA = x; + + return 1; +} diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c new file mode 100644 index 0000000000..ad78f3961a --- /dev/null +++ b/components/openssl/library/ssl_lib.c @@ -0,0 +1,1622 @@ +#include "ssl_lib.h" +#include "ssl_pkey.h" +#include "ssl_cert.h" +#include "ssl_dbg.h" +#include "ssl_pm.h" + +#define SSL_SEND_DATA_MAX_LENGTH 1460 + +static int ossl_statem_in_error(const SSL *ssl) +{ + if (ssl->statem.state == MSG_FLOW_ERROR) + return 1; + + return 0; +} + +/* + * SSL_get_error - 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) +{ + int ret = SSL_ERROR_SYSCALL; + + SSL_ASSERT(ssl); + + if (ret_code > 0) + ret = SSL_ERROR_NONE; + else if (ret_code < 0) + { + if (SSL_want_read(ssl)) + ret = SSL_ERROR_WANT_READ; + else if (SSL_want_write(ssl)) + ret = SSL_ERROR_WANT_WRITE; + else + ret = SSL_ERROR_SYSCALL; //unknown + } + else // ret_code == 0 + { + if (ssl->shutdown & SSL_RECEIVED_SHUTDOWN) + ret = SSL_ERROR_ZERO_RETURN; + else + ret = SSL_ERROR_SYSCALL; + } + + return ret; +} + +/* + * SSL_get_state - get the SSL state + * + * @param ssl - SSL point + * + * @return SSL state + */ +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) +{ + OSSL_HANDSHAKE_STATE state; + + SSL_ASSERT(ssl); + + state = ssl->method->func->ssl_get_state(ssl); + + return state; +} + +/* + * SSL_CTX_new - create a SSL context + * + * @param method - the SSL context configuration file + * + * @return the context point, if create failed return NULL + */ +SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) +{ + int ret; + SSL_CTX *ctx; + CERT *cert; + X509 *client_ca; + + if (!method) SSL_RET(go_failed1, "method\n"); + + client_ca = sk_X509_NAME_new_null(); + if (!client_ca) + SSL_ERR(-2, go_failed1, "ssl_ctx_new:ctx:[%d]\n", ret); + + cert = ssl_cert_new(); + if (!cert) + SSL_ERR(-2, go_failed2, "ssl_ctx_new:ctx:[%d]\n", ret); + + ctx = (SSL_CTX *)ssl_zalloc(sizeof(SSL_CTX)); + if (!ctx) + SSL_ERR(-2, go_failed3, "ssl_ctx_new:ctx:[%d]\n", ret); + + ctx->method = method; + ctx->cert = cert; + ctx->client_CA = client_ca; + + ctx->version = method->version; + + return ctx; + +go_failed3: + ssl_cert_free(cert); +go_failed2: + X509_free(client_ca); +go_failed1: + return NULL; +} + +/* + * SSL_CTX_free - free a SSL context + * + * @param method - the SSL context point + * + * @return none + */ +void SSL_CTX_free(SSL_CTX* ctx) +{ + SSL_ASSERT(ctx); + + ssl_cert_free(ctx->cert); + + X509_free(ctx->client_CA); + + ssl_free(ctx); +} + +/* + * SSL_CTX_set_ssl_version - set the SSL context version + * + * @param ctx - SSL context point + * @param meth - SSL method point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(meth); + + ctx->method = meth; + + return 1; +} + +/* + * SSL_CTX_get_ssl_method - get the SSL context current method + * + * @param ctx - SSL context point + * + * @return the SSL context current method + */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->method; +} + +/* + * SSL_new - create a SSL + * + * @param ctx - the SSL context point + * + * @return the SSL point or NULL if failed + */ +SSL *SSL_new(SSL_CTX *ctx) +{ + int ret; + void *ssl_pm; + SSL *ssl; + + if (!ctx) + SSL_RET(failed1, "ctx:NULL\n"); + + ssl = (SSL *)ssl_zalloc(sizeof(SSL)); + if (!ssl) + SSL_RET(failed1, "ssl_zalloc\n"); + + ssl->ctx = ctx; + ssl->method = ctx->method; + + ssl->version = ctx->version; + ssl->options = ctx->options; + + ret = ssl->method->func->ssl_new(ssl); + if (ret) + SSL_RET(failed2, "ssl_new\n"); + + return ssl; + +failed2: + ssl_free(ssl); +failed1: + return NULL; +} + +/* + * SSL_free - free the SSL + * + * @param ssl - the SSL point + * + * @return none + */ +void SSL_free(SSL *ssl) +{ + SSL_ASSERT(ssl); + + ssl->method->func->ssl_free(ssl); + + ssl_free(ssl); +} + +/* + * SSL_do_handshake - perform the SSL handshake + * + * @param ssl - SSL point + * + * @return + * 1 : OK + * 0 : failed + * -1 : a error catch + */ +int SSL_do_handshake(SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = ssl->method->func->ssl_handshake(ssl); + + return ret; +} + +/* + * SSL_connect - connect to the remote SSL server + * + * @param ssl - the SSL point + * + * @return + * 1 : OK + * -1 : failed + */ +int SSL_connect(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return SSL_do_handshake(ssl); +} + +/* + * SSL_accept - accept the remote connection + * + * @param ssl - the SSL point + * + * @return + * 1 : OK + * -1 : failed + */ +int SSL_accept(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return SSL_do_handshake(ssl); +} + +/* + * SSL_shutdown - shutdown the connection + * + * @param ssl - the SSL point + * + * @return + * 1 : OK + * 0 : shutdown is not finished + * -1 : an error catch + */ +int SSL_shutdown(SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + if (SSL_get_state(ssl) != TLS_ST_OK) return 0; + + ret = ssl->method->func->ssl_shutdown(ssl); + + return ret; +} + +/* + * SSL_clear - reset the SSL + * + * @param ssl - SSL point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_clear(SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = SSL_shutdown(ssl); + if (1 != ret) + SSL_ERR(0, go_failed1, "SSL_shutdown\n"); + + ssl->method->func->ssl_free(ssl); + + ret = ssl->method->func->ssl_new(ssl); + if (!ret) + SSL_ERR(0, go_failed1, "ssl_new\n"); + + return 1; + +go_failed1: + return ret; +} + +/* + * SSL_read - read data from to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the received data buffer point + * @param len - the received data length + * + * @return + * > 0 : OK, and return received data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_read(SSL *ssl, void *buffer, int len) +{ + int ret; + + SSL_ASSERT(ssl); + SSL_ASSERT(buffer); + SSL_ASSERT(len); + + ret = ssl->method->func->ssl_read(ssl, buffer, len); + + return ret; +} + +/* + * SSL_write - send the data to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the send data buffer point + * @param len - the send data length + * + * @return + * > 0 : OK, and return sent data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_write(SSL *ssl, const void *buffer, int len) +{ + int ret; + int send_bytes; + const unsigned char *pbuf; + + SSL_ASSERT(ssl); + SSL_ASSERT(buffer); + SSL_ASSERT(len); + + send_bytes = len; + pbuf = (const unsigned char *)buffer; + + do { + int bytes; + + if (send_bytes > SSL_SEND_DATA_MAX_LENGTH) + bytes = SSL_SEND_DATA_MAX_LENGTH; + else + bytes = send_bytes; + + ret = ssl->method->func->ssl_send(ssl, buffer, len); + if (ret > 0) { + pbuf += ret; + send_bytes -= ret; + } + } while (ret > 0 && send_bytes); + + send_bytes = len - send_bytes; + if (send_bytes >= 0) + ret = send_bytes; + else + ret = -1; + + return ret; +} + +/* + * SSL_get_SSL_CTX - get SSL context of the SSL + * + * @param ssl - SSL point + * + * @return SSL context + */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->ctx; +} + +/* + * SSL_CTX_get_ssl_method - get the SSL current method + * + * @param ssl - SSL point + * + * @return the SSL current method + */ +const SSL_METHOD *SSL_get_ssl_method(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->method; +} + +/* + * SSL_set_ssl_method - set the SSL method + * + * @param ssl - SSL point + * @param meth - SSL method point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method) +{ + int ret; + + SSL_ASSERT(ssl); + SSL_ASSERT(method); + + if (ssl->version != method->version) { + + ret = SSL_shutdown(ssl); + if (1 != ret) + SSL_ERR(0, go_failed1, "SSL_shutdown\n"); + + ssl->method->func->ssl_free(ssl); + + ssl->method = method; + + ret = ssl->method->func->ssl_new(ssl); + if (!ret) + SSL_ERR(0, go_failed1, "ssl_new\n"); + } else { + ssl->method = method; + } + + + return 1; + +go_failed1: + return ret; +} + +/* + * SSL_get_shutdown - get SSL shutdown mode + * + * @param ssl - SSL point + * + * @return shutdown mode + */ +int SSL_get_shutdown(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->shutdown; +} + +/* + * SSL_set_quiet_shutdown - set SSL shutdown mode + * + * @param ssl - SSL point + * @param mode - shutdown mode + * + * @return none + */ +void SSL_set_shutdown(SSL *ssl, int mode) +{ + SSL_ASSERT(ssl); + + ssl->shutdown = mode; +} + + +/* + * SSL_pending - get the number of the bytes to be read + * + * @param ssl - SSL point + * + * @return number of the bytes + */ +int SSL_pending(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = ssl->method->func->ssl_pending(ssl); + + return ret; +} + +/* + * SSL_has_pending - check if some data can be read + * + * @param ssl - SSL point + * + * @return + * 1 : there are bytes to be read + * 0 : no data + */ +int SSL_has_pending(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + if (SSL_pending(ssl)) + ret = 1; + else + ret = 0; + + return ret; +} + +/* + * SSL_CTX_clear_options - clear the SSL context option bit of "op" + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op) +{ + return ctx->options &= ~op; +} + +/* + * SSL_CTX_clear_options - get the SSL context option + * + * @param ctx - SSL context point + * @param op - option + * + * @return SSL context option + */ +unsigned long SSL_CTX_get_options(SSL_CTX *ctx) +{ + return ctx->options; +} + +/* + * SSL_CTX_set_option - set the option of the SSL context + * + * @param ctx - the SSL context + * + * @return the SSL context option + * + */ +unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt) +{ + return ctx->options |= opt; +} + +/* + * SSL_clear_options - clear SSL option + * + * @param ssl - SSL point + * @param op - clear option + * + * @return SSL option + */ +unsigned long SSL_clear_options(SSL *ssl, unsigned long op) +{ + SSL_ASSERT(ssl); + + return ssl->options & ~op; +} + +/* + * SSL_clear_options - get SSL option + * + * @param ssl - SSL point + * + * @return SSL option + */ +unsigned long SSL_get_options(SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->options; +} + +/* + * SSL_clear_options - clear SSL option + * + * @param ssl - SSL point + * @param op - setting option + * + * @return SSL option + */ +unsigned long SSL_set_options(SSL *ssl, unsigned long op) +{ + SSL_ASSERT(ssl); + + return ssl->options |= op; +} + +/* + * SSL_get_fd - get the socket handle of the SSL + * + * @param ssl - SSL point + * + * @return + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_fd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = ssl->method->func->ssl_get_fd(ssl, 0); + + return ret; +} + +/* + * SSL_get_rfd - get the read only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_rfd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = ssl->method->func->ssl_get_fd(ssl, 0); + + return ret; +} + +/* + * SSL_get_wfd - get the write only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_wfd(const SSL *ssl) +{ + int ret; + + SSL_ASSERT(ssl); + + ret = ssl->method->func->ssl_get_fd(ssl, 0); + + return ret; +} + +/* + * SSL_set_fd - bind the socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_set_fd(SSL *ssl, int fd) +{ + int ret; + + SSL_ASSERT(ssl); + SSL_ASSERT(fd >= 0); + + ssl->method->func->ssl_set_fd(ssl, fd, 0); + + return 1; +} + +/* + * SSL_set_fd - bind the read only socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_set_rfd(SSL *ssl, int fd) +{ + int ret; + + SSL_ASSERT(ssl); + SSL_ASSERT(fd >= 0); + + ssl->method->func->ssl_set_fd(ssl, fd, 0); + + return 1; +} + +/* + * SSL_set_fd - bind the write only socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_set_wfd(SSL *ssl, int fd) +{ + int ret; + + SSL_ASSERT(ssl); + SSL_ASSERT(fd >= 0); + + ssl->method->func->ssl_set_fd(ssl, fd, 0); + + return 1; +} + +/* + * SSL_version - get SSL version + * + * @param ssl - SSL point + * + * @return SSL version + */ +int SSL_version(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->version; +} + +/* + * ssl_protocol_to_string - get the SSL version string + * + * @param version - the SSL version + * + * @return the SSL version string + */ +static const char* ssl_protocol_to_string(int version) +{ + const char *str; + + if (version == TLS1_2_VERSION) + str = "TLSv1.2"; + else if (version == TLS1_1_VERSION) + str = "TLSv1.1"; + else if (version == TLS1_VERSION) + str = "TLSv1"; + else if (version == SSL3_VERSION) + str = "SSLv3"; + else + str = "unknown"; + + return str; +} + +/* + * SSL_get_version - get the SSL current version + * + * @param ssl - SSL point + * + * @return the version string + */ +const char *SSL_get_version(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl_protocol_to_string(SSL_version(ssl)); +} + +/* + * SSL_alert_desc_string - get alert description string + * + * @param value - alert value + * + * @return alert description string + */ +const char* SSL_alert_desc_string(int value) +{ + const char *str; + + switch (value & 0xff) + { + case SSL3_AD_CLOSE_NOTIFY: + str = "CN"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "UM"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "BM"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "DF"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "HF"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "NC"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "BC"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "UC"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "CR"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "CE"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "CU"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "IP"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "DC"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "RO"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "AD"; + break; + case TLS1_AD_DECODE_ERROR: + str = "DE"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "CY"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "ER"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "PV"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "IS"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "IE"; + break; + case TLS1_AD_USER_CANCELLED: + str = "US"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "NR"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "UE"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "CO"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "UN"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "BR"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "BH"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "UP"; + break; + default: + str = "UK"; + break; + } + + return str; +} + +/* + * SSL_alert_desc_string - get alert description long string + * + * @param value - alert value + * + * @return alert description long string + */ +const char* SSL_alert_desc_string_long(int value) +{ + const char *str; + + switch (value & 0xff) + { + case SSL3_AD_CLOSE_NOTIFY: + str = "close notify"; + break; + case SSL3_AD_UNEXPECTED_MESSAGE: + str = "unexpected_message"; + break; + case SSL3_AD_BAD_RECORD_MAC: + str = "bad record mac"; + break; + case SSL3_AD_DECOMPRESSION_FAILURE: + str = "decompression failure"; + break; + case SSL3_AD_HANDSHAKE_FAILURE: + str = "handshake failure"; + break; + case SSL3_AD_NO_CERTIFICATE: + str = "no certificate"; + break; + case SSL3_AD_BAD_CERTIFICATE: + str = "bad certificate"; + break; + case SSL3_AD_UNSUPPORTED_CERTIFICATE: + str = "unsupported certificate"; + break; + case SSL3_AD_CERTIFICATE_REVOKED: + str = "certificate revoked"; + break; + case SSL3_AD_CERTIFICATE_EXPIRED: + str = "certificate expired"; + break; + case SSL3_AD_CERTIFICATE_UNKNOWN: + str = "certificate unknown"; + break; + case SSL3_AD_ILLEGAL_PARAMETER: + str = "illegal parameter"; + break; + case TLS1_AD_DECRYPTION_FAILED: + str = "decryption failed"; + break; + case TLS1_AD_RECORD_OVERFLOW: + str = "record overflow"; + break; + case TLS1_AD_UNKNOWN_CA: + str = "unknown CA"; + break; + case TLS1_AD_ACCESS_DENIED: + str = "access denied"; + break; + case TLS1_AD_DECODE_ERROR: + str = "decode error"; + break; + case TLS1_AD_DECRYPT_ERROR: + str = "decrypt error"; + break; + case TLS1_AD_EXPORT_RESTRICTION: + str = "export restriction"; + break; + case TLS1_AD_PROTOCOL_VERSION: + str = "protocol version"; + break; + case TLS1_AD_INSUFFICIENT_SECURITY: + str = "insufficient security"; + break; + case TLS1_AD_INTERNAL_ERROR: + str = "internal error"; + break; + case TLS1_AD_USER_CANCELLED: + str = "user canceled"; + break; + case TLS1_AD_NO_RENEGOTIATION: + str = "no renegotiation"; + break; + case TLS1_AD_UNSUPPORTED_EXTENSION: + str = "unsupported extension"; + break; + case TLS1_AD_CERTIFICATE_UNOBTAINABLE: + str = "certificate unobtainable"; + break; + case TLS1_AD_UNRECOGNIZED_NAME: + str = "unrecognized name"; + break; + case TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE: + str = "bad certificate status response"; + break; + case TLS1_AD_BAD_CERTIFICATE_HASH_VALUE: + str = "bad certificate hash value"; + break; + case TLS1_AD_UNKNOWN_PSK_IDENTITY: + str = "unknown PSK identity"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/* + * SSL_alert_type_string - get alert type string + * + * @param value - alert value + * + * @return alert type string + */ +const char *SSL_alert_type_string(int value) +{ + const char *str; + + switch (value >> 8) + { + case SSL3_AL_WARNING: + str = "W"; + break; + case SSL3_AL_FATAL: + str = "F"; + break; + default: + str = "U"; + break; + } + + return str; +} + +/* + * SSL_alert_type_string_long - get alert type long string + * + * @param value - alert value + * + * @return alert type long string + */ +const char *SSL_alert_type_string_long(int value) +{ + const char *str; + + switch (value >> 8) + { + case SSL3_AL_WARNING: + str = "warning"; + break; + case SSL3_AL_FATAL: + str = "fatal"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/* + * SSL_rstate_string - get the state string where SSL is reading + * + * @param ssl - SSL point + * + * @return state string + */ +const char *SSL_rstate_string(SSL *ssl) +{ + const char *str; + + SSL_ASSERT(ssl); + + switch (ssl->rlayer.rstate) + { + case SSL_ST_READ_HEADER: + str = "RH"; + break; + case SSL_ST_READ_BODY: + str = "RB"; + break; + case SSL_ST_READ_DONE: + str = "RD"; + break; + default: + str = "unknown"; + break; + } + + return str; +} + +/* + * SSL_rstate_string_long - get the statement long string where SSL is reading + * + * @param ssl - SSL point + * + * @return statement long string + */ +const char *SSL_rstate_string_long(SSL *ssl) +{ + const char *str = "unknown"; + + SSL_ASSERT(ssl); + + switch (ssl->rlayer.rstate) + { + case SSL_ST_READ_HEADER: + str = "read header"; + break; + case SSL_ST_READ_BODY: + str = "read body"; + break; + case SSL_ST_READ_DONE: + str = "read done"; + break; + default: + break; + } + + return str; +} + +/* + * SSL_state_string - get SSL statement string + * + * @param ssl - SSL point + * + * @return SSL statement string + */ +char *SSL_state_string(const SSL *ssl) +{ + char *str = "UNKWN "; + + SSL_ASSERT(ssl); + + if (ossl_state_in_error(ssl)) + str = "SSLERR"; + else + { + switch (SSL_get_state(ssl)) + { + case TLS_ST_BEFORE: + str = "PINIT "; + break; + case TLS_ST_OK: + str = "SSLOK "; + break; + case TLS_ST_CW_CLNT_HELLO: + str = "TWCH"; + break; + case TLS_ST_CR_SRVR_HELLO: + str = "TRSH"; + break; + case TLS_ST_CR_CERT: + str = "TRSC"; + break; + case TLS_ST_CR_KEY_EXCH: + str = "TRSKE"; + break; + case TLS_ST_CR_CERT_REQ: + str = "TRCR"; + break; + case TLS_ST_CR_SRVR_DONE: + str = "TRSD"; + break; + case TLS_ST_CW_CERT: + str = "TWCC"; + break; + case TLS_ST_CW_KEY_EXCH: + str = "TWCKE"; + break; + case TLS_ST_CW_CERT_VRFY: + str = "TWCV"; + break; + case TLS_ST_SW_CHANGE: + case TLS_ST_CW_CHANGE: + str = "TWCCS"; + break; + case TLS_ST_SW_FINISHED: + case TLS_ST_CW_FINISHED: + str = "TWFIN"; + break; + case TLS_ST_SR_CHANGE: + case TLS_ST_CR_CHANGE: + str = "TRCCS"; + break; + case TLS_ST_SR_FINISHED: + case TLS_ST_CR_FINISHED: + str = "TRFIN"; + break; + case TLS_ST_SW_HELLO_REQ: + str = "TWHR"; + break; + case TLS_ST_SR_CLNT_HELLO: + str = "TRCH"; + break; + case TLS_ST_SW_SRVR_HELLO: + str = "TWSH"; + break; + case TLS_ST_SW_CERT: + str = "TWSC"; + break; + case TLS_ST_SW_KEY_EXCH: + str = "TWSKE"; + break; + case TLS_ST_SW_CERT_REQ: + str = "TWCR"; + break; + case TLS_ST_SW_SRVR_DONE: + str = "TWSD"; + break; + case TLS_ST_SR_CERT: + str = "TRCC"; + break; + case TLS_ST_SR_KEY_EXCH: + str = "TRCKE"; + break; + case TLS_ST_SR_CERT_VRFY: + str = "TRCV"; + break; + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + str = "DRCHV"; + break; + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + str = "DWCHV"; + break; + default: + break; + } + } + + return str; +} + +/* + * SSL_state_string_long - get SSL statement long string + * + * @param ssl - SSL point + * + * @return SSL statement long string + */ +char *SSL_state_string_long(const SSL *ssl) +{ + char *str = "UNKWN "; + + SSL_ASSERT(ssl); + + if (ossl_statem_in_error(ssl)) + str = "SSLERR"; + else + { + switch (SSL_get_state(ssl)) + { + case TLS_ST_BEFORE: + str = "before SSL initialization"; + break; + case TLS_ST_OK: + str = "SSL negotiation finished successfully"; + break; + case TLS_ST_CW_CLNT_HELLO: + str = "SSLv3/TLS write client hello"; + break; + case TLS_ST_CR_SRVR_HELLO: + str = "SSLv3/TLS read server hello"; + break; + case TLS_ST_CR_CERT: + str = "SSLv3/TLS read server certificate"; + break; + case TLS_ST_CR_KEY_EXCH: + str = "SSLv3/TLS read server key exchange"; + break; + case TLS_ST_CR_CERT_REQ: + str = "SSLv3/TLS read server certificate request"; + break; + case TLS_ST_CR_SESSION_TICKET: + str = "SSLv3/TLS read server session ticket"; + break; + case TLS_ST_CR_SRVR_DONE: + str = "SSLv3/TLS read server done"; + break; + case TLS_ST_CW_CERT: + str = "SSLv3/TLS write client certificate"; + break; + case TLS_ST_CW_KEY_EXCH: + str = "SSLv3/TLS write client key exchange"; + break; + case TLS_ST_CW_CERT_VRFY: + str = "SSLv3/TLS write certificate verify"; + break; + case TLS_ST_CW_CHANGE: + case TLS_ST_SW_CHANGE: + str = "SSLv3/TLS write change cipher spec"; + break; + case TLS_ST_CW_FINISHED: + case TLS_ST_SW_FINISHED: + str = "SSLv3/TLS write finished"; + break; + case TLS_ST_CR_CHANGE: + case TLS_ST_SR_CHANGE: + str = "SSLv3/TLS read change cipher spec"; + break; + case TLS_ST_CR_FINISHED: + case TLS_ST_SR_FINISHED: + str = "SSLv3/TLS read finished"; + break; + case TLS_ST_SR_CLNT_HELLO: + str = "SSLv3/TLS read client hello"; + break; + case TLS_ST_SW_HELLO_REQ: + str = "SSLv3/TLS write hello request"; + break; + case TLS_ST_SW_SRVR_HELLO: + str = "SSLv3/TLS write server hello"; + break; + case TLS_ST_SW_CERT: + str = "SSLv3/TLS write certificate"; + break; + case TLS_ST_SW_KEY_EXCH: + str = "SSLv3/TLS write key exchange"; + break; + case TLS_ST_SW_CERT_REQ: + str = "SSLv3/TLS write certificate request"; + break; + case TLS_ST_SW_SESSION_TICKET: + str = "SSLv3/TLS write session ticket"; + break; + case TLS_ST_SW_SRVR_DONE: + str = "SSLv3/TLS write server done"; + break; + case TLS_ST_SR_CERT: + str = "SSLv3/TLS read client certificate"; + break; + case TLS_ST_SR_KEY_EXCH: + str = "SSLv3/TLS read client key exchange"; + break; + case TLS_ST_SR_CERT_VRFY: + str = "SSLv3/TLS read certificate verify"; + break; + case DTLS_ST_CR_HELLO_VERIFY_REQUEST: + str = "DTLS1 read hello verify request"; + break; + case DTLS_ST_SW_HELLO_VERIFY_REQUEST: + str = "DTLS1 write hello verify request"; + break; + default: + break; + } + } + + return str; +} + +/* + * SSL_CTX_set_default_read_buffer_len - set the SSL context read buffer length + * + * @param ctx - SSL context point + * @param len - read buffer length + * + * @return none + */ +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(len); + + ctx->method->func->ssl_set_bufflen(NULL, len); +} + +/* + * SSL_set_default_read_buffer_len - set the SSL read buffer length + * + * @param ssl - SSL point + * @param len - read buffer length + * + * @return none + */ +void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(len); + + ssl->method->func->ssl_set_bufflen(ssl, len); +} + +/* + * SSL_set_info_callback - set the SSL information callback function + * + * @param ssl - SSL point + * @param cb - information callback function + * + * @return none + */ +void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)) +{ + SSL_ASSERT(ssl); + + ssl->info_callback = cb; +} + +/* + * SSL_CTX_up_ref - add SSL context reference count by '1' + * + * @param ctx - SSL context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_up_ref(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + /* no support multi-thread SSL here */ + ctx->references++; + + return 1; +} + +/* + * SSL_set_security_level - set the SSL security level + * + * @param ssl - SSL point + * @param level - security level + * + * @return none + */ +void SSL_set_security_level(SSL *ssl, int level) +{ + SSL_ASSERT(ssl); + + ssl->cert->sec_level = level; +} + +/* + * SSL_get_security_level - get the SSL security level + * + * @param ssl - SSL point + * + * @return security level + */ +int SSL_get_security_level(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->cert->sec_level; +} + +/* + * SSL_CTX_get_verify_mode - get the SSL verifying mode of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying mode + */ +int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->verify_mode; +} + +/* + * SSL_CTX_set_timeout - set the session timeout time + * + * @param ctx - SSL context point + * @param t - new session timeout time + * + * @return old session timeout time + */ +long SSL_CTX_set_timeout(SSL_CTX *ctx, long t) +{ + long l; + + SSL_ASSERT(ctx); + + l = ctx->session_timeout; + ctx->session_timeout = t; + + return l; +} + +/* + * SSL_CTX_get_timeout - get the session timeout time + * + * @param ctx - SSL context point + * + * @return current session timeout time + */ +long SSL_CTX_get_timeout(const SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->session_timeout; +} + +/* + * SSL_set_read_ahead - set the SSL if we can read as many as data + * + * @param ssl - SSL point + * @param yes - enable the function + * + * @return none + */ +void SSL_set_read_ahead(SSL *ssl, int yes) +{ + SSL_ASSERT(ssl); + + ssl->rlayer.read_ahead = yes; +} + +/* + * SSL_set_read_ahead - set the SSL context if we can read as many as data + * + * @param ctx - SSL context point + * @param yes - enable the function + * + * @return none + */ +void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) +{ + SSL_ASSERT(ctx); + + ctx->read_ahead = yes; +} + +/* + * SSL_set_read_ahead - get the SSL ahead signal if we can read as many as data + * + * @param ssl - SSL point + * + * @return SSL context ahead signal + */ +int SSL_get_read_ahead(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->rlayer.read_ahead; +} + +/* + * SSL_set_read_ahead - get the SSL context ahead signal if we can read as many as data + * + * @param ctx - SSL context point + * + * @return SSL context ahead signal + */ +long SSL_CTX_get_read_ahead(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->read_ahead; +} + +/* + * SSL_CTX_get_ciphers - check if the SSL context can read as many as data + * + * @param ctx - SSL context point + * + * @return + * 1 : Yes + * 0 : No + */ +long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->read_ahead; +} + +/* + * SSL_set_time - set SSL session time + * + * @param ssl - SSL point + * @param t - session time + * + * @return session time + */ +long SSL_set_time(SSL *ssl, long t) +{ + SSL_ASSERT(ssl); + + ssl->session.time = t; + + return t; +} + +/* + * SSL_set_time - set SSL session timeout time + * + * @param ssl - SSL point + * @param t - session timeout time + * + * @return session timeout time + */ +long SSL_set_timeout(SSL *ssl, long t) +{ + SSL_ASSERT(ssl); + + ssl->session.timeout = t; + + return t; +} diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c new file mode 100644 index 0000000000..502262f7e9 --- /dev/null +++ b/components/openssl/library/ssl_methods.c @@ -0,0 +1,43 @@ +#include "ssl_lib.h" +#include "ssl_methods.h" +#include "ssl_pm.h" + +IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, + ssl_pm_new, ssl_pm_free, + ssl_pm_handshake, ssl_pm_shutdown, ssl_pm_clear, + ssl_pm_read, ssl_pm_send, ssl_pm_pending, + ssl_pm_set_fd, ssl_pm_get_fd, + ssl_pm_set_bufflen, + ssl_pm_get_state); + +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 0, TLS_method_func, TLS_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 0, TLS_method_func, TLSv1_2_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 0, TLS_method_func, TLSv1_1_client_method); + +IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_client_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, 0, TLS_method_func, SSLv3_client_method); + + +IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 1, TLS_method_func, TLS_server_method); + +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_VERSION, 0, TLS_method_func, TLSv1_server_method); + +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_SSL_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_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method); + +IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c new file mode 100644 index 0000000000..2a170716c0 --- /dev/null +++ b/components/openssl/library/ssl_pkey.c @@ -0,0 +1,50 @@ +#include "ssl_lib.h" +#include "ssl_pkey.h" +#include "ssl_dbg.h" +#include "ssl_pm.h" + +EVP_PKEY *d2i_PrivateKey(int type, + EVP_PKEY **a, + const unsigned char **pp, + long length) +{ + EVP_PKEY *pkey; + void *pkey_pm; + int ret; + + SSL_ASSERT(pp); + SSL_ASSERT(*pp); + SSL_ASSERT(length); + + pkey = ssl_malloc(sizeof(EVP_PKEY)); + if (!pkey) + SSL_RET(failed1, "ssl_malloc\n"); + + pkey_pm = pkey_pm_new(); + if (!pkey_pm) + SSL_RET(failed2, "pkey_pm_new\n"); + + ret = pkey_pm_load_crt(pkey_pm, *pp, length); + if (ret) + SSL_RET(failed3, "pkey_pm_load_crt\n"); + + pkey->pkey_pm = pkey_pm; + if (a) + *a = pkey; + + return pkey; + +failed3: + pkey_pm_free(pkey_pm); +failed2: + ssl_free(pkey); +failed1: + return NULL; +} + +void EVP_PKEY_free(EVP_PKEY *x) +{ + pkey_pm_unload_crt(x->pkey_pm); + pkey_pm_free(x->pkey_pm); + ssl_free(x); +} diff --git a/components/openssl/library/ssl_rsa.c b/components/openssl/library/ssl_rsa.c new file mode 100644 index 0000000000..9088f67f57 --- /dev/null +++ b/components/openssl/library/ssl_rsa.c @@ -0,0 +1,70 @@ +#include "ssl_lib.h" +#include "ssl_rsa.h" +#include "ssl_pkey.h" +#include "ssl_x509.h" +#include "ssl_dbg.h" +#include "ssl_pm.h" + +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + ctx->cert->x509 = x; + + return 1; +} + +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d) +{ + int ret; + X509 *cert; + + cert = d2i_X509(NULL, d, len); + if (!cert) + SSL_RET(failed1, "d2i_X509\n"); + + ret = SSL_CTX_use_certificate(ctx, cert); + if (!ret) + SSL_RET(failed2, "SSL_CTX_use_certificate\n"); + + return 1; + +failed2: + X509_free(cert); +failed1: + return 0; +} + +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(pkey); + + ctx->cert->pkey = pkey; + + return 1; +} + +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, + const unsigned char *d, long len) +{ + int ret; + EVP_PKEY *pkey; + + pkey = d2i_PrivateKey(0, NULL, &d, len); + if (!pkey) + SSL_RET(failed1, "d2i_PrivateKey\n"); + + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + if (!ret) + SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); + + return 1; + +failed2: + EVP_PKEY_free(pkey); +failed1: + return 0; +} diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c new file mode 100644 index 0000000000..23aa00681e --- /dev/null +++ b/components/openssl/library/ssl_x509.c @@ -0,0 +1,54 @@ +#include "ssl_x509.h" +#include "ssl_dbg.h" +#include "ssl_pm.h" + +X509* sk_X509_NAME_new_null(void) +{ + return ssl_malloc(sizeof(X509)); +} + +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) +{ + X509 *x509_crt; + void *x509_pm; + int ret; + + SSL_ASSERT(cert); + SSL_ASSERT(buffer); + SSL_ASSERT(len); + + x509_crt = sk_X509_NAME_new_null(); + if (!x509_crt) + SSL_RET(failed1, ""); + + x509_pm = x509_pm_new(); + if (!x509_pm) + SSL_RET(failed2, ""); + + ret = x509_pm_load_crt(x509_pm, buffer, len); + if (ret) + SSL_RET(failed3, ""); + + x509_crt->x509_pm = x509_pm; + if (cert) + *cert = x509_crt; + + return x509_crt; + +failed3: + x509_pm_free(x509_pm); +failed2: + ssl_free(x509_crt); +failed1: + return NULL; +} + +void X509_free(X509 *cert) +{ + if (cert->x509_pm) { + x509_pm_unload_crt(cert->x509_pm); + x509_pm_free(cert->x509_pm); + } + ssl_free(cert); +}; + diff --git a/components/openssl/platform/Makefile b/components/openssl/platform/Makefile new file mode 100644 index 0000000000..749b4787ca --- /dev/null +++ b/components/openssl/platform/Makefile @@ -0,0 +1,46 @@ + +############################################################# +# Required variables for each makefile +# Discard this section from all parent makefiles +# Expected variables (with automatic defaults): +# CSRCS (all "C" files in the dir) +# SUBDIRS (all subdirs with a Makefile) +# GEN_LIBS - list of libs to be generated () +# GEN_IMAGES - list of images to be generated () +# COMPONENTS_xxx - a list of libs/objs in the form +# subdir/lib to be extracted and rolled up into +# a generated lib/image xxx.a () +# +ifndef PDIR + +GEN_LIBS = libplatform.a + +endif + + +############################################################# +# Configuration i.e. compile options etc. +# Target specific stuff (defines etc.) goes in here! +# Generally values applying to a tree are captured in the +# makefile at its root level - these are then overridden +# for a subtree within the makefile rooted therein +# +#DEFINES += + +############################################################# +# Recursion Magic - Don't touch this!! +# +# Each subtree potentially has an include directory +# corresponding to the common APIs applicable to modules +# rooted at that subtree. Accordingly, the INCLUDE PATH +# of a module can only contain the include directories up +# its parent path, and not its siblings +# +# Required for each makefile to inherit from the parent +# + +INCLUDES := $(INCLUDES) -I $(PDIR)include +INCLUDES += -I ./ +PDIR := ../$(PDIR) +sinclude $(PDIR)Makefile + diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c new file mode 100644 index 0000000000..831420180c --- /dev/null +++ b/components/openssl/platform/ssl_pm.c @@ -0,0 +1,422 @@ +#include "ssl_pm.h" +#include "ssl_dbg.h" + +/* mbedtls include */ +#include "mbedtls/platform.h" +#include "mbedtls/net.h" +#include "mbedtls/debug.h" +#include "mbedtls/entropy.h" +#include "mbedtls/ctr_drbg.h" +#include "mbedtls/error.h" +#include "mbedtls/certs.h" + +struct ssl_pm +{ + /* local socket file description */ + mbedtls_net_context fd; + /* remote client socket file description */ + mbedtls_net_context cl_fd; + + mbedtls_ssl_config conf; + + mbedtls_ctr_drbg_context ctr_drbg; + + mbedtls_ssl_context ssl; + + mbedtls_entropy_context entropy; +}; + +struct x509_pm +{ + mbedtls_x509_crt x509_crt; +}; + +struct pkey_pm +{ + mbedtls_pk_context pkey; +}; + + +unsigned int max_content_len; + + +/*********************************************************************************************/ +/********************************* SSL general interface *************************************/ + +void* ssl_zalloc(size_t size) +{ + void *p = malloc(size); + + if (p) + memset(p, 0, size); + + return p; +} + +void *ssl_malloc(size_t size) +{ + return zalloc(size); +} + +void ssl_free(void *p) +{ + free(p); +} + +void* ssl_memcpy(void *to, const void *from, size_t size) +{ + return memcpy(to, from, size); +} + +void ssl_speed_up_enter(void) +{ + +} + +void ssl_speed_up_exit(void) +{ + +} + +/*********************************************************************************************/ +/************************************ SSL arch interface *************************************/ + +int ssl_pm_new(SSL *ssl) +{ + struct ssl_pm *ssl_pm; + int ret; + + char *pers; + int endpoint; + + SSL_CTX *ctx = ssl->ctx; + const SSL_METHOD *method = ssl->method; + + ssl_pm = malloc(sizeof(struct ssl_pm)); + if (!ssl_pm) + return -1; + + if (method->endpoint) { + pers = "server"; + endpoint = MBEDTLS_SSL_IS_SERVER; + } else { + pers = "client"; + endpoint = MBEDTLS_SSL_IS_CLIENT; + } + + //max_content_len = 4096; + + mbedtls_net_init(&ssl_pm->fd); + mbedtls_net_init(&ssl_pm->cl_fd); + + mbedtls_ssl_config_init(&ssl_pm->conf); + mbedtls_ctr_drbg_init(&ssl_pm->ctr_drbg); + mbedtls_entropy_init(&ssl_pm->entropy); + mbedtls_ssl_init(&ssl_pm->ssl); + + ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, (const unsigned char *)pers, strlen(pers)); + if (ret) + SSL_ERR(ret, failed1, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); + + ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); + if (ret) + SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); + + mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); + mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL); + + if (ctx->client_CA->x509_pm) { + struct x509_pm *x509_pm = (struct x509_pm *)ctx->client_CA->x509_pm; + + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &x509_pm->x509_crt, NULL); + mbedtls_ssl_conf_authmode(&ssl_pm->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + } else { + mbedtls_ssl_conf_authmode(&ssl_pm->conf, MBEDTLS_SSL_VERIFY_NONE); + } + if (ctx->cert->x509 && + ctx->cert->pkey) { + struct x509_pm *x509_pm = (struct x509_pm *)ctx->cert->x509->x509_pm; + struct pkey_pm *pkey_pm = (struct pkey_pm *)ctx->cert->pkey->pkey_pm; + + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); + if (ret) + SSL_ERR(ret, failed4, "mbedtls_ssl_conf_own_cert:[%d]\n", ret); + } + + ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); + if (ret) + SSL_ERR(ret, failed4, "mbedtls_ssl_setup:[-0x%x]\n", -ret); + + mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); + + ssl->ssl_pm = ssl_pm; + + return 0; + +failed4: + mbedtls_ssl_config_free(&ssl_pm->conf); +failed3: + mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); +failed2: + mbedtls_entropy_free(&ssl_pm->entropy); +failed1: + return -1; +} + +void ssl_pm_free(SSL *ssl) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbedtls_ssl_config_free(&ssl_pm->conf); + mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); + mbedtls_entropy_free(&ssl_pm->entropy); + mbedtls_ssl_free(&ssl_pm->ssl); + + mbedtls_net_free(&ssl_pm->fd); + mbedtls_net_free(&ssl_pm->cl_fd); +} + +int ssl_pm_handshake(SSL *ssl) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ssl_speed_up_enter(); + while((mbed_ret = mbedtls_ssl_handshake(&ssl_pm->ssl)) != 0) { + if (mbed_ret != MBEDTLS_ERR_SSL_WANT_READ && mbed_ret != MBEDTLS_ERR_SSL_WANT_WRITE) { + break; + } + } + ssl_speed_up_exit(); + + if (!mbed_ret) + ret = 1; + else { + ret = 0; + SSL_DEBUG(1, "mbedtls_ssl_handshake [-0x%x]\n", -mbed_ret); + } + + return ret; +} + +int ssl_pm_shutdown(SSL *ssl) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbed_ret = mbedtls_ssl_close_notify(&ssl_pm->ssl); + if (!mbed_ret) + ret = 0; + else + ret = -1; + + return ret; +} + +int ssl_pm_clear(SSL *ssl) +{ + return ssl_pm_shutdown(ssl); +} + + +int ssl_pm_read(SSL *ssl, void *buffer, int len) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbed_ret = mbedtls_ssl_read(&ssl_pm->ssl, buffer, len); + if (mbed_ret < 0) + ret = -1; + else if (mbed_ret == 0) + ret = 0; + else + ret = mbed_ret; + + return ret; +} + +int ssl_pm_send(SSL *ssl, const void *buffer, int len) +{ + int ret, mbed_ret; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + mbed_ret = mbedtls_ssl_write(&ssl_pm->ssl, buffer, len); + if (mbed_ret < 0) + ret = -1; + else if (mbed_ret == 0) + ret = 0; + else + ret = mbed_ret; + + return ret; +} + +int ssl_pm_pending(const SSL *ssl) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + return mbedtls_ssl_get_bytes_avail(&ssl_pm->ssl); +} + +void ssl_pm_set_fd(SSL *ssl, int fd, int mode) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ssl_pm->fd.fd = fd; +} + +int ssl_pm_get_fd(const SSL *ssl, int mode) +{ + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + return ssl_pm->fd.fd; +} + +OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl) +{ + OSSL_HANDSHAKE_STATE state; + + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + switch (ssl_pm->ssl.state) + { + case MBEDTLS_SSL_CLIENT_HELLO: + state = TLS_ST_CW_CLNT_HELLO; + break; + case MBEDTLS_SSL_SERVER_HELLO: + state = TLS_ST_SW_SRVR_HELLO; + break; + case MBEDTLS_SSL_SERVER_CERTIFICATE: + state = TLS_ST_SW_CERT; + break; + case MBEDTLS_SSL_SERVER_HELLO_DONE: + state = TLS_ST_SW_SRVR_DONE; + break; + case MBEDTLS_SSL_CLIENT_KEY_EXCHANGE: + state = TLS_ST_CW_KEY_EXCH; + break; + case MBEDTLS_SSL_CLIENT_CHANGE_CIPHER_SPEC: + state = TLS_ST_CW_CHANGE; + break; + case MBEDTLS_SSL_CLIENT_FINISHED: + state = TLS_ST_CW_FINISHED; + break; + case MBEDTLS_SSL_SERVER_CHANGE_CIPHER_SPEC: + state = TLS_ST_SW_CHANGE; + break; + case MBEDTLS_SSL_SERVER_FINISHED: + state = TLS_ST_SW_FINISHED; + break; + case MBEDTLS_SSL_CLIENT_CERTIFICATE: + state = TLS_ST_CW_CERT; + break; + case MBEDTLS_SSL_SERVER_KEY_EXCHANGE: + state = TLS_ST_SR_KEY_EXCH; + break; + case MBEDTLS_SSL_SERVER_NEW_SESSION_TICKET: + state = TLS_ST_SW_SESSION_TICKET; + break; + case MBEDTLS_SSL_SERVER_HELLO_VERIFY_REQUEST_SENT: + state = TLS_ST_SW_CERT_REQ; + break; + case MBEDTLS_SSL_HANDSHAKE_OVER: + state = TLS_ST_OK; + break; + default : + state = TLS_ST_BEFORE; + break; + } + + return state; +} + +void* x509_pm_new(void) +{ + return ssl_malloc(sizeof(struct x509_pm)); +} + +void x509_pm_free(void *pm) +{ + ssl_free(pm); +} + +int x509_pm_load_crt(void *pm, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct x509_pm *x509_pm = (struct x509_pm *)pm; + + load_buf = ssl_malloc(len + 1); + if (!load_buf) + SSL_RET(failed1, ""); + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + mbedtls_x509_crt_init(&x509_pm->x509_crt); + ret = mbedtls_x509_crt_parse(&x509_pm->x509_crt, load_buf, len); + ssl_free(load_buf); + + if (ret) + SSL_RET(failed1, ""); + + return 0; + +failed1: + return -1; +} + +void x509_pm_unload_crt(void *pm) +{ + struct x509_pm *x509_pm = (struct x509_pm *)pm; + + mbedtls_x509_crt_free(&x509_pm->x509_crt); +} + +void* pkey_pm_new(void) +{ + return ssl_malloc(sizeof(struct pkey_pm)); +} + +void pkey_pm_free(void *pm) +{ + ssl_free(pm); +} + +int pkey_pm_load_crt(void *pm, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pm; + + load_buf = ssl_malloc(len + 1); + if (!load_buf) + SSL_RET(failed1, ""); + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + mbedtls_pk_init(&pkey_pm->pkey); + ret = mbedtls_pk_parse_key(&pkey_pm->pkey, load_buf, len, NULL, 0); + ssl_free(load_buf); + + if (ret) + SSL_RET(failed1, ""); + + return 0; + +failed1: + return -1; +} + +void pkey_pm_unload_crt(void *pm) +{ + struct pkey_pm *pkey_pm = (struct pkey_pm *)pm; + + mbedtls_pk_free(&pkey_pm->pkey); +} + +void ssl_pm_set_bufflen(SSL *ssl, int len) +{ + max_content_len = len; +} From 5adc661d05ea0ab75e68674aae3ba6b2a7795824 Mon Sep 17 00:00:00 2001 From: dongheng Date: Wed, 21 Sep 2016 09:23:29 +0800 Subject: [PATCH 03/95] components/openssl: add more interface for application --- components/openssl/Makefile | 50 ------------- components/openssl/Makefile.projbuild | 4 ++ components/openssl/component.mk | 9 +++ components/openssl/include/internal/ssl_lib.h | 5 -- .../openssl/include/internal/ssl_pkey.h | 2 + components/openssl/include/platform/ssl_pm.h | 3 +- components/openssl/library/Makefile | 46 ------------ components/openssl/library/ssl_cert.c | 1 + components/openssl/library/ssl_lib.c | 72 ++++++++++++++++++- components/openssl/platform/Makefile | 46 ------------ components/openssl/platform/ssl_pm.c | 6 +- 11 files changed, 92 insertions(+), 152 deletions(-) delete mode 100644 components/openssl/Makefile create mode 100644 components/openssl/Makefile.projbuild create mode 100644 components/openssl/component.mk delete mode 100644 components/openssl/library/Makefile delete mode 100644 components/openssl/platform/Makefile diff --git a/components/openssl/Makefile b/components/openssl/Makefile deleted file mode 100644 index bdd8a0e932..0000000000 --- a/components/openssl/Makefile +++ /dev/null @@ -1,50 +0,0 @@ - -############################################################# -# Required variables for each makefile -# Discard this section from all parent makefiles -# Expected variables (with automatic defaults): -# CSRCS (all "C" files in the dir) -# SUBDIRS (all subdirs with a Makefile) -# GEN_LIBS - list of libs to be generated () -# GEN_IMAGES - list of images to be generated () -# COMPONENTS_xxx - a list of libs/objs in the form -# subdir/lib to be extracted and rolled up into -# a generated lib/image xxx.a () -# -ifndef PDIR - -UP_EXTRACT_DIR = .. -GEN_LIBS = libopenssl.a -COMPONENTS_libopenssl = library/liblibrary.a platform/libplatform.a - -endif - - -############################################################# -# Configuration i.e. compile options etc. -# Target specific stuff (defines etc.) goes in here! -# Generally values applying to a tree are captured in the -# makefile at its root level - these are then overridden -# for a subtree within the makefile rooted therein -# -#DEFINES += - -############################################################# -# Recursion Magic - Don't touch this!! -# -# Each subtree potentially has an include directory -# corresponding to the common APIs applicable to modules -# rooted at that subtree. Accordingly, the INCLUDE PATH -# of a module can only contain the include directories up -# its parent path, and not its siblings -# -# Required for each makefile to inherit from the parent -# - -INCLUDES := $(INCLUDES) -I $(PDIR)include -I $(PDIR)include/platform -I $(PDIR)include/internal -INCLUDES += -I ./inlcude -INCLUDES += -I $(SDK_PATH)/include/openssl/internal -INCLUDES += -I ./ -PDIR := ../$(PDIR) -sinclude $(PDIR)Makefile - diff --git a/components/openssl/Makefile.projbuild b/components/openssl/Makefile.projbuild new file mode 100644 index 0000000000..51300efd11 --- /dev/null +++ b/components/openssl/Makefile.projbuild @@ -0,0 +1,4 @@ +# Anyone compiling mbedTLS code needs the name of the +# alternative config file +CFLAGS += -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' + diff --git a/components/openssl/component.mk b/components/openssl/component.mk new file mode 100644 index 0000000000..97de6975c9 --- /dev/null +++ b/components/openssl/component.mk @@ -0,0 +1,9 @@ +# +# Component Makefile +# + +COMPONENT_ADD_INCLUDEDIRS := include include/internal include/platform include/oepnssl + +COMPONENT_SRCDIRS := library platform + +include $(IDF_PATH)/make/component_common.mk diff --git a/components/openssl/include/internal/ssl_lib.h b/components/openssl/include/internal/ssl_lib.h index d95d219556..0881fbbfdb 100644 --- a/components/openssl/include/internal/ssl_lib.h +++ b/components/openssl/include/internal/ssl_lib.h @@ -3,9 +3,4 @@ #include "ssl_types.h" -#define SSL_want_nothing(s) (SSL_want(s) == SSL_NOTHING) -#define SSL_want_read(s) (SSL_want(s) == SSL_READING) -#define SSL_want_write(s) (SSL_want(s) == SSL_WRITING) -#define SSL_want_x509_lookup(s) (SSL_want(s) == SSL_WRITING) - #endif diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h index cc870e18ed..c7170244a6 100644 --- a/components/openssl/include/internal/ssl_pkey.h +++ b/components/openssl/include/internal/ssl_pkey.h @@ -8,4 +8,6 @@ EVP_PKEY *d2i_PrivateKey(int type, const unsigned char **pp, long length); +void EVP_PKEY_free(EVP_PKEY *x); + #endif diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index c75ae95af5..a6731cff7f 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -2,7 +2,8 @@ #define _SSL_PM_H_ #include "ssl_types.h" -#include "esp_common.h" +#include "esp_types.h" +#include "esp_system.h" void* ssl_zalloc(size_t size); void *ssl_malloc(size_t size); diff --git a/components/openssl/library/Makefile b/components/openssl/library/Makefile deleted file mode 100644 index 10f4067c64..0000000000 --- a/components/openssl/library/Makefile +++ /dev/null @@ -1,46 +0,0 @@ - -############################################################# -# Required variables for each makefile -# Discard this section from all parent makefiles -# Expected variables (with automatic defaults): -# CSRCS (all "C" files in the dir) -# SUBDIRS (all subdirs with a Makefile) -# GEN_LIBS - list of libs to be generated () -# GEN_IMAGES - list of images to be generated () -# COMPONENTS_xxx - a list of libs/objs in the form -# subdir/lib to be extracted and rolled up into -# a generated lib/image xxx.a () -# -ifndef PDIR - -GEN_LIBS = liblibrary.a - -endif - - -############################################################# -# Configuration i.e. compile options etc. -# Target specific stuff (defines etc.) goes in here! -# Generally values applying to a tree are captured in the -# makefile at its root level - these are then overridden -# for a subtree within the makefile rooted therein -# -#DEFINES += - -############################################################# -# Recursion Magic - Don't touch this!! -# -# Each subtree potentially has an include directory -# corresponding to the common APIs applicable to modules -# rooted at that subtree. Accordingly, the INCLUDE PATH -# of a module can only contain the include directories up -# its parent path, and not its siblings -# -# Required for each makefile to inherit from the parent -# - -INCLUDES := $(INCLUDES) -I $(PDIR)include -INCLUDES += -I ./ -PDIR := ../$(PDIR) -sinclude $(PDIR)Makefile - diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index 10f723bfcb..5332592460 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -1,4 +1,5 @@ #include "ssl_cert.h" +#include "ssl_dbg.h" #include "ssl_pm.h" CERT *ssl_cert_new(void) diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index ad78f3961a..e1e112cc7b 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -6,7 +6,7 @@ #define SSL_SEND_DATA_MAX_LENGTH 1460 -static int ossl_statem_in_error(const SSL *ssl) +int ossl_statem_in_error(const SSL *ssl) { if (ssl->statem.state == MSG_FLOW_ERROR) return 1; @@ -14,6 +14,74 @@ static int ossl_statem_in_error(const SSL *ssl) return 0; } +/* + * SSL_want - get the SSL specifical statement + * + * @param ssl - SSL point + * + * @return specifical statement + */ +int SSL_want(const SSL *ssl) +{ + return 0; +} + +/* + * SSL_want_nothing - check if SSL want nothing + * + * @param ssl - SSL point + * + * @return + * 1 : yes + * 0 : no + */ +int SSL_want_nothing(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_NOTHING); +} + +/* + * SSL_want_read - check if SSL want to read + * + * @param ssl - SSL point + * + * @return + * 1 : yes + * 0 : no + */ +int SSL_want_read(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_READING); +} + +/* + * SSL_want_read - check if SSL want to write + * + * @param ssl - SSL point + * + * @return + * 1 : yes + * 0 : no + */ +int SSL_want_write(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_WRITING); +} + +/* + * SSL_want_read - check if SSL want to lookup X509 certification + * + * @param ssl - SSL point + * + * @return + * 1 : yes + * 0 : no + */ +int SSL_want_x509_lookup(const SSL *ssl) +{ + return (SSL_want(ssl) == SSL_WRITING); +} + /* * SSL_get_error - get SSL error code * @@ -1153,7 +1221,7 @@ char *SSL_state_string(const SSL *ssl) SSL_ASSERT(ssl); - if (ossl_state_in_error(ssl)) + if (ossl_statem_in_error(ssl)) str = "SSLERR"; else { diff --git a/components/openssl/platform/Makefile b/components/openssl/platform/Makefile deleted file mode 100644 index 749b4787ca..0000000000 --- a/components/openssl/platform/Makefile +++ /dev/null @@ -1,46 +0,0 @@ - -############################################################# -# Required variables for each makefile -# Discard this section from all parent makefiles -# Expected variables (with automatic defaults): -# CSRCS (all "C" files in the dir) -# SUBDIRS (all subdirs with a Makefile) -# GEN_LIBS - list of libs to be generated () -# GEN_IMAGES - list of images to be generated () -# COMPONENTS_xxx - a list of libs/objs in the form -# subdir/lib to be extracted and rolled up into -# a generated lib/image xxx.a () -# -ifndef PDIR - -GEN_LIBS = libplatform.a - -endif - - -############################################################# -# Configuration i.e. compile options etc. -# Target specific stuff (defines etc.) goes in here! -# Generally values applying to a tree are captured in the -# makefile at its root level - these are then overridden -# for a subtree within the makefile rooted therein -# -#DEFINES += - -############################################################# -# Recursion Magic - Don't touch this!! -# -# Each subtree potentially has an include directory -# corresponding to the common APIs applicable to modules -# rooted at that subtree. Accordingly, the INCLUDE PATH -# of a module can only contain the include directories up -# its parent path, and not its siblings -# -# Required for each makefile to inherit from the parent -# - -INCLUDES := $(INCLUDES) -I $(PDIR)include -INCLUDES += -I ./ -PDIR := ../$(PDIR) -sinclude $(PDIR)Makefile - diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 831420180c..9d207b3a0e 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -1,6 +1,8 @@ #include "ssl_pm.h" #include "ssl_dbg.h" +#include + /* mbedtls include */ #include "mbedtls/platform.h" #include "mbedtls/net.h" @@ -55,7 +57,7 @@ void* ssl_zalloc(size_t size) void *ssl_malloc(size_t size) { - return zalloc(size); + return ssl_zalloc(size); } void ssl_free(void *p) @@ -140,7 +142,7 @@ int ssl_pm_new(SSL *ssl) ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); if (ret) - SSL_ERR(ret, failed4, "mbedtls_ssl_conf_own_cert:[%d]\n", ret); + SSL_ERR(ret, failed3, "mbedtls_ssl_conf_own_cert:[%d]\n", ret); } ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); From b89168d0f1be251fce1b37bfe0684ae097da30f7 Mon Sep 17 00:00:00 2001 From: dongheng Date: Wed, 21 Sep 2016 17:51:12 +0800 Subject: [PATCH 04/95] components/openssl: add ssl_port.c & .h file --- .../openssl/include/platform/ssl_port.h | 29 ++++++++++ components/openssl/platform/ssl_port.c | 56 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 components/openssl/include/platform/ssl_port.h create mode 100644 components/openssl/platform/ssl_port.c diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h new file mode 100644 index 0000000000..252e2566c3 --- /dev/null +++ b/components/openssl/include/platform/ssl_port.h @@ -0,0 +1,29 @@ +/* Copyright 2015-2016 Espressif Systems (Wuxi) 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 _SSL_PORT_H_ +#define _SSL_PORT_H_ + +#include "esp_types.h" + +void* ssl_zalloc(size_t size); +void *ssl_malloc(size_t size); +void ssl_free(void *p); +void* ssl_memcpy(void *to, const void *from, size_t size); + +void ssl_speed_up_enter(void); +void ssl_speed_up_exit(void); + +#endif diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c new file mode 100644 index 0000000000..66aac5f6d9 --- /dev/null +++ b/components/openssl/platform/ssl_port.c @@ -0,0 +1,56 @@ +/* Copyright 2015-2016 Espressif Systems (Wuxi) 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 +#include "ssl_port.h" +#include "malloc.h" + +/*********************************************************************************************/ +/********************************* SSL general interface *************************************/ + +void* ssl_zalloc(size_t size) +{ + void *p = malloc(size); + + if (p) + memset(p, 0, size); + + return p; +} + +void *ssl_malloc(size_t size) +{ + return ssl_zalloc(size); +} + +void ssl_free(void *p) +{ + free(p); +} + +void* ssl_memcpy(void *to, const void *from, size_t size) +{ + return memcpy(to, from, size); +} + +void ssl_speed_up_enter(void) +{ + +} + +void ssl_speed_up_exit(void) +{ + +} From 6bd3d62d7ceadb11c814459dfbe68160aa511409 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 10:28:08 +0800 Subject: [PATCH 05/95] components/openssl: add license header --- components/openssl/Makefile.projbuild | 1 - components/openssl/include/internal/ssl3.h | 14 ++ .../openssl/include/internal/ssl_cert.h | 20 ++- .../openssl/include/internal/ssl_code.h | 14 ++ components/openssl/include/internal/ssl_dbg.h | 20 ++- components/openssl/include/internal/ssl_lib.h | 14 ++ .../openssl/include/internal/ssl_methods.h | 53 +++++- .../openssl/include/internal/ssl_pkey.h | 18 +- components/openssl/include/internal/ssl_rsa.h | 14 ++ .../openssl/include/internal/ssl_types.h | 53 +++++- .../openssl/include/internal/ssl_x509.h | 14 ++ components/openssl/include/internal/tls1.h | 14 ++ components/openssl/include/openssl/ssl.h | 19 +- components/openssl/include/platform/ssl_pm.h | 40 +++-- .../openssl/include/platform/ssl_port.h | 27 ++- components/openssl/library/ssl_cert.c | 75 ++++++-- components/openssl/library/ssl_lib.c | 101 ++++++++--- components/openssl/library/ssl_methods.c | 42 ++++- components/openssl/library/ssl_pkey.c | 111 +++++++++--- components/openssl/library/ssl_rsa.c | 82 ++++++++- components/openssl/library/ssl_x509.c | 118 +++++++++---- components/openssl/platform/ssl_pm.c | 163 ++++++++++-------- components/openssl/platform/ssl_port.c | 27 ++- 23 files changed, 819 insertions(+), 235 deletions(-) diff --git a/components/openssl/Makefile.projbuild b/components/openssl/Makefile.projbuild index 51300efd11..b1d5641231 100644 --- a/components/openssl/Makefile.projbuild +++ b/components/openssl/Makefile.projbuild @@ -1,4 +1,3 @@ # Anyone compiling mbedTLS code needs the name of the # alternative config file -CFLAGS += -DMBEDTLS_CONFIG_FILE='"mbedtls/esp_config.h"' diff --git a/components/openssl/include/internal/ssl3.h b/components/openssl/include/internal/ssl3.h index d7c254563b..c90d546df0 100644 --- a/components/openssl/include/internal/ssl3.h +++ b/components/openssl/include/internal/ssl3.h @@ -1,3 +1,17 @@ +// Copyright 2015-2016 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 _SSL3_H_ #define _SSL3_H_ diff --git a/components/openssl/include/internal/ssl_cert.h b/components/openssl/include/internal/ssl_cert.h index e0b3ea75dc..109012a194 100644 --- a/components/openssl/include/internal/ssl_cert.h +++ b/components/openssl/include/internal/ssl_cert.h @@ -1,11 +1,23 @@ +// Copyright 2015-2016 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 _SSL_CERT_H_ #define _SSL_CERT_H_ -#include "ssl_pkey.h" -#include "ssl_x509.h" - -CERT *ssl_cert_new(void); +#include "ssl_types.h" +CERT* ssl_cert_new(void); void ssl_cert_free(CERT *c); #endif diff --git a/components/openssl/include/internal/ssl_code.h b/components/openssl/include/internal/ssl_code.h index d45abff680..1510ce6ff4 100644 --- a/components/openssl/include/internal/ssl_code.h +++ b/components/openssl/include/internal/ssl_code.h @@ -1,3 +1,17 @@ +// Copyright 2015-2016 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 _SSL_CODE_H_ #define _SSL_CODE_H_ diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index 436d33132f..27a192b28f 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -1,13 +1,29 @@ +// Copyright 2015-2016 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 _SSL_DEBUG_H_ #define _SSL_DEBUG_H_ -#define SSL_DEBUG_ENBALE 0 +#define SSL_DEBUG_ENBALE 1 #define SSL_DEBUG_LEVEL 0 #define SSL_ASSERT_ENABLE 1 #define SSL_DEBUG_LOCATION_ENABLE 1 #if SSL_DEBUG_ENBALE - #define SSL_PRINT os_printf + extern int ets_printf(const char *fmt, ...); + + #define SSL_PRINT ets_printf #else #define SSL_PRINT(...) #endif diff --git a/components/openssl/include/internal/ssl_lib.h b/components/openssl/include/internal/ssl_lib.h index 0881fbbfdb..6ea547a7c5 100644 --- a/components/openssl/include/internal/ssl_lib.h +++ b/components/openssl/include/internal/ssl_lib.h @@ -1,3 +1,17 @@ +// Copyright 2015-2016 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 _SSL_LIB_H_ #define _SSL_LIB_H_ diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index e2806f177a..b72b17ad3d 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -1,3 +1,17 @@ +// Copyright 2015-2016 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 _SSL_METHODS_H_ #define _SSL_METHODS_H_ @@ -8,7 +22,7 @@ set_fd, get_fd, \ set_bufflen, \ get_state) \ - static const SSL_METHOD_FUNC func_name = { \ + static const SSL_METHOD_FUNC func_name LOCAL_ATRR = { \ new, \ free, \ handshake, \ @@ -25,7 +39,7 @@ #define IMPLEMENT_TLS_METHOD(ver, mode, fun, func_name) \ const SSL_METHOD* func_name(void) { \ - static const SSL_METHOD func_name##_data = { \ + static const SSL_METHOD func_name##_data LOCAL_ATRR = { \ ver, \ mode, \ &(fun), \ @@ -35,7 +49,7 @@ #define IMPLEMENT_SSL_METHOD(ver, mode, fun, func_name) \ const SSL_METHOD* func_name(void) { \ - static const SSL_METHOD func_name##_data = { \ + static const SSL_METHOD func_name##_data LOCAL_ATRR = { \ ver, \ mode, \ &(fun), \ @@ -43,4 +57,37 @@ return &func_name##_data; \ } +#define IMPLEMENT_X509_METHOD(func_name, \ + new, \ + free, \ + load, \ + unload) \ + const X509_METHOD* func_name(void) { \ + static const X509_METHOD func_name##_data LOCAL_ATRR = { \ + new, \ + free, \ + load, \ + unload, \ + }; \ + return &func_name##_data; \ + } + +#define IMPLEMENT_PKEY_METHOD(func_name, \ + new, \ + free, \ + load, \ + unload) \ + const PKEY_METHOD* func_name(void) { \ + static const PKEY_METHOD func_name##_data LOCAL_ATRR = { \ + new, \ + free, \ + load, \ + unload, \ + }; \ + return &func_name##_data; \ + } + +const X509_METHOD* X509_method(void); +const PKEY_METHOD* EVP_PKEY_method(void); + #endif diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h index c7170244a6..34be294efe 100644 --- a/components/openssl/include/internal/ssl_pkey.h +++ b/components/openssl/include/internal/ssl_pkey.h @@ -1,9 +1,25 @@ +// Copyright 2015-2016 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 _SSL_PKEY_H_ #define _SSL_PKEY_H_ #include "ssl_types.h" -EVP_PKEY *d2i_PrivateKey(int type, +EVP_PKEY* EVP_PKEY_new(void); + +EVP_PKEY* d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp, long length); diff --git a/components/openssl/include/internal/ssl_rsa.h b/components/openssl/include/internal/ssl_rsa.h index 7530bde734..d0ce40312c 100644 --- a/components/openssl/include/internal/ssl_rsa.h +++ b/components/openssl/include/internal/ssl_rsa.h @@ -1,3 +1,17 @@ +// Copyright 2015-2016 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 _SSL_RSA_H_ #define _SSL_RSA_H_ diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 19eb6cb165..417350627c 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -1,8 +1,21 @@ +// Copyright 2015-2016 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 _SSL_TYPES_H_ #define _SSL_TYPES_H_ #include "ssl_code.h" -#include typedef void SSL_CIPHER; @@ -47,15 +60,25 @@ typedef struct x509_st X509; struct evp_pkey_st; typedef struct evp_pkey_st EVP_PKEY; +struct x509_method_st; +typedef struct x509_method_st X509_METHOD; + +struct pkey_method_st; +typedef struct pkey_method_st PKEY_METHOD; + struct evp_pkey_st { void *pkey_pm; + + const PKEY_METHOD *method; }; struct x509_st { /* X509 certification platform private point */ void *x509_pm; + + const X509_METHOD *method; }; struct cert_st { @@ -111,6 +134,8 @@ struct ssl_ctx_st long session_timeout; int read_ahead; + + int read_buffer_len; }; struct ssl_st @@ -183,8 +208,34 @@ struct ssl_method_func_st { OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl); }; +struct x509_method_st { + + int (*x509_new)(X509 *x); + + void (*x509_free)(X509 *x); + + int (*x509_load)(X509 *x, const unsigned char *buf, int len); + + void (*x509_unload)(X509 *x); +}; + +struct pkey_method_st { + + int (*pkey_new)(EVP_PKEY *pkey); + + void (*pkey_free)(EVP_PKEY *pkey); + + int (*pkey_load)(EVP_PKEY *pkey, const unsigned char *buf, int len); + + void (*pkey_unload)(EVP_PKEY *pkey); +}; + typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg); +#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__) +#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__) +#define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__) + #endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index 28a7baf513..a169352bac 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -1,3 +1,17 @@ +// Copyright 2015-2016 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 _SSL_X509_H_ #define _SSL_X509_H_ diff --git a/components/openssl/include/internal/tls1.h b/components/openssl/include/internal/tls1.h index 70de22bb5b..b2da639194 100644 --- a/components/openssl/include/internal/tls1.h +++ b/components/openssl/include/internal/tls1.h @@ -1,3 +1,17 @@ +// Copyright 2015-2016 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 _TLS1_H_ #define _TLS1_H_ diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index 89cb5bb9f7..0d4c9c2080 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -1,6 +1,21 @@ -#ifndef HEADER_SSL_H -#define HEADER_SSL_H +// Copyright 2015-2016 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 _SSL_H_ +#define _SSL_H_ + +#include "ssl_port.h" #include "internal/ssl_types.h" /* diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index a6731cff7f..783ba5445e 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -1,14 +1,24 @@ +// Copyright 2015-2016 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 _SSL_PM_H_ #define _SSL_PM_H_ #include "ssl_types.h" -#include "esp_types.h" -#include "esp_system.h" +#include "ssl_port.h" -void* ssl_zalloc(size_t size); -void *ssl_malloc(size_t size); -void ssl_free(void *p); -void* ssl_memcpy(void *to, const void *from, size_t size); +#define LOCAL_ATRR int ssl_pm_new(SSL *ssl); void ssl_pm_free(SSL *ssl); @@ -28,15 +38,15 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl); void ssl_pm_set_bufflen(SSL *ssl, int len); -void* x509_pm_new(void); -void x509_pm_free(void *pm); -int x509_pm_load_crt(void *pm, const unsigned char *buffer, int len); -void x509_pm_unload_crt(void *pm); -void x509_pm_start_ca(void *ssl, void *pm); +int x509_pm_new(X509 *x); +void x509_pm_free(X509 *x); +int x509_pm_load(X509 *x, const unsigned char *buffer, int len); +void x509_pm_unload(X509 *x); +void x509_pm_start_ca(X509 *x); -void* pkey_pm_new(void); -void pkey_pm_free(void *pm); -int pkey_pm_load_crt(void *pm, const unsigned char *buffer, int len); -void pkey_pm_unload_crt(void *pm); +int pkey_pm_new(EVP_PKEY *pkey); +void pkey_pm_free(EVP_PKEY *pkey); +int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len); +void pkey_pm_unload(EVP_PKEY *pkey); #endif diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h index 252e2566c3..48a7c7ca97 100644 --- a/components/openssl/include/platform/ssl_port.h +++ b/components/openssl/include/platform/ssl_port.h @@ -1,17 +1,16 @@ -/* Copyright 2015-2016 Espressif Systems (Wuxi) 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. - */ +// Copyright 2015-2016 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 _SSL_PORT_H_ #define _SSL_PORT_H_ diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index 5332592460..0bdba459d3 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -1,29 +1,68 @@ -#include "ssl_cert.h" -#include "ssl_dbg.h" -#include "ssl_pm.h" +// Copyright 2015-2016 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_cert.h" +#include "ssl_pkey.h" +#include "ssl_x509.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/* + * ssl_cert_new - create a certification object include private key object + * + * @param none + * + * @return certification object point or NULL if failed + */ CERT *ssl_cert_new(void) { - return ssl_zalloc(sizeof(CERT)); + CERT *cert; + + cert = ssl_zalloc(sizeof(CERT)); + if (!cert) + SSL_RET(failed1, "ssl_zalloc\n"); + + cert->pkey = EVP_PKEY_new(); + if (!cert->pkey) + SSL_RET(failed2, "EVP_PKEY_new\n"); + + cert->x509 = sk_X509_NAME_new_null(); + if (!cert->x509) + SSL_RET(failed3, "sk_X509_NAME_new_null\n"); + + return cert; + +failed3: + EVP_PKEY_free(cert->pkey); +failed2: + ssl_free(cert); +failed1: + return NULL; } +/* + * ssl_cert_free - free a certification object + * + * @param c - certification object point + * + * @return none + */ void ssl_cert_free(CERT *c) { - if (c->x509) - X509_free(c->x509); + X509_free(c->x509); - if (c->pkey) - EVP_PKEY_free(c->pkey); + EVP_PKEY_free(c->pkey); ssl_free(c); } - -int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) -{ - SSL_ASSERT(ctx); - SSL_ASSERT(x); - - ctx->client_CA = x; - - return 1; -} diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index e1e112cc7b..331ed17bd5 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -1,11 +1,35 @@ +// Copyright 2015-2016 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 "ssl_pkey.h" +#include "ssl_x509.h" #include "ssl_cert.h" #include "ssl_dbg.h" -#include "ssl_pm.h" +#include "ssl_port.h" #define SSL_SEND_DATA_MAX_LENGTH 1460 +/* + * ossl_statem_in_error - Discover whether the current connection is in the error state + * + * @param ssl - SSL point + * + * @return + * 1 : Yes + * 0 : no + */ int ossl_statem_in_error(const SSL *ssl) { if (ssl->statem.state == MSG_FLOW_ERROR) @@ -23,7 +47,7 @@ int ossl_statem_in_error(const SSL *ssl) */ int SSL_want(const SSL *ssl) { - return 0; + return ssl->rwstate; } /* @@ -131,7 +155,7 @@ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) SSL_ASSERT(ssl); - state = ssl->method->func->ssl_get_state(ssl); + state = SSL_METHOD_CALL(get_state, ssl); return state; } @@ -154,15 +178,15 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) client_ca = sk_X509_NAME_new_null(); if (!client_ca) - SSL_ERR(-2, go_failed1, "ssl_ctx_new:ctx:[%d]\n", ret); + SSL_ERR(-2, go_failed1, "sk_X509_NAME_new_null\n"); cert = ssl_cert_new(); if (!cert) - SSL_ERR(-2, go_failed2, "ssl_ctx_new:ctx:[%d]\n", ret); + SSL_ERR(-2, go_failed2, "ssl_cert_new\n"); ctx = (SSL_CTX *)ssl_zalloc(sizeof(SSL_CTX)); if (!ctx) - SSL_ERR(-2, go_failed3, "ssl_ctx_new:ctx:[%d]\n", ret); + SSL_ERR(-2, go_failed3, "ssl_ctx_new:ctx\n"); ctx->method = method; ctx->cert = cert; @@ -215,6 +239,8 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) ctx->method = meth; + ctx->version = meth->version; + return 1; } @@ -258,10 +284,12 @@ SSL *SSL_new(SSL_CTX *ctx) ssl->version = ctx->version; ssl->options = ctx->options; - ret = ssl->method->func->ssl_new(ssl); + ret = SSL_METHOD_CALL(new, ssl); if (ret) SSL_RET(failed2, "ssl_new\n"); + ssl->rwstate = SSL_NOTHING; + return ssl; failed2: @@ -281,7 +309,7 @@ void SSL_free(SSL *ssl) { SSL_ASSERT(ssl); - ssl->method->func->ssl_free(ssl); + SSL_METHOD_CALL(free, ssl); ssl_free(ssl); } @@ -302,7 +330,7 @@ int SSL_do_handshake(SSL *ssl) SSL_ASSERT(ssl); - ret = ssl->method->func->ssl_handshake(ssl); + ret = SSL_METHOD_CALL(handshake, ssl); return ret; } @@ -357,7 +385,7 @@ int SSL_shutdown(SSL *ssl) if (SSL_get_state(ssl) != TLS_ST_OK) return 0; - ret = ssl->method->func->ssl_shutdown(ssl); + ret = SSL_METHOD_CALL(shutdown, ssl); return ret; } @@ -381,9 +409,9 @@ int SSL_clear(SSL *ssl) if (1 != ret) SSL_ERR(0, go_failed1, "SSL_shutdown\n"); - ssl->method->func->ssl_free(ssl); + SSL_METHOD_CALL(free, ssl); - ret = ssl->method->func->ssl_new(ssl); + ret = SSL_METHOD_CALL(new, ssl); if (!ret) SSL_ERR(0, go_failed1, "ssl_new\n"); @@ -413,7 +441,11 @@ int SSL_read(SSL *ssl, void *buffer, int len) SSL_ASSERT(buffer); SSL_ASSERT(len); - ret = ssl->method->func->ssl_read(ssl, buffer, len); + ssl->rwstate = SSL_READING; + + ret = SSL_METHOD_CALL(read, ssl, buffer, len); + + ssl->rwstate = SSL_NOTHING; return ret; } @@ -440,6 +472,8 @@ int SSL_write(SSL *ssl, const void *buffer, int len) SSL_ASSERT(buffer); SSL_ASSERT(len); + ssl->rwstate = SSL_WRITING; + send_bytes = len; pbuf = (const unsigned char *)buffer; @@ -451,13 +485,15 @@ int SSL_write(SSL *ssl, const void *buffer, int len) else bytes = send_bytes; - ret = ssl->method->func->ssl_send(ssl, buffer, len); + ret = SSL_METHOD_CALL(send, ssl, buffer, len); if (ret > 0) { pbuf += ret; send_bytes -= ret; } } while (ret > 0 && send_bytes); + ssl->rwstate = SSL_NOTHING; + send_bytes = len - send_bytes; if (send_bytes >= 0) ret = send_bytes; @@ -518,11 +554,11 @@ int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method) if (1 != ret) SSL_ERR(0, go_failed1, "SSL_shutdown\n"); - ssl->method->func->ssl_free(ssl); + SSL_METHOD_CALL(free, ssl); ssl->method = method; - ret = ssl->method->func->ssl_new(ssl); + ret = SSL_METHOD_CALL(new, ssl); if (!ret) SSL_ERR(0, go_failed1, "ssl_new\n"); } else { @@ -579,7 +615,7 @@ int SSL_pending(const SSL *ssl) SSL_ASSERT(ssl); - ret = ssl->method->func->ssl_pending(ssl); + ret = SSL_METHOD_CALL(pending, ssl); return ret; } @@ -705,7 +741,7 @@ int SSL_get_fd(const SSL *ssl) SSL_ASSERT(ssl); - ret = ssl->method->func->ssl_get_fd(ssl, 0); + ret = SSL_METHOD_CALL(get_fd, ssl, 0); return ret; } @@ -725,7 +761,7 @@ int SSL_get_rfd(const SSL *ssl) SSL_ASSERT(ssl); - ret = ssl->method->func->ssl_get_fd(ssl, 0); + ret = SSL_METHOD_CALL(get_fd, ssl, 0); return ret; } @@ -745,7 +781,7 @@ int SSL_get_wfd(const SSL *ssl) SSL_ASSERT(ssl); - ret = ssl->method->func->ssl_get_fd(ssl, 0); + ret = SSL_METHOD_CALL(get_fd, ssl, 0); return ret; } @@ -767,7 +803,7 @@ int SSL_set_fd(SSL *ssl, int fd) SSL_ASSERT(ssl); SSL_ASSERT(fd >= 0); - ssl->method->func->ssl_set_fd(ssl, fd, 0); + SSL_METHOD_CALL(set_fd, ssl, fd, 0); return 1; } @@ -789,7 +825,7 @@ int SSL_set_rfd(SSL *ssl, int fd) SSL_ASSERT(ssl); SSL_ASSERT(fd >= 0); - ssl->method->func->ssl_set_fd(ssl, fd, 0); + SSL_METHOD_CALL(set_fd, ssl, fd, 0); return 1; } @@ -811,7 +847,7 @@ int SSL_set_wfd(SSL *ssl, int fd) SSL_ASSERT(ssl); SSL_ASSERT(fd >= 0); - ssl->method->func->ssl_set_fd(ssl, fd, 0); + SSL_METHOD_CALL(set_fd, ssl, fd, 0); return 1; } @@ -1451,7 +1487,7 @@ void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) SSL_ASSERT(ctx); SSL_ASSERT(len); - ctx->method->func->ssl_set_bufflen(NULL, len); + ctx->read_buffer_len = len; } /* @@ -1467,7 +1503,7 @@ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) SSL_ASSERT(ssl); SSL_ASSERT(len); - ssl->method->func->ssl_set_bufflen(ssl, len); + SSL_METHOD_CALL(set_bufflen, ssl, len); } /* @@ -1688,3 +1724,18 @@ long SSL_set_timeout(SSL *ssl, long t) return t; } + +/* + * SSL_set_verify - set the SSL verifying of the SSL context + * + * @param ctx - SSL point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) +{ + SSL_ASSERT(ssl); + SSL_ASSERT(verify_callback); +} diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index 502262f7e9..0c5c6e7fa4 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -1,7 +1,24 @@ +// Copyright 2015-2016 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 "ssl_methods.h" #include "ssl_pm.h" +/* + * TLS method function collection + */ IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, ssl_pm_new, ssl_pm_free, ssl_pm_handshake, ssl_pm_shutdown, ssl_pm_clear, @@ -10,6 +27,9 @@ IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, ssl_pm_set_bufflen, ssl_pm_get_state); +/* + * TLS or SSL client method collection + */ IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 0, TLS_method_func, TLS_client_method); IMPLEMENT_TLS_METHOD(TLS1_2_VERSION, 0, TLS_method_func, TLSv1_2_client_method); @@ -20,7 +40,9 @@ IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_client_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, 0, TLS_method_func, SSLv3_client_method); - +/* + * TLS or SSL server method collection + */ IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 1, TLS_method_func, TLS_server_method); IMPLEMENT_TLS_METHOD(TLS1_1_VERSION, 1, TLS_method_func, TLSv1_1_server_method); @@ -31,7 +53,9 @@ IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_server_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method); - +/* + * TLS or SSL method collection + */ 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); @@ -41,3 +65,17 @@ IMPLEMENT_SSL_METHOD(TLS1_1_VERSION, -1, TLS_method_func, TLSv1_1_method); IMPLEMENT_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); + +/* + * X509 certification method collection + */ +IMPLEMENT_X509_METHOD(X509_method, + x509_pm_new, x509_pm_free, + x509_pm_load, x509_pm_unload); + +/* + * private key method collection + */ +IMPLEMENT_PKEY_METHOD(EVP_PKEY_method, + pkey_pm_new, pkey_pm_free, + pkey_pm_load, pkey_pm_unload); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 2a170716c0..785ebf41db 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -1,50 +1,109 @@ +// Copyright 2015-2016 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 "ssl_pkey.h" +#include "ssl_methods.h" #include "ssl_dbg.h" -#include "ssl_pm.h" +#include "ssl_port.h" -EVP_PKEY *d2i_PrivateKey(int type, - EVP_PKEY **a, - const unsigned char **pp, - long length) +/* + * EVP_PKEY_new - create a private key object + * + * @param none + * + * @return private key object point or NULL if failed + */ +EVP_PKEY* EVP_PKEY_new(void) { - EVP_PKEY *pkey; - void *pkey_pm; int ret; - - SSL_ASSERT(pp); - SSL_ASSERT(*pp); - SSL_ASSERT(length); + EVP_PKEY *pkey; pkey = ssl_malloc(sizeof(EVP_PKEY)); if (!pkey) SSL_RET(failed1, "ssl_malloc\n"); - pkey_pm = pkey_pm_new(); - if (!pkey_pm) - SSL_RET(failed2, "pkey_pm_new\n"); + pkey->method = EVP_PKEY_method(); - ret = pkey_pm_load_crt(pkey_pm, *pp, length); + ret = EVP_PKEY_METHOD_CALL(new, pkey); if (ret) - SSL_RET(failed3, "pkey_pm_load_crt\n"); - - pkey->pkey_pm = pkey_pm; - if (a) - *a = pkey; + SSL_RET(failed2, "pkey_new\n"); return pkey; -failed3: - pkey_pm_free(pkey_pm); failed2: ssl_free(pkey); failed1: return NULL; } -void EVP_PKEY_free(EVP_PKEY *x) +/* + * EVP_PKEY_free - free a private key object + * + * @param pkey - private key object point + * + * @return none + */ +void EVP_PKEY_free(EVP_PKEY *pkey) { - pkey_pm_unload_crt(x->pkey_pm); - pkey_pm_free(x->pkey_pm); - ssl_free(x); + EVP_PKEY_METHOD_CALL(free, pkey); + + ssl_free(pkey); +} + +/* + * d2i_PrivateKey - load a character key context into system context. If '*a' is pointed to the + * private key, then load key into it. Or create a new private key object + * + * @param type - private key type + * @param a - a point pointed to a private key point + * @param pp - a point pointed to the key context memory point + * @param length - key bytes + * + * @return private key object point or NULL if failed + */ +EVP_PKEY *d2i_PrivateKey(int type, + EVP_PKEY **a, + const unsigned char **pp, + long length) +{ + int ret; + EVP_PKEY *pkey; + + SSL_ASSERT(pp); + SSL_ASSERT(*pp); + SSL_ASSERT(length); + + if (a && *a) { + pkey = *a; + } else { + pkey = EVP_PKEY_new();; + if (!pkey) + SSL_RET(failed1, "ssl_malloc\n"); + } + + ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length); + if (ret) + SSL_RET(failed2, "pkey_pm_load_crt\n"); + + if (a) + *a = pkey; + + return pkey; + +failed2: + EVP_PKEY_free(pkey); +failed1: + return NULL; } diff --git a/components/openssl/library/ssl_rsa.c b/components/openssl/library/ssl_rsa.c index 9088f67f57..75a2d3baa7 100644 --- a/components/openssl/library/ssl_rsa.c +++ b/components/openssl/library/ssl_rsa.c @@ -1,10 +1,33 @@ +// Copyright 2015-2016 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 "ssl_rsa.h" #include "ssl_pkey.h" #include "ssl_x509.h" #include "ssl_dbg.h" -#include "ssl_pm.h" +/* + * SSL_CTX_use_certificate - set the SSL context certification + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return + * 1 : OK + * 0 : failed + */ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { SSL_ASSERT(ctx); @@ -15,13 +38,24 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) return 1; } +/* + * SSL_CTX_use_certificate_ASN1 - load certification into the SSL context + * + * @param ctx - SSL context point + * @param len - certification context bytes + * @param d - certification context point + * + * @return + * 1 : OK + * 0 : failed + */ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d) { int ret; X509 *cert; - cert = d2i_X509(NULL, d, len); + cert = d2i_X509(&ctx->cert->x509, d, len); if (!cert) SSL_RET(failed1, "d2i_X509\n"); @@ -37,6 +71,16 @@ failed1: return 0; } +/* + * SSL_CTX_use_certificate - set the SSL context private key + * + * @param ctx - SSL context point + * @param x - private key point + * + * @return + * 1 : OK + * 0 : failed + */ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { SSL_ASSERT(ctx); @@ -47,13 +91,25 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) return 1; } +/* + * SSL_CTX_use_PrivateKey_ASN1 - load private key into the SSL context + * + * @param type - private key type + * @param ctx - SSL context point + * @param d - private key context point + * @param len - private key context bytes + * + * @return + * 1 : OK + * 0 : failed + */ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const unsigned char *d, long len) { int ret; EVP_PKEY *pkey; - pkey = d2i_PrivateKey(0, NULL, &d, len); + pkey = d2i_PrivateKey(0, &ctx->cert->pkey, &d, len); if (!pkey) SSL_RET(failed1, "d2i_PrivateKey\n"); @@ -68,3 +124,23 @@ failed2: failed1: return 0; } + +/* + * SSL_CTX_add_client_CA - set SSL context client CA certification + * + * @param ctx - SSL context point + * @param x - client CA certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + ctx->client_CA = x; + + return 1; +} diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 23aa00681e..fd2643e6b7 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -1,54 +1,100 @@ -#include "ssl_x509.h" -#include "ssl_dbg.h" -#include "ssl_pm.h" +// Copyright 2015-2016 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_x509.h" +#include "ssl_methods.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +/* + * sk_X509_NAME_new_null - create a X509 certification object + * + * @param none + * + * @return X509 certification object point or NULL if failed + */ X509* sk_X509_NAME_new_null(void) { - return ssl_malloc(sizeof(X509)); -} - -X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) -{ - X509 *x509_crt; - void *x509_pm; int ret; + X509 *x; - SSL_ASSERT(cert); - SSL_ASSERT(buffer); - SSL_ASSERT(len); + x = ssl_malloc(sizeof(X509)); + if (!x) + SSL_RET(failed1, "ssl_malloc\n"); - x509_crt = sk_X509_NAME_new_null(); - if (!x509_crt) - SSL_RET(failed1, ""); + x->method = X509_method(); - x509_pm = x509_pm_new(); - if (!x509_pm) - SSL_RET(failed2, ""); - - ret = x509_pm_load_crt(x509_pm, buffer, len); + ret = x->method->x509_new(x); if (ret) - SSL_RET(failed3, ""); + SSL_RET(failed2, "x509_new\n"); - x509_crt->x509_pm = x509_pm; - if (cert) - *cert = x509_crt; + return x; - return x509_crt; - -failed3: - x509_pm_free(x509_pm); failed2: - ssl_free(x509_crt); + ssl_free(x); failed1: return NULL; } -void X509_free(X509 *cert) +/* + * X509_free - free a X509 certification object + * + * @param x - X509 certification object point + * + * @return none + */ +void X509_free(X509 *x) { - if (cert->x509_pm) { - x509_pm_unload_crt(cert->x509_pm); - x509_pm_free(cert->x509_pm); - } - ssl_free(cert); + X509_METHOD_CALL(free, x); + + ssl_free(x); }; +/* + * d2i_X509 - load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object + * + * @param cert - a point pointed to X509 certification + * @param buffer - a point pointed to the certification context memory point + * @param length - certification bytes + * + * @return X509 certification object point or NULL if failed + */ +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) +{ + int ret; + X509 *x; + + SSL_ASSERT(buffer); + SSL_ASSERT(len); + + if (cert && *cert) { + x = *cert; + } else { + x = sk_X509_NAME_new_null(); + if (!x) + SSL_RET(failed1, "sk_X509_NAME_new_null\n"); + } + + ret = X509_METHOD_CALL(load, x, buffer, len); + if (ret) + SSL_RET(failed2, "x509_load\n"); + + return x; + +failed2: + X509_free(x); +failed1: + return NULL; +} diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 9d207b3a0e..b8a046aa1e 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -1,4 +1,19 @@ +// Copyright 2015-2016 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_pm.h" +#include "ssl_port.h" #include "ssl_dbg.h" #include @@ -30,11 +45,15 @@ struct ssl_pm struct x509_pm { + int load; + mbedtls_x509_crt x509_crt; }; struct pkey_pm { + int load; + mbedtls_pk_context pkey; }; @@ -42,44 +61,6 @@ struct pkey_pm unsigned int max_content_len; -/*********************************************************************************************/ -/********************************* SSL general interface *************************************/ - -void* ssl_zalloc(size_t size) -{ - void *p = malloc(size); - - if (p) - memset(p, 0, size); - - return p; -} - -void *ssl_malloc(size_t size) -{ - return ssl_zalloc(size); -} - -void ssl_free(void *p) -{ - free(p); -} - -void* ssl_memcpy(void *to, const void *from, size_t size) -{ - return memcpy(to, from, size); -} - -void ssl_speed_up_enter(void) -{ - -} - -void ssl_speed_up_exit(void) -{ - -} - /*********************************************************************************************/ /************************************ SSL arch interface *************************************/ @@ -90,13 +71,18 @@ int ssl_pm_new(SSL *ssl) char *pers; int endpoint; + int mode; + int version; SSL_CTX *ctx = ssl->ctx; const SSL_METHOD *method = ssl->method; - ssl_pm = malloc(sizeof(struct ssl_pm)); + struct x509_pm *x509_pm; + struct pkey_pm *pkey_pm; + + ssl_pm = ssl_malloc(sizeof(struct ssl_pm)); if (!ssl_pm) - return -1; + SSL_ERR(ret, failed1, "ssl_malloc\n"); if (method->endpoint) { pers = "server"; @@ -124,21 +110,34 @@ int ssl_pm_new(SSL *ssl) if (ret) SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); + if (TLS1_2_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_3; + 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_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); + mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL); - if (ctx->client_CA->x509_pm) { - struct x509_pm *x509_pm = (struct x509_pm *)ctx->client_CA->x509_pm; + x509_pm = (struct x509_pm *)ctx->client_CA->x509_pm; + if (x509_pm->load) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &x509_pm->x509_crt, NULL); - mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &x509_pm->x509_crt, NULL); - mbedtls_ssl_conf_authmode(&ssl_pm->conf, MBEDTLS_SSL_VERIFY_REQUIRED); + mode = MBEDTLS_SSL_VERIFY_REQUIRED; } else { - mbedtls_ssl_conf_authmode(&ssl_pm->conf, MBEDTLS_SSL_VERIFY_NONE); + mode = MBEDTLS_SSL_VERIFY_NONE; } - if (ctx->cert->x509 && - ctx->cert->pkey) { - struct x509_pm *x509_pm = (struct x509_pm *)ctx->cert->x509->x509_pm; - struct pkey_pm *pkey_pm = (struct pkey_pm *)ctx->cert->pkey->pkey_pm; + mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); + + pkey_pm = (struct pkey_pm *)ctx->cert->pkey->pkey_pm; + if (pkey_pm->load) { + x509_pm = (struct x509_pm *)ctx->cert->x509->x509_pm; ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); if (ret) @@ -332,21 +331,24 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl) return state; } -void* x509_pm_new(void) +int x509_pm_new(X509 *x) { - return ssl_malloc(sizeof(struct x509_pm)); + struct x509_pm *x509_pm; + + x509_pm = ssl_malloc(sizeof(struct x509_pm)); + if (!x509_pm) + return -1; + + x->x509_pm = x509_pm; + + return 0; } -void x509_pm_free(void *pm) -{ - ssl_free(pm); -} - -int x509_pm_load_crt(void *pm, const unsigned char *buffer, int len) +int x509_pm_load(X509 *x, const unsigned char *buffer, int len) { int ret; unsigned char *load_buf; - struct x509_pm *x509_pm = (struct x509_pm *)pm; + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; load_buf = ssl_malloc(len + 1); if (!load_buf) @@ -362,34 +364,48 @@ int x509_pm_load_crt(void *pm, const unsigned char *buffer, int len) if (ret) SSL_RET(failed1, ""); + x509_pm->load = 1; + return 0; failed1: return -1; } -void x509_pm_unload_crt(void *pm) +void x509_pm_unload(X509 *x) { - struct x509_pm *x509_pm = (struct x509_pm *)pm; + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; mbedtls_x509_crt_free(&x509_pm->x509_crt); + + x509_pm->load = 0; } -void* pkey_pm_new(void) +void x509_pm_free(X509 *x) { - return ssl_malloc(sizeof(struct pkey_pm)); + x509_pm_unload(x); + + ssl_free(x->x509_pm); } -void pkey_pm_free(void *pm) +int pkey_pm_new(EVP_PKEY *pkey) { - ssl_free(pm); + struct pkey_pm *pkey_pm; + + pkey_pm = ssl_malloc(sizeof(struct pkey_pm)); + if (!pkey_pm) + return -1; + + pkey->pkey_pm = pkey_pm; + + return 0; } -int pkey_pm_load_crt(void *pm, const unsigned char *buffer, int len) +int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len) { int ret; unsigned char *load_buf; - struct pkey_pm *pkey_pm = (struct pkey_pm *)pm; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; load_buf = ssl_malloc(len + 1); if (!load_buf) @@ -405,17 +421,28 @@ int pkey_pm_load_crt(void *pm, const unsigned char *buffer, int len) if (ret) SSL_RET(failed1, ""); + pkey_pm->load = 1; + return 0; failed1: return -1; } -void pkey_pm_unload_crt(void *pm) +void pkey_pm_unload(EVP_PKEY *pkey) { - struct pkey_pm *pkey_pm = (struct pkey_pm *)pm; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; mbedtls_pk_free(&pkey_pm->pkey); + + pkey_pm->load = 0; +} + +void pkey_pm_free(EVP_PKEY *pkey) +{ + pkey_pm_unload(pkey); + + ssl_free(pkey->pkey_pm); } void ssl_pm_set_bufflen(SSL *ssl, int len) diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index 66aac5f6d9..4045e29116 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -1,17 +1,16 @@ -/* Copyright 2015-2016 Espressif Systems (Wuxi) 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. - */ +// Copyright 2015-2016 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 #include "ssl_port.h" From 845ca8b34ffce008f8992b5799964da14209739f Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 11:43:59 +0800 Subject: [PATCH 06/95] components/openssl: delete ssl_rsa.c & .h file --- components/openssl/include/internal/ssl_rsa.h | 28 ---- .../openssl/include/platform/ssl_port.h | 2 + components/openssl/library/ssl_pkey.c | 55 +++++++ components/openssl/library/ssl_rsa.c | 146 ------------------ components/openssl/library/ssl_x509.c | 74 +++++++++ components/openssl/platform/ssl_pm.c | 23 ++- components/openssl/platform/ssl_port.c | 7 +- 7 files changed, 146 insertions(+), 189 deletions(-) delete mode 100644 components/openssl/include/internal/ssl_rsa.h delete mode 100644 components/openssl/library/ssl_rsa.c diff --git a/components/openssl/include/internal/ssl_rsa.h b/components/openssl/include/internal/ssl_rsa.h deleted file mode 100644 index d0ce40312c..0000000000 --- a/components/openssl/include/internal/ssl_rsa.h +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2015-2016 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 _SSL_RSA_H_ -#define _SSL_RSA_H_ - -#include "ssl_lib.h" - -int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, - const unsigned char *d); - -int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); -int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, - const unsigned char *d, long len); - -#endif diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h index 48a7c7ca97..23ef5a8757 100644 --- a/components/openssl/include/platform/ssl_port.h +++ b/components/openssl/include/platform/ssl_port.h @@ -20,7 +20,9 @@ void* ssl_zalloc(size_t size); void *ssl_malloc(size_t size); void ssl_free(void *p); + void* ssl_memcpy(void *to, const void *from, size_t size); +size_t ssl_strlen(const char *src); void ssl_speed_up_enter(void); void ssl_speed_up_exit(void); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 785ebf41db..0c8d9de8fa 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -107,3 +107,58 @@ failed2: failed1: return NULL; } + +/* + * SSL_CTX_use_certificate - set the SSL context private key + * + * @param ctx - SSL context point + * @param x - private key point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(pkey); + + ctx->cert->pkey = pkey; + + return 1; +} + +/* + * SSL_CTX_use_PrivateKey_ASN1 - load private key into the SSL context + * + * @param type - private key type + * @param ctx - SSL context point + * @param d - private key context point + * @param len - private key context bytes + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, + const unsigned char *d, long len) +{ + int ret; + EVP_PKEY *pkey; + + pkey = d2i_PrivateKey(0, &ctx->cert->pkey, &d, len); + if (!pkey) + SSL_RET(failed1, "d2i_PrivateKey\n"); + + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + if (!ret) + SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); + + return 1; + +failed2: + EVP_PKEY_free(pkey); +failed1: + return 0; +} + diff --git a/components/openssl/library/ssl_rsa.c b/components/openssl/library/ssl_rsa.c deleted file mode 100644 index 75a2d3baa7..0000000000 --- a/components/openssl/library/ssl_rsa.c +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2015-2016 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 "ssl_rsa.h" -#include "ssl_pkey.h" -#include "ssl_x509.h" -#include "ssl_dbg.h" - -/* - * SSL_CTX_use_certificate - set the SSL context certification - * - * @param ctx - SSL context point - * @param x - X509 certification point - * - * @return - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) -{ - SSL_ASSERT(ctx); - SSL_ASSERT(x); - - ctx->cert->x509 = x; - - return 1; -} - -/* - * SSL_CTX_use_certificate_ASN1 - load certification into the SSL context - * - * @param ctx - SSL context point - * @param len - certification context bytes - * @param d - certification context point - * - * @return - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, - const unsigned char *d) -{ - int ret; - X509 *cert; - - cert = d2i_X509(&ctx->cert->x509, d, len); - if (!cert) - SSL_RET(failed1, "d2i_X509\n"); - - ret = SSL_CTX_use_certificate(ctx, cert); - if (!ret) - SSL_RET(failed2, "SSL_CTX_use_certificate\n"); - - return 1; - -failed2: - X509_free(cert); -failed1: - return 0; -} - -/* - * SSL_CTX_use_certificate - set the SSL context private key - * - * @param ctx - SSL context point - * @param x - private key point - * - * @return - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) -{ - SSL_ASSERT(ctx); - SSL_ASSERT(pkey); - - ctx->cert->pkey = pkey; - - return 1; -} - -/* - * SSL_CTX_use_PrivateKey_ASN1 - load private key into the SSL context - * - * @param type - private key type - * @param ctx - SSL context point - * @param d - private key context point - * @param len - private key context bytes - * - * @return - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, - const unsigned char *d, long len) -{ - int ret; - EVP_PKEY *pkey; - - pkey = d2i_PrivateKey(0, &ctx->cert->pkey, &d, len); - if (!pkey) - SSL_RET(failed1, "d2i_PrivateKey\n"); - - ret = SSL_CTX_use_PrivateKey(ctx, pkey); - if (!ret) - SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); - - return 1; - -failed2: - EVP_PKEY_free(pkey); -failed1: - return 0; -} - -/* - * SSL_CTX_add_client_CA - set SSL context client CA certification - * - * @param ctx - SSL context point - * @param x - client CA certification point - * - * @return - * 1 : OK - * 0 : failed - */ -int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) -{ - SSL_ASSERT(ctx); - SSL_ASSERT(x); - - ctx->client_CA = x; - - return 1; -} diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index fd2643e6b7..219f283991 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -98,3 +98,77 @@ failed2: failed1: return NULL; } + +/* + * SSL_CTX_add_client_CA - set SSL context client CA certification + * + * @param ctx - SSL context point + * @param x - client CA certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + ctx->client_CA = x; + + return 1; +} + +/* + * SSL_CTX_use_certificate - set the SSL context certification + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + ctx->cert->x509 = x; + + return 1; +} + +/* + * SSL_CTX_use_certificate_ASN1 - load certification into the SSL context + * + * @param ctx - SSL context point + * @param len - certification context bytes + * @param d - certification context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, + const unsigned char *d) +{ + int ret; + X509 *cert; + + cert = d2i_X509(&ctx->cert->x509, d, len); + if (!cert) + SSL_RET(failed1, "d2i_X509\n"); + + ret = SSL_CTX_use_certificate(ctx, cert); + if (!ret) + SSL_RET(failed2, "SSL_CTX_use_certificate\n"); + + return 1; + +failed2: + X509_free(cert); +failed1: + return 0; +} + diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index b8a046aa1e..948c1bc4ee 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -16,8 +16,6 @@ #include "ssl_port.h" #include "ssl_dbg.h" -#include - /* mbedtls include */ #include "mbedtls/platform.h" #include "mbedtls/net.h" @@ -69,7 +67,9 @@ int ssl_pm_new(SSL *ssl) struct ssl_pm *ssl_pm; int ret; - char *pers; + const unsigned char pers[] = "OpenSSL PM"; + size_t pers_len = sizeof(pers); + int endpoint; int mode; int version; @@ -84,16 +84,6 @@ int ssl_pm_new(SSL *ssl) if (!ssl_pm) SSL_ERR(ret, failed1, "ssl_malloc\n"); - if (method->endpoint) { - pers = "server"; - endpoint = MBEDTLS_SSL_IS_SERVER; - } else { - pers = "client"; - endpoint = MBEDTLS_SSL_IS_CLIENT; - } - - //max_content_len = 4096; - mbedtls_net_init(&ssl_pm->fd); mbedtls_net_init(&ssl_pm->cl_fd); @@ -102,10 +92,15 @@ int ssl_pm_new(SSL *ssl) mbedtls_entropy_init(&ssl_pm->entropy); mbedtls_ssl_init(&ssl_pm->ssl); - ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, (const unsigned char *)pers, strlen(pers)); + ret = mbedtls_ctr_drbg_seed(&ssl_pm->ctr_drbg, mbedtls_entropy_func, &ssl_pm->entropy, pers, pers_len); if (ret) SSL_ERR(ret, failed1, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); + if (method->endpoint) { + endpoint = MBEDTLS_SSL_IS_SERVER; + } else { + endpoint = MBEDTLS_SSL_IS_CLIENT; + } ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret) SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index 4045e29116..3e6ada5cc9 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -12,8 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include #include "ssl_port.h" +#include "string.h" #include "malloc.h" /*********************************************************************************************/ @@ -44,6 +44,11 @@ void* ssl_memcpy(void *to, const void *from, size_t size) return memcpy(to, from, size); } +size_t ssl_strlen(const char *src) +{ + return strlen(src); +} + void ssl_speed_up_enter(void) { From c504fe4856ed259b995dc1eb3cfa72b7dade21aa Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 12:57:39 +0800 Subject: [PATCH 07/95] components/openssl: 1. add stack_st structure and its advanced defination including its derived child defination 2. add SSL_add_client_CA & SSL_get_certificate --- .../openssl/include/internal/ssl_types.h | 19 +++++++++++-- .../openssl/include/internal/ssl_x509.h | 2 ++ components/openssl/library/ssl_x509.c | 27 +++++++++++++++++++ 3 files changed, 46 insertions(+), 2 deletions(-) diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 417350627c..7f8503e2ab 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -20,7 +20,6 @@ typedef void SSL_CIPHER; typedef void X509_STORE_CTX; -typedef void X509_NAME; typedef void X509_STORE; typedef void RSA; @@ -28,7 +27,19 @@ typedef void RSA; typedef void STACK; typedef void BIO; -#define STACK_OF(x) x +#define STACK_OF(type) struct stack_st_##type + +#define SKM_DEFINE_STACK_OF(t1, t2, t3) \ + STACK_OF(t1); \ + static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \ + } \ + +#define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) + +struct stack_st; +typedef struct stack_st OPENSSL_STACK; struct ssl_method_st; typedef struct ssl_method_st SSL_METHOD; @@ -66,6 +77,10 @@ typedef struct x509_method_st X509_METHOD; struct pkey_method_st; typedef struct pkey_method_st PKEY_METHOD; +struct stack_st { + char *data; +}; + struct evp_pkey_st { void *pkey_pm; diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index a169352bac..0583cd94e4 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -17,6 +17,8 @@ #include "ssl_types.h" +DEFINE_STACK_OF(X509_NAME) + X509* sk_X509_NAME_new_null(void); X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 219f283991..e322b6ad3d 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -119,6 +119,21 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) return 1; } +/* + * SSL_add_client_CA - add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - CA certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_add_client_CA(SSL *ssl, X509 *x) +{ + +} + /* * SSL_CTX_use_certificate - set the SSL context certification * @@ -139,6 +154,18 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) return 1; } +/* + * SSL_get_certificate - get the SSL certification point + * + * @param ssl - SSL point + * + * @return SSL certification point + */ +X509 *SSL_get_certificate(const SSL *ssl) +{ + return ssl->cert->x509; +} + /* * SSL_CTX_use_certificate_ASN1 - load certification into the SSL context * From 2cc32db52dd4d4de8a0521153f5dbd598106ec19 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 14:42:49 +0800 Subject: [PATCH 08/95] component/openssl: add openssl stack function and clear unused variate 1. add openssl 'new' and 'free' function 2. add clear unused variate to void warning to appear when compile 3. add internal function 'X509_new' to take the place of 'sk_X509_NAME_new_null' function whitch is openssl stack function --- components/openssl/include/internal/ssl_dbg.h | 6 ++--- .../openssl/include/internal/ssl_types.h | 21 ++++++++++++---- .../openssl/include/internal/ssl_x509.h | 10 +++++++- components/openssl/include/openssl/ssl.h | 4 ++-- components/openssl/library/ssl_cert.c | 2 +- components/openssl/library/ssl_lib.c | 20 +++++----------- components/openssl/library/ssl_pkey.c | 5 +++- components/openssl/library/ssl_x509.c | 24 ++++++++++++++++--- 8 files changed, 62 insertions(+), 30 deletions(-) diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index 27a192b28f..745de536ff 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -15,10 +15,10 @@ #ifndef _SSL_DEBUG_H_ #define _SSL_DEBUG_H_ -#define SSL_DEBUG_ENBALE 1 +#define SSL_DEBUG_ENBALE 0 #define SSL_DEBUG_LEVEL 0 -#define SSL_ASSERT_ENABLE 1 -#define SSL_DEBUG_LOCATION_ENABLE 1 +#define SSL_ASSERT_ENABLE 0 +#define SSL_DEBUG_LOCATION_ENABLE 0 #if SSL_DEBUG_ENBALE extern int ets_printf(const char *fmt, ...); diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 7f8503e2ab..133feb9dc1 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -27,6 +27,12 @@ typedef void RSA; typedef void STACK; typedef void BIO; +#define ossl_inline inline + +#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__) +#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__) +#define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__) + #define STACK_OF(type) struct stack_st_##type #define SKM_DEFINE_STACK_OF(t1, t2, t3) \ @@ -38,6 +44,8 @@ typedef void BIO; #define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) +typedef int (*OPENSSL_sk_compfunc)(const void *, const void *); + struct stack_st; typedef struct stack_st OPENSSL_STACK; @@ -78,7 +86,12 @@ struct pkey_method_st; typedef struct pkey_method_st PKEY_METHOD; struct stack_st { - char *data; + + char **data; + + int num_alloc; + + OPENSSL_sk_compfunc c; }; struct evp_pkey_st { @@ -178,6 +191,8 @@ struct ssl_st int rwstate; + X509 *client_CA; + int err; void (*info_callback) (const SSL *ssl, int type, int val); @@ -249,8 +264,4 @@ typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg); -#define SSL_METHOD_CALL(f, s, ...) s->method->func->ssl_##f(s, ##__VA_ARGS__) -#define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__) -#define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__) - #endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index 0583cd94e4..ee3448544b 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -16,10 +16,18 @@ #define _SSL_X509_H_ #include "ssl_types.h" +#include "ssl_stack.h" DEFINE_STACK_OF(X509_NAME) -X509* sk_X509_NAME_new_null(void); +/* + * sk_X509_NAME_new_null - create a X509 certification object + * + * @param none + * + * @return X509 certification object point or NULL if failed + */ +X509* X509_new(void); X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index 0d4c9c2080..b7506c8fb0 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -15,8 +15,8 @@ #ifndef _SSL_H_ #define _SSL_H_ -#include "ssl_port.h" -#include "internal/ssl_types.h" +#include "platform/ssl_port.h" +#include "internal/ssl_x509.h" /* { diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index 0bdba459d3..caa901b660 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -37,7 +37,7 @@ CERT *ssl_cert_new(void) if (!cert->pkey) SSL_RET(failed2, "EVP_PKEY_new\n"); - cert->x509 = sk_X509_NAME_new_null(); + cert->x509 = X509_new(); if (!cert->x509) SSL_RET(failed3, "sk_X509_NAME_new_null\n"); diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 331ed17bd5..36e8cdf794 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -169,28 +169,27 @@ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) */ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) { - int ret; SSL_CTX *ctx; CERT *cert; X509 *client_ca; if (!method) SSL_RET(go_failed1, "method\n"); - client_ca = sk_X509_NAME_new_null(); + client_ca = X509_new(); if (!client_ca) - SSL_ERR(-2, go_failed1, "sk_X509_NAME_new_null\n"); + SSL_RET(go_failed1, "sk_X509_NAME_new_null\n"); cert = ssl_cert_new(); if (!cert) - SSL_ERR(-2, go_failed2, "ssl_cert_new\n"); + SSL_RET(go_failed2, "ssl_cert_new\n"); ctx = (SSL_CTX *)ssl_zalloc(sizeof(SSL_CTX)); if (!ctx) - SSL_ERR(-2, go_failed3, "ssl_ctx_new:ctx\n"); + SSL_RET(go_failed3, "ssl_ctx_new:ctx\n"); ctx->method = method; - ctx->cert = cert; ctx->client_CA = client_ca; + ctx->cert = cert; ctx->version = method->version; @@ -268,7 +267,6 @@ const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) SSL *SSL_new(SSL_CTX *ctx) { int ret; - void *ssl_pm; SSL *ssl; if (!ctx) @@ -485,7 +483,7 @@ int SSL_write(SSL *ssl, const void *buffer, int len) else bytes = send_bytes; - ret = SSL_METHOD_CALL(send, ssl, buffer, len); + ret = SSL_METHOD_CALL(send, ssl, buffer, bytes); if (ret > 0) { pbuf += ret; send_bytes -= ret; @@ -798,8 +796,6 @@ int SSL_get_wfd(const SSL *ssl) */ int SSL_set_fd(SSL *ssl, int fd) { - int ret; - SSL_ASSERT(ssl); SSL_ASSERT(fd >= 0); @@ -820,8 +816,6 @@ int SSL_set_fd(SSL *ssl, int fd) */ int SSL_set_rfd(SSL *ssl, int fd) { - int ret; - SSL_ASSERT(ssl); SSL_ASSERT(fd >= 0); @@ -842,8 +836,6 @@ int SSL_set_rfd(SSL *ssl, int fd) */ int SSL_set_wfd(SSL *ssl, int fd) { - int ret; - SSL_ASSERT(ssl); SSL_ASSERT(fd >= 0); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 0c8d9de8fa..c9866e27b5 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -78,6 +78,7 @@ EVP_PKEY *d2i_PrivateKey(int type, const unsigned char **pp, long length) { + int m = 0; int ret; EVP_PKEY *pkey; @@ -91,6 +92,7 @@ EVP_PKEY *d2i_PrivateKey(int type, pkey = EVP_PKEY_new();; if (!pkey) SSL_RET(failed1, "ssl_malloc\n"); + m = 1; } ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length); @@ -103,7 +105,8 @@ EVP_PKEY *d2i_PrivateKey(int type, return pkey; failed2: - EVP_PKEY_free(pkey); + if (m) + EVP_PKEY_free(pkey); failed1: return NULL; } diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index e322b6ad3d..9c38849dd6 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -24,7 +24,7 @@ * * @return X509 certification object point or NULL if failed */ -X509* sk_X509_NAME_new_null(void) +X509* X509_new(void) { int ret; X509 *x; @@ -73,6 +73,7 @@ void X509_free(X509 *x) */ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) { + int m = 0; int ret; X509 *x; @@ -82,9 +83,10 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) if (cert && *cert) { x = *cert; } else { - x = sk_X509_NAME_new_null(); + x = X509_new(); if (!x) SSL_RET(failed1, "sk_X509_NAME_new_null\n"); + m = 1; } ret = X509_METHOD_CALL(load, x, buffer, len); @@ -94,7 +96,8 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) return x; failed2: - X509_free(x); + if (m) + X509_free(x); failed1: return NULL; } @@ -111,9 +114,14 @@ failed1: */ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) { + int ret; + SSL_ASSERT(ctx); SSL_ASSERT(x); + if (ctx->client_CA) + X509_free(ctx->client_CA); + ctx->client_CA = x; return 1; @@ -131,7 +139,17 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) */ int SSL_add_client_CA(SSL *ssl, X509 *x) { + int ret; + SSL_ASSERT(ssl); + SSL_ASSERT(x); + + if (ssl->client_CA) + X509_free(ssl->client_CA); + + ssl->client_CA = x; + + return 1; } /* From b3145446aa31118a3ab8d58f771ebc3998cd10cb Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 15:15:16 +0800 Subject: [PATCH 09/95] components/openssl: add function "ssl_pm_get_verify_result" 1. add function ssl_pm_get_verify_result 2. add its platform low-level interface --- components/openssl/include/internal/ssl_code.h | 1 + .../openssl/include/internal/ssl_methods.h | 2 ++ components/openssl/include/internal/ssl_types.h | 4 ++++ components/openssl/include/platform/ssl_pm.h | 2 ++ components/openssl/library/ssl_lib.c | 14 ++++++++++++++ components/openssl/library/ssl_methods.c | 1 + components/openssl/library/ssl_x509.c | 4 ---- components/openssl/platform/ssl_pm.c | 16 ++++++++++++++++ 8 files changed, 40 insertions(+), 4 deletions(-) diff --git a/components/openssl/include/internal/ssl_code.h b/components/openssl/include/internal/ssl_code.h index 1510ce6ff4..de86e07df1 100644 --- a/components/openssl/include/internal/ssl_code.h +++ b/components/openssl/include/internal/ssl_code.h @@ -17,6 +17,7 @@ #include "ssl3.h" #include "tls1.h" +#include "x509_vfy.h" /* Used in SSL_set_shutdown()/SSL_get_shutdown(); */ # define SSL_SENT_SHUTDOWN 1 diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index b72b17ad3d..244eec38dd 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -21,6 +21,7 @@ read, send, pending, \ set_fd, get_fd, \ set_bufflen, \ + get_verify_result, \ get_state) \ static const SSL_METHOD_FUNC func_name LOCAL_ATRR = { \ new, \ @@ -34,6 +35,7 @@ set_fd, \ get_fd, \ set_bufflen, \ + get_verify_result, \ get_state \ }; diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 133feb9dc1..761250eef7 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -193,6 +193,8 @@ struct ssl_st X509 *client_CA; + long verify_result; + int err; void (*info_callback) (const SSL *ssl, int type, int val); @@ -235,6 +237,8 @@ struct ssl_method_func_st { void (*ssl_set_bufflen)(SSL *ssl, int len); + long (*ssl_get_verify_result)(const SSL *ssl); + OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl); }; diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index 783ba5445e..3f64a4ae32 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -49,4 +49,6 @@ void pkey_pm_free(EVP_PKEY *pkey); int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len); void pkey_pm_unload(EVP_PKEY *pkey); +long ssl_pm_get_verify_result(const SSL *ssl); + #endif diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 36e8cdf794..ac41be6276 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -1731,3 +1731,17 @@ void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_C SSL_ASSERT(ssl); SSL_ASSERT(verify_callback); } + +/* + * SSL_get_verify_result - get the verifying result of the SSL certification + * + * @param ssl - the SSL point + * + * @return the result of verifying + */ +long SSL_get_verify_result(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return SSL_METHOD_CALL(get_verify_result, ssl); +} diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index 0c5c6e7fa4..c6fb40e59c 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -25,6 +25,7 @@ IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, ssl_pm_read, ssl_pm_send, ssl_pm_pending, ssl_pm_set_fd, ssl_pm_get_fd, ssl_pm_set_bufflen, + ssl_pm_get_verify_result, ssl_pm_get_state); /* diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 9c38849dd6..102e5a543a 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -114,8 +114,6 @@ failed1: */ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) { - int ret; - SSL_ASSERT(ctx); SSL_ASSERT(x); @@ -139,8 +137,6 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) */ int SSL_add_client_CA(SSL *ssl, X509 *x) { - int ret; - SSL_ASSERT(ssl); SSL_ASSERT(x); diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 948c1bc4ee..ebb9687ea8 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -444,3 +444,19 @@ void ssl_pm_set_bufflen(SSL *ssl, int len) { max_content_len = len; } + +long ssl_pm_get_verify_result(const SSL *ssl) +{ + long ret; + long verify_result; + struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + + ret = mbedtls_ssl_get_verify_result(&ssl_pm->ssl); + + if (!ret) + verify_result = X509_V_OK; + else + verify_result = X509_V_ERR_UNSPECIFIED; + + return verify_result; +} From 6f07409d7c639bfa9a6eecbf97a74d4c8d762861 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 15:30:25 +0800 Subject: [PATCH 10/95] components/openssl: add function to set and get verify depth 1. add function to set and get SSL verify depth 2. add function to set and get SSL context verify depth 3. add X509_VERIFY_PARAM structure --- .../openssl/include/internal/ssl_types.h | 13 +++++ components/openssl/library/ssl_lib.c | 58 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 761250eef7..d001befdb9 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -76,6 +76,9 @@ typedef struct cert_st CERT; struct x509_st; typedef struct x509_st X509; +struct X509_VERIFY_PARAM_st; +typedef struct X509_VERIFY_PARAM_st X509_VERIFY_PARAM; + struct evp_pkey_st; typedef struct evp_pkey_st EVP_PKEY; @@ -139,6 +142,12 @@ struct ssl_session_st { long time; }; +struct X509_VERIFY_PARAM_st { + + int depth; + +}; + struct ssl_ctx_st { int version; @@ -164,6 +173,8 @@ struct ssl_ctx_st int read_ahead; int read_buffer_len; + + X509_VERIFY_PARAM param; }; struct ssl_st @@ -195,6 +206,8 @@ struct ssl_st long verify_result; + X509_VERIFY_PARAM param; + int err; void (*info_callback) (const SSL *ssl, int type, int val); diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index ac41be6276..442920f119 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -1745,3 +1745,61 @@ long SSL_get_verify_result(const SSL *ssl) return SSL_METHOD_CALL(get_verify_result, ssl); } + +/* + * SSL_CTX_get_verify_depth - get the SSL verifying depth of the SSL context + * + * @param ctx - SSL context point + * + * @return verifying depth + */ +int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) +{ + SSL_ASSERT(ctx); + + return ctx->param.depth; +} + +/* + * SSL_CTX_set_verify_depth - set the SSL verify depth of the SSL context + * + * @param ctx - SSL context point + * @param depth - verifying depth + * + * @return one + */ +void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) +{ + SSL_ASSERT(ctx); + + ctx->param.depth = depth; +} + +/* + * SSL_get_verify_depth - get the SSL verifying depth of the SSL + * + * @param ctx - SSL point + * + * @return verifying depth + */ +int SSL_get_verify_depth(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->param.depth; +} + +/* + * SSL_set_verify_depth - set the SSL verify depth of the SSL + * + * @param ctx - SSL point + * @param depth - verifying depth + * + * @return one + */ +void SSL_set_verify_depth(SSL *ssl, int depth) +{ + SSL_ASSERT(ssl); + + ssl->param.depth = depth; +} From 2faa2376a0de66af42ff2c55e00106472090677a Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 15:39:28 +0800 Subject: [PATCH 11/95] components/openssl: add empty function to load verify file into SSL context 1. add empty function to load private key into SSL context 2. add empty function to load certification into SSL context 3. add function to load RSA private key --- components/openssl/include/openssl/ssl.h | 4 +-- components/openssl/library/ssl_pkey.c | 31 ++++++++++++++++++++++++ components/openssl/library/ssl_x509.c | 15 ++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index b7506c8fb0..865405d868 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -927,7 +927,7 @@ int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, l * 1 : OK * 0 : failed */ -int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type);//adds the first private key found in file to ctx, The formatting type of the certificate must be specified from the known types SSL_FILETYPE_PEM, SSL_FILETYPE_ASN1. +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); /* * SSL_CTX_use_certificate - load the RSA private key into SSL context @@ -952,7 +952,7 @@ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); * 1 : OK * 0 : failed */ -int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, unsigned char *d, long len); +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); /* * SSL_CTX_use_certificate_file - load the RSA private key file into SSL context diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index c9866e27b5..1ab080ac28 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -165,3 +165,34 @@ failed1: return 0; } +/* + * SSL_CTX_use_certificate_file - load the private key file into SSL context + * + * @param ctx - SSL context point + * @param file - private key file name + * @param type - private key encoding type + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + +/* + * SSL_CTX_use_certificate_ASN1 - load the RSA ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - RSA private key length + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len) +{ + return SSL_CTX_use_PrivateKey_ASN1(0, ctx, d, len); +} diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 102e5a543a..b0ddd42593 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -213,3 +213,18 @@ failed1: return 0; } +/* + * SSL_CTX_use_certificate_file - load the certification file into SSL context + * + * @param ctx - SSL context point + * @param file - certification file name + * @param type - certification encoding type + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} From a99f6bd727cea8d8cdee32d2f28b09c6cf4fae99 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 15:56:56 +0800 Subject: [PATCH 12/95] components/openssl: add function load verify data into SSL 1. add function to load private key into SSL 1. add function to load certification into SSL --- components/openssl/library/ssl_pkey.c | 70 ++++++++++++++++++++++++++ components/openssl/library/ssl_x509.c | 71 +++++++++++++++++++++++++++ 2 files changed, 141 insertions(+) diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 1ab080ac28..a86a257e98 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -131,6 +131,26 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) return 1; } +/* + * SSL_CTX_use_certificate - set the SSL private key + * + * @param ctx - SSL point + * @param x - private key point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(pkey); + + ssl->cert->pkey = pkey; + + return 1; +} + /* * SSL_CTX_use_PrivateKey_ASN1 - load private key into the SSL context * @@ -165,6 +185,40 @@ failed1: return 0; } +/* + * SSL_use_PrivateKey_ASN1 - load private key into the SSL + * + * @param type - private key type + * @param ctx - SSL context point + * @param d - private key context point + * @param len - private key context bytes + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, + const unsigned char *d, long len) +{ + int ret; + EVP_PKEY *pkey; + + pkey = d2i_PrivateKey(0, &ssl->cert->pkey, &d, len); + if (!pkey) + SSL_RET(failed1, "d2i_PrivateKey\n"); + + ret = SSL_use_PrivateKey(ssl, pkey); + if (!ret) + SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); + + return 1; + +failed2: + EVP_PKEY_free(pkey); +failed1: + return 0; +} + /* * SSL_CTX_use_certificate_file - load the private key file into SSL context * @@ -181,6 +235,22 @@ int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) return 0; } +/* + * SSL_use_PrivateKey_file - load the private key file into SSL + * + * @param ctx - SSL point + * @param file - private key file name + * @param type - private key encoding type + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) +{ + return 0; +} + /* * SSL_CTX_use_certificate_ASN1 - load the RSA ASN1 private key into SSL context * diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index b0ddd42593..ba5c924e75 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -168,6 +168,26 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) return 1; } +/* + * SSL_CTX_use_certificate - set the SSL certification + * + * @param ctx - SSL point + * @param x - X509 certification point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_use_certificate(SSL *ssl, X509 *x) +{ + SSL_ASSERT(ctx); + SSL_ASSERT(x); + + ssl->cert->x509 = x; + + return 1; +} + /* * SSL_get_certificate - get the SSL certification point * @@ -177,6 +197,8 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) */ X509 *SSL_get_certificate(const SSL *ssl) { + SSL_ASSERT(ssl); + return ssl->cert->x509; } @@ -213,6 +235,39 @@ failed1: return 0; } +/* + * SSL_use_certificate_ASN1 - load certification into the SSL + * + * @param ctx - SSL point + * @param len - certification context bytes + * @param d - certification context point + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_use_certificate_ASN1(SSL *ssl, int len, + const unsigned char *d) +{ + int ret; + X509 *cert; + + cert = d2i_X509(&ssl->cert->x509, d, len); + if (!cert) + SSL_RET(failed1, "d2i_X509\n"); + + ret = SSL_use_certificate(ssl, cert); + if (!ret) + SSL_RET(failed2, "SSL_use_certificate\n"); + + return 1; + +failed2: + X509_free(cert); +failed1: + return 0; +} + /* * SSL_CTX_use_certificate_file - load the certification file into SSL context * @@ -228,3 +283,19 @@ int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) { return 0; } + +/* + * SSL_use_certificate_file - load the certification file into SSL + * + * @param ctx - SSL point + * @param file - certification file name + * @param type - certification encoding type + * + * @return + * 1 : OK + * 0 : failed + */ +int SSL_use_certificate_file(SSL *ssl, const char *file, int type) +{ + return 0; +} From fa6f03f77f3ff81f676d6bad017194c50d7cc2a1 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 16:08:36 +0800 Subject: [PATCH 13/95] components/openssl: add function to load certification or private key more than one time --- components/openssl/platform/ssl_pm.c | 42 ++++++++++++++++------------ 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index ebb9687ea8..17cc080bb6 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -339,6 +339,16 @@ int x509_pm_new(X509 *x) return 0; } +void x509_pm_unload(X509 *x) +{ + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; + + if (x509_pm->load) + mbedtls_x509_crt_free(&x509_pm->x509_crt); + + x509_pm->load = 0; +} + int x509_pm_load(X509 *x, const unsigned char *buffer, int len) { int ret; @@ -352,6 +362,8 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; + x509_pm_unload(x); + mbedtls_x509_crt_init(&x509_pm->x509_crt); ret = mbedtls_x509_crt_parse(&x509_pm->x509_crt, load_buf, len); ssl_free(load_buf); @@ -367,15 +379,6 @@ failed1: return -1; } -void x509_pm_unload(X509 *x) -{ - struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; - - mbedtls_x509_crt_free(&x509_pm->x509_crt); - - x509_pm->load = 0; -} - void x509_pm_free(X509 *x) { x509_pm_unload(x); @@ -396,6 +399,16 @@ int pkey_pm_new(EVP_PKEY *pkey) return 0; } +void pkey_pm_unload(EVP_PKEY *pkey) +{ + struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; + + if (pkey_pm->load) + mbedtls_pk_free(&pkey_pm->pkey); + + pkey_pm->load = 0; +} + int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len) { int ret; @@ -409,6 +422,8 @@ int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len) ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; + pkey_pm_unload(pkey); + mbedtls_pk_init(&pkey_pm->pkey); ret = mbedtls_pk_parse_key(&pkey_pm->pkey, load_buf, len, NULL, 0); ssl_free(load_buf); @@ -424,15 +439,6 @@ failed1: return -1; } -void pkey_pm_unload(EVP_PKEY *pkey) -{ - struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; - - mbedtls_pk_free(&pkey_pm->pkey); - - pkey_pm->load = 0; -} - void pkey_pm_free(EVP_PKEY *pkey) { pkey_pm_unload(pkey); From f796b4e58ef2311e11b51f15ef5e8807c84c5272 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 16:41:51 +0800 Subject: [PATCH 14/95] components/openssl: SSL load verify data from itself structure when "new" --- components/openssl/include/internal/ssl_types.h | 4 ++++ components/openssl/library/ssl_lib.c | 3 +++ components/openssl/library/ssl_pkey.c | 9 ++++++++- components/openssl/library/ssl_x509.c | 12 ++++++++++-- components/openssl/platform/ssl_pm.c | 6 +++--- 5 files changed, 28 insertions(+), 6 deletions(-) diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index d001befdb9..6f2fb5a2f2 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -99,6 +99,8 @@ struct stack_st { struct evp_pkey_st { + int ref; + void *pkey_pm; const PKEY_METHOD *method; @@ -106,6 +108,8 @@ struct evp_pkey_st { struct x509_st { + int ref; + /* X509 certification platform private point */ void *x509_pm; diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 442920f119..7e3b4554d6 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -282,6 +282,9 @@ SSL *SSL_new(SSL_CTX *ctx) ssl->version = ctx->version; ssl->options = ctx->options; + ssl->cert = ctx->cert; + ssl->client_CA = ctx->client_CA; + ret = SSL_METHOD_CALL(new, ssl); if (ret) SSL_RET(failed2, "ssl_new\n"); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index a86a257e98..15c4977b0f 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -177,6 +177,8 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, if (!ret) SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); + ctx->cert->pkey->ref++; + return 1; failed2: @@ -203,7 +205,10 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, int ret; EVP_PKEY *pkey; - pkey = d2i_PrivateKey(0, &ssl->cert->pkey, &d, len); + if (ssl->cert->pkey->ref) + SSL_RET(failed1); + + pkey = d2i_PrivateKey(0, NULL, &d, len); if (!pkey) SSL_RET(failed1, "d2i_PrivateKey\n"); @@ -211,6 +216,8 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, if (!ret) SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); + ssl->cert->pkey->ref++; + return 1; failed2: diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index ba5c924e75..6e249eef58 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -85,7 +85,7 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) } else { x = X509_new(); if (!x) - SSL_RET(failed1, "sk_X509_NAME_new_null\n"); + SSL_RET(failed1, "X509_new\n"); m = 1; } @@ -218,6 +218,7 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, { int ret; X509 *cert; + const unsigned char *pbuf; cert = d2i_X509(&ctx->cert->x509, d, len); if (!cert) @@ -227,6 +228,8 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, if (!ret) SSL_RET(failed2, "SSL_CTX_use_certificate\n"); + ctx->cert->x509->ref++; + return 1; failed2: @@ -252,7 +255,10 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, int ret; X509 *cert; - cert = d2i_X509(&ssl->cert->x509, d, len); + if (ssl->cert->x509->ref) + SSL_RET(failed1); + + cert = d2i_X509(NULL, d, len); if (!cert) SSL_RET(failed1, "d2i_X509\n"); @@ -260,6 +266,8 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, if (!ret) SSL_RET(failed2, "SSL_use_certificate\n"); + ssl->cert->x509->ref++; + return 1; failed2: diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 17cc080bb6..d4ed2ececb 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -120,7 +120,7 @@ int ssl_pm_new(SSL *ssl) mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL); - x509_pm = (struct x509_pm *)ctx->client_CA->x509_pm; + x509_pm = (struct x509_pm *)ssl->client_CA->x509_pm; if (x509_pm->load) { mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &x509_pm->x509_crt, NULL); @@ -130,9 +130,9 @@ int ssl_pm_new(SSL *ssl) } mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); - pkey_pm = (struct pkey_pm *)ctx->cert->pkey->pkey_pm; + pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; if (pkey_pm->load) { - x509_pm = (struct x509_pm *)ctx->cert->x509->x509_pm; + x509_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); if (ret) From 18787fd4fc9e1a0defb66cb29541432b8c76c4a9 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 17:20:07 +0800 Subject: [PATCH 15/95] components/openssl: add empty fucntion to get peer certification and fix ref overflow --- .../openssl/include/internal/ssl_types.h | 2 ++ components/openssl/library/ssl_pkey.c | 4 ++-- components/openssl/library/ssl_x509.c | 19 ++++++++++++++++--- components/openssl/platform/ssl_pm.c | 5 ++--- 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 6f2fb5a2f2..7a0bd0d76f 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -144,6 +144,8 @@ struct ssl_session_st { long timeout; long time; + + X509 *peer; }; struct X509_VERIFY_PARAM_st { diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 15c4977b0f..7278287a63 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -177,7 +177,7 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, if (!ret) SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); - ctx->cert->pkey->ref++; + ctx->cert->pkey->ref = 1; return 1; @@ -216,7 +216,7 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, if (!ret) SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); - ssl->cert->pkey->ref++; + ssl->cert->pkey->ref = 1; return 1; diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 6e249eef58..19c94c3eca 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -218,7 +218,6 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, { int ret; X509 *cert; - const unsigned char *pbuf; cert = d2i_X509(&ctx->cert->x509, d, len); if (!cert) @@ -228,7 +227,7 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, if (!ret) SSL_RET(failed2, "SSL_CTX_use_certificate\n"); - ctx->cert->x509->ref++; + ctx->cert->x509->ref = 1; return 1; @@ -266,7 +265,7 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, if (!ret) SSL_RET(failed2, "SSL_use_certificate\n"); - ssl->cert->x509->ref++; + ssl->cert->x509->ref = 1; return 1; @@ -307,3 +306,17 @@ int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { return 0; } + +/* + * SSL_get_peer_certificate - get peer certification + * + * @param ssl - SSL point + * + * @return certification + */ +X509 *SSL_get_peer_certificate(const SSL *ssl) +{ + SSL_ASSERT(ssl); + + return ssl->session.peer; +} diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index d4ed2ececb..1ddd1f30d2 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -74,7 +74,6 @@ int ssl_pm_new(SSL *ssl) int mode; int version; - SSL_CTX *ctx = ssl->ctx; const SSL_METHOD *method = ssl->method; struct x509_pm *x509_pm; @@ -185,9 +184,9 @@ int ssl_pm_handshake(SSL *ssl) } ssl_speed_up_exit(); - if (!mbed_ret) + if (!mbed_ret) { ret = 1; - else { + } else { ret = 0; SSL_DEBUG(1, "mbedtls_ssl_handshake [-0x%x]\n", -mbed_ret); } From 1bfedf9816a12581a35a053b964b40b8182c44d9 Mon Sep 17 00:00:00 2001 From: dongheng Date: Thu, 22 Sep 2016 18:33:55 +0800 Subject: [PATCH 16/95] components/openssl: fix the SSL_free memory leak --- components/openssl/library/ssl_lib.c | 2 +- components/openssl/platform/ssl_pm.c | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 7e3b4554d6..20c8931457 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -266,7 +266,7 @@ const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) */ SSL *SSL_new(SSL_CTX *ctx) { - int ret; + int ret = 0; SSL *ssl; if (!ctx) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 1ddd1f30d2..04e370f9fc 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -162,13 +162,13 @@ void ssl_pm_free(SSL *ssl) { struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; - mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); mbedtls_entropy_free(&ssl_pm->entropy); + mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ssl_free(&ssl_pm->ssl); - mbedtls_net_free(&ssl_pm->fd); - mbedtls_net_free(&ssl_pm->cl_fd); + ssl_free(ssl_pm); + ssl->ssl_pm = NULL; } int ssl_pm_handshake(SSL *ssl) @@ -383,6 +383,7 @@ void x509_pm_free(X509 *x) x509_pm_unload(x); ssl_free(x->x509_pm); + x->x509_pm = NULL; } int pkey_pm_new(EVP_PKEY *pkey) @@ -443,6 +444,7 @@ void pkey_pm_free(EVP_PKEY *pkey) pkey_pm_unload(pkey); ssl_free(pkey->pkey_pm); + pkey->pkey_pm = NULL; } void ssl_pm_set_bufflen(SSL *ssl, int len) From 9fc054bb553c3df68eb3f956c4496ac178422c3f Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 10:33:31 +0800 Subject: [PATCH 17/95] components/openssl: SSL load cert with creating new cert object 1. when 'SSL_new' SSL's cert is pointed to SSL context cert If SSL load new cert, it will create a new cert object 2. change some debug informaion --- .../openssl/include/internal/ssl_types.h | 13 ++--- components/openssl/library/ssl_cert.c | 2 +- components/openssl/library/ssl_lib.c | 6 +++ components/openssl/library/ssl_pkey.c | 44 +++++++++++----- components/openssl/library/ssl_x509.c | 50 +++++++++++++------ components/openssl/platform/ssl_pm.c | 32 +++++++----- 6 files changed, 100 insertions(+), 47 deletions(-) diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 7a0bd0d76f..c872c5191c 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -99,8 +99,6 @@ struct stack_st { struct evp_pkey_st { - int ref; - void *pkey_pm; const PKEY_METHOD *method; @@ -108,8 +106,6 @@ struct evp_pkey_st { struct x509_st { - int ref; - /* X509 certification platform private point */ void *x509_pm; @@ -127,6 +123,7 @@ struct cert_st { }; struct ossl_statem_st { + MSG_FLOW_STATE state; int hand_state; @@ -193,8 +190,14 @@ struct ssl_st /* shut things down(0x01 : sent, 0x02 : received) */ int shutdown; + int crt_reload; + CERT *cert; + int ca_reload; + + X509 *client_CA; + SSL_CTX *ctx; const SSL_METHOD *method; @@ -208,8 +211,6 @@ struct ssl_st int rwstate; - X509 *client_CA; - long verify_result; X509_VERIFY_PARAM param; diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index caa901b660..2d82e62aaa 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -39,7 +39,7 @@ CERT *ssl_cert_new(void) cert->x509 = X509_new(); if (!cert->x509) - SSL_RET(failed3, "sk_X509_NAME_new_null\n"); + SSL_RET(failed3, "X509_new\n"); return cert; diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 20c8931457..cc218f9a26 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -312,6 +312,12 @@ void SSL_free(SSL *ssl) SSL_METHOD_CALL(free, ssl); + if (ssl->ca_reload) + X509_free(ssl->client_CA); + + if (ssl->crt_reload) + ssl_cert_free(ssl->cert); + ssl_free(ssl); } diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 7278287a63..c77785f473 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -14,6 +14,7 @@ #include "ssl_lib.h" #include "ssl_pkey.h" +#include "ssl_cert.h" #include "ssl_methods.h" #include "ssl_dbg.h" #include "ssl_port.h" @@ -38,7 +39,7 @@ EVP_PKEY* EVP_PKEY_new(void) ret = EVP_PKEY_METHOD_CALL(new, pkey); if (ret) - SSL_RET(failed2, "pkey_new\n"); + SSL_RET(failed2, "EVP_PKEY_METHOD_CALL\n"); return pkey; @@ -91,13 +92,13 @@ EVP_PKEY *d2i_PrivateKey(int type, } else { pkey = EVP_PKEY_new();; if (!pkey) - SSL_RET(failed1, "ssl_malloc\n"); + SSL_RET(failed1, "EVP_PKEY_new\n"); m = 1; } ret = EVP_PKEY_METHOD_CALL(load, pkey, *pp, length); if (ret) - SSL_RET(failed2, "pkey_pm_load_crt\n"); + SSL_RET(failed2, "EVP_PKEY_METHOD_CALL\n"); if (a) *a = pkey; @@ -177,8 +178,6 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, if (!ret) SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); - ctx->cert->pkey->ref = 1; - return 1; failed2: @@ -203,25 +202,44 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len) { int ret; + int reload; EVP_PKEY *pkey; + CERT *cert; + CERT *old_cert; - if (ssl->cert->pkey->ref) - SSL_RET(failed1); + if (!ssl->crt_reload) { + cert = ssl_cert_new(); + if (!cert) + SSL_RET(failed1, "ssl_cert_new\n"); - pkey = d2i_PrivateKey(0, NULL, &d, len); + old_cert = ssl->cert ; + ssl->cert = cert; + + ssl->crt_reload = 1; + + reload = 1; + } else { + reload = 0; + } + + pkey = d2i_PrivateKey(0, &ssl->cert->pkey, &d, len); if (!pkey) - SSL_RET(failed1, "d2i_PrivateKey\n"); + SSL_RET(failed2, "d2i_PrivateKey\n"); ret = SSL_use_PrivateKey(ssl, pkey); if (!ret) - SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); - - ssl->cert->pkey->ref = 1; + SSL_RET(failed3, "SSL_use_PrivateKey\n"); return 1; -failed2: +failed3: EVP_PKEY_free(pkey); +failed2: + if (reload) { + ssl->cert = old_cert; + ssl_cert_free(cert); + ssl->crt_reload = 0; + } failed1: return 0; } diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 19c94c3eca..9ca60d8b31 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -13,6 +13,7 @@ // limitations under the License. #include "ssl_x509.h" +#include "ssl_cert.h" #include "ssl_methods.h" #include "ssl_dbg.h" #include "ssl_port.h" @@ -91,7 +92,7 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) ret = X509_METHOD_CALL(load, x, buffer, len); if (ret) - SSL_RET(failed2, "x509_load\n"); + SSL_RET(failed2, "X509_METHOD_CALL\n"); return x; @@ -140,7 +141,9 @@ int SSL_add_client_CA(SSL *ssl, X509 *x) SSL_ASSERT(ssl); SSL_ASSERT(x); - if (ssl->client_CA) + if (!ssl->ca_reload) + ssl->ca_reload = 1; + else X509_free(ssl->client_CA); ssl->client_CA = x; @@ -227,8 +230,6 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, if (!ret) SSL_RET(failed2, "SSL_CTX_use_certificate\n"); - ctx->cert->x509->ref = 1; - return 1; failed2: @@ -252,25 +253,44 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d) { int ret; - X509 *cert; + int reload; + X509 *x; + CERT *cert; + CERT *old_cert; - if (ssl->cert->x509->ref) - SSL_RET(failed1); + if (!ssl->crt_reload) { + cert = ssl_cert_new(); + if (!cert) + SSL_RET(failed1, "ssl_cert_new\n"); - cert = d2i_X509(NULL, d, len); - if (!cert) - SSL_RET(failed1, "d2i_X509\n"); + old_cert = ssl->cert ; + ssl->cert = cert; - ret = SSL_use_certificate(ssl, cert); + ssl->crt_reload = 1; + + reload = 1; + } else { + reload = 0; + } + + x = d2i_X509(&ssl->cert->x509, d, len); + if (!x) + SSL_RET(failed2, "d2i_X509\n"); + + ret = SSL_use_certificate(ssl, x); if (!ret) - SSL_RET(failed2, "SSL_use_certificate\n"); - - ssl->cert->x509->ref = 1; + SSL_RET(failed3, "SSL_use_certificate\n"); return 1; +failed3: + X509_free(x); failed2: - X509_free(cert); + if (reload) { + ssl->cert = old_cert; + ssl_cert_free(cert); + ssl->crt_reload = 0; + } failed1: return 0; } diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 04e370f9fc..54e6cba25c 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -43,16 +43,16 @@ struct ssl_pm struct x509_pm { - int load; - mbedtls_x509_crt x509_crt; + + int load; }; struct pkey_pm { - int load; - mbedtls_pk_context pkey; + + int load; }; @@ -79,9 +79,13 @@ int ssl_pm_new(SSL *ssl) struct x509_pm *x509_pm; struct pkey_pm *pkey_pm; + ssl->session.peer = ssl_malloc(sizeof(X509)); + if (!ssl->session.peer) + SSL_ERR(ret, failed1, "ssl_malloc\n"); + ssl_pm = ssl_malloc(sizeof(struct ssl_pm)); if (!ssl_pm) - SSL_ERR(ret, failed1, "ssl_malloc\n"); + SSL_ERR(ret, failed2, "ssl_malloc\n"); mbedtls_net_init(&ssl_pm->fd); mbedtls_net_init(&ssl_pm->cl_fd); @@ -93,7 +97,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); if (ret) - SSL_ERR(ret, failed1, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); + SSL_ERR(ret, failed3, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); if (method->endpoint) { endpoint = MBEDTLS_SSL_IS_SERVER; @@ -102,7 +106,7 @@ int ssl_pm_new(SSL *ssl) } ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret) - SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); + SSL_ERR(ret, failed3, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); if (TLS1_2_VERSION == ssl->version) version = MBEDTLS_SSL_MINOR_VERSION_3; @@ -135,12 +139,12 @@ int ssl_pm_new(SSL *ssl) ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); if (ret) - SSL_ERR(ret, failed3, "mbedtls_ssl_conf_own_cert:[%d]\n", ret); + SSL_ERR(ret, failed4, "mbedtls_ssl_conf_own_cert:[%d]\n", ret); } ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); if (ret) - SSL_ERR(ret, failed4, "mbedtls_ssl_setup:[-0x%x]\n", -ret); + SSL_ERR(ret, failed5, "mbedtls_ssl_setup:[-0x%x]\n", -ret); mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); @@ -148,12 +152,14 @@ int ssl_pm_new(SSL *ssl) return 0; -failed4: +failed5: mbedtls_ssl_config_free(&ssl_pm->conf); -failed3: +failed4: mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); -failed2: +failed3: mbedtls_entropy_free(&ssl_pm->entropy); +failed2: + ssl_free(ssl->session.peer); failed1: return -1; } @@ -186,6 +192,8 @@ int ssl_pm_handshake(SSL *ssl) if (!mbed_ret) { ret = 1; + + ssl->session.peer = (X509 *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); } else { ret = 0; SSL_DEBUG(1, "mbedtls_ssl_handshake [-0x%x]\n", -mbed_ret); From 07c8bbca6c70836b46cf040a472eb348b1d9f59d Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 10:53:18 +0800 Subject: [PATCH 18/95] components/openssl: SSL low-level reload cert when user add new cert --- .../openssl/include/internal/ssl_methods.h | 2 ++ .../openssl/include/internal/ssl_types.h | 2 ++ components/openssl/include/platform/ssl_pm.h | 2 ++ components/openssl/library/ssl_methods.c | 1 + components/openssl/library/ssl_pkey.c | 19 +++++++++++- components/openssl/library/ssl_x509.c | 11 ++++++- components/openssl/platform/ssl_pm.c | 30 +++++++++++++++++++ 7 files changed, 65 insertions(+), 2 deletions(-) diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index 244eec38dd..2893db1888 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -22,6 +22,7 @@ set_fd, get_fd, \ set_bufflen, \ get_verify_result, \ + ssl_reload_crt, \ get_state) \ static const SSL_METHOD_FUNC func_name LOCAL_ATRR = { \ new, \ @@ -36,6 +37,7 @@ get_fd, \ set_bufflen, \ get_verify_result, \ + ssl_reload_crt, \ get_state \ }; diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index c872c5191c..47e6b0bf65 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -259,6 +259,8 @@ struct ssl_method_func_st { long (*ssl_get_verify_result)(const SSL *ssl); + int (*ssl_reload_crt)(SSL *ssl); + OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl); }; diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index 3f64a4ae32..53bff0d80e 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -51,4 +51,6 @@ void pkey_pm_unload(EVP_PKEY *pkey); long ssl_pm_get_verify_result(const SSL *ssl); +int ssl_pm_reload_crt(SSL *ssl); + #endif diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index c6fb40e59c..0674f40587 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -26,6 +26,7 @@ IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, ssl_pm_set_fd, ssl_pm_get_fd, ssl_pm_set_bufflen, ssl_pm_get_verify_result, + ssl_pm_reload_crt, ssl_pm_get_state); /* diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index c77785f473..893a391dd8 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -127,6 +127,9 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) SSL_ASSERT(ctx); SSL_ASSERT(pkey); + if (ctx->cert->pkey) + EVP_PKEY_free(ctx->cert->pkey); + ctx->cert->pkey = pkey; return 1; @@ -144,12 +147,26 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) */ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { + int ret; + int ssl_ret; + SSL_ASSERT(ctx); SSL_ASSERT(pkey); + if (!ssl->ca_reload) + ssl->ca_reload = 1; + else + EVP_PKEY_free(ssl->cert->pkey); + ssl->cert->pkey = pkey; - return 1; + ssl_ret = SSL_METHOD_CALL(reload_crt, ssl); + if (ssl_ret) + ret = 0; + else + ret = 1; + + return ret; } /* diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 9ca60d8b31..2368344a7a 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -138,6 +138,9 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) */ int SSL_add_client_CA(SSL *ssl, X509 *x) { + int ret; + int ssl_ret; + SSL_ASSERT(ssl); SSL_ASSERT(x); @@ -148,7 +151,13 @@ int SSL_add_client_CA(SSL *ssl, X509 *x) ssl->client_CA = x; - return 1; + ssl_ret = SSL_METHOD_CALL(reload_crt, ssl); + if (ssl_ret) + ret = 0; + else + ret = 1; + + return ret; } /* diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 54e6cba25c..00c8f83020 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -475,3 +475,33 @@ long ssl_pm_get_verify_result(const SSL *ssl) return verify_result; } + +int ssl_pm_reload_crt(SSL *ssl) +{ + int ret; + int mode; + struct ssl_pm *ssl_pm = ssl->ssl_pm; + struct x509_pm *x509_pm; + struct pkey_pm *pkey_pm; + + x509_pm = (struct x509_pm *)ssl->client_CA->x509_pm; + if (x509_pm->load) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &x509_pm->x509_crt, NULL); + + mode = MBEDTLS_SSL_VERIFY_REQUIRED; + } else { + mode = MBEDTLS_SSL_VERIFY_NONE; + } + mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); + + pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; + if (pkey_pm->load) { + x509_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; + + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); + if (ret) + return -1; + } + + return 0; +} From f5d9bfc7aecdda78f849e0f9bd7dd4b228feb8ab Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 11:03:13 +0800 Subject: [PATCH 19/95] components/openssl: fix SSL get peer cert struct point type error 1. fix SSL get peer cert struct point type error 2. some function use "zalloc" instead of "malloc" --- components/openssl/library/ssl_pkey.c | 2 +- components/openssl/library/ssl_x509.c | 2 +- components/openssl/platform/ssl_pm.c | 18 +++++++++--------- components/openssl/platform/ssl_port.c | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 893a391dd8..ab56fe789d 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -31,7 +31,7 @@ EVP_PKEY* EVP_PKEY_new(void) int ret; EVP_PKEY *pkey; - pkey = ssl_malloc(sizeof(EVP_PKEY)); + pkey = ssl_zalloc(sizeof(EVP_PKEY)); if (!pkey) SSL_RET(failed1, "ssl_malloc\n"); diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 2368344a7a..431f03caa9 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -30,7 +30,7 @@ X509* X509_new(void) int ret; X509 *x; - x = ssl_malloc(sizeof(X509)); + x = ssl_zalloc(sizeof(X509)); if (!x) SSL_RET(failed1, "ssl_malloc\n"); diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 00c8f83020..10b736aa9c 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -79,13 +79,13 @@ int ssl_pm_new(SSL *ssl) struct x509_pm *x509_pm; struct pkey_pm *pkey_pm; - ssl->session.peer = ssl_malloc(sizeof(X509)); + ssl->session.peer = ssl_zalloc(sizeof(X509)); if (!ssl->session.peer) - SSL_ERR(ret, failed1, "ssl_malloc\n"); + SSL_ERR(ret, failed1, "ssl_zalloc\n"); - ssl_pm = ssl_malloc(sizeof(struct ssl_pm)); + ssl_pm = ssl_zalloc(sizeof(struct ssl_pm)); if (!ssl_pm) - SSL_ERR(ret, failed2, "ssl_malloc\n"); + SSL_ERR(ret, failed2, "ssl_zalloc\n"); mbedtls_net_init(&ssl_pm->fd); mbedtls_net_init(&ssl_pm->cl_fd); @@ -193,7 +193,7 @@ int ssl_pm_handshake(SSL *ssl) if (!mbed_ret) { ret = 1; - ssl->session.peer = (X509 *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); + ssl->session.peer->x509_pm = (struct x509_pm *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); } else { ret = 0; SSL_DEBUG(1, "mbedtls_ssl_handshake [-0x%x]\n", -mbed_ret); @@ -337,7 +337,7 @@ int x509_pm_new(X509 *x) { struct x509_pm *x509_pm; - x509_pm = ssl_malloc(sizeof(struct x509_pm)); + x509_pm = ssl_zalloc(sizeof(struct x509_pm)); if (!x509_pm) return -1; @@ -364,7 +364,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) load_buf = ssl_malloc(len + 1); if (!load_buf) - SSL_RET(failed1, ""); + SSL_RET(failed1); ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; @@ -398,7 +398,7 @@ int pkey_pm_new(EVP_PKEY *pkey) { struct pkey_pm *pkey_pm; - pkey_pm = ssl_malloc(sizeof(struct pkey_pm)); + pkey_pm = ssl_zalloc(sizeof(struct pkey_pm)); if (!pkey_pm) return -1; @@ -425,7 +425,7 @@ int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len) load_buf = ssl_malloc(len + 1); if (!load_buf) - SSL_RET(failed1, ""); + SSL_RET(failed1); ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index 3e6ada5cc9..b57e703a17 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -31,7 +31,7 @@ void* ssl_zalloc(size_t size) void *ssl_malloc(size_t size) { - return ssl_zalloc(size); + return malloc(size); } void ssl_free(void *p) From e475d0539eb8c960f7996d0ec6c0842f4534a235 Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 11:41:57 +0800 Subject: [PATCH 20/95] components/openssl: add SSL and SSL context verify mode selection --- .../openssl/include/internal/ssl_code.h | 5 + .../openssl/include/internal/ssl_methods.h | 2 - .../openssl/include/internal/ssl_types.h | 8 +- components/openssl/include/platform/ssl_pm.h | 2 - components/openssl/library/ssl_lib.c | 50 +++++++--- components/openssl/library/ssl_methods.c | 1 - components/openssl/library/ssl_pkey.c | 8 +- components/openssl/library/ssl_x509.c | 11 +-- components/openssl/platform/ssl_pm.c | 96 ++++++++----------- 9 files changed, 88 insertions(+), 95 deletions(-) diff --git a/components/openssl/include/internal/ssl_code.h b/components/openssl/include/internal/ssl_code.h index de86e07df1..e76b35abe9 100644 --- a/components/openssl/include/internal/ssl_code.h +++ b/components/openssl/include/internal/ssl_code.h @@ -23,6 +23,11 @@ # define SSL_SENT_SHUTDOWN 1 # define SSL_RECEIVED_SHUTDOWN 2 +# define SSL_VERIFY_NONE 0x00 +# define SSL_VERIFY_PEER 0x01 +# define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 0x02 +# define SSL_VERIFY_CLIENT_ONCE 0x04 + /* * The following 3 states are kept in ssl->rlayer.rstate when reads fail, you * should not need these diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index 2893db1888..244eec38dd 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -22,7 +22,6 @@ set_fd, get_fd, \ set_bufflen, \ get_verify_result, \ - ssl_reload_crt, \ get_state) \ static const SSL_METHOD_FUNC func_name LOCAL_ATRR = { \ new, \ @@ -37,7 +36,6 @@ get_fd, \ set_bufflen, \ get_verify_result, \ - ssl_reload_crt, \ get_state \ }; diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 47e6b0bf65..6da6076148 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -171,6 +171,8 @@ struct ssl_ctx_st int verify_mode; + int (*default_verify_callback) (int ok, X509_STORE_CTX *ctx); + long session_timeout; int read_ahead; @@ -209,6 +211,10 @@ struct ssl_st SSL_SESSION session; + int verify_mode; + + int (*verify_callback) (int ok, X509_STORE_CTX *ctx); + int rwstate; long verify_result; @@ -259,8 +265,6 @@ struct ssl_method_func_st { long (*ssl_get_verify_result)(const SSL *ssl); - int (*ssl_reload_crt)(SSL *ssl); - OSSL_HANDSHAKE_STATE (*ssl_get_state)(const SSL *ssl); }; diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index 53bff0d80e..3f64a4ae32 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -51,6 +51,4 @@ void pkey_pm_unload(EVP_PKEY *pkey); long ssl_pm_get_verify_result(const SSL *ssl); -int ssl_pm_reload_crt(SSL *ssl); - #endif diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index cc218f9a26..ae517b0a40 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -284,6 +284,7 @@ SSL *SSL_new(SSL_CTX *ctx) ssl->cert = ctx->cert; ssl->client_CA = ctx->client_CA; + ssl->verify_mode = ctx->verify_mode; ret = SSL_METHOD_CALL(new, ssl); if (ret) @@ -1726,21 +1727,6 @@ long SSL_set_timeout(SSL *ssl, long t) return t; } -/* - * SSL_set_verify - set the SSL verifying of the SSL context - * - * @param ctx - SSL point - * @param mode - verifying mode - * @param verify_callback - verifying callback function - * - * @return none - */ -void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) -{ - SSL_ASSERT(ssl); - SSL_ASSERT(verify_callback); -} - /* * SSL_get_verify_result - get the verifying result of the SSL certification * @@ -1812,3 +1798,37 @@ void SSL_set_verify_depth(SSL *ssl, int depth) ssl->param.depth = depth; } + +/* + * SSL_CTX_set_verify - set the SSL context verifying of the SSL context + * + * @param ctx - SSL context point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) +{ + SSL_ASSERT(ctx); + + ctx->verify_mode = mode; + ctx->default_verify_callback = verify_callback; +} + +/* + * SSL_set_verify - set the SSL verifying of the SSL context + * + * @param ctx - SSL point + * @param mode - verifying mode + * @param verify_callback - verifying callback function + * + * @return none + */ +void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) +{ + SSL_ASSERT(ctx); + + ssl->verify_mode = mode; + ssl->verify_callback = verify_callback; +} diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index 0674f40587..c6fb40e59c 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -26,7 +26,6 @@ IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, ssl_pm_set_fd, ssl_pm_get_fd, ssl_pm_set_bufflen, ssl_pm_get_verify_result, - ssl_pm_reload_crt, ssl_pm_get_state); /* diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index ab56fe789d..e13870344f 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -160,13 +160,7 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) ssl->cert->pkey = pkey; - ssl_ret = SSL_METHOD_CALL(reload_crt, ssl); - if (ssl_ret) - ret = 0; - else - ret = 1; - - return ret; + return 1; } /* diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 431f03caa9..6eb3c1d461 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -138,9 +138,6 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) */ int SSL_add_client_CA(SSL *ssl, X509 *x) { - int ret; - int ssl_ret; - SSL_ASSERT(ssl); SSL_ASSERT(x); @@ -151,13 +148,7 @@ int SSL_add_client_CA(SSL *ssl, X509 *x) ssl->client_CA = x; - ssl_ret = SSL_METHOD_CALL(reload_crt, ssl); - if (ssl_ret) - ret = 0; - else - ret = 1; - - return ret; + return 1; } /* diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 10b736aa9c..cd29882dfa 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -71,14 +71,10 @@ int ssl_pm_new(SSL *ssl) size_t pers_len = sizeof(pers); int endpoint; - int mode; int version; const SSL_METHOD *method = ssl->method; - struct x509_pm *x509_pm; - struct pkey_pm *pkey_pm; - ssl->session.peer = ssl_zalloc(sizeof(X509)); if (!ssl->session.peer) SSL_ERR(ret, failed1, "ssl_zalloc\n"); @@ -123,28 +119,9 @@ int ssl_pm_new(SSL *ssl) mbedtls_ssl_conf_dbg(&ssl_pm->conf, NULL, NULL); - x509_pm = (struct x509_pm *)ssl->client_CA->x509_pm; - if (x509_pm->load) { - mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &x509_pm->x509_crt, NULL); - - mode = MBEDTLS_SSL_VERIFY_REQUIRED; - } else { - mode = MBEDTLS_SSL_VERIFY_NONE; - } - mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); - - pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; - if (pkey_pm->load) { - x509_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; - - ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); - if (ret) - SSL_ERR(ret, failed4, "mbedtls_ssl_conf_own_cert:[%d]\n", ret); - } - ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); if (ret) - SSL_ERR(ret, failed5, "mbedtls_ssl_setup:[-0x%x]\n", -ret); + SSL_ERR(ret, failed4, "mbedtls_ssl_setup:[-0x%x]\n", -ret); mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); @@ -152,9 +129,8 @@ int ssl_pm_new(SSL *ssl) return 0; -failed5: - mbedtls_ssl_config_free(&ssl_pm->conf); failed4: + mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); failed3: mbedtls_entropy_free(&ssl_pm->entropy); @@ -177,11 +153,49 @@ void ssl_pm_free(SSL *ssl) ssl->ssl_pm = NULL; } +static int ssl_pm_reload_crt(SSL *ssl) +{ + int ret; + int mode; + struct ssl_pm *ssl_pm = ssl->ssl_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 x509_pm *crt_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; + + if (ssl->verify_mode == SSL_VERIFY_PEER) + mode = MBEDTLS_SSL_VERIFY_REQUIRED; + else if (ssl->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT) + mode = MBEDTLS_SSL_VERIFY_NONE; + else if (ssl->verify_mode == SSL_VERIFY_CLIENT_ONCE) + mode = MBEDTLS_SSL_VERIFY_UNSET; + else + mode = MBEDTLS_SSL_VERIFY_NONE; + + mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); + + if (ca_pm->load) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &ca_pm->x509_crt, NULL); + } + + if (pkey_pm->load) { + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &crt_pm->x509_crt, &pkey_pm->pkey); + if (ret) + return -1; + } + + return 0; +} + int ssl_pm_handshake(SSL *ssl) { int ret, mbed_ret; struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; + mbed_ret = ssl_pm_reload_crt(ssl); + if (mbed_ret) + return 0; + ssl_speed_up_enter(); while((mbed_ret = mbedtls_ssl_handshake(&ssl_pm->ssl)) != 0) { if (mbed_ret != MBEDTLS_ERR_SSL_WANT_READ && mbed_ret != MBEDTLS_ERR_SSL_WANT_WRITE) { @@ -475,33 +489,3 @@ long ssl_pm_get_verify_result(const SSL *ssl) return verify_result; } - -int ssl_pm_reload_crt(SSL *ssl) -{ - int ret; - int mode; - struct ssl_pm *ssl_pm = ssl->ssl_pm; - struct x509_pm *x509_pm; - struct pkey_pm *pkey_pm; - - x509_pm = (struct x509_pm *)ssl->client_CA->x509_pm; - if (x509_pm->load) { - mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &x509_pm->x509_crt, NULL); - - mode = MBEDTLS_SSL_VERIFY_REQUIRED; - } else { - mode = MBEDTLS_SSL_VERIFY_NONE; - } - mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); - - pkey_pm = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; - if (pkey_pm->load) { - x509_pm = (struct x509_pm *)ssl->cert->x509->x509_pm; - - ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &x509_pm->x509_crt, &pkey_pm->pkey); - if (ret) - return -1; - } - - return 0; -} From db9becfa744b651080c435eefe48adc0cf24cdba Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 13:38:11 +0800 Subject: [PATCH 21/95] components/openssl: free peer cert X509 object when SSL_free --- components/openssl/platform/ssl_pm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index cd29882dfa..b03aee3e37 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -149,6 +149,9 @@ void ssl_pm_free(SSL *ssl) mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ssl_free(&ssl_pm->ssl); + ssl_free(ssl->session.peer); + ssl->session.peer = NULL; + ssl_free(ssl_pm); ssl->ssl_pm = NULL; } From 59bb9a9a011050c2a9af55c6da2f37a22337b527 Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 14:50:27 +0800 Subject: [PATCH 22/95] components/openssl: [TW7411] supply doxygen type note --- .../openssl/include/internal/ssl_cert.h | 17 +- .../openssl/include/internal/ssl_code.h | 1 + .../openssl/include/internal/ssl_methods.h | 18 + .../openssl/include/internal/ssl_pkey.h | 25 + .../openssl/include/internal/ssl_x509.h | 25 +- components/openssl/include/openssl/ssl.h | 953 +++++++++--------- components/openssl/library/ssl_cert.c | 24 +- components/openssl/library/ssl_lib.c | 677 +++---------- components/openssl/library/ssl_methods.c | 16 +- components/openssl/library/ssl_pkey.c | 113 +-- components/openssl/library/ssl_x509.c | 136 +-- components/openssl/platform/ssl_pm.c | 9 + 12 files changed, 782 insertions(+), 1232 deletions(-) diff --git a/components/openssl/include/internal/ssl_cert.h b/components/openssl/include/internal/ssl_cert.h index 109012a194..b0bd09d480 100644 --- a/components/openssl/include/internal/ssl_cert.h +++ b/components/openssl/include/internal/ssl_cert.h @@ -17,7 +17,22 @@ #include "ssl_types.h" +/** + * @brief create a certification object include private key object + * + * @param none + * + * @return certification object point + */ CERT* ssl_cert_new(void); -void ssl_cert_free(CERT *c); + +/** + * @brief free a certification object + * + * @param cert - certification object point + * + * @return none + */ +void ssl_cert_free(CERT *cert); #endif diff --git a/components/openssl/include/internal/ssl_code.h b/components/openssl/include/internal/ssl_code.h index e76b35abe9..34107d432d 100644 --- a/components/openssl/include/internal/ssl_code.h +++ b/components/openssl/include/internal/ssl_code.h @@ -72,6 +72,7 @@ typedef enum { MSG_FLOW_FINISHED } MSG_FLOW_STATE; +/* SSL subsystem states */ typedef enum { TLS_ST_BEFORE, TLS_ST_OK, diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index 244eec38dd..68737b4381 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -15,6 +15,9 @@ #ifndef _SSL_METHODS_H_ #define _SSL_METHODS_H_ +/** + * TLS method function implement + */ #define IMPLEMENT_TLS_METHOD_FUNC(func_name, \ new, free, \ handshake, shutdown, clear, \ @@ -89,7 +92,22 @@ return &func_name##_data; \ } +/** + * @brief get X509 object method + * + * @param none + * + * @return X509 object method point + */ const X509_METHOD* X509_method(void); + +/** + * @brief get private key object method + * + * @param none + * + * @return private key object method point + */ const PKEY_METHOD* EVP_PKEY_method(void); #endif diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h index 34be294efe..d9a22ee02c 100644 --- a/components/openssl/include/internal/ssl_pkey.h +++ b/components/openssl/include/internal/ssl_pkey.h @@ -17,13 +17,38 @@ #include "ssl_types.h" +/** + * @brief create a private key object + * + * @param none + * + * @return private key object point + */ EVP_PKEY* EVP_PKEY_new(void); +/** + * @brief load a character key context into system context. If '*a' is pointed to the + * private key, then load key into it. Or create a new private key object + * + * @param type - private key type + * @param a - a point pointed to a private key point + * @param pp - a point pointed to the key context memory point + * @param length - key bytes + * + * @return private key object point + */ EVP_PKEY* d2i_PrivateKey(int type, EVP_PKEY **a, const unsigned char **pp, long length); +/** + * @brief free a private key object + * + * @param pkey - private key object point + * + * @return none + */ void EVP_PKEY_free(EVP_PKEY *x); #endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index ee3448544b..9359073b69 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -20,17 +20,34 @@ DEFINE_STACK_OF(X509_NAME) -/* - * sk_X509_NAME_new_null - create a X509 certification object +/** + * @brief create a X509 certification object * * @param none * - * @return X509 certification object point or NULL if failed + * @return X509 certification object point */ X509* X509_new(void); +/** + * @brief load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object + * + * @param cert - a point pointed to X509 certification + * @param buffer - a point pointed to the certification context memory point + * @param length - certification bytes + * + * @return X509 certification object point + */ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); -void X509_free(X509 *cert); +/** + * @brief free a X509 certification object + * + * @param x - X509 certification object point + * + * @return none + */ +void X509_free(X509 *x); #endif diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index 865405d868..3f92a68d70 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -22,17 +22,17 @@ { */ -/* - * SSL_CTX_new - create a SSL context +/** + * @brief create a SSL context * * @param method - the SSL context method point * - * @return the context point, if create failed return NULL + * @return the context point */ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); -/* - * SSL_CTX_free - free a SSL context +/** + * @brief free a SSL context * * @param method - the SSL context point * @@ -40,17 +40,17 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); */ void SSL_CTX_free(SSL_CTX *ctx); -/* - * SSL_new - create a SSL +/** + * @brief create a SSL * * @param ctx - the SSL context point * - * @return the SSL point or NULL if failed + * @return the SSL point */ SSL* SSL_new(SSL_CTX *ctx); -/* - * SSL_free - free the SSL +/** + * @brief free the SSL * * @param ssl - the SSL point * @@ -58,58 +58,58 @@ SSL* SSL_new(SSL_CTX *ctx); */ void SSL_free(SSL *ssl); -/* - * SSL_connect - connect to the remote SSL server +/** + * @brief connect to the remote SSL server * * @param ssl - the SSL point * - * @return - * 1 : OK - * -1 : failed + * @return result + * 1 : OK + * -1 : failed */ int SSL_connect(SSL *ssl); -/* - * SSL_accept - accept the remote connection +/** + * @brief accept the remote connection * * @param ssl - the SSL point * - * @return - * 1 : OK - * -1 : failed + * @return result + * 1 : OK + * -1 : failed */ int SSL_accept(SSL *ssl); -/* - * SSL_read - read data from to remote +/** + * @brief read data from to remote * * @param ssl - the SSL point which has been connected * @param buffer - the received data buffer point * @param len - the received data length * - * @return - * > 0 : OK, and return received data bytes - * = 0 : connection is closed - * < 0 : an error catch + * @return result + * > 0 : OK, and return received data bytes + * = 0 : connection is closed + * < 0 : an error catch */ int SSL_read(SSL *ssl, void *buffer, int len); -/* - * SSL_write - send the data to remote +/** + * @brief send the data to remote * * @param ssl - the SSL point which has been connected * @param buffer - the send data buffer point * @param len - the send data length * - * @return - * > 0 : OK, and return sent data bytes - * = 0 : connection is closed - * < 0 : an error catch + * @return result + * > 0 : OK, and return sent data bytes + * = 0 : connection is closed + * < 0 : an error catch */ int SSL_write(SSL *ssl, const void *buffer, int len); -/* - * SSL_get_verify_result - get the verifying result of the SSL certification +/** + * @brief get the verifying result of the SSL certification * * @param ssl - the SSL point * @@ -117,56 +117,56 @@ int SSL_write(SSL *ssl, const void *buffer, int len); */ long SSL_get_verify_result(const SSL *ssl); -/* - * SSL_shutdown - shutdown the connection +/** + * @brief shutdown the connection * * @param ssl - the SSL point * - * @return - * 1 : OK - * 0 : shutdown is not finished - * -1 : an error catch + * @return result + * 1 : OK + * 0 : shutdown is not finished + * -1 : an error catch */ int SSL_shutdown(SSL *ssl); -/* - * SSL_set_fd - bind the socket file description into the SSL +/** + * @brief bind the socket file description into the SSL * * @param ssl - the SSL point * @param fd - socket handle * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_set_fd(SSL *ssl, int fd); -/* - * SSL_CTX_use_PrivateKey - These functions load the private key into the SSL_CTX or SSL object +/** + * @brief These functions load the private key into the SSL_CTX or SSL object * * @param ctx - the SSL context point * @param pkey - private key object point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); -/* - * SSL_CTX_use_PrivateKey - These functions load the certification into the SSL_CTX or SSL object +/** + * @brief These functions load the certification into the SSL_CTX or SSL object * * @param ctx - the SSL context point * @param pkey - certification object point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); -/* - * SSLv23_client_method - create the target SSL context client method +/** + * @brief create the target SSL context client method * * @param none * @@ -174,8 +174,8 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); */ const SSL_METHOD* SSLv23_client_method(void); -/* - * TLSv1_client_method - create the target SSL context client method +/** + * @brief create the target SSL context client method * * @param none * @@ -183,8 +183,8 @@ const SSL_METHOD* SSLv23_client_method(void); */ const SSL_METHOD* TLSv1_client_method(void); -/* - * SSLv3_client_method - create the target SSL context client method +/** + * @brief create the target SSL context client method * * @param none * @@ -192,8 +192,8 @@ const SSL_METHOD* TLSv1_client_method(void); */ const SSL_METHOD* SSLv3_client_method(void); -/* - * TLSv1_1_client_method - create the target SSL context client method +/** + * @brief create the target SSL context client method * * @param none * @@ -201,8 +201,8 @@ const SSL_METHOD* SSLv3_client_method(void); */ const SSL_METHOD* TLSv1_1_client_method(void); -/* - * TLSv1_1_client_method - create the target SSL context client method +/** + * @brief create the target SSL context client method * * @param none * @@ -211,8 +211,8 @@ const SSL_METHOD* TLSv1_1_client_method(void); const SSL_METHOD* TLSv1_2_client_method(void); -/* - * SSLv23_server_method - create the target SSL context server method +/** + * @brief create the target SSL context server method * * @param none * @@ -220,8 +220,8 @@ const SSL_METHOD* TLSv1_2_client_method(void); */ const SSL_METHOD* SSLv23_server_method(void); -/* - * TLSv1_1_server_method - create the target SSL context server method +/** + * @brief create the target SSL context server method * * @param none * @@ -229,8 +229,8 @@ const SSL_METHOD* SSLv23_server_method(void); */ const SSL_METHOD* TLSv1_1_server_method(void); -/* - * TLSv1_1_server_method - create the target SSL context server method +/** + * @brief create the target SSL context server method * * @param none * @@ -238,8 +238,8 @@ const SSL_METHOD* TLSv1_1_server_method(void); */ const SSL_METHOD* TLSv1_2_server_method(void); -/* - * TLSv1_server_method - create the target SSL context server method +/** + * @brief create the target SSL context server method * * @param none * @@ -247,8 +247,8 @@ const SSL_METHOD* TLSv1_2_server_method(void); */ const SSL_METHOD* TLSv1_server_method(void); -/* - * SSLv3_server_method - create the target SSL context server method +/** + * @brief create the target SSL context server method * * @param none * @@ -256,8 +256,8 @@ const SSL_METHOD* TLSv1_server_method(void); */ const SSL_METHOD* SSLv3_server_method(void); -/* - * SSL_CTX_set_alpn_select_cb - set the SSL context ALPN select callback function +/** + * @brief set the SSL context ALPN select callback function * * @param ctx - SSL context point * @param cb - ALPN select callback function @@ -275,21 +275,21 @@ void SSL_CTX_set_alpn_select_cb(SSL_CTX *ctx, void *arg); -/* - * SSL_CTX_set_alpn_protos - set the SSL context ALPN select protocol +/** + * @brief set the SSL context ALPN select protocol * * @param ctx - SSL context point * @param protos - ALPN protocol name * @param protos_len - ALPN protocol name bytes * - * @return - * 0 : OK - * 1 : failed + * @return result + * 0 : OK + * 1 : failed */ int SSL_CTX_set_alpn_protos(SSL_CTX *ctx, const unsigned char *protos, unsigned int protos_len); -/* - * SSL_CTX_set_next_proto_select_cb - set the SSL context next ALPN select callback function +/** + * @brief set the SSL context next ALPN select callback function * * @param ctx - SSL context point * @param cb - ALPN select callback function @@ -306,8 +306,8 @@ void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, void *arg), void *arg); -/* - * SSL_get_error - get SSL error code +/** + * @brief get SSL error code * * @param ssl - SSL point * @param ret_code - SSL return code @@ -316,8 +316,8 @@ void SSL_CTX_set_next_proto_select_cb(SSL_CTX *ctx, */ int SSL_get_error(const SSL *ssl, int ret_code); -/* - * ERR_clear_error - clear the SSL error code +/** + * @brief clear the SSL error code * * @param none * @@ -325,8 +325,8 @@ int SSL_get_error(const SSL *ssl, int ret_code); */ void ERR_clear_error(void); -/* - * ERR_get_error - get the current SSL error code +/** + * @brief get the current SSL error code * * @param none * @@ -334,8 +334,8 @@ void ERR_clear_error(void); */ int ERR_get_error(void); -/* - * ERR_load_SSL_strings - register the SSL error strings +/** + * @brief register the SSL error strings * * @param none * @@ -343,8 +343,8 @@ int ERR_get_error(void); */ void ERR_load_SSL_strings(void); -/* - * SSL_library_init - initialize the SSL library +/** + * @brief initialize the SSL library * * @param none * @@ -352,9 +352,9 @@ void ERR_load_SSL_strings(void); */ void SSL_library_init(void); -/* - * ERR_error_string - generates a human-readable string representing the error code e - * and store it into the "ret" point memory +/** + * @brief generates a human-readable string representing the error code e + * and store it into the "ret" point memory * * @param e - error code * @param ret - memory point to store the string @@ -363,8 +363,8 @@ void SSL_library_init(void); */ char *ERR_error_string(unsigned long e, char *ret); -/* - * SSL_CTX_set_options - add the SSL context option +/** + * @brief add the SSL context option * * @param ctx - SSL context point * @param opt - new SSL context option @@ -373,15 +373,15 @@ char *ERR_error_string(unsigned long e, char *ret); */ unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt); -/* - * SSL_CTX_set_options - add the SSL context mode +/** + * @brief add the SSL context mode * * @param ctx - SSL context point * @param mod - new SSL context mod * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_mode(SSL_CTX *ctx, int mod); @@ -389,20 +389,20 @@ int SSL_CTX_set_mode(SSL_CTX *ctx, int mod); } */ -/* - * SSL_do_handshake - perform the SSL handshake +/** + * @brief perform the SSL handshake * * @param ssl - SSL point * - * @return - * 1 : OK - * 0 : failed - * -1 : a error catch + * @return result + * 1 : OK + * 0 : failed + * -1 : a error catch */ int SSL_do_handshake(SSL *ssl); -/* - * SSL_get_version - get the SSL current version +/** + * @brief get the SSL current version * * @param ssl - SSL point * @@ -410,20 +410,20 @@ int SSL_do_handshake(SSL *ssl); */ const char *SSL_get_version(const SSL *ssl); -/* - * SSL_CTX_set_ssl_version - set the SSL context version +/** + * @brief set the SSL context version * * @param ctx - SSL context point * @param meth - SSL method point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); -/* - * SSL_CTX_get_ssl_method - get the SSL context current method +/** + * @brief get the SSL context current method * * @param ctx - SSL context point * @@ -431,8 +431,8 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); */ const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); -/* - * SSL_CTX_get_ssl_method - get the SSL current method +/** + * @brief get the SSL current method * * @param ssl - SSL point * @@ -440,44 +440,44 @@ const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); */ const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); -/* - * SSL_set_ssl_method - set the SSL method +/** + * @brief set the SSL method * * @param ssl - SSL point * @param meth - SSL method point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); -/* - * SSL_add_client_CA - add CA client certification into the SSL +/** + * @brief add CA client certification into the SSL * * @param ssl - SSL point * @param x - CA certification point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_add_client_CA(SSL *ssl, X509 *x); -/* - * SSL_add_client_CA - add CA client certification into the SSL context +/** + * @brief add CA client certification into the SSL context * * @param ctx - SSL context point * @param x - CA certification point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); -/* - * SSL_set_client_CA_list - set the SSL CA certification list +/** + * @brief set the SSL CA certification list * * @param ssl - SSL point * @param name_list - CA certification list @@ -486,8 +486,8 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); */ void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list); -/* - * SSL_CTX_set_client_CA_list - set the SSL context CA certification list +/** + * @brief set the SSL context CA certification list * * @param ctx - SSL context point * @param name_list - CA certification list @@ -496,8 +496,8 @@ void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list); */ void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); -/* - * SSL_get_client_CA_list - get the SSL CA certification list +/** + * @briefget the SSL CA certification list * * @param ssl - SSL point * @@ -505,8 +505,8 @@ void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list); */ STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl); -/* - * SSL_CTX_get_client_CA_list - get the SSL context CA certification list +/** + * @brief get the SSL context CA certification list * * @param ctx - SSL context point * @@ -514,8 +514,8 @@ STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl); */ STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx); -/* - * SSL_get_certificate - get the SSL certification point +/** + * @brief get the SSL certification point * * @param ssl - SSL point * @@ -523,8 +523,8 @@ STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx); */ X509 *SSL_get_certificate(const SSL *ssl); -/* - * SSL_get_privatekey - get the SSL private key point +/** + * @brief get the SSL private key point * * @param ssl - SSL point * @@ -532,8 +532,8 @@ X509 *SSL_get_certificate(const SSL *ssl); */ EVP_PKEY *SSL_get_privatekey(const SSL *ssl); -/* - * SSL_set_info_callback - set the SSL information callback function +/** + * @brief set the SSL information callback function * * @param ssl - SSL point * @param cb - information callback function @@ -542,8 +542,8 @@ EVP_PKEY *SSL_get_privatekey(const SSL *ssl); */ void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)); -/* - * SSL_get_state - get the SSL state +/** + * @brief get the SSL state * * @param ssl - SSL point * @@ -551,8 +551,8 @@ void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int v */ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); -/* - * SSL_CTX_set_default_read_buffer_len - set the SSL context read buffer length +/** + * @brief set the SSL context read buffer length * * @param ctx - SSL context point * @param len - read buffer length @@ -561,8 +561,8 @@ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); */ void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); -/* - * SSL_set_default_read_buffer_len - set the SSL read buffer length +/** + * @brief set the SSL read buffer length * * @param ssl - SSL point * @param len - read buffer length @@ -571,8 +571,8 @@ void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); */ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); -/* - * SSL_set_security_level - set the SSL security level +/** + * @brief set the SSL security level * * @param ssl - SSL point * @param level - security level @@ -581,8 +581,8 @@ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); */ void SSL_set_security_level(SSL *ssl, int level); -/* - * SSL_get_security_level - get the SSL security level +/** + * @brief get the SSL security level * * @param ssl - SSL point * @@ -590,8 +590,8 @@ void SSL_set_security_level(SSL *ssl, int level); */ int SSL_get_security_level(const SSL *ssl); -/* - * SSL_CTX_get_verify_mode - get the SSL verifying mode of the SSL context +/** + * @brief get the SSL verifying mode of the SSL context * * @param ctx - SSL context point * @@ -599,8 +599,8 @@ int SSL_get_security_level(const SSL *ssl); */ int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); -/* - * SSL_CTX_get_verify_depth - get the SSL verifying depth of the SSL context +/** + * @brief get the SSL verifying depth of the SSL context * * @param ctx - SSL context point * @@ -608,8 +608,8 @@ int SSL_CTX_get_verify_mode(const SSL_CTX *ctx); */ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); -/* - * SSL_CTX_set_verify - set the SSL context verifying of the SSL context +/** + * @brief set the SSL context verifying of the SSL context * * @param ctx - SSL context point * @param mode - verifying mode @@ -619,8 +619,8 @@ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx); */ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); -/* - * SSL_set_verify - set the SSL verifying of the SSL context +/** + * @brief set the SSL verifying of the SSL context * * @param ctx - SSL point * @param mode - verifying mode @@ -630,18 +630,18 @@ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509 */ void SSL_set_verify(SSL *s, int mode, int (*verify_callback)(int, X509_STORE_CTX *)); -/* - * SSL_CTX_set_verify_depth - set the SSL verify depth of the SSL context +/** + * @brief set the SSL verify depth of the SSL context * * @param ctx - SSL context point * @param depth - verifying depth * - * @return one + * @return none */ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); -/* - * verify_callback - certification verifying callback function +/** + * @brief certification verifying callback function * * @param preverify_ok - verifying result * @param x509_ctx - X509 certification point @@ -650,8 +650,8 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth); */ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx); -/* - * SSL_CTX_set_timeout - set the session timeout time +/** + * @brief set the session timeout time * * @param ctx - SSL context point * @param t - new session timeout time @@ -660,8 +660,8 @@ int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx); */ long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); -/* - * SSL_CTX_get_timeout - get the session timeout time +/** + * @brief get the session timeout time * * @param ctx - SSL context point * @@ -669,32 +669,32 @@ long SSL_CTX_set_timeout(SSL_CTX *ctx, long t); */ long SSL_CTX_get_timeout(const SSL_CTX *ctx); -/* - * SSL_CTX_set_cipher_list - set the SSL context cipher through the list string +/** + * @brief set the SSL context cipher through the list string * * @param ctx - SSL context point * @param str - cipher controller list string * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_cipher_list(SSL_CTX *ctx, const char *str); -/* - * SSL_set_cipher_list - set the SSL cipher through the list string +/** + * @brief set the SSL cipher through the list string * * @param ssl - SSL point * @param str - cipher controller list string * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_set_cipher_list(SSL *ssl, const char *str); -/* - * SSL_get_cipher_list - get the SSL cipher list string +/** + * @brief get the SSL cipher list string * * @param ssl - SSL point * @@ -702,8 +702,8 @@ int SSL_set_cipher_list(SSL *ssl, const char *str); */ const char *SSL_get_cipher_list(const SSL *ssl, int n); -/* - * SSL_get_current_cipher - get the SSL cipher +/** + * @brief get the SSL cipher * * @param ssl - SSL point * @@ -711,8 +711,8 @@ const char *SSL_get_cipher_list(const SSL *ssl, int n); */ const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl); -/* - * SSL_get_cipher - get the SSL cipher string +/** + * @brief get the SSL cipher string * * @param ssl - SSL point * @@ -720,8 +720,8 @@ const SSL_CIPHER *SSL_get_current_cipher(const SSL *ssl); */ const char *SSL_get_cipher(const SSL *ssl); -/* - * SSL_CTX_get_cert_store - get the SSL context object X509 certification storage +/** + * @brief get the SSL context object X509 certification storage * * @param ctx - SSL context point * @@ -729,8 +729,8 @@ const char *SSL_get_cipher(const SSL *ssl); */ X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); -/* - * SSL_CTX_set_cert_store - set the SSL context object X509 certification store +/** + * @brief set the SSL context object X509 certification store * * @param ctx - SSL context point * @param store - X509 certification store @@ -739,8 +739,8 @@ X509_STORE *SSL_CTX_get_cert_store(const SSL_CTX *ctx); */ void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store); -/* - * SSL_want - get the SSL specifical statement +/** + * @brief get the SSL specifical statement * * @param ssl - SSL point * @@ -748,63 +748,63 @@ void SSL_CTX_set_cert_store(SSL_CTX *ctx, X509_STORE *store); */ int SSL_want(const SSL *ssl); -/* - * SSL_want_x509_lookup - check if the SSL is SSL_X509_LOOKUP state +/** + * @brief check if the SSL is SSL_X509_LOOKUP state * * @param ssl - SSL point * - * @return - * 1 : yes - * 0 : no + * @return result + * 1 : OK + * 0 : failed */ int SSL_want_x509_lookup(const SSL *ssl); -/* - * SSL_clear - reset the SSL +/** + * @brief reset the SSL * * @param ssl - SSL point * - * @return - * 1 : yes - * 0 : no + * @return result + * 1 : OK + * 0 : failed */ int SSL_clear(SSL *ssl); -/* - * SSL_get_fd - get the socket handle of the SSL +/** + * @brief get the socket handle of the SSL * * @param ssl - SSL point * - * @return - * >= 0 : yes, and return socket handle - * < 0 : a error catch + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch */ int SSL_get_fd(const SSL *ssl); -/* - * SSL_get_rfd - get the read only socket handle of the SSL +/** + * @brief get the read only socket handle of the SSL * * @param ssl - SSL point * - * @return - * >= 0 : yes, and return socket handle - * < 0 : a error catch + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch */ int SSL_get_rfd(const SSL *ssl); -/* - * SSL_get_wfd - get the write only socket handle of the SSL +/** + * @brief get the write only socket handle of the SSL * * @param ssl - SSL point * - * @return - * >= 0 : yes, and return socket handle - * < 0 : a error catch + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch */ int SSL_get_wfd(const SSL *ssl); -/* - * SSL_set_read_ahead - set the SSL if we can read as many as data +/** + * @brief set the SSL if we can read as many as data * * @param ssl - SSL point * @param yes - enable the function @@ -813,8 +813,8 @@ int SSL_get_wfd(const SSL *ssl); */ void SSL_set_read_ahead(SSL *s, int yes); -/* - * SSL_set_read_ahead - set the SSL context if we can read as many as data +/** + * @brief set the SSL context if we can read as many as data * * @param ctx - SSL context point * @param yes - enbale the function @@ -823,8 +823,8 @@ void SSL_set_read_ahead(SSL *s, int yes); */ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); -/* - * SSL_set_read_ahead - get the SSL ahead signal if we can read as many as data +/** + * @brief get the SSL ahead signal if we can read as many as data * * @param ssl - SSL point * @@ -832,8 +832,8 @@ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes); */ int SSL_get_read_ahead(const SSL *ssl); -/* - * SSL_set_read_ahead - get the SSL context ahead signal if we can read as many as data +/** + * @brief get the SSL context ahead signal if we can read as many as data * * @param ctx - SSL context point * @@ -841,8 +841,8 @@ int SSL_get_read_ahead(const SSL *ssl); */ long SSL_CTX_get_read_ahead(SSL_CTX *ctx); -/* - * SSL_has_pending - check if some data can be read +/** + * @brief check if some data can be read * * @param ssl - SSL point * @@ -852,160 +852,160 @@ long SSL_CTX_get_read_ahead(SSL_CTX *ctx); */ int SSL_has_pending(const SSL *ssl); -/* - * SSL_CTX_use_certificate - load the X509 certification into SSL context +/** + * @brief load the X509 certification into SSL context * * @param ctx - SSL context point * @param x - X509 certification point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x);//loads the certificate x into ctx -/* - * SSL_CTX_use_certificate_ASN1 - load the ASN1 certification into SSL context +/** + * @brief load the ASN1 certification into SSL context * * @param ctx - SSL context point * @param len - certification length * @param d - data point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); -/* - * SSL_CTX_use_certificate_file - load the certification file into SSL context +/** + * @brief load the certification file into SSL context * * @param ctx - SSL context point * @param file - certification file name * @param type - certification encoding type * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type); -/* - * SSL_CTX_use_certificate_chain_file - load the certification chain file into SSL context +/** + * @brief load the certification chain file into SSL context * * @param ctx - SSL context point * @param file - certification chain file name * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_certificate_chain_file(SSL_CTX *ctx, const char *file); -/* - * SSL_CTX_use_certificate_ASN1 - load the ASN1 private key into SSL context +/** + * @brief load the ASN1 private key into SSL context * * @param ctx - SSL context point * @param d - data point * @param len - private key length * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len);//adds the private key of type pk stored at memory location d (length len) to ctx -/* - * SSL_CTX_use_certificate_file - load the private key file into SSL context +/** + * @brief load the private key file into SSL context * * @param ctx - SSL context point * @param file - private key file name * @param type - private key encoding type * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type); -/* - * SSL_CTX_use_certificate - load the RSA private key into SSL context +/** + * @brief load the RSA private key into SSL context * * @param ctx - SSL context point * @param x - RSA private key point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_RSAPrivateKey(SSL_CTX *ctx, RSA *rsa); -/* - * SSL_CTX_use_certificate_ASN1 - load the RSA ASN1 private key into SSL context +/** + * @brief load the RSA ASN1 private key into SSL context * * @param ctx - SSL context point * @param d - data point * @param len - RSA private key length * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); -/* - * SSL_CTX_use_certificate_file - load the RSA private key file into SSL context +/** + * @brief load the RSA private key file into SSL context * * @param ctx - SSL context point * @param file - RSA private key file name * @param type - private key encoding type * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_RSAPrivateKey_file(SSL_CTX *ctx, const char *file, int type); -/* - * SSL_CTX_check_private_key - check if the private key and certification is matched +/** + * @brief check if the private key and certification is matched * * @param ctx - SSL context point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_check_private_key(const SSL_CTX *ctx); -/* - * SSL_CTX_use_serverinfo - set the SSL context server information +/** + * @brief set the SSL context server information * * @param ctx - SSL context point * @param serverinfo - server information string * @param serverinfo_length - server information length * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_serverinfo(SSL_CTX *ctx, const unsigned char *serverinfo, size_t serverinfo_length); -/* - * SSL_CTX_use_serverinfo - load the SSL context server infomation file into SSL context +/** + * @brief load the SSL context server infomation file into SSL context * * @param ctx - SSL context point * @param file - server information file * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file); -/* - * SSL_select_next_proto - SSL select next function +/** + * @brief SSL select next function * * @param out - point of output data point * @param outlen - output data length @@ -1014,7 +1014,7 @@ int SSL_CTX_use_serverinfo_file(SSL_CTX *ctx, const char *file); * @param client - client data point * @param client_len -client data length * - * @return + * @return NPN state * OPENSSL_NPN_UNSUPPORTED : not support * OPENSSL_NPN_NEGOTIATED : negotiated * OPENSSL_NPN_NO_OVERLAP : no overlap @@ -1023,34 +1023,34 @@ int SSL_select_next_proto(unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, const unsigned char *client, unsigned int client_len); -/* - * SSL_CTX_add_extra_chain_cert - load the extra certification chain into the SSL context +/** + * @brief load the extra certification chain into the SSL context * * @param ctx - SSL context point * @param x509 - X509 certification * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ long SSL_CTX_add_extra_chain_cert(SSL_CTX *ctx, X509 *); -/* - * SSL_CTX_ctrl - control the SSL context +/** + * @brief control the SSL context * * @param ctx - SSL context point * @param cmd - command * @param larg - parameter length * @param parg - parameter point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg); -/* - * SSL_CTX_get_ciphers - get the SSL context cipher +/** + * @brief get the SSL context cipher * * @param ctx - SSL context point * @@ -1058,19 +1058,19 @@ long SSL_CTX_ctrl(SSL_CTX *ctx, int cmd, long larg, char *parg); */ STACK *SSL_CTX_get_ciphers(const SSL_CTX *ctx); -/* - * SSL_CTX_get_ciphers - check if the SSL context can read as many as data +/** + * @brief check if the SSL context can read as many as data * * @param ctx - SSL context point * - * @return - * 1 : Yes - * 0 : No + * @return result + * 1 : OK + * 0 : failed */ long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx); -/* - * SSL_CTX_get_ex_data - get the SSL context extra data +/** + * @brief get the SSL context extra data * * @param ctx - SSL context point * @param idx - index @@ -1079,8 +1079,8 @@ long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx); */ char *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx); -/* - * SSL_CTX_get_quiet_shutdown - get the SSL context quiet shutdown option +/** + * @brief get the SSL context quiet shutdown option * * @param ctx - SSL context point * @@ -1088,44 +1088,44 @@ char *SSL_CTX_get_ex_data(const SSL_CTX *ctx, int idx); */ int SSL_CTX_get_quiet_shutdown(const SSL_CTX *ctx); -/* - * SSL_CTX_get_quiet_shutdown - load the SSL context CA file +/** + * @brief load the SSL context CA file * * @param ctx - SSL context point * @param CAfile - CA certification file * @param CApath - CA certification file path * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_load_verify_locations(SSL_CTX *ctx, const char *CAfile, const char *CApath); -/* - * SSL_CTX_up_ref - add SSL context reference count by '1' +/** + * @brief add SSL context reference count by '1' * * @param ctx - SSL context point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_up_ref(SSL_CTX *ctx); -/* - * SSL_CTX_set_app_data - set SSL context application private data +/** + * @brief set SSL context application private data * * @param ctx - SSL context point * @param arg - private data * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_app_data(SSL_CTX *ctx, void *arg); -/* - * SSL_CTX_set_client_cert_cb - set SSL context client certification callback function +/** + * @brief set SSL context client certification callback function * * @param ctx - SSL context point * @param cb - callback function @@ -1134,8 +1134,8 @@ int SSL_CTX_set_app_data(SSL_CTX *ctx, void *arg); */ void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, X509 **x509, EVP_PKEY **pkey)); -/* - * SSL_CTX_set_default_read_ahead - set the SSL context if we can read as many as data +/** + * @brief set the SSL context if we can read as many as data * * @param ctx - SSL context point * @param m - enable the fuction @@ -1144,54 +1144,54 @@ void SSL_CTX_set_client_cert_cb(SSL_CTX *ctx, int (*cb)(SSL *ssl, X509 **x509, E */ void SSL_CTX_set_default_read_ahead(SSL_CTX *ctx, int m); -/* - * SSL_CTX_set_default_verify_paths - set SSL context default verifying path +/** + * @brief set SSL context default verifying path * * @param ctx - SSL context point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx); -/* - * SSL_CTX_set_default_verify_paths - set SSL context default verifying directory +/** + * @brief set SSL context default verifying directory * * @param ctx - SSL context point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_default_verify_dir(SSL_CTX *ctx); -/* - * SSL_CTX_set_default_verify_paths - set SSL context default verifying file +/** + * @brief set SSL context default verifying file * * @param ctx - SSL context point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_default_verify_file(SSL_CTX *ctx); -/* - * SSL_CTX_set_ex_data - set SSL context extra data +/** + * @brief set SSL context extra data * * @param ctx - SSL context point * @param idx - data index * @param arg - data point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, char *arg); -/* - * SSL_CTX_clear_options - clear the SSL context option bit of "op" +/** + * @brief clear the SSL context option bit of "op" * * @param ctx - SSL context point * @param op - option @@ -1200,8 +1200,8 @@ int SSL_CTX_set_ex_data(SSL_CTX *s, int idx, char *arg); */ unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op); -/* - * SSL_CTX_clear_options - get the SSL context option +/** + * @brief get the SSL context option * * @param ctx - SSL context point * @param op - option @@ -1210,8 +1210,8 @@ unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op); */ unsigned long SSL_CTX_get_options(SSL_CTX *ctx); -/* - * SSL_CTX_set_quiet_shutdown - set the SSL context quiet shutdown mode +/** + * @brief set the SSL context quiet shutdown mode * * @param ctx - SSL context point * @param mode - mode @@ -1220,8 +1220,8 @@ unsigned long SSL_CTX_get_options(SSL_CTX *ctx); */ void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); -/* - * SSL_CTX_get0_certificate - get the SSL context X509 certification +/** + * @brief get the SSL context X509 certification * * @param ctx - SSL context point * @@ -1229,8 +1229,8 @@ void SSL_CTX_set_quiet_shutdown(SSL_CTX *ctx, int mode); */ X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); -/* - * SSL_CTX_get0_certificate - get the SSL context private key +/** + * @brief get the SSL context private key * * @param ctx - SSL context point * @@ -1238,32 +1238,33 @@ X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx); */ EVP_PKEY *SSL_CTX_get0_privatekey(const SSL_CTX *ctx); -/* - * SSL_CTX_use_psk_identity_hint - set SSL context PSK identity hint +/** + * @brief set SSL context PSK identity hint * * @param ctx - SSL context point * @param hint - PSK identity hint * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_CTX_use_psk_identity_hint(SSL_CTX *ctx, const char *hint); -/* - * SSL_CTX_set_psk_server_callback - set SSL context PSK server callback function +/** + * @brief set SSL context PSK server callback function * * @param ctx - SSL context point * @param callback - callback function * + * @return none */ void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, unsigned int (*callback)(SSL *ssl, const char *identity, unsigned char *psk, int max_psk_len)); -/* - * SSL_alert_desc_string - get alert description string +/** + * @brief get alert description string * * @param value - alert value * @@ -1271,8 +1272,8 @@ void SSL_CTX_set_psk_server_callback(SSL_CTX *ctx, */ const char *SSL_alert_desc_string(int value); -/* - * SSL_alert_desc_string - get alert description long string +/** + * @brief get alert description long string * * @param value - alert value * @@ -1280,8 +1281,8 @@ const char *SSL_alert_desc_string(int value); */ const char *SSL_alert_desc_string_long(int value); -/* - * SSL_alert_type_string - get alert type string +/** + * @brief get alert type string * * @param value - alert value * @@ -1289,8 +1290,8 @@ const char *SSL_alert_desc_string_long(int value); */ const char *SSL_alert_type_string(int value); -/* - * SSL_alert_type_string_long - get alert type long string +/** + * @brief get alert type long string * * @param value - alert value * @@ -1298,8 +1299,8 @@ const char *SSL_alert_type_string(int value); */ const char *SSL_alert_type_string_long(int value); -/* - * SSL_get_SSL_CTX - get SSL context of the SSL +/** + * @brief get SSL context of the SSL * * @param ssl - SSL point * @@ -1307,8 +1308,8 @@ const char *SSL_alert_type_string_long(int value); */ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); -/* - * SSL_get_app_data - get SSL application data +/** + * @brief get SSL application data * * @param ssl - SSL point * @@ -1316,8 +1317,8 @@ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); */ char *SSL_get_app_data(SSL *ssl); -/* - * SSL_get_cipher_bits - get SSL cipher bits +/** + * @brief get SSL cipher bits * * @param ssl - SSL point * @param alg_bits - algorithm bits @@ -1326,8 +1327,8 @@ char *SSL_get_app_data(SSL *ssl); */ int SSL_get_cipher_bits(const SSL *ssl, int *alg_bits); -/* - * SSL_get_cipher_name - get SSL cipher name +/** + * @brief get SSL cipher name * * @param ssl - SSL point * @@ -1335,8 +1336,8 @@ int SSL_get_cipher_bits(const SSL *ssl, int *alg_bits); */ char *SSL_get_cipher_name(const SSL *ssl); -/* - * SSL_get_cipher_version - get SSL cipher version +/** + * @brief get SSL cipher version * * @param ssl - SSL point * @@ -1344,8 +1345,8 @@ char *SSL_get_cipher_name(const SSL *ssl); */ char *SSL_get_cipher_version(const SSL *ssl); -/* - * SSL_get_ex_data - get SSL extra data +/** + * @brief get SSL extra data * * @param ssl - SSL point * @param idx - data index @@ -1354,8 +1355,8 @@ char *SSL_get_cipher_version(const SSL *ssl); */ char *SSL_get_ex_data(const SSL *ssl, int idx); -/* - * SSL_get_ex_data_X509_STORE_CTX_idx - get index of the SSL extra data X509 storage context +/** + * @brief get index of the SSL extra data X509 storage context * * @param none * @@ -1363,8 +1364,8 @@ char *SSL_get_ex_data(const SSL *ssl, int idx); */ int SSL_get_ex_data_X509_STORE_CTX_idx(void); -/* - * SSL_get_peer_cert_chain - get peer certification chain +/** + * @brief get peer certification chain * * @param ssl - SSL point * @@ -1372,8 +1373,8 @@ int SSL_get_ex_data_X509_STORE_CTX_idx(void); */ STACK *SSL_get_peer_cert_chain(const SSL *ssl); -/* - * SSL_get_peer_certificate - get peer certification +/** + * @brief get peer certification * * @param ssl - SSL point * @@ -1381,8 +1382,8 @@ STACK *SSL_get_peer_cert_chain(const SSL *ssl); */ X509 *SSL_get_peer_certificate(const SSL *ssl); -/* - * SSL_get_quiet_shutdown - get SSL quiet shutdown mode +/** + * @brief get SSL quiet shutdown mode * * @param ssl - SSL point * @@ -1390,8 +1391,8 @@ X509 *SSL_get_peer_certificate(const SSL *ssl); */ int SSL_get_quiet_shutdown(const SSL *ssl); -/* - * SSL_get_rbio - get SSL read only IO handle +/** + * @brief get SSL read only IO handle * * @param ssl - SSL point * @@ -1399,19 +1400,19 @@ int SSL_get_quiet_shutdown(const SSL *ssl); */ BIO *SSL_get_rbio(const SSL *ssl); -/* - * SSL_get_shared_ciphers - get SSL shared ciphers +/** + * @brief get SSL shared ciphers * * @param ssl - SSL point * @param buf - buffer to store the ciphers * @param len - buffer len * - * @return shared ciphers or NULL if failed + * @return shared ciphers */ char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len); -/* - * SSL_get_shutdown - get SSL shutdown mode +/** + * @brief get SSL shutdown mode * * @param ssl - SSL point * @@ -1419,8 +1420,8 @@ char *SSL_get_shared_ciphers(const SSL *ssl, char *buf, int len); */ int SSL_get_shutdown(const SSL *ssl); -/* - * SSL_get_time - get SSL session time +/** + * @brief get SSL session time * * @param ssl - SSL point * @@ -1428,8 +1429,8 @@ int SSL_get_shutdown(const SSL *ssl); */ long SSL_get_time(const SSL *ssl); -/* - * SSL_get_timeout - get SSL session timeout time +/** + * @brief get SSL session timeout time * * @param ssl - SSL point * @@ -1437,8 +1438,8 @@ long SSL_get_time(const SSL *ssl); */ long SSL_get_timeout(const SSL *ssl); -/* - * SSL_get_verify_mode - get SSL verifying mode +/** + * @brief get SSL verifying mode * * @param ssl - SSL point * @@ -1446,8 +1447,8 @@ long SSL_get_timeout(const SSL *ssl); */ int SSL_get_verify_mode(const SSL *ssl); -/* - * SSL_get_wbio - get SSL write only IO handle +/** + * @brief get SSL write only IO handle * * @param ssl - SSL point * @@ -1455,8 +1456,8 @@ int SSL_get_verify_mode(const SSL *ssl); */ BIO *SSL_get_wbio(const SSL *ssl); -/* - * SSL_load_client_CA_file - load SSL client CA certification file +/** + * @brief load SSL client CA certification file * * @param file - file name * @@ -1464,44 +1465,44 @@ BIO *SSL_get_wbio(const SSL *ssl); */ STACK *SSL_load_client_CA_file(const char *file); -/* - * SSL_up_ref - add SSL reference by '1' +/** + * @brief add SSL reference by '1' * * @param ssl - SSL point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_up_ref(SSL *ssl); -/* - * SSL_peek - read and put data into buf, but not clear the SSL low-level storage +/** + * @brief read and put data into buf, but not clear the SSL low-level storage * * @param ssl - SSL point * @param buf - storage buffer point * @param num - data bytes * - * @return - * > 0 : OK, and return read bytes - * = 0 : connect is closed - * < 0 : a error catch + * @return result + * > 0 : OK, and return read bytes + * = 0 : connect is closed + * < 0 : a error catch */ int SSL_peek(SSL *ssl, void *buf, int num); -/* - * SSL_renegotiate - make SSL renegotiate +/** + * @brief make SSL renegotiate * * @param ssl - SSL point * - * @return - * 1 : OK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_renegotiate(SSL *ssl); -/* - * SSL_rstate_string - get the state string where SSL is reading +/** + * @brief get the state string where SSL is reading * * @param ssl - SSL point * @@ -1509,8 +1510,8 @@ int SSL_renegotiate(SSL *ssl); */ const char *SSL_rstate_string(SSL *ssl); -/* - * SSL_rstate_string_long - get the statement long string where SSL is reading +/** + * @brief get the statement long string where SSL is reading * * @param ssl - SSL point * @@ -1518,8 +1519,8 @@ const char *SSL_rstate_string(SSL *ssl); */ const char *SSL_rstate_string_long(SSL *ssl); -/* - * SSL_set_accept_state - set SSL accept statement +/** + * @brief set SSL accept statement * * @param ssl - SSL point * @@ -1527,8 +1528,8 @@ const char *SSL_rstate_string_long(SSL *ssl); */ void SSL_set_accept_state(SSL *ssl); -/* - * SSL_set_app_data - set SSL application data +/** + * @brief set SSL application data * * @param ssl - SSL point * @param arg - SSL application data point @@ -1537,8 +1538,8 @@ void SSL_set_accept_state(SSL *ssl); */ void SSL_set_app_data(SSL *ssl, char *arg); -/* - * SSL_set_bio - set SSL BIO +/** + * @brief set SSL BIO * * @param ssl - SSL point * @param rbio - read only IO @@ -1548,8 +1549,8 @@ void SSL_set_app_data(SSL *ssl, char *arg); */ void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); -/* - * SSL_clear_options - clear SSL option +/** + * @brief clear SSL option * * @param ssl - SSL point * @param op - clear option @@ -1558,8 +1559,8 @@ void SSL_set_bio(SSL *ssl, BIO *rbio, BIO *wbio); */ unsigned long SSL_clear_options(SSL *ssl, unsigned long op); -/* - * SSL_clear_options - get SSL option +/** + * @brief get SSL option * * @param ssl - SSL point * @@ -1567,8 +1568,8 @@ unsigned long SSL_clear_options(SSL *ssl, unsigned long op); */ unsigned long SSL_get_options(SSL *ssl); -/* - * SSL_clear_options - clear SSL option +/** + * @brief clear SSL option * * @param ssl - SSL point * @param op - setting option @@ -1577,8 +1578,8 @@ unsigned long SSL_get_options(SSL *ssl); */ unsigned long SSL_set_options(SSL *ssl, unsigned long op); -/* - * SSL_set_quiet_shutdown - set SSL quiet shutdown mode +/** + * @brief set SSL quiet shutdown mode * * @param ssl - SSL point * @param mode - quiet shutdown mode @@ -1587,8 +1588,8 @@ unsigned long SSL_set_options(SSL *ssl, unsigned long op); */ void SSL_set_quiet_shutdown(SSL *ssl, int mode); -/* - * SSL_set_quiet_shutdown - set SSL shutdown mode +/** + * @brief set SSL shutdown mode * * @param ssl - SSL point * @param mode - shutdown mode @@ -1597,8 +1598,8 @@ void SSL_set_quiet_shutdown(SSL *ssl, int mode); */ void SSL_set_shutdown(SSL *ssl, int mode); -/* - * SSL_set_time - set SSL session time +/** + * @brief set SSL session time * * @param ssl - SSL point * @param t - session time @@ -1607,8 +1608,8 @@ void SSL_set_shutdown(SSL *ssl, int mode); */ void SSL_set_time(SSL *ssl, long t); -/* - * SSL_set_time - set SSL session timeout time +/** + * @brief set SSL session timeout time * * @param ssl - SSL point * @param t - session timeout time @@ -1617,8 +1618,8 @@ void SSL_set_time(SSL *ssl, long t); */ void SSL_set_timeout(SSL *ssl, long t); -/* - * SSL_state_string - get SSL statement string +/** + * @brief get SSL statement string * * @param ssl - SSL point * @@ -1626,8 +1627,8 @@ void SSL_set_timeout(SSL *ssl, long t); */ char *SSL_state_string(const SSL *ssl); -/* - * SSL_state_string_long - get SSL statement long string +/** + * @brief get SSL statement long string * * @param ssl - SSL point * @@ -1635,8 +1636,8 @@ char *SSL_state_string(const SSL *ssl); */ char *SSL_state_string_long(const SSL *ssl); -/* - * SSL_total_renegotiations - get SSL renegotiation count +/** + * @brief get SSL renegotiation count * * @param ssl - SSL point * @@ -1644,8 +1645,8 @@ char *SSL_state_string_long(const SSL *ssl); */ long SSL_total_renegotiations(SSL *ssl); -/* - * SSL_version - get SSL version +/** + * @brief get SSL version * * @param ssl - SSL point * @@ -1653,20 +1654,20 @@ long SSL_total_renegotiations(SSL *ssl); */ int SSL_version(const SSL *ssl); -/* - * SSL_use_psk_identity_hint - set SSL PSK identity hint +/** + * @brief set SSL PSK identity hint * * @param ssl - SSL point * @param hint - identity hint * - * @return - * 1 : oK - * 0 : failed + * @return result + * 1 : OK + * 0 : failed */ int SSL_use_psk_identity_hint(SSL *ssl, const char *hint); -/* - * SSL_get_psk_identity_hint - get SSL PSK identity hint +/** + * @brief get SSL PSK identity hint * * @param ssl - SSL point * @@ -1674,8 +1675,8 @@ int SSL_use_psk_identity_hint(SSL *ssl, const char *hint); */ const char *SSL_get_psk_identity_hint(SSL *ssl); -/* - * SSL_get_psk_identity - get SSL PSK identity +/** + * @brief get SSL PSK identity * * @param ssl - SSL point * diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index 2d82e62aaa..fd05bc8315 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -18,12 +18,8 @@ #include "ssl_dbg.h" #include "ssl_port.h" -/* - * ssl_cert_new - create a certification object include private key object - * - * @param none - * - * @return certification object point or NULL if failed +/** + * @brief create a certification object include private key object */ CERT *ssl_cert_new(void) { @@ -51,18 +47,14 @@ failed1: return NULL; } -/* - * ssl_cert_free - free a certification object - * - * @param c - certification object point - * - * @return none +/** + * @brief free a certification object */ -void ssl_cert_free(CERT *c) +void ssl_cert_free(CERT *cert) { - X509_free(c->x509); + X509_free(cert->x509); - EVP_PKEY_free(c->pkey); + EVP_PKEY_free(cert->pkey); - ssl_free(c); + ssl_free(cert); } diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index ae517b0a40..a84b89e06c 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -21,14 +21,8 @@ #define SSL_SEND_DATA_MAX_LENGTH 1460 -/* - * ossl_statem_in_error - Discover whether the current connection is in the error state - * - * @param ssl - SSL point - * - * @return - * 1 : Yes - * 0 : no +/** + * @brief Discover whether the current connection is in the error state */ int ossl_statem_in_error(const SSL *ssl) { @@ -38,81 +32,48 @@ int ossl_statem_in_error(const SSL *ssl) return 0; } -/* - * SSL_want - get the SSL specifical statement - * - * @param ssl - SSL point - * - * @return specifical statement +/** + * @brief get the SSL specifical statement */ int SSL_want(const SSL *ssl) { return ssl->rwstate; } -/* - * SSL_want_nothing - check if SSL want nothing - * - * @param ssl - SSL point - * - * @return - * 1 : yes - * 0 : no +/** + * @brief check if SSL want nothing */ int SSL_want_nothing(const SSL *ssl) { return (SSL_want(ssl) == SSL_NOTHING); } -/* - * SSL_want_read - check if SSL want to read - * - * @param ssl - SSL point - * - * @return - * 1 : yes - * 0 : no +/** + * @brief check if SSL want to read */ int SSL_want_read(const SSL *ssl) { return (SSL_want(ssl) == SSL_READING); } -/* - * SSL_want_read - check if SSL want to write - * - * @param ssl - SSL point - * - * @return - * 1 : yes - * 0 : no +/** + * @brief check if SSL want to write */ int SSL_want_write(const SSL *ssl) { return (SSL_want(ssl) == SSL_WRITING); } -/* - * SSL_want_read - check if SSL want to lookup X509 certification - * - * @param ssl - SSL point - * - * @return - * 1 : yes - * 0 : no +/** + * @brief check if SSL want to lookup X509 certification */ int SSL_want_x509_lookup(const SSL *ssl) { return (SSL_want(ssl) == SSL_WRITING); } -/* - * SSL_get_error - get SSL error code - * - * @param ssl - SSL point - * @param ret_code - SSL return code - * - * @return SSL error number +/** + * @brief get SSL error code */ int SSL_get_error(const SSL *ssl, int ret_code) { @@ -142,12 +103,8 @@ int SSL_get_error(const SSL *ssl, int ret_code) return ret; } -/* - * SSL_get_state - get the SSL state - * - * @param ssl - SSL point - * - * @return SSL state +/** + * @brief get the SSL state */ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) { @@ -160,12 +117,8 @@ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) return state; } -/* - * SSL_CTX_new - create a SSL context - * - * @param method - the SSL context configuration file - * - * @return the context point, if create failed return NULL +/** + * @brief create a SSL context */ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) { @@ -203,12 +156,8 @@ go_failed1: return NULL; } -/* - * SSL_CTX_free - free a SSL context - * - * @param method - the SSL context point - * - * @return none +/** + * @brief free a SSL context */ void SSL_CTX_free(SSL_CTX* ctx) { @@ -221,15 +170,8 @@ void SSL_CTX_free(SSL_CTX* ctx) ssl_free(ctx); } -/* - * SSL_CTX_set_ssl_version - set the SSL context version - * - * @param ctx - SSL context point - * @param meth - SSL method point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief set the SSL context version */ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) { @@ -243,12 +185,8 @@ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth) return 1; } -/* - * SSL_CTX_get_ssl_method - get the SSL context current method - * - * @param ctx - SSL context point - * - * @return the SSL context current method +/** + * @brief get the SSL context current method */ const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) { @@ -257,12 +195,8 @@ const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx) return ctx->method; } -/* - * SSL_new - create a SSL - * - * @param ctx - the SSL context point - * - * @return the SSL point or NULL if failed +/** + * @brief create a SSL */ SSL *SSL_new(SSL_CTX *ctx) { @@ -300,12 +234,8 @@ failed1: return NULL; } -/* - * SSL_free - free the SSL - * - * @param ssl - the SSL point - * - * @return none +/** + * @brief free the SSL */ void SSL_free(SSL *ssl) { @@ -322,15 +252,8 @@ void SSL_free(SSL *ssl) ssl_free(ssl); } -/* - * SSL_do_handshake - perform the SSL handshake - * - * @param ssl - SSL point - * - * @return - * 1 : OK - * 0 : failed - * -1 : a error catch +/** + * @brief perform the SSL handshake */ int SSL_do_handshake(SSL *ssl) { @@ -343,14 +266,8 @@ int SSL_do_handshake(SSL *ssl) return ret; } -/* - * SSL_connect - connect to the remote SSL server - * - * @param ssl - the SSL point - * - * @return - * 1 : OK - * -1 : failed +/** + * @brief connect to the remote SSL server */ int SSL_connect(SSL *ssl) { @@ -359,14 +276,8 @@ int SSL_connect(SSL *ssl) return SSL_do_handshake(ssl); } -/* - * SSL_accept - accept the remote connection - * - * @param ssl - the SSL point - * - * @return - * 1 : OK - * -1 : failed +/** + * @brief accept the remote connection */ int SSL_accept(SSL *ssl) { @@ -375,15 +286,8 @@ int SSL_accept(SSL *ssl) return SSL_do_handshake(ssl); } -/* - * SSL_shutdown - shutdown the connection - * - * @param ssl - the SSL point - * - * @return - * 1 : OK - * 0 : shutdown is not finished - * -1 : an error catch +/** + * @brief shutdown the connection */ int SSL_shutdown(SSL *ssl) { @@ -398,14 +302,8 @@ int SSL_shutdown(SSL *ssl) return ret; } -/* - * SSL_clear - reset the SSL - * - * @param ssl - SSL point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief reset the SSL */ int SSL_clear(SSL *ssl) { @@ -429,17 +327,8 @@ go_failed1: return ret; } -/* - * SSL_read - read data from to remote - * - * @param ssl - the SSL point which has been connected - * @param buffer - the received data buffer point - * @param len - the received data length - * - * @return - * > 0 : OK, and return received data bytes - * = 0 : connection is closed - * < 0 : an error catch +/** + * @brief read data from to remote */ int SSL_read(SSL *ssl, void *buffer, int len) { @@ -458,17 +347,8 @@ int SSL_read(SSL *ssl, void *buffer, int len) return ret; } -/* - * SSL_write - send the data to remote - * - * @param ssl - the SSL point which has been connected - * @param buffer - the send data buffer point - * @param len - the send data length - * - * @return - * > 0 : OK, and return sent data bytes - * = 0 : connection is closed - * < 0 : an error catch +/** + * @brief send the data to remote */ int SSL_write(SSL *ssl, const void *buffer, int len) { @@ -511,12 +391,8 @@ int SSL_write(SSL *ssl, const void *buffer, int len) return ret; } -/* - * SSL_get_SSL_CTX - get SSL context of the SSL - * - * @param ssl - SSL point - * - * @return SSL context +/** + * @brief get SSL context of the SSL */ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) { @@ -525,12 +401,8 @@ SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl) return ssl->ctx; } -/* - * SSL_CTX_get_ssl_method - get the SSL current method - * - * @param ssl - SSL point - * - * @return the SSL current method +/** + * @brief get the SSL current method */ const SSL_METHOD *SSL_get_ssl_method(SSL *ssl) { @@ -539,15 +411,8 @@ const SSL_METHOD *SSL_get_ssl_method(SSL *ssl) return ssl->method; } -/* - * SSL_set_ssl_method - set the SSL method - * - * @param ssl - SSL point - * @param meth - SSL method point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief set the SSL method */ int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method) { @@ -580,12 +445,8 @@ go_failed1: return ret; } -/* - * SSL_get_shutdown - get SSL shutdown mode - * - * @param ssl - SSL point - * - * @return shutdown mode +/** + * @brief get SSL shutdown mode */ int SSL_get_shutdown(const SSL *ssl) { @@ -594,13 +455,8 @@ int SSL_get_shutdown(const SSL *ssl) return ssl->shutdown; } -/* - * SSL_set_quiet_shutdown - set SSL shutdown mode - * - * @param ssl - SSL point - * @param mode - shutdown mode - * - * @return none +/** + * @brief set SSL shutdown mode */ void SSL_set_shutdown(SSL *ssl, int mode) { @@ -610,12 +466,8 @@ void SSL_set_shutdown(SSL *ssl, int mode) } -/* - * SSL_pending - get the number of the bytes to be read - * - * @param ssl - SSL point - * - * @return number of the bytes +/** + * @brief get the number of the bytes to be read */ int SSL_pending(const SSL *ssl) { @@ -628,14 +480,8 @@ int SSL_pending(const SSL *ssl) return ret; } -/* - * SSL_has_pending - check if some data can be read - * - * @param ssl - SSL point - * - * @return - * 1 : there are bytes to be read - * 0 : no data +/** + * @brief check if some data can be read */ int SSL_has_pending(const SSL *ssl) { @@ -651,52 +497,32 @@ int SSL_has_pending(const SSL *ssl) return ret; } -/* - * SSL_CTX_clear_options - clear the SSL context option bit of "op" - * - * @param ctx - SSL context point - * @param op - option - * - * @return SSL context option +/** + * @brief clear the SSL context option bit of "op" */ unsigned long SSL_CTX_clear_options(SSL_CTX *ctx, unsigned long op) { return ctx->options &= ~op; } -/* - * SSL_CTX_clear_options - get the SSL context option - * - * @param ctx - SSL context point - * @param op - option - * - * @return SSL context option +/** + * @brief get the SSL context option */ unsigned long SSL_CTX_get_options(SSL_CTX *ctx) { return ctx->options; } -/* - * SSL_CTX_set_option - set the option of the SSL context - * - * @param ctx - the SSL context - * - * @return the SSL context option - * +/** + * @brief set the option of the SSL context */ unsigned long SSL_CTX_set_options(SSL_CTX *ctx, unsigned long opt) { return ctx->options |= opt; } -/* - * SSL_clear_options - clear SSL option - * - * @param ssl - SSL point - * @param op - clear option - * - * @return SSL option +/** + * @brief clear SSL option */ unsigned long SSL_clear_options(SSL *ssl, unsigned long op) { @@ -705,12 +531,8 @@ unsigned long SSL_clear_options(SSL *ssl, unsigned long op) return ssl->options & ~op; } -/* - * SSL_clear_options - get SSL option - * - * @param ssl - SSL point - * - * @return SSL option +/** + * @brief get SSL option */ unsigned long SSL_get_options(SSL *ssl) { @@ -719,13 +541,8 @@ unsigned long SSL_get_options(SSL *ssl) return ssl->options; } -/* - * SSL_clear_options - clear SSL option - * - * @param ssl - SSL point - * @param op - setting option - * - * @return SSL option +/** + * @brief clear SSL option */ unsigned long SSL_set_options(SSL *ssl, unsigned long op) { @@ -734,14 +551,8 @@ unsigned long SSL_set_options(SSL *ssl, unsigned long op) return ssl->options |= op; } -/* - * SSL_get_fd - get the socket handle of the SSL - * - * @param ssl - SSL point - * - * @return - * >= 0 : yes, and return socket handle - * < 0 : a error catch +/** + * @brief get the socket handle of the SSL */ int SSL_get_fd(const SSL *ssl) { @@ -754,14 +565,8 @@ int SSL_get_fd(const SSL *ssl) return ret; } -/* - * SSL_get_rfd - get the read only socket handle of the SSL - * - * @param ssl - SSL point - * - * @return - * >= 0 : yes, and return socket handle - * < 0 : a error catch +/** + * @brief get the read only socket handle of the SSL */ int SSL_get_rfd(const SSL *ssl) { @@ -774,14 +579,8 @@ int SSL_get_rfd(const SSL *ssl) return ret; } -/* - * SSL_get_wfd - get the write only socket handle of the SSL - * - * @param ssl - SSL point - * - * @return - * >= 0 : yes, and return socket handle - * < 0 : a error catch +/** + * @brief get the write only socket handle of the SSL */ int SSL_get_wfd(const SSL *ssl) { @@ -794,15 +593,8 @@ int SSL_get_wfd(const SSL *ssl) return ret; } -/* - * SSL_set_fd - bind the socket file description into the SSL - * - * @param ssl - the SSL point - * @param fd - socket handle - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief bind the socket file description into the SSL */ int SSL_set_fd(SSL *ssl, int fd) { @@ -814,15 +606,8 @@ int SSL_set_fd(SSL *ssl, int fd) return 1; } -/* - * SSL_set_fd - bind the read only socket file description into the SSL - * - * @param ssl - the SSL point - * @param fd - socket handle - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief bind the read only socket file description into the SSL */ int SSL_set_rfd(SSL *ssl, int fd) { @@ -834,15 +619,8 @@ int SSL_set_rfd(SSL *ssl, int fd) return 1; } -/* - * SSL_set_fd - bind the write only socket file description into the SSL - * - * @param ssl - the SSL point - * @param fd - socket handle - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief bind the write only socket file description into the SSL */ int SSL_set_wfd(SSL *ssl, int fd) { @@ -854,12 +632,8 @@ int SSL_set_wfd(SSL *ssl, int fd) return 1; } -/* - * SSL_version - get SSL version - * - * @param ssl - SSL point - * - * @return SSL version +/** + * @brief get SSL version */ int SSL_version(const SSL *ssl) { @@ -868,12 +642,8 @@ int SSL_version(const SSL *ssl) return ssl->version; } -/* - * ssl_protocol_to_string - get the SSL version string - * - * @param version - the SSL version - * - * @return the SSL version string +/** + * @brief get the SSL version string */ static const char* ssl_protocol_to_string(int version) { @@ -893,12 +663,8 @@ static const char* ssl_protocol_to_string(int version) return str; } -/* - * SSL_get_version - get the SSL current version - * - * @param ssl - SSL point - * - * @return the version string +/** + * @brief get the SSL current version */ const char *SSL_get_version(const SSL *ssl) { @@ -907,12 +673,8 @@ const char *SSL_get_version(const SSL *ssl) return ssl_protocol_to_string(SSL_version(ssl)); } -/* - * SSL_alert_desc_string - get alert description string - * - * @param value - alert value - * - * @return alert description string +/** + * @brief get alert description string */ const char* SSL_alert_desc_string(int value) { @@ -1018,12 +780,8 @@ const char* SSL_alert_desc_string(int value) return str; } -/* - * SSL_alert_desc_string - get alert description long string - * - * @param value - alert value - * - * @return alert description long string +/** + * @brief get alert description long string */ const char* SSL_alert_desc_string_long(int value) { @@ -1129,12 +887,8 @@ const char* SSL_alert_desc_string_long(int value) return str; } -/* - * SSL_alert_type_string - get alert type string - * - * @param value - alert value - * - * @return alert type string +/** + * @brief get alert type string */ const char *SSL_alert_type_string(int value) { @@ -1156,12 +910,8 @@ const char *SSL_alert_type_string(int value) return str; } -/* - * SSL_alert_type_string_long - get alert type long string - * - * @param value - alert value - * - * @return alert type long string +/** + * @brief get alert type long string */ const char *SSL_alert_type_string_long(int value) { @@ -1183,12 +933,8 @@ const char *SSL_alert_type_string_long(int value) return str; } -/* - * SSL_rstate_string - get the state string where SSL is reading - * - * @param ssl - SSL point - * - * @return state string +/** + * @brief get the state string where SSL is reading */ const char *SSL_rstate_string(SSL *ssl) { @@ -1215,12 +961,8 @@ const char *SSL_rstate_string(SSL *ssl) return str; } -/* - * SSL_rstate_string_long - get the statement long string where SSL is reading - * - * @param ssl - SSL point - * - * @return statement long string +/** + * @brief get the statement long string where SSL is reading */ const char *SSL_rstate_string_long(SSL *ssl) { @@ -1246,12 +988,8 @@ const char *SSL_rstate_string_long(SSL *ssl) return str; } -/* - * SSL_state_string - get SSL statement string - * - * @param ssl - SSL point - * - * @return SSL statement string +/** + * @brief get SSL statement string */ char *SSL_state_string(const SSL *ssl) { @@ -1358,12 +1096,8 @@ char *SSL_state_string(const SSL *ssl) return str; } -/* - * SSL_state_string_long - get SSL statement long string - * - * @param ssl - SSL point - * - * @return SSL statement long string +/** + * @brief get SSL statement long string */ char *SSL_state_string_long(const SSL *ssl) { @@ -1476,13 +1210,8 @@ char *SSL_state_string_long(const SSL *ssl) return str; } -/* - * SSL_CTX_set_default_read_buffer_len - set the SSL context read buffer length - * - * @param ctx - SSL context point - * @param len - read buffer length - * - * @return none +/** + * @brief set the SSL context read buffer length */ void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) { @@ -1492,13 +1221,8 @@ void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len) ctx->read_buffer_len = len; } -/* - * SSL_set_default_read_buffer_len - set the SSL read buffer length - * - * @param ssl - SSL point - * @param len - read buffer length - * - * @return none +/** + * @brief set the SSL read buffer length */ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) { @@ -1508,13 +1232,8 @@ void SSL_set_default_read_buffer_len(SSL *ssl, size_t len) SSL_METHOD_CALL(set_bufflen, ssl, len); } -/* - * SSL_set_info_callback - set the SSL information callback function - * - * @param ssl - SSL point - * @param cb - information callback function - * - * @return none +/** + * @brief set the SSL information callback function */ void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int val)) { @@ -1523,32 +1242,23 @@ void SSL_set_info_callback(SSL *ssl, void (*cb) (const SSL *ssl, int type, int v ssl->info_callback = cb; } -/* - * SSL_CTX_up_ref - add SSL context reference count by '1' - * - * @param ctx - SSL context point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief add SSL context reference count by '1' */ int SSL_CTX_up_ref(SSL_CTX *ctx) { SSL_ASSERT(ctx); - /* no support multi-thread SSL here */ + /** + * no support multi-thread SSL here + */ ctx->references++; return 1; } -/* - * SSL_set_security_level - set the SSL security level - * - * @param ssl - SSL point - * @param level - security level - * - * @return none +/** + * @brief set the SSL security level */ void SSL_set_security_level(SSL *ssl, int level) { @@ -1557,12 +1267,8 @@ void SSL_set_security_level(SSL *ssl, int level) ssl->cert->sec_level = level; } -/* - * SSL_get_security_level - get the SSL security level - * - * @param ssl - SSL point - * - * @return security level +/** + * @brief get the SSL security level */ int SSL_get_security_level(const SSL *ssl) { @@ -1571,12 +1277,8 @@ int SSL_get_security_level(const SSL *ssl) return ssl->cert->sec_level; } -/* - * SSL_CTX_get_verify_mode - get the SSL verifying mode of the SSL context - * - * @param ctx - SSL context point - * - * @return verifying mode +/** + * @brief get the SSL verifying mode of the SSL context */ int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) { @@ -1585,13 +1287,8 @@ int SSL_CTX_get_verify_mode(const SSL_CTX *ctx) return ctx->verify_mode; } -/* - * SSL_CTX_set_timeout - set the session timeout time - * - * @param ctx - SSL context point - * @param t - new session timeout time - * - * @return old session timeout time +/** + * @brief set the session timeout time */ long SSL_CTX_set_timeout(SSL_CTX *ctx, long t) { @@ -1605,12 +1302,8 @@ long SSL_CTX_set_timeout(SSL_CTX *ctx, long t) return l; } -/* - * SSL_CTX_get_timeout - get the session timeout time - * - * @param ctx - SSL context point - * - * @return current session timeout time +/** + * @brief get the session timeout time */ long SSL_CTX_get_timeout(const SSL_CTX *ctx) { @@ -1619,13 +1312,8 @@ long SSL_CTX_get_timeout(const SSL_CTX *ctx) return ctx->session_timeout; } -/* - * SSL_set_read_ahead - set the SSL if we can read as many as data - * - * @param ssl - SSL point - * @param yes - enable the function - * - * @return none +/** + * @brief set the SSL if we can read as many as data */ void SSL_set_read_ahead(SSL *ssl, int yes) { @@ -1634,13 +1322,8 @@ void SSL_set_read_ahead(SSL *ssl, int yes) ssl->rlayer.read_ahead = yes; } -/* - * SSL_set_read_ahead - set the SSL context if we can read as many as data - * - * @param ctx - SSL context point - * @param yes - enable the function - * - * @return none +/** + * @brief set the SSL context if we can read as many as data */ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) { @@ -1649,12 +1332,8 @@ void SSL_CTX_set_read_ahead(SSL_CTX *ctx, int yes) ctx->read_ahead = yes; } -/* - * SSL_set_read_ahead - get the SSL ahead signal if we can read as many as data - * - * @param ssl - SSL point - * - * @return SSL context ahead signal +/** + * @brief get the SSL ahead signal if we can read as many as data */ int SSL_get_read_ahead(const SSL *ssl) { @@ -1663,12 +1342,8 @@ int SSL_get_read_ahead(const SSL *ssl) return ssl->rlayer.read_ahead; } -/* - * SSL_set_read_ahead - get the SSL context ahead signal if we can read as many as data - * - * @param ctx - SSL context point - * - * @return SSL context ahead signal +/** + * @brief get the SSL context ahead signal if we can read as many as data */ long SSL_CTX_get_read_ahead(SSL_CTX *ctx) { @@ -1677,14 +1352,8 @@ long SSL_CTX_get_read_ahead(SSL_CTX *ctx) return ctx->read_ahead; } -/* - * SSL_CTX_get_ciphers - check if the SSL context can read as many as data - * - * @param ctx - SSL context point - * - * @return - * 1 : Yes - * 0 : No +/** + * @brief check if the SSL context can read as many as data */ long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx) { @@ -1693,13 +1362,8 @@ long SSL_CTX_get_default_read_ahead(SSL_CTX *ctx) return ctx->read_ahead; } -/* - * SSL_set_time - set SSL session time - * - * @param ssl - SSL point - * @param t - session time - * - * @return session time +/** + * @brief set SSL session time */ long SSL_set_time(SSL *ssl, long t) { @@ -1710,13 +1374,8 @@ long SSL_set_time(SSL *ssl, long t) return t; } -/* - * SSL_set_time - set SSL session timeout time - * - * @param ssl - SSL point - * @param t - session timeout time - * - * @return session timeout time +/** + * @brief set SSL session timeout time */ long SSL_set_timeout(SSL *ssl, long t) { @@ -1727,12 +1386,8 @@ long SSL_set_timeout(SSL *ssl, long t) return t; } -/* - * SSL_get_verify_result - get the verifying result of the SSL certification - * - * @param ssl - the SSL point - * - * @return the result of verifying +/** + * @brief get the verifying result of the SSL certification */ long SSL_get_verify_result(const SSL *ssl) { @@ -1741,12 +1396,8 @@ long SSL_get_verify_result(const SSL *ssl) return SSL_METHOD_CALL(get_verify_result, ssl); } -/* - * SSL_CTX_get_verify_depth - get the SSL verifying depth of the SSL context - * - * @param ctx - SSL context point - * - * @return verifying depth +/** + * @brief get the SSL verifying depth of the SSL context */ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) { @@ -1755,13 +1406,8 @@ int SSL_CTX_get_verify_depth(const SSL_CTX *ctx) return ctx->param.depth; } -/* - * SSL_CTX_set_verify_depth - set the SSL verify depth of the SSL context - * - * @param ctx - SSL context point - * @param depth - verifying depth - * - * @return one +/** + * @brief set the SSL verify depth of the SSL context */ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { @@ -1770,12 +1416,8 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) ctx->param.depth = depth; } -/* - * SSL_get_verify_depth - get the SSL verifying depth of the SSL - * - * @param ctx - SSL point - * - * @return verifying depth +/** + * @brief get the SSL verifying depth of the SSL */ int SSL_get_verify_depth(const SSL *ssl) { @@ -1784,13 +1426,8 @@ int SSL_get_verify_depth(const SSL *ssl) return ssl->param.depth; } -/* - * SSL_set_verify_depth - set the SSL verify depth of the SSL - * - * @param ctx - SSL point - * @param depth - verifying depth - * - * @return one +/** + * @brief set the SSL verify depth of the SSL */ void SSL_set_verify_depth(SSL *ssl, int depth) { @@ -1799,14 +1436,8 @@ void SSL_set_verify_depth(SSL *ssl, int depth) ssl->param.depth = depth; } -/* - * SSL_CTX_set_verify - set the SSL context verifying of the SSL context - * - * @param ctx - SSL context point - * @param mode - verifying mode - * @param verify_callback - verifying callback function - * - * @return none +/** + * @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 *)) { @@ -1816,14 +1447,8 @@ void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509 ctx->default_verify_callback = verify_callback; } -/* - * SSL_set_verify - set the SSL verifying of the SSL context - * - * @param ctx - SSL point - * @param mode - verifying mode - * @param verify_callback - verifying callback function - * - * @return none +/** + * @brief set the SSL verifying of the SSL context */ void SSL_set_verify(SSL *ssl, int mode, int (*verify_callback)(int, X509_STORE_CTX *)) { diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index c6fb40e59c..042d670ab9 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -16,7 +16,7 @@ #include "ssl_methods.h" #include "ssl_pm.h" -/* +/** * TLS method function collection */ IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, @@ -28,7 +28,7 @@ IMPLEMENT_TLS_METHOD_FUNC(TLS_method_func, ssl_pm_get_verify_result, ssl_pm_get_state); -/* +/** * TLS or SSL client method collection */ IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 0, TLS_method_func, TLS_client_method); @@ -41,7 +41,7 @@ IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_client_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, 0, TLS_method_func, SSLv3_client_method); -/* +/** * TLS or SSL server method collection */ IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, 1, TLS_method_func, TLS_server_method); @@ -54,7 +54,7 @@ IMPLEMENT_TLS_METHOD(TLS1_VERSION, 0, TLS_method_func, TLSv1_server_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, 1, TLS_method_func, SSLv3_server_method); -/* +/** * TLS or SSL method collection */ IMPLEMENT_TLS_METHOD(TLS_ANY_VERSION, -1, TLS_method_func, TLS_method); @@ -67,15 +67,15 @@ IMPLEMENT_SSL_METHOD(TLS1_VERSION, -1, TLS_method_func, TLSv1_method); IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); -/* - * X509 certification method collection +/** + * @brief get X509 object method */ IMPLEMENT_X509_METHOD(X509_method, x509_pm_new, x509_pm_free, x509_pm_load, x509_pm_unload); -/* - * private key method collection +/** + * @brief get private key object method */ IMPLEMENT_PKEY_METHOD(EVP_PKEY_method, pkey_pm_new, pkey_pm_free, diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index e13870344f..6f51963eb0 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -19,12 +19,8 @@ #include "ssl_dbg.h" #include "ssl_port.h" -/* - * EVP_PKEY_new - create a private key object - * - * @param none - * - * @return private key object point or NULL if failed +/** + * @brief create a private key object */ EVP_PKEY* EVP_PKEY_new(void) { @@ -49,12 +45,8 @@ failed1: return NULL; } -/* - * EVP_PKEY_free - free a private key object - * - * @param pkey - private key object point - * - * @return none +/** + * @brief free a private key object */ void EVP_PKEY_free(EVP_PKEY *pkey) { @@ -63,16 +55,9 @@ void EVP_PKEY_free(EVP_PKEY *pkey) ssl_free(pkey); } -/* - * d2i_PrivateKey - load a character key context into system context. If '*a' is pointed to the - * private key, then load key into it. Or create a new private key object - * - * @param type - private key type - * @param a - a point pointed to a private key point - * @param pp - a point pointed to the key context memory point - * @param length - key bytes - * - * @return private key object point or NULL if failed +/** + * @brief load a character key context into system context. If '*a' is pointed to the + * private key, then load key into it. Or create a new private key object */ EVP_PKEY *d2i_PrivateKey(int type, EVP_PKEY **a, @@ -112,15 +97,8 @@ failed1: return NULL; } -/* - * SSL_CTX_use_certificate - set the SSL context private key - * - * @param ctx - SSL context point - * @param x - private key point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief set the SSL context private key */ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) { @@ -135,15 +113,8 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) return 1; } -/* - * SSL_CTX_use_certificate - set the SSL private key - * - * @param ctx - SSL point - * @param x - private key point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief set the SSL private key */ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { @@ -163,17 +134,8 @@ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) return 1; } -/* - * SSL_CTX_use_PrivateKey_ASN1 - load private key into the SSL context - * - * @param type - private key type - * @param ctx - SSL context point - * @param d - private key context point - * @param len - private key context bytes - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load private key into the SSL context */ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const unsigned char *d, long len) @@ -197,17 +159,8 @@ failed1: return 0; } -/* - * SSL_use_PrivateKey_ASN1 - load private key into the SSL - * - * @param type - private key type - * @param ctx - SSL context point - * @param d - private key context point - * @param len - private key context bytes - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load private key into the SSL */ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len) @@ -255,48 +208,24 @@ failed1: return 0; } -/* - * SSL_CTX_use_certificate_file - load the private key file into SSL context - * - * @param ctx - SSL context point - * @param file - private key file name - * @param type - private key encoding type - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load the private key file into SSL context */ int SSL_CTX_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { return 0; } -/* - * SSL_use_PrivateKey_file - load the private key file into SSL - * - * @param ctx - SSL point - * @param file - private key file name - * @param type - private key encoding type - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load the private key file into SSL */ int SSL_use_PrivateKey_file(SSL_CTX *ctx, const char *file, int type) { return 0; } -/* - * SSL_CTX_use_certificate_ASN1 - load the RSA ASN1 private key into SSL context - * - * @param ctx - SSL context point - * @param d - data point - * @param len - RSA private key length - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load the RSA ASN1 private key into SSL context */ int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len) { diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 6eb3c1d461..e96511dc4a 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -18,12 +18,8 @@ #include "ssl_dbg.h" #include "ssl_port.h" -/* - * sk_X509_NAME_new_null - create a X509 certification object - * - * @param none - * - * @return X509 certification object point or NULL if failed +/** + * @brief create a X509 certification object */ X509* X509_new(void) { @@ -48,12 +44,8 @@ failed1: return NULL; } -/* - * X509_free - free a X509 certification object - * - * @param x - X509 certification object point - * - * @return none +/** + * @brief free a X509 certification object */ void X509_free(X509 *x) { @@ -62,15 +54,9 @@ void X509_free(X509 *x) ssl_free(x); }; -/* - * d2i_X509 - load a character certification context into system context. If '*cert' is pointed to the - * certification, then load certification into it. Or create a new X509 certification object - * - * @param cert - a point pointed to X509 certification - * @param buffer - a point pointed to the certification context memory point - * @param length - certification bytes - * - * @return X509 certification object point or NULL if failed +/** + * @brief load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object */ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) { @@ -103,15 +89,8 @@ failed1: return NULL; } -/* - * SSL_CTX_add_client_CA - set SSL context client CA certification - * - * @param ctx - SSL context point - * @param x - client CA certification point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief set SSL context client CA certification */ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) { @@ -126,15 +105,8 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) return 1; } -/* - * SSL_add_client_CA - add CA client certification into the SSL - * - * @param ssl - SSL point - * @param x - CA certification point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief add CA client certification into the SSL */ int SSL_add_client_CA(SSL *ssl, X509 *x) { @@ -151,15 +123,8 @@ int SSL_add_client_CA(SSL *ssl, X509 *x) return 1; } -/* - * SSL_CTX_use_certificate - set the SSL context certification - * - * @param ctx - SSL context point - * @param x - X509 certification point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief set the SSL context certification */ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) { @@ -171,15 +136,8 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) return 1; } -/* - * SSL_CTX_use_certificate - set the SSL certification - * - * @param ctx - SSL point - * @param x - X509 certification point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief set the SSL certification */ int SSL_use_certificate(SSL *ssl, X509 *x) { @@ -191,12 +149,8 @@ int SSL_use_certificate(SSL *ssl, X509 *x) return 1; } -/* - * SSL_get_certificate - get the SSL certification point - * - * @param ssl - SSL point - * - * @return SSL certification point +/** + * @brief get the SSL certification point */ X509 *SSL_get_certificate(const SSL *ssl) { @@ -205,16 +159,8 @@ X509 *SSL_get_certificate(const SSL *ssl) return ssl->cert->x509; } -/* - * SSL_CTX_use_certificate_ASN1 - load certification into the SSL context - * - * @param ctx - SSL context point - * @param len - certification context bytes - * @param d - certification context point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load certification into the SSL context */ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d) @@ -238,16 +184,8 @@ failed1: return 0; } -/* - * SSL_use_certificate_ASN1 - load certification into the SSL - * - * @param ctx - SSL point - * @param len - certification context bytes - * @param d - certification context point - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load certification into the SSL */ int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d) @@ -295,44 +233,24 @@ failed1: return 0; } -/* - * SSL_CTX_use_certificate_file - load the certification file into SSL context - * - * @param ctx - SSL context point - * @param file - certification file name - * @param type - certification encoding type - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load the certification file into SSL context */ int SSL_CTX_use_certificate_file(SSL_CTX *ctx, const char *file, int type) { return 0; } -/* - * SSL_use_certificate_file - load the certification file into SSL - * - * @param ctx - SSL point - * @param file - certification file name - * @param type - certification encoding type - * - * @return - * 1 : OK - * 0 : failed +/** + * @brief load the certification file into SSL */ int SSL_use_certificate_file(SSL *ssl, const char *file, int type) { return 0; } -/* - * SSL_get_peer_certificate - get peer certification - * - * @param ssl - SSL point - * - * @return certification +/** + * @brief get peer certification */ X509 *SSL_get_peer_certificate(const SSL *ssl) { diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index b03aee3e37..9abfc212ec 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -62,6 +62,9 @@ unsigned int max_content_len; /*********************************************************************************************/ /************************************ SSL arch interface *************************************/ +/** + * @brief create SSL low-level object + */ int ssl_pm_new(SSL *ssl) { struct ssl_pm *ssl_pm; @@ -140,6 +143,9 @@ failed1: return -1; } +/** + * @brief free SSL low-level object + */ void ssl_pm_free(SSL *ssl) { struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; @@ -156,6 +162,9 @@ void ssl_pm_free(SSL *ssl) ssl->ssl_pm = NULL; } +/** + * @brief reload SSL low-level certification object + */ static int ssl_pm_reload_crt(SSL *ssl) { int ret; From f9fd5b6c72b6a08579f17317ab997306393516b1 Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 14:52:33 +0800 Subject: [PATCH 23/95] components/openssl: add X509 verify result errno --- .../openssl/include/internal/x509_vfy.h | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) create mode 100644 components/openssl/include/internal/x509_vfy.h diff --git a/components/openssl/include/internal/x509_vfy.h b/components/openssl/include/internal/x509_vfy.h new file mode 100644 index 0000000000..cab110e421 --- /dev/null +++ b/components/openssl/include/internal/x509_vfy.h @@ -0,0 +1,103 @@ +// Copyright 2015-2016 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 _X509_VFY_H_ +#define _X509_VFY_H_ + +#define X509_V_OK 0 +#define X509_V_ERR_UNSPECIFIED 1 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 +#define X509_V_ERR_UNABLE_TO_GET_CRL 3 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE 4 +#define X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE 5 +#define X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY 6 +#define X509_V_ERR_CERT_SIGNATURE_FAILURE 7 +#define X509_V_ERR_CRL_SIGNATURE_FAILURE 8 +#define X509_V_ERR_CERT_NOT_YET_VALID 9 +#define X509_V_ERR_CERT_HAS_EXPIRED 10 +#define X509_V_ERR_CRL_NOT_YET_VALID 11 +#define X509_V_ERR_CRL_HAS_EXPIRED 12 +#define X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD 13 +#define X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD 14 +#define X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD 15 +#define X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD 16 +#define X509_V_ERR_OUT_OF_MEM 17 +#define X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT 18 +#define X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN 19 +#define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY 20 +#define X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE 21 +#define X509_V_ERR_CERT_CHAIN_TOO_LONG 22 +#define X509_V_ERR_CERT_REVOKED 23 +#define X509_V_ERR_INVALID_CA 24 +#define X509_V_ERR_PATH_LENGTH_EXCEEDED 25 +#define X509_V_ERR_INVALID_PURPOSE 26 +#define X509_V_ERR_CERT_UNTRUSTED 27 +#define X509_V_ERR_CERT_REJECTED 28 +/* These are 'informational' when looking for issuer cert */ +#define X509_V_ERR_SUBJECT_ISSUER_MISMATCH 29 +#define X509_V_ERR_AKID_SKID_MISMATCH 30 +#define X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH 31 +#define X509_V_ERR_KEYUSAGE_NO_CERTSIGN 32 +#define X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER 33 +#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 +#define X509_V_ERR_KEYUSAGE_NO_CRL_SIGN 35 +#define X509_V_ERR_UNHANDLED_CRITICAL_CRL_EXTENSION 36 +#define X509_V_ERR_INVALID_NON_CA 37 +#define X509_V_ERR_PROXY_PATH_LENGTH_EXCEEDED 38 +#define X509_V_ERR_KEYUSAGE_NO_DIGITAL_SIGNATURE 39 +#define X509_V_ERR_PROXY_CERTIFICATES_NOT_ALLOWED 40 +#define X509_V_ERR_INVALID_EXTENSION 41 +#define X509_V_ERR_INVALID_POLICY_EXTENSION 42 +#define X509_V_ERR_NO_EXPLICIT_POLICY 43 +#define X509_V_ERR_DIFFERENT_CRL_SCOPE 44 +#define X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE 45 +#define X509_V_ERR_UNNESTED_RESOURCE 46 +#define X509_V_ERR_PERMITTED_VIOLATION 47 +#define X509_V_ERR_EXCLUDED_VIOLATION 48 +#define X509_V_ERR_SUBTREE_MINMAX 49 +/* The application is not happy */ +#define X509_V_ERR_APPLICATION_VERIFICATION 50 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE 51 +#define X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX 52 +#define X509_V_ERR_UNSUPPORTED_NAME_SYNTAX 53 +#define X509_V_ERR_CRL_PATH_VALIDATION_ERROR 54 +/* Another issuer check debug option */ +#define X509_V_ERR_PATH_LOOP 55 +/* Suite B mode algorithm violation */ +#define X509_V_ERR_SUITE_B_INVALID_VERSION 56 +#define X509_V_ERR_SUITE_B_INVALID_ALGORITHM 57 +#define X509_V_ERR_SUITE_B_INVALID_CURVE 58 +#define X509_V_ERR_SUITE_B_INVALID_SIGNATURE_ALGORITHM 59 +#define X509_V_ERR_SUITE_B_LOS_NOT_ALLOWED 60 +#define X509_V_ERR_SUITE_B_CANNOT_SIGN_P_384_WITH_P_256 61 +/* Host, email and IP check errors */ +#define X509_V_ERR_HOSTNAME_MISMATCH 62 +#define X509_V_ERR_EMAIL_MISMATCH 63 +#define X509_V_ERR_IP_ADDRESS_MISMATCH 64 +/* DANE TLSA errors */ +#define X509_V_ERR_DANE_NO_MATCH 65 +/* security level errors */ +#define X509_V_ERR_EE_KEY_TOO_SMALL 66 +#define X509_V_ERR_CA_KEY_TOO_SMALL 67 +#define X509_V_ERR_CA_MD_TOO_WEAK 68 +/* Caller error */ +#define X509_V_ERR_INVALID_CALL 69 +/* Issuer lookup error */ +#define X509_V_ERR_STORE_LOOKUP 70 +/* Certificate transparency */ +#define X509_V_ERR_NO_VALID_SCTS 71 + +#define X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION 72 + +#endif From 5c5f7eb7feb16ba2632ad4701d7ef283a3371fec Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 14:53:19 +0800 Subject: [PATCH 24/95] components/openssl: add openssl stack object function --- .../openssl/include/internal/ssl_stack.h | 33 +++++++++ components/openssl/library/ssl_stack.c | 70 +++++++++++++++++++ 2 files changed, 103 insertions(+) create mode 100644 components/openssl/include/internal/ssl_stack.h create mode 100644 components/openssl/library/ssl_stack.c diff --git a/components/openssl/include/internal/ssl_stack.h b/components/openssl/include/internal/ssl_stack.h new file mode 100644 index 0000000000..b97015bd95 --- /dev/null +++ b/components/openssl/include/internal/ssl_stack.h @@ -0,0 +1,33 @@ +#ifndef _SSL_STACK_H_ +#define _SSL_STACK_H_ + +#include "ssl_types.h" + +/** + * @brief create a openssl stack object + * + * @param c - stack function + * + * @return openssl stack object point + */ +OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c); + +/** + * @brief create a NULL function openssl stack object + * + * @param none + * + * @return openssl stack object point + */ +OPENSSL_STACK *OPENSSL_sk_new_null(void); + +/** + * @brief free openssl stack object + * + * @param openssl stack object point + * + * @return none + */ +void OPENSSL_sk_free(OPENSSL_STACK *stack); + +#endif diff --git a/components/openssl/library/ssl_stack.c b/components/openssl/library/ssl_stack.c new file mode 100644 index 0000000000..46e6f7efd8 --- /dev/null +++ b/components/openssl/library/ssl_stack.c @@ -0,0 +1,70 @@ +// Copyright 2015-2016 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_stack.h" +#include "ssl_dbg.h" +#include "ssl_port.h" + +#ifndef CONFIG_MIN_NODES + #define MIN_NODES 4 +#else + #define MIN_NODES CONFIG_MIN_NODES +#endif + +/** + * @brief create a openssl stack object + */ +OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) +{ + OPENSSL_STACK *stack; + char **data; + + stack = ssl_malloc(sizeof(OPENSSL_STACK)); + if (!stack) + SSL_RET(failed1); + + data = ssl_malloc(sizeof(*data) * MIN_NODES); + if (!data) + SSL_RET(failed2); + + stack->data = data; + stack->num_alloc = MIN_NODES; + stack->c = c; + + return stack; + +failed2: + ssl_free(stack); +failed1: + return NULL; +} + +/** + * @brief create a NULL function openssl stack object + */ +OPENSSL_STACK *OPENSSL_sk_new_null(void) +{ + return OPENSSL_sk_new((OPENSSL_sk_compfunc)NULL); +} + +/** + * @brief free openssl stack object + */ +void OPENSSL_sk_free(OPENSSL_STACK *stack) +{ + SSL_ASSERT(stack); + + ssl_free(stack->data); + ssl_free(stack); +} From 12b72e91afb384d975a5abfe0eeedcec560345b6 Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 14:58:14 +0800 Subject: [PATCH 25/95] components/openssl: remove unused variate --- components/openssl/library/ssl_pkey.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 6f51963eb0..6891b69eb3 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -118,9 +118,6 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) */ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { - int ret; - int ssl_ret; - SSL_ASSERT(ctx); SSL_ASSERT(pkey); From 83aea6c833c399757d3c740bcd23b0f6ba912859 Mon Sep 17 00:00:00 2001 From: dongheng Date: Fri, 23 Sep 2016 15:18:14 +0800 Subject: [PATCH 26/95] components/openssl: add extern C symbol --- components/openssl/include/internal/ssl3.h | 8 ++++++++ components/openssl/include/internal/ssl_cert.h | 8 ++++++++ components/openssl/include/internal/ssl_code.h | 8 ++++++++ components/openssl/include/internal/ssl_dbg.h | 8 ++++++++ components/openssl/include/internal/ssl_lib.h | 8 ++++++++ components/openssl/include/internal/ssl_methods.h | 8 ++++++++ components/openssl/include/internal/ssl_pkey.h | 8 ++++++++ components/openssl/include/internal/ssl_stack.h | 8 ++++++++ components/openssl/include/internal/ssl_types.h | 8 ++++++++ components/openssl/include/internal/ssl_x509.h | 8 ++++++++ components/openssl/include/internal/tls1.h | 8 ++++++++ components/openssl/include/internal/x509_vfy.h | 8 ++++++++ components/openssl/include/openssl/ssl.h | 7 +++++++ components/openssl/include/platform/ssl_pm.h | 4 ++++ components/openssl/include/platform/ssl_port.h | 4 ++++ 15 files changed, 111 insertions(+) diff --git a/components/openssl/include/internal/ssl3.h b/components/openssl/include/internal/ssl3.h index c90d546df0..007b392f3e 100644 --- a/components/openssl/include/internal/ssl3.h +++ b/components/openssl/include/internal/ssl3.h @@ -15,6 +15,10 @@ #ifndef _SSL3_H_ #define _SSL3_H_ +#ifdef __cplusplus + extern "C" { +#endif + # define SSL3_AD_CLOSE_NOTIFY 0 # define SSL3_AD_UNEXPECTED_MESSAGE 10/* fatal */ # define SSL3_AD_BAD_RECORD_MAC 20/* fatal */ @@ -33,4 +37,8 @@ #define SSL3_VERSION 0x0300 +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_cert.h b/components/openssl/include/internal/ssl_cert.h index b0bd09d480..6441aaf521 100644 --- a/components/openssl/include/internal/ssl_cert.h +++ b/components/openssl/include/internal/ssl_cert.h @@ -15,6 +15,10 @@ #ifndef _SSL_CERT_H_ #define _SSL_CERT_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl_types.h" /** @@ -35,4 +39,8 @@ CERT* ssl_cert_new(void); */ void ssl_cert_free(CERT *cert); +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_code.h b/components/openssl/include/internal/ssl_code.h index 34107d432d..80fdbb20f3 100644 --- a/components/openssl/include/internal/ssl_code.h +++ b/components/openssl/include/internal/ssl_code.h @@ -15,6 +15,10 @@ #ifndef _SSL_CODE_H_ #define _SSL_CODE_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl3.h" #include "tls1.h" #include "x509_vfy.h" @@ -113,4 +117,8 @@ typedef enum { TLS_ST_SW_FINISHED } OSSL_HANDSHAKE_STATE; +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index 745de536ff..27a4bc4db5 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -15,6 +15,10 @@ #ifndef _SSL_DEBUG_H_ #define _SSL_DEBUG_H_ +#ifdef __cplusplus + extern "C" { +#endif + #define SSL_DEBUG_ENBALE 0 #define SSL_DEBUG_LEVEL 0 #define SSL_ASSERT_ENABLE 0 @@ -46,4 +50,8 @@ #define SSL_DEBUG(level, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT(__VA_ARGS__);} } +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_lib.h b/components/openssl/include/internal/ssl_lib.h index 6ea547a7c5..bf7de22fdf 100644 --- a/components/openssl/include/internal/ssl_lib.h +++ b/components/openssl/include/internal/ssl_lib.h @@ -15,6 +15,14 @@ #ifndef _SSL_LIB_H_ #define _SSL_LIB_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl_types.h" +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index 68737b4381..a20b7c768e 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -15,6 +15,10 @@ #ifndef _SSL_METHODS_H_ #define _SSL_METHODS_H_ +#ifdef __cplusplus + extern "C" { +#endif + /** * TLS method function implement */ @@ -110,4 +114,8 @@ const X509_METHOD* X509_method(void); */ const PKEY_METHOD* EVP_PKEY_method(void); +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h index d9a22ee02c..5b7f341de9 100644 --- a/components/openssl/include/internal/ssl_pkey.h +++ b/components/openssl/include/internal/ssl_pkey.h @@ -15,6 +15,10 @@ #ifndef _SSL_PKEY_H_ #define _SSL_PKEY_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl_types.h" /** @@ -51,4 +55,8 @@ EVP_PKEY* d2i_PrivateKey(int type, */ void EVP_PKEY_free(EVP_PKEY *x); +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_stack.h b/components/openssl/include/internal/ssl_stack.h index b97015bd95..b37c8dffa9 100644 --- a/components/openssl/include/internal/ssl_stack.h +++ b/components/openssl/include/internal/ssl_stack.h @@ -1,6 +1,10 @@ #ifndef _SSL_STACK_H_ #define _SSL_STACK_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl_types.h" /** @@ -30,4 +34,8 @@ OPENSSL_STACK *OPENSSL_sk_new_null(void); */ void OPENSSL_sk_free(OPENSSL_STACK *stack); +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 6da6076148..1dc31f5a53 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -15,6 +15,10 @@ #ifndef _SSL_TYPES_H_ #define _SSL_TYPES_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl_code.h" typedef void SSL_CIPHER; @@ -294,4 +298,8 @@ typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg); +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index 9359073b69..5dac46137b 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -15,6 +15,10 @@ #ifndef _SSL_X509_H_ #define _SSL_X509_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl_types.h" #include "ssl_stack.h" @@ -50,4 +54,8 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); */ void X509_free(X509 *x); +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/tls1.h b/components/openssl/include/internal/tls1.h index b2da639194..a9da53e063 100644 --- a/components/openssl/include/internal/tls1.h +++ b/components/openssl/include/internal/tls1.h @@ -15,6 +15,10 @@ #ifndef _TLS1_H_ #define _TLS1_H_ +#ifdef __cplusplus + extern "C" { +#endif + # define TLS1_AD_DECRYPTION_FAILED 21 # define TLS1_AD_RECORD_OVERFLOW 22 # define TLS1_AD_UNKNOWN_CA 48/* fatal */ @@ -44,4 +48,8 @@ #define TLS1_1_VERSION 0x0302 #define TLS1_2_VERSION 0x0303 +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/internal/x509_vfy.h b/components/openssl/include/internal/x509_vfy.h index cab110e421..d5b0d1a213 100644 --- a/components/openssl/include/internal/x509_vfy.h +++ b/components/openssl/include/internal/x509_vfy.h @@ -15,6 +15,10 @@ #ifndef _X509_VFY_H_ #define _X509_VFY_H_ +#ifdef __cplusplus + extern "C" { +#endif + #define X509_V_OK 0 #define X509_V_ERR_UNSPECIFIED 1 #define X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT 2 @@ -100,4 +104,8 @@ #define X509_V_ERR_PROXY_SUBJECT_NAME_VIOLATION 72 +#ifdef __cplusplus +} +#endif + #endif diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index 3f92a68d70..3e8e88e67c 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -15,6 +15,10 @@ #ifndef _SSL_H_ #define _SSL_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "platform/ssl_port.h" #include "internal/ssl_x509.h" @@ -1684,5 +1688,8 @@ const char *SSL_get_psk_identity_hint(SSL *ssl); */ const char *SSL_get_psk_identity(SSL *ssl); +#ifdef __cplusplus +} +#endif #endif diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index 3f64a4ae32..47a7331b7e 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -15,6 +15,10 @@ #ifndef _SSL_PM_H_ #define _SSL_PM_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "ssl_types.h" #include "ssl_port.h" diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h index 23ef5a8757..995d33e0e5 100644 --- a/components/openssl/include/platform/ssl_port.h +++ b/components/openssl/include/platform/ssl_port.h @@ -15,6 +15,10 @@ #ifndef _SSL_PORT_H_ #define _SSL_PORT_H_ +#ifdef __cplusplus + extern "C" { +#endif + #include "esp_types.h" void* ssl_zalloc(size_t size); From d2bc170b869be45772c0889f0c2a8af751222510 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 23 Sep 2016 18:13:10 +0800 Subject: [PATCH 27/95] components/openssl: add SSL session function 1. add SSL session new and free function 2. add SSL session peer cert get and free operation 3. above all, change low-level cert object to be object point not object --- .../openssl/include/internal/ssl_types.h | 2 +- components/openssl/library/ssl_lib.c | 46 +++- components/openssl/library/ssl_x509.c | 4 +- components/openssl/platform/ssl_pm.c | 207 ++++++++++-------- 4 files changed, 161 insertions(+), 98 deletions(-) diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 1dc31f5a53..34249ea054 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -213,7 +213,7 @@ struct ssl_st /* where we are */ OSSL_STATEM statem; - SSL_SESSION session; + SSL_SESSION *session; int verify_mode; diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index a84b89e06c..ded30a33ac 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -117,6 +117,38 @@ OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl) return state; } +/** + * @brief create a new SSL session object + */ +SSL_SESSION* SSL_SESSION_new(void) +{ + SSL_SESSION *session; + + session = ssl_zalloc(sizeof(SSL_SESSION)); + if (!session) + SSL_RET(failed1); + + session->peer = X509_new(); + if (!session->peer) + SSL_RET(failed2); + + return session; + +failed2: + ssl_free(session); +failed1: + return NULL; +} + +/** + * @brief free a new SSL session object + */ +void SSL_SESSION_free(SSL_SESSION *session) +{ + X509_free(session->peer); + ssl_free(session); +} + /** * @brief create a SSL context */ @@ -210,6 +242,10 @@ SSL *SSL_new(SSL_CTX *ctx) if (!ssl) SSL_RET(failed1, "ssl_zalloc\n"); + ssl->session = SSL_SESSION_new(); + if (!ssl->session) + SSL_RET(failed2, "ssl_zalloc\n"); + ssl->ctx = ctx; ssl->method = ctx->method; @@ -222,12 +258,14 @@ SSL *SSL_new(SSL_CTX *ctx) ret = SSL_METHOD_CALL(new, ssl); if (ret) - SSL_RET(failed2, "ssl_new\n"); + SSL_RET(failed3, "ssl_new\n"); ssl->rwstate = SSL_NOTHING; return ssl; +failed3: + SSL_SESSION_free(ssl->session); failed2: ssl_free(ssl); failed1: @@ -243,6 +281,8 @@ void SSL_free(SSL *ssl) SSL_METHOD_CALL(free, ssl); + SSL_SESSION_free(ssl->session); + if (ssl->ca_reload) X509_free(ssl->client_CA); @@ -1369,7 +1409,7 @@ long SSL_set_time(SSL *ssl, long t) { SSL_ASSERT(ssl); - ssl->session.time = t; + ssl->session->time = t; return t; } @@ -1381,7 +1421,7 @@ long SSL_set_timeout(SSL *ssl, long t) { SSL_ASSERT(ssl); - ssl->session.timeout = t; + ssl->session->timeout = t; return t; } diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index e96511dc4a..c3fa0b307a 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -32,7 +32,7 @@ X509* X509_new(void) x->method = X509_method(); - ret = x->method->x509_new(x); + ret = X509_METHOD_CALL(new, x); if (ret) SSL_RET(failed2, "x509_new\n"); @@ -256,5 +256,5 @@ X509 *SSL_get_peer_certificate(const SSL *ssl) { SSL_ASSERT(ssl); - return ssl->session.peer; + return ssl->session->peer; } diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 9abfc212ec..0cf8f6c0a9 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -43,16 +43,16 @@ struct ssl_pm struct x509_pm { - mbedtls_x509_crt x509_crt; + mbedtls_x509_crt *x509_crt; - int load; + mbedtls_x509_crt *ex_crt; }; struct pkey_pm { - mbedtls_pk_context pkey; + mbedtls_pk_context *pkey; - int load; + mbedtls_pk_context *ex_pkey; }; @@ -78,13 +78,9 @@ int ssl_pm_new(SSL *ssl) const SSL_METHOD *method = ssl->method; - ssl->session.peer = ssl_zalloc(sizeof(X509)); - if (!ssl->session.peer) - SSL_ERR(ret, failed1, "ssl_zalloc\n"); - ssl_pm = ssl_zalloc(sizeof(struct ssl_pm)); if (!ssl_pm) - SSL_ERR(ret, failed2, "ssl_zalloc\n"); + SSL_ERR(ret, failed1, "ssl_zalloc\n"); mbedtls_net_init(&ssl_pm->fd); mbedtls_net_init(&ssl_pm->cl_fd); @@ -96,7 +92,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); if (ret) - SSL_ERR(ret, failed3, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); + SSL_ERR(ret, failed2, "mbedtls_ctr_drbg_seed:[-0x%x]\n", -ret); if (method->endpoint) { endpoint = MBEDTLS_SSL_IS_SERVER; @@ -105,7 +101,7 @@ int ssl_pm_new(SSL *ssl) } ret = mbedtls_ssl_config_defaults(&ssl_pm->conf, endpoint, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret) - SSL_ERR(ret, failed3, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); + SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); if (TLS1_2_VERSION == ssl->version) version = MBEDTLS_SSL_MINOR_VERSION_3; @@ -124,7 +120,7 @@ int ssl_pm_new(SSL *ssl) ret = mbedtls_ssl_setup(&ssl_pm->ssl, &ssl_pm->conf); if (ret) - SSL_ERR(ret, failed4, "mbedtls_ssl_setup:[-0x%x]\n", -ret); + SSL_ERR(ret, failed3, "mbedtls_ssl_setup:[-0x%x]\n", -ret); mbedtls_ssl_set_bio(&ssl_pm->ssl, &ssl_pm->fd, mbedtls_net_send, mbedtls_net_recv, NULL); @@ -132,13 +128,11 @@ int ssl_pm_new(SSL *ssl) return 0; -failed4: +failed3: mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); -failed3: - mbedtls_entropy_free(&ssl_pm->entropy); failed2: - ssl_free(ssl->session.peer); + mbedtls_entropy_free(&ssl_pm->entropy); failed1: return -1; } @@ -155,9 +149,6 @@ void ssl_pm_free(SSL *ssl) mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ssl_free(&ssl_pm->ssl); - ssl_free(ssl->session.peer); - ssl->session.peer = NULL; - ssl_free(ssl_pm); ssl->ssl_pm = NULL; } @@ -186,12 +177,12 @@ static int ssl_pm_reload_crt(SSL *ssl) mbedtls_ssl_conf_authmode(&ssl_pm->conf, mode); - if (ca_pm->load) { - mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, &ca_pm->x509_crt, NULL); + if (ca_pm->x509_crt) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL); } - if (pkey_pm->load) { - ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, &crt_pm->x509_crt, &pkey_pm->pkey); + if (crt_pm->x509_crt && pkey_pm->pkey) { + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->x509_crt, pkey_pm->pkey); if (ret) return -1; } @@ -217,9 +208,11 @@ int ssl_pm_handshake(SSL *ssl) ssl_speed_up_exit(); if (!mbed_ret) { + struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; + ret = 1; - ssl->session.peer->x509_pm = (struct x509_pm *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); + x509_pm->ex_crt = (mbedtls_x509_crt *)mbedtls_ssl_get_peer_cert(&ssl_pm->ssl); } else { ret = 0; SSL_DEBUG(1, "mbedtls_ssl_handshake [-0x%x]\n", -mbed_ret); @@ -234,8 +227,13 @@ int ssl_pm_shutdown(SSL *ssl) struct ssl_pm *ssl_pm = (struct ssl_pm *)ssl->ssl_pm; mbed_ret = mbedtls_ssl_close_notify(&ssl_pm->ssl); - if (!mbed_ret) + if (!mbed_ret) { + struct x509_pm *x509_pm = (struct x509_pm *)ssl->session->peer->x509_pm; + ret = 0; + + x509_pm->ex_crt = NULL; + } else ret = -1; @@ -365,51 +363,26 @@ int x509_pm_new(X509 *x) x509_pm = ssl_zalloc(sizeof(struct x509_pm)); if (!x509_pm) - return -1; + SSL_RET(failed1); x->x509_pm = x509_pm; return 0; + +failed1: + return -1; } void x509_pm_unload(X509 *x) { struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; - if (x509_pm->load) - mbedtls_x509_crt_free(&x509_pm->x509_crt); + if (x509_pm->x509_crt) { + mbedtls_x509_crt_free(x509_pm->x509_crt); - x509_pm->load = 0; -} - -int x509_pm_load(X509 *x, const unsigned char *buffer, int len) -{ - int ret; - unsigned char *load_buf; - struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; - - load_buf = ssl_malloc(len + 1); - if (!load_buf) - SSL_RET(failed1); - - ssl_memcpy(load_buf, buffer, len); - load_buf[len] = '\0'; - - x509_pm_unload(x); - - mbedtls_x509_crt_init(&x509_pm->x509_crt); - ret = mbedtls_x509_crt_parse(&x509_pm->x509_crt, load_buf, len); - ssl_free(load_buf); - - if (ret) - SSL_RET(failed1, ""); - - x509_pm->load = 1; - - return 0; - -failed1: - return -1; + ssl_free(x509_pm->x509_crt); + x509_pm->x509_crt = NULL; + } } void x509_pm_free(X509 *x) @@ -420,6 +393,44 @@ void x509_pm_free(X509 *x) x->x509_pm = NULL; } +int x509_pm_load(X509 *x, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; + + if (!x509_pm->x509_crt) { + x509_pm->x509_crt = ssl_malloc(sizeof(mbedtls_x509_crt)); + if (!x509_pm->x509_crt) + SSL_RET(failed1); + } + + load_buf = ssl_malloc(len + 1); + if (!load_buf) + SSL_RET(failed2); + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + if (x509_pm->x509_crt) + mbedtls_x509_crt_free(x509_pm->x509_crt); + + mbedtls_x509_crt_init(x509_pm->x509_crt); + ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len); + ssl_free(load_buf); + + if (ret) + SSL_RET(failed2); + + return 0; + +failed2: + ssl_free(x509_pm->x509_crt); + x509_pm->x509_crt = NULL; +failed1: + return -1; +} + int pkey_pm_new(EVP_PKEY *pkey) { struct pkey_pm *pkey_pm; @@ -437,40 +448,12 @@ void pkey_pm_unload(EVP_PKEY *pkey) { struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; - if (pkey_pm->load) - mbedtls_pk_free(&pkey_pm->pkey); + if (pkey_pm->pkey) { + mbedtls_pk_free(pkey_pm->pkey); - pkey_pm->load = 0; -} - -int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len) -{ - int ret; - unsigned char *load_buf; - struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; - - load_buf = ssl_malloc(len + 1); - if (!load_buf) - SSL_RET(failed1); - - ssl_memcpy(load_buf, buffer, len); - load_buf[len] = '\0'; - - pkey_pm_unload(pkey); - - mbedtls_pk_init(&pkey_pm->pkey); - ret = mbedtls_pk_parse_key(&pkey_pm->pkey, load_buf, len, NULL, 0); - ssl_free(load_buf); - - if (ret) - SSL_RET(failed1, ""); - - pkey_pm->load = 1; - - return 0; - -failed1: - return -1; + ssl_free(pkey_pm->pkey); + pkey_pm->pkey = NULL; + } } void pkey_pm_free(EVP_PKEY *pkey) @@ -481,6 +464,46 @@ void pkey_pm_free(EVP_PKEY *pkey) pkey->pkey_pm = NULL; } +int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len) +{ + int ret; + unsigned char *load_buf; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; + + if (!pkey_pm->pkey) { + pkey_pm->pkey = ssl_malloc(sizeof(mbedtls_pk_context)); + if (!pkey_pm->pkey) + SSL_RET(failed1); + } + + load_buf = ssl_malloc(len + 1); + if (!load_buf) + SSL_RET(failed2); + + ssl_memcpy(load_buf, buffer, len); + load_buf[len] = '\0'; + + if (pkey_pm->pkey) + mbedtls_pk_free(pkey_pm->pkey); + + mbedtls_pk_init(pkey_pm->pkey); + ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len, NULL, 0); + ssl_free(load_buf); + + if (ret) + SSL_RET(failed2); + + return 0; + +failed2: + ssl_free(pkey_pm->pkey); + pkey_pm->pkey = NULL; +failed1: + return -1; +} + + + void ssl_pm_set_bufflen(SSL *ssl, int len) { max_content_len = len; From e1c4a4bfa3e9a929c42e40238878c1bce83db76a Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 23 Sep 2016 18:47:09 +0800 Subject: [PATCH 28/95] components/openssl: add cert and pkey extra object point the point is pointed to its father's object and should not free just set NULL if not use --- components/openssl/library/ssl_lib.c | 26 +++++++++++++++++--------- components/openssl/platform/ssl_pm.c | 23 +++++++++++++++++++++-- 2 files changed, 38 insertions(+), 11 deletions(-) diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index ded30a33ac..06bbe270c5 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -246,24 +246,34 @@ SSL *SSL_new(SSL_CTX *ctx) if (!ssl->session) SSL_RET(failed2, "ssl_zalloc\n"); + ssl->cert = ssl_cert_new(); + if (!ssl->cert) + SSL_RET(failed3, "ssl_cert_new\n"); + + ssl->client_CA = X509_new(); + if (!ssl->client_CA) + SSL_RET(failed4, "ssl_cert_new\n"); + ssl->ctx = ctx; ssl->method = ctx->method; ssl->version = ctx->version; ssl->options = ctx->options; - ssl->cert = ctx->cert; - ssl->client_CA = ctx->client_CA; ssl->verify_mode = ctx->verify_mode; ret = SSL_METHOD_CALL(new, ssl); if (ret) - SSL_RET(failed3, "ssl_new\n"); + SSL_RET(failed5, "ssl_new\n"); ssl->rwstate = SSL_NOTHING; return ssl; +failed5: + X509_free(ssl->client_CA); +failed4: + ssl_cert_free(ssl->cert); failed3: SSL_SESSION_free(ssl->session); failed2: @@ -281,14 +291,12 @@ void SSL_free(SSL *ssl) SSL_METHOD_CALL(free, ssl); + X509_free(ssl->client_CA); + + ssl_cert_free(ssl->cert); + SSL_SESSION_free(ssl->session); - if (ssl->ca_reload) - X509_free(ssl->client_CA); - - if (ssl->crt_reload) - ssl_cert_free(ssl->cert); - ssl_free(ssl); } diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 0cf8f6c0a9..311c3a4b6f 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -78,6 +78,14 @@ int ssl_pm_new(SSL *ssl) const SSL_METHOD *method = ssl->method; + struct x509_pm *ctx_ca = (struct x509_pm *)ssl->ctx->client_CA->x509_pm; + struct x509_pm *ctx_crt = (struct x509_pm *)ssl->ctx->cert->x509->x509_pm; + struct pkey_pm *ctx_pkey = (struct pkey_pm *)ssl->ctx->cert->pkey->pkey_pm; + + struct x509_pm *ssl_ca = (struct x509_pm *)ssl->client_CA->x509_pm; + struct x509_pm *ssl_crt = (struct x509_pm *)ssl->cert->x509->x509_pm; + struct pkey_pm *ssl_pkey = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; + ssl_pm = ssl_zalloc(sizeof(struct ssl_pm)); if (!ssl_pm) SSL_ERR(ret, failed1, "ssl_zalloc\n"); @@ -126,6 +134,10 @@ int ssl_pm_new(SSL *ssl) ssl->ssl_pm = ssl_pm; + ssl_ca->ex_crt = ctx_ca->x509_crt; + ssl_crt->ex_crt = ctx_crt->x509_crt; + ssl_pkey->ex_pkey = ctx_pkey->pkey; + return 0; failed3: @@ -179,14 +191,21 @@ static int ssl_pm_reload_crt(SSL *ssl) if (ca_pm->x509_crt) { mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL); + } else if (ca_pm->ex_crt) { + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL); } if (crt_pm->x509_crt && pkey_pm->pkey) { ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->x509_crt, pkey_pm->pkey); - if (ret) - return -1; + } else if (crt_pm->ex_crt && pkey_pm->ex_pkey) { + ret = mbedtls_ssl_conf_own_cert(&ssl_pm->conf, crt_pm->ex_crt, pkey_pm->ex_pkey); + } else { + ret = 0; } + if (ret) + return -1; + return 0; } From cf4aaf639714f4d479dd38ea396ff0a66d5a5981 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 26 Sep 2016 11:14:19 +0800 Subject: [PATCH 29/95] components/openssl: optimize the SSL certification and private key function 1. add inheritance function 2. remove low-level platform unload cert & pkey function 3. optimize the cert load and free function --- .../openssl/include/internal/ssl_cert.h | 9 ++ .../openssl/include/internal/ssl_methods.h | 12 +-- .../openssl/include/internal/ssl_pkey.h | 9 ++ .../openssl/include/internal/ssl_types.h | 12 +-- .../openssl/include/internal/ssl_x509.h | 9 ++ components/openssl/include/platform/ssl_pm.h | 11 +-- components/openssl/library/ssl_cert.c | 33 +++++-- components/openssl/library/ssl_lib.c | 16 ++-- components/openssl/library/ssl_methods.c | 4 +- components/openssl/library/ssl_pkey.c | 82 ++++++++--------- components/openssl/library/ssl_x509.c | 89 ++++++++++--------- components/openssl/platform/ssl_pm.c | 56 +++++------- 12 files changed, 178 insertions(+), 164 deletions(-) diff --git a/components/openssl/include/internal/ssl_cert.h b/components/openssl/include/internal/ssl_cert.h index 6441aaf521..86cf31ad51 100644 --- a/components/openssl/include/internal/ssl_cert.h +++ b/components/openssl/include/internal/ssl_cert.h @@ -21,6 +21,15 @@ #include "ssl_types.h" +/** + * @brief create a certification object include private key object according to input certification + * + * @param ic - input certification point + * + * @return certification object point + */ +CERT *__ssl_cert_new(CERT *ic); + /** * @brief create a certification object include private key object * diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index a20b7c768e..9fd9ce9068 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -69,14 +69,12 @@ #define IMPLEMENT_X509_METHOD(func_name, \ new, \ free, \ - load, \ - unload) \ + load) \ const X509_METHOD* func_name(void) { \ static const X509_METHOD func_name##_data LOCAL_ATRR = { \ new, \ free, \ - load, \ - unload, \ + load \ }; \ return &func_name##_data; \ } @@ -84,14 +82,12 @@ #define IMPLEMENT_PKEY_METHOD(func_name, \ new, \ free, \ - load, \ - unload) \ + load) \ const PKEY_METHOD* func_name(void) { \ static const PKEY_METHOD func_name##_data LOCAL_ATRR = { \ new, \ free, \ - load, \ - unload, \ + load \ }; \ return &func_name##_data; \ } diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h index 5b7f341de9..f4da041681 100644 --- a/components/openssl/include/internal/ssl_pkey.h +++ b/components/openssl/include/internal/ssl_pkey.h @@ -21,6 +21,15 @@ #include "ssl_types.h" +/** + * @brief create a private key object according to input private key + * + * @param ipk - input private key point + * + * @return new private key object point + */ +EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk); + /** * @brief create a private key object * diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 34249ea054..c571865c1e 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -196,12 +196,8 @@ struct ssl_st /* shut things down(0x01 : sent, 0x02 : received) */ int shutdown; - int crt_reload; - CERT *cert; - int ca_reload; - X509 *client_CA; SSL_CTX *ctx; @@ -274,24 +270,20 @@ struct ssl_method_func_st { struct x509_method_st { - int (*x509_new)(X509 *x); + int (*x509_new)(X509 *x, X509 *m_x); void (*x509_free)(X509 *x); int (*x509_load)(X509 *x, const unsigned char *buf, int len); - - void (*x509_unload)(X509 *x); }; struct pkey_method_st { - int (*pkey_new)(EVP_PKEY *pkey); + int (*pkey_new)(EVP_PKEY *pkey, EVP_PKEY *m_pkey); void (*pkey_free)(EVP_PKEY *pkey); int (*pkey_load)(EVP_PKEY *pkey, const unsigned char *buf, int len); - - void (*pkey_unload)(EVP_PKEY *pkey); }; typedef int (*next_proto_cb)(SSL *ssl, unsigned char **out, diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index 5dac46137b..2c72980b07 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -24,6 +24,15 @@ DEFINE_STACK_OF(X509_NAME) +/** + * @brief create a X509 certification object according to input X509 certification + * + * @param ix - input X509 certification point + * + * @return new X509 certification object point + */ +X509* __X509_new(X509 *ix); + /** * @brief create a X509 certification object * diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index 47a7331b7e..cf1d213799 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -42,16 +42,13 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl); void ssl_pm_set_bufflen(SSL *ssl, int len); -int x509_pm_new(X509 *x); +int x509_pm_new(X509 *x, X509 *m_x); void x509_pm_free(X509 *x); int x509_pm_load(X509 *x, const unsigned char *buffer, int len); -void x509_pm_unload(X509 *x); -void x509_pm_start_ca(X509 *x); -int pkey_pm_new(EVP_PKEY *pkey); -void pkey_pm_free(EVP_PKEY *pkey); -int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len); -void pkey_pm_unload(EVP_PKEY *pkey); +int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pk); +void pkey_pm_free(EVP_PKEY *pk); +int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len); long ssl_pm_get_verify_result(const SSL *ssl); diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index fd05bc8315..e4fd4d7785 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -19,23 +19,34 @@ #include "ssl_port.h" /** - * @brief create a certification object include private key object + * @brief create a certification object according to input certification */ -CERT *ssl_cert_new(void) +CERT *__ssl_cert_new(CERT *ic) { CERT *cert; + X509 *ix; + EVP_PKEY *ipk; + cert = ssl_zalloc(sizeof(CERT)); if (!cert) SSL_RET(failed1, "ssl_zalloc\n"); - cert->pkey = EVP_PKEY_new(); - if (!cert->pkey) - SSL_RET(failed2, "EVP_PKEY_new\n"); + if (ic) { + ipk = ic->pkey; + ix = ic->x509; + } else { + ipk = NULL; + ix = NULL; + } - cert->x509 = X509_new(); + cert->pkey = __EVP_PKEY_new(ipk); + if (!cert->pkey) + SSL_RET(failed2, "__EVP_PKEY_new\n"); + + cert->x509 = __X509_new(ix); if (!cert->x509) - SSL_RET(failed3, "X509_new\n"); + SSL_RET(failed3, "__X509_new\n"); return cert; @@ -47,6 +58,14 @@ failed1: return NULL; } +/** + * @brief create a certification object include private key object + */ +CERT *ssl_cert_new(void) +{ + return __ssl_cert_new(NULL); +} + /** * @brief free a certification object */ diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 06bbe270c5..b82d54cd26 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -158,11 +158,11 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) CERT *cert; X509 *client_ca; - if (!method) SSL_RET(go_failed1, "method\n"); + if (!method) SSL_RET(go_failed1, "method:NULL\n"); client_ca = X509_new(); if (!client_ca) - SSL_RET(go_failed1, "sk_X509_NAME_new_null\n"); + SSL_RET(go_failed1, "X509_new\n"); cert = ssl_cert_new(); if (!cert) @@ -170,7 +170,7 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) ctx = (SSL_CTX *)ssl_zalloc(sizeof(SSL_CTX)); if (!ctx) - SSL_RET(go_failed3, "ssl_ctx_new:ctx\n"); + SSL_RET(go_failed3, "ssl_zalloc:ctx\n"); ctx->method = method; ctx->client_CA = client_ca; @@ -244,15 +244,15 @@ SSL *SSL_new(SSL_CTX *ctx) ssl->session = SSL_SESSION_new(); if (!ssl->session) - SSL_RET(failed2, "ssl_zalloc\n"); + SSL_RET(failed2, "SSL_SESSION_new\n"); - ssl->cert = ssl_cert_new(); + ssl->cert = __ssl_cert_new(ctx->cert); if (!ssl->cert) - SSL_RET(failed3, "ssl_cert_new\n"); + SSL_RET(failed3, "__ssl_cert_new\n"); - ssl->client_CA = X509_new(); + ssl->client_CA = __X509_new(ctx->client_CA); if (!ssl->client_CA) - SSL_RET(failed4, "ssl_cert_new\n"); + SSL_RET(failed4, "__X509_new\n"); ssl->ctx = ctx; ssl->method = ctx->method; diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index 042d670ab9..e363b5e46d 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -72,11 +72,11 @@ IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); */ IMPLEMENT_X509_METHOD(X509_method, x509_pm_new, x509_pm_free, - x509_pm_load, x509_pm_unload); + x509_pm_load); /** * @brief get private key object method */ IMPLEMENT_PKEY_METHOD(EVP_PKEY_method, pkey_pm_new, pkey_pm_free, - pkey_pm_load, pkey_pm_unload); + pkey_pm_load); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 6891b69eb3..573b1f2e8f 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -20,20 +20,24 @@ #include "ssl_port.h" /** - * @brief create a private key object + * @brief create a private key object according to input private key */ -EVP_PKEY* EVP_PKEY_new(void) +EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk) { int ret; EVP_PKEY *pkey; pkey = ssl_zalloc(sizeof(EVP_PKEY)); if (!pkey) - SSL_RET(failed1, "ssl_malloc\n"); + SSL_RET(failed1, "ssl_zalloc\n"); - pkey->method = EVP_PKEY_method(); + if (ipk) { + pkey->method = ipk->method; + } else { + pkey->method = EVP_PKEY_method(); + } - ret = EVP_PKEY_METHOD_CALL(new, pkey); + ret = EVP_PKEY_METHOD_CALL(new, pkey, ipk); if (ret) SSL_RET(failed2, "EVP_PKEY_METHOD_CALL\n"); @@ -45,6 +49,14 @@ failed1: return NULL; } +/** + * @brief create a private key object + */ +EVP_PKEY* EVP_PKEY_new(void) +{ + return __EVP_PKEY_new(NULL); +} + /** * @brief free a private key object */ @@ -105,6 +117,9 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) SSL_ASSERT(ctx); SSL_ASSERT(pkey); + if (ctx->cert->pkey == pkey) + return 1; + if (ctx->cert->pkey) EVP_PKEY_free(ctx->cert->pkey); @@ -118,12 +133,13 @@ int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey) */ int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { - SSL_ASSERT(ctx); + SSL_ASSERT(ssl); SSL_ASSERT(pkey); - if (!ssl->ca_reload) - ssl->ca_reload = 1; - else + if (ssl->cert->pkey == pkey) + return 1; + + if (ssl->cert->pkey) EVP_PKEY_free(ssl->cert->pkey); ssl->cert->pkey = pkey; @@ -138,20 +154,20 @@ int SSL_CTX_use_PrivateKey_ASN1(int type, SSL_CTX *ctx, const unsigned char *d, long len) { int ret; - EVP_PKEY *pkey; + EVP_PKEY *pk; - pkey = d2i_PrivateKey(0, &ctx->cert->pkey, &d, len); - if (!pkey) + pk = d2i_PrivateKey(0, NULL, &d, len); + if (!pk) SSL_RET(failed1, "d2i_PrivateKey\n"); - ret = SSL_CTX_use_PrivateKey(ctx, pkey); + ret = SSL_CTX_use_PrivateKey(ctx, pk); if (!ret) SSL_RET(failed2, "SSL_CTX_use_PrivateKey\n"); return 1; failed2: - EVP_PKEY_free(pkey); + EVP_PKEY_free(pk); failed1: return 0; } @@ -163,44 +179,20 @@ int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len) { int ret; - int reload; - EVP_PKEY *pkey; - CERT *cert; - CERT *old_cert; + EVP_PKEY *pk; - if (!ssl->crt_reload) { - cert = ssl_cert_new(); - if (!cert) - SSL_RET(failed1, "ssl_cert_new\n"); + pk = d2i_PrivateKey(0, NULL, &d, len); + if (!pk) + SSL_RET(failed1, "d2i_PrivateKey\n"); - old_cert = ssl->cert ; - ssl->cert = cert; - - ssl->crt_reload = 1; - - reload = 1; - } else { - reload = 0; - } - - pkey = d2i_PrivateKey(0, &ssl->cert->pkey, &d, len); - if (!pkey) - SSL_RET(failed2, "d2i_PrivateKey\n"); - - ret = SSL_use_PrivateKey(ssl, pkey); + ret = SSL_use_PrivateKey(ssl, pk); if (!ret) - SSL_RET(failed3, "SSL_use_PrivateKey\n"); + SSL_RET(failed2, "SSL_use_PrivateKey\n"); return 1; -failed3: - EVP_PKEY_free(pkey); failed2: - if (reload) { - ssl->cert = old_cert; - ssl_cert_free(cert); - ssl->crt_reload = 0; - } + EVP_PKEY_free(pk); failed1: return 0; } diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index c3fa0b307a..b57cc0dfb9 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -19,9 +19,9 @@ #include "ssl_port.h" /** - * @brief create a X509 certification object + * @brief create a X509 certification object according to input X509 certification */ -X509* X509_new(void) +X509* __X509_new(X509 *ix) { int ret; X509 *x; @@ -30,9 +30,12 @@ X509* X509_new(void) if (!x) SSL_RET(failed1, "ssl_malloc\n"); - x->method = X509_method(); + if (ix) + x->method = ix->method; + else + x->method = X509_method(); - ret = X509_METHOD_CALL(new, x); + ret = X509_METHOD_CALL(new, x, ix); if (ret) SSL_RET(failed2, "x509_new\n"); @@ -44,6 +47,14 @@ failed1: return NULL; } +/** + * @brief create a X509 certification object + */ +X509* X509_new(void) +{ + return __X509_new(NULL); +} + /** * @brief free a X509 certification object */ @@ -78,7 +89,7 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len) ret = X509_METHOD_CALL(load, x, buffer, len); if (ret) - SSL_RET(failed2, "X509_METHOD_CALL\n"); + SSL_RET(failed2, "x509_load\n"); return x; @@ -97,8 +108,10 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x) SSL_ASSERT(ctx); SSL_ASSERT(x); - if (ctx->client_CA) - X509_free(ctx->client_CA); + if (ctx->client_CA == x) + return 1; + + X509_free(ctx->client_CA); ctx->client_CA = x; @@ -113,10 +126,10 @@ int SSL_add_client_CA(SSL *ssl, X509 *x) SSL_ASSERT(ssl); SSL_ASSERT(x); - if (!ssl->ca_reload) - ssl->ca_reload = 1; - else - X509_free(ssl->client_CA); + if (ssl->client_CA == x) + return 1; + + X509_free(ssl->client_CA); ssl->client_CA = x; @@ -131,6 +144,11 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) SSL_ASSERT(ctx); SSL_ASSERT(x); + if (ctx->cert->x509 == x) + return 1; + + X509_free(ctx->cert->x509); + ctx->cert->x509 = x; return 1; @@ -141,9 +159,14 @@ int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x) */ int SSL_use_certificate(SSL *ssl, X509 *x) { - SSL_ASSERT(ctx); + SSL_ASSERT(ssl); SSL_ASSERT(x); + if (ssl->cert->x509 == x) + return 1; + + X509_free(ssl->cert->x509); + ssl->cert->x509 = x; return 1; @@ -166,20 +189,20 @@ int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d) { int ret; - X509 *cert; + X509 *x; - cert = d2i_X509(&ctx->cert->x509, d, len); - if (!cert) + x = d2i_X509(NULL, d, len); + if (!x) SSL_RET(failed1, "d2i_X509\n"); - ret = SSL_CTX_use_certificate(ctx, cert); + ret = SSL_CTX_use_certificate(ctx, x); if (!ret) SSL_RET(failed2, "SSL_CTX_use_certificate\n"); return 1; failed2: - X509_free(cert); + X509_free(x); failed1: return 0; } @@ -193,42 +216,20 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, int ret; int reload; X509 *x; - CERT *cert; - CERT *old_cert; + int m = 0; - if (!ssl->crt_reload) { - cert = ssl_cert_new(); - if (!cert) - SSL_RET(failed1, "ssl_cert_new\n"); - - old_cert = ssl->cert ; - ssl->cert = cert; - - ssl->crt_reload = 1; - - reload = 1; - } else { - reload = 0; - } - - x = d2i_X509(&ssl->cert->x509, d, len); + x = d2i_X509(NULL, d, len); if (!x) - SSL_RET(failed2, "d2i_X509\n"); + SSL_RET(failed1, "d2i_X509\n"); ret = SSL_use_certificate(ssl, x); if (!ret) - SSL_RET(failed3, "SSL_use_certificate\n"); + SSL_RET(failed2, "SSL_use_certificate\n"); return 1; -failed3: - X509_free(x); failed2: - if (reload) { - ssl->cert = old_cert; - ssl_cert_free(cert); - ssl->crt_reload = 0; - } + X509_free(x); failed1: return 0; } diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 311c3a4b6f..9f5290cc52 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -78,14 +78,6 @@ int ssl_pm_new(SSL *ssl) const SSL_METHOD *method = ssl->method; - struct x509_pm *ctx_ca = (struct x509_pm *)ssl->ctx->client_CA->x509_pm; - struct x509_pm *ctx_crt = (struct x509_pm *)ssl->ctx->cert->x509->x509_pm; - struct pkey_pm *ctx_pkey = (struct pkey_pm *)ssl->ctx->cert->pkey->pkey_pm; - - struct x509_pm *ssl_ca = (struct x509_pm *)ssl->client_CA->x509_pm; - struct x509_pm *ssl_crt = (struct x509_pm *)ssl->cert->x509->x509_pm; - struct pkey_pm *ssl_pkey = (struct pkey_pm *)ssl->cert->pkey->pkey_pm; - ssl_pm = ssl_zalloc(sizeof(struct ssl_pm)); if (!ssl_pm) SSL_ERR(ret, failed1, "ssl_zalloc\n"); @@ -134,10 +126,6 @@ int ssl_pm_new(SSL *ssl) ssl->ssl_pm = ssl_pm; - ssl_ca->ex_crt = ctx_ca->x509_crt; - ssl_crt->ex_crt = ctx_crt->x509_crt; - ssl_pkey->ex_pkey = ctx_pkey->pkey; - return 0; failed3: @@ -376,7 +364,7 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl) return state; } -int x509_pm_new(X509 *x) +int x509_pm_new(X509 *x, X509 *m_x) { struct x509_pm *x509_pm; @@ -386,13 +374,19 @@ int x509_pm_new(X509 *x) x->x509_pm = x509_pm; + if (m_x) { + struct x509_pm *m_x509_pm = (struct x509_pm *)m_x->x509_pm; + + x509_pm->ex_crt = m_x509_pm->x509_crt; + } + return 0; failed1: return -1; } -void x509_pm_unload(X509 *x) +void x509_pm_free(X509 *x) { struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; @@ -402,11 +396,6 @@ void x509_pm_unload(X509 *x) ssl_free(x509_pm->x509_crt); x509_pm->x509_crt = NULL; } -} - -void x509_pm_free(X509 *x) -{ - x509_pm_unload(x); ssl_free(x->x509_pm); x->x509_pm = NULL; @@ -450,7 +439,7 @@ failed1: return -1; } -int pkey_pm_new(EVP_PKEY *pkey) +int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey) { struct pkey_pm *pkey_pm; @@ -458,14 +447,20 @@ int pkey_pm_new(EVP_PKEY *pkey) if (!pkey_pm) return -1; - pkey->pkey_pm = pkey_pm; + pk->pkey_pm = pkey_pm; + + if (m_pkey) { + struct pkey_pm *m_pkey_pm = (struct pkey_pm *)m_pkey->pkey_pm; + + pkey_pm->ex_pkey = m_pkey_pm->pkey; + } return 0; } -void pkey_pm_unload(EVP_PKEY *pkey) +void pkey_pm_free(EVP_PKEY *pk) { - struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; if (pkey_pm->pkey) { mbedtls_pk_free(pkey_pm->pkey); @@ -473,21 +468,16 @@ void pkey_pm_unload(EVP_PKEY *pkey) ssl_free(pkey_pm->pkey); pkey_pm->pkey = NULL; } + + ssl_free(pk->pkey_pm); + pk->pkey_pm = NULL; } -void pkey_pm_free(EVP_PKEY *pkey) -{ - pkey_pm_unload(pkey); - - ssl_free(pkey->pkey_pm); - pkey->pkey_pm = NULL; -} - -int pkey_pm_load(EVP_PKEY *pkey, const unsigned char *buffer, int len) +int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) { int ret; unsigned char *load_buf; - struct pkey_pm *pkey_pm = (struct pkey_pm *)pkey->pkey_pm; + struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; if (!pkey_pm->pkey) { pkey_pm->pkey = ssl_malloc(sizeof(mbedtls_pk_context)); From 3882937427e7cd3fe60ee78ff7b5d583cfb84fec Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 27 Sep 2016 10:06:24 +0800 Subject: [PATCH 30/95] components/openssl: add debug message and change verifying mode --- components/openssl/include/internal/ssl_dbg.h | 6 ++-- .../openssl/include/internal/ssl_methods.h | 2 ++ .../openssl/include/internal/ssl_x509.h | 24 ++++++++++++++++ components/openssl/library/ssl_lib.c | 6 ++-- components/openssl/library/ssl_methods.c | 1 - components/openssl/library/ssl_pkey.c | 2 -- components/openssl/library/ssl_stack.c | 8 +++--- components/openssl/library/ssl_x509.c | 3 -- components/openssl/platform/ssl_pm.c | 28 ++++++++++--------- 9 files changed, 51 insertions(+), 29 deletions(-) diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index 27a4bc4db5..d6ae47499e 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -19,10 +19,10 @@ extern "C" { #endif -#define SSL_DEBUG_ENBALE 0 +#define SSL_DEBUG_ENBALE 1 #define SSL_DEBUG_LEVEL 0 -#define SSL_ASSERT_ENABLE 0 -#define SSL_DEBUG_LOCATION_ENABLE 0 +#define SSL_ASSERT_ENABLE 1 +#define SSL_DEBUG_LOCATION_ENABLE 1 #if SSL_DEBUG_ENBALE extern int ets_printf(const char *fmt, ...); diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index 9fd9ce9068..7a63b9e949 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -15,6 +15,8 @@ #ifndef _SSL_METHODS_H_ #define _SSL_METHODS_H_ +#include "ssl_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index 2c72980b07..b5fea34f1a 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -63,6 +63,30 @@ X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); */ void X509_free(X509 *x); +/** + * @brief set SSL context client CA certification + * + * @param ctx - SSL context point + * @param x - X509 certification point + * + * @return result + * 0 : failed + * 1 : OK + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +/** + * @brief add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - X509 certification point + * + * @return result + * 0 : failed + * 1 : OK + */ +int SSL_add_client_CA(SSL *ssl, X509 *x); + #ifdef __cplusplus } #endif diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index b82d54cd26..267d23f25f 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -126,11 +126,11 @@ SSL_SESSION* SSL_SESSION_new(void) session = ssl_zalloc(sizeof(SSL_SESSION)); if (!session) - SSL_RET(failed1); + SSL_RET(failed1, "ssl_zalloc\n"); session->peer = X509_new(); if (!session->peer) - SSL_RET(failed2); + SSL_RET(failed2, "X509_new\n"); return session; @@ -1500,7 +1500,7 @@ 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 *)) { - SSL_ASSERT(ctx); + SSL_ASSERT(ssl); ssl->verify_mode = mode; ssl->verify_callback = verify_callback; diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index e363b5e46d..8159511c49 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ssl_lib.h" #include "ssl_methods.h" #include "ssl_pm.h" diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 573b1f2e8f..20debfbcfc 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -12,9 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -#include "ssl_lib.h" #include "ssl_pkey.h" -#include "ssl_cert.h" #include "ssl_methods.h" #include "ssl_dbg.h" #include "ssl_port.h" diff --git a/components/openssl/library/ssl_stack.c b/components/openssl/library/ssl_stack.c index 46e6f7efd8..4ea40e7259 100644 --- a/components/openssl/library/ssl_stack.c +++ b/components/openssl/library/ssl_stack.c @@ -30,13 +30,13 @@ OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) OPENSSL_STACK *stack; char **data; - stack = ssl_malloc(sizeof(OPENSSL_STACK)); + stack = ssl_zalloc(sizeof(OPENSSL_STACK)); if (!stack) - SSL_RET(failed1); + SSL_RET(failed1, "ssl_zalloc\n"); - data = ssl_malloc(sizeof(*data) * MIN_NODES); + data = ssl_zalloc(sizeof(*data) * MIN_NODES); if (!data) - SSL_RET(failed2); + SSL_RET(failed2, "ssl_zalloc\n"); stack->data = data; stack->num_alloc = MIN_NODES; diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index b57cc0dfb9..d060419e6a 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -13,7 +13,6 @@ // limitations under the License. #include "ssl_x509.h" -#include "ssl_cert.h" #include "ssl_methods.h" #include "ssl_dbg.h" #include "ssl_port.h" @@ -214,9 +213,7 @@ int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d) { int ret; - int reload; X509 *x; - int m = 0; x = d2i_X509(NULL, d, len); if (!x) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 9f5290cc52..151adbaf81 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -112,7 +112,7 @@ int ssl_pm_new(SSL *ssl) 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, version); mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); @@ -169,7 +169,7 @@ static int ssl_pm_reload_crt(SSL *ssl) if (ssl->verify_mode == SSL_VERIFY_PEER) mode = MBEDTLS_SSL_VERIFY_REQUIRED; else if (ssl->verify_mode == SSL_VERIFY_FAIL_IF_NO_PEER_CERT) - mode = MBEDTLS_SSL_VERIFY_NONE; + mode = MBEDTLS_SSL_VERIFY_OPTIONAL; else if (ssl->verify_mode == SSL_VERIFY_CLIENT_ONCE) mode = MBEDTLS_SSL_VERIFY_UNSET; else @@ -370,7 +370,7 @@ int x509_pm_new(X509 *x, X509 *m_x) x509_pm = ssl_zalloc(sizeof(struct x509_pm)); if (!x509_pm) - SSL_RET(failed1); + SSL_RET(failed1, "ssl_zalloc\n"); x->x509_pm = x509_pm; @@ -408,27 +408,28 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; if (!x509_pm->x509_crt) { - x509_pm->x509_crt = ssl_malloc(sizeof(mbedtls_x509_crt)); + x509_pm->x509_crt = ssl_zalloc(sizeof(mbedtls_x509_crt)); if (!x509_pm->x509_crt) - SSL_RET(failed1); + SSL_RET(failed1, "ssl_zalloc\n"); } load_buf = ssl_malloc(len + 1); if (!load_buf) - SSL_RET(failed2); + SSL_RET(failed2, "ssl_malloc\n"); ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; + mbedtls_x509_crt_init(x509_pm->x509_crt); + if (x509_pm->x509_crt) mbedtls_x509_crt_free(x509_pm->x509_crt); - mbedtls_x509_crt_init(x509_pm->x509_crt); ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len); ssl_free(load_buf); if (ret) - SSL_RET(failed2); + SSL_RET(failed2, "mbedtls_x509_crt_parse, return [-0x%x]\n", -ret); return 0; @@ -480,27 +481,28 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; if (!pkey_pm->pkey) { - pkey_pm->pkey = ssl_malloc(sizeof(mbedtls_pk_context)); + pkey_pm->pkey = ssl_zalloc(sizeof(mbedtls_pk_context)); if (!pkey_pm->pkey) - SSL_RET(failed1); + SSL_RET(failed1, "ssl_zalloc\n"); } load_buf = ssl_malloc(len + 1); if (!load_buf) - SSL_RET(failed2); + SSL_RET(failed2, "ssl_malloc\n"); ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; + mbedtls_pk_init(pkey_pm->pkey); + if (pkey_pm->pkey) mbedtls_pk_free(pkey_pm->pkey); - mbedtls_pk_init(pkey_pm->pkey); ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len, NULL, 0); ssl_free(load_buf); if (ret) - SSL_RET(failed2); + SSL_RET(failed2, "mbedtls_pk_parse_key, return [-0x%x]\n", -ret); return 0; From 652ddae44f7fe78ab45f7efc524204f2e6ad5ee8 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 27 Sep 2016 14:28:39 +0800 Subject: [PATCH 31/95] components/openssl: change low-level certification loading sequence --- components/openssl/platform/ssl_pm.c | 34 ++++++++++++++++++---------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 151adbaf81..9df8b6481e 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -25,6 +25,12 @@ #include "mbedtls/error.h" #include "mbedtls/certs.h" +#if 0 + #define DEBUG_LOAD_BUF_STRING(str) SSL_DEBUG(1, "%s\n", str) +#else + #define DEBUG_LOAD_BUF_STRING(str) +#endif + struct ssl_pm { /* local socket file description */ @@ -407,10 +413,13 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) unsigned char *load_buf; struct x509_pm *x509_pm = (struct x509_pm *)x->x509_pm; + if (x509_pm->x509_crt) + mbedtls_x509_crt_free(x509_pm->x509_crt); + if (!x509_pm->x509_crt) { - x509_pm->x509_crt = ssl_zalloc(sizeof(mbedtls_x509_crt)); + x509_pm->x509_crt = ssl_malloc(sizeof(mbedtls_x509_crt)); if (!x509_pm->x509_crt) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_malloc\n"); } load_buf = ssl_malloc(len + 1); @@ -420,12 +429,11 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; - mbedtls_x509_crt_init(x509_pm->x509_crt); + DEBUG_LOAD_BUF_STRING(load_buf); - if (x509_pm->x509_crt) - mbedtls_x509_crt_free(x509_pm->x509_crt); + mbedtls_x509_crt_init(x509_pm->x509_crt); - ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len); + ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len + 1); ssl_free(load_buf); if (ret) @@ -480,10 +488,13 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) unsigned char *load_buf; struct pkey_pm *pkey_pm = (struct pkey_pm *)pk->pkey_pm; + if (pkey_pm->pkey) + mbedtls_pk_free(pkey_pm->pkey); + if (!pkey_pm->pkey) { - pkey_pm->pkey = ssl_zalloc(sizeof(mbedtls_pk_context)); + pkey_pm->pkey = ssl_malloc(sizeof(mbedtls_pk_context)); if (!pkey_pm->pkey) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_malloc\n"); } load_buf = ssl_malloc(len + 1); @@ -493,12 +504,11 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; + DEBUG_LOAD_BUF_STRING(load_buf); + mbedtls_pk_init(pkey_pm->pkey); - if (pkey_pm->pkey) - mbedtls_pk_free(pkey_pm->pkey); - - ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len, NULL, 0); + ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len + 1, NULL, 0); ssl_free(load_buf); if (ret) From 877adaab7a0365ab2a85f9df8073332a38fd9232 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 27 Sep 2016 18:50:57 +0800 Subject: [PATCH 32/95] components/openssl: add some function description --- .../openssl/include/internal/ssl_pkey.h | 15 +++++++++++++ .../openssl/include/internal/ssl_x509.h | 14 +++++++++++++ components/openssl/include/openssl/ssl.h | 21 +++++++++++++++++++ 3 files changed, 50 insertions(+) diff --git a/components/openssl/include/internal/ssl_pkey.h b/components/openssl/include/internal/ssl_pkey.h index f4da041681..e790fcc995 100644 --- a/components/openssl/include/internal/ssl_pkey.h +++ b/components/openssl/include/internal/ssl_pkey.h @@ -64,6 +64,21 @@ EVP_PKEY* d2i_PrivateKey(int type, */ void EVP_PKEY_free(EVP_PKEY *x); +/** + * @brief load private key into the SSL + * + * @param type - private key type + * @param ssl - SSL point + * @param len - data bytes + * @param d - data point + * + * @return result + * 0 : failed + * 1 : OK + */ + int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const unsigned char *d, long len); + + #ifdef __cplusplus } #endif diff --git a/components/openssl/include/internal/ssl_x509.h b/components/openssl/include/internal/ssl_x509.h index b5fea34f1a..840fbf1ec1 100644 --- a/components/openssl/include/internal/ssl_x509.h +++ b/components/openssl/include/internal/ssl_x509.h @@ -87,6 +87,20 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); */ int SSL_add_client_CA(SSL *ssl, X509 *x); +/** + * @brief load certification into the SSL + * + * @param ssl - SSL point + * @param len - data bytes + * @param d - data point + * + * @return result + * 0 : failed + * 1 : OK + * + */ +int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + #ifdef __cplusplus } #endif diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index 3e8e88e67c..1d115214fd 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -21,6 +21,7 @@ #include "platform/ssl_port.h" #include "internal/ssl_x509.h" +#include "internal/ssl_pkey.h" /* { @@ -426,6 +427,26 @@ const char *SSL_get_version(const SSL *ssl); */ int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); +/** + * @brief get the bytes numbers which are to be read + * + * @param ssl - SSL point + * + * @return bytes number + */ +int SSL_pending(const SSL *ssl); + +/** + * @brief check if SSL want nothing + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_nothing(const SSL *ssl); + /** * @brief get the SSL context current method * From 6941b5871a73086786191a9d73a21d8c64dbec82 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 27 Sep 2016 18:52:31 +0800 Subject: [PATCH 33/95] components/openssl: add OpenSSL APIs description --- components/openssl/OpenSSL_APIs.rst | 688 ++++++++++++++++++++++++++++ 1 file changed, 688 insertions(+) create mode 100644 components/openssl/OpenSSL_APIs.rst diff --git a/components/openssl/OpenSSL_APIs.rst b/components/openssl/OpenSSL_APIs.rst new file mode 100644 index 0000000000..e130d8398b --- /dev/null +++ b/components/openssl/OpenSSL_APIs.rst @@ -0,0 +1,688 @@ +OpenSSL APIs +====================== + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the SSLV2.3 version SSL context client method + */ +const SSL_METHOD* SSLv23_client_method(void); + + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.0 version SSL context client method + */ +const SSL_METHOD* TLSv1_client_method(void); + + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the SSLV1.0 version SSL context client method + */ +const SSL_METHOD* SSLv3_client_method(void); + + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.1 version SSL context client method + */ +const SSL_METHOD* TLSv1_1_client_method(void); + + +/** + * @brief create the target SSL context client method + * + * @param none + * + * @return the TLSV1.2 version SSL context client method + */ +const SSL_METHOD* TLSv1_2_client_method(void); + + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the SSLV2.3 version SSL context server method + */ +const SSL_METHOD* SSLv23_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.1 version SSL context server method + */ +const SSL_METHOD* TLSv1_1_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.2 version SSL context server method + */ +const SSL_METHOD* TLSv1_2_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the TLSV1.0 version SSL context server method + */ +const SSL_METHOD* TLSv1_server_method(void); + +/** + * @brief create the target SSL context server method + * + * @param none + * + * @return the SSLV3.0 version SSL context server method + */ +const SSL_METHOD* SSLv3_server_method(void); + +/** + * @brief create a SSL context + * + * @param method - the SSL context method point + * + * @return the context point + */ +SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); + +/** + * @brief free a SSL context + * + * @param method - the SSL context point + * + * @return none + */ +void SSL_CTX_free(SSL_CTX *ctx); + +/** + * @brief set the SSL context version + * + * @param ctx - SSL context point + * @param meth - SSL method point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + +/** + * @brief get the SSL context current method + * + * @param ctx - SSL context point + * + * @return the SSL context current method + */ +const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); + +/** + * @brief create a SSL + * + * @param ctx - the SSL context point + * + * @return the SSL point + */ +SSL* SSL_new(SSL_CTX *ctx); + +/** + * @brief free the SSL + * + * @param ssl - the SSL point + * + * @return none + */ +void SSL_free(SSL *ssl); + +/** + * @brief perform the SSL handshake + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + * -1 : a error catch + */ +int SSL_do_handshake(SSL *ssl); + +/** + * @brief connect to the remote SSL server + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * -1 : failed + */ +int SSL_connect(SSL *ssl); + +/** + * @brief accept the remote connection + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * -1 : failed + */ +int SSL_accept(SSL *ssl); + +/** + * @brief shutdown the connection + * + * @param ssl - the SSL point + * + * @return result + * 1 : OK + * 0 : shutdown is not finished + * -1 : an error catch + */ +int SSL_shutdown(SSL *ssl); + +/** + * @brief reset the SSL + * + * @param ssl - SSL point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_clear(SSL *ssl); + +/** + * @brief read data from to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the received data buffer point + * @param len - the received data length + * + * @return result + * > 0 : OK, and return received data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_read(SSL *ssl, void *buffer, int len); + +/** + * @brief send the data to remote + * + * @param ssl - the SSL point which has been connected + * @param buffer - the send data buffer point + * @param len - the send data length + * + * @return result + * > 0 : OK, and return sent data bytes + * = 0 : connection is closed + * < 0 : an error catch + */ +int SSL_write(SSL *ssl, const void *buffer, int len); + +/** + * @brief get SSL context of the SSL + * + * @param ssl - SSL point + * + * @return SSL context + */ +SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); + +/** + * @brief get SSL shutdown mode + * + * @param ssl - SSL point + * + * @return shutdown mode + */ +int SSL_get_shutdown(const SSL *ssl); + +/** + * @brief set SSL shutdown mode + * + * @param ssl - SSL point + * @param mode - shutdown mode + * + * @return none + */ +void SSL_set_shutdown(SSL *ssl, int mode); + +/** + * @brief get the SSL current method + * + * @param ssl - SSL point + * + * @return the SSL current method + */ +const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); + +/** + * @brief set the SSL method + * + * @param ssl - SSL point + * @param meth - SSL method point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); + +/** + * @brief get the bytes numbers which are to be read + * + * @param ssl - SSL point + * + * @return bytes number + */ +int SSL_pending(const SSL *ssl); + +/** + * @brief check if some data can be read + * + * @param ssl - SSL point + * + * @return + * 1 : there are bytes to be read + * 0 : no data + */ +int SSL_has_pending(const SSL *ssl); + +/** + * @brief get the socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_fd(const SSL *ssl); + +/** + * @brief get the read only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_rfd(const SSL *ssl); + +/** + * @brief get the write only socket handle of the SSL + * + * @param ssl - SSL point + * + * @return result + * >= 0 : yes, and return socket handle + * < 0 : a error catch + */ +int SSL_get_wfd(const SSL *ssl); + +/** + * @brief bind the socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_fd(SSL *ssl, int fd); + +/** + * @brief bind the read only socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_rfd(SSL *ssl, int fd); + +/** + * @brief bind the write only socket file description into the SSL + * + * @param ssl - the SSL point + * @param fd - socket handle + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_set_wfd(SSL *ssl, int fd); + +/** + * @brief get SSL version + * + * @param ssl - SSL point + * + * @return SSL version + */ +int SSL_version(const SSL *ssl); + +/** + * @brief get the SSL current version + * + * @param ssl - SSL point + * + * @return the version string + */ +const char *SSL_get_version(const SSL *ssl); + +/** + * @brief get the SSL state + * + * @param ssl - SSL point + * + * @return SSL state + */ +OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); + +/** + * @brief get alert description string + * + * @param value - alert value + * + * @return alert description string + */ +const char *SSL_alert_desc_string(int value); + +/** + * @brief get alert description long string + * + * @param value - alert value + * + * @return alert description long string + */ +const char *SSL_alert_desc_string_long(int value); + +/** + * @brief get alert type string + * + * @param value - alert value + * + * @return alert type string + */ +const char *SSL_alert_type_string(int value); + +/** + * @brief get alert type long string + * + * @param value - alert value + * + * @return alert type long string + */ +const char *SSL_alert_type_string_long(int value); + +/** + * @brief get the state string where SSL is reading + * + * @param ssl - SSL point + * + * @return state string + */ +const char *SSL_rstate_string(SSL *ssl); + +/** + * @brief get the statement long string where SSL is reading + * + * @param ssl - SSL point + * + * @return statement long string + */ +const char *SSL_rstate_string_long(SSL *ssl); + +/** + * @brief get SSL statement string + * + * @param ssl - SSL point + * + * @return SSL statement string + */ +char *SSL_state_string(const SSL *ssl); + +/** + * @brief get SSL statement long string + * + * @param ssl - SSL point + * + * @return SSL statement long string + */ +char *SSL_state_string_long(const 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 load a character certification context into system context. If '*cert' is pointed to the + * certification, then load certification into it. Or create a new X509 certification object + * + * @param cert - a point pointed to X509 certification + * @param buffer - a point pointed to the certification context memory point + * @param length - certification bytes + * + * @return X509 certification object point + */ +X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); + +/** + * @brief add CA client certification into the SSL + * + * @param ssl - SSL point + * @param x - CA certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_add_client_CA(SSL *ssl, X509 *x); + +/** + * @brief add CA client certification into the SSL context + * + * @param ctx - SSL context point + * @param x - CA certification point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + +/** + * @brief get the SSL certification point + * + * @param ssl - SSL point + * + * @return SSL certification point + */ +X509 *SSL_get_certificate(const SSL *ssl); + +/** + * @brief get the verifying result of the SSL certification + * + * @param ssl - the SSL point + * + * @return the result of verifying + */ +long SSL_get_verify_result(const SSL *ssl); + +/** + * @brief These functions load the certification into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - certification object point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); + +/** + * @brief load the ASN1 certification into SSL context + * + * @param ctx - SSL context point + * @param len - certification length + * @param d - data point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); + +/** + * @brief These functions load the private key into the SSL_CTX or SSL object + * + * @param ctx - the SSL context point + * @param pkey - private key object point + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + +/** + * @brief load the ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - private key length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); + +/** + * @brief load the RSA ASN1 private key into SSL context + * + * @param ctx - SSL context point + * @param d - data point + * @param len - RSA private key length + * + * @return result + * 1 : OK + * 0 : failed + */ +int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); + +/** + * @brief load certification into the SSL + * + * @param ssl - SSL point + * @param len - data bytes + * @param d - data point + * + * @return result + * 0 : failed + * 1 : OK + * + */ +int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + +/** + * @brief get peer certification + * + * @param ssl - SSL point + * + * @return certification + */ +X509 *SSL_get_peer_certificate(const SSL *ssl); + +/** + * @brief set the SSL context read buffer length + * + * @param ctx - SSL context point + * @param len - read buffer length + * + * @return none + */ +void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); + +/** + * @brief set the SSL read buffer length + * + * @param ssl - SSL point + * @param len - read buffer length + * + * @return none + */ +void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); + +/** + * @brief get the SSL specifical statement + * + * @param ssl - SSL point + * + * @return specifical statement + */ +int SSL_want(const SSL *ssl); + +/** + * @brief check if SSL want nothing + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_nothing(const SSL *ssl); + +/** + * @brief check if SSL want to read + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_read(const SSL *ssl); + +/** + * @brief check if SSL want to write + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_write(const SSL *ssl); From 9e20d31f898ef561c908d3db14887a8e68dd9bb4 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 27 Sep 2016 19:06:07 +0800 Subject: [PATCH 34/95] components/openssl: fix extra certification loading --- components/openssl/platform/ssl_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 9df8b6481e..4bc631382f 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -186,7 +186,7 @@ static int ssl_pm_reload_crt(SSL *ssl) if (ca_pm->x509_crt) { mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL); } else if (ca_pm->ex_crt) { - mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->x509_crt, NULL); + mbedtls_ssl_conf_ca_chain(&ssl_pm->conf, ca_pm->ex_crt, NULL); } if (crt_pm->x509_crt && pkey_pm->pkey) { From 9c4e43a3a5becc441642edbbbf06b90a06bfa5eb Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 28 Sep 2016 16:46:27 +0800 Subject: [PATCH 35/95] components/openssl: optimize the OpenSSL APIs brief document 1. change document name 2. change function introduction template --- components/openssl/OpenSSL-APIs.rst | 1478 +++++++++++++++++++++++++++ components/openssl/OpenSSL_APIs.rst | 688 ------------- 2 files changed, 1478 insertions(+), 688 deletions(-) create mode 100644 components/openssl/OpenSSL-APIs.rst delete mode 100644 components/openssl/OpenSSL_APIs.rst diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst new file mode 100644 index 0000000000..ff91d2ebb7 --- /dev/null +++ b/components/openssl/OpenSSL-APIs.rst @@ -0,0 +1,1478 @@ +OpenSSL-APIs +====================== + +Chapter 1. SSL Context Method Create +Chapter 2. SSL Context Fucntion +Chapter 3. SSL Fucntion +Chapter 4. SSL X509 Certification and Private Key Function + +====================== +Chapter 1. SSL Context Method Create + +1.1 const SSL_METHOD* SSLv23_client_method(void); + + Arguments : none + + Return : SSLV2 and 3 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv23_client_method(); + + ... + } + + +1.2 const SSL_METHOD* TLSv1_client_method(void); + + Arguments : none + + Return : TLSV1.0 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_client_method(); + + ... + } + + +1.3 const SSL_METHOD* SSLv3_client_method(void); + + Arguments : none + + Return : SSLV3.0 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv3_client_method(); + + ... + } + + +1.4 const SSL_METHOD* TLSv1_1_client_method(void); + + Arguments : none + + Return : TLSV1.1 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_client_method(); + + ... + } + + +1.5 const SSL_METHOD* TLSv1_2_client_method(void); + + Arguments : none + + Return : TLSV1.2 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_client_method(); + + ... + } + + +1.6 const SSL_METHOD* SSLv23_server_method(void); + + Arguments : none + + Return : SSLV2 and 3 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv23_server_method(); + + ... + } + + +1.7 const SSL_METHOD* TLSv1_1_server_method(void); + + Arguments : none + + Return : TLSV1.1 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_server_method(); + + ... + } + + +1.8 const SSL_METHOD* TLSv1_2_server_method(void); + + Arguments : none + + Return : TLSV1.2 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_server_method(); + + ... + } + + +1.9 const SSL_METHOD* TLSv1_server_method(void); + + Arguments : none + + Return : TLSV1.0 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_server_method(); + + ... + } + + +1.10 const SSL_METHOD* SSLv3_server_method(void); + + Arguments : none + + Return : SSLV3.0 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv3_server_method(); + + ... + } + + +====================== +Chapter 2. SSL Context Fucntion + +2.1 SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); + + Arguments : method - the SSL context method point + + Return : context point + + Description : create a SSL context + + Example : + + void example(void) + { + SSL_CTX *ctx = SSL_CTX_new(SSLv3_server_method()); + + ... + } + + +2.2 void SSL_CTX_free(SSL_CTX *ctx); + + Arguments : ctx - the SSL context point + + Return : none + + Description : free a SSL context + + Example : + + void example(void) + { + SSL_CTX *ctx; + + ... ... + + SSL_CTX_free(ctx); + } + + +2.3 int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + + Arguments : ctx - SSL context point + meth - SSL method point + + Return : result + 1 : OK + 0 : failed + + Description : set the SSL context version + + Example : + + void example(void) + { + SSL_CTX *ctx; + const SSL_METHOD *meth; + + ... ... + + SSL_CTX_set_ssl_version(ctx, meth); + } + + +2.4 const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); + + Arguments : ctx - SSL context point + + Return : SSL context method + + Description : get the SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method; + SSL_CTX *ctx; + + ... ... + + method = SSL_CTX_get_ssl_method(ctx); + } + + +====================== +Chapter 3. SSL Fucntion + +3.1 SSL* SSL_new(SSL_CTX *ctx); + + Arguments : ctx - SSL context point + + Return : SSL method + + Description : create a SSL + + Example : + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ssl = SSL_new(ctx); + } + + +3.2 void SSL_free(SSL *ssl); + + Arguments : ssl - SSL point + + Return : none + + Description : free SSL + + Example : + + void example(void) + { + SSL *ssl; + + ... ... + + SSL_free(ssl); + } + + +3.3 int SSL_do_handshake(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : perform the SSL handshake + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_do_handshake(ssl); + } + + +3.4 int SSL_connect(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : connect to the remote SSL server + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_connect(ssl); + } + + +3.5 int SSL_accept(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : accept the remote connection + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_accept(ssl); + } + + +3.6 int SSL_shutdown(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : shutdown the connection + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_shutdown(ssl); + } + + +3.7 int SSL_clear(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed + + Description : shutdown the connection + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_clear(ssl); + } + + +3.8 int SSL_read(SSL *ssl, void *buffer, int len); + + Arguments : ssl - point + buffer - data buffer point + len - data length + + Return : result + > 0 : OK, and return received data bytes + = 0 : no data received or connection is closed + < 0 : an error catch + + Description : read data from remote + + Example : + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_read(ssl, buf, len); + } + +3.9 int SSL_write(SSL *ssl, const void *buffer, int len); + + Arguments : ssl - SSL point + buffer - data buffer point + len - data length + + Return : result + > 0 : OK, and return received data bytes + = 0 : no data sent or connection is closed + < 0 : an error catch + + Description : send the data to remote + + Example : + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_write(ssl, buf, len); + } + + +3.10 SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL context + + Description : get SSL context of the SSL + + Example : + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ctx = SSL_get_SSL_CTX(ssl); + } + + +3.11 int SSL_get_shutdown(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : shutdown mode + + Description : get SSL shutdown mode + + Example : + + void example(void) + { + SSL *ssl; + int mode; + + ... ... + + mode = SSL_get_SSL_CTX(ssl); + } + + +3.12 void SSL_set_shutdown(SSL *ssl, int mode); + + Arguments : ssl - SSL point + + Return : shutdown mode + + Description : set SSL shutdown mode + + Example : + + void example(void) + { + SSL *ssl; + int mode = 0; + + ... ... + + SSL_set_shutdown(ssl, mode); + } + + +3.13 const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL method + + Description : set SSL shutdown mode + + Example : + + void example(void) + { + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + method = SSL_get_ssl_method(ssl); + } + + +3.14 int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); + + Arguments : ssl - SSL point + meth - SSL method point + + Return : result + 1 : OK + 0 : failed + + Description : set the SSL method + + Example : + + void example(void) + { + int ret; + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + ret = SSL_set_ssl_method(ssl, method); + } + + +3.15 int SSL_pending(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : data bytes + + Description : get received data bytes + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_pending(ssl); + } + + +3.16 int SSL_has_pending(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : Yes + 0 : No + + Description : check if data is received + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_has_pending(ssl); + } + + +3.17 int SSL_get_fd(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + >= 0 : socket id + < 0 : a error catch + + Description : get the socket of the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_fd(ssl); + } + + +3.18 int SSL_get_rfd(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + >= 0 : socket id + < 0 : a error catch + + Description : get the read only socket of the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_rfd(ssl); + } + + +3.19 int SSL_get_wfd(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + >= 0 : socket id + < 0 : a error catch + + Description : get the write only socket of the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_wfd(ssl); + } + + +3.20 int SSL_set_fd(SSL *ssl, int fd); + + Arguments : ssl - SSL point + fd - socket id + + Return : result + 1 : OK + 0 : failed + + Description : set socket to SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_fd(ssl, socket); + } + + +3.21 int SSL_set_rfd(SSL *ssl, int fd); + + Arguments : ssl - SSL point + fd - socket id + + Return : result + 1 : OK + 0 : failed + + Description : set read only socket to SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_rfd(ssl, socket); + } + + +3.22 int SSL_set_wfd(SSL *ssl, int fd); + + Arguments : ssl - SSL point + fd - socket id + + Return : result + 1 : OK + 0 : failed + + Description : set write only socket to SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_wfd(ssl, socket); + } + + +3.23 int SSL_version(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL version + + Description : get SSL version + + Example : + + void example(void) + { + int version; + SSL *ssl; + + ... ... + + version = SSL_version(ssl); + } + + +3.24 const char *SSL_get_version(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL version string + + Description : get the SSL current version string + + Example : + + void example(void) + { + char *version; + SSL *ssl; + + ... ... + + version = SSL_get_version(ssl); + } + + +3.25 OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL state + + Description : get the SSL state + + Example : + + void example(void) + { + OSSL_HANDSHAKE_STATE state; + SSL *ssl; + + ... ... + + state = SSL_get_state(ssl); + } + + +3.26 const char *SSL_alert_desc_string(int value); + + Arguments : value - SSL description + + Return : alert value string + + Description : get alert description string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string(val); + } + + +3.27 const char *SSL_alert_desc_string_long(int value); + + Arguments : value - SSL description + + Return : alert value long string + + Description : get alert description long string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string_long(val); + } + + +3.28 const char *SSL_alert_type_string(int value); + + Arguments : value - SSL type description + + Return : alert type string + + Description : get alert type string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string(val); + } + + +3.29 const char *SSL_alert_type_string_long(int value); + + Arguments : value - SSL type description + + Return : alert type long string + + Description : get alert type long string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string_long(val); + } + +3.30 const char *SSL_rstate_string(SSL *ssl); + + Arguments : ssl - SSL point + + Return : state string + + Description : get the state string where SSL is reading + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string(ssl); + } + + +3.31 const char *SSL_rstate_string_long(SSL *ssl); + + Arguments : ssl - SSL point + + Return : state long string + + Description : get the state long string where SSL is reading + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string_long(ssl); + } + + +3.32 char *SSL_state_string(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : state string + + Description : get the state string + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.33 char *SSL_state_string_long(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : state long string + + Description : get the state long string + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.34 int SSL_get_error(const SSL *ssl, int ret_code); + + Arguments : ssl - SSL point + ret_code - SSL return code + + Return : SSL error number + + Description : get SSL error code + + Example : + + void example(void) + { + SSL *ssl; + int ret; + int err; + + ... ... + + err = SSL_get_error(ssl, ret); + } + +3.35 void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); + + Arguments : ctx - SSL context point + len - read buffer length + + Return : none + + Description : set the SSL context read buffer length + + Example : + + void example(void) + { + SSL_CTX *ctx; + size_t len; + + ... ... + + SSL_CTX_set_default_read_buffer_len(ctx, len); + } + + +3.36 void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); + + Arguments : ssl - SSL point + len - read buffer length + + Return : none + + Description : set the SSL read buffer length + + Example : + + void example(void) + { + SSL *ssl; + size_t len; + + ... ... + + SSL_set_default_read_buffer_len(ctx, len); + } + + +3.37 int SSL_want(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : specifical statement + + Description : get the SSL specifical statement + + Example : + + void example(void) + { + SSL *ssl; + int state; + + ... ... + + state = SSL_want(ssl); + } + + +3.38 int SSL_want_nothing(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 0 : false + 1 : true + + Description : check if SSL want nothing + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want(ssl); + } + + +3.39 int SSL_want_read(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 0 : false + 1 : true + + Description : check if SSL want to read + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_read(ssl); + } + + +3.40 int SSL_want_write(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 0 : false + 1 : true + + Description : check if SSL want to write + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_write(ssl); + } + +====================== +Chapter 4. SSL X509 Certification and Private Key Function + +4.1 X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); + + Arguments : cert - a point pointed to X509 certification + buffer - a point pointed to the certification context memory point + length - certification bytes + + Return : X509 certification object point + + Description : load a character certification context into system context. If '*cert' is pointed to the + certification, then load certification into it. Or create a new X509 certification object + + Example : + + void example(void) + { + X509 *new; + X509 *cert; + unsigned char *buffer; + long len; + ... ... + + new = d2i_X509(&cert, buffer, len); + } + + +4.2 int SSL_add_client_CA(SSL *ssl, X509 *x); + + Arguments : ssl - SSL point + x - CA certification point + + Return : result + 1 : OK + 0 : failed + + Description : add CA client certification into the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + X509 *new; + + ... ... + + ret = SSL_add_client_CA(ssl, new); + } + + +4.3 int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + + Arguments : ctx - SSL context point + x - CA certification point + + Return : result + 1 : OK + 0 : failed + + Description : add CA client certification into the SSL context + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + X509 *new; + + ... ... + + ret = SSL_add_clSSL_CTX_add_client_CAient_CA(ctx, new); + } + + +4.4 X509 *SSL_get_certificate(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL certification point + + Description : get the SSL certification point + + Example : + + void example(void) + { + SSL *ssl; + X509 *cert; + + ... ... + + cert = SSL_get_certificate(ssl); + } + + +4.5 long SSL_get_verify_result(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : the result of verifying + + Description : get the verifying result of the SSL certification + + Example : + + void example(void) + { + SSL *ssl; + long ret; + + ... ... + + ret = SSL_get_verify_result(ssl); + } + + +4.6 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); + + Arguments : ctx - the SSL context point + pkey - certification object point + + Return : result + 1 : OK + 0 : failed + + Description : load the certification into the SSL_CTX or SSL object + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx + X509 *new; + + ... ... + + ret = SSL_CTX_use_certificate(ctx, new); + } + + +4.7 int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); + + Arguments : ctx - SSL context point + len - certification length + d - data point + + Return : result + 1 : OK + 0 : failed + + Description : load the ASN1 certification into SSL context + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + int len; + + ... ... + + ret = SSL_CTX_use_certificate_ASN1(ctx, len, buf); + } + + +4.8 int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + + Arguments : ctx - SSL context point + pkey - private key object point + + Return : result + 1 : OK + 0 : failed + + Description : load the private key into the context object + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + EVP_PKEY *pkey; + + ... ... + + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + } + + +4.9 int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); + + Arguments : ctx - SSL context point + d - data point + len - private key length + + Return : result + 1 : OK + 0 : failed + + Description : load the ASN1 private key into SSL context + + Example : + + void example(void) + { + int ret; + int pk; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_PrivateKey_ASN1(pk, ctx, buf, len); + } + + +4.10 int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); + + Arguments : ctx - SSL context point + d - data point + len - private key length + + Return : result + 1 : OK + 0 : failed + + Description : load the RSA ASN1 private key into SSL context + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_RSAPrivateKey_ASN1(ctx, buf, len); + } + + +4.11 int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + + Arguments : ssl - SSL point + len - data bytes + d - data point + + Return : result + 1 : OK + 0 : failed + + Description : load certification into the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_use_certificate_ASN1(ssl, len, buf); + } + + +4.12 X509 *SSL_get_peer_certificate(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : peer certification + + Description : get peer certification + + Example : + + void example(void) + { + SSL *ssl; + X509 *peer; + + ... ... + + peer = SSL_get_peer_certificate(ssl); + } + +====================== +END \ No newline at end of file diff --git a/components/openssl/OpenSSL_APIs.rst b/components/openssl/OpenSSL_APIs.rst deleted file mode 100644 index e130d8398b..0000000000 --- a/components/openssl/OpenSSL_APIs.rst +++ /dev/null @@ -1,688 +0,0 @@ -OpenSSL APIs -====================== - -/** - * @brief create the target SSL context client method - * - * @param none - * - * @return the SSLV2.3 version SSL context client method - */ -const SSL_METHOD* SSLv23_client_method(void); - - -/** - * @brief create the target SSL context client method - * - * @param none - * - * @return the TLSV1.0 version SSL context client method - */ -const SSL_METHOD* TLSv1_client_method(void); - - -/** - * @brief create the target SSL context client method - * - * @param none - * - * @return the SSLV1.0 version SSL context client method - */ -const SSL_METHOD* SSLv3_client_method(void); - - -/** - * @brief create the target SSL context client method - * - * @param none - * - * @return the TLSV1.1 version SSL context client method - */ -const SSL_METHOD* TLSv1_1_client_method(void); - - -/** - * @brief create the target SSL context client method - * - * @param none - * - * @return the TLSV1.2 version SSL context client method - */ -const SSL_METHOD* TLSv1_2_client_method(void); - - -/** - * @brief create the target SSL context server method - * - * @param none - * - * @return the SSLV2.3 version SSL context server method - */ -const SSL_METHOD* SSLv23_server_method(void); - -/** - * @brief create the target SSL context server method - * - * @param none - * - * @return the TLSV1.1 version SSL context server method - */ -const SSL_METHOD* TLSv1_1_server_method(void); - -/** - * @brief create the target SSL context server method - * - * @param none - * - * @return the TLSV1.2 version SSL context server method - */ -const SSL_METHOD* TLSv1_2_server_method(void); - -/** - * @brief create the target SSL context server method - * - * @param none - * - * @return the TLSV1.0 version SSL context server method - */ -const SSL_METHOD* TLSv1_server_method(void); - -/** - * @brief create the target SSL context server method - * - * @param none - * - * @return the SSLV3.0 version SSL context server method - */ -const SSL_METHOD* SSLv3_server_method(void); - -/** - * @brief create a SSL context - * - * @param method - the SSL context method point - * - * @return the context point - */ -SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); - -/** - * @brief free a SSL context - * - * @param method - the SSL context point - * - * @return none - */ -void SSL_CTX_free(SSL_CTX *ctx); - -/** - * @brief set the SSL context version - * - * @param ctx - SSL context point - * @param meth - SSL method point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); - -/** - * @brief get the SSL context current method - * - * @param ctx - SSL context point - * - * @return the SSL context current method - */ -const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); - -/** - * @brief create a SSL - * - * @param ctx - the SSL context point - * - * @return the SSL point - */ -SSL* SSL_new(SSL_CTX *ctx); - -/** - * @brief free the SSL - * - * @param ssl - the SSL point - * - * @return none - */ -void SSL_free(SSL *ssl); - -/** - * @brief perform the SSL handshake - * - * @param ssl - SSL point - * - * @return result - * 1 : OK - * 0 : failed - * -1 : a error catch - */ -int SSL_do_handshake(SSL *ssl); - -/** - * @brief connect to the remote SSL server - * - * @param ssl - the SSL point - * - * @return result - * 1 : OK - * -1 : failed - */ -int SSL_connect(SSL *ssl); - -/** - * @brief accept the remote connection - * - * @param ssl - the SSL point - * - * @return result - * 1 : OK - * -1 : failed - */ -int SSL_accept(SSL *ssl); - -/** - * @brief shutdown the connection - * - * @param ssl - the SSL point - * - * @return result - * 1 : OK - * 0 : shutdown is not finished - * -1 : an error catch - */ -int SSL_shutdown(SSL *ssl); - -/** - * @brief reset the SSL - * - * @param ssl - SSL point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_clear(SSL *ssl); - -/** - * @brief read data from to remote - * - * @param ssl - the SSL point which has been connected - * @param buffer - the received data buffer point - * @param len - the received data length - * - * @return result - * > 0 : OK, and return received data bytes - * = 0 : connection is closed - * < 0 : an error catch - */ -int SSL_read(SSL *ssl, void *buffer, int len); - -/** - * @brief send the data to remote - * - * @param ssl - the SSL point which has been connected - * @param buffer - the send data buffer point - * @param len - the send data length - * - * @return result - * > 0 : OK, and return sent data bytes - * = 0 : connection is closed - * < 0 : an error catch - */ -int SSL_write(SSL *ssl, const void *buffer, int len); - -/** - * @brief get SSL context of the SSL - * - * @param ssl - SSL point - * - * @return SSL context - */ -SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); - -/** - * @brief get SSL shutdown mode - * - * @param ssl - SSL point - * - * @return shutdown mode - */ -int SSL_get_shutdown(const SSL *ssl); - -/** - * @brief set SSL shutdown mode - * - * @param ssl - SSL point - * @param mode - shutdown mode - * - * @return none - */ -void SSL_set_shutdown(SSL *ssl, int mode); - -/** - * @brief get the SSL current method - * - * @param ssl - SSL point - * - * @return the SSL current method - */ -const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); - -/** - * @brief set the SSL method - * - * @param ssl - SSL point - * @param meth - SSL method point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); - -/** - * @brief get the bytes numbers which are to be read - * - * @param ssl - SSL point - * - * @return bytes number - */ -int SSL_pending(const SSL *ssl); - -/** - * @brief check if some data can be read - * - * @param ssl - SSL point - * - * @return - * 1 : there are bytes to be read - * 0 : no data - */ -int SSL_has_pending(const SSL *ssl); - -/** - * @brief get the socket handle of the SSL - * - * @param ssl - SSL point - * - * @return result - * >= 0 : yes, and return socket handle - * < 0 : a error catch - */ -int SSL_get_fd(const SSL *ssl); - -/** - * @brief get the read only socket handle of the SSL - * - * @param ssl - SSL point - * - * @return result - * >= 0 : yes, and return socket handle - * < 0 : a error catch - */ -int SSL_get_rfd(const SSL *ssl); - -/** - * @brief get the write only socket handle of the SSL - * - * @param ssl - SSL point - * - * @return result - * >= 0 : yes, and return socket handle - * < 0 : a error catch - */ -int SSL_get_wfd(const SSL *ssl); - -/** - * @brief bind the socket file description into the SSL - * - * @param ssl - the SSL point - * @param fd - socket handle - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_set_fd(SSL *ssl, int fd); - -/** - * @brief bind the read only socket file description into the SSL - * - * @param ssl - the SSL point - * @param fd - socket handle - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_set_rfd(SSL *ssl, int fd); - -/** - * @brief bind the write only socket file description into the SSL - * - * @param ssl - the SSL point - * @param fd - socket handle - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_set_wfd(SSL *ssl, int fd); - -/** - * @brief get SSL version - * - * @param ssl - SSL point - * - * @return SSL version - */ -int SSL_version(const SSL *ssl); - -/** - * @brief get the SSL current version - * - * @param ssl - SSL point - * - * @return the version string - */ -const char *SSL_get_version(const SSL *ssl); - -/** - * @brief get the SSL state - * - * @param ssl - SSL point - * - * @return SSL state - */ -OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); - -/** - * @brief get alert description string - * - * @param value - alert value - * - * @return alert description string - */ -const char *SSL_alert_desc_string(int value); - -/** - * @brief get alert description long string - * - * @param value - alert value - * - * @return alert description long string - */ -const char *SSL_alert_desc_string_long(int value); - -/** - * @brief get alert type string - * - * @param value - alert value - * - * @return alert type string - */ -const char *SSL_alert_type_string(int value); - -/** - * @brief get alert type long string - * - * @param value - alert value - * - * @return alert type long string - */ -const char *SSL_alert_type_string_long(int value); - -/** - * @brief get the state string where SSL is reading - * - * @param ssl - SSL point - * - * @return state string - */ -const char *SSL_rstate_string(SSL *ssl); - -/** - * @brief get the statement long string where SSL is reading - * - * @param ssl - SSL point - * - * @return statement long string - */ -const char *SSL_rstate_string_long(SSL *ssl); - -/** - * @brief get SSL statement string - * - * @param ssl - SSL point - * - * @return SSL statement string - */ -char *SSL_state_string(const SSL *ssl); - -/** - * @brief get SSL statement long string - * - * @param ssl - SSL point - * - * @return SSL statement long string - */ -char *SSL_state_string_long(const 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 load a character certification context into system context. If '*cert' is pointed to the - * certification, then load certification into it. Or create a new X509 certification object - * - * @param cert - a point pointed to X509 certification - * @param buffer - a point pointed to the certification context memory point - * @param length - certification bytes - * - * @return X509 certification object point - */ -X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); - -/** - * @brief add CA client certification into the SSL - * - * @param ssl - SSL point - * @param x - CA certification point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_add_client_CA(SSL *ssl, X509 *x); - -/** - * @brief add CA client certification into the SSL context - * - * @param ctx - SSL context point - * @param x - CA certification point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); - -/** - * @brief get the SSL certification point - * - * @param ssl - SSL point - * - * @return SSL certification point - */ -X509 *SSL_get_certificate(const SSL *ssl); - -/** - * @brief get the verifying result of the SSL certification - * - * @param ssl - the SSL point - * - * @return the result of verifying - */ -long SSL_get_verify_result(const SSL *ssl); - -/** - * @brief These functions load the certification into the SSL_CTX or SSL object - * - * @param ctx - the SSL context point - * @param pkey - certification object point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); - -/** - * @brief load the ASN1 certification into SSL context - * - * @param ctx - SSL context point - * @param len - certification length - * @param d - data point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); - -/** - * @brief These functions load the private key into the SSL_CTX or SSL object - * - * @param ctx - the SSL context point - * @param pkey - private key object point - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); - -/** - * @brief load the ASN1 private key into SSL context - * - * @param ctx - SSL context point - * @param d - data point - * @param len - private key length - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); - -/** - * @brief load the RSA ASN1 private key into SSL context - * - * @param ctx - SSL context point - * @param d - data point - * @param len - RSA private key length - * - * @return result - * 1 : OK - * 0 : failed - */ -int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); - -/** - * @brief load certification into the SSL - * - * @param ssl - SSL point - * @param len - data bytes - * @param d - data point - * - * @return result - * 0 : failed - * 1 : OK - * - */ -int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); - -/** - * @brief get peer certification - * - * @param ssl - SSL point - * - * @return certification - */ -X509 *SSL_get_peer_certificate(const SSL *ssl); - -/** - * @brief set the SSL context read buffer length - * - * @param ctx - SSL context point - * @param len - read buffer length - * - * @return none - */ -void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); - -/** - * @brief set the SSL read buffer length - * - * @param ssl - SSL point - * @param len - read buffer length - * - * @return none - */ -void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); - -/** - * @brief get the SSL specifical statement - * - * @param ssl - SSL point - * - * @return specifical statement - */ -int SSL_want(const SSL *ssl); - -/** - * @brief check if SSL want nothing - * - * @param ssl - SSL point - * - * @return result - * 0 : false - * 1 : true - */ -int SSL_want_nothing(const SSL *ssl); - -/** - * @brief check if SSL want to read - * - * @param ssl - SSL point - * - * @return result - * 0 : false - * 1 : true - */ -int SSL_want_read(const SSL *ssl); - -/** - * @brief check if SSL want to write - * - * @param ssl - SSL point - * - * @return result - * 0 : false - * 1 : true - */ -int SSL_want_write(const SSL *ssl); From 1bcc5438ec51e3755b4fe98e18891e96335e1a57 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 28 Sep 2016 19:40:05 +0800 Subject: [PATCH 36/95] components/openssl: fix .rst file encoding type --- components/openssl/OpenSSL-APIs.rst | 2965 ++++++++++++++------------- 1 file changed, 1487 insertions(+), 1478 deletions(-) diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst index ff91d2ebb7..5a44794cd2 100644 --- a/components/openssl/OpenSSL-APIs.rst +++ b/components/openssl/OpenSSL-APIs.rst @@ -1,1478 +1,1487 @@ -OpenSSL-APIs -====================== - -Chapter 1. SSL Context Method Create -Chapter 2. SSL Context Fucntion -Chapter 3. SSL Fucntion -Chapter 4. SSL X509 Certification and Private Key Function - -====================== -Chapter 1. SSL Context Method Create - -1.1 const SSL_METHOD* SSLv23_client_method(void); - - Arguments : none - - Return : SSLV2 and 3 version SSL context client method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = SSLv23_client_method(); - - ... - } - - -1.2 const SSL_METHOD* TLSv1_client_method(void); - - Arguments : none - - Return : TLSV1.0 version SSL context client method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = TLSv1_client_method(); - - ... - } - - -1.3 const SSL_METHOD* SSLv3_client_method(void); - - Arguments : none - - Return : SSLV3.0 version SSL context client method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = SSLv3_client_method(); - - ... - } - - -1.4 const SSL_METHOD* TLSv1_1_client_method(void); - - Arguments : none - - Return : TLSV1.1 version SSL context client method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = TLSv1_1_client_method(); - - ... - } - - -1.5 const SSL_METHOD* TLSv1_2_client_method(void); - - Arguments : none - - Return : TLSV1.2 version SSL context client method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = TLSv1_2_client_method(); - - ... - } - - -1.6 const SSL_METHOD* SSLv23_server_method(void); - - Arguments : none - - Return : SSLV2 and 3 version SSL context server method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = SSLv23_server_method(); - - ... - } - - -1.7 const SSL_METHOD* TLSv1_1_server_method(void); - - Arguments : none - - Return : TLSV1.1 version SSL context server method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = TLSv1_1_server_method(); - - ... - } - - -1.8 const SSL_METHOD* TLSv1_2_server_method(void); - - Arguments : none - - Return : TLSV1.2 version SSL context server method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = TLSv1_2_server_method(); - - ... - } - - -1.9 const SSL_METHOD* TLSv1_server_method(void); - - Arguments : none - - Return : TLSV1.0 version SSL context server method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = TLSv1_server_method(); - - ... - } - - -1.10 const SSL_METHOD* SSLv3_server_method(void); - - Arguments : none - - Return : SSLV3.0 version SSL context server method point - - Description : create the target SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method = SSLv3_server_method(); - - ... - } - - -====================== -Chapter 2. SSL Context Fucntion - -2.1 SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); - - Arguments : method - the SSL context method point - - Return : context point - - Description : create a SSL context - - Example : - - void example(void) - { - SSL_CTX *ctx = SSL_CTX_new(SSLv3_server_method()); - - ... - } - - -2.2 void SSL_CTX_free(SSL_CTX *ctx); - - Arguments : ctx - the SSL context point - - Return : none - - Description : free a SSL context - - Example : - - void example(void) - { - SSL_CTX *ctx; - - ... ... - - SSL_CTX_free(ctx); - } - - -2.3 int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); - - Arguments : ctx - SSL context point - meth - SSL method point - - Return : result - 1 : OK - 0 : failed - - Description : set the SSL context version - - Example : - - void example(void) - { - SSL_CTX *ctx; - const SSL_METHOD *meth; - - ... ... - - SSL_CTX_set_ssl_version(ctx, meth); - } - - -2.4 const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); - - Arguments : ctx - SSL context point - - Return : SSL context method - - Description : get the SSL context method - - Example : - - void example(void) - { - const SSL_METHOD *method; - SSL_CTX *ctx; - - ... ... - - method = SSL_CTX_get_ssl_method(ctx); - } - - -====================== -Chapter 3. SSL Fucntion - -3.1 SSL* SSL_new(SSL_CTX *ctx); - - Arguments : ctx - SSL context point - - Return : SSL method - - Description : create a SSL - - Example : - - void example(void) - { - SSL *ssl; - SSL_CTX *ctx; - - ... ... - - ssl = SSL_new(ctx); - } - - -3.2 void SSL_free(SSL *ssl); - - Arguments : ssl - SSL point - - Return : none - - Description : free SSL - - Example : - - void example(void) - { - SSL *ssl; - - ... ... - - SSL_free(ssl); - } - - -3.3 int SSL_do_handshake(SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 1 : OK - 0 : failed, connect is close by remote - -1 : a error catch - - Description : perform the SSL handshake - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_do_handshake(ssl); - } - - -3.4 int SSL_connect(SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 1 : OK - 0 : failed, connect is close by remote - -1 : a error catch - - Description : connect to the remote SSL server - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_connect(ssl); - } - - -3.5 int SSL_accept(SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 1 : OK - 0 : failed, connect is close by remote - -1 : a error catch - - Description : accept the remote connection - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_accept(ssl); - } - - -3.6 int SSL_shutdown(SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 1 : OK - 0 : failed, connect is close by remote - -1 : a error catch - - Description : shutdown the connection - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_shutdown(ssl); - } - - -3.7 int SSL_clear(SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 1 : OK - 0 : failed - - Description : shutdown the connection - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_clear(ssl); - } - - -3.8 int SSL_read(SSL *ssl, void *buffer, int len); - - Arguments : ssl - point - buffer - data buffer point - len - data length - - Return : result - > 0 : OK, and return received data bytes - = 0 : no data received or connection is closed - < 0 : an error catch - - Description : read data from remote - - Example : - - void example(void) - { - SSL *ssl; - char *buf; - int len; - int ret; - - ... ... - - ret = SSL_read(ssl, buf, len); - } - -3.9 int SSL_write(SSL *ssl, const void *buffer, int len); - - Arguments : ssl - SSL point - buffer - data buffer point - len - data length - - Return : result - > 0 : OK, and return received data bytes - = 0 : no data sent or connection is closed - < 0 : an error catch - - Description : send the data to remote - - Example : - - void example(void) - { - SSL *ssl; - char *buf; - int len; - int ret; - - ... ... - - ret = SSL_write(ssl, buf, len); - } - - -3.10 SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : SSL context - - Description : get SSL context of the SSL - - Example : - - void example(void) - { - SSL *ssl; - SSL_CTX *ctx; - - ... ... - - ctx = SSL_get_SSL_CTX(ssl); - } - - -3.11 int SSL_get_shutdown(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : shutdown mode - - Description : get SSL shutdown mode - - Example : - - void example(void) - { - SSL *ssl; - int mode; - - ... ... - - mode = SSL_get_SSL_CTX(ssl); - } - - -3.12 void SSL_set_shutdown(SSL *ssl, int mode); - - Arguments : ssl - SSL point - - Return : shutdown mode - - Description : set SSL shutdown mode - - Example : - - void example(void) - { - SSL *ssl; - int mode = 0; - - ... ... - - SSL_set_shutdown(ssl, mode); - } - - -3.13 const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); - - Arguments : ssl - SSL point - - Return : SSL method - - Description : set SSL shutdown mode - - Example : - - void example(void) - { - SSL *ssl; - const SSL_METHOD *method; - - ... ... - - method = SSL_get_ssl_method(ssl); - } - - -3.14 int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); - - Arguments : ssl - SSL point - meth - SSL method point - - Return : result - 1 : OK - 0 : failed - - Description : set the SSL method - - Example : - - void example(void) - { - int ret; - SSL *ssl; - const SSL_METHOD *method; - - ... ... - - ret = SSL_set_ssl_method(ssl, method); - } - - -3.15 int SSL_pending(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : data bytes - - Description : get received data bytes - - Example : - - void example(void) - { - int ret; - SSL *ssl; - - ... ... - - ret = SSL_pending(ssl); - } - - -3.16 int SSL_has_pending(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 1 : Yes - 0 : No - - Description : check if data is received - - Example : - - void example(void) - { - int ret; - SSL *ssl; - - ... ... - - ret = SSL_has_pending(ssl); - } - - -3.17 int SSL_get_fd(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - >= 0 : socket id - < 0 : a error catch - - Description : get the socket of the SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - - ... ... - - ret = SSL_get_fd(ssl); - } - - -3.18 int SSL_get_rfd(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - >= 0 : socket id - < 0 : a error catch - - Description : get the read only socket of the SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - - ... ... - - ret = SSL_get_rfd(ssl); - } - - -3.19 int SSL_get_wfd(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - >= 0 : socket id - < 0 : a error catch - - Description : get the write only socket of the SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - - ... ... - - ret = SSL_get_wfd(ssl); - } - - -3.20 int SSL_set_fd(SSL *ssl, int fd); - - Arguments : ssl - SSL point - fd - socket id - - Return : result - 1 : OK - 0 : failed - - Description : set socket to SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - int socket; - - ... ... - - ret = SSL_set_fd(ssl, socket); - } - - -3.21 int SSL_set_rfd(SSL *ssl, int fd); - - Arguments : ssl - SSL point - fd - socket id - - Return : result - 1 : OK - 0 : failed - - Description : set read only socket to SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - int socket; - - ... ... - - ret = SSL_set_rfd(ssl, socket); - } - - -3.22 int SSL_set_wfd(SSL *ssl, int fd); - - Arguments : ssl - SSL point - fd - socket id - - Return : result - 1 : OK - 0 : failed - - Description : set write only socket to SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - int socket; - - ... ... - - ret = SSL_set_wfd(ssl, socket); - } - - -3.23 int SSL_version(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : SSL version - - Description : get SSL version - - Example : - - void example(void) - { - int version; - SSL *ssl; - - ... ... - - version = SSL_version(ssl); - } - - -3.24 const char *SSL_get_version(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : SSL version string - - Description : get the SSL current version string - - Example : - - void example(void) - { - char *version; - SSL *ssl; - - ... ... - - version = SSL_get_version(ssl); - } - - -3.25 OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : SSL state - - Description : get the SSL state - - Example : - - void example(void) - { - OSSL_HANDSHAKE_STATE state; - SSL *ssl; - - ... ... - - state = SSL_get_state(ssl); - } - - -3.26 const char *SSL_alert_desc_string(int value); - - Arguments : value - SSL description - - Return : alert value string - - Description : get alert description string - - Example : - - void example(void) - { - int val; - char *str; - - ... ... - - str = SSL_alert_desc_string(val); - } - - -3.27 const char *SSL_alert_desc_string_long(int value); - - Arguments : value - SSL description - - Return : alert value long string - - Description : get alert description long string - - Example : - - void example(void) - { - int val; - char *str; - - ... ... - - str = SSL_alert_desc_string_long(val); - } - - -3.28 const char *SSL_alert_type_string(int value); - - Arguments : value - SSL type description - - Return : alert type string - - Description : get alert type string - - Example : - - void example(void) - { - int val; - char *str; - - ... ... - - str = SSL_alert_type_string(val); - } - - -3.29 const char *SSL_alert_type_string_long(int value); - - Arguments : value - SSL type description - - Return : alert type long string - - Description : get alert type long string - - Example : - - void example(void) - { - int val; - char *str; - - ... ... - - str = SSL_alert_type_string_long(val); - } - -3.30 const char *SSL_rstate_string(SSL *ssl); - - Arguments : ssl - SSL point - - Return : state string - - Description : get the state string where SSL is reading - - Example : - - void example(void) - { - SSL *ssl; - char *str; - - ... ... - - str = SSL_rstate_string(ssl); - } - - -3.31 const char *SSL_rstate_string_long(SSL *ssl); - - Arguments : ssl - SSL point - - Return : state long string - - Description : get the state long string where SSL is reading - - Example : - - void example(void) - { - SSL *ssl; - char *str; - - ... ... - - str = SSL_rstate_string_long(ssl); - } - - -3.32 char *SSL_state_string(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : state string - - Description : get the state string - - Example : - - void example(void) - { - SSL *ssl; - char *str; - - ... ... - - str = SSL_state_string(ssl); - } - - -3.33 char *SSL_state_string_long(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : state long string - - Description : get the state long string - - Example : - - void example(void) - { - SSL *ssl; - char *str; - - ... ... - - str = SSL_state_string(ssl); - } - - -3.34 int SSL_get_error(const SSL *ssl, int ret_code); - - Arguments : ssl - SSL point - ret_code - SSL return code - - Return : SSL error number - - Description : get SSL error code - - Example : - - void example(void) - { - SSL *ssl; - int ret; - int err; - - ... ... - - err = SSL_get_error(ssl, ret); - } - -3.35 void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); - - Arguments : ctx - SSL context point - len - read buffer length - - Return : none - - Description : set the SSL context read buffer length - - Example : - - void example(void) - { - SSL_CTX *ctx; - size_t len; - - ... ... - - SSL_CTX_set_default_read_buffer_len(ctx, len); - } - - -3.36 void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); - - Arguments : ssl - SSL point - len - read buffer length - - Return : none - - Description : set the SSL read buffer length - - Example : - - void example(void) - { - SSL *ssl; - size_t len; - - ... ... - - SSL_set_default_read_buffer_len(ctx, len); - } - - -3.37 int SSL_want(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : specifical statement - - Description : get the SSL specifical statement - - Example : - - void example(void) - { - SSL *ssl; - int state; - - ... ... - - state = SSL_want(ssl); - } - - -3.38 int SSL_want_nothing(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 0 : false - 1 : true - - Description : check if SSL want nothing - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_want(ssl); - } - - -3.39 int SSL_want_read(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 0 : false - 1 : true - - Description : check if SSL want to read - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_want_read(ssl); - } - - -3.40 int SSL_want_write(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : result - 0 : false - 1 : true - - Description : check if SSL want to write - - Example : - - void example(void) - { - SSL *ssl; - int ret; - - ... ... - - ret = SSL_want_write(ssl); - } - -====================== -Chapter 4. SSL X509 Certification and Private Key Function - -4.1 X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); - - Arguments : cert - a point pointed to X509 certification - buffer - a point pointed to the certification context memory point - length - certification bytes - - Return : X509 certification object point - - Description : load a character certification context into system context. If '*cert' is pointed to the - certification, then load certification into it. Or create a new X509 certification object - - Example : - - void example(void) - { - X509 *new; - X509 *cert; - unsigned char *buffer; - long len; - ... ... - - new = d2i_X509(&cert, buffer, len); - } - - -4.2 int SSL_add_client_CA(SSL *ssl, X509 *x); - - Arguments : ssl - SSL point - x - CA certification point - - Return : result - 1 : OK - 0 : failed - - Description : add CA client certification into the SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - X509 *new; - - ... ... - - ret = SSL_add_client_CA(ssl, new); - } - - -4.3 int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); - - Arguments : ctx - SSL context point - x - CA certification point - - Return : result - 1 : OK - 0 : failed - - Description : add CA client certification into the SSL context - - Example : - - void example(void) - { - int ret; - SSL_CTX *ctx; - X509 *new; - - ... ... - - ret = SSL_add_clSSL_CTX_add_client_CAient_CA(ctx, new); - } - - -4.4 X509 *SSL_get_certificate(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : SSL certification point - - Description : get the SSL certification point - - Example : - - void example(void) - { - SSL *ssl; - X509 *cert; - - ... ... - - cert = SSL_get_certificate(ssl); - } - - -4.5 long SSL_get_verify_result(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : the result of verifying - - Description : get the verifying result of the SSL certification - - Example : - - void example(void) - { - SSL *ssl; - long ret; - - ... ... - - ret = SSL_get_verify_result(ssl); - } - - -4.6 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); - - Arguments : ctx - the SSL context point - pkey - certification object point - - Return : result - 1 : OK - 0 : failed - - Description : load the certification into the SSL_CTX or SSL object - - Example : - - void example(void) - { - int ret; - SSL_CTX *ctx - X509 *new; - - ... ... - - ret = SSL_CTX_use_certificate(ctx, new); - } - - -4.7 int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); - - Arguments : ctx - SSL context point - len - certification length - d - data point - - Return : result - 1 : OK - 0 : failed - - Description : load the ASN1 certification into SSL context - - Example : - - void example(void) - { - int ret; - SSL_CTX *ctx; - const unsigned char *buf; - int len; - - ... ... - - ret = SSL_CTX_use_certificate_ASN1(ctx, len, buf); - } - - -4.8 int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); - - Arguments : ctx - SSL context point - pkey - private key object point - - Return : result - 1 : OK - 0 : failed - - Description : load the private key into the context object - - Example : - - void example(void) - { - int ret; - SSL_CTX *ctx; - EVP_PKEY *pkey; - - ... ... - - ret = SSL_CTX_use_PrivateKey(ctx, pkey); - } - - -4.9 int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); - - Arguments : ctx - SSL context point - d - data point - len - private key length - - Return : result - 1 : OK - 0 : failed - - Description : load the ASN1 private key into SSL context - - Example : - - void example(void) - { - int ret; - int pk; - SSL_CTX *ctx; - const unsigned char *buf; - long len; - - ... ... - - ret = SSL_CTX_use_PrivateKey_ASN1(pk, ctx, buf, len); - } - - -4.10 int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); - - Arguments : ctx - SSL context point - d - data point - len - private key length - - Return : result - 1 : OK - 0 : failed - - Description : load the RSA ASN1 private key into SSL context - - Example : - - void example(void) - { - int ret; - SSL_CTX *ctx; - const unsigned char *buf; - long len; - - ... ... - - ret = SSL_CTX_use_RSAPrivateKey_ASN1(ctx, buf, len); - } - - -4.11 int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); - - Arguments : ssl - SSL point - len - data bytes - d - data point - - Return : result - 1 : OK - 0 : failed - - Description : load certification into the SSL - - Example : - - void example(void) - { - int ret; - SSL *ssl; - const unsigned char *buf; - long len; - - ... ... - - ret = SSL_use_certificate_ASN1(ssl, len, buf); - } - - -4.12 X509 *SSL_get_peer_certificate(const SSL *ssl); - - Arguments : ssl - SSL point - - Return : peer certification - - Description : get peer certification - - Example : - - void example(void) - { - SSL *ssl; - X509 *peer; - - ... ... - - peer = SSL_get_peer_certificate(ssl); - } - -====================== -END \ No newline at end of file +OpenSSL-APIs +============ + +All original source code in this repository is Copyright (C) 2015-2016 +Espressif Systems. This source code is licensed under the Apache +License 2.0 as described in the file LICENSE. + +Chapter Introduction +==================== + +Chapter 1. SSL Context Method Create +Chapter 2. SSL Context Fucntion +Chapter 3. SSL Fucntion +Chapter 4. SSL X509 Certification and Private Key Function + + +Chapter 1. SSL Context Method Create +==================================== + +1.1 const SSL_METHOD* SSLv23_client_method(void); + + Arguments : none + + Return : SSLV2 and 3 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv23_client_method(); + + ... + } + + +1.2 const SSL_METHOD* TLSv1_client_method(void); + + Arguments : none + + Return : TLSV1.0 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_client_method(); + + ... + } + + +1.3 const SSL_METHOD* SSLv3_client_method(void); + + Arguments : none + + Return : SSLV3.0 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv3_client_method(); + + ... + } + + +1.4 const SSL_METHOD* TLSv1_1_client_method(void); + + Arguments : none + + Return : TLSV1.1 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_client_method(); + + ... + } + + +1.5 const SSL_METHOD* TLSv1_2_client_method(void); + + Arguments : none + + Return : TLSV1.2 version SSL context client method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_client_method(); + + ... + } + + +1.6 const SSL_METHOD* SSLv23_server_method(void); + + Arguments : none + + Return : SSLV2 and 3 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv23_server_method(); + + ... + } + + +1.7 const SSL_METHOD* TLSv1_1_server_method(void); + + Arguments : none + + Return : TLSV1.1 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_1_server_method(); + + ... + } + + +1.8 const SSL_METHOD* TLSv1_2_server_method(void); + + Arguments : none + + Return : TLSV1.2 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_server_method(); + + ... + } + + +1.9 const SSL_METHOD* TLSv1_server_method(void); + + Arguments : none + + Return : TLSV1.0 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = TLSv1_server_method(); + + ... + } + + +1.10 const SSL_METHOD* SSLv3_server_method(void); + + Arguments : none + + Return : SSLV3.0 version SSL context server method point + + Description : create the target SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method = SSLv3_server_method(); + + ... + } + + + +Chapter 2. SSL Context Fucntion +=============================== + +2.1 SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); + + Arguments : method - the SSL context method point + + Return : context point + + Description : create a SSL context + + Example : + + void example(void) + { + SSL_CTX *ctx = SSL_CTX_new(SSLv3_server_method()); + + ... + } + + +2.2 void SSL_CTX_free(SSL_CTX *ctx); + + Arguments : ctx - the SSL context point + + Return : none + + Description : free a SSL context + + Example : + + void example(void) + { + SSL_CTX *ctx; + + ... ... + + SSL_CTX_free(ctx); + } + + +2.3 int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); + + Arguments : ctx - SSL context point + meth - SSL method point + + Return : result + 1 : OK + 0 : failed + + Description : set the SSL context version + + Example : + + void example(void) + { + SSL_CTX *ctx; + const SSL_METHOD *meth; + + ... ... + + SSL_CTX_set_ssl_version(ctx, meth); + } + + +2.4 const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); + + Arguments : ctx - SSL context point + + Return : SSL context method + + Description : get the SSL context method + + Example : + + void example(void) + { + const SSL_METHOD *method; + SSL_CTX *ctx; + + ... ... + + method = SSL_CTX_get_ssl_method(ctx); + } + + + +Chapter 3. SSL Fucntion +======================= + +3.1 SSL* SSL_new(SSL_CTX *ctx); + + Arguments : ctx - SSL context point + + Return : SSL method + + Description : create a SSL + + Example : + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ssl = SSL_new(ctx); + } + + +3.2 void SSL_free(SSL *ssl); + + Arguments : ssl - SSL point + + Return : none + + Description : free SSL + + Example : + + void example(void) + { + SSL *ssl; + + ... ... + + SSL_free(ssl); + } + + +3.3 int SSL_do_handshake(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : perform the SSL handshake + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_do_handshake(ssl); + } + + +3.4 int SSL_connect(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : connect to the remote SSL server + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_connect(ssl); + } + + +3.5 int SSL_accept(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : accept the remote connection + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_accept(ssl); + } + + +3.6 int SSL_shutdown(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed, connect is close by remote + -1 : a error catch + + Description : shutdown the connection + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_shutdown(ssl); + } + + +3.7 int SSL_clear(SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : OK + 0 : failed + + Description : shutdown the connection + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_clear(ssl); + } + + +3.8 int SSL_read(SSL *ssl, void *buffer, int len); + + Arguments : ssl - point + buffer - data buffer point + len - data length + + Return : result + > 0 : OK, and return received data bytes + = 0 : no data received or connection is closed + < 0 : an error catch + + Description : read data from remote + + Example : + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_read(ssl, buf, len); + } + +3.9 int SSL_write(SSL *ssl, const void *buffer, int len); + + Arguments : ssl - SSL point + buffer - data buffer point + len - data length + + Return : result + > 0 : OK, and return received data bytes + = 0 : no data sent or connection is closed + < 0 : an error catch + + Description : send the data to remote + + Example : + + void example(void) + { + SSL *ssl; + char *buf; + int len; + int ret; + + ... ... + + ret = SSL_write(ssl, buf, len); + } + + +3.10 SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL context + + Description : get SSL context of the SSL + + Example : + + void example(void) + { + SSL *ssl; + SSL_CTX *ctx; + + ... ... + + ctx = SSL_get_SSL_CTX(ssl); + } + + +3.11 int SSL_get_shutdown(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : shutdown mode + + Description : get SSL shutdown mode + + Example : + + void example(void) + { + SSL *ssl; + int mode; + + ... ... + + mode = SSL_get_SSL_CTX(ssl); + } + + +3.12 void SSL_set_shutdown(SSL *ssl, int mode); + + Arguments : ssl - SSL point + + Return : shutdown mode + + Description : set SSL shutdown mode + + Example : + + void example(void) + { + SSL *ssl; + int mode = 0; + + ... ... + + SSL_set_shutdown(ssl, mode); + } + + +3.13 const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL method + + Description : set SSL shutdown mode + + Example : + + void example(void) + { + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + method = SSL_get_ssl_method(ssl); + } + + +3.14 int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); + + Arguments : ssl - SSL point + meth - SSL method point + + Return : result + 1 : OK + 0 : failed + + Description : set the SSL method + + Example : + + void example(void) + { + int ret; + SSL *ssl; + const SSL_METHOD *method; + + ... ... + + ret = SSL_set_ssl_method(ssl, method); + } + + +3.15 int SSL_pending(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : data bytes + + Description : get received data bytes + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_pending(ssl); + } + + +3.16 int SSL_has_pending(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 1 : Yes + 0 : No + + Description : check if data is received + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_has_pending(ssl); + } + + +3.17 int SSL_get_fd(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + >= 0 : socket id + < 0 : a error catch + + Description : get the socket of the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_fd(ssl); + } + + +3.18 int SSL_get_rfd(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + >= 0 : socket id + < 0 : a error catch + + Description : get the read only socket of the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_rfd(ssl); + } + + +3.19 int SSL_get_wfd(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + >= 0 : socket id + < 0 : a error catch + + Description : get the write only socket of the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + + ... ... + + ret = SSL_get_wfd(ssl); + } + + +3.20 int SSL_set_fd(SSL *ssl, int fd); + + Arguments : ssl - SSL point + fd - socket id + + Return : result + 1 : OK + 0 : failed + + Description : set socket to SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_fd(ssl, socket); + } + + +3.21 int SSL_set_rfd(SSL *ssl, int fd); + + Arguments : ssl - SSL point + fd - socket id + + Return : result + 1 : OK + 0 : failed + + Description : set read only socket to SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_rfd(ssl, socket); + } + + +3.22 int SSL_set_wfd(SSL *ssl, int fd); + + Arguments : ssl - SSL point + fd - socket id + + Return : result + 1 : OK + 0 : failed + + Description : set write only socket to SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + int socket; + + ... ... + + ret = SSL_set_wfd(ssl, socket); + } + + +3.23 int SSL_version(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL version + + Description : get SSL version + + Example : + + void example(void) + { + int version; + SSL *ssl; + + ... ... + + version = SSL_version(ssl); + } + + +3.24 const char *SSL_get_version(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL version string + + Description : get the SSL current version string + + Example : + + void example(void) + { + char *version; + SSL *ssl; + + ... ... + + version = SSL_get_version(ssl); + } + + +3.25 OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL state + + Description : get the SSL state + + Example : + + void example(void) + { + OSSL_HANDSHAKE_STATE state; + SSL *ssl; + + ... ... + + state = SSL_get_state(ssl); + } + + +3.26 const char *SSL_alert_desc_string(int value); + + Arguments : value - SSL description + + Return : alert value string + + Description : get alert description string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string(val); + } + + +3.27 const char *SSL_alert_desc_string_long(int value); + + Arguments : value - SSL description + + Return : alert value long string + + Description : get alert description long string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_desc_string_long(val); + } + + +3.28 const char *SSL_alert_type_string(int value); + + Arguments : value - SSL type description + + Return : alert type string + + Description : get alert type string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string(val); + } + + +3.29 const char *SSL_alert_type_string_long(int value); + + Arguments : value - SSL type description + + Return : alert type long string + + Description : get alert type long string + + Example : + + void example(void) + { + int val; + char *str; + + ... ... + + str = SSL_alert_type_string_long(val); + } + +3.30 const char *SSL_rstate_string(SSL *ssl); + + Arguments : ssl - SSL point + + Return : state string + + Description : get the state string where SSL is reading + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string(ssl); + } + + +3.31 const char *SSL_rstate_string_long(SSL *ssl); + + Arguments : ssl - SSL point + + Return : state long string + + Description : get the state long string where SSL is reading + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_rstate_string_long(ssl); + } + + +3.32 char *SSL_state_string(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : state string + + Description : get the state string + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.33 char *SSL_state_string_long(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : state long string + + Description : get the state long string + + Example : + + void example(void) + { + SSL *ssl; + char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.34 int SSL_get_error(const SSL *ssl, int ret_code); + + Arguments : ssl - SSL point + ret_code - SSL return code + + Return : SSL error number + + Description : get SSL error code + + Example : + + void example(void) + { + SSL *ssl; + int ret; + int err; + + ... ... + + err = SSL_get_error(ssl, ret); + } + +3.35 void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); + + Arguments : ctx - SSL context point + len - read buffer length + + Return : none + + Description : set the SSL context read buffer length + + Example : + + void example(void) + { + SSL_CTX *ctx; + size_t len; + + ... ... + + SSL_CTX_set_default_read_buffer_len(ctx, len); + } + + +3.36 void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); + + Arguments : ssl - SSL point + len - read buffer length + + Return : none + + Description : set the SSL read buffer length + + Example : + + void example(void) + { + SSL *ssl; + size_t len; + + ... ... + + SSL_set_default_read_buffer_len(ctx, len); + } + + +3.37 int SSL_want(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : specifical statement + + Description : get the SSL specifical statement + + Example : + + void example(void) + { + SSL *ssl; + int state; + + ... ... + + state = SSL_want(ssl); + } + + +3.38 int SSL_want_nothing(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 0 : false + 1 : true + + Description : check if SSL want nothing + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want(ssl); + } + + +3.39 int SSL_want_read(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 0 : false + 1 : true + + Description : check if SSL want to read + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_read(ssl); + } + + +3.40 int SSL_want_write(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : result + 0 : false + 1 : true + + Description : check if SSL want to write + + Example : + + void example(void) + { + SSL *ssl; + int ret; + + ... ... + + ret = SSL_want_write(ssl); + } + + +Chapter 4. SSL X509 Certification and Private Key Function +========================================================== + +4.1 X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); + + Arguments : cert - a point pointed to X509 certification + buffer - a point pointed to the certification context memory point + length - certification bytes + + Return : X509 certification object point + + Description : load a character certification context into system context. If '*cert' is pointed to the + certification, then load certification into it. Or create a new X509 certification object + + Example : + + void example(void) + { + X509 *new; + X509 *cert; + unsigned char *buffer; + long len; + ... ... + + new = d2i_X509(&cert, buffer, len); + } + + +4.2 int SSL_add_client_CA(SSL *ssl, X509 *x); + + Arguments : ssl - SSL point + x - CA certification point + + Return : result + 1 : OK + 0 : failed + + Description : add CA client certification into the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + X509 *new; + + ... ... + + ret = SSL_add_client_CA(ssl, new); + } + + +4.3 int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); + + Arguments : ctx - SSL context point + x - CA certification point + + Return : result + 1 : OK + 0 : failed + + Description : add CA client certification into the SSL context + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + X509 *new; + + ... ... + + ret = SSL_add_clSSL_CTX_add_client_CAient_CA(ctx, new); + } + + +4.4 X509 *SSL_get_certificate(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : SSL certification point + + Description : get the SSL certification point + + Example : + + void example(void) + { + SSL *ssl; + X509 *cert; + + ... ... + + cert = SSL_get_certificate(ssl); + } + + +4.5 long SSL_get_verify_result(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : the result of verifying + + Description : get the verifying result of the SSL certification + + Example : + + void example(void) + { + SSL *ssl; + long ret; + + ... ... + + ret = SSL_get_verify_result(ssl); + } + + +4.6 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); + + Arguments : ctx - the SSL context point + pkey - certification object point + + Return : result + 1 : OK + 0 : failed + + Description : load the certification into the SSL_CTX or SSL object + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx + X509 *new; + + ... ... + + ret = SSL_CTX_use_certificate(ctx, new); + } + + +4.7 int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); + + Arguments : ctx - SSL context point + len - certification length + d - data point + + Return : result + 1 : OK + 0 : failed + + Description : load the ASN1 certification into SSL context + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + int len; + + ... ... + + ret = SSL_CTX_use_certificate_ASN1(ctx, len, buf); + } + + +4.8 int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); + + Arguments : ctx - SSL context point + pkey - private key object point + + Return : result + 1 : OK + 0 : failed + + Description : load the private key into the context object + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + EVP_PKEY *pkey; + + ... ... + + ret = SSL_CTX_use_PrivateKey(ctx, pkey); + } + + +4.9 int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); + + Arguments : ctx - SSL context point + d - data point + len - private key length + + Return : result + 1 : OK + 0 : failed + + Description : load the ASN1 private key into SSL context + + Example : + + void example(void) + { + int ret; + int pk; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_PrivateKey_ASN1(pk, ctx, buf, len); + } + + +4.10 int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); + + Arguments : ctx - SSL context point + d - data point + len - private key length + + Return : result + 1 : OK + 0 : failed + + Description : load the RSA ASN1 private key into SSL context + + Example : + + void example(void) + { + int ret; + SSL_CTX *ctx; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_CTX_use_RSAPrivateKey_ASN1(ctx, buf, len); + } + + +4.11 int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); + + Arguments : ssl - SSL point + len - data bytes + d - data point + + Return : result + 1 : OK + 0 : failed + + Description : load certification into the SSL + + Example : + + void example(void) + { + int ret; + SSL *ssl; + const unsigned char *buf; + long len; + + ... ... + + ret = SSL_use_certificate_ASN1(ssl, len, buf); + } + + +4.12 X509 *SSL_get_peer_certificate(const SSL *ssl); + + Arguments : ssl - SSL point + + Return : peer certification + + Description : get peer certification + + Example : + + void example(void) + { + SSL *ssl; + X509 *peer; + + ... ... + + peer = SSL_get_peer_certificate(ssl); + } + From b97c00f2c1b367fb5d6e2602ccc21392282378ff Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 28 Sep 2016 20:41:11 +0800 Subject: [PATCH 37/95] components/openssl: add more .rst encoding type --- components/openssl/OpenSSL-APIs.rst | 1123 ++++++++++++++++++--------- 1 file changed, 748 insertions(+), 375 deletions(-) diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst index 5a44794cd2..cb90a23c93 100644 --- a/components/openssl/OpenSSL-APIs.rst +++ b/components/openssl/OpenSSL-APIs.rst @@ -8,24 +8,31 @@ License 2.0 as described in the file LICENSE. Chapter Introduction ==================== -Chapter 1. SSL Context Method Create -Chapter 2. SSL Context Fucntion -Chapter 3. SSL Fucntion -Chapter 4. SSL X509 Certification and Private Key Function +- Chapter 1. SSL Context Method Create +- Chapter 2. SSL Context Fucntion +- Chapter 3. SSL Fucntion +- Chapter 4. SSL X509 Certification and Private Key Function Chapter 1. SSL Context Method Create ==================================== -1.1 const SSL_METHOD* SSLv23_client_method(void); - Arguments : none +1.1 const SSL_METHOD* ``SSLv23_client_method``(void) + + Arguments:: - Return : SSLV2 and 3 version SSL context client method point + none - Description : create the target SSL context method + Return:: - Example : + SSLV2 and 3 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -35,15 +42,21 @@ Chapter 1. SSL Context Method Create } -1.2 const SSL_METHOD* TLSv1_client_method(void); +1.2 const SSL_METHOD* ``TLSv1_client_method``(void) - Arguments : none + Arguments:: - Return : TLSV1.0 version SSL context client method point + none - Description : create the target SSL context method + Return:: - Example : + TLSV1.0 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -53,15 +66,21 @@ Chapter 1. SSL Context Method Create } -1.3 const SSL_METHOD* SSLv3_client_method(void); +1.3 const SSL_METHOD* ``SSLv3_client_method``(void) - Arguments : none + Arguments:: - Return : SSLV3.0 version SSL context client method point + none - Description : create the target SSL context method + Return:: - Example : + SSLV3.0 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -71,15 +90,21 @@ Chapter 1. SSL Context Method Create } -1.4 const SSL_METHOD* TLSv1_1_client_method(void); +1.4 const SSL_METHOD* ``TLSv1_1_client_method``(void) - Arguments : none + Arguments:: - Return : TLSV1.1 version SSL context client method point + none - Description : create the target SSL context method + Return:: - Example : + TLSV1.1 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -89,15 +114,21 @@ Chapter 1. SSL Context Method Create } -1.5 const SSL_METHOD* TLSv1_2_client_method(void); +1.5 const SSL_METHOD* ``TLSv1_2_client_method``(void) - Arguments : none + Arguments:: - Return : TLSV1.2 version SSL context client method point + none - Description : create the target SSL context method + Return:: - Example : + TLSV1.2 version SSL context client method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -107,15 +138,21 @@ Chapter 1. SSL Context Method Create } -1.6 const SSL_METHOD* SSLv23_server_method(void); +1.6 const SSL_METHOD* ``SSLv23_server_method``(void) - Arguments : none + Arguments:: - Return : SSLV2 and 3 version SSL context server method point + none - Description : create the target SSL context method + Return:: - Example : + SSLV2 and 3 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -125,13 +162,19 @@ Chapter 1. SSL Context Method Create } -1.7 const SSL_METHOD* TLSv1_1_server_method(void); +1.7 const SSL_METHOD* ``TLSv1_1_server_method``(void) - Arguments : none + Arguments:: - Return : TLSV1.1 version SSL context server method point + none - Description : create the target SSL context method + Return:: + + TLSV1.1 version SSL context server method point + + Description:: + + create the target SSL context method Example : @@ -143,15 +186,21 @@ Chapter 1. SSL Context Method Create } -1.8 const SSL_METHOD* TLSv1_2_server_method(void); +1.8 const SSL_METHOD* ``TLSv1_2_server_method``(void) - Arguments : none + Arguments:: - Return : TLSV1.2 version SSL context server method point + none - Description : create the target SSL context method + Return:: - Example : + TLSV1.2 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -161,15 +210,21 @@ Chapter 1. SSL Context Method Create } -1.9 const SSL_METHOD* TLSv1_server_method(void); +1.9 const SSL_METHOD* ``TLSv1_server_method``(void) - Arguments : none + Arguments:: - Return : TLSV1.0 version SSL context server method point + none - Description : create the target SSL context method + Return:: - Example : + TLSV1.0 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -179,15 +234,21 @@ Chapter 1. SSL Context Method Create } -1.10 const SSL_METHOD* SSLv3_server_method(void); +1.10 const SSL_METHOD* ``SSLv3_server_method``(void) - Arguments : none + Arguments:: - Return : SSLV3.0 version SSL context server method point + none - Description : create the target SSL context method + Return:: - Example : + SSLV3.0 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: void example(void) { @@ -201,15 +262,22 @@ Chapter 1. SSL Context Method Create Chapter 2. SSL Context Fucntion =============================== -2.1 SSL_CTX* SSL_CTX_new(const SSL_METHOD *method); - Arguments : method - the SSL context method point +2.1 SSL_CTX* ``SSL_CTX_new``(const SSL_METHOD *method) + + Arguments:: - Return : context point + method - the SSL context method point - Description : create a SSL context + Return:: - Example : + context point + + Description:: + + create a SSL context + + Example:: void example(void) { @@ -219,15 +287,21 @@ Chapter 2. SSL Context Fucntion } -2.2 void SSL_CTX_free(SSL_CTX *ctx); +2.2 ``void SSL_CTX_free``(SSL_CTX *ctx) - Arguments : ctx - the SSL context point + Arguments:: - Return : none + ctx - the SSL context point - Description : free a SSL context + Return:: - Example : + none + + Description:: + + free a SSL context + + Example:: void example(void) { @@ -239,18 +313,23 @@ Chapter 2. SSL Context Fucntion } -2.3 int SSL_CTX_set_ssl_version(SSL_CTX *ctx, const SSL_METHOD *meth); +2.3 ``int SSL_CTX_set_ssl_version``(SSL_CTX *ctx, const SSL_METHOD *meth) - Arguments : ctx - SSL context point - meth - SSL method point + Arguments:: + + ctx - SSL context point + meth - SSL method point + + Return:: - Return : result 1 : OK 0 : failed - Description : set the SSL context version + Description:: - Example : + set the SSL context version + + Example:: void example(void) { @@ -263,15 +342,21 @@ Chapter 2. SSL Context Fucntion } -2.4 const SSL_METHOD *SSL_CTX_get_ssl_method(SSL_CTX *ctx); +2.4 const SSL_METHOD* ``SSL_CTX_get_ssl_method``(SSL_CTX *ctx) - Arguments : ctx - SSL context point + Arguments:: - Return : SSL context method + ctx - SSL context point - Description : get the SSL context method + Return:: - Example : + SSL context method + + Description:: + + get the SSL context method + + Example:: void example(void) { @@ -288,15 +373,22 @@ Chapter 2. SSL Context Fucntion Chapter 3. SSL Fucntion ======================= -3.1 SSL* SSL_new(SSL_CTX *ctx); - Arguments : ctx - SSL context point +3.1 SSL* ``SSL_new``(SSL_CTX *ctx) + + Arguments:: - Return : SSL method + ctx - SSL context point - Description : create a SSL + Return:: - Example : + SSL method + + Description:: + + create a SSL + + Example:: void example(void) { @@ -309,15 +401,21 @@ Chapter 3. SSL Fucntion } -3.2 void SSL_free(SSL *ssl); +3.2 void ``SSL_free``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : none + ssl - SSL point - Description : free SSL + Return:: - Example : + none + + Description:: + + free SSL + + Example:: void example(void) { @@ -329,18 +427,23 @@ Chapter 3. SSL Fucntion } -3.3 int SSL_do_handshake(SSL *ssl); +3.3 int ``SSL_do_handshake``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 1 : OK 0 : failed, connect is close by remote -1 : a error catch - Description : perform the SSL handshake + Description:: - Example : + perform the SSL handshake + + Example:: void example(void) { @@ -353,18 +456,23 @@ Chapter 3. SSL Fucntion } -3.4 int SSL_connect(SSL *ssl); +3.4 int ``SSL_connect``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 1 : OK 0 : failed, connect is close by remote -1 : a error catch - Description : connect to the remote SSL server + Description:: - Example : + connect to the remote SSL server + + Example:: void example(void) { @@ -377,18 +485,23 @@ Chapter 3. SSL Fucntion } -3.5 int SSL_accept(SSL *ssl); +3.5 int ``SSL_accept``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 1 : OK 0 : failed, connect is close by remote -1 : a error catch - Description : accept the remote connection + Description:: - Example : + accept the remote connection + + Example:: void example(void) { @@ -401,18 +514,23 @@ Chapter 3. SSL Fucntion } -3.6 int SSL_shutdown(SSL *ssl); +3.6 int ``SSL_shutdown``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 1 : OK 0 : failed, connect is close by remote -1 : a error catch - Description : shutdown the connection + Description:: - Example : + shutdown the connection + + Example:: void example(void) { @@ -425,17 +543,22 @@ Chapter 3. SSL Fucntion } -3.7 int SSL_clear(SSL *ssl); +3.7 int ``SSL_clear``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 1 : OK 0 : failed - Description : shutdown the connection + Description:: - Example : + shutdown the connection + + Example:: void example(void) { @@ -448,20 +571,25 @@ Chapter 3. SSL Fucntion } -3.8 int SSL_read(SSL *ssl, void *buffer, int len); +3.8 int ``SSL_read``(SSL *ssl, void *buffer, int len) - Arguments : ssl - point - buffer - data buffer point - len - data length + Arguments:: + + ssl - point + buffer - data buffer point + len - data length + + Return:: - Return : result > 0 : OK, and return received data bytes = 0 : no data received or connection is closed < 0 : an error catch - Description : read data from remote + Description:: - Example : + read data from remote + + Example:: void example(void) { @@ -475,20 +603,25 @@ Chapter 3. SSL Fucntion ret = SSL_read(ssl, buf, len); } -3.9 int SSL_write(SSL *ssl, const void *buffer, int len); +3.9 int ``SSL_write``(SSL *ssl, const void *buffer, int len) - Arguments : ssl - SSL point - buffer - data buffer point - len - data length + Arguments:: + + ssl - SSL point + buffer - data buffer point + len - data length + + Return:: - Return : result > 0 : OK, and return received data bytes = 0 : no data sent or connection is closed < 0 : an error catch - Description : send the data to remote + Description:: - Example : + send the data to remote + + Example:: void example(void) { @@ -503,15 +636,21 @@ Chapter 3. SSL Fucntion } -3.10 SSL_CTX *SSL_get_SSL_CTX(const SSL *ssl); +3.10 ``SSL_CTX *SSL_get_SSL_CTX``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : SSL context + ssl - SSL point + + Return:: + + SSL context - Description : get SSL context of the SSL + Description:: - Example : + get SSL context of the SSL + + Example:: void example(void) { @@ -524,15 +663,21 @@ Chapter 3. SSL Fucntion } -3.11 int SSL_get_shutdown(const SSL *ssl); +3.11 int ``SSL_get_shutdown``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : shutdown mode + ssl - SSL point + + Return:: + + shutdown mode - Description : get SSL shutdown mode + Description:: - Example : + get SSL shutdown mode + + Example:: void example(void) { @@ -545,15 +690,21 @@ Chapter 3. SSL Fucntion } -3.12 void SSL_set_shutdown(SSL *ssl, int mode); +3.12 void ``SSL_set_shutdown``(SSL *ssl, int mode) - Arguments : ssl - SSL point + Arguments:: - Return : shutdown mode + ssl - SSL point + + Return:: + + shutdown mode - Description : set SSL shutdown mode + Description:: - Example : + set SSL shutdown mode + + Example:: void example(void) { @@ -566,15 +717,21 @@ Chapter 3. SSL Fucntion } -3.13 const SSL_METHOD *SSL_get_ssl_method(SSL *ssl); +3.13 const SSL_METHOD* ``SSL_get_ssl_method``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : SSL method + ssl - SSL point + + Return:: + + SSL method - Description : set SSL shutdown mode + Description:: - Example : + set SSL shutdown mode + + Example:: void example(void) { @@ -587,18 +744,23 @@ Chapter 3. SSL Fucntion } -3.14 int SSL_set_ssl_method(SSL *ssl, const SSL_METHOD *method); +3.14 int ``SSL_set_ssl_method``(SSL *ssl, const SSL_METHOD *method) - Arguments : ssl - SSL point - meth - SSL method point + Arguments:: + + ssl - SSL point + meth - SSL method point + + Return:: - Return : result 1 : OK 0 : failed - Description : set the SSL method + Description:: - Example : + set the SSL method + + Example:: void example(void) { @@ -612,15 +774,21 @@ Chapter 3. SSL Fucntion } -3.15 int SSL_pending(const SSL *ssl); +3.15 int ``SSL_pending``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : data bytes + ssl - SSL point + + Return:: + + data bytes - Description : get received data bytes + Description:: - Example : + get received data bytes + + Example:: void example(void) { @@ -633,17 +801,22 @@ Chapter 3. SSL Fucntion } -3.16 int SSL_has_pending(const SSL *ssl); +3.16 int ``SSL_has_pending``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 1 : Yes 0 : No - Description : check if data is received + Description:: - Example : + check if data is received + + Example:: void example(void) { @@ -656,17 +829,22 @@ Chapter 3. SSL Fucntion } -3.17 int SSL_get_fd(const SSL *ssl); +3.17 int ``SSL_get_fd``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result >= 0 : socket id < 0 : a error catch - Description : get the socket of the SSL + Description:: - Example : + get the socket of the SSL + + Example:: void example(void) { @@ -679,17 +857,22 @@ Chapter 3. SSL Fucntion } -3.18 int SSL_get_rfd(const SSL *ssl); +3.18 int ``SSL_get_rfd``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result >= 0 : socket id < 0 : a error catch - Description : get the read only socket of the SSL + Description:: - Example : + get the read only socket of the SSL + + Example:: void example(void) { @@ -702,17 +885,22 @@ Chapter 3. SSL Fucntion } -3.19 int SSL_get_wfd(const SSL *ssl); +3.19 int ``SSL_get_wfd``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result >= 0 : socket id < 0 : a error catch - Description : get the write only socket of the SSL + Description:: - Example : + get the write only socket of the SSL + + Example:: void example(void) { @@ -725,18 +913,23 @@ Chapter 3. SSL Fucntion } -3.20 int SSL_set_fd(SSL *ssl, int fd); +3.20 int ``SSL_set_fd``(SSL *ssl, int fd) - Arguments : ssl - SSL point - fd - socket id + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: - Return : result 1 : OK 0 : failed - Description : set socket to SSL + Description:: - Example : + set socket to SSL + + Example:: void example(void) { @@ -750,18 +943,23 @@ Chapter 3. SSL Fucntion } -3.21 int SSL_set_rfd(SSL *ssl, int fd); +3.21 int ``SSL_set_rfd``(SSL *ssl, int fd) - Arguments : ssl - SSL point - fd - socket id + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: - Return : result 1 : OK 0 : failed - Description : set read only socket to SSL + Description:: - Example : + set read only socket to SSL + + Example:: void example(void) { @@ -775,18 +973,23 @@ Chapter 3. SSL Fucntion } -3.22 int SSL_set_wfd(SSL *ssl, int fd); +3.22 int ``SSL_set_wfd``(SSL *ssl, int fd) - Arguments : ssl - SSL point - fd - socket id + Arguments:: + + ssl - SSL point + fd - socket id + + Return:: - Return : result 1 : OK 0 : failed - Description : set write only socket to SSL + Description:: - Example : + set write only socket to SSL + + Example:: void example(void) { @@ -800,15 +1003,21 @@ Chapter 3. SSL Fucntion } -3.23 int SSL_version(const SSL *ssl); +3.23 int ``SSL_version``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : SSL version + ssl - SSL point + + Return:: + + SSL version - Description : get SSL version + Description:: - Example : + get SSL version + + Example:: void example(void) { @@ -821,15 +1030,21 @@ Chapter 3. SSL Fucntion } -3.24 const char *SSL_get_version(const SSL *ssl); +3.24 const char* ``SSL_get_version``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : SSL version string + ssl - SSL point + + Return:: + + SSL version string - Description : get the SSL current version string + Description:: - Example : + get the SSL current version string + + Example:: void example(void) { @@ -842,15 +1057,21 @@ Chapter 3. SSL Fucntion } -3.25 OSSL_HANDSHAKE_STATE SSL_get_state(const SSL *ssl); +3.25 OSSL_HANDSHAKE_STATE ``SSL_get_state``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : SSL state + ssl - SSL point + + Return:: + + SSL state - Description : get the SSL state + Description:: - Example : + get the SSL state + + Example:: void example(void) { @@ -863,15 +1084,21 @@ Chapter 3. SSL Fucntion } -3.26 const char *SSL_alert_desc_string(int value); +3.26 const char* ``SSL_alert_desc_string``(int value) - Arguments : value - SSL description + Arguments:: - Return : alert value string + value - SSL description + + Return:: + + alert value string - Description : get alert description string + Description:: - Example : + get alert description string + + Example:: void example(void) { @@ -884,15 +1111,21 @@ Chapter 3. SSL Fucntion } -3.27 const char *SSL_alert_desc_string_long(int value); +3.27 const char* ``SSL_alert_desc_string_long``(int value) - Arguments : value - SSL description + Arguments:: - Return : alert value long string + value - SSL description + + Return:: + + alert value long string - Description : get alert description long string + Description:: - Example : + get alert description long string + + Example:: void example(void) { @@ -905,15 +1138,21 @@ Chapter 3. SSL Fucntion } -3.28 const char *SSL_alert_type_string(int value); +3.28 const char* ``SSL_alert_type_string``(int value) - Arguments : value - SSL type description + Arguments:: - Return : alert type string + value - SSL type description + + Return:: + + alert type string - Description : get alert type string + Description:: - Example : + get alert type string + + Example:: void example(void) { @@ -926,15 +1165,21 @@ Chapter 3. SSL Fucntion } -3.29 const char *SSL_alert_type_string_long(int value); +3.29 const char* ``SSL_alert_type_string_long``(int value) - Arguments : value - SSL type description + Arguments:: - Return : alert type long string + value - SSL type description + + Return:: + + alert type long string - Description : get alert type long string + Description:: - Example : + get alert type long string + + Example:: void example(void) { @@ -946,15 +1191,21 @@ Chapter 3. SSL Fucntion str = SSL_alert_type_string_long(val); } -3.30 const char *SSL_rstate_string(SSL *ssl); +3.30 const char* ``SSL_rstate_string``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : state string + ssl - SSL point + + Return:: + + state string - Description : get the state string where SSL is reading + Description:: - Example : + get the state string where SSL is reading + + Example:: void example(void) { @@ -967,15 +1218,21 @@ Chapter 3. SSL Fucntion } -3.31 const char *SSL_rstate_string_long(SSL *ssl); +3.31 const char* ``SSL_rstate_string_long``(SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : state long string + ssl - SSL point + + Return:: + + state long string - Description : get the state long string where SSL is reading + Description:: - Example : + get the state long string where SSL is reading + + Example:: void example(void) { @@ -988,15 +1245,48 @@ Chapter 3. SSL Fucntion } -3.32 char *SSL_state_string(const SSL *ssl); +3.32 const char* ``SSL_state_string``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : state string + ssl - SSL point + + Return:: + + state string - Description : get the state string + Description:: - Example : + get the state string + + Example:: + + void example(void) + { + SSL *ssl; + const char *str; + + ... ... + + str = SSL_state_string(ssl); + } + + +3.33 char* ``SSL_state_string_long``(const SSL *ssl) + + Arguments:: + + ssl - SSL point + + Return:: + + state long string + + Description:: + + get the state long string + + Example:: void example(void) { @@ -1009,37 +1299,22 @@ Chapter 3. SSL Fucntion } -3.33 char *SSL_state_string_long(const SSL *ssl); +3.34 int ``SSL_get_error``(const SSL *ssl, int ret_code) - Arguments : ssl - SSL point + Arguments:: - Return : state long string + ssl - SSL point + ret_code - SSL return code + + Return:: + + SSL error number - Description : get the state long string + Description:: - Example : + get SSL error code - void example(void) - { - SSL *ssl; - char *str; - - ... ... - - str = SSL_state_string(ssl); - } - - -3.34 int SSL_get_error(const SSL *ssl, int ret_code); - - Arguments : ssl - SSL point - ret_code - SSL return code - - Return : SSL error number - - Description : get SSL error code - - Example : + Example:: void example(void) { @@ -1052,16 +1327,22 @@ Chapter 3. SSL Fucntion err = SSL_get_error(ssl, ret); } -3.35 void SSL_CTX_set_default_read_buffer_len(SSL_CTX *ctx, size_t len); +3.35 void ``SSL_CTX_set_default_read_buffer_len``(SSL_CTX *ctx, size_t len) - Arguments : ctx - SSL context point - len - read buffer length + Arguments:: - Return : none + ctx - SSL context point + len - read buffer length + + Return:: + + none - Description : set the SSL context read buffer length + Description:: - Example : + set the SSL context read buffer length + + Example:: void example(void) { @@ -1074,16 +1355,22 @@ Chapter 3. SSL Fucntion } -3.36 void SSL_set_default_read_buffer_len(SSL *ssl, size_t len); +3.36 void ``SSL_set_default_read_buffer_len``(SSL *ssl, size_t len) - Arguments : ssl - SSL point - len - read buffer length + Arguments:: - Return : none + ssl - SSL point + len - read buffer length + + Return:: + + none - Description : set the SSL read buffer length + Description:: - Example : + set the SSL read buffer length + + Example:: void example(void) { @@ -1096,15 +1383,21 @@ Chapter 3. SSL Fucntion } -3.37 int SSL_want(const SSL *ssl); +3.37 int ``SSL_want``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : specifical statement + ssl - SSL point + + Return:: + + specifical statement - Description : get the SSL specifical statement + Description:: - Example : + get the SSL specifical statement + + Example:: void example(void) { @@ -1117,17 +1410,22 @@ Chapter 3. SSL Fucntion } -3.38 int SSL_want_nothing(const SSL *ssl); +3.38 int ``SSL_want_nothing``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 0 : false 1 : true - Description : check if SSL want nothing + Description:: - Example : + check if SSL want nothing + + Example:: void example(void) { @@ -1140,17 +1438,22 @@ Chapter 3. SSL Fucntion } -3.39 int SSL_want_read(const SSL *ssl); +3.39 int ``SSL_want_read``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 0 : false 1 : true - Description : check if SSL want to read + Description:: - Example : + check if SSL want to read + + Example:: void example(void) { @@ -1163,17 +1466,22 @@ Chapter 3. SSL Fucntion } -3.40 int SSL_want_write(const SSL *ssl); +3.40 int ``SSL_want_write``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: + + ssl - SSL point + + Return:: - Return : result 0 : false 1 : true - Description : check if SSL want to write + Description:: - Example : + check if SSL want to write + + Example:: void example(void) { @@ -1189,18 +1497,25 @@ Chapter 3. SSL Fucntion Chapter 4. SSL X509 Certification and Private Key Function ========================================================== -4.1 X509* d2i_X509(X509 **cert, const unsigned char *buffer, long len); - Arguments : cert - a point pointed to X509 certification - buffer - a point pointed to the certification context memory point - length - certification bytes +4.1 X509* ``d2i_X509``(X509 **cert, const unsigned char *buffer, long len) + + Arguments:: - Return : X509 certification object point + cert - a point pointed to X509 certification + buffer - a point pointed to the certification context memory point + length - certification bytes + + Return:: + + X509 certification object point - Description : load a character certification context into system context. If '*cert' is pointed to the - certification, then load certification into it. Or create a new X509 certification object + Description:: - Example : + load a character certification context into system context. If '*cert' is pointed to the + certification, then load certification into it. Or create a new X509 certification object + + Example:: void example(void) { @@ -1214,18 +1529,23 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.2 int SSL_add_client_CA(SSL *ssl, X509 *x); +4.2 int ``SSL_add_client_CA``(SSL *ssl, X509 *x) - Arguments : ssl - SSL point - x - CA certification point + Arguments:: - Return : result + ssl - SSL point + x - CA certification point + + Return:: + 1 : OK 0 : failed - Description : add CA client certification into the SSL + Description:: - Example : + add CA client certification into the SSL + + Example:: void example(void) { @@ -1239,18 +1559,23 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.3 int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x); +4.3 int ``SSL_CTX_add_client_CA``(SSL_CTX *ctx, X509 *x) - Arguments : ctx - SSL context point - x - CA certification point + Arguments:: - Return : result + ctx - SSL context point + x - CA certification point + + Return:: + 1 : OK 0 : failed - Description : add CA client certification into the SSL context + Description:: - Example : + add CA client certification into the SSL context + + Example:: void example(void) { @@ -1264,15 +1589,21 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.4 X509 *SSL_get_certificate(const SSL *ssl); +4.4 X509* ``SSL_get_certificate``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : SSL certification point + ssl - SSL point + + Return:: + + SSL certification point - Description : get the SSL certification point + Description:: - Example : + get the SSL certification point + + Example:: void example(void) { @@ -1285,15 +1616,21 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.5 long SSL_get_verify_result(const SSL *ssl); +4.5 long ``SSL_get_verify_result``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : the result of verifying + ssl - SSL point + + Return:: + + the result of verifying - Description : get the verifying result of the SSL certification + Description:: - Example : + get the verifying result of the SSL certification + + Example:: void example(void) { @@ -1306,18 +1643,23 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.6 int SSL_CTX_use_certificate(SSL_CTX *ctx, X509 *x); +4.6 int ``SSL_CTX_use_certificate``(SSL_CTX *ctx, X509 *x) - Arguments : ctx - the SSL context point - pkey - certification object point + Arguments:: + + ctx - the SSL context point + pkey - certification object point + + Return:: - Return : result 1 : OK 0 : failed - Description : load the certification into the SSL_CTX or SSL object + Description:: - Example : + load the certification into the SSL_CTX or SSL object + + Example:: void example(void) { @@ -1331,19 +1673,24 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.7 int SSL_CTX_use_certificate_ASN1(SSL_CTX *ctx, int len, const unsigned char *d); +4.7 int ``SSL_CTX_use_certificate_ASN1``(SSL_CTX *ctx, int len, const unsigned char *d) - Arguments : ctx - SSL context point - len - certification length - d - data point + Arguments:: - Return : result + ctx - SSL context point + len - certification length + d - data point + + Return:: + 1 : OK 0 : failed - Description : load the ASN1 certification into SSL context + Description:: - Example : + load the ASN1 certification into SSL context + + Example:: void example(void) { @@ -1358,18 +1705,23 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.8 int SSL_CTX_use_PrivateKey(SSL_CTX *ctx, EVP_PKEY *pkey); +4.8 int ``SSL_CTX_use_PrivateKey``(SSL_CTX *ctx, EVP_PKEY *pkey) - Arguments : ctx - SSL context point - pkey - private key object point + Arguments:: - Return : result + ctx - SSL context point + pkey - private key object point + + Return:: + 1 : OK 0 : failed - Description : load the private key into the context object + Description:: - Example : + load the private key into the context object + + Example:: void example(void) { @@ -1383,19 +1735,24 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.9 int SSL_CTX_use_PrivateKey_ASN1(int pk, SSL_CTX *ctx, const unsigned char *d, long len); +4.9 int ``SSL_CTX_use_PrivateKey_ASN1``(int pk, SSL_CTX *ctx, const unsigned char *d, long len) - Arguments : ctx - SSL context point - d - data point - len - private key length + Arguments:: + + ctx - SSL context point + d - data point + len - private key length + + Return:: - Return : result 1 : OK 0 : failed - Description : load the ASN1 private key into SSL context + Description:: - Example : + load the ASN1 private key into SSL context + + Example:: void example(void) { @@ -1411,19 +1768,24 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.10 int SSL_CTX_use_RSAPrivateKey_ASN1(SSL_CTX *ctx, const unsigned char *d, long len); +4.10 int ``SSL_CTX_use_RSAPrivateKey_ASN1``(SSL_CTX *ctx, const unsigned char *d, long len) - Arguments : ctx - SSL context point - d - data point - len - private key length + Arguments:: + + ctx - SSL context point + d - data point + len - private key length + + Return:: - Return : result 1 : OK 0 : failed - Description : load the RSA ASN1 private key into SSL context + Description:: - Example : + load the RSA ASN1 private key into SSL context + + Example:: void example(void) { @@ -1438,19 +1800,24 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.11 int SSL_use_certificate_ASN1(SSL *ssl, int len, const unsigned char *d); +4.11 int ``SSL_use_certificate_ASN1``(SSL *ssl, int len, const unsigned char *d) - Arguments : ssl - SSL point - len - data bytes - d - data point + Arguments:: + + ssl - SSL point + len - data bytes + d - data point + + Return:: - Return : result 1 : OK 0 : failed - Description : load certification into the SSL + Description:: - Example : + load certification into the SSL + + Example:: void example(void) { @@ -1465,15 +1832,21 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.12 X509 *SSL_get_peer_certificate(const SSL *ssl); +4.12 X509* ``SSL_get_peer_certificate``(const SSL *ssl) - Arguments : ssl - SSL point + Arguments:: - Return : peer certification + ssl - SSL point + + Return:: + + peer certification - Description : get peer certification + Description:: - Example : + get peer certification + + Example:: void example(void) { From de587a2e0d1418d45c9b7880ed07a68237975f3d Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Wed, 28 Sep 2016 20:46:45 +0800 Subject: [PATCH 38/95] components/openssl: fix .rst file encoding error --- components/openssl/OpenSSL-APIs.rst | 132 ++++++++++++++-------------- 1 file changed, 66 insertions(+), 66 deletions(-) diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst index cb90a23c93..6a8a68c1ff 100644 --- a/components/openssl/OpenSSL-APIs.rst +++ b/components/openssl/OpenSSL-APIs.rst @@ -18,7 +18,7 @@ Chapter 1. SSL Context Method Create ==================================== -1.1 const SSL_METHOD* ``SSLv23_client_method``(void) +1.1 const SSL_METHOD* ``SSLv23_client_method`` (void) Arguments:: @@ -42,7 +42,7 @@ Chapter 1. SSL Context Method Create } -1.2 const SSL_METHOD* ``TLSv1_client_method``(void) +1.2 const SSL_METHOD* ``TLSv1_client_method`` (void) Arguments:: @@ -66,7 +66,7 @@ Chapter 1. SSL Context Method Create } -1.3 const SSL_METHOD* ``SSLv3_client_method``(void) +1.3 const SSL_METHOD* ``SSLv3_client_method`` (void) Arguments:: @@ -90,7 +90,7 @@ Chapter 1. SSL Context Method Create } -1.4 const SSL_METHOD* ``TLSv1_1_client_method``(void) +1.4 const SSL_METHOD* ``TLSv1_1_client_method`` (void) Arguments:: @@ -114,7 +114,7 @@ Chapter 1. SSL Context Method Create } -1.5 const SSL_METHOD* ``TLSv1_2_client_method``(void) +1.5 const SSL_METHOD* ``TLSv1_2_client_method`` (void) Arguments:: @@ -138,7 +138,7 @@ Chapter 1. SSL Context Method Create } -1.6 const SSL_METHOD* ``SSLv23_server_method``(void) +1.6 const SSL_METHOD* ``SSLv23_server_method`` (void) Arguments:: @@ -162,7 +162,7 @@ Chapter 1. SSL Context Method Create } -1.7 const SSL_METHOD* ``TLSv1_1_server_method``(void) +1.7 const SSL_METHOD* ``TLSv1_1_server_method`` (void) Arguments:: @@ -186,7 +186,7 @@ Chapter 1. SSL Context Method Create } -1.8 const SSL_METHOD* ``TLSv1_2_server_method``(void) +1.8 const SSL_METHOD* ``TLSv1_2_server_method`` (void) Arguments:: @@ -210,7 +210,7 @@ Chapter 1. SSL Context Method Create } -1.9 const SSL_METHOD* ``TLSv1_server_method``(void) +1.9 const SSL_METHOD* ``TLSv1_server_method`` (void) Arguments:: @@ -234,7 +234,7 @@ Chapter 1. SSL Context Method Create } -1.10 const SSL_METHOD* ``SSLv3_server_method``(void) +1.10 const SSL_METHOD* ``SSLv3_server_method`` (void) Arguments:: @@ -263,7 +263,7 @@ Chapter 2. SSL Context Fucntion =============================== -2.1 SSL_CTX* ``SSL_CTX_new``(const SSL_METHOD *method) +2.1 SSL_CTX* ``SSL_CTX_new`` (const SSL_METHOD *method) Arguments:: @@ -287,7 +287,7 @@ Chapter 2. SSL Context Fucntion } -2.2 ``void SSL_CTX_free``(SSL_CTX *ctx) +2.2 ``void SSL_CTX_free`` (SSL_CTX *ctx) Arguments:: @@ -313,7 +313,7 @@ Chapter 2. SSL Context Fucntion } -2.3 ``int SSL_CTX_set_ssl_version``(SSL_CTX *ctx, const SSL_METHOD *meth) +2.3 ``int SSL_CTX_set_ssl_version`` (SSL_CTX *ctx, const SSL_METHOD *meth) Arguments:: @@ -342,7 +342,7 @@ Chapter 2. SSL Context Fucntion } -2.4 const SSL_METHOD* ``SSL_CTX_get_ssl_method``(SSL_CTX *ctx) +2.4 const SSL_METHOD* ``SSL_CTX_get_ssl_method`` (SSL_CTX *ctx) Arguments:: @@ -374,7 +374,7 @@ Chapter 3. SSL Fucntion ======================= -3.1 SSL* ``SSL_new``(SSL_CTX *ctx) +3.1 SSL* ``SSL_new`` (SSL_CTX *ctx) Arguments:: @@ -401,7 +401,7 @@ Chapter 3. SSL Fucntion } -3.2 void ``SSL_free``(SSL *ssl) +3.2 void ``SSL_free`` (SSL *ssl) Arguments:: @@ -427,7 +427,7 @@ Chapter 3. SSL Fucntion } -3.3 int ``SSL_do_handshake``(SSL *ssl) +3.3 int ``SSL_do_handshake`` (SSL *ssl) Arguments:: @@ -456,7 +456,7 @@ Chapter 3. SSL Fucntion } -3.4 int ``SSL_connect``(SSL *ssl) +3.4 int ``SSL_connect`` (SSL *ssl) Arguments:: @@ -485,7 +485,7 @@ Chapter 3. SSL Fucntion } -3.5 int ``SSL_accept``(SSL *ssl) +3.5 int ``SSL_accept`` (SSL *ssl) Arguments:: @@ -514,7 +514,7 @@ Chapter 3. SSL Fucntion } -3.6 int ``SSL_shutdown``(SSL *ssl) +3.6 int ``SSL_shutdown`` (SSL *ssl) Arguments:: @@ -543,7 +543,7 @@ Chapter 3. SSL Fucntion } -3.7 int ``SSL_clear``(SSL *ssl) +3.7 int ``SSL_clear`` (SSL *ssl) Arguments:: @@ -571,7 +571,7 @@ Chapter 3. SSL Fucntion } -3.8 int ``SSL_read``(SSL *ssl, void *buffer, int len) +3.8 int ``SSL_read`` (SSL *ssl, void *buffer, int len) Arguments:: @@ -603,7 +603,7 @@ Chapter 3. SSL Fucntion ret = SSL_read(ssl, buf, len); } -3.9 int ``SSL_write``(SSL *ssl, const void *buffer, int len) +3.9 int ``SSL_write`` (SSL *ssl, const void *buffer, int len) Arguments:: @@ -636,7 +636,7 @@ Chapter 3. SSL Fucntion } -3.10 ``SSL_CTX *SSL_get_SSL_CTX``(const SSL *ssl) +3.10 ``SSL_CTX *SSL_get_SSL_CTX`` (const SSL *ssl) Arguments:: @@ -663,7 +663,7 @@ Chapter 3. SSL Fucntion } -3.11 int ``SSL_get_shutdown``(const SSL *ssl) +3.11 int ``SSL_get_shutdown`` (const SSL *ssl) Arguments:: @@ -690,7 +690,7 @@ Chapter 3. SSL Fucntion } -3.12 void ``SSL_set_shutdown``(SSL *ssl, int mode) +3.12 void ``SSL_set_shutdown`` (SSL *ssl, int mode) Arguments:: @@ -717,7 +717,7 @@ Chapter 3. SSL Fucntion } -3.13 const SSL_METHOD* ``SSL_get_ssl_method``(SSL *ssl) +3.13 const SSL_METHOD* ``SSL_get_ssl_method`` (SSL *ssl) Arguments:: @@ -744,7 +744,7 @@ Chapter 3. SSL Fucntion } -3.14 int ``SSL_set_ssl_method``(SSL *ssl, const SSL_METHOD *method) +3.14 int ``SSL_set_ssl_method`` (SSL *ssl, const SSL_METHOD *method) Arguments:: @@ -774,7 +774,7 @@ Chapter 3. SSL Fucntion } -3.15 int ``SSL_pending``(const SSL *ssl) +3.15 int ``SSL_pending`` (const SSL *ssl) Arguments:: @@ -801,7 +801,7 @@ Chapter 3. SSL Fucntion } -3.16 int ``SSL_has_pending``(const SSL *ssl) +3.16 int ``SSL_has_pending`` (const SSL *ssl) Arguments:: @@ -829,7 +829,7 @@ Chapter 3. SSL Fucntion } -3.17 int ``SSL_get_fd``(const SSL *ssl) +3.17 int ``SSL_get_fd`` (const SSL *ssl) Arguments:: @@ -857,7 +857,7 @@ Chapter 3. SSL Fucntion } -3.18 int ``SSL_get_rfd``(const SSL *ssl) +3.18 int ``SSL_get_rfd`` (const SSL *ssl) Arguments:: @@ -885,7 +885,7 @@ Chapter 3. SSL Fucntion } -3.19 int ``SSL_get_wfd``(const SSL *ssl) +3.19 int ``SSL_get_wfd`` (const SSL *ssl) Arguments:: @@ -913,7 +913,7 @@ Chapter 3. SSL Fucntion } -3.20 int ``SSL_set_fd``(SSL *ssl, int fd) +3.20 int ``SSL_set_fd`` (SSL *ssl, int fd) Arguments:: @@ -943,7 +943,7 @@ Chapter 3. SSL Fucntion } -3.21 int ``SSL_set_rfd``(SSL *ssl, int fd) +3.21 int ``SSL_set_rfd`` (SSL *ssl, int fd) Arguments:: @@ -973,7 +973,7 @@ Chapter 3. SSL Fucntion } -3.22 int ``SSL_set_wfd``(SSL *ssl, int fd) +3.22 int ``SSL_set_wfd`` (SSL *ssl, int fd) Arguments:: @@ -1003,7 +1003,7 @@ Chapter 3. SSL Fucntion } -3.23 int ``SSL_version``(const SSL *ssl) +3.23 int ``SSL_version`` (const SSL *ssl) Arguments:: @@ -1030,7 +1030,7 @@ Chapter 3. SSL Fucntion } -3.24 const char* ``SSL_get_version``(const SSL *ssl) +3.24 const char* ``SSL_get_version`` (const SSL *ssl) Arguments:: @@ -1057,7 +1057,7 @@ Chapter 3. SSL Fucntion } -3.25 OSSL_HANDSHAKE_STATE ``SSL_get_state``(const SSL *ssl) +3.25 OSSL_HANDSHAKE_STATE ``SSL_get_state`` (const SSL *ssl) Arguments:: @@ -1084,7 +1084,7 @@ Chapter 3. SSL Fucntion } -3.26 const char* ``SSL_alert_desc_string``(int value) +3.26 const char* ``SSL_alert_desc_string`` (int value) Arguments:: @@ -1111,7 +1111,7 @@ Chapter 3. SSL Fucntion } -3.27 const char* ``SSL_alert_desc_string_long``(int value) +3.27 const char* ``SSL_alert_desc_string_long`` (int value) Arguments:: @@ -1138,7 +1138,7 @@ Chapter 3. SSL Fucntion } -3.28 const char* ``SSL_alert_type_string``(int value) +3.28 const char* ``SSL_alert_type_string`` (int value) Arguments:: @@ -1165,7 +1165,7 @@ Chapter 3. SSL Fucntion } -3.29 const char* ``SSL_alert_type_string_long``(int value) +3.29 const char* ``SSL_alert_type_string_long`` (int value) Arguments:: @@ -1191,7 +1191,7 @@ Chapter 3. SSL Fucntion str = SSL_alert_type_string_long(val); } -3.30 const char* ``SSL_rstate_string``(SSL *ssl) +3.30 const char* ``SSL_rstate_string`` (SSL *ssl) Arguments:: @@ -1218,7 +1218,7 @@ Chapter 3. SSL Fucntion } -3.31 const char* ``SSL_rstate_string_long``(SSL *ssl) +3.31 const char* ``SSL_rstate_string_long`` (SSL *ssl) Arguments:: @@ -1245,7 +1245,7 @@ Chapter 3. SSL Fucntion } -3.32 const char* ``SSL_state_string``(const SSL *ssl) +3.32 const char* ``SSL_state_string`` (const SSL *ssl) Arguments:: @@ -1272,7 +1272,7 @@ Chapter 3. SSL Fucntion } -3.33 char* ``SSL_state_string_long``(const SSL *ssl) +3.33 char* ``SSL_state_string_long`` (const SSL *ssl) Arguments:: @@ -1299,7 +1299,7 @@ Chapter 3. SSL Fucntion } -3.34 int ``SSL_get_error``(const SSL *ssl, int ret_code) +3.34 int ``SSL_get_error`` (const SSL *ssl, int ret_code) Arguments:: @@ -1327,7 +1327,7 @@ Chapter 3. SSL Fucntion err = SSL_get_error(ssl, ret); } -3.35 void ``SSL_CTX_set_default_read_buffer_len``(SSL_CTX *ctx, size_t len) +3.35 void ``SSL_CTX_set_default_read_buffer_len`` (SSL_CTX *ctx, size_t len) Arguments:: @@ -1355,7 +1355,7 @@ Chapter 3. SSL Fucntion } -3.36 void ``SSL_set_default_read_buffer_len``(SSL *ssl, size_t len) +3.36 void ``SSL_set_default_read_buffer_len`` (SSL *ssl, size_t len) Arguments:: @@ -1383,7 +1383,7 @@ Chapter 3. SSL Fucntion } -3.37 int ``SSL_want``(const SSL *ssl) +3.37 int ``SSL_want`` (const SSL *ssl) Arguments:: @@ -1410,7 +1410,7 @@ Chapter 3. SSL Fucntion } -3.38 int ``SSL_want_nothing``(const SSL *ssl) +3.38 int ``SSL_want_nothing`` (const SSL *ssl) Arguments:: @@ -1438,7 +1438,7 @@ Chapter 3. SSL Fucntion } -3.39 int ``SSL_want_read``(const SSL *ssl) +3.39 int ``SSL_want_read`` (const SSL *ssl) Arguments:: @@ -1466,7 +1466,7 @@ Chapter 3. SSL Fucntion } -3.40 int ``SSL_want_write``(const SSL *ssl) +3.40 int ``SSL_want_write`` (const SSL *ssl) Arguments:: @@ -1498,7 +1498,7 @@ Chapter 4. SSL X509 Certification and Private Key Function ========================================================== -4.1 X509* ``d2i_X509``(X509 **cert, const unsigned char *buffer, long len) +4.1 X509* ``d2i_X509`` (X509 **cert, const unsigned char *buffer, long len) Arguments:: @@ -1529,7 +1529,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.2 int ``SSL_add_client_CA``(SSL *ssl, X509 *x) +4.2 int ``SSL_add_client_CA`` (SSL *ssl, X509 *x) Arguments:: @@ -1559,7 +1559,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.3 int ``SSL_CTX_add_client_CA``(SSL_CTX *ctx, X509 *x) +4.3 int ``SSL_CTX_add_client_CA`` (SSL_CTX *ctx, X509 *x) Arguments:: @@ -1589,7 +1589,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.4 X509* ``SSL_get_certificate``(const SSL *ssl) +4.4 X509* ``SSL_get_certificate`` (const SSL *ssl) Arguments:: @@ -1616,7 +1616,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.5 long ``SSL_get_verify_result``(const SSL *ssl) +4.5 long ``SSL_get_verify_result`` (const SSL *ssl) Arguments:: @@ -1643,7 +1643,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.6 int ``SSL_CTX_use_certificate``(SSL_CTX *ctx, X509 *x) +4.6 int ``SSL_CTX_use_certificate`` (SSL_CTX *ctx, X509 *x) Arguments:: @@ -1673,7 +1673,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.7 int ``SSL_CTX_use_certificate_ASN1``(SSL_CTX *ctx, int len, const unsigned char *d) +4.7 int ``SSL_CTX_use_certificate_ASN1`` (SSL_CTX *ctx, int len, const unsigned char *d) Arguments:: @@ -1705,7 +1705,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.8 int ``SSL_CTX_use_PrivateKey``(SSL_CTX *ctx, EVP_PKEY *pkey) +4.8 int ``SSL_CTX_use_PrivateKey`` (SSL_CTX *ctx, EVP_PKEY *pkey) Arguments:: @@ -1735,7 +1735,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.9 int ``SSL_CTX_use_PrivateKey_ASN1``(int pk, SSL_CTX *ctx, const unsigned char *d, long len) +4.9 int ``SSL_CTX_use_PrivateKey_ASN1`` (int pk, SSL_CTX *ctx, const unsigned char *d, long len) Arguments:: @@ -1768,7 +1768,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.10 int ``SSL_CTX_use_RSAPrivateKey_ASN1``(SSL_CTX *ctx, const unsigned char *d, long len) +4.10 int ``SSL_CTX_use_RSAPrivateKey_ASN1`` (SSL_CTX *ctx, const unsigned char *d, long len) Arguments:: @@ -1800,7 +1800,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.11 int ``SSL_use_certificate_ASN1``(SSL *ssl, int len, const unsigned char *d) +4.11 int ``SSL_use_certificate_ASN1`` (SSL *ssl, int len, const unsigned char *d) Arguments:: @@ -1832,7 +1832,7 @@ Chapter 4. SSL X509 Certification and Private Key Function } -4.12 X509* ``SSL_get_peer_certificate``(const SSL *ssl) +4.12 X509* ``SSL_get_peer_certificate`` (const SSL *ssl) Arguments:: From 2033068a72fd122561be0d91b79c9a6b652f597e Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Sun, 9 Oct 2016 16:42:49 +0800 Subject: [PATCH 39/95] components/openssl: add internal openssl X509 debug function --- .../openssl/include/internal/ssl_methods.h | 6 ++- .../openssl/include/internal/ssl_types.h | 2 + components/openssl/include/openssl/ssl.h | 22 +++++++++++ components/openssl/include/platform/ssl_pm.h | 1 + components/openssl/library/ssl_methods.c | 2 +- components/openssl/library/ssl_x509.c | 9 +++++ components/openssl/platform/ssl_pm.c | 38 +++++++++++++++++++ 7 files changed, 77 insertions(+), 3 deletions(-) diff --git a/components/openssl/include/internal/ssl_methods.h b/components/openssl/include/internal/ssl_methods.h index 7a63b9e949..cd2f8c0533 100644 --- a/components/openssl/include/internal/ssl_methods.h +++ b/components/openssl/include/internal/ssl_methods.h @@ -71,12 +71,14 @@ #define IMPLEMENT_X509_METHOD(func_name, \ new, \ free, \ - load) \ + load, \ + show_info) \ const X509_METHOD* func_name(void) { \ static const X509_METHOD func_name##_data LOCAL_ATRR = { \ new, \ free, \ - load \ + load, \ + show_info \ }; \ return &func_name##_data; \ } diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index c571865c1e..19944c7819 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -275,6 +275,8 @@ struct x509_method_st { void (*x509_free)(X509 *x); int (*x509_load)(X509 *x, const unsigned char *buf, int len); + + int (*x509_show_info)(X509 *x); }; struct pkey_method_st { diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index 1d115214fd..d8400e66b5 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -447,6 +447,28 @@ int SSL_pending(const SSL *ssl); */ int SSL_want_nothing(const SSL *ssl); +/** + * @brief check if SSL want to read + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_read(const SSL *ssl); + +/** + * @brief check if SSL want to write + * + * @param ssl - SSL point + * + * @return result + * 0 : false + * 1 : true + */ +int SSL_want_write(const SSL *ssl); + /** * @brief get the SSL context current method * diff --git a/components/openssl/include/platform/ssl_pm.h b/components/openssl/include/platform/ssl_pm.h index cf1d213799..a516d57422 100644 --- a/components/openssl/include/platform/ssl_pm.h +++ b/components/openssl/include/platform/ssl_pm.h @@ -42,6 +42,7 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl); void ssl_pm_set_bufflen(SSL *ssl, int len); +int x509_pm_show_info(X509 *x); int x509_pm_new(X509 *x, X509 *m_x); void x509_pm_free(X509 *x); int x509_pm_load(X509 *x, const unsigned char *buffer, int len); diff --git a/components/openssl/library/ssl_methods.c b/components/openssl/library/ssl_methods.c index 8159511c49..0002360846 100644 --- a/components/openssl/library/ssl_methods.c +++ b/components/openssl/library/ssl_methods.c @@ -71,7 +71,7 @@ IMPLEMENT_SSL_METHOD(SSL3_VERSION, -1, TLS_method_func, SSLv3_method); */ IMPLEMENT_X509_METHOD(X509_method, x509_pm_new, x509_pm_free, - x509_pm_load); + x509_pm_load, x509_pm_show_info); /** * @brief get private key object method diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index d060419e6a..06e6e7b544 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -17,6 +17,14 @@ #include "ssl_dbg.h" #include "ssl_port.h" +/** + * @brief show X509 certification information + */ +int __X509_show_info(X509 *x) +{ + return X509_METHOD_CALL(show_info, x); +} + /** * @brief create a X509 certification object according to input X509 certification */ @@ -256,3 +264,4 @@ X509 *SSL_get_peer_certificate(const SSL *ssl) return ssl->session->peer; } + diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 4bc631382f..bbe290f2a3 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -31,6 +31,8 @@ #define DEBUG_LOAD_BUF_STRING(str) #endif +#define X509_INFO_STRING_LENGTH 1024 + struct ssl_pm { /* local socket file description */ @@ -370,6 +372,42 @@ OSSL_HANDSHAKE_STATE ssl_pm_get_state(const SSL *ssl) return state; } +int x509_pm_show_info(X509 *x) +{ + int ret; + char *buf; + mbedtls_x509_crt *x509_crt; + struct x509_pm *x509_pm = x->x509_pm; + + if (x509_pm->x509_crt) + x509_crt = x509_pm->x509_crt; + else if (x509_pm->ex_crt) + x509_crt = x509_pm->ex_crt; + else + x509_crt = NULL; + + if (!x509_crt) + return -1; + + buf = ssl_malloc(X509_INFO_STRING_LENGTH); + if (!buf) + SSL_RET(failed1, ""); + + ret = mbedtls_x509_crt_info(buf, X509_INFO_STRING_LENGTH - 1, "", x509_crt); + if (ret <= 0) + SSL_RET(failed2, ""); + buf[ret] = 0; + + SSL_PRINT("%s", buf); + + return 0; + +failed2: + ssl_free(buf); +failed1: + return -1; +} + int x509_pm_new(X509 *x, X509 *m_x) { struct x509_pm *x509_pm; From 47e83ee65e4861a79b4396fca00ee4fa9427886d Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Sun, 9 Oct 2016 17:49:16 +0800 Subject: [PATCH 40/95] components/openssl: add SSL any version function setting --- components/openssl/platform/ssl_pm.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index bbe290f2a3..539e954c78 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -111,16 +111,19 @@ int ssl_pm_new(SSL *ssl) if (ret) SSL_ERR(ret, failed2, "mbedtls_ssl_config_defaults:[-0x%x]\n", -ret); - if (TLS1_2_VERSION == ssl->version) - version = MBEDTLS_SSL_MINOR_VERSION_3; - 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; + if (TLS_ANY_VERSION != ssl->version) { + if (TLS1_2_VERSION == ssl->version) + version = MBEDTLS_SSL_MINOR_VERSION_3; + 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, version); + mbedtls_ssl_conf_min_version(&ssl_pm->conf, MBEDTLS_SSL_MAJOR_VERSION_3, version); + } mbedtls_ssl_conf_rng(&ssl_pm->conf, mbedtls_ctr_drbg_random, &ssl_pm->ctr_drbg); From 37a68ad6052b94ba4f3e969021eb5318bb4eb30f Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Sun, 9 Oct 2016 19:02:31 +0800 Subject: [PATCH 41/95] components/openssl: fix SSL X509 show message, leaking memory --- components/openssl/platform/ssl_pm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 539e954c78..eadd323e70 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -401,6 +401,8 @@ int x509_pm_show_info(X509 *x) SSL_RET(failed2, ""); buf[ret] = 0; + ssl_free(buf); + SSL_PRINT("%s", buf); return 0; From 034da95abb17974e5ed7ec0bfa9d1ba629636986 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Sun, 9 Oct 2016 19:18:18 +0800 Subject: [PATCH 42/95] components/openssl: change SSL read or write statement after success --- components/openssl/library/ssl_lib.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 267d23f25f..9740282d13 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -390,7 +390,8 @@ int SSL_read(SSL *ssl, void *buffer, int len) ret = SSL_METHOD_CALL(read, ssl, buffer, len); - ssl->rwstate = SSL_NOTHING; + if (ret == len) + ssl->rwstate = SSL_NOTHING; return ret; } @@ -428,12 +429,10 @@ int SSL_write(SSL *ssl, const void *buffer, int len) } } while (ret > 0 && send_bytes); - ssl->rwstate = SSL_NOTHING; - - send_bytes = len - send_bytes; - if (send_bytes >= 0) - ret = send_bytes; - else + if (ret >= 0) { + ret = len - send_bytes; + ssl->rwstate = SSL_NOTHING; + } else ret = -1; return ret; From ecefb1305a08ba5bad49894273a3c47f82fbe0ab Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 10 Oct 2016 10:40:00 +0800 Subject: [PATCH 43/95] components/openssl: change header file relationship of level --- components/openssl/include/internal/ssl_stack.h | 11 +++++++++++ components/openssl/include/internal/ssl_types.h | 11 ----------- components/openssl/include/openssl/ssl.h | 1 - 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/components/openssl/include/internal/ssl_stack.h b/components/openssl/include/internal/ssl_stack.h index b37c8dffa9..7a7051a026 100644 --- a/components/openssl/include/internal/ssl_stack.h +++ b/components/openssl/include/internal/ssl_stack.h @@ -7,6 +7,17 @@ #include "ssl_types.h" +#define STACK_OF(type) struct stack_st_##type + +#define SKM_DEFINE_STACK_OF(t1, t2, t3) \ + STACK_OF(t1); \ + static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \ + { \ + return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \ + } \ + +#define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) + /** * @brief create a openssl stack object * diff --git a/components/openssl/include/internal/ssl_types.h b/components/openssl/include/internal/ssl_types.h index 19944c7819..5aaee94176 100644 --- a/components/openssl/include/internal/ssl_types.h +++ b/components/openssl/include/internal/ssl_types.h @@ -37,17 +37,6 @@ typedef void BIO; #define X509_METHOD_CALL(f, x, ...) x->method->x509_##f(x, ##__VA_ARGS__) #define EVP_PKEY_METHOD_CALL(f, k, ...) k->method->pkey_##f(k, ##__VA_ARGS__) -#define STACK_OF(type) struct stack_st_##type - -#define SKM_DEFINE_STACK_OF(t1, t2, t3) \ - STACK_OF(t1); \ - static ossl_inline STACK_OF(t1) *sk_##t1##_new_null(void) \ - { \ - return (STACK_OF(t1) *)OPENSSL_sk_new_null(); \ - } \ - -#define DEFINE_STACK_OF(t) SKM_DEFINE_STACK_OF(t, t, t) - typedef int (*OPENSSL_sk_compfunc)(const void *, const void *); struct stack_st; diff --git a/components/openssl/include/openssl/ssl.h b/components/openssl/include/openssl/ssl.h index d8400e66b5..7f8eb88302 100644 --- a/components/openssl/include/openssl/ssl.h +++ b/components/openssl/include/openssl/ssl.h @@ -19,7 +19,6 @@ extern "C" { #endif -#include "platform/ssl_port.h" #include "internal/ssl_x509.h" #include "internal/ssl_pkey.h" From 5d60a1153d04ac90dd037b39bc79392bca72c02c Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 10 Oct 2016 11:18:45 +0800 Subject: [PATCH 44/95] components/openssl: Modify the documentation of OpenSSL-APIs 1. add description of non-supported APIs 2. remove non-supported APIs now 3. add more supported APIs --- components/openssl/OpenSSL-APIs.rst | 197 ++++++++++------------------ 1 file changed, 68 insertions(+), 129 deletions(-) diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst index 6a8a68c1ff..e7877b128c 100644 --- a/components/openssl/OpenSSL-APIs.rst +++ b/components/openssl/OpenSSL-APIs.rst @@ -1,10 +1,15 @@ OpenSSL-APIs -============ +------------ All original source code in this repository is Copyright (C) 2015-2016 Espressif Systems. This source code is licensed under the Apache License 2.0 as described in the file LICENSE. +OpenSSL APIs not mentioned in this article are not open to public for the time, +also do not have the corresponding function. +If user calls it directly, it will always return an error or may show cannot link +at compile time. + Chapter Introduction ==================== @@ -17,8 +22,7 @@ Chapter Introduction Chapter 1. SSL Context Method Create ==================================== - -1.1 const SSL_METHOD* ``SSLv23_client_method`` (void) +1.1 const SSL_METHOD* ``SSLv3_client_method`` (void) Arguments:: @@ -26,7 +30,7 @@ Chapter 1. SSL Context Method Create Return:: - SSLV2 and 3 version SSL context client method point + SSLV3.0 version SSL context client method point Description:: @@ -36,12 +40,11 @@ Chapter 1. SSL Context Method Create void example(void) { - const SSL_METHOD *method = SSLv23_client_method(); + const SSL_METHOD *method = SSLv3_client_method(); ... } - 1.2 const SSL_METHOD* ``TLSv1_client_method`` (void) Arguments:: @@ -65,32 +68,7 @@ Chapter 1. SSL Context Method Create ... } - -1.3 const SSL_METHOD* ``SSLv3_client_method`` (void) - - Arguments:: - - none - - Return:: - - SSLV3.0 version SSL context client method point - - Description:: - - create the target SSL context method - - Example:: - - void example(void) - { - const SSL_METHOD *method = SSLv3_client_method(); - - ... - } - - -1.4 const SSL_METHOD* ``TLSv1_1_client_method`` (void) +1.3 const SSL_METHOD* ``TLSv1_1_client_method`` (void) Arguments:: @@ -113,8 +91,7 @@ Chapter 1. SSL Context Method Create ... } - -1.5 const SSL_METHOD* ``TLSv1_2_client_method`` (void) +1.4 const SSL_METHOD* ``TLSv1_2_client_method`` (void) Arguments:: @@ -136,9 +113,31 @@ Chapter 1. SSL Context Method Create ... } + +1.5 const SSL_METHOD* ``TLS_client_method`` (void) + Arguments:: + + none + + Return:: + + TLSV1.2 version SSL context client method point + + Description:: + + create the default SSL context method, it's always to be TLSV1.2 + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_2_client_method(); + + ... + } -1.6 const SSL_METHOD* ``SSLv23_server_method`` (void) +1.6 const SSL_METHOD* ``SSLv3_server_method`` (void) Arguments:: @@ -146,7 +145,7 @@ Chapter 1. SSL Context Method Create Return:: - SSLV2 and 3 version SSL context server method point + SSLV3.0 version SSL context server method point Description:: @@ -156,13 +155,35 @@ Chapter 1. SSL Context Method Create void example(void) { - const SSL_METHOD *method = SSLv23_server_method(); + const SSL_METHOD *method = SSLv3_server_method(); ... } +1.7 const SSL_METHOD* ``TLSv1_server_method`` (void) -1.7 const SSL_METHOD* ``TLSv1_1_server_method`` (void) + Arguments:: + + none + + Return:: + + TLSV1.0 version SSL context server method point + + Description:: + + create the target SSL context method + + Example:: + + void example(void) + { + const SSL_METHOD *method = TLSv1_server_method(); + + ... + } + +1.8 const SSL_METHOD* ``TLSv1_1_server_method`` (void) Arguments:: @@ -186,7 +207,7 @@ Chapter 1. SSL Context Method Create } -1.8 const SSL_METHOD* ``TLSv1_2_server_method`` (void) +1.9 const SSL_METHOD* ``TLSv1_2_server_method`` (void) Arguments:: @@ -209,8 +230,7 @@ Chapter 1. SSL Context Method Create ... } - -1.9 const SSL_METHOD* ``TLSv1_server_method`` (void) +1.10 const SSL_METHOD* ``TLS_server_method`` (void) Arguments:: @@ -218,47 +238,22 @@ Chapter 1. SSL Context Method Create Return:: - TLSV1.0 version SSL context server method point + TLSV1.2 version SSL context server method point Description:: - create the target SSL context method + create the default SSL context method, it's always to be TLSV1.2 Example:: void example(void) { - const SSL_METHOD *method = TLSv1_server_method(); + const SSL_METHOD *method = TLSv1_2_server_method(); ... } -1.10 const SSL_METHOD* ``SSLv3_server_method`` (void) - - Arguments:: - - none - - Return:: - - SSLV3.0 version SSL context server method point - - Description:: - - create the target SSL context method - - Example:: - - void example(void) - { - const SSL_METHOD *method = SSLv3_server_method(); - - ... - } - - - Chapter 2. SSL Context Fucntion =============================== @@ -1326,64 +1321,8 @@ Chapter 3. SSL Fucntion err = SSL_get_error(ssl, ret); } - -3.35 void ``SSL_CTX_set_default_read_buffer_len`` (SSL_CTX *ctx, size_t len) - Arguments:: - - ctx - SSL context point - len - read buffer length - - Return:: - - none - - Description:: - - set the SSL context read buffer length - - Example:: - - void example(void) - { - SSL_CTX *ctx; - size_t len; - - ... ... - - SSL_CTX_set_default_read_buffer_len(ctx, len); - } - - -3.36 void ``SSL_set_default_read_buffer_len`` (SSL *ssl, size_t len) - - Arguments:: - - ssl - SSL point - len - read buffer length - - Return:: - - none - - Description:: - - set the SSL read buffer length - - Example:: - - void example(void) - { - SSL *ssl; - size_t len; - - ... ... - - SSL_set_default_read_buffer_len(ctx, len); - } - - -3.37 int ``SSL_want`` (const SSL *ssl) +3.35 int ``SSL_want`` (const SSL *ssl) Arguments:: @@ -1410,7 +1349,7 @@ Chapter 3. SSL Fucntion } -3.38 int ``SSL_want_nothing`` (const SSL *ssl) +3.36 int ``SSL_want_nothing`` (const SSL *ssl) Arguments:: @@ -1438,7 +1377,7 @@ Chapter 3. SSL Fucntion } -3.39 int ``SSL_want_read`` (const SSL *ssl) +3.37 int ``SSL_want_read`` (const SSL *ssl) Arguments:: @@ -1466,7 +1405,7 @@ Chapter 3. SSL Fucntion } -3.40 int ``SSL_want_write`` (const SSL *ssl) +3.38 int ``SSL_want_write`` (const SSL *ssl) Arguments:: From 28d83e766a64b52b3e5a1ed6e64aa6fe6797c667 Mon Sep 17 00:00:00 2001 From: Yinling Date: Mon, 17 Oct 2016 17:03:54 +0800 Subject: [PATCH 45/95] fix bug that deploy when test failed: test report will be a single stage. The result of test report will be calculated from the result of all test jobs in test stage. So it will only deploy when all test job passed. --- .gitlab-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index dd4049358a..5718cc542d 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,7 @@ stages: - build - test + - test_report - deploy before_script: @@ -106,13 +107,12 @@ test_build_system: - ./make/test_build_system.sh test_report: - stage: deploy + stage: test_report only: - master - triggers tags: - test_report - allow_failure: true variables: LOG_PATH: "$CI_PROJECT_DIR/$CI_BUILD_REF" TEST_CASE_FILE_PATH: "$CI_PROJECT_DIR/components/idf_test" @@ -121,7 +121,7 @@ test_report: when: always paths: - $REPORT_PATH - expire_in: 6 mos + expire_in: 12 mos script: # clone test bench - git clone $GITLAB_SSH_SERVER/yinling/auto_test_script.git From da706111965e471e9d0425e1b853aa63cc4e64d3 Mon Sep 17 00:00:00 2001 From: Angus Gratton Date: Thu, 13 Oct 2016 11:46:51 +1100 Subject: [PATCH 46/95] Deep sleep: Any source named rtc_wake_stub* is linked as RTC wake stub code Also move esp_deepsleep.h documentation out to docs/deep-sleep-stub.rst --- components/esp32/cpu_start.c | 8 +++ components/esp32/deepsleep.c | 3 +- components/esp32/include/esp_attr.h | 9 ++- components/esp32/include/esp_deepsleep.h | 36 +--------- components/esp32/include/esp_system.h | 1 + components/esp32/ld/esp32.common.ld | 44 ++++++++---- docs/deep-sleep-stub.rst | 87 ++++++++++++++++++++++++ 7 files changed, 134 insertions(+), 54 deletions(-) create mode 100644 docs/deep-sleep-stub.rst diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 7b2ccdc609..35f2efd477 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -19,6 +19,7 @@ #include "rom/ets_sys.h" #include "rom/uart.h" +#include "rom/rtc.h" #include "soc/cpu.h" #include "soc/dport_reg.h" @@ -59,6 +60,8 @@ extern void app_main(void); extern int _bss_start; extern int _bss_end; +extern int _rtc_bss_start; +extern int _rtc_bss_end; extern int _init_start; extern void (*__init_array_start)(void); extern void (*__init_array_end)(void); @@ -89,6 +92,11 @@ void IRAM_ATTR call_start_cpu0() memset(&_bss_start, 0, (&_bss_end - &_bss_start) * sizeof(_bss_start)); + /* Unless waking from deep sleep (implying RTC memory is intact), clear RTC bss */ + if (rtc_get_reset_reason(0) != DEEPSLEEP_RESET) { + memset(&_rtc_bss_start, 0, (&_rtc_bss_end - &_rtc_bss_start) * sizeof(_rtc_bss_start)); + } + // Initialize heap allocator heap_alloc_caps_init(); diff --git a/components/esp32/deepsleep.c b/components/esp32/deepsleep.c index 61268bce6b..742ff8cf40 100644 --- a/components/esp32/deepsleep.c +++ b/components/esp32/deepsleep.c @@ -40,8 +40,7 @@ void esp_set_deep_sleep_wake_stub(esp_deep_sleep_wake_stub_fn_t new_stub) } void RTC_IRAM_ATTR esp_default_wake_deep_sleep(void) { - // - //mmu_init(0); + /* Clear MMU for CPU 0 */ REG_SET_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR); REG_CLR_BIT(DPORT_PRO_CACHE_CTRL1_REG, DPORT_PRO_CACHE_MMU_IA_CLR); } diff --git a/components/esp32/include/esp_attr.h b/components/esp32/include/esp_attr.h index 156d2957f9..78aa3bd190 100644 --- a/components/esp32/include/esp_attr.h +++ b/components/esp32/include/esp_attr.h @@ -20,22 +20,21 @@ //and all variables in shared RAM. These macros can be used to redirect //particular functions/variables to other memory regions. -// Forces code into IRAM instead of flash +// Forces code into IRAM instead of flash. #define IRAM_ATTR __attribute__((section(".iram1"))) // Forces data into DRAM instead of flash #define DRAM_ATTR __attribute__((section(".dram1"))) -// Forces code into RTC fast memory +// Forces code into RTC fast memory. See "docs/deep-sleep-stub.rst" #define RTC_IRAM_ATTR __attribute__((section(".rtc.text"))) -// Forces data into RTC slow memory +// Forces data into RTC slow memory. See "docs/deep-sleep-stub.rst" // Any variable marked with this attribute will keep its value // during a deep sleep / wake cycle. #define RTC_DATA_ATTR __attribute__((section(".rtc.data"))) -// Forces read-only data into RTC slow memory -// Makes constant data available to RTC wake stubs (see esp_deepsleep.h) +// Forces read-only data into RTC slow memory. See "docs/deep-sleep-stub.rst" #define RTC_RODATA_ATTR __attribute__((section(".rtc.rodata"))) #endif /* __ESP_ATTR_H__ */ diff --git a/components/esp32/include/esp_deepsleep.h b/components/esp32/include/esp_deepsleep.h index 3683a8eeab..59b3129185 100644 --- a/components/esp32/include/esp_deepsleep.h +++ b/components/esp32/include/esp_deepsleep.h @@ -54,37 +54,7 @@ void system_deep_sleep(uint64_t time_in_us); * to run code immediately when the chip wakes from * sleep. * - * For example: - * @code - * void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { - * esp_default_wake_deep_sleep(); - * // Add additional functionality here - * } - * - * (Implementing this function is not required for normal operation, - * in the usual case your app will start normally when waking from - * deep sleep.) - * - * esp_wake_deep_sleep() functionality is limited: - * - * - Runs immediately on wake, so most of the SoC is freshly reset - - * flash is unmapped and hardware is otherwise uninitialised. - * - * - Can only call functions implemented in ROM, or marked RTC_IRAM_ATTR. - * - * - Static variables marked RTC_DATA_ATTR will have initial values on - * cold boot, and maintain these values between sleep/wake cycles. - * - * - Read-only data should be marked RTC_RODATA_ATTR. Strings must be - * declared as variables also using RTC_RODATA_ATTR, like this: - * RTC_RODATA_ATTR const char message[] = "Hello from very early boot!\n"; - * - * - Any other static memory will not be initialised (either to zero, - * or to any predefined value). - * - * - * - If you implement your own stub, the first call the stub makes - should be to esp_default_wake_deep_sleep(). + * See docs/deep-sleep-stub.rst for details. */ void esp_wake_deep_sleep(void); @@ -115,9 +85,7 @@ esp_deep_sleep_wake_stub_fn_t esp_get_deep_sleep_wake_stub(void); /* The default esp-idf-provided esp_wake_deep_sleep() stub. - If you replace esp_wake_deep_sleep() in your program, or use - esp_set_deep_sleep_wake_stub(), then it is recommended you call - esp_default_wake_deep_sleep() as the first function in your stub. + See docs/deep-sleep-stub.rst for details. */ void esp_default_wake_deep_sleep(void); diff --git a/components/esp32/include/esp_system.h b/components/esp32/include/esp_system.h index 84133366d7..8c6564c55b 100644 --- a/components/esp32/include/esp_system.h +++ b/components/esp32/include/esp_system.h @@ -16,6 +16,7 @@ #define __ESP_SYSTEM_H__ #include +#include #include "esp_err.h" #include "esp_deepsleep.h" diff --git a/components/esp32/ld/esp32.common.ld b/components/esp32/ld/esp32.common.ld index a3c6367840..991259a5e2 100644 --- a/components/esp32/ld/esp32.common.ld +++ b/components/esp32/ld/esp32.common.ld @@ -3,8 +3,38 @@ ENTRY(call_start_cpu0); SECTIONS { + /* RTC fast memory holds RTC wake stub code, + including from any source file named rtc_wake_stub*.c + */ + .rtc.text : + { + . = ALIGN(4); + *(.rtc.literal .rtc.text) + *rtc_wake_stub*.o(.literal .text .literal.* .text.*) + } >rtc_iram_seg + + /* RTC slow memory holds RTC wake stub + data/rodata, including from any source file + named rtc_wake_stub*.c + */ + .rtc.data : + { + *(.rtc.data) + *(.rtc.rodata) + *rtc_wake_stub*.o(.data .rodata .data.* .rodata.* .bss .bss.*) + } > rtc_slow_seg + + /* RTC bss, from any source file named rtc_wake_stub*.c */ + .rtc.bss (NOLOAD) : + { + _rtc_bss_start = ABSOLUTE(.); + *rtc_wake_stub*.o(.bss .bss.*) + *rtc_wake_stub*.o(COMMON) + _rtc_bss_end = ABSOLUTE(.); + } > rtc_slow_seg + /* Send .iram0 code to iram */ - .iram0.vectors : + .iram0.vectors : { /* Vectors go to IRAM */ _init_start = ABSOLUTE(.); @@ -153,16 +183,4 @@ SECTIONS _text_end = ABSOLUTE(.); _etext = .; } >iram0_2_seg - - .rtc.text : - { - . = ALIGN(4); - *(.rtc.literal .rtc.text) - } >rtc_iram_seg - - .rtc.data : - { - *(.rtc.data) - *(.rtc.rodata) - } > rtc_slow_seg } diff --git a/docs/deep-sleep-stub.rst b/docs/deep-sleep-stub.rst new file mode 100644 index 0000000000..983f8bbf26 --- /dev/null +++ b/docs/deep-sleep-stub.rst @@ -0,0 +1,87 @@ +Deep Sleep Wake Stubs +--------------------- + +ESP32 supports running a "deep sleep wake stub" when coming out of deep sleep. This function runs immediately as soon as the chip wakes up - before any normal initialisation, bootloader, or ESP-IDF code has run. After the wake stub runs, the SoC can go back to sleep or continue to start ESP-IDF normally. + +Deep sleep wake stub code is loaded into "RTC Fast Memory" and any data which it uses must also be loaded into RTC memory. RTC memory regions hold their contents during deep sleep. + +Rules for Wake Stubs +==================== + +Wake stub code must be carefully written: + +* As the SoC has freshly woken from sleep, most of the peripherals are in reset states. The SPI flash is unmapped. + +* The wake stub code can only call functions implemented in ROM or loaded into RTC Fast Memory (see below.) + +* The wake stub code can only access data loaded in RTC memory. All other RAM will be unintiailised and have random contents. The wake stub can use other RAM for temporary storage, but the contents will be overwritten when the SoC goes back to sleep or starts ESP-IDF. + +* RTC memory must include any read-only data (.rodata) used by the stub. + +* Data in RTC memory is initialised whenever the SoC restarts, except when waking from deep sleep. When waking from deep sleep, the values which were present before going to sleep are kept. + +* Wake stub code is a part of the main esp-idf app. During normal running of esp-idf, functions can call the wake stub functions or access RTC memory. It is as if these were regular parts of the app. + +Implementing A Stub +=================== + +The wake stub in esp-idf is called ``esp_wake_deep_sleep()``. This function runs whenever the SoC wakes from deep sleep. There is a default version of this function provided in esp-idf, but the default function is weak-linked so if your app contains a function named ``esp_wake_deep_sleep()` then this will override the default. + +If supplying a custom wake stub, the first thing it does should be to call ``esp_default_wake_deep_sleep()``. + +It is not necessary to implement ``esp_wake_deep_sleep()`` in your app in order to use deep sleep. It is only necessary if you want to have special behaviour immediately on wake. + +If you want to swap between different deep sleep stubs at runtime, it is also possible to do this by calling the ``esp_set_deep_sleep_wake_stub()`` function. This is not necessary if you only use the default ``esp_wake_deep_sleep()`` function. + +All of these functions are declared in the ``esp_deepsleep.h`` header under components/esp32. + +Loading Code Into RTC Memory +============================ + +Wake stub code must be resident in RTC Fast Memory. This can be done in one of two ways. + +The first way is to use the ``RTC_IRAM_ATTR`` attribute to place a function into RTC memory:: + + void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { + esp_default_wake_deep_sleep(); + // Add additional functionality here + } + +The second way is to place the function into any source file whose name starts with ``rtc_wake_stub``. Files names ``rtc_wake_stub*`` have their contents automatically put into RTC memory by the linker. + +The first way is simpler for very short and simple code, or for source files where you want to mix "normal" and "RTC" code. The second way is simpler when you want to write longer pieces of code for RTC memory. + + +Loading Data Into RTC Memory +============================ + +Data used by stub code must be resident in RTC Slow Memory. This memory is also used by the ULP. + +Specifying this data can be done in one of two ways: + +The first way is to use the ``RTC_DATA_ATTR`` and ``RTC_RODATA_ATTR`` to specify any data (writeable or read-only, respectivley) which should be loaded into RTC slow memory:: + + RTC_DATA_ATTR int wake_count; + + void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { + esp_default_wake_deep_sleep(); + static RTC_RODATA_ATTR const char fmt_str[] = "Wake count %d\n"; + ets_printf(fmt_str, wake_count++); + } + +Unfortunately, any string constants used in this way must be declared as arrays and marked with RTC_RODATA_ATTR, as shown in the example above. + +The second way is to place the data into any source file whose name starts with ``rtc_wake_stub``. + +For example, the equivalent example in ``rtc_wake_stub_counter.c``:: + + int wake_count; + + void RTC_IRAM_ATTR esp_wake_deep_sleep(void) { + esp_default_wake_deep_sleep(); + ets_printf("Wake count %d\n", wake_count++); + } + +The second way is a better option if you need to use strings, or write other more complex code. + + From 78392bf76b3d47ba290a0d97f443e695916416f5 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Fri, 28 Oct 2016 14:32:13 +0800 Subject: [PATCH 47/95] components/openssl: change the description 1. change the description of Makefile.projbuild 2. remove the license header in the API document 3. add private inlcuding header code in the components file --- components/openssl/Makefile.projbuild | 3 +-- components/openssl/OpenSSL-APIs.rst | 7 +------ components/openssl/component.mk | 3 ++- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/components/openssl/Makefile.projbuild b/components/openssl/Makefile.projbuild index b1d5641231..f8501f3187 100644 --- a/components/openssl/Makefile.projbuild +++ b/components/openssl/Makefile.projbuild @@ -1,3 +1,2 @@ -# Anyone compiling mbedTLS code needs the name of the -# alternative config file +# Anyone compiling openssl code needs the mbedtls library and header file diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst index e7877b128c..2b606dbcf2 100644 --- a/components/openssl/OpenSSL-APIs.rst +++ b/components/openssl/OpenSSL-APIs.rst @@ -1,14 +1,9 @@ OpenSSL-APIs ------------ -All original source code in this repository is Copyright (C) 2015-2016 -Espressif Systems. This source code is licensed under the Apache -License 2.0 as described in the file LICENSE. - OpenSSL APIs not mentioned in this article are not open to public for the time, also do not have the corresponding function. -If user calls it directly, it will always return an error or may show cannot link -at compile time. +If user calls it directly, it will always return an error or may show cannot link at compile time. Chapter Introduction ==================== diff --git a/components/openssl/component.mk b/components/openssl/component.mk index 97de6975c9..2dfcc6b38d 100644 --- a/components/openssl/component.mk +++ b/components/openssl/component.mk @@ -2,7 +2,8 @@ # Component Makefile # -COMPONENT_ADD_INCLUDEDIRS := include include/internal include/platform include/oepnssl +COMPONENT_ADD_INCLUDEDIRS := include +COMPONENT_PRIV_INCLUDEDIRS := include/internal include/platform include/openssl COMPONENT_SRCDIRS := library platform From 41a91d7cb9540f718811c62629aaca140d87ac08 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 31 Oct 2016 14:06:29 +0800 Subject: [PATCH 48/95] feature/openssl: change the description for docbook --- components/openssl/Makefile.projbuild | 2 -- components/openssl/OpenSSL-APIs.rst | 5 ++++- 2 files changed, 4 insertions(+), 3 deletions(-) delete mode 100644 components/openssl/Makefile.projbuild diff --git a/components/openssl/Makefile.projbuild b/components/openssl/Makefile.projbuild deleted file mode 100644 index f8501f3187..0000000000 --- a/components/openssl/Makefile.projbuild +++ /dev/null @@ -1,2 +0,0 @@ -# Anyone compiling openssl code needs the mbedtls library and header file - diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst index 2b606dbcf2..39fa0ebb9b 100644 --- a/components/openssl/OpenSSL-APIs.rst +++ b/components/openssl/OpenSSL-APIs.rst @@ -1,9 +1,12 @@ OpenSSL-APIs ------------ +This directory does not contain OpenSSL itself, but the code here can be used as a wrapper for applications using the OpenSSL API. +It uses mbedSSL to do the actual work, so anyone compiling openssl code needs the mbedtls library and header file. + OpenSSL APIs not mentioned in this article are not open to public for the time, also do not have the corresponding function. -If user calls it directly, it will always return an error or may show cannot link at compile time. +If user calls it directly, it will always return an error or may show cannot link at compiling time. Chapter Introduction ==================== From 9555ce291e094b8e9e25c1b6e4a36ee8d340ca14 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Mon, 31 Oct 2016 14:13:00 +0800 Subject: [PATCH 49/95] feature/openssl: correct wrong description --- components/openssl/OpenSSL-APIs.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/openssl/OpenSSL-APIs.rst b/components/openssl/OpenSSL-APIs.rst index 39fa0ebb9b..93e438dcf9 100644 --- a/components/openssl/OpenSSL-APIs.rst +++ b/components/openssl/OpenSSL-APIs.rst @@ -2,7 +2,7 @@ OpenSSL-APIs ------------ This directory does not contain OpenSSL itself, but the code here can be used as a wrapper for applications using the OpenSSL API. -It uses mbedSSL to do the actual work, so anyone compiling openssl code needs the mbedtls library and header file. +It uses mbedTLS to do the actual work, so anyone compiling openssl code needs the mbedtls library and header file. OpenSSL APIs not mentioned in this article are not open to public for the time, also do not have the corresponding function. From 2119b9846962c2b2d961fa13c26662a2be711e19 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 31 Oct 2016 19:08:56 +0800 Subject: [PATCH 50/95] spi_flash: remove unnecessary src pointer alignment check in spi_flash_write ROM SPIWrite routine can work with unaligned sources, so this check is unnecessary. Furthermore, it breaks nvs_set_str and nvs_get_blob when data pointer is unaligned. Also fix stray backslash in COUNTER_STOP macro --- components/spi_flash/flash_ops.c | 6 +----- components/spi_flash/include/esp_spi_flash.h | 4 ++-- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/components/spi_flash/flash_ops.c b/components/spi_flash/flash_ops.c index ae72568aa5..134e1fe65b 100644 --- a/components/spi_flash/flash_ops.c +++ b/components/spi_flash/flash_ops.c @@ -39,7 +39,7 @@ static spi_flash_counters_t s_flash_stats; #define COUNTER_STOP(counter) \ do{ \ s_flash_stats.counter.count++; \ - s_flash_stats.counter.time += (xthal_get_ccount() - ts_begin) / (XT_CLOCK_FREQ / 1000000); \\ + s_flash_stats.counter.time += (xthal_get_ccount() - ts_begin) / (XT_CLOCK_FREQ / 1000000); \ } while(0) #define COUNTER_ADD_BYTES(counter, size) \ @@ -126,10 +126,6 @@ esp_err_t IRAM_ATTR spi_flash_erase_range(uint32_t start_addr, uint32_t size) esp_err_t IRAM_ATTR spi_flash_write(size_t dest_addr, const void *src, size_t size) { - // TODO: replace this check with code which deals with unaligned sources - if (((ptrdiff_t) src) % 4 != 0) { - return ESP_ERR_INVALID_ARG; - } // Destination alignment is also checked in ROM code, but we can give // better error code here // TODO: add handling of unaligned destinations diff --git a/components/spi_flash/include/esp_spi_flash.h b/components/spi_flash/include/esp_spi_flash.h index c65eaa5836..840bbc4971 100644 --- a/components/spi_flash/include/esp_spi_flash.h +++ b/components/spi_flash/include/esp_spi_flash.h @@ -74,7 +74,7 @@ esp_err_t spi_flash_erase_range(size_t start_addr, size_t size); /** * @brief Write data to Flash. * - * @note Both des_addr and src_addr have to be 4-byte aligned. + * @note Address in flash, dest, has to be 4-byte aligned. * This is a temporary limitation which will be removed. * * @param dest destination address in Flash @@ -88,7 +88,7 @@ esp_err_t spi_flash_write(size_t dest, const void *src, size_t size); /** * @brief Read data from Flash. * - * @note Both des_addr and src_addr have to be 4-byte aligned. + * @note Both src and dest have to be 4-byte aligned. * This is a temporary limitation which will be removed. * * @param src source address of the data in Flash. From 269332f473b6e3b2960f53605dbac840ecedd60d Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 31 Oct 2016 19:11:40 +0800 Subject: [PATCH 51/95] nvs_flash: use CRC-32 routine compatible with ROM version Host tests used different flavour of CRC-32, which made it impossible to load NVS partition dumps created on the chip --- components/nvs_flash/test/crc.cpp | 64 ++++++++++++++++++++++--------- 1 file changed, 45 insertions(+), 19 deletions(-) diff --git a/components/nvs_flash/test/crc.cpp b/components/nvs_flash/test/crc.cpp index 288b58a323..4cbb9be9ec 100644 --- a/components/nvs_flash/test/crc.cpp +++ b/components/nvs_flash/test/crc.cpp @@ -14,25 +14,51 @@ #include #include -extern "C" unsigned long crc32_le(unsigned long crc_in, unsigned char const* data, unsigned int length) -{ - uint32_t i; - bool bit; - uint8_t c; - uint32_t crc = (uint32_t) crc_in; +static const unsigned int crc32_le_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, 0x706af48fL, 0xe963a535L, 0x9e6495a3L, + 0x0edb8832L, 0x79dcb8a4L, 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, 0x90bf1d91L, + 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, + 0x136c9856L, 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, 0xfa0f3d63L, 0x8d080df5L, + 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, + 0x26d930acL, 0x51de003aL, 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, 0xb8bda50fL, + 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, + 0x76dc4190L, 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, 0x9fbfe4a5L, 0xe8b8d433L, + 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, + 0x65b0d9c6L, 0x12b7e950L, 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, 0xfbd44c65L, + 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, + 0x4369e96aL, 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, 0xaa0a4c5fL, 0xdd0d7cc9L, + 0x5005713cL, 0x270241aaL, 0xbe0b1010L, 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, + + 0xedb88320L, 0x9abfb3b6L, 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, 0x73dc1683L, + 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, + 0xf00f9344L, 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, 0x196c3671L, 0x6e6b06e7L, + 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, + 0xd80d2bdaL, 0xaf0a1b4cL, 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, 0x4669be79L, + 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, + 0xc5ba3bbeL, 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, 0x2cd99e8bL, 0x5bdeae1dL, + 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, + 0x86d3d2d4L, 0xf1d4e242L, 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, 0x18b74777L, + 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, + 0xa00ae278L, 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, 0x4969474dL, 0x3e6e77dbL, + 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, 0xcdd70693L, 0x54de5729L, 0x23d967bfL, + 0xb3667a2eL, 0xc4614ab8L, 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, 0x2d02ef8dL +}; - while (length--) { - c = *data++; - for (i = 0x80; i > 0; i >>= 1) { - bit = crc & 0x80000000; - if (c & i) { - bit = !bit; - } - crc <<= 1; - if (bit) { - crc ^= 0x04c11db7; - } - } + + +extern "C" unsigned int crc32_le(unsigned int crc, unsigned char const * buf,unsigned int len) +{ + unsigned int i; + crc = ~crc; + for(i=0;i>8); } - return crc; + return ~crc; } + From 413f2c00f69ff6ce9777eab366280eb82cb3ac35 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 31 Oct 2016 19:17:25 +0800 Subject: [PATCH 52/95] nvs_flash: introduce write failures after each word written Previously the test bench would check failure recovery by introducing error after each write operation. This makes checks a bit more extensive (and much longer) by failing after every word written. Surprisingly, this change didn't expose any bugs. --- .../nvs_flash/test/spi_flash_emulation.h | 8 +++---- components/nvs_flash/test/test_nvs.cpp | 22 ++++++++++--------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/components/nvs_flash/test/spi_flash_emulation.h b/components/nvs_flash/test/spi_flash_emulation.h index ba50c4f9e4..4e544a39e2 100644 --- a/components/nvs_flash/test/spi_flash_emulation.h +++ b/components/nvs_flash/test/spi_flash_emulation.h @@ -74,11 +74,11 @@ public: return false; } - if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) { - return false; - } - for (size_t i = 0; i < size / 4; ++i) { + if (mFailCountdown != SIZE_MAX && mFailCountdown-- == 0) { + return false; + } + uint32_t sv = src[i]; size_t pos = dstAddr / 4 + i; uint32_t& dv = mData[pos]; diff --git a/components/nvs_flash/test/test_nvs.cpp b/components/nvs_flash/test/test_nvs.cpp index ce552578db..223e5dea9a 100644 --- a/components/nvs_flash/test/test_nvs.cpp +++ b/components/nvs_flash/test/test_nvs.cpp @@ -894,7 +894,7 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey size_t totalOps = 0; int lastPercent = -1; - for (uint32_t errDelay = 4; ; ++errDelay) { + for (uint32_t errDelay = 0; ; ++errDelay) { INFO(errDelay); emu.randomize(seed); emu.clearStats(); @@ -903,23 +903,25 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey if (totalOps != 0) { int percent = errDelay * 100 / totalOps; - if (percent != lastPercent) { + if (percent > lastPercent) { printf("%d/%d (%d%%)\r\n", errDelay, static_cast(totalOps), percent); lastPercent = percent; } } - TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); nvs_handle handle; - TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); - size_t count = iter_count; - if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) { - nvs_close(handle); - break; + + if (nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN) == ESP_OK) { + if (nvs_open("namespace1", NVS_READWRITE, &handle) == ESP_OK) { + if(test.doRandomThings(handle, gen, count) != ESP_ERR_FLASH_OP_FAIL) { + nvs_close(handle); + break; + } + nvs_close(handle); + } } - nvs_close(handle); TEST_ESP_OK(nvs_flash_init_custom(NVS_FLASH_SECTOR, NVS_FLASH_SECTOR_COUNT_MIN)); TEST_ESP_OK(nvs_open("namespace1", NVS_READWRITE, &handle)); @@ -929,7 +931,7 @@ TEST_CASE("test recovery from sudden poweroff", "[.][long][nvs][recovery][monkey CHECK(0); } nvs_close(handle); - totalOps = emu.getEraseOps() + emu.getWriteOps(); + totalOps = emu.getEraseOps() + emu.getWriteBytes() / 4; } } From d9cdc7de5811a450919518b5ea8d6a8edd0a960f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 31 Oct 2016 19:48:28 +0800 Subject: [PATCH 53/95] nvs_flash: don't allow more operation to be done on page in PageState::INVALID Currently a restart is required to recover a page from invalid state. The long-term solution is to detect such a condition and recover automatically (without a restart). This will be implemented in a separate change set. --- components/nvs_flash/src/nvs_page.cpp | 26 +++++--- .../nvs_flash/test/spi_flash_emulation.h | 12 ++++ components/nvs_flash/test/test_nvs.cpp | 62 +++++++++++++++++++ 3 files changed, 93 insertions(+), 7 deletions(-) diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index fae1f6f1b7..a10b88c976 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -3,7 +3,7 @@ // 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 @@ -131,8 +131,12 @@ esp_err_t Page::writeEntryData(const uint8_t* data, size_t size) esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, const void* data, size_t dataSize) { Item item; - esp_err_t err; + + if (mState == PageState::INVALID) { + return ESP_ERR_NVS_INVALID_STATE; + } + if (mState == PageState::UNINITIALIZED) { err = initialize(); if (err != ESP_OK) { @@ -166,7 +170,6 @@ esp_err_t Page::writeItem(uint8_t nsIndex, ItemType datatype, const char* key, c } // write first item - size_t span = (totalSize + ENTRY_SIZE - 1) / ENTRY_SIZE; item = Item(nsIndex, datatype, span, key); mHashList.insert(item, mNextFreeEntry); @@ -215,6 +218,11 @@ esp_err_t Page::readItem(uint8_t nsIndex, ItemType datatype, const char* key, vo { size_t index = 0; Item item; + + if (mState == PageState::INVALID) { + return ESP_ERR_NVS_INVALID_STATE; + } + esp_err_t rc = findItem(nsIndex, datatype, key, index, item); if (rc != ESP_OK) { return rc; @@ -478,6 +486,8 @@ esp_err_t Page::mLoadEntryTable() mState = PageState::INVALID; return err; } + + mHashList.insert(item, i); if (item.crc32 != item.calculateCrc32()) { err = eraseEntryAndSpan(i); @@ -488,8 +498,6 @@ esp_err_t Page::mLoadEntryTable() continue; } - mHashList.insert(item, i); - if (item.datatype != ItemType::BLOB && item.datatype != ItemType::SZ) { continue; } @@ -785,8 +793,12 @@ void Page::debugDump() const Item item; readEntry(i, item); if (skip == 0) { - printf("W ns=%2u type=%2u span=%3u key=\"%s\"\n", item.nsIndex, static_cast(item.datatype), item.span, item.key); - skip = item.span - 1; + printf("W ns=%2u type=%2u span=%3u key=\"%s\" len=%d\n", item.nsIndex, static_cast(item.datatype), item.span, item.key, (item.span != 1)?((int)item.varLength.dataSize):-1); + if (item.span > 0 && item.span <= ENTRY_COUNT - i) { + skip = item.span - 1; + } else { + skip = 0; + } } else { printf("D\n"); skip--; diff --git a/components/nvs_flash/test/spi_flash_emulation.h b/components/nvs_flash/test/spi_flash_emulation.h index 4e544a39e2..14e56bab6e 100644 --- a/components/nvs_flash/test/spi_flash_emulation.h +++ b/components/nvs_flash/test/spi_flash_emulation.h @@ -141,6 +141,18 @@ public: { return reinterpret_cast(mData.data()); } + + void load(const char* filename) + { + FILE* f = fopen(filename, "rb"); + fseek(f, 0, SEEK_END); + off_t size = ftell(f); + assert(size % SPI_FLASH_SEC_SIZE == 0); + mData.resize(size); + fseek(f, 0, SEEK_SET); + auto s = fread(mData.data(), SPI_FLASH_SEC_SIZE, size / SPI_FLASH_SEC_SIZE, f); + assert(s == static_cast(size / SPI_FLASH_SEC_SIZE)); + } void clearStats() { diff --git a/components/nvs_flash/test/test_nvs.cpp b/components/nvs_flash/test/test_nvs.cpp index 223e5dea9a..b70801f848 100644 --- a/components/nvs_flash/test/test_nvs.cpp +++ b/components/nvs_flash/test/test_nvs.cpp @@ -953,6 +953,68 @@ TEST_CASE("test for memory leaks in open/set", "[leaks]") } } +TEST_CASE("duplicate items are removed", "[nvs][dupes]") +{ + SpiFlashEmulator emu(3); + { + // create one item + nvs::Page p; + p.load(0); + p.writeItem(1, "opmode", 3); + } + { + // add another one without deleting the first one + nvs::Item item(1, ItemType::U8, 1, "opmode"); + item.data[0] = 2; + item.crc32 = item.calculateCrc32(); + emu.write(3 * 32, reinterpret_cast(&item), sizeof(item)); + uint32_t mask = 0xFFFFFFFA; + emu.write(32, &mask, 4); + } + { + // load page and check that second item persists + nvs::Page p; + p.load(0); + uint8_t val; + p.readItem(1, "opmode", val); + CHECK(val == 2); + CHECK(p.getErasedEntryCount() == 1); + CHECK(p.getUsedEntryCount() == 1); + } +} + +TEST_CASE("recovery after failure to write data", "[nvs]") +{ + SpiFlashEmulator emu(3); + // TODO: remove explicit alignment + const char str[] __attribute__((aligned(4))) = "value 0123456789abcdef012345678value 0123456789abcdef012345678"; + + // make flash write fail exactly in Page::writeEntryData + emu.failAfter(17); + { + Storage storage; + TEST_ESP_OK(storage.init(0, 3)); + + TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_FLASH_OP_FAIL); + + // check that repeated operations cause an error + TEST_ESP_ERR(storage.writeItem(1, ItemType::SZ, "key", str, strlen(str)), ESP_ERR_NVS_INVALID_STATE); + + uint8_t val; + TEST_ESP_ERR(storage.readItem(1, ItemType::U8, "key", &val, sizeof(val)), ESP_ERR_NVS_NOT_FOUND); + } + { + // load page and check that data was erased + Page p; + p.load(0); + CHECK(p.getErasedEntryCount() == 3); + CHECK(p.getUsedEntryCount() == 0); + + // try to write again + TEST_ESP_OK(p.writeItem(1, ItemType::SZ, "key", str, strlen(str))); + } +} + TEST_CASE("dump all performance data", "[nvs]") { std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl; From abea6c50f15f74c43f467a1179166ad031443b0a Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Mon, 31 Oct 2016 21:10:47 +0800 Subject: [PATCH 54/95] nvs_flash: delete all duplicate entries in a page while loading Due to previous flash write bug it was possible to create multiple duplicate entries in a single page. Recovery logic detected that case and bailed out with an assert. This change adds graceful recovery from this condition. Tests included. --- components/nvs_flash/src/nvs_page.cpp | 40 +++++++++++------- components/nvs_flash/test/test_nvs.cpp | 56 ++++++++++++++++++++++---- 2 files changed, 73 insertions(+), 23 deletions(-) diff --git a/components/nvs_flash/src/nvs_page.cpp b/components/nvs_flash/src/nvs_page.cpp index a10b88c976..23cefd1aad 100644 --- a/components/nvs_flash/src/nvs_page.cpp +++ b/components/nvs_flash/src/nvs_page.cpp @@ -301,6 +301,8 @@ esp_err_t Page::eraseEntryAndSpan(size_t index) } if (item.calculateCrc32() != item.crc32) { rc = alterEntryState(index, EntryState::ERASED); + --mUsedEntryCount; + ++mErasedEntryCount; if (rc != ESP_OK) { return rc; } @@ -473,7 +475,9 @@ esp_err_t Page::mLoadEntryTable() if (end > ENTRY_COUNT) { end = ENTRY_COUNT; } - for (size_t i = 0; i < end; ++i) { + size_t span; + for (size_t i = 0; i < end; i += span) { + span = 1; if (mEntryTable.get(i) == EntryState::ERASED) { lastItemIndex = INVALID_ENTRY; continue; @@ -488,6 +492,9 @@ esp_err_t Page::mLoadEntryTable() } mHashList.insert(item, i); + + // search for potential duplicate item + size_t duplicateIndex = mHashList.find(0, item); if (item.crc32 != item.calculateCrc32()) { err = eraseEntryAndSpan(i); @@ -498,23 +505,26 @@ esp_err_t Page::mLoadEntryTable() continue; } - if (item.datatype != ItemType::BLOB && item.datatype != ItemType::SZ) { - continue; - } - - size_t span = item.span; - bool needErase = false; - for (size_t j = i; j < i + span; ++j) { - if (mEntryTable.get(j) != EntryState::WRITTEN) { - needErase = true; - lastItemIndex = INVALID_ENTRY; - break; + + if (item.datatype == ItemType::BLOB || item.datatype == ItemType::SZ) { + span = item.span; + bool needErase = false; + for (size_t j = i; j < i + span; ++j) { + if (mEntryTable.get(j) != EntryState::WRITTEN) { + needErase = true; + lastItemIndex = INVALID_ENTRY; + break; + } + } + if (needErase) { + eraseEntryAndSpan(i); + continue; } } - if (needErase) { - eraseEntryAndSpan(i); + + if (duplicateIndex < i) { + eraseEntryAndSpan(duplicateIndex); } - i += span - 1; } // check that last item is not duplicate diff --git a/components/nvs_flash/test/test_nvs.cpp b/components/nvs_flash/test/test_nvs.cpp index b70801f848..528c9df686 100644 --- a/components/nvs_flash/test/test_nvs.cpp +++ b/components/nvs_flash/test/test_nvs.cpp @@ -963,22 +963,27 @@ TEST_CASE("duplicate items are removed", "[nvs][dupes]") p.writeItem(1, "opmode", 3); } { - // add another one without deleting the first one + // add another two without deleting the first one nvs::Item item(1, ItemType::U8, 1, "opmode"); item.data[0] = 2; item.crc32 = item.calculateCrc32(); emu.write(3 * 32, reinterpret_cast(&item), sizeof(item)); - uint32_t mask = 0xFFFFFFFA; + emu.write(4 * 32, reinterpret_cast(&item), sizeof(item)); + uint32_t mask = 0xFFFFFFEA; emu.write(32, &mask, 4); } { // load page and check that second item persists - nvs::Page p; - p.load(0); + nvs::Storage s; + s.init(0, 3); uint8_t val; - p.readItem(1, "opmode", val); + ESP_ERROR_CHECK(s.readItem(1, "opmode", val)); CHECK(val == 2); - CHECK(p.getErasedEntryCount() == 1); + } + { + Page p; + p.load(0); + CHECK(p.getErasedEntryCount() == 2); CHECK(p.getUsedEntryCount() == 1); } } @@ -986,8 +991,7 @@ TEST_CASE("duplicate items are removed", "[nvs][dupes]") TEST_CASE("recovery after failure to write data", "[nvs]") { SpiFlashEmulator emu(3); - // TODO: remove explicit alignment - const char str[] __attribute__((aligned(4))) = "value 0123456789abcdef012345678value 0123456789abcdef012345678"; + const char str[] = "value 0123456789abcdef012345678value 0123456789abcdef012345678"; // make flash write fail exactly in Page::writeEntryData emu.failAfter(17); @@ -1015,6 +1019,42 @@ TEST_CASE("recovery after failure to write data", "[nvs]") } } +TEST_CASE("crc error in variable length item is handled", "[nvs]") +{ + SpiFlashEmulator emu(3); + const uint64_t before_val = 0xbef04e; + const uint64_t after_val = 0xaf7e4; + // write some data + { + Page p; + p.load(0); + TEST_ESP_OK(p.writeItem(0, "before", before_val)); + const char* str = "foobar"; + TEST_ESP_OK(p.writeItem(0, ItemType::SZ, "key", str, strlen(str))); + TEST_ESP_OK(p.writeItem(0, "after", after_val)); + } + // corrupt some data + uint32_t w; + CHECK(emu.read(&w, 32 * 3 + 8, sizeof(w))); + w &= 0xf000000f; + CHECK(emu.write(32 * 3 + 8, &w, sizeof(w))); + // load and check + { + Page p; + p.load(0); + CHECK(p.getUsedEntryCount() == 2); + CHECK(p.getErasedEntryCount() == 2); + + uint64_t val; + TEST_ESP_OK(p.readItem(0, "before", val)); + CHECK(val == before_val); + TEST_ESP_ERR(p.findItem(0, ItemType::SZ, "key"), ESP_ERR_NVS_NOT_FOUND); + TEST_ESP_OK(p.readItem(0, "after", val)); + CHECK(val == after_val); + } +} + + TEST_CASE("dump all performance data", "[nvs]") { std::cout << "====================" << std::endl << "Dumping benchmarks" << std::endl; From 92b663d9f214180486f46c5c6926f518b345083b Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Mon, 31 Oct 2016 21:26:33 +0800 Subject: [PATCH 55/95] lwip: optimize tx flow control 1. Remove tx flow control for TCP 2. Remove tx flow control for UDP temporary 3. Return the error code when call esp_wifi_internal_tx() --- components/lwip/api/sockets.c | 5 +++-- components/lwip/port/netif/wlanif.c | 7 ++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/components/lwip/api/sockets.c b/components/lwip/api/sockets.c index 455d007ea7..df658578af 100755 --- a/components/lwip/api/sockets.c +++ b/components/lwip/api/sockets.c @@ -395,12 +395,15 @@ static void lwip_socket_drop_registered_memberships(int s); */ static inline void esp32_tx_flow_ctrl(void) { +//TODO we need to do flow control for UDP +#if 0 uint8_t _wait_delay = 1; while ((system_get_free_heap_size() < HEAP_HIGHWAT) || esp_wifi_internal_tx_is_stop()){ vTaskDelay(_wait_delay/portTICK_RATE_MS); if (_wait_delay < 64) _wait_delay *= 2; } +#endif } #else @@ -1208,8 +1211,6 @@ lwip_send(int s, const void *data, size_t size, int flags) #endif /* (LWIP_UDP || LWIP_RAW) */ } - esp32_tx_flow_ctrl(); - write_flags = NETCONN_COPY | ((flags & MSG_MORE) ? NETCONN_MORE : 0) | ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); diff --git a/components/lwip/port/netif/wlanif.c b/components/lwip/port/netif/wlanif.c index 548bb7f970..ffad69cd46 100755 --- a/components/lwip/port/netif/wlanif.c +++ b/components/lwip/port/netif/wlanif.c @@ -142,16 +142,13 @@ low_level_output(struct netif *netif, struct pbuf *p) } } - esp_wifi_internal_tx(wifi_if, q->payload, pbuf_x_len); - return ERR_OK; - + return esp_wifi_internal_tx(wifi_if, q->payload, pbuf_x_len); #else for(q = p; q != NULL; q = q->next) { esp_wifi_internal_tx(wifi_if, q->payload, q->len); } -#endif - return ERR_OK; +#endif } /** From 41514f497aa5965a7b8b238392205d11c6c8805b Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 23 Oct 2016 22:12:34 +0200 Subject: [PATCH 56/95] Renamed .md to .rst --- CONTRIBUTING.md => CONTRIBUTING.rst | 15 ++++++++++----- README.md => README.rst | 29 ++++++++++++++++++++--------- 2 files changed, 30 insertions(+), 14 deletions(-) rename CONTRIBUTING.md => CONTRIBUTING.rst (91%) rename README.md => README.rst (86%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.rst similarity index 91% rename from CONTRIBUTING.md rename to CONTRIBUTING.rst index b0af761d53..a6e759eb18 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.rst @@ -1,12 +1,15 @@ -# Contributions Guide +Contributions Guide +=================== We welcome contributions to the esp-idf project! -## How to Contribute +How to Contribute +----------------- Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via [Github Pull Requests](https://help.github.com/articles/about-pull-requests/). -## Before Contributing +Before Contributing +------------------- Before sending us a Pull Request, please consider this list of points: @@ -24,7 +27,8 @@ Before sending us a Pull Request, please consider this list of points: * If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback. -## Pull Request Process +Pull Request Process +-------------------- After you open the Pull Request, there will probably be some discussion in the comments field of the request itself. @@ -32,6 +36,7 @@ Once the Pull Request is ready to merge, it will first be merged into our intern If this process passes, it will be merged onto the public github repository. -## Legal Part +Legal Part +---------- Before a contribution can be accepted, you will need to sign our [Contributor Agreement](docs/contributor-agreement.rst). You will be prompted for this automatically as part of the Pull Request process. diff --git a/README.md b/README.rst similarity index 86% rename from README.md rename to README.rst index ff645c3392..65d6167673 100644 --- a/README.md +++ b/README.rst @@ -1,6 +1,10 @@ -# Using Espressif IoT Development Framework with the ESP32 +Using Espressif IoT Development Framework with the ESP32 +======================================================== -# Setting Up ESP-IDF +|docs| + +Setting Up ESP-IDF +------------------ In the [docs](docs) directory you will find per-platform setup guides: @@ -8,23 +12,27 @@ In the [docs](docs) directory you will find per-platform setup guides: * [Mac OS Setup Guide](docs/macos-setup.rst) * [Linux Setup Guide](docs/linux-setup.rst) -# Finding A Project +Finding A Project +----------------- As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, esp-idf comes with some example projects in the [examples](examples) directory. Once you've found the project you want to work with, change to its directory and you can configure and build it: -# Configuring your project +Configuring your project +------------------------ `make menuconfig` -# Compiling your project +Compiling your project +---------------------- `make all` ... will compile app, bootloader and generate a partition table based on the config. -# Flashing your project +Flashing your project +--------------------- When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running: @@ -34,7 +42,8 @@ This will flash the entire project (app, bootloader and partition table) to a ne You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it. -# Compiling & Flashing Just the App +Compiling & Flashing Just the App +--------------------------------- After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table: @@ -45,7 +54,8 @@ After the initial flash, you may just want to build and flash just your app, not (There's no downside to reflashing the bootloader and partition table each time, if they haven't changed.) -# The Partition Table +The Partition Table +------------------- Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader. @@ -62,7 +72,8 @@ In both cases the factory app is flashed at offset 0x10000. If you `make partiti For more details about partition tables and how to create custom variations, view the `docs/partition_tables.rst` file. -# Resources +Resources +--------- * The [docs directory of the esp-idf repository](docs) contains esp-idf documentation. From ec99397c3ea057903fba8cf12e1360df0727baae Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 23 Oct 2016 22:14:24 +0200 Subject: [PATCH 57/95] Initial Sphinx / ReadTheDocs.org configuration --- docs/Doxyfile | 12 ++ docs/Makefile | 177 +++++++++++++++++++++++++++ docs/_static/1.png | Bin 0 -> 11412 bytes docs/conf.py | 270 ++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 88 ++++++++++++++ docs/requirements.txt | 1 + 6 files changed, 548 insertions(+) create mode 100644 docs/Doxyfile create mode 100644 docs/Makefile create mode 100644 docs/_static/1.png create mode 100644 docs/conf.py create mode 100644 docs/index.rst create mode 100644 docs/requirements.txt diff --git a/docs/Doxyfile b/docs/Doxyfile new file mode 100644 index 0000000000..795bfa5e89 --- /dev/null +++ b/docs/Doxyfile @@ -0,0 +1,12 @@ +PROJECT_NAME = "ESP32 Programming Guide" +XML_OUTPUT = xml +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = ../components/driver/include +RECURSIVE = YES +QUIET = YES +JAVADOC_AUTOBRIEF = YES +GENERATE_HTML = NO +GENERATE_XML = YES \ No newline at end of file diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000000..c04268ff1d --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,177 @@ +# Makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +PAPER = +BUILDDIR = _build + +# User-friendly check for sphinx-build +ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) +$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) +endif + +# Internal variables. +PAPEROPT_a4 = -D latex_paper_size=a4 +PAPEROPT_letter = -D latex_paper_size=letter +ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . +# the i18n builder cannot share the environment and doctrees with the others +I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . + +.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext + +help: + @echo "Please use \`make ' where is one of" + @echo " html to make standalone HTML files" + @echo " dirhtml to make HTML files named index.html in directories" + @echo " singlehtml to make a single large HTML file" + @echo " pickle to make pickle files" + @echo " json to make JSON files" + @echo " htmlhelp to make HTML files and a HTML help project" + @echo " qthelp to make HTML files and a qthelp project" + @echo " devhelp to make HTML files and a Devhelp project" + @echo " epub to make an epub" + @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" + @echo " latexpdf to make LaTeX files and run them through pdflatex" + @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" + @echo " text to make text files" + @echo " man to make manual pages" + @echo " texinfo to make Texinfo files" + @echo " info to make Texinfo files and run them through makeinfo" + @echo " gettext to make PO message catalogs" + @echo " changes to make an overview of all changed/added/deprecated items" + @echo " xml to make Docutils-native XML files" + @echo " pseudoxml to make pseudoxml-XML files for display purposes" + @echo " linkcheck to check all external links for integrity" + @echo " doctest to run all doctests embedded in the documentation (if enabled)" + +clean: + rm -rf $(BUILDDIR)/* + +html: + $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +dirhtml: + $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." + +singlehtml: + $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml + @echo + @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." + +pickle: + $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle + @echo + @echo "Build finished; now you can process the pickle files." + +json: + $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json + @echo + @echo "Build finished; now you can process the JSON files." + +htmlhelp: + $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp + @echo + @echo "Build finished; now you can run HTML Help Workshop with the" \ + ".hhp project file in $(BUILDDIR)/htmlhelp." + +qthelp: + $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp + @echo + @echo "Build finished; now you can run "qcollectiongenerator" with the" \ + ".qhcp project file in $(BUILDDIR)/qthelp, like this:" + @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhcp" + @echo "To view the help file:" + @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/ReadtheDocsTemplate.qhc" + +devhelp: + $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp + @echo + @echo "Build finished." + @echo "To view the help file:" + @echo "# mkdir -p $$HOME/.local/share/devhelp/ReadtheDocsTemplate" + @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/ReadtheDocsTemplate" + @echo "# devhelp" + +epub: + $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub + @echo + @echo "Build finished. The epub file is in $(BUILDDIR)/epub." + +latex: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo + @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." + @echo "Run \`make' in that directory to run these through (pdf)latex" \ + "(use \`make latexpdf' here to do that automatically)." + +latexpdf: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through pdflatex..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +latexpdfja: + $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex + @echo "Running LaTeX files through platex and dvipdfmx..." + $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja + @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." + +text: + $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text + @echo + @echo "Build finished. The text files are in $(BUILDDIR)/text." + +man: + $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man + @echo + @echo "Build finished. The manual pages are in $(BUILDDIR)/man." + +texinfo: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo + @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." + @echo "Run \`make' in that directory to run these through makeinfo" \ + "(use \`make info' here to do that automatically)." + +info: + $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo + @echo "Running Texinfo files through makeinfo..." + make -C $(BUILDDIR)/texinfo info + @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." + +gettext: + $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale + @echo + @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." + +changes: + $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes + @echo + @echo "The overview file is in $(BUILDDIR)/changes." + +linkcheck: + $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck + @echo + @echo "Link check complete; look for any errors in the above output " \ + "or in $(BUILDDIR)/linkcheck/output.txt." + +doctest: + $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest + @echo "Testing of doctests in the sources finished, look at the " \ + "results in $(BUILDDIR)/doctest/output.txt." + +xml: + $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml + @echo + @echo "Build finished. The XML files are in $(BUILDDIR)/xml." + +pseudoxml: + $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml + @echo + @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/docs/_static/1.png b/docs/_static/1.png new file mode 100644 index 0000000000000000000000000000000000000000..4920892781f90c3db323f82033866c3f7116c073 GIT binary patch literal 11412 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
I-V-NX(N}q}D@(Dr+V{Hb>y4lN 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 U;S}7@z`(%Z>FVdQ&MBb@0LNnn&j0`b literal 0 HcmV?d00001 diff --git a/docs/conf.py b/docs/conf.py new file mode 100644 index 0000000000..7c4614d458 --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,270 @@ +# -*- coding: utf-8 -*- +# +# Read the Docs Template documentation build configuration file, created by +# sphinx-quickstart on Tue Aug 26 14:19:49 2014. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys +import os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +#sys.path.insert(0, os.path.abspath('.')) + +# run doxygen +# +# for implementation on readthedocs.org check +# https://github.com/rtfd/readthedocs.org/issues/388 +# +from subprocess import call +call('doxygen') + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +#needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['breathe'] + +# Breathe extension variables +breathe_projects = { "esp32-idf": "xml/" } +breathe_default_project = "esp32-idf" + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Read the Docs Template' +copyright = u'2014, Read the Docs' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '1.0' +# The full version, including alpha/beta/rc tags. +release = '1.0' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all +# documents. +#default_role = None + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + +# If true, keep warnings as "system message" paragraphs in the built documents. +#keep_warnings = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Add any extra paths that contain custom files (such as robots.txt or +# .htaccess) here, relative to this directory. These files are copied +# directly to the root of the documentation. +#html_extra_path = [] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'ReadtheDocsTemplatedoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { +# The paper size ('letterpaper' or 'a4paper'). +#'papersize': 'letterpaper', + +# The font size ('10pt', '11pt' or '12pt'). +#'pointsize': '10pt', + +# Additional stuff for the LaTeX preamble. +#'preamble': '', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + ('index', 'ReadtheDocsTemplate.tex', u'Read the Docs Template Documentation', + u'Read the Docs', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'readthedocstemplate', u'Read the Docs Template Documentation', + [u'Read the Docs'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'ReadtheDocsTemplate', u'Read the Docs Template Documentation', + u'Read the Docs', 'ReadtheDocsTemplate', 'One line description of project.', + 'Miscellaneous'), +] + +# Documents to append as an appendix to all manuals. +#texinfo_appendices = [] + +# If false, no module index is generated. +#texinfo_domain_indices = True + +# How to display URL addresses: 'footnote', 'no', or 'inline'. +#texinfo_show_urls = 'footnote' + +# If true, do not generate a @detailmenu in the "Top" node's menu. +#texinfo_no_detailmenu = False diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000000..f74a3acae1 --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,88 @@ +.. Read the Docs Template documentation master file + +Welcome to ESP32 Programming Guide +================================== + + +Example C functions +------------------- + +.. c:function:: esp_err_t esp_wifi_get_ap_list (uint16_t *number, wifi_ap_list_t *ap_list) + +.. c:function:: esp_err_t esp_wifi_set_protocol (wifi_interface_t ifx, uint8_t protocol_bitmap) + + +Example C function integration +------------------------------ + +.. doxygenfunction:: esp_wifi_init +.. doxygenfunction:: esp_wifi_set_config + +.. doxygenfunction:: gpio_isr_register +.. doxygenfunction:: ledc_timer_set + + +Example C enum integration +-------------------------- + +.. doxygenenum:: wifi_auth_mode_t + + +Example C struct integration +---------------------------- + +.. doxygenstruct:: wifi_scan_config_t + :members: + + +Contents: + +.. About - TBA + +.. toctree:: + :caption: Toolchain Setup + :maxdepth: 1 + + windows-setup + linux-setup + macos-setup + eclipse-setup + +.. API Reference - TBA + +.. Technical Reference - TBA + +.. toctree:: + :caption: Debugging + :maxdepth: 1 + + openocd + +.. Resources - TBA + +.. toctree:: + :caption: Contribute + :maxdepth: 1 + + contributing + contributor-agreement + +.. toctree:: + :caption: Copyrights and Licenses + :maxdepth: 1 + + COPYRIGHT + +.. toctree:: + :caption: Flapping Documents + :maxdepth: 1 + + partition-tables + build_system + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/docs/requirements.txt b/docs/requirements.txt new file mode 100644 index 0000000000..188f51e62d --- /dev/null +++ b/docs/requirements.txt @@ -0,0 +1 @@ +breathe \ No newline at end of file From 99fc7600888ae76252772ac544aed3a8399c1de6 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 23 Oct 2016 22:15:13 +0200 Subject: [PATCH 58/95] Link to file a folder up --- docs/contributing.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 docs/contributing.rst diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 0000000000..3bdd7dc21a --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.rst \ No newline at end of file From cb70ac831f3430175cbb8f230e48ce2c8b164f28 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 23 Oct 2016 22:25:28 +0200 Subject: [PATCH 59/95] Increased buikd coverage of DoxyGen --- docs/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Doxyfile b/docs/Doxyfile index 795bfa5e89..23f6f1a2d7 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -4,7 +4,7 @@ GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO -INPUT = ../components/driver/include +INPUT = ../components RECURSIVE = YES QUIET = YES JAVADOC_AUTOBRIEF = YES From 6435a71de2b9b9e5a3c731f630cf0dc8a33953ac Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 23 Oct 2016 22:31:15 +0200 Subject: [PATCH 60/95] Reduced the build coverage by DoxyGen --- docs/Doxyfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Doxyfile b/docs/Doxyfile index 23f6f1a2d7..795bfa5e89 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -4,7 +4,7 @@ GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO -INPUT = ../components +INPUT = ../components/driver/include RECURSIVE = YES QUIET = YES JAVADOC_AUTOBRIEF = YES From 4900c63071a88883b327aedc754bcae0bcc6fd62 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 23 Oct 2016 22:59:53 +0200 Subject: [PATCH 61/95] Added ReadTheDocs.org badges --- README.rst | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 65d6167673..9711e22946 100644 --- a/README.rst +++ b/README.rst @@ -15,7 +15,9 @@ In the [docs](docs) directory you will find per-platform setup guides: Finding A Project ----------------- -As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, esp-idf comes with some example projects in the [examples](examples) directory. +As well as the esp-idf-template_ project mentioned in the setup guide, esp-idf comes with some example projects in the [examples](examples) directory. + +.. _esp-idf-template: https://github.com/espressif/esp-idf-template Once you've found the project you want to work with, change to its directory and you can configure and build it: @@ -82,3 +84,9 @@ Resources * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one. * If you're interested in contributing to esp-idf, please check the [CONTRIBUTING.md](CONTRIBUTING.md) file. + + +.. |docs| image:: https://readthedocs.org/projects/docs/badge/?version=latest + :alt: Documentation Status + :scale: 100% + :target: http://esp-idf.readthedocs.io/en/latest/?badge=latest \ No newline at end of file From 6ce1af58984751a3dafc3d5111e8bbedffdf7aa3 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Mon, 24 Oct 2016 20:43:13 +0200 Subject: [PATCH 62/95] Set up of theme for local builds --- docs/conf.py | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 7c4614d458..5ba76d7f25 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,14 +20,16 @@ import os # documentation root, use os.path.abspath to make it absolute, like shown here. #sys.path.insert(0, os.path.abspath('.')) -# run doxygen +# -- Run DoxyGen to prepare XML for Sphinx--------------------------------- +# ref. https://github.com/rtfd/readthedocs.org/issues/388 # -# for implementation on readthedocs.org check -# https://github.com/rtfd/readthedocs.org/issues/388 +# added by krzychb, 24-Oct-2016 # + from subprocess import call call('doxygen') + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -268,3 +270,18 @@ texinfo_documents = [ # If true, do not generate a @detailmenu in the "Top" node's menu. #texinfo_no_detailmenu = False + +# -- Use sphinx_rtd_theme for local builds -------------------------------- +# ref. https://github.com/snide/sphinx_rtd_theme#using-this-theme-locally-then-building-on-read-the-docs +# +# added by krzychb, 24-Oct-2016 +# +# on_rtd is whether we are on readthedocs.org +on_rtd = os.environ.get('READTHEDOCS', None) == 'True' + +if not on_rtd: # only import and set the theme if we're building docs locally + import sphinx_rtd_theme + html_theme = 'sphinx_rtd_theme' + html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] + +# otherwise, readthedocs.org uses their theme by default, so no need to specify it From 8ae97a285551a07046e7b80a5fb4de157fb36faf Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Mon, 24 Oct 2016 20:44:57 +0200 Subject: [PATCH 63/95] Initial list of Wi-Fi API --- docs/COPYRIGHT.rst | 6 ++- docs/Doxyfile | 4 +- docs/api/esp_wifi.rst | 59 ++++++++++++++++++++++++ docs/api/example.rst | 41 +++++++++++++++++ docs/build_system.rst | 2 +- docs/contributor-agreement.rst | 2 +- docs/eclipse-setup.rst | 3 ++ docs/index.rst | 82 ++++++++++++++-------------------- docs/linux-setup.rst | 3 ++ docs/macos-setup.rst | 3 ++ docs/openocd.rst | 3 ++ docs/partition-tables.rst | 5 ++- docs/windows-setup.rst | 7 ++- 13 files changed, 162 insertions(+), 58 deletions(-) create mode 100644 docs/api/esp_wifi.rst create mode 100644 docs/api/example.rst diff --git a/docs/COPYRIGHT.rst b/docs/COPYRIGHT.rst index da5f5b204a..67b3d9bf1c 100644 --- a/docs/COPYRIGHT.rst +++ b/docs/COPYRIGHT.rst @@ -1,3 +1,6 @@ +Copyrights and Licenses +*********************** + Software Copyrights =================== @@ -87,8 +90,7 @@ developments under license policy of following terms. Copyright (C) 2011, ChaN, all right reserved. * The TJpgDec module is a free software and there is NO WARRANTY. -* No restriction on use. You can use, modify and redistribute it for -personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. +* No restriction on use. You can use, modify and redistribute it for personal, non-profit or commercial products UNDER YOUR RESPONSIBILITY. * Redistributions of source code must retain the above copyright notice. diff --git a/docs/Doxyfile b/docs/Doxyfile index 795bfa5e89..9c8fb81df8 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -4,9 +4,9 @@ GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO -INPUT = ../components/driver/include +INPUT = ../components/esp32/include/esp_wifi.h RECURSIVE = YES QUIET = YES JAVADOC_AUTOBRIEF = YES GENERATE_HTML = NO -GENERATE_XML = YES \ No newline at end of file +GENERATE_XML = YES diff --git a/docs/api/esp_wifi.rst b/docs/api/esp_wifi.rst new file mode 100644 index 0000000000..48b4db204a --- /dev/null +++ b/docs/api/esp_wifi.rst @@ -0,0 +1,59 @@ +Wi-Fi API +========= + +Macros +------ + +.. doxygendefine:: WIFI_INIT_CONFIG_DEFAULT + + +Typedefs +-------- + +.. doxygentypedef:: wifi_promiscuous_cb_t +.. doxygentypedef:: wifi_rxcb_t +.. doxygentypedef:: esp_vendor_ie_cb_t + + +Functions +--------- + +.. doxygenfunction:: esp_wifi_init +.. doxygenfunction:: esp_wifi_deinit +.. doxygenfunction:: esp_wifi_set_mode +.. doxygenfunction:: esp_wifi_get_mode +.. doxygenfunction:: esp_wifi_start +.. doxygenfunction:: esp_wifi_stop +.. doxygenfunction:: esp_wifi_connect +.. doxygenfunction:: esp_wifi_disconnect +.. doxygenfunction:: esp_wifi_clear_fast_connect +.. doxygenfunction:: esp_wifi_kick_station +.. doxygenfunction:: esp_wifi_scan_start +.. doxygenfunction:: esp_wifi_scan_stop +.. doxygenfunction:: esp_wifi_get_ap_num +.. doxygenfunction:: esp_wifi_get_ap_list +.. doxygenfunction:: esp_wifi_set_ps +.. doxygenfunction:: esp_wifi_get_ps +.. doxygenfunction:: esp_wifi_set_protocol +.. doxygenfunction:: esp_wifi_get_protocol +.. doxygenfunction:: esp_wifi_set_bandwidth +.. doxygenfunction:: esp_wifi_get_bandwidth +.. doxygenfunction:: esp_wifi_set_channel +.. doxygenfunction:: esp_wifi_get_channel +.. doxygenfunction:: esp_wifi_set_country +.. doxygenfunction:: esp_wifi_get_country +.. doxygenfunction:: esp_wifi_set_mac +.. doxygenfunction:: esp_wifi_get_mac +.. doxygenfunction:: esp_wifi_set_promiscuous_rx_cb +.. doxygenfunction:: esp_wifi_set_promiscuous +.. doxygenfunction:: esp_wifi_get_promiscuous +.. doxygenfunction:: esp_wifi_set_config +.. doxygenfunction:: esp_wifi_get_config +.. doxygenfunction:: esp_wifi_get_station_list +.. doxygenfunction:: esp_wifi_free_station_list +.. doxygenfunction:: esp_wifi_set_storage +.. doxygenfunction:: esp_wifi_reg_rxcb +.. doxygenfunction:: esp_wifi_set_auto_connect +.. doxygenfunction:: esp_wifi_get_auto_connect +.. doxygenfunction:: esp_wifi_set_vendor_ie +.. doxygenfunction:: esp_wifi_set_vendor_ie_cb diff --git a/docs/api/example.rst b/docs/api/example.rst new file mode 100644 index 0000000000..88ecb4601d --- /dev/null +++ b/docs/api/example.rst @@ -0,0 +1,41 @@ +Example Visualizations +====================== + +Function prototpe +----------------- + +.. c:function:: esp_err_t esp_wifi_get_ap_list (uint16_t *number, wifi_ap_list_t *ap_list) +.. c:function:: esp_err_t esp_wifi_set_protocol (wifi_interface_t ifx, uint8_t protocol_bitmap) + + +Function definition +------------------- + +Wi-Fi +^^^^^ +.. doxygenfunction:: esp_wifi_init +.. doxygenfunction:: esp_wifi_set_config + +GPIO +^^^^ +.. doxygenfunction:: gpio_isr_register + +Led Control +^^^^^^^^^^^ + +.. doxygenfunction:: ledc_timer_set + + +Enum definition +--------------- + +.. doxygenenum:: wifi_auth_mode_t + + +Struct definition +----------------- + +.. doxygenstruct:: wifi_scan_config_t + :members: + + diff --git a/docs/build_system.rst b/docs/build_system.rst index 4df65b1b5c..34db487e0a 100644 --- a/docs/build_system.rst +++ b/docs/build_system.rst @@ -1,5 +1,5 @@ Build System ------------- +************ This document explains the Espressif IoT Development Framework build system and the concept of "components" diff --git a/docs/contributor-agreement.rst b/docs/contributor-agreement.rst index 7c194e7728..de294740c4 100644 --- a/docs/contributor-agreement.rst +++ b/docs/contributor-agreement.rst @@ -1,5 +1,5 @@ Contributor Agreement ---------------------- +===================== Individual Contributor Non-Exclusive License Agreement ------------------------------------------------------ diff --git a/docs/eclipse-setup.rst b/docs/eclipse-setup.rst index 21d83a7f06..32d60a17a0 100644 --- a/docs/eclipse-setup.rst +++ b/docs/eclipse-setup.rst @@ -1,3 +1,6 @@ +Build and Falsh with Eclipse IDE +******************************** + Installing Eclipse IDE ====================== diff --git a/docs/index.rst b/docs/index.rst index f74a3acae1..30e981e8ef 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,54 +1,41 @@ .. Read the Docs Template documentation master file -Welcome to ESP32 Programming Guide -================================== - - -Example C functions -------------------- - -.. c:function:: esp_err_t esp_wifi_get_ap_list (uint16_t *number, wifi_ap_list_t *ap_list) - -.. c:function:: esp_err_t esp_wifi_set_protocol (wifi_interface_t ifx, uint8_t protocol_bitmap) - - -Example C function integration ------------------------------- - -.. doxygenfunction:: esp_wifi_init -.. doxygenfunction:: esp_wifi_set_config - -.. doxygenfunction:: gpio_isr_register -.. doxygenfunction:: ledc_timer_set - - -Example C enum integration --------------------------- - -.. doxygenenum:: wifi_auth_mode_t - - -Example C struct integration ----------------------------- - -.. doxygenstruct:: wifi_scan_config_t - :members: - +ESP32 Programming Guide +======================= Contents: -.. About - TBA - .. toctree:: - :caption: Toolchain Setup + :caption: Setup Toolchain :maxdepth: 1 - windows-setup - linux-setup - macos-setup - eclipse-setup + Windows + Linux + Mac OS -.. API Reference - TBA +.. Configure - TBA + +.. Connect - TBA + +.. toctree:: + :caption: Build and Flash + :maxdepth: 1 + + Eclipse IDE + +.. toctree:: + :caption: Tweak + :maxdepth: 1 + + partition-tables + build_system + +.. toctree:: + :caption: API Reference + :maxdepth: 1 + + Wi-Fi + api/example .. Technical Reference - TBA @@ -68,17 +55,14 @@ Contents: contributor-agreement .. toctree:: - :caption: Copyrights and Licenses + :caption: Legal :maxdepth: 1 COPYRIGHT -.. toctree:: - :caption: Flapping Documents - :maxdepth: 1 - - partition-tables - build_system +.. About - TBA + + Indices and tables diff --git a/docs/linux-setup.rst b/docs/linux-setup.rst index 13e1b3a9c0..cf5e78b63d 100644 --- a/docs/linux-setup.rst +++ b/docs/linux-setup.rst @@ -1,3 +1,6 @@ +Set up of Toolchain for Linux +***************************** + Step 0: Prerequisites ===================== diff --git a/docs/macos-setup.rst b/docs/macos-setup.rst index 8178a17ada..53c6fe54c8 100644 --- a/docs/macos-setup.rst +++ b/docs/macos-setup.rst @@ -1,3 +1,6 @@ +Set up of Toolchain for Mac OS +****************************** + Step 0: Prerequisites ===================== diff --git a/docs/openocd.rst b/docs/openocd.rst index 57ee93db4a..6a6f50e3f4 100644 --- a/docs/openocd.rst +++ b/docs/openocd.rst @@ -1,3 +1,6 @@ +Debugging +========= + OpenOCD setup for ESP32 ----------------------- diff --git a/docs/partition-tables.rst b/docs/partition-tables.rst index e0a39126b5..88597532d2 100644 --- a/docs/partition-tables.rst +++ b/docs/partition-tables.rst @@ -1,5 +1,8 @@ Partition Tables ----------------- +================ + +Overview +-------- A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x4000 in the flash. diff --git a/docs/windows-setup.rst b/docs/windows-setup.rst index baea1ac40b..a425f5b3a0 100644 --- a/docs/windows-setup.rst +++ b/docs/windows-setup.rst @@ -1,5 +1,8 @@ -Step 1: Toolchain for Windows: Quick Steps -================================== +Set up of Toolchain for Windows +******************************* + +Step 1: Quick Steps +=================== Windows doesn't have a built-in "make" environment, so as well as installing the toolchain you will need a GNU-compatible environment. We use the MSYS2_ environment to provide. You don't need to use this environment all the time (you can use Eclipse_ or some other front-end), but it runs behind the scenes. From b6a463e94f5886bc953515e8b9a45b7c13a514a2 Mon Sep 17 00:00:00 2001 From: krzychb Date: Tue, 25 Oct 2016 12:09:05 +0200 Subject: [PATCH 64/95] Draft of GPIO API included --- docs/Doxyfile | 25 +++++++++--------- docs/api/gpio.rst | 67 +++++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 3 files changed, 81 insertions(+), 12 deletions(-) create mode 100644 docs/api/gpio.rst diff --git a/docs/Doxyfile b/docs/Doxyfile index 9c8fb81df8..8328d44ca3 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,12 +1,13 @@ -PROJECT_NAME = "ESP32 Programming Guide" -XML_OUTPUT = xml -GENERATE_LATEX = NO -GENERATE_MAN = NO -GENERATE_RTF = NO -CASE_SENSE_NAMES = NO -INPUT = ../components/esp32/include/esp_wifi.h -RECURSIVE = YES -QUIET = YES -JAVADOC_AUTOBRIEF = YES -GENERATE_HTML = NO -GENERATE_XML = YES +PROJECT_NAME = "ESP32 Programming Guide" +XML_OUTPUT = xml +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver/gpio.h ../components/esp32/include/rom/gpio.h +RECURSIVE = YES +QUIET = YES +JAVADOC_AUTOBRIEF = YES +GENERATE_HTML = NO +GENERATE_XML = YES +WARN_LOGFILE = "DoxyGenWarningLog.txt" \ No newline at end of file diff --git a/docs/api/gpio.rst b/docs/api/gpio.rst new file mode 100644 index 0000000000..11b0e4a463 --- /dev/null +++ b/docs/api/gpio.rst @@ -0,0 +1,67 @@ +GPIO API +======== + +Functions +--------- + +.. doxygenfunction:: gpio_config +.. doxygenfunction:: gpio_set_intr_type +.. doxygenfunction:: gpio_intr_enable +.. doxygenfunction:: gpio_intr_disable +.. doxygenfunction:: gpio_set_level +.. doxygenfunction:: gpio_get_level +.. doxygenfunction:: gpio_set_direction +.. doxygenfunction:: gpio_set_pull_mode +.. doxygenfunction:: gpio_wakeup_enable +.. doxygenfunction:: gpio_wakeup_disable +.. doxygenfunction:: gpio_isr_register + +*Example code:* + +Configuration of GPIO as an output + +.. code-block:: c + + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt + io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode + io_conf.pin_bit_mask = GPIO_SEL_18 | GPIO_SEL_19; //bit mask of the pins that you want to set,e.g.GPIO18/19 + io_conf.pull_down_en = 0; //disable pull-down mode + io_conf.pull_up_en = 0; //disable pull-up mode + gpio_config(&io_conf); //configure GPIO with the given settings + +Configuration of GPIO as an input + +.. code-block:: c + + gpio_config_t io_conf; + io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt + io_conf.mode = GPIO_MODE_INPUT; //set as input + io_conf.pin_bit_mask = GPIO_SEL_4 | GPIO_SEL_5; //bit mask of the pins that you want to set, e.g.,GPIO4/5 + io_conf.pull_down_en = 0; //disable pull-down mode + io_conf.pull_up_en = 1; //enable pull-up mode + gpio_config(&io_conf); //configure GPIO with the given settings + + +Low level ROM GPIO functions + +.. doxygenfunction:: gpio_init +.. doxygenfunction:: gpio_output_set +.. doxygenfunction:: gpio_output_set_high +.. doxygenfunction:: gpio_input_get +.. doxygenfunction:: gpio_input_get_high +.. doxygenfunction:: gpio_intr_handler_register +.. doxygenfunction:: gpio_intr_pending +.. doxygenfunction:: gpio_intr_pending_high +.. doxygenfunction:: gpio_intr_ack +.. doxygenfunction:: gpio_intr_ack_high +.. doxygenfunction:: gpio_pin_wakeup_enable +.. doxygenfunction:: gpio_pin_wakeup_disable +.. doxygenfunction:: gpio_matrix_in +.. doxygenfunction:: gpio_matrix_out +.. doxygenfunction:: gpio_pad_select_gpio +.. doxygenfunction:: gpio_pad_set_drv +.. doxygenfunction:: gpio_pad_pullup +.. doxygenfunction:: gpio_pad_pulldown +.. doxygenfunction:: gpio_pad_unhold +.. doxygenfunction:: gpio_pad_hold diff --git a/docs/index.rst b/docs/index.rst index 30e981e8ef..26b906c366 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -35,6 +35,7 @@ Contents: :maxdepth: 1 Wi-Fi + GPIO api/example .. Technical Reference - TBA From 3584fcfc7cf3a3211c476cb2d02b66360d649bce Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Tue, 25 Oct 2016 21:28:21 +0200 Subject: [PATCH 65/95] Make section --- docs/index.rst | 19 ++++++------- docs/make-project.rst | 63 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 71 insertions(+), 11 deletions(-) create mode 100644 docs/make-project.rst diff --git a/docs/index.rst b/docs/index.rst index 26b906c366..84f37b5600 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -21,14 +21,16 @@ Contents: :caption: Build and Flash :maxdepth: 1 + Make Eclipse IDE .. toctree:: - :caption: Tweak + :caption: Want More? :maxdepth: 1 partition-tables build_system + openocd .. toctree:: :caption: API Reference @@ -38,13 +40,10 @@ Contents: GPIO api/example -.. Technical Reference - TBA - .. toctree:: - :caption: Debugging - :maxdepth: 1 + :caption: Technical Reference - openocd + Technical Reference .. Resources - TBA @@ -63,11 +62,9 @@ Contents: .. About - TBA - - - -Indices and tables -================== + +Indices +======= * :ref:`genindex` * :ref:`search` diff --git a/docs/make-project.rst b/docs/make-project.rst new file mode 100644 index 0000000000..e72bb81dd0 --- /dev/null +++ b/docs/make-project.rst @@ -0,0 +1,63 @@ +Build and Flash with Make +========================= + +Finding a project +----------------- + +As well as the `esp-idf-template `_ project mentioned in the setup guide, esp-idf comes with some example projects on github in the `examples `_ directory. + +Once you've found the project you want to work with, change to its directory and you can configure and build it: + +Configuring your project +------------------------ + +`make menuconfig` + +Compiling your project +---------------------- + +`make all` + +... will compile app, bootloader and generate a partition table based on the config. + +Flashing your project +--------------------- + +When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running: + +`make flash` + +This will flash the entire project (app, bootloader and partition table) to a new chip. The settings for serial port flashing can be configured with `make menuconfig`. + +You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it. + +Compiling & Flashing Just the App +--------------------------------- + +After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table: + +* `make app` - build just the app. +* `make app-flash` - flash just the app. + +`make app-flash` will automatically rebuild the app if it needs it. + +(There's no downside to reflashing the bootloader and partition table each time, if they haven't changed.) + +The Partition Table +------------------- + +Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader. + +A single ESP32's flash can contain multiple apps, as well as many different kinds of data (calibration data, filesystems, parameter storage, etc). For this reason a partition table is flashed to offset 0x4000 in the flash. + +Each entry in the partition table has a name (label), type (app, data, or something else), subtype and the offset in flash where the partition is loaded. + +The simplest way to use the partition table is to `make menuconfig` and choose one of the simple predefined partition tables: + +* "Single factory app, no OTA" +* "Factory app, two OTA definitions" + +In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. + +For more details about :doc:`partition tables ` and how to create custom variations, view the :doc:`documentation `. + From 591b7caa9514ab7d2a2c03bf8b42bec490eea86f Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Tue, 25 Oct 2016 21:28:42 +0200 Subject: [PATCH 66/95] Back to .md format --- CONTRIBUTING.rst | 6 +++--- README.rst => README.md | 44 +++++++++++++---------------------------- 2 files changed, 17 insertions(+), 33 deletions(-) rename README.rst => README.md (72%) diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index a6e759eb18..ed1c0b92d8 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -6,7 +6,7 @@ We welcome contributions to the esp-idf project! How to Contribute ----------------- -Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via [Github Pull Requests](https://help.github.com/articles/about-pull-requests/). +Contributions to esp-idf - fixing bugs, adding features, adding documentation - are welcome. We accept contributions via `Github Pull Requests `_. Before Contributing ------------------- @@ -23,7 +23,7 @@ Before sending us a Pull Request, please consider this list of points: * Are comments and documentation written in clear English, with no spelling or grammar errors? -* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" [squashed into previous commits](http://eli.thegreenplace.net/2014/02/19/squashing-github-pull-requests-into-a-single-commit/)? +* If the contribution contains multiple commits, are they grouped together into logical changes (one major change per pull request)? Are any commits with names like "fixed typo" `squashed into previous commits `_? * If you're unsure about any of these points, please open the Pull Request anyhow and then ask us for feedback. @@ -39,4 +39,4 @@ If this process passes, it will be merged onto the public github repository. Legal Part ---------- -Before a contribution can be accepted, you will need to sign our [Contributor Agreement](docs/contributor-agreement.rst). You will be prompted for this automatically as part of the Pull Request process. +Before a contribution can be accepted, you will need to sign our :doc:`Contributor Agreement `. You will be prompted for this automatically as part of the Pull Request process. diff --git a/README.rst b/README.md similarity index 72% rename from README.rst rename to README.md index 9711e22946..c01e314f11 100644 --- a/README.rst +++ b/README.md @@ -1,10 +1,8 @@ -Using Espressif IoT Development Framework with the ESP32 -======================================================== +# Using Espressif IoT Development Framework with the ESP32 -|docs| +[![alt text](https://readthedocs.org/projects/docs/badge/?version=latest "Documentation Status")](http://esp-idf.readthedocs.io/en/latest/?badge=latest) -Setting Up ESP-IDF ------------------- +# Setting Up ESP-IDF In the [docs](docs) directory you will find per-platform setup guides: @@ -12,29 +10,23 @@ In the [docs](docs) directory you will find per-platform setup guides: * [Mac OS Setup Guide](docs/macos-setup.rst) * [Linux Setup Guide](docs/linux-setup.rst) -Finding A Project ------------------ +# Finding A Project -As well as the esp-idf-template_ project mentioned in the setup guide, esp-idf comes with some example projects in the [examples](examples) directory. - -.. _esp-idf-template: https://github.com/espressif/esp-idf-template +As well as the [esp-idf-template](https://github.com/espressif/esp-idf-template) project mentioned in the setup guide, esp-idf comes with some example projects in the [examples](examples) directory. Once you've found the project you want to work with, change to its directory and you can configure and build it: -Configuring your project ------------------------- +# Configuring your project `make menuconfig` -Compiling your project ----------------------- +# Compiling your project `make all` ... will compile app, bootloader and generate a partition table based on the config. -Flashing your project ---------------------- +# Flashing your project When `make all` finishes, it will print a command line to use esptool.py to flash the chip. However you can also do this from make by running: @@ -44,8 +36,7 @@ This will flash the entire project (app, bootloader and partition table) to a ne You don't need to run `make all` before running `make flash`, `make flash` will automatically rebuild anything which needs it. -Compiling & Flashing Just the App ---------------------------------- +# Compiling & Flashing Just the App After the initial flash, you may just want to build and flash just your app, not the bootloader and partition table: @@ -56,8 +47,7 @@ After the initial flash, you may just want to build and flash just your app, not (There's no downside to reflashing the bootloader and partition table each time, if they haven't changed.) -The Partition Table -------------------- +# The Partition Table Once you've compiled your project, the "build" directory will contain a binary file with a name like "my_app.bin". This is an ESP32 image binary that can be loaded by the bootloader. @@ -72,21 +62,15 @@ The simplest way to use the partition table is to `make menuconfig` and choose o In both cases the factory app is flashed at offset 0x10000. If you `make partition_table` then it will print a summary of the partition table. -For more details about partition tables and how to create custom variations, view the `docs/partition_tables.rst` file. +For more details about partition tables and how to create custom variations, view the `docs/partition-tables.rst` file. -Resources ---------- +# Resources -* The [docs directory of the esp-idf repository](docs) contains esp-idf documentation. +* The [docs directory of the esp-idf repository](docs) contains source of [esp-idf](http://esp-idf.readthedocs.io/) documentation. * The [esp32.com forum](http://esp32.com/) is a place to ask questions and find community resources. * [Check the Issues section on github](https://github.com/espressif/esp-idf/issues) if you find a bug or have a feature request. Please check existing Issues before opening a new one. -* If you're interested in contributing to esp-idf, please check the [CONTRIBUTING.md](CONTRIBUTING.md) file. +* If you're interested in contributing to esp-idf, please check the [Contributions Guide](http://esp-idf.readthedocs.io/en/latest/contributing.html>). - -.. |docs| image:: https://readthedocs.org/projects/docs/badge/?version=latest - :alt: Documentation Status - :scale: 100% - :target: http://esp-idf.readthedocs.io/en/latest/?badge=latest \ No newline at end of file From adae42fd85381071a2564940f398e2fdf22fdc97 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Wed, 26 Oct 2016 21:08:36 +0200 Subject: [PATCH 67/95] API template - reflected template in other DRAFT API dcouments - DRAFT of Bluetooth API - link fixes in CONTRIBUTING.rst --- CONTRIBUTING.rst | 6 +++-- docs/Doxyfile | 26 +++++++++--------- docs/api/bt.rst | 31 ++++++++++++++++++++++ docs/api/esp_wifi.rst | 15 +++++++++++ docs/api/example.rst | 41 ----------------------------- docs/api/gpio.rst | 28 +++++++++++++++----- docs/api/template.rst | 61 +++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 7 +++-- 8 files changed, 149 insertions(+), 66 deletions(-) create mode 100644 docs/api/bt.rst delete mode 100644 docs/api/example.rst create mode 100644 docs/api/template.rst diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst index ed1c0b92d8..3bf43f6dbe 100644 --- a/CONTRIBUTING.rst +++ b/CONTRIBUTING.rst @@ -19,7 +19,7 @@ Before sending us a Pull Request, please consider this list of points: * Is the code adequately commented for people to understand how it is structured? -* Is there documentation or examples that go with code contributions? [There are additional suggestions for writing good examples in the examples README](examples/README.md). +* Is there documentation or examples that go with code contributions? `There are additional suggestions for writing good examples in the examples README `_. * Are comments and documentation written in clear English, with no spelling or grammar errors? @@ -39,4 +39,6 @@ If this process passes, it will be merged onto the public github repository. Legal Part ---------- -Before a contribution can be accepted, you will need to sign our :doc:`Contributor Agreement `. You will be prompted for this automatically as part of the Pull Request process. +Before a contribution can be accepted, you will need to sign our `Contributor Agreement `_. You will be prompted for this automatically as part of the Pull Request process. + + diff --git a/docs/Doxyfile b/docs/Doxyfile index 8328d44ca3..f905de74ce 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,13 +1,13 @@ -PROJECT_NAME = "ESP32 Programming Guide" -XML_OUTPUT = xml -GENERATE_LATEX = NO -GENERATE_MAN = NO -GENERATE_RTF = NO -CASE_SENSE_NAMES = NO -INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver/gpio.h ../components/esp32/include/rom/gpio.h -RECURSIVE = YES -QUIET = YES -JAVADOC_AUTOBRIEF = YES -GENERATE_HTML = NO -GENERATE_XML = YES -WARN_LOGFILE = "DoxyGenWarningLog.txt" \ No newline at end of file +PROJECT_NAME = "ESP32 Programming Guide" +XML_OUTPUT = xml +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO +CASE_SENSE_NAMES = NO +INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver/gpio.h ../components/esp32/include/rom/gpio.h ../components/bt/include/bt.h +RECURSIVE = YES +QUIET = YES +JAVADOC_AUTOBRIEF = YES +GENERATE_HTML = NO +GENERATE_XML = YES +WARN_LOGFILE = "DoxyGenWarningLog.txt" diff --git a/docs/api/bt.rst b/docs/api/bt.rst new file mode 100644 index 0000000000..16f30dc4e6 --- /dev/null +++ b/docs/api/bt.rst @@ -0,0 +1,31 @@ +Bluetooth API +============= + +Overview +-------- + +`Instructions `_ + +Application Example +------------------- + +`Instructions `_ + +Reference +--------- + +`Instructions `_ + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. doxygentypedef:: vhci_host_callback + +Functions +^^^^^^^^^ + +.. doxygenfunction:: API_vhci_host_check_send_available +.. doxygenfunction:: API_vhci_host_register_callback +.. doxygenfunction:: API_vhci_host_send_packet +.. doxygenfunction:: bt_controller_init + diff --git a/docs/api/esp_wifi.rst b/docs/api/esp_wifi.rst index 48b4db204a..e4ec59fc82 100644 --- a/docs/api/esp_wifi.rst +++ b/docs/api/esp_wifi.rst @@ -1,6 +1,21 @@ Wi-Fi API ========= +Overview +-------- + +`Instructions `_ + +Application Example +------------------- + +`Instructions `_ + +Reference +--------- + +`Instructions `_ + Macros ------ diff --git a/docs/api/example.rst b/docs/api/example.rst deleted file mode 100644 index 88ecb4601d..0000000000 --- a/docs/api/example.rst +++ /dev/null @@ -1,41 +0,0 @@ -Example Visualizations -====================== - -Function prototpe ------------------ - -.. c:function:: esp_err_t esp_wifi_get_ap_list (uint16_t *number, wifi_ap_list_t *ap_list) -.. c:function:: esp_err_t esp_wifi_set_protocol (wifi_interface_t ifx, uint8_t protocol_bitmap) - - -Function definition -------------------- - -Wi-Fi -^^^^^ -.. doxygenfunction:: esp_wifi_init -.. doxygenfunction:: esp_wifi_set_config - -GPIO -^^^^ -.. doxygenfunction:: gpio_isr_register - -Led Control -^^^^^^^^^^^ - -.. doxygenfunction:: ledc_timer_set - - -Enum definition ---------------- - -.. doxygenenum:: wifi_auth_mode_t - - -Struct definition ------------------ - -.. doxygenstruct:: wifi_scan_config_t - :members: - - diff --git a/docs/api/gpio.rst b/docs/api/gpio.rst index 11b0e4a463..c12c991ce4 100644 --- a/docs/api/gpio.rst +++ b/docs/api/gpio.rst @@ -1,9 +1,24 @@ GPIO API ======== -Functions +Overview +-------- + +`Instructions `_ + +Application Example +------------------- + +`Instructions `_ + +Reference --------- +`Instructions `_ + +Functions +^^^^^^^^^ + .. doxygenfunction:: gpio_config .. doxygenfunction:: gpio_set_intr_type .. doxygenfunction:: gpio_intr_enable @@ -16,9 +31,7 @@ Functions .. doxygenfunction:: gpio_wakeup_disable .. doxygenfunction:: gpio_isr_register -*Example code:* - -Configuration of GPIO as an output +*Example code:* Configuration of GPIO as an output .. code-block:: c @@ -30,7 +43,7 @@ Configuration of GPIO as an output io_conf.pull_up_en = 0; //disable pull-up mode gpio_config(&io_conf); //configure GPIO with the given settings -Configuration of GPIO as an input +*Example code:* Configuration of GPIO as an input .. code-block:: c @@ -43,7 +56,8 @@ Configuration of GPIO as an input gpio_config(&io_conf); //configure GPIO with the given settings -Low level ROM GPIO functions +ROM GPIO functions +^^^^^^^^^^^^^^^^^^ .. doxygenfunction:: gpio_init .. doxygenfunction:: gpio_output_set @@ -65,3 +79,5 @@ Low level ROM GPIO functions .. doxygenfunction:: gpio_pad_pulldown .. doxygenfunction:: gpio_pad_unhold .. doxygenfunction:: gpio_pad_hold + + diff --git a/docs/api/template.rst b/docs/api/template.rst new file mode 100644 index 0000000000..8b1dfd4c50 --- /dev/null +++ b/docs/api/template.rst @@ -0,0 +1,61 @@ +Template API +============= + +Overview +-------- + +INSTRUCTIONS: Provide overview where and how this API may be used. For large number of functions, break down description into groups. + + +Application Example +------------------- + +INSTRUCTIONS: Provide one or more pratical examples to demonstrate functionality of this API. + + +Reference +--------- + +INSTRUCTIONS: Provide list of API memebers divided into sections. Use coresponding **.. doxygen** directices, so member documentation is auto updated. + +* Data Structures **.. doxygenstruct** +* Macros **.. doxygendefine** +* Type Definitions **.. doxygentypedef** +* Enumerations **.. doxygenenum** +* Functions **.. doxygenfunction** +* Variables **.. doxygenvariable** + +Include code snippotes to ilustrate functionality of particular functions where applicable. Skip section hearder if empty. + + +Data Structures +^^^^^^^^^^^^^^^ + +.. Data Structures .. doxygenstruct + +Macros +^^^^^^ + +.. Macros .. doxygendefine + +Type Definitions +^^^^^^^^^^^^^^^^ + +.. Type Definitions .. doxygentypedef + +Enumerations +^^^^^^^^^^^^ + +.. Enumerations .. doxygenenum + +Functions +^^^^^^^^^ + +.. Functions .. doxygenfunction + +Variables +^^^^^^^^^ + +.. Variables .. doxygenvariable + + diff --git a/docs/index.rst b/docs/index.rst index 84f37b5600..5c4d7025c6 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,5 +1,3 @@ -.. Read the Docs Template documentation master file - ESP32 Programming Guide ======================= @@ -25,7 +23,7 @@ Contents: Eclipse IDE .. toctree:: - :caption: Want More? + :caption: What Else? :maxdepth: 1 partition-tables @@ -37,8 +35,9 @@ Contents: :maxdepth: 1 Wi-Fi + Bluetooth GPIO - api/example + Template .. toctree:: :caption: Technical Reference From f05cd619f4bdbdfc2019b4e9f800b82ae6a13f3b Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Wed, 26 Oct 2016 22:17:58 +0200 Subject: [PATCH 68/95] Sample cleaning of markup --- components/driver/include/driver/gpio.h | 148 ++++++++++++------------ docs/api/gpio.rst | 7 ++ 2 files changed, 81 insertions(+), 74 deletions(-) diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 9b47c88e69..001be2a39d 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -157,39 +157,39 @@ typedef enum { } gpio_num_t; typedef enum { - GPIO_INTR_DISABLE = 0, /* disable GPIO interrupt */ - GPIO_INTR_POSEDGE = 1, /* GPIO interrupt type : rising edge */ - GPIO_INTR_NEGEDGE = 2, /* GPIO interrupt type : falling edge */ - GPIO_INTR_ANYEDGE = 3, /* GPIO interrupt type : both rising and falling edge */ - GPIO_INTR_LOW_LEVEL = 4, /* GPIO interrupt type : input low level trigger */ - GPIO_INTR_HIGH_LEVEL = 5, /* GPIO interrupt type : input high level trigger */ + GPIO_INTR_DISABLE = 0, /*!< disable GPIO interrupt */ + GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */ + GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */ + GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */ + GPIO_INTR_LOW_LEVEL = 4, /*!< GPIO interrupt type : input low level trigger */ + GPIO_INTR_HIGH_LEVEL = 5, /*!< GPIO interrupt type : input high level trigger */ GPIO_INTR_MAX, } gpio_int_type_t; typedef enum { - GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /* GPIO mode : input only */ - GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /* GPIO mode : output only mode */ - GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /* GPIO mode : output only with open-drain mode */ - GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /* GPIO mode : output and input with open-drain mode*/ - GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)), /* GPIO mode : output and input mode */ + GPIO_MODE_INPUT = GPIO_MODE_DEF_INPUT, /*!< GPIO mode : input only */ + GPIO_MODE_OUTPUT = GPIO_MODE_DEF_OUTPUT, /*!< GPIO mode : output only mode */ + GPIO_MODE_OUTPUT_OD = ((GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /*!< GPIO mode : output only with open-drain mode */ + GPIO_MODE_INPUT_OUTPUT_OD = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)|(GPIO_MODE_DEF_OD)), /*!< GPIO mode : output and input with open-drain mode*/ + GPIO_MODE_INPUT_OUTPUT = ((GPIO_MODE_DEF_INPUT)|(GPIO_MODE_DEF_OUTPUT)), /*!< GPIO mode : output and input mode */ } gpio_mode_t; typedef enum { - GPIO_PULLUP_DISABLE = 0x0, /* disable GPIO pull-up resistor */ - GPIO_PULLUP_ENABLE = 0x1, /* enable GPIO pull-up resistor */ + GPIO_PULLUP_DISABLE = 0x0, /*!< disable GPIO pull-up resistor */ + GPIO_PULLUP_ENABLE = 0x1, /*!< enable GPIO pull-up resistor */ } gpio_pullup_t; typedef enum { - GPIO_PULLDOWN_DISABLE = 0x0, /* disable GPIO pull-down resistor */ - GPIO_PULLDOWN_ENABLE = 0x1, /* enable GPIO pull-down resistor */ + GPIO_PULLDOWN_DISABLE = 0x0, /*!< disable GPIO pull-down resistor */ + GPIO_PULLDOWN_ENABLE = 0x1, /*!< enable GPIO pull-down resistor */ } gpio_pulldown_t; typedef struct { - uint64_t pin_bit_mask; /* GPIO pin: set with bit mask, each bit maps to a GPIO */ - gpio_mode_t mode; /* GPIO mode: set input/output mode */ - gpio_pullup_t pull_up_en; /* GPIO pull-up */ - gpio_pulldown_t pull_down_en; /* GPIO pull-down */ - gpio_int_type_t intr_type; /* GPIO interrupt type */ + uint64_t pin_bit_mask; /*!< GPIO pin: set with bit mask, each bit maps to a GPIO */ + gpio_mode_t mode; /*!< GPIO mode: set input/output mode */ + gpio_pullup_t pull_up_en; /*!< GPIO pull-up */ + gpio_pulldown_t pull_down_en; /*!< GPIO pull-down */ + gpio_int_type_t intr_type; /*!< GPIO interrupt type */ } gpio_config_t; typedef enum { @@ -199,10 +199,10 @@ typedef enum { } gpio_level_t; typedef enum { - GPIO_PULLUP_ONLY, /* Pad pull up */ - GPIO_PULLDOWN_ONLY, /* Pad pull down */ - GPIO_PULLUP_PULLDOWN, /* Pad pull up + pull down*/ - GPIO_FLOATING, /* Pad floating */ + GPIO_PULLUP_ONLY, /*!< Pad pull up */ + GPIO_PULLDOWN_ONLY, /*!< Pad pull down */ + GPIO_PULLUP_PULLDOWN, /*!< Pad pull up + pull down*/ + GPIO_FLOATING, /*!< Pad floating */ } gpio_pull_mode_t; typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num); @@ -224,20 +224,20 @@ typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num); */ /** - * @brief GPIO common configuration + * @brief GPIO common configuration * * Use this Function ,Configure GPIO's Mode,pull-up,PullDown,IntrType * - * @parameter[in] pGPIOConfig - * pGPIOConfig.pin_bit_mask : Configure GPIO pins bits,set this parameter with bit mask. + * @param[in] pGPIOConfig + * pGPIOConfig.pin_bit_mask : Configure GPIO pins bits,set this parameter with bit mask. * If you want to configure GPIO34 and GPIO16, pin_bit_mask=GPIO_Pin_16|GPIO_Pin_34; - * pGPIOConfig.mode : Configure GPIO mode,such as output ,input... - * pGPIOConfig.pull_up_en : Enable or Disable pull-up - * pGPIOConfig.pull_down_en : Enable or Disable pull-down - * pGPIOConfig.intr_type : Configure GPIO interrupt trigger type - * @return ESP_OK: success ; - * ESP_ERR_INVALID_ARG: parameter error - * ESP_FAIL : GPIO error + * pGPIOConfig.mode : Configure GPIO mode,such as output ,input... + * pGPIOConfig.pull_up_en : Enable or Disable pull-up + * pGPIOConfig.pull_down_en : Enable or Disable pull-down + * pGPIOConfig.intr_type : Configure GPIO interrupt trigger type + * @return ESP_OK: success ; + * ESP_ERR_INVALID_ARG: parameter error + * ESP_FAIL : GPIO error * */ esp_err_t gpio_config(gpio_config_t *pGPIOConfig); @@ -246,12 +246,12 @@ esp_err_t gpio_config(gpio_config_t *pGPIOConfig); /** * @brief GPIO set interrupt trigger type * - * @parameter[in] gpio_num : GPIO number. + * @param[in] gpio_num : GPIO number. * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] intr_type: interrupt type, select from gpio_int_type_t + * @param[in] intr_type: interrupt type, select from gpio_int_type_t * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return ESP_OK : success + * ESP_ERR_INVALID_ARG: parameter error * */ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type); @@ -259,11 +259,11 @@ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** * @brief enable GPIO module interrupt signal * - * @parameter[in] gpio_num : GPIO number. + * @param[in] gpio_num : GPIO number. * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return ESP_OK : success + * ESP_ERR_INVALID_ARG: parameter error * */ esp_err_t gpio_intr_enable(gpio_num_t gpio_num); @@ -271,78 +271,78 @@ esp_err_t gpio_intr_enable(gpio_num_t gpio_num); /** * @brief disable GPIO module interrupt signal * - * @parameter[in] gpio_num : GPIO number. + * @param[in] gpio_num : GPIO number. * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return ESP_OK : success + * ESP_ERR_INVALID_ARG: parameter error * */ esp_err_t gpio_intr_disable(gpio_num_t gpio_num); /** - * @brief GPIO set output level + * @brief GPIO set output level * - * @parameter[in] gpio_num : GPIO number. + * @param[in] gpio_num : GPIO number. * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] level : Output level. 0: low ; 1: high + * @param[in] level : Output level. 0: low ; 1: high * - * @return ESP_OK : success - * ESP_FAIL : GPIO error + * @return ESP_OK : success + * ESP_FAIL : GPIO error * */ esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level); /** - * @brief GPIO get input level + * @brief GPIO get input level * - * @parameter[in] gpio_num : GPIO number. + * @param[in] gpio_num : GPIO number. * If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return 0 : the GPIO input level is 0 + * @return 0 : the GPIO input level is 0 * 1 : the GPIO input level is 1 * */ int gpio_get_level(gpio_num_t gpio_num); /** - * @brief GPIO set direction + * @brief GPIO set direction * * Configure GPIO direction,such as output_only,input_only,output_and_input * - * @parameter[in] gpio_num : Configure GPIO pins number,it should be GPIO number. + * @param[in] gpio_num : Configure GPIO pins number,it should be GPIO number. * If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] mode : Configure GPIO direction,such as output_only,input_only,... + * @param[in] mode : Configure GPIO direction,such as output_only,input_only,... * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : fail - * ESP_FAIL : GPIO error + * @return ESP_OK : success + * ESP_ERR_INVALID_ARG : fail + * ESP_FAIL : GPIO error * */ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); /** - * @brief GPIO set pull + * @brief GPIO set pull * * User this Function,configure GPIO pull mode,such as pull-up,pull-down * - * @parameter[in] gpio_num : Configure GPIO pins number,it should be GPIO number. + * @param[in] gpio_num : Configure GPIO pins number,it should be GPIO number. * If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16); - * @parameter[in] pull : Configure GPIO pull up/down mode,such as pullup_only,pulldown_only,pullup_and_pulldown,... + * @param[in] pull : Configure GPIO pull up/down mode,such as pullup_only,pulldown_only,pullup_and_pulldown,... * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : fail - * ESP_FAIL : GPIO error + * @return ESP_OK : success + * ESP_ERR_INVALID_ARG : fail + * ESP_FAIL : GPIO error * */ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); /** - * @brief enable GPIO wake-up function. + * @brief enable GPIO wake-up function. * - * @param gpio_num_t gpio_num : GPIO number. + * @param gpio_num : GPIO number. * - * @param gpio_int_type_t intr_type : only GPIO_INTR_LOLEVEL\GPIO_INTR_HILEVEL can be used + * @param intr_type : only GPIO_INTR_LOLEVEL\GPIO_INTR_HILEVEL can be used * * @return ESP_OK: success * ESP_ERR_INVALID_ARG: parameter error @@ -350,9 +350,9 @@ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** - * @brief disable GPIO wake-up function. + * @brief disable GPIO wake-up function. * - * @param gpio_num_t gpio_num: GPIO number + * @param gpio_num: GPIO number * * @return ESP_OK: success * ESP_ERR_INVALID_ARG: parameter error @@ -365,13 +365,13 @@ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num); * Users should know that which CPU is running and then pick a INUM that is not used by system. * We can find the information of INUM and interrupt level in soc.h. * TODO: to move INUM options to menu_config - * @parameter uint32_t gpio_intr_num : GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details - * @parameter void (* fn)(void* ) : interrupt handler function. + * @param gpio_intr_num : GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details + * @param (*fn)(void* ) : interrupt handler function. * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". - * @parameter void * arg : parameter for handler function + * @param arg : parameter for handler function * - * @return ESP_OK : success ; - * ESP_FAIL: gpio error + * @return ESP_OK : success ; + * ESP_FAIL: gpio error */ esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg); diff --git a/docs/api/gpio.rst b/docs/api/gpio.rst index c12c991ce4..3c5c122921 100644 --- a/docs/api/gpio.rst +++ b/docs/api/gpio.rst @@ -16,6 +16,13 @@ Reference `Instructions `_ +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: gpio_int_type_t +.. doxygenenum:: gpio_mode_t +.. doxygenenum:: gpio_pull_mode_t + Functions ^^^^^^^^^ From 1263cd340eb492581f4f179e28eb7c6df3fec644 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Thu, 27 Oct 2016 21:20:30 +0200 Subject: [PATCH 69/95] Add missing annotations --- components/nvs_flash/include/nvs.h | 42 +++++++++++++++++------------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index 912ea22103..d0c9908afb 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -28,23 +28,27 @@ extern "C" { */ typedef uint32_t nvs_handle; -#define ESP_ERR_NVS_BASE 0x1100 -#define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) -#define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) -#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) -#define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) -#define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) -#define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) -#define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) -#define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) -#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) -#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) -#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) -#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) +#define ESP_ERR_NVS_BASE 0x1100 /*!< Starting number of error codes */ +#define ESP_ERR_NVS_NOT_INITIALIZED (ESP_ERR_NVS_BASE + 0x01) /*!< The storage driver is not initialized */ +#define ESP_ERR_NVS_NOT_FOUND (ESP_ERR_NVS_BASE + 0x02) /*!< Id namespace doesn’t exist yet and mode is NVS_READONLY */ +#define ESP_ERR_NVS_TYPE_MISMATCH (ESP_ERR_NVS_BASE + 0x03) /*!< TBA */ +#define ESP_ERR_NVS_READ_ONLY (ESP_ERR_NVS_BASE + 0x04) /*!< Storage handle was opened as read only */ +#define ESP_ERR_NVS_NOT_ENOUGH_SPACE (ESP_ERR_NVS_BASE + 0x05) /*!< There is not enough space in the underlying storage to save the value */ +#define ESP_ERR_NVS_INVALID_NAME (ESP_ERR_NVS_BASE + 0x06) /*!< Namespace name doesn’t satisfy constraints */ +#define ESP_ERR_NVS_INVALID_HANDLE (ESP_ERR_NVS_BASE + 0x07) /*!< Handle has been closed or is NULL */ +#define ESP_ERR_NVS_REMOVE_FAILED (ESP_ERR_NVS_BASE + 0x08) /*!< The value wasn’t updated because flash write operation has failed. The value was written however, and update will be finished after re-initialization of nvs, provided that flash operation doesn’t fail again. */ +#define ESP_ERR_NVS_KEY_TOO_LONG (ESP_ERR_NVS_BASE + 0x09) /*!< TBA */ +#define ESP_ERR_NVS_PAGE_FULL (ESP_ERR_NVS_BASE + 0x0a) /*!< TBA */ +#define ESP_ERR_NVS_INVALID_STATE (ESP_ERR_NVS_BASE + 0x0b) /*!< TBA */ +#define ESP_ERR_NVS_INVALID_LENGTH (ESP_ERR_NVS_BASE + 0x0c) /*!< TBA */ +/** + * @brief Mode of opening the non-volatile storage + * + */ typedef enum { - NVS_READONLY, - NVS_READWRITE + NVS_READONLY, /*!< Read only */ + NVS_READWRITE /*!< Read and write */ } nvs_open_mode; /** @@ -129,24 +133,26 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * It is suggested that nvs_get/set_str is used for zero-terminated C strings, and * nvs_get/set_blob used for arbitrary data structures. * - * Example of using nvs_get_i32: + * \code{c} + * // Example of using nvs_get_i32: * int32_t max_buffer_size = 4096; // default value * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size); * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still * // have its default value. * - * Example (without error checking) of using nvs_get_str to get a string into dynamic array: + * // Example (without error checking) of using nvs_get_str to get a string into dynamic array: * size_t required_size; * nvs_get_str(my_handle, "server_name", NULL, &required_size); * char* server_name = malloc(required_size); * nvs_get_str(my_handle, "server_name", server_name, &required_size); * - * Example (without error checking) of using nvs_get_blob to get a binary data + * // Example (without error checking) of using nvs_get_blob to get a binary data * into a static array: * uint8_t mac_addr[6]; * size_t size = sizeof(mac_addr); * nvs_get_blob(my_handle, "dst_mac_addr", mac_addr, &size); + * \endcode * * @param[in] handle Handle obtained from nvs_open function. * @param[in] key Key name. Maximal length is determined by the underlying From 234739f51a917ae3b27c551471d906d548678b09 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Thu, 27 Oct 2016 21:22:35 +0200 Subject: [PATCH 70/95] Draft of non-volatile storage component documentation --- docs/Doxyfile | 2 +- docs/api/nvs.rst | 68 +++++++++++++++++++++++++++++++++++++++++++ docs/api/template.rst | 9 ++++++ docs/index.rst | 1 + 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 docs/api/nvs.rst diff --git a/docs/Doxyfile b/docs/Doxyfile index f905de74ce..bb55b8ba39 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -4,7 +4,7 @@ GENERATE_LATEX = NO GENERATE_MAN = NO GENERATE_RTF = NO CASE_SENSE_NAMES = NO -INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver/gpio.h ../components/esp32/include/rom/gpio.h ../components/bt/include/bt.h +INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver/gpio.h ../components/esp32/include/rom/gpio.h ../components/bt/include ../components/nvs_flash/include RECURSIVE = YES QUIET = YES JAVADOC_AUTOBRIEF = YES diff --git a/docs/api/nvs.rst b/docs/api/nvs.rst new file mode 100644 index 0000000000..227a1c1f7f --- /dev/null +++ b/docs/api/nvs.rst @@ -0,0 +1,68 @@ +.. include:: ../../components/nvs_flash/README.rst + +Reference +--------- + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: nvs_open_mode + +Functions +^^^^^^^^^ + +.. doxygenfunction:: nvs_flash_init +.. doxygenfunction:: nvs_flash_init_custom + +.. doxygenfunction:: nvs_open + +*Note: the following nvs_set_X function are "the same" except the data type accepted* + +.. doxygenfunction:: nvs_set_i8 +.. doxygenfunction:: nvs_set_u8 +.. doxygenfunction:: nvs_set_i16 +.. doxygenfunction:: nvs_set_u16 +.. doxygenfunction:: nvs_set_i32 +.. doxygenfunction:: nvs_set_u32 +.. doxygenfunction:: nvs_set_i64 +.. doxygenfunction:: nvs_set_u64 +.. doxygenfunction:: nvs_set_str +.. doxygenfunction:: nvs_set_blob + +*Note: the following nvs_get_X functions are "the same" except the data type returned* + +.. doxygenfunction:: nvs_get_i8 +.. doxygenfunction:: nvs_get_u8 +.. doxygenfunction:: nvs_get_i16 +.. doxygenfunction:: nvs_get_u16 +.. doxygenfunction:: nvs_get_i32 +.. doxygenfunction:: nvs_get_u32 +.. doxygenfunction:: nvs_get_i64 +.. doxygenfunction:: nvs_get_u64 +.. doxygenfunction:: nvs_get_str +.. doxygenfunction:: nvs_get_blob + +.. doxygenfunction:: nvs_erase_key +.. doxygenfunction:: nvs_erase_all +.. doxygenfunction:: nvs_commit +.. doxygenfunction:: nvs_close + +Error codes +^^^^^^^^^^^ + +.. doxygendefine:: ESP_ERR_NVS_BASE +.. doxygendefine:: ESP_ERR_NVS_NOT_INITIALIZED +.. doxygendefine:: ESP_ERR_NVS_NOT_FOUND +.. doxygendefine:: ESP_ERR_NVS_TYPE_MISMATCH +.. doxygendefine:: ESP_ERR_NVS_READ_ONLY +.. doxygendefine:: ESP_ERR_NVS_NOT_ENOUGH_SPACE +.. doxygendefine:: ESP_ERR_NVS_INVALID_NAME +.. doxygendefine:: ESP_ERR_NVS_INVALID_HANDLE +.. doxygendefine:: ESP_ERR_NVS_REMOVE_FAILED +.. doxygendefine:: ESP_ERR_NVS_KEY_TOO_LONG +.. doxygendefine:: ESP_ERR_NVS_PAGE_FULL +.. doxygendefine:: ESP_ERR_NVS_INVALID_STATE +.. doxygendefine:: ESP_ERR_NVS_INVALID_LENGTH + + + diff --git a/docs/api/template.rst b/docs/api/template.rst index 8b1dfd4c50..0f2623c47f 100644 --- a/docs/api/template.rst +++ b/docs/api/template.rst @@ -6,6 +6,15 @@ Overview INSTRUCTIONS: Provide overview where and how this API may be used. For large number of functions, break down description into groups. +Use the folowing heading levels: + +* # with overline, for parts +* \* with overline, for chapters +* =, for sections +* -, for subsections +* ^, for subsubsections +* ", for paragraphs + Application Example ------------------- diff --git a/docs/index.rst b/docs/index.rst index 5c4d7025c6..9b62885bb1 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,6 +37,7 @@ Contents: Wi-Fi Bluetooth GPIO + NVS Template .. toctree:: From fa002b490966ba3e4112a0d6f459ced22c7aa0ca Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Fri, 28 Oct 2016 14:43:48 +0200 Subject: [PATCH 71/95] Fixed headers to match python doc standard --- components/nvs_flash/README.rst | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/components/nvs_flash/README.rst b/components/nvs_flash/README.rst index 2f1c469135..ade5518aa5 100644 --- a/components/nvs_flash/README.rst +++ b/components/nvs_flash/README.rst @@ -7,14 +7,14 @@ Introduction Non-volatile storage (NVS) library is designed to store key-value pairs in flash. This sections introduces some concepts used by NVS. Underlying storage -~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^ Currently NVS uses a portion of main flash memory through ``spi_flash_{read|write|erase}`` APIs. The range of flash sectors to be used by the library is provided to ``nvs_flash_init`` function. Future versions of this library may add other storage backends to keep data in another flash chip (SPI or I2C), RTC, FRAM, etc. Keys and values -~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^ NVS operates on key-value pairs. Keys are ASCII strings, maximum key length is currently 15 characters. Values can have one of the following types: @@ -32,12 +32,12 @@ Keys are required to be unique. Writing a value for a key which already exists b Data type check is also performed when reading a value. An error is returned if data type of read operation doesn’t match the data type of the value. Namespaces -~~~~~~~~~~ +^^^^^^^^^^ To mitigate potential conflicts in key names between different components, NVS assigns each key-value pair to one of namespaces. Namespace names follow the same rules as key names, i.e. 15 character maximum length. Namespace name is specified in the ``nvs_open`` call. This call returns an opaque handle, which is used in subsequent calls to ``nvs_read_*``, ``nvs_write_*``, and ``nvs_commit`` functions. This way, handle is associated with a namespace, and key names will not collide with same names in other namespaces. Security, tampering, and robustness -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ NVS library doesn't implement tamper prevention measures. It is possible for anyone with physical access to the flash chip to alter, erase, or add key-value pairs. @@ -59,12 +59,12 @@ Internals --------- Log of key-value pairs -~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^ NVS stores key-value pairs sequentially, with new key-value pairs being added at the end. When a value of any given key has to be updated, new key-value pair is added at the end of the log and old key-value pair is marked as erased. Pages and entries -~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^ NVS library uses two main entities in its operation: pages and entries. Page is a logical structure which stores a portion of the overall log. Logical page corresponds to one physical sector of flash memory. Pages which are in use have a *sequence number* associated with them. Sequence numbers impose an ordering on pages. Higher sequence numbers correspond to pages which were created later. Each page can be in one of the following states: @@ -101,7 +101,7 @@ Mapping from flash sectors to logical pages doesn't have any particular order. L +----------+ +----------+ +----------+ +----------+ Structure of a page -~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^ For now we assume that flash sector size is 4096 bytes and that ESP32 flash encryption hardware operates on 32-byte blocks. It is possible to introduce some settings configurable at compile-time (e.g. via menuconfig) to accommodate flash chips with different sector sizes (although it is not clear if other components in the system, e.g. SPI flash driver and SPI flash cache can support these other sizes). @@ -133,7 +133,7 @@ CRC32 value in header is calculated over the part which doesn't include state va The following sections describe structure of entry state bitmap and entry itself. Entry and entry state bitmap -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Each entry can be in one of the following three states. Each state is represented with two bits in the entry state bitmap. Final four bits in the bitmap (256 - 2 * 126) are unused. @@ -148,7 +148,7 @@ Erased (2'b00) Structure of entry -~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^ For values of primitive types (currently integers from 1 to 8 bytes long), entry holds one key-value pair. For string and blob types, entry holds part of the whole key-value pair. In case when a key-value pair spans multiple entries, all entries are stored in the same page. @@ -200,7 +200,7 @@ Variable length values (strings and blobs) are written into subsequent entries, Namespaces -~~~~~~~~~~ +^^^^^^^^^^ As mentioned above, each key-value pair belongs to one of the namespaces. Namespaces identifiers (strings) are stored as keys of key-value pairs in namespace with index 0. Values corresponding to these keys are indexes of these namespaces. @@ -218,10 +218,9 @@ As mentioned above, each key-value pair belongs to one of the namespaces. Namesp Item hash list -~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^ To reduce the number of reads performed from flash memory, each member of Page class maintains a list of pairs: (item index; item hash). This list makes searches much quicker. Instead of iterating over all entries, reading them from flash one at a time, ``Page::findItem`` first performs search for item hash in the hash list. This gives the item index within the page, if such an item exists. Due to a hash collision it is possible that a different item will be found. This is handled by falling back to iteration over items in flash. Each node in hash list contains a 24-bit hash and 8-bit item index. Hash is calculated based on item namespace and key name. CRC32 is used for calculation, result is truncated to 24 bits. To reduce overhead of storing 32-bit entries in a linked list, list is implemented as a doubly-linked list of arrays. Each array holds 29 entries, for the total size of 128 bytes, together with linked list pointers and 32-bit count field. Minimal amount of extra RAM useage per page is therefore 128 bytes, maximum is 640 bytes. - From 2d56953ee458266e00bba2788ec6821823eddd8d Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sat, 29 Oct 2016 20:54:58 +0200 Subject: [PATCH 72/95] docu makup update --- components/bt/include/bt.h | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/components/bt/include/bt.h b/components/bt/include/bt.h index 1e89f96aa1..f476334b12 100644 --- a/components/bt/include/bt.h +++ b/components/bt/include/bt.h @@ -28,37 +28,36 @@ extern "C" { * * This function should be called only once, before any other BT functions are called. */ -void bt_controller_init(); +void bt_controller_init(void); -/** @brief: vhci_host_callback +/** @brief vhci_host_callback * used for vhci call host function to notify what host need to do * * notify_host_send_available: notify host can send packet to controller * notify_host_recv: notify host that controller has packet send to host */ typedef struct vhci_host_callback { - void (*notify_host_send_available)(void); int (*notify_host_recv)(uint8_t *data, uint16_t len); } vhci_host_callback_t; -/** @brief: API_vhci_host_check_send_available +/** @brief API_vhci_host_check_send_available * used for check actively if the host can send packet to controller or not. - * return true for ready to send, false means cannot send packet + * @return true for ready to send, false means cannot send packet */ bool API_vhci_host_check_send_available(void); -/** @brief: API_vhci_host_send_packet +/** @brief API_vhci_host_send_packet * host send packet to controller - * param data is the packet point, the param len is the packet length - * return void + * @param data the packet point + *,@param len the packet length */ void API_vhci_host_send_packet(uint8_t *data, uint16_t len); -/** @brief: API_vhci_host_register_callback +/** @brief API_vhci_host_register_callback * register the vhci referece callback, the call back * struct defined by vhci_host_callback structure. - * param is the vhci_host_callback type variable + * @param callback vhci_host_callback type variable */ void API_vhci_host_register_callback(const vhci_host_callback_t *callback); From 905d27815c4889be2250e408e9194fd3ae70d058 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sat, 29 Oct 2016 23:00:30 +0200 Subject: [PATCH 73/95] API samples - Logging library - Virtual file system component --- docs/Doxyfile | 31 ++++++++++++++++++++----------- docs/api/bt.rst | 2 +- docs/api/log.rst | 20 ++++++++++++++++++++ docs/api/nvs.rst | 4 ++-- docs/api/vfs.rst | 27 +++++++++++++++++++++++++++ docs/index.rst | 4 +++- 6 files changed, 73 insertions(+), 15 deletions(-) create mode 100644 docs/api/log.rst create mode 100644 docs/api/vfs.rst diff --git a/docs/Doxyfile b/docs/Doxyfile index bb55b8ba39..9c53aff1f3 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1,13 +1,22 @@ PROJECT_NAME = "ESP32 Programming Guide" -XML_OUTPUT = xml -GENERATE_LATEX = NO -GENERATE_MAN = NO -GENERATE_RTF = NO -CASE_SENSE_NAMES = NO -INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver/gpio.h ../components/esp32/include/rom/gpio.h ../components/bt/include ../components/nvs_flash/include -RECURSIVE = YES + +INPUT = ../components/esp32/include/esp_wifi.h ../components/driver/include/driver ../components/esp32/include/rom/gpio.h ../components/bt/include ../components/nvs_flash/include ../components/log/include ../components/vfs/include + +WARN_NO_PARAMDOC = YES + +RECURSIVE = NO +CASE_SENSE_NAMES = NO +EXTRACT_ALL = NO + +GENERATE_XML = YES +XML_OUTPUT = xml + +GENERATE_HTML = NO +HAVE_DOT = NO +GENERATE_LATEX = NO +GENERATE_MAN = NO +GENERATE_RTF = NO + QUIET = YES -JAVADOC_AUTOBRIEF = YES -GENERATE_HTML = NO -GENERATE_XML = YES -WARN_LOGFILE = "DoxyGenWarningLog.txt" +WARN_LOGFILE = "doxygen-warning-log.txt" + diff --git a/docs/api/bt.rst b/docs/api/bt.rst index 16f30dc4e6..72ab9fbd12 100644 --- a/docs/api/bt.rst +++ b/docs/api/bt.rst @@ -19,7 +19,7 @@ Reference Type Definitions ^^^^^^^^^^^^^^^^ -.. doxygentypedef:: vhci_host_callback +.. doxygenstruct:: vhci_host_callback Functions ^^^^^^^^^ diff --git a/docs/api/log.rst b/docs/api/log.rst new file mode 100644 index 0000000000..8e0f2d85da --- /dev/null +++ b/docs/api/log.rst @@ -0,0 +1,20 @@ +.. include:: ../../components/log/README.rst + +API Reference +------------- + +Enumerations +^^^^^^^^^^^^ + +.. doxygenenum:: esp_log_level_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: esp_log_level_set +.. doxygenfunction:: esp_log_set_vprintf +.. doxygenfunction:: esp_log_write + +.. FIXME esp_log_timestamp + + diff --git a/docs/api/nvs.rst b/docs/api/nvs.rst index 227a1c1f7f..fc2bba5a16 100644 --- a/docs/api/nvs.rst +++ b/docs/api/nvs.rst @@ -1,7 +1,7 @@ .. include:: ../../components/nvs_flash/README.rst -Reference ---------- +API Reference +------------- Enumerations ^^^^^^^^^^^^ diff --git a/docs/api/vfs.rst b/docs/api/vfs.rst new file mode 100644 index 0000000000..97ea1a5848 --- /dev/null +++ b/docs/api/vfs.rst @@ -0,0 +1,27 @@ +.. include:: ../../components/vfs/README.rst + +API Reference +------------- + +Defines +^^^^^^^ + +.. doxygendefine:: ESP_VFS_PATH_MAX +.. doxygendefine:: ESP_VFS_FLAG_DEFAULT +.. doxygendefine:: ESP_VFS_FLAG_CONTEXT_PTR + + +Structures +^^^^^^^^^^ + +.. doxygenstruct:: esp_vfs_t + +Functions +^^^^^^^^^ + +.. doxygenfunction:: esp_vfs_dev_uart_register +.. doxygenfunction:: esp_vfs_register + + + + diff --git a/docs/index.rst b/docs/index.rst index 9b62885bb1..72c5df13f4 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,7 +37,9 @@ Contents: Wi-Fi Bluetooth GPIO - NVS + Logging + Non-volatile storage + Virtual filesystem Template .. toctree:: From f6118c67b09f479297a959ce6b0714d717e2ebbc Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sat, 29 Oct 2016 23:00:46 +0200 Subject: [PATCH 74/95] Fixed desription of logging library --- components/log/README.rst | 61 +++++++++++++++++++++++++ components/log/include/esp_log.h | 76 ++++---------------------------- 2 files changed, 69 insertions(+), 68 deletions(-) create mode 100644 components/log/README.rst diff --git a/components/log/README.rst b/components/log/README.rst new file mode 100644 index 0000000000..d378179c8f --- /dev/null +++ b/components/log/README.rst @@ -0,0 +1,61 @@ +Logging library +=============== + +Overview +-------- + +Log library has two ways of managing log verbosity: compile time, set via menuconfig; and runtime, using ``esp_log_set_level`` function. + +At compile time, filtering is done using ``CONFIG_LOG_DEFAULT_LEVEL`` macro, set via menuconfig. All logging statments for levels higher than ``CONFIG_LOG_DEFAULT_LEVEL`` will be removed by the preprocessor. + +At run time, all logs below ``CONFIG_LOG_DEFAULT_LEVEL`` are enabled by default. ``esp_log_set_level`` function may be used to set logging level per module. Modules are identified by their tags, which are human-readable ASCII zero-terminated strings. + +How to use this library +----------------------- + +In each C file which uses logging functionality, define TAG variable like this: + +.. code-block:: c + + static const char* TAG = "MyModule"; + +then use one of logging macros to produce output, e.g: + +.. code-block:: c + + ESP_LOGW(TAG, "Baud rate error %.1f%%. Requested: %d baud, actual: %d baud", error * 100, baud_req, baud_real); + +Several macros are available for different verbosity levels: + +* ``ESP_LOGE`` - error +* ``ESP_LOGW`` - warning +* ``ESP_LOGI`` - info +* ``ESP_LOGD`` - debug +* ``ESP_LOGV`` - verbose + +Additionally there is an _EARLY_ variant for each of these macros (e.g. ``ESP_EARLY_LOGE`` ).These variants can run in startup code, before heap allocator and syscalls have been initialized. When compiling bootloader, normal ``ESP_LOGx`` macros fall back to the same implementation as ``ESP_EARLY_LOGx`` macros. So the only place where ``ESP_EARLY_LOGx`` have to be used explicitly is the early startup code, such as heap allocator initialization code. + +(Note that such distinction would not have been necessary if we would have an ``ets_vprintf`` function in the ROM. Then it would be possible to switch implementation from _EARLY_ version to normal version on the fly. Unfortunately, ``ets_vprintf`` in ROM has been inlined by the compiler into ``ets_printf``, so it is not accessible outside.) + +To override default verbosity level at file or component scope, define ``LOG_LOCAL_LEVEL`` macro. At file scope, define it before including ``esp_log.h``, e.g.: + +.. code-block:: c + + #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE + #include "esp_log.h" + + +At component scope, define it in component makefile: + +.. code-block:: make + + CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG + +To configure logging output per module at runtime, add calls to ``esp_log_set_level`` function: + +.. code-block:: c + + esp_log_set_level("*", ESP_LOG_ERROR); // set all components to ERROR level + esp_log_set_level("wifi", ESP_LOG_WARN); // enable WARN logs from WiFi stack + esp_log_set_level("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client + diff --git a/components/log/include/esp_log.h b/components/log/include/esp_log.h index 8ca6e241d4..2878dc5015 100644 --- a/components/log/include/esp_log.h +++ b/components/log/include/esp_log.h @@ -24,76 +24,16 @@ extern "C" { #endif /** - * @brief Logging library - * - * Log library has two ways of managing log verbosity: compile time, set via - * menuconfig, and runtime, using esp_log_set_level function. - * - * At compile time, filtering is done using CONFIG_LOG_DEFAULT_LEVEL macro, set via - * menuconfig. All logging statments for levels higher than CONFIG_LOG_DEFAULT_LEVEL - * will be removed by the preprocessor. - * - * At run time, all logs below CONFIG_LOG_DEFAULT_LEVEL are enabled by default. - * esp_log_set_level function may be used to set logging level per module. - * Modules are identified by their tags, which are human-readable ASCII - * zero-terminated strings. - * - * How to use this library: - * - * In each C file which uses logging functionality, define TAG variable like this: - * - * static const char* TAG = "MyModule"; - * - * then use one of logging macros to produce output, e.g: - * - * ESP_LOGW(TAG, "Baud rate error %.1f%%. Requested: %d baud, actual: %d baud", error * 100, baud_req, baud_real); - * - * Several macros are available for different verbosity levels: - * - * ESP_LOGE — error - * ESP_LOGW — warning - * ESP_LOGI — info - * ESP_LOGD - debug - * ESP_LOGV - verbose - * - * Additionally there is an _EARLY_ variant for each of these macros (e.g. ESP_EARLY_LOGE). - * These variants can run in startup code, before heap allocator and syscalls - * have been initialized. - * When compiling bootloader, normal ESP_LOGx macros fall back to the same implementation - * as ESP_EARLY_LOGx macros. So the only place where ESP_EARLY_LOGx have to be used explicitly - * is the early startup code, such as heap allocator initialization code. - * - * (Note that such distinction would not have been necessary if we would have an - * ets_vprintf function in the ROM. Then it would be possible to switch implementation - * from _EARLY version to normal version on the fly. Unfortunately, ets_vprintf in ROM - * has been inlined by the compiler into ets_printf, so it is not accessible outside.) - * - * To override default verbosity level at file or component scope, define LOG_LOCAL_LEVEL macro. - * At file scope, define it before including esp_log.h, e.g.: - * - * #define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE - * #include "esp_log.h" - * - * At component scope, define it in component makefile: - * - * CFLAGS += -D LOG_LOCAL_LEVEL=ESP_LOG_DEBUG - * - * To configure logging output per module at runtime, add calls to esp_log_set_level function: - * - * esp_log_set_level("*", ESP_LOG_ERROR); // set all components to ERROR level - * esp_log_set_level("wifi", ESP_LOG_WARN); // enable WARN logs from WiFi stack - * esp_log_set_level("dhcpc", ESP_LOG_INFO); // enable INFO logs from DHCP client + * @brief Log level * */ - - typedef enum { - ESP_LOG_NONE, // No log output - ESP_LOG_ERROR, // Critical errors, software module can not recover on its own - ESP_LOG_WARN, // Error conditions from which recovery measures have been taken - ESP_LOG_INFO, // Information messages which describe normal flow of events - ESP_LOG_DEBUG, // Extra information which is not necessary for normal use (values, pointers, sizes, etc). - ESP_LOG_VERBOSE // Bigger chunks of debugging information, or frequent messages which can potentially flood the output. + ESP_LOG_NONE, /*!< No log output */ + ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ + ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */ + ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */ + ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ + ESP_LOG_VERBOSE /*!< Bigger chunks of debugging information, or frequent messages which can potentially flood the output. */ } esp_log_level_t; typedef int (*vprintf_like_t)(const char *, va_list); @@ -143,7 +83,7 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, . * * @return timestamp, in milliseconds */ -uint32_t esp_log_timestamp(); +uint32_t esp_log_timestamp(void); #if CONFIG_LOG_COLORS From 079f5faad88353ec64d44bbe08d612e514fc0819 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sat, 29 Oct 2016 23:15:27 +0200 Subject: [PATCH 75/95] Fixed confused Sphinx Sphinx failed to phrase esp_log_timestamp reorderdering esp_log_write and esp_log_timestamp fixed this issue --- components/log/include/esp_log.h | 23 +++++++++++------------ docs/api/log.rst | 3 +-- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/components/log/include/esp_log.h b/components/log/include/esp_log.h index 2878dc5015..6716f6e10f 100644 --- a/components/log/include/esp_log.h +++ b/components/log/include/esp_log.h @@ -29,7 +29,7 @@ extern "C" { */ typedef enum { ESP_LOG_NONE, /*!< No log output */ - ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ + ESP_LOG_ERROR, /*!< Critical errors, software module can not recover on its own */ ESP_LOG_WARN, /*!< Error conditions from which recovery measures have been taken */ ESP_LOG_INFO, /*!< Information messages which describe normal flow of events */ ESP_LOG_DEBUG, /*!< Extra information which is not necessary for normal use (values, pointers, sizes, etc). */ @@ -60,17 +60,6 @@ void esp_log_level_set(const char* tag, esp_log_level_t level); */ void esp_log_set_vprintf(vprintf_like_t func); -/** - * @brief Write message into the log - * - * This function is not intended to be used directly. Instead, use one of - * ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros. - * - * This function or these macros should not be used from an interrupt. - */ -void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4))); - - /** * @brief Function which returns timestamp to be used in log output * @@ -85,6 +74,16 @@ void esp_log_write(esp_log_level_t level, const char* tag, const char* format, . */ uint32_t esp_log_timestamp(void); +/** + * @brief Write message into the log + * + * This function is not intended to be used directly. Instead, use one of + * ESP_LOGE, ESP_LOGW, ESP_LOGI, ESP_LOGD, ESP_LOGV macros. + * + * This function or these macros should not be used from an interrupt. + */ +void esp_log_write(esp_log_level_t level, const char* tag, const char* format, ...) __attribute__ ((format (printf, 3, 4))); + #if CONFIG_LOG_COLORS #define LOG_COLOR_BLACK "30" diff --git a/docs/api/log.rst b/docs/api/log.rst index 8e0f2d85da..dc76a30470 100644 --- a/docs/api/log.rst +++ b/docs/api/log.rst @@ -13,8 +13,7 @@ Functions .. doxygenfunction:: esp_log_level_set .. doxygenfunction:: esp_log_set_vprintf +.. doxygenfunction:: esp_log_timestamp .. doxygenfunction:: esp_log_write -.. FIXME esp_log_timestamp - From 19af5b7a764ae33a29001cb392f5a20ce4400432 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sat, 29 Oct 2016 23:35:12 +0200 Subject: [PATCH 76/95] Changed title of docs --- docs/conf.py | 4 ++-- docs/index.rst | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 5ba76d7f25..8a8821fb0d 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -57,8 +57,8 @@ source_suffix = '.rst' master_doc = 'index' # General information about the project. -project = u'Read the Docs Template' -copyright = u'2014, Read the Docs' +project = u'ESP32 Programming Guide' +copyright = u'2016, Espressif' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the diff --git a/docs/index.rst b/docs/index.rst index 72c5df13f4..e194992089 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,6 +1,10 @@ ESP32 Programming Guide ======================= +.. caution:: + + This is DRAFT - mind your step + Contents: .. toctree:: From 12efd96fb489ea3e697c32f24406aff2f96d7ff0 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 30 Oct 2016 19:37:45 +0100 Subject: [PATCH 77/95] Corrected documentation style This is for better visuaization with Sphinx --- components/nvs_flash/include/nvs.h | 23 +++++++++++++++-------- components/nvs_flash/include/nvs_flash.h | 2 ++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/components/nvs_flash/include/nvs.h b/components/nvs_flash/include/nvs.h index d0c9908afb..8418959793 100644 --- a/components/nvs_flash/include/nvs.h +++ b/components/nvs_flash/include/nvs.h @@ -62,12 +62,13 @@ typedef enum { * underlying implementation, but is guaranteed to be * at least 16 characters. Shouldn't be empty. * @param[in] open_mode NVS_READWRITE or NVS_READONLY. If NVS_READONLY, will - * open a handle for reading only. All write requests will - * be rejected for this handle. + * open a handle for reading only. All write requests will + * be rejected for this handle. * @param[out] out_handle If successful (return code is zero), handle will be * returned in this argument. * - * @return - ESP_OK if storage handle was opened successfully + * @return + * - ESP_OK if storage handle was opened successfully * - ESP_ERR_NVS_NOT_INITIALIZED if the storage driver is not initialized * - ESP_ERR_NVS_NOT_FOUND id namespace doesn't exist yet and * mode is NVS_READONLY @@ -90,7 +91,8 @@ esp_err_t nvs_open(const char* name, nvs_open_mode open_mode, nvs_handle *out_ha * @param[in] value The value to set. * @param[in] length For nvs_set_blob: length of binary value to set, in bytes. * - * @return - ESP_OK if value was set successfully + * @return + * - ESP_OK if value was set successfully * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_READ_ONLY if storage handle was opened as read only * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints @@ -168,7 +170,8 @@ esp_err_t nvs_set_blob(nvs_handle handle, const char* key, const void* value, si * zero, will be set to the actual length of the value * written. For nvs_get_str this includes zero terminator. * - * @return - ESP_OK if the value was retrieved successfully + * @return + * - ESP_OK if the value was retrieved successfully * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_INVALID_NAME if key name doesn't satisfy constraints @@ -197,7 +200,8 @@ esp_err_t nvs_get_blob(nvs_handle handle, const char* key, void* out_value, size * implementation, but is guaranteed to be at least * 16 characters. Shouldn't be empty. * - * @return - ESP_OK if erase operation was successful + * @return + * - ESP_OK if erase operation was successful * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist @@ -213,7 +217,8 @@ esp_err_t nvs_erase_key(nvs_handle handle, const char* key); * @param[in] handle Storage handle obtained with nvs_open. * Handles that were opened read only cannot be used. * - * @return - ESP_OK if erase operation was successful + * @return + * - ESP_OK if erase operation was successful * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only * - other error codes from the underlying storage driver @@ -230,7 +235,8 @@ esp_err_t nvs_erase_all(nvs_handle handle); * @param[in] handle Storage handle obtained with nvs_open. * Handles that were opened read only cannot be used. * - * @return - ESP_OK if the changes have been written successfully + * @return + * - ESP_OK if the changes have been written successfully * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL * - other error codes from the underlying storage driver */ @@ -255,3 +261,4 @@ void nvs_close(nvs_handle handle); #endif #endif //ESP_NVS_H + diff --git a/components/nvs_flash/include/nvs_flash.h b/components/nvs_flash/include/nvs_flash.h index ce98f39407..1cade0e956 100644 --- a/components/nvs_flash/include/nvs_flash.h +++ b/components/nvs_flash/include/nvs_flash.h @@ -22,6 +22,8 @@ extern "C" { Temporarily, this region is hardcoded as a 12KB (0x3000 byte) region starting at 24KB (0x6000 byte) offset in flash. + + @return ESP_OK if flash was successfully initialised. */ esp_err_t nvs_flash_init(void); From d66f05c61b561c04d46cbe2aeb1cdb54fd0c2fb9 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 30 Oct 2016 19:38:44 +0100 Subject: [PATCH 78/95] Guide on documenting code --- docs/_static/1.png | Bin 11412 -> 0 bytes .../_static/doc-code-documentation-inline.png | Bin 0 -> 52513 bytes .../doc-code-documentation-rendered.png | Bin 0 -> 93186 bytes docs/_static/doc-code-function.png | Bin 0 -> 194398 bytes docs/_static/doc-code-member.png | Bin 0 -> 75946 bytes docs/_static/doc-code-void-function.png | Bin 0 -> 68465 bytes docs/documenting-code.rst | 126 ++++++++++++++++++ docs/index.rst | 7 +- 8 files changed, 132 insertions(+), 1 deletion(-) delete mode 100644 docs/_static/1.png create mode 100644 docs/_static/doc-code-documentation-inline.png create mode 100644 docs/_static/doc-code-documentation-rendered.png create mode 100644 docs/_static/doc-code-function.png create mode 100644 docs/_static/doc-code-member.png create mode 100644 docs/_static/doc-code-void-function.png create mode 100644 docs/documenting-code.rst diff --git a/docs/_static/1.png b/docs/_static/1.png deleted file mode 100644 index 4920892781f90c3db323f82033866c3f7116c073..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11412 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
I-V-NX(N}q}D@(Dr+V{Hb>y4lN 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 U;S}7@z`(%Z>FVdQ&MBb@0LNnn&j0`b diff --git a/docs/_static/doc-code-documentation-inline.png b/docs/_static/doc-code-documentation-inline.png new file mode 100644 index 0000000000000000000000000000000000000000..72bf22f156224e4e32e7934828ccc73f15cea67e GIT binary patch literal 52513 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 Tw6A4gU|{fc^>bP0l+XkKb7s{- literal 0 HcmV?d00001 diff --git a/docs/_static/doc-code-documentation-rendered.png b/docs/_static/doc-code-documentation-rendered.png new file mode 100644 index 0000000000000000000000000000000000000000..d287d3c2e133a45c7bf11fd130d274a52202e246 GIT binary patch literal 93186 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

y~8{bZ}19aYtNhJoDYr@JJ@(7 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৞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 z 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 literal 0 HcmV?d00001 diff --git a/docs/_static/doc-code-function.png b/docs/_static/doc-code-function.png new file mode 100644 index 0000000000000000000000000000000000000000..758971ce7271bb175d27d063643f21c03e00b8df GIT binary patch literal 194398 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
$*5C2*T@t5w)7_oH_GgxzT(B&3dvZ$n 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%0A?u9=SpB8M@^|-vuH{9*h;kfX_ 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 literal 0 HcmV?d00001 diff --git a/docs/_static/doc-code-member.png b/docs/_static/doc-code-member.png new file mode 100644 index 0000000000000000000000000000000000000000..eee897a496bd7ad895a57ca8c1669f7a7cc33576 GIT binary patch literal 75946 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 ZpE*ISOZ4R8A_fKq22WQ%mvv4FO#r-{g--wg literal 0 HcmV?d00001 diff --git a/docs/_static/doc-code-void-function.png b/docs/_static/doc-code-void-function.png new file mode 100644 index 0000000000000000000000000000000000000000..36eeced6b8bf0dabff9dbb43b4e1434d2ea662bf GIT binary patch literal 68465 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 JMIrT3?xD?ncNi~T>xP=l;= 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

)u%d`#&u* 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 . You are doing it by inserting special commands, for instance ``@param``, into standard comments blocks like for example ``/* @param ratio this is oxygen to air ratio */``. + +Doxygen is phrasing the code, extracting the commands together with subsequent text, and building documentation out of it. + +Typical comment block, that contains documentation of a function, looks like below. + +.. image:: _static/doc-code-documentation-inline.png + :align: center + :alt: Sample inline code documentation + +Doxygen supports couple of formatting styles. It also gives you great flexibility on level of details to include in documentation. To get the taste of available features please check data reach and very well organized `Doxygen Manual `_ . + +Why we need it? +--------------- + +The purpose of this description is to provide quick summary on documentation style used in `espressif/esp-idf `_ repository. + +The ultimate goal is to ensure that all the code is consistently documented, so we can use tools like `Sphinx `_ and `Breathe `_ to aid preparation and automatic updates of API documentation when the code changes. The above piece of code renders in Sphinx like below: + +.. image:: _static/doc-code-documentation-rendered.png + :align: center + :alt: Sample inline code after rendering + + +Go for it! +---------- + +When writing code for this repository, please follow guidelines below. + + 1. Document all building blocks of code: functions, structs, typedefs, enums, macros, etc. Provide enough information on purpose, functionality and limitations of documented items, as you would like to see them documented when reading the code by others. + + 2. Documentation of function should describe what this function does. If it accepts input parameters and returns some value, all they should be explained. + + 3. Do not add a data type before parameter or any other characters besides spaces. All spaces and line breaks are compressed into a single space. If you like to break a line, then break it twice. + + .. image:: _static/doc-code-function.png + :align: center + :alt: Sample function documented inline and after rendering + + 4. If function has void input or does not return any value, then skip ``@param`` or ``@return`` + + .. image:: _static/doc-code-void-function.png + :align: center + :alt: Sample void function documented inline and after rendering + + 5. When documenting members of a ``struct``, ``typedef`` or ``enum``, place specific comment like below after each member. + + .. image:: _static/doc-code-member.png + :align: center + :alt: Sample of member documentation inline and after rendering + + 6. To provide well formatted lists, break the line after command (like ``@return`` in example below). + + :: + + ... + * + * @return + * - ESP_OK if erase operation was successful + * - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL + * - ESP_ERR_NVS_READ_ONLY if handle was opened as read only + * - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist + * - other error codes from the underlying storage driver + * + ... + + + 7. Overview of functionality of documented header file, or group of files that make a library, should be placed in separate ``README.rst`` file. + +Go one extra mile +----------------- + +There are are couple of tips how you can make your documentation even better and more useful to the reader. + +Add code snippets to illustrate implementation. To do so, enclose the snippet using ``@code{c}`` and ``@endcode`` commands. + +:: + + ... + * + * @code{c} + * // Example of using nvs_get_i32: + * int32_t max_buffer_size = 4096; // default value + * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size); + * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND); + * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still + * // have its default value. + * @endcode + * + ... + +To highlight some information use command ``@attention`` or ``@note``. Example below also shows how to use a numbered list. + +:: + + ... + * + * @attention + * 1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode + * 2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect. + * + ... + + +Use markdown to make your documentation even more readable. With markdown you can add headers, links, tables and more. + +:: + + ... + * + * [ESP32 Technical Reference](http://espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_en.pdf) + * + ... + +Wrap up +------- + +We love good code that is doing cool things. +We love it even better, if it is well documented, so we can qickly make it run and also do the cool things. + diff --git a/docs/index.rst b/docs/index.rst index e194992089..da03346e71 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,7 +3,11 @@ ESP32 Programming Guide .. caution:: - This is DRAFT - mind your step + This DRAF version of documentation developed within `ESP-IDF 1.0 Release plan `_. + It is scheduled for merging with `espressif/esp-idf `_ repository at the release date. + Before merging it may be incomplete, or not fully in sync with espressif/esp-idf. + Please mind your step! + Contents: @@ -58,6 +62,7 @@ Contents: :maxdepth: 1 contributing + documenting-code contributor-agreement .. toctree:: From 73944e680053610e7718cdb21763e28dae08b246 Mon Sep 17 00:00:00 2001 From: Krzysztof Date: Sun, 30 Oct 2016 19:54:10 +0100 Subject: [PATCH 79/95] Typo corrections --- docs/documenting-code.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/documenting-code.rst b/docs/documenting-code.rst index f07f464ed9..51a0dbf7d3 100644 --- a/docs/documenting-code.rst +++ b/docs/documenting-code.rst @@ -4,7 +4,7 @@ Documenting Code Introduction ------------ -When documenting code for this repository, please follow `Doxygen style `_ . You are doing it by inserting special commands, for instance ``@param``, into standard comments blocks like for example ``/* @param ratio this is oxygen to air ratio */``. +When documenting code for this repository, please follow `Doxygen style `_. You are doing it by inserting special commands, for instance ``@param``, into standard comments blocks like for example ``/* @param ratio this is oxygen to air ratio */``. Doxygen is phrasing the code, extracting the commands together with subsequent text, and building documentation out of it. @@ -14,7 +14,7 @@ Typical comment block, that contains documentation of a function, looks like bel :align: center :alt: Sample inline code documentation -Doxygen supports couple of formatting styles. It also gives you great flexibility on level of details to include in documentation. To get the taste of available features please check data reach and very well organized `Doxygen Manual `_ . +Doxygen supports couple of formatting styles. It also gives you great flexibility on level of details to include in documentation. To get the taste of available features please check data reach and very well organized `Doxygen Manual `_. Why we need it? --------------- @@ -35,7 +35,7 @@ When writing code for this repository, please follow guidelines below. 1. Document all building blocks of code: functions, structs, typedefs, enums, macros, etc. Provide enough information on purpose, functionality and limitations of documented items, as you would like to see them documented when reading the code by others. - 2. Documentation of function should describe what this function does. If it accepts input parameters and returns some value, all they should be explained. + 2. Documentation of function should describe what this function does. If it accepts input parameters and returns some value, all of them should be explained. 3. Do not add a data type before parameter or any other characters besides spaces. All spaces and line breaks are compressed into a single space. If you like to break a line, then break it twice. @@ -76,7 +76,7 @@ When writing code for this repository, please follow guidelines below. Go one extra mile ----------------- -There are are couple of tips how you can make your documentation even better and more useful to the reader. +There are couple of tips how you can make your documentation even better and more useful to the reader. Add code snippets to illustrate implementation. To do so, enclose the snippet using ``@code{c}`` and ``@endcode`` commands. @@ -122,5 +122,5 @@ Wrap up ------- We love good code that is doing cool things. -We love it even better, if it is well documented, so we can qickly make it run and also do the cool things. +We love it even better, if it is well documented, so we can quickly make it run and also do the cool things. From fc6b52574a337fd4f4b7a13155eea488582e1b0d Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 1 Nov 2016 13:07:10 +0800 Subject: [PATCH 80/95] components/openssl: refactor the SSL port function and debug function --- components/openssl/include/internal/ssl_dbg.h | 28 ++++++--- components/openssl/include/platform/ssl_opt.h | 48 ++++++++++++++++ .../openssl/include/platform/ssl_port.h | 16 +++++- components/openssl/library/ssl_cert.c | 8 +-- components/openssl/library/ssl_lib.c | 24 ++++---- components/openssl/library/ssl_pkey.c | 8 +-- components/openssl/library/ssl_stack.c | 14 ++--- components/openssl/library/ssl_x509.c | 8 +-- components/openssl/platform/ssl_pm.c | 57 +++++++++++-------- components/openssl/platform/ssl_port.c | 6 +- 10 files changed, 148 insertions(+), 69 deletions(-) create mode 100644 components/openssl/include/platform/ssl_opt.h diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index d6ae47499e..1b0a73f167 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -15,21 +15,33 @@ #ifndef _SSL_DEBUG_H_ #define _SSL_DEBUG_H_ +#include "platform/ssl_opt.h" +#include "platform/ssl_port.h" + #ifdef __cplusplus extern "C" { #endif -#define SSL_DEBUG_ENBALE 1 +#ifndef SSL_DEBUG_ENBALE +#define SSL_DEBUG_ENBALE 0 +#endif + +#ifndef SSL_DEBUG_LEVEL #define SSL_DEBUG_LEVEL 0 -#define SSL_ASSERT_ENABLE 1 -#define SSL_DEBUG_LOCATION_ENABLE 1 +#endif -#if SSL_DEBUG_ENBALE - extern int ets_printf(const char *fmt, ...); +#ifndef SSL_ASSERT_ENABLE +#define SSL_ASSERT_ENABLE 0 +#endif - #define SSL_PRINT ets_printf -#else - #define SSL_PRINT(...) +#ifndef SSL_DEBUG_LOCATION_ENABLE +#define SSL_DEBUG_LOCATION_ENABLE 0 +#endif + +#ifndef SSL_PRINT + #include "stdio.h" + extern int printf(const char *fmt, ...); + #define SSL_PRINT printf #endif #if SSL_DEBUG_LOCATION_ENABLE diff --git a/components/openssl/include/platform/ssl_opt.h b/components/openssl/include/platform/ssl_opt.h new file mode 100644 index 0000000000..01d438eb8a --- /dev/null +++ b/components/openssl/include/platform/ssl_opt.h @@ -0,0 +1,48 @@ +// Copyright 2015-2016 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 _SSL_OPT_H_ +#define _SSL_OPT_H_ + +#ifdef __cplusplus + extern "C" { +#endif + +/** + * if not define "ESP32_IDF_PLATFORM", system will use esp8266 platform interface + */ +#define ESP32_IDF_PLATFORM + +/** + * openssl debug print function enable + */ +#define SSL_DEBUG_ENBALE 0 + +/** + * openssl debug print function level. function whose level is lower that "SSL_DEBUG_LEVEL" + * will not print message + */ +#define SSL_DEBUG_LEVEL 0 + +/** + * openssl assert function enable, it will check the input paramter and print the message + */ +#define SSL_ASSERT_ENABLE 0 + +/** + * openssl location function enable, it will print location of the positioning error + */ +#define SSL_DEBUG_LOCATION_ENABLE 0 + +#endif diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h index 995d33e0e5..4a319c91ae 100644 --- a/components/openssl/include/platform/ssl_port.h +++ b/components/openssl/include/platform/ssl_port.h @@ -19,11 +19,15 @@ extern "C" { #endif +#include "platform/ssl_opt.h" + +#ifdef ESP32_IDF_PLATFORM + #include "esp_types.h" -void* ssl_zalloc(size_t size); -void *ssl_malloc(size_t size); -void ssl_free(void *p); +void *ssl_mem_zalloc(size_t size); +void *ssl_mem_malloc(size_t size); +void ssl_mem_free(void *p); void* ssl_memcpy(void *to, const void *from, size_t size); size_t ssl_strlen(const char *src); @@ -31,4 +35,10 @@ size_t ssl_strlen(const char *src); void ssl_speed_up_enter(void); void ssl_speed_up_exit(void); +#elif defined(SSL_PLATFORM_USER_INCLUDE) + +SSL_PLATFORM_USER_INCLUDE + +#endif + #endif diff --git a/components/openssl/library/ssl_cert.c b/components/openssl/library/ssl_cert.c index e4fd4d7785..0193a441e0 100644 --- a/components/openssl/library/ssl_cert.c +++ b/components/openssl/library/ssl_cert.c @@ -28,9 +28,9 @@ CERT *__ssl_cert_new(CERT *ic) X509 *ix; EVP_PKEY *ipk; - cert = ssl_zalloc(sizeof(CERT)); + cert = ssl_mem_zalloc(sizeof(CERT)); if (!cert) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_mem_zalloc\n"); if (ic) { ipk = ic->pkey; @@ -53,7 +53,7 @@ CERT *__ssl_cert_new(CERT *ic) failed3: EVP_PKEY_free(cert->pkey); failed2: - ssl_free(cert); + ssl_mem_free(cert); failed1: return NULL; } @@ -75,5 +75,5 @@ void ssl_cert_free(CERT *cert) EVP_PKEY_free(cert->pkey); - ssl_free(cert); + ssl_mem_free(cert); } diff --git a/components/openssl/library/ssl_lib.c b/components/openssl/library/ssl_lib.c index 9740282d13..23b8bf4cea 100644 --- a/components/openssl/library/ssl_lib.c +++ b/components/openssl/library/ssl_lib.c @@ -124,9 +124,9 @@ SSL_SESSION* SSL_SESSION_new(void) { SSL_SESSION *session; - session = ssl_zalloc(sizeof(SSL_SESSION)); + session = ssl_mem_zalloc(sizeof(SSL_SESSION)); if (!session) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_mem_zalloc\n"); session->peer = X509_new(); if (!session->peer) @@ -135,7 +135,7 @@ SSL_SESSION* SSL_SESSION_new(void) return session; failed2: - ssl_free(session); + ssl_mem_free(session); failed1: return NULL; } @@ -146,7 +146,7 @@ failed1: void SSL_SESSION_free(SSL_SESSION *session) { X509_free(session->peer); - ssl_free(session); + ssl_mem_free(session); } /** @@ -168,9 +168,9 @@ SSL_CTX* SSL_CTX_new(const SSL_METHOD *method) if (!cert) SSL_RET(go_failed2, "ssl_cert_new\n"); - ctx = (SSL_CTX *)ssl_zalloc(sizeof(SSL_CTX)); + ctx = (SSL_CTX *)ssl_mem_zalloc(sizeof(SSL_CTX)); if (!ctx) - SSL_RET(go_failed3, "ssl_zalloc:ctx\n"); + SSL_RET(go_failed3, "ssl_mem_zalloc:ctx\n"); ctx->method = method; ctx->client_CA = client_ca; @@ -199,7 +199,7 @@ void SSL_CTX_free(SSL_CTX* ctx) X509_free(ctx->client_CA); - ssl_free(ctx); + ssl_mem_free(ctx); } /** @@ -238,9 +238,9 @@ SSL *SSL_new(SSL_CTX *ctx) if (!ctx) SSL_RET(failed1, "ctx:NULL\n"); - ssl = (SSL *)ssl_zalloc(sizeof(SSL)); + ssl = (SSL *)ssl_mem_zalloc(sizeof(SSL)); if (!ssl) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_mem_zalloc\n"); ssl->session = SSL_SESSION_new(); if (!ssl->session) @@ -277,7 +277,7 @@ failed4: failed3: SSL_SESSION_free(ssl->session); failed2: - ssl_free(ssl); + ssl_mem_free(ssl); failed1: return NULL; } @@ -297,7 +297,7 @@ void SSL_free(SSL *ssl) SSL_SESSION_free(ssl->session); - ssl_free(ssl); + ssl_mem_free(ssl); } /** @@ -343,7 +343,7 @@ int SSL_shutdown(SSL *ssl) SSL_ASSERT(ssl); - if (SSL_get_state(ssl) != TLS_ST_OK) return 0; + if (SSL_get_state(ssl) != TLS_ST_OK) return 1; ret = SSL_METHOD_CALL(shutdown, ssl); diff --git a/components/openssl/library/ssl_pkey.c b/components/openssl/library/ssl_pkey.c index 20debfbcfc..dbd82dc9c2 100644 --- a/components/openssl/library/ssl_pkey.c +++ b/components/openssl/library/ssl_pkey.c @@ -25,9 +25,9 @@ EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk) int ret; EVP_PKEY *pkey; - pkey = ssl_zalloc(sizeof(EVP_PKEY)); + pkey = ssl_mem_zalloc(sizeof(EVP_PKEY)); if (!pkey) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_mem_zalloc\n"); if (ipk) { pkey->method = ipk->method; @@ -42,7 +42,7 @@ EVP_PKEY* __EVP_PKEY_new(EVP_PKEY *ipk) return pkey; failed2: - ssl_free(pkey); + ssl_mem_free(pkey); failed1: return NULL; } @@ -62,7 +62,7 @@ void EVP_PKEY_free(EVP_PKEY *pkey) { EVP_PKEY_METHOD_CALL(free, pkey); - ssl_free(pkey); + ssl_mem_free(pkey); } /** diff --git a/components/openssl/library/ssl_stack.c b/components/openssl/library/ssl_stack.c index 4ea40e7259..5dbb69af9d 100644 --- a/components/openssl/library/ssl_stack.c +++ b/components/openssl/library/ssl_stack.c @@ -30,13 +30,13 @@ OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) OPENSSL_STACK *stack; char **data; - stack = ssl_zalloc(sizeof(OPENSSL_STACK)); + stack = ssl_mem_zalloc(sizeof(OPENSSL_STACK)); if (!stack) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_mem_zalloc\n"); - data = ssl_zalloc(sizeof(*data) * MIN_NODES); + data = ssl_mem_zalloc(sizeof(*data) * MIN_NODES); if (!data) - SSL_RET(failed2, "ssl_zalloc\n"); + SSL_RET(failed2, "ssl_mem_zalloc\n"); stack->data = data; stack->num_alloc = MIN_NODES; @@ -45,7 +45,7 @@ OPENSSL_STACK* OPENSSL_sk_new(OPENSSL_sk_compfunc c) return stack; failed2: - ssl_free(stack); + ssl_mem_free(stack); failed1: return NULL; } @@ -65,6 +65,6 @@ void OPENSSL_sk_free(OPENSSL_STACK *stack) { SSL_ASSERT(stack); - ssl_free(stack->data); - ssl_free(stack); + ssl_mem_free(stack->data); + ssl_mem_free(stack); } diff --git a/components/openssl/library/ssl_x509.c b/components/openssl/library/ssl_x509.c index 06e6e7b544..d0426db18c 100644 --- a/components/openssl/library/ssl_x509.c +++ b/components/openssl/library/ssl_x509.c @@ -33,9 +33,9 @@ X509* __X509_new(X509 *ix) int ret; X509 *x; - x = ssl_zalloc(sizeof(X509)); + x = ssl_mem_zalloc(sizeof(X509)); if (!x) - SSL_RET(failed1, "ssl_malloc\n"); + SSL_RET(failed1, "ssl_mem_zalloc\n"); if (ix) x->method = ix->method; @@ -49,7 +49,7 @@ X509* __X509_new(X509 *ix) return x; failed2: - ssl_free(x); + ssl_mem_free(x); failed1: return NULL; } @@ -69,7 +69,7 @@ void X509_free(X509 *x) { X509_METHOD_CALL(free, x); - ssl_free(x); + ssl_mem_free(x); }; /** diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index eadd323e70..21c0ac58c9 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -86,10 +86,16 @@ int ssl_pm_new(SSL *ssl) const SSL_METHOD *method = ssl->method; - ssl_pm = ssl_zalloc(sizeof(struct ssl_pm)); + ssl_pm = ssl_mem_zalloc(sizeof(struct ssl_pm)); if (!ssl_pm) - SSL_ERR(ret, failed1, "ssl_zalloc\n"); + SSL_ERR(ret, failed1, "ssl_mem_zalloc\n"); + if (ssl->ctx->read_buffer_len < 2048 || + ssl->ctx->read_buffer_len > 8192) + return -1; + + max_content_len = ssl->ctx->read_buffer_len; + mbedtls_net_init(&ssl_pm->fd); mbedtls_net_init(&ssl_pm->cl_fd); @@ -144,6 +150,7 @@ failed3: mbedtls_ctr_drbg_free(&ssl_pm->ctr_drbg); failed2: mbedtls_entropy_free(&ssl_pm->entropy); + ssl_mem_free(ssl_pm); failed1: return -1; } @@ -160,7 +167,7 @@ void ssl_pm_free(SSL *ssl) mbedtls_ssl_config_free(&ssl_pm->conf); mbedtls_ssl_free(&ssl_pm->ssl); - ssl_free(ssl_pm); + ssl_mem_free(ssl_pm); ssl->ssl_pm = NULL; } @@ -392,7 +399,7 @@ int x509_pm_show_info(X509 *x) if (!x509_crt) return -1; - buf = ssl_malloc(X509_INFO_STRING_LENGTH); + buf = ssl_mem_malloc(X509_INFO_STRING_LENGTH); if (!buf) SSL_RET(failed1, ""); @@ -401,14 +408,14 @@ int x509_pm_show_info(X509 *x) SSL_RET(failed2, ""); buf[ret] = 0; - ssl_free(buf); + ssl_mem_free(buf); SSL_PRINT("%s", buf); return 0; failed2: - ssl_free(buf); + ssl_mem_free(buf); failed1: return -1; } @@ -417,9 +424,9 @@ int x509_pm_new(X509 *x, X509 *m_x) { struct x509_pm *x509_pm; - x509_pm = ssl_zalloc(sizeof(struct x509_pm)); + x509_pm = ssl_mem_zalloc(sizeof(struct x509_pm)); if (!x509_pm) - SSL_RET(failed1, "ssl_zalloc\n"); + SSL_RET(failed1, "ssl_mem_zalloc\n"); x->x509_pm = x509_pm; @@ -442,11 +449,11 @@ void x509_pm_free(X509 *x) if (x509_pm->x509_crt) { mbedtls_x509_crt_free(x509_pm->x509_crt); - ssl_free(x509_pm->x509_crt); + ssl_mem_free(x509_pm->x509_crt); x509_pm->x509_crt = NULL; } - ssl_free(x->x509_pm); + ssl_mem_free(x->x509_pm); x->x509_pm = NULL; } @@ -460,14 +467,14 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) mbedtls_x509_crt_free(x509_pm->x509_crt); if (!x509_pm->x509_crt) { - x509_pm->x509_crt = ssl_malloc(sizeof(mbedtls_x509_crt)); + x509_pm->x509_crt = ssl_mem_malloc(sizeof(mbedtls_x509_crt)); if (!x509_pm->x509_crt) - SSL_RET(failed1, "ssl_malloc\n"); + SSL_RET(failed1, "ssl_mem_malloc\n"); } - load_buf = ssl_malloc(len + 1); + load_buf = ssl_mem_malloc(len + 1); if (!load_buf) - SSL_RET(failed2, "ssl_malloc\n"); + SSL_RET(failed2, "ssl_mem_malloc\n"); ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; @@ -477,7 +484,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) mbedtls_x509_crt_init(x509_pm->x509_crt); ret = mbedtls_x509_crt_parse(x509_pm->x509_crt, load_buf, len + 1); - ssl_free(load_buf); + ssl_mem_free(load_buf); if (ret) SSL_RET(failed2, "mbedtls_x509_crt_parse, return [-0x%x]\n", -ret); @@ -485,7 +492,7 @@ int x509_pm_load(X509 *x, const unsigned char *buffer, int len) return 0; failed2: - ssl_free(x509_pm->x509_crt); + ssl_mem_free(x509_pm->x509_crt); x509_pm->x509_crt = NULL; failed1: return -1; @@ -495,7 +502,7 @@ int pkey_pm_new(EVP_PKEY *pk, EVP_PKEY *m_pkey) { struct pkey_pm *pkey_pm; - pkey_pm = ssl_zalloc(sizeof(struct pkey_pm)); + pkey_pm = ssl_mem_zalloc(sizeof(struct pkey_pm)); if (!pkey_pm) return -1; @@ -517,11 +524,11 @@ void pkey_pm_free(EVP_PKEY *pk) if (pkey_pm->pkey) { mbedtls_pk_free(pkey_pm->pkey); - ssl_free(pkey_pm->pkey); + ssl_mem_free(pkey_pm->pkey); pkey_pm->pkey = NULL; } - ssl_free(pk->pkey_pm); + ssl_mem_free(pk->pkey_pm); pk->pkey_pm = NULL; } @@ -535,14 +542,14 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) mbedtls_pk_free(pkey_pm->pkey); if (!pkey_pm->pkey) { - pkey_pm->pkey = ssl_malloc(sizeof(mbedtls_pk_context)); + pkey_pm->pkey = ssl_mem_malloc(sizeof(mbedtls_pk_context)); if (!pkey_pm->pkey) - SSL_RET(failed1, "ssl_malloc\n"); + SSL_RET(failed1, "ssl_mem_malloc\n"); } - load_buf = ssl_malloc(len + 1); + load_buf = ssl_mem_malloc(len + 1); if (!load_buf) - SSL_RET(failed2, "ssl_malloc\n"); + SSL_RET(failed2, "ssl_mem_malloc\n"); ssl_memcpy(load_buf, buffer, len); load_buf[len] = '\0'; @@ -552,7 +559,7 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) mbedtls_pk_init(pkey_pm->pkey); ret = mbedtls_pk_parse_key(pkey_pm->pkey, load_buf, len + 1, NULL, 0); - ssl_free(load_buf); + ssl_mem_free(load_buf); if (ret) SSL_RET(failed2, "mbedtls_pk_parse_key, return [-0x%x]\n", -ret); @@ -560,7 +567,7 @@ int pkey_pm_load(EVP_PKEY *pk, const unsigned char *buffer, int len) return 0; failed2: - ssl_free(pkey_pm->pkey); + ssl_mem_free(pkey_pm->pkey); pkey_pm->pkey = NULL; failed1: return -1; diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index b57e703a17..9fbc44deb6 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -15,6 +15,7 @@ #include "ssl_port.h" #include "string.h" #include "malloc.h" +#include "esp_system.h" /*********************************************************************************************/ /********************************* SSL general interface *************************************/ @@ -51,10 +52,11 @@ size_t ssl_strlen(const char *src) void ssl_speed_up_enter(void) { - + system_update_cpu_freq(SYS_CPU_160MHZ); } void ssl_speed_up_exit(void) { - + system_update_cpu_freq(SYS_CPU_80MHZ); } + From 16a4d56fe5af03005afc9a3b57e95219918841c6 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 1 Nov 2016 13:09:54 +0800 Subject: [PATCH 81/95] components/openssl: remove some platform interface --- components/openssl/platform/ssl_port.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index 9fbc44deb6..b333fdbfba 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -15,7 +15,6 @@ #include "ssl_port.h" #include "string.h" #include "malloc.h" -#include "esp_system.h" /*********************************************************************************************/ /********************************* SSL general interface *************************************/ @@ -52,11 +51,11 @@ size_t ssl_strlen(const char *src) void ssl_speed_up_enter(void) { - system_update_cpu_freq(SYS_CPU_160MHZ); + } void ssl_speed_up_exit(void) { - system_update_cpu_freq(SYS_CPU_80MHZ); + } From 8d1f360ca6835c2d13563da10bed97bb7c38cc6c Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 1 Nov 2016 13:10:56 +0800 Subject: [PATCH 82/95] components/openssl: ssl port use esp32_idf default --- components/openssl/platform/ssl_port.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index b333fdbfba..1f19510116 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -13,6 +13,9 @@ // limitations under the License. #include "ssl_port.h" + +#ifdef ESP32_IDF_PLATFORM + #include "string.h" #include "malloc.h" @@ -59,3 +62,5 @@ void ssl_speed_up_exit(void) } +#endif + From bc710e5b885df673e13470de8ce99997acb7e4dd Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 1 Nov 2016 14:59:50 +0800 Subject: [PATCH 83/95] components/openssl: refacetor the SSL debug function Add the "ssl_opt.h" file to make user able t add its platform interface --- components/openssl/include/internal/ssl_dbg.h | 21 ++++++++++++------- .../openssl/include/platform/ssl_port.h | 3 +++ components/openssl/platform/ssl_port.c | 6 +++--- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index 1b0a73f167..5b909955e4 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -38,10 +38,17 @@ #define SSL_DEBUG_LOCATION_ENABLE 0 #endif -#ifndef SSL_PRINT - #include "stdio.h" - extern int printf(const char *fmt, ...); - #define SSL_PRINT printf +#if SSL_DEBUG_ENBALE + #ifndef SSL_PRINT + #include "stdio.h" + extern int printf(const char *fmt, ...); + #define SSL_PRINT printf + #endif +#else + #ifdef SSL_PRINT + #undef SSL_PRINT + #define SSL_PRINT(...) + #endif #endif #if SSL_DEBUG_LOCATION_ENABLE @@ -56,11 +63,11 @@ #define SSL_ASSERT(s) #endif -#define SSL_ERR(err, go, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(__VA_ARGS__); ret = err; goto go; } +#define SSL_ERR(err, go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(fmt, ##__VA_ARGS__); ret = err; goto go; } -#define SSL_RET(go, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(__VA_ARGS__); goto go; } +#define SSL_RET(go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(fmt, ##__VA_ARGS__); goto go; } -#define SSL_DEBUG(level, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT(__VA_ARGS__);} } +#define SSL_DEBUG(level, fmt, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT(fmt, ##__VA_ARGS__);} } #ifdef __cplusplus } diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h index 4a319c91ae..1e4c2f31f9 100644 --- a/components/openssl/include/platform/ssl_port.h +++ b/components/openssl/include/platform/ssl_port.h @@ -24,6 +24,7 @@ #ifdef ESP32_IDF_PLATFORM #include "esp_types.h" +#include "esp_log.h" void *ssl_mem_zalloc(size_t size); void *ssl_mem_malloc(size_t size); @@ -35,6 +36,8 @@ size_t ssl_strlen(const char *src); void ssl_speed_up_enter(void); void ssl_speed_up_exit(void); +#define SSL_PRINT(fmt, ...) ESP_LOGD("OpenSSL", fmt, ##__VA_ARGS__) + #elif defined(SSL_PLATFORM_USER_INCLUDE) SSL_PLATFORM_USER_INCLUDE diff --git a/components/openssl/platform/ssl_port.c b/components/openssl/platform/ssl_port.c index 1f19510116..ae3b849ca3 100644 --- a/components/openssl/platform/ssl_port.c +++ b/components/openssl/platform/ssl_port.c @@ -22,7 +22,7 @@ /*********************************************************************************************/ /********************************* SSL general interface *************************************/ -void* ssl_zalloc(size_t size) +void* ssl_mem_zalloc(size_t size) { void *p = malloc(size); @@ -32,12 +32,12 @@ void* ssl_zalloc(size_t size) return p; } -void *ssl_malloc(size_t size) +void *ssl_mem_malloc(size_t size) { return malloc(size); } -void ssl_free(void *p) +void ssl_mem_free(void *p) { free(p); } From 12e78e9590655a494e72e7e6d6cea391ecda32b3 Mon Sep 17 00:00:00 2001 From: Dong Heng Date: Tue, 1 Nov 2016 15:16:14 +0800 Subject: [PATCH 84/95] components/openssl: add more debug stream output function --- components/openssl/include/internal/ssl_dbg.h | 34 ++++++++++++++----- .../openssl/include/platform/ssl_port.h | 4 ++- components/openssl/platform/ssl_pm.c | 2 +- 3 files changed, 29 insertions(+), 11 deletions(-) diff --git a/components/openssl/include/internal/ssl_dbg.h b/components/openssl/include/internal/ssl_dbg.h index 5b909955e4..887fe2e82b 100644 --- a/components/openssl/include/internal/ssl_dbg.h +++ b/components/openssl/include/internal/ssl_dbg.h @@ -39,20 +39,36 @@ #endif #if SSL_DEBUG_ENBALE - #ifndef SSL_PRINT + #if !defined(SSL_PRINT_LOG) || !defined(SSL_ERROR_LOG) || !defined(SSL_LOCAL_LOG) #include "stdio.h" extern int printf(const char *fmt, ...); - #define SSL_PRINT printf + #ifndef SSL_PRINT_LOG + #define SSL_PRINT_LOG printf + #endif + #ifndef SSL_ERROR_LOG + #define SSL_ERROR_LOG printf + #endif + #ifndef SSL_LOCAL_LOG + #define SSL_LOCAL_LOG printf + #endif #endif #else - #ifdef SSL_PRINT - #undef SSL_PRINT - #define SSL_PRINT(...) + #ifdef SSL_PRINT_LOG + #undef SSL_PRINT_LOG + #define SSL_PRINT_LOG(...) + #endif + #ifdef SSL_ERROR_LOG + #undef SSL_ERROR_LOG + #define SSL_ERROR_LOG(...) + #endif + #ifdef SSL_LOCAL_LOG + #undef SSL_LOCAL_LOG + #define SSL_LOCAL_LOG(...) #endif #endif #if SSL_DEBUG_LOCATION_ENABLE - #define SSL_DEBUG_LOCATION() SSL_PRINT("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__) + #define SSL_DEBUG_LOCATION() SSL_LOCAL_LOG("%s %s line %d\n", __FILE__, __FUNCTION__, __LINE__) #else #define SSL_DEBUG_LOCATION() #endif @@ -63,11 +79,11 @@ #define SSL_ASSERT(s) #endif -#define SSL_ERR(err, go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(fmt, ##__VA_ARGS__); ret = err; goto go; } +#define SSL_ERR(err, go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_ERROR_LOG(fmt, ##__VA_ARGS__); ret = err; goto go; } -#define SSL_RET(go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_PRINT(fmt, ##__VA_ARGS__); goto go; } +#define SSL_RET(go, fmt, ...) { SSL_DEBUG_LOCATION(); SSL_ERROR_LOG(fmt, ##__VA_ARGS__); goto go; } -#define SSL_DEBUG(level, fmt, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT(fmt, ##__VA_ARGS__);} } +#define SSL_DEBUG(level, fmt, ...) { if (level > SSL_DEBUG_LEVEL) {SSL_PRINT_LOG(fmt, ##__VA_ARGS__);} } #ifdef __cplusplus } diff --git a/components/openssl/include/platform/ssl_port.h b/components/openssl/include/platform/ssl_port.h index 1e4c2f31f9..35c8dc18f9 100644 --- a/components/openssl/include/platform/ssl_port.h +++ b/components/openssl/include/platform/ssl_port.h @@ -36,7 +36,9 @@ size_t ssl_strlen(const char *src); void ssl_speed_up_enter(void); void ssl_speed_up_exit(void); -#define SSL_PRINT(fmt, ...) ESP_LOGD("OpenSSL", fmt, ##__VA_ARGS__) +#define SSL_PRINT_LOG(fmt, ...) ESP_LOGD("openssl", fmt, ##__VA_ARGS__) +#define SSL_ERROR_LOG(fmt, ...) ESP_LOGE("openssl", fmt, ##__VA_ARGS__) +#define SSL_LOCAL_LOG(fmt, ...) ESP_LOGD("openssl", fmt, ##__VA_ARGS__) #elif defined(SSL_PLATFORM_USER_INCLUDE) diff --git a/components/openssl/platform/ssl_pm.c b/components/openssl/platform/ssl_pm.c index 21c0ac58c9..92e72bfdb8 100644 --- a/components/openssl/platform/ssl_pm.c +++ b/components/openssl/platform/ssl_pm.c @@ -410,7 +410,7 @@ int x509_pm_show_info(X509 *x) ssl_mem_free(buf); - SSL_PRINT("%s", buf); + SSL_DEBUG(1, "%s", buf); return 0; From f0cd38a0799f13357761e134b108c8ab8dc40abf Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Tue, 1 Nov 2016 15:25:46 +0800 Subject: [PATCH 85/95] lwip: remove tx flow control code --- components/lwip/api/sockets.c | 30 -------------------- components/lwip/include/lwip/port/lwipopts.h | 3 -- 2 files changed, 33 deletions(-) diff --git a/components/lwip/api/sockets.c b/components/lwip/api/sockets.c index df658578af..1529382f50 100755 --- a/components/lwip/api/sockets.c +++ b/components/lwip/api/sockets.c @@ -382,34 +382,6 @@ static void lwip_socket_unregister_membership(int s, const ip4_addr_t *if_addr, static void lwip_socket_drop_registered_memberships(int s); #endif /* LWIP_IGMP */ -#if ESP_LWIP -#include "esp_wifi_internal.h" -#include "esp_system.h" - -/* Please be notified that this flow control is just a workaround for fixing wifi Q full issue. - * Under UDP/TCP pressure test, we found that the sockets may cause wifi tx queue full if the socket - * sending speed is faster than the wifi sending speed, it will finally cause the packet to be dropped - * in wifi layer, it's not acceptable in some application. That's why we introdue the tx flow control here. - * However, current solution is just a workaround, we need to consider the return value of wifi tx interface, - * and feedback the return value to lwip and let lwip do the flow control itself. - */ -static inline void esp32_tx_flow_ctrl(void) -{ -//TODO we need to do flow control for UDP -#if 0 - uint8_t _wait_delay = 1; - - while ((system_get_free_heap_size() < HEAP_HIGHWAT) || esp_wifi_internal_tx_is_stop()){ - vTaskDelay(_wait_delay/portTICK_RATE_MS); - if (_wait_delay < 64) _wait_delay *= 2; - } -#endif -} - -#else -#define esp32_tx_flow_ctrl() -#endif - /** The global array of available sockets */ static struct lwip_sock sockets[NUM_SOCKETS]; #if ESP_THREAD_SAFE @@ -1392,8 +1364,6 @@ lwip_sendto(int s, const void *data, size_t size, int flags, #endif /* LWIP_TCP */ } - esp32_tx_flow_ctrl(); - if ((to != NULL) && !SOCK_ADDR_TYPE_MATCH(to, sock)) { /* sockaddr does not match socket type (IPv4/IPv6) */ sock_set_errno(sock, err_to_errno(ERR_VAL)); diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index 67a62b8227..b970ae5539 100755 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -523,7 +523,6 @@ extern unsigned long os_random(void); #define ESP_IP4_ATON 1 #define ESP_LIGHT_SLEEP 1 - #define TCP_WND_DEFAULT (4*TCP_MSS) #define TCP_SND_BUF_DEFAULT (2*TCP_MSS) @@ -550,8 +549,6 @@ extern unsigned char misc_prof_get_tcp_snd_buf(void); #define CHECKSUM_CHECK_UDP 0 #define CHECKSUM_CHECK_IP 0 -#define HEAP_HIGHWAT 20*1024 - #define LWIP_NETCONN_FULLDUPLEX 1 #define LWIP_NETCONN_SEM_PER_THREAD 1 From edf5b103449e4120c0e1b03e40f0e82f17c38daf Mon Sep 17 00:00:00 2001 From: Liu Zhi Fu Date: Tue, 1 Nov 2016 15:34:30 +0800 Subject: [PATCH 86/95] esp32: update wifi lib 146f5962 - Make the return value of esp_wifi_internal_tx consistent with LWIP error code so that the up-layer can detect the out-of-memory error and take action accordingly, such do flow control. --- components/esp32/lib | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/esp32/lib b/components/esp32/lib index 9d18fd1a8f..b3090d8854 160000 --- a/components/esp32/lib +++ b/components/esp32/lib @@ -1 +1 @@ -Subproject commit 9d18fd1a8f7610130e69f8be74ec68f6399221b1 +Subproject commit b3090d885413fb78c86e7b88116cdb5c8c5e9e68 From 8c1d1e19c230b5229fcb1463ceb3cd804728b9a8 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Tue, 1 Nov 2016 15:41:10 +0800 Subject: [PATCH 87/95] OpenOCD doc fix, fix gdbstub --- components/esp32/gdbstub.c | 2 +- docs/openocd.rst | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/components/esp32/gdbstub.c b/components/esp32/gdbstub.c index d75fced4cd..a43793f835 100644 --- a/components/esp32/gdbstub.c +++ b/components/esp32/gdbstub.c @@ -351,7 +351,7 @@ static int gdbReadCommand() { -void gdbstubPanicHandler(XtExcFrame *frame) { +void esp_gdbstub_panic_handler(XtExcFrame *frame) { dumpHwToRegfile(frame); //Make sure txd/rxd are enabled PIN_PULLUP_DIS(PERIPHS_IO_MUX_U0TXD_U); diff --git a/docs/openocd.rst b/docs/openocd.rst index 57ee93db4a..cf1d25e60b 100644 --- a/docs/openocd.rst +++ b/docs/openocd.rst @@ -2,10 +2,10 @@ OpenOCD setup for ESP32 ----------------------- The ESP31 and ESP32 have two powerful Xtensa cores, allowing for a great deal of variety of program architectures. The FreeRTOS -OS that comes with ESP-IDF is capable multi-core pre-emptive multithreading, allowing for an intuitive way of writing software. +OS that comes with ESP-IDF is capable of multi-core pre-emptive multithreading, allowing for an intuitive way of writing software. The downside of the ease of programming is that debugging without the right tools is harder: figuring out a bug that is caused -by two threads, maybe even running simultaneously on two different CPU cures, can take a long time when all you have are printf +by two threads, maybe even running simultaneously on two different CPU cores, can take a long time when all you have are printf statements. A better and in many cases quicker way to debug such problems is by using a debugger, connected to the processors over a debug port. @@ -84,7 +84,7 @@ Connecting a debugger to OpenOCD OpenOCD should now be ready to accept gdb connections. If you have compiled the ESP32 toolchain using Crosstool-NG, or if you have downloaded a precompiled toolchain from the Espressif website, you should already have xtensa-esp32-elf-gdb, a version of gdb that can be used for this. First, make sure the project you want to debug is compiled and flashed -into the ESP32s SPI flash. Then, in a different console than OpenOCD is running in, invoke gdb. For example, for the +into the ESP32's SPI flash. Then, in a different console than OpenOCD is running in, invoke gdb. For example, for the template app, you would do this like such:: cd esp-idf-template From 1d3626c119d2acbb164571ce01dc5326f418172f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 1 Nov 2016 20:08:29 +0800 Subject: [PATCH 88/95] docs: fix typos, build docs with gitlab CI --- .gitlab-ci.yml | 14 ++++++++++++++ docs/eclipse-setup.rst | 2 +- docs/index.rst | 5 +---- docs/requirements.txt | 7 ++++++- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index aff9bea8d1..25e4d4f177 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -92,6 +92,20 @@ build_examples: - cd build_examples - ${IDF_PATH}/make/build_examples.sh +build_docs: + stage: build + image: espressif/esp32-ci-env + tags: + - build_docs + script: + - cd docs + - make html + artifacts: + paths: + - docs/_build/html + expire_in: 6 mos + + test_nvs_on_host: stage: test image: espressif/esp32-ci-env diff --git a/docs/eclipse-setup.rst b/docs/eclipse-setup.rst index 32d60a17a0..fbad93be6c 100644 --- a/docs/eclipse-setup.rst +++ b/docs/eclipse-setup.rst @@ -1,4 +1,4 @@ -Build and Falsh with Eclipse IDE +Build and Flash with Eclipse IDE ******************************** Installing Eclipse IDE diff --git a/docs/index.rst b/docs/index.rst index da03346e71..c973950615 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -3,10 +3,7 @@ ESP32 Programming Guide .. caution:: - This DRAF version of documentation developed within `ESP-IDF 1.0 Release plan `_. - It is scheduled for merging with `espressif/esp-idf `_ repository at the release date. - Before merging it may be incomplete, or not fully in sync with espressif/esp-idf. - Please mind your step! + Until ESP-IDF release 1.0, this documentation is a draft. It is incomplete and may have mistakes. Please mind your step! Contents: diff --git a/docs/requirements.txt b/docs/requirements.txt index 188f51e62d..debed28677 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1 +1,6 @@ -breathe \ No newline at end of file +# This is a list of python packages used to generate documentation. This file is used with pip: +# pip install requirements.txt +# +sphinx +sphinx-rtd-theme +breathe From 4f71d741ec79c1a155d4130a3936f2971dd6caf9 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Tue, 1 Nov 2016 20:58:47 +0800 Subject: [PATCH 89/95] docs: deploy built docs --- .gitlab-ci.yml | 27 ++++++++++++++++++++++++++- docs/conf.py | 22 ++++++++++++++++++---- 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 25e4d4f177..931009f4b9 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -103,7 +103,7 @@ build_docs: artifacts: paths: - docs/_build/html - expire_in: 6 mos + expire_in: 1 mos test_nvs_on_host: @@ -173,6 +173,31 @@ push_master_to_github: - git push --follow-tags github HEAD:master +deploy_docs: + before_script: + - echo "Not setting up GitLab key, not fetching submodules" + stage: deploy + only: + - master + - triggers + tags: + - deploy + image: espressif/esp32-ci-env + script: + - mkdir -p ~/.ssh + - chmod 700 ~/.ssh + - echo -n $DOCS_DEPLOY_KEY > ~/.ssh/id_rsa_base64 + - base64 --decode --ignore-garbage ~/.ssh/id_rsa_base64 > ~/.ssh/id_rsa + - chmod 600 ~/.ssh/id_rsa + - echo -e "Host $DOCS_SERVER\n\tStrictHostKeyChecking no\n\tUser $DOCS_SERVER_USER\n" >> ~/.ssh/config + - export GIT_VER=$(git describe --always) + - cd docs/_build/ + - mv html $GIT_VER + - tar czvf $GIT_VER.tar.gz $GIT_VER + - scp $GIT_VER.tar.gz $DOCS_SERVER:$DOCS_PATH + - ssh $DOCS_SERVER -x "cd $DOCS_PATH && tar xzvf $GIT_VER.tar.gz && rm -f latest && ln -s $GIT_VER latest" + + # AUTO GENERATED PART START, DO NOT MODIFY CONTENT BELOW # template for test jobs .test_template: &test_template diff --git a/docs/conf.py b/docs/conf.py index 8a8821fb0d..8a4a275c8a 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,9 +26,20 @@ import os # added by krzychb, 24-Oct-2016 # -from subprocess import call +from subprocess import call, Popen, PIPE +import shlex + call('doxygen') +# -- Function to get output of a command ---------------------------------- +def run_cmd_get_output(cmd): + process = Popen(shlex.split(cmd), stdout=PIPE) + (output, err) = process.communicate() + exit_code = process.wait() + if exit_code != 0: + raise RuntimeError('command line program has failed') + return output + # -- General configuration ------------------------------------------------ @@ -64,10 +75,13 @@ copyright = u'2016, Espressif' # |version| and |release|, also used in various other places throughout the # built documents. # -# The short X.Y version. -version = '1.0' +# This is supposed to be "the short X.Y version", but it's the only version +# visible when you open index.html. +# Display full version to make things less confusing. +# If needed, nearest tag is returned by 'git describe --abbrev=0'. +version = run_cmd_get_output('git describe') # The full version, including alpha/beta/rc tags. -release = '1.0' +release = run_cmd_get_output('git describe') # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. From e1f0c98ef531ed803bc5ad9100c0a971f8c272b2 Mon Sep 17 00:00:00 2001 From: Wangjialin Date: Tue, 1 Nov 2016 11:48:32 +0800 Subject: [PATCH 90/95] Modify gpio.h and ledc.h --- components/driver/include/driver/gpio.h | 436 ++++++++++++------------ components/driver/include/driver/ledc.h | 330 +++++++++--------- 2 files changed, 388 insertions(+), 378 deletions(-) diff --git a/components/driver/include/driver/gpio.h b/components/driver/include/driver/gpio.h index 001be2a39d..7106489d6c 100644 --- a/components/driver/include/driver/gpio.h +++ b/components/driver/include/driver/gpio.h @@ -27,43 +27,43 @@ extern "C" { #endif -#define GPIO_SEL_0 (BIT(0)) /* Pin 0 selected */ -#define GPIO_SEL_1 (BIT(1)) /* Pin 1 selected */ -#define GPIO_SEL_2 (BIT(2)) /* Pin 2 selected */ -#define GPIO_SEL_3 (BIT(3)) /* Pin 3 selected */ -#define GPIO_SEL_4 (BIT(4)) /* Pin 4 selected */ -#define GPIO_SEL_5 (BIT(5)) /* Pin 5 selected */ -#define GPIO_SEL_6 (BIT(6)) /* Pin 6 selected */ -#define GPIO_SEL_7 (BIT(7)) /* Pin 7 selected */ -#define GPIO_SEL_8 (BIT(8)) /* Pin 8 selected */ -#define GPIO_SEL_9 (BIT(9)) /* Pin 9 selected */ -#define GPIO_SEL_10 (BIT(10)) /* Pin 10 selected */ -#define GPIO_SEL_11 (BIT(11)) /* Pin 11 selected */ -#define GPIO_SEL_12 (BIT(12)) /* Pin 12 selected */ -#define GPIO_SEL_13 (BIT(13)) /* Pin 13 selected */ -#define GPIO_SEL_14 (BIT(14)) /* Pin 14 selected */ -#define GPIO_SEL_15 (BIT(15)) /* Pin 15 selected */ -#define GPIO_SEL_16 (BIT(16)) /* Pin 16 selected */ -#define GPIO_SEL_17 (BIT(17)) /* Pin 17 selected */ -#define GPIO_SEL_18 (BIT(18)) /* Pin 18 selected */ -#define GPIO_SEL_19 (BIT(19)) /* Pin 19 selected */ +#define GPIO_SEL_0 (BIT(0)) /*!< Pin 0 selected */ +#define GPIO_SEL_1 (BIT(1)) /*!< Pin 1 selected */ +#define GPIO_SEL_2 (BIT(2)) /*!< Pin 2 selected */ +#define GPIO_SEL_3 (BIT(3)) /*!< Pin 3 selected */ +#define GPIO_SEL_4 (BIT(4)) /*!< Pin 4 selected */ +#define GPIO_SEL_5 (BIT(5)) /*!< Pin 5 selected */ +#define GPIO_SEL_6 (BIT(6)) /*!< Pin 6 selected */ +#define GPIO_SEL_7 (BIT(7)) /*!< Pin 7 selected */ +#define GPIO_SEL_8 (BIT(8)) /*!< Pin 8 selected */ +#define GPIO_SEL_9 (BIT(9)) /*!< Pin 9 selected */ +#define GPIO_SEL_10 (BIT(10)) /*!< Pin 10 selected */ +#define GPIO_SEL_11 (BIT(11)) /*!< Pin 11 selected */ +#define GPIO_SEL_12 (BIT(12)) /*!< Pin 12 selected */ +#define GPIO_SEL_13 (BIT(13)) /*!< Pin 13 selected */ +#define GPIO_SEL_14 (BIT(14)) /*!< Pin 14 selected */ +#define GPIO_SEL_15 (BIT(15)) /*!< Pin 15 selected */ +#define GPIO_SEL_16 (BIT(16)) /*!< Pin 16 selected */ +#define GPIO_SEL_17 (BIT(17)) /*!< Pin 17 selected */ +#define GPIO_SEL_18 (BIT(18)) /*!< Pin 18 selected */ +#define GPIO_SEL_19 (BIT(19)) /*!< Pin 19 selected */ -#define GPIO_SEL_21 (BIT(21)) /* Pin 21 selected */ -#define GPIO_SEL_22 (BIT(22)) /* Pin 22 selected */ -#define GPIO_SEL_23 (BIT(23)) /* Pin 23 selected */ +#define GPIO_SEL_21 (BIT(21)) /*!< Pin 21 selected */ +#define GPIO_SEL_22 (BIT(22)) /*!< Pin 22 selected */ +#define GPIO_SEL_23 (BIT(23)) /*!< Pin 23 selected */ -#define GPIO_SEL_25 (BIT(25)) /* Pin 25 selected */ -#define GPIO_SEL_26 (BIT(26)) /* Pin 26 selected */ -#define GPIO_SEL_27 (BIT(27)) /* Pin 27 selected */ +#define GPIO_SEL_25 (BIT(25)) /*!< Pin 25 selected */ +#define GPIO_SEL_26 (BIT(26)) /*!< Pin 26 selected */ +#define GPIO_SEL_27 (BIT(27)) /*!< Pin 27 selected */ -#define GPIO_SEL_32 ((uint64_t)(((uint64_t)1)<<32)) /* Pin 32 selected */ -#define GPIO_SEL_33 ((uint64_t)(((uint64_t)1)<<33)) /* Pin 33 selected */ -#define GPIO_SEL_34 ((uint64_t)(((uint64_t)1)<<34)) /* Pin 34 selected */ -#define GPIO_SEL_35 ((uint64_t)(((uint64_t)1)<<35)) /* Pin 35 selected */ -#define GPIO_SEL_36 ((uint64_t)(((uint64_t)1)<<36)) /* Pin 36 selected */ -#define GPIO_SEL_37 ((uint64_t)(((uint64_t)1)<<37)) /* Pin 37 selected */ -#define GPIO_SEL_38 ((uint64_t)(((uint64_t)1)<<38)) /* Pin 38 selected */ -#define GPIO_SEL_39 ((uint64_t)(((uint64_t)1)<<39)) /* Pin 39 selected */ +#define GPIO_SEL_32 ((uint64_t)(((uint64_t)1)<<32)) /*!< Pin 32 selected */ +#define GPIO_SEL_33 ((uint64_t)(((uint64_t)1)<<33)) /*!< Pin 33 selected */ +#define GPIO_SEL_34 ((uint64_t)(((uint64_t)1)<<34)) /*!< Pin 34 selected */ +#define GPIO_SEL_35 ((uint64_t)(((uint64_t)1)<<35)) /*!< Pin 35 selected */ +#define GPIO_SEL_36 ((uint64_t)(((uint64_t)1)<<36)) /*!< Pin 36 selected */ +#define GPIO_SEL_37 ((uint64_t)(((uint64_t)1)<<37)) /*!< Pin 37 selected */ +#define GPIO_SEL_38 ((uint64_t)(((uint64_t)1)<<38)) /*!< Pin 38 selected */ +#define GPIO_SEL_39 ((uint64_t)(((uint64_t)1)<<39)) /*!< Pin 39 selected */ #define GPIO_PIN_REG_0 PERIPHS_IO_MUX_GPIO0_U #define GPIO_PIN_REG_1 PERIPHS_IO_MUX_U0TXD_U @@ -117,47 +117,47 @@ extern const uint32_t GPIO_PIN_MUX_REG[GPIO_PIN_COUNT]; #define GPIO_IS_VALID_OUTPUT_GPIO(gpio_num) ((GPIO_IS_VALID_GPIO(gpio_num)) && (gpio_num < 34)) //to decide whether it can be a valid GPIO number of output mode typedef enum { - GPIO_NUM_0 = 0, - GPIO_NUM_1 = 1, - GPIO_NUM_2 = 2, - GPIO_NUM_3 = 3, - GPIO_NUM_4 = 4, - GPIO_NUM_5 = 5, - GPIO_NUM_6 = 6, - GPIO_NUM_7 = 7, - GPIO_NUM_8 = 8, - GPIO_NUM_9 = 9, - GPIO_NUM_10 = 10, - GPIO_NUM_11 = 11, - GPIO_NUM_12 = 12, - GPIO_NUM_13 = 13, - GPIO_NUM_14 = 14, - GPIO_NUM_15 = 15, - GPIO_NUM_16 = 16, - GPIO_NUM_17 = 17, - GPIO_NUM_18 = 18, - GPIO_NUM_19 = 19, + GPIO_NUM_0 = 0, /*!< GPIO0, input and output */ + GPIO_NUM_1 = 1, /*!< GPIO1, input and output */ + GPIO_NUM_2 = 2, /*!< GPIO2, input and output */ + GPIO_NUM_3 = 3, /*!< GPIO3, input and output */ + GPIO_NUM_4 = 4, /*!< GPIO4, input and output */ + GPIO_NUM_5 = 5, /*!< GPIO5, input and output */ + GPIO_NUM_6 = 6, /*!< GPIO6, input and output */ + GPIO_NUM_7 = 7, /*!< GPIO7, input and output */ + GPIO_NUM_8 = 8, /*!< GPIO8, input and output */ + GPIO_NUM_9 = 9, /*!< GPIO9, input and output */ + GPIO_NUM_10 = 10, /*!< GPIO10, input and output */ + GPIO_NUM_11 = 11, /*!< GPIO11, input and output */ + GPIO_NUM_12 = 12, /*!< GPIO12, input and output */ + GPIO_NUM_13 = 13, /*!< GPIO13, input and output */ + GPIO_NUM_14 = 14, /*!< GPIO14, input and output */ + GPIO_NUM_15 = 15, /*!< GPIO15, input and output */ + GPIO_NUM_16 = 16, /*!< GPIO16, input and output */ + GPIO_NUM_17 = 17, /*!< GPIO17, input and output */ + GPIO_NUM_18 = 18, /*!< GPIO18, input and output */ + GPIO_NUM_19 = 19, /*!< GPIO19, input and output */ - GPIO_NUM_21 = 21, - GPIO_NUM_22 = 22, - GPIO_NUM_23 = 23, + GPIO_NUM_21 = 21, /*!< GPIO21, input and output */ + GPIO_NUM_22 = 22, /*!< GPIO22, input and output */ + GPIO_NUM_23 = 23, /*!< GPIO23, input and output */ - GPIO_NUM_25 = 25, - GPIO_NUM_26 = 26, - GPIO_NUM_27 = 27, + GPIO_NUM_25 = 25, /*!< GPIO25, input and output */ + GPIO_NUM_26 = 26, /*!< GPIO26, input and output */ + GPIO_NUM_27 = 27, /*!< GPIO27, input and output */ - GPIO_NUM_32 = 32, - GPIO_NUM_33 = 33, - GPIO_NUM_34 = 34, /*input mode only */ - GPIO_NUM_35 = 35, /*input mode only */ - GPIO_NUM_36 = 36, /*input mode only */ - GPIO_NUM_37 = 37, /*input mode only */ - GPIO_NUM_38 = 38, /*input mode only */ - GPIO_NUM_39 = 39, /*input mode only */ + GPIO_NUM_32 = 32, /*!< GPIO32, input and output */ + GPIO_NUM_33 = 33, /*!< GPIO32, input and output */ + GPIO_NUM_34 = 34, /*!< GPIO34, input mode only */ + GPIO_NUM_35 = 35, /*!< GPIO35, input mode only */ + GPIO_NUM_36 = 36, /*!< GPIO36, input mode only */ + GPIO_NUM_37 = 37, /*!< GPIO37, input mode only */ + GPIO_NUM_38 = 38, /*!< GPIO38, input mode only */ + GPIO_NUM_39 = 39, /*!< GPIO39, input mode only */ } gpio_num_t; typedef enum { - GPIO_INTR_DISABLE = 0, /*!< disable GPIO interrupt */ + GPIO_INTR_DISABLE = 0, /*!< Disable GPIO interrupt */ GPIO_INTR_POSEDGE = 1, /*!< GPIO interrupt type : rising edge */ GPIO_INTR_NEGEDGE = 2, /*!< GPIO interrupt type : falling edge */ GPIO_INTR_ANYEDGE = 3, /*!< GPIO interrupt type : both rising and falling edge */ @@ -175,13 +175,13 @@ typedef enum { } gpio_mode_t; typedef enum { - GPIO_PULLUP_DISABLE = 0x0, /*!< disable GPIO pull-up resistor */ - GPIO_PULLUP_ENABLE = 0x1, /*!< enable GPIO pull-up resistor */ + GPIO_PULLUP_DISABLE = 0x0, /*!< Disable GPIO pull-up resistor */ + GPIO_PULLUP_ENABLE = 0x1, /*!< Enable GPIO pull-up resistor */ } gpio_pullup_t; typedef enum { - GPIO_PULLDOWN_DISABLE = 0x0, /*!< disable GPIO pull-down resistor */ - GPIO_PULLDOWN_ENABLE = 0x1, /*!< enable GPIO pull-down resistor */ + GPIO_PULLDOWN_DISABLE = 0x0, /*!< Disable GPIO pull-down resistor */ + GPIO_PULLDOWN_ENABLE = 0x1, /*!< Enable GPIO pull-down resistor */ } gpio_pulldown_t; typedef struct { @@ -192,12 +192,6 @@ typedef struct { gpio_int_type_t intr_type; /*!< GPIO interrupt type */ } gpio_config_t; -typedef enum { - GPIO_LOW_LEVEL = 0, - GPIO_HIGH_LEVEL = 1, - GPIO_LEVEL_ERR, -} gpio_level_t; - typedef enum { GPIO_PULLUP_ONLY, /*!< Pad pull up */ GPIO_PULLDOWN_ONLY, /*!< Pad pull down */ @@ -207,254 +201,250 @@ typedef enum { typedef void (*gpio_event_callback)(gpio_num_t gpio_intr_num); -/** \defgroup Driver_APIs Driver APIs - * @brief Driver APIs - */ - -/** @addtogroup Driver_APIs - * @{ - */ - -/** \defgroup GPIO_Driver_APIs GPIO Driver APIs - * @brief GPIO APIs - */ - -/** @addtogroup GPIO_Driver_APIs - * @{ - */ - /** - * @brief GPIO common configuration + * @brief GPIO common configuration * - * Use this Function ,Configure GPIO's Mode,pull-up,PullDown,IntrType + * Configure GPIO's Mode,pull-up,PullDown,IntrType * - * @param[in] pGPIOConfig - * pGPIOConfig.pin_bit_mask : Configure GPIO pins bits,set this parameter with bit mask. - * If you want to configure GPIO34 and GPIO16, pin_bit_mask=GPIO_Pin_16|GPIO_Pin_34; - * pGPIOConfig.mode : Configure GPIO mode,such as output ,input... - * pGPIOConfig.pull_up_en : Enable or Disable pull-up - * pGPIOConfig.pull_down_en : Enable or Disable pull-down - * pGPIOConfig.intr_type : Configure GPIO interrupt trigger type - * @return ESP_OK: success ; - * ESP_ERR_INVALID_ARG: parameter error - * ESP_FAIL : GPIO error + * @param pGPIOConfig Pointer to GPIO configure struct + * + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_config(gpio_config_t *pGPIOConfig); /** - * @brief GPIO set interrupt trigger type + * @brief GPIO set interrupt trigger type * - * @param[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @param[in] intr_type: interrupt type, select from gpio_int_type_t + * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param intr_type Interrupt type, select from gpio_int_type_t * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_set_intr_type(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** - * @brief enable GPIO module interrupt signal + * @brief Enable GPIO module interrupt signal * - * @param[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_intr_enable(gpio_num_t gpio_num); /** - * @brief disable GPIO module interrupt signal + * @brief Disable GPIO module interrupt signal * - * @param[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t gpio_intr_disable(gpio_num_t gpio_num); /** - * @brief GPIO set output level + * @brief GPIO set output level * - * @param[in] gpio_num : GPIO number. - * If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @param[in] level : Output level. 0: low ; 1: high + * @param gpio_num GPIO number. If you want to set output level of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param level Output level. 0: low ; 1: high * - * @return ESP_OK : success - * ESP_FAIL : GPIO error + * @return + * - ESP_OK Success + * - GPIO_IS_VALID_GPIO GPIO number error * */ esp_err_t gpio_set_level(gpio_num_t gpio_num, uint32_t level); /** - * @brief GPIO get input level + * @brief GPIO get input level * - * @param[in] gpio_num : GPIO number. - * If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param gpio_num GPIO number. If you want to get level of pin GPIO16, gpio_num should be GPIO_NUM_16 (16); * - * @return 0 : the GPIO input level is 0 - * 1 : the GPIO input level is 1 + * @return + * - 0 the GPIO input level is 0 + * - 1 the GPIO input level is 1 * */ int gpio_get_level(gpio_num_t gpio_num); /** - * @brief GPIO set direction + * @brief GPIO set direction * * Configure GPIO direction,such as output_only,input_only,output_and_input * - * @param[in] gpio_num : Configure GPIO pins number,it should be GPIO number. - * If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16); - * @param[in] mode : Configure GPIO direction,such as output_only,input_only,... + * @param gpio_num Configure GPIO pins number, it should be GPIO number. If you want to set direction of GPIO16, gpio_num should be GPIO_NUM_16 (16); + * @param mode GPIO direction * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : fail - * ESP_FAIL : GPIO error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG GPIO error * */ esp_err_t gpio_set_direction(gpio_num_t gpio_num, gpio_mode_t mode); /** - * @brief GPIO set pull + * @brief GPIO set pull * * User this Function,configure GPIO pull mode,such as pull-up,pull-down * - * @param[in] gpio_num : Configure GPIO pins number,it should be GPIO number. - * If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16); - * @param[in] pull : Configure GPIO pull up/down mode,such as pullup_only,pulldown_only,pullup_and_pulldown,... + * @param gpio_num GPIO number. If you want to set pull up or down mode for GPIO16,gpio_num should be GPIO_NUM_16 (16); + * @param pull GPIO pull up/down mode. * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : fail - * ESP_FAIL : GPIO error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG : Parameter error * */ esp_err_t gpio_set_pull_mode(gpio_num_t gpio_num, gpio_pull_mode_t pull); /** - * @brief enable GPIO wake-up function. + * @brief enable GPIO wake-up function. * - * @param gpio_num : GPIO number. + * @param gpio_num GPIO number. * - * @param intr_type : only GPIO_INTR_LOLEVEL\GPIO_INTR_HILEVEL can be used + * @param intr_type GPIO wake-up type. Only GPIO_INTR_LOLEVEL\GPIO_INTR_HILEVEL can be used * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t gpio_wakeup_enable(gpio_num_t gpio_num, gpio_int_type_t intr_type); /** - * @brief disable GPIO wake-up function. + * @brief Disable GPIO wake-up function. * - * @param gpio_num: GPIO number + * @param gpio_num GPIO number * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t gpio_wakeup_disable(gpio_num_t gpio_num); /** * @brief register GPIO interrupt handler, the handler is an ISR. * The handler will be attached to the same CPU core that this function is running on. + * @note * Users should know that which CPU is running and then pick a INUM that is not used by system. * We can find the information of INUM and interrupt level in soc.h. - * TODO: to move INUM options to menu_config - * @param gpio_intr_num : GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details - * @param (*fn)(void* ) : interrupt handler function. - * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". - * @param arg : parameter for handler function * - * @return ESP_OK : success ; - * ESP_FAIL: gpio error + * @param gpio_intr_num GPIO interrupt number,check the info in soc.h, and please see the core-isa.h for more details + * @param fn Interrupt handler function. + * + * @note + * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". + * + * @param arg Parameter for handler function + * + * @return + * - ESP_OK Success ; + * - ESP_ERR_INVALID_ARG GPIO error */ esp_err_t gpio_isr_register(uint32_t gpio_intr_num, void (*fn)(void*), void * arg); /** * *************** ATTENTION ********************/ /** - * - * Each GPIO has its own separate configuration register, so we do not use - * a lock to serialize access to them. This works under the assumption that - * no situation will occur where two tasks try to configure the same GPIO - * pin simultaneously. It is up to the application developer to guarantee this. + *@attention + * Each GPIO has its own separate configuration register, so we do not use + * a lock to serialize access to them. This works under the assumption that + * no situation will occur where two tasks try to configure the same GPIO + * pin simultaneously. It is up to the application developer to guarantee this. */ - -/*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ */ -/* gpio_config_t io_conf; +/** + *----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ * + * @code{c} + * gpio_config_t io_conf; * io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt * io_conf.mode = GPIO_MODE_OUTPUT; //set as output mode * io_conf.pin_bit_mask = GPIO_SEL_18 | GPIO_SEL_19; //bit mask of the pins that you want to set,e.g.GPIO18/19 * io_conf.pull_down_en = 0; //disable pull-down mode * io_conf.pull_up_en = 0; //disable pull-up mode * gpio_config(&io_conf); //configure GPIO with the given settings + * @endcode **/ -/*----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ */ -/* io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt + +/** + *----------EXAMPLE TO CONIFGURE GPIO AS OUTPUT ------------ * + * @code{c} + * io_conf.intr_type = GPIO_INTR_POSEDGE; //set posedge interrupt * io_conf.mode = GPIO_MODE_INPUT; //set as input * io_conf.pin_bit_mask = GPIO_SEL_4 | GPIO_SEL_5; //bit mask of the pins that you want to set, e.g.,GPIO4/5 * io_conf.pull_down_en = 0; //disable pull-down mode * io_conf.pull_up_en = 1; //enable pull-up mode * gpio_config(&io_conf); //configure GPIO with the given settings - *----------EXAMPLE TO SET ISR HANDLER ----------------------*/ -/* gpio_isr_register(18,gpio_intr_test,NULL); //hook the isr handler for GPIO interrupt - * //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. - * //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt. - * //NOTE2:do not pick the INUM that already occupied by the system. - * //NOTE3:refer to soc.h to check which INUMs that can be used. - *-------------EXAMPLE OF HANDLER FUNCTION-------------------*/ -/*#include "esp_attr.h" + * @endcode + */ +/** + *----------EXAMPLE TO SET ISR HANDLER ---------------------- + * @code{c} + * //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. + * gpio_isr_register(18,gpio_intr_test,NULL); //hook the isr handler for GPIO interrupt + * @endcode + * @note + * 1. user should arrange the INUMs that used, better not to use a same INUM for different interrupt. + * 2. do not pick the INUM that already occupied by the system. + * 3. refer to soc.h to check which INUMs that can be used. + */ +/** + *-------------EXAMPLE OF HANDLER FUNCTION-------------------* + * @code{c} + * #include "esp_attr.h" * void IRAM_ATTR gpio_intr_test(void* arg) - *{ - * //GPIO intr process - * ets_printf("in gpio_intr\n"); - * uint32_t gpio_num = 0; - * uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31 - * uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39 - * SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31 - * SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39 - * do { - * if(gpio_num < 32) { - * if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31 - * ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num)); - * //This is an isr handler, you should post an event to process it in RTOS queue. - * } - * } else { - * if(gpio_intr_status_h & BIT(gpio_num - 32)) { - * ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num)); - * //This is an isr handler, you should post an event to process it in RTOS queue. - * } - * } - * } while(++gpio_num < GPIO_PIN_COUNT); - *} - *----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---*/ -/* gpio_config_t io_conf; - * io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt - * io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode - * io_conf.pin_bit_mask = GPIO_SEL_21 | GPIO_SEL_22; //bit mask of the pins that you want to set,e.g.GPIO21/22 - * io_conf.pull_down_en = 0; //disable pull-down mode - * io_conf.pull_up_en = 1; //enable pull-up mode - * gpio_config(&io_conf); //configure GPIO with the given settings - * gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix - * gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix - * gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix + * { + * //GPIO intr process + * ets_printf("in gpio_intr\n"); + * uint32_t gpio_num = 0; + * uint32_t gpio_intr_status = READ_PERI_REG(GPIO_STATUS_REG); //read status to get interrupt status for GPIO0-31 + * uint32_t gpio_intr_status_h = READ_PERI_REG(GPIO_STATUS1_REG);//read status1 to get interrupt status for GPIO32-39 + * SET_PERI_REG_MASK(GPIO_STATUS_W1TC_REG, gpio_intr_status); //Clear intr for gpio0-gpio31 + * SET_PERI_REG_MASK(GPIO_STATUS1_W1TC_REG, gpio_intr_status_h); //Clear intr for gpio32-39 + * do { + * if(gpio_num < 32) { + * if(gpio_intr_status & BIT(gpio_num)) { //gpio0-gpio31 + * ets_printf("Intr GPIO%d ,val: %d\n",gpio_num,gpio_get_level(gpio_num)); + * //This is an isr handler, you should post an event to process it in RTOS queue. + * } + * } else { + * if(gpio_intr_status_h & BIT(gpio_num - 32)) { + * ets_printf("Intr GPIO%d, val : %d\n",gpio_num,gpio_get_level(gpio_num)); + * //This is an isr handler, you should post an event to process it in RTOS queue. + * } + * } + * } while(++gpio_num < GPIO_PIN_COUNT); + * } + * @endcode + */ + +/** + *----EXAMPLE OF I2C CONFIG AND PICK SIGNAL FOR IO MATRIX---* + * @code{c} + * gpio_config_t io_conf; + * io_conf.intr_type = GPIO_INTR_DISABLE; //disable interrupt + * io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD; //set as output mode + * io_conf.pin_bit_mask = GPIO_SEL_21 | GPIO_SEL_22; //bit mask of the pins that you want to set,e.g.GPIO21/22 + * io_conf.pull_down_en = 0; //disable pull-down mode + * io_conf.pull_up_en = 1; //enable pull-up mode + * gpio_config(&io_conf); //configure GPIO with the given settings + * gpio_matrix_out(21, EXT_I2C_SCL_O_IDX, 0, 0); //set output signal for io_matrix + * gpio_matrix_out(22, EXT_I2C_SDA_O_IDX, 0, 0); //set output signal for io_matrix + * gpio_matrix_in( 22, EXT_I2C_SDA_I_IDX, 0); //set input signal for io_matrix + * @endcode * */ -/** - * @} - */ - -/** - * @} - */ - #ifdef __cplusplus } #endif diff --git a/components/driver/include/driver/ledc.h b/components/driver/include/driver/ledc.h index 79a6c7f9f3..3ab0ebff1e 100644 --- a/components/driver/include/driver/ledc.h +++ b/components/driver/include/driver/ledc.h @@ -30,68 +30,68 @@ extern "C" { #define LEDC_REF_CLK_HZ (1*1000000) typedef enum { - LEDC_HIGH_SPEED_MODE = 0, /*LEDC high speed speed_mode */ + LEDC_HIGH_SPEED_MODE = 0, /*!< LEDC high speed speed_mode */ //in this version, we only support high speed speed_mode. We will access low speed speed_mode later - //LEDC_LOW_SPEED_MODE, /*LEDC low speed speed_mode */ - LEDC_SPEED_MODE_MAX, + //LEDC_LOW_SPEED_MODE, /*!< LEDC low speed speed_mode */ + LEDC_SPEED_MODE_MAX, /*!< LEDC speed limit */ } ledc_mode_t; typedef enum { - LEDC_INTR_DISABLE = 0, /*Disable LEDC interrupt */ - LEDC_INTR_FADE_END, /*Enable LEDC interrupt */ + LEDC_INTR_DISABLE = 0, /*!< Disable LEDC interrupt */ + LEDC_INTR_FADE_END, /*!< Enable LEDC interrupt */ } ledc_intr_type_t; typedef enum { - LEDC_DUTY_DIR_DECREASE = 0, /*LEDC duty decrease direction */ - LEDC_DUTY_DIR_INCREASE = 1, /*LEDC duty increase direction */ + LEDC_DUTY_DIR_DECREASE = 0, /*!< LEDC duty decrease direction */ + LEDC_DUTY_DIR_INCREASE = 1, /*!< LEDC duty increase direction */ } ledc_duty_direction_t; typedef enum { - LEDC_REF_TICK = 0, /*LEDC timer clock divided from reference tick(1Mhz) */ - LEDC_APB_CLK, /*LEDC timer clock divided from APB clock(80Mhz)*/ + LEDC_REF_TICK = 0, /*!< LEDC timer clock divided from reference tick(1Mhz) */ + LEDC_APB_CLK, /*!< LEDC timer clock divided from APB clock(80Mhz)*/ } ledc_clk_src_t; typedef enum { - LEDC_TIMER_0 = 0, /*LEDC source timer TIMER0 */ - LEDC_TIMER_1, /*LEDC source timer TIMER1 */ - LEDC_TIMER_2, /*LEDC source timer TIMER2 */ - LEDC_TIMER_3, /*LEDC source timer TIMER3 */ + LEDC_TIMER_0 = 0, /*!< LEDC source timer TIMER0 */ + LEDC_TIMER_1, /*!< LEDC source timer TIMER1 */ + LEDC_TIMER_2, /*!< LEDC source timer TIMER2 */ + LEDC_TIMER_3, /*!< LEDC source timer TIMER3 */ } ledc_timer_t; typedef enum { - LEDC_CHANNEL_0 = 0, /*LEDC channel 0 */ - LEDC_CHANNEL_1, /*LEDC channel 1 */ - LEDC_CHANNEL_2, /*LEDC channel 2 */ - LEDC_CHANNEL_3, /*LEDC channel 3 */ - LEDC_CHANNEL_4, /*LEDC channel 4 */ - LEDC_CHANNEL_5, /*LEDC channel 5 */ - LEDC_CHANNEL_6, /*LEDC channel 6 */ - LEDC_CHANNEL_7, /*LEDC channel 7 */ + LEDC_CHANNEL_0 = 0, /*!< LEDC channel 0 */ + LEDC_CHANNEL_1, /*!< LEDC channel 1 */ + LEDC_CHANNEL_2, /*!< LEDC channel 2 */ + LEDC_CHANNEL_3, /*!< LEDC channel 3 */ + LEDC_CHANNEL_4, /*!< LEDC channel 4 */ + LEDC_CHANNEL_5, /*!< LEDC channel 5 */ + LEDC_CHANNEL_6, /*!< LEDC channel 6 */ + LEDC_CHANNEL_7, /*!< LEDC channel 7 */ } ledc_channel_t; typedef enum { - LEDC_TIMER_10_BIT = 10, /*LEDC PWM depth 10Bit */ - LEDC_TIMER_11_BIT = 11, /*LEDC PWM depth 11Bit */ - LEDC_TIMER_12_BIT = 12, /*LEDC PWM depth 12Bit */ - LEDC_TIMER_13_BIT = 13, /*LEDC PWM depth 13Bit */ - LEDC_TIMER_14_BIT = 14, /*LEDC PWM depth 14Bit */ - LEDC_TIMER_15_BIT = 15, /*LEDC PWM depth 15Bit */ + LEDC_TIMER_10_BIT = 10, /*!< LEDC PWM depth 10Bit */ + LEDC_TIMER_11_BIT = 11, /*!< LEDC PWM depth 11Bit */ + LEDC_TIMER_12_BIT = 12, /*!< LEDC PWM depth 12Bit */ + LEDC_TIMER_13_BIT = 13, /*!< LEDC PWM depth 13Bit */ + LEDC_TIMER_14_BIT = 14, /*!< LEDC PWM depth 14Bit */ + LEDC_TIMER_15_BIT = 15, /*!< LEDC PWM depth 15Bit */ } ledc_timer_bit_t; typedef struct { - int gpio_num; /*the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/ - ledc_mode_t speed_mode; /*LEDC speed speed_mode, high-speed mode or low-speed mode*/ - ledc_channel_t channel; /*LEDC channel(0 - 7)*/ - ledc_intr_type_t intr_type; /*configure interrupt, Fade interrupt enable or Fade interrupt disable*/ - ledc_timer_t timer_sel; /*Select the timer source of channel (0 - 3)*/ - uint32_t duty; /*LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */ + int gpio_num; /*!< the LEDC output gpio_num, if you want to use gpio16, gpio_num = 16*/ + ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/ + ledc_channel_t channel; /*!< LEDC channel(0 - 7)*/ + ledc_intr_type_t intr_type; /*!< configure interrupt, Fade interrupt enable or Fade interrupt disable*/ + ledc_timer_t timer_sel; /*!< Select the timer source of channel (0 - 3)*/ + uint32_t duty; /*!< LEDC channel duty, the duty range is [0, (2**bit_num) - 1], */ } ledc_channel_config_t; typedef struct { - ledc_mode_t speed_mode; /*LEDC speed speed_mode, high-speed mode or low-speed mode*/ - ledc_timer_bit_t bit_num; /*LEDC channel duty depth*/ - ledc_timer_t timer_num; /*The timer source of channel (0 - 3)*/ - uint32_t freq_hz; /*LEDC timer frequency(Hz)*/ + ledc_mode_t speed_mode; /*!< LEDC speed speed_mode, high-speed mode or low-speed mode*/ + ledc_timer_bit_t bit_num; /*!< LEDC channel duty depth*/ + ledc_timer_t timer_num; /*!< The timer source of channel (0 - 3)*/ + uint32_t freq_hz; /*!< LEDC timer frequency(Hz)*/ } ledc_timer_config_t; @@ -100,15 +100,10 @@ typedef struct { * * User this Function, configure LEDC channel with the given channel/output gpio_num/interrupt/source timer/frequency(Hz)/LEDC depth * - * @param[in] ledc_channel_config_t - * ledc_channel_config_t.speed_mode : LEDC speed speed_mode - * ledc_channel_config_t.gpio_num : LEDC output gpio_num, if you want to use gpio16, ledc_channel_config_t.gpio_num = 16 - * ledc_channel_config_t.channel : LEDC channel(0 - 7) - * ledc_channel_config_t.intr_type : configure interrupt, Fade interrupt enable or Fade interrupt disable - * ledc_channel_config_t.timer_sel : Select the timer source of channel (0 - 3), high speed channel must bind with high speed timer. - * ledc_channel_config_t.duty : LEDC channel duty, the duty range is [0, (2**timer_bit_num) - 1], - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @param ledc_conf Pointer of LEDC channel configure struct + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf); @@ -118,14 +113,13 @@ esp_err_t ledc_channel_config(ledc_channel_config_t* ledc_conf); * * User this Function, configure LEDC timer with the given source timer/frequency(Hz)/bit_num * - * @param[in] ledc_timer_config_t - * ledc_timer_config_t.speed_mode : LEDC speed speed_mode - * ledc_timer_config_t.timer_num : Select the timer source of channel (0 - 3) - * ledc_timer_config_t.freq_hz : LEDC channel frequency(Hz), - * ledc_timer_config_t.bit_num : LEDC channel duty depth - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error - * ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num. + * @param timer_conf Pointer of LEDC timer configure struct + * + * + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num. * */ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf); @@ -136,12 +130,13 @@ esp_err_t ledc_timer_config(ledc_timer_config_t* timer_conf); * Call this function to activate the LEDC updated parameters. * After ledc_set_duty, ledc_set_fade, we need to call this function to update the settings. * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error * */ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); @@ -151,12 +146,13 @@ esp_err_t ledc_update_duty(ledc_mode_t speed_mode, ledc_channel_t channel); * * Disable LEDC output, and set idle level * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idle_level); @@ -165,27 +161,29 @@ esp_err_t ledc_stop(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t idl * * Set LEDC frequency(Hz) * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_num : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_num LEDC timer index(0-3), select from ledc_timer_t * - * @param[in] freq_hz : set the LEDC frequency + * @param freq_hz Set the LEDC frequency * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error - * ESP_FAIL: Can not find a proper pre-divider number base on the given frequency and the current bit_num. + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_FAIL Can not find a proper pre-divider number base on the given frequency and the current bit_num. */ esp_err_t ledc_set_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num, uint32_t freq_hz); /** * @brief LEDC get channel frequency(Hz) * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_num : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_num LEDC timer index(0-3), select from ledc_timer_t * - * @return 0 : error - * others : current LEDC frequency + * @return + * - 0 error + * - Others Current LEDC frequency * */ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num); @@ -195,27 +193,29 @@ uint32_t ledc_get_freq(ledc_mode_t speed_mode, ledc_timer_t timer_num); * * Set LEDC duty, After the function calls the ledc_update_duty function, the function can take effect. * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @param[in] duty : set the LEDC duty, the duty range is [0, (2**bit_num) - 1] + * @param duty Set the LEDC duty, the duty range is [0, (2**bit_num) - 1] * - * @return ESP_OK: success - * ESP_ERR_INVALID_ARG: parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_duty(ledc_mode_t speed_mode, ledc_channel_t channel, uint32_t duty); /** * @brief LEDC get duty * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * * - * @return -1: parameter error - * other value: current LEDC duty + * @return + * - (-1) parameter error + * - Others Current LEDC duty * */ int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel); @@ -225,22 +225,23 @@ int ledc_get_duty(ledc_mode_t speed_mode, ledc_channel_t channel); * * Set LEDC gradient, After the function calls the ledc_update_duty function, the function can take effect. * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel(0-7), select from ledc_channel_t + * @param channel LEDC channel(0-7), select from ledc_channel_t * - * @param[in] duty : set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1] + * @param duty Set the start of the gradient duty, the duty range is [0, (2**bit_num) - 1] * - * @param[in] gradule_direction : set the direction of the gradient + * @param gradule_direction Set the direction of the gradient * - * @param[in] step_num : set the number of the gradient + * @param step_num Set the number of the gradient * - * @param[in] duty_cyle_num : set how many LEDC tick each time the gradient lasts + * @param duty_cyle_num Set how many LEDC tick each time the gradient lasts * - * @param[in] duty_scale : set gradient change amplitude + * @param duty_scale Set gradient change amplitude * - * @return ESP_OK : success - * ESP_ERR_INVALID_ARG : parameter error + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Parameter error */ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, ledc_duty_direction_t gradule_direction, uint32_t step_num, uint32_t duty_cyle_num, uint32_t duty_scale); @@ -248,34 +249,37 @@ esp_err_t ledc_set_fade(ledc_mode_t speed_mode, uint32_t channel, uint32_t duty, /** * @brief register LEDC interrupt handler, the handler is an ISR. * The handler will be attached to the same CPU core that this function is running on. - * Users should know that which CPU is running and then pick a INUM that is not used by system. - * We can find the information of INUM and interrupt level in soc.h. - * TODO: to move INUM options to menu_config - * @param[in] uint32_t ledc_intr_num : LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details - * @param[in] void (* fn)(void* ) : interrupt handler function. - * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". - * @param[in] void * arg : parameter for handler function + * @note + * Users should know that which CPU is running and then pick a INUM that is not used by system. + * We can find the information of INUM and interrupt level in soc.h. + * @param ledc_intr_num LEDC interrupt number, check the info in soc.h, and please see the core-isa.h for more details + * @param fn Interrupt handler function. + * @note + * Note that the handler function MUST be defined with attribution of "IRAM_ATTR". + * @param arg Parameter for handler function * - * @return ESP_OK : success ; - * ESP_ERR_INVALID_ARG : function ptr error. + * @return + * - ESP_OK Success + * - ESP_ERR_INVALID_ARG Function pointer error. */ esp_err_t ledc_isr_register(uint32_t ledc_intr_num, void (*fn)(void*), void * arg); /** * @brief configure LEDC settings * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : timer index(0-3), there are 4 timers in LEDC module + * @param timer_sel Timer index(0-3), there are 4 timers in LEDC module * - * @param[in] div_num : timer clock divide number, the timer clock is divided from the selected clock source + * @param div_num Timer clock divide number, the timer clock is divided from the selected clock source * - * @param[in] bit_num : the count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1) + * @param bit_num The count number of one period, counter range is 0 ~ ((2 ** bit_num) - 1) * - * @param[in] clk_src : select LEDC source clock. + * @param clk_src Select LEDC source clock. * - * @return -1: parameter error - * other value: current LEDC duty + * @return + * - (-1) Parameter error + * - Other Current LEDC duty * */ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_t div_num, uint32_t bit_num, ledc_clk_src_t clk_src); @@ -283,13 +287,14 @@ esp_err_t ledc_timer_set(ledc_mode_t speed_mode, ledc_timer_t timer_sel, uint32_ /** * @brief reset LEDC timer * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel); @@ -297,13 +302,14 @@ esp_err_t ledc_timer_rst(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief pause LEDC timer counter * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel); @@ -311,13 +317,14 @@ esp_err_t ledc_timer_pause(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief pause LEDC timer resume * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] timer_sel : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_sel LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel); @@ -325,15 +332,16 @@ esp_err_t ledc_timer_resume(ledc_mode_t speed_mode, uint32_t timer_sel); /** * @brief bind LEDC channel with the selected timer * - * @param[in] speed_mode : select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version + * @param speed_mode Select the LEDC speed_mode, high-speed mode and low-speed mode, now we only support high-speed mode. We will access low-speed mode in next version * - * @param[in] channel : LEDC channel index(0-7), select from ledc_channel_t + * @param channel LEDC channel index(0-7), select from ledc_channel_t * - * @param[in] timer_idx : LEDC timer index(0-3), select from ledc_timer_t + * @param timer_idx LEDC timer index(0-3), select from ledc_timer_t * * - * @return ESP_ERR_INVALID_ARG: parameter error - * ESP_OK: success + * @return + * - ESP_ERR_INVALID_ARG Parameter error + * - ESP_OK Success * */ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint32_t timer_idx); @@ -342,44 +350,56 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint * * * ----------------EXAMPLE OF LEDC SETTING --------------------- - * //1. enable LEDC - * periph_module_enable(PERIPH_LEDC_MODULE); //enable LEDC module, or you can not set any register of it. + * @code{c} + * //1. enable LEDC + * //enable LEDC module, or you can not set any register of it. + * periph_module_enable(PERIPH_LEDC_MODULE); + * @endcode * - * //2. set LEDC timer - * ledc_timer_config_t timer_conf = { - * .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number - * .freq_hz = 1000, //set frequency of pwm, here, 1000Hz - * .speed_mode = LEDC_HIGH_SPEED_MODE //timer mode, - * .timer_num = LEDC_TIMER_0, //timer number - * }; - * ledc_timer_config(&timer_conf); //setup timer. + * @code{c} + * //2. set LEDC timer + * ledc_timer_config_t timer_conf = { + * .bit_num = LEDC_TIMER_12_BIT, //set timer counter bit number + * .freq_hz = 1000, //set frequency of pwm, here, 1000Hz + * .speed_mode = LEDC_HIGH_SPEED_MODE, //timer mode, + * .timer_num = LEDC_TIMER_0, //timer number + * }; + * ledc_timer_config(&timer_conf); //setup timer. + * @endcode * - * //3. set LEDC channel - * ledc_channel_config_t ledc_conf = { - * .channel = LEDC_CHANNEL_0; //set LEDC channel 0 - * .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1) - * .gpio_num = 16; //GPIO number - * .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. - * .speed_mode = LEDC_HIGH_SPEED_MODE; //set LEDC mode, from ledc_mode_t - * .timer_sel = LEDC_TIMER_0; //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same - * } - * ledc_channel_config(&ledc_conf); //setup the configuration + * @code{c} + * //3. set LEDC channel + * ledc_channel_config_t ledc_conf = { + * .channel = LEDC_CHANNEL_0; //set LEDC channel 0 + * .duty = 1000; //set the duty for initialization.(duty range is 0 ~ ((2**bit_num)-1) + * .gpio_num = 16; //GPIO number + * .intr_type = LEDC_INTR_FADE_END; //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. + * .speed_mode = LEDC_HIGH_SPEED_MODE; //set LEDC mode, from ledc_mode_t + * .timer_sel = LEDC_TIMER_0; //set LEDC timer source, if different channel use one timer, the frequency and bit_num of these channels should be the same + * } + * ledc_channel_config(&ledc_conf); //setup the configuration * * ----------------EXAMPLE OF SETTING DUTY --- ----------------- - * uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73) - * uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1) - * LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty. - * ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings. - * + * @code{c} + * uint32_t ledc_channel = LEDC_CHANNEL_0; //LEDC channel(0-73) + * uint32_t duty = 2000; //duty range is 0 ~ ((2**bit_num)-1) + * LEDC_set_duty(LEDC_HIGH_SPEED_MODE, ledc_channel, duty); //set speed mode, channel, and duty. + * ledc_update_duty(LEDC_HIGH_SPEED_MODE, ledc_channel); //after set duty, we need to call ledc_update_duty to update the settings. + * @endcode * * ----------------EXAMPLE OF LEDC INTERRUPT ------------------ - * //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here. - * ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt - * //the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. - * //NOTE1:user should arrange the INUMs that used, better not to use a same INUM for different interrupt source. - * //NOTE2:do not pick the INUM that already occupied by the system. - * //NOTE3:refer to soc.h to check which INUMs that can be used. + * @code{c} + * //we have fade_end interrupt and counter overflow interrupt. we just give an example of fade_end interrupt here. + * ledc_isr_register(18, ledc_isr_handler, NULL); //hook the isr handler for LEDC interrupt + * @endcode + * @note + * 1. the first parameter is INUM, you can pick one form interrupt level 1/2 which is not used by the system. + * 2. user should arrange the INUMs that used, better not to use a same INUM for different interrupt source. + * 3. do not pick the INUM that already occupied by the system. + * 4. refer to soc.h to check which INUMs that can be used. + * * ----------------EXAMPLE OF INTERRUPT HANDLER --------------- + * @code{c} * #include "esp_attr.h" * void IRAM_ATTR ledc_isr_handler(void* arg) //we should add 'IRAM_ATTR' attribution when we declare the isr function * { @@ -391,7 +411,7 @@ esp_err_t ledc_bind_channel_timer(ledc_mode_t speed_mode, uint32_t channel, uint * * LEDC.int_clr.val = intr_st; //clear LEDC interrupt status. * } - * + * @endcode * *--------------------------END OF EXAMPLE -------------------------- */ From d0fac3c39566d819022b569f2f2f26b3552c2166 Mon Sep 17 00:00:00 2001 From: Jeroen Domburg Date: Wed, 2 Nov 2016 10:26:02 +0800 Subject: [PATCH 91/95] Language tweaking --- docs/openocd.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/openocd.rst b/docs/openocd.rst index cf1d25e60b..9e2aeff459 100644 --- a/docs/openocd.rst +++ b/docs/openocd.rst @@ -1,7 +1,7 @@ OpenOCD setup for ESP32 ----------------------- -The ESP31 and ESP32 have two powerful Xtensa cores, allowing for a great deal of variety of program architectures. The FreeRTOS +The ESP31 and ESP32 have two powerful Xtensa cores, allowing for a great variety of program architectures. The FreeRTOS OS that comes with ESP-IDF is capable of multi-core pre-emptive multithreading, allowing for an intuitive way of writing software. The downside of the ease of programming is that debugging without the right tools is harder: figuring out a bug that is caused From c534dedf2d2a720fa748a57ce60b823d7a8069fe Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Wed, 2 Nov 2016 17:17:28 +0800 Subject: [PATCH 92/95] newlib: implement time syscalls --- components/esp32/Kconfig | 29 +++++ components/esp32/cpu_start.c | 3 +- components/esp32/include/soc/frc_timer_reg.h | 49 ++++++++ components/esp32/include/soc/rtc_cntl_reg.h | 3 + components/esp32/include/soc/soc.h | 9 +- .../newlib/platform_include/esp_newlib.h | 8 +- components/newlib/syscall_table.c | 3 +- components/newlib/time.c | 118 +++++++++++++++++- 8 files changed, 211 insertions(+), 11 deletions(-) create mode 100644 components/esp32/include/soc/frc_timer_reg.h diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index b5a8d2f2dd..928b190321 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -319,6 +319,35 @@ config BROWNOUT_DET_RESETDELAY before trying to restart the chip. You can set the delay here. +choice ESP32_TIME_SYSCALL + prompt "Timers used for gettimeofday function" + default ESP32_TIME_SYSCALL_USE_RTC_FRC1 + help + This setting defines which hardware timers are used to + implement 'gettimeofday' function in C library. + + - If only FRC1 timer is used, gettimeofday will provide time at + microsecond resolution. Time will not be preserved when going + into deep sleep mode. + - If both FRC1 and RTC timers are used, timekeeping will + continue in deep sleep. Time will be reported at 1 microsecond + resolution. + - If only RTC timer is used, timekeeping will continue in + deep sleep, but time will be measured at 6.(6) microsecond + resolution. Also the gettimeofday function itself may take + longer to run. + - If no timers are used, gettimeofday function return -1 and + set errno to ENOSYS. + +config ESP32_TIME_SYSCALL_USE_RTC + bool "RTC" +config ESP32_TIME_SYSCALL_USE_RTC_FRC1 + bool "RTC and FRC1" +config ESP32_TIME_SYSCALL_USE_FRC1 + bool "FRC1" +config ESP32_TIME_SYSCALL_USE_NONE + bool "None" +endchoice endmenu diff --git a/components/esp32/cpu_start.c b/components/esp32/cpu_start.c index 8d56e2c12d..c82c528597 100644 --- a/components/esp32/cpu_start.c +++ b/components/esp32/cpu_start.c @@ -169,7 +169,8 @@ void start_cpu0_default(void) #if CONFIG_TASK_WDT esp_task_wdt_init(); #endif - esp_setup_syscalls(); + esp_setup_syscall_table(); + esp_setup_time_syscalls(); esp_vfs_dev_uart_register(); esp_reent_init(_GLOBAL_REENT); const char* default_uart_dev = "/dev/uart/0"; diff --git a/components/esp32/include/soc/frc_timer_reg.h b/components/esp32/include/soc/frc_timer_reg.h new file mode 100644 index 0000000000..24b942c0bb --- /dev/null +++ b/components/esp32/include/soc/frc_timer_reg.h @@ -0,0 +1,49 @@ +// Copyright 2015-2016 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 _SOC_FRC_TIMER_REG_H_ +#define _SOC_FRC_TIMER_REG_H_ + +#include "soc.h" + +/** + * These are the register definitions for "legacy" timers + */ + +#define REG_FRC_TIMER_BASE(i) (DR_REG_FRC_TIMER_BASE + i*0x20) + +#define FRC_TIMER_LOAD_REG(i) (REG_FRC_TIMER_BASE(i) + 0x0) // timer load value (23 bit for i==0, 32 bit for i==1) +#define FRC_TIMER_LOAD_VALUE(i) ((i == 0)?0x007FFFFF:0xffffffff) +#define FRC_TIMER_LOAD_VALUE_S 0 + +#define FRC_TIMER_COUNT_REG(i) (REG_FRC_TIMER_BASE(i) + 0x4) // timer count value (23 bit for i==0, 32 bit for i==1) +#define FRC_TIMER_COUNT ((i == 0)?0x007FFFFF:0xffffffff) +#define FRC_TIMER_COUNT_S 0 + +#define FRC_TIMER_CTRL_REG(i) (REG_FRC_TIMER_BASE(i) + 0x8) +#define FRC_TIMER_INT_ENABLE (BIT(8)) // enable interrupt +#define FRC_TIMER_ENABLE (BIT(7)) // enable timer +#define FRC_TIMER_AUTOLOAD (BIT(6)) // enable autoload +#define FRC_TIMER_PRESCALER 0x00000007 // 0: divide by 1, 2: divide by 16, 4: divide by 256 +#define FRC_TIMER_PRESCALER_S 1 +#define FRC_TIMER_EDGE_INT (BIT(0)) // 0: level, 1: edge + +#define FRC_TIMER_INT_REG(i) (REG_FRC_TIMER_BASE(i) + 0xC) +#define FRC_TIMER_INT_CLR (BIT(0)) // clear interrupt + +#define FRC_TIMER_ALARM_REG(i) (REG_FRC_TIMER_BASE(i) + 0x10) // timer alarm value; register only present for i == 1 +#define FRC_TIMER_ALARM 0xFFFFFFFF +#define FRC_TIMER_ALARM_S 0 + +#endif //_SOC_FRC_TIMER_REG_H_ diff --git a/components/esp32/include/soc/rtc_cntl_reg.h b/components/esp32/include/soc/rtc_cntl_reg.h index bb4e2afced..d99cec1864 100644 --- a/components/esp32/include/soc/rtc_cntl_reg.h +++ b/components/esp32/include/soc/rtc_cntl_reg.h @@ -239,6 +239,9 @@ #define RTC_CNTL_TIME_VALID_V 0x1 #define RTC_CNTL_TIME_VALID_S 30 +/* frequency of RTC slow clock, Hz */ +#define RTC_CTNL_SLOWCLK_FREQ 150000 + #define RTC_CNTL_TIME0_REG (DR_REG_RTCCNTL_BASE + 0x10) /* RTC_CNTL_TIME_LO : RO ;bitpos:[31:0] ;default: 32'h0 ; */ /*description: RTC timer low 32 bits*/ diff --git a/components/esp32/include/soc/soc.h b/components/esp32/include/soc/soc.h index 4ffdfb069e..8ab9f027c5 100755 --- a/components/esp32/include/soc/soc.h +++ b/components/esp32/include/soc/soc.h @@ -148,6 +148,7 @@ #define DR_REG_GPIO_SD_BASE 0x3ff44f00 #define DR_REG_FE2_BASE 0x3ff45000 #define DR_REG_FE_BASE 0x3ff46000 +#define DR_REG_FRC_TIMER_BASE 0x3ff47000 #define DR_REG_RTCCNTL_BASE 0x3ff48000 #define DR_REG_RTCIO_BASE 0x3ff48400 #define DR_REG_SARADC_BASE 0x3ff48800 @@ -281,9 +282,9 @@ * 19 2 extern level * 20 2 extern level * 21 2 extern level - * 22 3 extern edge + * 22 3 extern edge FRC1 timer * 23 3 extern level - * 24 4 extern level + * 24 4 extern level TG1_WDT * 25 4 extern level Reserved Reserved * 26 5 extern level Reserved Reserved * 27 3 extern level Reserved Reserved @@ -301,8 +302,10 @@ #define ETS_T0_WDT_INUM 3 #define ETS_WBB_INUM 4 #define ETS_TG0_T1_INUM 10 /**< use edge interrupt*/ +#define ETS_FRC1_INUM 22 +#define ETS_T1_WDT_INUM 24 -//CPU0 Intrrupt number used in ROM, should be cancelled in SDK +//CPU0 Interrupt number used in ROM, should be cancelled in SDK #define ETS_SLC_INUM 1 #define ETS_UART0_INUM 5 #define ETS_UART1_INUM 5 diff --git a/components/newlib/platform_include/esp_newlib.h b/components/newlib/platform_include/esp_newlib.h index 468f2ae34f..eac3544259 100644 --- a/components/newlib/platform_include/esp_newlib.h +++ b/components/newlib/platform_include/esp_newlib.h @@ -31,7 +31,13 @@ void esp_reent_init(struct _reent* r); * Called from the startup code, not intended to be called from application * code. */ -void esp_setup_syscalls(); +void esp_setup_syscall_table(); +/** + * Initialize hardware timer used as time source for newlib time functions. + * + * Called from the startup code, not intended to be called from application. + */ +void esp_setup_time_syscalls(); #endif //__ESP_NEWLIB_H__ diff --git a/components/newlib/syscall_table.c b/components/newlib/syscall_table.c index b6414af554..feed768172 100644 --- a/components/newlib/syscall_table.c +++ b/components/newlib/syscall_table.c @@ -24,6 +24,7 @@ #include #include "rom/libc_stubs.h" #include "esp_vfs.h" +#include "esp_newlib.h" static struct _reent s_reent; @@ -79,7 +80,7 @@ static struct syscall_stub_table s_stub_table = { ._scanf_float = &_scanf_float, }; -void esp_setup_syscalls() +void esp_setup_syscall_table() { syscall_table_ptr_pro = &s_stub_table; syscall_table_ptr_app = &s_stub_table; diff --git a/components/newlib/time.c b/components/newlib/time.c index 021b295451..83645aa4cc 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -14,22 +14,130 @@ #include #include +#include +#include #include #include #include #include #include "esp_attr.h" +#include "soc/soc.h" +#include "soc/rtc_cntl_reg.h" +#include "soc/frc_timer_reg.h" +#include "rom/ets_sys.h" +#include "freertos/FreeRTOS.h" +#include "freertos/xtensa_api.h" +#include "freertos/task.h" +#include "sdkconfig.h" +#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) +#define WITH_RTC 1 +#endif -clock_t _times_r(struct _reent *r, struct tms *ptms) +#if defined( CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 ) || defined( CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1 ) +#define WITH_FRC1 1 +#endif + +#ifdef WITH_RTC +static uint64_t get_rtc_time_us() { - __errno_r(r) = ENOSYS; - return (clock_t) -1; + SET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M); + while (GET_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_VALID_M) == 0) { + ; + } + CLEAR_PERI_REG_MASK(RTC_CNTL_TIME_UPDATE_REG, RTC_CNTL_TIME_UPDATE_M); + uint64_t low = READ_PERI_REG(RTC_CNTL_TIME0_REG); + uint64_t high = READ_PERI_REG(RTC_CNTL_TIME1_REG); + uint64_t ticks = (high << 32) | low; + return ticks * 100 / (RTC_CTNL_SLOWCLK_FREQ / 10000); // scale RTC_CTNL_SLOWCLK_FREQ to avoid overflow +} +#endif // WITH_RTC + + +#ifdef WITH_FRC1 +#define FRC1_PRESCALER 16 +#define FRC1_PRESCALER_CTL 2 +#define FRC1_TICK_FREQ (APB_CLK_FREQ / FRC1_PRESCALER) +#define FRC1_TICKS_PER_US (FRC1_TICK_FREQ / 1000000) +#define FRC1_ISR_PERIOD_US (FRC_TIMER_LOAD_VALUE(0) / FRC1_TICKS_PER_US) +// Counter frequency will be APB_CLK_FREQ / 16 = 5 MHz +// 1 tick = 0.2 us +// Timer has 23 bit counter, so interrupt will fire each 1677721.6 microseconds. +// This is not a whole number, so timer will drift by 0.3 ppm due to rounding error. + +static volatile uint64_t s_microseconds = 0; + +static void IRAM_ATTR frc_timer_isr() +{ + WRITE_PERI_REG(FRC_TIMER_INT_REG(0), FRC_TIMER_INT_CLR); + s_microseconds += FRC1_ISR_PERIOD_US; } -// TODO: read time from RTC -int _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) +#endif // WITH_FRC1 + +void esp_setup_time_syscalls() { +#if defined( WITH_FRC1 ) +#if defined( WITH_RTC ) + // initialize time from RTC clock + s_microseconds = get_rtc_time_us(); +#endif //WITH_RTC + + + // set up timer + WRITE_PERI_REG(FRC_TIMER_CTRL_REG(0), \ + FRC_TIMER_AUTOLOAD | \ + (FRC1_PRESCALER_CTL << FRC_TIMER_PRESCALER_S) | \ + FRC_TIMER_EDGE_INT); + + WRITE_PERI_REG(FRC_TIMER_LOAD_REG(0), FRC_TIMER_LOAD_VALUE(0)); + SET_PERI_REG_MASK(FRC_TIMER_CTRL_REG(0), + FRC_TIMER_ENABLE | \ + FRC_TIMER_INT_ENABLE); + intr_matrix_set(xPortGetCoreID(), ETS_TIMER1_INTR_SOURCE, ETS_FRC1_INUM); + xt_set_interrupt_handler(ETS_FRC1_INUM, &frc_timer_isr, NULL); + xt_ints_on(1 << ETS_FRC1_INUM); +#endif // WITH_FRC1 +} + +clock_t IRAM_ATTR _times_r(struct _reent *r, struct tms *ptms) +{ + clock_t t = xTaskGetTickCount() * (portTICK_PERIOD_MS * CLK_TCK / 1000); + ptms->tms_cstime = t; + ptms->tms_cutime = 0; + ptms->tms_stime = t; + ptms->tms_utime = 0; + struct timeval tv = {0, 0}; + _gettimeofday_r(r, &tv, NULL); + return (clock_t) tv.tv_sec; +} + +int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) +{ + (void) tz; +#ifdef WITH_FRC1 + uint32_t timer_ticks_before = READ_PERI_REG(FRC_TIMER_COUNT_REG(0)); + uint64_t microseconds = s_microseconds; + uint32_t timer_ticks_after = READ_PERI_REG(FRC_TIMER_COUNT_REG(0)); + if (timer_ticks_after > timer_ticks_before) { + // overflow happened at some point between getting + // timer_ticks_before and timer_ticks_after + // microseconds value is ambiguous, get a new one + microseconds = s_microseconds; + } + microseconds += (FRC_TIMER_LOAD_VALUE(0) - timer_ticks_after) / FRC1_TICKS_PER_US; +#elif defined(WITH_RTC) + uint64_t microseconds = get_rtc_time_us(); +#endif + +#if defined( WITH_FRC1 ) || defined( WITH_RTC ) + if (tv) { + tv->tv_sec = microseconds / 1000000; + tv->tv_usec = microseconds % 1000000; + } + return 0; +#else __errno_r(r) = ENOSYS; return -1; +#endif // defined( WITH_FRC1 ) || defined( WITH_RTC ) } From eb2c633cbf4acabbb5822a294d39458ea6c8c81f Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 3 Nov 2016 12:46:46 +0800 Subject: [PATCH 93/95] newlib: implement settimeofday, integrate LwIP SNTP, add SNTP example --- components/esp32/Kconfig | 6 +- components/lwip/Kconfig | 9 + components/lwip/include/lwip/port/lwipopts.h | 17 ++ components/newlib/time.c | 51 +++++- examples/06_sntp/Makefile | 9 + examples/06_sntp/README.md | 41 +++++ examples/06_sntp/main/Kconfig.projbuild | 17 ++ examples/06_sntp/main/component.mk | 10 ++ examples/06_sntp/main/sntp_main.c | 163 +++++++++++++++++++ 9 files changed, 314 insertions(+), 9 deletions(-) create mode 100644 examples/06_sntp/Makefile create mode 100644 examples/06_sntp/README.md create mode 100644 examples/06_sntp/main/Kconfig.projbuild create mode 100644 examples/06_sntp/main/component.mk create mode 100644 examples/06_sntp/main/sntp_main.c diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 928b190321..65cac4ee9f 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -324,7 +324,7 @@ choice ESP32_TIME_SYSCALL default ESP32_TIME_SYSCALL_USE_RTC_FRC1 help This setting defines which hardware timers are used to - implement 'gettimeofday' function in C library. + implement 'gettimeofday' and 'time' functions in C library. - If only FRC1 timer is used, gettimeofday will provide time at microsecond resolution. Time will not be preserved when going @@ -336,8 +336,8 @@ choice ESP32_TIME_SYSCALL deep sleep, but time will be measured at 6.(6) microsecond resolution. Also the gettimeofday function itself may take longer to run. - - If no timers are used, gettimeofday function return -1 and - set errno to ENOSYS. + - If no timers are used, gettimeofday and time functions + return -1 and set errno to ENOSYS. config ESP32_TIME_SYSCALL_USE_RTC bool "RTC" diff --git a/components/lwip/Kconfig b/components/lwip/Kconfig index 15c94c66ba..801fa0b51c 100644 --- a/components/lwip/Kconfig +++ b/components/lwip/Kconfig @@ -24,6 +24,15 @@ config LWIP_SO_REUSE Enabling this option allows binding to a port which remains in TIME_WAIT. +config LWIP_DHCP_MAX_NTP_SERVERS + int "Maximum number of NTP servers" + default 1 + range 1 16 + help + Set maxumum number of NTP servers used by LwIP SNTP module. + First argument of sntp_setserver/sntp_setservername functions + is limited to this value. + endmenu diff --git a/components/lwip/include/lwip/port/lwipopts.h b/components/lwip/include/lwip/port/lwipopts.h index b970ae5539..f705887508 100755 --- a/components/lwip/include/lwip/port/lwipopts.h +++ b/components/lwip/include/lwip/port/lwipopts.h @@ -33,6 +33,8 @@ #define __LWIPOPTS_H__ #include +#include +#include #include "esp_task.h" #include "sdkconfig.h" @@ -552,7 +554,22 @@ extern unsigned char misc_prof_get_tcp_snd_buf(void); #define LWIP_NETCONN_FULLDUPLEX 1 #define LWIP_NETCONN_SEM_PER_THREAD 1 +#define LWIP_DHCP_MAX_NTP_SERVERS CONFIG_LWIP_DHCP_MAX_NTP_SERVERS +#define LWIP_TIMEVAL_PRIVATE 0 +#define SNTP_SET_SYSTEM_TIME_US(sec, us) \ + do { \ + struct timeval tv = { .tv_sec = sec, .tv_usec = us }; \ + settimeofday(&tv, NULL); \ + } while (0); + +#define SNTP_GET_SYSTEM_TIME(sec, us) \ + do { \ + struct timeval tv = { .tv_sec = 0, .tv_usec = 0 }; \ + gettimeofday(&tv, NULL); \ + (sec) = tv.tv_sec; \ + (us) = tv.tv_usec; \ + } while (0); #define SOC_SEND_LOG //printf diff --git a/components/newlib/time.c b/components/newlib/time.c index 83645aa4cc..5f60e1d7b2 100644 --- a/components/newlib/time.c +++ b/components/newlib/time.c @@ -20,6 +20,7 @@ #include #include #include +#include #include "esp_attr.h" #include "soc/soc.h" #include "soc/rtc_cntl_reg.h" @@ -54,6 +55,15 @@ static uint64_t get_rtc_time_us() #endif // WITH_RTC +// time from Epoch to the first boot time +#ifdef WITH_RTC +static RTC_DATA_ATTR struct timeval s_boot_time; +#else +static struct timeval s_boot_time; +#endif +static _lock_t s_boot_time_lock; + + #ifdef WITH_FRC1 #define FRC1_PRESCALER 16 #define FRC1_PRESCALER_CTL 2 @@ -83,7 +93,6 @@ void esp_setup_time_syscalls() s_microseconds = get_rtc_time_us(); #endif //WITH_RTC - // set up timer WRITE_PERI_REG(FRC_TIMER_CTRL_REG(0), \ FRC_TIMER_AUTOLOAD | \ @@ -112,12 +121,12 @@ clock_t IRAM_ATTR _times_r(struct _reent *r, struct tms *ptms) return (clock_t) tv.tv_sec; } -int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) +static uint64_t get_time_since_boot() { - (void) tz; + uint64_t microseconds = 0; #ifdef WITH_FRC1 uint32_t timer_ticks_before = READ_PERI_REG(FRC_TIMER_COUNT_REG(0)); - uint64_t microseconds = s_microseconds; + microseconds = s_microseconds; uint32_t timer_ticks_after = READ_PERI_REG(FRC_TIMER_COUNT_REG(0)); if (timer_ticks_after > timer_ticks_before) { // overflow happened at some point between getting @@ -127,13 +136,22 @@ int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) } microseconds += (FRC_TIMER_LOAD_VALUE(0) - timer_ticks_after) / FRC1_TICKS_PER_US; #elif defined(WITH_RTC) - uint64_t microseconds = get_rtc_time_us(); + microseconds = get_rtc_time_us(); #endif + return microseconds; +} +int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) +{ + (void) tz; #if defined( WITH_FRC1 ) || defined( WITH_RTC ) + uint64_t microseconds = get_time_since_boot(); if (tv) { - tv->tv_sec = microseconds / 1000000; + _lock_acquire(&s_boot_time_lock); + microseconds += s_boot_time.tv_usec; + tv->tv_sec = s_boot_time.tv_sec + microseconds / 1000000; tv->tv_usec = microseconds % 1000000; + _lock_release(&s_boot_time_lock); } return 0; #else @@ -141,3 +159,24 @@ int IRAM_ATTR _gettimeofday_r(struct _reent *r, struct timeval *tv, void *tz) return -1; #endif // defined( WITH_FRC1 ) || defined( WITH_RTC ) } + +int settimeofday(const struct timeval *tv, const struct timezone *tz) +{ + (void) tz; +#if defined( WITH_FRC1 ) || defined( WITH_RTC ) + if (tv) { + _lock_acquire(&s_boot_time_lock); + uint64_t now = ((uint64_t) tv->tv_sec) * 1000000LL + tv->tv_usec; + uint64_t since_boot = get_time_since_boot(); + uint64_t boot_time = now - since_boot; + + s_boot_time.tv_sec = boot_time / 1000000; + s_boot_time.tv_usec = boot_time % 1000000; + _lock_release(&s_boot_time_lock); + } + return 0; +#else + __errno_r(r) = ENOSYS; + return -1; +#endif +} diff --git a/examples/06_sntp/Makefile b/examples/06_sntp/Makefile new file mode 100644 index 0000000000..e6ef17be14 --- /dev/null +++ b/examples/06_sntp/Makefile @@ -0,0 +1,9 @@ +# +# This is a project Makefile. It is assumed the directory this Makefile resides in is a +# project subdirectory. +# + +PROJECT_NAME := sntp + +include $(IDF_PATH)/make/project.mk + diff --git a/examples/06_sntp/README.md b/examples/06_sntp/README.md new file mode 100644 index 0000000000..c5a153bbb2 --- /dev/null +++ b/examples/06_sntp/README.md @@ -0,0 +1,41 @@ +# Example: using LwIP SNTP module and time functions + +This example demonstrates the use of LwIP SNTP module to obtain time from Internet servers. See the README.md file in the upper level 'examples' directory for more information about examples. + +## Obtaining time using LwIP SNTP module + +When this example boots first time after ESP32 is reset, it connects to WiFi and obtains time using SNTP. +See `initialize_sntp` function for details. + +## Timekeeping + +Once time is synchronized, ESP32 will perform timekeeping using built-in timers. + +- RTC clock is used to maintain accurate time when chip is in deep sleep mode + +- FRC1 timer is used to provide time at microsecond accuracy when ESP32 is running. + +Timekeeping using RTC timer is demonstrated in this example by going into deep sleep mode. After wake up, ESP32 will print current time without connecting to WiFi. + +To use this functionality, make sure "Timers used for gettimeofday function" option in "ESP32-specific config" menu of menuconfig is set to "RTC and FRC1" or "RTC". + +## Working with time + +To get current time, [`gettimeofday`](http://man7.org/linux/man-pages/man2/gettimeofday.2.html) function may be used. Additionally the following [standard C library functions](http://en.cppreference.com/w/cpp/header/ctime) can be used to obtain time and manipulate it: + + gettimeofday + time + asctime + clock + ctime + difftime + gmtime + localtime + mktime + strftime + +To set time, [`settimeofday`](http://man7.org/linux/man-pages/man2/settimeofday.2.html) POSIX function can be used. It is used internally in LwIP SNTP library to set current time when response from NTP server is received. + +## Timezones + +To set local timezone, use [`setenv`](http://man7.org/linux/man-pages/man3/setenv.3.html) and [`tzset`](http://man7.org/linux/man-pages/man3/tzset.3.html) POSIX functions. First, call `setenv` to set `TZ` environment variable to the correct value depending on device location. Format of the time string is described in [libc documentation](https://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html). Next, call `tzset` to update C library runtime data for the new time zone. Once these steps are done, `localtime` function will return correct local time, taking time zone offset and daylight saving time into account. diff --git a/examples/06_sntp/main/Kconfig.projbuild b/examples/06_sntp/main/Kconfig.projbuild new file mode 100644 index 0000000000..c5d5523a9f --- /dev/null +++ b/examples/06_sntp/main/Kconfig.projbuild @@ -0,0 +1,17 @@ +menu "Example Configuration" + +config WIFI_SSID + string "WiFi SSID" + default "myssid" + help + SSID (network name) for the example to connect to. + +config WIFI_PASSWORD + string "WiFi Password" + default "myssid" + help + WiFi password (WPA or WPA2) for the example to use. + + Can be left blank if the network has no security set. + +endmenu \ No newline at end of file diff --git a/examples/06_sntp/main/component.mk b/examples/06_sntp/main/component.mk new file mode 100644 index 0000000000..24356f23ed --- /dev/null +++ b/examples/06_sntp/main/component.mk @@ -0,0 +1,10 @@ +# +# Main Makefile. This is basically the same as a component makefile. +# +# This Makefile should, at the very least, just include $(SDK_PATH)/make/component_common.mk. By default, +# this 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. +# + +include $(IDF_PATH)/make/component_common.mk diff --git a/examples/06_sntp/main/sntp_main.c b/examples/06_sntp/main/sntp_main.c new file mode 100644 index 0000000000..7f516625e3 --- /dev/null +++ b/examples/06_sntp/main/sntp_main.c @@ -0,0 +1,163 @@ +/* LwIP SNTP example + + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/event_groups.h" +#include "esp_system.h" +#include "esp_wifi.h" +#include "esp_event_loop.h" +#include "esp_log.h" +#include "esp_attr.h" +#include "esp_deepsleep.h" +#include "nvs_flash.h" + +#include "lwip/err.h" +#include "apps/sntp/sntp.h" + +/* The examples use simple WiFi configuration that you can set via + 'make menuconfig'. + + If you'd rather not, just change the below entries to strings with + the config you want - ie #define EXAMPLE_WIFI_SSID "mywifissid" +*/ +#define EXAMPLE_WIFI_SSID CONFIG_WIFI_SSID +#define EXAMPLE_WIFI_PASS CONFIG_WIFI_PASSWORD + +/* FreeRTOS event group to signal when we are connected & ready to make a request */ +static EventGroupHandle_t wifi_event_group; + +/* The event group allows multiple bits for each event, + but we only care about one event - are we connected + to the AP with an IP? */ +const int CONNECTED_BIT = BIT0; + +static const char *TAG = "example"; + +/* Variable holding number of times ESP32 restarted since first boot. + * It is placed into RTC memory using RTC_DATA_ATTR and + * maintains its value when ESP32 wakes from deep sleep. + */ +RTC_DATA_ATTR static int boot_count = 0; + +static void obtain_time(void); +static void initialize_sntp(void); +static void initialise_wifi(void); +static esp_err_t event_handler(void *ctx, system_event_t *event); + + +void app_main() +{ + ++boot_count; + ESP_LOGI(TAG, "Boot count: %d", boot_count); + + time_t now; + struct tm timeinfo; + time(&now); + localtime_r(&now, &timeinfo); + // Is time set? If not, tm_year will be (1970 - 1900). + if (timeinfo.tm_year < (2016 - 1900)) { + ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP."); + obtain_time(); + // update 'now' variable with current time + time(&now); + } + char strftime_buf[64]; + + // Set timezone to Eastern Standard Time and print local time + setenv("TZ", "EST5EDT,M3.2.0/2,M11.1.0", 1); + tzset(); + localtime_r(&now, &timeinfo); + strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); + ESP_LOGI(TAG, "The current date/time in New York is: %s", strftime_buf); + + // Set timezone to China Standard Time + setenv("TZ", "CST-8CDT-9,M4.2.0/2,M9.2.0/3", 1); + tzset(); + localtime_r(&now, &timeinfo); + strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo); + ESP_LOGI(TAG, "The current date/time in Shanghai is: %s", strftime_buf); + + const int deep_sleep_sec = 10; + ESP_LOGI(TAG, "Entering deep sleep for %d seconds", deep_sleep_sec); + system_deep_sleep(1000000LL * deep_sleep_sec); +} + +static void obtain_time(void) +{ + nvs_flash_init(); + system_init(); + initialise_wifi(); + xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, + false, true, portMAX_DELAY); + initialize_sntp(); + + // wait for time to be set + time_t now = 0; + struct tm timeinfo = { 0 }; + int retry = 0; + const int retry_count = 10; + while(timeinfo.tm_year < (2016 - 1900) && ++retry < retry_count) { + ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count); + vTaskDelay(2000 / portTICK_PERIOD_MS); + time(&now); + localtime_r(&now, &timeinfo); + } +} + +static void initialize_sntp(void) +{ + ESP_LOGI(TAG, "Initializing SNTP"); + sntp_setoperatingmode(SNTP_OPMODE_POLL); + sntp_setservername(0, "pool.ntp.org"); + sntp_init(); +} + +static void initialise_wifi(void) +{ + tcpip_adapter_init(); + wifi_event_group = xEventGroupCreate(); + ESP_ERROR_CHECK( esp_event_loop_init(event_handler, NULL) ); + wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); + ESP_ERROR_CHECK( esp_wifi_init(&cfg) ); + ESP_ERROR_CHECK( esp_wifi_set_storage(WIFI_STORAGE_RAM) ); + wifi_config_t wifi_config = { + .sta = { + .ssid = EXAMPLE_WIFI_SSID, + .password = EXAMPLE_WIFI_PASS, + }, + }; + ESP_LOGI(TAG, "Setting WiFi configuration SSID %s...", wifi_config.sta.ssid); + ESP_ERROR_CHECK( esp_wifi_set_mode(WIFI_MODE_STA) ); + ESP_ERROR_CHECK( esp_wifi_set_config(WIFI_IF_STA, &wifi_config) ); + ESP_ERROR_CHECK( esp_wifi_start() ); +} + +static esp_err_t event_handler(void *ctx, system_event_t *event) +{ + switch(event->event_id) { + case SYSTEM_EVENT_STA_START: + esp_wifi_connect(); + break; + case SYSTEM_EVENT_STA_GOT_IP: + xEventGroupSetBits(wifi_event_group, CONNECTED_BIT); + break; + case SYSTEM_EVENT_STA_DISCONNECTED: + /* This is a workaround as ESP32 WiFi libs don't currently + auto-reassociate. */ + esp_wifi_connect(); + xEventGroupClearBits(wifi_event_group, CONNECTED_BIT); + break; + default: + break; + } + return ESP_OK; +} From 299655e3be68212bd2317cce9c1d8f11bb6ffbf7 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 3 Nov 2016 14:49:05 +0800 Subject: [PATCH 94/95] esp32: add choice for RTC clock source For now only one option is supported: internal RC oscillator --- components/esp32/Kconfig | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/components/esp32/Kconfig b/components/esp32/Kconfig index 65cac4ee9f..1f04cf4bb7 100644 --- a/components/esp32/Kconfig +++ b/components/esp32/Kconfig @@ -349,5 +349,19 @@ config ESP32_TIME_SYSCALL_USE_NONE bool "None" endchoice +choice ESP32_RTC_CLOCK_SOURCE + prompt "RTC clock source" + default ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC + help + Choose which clock is used as RTC clock source. + The only available option for now is to use internal + 150kHz RC oscillator. + +config ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC + bool "Internal RC" +config ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL + bool "External 32kHz crystal" + depends on DOCUMENTATION_FOR_RTC_CNTL +endchoice endmenu From bc4f1c90a7cbf8f457df9cc97dc89d2e3e8d5a85 Mon Sep 17 00:00:00 2001 From: Ivan Grokhotkov Date: Thu, 3 Nov 2016 17:44:23 +0800 Subject: [PATCH 95/95] conver tabs to spaces in frc_timer_reg.h --- components/esp32/include/soc/frc_timer_reg.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/esp32/include/soc/frc_timer_reg.h b/components/esp32/include/soc/frc_timer_reg.h index 24b942c0bb..d76199c4f3 100644 --- a/components/esp32/include/soc/frc_timer_reg.h +++ b/components/esp32/include/soc/frc_timer_reg.h @@ -23,26 +23,26 @@ #define REG_FRC_TIMER_BASE(i) (DR_REG_FRC_TIMER_BASE + i*0x20) -#define FRC_TIMER_LOAD_REG(i) (REG_FRC_TIMER_BASE(i) + 0x0) // timer load value (23 bit for i==0, 32 bit for i==1) +#define FRC_TIMER_LOAD_REG(i) (REG_FRC_TIMER_BASE(i) + 0x0) // timer load value (23 bit for i==0, 32 bit for i==1) #define FRC_TIMER_LOAD_VALUE(i) ((i == 0)?0x007FFFFF:0xffffffff) #define FRC_TIMER_LOAD_VALUE_S 0 -#define FRC_TIMER_COUNT_REG(i) (REG_FRC_TIMER_BASE(i) + 0x4) // timer count value (23 bit for i==0, 32 bit for i==1) +#define FRC_TIMER_COUNT_REG(i) (REG_FRC_TIMER_BASE(i) + 0x4) // timer count value (23 bit for i==0, 32 bit for i==1) #define FRC_TIMER_COUNT ((i == 0)?0x007FFFFF:0xffffffff) #define FRC_TIMER_COUNT_S 0 #define FRC_TIMER_CTRL_REG(i) (REG_FRC_TIMER_BASE(i) + 0x8) -#define FRC_TIMER_INT_ENABLE (BIT(8)) // enable interrupt -#define FRC_TIMER_ENABLE (BIT(7)) // enable timer -#define FRC_TIMER_AUTOLOAD (BIT(6)) // enable autoload -#define FRC_TIMER_PRESCALER 0x00000007 // 0: divide by 1, 2: divide by 16, 4: divide by 256 -#define FRC_TIMER_PRESCALER_S 1 -#define FRC_TIMER_EDGE_INT (BIT(0)) // 0: level, 1: edge +#define FRC_TIMER_INT_ENABLE (BIT(8)) // enable interrupt +#define FRC_TIMER_ENABLE (BIT(7)) // enable timer +#define FRC_TIMER_AUTOLOAD (BIT(6)) // enable autoload +#define FRC_TIMER_PRESCALER 0x00000007 // 0: divide by 1, 2: divide by 16, 4: divide by 256 +#define FRC_TIMER_PRESCALER_S 1 +#define FRC_TIMER_EDGE_INT (BIT(0)) // 0: level, 1: edge #define FRC_TIMER_INT_REG(i) (REG_FRC_TIMER_BASE(i) + 0xC) -#define FRC_TIMER_INT_CLR (BIT(0)) // clear interrupt +#define FRC_TIMER_INT_CLR (BIT(0)) // clear interrupt -#define FRC_TIMER_ALARM_REG(i) (REG_FRC_TIMER_BASE(i) + 0x10) // timer alarm value; register only present for i == 1 +#define FRC_TIMER_ALARM_REG(i) (REG_FRC_TIMER_BASE(i) + 0x10) // timer alarm value; register only present for i == 1 #define FRC_TIMER_ALARM 0xFFFFFFFF #define FRC_TIMER_ALARM_S 0