1#[cfg(any(feature = "aws_lc", feature = "ring", feature = "rust_crypto"))]
2#[macro_use]
3mod backend;
4
5#[cfg(feature = "aws_lc")]
6pub mod aws_lc;
7#[cfg(feature = "ring")]
8pub mod ring;
9#[cfg(feature = "rust_crypto")]
10pub mod rust_crypto;
11
12use core::fmt::Debug;
13
14use crate::x509::{AlgorithmIdentifier, SubjectPublicKeyInfo};
15use crate::{Any, RsaSsaPssParams, oid_registry};
16
17#[derive(thiserror::Error, Debug)]
18pub enum CryptoError {
19 #[error("invalid key encoding: {0}")]
20 InvalidKey(String),
21 #[error("signature verification failed")]
22 VerificationFailed,
23}
24
25pub trait SignatureVerifier: Send + Sync + Debug {
35 fn verify_signature(
36 &self,
37 algorithm: &AlgorithmIdentifier<'_>,
38 public_key: &SubjectPublicKeyInfo<'_>,
39 message: &[u8],
40 signature: &[u8],
41 ) -> Result<(), CryptoError>;
42}
43
44#[derive(Debug)]
47struct UndeterminedCryptoBackend;
48
49const NO_BACKEND_ERROR: &str = "
50Could not automatically determine the crypto backend from x509-validator crate features.
51Make sure exactly one of the 'aws_lc', 'ring' and 'rust_crypto' features is enabled, or pass a
52provider explicitly to Validator::with_policy_and_backend instead of Validator::with_policy.
53";
54
55impl SignatureVerifier for UndeterminedCryptoBackend {
56 fn verify_signature(
57 &self,
58 _algorithm: &AlgorithmIdentifier<'_>,
59 _public_key: &SubjectPublicKeyInfo<'_>,
60 _message: &[u8],
61 _signature: &[u8],
62 ) -> Result<(), CryptoError> {
63 panic!("{NO_BACKEND_ERROR}")
64 }
65}
66
67pub fn default_provider() -> &'static dyn SignatureVerifier {
69 #[cfg(all(
70 feature = "aws_lc",
71 not(feature = "ring"),
72 not(feature = "rust_crypto")
73 ))]
74 {
75 return &aws_lc::DEFAULT_PROVIDER;
76 }
77
78 #[cfg(all(
79 feature = "ring",
80 not(feature = "aws_lc"),
81 not(feature = "rust_crypto")
82 ))]
83 {
84 return &ring::DEFAULT_PROVIDER;
85 }
86
87 #[cfg(all(
88 feature = "rust_crypto",
89 not(feature = "aws_lc"),
90 not(feature = "ring")
91 ))]
92 {
93 return &rust_crypto::DEFAULT_PROVIDER;
94 }
95
96 #[allow(unreachable_code)]
98 {
99 static UNDETERMINED_BACKEND: UndeterminedCryptoBackend = UndeterminedCryptoBackend;
100
101 &UNDETERMINED_BACKEND
102 }
103}
104
105pub fn rsa_pss_digest_bits(params: Option<&Any<'_>>) -> Option<usize> {
106 let params = params?;
107 let params = RsaSsaPssParams::try_from(params).ok()?;
108 let hash_algorithm = params.hash_algorithm_oid();
109
110 if *hash_algorithm == oid_registry::OID_NIST_HASH_SHA256 {
111 Some(256)
112 } else if *hash_algorithm == oid_registry::OID_NIST_HASH_SHA384 {
113 Some(384)
114 } else if *hash_algorithm == oid_registry::OID_NIST_HASH_SHA512 {
115 Some(512)
116 } else {
117 None
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use x509_validator_testkit::rcgen::{CertificateParams, KeyPair};
124
125 use super::*;
126 use crate::{Certificate, CertificateExt, FromDer};
127
128 fn algorithm_and_spki() -> (AlgorithmIdentifier<'static>, SubjectPublicKeyInfo<'static>) {
132 let key_pair = KeyPair::generate().expect("generate key pair");
133 let der = CertificateParams::default()
134 .self_signed(&key_pair)
135 .expect("self-sign")
136 .der()
137 .to_vec();
138 let der: &'static [u8] = Box::leak(der.into_boxed_slice());
139 let cert = Certificate::parse(der).expect("parse certificate");
140 (cert.signature_algorithm, cert.tbs_certificate.subject_pki)
141 }
142
143 #[derive(Debug)]
146 struct TaggedVerifier;
147
148 impl SignatureVerifier for TaggedVerifier {
149 fn verify_signature(
150 &self,
151 algorithm: &AlgorithmIdentifier<'_>,
152 _public_key: &SubjectPublicKeyInfo<'_>,
153 _message: &[u8],
154 _signature: &[u8],
155 ) -> Result<(), CryptoError> {
156 Err(CryptoError::InvalidKey(format!(
157 "{}-was-called",
158 algorithm.algorithm
159 )))
160 }
161 }
162
163 #[derive(Debug)]
165 struct FailureVerifier;
166
167 impl SignatureVerifier for FailureVerifier {
168 fn verify_signature(
169 &self,
170 _algorithm: &AlgorithmIdentifier<'_>,
171 _public_key: &SubjectPublicKeyInfo<'_>,
172 _message: &[u8],
173 _signature: &[u8],
174 ) -> Result<(), CryptoError> {
175 Err(CryptoError::VerificationFailed)
176 }
177 }
178
179 #[test]
180 fn verify_signature_receives_the_signature_algorithm() {
181 let (algorithm, spki) = algorithm_and_spki();
182
183 let result = TaggedVerifier.verify_signature(&algorithm, &spki, b"message", b"signature");
184
185 match result {
186 Err(CryptoError::InvalidKey(msg)) => {
187 assert_eq!(msg, format!("{}-was-called", algorithm.algorithm));
188 }
189 _ => panic!("Expected InvalidKey error naming the algorithm, got {result:?}"),
190 }
191 }
192
193 #[test]
194 fn verify_signature_propagates_verification_failure() {
195 let (algorithm, spki) = algorithm_and_spki();
196
197 let result = FailureVerifier.verify_signature(&algorithm, &spki, b"message", b"signature");
198
199 assert!(matches!(result, Err(CryptoError::VerificationFailed)));
200 }
201
202 #[test]
203 fn absent_parameters_yield_no_digest() {
204 assert_eq!(rsa_pss_digest_bits(None), None);
205 }
206
207 #[test]
208 fn undecodable_parameters_yield_no_digest() {
209 let params = Any::from_der(&[0x05, 0x00])
211 .expect("parse NULL")
212 .1;
213
214 assert_eq!(rsa_pss_digest_bits(Some(¶ms)), None);
215 }
216
217 fn pss_params_der(oid_der: &[u8]) -> Vec<u8> {
219 let mut algorithm_identifier = vec![0x30, oid_der.len() as u8];
221 algorithm_identifier.extend_from_slice(oid_der);
222
223 let mut tagged = vec![0xa0, algorithm_identifier.len() as u8];
225 tagged.extend_from_slice(&algorithm_identifier);
226
227 let mut params = vec![0x30, tagged.len() as u8];
229 params.extend_from_slice(&tagged);
230 params
231 }
232
233 #[test]
234 fn sha2_hash_algorithms_yield_their_digest_size() {
235 for (last_octet, expected) in [(0x01, 256), (0x02, 384), (0x03, 512)] {
237 let oid_der = [
238 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, last_octet,
239 ];
240 let der = pss_params_der(&oid_der);
241 let params = Any::from_der(&der)
242 .expect("parse PSS params")
243 .1;
244
245 assert_eq!(rsa_pss_digest_bits(Some(¶ms)), Some(expected));
246 }
247 }
248
249 #[test]
250 fn non_sha2_hash_algorithm_yields_no_digest() {
251 let oid_der = [0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a];
253 let der = pss_params_der(&oid_der);
254 let params = Any::from_der(&der)
255 .expect("parse PSS params")
256 .1;
257
258 assert_eq!(rsa_pss_digest_bits(Some(¶ms)), None);
259 }
260}