smime_tree/lib.rs
1//! S/MIME sign, verify, encrypt, and decrypt via caller-provided key traits.
2//!
3//! # Quick start
4//!
5//! ```rust,ignore
6//! use smime_tree::{sign, verify, encrypt, decrypt};
7//! use smime_tree::{SigningKey, DecryptionKey, NoRevocationCheck};
8//! use x509_cert::Certificate;
9//! use std::time::SystemTime;
10//!
11//! // Sign a MIME body part.
12//! // key implements SigningKey; returns multipart/signed bytes.
13//! let signed = sign(content_mime, &[&key], SystemTime::now()).expect("sign failed");
14//!
15//! // Verify a multipart/signed message.
16//! // signed_content: exact bytes of the signed part (from mime-tree byte ranges).
17//! // signature_der: DER of the application/pkcs7-signature part (base64-decoded).
18//! let result = verify(&signed_content, &signature_der, &trust_anchors,
19//! SystemTime::now(), &NoRevocationCheck)
20//! .expect("verify failed");
21//! assert!(result.is_verified());
22//!
23//! // Encrypt a MIME body part to one or more recipient certificates.
24//! let encrypted = encrypt(inner_mime, &recipient_certs).expect("encrypt failed");
25//!
26//! // Decrypt an enveloped-data blob.
27//! // key implements DecryptionKey; returns inner plaintext bytes.
28//! let plaintext = decrypt(&enveloped_der, &key).expect("decrypt failed");
29//! ```
30//!
31//! # Design
32//!
33//! - **Trait-based keys**: [`SigningKey`] and [`DecryptionKey`] abstract over key
34//! location — in-memory, HSM, or hardware token — without the crate needing to
35//! know the difference.
36//! - **No network calls**: certificate chain validation uses a trust store supplied
37//! by the caller. [`RevocationChecker`] is an injected trait; use
38//! [`NoRevocationCheck`] to skip OCSP/CRL.
39//! - **No async**: all operations are synchronous.
40//! - **Supported algorithms**:
41//! - Sign/verify: RSA PKCS#1 v1.5 (SHA-256/384/512); ECDSA P-256 (SHA-256 only), P-384 (SHA-384 only). P-521 is not supported.
42//! - Encrypt: AES-128-GCM (RSA/P-256 recipients), AES-256-GCM (P-384 recipients) via `AuthEnvelopedData` (RFC 5083).
43//! - Decrypt: AES-128/256-GCM (`AuthEnvelopedData`) and AES-128/256-CBC (`EnvelopedData`, legacy).
44//! - Key transport: RSA PKCS#1 v1.5 (`KeyTransRecipientInfo`).
45//! - Key agreement: ECDH P-256 + AES-128-KW, ECDH P-384 + AES-256-KW (`KeyAgreeRecipientInfo`).
46//!
47//! # Known Limitations
48//!
49//! * **AES-CBC decryption (legacy) is unauthenticated.** `decrypt()` accepts
50//! both `AuthEnvelopedData` (AES-GCM, authenticated) and `EnvelopedData`
51//! (AES-CBC, unauthenticated). The CBC path is retained for interoperability
52//! with existing S/MIME deployments but exposes callers to padding oracle and
53//! EFAIL-class (CVE-2017-17688) risks. See the [`decrypt`] function-level docs
54//! for mitigation guidance.
55//! * **RSA-PSS signatures are not supported** for certificate chain validation.
56//! Real-world S/MIME CAs overwhelmingly use RSA-PKCS1v15 or ECDSA; RSA-PSS CA
57//! signatures are rare in practice. File an issue if you need it.
58//! * **RSA key transport uses PKCS#1 v1.5** (`ktri`), not RSAES-OAEP. PKCS#1 v1.5 is
59//! deprecated by RFC 8017 in favour of OAEP and is susceptible to Bleichenbacher
60//! padding oracle attacks in interactive decryption scenarios.
61
62mod cert;
63mod decrypt;
64mod encrypt;
65mod error;
66mod key;
67mod sig_verify;
68mod sign;
69mod verify;
70
71pub use decrypt::decrypt;
72pub use encrypt::encrypt;
73pub use error::{CertChainError, SignerResult, SmimeError, VerificationResult};
74pub use key::{
75 DecryptionKey, DigestAlgorithm, EcCurve, KariAlgorithm, KariKeyAgreement,
76 KeyEncryptionAlgorithm, KeyWrapAlgorithm, NoRevocationCheck, RecipientIdentifier,
77 RevocationChecker, SigningKey,
78};
79pub use sign::sign;
80pub use verify::verify;