mirror of https://github.com/JAJames/Jupiter.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
6.9 KiB
221 lines
6.9 KiB
/**
|
|
* Copyright (C) Justin James - All Rights Reserved.
|
|
* Unauthorized use or copying of this file via any medium is strictly prohibited.
|
|
* This document is proprietary and confidential.
|
|
* This document should be immediately destroyed unless given explicit permission by Justin James.
|
|
* Written by Justin James <justin.aj@hotmail.com>
|
|
*/
|
|
|
|
#include <utility> // std::move
|
|
#include <openssl/ssl.h> // OpenSSL SSL functions
|
|
#include <openssl/err.h> // OpenSSL SSL errors
|
|
#include "SecureSocket.h"
|
|
#include "CString.h"
|
|
|
|
struct Jupiter::SecureSocket::SSLData
|
|
{
|
|
SSL *handle = nullptr;
|
|
SSL_CTX *context = nullptr;
|
|
const SSL_METHOD *method = nullptr;
|
|
Jupiter::SecureSocket::EncryptionMethod eMethod = ANY;
|
|
Jupiter::CStringS cert;
|
|
Jupiter::CStringS key;
|
|
~SSLData();
|
|
};
|
|
|
|
Jupiter::SecureSocket::SSLData::~SSLData()
|
|
{
|
|
if (Jupiter::SecureSocket::SSLData::handle != nullptr)
|
|
{
|
|
if (SSL_shutdown(Jupiter::SecureSocket::SSLData::handle) == 0) SSL_shutdown(Jupiter::SecureSocket::SSLData::handle);
|
|
SSL_free(Jupiter::SecureSocket::SSLData::handle);
|
|
}
|
|
if (Jupiter::SecureSocket::SSLData::context != nullptr) SSL_CTX_free(Jupiter::SecureSocket::SSLData::context);
|
|
}
|
|
|
|
Jupiter::SecureSocket::SecureSocket() : Jupiter::Socket()
|
|
{
|
|
Jupiter::SecureSocket::SSLdata_ = new Jupiter::SecureSocket::SSLData();
|
|
}
|
|
|
|
Jupiter::SecureSocket::SecureSocket(size_t bufferSize) : Jupiter::Socket(bufferSize)
|
|
{
|
|
Jupiter::SecureSocket::SSLdata_ = new Jupiter::SecureSocket::SSLData();
|
|
}
|
|
|
|
Jupiter::SecureSocket::SecureSocket(Jupiter::Socket &&source) : Jupiter::Socket(std::move(source))
|
|
{
|
|
Jupiter::SecureSocket::SSLdata_ = new Jupiter::SecureSocket::SSLData();
|
|
}
|
|
|
|
Jupiter::SecureSocket::SecureSocket(Jupiter::SecureSocket &&source) : Jupiter::Socket(std::move(source))
|
|
{
|
|
Jupiter::SecureSocket::SSLdata_ = source.SSLdata_;
|
|
source.SSLdata_ = nullptr;
|
|
}
|
|
|
|
Jupiter::SecureSocket::~SecureSocket()
|
|
{
|
|
if (Jupiter::SecureSocket::SSLdata_ != nullptr) delete Jupiter::SecureSocket::SSLdata_;
|
|
}
|
|
|
|
Jupiter::SecureSocket *Jupiter::SecureSocket::acceptConnection()
|
|
{
|
|
int tSock = SSL_accept(Jupiter::SecureSocket::SSLdata_->handle);
|
|
if (tSock > 0)
|
|
{
|
|
SecureSocket *r = new SecureSocket(Jupiter::SecureSocket::getBufferSize());
|
|
r->setDescriptor(tSock);
|
|
r->setType(this->getType());
|
|
r->setProtocol(this->getProtocol());
|
|
return r;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
bool Jupiter::SecureSocket::bindToPort(const char *hostname, unsigned short iPort, bool andListen)
|
|
{
|
|
return Jupiter::Socket::bindToPort(hostname, iPort, andListen);
|
|
}
|
|
|
|
void Jupiter::SecureSocket::closeSocket()
|
|
{
|
|
if (Jupiter::SecureSocket::SSLdata_ != nullptr)
|
|
{
|
|
Jupiter::Socket::closeSocket();
|
|
delete Jupiter::SecureSocket::SSLdata_;
|
|
Jupiter::SecureSocket::SSLdata_ = new Jupiter::SecureSocket::SSLData();
|
|
}
|
|
}
|
|
|
|
const SSL_METHOD *translateEncryptionMethod(Jupiter::SecureSocket::EncryptionMethod method)
|
|
{
|
|
switch (method)
|
|
{
|
|
case Jupiter::SecureSocket::EncryptionMethod::SSL3:
|
|
return SSLv3_method();
|
|
case Jupiter::SecureSocket::EncryptionMethod::TLS1:
|
|
return TLSv1_method();
|
|
case Jupiter::SecureSocket::EncryptionMethod::TLS1_1:
|
|
return TLSv1_1_method();
|
|
case Jupiter::SecureSocket::EncryptionMethod::TLS1_2:
|
|
return TLSv1_2_method();
|
|
case Jupiter::SecureSocket::EncryptionMethod::DTLS1:
|
|
return DTLSv1_method();
|
|
case Jupiter::SecureSocket::EncryptionMethod::ANY:
|
|
return SSLv23_method();
|
|
default:
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
const char *Jupiter::SecureSocket::getCipherName() const
|
|
{
|
|
return SSL_CIPHER_get_name(SSL_get_current_cipher(Jupiter::SecureSocket::SSLdata_->handle));
|
|
}
|
|
|
|
Jupiter::SecureSocket::EncryptionMethod Jupiter::SecureSocket::getMethod() const
|
|
{
|
|
return Jupiter::SecureSocket::SSLdata_->eMethod;
|
|
}
|
|
|
|
void Jupiter::SecureSocket::setMethod(Jupiter::SecureSocket::EncryptionMethod method)
|
|
{
|
|
Jupiter::SecureSocket::SSLdata_->eMethod = method;
|
|
}
|
|
|
|
bool loadCertificate(SSL_CTX *context, const char *cert, const char *key)
|
|
{
|
|
if (SSL_CTX_load_verify_locations(context, cert, key) != 1) ERR_print_errors_fp(stderr);
|
|
|
|
if (SSL_CTX_set_default_verify_paths(context) != 1) ERR_print_errors_fp(stderr);
|
|
|
|
if (SSL_CTX_use_certificate_file(context, cert, SSL_FILETYPE_PEM) <= 0)
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return false;
|
|
}
|
|
|
|
if (SSL_CTX_use_PrivateKey_file(context, key, SSL_FILETYPE_PEM) <= 0)
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return false;
|
|
}
|
|
|
|
if (!SSL_CTX_check_private_key(context)) return false;
|
|
return true;
|
|
}
|
|
|
|
void Jupiter::SecureSocket::setCertificate(const Jupiter::ReadableString &cert, const Jupiter::ReadableString &key)
|
|
{
|
|
Jupiter::SecureSocket::SSLdata_->cert = cert;
|
|
Jupiter::SecureSocket::SSLdata_->key = key;
|
|
}
|
|
|
|
void Jupiter::SecureSocket::setCertificate(const Jupiter::ReadableString &pem)
|
|
{
|
|
Jupiter::SecureSocket::setCertificate(pem, pem);
|
|
}
|
|
|
|
bool Jupiter::SecureSocket::connectToHost(const char *hostname, unsigned short iPort, const char *clientAddress, unsigned short clientPort)
|
|
{
|
|
return Jupiter::Socket::connectToHost(hostname, iPort, clientAddress, clientPort) && this->initSSL();
|
|
}
|
|
|
|
int Jupiter::SecureSocket::peek()
|
|
{
|
|
int r = SSL_peek(Jupiter::SecureSocket::SSLdata_->handle, (char *) this->getBuffer(), this->getBufferSize()-1);
|
|
if (r >= 0) ((char *) this->getBuffer())[r] = 0;
|
|
return r;
|
|
}
|
|
|
|
int Jupiter::SecureSocket::recv()
|
|
{
|
|
if (Jupiter::SecureSocket::SSLdata_->handle == nullptr) return -1;
|
|
int r = SSL_read(Jupiter::SecureSocket::SSLdata_->handle, (char *) this->getBuffer(), this->getBufferSize()-1);
|
|
if (r >= 0) ((char *) this->getBuffer())[r] = 0;
|
|
return r;
|
|
}
|
|
|
|
int Jupiter::SecureSocket::send(const char *data, size_t datalen)
|
|
{
|
|
return SSL_write(Jupiter::SecureSocket::SSLdata_->handle, data, datalen);
|
|
}
|
|
|
|
bool Jupiter::SecureSocket::initSSL()
|
|
{
|
|
SSL_load_error_strings();
|
|
SSL_library_init();
|
|
Jupiter::SecureSocket::SSLdata_->method = translateEncryptionMethod(Jupiter::SecureSocket::SSLdata_->eMethod);
|
|
if (Jupiter::SecureSocket::SSLdata_->method == nullptr) return false;
|
|
Jupiter::SecureSocket::SSLdata_->context = SSL_CTX_new(Jupiter::SecureSocket::SSLdata_->method);
|
|
if (Jupiter::SecureSocket::SSLdata_->context == nullptr)
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return false;
|
|
}
|
|
if (Jupiter::SecureSocket::SSLdata_->cert.size() != 0) loadCertificate(Jupiter::SecureSocket::SSLdata_->context, Jupiter::SecureSocket::SSLdata_->cert.c_str(), Jupiter::SecureSocket::SSLdata_->key.c_str());
|
|
Jupiter::SecureSocket::SSLdata_->handle = SSL_new(Jupiter::SecureSocket::SSLdata_->context);
|
|
if (Jupiter::SecureSocket::SSLdata_->handle == nullptr)
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return false;
|
|
}
|
|
if (SSL_set_fd(Jupiter::SecureSocket::SSLdata_->handle, this->getDescriptor()) == 0)
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return false;
|
|
}
|
|
if (SSL_set_tlsext_host_name(Jupiter::SecureSocket::SSLdata_->handle, this->getHost()) != 1) // This error check is potentially redundant, but no documentation has been found.
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return false;
|
|
}
|
|
int t = SSL_connect(Jupiter::SecureSocket::SSLdata_->handle);
|
|
if (t != 1)
|
|
{
|
|
ERR_print_errors_fp(stderr);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|