Skip to content

Commit 2fd3445

Browse files
committed
Add Verify function
1 parent 8fbe6e5 commit 2fd3445

2 files changed

Lines changed: 124 additions & 3 deletions

File tree

guest-agent/rpc/proto/agent_rpc.proto

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,11 @@ service DstackGuest {
4949
// Get app info
5050
rpc Info(google.protobuf.Empty) returns (AppInfo) {}
5151

52-
// Get app info
52+
// Sign a payload
5353
rpc Sign(SignRequest) returns (SignResponse) {}
54+
55+
// Verify a signature
56+
rpc Verify(VerifyRequest) returns (VerifyResponse) {}
5457
}
5558

5659
// The request to derive a key
@@ -234,6 +237,17 @@ message SignResponse {
234237
bytes signature = 1;
235238
}
236239

240+
message VerifyRequest {
241+
string algorithm = 1;
242+
bytes data = 2;
243+
bytes signature = 3;
244+
bytes public_key = 4;
245+
}
246+
247+
message VerifyResponse {
248+
bool valid = 1;
249+
}
250+
237251
message GetAttestationForAppKeyRequest {
238252
string algorithm = 1;
239253
}

guest-agent/src/rpc_service.rs

Lines changed: 109 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,14 @@ use dstack_guest_agent_rpc::{
1313
worker_server::{WorkerRpc, WorkerServer},
1414
AppInfo, DeriveK256KeyResponse, DeriveKeyArgs, EmitEventArgs, GetAttestationForAppKeyRequest,
1515
GetKeyArgs, GetKeyResponse, GetQuoteResponse, GetTlsKeyArgs, GetTlsKeyResponse, RawQuoteArgs,
16-
SignRequest, SignResponse, TdxQuoteArgs, TdxQuoteResponse, WorkerVersion,
16+
SignRequest, SignResponse, TdxQuoteArgs, TdxQuoteResponse, VerifyRequest, VerifyResponse,
17+
WorkerVersion,
1718
};
1819
use dstack_types::{AppKeys, SysConfig};
1920
use ed25519_dalek::ed25519::signature::hazmat::PrehashSigner;
20-
use ed25519_dalek::{Signer as Ed25519Signer, SigningKey as Ed25519SigningKey};
21+
use ed25519_dalek::{
22+
Signer as Ed25519Signer, SigningKey as Ed25519SigningKey, Verifier as Ed25519Verifier,
23+
};
2124
use fs_err as fs;
2225
use k256::ecdsa::SigningKey;
2326
use ra_rpc::{Attestation, CallContext, RpcCall};
@@ -305,6 +308,56 @@ impl DstackGuestRpc for InternalRpcHandler {
305308
};
306309
Ok(SignResponse { signature })
307310
}
311+
312+
async fn verify(self, request: VerifyRequest) -> Result<VerifyResponse> {
313+
let valid = match request.algorithm.as_str() {
314+
"ed25519" => {
315+
let public_key = if request.public_key.is_empty() {
316+
let key_response = self
317+
.get_key(GetKeyArgs {
318+
path: "vms".to_string(),
319+
purpose: "signing".to_string(),
320+
algorithm: "ed25519".to_string(),
321+
})
322+
.await?;
323+
let key_bytes: [u8; 32] =
324+
key_response.key.try_into().expect("Key is incorrect");
325+
Ed25519SigningKey::from_bytes(&key_bytes)
326+
.verifying_key()
327+
.to_bytes()
328+
.to_vec()
329+
} else {
330+
request.public_key
331+
};
332+
let verifying_key = ed25519_dalek::VerifyingKey::from_bytes(
333+
&public_key.as_slice().try_into().unwrap(),
334+
)?;
335+
let signature = ed25519_dalek::Signature::from_slice(&request.signature)?;
336+
verifying_key.verify(&request.data, &signature).is_ok()
337+
}
338+
"secp256k1" | "secp256k1_prehashed" => {
339+
let public_key = if request.public_key.is_empty() {
340+
let key_response = self
341+
.get_key(GetKeyArgs {
342+
path: "vms".to_string(),
343+
purpose: "signing".to_string(),
344+
algorithm: request.algorithm,
345+
})
346+
.await?;
347+
let signing_key = SigningKey::from_slice(&key_response.key)
348+
.context("Failed to parse secp256k1 key")?;
349+
signing_key.verifying_key().to_sec1_bytes().to_vec()
350+
} else {
351+
request.public_key
352+
};
353+
let verifying_key = k256::ecdsa::VerifyingKey::from_sec1_bytes(&public_key)?;
354+
let signature = k256::ecdsa::Signature::from_slice(&request.signature)?;
355+
verifying_key.verify(&request.data, &signature).is_ok()
356+
}
357+
_ => return Err(anyhow::anyhow!("Unsupported algorithm")),
358+
};
359+
Ok(VerifyResponse { valid })
360+
}
308361
}
309362

310363
fn simulate_quote(
@@ -746,6 +799,60 @@ pNs85uhOZE8z2jr8Pg==
746799
}
747800
}
748801

802+
#[tokio::test]
803+
async fn test_verify_ed25519_success() {
804+
let state = setup_test_state().await;
805+
let handler = InternalRpcHandler {
806+
state: state.clone(),
807+
};
808+
let data_to_sign = b"test message for ed25519";
809+
let sign_request = SignRequest {
810+
algorithm: "ed25519".to_string(),
811+
data: data_to_sign.to_vec(),
812+
};
813+
814+
let sign_response = handler.sign(sign_request).await.unwrap();
815+
816+
let verify_request = VerifyRequest {
817+
algorithm: "ed25519".to_string(),
818+
data: data_to_sign.to_vec(),
819+
signature: sign_response.signature,
820+
public_key: vec![],
821+
};
822+
let handler = InternalRpcHandler {
823+
state: state.clone(),
824+
};
825+
let verify_response = handler.verify(verify_request).await.unwrap();
826+
assert!(verify_response.valid);
827+
}
828+
829+
#[tokio::test]
830+
async fn test_verify_secp256k1_success() {
831+
let state = setup_test_state().await;
832+
let handler = InternalRpcHandler {
833+
state: state.clone(),
834+
};
835+
let data_to_sign = b"test message for secp256k1";
836+
let sign_request = SignRequest {
837+
algorithm: "secp256k1".to_string(),
838+
data: data_to_sign.to_vec(),
839+
};
840+
841+
let sign_response = handler.sign(sign_request).await.unwrap();
842+
843+
let verify_request = VerifyRequest {
844+
algorithm: "secp256k1".to_string(),
845+
data: data_to_sign.to_vec(),
846+
signature: sign_response.signature,
847+
public_key: vec![],
848+
};
849+
let handler = InternalRpcHandler {
850+
state: state.clone(),
851+
};
852+
let verify_response = handler.verify(verify_request).await.unwrap();
853+
assert!(verify_response.valid);
854+
}
855+
749856
#[tokio::test]
750857
async fn test_sign_ed25519_success() {
751858
let state = setup_test_state().await;

0 commit comments

Comments
 (0)