Skip to content

Commit 5f319dd

Browse files
authored
spki: extract crate from pkcs8 (#261)
Extracts the core parts of the PKCS#8 crate which implement X.509 Subject Public Key Info (SPKI) into their own crate. The longer-term goal of this extraction is to be able to share SPKI-related types between the `pkcs8` crate and an X.509 crate.
1 parent 7b38a17 commit 5f319dd

23 files changed

+571
-210
lines changed

.github/workflows/pkcs8.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
- "const-oid/**"
88
- "der/**"
99
- "pkcs8/**"
10+
- "spki/**"
1011
- "Cargo.*"
1112
push:
1213
branches: master
@@ -25,7 +26,7 @@ jobs:
2526
strategy:
2627
matrix:
2728
rust:
28-
- 1.46.0 # MSRV
29+
- 1.47.0 # MSRV
2930
- stable
3031
target:
3132
- thumbv7em-none-eabi
@@ -47,7 +48,7 @@ jobs:
4748
strategy:
4849
matrix:
4950
rust:
50-
- 1.46.0 # MSRV
51+
- 1.47.0 # MSRV
5152
- stable
5253
steps:
5354
- uses: actions/checkout@v1

.github/workflows/spki.yml

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
name: spki
2+
3+
on:
4+
pull_request:
5+
paths:
6+
- "base64ct/**"
7+
- "const-oid/**"
8+
- "der/**"
9+
- "spki/**"
10+
- "Cargo.*"
11+
push:
12+
branches: master
13+
14+
defaults:
15+
run:
16+
working-directory: spki
17+
18+
env:
19+
CARGO_INCREMENTAL: 0
20+
RUSTFLAGS: "-Dwarnings"
21+
22+
jobs:
23+
build:
24+
runs-on: ubuntu-latest
25+
strategy:
26+
matrix:
27+
rust:
28+
- 1.47.0 # MSRV
29+
- stable
30+
target:
31+
- thumbv7em-none-eabi
32+
- wasm32-unknown-unknown
33+
steps:
34+
- uses: actions/checkout@v1
35+
- uses: actions-rs/toolchain@v1
36+
with:
37+
profile: minimal
38+
toolchain: ${{ matrix.rust }}
39+
target: ${{ matrix.target }}
40+
override: true
41+
- run: cargo build --release --target ${{ matrix.target }}
42+
43+
test:
44+
runs-on: ubuntu-latest
45+
strategy:
46+
matrix:
47+
rust:
48+
- 1.47.0 # MSRV
49+
- stable
50+
steps:
51+
- uses: actions/checkout@v1
52+
- uses: actions-rs/toolchain@v1
53+
with:
54+
profile: minimal
55+
toolchain: ${{ matrix.rust }}
56+
override: true
57+
- run: cargo test --release
58+
- run: cargo test --release --all-features

Cargo.lock

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@ members = [
1212
"der/derive",
1313
"hex-literal",
1414
"opaque-debug",
15-
"pkcs8"
15+
"pkcs8",
16+
"spki",
1617
]

der/src/asn1/generalized_time.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ impl Encodable for GeneralizedTime {
135135
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
136136
self.header().encode(encoder)?;
137137

138-
let datetime = DateTime::from_unix_duration(self.0).ok_or_else(|| ErrorKind::Value {
138+
let datetime = DateTime::from_unix_duration(self.0).ok_or(ErrorKind::Value {
139139
tag: Tag::GeneralizedTime,
140140
})?;
141141

der/src/asn1/utc_time.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,8 @@ impl Encodable for UtcTime {
133133
fn encode(&self, encoder: &mut Encoder<'_>) -> Result<()> {
134134
self.header().encode(encoder)?;
135135

136-
let datetime = DateTime::from_unix_duration(self.0)
137-
.ok_or_else(|| ErrorKind::Value { tag: Tag::UtcTime })?;
136+
let datetime =
137+
DateTime::from_unix_duration(self.0).ok_or(ErrorKind::Value { tag: Tag::UtcTime })?;
138138

139139
debug_assert!((1950..2050).contains(&datetime.year()));
140140
datetime::encode_decimal(encoder, Tag::UtcTime, datetime.year() - 1900)?;

pkcs8/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "pkcs8"
3-
version = "0.4.1" # Also update html_root_url in lib.rs when bumping this
3+
version = "0.5.0-pre" # Also update html_root_url in lib.rs when bumping this
44
description = """
55
Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #8:
66
Private-Key Information Syntax Specification (RFC 5208)
@@ -17,6 +17,7 @@ readme = "README.md"
1717
[dependencies]
1818
base64ct = { version = "0.2", optional = true, features = ["alloc"], path = "../base64ct" }
1919
der = { version = "0.2", features = ["oid"], path = "../der" }
20+
spki = { version = "0", path = "../spki" }
2021
zeroize = { version = "1", optional = true, default-features = false, features = ["alloc"] }
2122

2223
[dev-dependencies]

pkcs8/README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
[![Build Status][build-image]][build-link]
99

1010
Pure Rust implementation of Public-Key Cryptography Standards (PKCS) #8:
11-
Private-Key Information Syntax Specification (RFC 5208)
11+
Private-Key Information Syntax Specification ([RFC 5208]).
1212

1313
[Documentation][docs-link]
1414

@@ -34,8 +34,12 @@ dual licensed as above, without any additional terms or conditions.
3434
[docs-image]: https://docs.rs/pkcs8/badge.svg
3535
[docs-link]: https://docs.rs/pkcs8/
3636
[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg
37-
[rustc-image]: https://img.shields.io/badge/rustc-1.46+-blue.svg
37+
[rustc-image]: https://img.shields.io/badge/rustc-1.47+-blue.svg
3838
[chat-image]: https://img.shields.io/badge/zulip-join_chat-blue.svg
3939
[chat-link]: https://rustcrypto.zulipchat.com/#narrow/stream/260052-utils
4040
[build-image]: https://github.com/RustCrypto/utils/workflows/pkcs8/badge.svg?branch=master&event=push
4141
[build-link]: https://github.com/RustCrypto/utils/actions
42+
43+
[//]: # (general links)
44+
45+
[RFC 5208]: https://tools.ietf.org/html/rfc5208

pkcs8/src/document.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
//! PKCS#8 documents: serialized PKCS#8 private keys and SPKI public keys
22
// TODO(tarcieri): heapless support?
33

4-
use crate::{Error, PrivateKeyInfo, Result, SubjectPublicKeyInfo};
4+
use crate::{error, Error, PrivateKeyInfo, Result, SubjectPublicKeyInfo};
55
use alloc::{borrow::ToOwned, vec::Vec};
66
use core::{
77
convert::{TryFrom, TryInto},
88
fmt,
99
};
10+
use der::Encodable;
1011
use zeroize::{Zeroize, Zeroizing};
1112

1213
#[cfg(feature = "std")]
@@ -86,7 +87,7 @@ impl PrivateKeyDocument {
8687

8788
/// Parse the [`PrivateKeyInfo`] contained in this [`PrivateKeyDocument`]
8889
pub fn private_key_info(&self) -> PrivateKeyInfo<'_> {
89-
PrivateKeyInfo::from_der(self.0.as_ref()).expect("constructor failed to validate document")
90+
PrivateKeyInfo::try_from(self.0.as_ref()).expect("constructor failed to validate document")
9091
}
9192
}
9293

@@ -96,12 +97,28 @@ impl AsRef<[u8]> for PrivateKeyDocument {
9697
}
9798
}
9899

100+
impl From<PrivateKeyInfo<'_>> for PrivateKeyDocument {
101+
fn from(private_key_info: PrivateKeyInfo<'_>) -> PrivateKeyDocument {
102+
PrivateKeyDocument::from(&private_key_info)
103+
}
104+
}
105+
106+
impl From<&PrivateKeyInfo<'_>> for PrivateKeyDocument {
107+
fn from(private_key_info: &PrivateKeyInfo<'_>) -> PrivateKeyDocument {
108+
private_key_info
109+
.to_vec()
110+
.ok()
111+
.and_then(|buf| buf.try_into().ok())
112+
.expect(error::DER_ENCODING_MSG)
113+
}
114+
}
115+
99116
impl TryFrom<&[u8]> for PrivateKeyDocument {
100117
type Error = Error;
101118

102119
fn try_from(bytes: &[u8]) -> Result<Self> {
103120
// Ensure document is well-formed
104-
PrivateKeyInfo::from_der(bytes)?;
121+
PrivateKeyInfo::try_from(bytes)?;
105122
Ok(Self(Zeroizing::new(bytes.to_owned())))
106123
}
107124
}
@@ -111,7 +128,7 @@ impl TryFrom<Vec<u8>> for PrivateKeyDocument {
111128

112129
fn try_from(mut bytes: Vec<u8>) -> Result<Self> {
113130
// Ensure document is well-formed
114-
if PrivateKeyInfo::from_der(&bytes).is_ok() {
131+
if PrivateKeyInfo::try_from(bytes.as_slice()).is_ok() {
115132
Ok(Self(Zeroizing::new(bytes)))
116133
} else {
117134
bytes.zeroize();
@@ -210,7 +227,7 @@ impl PublicKeyDocument {
210227

211228
/// Parse the [`SubjectPublicKeyInfo`] contained in this [`PublicKeyDocument`]
212229
pub fn spki(&self) -> SubjectPublicKeyInfo<'_> {
213-
SubjectPublicKeyInfo::from_der(self.0.as_ref())
230+
SubjectPublicKeyInfo::try_from(self.0.as_slice())
214231
.expect("constructor failed to validate document")
215232
}
216233
}
@@ -221,12 +238,27 @@ impl AsRef<[u8]> for PublicKeyDocument {
221238
}
222239
}
223240

241+
impl From<SubjectPublicKeyInfo<'_>> for PublicKeyDocument {
242+
fn from(spki: SubjectPublicKeyInfo<'_>) -> PublicKeyDocument {
243+
PublicKeyDocument::from(&spki)
244+
}
245+
}
246+
247+
impl From<&SubjectPublicKeyInfo<'_>> for PublicKeyDocument {
248+
fn from(spki: &SubjectPublicKeyInfo<'_>) -> PublicKeyDocument {
249+
spki.to_vec()
250+
.ok()
251+
.and_then(|buf| buf.try_into().ok())
252+
.expect(error::DER_ENCODING_MSG)
253+
}
254+
}
255+
224256
impl TryFrom<&[u8]> for PublicKeyDocument {
225257
type Error = Error;
226258

227259
fn try_from(bytes: &[u8]) -> Result<Self> {
228260
// Ensure document is well-formed
229-
SubjectPublicKeyInfo::from_der(bytes)?;
261+
SubjectPublicKeyInfo::try_from(bytes)?;
230262
Ok(Self(bytes.to_owned()))
231263
}
232264
}
@@ -236,7 +268,7 @@ impl TryFrom<Vec<u8>> for PublicKeyDocument {
236268

237269
fn try_from(bytes: Vec<u8>) -> Result<Self> {
238270
// Ensure document is well-formed
239-
SubjectPublicKeyInfo::from_der(&bytes)?;
271+
SubjectPublicKeyInfo::try_from(bytes.as_slice())?;
240272
Ok(Self(bytes))
241273
}
242274
}

pkcs8/src/lib.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
//! of a heap:
99
//!
1010
//! - [`PrivateKeyInfo`]: algorithm identifier and data representing a private key.
11-
//! - [`SubjectPublicKeyInfo`]: algorithm identifier and data representing a public key.
11+
//! - [`SubjectPublicKeyInfo`]: algorithm identifier and data representing a public key
12+
//! (re-exported from the [`spki`] crate)
1213
//!
1314
//! When the `alloc` feature is enabled, the following additional types are
1415
//! available which provide more convenient decoding/encoding support:
@@ -35,7 +36,7 @@
3536
//!
3637
//! # Minimum Supported Rust Version
3738
//!
38-
//! This crate requires **Rust 1.46** at a minimum.
39+
//! This crate requires **Rust 1.47** at a minimum.
3940
//!
4041
//! [RFC 5208]: https://tools.ietf.org/html/rfc5208
4142
@@ -44,7 +45,7 @@
4445
#![doc(
4546
html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
4647
html_favicon_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg",
47-
html_root_url = "https://docs.rs/pkcs8/0.4.1"
48+
html_root_url = "https://docs.rs/pkcs8/0.5.0-pre"
4849
)]
4950
#![forbid(unsafe_code)]
5051
#![warn(missing_docs, rust_2018_idioms)]
@@ -55,10 +56,8 @@ extern crate alloc;
5556
#[cfg(feature = "std")]
5657
extern crate std;
5758

58-
mod algorithm;
5959
mod error;
6060
mod private_key_info;
61-
mod spki;
6261
mod traits;
6362

6463
#[cfg(feature = "alloc")]
@@ -68,13 +67,12 @@ mod document;
6867
mod pem;
6968

7069
pub use crate::{
71-
algorithm::{AlgorithmIdentifier, AlgorithmParameters},
7270
error::{Error, Result},
7371
private_key_info::PrivateKeyInfo,
74-
spki::SubjectPublicKeyInfo,
7572
traits::{FromPrivateKey, FromPublicKey},
7673
};
7774
pub use der::{self, ObjectIdentifier};
75+
pub use spki::{AlgorithmIdentifier, AlgorithmParameters, SubjectPublicKeyInfo};
7876

7977
#[cfg(feature = "alloc")]
8078
pub use crate::{

pkcs8/src/private_key_info.rs

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -49,17 +49,6 @@ pub struct PrivateKeyInfo<'a> {
4949
}
5050

5151
impl<'a> PrivateKeyInfo<'a> {
52-
/// Parse [`PrivateKeyInfo`] encoded as ASN.1 DER.
53-
pub fn from_der(bytes: &'a [u8]) -> Result<Self> {
54-
Ok(Self::from_bytes(bytes)?)
55-
}
56-
57-
/// Write ASN.1 DER-encoded [`PrivateKeyInfo`] to the provided
58-
/// buffer, returning a slice containing the encoded data.
59-
pub fn write_der<'b>(&self, buffer: &'b mut [u8]) -> Result<&'b [u8]> {
60-
Ok(self.encode_to_slice(buffer)?)
61-
}
62-
6352
/// Encode this [`PrivateKeyInfo`] as ASN.1 DER.
6453
#[cfg(feature = "alloc")]
6554
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
@@ -84,7 +73,7 @@ impl<'a> TryFrom<&'a [u8]> for PrivateKeyInfo<'a> {
8473
type Error = Error;
8574

8675
fn try_from(bytes: &'a [u8]) -> Result<Self> {
87-
Self::from_der(bytes)
76+
Ok(Self::from_bytes(bytes)?)
8877
}
8978
}
9079

0 commit comments

Comments
 (0)