/* * Secure X Message Passing Library v2 implementation. * (sxmplv2) it superseed all versions before due to the: * - memory consumption * - new features such as pulse emitting * - performance optimization * * (c) Askele Group 2013-2015 * (c) Alexander Vdolainen 2013-2015, 2016 * * libsxmp is free software: you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation, either version 2.1 of the License, or * (at your option) any later version. * * libsxmp is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see ."; * */ #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 #include #include "internal.h" static int __insert_rpc_function(usrtc_t *tree, const char *name, int (*rpcf)(void *, sexp_t *)) { sxl_rpc_t *ent = malloc(sizeof(sxl_rpc_t)); usrtc_node_t *node; if(!ent) return ENOMEM; else node = &ent->node; if(!(ent->name = strdup(name))) { free(ent); return ENOMEM; } else ent->rpcf = rpcf; usrtc_node_init(node, ent); usrtc_insert(tree, node, ent->name); return 0; } static void __destroy_rpc_list_tree(usrtc_t *tree) { usrtc_node_t *node; sxl_rpc_t *ent; for(node = usrtc_first(tree); node != NULL; node = usrtc_first(tree)) { ent = (sxl_rpc_t *)usrtc_node_getdata(node); usrtc_delete(tree, node); free(ent->name); free(ent); } return; } /* negotiation functions */ /** * Proto: (auth-set-credentials "" "") * Return - message return; opcode as a return of this function. * in batch mode message with 0 index used always */ static int __set_credentials(void *cctx, sexp_t *sx) { register int idx; sxlink_t *link = (sxlink_t *)cctx; sxhub_t *hub = link->hub; sexp_t *isx; char *login = NULL; char *passwd = NULL; /* take a deal with S-exp */ SEXP_ITERATE_LIST(sx, isx, idx) { if(isx->ty == SEXP_LIST) return SXE_BADPROTO; if(idx > 0 && isx->aty != SEXP_DQUOTE) return SXE_BADPROTO; if(idx == 1) login = isx->val; else if(idx == 2) passwd = isx->val; else if(idx > 2) return SXE_BADPROTO; } if(!login || !passwd) return SXE_BADPROTO; link->pctx->login = strdup(login); link->pctx->passwd = strdup(passwd); if(!link->pctx->login || !link->pctx->passwd) { if(link->pctx->login) free(link->pctx->login); if(link->pctx->passwd) free(link->pctx->passwd); return SXE_ENOMEM; } if(hub->secure_check) return hub->secure_check(link); else return SXE_SUCCESS; } static int __get_channels_list(void *cctx, sexp_t *sx) { sxlink_t *co = (sxlink_t *)cctx; sxhub_t *ssys = co->hub; sxmsg_t *msg = co->messages[0]; char *buf = msg->payload; usrtc_node_t *node; rpc_typed_list_t *list_ent; size_t maxlen = 65535 - sizeof(sxmplv2_head_t); size_t ulen = 0; /* determine how this function was called */ if(!strcmp(sx->list->val, "get-channels-list")) co->cp_version = V2; else co->cp_version = V2_1; /* last supported in this version */ /* call the function */ if(ssys->get_rpc_typed_list_tree) co->rpc_list = ssys->get_rpc_typed_list_tree(co); if(!co->rpc_list) return SXE_EPERM; //buf += sizeof(sxmplv2_head_t); if(co->cp_version == V2) ulen += snprintf(buf + ulen, maxlen - ulen, "(set-channels-list "); else ulen += snprintf(buf + ulen, maxlen - ulen, "(!@c< "); for(node = usrtc_first(co->rpc_list); node != NULL; node = usrtc_next(co->rpc_list, node)) { /* fill the list */ list_ent = (rpc_typed_list_t *)usrtc_node_getdata(node); ulen += snprintf(buf + ulen, maxlen - ulen, "(:%d \"%s\")", list_ent->type_id, list_ent->description); } ulen += snprintf(buf + ulen, maxlen - ulen, ")"); msg->mhead.payload_length = ulen + 1; if(co->cp_version == V2) { /* we're ready for messaging mode */ co->flags |= SXMP_MESSAGINGMODE; co->flags &= ~SXMP_BATCHMODE; } return SXE_SUCCESS; } static int __get_streams(void *cctx, sexp_t *sx) { sxlink_t *link = (sxlink_t *)cctx; sxhub_t *hub = link->hub; sxmsg_t *msg = link->messages[0]; char *buf = msg->payload; usrtc_node_t *node, *rpc_node; struct sxstream_description *s_desc; size_t maxlen = 65535 - sizeof(sxmplv2_head_t); size_t ulen = 0, sts = 0; int tcid = 0; if(link->cp_version == V_UNKNOWN) /* oops, version doesn't a happy one */ return SXE_FAILED; if(!hub->streams) { /* no streams provided */ __return_nil: ulen = snprintf(buf, maxlen, "(!@s< nil)"); msg->mhead.payload_length = ulen + 1; /* and now we're ready to exit from batch mode */ link->flags |= SXMP_MESSAGINGMODE; link->flags &= ~SXMP_BATCHMODE; return SXE_SUCCESS; } else { /* set all streams available */ ulen += snprintf(buf + ulen, maxlen - ulen, "(!@s< "); for(node = usrtc_first(hub->streams); node != NULL; node = usrtc_next(hub->streams, node)) { s_desc = (struct sxstream_description *)usrtc_node_getdata(node); tcid = s_desc->pcid; if((rpc_node = usrtc_lookup(link->rpc_list, &tcid))) { /* channel allowed */ /* ids */ ulen += snprintf(buf + ulen, maxlen - ulen, "(:tcid %d :stid %d :t ", s_desc->pcid, s_desc->stid); /* type */ switch(s_desc->type) { case 0: ulen += snprintf(buf + ulen, maxlen - ulen, "e "); break; case SXE_O_NAMED: ulen += snprintf(buf + ulen, maxlen - ulen, "n "); break; case SXE_O_BINARY: ulen += snprintf(buf + ulen, maxlen - ulen, "b "); break; } /* flags */ ulen += snprintf(buf + ulen, maxlen - ulen, ":a "); if(s_desc->flags & SXE_O_READ) ulen += snprintf(buf + ulen, maxlen - ulen, "r"); else ulen += snprintf(buf + ulen, maxlen - ulen, "-"); if(s_desc->flags & SXE_O_WRITE) ulen += snprintf(buf + ulen, maxlen - ulen, "w"); else ulen += snprintf(buf + ulen, maxlen - ulen, "-"); if(s_desc->flags & SXE_O_TRUNC) ulen += snprintf(buf + ulen, maxlen - ulen, "t"); else ulen += snprintf(buf + ulen, maxlen - ulen, "-"); if(s_desc->flags & SXE_O_ASYNC) ulen += snprintf(buf + ulen, maxlen - ulen, "a"); else ulen += snprintf(buf + ulen, maxlen - ulen, "-"); ulen += snprintf(buf + ulen, maxlen - ulen, ")"); sts++; } } if(!sts) goto __return_nil; ulen += snprintf(buf + ulen, maxlen - ulen, ")"); msg->mhead.payload_length = ulen + 1; } link->flags |= SXMP_MESSAGINGMODE; link->flags &= ~SXMP_BATCHMODE; return SXE_SUCCESS; } static long __cmp_uint16(const void *a, const void *b) { return (long) *(uint16_t*)a - *(uint16_t*)b; } #define _MOD_STID 0xa #define _MOD_TCID 0xb #define _MOD_TYPE 0xc #define _MOD_FLAGS 0xd #define _MOD_UNKWN 0x0 static int __set_streams(void *cctx, sexp_t *sx) { register int idx, iidx; usrtc_t *tree = NULL; sxlink_t *link = (sxlink_t *)cctx; sexp_t *isx, *iisx; struct sxstream_description *s_desc; usrtc_node_t *node = NULL; int modp = 0, r, value_mod = 0, mod = _MOD_UNKWN; int flags, type, stid, pcid; if(!link->remote_streams) { tree = malloc(sizeof(usrtc_t)); if(!tree) return SXE_ENOMEM; usrtc_init(tree, USRTC_SPLAY, MAX_STREAMS_TYPES, __cmp_uint16); link->remote_streams = tree; } SEXP_ITERATE_LIST(sx, isx, idx) { if(!idx) continue; if(isx->ty != SEXP_LIST) { free(tree); link->remote_streams = NULL; if(!strcmp(isx->val, "nil")) goto __fini; else return SXE_BADPROTO; } else { SEXP_ITERATE_LIST(isx, iisx, iidx) { if(iisx->ty == SEXP_LIST) { r = SXE_BADPROTO; __clean_up_on_error: /* clean up all stuff */ for(node = usrtc_first(tree); node != NULL; node = usrtc_first(tree)) { s_desc = (struct sxstream_description *)usrtc_node_getdata(node); usrtc_delete(tree, node); free(s_desc); } free(tree); link->remote_streams = NULL; return r; } if(iisx->val[0] == ':' && value_mod) { r = SXE_BADPROTO; goto __clean_up_on_error; } else if(iisx->val[0] == ':' && !value_mod) { value_mod = 1; if(!strcmp(iisx->val, ":stid")) mod = _MOD_STID; else if(!strcmp(iisx->val, ":tcid")) mod = _MOD_TCID; else if(!strcmp(iisx->val, ":t")) mod = _MOD_TYPE; else if(!strcmp(iisx->val, ":a")) mod = _MOD_FLAGS; else { r = SXE_BADPROTO; goto __clean_up_on_error; } } else if(iisx->val[0] != ':' && value_mod) { switch(mod) { case _MOD_STID: stid = atoi(iisx->val); modp++; break; case _MOD_TCID: pcid = atoi(iisx->val); modp++; break; case _MOD_TYPE: switch(iisx->val[0]) { case 'e': type = 0; break; case 'b': type = SXE_O_BINARY; break; case 'n': type = SXE_O_NAMED; break; default: r = SXE_BADPROTO; goto __clean_up_on_error; } modp++; break; case _MOD_FLAGS: flags = 0; if(iisx->val[0] == 'r') flags |= SXE_O_READ; else if(iisx->val[1] == 'w') flags |= SXE_O_WRITE; else if(iisx->val[2] == 't') flags |= SXE_O_TRUNC; else if(iisx->val[3] == 'a') flags |= SXE_O_ASYNC; else { r = SXE_BADPROTO; goto __clean_up_on_error; } modp++; break; } value_mod = 0; } else { r = SXE_BADPROTO; goto __clean_up_on_error; } } /* here we go */ if(modp < 4) { r = SXE_BADPROTO; goto __clean_up_on_error; } else if(!(s_desc = malloc(sizeof(struct sxstream_description)))) { r = SXE_ENOMEM; goto __clean_up_on_error; } usrtc_node_init(&s_desc->node, s_desc); s_desc->ops = NULL; s_desc->flags = (uint16_t)flags; s_desc->type = (uint16_t)type; s_desc->pcid = (uint16_t)pcid; s_desc->stid = (uint16_t)stid; usrtc_insert(tree, &s_desc->node, &s_desc->stid); /* finish */ modp = 0; } } __fini: link->flags |= SXMP_MESSAGINGMODE; link->flags &= ~SXMP_BATCHMODE; return SXE_SUCCESS; } #undef _MOD_STID #undef _MOD_TCID #undef _MOD_TYPE #undef _MOD_FLAGS #undef _MOD_UNKWN static int __set_channels_list(void *cctx, sexp_t *sx) { register int idx; sxlink_t *co = (sxlink_t *)cctx; sxhub_t *ssys = co->hub; sexp_t *isx, *iisx; int id, r; /* determine how this function was called */ if(!strcmp(sx->list->val, "get-channels-list")) co->cp_version = V2; else co->cp_version = V2_1; /* last supported in this version */ SEXP_ITERATE_LIST(sx, isx, idx) { if(!idx) continue; if(isx->ty != SEXP_LIST) return SXE_BADPROTO; if(sexp_list_length(isx) != 2) return SXE_BADPROTO; /* get id */ sexp_list_car(isx, &iisx); if(iisx->ty == SEXP_LIST) return SXE_BADPROTO; if(iisx->aty != SEXP_BASIC) return SXE_BADPROTO; if(iisx->val[0] != ':') return SXE_BADPROTO; id = atoi(iisx->val + sizeof(char)); /* get short description */ sexp_list_cdr(isx, &iisx); if(iisx->ty == SEXP_LIST) return SXE_BADPROTO; if(iisx->aty != SEXP_DQUOTE) return SXE_BADPROTO; /* ok, here we go */ if(ssys->set_typed_list_callback) { r = ssys->set_typed_list_callback(co, id, iisx->val); if(r != SXE_SUCCESS) return r; } } if(co->cp_version == V2) { /* we're ready for messaging mode */ co->flags |= SXMP_MESSAGINGMODE; co->flags &= ~SXMP_BATCHMODE; } return SXE_SUCCESS; } static int __my_version_ack(void *cctx, sexp_t *sx) { register int idx; sxlink_t *link = (sxlink_t *)cctx; sexp_t *isx; SEXP_ITERATE_LIST(sx, isx, idx) { if(!idx) continue; if(idx > 2) return SXE_BADPROTO; if(isx->ty == SEXP_LIST) return SXE_BADPROTO; if(!strcmp(isx->val, V2_1_TPROT)) link->cp_version = V2_1; else link->cp_version = V_UNKNOWN; } return SXE_SUCCESS; } static int __my_version_set(void *cctx, sexp_t *sx) { register int idx; sxlink_t *link = (sxlink_t *)cctx; sexp_t *isx; SEXP_ITERATE_LIST(sx, isx, idx) { if(!idx) continue; if(idx > 2) return SXE_BADPROTO; if(isx->ty == SEXP_LIST) return SXE_BADPROTO; if(!strcmp(isx->val, V2_1_TPROT)) link->cp_version = V2_1; else return SXE_FAILED; /* failed to set another version */ } return SXE_SUCCESS; } static int __init_systemrpc_tree(usrtc_t *rtree) { /* batch mode negotiation context functions */ if(__insert_rpc_function(rtree, "auth-set-credentials", __set_credentials)) goto __fail; /* old version V2 */ if(__insert_rpc_function(rtree, "get-channels-list", __get_channels_list)) goto __fail; /* old V2 (v1 also) */ if(__insert_rpc_function(rtree, "set-channels-list", __set_channels_list)) goto __fail; /* sync functions */ /* channels */ if(__insert_rpc_function(rtree, "!@c>", __get_channels_list)) goto __fail; if(__insert_rpc_function(rtree, "!@c<", __set_channels_list)) goto __fail; /* version */ if(__insert_rpc_function(rtree, "!@v>", __my_version_ack)) goto __fail; if(__insert_rpc_function(rtree, "!@v<", __my_version_ack)) goto __fail; if(__insert_rpc_function(rtree, "!@V>", __my_version_set)) goto __fail; /* streams */ if(__insert_rpc_function(rtree, "!@s>", __get_streams)) goto __fail; if(__insert_rpc_function(rtree, "!@s<", __set_streams)) goto __fail; return 0; __fail: __destroy_rpc_list_tree(rtree); return ENOMEM; } static int __init_builtinrpc_tree(usrtc_t *rtree) { /* streams */ if(__insert_rpc_function(rtree, _SXSTREAMOPEN_CMD, _builtin_stream_open)) goto __fail; if(__insert_rpc_function(rtree, _SXSTREAMCLOSE_CMD, _builtin_stream_close)) goto __fail; if(__insert_rpc_function(rtree, _SXSTREAMEREAD_CMD, _builtin_stream_eread)) goto __fail; if(__insert_rpc_function(rtree, _SXSTREAMBREAD_CMD, _builtin_stream_bread)) goto __fail; if(__insert_rpc_function(rtree, _SXSTREAMBWRITE_CMD, _builtin_stream_bwrite)) goto __fail; return 0; __fail: __destroy_rpc_list_tree(rtree); return ENOMEM; } static long __cmp_cstr(const void *a, const void *b) { return (long)strcmp((const char *)a, (const char *)b); } static int __sxhub_log_dummy(const sxlogtype_t type, const char *fmt, ...) { int r; va_list arglist; va_start(arglist, fmt); r = vfprintf(stderr, fmt, arglist); va_end(arglist); return r; } int sxhub_init(sxhub_t *ssys) { int r = 0; if(!ssys) return EINVAL; else memset(ssys, 0, sizeof(sxhub_t)); if(!(ssys->links = malloc(sizeof(usrtc_t)))) return ENOMEM; /* init links list */ usrtc_init(ssys->links, USRTC_REDBLACK, MAX_LINKS, __cmp_cstr); if((r = pthread_rwlock_init(&(ssys->rwlock), NULL))) goto __fini; /* init RPC list related functions */ if(!(ssys->system_rpc = malloc(sizeof(sxl_rpclist_t)))) { r = ENOMEM; goto __lfini; } else { if(!(ssys->system_rpc->rpc_tree = malloc(sizeof(usrtc_t)))) { r = ENOMEM; goto __lfini; } usrtc_init(ssys->system_rpc->rpc_tree, USRTC_SPLAY, 256, __cmp_cstr); r = __init_systemrpc_tree(ssys->system_rpc->rpc_tree); if(r) { free(ssys->system_rpc->rpc_tree); goto __lfini; } } /* init builtin functions list */ if(!(ssys->stream_rpc = malloc(sizeof(sxl_rpclist_t)))) { r = ENOMEM; goto __lfini; } else { if(!(ssys->stream_rpc->rpc_tree = malloc(sizeof(usrtc_t)))) { r = ENOMEM; goto __lfini; } usrtc_init(ssys->stream_rpc->rpc_tree, USRTC_SPLAY, 256, __cmp_cstr); r = __init_builtinrpc_tree(ssys->stream_rpc->rpc_tree); if(r) { free(ssys->stream_rpc->rpc_tree); goto __lfini; } } /* set function pointers to default implementation */ sxhub_set_logops(ssys, __sxhub_log_dummy); return 0; __lfini: if(ssys->system_rpc) free(ssys->system_rpc); if(ssys->stream_rpc) free(ssys->stream_rpc); pthread_rwlock_destroy(&(ssys->rwlock)); __fini: if(ssys->links) free(ssys->links); return r; } int sxhub_free(sxhub_t *ssys) { usrtc_node_t *node; __destroy_rpc_list_tree(ssys->system_rpc->rpc_tree); free(ssys->system_rpc->rpc_tree); free(ssys->system_rpc); /* free streams description tree */ if(ssys->streams) { for(node = usrtc_first(ssys->streams); node != NULL; node = usrtc_first(ssys->streams)) usrtc_delete(ssys->streams, node); free(ssys->streams); } free(ssys->links); pthread_rwlock_destroy(&(ssys->rwlock)); SSL_CTX_free(ssys->ctx); return 0; } int sxhub_destroy(sxhub_t *ssys) { int r = sxhub_free(ssys); free(ssys); return r; } sxhub_t *sxhub_create(void) { int r = 0; sxhub_t *nsys = malloc(sizeof(sxhub_t)); if(!nsys) { errno = ENOMEM; return NULL; } r = sxhub_init(nsys); if(r) { errno = r; free(nsys); return NULL; } return nsys; } int sxhub_setsslserts(sxhub_t *ssys, const char *rootca, const char *certpem, const char *certkey) { if (!ssys || !rootca || !certpem || !certkey) return EINVAL; /* check on existence of certificate files */ if (access(rootca, R_OK) == -1) { ssys->log(SXERROR_LOG, "Unable to read rootca file '%s': %s\n", rootca, strerror(errno)); return ENOENT; } if (access(certpem, R_OK) == -1) { ssys->log(SXERROR_LOG, "Unable to read certpem file '%s': %s\n", certpem, strerror(errno)); return ENOENT; } if (access(certkey, R_OK) == -1) { ssys->log(SXERROR_LOG, "Unable to read certkey file '%s': %s\n", certkey, strerror(errno)); return ENOENT; } /* obtain full paths of certificate files */ int r; if (NULL == (ssys->rootca = realpath(rootca, NULL))) { ssys->log(SXERROR_LOG, "Unable to obtain the full path of '%s': %s\n", rootca, strerror(errno)); if (errno == ENOMEM) r = errno; goto __fail; } if (NULL == (ssys->certpem = realpath(certpem, NULL))) { ssys->log(SXERROR_LOG, "Unable to obtain the full path of '%s': %s\n", certpem, strerror(errno)); if (errno == ENOMEM) r = errno; goto __fail; } if (NULL == (ssys->certkey = realpath(certkey, NULL))) { ssys->log(SXERROR_LOG, "Unable to obtain the full path of '%s': %s\n", certkey, strerror(errno)); if (errno == ENOMEM) r = errno; goto __fail; } return 0; __fail: if(ssys->rootca) free(ssys->rootca); if(ssys->certkey) free(ssys->certkey); if(ssys->certpem) free(ssys->certpem); return r; } int sxhub_stream_register(sxhub_t *hub, const struct sxstream_description *s_desc) { usrtc_t *tree = NULL; usrtc_node_t *node = NULL; if(!hub->streams) { tree = malloc(sizeof(usrtc_t)); if(!tree) return ENOMEM; usrtc_init(tree, USRTC_SPLAY, MAX_STREAMS_TYPES, __cmp_uint16); hub->streams = tree; } else { tree = hub->streams; node = usrtc_lookup(tree, &s_desc->stid); if(node) return EEXIST; } node = (usrtc_node_t *)&s_desc->node; usrtc_node_init(node, (void *)s_desc); usrtc_insert(tree, node, &s_desc->stid); return 0; } /* internally used functions */ static int __verify_certcall_dummy(int preverify_ok, X509_STORE_CTX *ctx) { return preverify_ok; } int ex_ssldata_index; /* 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()); sxlink_t *link = SSL_get_ex_data(ssl, ex_ssldata_index); /* this is a custom data we're set before */ sxhub_t *hub = link->hub; /* 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) { link->pctx->certid = ASN1_INTEGER_get((const ASN1_INTEGER *)X509_get_serialNumber(ctx->current_cert)); /* now we're need to check the ssl cert */ if(hub->validate_sslpem) { if(hub->validate_sslpem(link)) return 0; else return 1; } else return 0; } return preverify_ok; } int _sxhub_settls_ctx(sxhub_t *hub, const char *crtfile) { if(!hub->ctx) { /* init SSL certificates and context */ if(!(hub->ctx = SSL_CTX_new(TLSv1_2_client_method()))) return SXE_ENOMEM; /* set verify context */ SSL_CTX_set_verify(hub->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, __verify_certcall_dummy); /* set verify depth */ SSL_CTX_set_verify_depth(hub->ctx, VERIFY_DEPTH); /* load certificates */ SSL_CTX_load_verify_locations(hub->ctx, hub->rootca, NULL); } /* set the local certificate from CertFile */ if(SSL_CTX_use_certificate_file(hub->ctx, crtfile, SSL_FILETYPE_PEM)<=0) return SXE_ESSL; /* set the private key from KeyFile (may be the same as CertFile) */ if(SSL_CTX_use_PrivateKey_file(hub->ctx, crtfile, SSL_FILETYPE_PEM)<=0) return SXE_ESSL; /* verify private key */ if (!SSL_CTX_check_private_key(hub->ctx)) return SXE_ESSL; return SXE_SUCCESS; } int _sxhub_settls_ctx_s(sxhub_t *hub) { if(hub->ctx) return SXE_SUCCESS; /* init SSL certificates and context */ if(!(hub->ctx = SSL_CTX_new(TLSv1_2_server_method()))) return SXE_ENOMEM; /* set verify context */ SSL_CTX_set_verify(hub->ctx, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, __verify_certcall); /* set verify depth */ SSL_CTX_set_verify_depth(hub->ctx, VERIFY_DEPTH); /* set cache policy */ SSL_CTX_set_session_cache_mode(hub->ctx, SSL_SESS_CACHE_OFF); SSL_CTX_set_mode(hub->ctx, SSL_MODE_RELEASE_BUFFERS); /* load certificates */ SSL_CTX_load_verify_locations(hub->ctx, hub->rootca, NULL); /* set the local certificate from CertFile */ if(SSL_CTX_use_certificate_file(hub->ctx, hub->certpem, SSL_FILETYPE_PEM) <= 0) return SXE_ESSL; /* set the private key from KeyFile (may be the same as CertFile) */ if(SSL_CTX_use_PrivateKey_file(hub->ctx, hub->certkey, SSL_FILETYPE_PEM) <= 0) return SXE_ESSL; /* verify private key */ if (!SSL_CTX_check_private_key(hub->ctx)) return SXE_ESSL; return SXE_SUCCESS; }