From 5b1f2bc42019126be9166fc523dac493f99be1c8 Mon Sep 17 00:00:00 2001 From: Tony Arcieri Date: Sat, 25 Apr 2026 09:10:46 -0600 Subject: [PATCH] pkcs8: enable workspace-level lint config Applies the workspace-level `clippy` and other lints added in #2231, then fixes the lint failures. --- pkcs8/Cargo.toml | 4 +- pkcs8/src/encrypted_private_key_info.rs | 4 ++ pkcs8/src/lib.rs | 19 +++---- pkcs8/src/private_key_info.rs | 13 ++++- pkcs8/src/traits.rs | 70 ++++++++++++++++++++----- pkcs8/src/version.rs | 1 + pkcs8/tests/encrypted_private_key.rs | 4 +- pkcs8/tests/private_key.rs | 2 +- pkcs8/tests/traits.rs | 1 + 9 files changed, 87 insertions(+), 31 deletions(-) diff --git a/pkcs8/Cargo.toml b/pkcs8/Cargo.toml index 52507a1bc..c25127dec 100644 --- a/pkcs8/Cargo.toml +++ b/pkcs8/Cargo.toml @@ -39,6 +39,8 @@ encryption = ["alloc", "pkcs5/alloc", "pkcs5/pbes2", "rand_core"] pem = ["alloc", "der/pem", "spki/pem"] sha1-insecure = ["encryption", "pkcs5/sha1-insecure"] +[lints] +workspace = true + [package.metadata.docs.rs] all-features = true -rustdoc-args = ["--cfg", "docsrs"] diff --git a/pkcs8/src/encrypted_private_key_info.rs b/pkcs8/src/encrypted_private_key_info.rs index d3af77a84..0a7cd812e 100644 --- a/pkcs8/src/encrypted_private_key_info.rs +++ b/pkcs8/src/encrypted_private_key_info.rs @@ -53,6 +53,10 @@ where { /// Attempt to decrypt this encrypted private key using the provided /// password to derive an encryption key. + /// + /// # Errors + /// - Returns errors in the event the file could not be decrypted successfully. + /// - Returns errors if the file decrypted but the resulting plaintext failed to decode. #[cfg(feature = "encryption")] pub fn decrypt(&self, password: impl AsRef<[u8]>) -> Result { Ok(self diff --git a/pkcs8/src/lib.rs b/pkcs8/src/lib.rs index d8bf1ebd8..0ebde2cd0 100644 --- a/pkcs8/src/lib.rs +++ b/pkcs8/src/lib.rs @@ -6,14 +6,6 @@ html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg" )] #![forbid(unsafe_code)] -#![warn( - clippy::mod_module_files, - clippy::unwrap_used, - missing_docs, - rust_2018_idioms, - unused_lifetimes, - unused_qualifications -)] //! ## About this crate //! This library provides generalized PKCS#8 support designed to work with a @@ -54,15 +46,16 @@ //! private keys encrypted with DES-CBC and DES-EDE3-CBC (3DES or Triple DES) symmetric //! encryption, respectively. //! -//! ⚠️ WARNING ⚠️ +//!
+//! Security Warning //! -//! DES support (gated behind the `des-insecure` feature) is implemented to -//! allow for decryption of legacy PKCS#8 files only. +//! DES support (gated behind the `des-insecure` feature) is implemented to allow for decryption of +//! legacy PKCS#8 files only. //! -//! Such PKCS#8 documents should be considered *INSECURE* due to the short -//! 56-bit key size of DES. +//! Such PKCS#8 documents should be considered *INSECURE* due to the short 56-bit key size of DES. //! //! New keys should use AES instead. +//!
//! //! [RFC 5208]: https://tools.ietf.org/html/rfc5208 //! [RFC 5958]: https://tools.ietf.org/html/rfc5958 diff --git a/pkcs8/src/private_key_info.rs b/pkcs8/src/private_key_info.rs index 9ee713acb..6b68e3524 100644 --- a/pkcs8/src/private_key_info.rs +++ b/pkcs8/src/private_key_info.rs @@ -147,6 +147,10 @@ where /// - r: 8 /// - p: 1 /// - Cipher: AES-256-CBC (best available option for PKCS#5 encryption) + /// + /// # Errors + /// - Propagates errors from calling [`Encode::to_der`] on `Self`. + /// - Returns errors in the event encryption failed. #[cfg(feature = "encryption")] pub fn encrypt( &self, @@ -159,6 +163,10 @@ where /// Encrypt this private key using a symmetric encryption key derived /// from the provided password and [`pbes2::Parameters`]. + /// + /// # Errors + /// - Propagates errors from calling [`Encode::to_der`] on `Self`. + /// - Returns errors in the event encryption failed. #[cfg(feature = "encryption")] pub fn encrypt_with_params( &self, @@ -341,7 +349,7 @@ where self.algorithm == other.algorithm && self.public_key == other.public_key; self.private_key.as_ref().ct_eq(other.private_key.as_ref()) - & Choice::from(public_fields_eq as u8) + & Choice::from(u8::from(public_fields_eq)) } } @@ -373,9 +381,10 @@ pub type PrivateKeyInfoRef<'a> = PrivateKeyInfo, &'a OctetStringRef, #[cfg(feature = "alloc")] pub type PrivateKeyInfoOwned = PrivateKeyInfo; -/// [`BitStringLike`] marks object that will act like a BitString. +/// [`BitStringLike`] marks object that will act like a `BitString`. /// /// It will allow to get a [`BitStringRef`] that points back to the underlying bytes. +// TODO(tarcieri): replace this with `AsRef` when we can have `&BitStringRef`. pub trait BitStringLike { fn as_bit_string(&self) -> BitStringRef<'_>; } diff --git a/pkcs8/src/traits.rs b/pkcs8/src/traits.rs index 394089ee3..a0b6b71e0 100644 --- a/pkcs8/src/traits.rs +++ b/pkcs8/src/traits.rs @@ -23,12 +23,18 @@ use std::path::Path; /// Parse a private key object from a PKCS#8 encoded document. pub trait DecodePrivateKey: Sized { - /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data - /// (binary format). + /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data (binary format). + /// + /// # Errors + /// Returns format-specific errors in the event the document failed to parse. fn from_pkcs8_der(bytes: &[u8]) -> Result; - /// Deserialize encrypted PKCS#8 private key from ASN.1 DER-encoded data - /// (binary format) and attempt to decrypt it using the provided password. + /// Deserialize encrypted PKCS#8 private key from ASN.1 DER-encoded data (binary format) and + /// attempt to decrypt it using the provided password. + /// + /// # Errors + /// - Returns errors if the DER failed to decode + /// - Returns errors if the ciphertext failed to decrypt under the given password #[cfg(feature = "encryption")] fn from_pkcs8_encrypted_der(bytes: &[u8], password: impl AsRef<[u8]>) -> Result { let doc = EncryptedPrivateKeyInfoRef::try_from(bytes)?.decrypt(password)?; @@ -42,6 +48,10 @@ pub trait DecodePrivateKey: Sized { /// ```text /// -----BEGIN PRIVATE KEY----- /// ``` + /// + /// # Errors + /// - Returns [`Error::Asn1`] in the event of a decoding error (PEM or DER). + /// - Returns the same errors as [`DecodePrivateKey::from_pkcs8_der`]. #[cfg(feature = "pem")] fn from_pkcs8_pem(s: &str) -> Result { // Validate PEM label @@ -52,14 +62,18 @@ pub trait DecodePrivateKey: Sized { Self::from_pkcs8_der(doc.as_bytes()) } - /// Deserialize encrypted PKCS#8-encoded private key from PEM and attempt - /// to decrypt it using the provided password. + /// Deserialize encrypted PKCS#8-encoded private key from PEM and attempt to decrypt it using + /// the provided password. /// /// Keys in this format begin with the following delimiter: /// /// ```text /// -----BEGIN ENCRYPTED PRIVATE KEY----- /// ``` + /// + /// # Errors + /// - Returns [`Error::Asn1`] in the event of a decoding error (PEM or DER). + /// - Returns the same errors as [`DecodePrivateKey::from_pkcs8_encrypted_der`]. #[cfg(all(feature = "encryption", feature = "pem"))] fn from_pkcs8_encrypted_pem(s: &str, password: impl AsRef<[u8]>) -> Result { let (label, doc) = SecretDocument::from_pem(s)?; @@ -67,14 +81,23 @@ pub trait DecodePrivateKey: Sized { Self::from_pkcs8_encrypted_der(doc.as_bytes(), password) } - /// Load PKCS#8 private key from an ASN.1 DER-encoded file on the local - /// filesystem (binary format). + /// Load PKCS#8 private key from an ASN.1 DER-encoded file (binary format) on the local + /// filesystem. + /// + /// # Errors + /// - Returns the same errors as [`DecodePrivateKey::from_pkcs8_der`]. + /// - Returns errors in event the file cannot be read from the filesystem. #[cfg(feature = "std")] fn read_pkcs8_der_file(path: impl AsRef) -> Result { Self::from_pkcs8_der(SecretDocument::read_der_file(path)?.as_bytes()) } /// Load PKCS#8 private key from a PEM-encoded file on the local filesystem. + /// + /// # Errors + /// - Returns the same errors as [`SecretDocument::read_pem_file`]. + /// - Returns the same errors as [`DecodePrivateKey::from_pkcs8_der`]. + /// - Returns errors in event the file cannot be read from the filesystem. #[cfg(all(feature = "pem", feature = "std"))] fn read_pkcs8_pem_file(path: impl AsRef) -> Result { let (label, doc) = SecretDocument::read_pem_file(path)?; @@ -96,10 +119,17 @@ where #[cfg(feature = "alloc")] pub trait EncodePrivateKey { /// Serialize a [`SecretDocument`] containing a PKCS#8-encoded private key. + /// + /// # Errors + /// Returns format-specific errors in the event the document failed to serialize. fn to_pkcs8_der(&self) -> Result; - /// Create an [`SecretDocument`] containing the ciphertext of - /// a PKCS#8 encoded private key encrypted under the given `password`. + /// Create an [`SecretDocument`] containing the ciphertext of a PKCS#8 encoded private key + /// encrypted under the given `password`. + /// + /// # Errors + /// - Returns format-specific errors in the event the document failed to serialize. + /// - Returns algorithm-specific errors in the event the document couldn't be encrypted. #[cfg(feature = "encryption")] fn to_pkcs8_encrypted_der( &self, @@ -110,6 +140,10 @@ pub trait EncodePrivateKey { } /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`]. + /// + /// # Errors + /// - Returns the same errors as [`EncodePrivateKey::to_pkcs8_der`]. + /// - Returns the same errors as [`SecretDocument::to_pem`]. #[cfg(feature = "pem")] fn to_pkcs8_pem(&self, line_ending: LineEnding) -> Result> { let doc = self.to_pkcs8_der()?; @@ -118,6 +152,10 @@ pub trait EncodePrivateKey { /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private /// key using the `provided` to derive an encryption key. + /// + /// # Errors + /// - Returns the same errors as [`EncodePrivateKey::to_pkcs8_encrypted_der`]. + /// - Returns the same errors as [`SecretDocument::to_pem`]. #[cfg(all(feature = "encryption", feature = "pem"))] fn to_pkcs8_encrypted_pem( &self, @@ -129,13 +167,21 @@ pub trait EncodePrivateKey { Ok(doc.to_pem(EncryptedPrivateKeyInfoRef::PEM_LABEL, line_ending)?) } - /// Write ASN.1 DER-encoded PKCS#8 private key to the given path + /// Write ASN.1 DER-encoded PKCS#8 private key to the given path. + /// + /// # Errors + /// - Returns the same errors as [`EncodePrivateKey::to_pkcs8_der`]. + /// - Returns errors in the event the file could not be written to the filesystem. #[cfg(feature = "std")] fn write_pkcs8_der_file(&self, path: impl AsRef) -> Result<()> { Ok(self.to_pkcs8_der()?.write_der_file(path)?) } - /// Write ASN.1 PEM-encoded PKCS#8 private key to the given path + /// Write ASN.1 PEM-encoded PKCS#8 private key to the given path. + /// + /// # Errors + /// - Returns the same errors as [`EncodePrivateKey::to_pkcs8_der`]. + /// - Returns errors in the event the file could not be written to the filesystem. #[cfg(all(feature = "pem", feature = "std"))] fn write_pkcs8_pem_file(&self, path: impl AsRef, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs8_der()?; diff --git a/pkcs8/src/version.rs b/pkcs8/src/version.rs index d0d8745a5..ec2a4b21d 100644 --- a/pkcs8/src/version.rs +++ b/pkcs8/src/version.rs @@ -17,6 +17,7 @@ pub enum Version { impl Version { /// Is this version expected to have a public key? + #[must_use] pub fn has_public_key(self) -> bool { match self { Version::V1 => false, diff --git a/pkcs8/tests/encrypted_private_key.rs b/pkcs8/tests/encrypted_private_key.rs index cd5d06186..acd639c85 100644 --- a/pkcs8/tests/encrypted_private_key.rs +++ b/pkcs8/tests/encrypted_private_key.rs @@ -170,7 +170,7 @@ fn decrypt_ed25519_der_encpriv_aes256_scrypt() { #[cfg(feature = "encryption")] #[test] fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { - let pbes2_params = pkcs5::pbes2::Parameters::generate_pbkdf2_sha256_aes256cbc( + let pbes2_params = pbes2::Parameters::generate_pbkdf2_sha256_aes256cbc( 2048, &hex!("79d982e70df91a88"), hex!("b2d02d78b2efd9dff694cf8e0af40925"), @@ -191,7 +191,7 @@ fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { #[cfg(feature = "encryption")] #[test] fn encrypt_ed25519_der_encpriv_aes256_scrypt() { - let scrypt_params = pkcs5::pbes2::Parameters::generate_scrypt_aes256cbc( + let scrypt_params = pbes2::Parameters::generate_scrypt_aes256cbc( pkcs5::scrypt::Params::new(15, 8, 1).unwrap(), &hex!("E6211E2348AD69E0"), hex!("9BD0A6251F2254F9FD5963887C27CF01"), diff --git a/pkcs8/tests/private_key.rs b/pkcs8/tests/private_key.rs index 14e012b4e..b1e7f5d6c 100644 --- a/pkcs8/tests/private_key.rs +++ b/pkcs8/tests/private_key.rs @@ -99,7 +99,7 @@ fn decode_ec_bignp256_der() { "1F66B5B84B7339674533F0329C74F21834281FED0732429E0C79235FC273E269" )) .unwrap() - ) + ); } // Test vector from RFC8410 Section 10.3: diff --git a/pkcs8/tests/traits.rs b/pkcs8/tests/traits.rs index c9e63d124..191ce754d 100644 --- a/pkcs8/tests/traits.rs +++ b/pkcs8/tests/traits.rs @@ -22,6 +22,7 @@ const ED25519_DER_EXAMPLE: &[u8] = include_bytes!("examples/ed25519-priv-pkcs8v1 const ED25519_PEM_EXAMPLE: &str = include_str!("examples/ed25519-priv-pkcs8v1.pem"); /// Mock key type for testing trait impls against. +#[derive(Debug)] pub struct MockKey(Vec); impl AsRef<[u8]> for MockKey {