Verify that a certificate is valid for the given IP address. Checks Subject Alternative Names for IP Address entries.
(
cert: &X509Certificate<'_>,
expected_ip: &rustls::pki_types::IpAddr,
)
| 1725 | /// Verify that a certificate is valid for the given IP address. |
| 1726 | /// Checks Subject Alternative Names for IP Address entries. |
| 1727 | fn verify_ip_address( |
| 1728 | cert: &X509Certificate<'_>, |
| 1729 | expected_ip: &rustls::pki_types::IpAddr, |
| 1730 | ) -> Result<(), rustls::Error> { |
| 1731 | use core::net::IpAddr; |
| 1732 | use x509_parser::extensions::GeneralName; |
| 1733 | |
| 1734 | // Convert rustls IpAddr to std::net::IpAddr for comparison |
| 1735 | let expected_std_ip: IpAddr = match expected_ip { |
| 1736 | rustls::pki_types::IpAddr::V4(octets) => IpAddr::V4(core::net::Ipv4Addr::from(*octets)), |
| 1737 | rustls::pki_types::IpAddr::V6(octets) => IpAddr::V6(core::net::Ipv6Addr::from(*octets)), |
| 1738 | }; |
| 1739 | |
| 1740 | // Check Subject Alternative Names for IP addresses |
| 1741 | if let Ok(Some(san_ext)) = cert.subject_alternative_name() { |
| 1742 | for name in &san_ext.value.general_names { |
| 1743 | if let GeneralName::IPAddress(cert_ip_bytes) = name { |
| 1744 | // Parse the IP address from the certificate |
| 1745 | let cert_ip = match cert_ip_bytes.len() { |
| 1746 | 4 => { |
| 1747 | // IPv4 |
| 1748 | if let Ok(octets) = <[u8; 4]>::try_from(*cert_ip_bytes) { |
| 1749 | IpAddr::V4(core::net::Ipv4Addr::from(octets)) |
| 1750 | } else { |
| 1751 | continue; |
| 1752 | } |
| 1753 | } |
| 1754 | 16 => { |
| 1755 | // IPv6 |
| 1756 | if let Ok(octets) = <[u8; 16]>::try_from(*cert_ip_bytes) { |
| 1757 | IpAddr::V6(core::net::Ipv6Addr::from(octets)) |
| 1758 | } else { |
| 1759 | continue; |
| 1760 | } |
| 1761 | } |
| 1762 | _ => continue, // Invalid IP address length |
| 1763 | }; |
| 1764 | |
| 1765 | if cert_ip == expected_std_ip { |
| 1766 | return Ok(()); |
| 1767 | } |
| 1768 | } |
| 1769 | } |
| 1770 | } |
| 1771 | |
| 1772 | // No matching IP address found |
| 1773 | Err(cert_error::to_rustls_invalid_cert(format!( |
| 1774 | "IP address mismatch: certificate is not valid for '{expected_std_ip}'", |
| 1775 | ))) |
| 1776 | } |
no test coverage detected