1mod crypto;
9mod error;
10mod message_component;
11mod signature_base;
12mod signature_params;
13mod trace;
14mod util;
15
16pub mod prelude {
17 pub mod message_component {
18 pub use crate::message_component::{
19 DerivedComponentName, HttpMessageComponent, HttpMessageComponentId, HttpMessageComponentName, HttpMessageComponentParam,
20 };
21 }
22
23 pub use crate::{
24 crypto::{AlgorithmName, PublicKey, SecretKey, SharedKey, SigningKey, VerifyingKey},
25 error::{HttpSigError, HttpSigResult},
26 signature_base::{HttpSignature, HttpSignatureBase, HttpSignatureHeaders, HttpSignatureHeadersMap},
27 signature_params::HttpSignatureParams,
28 };
29}
30
31#[cfg(test)]
33mod tests {
34 use super::prelude::*;
35 use base64::{engine::general_purpose, Engine as _};
36
37 const EDDSA_SECRET_KEY: &str = r##"-----BEGIN PRIVATE KEY-----
40MC4CAQAwBQYDK2VwBCIEIJ+DYvh6SEqVTm50DFtMDoQikTmiCqirVv9mWG9qfSnF
41-----END PRIVATE KEY-----
42"##;
43 const EDDSA_PUBLIC_KEY: &str = r##"-----BEGIN PUBLIC KEY-----
44MCowBQYDK2VwAyEAJrQLj5P/89iXES9+vFgrIy29clF9CC/oPPsw3c5D0bs=
45-----END PUBLIC KEY-----
46"##;
47 const EDDSA_SIGNATURE_BASE: &str = r##""date": Tue, 20 Apr 2021 02:07:55 GMT
48"@method": POST
49"@path": /foo
50"@authority": example.com
51"content-type": application/json
52"content-length": 18
53"@signature-params": ("date" "@method" "@path" "@authority" "content-type" "content-length");created=1618884473;keyid="test-key-ed25519""##;
54 const EDDSA_SIGNATURE_VALUE: &str = "wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==";
55 const _EDDSA_SIGNATURE_RESULT: &str = r##"Signature-Input: sig-b26=("date" "@method" "@path" "@authority" "content-type" "content-length");created=1618884473;keyid="test-key-ed25519"
56Signature: sig-b26=:wqcAqbmYJ2ji2glfAMaRy4gruYYnx2nEFN2HN6jrnDnQCK1u02Gb04v9EDgwUPiu4A0w6vuQv5lIp5WPpBKRCw==:"##;
57
58 #[test]
59 fn test_using_test_vector_ed25519() {
60 let sk = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
61 let pk = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
62 assert_eq!(pk.key_id(), sk.public_key().key_id());
63
64 let data = EDDSA_SIGNATURE_BASE.as_bytes();
65 let binary_signature = general_purpose::STANDARD.decode(EDDSA_SIGNATURE_VALUE).unwrap();
66 let verification_result = pk.verify(data, &binary_signature);
67 assert!(verification_result.is_ok());
68
69 let signature = sk.sign(EDDSA_SIGNATURE_BASE.as_bytes()).unwrap();
70 let signature_value = general_purpose::STANDARD.encode(signature);
71 let signature_bytes = general_purpose::STANDARD.decode(signature_value).unwrap();
73 let verification_result = pk.verify(EDDSA_SIGNATURE_BASE.as_bytes(), &signature_bytes);
74 assert!(verification_result.is_ok());
75 }
76
77 const HMACSHA256_SECRET_KEY: &str =
80 r##"uzvJfB4u3N0Jy4T7NZ75MDVcr8zSTInedJtkgcu46YW4XByzNJjxBdtjUkdJPBtbmHhIDi6pcl8jsasjlTMtDQ=="##;
81 const HMACSHA256_SIGNATURE_BASE: &str = r##""date": Tue, 20 Apr 2021 02:07:55 GMT
82"@authority": example.com
83"content-type": application/json
84"@signature-params": ("date" "@authority" "content-type");created=1618884473;keyid="test-shared-secret""##;
85 const HMACSHA256_SIGNATURE_VALUE: &str = r##"pxcQw6G3AjtMBQjwo8XzkZf/bws5LelbaMk5rGIGtE8="##;
86
87 #[test]
88 fn test_using_test_vector_hmac_sha256() {
89 let sk = SharedKey::from_base64(HMACSHA256_SECRET_KEY).unwrap();
90
91 let data = HMACSHA256_SIGNATURE_BASE.as_bytes();
92 let binary_signature = general_purpose::STANDARD.decode(HMACSHA256_SIGNATURE_VALUE).unwrap();
93 let verification_result = sk.verify(data, &binary_signature);
94 assert!(verification_result.is_ok());
95
96 let signature = sk.sign(HMACSHA256_SIGNATURE_BASE.as_bytes()).unwrap();
97 let signature_value = general_purpose::STANDARD.encode(signature);
98 assert_eq!(signature_value, HMACSHA256_SIGNATURE_VALUE.to_string());
99
100 let signature_bytes = general_purpose::STANDARD.decode(signature_value).unwrap();
101 let verification_result = sk.verify(HMACSHA256_SIGNATURE_BASE.as_bytes(), &signature_bytes);
102 assert!(verification_result.is_ok());
103 }
104
105 const COMPONENT_LINES: &[&str] = &[
107 r##""date": Tue, 20 Apr 2021 02:07:55 GMT"##,
108 r##""@method": POST"##,
109 r##""@path": /foo"##,
110 r##""@authority": example.com"##,
111 r##""content-type": application/json"##,
112 r##""content-length": 18"##,
113 ];
114 const SIGNATURE_PARAMS: &str =
115 r##"("date" "@method" "@path" "@authority" "content-type" "content-length");created=1618884473;keyid="test-key-ed25519""##;
116
117 #[test]
118 fn test_with_directly_using_crypto_api() {
119 let signature_params = HttpSignatureParams::try_from(SIGNATURE_PARAMS).unwrap();
120 let component_lines = COMPONENT_LINES
121 .iter()
122 .map(|&line| message_component::HttpMessageComponent::try_from(line).unwrap())
123 .collect::<Vec<_>>();
124
125 let signature_base = HttpSignatureBase::try_new(&component_lines, &signature_params).unwrap();
126 let sk = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
127 let pk = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
128
129 let signature_bytes = sk.sign(&signature_base.as_bytes()).unwrap();
130 let verification_result = pk.verify(&signature_base.as_bytes(), &signature_bytes);
131 assert!(verification_result.is_ok());
132 }
133
134 #[test]
135 fn test_with_build_signature_api() {
136 let component_lines = COMPONENT_LINES
137 .iter()
138 .map(|&line| message_component::HttpMessageComponent::try_from(line).unwrap())
139 .collect::<Vec<_>>();
140
141 let signature_params = HttpSignatureParams::try_from(SIGNATURE_PARAMS).unwrap();
143 let signature_base = HttpSignatureBase::try_new(&component_lines, &signature_params).unwrap();
144 let sk = SecretKey::from_pem(EDDSA_SECRET_KEY).unwrap();
145 let signature_headers = signature_base.build_signature_headers(&sk, Some("sig-b26")).unwrap();
146 let signature_params_header_string = signature_headers.signature_input_header_value();
147 let signature_header_string = signature_headers.signature_header_value();
148
149 assert_eq!(signature_params_header_string, format!("sig-b26={}", SIGNATURE_PARAMS));
150 assert!(signature_header_string.starts_with("sig-b26=:") && signature_header_string.ends_with(':'));
151
152 let header_map = HttpSignatureHeaders::try_parse(&signature_header_string, &signature_params_header_string).unwrap();
154 let received_signature_headers = header_map.get("sig-b26").unwrap();
155 let received_signature_base =
156 HttpSignatureBase::try_new(&component_lines, received_signature_headers.signature_params()).unwrap();
157 let pk = PublicKey::from_pem(EDDSA_PUBLIC_KEY).unwrap();
158 let verification_result = received_signature_base.verify_signature_headers(&pk, received_signature_headers);
159 assert!(verification_result.is_ok());
160 }
161}