This repository has been archived on 2025-09-14. You can view files and clone it, but cannot push or open issues or pull requests.
Files
tango-tfe/platform/src/ssl_fetch_cert.cpp
2023-12-19 14:23:55 +08:00

222 lines
4.9 KiB
C++

//
// Created by lwp on 2019/10/16.
//
#include <assert.h>
#include <cjson/cJSON.h>
#include <ssl_utils.h>
#include <tfe_kafka_logger.h>
#include <tfe_resource.h>
#include <MESA/MESA_prof_load.h>
typedef struct x509_object_st
{
/* one of the above types */
X509_LOOKUP_TYPE type;
union
{
char *ptr;
X509 *x509;
X509_CRL *crl;
EVP_PKEY *pkey;
} 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"},
};
struct ssl_mid_cert_ctx
{
int enable;
tfe_kafka_logger_t *g_kafka_logger;
};
struct ssl_mid_cert_ctx mid_cert_ctx;
int ssl_mid_cert_kafka_logger_create(const char *profile, const char *section)
{
char topic_name[TFE_SYMBOL_MAX] = {0};
MESA_load_profile_int_def(profile, section, "mc_cache_enable", &mid_cert_ctx.enable, 0);
MESA_load_profile_string_def(profile, "tfe", "mc_cache_topic", topic_name, sizeof(topic_name), "PXY-EXCH-INTERMEDIA-CERT");
if(mid_cert_ctx.enable == 0)
{
return 0;
}
mid_cert_ctx.g_kafka_logger = (tfe_kafka_logger_t *)tfe_bussiness_resouce_get(KAFKA_LOGGER);
if(!mid_cert_ctx.g_kafka_logger)
{
return -1;
}
int ret = tfe_kafka_logger_topic_new(mid_cert_ctx.g_kafka_logger, topic_name, TOPIC_MC_CACHE, g_default_logger);
if(ret < 0)
{
return -1;
}
return 0;
}
static void ssl_mid_cert_kafka_logger_send(const char *sni, const char *fingerprint, const char *cert)
{
if (mid_cert_ctx.g_kafka_logger->enable == 0)
{
return;
}
cJSON *obj = NULL;
cJSON *dup = NULL;
char *msg = NULL;
obj = cJSON_CreateObject();
cJSON_AddStringToObject(obj, "sni", sni);
cJSON_AddStringToObject(obj, "fingerprint", fingerprint);
cJSON_AddNumberToObject(obj, "vsys_id", mid_cert_ctx.g_kafka_logger->t_vsys_id);
cJSON_AddStringToObject(obj, "cert", cert);
cJSON_AddStringToObject(obj, "tfe_ip", mid_cert_ctx.g_kafka_logger->local_ip_str);
dup = cJSON_Duplicate(obj, 1);
msg = cJSON_PrintUnformatted(dup);
TFE_LOG_DEBUG(g_default_logger, "log to [%s] msg:%s", mid_cert_ctx.g_kafka_logger->topic_name[TOPIC_MC_CACHE], msg);
tfe_kafka_logger_send(mid_cert_ctx.g_kafka_logger, TOPIC_MC_CACHE, msg, strlen(msg));
free(msg);
cJSON_Delete(dup);
cJSON_Delete(obj);
}
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;
char *issuer = NULL;
char *fingerprint = NULL;
X509 *cert = NULL;
X509_OBJECT *obj = NULL;
if (!mid_cert_ctx.g_kafka_logger || !mid_cert_ctx.enable)
{
return;
}
deep = sk_X509_num(cert_chain);
for (int i = 0; i < deep; i++)
{
cert = sk_X509_value(cert_chain, i);
assert(cert);
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);
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;
}
}
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 && mid_cert_ctx.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;
}
}
}