diff --git a/deny.toml b/deny.toml index d0a7f4aa..a91ecdbb 100644 --- a/deny.toml +++ b/deny.toml @@ -35,9 +35,6 @@ yanked = "warn" # A list of advisory IDs to ignore. Note that ignored advisories will still # output a note when they are encountered. ignore = [ - # TODO remove deprecated ehters crate - "RUSTSEC-2024-0384", - "RUSTSEC-2025-0009" ] # Threshold for security vulnerabilities, any vulnerability with a CVSS score # lower than the range specified will be ignored. Note that ignored advisories @@ -184,7 +181,6 @@ skip-tree = [ { name = "regex-automata" }, { name = "windows-sys" }, { name = "reqwest" }, - { name = "ethers"}, { name = "tonic"}, ] diff --git a/kms/Cargo.toml b/kms/Cargo.toml index 781aa0ba..6dd7fd18 100644 --- a/kms/Cargo.toml +++ b/kms/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gcloud-kms" -version = "1.0.0" +version = "1.1.0" edition = "2021" authors = ["yoshidan "] repository = "https://github.com/yoshidan/google-cloud-rust/tree/main/kms" @@ -19,14 +19,6 @@ google-cloud-auth = { package = "gcloud-auth", optional = true, version = "1.0.0 google-cloud-googleapis = { package = "gcloud-googleapis", version="1.0.0", path = "../googleapis", features=["kms"]} google-cloud-gax = { package = "gcloud-gax", version = "1.0.0", path = "../foundation/gax"} tracing = "0.1" -thiserror = "1.0" -prost-types = "0.13" - -# ethereum -ethers-core = { version = "2.0", optional = true} -ethers-signers = { version = "2.0", optional = true} -async-trait = { version = "0.1", optional = true } -k256 = { version = "0.13", features = ["pem"], optional = true} [dev-dependencies] tokio = { version="1.32", features=["rt-multi-thread"] } @@ -34,8 +26,6 @@ serial_test = "3.1" tracing-subscriber = { version="0.3.17", features=["env-filter"]} ctor = "0.1" google-cloud-auth = { package = "gcloud-auth", path = "../foundation/auth", default-features=false } -hex-literal = "0.4" -ethers = "2.0" [features] default = ["default-tls", "auth"] @@ -44,4 +34,3 @@ rustls-tls = ["google-cloud-auth?/rustls-tls"] trace = [] auth = ["google-cloud-auth"] external-account = ["google-cloud-auth?/external-account"] -eth = ["ethers-core", "ethers-signers", "async-trait", "k256"] diff --git a/kms/src/lib.rs b/kms/src/lib.rs index e73ff04a..61dd11c8 100644 --- a/kms/src/lib.rs +++ b/kms/src/lib.rs @@ -113,41 +113,5 @@ //!} //!``` //! -//! ### Ethereum Integration -//! -//! Enable 'eth' feature. -//! google-cloud-kms = { version="version", features=["eth"] } -//! -//! ``` -//! use ethers::prelude::SignerMiddleware; -//! use ethers::providers::{Http, Middleware, Provider}; -//! use ethers_core::types::{TransactionReceipt, TransactionRequest}; -//! use ethers_signers::Signer as EthSigner; -//! use google_cloud_kms::client::Client; -//! use google_cloud_kms::signer::ethereum::{Error, Signer}; -//! -//! pub async fn send_bnb(client: Client, key_name: &str, rpc_node: &str) { -//! -//! // BSC testnet -//! let chain_id = 97; -//! -//! let signer = Signer::new(client, key_name, chain_id, None).await.unwrap(); -//! let provider = Provider::::try_from(rpc_node).unwrap(); -//! let signer_address = signer.address(); -//! -//! let eth_client = SignerMiddleware::new_with_provider_chain(provider, signer).await.unwrap(); -//! -//! let tx = TransactionRequest::new() -//! .to(signer_address) -//! .value(100_000_000_000_000_u128) -//! .gas(1_500_000_u64) -//! .gas_price(4_000_000_000_u64) -//! .chain_id(chain_id); -//! -//! let res = eth_client.send_transaction(tx, None).await.unwrap(); -//! let receipt: TransactionReceipt = res.confirmations(3).await.unwrap().unwrap(); -//! } -//! ``` pub mod client; pub mod grpc; -pub mod signer; diff --git a/kms/src/signer/ethereum.rs b/kms/src/signer/ethereum.rs deleted file mode 100644 index 688daa18..00000000 --- a/kms/src/signer/ethereum.rs +++ /dev/null @@ -1,279 +0,0 @@ -use crate::client::Client; -use ethers_core::k256::ecdsa::RecoveryId; -use ethers_core::k256::pkcs8::DecodePublicKey; -use ethers_core::k256::FieldBytes; -use ethers_core::types::{Signature, U256}; -use ethers_core::utils::public_key_to_address; -use ethers_core::{ - k256::ecdsa::{Error as K256Error, Signature as KSig, VerifyingKey}, - types::{ - transaction::{eip2718::TypedTransaction, eip712::Eip712}, - Address, - }, - utils::hash_message, -}; -use ethers_signers::Signer as EthSigner; -use google_cloud_gax::grpc::Status; -use google_cloud_gax::retry::RetrySetting; -use google_cloud_googleapis::cloud::kms::v1::{digest, AsymmetricSignRequest, Digest, GetPublicKeyRequest}; -use std::fmt::Debug; - -#[derive(thiserror::Error, Debug)] -pub enum Error { - #[error("{0}")] - GRPC(#[from] Status), - #[error("{0}")] - K256(#[from] K256Error), - #[error("{0}")] - SPKIError(#[from] k256::pkcs8::spki::Error), - #[error("error encoding eip712 struct: {0:?}")] - Eip712Error(String), - #[error("invalid signature: {0:?}")] - InvalidSignature(Vec), -} - -#[derive(Clone, Debug)] -pub struct Signer { - client: Client, - /// key_name managed by GoogleClod. - /// Format: "projects/{project}/locations/{region}/keyRings/{keyRing}/cryptoKeys/{key}/cryptoKeyVersions/{version}" - /// It must be ECDSA secp256k1. - key_name: String, - /// ECDSA/secp256k1 pubkey - pubkey: VerifyingKey, - /// Ethereum address - address: Address, - chain_id: u64, - retry_setting: Option, -} - -impl Signer { - pub fn new_with_pubkey( - client: Client, - key_name: &str, - pubkey: VerifyingKey, - address: Address, - chain_id: u64, - retry_setting: Option, - ) -> Self { - Self { - client, - key_name: key_name.to_string(), - pubkey, - address, - chain_id, - retry_setting, - } - } - - /// Instantiate a new signer from an existing `Client` and Key ID. - /// - /// This function retrieves the public key from Google Cloud and calculates the Etheruem address. - /// It is therefore `async`. - /// - /// ``` - /// use ethers::prelude::SignerMiddleware; - /// use ethers::providers::{Http, Middleware, Provider}; - /// use ethers_core::types::{TransactionReceipt, TransactionRequest}; - /// use ethers_signers::Signer as EthSigner; - /// use google_cloud_kms::client::Client; - /// use google_cloud_kms::signer::ethereum::{Error, Signer}; - /// - /// pub async fn run(client: Client, key_name: &str) { - /// - /// // BSC testnet - /// let chain_id = 97; - /// - /// let signer = Signer::new(client, key_name, chain_id, None).await.unwrap(); - /// let provider = Provider::::try_from("https://bsc-testnet-rpc.publicnode.com").unwrap(); - /// let signer_address = signer.address(); - /// - /// let eth_client = SignerMiddleware::new_with_provider_chain(provider, signer).await.unwrap(); - /// - /// let tx = TransactionRequest::new() - /// .to(signer_address) - /// .value(100_000_000_000_000_u128) - /// .gas(1_500_000_u64) - /// .gas_price(4_000_000_000_u64) - /// .chain_id(chain_id); // BSC testnet - /// - /// let res = eth_client.send_transaction(tx, None).await.unwrap(); - /// let receipt: TransactionReceipt = res.confirmations(3).await.unwrap().unwrap(); - /// } - /// ``` - pub async fn new( - client: Client, - key_name: &str, - chain_id: u64, - retry: Option, - ) -> Result { - let pubkey = client - .get_public_key( - GetPublicKeyRequest { - name: key_name.to_string(), - }, - retry.clone(), - ) - .await?; - let pubkey = VerifyingKey::from_public_key_pem(&pubkey.pem)?; - let address = public_key_to_address(&pubkey); - Ok(Self::new_with_pubkey(client, key_name, pubkey, address, chain_id, retry)) - } - - pub async fn sign_digest(&self, digest: &[u8]) -> Result { - let request = Self::asymmetric_sign_request(&self.key_name, digest.to_vec()); - let result = self.client.asymmetric_sign(request, self.retry_setting.clone()).await?; - - let mut signature = KSig::from_der(&result.signature)?; - if let Some(new_sig) = signature.normalize_s() { - signature = new_sig - } - - for rid in 0..=1 { - let recovery_id = RecoveryId::from_byte(rid).unwrap(); - let recovered_pubkey = VerifyingKey::recover_from_prehash(digest, &signature, recovery_id)?; - if recovered_pubkey == self.pubkey { - let r_bytes: FieldBytes = signature.r().into(); - let s_bytes: FieldBytes = signature.s().into(); - return Ok(Signature { - r: U256::from_big_endian(r_bytes.as_slice()), - s: U256::from_big_endian(s_bytes.as_slice()), - v: rid as u64, - }); - } - } - Err(Error::InvalidSignature(result.signature)) - } - - fn asymmetric_sign_request(name: &str, digest: Vec) -> AsymmetricSignRequest { - AsymmetricSignRequest { - name: name.to_string(), - digest: Some(Digest { - digest: Some(digest::Digest::Sha256(digest)), - }), - digest_crc32c: None, - data: vec![], - data_crc32c: None, - } - } - - fn with_eip155(&self, mut signature: Signature) -> Signature { - signature.v += self.chain_id * 2 + 35; - signature - } -} - -#[async_trait::async_trait] -impl EthSigner for Signer { - type Error = Error; - - async fn sign_message>(&self, message: S) -> Result { - let message = message.as_ref(); - let message_hash = hash_message(message); - let signature = self.sign_digest(message_hash.as_bytes()).await?; - Ok(self.with_eip155(signature)) - } - - async fn sign_transaction(&self, tx: &TypedTransaction) -> Result { - let mut tx_with_chain = tx.clone(); - let chain_id = tx_with_chain.chain_id().map(|id| id.as_u64()).unwrap_or(self.chain_id); - tx_with_chain.set_chain_id(chain_id); - - let sighash = tx_with_chain.sighash(); - - let signature = self.sign_digest(sighash.as_bytes()).await?; - Ok(self.with_eip155(signature)) - } - - async fn sign_typed_data(&self, payload: &T) -> Result { - let digest = payload - .encode_eip712() - .map_err(|e| Self::Error::Eip712Error(e.to_string()))?; - - let signature = self.sign_digest(&digest).await?; - Ok(signature) - } - - fn address(&self) -> Address { - self.address - } - - fn chain_id(&self) -> u64 { - self.chain_id - } - - fn with_chain_id>(mut self, chain_id: T) -> Self { - self.chain_id = chain_id.into(); - self - } -} - -#[cfg(test)] -mod tests { - use crate::client::{Client, ClientConfig}; - use crate::signer::ethereum::Signer; - use ethers::middleware::SignerMiddleware; - use ethers::providers::{Http, Middleware, Provider}; - use ethers_core::types::{TransactionReceipt, TransactionRequest}; - use ethers_signers::Signer as EthSigner; - use serial_test::serial; - - async fn new_client() -> (Client, String) { - let cred = google_cloud_auth::credentials::CredentialsFile::new().await.unwrap(); - let project = cred.project_id.clone().unwrap(); - let config = ClientConfig::default().with_credentials(cred).await.unwrap(); - (Client::new(config).await.unwrap(), project) - } - - #[tokio::test] - #[serial] - async fn test_sign_ecdsa() { - use hex_literal::hex; - - let (client, project) = new_client().await; - let key = format!( - "projects/{project}/locations/asia-northeast1/keyRings/gcr_test/cryptoKeys/eth-sign/cryptoKeyVersions/1" - ); - - let signer = Signer::new(client, &key, 1, None).await.unwrap(); - let signature = signer - .sign_digest(&hex!("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08")) - .await - .unwrap(); - println!("{:?}", signature); - } - - #[tokio::test] - #[serial] - async fn test_send_ethereum_transaction() { - let provider = Provider::::try_from("https://bsc-testnet-rpc.publicnode.com").unwrap(); - - let (client, project) = new_client().await; - let key = format!( - "projects/{project}/locations/asia-northeast1/keyRings/gcr_test/cryptoKeys/eth-sign/cryptoKeyVersions/1" - ); - let chain_id = 97; - let signer = Signer::new(client, &key, chain_id, None).await.unwrap(); - let signer_address = signer.address(); - tracing::info!("signerAddress = {:?}", signer_address); - - let eth_client = SignerMiddleware::new_with_provider_chain(provider, signer) - .await - .unwrap(); - - let tx = TransactionRequest::new() - .to(signer_address) - .value(100_000_000_000_000_u128) - .gas(1_500_000_u64) - .gas_price(4_000_000_000_u64) - .chain_id(chain_id); // BSC testnet - - let res = eth_client.send_transaction(tx, None).await.unwrap(); - tracing::info!("tx res: {:?}", res); - - let receipt: TransactionReceipt = res.confirmations(3).await.unwrap().unwrap(); - tracing::info!("receipt: {:?}", receipt); - assert_eq!(receipt.from, signer_address); - assert_eq!(receipt.status.unwrap().as_u64(), 1); - } -} diff --git a/kms/src/signer/mod.rs b/kms/src/signer/mod.rs deleted file mode 100644 index bc19f17b..00000000 --- a/kms/src/signer/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(feature = "eth")] -pub mod ethereum; diff --git a/storage/Cargo.toml b/storage/Cargo.toml index 3d81a1bd..3db190f0 100644 --- a/storage/Cargo.toml +++ b/storage/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT" name = "gcloud-storage" readme = "README.md" repository = "https://github.com/yoshidan/google-cloud-rust/tree/main/storage" -version = "1.0.0" +version = "1.0.1" [lib] doctest = false @@ -52,8 +52,6 @@ google-cloud-metadata = {package = "gcloud-metadata", optional = true, version = [dev-dependencies] ctor = "0.1.26" google-cloud-auth = { package = "gcloud-auth", path = "../foundation/auth", default-features = false} -reqwest-retry = "0.7.0" -retry-policies = "0.4.0" serial_test = "3.1" tokio = {version = "1.32", features = ["rt-multi-thread"]} tracing-subscriber = {version = "0.3.17", features = ["env-filter"]}