Initial commit

This commit is contained in:
Alcaro
2016-07-13 18:44:41 +02:00
commit 9335f0b024
149 changed files with 107169 additions and 0 deletions

34375
arlib/socket/libtomcrypt.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,64 @@
#ifdef ARLIB_TEST_SERVER
//Shitty Server: a buggy echo server
//after the first 32 bytes, it drops your connection on the floor, without FIN or anything
//probably somewhat useful to test resilience against network failure
//it would be more useful to make it ignore the pings too, but I can't do that without fiddling with the firewall, and I'd rather not
//linux and root only because TCP_REPAIR requires that
//http://oroboro.com/dealing-with-network-port-abuse-in-sockets-in-c
//if you need to test a windows program against dropped sockets, run this on another machine, possibly a virtual machine
//most of the code stolen from http://www.thegeekstuff.com/2011/12/c-socket-programming/ because I'm lazy
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <time.h>
#include <netinet/tcp.h>
int main()
{
int listenfd = 0, connfd = 0;
struct sockaddr_in serv_addr;
char sendBuff[1025];
time_t ticks;
listenfd = socket(AF_INET, SOCK_STREAM, 0);
memset(&serv_addr, '0', sizeof(serv_addr));
memset(sendBuff, '0', sizeof(sendBuff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(168);
bind(listenfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
perror("bind");
listen(listenfd, 10);
perror("listen");
while(1)
{
connfd = accept(listenfd, (struct sockaddr*)NULL, NULL);
perror("accept");
memset(sendBuff, 0, 32);
read(connfd, sendBuff, 32);
write(connfd, sendBuff, 32);
sleep(1); // otherwise the ACK gives a RST
int yes = 1;
setsockopt(connfd, SOL_TCP, TCP_REPAIR, &yes, sizeof(yes));
perror("TCP_REPAIR");
close(connfd);
}
}
#endif

View File

@@ -0,0 +1,342 @@
#include "socket.h"
#ifdef ARLIB_SSL_OPENSSL
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/x509v3.h>
static SSL_CTX * ctx;
static void initialize()
{
static bool initialized = false;
if (initialized) return;
initialized = true;
//SSL_load_error_strings(); // TODO
SSL_library_init();
ctx = SSL_CTX_new(SSLv23_client_method());
SSL_CTX_set_default_verify_paths(ctx);
SSL_CTX_set_cipher_list(ctx, "HIGH:!DSS:!aNULL@STRENGTH");
}
static bool validate_hostname(const char *hostname, const X509 *server_cert);
class socketssl_impl : public socketssl {
public:
socket* sock;
SSL* ssl;
//bool nonblock;
static socketssl_impl* create(socket* parent, const char * domain, bool permissive)
{
if (!parent) return NULL;
socketssl_impl* ret = new socketssl_impl();
ret->sock = parent;
ret->fd = parent->get_fd();
ret->ssl = SSL_new(ctx);
//ret->nonblock = false;
SSL_set_fd(ret->ssl, ret->fd);
//TODO: set fd to nonblock
if (!permissive)
{
SSL_set_verify(ret->ssl, SSL_VERIFY_PEER, NULL);
}
//plausible cert failure cases: unrooted (including self-signed), expired, wrong domain
//permissive should allow the former two, but still block the third
#if OPENSSL_VERSION_NUMBER >= 0x10100000 // >= 1.1.0
#error test, especially set0 vs set1
SSL_set1_host(ssl, "example.com");
#endif
#if OPENSSL_VERSION_NUMBER >= 0x10002000 && OPENSSL_VERSION_NUMBER < 0x10100000 // >= 1.0.2, < 1.1.0
#error test, especially [gs]et0 vs [gs]et1
X509_VERIFY_PARAM* param = SSL_get0_param(ssl);
//optional?
//X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
X509_VERIFY_PARAM_set1_host(param, "example.com", 0);
#endif
bool ok = (SSL_connect(ret->ssl)==1);
#if OPENSSL_VERSION_NUMBER < 0x10002000 // < 1.0.2
if (ok && !validate_hostname(domain, SSL_get_peer_certificate(ret->ssl)))
{
ok=false;
}
#endif
if (!ok)
{
delete ret;
return 0;
}
return ret;
}
/*private*/ int fixret(int ret)
{
if (ret > 0) return ret;
int sslerror = SSL_get_error(ssl, ret);
if (sslerror==SSL_ERROR_WANT_READ || sslerror==SSL_ERROR_WANT_WRITE) return 0;
//printf("ERR=%i\n",sslerror);
//ERR_print_errors();
return e_ssl_failure;
}
//only supports nonblocking
int recv(uint8_t* data, unsigned int len, bool block = false)
{
return fixret(SSL_read(ssl, data, len));
}
int sendp(const uint8_t* data, unsigned int len, bool block = true)
{
return fixret(SSL_write(ssl, data, len));
}
~socketssl_impl()
{
SSL_shutdown(ssl);
SSL_free(ssl);
delete sock;
}
};
socketssl* socketssl::create(socket* parent, const char * domain, bool permissive)
{
initialize();
if (!ctx) return NULL;
return socketssl_impl::create(parent, domain, permissive);
}
#if OPENSSL_VERSION_NUMBER < 0x10002000
//from TLSe https://github.com/eduardsui/tlse/blob/90bdc5d/tlse.c#L2519
#define bad_certificate -1
static int tls_certificate_valid_subject_name(const unsigned char *cert_subject, const char *subject) {
// no subjects ...
if (((!cert_subject) || (!cert_subject[0])) && ((!subject) || (!subject[0])))
return 0;
if ((!subject) || (!subject[0]))
return bad_certificate;
if ((!cert_subject) || (!cert_subject[0]))
return bad_certificate;
// exact match
if (!strcmp((const char *)cert_subject, subject))
return 0;
const char *wildcard = strchr((const char *)cert_subject, '*');
if (wildcard) {
// 6.4.3 (1) The client SHOULD NOT attempt to match a presented identifier in
// which the wildcard character comprises a label other than the left-most label
if (!wildcard[1]) {
// subject is [*]
// or
// subject is [something*] .. invalid
return bad_certificate;
}
wildcard++;
const char *match = strstr(subject, wildcard);
if ((!match) && (wildcard[0] == '.')) {
// check *.domain.com agains domain.com
wildcard++;
if (!strcasecmp(subject, wildcard))
return 0;
}
if (match) {
unsigned long offset = (unsigned long)match - (unsigned long)subject;
if (offset) {
// check for foo.*.domain.com against *.domain.com (invalid)
if (memchr(subject, '.', offset))
return bad_certificate;
}
// check if exact match
if (!strcasecmp(match, wildcard))
return 0;
}
}
return bad_certificate;
}
//copypasted from https://wiki.openssl.org/index.php/Hostname_validation
//and modified a bit (for example to add a missing cast)
/*
Copyright (C) 2012, iSEC Partners.
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.
*/
/*
* Helper functions to perform basic hostname validation using OpenSSL.
*
* Please read "everything-you-wanted-to-know-about-openssl.pdf" before
* attempting to use this code. This whitepaper describes how the code works,
* how it should be used, and what its limitations are.
*
* Author: Alban Diquet
* License: See LICENSE
*
*/
// Get rid of OSX 10.7 and greater deprecation warnings.
#if defined(__APPLE__) && defined(__clang__)
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
//#include <openssl/ssl.h>
//#include "openssl_hostname_validation.h"
//#include "hostcheck.h"
#define HOSTNAME_MAX_SIZE 255
enum HostnameValidationResult { Error, MalformedCertificate, NoSANPresent, MatchFound, MatchNotFound };
/**
* Tries to find a match for hostname in the certificate's Common Name field.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if the Common Name had a NUL character embedded in it.
* Returns Error if the Common Name could not be extracted.
*/
static HostnameValidationResult matches_common_name(const char *hostname, const X509 *server_cert) {
int common_name_loc = -1;
X509_NAME_ENTRY *common_name_entry = NULL;
ASN1_STRING *common_name_asn1 = NULL;
char *common_name_str = NULL;
// Find the position of the CN field in the Subject field of the certificate
common_name_loc = X509_NAME_get_index_by_NID(X509_get_subject_name((X509 *) server_cert), NID_commonName, -1);
if (common_name_loc < 0) {
return Error;
}
// Extract the CN field
common_name_entry = X509_NAME_get_entry(X509_get_subject_name((X509 *) server_cert), common_name_loc);
if (common_name_entry == NULL) {
return Error;
}
// Convert the CN field to a C string
common_name_asn1 = X509_NAME_ENTRY_get_data(common_name_entry);
if (common_name_asn1 == NULL) {
return Error;
}
common_name_str = (char *) ASN1_STRING_data(common_name_asn1);
// Make sure there isn't an embedded NUL character in the CN
if ((size_t)ASN1_STRING_length(common_name_asn1) != strlen(common_name_str)) {
return MalformedCertificate;
}
// Compare expected hostname with the CN
if (tls_certificate_valid_subject_name((uint8_t*)common_name_str, hostname)==0) {
return MatchFound;
}
else {
return MatchNotFound;
}
}
/**
* Tries to find a match for hostname in the certificate's Subject Alternative Name extension.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
* Returns NoSANPresent if the SAN extension was not present in the certificate.
*/
static HostnameValidationResult matches_subject_alternative_name(const char *hostname, const X509 *server_cert) {
HostnameValidationResult result = MatchNotFound;
int i;
int san_names_nb = -1;
STACK_OF(GENERAL_NAME) *san_names = NULL;
// Try to extract the names within the SAN extension from the certificate
san_names = (STACK_OF(GENERAL_NAME)*)X509_get_ext_d2i((X509 *) server_cert, NID_subject_alt_name, NULL, NULL);
if (san_names == NULL) {
return NoSANPresent;
}
san_names_nb = sk_GENERAL_NAME_num(san_names);
// Check each name within the extension
for (i=0; i<san_names_nb; i++) {
const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i);
if (current_name->type == GEN_DNS) {
// Current name is a DNS name, let's check it
char *dns_name = (char *) ASN1_STRING_data(current_name->d.dNSName);
// Make sure there isn't an embedded NUL character in the DNS name
if ((size_t)ASN1_STRING_length(current_name->d.dNSName) != strlen(dns_name)) {
result = MalformedCertificate;
break;
}
else { // Compare expected hostname with the DNS name
if (tls_certificate_valid_subject_name((uint8_t*)dns_name, hostname)==0) {
result = MatchFound;
break;
}
}
}
}
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
return result;
}
/**
* Validates the server's identity by looking for the expected hostname in the
* server's certificate. As described in RFC 6125, it first tries to find a match
* in the Subject Alternative Name extension. If the extension is not present in
* the certificate, it checks the Common Name instead.
*
* Returns MatchFound if a match was found.
* Returns MatchNotFound if no matches were found.
* Returns MalformedCertificate if any of the hostnames had a NUL character embedded in it.
* Returns Error if there was an error.
*/
static bool validate_hostname(const char *hostname, const X509 *server_cert) {
HostnameValidationResult result;
if((hostname == NULL) || (server_cert == NULL))
return false;
// First try the Subject Alternative Names extension
result = matches_subject_alternative_name(hostname, server_cert);
if (result == NoSANPresent) {
// Extension was not found: try the Common Name
result = matches_common_name(hostname, server_cert);
}
return (result==MatchFound);
}
#endif
#endif

View File

@@ -0,0 +1,339 @@
#include "socket.h"
//based on http://wayback.archive.org/web/20100528130307/http://www.coastrd.com/c-schannel-smtp
//but heavily rewritten for stability and compactness
#ifdef ARLIB_SSL_SCHANNEL
#ifndef _WIN32
#error SChannel only exists on Windows
#endif
#define SECURITY_WIN32
#undef bind
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock.h>
#include <wincrypt.h>
#include <wintrust.h>
#include <schannel.h>
#include <security.h>
#include <sspi.h>
namespace {
static SecurityFunctionTable* SSPI;
static CredHandle cred;
#define SSPIFlags \
(ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | ISC_REQ_CONFIDENTIALITY | \
ISC_RET_EXTENDED_ERROR | ISC_REQ_ALLOCATE_MEMORY | ISC_REQ_STREAM)
//my mingw headers are outdated
#ifndef SCH_USE_STRONG_CRYPTO
#define SCH_USE_STRONG_CRYPTO 0x00400000
#endif
#ifndef SP_PROT_TLS1_2_CLIENT
#define SP_PROT_TLS1_2_CLIENT 0x00000800
#endif
#ifndef SEC_Entry
#define SEC_Entry WINAPI
#endif
static void initialize()
{
if (SSPI) return;
//linking a DLL is easy, but when there's only one exported function, spending the extra effort is worth it
HMODULE secur32 = LoadLibraryA("secur32.dll");
typedef PSecurityFunctionTableA SEC_Entry (*InitSecurityInterfaceA_t)(void);
InitSecurityInterfaceA_t InitSecurityInterfaceA = (InitSecurityInterfaceA_t)GetProcAddress(secur32, SECURITY_ENTRYPOINT_ANSIA);
SSPI = InitSecurityInterfaceA();
SCHANNEL_CRED SchannelCred = {};
SchannelCred.dwVersion = SCHANNEL_CRED_VERSION;
SchannelCred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS | SCH_USE_STRONG_CRYPTO;
// fun fact: IE11 doesn't use SCH_USE_STRONG_CRYPTO. I guess it favors accepting outdated servers over rejecting evil ones.
SchannelCred.grbitEnabledProtocols = SP_PROT_TLS1_2_CLIENT; // Microsoft recommends setting this to zero, but that makes it use TLS 1.0, which sucks.
//howsmyssl expects session ticket support for the Good rating, but that's only supported on windows 8, according to
// https://connect.microsoft.com/IE/feedback/details/997136/internet-explorer-11-on-windows-7-does-not-support-tls-session-tickets
//and I can't find which flag enables that, anyways
SSPI->AcquireCredentialsHandleA(NULL, (char*)UNISP_NAME_A, SECPKG_CRED_OUTBOUND,
NULL, &SchannelCred, NULL, NULL, &cred, NULL);
}
class socketssl_impl : public socketssl {
public:
socket* sock;
CtxtHandle ssl;
SecPkgContext_StreamSizes bufsizes;
BYTE* recv_buf;
size_t recv_buf_len;
BYTE* ret_buf;
size_t ret_buf_len;
bool in_handshake;
void fetch(bool block)
{
int bytes = sock->recv(recv_buf+recv_buf_len, 1024, block);
if (bytes < 0)
{
delete sock;
sock = NULL;
}
if (bytes > 0)
{
recv_buf_len += bytes;
if (recv_buf_len > 1024)
{
recv_buf = realloc(recv_buf, recv_buf_len + 1024);
}
}
}
void fetch() { fetch(true); }
void fetchnb() { fetch(false); }
void ret_realloc(int bytes)
{
if (bytes > 0)
{
ret_buf_len += bytes;
if (ret_buf_len > 1024)
{
ret_buf = realloc(ret_buf, ret_buf_len + 1024);
}
}
}
BYTE* tmpptr()
{
return recv_buf + recv_buf_len;
}
void error()
{
SSPI->DeleteSecurityContext(&ssl);
delete sock;
sock = NULL;
}
void handshake()
{
if (!in_handshake) return;
SecBuffer InBuffers[2] = { { recv_buf_len, SECBUFFER_TOKEN, recv_buf }, { 0, SECBUFFER_EMPTY, NULL } };
SecBufferDesc InBufferDesc = { SECBUFFER_VERSION, 2, InBuffers };
SecBuffer OutBuffer = { 0, SECBUFFER_TOKEN, NULL };
SecBufferDesc OutBufferDesc = { SECBUFFER_VERSION, 1, &OutBuffer };
DWORD ignore;
SECURITY_STATUS scRet;
scRet = SSPI->InitializeSecurityContextA(&cred, &ssl, NULL, SSPIFlags, 0, SECURITY_NATIVE_DREP,
&InBufferDesc, 0, NULL, &OutBufferDesc, &ignore, NULL);
// according to the original program, extended errors are success
// but they also hit the error handler below, so I guess it just sends an error to the server?
// either way, ignore
if (scRet == SEC_E_OK || scRet == SEC_I_CONTINUE_NEEDED)
{
if (OutBuffer.cbBuffer != 0 && OutBuffer.pvBuffer != NULL)
{
if (sock->send((BYTE*)OutBuffer.pvBuffer, OutBuffer.cbBuffer) < 0)
{
SSPI->FreeContextBuffer(OutBuffer.pvBuffer);
error();
return;
}
SSPI->FreeContextBuffer(OutBuffer.pvBuffer);
}
}
if (scRet == SEC_E_INCOMPLETE_MESSAGE) return;
if (scRet == SEC_E_OK)
{
in_handshake = false;
}
if (FAILED(scRet))
{
error();
return;
}
// SEC_I_INCOMPLETE_CREDENTIALS is possible and means server requested client authentication
// we don't support that, just ignore it
if (InBuffers[1].BufferType == SECBUFFER_EXTRA)
{
memmove(recv_buf, recv_buf + (recv_buf_len - InBuffers[1].cbBuffer), InBuffers[1].cbBuffer);
recv_buf_len = InBuffers[1].cbBuffer;
}
else recv_buf_len = 0;
}
bool handshake_first(const char * domain)
{
SecBuffer OutBuffer = { 0, SECBUFFER_TOKEN, NULL };
SecBufferDesc OutBufferDesc = { SECBUFFER_VERSION, 1, &OutBuffer };
DWORD ignore;
if (SSPI->InitializeSecurityContextA(&cred, NULL, (char*)domain, SSPIFlags, 0, SECURITY_NATIVE_DREP,
NULL, 0, &ssl, &OutBufferDesc, &ignore, NULL)
!= SEC_I_CONTINUE_NEEDED)
{
return false;
}
if (OutBuffer.cbBuffer != 0)
{
if (sock->send((BYTE*)OutBuffer.pvBuffer, OutBuffer.cbBuffer) < 0)
{
SSPI->FreeContextBuffer(OutBuffer.pvBuffer);
error();
return false;
}
SSPI->FreeContextBuffer(OutBuffer.pvBuffer); // Free output buffer.
}
in_handshake = true;
while (in_handshake) { fetch(); handshake(); }
return true;
}
bool init(socket* parent, const char * domain, bool permissive)
{
if (!parent) return false;
sock = parent;
fd = parent->get_fd();
recv_buf = malloc(2048);
recv_buf_len = 0;
ret_buf = malloc(2048);
ret_buf_len = 0;
if (!handshake_first(domain)) return false;
SSPI->QueryContextAttributes(&ssl, SECPKG_ATTR_STREAM_SIZES, &bufsizes);
return (sock);
}
void process()
{
handshake();
bool again = true;
while (again)
{
again = false;
SecBuffer Buffers[4] = {
{ recv_buf_len, SECBUFFER_DATA, recv_buf },
{ 0, SECBUFFER_EMPTY, NULL },
{ 0, SECBUFFER_EMPTY, NULL },
{ 0, SECBUFFER_EMPTY, NULL },
};
SecBufferDesc Message = { SECBUFFER_VERSION, 4, Buffers };
SECURITY_STATUS scRet = SSPI->DecryptMessage(&ssl, &Message, 0, NULL);
if (scRet == SEC_E_INCOMPLETE_MESSAGE) return;
else if (scRet == SEC_I_RENEGOTIATE)
{
in_handshake = true;
}
else if (scRet != SEC_E_OK)
{
error();
return;
}
recv_buf_len = 0;
// Locate data and (optional) extra buffers.
for (int i=0;i<4;i++)
{
if (Buffers[i].BufferType == SECBUFFER_DATA)
{
memcpy(ret_buf+ret_buf_len, Buffers[i].pvBuffer, Buffers[i].cbBuffer);
ret_realloc(Buffers[i].cbBuffer);
again = true;
}
if (Buffers[i].BufferType == SECBUFFER_EXTRA)
{
memmove(recv_buf, Buffers[i].pvBuffer, Buffers[i].cbBuffer);
recv_buf_len = Buffers[i].cbBuffer;
}
}
}
}
int recv(uint8_t* data, unsigned int len, bool block = false)
{
if (!sock) return -1;
fetch(block);
process();
if (!ret_buf_len) return 0;
unsigned ulen = len;
int ret = (ulen < ret_buf_len ? ulen : ret_buf_len);
memcpy(data, ret_buf, ret);
memmove(ret_buf, ret_buf+ret, ret_buf_len-ret);
ret_buf_len -= ret;
return ret;
}
int sendp(const uint8_t* data, unsigned int len, bool block = true)
{
if (!sock) return -1;
fetchnb();
process();
BYTE* sendbuf = tmpptr(); // let's reuse this
unsigned int maxmsglen = 0x1000 - bufsizes.cbHeader - bufsizes.cbTrailer;
if (len > maxmsglen) len = maxmsglen;
memcpy(sendbuf+bufsizes.cbHeader, data, len);
SecBuffer Buffers[4] = {
{ bufsizes.cbHeader, SECBUFFER_STREAM_HEADER, sendbuf },
{ len, SECBUFFER_DATA, sendbuf+bufsizes.cbHeader },
{ bufsizes.cbTrailer, SECBUFFER_STREAM_TRAILER, sendbuf+bufsizes.cbHeader+len },
{ 0, SECBUFFER_EMPTY, NULL },
};
SecBufferDesc Message = { SECBUFFER_VERSION, 4, Buffers };
if (FAILED(SSPI->EncryptMessage(&ssl, 0, &Message, 0))) { error(); return -1; }
if (sock->send(sendbuf, Buffers[0].cbBuffer + Buffers[1].cbBuffer + Buffers[2].cbBuffer) < 0) error();
return len;
}
~socketssl_impl()
{
error();
free(recv_buf);
free(ret_buf);
}
};
}
socketssl* socketssl::create(socket* parent, const char * domain, bool permissive)
{
initialize();
socketssl_impl* ret = new socketssl_impl();
if (!ret->init(parent, domain, permissive)) { delete ret; return NULL; }
else return ret;
}
#endif

View File

@@ -0,0 +1,5 @@
//TODO:
//- fetch howsmyssl, ensure the only failure is the session cache
//- ensure Subject Name is verified: fetch https://172.217.18.142/ (IP of google.com)
//- ensure bad roots are rejected: fetch https://badfish.filippo.io/
//- ensure bad certs are accepted with verification off

View File

@@ -0,0 +1,260 @@
#include "socket.h"
#ifdef ARLIB_SSL_TLSE
extern "C" {
#include "tlse.h"
}
#include <sys/stat.h>
#include <dirent.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
//TLSe flaws and limitations:
//- can't share root certs between contexts (with possible exception of tls_accept, didn't check)
//- lack of const on some functions
//- have to load root certs myself
//- had to implement Subject Alternative Name myself
//- turns out tls_consume_stream(buf_len=0) throws an error - and no debug output
//- tls_export_context return value seems be 'bytes expected' for inputlen=0 and inputlen>=expected,
// but 'additional bytes expected' for inputlen=1
//- lacks extern "C" on header
//- lack of documentation
// separate context here to ensure they're not loaded multiple times, saves memory and time
static TLSContext* rootcerts;
static void initialize()
{
if (rootcerts) return;
rootcerts = tls_create_context(false, TLS_V12);
#ifdef __unix__
DIR* dir = opendir("/etc/ssl/certs/");
uint8_t* cert = NULL;
off_t cert_buf_len = 0;
if (dir)
{
while (true)
{
struct dirent* entry = readdir(dir);
if (!entry) break;
char name[256];
snprintf(name, sizeof(name), "%s%s", "/etc/ssl/certs/", entry->d_name);
if (!strstr(name, "DST_Root")) continue;
struct stat s;
if (stat(name, &s) == 0 && (s.st_mode & S_IFREG))
{
if (s.st_size > cert_buf_len)
{
free(cert);
cert_buf_len = s.st_size;
cert = (uint8_t*)malloc(cert_buf_len);
}
int fd = open(name, O_RDONLY);
if (fd >= 0)
{
off_t actualsize = read(fd, cert, s.st_size);
tls_load_root_certificates(rootcerts, cert, actualsize);
}
}
}
closedir(dir);
}
free(cert);
#else
#error unsupported
#endif
}
class socketssl_impl : public socketssl {
public:
socket* sock;
TLSContext* ssl;
//same as tls_default_verify, except tls_certificate_chain_is_valid_root is given another context
static int verify(TLSContext* context, TLSCertificate* * certificate_chain, int len) {
int err;
if (certificate_chain) {
for (int i = 0; i < len; i++) {
TLSCertificate* certificate = certificate_chain[i];
// check validity date
err = tls_certificate_is_valid(certificate);
if (err)
return err;
// check certificate in certificate->bytes of length certificate->len
// the certificate is in ASN.1 DER format
}
}
// check if chain is valid
err = tls_certificate_chain_is_valid(certificate_chain, len);
if (err)
return err;
const char * sni = tls_sni(context);
if (len>0 && sni) {
err = tls_certificate_valid_subject(certificate_chain[0], sni);
if (err)
return err;
}
// Perform certificate validation agains ROOT CA
err = tls_certificate_chain_is_valid_root(rootcerts, certificate_chain, len);
if (err)
return err;
//return certificate_expired;
//return certificate_revoked;
//return certificate_unknown;
return no_error;
}
void process(bool block)
{
if (!sock) return;
unsigned int outlen = 0;
const uint8_t * out = tls_get_write_buffer(ssl, &outlen);
if (out && outlen)
{
if (sock->send(out, outlen) < 0) { error(); return; }
tls_buffer_clear(ssl);
}
uint8_t in[0x2000];
int inlen = sock->recv(in, sizeof(in), block);
if (inlen<0) { error(); return; }
if (inlen>0) tls_consume_stream(ssl, in, inlen, verify);
}
void error()
{
delete sock;
sock = NULL;
}
static socketssl_impl* create(socket* parent, const char * domain, bool permissive)
{
if (!parent) return NULL;
socketssl_impl* ret = new socketssl_impl();
ret->sock = parent;
ret->fd = parent->get_fd();
ret->ssl = tls_create_context(false, TLS_V12);
tls_make_exportable(ret->ssl, true);
tls_sni_set(ret->ssl, domain);
tls_client_connect(ret->ssl);
while (!tls_established(ret->ssl))
{
ret->process(true);
}
return ret;
}
int recv(uint8_t* data, unsigned int len, bool block = false)
{
process(block);
int ret = tls_read(ssl, data, len);
if (ret==0 && !sock) return e_broken;
return ret;
}
int sendp(const uint8_t* data, unsigned int len, bool block = true)
{
if (!sock) return -1;
int ret = tls_write(ssl, (uint8_t*)data, len);
process(false);
return ret;
}
~socketssl_impl()
{
if (ssl && sock)
{
tls_close_notify(ssl);
process(false);
}
if (ssl) tls_destroy_context(ssl);
if (sock) delete sock;
}
void q()
{
uint8_t data[4096];
int len = tls_export_context(ssl, NULL, 0, false);
int len2 = tls_export_context(ssl, data, len, false);
printf("len=%i len2=%i\n", len, len2);
//tls_destroy_context(ssl);
TLSContext* ssl2 = tls_import_context(data, len);
uint8_t* p1 = (uint8_t*)ssl;
uint8_t* p2 = (uint8_t*)ssl2;
for (int i=0;i<140304;i++)
{
//if (p1[i] != p2[i]) printf("%i: g=%.2X b=%.2X\n", i, p1[i], p2[i]);
}
//ssl = ssl2;
}
size_t serialize_size()
{
return tls_export_context(ssl, NULL, 0, false);
}
int serialize(uint8_t* data, size_t len)
{
process(true);
tls_export_context(ssl, data, len, false);
tls_destroy_context(this->ssl);
this->ssl = NULL;
int ret = decompose(this->sock);
this->sock = NULL;
delete this;
return ret;
}
static socketssl_impl* unserialize(int fd, const uint8_t* data, size_t len)
{
socketssl_impl* ret = new socketssl_impl();
ret->sock = socket::create_from_fd(fd);
ret->fd = fd;
ret->ssl = tls_import_context((uint8_t*)data, len);
if (!ret->ssl) { delete ret; return NULL; }
return ret;
}
};
socketssl* socketssl::create(socket* parent, const char * domain, bool permissive)
{
initialize();
return socketssl_impl::create(parent, domain, permissive);
}
socketssl* socketssl::unserialize(int fd, const uint8_t* data, size_t len)
{
initialize();
return socketssl_impl::unserialize(fd, data, len);
}
#endif

View File

@@ -0,0 +1,241 @@
#include "socket.h"
#ifdef ARLIB_SSL_WOLFSSL
//#define HAVE_SNI
#define HAVE_SUPPORTED_CURVES
#include <wolfssl/ssl.h>
#ifdef __unix__
#include <sys/socket.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <errno.h>
#endif
#include <stdlib.h>
#error "this thing is broken. try again once wolfSSL > 3.9 is released and see if that fixes the alert 40 handshake failed errors"
static WOLFSSL_CTX* ctx;
class socketssl_impl : public socketssl {
public:
socket* sock;
WOLFSSL* ssl;
bool nonblock;
socketssl_impl(socket* parent, const char * domain, bool permissive)
{
sock = parent;
fd = get_fd(parent);
//ssl = wolfSSL_new(ctx);
nonblock = 0;
wolfSSL_Init();
wolfSSL_Debugging_ON();
ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
wolfSSL_SetIORecv(ctx, socketssl_impl::recv_raw);
wolfSSL_SetIOSend(ctx, socketssl_impl::send_raw);
wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
#define err_sys puts
ssl = wolfSSL_new(ctx);
wolfSSL_SetIOReadCtx(ssl, this);
wolfSSL_SetIOWriteCtx(ssl, this);
if (ssl == NULL)
err_sys("unable to get SSL object");
if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP256R1)
!= SSL_SUCCESS) {
err_sys("unable to set curve secp256r1");
}
if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP384R1)
!= SSL_SUCCESS) {
err_sys("unable to set curve secp384r1");
}
if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP521R1)
!= SSL_SUCCESS) {
err_sys("unable to set curve secp521r1");
}
if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP224R1)
!= SSL_SUCCESS) {
err_sys("unable to set curve secp224r1");
}
if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP192R1)
!= SSL_SUCCESS) {
err_sys("unable to set curve secp192r1");
}
if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP160R1)
!= SSL_SUCCESS) {
err_sys("unable to set curve secp160r1");
}
//printf("fd=%i ret=%i ok=%i f=%i\n", fd,
//wolfSSL_set_fd(ssl, fd),
//SSL_SUCCESS, SSL_FAILURE);
puts("AAAAAAA");
if (wolfSSL_connect(ssl) != SSL_SUCCESS) {puts("NOOO");}
//wolfSSL_check_domain_name(ssl, domain);
//#define err_sys puts
// if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP256R1)
// != SSL_SUCCESS) {
// err_sys("unable to set curve secp256r1");
// }
// if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP384R1)
// != SSL_SUCCESS) {
// err_sys("unable to set curve secp384r1");
// }
// if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP521R1)
// != SSL_SUCCESS) {
// err_sys("unable to set curve secp521r1");
// }
// if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP224R1)
// != SSL_SUCCESS) {
// err_sys("unable to set curve secp224r1");
// }
// if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP192R1)
// != SSL_SUCCESS) {
// err_sys("unable to set curve secp192r1");
// }
// if (wolfSSL_UseSupportedCurve(ssl, WOLFSSL_ECC_SECP160R1)
// != SSL_SUCCESS) {
// err_sys("unable to set curve secp160r1");
// }
//
// wolfSSL_set_fd(ssl, fd);
// puts("cactus");
// if (wolfSSL_connect(ssl) != SSL_SUCCESS) {
// /* see note at top of README */
// int err = wolfSSL_get_error(ssl, 0);
// char buffer[80];
// printf("err = %d, %s\n", err,
// wolfSSL_ERR_error_string(err, buffer));
// err_sys("SSL_connect failed");
// /* if you're getting an error here */
// }
exit(0);
}
/*private*/ static int recv_raw(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
socketssl_impl* this_ = (socketssl_impl*)ctx;
int ret = this_->sock->recv((uint8_t*)buf, sz);
printf("SSLDATRAW_R=%i\n",ret);
for(int i=0;i<ret;i++)printf("%.2X ",(uint8_t)buf[i]);
puts("");
if (ret==0) return WOLFSSL_CBIO_ERR_WANT_READ;
if (ret<0) return WOLFSSL_CBIO_ERR_GENERAL;
return ret;
}
/*private*/ static int send_raw(WOLFSSL* ssl, char* buf, int sz, void* ctx)
{
socketssl_impl* this_ = (socketssl_impl*)ctx;
int ret;
if (this_->nonblock) ret = this_->sock->send0((uint8_t*)buf, sz);
else ret = this_->sock->send1((uint8_t*)buf, sz);
printf("SSLDATRAW_S=%i\n",ret);
for(int i=0;i<ret;i++)printf("%.2X ",(uint8_t)buf[i]);
puts("");
if (ret==0) return WOLFSSL_CBIO_ERR_WANT_WRITE;
if (ret<0) return WOLFSSL_CBIO_ERR_GENERAL;
return ret;
}
/*private*/ int fixret(int ret)
{
printf("SSLDAT=%i\n",ret);
if (ret > 0) return ret;
int err = wolfSSL_get_error(ssl, ret);
if (err==SSL_ERROR_WANT_READ || err==SSL_ERROR_WANT_WRITE) return 0;
printf("SSLERR=%i\n",err);
return e_broken;
}
int recv(uint8_t* data, int len)
{
nonblock = false;
return fixret(wolfSSL_read(ssl, data, len));
}
int send0(const uint8_t* data, int len)
{
nonblock = true;
return fixret(wolfSSL_write(ssl, data, len));
}
int send1(const uint8_t* data, int len)
{
nonblock = false;
return fixret(wolfSSL_write(ssl, data, len));
}
~socketssl_impl()
{
wolfSSL_free(ssl);
delete sock;
}
};
static void initialize()
{
static bool initialized = false;
if (initialized) return;
initialized = true;
//wolfSSL_Init();
//
//ctx = wolfSSL_CTX_new(wolfTLSv1_2_client_method());
//if (!ctx) return;
//wolfSSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, 0);
//wolfSSL_SetIORecv(ctx, socketssl_impl::recv_raw);
//wolfSSL_SetIOSend(ctx, socketssl_impl::send_raw);
#ifdef __unix__
//mostly copypasta from wolfSSL_CTX_load_verify_locations, minus the abort-on-first-error thingy
//there's some random weirdo files in my /etc/ssl/certs/, possibly duplicates?
//DIR* dir = opendir("/etc/ssl/certs/");
//if (dir)
//{
//while (true)
//{
//struct dirent* entry = readdir(dir);
//if (!entry) break;
//char name[256];
//snprintf(name, sizeof(name), "%s%s", "/etc/ssl/certs/", entry->d_name);
//
//struct stat s;
//if (stat(name, &s) == 0 && (s.st_mode & S_IFREG))
//{
//printf("cert=%s\n",name);
//wolfSSL_CTX_load_verify_locations(ctx, name, NULL);
//}
//}
//closedir(dir);
//}
#else
#error unsupported
#endif
//wolfSSL_Debugging_ON();
}
socketssl* socketssl::create(socket* parent, const char * domain, bool permissive)
{
initialize();
//if (!ctx) return NULL;
return new socketssl_impl(parent, domain, permissive);
}
#endif

160
arlib/socket/socket.cpp Normal file
View File

@@ -0,0 +1,160 @@
#include "socket.h"
#include <stdio.h>
#undef socket
#undef bind
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#define MSG_NOSIGNAL 0
#define MSG_DONTWAIT 0
#define close closesocket
#define usleep(n) Sleep(n/1000)
#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#endif
#else
#include <netdb.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <netinet/tcp.h>
static int setsockopt(int socket, int level, int option_name, int option_value)
{
return setsockopt(socket, level, option_name, &option_value, sizeof(option_value));
}
#endif
namespace {
static void initialize()
{
#ifdef _WIN32 // lol
static bool initialized = false;
if (initialized) return;
initialized = true;
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#endif
}
static int connect(const char * domain, int port)
{
initialize();
char portstr[16];
sprintf(portstr, "%i", port);
addrinfo hints;
memset(&hints, 0, sizeof(addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = 0;
addrinfo * addr = NULL;
getaddrinfo(domain, portstr, &hints, &addr);
if (!addr) return -1;
int fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
#ifndef _WIN32
//because 30 second pauses are unequivocally detestable
timeval timeout;
timeout.tv_sec = 4;
timeout.tv_usec = 0;
setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof(timeout));
#endif
if (connect(fd, addr->ai_addr, addr->ai_addrlen) != 0)
{
freeaddrinfo(addr);
close(fd);
return -1;
}
#ifndef _WIN32
setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, 1); // enable
setsockopt(fd, SOL_TCP, TCP_KEEPCNT, 3); // ping count before the kernel gives up
setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, 30); // seconds idle until it starts pinging
setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, 10); // seconds per ping once the pings start
#else
u_long yes = 1;
ioctlsocket(fd, FIONBIO, &yes);
struct tcp_keepalive keepalive = {
1, // SO_KEEPALIVE
30*1000, // TCP_KEEPIDLE in milliseconds
3*1000, // TCP_KEEPINTVL
//On Windows Vista and later, the number of keep-alive probes (data retransmissions) is set to 10 and cannot be changed.
//https://msdn.microsoft.com/en-us/library/windows/desktop/dd877220(v=vs.85).aspx
//so no TCP_KEEPCNT; I'll reduce INTVL instead. And a polite server will RST anyways.
};
u_long ignore;
WSAIoctl(fd, SIO_KEEPALIVE_VALS, &keepalive, sizeof(keepalive), NULL, 0, &ignore, NULL, NULL);
#endif
freeaddrinfo(addr);
return fd;
}
#define socket socket_t
class socket_impl : public socket {
public:
socket_impl(int fd) { this->fd = fd; }
/*private*/ int fixret(int ret)
{
//printf("r=%i e=%i wb=%i\n", ret, WSAGetLastError(), WSAEWOULDBLOCK);
if (ret > 0) return ret;
if (ret == 0) return e_closed;
#ifdef __unix__
if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) return 0;
#endif
#ifdef _WIN32
if (ret < 0 && WSAGetLastError() == WSAEWOULDBLOCK) return 0;
#endif
return e_broken;
}
int recv(uint8_t* data, unsigned int len, bool block = false)
{
return fixret(::recv(fd, (char*)data, len, MSG_NOSIGNAL | (block ? 0 : MSG_DONTWAIT)));
}
int sendp(const uint8_t* data, unsigned int len, bool block = true)
{
//printf("snd=%i\n",len);
return fixret(::send(fd, (char*)data, len, MSG_NOSIGNAL | (block ? 0 : MSG_DONTWAIT)));
}
~socket_impl()
{
close(fd);
}
};
static socket* socket_wrap(int fd)
{
if (fd<0) return NULL;
return new socket_impl(fd);
}
}
socket* socket::create_from_fd(int fd)
{
return socket_wrap(fd);
}
socket* socket::create(const char * domain, int port)
{
return socket_wrap(connect(domain, port));
}
//static socket* create_async(const char * domain, int port);
//static socket* create_udp(const char * domain, int port);
//int socket::select(socket* * socks, int nsocks, int timeout_ms)
//{
// return -1;
//}

99
arlib/socket/socket.h Normal file
View File

@@ -0,0 +1,99 @@
#include "../global.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#define socket socket_t
class socket : nocopy {
protected:
socket(){}
int fd; // Used by select().
//deallocates the socket, returning its fd, while letting the fd remain valid
static int decompose(socket* sock) { int ret = sock->fd; sock->fd=-1; delete sock; return ret; }
public:
//Returns NULL on connection failure.
static socket* create(const char * domain, int port);
//Always succeeds. If the server can't be contacted, returns failure on first write or read.
static socket* create_async(const char * domain, int port);
static socket* create_udp(const char * domain, int port);
enum {
e_lazy_dev = -1, // Whoever implemented this socket layer was lazy and just returned -1. Treat it as e_broken or an unknown error.
e_closed = -2, // Remote host chose to gracefully close the connection.
e_broken = -3, // Connection was forcibly torn down.
e_udp_too_big = -4, // Attempted to process an unacceptably large UDP packet.
e_ssl_failure = -5, // Certificate validation failed, no algorithms in common, or other SSL error.
};
//Negative means error, see above.
//Positive is number of bytes handled.
//WARNING: Unlike most socket layers, zero does not mean graceful close!
// It means success, zero bytes processed, and is a valid byte count. Socket closed is in the error list above.
//The first two functions will process at least one byte, or if block is false, at least zero. send() sends all bytes before returning.
//block is ignored on Windows (always false), due to lack of MSG_NOWAIT and I don't want to do another syscall every time.
//For UDP sockets, partial reads or writes aren't possible; you always get one or zero packets.
virtual int recv(uint8_t* data, unsigned int len, bool block = true) = 0;
virtual int sendp(const uint8_t* data, unsigned int len, bool block = true) = 0;
int send(const uint8_t* data, unsigned int len)
{
unsigned int sent = 0;
while (sent < len)
{
int here = sendp(data+sent, len-sent);
if (here<0) return here;
sent += here;
}
return len;
}
//Convenience functions for handling textual data.
int recv(char* data, unsigned int len, bool block = false)
{
int ret = recv((uint8_t*)data, len-1, block);
if (ret >= 0) data[ret]='\0';
else data[0]='\0';
return ret;
}
int sendp(const char * data, bool block = true) { return sendp((uint8_t*)data, strlen(data), block); }
int send (const char * data) { return send((uint8_t*)data, strlen(data)); }
//Returns an index to the sockets array, or negative if timeout expires.
//Negative timeouts mean wait forever.
//It's possible that an active socket returns zero bytes.
//However, this is guaranteed to happen rarely enough that repeatedly select()ing will leave the CPU mostly idle.
//(It may be caused by packets with wrong checksum, SSL renegotiation, or whatever.)
static int select(socket* * socks, unsigned int nsocks, int timeout_ms = -1);
virtual ~socket() {}
//Can be used to keep a socket alive across exec(). Don't use for an SSL socket.
static socket* create_from_fd(int fd);
int get_fd() { return fd; }
};
class socketssl : public socket {
protected:
socketssl(){}
public:
//If 'permissive' is true, expired and self-signed server certificates will be accepted.
//Other invalid certs, such as ones for a different domain, may or may not be accepted.
static socketssl* create(const char * domain, int port, bool permissive=false)
{
return socketssl::create(socket::create(domain, port), domain, permissive);
}
//On entry, this takes ownership of the socket. Even if connection fails, the socket may not be used anymore.
//The socket must be a normal TCP socket. UDP and nested SSL is not supported.
static socketssl* create(socket* parent, const char * domain, bool permissive=false);
virtual void q(){}
//Can be used to keep a socket alive across exec().
//If successful, serialize() returns the the file descriptor needed to unserialize, and the socket is deleted.
//If failure, negative return and nothing happens.
virtual size_t serialize_size() { return 0; }
virtual int serialize(uint8_t* data, size_t len) { return -1; }
static socketssl* unserialize(int fd, const uint8_t* data, size_t len);
};

109
arlib/socket/test.c Normal file
View File

@@ -0,0 +1,109 @@
#include <stdio.h>
#include <sys/types.h>
#include <stdlib.h>
#ifdef _WIN32
#include <winsock2.h>
#define socklen_t int
#define sleep(x) Sleep(x*1000)
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#endif
#include "tlse.c"
void error(char *msg) {
perror(msg);
exit(0);
}
int send_pending(int client_sock, struct TLSContext *context) {
unsigned int out_buffer_len = 0;
const unsigned char *out_buffer = tls_get_write_buffer(context, &out_buffer_len);
unsigned int out_buffer_index = 0;
int send_res = 0;
while ((out_buffer) && (out_buffer_len > 0)) {
int res = send(client_sock, (char *)&out_buffer[out_buffer_index], out_buffer_len, 0);
if (res <= 0) {
send_res = res;
break;
}
out_buffer_len -= res;
out_buffer_index += res;
}
tls_buffer_clear(context);
return send_res;
}
int validate_certificate(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len) {
int i;
if (certificate_chain) {
for (i = 0; i < len; i++) {
struct TLSCertificate *certificate = certificate_chain[i];
// check certificate ...
}
}
//return certificate_expired;
//return certificate_revoked;
//return certificate_unknown;
return no_error;
}
int main(int argc, char *argv[]) {
int sockfd, portno, n;
//tls_print_certificate("testcert/server.certificate");
//tls_print_certificate("000.certificate");
//exit(0);
struct sockaddr_in serv_addr;
struct hostent *server;
char buffer[256];
char *ref_argv[] = {"", "google.com", "443"};
if (argc < 3) {
argv = ref_argv;
//fprintf(stderr,"usage %s hostname port\n", argv[0]);
//exit(0);
}
#ifdef _WIN32
WSADATA wsaData;
WSAStartup(MAKEWORD(2, 2), &wsaData);
#else
signal(SIGPIPE, SIG_IGN);
#endif
portno = atoi(argv[2]);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
server = gethostbyname(argv[1]);
if (server == NULL) {
fprintf(stderr,"ERROR, no such host\n");
exit(0);
}
memset((char *) &serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
memcpy((char *)&serv_addr.sin_addr.s_addr, (char *)server->h_addr, server->h_length);
serv_addr.sin_port = htons(portno);
if (connect(sockfd,(struct sockaddr *)&serv_addr,sizeof(serv_addr)) < 0)
error("ERROR connecting");
struct TLSContext *context = tls_create_context(0, TLS_V12);
tls_client_connect(context);
send_pending(sockfd, context);
unsigned char client_message[0xFFFF];
int read_size;
while ((read_size = recv(sockfd, client_message, sizeof(client_message) , 0)) > 0) {
tls_consume_stream(context, client_message, read_size, validate_certificate);
send_pending(sockfd, context);
if (tls_established(context)) {
const char * out = "GET / HTTP/1.1\nHost: example.com\nConnection: close\n\n";
tls_write(context, out, strlen(out));
send_pending(sockfd, context);
unsigned char read_buffer[0xFFFF];
int read_size = tls_read(context, read_buffer, 0xFFFF - 1);
if (read_size > 0)
fwrite(read_buffer, read_size, 1, stdout);
}
}
return 0;
}

7974
arlib/socket/tlse.c Normal file

File diff suppressed because it is too large Load Diff

276
arlib/socket/tlse.h Normal file
View File

@@ -0,0 +1,276 @@
// from https://github.com/eduardsui/tlse
#ifndef TLSE_H
#define TLSE_H
// #define DEBUG
// define TLS_LEGACY_SUPPORT to support TLS 1.1/1.0 (legacy)
// legacy support it will use an additional 272 bytes / context
#define TLS_LEGACY_SUPPORT
// SSL_* style blocking APIs
#define SSL_COMPATIBLE_INTERFACE
// support forward secrecy (Diffie-Hellman ephemeral)
#define TLS_FORWARD_SECRECY
// support client-side ECDHE
#define TLS_CLIENT_ECDHE
// suport ecdsa
#define TLS_ECDSA_SUPPORTED
// TLS renegotiation is disabled by default (secured or not)
// do not uncomment next line!
// #define TLS_ACCEPT_SECURE_RENEGOTIATION
#define TLS_V10 0x0301
#define TLS_V11 0x0302
#define TLS_V12 0x0303
#define DTLS_V10 0xFEFF
#define DTLS_V12 0xFEFD
#define TLS_NEED_MORE_DATA 0
#define TLS_GENERIC_ERROR -1
#define TLS_BROKEN_PACKET -2
#define TLS_NOT_UNDERSTOOD -3
#define TLS_NOT_SAFE -4
#define TLS_NO_COMMON_CIPHER -5
#define TLS_UNEXPECTED_MESSAGE -6
#define TLS_CLOSE_CONNECTION -7
#define TLS_COMPRESSION_NOT_SUPPORTED -8
#define TLS_NO_MEMORY -9
#define TLS_NOT_VERIFIED -10
#define TLS_INTEGRITY_FAILED -11
#define TLS_ERROR_ALERT -12
#define TLS_BROKEN_CONNECTION -13
#define TLS_BAD_CERTIFICATE -14
#define TLS_UNSUPPORTED_CERTIFICATE -15
#define TLS_NO_RENEGOTIATION -16
#define TLS_FEATURE_NOT_SUPPORTED -17
#define TLS_RSA_WITH_AES_128_CBC_SHA 0x002F
#define TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
#define TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C
#define TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D
#define TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C
#define TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D
// forward secrecy
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039
#define TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067
#define TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B
#define TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E
#define TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013
#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014
#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027
#define TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F
#define TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A
#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024
#define TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
#define TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C
#define TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8
#define TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9
#define TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA
#define TLS_FALLBACK_SCSV 0x5600
#define TLS_UNSUPPORTED_ALGORITHM 0x00
#define TLS_RSA_SIGN_RSA 0x01
#define TLS_RSA_SIGN_MD5 0x04
#define TLS_RSA_SIGN_SHA1 0x05
#define TLS_RSA_SIGN_SHA256 0x0B
#define TLS_RSA_SIGN_SHA384 0x0C
#define TLS_RSA_SIGN_SHA512 0x0D
#define TLS_EC_PUBLIC_KEY 0x11
#define TLS_EC_prime192v1 0x12
#define TLS_EC_prime192v2 0x13
#define TLS_EC_prime192v3 0x14
#define TLS_EC_prime239v1 0x15
#define TLS_EC_prime239v2 0x16
#define TLS_EC_prime239v3 0x17
#define TLS_EC_prime256v1 0x18
#define TLS_EC_secp224r1 21
#define TLS_EC_secp256r1 23
#define TLS_EC_secp384r1 24
#define TLS_EC_secp521r1 25
#define TLS_ALERT_WARNING 0x01
#define TLS_ALERT_CRITICAL 0x02
typedef enum {
close_notify = 0,
unexpected_message = 10,
bad_record_mac = 20,
decryption_failed_RESERVED = 21,
record_overflow = 22,
decompression_failure = 30,
handshake_failure = 40,
no_certificate_RESERVED = 41,
bad_certificate = 42,
unsupported_certificate = 43,
certificate_revoked = 44,
certificate_expired = 45,
certificate_unknown = 46,
illegal_parameter = 47,
unknown_ca = 48,
access_denied = 49,
decode_error = 50,
decrypt_error = 51,
export_restriction_RESERVED = 60,
protocol_version = 70,
insufficient_security = 71,
internal_error = 80,
inappropriate_fallback = 86,
user_canceled = 90,
no_renegotiation = 100,
unsupported_extension = 110,
no_error = 255
} TLSAlertDescription;
// forward declarations
struct TLSPacket;
struct TLSCertificate;
struct TLSContext;
struct ECCCurveParameters;
typedef struct TLSContext TLS;
typedef struct TLSCertificate Certificate;
typedef int (*tls_validation_function)(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len);
unsigned char *tls_pem_decode(const unsigned char *data_in, unsigned int input_length, int cert_index, unsigned int *output_len);
struct TLSCertificate *tls_create_certificate();
int tls_certificate_valid_subject(struct TLSCertificate *cert, const char *subject);
int tls_certificate_valid_subject_name(const unsigned char *cert_subject, const char *subject);
int tls_certificate_is_valid(struct TLSCertificate *cert);
void tls_certificate_set_copy(unsigned char **member, const unsigned char *val, int len);
void tls_certificate_set_copy_date(unsigned char **member, const unsigned char *val, int len);
void tls_certificate_set_key(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_priv(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_sign_key(struct TLSCertificate *cert, const unsigned char *val, int len);
char *tls_certificate_to_string(struct TLSCertificate *cert, char *buffer, int len);
void tls_certificate_set_exponent(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_serial(struct TLSCertificate *cert, const unsigned char *val, int len);
void tls_certificate_set_algorithm(unsigned int *algorithm, const unsigned char *val, int len);
void tls_destroy_certificate(struct TLSCertificate *cert);
struct TLSPacket *tls_create_packet(struct TLSContext *context, unsigned char type, unsigned short version, int payload_size_hint);
void tls_destroy_packet(struct TLSPacket *packet);
void tls_packet_update(struct TLSPacket *packet);
int tls_packet_append(struct TLSPacket *packet, unsigned char *buf, unsigned int len);
int tls_packet_uint8(struct TLSPacket *packet, unsigned char i);
int tls_packet_uint16(struct TLSPacket *packet, unsigned short i);
int tls_packet_uint32(struct TLSPacket *packet, unsigned int i);
int tls_packet_uint24(struct TLSPacket *packet, unsigned int i);
int tls_random(unsigned char *key, int len);
const unsigned char *tls_get_write_buffer(struct TLSContext *context, unsigned int *outlen);
void tls_buffer_clear(struct TLSContext *context);
int tls_established(struct TLSContext *context);
void tls_read_clear(struct TLSContext *context);
int tls_read(struct TLSContext *context, unsigned char *buf, unsigned int size);
struct TLSContext *tls_create_context(unsigned char is_server, unsigned short version);
const struct ECCCurveParameters *tls_set_curve(struct TLSContext *context, const struct ECCCurveParameters *curve);
struct TLSContext *tls_accept(struct TLSContext *context);
int tls_set_default_dhe_pg(struct TLSContext *context, const char *p_hex_str, const char *g_hex_str);
void tls_destroy_context(struct TLSContext *context);
int tls_cipher_supported(struct TLSContext *context, unsigned short cipher);
int tls_cipher_is_fs(struct TLSContext *context, unsigned short cipher);
int tls_choose_cipher(struct TLSContext *context, const unsigned char *buf, int buf_len, int *scsv_set);
int tls_cipher_is_ephemeral(struct TLSContext *context);
const char *tls_cipher_name(struct TLSContext *context);
int tls_is_ecdsa(struct TLSContext *context);
struct TLSPacket *tls_build_client_key_exchange(struct TLSContext *context);
struct TLSPacket *tls_build_server_key_exchange(struct TLSContext *context, int method);
struct TLSPacket *tls_build_hello(struct TLSContext *context);
struct TLSPacket *tls_certificate_request(struct TLSContext *context);
struct TLSPacket *tls_build_verify_request(struct TLSContext *context);
int tls_parse_hello(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets, unsigned int *dtls_verified);
int tls_parse_certificate(struct TLSContext *context, const unsigned char *buf, int buf_len, int is_client);
int tls_parse_server_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_client_key_exchange(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_server_hello_done(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_finished(struct TLSContext *context, const unsigned char *buf, int buf_len, unsigned int *write_packets);
int tls_parse_verify(struct TLSContext *context, const unsigned char *buf, int buf_len);
int tls_parse_payload(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
int tls_parse_message(struct TLSContext *context, unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
int tls_certificate_verify_signature(struct TLSCertificate *cert, struct TLSCertificate *parent);
int tls_certificate_chain_is_valid(struct TLSCertificate **certificates, int len);
int tls_certificate_chain_is_valid_root(struct TLSContext *context, struct TLSCertificate **certificates, int len);
int tls_load_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
int tls_load_private_key(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
struct TLSPacket *tls_build_certificate(struct TLSContext *context);
struct TLSPacket *tls_build_finished(struct TLSContext *context);
struct TLSPacket *tls_build_change_cipher_spec(struct TLSContext *context);
struct TLSPacket *tls_build_done(struct TLSContext *context);
struct TLSPacket *tls_build_message(struct TLSContext *context, unsigned char *data, unsigned int len);
int tls_client_connect(struct TLSContext *context);
int tls_write(struct TLSContext *context, unsigned char *data, unsigned int len);
struct TLSPacket *tls_build_alert(struct TLSContext *context, char critical, unsigned char code);
int tls_consume_stream(struct TLSContext *context, const unsigned char *buf, int buf_len, tls_validation_function certificate_verify);
void tls_close_notify(struct TLSContext *context);
void tls_alert(struct TLSContext *context, unsigned char critical, int code);
int tls_pending(struct TLSContext *context);
void tls_make_exportable(struct TLSContext *context, unsigned char exportable_flag);
int tls_export_context(struct TLSContext *context, unsigned char *buffer, unsigned int buf_len, unsigned char small_version);
struct TLSContext *tls_import_context(unsigned char *buffer, unsigned int buf_len);
int tls_is_broken(struct TLSContext *context);
int tls_request_client_certificate(struct TLSContext *context);
int tls_client_verified(struct TLSContext *context);
const char *tls_sni(struct TLSContext *context);
int tls_sni_set(struct TLSContext *context, const char *sni);
int tls_load_root_certificates(struct TLSContext *context, const unsigned char *pem_buffer, int pem_size);
int tls_default_verify(struct TLSContext *context, struct TLSCertificate **certificate_chain, int len);
void tls_print_certificate(const char *fname);
#ifdef SSL_COMPATIBLE_INTERFACE
#define SSL_SERVER_RSA_CERT 1
#define SSL_SERVER_RSA_KEY 2
typedef struct TLSContext SSL_CTX;
typedef struct TLSContext SSL;
#define SSL_FILETYPE_PEM 1
#define SSL_VERIFY_NONE 0
#define SSL_VERIFY_PEER 1
#define SSL_VERIFY_FAIL_IF_NO_PEER_CERT 2
#define SSL_VERIFY_CLIENT_ONCE 3
typedef struct {
int fd;
tls_validation_function certificate_verify;
void *user_data;
} SSLUserData;
int SSL_library_init();
void SSL_load_error_strings();
void OpenSSL_add_all_algorithms();
void OpenSSL_add_all_ciphers();
void OpenSSL_add_all_digests();
void EVP_cleanup();
int SSLv3_server_method();
int SSLv3_client_method();
struct TLSContext *SSL_new(struct TLSContext *context);
int SSL_CTX_use_certificate_file(struct TLSContext *context, const char *filename, int dummy);
int SSL_CTX_use_PrivateKey_file(struct TLSContext *context, const char *filename, int dummy);
int SSL_CTX_check_private_key(struct TLSContext *context);
struct TLSContext *SSL_CTX_new(int method);
void SSL_free(struct TLSContext *context);
void SSL_CTX_free(struct TLSContext *context);
int SSL_get_error(struct TLSContext *context, int ret);
int SSL_set_fd(struct TLSContext *context, int socket);
void *SSL_set_userdata(struct TLSContext *context, void *data);
void *SSL_userdata(struct TLSContext *context);
int SSL_CTX_root_ca(struct TLSContext *context, const char *pem_filename);
void SSL_CTX_set_verify(struct TLSContext *context, int mode, tls_validation_function verify_callback);
int SSL_accept(struct TLSContext *context);
int SSL_connect(struct TLSContext *context);
int SSL_shutdown(struct TLSContext *context);
int SSL_write(struct TLSContext *context, void *buf, unsigned int len);
int SSL_read(struct TLSContext *context, void *buf, unsigned int len);
int SSL_pending(struct TLSContext *context);
#endif
#endif

1555
arlib/socket/uuu.cpp Normal file

File diff suppressed because it is too large Load Diff

141
arlib/socket/wolfssl-lib.c Normal file
View File

@@ -0,0 +1,141 @@
#ifdef ARLIB_SSL_WOLFSSL_SP
//I'll have to #include the parts of WolfSSL I need
//it's easier in preprocessor than in makefile
#define DEBUG_WOLFSSL
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
//#define NO_WOLFSSL_MEMORY // use malloc like a sane program
//#define NO_WOLFSSL_DIR // we scan the directories ourelves
//#define WOLFSSL_USER_IO // we set our own read/write callbacks
#ifdef _WIN32
#define USE_WINDOWS_API
#else
#define WOLFSSL_PTHREADS
#endif
//#ifndef ARLIB_THREAD
//#define SINGLE_THREADED
//#endif
//got these from ./configure
#define HAVE_THREAD_LS
#define HAVE_AESGCM
#define WOLFSSL_SHA512
#define WOLFSSL_SHA384
#define NO_DSA
#define HAVE_ECC
#define TFM_ECC256
#define ECC_SHAMIR
#define NO_RC4
#define NO_HC128
#define NO_RABBIT
#define HAVE_POLY1305
#define HAVE_ONE_TIME_AUTH
#define HAVE_CHACHA
#define HAVE_HASHDRBG
#define HAVE_TLS_EXTENSIONS
#define HAVE_SUPPORTED_CURVES
#define NO_PSK
#define NO_MD4
#define NO_PWDBASED
#define USE_FAST_MATH
#define WOLFSSL_X86_64_BUILD
#define HAVE___UINT128_T
#include "wolfssl-3.9.0/src/crl.c"
#include "wolfssl-3.9.0/src/internal.c"
#define c16toa c16toa_b // these functions are copypasted. should be in a header
#define c32toa c32toa_b
#define ato16 ato16_b
#define c24to32 c24to32_b
#define GetSEQIncrement GetSEQIncrement_b
#include "wolfssl-3.9.0/src/io.c"
#include "wolfssl-3.9.0/src/keys.c"
#include "wolfssl-3.9.0/src/ocsp.c"
#include "wolfssl-3.9.0/src/sniffer.c"
#include "wolfssl-3.9.0/src/ssl.c"
#include "wolfssl-3.9.0/src/tls.c"
#include "wolfssl-3.9.0/wolfcrypt/src/aes.c"
#include "wolfssl-3.9.0/wolfcrypt/src/arc4.c"
//#include "wolfssl-3.9.0/wolfcrypt/src/asm.c"
#include "wolfssl-3.9.0/wolfcrypt/src/asn.c"
#include "wolfssl-3.9.0/wolfcrypt/src/blake2b.c"
#include "wolfssl-3.9.0/wolfcrypt/src/camellia.c"
#include "wolfssl-3.9.0/wolfcrypt/src/chacha20_poly1305.c"
#include "wolfssl-3.9.0/wolfcrypt/src/chacha.c"
#include "wolfssl-3.9.0/wolfcrypt/src/coding.c"
#include "wolfssl-3.9.0/wolfcrypt/src/compress.c"
#include "wolfssl-3.9.0/wolfcrypt/src/curve25519.c"
#include "wolfssl-3.9.0/wolfcrypt/src/des3.c"
#include "wolfssl-3.9.0/wolfcrypt/src/dh.c"
#include "wolfssl-3.9.0/wolfcrypt/src/dsa.c"
#include "wolfssl-3.9.0/wolfcrypt/src/ecc.c"
#include "wolfssl-3.9.0/wolfcrypt/src/ecc_fp.c"
#include "wolfssl-3.9.0/wolfcrypt/src/ed25519.c"
#include "wolfssl-3.9.0/wolfcrypt/src/error.c"
#include "wolfssl-3.9.0/wolfcrypt/src/fe_low_mem.c"
#include "wolfssl-3.9.0/wolfcrypt/src/fe_operations.c"
#include "wolfssl-3.9.0/wolfcrypt/src/ge_low_mem.c"
#include "wolfssl-3.9.0/wolfcrypt/src/ge_operations.c"
#include "wolfssl-3.9.0/wolfcrypt/src/hash.c"
#include "wolfssl-3.9.0/wolfcrypt/src/hc128.c"
#include "wolfssl-3.9.0/wolfcrypt/src/hmac.c"
#include "wolfssl-3.9.0/wolfcrypt/src/idea.c"
#include "wolfssl-3.9.0/wolfcrypt/src/integer.c"
#include "wolfssl-3.9.0/wolfcrypt/src/logging.c"
#include "wolfssl-3.9.0/wolfcrypt/src/md2.c"
#define Transform Transform_md4 // several functions and macros exist multiple times
#define AddLength AddLength_md4
#include "wolfssl-3.9.0/wolfcrypt/src/md4.c"
#undef Transform
#undef AddLength
#define Transform Transform_md5
#define AddLength AddLength_md5
#include "wolfssl-3.9.0/wolfcrypt/src/md5.c"
#undef Transform
#undef AddLength
#undef XTRANSFORM
#include "wolfssl-3.9.0/wolfcrypt/src/memory.c"
#include "wolfssl-3.9.0/wolfcrypt/src/misc.c"
#include "wolfssl-3.9.0/wolfcrypt/src/pkcs7.c"
#include "wolfssl-3.9.0/wolfcrypt/src/poly1305.c"
#undef LO
#include "wolfssl-3.9.0/wolfcrypt/src/pwdbased.c"
#include "wolfssl-3.9.0/wolfcrypt/src/rabbit.c"
#include "wolfssl-3.9.0/wolfcrypt/src/random.c"
#include "wolfssl-3.9.0/wolfcrypt/src/ripemd.c"
#include "wolfssl-3.9.0/wolfcrypt/src/rsa.c"
#define Transform Transform_sha256
#define AddLength AddLength_sha256
#include "wolfssl-3.9.0/wolfcrypt/src/sha256.c"
#undef Ch
#undef Maj
#undef R
#undef R2
#undef blk0
#undef Transform
#undef AddLength
#include "wolfssl-3.9.0/wolfcrypt/src/sha512.c"
#undef Ch
#undef Maj
#undef R
#undef R2
#undef blk0
#undef XTRANSFORM
#define _Transform _Transform_sha
#define AddLength AddLength_sha
#include "wolfssl-3.9.0/wolfcrypt/src/sha.c"
#undef Transform
#undef AddLength
#include "wolfssl-3.9.0/wolfcrypt/src/signature.c"
#include "wolfssl-3.9.0/wolfcrypt/src/srp.c"
#include "wolfssl-3.9.0/wolfcrypt/src/tfm.c"
#include "wolfssl-3.9.0/wolfcrypt/src/wc_encrypt.c"
#include "wolfssl-3.9.0/wolfcrypt/src/wc_port.c"
#endif