xdoc/signature/
algorithms.rs1use crate::core::{ErrorKind, XmlError, XmlResult};
2
3pub const XMLDSIG_ENVELOPED_SIGNATURE_URI: &str =
4 "http://www.w3.org/2000/09/xmldsig#enveloped-signature";
5pub const XMLDSIG_SIGNED_PROPERTIES_TYPE_URI: &str = "http://uri.etsi.org/01903#SignedProperties";
6
7const C14N_11_URI: &str = "http://www.w3.org/2006/12/xml-c14n11";
8const C14N_10_URI: &str = "http://www.w3.org/TR/2001/REC-xml-c14n-20010315";
9const EXCLUSIVE_C14N_10_URI: &str = "http://www.w3.org/2001/10/xml-exc-c14n#";
10const SHA1_URI: &str = "http://www.w3.org/2000/09/xmldsig#sha1";
11const SHA256_URI: &str = "http://www.w3.org/2001/04/xmlenc#sha256";
12const SHA512_URI: &str = "http://www.w3.org/2001/04/xmlenc#sha512";
13const RSA_SHA1_URI: &str = "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
14const RSA_SHA256_URI: &str = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256";
15
16#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
18pub enum CanonicalizationAlgorithm {
19 #[default]
20 CanonicalXml11,
21 CanonicalXml10,
22 ExclusiveXml10,
23}
24
25impl CanonicalizationAlgorithm {
26 pub fn uri(self) -> &'static str {
27 match self {
28 Self::CanonicalXml11 => C14N_11_URI,
29 Self::CanonicalXml10 => C14N_10_URI,
30 Self::ExclusiveXml10 => EXCLUSIVE_C14N_10_URI,
31 }
32 }
33
34 pub fn from_uri(uri: &str) -> XmlResult<Self> {
35 match uri {
36 C14N_11_URI => Ok(Self::CanonicalXml11),
37 C14N_10_URI => Ok(Self::CanonicalXml10),
38 EXCLUSIVE_C14N_10_URI => Ok(Self::ExclusiveXml10),
39 _ => Err(unsupported_algorithm("canonicalization", uri)),
40 }
41 }
42}
43
44#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
46pub enum DigestAlgorithm {
47 Sha1,
49 #[default]
50 Sha256,
51 Sha512,
52}
53
54impl DigestAlgorithm {
55 pub fn uri(self) -> &'static str {
56 match self {
57 Self::Sha1 => SHA1_URI,
58 Self::Sha256 => SHA256_URI,
59 Self::Sha512 => SHA512_URI,
60 }
61 }
62
63 pub fn from_uri(uri: &str) -> XmlResult<Self> {
64 match uri {
65 SHA1_URI => Ok(Self::Sha1),
66 SHA256_URI => Ok(Self::Sha256),
67 SHA512_URI => Ok(Self::Sha512),
68 _ => Err(unsupported_algorithm("digest", uri)),
69 }
70 }
71
72 pub fn ensure_allowed_for_generation(self) -> XmlResult<()> {
73 match self {
74 Self::Sha1 => Err(XmlError::new(
75 ErrorKind::Signature,
76 "SHA-1 is not allowed for signature generation",
77 )),
78 Self::Sha256 | Self::Sha512 => Ok(()),
79 }
80 }
81}
82
83#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
85pub enum SignatureAlgorithm {
86 RsaSha1,
88 #[default]
89 RsaSha256,
90}
91
92impl SignatureAlgorithm {
93 pub fn uri(self) -> &'static str {
94 match self {
95 Self::RsaSha1 => RSA_SHA1_URI,
96 Self::RsaSha256 => RSA_SHA256_URI,
97 }
98 }
99
100 pub fn from_uri(uri: &str) -> XmlResult<Self> {
101 match uri {
102 RSA_SHA1_URI => Ok(Self::RsaSha1),
103 RSA_SHA256_URI => Ok(Self::RsaSha256),
104 _ => Err(unsupported_algorithm("signature", uri)),
105 }
106 }
107
108 pub fn ensure_allowed_for_generation(self) -> XmlResult<()> {
109 match self {
110 Self::RsaSha1 => Err(XmlError::new(
111 ErrorKind::Signature,
112 "RSA-SHA1 is not allowed for signature generation",
113 )),
114 Self::RsaSha256 => Ok(()),
115 }
116 }
117}
118
119fn unsupported_algorithm(kind: &str, uri: &str) -> XmlError {
120 XmlError::new(
121 ErrorKind::Signature,
122 format!("unsupported {kind} algorithm URI `{uri}`"),
123 )
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn signature_algorithms_expose_xml_uris() {
132 assert_eq!(
133 CanonicalizationAlgorithm::CanonicalXml11.uri(),
134 "http://www.w3.org/2006/12/xml-c14n11"
135 );
136 assert_eq!(
137 CanonicalizationAlgorithm::CanonicalXml10.uri(),
138 "http://www.w3.org/TR/2001/REC-xml-c14n-20010315"
139 );
140 assert_eq!(
141 DigestAlgorithm::Sha256.uri(),
142 "http://www.w3.org/2001/04/xmlenc#sha256"
143 );
144 assert_eq!(
145 DigestAlgorithm::Sha512.uri(),
146 "http://www.w3.org/2001/04/xmlenc#sha512"
147 );
148 assert_eq!(
149 SignatureAlgorithm::RsaSha256.uri(),
150 "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
151 );
152 }
153
154 #[test]
155 fn signature_algorithms_parse_known_uris() {
156 assert_eq!(
157 CanonicalizationAlgorithm::from_uri("http://www.w3.org/2006/12/xml-c14n11")
158 .expect("c14n uri"),
159 CanonicalizationAlgorithm::CanonicalXml11
160 );
161 assert_eq!(
162 CanonicalizationAlgorithm::from_uri("http://www.w3.org/TR/2001/REC-xml-c14n-20010315")
163 .expect("c14n 1.0 uri"),
164 CanonicalizationAlgorithm::CanonicalXml10
165 );
166 assert_eq!(
167 DigestAlgorithm::from_uri("http://www.w3.org/2001/04/xmlenc#sha256")
168 .expect("digest uri"),
169 DigestAlgorithm::Sha256
170 );
171 assert_eq!(
172 DigestAlgorithm::from_uri("http://www.w3.org/2001/04/xmlenc#sha512")
173 .expect("digest uri"),
174 DigestAlgorithm::Sha512
175 );
176 assert_eq!(
177 SignatureAlgorithm::from_uri("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256")
178 .expect("signature uri"),
179 SignatureAlgorithm::RsaSha256
180 );
181 }
182
183 #[test]
184 fn signature_algorithms_reject_unknown_uris() {
185 let error = DigestAlgorithm::from_uri("urn:unknown")
186 .expect_err("unknown digest algorithm must fail");
187
188 assert_eq!(error.kind(), &ErrorKind::Signature);
189 assert!(error.message().contains("unsupported digest algorithm"));
190 }
191
192 #[test]
193 fn signature_algorithms_reject_sha1_for_generation() {
194 let digest_error = DigestAlgorithm::Sha1
195 .ensure_allowed_for_generation()
196 .expect_err("sha1 digest must be rejected");
197 let signature_error = SignatureAlgorithm::RsaSha1
198 .ensure_allowed_for_generation()
199 .expect_err("rsa-sha1 signature must be rejected");
200
201 assert_eq!(digest_error.kind(), &ErrorKind::Signature);
202 assert_eq!(signature_error.kind(), &ErrorKind::Signature);
203 }
204}