1mod error;
24mod hyper_content_digest;
25mod hyper_http;
26
27const CONTENT_DIGEST_HEADER: &str = "content-digest";
31
32pub enum ContentDigestType {
34 Sha256,
35 Sha512,
36}
37
38impl std::fmt::Display for ContentDigestType {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 match self {
41 ContentDigestType::Sha256 => write!(f, "sha-256"),
42 ContentDigestType::Sha512 => write!(f, "sha-512"),
43 }
44 }
45}
46
47impl std::str::FromStr for ContentDigestType {
48 type Err = error::HyperDigestError;
49 fn from_str(s: &str) -> Result<Self, Self::Err> {
50 match s {
51 "sha-256" => Ok(ContentDigestType::Sha256),
52 "sha-512" => Ok(ContentDigestType::Sha512),
53 _ => Err(error::HyperDigestError::InvalidContentDigestType(s.to_string())),
54 }
55 }
56}
57
58pub use error::{HyperDigestError, HyperDigestResult, HyperSigError, HyperSigResult};
59pub use httpsig::prelude;
60pub use hyper_content_digest::{ContentDigest, RequestContentDigest, ResponseContentDigest};
61pub use hyper_http::{
62 MessageSignature, MessageSignatureReq, MessageSignatureReqSync, MessageSignatureRes, MessageSignatureResSync,
63};
64
65#[cfg(test)]
67mod tests {
68 use super::{prelude::*, *};
69 use http::{Request, Response};
70 use http_body_util::Full;
71 use httpsig::prelude::{PublicKey, SecretKey};
72
73 type BoxBody = http_body_util::combinators::BoxBody<bytes::Bytes, crate::error::HyperDigestError>;
74
75 const EDDSA_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
76MC4CAQAwBQYDK2VwBCIEIDSHAE++q1BP7T8tk+mJtS+hLf81B0o6CFyWgucDFN/C
77-----END PRIVATE KEY-----
78"##;
79 const EDDSA_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
80MCowBQYDK2VwAyEA1ixMQcxO46PLlgQfYS46ivFd+n0CcDHSKUnuhm3i1O0=
81-----END PUBLIC KEY-----
82"##;
83 const COVERED_COMPONENTS_REQ: &[&str] = &["@method", "date", "content-type", "content-digest"];
86 const COVERED_COMPONENTS_RES: &[&str] = &["@status", "\"@method\";req", "date", "content-type", "\"content-digest\";req"];
87
88 async fn build_request() -> Request<BoxBody> {
89 let body = Full::new(&b"{\"hello\": \"world\"}"[..]);
90 let req = Request::builder()
91 .method("GET")
92 .uri("https://example.com/parameters?var=this%20is%20a%20big%0Amultiline%20value&bar=with+plus+whitespace&fa%C3%A7ade%22%3A%20=something")
93 .header("date", "Sun, 09 May 2021 18:30:00 GMT")
94 .header("content-type", "application/json")
95 .header("content-type", "application/json-patch+json")
96 .body(body)
97 .unwrap();
98 req.set_content_digest(&ContentDigestType::Sha256).await.unwrap()
99 }
100
101 async fn build_response() -> Response<BoxBody> {
102 let body = Full::new(&b"{\"hello\": \"world!!\"}"[..]);
103 let res = Response::builder()
104 .status(200)
105 .header("date", "Sun, 09 May 2021 18:30:00 GMT")
106 .header("content-type", "application/json")
107 .header("content-type", "application/json-patch+json")
108 .body(body)
109 .unwrap();
110 res.set_content_digest(&ContentDigestType::Sha256).await.unwrap()
111 }
112
113 #[test]
114 fn test_content_digest_type() {
115 assert_eq!(ContentDigestType::Sha256.to_string(), "sha-256");
116 assert_eq!(ContentDigestType::Sha512.to_string(), "sha-512");
117 }
118
119 #[tokio::test]
120 async fn test_set_verify_request() {
121 let mut req = build_request().await;
124
125 let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
126
127 let covered_components = COVERED_COMPONENTS_REQ
128 .iter()
129 .map(|v| message_component::HttpMessageComponentId::try_from(*v))
130 .collect::<Result<Vec<_>, _>>()
131 .unwrap();
132 let mut signature_params = HttpSignatureParams::try_new(&covered_components).unwrap();
133
134 signature_params.set_key_info(&secret_key);
136
137 req
139 .set_message_signature(&signature_params, &secret_key, Some("custom_sig_name"))
140 .await
141 .unwrap();
142 let signature_input = req.headers().get("signature-input").unwrap().to_str().unwrap();
143 let signature = req.headers().get("signature").unwrap().to_str().unwrap();
144 assert!(signature_input.starts_with(r##"custom_sig_name=("##));
145 assert!(signature.starts_with(r##"custom_sig_name=:"##));
146
147 let (alg, _key_id) = req.get_alg_key_ids().unwrap().into_iter().next().unwrap().1;
150 let public_key = PublicKey::from_pem(&alg.unwrap(), EDDSA_PUBLIC_KEY).unwrap();
151 let verification_res = req.verify_message_signature(&public_key, None).await;
152 assert!(verification_res.is_ok());
153
154 let key_id = public_key.key_id();
156 let verification_res = req.verify_message_signature(&public_key, Some(&key_id)).await;
157 assert!(verification_res.is_ok());
158
159 let verification_res = req.verify_message_signature(&public_key, Some("NotFoundKeyId")).await;
160 assert!(verification_res.is_err());
161 }
162
163 #[tokio::test]
164 async fn test_set_verify_response() {
165 let req = build_request().await;
168 let mut res = build_response().await;
169
170 let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
171
172 let covered_components = COVERED_COMPONENTS_RES
173 .iter()
174 .map(|v| message_component::HttpMessageComponentId::try_from(*v))
175 .collect::<Result<Vec<_>, _>>()
176 .unwrap();
177 let mut signature_params = HttpSignatureParams::try_new(&covered_components).unwrap();
178
179 signature_params.set_key_info(&secret_key);
181
182 res
184 .set_message_signature(&signature_params, &secret_key, Some("custom_sig_name"), Some(&req))
185 .await
186 .unwrap();
187 let signature_input = res.headers().get("signature-input").unwrap().to_str().unwrap();
188 let signature = res.headers().get("signature").unwrap().to_str().unwrap();
189 assert!(signature_input.starts_with(r##"custom_sig_name=("##));
190 assert!(signature.starts_with(r##"custom_sig_name=:"##));
191
192 let (alg, _key_id) = res.get_alg_key_ids().unwrap().into_iter().next().unwrap().1;
195 let public_key = PublicKey::from_pem(&alg.unwrap(), EDDSA_PUBLIC_KEY).unwrap();
196 let verification_res = res.verify_message_signature(&public_key, None, Some(&req)).await;
197 assert!(verification_res.is_ok());
198 let verification_res = res
199 .verify_message_signature(&public_key, None, None as Option<&Request<()>>)
200 .await;
201 assert!(verification_res.is_err());
202
203 let key_id = public_key.key_id();
205 let verification_res = res.verify_message_signature(&public_key, Some(&key_id), Some(&req)).await;
206 assert!(verification_res.is_ok());
207
208 let verification_res = res
209 .verify_message_signature(&public_key, Some("NotFoundKeyId"), Some(&req))
210 .await;
211 assert!(verification_res.is_err());
212 }
213
214 #[cfg(feature = "blocking")]
215 #[test]
216 fn test_set_verify_request_sync() {
217 let mut req = futures::executor::block_on(build_request());
220 let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
221 let covered_components = COVERED_COMPONENTS_REQ
222 .iter()
223 .map(|v| message_component::HttpMessageComponentId::try_from(*v))
224 .collect::<Result<Vec<_>, _>>()
225 .unwrap();
226 let mut signature_params = HttpSignatureParams::try_new(&covered_components).unwrap();
227 signature_params.set_key_info(&secret_key);
229 req.set_message_signature_sync(&signature_params, &secret_key, None).unwrap();
231
232 let (alg, _key_id) = req.get_alg_key_ids().unwrap().into_iter().next().unwrap().1;
233 let public_key = PublicKey::from_pem(&alg.unwrap(), EDDSA_PUBLIC_KEY).unwrap();
234 let verification_res = req.verify_message_signature_sync(&public_key, None);
235 assert!(verification_res.is_ok());
236 }
237
238 #[cfg(feature = "blocking")]
239 #[test]
240 fn test_set_verify_response_sync() {
241 let req = futures::executor::block_on(build_request());
243 let mut res = futures::executor::block_on(build_response());
244 let secret_key = SecretKey::from_pem(&AlgorithmName::Ed25519, EDDSA_SECRET_KEY).unwrap();
245 let covered_components = COVERED_COMPONENTS_RES
246 .iter()
247 .map(|v| message_component::HttpMessageComponentId::try_from(*v))
248 .collect::<Result<Vec<_>, _>>()
249 .unwrap();
250 let mut signature_params = HttpSignatureParams::try_new(&covered_components).unwrap();
251 signature_params.set_key_info(&secret_key);
253 res
255 .set_message_signature_sync(&signature_params, &secret_key, None, Some(&req))
256 .unwrap();
257
258 let (alg, _key_id) = res.get_alg_key_ids().unwrap().into_iter().next().unwrap().1;
259 let public_key = PublicKey::from_pem(&alg.unwrap(), EDDSA_PUBLIC_KEY).unwrap();
260 let verification_res = res.verify_message_signature_sync(&public_key, None, Some(&req));
261 assert!(verification_res.is_ok());
262 }
263}