Commit
Author: Dirkjan Ochtman [dirkjan@ochtman.nl]
Hash: 0730789dca4aa88b02a64f1f83599495e125dfb9
Timestamp: Wed, 14 Dec 2022 14:10:59 +0000 (1 year ago)

+335 -345 +/-3 browse
Move RustCrypto module into a separate file
1diff --git a/src/common/crypto.rs b/src/common/crypto.rs
2deleted file mode 100644
3index 76e20bb..0000000
4--- a/src/common/crypto.rs
5+++ /dev/null
6 @@ -1,345 +0,0 @@
7- use sha1::{digest::Output, Digest};
8-
9- use crate::{dkim::Canonicalization, Error, Result};
10-
11- use super::headers::Writer;
12-
13- pub trait SigningKey {
14- type Hasher: HashImpl;
15-
16- fn sign(&self, data: HashOutput) -> Result<Vec<u8>>;
17-
18- fn hasher(&self) -> <Self::Hasher as HashImpl>::Context {
19- <Self::Hasher as HashImpl>::hasher()
20- }
21-
22- fn algorithm(&self) -> Algorithm;
23- }
24-
25- mod rust_crypto {
26- use std::marker::PhantomData;
27-
28- use ed25519_dalek::Signer;
29- use rsa::{pkcs1::DecodeRsaPrivateKey, PaddingScheme, PublicKey as _, RsaPrivateKey};
30- use sha2::digest::Digest;
31-
32- use crate::{common::headers::Writer, dkim::Canonicalization};
33-
34- use super::{
35- Algorithm, Error, HashContext, HashImpl, HashOutput, Result, Sha1, Sha256, SigningKey,
36- VerifyingKey,
37- };
38-
39- #[derive(Clone, Debug)]
40- pub struct RsaKey<T> {
41- inner: RsaPrivateKey,
42- padding: PhantomData<T>,
43- }
44-
45- impl<T: HashImpl> RsaKey<T> {
46- /// Creates a new RSA private key from a PKCS1 PEM string.
47- pub fn from_pkcs1_pem(private_key_pem: &str) -> Result<Self> {
48- let inner = RsaPrivateKey::from_pkcs1_pem(private_key_pem)
49- .map_err(|err| Error::CryptoError(err.to_string()))?;
50-
51- Ok(RsaKey {
52- inner,
53- padding: PhantomData,
54- })
55- }
56-
57- /// Creates a new RSA private key from a PKCS1 binary slice.
58- pub fn from_pkcs1_der(private_key_bytes: &[u8]) -> Result<Self> {
59- let inner = RsaPrivateKey::from_pkcs1_der(private_key_bytes)
60- .map_err(|err| Error::CryptoError(err.to_string()))?;
61-
62- Ok(RsaKey {
63- inner,
64- padding: PhantomData,
65- })
66- }
67- }
68-
69- impl SigningKey for RsaKey<Sha1> {
70- type Hasher = Sha1;
71-
72- fn sign(&self, data: HashOutput) -> Result<Vec<u8>> {
73- self.inner
74- .sign(
75- PaddingScheme::new_pkcs1v15_sign::<<Self::Hasher as HashImpl>::Context>(),
76- data.as_ref(),
77- )
78- .map_err(|err| Error::CryptoError(err.to_string()))
79- }
80-
81- fn algorithm(&self) -> Algorithm {
82- Algorithm::RsaSha1
83- }
84- }
85-
86- impl SigningKey for RsaKey<Sha256> {
87- type Hasher = Sha256;
88-
89- fn sign(&self, data: HashOutput) -> Result<Vec<u8>> {
90- self.inner
91- .sign(
92- PaddingScheme::new_pkcs1v15_sign::<<Self::Hasher as HashImpl>::Context>(),
93- data.as_ref(),
94- )
95- .map_err(|err| Error::CryptoError(err.to_string()))
96- }
97-
98- fn algorithm(&self) -> Algorithm {
99- Algorithm::RsaSha256
100- }
101- }
102-
103- pub struct Ed25519Key {
104- inner: ed25519_dalek::Keypair,
105- }
106-
107- impl Ed25519Key {
108- /// Creates an Ed25519 private key
109- pub fn from_bytes(
110- public_key_bytes: &[u8],
111- private_key_bytes: &[u8],
112- ) -> crate::Result<Self> {
113- Ok(Self {
114- inner: ed25519_dalek::Keypair {
115- public: ed25519_dalek::PublicKey::from_bytes(public_key_bytes)
116- .map_err(|err| Error::CryptoError(err.to_string()))?,
117- secret: ed25519_dalek::SecretKey::from_bytes(private_key_bytes)
118- .map_err(|err| Error::CryptoError(err.to_string()))?,
119- },
120- })
121- }
122- }
123-
124- impl SigningKey for Ed25519Key {
125- type Hasher = Sha256;
126-
127- fn sign(&self, data: HashOutput) -> Result<Vec<u8>> {
128- Ok(self.inner.sign(data.as_ref()).to_bytes().to_vec())
129- }
130-
131- fn algorithm(&self) -> Algorithm {
132- Algorithm::Ed25519Sha256
133- }
134- }
135-
136- pub(crate) struct RsaPublicKey {
137- inner: rsa::RsaPublicKey,
138- }
139-
140- impl RsaPublicKey {
141- pub(crate) fn verifying_key_from_bytes(
142- bytes: &[u8],
143- ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
144- Ok(Box::new(RsaPublicKey {
145- inner: <rsa::RsaPublicKey as rsa::pkcs8::DecodePublicKey>::from_public_key_der(
146- bytes,
147- )
148- .or_else(|_| rsa::pkcs1::DecodeRsaPublicKey::from_pkcs1_der(bytes))
149- .map_err(|err| Error::CryptoError(err.to_string()))?,
150- }))
151- }
152- }
153-
154- impl VerifyingKey for RsaPublicKey {
155- fn verify<'a>(
156- &self,
157- headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
158- signature: &[u8],
159- canonicalization: Canonicalization,
160- algorithm: Algorithm,
161- ) -> Result<()> {
162- match algorithm {
163- Algorithm::RsaSha256 => {
164- let hash = canonicalization.hash_headers::<Sha256>(headers);
165- self.inner
166- .verify(
167- PaddingScheme::new_pkcs1v15_sign::<sha2::Sha256>(),
168- hash.as_ref(),
169- signature,
170- )
171- .map_err(|_| Error::FailedVerification)
172- }
173- Algorithm::RsaSha1 => {
174- let hash = canonicalization.hash_headers::<Sha1>(headers);
175- self.inner
176- .verify(
177- PaddingScheme::new_pkcs1v15_sign::<sha1::Sha1>(),
178- hash.as_ref(),
179- signature,
180- )
181- .map_err(|_| Error::FailedVerification)
182- }
183- Algorithm::Ed25519Sha256 => Err(Error::IncompatibleAlgorithms),
184- }
185- }
186- }
187-
188- pub(crate) struct Ed25519PublicKey {
189- inner: ed25519_dalek::PublicKey,
190- }
191-
192- impl Ed25519PublicKey {
193- pub(crate) fn verifying_key_from_bytes(
194- bytes: &[u8],
195- ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
196- Ok(Box::new(Ed25519PublicKey {
197- inner: ed25519_dalek::PublicKey::from_bytes(bytes)
198- .map_err(|err| Error::CryptoError(err.to_string()))?,
199- }))
200- }
201- }
202-
203- impl VerifyingKey for Ed25519PublicKey {
204- fn verify<'a>(
205- &self,
206- headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
207- signature: &[u8],
208- canonicalization: Canonicalization,
209- algorithm: Algorithm,
210- ) -> Result<()> {
211- if !matches!(algorithm, Algorithm::Ed25519Sha256) {
212- return Err(Error::IncompatibleAlgorithms);
213- }
214-
215- let hash = canonicalization.hash_headers::<Sha256>(headers);
216- self.inner
217- .verify_strict(
218- hash.as_ref(),
219- &ed25519_dalek::Signature::from_bytes(signature)
220- .map_err(|err| Error::CryptoError(err.to_string()))?,
221- )
222- .map_err(|_| Error::FailedVerification)
223- }
224- }
225-
226- impl Writer for sha1::Sha1 {
227- fn write(&mut self, buf: &[u8]) {
228- self.update(buf);
229- }
230- }
231-
232- impl Writer for sha2::Sha256 {
233- fn write(&mut self, buf: &[u8]) {
234- self.update(buf);
235- }
236- }
237-
238- impl HashImpl for Sha1 {
239- type Context = sha1::Sha1;
240-
241- fn hasher() -> Self::Context {
242- <Self::Context as Digest>::new()
243- }
244- }
245-
246- impl HashImpl for Sha256 {
247- type Context = sha2::Sha256;
248-
249- fn hasher() -> Self::Context {
250- <Self::Context as Digest>::new()
251- }
252- }
253-
254- impl HashContext for sha1::Sha1 {
255- fn finish(self) -> HashOutput {
256- HashOutput::Sha1(self.finalize())
257- }
258- }
259-
260- impl HashContext for sha2::Sha256 {
261- fn finish(self) -> HashOutput {
262- HashOutput::Sha256(self.finalize())
263- }
264- }
265- }
266-
267- pub use rust_crypto::{Ed25519Key, RsaKey};
268- pub(crate) use rust_crypto::{Ed25519PublicKey, RsaPublicKey};
269-
270- pub trait VerifyingKey {
271- fn verify<'a>(
272- &self,
273- headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
274- signature: &[u8],
275- canonicalication: Canonicalization,
276- algorithm: Algorithm,
277- ) -> Result<()>;
278- }
279-
280- pub(crate) enum VerifyingKeyType {
281- Rsa,
282- Ed25519,
283- }
284-
285- impl VerifyingKeyType {
286- pub(crate) fn verifying_key(
287- &self,
288- bytes: &[u8],
289- ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
290- match self {
291- Self::Rsa => RsaPublicKey::verifying_key_from_bytes(bytes),
292- Self::Ed25519 => Ed25519PublicKey::verifying_key_from_bytes(bytes),
293- }
294- }
295- }
296-
297- pub trait HashContext: Writer + Sized {
298- fn finish(self) -> HashOutput;
299- }
300-
301- pub trait HashImpl {
302- type Context: HashContext;
303-
304- fn hasher() -> Self::Context;
305- }
306-
307- #[derive(Clone, Copy)]
308- pub struct Sha1;
309-
310- #[derive(Clone, Copy)]
311- pub struct Sha256;
312-
313- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
314- #[repr(u64)]
315- pub enum HashAlgorithm {
316- Sha1 = R_HASH_SHA1,
317- Sha256 = R_HASH_SHA256,
318- }
319-
320- impl HashAlgorithm {
321- pub fn hash(&self, data: &[u8]) -> HashOutput {
322- match self {
323- Self::Sha1 => HashOutput::Sha1(sha1::Sha1::digest(data)),
324- Self::Sha256 => HashOutput::Sha256(sha2::Sha256::digest(data)),
325- }
326- }
327- }
328-
329- pub enum HashOutput {
330- Sha1(Output<sha1::Sha1>),
331- Sha256(Output<sha2::Sha256>),
332- }
333-
334- impl AsRef<[u8]> for HashOutput {
335- fn as_ref(&self) -> &[u8] {
336- match self {
337- Self::Sha1(output) => output.as_ref(),
338- Self::Sha256(output) => output.as_ref(),
339- }
340- }
341- }
342-
343- #[derive(Debug, Clone, Copy, PartialEq, Eq)]
344- pub enum Algorithm {
345- RsaSha1,
346- RsaSha256,
347- Ed25519Sha256,
348- }
349-
350- pub(crate) const R_HASH_SHA1: u64 = 0x01;
351- pub(crate) const R_HASH_SHA256: u64 = 0x02;
352 diff --git a/src/common/crypto/mod.rs b/src/common/crypto/mod.rs
353new file mode 100644
354index 0000000..bfb494d
355--- /dev/null
356+++ b/src/common/crypto/mod.rs
357 @@ -0,0 +1,104 @@
358+ use sha1::{digest::Output, Digest};
359+
360+ use crate::{dkim::Canonicalization, Result};
361+
362+ use super::headers::Writer;
363+
364+ mod rust_crypto;
365+ pub use rust_crypto::{Ed25519Key, RsaKey};
366+ pub(crate) use rust_crypto::{Ed25519PublicKey, RsaPublicKey};
367+
368+ pub trait SigningKey {
369+ type Hasher: HashImpl;
370+
371+ fn sign(&self, data: HashOutput) -> Result<Vec<u8>>;
372+
373+ fn hasher(&self) -> <Self::Hasher as HashImpl>::Context {
374+ <Self::Hasher as HashImpl>::hasher()
375+ }
376+
377+ fn algorithm(&self) -> Algorithm;
378+ }
379+
380+ pub trait VerifyingKey {
381+ fn verify<'a>(
382+ &self,
383+ headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
384+ signature: &[u8],
385+ canonicalication: Canonicalization,
386+ algorithm: Algorithm,
387+ ) -> Result<()>;
388+ }
389+
390+ pub(crate) enum VerifyingKeyType {
391+ Rsa,
392+ Ed25519,
393+ }
394+
395+ impl VerifyingKeyType {
396+ pub(crate) fn verifying_key(
397+ &self,
398+ bytes: &[u8],
399+ ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
400+ match self {
401+ Self::Rsa => RsaPublicKey::verifying_key_from_bytes(bytes),
402+ Self::Ed25519 => Ed25519PublicKey::verifying_key_from_bytes(bytes),
403+ }
404+ }
405+ }
406+
407+ pub trait HashContext: Writer + Sized {
408+ fn finish(self) -> HashOutput;
409+ }
410+
411+ pub trait HashImpl {
412+ type Context: HashContext;
413+
414+ fn hasher() -> Self::Context;
415+ }
416+
417+ #[derive(Clone, Copy)]
418+ pub struct Sha1;
419+
420+ #[derive(Clone, Copy)]
421+ pub struct Sha256;
422+
423+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
424+ #[repr(u64)]
425+ pub enum HashAlgorithm {
426+ Sha1 = R_HASH_SHA1,
427+ Sha256 = R_HASH_SHA256,
428+ }
429+
430+ impl HashAlgorithm {
431+ pub fn hash(&self, data: &[u8]) -> HashOutput {
432+ match self {
433+ Self::Sha1 => HashOutput::Sha1(sha1::Sha1::digest(data)),
434+ Self::Sha256 => HashOutput::Sha256(sha2::Sha256::digest(data)),
435+ }
436+ }
437+ }
438+
439+ pub enum HashOutput {
440+ Sha1(Output<sha1::Sha1>),
441+ Sha256(Output<sha2::Sha256>),
442+ }
443+
444+ impl AsRef<[u8]> for HashOutput {
445+ fn as_ref(&self) -> &[u8] {
446+ match self {
447+ Self::Sha1(output) => output.as_ref(),
448+ Self::Sha256(output) => output.as_ref(),
449+ }
450+ }
451+ }
452+
453+ #[derive(Debug, Clone, Copy, PartialEq, Eq)]
454+ pub enum Algorithm {
455+ RsaSha1,
456+ RsaSha256,
457+ Ed25519Sha256,
458+ }
459+
460+ pub(crate) const R_HASH_SHA1: u64 = 0x01;
461+ pub(crate) const R_HASH_SHA256: u64 = 0x02;
462 diff --git a/src/common/crypto/rust_crypto.rs b/src/common/crypto/rust_crypto.rs
463new file mode 100644
464index 0000000..dd59436
465--- /dev/null
466+++ b/src/common/crypto/rust_crypto.rs
467 @@ -0,0 +1,231 @@
468+ use std::marker::PhantomData;
469+
470+ use ed25519_dalek::Signer;
471+ use rsa::{pkcs1::DecodeRsaPrivateKey, PaddingScheme, PublicKey as _, RsaPrivateKey};
472+ use sha2::digest::Digest;
473+
474+ use crate::{common::headers::Writer, dkim::Canonicalization, Error, Result};
475+
476+ use super::{Algorithm, HashContext, HashImpl, HashOutput, Sha1, Sha256, SigningKey, VerifyingKey};
477+
478+ #[derive(Clone, Debug)]
479+ pub struct RsaKey<T> {
480+ inner: RsaPrivateKey,
481+ padding: PhantomData<T>,
482+ }
483+
484+ impl<T: HashImpl> RsaKey<T> {
485+ /// Creates a new RSA private key from a PKCS1 PEM string.
486+ pub fn from_pkcs1_pem(private_key_pem: &str) -> Result<Self> {
487+ let inner = RsaPrivateKey::from_pkcs1_pem(private_key_pem)
488+ .map_err(|err| Error::CryptoError(err.to_string()))?;
489+
490+ Ok(RsaKey {
491+ inner,
492+ padding: PhantomData,
493+ })
494+ }
495+
496+ /// Creates a new RSA private key from a PKCS1 binary slice.
497+ pub fn from_pkcs1_der(private_key_bytes: &[u8]) -> Result<Self> {
498+ let inner = RsaPrivateKey::from_pkcs1_der(private_key_bytes)
499+ .map_err(|err| Error::CryptoError(err.to_string()))?;
500+
501+ Ok(RsaKey {
502+ inner,
503+ padding: PhantomData,
504+ })
505+ }
506+ }
507+
508+ impl SigningKey for RsaKey<Sha1> {
509+ type Hasher = Sha1;
510+
511+ fn sign(&self, data: HashOutput) -> Result<Vec<u8>> {
512+ self.inner
513+ .sign(
514+ PaddingScheme::new_pkcs1v15_sign::<<Self::Hasher as HashImpl>::Context>(),
515+ data.as_ref(),
516+ )
517+ .map_err(|err| Error::CryptoError(err.to_string()))
518+ }
519+
520+ fn algorithm(&self) -> Algorithm {
521+ Algorithm::RsaSha1
522+ }
523+ }
524+
525+ impl SigningKey for RsaKey<Sha256> {
526+ type Hasher = Sha256;
527+
528+ fn sign(&self, data: HashOutput) -> Result<Vec<u8>> {
529+ self.inner
530+ .sign(
531+ PaddingScheme::new_pkcs1v15_sign::<<Self::Hasher as HashImpl>::Context>(),
532+ data.as_ref(),
533+ )
534+ .map_err(|err| Error::CryptoError(err.to_string()))
535+ }
536+
537+ fn algorithm(&self) -> Algorithm {
538+ Algorithm::RsaSha256
539+ }
540+ }
541+
542+ pub struct Ed25519Key {
543+ inner: ed25519_dalek::Keypair,
544+ }
545+
546+ impl Ed25519Key {
547+ /// Creates an Ed25519 private key
548+ pub fn from_bytes(public_key_bytes: &[u8], private_key_bytes: &[u8]) -> crate::Result<Self> {
549+ Ok(Self {
550+ inner: ed25519_dalek::Keypair {
551+ public: ed25519_dalek::PublicKey::from_bytes(public_key_bytes)
552+ .map_err(|err| Error::CryptoError(err.to_string()))?,
553+ secret: ed25519_dalek::SecretKey::from_bytes(private_key_bytes)
554+ .map_err(|err| Error::CryptoError(err.to_string()))?,
555+ },
556+ })
557+ }
558+ }
559+
560+ impl SigningKey for Ed25519Key {
561+ type Hasher = Sha256;
562+
563+ fn sign(&self, data: HashOutput) -> Result<Vec<u8>> {
564+ Ok(self.inner.sign(data.as_ref()).to_bytes().to_vec())
565+ }
566+
567+ fn algorithm(&self) -> Algorithm {
568+ Algorithm::Ed25519Sha256
569+ }
570+ }
571+
572+ pub(crate) struct RsaPublicKey {
573+ inner: rsa::RsaPublicKey,
574+ }
575+
576+ impl RsaPublicKey {
577+ pub(crate) fn verifying_key_from_bytes(
578+ bytes: &[u8],
579+ ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
580+ Ok(Box::new(RsaPublicKey {
581+ inner: <rsa::RsaPublicKey as rsa::pkcs8::DecodePublicKey>::from_public_key_der(bytes)
582+ .or_else(|_| rsa::pkcs1::DecodeRsaPublicKey::from_pkcs1_der(bytes))
583+ .map_err(|err| Error::CryptoError(err.to_string()))?,
584+ }))
585+ }
586+ }
587+
588+ impl VerifyingKey for RsaPublicKey {
589+ fn verify<'a>(
590+ &self,
591+ headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
592+ signature: &[u8],
593+ canonicalization: Canonicalization,
594+ algorithm: Algorithm,
595+ ) -> Result<()> {
596+ match algorithm {
597+ Algorithm::RsaSha256 => {
598+ let hash = canonicalization.hash_headers::<Sha256>(headers);
599+ self.inner
600+ .verify(
601+ PaddingScheme::new_pkcs1v15_sign::<sha2::Sha256>(),
602+ hash.as_ref(),
603+ signature,
604+ )
605+ .map_err(|_| Error::FailedVerification)
606+ }
607+ Algorithm::RsaSha1 => {
608+ let hash = canonicalization.hash_headers::<Sha1>(headers);
609+ self.inner
610+ .verify(
611+ PaddingScheme::new_pkcs1v15_sign::<sha1::Sha1>(),
612+ hash.as_ref(),
613+ signature,
614+ )
615+ .map_err(|_| Error::FailedVerification)
616+ }
617+ Algorithm::Ed25519Sha256 => Err(Error::IncompatibleAlgorithms),
618+ }
619+ }
620+ }
621+
622+ pub(crate) struct Ed25519PublicKey {
623+ inner: ed25519_dalek::PublicKey,
624+ }
625+
626+ impl Ed25519PublicKey {
627+ pub(crate) fn verifying_key_from_bytes(
628+ bytes: &[u8],
629+ ) -> Result<Box<dyn VerifyingKey + Send + Sync>> {
630+ Ok(Box::new(Ed25519PublicKey {
631+ inner: ed25519_dalek::PublicKey::from_bytes(bytes)
632+ .map_err(|err| Error::CryptoError(err.to_string()))?,
633+ }))
634+ }
635+ }
636+
637+ impl VerifyingKey for Ed25519PublicKey {
638+ fn verify<'a>(
639+ &self,
640+ headers: &mut dyn Iterator<Item = (&'a [u8], &'a [u8])>,
641+ signature: &[u8],
642+ canonicalization: Canonicalization,
643+ algorithm: Algorithm,
644+ ) -> Result<()> {
645+ if !matches!(algorithm, Algorithm::Ed25519Sha256) {
646+ return Err(Error::IncompatibleAlgorithms);
647+ }
648+
649+ let hash = canonicalization.hash_headers::<Sha256>(headers);
650+ self.inner
651+ .verify_strict(
652+ hash.as_ref(),
653+ &ed25519_dalek::Signature::from_bytes(signature)
654+ .map_err(|err| Error::CryptoError(err.to_string()))?,
655+ )
656+ .map_err(|_| Error::FailedVerification)
657+ }
658+ }
659+
660+ impl Writer for sha1::Sha1 {
661+ fn write(&mut self, buf: &[u8]) {
662+ self.update(buf);
663+ }
664+ }
665+
666+ impl Writer for sha2::Sha256 {
667+ fn write(&mut self, buf: &[u8]) {
668+ self.update(buf);
669+ }
670+ }
671+
672+ impl HashImpl for Sha1 {
673+ type Context = sha1::Sha1;
674+
675+ fn hasher() -> Self::Context {
676+ <Self::Context as Digest>::new()
677+ }
678+ }
679+
680+ impl HashImpl for Sha256 {
681+ type Context = sha2::Sha256;
682+
683+ fn hasher() -> Self::Context {
684+ <Self::Context as Digest>::new()
685+ }
686+ }
687+
688+ impl HashContext for sha1::Sha1 {
689+ fn finish(self) -> HashOutput {
690+ HashOutput::Sha1(self.finalize())
691+ }
692+ }
693+
694+ impl HashContext for sha2::Sha256 {
695+ fn finish(self) -> HashOutput {
696+ HashOutput::Sha256(self.finalize())
697+ }
698+ }