| Version | Supported |
|---|---|
| 1.0.x | ✅ |
Report any vulnerabilities by either emailing dwg@linuxprogrammer.org or redmike7@gmail.com. DO NOT file public issues in this repo.
This crate is std-only. It depends on std::collections::BTreeMap,
std::fmt, and unsigned-varint with the std feature. The crypto
dependency stack (RSA, SSH, BLS, hybrid KEMs, post-quantum signature
schemes) all require std. A full no_std conversion is infeasible given
the crypto dependency stack; this decision is final for the foreseeable
future.
This crate depends on the following release-candidate (RC) crates:
slh-dsa = "0.2.0-rc.5"— SLH-DSA post-quantum signaturesvsss-rs = "6.0.0-rc2"— verifiable secret sharing (transitive viablsful)blsful = "4.0.0-rc1"— BLS12-381 signature implementationssh-key = "0.7.0-rc.11"— SSH key/signature encoding
These are pinned to RC versions because stable releases are not yet
available. This is a tracked acceptance: the RC versions are reviewed
on each release and will be upgraded to stable when available. Consumers
should be aware that RC APIs may change before stabilisation. Coordinate
with multi-sig (which depends on the same blsful and ssh-key
versions) when upgrading.
This crate uses sad-rsa (0.2.3)
instead of the upstream rsa crate to mitigate RUSTSEC-2023-0071 (Marvin
Attack: potential key recovery through timing sidechannels).
sad-rsa is a hardened fork of rsa that implements implicit rejection
for PKCS#1 v1.5 decryption, making valid and invalid ciphertexts
indistinguishable to attackers. The API is fully compatible with rsa.
This crate uses RSA for:
- RSA key generation (
RsaPrivateKey::newfor 2048/3072/4096-bit keys) - PKCS#1 encoding (
pkcs1::EncodeRsaPrivateKey) - RSA-PSS signing and verification (
pss::SigningKey,pss::VerifyingKey) - RSA-OAEP encryption/decryption for hybrid key encapsulation
RSA key material is wrapped in Zeroizing<Vec<u8>> and zeroized on drop.
The Multikey comment field is stored as a plain String and is not
zeroized on drop. This is a deliberate design decision:
- Rationale: The comment is non-sensitive metadata (e.g. a key label
or human-readable description). Wrapping it in
Zeroizing<String>would require deref-coercion shims across ~120 call sites that read the comment, adding complexity and friction for no security benefit when the comment does not contain sensitive material. - Key material is zeroized: The actual key material in
attributesis wrapped inZeroizing<Vec<u8>>and is zeroized on drop. - Caller responsibility: If a caller places sensitive material in the comment field, they must zeroize that material themselves before it leaves scope. The crate does not assume the comment is sensitive.
The decoder enforces the following caps on untrusted wire data to mitigate CWE-400 (Uncontrolled Resource Consumption):
MAX_ATTRIBUTES = 256— maximum number of attributes perMultikey.MAX_DECODED_SIZE = 16 MiB— maximum total decoded bytes perMultikey. Tracked across the attribute decode loop.- Per-attribute
Varbytespayloads are individually capped bymulti_util::varbytes::MAX_DECODED_SIZE(16 MiB).
Exceeding any cap returns a clean Err (Error::TooManyAttributes or
Error::InputTooLarge); the decoder never panics on oversized input.
- No unsafe code:
#![deny(unsafe_code)]is enforced at compile time. - Key material zeroization: Private key bytes are wrapped in
Zeroizing<Vec<u8>>and zeroized on drop. - Constant-time comparison:
impl ConstantTimeEq for Multikeycompares the canonical wire encoding in constant time. Usemk.ct_eq(&other)in timing-sensitive contexts instead ofPartialEq.