diff --git a/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs b/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs index c310c51460..b944c69076 100644 --- a/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs +++ b/aws/rust-runtime/aws-credential-types/src/credentials_impl.rs @@ -140,9 +140,21 @@ impl Credentials { ) } - /// Creates a test `Credentials`. + /// Creates a test `Credentials` without a session token. #[cfg(feature = "test-util")] pub fn for_tests() -> Self { + Self::new( + "ANOTREAL", + "notrealrnrELgWzOk3IfjzDKtFBhDby", + None, + None, + "test", + ) + } + + /// Creates a test `Credentials` with a session token. + #[cfg(feature = "test-util")] + pub fn for_tests_with_session_token() -> Self { Self::new( "ANOTREAL", "notrealrnrELgWzOk3IfjzDKtFBhDby", diff --git a/aws/rust-runtime/aws-endpoint/src/lib.rs b/aws/rust-runtime/aws-endpoint/src/lib.rs index 8003d7c4aa..750856fb8c 100644 --- a/aws/rust-runtime/aws-endpoint/src/lib.rs +++ b/aws/rust-runtime/aws-endpoint/src/lib.rs @@ -14,13 +14,13 @@ use aws_smithy_types::endpoint::Endpoint as SmithyEndpoint; use aws_smithy_types::Document; use aws_types::region::{Region, SigningRegion}; -use aws_types::SigningService; +use aws_types::SigningName; /// Middleware Stage to add authentication information from a Smithy endpoint into the property bag /// /// AwsAuthStage implements [`MapRequest`](MapRequest). It will: /// 1. Load an endpoint from the property bag -/// 2. Set the `SigningRegion` and `SigningService` in the property bag to drive downstream +/// 2. Set the `SigningRegion` and `SigningName` in the property bag to drive downstream /// signing middleware. #[derive(Clone, Debug)] pub struct AwsAuthStage; @@ -74,21 +74,21 @@ impl MapRequest for AwsAuthStage { let endpoint = props .get::() .ok_or(AwsAuthStageErrorKind::NoEndpointResolver)?; - let (signing_scope_override, signing_service_override) = smithy_to_aws(endpoint) + let (signing_region_override, signing_name_override) = smithy_to_aws(endpoint) .map_err(|err| AwsAuthStageErrorKind::EndpointResolutionError(err))?; - if let Some(signing_scope) = signing_scope_override { + if let Some(signing_scope) = signing_region_override { props.insert(signing_scope); } - if let Some(signing_service) = signing_service_override { - props.insert(signing_service); + if let Some(signing_name) = signing_name_override { + props.insert(signing_name); } Ok(http_req) }) } } -type EndpointMetadata = (Option, Option); +type EndpointMetadata = (Option, Option); fn smithy_to_aws(value: &SmithyEndpoint) -> Result> { // look for v4 as an auth scheme @@ -122,17 +122,17 @@ fn smithy_to_aws(value: &SmithyEndpoint) -> Result Some(SigningRegion::from(Region::new(s.clone()))), None => None, _ => return Err("unexpected type".into()), }; - let signing_service = match v4.get("signingName") { - Some(Document::String(s)) => Some(SigningService::from(s.to_string())), + let signing_name = match v4.get("signingName") { + Some(Document::String(s)) => Some(SigningName::from(s.to_string())), None => None, _ => return Err("unexpected type".into()), }; - Ok((signing_scope, signing_service)) + Ok((signing_region, signing_name)) } #[cfg(test)] @@ -147,7 +147,7 @@ mod test { use http::header::HOST; use aws_types::region::{Region, SigningRegion}; - use aws_types::SigningService; + use aws_types::SigningName; use crate::AwsAuthStage; @@ -162,14 +162,14 @@ mod test { { let mut props = req.properties_mut(); props.insert(SigningRegion::from(region.clone())); - props.insert(SigningService::from_static("kinesis")); + props.insert(SigningName::from_static("kinesis")); props.insert(endpoint); }; let req = AwsAuthStage.apply(req).expect("should succeed"); assert_eq!(req.properties().get(), Some(&SigningRegion::from(region))); assert_eq!( req.properties().get(), - Some(&SigningService::from_static("kinesis")) + Some(&SigningName::from_static("kinesis")) ); assert!(req.http().headers().get(HOST).is_none()); @@ -206,7 +206,7 @@ mod test { { let mut props = req.properties_mut(); props.insert(region); - props.insert(SigningService::from_static("qldb")); + props.insert(SigningName::from_static("qldb")); props.insert(endpoint); }; let req = AwsAuthStage.apply(req).expect("should succeed"); @@ -216,7 +216,7 @@ mod test { ); assert_eq!( req.properties().get(), - Some(&SigningService::from_static("qldb-override")) + Some(&SigningName::from_static("qldb-override")) ); } @@ -229,14 +229,14 @@ mod test { { let mut props = req.properties_mut(); props.insert(region.clone()); - props.insert(SigningService::from_static("qldb")); + props.insert(SigningName::from_static("qldb")); props.insert(endpoint); }; let req = AwsAuthStage.apply(req).expect("should succeed"); assert_eq!(req.properties().get(), Some(®ion)); assert_eq!( req.properties().get(), - Some(&SigningService::from_static("qldb")) + Some(&SigningName::from_static("qldb")) ); } } diff --git a/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs b/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs index 53500eae50..80cac6842d 100644 --- a/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs +++ b/aws/rust-runtime/aws-inlineable/src/glacier_interceptors.rs @@ -6,7 +6,7 @@ // This code is referenced in generated code, so the compiler doesn't realize it is used. #![allow(dead_code)] -use aws_runtime::auth::sigv4::SigV4OperationSigningConfig; +use aws_runtime::auth::SigV4OperationSigningConfig; use aws_sigv4::http_request::SignableBody; use aws_smithy_http::body::SdkBody; use aws_smithy_http::byte_stream; diff --git a/aws/rust-runtime/aws-inlineable/src/http_request_checksum.rs b/aws/rust-runtime/aws-inlineable/src/http_request_checksum.rs index 701a2e36a0..c6ce150e5b 100644 --- a/aws/rust-runtime/aws-inlineable/src/http_request_checksum.rs +++ b/aws/rust-runtime/aws-inlineable/src/http_request_checksum.rs @@ -8,7 +8,7 @@ //! Interceptor for handling Smithy `@httpChecksum` request checksumming with AWS SigV4 use aws_http::content_encoding::{AwsChunkedBody, AwsChunkedBodyOptions}; -use aws_runtime::auth::sigv4::SigV4OperationSigningConfig; +use aws_runtime::auth::SigV4OperationSigningConfig; use aws_sigv4::http_request::SignableBody; use aws_smithy_checksums::ChecksumAlgorithm; use aws_smithy_checksums::{body::calculate, http::HttpChecksum}; diff --git a/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs b/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs index 3ded9fcd68..1d73aca8d1 100644 --- a/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs +++ b/aws/rust-runtime/aws-inlineable/src/presigning_interceptors.rs @@ -7,7 +7,8 @@ use crate::presigning::PresigningConfig; use crate::serialization_settings::HeaderSerializationSettings; -use aws_runtime::auth::sigv4::{HttpSignatureType, SigV4OperationSigningConfig}; +use aws_runtime::auth::HttpSignatureType; +use aws_runtime::auth::SigV4OperationSigningConfig; use aws_runtime::invocation_id::InvocationIdInterceptor; use aws_runtime::request_info::RequestInfoInterceptor; use aws_runtime::user_agent::UserAgentInterceptor; diff --git a/aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs b/aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs index 3a5c3258d1..67dee4528c 100644 --- a/aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs +++ b/aws/rust-runtime/aws-inlineable/tests/middleware_e2e_test.rs @@ -3,15 +3,14 @@ * SPDX-License-Identifier: Apache-2.0 */ -use std::convert::Infallible; -use std::error::Error; -use std::fmt; -use std::fmt::{Display, Formatter}; -use std::time::{Duration, UNIX_EPOCH}; - use aws_credential_types::cache::CredentialsCache; use aws_credential_types::provider::SharedCredentialsProvider; use aws_credential_types::Credentials; +use aws_http::retry::AwsResponseRetryClassifier; +use aws_http::user_agent::AwsUserAgent; +use aws_inlineable::middleware::DefaultMiddleware; +use aws_sig_auth::signer::OperationSigningConfig; +use aws_smithy_async::time::SharedTimeSource; use aws_smithy_client::erase::DynConnector; use aws_smithy_client::test_connection::TestConnection; use aws_smithy_http::body::SdkBody; @@ -20,17 +19,16 @@ use aws_smithy_http::operation::Operation; use aws_smithy_http::response::ParseHttpResponse; use aws_smithy_types::endpoint::Endpoint; use aws_smithy_types::retry::{ErrorKind, ProvideErrorKind}; +use aws_types::region::SigningRegion; +use aws_types::SigningName; use bytes::Bytes; use http::header::{AUTHORIZATION, USER_AGENT}; use http::{self, Uri}; - -use aws_http::retry::AwsResponseRetryClassifier; -use aws_http::user_agent::AwsUserAgent; -use aws_inlineable::middleware::DefaultMiddleware; -use aws_sig_auth::signer::OperationSigningConfig; -use aws_smithy_async::time::SharedTimeSource; -use aws_types::region::SigningRegion; -use aws_types::SigningService; +use std::convert::Infallible; +use std::error::Error; +use std::fmt; +use std::fmt::{Display, Formatter}; +use std::time::{Duration, UNIX_EPOCH}; type Client = aws_smithy_client::Client; @@ -89,12 +87,13 @@ fn test_operation() -> Operation>, + /// Signature type. + pub signature_type: HttpSignatureType, + /// Whether or not the signature is optional. + pub signing_optional: bool, + /// Optional expiration (for presigning) + pub expires_in: Option, +} + +impl Default for SigningOptions { + fn default() -> Self { + Self { + double_uri_encode: true, + content_sha256_header: false, + normalize_uri_path: true, + omit_session_token: false, + payload_override: None, + signature_type: HttpSignatureType::HttpRequestHeaders, + signing_optional: false, + expires_in: None, + } + } +} + +/// SigV4 signing configuration for an operation +/// +/// Although these fields MAY be customized on a per request basis, they are generally static +/// for a given operation +#[derive(Clone, Debug, Default, PartialEq, Eq)] +pub struct SigV4OperationSigningConfig { + /// AWS Region to sign for. + pub region: Option, + /// AWS Region to sign for. + pub region_set: Option, + /// AWS Service to sign for. + pub name: Option, + /// Signing options. + pub signing_options: SigningOptions, +} + +impl Storable for SigV4OperationSigningConfig { + type Storer = StoreReplace; +} + +fn settings(operation_config: &SigV4OperationSigningConfig) -> SigningSettings { + let mut settings = SigningSettings::default(); + settings.percent_encoding_mode = if operation_config.signing_options.double_uri_encode { + PercentEncodingMode::Double + } else { + PercentEncodingMode::Single + }; + settings.payload_checksum_kind = if operation_config.signing_options.content_sha256_header { + PayloadChecksumKind::XAmzSha256 + } else { + PayloadChecksumKind::NoHeader + }; + settings.uri_path_normalization_mode = if operation_config.signing_options.normalize_uri_path { + UriPathNormalizationMode::Enabled + } else { + UriPathNormalizationMode::Disabled + }; + settings.session_token_mode = if operation_config.signing_options.omit_session_token { + SessionTokenMode::Exclude + } else { + SessionTokenMode::Include + }; + settings.signature_location = match operation_config.signing_options.signature_type { + HttpSignatureType::HttpRequestHeaders => SignatureLocation::Headers, + HttpSignatureType::HttpRequestQueryParams => SignatureLocation::QueryParams, + }; + settings.expires_in = operation_config.signing_options.expires_in; + settings +} + +#[derive(Debug)] +enum SigV4SigningError { + MissingOperationSigningConfig, + MissingSigningRegion, + MissingSigningRegionSet, + MissingSigningName, + WrongIdentityType(Identity), + BadTypeInEndpointAuthSchemeConfig(&'static str), +} + +impl fmt::Display for SigV4SigningError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use SigV4SigningError::*; + let mut w = |s| f.write_str(s); + match self { + MissingOperationSigningConfig => w("missing operation signing config"), + MissingSigningRegion => w("missing signing region"), + MissingSigningRegionSet => w("missing signing region set"), + MissingSigningName => w("missing signing name"), + WrongIdentityType(identity) => { + write!(f, "wrong identity type for SigV4/sigV4a. Expected AWS credentials but got `{identity:?}`") + } + BadTypeInEndpointAuthSchemeConfig(field_name) => { + write!( + f, + "unexpected type for `{field_name}` in endpoint auth scheme config", + ) + } + } + } +} + +impl StdError for SigV4SigningError { + fn source(&self) -> Option<&(dyn StdError + 'static)> { + match self { + Self::MissingOperationSigningConfig => None, + Self::MissingSigningRegion => None, + Self::MissingSigningRegionSet => None, + Self::MissingSigningName => None, + Self::WrongIdentityType(_) => None, + Self::BadTypeInEndpointAuthSchemeConfig(_) => None, + } + } +} + +fn extract_endpoint_auth_scheme_signing_name( + endpoint_config: &AuthSchemeEndpointConfig<'_>, +) -> Result, SigV4SigningError> { + use SigV4SigningError::BadTypeInEndpointAuthSchemeConfig as UnexpectedType; + + match extract_field_from_endpoint_config("signingName", endpoint_config) { + Some(Document::String(s)) => Ok(Some(SigningName::from(s.to_string()))), + None => Ok(None), + _ => Err(UnexpectedType("signingName")), + } +} + +fn extract_endpoint_auth_scheme_signing_region( + endpoint_config: &AuthSchemeEndpointConfig<'_>, +) -> Result, SigV4SigningError> { + use SigV4SigningError::BadTypeInEndpointAuthSchemeConfig as UnexpectedType; + + match extract_field_from_endpoint_config("signingRegion", endpoint_config) { + Some(Document::String(s)) => Ok(Some(SigningRegion::from(Region::new(s.clone())))), + None => Ok(None), + _ => Err(UnexpectedType("signingRegion")), + } +} + +fn extract_endpoint_auth_scheme_signing_region_set( + endpoint_config: &AuthSchemeEndpointConfig<'_>, +) -> Result, SigV4SigningError> { + use SigV4SigningError::BadTypeInEndpointAuthSchemeConfig as UnexpectedType; + + match extract_field_from_endpoint_config("signingRegionSet", endpoint_config) { + Some(Array(docs)) => { + // The service defines the region set as a string array. Here, we convert it to a comma separated list. + let regions: Vec = docs + .iter() + .filter_map(|doc| doc.as_string()) + .map(ToString::to_string) + .collect(); + Ok(Some(SigningRegionSet::from_vec(regions))) + } + None => Ok(None), + _it => Err(UnexpectedType("signingRegionSet")), + } +} + +fn extract_field_from_endpoint_config<'a>( + field_name: &'static str, + endpoint_config: &'a AuthSchemeEndpointConfig<'_>, +) -> Option<&'a Document> { + endpoint_config + .as_document() + .and_then(Document::as_object) + .and_then(|config| config.get(field_name)) +} diff --git a/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs b/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs index ac1eab1ea7..b08fc7bc38 100644 --- a/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs +++ b/aws/rust-runtime/aws-runtime/src/auth/sigv4.rs @@ -3,11 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +use crate::auth::{ + extract_endpoint_auth_scheme_signing_name, extract_endpoint_auth_scheme_signing_region, + SigV4OperationSigningConfig, SigV4SigningError, +}; use aws_credential_types::Credentials; use aws_sigv4::http_request::{ - sign, PayloadChecksumKind, PercentEncodingMode, SessionTokenMode, SignableBody, - SignableRequest, SignatureLocation, SigningParams, SigningSettings, UriPathNormalizationMode, + sign, SignableBody, SignableRequest, SigningParams, SigningSettings, }; +use aws_sigv4::sign::v4; use aws_smithy_runtime_api::box_error::BoxError; use aws_smithy_runtime_api::client::auth::{ AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Signer, @@ -15,14 +19,11 @@ use aws_smithy_runtime_api::client::auth::{ use aws_smithy_runtime_api::client::identity::{Identity, SharedIdentityResolver}; use aws_smithy_runtime_api::client::orchestrator::HttpRequest; use aws_smithy_runtime_api::client::runtime_components::{GetIdentityResolver, RuntimeComponents}; -use aws_smithy_types::config_bag::{ConfigBag, Storable, StoreReplace}; -use aws_smithy_types::Document; -use aws_types::region::{Region, SigningRegion}; -use aws_types::SigningService; +use aws_smithy_types::config_bag::ConfigBag; +use aws_types::region::SigningRegion; +use aws_types::SigningName; use std::borrow::Cow; -use std::error::Error as StdError; -use std::fmt; -use std::time::{Duration, SystemTime}; +use std::time::SystemTime; const EXPIRATION_WARNING: &str = "Presigned request will expire before the given \ `expires_in` duration because the credentials used to sign it will expire first."; @@ -30,53 +31,6 @@ const EXPIRATION_WARNING: &str = "Presigned request will expire before the given /// Auth scheme ID for SigV4. pub const SCHEME_ID: AuthSchemeId = AuthSchemeId::new("sigv4"); -struct EndpointAuthSchemeConfig { - signing_region_override: Option, - signing_service_override: Option, -} - -#[derive(Debug)] -enum SigV4SigningError { - MissingOperationSigningConfig, - MissingSigningRegion, - MissingSigningService, - WrongIdentityType(Identity), - BadTypeInEndpointAuthSchemeConfig(&'static str), -} - -impl fmt::Display for SigV4SigningError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - use SigV4SigningError::*; - let mut w = |s| f.write_str(s); - match self { - MissingOperationSigningConfig => w("missing operation signing config for SigV4"), - MissingSigningRegion => w("missing signing region for SigV4 signing"), - MissingSigningService => w("missing signing service for SigV4 signing"), - WrongIdentityType(identity) => { - write!(f, "wrong identity type for SigV4: {identity:?}") - } - BadTypeInEndpointAuthSchemeConfig(field_name) => { - write!( - f, - "unexpected type for `{field_name}` in endpoint auth scheme config", - ) - } - } - } -} - -impl StdError for SigV4SigningError { - fn source(&self) -> Option<&(dyn StdError + 'static)> { - match self { - Self::MissingOperationSigningConfig => None, - Self::MissingSigningRegion => None, - Self::MissingSigningService => None, - Self::WrongIdentityType(_) => None, - Self::BadTypeInEndpointAuthSchemeConfig(_) => None, - } - } -} - /// SigV4 auth scheme. #[derive(Debug, Default)] pub struct SigV4AuthScheme { @@ -107,73 +61,6 @@ impl AuthScheme for SigV4AuthScheme { } } -/// Type of SigV4 signature. -#[derive(Debug, Eq, PartialEq, Clone, Copy)] -pub enum HttpSignatureType { - /// A signature for a full http request should be computed, with header updates applied to the signing result. - HttpRequestHeaders, - - /// A signature for a full http request should be computed, with query param updates applied to the signing result. - /// - /// This is typically used for presigned URLs. - HttpRequestQueryParams, -} - -/// Signing options for SigV4. -#[derive(Clone, Debug, Eq, PartialEq)] -#[non_exhaustive] -pub struct SigningOptions { - /// Apply URI encoding twice. - pub double_uri_encode: bool, - /// Apply a SHA-256 payload checksum. - pub content_sha256_header: bool, - /// Normalize the URI path before signing. - pub normalize_uri_path: bool, - /// Omit the session token from the signature. - pub omit_session_token: bool, - /// Optional override for the payload to be used in signing. - pub payload_override: Option>, - /// Signature type. - pub signature_type: HttpSignatureType, - /// Whether or not the signature is optional. - pub signing_optional: bool, - /// Optional expiration (for presigning) - pub expires_in: Option, -} - -impl Default for SigningOptions { - fn default() -> Self { - Self { - double_uri_encode: true, - content_sha256_header: false, - normalize_uri_path: true, - omit_session_token: false, - payload_override: None, - signature_type: HttpSignatureType::HttpRequestHeaders, - signing_optional: false, - expires_in: None, - } - } -} - -/// SigV4 signing configuration for an operation -/// -/// Although these fields MAY be customized on a per request basis, they are generally static -/// for a given operation -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct SigV4OperationSigningConfig { - /// AWS Region to sign for. - pub region: Option, - /// AWS Service to sign for. - pub service: Option, - /// Signing options. - pub signing_options: SigningOptions, -} - -impl Storable for SigV4OperationSigningConfig { - type Storer = StoreReplace; -} - /// SigV4 signer. #[derive(Debug, Default)] pub struct SigV4Signer; @@ -185,34 +72,7 @@ impl SigV4Signer { } fn settings(operation_config: &SigV4OperationSigningConfig) -> SigningSettings { - let mut settings = SigningSettings::default(); - settings.percent_encoding_mode = if operation_config.signing_options.double_uri_encode { - PercentEncodingMode::Double - } else { - PercentEncodingMode::Single - }; - settings.payload_checksum_kind = if operation_config.signing_options.content_sha256_header { - PayloadChecksumKind::XAmzSha256 - } else { - PayloadChecksumKind::NoHeader - }; - settings.uri_path_normalization_mode = - if operation_config.signing_options.normalize_uri_path { - UriPathNormalizationMode::Enabled - } else { - UriPathNormalizationMode::Disabled - }; - settings.session_token_mode = if operation_config.signing_options.omit_session_token { - SessionTokenMode::Exclude - } else { - SessionTokenMode::Include - }; - settings.signature_location = match operation_config.signing_options.signature_type { - HttpSignatureType::HttpRequestHeaders => SignatureLocation::Headers, - HttpSignatureType::HttpRequestQueryParams => SignatureLocation::QueryParams, - }; - settings.expires_in = operation_config.signing_options.expires_in; - settings + super::settings(operation_config) } fn signing_params<'a>( @@ -220,7 +80,7 @@ impl SigV4Signer { credentials: &'a Credentials, operation_config: &'a SigV4OperationSigningConfig, request_timestamp: SystemTime, - ) -> Result, SigV4SigningError> { + ) -> Result, SigV4SigningError> { if let Some(expires_in) = settings.expires_in { if let Some(creds_expires_time) = credentials.expiry() { let presigned_expires_time = request_timestamp + expires_in; @@ -230,9 +90,8 @@ impl SigV4Signer { } } - let mut builder = SigningParams::builder() - .access_key(credentials.access_key_id()) - .secret_key(credentials.secret_access_key()) + Ok(v4::SigningParams::builder() + .identity(Identity::new(credentials.clone(), credentials.expiry())) .region( operation_config .region @@ -240,17 +99,17 @@ impl SigV4Signer { .ok_or(SigV4SigningError::MissingSigningRegion)? .as_ref(), ) - .service_name( + .name( operation_config - .service + .name .as_ref() - .ok_or(SigV4SigningError::MissingSigningService)? + .ok_or(SigV4SigningError::MissingSigningName)? .as_ref(), ) .time(request_timestamp) - .settings(settings); - builder.set_security_token(credentials.session_token()); - Ok(builder.build().expect("all required fields set")) + .settings(settings) + .build() + .expect("all required fields set")) } fn extract_operation_config<'a>( @@ -261,18 +120,13 @@ impl SigV4Signer { .load::() .ok_or(SigV4SigningError::MissingOperationSigningConfig)?; - let signing_region = config_bag.load::(); - let signing_service = config_bag.load::(); + let service = extract_endpoint_auth_scheme_signing_name(&auth_scheme_endpoint_config)? + .or(config_bag.load::().cloned()); - let EndpointAuthSchemeConfig { - signing_region_override, - signing_service_override, - } = Self::extract_endpoint_auth_scheme_config(auth_scheme_endpoint_config)?; + let region = extract_endpoint_auth_scheme_signing_region(&auth_scheme_endpoint_config)? + .or(config_bag.load::().cloned()); - match ( - signing_region_override.or_else(|| signing_region.cloned()), - signing_service_override.or_else(|| signing_service.cloned()), - ) { + match (region, service) { (None, None) => Ok(Cow::Borrowed(operation_config)), (region, service) => { let mut operation_config = operation_config.clone(); @@ -280,35 +134,12 @@ impl SigV4Signer { operation_config.region = region; } if service.is_some() { - operation_config.service = service; + operation_config.name = service; } Ok(Cow::Owned(operation_config)) } } } - - fn extract_endpoint_auth_scheme_config( - endpoint_config: AuthSchemeEndpointConfig<'_>, - ) -> Result { - let (mut signing_region_override, mut signing_service_override) = (None, None); - if let Some(config) = endpoint_config.as_document().and_then(Document::as_object) { - use SigV4SigningError::BadTypeInEndpointAuthSchemeConfig as UnexpectedType; - signing_region_override = match config.get("signingRegion") { - Some(Document::String(s)) => Some(SigningRegion::from(Region::new(s.clone()))), - None => None, - _ => return Err(UnexpectedType("signingRegion")), - }; - signing_service_override = match config.get("signingName") { - Some(Document::String(s)) => Some(SigningService::from(s.to_string())), - None => None, - _ => return Err(UnexpectedType("signingName")), - }; - } - Ok(EndpointAuthSchemeConfig { - signing_region_override, - signing_service_override, - }) - } } impl Signer for SigV4Signer { @@ -337,6 +168,14 @@ impl Signer for SigV4Signer { let signing_params = Self::signing_params(settings, credentials, &operation_config, request_time)?; + #[cfg(feature = "event-stream")] + let (signing_region, signing_name) = { + let region = aws_types::region::Region::new(signing_params.region().to_owned()); + let service = signing_params.name().to_owned(); + + (SigningRegion::from(region), SigningName::from(service)) + }; + let (signing_instructions, _signature) = { // A body that is already in memory can be signed directly. A body that is not in memory // (any sort of streaming body or presigned request) will be signed via UNSIGNED-PAYLOAD. @@ -361,7 +200,7 @@ impl Signer for SigV4Signer { request.headers(), signable_body, ); - sign(signable_request, &signing_params)? + sign(signable_request, &SigningParams::V4(signing_params))? } .into_parts(); @@ -373,12 +212,13 @@ impl Signer for SigV4Signer { if let Some(signer_sender) = config_bag.load::() { let time_source = runtime_components.time_source().unwrap_or_default(); + signer_sender .send(Box::new(SigV4MessageSigner::new( _signature, - credentials.clone(), - Region::new(signing_params.region().to_string()).into(), - signing_params.service_name().to_string().into(), + Identity::new(credentials.clone(), credentials.expiry()), + signing_region, + signing_name, time_source, )) as _) .expect("failed to send deferred signer"); @@ -392,50 +232,60 @@ impl Signer for SigV4Signer { #[cfg(feature = "event-stream")] mod event_stream { - use aws_credential_types::Credentials; use aws_sigv4::event_stream::{sign_empty_message, sign_message}; - use aws_sigv4::SigningParams; + use aws_sigv4::sign::v4::SigningParams; use aws_smithy_async::time::SharedTimeSource; use aws_smithy_eventstream::frame::{Message, SignMessage, SignMessageError}; + use aws_smithy_runtime_api::client::identity::Identity; use aws_types::region::SigningRegion; - use aws_types::SigningService; + use aws_types::SigningName; + use std::fmt; /// Event Stream SigV4 signing implementation. - #[derive(Debug)] pub(super) struct SigV4MessageSigner { + identity: Identity, last_signature: String, - credentials: Credentials, signing_region: SigningRegion, - signing_service: SigningService, + signing_name: SigningName, time: SharedTimeSource, } + impl fmt::Debug for SigV4MessageSigner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SigV4MessageSigner") + .field("identity", &"** redacted **") + .field("last_signature", &self.last_signature) + .field("signing_region", &self.signing_region) + .field("signing_name", &self.signing_name) + .field("time", &self.time) + .finish() + } + } + impl SigV4MessageSigner { pub(super) fn new( last_signature: String, - credentials: Credentials, + identity: Identity, signing_region: SigningRegion, - signing_service: SigningService, + signing_name: SigningName, time: SharedTimeSource, ) -> Self { Self { last_signature, - credentials, + identity, signing_region, - signing_service, + signing_name, time, } } fn signing_params(&self) -> SigningParams<'_, ()> { - let mut builder = SigningParams::builder() - .access_key(self.credentials.access_key_id()) - .secret_key(self.credentials.secret_access_key()) + let builder = SigningParams::builder() + .identity(self.identity.clone()) .region(self.signing_region.as_ref()) - .service_name(self.signing_service.as_ref()) + .name(self.signing_name.as_ref()) .time(self.time.now()) .settings(()); - builder.set_security_token(self.credentials.session_token()); builder.build().unwrap() } } @@ -444,7 +294,7 @@ mod event_stream { fn sign(&mut self, message: Message) -> Result { let (signed_message, signature) = { let params = self.signing_params(); - sign_message(&message, &self.last_signature, ¶ms).into_parts() + sign_message(&message, &self.last_signature, ¶ms)?.into_parts() }; self.last_signature = signature; Ok(signed_message) @@ -453,7 +303,9 @@ mod event_stream { fn sign_empty(&mut self) -> Option> { let (signed_message, signature) = { let params = self.signing_params(); - sign_empty_message(&self.last_signature, ¶ms).into_parts() + sign_empty_message(&self.last_signature, ¶ms) + .expect("signing an empty message will always succeed.") + .into_parts() }; self.last_signature = signature; Some(Ok(signed_message)) @@ -467,7 +319,7 @@ mod event_stream { use aws_smithy_eventstream::frame::{HeaderValue, Message, SignMessage}; use aws_types::region::Region; use aws_types::region::SigningRegion; - use aws_types::SigningService; + use aws_types::SigningName; use std::time::{Duration, UNIX_EPOCH}; fn check_send_sync(value: T) -> T { @@ -477,11 +329,12 @@ mod event_stream { #[test] fn sign_message() { let region = Region::new("us-east-1"); + let creds = Credentials::for_tests(); let mut signer = check_send_sync(SigV4MessageSigner::new( "initial-signature".into(), - Credentials::for_tests(), + Identity::new(creds.clone(), creds.expiry()), SigningRegion::from(region), - SigningService::from_static("transcribe"), + SigningName::from_static("transcribe"), SharedTimeSource::new(UNIX_EPOCH + Duration::new(1611160427, 0)), )); let mut signatures = Vec::new(); @@ -510,15 +363,21 @@ mod event_stream { #[cfg(test)] mod tests { - use super::*; + use std::collections::HashMap; + use std::time::{Duration, SystemTime}; + + use tracing_test::traced_test; + use aws_credential_types::Credentials; use aws_sigv4::http_request::SigningSettings; use aws_smithy_types::config_bag::Layer; + use aws_smithy_types::Document; use aws_types::region::SigningRegion; - use aws_types::SigningService; - use std::collections::HashMap; - use std::time::{Duration, SystemTime}; - use tracing_test::traced_test; + use aws_types::SigningName; + + use crate::auth::{HttpSignatureType, SigningOptions}; + + use super::*; #[test] #[traced_test] @@ -538,7 +397,7 @@ mod tests { ); let operation_config = SigV4OperationSigningConfig { region: Some(SigningRegion::from_static("test")), - service: Some(SigningService::from_static("test")), + name: Some(SigningName::from_static("test")), signing_options: SigningOptions { double_uri_encode: true, content_sha256_header: true, @@ -549,6 +408,7 @@ mod tests { expires_in: None, payload_override: None, }, + ..Default::default() }; SigV4Signer::signing_params(settings, &credentials, &operation_config, now).unwrap(); assert!(!logs_contain(EXPIRATION_WARNING)); @@ -564,20 +424,17 @@ mod tests { fn endpoint_config_overrides_region_and_service() { let mut layer = Layer::new("test"); layer.store_put(SigV4OperationSigningConfig { - region: Some(SigningRegion::from(Region::new("override-this-region"))), - service: Some(SigningService::from_static("override-this-service")), - signing_options: Default::default(), + region: Some(SigningRegion::from_static("test")), + name: Some(SigningName::from_static("override-this-service")), + ..Default::default() }); let config = Document::Object({ let mut out = HashMap::new(); - out.insert("name".to_string(), "sigv4".to_string().into()); - out.insert( - "signingName".to_string(), - "qldb-override".to_string().into(), - ); + out.insert("name".to_owned(), "sigv4".to_owned().into()); + out.insert("signingName".to_owned(), "qldb-override".to_owned().into()); out.insert( - "signingRegion".to_string(), - "us-east-override".to_string().into(), + "signingRegion".to_owned(), + "us-east-override".to_owned().into(), ); out }); @@ -588,12 +445,9 @@ mod tests { assert_eq!( result.region, - Some(SigningRegion::from(Region::new("us-east-override"))) - ); - assert_eq!( - result.service, - Some(SigningService::from_static("qldb-override")) + Some(SigningRegion::from_static("us-east-override")) ); + assert_eq!(result.name, Some(SigningName::from_static("qldb-override"))); assert!(matches!(result, Cow::Owned(_))); } @@ -601,20 +455,17 @@ mod tests { fn endpoint_config_supports_fallback_when_region_or_service_are_unset() { let mut layer = Layer::new("test"); layer.store_put(SigV4OperationSigningConfig { - region: Some(SigningRegion::from(Region::new("us-east-1"))), - service: Some(SigningService::from_static("qldb")), - signing_options: Default::default(), + region: Some(SigningRegion::from_static("us-east-1")), + name: Some(SigningName::from_static("qldb")), + ..Default::default() }); let cfg = ConfigBag::of_layers(vec![layer]); let config = AuthSchemeEndpointConfig::empty(); let result = SigV4Signer::extract_operation_config(config, &cfg).expect("success"); - assert_eq!( - result.region, - Some(SigningRegion::from(Region::new("us-east-1"))) - ); - assert_eq!(result.service, Some(SigningService::from_static("qldb"))); + assert_eq!(result.region, Some(SigningRegion::from_static("us-east-1"))); + assert_eq!(result.name, Some(SigningName::from_static("qldb"))); assert!(matches!(result, Cow::Borrowed(_))); } } diff --git a/aws/rust-runtime/aws-runtime/src/auth/sigv4a.rs b/aws/rust-runtime/aws-runtime/src/auth/sigv4a.rs new file mode 100644 index 0000000000..2708874218 --- /dev/null +++ b/aws/rust-runtime/aws-runtime/src/auth/sigv4a.rs @@ -0,0 +1,312 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_credential_types::Credentials; +use aws_sigv4::http_request::{sign, SignableBody, SignableRequest, SigningSettings}; +use std::borrow::Cow; +use std::time::SystemTime; + +use crate::auth::{ + extract_endpoint_auth_scheme_signing_name, extract_endpoint_auth_scheme_signing_region_set, + SigV4OperationSigningConfig, SigV4SigningError, +}; +use aws_sigv4::sign::v4a; +use aws_smithy_runtime_api::box_error::BoxError; +use aws_smithy_runtime_api::client::auth::{ + AuthScheme, AuthSchemeEndpointConfig, AuthSchemeId, Signer, +}; +use aws_smithy_runtime_api::client::identity::{Identity, SharedIdentityResolver}; +use aws_smithy_runtime_api::client::orchestrator::HttpRequest; +use aws_smithy_runtime_api::client::runtime_components::{GetIdentityResolver, RuntimeComponents}; +use aws_smithy_types::config_bag::ConfigBag; +use aws_types::region::SigningRegionSet; +use aws_types::SigningName; + +const EXPIRATION_WARNING: &str = "Presigned request will expire before the given \ + `expires_in` duration because the credentials used to sign it will expire first."; + +/// Auth scheme ID for SigV4a. +pub const SCHEME_ID: AuthSchemeId = AuthSchemeId::new("sigv4a"); + +/// SigV4a auth scheme. +#[derive(Debug, Default)] +pub struct SigV4aAuthScheme { + signer: SigV4aSigner, +} + +impl SigV4aAuthScheme { + /// Creates a new `SigV4aHttpAuthScheme`. + pub fn new() -> Self { + Default::default() + } +} + +impl AuthScheme for SigV4aAuthScheme { + fn scheme_id(&self) -> AuthSchemeId { + SCHEME_ID + } + + fn identity_resolver( + &self, + identity_resolvers: &dyn GetIdentityResolver, + ) -> Option { + identity_resolvers.identity_resolver(self.scheme_id()) + } + + fn signer(&self) -> &dyn Signer { + &self.signer + } +} + +/// SigV4a HTTP request signer. +#[derive(Debug, Default)] +pub struct SigV4aSigner; + +impl SigV4aSigner { + /// Creates a new signer instance. + pub fn new() -> Self { + Self + } + + fn settings(operation_config: &SigV4OperationSigningConfig) -> SigningSettings { + super::settings(operation_config) + } + + fn signing_params<'a>( + settings: SigningSettings, + credentials: &'a Credentials, + operation_config: &'a SigV4OperationSigningConfig, + request_timestamp: SystemTime, + ) -> Result, SigV4SigningError> { + if let Some(expires_in) = settings.expires_in { + if let Some(creds_expires_time) = credentials.expiry() { + let presigned_expires_time = request_timestamp + expires_in; + if presigned_expires_time > creds_expires_time { + tracing::warn!(EXPIRATION_WARNING); + } + } + } + + Ok(v4a::SigningParams::builder() + .identity(Identity::new(credentials.clone(), credentials.expiry())) + .region_set( + operation_config + .region_set + .as_ref() + .ok_or(SigV4SigningError::MissingSigningRegionSet)? + .as_ref(), + ) + .service_name( + operation_config + .name + .as_ref() + .ok_or(SigV4SigningError::MissingSigningName)? + .as_ref(), + ) + .time(request_timestamp) + .settings(settings) + .build() + .expect("all required fields set")) + } + + fn extract_operation_config<'a>( + auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'a>, + config_bag: &'a ConfigBag, + ) -> Result, SigV4SigningError> { + let operation_config = config_bag + .load::() + .ok_or(SigV4SigningError::MissingOperationSigningConfig)?; + + let service = extract_endpoint_auth_scheme_signing_name(&auth_scheme_endpoint_config)? + .or(config_bag.load::().cloned()); + + let region_set = + extract_endpoint_auth_scheme_signing_region_set(&auth_scheme_endpoint_config)? + .or(config_bag.load::().cloned()); + + match (®ion_set, service) { + (None, None) => Ok(Cow::Borrowed(operation_config)), + (_region, service) => { + let mut operation_config = operation_config.clone(); + if region_set.is_some() { + operation_config.region_set = region_set; + } + if service.is_some() { + operation_config.name = service; + } + Ok(Cow::Owned(operation_config)) + } + } + } +} + +impl Signer for SigV4aSigner { + fn sign_http_request( + &self, + request: &mut HttpRequest, + identity: &Identity, + auth_scheme_endpoint_config: AuthSchemeEndpointConfig<'_>, + runtime_components: &RuntimeComponents, + config_bag: &ConfigBag, + ) -> Result<(), BoxError> { + let operation_config = + Self::extract_operation_config(auth_scheme_endpoint_config, config_bag)?; + let request_time = runtime_components.time_source().unwrap_or_default().now(); + + let credentials = if let Some(creds) = identity.data::() { + creds + } else if operation_config.signing_options.signing_optional { + tracing::debug!("skipped SigV4a signing since signing is optional for this operation and there are no credentials"); + return Ok(()); + } else { + return Err(SigV4SigningError::WrongIdentityType(identity.clone()).into()); + }; + + let settings = Self::settings(&operation_config); + let signing_params = + Self::signing_params(settings, credentials, &operation_config, request_time)?; + + let (signing_instructions, _signature) = { + // A body that is already in memory can be signed directly. A body that is not in memory + // (any sort of streaming body or presigned request) will be signed via UNSIGNED-PAYLOAD. + let signable_body = operation_config + .signing_options + .payload_override + .as_ref() + // the payload_override is a cheap clone because it contains either a + // reference or a short checksum (we're not cloning the entire body) + .cloned() + .unwrap_or_else(|| { + request + .body() + .bytes() + .map(SignableBody::Bytes) + .unwrap_or(SignableBody::UnsignedPayload) + }); + + let signable_request = SignableRequest::new( + request.method(), + request.uri(), + request.headers(), + signable_body, + ); + sign(signable_request, &signing_params.into())? + } + .into_parts(); + + signing_instructions.apply_to_request(request); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::{SigV4OperationSigningConfig, SigV4aSigner, EXPIRATION_WARNING}; + use crate::auth::{HttpSignatureType, SigningOptions}; + use aws_credential_types::Credentials; + use aws_sigv4::http_request::SigningSettings; + use aws_smithy_runtime_api::client::auth::AuthSchemeEndpointConfig; + use aws_smithy_types::config_bag::{ConfigBag, Layer}; + use aws_smithy_types::Document; + use aws_types::region::SigningRegionSet; + use aws_types::SigningName; + use std::borrow::Cow; + use std::collections::HashMap; + use std::time::{Duration, SystemTime}; + use tracing_test::traced_test; + + #[test] + #[traced_test] + fn expiration_warning() { + let now = SystemTime::UNIX_EPOCH + Duration::from_secs(1000); + let creds_expire_in = Duration::from_secs(100); + + let mut settings = SigningSettings::default(); + settings.expires_in = Some(creds_expire_in - Duration::from_secs(10)); + + let credentials = Credentials::new( + "test-access-key", + "test-secret-key", + Some("test-session-token".into()), + Some(now + creds_expire_in), + "test", + ); + let operation_config = SigV4OperationSigningConfig { + region_set: Some(SigningRegionSet::from_static("test")), + name: Some(SigningName::from_static("test")), + signing_options: SigningOptions { + double_uri_encode: true, + content_sha256_header: true, + normalize_uri_path: true, + omit_session_token: true, + signature_type: HttpSignatureType::HttpRequestHeaders, + signing_optional: false, + expires_in: None, + payload_override: None, + }, + ..Default::default() + }; + SigV4aSigner::signing_params(settings, &credentials, &operation_config, now).unwrap(); + assert!(!logs_contain(EXPIRATION_WARNING)); + + let mut settings = SigningSettings::default(); + settings.expires_in = Some(creds_expire_in + Duration::from_secs(10)); + + SigV4aSigner::signing_params(settings, &credentials, &operation_config, now).unwrap(); + assert!(logs_contain(EXPIRATION_WARNING)); + } + + #[test] + fn endpoint_config_overrides_region_and_service() { + let mut layer = Layer::new("test"); + layer.store_put(SigV4OperationSigningConfig { + region_set: Some(SigningRegionSet::from_static("test")), + name: Some(SigningName::from_static("override-this-service")), + ..Default::default() + }); + let config = Document::Object({ + let mut out = HashMap::new(); + out.insert("name".to_owned(), "sigv4a".to_owned().into()); + out.insert("signingName".to_owned(), "qldb-override".to_owned().into()); + out.insert( + "signingRegionSet".to_string(), + Document::Array(vec!["us-east-override".to_string().into()]), + ); + out + }); + let config = AuthSchemeEndpointConfig::from(Some(&config)); + + let cfg = ConfigBag::of_layers(vec![layer]); + let result = SigV4aSigner::extract_operation_config(config, &cfg).expect("success"); + + assert_eq!( + result.region_set, + Some(SigningRegionSet::from_static("us-east-override")) + ); + assert_eq!(result.name, Some(SigningName::from_static("qldb-override"))); + assert!(matches!(result, Cow::Owned(_))); + } + + #[test] + fn endpoint_config_supports_fallback_when_region_or_service_are_unset() { + let mut layer = Layer::new("test"); + layer.store_put(SigV4OperationSigningConfig { + region_set: Some(SigningRegionSet::from_static("us-east-1")), + name: Some(SigningName::from_static("qldb")), + ..Default::default() + }); + let cfg = ConfigBag::of_layers(vec![layer]); + let config = AuthSchemeEndpointConfig::empty(); + + let result = SigV4aSigner::extract_operation_config(config, &cfg).expect("success"); + + assert_eq!( + result.region_set, + Some(SigningRegionSet::from_static("us-east-1")) + ); + assert_eq!(result.name, Some(SigningName::from_static("qldb"))); + assert!(matches!(result, Cow::Borrowed(_))); + } +} diff --git a/aws/rust-runtime/aws-runtime/src/invocation_id.rs b/aws/rust-runtime/aws-runtime/src/invocation_id.rs index 18fcac7c4a..bb1398542d 100644 --- a/aws/rust-runtime/aws-runtime/src/invocation_id.rs +++ b/aws/rust-runtime/aws-runtime/src/invocation_id.rs @@ -212,7 +212,9 @@ mod test_util { #[cfg(test)] mod tests { - use super::*; + use crate::invocation_id::{ + InvocationId, InvocationIdInterceptor, SharedInvocationIdGenerator, + }; use aws_smithy_http::body::SdkBody; use aws_smithy_runtime_api::client::interceptors::context::{ BeforeTransmitInterceptorContextMut, Input, InterceptorContext, @@ -268,7 +270,7 @@ mod tests { let mut cfg = ConfigBag::base(); let mut layer = Layer::new("test"); layer.store_put(SharedInvocationIdGenerator::new( - PredefinedInvocationIdGenerator::new(vec![InvocationId::new( + crate::invocation_id::PredefinedInvocationIdGenerator::new(vec![InvocationId::new( "the-best-invocation-id".into(), )]), )); diff --git a/aws/rust-runtime/aws-sig-auth/Cargo.toml b/aws/rust-runtime/aws-sig-auth/Cargo.toml index deece1ac30..591ef40966 100644 --- a/aws/rust-runtime/aws-sig-auth/Cargo.toml +++ b/aws/rust-runtime/aws-sig-auth/Cargo.toml @@ -16,6 +16,7 @@ aws-sigv4 = { path = "../aws-sigv4" } aws-smithy-eventstream = { path = "../../../rust-runtime/aws-smithy-eventstream", optional = true } aws-smithy-http = { path = "../../../rust-runtime/aws-smithy-http" } aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async" } +aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api" } aws-types = { path = "../aws-types" } http = "0.2.2" tracing = "0.1" @@ -23,9 +24,10 @@ tracing = "0.1" [dev-dependencies] aws-credential-types = { path = "../aws-credential-types", features = ["test-util"] } aws-endpoint = { path = "../aws-endpoint" } +aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async", features = ["test-util"] } aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types" } +pretty_assertions = "1.3" tracing-test = "0.2.4" -aws-smithy-async = { path = "../../../rust-runtime/aws-smithy-async", features = ["test-util"] } [package.metadata.docs.rs] all-features = true diff --git a/aws/rust-runtime/aws-sig-auth/src/event_stream.rs b/aws/rust-runtime/aws-sig-auth/src/event_stream.rs index bf51ac2723..60ac2e05f1 100644 --- a/aws/rust-runtime/aws-sig-auth/src/event_stream.rs +++ b/aws/rust-runtime/aws-sig-auth/src/event_stream.rs @@ -10,49 +10,48 @@ use crate::middleware::Signature; use aws_credential_types::Credentials; use aws_sigv4::event_stream::{sign_empty_message, sign_message}; -use aws_sigv4::SigningParams; +use aws_sigv4::sign::v4; use aws_smithy_eventstream::frame::{Message, SignMessage, SignMessageError}; use aws_smithy_http::property_bag::{PropertyBag, SharedPropertyBag}; +use aws_smithy_runtime_api::client::identity::Identity; use aws_types::region::SigningRegion; -use aws_types::SigningService; +use aws_types::SigningName; use std::time::SystemTime; /// Event Stream SigV4 signing implementation. #[derive(Debug)] pub struct SigV4MessageSigner { last_signature: String, - credentials: Credentials, + identity: Identity, signing_region: SigningRegion, - signing_service: SigningService, + signing_name: SigningName, time: Option, } impl SigV4MessageSigner { pub fn new( last_signature: String, - credentials: Credentials, + identity: Identity, signing_region: SigningRegion, - signing_service: SigningService, + signing_name: SigningName, time: Option, ) -> Self { Self { last_signature, - credentials, + identity, signing_region, - signing_service, + signing_name, time, } } - fn signing_params(&self) -> SigningParams<()> { - let mut builder = SigningParams::builder() - .access_key(self.credentials.access_key_id()) - .secret_key(self.credentials.secret_access_key()) + fn signing_params(&self) -> v4::SigningParams<()> { + let builder = v4::SigningParams::builder() + .identity(self.identity.clone()) .region(self.signing_region.as_ref()) - .service_name(self.signing_service.as_ref()) + .name(self.signing_name.as_ref()) .time(self.time.unwrap_or_else(SystemTime::now)) .settings(()); - builder.set_security_token(self.credentials.session_token()); builder.build().unwrap() } } @@ -61,7 +60,7 @@ impl SignMessage for SigV4MessageSigner { fn sign(&mut self, message: Message) -> Result { let (signed_message, signature) = { let params = self.signing_params(); - sign_message(&message, &self.last_signature, ¶ms).into_parts() + sign_message(&message, &self.last_signature, ¶ms)?.into_parts() }; self.last_signature = signature; Ok(signed_message) @@ -70,7 +69,9 @@ impl SignMessage for SigV4MessageSigner { fn sign_empty(&mut self) -> Option> { let (signed_message, signature) = { let params = self.signing_params(); - sign_empty_message(&self.last_signature, ¶ms).into_parts() + sign_empty_message(&self.last_signature, ¶ms) + .expect("signing an empty message will always succeed.") + .into_parts() }; self.last_signature = signature; Some(Ok(signed_message)) @@ -82,9 +83,10 @@ mod tests { use crate::event_stream::SigV4MessageSigner; use aws_credential_types::Credentials; use aws_smithy_eventstream::frame::{HeaderValue, Message, SignMessage}; + use aws_smithy_runtime_api::client::identity::Identity; use aws_types::region::Region; use aws_types::region::SigningRegion; - use aws_types::SigningService; + use aws_types::SigningName; use std::time::{Duration, UNIX_EPOCH}; fn check_send_sync(value: T) -> T { @@ -96,9 +98,9 @@ mod tests { let region = Region::new("us-east-1"); let mut signer = check_send_sync(SigV4MessageSigner::new( "initial-signature".into(), - Credentials::for_tests(), + Identity::new(Credentials::for_tests(), None), SigningRegion::from(region), - SigningService::from_static("transcribe"), + SigningName::from_static("transcribe"), Some(UNIX_EPOCH + Duration::new(1611160427, 0)), )); let mut signatures = Vec::new(); @@ -141,24 +143,22 @@ impl SigV4Signer { } } - fn signing_params(properties: &PropertyBag) -> SigningParams<()> { + fn signing_params(properties: &PropertyBag) -> v4::SigningParams<()> { // Every single one of these values would have been retrieved during the initial request, // so we can safely assume they all exist in the property bag at this point. let credentials = properties.get::().unwrap(); let region = properties.get::().unwrap(); - let signing_service = properties.get::().unwrap(); + let signing_name = properties.get::().unwrap(); let time = properties .get::() .copied() .unwrap_or_else(SystemTime::now); - let mut builder = SigningParams::builder() - .access_key(credentials.access_key_id()) - .secret_key(credentials.secret_access_key()) + let builder = v4::SigningParams::builder() + .identity(Identity::new(credentials.clone(), credentials.expiry())) .region(region.as_ref()) - .service_name(signing_service.as_ref()) + .name(signing_name.as_ref()) .time(time) .settings(()); - builder.set_security_token(credentials.session_token()); builder.build().unwrap() } } @@ -179,7 +179,7 @@ impl SignMessage for SigV4Signer { let (signed_message, signature) = { let params = Self::signing_params(&properties); - sign_message(&message, self.last_signature.as_ref().unwrap(), ¶ms).into_parts() + sign_message(&message, self.last_signature.as_ref().unwrap(), ¶ms)?.into_parts() }; self.last_signature = Some(signature); Ok(signed_message) @@ -193,7 +193,9 @@ impl SignMessage for SigV4Signer { } let (signed_message, signature) = { let params = Self::signing_params(&properties); - sign_empty_message(self.last_signature.as_ref().unwrap(), ¶ms).into_parts() + sign_empty_message(self.last_signature.as_ref().unwrap(), ¶ms) + .expect("signing an empty message will always succeed") + .into_parts() }; self.last_signature = Some(signature); Some(Ok(signed_message)) @@ -210,7 +212,7 @@ mod old_tests { use aws_smithy_http::property_bag::PropertyBag; use aws_types::region::Region; use aws_types::region::SigningRegion; - use aws_types::SigningService; + use aws_types::SigningName; use std::time::{Duration, UNIX_EPOCH}; #[test] @@ -219,7 +221,7 @@ mod old_tests { let mut properties = PropertyBag::new(); properties.insert(region.clone()); properties.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - properties.insert(SigningService::from_static("transcribe")); + properties.insert(SigningName::from_static("transcribe")); properties.insert(Credentials::for_tests()); properties.insert(SigningRegion::from(region)); properties.insert(Signature::new("initial-signature".into())); diff --git a/aws/rust-runtime/aws-sig-auth/src/lib.rs b/aws/rust-runtime/aws-sig-auth/src/lib.rs index 90cc88a7e3..6746c3321b 100644 --- a/aws/rust-runtime/aws-sig-auth/src/lib.rs +++ b/aws/rust-runtime/aws-sig-auth/src/lib.rs @@ -18,7 +18,7 @@ //! ```rust //! use aws_credential_types::Credentials; //! use aws_smithy_http::body::SdkBody; -//! use aws_types::SigningService; +//! use aws_types::SigningName; //! use aws_types::region::{Region, SigningRegion}; //! use std::time::{Duration, SystemTime, UNIX_EPOCH}; //! use aws_sig_auth::signer::{self, SigningError, OperationSigningConfig, HttpSignatureType, RequestConfig}; @@ -38,7 +38,7 @@ //! let request_config = RequestConfig { //! request_ts: timestamp, //! region: &SigningRegion::from(region), -//! service: &SigningService::from_static("rds-db"), +//! service: &SigningName::from_static("rds-db"), //! payload_override: None, //! }; //! let mut request = http::Request::builder() @@ -85,7 +85,7 @@ //! use aws_sig_auth::signer::{OperationSigningConfig, RequestConfig, SigV4Signer}; //! use aws_smithy_http::body::SdkBody; //! use aws_types::region::{Region, SigningRegion}; -//! use aws_types::SigningService; +//! use aws_types::SigningName; //! use std::error::Error; //! use std::time::SystemTime; //! async fn sign_request( @@ -98,7 +98,7 @@ //! let request_config = RequestConfig { //! request_ts: now, //! region: &SigningRegion::from(region), -//! service: &SigningService::from_static("execute-api"), +//! service: &SigningName::from_static("execute-api"), //! payload_override: None, //! }; //! signer.sign( diff --git a/aws/rust-runtime/aws-sig-auth/src/middleware.rs b/aws/rust-runtime/aws-sig-auth/src/middleware.rs index b901f3a856..03c41dc20f 100644 --- a/aws/rust-runtime/aws-sig-auth/src/middleware.rs +++ b/aws/rust-runtime/aws-sig-auth/src/middleware.rs @@ -14,7 +14,7 @@ use aws_credential_types::Credentials; use aws_sigv4::http_request::SignableBody; use aws_smithy_async::time::SharedTimeSource; use aws_types::region::SigningRegion; -use aws_types::SigningService; +use aws_types::SigningName; use crate::signer::{ OperationSigningConfig, RequestConfig, SigV4Signer, SigningError, SigningRequirements, @@ -49,10 +49,10 @@ impl AsRef for Signature { /// a signature. /// /// Prior to signing, the following fields MUST be present in the property bag: -/// - [`SigningRegion`](SigningRegion): The region used when signing the request, e.g. `us-east-1` -/// - [`SigningService`](SigningService): The name of the service to use when signing the request, e.g. `dynamodb` -/// - [`Credentials`](Credentials): Credentials to sign with -/// - [`OperationSigningConfig`](OperationSigningConfig): Operation specific signing configuration, e.g. +/// - [`SigningRegion`]: The region used when signing the request, e.g. `us-east-1` +/// - [`SigningName`]: The name of the service to use when signing the request, e.g. `dynamodb` +/// - [`Credentials`]: Credentials to sign with +/// - [`OperationSigningConfig`]: Operation specific signing configuration, e.g. /// changes to URL encoding behavior, or headers that must be omitted. /// - [`SharedTimeSource`]: The time source to use when signing the request. /// If any of these fields are missing, the middleware will return an error. @@ -71,7 +71,7 @@ impl SigV4SigningStage { enum SigningStageErrorKind { MissingCredentials, MissingSigningRegion, - MissingSigningService, + MissingSigningName, MissingSigningConfig, SigningFailure(SigningError), } @@ -91,8 +91,8 @@ impl Display for SigningStageError { MissingSigningRegion => { write!(f, "no signing region in the property bag") } - MissingSigningService => { - write!(f, "no signing service in the property bag") + MissingSigningName => { + write!(f, "no signing name in the property bag") } MissingSigningConfig => { write!(f, "no signing configuration in the property bag") @@ -109,7 +109,7 @@ impl Error for SigningStageError { ErrorKind::SigningFailure(err) => Some(err), ErrorKind::MissingCredentials | ErrorKind::MissingSigningRegion - | ErrorKind::MissingSigningService + | ErrorKind::MissingSigningName | ErrorKind::MissingSigningConfig => None, } } @@ -143,9 +143,9 @@ fn signing_config( let region = config .get::() .ok_or(SigningStageErrorKind::MissingSigningRegion)?; - let signing_service = config - .get::() - .ok_or(SigningStageErrorKind::MissingSigningService)?; + let signing_name = config + .get::() + .ok_or(SigningStageErrorKind::MissingSigningName)?; let payload_override = config.get::>(); let request_config = RequestConfig { request_ts: config @@ -154,7 +154,7 @@ fn signing_config( .unwrap_or_else(|| SharedTimeSource::default().now()), region, payload_override, - service: signing_service, + service: signing_name, }; Ok((operation_config, request_config, credentials)) } @@ -193,7 +193,10 @@ impl MapRequest for SigV4SigningStage { signer_sender .send(Box::new(EventStreamSigV4Signer::new( signature.as_ref().into(), - creds, + aws_smithy_runtime_api::client::identity::Identity::new( + creds.clone(), + creds.expiry(), + ), request_config.region.clone(), request_config.service.clone(), time_override, @@ -209,24 +212,23 @@ impl MapRequest for SigV4SigningStage { #[cfg(test)] mod test { - use std::convert::Infallible; - use std::time::{Duration, UNIX_EPOCH}; - - use aws_smithy_http::body::SdkBody; - use aws_smithy_http::middleware::MapRequest; - use aws_smithy_http::operation; - use http::header::AUTHORIZATION; - - use aws_credential_types::Credentials; - use aws_endpoint::AwsAuthStage; - use aws_smithy_async::time::SharedTimeSource; - use aws_types::region::{Region, SigningRegion}; - use aws_types::SigningService; - use crate::middleware::{ SigV4SigningStage, Signature, SigningStageError, SigningStageErrorKind, }; use crate::signer::{OperationSigningConfig, SigV4Signer}; + use aws_credential_types::Credentials; + use aws_endpoint::AwsAuthStage; + use aws_smithy_async::time::SharedTimeSource; + use aws_smithy_http::body::SdkBody; + use aws_smithy_http::middleware::MapRequest; + use aws_smithy_http::operation; + use aws_smithy_runtime_api::client::identity::Identity; + use aws_types::region::{Region, SigningRegion}; + use aws_types::SigningName; + use http::header::AUTHORIZATION; + use pretty_assertions::assert_eq; + use std::convert::Infallible; + use std::time::{Duration, UNIX_EPOCH}; #[test] fn places_signature_in_property_bag() { @@ -239,7 +241,7 @@ mod test { .augment(|req, properties| { properties.insert(region.clone()); properties.insert(UNIX_EPOCH + Duration::new(1611160427, 0)); - properties.insert(SigningService::from_static("kinesis")); + properties.insert(SigningName::from_static("kinesis")); properties.insert(OperationSigningConfig::default_config()); properties.insert(Credentials::for_tests()); properties.insert(SigningRegion::from(region)); @@ -273,9 +275,9 @@ mod test { properties.insert::(SharedTimeSource::new( UNIX_EPOCH + Duration::new(1611160427, 0), )); - properties.insert(SigningService::from_static("kinesis")); + properties.insert(SigningName::from_static("kinesis")); properties.insert(OperationSigningConfig::default_config()); - properties.insert(Credentials::for_tests()); + properties.insert(Credentials::for_tests_with_session_token()); properties.insert(SigningRegion::from(region.clone())); properties.insert(deferred_signer_sender); Result::<_, Infallible>::Ok(req) @@ -288,9 +290,9 @@ mod test { let mut signer_for_comparison = EventStreamSigV4Signer::new( // This is the expected SigV4 signature for the HTTP request above "abac477b4afabf5651079e7b9a0aa6a1a3e356a7418a81d974cdae9d4c8e5441".into(), - Credentials::for_tests(), + Identity::new(Credentials::for_tests_with_session_token(), None), SigningRegion::from(region), - SigningService::from_static("kinesis"), + SigningName::from_static("kinesis"), Some(UNIX_EPOCH + Duration::new(1611160427, 0)), ); @@ -317,7 +319,7 @@ mod test { conf.insert(SharedTimeSource::new( UNIX_EPOCH + Duration::new(1611160427, 0), )); - conf.insert(SigningService::from_static("kinesis")); + conf.insert(SigningName::from_static("kinesis")); conf.insert(endpoint); Result::<_, Infallible>::Ok(req) }) @@ -337,7 +339,8 @@ mod test { .apply(req.try_clone().expect("can clone")) .expect_err("no cred provider"), ); - req.properties_mut().insert(Credentials::for_tests()); + req.properties_mut() + .insert(Credentials::for_tests_with_session_token()); let req = signer.apply(req).expect("signing succeeded"); // make sure we got the correct error types in any order assert!(errs.iter().all(|el| matches!( diff --git a/aws/rust-runtime/aws-sig-auth/src/signer.rs b/aws/rust-runtime/aws-sig-auth/src/signer.rs index d71c6ecf42..127823889f 100644 --- a/aws/rust-runtime/aws-sig-auth/src/signer.rs +++ b/aws/rust-runtime/aws-sig-auth/src/signer.rs @@ -6,16 +6,19 @@ use aws_credential_types::Credentials; use aws_sigv4::http_request::{ sign, PayloadChecksumKind, PercentEncodingMode, SessionTokenMode, SignableRequest, - SignatureLocation, SigningParams, SigningSettings, UriPathNormalizationMode, + SignatureLocation, SigningSettings, UriPathNormalizationMode, }; use aws_smithy_http::body::SdkBody; use aws_types::region::SigningRegion; -use aws_types::SigningService; +use aws_types::SigningName; use std::fmt; use std::time::{Duration, SystemTime}; use crate::middleware::Signature; pub use aws_sigv4::http_request::SignableBody; +use aws_sigv4::sign::v4; +use aws_smithy_runtime_api::client::identity::Identity; + pub type SigningError = aws_sigv4::http_request::SigningError; const EXPIRATION_WARNING: &str = "Presigned request will expire before the given \ @@ -101,14 +104,14 @@ pub struct SigningOptions { pub struct RequestConfig<'a> { pub request_ts: SystemTime, pub region: &'a SigningRegion, - pub service: &'a SigningService, + pub service: &'a SigningName, pub payload_override: Option<&'a SignableBody<'static>>, } #[derive(Clone, Default)] pub struct SigV4Signer { - // In the future, the SigV4Signer will use the CRT signer. This will require constructing - // and holding an instance of the signer, so prevent people from constructing a SigV4Signer without + // In the future, the SigV4Signer may use the CRT signer. This will require constructing + // and holding an instance of the signer. Therefore, we must prevent people from constructing a SigV4Signer without // going through the constructor. _private: (), } @@ -160,7 +163,7 @@ impl SigV4Signer { settings: SigningSettings, credentials: &'a Credentials, request_config: &'a RequestConfig<'a>, - ) -> SigningParams<'a> { + ) -> v4::SigningParams<'a, SigningSettings> { if let Some(expires_in) = settings.expires_in { if let Some(creds_expires_time) = credentials.expiry() { let presigned_expires_time = request_config.request_ts + expires_in; @@ -170,14 +173,12 @@ impl SigV4Signer { } } - let mut builder = SigningParams::builder() - .access_key(credentials.access_key_id()) - .secret_key(credentials.secret_access_key()) + let builder = v4::SigningParams::builder() + .identity(Identity::new(credentials.clone(), credentials.expiry())) .region(request_config.region.as_ref()) - .service_name(request_config.service.as_ref()) + .name(request_config.service.as_ref()) .time(request_config.request_ts) .settings(settings); - builder.set_security_token(credentials.session_token()); builder.build().expect("all required fields set") } @@ -217,7 +218,7 @@ impl SigV4Signer { request.headers(), signable_body, ); - sign(signable_request, &signing_params)? + sign(signable_request, &signing_params.into())? } .into_parts(); @@ -233,7 +234,7 @@ mod tests { use aws_credential_types::Credentials; use aws_sigv4::http_request::SigningSettings; use aws_types::region::SigningRegion; - use aws_types::SigningService; + use aws_types::SigningName; use std::time::{Duration, SystemTime}; use tracing_test::traced_test; @@ -256,7 +257,7 @@ mod tests { let request_config = RequestConfig { request_ts: now, region: &SigningRegion::from_static("test"), - service: &SigningService::from_static("test"), + service: &SigningName::from_static("test"), payload_override: None, }; SigV4Signer::signing_params(settings, &credentials, &request_config); diff --git a/aws/rust-runtime/aws-sigv4/Cargo.toml b/aws/rust-runtime/aws-sigv4/Cargo.toml index ea54025552..3bf42131f2 100644 --- a/aws/rust-runtime/aws-sigv4/Cargo.toml +++ b/aws/rust-runtime/aws-sigv4/Cargo.toml @@ -4,37 +4,50 @@ version = "0.0.0-smithy-rs-head" authors = ["AWS Rust SDK Team ", "David Barsky "] description = "SigV4 signer for HTTP requests and Event Stream messages." edition = "2021" -exclude = ["aws-sig-v4-test-suite/*"] +exclude = ["aws-sig-v4-test-suite/*", "aws-sig-v4a-test-suite/*"] license = "Apache-2.0" repository = "https://github.com/awslabs/smithy-rs" [features] sign-http = ["http", "percent-encoding", "form_urlencoded"] -sign-eventstream = ["aws-smithy-eventstream", "bytes"] +sign-eventstream = ["aws-smithy-eventstream"] default = ["sign-http"] +sigv4a = ["p256", "num-bigint", "zeroize", "aws-smithy-types"] [dependencies] aws-smithy-eventstream = { path = "../../../rust-runtime/aws-smithy-eventstream", optional = true } aws-smithy-http = { path = "../../../rust-runtime/aws-smithy-http" } -bytes = { version = "1", optional = true } +aws-smithy-runtime-api = { path = "../../../rust-runtime/aws-smithy-runtime-api", features = ["client"] } +aws-smithy-types = { path = "../../../rust-runtime/aws-smithy-types", optional = true } +aws-credential-types = { path = "../aws-credential-types" } +bytes = "1" form_urlencoded = { version = "1.0", optional = true } hex = "0.4" +hmac = "0.12" http = { version = "0.2", optional = true } +num-bigint = { version = "0.4", optional = true } once_cell = "1.8" +p256 = { version = "0.13.2", features = ["ecdsa"], optional = true } percent-encoding = { version = "2.1", optional = true } regex = "1.5" +ring = "0.16" +sha2 = "0.10" time = "0.3.5" tracing = "0.1" -hmac = "0.12" -sha2 = "0.10" +zeroize = { version = "^1", optional = true } [dev-dependencies] +aws-credential-types = { path = "../aws-credential-types", features = ["test-util", "hardcoded-credentials"] } criterion = "0.4" -bytes = "1" -httparse = "1.5" +hex-literal = "0.4.1" +httparse = "1.8" +libfuzzer-sys = "0.4.6" pretty_assertions = "1.3" proptest = "1.2" -time = { version = "0.3.4", features = ["parsing"] } +serde = "1.0.180" +serde_derive = "1.0.180" +serde_json = "1.0.104" +time = { version = "0.3.5", features = ["parsing"] } [target.'cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))'.dev-dependencies] ring = "0.16" @@ -43,6 +56,10 @@ ring = "0.16" name = "hmac" harness = false +[[bench]] +name = "sigv4a" +harness = false + [package.metadata.docs.rs] all-features = true targets = ["x86_64-unknown-linux-gnu"] diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/double-encode-path/double-encode-path.sreq b/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/double-encode-path/double-encode-path.sreq index 860ac5966d..2c61e69ee7 100644 --- a/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/double-encode-path/double-encode-path.sreq +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/double-encode-path/double-encode-path.sreq @@ -1,4 +1,4 @@ POST /test/@connections/JBDvjfGEIAMCERw%3D HTTP/1.1 X-amz-date:20150830T123600Z -Authorization:AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=6f871eb157f326fa5f7439eb88ca200048635950ce7d6037deda56f0c95d4364 +Authorization:AWS4-HMAC-SHA256 Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=57d157672191bac40bae387e48bbe14b15303c001fdbb01f4abf295dccb09705 Host:tj9n5r0m12.execute-api.us-east-1.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.qpsreq b/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.qpsreq index 3549284538..b29c1e0755 100644 --- a/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.qpsreq +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.qpsreq @@ -1,2 +1,2 @@ -GET /?Param2=value2&Param1=value1&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fus-east-1%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=35&X-Amz-SignedHeaders=host&X-Amz-Signature=f25aea20f8c722ece3b363fc5d60cc91add973f9b64c42ba36fa28d57afe9019 HTTP/1.1 +GET /?Param2=value2&Param1=value1&X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=ANOTREAL%2F20150830%2Fus-east-1%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=35&X-Amz-SignedHeaders=host&X-Amz-Signature=ecce208e4b4f7d7e3a4cc22ced6acc2ad1d170ee8ba87d7165f6fa4b9aff09ab HTTP/1.1 Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.sreq b/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.sreq index dff7414558..e55b6b8cec 100644 --- a/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.sreq +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4-test-suite/get-vanilla-query-order-key-case/get-vanilla-query-order-key-case.sreq @@ -1,4 +1,4 @@ GET /?Param2=value2&Param1=value1 HTTP/1.1 Host:example.amazonaws.com X-Amz-Date:20150830T123600Z -Authorization: AWS4-HMAC-SHA256 Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=b97d918cfa904a5beff61c982a1b6f458b799221646efd99d3219ec94cdf2500 +Authorization: AWS4-HMAC-SHA256 Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, SignedHeaders=host;x-amz-date, Signature=5557820e7380d585310524bd93d51a08d7757fb5efd7344ee12088f2b0860947 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/header-canonical-request.txt new file mode 100644 index 0000000000..ccb5f43748 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/header-canonical-request.txt @@ -0,0 +1,10 @@ +GET +/ + +host:example.amazonaws.com +my-header1:value2,value2,value1 +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;my-header1;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/header-string-to-sign.txt new file mode 100644 index 0000000000..8783461a4d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +30f1f7b639b7fd5982a0f700e6d23bf7bb24f2f1d9e1314005bf22130da61cdf diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/query-canonical-request.txt new file mode 100644 index 0000000000..9561297c7a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/query-canonical-request.txt @@ -0,0 +1,8 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host%3Bmy-header1 +host:example.amazonaws.com +my-header1:value2,value2,value1 + +host;my-header1 +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/query-string-to-sign.txt new file mode 100644 index 0000000000..3140f6f64d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +a6e21a0099c98cbb4ec73928a08e8b116dfd634c471a8c03c4007b5258b664ea diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/request.txt new file mode 100644 index 0000000000..40455cec6f --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-key-duplicate/request.txt @@ -0,0 +1,5 @@ +GET / HTTP/1.1 +Host:example.amazonaws.com +My-Header1:value2 +My-Header1:value2 +My-Header1:value1 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/header-canonical-request.txt new file mode 100644 index 0000000000..93751930e4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/header-canonical-request.txt @@ -0,0 +1,10 @@ +GET +/ + +host:example.amazonaws.com +my-header1:value4,value1,value3,value2 +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;my-header1;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/header-string-to-sign.txt new file mode 100644 index 0000000000..6400baf52b --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +e1c3b5d34632ffff080330b3bc31906c8988bf1683f4af689ef3f1811952df36 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/query-canonical-request.txt new file mode 100644 index 0000000000..ecf494a365 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/query-canonical-request.txt @@ -0,0 +1,8 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host%3Bmy-header1 +host:example.amazonaws.com +my-header1:value4,value1,value3,value2 + +host;my-header1 +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/query-string-to-sign.txt new file mode 100644 index 0000000000..b58417973a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +e2bf35ea25a1943bf52cfc8348c787db8fd8ca642dc9f2b9443939c2fb0d3c54 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/request.txt new file mode 100644 index 0000000000..2c6f49d369 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-order/request.txt @@ -0,0 +1,6 @@ +GET / HTTP/1.1 +Host:example.amazonaws.com +My-Header1:value4 +My-Header1:value1 +My-Header1:value3 +My-Header1:value2 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/header-canonical-request.txt new file mode 100644 index 0000000000..e91e952419 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/header-canonical-request.txt @@ -0,0 +1,11 @@ +GET +/ + +host:example.amazonaws.com +my-header1:value1 +my-header2:"a b c" +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;my-header1;my-header2;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/header-string-to-sign.txt new file mode 100644 index 0000000000..0e407d8557 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +18b43001be9b531ebdd8202144dbd7630ea8a35bc328a7d0e561dda03a876095 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/query-canonical-request.txt new file mode 100644 index 0000000000..8a3b042ca9 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/query-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host%3Bmy-header1%3Bmy-header2 +host:example.amazonaws.com +my-header1:value1 +my-header2:"a b c" + +host;my-header1;my-header2 +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/query-string-to-sign.txt new file mode 100644 index 0000000000..5eead2534d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +4f92ebcf5f0844588e443a2243fafdb64319c6d1ad913c07686129b9991326a3 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/request.txt new file mode 100644 index 0000000000..ad1ea98677 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-header-value-trim/request.txt @@ -0,0 +1,4 @@ +GET / HTTP/1.1 +Host:example.amazonaws.com +My-Header1: value1 +My-Header2: "a b c" diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/header-canonical-request.txt new file mode 100644 index 0000000000..47e71285fd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/header-string-to-sign.txt new file mode 100644 index 0000000000..95d7219c28 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cf59db423e841c8b7e3444158185aa261b724a5c27cbe762676f3eed19f4dc02 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/query-canonical-request.txt new file mode 100644 index 0000000000..a34ea263b0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/query-string-to-sign.txt new file mode 100644 index 0000000000..48f855c312 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +890c4ed28c1a1ac10b5862719b537afbe392e987dc1aab1efa16fe7de41d3c81 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/request.txt new file mode 100644 index 0000000000..6aa9f995bd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-normalized/request.txt @@ -0,0 +1,2 @@ +GET /example/.. HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/header-canonical-request.txt new file mode 100644 index 0000000000..47e71285fd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/header-string-to-sign.txt new file mode 100644 index 0000000000..95d7219c28 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cf59db423e841c8b7e3444158185aa261b724a5c27cbe762676f3eed19f4dc02 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/query-canonical-request.txt new file mode 100644 index 0000000000..a34ea263b0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/query-string-to-sign.txt new file mode 100644 index 0000000000..48f855c312 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +890c4ed28c1a1ac10b5862719b537afbe392e987dc1aab1efa16fe7de41d3c81 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/request.txt new file mode 100644 index 0000000000..a856c10739 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-normalized/request.txt @@ -0,0 +1,2 @@ +GET /example1/example2/../.. HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/context.json new file mode 100644 index 0000000000..afe367bb17 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": false, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/header-canonical-request.txt new file mode 100644 index 0000000000..5e1d1cfcaa --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/example1/example2/../.. + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/header-string-to-sign.txt new file mode 100644 index 0000000000..1cca6cfb38 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +7bad1fab948577ec4e860ff2bb06ce9b69f0dd60eb8a9ad7c016b584254f9b5b diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/query-canonical-request.txt new file mode 100644 index 0000000000..95dc10402d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/example1/example2/../.. +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/query-string-to-sign.txt new file mode 100644 index 0000000000..50edce6de3 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +504892d7f7262dd98d79ab7f3bb6f918cd59d491aacb2d76450f6e065479b31a diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/request.txt new file mode 100644 index 0000000000..a856c10739 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-relative-unnormalized/request.txt @@ -0,0 +1,2 @@ +GET /example1/example2/../.. HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/context.json new file mode 100644 index 0000000000..afe367bb17 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": false, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/header-canonical-request.txt new file mode 100644 index 0000000000..d6a0abe36f --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/example/.. + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/header-string-to-sign.txt new file mode 100644 index 0000000000..4a34e93717 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +c859b5032f2ebd5df0285ff633b495b0e6e962e5adb94731c95e8e993a9a8213 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/query-canonical-request.txt new file mode 100644 index 0000000000..b1d123ed95 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/example/.. +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/query-string-to-sign.txt new file mode 100644 index 0000000000..a17f5abdbb --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +bbbb3668f996906ebb2c96ebdc2418af99656315adaf647989ab336c88fb516e diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/request.txt new file mode 100644 index 0000000000..6aa9f995bd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-relative-unnormalized/request.txt @@ -0,0 +1,2 @@ +GET /example/.. HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/header-canonical-request.txt new file mode 100644 index 0000000000..47e71285fd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/header-string-to-sign.txt new file mode 100644 index 0000000000..95d7219c28 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cf59db423e841c8b7e3444158185aa261b724a5c27cbe762676f3eed19f4dc02 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/query-canonical-request.txt new file mode 100644 index 0000000000..a34ea263b0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/query-string-to-sign.txt new file mode 100644 index 0000000000..48f855c312 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +890c4ed28c1a1ac10b5862719b537afbe392e987dc1aab1efa16fe7de41d3c81 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/request.txt new file mode 100644 index 0000000000..2c5ff3851e --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-normalized/request.txt @@ -0,0 +1,2 @@ +GET /./ HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/context.json new file mode 100644 index 0000000000..afe367bb17 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": false, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/header-canonical-request.txt new file mode 100644 index 0000000000..d05303d006 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/./ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/header-string-to-sign.txt new file mode 100644 index 0000000000..e1bfb399af --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +a14dce0217a32357c623c3db790988b6b5aa1494a527158b06d3ca4444561a4b diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/query-canonical-request.txt new file mode 100644 index 0000000000..f048d0fe58 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/./ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/query-string-to-sign.txt new file mode 100644 index 0000000000..bfcf245534 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +0d146fed00cdf50d7a87864583b7a33ca75322aab46b0a2d204f5d0c13440917 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/request.txt new file mode 100644 index 0000000000..2c5ff3851e --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-dot-slash-unnormalized/request.txt @@ -0,0 +1,2 @@ +GET /./ HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/header-canonical-request.txt new file mode 100644 index 0000000000..47e71285fd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/header-string-to-sign.txt new file mode 100644 index 0000000000..95d7219c28 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cf59db423e841c8b7e3444158185aa261b724a5c27cbe762676f3eed19f4dc02 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/query-canonical-request.txt new file mode 100644 index 0000000000..a34ea263b0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/query-string-to-sign.txt new file mode 100644 index 0000000000..48f855c312 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +890c4ed28c1a1ac10b5862719b537afbe392e987dc1aab1efa16fe7de41d3c81 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/request.txt new file mode 100644 index 0000000000..25bc21e36f --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-normalized/request.txt @@ -0,0 +1,2 @@ +GET // HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/header-canonical-request.txt new file mode 100644 index 0000000000..2e36c2065a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/example + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/header-string-to-sign.txt new file mode 100644 index 0000000000..cd30e8b5c0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +823cb165e35e124f862c99c89a46414c24e3800f149377591e35a4848317e825 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/query-canonical-request.txt new file mode 100644 index 0000000000..77cf28df87 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/example +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/query-string-to-sign.txt new file mode 100644 index 0000000000..49d9b24a72 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +0cc67a8acfed5946b645794c649dd98d3485728119cdf17d38985ba0ff55abca diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/request.txt new file mode 100644 index 0000000000..5d919c9ba6 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-normalized/request.txt @@ -0,0 +1,2 @@ +GET /./example HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/context.json new file mode 100644 index 0000000000..afe367bb17 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": false, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/header-canonical-request.txt new file mode 100644 index 0000000000..44448421e1 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/./example + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/header-string-to-sign.txt new file mode 100644 index 0000000000..cc63510cad --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +407314cdff397462b2458ba1860907adefcbb73fd630ddbd3de7300d2f773804 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/query-canonical-request.txt new file mode 100644 index 0000000000..ed2cb2d8b1 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/./example +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/query-string-to-sign.txt new file mode 100644 index 0000000000..c9f3b6ddac --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +efbe4f47c2acbb53fbfd0be6846cfa35a48c21f3f800e741278dae7b721302b4 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/request.txt new file mode 100644 index 0000000000..5d919c9ba6 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-pointless-dot-unnormalized/request.txt @@ -0,0 +1,2 @@ +GET /./example HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/context.json new file mode 100644 index 0000000000..afe367bb17 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": false, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/header-canonical-request.txt new file mode 100644 index 0000000000..8a4d33b0ba --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +// + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/header-string-to-sign.txt new file mode 100644 index 0000000000..874c01c1ee --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +fc8f42c7ce50ba8830a34b16d9fb478170176d78c81339e8d7e31d4baa9ec9f4 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/query-canonical-request.txt new file mode 100644 index 0000000000..81d7b0b157 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +// +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/query-string-to-sign.txt new file mode 100644 index 0000000000..17e5279ee7 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +633e0570a745c18cc22e43af8be65cfed3e7173061ec403353734bdfae90e0b6 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/request.txt new file mode 100644 index 0000000000..25bc21e36f --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slash-unnormalized/request.txt @@ -0,0 +1,2 @@ +GET // HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/header-canonical-request.txt new file mode 100644 index 0000000000..fdf9c48f5a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/example/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/header-string-to-sign.txt new file mode 100644 index 0000000000..8f9c95e66f --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +ea6c9c4bc1e85b94f2579cebbc85a84c3f8eaa055c006697555f074dd68509a6 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/query-canonical-request.txt new file mode 100644 index 0000000000..1046735a53 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/example/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/query-string-to-sign.txt new file mode 100644 index 0000000000..b293cc2be4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +ab3f7b8af0ce16e0faf508160fb13d890874992d74f36214ae9eec7437361f2b diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/request.txt new file mode 100644 index 0000000000..12e0931969 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-normalized/request.txt @@ -0,0 +1,2 @@ +GET //example// HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/context.json new file mode 100644 index 0000000000..afe367bb17 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": false, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/header-canonical-request.txt new file mode 100644 index 0000000000..a9c55f6215 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +//example// + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/header-string-to-sign.txt new file mode 100644 index 0000000000..5c4c2cd4a4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +bf8c459a6a7f3879f55bff41e4dca65f69df4628456904e47f83013c0deb7276 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/query-canonical-request.txt new file mode 100644 index 0000000000..c878ab4f56 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +//example// +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/query-string-to-sign.txt new file mode 100644 index 0000000000..5f596452cb --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +660b4a6f0bd53b287cefb21cdf69c1574303de44d2e9f7759b5379b428b70157 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/request.txt new file mode 100644 index 0000000000..12e0931969 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-slashes-unnormalized/request.txt @@ -0,0 +1,2 @@ +GET //example// HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/header-canonical-request.txt new file mode 100644 index 0000000000..b0db64880a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/header-string-to-sign.txt new file mode 100644 index 0000000000..20c7cd66a4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +b48c0f7d7cdaa2cd05e4b789c913063becd96ccace5296a334c950040e58bcac diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/query-canonical-request.txt new file mode 100644 index 0000000000..f9fb726476 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/query-string-to-sign.txt new file mode 100644 index 0000000000..ef06e89988 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +a967a5035e5dc574f94fb9f0de0faf9d56e889c26d9a65d7d0a15d89690280d1 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/request.txt new file mode 100644 index 0000000000..a149694b9c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-unreserved/request.txt @@ -0,0 +1,2 @@ +GET /-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/header-canonical-request.txt new file mode 100644 index 0000000000..bb9d4bfa6a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ +Param1=value1 +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/header-string-to-sign.txt new file mode 100644 index 0000000000..a176f1dfc7 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +894f4237e92aae973c992da1d1f39d7a5913a23e9f7cbcf085e9550685eb498a diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/query-canonical-request.txt new file mode 100644 index 0000000000..344384bdb7 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +Param1=value1&X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/query-string-to-sign.txt new file mode 100644 index 0000000000..b6250526be --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +07551f1d699afeb50d6811a527ab7b0270b60448ea27d8cbccb9750d68287b3f diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/request.txt new file mode 100644 index 0000000000..f4a03bb0ad --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-empty-query-key/request.txt @@ -0,0 +1,2 @@ +GET /?Param1=value1 HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/header-canonical-request.txt new file mode 100644 index 0000000000..74f625a145 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ +Param1=value1&Param2=value2 +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/header-string-to-sign.txt new file mode 100644 index 0000000000..44873b70da --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cc07b29e0d0f0b2d6aa296621a5608fd9c2271159b9b2f737f682704ebb96482 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/query-canonical-request.txt new file mode 100644 index 0000000000..6d30727353 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +Param1=value1&Param2=value2&X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/query-string-to-sign.txt new file mode 100644 index 0000000000..99d0510569 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +c688584c3dbae2868c4911c825239f2c9375e66b9962f21db60b9b2fcd75bf45 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/request.txt new file mode 100644 index 0000000000..1158ac4ebd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-order-key-case/request.txt @@ -0,0 +1,2 @@ +GET /?Param2=value2&Param1=value1 HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/header-canonical-request.txt new file mode 100644 index 0000000000..816c862301 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ +-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/header-string-to-sign.txt new file mode 100644 index 0000000000..6129fc52fe --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +377b8a3e195894659b84cd1c475dc8a3663a663360a349430c0c3b82bd82b77b diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/query-canonical-request.txt new file mode 100644 index 0000000000..b77ee9ffee --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz&X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/query-string-to-sign.txt new file mode 100644 index 0000000000..1cfed7a3cc --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +5d8923c620c699f856a35a6eb8dd786fd4c8c6ab0a35c552caeb5b648989433f diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/request.txt new file mode 100644 index 0000000000..36b2fe3ea4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query-unreserved/request.txt @@ -0,0 +1,2 @@ +GET /?-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=-._~0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/header-canonical-request.txt new file mode 100644 index 0000000000..47e71285fd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/header-string-to-sign.txt new file mode 100644 index 0000000000..95d7219c28 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cf59db423e841c8b7e3444158185aa261b724a5c27cbe762676f3eed19f4dc02 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/query-canonical-request.txt new file mode 100644 index 0000000000..a34ea263b0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/query-string-to-sign.txt new file mode 100644 index 0000000000..48f855c312 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +890c4ed28c1a1ac10b5862719b537afbe392e987dc1aab1efa16fe7de41d3c81 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/request.txt new file mode 100644 index 0000000000..e659c3be2c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-query/request.txt @@ -0,0 +1,2 @@ +GET / HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/context.json new file mode 100644 index 0000000000..a457c8a662 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/context.json @@ -0,0 +1,13 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", + "token": "6e86291e8372ff2a2260956d9b8aae1d763fbf315fa00fa31553b73ebf194267" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/header-canonical-request.txt new file mode 100644 index 0000000000..f14defd893 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/header-canonical-request.txt @@ -0,0 +1,10 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 +x-amz-security-token:6e86291e8372ff2a2260956d9b8aae1d763fbf315fa00fa31553b73ebf194267 + +host;x-amz-date;x-amz-region-set;x-amz-security-token +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/header-string-to-sign.txt new file mode 100644 index 0000000000..4edece5422 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +79893373104239a0547df489af395ec3c1b8873a8601f07f11ffd3f1ac557e7d diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/query-canonical-request.txt new file mode 100644 index 0000000000..7c042af70c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-Security-Token=6e86291e8372ff2a2260956d9b8aae1d763fbf315fa00fa31553b73ebf194267&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/query-string-to-sign.txt new file mode 100644 index 0000000000..0fd066ab75 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +496062b4c2ed2175fe08ad084158783fa8d013c694542af721d49b25d1ebd390 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/request.txt new file mode 100644 index 0000000000..e659c3be2c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla-with-session-token/request.txt @@ -0,0 +1,2 @@ +GET / HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/canonical-request.txt new file mode 100644 index 0000000000..47e71285fd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/header-canonical-request.txt new file mode 100644 index 0000000000..47e71285fd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/header-canonical-request.txt @@ -0,0 +1,9 @@ +GET +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/header-string-to-sign.txt new file mode 100644 index 0000000000..95d7219c28 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cf59db423e841c8b7e3444158185aa261b724a5c27cbe762676f3eed19f4dc02 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/query-canonical-request.txt new file mode 100644 index 0000000000..a34ea263b0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/query-canonical-request.txt @@ -0,0 +1,7 @@ +GET +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/query-string-to-sign.txt new file mode 100644 index 0000000000..48f855c312 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +890c4ed28c1a1ac10b5862719b537afbe392e987dc1aab1efa16fe7de41d3c81 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/request.txt new file mode 100644 index 0000000000..e659c3be2c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/request.txt @@ -0,0 +1,2 @@ +GET / HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/string-to-sign.txt new file mode 100644 index 0000000000..95d7219c28 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/get-vanilla/string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +cf59db423e841c8b7e3444158185aa261b724a5c27cbe762676f3eed19f4dc02 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/header-canonical-request.txt new file mode 100644 index 0000000000..a6942c1171 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/header-canonical-request.txt @@ -0,0 +1,9 @@ +POST +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/header-string-to-sign.txt new file mode 100644 index 0000000000..d5650cb879 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +806a9b01b76472cc6b66fff02630726d55f8b4ada6d2fd9b36eb0d710e215861 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/query-canonical-request.txt new file mode 100644 index 0000000000..e48ce070ae --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/query-canonical-request.txt @@ -0,0 +1,7 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/query-string-to-sign.txt new file mode 100644 index 0000000000..34e3382b43 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +192546340393592ef9baaa24656f55ed91288110e7514b50f0a3f79bb761a29c diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/request.txt new file mode 100644 index 0000000000..3f0a82a268 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-case/request.txt @@ -0,0 +1,2 @@ +POST / HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/header-canonical-request.txt new file mode 100644 index 0000000000..a8e1727ba4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/header-canonical-request.txt @@ -0,0 +1,10 @@ +POST +/ + +host:example.amazonaws.com +my-header1:value1 +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;my-header1;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/header-string-to-sign.txt new file mode 100644 index 0000000000..f6e3e9b158 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +b92b1e85236a12f9d118f85fb6686c83b0e83fb3428f8d4da3cc9acb2851fcfa diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/query-canonical-request.txt new file mode 100644 index 0000000000..0ae73e130b --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/query-canonical-request.txt @@ -0,0 +1,8 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host%3Bmy-header1 +host:example.amazonaws.com +my-header1:value1 + +host;my-header1 +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/query-string-to-sign.txt new file mode 100644 index 0000000000..8cb96bfd5a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +336638ab840d4785edc7db35ab9c036bc15ffb2dc1a4e05b04f3a7cd7407593f diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/request.txt new file mode 100644 index 0000000000..917720efcb --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-key-sort/request.txt @@ -0,0 +1,3 @@ +POST / HTTP/1.1 +Host:example.amazonaws.com +My-Header1:value1 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/header-canonical-request.txt new file mode 100644 index 0000000000..1dc3ef8e8c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/header-canonical-request.txt @@ -0,0 +1,10 @@ +POST +/ + +host:example.amazonaws.com +my-header1:VALUE1 +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;my-header1;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/header-string-to-sign.txt new file mode 100644 index 0000000000..59c7e45e2a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +7de5a74bc45fb5c8a90faada2ab9538e69e4a5eb7f330f62387715669cecd492 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/query-canonical-request.txt new file mode 100644 index 0000000000..377e6f3b6c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/query-canonical-request.txt @@ -0,0 +1,8 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host%3Bmy-header1 +host:example.amazonaws.com +my-header1:VALUE1 + +host;my-header1 +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/query-string-to-sign.txt new file mode 100644 index 0000000000..84a7afd6dc --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +949fb555e05d3289760ff0f0566ad73a69ed865000d9843b93a15b916dbc8b6f diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/request.txt new file mode 100644 index 0000000000..5f14c91595 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-header-value-case/request.txt @@ -0,0 +1,3 @@ +POST / HTTP/1.1 +Host:example.amazonaws.com +My-Header1:VALUE1 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/context.json new file mode 100644 index 0000000000..8f1d5ced76 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/context.json @@ -0,0 +1,14 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", + "token": "AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z", + "omit_session_token": true +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/header-canonical-request.txt new file mode 100644 index 0000000000..a6942c1171 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/header-canonical-request.txt @@ -0,0 +1,9 @@ +POST +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/header-string-to-sign.txt new file mode 100644 index 0000000000..d5650cb879 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +806a9b01b76472cc6b66fff02630726d55f8b4ada6d2fd9b36eb0d710e215861 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/query-canonical-request.txt new file mode 100644 index 0000000000..e48ce070ae --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/query-canonical-request.txt @@ -0,0 +1,7 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/query-string-to-sign.txt new file mode 100644 index 0000000000..34e3382b43 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +192546340393592ef9baaa24656f55ed91288110e7514b50f0a3f79bb761a29c diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/request.txt new file mode 100644 index 0000000000..3f0a82a268 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-after/request.txt @@ -0,0 +1,2 @@ +POST / HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/context.json new file mode 100644 index 0000000000..5187392c0a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/context.json @@ -0,0 +1,14 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", + "token": "AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA==" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z", + "omit_session_token": false +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/header-canonical-request.txt new file mode 100644 index 0000000000..dd408c84e0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/header-canonical-request.txt @@ -0,0 +1,10 @@ +POST +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 +x-amz-security-token:AQoDYXdzEPT//////////wEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI/qkPpKPi/kMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d+xo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz+scqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR/oLxBA== + +host;x-amz-date;x-amz-region-set;x-amz-security-token +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/header-string-to-sign.txt new file mode 100644 index 0000000000..f352b5416c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +964c15d46a67b327b877c02d680c81cb75df04e85144142e190da565ff0d029f diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/query-canonical-request.txt new file mode 100644 index 0000000000..832cdc0504 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/query-canonical-request.txt @@ -0,0 +1,7 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-Security-Token=AQoDYXdzEPT%2F%2F%2F%2F%2F%2F%2F%2F%2F%2FwEXAMPLEtc764bNrC9SAPBSM22wDOk4x4HIZ8j4FZTwdQWLWsKWHGBuFqwAeMicRXmxfpSPfIeoIYRqTflfKD8YUuwthAx7mSEI%2FqkPpKPi%2FkMcGdQrmGdeehM4IC1NtBmUpp2wUE8phUZampKsburEDy0KPkyQDYwT7WZ0wq5VSXDvp75YU9HFvlRd8Tx6q6fE8YQcHNVXAkiY9q6d%2Bxo0rKwT38xVqr7ZD0u0iPPkUL64lIZbqBAz%2BscqKmlzm8FDrypNC9Yjc8fPOLn9FX9KSYvKTr4rvx3iSIlTJabIQwj2ICCR%2FoLxBA%3D%3D&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/query-string-to-sign.txt new file mode 100644 index 0000000000..d7f36687c4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +c3a8ba26c461df46b5010b756fb8644fd922a2aea95d77b56295e5e4d3bb155f diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/request.txt new file mode 100644 index 0000000000..3f0a82a268 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-sts-header-before/request.txt @@ -0,0 +1,2 @@ +POST / HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/header-canonical-request.txt new file mode 100644 index 0000000000..02af60fb2e --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/header-canonical-request.txt @@ -0,0 +1,9 @@ +POST +/ +Param1=value1 +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/header-string-to-sign.txt new file mode 100644 index 0000000000..4256b4ff1b --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +502dea2656f02eea10bd05eeec315ea1a6686ed2861176e1670b2d67e17b2f36 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/query-canonical-request.txt new file mode 100644 index 0000000000..fa84bbdc3d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/query-canonical-request.txt @@ -0,0 +1,7 @@ +POST +/ +Param1=value1&X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/query-string-to-sign.txt new file mode 100644 index 0000000000..de270efe06 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +b9ec8df7b378fbee58903f5c54bd50e80a4d2d5aa9532583910ce771e42574fe diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/request.txt new file mode 100644 index 0000000000..c9d6e5dfb0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-empty-query-value/request.txt @@ -0,0 +1,2 @@ +POST /?Param1=value1 HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/header-canonical-request.txt new file mode 100644 index 0000000000..02af60fb2e --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/header-canonical-request.txt @@ -0,0 +1,9 @@ +POST +/ +Param1=value1 +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/header-string-to-sign.txt new file mode 100644 index 0000000000..4256b4ff1b --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +502dea2656f02eea10bd05eeec315ea1a6686ed2861176e1670b2d67e17b2f36 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/query-canonical-request.txt new file mode 100644 index 0000000000..fa84bbdc3d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/query-canonical-request.txt @@ -0,0 +1,7 @@ +POST +/ +Param1=value1&X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/query-string-to-sign.txt new file mode 100644 index 0000000000..de270efe06 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +b9ec8df7b378fbee58903f5c54bd50e80a4d2d5aa9532583910ce771e42574fe diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/request.txt new file mode 100644 index 0000000000..c9d6e5dfb0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla-query/request.txt @@ -0,0 +1,2 @@ +POST /?Param1=value1 HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/context.json new file mode 100644 index 0000000000..45771c756d --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": false, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/header-canonical-request.txt new file mode 100644 index 0000000000..a6942c1171 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/header-canonical-request.txt @@ -0,0 +1,9 @@ +POST +/ + +host:example.amazonaws.com +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +host;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/header-string-to-sign.txt new file mode 100644 index 0000000000..d5650cb879 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +806a9b01b76472cc6b66fff02630726d55f8b4ada6d2fd9b36eb0d710e215861 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/query-canonical-request.txt new file mode 100644 index 0000000000..e48ce070ae --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/query-canonical-request.txt @@ -0,0 +1,7 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=host +host:example.amazonaws.com + +host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/query-string-to-sign.txt new file mode 100644 index 0000000000..34e3382b43 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +192546340393592ef9baaa24656f55ed91288110e7514b50f0a3f79bb761a29c diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/request.txt new file mode 100644 index 0000000000..3f0a82a268 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-vanilla/request.txt @@ -0,0 +1,2 @@ +POST / HTTP/1.1 +Host:example.amazonaws.com diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/context.json new file mode 100644 index 0000000000..fc4bce6dc6 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": true, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/header-canonical-request.txt new file mode 100644 index 0000000000..05ab787e7e --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/header-canonical-request.txt @@ -0,0 +1,12 @@ +POST +/ + +content-length:13 +content-type:application/x-www-form-urlencoded; charset=utf-8 +host:example.amazonaws.com +x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/header-string-to-sign.txt new file mode 100644 index 0000000000..b6fdecfa4a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +03c5c4387e7c1bd3a606d1b19301d277e51d7621ced07c8c9ff2aeb151c0f4c6 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/query-canonical-request.txt new file mode 100644 index 0000000000..fcc454f230 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/query-canonical-request.txt @@ -0,0 +1,9 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=content-length%3Bcontent-type%3Bhost +content-length:13 +content-type:application/x-www-form-urlencoded; charset=utf-8 +host:example.amazonaws.com + +content-length;content-type;host +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/query-string-to-sign.txt new file mode 100644 index 0000000000..a300bea048 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +ab426c74406d082ad98929df8969624e6ed5cb7f4e8501fbbe7d8c20e9c3b417 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/request.txt new file mode 100644 index 0000000000..b711c25054 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded-parameters/request.txt @@ -0,0 +1,6 @@ +POST / HTTP/1.1 +Content-Type:application/x-www-form-urlencoded; charset=utf-8 +Host:example.amazonaws.com +Content-Length:13 + +Param1=value1 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/context.json b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/context.json new file mode 100644 index 0000000000..fc4bce6dc6 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/context.json @@ -0,0 +1,12 @@ +{ + "credentials": { + "access_key_id": "AKIDEXAMPLE", + "secret_access_key": "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY" + }, + "expiration_in_seconds": 3600, + "normalize": true, + "region": "us-east-1", + "service": "service", + "sign_body": true, + "timestamp": "2015-08-30T12:36:00Z" +} diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/header-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/header-canonical-request.txt new file mode 100644 index 0000000000..69009dc761 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/header-canonical-request.txt @@ -0,0 +1,12 @@ +POST +/ + +content-length:13 +content-type:application/x-www-form-urlencoded +host:example.amazonaws.com +x-amz-content-sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 +x-amz-date:20150830T123600Z +x-amz-region-set:us-east-1 + +content-length;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-region-set +e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/header-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/header-string-to-sign.txt new file mode 100644 index 0000000000..b6fdecfa4a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/header-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +03c5c4387e7c1bd3a606d1b19301d277e51d7621ced07c8c9ff2aeb151c0f4c6 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/query-canonical-request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/query-canonical-request.txt new file mode 100644 index 0000000000..9ed065b9e4 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/query-canonical-request.txt @@ -0,0 +1,9 @@ +POST +/ +X-Amz-Algorithm=AWS4-ECDSA-P256-SHA256&X-Amz-Credential=AKIDEXAMPLE%2F20150830%2Fservice%2Faws4_request&X-Amz-Date=20150830T123600Z&X-Amz-Expires=3600&X-Amz-Region-Set=us-east-1&X-Amz-SignedHeaders=content-length%3Bcontent-type%3Bhost +content-length:13 +content-type:application/x-www-form-urlencoded +host:example.amazonaws.com + +content-length;content-type;host +9095672bbd1f56dfc5b65f3e153adc8731a4a654192329106275f4c7b24d0b6e diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/query-string-to-sign.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/query-string-to-sign.txt new file mode 100644 index 0000000000..bef3143615 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/query-string-to-sign.txt @@ -0,0 +1,4 @@ +AWS4-ECDSA-P256-SHA256 +20150830T123600Z +20150830/service/aws4_request +4e4122984d30d13170a298ece62cc30f8da12578fb3b482616b1f11036b13934 diff --git a/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/request.txt b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/request.txt new file mode 100644 index 0000000000..00911020c0 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/aws-sig-v4a-test-suite/post-x-www-form-urlencoded/request.txt @@ -0,0 +1,6 @@ +POST / HTTP/1.1 +Content-Type:application/x-www-form-urlencoded +Host:example.amazonaws.com +Content-Length:13 + +Param1=value1 diff --git a/aws/rust-runtime/aws-sigv4/benches/sigv4a.rs b/aws/rust-runtime/aws-sigv4/benches/sigv4a.rs new file mode 100644 index 0000000000..26c1853cf2 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/benches/sigv4a.rs @@ -0,0 +1,28 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_sigv4::sign::v4a; +use criterion::{criterion_group, criterion_main, Criterion}; + +pub fn generate_signing_key(c: &mut Criterion) { + c.bench_function("generate_signing_key", |b| { + b.iter(|| { + let _ = v4a::generate_signing_key( + "AKIAIOSFODNN7EXAMPLE", + "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", + ); + }) + }); +} + +criterion_group! { + name = benches; + + config = Criterion::default(); + + targets = generate_signing_key +} + +criterion_main!(benches); diff --git a/aws/rust-runtime/aws-sigv4/fuzz/.gitignore b/aws/rust-runtime/aws-sigv4/fuzz/.gitignore new file mode 100644 index 0000000000..1a45eee776 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/fuzz/.gitignore @@ -0,0 +1,4 @@ +target +corpus +artifacts +coverage diff --git a/aws/rust-runtime/aws-sigv4/fuzz/Cargo.toml b/aws/rust-runtime/aws-sigv4/fuzz/Cargo.toml new file mode 100644 index 0000000000..aa200b249e --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/fuzz/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "aws-sigv4-fuzz" +version = "0.0.0" +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +arbitrary = "1.3" +derive_arbitrary = "1.3" +libfuzzer-sys = "0.4" + +[dependencies.aws-sigv4] +path = ".." +features = ["sigv4a"] + +# Prevent this from interfering with workspaces +[workspace] +members = ["."] + +[profile.release] +debug = 1 + +[[bin]] +name = "sigv4a" +path = "fuzz_targets/sigv4a.rs" +test = false +doc = false diff --git a/aws/rust-runtime/aws-sigv4/fuzz/fuzz_targets/sigv4a.rs b/aws/rust-runtime/aws-sigv4/fuzz/fuzz_targets/sigv4a.rs new file mode 100644 index 0000000000..9d69aa703a --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/fuzz/fuzz_targets/sigv4a.rs @@ -0,0 +1,20 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +#![no_main] + +use aws_sigv4::sign::v4a::generate_signing_key; +use libfuzzer_sys::fuzz_target; + +#[derive(derive_arbitrary::Arbitrary, Debug)] +struct Input { + access_key_id: String, + secret_access_key: String, +} + +fuzz_target!(|input: Input| { + // We're looking for panics + let _ = generate_signing_key(&input.access_key_id, &input.secret_access_key); +}); diff --git a/aws/rust-runtime/aws-sigv4/index.html b/aws/rust-runtime/aws-sigv4/index.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/aws/rust-runtime/aws-sigv4/src/event_stream.rs b/aws/rust-runtime/aws-sigv4/src/event_stream.rs index a8da19ab03..1d7925b1d0 100644 --- a/aws/rust-runtime/aws-sigv4/src/event_stream.rs +++ b/aws/rust-runtime/aws-sigv4/src/event_stream.rs @@ -8,9 +8,12 @@ //! # Example: Signing an event stream message //! //! ```rust -//! use aws_sigv4::event_stream::{sign_message, SigningParams}; +//! use aws_sigv4::event_stream::{sign_message}; //! use aws_smithy_eventstream::frame::{Header, HeaderValue, Message}; //! use std::time::SystemTime; +//! use aws_credential_types::Credentials; +//! use aws_sigv4::sign::v4; +//! use aws_smithy_runtime_api::client::identity::Identity; //! //! // The `last_signature` argument is the previous message's signature, or //! // the signature of the initial HTTP request if a message hasn't been signed yet. @@ -21,31 +24,44 @@ //! HeaderValue::String("value".into()), //! )); //! -//! let params = SigningParams::builder() -//! .access_key("example access key") -//! .secret_key("example secret key") +//! let params = v4::SigningParams::builder() +//! .identity( +//! Identity::new( +//! Credentials::new( +//! "AKIDEXAMPLE", +//! "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", +//! None, +//! None, +//! "hardcoded-credentials" +//! ), +//! None +//! ) +//! ) //! .region("us-east-1") -//! .service_name("exampleservice") +//! .name("exampleservice") //! .time(SystemTime::now()) //! .settings(()) //! .build() //! .unwrap(); //! //! // Use the returned `signature` to sign the next message. -//! let (signed, signature) = -//! sign_message(&message_to_sign, &last_signature, ¶ms).into_parts(); +//! let (signed, signature) = sign_message(&message_to_sign, &last_signature, ¶ms) +//! .expect("signing should succeed") +//! .into_parts(); //! ``` use crate::date_time::{format_date, format_date_time, truncate_subsecs}; -use crate::sign::{calculate_signature, generate_signing_key, sha256_hex_string}; +use crate::http_request::SigningError; +use crate::sign::v4::{calculate_signature, generate_signing_key, sha256_hex_string}; use crate::SigningOutput; +use aws_credential_types::Credentials; use aws_smithy_eventstream::frame::{write_headers_to, Header, HeaderValue, Message}; use bytes::Bytes; use std::io::Write; use std::time::SystemTime; /// Event stream signing parameters -pub type SigningParams<'a> = super::SigningParams<'a, ()>; +pub type SigningParams<'a> = crate::sign::v4::SigningParams<'a, ()>; /// Creates a string to sign for an Event Stream message. fn calculate_string_to_sign( @@ -65,7 +81,7 @@ fn calculate_string_to_sign( writeln!( sts, "{}/{}/{}/aws4_request", - date_str, params.region, params.service_name + date_str, params.region, params.name ) .unwrap(); writeln!(sts, "{}", last_signature).unwrap(); @@ -87,7 +103,7 @@ pub fn sign_message<'a>( message: &'a Message, last_signature: &'a str, params: &'a SigningParams<'a>, -) -> SigningOutput { +) -> Result, SigningError> { let message_payload = { let mut payload = Vec::new(); message.write_to(&mut payload).unwrap(); @@ -104,7 +120,7 @@ pub fn sign_message<'a>( pub fn sign_empty_message<'a>( last_signature: &'a str, params: &'a SigningParams<'a>, -) -> SigningOutput { +) -> Result, SigningError> { sign_payload(None, last_signature, params) } @@ -112,13 +128,17 @@ fn sign_payload<'a>( message_payload: Option>, last_signature: &'a str, params: &'a SigningParams<'a>, -) -> SigningOutput { +) -> Result, SigningError> { // Truncate the sub-seconds up front since the timestamp written to the signed message header // needs to exactly match the string formatted timestamp, which doesn't include sub-seconds. let time = truncate_subsecs(params.time); + let creds = params + .identity + .data::() + .ok_or_else(SigningError::unsupported_identity_type)?; let signing_key = - generate_signing_key(params.secret_key, time, params.region, params.service_name); + generate_signing_key(creds.secret_access_key(), time, params.region, params.name); let string_to_sign = calculate_string_to_sign( message_payload.as_ref().map(|v| &v[..]).unwrap_or(&[]), last_signature, @@ -129,7 +149,7 @@ fn sign_payload<'a>( tracing::trace!(canonical_request = ?message_payload, string_to_sign = ?string_to_sign, "calculated signing parameters"); // Generate the signed wrapper event frame - SigningOutput::new( + Ok(SigningOutput::new( Message::new(message_payload.map(Bytes::from).unwrap_or_else(Bytes::new)) .add_header(Header::new( ":chunk-signature", @@ -137,12 +157,16 @@ fn sign_payload<'a>( )) .add_header(Header::new(":date", HeaderValue::Timestamp(time.into()))), signature, - ) + )) } #[cfg(test)] mod tests { - use super::*; + use crate::event_stream::{calculate_string_to_sign, sign_message, SigningParams}; + use crate::sign::v4::sha256_hex_string; + use aws_credential_types::Credentials; + use aws_smithy_eventstream::frame::{Header, HeaderValue, Message}; + use aws_smithy_runtime_api::client::identity::Identity; use std::time::{Duration, UNIX_EPOCH}; #[test] @@ -155,11 +179,9 @@ mod tests { message_to_sign.write_to(&mut message_payload).unwrap(); let params = SigningParams { - access_key: "fake access key", - secret_key: "fake secret key", - security_token: None, + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "testservice", + name: "testservice", time: (UNIX_EPOCH + Duration::new(123_456_789_u64, 1234u32)), settings: (), }; @@ -193,18 +215,17 @@ mod tests { HeaderValue::String("value".into()), )); let params = SigningParams { - access_key: "fake access key", - secret_key: "fake secret key", - security_token: None, + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "testservice", + name: "testservice", time: (UNIX_EPOCH + Duration::new(123_456_789_u64, 1234u32)), settings: (), }; let last_signature = sha256_hex_string(b"last message sts"); - let (signed, signature) = - sign_message(&message_to_sign, &last_signature, ¶ms).into_parts(); + let (signed, signature) = sign_message(&message_to_sign, &last_signature, ¶ms) + .unwrap() + .into_parts(); assert_eq!(":chunk-signature", signed.headers()[0].name().as_str()); if let HeaderValue::ByteArray(bytes) = signed.headers()[0].value() { assert_eq!(signature, hex::encode(bytes)); diff --git a/aws/rust-runtime/aws-sigv4/src/http_request.rs b/aws/rust-runtime/aws-sigv4/src/http_request.rs new file mode 100644 index 0000000000..f41da0b57c --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/src/http_request.rs @@ -0,0 +1,225 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Utilities to sign HTTP requests. +//! +//! # Example: Signing an HTTP request +//! +//! ```rust +//! # use aws_smithy_runtime_api::client::identity::Identity; +//! fn test() -> Result<(), aws_sigv4::http_request::SigningError> { +//! use aws_sigv4::http_request::{SigningSettings, SigningParams, SignableRequest}; +//! use http; +//! use std::time::SystemTime; +//! use aws_credential_types::Credentials; +//! +//! // Create the request to sign +//! let mut request = http::Request::builder() +//! .uri("https://some-endpoint.some-region.amazonaws.com") +//! .body("") +//! .unwrap(); +//! +//! // Set up information and settings for the signing +//! let signing_settings = SigningSettings::default(); +//! let signing_params = aws_sigv4::sign::v4::SigningParams::builder() +//! .identity( +//! Identity::new( +//! Credentials::new( +//! "AKIDEXAMPLE", +//! "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", +//! None, +//! None, +//! "hardcoded-credentials" +//! ), +//! None +//! ) +//! ) +//! .region("us-east-1") +//! .name("exampleservice") +//! .time(SystemTime::now()) +//! .settings(signing_settings) +//! .build() +//! .unwrap(); +//! // Convert the HTTP request into a signable request +//! let signable_request = SignableRequest::from(&request); +//! +//! // Sign and then apply the signature to the request +//! let (signing_instructions, _signature) = aws_sigv4::http_request::sign(signable_request, &signing_params.into())?.into_parts(); +//! signing_instructions.apply_to_request(&mut request); +//! # Ok(()) +//! # } +//! ``` +//! + +pub(crate) mod canonical_request; +mod error; +mod settings; +mod sign; +mod uri_path_normalization; +mod url_escape; + +#[cfg(test)] +pub(crate) mod test_v4; + +#[cfg(all(test, feature = "sigv4a"))] +pub(crate) mod test_v4a; + +use crate::sign::v4; +#[cfg(feature = "sigv4a")] +use crate::sign::v4a; +use crate::SignatureVersion; +use aws_credential_types::Credentials; +pub use error::SigningError; +pub use settings::{ + PayloadChecksumKind, PercentEncodingMode, SessionTokenMode, SignatureLocation, SigningSettings, + UriPathNormalizationMode, +}; +pub use sign::{sign, SignableBody, SignableRequest, SigningInstructions}; +use std::time::SystemTime; + +// Individual Debug impls are responsible for redacting sensitive fields. +#[derive(Debug)] +#[non_exhaustive] +/// Parameters for signing an HTTP request. +pub enum SigningParams<'a> { + /// Sign with the SigV4 algorithm + V4(v4::SigningParams<'a, SigningSettings>), + #[cfg(feature = "sigv4a")] + /// Sign with the SigV4a algorithm + V4a(v4a::SigningParams<'a, SigningSettings>), +} + +impl<'a> From> for SigningParams<'a> { + fn from(value: v4::SigningParams<'a, SigningSettings>) -> Self { + Self::V4(value) + } +} + +#[cfg(feature = "sigv4a")] +impl<'a> From> for SigningParams<'a> { + fn from(value: v4a::SigningParams<'a, SigningSettings>) -> Self { + Self::V4a(value) + } +} + +impl<'a> SigningParams<'a> { + /// Return the credentials within the signing params. + pub fn credentials(&self) -> Result<&Credentials, error::SigningError> { + let identity = match self { + Self::V4(v4::SigningParams { identity, .. }) => identity, + #[cfg(feature = "sigv4a")] + Self::V4a(v4a::SigningParams { identity, .. }) => identity, + }; + + identity + .data::() + .ok_or_else(error::SigningError::unsupported_identity_type) + } + + /// If the signing params are for SigV4, return the region. Otherwise, return `None`. + pub fn region(&self) -> Option<&str> { + match self { + SigningParams::V4(v4::SigningParams { region, .. }) => Some(region), + #[allow(unreachable_patterns)] + _ => None, + } + } + + #[cfg(feature = "sigv4a")] + /// If the signing params are for SigV4a, return the region set. Otherwise, return `None`. + pub fn region_set(&self) -> Option<&str> { + match self { + SigningParams::V4a(v4a::SigningParams { region_set, .. }) => Some(region_set), + _ => None, + } + } + + #[cfg(test)] + /// Set the credentials for the signing params. + pub fn set_credentials(&mut self, credentials: Credentials) { + use aws_smithy_runtime_api::client::identity::Identity; + + let id = match self { + Self::V4(v4::SigningParams { identity, .. }) => identity, + #[cfg(feature = "sigv4a")] + Self::V4a(v4a::SigningParams { identity, .. }) => identity, + }; + + let expiry = credentials.expiry(); + *id = Identity::new(credentials, expiry); + } + + /// Return a reference to the settings held by the signing params. + pub fn settings(&self) -> &SigningSettings { + match self { + Self::V4(v4::SigningParams { settings, .. }) => settings, + #[cfg(feature = "sigv4a")] + Self::V4a(v4a::SigningParams { settings, .. }) => settings, + } + } + + /// Return a mutable reference to the settings held by the signing params. + pub fn settings_mut(&mut self) -> &mut SigningSettings { + match self { + Self::V4(v4::SigningParams { settings, .. }) => settings, + #[cfg(feature = "sigv4a")] + Self::V4a(v4a::SigningParams { settings, .. }) => settings, + } + } + + #[cfg(test)] + /// Set the [PayloadChecksumKind] for the signing params. + pub fn set_payload_checksum_kind(&mut self, kind: PayloadChecksumKind) { + let settings = self.settings_mut(); + + settings.payload_checksum_kind = kind; + } + + #[cfg(test)] + /// Set the [SessionTokenMode] for the signing params. + pub fn set_session_token_mode(&mut self, mode: SessionTokenMode) { + let settings = self.settings_mut(); + + settings.session_token_mode = mode; + } + + /// Return a reference to the time in the signing params. + pub fn time(&self) -> &SystemTime { + match self { + Self::V4(v4::SigningParams { time, .. }) => time, + #[cfg(feature = "sigv4a")] + Self::V4a(v4a::SigningParams { time, .. }) => time, + } + } + + /// Return a reference to the service name in the signing params. + pub fn service_name(&self) -> &str { + match self { + Self::V4(v4::SigningParams { + name: service_name, .. + }) => service_name, + #[cfg(feature = "sigv4a")] + Self::V4a(v4a::SigningParams { service_name, .. }) => service_name, + } + } + + /// Return the name of the configured signing algorithm. + pub fn algorithm(&self) -> &'static str { + match self { + Self::V4(params) => params.algorithm(), + #[cfg(feature = "sigv4a")] + Self::V4a(params) => params.algorithm(), + } + } + + /// Return the name of the signing scheme + pub fn signature_version(&self) -> SignatureVersion { + match self { + Self::V4(..) => SignatureVersion::V4, + #[cfg(feature = "sigv4a")] + Self::V4a(..) => SignatureVersion::V4a, + } + } +} diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs index 221463ada2..d726ef71df 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/canonical_request.rs @@ -10,9 +10,11 @@ use crate::http_request::settings::UriPathNormalizationMode; use crate::http_request::sign::SignableRequest; use crate::http_request::uri_path_normalization::normalize_uri_path; use crate::http_request::url_escape::percent_encode_path; -use crate::http_request::PercentEncodingMode; -use crate::http_request::{PayloadChecksumKind, SignableBody, SignatureLocation, SigningParams}; -use crate::sign::sha256_hex_string; +use crate::http_request::{ + PayloadChecksumKind, PercentEncodingMode, SignableBody, SignatureLocation, SigningParams, +}; +use crate::sign::v4; +use crate::SignatureVersion; use aws_smithy_http::query_writer::QueryWriter; use http::header::{AsHeaderName, HeaderName, HOST}; use http::{HeaderMap, HeaderValue, Method, Uri}; @@ -20,7 +22,6 @@ use std::borrow::Cow; use std::cmp::Ordering; use std::convert::TryFrom; use std::fmt; -use std::fmt::Formatter; use std::str::FromStr; use std::time::SystemTime; @@ -29,6 +30,8 @@ pub(crate) mod header { pub(crate) const X_AMZ_DATE: &str = "x-amz-date"; pub(crate) const X_AMZ_SECURITY_TOKEN: &str = "x-amz-security-token"; pub(crate) const X_AMZ_USER_AGENT: &str = "x-amz-user-agent"; + #[cfg(feature = "sigv4a")] + pub(crate) const X_AMZ_REGION_SET: &str = "x-amz-region-set"; } pub(crate) mod param { @@ -39,40 +42,44 @@ pub(crate) mod param { pub(crate) const X_AMZ_SECURITY_TOKEN: &str = "X-Amz-Security-Token"; pub(crate) const X_AMZ_SIGNED_HEADERS: &str = "X-Amz-SignedHeaders"; pub(crate) const X_AMZ_SIGNATURE: &str = "X-Amz-Signature"; + #[cfg(feature = "sigv4a")] + pub(crate) const X_AMZ_REGION_SET: &str = "X-Amz-Region-Set"; } -pub(crate) const HMAC_256: &str = "AWS4-HMAC-SHA256"; - const UNSIGNED_PAYLOAD: &str = "UNSIGNED-PAYLOAD"; const STREAMING_UNSIGNED_PAYLOAD_TRAILER: &str = "STREAMING-UNSIGNED-PAYLOAD-TRAILER"; #[derive(Debug, PartialEq)] -pub(super) struct HeaderValues<'a> { - pub(super) content_sha256: Cow<'a, str>, - pub(super) date_time: String, - pub(super) security_token: Option<&'a str>, - pub(super) signed_headers: SignedHeaders, +pub(crate) struct HeaderValues<'a> { + pub(crate) content_sha256: Cow<'a, str>, + pub(crate) date_time: String, + pub(crate) security_token: Option<&'a str>, + pub(crate) signed_headers: SignedHeaders, + #[cfg(feature = "sigv4a")] + pub(crate) region_set: Option<&'a str>, } #[derive(Debug, PartialEq)] -pub(super) struct QueryParamValues<'a> { - pub(super) algorithm: &'static str, - pub(super) content_sha256: Cow<'a, str>, - pub(super) credential: String, - pub(super) date_time: String, - pub(super) expires: String, - pub(super) security_token: Option<&'a str>, - pub(super) signed_headers: SignedHeaders, +pub(crate) struct QueryParamValues<'a> { + pub(crate) algorithm: &'static str, + pub(crate) content_sha256: Cow<'a, str>, + pub(crate) credential: String, + pub(crate) date_time: String, + pub(crate) expires: String, + pub(crate) security_token: Option<&'a str>, + pub(crate) signed_headers: SignedHeaders, + #[cfg(feature = "sigv4a")] + pub(crate) region_set: Option<&'a str>, } #[derive(Debug, PartialEq)] -pub(super) enum SignatureValues<'a> { +pub(crate) enum SignatureValues<'a> { Headers(HeaderValues<'a>), QueryParams(QueryParamValues<'a>), } impl<'a> SignatureValues<'a> { - pub(super) fn signed_headers(&self) -> &SignedHeaders { + pub(crate) fn signed_headers(&self) -> &SignedHeaders { match self { SignatureValues::Headers(values) => &values.signed_headers, SignatureValues::QueryParams(values) => &values.signed_headers, @@ -86,14 +93,14 @@ impl<'a> SignatureValues<'a> { } } - pub(super) fn as_headers(&self) -> Option<&HeaderValues<'_>> { + pub(crate) fn as_headers(&self) -> Option<&HeaderValues<'_>> { match self { SignatureValues::Headers(values) => Some(values), _ => None, } } - pub(super) fn into_query_params(self) -> Result, Self> { + pub(crate) fn into_query_params(self) -> Result, Self> { match self { SignatureValues::QueryParams(values) => Ok(values), _ => Err(self), @@ -102,12 +109,12 @@ impl<'a> SignatureValues<'a> { } #[derive(Debug, PartialEq)] -pub(super) struct CanonicalRequest<'a> { - pub(super) method: &'a Method, - pub(super) path: Cow<'a, str>, - pub(super) params: Option, - pub(super) headers: HeaderMap, - pub(super) values: SignatureValues<'a>, +pub(crate) struct CanonicalRequest<'a> { + pub(crate) method: &'a Method, + pub(crate) path: Cow<'a, str>, + pub(crate) params: Option, + pub(crate) headers: HeaderMap, + pub(crate) values: SignatureValues<'a>, } impl<'a> CanonicalRequest<'a> { @@ -127,61 +134,84 @@ impl<'a> CanonicalRequest<'a> { /// included before calculating the signature, add it, otherwise omit it. /// - `settings.signature_location` determines where the signature will be placed in a request, /// and also alters the kinds of signing values that go along with it in the request. - pub(super) fn from<'b>( + pub(crate) fn from<'b>( req: &'b SignableRequest<'b>, params: &'b SigningParams<'b>, ) -> Result, CanonicalRequestError> { + let creds = params.credentials() + .expect("Safe to unwrap because the credentials must be correct to get to this point. If you encounter this error, report it as a bug."); // Path encoding: if specified, re-encode % as %25 // Set method and path into CanonicalRequest let path = req.uri().path(); - let path = match params.settings.uri_path_normalization_mode { + let path = match params.settings().uri_path_normalization_mode { UriPathNormalizationMode::Enabled => normalize_uri_path(path), UriPathNormalizationMode::Disabled => Cow::Borrowed(path), }; - let path = match params.settings.percent_encoding_mode { + let path = match params.settings().percent_encoding_mode { // The string is already URI encoded, we don't need to encode everything again, just `%` PercentEncodingMode::Double => Cow::Owned(percent_encode_path(&path)), PercentEncodingMode::Single => path, }; let payload_hash = Self::payload_hash(req.body()); - let date_time = format_date_time(params.time); + let date_time = format_date_time(*params.time()); let (signed_headers, canonical_headers) = Self::headers(req, params, &payload_hash, &date_time)?; let signed_headers = SignedHeaders::new(signed_headers); - let security_token = match params.settings.session_token_mode { - SessionTokenMode::Include => params.security_token, + let security_token = match params.settings().session_token_mode { + SessionTokenMode::Include => creds.session_token(), SessionTokenMode::Exclude => None, }; - let values = match params.settings.signature_location { + let values = match params.settings().signature_location { SignatureLocation::Headers => SignatureValues::Headers(HeaderValues { content_sha256: payload_hash, date_time, security_token, signed_headers, + #[cfg(feature = "sigv4a")] + region_set: params.region_set(), }), - SignatureLocation::QueryParams => SignatureValues::QueryParams(QueryParamValues { - algorithm: "AWS4-HMAC-SHA256", - content_sha256: payload_hash, - credential: format!( - "{}/{}/{}/{}/aws4_request", - params.access_key, - format_date(params.time), - params.region, - params.service_name, - ), - date_time, - expires: params - .settings - .expires_in - .expect("presigning requires expires_in") - .as_secs() - .to_string(), - security_token, - signed_headers, - }), + SignatureLocation::QueryParams => { + let credential = match params { + SigningParams::V4(params) => { + format!( + "{}/{}/{}/{}/aws4_request", + creds.access_key_id(), + format_date(params.time), + params.region, + params.name, + ) + } + #[cfg(feature = "sigv4a")] + SigningParams::V4a(params) => { + format!( + "{}/{}/{}/aws4_request", + creds.access_key_id(), + format_date(params.time), + params.service_name, + ) + } + }; + + SignatureValues::QueryParams(QueryParamValues { + algorithm: params.algorithm(), + content_sha256: payload_hash, + credential, + date_time, + expires: params + .settings() + .expires_in + .expect("presigning requires expires_in") + .as_secs() + .to_string(), + security_token, + signed_headers, + #[cfg(feature = "sigv4a")] + region_set: params.region_set(), + }) + } }; let creq = CanonicalRequest { @@ -219,36 +249,44 @@ impl<'a> CanonicalRequest<'a> { Self::insert_host_header(&mut canonical_headers, req.uri()); - if params.settings.signature_location == SignatureLocation::Headers { + if params.settings().signature_location == SignatureLocation::Headers { + let creds = params.credentials() + .expect("Safe to unwrap because the credentials must be correct to get to this point. If you encounter this error, report it as a bug."); Self::insert_date_header(&mut canonical_headers, date_time); - if let Some(security_token) = params.security_token { + if let Some(security_token) = creds.session_token() { let mut sec_header = HeaderValue::from_str(security_token)?; sec_header.set_sensitive(true); canonical_headers.insert(header::X_AMZ_SECURITY_TOKEN, sec_header); } - if params.settings.payload_checksum_kind == PayloadChecksumKind::XAmzSha256 { + if params.settings().payload_checksum_kind == PayloadChecksumKind::XAmzSha256 { let header = HeaderValue::from_str(payload_hash)?; canonical_headers.insert(header::X_AMZ_CONTENT_SHA_256, header); } + + #[cfg(feature = "sigv4a")] + if let Some(region_set) = params.region_set() { + let header = HeaderValue::from_str(region_set)?; + canonical_headers.insert(header::X_AMZ_REGION_SET, header); + } } let mut signed_headers = Vec::with_capacity(canonical_headers.len()); for name in canonical_headers.keys() { - if let Some(excluded_headers) = params.settings.excluded_headers.as_ref() { + if let Some(excluded_headers) = params.settings().excluded_headers.as_ref() { if excluded_headers.contains(name) { continue; } } - if params.settings.session_token_mode == SessionTokenMode::Exclude + if params.settings().session_token_mode == SessionTokenMode::Exclude && name == HeaderName::from_static(header::X_AMZ_SECURITY_TOKEN) { continue; } - if params.settings.signature_location == SignatureLocation::QueryParams { + if params.settings().signature_location == SignatureLocation::QueryParams { // The X-Amz-User-Agent header should not be signed if this is for a presigned URL if name == HeaderName::from_static(header::X_AMZ_USER_AGENT) { continue; @@ -271,7 +309,7 @@ impl<'a> CanonicalRequest<'a> { // - use `UnsignedPayload` for streaming requests // - use `StreamingUnsignedPayloadTrailer` for streaming requests with trailers match body { - SignableBody::Bytes(data) => Cow::Owned(sha256_hex_string(data)), + SignableBody::Bytes(data) => Cow::Owned(v4::sha256_hex_string(data)), SignableBody::Precomputed(digest) => Cow::Borrowed(digest.as_str()), SignableBody::UnsignedPayload => Cow::Borrowed(UNSIGNED_PAYLOAD), SignableBody::StreamingUnsignedPayloadTrailer => { @@ -290,6 +328,12 @@ impl<'a> CanonicalRequest<'a> { if let SignatureValues::QueryParams(values) = values { add_param(&mut params, param::X_AMZ_DATE, &values.date_time); add_param(&mut params, param::X_AMZ_EXPIRES, &values.expires); + + #[cfg(feature = "sigv4a")] + if let Some(regions) = values.region_set { + add_param(&mut params, param::X_AMZ_REGION_SET, regions); + } + add_param(&mut params, param::X_AMZ_ALGORITHM, values.algorithm); add_param(&mut params, param::X_AMZ_CREDENTIAL, &values.credential); add_param( @@ -418,7 +462,7 @@ fn normalize_header_value( } #[derive(Debug, PartialEq, Default)] -pub(super) struct SignedHeaders { +pub(crate) struct SignedHeaders { headers: Vec, formatted: String, } @@ -442,7 +486,7 @@ impl SignedHeaders { value } - pub(super) fn as_str(&self) -> &str { + pub(crate) fn as_str(&self) -> &str { &self.formatted } } @@ -469,10 +513,16 @@ impl Ord for CanonicalHeaderName { } #[derive(PartialEq, Debug, Clone)] -pub(super) struct SigningScope<'a> { - pub(super) time: SystemTime, - pub(super) region: &'a str, - pub(super) service: &'a str, +pub(crate) struct SigningScope<'a> { + pub(crate) time: SystemTime, + pub(crate) region: &'a str, + pub(crate) service: &'a str, +} + +impl<'a> SigningScope<'a> { + pub(crate) fn v4a_display(&self) -> String { + format!("{}/{}/aws4_request", format_date(self.time), self.service) + } } impl<'a> fmt::Display for SigningScope<'a> { @@ -487,17 +537,19 @@ impl<'a> fmt::Display for SigningScope<'a> { } } -#[derive(PartialEq, Debug)] -pub(super) struct StringToSign<'a> { - pub(super) scope: SigningScope<'a>, - pub(super) time: SystemTime, - pub(super) region: &'a str, - pub(super) service: &'a str, - pub(super) hashed_creq: &'a str, +#[derive(PartialEq, Debug, Clone)] +pub(crate) struct StringToSign<'a> { + pub(crate) algorithm: &'static str, + pub(crate) scope: SigningScope<'a>, + pub(crate) time: SystemTime, + pub(crate) region: &'a str, + pub(crate) service: &'a str, + pub(crate) hashed_creq: &'a str, + signature_version: SignatureVersion, } impl<'a> StringToSign<'a> { - pub(crate) fn new( + pub(crate) fn new_v4( time: SystemTime, region: &'a str, service: &'a str, @@ -509,23 +561,51 @@ impl<'a> StringToSign<'a> { service, }; Self { + algorithm: "AWS4-HMAC-SHA256", scope, time, region, service, hashed_creq, + signature_version: SignatureVersion::V4, + } + } + + #[cfg(feature = "sigv4a")] + pub(crate) fn new_v4a( + time: SystemTime, + region: &'a str, + service: &'a str, + hashed_creq: &'a str, + ) -> Self { + let scope = SigningScope { + time, + region, + service, + }; + Self { + algorithm: "AWS4-ECDSA-P256-SHA256", + scope, + time, + region, + service, + hashed_creq, + signature_version: SignatureVersion::V4a, } } } impl<'a> fmt::Display for StringToSign<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "{}\n{}\n{}\n{}", - HMAC_256, + self.algorithm, format_date_time(self.time), - self.scope, + match self.signature_version { + SignatureVersion::V4 => self.scope.to_string(), + SignatureVersion::V4a => self.scope.v4a_display(), + }, self.hashed_creq ) } @@ -537,13 +617,15 @@ mod tests { use crate::http_request::canonical_request::{ normalize_header_value, trim_all, CanonicalRequest, SigningScope, StringToSign, }; - use crate::http_request::test::{test_canonical_request, test_request, test_sts}; + use crate::http_request::test_v4::{test_canonical_request, test_request, test_sts}; use crate::http_request::{ - PayloadChecksumKind, SessionTokenMode, SignableBody, SignableRequest, SigningSettings, + PayloadChecksumKind, SessionTokenMode, SignableBody, SignableRequest, SignatureLocation, + SigningParams, SigningSettings, }; - use crate::http_request::{SignatureLocation, SigningParams}; - use crate::sign::sha256_hex_string; + use crate::sign::v4; + use aws_credential_types::Credentials; use aws_smithy_http::query_writer::QueryWriter; + use aws_smithy_runtime_api::client::identity::Identity; use http::Uri; use http::{header::HeaderName, HeaderValue}; use pretty_assertions::assert_eq; @@ -551,15 +633,18 @@ mod tests { use std::time::Duration; fn signing_params(settings: SigningSettings) -> SigningParams<'static> { - SigningParams { - access_key: "test-access-key", - secret_key: "test-secret-key", - security_token: None, - region: "test-region", - service_name: "testservicename", - time: parse_date_time("20210511T154045Z").unwrap(), - settings, - } + let creds = Credentials::for_tests(); + let expiry = creds.expiry(); + + v4::signing_params::Builder::default() + .identity(Identity::new(creds, expiry)) + .region("test-region") + .name("testservicename") + .time(parse_date_time("20210511T154045Z").unwrap()) + .settings(settings) + .build() + .unwrap() + .into() } #[test] @@ -576,6 +661,7 @@ mod tests { let req = SignableRequest::from(&req); let settings = SigningSettings { payload_checksum_kind: PayloadChecksumKind::XAmzSha256, + session_token_mode: SessionTokenMode::Exclude, ..Default::default() }; let signing_params = signing_params(settings); @@ -597,6 +683,7 @@ mod tests { let req = SignableRequest::from(&req); let settings = SigningSettings { payload_checksum_kind: PayloadChecksumKind::XAmzSha256, + session_token_mode: SessionTokenMode::Exclude, ..Default::default() }; let mut signing_params = signing_params(settings); @@ -611,7 +698,7 @@ mod tests { "host;x-amz-content-sha256;x-amz-date" ); - signing_params.settings.payload_checksum_kind = PayloadChecksumKind::NoHeader; + signing_params.set_payload_checksum_kind(PayloadChecksumKind::NoHeader); let creq = CanonicalRequest::from(&req, &signing_params).unwrap(); assert_eq!(creq.values.signed_headers().as_str(), "host;x-amz-date"); } @@ -671,9 +758,9 @@ mod tests { let time = parse_date_time("20150830T123600Z").unwrap(); let creq = test_canonical_request("get-vanilla-query-order-key-case"); let expected_sts = test_sts("get-vanilla-query-order-key-case"); - let encoded = sha256_hex_string(creq.as_bytes()); + let encoded = v4::sha256_hex_string(creq.as_bytes()); - let actual = StringToSign::new(time, "us-east-1", "service", &encoded); + let actual = StringToSign::new_v4(time, "us-east-1", "service", &encoded); assert_eq!(expected_sts, actual.to_string()); } @@ -681,7 +768,7 @@ mod tests { fn test_digest_of_canonical_request() { let creq = test_canonical_request("get-vanilla-query-order-key-case"); let expected = "816cd5b414d056048ba4f7c5386d6e0533120fb1fcfa93762cf0fc39e2cf19e0"; - let actual = sha256_hex_string(creq.as_bytes()); + let actual = v4::sha256_hex_string(creq.as_bytes()); assert_eq!(expected, actual); } @@ -689,7 +776,11 @@ mod tests { fn test_double_url_encode_path() { let req = test_request("double-encode-path"); let req = SignableRequest::from(&req); - let signing_params = signing_params(SigningSettings::default()); + let settings = SigningSettings { + session_token_mode: SessionTokenMode::Exclude, + ..Default::default() + }; + let signing_params = signing_params(settings); let creq = CanonicalRequest::from(&req, &signing_params).unwrap(); let expected = test_canonical_request("double-encode-path"); @@ -701,7 +792,11 @@ mod tests { fn test_double_url_encode() { let req = test_request("double-url-encode"); let req = SignableRequest::from(&req); - let signing_params = signing_params(SigningSettings::default()); + let settings = SigningSettings { + session_token_mode: SessionTokenMode::Exclude, + ..Default::default() + }; + let signing_params = signing_params(settings); let creq = CanonicalRequest::from(&req, &signing_params).unwrap(); let expected = test_canonical_request("double-url-encode"); @@ -753,7 +848,7 @@ mod tests { ..Default::default() }; let mut signing_params = signing_params(settings); - signing_params.security_token = Some("notarealsessiontoken"); + signing_params.set_credentials(Credentials::for_tests_with_session_token()); let creq = CanonicalRequest::from(&req, &signing_params).unwrap(); assert_eq!( @@ -765,7 +860,7 @@ mod tests { "notarealsessiontoken" ); - signing_params.settings.session_token_mode = SessionTokenMode::Exclude; + signing_params.set_session_token_mode(SessionTokenMode::Exclude); let creq = CanonicalRequest::from(&req, &signing_params).unwrap(); assert_eq!( creq.headers.get("x-amz-security-token").unwrap(), @@ -791,6 +886,7 @@ mod tests { let settings = SigningSettings { signature_location: SignatureLocation::Headers, + session_token_mode: SessionTokenMode::Exclude, ..Default::default() }; diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/error.rs b/aws/rust-runtime/aws-sigv4/src/http_request/error.rs index d67acbc327..bd534258bf 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/error.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/error.rs @@ -11,6 +11,7 @@ use std::str::Utf8Error; #[derive(Debug)] enum SigningErrorKind { FailedToCreateCanonicalRequest { source: CanonicalRequestError }, + UnsupportedIdentityType, } /// Error signing request @@ -19,20 +20,37 @@ pub struct SigningError { kind: SigningErrorKind, } +impl SigningError { + pub(crate) fn unsupported_identity_type() -> Self { + Self { + kind: SigningErrorKind::UnsupportedIdentityType, + } + } +} + impl fmt::Display for SigningError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use SigningErrorKind::*; match self.kind { - SigningErrorKind::FailedToCreateCanonicalRequest { .. } => { + FailedToCreateCanonicalRequest { .. } => { write!(f, "failed to create canonical request") } + UnsupportedIdentityType => { + write!( + f, + "this Identity type is not supported for sigv4 signing. This is a bug" + ) + } } } } impl Error for SigningError { fn source(&self) -> Option<&(dyn Error + 'static)> { + use SigningErrorKind::*; match &self.kind { - SigningErrorKind::FailedToCreateCanonicalRequest { source } => Some(source), + FailedToCreateCanonicalRequest { source } => Some(source), + UnsupportedIdentityType => None, } } } diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/mod.rs b/aws/rust-runtime/aws-sigv4/src/http_request/mod.rs deleted file mode 100644 index db021bbee5..0000000000 --- a/aws/rust-runtime/aws-sigv4/src/http_request/mod.rs +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. - * SPDX-License-Identifier: Apache-2.0 - */ - -//! Utilities to sign HTTP requests. -//! -//! # Example: Signing an HTTP request -//! -//! ```rust -//! # fn test() -> Result<(), aws_sigv4::http_request::SigningError> { -//! use aws_sigv4::http_request::{sign, SigningSettings, SigningParams, SignableRequest}; -//! use http; -//! use std::time::SystemTime; -//! -//! // Create the request to sign -//! let mut request = http::Request::builder() -//! .uri("https://some-endpoint.some-region.amazonaws.com") -//! .body("") -//! .unwrap(); -//! -//! // Set up information and settings for the signing -//! let signing_settings = SigningSettings::default(); -//! let signing_params = SigningParams::builder() -//! .access_key("example access key") -//! .secret_key("example secret key") -//! .region("us-east-1") -//! .service_name("exampleservice") -//! .time(SystemTime::now()) -//! .settings(signing_settings) -//! .build() -//! .unwrap(); -//! // Convert the HTTP request into a signable request -//! let signable_request = SignableRequest::from(&request); -//! -//! // Sign and then apply the signature to the request -//! let (signing_instructions, _signature) = sign(signable_request, &signing_params)?.into_parts(); -//! signing_instructions.apply_to_request(&mut request); -//! # Ok(()) -//! # } -//! ``` -//! - -mod canonical_request; -mod error; -mod settings; -mod sign; -mod uri_path_normalization; -mod url_escape; - -#[cfg(test)] -pub(crate) mod test; - -pub use error::SigningError; -pub use settings::{ - PayloadChecksumKind, PercentEncodingMode, SessionTokenMode, SignatureLocation, SigningParams, - SigningSettings, UriPathNormalizationMode, -}; -pub use sign::{sign, SignableBody, SignableRequest, SigningInstructions}; diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs index 501cd5c775..7924b13008 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/settings.rs @@ -6,9 +6,6 @@ use http::header::{HeaderName, AUTHORIZATION, USER_AGENT}; use std::time::Duration; -/// HTTP signing parameters -pub type SigningParams<'a> = crate::SigningParams<'a, SigningSettings>; - const HEADER_NAME_X_RAY_TRACE_ID: &str = "x-amzn-trace-id"; /// HTTP-specific signing settings @@ -85,6 +82,16 @@ pub enum UriPathNormalizationMode { Disabled, } +impl From for UriPathNormalizationMode { + fn from(value: bool) -> Self { + if value { + UriPathNormalizationMode::Enabled + } else { + UriPathNormalizationMode::Disabled + } + } +} + /// Config value to specify whether X-Amz-Security-Token should be part of the canonical request. /// #[non_exhaustive] diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs index aaeda06bb7..8b032ee64d 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/sign.rs @@ -5,15 +5,14 @@ use super::error::SigningError; use super::{PayloadChecksumKind, SignatureLocation}; -use crate::http_request::canonical_request::header; -use crate::http_request::canonical_request::param; -use crate::http_request::canonical_request::{CanonicalRequest, StringToSign, HMAC_256}; +use crate::http_request::canonical_request::{header, param, CanonicalRequest, StringToSign}; use crate::http_request::SigningParams; -use crate::sign::{calculate_signature, generate_signing_key, sha256_hex_string}; -use crate::SigningOutput; +use crate::sign::v4; +#[cfg(feature = "sigv4a")] +use crate::sign::v4a; +use crate::{SignatureVersion, SigningOutput}; use aws_smithy_http::query_writer::QueryWriter; -use http::header::HeaderValue; -use http::{HeaderMap, Method, Uri}; +use http::{HeaderMap, HeaderValue, Method, Uri}; use std::borrow::Cow; use std::convert::TryFrom; use std::str; @@ -162,7 +161,7 @@ pub fn sign<'a>( params: &'a SigningParams<'a>, ) -> Result, SigningError> { tracing::trace!(request = ?request, params = ?params, "signing request"); - match params.settings.signature_location { + match params.settings().signature_location { SignatureLocation::Headers => { let (signing_headers, signature) = calculate_signing_headers(&request, params)?.into_parts(); @@ -188,23 +187,46 @@ fn calculate_signing_params<'a>( params: &'a SigningParams<'a>, ) -> Result<(CalculatedParams, String), SigningError> { let creq = CanonicalRequest::from(request, params)?; + let encoded_creq = &v4::sha256_hex_string(creq.to_string().as_bytes()); + let creds = params.credentials()?; + + let (signature, string_to_sign) = match params { + SigningParams::V4(params) => { + let string_to_sign = + StringToSign::new_v4(params.time, params.region, params.name, encoded_creq) + .to_string(); + let signing_key = v4::generate_signing_key( + creds.secret_access_key(), + params.time, + params.region, + params.name, + ); + let signature = v4::calculate_signature(signing_key, string_to_sign.as_bytes()); + (signature, string_to_sign) + } + #[cfg(feature = "sigv4a")] + SigningParams::V4a(params) => { + let string_to_sign = StringToSign::new_v4a( + params.time, + params.region_set, + params.service_name, + encoded_creq, + ) + .to_string(); + + // Step 3: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-calculate-signature.html + let secret_key = + v4a::generate_signing_key(creds.access_key_id(), creds.secret_access_key()); + let signature = v4a::calculate_signature(&secret_key, string_to_sign.as_bytes()); + (signature, string_to_sign) + } + }; - let encoded_creq = &sha256_hex_string(creq.to_string().as_bytes()); - let string_to_sign = StringToSign::new( - params.time, - params.region, - params.service_name, - encoded_creq, - ) - .to_string(); - let signing_key = generate_signing_key( - params.secret_key, - params.time, - params.region, - params.service_name, + tracing::trace!( + canonical_request = %creq, + string_to_sign = %string_to_sign, + "calculated signing parameters" ); - let signature = calculate_signature(signing_key, string_to_sign.as_bytes()); - tracing::trace!(canonical_request = %creq, string_to_sign = %string_to_sign, "calculated signing parameters"); let values = creq.values.into_query_params().expect("signing with query"); let mut signing_params = vec![ @@ -219,7 +241,12 @@ fn calculate_signing_params<'a>( (param::X_AMZ_SIGNATURE, Cow::Owned(signature.clone())), ]; - if let Some(security_token) = params.security_token { + #[cfg(feature = "sigv4a")] + if let Some(region_set) = params.region_set() { + signing_params.push((param::X_AMZ_REGION_SET, Cow::Owned(region_set.to_owned()))); + } + + if let Some(security_token) = creds.session_token() { signing_params.push(( param::X_AMZ_SECURITY_TOKEN, Cow::Owned(security_token.to_string()), @@ -239,53 +266,118 @@ fn calculate_signing_headers<'a>( request: &'a SignableRequest<'a>, params: &'a SigningParams<'a>, ) -> Result>, SigningError> { + let creds = params.credentials()?; + // Step 1: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-create-canonical-request.html. let creq = CanonicalRequest::from(request, params)?; - tracing::trace!(canonical_request = %creq); - // Step 2: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-create-string-to-sign.html. - let encoded_creq = &sha256_hex_string(creq.to_string().as_bytes()); - let sts = StringToSign::new( - params.time, - params.region, - params.service_name, - encoded_creq, - ); + let encoded_creq = v4::sha256_hex_string(creq.to_string().as_bytes()); + tracing::trace!(canonical_request = %creq); + let mut headers = HeaderMap::new(); - // Step 3: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-calculate-signature.html - let signing_key = generate_signing_key( - params.secret_key, - params.time, - params.region, - params.service_name, - ); - let signature = calculate_signature(signing_key, sts.to_string().as_bytes()); + let signature = match params { + SigningParams::V4(params) => { + let sts = StringToSign::new_v4( + params.time, + params.region, + params.name, + encoded_creq.as_str(), + ); + + // Step 3: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-calculate-signature.html + let signing_key = v4::generate_signing_key( + creds.secret_access_key(), + params.time, + params.region, + params.name, + ); + let signature = v4::calculate_signature(signing_key, sts.to_string().as_bytes()); + + // Step 4: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-add-signature-to-request.html + let values = creq.values.as_headers().expect("signing with headers"); + add_header(&mut headers, header::X_AMZ_DATE, &values.date_time, false); + headers.insert( + "authorization", + build_authorization_header( + creds.access_key_id(), + &creq, + sts, + &signature, + SignatureVersion::V4, + ), + ); + if params.settings.payload_checksum_kind == PayloadChecksumKind::XAmzSha256 { + add_header( + &mut headers, + header::X_AMZ_CONTENT_SHA_256, + &values.content_sha256, + false, + ); + } - // Step 4: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-add-signature-to-request.html - let values = creq.values.as_headers().expect("signing with headers"); - let mut headers = HeaderMap::new(); - add_header(&mut headers, header::X_AMZ_DATE, &values.date_time, false); - headers.insert( - "authorization", - build_authorization_header(params.access_key, &creq, sts, &signature), - ); - if params.settings.payload_checksum_kind == PayloadChecksumKind::XAmzSha256 { - add_header( - &mut headers, - header::X_AMZ_CONTENT_SHA_256, - &values.content_sha256, - false, - ); - } + if let Some(security_token) = creds.session_token() { + add_header( + &mut headers, + header::X_AMZ_SECURITY_TOKEN, + security_token, + true, + ); + } + signature + } + #[cfg(feature = "sigv4a")] + SigningParams::V4a(params) => { + let sts = StringToSign::new_v4a( + params.time, + params.region_set, + params.service_name, + encoded_creq.as_str(), + ); + + // Step 3: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-calculate-signature.html + let signing_key = + v4a::generate_signing_key(creds.access_key_id(), creds.secret_access_key()); + let signature = v4a::calculate_signature(&signing_key, sts.to_string().as_bytes()); + + // Step 4: https://docs.aws.amazon.com/en_pv/general/latest/gr/sigv4-add-signature-to-request.html + let values = creq.values.as_headers().expect("signing with headers"); + add_header(&mut headers, header::X_AMZ_DATE, &values.date_time, false); + add_header( + &mut headers, + header::X_AMZ_REGION_SET, + params.region_set, + false, + ); + headers.insert( + "authorization", + build_authorization_header( + creds.access_key_id(), + &creq, + sts, + &signature, + SignatureVersion::V4a, + ), + ); + if params.settings.payload_checksum_kind == PayloadChecksumKind::XAmzSha256 { + add_header( + &mut headers, + header::X_AMZ_CONTENT_SHA_256, + &values.content_sha256, + false, + ); + } - if let Some(security_token) = params.security_token { - add_header( - &mut headers, - header::X_AMZ_SECURITY_TOKEN, - security_token, - true, - ); - } + if let Some(security_token) = creds.session_token() { + add_header( + &mut headers, + header::X_AMZ_SECURITY_TOKEN, + security_token, + true, + ); + } + signature + } + }; Ok(SigningOutput::new(headers, signature)) } @@ -303,12 +395,17 @@ fn build_authorization_header( creq: &CanonicalRequest<'_>, sts: StringToSign<'_>, signature: &str, + signature_version: SignatureVersion, ) -> HeaderValue { + let scope = match signature_version { + SignatureVersion::V4a => sts.scope.v4a_display(), + SignatureVersion::V4 => sts.scope.to_string(), + }; let mut value = HeaderValue::try_from(format!( "{} Credential={}/{}, SignedHeaders={}, Signature={}", - HMAC_256, + sts.algorithm, access_key, - sts.scope, + scope, creq.values.signed_headers().as_str(), signature )) @@ -322,13 +419,14 @@ mod tests { use super::{sign, SigningInstructions}; use crate::date_time::test_parsers::parse_date_time; use crate::http_request::sign::SignableRequest; - use crate::http_request::test::{ + use crate::http_request::test_v4::{ make_headers_comparable, test_request, test_signed_request, test_signed_request_query_params, }; - use crate::http_request::{ - SessionTokenMode, SignatureLocation, SigningParams, SigningSettings, - }; + use crate::http_request::{SessionTokenMode, SignatureLocation, SigningSettings}; + use crate::sign::v4; + use aws_credential_types::Credentials; + use aws_smithy_runtime_api::client::identity::Identity; use http::{HeaderMap, HeaderValue}; use pretty_assertions::assert_eq; use proptest::proptest; @@ -339,28 +437,27 @@ mod tests { ($a:tt, $b:tt) => { make_headers_comparable(&mut $a); make_headers_comparable(&mut $b); - assert_eq!(format!("{:?}", $a), format!("{:?}", $b)) + assert_eq!(format!("{:#?}", $a), format!("{:#?}", $b)) }; } #[test] fn test_sign_vanilla_with_headers() { let settings = SigningSettings::default(); - let params = SigningParams { - access_key: "AKIDEXAMPLE", - secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "service", + name: "service", time: parse_date_time("20150830T123600Z").unwrap(), settings, - }; + } + .into(); let original = test_request("get-vanilla-query-order-key-case"); let signable = SignableRequest::from(&original); let out = sign(signable, ¶ms).unwrap(); assert_eq!( - "b97d918cfa904a5beff61c982a1b6f458b799221646efd99d3219ec94cdf2500", + "5557820e7380d585310524bd93d51a08d7757fb5efd7344ee12088f2b0860947", out.signature ); @@ -371,25 +468,312 @@ mod tests { assert_req_eq!(expected, signed); } + #[cfg(feature = "sigv4a")] + mod sigv4a_tests { + use super::*; + use crate::http_request::canonical_request::{CanonicalRequest, StringToSign}; + use crate::http_request::{test_v4a, PayloadChecksumKind}; + use crate::sign::{v4, v4a}; + use p256::ecdsa::signature::Verifier; + use p256::ecdsa::DerSignature; + use pretty_assertions::assert_eq; + use std::time::SystemTime; + use time::format_description::well_known::Rfc3339; + use time::OffsetDateTime; + + fn new_v4a_signing_params_from_context( + test_context: &'_ test_v4a::TestContext, + signature_location: SignatureLocation, + ) -> crate::http_request::SigningParams<'_> { + let expires_in = Some(Duration::from_secs(test_context.expiration_in_seconds)); + + v4a::SigningParams { + identity: Identity::new( + Credentials::from_keys( + &test_context.credentials.access_key_id, + &test_context.credentials.secret_access_key, + test_context.credentials.token.clone(), + ), + expires_in.map(|t| SystemTime::UNIX_EPOCH + t), + ), + region_set: &test_context.region, + service_name: &test_context.service, + time: OffsetDateTime::parse(&test_context.timestamp, &Rfc3339) + .unwrap() + .into(), + settings: SigningSettings { + // payload_checksum_kind: PayloadChecksumKind::XAmzSha256, + expires_in: Some(Duration::from_secs(test_context.expiration_in_seconds)), + uri_path_normalization_mode: test_context.normalize.into(), + signature_location, + session_token_mode: if test_context.omit_session_token { + SessionTokenMode::Exclude + } else { + SessionTokenMode::Include + }, + payload_checksum_kind: if test_context.sign_body { + PayloadChecksumKind::XAmzSha256 + } else { + PayloadChecksumKind::NoHeader + }, + ..Default::default() + }, + } + .into() + } + + fn run_v4a_test_suite(test_name: &str, signature_location: SignatureLocation) { + let tc = test_v4a::test_context(test_name); + let params = new_v4a_signing_params_from_context(&tc, signature_location); + + let req = test_v4a::test_request(test_name); + let expected_creq = test_v4a::test_canonical_request(test_name, signature_location); + let signable_req = SignableRequest::from(&req); + let actual_creq = CanonicalRequest::from(&signable_req, ¶ms).unwrap(); + + assert_eq!(expected_creq, actual_creq.to_string(), "creq didn't match"); + + let expected_string_to_sign = + test_v4a::test_string_to_sign(test_name, signature_location); + let hashed_creq = &v4::sha256_hex_string(actual_creq.to_string().as_bytes()); + let actual_string_to_sign = StringToSign::new_v4a( + *params.time(), + params.region_set().unwrap(), + params.service_name(), + hashed_creq, + ) + .to_string(); + + assert_eq!( + expected_string_to_sign, actual_string_to_sign, + "'string to sign' didn't match" + ); + + let out = sign(signable_req, ¶ms).unwrap(); + + let mut signed = req; + // Sigv4a signatures are non-deterministic, so we can't compare the signature directly. + out.output.apply_to_request(&mut signed); + + let creds = params.credentials().unwrap(); + let keypair = + v4a::generate_signing_key(creds.access_key_id(), creds.secret_access_key()); + let sig = DerSignature::from_bytes(&hex::decode(out.signature).unwrap()).unwrap(); + + let peer_public_key = keypair.verifying_key(); + let sts = actual_string_to_sign.as_bytes(); + peer_public_key.verify(sts, &sig).unwrap(); + } + + #[test] + fn test_get_header_key_duplicate() { + run_v4a_test_suite("get-header-key-duplicate", SignatureLocation::Headers); + } + + #[test] + fn test_get_header_value_order() { + run_v4a_test_suite("get-header-value-order", SignatureLocation::Headers); + } + + #[test] + fn test_get_header_value_trim() { + run_v4a_test_suite("get-header-value-trim", SignatureLocation::Headers); + } + + #[test] + fn test_get_relative_normalized() { + run_v4a_test_suite("get-relative-normalized", SignatureLocation::Headers); + } + + #[test] + fn test_get_relative_relative_normalized() { + run_v4a_test_suite( + "get-relative-relative-normalized", + SignatureLocation::Headers, + ); + } + + #[test] + fn test_get_relative_relative_unnormalized() { + run_v4a_test_suite( + "get-relative-relative-unnormalized", + SignatureLocation::Headers, + ); + } + + #[test] + fn test_get_relative_unnormalized() { + run_v4a_test_suite("get-relative-unnormalized", SignatureLocation::Headers); + } + + #[test] + fn test_get_slash_dot_slash_normalized() { + run_v4a_test_suite("get-slash-dot-slash-normalized", SignatureLocation::Headers); + } + + #[test] + fn test_get_slash_dot_slash_unnormalized() { + run_v4a_test_suite( + "get-slash-dot-slash-unnormalized", + SignatureLocation::Headers, + ); + } + + #[test] + fn test_get_slash_normalized() { + run_v4a_test_suite("get-slash-normalized", SignatureLocation::Headers); + } + + #[test] + fn test_get_slash_pointless_dot_normalized() { + run_v4a_test_suite( + "get-slash-pointless-dot-normalized", + SignatureLocation::Headers, + ); + } + + #[test] + fn test_get_slash_pointless_dot_unnormalized() { + run_v4a_test_suite( + "get-slash-pointless-dot-unnormalized", + SignatureLocation::Headers, + ); + } + + #[test] + fn test_get_slash_unnormalized() { + run_v4a_test_suite("get-slash-unnormalized", SignatureLocation::Headers); + } + + #[test] + fn test_get_slashes_normalized() { + run_v4a_test_suite("get-slashes-normalized", SignatureLocation::Headers); + } + + #[test] + fn test_get_slashes_unnormalized() { + run_v4a_test_suite("get-slashes-unnormalized", SignatureLocation::Headers); + } + + #[test] + fn test_get_unreserved() { + run_v4a_test_suite("get-unreserved", SignatureLocation::Headers); + } + + #[test] + fn test_get_vanilla() { + run_v4a_test_suite("get-vanilla", SignatureLocation::Headers); + } + + #[test] + fn test_get_vanilla_empty_query_key() { + run_v4a_test_suite( + "get-vanilla-empty-query-key", + SignatureLocation::QueryParams, + ); + } + + #[test] + fn test_get_vanilla_query() { + run_v4a_test_suite("get-vanilla-query", SignatureLocation::QueryParams); + } + + #[test] + fn test_get_vanilla_query_order_key_case() { + run_v4a_test_suite( + "get-vanilla-query-order-key-case", + SignatureLocation::QueryParams, + ); + } + + #[test] + fn test_get_vanilla_query_unreserved() { + run_v4a_test_suite( + "get-vanilla-query-unreserved", + SignatureLocation::QueryParams, + ); + } + + #[test] + fn test_get_vanilla_with_session_token() { + run_v4a_test_suite("get-vanilla-with-session-token", SignatureLocation::Headers); + } + + #[test] + fn test_post_header_key_case() { + run_v4a_test_suite("post-header-key-case", SignatureLocation::Headers); + } + + #[test] + fn test_post_header_key_sort() { + run_v4a_test_suite("post-header-key-sort", SignatureLocation::Headers); + } + + #[test] + fn test_post_header_value_case() { + run_v4a_test_suite("post-header-value-case", SignatureLocation::Headers); + } + + #[test] + fn test_post_sts_header_after() { + run_v4a_test_suite("post-sts-header-after", SignatureLocation::Headers); + } + + #[test] + fn test_post_sts_header_before() { + run_v4a_test_suite("post-sts-header-before", SignatureLocation::Headers); + } + + #[test] + fn test_post_vanilla() { + run_v4a_test_suite("post-vanilla", SignatureLocation::Headers); + } + + #[test] + fn test_post_vanilla_empty_query_value() { + run_v4a_test_suite( + "post-vanilla-empty-query-value", + SignatureLocation::QueryParams, + ); + } + + #[test] + fn test_post_vanilla_query() { + run_v4a_test_suite("post-vanilla-query", SignatureLocation::QueryParams); + } + + #[test] + fn test_post_x_www_form_urlencoded() { + run_v4a_test_suite("post-x-www-form-urlencoded", SignatureLocation::Headers); + } + + #[test] + fn test_post_x_www_form_urlencoded_parameters() { + run_v4a_test_suite( + "post-x-www-form-urlencoded-parameters", + SignatureLocation::QueryParams, + ); + } + } + #[test] fn test_sign_url_escape() { let test = "double-encode-path"; let settings = SigningSettings::default(); - let params = SigningParams { - access_key: "AKIDEXAMPLE", - secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "service", + name: "service", time: parse_date_time("20150830T123600Z").unwrap(), settings, - }; + } + .into(); let original = test_request(test); let signable = SignableRequest::from(&original); let out = sign(signable, ¶ms).unwrap(); assert_eq!( - "6f871eb157f326fa5f7439eb88ca200048635950ce7d6037deda56f0c95d4364", + "57d157672191bac40bae387e48bbe14b15303c001fdbb01f4abf295dccb09705", out.signature ); @@ -407,21 +791,20 @@ mod tests { expires_in: Some(Duration::from_secs(35)), ..Default::default() }; - let params = SigningParams { - access_key: "AKIDEXAMPLE", - secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "service", + name: "service", time: parse_date_time("20150830T123600Z").unwrap(), settings, - }; + } + .into(); let original = test_request("get-vanilla-query-order-key-case"); let signable = SignableRequest::from(&original); let out = sign(signable, ¶ms).unwrap(); assert_eq!( - "f25aea20f8c722ece3b363fc5d60cc91add973f9b64c42ba36fa28d57afe9019", + "ecce208e4b4f7d7e3a4cc22ced6acc2ad1d170ee8ba87d7165f6fa4b9aff09ab", out.signature ); @@ -435,15 +818,14 @@ mod tests { #[test] fn test_sign_headers_utf8() { let settings = SigningSettings::default(); - let params = SigningParams { - access_key: "AKIDEXAMPLE", - secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "service", + name: "service", time: parse_date_time("20150830T123600Z").unwrap(), settings, - }; + } + .into(); let original = http::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") @@ -453,7 +835,7 @@ mod tests { let signable = SignableRequest::from(&original); let out = sign(signable, ¶ms).unwrap(); assert_eq!( - "4596b207a7fc6bdf18725369bc0cd7022cf20efbd2c19730549f42d1a403648e", + "55e16b31f9bde5fd04f9d3b780dd2b5e5f11a5219001f91a8ca9ec83eaf1618f", out.signature ); @@ -471,9 +853,9 @@ mod tests { "authorization", HeaderValue::from_str( "AWS4-HMAC-SHA256 \ - Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, \ + Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, \ SignedHeaders=host;some-header;x-amz-date, \ - Signature=4596b207a7fc6bdf18725369bc0cd7022cf20efbd2c19730549f42d1a403648e", + Signature=55e16b31f9bde5fd04f9d3b780dd2b5e5f11a5219001f91a8ca9ec83eaf1618f", ) .unwrap(), ) @@ -488,27 +870,25 @@ mod tests { session_token_mode: SessionTokenMode::Exclude, ..Default::default() }; - let mut params = SigningParams { - access_key: "AKIDEXAMPLE", - secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests_with_session_token(), None), region: "us-east-1", - service_name: "service", + name: "service", time: parse_date_time("20150830T123600Z").unwrap(), settings, - }; + } + .into(); let original = http::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") .body("") .unwrap(); let out_without_session_token = sign(SignableRequest::from(&original), ¶ms).unwrap(); - params.security_token = Some("notarealsessiontoken"); let out_with_session_token_but_excluded = sign(SignableRequest::from(&original), ¶ms).unwrap(); assert_eq!( - "d2445d2d58e01146627c1e498dc0b4749d0cecd2cab05c5349ed132c083914e8", + "ab32de057edf094958d178b3c91f3c8d5c296d526b11da991cd5773d09cea560", out_with_session_token_but_excluded.signature ); assert_eq!( @@ -531,9 +911,9 @@ mod tests { "authorization", HeaderValue::from_str( "AWS4-HMAC-SHA256 \ - Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, \ + Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, \ SignedHeaders=host;x-amz-date, \ - Signature=d2445d2d58e01146627c1e498dc0b4749d0cecd2cab05c5349ed132c083914e8", + Signature=ab32de057edf094958d178b3c91f3c8d5c296d526b11da991cd5773d09cea560", ) .unwrap(), ) @@ -549,15 +929,14 @@ mod tests { #[test] fn test_sign_headers_space_trimming() { let settings = SigningSettings::default(); - let params = SigningParams { - access_key: "AKIDEXAMPLE", - secret_key: "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "service", + name: "service", time: parse_date_time("20150830T123600Z").unwrap(), settings, - }; + } + .into(); let original = http::Request::builder() .uri("https://some-endpoint.some-region.amazonaws.com") @@ -570,7 +949,7 @@ mod tests { let signable = SignableRequest::from(&original); let out = sign(signable, ¶ms).unwrap(); assert_eq!( - "0bd74dbf6f21161f61a1a3a1c313b6a4bc67ec57bf5ea9ae956a63753ca1d7f7", + "244f2a0db34c97a528f22715fe01b2417b7750c8a95c7fc104a3c48d81d84c08", out.signature ); @@ -591,9 +970,9 @@ mod tests { "authorization", HeaderValue::from_str( "AWS4-HMAC-SHA256 \ - Credential=AKIDEXAMPLE/20150830/us-east-1/service/aws4_request, \ + Credential=ANOTREAL/20150830/us-east-1/service/aws4_request, \ SignedHeaders=host;some-header;x-amz-date, \ - Signature=0bd74dbf6f21161f61a1a3a1c313b6a4bc67ec57bf5ea9ae956a63753ca1d7f7", + Signature=244f2a0db34c97a528f22715fe01b2417b7750c8a95c7fc104a3c48d81d84c08", ) .unwrap(), ) @@ -605,15 +984,14 @@ mod tests { #[test] fn test_sign_headers_returning_expected_error_on_invalid_utf8() { let settings = SigningSettings::default(); - let params = SigningParams { - access_key: "123", - secret_key: "asdf", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "foo", + name: "foo", time: std::time::SystemTime::UNIX_EPOCH, settings, - }; + } + .into(); let req = http::Request::builder() .uri("https://foo.com/") @@ -621,7 +999,7 @@ mod tests { .body(&[]) .unwrap(); - let creq = crate::http_request::sign(SignableRequest::from(&req), ¶ms); + let creq = sign(SignableRequest::from(&req), ¶ms); assert!(creq.is_err()); } @@ -634,15 +1012,13 @@ mod tests { right in proptest::collection::vec(128_u8..=255, 0..100), ) { let settings = SigningSettings::default(); - let params = SigningParams { - access_key: "123", - secret_key: "asdf", - security_token: None, + let params = v4::SigningParams { + identity: Identity::new(Credentials::for_tests(), None), region: "us-east-1", - service_name: "foo", + name: "foo", time: std::time::SystemTime::UNIX_EPOCH, settings, - }; + }.into(); let bytes = left.iter().chain(right.iter()).cloned().collect::>(); let req = http::Request::builder() diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/test.rs b/aws/rust-runtime/aws-sigv4/src/http_request/test_v4.rs similarity index 99% rename from aws/rust-runtime/aws-sigv4/src/http_request/test.rs rename to aws/rust-runtime/aws-sigv4/src/http_request/test_v4.rs index 93bef370f4..94bf1b7335 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/test.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/test_v4.rs @@ -134,3 +134,5 @@ fn test_parse() { fn test_read_query_params() { test_request("get-vanilla-query-order-key-case"); } + +mod v4a {} diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/test_v4a.rs b/aws/rust-runtime/aws-sigv4/src/http_request/test_v4a.rs new file mode 100644 index 0000000000..30a333721e --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/src/http_request/test_v4a.rs @@ -0,0 +1,126 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +//! Functions shared between the tests of several modules. + +use super::SignatureLocation; +use bytes::Bytes; +use http::{Method, Request, Uri, Version}; +use serde_derive::Deserialize; +use std::error::Error as StdError; + +fn path(test_name: &str, definition_name: &str) -> String { + format!("aws-sig-v4a-test-suite/{test_name}/{definition_name}.txt") +} + +fn read(path: &str) -> String { + println!("Loading `{}` for test case...", path); + match std::fs::read_to_string(path) { + // This replacement is necessary for tests to pass on Windows, as reading the + // sigv4 snapshots from the file system results in CRLF line endings being inserted. + Ok(value) => value.replace("\r\n", "\n").trim().to_string(), + Err(err) => { + panic!("failed to load test case `{}`: {}", path, err); + } + } +} + +pub(crate) fn test_request(name: &str) -> Request { + test_parsed_request(&path(name, "request")) +} + +pub(crate) fn test_canonical_request(name: &str, signature_location: SignatureLocation) -> String { + match signature_location { + SignatureLocation::QueryParams => read(&path(name, "query-canonical-request")), + SignatureLocation::Headers => read(&path(name, "header-canonical-request")), + } +} + +pub(crate) fn test_string_to_sign(name: &str, signature_location: SignatureLocation) -> String { + match signature_location { + SignatureLocation::QueryParams => read(&path(name, "query-string-to-sign")), + SignatureLocation::Headers => read(&path(name, "header-string-to-sign")), + } +} + +fn test_parsed_request(path: &str) -> Request { + match parse_request(read(path).as_bytes()) { + Ok(parsed) => parsed, + Err(err) => panic!("Failed to parse {}: {}", path, err), + } +} + +fn parse_request(s: &[u8]) -> Result, Box> { + let mut headers = [httparse::EMPTY_HEADER; 64]; + // httparse 1.5 requires two trailing newlines to head the header section. + let mut with_newline = Vec::from(s); + with_newline.push(b'\n'); + let mut req = httparse::Request::new(&mut headers); + let _ = req.parse(&with_newline).unwrap(); + + let version = match req.version.unwrap() { + 1 => Version::HTTP_11, + _ => unimplemented!(), + }; + + let method = match req.method.unwrap() { + "GET" => Method::GET, + "POST" => Method::POST, + _ => unimplemented!(), + }; + + let mut builder = Request::builder(); + builder = builder.version(version); + builder = builder.method(method); + + let mut uri_builder = Uri::builder().scheme("https"); + if let Some(path) = req.path { + uri_builder = uri_builder.path_and_query(path); + } + for header in req.headers { + let name = header.name.to_lowercase(); + if name == "host" { + uri_builder = uri_builder.authority(header.value); + } else if !name.is_empty() { + builder = builder.header(&name, header.value); + } + } + + builder = builder.uri(uri_builder.build()?); + let req = builder.body(Bytes::new())?; + Ok(req) +} + +pub(crate) fn test_context(test_name: &str) -> TestContext { + let path = format!("aws-sig-v4a-test-suite/{test_name}/context.json"); + let context = read(&path); + serde_json::from_str(&context).unwrap() +} + +// I can't figure out how to default to `true` otherwise. Please help :( +fn why_serde_why() -> bool { + true +} + +#[derive(Deserialize)] +pub(crate) struct TestContext { + pub(crate) credentials: TestContextCreds, + pub(crate) expiration_in_seconds: u64, + pub(crate) normalize: bool, + pub(crate) region: String, + pub(crate) service: String, + pub(crate) timestamp: String, + #[serde(default)] + pub(crate) omit_session_token: bool, + #[serde(default = "why_serde_why")] + pub(crate) sign_body: bool, +} + +#[derive(Deserialize)] +pub(crate) struct TestContextCreds { + pub(crate) access_key_id: String, + pub(crate) secret_access_key: String, + pub(crate) token: Option, +} diff --git a/aws/rust-runtime/aws-sigv4/src/http_request/uri_path_normalization.rs b/aws/rust-runtime/aws-sigv4/src/http_request/uri_path_normalization.rs index 7ea834a252..fe37db8cd4 100644 --- a/aws/rust-runtime/aws-sigv4/src/http_request/uri_path_normalization.rs +++ b/aws/rust-runtime/aws-sigv4/src/http_request/uri_path_normalization.rs @@ -20,7 +20,7 @@ pub(super) fn normalize_uri_path(uri_path: &str) -> Cow<'_, str> { Cow::Owned(format!("/{uri_path}")) }; - if !result.contains('.') { + if !(result.contains('.') || result.contains("//")) { return result; } @@ -37,7 +37,8 @@ fn normalize_path_segment(uri_path: &str) -> String { for segment in uri_path.split('/') { match segment { - "." => {} + // Segments that are empty or contain only a single period should not be preserved + "" | "." => {} ".." => { normalized.pop(); } @@ -232,6 +233,15 @@ mod tests { ); } + // The CRT does this so I figured we should too. + #[test] + fn normalize_uri_path_should_merge_multiple_subsequent_slashes_into_one() { + assert_eq!( + normalize_uri_path("//foo//"), + Cow::<'_, str>::Owned("/foo/".to_owned()) + ); + } + #[test] fn normalize_uri_path_should_not_remove_dot_when_surrounded_by_percent_encoded_forward_slashes() { diff --git a/aws/rust-runtime/aws-sigv4/src/lib.rs b/aws/rust-runtime/aws-sigv4/src/lib.rs index d20df23994..5fe83a0bf5 100644 --- a/aws/rust-runtime/aws-sigv4/src/lib.rs +++ b/aws/rust-runtime/aws-sigv4/src/lib.rs @@ -16,7 +16,6 @@ )] use std::fmt; -use std::time::SystemTime; pub mod sign; @@ -28,193 +27,21 @@ pub mod event_stream; #[cfg(feature = "sign-http")] pub mod http_request; -/// Parameters to use when signing. +/// The version of the signing algorithm to use +#[derive(Debug, Eq, PartialEq, Copy, Clone)] #[non_exhaustive] -pub struct SigningParams<'a, S> { - /// Access Key ID to use. - pub(crate) access_key: &'a str, - /// Secret access key to use. - pub(crate) secret_key: &'a str, - /// (Optional) Security token to use. - pub(crate) security_token: Option<&'a str>, - - /// Region to sign for. - pub(crate) region: &'a str, - /// AWS Service Name to sign for. - pub(crate) service_name: &'a str, - /// Timestamp to use in the signature (should be `SystemTime::now()` unless testing). - pub(crate) time: SystemTime, - - /// Additional signing settings. These differ between HTTP and Event Stream. - pub(crate) settings: S, -} - -impl<'a, S> SigningParams<'a, S> { - /// Returns the region that will be used to sign - pub fn region(&self) -> &str { - self.region - } - - /// Returns the service name that will be used to sign - pub fn service_name(&self) -> &str { - self.service_name - } +pub enum SignatureVersion { + /// The SigV4 signing algorithm. + V4, + /// The SigV4a signing algorithm. + V4a, } -impl<'a, S: fmt::Debug> fmt::Debug for SigningParams<'a, S> { +impl fmt::Display for SignatureVersion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SigningParams") - .field("access_key", &"** redacted **") - .field("secret_key", &"** redacted **") - .field("security_token", &"** redacted **") - .field("region", &self.region) - .field("service_name", &self.service_name) - .field("time", &self.time) - .field("settings", &self.settings) - .finish() - } -} - -impl<'a, S: Default> SigningParams<'a, S> { - /// Returns a builder that can create new `SigningParams`. - pub fn builder() -> signing_params::Builder<'a, S> { - Default::default() - } -} - -/// Builder and error for creating [`SigningParams`] -pub mod signing_params { - use super::SigningParams; - use std::error::Error; - use std::fmt; - use std::time::SystemTime; - - /// [`SigningParams`] builder error - #[derive(Debug)] - pub struct BuildError { - reason: &'static str, - } - impl BuildError { - fn new(reason: &'static str) -> Self { - Self { reason } - } - } - - impl fmt::Display for BuildError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.reason) - } - } - - impl Error for BuildError {} - - /// Builder that can create new [`SigningParams`] - #[derive(Debug, Default)] - pub struct Builder<'a, S> { - access_key: Option<&'a str>, - secret_key: Option<&'a str>, - security_token: Option<&'a str>, - region: Option<&'a str>, - service_name: Option<&'a str>, - time: Option, - settings: Option, - } - - impl<'a, S> Builder<'a, S> { - /// Sets the access key (required). - pub fn access_key(mut self, access_key: &'a str) -> Self { - self.access_key = Some(access_key); - self - } - /// Sets the access key (required) - pub fn set_access_key(&mut self, access_key: Option<&'a str>) { - self.access_key = access_key; - } - - /// Sets the secret key (required) - pub fn secret_key(mut self, secret_key: &'a str) -> Self { - self.secret_key = Some(secret_key); - self - } - /// Sets the secret key (required) - pub fn set_secret_key(&mut self, secret_key: Option<&'a str>) { - self.secret_key = secret_key; - } - - /// Sets the security token (optional) - pub fn security_token(mut self, security_token: &'a str) -> Self { - self.security_token = Some(security_token); - self - } - /// Sets the security token (optional) - pub fn set_security_token(&mut self, security_token: Option<&'a str>) { - self.security_token = security_token; - } - - /// Sets the region (required) - pub fn region(mut self, region: &'a str) -> Self { - self.region = Some(region); - self - } - /// Sets the region (required) - pub fn set_region(&mut self, region: Option<&'a str>) { - self.region = region; - } - - /// Sets the service name (required) - pub fn service_name(mut self, service_name: &'a str) -> Self { - self.service_name = Some(service_name); - self - } - /// Sets the service name (required) - pub fn set_service_name(&mut self, service_name: Option<&'a str>) { - self.service_name = service_name; - } - - /// Sets the time to be used in the signature (required) - pub fn time(mut self, time: SystemTime) -> Self { - self.time = Some(time); - self - } - /// Sets the time to be used in the signature (required) - pub fn set_time(&mut self, time: Option) { - self.time = time; - } - - /// Sets additional signing settings (required) - pub fn settings(mut self, settings: S) -> Self { - self.settings = Some(settings); - self - } - /// Sets additional signing settings (required) - pub fn set_settings(&mut self, settings: Option) { - self.settings = settings; - } - - /// Builds an instance of [`SigningParams`]. Will yield a [`BuildError`] if - /// a required argument was not given. - pub fn build(self) -> Result, BuildError> { - Ok(SigningParams { - access_key: self - .access_key - .ok_or_else(|| BuildError::new("access key is required"))?, - secret_key: self - .secret_key - .ok_or_else(|| BuildError::new("secret key is required"))?, - security_token: self.security_token, - region: self - .region - .ok_or_else(|| BuildError::new("region is required"))?, - service_name: self - .service_name - .ok_or_else(|| BuildError::new("service name is required"))?, - time: self - .time - .ok_or_else(|| BuildError::new("time is required"))?, - settings: self - .settings - .ok_or_else(|| BuildError::new("settings are required"))?, - }) + match self { + SignatureVersion::V4 => write!(f, "SigV4"), + SignatureVersion::V4a => write!(f, "SigV4a"), } } } diff --git a/aws/rust-runtime/aws-sigv4/src/sign.rs b/aws/rust-runtime/aws-sigv4/src/sign.rs index 43e9da1ac1..244ae3f159 100644 --- a/aws/rust-runtime/aws-sigv4/src/sign.rs +++ b/aws/rust-runtime/aws-sigv4/src/sign.rs @@ -5,86 +5,10 @@ //! Functions to create signing keys and calculate signatures. -use crate::date_time::format_date; -use hmac::{digest::FixedOutput, Hmac, Mac}; -use sha2::{Digest, Sha256}; -use std::time::SystemTime; +/// Support for Sigv4 signing +pub mod v4; +#[cfg(feature = "sigv4a")] +/// Support for Sigv4a signing +pub mod v4a; -/// HashedPayload = Lowercase(HexEncode(Hash(requestPayload))) -#[allow(dead_code)] // Unused when compiling without certain features -pub(crate) fn sha256_hex_string(bytes: impl AsRef<[u8]>) -> String { - let mut hasher = Sha256::new(); - hasher.update(bytes); - hex::encode(hasher.finalize_fixed()) -} - -/// Calculates a Sigv4 signature -pub fn calculate_signature(signing_key: impl AsRef<[u8]>, string_to_sign: &[u8]) -> String { - let mut mac = Hmac::::new_from_slice(signing_key.as_ref()) - .expect("HMAC can take key of any size"); - mac.update(string_to_sign); - hex::encode(mac.finalize_fixed()) -} - -/// Generates a signing key for Sigv4 -pub fn generate_signing_key( - secret: &str, - time: SystemTime, - region: &str, - service: &str, -) -> impl AsRef<[u8]> { - // kSecret = your secret access key - // kDate = HMAC("AWS4" + kSecret, Date) - // kRegion = HMAC(kDate, Region) - // kService = HMAC(kRegion, Service) - // kSigning = HMAC(kService, "aws4_request") - - let secret = format!("AWS4{}", secret); - let mut mac = - Hmac::::new_from_slice(secret.as_ref()).expect("HMAC can take key of any size"); - mac.update(format_date(time).as_bytes()); - let tag = mac.finalize_fixed(); - - // sign region - let mut mac = Hmac::::new_from_slice(&tag).expect("HMAC can take key of any size"); - mac.update(region.as_bytes()); - let tag = mac.finalize_fixed(); - - // sign service - let mut mac = Hmac::::new_from_slice(&tag).expect("HMAC can take key of any size"); - mac.update(service.as_bytes()); - let tag = mac.finalize_fixed(); - - // sign request - let mut mac = Hmac::::new_from_slice(&tag).expect("HMAC can take key of any size"); - mac.update("aws4_request".as_bytes()); - mac.finalize_fixed() -} - -#[cfg(test)] -mod tests { - use super::{calculate_signature, generate_signing_key}; - use crate::date_time::test_parsers::parse_date_time; - use crate::http_request::test::test_canonical_request; - use crate::sign::sha256_hex_string; - - #[test] - fn test_signature_calculation() { - let secret = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"; - let creq = test_canonical_request("iam"); - let time = parse_date_time("20150830T123600Z").unwrap(); - - let derived_key = generate_signing_key(secret, time, "us-east-1", "iam"); - let signature = calculate_signature(derived_key, creq.as_bytes()); - - let expected = "5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"; - assert_eq!(expected, &signature); - } - - #[test] - fn sign_payload_empty_string() { - let expected = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; - let actual = sha256_hex_string([]); - assert_eq!(expected, actual); - } -} +pub use v4::{calculate_signature, generate_signing_key}; diff --git a/aws/rust-runtime/aws-sigv4/src/sign/v4.rs b/aws/rust-runtime/aws-sigv4/src/sign/v4.rs new file mode 100644 index 0000000000..999574c6cd --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/src/sign/v4.rs @@ -0,0 +1,229 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use crate::date_time::format_date; +use aws_smithy_runtime_api::client::identity::Identity; +use hmac::{digest::FixedOutput, Hmac, Mac}; +use sha2::{Digest, Sha256}; +use std::fmt; +use std::time::SystemTime; + +/// HashedPayload = Lowercase(HexEncode(Hash(requestPayload))) +#[allow(dead_code)] // Unused when compiling without certain features +pub(crate) fn sha256_hex_string(bytes: impl AsRef<[u8]>) -> String { + let mut hasher = Sha256::new(); + hasher.update(bytes); + hex::encode(hasher.finalize_fixed()) +} + +/// Calculates a Sigv4 signature +pub fn calculate_signature(signing_key: impl AsRef<[u8]>, string_to_sign: &[u8]) -> String { + let mut mac = Hmac::::new_from_slice(signing_key.as_ref()) + .expect("HMAC can take key of any size"); + mac.update(string_to_sign); + hex::encode(mac.finalize_fixed()) +} + +/// Generates a signing key for Sigv4 +pub fn generate_signing_key( + secret: &str, + time: SystemTime, + region: &str, + service: &str, +) -> impl AsRef<[u8]> { + // kSecret = your secret access key + // kDate = HMAC("AWS4" + kSecret, Date) + // kRegion = HMAC(kDate, Region) + // kService = HMAC(kRegion, Service) + // kSigning = HMAC(kService, "aws4_request") + + let secret = format!("AWS4{}", secret); + let mut mac = + Hmac::::new_from_slice(secret.as_ref()).expect("HMAC can take key of any size"); + mac.update(format_date(time).as_bytes()); + let tag = mac.finalize_fixed(); + + // sign region + let mut mac = Hmac::::new_from_slice(&tag).expect("HMAC can take key of any size"); + mac.update(region.as_bytes()); + let tag = mac.finalize_fixed(); + + // sign service + let mut mac = Hmac::::new_from_slice(&tag).expect("HMAC can take key of any size"); + mac.update(service.as_bytes()); + let tag = mac.finalize_fixed(); + + // sign request + let mut mac = Hmac::::new_from_slice(&tag).expect("HMAC can take key of any size"); + mac.update("aws4_request".as_bytes()); + mac.finalize_fixed() +} + +/// Parameters to use when signing. +#[non_exhaustive] +pub struct SigningParams<'a, S> { + /// The identity to use when signing a request + pub(crate) identity: Identity, + /// Region to sign for. + pub(crate) region: &'a str, + /// Name to sign for. + pub(crate) name: &'a str, + /// Timestamp to use in the signature (should be `SystemTime::now()` unless testing). + pub(crate) time: SystemTime, + + /// Additional signing settings. These differ between HTTP and Event Stream. + pub(crate) settings: S, +} + +const HMAC_256: &str = "AWS4-HMAC-SHA256"; + +impl<'a, S> SigningParams<'a, S> { + /// Returns the region that will be used to sign SigV4 requests + pub fn region(&self) -> &str { + self.region + } + + /// Returns the signing name that will be used to sign requests + pub fn name(&self) -> &str { + self.name + } + + /// Return the name of the algorithm used to sign requests + pub fn algorithm(&self) -> &'static str { + HMAC_256 + } +} + +impl<'a, S: fmt::Debug> fmt::Debug for SigningParams<'a, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SigningParams") + .field("identity", &"** redacted **") + .field("region", &self.region) + .field("name", &self.name) + .field("time", &self.time) + .field("settings", &self.settings) + .finish() + } +} + +impl<'a, S: Default> SigningParams<'a, S> { + /// Returns a builder that can create new `SigningParams`. + pub fn builder() -> signing_params::Builder<'a, S> { + Default::default() + } +} + +/// Builder and error for creating [`SigningParams`] +pub mod signing_params { + use super::SigningParams; + use aws_smithy_runtime_api::builder_methods; + use aws_smithy_runtime_api::client::identity::Identity; + use std::error::Error; + use std::fmt; + use std::time::SystemTime; + + /// [`SigningParams`] builder error + #[derive(Debug)] + pub struct BuildError { + reason: &'static str, + } + impl BuildError { + fn new(reason: &'static str) -> Self { + Self { reason } + } + } + + impl fmt::Display for BuildError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.reason) + } + } + + impl Error for BuildError {} + + /// Builder that can create new [`SigningParams`] + #[derive(Debug, Default)] + pub struct Builder<'a, S> { + identity: Option, + region: Option<&'a str>, + name: Option<&'a str>, + time: Option, + settings: Option, + } + + impl<'a, S> Builder<'a, S> { + builder_methods!( + set_identity, + identity, + Identity, + "Sets the identity (required)", + set_region, + region, + &'a str, + "Sets the region (required)", + set_name, + name, + &'a str, + "Sets the name (required)", + set_time, + time, + SystemTime, + " /// Sets the time to be used in the signature (required)", + set_settings, + settings, + S, + "Sets additional signing settings (required)" + ); + + /// Builds an instance of [`SigningParams`]. Will yield a [`BuildError`] if + /// a required argument was not given. + pub fn build(self) -> Result, BuildError> { + Ok(SigningParams { + identity: self + .identity + .ok_or_else(|| BuildError::new("An identity is required"))?, + region: self + .region + .ok_or_else(|| BuildError::new("region is required"))?, + name: self + .name + .ok_or_else(|| BuildError::new("name is required"))?, + time: self + .time + .ok_or_else(|| BuildError::new("time is required"))?, + settings: self + .settings + .ok_or_else(|| BuildError::new("settings are required"))?, + }) + } + } +} + +#[cfg(test)] +mod tests { + use super::{calculate_signature, generate_signing_key, sha256_hex_string}; + use crate::date_time::test_parsers::parse_date_time; + use crate::http_request::test_v4::test_canonical_request; + + #[test] + fn test_signature_calculation() { + let secret = "wJalrXUtnFEMI/K7MDENG+bPxRfiCYEXAMPLEKEY"; + let creq = test_canonical_request("iam"); + let time = parse_date_time("20150830T123600Z").unwrap(); + + let derived_key = generate_signing_key(secret, time, "us-east-1", "iam"); + let signature = calculate_signature(derived_key, creq.as_bytes()); + + let expected = "5d672d79c15b13162d9279b0855cfba6789a8edb4c82c400e06b5924a6f2b5d7"; + assert_eq!(expected, &signature); + } + + #[test] + fn sign_payload_empty_string() { + let expected = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"; + let actual = sha256_hex_string([]); + assert_eq!(expected, actual); + } +} diff --git a/aws/rust-runtime/aws-sigv4/src/sign/v4a.rs b/aws/rust-runtime/aws-sigv4/src/sign/v4a.rs new file mode 100644 index 0000000000..5f1dd23472 --- /dev/null +++ b/aws/rust-runtime/aws-sigv4/src/sign/v4a.rs @@ -0,0 +1,214 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +use aws_smithy_runtime_api::client::identity::Identity; +use bytes::{BufMut, BytesMut}; +use num_bigint::BigInt; +use once_cell::sync::Lazy; +use p256::ecdsa::{signature::Signer, DerSignature, SigningKey}; +use std::fmt; +use std::io::Write; +use std::time::SystemTime; +use zeroize::Zeroizing; + +const ALGORITHM: &[u8] = b"AWS4-ECDSA-P256-SHA256"; +static BIG_N_MINUS_2: Lazy = Lazy::new(|| { + const ORDER: &[u32] = &[ + 0xFFFFFFFF, 0x00000000, 0xFFFFFFFF, 0xFFFFFFFF, 0xBCE6FAAD, 0xA7179E84, 0xF3B9CAC2, + 0xFC632551, + ]; + let big_n = BigInt::from_slice(num_bigint::Sign::Plus, ORDER); + big_n - BigInt::from(2i32) +}); + +/// Calculates a Sigv4a signature +pub fn calculate_signature(signing_key: &SigningKey, string_to_sign: &[u8]) -> String { + let signature: DerSignature = signing_key.sign(string_to_sign); + hex::encode(signature.as_ref()) +} + +/// Generates a signing key for Sigv4a. +pub fn generate_signing_key(access_key: &str, secret_access_key: &str) -> SigningKey { + // Capacity is the secret access key length plus the length of "AWS4A" + let mut input_key = Zeroizing::new(Vec::with_capacity(secret_access_key.len() + 5)); + write!(input_key, "AWS4A{secret_access_key}").unwrap(); + + // Capacity is the access key length plus the counter byte + let mut kdf_context = Zeroizing::new(Vec::with_capacity(access_key.len() + 1)); + let mut counter = Zeroizing::new(1u8); + let key = loop { + write!(kdf_context, "{access_key}").unwrap(); + kdf_context.push(*counter); + + let mut fis = ALGORITHM.to_vec(); + fis.push(0); + fis.append(&mut kdf_context); + fis.put_i32(256); + + let key = ring::hmac::Key::new(ring::hmac::HMAC_SHA256, &input_key); + + let mut buf = BytesMut::new(); + buf.put_i32(1); + buf.put_slice(&fis); + let tag = ring::hmac::sign(&key, &buf); + let tag = &tag.as_ref()[0..32]; + + let k0 = BigInt::from_bytes_be(num_bigint::Sign::Plus, tag); + + // It would be more secure for this to be a constant time comparison, but because this + // is for client usage, that's not as big a deal. + if k0 <= *BIG_N_MINUS_2 { + let pk = k0 + BigInt::from(1i32); + let d = Zeroizing::new(pk.to_bytes_be().1); + break SigningKey::from_slice(&d).unwrap(); + } + + *counter = counter + .checked_add(1) + .expect("counter will never get to 255"); + }; + + key +} + +/// Parameters to use when signing. +#[non_exhaustive] +pub struct SigningParams<'a, S> { + /// The identity to use when signing a request + pub(crate) identity: Identity, + /// Region set to sign for. + pub(crate) region_set: &'a str, + /// AWS Service Name to sign for. + pub(crate) service_name: &'a str, + /// Timestamp to use in the signature (should be `SystemTime::now()` unless testing). + pub(crate) time: SystemTime, + + /// Additional signing settings. These differ between HTTP and Event Stream. + pub(crate) settings: S, +} + +pub(crate) const ECDSA_256: &str = "AWS4-ECDSA-P256-SHA256"; + +impl<'a, S> SigningParams<'a, S> { + /// Returns the region that will be used to sign SigV4a requests + pub fn region_set(&self) -> &str { + self.region_set + } + + /// Returns the service name that will be used to sign requests + pub fn service_name(&self) -> &str { + self.service_name + } + + /// Return the name of the algorithm used to sign requests + pub fn algorithm(&self) -> &'static str { + ECDSA_256 + } +} + +impl<'a, S: fmt::Debug> fmt::Debug for SigningParams<'a, S> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SigningParams") + .field("identity", &"** redacted **") + .field("region_set", &self.region_set) + .field("service_name", &self.service_name) + .field("time", &self.time) + .field("settings", &self.settings) + .finish() + } +} + +impl<'a, S: Default> SigningParams<'a, S> { + /// Returns a builder that can create new `SigningParams`. + pub fn builder() -> signing_params::Builder<'a, S> { + Default::default() + } +} + +/// Builder and error for creating [`SigningParams`] +pub mod signing_params { + use super::SigningParams; + use aws_smithy_runtime_api::builder_methods; + use aws_smithy_runtime_api::client::identity::Identity; + use std::error::Error; + use std::fmt; + use std::time::SystemTime; + + /// [`SigningParams`] builder error + #[derive(Debug)] + pub struct BuildError { + reason: &'static str, + } + impl BuildError { + fn new(reason: &'static str) -> Self { + Self { reason } + } + } + + impl fmt::Display for BuildError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.reason) + } + } + + impl Error for BuildError {} + + /// Builder that can create new [`SigningParams`] + #[derive(Debug, Default)] + pub struct Builder<'a, S> { + identity: Option, + region_set: Option<&'a str>, + service_name: Option<&'a str>, + time: Option, + settings: Option, + } + + impl<'a, S> Builder<'a, S> { + builder_methods!( + set_identity, + identity, + Identity, + "Sets the identity (required)", + set_region_set, + region_set, + &'a str, + "Sets the region set (required)", + set_service_name, + service_name, + &'a str, + "Sets the service_name (required)", + set_time, + time, + SystemTime, + "Sets the time to be used in the signature (required)", + set_settings, + settings, + S, + "Sets additional signing settings (required)" + ); + + /// Builds an instance of [`SigningParams`]. Will yield a [`BuildError`] if + /// a required argument was not given. + pub fn build(self) -> Result, BuildError> { + Ok(SigningParams { + identity: self + .identity + .ok_or_else(|| BuildError::new("An identity is required"))?, + region_set: self + .region_set + .ok_or_else(|| BuildError::new("region_set is required"))?, + service_name: self + .service_name + .ok_or_else(|| BuildError::new("service name is required"))?, + time: self + .time + .ok_or_else(|| BuildError::new("time is required"))?, + settings: self + .settings + .ok_or_else(|| BuildError::new("settings are required"))?, + }) + } + } +} diff --git a/aws/rust-runtime/aws-types/src/lib.rs b/aws/rust-runtime/aws-types/src/lib.rs index ed4e635037..444f6cc6fc 100644 --- a/aws/rust-runtime/aws-types/src/lib.rs +++ b/aws/rust-runtime/aws-types/src/lib.rs @@ -28,36 +28,38 @@ pub use sdk_config::SdkConfig; use aws_smithy_types::config_bag::{Storable, StoreReplace}; use std::borrow::Cow; -/// The name of the service used to sign this request +/// The name of the service used to sign this request. /// -/// Generally, user code should never interact with `SigningService` directly +/// The signing name may be overridden by the endpoint resolver, +/// or by specifying a custom name during operation construction. #[derive(Clone, Debug, PartialEq, Eq)] -pub struct SigningService(Cow<'static, str>); -impl AsRef for SigningService { +pub struct SigningName(Cow<'static, str>); + +impl AsRef for SigningName { fn as_ref(&self) -> &str { &self.0 } } -impl SigningService { - /// Creates a `SigningService` from a static str. - pub fn from_static(service: &'static str) -> Self { - SigningService(Cow::Borrowed(service)) +impl SigningName { + /// Creates a `SigningName` from a static str. + pub fn from_static(signing_name: &'static str) -> Self { + SigningName(Cow::Borrowed(signing_name)) } } -impl From for SigningService { - fn from(service: String) -> Self { - SigningService(Cow::Owned(service)) +impl From for SigningName { + fn from(signing_name: String) -> Self { + SigningName(Cow::Owned(signing_name)) } } -impl From<&'static str> for SigningService { - fn from(service: &'static str) -> Self { - Self::from_static(service) +impl From<&'static str> for SigningName { + fn from(signing_name: &'static str) -> Self { + Self::from_static(signing_name) } } -impl Storable for SigningService { +impl Storable for SigningName { type Storer = StoreReplace; } diff --git a/aws/rust-runtime/aws-types/src/region.rs b/aws/rust-runtime/aws-types/src/region.rs index a58f809a70..c5e5f0ae2e 100644 --- a/aws/rust-runtime/aws-types/src/region.rs +++ b/aws/rust-runtime/aws-types/src/region.rs @@ -52,7 +52,7 @@ impl Region { } } -/// The region to use when signing requests +/// The region to use when signing sigv4 requests /// /// Generally, user code will not need to interact with `SigningRegion`. See `[Region](crate::Region)`. #[derive(Clone, Debug, PartialEq, Eq)] @@ -86,3 +86,49 @@ impl SigningRegion { impl Storable for SigningRegion { type Storer = StoreReplace; } + +/// The region to use when signing Sigv4a requests +/// +/// Generally, user code will not need to interact with `SigningRegionSet`. See `[Region](crate::Region)`. +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SigningRegionSet(Cow<'static, str>); + +impl From for SigningRegionSet { + fn from(inp: Region) -> Self { + SigningRegionSet(inp.0) + } +} + +impl From<&'static str> for SigningRegionSet { + fn from(region: &'static str) -> Self { + Self::from_static(region) + } +} + +impl SigningRegionSet { + /// Create a `SigningRegionSet` from a static str. + pub const fn from_static(region_set: &'static str) -> Self { + SigningRegionSet(Cow::Borrowed(region_set)) + } + + /// Create a new `SigningRegionSet` that's valid for all regions. + pub fn wildcard() -> Self { + Self(Cow::Borrowed("*")) + } + + /// Create a new `SigningRegionSet` from a list of regions. + pub fn from_vec(vec: Vec) -> Self { + let set = vec.join(", "); + Self(Cow::Owned(set)) + } +} + +impl Storable for SigningRegionSet { + type Storer = StoreReplace; +} + +impl AsRef for SigningRegionSet { + fn as_ref(&self) -> &str { + self.0.as_ref() + } +} diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt index 952cb35e60..0ceaea66cd 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/AwsCodegenDecorator.kt @@ -35,6 +35,7 @@ val DECORATORS: List = listOf( RequireEndpointRules(), UserAgentDecorator(), SigV4AuthDecorator(), + SigV4aAuthDecorator(), SigV4SigningDecorator(), HttpRequestChecksumDecorator(), HttpResponseChecksumDecorator(), diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt index 0437075d3e..96af4a1450 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/CredentialProviders.kt @@ -140,20 +140,35 @@ class CredentialsIdentityResolverRegistration( when (section) { is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { rustBlockTemplate("if let Some(credentials_cache) = ${section.serviceConfigName}.credentials_cache()") { + rustTemplate( + """ + let shared_identity_resolver = #{SharedIdentityResolver}::new( + #{CredentialsIdentityResolver}::new(credentials_cache) + ); + """, + "CredentialsIdentityResolver" to AwsRuntimeType.awsRuntime(runtimeConfig) + .resolve("identity::credentials::CredentialsIdentityResolver"), + "SharedIdentityResolver" to RuntimeType.smithyRuntimeApi(runtimeConfig) + .resolve("client::identity::SharedIdentityResolver"), + ) + section.registerIdentityResolver(this) { + rustTemplate( + """ + #{SIGV4A_SCHEME_ID}, + shared_identity_resolver.clone(), + """, + "SIGV4A_SCHEME_ID" to AwsRuntimeType.awsRuntime(runtimeConfig) + .resolve("auth::sigv4a::SCHEME_ID"), + ) + } section.registerIdentityResolver(this) { rustTemplate( """ #{SIGV4_SCHEME_ID}, - #{SharedIdentityResolver}::new( - #{CredentialsIdentityResolver}::new(credentials_cache), - ), + shared_identity_resolver, """, "SIGV4_SCHEME_ID" to AwsRuntimeType.awsRuntime(runtimeConfig) .resolve("auth::sigv4::SCHEME_ID"), - "CredentialsIdentityResolver" to AwsRuntimeType.awsRuntime(runtimeConfig) - .resolve("identity::credentials::CredentialsIdentityResolver"), - "SharedIdentityResolver" to RuntimeType.smithyRuntimeApi(runtimeConfig) - .resolve("client::identity::SharedIdentityResolver"), ) } } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt index 279626e508..1bd2f1aa99 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4AuthDecorator.kt @@ -68,10 +68,7 @@ private class AuthServiceRuntimePluginCustomization(private val codegenContext: private val codegenScope by lazy { val awsRuntime = AwsRuntimeType.awsRuntime(runtimeConfig) arrayOf( - "SIGV4_SCHEME_ID" to awsRuntime.resolve("auth::sigv4::SCHEME_ID"), "SigV4AuthScheme" to awsRuntime.resolve("auth::sigv4::SigV4AuthScheme"), - "SigningRegion" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::SigningRegion"), - "SigningService" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningService"), "SharedAuthScheme" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::auth::SharedAuthScheme"), ) } @@ -99,13 +96,10 @@ private class AuthOperationCustomization(private val codegenContext: ClientCodeg private val codegenScope by lazy { val awsRuntime = AwsRuntimeType.awsRuntime(runtimeConfig) arrayOf( - "HttpSignatureType" to awsRuntime.resolve("auth::sigv4::HttpSignatureType"), - "SIGV4_SCHEME_ID" to awsRuntime.resolve("auth::sigv4::SCHEME_ID"), - "SigV4OperationSigningConfig" to awsRuntime.resolve("auth::sigv4::SigV4OperationSigningConfig"), - "SigningOptions" to awsRuntime.resolve("auth::sigv4::SigningOptions"), - "SigningRegion" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::SigningRegion"), - "SigningService" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningService"), + "SigV4OperationSigningConfig" to awsRuntime.resolve("auth::SigV4OperationSigningConfig"), + "SigningOptions" to awsRuntime.resolve("auth::SigningOptions"), "SignableBody" to AwsRuntimeType.awsSigv4(runtimeConfig).resolve("http_request::SignableBody"), + "Default" to RuntimeType.Default, ) } private val serviceIndex = ServiceIndex.of(codegenContext.model) @@ -128,9 +122,8 @@ private class AuthOperationCustomization(private val codegenContext: ClientCodeg signing_options.payload_override = #{payload_override}; ${section.newLayerName}.store_put(#{SigV4OperationSigningConfig} { - region: None, - service: None, signing_options, + ..#{Default}::default() }); """, *codegenScope, diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecorator.kt index c7ba6f9c60..1e68007eaa 100644 --- a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecorator.kt +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecorator.kt @@ -36,9 +36,9 @@ import software.amazon.smithy.rust.codegen.core.util.isInputEventStream // TODO(enableNewSmithyRuntimeCleanup): Remove this decorator (superseded by SigV4AuthDecorator) /** * The SigV4SigningDecorator: - * - adds a `signing_service()` method to `config` to return the default signing service + * - adds a `signing_name()` method to `config` to return the default signing name * - adds a `new_event_stream_signer()` method to `config` to create an Event Stream SigV4 signer - * - sets the `SigningService` during operation construction + * - sets the `SigningName` during operation construction * - sets a default `OperationSigningConfig` A future enhancement will customize this for specific services that need * different behavior. */ @@ -86,7 +86,7 @@ class SigV4SigningConfig( ) : ConfigCustomization() { private val codegenScope = arrayOf( "Region" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::Region"), - "SigningService" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningService"), + "SigningName" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("SigningName"), "SigningRegion" to AwsRuntimeType.awsTypes(runtimeConfig).resolve("region::SigningRegion"), ) @@ -101,9 +101,9 @@ class SigV4SigningConfig( """ /// The signature version 4 service signing name to use in the credential scope when signing requests. /// - /// The signing service may be overridden by the `Endpoint`, or by specifying a custom - /// [`SigningService`](aws_types::SigningService) during operation construction - pub fn signing_service(&self) -> &'static str { + /// The signing name may be overridden by the `Endpoint`, or by specifying a custom + /// [`SigningName`](aws_types::SigningName) during operation construction. + pub fn signing_name(&self) -> &'static str { ${sigV4Trait.name.dq()} } """, @@ -113,7 +113,7 @@ class SigV4SigningConfig( if (runtimeMode.generateOrchestrator) { rustTemplate( """ - layer.store_put(#{SigningService}::from_static(${sigV4Trait.name.dq()})); + layer.store_put(#{SigningName}::from_static(${sigV4Trait.name.dq()})); layer.load::<#{Region}>().cloned().map(|r| layer.store_put(#{SigningRegion}::from(r))); """, *codegenScope, @@ -203,7 +203,7 @@ class SigV4SigningFeature( rustTemplate( """ ${section.request}.properties_mut().insert(signing_config); - ${section.request}.properties_mut().insert(#{aws_types}::SigningService::from_static(${section.config}.signing_service())); + ${section.request}.properties_mut().insert(#{aws_types}::SigningName::from_static(${section.config}.signing_name())); if let Some(region) = &${section.config}.region { ${section.request}.properties_mut().insert(#{aws_types}::region::SigningRegion::from(region.clone())); } diff --git a/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4aAuthDecorator.kt b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4aAuthDecorator.kt new file mode 100644 index 0000000000..8769e7624f --- /dev/null +++ b/aws/sdk-codegen/src/main/kotlin/software/amazon/smithy/rustsdk/SigV4aAuthDecorator.kt @@ -0,0 +1,141 @@ +/* + * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + * SPDX-License-Identifier: Apache-2.0 + */ + +package software.amazon.smithy.rustsdk + +import software.amazon.smithy.aws.traits.auth.SigV4Trait +import software.amazon.smithy.aws.traits.auth.UnsignedPayloadTrait +import software.amazon.smithy.model.knowledge.ServiceIndex +import software.amazon.smithy.model.shapes.OperationShape +import software.amazon.smithy.rust.codegen.client.smithy.ClientCodegenContext +import software.amazon.smithy.rust.codegen.client.smithy.customize.AuthSchemeOption +import software.amazon.smithy.rust.codegen.client.smithy.customize.ClientCodegenDecorator +import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.OperationSection +import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginCustomization +import software.amazon.smithy.rust.codegen.client.smithy.generators.ServiceRuntimePluginSection +import software.amazon.smithy.rust.codegen.core.rustlang.Writable +import software.amazon.smithy.rust.codegen.core.rustlang.rust +import software.amazon.smithy.rust.codegen.core.rustlang.rustTemplate +import software.amazon.smithy.rust.codegen.core.rustlang.writable +import software.amazon.smithy.rust.codegen.core.smithy.RuntimeType +import software.amazon.smithy.rust.codegen.core.util.hasTrait +import software.amazon.smithy.rust.codegen.core.util.isInputEventStream +import software.amazon.smithy.rust.codegen.core.util.letIf + +class SigV4aAuthDecorator : ClientCodegenDecorator { + override val name: String get() = "SigV4aAuthDecorator" + override val order: Byte = (SigV4AuthDecorator().order + 1).toByte() + + override fun authOptions( + codegenContext: ClientCodegenContext, + operationShape: OperationShape, + baseAuthSchemeOptions: List, + ): List = baseAuthSchemeOptions.letIf(codegenContext.smithyRuntimeMode.generateOrchestrator) { + it + AuthSchemeOption.StaticAuthSchemeOption(SigV4Trait.ID) { + rustTemplate( + "#{scheme_id},", + "scheme_id" to AwsRuntimeType.awsRuntime(codegenContext.runtimeConfig) + .resolve("auth::sigv4a::SCHEME_ID"), + ) + } + } + + override fun serviceRuntimePluginCustomizations( + codegenContext: ClientCodegenContext, + baseCustomizations: List, + ): List = + baseCustomizations.letIf(codegenContext.smithyRuntimeMode.generateOrchestrator) { + it + listOf(V4aAuthServiceRuntimePluginCustomization(codegenContext)) + } + + override fun operationCustomizations( + codegenContext: ClientCodegenContext, + operation: OperationShape, + baseCustomizations: List, + ): List = + baseCustomizations.letIf(codegenContext.smithyRuntimeMode.generateOrchestrator) { + it + listOf(V4aAuthOperationCustomization(codegenContext)) + } +} + +private class V4aAuthServiceRuntimePluginCustomization(codegenContext: ClientCodegenContext) : + ServiceRuntimePluginCustomization() { + private val runtimeConfig = codegenContext.runtimeConfig + private val codegenScope by lazy { + val awsRuntime = AwsRuntimeType.awsRuntime(runtimeConfig) + arrayOf( + "SigV4aAuthScheme" to awsRuntime.resolve("auth::sigv4a::SigV4aAuthScheme"), + "SharedAuthScheme" to RuntimeType.smithyRuntimeApi(runtimeConfig).resolve("client::auth::SharedAuthScheme"), + ) + } + + override fun section(section: ServiceRuntimePluginSection): Writable = writable { + when (section) { + is ServiceRuntimePluginSection.RegisterRuntimeComponents -> { + section.registerAuthScheme(this) { + rustTemplate("#{SharedAuthScheme}::new(#{SigV4aAuthScheme}::new())", *codegenScope) + } + } + + else -> {} + } + } +} + +private class V4aAuthOperationCustomization(private val codegenContext: ClientCodegenContext) : OperationCustomization() { + private val runtimeConfig = codegenContext.runtimeConfig + private val codegenScope by lazy { + val awsRuntime = AwsRuntimeType.awsRuntime(runtimeConfig) + arrayOf( + "SigV4OperationSigningConfig" to awsRuntime.resolve("auth::SigV4OperationSigningConfig"), + "SigningOptions" to awsRuntime.resolve("auth::SigningOptions"), + "SignableBody" to AwsRuntimeType.awsSigv4(runtimeConfig).resolve("http_request::SignableBody"), + "Default" to RuntimeType.Default, + ) + } + private val serviceIndex = ServiceIndex.of(codegenContext.model) + + override fun section(section: OperationSection): Writable = writable { + when (section) { + is OperationSection.AdditionalRuntimePluginConfig -> { + val authSchemes = serviceIndex.getEffectiveAuthSchemes(codegenContext.serviceShape, section.operationShape) + if (authSchemes.containsKey(SigV4Trait.ID)) { + val unsignedPayload = section.operationShape.hasTrait() + val doubleUriEncode = unsignedPayload || !disableDoubleEncode(codegenContext.serviceShape) + val contentSha256Header = needsAmzSha256(codegenContext.serviceShape) + val normalizeUrlPath = !disableUriPathNormalization(codegenContext.serviceShape) + rustTemplate( + """ + let mut signing_options = #{SigningOptions}::default(); + signing_options.double_uri_encode = $doubleUriEncode; + signing_options.content_sha256_header = $contentSha256Header; + signing_options.normalize_uri_path = $normalizeUrlPath; + signing_options.payload_override = #{payload_override}; + + ${section.newLayerName}.store_put(#{SigV4OperationSigningConfig} { + signing_options, + ..#{Default}::default() + }); + """, + *codegenScope, + "payload_override" to writable { + if (unsignedPayload) { + rustTemplate("Some(#{SignableBody}::UnsignedPayload)", *codegenScope) + } else if (section.operationShape.isInputEventStream(codegenContext.model)) { + // TODO(EventStream): Is this actually correct for all Event Stream operations? + rustTemplate("Some(#{SignableBody}::Bytes(&[]))", *codegenScope) + } else { + rust("None") + } + }, + ) + } + } + + else -> {} + } + } +} diff --git a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecoratorTest.kt b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecoratorTest.kt index fae4da0386..d2bd4d36f9 100644 --- a/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecoratorTest.kt +++ b/aws/sdk-codegen/src/test/kotlin/software/amazon/smithy/rustsdk/SigV4SigningDecoratorTest.kt @@ -38,10 +38,10 @@ internal class SigV4SigningDecoratorTest { ) project.lib { unitTest( - "signing_service_override", + "signing_name_override", """ let conf = crate::config::Config::builder().build(); - assert_eq!(conf.signing_service(), "test-service"); + assert_eq!(conf.signing_name(), "test-service"); """, ) } diff --git a/aws/sdk/build.gradle.kts b/aws/sdk/build.gradle.kts index ebf1b3a705..b2fff6eb90 100644 --- a/aws/sdk/build.gradle.kts +++ b/aws/sdk/build.gradle.kts @@ -279,7 +279,6 @@ fun rewritePathDependency(line: String): String { } tasks.register("copyAllRuntimes") { - dependsOn("smithyBuildJar") from("$rootDir/aws/rust-runtime") { CrateSet.AWS_SDK_RUNTIME.forEach { include("$it/**") } } diff --git a/aws/sdk/integration-tests/s3/tests/endpoints.rs b/aws/sdk/integration-tests/s3/tests/endpoints.rs index 0479f94bc5..ad535e2c57 100644 --- a/aws/sdk/integration-tests/s3/tests/endpoints.rs +++ b/aws/sdk/integration-tests/s3/tests/endpoints.rs @@ -62,28 +62,6 @@ async fn dual_stack() { ); } -#[cfg(not(aws_sdk_middleware_mode))] -#[tokio::test] -async fn multi_region_access_points() { - let (_captured_request, client) = test_client(|b| b); - let response = client - .get_object() - .bucket("arn:aws:s3::123456789012:accesspoint/mfzwi23gnjvgw.mrap") - .key("blah") - .send() - .await; - let error = response.expect_err("should fail—sigv4a is not supported"); - assert!( - dbg!(format!( - "{}", - aws_smithy_types::error::display::DisplayErrorContext(&error) - )) - .contains("selected auth scheme / endpoint config mismatch"), - "message should contain the correct error, found: {:?}", - error - ); -} - #[cfg(aws_sdk_middleware_mode)] #[tokio::test] async fn multi_region_access_points() { @@ -127,7 +105,10 @@ async fn s3_object_lambda() { assert!( auth_header.starts_with(expected_start), - "expected auth header to start with {} but it was {}", + "expected auth header to start with\n\ + {}\n\ + but it was\n\ + {}", expected_start, auth_header ); diff --git a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt index 73d6756072..0e3cdb629b 100644 --- a/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt +++ b/codegen-client/src/main/kotlin/software/amazon/smithy/rust/codegen/client/smithy/generators/OperationRuntimePluginGenerator.kt @@ -133,10 +133,6 @@ class OperationRuntimePluginGenerator( if (authSchemeOptions.any { it is AuthSchemeOption.CustomResolver }) { throw IllegalStateException("AuthSchemeOption.CustomResolver is unimplemented") } else { - val authOptionsMap = authSchemeOptions.associate { - val option = it as AuthSchemeOption.StaticAuthSchemeOption - option.schemeShapeId to option - } withBlockTemplate( """ .with_auth_scheme_option_resolver(#{Some}( @@ -149,10 +145,19 @@ class OperationRuntimePluginGenerator( var noSupportedAuthSchemes = true val authSchemes = ServiceIndex.of(codegenContext.model) .getEffectiveAuthSchemes(codegenContext.serviceShape, operationShape) + for (schemeShapeId in authSchemes.keys) { - val authOption = authOptionsMap[schemeShapeId] - if (authOption != null) { - authOption.constructor(this) + val optionsForScheme = authSchemeOptions.filter { + when (it) { + is AuthSchemeOption.CustomResolver -> false + is AuthSchemeOption.StaticAuthSchemeOption -> { + it.schemeShapeId == schemeShapeId + } + } + } + + if (optionsForScheme.isNotEmpty()) { + optionsForScheme.forEach { (it as AuthSchemeOption.StaticAuthSchemeOption).constructor(this) } noSupportedAuthSchemes = false } else { logger.warning( @@ -162,9 +167,11 @@ class OperationRuntimePluginGenerator( } } if (operationShape.hasTrait() || noSupportedAuthSchemes) { - val authOption = authOptionsMap[noAuthSchemeShapeId] + val authOption = authSchemeOptions.find { + it is AuthSchemeOption.StaticAuthSchemeOption && it.schemeShapeId == noAuthSchemeShapeId + } ?: throw IllegalStateException("Missing 'no auth' implementation. This is a codegen bug.") - authOption.constructor(this) + (authOption as AuthSchemeOption.StaticAuthSchemeOption).constructor(this) } } } diff --git a/design/src/transport/operation.md b/design/src/transport/operation.md index 9ca8a4dfc9..6917a78966 100644 --- a/design/src/transport/operation.md +++ b/design/src/transport/operation.md @@ -47,7 +47,7 @@ pub fn build(self, config: &dynamodb::config::Config) -> Operation), - AuthSchemeEndpointConfigMismatch(String), + AuthSchemeEndpointConfigMismatch { + desired_scheme: String, + supported_schemes: String, + }, } impl AuthOrchestrationError { fn auth_scheme_endpoint_config_mismatch<'a>( - auth_schemes: impl Iterator, + desired_scheme: impl Into, + supported_schemes: impl Iterator, ) -> Self { - Self::AuthSchemeEndpointConfigMismatch( - auth_schemes - .flat_map(|s| match s { - Document::Object(map) => match map.get("name") { - Some(Document::String(name)) => Some(name.as_str()), - _ => None, - }, + let supported_schemes = supported_schemes + .flat_map(|s| match s { + Document::Object(map) => match map.get("name") { + Some(Document::String(name)) => Some(name.as_str()), _ => None, - }) - .collect::>() - .join(", "), - ) + }, + _ => None, + }) + .collect::>() + .join(", "); + + Self::AuthSchemeEndpointConfigMismatch { + desired_scheme: desired_scheme.into(), + supported_schemes, + } } } @@ -52,11 +59,13 @@ impl fmt::Display for AuthOrchestrationError { "no auth scheme matched auth scheme options. This is a bug. Please file an issue.", ), Self::BadAuthSchemeEndpointConfig(message) => f.write_str(message), - Self::AuthSchemeEndpointConfigMismatch(supported_schemes) => { + Self::AuthSchemeEndpointConfigMismatch { + desired_scheme, + supported_schemes, + } => { write!(f, - "selected auth scheme / endpoint config mismatch. Couldn't find `sigv4` endpoint config for this endpoint. \ - The authentication schemes supported by this endpoint are: {:?}", - supported_schemes + "selected auth scheme / endpoint config mismatch. Couldn't find `{desired_scheme}` endpoint config for this endpoint. \ + The authentication schemes supported by this endpoint are: {supported_schemes:?}" ) } } @@ -97,7 +106,13 @@ pub(super) async fn orchestrate_auth( .load::() .expect("endpoint added to config bag by endpoint orchestrator"); let auth_scheme_endpoint_config = - extract_endpoint_auth_scheme_config(endpoint, scheme_id)?; + match extract_endpoint_auth_scheme_config(endpoint, scheme_id) { + Ok(config) => config, + Err(AuthOrchestrationError::AuthSchemeEndpointConfigMismatch { + .. + }) => continue, + other_err => other_err?, + }; trace!(auth_scheme_endpoint_config = ?auth_scheme_endpoint_config, "extracted auth scheme endpoint config"); let identity = identity_resolver.resolve_identity(cfg).await?; @@ -144,7 +159,10 @@ fn extract_endpoint_auth_scheme_config( config_scheme_id == Some(scheme_id.as_str()) }) .ok_or_else(|| { - AuthOrchestrationError::auth_scheme_endpoint_config_mismatch(auth_schemes.iter()) + AuthOrchestrationError::auth_scheme_endpoint_config_mismatch( + scheme_id.as_str(), + auth_schemes.iter(), + ) })?; Ok(AuthSchemeEndpointConfig::from(Some(auth_scheme_config))) } diff --git a/rust-runtime/aws-smithy-types/README.md b/rust-runtime/aws-smithy-types/README.md index ba9dcecc17..f38b39d2f0 100644 --- a/rust-runtime/aws-smithy-types/README.md +++ b/rust-runtime/aws-smithy-types/README.md @@ -1,6 +1,6 @@ # Fundamental Types for Smithy Services -This crate implements fundmental types shared across all service clients generated +This crate implements fundamental types shared across all service clients generated by [smithy-rs](https://github.com/awslabs/smithy-rs). Generally, you should not need to take a direct dependency on this crate as service clients should publicly re-export the types when used.