1use crate::error::{KeyRejected, Unspecified};
9use native_ossl::digest::DigestAlg;
10use native_ossl::params::ParamBuilder;
11use native_ossl::pkey::{KeygenCtx, Pkey, Private, Public, SignInit, Signer, Verifier};
12use std::ffi::CStr;
13
14use crate::spki::{ED25519_SPKI_HEADER, P256_SPKI_HEADER, P384_SPKI_HEADER};
15
16#[derive(Debug)]
24pub struct Algorithm {
25 pub(crate) name: &'static str,
27 pub(crate) ec_curve: Option<&'static CStr>,
29 pub(crate) spki_header: Option<&'static [u8]>,
32 pub(crate) digest_name: Option<&'static CStr>,
34 pub(crate) rsa_pss: bool,
36}
37
38pub static ECDSA_P256_SHA256_ASN1: Algorithm = Algorithm {
39 name: "ECDSA_P256_SHA256_ASN1",
40 ec_curve: Some(c"P-256"),
41 spki_header: Some(P256_SPKI_HEADER),
42 digest_name: Some(c"SHA2-256"),
43 rsa_pss: false,
44};
45pub static ECDSA_P384_SHA384_ASN1: Algorithm = Algorithm {
46 name: "ECDSA_P384_SHA384_ASN1",
47 ec_curve: Some(c"P-384"),
48 spki_header: Some(P384_SPKI_HEADER),
49 digest_name: Some(c"SHA2-384"),
50 rsa_pss: false,
51};
52pub static ED25519: Algorithm = Algorithm {
53 name: "ED25519",
54 ec_curve: None,
55 spki_header: Some(ED25519_SPKI_HEADER),
56 digest_name: None,
57 rsa_pss: false,
58};
59pub static RSA_PKCS1_SHA256: Algorithm = Algorithm {
60 name: "RSA_PKCS1_SHA256",
61 ec_curve: None,
62 spki_header: None,
63 digest_name: Some(c"SHA2-256"),
64 rsa_pss: false,
65};
66pub static RSA_PKCS1_SHA384: Algorithm = Algorithm {
67 name: "RSA_PKCS1_SHA384",
68 ec_curve: None,
69 spki_header: None,
70 digest_name: Some(c"SHA2-384"),
71 rsa_pss: false,
72};
73pub static RSA_PKCS1_SHA512: Algorithm = Algorithm {
74 name: "RSA_PKCS1_SHA512",
75 ec_curve: None,
76 spki_header: None,
77 digest_name: Some(c"SHA2-512"),
78 rsa_pss: false,
79};
80pub static RSA_PSS_SHA256: Algorithm = Algorithm {
81 name: "RSA_PSS_SHA256",
82 ec_curve: None,
83 spki_header: None,
84 digest_name: Some(c"SHA2-256"),
85 rsa_pss: true,
86};
87pub static RSA_PSS_SHA384: Algorithm = Algorithm {
88 name: "RSA_PSS_SHA384",
89 ec_curve: None,
90 spki_header: None,
91 digest_name: Some(c"SHA2-384"),
92 rsa_pss: true,
93};
94pub static RSA_PSS_SHA512: Algorithm = Algorithm {
95 name: "RSA_PSS_SHA512",
96 ec_curve: None,
97 spki_header: None,
98 digest_name: Some(c"SHA2-512"),
99 rsa_pss: true,
100};
101
102#[derive(Debug)]
106pub struct Signature(Vec<u8>);
107
108impl AsRef<[u8]> for Signature {
109 fn as_ref(&self) -> &[u8] {
110 &self.0
111 }
112}
113
114pub struct EcdsaKeyPair {
118 alg: &'static Algorithm,
119 priv_key: Pkey<Private>,
120 pub_key_bytes: Vec<u8>,
121}
122
123impl std::fmt::Debug for EcdsaKeyPair {
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 f.debug_struct("EcdsaKeyPair")
126 .field("alg", &self.alg.name)
127 .finish_non_exhaustive()
128 }
129}
130
131impl EcdsaKeyPair {
132 pub fn generate(alg: &'static Algorithm) -> Result<Self, Unspecified> {
138 let curve = alg.ec_curve.ok_or(Unspecified)?;
139 let spki_header = alg.spki_header.ok_or(Unspecified)?;
140
141 let mut ctx = KeygenCtx::new(c"EC").map_err(|_| Unspecified)?;
142 let params = ParamBuilder::new()
143 .and_then(|b| b.push_utf8_string(c"group", curve))
144 .and_then(ParamBuilder::build)
145 .map_err(|_| Unspecified)?;
146 ctx.set_params(¶ms).map_err(|_| Unspecified)?;
147 let priv_key = ctx.generate().map_err(|_| Unspecified)?;
148
149 let spki = priv_key.public_key_to_der().map_err(|_| Unspecified)?;
150 let raw_pub = spki.get(spki_header.len()..).ok_or(Unspecified)?.to_vec();
151
152 Ok(Self {
153 alg,
154 priv_key,
155 pub_key_bytes: raw_pub,
156 })
157 }
158
159 pub fn from_pkcs8(
165 alg: &'static Algorithm,
166 pkcs8: &[u8],
167 _rng: &dyn crate::rand::SecureRandom,
168 ) -> Result<Self, KeyRejected> {
169 let spki_header = alg
170 .spki_header
171 .ok_or_else(|| KeyRejected::new("wrong algorithm kind for ECDSA"))?;
172
173 let priv_key =
174 Pkey::<Private>::from_der(pkcs8).map_err(|_| KeyRejected::new("bad PKCS8 DER"))?;
175 if !priv_key.is_a(c"EC") {
176 return Err(KeyRejected::new("not an EC key"));
177 }
178 let spki = priv_key
180 .public_key_to_der()
181 .map_err(|_| KeyRejected::new("public_key_to_der failed"))?;
182 if !spki.starts_with(spki_header) {
183 return Err(KeyRejected::new("wrong EC curve"));
184 }
185 let raw_pub = spki[spki_header.len()..].to_vec();
186
187 Ok(Self {
188 alg,
189 priv_key,
190 pub_key_bytes: raw_pub,
191 })
192 }
193
194 #[must_use]
195 pub fn public_key(&self) -> &[u8] {
196 &self.pub_key_bytes
197 }
198
199 pub fn sign(
205 &self,
206 _rng: &dyn crate::rand::SecureRandom,
207 message: &[u8],
208 ) -> Result<Signature, Unspecified> {
209 let digest_name = self.alg.digest_name.ok_or(Unspecified)?;
210 let digest_alg = DigestAlg::fetch(digest_name, None).map_err(|_| Unspecified)?;
211 let init = SignInit {
212 digest: Some(&digest_alg),
213 params: None,
214 };
215 let mut signer = Signer::new(&self.priv_key, &init).map_err(|_| Unspecified)?;
216 let sig = signer.sign_oneshot(message).map_err(|_| Unspecified)?;
217 Ok(Signature(sig))
218 }
219}
220
221pub struct Ed25519KeyPair {
225 priv_key: Pkey<Private>,
226 pub_key_bytes: Vec<u8>,
227}
228
229impl std::fmt::Debug for Ed25519KeyPair {
230 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
231 f.debug_struct("Ed25519KeyPair").finish_non_exhaustive()
232 }
233}
234
235impl Ed25519KeyPair {
236 pub fn generate() -> Result<Self, Unspecified> {
242 let mut ctx = KeygenCtx::new(c"ED25519").map_err(|_| Unspecified)?;
243 let priv_key = ctx.generate().map_err(|_| Unspecified)?;
244 let spki = priv_key.public_key_to_der().map_err(|_| Unspecified)?;
245 let raw_pub = spki
246 .get(ED25519_SPKI_HEADER.len()..)
247 .ok_or(Unspecified)?
248 .to_vec();
249 Ok(Self {
250 priv_key,
251 pub_key_bytes: raw_pub,
252 })
253 }
254
255 pub fn from_pkcs8(pkcs8: &[u8]) -> Result<Self, KeyRejected> {
261 let priv_key =
262 Pkey::<Private>::from_der(pkcs8).map_err(|_| KeyRejected::new("bad PKCS8 DER"))?;
263 if !priv_key.is_a(c"ED25519") {
264 return Err(KeyRejected::new("not an Ed25519 key"));
265 }
266 let spki = priv_key
267 .public_key_to_der()
268 .map_err(|_| KeyRejected::new("public_key_to_der failed"))?;
269 let raw_pub = spki
270 .get(ED25519_SPKI_HEADER.len()..)
271 .ok_or_else(|| KeyRejected::new("unexpected SPKI layout"))?
272 .to_vec();
273 Ok(Self {
274 priv_key,
275 pub_key_bytes: raw_pub,
276 })
277 }
278
279 #[must_use]
280 pub fn public_key(&self) -> &[u8] {
281 &self.pub_key_bytes
282 }
283
284 pub fn sign(&self, message: &[u8]) -> Result<Signature, Unspecified> {
290 let init = SignInit {
291 digest: None,
292 params: None,
293 };
294 let mut signer = Signer::new(&self.priv_key, &init).map_err(|_| Unspecified)?;
295 let sig = signer.sign_oneshot(message).map_err(|_| Unspecified)?;
296 Ok(Signature(sig))
297 }
298}
299
300pub struct UnparsedPublicKey<'a> {
304 alg: &'static Algorithm,
305 bytes: &'a [u8],
306}
307
308impl<'a> UnparsedPublicKey<'a> {
309 #[must_use]
310 pub fn new(algorithm: &'static Algorithm, bytes: &'a [u8]) -> Self {
311 Self {
312 alg: algorithm,
313 bytes,
314 }
315 }
316}
317
318pub fn verify(
324 algorithm: &'static Algorithm,
325 public_key: &[u8],
326 message: &[u8],
327 signature: &[u8],
328) -> Result<(), Unspecified> {
329 UnparsedPublicKey::new(algorithm, public_key).verify(message, signature)
330}
331
332impl UnparsedPublicKey<'_> {
333 pub fn verify(&self, message: &[u8], signature: &[u8]) -> Result<(), Unspecified> {
337 let pub_key = load_public_key(self.alg, self.bytes)?;
338 verify_with_key(self.alg, &pub_key, message, signature)
339 }
340}
341
342fn load_public_key(alg: &'static Algorithm, raw: &[u8]) -> Result<Pkey<Public>, Unspecified> {
343 let spki = match alg.spki_header {
344 Some(header) => {
345 let mut v = header.to_vec();
346 v.extend_from_slice(raw);
347 v
348 }
349 None => raw.to_vec(),
351 };
352 Pkey::<Public>::from_der(&spki).map_err(|_| Unspecified)
353}
354
355fn verify_with_key(
356 alg: &'static Algorithm,
357 pub_key: &Pkey<Public>,
358 message: &[u8],
359 signature: &[u8],
360) -> Result<(), Unspecified> {
361 match alg.digest_name {
362 None => {
363 let init = SignInit {
365 digest: None,
366 params: None,
367 };
368 let mut verifier = Verifier::new(pub_key, &init).map_err(|_| Unspecified)?;
369 let ok = verifier
370 .verify_oneshot(message, signature)
371 .map_err(|_| Unspecified)?;
372 if ok {
373 Ok(())
374 } else {
375 Err(Unspecified)
376 }
377 }
378 Some(digest_name) => verify_digest(pub_key, digest_name, alg.rsa_pss, message, signature),
379 }
380}
381
382fn verify_digest(
383 pub_key: &Pkey<Public>,
384 digest_name: &'static CStr,
385 rsa_pss: bool,
386 message: &[u8],
387 signature: &[u8],
388) -> Result<(), Unspecified> {
389 let digest_alg = DigestAlg::fetch(digest_name, None).map_err(|_| Unspecified)?;
390
391 let params = if rsa_pss {
392 let p = ParamBuilder::new()
393 .and_then(|b| b.push_utf8_string(c"pad-mode", c"pss"))
394 .and_then(ParamBuilder::build)
395 .map_err(|_| Unspecified)?;
396 Some(p)
397 } else {
398 None
399 };
400
401 let init = SignInit {
402 digest: Some(&digest_alg),
403 params: params.as_ref(),
404 };
405 let mut verifier = Verifier::new(pub_key, &init).map_err(|_| Unspecified)?;
406 let ok = verifier
407 .verify_oneshot(message, signature)
408 .map_err(|_| Unspecified)?;
409 if ok {
410 Ok(())
411 } else {
412 Err(Unspecified)
413 }
414}