Skip to content

Commit

Permalink
Arbitrary data signing service (#1350)
Browse files Browse the repository at this point in the history
  • Loading branch information
UMR1352 authored Apr 30, 2024
1 parent f59e75a commit edec26c
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 0 deletions.
23 changes: 23 additions & 0 deletions bindings/grpc/proto/utils.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

syntax = "proto3";
package utils;

message DataSigningRequest {
// Raw data that will be signed.
bytes data = 1;
// Signing key's ID.
string key_id = 2;
}

message DataSigningResponse {
// Raw data signature.
bytes signature = 1;
}

// Service that handles signing operations on raw data.
service Signing {
rpc sign(DataSigningRequest) returns (DataSigningResponse);
}

2 changes: 2 additions & 0 deletions bindings/grpc/src/services/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod domain_linkage;
pub mod health_check;
pub mod sd_jwt;
pub mod status_list_2021;
pub mod utils;

use identity_stronghold::StrongholdStorage;
use iota_sdk::client::Client;
Expand All @@ -21,6 +22,7 @@ pub fn routes(client: &Client, stronghold: &StrongholdStorage) -> Routes {
routes.add_service(domain_linkage::service(client));
routes.add_service(document::service(client, stronghold));
routes.add_service(status_list_2021::service());
routes.add_service(utils::service(stronghold));

routes.routes()
}
67 changes: 67 additions & 0 deletions bindings/grpc/src/services/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use _utils::signing_server::Signing as SigningSvc;
use _utils::signing_server::SigningServer;
use _utils::DataSigningRequest;
use _utils::DataSigningResponse;
use identity_iota::storage::JwkStorage;
use identity_iota::storage::KeyId;
use identity_iota::storage::KeyStorageError;
use identity_stronghold::StrongholdStorage;
use tonic::Request;
use tonic::Response;
use tonic::Status;

mod _utils {
tonic::include_proto!("utils");
}

#[derive(Debug, thiserror::Error)]
#[error("Key storage error: {0}")]
pub struct Error(#[from] KeyStorageError);

impl From<Error> for Status {
fn from(value: Error) -> Self {
Status::internal(value.to_string())
}
}

pub struct SigningService {
storage: StrongholdStorage,
}

impl SigningService {
pub fn new(stronghold: &StrongholdStorage) -> Self {
Self {
storage: stronghold.clone(),
}
}
}

#[tonic::async_trait]
impl SigningSvc for SigningService {
#[tracing::instrument(
name = "utils/sign",
skip_all,
fields(request = ?req.get_ref())
ret,
err,
)]
async fn sign(&self, req: Request<DataSigningRequest>) -> Result<Response<DataSigningResponse>, Status> {
let DataSigningRequest { data, key_id } = req.into_inner();
let key_id = KeyId::new(key_id);
let public_key_jwk = self.storage.get_public_key(&key_id).await.map_err(Error)?;
let signature = self
.storage
.sign(&key_id, &data, &public_key_jwk)
.await
.map_err(Error)?;

Ok(Response::new(DataSigningResponse { signature }))
}
}

pub fn service(stronghold: &StrongholdStorage) -> SigningServer<SigningService> {
SigningServer::new(SigningService::new(stronghold))
}
1 change: 1 addition & 0 deletions bindings/grpc/tests/api/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ mod helpers;
mod jwt;
mod sd_jwt_validation;
mod status_list_2021;
mod utils;
48 changes: 48 additions & 0 deletions bindings/grpc/tests/api/utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright 2020-2024 IOTA Stiftung
// SPDX-License-Identifier: Apache-2.0

use _utils::signing_client::SigningClient;
use _utils::DataSigningRequest;
use identity_iota::verification::jws::JwsAlgorithm;
use identity_storage::JwkStorage;
use identity_storage::KeyType;
use identity_stronghold::StrongholdStorage;

use crate::helpers::make_stronghold;
use crate::helpers::TestServer;

mod _utils {
tonic::include_proto!("utils");
}

const SAMPLE_SIGNING_DATA: &'static [u8] = b"I'm just some random data to be signed :)";

#[tokio::test]
async fn raw_data_signing_works() -> anyhow::Result<()> {
let stronghold = StrongholdStorage::new(make_stronghold());
let server = TestServer::new_with_stronghold(stronghold.clone()).await;

let key_id = stronghold
.generate(KeyType::from_static_str("Ed25519"), JwsAlgorithm::EdDSA)
.await?
.key_id;

let expected_signature = {
let public_key_jwk = stronghold.get_public_key(&key_id).await?;
stronghold.sign(&key_id, SAMPLE_SIGNING_DATA, &public_key_jwk).await?
};

let mut grpc_client = SigningClient::connect(server.endpoint()).await?;
let signature = grpc_client
.sign(DataSigningRequest {
data: SAMPLE_SIGNING_DATA.to_owned(),
key_id: key_id.to_string(),
})
.await?
.into_inner()
.signature;

assert_eq!(signature, expected_signature);

Ok(())
}

0 comments on commit edec26c

Please sign in to comment.