Skip to main content

openauth_saml/saml/
security.rs

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