diff --git a/Makefile b/Makefile index 01b2f284..02b20deb 100644 --- a/Makefile +++ b/Makefile @@ -68,10 +68,12 @@ LIB_SOURCES = src/libhttp.c \ src/httplib_set_ssl_option.c \ src/httplib_set_sock_timeout.c \ src/httplib_set_tcp_nodelay.c \ + src/httplib_ssl_error.c \ src/httplib_ssl_get_client_cert_info.c \ src/httplib_ssl_get_protocol.c \ src/httplib_ssl_locking_callback.c \ src/httplib_ssl_use_pem_file.c \ + src/httplib_sslize.c \ src/httplib_start.c \ src/httplib_stop.c \ src/httplib_uninitialize_ssl.c \ diff --git a/src/httplib_ssl_error.c b/src/httplib_ssl_error.c new file mode 100644 index 00000000..d64b60c6 --- /dev/null +++ b/src/httplib_ssl_error.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +/* + * const char *XX_httplib_ssl_error( void ); + * + * The function XX_httplib_ssl_error() returns an error string describing the + * current error encountered in the SSL library, or an empty string if no error + * occured. + */ + +#if !defined(NO_SSL) + +const char *XX_httplib_ssl_error( void ) { + + unsigned long err; + + err = ERR_get_error(); + return ((err == 0) ? "" : ERR_error_string(err, NULL)); + +} /* XX_httplib_ssl_error */ + +#endif /* !NO_SSL */ diff --git a/src/httplib_sslize.c b/src/httplib_sslize.c new file mode 100644 index 00000000..4fe13718 --- /dev/null +++ b/src/httplib_sslize.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2016 Lammert Bies + * Copyright (c) 2013-2016 the Civetweb developers + * Copyright (c) 2004-2013 Sergey Lyubka + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + + + +#include "libhttp-private.h" + + + +/* + * int XX_httplib_sslize( struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *) ); + * + * The fucntion XX_httplib_sslize() initiates SSL on a connection. + */ + +#if !defined(NO_SSL) + +int XX_httplib_sslize( struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *) ) { + + int ret; + int err; + int short_trust; + unsigned i; + + if ( conn == NULL ) return 0; + + short_trust = (conn->ctx->config[SSL_SHORT_TRUST] != NULL) && (mg_strcasecmp(conn->ctx->config[SSL_SHORT_TRUST], "yes") == 0); + + if (short_trust) { + int trust_ret = XX_httplib_refresh_trust(conn); + if (!trust_ret) return trust_ret; + } + + conn->ssl = SSL_new(s); + if (conn->ssl == NULL) return 0; + + ret = SSL_set_fd(conn->ssl, conn->client.sock); + if (ret != 1) { + err = SSL_get_error(conn->ssl, ret); + (void)err; /* TODO: set some error message */ + SSL_free(conn->ssl); + conn->ssl = NULL; + /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion: + * https://wiki.openssl.org/index.php/Talk:Library_Initialization */ + ERR_remove_state(0); + return 0; + } + + /* SSL functions may fail and require to be called again: + * see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html + * Here "func" could be SSL_connect or SSL_accept. */ + for (i = 0; i <= 16; i *= 2) { + ret = func(conn->ssl); + if (ret != 1) { + err = SSL_get_error(conn->ssl, ret); + if ((err == SSL_ERROR_WANT_CONNECT) + || (err == SSL_ERROR_WANT_ACCEPT)) { + /* Retry */ + mg_sleep(i); + + } else break; /* This is an error. TODO: set some error message */ + + } + else break; /* Success */ + } + + if (ret != 1) { + SSL_free(conn->ssl); + conn->ssl = NULL; + /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion: + * https://wiki.openssl.org/index.php/Talk:Library_Initialization */ + ERR_remove_state(0); + return 0; + } + + return 1; + +} /* XX_httplib_sslize */ + +#endif /* !NO_SSL */ diff --git a/src/libhttp-private.h b/src/libhttp-private.h index ba98f8cf..4b66953d 100644 --- a/src/libhttp-private.h +++ b/src/libhttp-private.h @@ -852,6 +852,7 @@ void XX_httplib_process_new_connection( struct mg_connection *conn ); void XX_httplib_produce_socket( struct mg_context *ctx, const struct socket *sp ); int XX_httplib_read_request( FILE *fp, struct mg_connection *conn, char *buf, int bufsiz, int *nread ); void XX_httplib_read_websocket( struct mg_connection *conn, mg_websocket_data_handler ws_data_handler, void *callback_data ); +int XX_httplib_refresh_trust( struct mg_connection *conn ); void XX_httplib_reset_per_request_attributes( struct mg_connection *conn ); void XX_httplib_send_http_error( struct mg_connection *, int, PRINTF_FORMAT_STRING(const char *fmt), ... ) PRINTF_ARGS(3, 4); int XX_httplib_set_acl_option( struct mg_context *ctx ); diff --git a/src/libhttp.c b/src/libhttp.c index 9d3d6f94..514494a5 100644 --- a/src/libhttp.c +++ b/src/libhttp.c @@ -8426,7 +8426,7 @@ unsigned long XX_httplib_ssl_id_callback( void ) { -static int refresh_trust( struct mg_connection *conn ) { +int XX_httplib_refresh_trust( struct mg_connection *conn ) { static int reload_lock = 0; static long int data_check = 0; @@ -8478,83 +8478,10 @@ static int refresh_trust( struct mg_connection *conn ) { while (*p_reload_lock) sleep(1); return 1; -} + +} /* XX_httplib_refresh_trust */ pthread_mutex_t *XX_httplib_ssl_mutexes; - -int XX_httplib_sslize( struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *) ) { - - int ret; - int err; - int short_trust; - unsigned i; - - if ( conn == NULL ) return 0; - - short_trust = (conn->ctx->config[SSL_SHORT_TRUST] != NULL) && (mg_strcasecmp(conn->ctx->config[SSL_SHORT_TRUST], "yes") == 0); - - if (short_trust) { - int trust_ret = refresh_trust(conn); - if (!trust_ret) return trust_ret; - } - - conn->ssl = SSL_new(s); - if (conn->ssl == NULL) return 0; - - ret = SSL_set_fd(conn->ssl, conn->client.sock); - if (ret != 1) { - err = SSL_get_error(conn->ssl, ret); - (void)err; /* TODO: set some error message */ - SSL_free(conn->ssl); - conn->ssl = NULL; - /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion: - * https://wiki.openssl.org/index.php/Talk:Library_Initialization */ - ERR_remove_state(0); - return 0; - } - - /* SSL functions may fail and require to be called again: - * see https://www.openssl.org/docs/manmaster/ssl/SSL_get_error.html - * Here "func" could be SSL_connect or SSL_accept. */ - for (i = 0; i <= 16; i *= 2) { - ret = func(conn->ssl); - if (ret != 1) { - err = SSL_get_error(conn->ssl, ret); - if ((err == SSL_ERROR_WANT_CONNECT) - || (err == SSL_ERROR_WANT_ACCEPT)) { - /* Retry */ - mg_sleep(i); - - } else break; /* This is an error. TODO: set some error message */ - - } - else break; /* Success */ - } - - if (ret != 1) { - SSL_free(conn->ssl); - conn->ssl = NULL; - /* Avoid CRYPTO_cleanup_all_ex_data(); See discussion: - * https://wiki.openssl.org/index.php/Talk:Library_Initialization */ - ERR_remove_state(0); - return 0; - } - - return 1; - -} /* XX_httplib_sslize */ - - -/* Return OpenSSL error message (from CRYPTO lib) */ -const char * XX_httplib_ssl_error(void) { - - unsigned long err; - - err = ERR_get_error(); - return ((err == 0) ? "" : ERR_error_string(err, NULL)); - -} /* XX_httplib_ssl_error */ - #endif /* !NO_SSL */