mirror of
https://github.com/yhirose/cpp-httplib.git
synced 2026-10-13 10:24:47 +00:00
use the SAN type tag in Mbed TLS verify_hostname and get_cert_sans (#2614)
* use the SAN type tag in Mbed TLS verify_hostname and get_cert_sans Mbed TLS keeps a subjectAltName entry's GeneralName tag in buf.tag and the bare value in buf.p / buf.len. verify_hostname ignored the tag, so a dNSName whose bytes equal an address authenticated that IP host, and an iPAddress or rfc822Name was matched as a DNS pattern. get_cert_sans looked for the tag inside the value, so it reported no entries for an ordinary certificate, or part of a dNSName as an entry of its own. * Shorten the SAN type comments --------- Co-authored-by: yhirose <yuji.hirose.bug@gmail.com>
This commit is contained in:
1 parent
6d1049462d
commit
edc9760005
5 files changed
+184
-70
No files matched your search
@@ -21056,29 +21056,24 @@ inline bool verify_hostname(cert_t cert, const char *hostname) {
|
||||
auto ip_len = impl::parse_ip_address(host_str, ip_bytes);
|
||||
auto is_ip = ip_len > 0;
|
||||
|
||||
// Check Subject Alternative Names (SAN)
|
||||
// In Mbed TLS 3.x, subject_alt_names contains raw values without ASN.1 tags
|
||||
// - DNS names: raw string bytes
|
||||
// - IP addresses: raw IP bytes (4 for IPv4, 16 for IPv6)
|
||||
// Check Subject Alternative Names (SAN). Mbed TLS keeps the GeneralName type
|
||||
// in buf.tag and the raw value in buf.p / buf.len.
|
||||
const mbedtls_x509_sequence *san = &mcert->subject_alt_names;
|
||||
while (san != nullptr && san->buf.p != nullptr && san->buf.len > 0) {
|
||||
const unsigned char *p = san->buf.p;
|
||||
size_t len = san->buf.len;
|
||||
auto san_type = san->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK;
|
||||
|
||||
if (is_ip) {
|
||||
// For an IP host, only a matching iPAddress SAN of the same family
|
||||
// (4 bytes for IPv4, 16 bytes for IPv6) may authenticate it.
|
||||
if (len == ip_len && memcmp(p, ip_bytes, ip_len) == 0) { return true; }
|
||||
} else {
|
||||
// Check if this SAN is a DNS name (printable ASCII string)
|
||||
bool is_dns = len > 0;
|
||||
for (size_t i = 0; i < len && is_dns; i++) {
|
||||
if (p[i] < 32 || p[i] > 126) { is_dns = false; }
|
||||
}
|
||||
if (is_dns) {
|
||||
std::string san_name(reinterpret_cast<const char *>(p), len);
|
||||
if (detail::match_hostname(san_name, host_str)) { return true; }
|
||||
if (san_type == MBEDTLS_X509_SAN_IP_ADDRESS && len == ip_len &&
|
||||
memcmp(p, ip_bytes, ip_len) == 0) {
|
||||
return true;
|
||||
}
|
||||
} else if (san_type == MBEDTLS_X509_SAN_DNS_NAME) {
|
||||
std::string san_name(reinterpret_cast<const char *>(p), len);
|
||||
if (detail::match_hostname(san_name, host_str)) { return true; }
|
||||
}
|
||||
san = san->next;
|
||||
}
|
||||
@@ -21157,65 +21152,45 @@ inline bool get_cert_sans(cert_t cert, std::vector<SanEntry> &sans) {
|
||||
const mbedtls_x509_sequence *cur = &x509->subject_alt_names;
|
||||
while (cur != nullptr) {
|
||||
if (cur->buf.len > 0) {
|
||||
// Mbed TLS stores SAN as ASN.1 sequences
|
||||
// The tag byte indicates the type
|
||||
const unsigned char *p = cur->buf.p;
|
||||
size_t len = cur->buf.len;
|
||||
size_t value_len = cur->buf.len;
|
||||
|
||||
// First byte is the tag
|
||||
unsigned char tag = *p;
|
||||
p++;
|
||||
len--;
|
||||
|
||||
// Parse length (simple single-byte length assumed)
|
||||
if (len > 0 && *p < 0x80) {
|
||||
size_t value_len = *p;
|
||||
p++;
|
||||
len--;
|
||||
|
||||
if (value_len <= len) {
|
||||
SanEntry entry;
|
||||
// ASN.1 context tags for GeneralName
|
||||
switch (tag & 0x1F) {
|
||||
case 2: // dNSName
|
||||
entry.type = SanType::DNS;
|
||||
entry.value =
|
||||
std::string(reinterpret_cast<const char *>(p), value_len);
|
||||
break;
|
||||
case 7: // iPAddress
|
||||
entry.type = SanType::IP;
|
||||
if (value_len == 4) {
|
||||
// IPv4
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
|
||||
entry.value = buf;
|
||||
} else if (value_len == 16) {
|
||||
// IPv6
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
|
||||
"%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8],
|
||||
p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
|
||||
entry.value = buf;
|
||||
}
|
||||
break;
|
||||
case 1: // rfc822Name (email)
|
||||
entry.type = SanType::EMAIL;
|
||||
entry.value =
|
||||
std::string(reinterpret_cast<const char *>(p), value_len);
|
||||
break;
|
||||
case 6: // uniformResourceIdentifier
|
||||
entry.type = SanType::URI;
|
||||
entry.value =
|
||||
std::string(reinterpret_cast<const char *>(p), value_len);
|
||||
break;
|
||||
default: entry.type = SanType::OTHER; break;
|
||||
}
|
||||
|
||||
if (!entry.value.empty()) { sans.push_back(std::move(entry)); }
|
||||
SanEntry entry;
|
||||
switch (cur->buf.tag & MBEDTLS_ASN1_TAG_VALUE_MASK) {
|
||||
case MBEDTLS_X509_SAN_DNS_NAME:
|
||||
entry.type = SanType::DNS;
|
||||
entry.value = std::string(reinterpret_cast<const char *>(p), value_len);
|
||||
break;
|
||||
case MBEDTLS_X509_SAN_IP_ADDRESS:
|
||||
entry.type = SanType::IP;
|
||||
if (value_len == 4) {
|
||||
// IPv4
|
||||
char buf[16];
|
||||
snprintf(buf, sizeof(buf), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
|
||||
entry.value = buf;
|
||||
} else if (value_len == 16) {
|
||||
// IPv6
|
||||
char buf[64];
|
||||
snprintf(buf, sizeof(buf),
|
||||
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
|
||||
"%02x%02x:%02x%02x:%02x%02x:%02x%02x",
|
||||
p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9],
|
||||
p[10], p[11], p[12], p[13], p[14], p[15]);
|
||||
entry.value = buf;
|
||||
}
|
||||
break;
|
||||
case MBEDTLS_X509_SAN_RFC822_NAME:
|
||||
entry.type = SanType::EMAIL;
|
||||
entry.value = std::string(reinterpret_cast<const char *>(p), value_len);
|
||||
break;
|
||||
case MBEDTLS_X509_SAN_UNIFORM_RESOURCE_IDENTIFIER:
|
||||
entry.type = SanType::URI;
|
||||
entry.value = std::string(reinterpret_cast<const char *>(p), value_len);
|
||||
break;
|
||||
default: entry.type = SanType::OTHER; break;
|
||||
}
|
||||
|
||||
if (!entry.value.empty()) { sans.push_back(std::move(entry)); }
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user