Skip to content

Commit

Permalink
feat: generics for cryptography.
Browse files Browse the repository at this point in the history
  • Loading branch information
l-monninger committed Dec 18, 2024
1 parent 873d1ff commit df28163
Show file tree
Hide file tree
Showing 11 changed files with 293 additions and 149 deletions.
Empty file added demo/hsm/src/cli/mod.rs
Empty file.
28 changes: 28 additions & 0 deletions demo/hsm/src/cryptography/aws_kms.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::cryptography::Secp256k1;
use aws_sdk_kms::types::{KeySpec, KeyUsageType, SigningAlgorithmSpec};

/// Defines the needed methods for providing a definition of cryptography used with AWS KMS
pub trait AwsKmsCryptography {
/// Returns the [KeySpec] for the desired cryptography
fn key_spec() -> KeySpec;

/// Returns the [KeyUsageType] for the desired cryptography
fn key_usage_type() -> KeyUsageType;

/// Returns the [SigningAlgorithmSpec] for the desired cryptography
fn signing_algorithm_spec() -> SigningAlgorithmSpec;
}

impl AwsKmsCryptography for Secp256k1 {
fn key_spec() -> KeySpec {
KeySpec::EccSecgP256K1
}

fn key_usage_type() -> KeyUsageType {
KeyUsageType::SignVerify
}

fn signing_algorithm_spec() -> SigningAlgorithmSpec {
SigningAlgorithmSpec::EcdsaSha256
}
}
Empty file.
14 changes: 14 additions & 0 deletions demo/hsm/src/cryptography/hashicorp_vault.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use crate::cryptography::Ed25519;
use vaultrs::api::transit::KeyType;

/// Defines the needed methods for providing a definition of cryptography used with HashiCorp Vault
pub trait HashiCorpVaultCryptography {
/// Returns the [KeyType] for the desired cryptography
fn key_type() -> KeyType;
}

impl HashiCorpVaultCryptography for Ed25519 {
fn key_type() -> KeyType {
KeyType::Ed25519
}
}
18 changes: 18 additions & 0 deletions demo/hsm/src/cryptography/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
pub mod aws_kms;
pub mod google_kms;
pub mod hashicorp_vault;
pub mod verifier;

/// The Secp256k1 curve.
#[derive(Debug, Clone, Copy)]
pub struct Secp256k1;

/// The Ed25519 curve.
#[derive(Debug, Clone, Copy)]
pub struct Ed25519;

#[derive(Debug, Clone, Copy)]
pub enum Curve {
Secp256k1(Secp256k1),
Ed25519(Ed25519),
}
71 changes: 71 additions & 0 deletions demo/hsm/src/cryptography/verifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use crate::{Bytes, PublicKey, Signature};

#[async_trait::async_trait]
pub trait LocalVerifier {
/// Verifies a signature for a given message and public key.
async fn verify(
message: Bytes,
public_key: PublicKey,
signature: Signature,
) -> Result<bool, anyhow::Error>;
}

pub mod secp256k1 {
use super::*;
use crate::cryptography::Secp256k1;
use anyhow::Context;
use k256::ecdsa::{self, VerifyingKey};
use k256::pkcs8::DecodePublicKey;
use ring_compat::signature::Verifier;

#[async_trait::async_trait]
impl LocalVerifier for Secp256k1 {
async fn verify(
message: Bytes,
public_key: PublicKey,
signature: Signature,
) -> Result<bool, anyhow::Error> {
let verifying_key = VerifyingKey::from_public_key_der(&public_key.0 .0)
.context("Failed to create verifying key")?;

let signature = ecdsa::Signature::from_der(&signature.0 .0)
.context("Failed to create signature")?;

match verifying_key.verify(message.0.as_slice(), &signature) {
Ok(_) => Ok(true),
Err(e) => {
println!("Error verifying signature: {:?}", e);
Ok(false)
}
}
}
}
}

pub mod ed25519 {

use super::*;
use crate::cryptography::Ed25519;
use anyhow::Context;
use ring_compat::signature::{
ed25519::{self, VerifyingKey},
Verifier,
};

#[async_trait::async_trait]
impl LocalVerifier for Ed25519 {
async fn verify(
message: Bytes,
public_key: PublicKey,
signature: Signature,
) -> Result<bool, anyhow::Error> {
let verifying_key = VerifyingKey::from_slice(public_key.0 .0.as_slice())
.context("Failed to create verifying key")?;

let signature = ed25519::Signature::from_slice(signature.0 .0.as_slice())
.context("Failed to create signature")?;

Ok(verifying_key.verify(message.0.as_slice(), &signature).is_ok())
}
}
}
48 changes: 23 additions & 25 deletions demo/hsm/src/hsm/aws_kms.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
use crate::cryptography::aws_kms::AwsKmsCryptography;
use crate::cryptography::verifier::LocalVerifier;
use crate::{Bytes, Hsm, PublicKey, Signature};
use anyhow::Context;
use aws_sdk_kms::primitives::Blob;
use aws_sdk_kms::types::{KeySpec, KeyUsageType, SigningAlgorithmSpec};
use aws_sdk_kms::Client;
use dotenv::dotenv;
use k256::ecdsa::{self, VerifyingKey};
use k256::pkcs8::DecodePublicKey;
use ring_compat::signature::Verifier;

/// A AWS KMS HSM.
pub struct AwsKms {
pub struct AwsKms<C: AwsKmsCryptography> {
client: Client,
key_id: String,
pub public_key: PublicKey,
public_key: PublicKey,
_cryptography_marker: std::marker::PhantomData<C>,
}

impl AwsKms {
impl<C> AwsKms<C>
where
C: AwsKmsCryptography,
{
/// Creates a new AWS KMS HSM
pub fn new(client: Client, key_id: String, public_key: PublicKey) -> Self {
Self { client, key_id, public_key }
Self { client, key_id, public_key, _cryptography_marker: std::marker::PhantomData }
}

/// Tries to create a new AWS KMS HSM from the environment
Expand All @@ -38,8 +40,8 @@ impl AwsKms {
let res = self
.client
.create_key()
.key_spec(KeySpec::EccSecgP256K1)
.key_usage(KeyUsageType::SignVerify)
.key_spec(C::key_spec())
.key_usage(C::key_usage_type())
.send()
.await?;

Expand All @@ -58,17 +60,25 @@ impl AwsKms {
self.public_key = public_key;
Ok(self)
}

/// Gets a reference to the public key
pub fn public_key(&self) -> &PublicKey {
&self.public_key
}
}

#[async_trait::async_trait]
impl Hsm for AwsKms {
impl<C> Hsm for AwsKms<C>
where
C: AwsKmsCryptography + LocalVerifier + Send + Sync,
{
async fn sign(&self, message: Bytes) -> Result<(Bytes, PublicKey, Signature), anyhow::Error> {
let blob = Blob::new(message.clone().0);
let request = self
.client
.sign()
.key_id(&self.key_id)
.signing_algorithm(SigningAlgorithmSpec::EcdsaSha256)
.signing_algorithm(C::signing_algorithm_spec())
.message(blob);

let res = request.send().await?;
Expand All @@ -85,18 +95,6 @@ impl Hsm for AwsKms {
public_key: PublicKey,
signature: Signature,
) -> Result<bool, anyhow::Error> {
let verifying_key = VerifyingKey::from_public_key_der(&public_key.0 .0)
.context("Failed to create verifying key")?;

let signature =
ecdsa::Signature::from_der(&signature.0 .0).context("Failed to create signature")?;

match verifying_key.verify(message.0.as_slice(), &signature) {
Ok(_) => Ok(true),
Err(e) => {
println!("Error verifying signature: {:?}", e);
Ok(false)
}
}
C::verify(message, public_key, signature).await
}
}
38 changes: 21 additions & 17 deletions demo/hsm/src/hsm/hashi_corp_vault.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
use crate::cryptography::hashicorp_vault::HashiCorpVaultCryptography;
use crate::cryptography::verifier::LocalVerifier;
use crate::{Bytes, Hsm, PublicKey, Signature};
use anyhow::Context;
use ring_compat::signature::{
ed25519::{self, VerifyingKey},
Verifier,
};
use vaultrs::api::transit::KeyType;
use vaultrs::api::transit::{requests::CreateKeyRequest, responses::ReadKeyData};
use vaultrs::client::{VaultClient, VaultClientSettingsBuilder};
use vaultrs::transit::data;
use vaultrs::transit::key;

/// A HashiCorp Vault HSM.
pub struct HashiCorpVault {
pub struct HashiCorpVault<C: HashiCorpVaultCryptography> {
client: VaultClient,
key_name: String,
mount_name: String,
pub public_key: PublicKey,
_cryptography_marker: std::marker::PhantomData<C>,
}

impl HashiCorpVault {
impl<C> HashiCorpVault<C>
where
C: HashiCorpVaultCryptography,
{
/// Creates a new HashiCorp Vault HSM
pub fn new(
client: VaultClient,
key_name: String,
mount_name: String,
public_key: PublicKey,
) -> Self {
Self { client, key_name, mount_name, public_key }
Self {
client,
key_name,
mount_name,
public_key,
_cryptography_marker: std::marker::PhantomData,
}
}

/// Tries to create a new HashiCorp Vault HSM from the environment
Expand Down Expand Up @@ -60,7 +67,7 @@ impl HashiCorpVault {
&self.client,
self.mount_name.as_str(),
self.key_name.as_str(),
Some(CreateKeyRequest::builder().key_type(KeyType::Ed25519).derived(false)),
Some(CreateKeyRequest::builder().key_type(C::key_type()).derived(false)),
)
.await
.context("Failed to create key")?;
Expand Down Expand Up @@ -91,7 +98,10 @@ impl HashiCorpVault {
}

#[async_trait::async_trait]
impl Hsm for HashiCorpVault {
impl<C> Hsm for HashiCorpVault<C>
where
C: HashiCorpVaultCryptography + LocalVerifier + Send + Sync,
{
async fn sign(&self, message: Bytes) -> Result<(Bytes, PublicKey, Signature), anyhow::Error> {
let res = data::sign(
&self.client,
Expand Down Expand Up @@ -125,12 +135,6 @@ impl Hsm for HashiCorpVault {
public_key: PublicKey,
signature: Signature,
) -> Result<bool, anyhow::Error> {
let verifying_key = VerifyingKey::from_slice(public_key.0 .0.as_slice())
.context("Failed to create verifying key")?;

let signature = ed25519::Signature::from_slice(signature.0 .0.as_slice())
.context("Failed to create signature")?;

Ok(verifying_key.verify(message.0.as_slice(), &signature).is_ok())
C::verify(message, public_key, signature).await
}
}
7 changes: 7 additions & 0 deletions demo/hsm/src/hsm/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
pub mod aws_kms;
pub mod google_kms;
pub mod hashi_corp_vault;

#[derive(Debug, Clone, Copy)]
pub enum Provider {
AWS,
GCP,
Vault,
}
2 changes: 2 additions & 0 deletions demo/hsm/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
pub mod action_stream;
pub mod cli;
pub mod cryptography;
pub mod hsm;
pub mod server;

Expand Down
Loading

0 comments on commit df28163

Please sign in to comment.