adding more and more ;
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…
Reference in New Issue