feat: Add some better logging and add deps to readme
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -4,3 +4,4 @@ fireproxy
|
|||||||
certs/
|
certs/
|
||||||
|
|
||||||
ca/
|
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
|
- Uses hnsdoh.com as the DoH provider
|
||||||
- Multithreaded connection handling
|
- Multithreaded connection handling
|
||||||
|
|
||||||
|
## Install Dependencies
|
||||||
|
### Ubuntu/Debian (or similar)
|
||||||
|
```bash
|
||||||
|
apt install libssl-dev libcurl4-openssl-dev build-essential
|
||||||
|
```
|
||||||
|
|
||||||
## Building
|
## Building
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|||||||
307
src/dane.c
307
src/dane.c
@@ -20,84 +20,128 @@
|
|||||||
#define CA_CERT_FILE "ca/ca_cert.pem"
|
#define CA_CERT_FILE "ca/ca_cert.pem"
|
||||||
#define CA_KEY_FILE "ca/ca_key.pem"
|
#define CA_KEY_FILE "ca/ca_key.pem"
|
||||||
#define CERT_DIR "certs"
|
#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 X509* ca_cert = NULL;
|
||||||
static EVP_PKEY* ca_key = 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
|
// Helper function to print TLSA record information
|
||||||
static void print_tlsa_record(const tlsa_record* record, int index) {
|
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
|
// Print usage field information
|
||||||
printf("Usage: %d (", record->usage);
|
const char* usage_str = "Unknown";
|
||||||
switch (record->usage) {
|
switch (record->usage) {
|
||||||
case 0:
|
case 0: usage_str = "PKIX-TA - CA certificate"; break;
|
||||||
printf("PKIX-TA - CA certificate");
|
case 1: usage_str = "PKIX-EE - End entity certificate"; break;
|
||||||
break;
|
case 2: usage_str = "DANE-TA - Trust anchor certificate"; break;
|
||||||
case 1:
|
case 3: usage_str = "DANE-EE - Domain issued certificate"; break;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
printf(")\n");
|
log_message(LOG_DEBUG, "Usage: %d (%s)", record->usage, usage_str);
|
||||||
|
|
||||||
// Print selector field information
|
// Print selector field information
|
||||||
printf("Selector: %d (", record->selector);
|
const char* selector_str = "Unknown";
|
||||||
switch (record->selector) {
|
switch (record->selector) {
|
||||||
case 0:
|
case 0: selector_str = "Full certificate"; break;
|
||||||
printf("Full certificate");
|
case 1: selector_str = "SubjectPublicKeyInfo"; break;
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
printf("SubjectPublicKeyInfo");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("Unknown");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
printf(")\n");
|
log_message(LOG_DEBUG, "Selector: %d (%s)", record->selector, selector_str);
|
||||||
|
|
||||||
// Print matching type field information
|
// Print matching type field information
|
||||||
printf("Matching Type: %d (", record->matching_type);
|
const char* matching_type_str = "Unknown";
|
||||||
switch (record->matching_type) {
|
switch (record->matching_type) {
|
||||||
case 0:
|
case 0: matching_type_str = "Exact match"; break;
|
||||||
printf("Exact match");
|
case 1: matching_type_str = "SHA-256 hash"; break;
|
||||||
break;
|
case 2: matching_type_str = "SHA-512 hash"; break;
|
||||||
case 1:
|
|
||||||
printf("SHA-256 hash");
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
printf("SHA-512 hash");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
printf("Unknown");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
printf(")\n");
|
log_message(LOG_DEBUG, "Matching Type: %d (%s)", record->matching_type, matching_type_str);
|
||||||
|
|
||||||
// Print certificate association data as hex dump
|
// Print certificate association data as hex dump to log
|
||||||
printf("Certificate Association Data (%zu bytes):\n", record->data_len);
|
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++) {
|
for (size_t i = 0; i < record->data_len; i++) {
|
||||||
if (i % 16 == 0) {
|
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) {
|
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) {
|
} else if ((i + 1) % 8 == 0) {
|
||||||
printf(" ");
|
p += sprintf(p, " ");
|
||||||
} else {
|
} else {
|
||||||
printf(" ");
|
p += sprintf(p, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get TLSA record for a domain
|
// Get TLSA record for a domain
|
||||||
@@ -119,7 +163,7 @@ static int get_tlsa_records(const char* hostname, tlsa_record** records, int* re
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only log if TLSA records are found
|
// Only log if TLSA records are found
|
||||||
printf("Found %d TLSA records for %s\n", raw_record_count, hostname);
|
log_message(LOG_INFO, "Found %d TLSA records for %s", 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));
|
||||||
@@ -216,14 +260,14 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
|
|||||||
// Full certificate
|
// Full certificate
|
||||||
data_len = i2d_X509(cert, &data);
|
data_len = i2d_X509(cert, &data);
|
||||||
if (data_len <= 0) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
} else if (selector == 1) {
|
} else if (selector == 1) {
|
||||||
// Subject Public Key Info
|
// Subject Public Key Info
|
||||||
EVP_PKEY* pubkey = X509_get_pubkey(cert);
|
EVP_PKEY* pubkey = X509_get_pubkey(cert);
|
||||||
if (!pubkey) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,11 +276,11 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
|
|||||||
EVP_PKEY_free(pubkey);
|
EVP_PKEY_free(pubkey);
|
||||||
|
|
||||||
if (data_len <= 0) {
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Unsupported selector: %d\n", selector);
|
log_message(LOG_ERROR, "Unsupported selector: %d", selector);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +295,7 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
|
|||||||
hash = malloc(SHA256_DIGEST_LENGTH);
|
hash = malloc(SHA256_DIGEST_LENGTH);
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
OPENSSL_free(data);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,7 +310,7 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
|
|||||||
hash = malloc(SHA512_DIGEST_LENGTH);
|
hash = malloc(SHA512_DIGEST_LENGTH);
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
OPENSSL_free(data);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +322,7 @@ static int extract_and_hash_cert(X509* cert, int selector, int matching_type,
|
|||||||
return 1;
|
return 1;
|
||||||
} else {
|
} else {
|
||||||
OPENSSL_free(data);
|
OPENSSL_free(data);
|
||||||
fprintf(stderr, "Unsupported matching type: %d\n", matching_type);
|
log_message(LOG_ERROR, "Unsupported matching type: %d", matching_type);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,41 +331,45 @@ 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,
|
static int compare_hashes(const unsigned char* expected, size_t expected_len,
|
||||||
const unsigned char* actual, size_t actual_len) {
|
const unsigned char* actual, size_t actual_len) {
|
||||||
if (expected_len != 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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int result = memcmp(expected, actual, expected_len) == 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++) {
|
for (size_t i = 0; i < expected_len; i++) {
|
||||||
if (i % 16 == 0) {
|
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) {
|
if ((i + 1) % 16 == 0 || i + 1 == expected_len) {
|
||||||
printf("\n");
|
log_message(LOG_DEBUG, "%s", hex_line);
|
||||||
} else if ((i + 1) % 8 == 0) {
|
} else if ((i + 1) % 8 == 0) {
|
||||||
printf(" ");
|
p += sprintf(p, " ");
|
||||||
} else {
|
} else {
|
||||||
printf(" ");
|
p += sprintf(p, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Actual hash:\n");
|
log_message(LOG_DEBUG, "Actual hash:");
|
||||||
for (size_t i = 0; i < actual_len; i++) {
|
for (size_t i = 0; i < actual_len; i++) {
|
||||||
if (i % 16 == 0) {
|
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) {
|
if ((i + 1) % 16 == 0 || i + 1 == actual_len) {
|
||||||
printf("\n");
|
log_message(LOG_DEBUG, "%s", hex_line);
|
||||||
} else if ((i + 1) % 8 == 0) {
|
} else if ((i + 1) % 8 == 0) {
|
||||||
printf(" ");
|
p += sprintf(p, " ");
|
||||||
} else {
|
} else {
|
||||||
printf(" ");
|
p += sprintf(p, " ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -358,11 +406,11 @@ static int validate_cert_domain(X509* cert, const char* hostname, int verbose) {
|
|||||||
|
|
||||||
if (domain_matches_pattern(hostname, common_name)) {
|
if (domain_matches_pattern(hostname, common_name)) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("Domain matches certificate Common Name: %s\n", common_name);
|
log_message(LOG_INFO, "Domain matches certificate Common Name: %s", common_name);
|
||||||
}
|
}
|
||||||
valid = 1;
|
valid = 1;
|
||||||
} else if (verbose) {
|
} else if (verbose) {
|
||||||
printf("Domain does not match certificate Common Name: %s\n", common_name);
|
log_message(LOG_INFO, "Domain does not match certificate Common Name: %s", common_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,7 +419,7 @@ static int validate_cert_domain(X509* cert, const char* hostname, int verbose) {
|
|||||||
if (san_names) {
|
if (san_names) {
|
||||||
int san_count = sk_GENERAL_NAME_num(san_names);
|
int san_count = sk_GENERAL_NAME_num(san_names);
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("Certificate has %d Subject Alternative Names\n", san_count);
|
log_message(LOG_INFO, "Certificate has %d Subject Alternative Names", san_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < san_count; i++) {
|
for (int i = 0; i < san_count; i++) {
|
||||||
@@ -382,19 +430,19 @@ static int validate_cert_domain(X509* cert, const char* hostname, int verbose) {
|
|||||||
|
|
||||||
if (domain_matches_pattern(hostname, dns_name)) {
|
if (domain_matches_pattern(hostname, dns_name)) {
|
||||||
if (verbose) {
|
if (verbose) {
|
||||||
printf("Domain matches SAN: %s\n", dns_name);
|
log_message(LOG_INFO, "Domain matches SAN: %s", dns_name);
|
||||||
}
|
}
|
||||||
valid = 1;
|
valid = 1;
|
||||||
break;
|
break;
|
||||||
} else if (verbose) {
|
} else if (verbose) {
|
||||||
printf("Domain does not match SAN: %s\n", dns_name);
|
log_message(LOG_INFO, "Domain does not match SAN: %s", dns_name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
|
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
|
||||||
} else if (verbose) {
|
} else if (verbose) {
|
||||||
printf("Certificate has no Subject Alternative Names\n");
|
log_message(LOG_INFO, "Certificate has no Subject Alternative Names");
|
||||||
}
|
}
|
||||||
|
|
||||||
return valid;
|
return valid;
|
||||||
@@ -408,7 +456,7 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
|
|||||||
int domain_verified = 0;
|
int domain_verified = 0;
|
||||||
|
|
||||||
if (!cert) {
|
if (!cert) {
|
||||||
fprintf(stderr, "No certificate provided for DANE verification\n");
|
log_message(LOG_ERROR, "No certificate provided for DANE verification");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +471,7 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
|
|||||||
// Now that we know the domain has TLSA records, do verbose domain validation
|
// Now that we know the domain has TLSA records, do verbose domain validation
|
||||||
domain_verified = validate_cert_domain(cert, hostname, 1);
|
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);
|
log_message(LOG_ERROR, "Certificate is not valid for domain: %s", hostname);
|
||||||
// Clean up records
|
// Clean up records
|
||||||
for (int i = 0; i < record_count; i++) {
|
for (int i = 0; i < record_count; i++) {
|
||||||
if (records[i].data) {
|
if (records[i].data) {
|
||||||
@@ -434,10 +482,11 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("Certificate domain validation successful for: %s\n", hostname);
|
log_message(LOG_INFO, "Certificate domain validation successful for: %s", hostname);
|
||||||
|
printf("DANE: Verifying certificate for %s...\n", hostname);
|
||||||
|
|
||||||
// Print records that will be used for verification
|
// Log records that will be used for verification
|
||||||
printf("\n=== Starting DANE verification for %s ===\n", hostname);
|
log_message(LOG_DEBUG, "=== Starting DANE verification for %s ===", hostname);
|
||||||
for (int i = 0; i < record_count; i++) {
|
for (int i = 0; i < record_count; i++) {
|
||||||
print_tlsa_record(&records[i], i);
|
print_tlsa_record(&records[i], i);
|
||||||
}
|
}
|
||||||
@@ -446,7 +495,7 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
|
|||||||
for (int i = 0; i < record_count; i++) {
|
for (int i = 0; i < record_count; i++) {
|
||||||
tlsa_record* record = &records[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
|
// Generate the certificate hash based on selector and matching type
|
||||||
unsigned char* cert_hash = NULL;
|
unsigned char* cert_hash = NULL;
|
||||||
@@ -454,7 +503,7 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
|
|||||||
|
|
||||||
if (!extract_and_hash_cert(cert, record->selector, record->matching_type,
|
if (!extract_and_hash_cert(cert, record->selector, record->matching_type,
|
||||||
&cert_hash, &cert_hash_len)) {
|
&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;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,44 +511,48 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
|
|||||||
switch (record->usage) {
|
switch (record->usage) {
|
||||||
case 0: // PKIX-TA - CA constraint
|
case 0: // PKIX-TA - CA constraint
|
||||||
// Not implemented in this simplified version
|
// Not implemented in this simplified version
|
||||||
printf("PKIX-TA validation not implemented\n");
|
log_message(LOG_INFO, "PKIX-TA validation not implemented");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 1: // PKIX-EE - Service certificate constraint
|
case 1: // PKIX-EE - Service certificate constraint
|
||||||
// Not implemented in this simplified version
|
// Not implemented in this simplified version
|
||||||
printf("PKIX-EE validation not implemented\n");
|
log_message(LOG_INFO, "PKIX-EE validation not implemented");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 2: // DANE-TA - Trust anchor assertion
|
case 2: // DANE-TA - Trust anchor assertion
|
||||||
// Not implemented in this simplified version
|
// Not implemented in this simplified version
|
||||||
printf("DANE-TA validation not implemented\n");
|
log_message(LOG_INFO, "DANE-TA validation not implemented");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 3: // DANE-EE (3) - Domain-issued certificate
|
case 3: // DANE-EE (3) - Domain-issued certificate
|
||||||
// Verify the certificate directly against the TLSA record
|
// Verify the certificate directly against the TLSA record
|
||||||
printf("Performing DANE-EE validation...\n");
|
log_message(LOG_INFO, "Performing DANE-EE validation...");
|
||||||
dane_verified = compare_hashes(record->data, record->data_len,
|
dane_verified = compare_hashes(record->data, record->data_len,
|
||||||
cert_hash, cert_hash_len);
|
cert_hash, cert_hash_len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unknown usage type
|
// Unknown usage type
|
||||||
printf("Unknown usage type: %d\n", record->usage);
|
log_message(LOG_WARNING, "Unknown usage type: %d", record->usage);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
free(cert_hash);
|
free(cert_hash);
|
||||||
|
|
||||||
if (dane_verified) {
|
if (dane_verified) {
|
||||||
printf("DANE verification succeeded for record #%d\n", i + 1);
|
log_message(LOG_INFO, "DANE verification succeeded for record #%d", i + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int verified = domain_verified && dane_verified;
|
int verified = domain_verified && dane_verified;
|
||||||
printf("\nDomain verification: %s\n", domain_verified ? "SUCCESS" : "FAILED");
|
log_message(LOG_INFO, "Domain verification: %s", domain_verified ? "SUCCESS" : "FAILED");
|
||||||
printf("DANE verification: %s\n", dane_verified ? "SUCCESS" : "FAILED");
|
log_message(LOG_INFO, "DANE verification: %s", dane_verified ? "SUCCESS" : "FAILED");
|
||||||
printf("Overall verification result: %s\n", 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
|
// Clean up
|
||||||
for (int i = 0; i < record_count; i++) {
|
for (int i = 0; i < record_count; i++) {
|
||||||
@@ -540,12 +593,12 @@ static int create_cert_directories() {
|
|||||||
static int generate_ca_cert() {
|
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");
|
log_message(LOG_INFO, "CA certificate already exists");
|
||||||
|
|
||||||
// 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) {
|
||||||
perror("Failed to open CA certificate file");
|
log_message(LOG_ERROR, "Failed to open CA certificate file");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,13 +606,13 @@ static int generate_ca_cert() {
|
|||||||
fclose(ca_cert_file);
|
fclose(ca_cert_file);
|
||||||
|
|
||||||
if (!ca_cert) {
|
if (!ca_cert) {
|
||||||
fprintf(stderr, "Failed to read CA certificate\n");
|
log_message(LOG_ERROR, "Failed to read CA certificate");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
FILE* ca_key_file = fopen(CA_KEY_FILE, "r");
|
FILE* ca_key_file = fopen(CA_KEY_FILE, "r");
|
||||||
if (!ca_key_file) {
|
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);
|
X509_free(ca_cert);
|
||||||
ca_cert = NULL;
|
ca_cert = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -569,7 +622,7 @@ static int generate_ca_cert() {
|
|||||||
fclose(ca_key_file);
|
fclose(ca_key_file);
|
||||||
|
|
||||||
if (!ca_key) {
|
if (!ca_key) {
|
||||||
fprintf(stderr, "Failed to read CA key\n");
|
log_message(LOG_ERROR, "Failed to read CA key");
|
||||||
X509_free(ca_cert);
|
X509_free(ca_cert);
|
||||||
ca_cert = NULL;
|
ca_cert = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -584,7 +637,7 @@ static int generate_ca_cert() {
|
|||||||
BIGNUM* bn = BN_new();
|
BIGNUM* bn = BN_new();
|
||||||
|
|
||||||
if (!bn) {
|
if (!bn) {
|
||||||
fprintf(stderr, "Failed to create BIGNUM\n");
|
log_message(LOG_ERROR, "Failed to create BIGNUM");
|
||||||
EVP_PKEY_free(ca_key);
|
EVP_PKEY_free(ca_key);
|
||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
@@ -594,7 +647,7 @@ static int generate_ca_cert() {
|
|||||||
rsa = RSA_new();
|
rsa = RSA_new();
|
||||||
|
|
||||||
if (!rsa) {
|
if (!rsa) {
|
||||||
fprintf(stderr, "Failed to create RSA\n");
|
log_message(LOG_ERROR, "Failed to create RSA");
|
||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
EVP_PKEY_free(ca_key);
|
EVP_PKEY_free(ca_key);
|
||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
@@ -602,7 +655,7 @@ static int generate_ca_cert() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (RSA_generate_key_ex(rsa, 2048, bn, NULL) != 1) {
|
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);
|
RSA_free(rsa);
|
||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
EVP_PKEY_free(ca_key);
|
EVP_PKEY_free(ca_key);
|
||||||
@@ -613,7 +666,7 @@ static int generate_ca_cert() {
|
|||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
|
|
||||||
if (!EVP_PKEY_assign_RSA(ca_key, rsa)) {
|
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);
|
RSA_free(rsa);
|
||||||
EVP_PKEY_free(ca_key);
|
EVP_PKEY_free(ca_key);
|
||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
@@ -648,7 +701,7 @@ static int generate_ca_cert() {
|
|||||||
X509_EXTENSION* ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, "critical,CA:TRUE");
|
X509_EXTENSION* ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_basic_constraints, "critical,CA:TRUE");
|
||||||
|
|
||||||
if (!ext) {
|
if (!ext) {
|
||||||
fprintf(stderr, "Failed to create CA extension\n");
|
log_message(LOG_ERROR, "Failed to create CA extension");
|
||||||
EVP_PKEY_free(ca_key);
|
EVP_PKEY_free(ca_key);
|
||||||
X509_free(ca_cert);
|
X509_free(ca_cert);
|
||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
@@ -661,7 +714,7 @@ static int generate_ca_cert() {
|
|||||||
|
|
||||||
// Sign the certificate
|
// Sign the certificate
|
||||||
if (!X509_sign(ca_cert, ca_key, EVP_sha256())) {
|
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);
|
EVP_PKEY_free(ca_key);
|
||||||
X509_free(ca_cert);
|
X509_free(ca_cert);
|
||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
@@ -672,7 +725,7 @@ static int generate_ca_cert() {
|
|||||||
// Save the CA certificate and key
|
// Save the CA certificate and key
|
||||||
FILE* ca_cert_file = fopen(CA_CERT_FILE, "w");
|
FILE* ca_cert_file = fopen(CA_CERT_FILE, "w");
|
||||||
if (!ca_cert_file) {
|
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);
|
EVP_PKEY_free(ca_key);
|
||||||
X509_free(ca_cert);
|
X509_free(ca_cert);
|
||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
@@ -685,7 +738,7 @@ static int generate_ca_cert() {
|
|||||||
|
|
||||||
FILE* ca_key_file = fopen(CA_KEY_FILE, "w");
|
FILE* ca_key_file = fopen(CA_KEY_FILE, "w");
|
||||||
if (!ca_key_file) {
|
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);
|
EVP_PKEY_free(ca_key);
|
||||||
X509_free(ca_cert);
|
X509_free(ca_cert);
|
||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
@@ -696,7 +749,7 @@ static int generate_ca_cert() {
|
|||||||
PEM_write_PrivateKey(ca_key_file, ca_key, NULL, NULL, 0, NULL, NULL);
|
PEM_write_PrivateKey(ca_key_file, ca_key, NULL, NULL, 0, NULL, NULL);
|
||||||
fclose(ca_key_file);
|
fclose(ca_key_file);
|
||||||
|
|
||||||
printf("Generated new CA certificate\n");
|
log_message(LOG_INFO, "Generated new CA certificate");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,13 +762,13 @@ int setup_local_ca() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("CA setup complete\n");
|
log_message(LOG_INFO, "CA setup complete");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int generate_trusted_cert(const char* hostname, const char* cert_path, const char* key_path) {
|
int generate_trusted_cert(const char* hostname, const char* cert_path, const char* key_path) {
|
||||||
if (!ca_cert || !ca_key) {
|
if (!ca_cert || !ca_key) {
|
||||||
fprintf(stderr, "CA not initialized\n");
|
log_message(LOG_ERROR, "CA not initialized");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -725,7 +778,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
BIGNUM* bn = BN_new();
|
BIGNUM* bn = BN_new();
|
||||||
|
|
||||||
if (!bn) {
|
if (!bn) {
|
||||||
fprintf(stderr, "Failed to create BIGNUM\n");
|
log_message(LOG_ERROR, "Failed to create BIGNUM");
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -734,14 +787,14 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
rsa = RSA_new();
|
rsa = RSA_new();
|
||||||
|
|
||||||
if (!rsa) {
|
if (!rsa) {
|
||||||
fprintf(stderr, "Failed to create RSA\n");
|
log_message(LOG_ERROR, "Failed to create RSA");
|
||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (RSA_generate_key_ex(rsa, 2048, bn, NULL) != 1) {
|
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);
|
RSA_free(rsa);
|
||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
@@ -751,7 +804,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
BN_free(bn);
|
BN_free(bn);
|
||||||
|
|
||||||
if (!EVP_PKEY_assign_RSA(pkey, rsa)) {
|
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);
|
RSA_free(rsa);
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -790,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);
|
X509_EXTENSION* ext = X509V3_EXT_conf_nid(NULL, &ctx, NID_subject_alt_name, san);
|
||||||
|
|
||||||
if (!ext) {
|
if (!ext) {
|
||||||
fprintf(stderr, "Failed to create SAN extension\n");
|
log_message(LOG_ERROR, "Failed to create SAN extension");
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -801,7 +854,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
|
|
||||||
// Sign the certificate with our CA key
|
// Sign the certificate with our CA key
|
||||||
if (!X509_sign(cert, ca_key, EVP_sha256())) {
|
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);
|
EVP_PKEY_free(pkey);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -810,7 +863,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
// Save the certificate
|
// Save the certificate
|
||||||
FILE* cert_file = fopen(cert_path, "w");
|
FILE* cert_file = fopen(cert_path, "w");
|
||||||
if (!cert_file) {
|
if (!cert_file) {
|
||||||
perror("Failed to create certificate file");
|
log_message(LOG_ERROR, "Failed to create certificate file");
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -822,7 +875,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
// Save the private key
|
// Save the private key
|
||||||
FILE* key_file = fopen(key_path, "w");
|
FILE* key_file = fopen(key_path, "w");
|
||||||
if (!key_file) {
|
if (!key_file) {
|
||||||
perror("Failed to create key file");
|
log_message(LOG_ERROR, "Failed to create key file");
|
||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -835,7 +888,7 @@ int generate_trusted_cert(const char* hostname, const char* cert_path, const cha
|
|||||||
EVP_PKEY_free(pkey);
|
EVP_PKEY_free(pkey);
|
||||||
X509_free(cert);
|
X509_free(cert);
|
||||||
|
|
||||||
printf("Generated trusted certificate for %s\n", hostname);
|
log_message(LOG_INFO, "Generated trusted certificate for %s", hostname);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,7 +901,7 @@ static void delete_all_generated_certs() {
|
|||||||
// Open the certificates directory
|
// Open the certificates directory
|
||||||
dir = opendir(CERT_DIR);
|
dir = opendir(CERT_DIR);
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
perror("Failed to open certificates directory for cleanup");
|
log_message(LOG_ERROR, "Failed to open certificates directory for cleanup");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -863,18 +916,20 @@ static void delete_all_generated_certs() {
|
|||||||
|
|
||||||
// Delete the file and log the action
|
// Delete the file and log the action
|
||||||
if (unlink(path) == 0) {
|
if (unlink(path) == 0) {
|
||||||
printf("Deleted temporary certificate: %s\n", path);
|
log_message(LOG_INFO, "Deleted temporary certificate: %s", path);
|
||||||
} else {
|
} else {
|
||||||
perror("Failed to delete certificate");
|
log_message(LOG_ERROR, "Failed to delete certificate: %s", path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
printf("Cleaned up all generated certificates\n");
|
log_message(LOG_INFO, "Cleaned up all generated certificates");
|
||||||
}
|
}
|
||||||
|
|
||||||
int dane_init() {
|
int dane_init() {
|
||||||
init_openssl();
|
init_openssl();
|
||||||
|
init_logging();
|
||||||
|
log_message(LOG_INFO, "DANE subsystem initialized");
|
||||||
return setup_local_ca();
|
return setup_local_ca();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -893,5 +948,7 @@ void dane_cleanup() {
|
|||||||
ca_key = NULL;
|
ca_key = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log_message(LOG_INFO, "DANE subsystem shutdown");
|
||||||
|
close_logging();
|
||||||
EVP_cleanup();
|
EVP_cleanup();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,4 +61,9 @@ int dane_init();
|
|||||||
*/
|
*/
|
||||||
void dane_cleanup();
|
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
|
#endif // DANE_H
|
||||||
|
|||||||
Reference in New Issue
Block a user