#include "key_keeper.h" #include #include #include #include #include "MESA/MESA_prof_load.h" #include "tfe_rpc.h" #include "event2/http.h" #define HTABLE_MAX_KEY_LEN 256 #define KEYRING_EXSITED 0 #define KEYRING_NOT_EXSITED -1 enum KEY_KEEPER_MODE{ NORMAL = 0, DEBUG, }; struct keyring_private { struct keyring head; pthread_mutex_t mutex; size_t references; }; struct key_keeper_promise_ctx { void* logger; MESA_htable_handle htable; const uchar* key; unsigned int key_len; }; static const uchar* get_key_by_cert(X509* cert, int keyring_id, unsigned int* len); static long htable_search_cb(void * data, const uchar * key, uint size, void * user_arg); static int __wrapper_MESA_htable_set_opt(MESA_htable_handle table, enum MESA_htable_opt opt_type, unsigned int value); static MESA_htable_handle create_hash_table(unsigned int slot_size, unsigned int expire_seconds); static struct keyring* generate_x509_cert(X509* origin_cert, int keyring_id, const char* filename); static void tfe_rpc_on_succ(void* result, void* user); static void tfe_rpc_on_fail(enum e_future_error err, const char * what, void * user); static void ctx_destory_cb(struct promise* p); static X509* get_cert_from_response(const char* data, int len, void* logger); static EVP_PKEY* get_key_from_response(const char* data, int len, void* logger); static STACK_OF(X509)* get_chain_from_response(const char* data, int len, void* logger); /* * Certificate, including private key and keyring chain. */ struct keyring* key_keeper_keyring_new(void) { struct keyring_private *keyring; if (!(keyring = (struct keyring_private *)ALLOC(struct keyring_private, 1))) { return NULL; } if (pthread_mutex_init(&keyring->mutex, NULL)) { free(keyring); return NULL; } keyring->references = 1; return &(keyring->head); } /* * Passed OpenSSL objects are owned by cert_t; refcount will not be * incremented, stack will not be duplicated. */ struct keyring* key_keeper_keyring_new3(EVP_PKEY *key, X509 *cert, STACK_OF(X509) *chain) { struct keyring_private* keyring; if (!(keyring = (struct keyring_private *)ALLOC(struct keyring_private, 1))) { return NULL; } if (pthread_mutex_init(&keyring->mutex, NULL)) { free(keyring); return NULL; } keyring->references = 1; (keyring->head).key = key; (keyring->head).cert = cert; (keyring->head).chain = chain; if(key) { ssl_key_refcount_inc(key); } if(cert) { ssl_x509_refcount_inc(cert); } if(chain){ int i = 0; for (i = 0; i < sk_X509_num(chain); i++) { ssl_x509_refcount_inc(sk_X509_value(chain, i)); } } return &(keyring->head); } // Increment reference count. void key_keeper_keyring_refcount_inc(struct keyring* ring) { struct keyring_private* keyring = (struct keyring_private*)ring; pthread_mutex_lock(&keyring->mutex); keyring->references++; pthread_mutex_unlock(&keyring->mutex); } /* * Thread-safe setter functions; they copy the value (refcounts are inc'd). */ void key_keeper_keyring_set_key(struct keyring* ring, EVP_PKEY *key) { struct keyring_private* keyring = (struct keyring_private*)ring; pthread_mutex_lock(&keyring->mutex); if ((keyring->head).key) { EVP_PKEY_free((keyring->head).key); } (keyring->head).key = key; if (key) { ssl_key_refcount_inc((keyring->head).key); } pthread_mutex_unlock(&keyring->mutex); } void key_keeper_keyring_set_cert(struct keyring* ring, X509 *cert) { struct keyring_private* keyring = (struct keyring_private*)ring; pthread_mutex_lock(&keyring->mutex); if ((keyring->head).cert) { X509_free((keyring->head).cert); } (keyring->head).cert = cert; if (cert) { ssl_x509_refcount_inc((keyring->head).cert); } pthread_mutex_unlock(&keyring->mutex); } void key_keeper_keyring_set_chain(struct keyring* ring, STACK_OF(X509) *chain) { struct keyring_private* keyring = (struct keyring_private*)ring; pthread_mutex_lock(&keyring->mutex); if ((keyring->head).chain) { sk_X509_pop_free((keyring->head).chain, X509_free); } if (chain) { (keyring->head).chain = sk_X509_dup(chain); int i = 0; for (i = 0; i < sk_X509_num((keyring->head).chain); i++) { ssl_x509_refcount_inc(sk_X509_value((keyring->head).chain, i)); } } else { (keyring->head).chain = NULL; } pthread_mutex_unlock(&keyring->mutex); } /* * Free keyring including internal objects. */ void key_keeper_free_keyring(struct keyring *ring) { struct keyring_private* keyring = (struct keyring_private*)ring; pthread_mutex_lock(&keyring->mutex); keyring->references--; if (keyring->references) { pthread_mutex_unlock(&keyring->mutex); return; } pthread_mutex_unlock(&keyring->mutex); pthread_mutex_destroy(&keyring->mutex); if ((keyring->head).key) { EVP_PKEY_free((keyring->head).key); } if ((keyring->head).cert) { X509_free((keyring->head).cert); } if ((keyring->head).chain) { sk_X509_pop_free((keyring->head).chain, X509_free); } free(keyring); } static void key_keeper_free_serialized() { return; } static void key_keeper_verify_cb() { return; } struct key_keeper * key_keeper_init(const char * profile, const char* section, void* logger) { //load conf //TODO free struct key_keeper* keeper = ALLOC(struct key_keeper, 1); keeper->logger = logger; MESA_load_profile_uint_def(profile, section, "mode", &(keeper->mode), 1); MESA_load_profile_string_def(profile, section, "cert_store_host", keeper->cert_store_host, sizeof(keeper->cert_store_host), "xxxxx"); MESA_load_profile_uint_def(profile, section, "cert_store_port", &(keeper->cert_store_port), 80); //TODO: argument keeper->htable = create_hash_table(16,16); return keeper; } //return void ?? struct key_keeper * key_keeper_destroy(struct key_keeper *keeper) { free(keeper); keeper = NULL; return keeper; } struct keyring* key_keeper_release_cert(future_result_t* result) { return (struct keyring*)result; } static struct keyring* generate_x509_cert(X509* origin_cert, int keyring_id, const char* filename) { X509* ca = ssl_x509_load(filename); EVP_PKEY* cakey = ssl_key_load(filename); EVP_PKEY* forge_key = ssl_key_genrsa(1024); X509* forge_cert = ssl_x509_forge(ca, cakey, origin_cert, forge_key, NULL, NULL); STACK_OF(X509)* chain = sk_X509_new_null(); sk_X509_push(chain, ca); sk_X509_push(chain, forge_cert); struct keyring* ring= key_keeper_keyring_new(); key_keeper_keyring_set_key(ring, forge_key); key_keeper_keyring_set_cert(ring, forge_cert); key_keeper_keyring_set_chain(ring, chain); return ring; } static void tfe_rpc_on_succ(void* result, void* user) { struct promise * p = (struct promise *) user; struct key_keeper_promise_ctx* ctx = (struct key_keeper_promise_ctx*)promise_get_ctx(p); void* logger = ctx->logger; MESA_htable_handle htable= ctx->htable; const uchar* key = ctx->key; unsigned int key_len = ctx->key_len; //transform to x509 struct tfe_rpc_response_result* response = tfe_rpc_release(result); int status_code = response->status_code; const char* status_msg = response->status_msg; const char* data = response->data; int len = response->len; if(status_code == HTTP_OK) { struct keyring* ring= key_keeper_keyring_new(); X509* forge_cert = get_cert_from_response(data, len, NULL); EVP_PKEY* forge_key = get_key_from_response(data, len, NULL); STACK_OF(X509)* chain = get_chain_from_response(data, len, NULL); key_keeper_keyring_set_key(ring, forge_key); key_keeper_keyring_set_cert(ring, forge_cert); key_keeper_keyring_set_chain(ring, chain); promise_success(p, (void*)ring); int ret = MESA_htable_add(htable, key, key_len, (void*)ring); assert(ret >= 0); } else { promise_failed(p, FUTURE_ERROR_EXCEPTION, status_msg); } } static void tfe_rpc_on_fail(enum e_future_error err, const char * what, void * user) { struct promise * p = (struct promise *) user; promise_failed(p, err, what); } static void ctx_destory_cb(struct promise* p) { } //TODO: cert_not_valid void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, int keyring_id, X509 * origin_cert, int is_cert_valid, struct event_base * evbase) { //get subject name from cert //current promise, belong to key_keeper struct promise* p = future_to_promise(f); struct key_keeper_promise_ctx* ctx = ALLOC(struct key_keeper_promise_ctx, 1); unsigned int len = 0; const uchar* key = get_key_by_cert(origin_cert, keyring_id, &len); ctx->logger = keeper->logger; ctx->htable = keeper->htable; ctx->key = key; ctx->key_len = len; promise_set_ctx(p, (void*)ctx, ctx_destory_cb); long int cb_rtn = 0; MESA_htable_search_cb(ctx->htable, (const unsigned char*)(ctx->key), ctx->key_len, htable_search_cb, p, &cb_rtn); printf(cb_rtn == KEYRING_EXSITED ? "KEYRING_EXSITED\n": "KEYRING_NOT_EXSITED\n"); if(cb_rtn == KEYRING_EXSITED) { return; } int mode = keeper->mode; printf("mode is %s", mode == NORMAL ? "normal\n":"debug\n"); switch(mode){ case NORMAL: { struct future* f_tfe_rpc = future_create("tfe_rpc", tfe_rpc_on_succ, tfe_rpc_on_fail, p); //TODO: init in main()? store in ctx struct tfe_rpc* rpc = tfe_rpc_init(NULL, NULL, keeper->logger); char url[TFE_STRING_MAX]; const char host[] = "www.baidu.com"; snprintf(url, TFE_STRING_MAX, "%s:%d?host=%s&flag=1&valid=1&kering_id=%d", keeper->cert_store_host, keeper->cert_store_port, host, keyring_id); tfe_rpc_async_ask(f_tfe_rpc, rpc, url, GET, DONE_CB, NULL, 0, evbase); break; } case DEBUG: { //TOOD: generate X509 cert const char* filename = "./conf/mesalab-ca.pem"; struct keyring* ring = generate_x509_cert(origin_cert, keyring_id, filename); if(ring) { int ret = MESA_htable_add(ctx->htable, ctx->key, ctx->key_len, (void*)ring); assert(ret >= 0); printf("key %s is added to hash table\n", ctx->key); promise_success(p, (void*)ring); } else { promise_failed(p, FUTURE_ERROR_EXCEPTION, "generate X509 cert failed"); } break; } } return; } static long htable_search_cb(void * data, const uchar * key, uint size, void * user_arg) { //data is (struct keyring*) if(data == NULL) { return KEYRING_NOT_EXSITED; } else { struct promise* p = (struct promise*)user_arg; promise_success(p, data); return KEYRING_EXSITED; } } static const uchar* get_key_by_cert(X509* cert, int keyring_id, unsigned int* len) { char* cert_fgr = NULL; cert_fgr = ssl_x509_fingerprint(cert, 0); char* key = (char*)malloc(HTABLE_MAX_KEY_LEN); *key = '\0'; if(cert == NULL) { return NULL; } snprintf(key, HTABLE_MAX_KEY_LEN, "%d:", keyring_id); strncat(key, cert_fgr, HTABLE_MAX_KEY_LEN); *len = strnlen(key, HTABLE_MAX_KEY_LEN); return (const uchar*)key; } static int __wrapper_MESA_htable_set_opt(MESA_htable_handle table, enum MESA_htable_opt opt_type, unsigned int value) { int ret = MESA_htable_set_opt(table, opt_type, &value, (int)(sizeof(value))); assert(ret == 0); return ret; } static MESA_htable_handle create_hash_table(unsigned int slot_size, unsigned int expire_seconds) { int ret = 0; unsigned max_num = slot_size * 4; MESA_htable_handle htable = MESA_htable_born(); ret = __wrapper_MESA_htable_set_opt(htable, MHO_SCREEN_PRINT_CTRL, 0); ret = __wrapper_MESA_htable_set_opt(htable, MHO_THREAD_SAFE, 1); ret = __wrapper_MESA_htable_set_opt(htable, MHO_MUTEX_NUM, 16); ret = __wrapper_MESA_htable_set_opt(htable, MHO_HASH_SLOT_SIZE, slot_size); ret = __wrapper_MESA_htable_set_opt(htable, MHO_HASH_MAX_ELEMENT_NUM, max_num); ret = __wrapper_MESA_htable_set_opt(htable, MHO_EXPIRE_TIME, expire_seconds); ret = __wrapper_MESA_htable_set_opt(htable, MHO_ELIMIMINATE_TYPE, HASH_ELIMINATE_ALGO_FIFO); //TODO: how to do overide? //ret = __wrapper_MESA_htable_set_opt(htable, MHO_CBFUN_DATA_FREE, // (void *)key_keeper_free_serialized); //ret = __wrapper_MESA_htable_set_opt(htable, MHO_CBFUN_DATA_EXPIRE_NOTIFY, // (void *)key_keeper_verify_cb); ret = MESA_htable_mature(htable); assert(ret == 0); return htable; } //how to free static X509* get_cert_from_response(const char* data, int len, void* logger) { BIO *bio; X509 *cert; bio = BIO_new(BIO_s_mem()); BIO_write(bio, (const void*)data, len); cert = PEM_read_bio_X509(bio, NULL, NULL, NULL); return cert; } static EVP_PKEY* get_key_from_response(const char* data, int len, void* logger) { } static STACK_OF(X509)* get_chain_from_response(const char* data, int len, void* logger) { } /* * Passed OpenSSL objects are copied by cert_t; crt/key refcount will be * incremented, stack will be duplicated. * / cert_t *cert_new3_copy(EVP_PKEY *key, X509 *crt, STACK_OF(X509) *chain) { cert_t *c; if (!(c = (cert_t *)malloc(sizeof(cert_t)))) return NULL; if (pthread_mutex_init(&c->mutex, NULL)) { free(c); return NULL; } c->key = key; ssl_key_refcount_inc(c->key); c->crt = crt; ssl_x509_refcount_inc(c->crt); c->chain = sk_X509_dup(chain); for (int i = 0; i < sk_X509_num(c->chain); i++) { ssl_x509_refcount_inc(sk_X509_value(c->chain, i)); } c->references = 1; return c; } */ /* * Load cert_t from file. * / cert_t *cert_new_load(const char *filename) { cert_t *c; if (!(c = (cert_t *)malloc(sizeof(cert_t)))) return NULL; memset(c, 0, sizeof(cert_t)); if (pthread_mutex_init(&c->mutex, NULL)) { free(c); return NULL; } if (ssl_x509chain_load(&c->crt, &c->chain, filename) == -1) { free(c); return NULL; } c->key = ssl_key_load(filename); if (!c->key) { X509_free(c->crt); if (c->chain) { sk_X509_pop_free(c->chain, X509_free); } free(c); return NULL; } c->references = 1; return c; } */ /* void key_keeper_async_ask(struct future * f, struct key_keeper * keeper, int keyring_id, X509 * origin_cert, int is_cert_valid, struct event_base * evbase) { X509* orig_cert=SSL_get_peer_certificate(origssl); //todo: need implement cert_t * keyring = NULL; if (opts->tgcrtdir) { if (ctx->sni) { keyring = (cert_t *) cachemgr_tgcrt_get(ctx->sni); if (!keyring) { char * wildcarded = ssl_wildcardify(ctx->sni); if (!wildcarded) { ctx->enomem = 1; return NULL; } keyring = (cert_t *) cachemgr_tgcrt_get(wildcarded); free(wildcarded); } if (keyring && OPTS_DEBUG(ctx->opts)) { log_dbg_printf("Target keyring by SNI\n"); } } else if (ctx->origcrt) { char ** names = ssl_x509_names(ctx->origcrt); for (char ** p = names; *p; p++) { if (!keyring) { keyring = (cert_t *) cachemgr_tgcrt_get(*p); } if (!keyring) { char * wildcarded = ssl_wildcardify(*p); if (!wildcarded) { ctx->enomem = 1; } else { keyring = (cert_t *) (wildcarded); free(wildcarded); } } free(*p); } free(names); if (ctx->enomem) { return NULL; } if (keyring && OPTS_DEBUG(ctx->opts)) { log_dbg_printf("Target keyring by origcrt\n"); } } if (keyring) { ctx->immutable_cert = 1; } } if (!keyring && ctx->origcrt && ctx->opts->key) { keyring = cert_new(); keyring->cert = (X509 *) cachemgr_fkcrt_get(ctx->origcrt); if (keyring->cert) { if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: HIT\n"); } else { if (OPTS_DEBUG(ctx->opts)) log_dbg_printf("Certificate cache: MISS\n"); keyring->cert = ssl_x509_forge(ctx->opts->cacrt, ctx->opts->cakey, ctx->origcrt, ctx->opts->key, NULL, ctx->opts->crlurl); cachemgr_fkcrt_set(ctx->origcrt, keyring->cert); } cert_set_key(keyring, ctx->opts->key); cert_set_chain(keyring, ctx->opts->chain); ctx->generated_cert = 1; } if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgendir) && ctx->origcrt) { ctx->origcrtfpr = ssl_x509_fingerprint(ctx->origcrt, 0); if (!ctx->origcrtfpr) ctx->enomem = 1; } if ((WANT_CONNECT_LOG(ctx) || ctx->opts->certgen_writeall) && keyring && keyring->cert) { ctx->usedcrtfpr = ssl_x509_fingerprint(keyring->cert, 0); if (!ctx->usedcrtfpr) ctx->enomem = 1; } return keyring; } */