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