confium_tls_signer/
lib.rs1#![forbid(unsafe_code)]
11#![allow(missing_docs)] use serde::{Deserialize, Serialize};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
17#[serde(rename_all = "snake_case")]
18#[repr(u16)]
19pub enum SignatureScheme {
20 EcdsaSecp256r1Sha256 = 0x0403,
22 Ed25519 = 0x0807,
24 RsaPkcs1Sha256 = 0x0401,
26 RsaPssSha256 = 0x0804,
28}
29
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct TlsSignatureRequest {
33 pub scheme: SignatureScheme,
35 pub data: Vec<u8>,
37 pub quorum_id: String,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct TlsSignatureResponse {
44 pub scheme: SignatureScheme,
46 pub signature: Vec<u8>,
48}
49
50#[derive(Debug, thiserror::Error)]
52pub enum TlsSignerError {
53 #[error("unsupported signature scheme: {0:?}")]
55 UnsupportedScheme(SignatureScheme),
56 #[error("threshold signing failed: {0}")]
58 ThresholdFailed(String),
59 #[error("coordinator unreachable: {0}")]
61 CoordinatorUnreachable(String),
62 #[error("timeout waiting for T-of-N quorum")]
64 QuorumTimeout,
65}
66
67pub trait ThresholdSigner {
69 fn sign(
71 &self,
72 quorum_id: &str,
73 scheme: SignatureScheme,
74 data: &[u8],
75 ) -> Result<Vec<u8>, String>;
76}
77
78pub struct TlsSigner<'a> {
80 signer: &'a dyn ThresholdSigner,
81}
82
83impl<'a> TlsSigner<'a> {
84 pub fn new(signer: &'a dyn ThresholdSigner) -> Self {
86 Self { signer }
87 }
88
89 pub fn sign(
91 &self,
92 request: &TlsSignatureRequest,
93 ) -> Result<TlsSignatureResponse, TlsSignerError> {
94 let signature = self
95 .signer
96 .sign(&request.quorum_id, request.scheme, &request.data)
97 .map_err(TlsSignerError::ThresholdFailed)?;
98 Ok(TlsSignatureResponse {
99 scheme: request.scheme,
100 signature,
101 })
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 struct MockSigner;
110 impl ThresholdSigner for MockSigner {
111 fn sign(
112 &self,
113 _quorum_id: &str,
114 _scheme: SignatureScheme,
115 data: &[u8],
116 ) -> Result<Vec<u8>, String> {
117 Ok(data.to_vec())
118 }
119 }
120
121 #[test]
122 fn tls_sign_mock_round_trip() {
123 let signer = MockSigner;
124 let tls = TlsSigner::new(&signer);
125 let req = TlsSignatureRequest {
126 scheme: SignatureScheme::Ed25519,
127 data: b"handshake transcript".to_vec(),
128 quorum_id: "test-quorum".into(),
129 };
130 let resp = tls.sign(&req).unwrap();
131 assert_eq!(resp.scheme, SignatureScheme::Ed25519);
132 assert_eq!(resp.signature, req.data);
133 }
134}