feat: Fix a few other issues with certs

This commit is contained in:
2025-04-23 18:06:06 +10:00
parent eb4b9c9f7e
commit 4bde414964

View File

@@ -328,17 +328,93 @@ static int compare_hashes(const unsigned char* expected, size_t expected_len,
return result; 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 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)) {
printf("Domain matches certificate Common Name: %s\n", common_name);
valid = 1;
} else {
printf("Domain does not match certificate Common Name: %s\n", 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);
printf("Certificate has %d Subject Alternative Names\n", san_count);
for (int i = 0; i < san_count; i++) {
const GENERAL_NAME* current_name = sk_GENERAL_NAME_value(san_names, i);
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)) {
printf("Domain matches SAN: %s\n", dns_name);
valid = 1;
break;
} else {
printf("Domain does not match SAN: %s\n", dns_name);
}
}
}
sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free);
} else {
printf("Certificate has no Subject Alternative Names\n");
}
return valid;
}
// Verify a certificate against DANE TLSA records // Verify a certificate against DANE TLSA records
int verify_cert_against_dane(const char* hostname, X509* cert) { int verify_cert_against_dane(const char* hostname, X509* cert) {
tlsa_record* records = NULL; tlsa_record* records = NULL;
int record_count = 0; int record_count = 0;
int verified = 0; int dane_verified = 0;
int domain_verified = 0;
if (!cert) { if (!cert) {
fprintf(stderr, "No certificate provided for DANE verification\n"); fprintf(stderr, "No certificate provided for DANE verification\n");
return -1; return -1;
} }
// Verify the certificate domain
domain_verified = validate_cert_domain(cert, hostname);
if (!domain_verified) {
fprintf(stderr, "Certificate is not valid for domain: %s\n", hostname);
return 0;
}
printf("Certificate domain validation successful for: %s\n", hostname);
if (!get_tlsa_records(hostname, &records, &record_count)) { if (!get_tlsa_records(hostname, &records, &record_count)) {
return -1; return -1;
} }
@@ -389,7 +465,7 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
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"); printf("Performing DANE-EE validation...\n");
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;
@@ -401,13 +477,16 @@ int verify_cert_against_dane(const char* hostname, X509* cert) {
free(cert_hash); free(cert_hash);
if (verified) { if (dane_verified) {
printf("DANE verification succeeded for record #%d\n", i + 1); printf("DANE verification succeeded for record #%d\n", i + 1);
break; break;
} }
} }
printf("\nDANE verification result: %s\n", verified ? "SUCCESS" : "FAILED"); int verified = domain_verified && dane_verified;
printf("\nDomain verification: %s\n", domain_verified ? "SUCCESS" : "FAILED");
printf("DANE verification: %s\n", dane_verified ? "SUCCESS" : "FAILED");
printf("Overall verification result: %s\n", verified ? "SUCCESS" : "FAILED");
// Clean up // Clean up
for (int i = 0; i < record_count; i++) { for (int i = 0; i < record_count; i++) {