From 2bbd04f10ffdbaf162fe7d9b61392d67ee6ad602 Mon Sep 17 00:00:00 2001 From: Juliusz Sosinowicz Date: Tue, 13 Jul 2021 20:37:32 +0200 Subject: [PATCH] Implement BIO_new_accept and BIO_do_accept --- configure.ac | 34 +- src/ssl.c | 714 +++++++++++++++++++++++++++++++++++++++++ src/wolfio.c | 61 ++++ tests/api.c | 71 ++++ wolfssl/openssl/bio.h | 2 + wolfssl/openssl/err.h | 2 + wolfssl/openssl/ssl.h | 2 + wolfssl/openssl/x509.h | 26 ++ wolfssl/ssl.h | 6 +- wolfssl/wolfio.h | 2 + 10 files changed, 896 insertions(+), 24 deletions(-) diff --git a/configure.ac b/configure.ac index 6ddc72125..45de6e062 100644 --- a/configure.ac +++ b/configure.ac @@ -891,6 +891,13 @@ then AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_OPENSSH -DHAVE_EX_DATA -DWOLFSSL_BASE16" fi +# net-snmp Build +AC_ARG_ENABLE([net-snmp], + [AS_HELP_STRING([--enable-net-snmp],[Enable net-snmp (default: disabled)])], + [ ENABLED_NETSNMP=$enableval ], + [ ENABLED_NETSNMP=no ] + ) + #IP alternative name Support AC_ARG_ENABLE([ip-alt-name], [AS_HELP_STRING([--enable-ip-alt-name],[Enable IP subject alternative name (default: disabled)])], @@ -958,7 +965,7 @@ AC_ARG_ENABLE([opensslall], [ ENABLED_OPENSSLALL=$enableval ], [ ENABLED_OPENSSLALL=no ] ) -if test "$ENABLED_LIBWEBSOCKETS" = "yes" || test "$ENABLED_OPENVPN" = "yes" || test "$ENABLED_WPAS_DPP" = "yes" || test "$ENABLED_SMIME" = "yes" || test "$ENABLED_HAPROXY" = "yes" || test "$ENABLED_BIND" = "yes" || test "$ENABLED_NTP" == "yes" +if test "$ENABLED_LIBWEBSOCKETS" = "yes" || test "$ENABLED_OPENVPN" = "yes" || test "$ENABLED_WPAS_DPP" = "yes" || test "$ENABLED_SMIME" = "yes" || test "$ENABLED_HAPROXY" = "yes" || test "$ENABLED_BIND" = "yes" || test "$ENABLED_NTP" == "yes" || test "$ENABLED_NETSNMP" = "yes" then ENABLED_OPENSSLALL="yes" fi @@ -1881,7 +1888,7 @@ AC_ARG_ENABLE([sessioncerts], [ ENABLED_SESSIONCERTS=no ] ) -if test "x$ENABLED_NGINX" = "xyes" || test "x$ENABLED_OPENVPN" = "xyes" || test "x$ENABLED_LIGHTY" = "xyes" +if test "x$ENABLED_NGINX" = "xyes" || test "x$ENABLED_OPENVPN" = "xyes" || test "x$ENABLED_LIGHTY" = "xyes" || test "x$ENABLED_NETSNMP" = "xyes" then ENABLED_SESSIONCERTS=yes fi @@ -3015,7 +3022,7 @@ AC_ARG_ENABLE([des3], [ ENABLED_DES3=no ] ) -if test "$ENABLED_OPENSSH" = "yes" || test "$ENABLED_QT" = "yes" || test "$ENABLED_OPENVPN" = "yes" || test "x$ENABLED_WPAS" != "xno" || test "$ENABLED_LIBSSH2" = "yes" +if test "$ENABLED_OPENSSH" = "yes" || test "$ENABLED_QT" = "yes" || test "$ENABLED_OPENVPN" = "yes" || test "x$ENABLED_WPAS" != "xno" || test "$ENABLED_NETSNMP" = "yes" || test "$ENABLED_LIBSSH2" = "yes" then ENABLED_DES3="yes" fi @@ -3122,14 +3129,6 @@ AC_ARG_ENABLE([xts], AS_IF([test "x$ENABLED_XTS" = "xyes"], [AM_CFLAGS="$AM_CFLAGS -DWOLFSSL_AES_XTS -DWOLFSSL_AES_DIRECT"]) - - -# Web Server Build -AC_ARG_ENABLE([net-snmp], - [AS_HELP_STRING([--enable-net-snmp],[Enable net-snmp (default: disabled)])], - [ ENABLED_NETSNMP=$enableval ], - [ ENABLED_NETSNMP=no ] - ) # Web Server Build AC_ARG_ENABLE([webserver], @@ -3533,7 +3532,7 @@ AC_ARG_ENABLE([crl], ) -if test "x$ENABLED_NGINX" = "xyes" || test "x$ENABLED_HAPROXY" = "xyes" || test "x$ENABLED_OPENVPN" = "xyes" || test "x$ENABLED_WPAS" != "xno" || test "x$ENABLED_LIGHTY" = "xyes" +if test "x$ENABLED_NGINX" = "xyes" || test "x$ENABLED_HAPROXY" = "xyes" || test "x$ENABLED_OPENVPN" = "xyes" || test "x$ENABLED_WPAS" != "xno" || test "x$ENABLED_LIGHTY" = "xyes" || test "x$ENABLED_NETSNMP" = "xyes" then ENABLED_CRL=yes fi @@ -4394,16 +4393,7 @@ fi if test "$ENABLED_NETSNMP" = "yes" then - if test "x$ENABLED_OPENSSLEXTRA" = "xno" - then - ENABLED_OPENSSLEXTRA="yes" - AM_CFLAGS="-DOPENSSL_EXTRA $AM_CFLAGS" - fi - - if test "x$ENABLED_DES3" = "xno" - then - ENABLED_DES3="yes" - fi + AM_CFLAGS="$AM_CFLAGS -DHAVE_EX_DATA" if test "x$ENABLED_AESCFB" = "xno" then diff --git a/src/ssl.c b/src/ssl.c index 5cb2ff162..07cfe7f34 100644 --- a/src/ssl.c +++ b/src/ssl.c @@ -16548,6 +16548,563 @@ int wolfSSL_set_compression(WOLFSSL* ssl) #endif /* !NO_CERTS && (OPENSSL_EXTRA || WOLFSSL_WPAS_SMALL) */ +#ifdef OPENSSL_EXTRA +#ifndef NO_BIO + WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_md(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_f_md"); + meth.type = WOLFSSL_BIO_MD; + + return &meth; + } + + /* return the context and initialize the BIO state */ + int wolfSSL_BIO_get_md_ctx(WOLFSSL_BIO *bio, WOLFSSL_EVP_MD_CTX **mdcp) + { + int ret = WOLFSSL_FAILURE; + + if ((bio != NULL) && (mdcp != NULL)) { + *mdcp = (WOLFSSL_EVP_MD_CTX*)bio->ptr; + ret = WOLFSSL_SUCCESS; + } + + return ret; + } + + WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_buffer(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("BIO_f_buffer"); + meth.type = WOLFSSL_BIO_BUFFER; + + return &meth; + } + + #ifndef NO_WOLFSSL_STUB + long wolfSSL_BIO_set_write_buffer_size(WOLFSSL_BIO* bio, long size) + { + /* wolfSSL has internal buffer, compatibility only */ + WOLFSSL_ENTER("BIO_set_write_buffer_size"); + WOLFSSL_MSG("Buffer resize failed"); + WOLFSSL_STUB("BIO_set_write_buffer_size"); + (void)bio; + (void) size; + + /* Even though this is only a STUB at the moment many user applications + * may attempt to use this. OpenSSL documentation specifies the return + * "return 1 if the buffer was successfully resized or 0 for failure." + * since wolfSSL does not resize the buffer will always return failure + * by default due to memory concerns until this stub is promoted to + * a non-stub function */ + return WOLFSSL_FAILURE; /* 0, no resize happened */ + } + #endif + + WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_bio(void) + { + static WOLFSSL_BIO_METHOD bio_meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_bio"); + bio_meth.type = WOLFSSL_BIO_BIO; + + return &bio_meth; + } + + +#ifndef NO_FILESYSTEM + WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_file(void) + { + static WOLFSSL_BIO_METHOD file_meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_file"); + file_meth.type = WOLFSSL_BIO_FILE; + + return &file_meth; + } +#endif + + + WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_ssl(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_f_ssl"); + meth.type = WOLFSSL_BIO_SSL; + + return &meth; + } + + + WOLFSSL_BIO_METHOD *wolfSSL_BIO_s_socket(void) + { + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_socket"); + meth.type = WOLFSSL_BIO_SOCKET; + + return &meth; + } + + + WOLFSSL_BIO* wolfSSL_BIO_new_socket(int sfd, int closeF) + { + WOLFSSL_BIO* bio = wolfSSL_BIO_new(wolfSSL_BIO_s_socket()); + + WOLFSSL_ENTER("BIO_new_socket"); + if (bio) { + bio->type = WOLFSSL_BIO_SOCKET; + bio->shutdown = (byte)closeF; + bio->num = sfd; + } + return bio; + } + + /** + * Create new socket BIO object. This is a pure TCP connection with + * no SSL or TLS protection. + * @param str IP address to connect to + * @return New BIO object or NULL on failure + */ + WOLFSSL_BIO *wolfSSL_BIO_new_connect(const char *str) + { + WOLFSSL_BIO *bio; + const char* port; + WOLFSSL_ENTER("wolfSSL_BIO_new_connect"); + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_socket()); + if (bio) { + port = XSTRSTR(str, ":"); + + if (port != NULL) + bio->port = XATOI(port + 1); + else + port = str + XSTRLEN(str); /* point to null terminator */ + + bio->ip = (char*)XMALLOC(1 + port - str, bio->heap, + DYNAMIC_TYPE_OPENSSL); + XMEMCPY(bio->ip, str, port - str); + bio->ip[port - str] = '\0'; + bio->type = WOLFSSL_BIO_SOCKET; + } + return bio; + } + + /** + * Create new socket BIO object. This is a pure TCP connection with + * no SSL or TLS protection. + * @param str IP address to connect to + * @return New BIO object or NULL on failure + */ + WOLFSSL_BIO *wolfSSL_BIO_new_accept(const char *port) + { + WOLFSSL_BIO *bio; + WOLFSSL_ENTER("wolfSSL_BIO_new_accept"); + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_socket()); + if (bio) { + bio->port = XATOI(port); + bio->type = WOLFSSL_BIO_SOCKET; + } + return bio; + } + + /** + * Set the port to connect to in the BIO object + * @param b BIO object + * @param port destination port + * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure + */ + long wolfSSL_BIO_set_conn_port(WOLFSSL_BIO *b, char* port) + { + int p; + WOLFSSL_ENTER("wolfSSL_BIO_set_conn_port"); + + if (!b || !port) { + WOLFSSL_ENTER("Bad parameter"); + return WOLFSSL_FAILURE; + } + + p = XATOI(port); + if (!p || p < 0) { + WOLFSSL_ENTER("Port parsing error"); + return WOLFSSL_FAILURE; + } + + b->port = (word16)p; + return WOLFSSL_SUCCESS; + } + +#ifdef HAVE_HTTP_CLIENT + /** + * Attempt to connect to the destination address and port + * @param b BIO object + * @return WOLFSSL_SUCCESS on success and WOLFSSL_FAILURE on failure + */ + long wolfSSL_BIO_do_connect(WOLFSSL_BIO *b) + { + SOCKET_T sfd = SOCKET_INVALID; + WOLFSSL_ENTER("wolfSSL_BIO_do_connect"); + + if (!b) { + WOLFSSL_ENTER("Bad parameter"); + return WOLFSSL_FAILURE; + } + + while (b && b->type != WOLFSSL_BIO_SOCKET) + b = b->next; + + if (!b) { + WOLFSSL_ENTER("No socket BIO in chain"); + return WOLFSSL_FAILURE; + } + + if (wolfIO_TcpConnect(&sfd, b->ip, b->port, 0) < 0 ) { + WOLFSSL_ENTER("wolfIO_TcpConnect error"); + return WOLFSSL_FAILURE; + } + + b->num = sfd; + b->shutdown = BIO_CLOSE; + return WOLFSSL_SUCCESS; + } + + int wolfSSL_BIO_do_accept(WOLFSSL_BIO *b) + { + SOCKET_T sfd = SOCKET_INVALID; + WOLFSSL_ENTER("wolfSSL_BIO_do_accept"); + + if (!b) { + WOLFSSL_ENTER("Bad parameter"); + return WOLFSSL_FAILURE; + } + + while (b && b->type != WOLFSSL_BIO_SOCKET) + b = b->next; + + if (!b) { + WOLFSSL_ENTER("No socket BIO in chain"); + return WOLFSSL_FAILURE; + } + + if (b->num == SOCKET_INVALID) { + if (wolfIO_TcpBind(&sfd, b->port) < 0) { + WOLFSSL_ENTER("wolfIO_TcpBind error"); + return WOLFSSL_FAILURE; + } + b->num = sfd; + b->shutdown = BIO_CLOSE; + } + else { + WOLFSSL_BIO* new_bio; + int newfd = wolfIO_TcpAccept(b->num, NULL, NULL); + if (newfd < 0) { + WOLFSSL_ENTER("wolfIO_TcpBind error"); + return WOLFSSL_FAILURE; + } + /* Create a socket BIO for using the accept'ed connection */ + new_bio = wolfSSL_BIO_new_socket(newfd, BIO_CLOSE); + if (new_bio == NULL) { + WOLFSSL_ENTER("wolfSSL_BIO_new_socket error"); + CloseSocket(newfd); + return WOLFSSL_FAILURE; + } + wolfSSL_BIO_set_callback(new_bio, + wolfSSL_BIO_get_callback(b)); + wolfSSL_BIO_set_callback_arg(new_bio, + wolfSSL_BIO_get_callback_arg(b)); + /* Push onto bio chain for user retrieval */ + if (wolfSSL_BIO_push(b, new_bio) == NULL) { + WOLFSSL_ENTER("wolfSSL_BIO_push error"); + CloseSocket(newfd); + return WOLFSSL_FAILURE; + } + } + + return WOLFSSL_SUCCESS; + } +#endif /* HAVE_HTTP_CLIENT */ + + int wolfSSL_BIO_eof(WOLFSSL_BIO* b) + { + WOLFSSL_ENTER("BIO_eof"); + if ((b != NULL) && (b->eof)) + return 1; + + return 0; + } + + long wolfSSL_BIO_do_handshake(WOLFSSL_BIO *b) + { + WOLFSSL_ENTER("wolfSSL_BIO_do_handshake"); + if (b == NULL) { + WOLFSSL_MSG("Bad parameter"); + return WOLFSSL_FAILURE; + } + if (b->type == WOLFSSL_BIO_SSL && b->ptr != NULL) { + return wolfSSL_negotiate((WOLFSSL*)b->ptr); + } + else { + WOLFSSL_MSG("Not SSL BIO or no SSL object set"); + return WOLFSSL_FAILURE; + } + } + + long wolfSSL_BIO_set_ssl(WOLFSSL_BIO* b, WOLFSSL* ssl, int closeF) + { + long ret = WOLFSSL_FAILURE; + + WOLFSSL_ENTER("wolfSSL_BIO_set_ssl"); + + if (b != NULL) { + b->ptr = ssl; + b->shutdown = (byte)closeF; + if (b->next != NULL) + wolfSSL_set_bio(ssl, b->next, b->next); + /* add to ssl for bio free if SSL_free called before/instead of free_all? */ + ret = WOLFSSL_SUCCESS; + } + + return ret; + } + +#ifndef NO_FILESYSTEM + long wolfSSL_BIO_set_fd(WOLFSSL_BIO* b, int fd, int closeF) + { + WOLFSSL_ENTER("wolfSSL_BIO_set_fd"); + + if (b != NULL) { + b->num = fd; + b->shutdown = (byte)closeF; + } + + return WOLFSSL_SUCCESS; + } +#endif + + /* Sets the close flag */ + int wolfSSL_BIO_set_close(WOLFSSL_BIO *b, long flag) + { + WOLFSSL_ENTER("wolfSSL_BIO_set_close"); + if (b != NULL) { + b->shutdown = (byte)flag; + } + + return WOLFSSL_SUCCESS; + } + +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L + WOLFSSL_BIO* wolfSSL_BIO_new(const WOLFSSL_BIO_METHOD* method) +#else + WOLFSSL_BIO* wolfSSL_BIO_new(WOLFSSL_BIO_METHOD* method) +#endif + { + WOLFSSL_BIO* bio; + + WOLFSSL_ENTER("wolfSSL_BIO_new"); + if (method == NULL) { + WOLFSSL_MSG("Bad method pointer passed in"); + return NULL; + } + + bio = (WOLFSSL_BIO*) XMALLOC(sizeof(WOLFSSL_BIO), 0, + DYNAMIC_TYPE_OPENSSL); + if (bio) { + XMEMSET(bio, 0, sizeof(WOLFSSL_BIO)); + bio->type = (byte)method->type; +#if defined(OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER >= 0x10100000L + bio->method = (WOLFSSL_BIO_METHOD*)method; +#else + bio->method = method; +#endif + bio->shutdown = BIO_CLOSE; /* default to close things */ + bio->num = SOCKET_INVALID; /* Default to invalid socket */ + bio->init = 1; + if (method->type != WOLFSSL_BIO_FILE && + method->type != WOLFSSL_BIO_SOCKET && + method->type != WOLFSSL_BIO_MD) { + bio->mem_buf =(WOLFSSL_BUF_MEM*)XMALLOC(sizeof(WOLFSSL_BUF_MEM), + 0, DYNAMIC_TYPE_OPENSSL); + if (bio->mem_buf == NULL) { + WOLFSSL_MSG("Memory error"); + wolfSSL_BIO_free(bio); + return NULL; + } + bio->mem_buf->data = (char*)bio->ptr; + } + + if (method->type == WOLFSSL_BIO_MD) { + bio->ptr = wolfSSL_EVP_MD_CTX_new(); + if (bio->ptr == NULL) { + WOLFSSL_MSG("Memory error"); + wolfSSL_BIO_free(bio); + return NULL; + } + } + + /* check if is custom method */ + if (method->createCb) { + method->createCb(bio); + } + } + return bio; + } + + WOLFSSL_BIO* wolfSSL_BIO_new_mem_buf(const void* buf, int len) + { + WOLFSSL_BIO* bio = NULL; + + if (buf == NULL) { + return bio; + } + + bio = wolfSSL_BIO_new(wolfSSL_BIO_s_mem()); + if (bio == NULL) { + return bio; + } + + if (len < 0) { + /* The length of the string including terminating null. */ + len = (int)XSTRLEN((const char*)buf) + 1; + } + bio->num = bio->wrSz = len; + bio->ptr = (byte*)XMALLOC(len, 0, DYNAMIC_TYPE_OPENSSL); + if (bio->ptr == NULL) { + wolfSSL_BIO_free(bio); + return NULL; + } + if (bio->mem_buf != NULL) { + bio->mem_buf->data = (char*)bio->ptr; + bio->mem_buf->length = bio->num; + } + + XMEMCPY(bio->ptr, buf, len); + + return bio; + } + + /* + * Note : If the flag BIO_NOCLOSE is set then freeing memory buffers is up + * to the application. + * Returns 1 on success, 0 on failure + */ + int wolfSSL_BIO_free(WOLFSSL_BIO* bio) + { + int ret; + + /* unchain?, doesn't matter in goahead since from free all */ + WOLFSSL_ENTER("wolfSSL_BIO_free"); + if (bio) { +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS + wolfSSL_CRYPTO_cleanup_ex_data(&bio->ex_data); +#endif + if (bio->infoCb) { + /* info callback is called before free */ + ret = (int)bio->infoCb(bio, WOLFSSL_BIO_CB_FREE, NULL, 0, 0, 1); + if (ret <= 0) { + return ret; + } + } + + /* call custom set free callback */ + if (bio->method && bio->method->freeCb) { + bio->method->freeCb(bio); + } + + /* remove from pair by setting the paired bios pair to NULL */ + if (bio->pair != NULL) { + bio->pair->pair = NULL; + } + + if (bio->ip != NULL) { + XFREE(bio->ip, bio->heap, DYNAMIC_TYPE_OPENSSL); + } + + if (bio->shutdown) { + if (bio->type == WOLFSSL_BIO_SSL && bio->ptr) + wolfSSL_free((WOLFSSL*)bio->ptr); + #ifdef CloseSocket + if (bio->type == WOLFSSL_BIO_SOCKET && bio->num) + CloseSocket(bio->num); + #endif + } + + #ifndef NO_FILESYSTEM + if (bio->type == WOLFSSL_BIO_FILE && bio->shutdown == BIO_CLOSE) { + if (bio->ptr) { + XFCLOSE((XFILE)bio->ptr); + } + #if !defined(USE_WINDOWS_API) && !defined(NO_WOLFSSL_DIR)\ + && !defined(WOLFSSL_NUCLEUS) && !defined(WOLFSSL_NUCLEUS_1_2) + else if (bio->num != SOCKET_INVALID) { + XCLOSE(bio->num); + } + #endif + } + #endif + + if (bio->shutdown != BIO_NOCLOSE) { + if (bio->type == WOLFSSL_BIO_MEMORY && bio->ptr != NULL) { + if (bio->mem_buf != NULL) { + if (bio->mem_buf->data != (char*)bio->ptr) { + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + bio->ptr = NULL; + } + } + else { + XFREE(bio->ptr, bio->heap, DYNAMIC_TYPE_OPENSSL); + bio->ptr = NULL; + } + } + if (bio->mem_buf != NULL) { + wolfSSL_BUF_MEM_free(bio->mem_buf); + bio->mem_buf = NULL; + } + } + + if (bio->type == WOLFSSL_BIO_MD) { + wolfSSL_EVP_MD_CTX_free((WOLFSSL_EVP_MD_CTX*)bio->ptr); + } + + XFREE(bio, 0, DYNAMIC_TYPE_OPENSSL); + return WOLFSSL_SUCCESS; + } + return WOLFSSL_FAILURE; + } + + /* like BIO_free, but no return value */ + void wolfSSL_BIO_vfree(WOLFSSL_BIO* bio) + { + wolfSSL_BIO_free(bio); + } + + + void wolfSSL_BIO_free_all(WOLFSSL_BIO* bio) + { + WOLFSSL_ENTER("BIO_free_all"); + while (bio) { + WOLFSSL_BIO* next = bio->next; + wolfSSL_BIO_free(bio); + bio = next; + } + } + + + WOLFSSL_BIO* wolfSSL_BIO_push(WOLFSSL_BIO* top, WOLFSSL_BIO* append) + { + WOLFSSL_ENTER("BIO_push"); + top->next = append; + append->prev = top; + + /* SSL BIO's should use the next object in the chain for IO */ + if (top->type == WOLFSSL_BIO_SSL && top->ptr) + wolfSSL_set_bio((WOLFSSL*)top->ptr, append, append); + + return top; + } +#endif /* !NO_BIO */ +#endif /* OPENSSL_EXTRA */ + #ifdef WOLFSSL_ENCRYPTED_KEYS void wolfSSL_CTX_set_default_passwd_cb_userdata(WOLFSSL_CTX* ctx, @@ -23849,6 +24406,163 @@ void wolfSSL_MD4_Final(unsigned char* digest, WOLFSSL_MD4_CTX* md4) #endif /* NO_MD4 */ +#ifndef NO_BIO + +/* Removes a WOLFSSL_BIO struct from the WOLFSSL_BIO linked list. + * + * bio is the WOLFSSL_BIO struct in the list and removed. + * + * The return WOLFSSL_BIO struct is the next WOLFSSL_BIO in the list or NULL if + * there is none. + */ +WOLFSSL_BIO* wolfSSL_BIO_pop(WOLFSSL_BIO* bio) +{ + if (bio == NULL) { + WOLFSSL_MSG("Bad argument passed in"); + return NULL; + } + + if (bio->prev != NULL) { + bio->prev->next = bio->next; + } + + if (bio->next != NULL) { + bio->next->prev = bio->prev; + } + + return bio->next; +} + + + +WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_mem(void) +{ + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_s_mem"); + meth.type = WOLFSSL_BIO_MEMORY; + + return &meth; +} + + +WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void) +{ + static WOLFSSL_BIO_METHOD meth; + + WOLFSSL_ENTER("wolfSSL_BIO_f_base64"); + meth.type = WOLFSSL_BIO_BASE64; + + return &meth; +} + + +/* Set the flag for the bio. + * + * bio the structure to set the flag in + * flags the flag to use + */ +void wolfSSL_BIO_set_flags(WOLFSSL_BIO* bio, int flags) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_flags"); + + if (bio != NULL) { + bio->flags |= flags; + } +} + +void wolfSSL_BIO_clear_flags(WOLFSSL_BIO *bio, int flags) +{ + WOLFSSL_ENTER("wolfSSL_BIO_clear_flags"); + if (bio != NULL) { + bio->flags &= ~flags; + } +} + +/* Set ex_data for WOLFSSL_BIO + * + * bio : BIO structure to set ex_data in + * idx : Index of ex_data to set + * data : Data to set in ex_data + * + * Returns WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE on failure + */ +int wolfSSL_BIO_set_ex_data(WOLFSSL_BIO *bio, int idx, void *data) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_ex_data"); +#ifdef HAVE_EX_DATA + if (bio != NULL && idx < MAX_EX_DATA) { + return wolfSSL_CRYPTO_set_ex_data(&bio->ex_data, idx, data); + } +#else + (void)bio; + (void)idx; + (void)data; +#endif + return WOLFSSL_FAILURE; +} + +int wolfSSL_BIO_get_fd(WOLFSSL_BIO *bio, int* fd) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_fd"); + + if (bio != NULL) { + if (fd != NULL) + *fd = bio->num; + return bio->num; + } + + return SOCKET_INVALID; +} + +#ifdef HAVE_EX_DATA_CLEANUP_HOOKS +/* Set ex_data for WOLFSSL_BIO + * + * bio : BIO structure to set ex_data in + * idx : Index of ex_data to set + * data : Data to set in ex_data + * cleanup_routine : Function pointer to clean up data + * + * Returns WOLFSSL_SUCCESS on success or WOLFSSL_FAILURE on failure + */ +int wolfSSL_BIO_set_ex_data_with_cleanup( + WOLFSSL_BIO *bio, + int idx, + void *data, + wolfSSL_ex_data_cleanup_routine_t cleanup_routine) +{ + WOLFSSL_ENTER("wolfSSL_BIO_set_ex_data_with_cleanup"); + if (bio != NULL && idx < MAX_EX_DATA) { + return wolfSSL_CRYPTO_set_ex_data_with_cleanup(&bio->ex_data, idx, data, + cleanup_routine); + } + return WOLFSSL_FAILURE; +} +#endif /* HAVE_EX_DATA_CLEANUP_HOOKS */ + +/* Get ex_data in WOLFSSL_BIO at given index + * + * bio : BIO structure to get ex_data from + * idx : Index of ex_data to get data from + * + * Returns void pointer to ex_data on success or NULL on failure + */ +void *wolfSSL_BIO_get_ex_data(WOLFSSL_BIO *bio, int idx) +{ + WOLFSSL_ENTER("wolfSSL_BIO_get_ex_data"); +#ifdef HAVE_EX_DATA + if (bio != NULL && idx < MAX_EX_DATA && idx >= 0) { + return wolfSSL_CRYPTO_get_ex_data(&bio->ex_data, idx); + } +#else + (void)bio; + (void)idx; +#endif + return NULL; +} + +#endif /* !NO_BIO */ + #ifndef NO_WOLFSSL_STUB void wolfSSL_RAND_screen(void) { diff --git a/src/wolfio.c b/src/wolfio.c index 5be99ed0a..0ab1b8ac2 100644 --- a/src/wolfio.c +++ b/src/wolfio.c @@ -862,6 +862,67 @@ int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, word16 port, int to_sec) #endif /* HAVE_SOCKADDR */ } +int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port) +{ +#ifdef HAVE_SOCKADDR + SOCKADDR_S addr; + int sockaddr_len = sizeof(SOCKADDR_IN); + SOCKADDR_IN *sin = (SOCKADDR_IN *)&addr; + + if (sockfd == NULL || port < 1) { + return -1; + } + + XMEMSET(&addr, 0, sizeof(addr)); + + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = INADDR_ANY; + sin->sin_port = XHTONS(port); + *sockfd = (SOCKET_T)socket(AF_INET, SOCK_STREAM, 0); + +#if !defined(USE_WINDOWS_API) && !defined(WOLFSSL_MDK_ARM)\ + && !defined(WOLFSSL_KEIL_TCP_NET) && !defined(WOLFSSL_ZEPHYR) + { + int optval = 1; + socklen_t optlen = sizeof(optval); + if (setsockopt(*sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, optlen) < 0) { + WOLFSSL_MSG("setsockopt SO_REUSEADDR failed"); + CloseSocket(*sockfd); + *sockfd = SOCKET_INVALID; + return -1; + } + } +#endif + + if (bind(*sockfd, (SOCKADDR *)sin, sockaddr_len) != 0) { + WOLFSSL_MSG("tcp bind failed"); + CloseSocket(*sockfd); + *sockfd = SOCKET_INVALID; + return -1; + } + + if (listen(*sockfd, SOMAXCONN) != 0) { + WOLFSSL_MSG("tcp listen failed"); + CloseSocket(*sockfd); + *sockfd = SOCKET_INVALID; + return -1; + } + + return 0; +#else + (void)sockfd; + (void)port; + return -1; +#endif /* HAVE_SOCKADDR */ +} + +#ifdef HAVE_SOCKADDR +int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, socklen_t* peer_len) +{ + return accept(sockfd, peer_addr, peer_len); +} +#endif /* HAVE_SOCKADDR */ + #ifndef HTTP_SCRATCH_BUFFER_SIZE #define HTTP_SCRATCH_BUFFER_SIZE 512 #endif diff --git a/tests/api.c b/tests/api.c index 2c25ecd6c..cdecf64f4 100644 --- a/tests/api.c +++ b/tests/api.c @@ -35193,6 +35193,76 @@ static void test_wolfSSL_BIO_connect(void) #endif } +#if defined(OPENSSL_ALL) && defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_HTTP_CLIENT) +static THREAD_RETURN WOLFSSL_THREAD test_wolfSSL_BIO_accept_client(void* args) +{ + BIO* clientBio; + SSL* sslClient; + SSL_CTX* ctx; + char connectAddr[20]; /* IP + port */; + + (void)args; + + AssertIntGT(snprintf(connectAddr, sizeof(connectAddr), "%s:%d", wolfSSLIP, wolfSSLPort), 0); + AssertNotNull(clientBio = BIO_new_connect(connectAddr)); + AssertIntEQ(BIO_do_connect(clientBio), 1); + AssertNotNull(ctx = SSL_CTX_new(SSLv23_method())); + AssertNotNull(sslClient = SSL_new(ctx)); + AssertIntEQ(wolfSSL_CTX_load_verify_locations(ctx, caCertFile, 0), WOLFSSL_SUCCESS); + SSL_set_bio(sslClient, clientBio, clientBio); + AssertIntEQ(SSL_connect(sslClient), 1); + + SSL_free(sslClient); + SSL_CTX_free(ctx); + + return 0; +} +#endif + +static void test_wolfSSL_BIO_accept(void) +{ +#if defined(OPENSSL_ALL) && defined(HAVE_IO_TESTS_DEPENDENCIES) && defined(HAVE_HTTP_CLIENT) + + BIO* serverBindBio; + BIO* serverAcceptBio; + SSL* sslServer; + SSL_CTX* ctx; + func_args args; + THREAD_TYPE thread; + char port[10]; /* 10 bytes should be enough to store the string + * representation of the port */ + + printf(testingFmt, "wolfSSL_BIO_new_accept()"); + + AssertIntGT(snprintf(port, sizeof(port), "%d", wolfSSLPort), 0); + AssertNotNull(serverBindBio = BIO_new_accept(port)); + + /* First BIO_do_accept binds the port */ + AssertIntEQ(BIO_do_accept(serverBindBio), 1); + + XMEMSET(&args, 0, sizeof(func_args)); + start_thread(test_wolfSSL_BIO_accept_client, &args, &thread); + + AssertIntEQ(BIO_do_accept(serverBindBio), 1); + /* Let's plug it into SSL to test */ + AssertNotNull(ctx = SSL_CTX_new(SSLv23_method())); + AssertIntEQ(wolfSSL_CTX_use_certificate_file(ctx, svrCertFile, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + AssertIntEQ(wolfSSL_CTX_use_PrivateKey_file(ctx, svrKeyFile, SSL_FILETYPE_PEM), WOLFSSL_SUCCESS); + AssertNotNull(sslServer = SSL_new(ctx)); + AssertNotNull(serverAcceptBio = BIO_pop(serverBindBio)); + SSL_set_bio(sslServer, serverAcceptBio, serverAcceptBio); + AssertIntEQ(SSL_accept(sslServer), 1); + + join_thread(thread); + + BIO_free(serverBindBio); + SSL_free(sslServer); + SSL_CTX_free(ctx); + + printf(resultFmt, passed); +#endif +} + static void test_wolfSSL_BIO_write(void) { #if defined(OPENSSL_EXTRA) && defined(WOLFSSL_BASE64_ENCODE) @@ -46841,6 +46911,7 @@ void ApiTest(void) test_wolfSSL_d2i_PUBKEY(); test_wolfSSL_BIO_write(); test_wolfSSL_BIO_connect(); + test_wolfSSL_BIO_accept(); test_wolfSSL_BIO_printf(); test_wolfSSL_BIO_f_md(); #endif diff --git a/wolfssl/openssl/bio.h b/wolfssl/openssl/bio.h index 89ce4597f..69368e942 100644 --- a/wolfssl/openssl/bio.h +++ b/wolfssl/openssl/bio.h @@ -109,6 +109,8 @@ #define BIO_get_shutdown wolfSSL_BIO_get_shutdown #define BIO_set_shutdown wolfSSL_BIO_set_shutdown +#define BIO_get_fd wolfSSL_BIO_get_fd + #define BIO_clear_flags wolfSSL_BIO_clear_flags #define BIO_set_ex_data wolfSSL_BIO_set_ex_data #define BIO_get_ex_data wolfSSL_BIO_get_ex_data diff --git a/wolfssl/openssl/err.h b/wolfssl/openssl/err.h index 6ddf2d284..319b1872e 100644 --- a/wolfssl/openssl/err.h +++ b/wolfssl/openssl/err.h @@ -37,6 +37,8 @@ #define RSA_R_UNKNOWN_PADDING_TYPE RSA_PAD_E #define EC_R_BUFFER_TOO_SMALL BUFFER_E +#define ERR_TXT_MALLOCED 1 + /* SSL function codes */ #define RSA_F_RSA_OSSL_PRIVATE_ENCRYPT 1 #define SSL_F_SSL_CTX_USE_CERTIFICATE_FILE 2 diff --git a/wolfssl/openssl/ssl.h b/wolfssl/openssl/ssl.h index 0c0e73418..7ac9dea0b 100644 --- a/wolfssl/openssl/ssl.h +++ b/wolfssl/openssl/ssl.h @@ -715,8 +715,10 @@ wolfSSL_X509_STORE_set_verify_cb((WOLFSSL_X509_STORE *)(s), (WOLFSSL_X509_STORE_ #define BIO_f_ssl wolfSSL_BIO_f_ssl #define BIO_new_socket wolfSSL_BIO_new_socket #define BIO_new_connect wolfSSL_BIO_new_connect +#define BIO_new_accept wolfSSL_BIO_new_accept #define BIO_set_conn_port wolfSSL_BIO_set_conn_port #define BIO_do_connect wolfSSL_BIO_do_connect +#define BIO_do_accept wolfSSL_BIO_do_accept #define BIO_do_handshake wolfSSL_BIO_do_handshake #define SSL_set_bio wolfSSL_set_bio #define BIO_set_ssl wolfSSL_BIO_set_ssl diff --git a/wolfssl/openssl/x509.h b/wolfssl/openssl/x509.h index bf7ae25e3..a4ab4eace 100644 --- a/wolfssl/openssl/x509.h +++ b/wolfssl/openssl/x509.h @@ -1,5 +1,29 @@ +/* x509.h + * + * Copyright (C) 2006-2021 wolfSSL Inc. + * + * This file is part of wolfSSL. + * + * wolfSSL is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * wolfSSL is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + /* x509.h for openssl */ +#ifndef WOLFSSL_OPENSSL_509_H_ +#define WOLFSSL_OPENSSL_509_H_ + #include #include #include @@ -42,3 +66,5 @@ #define XN_FLAG_FN_ALIGN (1 << 25) #define XN_FLAG_MULTILINE 0xFFFF + +#endif /* WOLFSSL_OPENSSL_509_H_ */ diff --git a/wolfssl/ssl.h b/wolfssl/ssl.h index ef9c9dd49..d5127e784 100644 --- a/wolfssl/ssl.h +++ b/wolfssl/ssl.h @@ -422,7 +422,6 @@ struct WOLFSSL_X509_PUBKEY { int pubKeyOID; }; - enum BIO_TYPE { WOLFSSL_BIO_BUFFER = 1, WOLFSSL_BIO_SOCKET = 2, @@ -500,7 +499,7 @@ struct WOLFSSL_BIO { void* heap; /* user heap hint */ void* ptr; /* WOLFSSL, file descriptor, MD, or mem buf */ void* usrCtx; /* user set pointer */ - const char* ip; /* IP address for wolfIO_TcpConnect */ + char* ip; /* IP address for wolfIO_TcpConnect */ word16 port; /* Port for wolfIO_TcpConnect */ char* infoArg; /* BIO callback argument */ wolf_bio_info_cb infoCb; /* BIO callback */ @@ -1444,6 +1443,7 @@ WOLFSSL_API WOLFSSL_BIO_METHOD* wolfSSL_BIO_s_mem(void); WOLFSSL_API WOLFSSL_BIO_METHOD* wolfSSL_BIO_f_base64(void); WOLFSSL_API void wolfSSL_BIO_set_flags(WOLFSSL_BIO*, int); WOLFSSL_API void wolfSSL_BIO_clear_flags(WOLFSSL_BIO *bio, int flags); +WOLFSSL_API int wolfSSL_BIO_get_fd(WOLFSSL_BIO *bio, int* fd); WOLFSSL_API int wolfSSL_BIO_set_ex_data(WOLFSSL_BIO *bio, int idx, void *data); #ifdef HAVE_EX_DATA_CLEANUP_HOOKS WOLFSSL_API int wolfSSL_BIO_set_ex_data_with_cleanup( @@ -1492,8 +1492,10 @@ WOLFSSL_API WOLFSSL_BIO_METHOD *wolfSSL_BIO_s_bio(void); WOLFSSL_API WOLFSSL_BIO_METHOD *wolfSSL_BIO_s_socket(void); WOLFSSL_API WOLFSSL_BIO *wolfSSL_BIO_new_connect(const char *str); +WOLFSSL_API WOLFSSL_BIO *wolfSSL_BIO_new_accept(const char *port); WOLFSSL_API long wolfSSL_BIO_set_conn_port(WOLFSSL_BIO *b, char* port); WOLFSSL_API long wolfSSL_BIO_do_connect(WOLFSSL_BIO *b); +WOLFSSL_API int wolfSSL_BIO_do_accept(WOLFSSL_BIO *b); WOLFSSL_API long wolfSSL_BIO_do_handshake(WOLFSSL_BIO *b); diff --git a/wolfssl/wolfio.h b/wolfssl/wolfio.h index a233b6322..9ab060d05 100644 --- a/wolfssl/wolfio.h +++ b/wolfssl/wolfio.h @@ -373,6 +373,8 @@ #endif WOLFSSL_API int wolfIO_TcpConnect(SOCKET_T* sockfd, const char* ip, unsigned short port, int to_sec); +WOLFSSL_API int wolfIO_TcpAccept(SOCKET_T sockfd, SOCKADDR* peer_addr, socklen_t* peer_len); +WOLFSSL_API int wolfIO_TcpBind(SOCKET_T* sockfd, word16 port); WOLFSSL_API int wolfIO_Send(SOCKET_T sd, char *buf, int sz, int wrFlags); WOLFSSL_API int wolfIO_Recv(SOCKET_T sd, char *buf, int sz, int rdFlags);