From 80abb9e4dd0fa6fa383785898cdf31f0bc9cd189 Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Wed, 23 Apr 2025 18:26:51 +1000 Subject: [PATCH] feat: Add some improvments --- src/dane.c | 100 +++++++++++++++++++++++++++++++++++++++------------- src/proxy.c | 4 +++ 2 files changed, 80 insertions(+), 24 deletions(-) diff --git a/src/dane.c b/src/dane.c index 15aed10..0620e4c 100644 --- a/src/dane.c +++ b/src/dane.c @@ -13,6 +13,8 @@ #include // For SHA256 and SHA512 functions #include // For mkdir #include // For mkdir +#include // For directory operations +#include // For PATH_MAX #include // For errno and EEXIST #define CA_CERT_FILE "ca/ca_cert.pem" @@ -103,8 +105,6 @@ static int get_tlsa_records(const char* hostname, tlsa_record** records, int* re char dns_query[256]; sprintf(dns_query, "_443._tcp.%s", hostname); - printf("Looking up TLSA records for %s\n", dns_query); - // Initialize the record count and records array *record_count = 0; *records = NULL; @@ -114,12 +114,12 @@ static int get_tlsa_records(const char* hostname, tlsa_record** records, int* re int raw_record_count = 0; if (query_tlsa_records_doh(hostname, &raw_records, &raw_record_count) != 0 || raw_record_count == 0) { - // If no records found, return that DANE is not available - printf("No TLSA records found for %s\n", hostname); + // If no records found, return silently return 0; } - printf("Found %d real TLSA records\n", raw_record_count); + // Only log if TLSA records are found + printf("Found %d TLSA records for %s\n", raw_record_count, hostname); // Allocate memory for TLSA records *records = malloc(raw_record_count * sizeof(tlsa_record)); @@ -347,7 +347,7 @@ static int domain_matches_pattern(const char* domain, const char* pattern) { } // Validate that a certificate is valid for a given domain -static int validate_cert_domain(X509* cert, const char* hostname) { +static int validate_cert_domain(X509* cert, const char* hostname, int verbose) { int valid = 0; // First check the Common Name @@ -357,9 +357,11 @@ static int validate_cert_domain(X509* cert, const char* hostname) { X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name, sizeof(common_name)); if (domain_matches_pattern(hostname, common_name)) { - printf("Domain matches certificate Common Name: %s\n", common_name); + if (verbose) { + printf("Domain matches certificate Common Name: %s\n", common_name); + } valid = 1; - } else { + } else if (verbose) { printf("Domain does not match certificate Common Name: %s\n", common_name); } } @@ -368,7 +370,9 @@ static int validate_cert_domain(X509* cert, const char* hostname) { STACK_OF(GENERAL_NAME)* san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); if (san_names) { int san_count = sk_GENERAL_NAME_num(san_names); - printf("Certificate has %d Subject Alternative Names\n", san_count); + if (verbose) { + printf("Certificate has %d Subject Alternative Names\n", san_count); + } for (int i = 0; i < san_count; i++) { const GENERAL_NAME* current_name = sk_GENERAL_NAME_value(san_names, i); @@ -377,17 +381,19 @@ static int validate_cert_domain(X509* cert, const char* hostname) { const char* dns_name = (const char*)ASN1_STRING_get0_data(current_name->d.dNSName); if (domain_matches_pattern(hostname, dns_name)) { - printf("Domain matches SAN: %s\n", dns_name); + if (verbose) { + printf("Domain matches SAN: %s\n", dns_name); + } valid = 1; break; - } else { + } else if (verbose) { printf("Domain does not match SAN: %s\n", dns_name); } } } sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); - } else { + } else if (verbose) { printf("Certificate has no Subject Alternative Names\n"); } @@ -406,23 +412,30 @@ int verify_cert_against_dane(const char* hostname, X509* cert) { return -1; } - // Verify the certificate domain - domain_verified = validate_cert_domain(cert, hostname); + // Get TLSA records first to determine if we should do verbose logging + int has_tlsa = get_tlsa_records(hostname, &records, &record_count); + + if (!has_tlsa || record_count == 0) { + // No TLSA records, return silently + return 0; + } + + // Now that we know the domain has TLSA records, do verbose domain validation + domain_verified = validate_cert_domain(cert, hostname, 1); if (!domain_verified) { fprintf(stderr, "Certificate is not valid for domain: %s\n", hostname); + // Clean up records + for (int i = 0; i < record_count; i++) { + if (records[i].data) { + free(records[i].data); + } + } + free(records); return 0; } printf("Certificate domain validation successful for: %s\n", hostname); - if (!get_tlsa_records(hostname, &records, &record_count)) { - return -1; - } - - if (record_count == 0) { - return 0; - } - // Print records that will be used for verification printf("\n=== Starting DANE verification for %s ===\n", hostname); for (int i = 0; i < record_count; i++) { @@ -528,6 +541,7 @@ static int generate_ca_cert() { // Check if CA certificate already exists if (access(CA_CERT_FILE, F_OK) == 0 && access(CA_KEY_FILE, F_OK) == 0) { printf("CA certificate already exists\n"); + // Load the existing CA certificate and key FILE* ca_cert_file = fopen(CA_CERT_FILE, "r"); if (!ca_cert_file) { @@ -620,8 +634,8 @@ static int generate_ca_cert() { // Set certificate information X509_NAME* name = X509_get_subject_name(ca_cert); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)"FireProxy", -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char*)"Woodburn", -1, -1, 0); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)"FireProxy CA", -1, -1, 0); + X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char*)"FireProxy", -1, -1, 0); X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char*)"AU", -1, -1, 0); // Self-sign the certificate @@ -825,12 +839,50 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha return 1; } +// Function to delete all generated certificates (but not the CA certs) +static void delete_all_generated_certs() { + DIR* dir; + struct dirent* entry; + char path[PATH_MAX]; + + // Open the certificates directory + dir = opendir(CERT_DIR); + if (!dir) { + perror("Failed to open certificates directory for cleanup"); + return; + } + + // Read directory entries + while ((entry = readdir(dir)) != NULL) { + // Skip "." and ".." directories + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + // Create full path + snprintf(path, PATH_MAX, "%s/%s", CERT_DIR, entry->d_name); + + // Delete the file and log the action + if (unlink(path) == 0) { + printf("Deleted temporary certificate: %s\n", path); + } else { + perror("Failed to delete certificate"); + } + } + + closedir(dir); + printf("Cleaned up all generated certificates\n"); +} + int dane_init() { init_openssl(); return setup_local_ca(); } void dane_cleanup() { + // Delete all generated certificates first + delete_all_generated_certs(); + + // Then clean up CA resources if (ca_cert) { X509_free(ca_cert); ca_cert = NULL; diff --git a/src/proxy.c b/src/proxy.c index 97e7217..bfee3fb 100644 --- a/src/proxy.c +++ b/src/proxy.c @@ -710,7 +710,11 @@ void proxy_cleanup() { void handle_signal(int sig) { if (sig == SIGINT) { printf("\nShutting down proxy server...\n"); + printf("Cleaning up temporary certificates...\n"); + + // Clean up DANE resources (which will delete all generated certificates) proxy_cleanup(); + exit(0); } }