1313// You should have received a copy of the GNU General Public License
1414// along with HTTP Signatures If not, see <http://www.gnu.org/licenses/>.
1515
16+ //! This module defines types and traits for creating HTTP Signatures.
17+
1618use std:: collections:: HashMap ;
1719use std:: convert:: { TryFrom , TryInto } ;
1820use std:: sync:: Arc ;
@@ -23,33 +25,37 @@ use base64::encode;
2325use untrusted:: Input ;
2426
2527use super :: { SignatureAlgorithm , ShaSize } ;
26- use error:: Error ;
28+ use error:: { Error , CreationError } ;
2729
30+ /// `AsHttpSignature` defines a trait for getting an Authorization Header string from any type that
31+ /// implements it. It provides two methods: as_http_signature, which implementors must define, and
32+ /// authorization_header, which uses as_http_signature to create the header string.
2833pub trait AsHttpSignature < T >
2934where
3035 T : Read ,
3136{
37+ /// Gets an `HttpSignature` struct from an immutably borrowed Self
3238 fn as_http_signature (
3339 & self ,
3440 key_id : String ,
3541 key : T ,
3642 algorithm : SignatureAlgorithm ,
3743 ) -> Result < HttpSignature < T > , Error > ;
3844
45+ /// Generates the Authorization Header from an immutably borrowed Self
3946 fn authorization_header (
4047 & self ,
4148 key_id : String ,
4249 key : T ,
4350 algorithm : SignatureAlgorithm ,
4451 ) -> Result < String , Error > {
45- let signing_string: SigningString < T > = self . as_http_signature ( key_id, key, algorithm) ?
46- . into ( ) ;
47- let signature: Signature = signing_string. try_into ( ) ?;
48-
49- Ok ( signature. authorization ( ) )
52+ Ok ( self . as_http_signature ( key_id, key, algorithm) ?
53+ . authorization_header ( ) ?)
5054 }
5155}
5256
57+ /// `WithHttpSignature` defines a trait for adding an Authorization header to another library's
58+ /// request or response object.
5359pub trait WithHttpSignature < T > : AsHttpSignature < T >
5460where
5561 T : Read ,
@@ -62,22 +68,58 @@ where
6268 ) -> Result < & mut Self , Error > ;
6369}
6470
65- pub struct HttpSignature < T > {
71+ /// The `HttpSignature` struct, this is the entry point for creating an Authorization header. It
72+ /// contains all the values required for generation.
73+ pub struct HttpSignature < T >
74+ where
75+ T : Read ,
76+ {
77+ /// The keyId field in the Authorization header
6678 key_id : String ,
79+ /// The key (implementing `Read`) used to sign the request
6780 key : T ,
81+ /// The algorithm used to sign the request
6882 algorithm : SignatureAlgorithm ,
83+ /// The headers that will be included in the signature
6984 headers : HashMap < String , Vec < String > > ,
7085}
7186
72- impl < T > HttpSignature < T > {
87+ impl < T > HttpSignature < T >
88+ where
89+ T : Read ,
90+ {
91+ /// Create a new HttpSignature from its components.
92+ ///
93+ /// This method will Error if `headers` is empty.
94+ ///
95+ /// ### Example
96+ /// ```rust
97+ /// # use std::fs::File;
98+ /// # use std::collections::HashMap;
99+ /// # use http_signatures::Error;
100+ /// use http_signatures::{HttpSignature, SignatureAlgorithm, ShaSize, REQUEST_TARGET};
101+ ///
102+ /// # fn run() -> Result<(), Error> {
103+ /// let key_id = "test/assets/public.der".into();
104+ /// let priv_key = File::open("test/assets/private.der")?;
105+ ///
106+ /// let alg = SignatureAlgorithm::RSA(ShaSize::FiveTwelve);
107+ ///
108+ /// let mut headers = HashMap::new();
109+ /// headers.insert(REQUEST_TARGET.into(), vec!["get /".into()]);
110+ ///
111+ /// let http_sig = HttpSignature::new(key_id, priv_key, alg, headers)?;
112+ /// # Ok(())
113+ /// # }
114+ /// ```
73115 pub fn new (
74116 key_id : String ,
75117 key : T ,
76118 algorithm : SignatureAlgorithm ,
77119 headers : HashMap < String , Vec < String > > ,
78- ) -> Result < Self , Error > {
120+ ) -> Result < Self , CreationError > {
79121 if headers. is_empty ( ) {
80- return Err ( Error :: NoHeaders ) ;
122+ return Err ( CreationError :: NoHeaders ) ;
81123 }
82124
83125 Ok ( HttpSignature {
@@ -99,17 +141,76 @@ impl<T> HttpSignature<T> {
99141 pub fn headers ( & self ) -> & HashMap < String , Vec < String > > {
100142 & self . headers
101143 }
144+
145+ /// Generate the Authorization Header from the `HttpSignature`
146+ ///
147+ /// This method errors if signing the signing-string fails.
148+ ///
149+ /// ### Example
150+ /// ```rust
151+ /// # use std::fs::File;
152+ /// # use std::collections::HashMap;
153+ /// # use http_signatures::{Error, SignatureAlgorithm, ShaSize, REQUEST_TARGET};
154+ /// use http_signatures::HttpSignature;
155+ /// # fn run() -> Result<(), Error> {
156+ /// # let key_id = "test/assets/public.der".into();
157+ /// # let priv_key = File::open("test/assets/private.der")?;
158+ /// # let alg = SignatureAlgorithm::RSA(ShaSize::FiveTwelve);
159+ /// # let mut headers = HashMap::new();
160+ /// # headers.insert(REQUEST_TARGET.into(), vec!["get /".into()]);
161+ /// # let http_signature = HttpSignature::new(key_id, priv_key, alg, headers)?;
162+ ///
163+ /// let auth_header = http_signature.authorization_header()?;
164+ /// # Ok(())
165+ /// # }
166+ /// ```
167+ pub fn authorization_header ( self ) -> Result < String , CreationError > {
168+ let signing_string: SigningString < T > = self . into ( ) ;
169+ let signature: Signature = signing_string. try_into ( ) ?;
170+
171+ Ok ( signature. authorization ( ) )
172+ }
102173}
103174
175+ /// A default implementation of `AsHttpSignature` for `HttpSignature`.
176+ ///
177+ /// This only works if type `T` is `Clone` in addition to `Read`, which is normally required. This
178+ /// implementation doesn't serve much of a purpose.
179+ impl < T > AsHttpSignature < T > for HttpSignature < T >
180+ where
181+ T : Read + Clone ,
182+ {
183+ fn as_http_signature ( & self , _: String , _: T , _: SignatureAlgorithm ) -> Result < Self , Error > {
184+ Ok ( HttpSignature {
185+ key_id : self . key_id . clone ( ) ,
186+ key : self . key . clone ( ) ,
187+ algorithm : self . algorithm . clone ( ) ,
188+ headers : self . headers . clone ( ) ,
189+ } )
190+ }
191+ }
192+
193+ /// The `SigningString<T>` struct uses what was given in the `HttpSignature` struct, but also has a
194+ /// plaintext field called `signing_string` which holds the string used to sign the request.
195+ ///
196+ /// Since `From<HttpSignature<T>>` was implemented for `SigningString<T>`, the transition is as
197+ /// simple as calling `http_signature.into()`.
198+ ///
199+ /// This struct does not have public fields, and does not have a constructor since it should only
200+ /// be used as an intermediate point from `HttpSignature<T>` to the signed string.
104201pub struct SigningString < T > {
105202 key_id : String ,
106203 key : T ,
107204 headers : Vec < String > ,
108205 algorithm : SignatureAlgorithm ,
206+ // The plaintext string used to sign the request
109207 signing_string : String ,
110208}
111209
112- impl < T > From < HttpSignature < T > > for SigningString < T > {
210+ impl < T > From < HttpSignature < T > > for SigningString < T >
211+ where
212+ T : Read ,
213+ {
113214 fn from ( http_signature : HttpSignature < T > ) -> Self {
114215 let ( header_keys, signing_vec) : ( Vec < _ > , Vec < _ > ) = http_signature
115216 . headers
@@ -132,6 +233,11 @@ impl<T> From<HttpSignature<T>> for SigningString<T> {
132233 }
133234}
134235
236+ /// `Signature` is the result of using the `key: T` of `SigningString<T>` to sign the
237+ /// `signing_string`.
238+ ///
239+ /// To get the Authorization Header String from the Signature, the `authorization` method is
240+ /// provided.
135241pub struct Signature {
136242 sig : String ,
137243 key_id : String ,
@@ -140,6 +246,7 @@ pub struct Signature {
140246}
141247
142248impl Signature {
249+ /// Get the Authorization Header String.
143250 pub fn authorization ( self ) -> String {
144251 let alg: & str = self . algorithm . into ( ) ;
145252
@@ -151,7 +258,7 @@ impl Signature {
151258 )
152259 }
153260
154- fn rsa < T > ( mut key : T , size : & ShaSize , signing_string : & [ u8 ] ) -> Result < String , Error >
261+ fn rsa < T > ( mut key : T , size : & ShaSize , signing_string : & [ u8 ] ) -> Result < String , CreationError >
155262 where
156263 T : Read ,
157264 {
@@ -161,14 +268,14 @@ impl Signature {
161268
162269 let key_pair = signature:: RSAKeyPair :: from_der ( private_key_der) . map_err (
163270 |_| {
164- Error :: BadPrivateKey
271+ CreationError :: BadPrivateKey
165272 } ,
166273 ) ?;
167274 let key_pair = Arc :: new ( key_pair) ;
168275
169- let mut signing_state = signature:: RSASigningState :: new ( key_pair) . map_err (
170- |_| Error :: Unknown ,
171- ) ?;
276+ let mut signing_state = signature:: RSASigningState :: new ( key_pair) . map_err ( |_| {
277+ CreationError :: SigningError
278+ } ) ?;
172279
173280 let rng = rand:: SystemRandom :: new ( ) ;
174281 let mut signature = vec ! [ 0 ; signing_state. key_pair( ) . public_modulus_len( ) ] ;
@@ -183,12 +290,12 @@ impl Signature {
183290 signing_string,
184291 signature. as_mut_slice ( ) ,
185292 )
186- . map_err ( |_| Error :: SigningError ) ?;
293+ . map_err ( |_| CreationError :: SigningError ) ?;
187294
188295 Ok ( encode ( signature. as_slice ( ) ) )
189296 }
190297
191- fn hmac < T > ( mut key : T , size : & ShaSize , signing_string : & [ u8 ] ) -> Result < String , Error >
298+ fn hmac < T > ( mut key : T , size : & ShaSize , signing_string : & [ u8 ] ) -> Result < String , CreationError >
192299 where
193300 T : Read ,
194301 {
@@ -212,8 +319,10 @@ impl<T> TryFrom<SigningString<T>> for Signature
212319where
213320 T : Read ,
214321{
215- type Error = Error ;
322+ type Error = CreationError ;
216323
324+ /// Attempt to sign the signing_string. If signing fails, a `Signature` will not be created and
325+ /// an `Error` will be returned.
217326 fn try_from ( signing_string : SigningString < T > ) -> Result < Self , Self :: Error > {
218327 Ok ( match signing_string. algorithm {
219328 SignatureAlgorithm :: RSA ( size) => {
0 commit comments