Verify that a certificate is valid for the given hostname/IP address. This function checks Subject Alternative Names (SAN) and Common Name (CN).
(
cert_der: &CertificateDer<'_>,
server_name: &ServerName<'_>,
)
| 1641 | /// Verify that a certificate is valid for the given hostname/IP address. |
| 1642 | /// This function checks Subject Alternative Names (SAN) and Common Name (CN). |
| 1643 | fn verify_hostname( |
| 1644 | cert_der: &CertificateDer<'_>, |
| 1645 | server_name: &ServerName<'_>, |
| 1646 | ) -> Result<(), rustls::Error> { |
| 1647 | use x509_parser::extensions::GeneralName; |
| 1648 | use x509_parser::prelude::*; |
| 1649 | |
| 1650 | // Parse the certificate |
| 1651 | let (_, cert) = X509Certificate::from_der(cert_der.as_ref()).map_err(|e| { |
| 1652 | cert_error::to_rustls_invalid_cert(format!( |
| 1653 | "Failed to parse certificate for hostname verification: {e}" |
| 1654 | )) |
| 1655 | })?; |
| 1656 | |
| 1657 | match server_name { |
| 1658 | ServerName::DnsName(dns) => { |
| 1659 | let expected_name = dns.as_ref(); |
| 1660 | |
| 1661 | // 1. Check Subject Alternative Names (SAN) - preferred method |
| 1662 | if let Ok(Some(san_ext)) = cert.subject_alternative_name() { |
| 1663 | for name in &san_ext.value.general_names { |
| 1664 | if let GeneralName::DNSName(dns_name) = name |
| 1665 | && hostname_matches(expected_name, dns_name) |
| 1666 | { |
| 1667 | return Ok(()); |
| 1668 | } |
| 1669 | } |
| 1670 | } |
| 1671 | |
| 1672 | // 2. Fallback to Common Name (CN) - deprecated but still checked for compatibility |
| 1673 | for rdn in cert.subject().iter() { |
| 1674 | for attr in rdn.iter() { |
| 1675 | if attr.attr_type() == &x509_parser::oid_registry::OID_X509_COMMON_NAME |
| 1676 | && let Ok(cn) = attr.attr_value().as_str() |
| 1677 | && hostname_matches(expected_name, cn) |
| 1678 | { |
| 1679 | return Ok(()); |
| 1680 | } |
| 1681 | } |
| 1682 | } |
| 1683 | |
| 1684 | // No match found - return error |
| 1685 | Err(cert_error::to_rustls_invalid_cert(format!( |
| 1686 | "Hostname mismatch: certificate is not valid for '{expected_name}'", |
| 1687 | ))) |
| 1688 | } |
| 1689 | ServerName::IpAddress(ip) => verify_ip_address(&cert, ip), |
| 1690 | _ => { |
| 1691 | // Unknown server name type |
| 1692 | Err(cert_error::to_rustls_cert_error( |
| 1693 | std::io::ErrorKind::InvalidInput, |
| 1694 | "Unsupported server name type for hostname verification", |
| 1695 | )) |
| 1696 | } |
| 1697 | } |
| 1698 | } |
| 1699 | |
| 1700 | /// Match a hostname against a pattern, supporting wildcard certificates (*.example.com). |
no test coverage detected