ctclient_async/
certutils.rs

1//! Verious utilities for checking the content of a certificate.
2
3use crate::Error;
4use openssl::x509::X509Ref;
5
6/// Return the common name of the certificate. Usually will only contains one. May be empty.
7pub fn get_common_names<R: AsRef<X509Ref>>(cert: &R) -> Result<Vec<String>, Error> {
8    let cert = cert.as_ref();
9    let try_common_names: Vec<_> = cert
10        .subject_name()
11        .entries_by_nid(openssl::nid::Nid::COMMONNAME)
12        .map(|x| x.data().as_utf8())
13        .collect();
14    let mut common_names: Vec<String> = Vec::with_capacity(try_common_names.len());
15    for cn in try_common_names {
16        if let Err(e) = cn {
17            return Err(Error::BadCertificate(format!(
18                "While parsing common name: {}",
19                &e
20            )));
21        }
22        common_names.push(String::from(AsRef::<str>::as_ref(&cn.unwrap())));
23    }
24    Ok(common_names)
25}
26
27/// Return the DNS names in the subjectAlternativeNames of the certificate as well as its common name.
28///
29/// Result may contain duplicate items.
30pub fn get_dns_names<R: AsRef<X509Ref>>(cert: &R) -> Result<Vec<String>, Error> {
31    let cert = cert.as_ref();
32    let mut names = get_common_names(cert)?;
33    // fixme: common names may not be host names.
34    if let Some(san) = cert.subject_alt_names() {
35        for name in san.iter() {
36            if let Some(name) = name.dnsname() {
37                names.push(String::from(name));
38            } else if let Some(uri) = name.uri() {
39                let url_parsed = reqwest::Url::parse(uri).map_err(|_| {
40                    Error::BadCertificate(
41                        "This certificate has a URI SNI, but the URI is not parsable.".to_owned(),
42                    )
43                })?;
44                if let Some(host) = url_parsed.domain() {
45                    names.push(String::from(host));
46                }
47            }
48        }
49    }
50    Ok(names)
51}