diff --git a/platform/src/ssl_fetch_cert.cpp b/platform/src/ssl_fetch_cert.cpp index 58927bb..c2e48b5 100644 --- a/platform/src/ssl_fetch_cert.cpp +++ b/platform/src/ssl_fetch_cert.cpp @@ -9,10 +9,12 @@ #include #include -typedef struct x509_object_st { +typedef struct x509_object_st +{ /* one of the above types */ X509_LOOKUP_TYPE type; - union { + union + { char *ptr; X509 *x509; X509_CRL *crl; @@ -20,6 +22,19 @@ typedef struct x509_object_st { } data; } X509_OBJECT; +enum CERT_TYPE { + ENTITY_CERT = 0, + INTERMEDIATE_CERT = 1, + ROOT_CERT = 2, + MAX_TYPE = 3, +}; + +static char cert_type_desc[MAX_TYPE][64] = { + {"Entity certificate"}, + {"Intermediate certificate"}, + {"Root certificate"}, +}; + static tfe_kafka_logger_t *g_kafka_logger = NULL; void ssl_mid_cert_kafka_logger_destory(void) @@ -33,16 +48,15 @@ int ssl_mid_cert_kafka_logger_create(const char *profile, const char *section) char nic_name[64] = {0}; char broker_list[TFE_SYMBOL_MAX] = {0}; char topic_name[TFE_SYMBOL_MAX] = {0}; - const char *errstr = "SSL mid cert cache occer error, "; MESA_load_profile_int_def(profile, section, "mc_cache_enable", &enable, 0); MESA_load_profile_string_def(profile, section, "mc_cache_eth", nic_name, sizeof(nic_name), "eth0"); MESA_load_profile_string_def(profile, section, "mc_cache_topic", topic_name, sizeof(topic_name), "PXY-EXCH-INTERMEDIA-CERT"); - if (!enable) // is disable,skip broker list + if (!enable) goto skip; if (MESA_load_profile_string_def(profile, section, "mc_cache_broker_list", broker_list, sizeof(broker_list), NULL) < 0) { - TFE_LOG_ERROR(g_default_logger, "%s, Fail to get mc_cache_broker_list in profile %s section %s.", errstr, profile, section); + TFE_LOG_ERROR(g_default_logger, "Fail to get mc_cache_broker_list in profile %s section %s.", profile, section); return -1; } skip: @@ -78,9 +92,40 @@ static void ssl_mid_cert_kafka_logger_send(const char *sni, const char *fingerpr cJSON_Delete(obj); } -// test use http://www.360.cn/ -void ssl_fetch_trusted_cert_from_chain(STACK_OF(X509) * cert_chain, X509_STORE *trusted_store, const char *hostname) { - int ret; +static int is_x509v3_ca_cert(X509 *x) +{ + /* what is Basic Constraint Extension: + * http://www.pkiglobe.org/ + * https://tools.ietf.org/html/rfc5280#section-4.2.1.9 + * + * how to visit Basic Constraint Extension: + * https://stackoverflow.com/questions/40609792/how-can-i-verify-certificate-has-ca-true-basic-constraint + */ + int is_ca = 0; + BASIC_CONSTRAINTS *bs = NULL; + + if (X509_get_version(x) != 2) + { + return is_ca; + } + + bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL); + if (bs) + { + if (bs->ca) + { + is_ca = 1; + } + BASIC_CONSTRAINTS_free(bs); + } + + return is_ca; +} + +void ssl_fetch_trusted_cert_from_chain(STACK_OF(X509) * cert_chain, X509_STORE *trusted_store, const char *hostname) +{ + int in_store; + int type; int deep; char *pem = NULL; char *subj = NULL; @@ -88,57 +133,87 @@ void ssl_fetch_trusted_cert_from_chain(STACK_OF(X509) * cert_chain, X509_STORE * char *fingerprint = NULL; X509 *cert = NULL; X509_OBJECT *obj = NULL; - if (!g_kafka_logger || !g_kafka_logger->enable) { + if (!g_kafka_logger || !g_kafka_logger->enable) + { return; } deep = sk_X509_num(cert_chain); - for (int i = 1; i < deep; i++) { - // need't call X509_FREE(cert) + for (int i = 0; i < deep; i++) + { cert = sk_X509_value(cert_chain, i); assert(cert); - obj = X509_OBJECT_new(); - assert(obj); - obj->type = X509_LU_X509; - obj->data.x509 = (X509 *)cert; - - X509_OBJECT_up_ref_count(obj); - - // not in trusted store - if (X509_OBJECT_retrieve_match(X509_STORE_get0_objects(trusted_store), obj) == NULL) - { - ret = 0; - } - // in trusted store - else - { - ret = 1; - } - // https://man.openbsd.org/X509_OBJECT_up_ref_count.3 - // https://groups.google.com/forum/m/#!msg/mailing.openssl.dev/9-PNIcR91Qo/FqnBOr8sBAAJ - //X509_OBJECT_free_contents(obj); - X509_OBJECT_free(obj); - + in_store = 0; subj = ssl_x509_subject(cert); issuer = ssl_x509_issuer(cert); fingerprint = ssl_x509_fingerprint(cert, 0); pem = ssl_x509_to_pem(cert); - TFE_LOG_DEBUG(g_default_logger, "[dep:%d/%d] in_trusted_store:%d, sin:%s; subject:(%s); issuer:(%s); fingerprint:%s; cert:%s", - i, deep, ret, (hostname ? hostname : "NULL"), (subj ? subj : "NULL"), (issuer ? issuer : "NULL"), (fingerprint ? fingerprint : "NULL"), - ((pem && g_kafka_logger->enable == 0x10) ? pem : " ...")); + if (!is_x509v3_ca_cert(cert)) + { + type = ENTITY_CERT; + goto end; + } + else + { + if (subj && issuer && strcmp(subj, issuer) == 0) + { + type = ROOT_CERT; + goto end; + } + else + { + type = INTERMEDIATE_CERT; + } + } - if (!ret && fingerprint && pem) { + obj = X509_OBJECT_new(); + assert(obj); + obj->type = X509_LU_X509; + obj->data.x509 = (X509 *)cert; + X509_OBJECT_up_ref_count(obj); + + // not in trusted store + if (X509_OBJECT_retrieve_match(X509_STORE_get0_objects(trusted_store), obj) == NULL) + { + in_store = 0; + } + // in trusted store + else + { + in_store = 1; + } + X509_OBJECT_free(obj); + + if (!in_store && fingerprint && pem) + { ssl_mid_cert_kafka_logger_send(hostname, fingerprint, pem); } + + end: + TFE_LOG_DEBUG(g_default_logger, "[dep:%d/%d] is %s, in_trusted_store:%d, sin:%s; subject:(%s); issuer:(%s); fingerprint:%s; cert:%s", + i, deep, cert_type_desc[type], in_store, (hostname ? hostname : "NULL"), (subj ? subj : "NULL"), (issuer ? issuer : "NULL"), (fingerprint ? fingerprint : "NULL"), + ((pem && g_kafka_logger->enable == 0x10) ? pem : " ...")); if (pem) + { free(pem); + pem = NULL; + } if (subj) + { free(subj); + subj = NULL; + } if (issuer) + { free(issuer); + issuer = NULL; + } if (fingerprint) + { free(fingerprint); + fingerprint = NULL; + } } } \ No newline at end of file