From b09d7d6a1089f2f294f269c01b7e7bced58185f2 Mon Sep 17 00:00:00 2001 From: Alexander Vdolainen Date: Fri, 17 Jul 2015 03:27:22 +0300 Subject: [PATCH] adding more and more ; --- lib/sntllv2.c | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 287 insertions(+) create mode 100644 lib/sntllv2.c diff --git a/lib/sntllv2.c b/lib/sntllv2.c new file mode 100644 index 0000000..a05fcfe --- /dev/null +++ b/lib/sntllv2.c @@ -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 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef WIN32 +#include +#define EBADE 1 +#define NETDB_SUCCESS 0 +#else +#include +#include +#include +#include +#endif + +#include +#include + +#include +#include + +#include + +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; +}