Compare commits
6 Commits
eb4b9c9f7e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
8e4f6498e8
|
|||
|
1eb4cdc288
|
|||
|
e877a18abf
|
|||
|
80abb9e4dd
|
|||
|
49592ed4c0
|
|||
|
4bde414964
|
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ fireproxy
|
||||
certs/
|
||||
|
||||
ca/
|
||||
*.log
|
||||
|
||||
@@ -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
|
||||
|
||||
436
src/dane.c
436
src/dane.c
@@ -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,
|
||||
cert_hash, cert_hash_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();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
2126
src/proxy.c
2126
src/proxy.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user