Compare commits

..

6 Commits

5 changed files with 2277 additions and 295 deletions

1
.gitignore vendored
View File

@@ -4,3 +4,4 @@ fireproxy
certs/
ca/
*.log

View File

@@ -9,6 +9,12 @@ FireProxy is a lightweight HTTP proxy server written in C that intercepts web re
- Uses hnsdoh.com as the DoH provider
- Multithreaded connection handling
## Install Dependencies
### Ubuntu/Debian (or similar)
```bash
apt install libssl-dev libcurl4-openssl-dev build-essential
```
## Building
```bash

View File

@@ -13,89 +13,135 @@
#include <openssl/sha.h> // For SHA256 and SHA512 functions
#include <sys/stat.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
#define CA_CERT_FILE "ca/ca_cert.pem"
#define CA_KEY_FILE "ca/ca_key.pem"
#define CERT_DIR "certs"
#define DANE_LOG_FILE "dane.log"
#define LOG_ERROR 0
#define LOG_WARNING 1
#define LOG_INFO 2
#define LOG_DEBUG 3
static int log_level = LOG_INFO;
static FILE* log_file = NULL;
static X509* ca_cert = NULL;
static EVP_PKEY* ca_key = NULL;
// Initialize logging
static void init_logging() {
log_file = fopen(DANE_LOG_FILE, "a");
if (!log_file) {
fprintf(stderr, "Warning: Unable to open log file. Logging to stderr.\n");
log_file = stderr;
}
}
// Close log file
static void close_logging() {
if (log_file != NULL && log_file != stderr) {
fclose(log_file);
log_file = NULL;
}
}
// Log message with specific level
static void log_message(int level, const char* format, ...) {
if (log_file == NULL) {
init_logging();
}
if (level <= log_level) {
va_list args;
time_t now;
struct tm* timeinfo;
char timestamp[20];
time(&now);
timeinfo = localtime(&now);
strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", timeinfo);
const char* level_str = "UNKNOWN";
switch (level) {
case LOG_ERROR: level_str = "ERROR"; break;
case LOG_WARNING: level_str = "WARNING"; break;
case LOG_INFO: level_str = "INFO"; break;
case LOG_DEBUG: level_str = "DEBUG"; break;
}
fprintf(log_file, "[%s] [%s] ", timestamp, level_str);
va_start(args, format);
vfprintf(log_file, format, args);
va_end(args);
fprintf(log_file, "\n");
fflush(log_file);
// Critical errors should also go to stderr
if (level == LOG_ERROR && log_file != stderr) {
va_start(args, format);
fprintf(stderr, "Error: ");
vfprintf(stderr, format, args);
fprintf(stderr, "\n");
va_end(args);
}
}
}
// Helper function to print TLSA record information
static void print_tlsa_record(const tlsa_record* record, int index) {
printf("\n=== TLSA Record #%d ===\n", index + 1);
log_message(LOG_DEBUG, "=== TLSA Record #%d ===", index + 1);
// Print usage field information
printf("Usage: %d (", record->usage);
const char* usage_str = "Unknown";
switch (record->usage) {
case 0:
printf("PKIX-TA - CA certificate");
break;
case 1:
printf("PKIX-EE - End entity certificate");
break;
case 2:
printf("DANE-TA - Trust anchor certificate");
break;
case 3:
printf("DANE-EE - Domain issued certificate");
break;
default:
printf("Unknown");
break;
case 0: usage_str = "PKIX-TA - CA certificate"; break;
case 1: usage_str = "PKIX-EE - End entity certificate"; break;
case 2: usage_str = "DANE-TA - Trust anchor certificate"; break;
case 3: usage_str = "DANE-EE - Domain issued certificate"; break;
}
printf(")\n");
log_message(LOG_DEBUG, "Usage: %d (%s)", record->usage, usage_str);
// Print selector field information
printf("Selector: %d (", record->selector);
const char* selector_str = "Unknown";
switch (record->selector) {
case 0:
printf("Full certificate");
break;
case 1:
printf("SubjectPublicKeyInfo");
break;
default:
printf("Unknown");
break;
case 0: selector_str = "Full certificate"; break;
case 1: selector_str = "SubjectPublicKeyInfo"; break;
}
printf(")\n");
log_message(LOG_DEBUG, "Selector: %d (%s)", record->selector, selector_str);
// Print matching type field information
printf("Matching Type: %d (", record->matching_type);
const char* matching_type_str = "Unknown";
switch (record->matching_type) {
case 0:
printf("Exact match");
break;
case 1:
printf("SHA-256 hash");
break;
case 2:
printf("SHA-512 hash");
break;
default:
printf("Unknown");
break;
case 0: matching_type_str = "Exact match"; break;
case 1: matching_type_str = "SHA-256 hash"; break;
case 2: matching_type_str = "SHA-512 hash"; break;
}
printf(")\n");
log_message(LOG_DEBUG, "Matching Type: %d (%s)", record->matching_type, matching_type_str);
// Print certificate association data as hex dump
printf("Certificate Association Data (%zu bytes):\n", record->data_len);
// Print certificate association data as hex dump to log
log_message(LOG_DEBUG, "Certificate Association Data (%zu bytes):", record->data_len);
char hex_line[100];
char* p;
for (size_t i = 0; i < record->data_len; i++) {
if (i % 16 == 0) {
printf(" %04zx: ", i);
p = hex_line;
p += sprintf(p, " %04zx: ", i);
}
printf("%02x", record->data[i]);
p += sprintf(p, "%02x", record->data[i]);
if ((i + 1) % 16 == 0 || i + 1 == record->data_len) {
printf("\n");
log_message(LOG_DEBUG, "%s", hex_line);
} else if ((i + 1) % 8 == 0) {
printf(" ");
p += sprintf(p, " ");
} else {
printf(" ");
p += sprintf(p, " ");
}
}
printf("\n");
}
// Get TLSA record for a domain
@@ -103,8 +149,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 +158,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
log_message(LOG_INFO, "Found %d TLSA records for %s", raw_record_count, hostname);
// Allocate memory for TLSA records
*records = malloc(raw_record_count * sizeof(tlsa_record));
@@ -216,14 +260,14 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
// Full certificate
data_len = i2d_X509(cert, &data);
if (data_len <= 0) {
fprintf(stderr, "Failed to convert certificate to DER format\n");
log_message(LOG_ERROR, "Failed to convert certificate to DER format");
return 0;
}
} else if (selector == 1) {
// Subject Public Key Info
EVP_PKEY* pubkey = X509_get_pubkey(cert);
if (!pubkey) {
fprintf(stderr, "Failed to extract public key from certificate\n");
log_message(LOG_ERROR, "Failed to extract public key from certificate");
return 0;
}
@@ -232,11 +276,11 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
EVP_PKEY_free(pubkey);
if (data_len <= 0) {
fprintf(stderr, "Failed to convert public key to DER format\n");
log_message(LOG_ERROR, "Failed to convert public key to DER format");
return 0;
}
} else {
fprintf(stderr, "Unsupported selector: %d\n", selector);
log_message(LOG_ERROR, "Unsupported selector: %d", selector);
return 0;
}
@@ -251,7 +295,7 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
hash = malloc(SHA256_DIGEST_LENGTH);
if (!hash) {
OPENSSL_free(data);
fprintf(stderr, "Failed to allocate memory for SHA-256 hash\n");
log_message(LOG_ERROR, "Failed to allocate memory for SHA-256 hash");
return 0;
}
@@ -266,7 +310,7 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
hash = malloc(SHA512_DIGEST_LENGTH);
if (!hash) {
OPENSSL_free(data);
fprintf(stderr, "Failed to allocate memory for SHA-512 hash\n");
log_message(LOG_ERROR, "Failed to allocate memory for SHA-512 hash");
return 0;
}
@@ -278,7 +322,7 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
return 1;
} else {
OPENSSL_free(data);
fprintf(stderr, "Unsupported matching type: %d\n", matching_type);
log_message(LOG_ERROR, "Unsupported matching type: %d", matching_type);
return 0;
}
}
@@ -287,68 +331,162 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
static int compare_hashes(const unsigned char* expected, size_t expected_len,
const unsigned char* actual, size_t actual_len) {
if (expected_len != actual_len) {
printf("Hash length mismatch: expected %zu bytes, got %zu bytes\n", expected_len, actual_len);
log_message(LOG_WARNING, "Hash length mismatch: expected %zu bytes, got %zu bytes", expected_len, actual_len);
return 0;
}
int result = memcmp(expected, actual, expected_len) == 0;
printf("Certificate hash comparison: %s\n", result ? "MATCH" : "MISMATCH");
log_message(LOG_INFO, "Certificate hash comparison: %s", result ? "MATCH" : "MISMATCH");
printf("Expected hash:\n");
log_message(LOG_DEBUG, "Expected hash:");
char hex_line[100];
char* p;
for (size_t i = 0; i < expected_len; i++) {
if (i % 16 == 0) {
printf(" %04zx: ", i);
p = hex_line;
p += sprintf(p, " %04zx: ", i);
}
printf("%02x", expected[i]);
p += sprintf(p, "%02x", expected[i]);
if ((i + 1) % 16 == 0 || i + 1 == expected_len) {
printf("\n");
log_message(LOG_DEBUG, "%s", hex_line);
} else if ((i + 1) % 8 == 0) {
printf(" ");
p += sprintf(p, " ");
} else {
printf(" ");
p += sprintf(p, " ");
}
}
printf("Actual hash:\n");
log_message(LOG_DEBUG, "Actual hash:");
for (size_t i = 0; i < actual_len; i++) {
if (i % 16 == 0) {
printf(" %04zx: ", i);
p = hex_line;
p += sprintf(p, " %04zx: ", i);
}
printf("%02x", actual[i]);
p += sprintf(p, "%02x", actual[i]);
if ((i + 1) % 16 == 0 || i + 1 == actual_len) {
printf("\n");
log_message(LOG_DEBUG, "%s", hex_line);
} else if ((i + 1) % 8 == 0) {
printf(" ");
p += sprintf(p, " ");
} else {
printf(" ");
p += sprintf(p, " ");
}
}
return result;
}
// Check if a domain matches a pattern (supporting wildcards)
static int domain_matches_pattern(const char* domain, const char* pattern) {
// Exact match
if (strcmp(domain, pattern) == 0) {
return 1;
}
// Wildcard match
if (pattern[0] == '*' && pattern[1] == '.') {
const char* domain_dot = strchr(domain, '.');
if (domain_dot && strcmp(domain_dot, pattern + 1) == 0) {
return 1;
}
}
return 0;
}
// Validate that a certificate is valid for a given domain
static int validate_cert_domain(X509* cert, const char* hostname, int verbose) {
int valid = 0;
// First check the Common Name
X509_NAME* subject_name = X509_get_subject_name(cert);
if (subject_name) {
char common_name[256];
X509_NAME_get_text_by_NID(subject_name, NID_commonName, common_name, sizeof(common_name));
if (domain_matches_pattern(hostname, common_name)) {
if (verbose) {
log_message(LOG_INFO, "Domain matches certificate Common Name: %s", common_name);
}
valid = 1;
} else if (verbose) {
log_message(LOG_INFO, "Domain does not match certificate Common Name: %s", common_name);
}
}
// Then check Subject Alternative Names
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);
if (verbose) {
log_message(LOG_INFO, "Certificate has %d Subject Alternative Names", san_count);
}
for (int i = 0; i < san_count; i++) {
const GENERAL_NAME* current_name = sk_GENERAL_NAME_value(san_names, i);
if (current_name->type == GEN_DNS) {
const char* dns_name = (const char*)ASN1_STRING_get0_data(current_name->d.dNSName);
if (domain_matches_pattern(hostname, dns_name)) {
if (verbose) {
log_message(LOG_INFO, "Domain matches SAN: %s", dns_name);
}
valid = 1;
break;
} else if (verbose) {
log_message(LOG_INFO, "Domain does not match SAN: %s", dns_name);
}
}
}
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
} else if (verbose) {
log_message(LOG_INFO, "Certificate has no Subject Alternative Names");
}
return valid;
}
// Verify a certificate against DANE TLSA records
int verify_cert_against_dane(const char* hostname, X509* cert) {
tlsa_record* records = NULL;
int record_count = 0;
int verified = 0;
int dane_verified = 0;
int domain_verified = 0;
if (!cert) {
fprintf(stderr, "No certificate provided for DANE verification\n");
log_message(LOG_ERROR, "No certificate provided for DANE verification");
return -1;
}
if (!get_tlsa_records(hostname, &records, &record_count)) {
return -1;
}
// Get TLSA records first to determine if we should do verbose logging
int has_tlsa = get_tlsa_records(hostname, &records, &record_count);
if (record_count == 0) {
if (!has_tlsa || record_count == 0) {
// No TLSA records, return silently
return 0;
}
// Print records that will be used for verification
printf("\n=== Starting DANE verification for %s ===\n", hostname);
// Now that we know the domain has TLSA records, do verbose domain validation
domain_verified = validate_cert_domain(cert, hostname, 1);
if (!domain_verified) {
log_message(LOG_ERROR, "Certificate is not valid for domain: %s", hostname);
// Clean up records
for (int i = 0; i < record_count; i++) {
if (records[i].data) {
free(records[i].data);
}
}
free(records);
return 0;
}
log_message(LOG_INFO, "Certificate domain validation successful for: %s", hostname);
printf("DANE: Verifying certificate for %s...\n", hostname);
// Log records that will be used for verification
log_message(LOG_DEBUG, "=== Starting DANE verification for %s ===", hostname);
for (int i = 0; i < record_count; i++) {
print_tlsa_record(&records[i], i);
}
@@ -357,7 +495,7 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
for (int i = 0; i < record_count; i++) {
tlsa_record* record = &records[i];
printf("\nVerifying certificate against TLSA record #%d...\n", i + 1);
log_message(LOG_DEBUG, "Verifying certificate against TLSA record #%d...", i + 1);
// Generate the certificate hash based on selector and matching type
unsigned char* cert_hash = NULL;
@@ -365,7 +503,7 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
if (!extract_and_hash_cert(cert, record->selector, record->matching_type,
&cert_hash, &cert_hash_len)) {
fprintf(stderr, "Failed to extract and hash certificate\n");
log_message(LOG_ERROR, "Failed to extract and hash certificate");
continue;
}
@@ -373,41 +511,48 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
switch (record->usage) {
case 0: // PKIX-TA - CA constraint
// Not implemented in this simplified version
printf("PKIX-TA validation not implemented\n");
log_message(LOG_INFO, "PKIX-TA validation not implemented");
break;
case 1: // PKIX-EE - Service certificate constraint
// Not implemented in this simplified version
printf("PKIX-EE validation not implemented\n");
log_message(LOG_INFO, "PKIX-EE validation not implemented");
break;
case 2: // DANE-TA - Trust anchor assertion
// Not implemented in this simplified version
printf("DANE-TA validation not implemented\n");
log_message(LOG_INFO, "DANE-TA validation not implemented");
break;
case 3: // DANE-EE (3) - Domain-issued certificate
// Verify the certificate directly against the TLSA record
printf("Performing DANE-EE validation...\n");
verified = compare_hashes(record->data, record->data_len,
log_message(LOG_INFO, "Performing DANE-EE validation...");
dane_verified = compare_hashes(record->data, record->data_len,
cert_hash, cert_hash_len);
break;
default:
// Unknown usage type
printf("Unknown usage type: %d\n", record->usage);
log_message(LOG_WARNING, "Unknown usage type: %d", record->usage);
break;
}
free(cert_hash);
if (verified) {
printf("DANE verification succeeded for record #%d\n", i + 1);
if (dane_verified) {
log_message(LOG_INFO, "DANE verification succeeded for record #%d", i + 1);
break;
}
}
printf("\nDANE verification result: %s\n", verified ? "SUCCESS" : "FAILED");
int verified = domain_verified && dane_verified;
log_message(LOG_INFO, "Domain verification: %s", domain_verified ? "SUCCESS" : "FAILED");
log_message(LOG_INFO, "DANE verification: %s", dane_verified ? "SUCCESS" : "FAILED");
log_message(LOG_INFO, "Overall verification result: %s", verified ? "SUCCESS" : "FAILED");
// Show minimal output to console
printf("DANE: Verification %s for %s\n",
verified ? "SUCCEEDED" : "FAILED", hostname);
// Clean up
for (int i = 0; i < record_count; i++) {
@@ -448,11 +593,12 @@ static int create_cert_directories() {
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");
log_message(LOG_INFO, "CA certificate already exists");
// Load the existing CA certificate and key
FILE* ca_cert_file = fopen(CA_CERT_FILE, "r");
if (!ca_cert_file) {
perror("Failed to open CA certificate file");
log_message(LOG_ERROR, "Failed to open CA certificate file");
return 0;
}
@@ -460,13 +606,13 @@ static int generate_ca_cert() {
fclose(ca_cert_file);
if (!ca_cert) {
fprintf(stderr, "Failed to read CA certificate\n");
log_message(LOG_ERROR, "Failed to read CA certificate");
return 0;
}
FILE* ca_key_file = fopen(CA_KEY_FILE, "r");
if (!ca_key_file) {
perror("Failed to open CA key file");
log_message(LOG_ERROR, "Failed to open CA key file");
X509_free(ca_cert);
ca_cert = NULL;
return 0;
@@ -476,7 +622,7 @@ static int generate_ca_cert() {
fclose(ca_key_file);
if (!ca_key) {
fprintf(stderr, "Failed to read CA key\n");
log_message(LOG_ERROR, "Failed to read CA key");
X509_free(ca_cert);
ca_cert = NULL;
return 0;
@@ -491,7 +637,7 @@ static int generate_ca_cert() {
BIGNUM* bn = BN_new();
if (!bn) {
fprintf(stderr, "Failed to create BIGNUM\n");
log_message(LOG_ERROR, "Failed to create BIGNUM");
EVP_PKEY_free(ca_key);
ca_key = NULL;
return 0;
@@ -501,7 +647,7 @@ static int generate_ca_cert() {
rsa = RSA_new();
if (!rsa) {
fprintf(stderr, "Failed to create RSA\n");
log_message(LOG_ERROR, "Failed to create RSA");
BN_free(bn);
EVP_PKEY_free(ca_key);
ca_key = NULL;
@@ -509,7 +655,7 @@ static int generate_ca_cert() {
}
if (RSA_generate_key_ex(rsa, 2048, bn, NULL) != 1) {
fprintf(stderr, "Failed to generate RSA key\n");
log_message(LOG_ERROR, "Failed to generate RSA key");
RSA_free(rsa);
BN_free(bn);
EVP_PKEY_free(ca_key);
@@ -520,7 +666,7 @@ static int generate_ca_cert() {
BN_free(bn);
if (!EVP_PKEY_assign_RSA(ca_key, rsa)) {
fprintf(stderr, "Failed to assign RSA key\n");
log_message(LOG_ERROR, "Failed to assign RSA key");
RSA_free(rsa);
EVP_PKEY_free(ca_key);
ca_key = NULL;
@@ -543,7 +689,7 @@ static int generate_ca_cert() {
X509_NAME* name = X509_get_subject_name(ca_cert);
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*)"US", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char*)"AU", -1, -1, 0);
// Self-sign the certificate
X509_set_issuer_name(ca_cert, name);
@@ -555,7 +701,7 @@ static int generate_ca_cert() {
X509_EXTENSION* ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, "critical,CA:TRUE");
if (!ext) {
fprintf(stderr, "Failed to create CA extension\n");
log_message(LOG_ERROR, "Failed to create CA extension");
EVP_PKEY_free(ca_key);
X509_free(ca_cert);
ca_key = NULL;
@@ -568,7 +714,7 @@ static int generate_ca_cert() {
// Sign the certificate
if (!X509_sign(ca_cert, ca_key, EVP_sha256())) {
fprintf(stderr, "Failed to sign CA certificate\n");
log_message(LOG_ERROR, "Failed to sign CA certificate");
EVP_PKEY_free(ca_key);
X509_free(ca_cert);
ca_key = NULL;
@@ -579,7 +725,7 @@ static int generate_ca_cert() {
// Save the CA certificate and key
FILE* ca_cert_file = fopen(CA_CERT_FILE, "w");
if (!ca_cert_file) {
perror("Failed to create CA certificate file");
log_message(LOG_ERROR, "Failed to create CA certificate file");
EVP_PKEY_free(ca_key);
X509_free(ca_cert);
ca_key = NULL;
@@ -592,7 +738,7 @@ static int generate_ca_cert() {
FILE* ca_key_file = fopen(CA_KEY_FILE, "w");
if (!ca_key_file) {
perror("Failed to create CA key file");
log_message(LOG_ERROR, "Failed to create CA key file");
EVP_PKEY_free(ca_key);
X509_free(ca_cert);
ca_key = NULL;
@@ -603,7 +749,7 @@ static int generate_ca_cert() {
PEM_write_PrivateKey(ca_key_file, ca_key, NULL, NULL, 0, NULL, NULL);
fclose(ca_key_file);
printf("Generated new CA certificate\n");
log_message(LOG_INFO, "Generated new CA certificate");
return 1;
}
@@ -616,13 +762,13 @@ int setup_local_ca() {
return 0;
}
printf("CA setup complete\n");
log_message(LOG_INFO, "CA setup complete");
return 1;
}
int generate_trusted_cert(const char* hostname, const char* cert_path, const char* key_path) {
if (!ca_cert || !ca_key) {
fprintf(stderr, "CA not initialized\n");
log_message(LOG_ERROR, "CA not initialized");
return 0;
}
@@ -632,7 +778,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
BIGNUM* bn = BN_new();
if (!bn) {
fprintf(stderr, "Failed to create BIGNUM\n");
log_message(LOG_ERROR, "Failed to create BIGNUM");
EVP_PKEY_free(pkey);
return 0;
}
@@ -641,14 +787,14 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
rsa = RSA_new();
if (!rsa) {
fprintf(stderr, "Failed to create RSA\n");
log_message(LOG_ERROR, "Failed to create RSA");
BN_free(bn);
EVP_PKEY_free(pkey);
return 0;
}
if (RSA_generate_key_ex(rsa, 2048, bn, NULL) != 1) {
fprintf(stderr, "Failed to generate RSA key\n");
log_message(LOG_ERROR, "Failed to generate RSA key");
RSA_free(rsa);
BN_free(bn);
EVP_PKEY_free(pkey);
@@ -658,7 +804,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
BN_free(bn);
if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
fprintf(stderr, "Failed to assign RSA key\n");
log_message(LOG_ERROR, "Failed to assign RSA key");
RSA_free(rsa);
EVP_PKEY_free(pkey);
return 0;
@@ -681,7 +827,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
// Set certificate subject
X509_NAME* name = X509_get_subject_name(cert);
X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char*)hostname, -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char*)"FireProxy Secured", -1, -1, 0);
X509_NAME_add_entry_by_txt(name, "O", MBSTRING_ASC, (unsigned char*)"FireProxy", -1, -1, 0);
// Set certificate issuer (our CA)
X509_set_issuer_name(cert, X509_get_subject_name(ca_cert));
@@ -697,7 +843,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
X509_EXTENSION* ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_alt_name, san);
if (!ext) {
fprintf(stderr, "Failed to create SAN extension\n");
log_message(LOG_ERROR, "Failed to create SAN extension");
EVP_PKEY_free(pkey);
X509_free(cert);
return 0;
@@ -708,7 +854,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
// Sign the certificate with our CA key
if (!X509_sign(cert, ca_key, EVP_sha256())) {
fprintf(stderr, "Failed to sign certificate\n");
log_message(LOG_ERROR, "Failed to sign certificate");
EVP_PKEY_free(pkey);
X509_free(cert);
return 0;
@@ -717,7 +863,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
// Save the certificate
FILE* cert_file = fopen(cert_path, "w");
if (!cert_file) {
perror("Failed to create certificate file");
log_message(LOG_ERROR, "Failed to create certificate file");
EVP_PKEY_free(pkey);
X509_free(cert);
return 0;
@@ -729,7 +875,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
// Save the private key
FILE* key_file = fopen(key_path, "w");
if (!key_file) {
perror("Failed to create key file");
log_message(LOG_ERROR, "Failed to create key file");
EVP_PKEY_free(pkey);
X509_free(cert);
return 0;
@@ -742,16 +888,56 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
EVP_PKEY_free(pkey);
X509_free(cert);
printf("Generated trusted certificate for %s\n", hostname);
log_message(LOG_INFO, "Generated trusted certificate for %s", hostname);
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) {
log_message(LOG_ERROR, "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) {
log_message(LOG_INFO, "Deleted temporary certificate: %s", path);
} else {
log_message(LOG_ERROR, "Failed to delete certificate: %s", path);
}
}
closedir(dir);
log_message(LOG_INFO, "Cleaned up all generated certificates");
}
int dane_init() {
init_openssl();
init_logging();
log_message(LOG_INFO, "DANE subsystem initialized");
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;
@@ -762,5 +948,7 @@ void dane_cleanup() {
ca_key = NULL;
}
log_message(LOG_INFO, "DANE subsystem shutdown");
close_logging();
EVP_cleanup();
}

View File

@@ -61,4 +61,9 @@ int dane_init();
*/
void dane_cleanup();
/**
* Set DANE log level (0=errors only, 1=warnings, 2=info, 3=debug)
*/
void dane_set_log_level(int level);
#endif // DANE_H

File diff suppressed because it is too large Load Diff