diff --git a/src/error.rs b/src/error.rs
index 4ec8393e..f47e893b 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -33,6 +33,9 @@ pub enum Error {
     /// The certificate is not valid for the name it is being validated for.
     CertNotValidForName,
 
+    /// The certificate is not valid for the ip it is being validated for.
+    CertNotValidForIp,
+
     /// The certificate is not valid yet; i.e. the time it is being validated
     /// for is earlier than the certificate's notBefore time.
     CertNotValidYet,
diff --git a/src/name.rs b/src/name.rs
index 24cb69f0..203ca888 100644
--- a/src/name.rs
+++ b/src/name.rs
@@ -126,6 +126,43 @@ impl<'a> From<DNSNameRef<'a>> for &'a str {
     }
 }
 
+/// An ip address
+#[derive(Clone, Copy)]
+pub enum IPAddress {
+    /// An ipv4 address
+    V4(Ipv4),
+}
+
+impl From<Ipv4> for IPAddress {
+    fn from(ipv4: Ipv4) -> IPAddress {
+        IPAddress::V4(ipv4)
+    }
+}
+
+/// An Ipv4 address
+#[derive(Clone, Copy)]
+pub struct Ipv4 {
+    bytes: [u8;4],
+}
+
+impl Ipv4 {
+    /// Create a new Ipv4 address from a byte array
+    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Ipv4 {
+        Ipv4 { bytes: [a, b, c, d] }
+    }
+
+    fn matches(&self, ip: untrusted::Input) -> bool {
+        let mut reader = untrusted::Reader::new(ip);
+        for i in 0..4 {
+            if reader.read_byte() != Ok(self.bytes[i]) {
+                return false
+            }
+        }
+        // TODO: Check at end
+        return true;
+    }
+}
+
 pub fn verify_cert_dns_name(
     cert: &super::EndEntityCert, DNSNameRef(dns_name): DNSNameRef,
 ) -> Result<(), Error> {
@@ -154,6 +191,33 @@ pub fn verify_cert_dns_name(
     )
 }
 
+pub fn verify_cert_ip_san(
+    cert: &super::EndEntityCert, ip: IPAddress,
+) -> Result<(), Error> {
+    let cert = &cert.inner;
+    iterate_names(
+        cert.subject,
+        cert.subject_alt_name,
+        Err(Error::CertNotValidForIp),
+        &|name| {
+            match name {
+                GeneralName::IPAddress(ip_addr) => {
+                    match &ip {
+                        IPAddress::V4(ipv4) => {
+                            if ipv4.matches(ip_addr) {
+                                return NameIteration::Stop(Ok(()))
+                            }
+                        }
+                    }
+                }
+                _ => (),
+            }
+            NameIteration::KeepGoing
+        },
+    )
+}
+
+
 // https://tools.ietf.org/html/rfc5280#section-4.2.1.10
 pub fn check_name_constraints(
     input: Option<&mut untrusted::Reader>, subordinate_certs: &Cert,
diff --git a/src/webpki.rs b/src/webpki.rs
index adcded53..52b17592 100644
--- a/src/webpki.rs
+++ b/src/webpki.rs
@@ -60,7 +60,7 @@ pub mod trust_anchor_util;
 mod verify_cert;
 
 pub use error::Error;
-pub use name::{DNSNameRef, InvalidDNSNameError};
+pub use name::{DNSNameRef, InvalidDNSNameError, IPAddress, Ipv4};
 
 #[cfg(feature = "std")]
 pub use name::DNSName;
@@ -186,6 +186,11 @@ impl<'a> EndEntityCert<'a> {
         name::verify_cert_dns_name(&self, dns_name)
     }
 
+    /// Verifies that the certificate is valid for the given ip address
+    pub fn verify_is_valid_for_ip(&self, ip: IPAddress) -> Result<(), Error> {
+        name::verify_cert_ip_san(&self, ip)
+    }
+
     /// Verifies that the certificate is valid for at least one of the given DNS
     /// host names.
     ///