Skip to content

Commit

Permalink
Merge pull request #469 from rpkelly/aws-sdk-rust
Browse files Browse the repository at this point in the history
Aws sdk rust
  • Loading branch information
rpkelly authored Jul 26, 2022
2 parents 9b56b02 + f6f1a06 commit 973c94c
Show file tree
Hide file tree
Showing 14 changed files with 1,037 additions and 904 deletions.
1,343 changes: 789 additions & 554 deletions Cargo.lock

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ allow = [
"Zlib"
]

exceptions = [
{ name = "unicode-ident", version = "1.0.2", allow = ["MIT", "Apache-2.0", "Unicode-DFS-2016"] },
]

# https://github.com/hsivonen/encoding_rs The non-test code that isn't generated from the WHATWG data in this crate is
# under Apache-2.0 OR MIT. Test code is under CC0.
[[licenses.clarify]]
Expand Down Expand Up @@ -54,10 +58,13 @@ multiple-versions = "deny"
wildcards = "deny"

skip-tree = [
# rusoto_signature uses an older version of itoa
{ name = "rusoto_signature" },
# structopt-derive uses and older verision of heck
{ name = "structopt-derive" },
{ name = "h2", version = "0.3.11" },
# aws sdk depends on hyper, which pulls in an older version of itoa
{ name = "hyper", version = "0.14.16" },
# chrono pulls in an older version of time
{ name = "chrono", version = "0.4.19" },
# structopt is using an older heck
{ name = "heck", version="0.3.3"},
]

[sources]
Expand Down
19 changes: 10 additions & 9 deletions tough-kms/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,24 +9,25 @@ keywords = ["TUF", "KMS"]
edition = "2018"

[features]
default = ["rusoto"]
rusoto = ["rusoto-rustls"]
rusoto-native-tls = ["rusoto_core/native-tls", "rusoto_credential", "rusoto_kms/native-tls"]
rusoto-rustls = ["rusoto_core/rustls", "rusoto_credential", "rusoto_kms/rustls"]
default = ["aws-sdk-rust"]
aws-sdk-rust = ["aws-sdk-rust-rustls"]
aws-sdk-rust-tls = ["aws-config/native-tls", "aws-sdk-kms/native-tls"]
aws-sdk-rust-rustls = ["aws-config/rustls", "aws-sdk-kms/rustls"]

[dependencies]
tough = { version = "0.12.2", path = "../tough", features = ["http"] }
ring = { version = "0.16.16", features = ["std"] }
rusoto_core = { version = "0.48", optional = true, default-features = false }
rusoto_credential = { version = "0.48", optional = true }
rusoto_kms = { version = "0.48", optional = true, default-features = false }
aws-sdk-kms = "0.16.0"
aws-config = "0.46.0"
snafu = { version = "0.7", features = ["backtraces-impl-backtrace-crate"] }
tokio = "1.8"
tokio = { version = "1", features = ["fs", "io-util", "time", "macros", "rt-multi-thread"] }
pem = "1.0.2"

[dev-dependencies]
aws-smithy-client = {version = "0.46.0", features = ["test-util"]}
aws-smithy-http = "0.46.0"
base64 = "0.13"
bytes = "1"
rusoto_mock = { version = "0.48", default-features = false }
http = "0.2"
serde = "1.0.125"
serde_json = "1.0.63"
55 changes: 33 additions & 22 deletions tough-kms/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,43 @@
// SPDX-License-Identifier: MIT OR Apache-2.0

use crate::error::{self, Result};
use rusoto_core::{HttpClient, Region};
use rusoto_credential::ProfileProvider;
use rusoto_kms::KmsClient;
use aws_sdk_kms::Client as KmsClient;
use snafu::ResultExt;
use std::str::FromStr;
use std::thread;

/// Builds a KMS client for a given profile name.
pub(crate) fn build_client_kms(profile: Option<&str>) -> Result<KmsClient> {
Ok(if let Some(profile) = profile {
let mut provider = ProfileProvider::new().context(error::RusotoCredsSnafu)?;
provider.set_profile(profile);
let region = provider
.region_from_profile()
.context(error::RusotoRegionFromProfileSnafu { profile })?;
// We are cloning this so that we can send it across a thread boundary
let profile = profile.map(std::borrow::ToOwned::to_owned);
// We need to spin up a new thread to deal with the async nature of the
// AWS SDK Rust
let client: Result<KmsClient> = thread::spawn(move || {
let runtime = tokio::runtime::Runtime::new().context(error::RuntimeCreationSnafu)?;
Ok(runtime.block_on(async_build_client_kms(profile)))
})
.join()
.map_err(|_| error::Error::ThreadJoin {})?;
client
}

KmsClient::new_with(
HttpClient::new().context(error::RusotoTlsSnafu)?,
provider,
match region {
Some(region) => {
Region::from_str(&region).context(error::RusotoRegionSnafu { region })?
}
None => Region::default(),
},
)
async fn async_build_client_kms(profile: Option<String>) -> KmsClient {
let config = aws_config::from_env();
let client_config = if let Some(profile) = profile {
config
.region(
aws_config::profile::ProfileFileRegionProvider::builder()
.profile_name(&profile)
.build(),
)
.credentials_provider(
aws_config::profile::ProfileFileCredentialsProvider::builder()
.profile_name(&profile)
.build(),
)
.load()
.await
} else {
KmsClient::new(Region::default())
})
config.load().await
};
KmsClient::new(&client_config)
}
37 changes: 5 additions & 32 deletions tough-kms/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,15 @@ pub type Result<T> = std::result::Result<T, Error>;
#[non_exhaustive]
#[allow(missing_docs)]
pub enum Error {
/// The library failed to authenticate Aws account.
#[snafu(display("Error creating AWS credentials provider: {}", source))]
RusotoCreds {
source: rusoto_credential::CredentialsError,
backtrace: Backtrace,
},

/// The library failed to get the region for the given profile.
#[snafu(display("Unable to determine region from profile '{}': {}", profile, source))]
RusotoRegionFromProfile {
profile: String,
source: rusoto_credential::CredentialsError,
backtrace: Backtrace,
},

/// The library failed to identify the region obtained from the given profile.
#[snafu(display("Unknown AWS region '{}': {}", region, source))]
RusotoRegion {
region: String,
source: rusoto_core::region::ParseRegionError,
backtrace: Backtrace,
},

/// The library failed to instantiate 'HttpClient'.
#[snafu(display("Error creating AWS request dispatcher: {}", source))]
RusotoTls {
source: rusoto_core::request::TlsError,
backtrace: Backtrace,
},

/// The library failed to instantiate 'tokio Runtime'.
#[snafu(display("Unable to create tokio runtime: {}", source))]
RuntimeCreation {
source: std::io::Error,
backtrace: Backtrace,
},
/// The library failed to join 'tokio Runtime'.
#[snafu(display("Unable to join tokio thread used to offload async workloads"))]
ThreadJoin,

/// The library failed to get public key from AWS KMS
#[snafu(display(
Expand All @@ -63,7 +36,7 @@ pub enum Error {
KmsGetPublicKey {
profile: Option<String>,
key_id: String,
source: rusoto_core::RusotoError<rusoto_kms::GetPublicKeyError>,
source: aws_sdk_kms::types::SdkError<aws_sdk_kms::error::GetPublicKeyError>,
backtrace: Backtrace,
},

Expand All @@ -80,7 +53,7 @@ pub enum Error {
KmsSignMessage {
key_id: String,
profile: Option<String>,
source: rusoto_core::RusotoError<rusoto_kms::SignError>,
source: aws_sdk_kms::types::SdkError<aws_sdk_kms::error::SignError>,
backtrace: Backtrace,
},

Expand Down
46 changes: 26 additions & 20 deletions tough-kms/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@

mod client;
pub mod error;
use aws_sdk_kms::types::Blob;
use aws_sdk_kms::Client as KmsClient;
use ring::digest::{digest, SHA256};
use ring::rand::SecureRandom;
use rusoto_kms::{Kms, KmsClient, SignRequest};
use snafu::{ensure, OptionExt, ResultExt};
use std::collections::HashMap;
use std::fmt;
Expand All @@ -42,12 +43,14 @@ pub enum KmsSigningAlgorithm {
}

impl KmsSigningAlgorithm {
fn value(self) -> String {
fn value(self) -> aws_sdk_kms::model::SigningAlgorithmSpec {
// Currently we are supporting only single algorithm, but code stub is added to support
// multiple algorithms in future.
String::from(match self {
KmsSigningAlgorithm::RsassaPssSha256 => "RSASSA_PSS_SHA_256",
})
match self {
KmsSigningAlgorithm::RsassaPssSha256 => {
aws_sdk_kms::model::SigningAlgorithmSpec::RsassaPssSha256
}
}
}
}

Expand Down Expand Up @@ -83,10 +86,10 @@ impl KeySource for KmsKeySource {
None => client::build_client_kms(self.profile.as_deref())?,
};
// Get the public key from AWS KMS
let fut = kms_client.get_public_key(rusoto_kms::GetPublicKeyRequest {
key_id: self.key_id.clone(),
..rusoto_kms::GetPublicKeyRequest::default()
});
let fut = kms_client
.get_public_key()
.key_id(self.key_id.clone())
.send();
let response = tokio::runtime::Runtime::new()
.context(error::RuntimeCreationSnafu)?
.block_on(fut)
Expand All @@ -100,7 +103,7 @@ impl KeySource for KmsKeySource {
contents: response
.public_key
.context(error::PublicKeyNoneSnafu)?
.to_vec(),
.into_inner(),
},
pem::EncodeConfig {
line_ending: pem::LineEnding::LF,
Expand All @@ -115,15 +118,16 @@ impl KeySource for KmsKeySource {
);
Ok(Box::new(KmsRsaKey {
profile: self.profile.clone(),
client: Some(kms_client.clone()),
client: Some(kms_client),
key_id: self.key_id.clone(),
public_key: key.parse().context(error::PublicKeyParseSnafu)?,
signing_algorithm: self.signing_algorithm,
modulus_size_bytes: parse_modulus_length_bytes(
response
.customer_master_key_spec
.as_ref()
.context(error::MissingCustomerMasterKeySpecSnafu)?,
.context(error::MissingCustomerMasterKeySpecSnafu)?
.as_str(),
)?,
}))
}
Expand Down Expand Up @@ -185,13 +189,15 @@ impl Sign for KmsRsaKey {
Some(value) => value,
None => client::build_client_kms(self.profile.as_deref())?,
};
let sign_fut = kms_client.sign(SignRequest {
key_id: self.key_id.clone(),
message: digest(&SHA256, msg).as_ref().to_vec().into(),
message_type: Some(String::from("DIGEST")),
signing_algorithm: self.signing_algorithm.value(),
..rusoto_kms::SignRequest::default()
});
let blob = Blob::new(digest(&SHA256, msg).as_ref().to_vec());
let sign_fut = kms_client
.sign()
.key_id(self.key_id.clone())
.message(blob)
.message_type(aws_sdk_kms::model::MessageType::Digest)
.signing_algorithm(self.signing_algorithm.value())
.send();

let response = tokio::runtime::Runtime::new()
.context(error::RuntimeCreationSnafu)?
.block_on(sign_fut)
Expand All @@ -202,7 +208,7 @@ impl Sign for KmsRsaKey {
let signature = response
.signature
.context(error::SignatureNotFoundSnafu)?
.to_vec();
.into_inner();

// sometimes KMS produces a signature that is shorter than the modulus. in those cases,
// we have observed that openssl and KMS will both validate the signature, but ring will
Expand Down
Loading

0 comments on commit 973c94c

Please sign in to comment.