feat: Add some improvments
This commit is contained in:
100
src/dane.c
100
src/dane.c
@@ -13,6 +13,8 @@
|
|||||||
#include <openssl/sha.h> // For SHA256 and SHA512 functions
|
#include <openssl/sha.h> // For SHA256 and SHA512 functions
|
||||||
#include <sys/stat.h> // For mkdir
|
#include <sys/stat.h> // For mkdir
|
||||||
#include <sys/types.h> // For mkdir
|
#include <sys/types.h> // For mkdir
|
||||||
|
#include <dirent.h> // For directory operations
|
||||||
|
#include <limits.h> // For PATH_MAX
|
||||||
#include <errno.h> // For errno and EEXIST
|
#include <errno.h> // For errno and EEXIST
|
||||||
|
|
||||||
#define CA_CERT_FILE "ca/ca_cert.pem"
|
#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];
|
char dns_query[256];
|
||||||
sprintf(dns_query, "_443._tcp.%s", hostname);
|
sprintf(dns_query, "_443._tcp.%s", hostname);
|
||||||
|
|
||||||
printf("Looking up TLSA records for %s\n", dns_query);
|
|
||||||
|
|
||||||
// Initialize the record count and records array
|
// Initialize the record count and records array
|
||||||
*record_count = 0;
|
*record_count = 0;
|
||||||
*records = NULL;
|
*records = NULL;
|
||||||
@@ -114,12 +114,12 @@ static int get_tlsa_records(const char* hostname, tlsa_record** records, int* re
|
|||||||
int raw_record_count = 0;
|
int raw_record_count = 0;
|
||||||
|
|
||||||
if (query_tlsa_records_doh(hostname, &raw_records, &raw_record_count) != 0 || 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
|
// If no records found, return silently
|
||||||
printf("No TLSA records found for %s\n", hostname);
|
|
||||||
return 0;
|
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
|
// Allocate memory for TLSA records
|
||||||
*records = malloc(raw_record_count * sizeof(tlsa_record));
|
*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
|
// 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;
|
int valid = 0;
|
||||||
|
|
||||||
// First check the Common Name
|
// 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));
|
X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name, sizeof(common_name));
|
||||||
|
|
||||||
if (domain_matches_pattern(hostname, 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;
|
valid = 1;
|
||||||
} else {
|
} else if (verbose) {
|
||||||
printf("Domain does not match certificate Common Name: %s\n", common_name);
|
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);
|
STACK_OF(GENERAL_NAME)* san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
|
||||||
if (san_names) {
|
if (san_names) {
|
||||||
int san_count = sk_GENERAL_NAME_num(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++) {
|
for (int i = 0; i < san_count; i++) {
|
||||||
const GENERAL_NAME* current_name = sk_GENERAL_NAME_value(san_names, 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);
|
const char* dns_name = (const char*)ASN1_STRING_get0_data(current_name->d.dNSName);
|
||||||
|
|
||||||
if (domain_matches_pattern(hostname, dns_name)) {
|
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;
|
valid = 1;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else if (verbose) {
|
||||||
printf("Domain does not match SAN: %s\n", dns_name);
|
printf("Domain does not match SAN: %s\n", dns_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
|
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
|
||||||
} else {
|
} else if (verbose) {
|
||||||
printf("Certificate has no Subject Alternative Names\n");
|
printf("Certificate has no Subject Alternative Names\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,23 +412,30 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify the certificate domain
|
// Get TLSA records first to determine if we should do verbose logging
|
||||||
domain_verified = validate_cert_domain(cert, hostname);
|
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) {
|
if (!domain_verified) {
|
||||||
fprintf(stderr, "Certificate is not valid for domain: %s\n", hostname);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Certificate domain validation successful for: %s\n", hostname);
|
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
|
// Print records that will be used for verification
|
||||||
printf("\n=== Starting DANE verification for %s ===\n", hostname);
|
printf("\n=== Starting DANE verification for %s ===\n", hostname);
|
||||||
for (int i = 0; i < record_count; i++) {
|
for (int i = 0; i < record_count; i++) {
|
||||||
@@ -528,6 +541,7 @@ static int generate_ca_cert() {
|
|||||||
// Check if CA certificate already exists
|
// Check if CA certificate already exists
|
||||||
if (access(CA_CERT_FILE, F_OK) == 0 && access(CA_KEY_FILE, F_OK) == 0) {
|
if (access(CA_CERT_FILE, F_OK) == 0 && access(CA_KEY_FILE, F_OK) == 0) {
|
||||||
printf("CA certificate already exists\n");
|
printf("CA certificate already exists\n");
|
||||||
|
|
||||||
// Load the existing CA certificate and key
|
// Load the existing CA certificate and key
|
||||||
FILE* ca_cert_file = fopen(CA_CERT_FILE, "r");
|
FILE* ca_cert_file = fopen(CA_CERT_FILE, "r");
|
||||||
if (!ca_cert_file) {
|
if (!ca_cert_file) {
|
||||||
@@ -620,8 +634,8 @@ static int generate_ca_cert() {
|
|||||||
|
|
||||||
// Set certificate information
|
// Set certificate information
|
||||||
X509_NAME* name = X509_get_subject_name(ca_cert);
|
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, "CN", MBSTRING_ASC, (unsigned char*)"FireProxy CA", -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, "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);
|
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char*)"AU", -1, -1, 0);
|
||||||
|
|
||||||
// Self-sign the certificate
|
// Self-sign the certificate
|
||||||
@@ -825,12 +839,50 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
return 1;
|
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() {
|
int dane_init() {
|
||||||
init_openssl();
|
init_openssl();
|
||||||
return setup_local_ca();
|
return setup_local_ca();
|
||||||
}
|
}
|
||||||
|
|
||||||
void dane_cleanup() {
|
void dane_cleanup() {
|
||||||
|
// Delete all generated certificates first
|
||||||
|
delete_all_generated_certs();
|
||||||
|
|
||||||
|
// Then clean up CA resources
|
||||||
if (ca_cert) {
|
if (ca_cert) {
|
||||||
X509_free(ca_cert);
|
X509_free(ca_cert);
|
||||||
ca_cert = NULL;
|
ca_cert = NULL;
|
||||||
|
|||||||
@@ -710,7 +710,11 @@ void proxy_cleanup() {
|
|||||||
void handle_signal(int sig) {
|
void handle_signal(int sig) {
|
||||||
if (sig == SIGINT) {
|
if (sig == SIGINT) {
|
||||||
printf("\nShutting down proxy server...\n");
|
printf("\nShutting down proxy server...\n");
|
||||||
|
printf("Cleaning up temporary certificates...\n");
|
||||||
|
|
||||||
|
// Clean up DANE resources (which will delete all generated certificates)
|
||||||
proxy_cleanup();
|
proxy_cleanup();
|
||||||
|
|
||||||
exit(0);
|
exit(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user