feat: Fix a few other issues with certs
This commit is contained in:
87
src/dane.c
87
src/dane.c
@@ -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++) {
|
||||||
|
|||||||
Reference in New Issue
Block a user