Skip to content

Commit 58c91b8

Browse files
committed
Add support for signing pre-hashed digests with secp256k1
1 parent 3b0681d commit 58c91b8

1 file changed

Lines changed: 61 additions & 0 deletions

File tree

guest-agent/src/rpc_service.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use dstack_guest_agent_rpc::{
1515
SignRequest, SignResponse, TdxQuoteArgs, TdxQuoteResponse, WorkerVersion,
1616
};
1717
use dstack_types::{AppKeys, SysConfig};
18+
use ed25519_dalek::ed25519::signature::hazmat::PrehashSigner;
1819
use ed25519_dalek::{Signer as Ed25519Signer, SigningKey as Ed25519SigningKey};
1920
use fs_err as fs;
2021
use k256::ecdsa::SigningKey;
@@ -313,6 +314,17 @@ impl DstackGuestRpc for InternalRpcHandler {
313314
self.state.inner.secp256k1_key.sign(&request.data);
314315
signature.to_bytes().to_vec()
315316
}
317+
"secp256k1_prehashed" => {
318+
if request.data.len() != 32 {
319+
return Err(anyhow::anyhow!(
320+
"Pre-hashed signing requires a 32-byte digest, but received {} bytes",
321+
request.data.len()
322+
));
323+
}
324+
let signature: k256::ecdsa::Signature =
325+
self.state.inner.secp256k1_key.sign_prehash(&request.data)?;
326+
signature.to_bytes().to_vec()
327+
}
316328
_ => return Err(anyhow::anyhow!("Unsupported algorithm")),
317329
};
318330
Ok(SignResponse { signature })
@@ -517,8 +529,10 @@ mod tests {
517529
use crate::config::{AppComposeWrapper, Config, Simulator};
518530
use dstack_guest_agent_rpc::{GetAttestationForAppKeyRequest, SignRequest};
519531
use dstack_types::{AppCompose, AppKeys, DockerConfig, KeyProvider};
532+
use ed25519_dalek::ed25519::signature::hazmat::PrehashVerifier;
520533
use ed25519_dalek::{Signature as Ed25519Signature, Verifier};
521534
use k256::ecdsa::{Signature as K256Signature, VerifyingKey};
535+
use sha2::Sha256;
522536
use std::collections::HashSet;
523537
use std::convert::TryFrom;
524538

@@ -713,6 +727,53 @@ pNs85uhOZE8z2jr8Pg==
713727
assert!(public_key.verify(data_to_sign, &signature).is_ok());
714728
}
715729

730+
#[tokio::test]
731+
async fn test_sign_secp256k1_prehashed_success() {
732+
let state = setup_test_state().await;
733+
let handler = InternalRpcHandler {
734+
state: state.clone(),
735+
};
736+
let data_to_sign = b"test message for secp256k1 prehashed";
737+
738+
let digest = Sha256::digest(data_to_sign);
739+
740+
let request = SignRequest {
741+
algorithm: "secp256k1_prehashed".to_string(),
742+
data: digest.to_vec(),
743+
};
744+
745+
let response = handler.sign(request).await.unwrap();
746+
747+
let public_key = VerifyingKey::from(&state.inner.secp256k1_key);
748+
let signature = K256Signature::try_from(response.signature.as_slice()).unwrap();
749+
assert!(public_key
750+
.verify_prehash(digest.as_slice(), &signature)
751+
.is_ok());
752+
}
753+
754+
#[tokio::test]
755+
async fn test_sign_secp256k1_prehashed_invalid_length_fails() {
756+
let state = setup_test_state().await;
757+
let handler = InternalRpcHandler {
758+
state: state.clone(),
759+
};
760+
761+
// digest with an invalid length
762+
let invalid_digest = vec![0; 31];
763+
764+
let request = SignRequest {
765+
algorithm: "secp256k1_prehashed".to_string(),
766+
data: invalid_digest,
767+
};
768+
769+
let response = handler.sign(request).await;
770+
assert!(response.is_err());
771+
assert!(response
772+
.unwrap_err()
773+
.to_string()
774+
.contains("requires a 32-byte digest"));
775+
}
776+
716777
#[tokio::test]
717778
async fn test_sign_unsupported_algorithm_fails() {
718779
let state = setup_test_state().await;

0 commit comments

Comments
 (0)