Skip to content

Commit 01dd38c

Browse files
balootarcieri
andauthored
spki: make SubjectPublicKeyInfo own the public key (#790)
Co-authored-by: Tony Arcieri <[email protected]>
1 parent ab9a848 commit 01dd38c

File tree

11 files changed

+114
-70
lines changed

11 files changed

+114
-70
lines changed

pkcs1/src/traits.rs

+9-6
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@ use {
1616
};
1717

1818
#[cfg(feature = "pkcs8")]
19-
use crate::{ALGORITHM_ID, ALGORITHM_OID};
19+
use {
20+
crate::{ALGORITHM_ID, ALGORITHM_OID},
21+
der::asn1::BitStringRef,
22+
};
2023

2124
#[cfg(feature = "std")]
2225
use std::path::Path;
@@ -186,12 +189,12 @@ where
186189
#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
187190
impl<T: pkcs8::DecodePublicKey> DecodeRsaPublicKey for T
188191
where
189-
T: for<'a> TryFrom<pkcs8::SubjectPublicKeyInfo<'a>, Error = pkcs8::Error>,
192+
T: for<'a> TryFrom<pkcs8::SubjectPublicKeyInfoRef<'a>, Error = pkcs8::Error>,
190193
{
191194
fn from_pkcs1_der(public_key: &[u8]) -> Result<Self> {
192-
Ok(Self::try_from(pkcs8::SubjectPublicKeyInfo {
195+
Ok(Self::try_from(pkcs8::SubjectPublicKeyInfoRef {
193196
algorithm: ALGORITHM_ID,
194-
subject_public_key: public_key,
197+
subject_public_key: BitStringRef::from_bytes(public_key)?,
195198
})?)
196199
}
197200
}
@@ -212,8 +215,8 @@ impl<T: pkcs8::EncodePrivateKey> EncodeRsaPrivateKey for T {
212215
impl<T: pkcs8::EncodePublicKey> EncodeRsaPublicKey for T {
213216
fn to_pkcs1_der(&self) -> Result<Document> {
214217
let doc = self.to_public_key_der()?;
215-
let spki = pkcs8::SubjectPublicKeyInfo::from_der(doc.as_bytes())?;
218+
let spki = pkcs8::SubjectPublicKeyInfoRef::from_der(doc.as_bytes())?;
216219
spki.algorithm.assert_algorithm_oid(ALGORITHM_OID)?;
217-
RsaPublicKey::from_der(spki.subject_public_key)?.try_into()
220+
RsaPublicKey::from_der(spki.subject_public_key.raw_bytes())?.try_into()
218221
}
219222
}

pkcs8/src/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ pub use crate::{
8383
version::Version,
8484
};
8585
pub use der::{self, asn1::ObjectIdentifier, oid::AssociatedOid};
86-
pub use spki::{self, AlgorithmIdentifierRef, DecodePublicKey, SubjectPublicKeyInfo};
86+
pub use spki::{
87+
self, AlgorithmIdentifierRef, DecodePublicKey, SubjectPublicKeyInfo, SubjectPublicKeyInfoRef,
88+
};
8789

8890
#[cfg(feature = "alloc")]
8991
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]

spki/src/lib.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -43,13 +43,16 @@ mod fingerprint;
4343
pub use crate::{
4444
algorithm::{AlgorithmIdentifier, AlgorithmIdentifierRef},
4545
error::{Error, Result},
46-
spki::SubjectPublicKeyInfo,
46+
spki::{SubjectPublicKeyInfo, SubjectPublicKeyInfoRef},
4747
traits::DecodePublicKey,
4848
};
4949
pub use der::{self, asn1::ObjectIdentifier};
5050

5151
#[cfg(feature = "alloc")]
52-
pub use {crate::traits::EncodePublicKey, der::Document};
52+
pub use {
53+
crate::{spki::SubjectPublicKeyInfoOwned, traits::EncodePublicKey},
54+
der::Document,
55+
};
5356

5457
#[cfg(feature = "fingerprint")]
5558
pub use crate::fingerprint::FingerprintBytes;

spki/src/spki.rs

+62-29
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,30 @@
11
//! X.509 `SubjectPublicKeyInfo`
22
3-
use crate::{AlgorithmIdentifierRef, Error, Result};
3+
use crate::{AlgorithmIdentifier, Error, Result};
44
use core::cmp::Ordering;
55
use der::{
6-
asn1::BitStringRef, Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd,
6+
asn1::{AnyRef, BitStringRef},
7+
Choice, Decode, DecodeValue, DerOrd, Encode, FixedTag, Header, Reader, Sequence, ValueOrd,
78
};
89

910
#[cfg(feature = "alloc")]
10-
use der::Document;
11+
use der::{
12+
asn1::{Any, BitString},
13+
Document,
14+
};
1115

1216
#[cfg(feature = "fingerprint")]
1317
use crate::{fingerprint, FingerprintBytes};
1418

1519
#[cfg(feature = "pem")]
1620
use der::pem::PemLabel;
1721

18-
#[cfg(doc)]
19-
use crate::AlgorithmIdentifier;
22+
/// [`SubjectPublicKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BitStringRef`] params.
23+
pub type SubjectPublicKeyInfoRef<'a> = SubjectPublicKeyInfo<AnyRef<'a>, BitStringRef<'a>>;
24+
25+
/// [`SubjectPublicKeyInfo`] with [`Any`] algorithm parameters, and [`BitString`] params.
26+
#[cfg(feature = "alloc")]
27+
pub type SubjectPublicKeyInfoOwned = SubjectPublicKeyInfo<Any, BitString>;
2028

2129
/// X.509 `SubjectPublicKeyInfo` (SPKI) as defined in [RFC 5280 § 4.1.2.7].
2230
///
@@ -30,16 +38,22 @@ use crate::AlgorithmIdentifier;
3038
/// ```
3139
///
3240
/// [RFC 5280 § 4.1.2.7]: https://tools.ietf.org/html/rfc5280#section-4.1.2.7
33-
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
34-
pub struct SubjectPublicKeyInfo<'a> {
41+
#[derive(Clone, Debug, Eq, PartialEq)]
42+
pub struct SubjectPublicKeyInfo<Params, Key> {
3543
/// X.509 [`AlgorithmIdentifier`] for the public key type
36-
pub algorithm: AlgorithmIdentifierRef<'a>,
44+
pub algorithm: AlgorithmIdentifier<Params>,
3745

3846
/// Public key data
39-
pub subject_public_key: &'a [u8],
47+
pub subject_public_key: Key,
4048
}
4149

42-
impl<'a> SubjectPublicKeyInfo<'a> {
50+
impl<'a, Params, Key> SubjectPublicKeyInfo<Params, Key>
51+
where
52+
Params: Choice<'a> + Encode,
53+
// TODO: replace FixedTag with FixedTag<TAG = { Tag::BitString }> once
54+
// https://github.com/rust-lang/rust/issues/92827 is fixed
55+
Key: Decode<'a> + Encode + FixedTag,
56+
{
4357
/// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] and
4458
/// encode it as a Base64 string.
4559
///
@@ -69,74 +83,93 @@ impl<'a> SubjectPublicKeyInfo<'a> {
6983
self.encode(&mut builder)?;
7084
Ok(builder.finish())
7185
}
72-
73-
/// Get a [`BitString`] representing the `subject_public_key`
74-
fn bitstring(&self) -> der::Result<BitStringRef<'a>> {
75-
BitStringRef::from_bytes(self.subject_public_key)
76-
}
7786
}
7887

79-
impl<'a> DecodeValue<'a> for SubjectPublicKeyInfo<'a> {
88+
impl<'a: 'k, 'k, Params, Key: 'k> DecodeValue<'a> for SubjectPublicKeyInfo<Params, Key>
89+
where
90+
Params: Choice<'a> + Encode,
91+
Key: Decode<'a>,
92+
{
8093
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
8194
reader.read_nested(header.length, |reader| {
8295
Ok(Self {
8396
algorithm: reader.decode()?,
84-
subject_public_key: BitStringRef::decode(reader)?
85-
.as_bytes()
86-
.ok_or_else(|| der::Tag::BitString.value_error())?,
97+
subject_public_key: Key::decode(reader)?,
8798
})
8899
})
89100
}
90101
}
91102

92-
impl<'a> Sequence<'a> for SubjectPublicKeyInfo<'a> {
103+
impl<'a, Params, Key> Sequence<'a> for SubjectPublicKeyInfo<Params, Key>
104+
where
105+
Params: Choice<'a> + Encode,
106+
Key: Decode<'a> + Encode + FixedTag,
107+
{
93108
fn fields<F, T>(&self, f: F) -> der::Result<T>
94109
where
95110
F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
96111
{
97-
f(&[&self.algorithm, &self.bitstring()?])
112+
f(&[&self.algorithm, &self.subject_public_key])
98113
}
99114
}
100115

101-
impl<'a> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<'a> {
116+
impl<'a, Params, Key> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<Params, Key>
117+
where
118+
Params: Choice<'a> + Encode,
119+
Key: Decode<'a> + Encode + FixedTag,
120+
{
102121
type Error = Error;
103122

104123
fn try_from(bytes: &'a [u8]) -> Result<Self> {
105124
Ok(Self::from_der(bytes)?)
106125
}
107126
}
108127

109-
impl ValueOrd for SubjectPublicKeyInfo<'_> {
128+
impl<'a, Params, Key> ValueOrd for SubjectPublicKeyInfo<Params, Key>
129+
where
130+
Params: Choice<'a> + DerOrd + Encode,
131+
Key: ValueOrd,
132+
{
110133
fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
111134
match self.algorithm.der_cmp(&other.algorithm)? {
112-
Ordering::Equal => self.bitstring()?.der_cmp(&other.bitstring()?),
135+
Ordering::Equal => self.subject_public_key.value_cmp(&other.subject_public_key),
113136
other => Ok(other),
114137
}
115138
}
116139
}
117140

118141
#[cfg(feature = "alloc")]
119142
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
120-
impl TryFrom<SubjectPublicKeyInfo<'_>> for Document {
143+
impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<SubjectPublicKeyInfo<Params, Key>> for Document
144+
where
145+
Params: Choice<'a> + Encode,
146+
Key: Decode<'a> + Encode + FixedTag,
147+
BitStringRef<'a>: From<&'k Key>,
148+
{
121149
type Error = Error;
122150

123-
fn try_from(spki: SubjectPublicKeyInfo<'_>) -> Result<Document> {
151+
fn try_from(spki: SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
124152
Self::try_from(&spki)
125153
}
126154
}
127155

128156
#[cfg(feature = "alloc")]
129157
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
130-
impl TryFrom<&SubjectPublicKeyInfo<'_>> for Document {
158+
impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<&SubjectPublicKeyInfo<Params, Key>> for Document
159+
where
160+
Params: Choice<'a> + Encode,
161+
Key: Decode<'a> + Encode + FixedTag,
162+
BitStringRef<'a>: From<&'k Key>,
163+
{
131164
type Error = Error;
132165

133-
fn try_from(spki: &SubjectPublicKeyInfo<'_>) -> Result<Document> {
166+
fn try_from(spki: &SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
134167
Ok(Self::encode_msg(spki)?)
135168
}
136169
}
137170

138171
#[cfg(feature = "pem")]
139172
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
140-
impl PemLabel for SubjectPublicKeyInfo<'_> {
173+
impl<Params, Key> PemLabel for SubjectPublicKeyInfo<Params, Key> {
141174
const PEM_LABEL: &'static str = "PUBLIC KEY";
142175
}

spki/src/traits.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Traits for encoding/decoding SPKI public keys.
22
3-
use crate::{Error, Result, SubjectPublicKeyInfo};
3+
use crate::{Error, Result, SubjectPublicKeyInfoRef};
44

55
#[cfg(feature = "alloc")]
66
use der::Document;
@@ -14,6 +14,9 @@ use {
1414
#[cfg(feature = "std")]
1515
use std::path::Path;
1616

17+
#[cfg(doc)]
18+
use crate::SubjectPublicKeyInfo;
19+
1720
/// Parse a public key object from an encoded SPKI document.
1821
pub trait DecodePublicKey: Sized {
1922
/// Deserialize object from ASN.1 DER-encoded [`SubjectPublicKeyInfo`]
@@ -31,7 +34,7 @@ pub trait DecodePublicKey: Sized {
3134
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
3235
fn from_public_key_pem(s: &str) -> Result<Self> {
3336
let (label, doc) = Document::from_pem(s)?;
34-
SubjectPublicKeyInfo::validate_pem_label(label)?;
37+
SubjectPublicKeyInfoRef::validate_pem_label(label)?;
3538
Self::from_public_key_der(doc.as_bytes())
3639
}
3740

@@ -49,17 +52,17 @@ pub trait DecodePublicKey: Sized {
4952
#[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))]
5053
fn read_public_key_pem_file(path: impl AsRef<Path>) -> Result<Self> {
5154
let (label, doc) = Document::read_pem_file(path)?;
52-
SubjectPublicKeyInfo::validate_pem_label(&label)?;
55+
SubjectPublicKeyInfoRef::validate_pem_label(&label)?;
5356
Self::from_public_key_der(doc.as_bytes())
5457
}
5558
}
5659

5760
impl<T> DecodePublicKey for T
5861
where
59-
T: for<'a> TryFrom<SubjectPublicKeyInfo<'a>, Error = Error>,
62+
T: for<'a> TryFrom<SubjectPublicKeyInfoRef<'a>, Error = Error>,
6063
{
6164
fn from_public_key_der(bytes: &[u8]) -> Result<Self> {
62-
Self::try_from(SubjectPublicKeyInfo::try_from(bytes)?)
65+
Self::try_from(SubjectPublicKeyInfoRef::try_from(bytes)?)
6366
}
6467
}
6568

@@ -75,7 +78,7 @@ pub trait EncodePublicKey {
7578
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
7679
fn to_public_key_pem(&self, line_ending: LineEnding) -> Result<String> {
7780
let doc = self.to_public_key_der()?;
78-
Ok(doc.to_pem(SubjectPublicKeyInfo::PEM_LABEL, line_ending)?)
81+
Ok(doc.to_pem(SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?)
7982
}
8083

8184
/// Write ASN.1 DER-encoded public key to the given path
@@ -94,6 +97,6 @@ pub trait EncodePublicKey {
9497
line_ending: LineEnding,
9598
) -> Result<()> {
9699
let doc = self.to_public_key_der()?;
97-
Ok(doc.write_pem_file(path, SubjectPublicKeyInfo::PEM_LABEL, line_ending)?)
100+
Ok(doc.write_pem_file(path, SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?)
98101
}
99102
}

0 commit comments

Comments
 (0)