1use anyhow::Result;
6use cryptoki::mechanism::Mechanism;
7use cryptoki::mechanism::vendor_defined::VendorDefinedMechanism;
8use rsa::pkcs1v15::Pkcs1v15Sign;
9use serde::{Deserialize, Serialize};
10use sha2::Sha256;
11use sha2::digest::Digest;
12use sha2::digest::const_oid::AssociatedOid;
13use sphincsplus::SpxDomain;
14use std::str::FromStr;
15
16use crate::error::HsmError;
17use crate::util::attribute::{KeyType, MechanismType};
18use crate::util::helper::parse_range;
19
20#[derive(clap::ValueEnum, Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
22#[value(rename_all = "kebab-case")]
23pub enum MlDsaDomain {
24 Pure,
26 PreHashed,
28}
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
32pub enum SignData {
33 #[serde(alias = "plain-text")]
36 PlainText,
37 #[serde(alias = "sha256-hash")]
40 Sha256Hash,
41 #[serde(alias = "sha256-hash-reversed")]
44 Sha256HashReversed,
45 #[serde(alias = "raw")]
47 Raw,
48 #[serde(alias = "slice")]
51 Slice(usize, usize),
52}
53
54impl FromStr for SignData {
55 type Err = anyhow::Error;
56 fn from_str(input: &str) -> Result<Self> {
57 if input.eq_ignore_ascii_case("plain-text") {
58 Ok(SignData::PlainText)
59 } else if input.eq_ignore_ascii_case("sha256-hash") {
60 Ok(SignData::Sha256Hash)
61 } else if input.eq_ignore_ascii_case("sha256-hash-reversed") {
62 Ok(SignData::Sha256HashReversed)
63 } else if input.eq_ignore_ascii_case("raw") {
64 Ok(SignData::Raw)
65 } else if input[..6].eq_ignore_ascii_case("slice:") {
66 let r = parse_range(&input[6..])?;
67 Ok(SignData::Slice(r.start, r.end))
68 } else {
69 Err(HsmError::Unsupported(format!("invalid variant: {input}")).into())
70 }
71 }
72}
73
74impl SignData {
75 pub const HELP: &'static str = "[allowed values: plain-text, sha256-hash, raw, slice:m..n]";
76 pub fn prepare(&self, keytype: KeyType, input: &[u8]) -> Result<Vec<u8>> {
78 match keytype {
79 KeyType::Rsa => match self {
80 SignData::PlainText => Self::pkcs15sign::<Sha256>(&Self::data_plain_text(input)?),
82 SignData::Sha256Hash => Self::pkcs15sign::<Sha256>(&Self::data_raw(input, false)?),
84 SignData::Sha256HashReversed => {
85 Self::pkcs15sign::<Sha256>(&Self::data_raw(input, true)?)
86 }
87 SignData::Raw => Self::data_raw(input, false),
89 SignData::Slice(a, b) => {
91 Self::pkcs15sign::<Sha256>(&Self::data_plain_text(&input[*a..*b])?)
92 }
93 },
94 KeyType::Ec => match self {
95 SignData::PlainText => Self::data_plain_text(input),
97 SignData::Sha256Hash => Self::data_raw(input, false),
98 SignData::Sha256HashReversed => Self::data_raw(input, true),
99 SignData::Raw => Self::data_raw(input, false),
101 SignData::Slice(a, b) => Self::data_plain_text(&input[*a..*b]),
103 },
104 _ => Err(HsmError::Unsupported(format!("SignData prepare for {keytype:?}")).into()),
105 }
106 }
107
108 pub fn mldsa_prepare(&self, domain: MlDsaDomain, input: &[u8]) -> Result<Vec<u8>> {
109 match self {
110 SignData::PlainText => match domain {
111 MlDsaDomain::Pure => Ok(input.into()),
112 MlDsaDomain::PreHashed => Ok(Sha256::digest(input).as_slice().to_vec()),
113 },
114 SignData::Sha256Hash => Ok(input.into()),
115 SignData::Sha256HashReversed => Self::data_raw(input, true),
116 SignData::Raw => Ok(input.into()),
117 SignData::Slice(a, b) => {
118 let input = &input[*a..*b];
119 match domain {
120 MlDsaDomain::Pure => Ok(input.into()),
121 MlDsaDomain::PreHashed => Ok(Sha256::digest(input).as_slice().to_vec()),
122 }
123 }
124 }
125 }
126
127 pub fn spx_prepare(&self, domain: SpxDomain, input: &[u8]) -> Result<Vec<u8>> {
128 match self {
129 SignData::PlainText => {
130 match domain {
131 SpxDomain::None | SpxDomain::Pure => Ok(input.into()),
133 SpxDomain::PreHashedSha256 => Ok(Sha256::digest(input).as_slice().to_vec()),
135 }
136 }
137 SignData::Sha256Hash => {
138 Ok(input.into())
140 }
141 SignData::Sha256HashReversed => {
142 Self::data_raw(input, true)
144 }
145 SignData::Raw => {
146 Ok(input.into())
148 }
149 SignData::Slice(a, b) => {
150 let input = &input[*a..*b];
151 match domain {
152 SpxDomain::None | SpxDomain::Pure => Ok(input.into()),
154 SpxDomain::PreHashedSha256 => Ok(Sha256::digest(input).as_slice().to_vec()),
156 }
157 }
158 }
159 }
160
161 pub fn mechanism(&self, keytype: KeyType) -> Result<Mechanism<'_>> {
163 match keytype {
164 KeyType::Rsa => match self {
165 SignData::PlainText => Ok(Mechanism::RsaPkcs),
166 SignData::Sha256Hash => Ok(Mechanism::RsaPkcs),
167 SignData::Sha256HashReversed => Ok(Mechanism::RsaPkcs),
168 SignData::Raw => Err(HsmError::Unsupported(
169 "rust-cryptoki Mechanism doesn't include RSA_X_509".into(),
170 )
171 .into()),
172 SignData::Slice(_, _) => Ok(Mechanism::RsaPkcs),
173 },
174 KeyType::Ec => match self {
175 SignData::PlainText => Ok(Mechanism::Ecdsa),
176 SignData::Sha256Hash => Ok(Mechanism::Ecdsa),
177 SignData::Sha256HashReversed => Ok(Mechanism::Ecdsa),
178 SignData::Raw => Ok(Mechanism::Ecdsa),
179 SignData::Slice(_, _) => Ok(Mechanism::Ecdsa),
180 },
181 KeyType::MlDsa => {
182 let mechanism = Mechanism::VendorDefined(VendorDefinedMechanism::new::<()>(
183 MechanismType::MlDsa.try_into()?,
184 None,
185 ));
186 match self {
187 SignData::PlainText => Ok(mechanism),
188 SignData::Sha256Hash => Ok(mechanism),
189 SignData::Sha256HashReversed => Ok(mechanism),
190 SignData::Raw => Ok(mechanism),
191 SignData::Slice(_, _) => Ok(mechanism),
192 }
193 }
194 _ => Err(HsmError::Unsupported(format!("No mechanism for {keytype:?}")).into()),
195 }
196 }
197
198 fn data_raw(input: &[u8], reverse: bool) -> Result<Vec<u8>> {
199 let mut result = Vec::new();
200 result.extend_from_slice(input);
201 if reverse {
202 result.reverse();
203 }
204 Ok(result)
205 }
206
207 fn pkcs15sign<D>(input: &[u8]) -> Result<Vec<u8>>
208 where
209 D: Digest + AssociatedOid,
210 {
211 let s = Pkcs1v15Sign::new::<D>();
212 let hash_len = s.hash_len.unwrap();
213 if hash_len != input.len() {
214 return Err(HsmError::HashSizeError(hash_len, input.len()).into());
215 }
216 let mut result = Vec::new();
217 result.extend_from_slice(&s.prefix);
218 result.extend_from_slice(input);
219 Ok(result)
220 }
221
222 fn data_plain_text(input: &[u8]) -> Result<Vec<u8>> {
223 let result = Sha256::digest(input).as_slice().to_vec();
224 Ok(result)
225 }
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231
232 #[test]
233 fn test_raw() -> Result<()> {
234 let result = SignData::Raw.prepare(KeyType::Rsa, b"abc123")?;
235 assert_eq!(result, b"abc123");
236 Ok(())
237 }
238
239 #[test]
240 fn test_plain_text() -> Result<()> {
241 let result = SignData::PlainText.prepare(
242 KeyType::Rsa,
243 b"The quick brown fox jumped over the lazy dog",
244 )?;
245 assert_eq!(
246 hex::encode(result),
247 "3031300d0609608648016503040201050004207d38b5cd25a2baf85ad3bb5b9311383e671a8a142eb302b324d4a5fba8748c69"
248 );
249
250 let result = SignData::PlainText
251 .prepare(KeyType::Ec, b"The quick brown fox jumped over the lazy dog")?;
252 assert_eq!(
253 hex::encode(result),
254 "7d38b5cd25a2baf85ad3bb5b9311383e671a8a142eb302b324d4a5fba8748c69",
255 );
256 Ok(())
257 }
258
259 #[test]
260 fn test_hashed() -> Result<()> {
261 let input =
262 hex::decode("7d38b5cd25a2baf85ad3bb5b9311383e671a8a142eb302b324d4a5fba8748c69")?;
263 let result = SignData::Sha256Hash.prepare(KeyType::Rsa, &input)?;
264 assert_eq!(
265 hex::encode(result),
266 "3031300d0609608648016503040201050004207d38b5cd25a2baf85ad3bb5b9311383e671a8a142eb302b324d4a5fba8748c69"
267 );
268
269 assert!(SignData::Sha256Hash.prepare(KeyType::Rsa, b"").is_err());
270 Ok(())
271 }
272
273 #[test]
274 fn test_slice() -> Result<()> {
275 let result = SignData::Slice(0, 3)
276 .prepare(KeyType::Ec, b"The quick brown fox jumped over the lazy dog")?;
277 assert_eq!(
278 hex::encode(result),
279 "b344d80e24a3679999fa964450b34bc24d1578a35509f934c1418b0a20d21a67",
281 );
282 Ok(())
283 }
284}