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(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 public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
149 let verification_res = req.verify_message_signature(&public_key, None).await;
150 assert!(verification_res.is_ok());
151
152 let key_id = public_key.key_id();
154 let verification_res = req.verify_message_signature(&public_key, Some(&key_id)).await;
155 assert!(verification_res.is_ok());
156
157 let verification_res = req.verify_message_signature(&public_key, Some("NotFoundKeyId")).await;
158 assert!(verification_res.is_err());
159 }
160
161 #[tokio::test]
162 async fn test_set_verify_response() {
163 let req = build_request().await;
166 let mut res = build_response().await;
167
168 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
169
170 let covered_components = COVERED_COMPONENTS_RES
171 .iter()
172 .map(|v| message_component::HttpMessageComponentId::try_from(*v))
173 .collect::<Result<Vec<_>, _>>()
174 .unwrap();
175 let mut signature_params = HttpSignatureParams::try_new(&covered_components).unwrap();
176
177 signature_params.set_key_info(&secret_key);
179
180 res
182 .set_message_signature(&signature_params, &secret_key, Some("custom_sig_name"), Some(&req))
183 .await
184 .unwrap();
185 let signature_input = res.headers().get("signature-input").unwrap().to_str().unwrap();
186 let signature = res.headers().get("signature").unwrap().to_str().unwrap();
187 assert!(signature_input.starts_with(r##"custom_sig_name=("##));
188 assert!(signature.starts_with(r##"custom_sig_name=:"##));
189
190 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
192 let verification_res = res.verify_message_signature(&public_key, None, Some(&req)).await;
193 assert!(verification_res.is_ok());
194 let verification_res = res
195 .verify_message_signature(&public_key, None, None as Option<&Request<()>>)
196 .await;
197 assert!(verification_res.is_err());
198
199 let key_id = public_key.key_id();
201 let verification_res = res.verify_message_signature(&public_key, Some(&key_id), Some(&req)).await;
202 assert!(verification_res.is_ok());
203
204 let verification_res = res
205 .verify_message_signature(&public_key, Some("NotFoundKeyId"), Some(&req))
206 .await;
207 assert!(verification_res.is_err());
208 }
209
210 #[cfg(feature = "blocking")]
211 #[test]
212 fn test_set_verify_request_sync() {
213 let mut req = futures::executor::block_on(build_request());
216 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
217 let covered_components = COVERED_COMPONENTS_REQ
218 .iter()
219 .map(|v| message_component::HttpMessageComponentId::try_from(*v))
220 .collect::<Result<Vec<_>, _>>()
221 .unwrap();
222 let mut signature_params = HttpSignatureParams::try_new(&covered_components).unwrap();
223 signature_params.set_key_info(&secret_key);
225 req.set_message_signature_sync(&signature_params, &secret_key, None).unwrap();
227 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
228 let verification_res = req.verify_message_signature_sync(&public_key, None);
229 assert!(verification_res.is_ok());
230 }
231
232 #[cfg(feature = "blocking")]
233 #[test]
234 fn test_set_verify_response_sync() {
235 let req = futures::executor::block_on(build_request());
237 let mut res = futures::executor::block_on(build_response());
238 let secret_key = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
239 let covered_components = COVERED_COMPONENTS_RES
240 .iter()
241 .map(|v| message_component::HttpMessageComponentId::try_from(*v))
242 .collect::<Result<Vec<_>, _>>()
243 .unwrap();
244 let mut signature_params = HttpSignatureParams::try_new(&covered_components).unwrap();
245 signature_params.set_key_info(&secret_key);
247 res
249 .set_message_signature_sync(&signature_params, &secret_key, None, Some(&req))
250 .unwrap();
251 let public_key = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
252 let verification_res = res.verify_message_signature_sync(&public_key, None, Some(&req));
253 assert!(verification_res.is_ok());
254 }
255}