2018-10-31 19:44:13 +08:00
|
|
|
|
|
|
|
|
#include "ssl_trusted_cert_storage.h"
|
|
|
|
|
#include "MESA_htable_aux.h"
|
|
|
|
|
#include <MESA/MESA_htable.h>
|
|
|
|
|
|
|
|
|
|
#include <ssl_utils.h>
|
|
|
|
|
#include <tfe_utils.h>
|
|
|
|
|
|
|
|
|
|
#include <pthread.h>
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
|
|
struct ssl_X509_object
|
|
|
|
|
{
|
|
|
|
|
char* filename;
|
|
|
|
|
enum ssl_X509_obj_type type;
|
|
|
|
|
};
|
|
|
|
|
static void free_ssl_x509_obj(void* data)
|
|
|
|
|
{
|
|
|
|
|
struct ssl_X509_object* obj=(struct ssl_X509_object*)data;
|
|
|
|
|
free(obj->filename);
|
|
|
|
|
free(obj);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
struct ssl_trusted_cert_storage
|
|
|
|
|
{
|
2018-11-12 13:58:01 +08:00
|
|
|
struct cert_store_param param;
|
2018-11-02 20:38:06 +08:00
|
|
|
char* pem_bundle, *pem_dir;
|
2018-10-31 19:44:13 +08:00
|
|
|
MESA_htable_handle hash_table;
|
|
|
|
|
pthread_rwlock_t rwlock;
|
|
|
|
|
X509_STORE* effective_store;
|
|
|
|
|
};
|
2018-11-02 20:38:06 +08:00
|
|
|
static int _X509_add_cert_or_crl_add(X509_STORE* store, enum ssl_X509_obj_type type, const char* filename)
|
|
|
|
|
{
|
|
|
|
|
int ret=0;
|
|
|
|
|
BIO *bio=NULL;
|
|
|
|
|
X509* x=NULL;
|
|
|
|
|
X509_CRL* x_crl=NULL;
|
|
|
|
|
int error;
|
|
|
|
|
|
|
|
|
|
bio=BIO_new_file(filename, "r");
|
|
|
|
|
if(bio==NULL)
|
|
|
|
|
{
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
ret=0;
|
|
|
|
|
if(type==SSL_X509_OBJ_CERT)
|
|
|
|
|
{
|
|
|
|
|
while(NULL!=(x=PEM_read_bio_X509_AUX(bio, NULL, NULL, NULL)))
|
|
|
|
|
{
|
|
|
|
|
ret=X509_STORE_add_cert(store, x);
|
|
|
|
|
if(ret==0)
|
|
|
|
|
{
|
|
|
|
|
X509_free(x);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if(type==SSL_X509_OBJ_CRL)
|
|
|
|
|
{
|
|
|
|
|
while(NULL!=(x_crl=PEM_read_bio_X509_CRL(bio, NULL, NULL, NULL)))
|
|
|
|
|
{
|
|
|
|
|
ret=X509_STORE_add_crl(store, x_crl);
|
|
|
|
|
if(ret==0)
|
|
|
|
|
{
|
|
|
|
|
X509_CRL_free(x_crl);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if(ret==0)
|
|
|
|
|
{
|
|
|
|
|
BIO_free(bio);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
BIO_free(bio);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int filter_pem_fn(const struct dirent * ent)
|
|
|
|
|
{
|
|
|
|
|
const char* fn_suffix=".pem";
|
|
|
|
|
if(strlen(ent->d_name)< strlen(fn_suffix))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
if(0!=strcmp(ent->d_name+strlen(ent->d_name)-strlen(fn_suffix), fn_suffix))
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-12 13:58:01 +08:00
|
|
|
static X509_STORE* _X509_store_create(const char* pem_bundle, const char* pem_dir, struct cert_store_param* param)
|
2018-10-31 19:44:13 +08:00
|
|
|
{
|
2018-11-02 20:38:06 +08:00
|
|
|
int ret=0, n=0, i=0;
|
2018-11-07 14:14:03 +08:00
|
|
|
|
2018-10-31 19:44:13 +08:00
|
|
|
X509_STORE* store=X509_STORE_new();
|
2018-11-02 20:38:06 +08:00
|
|
|
char path[TFE_STRING_MAX]={0};
|
2018-10-31 19:44:13 +08:00
|
|
|
if (store == NULL)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = X509_STORE_set_default_paths(store);
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
ret = X509_STORE_load_locations(store, pem_bundle, NULL);
|
|
|
|
|
if (ret == 0)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
2018-11-12 13:58:01 +08:00
|
|
|
|
|
|
|
|
X509_VERIFY_PARAM *x509_param=NULL;
|
|
|
|
|
if(param->check_crl)
|
|
|
|
|
{
|
|
|
|
|
x509_param = X509_VERIFY_PARAM_new();
|
|
|
|
|
X509_VERIFY_PARAM_set_flags(x509_param, X509_V_FLAG_CRL_CHECK);
|
|
|
|
|
X509_STORE_set1_param(store, x509_param);
|
|
|
|
|
X509_VERIFY_PARAM_free(x509_param);
|
|
|
|
|
}
|
2018-11-07 14:14:03 +08:00
|
|
|
struct dirent **namelist = NULL;
|
2018-11-02 20:38:06 +08:00
|
|
|
n=tfe_scandir(pem_dir, &namelist, NULL, (int (*)(const void*, const void*))alphasort);
|
2018-11-07 14:14:03 +08:00
|
|
|
if(n < 0)
|
|
|
|
|
{
|
|
|
|
|
return store;
|
|
|
|
|
}
|
2018-11-02 20:38:06 +08:00
|
|
|
|
|
|
|
|
for(i=0;i<n;i++)
|
|
|
|
|
{
|
|
|
|
|
snprintf(path, sizeof(path), "%s/%s",pem_dir, namelist[i]->d_name);
|
|
|
|
|
if(0==strcasecmp(namelist[i]->d_name+strlen(namelist[i]->d_name)-strlen(".pem"), ".pem"))
|
|
|
|
|
{
|
|
|
|
|
_X509_add_cert_or_crl_add(store, SSL_X509_OBJ_CERT, path);
|
|
|
|
|
}
|
|
|
|
|
else if(0==strcasecmp(namelist[i]->d_name+strlen(namelist[i]->d_name)-strlen(".crl"), ".crl"))
|
|
|
|
|
{
|
|
|
|
|
_X509_add_cert_or_crl_add(store, SSL_X509_OBJ_CRL, path);
|
|
|
|
|
}
|
2018-11-07 14:14:03 +08:00
|
|
|
|
|
|
|
|
TFE_LOG_INFO(g_default_logger, "Found X509 additive trust CA: %s", path);
|
2018-11-02 20:38:06 +08:00
|
|
|
free(namelist[i]);
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-07 14:14:03 +08:00
|
|
|
free(namelist);
|
2018-10-31 19:44:13 +08:00
|
|
|
return store;
|
|
|
|
|
}
|
2018-11-07 14:14:03 +08:00
|
|
|
|
2018-10-31 19:44:13 +08:00
|
|
|
static MESA_htable_handle _create_mesa_htable(void)
|
|
|
|
|
{
|
|
|
|
|
int ret=0;
|
|
|
|
|
MESA_htable_handle htable = MESA_htable_born();
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_int(htable, MHO_SCREEN_PRINT_CTRL, 0);
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_int(htable, MHO_THREAD_SAFE, 0);
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_int(htable, MHO_MUTEX_NUM, 16);
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_int(htable, MHO_HASH_SLOT_SIZE, 1024*4);
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_int(htable, MHO_HASH_MAX_ELEMENT_NUM, 0);
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_int(htable, MHO_EXPIRE_TIME, 0);
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_int(htable, MHO_ELIMIMINATE_TYPE,
|
|
|
|
|
HASH_ELIMINATE_ALGO_FIFO);
|
|
|
|
|
ret = __wrapper_MESA_htable_set_opt_func(htable, MHO_CBFUN_DATA_FREE,
|
|
|
|
|
(void *)free_ssl_x509_obj, sizeof(&free_ssl_x509_obj));
|
|
|
|
|
//ret = __wrapper_MESA_htable_set_opt(htable, MHO_CBFUN_DATA_EXPIRE_NOTIFY,
|
|
|
|
|
// (void *)key_keeper_verify_cb);
|
|
|
|
|
ret = MESA_htable_mature(htable);
|
|
|
|
|
return htable;
|
|
|
|
|
}
|
2018-11-12 13:58:01 +08:00
|
|
|
struct ssl_trusted_cert_storage* ssl_trusted_cert_storage_create(const char* pem_bundle,
|
|
|
|
|
const char* pem_dir, struct cert_store_param* param)
|
2018-10-31 19:44:13 +08:00
|
|
|
{
|
|
|
|
|
int ret=0;
|
|
|
|
|
struct ssl_trusted_cert_storage* storage=ALLOC(struct ssl_trusted_cert_storage, 1);
|
2018-11-12 13:58:01 +08:00
|
|
|
storage->param=*param;
|
|
|
|
|
storage->effective_store=_X509_store_create(pem_bundle, pem_dir, &(storage->param));
|
2018-10-31 19:44:13 +08:00
|
|
|
if (storage->effective_store == NULL)
|
|
|
|
|
{
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
storage->pem_bundle=tfe_strdup(pem_bundle);
|
2018-11-02 20:38:06 +08:00
|
|
|
storage->pem_dir=tfe_strdup(pem_dir);
|
2018-10-31 19:44:13 +08:00
|
|
|
storage->hash_table=_create_mesa_htable();
|
|
|
|
|
pthread_rwlock_init(&(storage->rwlock), NULL);
|
|
|
|
|
|
|
|
|
|
return storage;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
void ssl_trusted_cert_storage_destroy(struct ssl_trusted_cert_storage* storage)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 20:38:06 +08:00
|
|
|
|
2018-10-31 19:44:13 +08:00
|
|
|
int ssl_trusted_cert_storage_add(struct ssl_trusted_cert_storage* storage, enum ssl_X509_obj_type type, const char* filename)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
int ret=0;
|
|
|
|
|
struct ssl_X509_object* obj=NULL;
|
|
|
|
|
void* data=NULL;
|
|
|
|
|
pthread_rwlock_wrlock(&(storage->rwlock));
|
|
|
|
|
data=MESA_htable_search(storage->hash_table, (const unsigned char*)filename, strlen(filename));
|
|
|
|
|
if(data!=NULL)//duplicated
|
|
|
|
|
{
|
|
|
|
|
ret=-1;
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
ret=_X509_add_cert_or_crl_add(storage->effective_store, type, filename);
|
|
|
|
|
if(ret<0)
|
|
|
|
|
{
|
|
|
|
|
ret=-1;
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
obj=ALLOC(struct ssl_X509_object, 1);
|
|
|
|
|
obj->type=SSL_X509_OBJ_CERT;
|
|
|
|
|
obj->filename=tfe_strdup(filename);
|
|
|
|
|
ret=MESA_htable_add(storage->hash_table, (const unsigned char*)obj->filename, strlen(obj->filename), obj);
|
|
|
|
|
assert(ret>0);
|
|
|
|
|
ret=1;
|
|
|
|
|
|
|
|
|
|
error_out:
|
|
|
|
|
pthread_rwlock_unlock(&(storage->rwlock));
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void cert_storage_htable_traverse_cb(const uchar * key, uint size, void * data, void * user)
|
|
|
|
|
{
|
|
|
|
|
X509_STORE* store=(X509_STORE* )user;
|
|
|
|
|
struct ssl_X509_object* obj=(struct ssl_X509_object*)data;
|
|
|
|
|
_X509_add_cert_or_crl_add(store, obj->type, obj->filename);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int ssl_trusted_cert_storage_del(struct ssl_trusted_cert_storage* storage, enum ssl_X509_obj_type type, const char* filename)
|
|
|
|
|
{
|
|
|
|
|
int ret=0;
|
|
|
|
|
X509_STORE* temp_store=NULL;
|
|
|
|
|
pthread_rwlock_wrlock(&(storage->rwlock));
|
|
|
|
|
ret=MESA_htable_del(storage->hash_table, (const unsigned char*)filename, strlen(filename), NULL);
|
|
|
|
|
if(ret<0)
|
|
|
|
|
{
|
|
|
|
|
ret=-1;
|
|
|
|
|
goto error_out;
|
|
|
|
|
}
|
2018-11-12 13:58:01 +08:00
|
|
|
temp_store=_X509_store_create(storage->pem_bundle, storage->pem_dir, &(storage->param));
|
2018-10-31 19:44:13 +08:00
|
|
|
MESA_htable_iterate(storage->hash_table, cert_storage_htable_traverse_cb, temp_store);
|
|
|
|
|
X509_STORE_free(storage->effective_store);
|
|
|
|
|
storage->effective_store=temp_store;
|
|
|
|
|
ret=1;
|
|
|
|
|
|
|
|
|
|
error_out:
|
|
|
|
|
pthread_rwlock_unlock(&(storage->rwlock));
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
void ssl_trusted_cert_storage_reset(struct ssl_trusted_cert_storage* storage)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
X509_STORE* temp_store=NULL;
|
|
|
|
|
MESA_htable_destroy(storage->hash_table, NULL);
|
|
|
|
|
|
|
|
|
|
storage->hash_table=_create_mesa_htable();
|
2018-11-12 13:58:01 +08:00
|
|
|
temp_store=_X509_store_create(storage->pem_bundle, storage->pem_dir, &(storage->param));
|
2018-10-31 19:44:13 +08:00
|
|
|
|
|
|
|
|
pthread_rwlock_wrlock(&(storage->rwlock));
|
|
|
|
|
X509_STORE_free(storage->effective_store);
|
|
|
|
|
storage->effective_store=temp_store;
|
|
|
|
|
pthread_rwlock_unlock(&(storage->rwlock));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
int ssl_trusted_cert_storage_verify_conn(struct ssl_trusted_cert_storage* storage, const SSL * ssl, char* reason, size_t n_reason)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0, err_code=0;
|
|
|
|
|
char *subj=NULL, *issuer=NULL;
|
|
|
|
|
STACK_OF(X509) * cert_chain = SSL_get_peer_cert_chain(ssl);
|
|
|
|
|
if (cert_chain == NULL)
|
|
|
|
|
{
|
|
|
|
|
// The peer certificate chain is not necessarily available after reusing a session, in which case a NULL pointer is returned.
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
X509_STORE_CTX * ctx = X509_STORE_CTX_new();
|
|
|
|
|
X509 * cert = sk_X509_value(cert_chain, 0);
|
2018-11-01 12:28:40 +08:00
|
|
|
|
|
|
|
|
pthread_rwlock_rdlock(&(storage->rwlock));
|
|
|
|
|
|
2018-10-31 19:44:13 +08:00
|
|
|
ret = X509_STORE_CTX_init(ctx, storage->effective_store, cert, cert_chain);
|
|
|
|
|
assert(ret == 1);
|
|
|
|
|
|
|
|
|
|
//If a complete chain can be built and validated this function returns 1, otherwise it return zero or negtive code.
|
|
|
|
|
ret = X509_verify_cert(ctx);
|
2018-11-01 12:28:40 +08:00
|
|
|
err_code=X509_STORE_CTX_get_error(ctx);
|
2018-11-11 17:41:23 +08:00
|
|
|
if(ret!=1 && err_code!=X509_V_ERR_UNABLE_TO_GET_CRL
|
|
|
|
|
&& err_code!=X509_V_ERR_DIFFERENT_CRL_SCOPE
|
|
|
|
|
&& err_code!=X509_V_ERR_CRL_HAS_EXPIRED)
|
2018-10-31 19:44:13 +08:00
|
|
|
{
|
|
|
|
|
subj=ssl_x509_subject(cert);
|
|
|
|
|
issuer=ssl_x509_issuer(cert);
|
|
|
|
|
snprintf(reason, n_reason, "%s : subject - %s issuer - %s"
|
|
|
|
|
, X509_verify_cert_error_string(err_code)
|
|
|
|
|
, subj
|
|
|
|
|
, issuer);
|
|
|
|
|
free(subj);
|
|
|
|
|
free(issuer);
|
2018-11-01 12:28:40 +08:00
|
|
|
ret=0;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ret=1;
|
2018-10-31 19:44:13 +08:00
|
|
|
}
|
|
|
|
|
X509_STORE_CTX_free(ctx);
|
|
|
|
|
pthread_rwlock_unlock(&(storage->rwlock));
|
2018-11-01 12:28:40 +08:00
|
|
|
return ret;
|
2018-10-31 19:44:13 +08:00
|
|
|
}
|
|
|
|
|
|