adding more and more ;

v0.5.xx
Alexander Vdolainen 9 years ago
parent 2d20080776
commit b09d7d6a10

@ -0,0 +1,287 @@
/*
* Secure Network Transport Layer Library v2 implementation.
* (sntllv2) it superseed all versions before due to the:
* - memory consumption
* - new features such as pulse emitting
* - performance optimization
*
* This is a proprietary software. See COPYING for further details.
*
* (c) Askele Group 2013-2015 <http://askele.com>
*
*/
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#ifdef WIN32
#include <Winsock2.h>
#define EBADE 1
#define NETDB_SUCCESS 0
#else
#include <sys/select.h>
#include <netdb.h>
#include <unistd.h>
#include <uuid/uuid.h>
#endif
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <tdata/usrtc.h>
#include <sexpr/sexp.h>
#include <sntl/connection.h>
static int ex_ssldata_index; /** < index used to work with additional data
* provided to the special call during SSL handshake */
/* this function is an ugly implementation to get C string with uuid */
extern char *__generate_uuid(void);
/* this is a callback to perform a custom SSL certs chain validation,
* as I promised here the comments, a lot of ...
* The first shit: 0 means validation failed, 1 otherwise
* The second shit: X509 API, I guess u will love it ;-)
* openssl calls this function for each certificate in chain,
* since our case is a simple (depth of chain is one, since we're
* don't care for public certificates lists or I cannot find any reasons to
* do it ...), amount of calls reduced, and in this case we're interested
* only in top of chain i.e. actual certificate used on client side,
* the validity of signing for other certificates within chain is
* guaranteed by the ssl itself.
* u know, we need to lookup in database, or elsewhere... some information
* about client certificate, and decide - is it valid, or not?, if so
* yep I mean it's valid, we can assign it's long fucking number to
* security context, to use in ongoing full scaled connection handshaking.
*/
static int __verify_certcall(int preverify_ok, X509_STORE_CTX *ctx)
{
// X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
int err = X509_STORE_CTX_get_error(ctx), depth = X509_STORE_CTX_get_error_depth(ctx);
SSL *ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
conn_t *co = SSL_get_ex_data(ssl, ex_ssldata_index); /* this is a custom data we're set before */
conn_sys_t *ssys = co->ssys;
/* now we need to check for certificates with a long chain,
* so since we have a short one, reject long ones */
if(depth > VERIFY_DEPTH) { /* longer than we expect */
preverify_ok = 0; /* yep, 0 means error for those function callback in openssl, fucking set */
err = X509_V_ERR_CERT_CHAIN_TOO_LONG;
X509_STORE_CTX_set_error(ctx, err);
}
if(!preverify_ok) return 0;
/* ok, now we're on top of SSL (depth == 0) certs chain,
* and we can validate client certificate */
if(!depth) {
co->pctx->certid =
ASN1_INTEGER_get((const ASN1_INTEGER *)X509_get_serialNumber(ctx->current_cert));
/* now we're need to check the ssl cert */
if(ssys->validate_sslpem) {
if(ssys->validate_sslpem(co)) return 0;
else return 1;
} else return 0;
}
return preverify_ok;
}
/* dummy just to check the server side */
static int __verify_certcall_dummy(int preverify_ok, X509_STORE_CTX *ctx)
{
return preverify_ok;
}
int sntl_init(void)
{
/* init SSL library */
SSL_library_init();
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
ex_ssldata_index = SSL_get_ex_new_index(0, "__ssldata index", NULL, NULL, NULL);
return 0;
}
conn_t *__connection_minimal_alloc(struct in_addr *addr)
{
conn_t *co = malloc(sizeof(conn_t));
int r;
if(!co) { r = ENOMEM; goto __fail; }
else memset(co, 0, sizeof(conn_t));
if(!(co->messages = malloc(sizeof(uintptr_t)*1024))) { r = ENOMEM; goto __fail; }
else memset(co->messages, 0, sizeof(uintptr_t)*1024);
if(!(co->pctx = malloc(sizeof(perm_ctx_t)))) { r = ENOMEM; goto __fail; }
else memset(co->pctx, 0, sizeof(perm_ctx_t));
if(addr) {
if(!(co->pctx->addr = malloc(sizeof(struct in_addr)))) { r = ENOMEM; goto __fail; }
memcpy(co->pctx->addr, addr, sizeof(struct in_addr));
}
if(!(co->uuid = __generate_uuid())) { r = ENOMEM; goto __fail; }
return co;
__fail:
if(co) {
if(co->pctx) {
if(co->pctx->addr) free(co->pctx->addr);
free(co->pctx);
}
if(co->messages) free(co->messages);
free(co);
}
errno = r;
return NULL;
}
static void __connection_minimal_free(conn_t *co)
{
if(co) {
if(co->pctx) {
if(co->pctx->addr) free(co->pctx->addr);
free(co->pctx);
}
if(co->messages) free(co->messages);
free(co->uuid);
free(co);
}
return;
}
int connection_create_fapi_m(conn_sys_t *ssys, conn_t *co, int sck,
struct in_addr *addr)
{
void *buf = NULL;
char *bbuf;
conn_t *coc = __connection_minimal_alloc(addr);
sx_msg_t *msg = NULL;
sntllv2_head_t *head;
size_t rd;
if(!coc) return SNE_ENOMEM;
/* ok, now we need to init ssl stuff */
co->ssys = ssys;
/* init SSL certificates and context */
co->ctx = SSL_CTX_new(TLSv1_2_server_method());
if(!co->ctx) { goto __fail; }
else {
/* set verify context */
SSL_CTX_set_verify(co->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
__verify_certcall);
/* set verify depth */
SSL_CTX_set_verify_depth(co->ctx, VERIFY_DEPTH);
}
/* load certificates */
SSL_CTX_load_verify_locations(co->ctx, ssys->rootca, NULL);
/* set the local certificate from CertFile */
if(SSL_CTX_use_certificate_file(co->ctx, ssys->certpem,
SSL_FILETYPE_PEM)<=0) {
ERR_print_errors_fp(stderr);
goto __fail;
}
/* set the private key from KeyFile (may be the same as CertFile) */
if(SSL_CTX_use_PrivateKey_file(co->ctx, ssys->certkey,
SSL_FILETYPE_PEM)<=0) {
goto __fail;
}
/* verify private key */
if (!SSL_CTX_check_private_key(co->ctx)) {
goto __fail;
}
/* now we will create an SSL connection */
co->ssl = SSL_new(co->ctx);
if(!co->ssl) goto __fail;
else SSL_set_fd(co->ssl, sck); /* attach connected socket */
SSL_set_accept_state(co->ssl);
/* set the context to verify ssl connection */
SSL_set_ex_data(co->ssl, ex_ssldata_index, (void *)co);
SSL_set_accept_state(co->ssl);
if(SSL_accept(co->ssl) == -1) {
goto __fail;
}
/* ok, now we are able to allocate and so on */
/* set connection to the batch mode */
co->flags |= SNSX_BATCHMODE;
/* allocate our first buffer */
buf = mmap(NULL, 65536, PROT_READ|PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if(buf == MAP_FAILED) goto __fail2;
/* allocate first message */
if(!(msg = malloc(sizeof(sx_msg_t)))) goto __fail2;
else {
memset(msg, 0, sizeof(sx_msg_t));
coc->messages[0] = msg;
}
bbuf = (char *)buf;
bbuf += sizeof(sntllv2_head_t);
sexp_t *sx;
while(co->flags & SNSX_BATCHMODE) {
rd = __conn_read(co, buf, sizeof(sntllv2_head_t));
if(rd == sizeof(sntllv2_head_t)) {
head = (sntllv2_head_t *)buf;
/* check for returns */
if(head->opcode != SNE_SUCCESS) goto __fail3;
rd = __conn_read(co, bbuf, head->payload_length);
if(rd != head->payload_length) goto __fail3;
bbuf[rd] = '\0';
sx = parse_sexp(bbuf, rd);
if(!sx) goto __fail3;
/* initialize message */
msg->payload = bbuf;
msg->payload_length = 0;
/* deal with it */
r = __eval_syssexp(co, sx);
if(r != SNE_SUCCESS) { /* fuck */
head->opcode = r;
head->payload_length = 0;
__conn_write(co, buf, sizeof(sntllv2_head_t));
goto __fail3;
}
destroy_sexp(sx);
} else goto __fail3;
}
return SNE_SUCCESS;
__fail3:
if(ssys->on_destroy) ssys->on_destroy(co);
__fail2:
if(msg) free(msg);
if(buf != MAP_FAILED) munmap(buf, 65536);
SSL_shutdown(co->ssl);
__fail:
if(coc) {
if(co->ssl) SSL_free(co->ssl);
if(co->ctx) SSL_CTX_free(co->ctx);
__connection_minimal_free(coc);
}
close(sck);
return SNE_FAILED;
}
Loading…
Cancel
Save