diff options
author | Andrew Walbran <qwandor@google.com> | 2023-12-19 11:09:05 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2023-12-19 11:09:08 +0000 |
commit | 9bc766a361b49b1f1233e377b2bb4d9a35f2931c (patch) | |
tree | c6286d70a036ba58ba4bb3fba182d0356d44593b | |
parent | 37c55c3173284573756e6079eecd253a8e46563a (diff) | |
download | pkcs8-trusty-main.tar.gz |
Revert^2 "Merge branch 'tmp_auto_upgrade' into trusty-main"trusty-main
37c55c3173284573756e6079eecd253a8e46563a
Change-Id: I56aa1221004526482b516b5bfcd9f633ded18c89
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | Android.bp | 60 | ||||
-rw-r--r-- | CHANGELOG.md | 24 | ||||
-rw-r--r-- | Cargo.toml | 15 | ||||
-rw-r--r-- | Cargo.toml.orig | 15 | ||||
-rw-r--r-- | LICENSE-MIT | 25 | ||||
-rw-r--r-- | METADATA | 26 | ||||
-rw-r--r-- | OWNERS | 2 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | cargo2android.json | 9 | ||||
-rw-r--r-- | cargo2android_viz.bp | 6 | ||||
-rw-r--r-- | cargo2rulesmk.json | 3 | ||||
-rw-r--r-- | cargo_embargo.json | 34 | ||||
-rw-r--r-- | patches/rules.mk.diff | 14 | ||||
-rw-r--r-- | rules.mk | 2 | ||||
-rw-r--r-- | src/encrypted_private_key_info.rs | 33 | ||||
-rw-r--r-- | src/error.rs | 2 | ||||
-rw-r--r-- | src/lib.rs | 23 | ||||
-rw-r--r-- | src/private_key_info.rs | 74 | ||||
-rw-r--r-- | src/traits.rs | 27 | ||||
-rw-r--r-- | src/version.rs | 4 | ||||
-rw-r--r-- | tests/encrypted_private_key.rs | 4 | ||||
-rw-r--r-- | tests/private_key.rs | 15 | ||||
-rw-r--r-- | tests/traits.rs | 8 |
24 files changed, 292 insertions, 139 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 68186e0..d445424 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,6 +1,6 @@ { "git": { - "sha1": "974c2c7c88bc8d0541895a6e200c3ea9f91a33af" + "sha1": "7736dd21389b8820dfeb396e8c4c932de93d3ddf" }, "path_in_vcs": "pkcs8" }
\ No newline at end of file @@ -1,13 +1,41 @@ -// This file is generated by cargo2android.py --config cargo2android.json. +// This file is generated by cargo_embargo. // Do not modify this file as changes will be overridden on upgrade. +package { + default_applicable_licenses: ["external_rust_crates_pkcs8_license"], +} +// Added automatically by a large-scale-change that took the approach of +// 'apply every license found to every target'. While this makes sure we respect +// every license restriction, it may not be entirely correct. +// +// e.g. GPL in an MIT project might only apply to the contrib/ directory. +// +// Please consider splitting the single license below into multiple licenses, +// taking care not to lose any license_kind information, and overriding the +// default license using the 'licenses: [...]' property on targets as needed. +// +// For unused files, consider creating a 'fileGroup' with "//visibility:private" +// to attach the license to, and including a comment whether the files may be +// used in the current project. +// See: http://go/android-license-faq +license { + name: "external_rust_crates_pkcs8_license", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + "SPDX-license-identifier-MIT", + ], + license_text: [ + "LICENSE-APACHE", + ], +} rust_library_host { name: "libpkcs8", crate_name: "pkcs8", cargo_env_compat: true, - cargo_pkg_version: "0.9.0", + cargo_pkg_version: "0.10.2", srcs: ["src/lib.rs"], edition: "2021", features: ["alloc"], @@ -15,9 +43,37 @@ rust_library_host { "libder", "libspki", ], +} + +rust_library_rlib { + name: "libpkcs8_nostd", + crate_name: "pkcs8", + cargo_env_compat: true, + cargo_pkg_version: "0.10.2", + srcs: ["src/lib.rs"], + edition: "2021", + features: ["alloc"], + rustlibs: [ + "libder_nostd", + "libspki_nostd", + ], apex_available: [ "//apex_available:platform", "com.android.virt", ], + prefer_rlib: true, + no_stdlibs: true, + stdlibs: [ + "libcompiler_builtins.rust_sysroot", + "libcore.rust_sysroot", + ], + product_available: true, vendor_available: true, + visibility: [ + "//external/rust/crates/pkcs1:__subpackages__", + "//external/rust/crates/sec1:__subpackages__", + "//packages/modules/Virtualization:__subpackages__", + "//system/keymint:__subpackages__", + ], + } diff --git a/CHANGELOG.md b/CHANGELOG.md index 15889d9..1f754d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,30 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 0.10.2 (2023-04-04) +### Changed +- Bump `spki` to v0.7.1 ([#981]) + +[#981]: https://github.com/RustCrypto/formats/pull/981 + +## 0.10.1 (2023-03-05) +### Added +- `sha1-insecure` feature ([#913]) + +[#913]: https://github.com/RustCrypto/formats/pull/913 + +## 0.10.0 (2023-02-26) [YANKED] +### Changed +- Use blanket impls for `Decode*` traits ([#785]) +- Bump `der` dependency to v0.7 ([#899]) +- Bump `spki` dependency to v0.7 ([#900]) +- Bump `pkcs5` dependency to v0.7 ([#901]) + +[#785]: https://github.com/RustCrypto/formats/pull/785 +[#899]: https://github.com/RustCrypto/formats/pull/899 +[#900]: https://github.com/RustCrypto/formats/pull/900 +[#901]: https://github.com/RustCrypto/formats/pull/901 + ## 0.9.0 (2022-05-08) ### Added - Error conversion support to `pkcs8::spki::Error` ([#335]) @@ -11,9 +11,9 @@ [package] edition = "2021" -rust-version = "1.57" +rust-version = "1.65" name = "pkcs8" -version = "0.9.0" +version = "0.10.2" authors = ["RustCrypto Developers"] description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #8: @@ -36,7 +36,6 @@ categories = [ ] license = "Apache-2.0 OR MIT" repository = "https://github.com/RustCrypto/formats/tree/master/pkcs8" -resolver = "2" [package.metadata.docs.rs] all-features = true @@ -46,11 +45,11 @@ rustdoc-args = [ ] [dependencies.der] -version = "0.6" +version = "0.7" features = ["oid"] [dependencies.pkcs5] -version = "0.5" +version = "0.7" optional = true [dependencies.rand_core] @@ -59,7 +58,7 @@ optional = true default-features = false [dependencies.spki] -version = "0.6" +version = "0.7.1" [dependencies.subtle] version = "2" @@ -98,9 +97,9 @@ pem = [ "der/pem", "spki/pem", ] -sha1 = [ +sha1-insecure = [ "encryption", - "pkcs5/sha1", + "pkcs5/sha1-insecure", ] std = [ "alloc", diff --git a/Cargo.toml.orig b/Cargo.toml.orig index c5e821a..9ffae2b 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "pkcs8" -version = "0.9.0" # Also update html_root_url in lib.rs when bumping this +version = "0.10.2" description = """ Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #8: Private-Key Information Syntax Specification (RFC 5208), with additional @@ -13,15 +13,15 @@ categories = ["cryptography", "data-structures", "encoding", "no-std", "parser-i keywords = ["crypto", "key", "pkcs", "private"] readme = "README.md" edition = "2021" -rust-version = "1.57" +rust-version = "1.65" [dependencies] -der = { version = "0.6", features = ["oid"], path = "../der" } -spki = { version = "0.6", path = "../spki" } +der = { version = "0.7", features = ["oid"], path = "../der" } +spki = { version = "0.7.1", path = "../spki" } # optional dependencies rand_core = { version = "0.6", optional = true, default-features = false } -pkcs5 = { version = "0.5", optional = true, path = "../pkcs5" } +pkcs5 = { version = "0.7", optional = true, path = "../pkcs5" } subtle = { version = "2", optional = true, default-features = false } [dev-dependencies] @@ -30,13 +30,14 @@ tempfile = "3" [features] alloc = ["der/alloc", "der/zeroize", "spki/alloc"] +std = ["alloc", "der/std", "spki/std"] + 3des = ["encryption", "pkcs5/3des"] des-insecure = ["encryption", "pkcs5/des-insecure"] encryption = ["alloc", "pkcs5/alloc", "pkcs5/pbes2", "rand_core"] getrandom = ["rand_core/getrandom"] pem = ["alloc", "der/pem", "spki/pem"] -sha1 = ["encryption", "pkcs5/sha1"] -std = ["alloc", "der/std", "spki/std"] +sha1-insecure = ["encryption", "pkcs5/sha1-insecure"] [package.metadata.docs.rs] all-features = true diff --git a/LICENSE-MIT b/LICENSE-MIT new file mode 100644 index 0000000..e0d0827 --- /dev/null +++ b/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020-2023 The RustCrypto Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. @@ -1,20 +1,20 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/pkcs8 +# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md + name: "pkcs8" description: "Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #8: Private-Key Information Syntax Specification (RFC 5208)." third_party { - url { - type: HOMEPAGE - value: "https://crates.io/crates/pkcs8" - } - url { - type: ARCHIVE - value: "https://static.crates.io/crates/pkcs8/pkcs8-0.9.0.crate" - } - version: "0.9.0" - # Dual-licensed, using the least restrictive per go/thirdpartylicenses#same. license_type: NOTICE last_upgrade_date { - year: 2022 - month: 9 - day: 6 + year: 2023 + month: 12 + day: 15 + } + homepage: "https://crates.io/crates/pkcs8" + identifier { + type: "Archive" + value: "https://static.crates.io/crates/pkcs8/pkcs8-0.10.2.crate" + version: "0.10.2" } } @@ -1 +1 @@ -include platform/prebuilts/rust:master:/OWNERS +include platform/prebuilts/rust:main:/OWNERS @@ -54,7 +54,7 @@ algorithm, including the ones listed above or other algorithms. ## Minimum Supported Rust Version -This crate requires **Rust 1.57** at a minimum. +This crate requires **Rust 1.65** at a minimum. We may change the MSRV in the future, but it will be accompanied by a minor version bump. @@ -81,7 +81,7 @@ dual licensed as above, without any additional terms or conditions. [docs-image]: https://docs.rs/pkcs8/badge.svg [docs-link]: https://docs.rs/pkcs8/ [license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg -[rustc-image]: https://img.shields.io/badge/rustc-1.57+-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.65+-blue.svg [chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg [chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/300570-formats [build-image]: https://github.com/RustCrypto/formats/workflows/pkcs8/badge.svg?branch=master&event=push diff --git a/cargo2android.json b/cargo2android.json deleted file mode 100644 index e26e552..0000000 --- a/cargo2android.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "apex-available": [ - "//apex_available:platform", - "com.android.virt" - ], - "run": true, - "vendor-available": true, - "features": "alloc" -} diff --git a/cargo2android_viz.bp b/cargo2android_viz.bp new file mode 100644 index 0000000..b7d85b3 --- /dev/null +++ b/cargo2android_viz.bp @@ -0,0 +1,6 @@ +visibility: [ + "//external/rust/crates/pkcs1:__subpackages__", + "//external/rust/crates/sec1:__subpackages__", + "//packages/modules/Virtualization:__subpackages__", + "//system/keymint:__subpackages__", +] diff --git a/cargo2rulesmk.json b/cargo2rulesmk.json index 47578e1..4243146 100644 --- a/cargo2rulesmk.json +++ b/cargo2rulesmk.json @@ -1,3 +1,4 @@ { - "features": "alloc" + "features": "alloc", + "patch": "patches/rules.mk.diff" } diff --git a/cargo_embargo.json b/cargo_embargo.json new file mode 100644 index 0000000..9d1cec5 --- /dev/null +++ b/cargo_embargo.json @@ -0,0 +1,34 @@ +{ + "apex_available": [ + "//apex_available:platform", + "com.android.virt" + ], + "features": [ + "alloc" + ], + "run_cargo": false, + "variants": [ + { + "package": { + "pkcs8": { + "device_supported": false + } + } + }, + { + "module_name_overrides": { + "libder": "libder_nostd", + "libpkcs8": "libpkcs8_nostd", + "libspki": "libspki_nostd" + }, + "package": { + "pkcs8": { + "add_module_block": "cargo2android_viz.bp", + "force_rlib": true, + "host_supported": false, + "no_std": true + } + } + } + ] +} diff --git a/patches/rules.mk.diff b/patches/rules.mk.diff new file mode 100644 index 0000000..e489493 --- /dev/null +++ b/patches/rules.mk.diff @@ -0,0 +1,14 @@ +diff --git b/rules.mk a/rules.mk +index c7476cb..0257d05 100644 +--- b/rules.mk ++++ a/rules.mk +@@ -13,9 +13,6 @@ MODULE_RUSTFLAGS += \ + + MODULE_LIBRARY_DEPS := \ + external/rust/crates/der \ +- external/rust/crates/pkcs5 \ +- external/rust/crates/rand_core \ + external/rust/crates/spki \ +- external/rust/crates/subtle \ + + include make/library.mk @@ -1,4 +1,4 @@ -# This file is generated by cargo2rulesmk.py --run --config cargo2rulesmk.json --features . +# This file is generated by cargo2rulesmk.py --run --config cargo2rulesmk.json. # Do not modify this file as changes will be overridden on upgrade. LOCAL_DIR := $(GET_LOCAL_DIR) diff --git a/src/encrypted_private_key_info.rs b/src/encrypted_private_key_info.rs index 460e3f6..d55949c 100644 --- a/src/encrypted_private_key_info.rs +++ b/src/encrypted_private_key_info.rs @@ -2,7 +2,10 @@ use crate::{Error, Result}; use core::fmt; -use der::{asn1::OctetStringRef, Decode, DecodeValue, Encode, Header, Reader, Sequence}; +use der::{ + asn1::OctetStringRef, Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, + Sequence, Writer, +}; use pkcs5::EncryptionScheme; #[cfg(feature = "alloc")] @@ -36,7 +39,6 @@ use der::pem::PemLabel; /// ``` /// /// [RFC 5208 Section 6]: https://tools.ietf.org/html/rfc5208#section-6 -#[cfg_attr(docsrs, doc(cfg(feature = "pkcs5")))] #[derive(Clone, Eq, PartialEq)] pub struct EncryptedPrivateKeyInfo<'a> { /// Algorithm identifier describing a password-based symmetric encryption @@ -51,7 +53,6 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { /// Attempt to decrypt this encrypted private key using the provided /// password to derive an encryption key. #[cfg(feature = "encryption")] - #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] pub fn decrypt(&self, password: impl AsRef<[u8]>) -> Result<SecretDocument> { Ok(self .encryption_algorithm @@ -62,7 +63,6 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { /// Encrypt the given ASN.1 DER document using a symmetric encryption key /// derived from the provided password. #[cfg(feature = "encryption")] - #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] pub(crate) fn encrypt( mut rng: impl CryptoRng + RngCore, password: impl AsRef<[u8]>, @@ -81,7 +81,6 @@ impl<'a> EncryptedPrivateKeyInfo<'a> { /// Encrypt this private key using a symmetric encryption key derived /// from the provided password and [`pbes2::Parameters`]. #[cfg(feature = "encryption")] - #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] pub(crate) fn encrypt_with( pbes2_params: pbes2::Parameters<'a>, password: impl AsRef<[u8]>, @@ -111,18 +110,21 @@ impl<'a> DecodeValue<'a> for EncryptedPrivateKeyInfo<'a> { } } -impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> { - fn fields<F, T>(&self, f: F) -> der::Result<T> - where - F: FnOnce(&[&dyn Encode]) -> der::Result<T>, - { - f(&[ - &self.encryption_algorithm, - &OctetStringRef::new(self.encrypted_data)?, - ]) +impl EncodeValue for EncryptedPrivateKeyInfo<'_> { + fn value_len(&self) -> der::Result<Length> { + self.encryption_algorithm.encoded_len()? + + OctetStringRef::new(self.encrypted_data)?.encoded_len()? + } + + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { + self.encryption_algorithm.encode(writer)?; + OctetStringRef::new(self.encrypted_data)?.encode(writer)?; + Ok(()) } } +impl<'a> Sequence<'a> for EncryptedPrivateKeyInfo<'a> {} + impl<'a> TryFrom<&'a [u8]> for EncryptedPrivateKeyInfo<'a> { type Error = Error; @@ -140,7 +142,6 @@ impl<'a> fmt::Debug for EncryptedPrivateKeyInfo<'a> { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs5"))))] impl TryFrom<EncryptedPrivateKeyInfo<'_>> for SecretDocument { type Error = Error; @@ -150,7 +151,6 @@ impl TryFrom<EncryptedPrivateKeyInfo<'_>> for SecretDocument { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(all(feature = "alloc", feature = "pkcs5"))))] impl TryFrom<&EncryptedPrivateKeyInfo<'_>> for SecretDocument { type Error = Error; @@ -160,7 +160,6 @@ impl TryFrom<&EncryptedPrivateKeyInfo<'_>> for SecretDocument { } #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] impl PemLabel for EncryptedPrivateKeyInfo<'_> { const PEM_LABEL: &'static str = "ENCRYPTED PRIVATE KEY"; } diff --git a/src/error.rs b/src/error.rs index bc4c2ea..70c60ae 100644 --- a/src/error.rs +++ b/src/error.rs @@ -26,7 +26,7 @@ pub enum Error { /// or [`SubjectPublicKeyInfo::subject_public_key`][`crate::SubjectPublicKeyInfo::subject_public_key`]. KeyMalformed, - /// [`AlgorithmIdentifier::parameters`][`crate::AlgorithmIdentifier::parameters`] + /// [`AlgorithmIdentifier::parameters`][`crate::AlgorithmIdentifierRef::parameters`] /// is malformed or otherwise encoded in an unexpected manner. ParametersMalformed, @@ -1,13 +1,19 @@ #![no_std] -#![cfg_attr(docsrs, feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] #![doc = include_str!("../README.md")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg", - html_root_url = "https://docs.rs/pkcs8/0.9.0-pre" + html_logo_url = "https://raw.githubusercontent.com/RustCrypto/media/6ee8e381/logo.svg", + 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 )] -#![forbid(unsafe_code, clippy::unwrap_used)] -#![warn(missing_docs, rust_2018_idioms, unused_qualifications)] //! ## About this crate //! This library provides generalized PKCS#8 support designed to work with a @@ -88,7 +94,9 @@ pub use crate::{ version::Version, }; pub use der::{self, asn1::ObjectIdentifier, oid::AssociatedOid}; -pub use spki::{self, AlgorithmIdentifier, DecodePublicKey, SubjectPublicKeyInfo}; +pub use spki::{ + self, AlgorithmIdentifierRef, DecodePublicKey, SubjectPublicKeyInfo, SubjectPublicKeyInfoRef, +}; #[cfg(feature = "alloc")] pub use { @@ -98,7 +106,6 @@ pub use { }; #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] pub use der::pem::LineEnding; #[cfg(feature = "pkcs5")] diff --git a/src/private_key_info.rs b/src/private_key_info.rs index 52f0878..ecae624 100644 --- a/src/private_key_info.rs +++ b/src/private_key_info.rs @@ -1,10 +1,11 @@ //! PKCS#8 `PrivateKeyInfo`. -use crate::{AlgorithmIdentifier, Error, Result, Version}; +use crate::{AlgorithmIdentifierRef, Error, Result, Version}; use core::fmt; use der::{ asn1::{AnyRef, BitStringRef, ContextSpecific, OctetStringRef}, - Decode, DecodeValue, Encode, Header, Reader, Sequence, TagMode, TagNumber, + Decode, DecodeValue, Encode, EncodeValue, Header, Length, Reader, Sequence, TagMode, TagNumber, + Writer, }; #[cfg(feature = "alloc")] @@ -29,7 +30,7 @@ const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; /// PKCS#8 `PrivateKeyInfo`. /// -/// ASN.1 structure containing an [`AlgorithmIdentifier`], private key +/// ASN.1 structure containing an `AlgorithmIdentifier`, private key /// data in an algorithm specific format, and optional attributes /// (ignored by this implementation). /// @@ -90,8 +91,8 @@ const PUBLIC_KEY_TAG: TagNumber = TagNumber::N1; /// [RFC 5958 Section 2]: https://datatracker.ietf.org/doc/html/rfc5958#section-2 #[derive(Clone)] pub struct PrivateKeyInfo<'a> { - /// X.509 [`AlgorithmIdentifier`] for the private key type. - pub algorithm: AlgorithmIdentifier<'a>, + /// X.509 `AlgorithmIdentifier` for the private key type. + pub algorithm: AlgorithmIdentifierRef<'a>, /// Private key data. pub private_key: &'a [u8], @@ -105,7 +106,7 @@ impl<'a> PrivateKeyInfo<'a> { /// /// This is a helper method which initializes `attributes` and `public_key` /// to `None`, helpful if you aren't using those. - pub fn new(algorithm: AlgorithmIdentifier<'a>, private_key: &'a [u8]) -> Self { + pub fn new(algorithm: AlgorithmIdentifierRef<'a>, private_key: &'a [u8]) -> Self { Self { algorithm, private_key, @@ -134,28 +135,39 @@ impl<'a> PrivateKeyInfo<'a> { /// - p: 1 /// - Cipher: AES-256-CBC (best available option for PKCS#5 encryption) #[cfg(feature = "encryption")] - #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] pub fn encrypt( &self, rng: impl CryptoRng + RngCore, password: impl AsRef<[u8]>, ) -> Result<SecretDocument> { - let der = Zeroizing::new(self.to_vec()?); + let der = Zeroizing::new(self.to_der()?); EncryptedPrivateKeyInfo::encrypt(rng, password, der.as_ref()) } /// Encrypt this private key using a symmetric encryption key derived /// from the provided password and [`pbes2::Parameters`]. #[cfg(feature = "encryption")] - #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] pub fn encrypt_with_params( &self, pbes2_params: pbes2::Parameters<'_>, password: impl AsRef<[u8]>, ) -> Result<SecretDocument> { - let der = Zeroizing::new(self.to_vec()?); + let der = Zeroizing::new(self.to_der()?); EncryptedPrivateKeyInfo::encrypt_with(pbes2_params, password, der.as_ref()) } + + /// Get a `BIT STRING` representation of the public key, if present. + fn public_key_bit_string(&self) -> der::Result<Option<ContextSpecific<BitStringRef<'a>>>> { + self.public_key + .map(|pk| { + BitStringRef::from_bytes(pk).map(|value| ContextSpecific { + tag_number: PUBLIC_KEY_TAG, + tag_mode: TagMode::Implicit, + value, + }) + }) + .transpose() + } } impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { @@ -201,29 +213,25 @@ impl<'a> DecodeValue<'a> for PrivateKeyInfo<'a> { } } -impl<'a> Sequence<'a> for PrivateKeyInfo<'a> { - fn fields<F, T>(&self, f: F) -> der::Result<T> - where - F: FnOnce(&[&dyn Encode]) -> der::Result<T>, - { - f(&[ - &u8::from(self.version()), - &self.algorithm, - &OctetStringRef::new(self.private_key)?, - &self - .public_key - .map(|pk| { - BitStringRef::from_bytes(pk).map(|value| ContextSpecific { - tag_number: PUBLIC_KEY_TAG, - tag_mode: TagMode::Implicit, - value, - }) - }) - .transpose()?, - ]) +impl EncodeValue for PrivateKeyInfo<'_> { + fn value_len(&self) -> der::Result<Length> { + self.version().encoded_len()? + + self.algorithm.encoded_len()? + + OctetStringRef::new(self.private_key)?.encoded_len()? + + self.public_key_bit_string()?.encoded_len()? + } + + fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> { + self.version().encode(writer)?; + self.algorithm.encode(writer)?; + OctetStringRef::new(self.private_key)?.encode(writer)?; + self.public_key_bit_string()?.encode(writer)?; + Ok(()) } } +impl<'a> Sequence<'a> for PrivateKeyInfo<'a> {} + impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> { type Error = Error; @@ -243,7 +251,6 @@ impl<'a> fmt::Debug for PrivateKeyInfo<'a> { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] impl TryFrom<PrivateKeyInfo<'_>> for SecretDocument { type Error = Error; @@ -253,7 +260,6 @@ impl TryFrom<PrivateKeyInfo<'_>> for SecretDocument { } #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] impl TryFrom<&PrivateKeyInfo<'_>> for SecretDocument { type Error = Error; @@ -263,13 +269,11 @@ impl TryFrom<&PrivateKeyInfo<'_>> for SecretDocument { } #[cfg(feature = "pem")] -#[cfg_attr(docsrs, doc(cfg(feature = "pem")))] impl PemLabel for PrivateKeyInfo<'_> { const PEM_LABEL: &'static str = "PRIVATE KEY"; } #[cfg(feature = "subtle")] -#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] impl<'a> ConstantTimeEq for PrivateKeyInfo<'a> { fn ct_eq(&self, other: &Self) -> Choice { // NOTE: public fields are not compared in constant time @@ -281,11 +285,9 @@ impl<'a> ConstantTimeEq for PrivateKeyInfo<'a> { } #[cfg(feature = "subtle")] -#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] impl<'a> Eq for PrivateKeyInfo<'a> {} #[cfg(feature = "subtle")] -#[cfg_attr(docsrs, doc(cfg(feature = "subtle")))] impl<'a> PartialEq for PrivateKeyInfo<'a> { fn eq(&self, other: &Self) -> bool { self.ct_eq(other).into() diff --git a/src/traits.rs b/src/traits.rs index dd86b90..b4f80b2 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -21,17 +21,14 @@ use der::pem::PemLabel; use std::path::Path; /// Parse a private key object from a PKCS#8 encoded document. -pub trait DecodePrivateKey: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + Sized { +pub trait DecodePrivateKey: Sized { /// Deserialize PKCS#8 private key from ASN.1 DER-encoded data /// (binary format). - fn from_pkcs8_der(bytes: &[u8]) -> Result<Self> { - Self::try_from(PrivateKeyInfo::try_from(bytes)?) - } + fn from_pkcs8_der(bytes: &[u8]) -> Result<Self>; /// Deserialize encrypted PKCS#8 private key from ASN.1 DER-encoded data /// (binary format) and attempt to decrypt it using the provided password. #[cfg(feature = "encryption")] - #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] fn from_pkcs8_encrypted_der(bytes: &[u8], password: impl AsRef<[u8]>) -> Result<Self> { let doc = EncryptedPrivateKeyInfo::try_from(bytes)?.decrypt(password)?; Self::from_pkcs8_der(doc.as_bytes()) @@ -45,7 +42,6 @@ pub trait DecodePrivateKey: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + /// -----BEGIN PRIVATE KEY----- /// ``` #[cfg(feature = "pem")] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] fn from_pkcs8_pem(s: &str) -> Result<Self> { let (label, doc) = SecretDocument::from_pem(s)?; PrivateKeyInfo::validate_pem_label(label)?; @@ -61,7 +57,6 @@ pub trait DecodePrivateKey: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + /// -----BEGIN ENCRYPTED PRIVATE KEY----- /// ``` #[cfg(all(feature = "encryption", feature = "pem"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))] fn from_pkcs8_encrypted_pem(s: &str, password: impl AsRef<[u8]>) -> Result<Self> { let (label, doc) = SecretDocument::from_pem(s)?; EncryptedPrivateKeyInfo::validate_pem_label(label)?; @@ -71,15 +66,12 @@ pub trait DecodePrivateKey: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + /// Load PKCS#8 private key from an ASN.1 DER-encoded file on the local /// filesystem (binary format). #[cfg(feature = "std")] - #[cfg_attr(docsrs, doc(cfg(feature = "std")))] fn read_pkcs8_der_file(path: impl AsRef<Path>) -> Result<Self> { 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. #[cfg(all(feature = "pem", feature = "std"))] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] - #[cfg_attr(docsrs, doc(cfg(feature = "std")))] fn read_pkcs8_pem_file(path: impl AsRef<Path>) -> Result<Self> { let (label, doc) = SecretDocument::read_pem_file(path)?; PrivateKeyInfo::validate_pem_label(&label)?; @@ -87,9 +79,17 @@ pub trait DecodePrivateKey: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error> + } } +impl<T> DecodePrivateKey for T +where + T: for<'a> TryFrom<PrivateKeyInfo<'a>, Error = Error>, +{ + fn from_pkcs8_der(bytes: &[u8]) -> Result<Self> { + Self::try_from(PrivateKeyInfo::try_from(bytes)?) + } +} + /// Serialize a private key object to a PKCS#8 encoded document. #[cfg(feature = "alloc")] -#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub trait EncodePrivateKey { /// Serialize a [`SecretDocument`] containing a PKCS#8-encoded private key. fn to_pkcs8_der(&self) -> Result<SecretDocument>; @@ -97,7 +97,6 @@ pub trait EncodePrivateKey { /// Create an [`SecretDocument`] containing the ciphertext of /// a PKCS#8 encoded private key encrypted under the given `password`. #[cfg(feature = "encryption")] - #[cfg_attr(docsrs, doc(cfg(feature = "encryption")))] fn to_pkcs8_encrypted_der( &self, rng: impl CryptoRng + RngCore, @@ -108,7 +107,6 @@ pub trait EncodePrivateKey { /// Serialize this private key as PEM-encoded PKCS#8 with the given [`LineEnding`]. #[cfg(feature = "pem")] - #[cfg_attr(docsrs, doc(cfg(feature = "pem")))] fn to_pkcs8_pem(&self, line_ending: LineEnding) -> Result<Zeroizing<String>> { let doc = self.to_pkcs8_der()?; Ok(doc.to_pem(PrivateKeyInfo::PEM_LABEL, line_ending)?) @@ -117,7 +115,6 @@ pub trait EncodePrivateKey { /// Serialize this private key as an encrypted PEM-encoded PKCS#8 private /// key using the `provided` to derive an encryption key. #[cfg(all(feature = "encryption", feature = "pem"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "encryption", feature = "pem"))))] fn to_pkcs8_encrypted_pem( &self, rng: impl CryptoRng + RngCore, @@ -130,14 +127,12 @@ pub trait EncodePrivateKey { /// Write ASN.1 DER-encoded PKCS#8 private key to the given path #[cfg(feature = "std")] - #[cfg_attr(docsrs, doc(cfg(feature = "std")))] fn write_pkcs8_der_file(&self, path: impl AsRef<Path>) -> Result<()> { Ok(self.to_pkcs8_der()?.write_der_file(path)?) } /// Write ASN.1 DER-encoded PKCS#8 private key to the given path #[cfg(all(feature = "pem", feature = "std"))] - #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))] fn write_pkcs8_pem_file(&self, path: impl AsRef<Path>, line_ending: LineEnding) -> Result<()> { let doc = self.to_pkcs8_der()?; Ok(doc.write_pem_file(path, PrivateKeyInfo::PEM_LABEL, line_ending)?) diff --git a/src/version.rs b/src/version.rs index 3393683..0ca80bc 100644 --- a/src/version.rs +++ b/src/version.rs @@ -6,7 +6,7 @@ use der::{Decode, Encode, FixedTag, Reader, Tag, Writer}; /// Version identifier for PKCS#8 documents. /// /// (RFC 5958 designates `0` and `1` as the only valid versions for PKCS#8 documents) -#[derive(Clone, Debug, Copy, PartialEq)] +#[derive(Clone, Debug, Copy, PartialEq, Eq)] pub enum Version { /// Denotes PKCS#8 v1: no public key field. V1 = 0, @@ -36,7 +36,7 @@ impl Encode for Version { der::Length::from(1u8).for_tlv() } - fn encode(&self, writer: &mut dyn Writer) -> der::Result<()> { + fn encode(&self, writer: &mut impl Writer) -> der::Result<()> { u8::from(*self).encode(writer) } } diff --git a/tests/encrypted_private_key.rs b/tests/encrypted_private_key.rs index 2bd72ae..dbe0a18 100644 --- a/tests/encrypted_private_key.rs +++ b/tests/encrypted_private_key.rs @@ -183,7 +183,7 @@ fn encrypt_ed25519_der_encpriv_aes256_pbkdf2_sha256() { #[test] fn encrypt_ed25519_der_encpriv_aes256_scrypt() { let scrypt_params = pkcs5::pbes2::Parameters::scrypt_aes256cbc( - Default::default(), + pkcs5::scrypt::Params::new(15, 8, 1, 32).unwrap(), &hex!("E6211E2348AD69E0"), &hex!("9BD0A6251F2254F9FD5963887C27CF01"), ) @@ -203,7 +203,7 @@ fn encode_ed25519_encpriv_aes256_pbkdf2_sha256_der() { let pk = EncryptedPrivateKeyInfo::try_from(ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE).unwrap(); assert_eq!( ED25519_DER_AES256_PBKDF2_SHA256_EXAMPLE, - &pk.to_vec().unwrap() + &pk.to_der().unwrap() ); } diff --git a/tests/private_key.rs b/tests/private_key.rs index 15d6694..1ef0f73 100644 --- a/tests/private_key.rs +++ b/tests/private_key.rs @@ -1,5 +1,6 @@ //! PKCS#8 private key tests +use der::asn1::ObjectIdentifier; use hex_literal::hex; use pkcs8::{PrivateKeyInfo, Version}; @@ -48,7 +49,11 @@ fn decode_ec_p256_der() { assert_eq!(pk.algorithm.oid, "1.2.840.10045.2.1".parse().unwrap()); assert_eq!( - pk.algorithm.parameters.unwrap().oid().unwrap(), + pk.algorithm + .parameters + .unwrap() + .decode_as::<ObjectIdentifier>() + .unwrap(), "1.2.840.10045.3.1.7".parse().unwrap() ); @@ -124,7 +129,7 @@ fn decode_x25519_der() { #[cfg(feature = "alloc")] fn encode_ec_p256_der() { let pk = PrivateKeyInfo::try_from(EC_P256_DER_EXAMPLE).unwrap(); - let pk_encoded = pk.to_vec().unwrap(); + let pk_encoded = pk.to_der().unwrap(); assert_eq!(EC_P256_DER_EXAMPLE, pk_encoded); } @@ -132,14 +137,14 @@ fn encode_ec_p256_der() { #[cfg(feature = "alloc")] fn encode_ed25519_der_v1() { let pk = PrivateKeyInfo::try_from(ED25519_DER_V1_EXAMPLE).unwrap(); - assert_eq!(ED25519_DER_V1_EXAMPLE, pk.to_vec().unwrap()); + assert_eq!(ED25519_DER_V1_EXAMPLE, pk.to_der().unwrap()); } #[test] #[cfg(all(feature = "alloc", feature = "subtle"))] fn encode_ed25519_der_v2() { let private_key = PrivateKeyInfo::try_from(ED25519_DER_V2_EXAMPLE).unwrap(); - let private_der = private_key.to_vec().unwrap(); + let private_der = private_key.to_der().unwrap(); assert_eq!( private_key, PrivateKeyInfo::try_from(private_der.as_ref()).unwrap() @@ -150,7 +155,7 @@ fn encode_ed25519_der_v2() { #[cfg(feature = "alloc")] fn encode_rsa_2048_der() { let pk = PrivateKeyInfo::try_from(RSA_2048_DER_EXAMPLE).unwrap(); - assert_eq!(RSA_2048_DER_EXAMPLE, &pk.to_vec().unwrap()); + assert_eq!(RSA_2048_DER_EXAMPLE, &pk.to_der().unwrap()); } #[test] diff --git a/tests/traits.rs b/tests/traits.rs index 1c8a969..4a603bb 100644 --- a/tests/traits.rs +++ b/tests/traits.rs @@ -30,12 +30,6 @@ impl AsRef<[u8]> for MockKey { } } -impl DecodePrivateKey for MockKey { - fn from_pkcs8_der(bytes: &[u8]) -> Result<MockKey> { - Ok(MockKey(bytes.to_vec())) - } -} - impl EncodePrivateKey for MockKey { fn to_pkcs8_der(&self) -> Result<SecretDocument> { Ok(SecretDocument::try_from(self.as_ref())?) @@ -46,7 +40,7 @@ impl TryFrom<PrivateKeyInfo<'_>> for MockKey { type Error = Error; fn try_from(pkcs8: PrivateKeyInfo<'_>) -> Result<MockKey> { - Ok(MockKey(pkcs8.to_vec()?)) + Ok(MockKey(pkcs8.to_der()?)) } } |