Skip to content

Commit

Permalink
Comment and naming updates.
Browse files Browse the repository at this point in the history
  • Loading branch information
EkardNT committed Apr 6, 2021
1 parent e1163ff commit b92f79f
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 55 deletions.
4 changes: 2 additions & 2 deletions examples/basic_sign.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ use std::collections::HashMap;

use bytes::BytesMut;
use http_sign::*;
use http_sign::message::{BorrowedHttpMessage, Method};
use http_sign::message::{BorrowedHttpRequest, Method};
use ring::{rand::SystemRandom, signature::RsaKeyPair};

static KEY: &'static [u8] = include_bytes!("example-rsa-2048-key.pk8");

fn main() {
let mut headers = HashMap::new();
headers.insert("x-foo".to_string(), "bar".to_string());
let mut request = http_sign::message::OwnedHttpMessage::new(
let mut request = http_sign::message::OwnedHttpRequest::new(
Method::Get,
"/foo/bar".to_string(),
Some("foo=bar".to_string()),
Expand Down
20 changes: 17 additions & 3 deletions src/algorithm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,15 @@ pub trait SignatureAlgorithm {
pub mod hs {
use std::io::Write;

use ring::{hmac::Key, rand::SecureRandom, signature::{RsaEncoding, RsaKeyPair}};
use ring::{hmac::Key, rand::SecureRandom, signature::RsaKeyPair};

use super::SignatureAlgorithm;

/// The "hs2019" [signature algorithm](super::SignatureAlgorithm). This is the only
/// non-deprecated algorithm. Unlike the other algorithms, the hash and digest
/// functions are not implied by the choice of this signature algorithm. Instead, the
/// hash and digest functions are chosen based on the key used. RSA, HMAC, and ECDSA
/// keys are all supported.
pub struct Hs2019<Rand>(Inner<Rand>);

enum Inner<Rand> {
Expand Down Expand Up @@ -118,6 +123,7 @@ pub mod hs {
}
}

#[allow(deprecated)]
pub mod rsa {
use std::fmt::Debug;
use std::io::Write;
Expand All @@ -126,6 +132,8 @@ pub mod rsa {

use super::SignatureAlgorithm;

/// The "rsa-sha256" [signature algorithm](super::SignatureAlgorithm). Deprecated by
/// the standard because it reveals which hash and digest algorithm is used.
#[deprecated]
pub struct RsaSha256<Rand> {
key_id: String,
Expand Down Expand Up @@ -176,14 +184,17 @@ pub mod rsa {
}
}

#[allow(deprecated)]
pub mod hmac {
use std::fmt::Debug;
use std::io::Write;

use ring::{rand::SecureRandom, hmac::Key};
use ring::hmac::Key;

use super::SignatureAlgorithm;

/// The "hmac-sha256" [signature algorithm](super::SignatureAlgorithm). Deprecated by
/// the standard because it reveals which hash and digest algorithm is used.
#[deprecated]
pub struct HmacSha256 {
key_id: String,
Expand All @@ -204,7 +215,7 @@ pub mod hmac {

impl SignatureAlgorithm for HmacSha256 {
fn name(&self) -> &str {
"rsa-sha256"
"hmac-sha256"
}

fn key_id(&self) -> &str {
Expand All @@ -231,6 +242,7 @@ pub mod hmac {
}
}

#[allow(deprecated)]
pub mod ecdsa {
use std::fmt::Debug;
use std::io::Write;
Expand All @@ -239,6 +251,8 @@ pub mod ecdsa {

use super::SignatureAlgorithm;

/// The "ecdsa-sha256" [signature algorithm](super::SignatureAlgorithm). Deprecated by
/// the standard because it reveals which hash and digest algorithm is used.
#[deprecated]
pub struct EcdsaSha256<Rand> {
key_id: String,
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod algorithm;
pub mod message;
mod signature;

#[allow(deprecated)]
pub use algorithm::{
SignatureAlgorithm,
hs::Hs2019,
Expand Down
75 changes: 37 additions & 38 deletions src/message.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
/// This trait exposes all of the information about a HTTP message that is required to
/// produce the signature header. This trait can represent both HTTP requests and
/// responses.
/// This trait exposes all of the information about a HTTP request that is required to
/// produce the signature header.
///
/// The [OwnedHttpMessage] and [BorrowedHttpMessage] types are provided for simple use
/// cases where you do not have preexisting structs representing HTTP requests and responses
/// that you can use. In addition to those two convenience types, support for other common
/// community crates can be enabled by turning on the following **features**, all of which are
/// off by default.
/// The [OwnedHttpRequest] and [BorrowedHttpRequest] types are provided for simple use
/// cases where you do not have preexisting structs representing HTTP requests that you
/// can use. In addition to those two convenience types, support for other common
/// community crates can be enabled by turning on the following **features**, all of which
/// are off by default.
/// - `http`: Enables support for the [http](https://crates.io/crates/http) crate's
/// Request and HeaderMap types.
pub trait HttpMessage {
pub trait HttpRequest {
/// The type of HTTP headers object.
type Headers: Headers;

/// Returns a shared reference to the HTTP message headers.
/// Returns a shared reference to the HTTP request headers.
fn headers(&self) -> &Self::Headers;

/// Returns a unique reference to the HTTP message headers. This is used by the
/// Returns a unique reference to the HTTP request headers. This is used by the
/// [sign](super::sign) function to insert the signature header according to the
/// chosen [algorithm](super::SignatureAlgorithm).
fn headers_mut(&mut self) -> &mut Self::Headers;
Expand All @@ -30,24 +29,24 @@ pub trait HttpMessage {
/// The HTTP method.
fn method(&self) -> Method;

/// The body data. If the message does not contain a body, this function should return
/// The body data. If the request does not contain a body, this function should return
/// a 0-length slice.
fn body(&self) -> &[u8];
}

/// This is a simple implementation of [HttpMessage] that does not depend on any external
/// library. It owns all of the message data.
/// This is a simple implementation of [HttpRequest] that does not depend on any external
/// library. It owns all of the request data.
#[derive(Debug)]
pub struct OwnedHttpMessage<H> {
pub struct OwnedHttpRequest<H> {
headers: H,
path: String,
query_string: Option<String>,
method: Method,
body: Vec<u8>
}

impl<H> OwnedHttpMessage<H> {
/// Build a new [OwnedHttpMessage] from owned components.
impl<H> OwnedHttpRequest<H> {
/// Build a new [OwnedHttpRequest] from owned components.
pub fn new(
method: Method,
path: String,
Expand All @@ -64,7 +63,7 @@ impl<H> OwnedHttpMessage<H> {
}
}

impl<H: Headers> HttpMessage for OwnedHttpMessage<H> {
impl<H: Headers> HttpRequest for OwnedHttpRequest<H> {
type Headers = H;

fn headers(&self) -> &Self::Headers {
Expand Down Expand Up @@ -93,24 +92,24 @@ impl<H: Headers> HttpMessage for OwnedHttpMessage<H> {
}


/// This is a simple implementation of [HttpMessage] that does not depend on any external
/// library. It borrows all of the message data.
pub struct BorrowedHttpMessage<'message, H> {
headers: &'message mut H,
path: &'message str,
query_string: Option<&'message str>,
/// This is a simple implementation of [HttpRequest] that does not depend on any external
/// library. It borrows all of the request data.
pub struct BorrowedHttpRequest<'request, H> {
headers: &'request mut H,
path: &'request str,
query_string: Option<&'request str>,
method: Method,
body: &'message [u8]
body: &'request [u8]
}

impl<'message, H> BorrowedHttpMessage<'message, H> {
/// Build a new [BorrowedHttpMessage] from borrowed components.
impl<'request, H> BorrowedHttpRequest<'request, H> {
/// Build a new [BorrowedHttpRequest] from borrowed components.
pub fn new(
method: Method,
path: &'message str,
query_string: Option<&'message str>,
headers: &'message mut H,
body: &'message [u8]) -> Self {
path: &'request str,
query_string: Option<&'request str>,
headers: &'request mut H,
body: &'request [u8]) -> Self {
Self {
headers,
path,
Expand All @@ -121,7 +120,7 @@ impl<'message, H> BorrowedHttpMessage<'message, H> {
}
}

impl<'message, H: Headers> HttpMessage for BorrowedHttpMessage<'message, H> {
impl<'request, H: Headers> HttpRequest for BorrowedHttpRequest<'request, H> {
type Headers = H;

fn headers(&self) -> &Self::Headers {
Expand Down Expand Up @@ -181,7 +180,7 @@ impl Method {
}

/// This trait allows the signature generation logic both read and write access to the
/// HTTP headers contained within a [HTTP message](HttpMessage).
/// HTTP headers contained within a [HTTP request](HttpRequest).
pub trait Headers {
/// Iterator over header names. This library can only work with header names that are
/// valid UTF-8 (and by extension, all ASCII-only headers).
Expand All @@ -190,10 +189,10 @@ pub trait Headers {
/// strings in any encoding.
type ValueIter<'a> : Iterator<Item = &'a [u8]>;

/// Returns an iterator over all the header names defined for the HTTP message.
/// Returns an iterator over all the header names defined for the HTTP request.
fn header_names<'this>(&'this self) -> Self::NameIter<'this>;

/// Returns true if the HTTP message contains a header with the given `name`, or false
/// Returns true if the HTTP request contains a header with the given `name`, or false
/// if no such header is present. It is up to the implementor of this trait whether
/// header names are case sensitive.
fn contains_header(&self, name: &str) -> bool;
Expand Down Expand Up @@ -309,16 +308,16 @@ mod btree_map {
}

/// Adds support for using types from the [http](https://crates.io/crates/http) crate
/// as implementations of [HttpMessage] and [Headers].
/// as implementations of [HttpRequest] and [Headers].
///
/// Requires the `http` feature to be enabled.
#[cfg(feature = "http")]
mod http {
use http::{HeaderMap, HeaderValue, header::HeaderName};

use super::{HttpMessage, Method};
use super::{HttpRequest, Method};

impl<Body: AsRef<[u8]>> HttpMessage for ::http::Request<Body> {
impl<Body: AsRef<[u8]>> HttpRequest for ::http::Request<Body> {
type Headers = ::http::HeaderMap;

fn headers(&self) -> &Self::Headers {
Expand Down
22 changes: 10 additions & 12 deletions src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ use std::time::SystemTime;

use bytes::{BufMut, BytesMut};

use crate::{algorithm::SignatureAlgorithm, message::{Headers, HttpMessage}};
use crate::{algorithm::SignatureAlgorithm, message::{Headers, HttpRequest}};

/// An element that contributes to the signature calculation. Standard HTTP headers may
/// be included in the signature, as well as special non-header fields such as
/// `(request-target)`, `(created)`, and `(expires)`. The list of signature elements
/// determines which parts of the HTTP message are protected by the signature. The order
/// of signature elements that is chosen is also important in that it determines the
/// order in which the signature input string is formed.
/// passed to the [sign] function determines which parts of the HTTP message are protected
/// by the signature. The order of signature elements that is chosen is also important in
/// that it determines the order in which the signature input string is formed.
#[derive(Debug, Eq, PartialEq)]
pub enum SignatureElement<'a> {
/// The `(request-target)` special field. Results in the concatenation of the lowercase
Expand Down Expand Up @@ -95,7 +95,7 @@ pub fn sign<'sig_elems, SigAlg, Msg>(
) -> Result<(), SignError>
where
SigAlg: SignatureAlgorithm,
Msg: HttpMessage,
Msg: HttpRequest,
{
validate_signature_elements(sig_alg, message, signature_elements)?;
let now = SystemTime::now();
Expand All @@ -106,7 +106,7 @@ pub fn sign<'sig_elems, SigAlg, Msg>(
.map_err(|_err| SignError::Internal("Unable to determine (expires) Unix timestamp"))?
.as_secs();
let signature_input = build_canonical_signature_input(
temporary_buffer, sig_alg, message, created, expires, signature_elements)?;
temporary_buffer, message, created, expires, signature_elements)?;
let encoded_signature = get_encoded_signature(temporary_buffer, sig_alg, signature_input)?;
let signature_header = build_final_header(temporary_buffer, scheme, sig_alg, encoded_signature, created, expires, signature_elements)?;
match scheme {
Expand All @@ -116,7 +116,7 @@ pub fn sign<'sig_elems, SigAlg, Msg>(
Ok(())
}

fn validate_signature_elements<SigAlg: SignatureAlgorithm, Msg: HttpMessage>(
fn validate_signature_elements<SigAlg: SignatureAlgorithm, Msg: HttpRequest>(
sig_alg: &SigAlg,
message: &mut Msg,
signature_elements: &[SignatureElement<'_>],
Expand Down Expand Up @@ -158,17 +158,15 @@ fn validate_signature_elements<SigAlg: SignatureAlgorithm, Msg: HttpMessage>(
Ok(())
}

fn build_canonical_signature_input<'sig_elems, SigAlg, Msg>(
fn build_canonical_signature_input<'sig_elems, Msg>(
temporary_buffer: &mut BytesMut,
sig_alg: &SigAlg,
message: &mut Msg,
created: u64,
expires: u64,
signature_elements: &[SignatureElement<'_>],
) -> Result<BytesMut, SignError>
where
SigAlg: SignatureAlgorithm,
Msg: HttpMessage,
Msg: HttpRequest,
{
temporary_buffer.clear();
for element in signature_elements {
Expand Down Expand Up @@ -223,7 +221,7 @@ fn build_canonical_signature_input<'sig_elems, SigAlg, Msg>(
fn get_encoded_signature<SigAlg: SignatureAlgorithm>(
temporary_buffer: &mut BytesMut,
sig_alg: &SigAlg,
mut signature_input: BytesMut,
signature_input: BytesMut,
) -> Result<BytesMut, SignError> {
temporary_buffer.clear();
sig_alg.sign(&signature_input, &mut temporary_buffer.writer())
Expand Down

0 comments on commit b92f79f

Please sign in to comment.