Skip to content

Commit

Permalink
chore: move verify signature to atoma-utils (#254)
Browse files Browse the repository at this point in the history
* chore: move verify signature to atoma-utils

* add trace
  • Loading branch information
Cifko authored Nov 27, 2024
1 parent 28d875f commit 781d3a2
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 87 deletions.
5 changes: 4 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion atoma-service/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ blake2 = { workspace = true }
clap = { workspace = true }
config = { workspace = true }
dotenv = { workspace = true }
fastcrypto = { workspace = true }
flume = { workspace = true }
futures = { workspace = true }
hex = { workspace = true }
Expand Down
87 changes: 2 additions & 85 deletions atoma-service/src/middleware.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
server::AppState,
};
use atoma_state::types::AtomaAtomaStateManagerEvent;
use atoma_utils::verify_signature;
use axum::{
body::Body,
extract::State,
Expand Down Expand Up @@ -166,7 +167,7 @@ pub async fn signature_verification_middleware(
.try_into()
.expect("Invalid Blake2b hash length");

utils::verify_signature(base64_signature, &body_blake2b_hash_bytes)?;
verify_signature(base64_signature, &body_blake2b_hash_bytes)?;

let request_metadata = req_parts
.extensions
Expand Down Expand Up @@ -371,90 +372,6 @@ pub async fn verify_stack_permissions(

pub(crate) mod utils {
use super::*;
use fastcrypto::{
ed25519::{Ed25519PublicKey, Ed25519Signature},
secp256k1::{Secp256k1PublicKey, Secp256k1Signature},
secp256r1::{Secp256r1PublicKey, Secp256r1Signature},
traits::{ToFromBytes, VerifyingKey},
};
use sui_sdk::types::{crypto::SignatureScheme, digests::TransactionDigest};

/// Verifies the authenticity of a request by checking its signature against the provided hash.
///
/// # Arguments
/// * `base64_signature` - A base64-encoded signature string that contains:
/// - The signature itself
/// - The public key
/// - The signature scheme used
/// * `body_hash` - A 32-byte Blake2b hash of the request body
///
/// # Returns
/// * `Ok(())` if the signature is valid
/// * `Err(StatusCode)` if:
/// - The signature cannot be parsed (`BAD_REQUEST`)
/// - The public key is invalid (`BAD_REQUEST`)
/// - The signature scheme is unsupported (`BAD_REQUEST`)
/// - The signature verification fails (`UNAUTHORIZED`)
///
/// # Supported Signature Schemes
/// - ED25519
/// - Secp256k1
/// - Secp256r1
///
/// # Security Note
/// This function is critical for ensuring request authenticity. It verifies that:
/// 1. The request was signed by the owner of the public key
/// 2. The request body hasn't been tampered with since signing
#[instrument(level = "trace", skip_all)]
pub(crate) fn verify_signature(
base64_signature: &str,
body_hash: &[u8; 32],
) -> Result<(), StatusCode> {
let signature = Signature::from_str(base64_signature).map_err(|_| {
error!("Failed to parse signature");
StatusCode::BAD_REQUEST
})?;
let signature_bytes = signature.signature_bytes();
let public_key_bytes = signature.public_key_bytes();
let signature_scheme = signature.scheme();
let public_key =
PublicKey::try_from_bytes(signature_scheme, public_key_bytes).map_err(|e| {
error!("Failed to extract public key from bytes, with error: {e}");
StatusCode::BAD_REQUEST
})?;

match signature_scheme {
SignatureScheme::ED25519 => {
let public_key = Ed25519PublicKey::from_bytes(public_key.as_ref()).unwrap();
let signature = Ed25519Signature::from_bytes(signature_bytes).unwrap();
public_key.verify(body_hash, &signature).map_err(|_| {
error!("Failed to verify signature");
StatusCode::UNAUTHORIZED
})?;
}
SignatureScheme::Secp256k1 => {
let public_key = Secp256k1PublicKey::from_bytes(public_key.as_ref()).unwrap();
let signature = Secp256k1Signature::from_bytes(signature_bytes).unwrap();
public_key.verify(body_hash, &signature).map_err(|_| {
error!("Failed to verify signature");
StatusCode::UNAUTHORIZED
})?;
}
SignatureScheme::Secp256r1 => {
let public_key = Secp256r1PublicKey::from_bytes(public_key.as_ref()).unwrap();
let signature = Secp256r1Signature::from_bytes(signature_bytes).unwrap();
public_key.verify(body_hash, &signature).map_err(|_| {
error!("Failed to verify signature");
StatusCode::UNAUTHORIZED
})?;
}
_ => {
error!("Currently unsupported signature scheme");
return Err(StatusCode::BAD_REQUEST);
}
}
Ok(())
}

/// Queries the blockchain to retrieve compute units associated with a specific transaction.
///
Expand Down
4 changes: 4 additions & 0 deletions atoma-utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,8 @@ license.workspace = true

[dependencies]
anyhow.workspace = true
axum.workspace = true
fastcrypto.workspace = true
sui-sdk = { workspace = true }
tokio.workspace = true
tracing.workspace = true
85 changes: 85 additions & 0 deletions atoma-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
use std::str::FromStr;

use anyhow::{Context, Error, Result};
use axum::http::StatusCode;
use fastcrypto::{
ed25519::{Ed25519PublicKey, Ed25519Signature},
secp256k1::{Secp256k1PublicKey, Secp256k1Signature},
secp256r1::{Secp256r1PublicKey, Secp256r1Signature},
traits::{ToFromBytes, VerifyingKey},
};
use sui_sdk::types::crypto::{PublicKey, Signature, SignatureScheme, SuiSignature};
use tokio::sync::watch;
use tracing::{error, instrument};

/// Spawns a task that will automatically trigger shutdown if it encounters an error
///
Expand Down Expand Up @@ -42,6 +53,80 @@ where
})
}

/// Verifies the authenticity of a request by checking its signature against the provided hash.
///
/// # Arguments
/// * `base64_signature` - A base64-encoded signature string that contains:
/// - The signature itself
/// - The public key
/// - The signature scheme used
/// * `body_hash` - A 32-byte Blake2b hash of the request body
///
/// # Returns
/// * `Ok(())` if the signature is valid
/// * `Err(StatusCode)` if:
/// - The signature cannot be parsed (`BAD_REQUEST`)
/// - The public key is invalid (`BAD_REQUEST`)
/// - The signature scheme is unsupported (`BAD_REQUEST`)
/// - The signature verification fails (`UNAUTHORIZED`)
///
/// # Supported Signature Schemes
/// - ED25519
/// - Secp256k1
/// - Secp256r1
///
/// # Security Note
/// This function is critical for ensuring request authenticity. It verifies that:
/// 1. The request was signed by the owner of the public key
/// 2. The request body hasn't been tampered with since signing
#[instrument(level = "trace", skip_all)]
pub fn verify_signature(base64_signature: &str, body_hash: &[u8; 32]) -> Result<(), StatusCode> {
let signature = Signature::from_str(base64_signature).map_err(|_| {
error!("Failed to parse signature");
StatusCode::BAD_REQUEST
})?;
let signature_bytes = signature.signature_bytes();
let public_key_bytes = signature.public_key_bytes();
let signature_scheme = signature.scheme();
let public_key =
PublicKey::try_from_bytes(signature_scheme, public_key_bytes).map_err(|e| {
error!("Failed to extract public key from bytes, with error: {e}");
StatusCode::BAD_REQUEST
})?;

match signature_scheme {
SignatureScheme::ED25519 => {
let public_key = Ed25519PublicKey::from_bytes(public_key.as_ref()).unwrap();
let signature = Ed25519Signature::from_bytes(signature_bytes).unwrap();
public_key.verify(body_hash, &signature).map_err(|_| {
error!("Failed to verify signature");
StatusCode::UNAUTHORIZED
})?;
}
SignatureScheme::Secp256k1 => {
let public_key = Secp256k1PublicKey::from_bytes(public_key.as_ref()).unwrap();
let signature = Secp256k1Signature::from_bytes(signature_bytes).unwrap();
public_key.verify(body_hash, &signature).map_err(|_| {
error!("Failed to verify signature");
StatusCode::UNAUTHORIZED
})?;
}
SignatureScheme::Secp256r1 => {
let public_key = Secp256r1PublicKey::from_bytes(public_key.as_ref()).unwrap();
let signature = Secp256r1Signature::from_bytes(signature_bytes).unwrap();
public_key.verify(body_hash, &signature).map_err(|_| {
error!("Failed to verify signature");
StatusCode::UNAUTHORIZED
})?;
}
_ => {
error!("Currently unsupported signature scheme");
return Err(StatusCode::BAD_REQUEST);
}
}
Ok(())
}

pub mod test {
pub const POSTGRES_TEST_DB_URL: &str = "postgres://atoma:atoma@localhost:5432/atoma";
}

0 comments on commit 781d3a2

Please sign in to comment.