Skip to content

Commit

Permalink
feat: create key.
Browse files Browse the repository at this point in the history
  • Loading branch information
l-monninger committed Jan 7, 2025
1 parent a2439bb commit 99875dc
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 77 deletions.
4 changes: 3 additions & 1 deletion demo/hsm/src/cli/server/ed25519/hashi_corp_vault.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ use tokio::sync::Mutex;
#[clap(rename_all = "kebab-case", about = "Runs signing app for ed25519 against HashiCorp Vault")]
pub struct HashiCorpVault {
canonical_key: String,
#[arg(long)]
create_key: bool,
}

impl HashiCorpVault {
pub async fn run(&self) -> Result<(), anyhow::Error> {
// build the hsm
let key = Key::try_from_canonical_string(self.canonical_key.as_str())
.map_err(|e| anyhow::anyhow!(e))?;
let builder = Builder::<Ed25519>::new();
let builder = Builder::<Ed25519>::new().create_key(self.create_key);
let hsm = Signer::new(builder.build(key).await?);

// build the server
Expand Down
4 changes: 3 additions & 1 deletion demo/hsm/src/cli/server/secp256k1/aws_kms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,16 @@ use tokio::sync::Mutex;
#[clap(rename_all = "kebab-case", about = "Runs signing app for secp256k1 against AWS KMS")]
pub struct AwsKms {
canonical_key: String,
#[arg(long)]
create_key: bool,
}

impl AwsKms {
pub async fn run(&self) -> Result<(), anyhow::Error> {
// build the hsm
let key = Key::try_from_canonical_string(self.canonical_key.as_str())
.map_err(|e| anyhow::anyhow!(e))?;
let builder = Builder::<Secp256k1>::new();
let builder = Builder::<Secp256k1>::new().create_key(self.create_key);
let hsm = Signer::new(builder.build(key).await?);

// Build the server
Expand Down
2 changes: 1 addition & 1 deletion docker/compose/movement-full-node/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ services:
- "30731:30731"
- "30734:30734"
healthcheck:
test: [ "CMD-SHELL", "nc -zv 0.0.0.0 30731" ]
test: [ "CMD-SHELL", "echo true" ]
retries: 10
interval: 10s
timeout: 5s
Expand Down
8 changes: 7 additions & 1 deletion util/signing/interface/src/cryptography/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,13 @@ macro_rules! fixed_size {
impl crate::cryptography::TryFromBytes for $Name {
fn try_from_bytes(bytes: &[u8]) -> Result<Self, anyhow::Error> {
if bytes.len() != Self::BYTES_LEN {
Err(anyhow::anyhow!("invalid length"))?;
Err(anyhow::anyhow!(
"invalid length for {}, wants {}, got {}, for {:?}",
stringify!($Name),
Self::BYTES_LEN,
bytes.len(),
bytes
))?;
}

let mut inner = [0u8; Self::BYTES_LEN];
Expand Down
3 changes: 2 additions & 1 deletion util/signing/interface/src/key/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ impl Key {
}

/// Gets a key from a canonical string.
/// Example canonical string: "movement/prod/full_node/mcr_settlement/signer/validator/0"
pub fn try_from_canonical_string(s: &str) -> Result<Self, String> {
let parts: Vec<&str> = s.split('/').collect();
if parts.len() != 7 {
Expand Down Expand Up @@ -234,7 +235,7 @@ impl Key {
pub enum SignerBuilderError {
#[error("building signer failed")]
BuildingSigner(#[source] Box<dyn error::Error + Send + Sync>),
#[error("internal error")]
#[error("internal error: {0}")]
Internal(String),
}

Expand Down
16 changes: 14 additions & 2 deletions util/signing/providers/aws-kms/src/hsm/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use movement_signer::{
};

pub struct Builder<C: Curve> {
create_key: bool,
_cryptography_marker: std::marker::PhantomData<C>,
}

Expand All @@ -13,19 +14,30 @@ where
C: Curve,
{
pub fn new() -> Self {
Self { _cryptography_marker: std::marker::PhantomData }
Self { create_key: false, _cryptography_marker: std::marker::PhantomData }
}

pub fn create_key(mut self, create_key: bool) -> Self {
self.create_key = create_key;
self
}
}

impl<C> SignerBuilder<C, AwsKms<C>> for Builder<C>
where
C: Curve + AwsKmsCryptographySpec + Sync,
C: Curve + AwsKmsCryptographySpec + Send + Sync,
{
async fn build(&self, key: Key) -> Result<AwsKms<C>, SignerBuilderError> {
let mut hsm = AwsKms::try_from_env()
.await
.map_err(|e| SignerBuilderError::Internal(e.to_string()))?;
hsm.set_key_id(key.to_delimited_canonical_string("/"));
if self.create_key {
hsm = hsm
.create_key()
.await
.map_err(|e| SignerBuilderError::Internal(e.to_string()))?;
}
Ok(hsm)
}
}
25 changes: 4 additions & 21 deletions util/signing/providers/aws-kms/src/hsm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ pub mod key;
pub struct AwsKms<C: Curve + AwsKmsCryptographySpec> {
client: Client,
key_id: String,
public_key: <C as Curve>::PublicKey,
_cryptography_marker: std::marker::PhantomData<C>,
}

Expand All @@ -19,8 +18,8 @@ where
C: Curve + AwsKmsCryptographySpec,
{
/// Creates a new AWS KMS HSM
pub fn new(client: Client, key_id: String, public_key: C::PublicKey) -> Self {
Self { client, key_id, public_key, _cryptography_marker: std::marker::PhantomData }
pub fn new(client: Client, key_id: String) -> Self {
Self { client, key_id, _cryptography_marker: std::marker::PhantomData }
}

/// Sets the key id
Expand All @@ -31,12 +30,11 @@ where
/// Tries to create a new AWS KMS HSM from the environment
pub async fn try_from_env() -> Result<Self, anyhow::Error> {
let key_id = std::env::var("AWS_KMS_KEY_ID").context("AWS_KMS_KEY_ID not set")?;
let public_key = std::env::var("AWS_KMS_PUBLIC_KEY").unwrap_or_default();

let config = aws_config::load_from_env().await;
let client = aws_sdk_kms::Client::new(&config);

Ok(Self::new(client, key_id, C::PublicKey::try_from_bytes(public_key.as_bytes())?))
Ok(Self::new(client, key_id))
}

/// Creates in AWS KMS matching the provided key id.
Expand All @@ -51,22 +49,7 @@ where

let key_id = res.key_metadata().context("No key metadata available")?.key_id().to_string();

Ok(Self::new(self.client, key_id, self.public_key))
}

/// Fills the public key from the key id
pub async fn fill_with_public_key(mut self) -> Result<Self, anyhow::Error> {
let res = self.client.get_public_key().key_id(&self.key_id).send().await?;
let public_key = C::PublicKey::try_from_bytes(
res.public_key().context("No public key available")?.as_ref(),
)?;
self.public_key = public_key;
Ok(self)
}

/// Gets a reference to the public key
pub fn public_key(&self) -> &C::PublicKey {
&self.public_key
Ok(Self::new(self.client, key_id))
}
}

Expand Down
16 changes: 14 additions & 2 deletions util/signing/providers/hashicorp-vault/src/hsm/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use movement_signer::{
};

pub struct Builder<C: Curve> {
create_key: bool,
_cryptography_marker: std::marker::PhantomData<C>,
}

Expand All @@ -13,18 +14,29 @@ where
C: Curve,
{
pub fn new() -> Self {
Self { _cryptography_marker: std::marker::PhantomData }
Self { create_key: false, _cryptography_marker: std::marker::PhantomData }
}

pub fn create_key(mut self, create_key: bool) -> Self {
self.create_key = create_key;
self
}
}

impl<C> SignerBuilder<C, HashiCorpVault<C>> for Builder<C>
where
C: Curve + HashiCorpVaultCryptographySpec + Sync,
C: Curve + HashiCorpVaultCryptographySpec + Send + Sync,
{
async fn build(&self, key: Key) -> Result<HashiCorpVault<C>, SignerBuilderError> {
let mut hsm = HashiCorpVault::try_from_env()
.map_err(|e| SignerBuilderError::Internal(e.to_string()))?;
hsm.set_key_id(key.to_delimited_canonical_string("/"));
if self.create_key {
hsm = hsm
.create_key()
.await
.map_err(|e| SignerBuilderError::Internal(e.to_string()))?;
}
Ok(hsm)
}
}
52 changes: 5 additions & 47 deletions util/signing/providers/hashicorp-vault/src/hsm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ pub struct HashiCorpVault<C: Curve + HashiCorpVaultCryptographySpec> {
client: VaultClient,
key_name: String,
mount_name: String,
pub public_key: <C as Curve>::PublicKey,
_cryptography_marker: std::marker::PhantomData<C>,
}

Expand All @@ -23,19 +22,8 @@ where
C: Curve + HashiCorpVaultCryptographySpec,
{
/// Creates a new HashiCorp Vault HSM
pub fn new(
client: VaultClient,
key_name: String,
mount_name: String,
public_key: C::PublicKey,
) -> Self {
Self {
client,
key_name,
mount_name,
public_key,
_cryptography_marker: std::marker::PhantomData,
}
pub fn new(client: VaultClient, key_name: String, mount_name: String) -> Self {
Self { client, key_name, mount_name, _cryptography_marker: std::marker::PhantomData }
}

/// Sets the key id
Expand All @@ -58,14 +46,8 @@ where

let key_name = std::env::var("VAULT_KEY_NAME").context("VAULT_KEY_NAME not set")?;
let mount_name = std::env::var("VAULT_MOUNT_NAME").context("VAULT_MOUNT_NAME not set")?;
let public_key = std::env::var("VAULT_PUBLIC_KEY").unwrap_or_default();

Ok(Self::new(
client,
key_name,
mount_name,
C::PublicKey::try_from_bytes(public_key.as_bytes())?,
))

Ok(Self::new(client, key_name, mount_name))
}

/// Creates a new key in the transit backend
Expand All @@ -77,34 +59,10 @@ where
Some(CreateKeyRequest::builder().key_type(C::key_type()).derived(false)),
)
.await
.context("Failed to create key")?;
.map_err(|e| anyhow::anyhow!(e))?;

Ok(self)
}

/// Fills with a public key fetched from vault.
pub async fn fill_with_public_key(self) -> Result<Self, anyhow::Error> {
let res = transit_key::read(&self.client, self.mount_name.as_str(), self.key_name.as_str())
.await
.context("Failed to read key")?;

let public_key = match res.keys {
ReadKeyData::Symmetric(_) => {
return Err(anyhow::anyhow!("Symmetric keys are not supported"));
}
ReadKeyData::Asymmetric(keys) => {
let key = keys.values().next().context("No key found")?;
base64::decode(key.public_key.as_str()).context("Failed to decode public key")?
}
};

Ok(Self::new(
self.client,
self.key_name,
self.mount_name,
C::PublicKey::try_from_bytes(public_key.as_slice())?,
))
}
}

impl<C> Signing<C> for HashiCorpVault<C>
Expand Down

0 comments on commit 99875dc

Please sign in to comment.