Skip to content

Commit d7315e4

Browse files
authored
Gate PKCS#1/PKCS#8 support on encoding feature (#537)
Support for these formats has a number of dependencies required, and isn't always necessary, e.g. the `ssh-key` crate implements an entirely different encoding format for RSA keys. Making support an optional feature avoids incurring these dependencies when that's the case. This commit also removes the `pem` feature and makes PEM support on-by-default whenever `encoding` is enabled. This only adds the `pem-rfc7468` dependency. Most users will probably want PEM support if they have the `encoding` feature enabled.
1 parent 34d5d46 commit d7315e4

20 files changed

+165
-107
lines changed

.github/workflows/workspace.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,4 +44,4 @@ jobs:
4444
- uses: Swatinem/rust-cache@v2
4545
- env:
4646
RUSTDOCFLAGS: "-Dwarnings --cfg docsrs"
47-
run: cargo doc --no-deps --features std,pem,serde,hazmat,sha2
47+
run: cargo doc --no-deps --features std,serde,hazmat,sha2

Cargo.toml

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,21 @@ readme = "README.md"
1313
rust-version = "1.85"
1414

1515
[dependencies]
16-
rand_core = { version = "0.9.0", default-features = false }
1716
const-oid = { version = "0.10.0", default-features = false }
18-
subtle = { version = "2.6.1", default-features = false }
17+
crypto-bigint = { version = "0.7.0-pre.5", default-features = false, features = ["zeroize", "alloc"] }
18+
crypto-primes = { version = "0.7.0-pre.1", default-features = false }
1919
digest = { version = "0.11.0-rc.0", default-features = false, features = ["alloc", "oid"] }
20-
pkcs1 = { version = "0.8.0-rc.2", default-features = false, features = ["alloc", "pkcs8"] }
21-
pkcs8 = { version = "0.11.0-rc.4", default-features = false, features = ["alloc"] }
20+
rand_core = { version = "0.9.0", default-features = false }
2221
signature = { version = "3.0.0-rc.1", default-features = false, features = ["alloc", "digest", "rand_core"] }
23-
spki = { version = "0.8.0-rc.2", default-features = false, features = ["alloc"] }
22+
subtle = { version = "2.6.1", default-features = false }
2423
zeroize = { version = "1.5", features = ["alloc"] }
25-
crypto-bigint = { version = "0.7.0-pre.5", default-features = false, features = ["zeroize", "alloc"] }
26-
crypto-primes = { version = "0.7.0-pre.1", default-features = false }
2724

2825
# optional dependencies
29-
sha1 = { version = "0.11.0-rc.0", optional = true, default-features = false, features = ["oid"] }
26+
pkcs1 = { version = "0.8.0-rc.2", optional = true, default-features = false, features = ["alloc", "pem", "pkcs8"] }
27+
pkcs8 = { version = "0.11.0-rc.4", optional = true, default-features = false, features = ["alloc", "pem"] }
3028
serdect = { version = "0.3.0", optional = true }
29+
sha1 = { version = "0.11.0-rc.0", optional = true, default-features = false, features = ["oid"] }
30+
spki = { version = "0.8.0-rc.2", optional = true, default-features = false, features = ["alloc"] }
3131
sha2 = { version = "0.11.0-rc.0", optional = true, default-features = false, features = ["oid"] }
3232
serde = { version = "1.0.184", optional = true, default-features = false, features = ["derive"] }
3333

@@ -51,15 +51,14 @@ serde = { version = "1.0.184", features = ["derive"] }
5151
name = "key"
5252

5353
[features]
54-
default = ["std", "pem"]
54+
default = ["std", "encoding"]
55+
encoding = ["dep:pkcs1", "dep:pkcs8", "dep:spki"]
5556
hazmat = []
5657
os_rng = ["rand_core/os_rng", "crypto-bigint/rand_core"]
57-
serde = ["dep:serde", "dep:serdect", "crypto-bigint/serde"]
58-
pem = ["pkcs1/pem", "pkcs8/pem"]
58+
serde = ["encoding", "dep:serde", "dep:serdect", "crypto-bigint/serde"]
5959
pkcs5 = ["pkcs8/encryption"]
6060
std = ["pkcs1/std", "pkcs8/std", "rand_core/std", "crypto-bigint/rand"]
6161

62-
6362
[package.metadata.docs.rs]
6463
features = ["std", "pem", "serde", "hazmat", "sha2"]
6564
rustdoc-args = ["--cfg", "docsrs"]

src/algorithms/pkcs1v15.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
//! [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
88
99
use alloc::vec::Vec;
10+
use const_oid::AssociatedOid;
1011
use digest::Digest;
11-
use pkcs8::AssociatedOid;
1212
use rand_core::TryCryptoRng;
1313
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
1414
use zeroize::Zeroizing;

src/encoding.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
//! Note: PKCS#1 support is achieved through a blanket impl of the
44
//! `pkcs1` crate's traits for types which impl the `pkcs8` crate's traits.
55
6+
#![cfg(feature = "encoding")]
7+
68
use crate::{
79
traits::{PrivateKeyParts, PublicKeyParts},
810
RsaPrivateKey, RsaPublicKey,
@@ -19,21 +21,19 @@ use zeroize::Zeroizing;
1921
pub const ID_RSASSA_PSS: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10");
2022

2123
/// Verify that the `AlgorithmIdentifier` for a key is correct.
22-
pub(crate) fn verify_algorithm_id(
23-
algorithm: &pkcs8::AlgorithmIdentifierRef,
24-
) -> pkcs8::spki::Result<()> {
24+
pub(crate) fn verify_algorithm_id(algorithm: &pkcs8::AlgorithmIdentifierRef) -> spki::Result<()> {
2525
match algorithm.oid {
2626
pkcs1::ALGORITHM_OID => {
2727
if algorithm.parameters_any()? != pkcs8::der::asn1::Null.into() {
28-
return Err(pkcs8::spki::Error::KeyMalformed);
28+
return Err(spki::Error::KeyMalformed);
2929
}
3030
}
3131
ID_RSASSA_PSS => {
3232
if algorithm.parameters.is_some() {
33-
return Err(pkcs8::spki::Error::KeyMalformed);
33+
return Err(spki::Error::KeyMalformed);
3434
}
3535
}
36-
_ => return Err(pkcs8::spki::Error::OidUnknown { oid: algorithm.oid }),
36+
_ => return Err(spki::Error::OidUnknown { oid: algorithm.oid }),
3737
};
3838

3939
Ok(())
@@ -76,10 +76,10 @@ impl TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for RsaPrivateKey {
7676
}
7777

7878
impl TryFrom<pkcs8::SubjectPublicKeyInfoRef<'_>> for RsaPublicKey {
79-
type Error = pkcs8::spki::Error;
79+
type Error = spki::Error;
8080

81-
fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> pkcs8::spki::Result<Self> {
82-
use pkcs8::spki::Error::KeyMalformed;
81+
fn try_from(spki: pkcs8::SubjectPublicKeyInfoRef<'_>) -> spki::Result<Self> {
82+
use spki::Error::KeyMalformed;
8383

8484
verify_algorithm_id(&spki.algorithm)?;
8585

@@ -156,7 +156,7 @@ impl EncodePrivateKey for RsaPrivateKey {
156156
}
157157

158158
impl EncodePublicKey for RsaPublicKey {
159-
fn to_public_key_der(&self) -> pkcs8::spki::Result<Document> {
159+
fn to_public_key_der(&self) -> spki::Result<Document> {
160160
let modulus = self.n().to_be_bytes();
161161
let public_exponent = self.e().to_be_bytes();
162162

src/errors.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ pub enum Error {
5050
PublicExponentTooLarge,
5151

5252
/// PKCS#1 error.
53+
#[cfg(feature = "encoding")]
5354
Pkcs1(pkcs1::Error),
5455

5556
/// PKCS#8 error.
57+
#[cfg(feature = "encoding")]
5658
Pkcs8(pkcs8::Error),
5759

5860
/// Internal error.
@@ -95,7 +97,9 @@ impl core::fmt::Display for Error {
9597
Error::ModulusTooLarge => write!(f, "modulus too large"),
9698
Error::PublicExponentTooSmall => write!(f, "public exponent too small"),
9799
Error::PublicExponentTooLarge => write!(f, "public exponent too large"),
100+
#[cfg(feature = "encoding")]
98101
Error::Pkcs1(err) => write!(f, "{}", err),
102+
#[cfg(feature = "encoding")]
99103
Error::Pkcs8(err) => write!(f, "{}", err),
100104
Error::Internal => write!(f, "internal error"),
101105
Error::LabelTooLong => write!(f, "label too long"),
@@ -107,12 +111,14 @@ impl core::fmt::Display for Error {
107111
}
108112
}
109113

114+
#[cfg(feature = "encoding")]
110115
impl From<pkcs1::Error> for Error {
111116
fn from(err: pkcs1::Error) -> Error {
112117
Error::Pkcs1(err)
113118
}
114119
}
115120

121+
#[cfg(feature = "encoding")]
116122
impl From<pkcs8::Error> for Error {
117123
fn from(err: pkcs8::Error) -> Error {
118124
Error::Pkcs8(err)

src/key.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -703,9 +703,11 @@ mod tests {
703703
use crate::traits::{PrivateKeyParts, PublicKeyParts};
704704

705705
use hex_literal::hex;
706-
use pkcs8::DecodePrivateKey;
707706
use rand_chacha::{rand_core::SeedableRng, ChaCha8Rng};
708707

708+
#[cfg(feature = "encoding")]
709+
use pkcs8::DecodePrivateKey;
710+
709711
#[test]
710712
fn test_from_into() {
711713
let raw_n = BoxedUint::from(101u64);
@@ -1014,6 +1016,7 @@ mod tests {
10141016
}
10151017

10161018
#[test]
1019+
#[cfg(feature = "encoding")]
10171020
fn build_key_from_primes() {
10181021
const RSA_2048_PRIV_DER: &[u8] = include_bytes!("../tests/examples/pkcs8/rsa2048-priv.der");
10191022
let ref_key = RsaPrivateKey::from_pkcs8_der(RSA_2048_PRIV_DER).unwrap();
@@ -1035,6 +1038,7 @@ mod tests {
10351038
}
10361039

10371040
#[test]
1041+
#[cfg(feature = "encoding")]
10381042
fn build_key_from_p_q() {
10391043
const RSA_2048_SP800_PRIV_DER: &[u8] =
10401044
include_bytes!("../tests/examples/pkcs8/rsa2048-sp800-56b-priv.der");

src/lib.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@
145145
//!
146146
//! ```
147147
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
148-
//! # #[cfg(all(feature = "pem", feature = "std"))]
148+
//! # #[cfg(all(feature = "encoding", feature = "std"))]
149149
//! # {
150150
//! use rsa::{RsaPublicKey, pkcs1::DecodeRsaPublicKey};
151151
//!
@@ -189,7 +189,7 @@
189189
//!
190190
//! ```
191191
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
192-
//! # #[cfg(all(feature = "pem", feature = "std"))]
192+
//! # #[cfg(all(feature = "encoding", feature = "std"))]
193193
//! # {
194194
//! use rsa::{RsaPublicKey, pkcs8::DecodePublicKey};
195195
//!
@@ -238,7 +238,9 @@ mod dummy_rng;
238238
mod encoding;
239239
mod key;
240240

241+
#[cfg(feature = "encoding")]
241242
pub use pkcs1;
243+
#[cfg(feature = "encoding")]
242244
pub use pkcs8;
243245
#[cfg(feature = "sha2")]
244246
pub use sha2;

src/pkcs1v15.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@ pub use self::{
1818
};
1919

2020
use alloc::{boxed::Box, vec::Vec};
21+
use const_oid::AssociatedOid;
2122
use core::fmt::Debug;
2223
use crypto_bigint::BoxedUint;
2324
use digest::Digest;
24-
use pkcs8::AssociatedOid;
2525
use rand_core::TryCryptoRng;
2626

2727
use crate::algorithms::pad::{uint_to_be_pad, uint_to_zeroizing_be_pad};

src/pkcs1v15/signature.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use signature::SignatureEncoding;
77

88
#[cfg(feature = "serde")]
99
use serdect::serde::{de, Deserialize, Serialize};
10+
#[cfg(feature = "encoding")]
1011
use spki::{
1112
der::{asn1::BitString, Result as DerResult},
1213
SignatureBitStringEncoding,
@@ -24,6 +25,7 @@ impl SignatureEncoding for Signature {
2425
type Repr = Box<[u8]>;
2526
}
2627

28+
#[cfg(feature = "encoding")]
2729
impl SignatureBitStringEncoding for Signature {
2830
fn to_bitstring(&self) -> DerResult<BitString> {
2931
BitString::new(0, self.to_vec())

src/pkcs1v15/signing_key.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,31 @@
1-
use super::{oid, pkcs1v15_generate_prefix, sign, Signature, VerifyingKey};
1+
use super::{pkcs1v15_generate_prefix, sign, Signature, VerifyingKey};
22
use crate::{dummy_rng::DummyRng, Result, RsaPrivateKey};
33
use alloc::vec::Vec;
4+
use const_oid::AssociatedOid;
45
use core::marker::PhantomData;
56
use digest::Digest;
6-
use pkcs8::{
7+
use rand_core::{CryptoRng, TryCryptoRng};
8+
use signature::{
9+
hazmat::PrehashSigner, DigestSigner, Keypair, MultipartSigner, RandomizedDigestSigner,
10+
RandomizedMultipartSigner, RandomizedSigner, Signer,
11+
};
12+
use zeroize::ZeroizeOnDrop;
13+
14+
#[cfg(feature = "encoding")]
15+
use {
16+
super::oid,
17+
pkcs8::{EncodePrivateKey, SecretDocument},
718
spki::{
819
der::AnyRef, AlgorithmIdentifierRef, AssociatedAlgorithmIdentifier,
920
SignatureAlgorithmIdentifier,
1021
},
11-
AssociatedOid, EncodePrivateKey, SecretDocument,
1222
};
13-
use rand_core::{CryptoRng, TryCryptoRng};
1423
#[cfg(feature = "serde")]
1524
use {
1625
pkcs8::DecodePrivateKey,
1726
serdect::serde::{de, ser, Deserialize, Serialize},
1827
};
1928

20-
use signature::{
21-
hazmat::PrehashSigner, DigestSigner, Keypair, MultipartSigner, RandomizedDigestSigner,
22-
RandomizedMultipartSigner, RandomizedSigner, Signer,
23-
};
24-
use zeroize::ZeroizeOnDrop;
25-
2629
/// Signing key for `RSASSA-PKCS1-v1_5` signatures as described in [RFC8017 § 8.2].
2730
///
2831
/// [RFC8017 § 8.2]: https://datatracker.ietf.org/doc/html/rfc8017#section-8.2
@@ -192,6 +195,7 @@ where
192195
}
193196
}
194197

198+
#[cfg(feature = "encoding")]
195199
impl<D> AssociatedAlgorithmIdentifier for SigningKey<D>
196200
where
197201
D: Digest,
@@ -201,6 +205,7 @@ where
201205
const ALGORITHM_IDENTIFIER: AlgorithmIdentifierRef<'static> = pkcs1::ALGORITHM_ID;
202206
}
203207

208+
#[cfg(feature = "encoding")]
204209
impl<D> EncodePrivateKey for SigningKey<D>
205210
where
206211
D: Digest,
@@ -243,6 +248,7 @@ where
243248
}
244249
}
245250

251+
#[cfg(feature = "encoding")]
246252
impl<D> SignatureAlgorithmIdentifier for SigningKey<D>
247253
where
248254
D: Digest + oid::RsaSignatureAssociatedOid,
@@ -256,6 +262,7 @@ where
256262
};
257263
}
258264

265+
#[cfg(feature = "encoding")]
259266
impl<D> TryFrom<pkcs8::PrivateKeyInfoRef<'_>> for SigningKey<D>
260267
where
261268
D: Digest + AssociatedOid,

0 commit comments

Comments
 (0)