Skip to main content

rustls_openssl/
signer.rs

1use openssl::hash::MessageDigest;
2use openssl::pkey::{Id, Private};
3use openssl::rsa::Padding;
4use openssl::sign::RsaPssSaltlen;
5use rustls::pki_types::PrivateKeyDer;
6use rustls::sign::SigningKey;
7use rustls::{Error, SignatureAlgorithm, SignatureScheme};
8use std::sync::Arc;
9
10/// A struct that implements [rustls::crypto::KeyProvider].
11#[derive(Debug)]
12pub struct KeyProvider;
13
14/// RSA schemes in descending order of preference
15pub(crate) static RSA_SCHEMES: &[SignatureScheme] = &[
16    SignatureScheme::RSA_PSS_SHA512,
17    SignatureScheme::RSA_PSS_SHA384,
18    SignatureScheme::RSA_PSS_SHA256,
19    SignatureScheme::RSA_PKCS1_SHA512,
20    SignatureScheme::RSA_PKCS1_SHA384,
21    SignatureScheme::RSA_PKCS1_SHA256,
22];
23
24#[derive(Debug)]
25struct Signer {
26    key: Arc<openssl::pkey::PKey<Private>>,
27    scheme: SignatureScheme,
28}
29
30#[derive(Debug)]
31struct PKey(Arc<openssl::pkey::PKey<Private>>);
32
33fn rsa_padding(scheme: SignatureScheme) -> Option<Padding> {
34    match scheme {
35        SignatureScheme::RSA_PKCS1_SHA256
36        | SignatureScheme::RSA_PKCS1_SHA384
37        | SignatureScheme::RSA_PKCS1_SHA512 => Some(Padding::PKCS1),
38        SignatureScheme::RSA_PSS_SHA256
39        | SignatureScheme::RSA_PSS_SHA384
40        | SignatureScheme::RSA_PSS_SHA512 => Some(Padding::PKCS1_PSS),
41        _ => None,
42    }
43}
44
45fn message_digest(scheme: SignatureScheme) -> Option<MessageDigest> {
46    match scheme {
47        SignatureScheme::RSA_PKCS1_SHA256
48        | SignatureScheme::RSA_PSS_SHA256
49        | SignatureScheme::ECDSA_NISTP256_SHA256 => Some(MessageDigest::sha256()),
50        SignatureScheme::RSA_PKCS1_SHA384
51        | SignatureScheme::RSA_PSS_SHA384
52        | SignatureScheme::ECDSA_NISTP384_SHA384 => Some(MessageDigest::sha384()),
53        SignatureScheme::RSA_PKCS1_SHA512
54        | SignatureScheme::RSA_PSS_SHA512
55        | SignatureScheme::ECDSA_NISTP521_SHA512 => Some(MessageDigest::sha512()),
56        _ => None,
57    }
58}
59
60fn mgf1(scheme: SignatureScheme) -> Option<MessageDigest> {
61    match scheme {
62        SignatureScheme::RSA_PSS_SHA256 => Some(MessageDigest::sha256()),
63        SignatureScheme::RSA_PSS_SHA384 => Some(MessageDigest::sha384()),
64        SignatureScheme::RSA_PSS_SHA512 => Some(MessageDigest::sha512()),
65        _ => None,
66    }
67}
68
69fn pss_salt_len(scheme: SignatureScheme) -> Option<RsaPssSaltlen> {
70    match scheme {
71        SignatureScheme::RSA_PSS_SHA256
72        | SignatureScheme::RSA_PSS_SHA384
73        | SignatureScheme::RSA_PSS_SHA512 => Some(RsaPssSaltlen::DIGEST_LENGTH),
74        _ => None,
75    }
76}
77
78impl PKey {
79    fn signer(&self, scheme: SignatureScheme) -> Signer {
80        Signer {
81            key: Arc::clone(&self.0),
82            scheme,
83        }
84    }
85}
86
87impl rustls::crypto::KeyProvider for KeyProvider {
88    fn load_private_key(
89        &self,
90        key_der: PrivateKeyDer<'static>,
91    ) -> Result<Arc<dyn SigningKey>, Error> {
92        let pkey = openssl::pkey::PKey::private_key_from_der(key_der.secret_der())
93            .map_err(|e| Error::General(format!("OpenSSL error: {e}")))?;
94        Ok(Arc::new(PKey(Arc::new(pkey))))
95    }
96
97    fn fips(&self) -> bool {
98        crate::fips::enabled()
99    }
100}
101
102impl SigningKey for PKey {
103    fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn rustls::sign::Signer>> {
104        match self.algorithm() {
105            SignatureAlgorithm::RSA => RSA_SCHEMES
106                .iter()
107                .find(|scheme| offered.contains(scheme))
108                .map(|scheme| Box::new(self.signer(*scheme)) as Box<dyn rustls::sign::Signer>),
109
110            SignatureAlgorithm::ED25519 => {
111                if crate::verify::ed25519_available() && offered.contains(&SignatureScheme::ED25519)
112                {
113                    Some(Box::new(Signer {
114                        key: Arc::clone(&self.0),
115                        scheme: SignatureScheme::ED25519,
116                    }))
117                } else {
118                    None
119                }
120            }
121            SignatureAlgorithm::ED448 => {
122                if offered.contains(&SignatureScheme::ED448) {
123                    Some(Box::new(Signer {
124                        key: Arc::clone(&self.0),
125                        scheme: SignatureScheme::ED448,
126                    }))
127                } else {
128                    None
129                }
130            }
131            SignatureAlgorithm::ECDSA => {
132                // First determine our scheme
133                self.0
134                    .ec_key()
135                    .ok()
136                    .and_then(|ec_key| {
137                        let nid = ec_key.group().curve_name();
138                        let scheme = match nid {
139                            Some(openssl::nid::Nid::X9_62_PRIME256V1) => {
140                                SignatureScheme::ECDSA_NISTP256_SHA256
141                            }
142                            Some(openssl::nid::Nid::SECP384R1) => {
143                                SignatureScheme::ECDSA_NISTP384_SHA384
144                            }
145                            Some(openssl::nid::Nid::SECP521R1) => {
146                                SignatureScheme::ECDSA_NISTP521_SHA512
147                            }
148                            _ => return None,
149                        };
150                        Some(scheme)
151                    })
152                    // Now see if that was offered
153                    .and_then(|scheme| {
154                        if offered.contains(&scheme) {
155                            Some(Box::new(self.signer(scheme)) as Box<dyn rustls::sign::Signer>)
156                        } else {
157                            None
158                        }
159                    })
160            }
161            _ => None,
162        }
163    }
164
165    fn algorithm(&self) -> SignatureAlgorithm {
166        match self.0.id() {
167            Id::RSA => SignatureAlgorithm::RSA,
168            Id::EC => SignatureAlgorithm::ECDSA,
169            Id::ED448 => SignatureAlgorithm::ED448,
170            Id::ED25519 => SignatureAlgorithm::ED25519,
171            _ => SignatureAlgorithm::Unknown(self.0.id().as_raw().try_into().unwrap_or_default()),
172        }
173    }
174}
175
176impl rustls::sign::Signer for Signer {
177    fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
178        if let Some(message_digest) = message_digest(self.scheme) {
179            openssl::sign::Signer::new(message_digest, &self.key)
180                .and_then(|mut signer| {
181                    if let Some(padding) = rsa_padding(self.scheme) {
182                        signer.set_rsa_padding(padding)?;
183                    }
184                    if let Some(mgf1) = mgf1(self.scheme) {
185                        signer.set_rsa_mgf1_md(mgf1)?;
186                    }
187                    if let Some(len) = pss_salt_len(self.scheme) {
188                        signer.set_rsa_pss_saltlen(len)?;
189                    }
190                    signer.update(message)?;
191                    signer.sign_to_vec()
192                })
193                .map_err(|e| Error::General(format!("OpenSSL error: {e}")))
194        } else {
195            openssl::sign::Signer::new_without_digest(&self.key)
196                .and_then(|mut signer| signer.sign_oneshot_to_vec(message))
197                .map_err(|e| Error::General(format!("OpenSSL error: {e}")))
198        }
199    }
200
201    fn scheme(&self) -> SignatureScheme {
202        self.scheme
203    }
204}