Bug fixes and socket improvements
Added the ability to disable certificate verification for SSL sockets which is useful for testing. Added the ability to specify maximum HTTP request header/body sizes in the CMake build config to prevent a malicious client from causing OOM errors. Fixed a bug in HttpResponse and HttpRequest parse causing it to abort if the request is invalid in some cases.
This commit is contained in:
parent
5c2b6c3a8d
commit
abb3655739
@ -8,11 +8,23 @@ set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake_mo
|
||||
#User options
|
||||
option(USE_SSL "Use SSL" OFF)
|
||||
set(FRNETLIB_BUILD_SHARED_LIBS false CACHE BOOL "Build shared library.")
|
||||
set(MAX_HTTP_HEADER_SIZE "0xC800" CACHE STRING "The maximum allowed HTTP header size in bytes")
|
||||
set(MAX_HTTP_BODY_SIZE "0xA00000" CACHE STRING "The maximum allowed HTTP body size in bytes")
|
||||
|
||||
#Enable tests and examples by default
|
||||
option(BUILD_EXAMPLES "Build frnetlib examples" ON)
|
||||
option(BUILD_TESTS "Build frnetlib tests" ON)
|
||||
|
||||
#Configure defines based on user options
|
||||
add_definitions(-DMAX_HTTP_HEADER_SIZE=${MAX_HTTP_HEADER_SIZE})
|
||||
add_definitions(-DMAX_HTTP_BODY_SIZE=${MAX_HTTP_BODY_SIZE})
|
||||
|
||||
if(USE_SSL)
|
||||
FIND_PACKAGE(MBEDTLS)
|
||||
INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR})
|
||||
add_definitions(-DSSL_ENABLED)
|
||||
endif()
|
||||
|
||||
add_definitions(-DNOMINMAX)
|
||||
add_definitions(-Dhtonf)
|
||||
add_definitions(-Dhtonll)
|
||||
@ -20,12 +32,6 @@ add_definitions(-Dntohll)
|
||||
add_definitions(-Dhtond)
|
||||
add_definitions(-Dntodh)
|
||||
|
||||
if(USE_SSL)
|
||||
FIND_PACKAGE(MBEDTLS)
|
||||
INCLUDE_DIRECTORIES(${MBEDTLS_INCLUDE_DIR})
|
||||
add_definitions(-DSSL_ENABLED)
|
||||
endif()
|
||||
|
||||
set( INCLUDE_PATH "${PROJECT_SOURCE_DIR}/include" )
|
||||
set( SOURCE_PATH "${PROJECT_SOURCE_DIR}/src" )
|
||||
|
||||
|
||||
@ -27,6 +27,9 @@ namespace fr
|
||||
};
|
||||
enum RequestStatus
|
||||
{
|
||||
ParseError = 0,
|
||||
HttpHeaderTooBig = 1,
|
||||
HttpBodyTooBig = 2,
|
||||
Continue = 100,
|
||||
SwitchingProtocols = 101,
|
||||
Ok = 200,
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#include <windows.h>
|
||||
#include <ws2tcpip.h>
|
||||
#define SOL_TCP SOL_SOCKET
|
||||
#define SHUT_RDWR SD_BOTH
|
||||
#else
|
||||
#define closesocket(x) close(x)
|
||||
#define INVALID_SOCKET 0
|
||||
|
||||
@ -24,7 +24,7 @@ namespace fr
|
||||
class SSLListener : public Listener
|
||||
{
|
||||
public:
|
||||
explicit SSLListener(std::shared_ptr<SSLContext> ssl_context, const std::string &crt_path, const std::string &pem_path, const std::string &private_key_path) noexcept;
|
||||
explicit SSLListener(std::shared_ptr<SSLContext> ssl_context, const std::string &pem_path, const std::string &private_key_path) noexcept;
|
||||
virtual ~SSLListener() noexcept;
|
||||
SSLListener(SSLListener &&o) noexcept = default;
|
||||
|
||||
|
||||
@ -107,6 +107,16 @@ namespace fr
|
||||
return ssl_socket_descriptor->fd > -1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sets if the socket should verify the endpoints
|
||||
* certificates or not. Verification is enforced
|
||||
* by default, but disabling it could be useful
|
||||
* for testing.
|
||||
*
|
||||
* @param should_verify True if certificates should be verified, false otherwise
|
||||
*/
|
||||
void verify_certificates(bool should_verify);
|
||||
|
||||
private:
|
||||
std::shared_ptr<SSLContext> ssl_context;
|
||||
|
||||
@ -114,6 +124,7 @@ namespace fr
|
||||
std::unique_ptr<mbedtls_ssl_context> ssl;
|
||||
mbedtls_ssl_config conf;
|
||||
uint32_t flags;
|
||||
bool should_verify;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -3,11 +3,11 @@
|
||||
//
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include "frnetlib/HttpRequest.h"
|
||||
|
||||
namespace fr
|
||||
{
|
||||
HttpRequest::HttpRequest()
|
||||
HttpRequest::HttpRequest()
|
||||
: header_ended(false),
|
||||
last_parsed_character(0),
|
||||
content_length(0)
|
||||
@ -22,6 +22,13 @@ namespace fr
|
||||
//Ensure that the whole header has been parsed first
|
||||
if(!header_ended)
|
||||
{
|
||||
//Ensure that the header doesn't exceed max length
|
||||
if(body.size() > MAX_HTTP_HEADER_SIZE)
|
||||
{
|
||||
status = HttpHeaderTooBig;
|
||||
return false; //End parse
|
||||
}
|
||||
|
||||
//Check to see if this request data contains the end of the header
|
||||
uint16_t header_end_size = 4;
|
||||
auto header_end = body.find("\r\n\r\n");
|
||||
@ -38,11 +45,17 @@ namespace fr
|
||||
|
||||
//Else parse it
|
||||
if(!parse_header(header_end))
|
||||
return false;
|
||||
body.clear();
|
||||
return false;
|
||||
|
||||
//Leave things after the header intact
|
||||
body.erase(0, header_end + header_end_size);
|
||||
}
|
||||
|
||||
body += std::string(request + header_end + header_end_size, requestsz - header_end - header_end_size);
|
||||
//Ensure that body doesn't exceed maximum length
|
||||
if(body.size() > MAX_HTTP_BODY_SIZE)
|
||||
{
|
||||
status = HttpBodyTooBig;
|
||||
return false; //End parse
|
||||
}
|
||||
|
||||
//If we've got the whole request, parse the POST if it exists
|
||||
|
||||
@ -14,6 +14,13 @@ namespace fr
|
||||
//Ensure that the whole header has been parsed first
|
||||
if(!header_ended)
|
||||
{
|
||||
//Ensure that the header doesn't exceed max length
|
||||
if(body.size() > MAX_HTTP_HEADER_SIZE)
|
||||
{
|
||||
status = HttpHeaderTooBig;
|
||||
return false; //End parse
|
||||
}
|
||||
|
||||
//Check to see if this request data contains the end of the header
|
||||
uint16_t header_end_size = 4;
|
||||
auto header_end = body.find("\r\n\r\n");
|
||||
@ -30,12 +37,20 @@ namespace fr
|
||||
|
||||
//Else parse it
|
||||
parse_header(header_end);
|
||||
body.clear();
|
||||
body.clear();
|
||||
|
||||
|
||||
body += std::string(response_data + header_end + header_end_size, datasz - header_end - header_end_size);
|
||||
//Leave things after the header intact
|
||||
body.erase(0, header_end + header_end_size);
|
||||
}
|
||||
|
||||
//Ensure that body doesn't exceed maximum length
|
||||
if(body.size() > MAX_HTTP_BODY_SIZE)
|
||||
{
|
||||
status = HttpBodyTooBig;
|
||||
return false; //End parse
|
||||
}
|
||||
|
||||
//Cut off any data if it exceeds content length
|
||||
if(body.size() > content_length)
|
||||
body.resize(content_length);
|
||||
return body.size() < content_length;
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
|
||||
namespace fr
|
||||
{
|
||||
SSLListener::SSLListener(std::shared_ptr<SSLContext> ssl_context_, const std::string &crt_path, const std::string &pem_path, const std::string &private_key_path) noexcept
|
||||
SSLListener::SSLListener(std::shared_ptr<SSLContext> ssl_context_, const std::string &pem_path, const std::string &private_key_path) noexcept
|
||||
: ssl_context(std::move(ssl_context_))
|
||||
{
|
||||
//Initialise SSL objects required
|
||||
@ -25,13 +25,6 @@ namespace fr
|
||||
int error = 0;
|
||||
|
||||
//Load certificates and private key
|
||||
error = mbedtls_x509_crt_parse_file(&srvcert, crt_path.c_str());
|
||||
if(error != 0)
|
||||
{
|
||||
std::cout << "Failed to initialise SSL listener. CRT Parse returned: " << error << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
error = mbedtls_x509_crt_parse_file(&srvcert, pem_path.c_str());
|
||||
if(error != 0)
|
||||
{
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
namespace fr
|
||||
{
|
||||
SSLSocket::SSLSocket(std::shared_ptr<SSLContext> ssl_context_) noexcept
|
||||
: ssl_context(std::move(ssl_context_))
|
||||
: ssl_context(std::move(ssl_context_)),
|
||||
should_verify(true)
|
||||
{
|
||||
//Initialise mbedtls structures
|
||||
mbedtls_ssl_config_init(&conf);
|
||||
@ -104,7 +105,7 @@ namespace fr
|
||||
return Socket::Status::Error;
|
||||
}
|
||||
|
||||
mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_REQUIRED);
|
||||
mbedtls_ssl_conf_authmode(&conf, should_verify ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_NONE);
|
||||
mbedtls_ssl_conf_ca_chain(&conf, &ssl_context->cacert, nullptr);
|
||||
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ssl_context->ctr_drbg);
|
||||
|
||||
@ -131,7 +132,7 @@ namespace fr
|
||||
}
|
||||
|
||||
//Verify server certificate
|
||||
if((flags = mbedtls_ssl_get_verify_result(ssl.get())) != 0)
|
||||
if(should_verify && ((flags = mbedtls_ssl_get_verify_result(ssl.get())) != 0))
|
||||
{
|
||||
char verify_buffer[512];
|
||||
mbedtls_x509_crt_verify_info( verify_buffer, sizeof( verify_buffer ), " ! ", flags );
|
||||
@ -157,6 +158,11 @@ namespace fr
|
||||
ssl_socket_descriptor = std::move(context);
|
||||
reconfigure_socket();
|
||||
}
|
||||
|
||||
void SSLSocket::verify_certificates(bool should_verify_)
|
||||
{
|
||||
should_verify = should_verify_;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -67,7 +67,7 @@ namespace fr
|
||||
|
||||
void Socket::shutdown()
|
||||
{
|
||||
::shutdown(get_socket_descriptor(), 0);
|
||||
::shutdown(get_socket_descriptor(), SHUT_RDWR);
|
||||
}
|
||||
|
||||
void Socket::reconfigure_socket()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user