ctclient_async/internal/
digitally_signed_struct.rs

1use log::trace;
2use openssl::pkey::PKey;
3
4use crate::Error;
5use crate::utils;
6
7// https://docs.rs/rustls/0.15.2/src/rustls/msgs/enums.rs.html#720
8// We only need to handle these two cases because RFC says so.
9pub(crate) const SIGSCHEME_ECDSA_NISTP256_SHA256: u16 = 0x0403;
10pub(crate) const SIGSCHEME_RSA_PKCS1_SHA256: u16 = 0x0401;
11
12/// Verifies a TLS digitally-signed struct (see [the TLS
13/// RFC](https://tools.ietf.org/html/rfc5246#section-4.7) for more info.)
14///
15/// This function is only useful to those who want to do some custom CT API
16/// calling. [`CTClient`](crate::CTClient) will automatically verify all
17/// signature.
18///
19/// # Params
20///
21/// * `dss`: the `DigitallySigned` struct. Often returned as a
22/// base64 "signature" json field by the CT server. De-base64 yourself before
23/// calling.
24///
25/// * `pub_key`: use
26/// [openssl::pkey::PKey::public_key_from_der](openssl::pkey::PKey::public_key_from_der)
27/// to turn the key provided by google's ct log list into openssl key object.
28///
29/// * `data`: the stuff to verify against. Server should have signed this.
30pub fn verify_dss(
31    dss: &[u8],
32    pub_key: &PKey<openssl::pkey::Public>,
33    data: &[u8],
34) -> Result<(), Error> {
35    // rustls crate contain code that parses this structure:
36    // 	https://docs.rs/rustls/0.15.2/src/rustls/msgs/handshake.rs.html#1546
37    // It shows that the struct begins with two bytes denoting the signature scheme, and
38    // then follows a 2-byte length of the rest of the struct.
39
40    if dss.len() > (1usize << 16usize) + 3 {
41        return Err(Error::InvalidSignature(format!(
42            "dss too long. (len = {})",
43            dss.len()
44        )));
45    }
46
47    if dss.len() < 4 {
48        return Err(Error::InvalidSignature(format!(
49            "Invalid dss: {}\n  Too short. Expected at least 4 bytes.",
50            &utils::u8_to_hex(dss)
51        )));
52    }
53    let sig_type = u16::from_be_bytes([dss[0], dss[1]]);
54    let length = u16::from_be_bytes([dss[2], dss[3]]);
55    let rest = &dss[4..];
56    if rest.len() != length as usize {
57        return Err(Error::InvalidSignature(format!(
58            "Invalid dss: {}\n  It says there that there are {} bytes in the signature part, but I see {}.",
59            &utils::u8_to_hex(dss),
60            length,
61            rest.len()
62        )));
63    }
64
65    let signature_algorithm = match sig_type {
66        SIGSCHEME_ECDSA_NISTP256_SHA256 => SignatureAlgorithm::Sha256Ecdsa,
67        SIGSCHEME_RSA_PKCS1_SHA256 => SignatureAlgorithm::Sha256Rsa,
68        _ => {
69            return Err(Error::InvalidSignature(format!(
70                "Unknow signature scheme {:2x}",
71                sig_type
72            )));
73        }
74    };
75
76    verify_dss_raw(signature_algorithm, pub_key, rest, data)
77}
78
79use crate::internal::openssl_ffi::SignatureAlgorithm;
80
81/// Verifies a raw, ASN.1 encoded signature.
82pub fn verify_dss_raw(
83    signature_algorithm: SignatureAlgorithm,
84    pub_key: &PKey<openssl::pkey::Public>,
85    raw_signature: &[u8],
86    data: &[u8],
87) -> Result<(), Error> {
88    use SignatureAlgorithm::*;
89    match signature_algorithm {
90        Sha256Ecdsa => {
91            if pub_key.id() != openssl::pkey::Id::EC {
92                return Err(Error::InvalidSignature(format!(
93                    "dss says signature is EC, but key is {:?}",
94                    pub_key.id()
95                )));
96            }
97        }
98        Sha256Rsa => {
99            if pub_key.id() != openssl::pkey::Id::RSA {
100                return Err(Error::InvalidSignature(format!(
101                    "dss says signature is RSA, but key is {:?}",
102                    pub_key.id()
103                )));
104            }
105        }
106    }
107
108    let mut verifier =
109        openssl::sign::Verifier::new(openssl::hash::MessageDigest::sha256(), pub_key)
110            .map_err(|e| Error::Unknown(format!("EVP_DigestVerifyInit: {}", &e)))?;
111    if signature_algorithm == Sha256Rsa {
112        verifier
113            .set_rsa_padding(openssl::rsa::Padding::PKCS1)
114            .map_err(|e| Error::Unknown(format!("EVP_PKEY_CTX_set_rsa_padding: {}", &e)))?;
115    }
116    verifier
117        .update(data)
118        .map_err(|e| Error::Unknown(format!("EVP_DigestUpdate: {}", &e)))?;
119    if !verifier
120        .verify(raw_signature)
121        .map_err(|e| Error::InvalidSignature(format!("EVP_DigestVerifyFinal: {}", &e)))?
122    {
123        return Err(Error::InvalidSignature(format!(
124            "Signature is invalid: signature = {}, data = {}.",
125            &utils::u8_to_hex(raw_signature),
126            &utils::u8_to_hex(data)
127        )));
128    }
129
130    debug_assert!({
131        trace!("Signature checked for data {}", &utils::u8_to_hex(data));
132        true
133    });
134
135    Ok(())
136}
137
138#[test]
139fn verify_dss_test() {
140    let key = PKey::public_key_from_der(&utils::hex_to_u8("3056301006072a8648ce3d020106052b8104000a0342000412c022d1b5cab048f419d46f111743cea4fcd54a05228d14cecd9cc1d120e4cc3e22e8481e5ccc3db16273a8d981ac144306d644a4227468fccd6580563ec8bd")[..]).unwrap();
141    verify_dss(&utils::hex_to_u8("040300473045022100ba6da0fb4d4440965dd1d096212da95880320113320ddc5202a0b280ac518349022005bb17637d4ed06facb4af5b4b9b9083210474998ac33809a6e10c9352032055"), &key, b"hello").unwrap();
142    verify_dss(&utils::hex_to_u8("0403004830460221009857dc5e2bcc0b67059a5bde9ead6a36614ab315423c0b2e4762ba7aca3f0181022100eab3af33367cb89d556c17c1ce7de1c2b8c2b80d709d0c3cbb45c8acc6809d1d"), &key, b"not hello").unwrap();
143    verify_dss(&utils::hex_to_u8("0403004830460221009857dc5e2bcc0b67059a5bde9ead6a36614ab315423c0b2e4762ba7aca3f0181022100eab3af33367cb89d556c17c1ce7de1c2b8c2b80d709d0c3cbb45c8acc6809d1d"), &key, b"hello").expect_err("");
144
145    // Don't panic.
146    verify_dss(&utils::hex_to_u8(""), &key, b"hello").expect_err("");
147    verify_dss(&utils::hex_to_u8("00"), &key, b"hello").expect_err("");
148    verify_dss(&utils::hex_to_u8("0001"), &key, b"hello").expect_err("");
149    verify_dss(&utils::hex_to_u8("000102"), &key, b"hello").expect_err("");
150    verify_dss(&utils::hex_to_u8("00010203"), &key, b"hello").expect_err("");
151    verify_dss(&utils::hex_to_u8("0001020304"), &key, b"hello").expect_err("");
152    verify_dss(&utils::hex_to_u8("000102030405"), &key, b"hello").expect_err("");
153}