Skip to main content

rustauth_saml/saml/
security.rs

1use quick_xml::events::{BytesStart, Event};
2use quick_xml::Reader;
3use rustauth_core::error::RustAuthError;
4use time::{Duration, OffsetDateTime};
5
6use super::xml::{local_name, validate_saml_xml};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
9pub struct SamlConditions {
10    pub not_before: Option<String>,
11    pub not_on_or_after: Option<String>,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct TimestampValidationOptions {
16    pub clock_skew: Duration,
17    pub require_timestamps: bool,
18}
19
20impl Default for TimestampValidationOptions {
21    fn default() -> Self {
22        Self {
23            clock_skew: Duration::minutes(5),
24            require_timestamps: false,
25        }
26    }
27}
28
29#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
30pub enum SamlSecurityError {
31    #[error("SAML assertion missing required timestamp conditions")]
32    MissingTimestampConditions,
33    #[error("SAML assertion has invalid NotBefore timestamp")]
34    InvalidNotBefore,
35    #[error("SAML assertion has invalid NotOnOrAfter timestamp")]
36    InvalidNotOnOrAfter,
37    #[error("SAML assertion is not yet valid")]
38    NotYetValid,
39    #[error("SAML assertion has expired")]
40    Expired,
41    #[error("SAML signature algorithm not recognized: {0}")]
42    UnknownSignatureAlgorithm(String),
43    #[error("SAML digest algorithm not recognized: {0}")]
44    UnknownDigestAlgorithm(String),
45    #[error("SAML signature algorithm is deprecated: {0}")]
46    DeprecatedSignatureAlgorithm(String),
47    #[error("SAML digest algorithm is deprecated: {0}")]
48    DeprecatedDigestAlgorithm(String),
49    #[error("SAML signature algorithm not in allow-list: {0}")]
50    SignatureAlgorithmNotAllowed(String),
51    #[error("SAML digest algorithm not in allow-list: {0}")]
52    DigestAlgorithmNotAllowed(String),
53    #[error("SAML key encryption algorithm not recognized: {0}")]
54    UnknownKeyEncryptionAlgorithm(String),
55    #[error("SAML data encryption algorithm not recognized: {0}")]
56    UnknownDataEncryptionAlgorithm(String),
57    #[error("SAML key encryption algorithm is deprecated: {0}")]
58    DeprecatedKeyEncryptionAlgorithm(String),
59    #[error("SAML data encryption algorithm is deprecated: {0}")]
60    DeprecatedDataEncryptionAlgorithm(String),
61    #[error("SAML key encryption algorithm not in allow-list: {0}")]
62    KeyEncryptionAlgorithmNotAllowed(String),
63    #[error("SAML data encryption algorithm not in allow-list: {0}")]
64    DataEncryptionAlgorithmNotAllowed(String),
65}
66
67pub fn validate_saml_timestamp(
68    conditions: Option<&SamlConditions>,
69    options: TimestampValidationOptions,
70) -> Result<(), SamlSecurityError> {
71    validate_saml_timestamp_at(conditions, options, OffsetDateTime::now_utc())
72}
73
74pub fn validate_saml_timestamp_at(
75    conditions: Option<&SamlConditions>,
76    options: TimestampValidationOptions,
77    now: OffsetDateTime,
78) -> Result<(), SamlSecurityError> {
79    let has_timestamps = conditions.is_some_and(|conditions| {
80        conditions.not_before.is_some() || conditions.not_on_or_after.is_some()
81    });
82    if !has_timestamps {
83        return if options.require_timestamps {
84            Err(SamlSecurityError::MissingTimestampConditions)
85        } else {
86            Ok(())
87        };
88    }
89
90    let Some(conditions) = conditions else {
91        return if options.require_timestamps {
92            Err(SamlSecurityError::MissingTimestampConditions)
93        } else {
94            Ok(())
95        };
96    };
97
98    if let Some(not_before) = &conditions.not_before {
99        let parsed =
100            OffsetDateTime::parse(not_before, &time::format_description::well_known::Rfc3339)
101                .map_err(|_| SamlSecurityError::InvalidNotBefore)?;
102        if now < parsed - options.clock_skew {
103            return Err(SamlSecurityError::NotYetValid);
104        }
105    }
106
107    if let Some(not_on_or_after) = &conditions.not_on_or_after {
108        let parsed = OffsetDateTime::parse(
109            not_on_or_after,
110            &time::format_description::well_known::Rfc3339,
111        )
112        .map_err(|_| SamlSecurityError::InvalidNotOnOrAfter)?;
113        if now > parsed + options.clock_skew {
114            return Err(SamlSecurityError::Expired);
115        }
116    }
117
118    Ok(())
119}
120
121#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
122#[serde(rename_all = "camelCase")]
123pub enum DeprecatedAlgorithmBehavior {
124    Reject,
125    Warn,
126    Allow,
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum SignatureAlgorithm {
131    RsaSha1,
132    RsaSha256,
133    RsaSha384,
134    RsaSha512,
135    EcdsaSha256,
136    EcdsaSha384,
137    EcdsaSha512,
138}
139
140impl SignatureAlgorithm {
141    pub fn as_uri(self) -> &'static str {
142        match self {
143            Self::RsaSha1 => "http://www.w3.org/2000/09/xmldsig#rsa-sha1",
144            Self::RsaSha256 => "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
145            Self::RsaSha384 => "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
146            Self::RsaSha512 => "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
147            Self::EcdsaSha256 => "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
148            Self::EcdsaSha384 => "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
149            Self::EcdsaSha512 => "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
150        }
151    }
152}
153
154pub fn validate_saml_config_algorithms(
155    signature_algorithm: Option<&str>,
156    digest_algorithm: Option<&str>,
157) -> Result<(), SamlSecurityError> {
158    validate_saml_config_algorithms_with_policy(
159        signature_algorithm,
160        digest_algorithm,
161        DeprecatedAlgorithmBehavior::Warn,
162        None,
163        None,
164    )
165}
166
167pub fn validate_saml_config_algorithms_with_policy(
168    signature_algorithm: Option<&str>,
169    digest_algorithm: Option<&str>,
170    on_deprecated: DeprecatedAlgorithmBehavior,
171    allowed_signature_algorithms: Option<&[String]>,
172    allowed_digest_algorithms: Option<&[String]>,
173) -> Result<(), SamlSecurityError> {
174    if let Some(algorithm) = signature_algorithm {
175        let normalized = normalize_signature_algorithm(algorithm);
176        if let Some(allowed) = allowed_signature_algorithms {
177            let is_allowed = allowed
178                .iter()
179                .map(|algorithm| normalize_signature_algorithm(algorithm))
180                .any(|allowed| allowed == normalized);
181            if !is_allowed {
182                return Err(SamlSecurityError::SignatureAlgorithmNotAllowed(
183                    algorithm.to_owned(),
184                ));
185            }
186        } else if is_deprecated_signature_algorithm(&normalized)
187            && on_deprecated == DeprecatedAlgorithmBehavior::Reject
188        {
189            return Err(SamlSecurityError::DeprecatedSignatureAlgorithm(
190                algorithm.to_owned(),
191            ));
192        } else if !is_known_signature_algorithm(&normalized) {
193            return Err(SamlSecurityError::UnknownSignatureAlgorithm(
194                algorithm.to_owned(),
195            ));
196        }
197    }
198    if let Some(algorithm) = digest_algorithm {
199        let normalized = normalize_digest_algorithm(algorithm);
200        if let Some(allowed) = allowed_digest_algorithms {
201            let is_allowed = allowed
202                .iter()
203                .map(|algorithm| normalize_digest_algorithm(algorithm))
204                .any(|allowed| allowed == normalized);
205            if !is_allowed {
206                return Err(SamlSecurityError::DigestAlgorithmNotAllowed(
207                    algorithm.to_owned(),
208                ));
209            }
210        } else if is_deprecated_digest_algorithm(&normalized)
211            && on_deprecated == DeprecatedAlgorithmBehavior::Reject
212        {
213            return Err(SamlSecurityError::DeprecatedDigestAlgorithm(
214                algorithm.to_owned(),
215            ));
216        } else if !is_known_digest_algorithm(&normalized) {
217            return Err(SamlSecurityError::UnknownDigestAlgorithm(
218                algorithm.to_owned(),
219            ));
220        }
221    }
222    Ok(())
223}
224
225#[derive(Debug, Clone, Default, PartialEq, Eq)]
226pub struct SamlRuntimeAlgorithms {
227    pub signature_algorithms: Vec<String>,
228    pub digest_algorithms: Vec<String>,
229    pub key_encryption_algorithms: Vec<String>,
230    pub data_encryption_algorithms: Vec<String>,
231}
232
233#[derive(Debug, Clone, Copy, PartialEq, Eq)]
234pub struct SamlRuntimeAlgorithmPolicy<'a> {
235    pub on_deprecated: DeprecatedAlgorithmBehavior,
236    pub allowed_signature_algorithms: Option<&'a [String]>,
237    pub allowed_digest_algorithms: Option<&'a [String]>,
238    pub allowed_key_encryption_algorithms: Option<&'a [String]>,
239    pub allowed_data_encryption_algorithms: Option<&'a [String]>,
240}
241
242impl Default for SamlRuntimeAlgorithmPolicy<'_> {
243    fn default() -> Self {
244        Self {
245            on_deprecated: DeprecatedAlgorithmBehavior::Warn,
246            allowed_signature_algorithms: None,
247            allowed_digest_algorithms: None,
248            allowed_key_encryption_algorithms: None,
249            allowed_data_encryption_algorithms: None,
250        }
251    }
252}
253
254pub fn collect_saml_runtime_algorithms(xml: &str) -> Result<SamlRuntimeAlgorithms, RustAuthError> {
255    validate_saml_xml(xml)?;
256
257    let mut reader = Reader::from_str(xml);
258    reader.config_mut().trim_text(true);
259    let mut stack = Vec::new();
260    let mut algorithms = SamlRuntimeAlgorithms::default();
261
262    loop {
263        match reader.read_event() {
264            Ok(Event::Start(element)) => {
265                let name = local_name(element.name().as_ref())?;
266                collect_algorithm(&reader, &element, &name, &stack, &mut algorithms)?;
267                stack.push(name);
268            }
269            Ok(Event::Empty(element)) => {
270                let name = local_name(element.name().as_ref())?;
271                collect_algorithm(&reader, &element, &name, &stack, &mut algorithms)?;
272            }
273            Ok(Event::End(_)) => {
274                stack.pop();
275            }
276            Ok(Event::Eof) => break,
277            Err(error) => return Err(RustAuthError::Api(format!("Invalid SAML XML: {error}"))),
278            Ok(_) => {}
279        }
280    }
281
282    Ok(algorithms)
283}
284
285pub fn validate_saml_runtime_algorithms(
286    algorithms: &SamlRuntimeAlgorithms,
287    policy: SamlRuntimeAlgorithmPolicy<'_>,
288) -> Result<(), SamlSecurityError> {
289    for algorithm in &algorithms.signature_algorithms {
290        validate_signature_algorithm(
291            algorithm,
292            policy.on_deprecated,
293            policy.allowed_signature_algorithms,
294        )?;
295    }
296    for algorithm in &algorithms.digest_algorithms {
297        validate_digest_algorithm(
298            algorithm,
299            policy.on_deprecated,
300            policy.allowed_digest_algorithms,
301        )?;
302    }
303    for algorithm in &algorithms.key_encryption_algorithms {
304        validate_key_encryption_algorithm(
305            algorithm,
306            policy.on_deprecated,
307            policy.allowed_key_encryption_algorithms,
308        )?;
309    }
310    for algorithm in &algorithms.data_encryption_algorithms {
311        validate_data_encryption_algorithm(
312            algorithm,
313            policy.on_deprecated,
314            policy.allowed_data_encryption_algorithms,
315        )?;
316    }
317    Ok(())
318}
319
320fn collect_algorithm(
321    reader: &Reader<&[u8]>,
322    element: &BytesStart<'_>,
323    name: &str,
324    stack: &[String],
325    algorithms: &mut SamlRuntimeAlgorithms,
326) -> Result<(), RustAuthError> {
327    let Some(algorithm) = attr(reader, element, "Algorithm")? else {
328        return Ok(());
329    };
330    match name {
331        "SignatureMethod" => algorithms.signature_algorithms.push(algorithm),
332        "DigestMethod" => algorithms.digest_algorithms.push(algorithm),
333        "EncryptionMethod" if stack.iter().any(|item| item == "EncryptedKey") => {
334            algorithms.key_encryption_algorithms.push(algorithm);
335        }
336        "EncryptionMethod" if stack.iter().any(|item| item == "EncryptedData") => {
337            algorithms.data_encryption_algorithms.push(algorithm);
338        }
339        _ => {}
340    }
341    Ok(())
342}
343
344fn attr(
345    reader: &Reader<&[u8]>,
346    element: &BytesStart<'_>,
347    name: &str,
348) -> Result<Option<String>, RustAuthError> {
349    for attribute in element.attributes() {
350        let attribute = attribute.map_err(|error| RustAuthError::Api(error.to_string()))?;
351        if local_name(attribute.key.as_ref())? == name {
352            return attribute
353                .decode_and_unescape_value(reader.decoder())
354                .map(|value| Some(value.into_owned()))
355                .map_err(|error| RustAuthError::Api(error.to_string()));
356        }
357    }
358    Ok(None)
359}
360
361fn normalize_signature_algorithm(algorithm: &str) -> String {
362    match algorithm.to_ascii_lowercase().as_str() {
363        "sha1" | "rsa-sha1" => SignatureAlgorithm::RsaSha1.as_uri().to_owned(),
364        "sha256" | "rsa-sha256" => SignatureAlgorithm::RsaSha256.as_uri().to_owned(),
365        "sha384" | "rsa-sha384" => SignatureAlgorithm::RsaSha384.as_uri().to_owned(),
366        "sha512" | "rsa-sha512" => SignatureAlgorithm::RsaSha512.as_uri().to_owned(),
367        "ecdsa-sha256" => SignatureAlgorithm::EcdsaSha256.as_uri().to_owned(),
368        "ecdsa-sha384" => SignatureAlgorithm::EcdsaSha384.as_uri().to_owned(),
369        "ecdsa-sha512" => SignatureAlgorithm::EcdsaSha512.as_uri().to_owned(),
370        _ => algorithm.to_owned(),
371    }
372}
373
374fn normalize_digest_algorithm(algorithm: &str) -> String {
375    match algorithm.to_ascii_lowercase().as_str() {
376        "sha1" => DigestAlgorithm::Sha1.as_uri().to_owned(),
377        "sha256" => DigestAlgorithm::Sha256.as_uri().to_owned(),
378        "sha384" => DigestAlgorithm::Sha384.as_uri().to_owned(),
379        "sha512" => DigestAlgorithm::Sha512.as_uri().to_owned(),
380        _ => algorithm.to_owned(),
381    }
382}
383
384fn normalize_key_encryption_algorithm(algorithm: &str) -> String {
385    match algorithm.to_ascii_lowercase().as_str() {
386        "rsa-1_5" | "rsa1_5" => KeyEncryptionAlgorithm::Rsa15.as_uri().to_owned(),
387        "rsa-oaep" | "rsa-oaep-mgf1p" => KeyEncryptionAlgorithm::RsaOaep.as_uri().to_owned(),
388        "rsa-oaep-sha256" => KeyEncryptionAlgorithm::RsaOaepSha256.as_uri().to_owned(),
389        _ => algorithm.to_owned(),
390    }
391}
392
393fn normalize_data_encryption_algorithm(algorithm: &str) -> String {
394    match algorithm.to_ascii_lowercase().as_str() {
395        "tripledes-cbc" | "3des-cbc" => DataEncryptionAlgorithm::TripleDesCbc.as_uri().to_owned(),
396        "aes128-cbc" => DataEncryptionAlgorithm::Aes128Cbc.as_uri().to_owned(),
397        "aes192-cbc" => DataEncryptionAlgorithm::Aes192Cbc.as_uri().to_owned(),
398        "aes256-cbc" => DataEncryptionAlgorithm::Aes256Cbc.as_uri().to_owned(),
399        "aes128-gcm" => DataEncryptionAlgorithm::Aes128Gcm.as_uri().to_owned(),
400        "aes192-gcm" => DataEncryptionAlgorithm::Aes192Gcm.as_uri().to_owned(),
401        "aes256-gcm" => DataEncryptionAlgorithm::Aes256Gcm.as_uri().to_owned(),
402        _ => algorithm.to_owned(),
403    }
404}
405
406fn validate_signature_algorithm(
407    algorithm: &str,
408    on_deprecated: DeprecatedAlgorithmBehavior,
409    allowed: Option<&[String]>,
410) -> Result<(), SamlSecurityError> {
411    let normalized = normalize_signature_algorithm(algorithm);
412    if let Some(allowed) = allowed {
413        let is_allowed = allowed
414            .iter()
415            .map(|algorithm| normalize_signature_algorithm(algorithm))
416            .any(|allowed| allowed == normalized);
417        if !is_allowed {
418            return Err(SamlSecurityError::SignatureAlgorithmNotAllowed(
419                algorithm.to_owned(),
420            ));
421        }
422    } else if is_deprecated_signature_algorithm(&normalized)
423        && on_deprecated == DeprecatedAlgorithmBehavior::Reject
424    {
425        return Err(SamlSecurityError::DeprecatedSignatureAlgorithm(
426            algorithm.to_owned(),
427        ));
428    } else if !is_known_signature_algorithm(&normalized) {
429        return Err(SamlSecurityError::UnknownSignatureAlgorithm(
430            algorithm.to_owned(),
431        ));
432    }
433    Ok(())
434}
435
436fn validate_digest_algorithm(
437    algorithm: &str,
438    on_deprecated: DeprecatedAlgorithmBehavior,
439    allowed: Option<&[String]>,
440) -> Result<(), SamlSecurityError> {
441    let normalized = normalize_digest_algorithm(algorithm);
442    if let Some(allowed) = allowed {
443        let is_allowed = allowed
444            .iter()
445            .map(|algorithm| normalize_digest_algorithm(algorithm))
446            .any(|allowed| allowed == normalized);
447        if !is_allowed {
448            return Err(SamlSecurityError::DigestAlgorithmNotAllowed(
449                algorithm.to_owned(),
450            ));
451        }
452    } else if is_deprecated_digest_algorithm(&normalized)
453        && on_deprecated == DeprecatedAlgorithmBehavior::Reject
454    {
455        return Err(SamlSecurityError::DeprecatedDigestAlgorithm(
456            algorithm.to_owned(),
457        ));
458    } else if !is_known_digest_algorithm(&normalized) {
459        return Err(SamlSecurityError::UnknownDigestAlgorithm(
460            algorithm.to_owned(),
461        ));
462    }
463    Ok(())
464}
465
466fn is_known_signature_algorithm(algorithm: &str) -> bool {
467    [
468        SignatureAlgorithm::RsaSha1,
469        SignatureAlgorithm::RsaSha256,
470        SignatureAlgorithm::RsaSha384,
471        SignatureAlgorithm::RsaSha512,
472        SignatureAlgorithm::EcdsaSha256,
473        SignatureAlgorithm::EcdsaSha384,
474        SignatureAlgorithm::EcdsaSha512,
475    ]
476    .into_iter()
477    .any(|known| known.as_uri() == algorithm)
478}
479
480fn is_deprecated_signature_algorithm(algorithm: &str) -> bool {
481    SignatureAlgorithm::RsaSha1.as_uri() == algorithm
482}
483
484fn is_known_digest_algorithm(algorithm: &str) -> bool {
485    [
486        DigestAlgorithm::Sha1,
487        DigestAlgorithm::Sha256,
488        DigestAlgorithm::Sha384,
489        DigestAlgorithm::Sha512,
490    ]
491    .into_iter()
492    .any(|known| known.as_uri() == algorithm)
493}
494
495fn is_deprecated_digest_algorithm(algorithm: &str) -> bool {
496    DigestAlgorithm::Sha1.as_uri() == algorithm
497}
498
499fn validate_key_encryption_algorithm(
500    algorithm: &str,
501    on_deprecated: DeprecatedAlgorithmBehavior,
502    allowed: Option<&[String]>,
503) -> Result<(), SamlSecurityError> {
504    let normalized = normalize_key_encryption_algorithm(algorithm);
505    if let Some(allowed) = allowed {
506        let is_allowed = allowed
507            .iter()
508            .map(|algorithm| normalize_key_encryption_algorithm(algorithm))
509            .any(|allowed| allowed == normalized);
510        if !is_allowed {
511            return Err(SamlSecurityError::KeyEncryptionAlgorithmNotAllowed(
512                algorithm.to_owned(),
513            ));
514        }
515    } else if is_deprecated_key_encryption_algorithm(&normalized)
516        && on_deprecated == DeprecatedAlgorithmBehavior::Reject
517    {
518        return Err(SamlSecurityError::DeprecatedKeyEncryptionAlgorithm(
519            algorithm.to_owned(),
520        ));
521    } else if !is_known_key_encryption_algorithm(&normalized) {
522        return Err(SamlSecurityError::UnknownKeyEncryptionAlgorithm(
523            algorithm.to_owned(),
524        ));
525    }
526    Ok(())
527}
528
529fn validate_data_encryption_algorithm(
530    algorithm: &str,
531    on_deprecated: DeprecatedAlgorithmBehavior,
532    allowed: Option<&[String]>,
533) -> Result<(), SamlSecurityError> {
534    let normalized = normalize_data_encryption_algorithm(algorithm);
535    if let Some(allowed) = allowed {
536        let is_allowed = allowed
537            .iter()
538            .map(|algorithm| normalize_data_encryption_algorithm(algorithm))
539            .any(|allowed| allowed == normalized);
540        if !is_allowed {
541            return Err(SamlSecurityError::DataEncryptionAlgorithmNotAllowed(
542                algorithm.to_owned(),
543            ));
544        }
545    } else if is_deprecated_data_encryption_algorithm(&normalized)
546        && on_deprecated == DeprecatedAlgorithmBehavior::Reject
547    {
548        return Err(SamlSecurityError::DeprecatedDataEncryptionAlgorithm(
549            algorithm.to_owned(),
550        ));
551    } else if !is_known_data_encryption_algorithm(&normalized) {
552        return Err(SamlSecurityError::UnknownDataEncryptionAlgorithm(
553            algorithm.to_owned(),
554        ));
555    }
556    Ok(())
557}
558
559fn is_known_key_encryption_algorithm(algorithm: &str) -> bool {
560    [
561        KeyEncryptionAlgorithm::Rsa15,
562        KeyEncryptionAlgorithm::RsaOaep,
563        KeyEncryptionAlgorithm::RsaOaepSha256,
564    ]
565    .into_iter()
566    .any(|known| known.as_uri() == algorithm)
567}
568
569fn is_deprecated_key_encryption_algorithm(algorithm: &str) -> bool {
570    KeyEncryptionAlgorithm::Rsa15.as_uri() == algorithm
571}
572
573fn is_known_data_encryption_algorithm(algorithm: &str) -> bool {
574    [
575        DataEncryptionAlgorithm::TripleDesCbc,
576        DataEncryptionAlgorithm::Aes128Cbc,
577        DataEncryptionAlgorithm::Aes192Cbc,
578        DataEncryptionAlgorithm::Aes256Cbc,
579        DataEncryptionAlgorithm::Aes128Gcm,
580        DataEncryptionAlgorithm::Aes192Gcm,
581        DataEncryptionAlgorithm::Aes256Gcm,
582    ]
583    .into_iter()
584    .any(|known| known.as_uri() == algorithm)
585}
586
587fn is_deprecated_data_encryption_algorithm(algorithm: &str) -> bool {
588    DataEncryptionAlgorithm::TripleDesCbc.as_uri() == algorithm
589}
590
591#[derive(Debug, Clone, Copy, PartialEq, Eq)]
592pub enum DigestAlgorithm {
593    Sha1,
594    Sha256,
595    Sha384,
596    Sha512,
597}
598
599impl DigestAlgorithm {
600    pub fn as_uri(self) -> &'static str {
601        match self {
602            Self::Sha1 => "http://www.w3.org/2000/09/xmldsig#sha1",
603            Self::Sha256 => "http://www.w3.org/2001/04/xmlenc#sha256",
604            Self::Sha384 => "http://www.w3.org/2001/04/xmldsig-more#sha384",
605            Self::Sha512 => "http://www.w3.org/2001/04/xmlenc#sha512",
606        }
607    }
608}
609
610#[derive(Debug, Clone, Copy, PartialEq, Eq)]
611pub enum KeyEncryptionAlgorithm {
612    Rsa15,
613    RsaOaep,
614    RsaOaepSha256,
615}
616
617impl KeyEncryptionAlgorithm {
618    pub fn as_uri(self) -> &'static str {
619        match self {
620            Self::Rsa15 => "http://www.w3.org/2001/04/xmlenc#rsa-1_5",
621            Self::RsaOaep => "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p",
622            Self::RsaOaepSha256 => "http://www.w3.org/2009/xmlenc11#rsa-oaep",
623        }
624    }
625}
626
627#[derive(Debug, Clone, Copy, PartialEq, Eq)]
628pub enum DataEncryptionAlgorithm {
629    TripleDesCbc,
630    Aes128Cbc,
631    Aes192Cbc,
632    Aes256Cbc,
633    Aes128Gcm,
634    Aes192Gcm,
635    Aes256Gcm,
636}
637
638impl DataEncryptionAlgorithm {
639    pub fn as_uri(self) -> &'static str {
640        match self {
641            Self::TripleDesCbc => "http://www.w3.org/2001/04/xmlenc#tripledes-cbc",
642            Self::Aes128Cbc => "http://www.w3.org/2001/04/xmlenc#aes128-cbc",
643            Self::Aes192Cbc => "http://www.w3.org/2001/04/xmlenc#aes192-cbc",
644            Self::Aes256Cbc => "http://www.w3.org/2001/04/xmlenc#aes256-cbc",
645            Self::Aes128Gcm => "http://www.w3.org/2009/xmlenc11#aes128-gcm",
646            Self::Aes192Gcm => "http://www.w3.org/2009/xmlenc11#aes192-gcm",
647            Self::Aes256Gcm => "http://www.w3.org/2009/xmlenc11#aes256-gcm",
648        }
649    }
650}