aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/algorithm.rs134
-rw-r--r--src/fingerprint.rs1
-rw-r--r--src/lib.rs40
-rw-r--r--src/spki.rs162
-rw-r--r--src/traits.rs128
5 files changed, 354 insertions, 111 deletions
diff --git a/src/algorithm.rs b/src/algorithm.rs
index 2a8b6c7..5f4b5e8 100644
--- a/src/algorithm.rs
+++ b/src/algorithm.rs
@@ -2,8 +2,14 @@
use crate::{Error, Result};
use core::cmp::Ordering;
-use der::asn1::{AnyRef, ObjectIdentifier};
-use der::{Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd};
+use der::{
+ asn1::{AnyRef, Choice, ObjectIdentifier},
+ Decode, DecodeValue, DerOrd, Encode, EncodeValue, Header, Length, Reader, Sequence, ValueOrd,
+ Writer,
+};
+
+#[cfg(feature = "alloc")]
+use der::asn1::Any;
/// X.509 `AlgorithmIdentifier` as defined in [RFC 5280 Section 4.1.1.2].
///
@@ -14,17 +20,82 @@ use der::{Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOr
/// ```
///
/// [RFC 5280 Section 4.1.1.2]: https://tools.ietf.org/html/rfc5280#section-4.1.1.2
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
-pub struct AlgorithmIdentifier<'a> {
+pub struct AlgorithmIdentifier<Params> {
/// Algorithm OID, i.e. the `algorithm` field in the `AlgorithmIdentifier`
/// ASN.1 schema.
pub oid: ObjectIdentifier,
/// Algorithm `parameters`.
- pub parameters: Option<AnyRef<'a>>,
+ pub parameters: Option<Params>,
+}
+
+impl<'a, Params> DecodeValue<'a> for AlgorithmIdentifier<Params>
+where
+ Params: Choice<'a>,
+{
+ fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
+ reader.read_nested(header.length, |reader| {
+ Ok(Self {
+ oid: reader.decode()?,
+ parameters: reader.decode()?,
+ })
+ })
+ }
+}
+
+impl<Params> EncodeValue for AlgorithmIdentifier<Params>
+where
+ Params: Encode,
+{
+ fn value_len(&self) -> der::Result<Length> {
+ self.oid.encoded_len()? + self.parameters.encoded_len()?
+ }
+
+ fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
+ self.oid.encode(writer)?;
+ self.parameters.encode(writer)?;
+ Ok(())
+ }
}
-impl<'a> AlgorithmIdentifier<'a> {
+impl<'a, Params> Sequence<'a> for AlgorithmIdentifier<Params> where Params: Choice<'a> + Encode {}
+
+impl<'a, Params> TryFrom<&'a [u8]> for AlgorithmIdentifier<Params>
+where
+ Params: Choice<'a> + Encode,
+{
+ type Error = Error;
+
+ fn try_from(bytes: &'a [u8]) -> Result<Self> {
+ Ok(Self::from_der(bytes)?)
+ }
+}
+
+impl<Params> ValueOrd for AlgorithmIdentifier<Params>
+where
+ Params: DerOrd,
+{
+ fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
+ match self.oid.der_cmp(&other.oid)? {
+ Ordering::Equal => self.parameters.der_cmp(&other.parameters),
+ other => Ok(other),
+ }
+ }
+}
+
+/// `AlgorithmIdentifier` reference which has `AnyRef` parameters.
+pub type AlgorithmIdentifierRef<'a> = AlgorithmIdentifier<AnyRef<'a>>;
+
+/// `AlgorithmIdentifier` with `ObjectIdentifier` parameters.
+pub type AlgorithmIdentifierWithOid = AlgorithmIdentifier<ObjectIdentifier>;
+
+/// `AlgorithmIdentifier` reference which has `Any` parameters.
+#[cfg(feature = "alloc")]
+pub type AlgorithmIdentifierOwned = AlgorithmIdentifier<Any>;
+
+impl<Params> AlgorithmIdentifier<Params> {
/// Assert the `algorithm` OID is an expected value.
pub fn assert_algorithm_oid(&self, expected_oid: ObjectIdentifier) -> Result<ObjectIdentifier> {
if self.oid == expected_oid {
@@ -33,7 +104,9 @@ impl<'a> AlgorithmIdentifier<'a> {
Err(Error::OidUnknown { oid: expected_oid })
}
}
+}
+impl<'a> AlgorithmIdentifierRef<'a> {
/// Assert `parameters` is an OID and has the expected value.
pub fn assert_parameters_oid(
&self,
@@ -87,46 +160,35 @@ impl<'a> AlgorithmIdentifier<'a> {
None => None,
Some(p) => match p {
AnyRef::NULL => None,
- _ => Some(p.oid()?),
+ _ => Some(p.decode_as::<ObjectIdentifier>()?),
},
},
))
}
}
-impl<'a> DecodeValue<'a> for AlgorithmIdentifier<'a> {
- fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
- reader.read_nested(header.length, |reader| {
- Ok(Self {
- oid: reader.decode()?,
- parameters: reader.decode()?,
- })
- })
- }
-}
-
-impl<'a> Sequence<'a> for AlgorithmIdentifier<'a> {
- fn fields<F, T>(&self, f: F) -> der::Result<T>
- where
- F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
- {
- f(&[&self.oid, &self.parameters])
- }
-}
+#[cfg(feature = "alloc")]
+mod allocating {
+ use super::*;
+ use der::referenced::*;
-impl<'a> TryFrom<&'a [u8]> for AlgorithmIdentifier<'a> {
- type Error = Error;
-
- fn try_from(bytes: &'a [u8]) -> Result<Self> {
- Ok(Self::from_der(bytes)?)
+ impl<'a> RefToOwned<'a> for AlgorithmIdentifierRef<'a> {
+ type Owned = AlgorithmIdentifierOwned;
+ fn ref_to_owned(&self) -> Self::Owned {
+ AlgorithmIdentifier {
+ oid: self.oid,
+ parameters: self.parameters.ref_to_owned(),
+ }
+ }
}
-}
-impl ValueOrd for AlgorithmIdentifier<'_> {
- fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
- match self.oid.der_cmp(&other.oid)? {
- Ordering::Equal => self.parameters.der_cmp(&other.parameters),
- other => Ok(other),
+ impl OwnedToRef for AlgorithmIdentifierOwned {
+ type Borrowed<'a> = AlgorithmIdentifierRef<'a>;
+ fn owned_to_ref(&self) -> Self::Borrowed<'_> {
+ AlgorithmIdentifier {
+ oid: self.oid,
+ parameters: self.parameters.owned_to_ref(),
+ }
}
}
}
diff --git a/src/fingerprint.rs b/src/fingerprint.rs
index 6a3901f..ba06e62 100644
--- a/src/fingerprint.rs
+++ b/src/fingerprint.rs
@@ -12,7 +12,6 @@ pub(crate) const SIZE: usize = 32;
/// See [RFC7469 § 2.1.1] for more information.
///
/// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
-#[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))]
pub type FingerprintBytes = [u8; SIZE];
/// Writer newtype which accepts DER being serialized on-the-fly and computes a
diff --git a/src/lib.rs b/src/lib.rs
index 995f3bd..a8b7653 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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_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)]
-
//! # Usage
//! The following example demonstrates how to use an OID as the `parameters`
//! of an [`AlgorithmIdentifier`].
@@ -15,14 +21,14 @@
//! Borrow the [`ObjectIdentifier`] first then use [`der::AnyRef::from`] or `.into()`:
//!
//! ```
-//! use spki::{AlgorithmIdentifier, ObjectIdentifier, der::AnyRef};
+//! use spki::{AlgorithmIdentifier, ObjectIdentifier};
//!
//! let alg_oid = "1.2.840.10045.2.1".parse::<ObjectIdentifier>().unwrap();
//! let params_oid = "1.2.840.10045.3.1.7".parse::<ObjectIdentifier>().unwrap();
//!
//! let alg_id = AlgorithmIdentifier {
//! oid: alg_oid,
-//! parameters: Some(AnyRef::from(&params_oid))
+//! parameters: Some(params_oid)
//! };
//! ```
@@ -41,10 +47,10 @@ mod traits;
mod fingerprint;
pub use crate::{
- algorithm::AlgorithmIdentifier,
+ algorithm::{AlgorithmIdentifier, AlgorithmIdentifierRef, AlgorithmIdentifierWithOid},
error::{Error, Result},
- spki::SubjectPublicKeyInfo,
- traits::DecodePublicKey,
+ spki::{SubjectPublicKeyInfo, SubjectPublicKeyInfoRef},
+ traits::{AssociatedAlgorithmIdentifier, DecodePublicKey, SignatureAlgorithmIdentifier},
};
pub use der::{self, asn1::ObjectIdentifier};
@@ -53,7 +59,17 @@ pub use der::{self, asn1::ObjectIdentifier};
extern crate std;
#[cfg(feature = "alloc")]
-pub use {crate::traits::EncodePublicKey, der::Document};
+pub use {
+ crate::{
+ algorithm::AlgorithmIdentifierOwned,
+ spki::SubjectPublicKeyInfoOwned,
+ traits::{
+ DynAssociatedAlgorithmIdentifier, DynSignatureAlgorithmIdentifier, EncodePublicKey,
+ SignatureBitStringEncoding,
+ },
+ },
+ der::Document,
+};
#[cfg(feature = "fingerprint")]
pub use crate::fingerprint::FingerprintBytes;
diff --git a/src/spki.rs b/src/spki.rs
index 9058e49..b7e4c92 100644
--- a/src/spki.rs
+++ b/src/spki.rs
@@ -3,24 +3,30 @@
use crate::{AlgorithmIdentifier, Error, Result};
use core::cmp::Ordering;
use der::{
- asn1::BitStringRef, Decode, DecodeValue, DerOrd, Encode, Header, Reader, Sequence, ValueOrd,
+ asn1::{AnyRef, BitStringRef},
+ Choice, Decode, DecodeValue, DerOrd, Encode, EncodeValue, FixedTag, Header, Length, Reader,
+ Sequence, ValueOrd, Writer,
};
#[cfg(feature = "alloc")]
-use der::Document;
+use der::{
+ asn1::{Any, BitString},
+ Document,
+};
#[cfg(feature = "fingerprint")]
use crate::{fingerprint, FingerprintBytes};
-#[cfg(all(feature = "alloc", feature = "fingerprint"))]
-use {
- alloc::string::String,
- base64ct::{Base64, Encoding},
-};
-
#[cfg(feature = "pem")]
use der::pem::PemLabel;
+/// [`SubjectPublicKeyInfo`] with [`AnyRef`] algorithm parameters, and [`BitStringRef`] params.
+pub type SubjectPublicKeyInfoRef<'a> = SubjectPublicKeyInfo<AnyRef<'a>, BitStringRef<'a>>;
+
+/// [`SubjectPublicKeyInfo`] with [`Any`] algorithm parameters, and [`BitString`] params.
+#[cfg(feature = "alloc")]
+pub type SubjectPublicKeyInfoOwned = SubjectPublicKeyInfo<Any, BitString>;
+
/// X.509 `SubjectPublicKeyInfo` (SPKI) as defined in [RFC 5280 § 4.1.2.7].
///
/// ASN.1 structure containing an [`AlgorithmIdentifier`] and public key
@@ -33,25 +39,32 @@ use der::pem::PemLabel;
/// ```
///
/// [RFC 5280 § 4.1.2.7]: https://tools.ietf.org/html/rfc5280#section-4.1.2.7
-#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub struct SubjectPublicKeyInfo<'a> {
+#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct SubjectPublicKeyInfo<Params, Key> {
/// X.509 [`AlgorithmIdentifier`] for the public key type
- pub algorithm: AlgorithmIdentifier<'a>,
+ pub algorithm: AlgorithmIdentifier<Params>,
/// Public key data
- pub subject_public_key: &'a [u8],
+ pub subject_public_key: Key,
}
-impl<'a> SubjectPublicKeyInfo<'a> {
+impl<'a, Params, Key> SubjectPublicKeyInfo<Params, Key>
+where
+ Params: Choice<'a> + Encode,
+ // TODO: replace FixedTag with FixedTag<TAG = { Tag::BitString }> once
+ // https://github.com/rust-lang/rust/issues/92827 is fixed
+ Key: Decode<'a> + Encode + FixedTag,
+{
/// Calculate the SHA-256 fingerprint of this [`SubjectPublicKeyInfo`] and
/// encode it as a Base64 string.
///
/// See [RFC7469 § 2.1.1] for more information.
///
/// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
- #[cfg(all(feature = "fingerprint", feature = "alloc"))]
- #[cfg_attr(docsrs, doc(cfg(all(feature = "fingerprint", feature = "alloc"))))]
- pub fn fingerprint_base64(&self) -> Result<String> {
+ #[cfg(all(feature = "fingerprint", feature = "alloc", feature = "base64"))]
+ pub fn fingerprint_base64(&self) -> Result<alloc::string::String> {
+ use base64ct::{Base64, Encoding};
Ok(Base64::encode_string(&self.fingerprint_bytes()?))
}
@@ -62,42 +75,56 @@ impl<'a> SubjectPublicKeyInfo<'a> {
///
/// [RFC7469 § 2.1.1]: https://datatracker.ietf.org/doc/html/rfc7469#section-2.1.1
#[cfg(feature = "fingerprint")]
- #[cfg_attr(docsrs, doc(cfg(feature = "fingerprint")))]
pub fn fingerprint_bytes(&self) -> Result<FingerprintBytes> {
let mut builder = fingerprint::Builder::new();
self.encode(&mut builder)?;
Ok(builder.finish())
}
-
- /// Get a [`BitString`] representing the `subject_public_key`
- fn bitstring(&self) -> der::Result<BitStringRef<'a>> {
- BitStringRef::from_bytes(self.subject_public_key)
- }
}
-impl<'a> DecodeValue<'a> for SubjectPublicKeyInfo<'a> {
+impl<'a: 'k, 'k, Params, Key: 'k> DecodeValue<'a> for SubjectPublicKeyInfo<Params, Key>
+where
+ Params: Choice<'a> + Encode,
+ Key: Decode<'a>,
+{
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<Self> {
reader.read_nested(header.length, |reader| {
Ok(Self {
algorithm: reader.decode()?,
- subject_public_key: BitStringRef::decode(reader)?
- .as_bytes()
- .ok_or_else(|| der::Tag::BitString.value_error())?,
+ subject_public_key: Key::decode(reader)?,
})
})
}
}
-impl<'a> Sequence<'a> for SubjectPublicKeyInfo<'a> {
- fn fields<F, T>(&self, f: F) -> der::Result<T>
- where
- F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
- {
- f(&[&self.algorithm, &self.bitstring()?])
+impl<'a, Params, Key> EncodeValue for SubjectPublicKeyInfo<Params, Key>
+where
+ Params: Choice<'a> + Encode,
+ Key: Encode,
+{
+ fn value_len(&self) -> der::Result<Length> {
+ self.algorithm.encoded_len()? + self.subject_public_key.encoded_len()?
}
+
+ fn encode_value(&self, writer: &mut impl Writer) -> der::Result<()> {
+ self.algorithm.encode(writer)?;
+ self.subject_public_key.encode(writer)?;
+ Ok(())
+ }
+}
+
+impl<'a, Params, Key> Sequence<'a> for SubjectPublicKeyInfo<Params, Key>
+where
+ Params: Choice<'a> + Encode,
+ Key: Decode<'a> + Encode + FixedTag,
+{
}
-impl<'a> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<'a> {
+impl<'a, Params, Key> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<Params, Key>
+where
+ Params: Choice<'a> + Encode,
+ Key: Decode<'a> + Encode + FixedTag,
+{
type Error = Error;
fn try_from(bytes: &'a [u8]) -> Result<Self> {
@@ -105,37 +132,86 @@ impl<'a> TryFrom<&'a [u8]> for SubjectPublicKeyInfo<'a> {
}
}
-impl ValueOrd for SubjectPublicKeyInfo<'_> {
+impl<'a, Params, Key> ValueOrd for SubjectPublicKeyInfo<Params, Key>
+where
+ Params: Choice<'a> + DerOrd + Encode,
+ Key: ValueOrd,
+{
fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
match self.algorithm.der_cmp(&other.algorithm)? {
- Ordering::Equal => self.bitstring()?.der_cmp(&other.bitstring()?),
+ Ordering::Equal => self.subject_public_key.value_cmp(&other.subject_public_key),
other => Ok(other),
}
}
}
#[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
-impl TryFrom<SubjectPublicKeyInfo<'_>> for Document {
+impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<SubjectPublicKeyInfo<Params, Key>> for Document
+where
+ Params: Choice<'a> + Encode,
+ Key: Decode<'a> + Encode + FixedTag,
+ BitStringRef<'a>: From<&'k Key>,
+{
type Error = Error;
- fn try_from(spki: SubjectPublicKeyInfo<'_>) -> Result<Document> {
+ fn try_from(spki: SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
Self::try_from(&spki)
}
}
#[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
-impl TryFrom<&SubjectPublicKeyInfo<'_>> for Document {
+impl<'a: 'k, 'k, Params, Key: 'k> TryFrom<&SubjectPublicKeyInfo<Params, Key>> for Document
+where
+ Params: Choice<'a> + Encode,
+ Key: Decode<'a> + Encode + FixedTag,
+ BitStringRef<'a>: From<&'k Key>,
+{
type Error = Error;
- fn try_from(spki: &SubjectPublicKeyInfo<'_>) -> Result<Document> {
+ fn try_from(spki: &SubjectPublicKeyInfo<Params, Key>) -> Result<Document> {
Ok(Self::encode_msg(spki)?)
}
}
#[cfg(feature = "pem")]
-#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
-impl PemLabel for SubjectPublicKeyInfo<'_> {
+impl<Params, Key> PemLabel for SubjectPublicKeyInfo<Params, Key> {
const PEM_LABEL: &'static str = "PUBLIC KEY";
}
+
+#[cfg(feature = "alloc")]
+mod allocating {
+ use super::*;
+ use crate::EncodePublicKey;
+ use der::referenced::*;
+
+ impl<'a> RefToOwned<'a> for SubjectPublicKeyInfoRef<'a> {
+ type Owned = SubjectPublicKeyInfoOwned;
+ fn ref_to_owned(&self) -> Self::Owned {
+ SubjectPublicKeyInfo {
+ algorithm: self.algorithm.ref_to_owned(),
+ subject_public_key: self.subject_public_key.ref_to_owned(),
+ }
+ }
+ }
+
+ impl OwnedToRef for SubjectPublicKeyInfoOwned {
+ type Borrowed<'a> = SubjectPublicKeyInfoRef<'a>;
+ fn owned_to_ref(&self) -> Self::Borrowed<'_> {
+ SubjectPublicKeyInfo {
+ algorithm: self.algorithm.owned_to_ref(),
+ subject_public_key: self.subject_public_key.owned_to_ref(),
+ }
+ }
+ }
+
+ impl SubjectPublicKeyInfoOwned {
+ /// Create a [`SubjectPublicKeyInfoOwned`] from any object that implements
+ /// [`EncodePublicKey`].
+ pub fn from_key<T>(source: T) -> Result<Self>
+ where
+ T: EncodePublicKey,
+ {
+ Ok(source.to_public_key_der()?.decode_msg::<Self>()?)
+ }
+ }
+}
diff --git a/src/traits.rs b/src/traits.rs
index c16e397..764b02a 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -1,9 +1,13 @@
//! Traits for encoding/decoding SPKI public keys.
-use crate::{Error, Result, SubjectPublicKeyInfo};
+use crate::{AlgorithmIdentifier, Error, Result, SubjectPublicKeyInfoRef};
+use der::{EncodeValue, Tagged};
#[cfg(feature = "alloc")]
-use der::Document;
+use {
+ crate::AlgorithmIdentifierOwned,
+ der::{asn1::BitString, Any, Document},
+};
#[cfg(feature = "pem")]
use {
@@ -14,15 +18,14 @@ use {
#[cfg(feature = "std")]
use std::path::Path;
+#[cfg(doc)]
+use crate::SubjectPublicKeyInfo;
+
/// Parse a public key object from an encoded SPKI document.
-pub trait DecodePublicKey:
- for<'a> TryFrom<SubjectPublicKeyInfo<'a>, Error = Error> + Sized
-{
+pub trait DecodePublicKey: Sized {
/// Deserialize object from ASN.1 DER-encoded [`SubjectPublicKeyInfo`]
/// (binary format).
- fn from_public_key_der(bytes: &[u8]) -> Result<Self> {
- Self::try_from(SubjectPublicKeyInfo::try_from(bytes)?)
- }
+ fn from_public_key_der(bytes: &[u8]) -> Result<Self>;
/// Deserialize PEM-encoded [`SubjectPublicKeyInfo`].
///
@@ -32,17 +35,15 @@ pub trait DecodePublicKey:
/// -----BEGIN PUBLIC KEY-----
/// ```
#[cfg(feature = "pem")]
- #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
fn from_public_key_pem(s: &str) -> Result<Self> {
let (label, doc) = Document::from_pem(s)?;
- SubjectPublicKeyInfo::validate_pem_label(label)?;
+ SubjectPublicKeyInfoRef::validate_pem_label(label)?;
Self::from_public_key_der(doc.as_bytes())
}
/// Load public key object 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_public_key_der_file(path: impl AsRef<Path>) -> Result<Self> {
let doc = Document::read_der_file(path)?;
Self::from_public_key_der(doc.as_bytes())
@@ -50,45 +51,134 @@ pub trait DecodePublicKey:
/// Load public key object from a PEM-encoded file on the local filesystem.
#[cfg(all(feature = "pem", feature = "std"))]
- #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))]
fn read_public_key_pem_file(path: impl AsRef<Path>) -> Result<Self> {
let (label, doc) = Document::read_pem_file(path)?;
- SubjectPublicKeyInfo::validate_pem_label(&label)?;
+ SubjectPublicKeyInfoRef::validate_pem_label(&label)?;
Self::from_public_key_der(doc.as_bytes())
}
}
+impl<T> DecodePublicKey for T
+where
+ T: for<'a> TryFrom<SubjectPublicKeyInfoRef<'a>, Error = Error>,
+{
+ fn from_public_key_der(bytes: &[u8]) -> Result<Self> {
+ Self::try_from(SubjectPublicKeyInfoRef::try_from(bytes)?)
+ }
+}
+
/// Serialize a public key object to a SPKI-encoded document.
#[cfg(feature = "alloc")]
-#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub trait EncodePublicKey {
/// Serialize a [`Document`] containing a SPKI-encoded public key.
fn to_public_key_der(&self) -> Result<Document>;
/// Serialize this public key as PEM-encoded SPKI with the given [`LineEnding`].
#[cfg(feature = "pem")]
- #[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
fn to_public_key_pem(&self, line_ending: LineEnding) -> Result<String> {
let doc = self.to_public_key_der()?;
- Ok(doc.to_pem(SubjectPublicKeyInfo::PEM_LABEL, line_ending)?)
+ Ok(doc.to_pem(SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?)
}
/// Write ASN.1 DER-encoded public key to the given path
#[cfg(feature = "std")]
- #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn write_public_key_der_file(&self, path: impl AsRef<Path>) -> Result<()> {
Ok(self.to_public_key_der()?.write_der_file(path)?)
}
/// Write ASN.1 DER-encoded public key to the given path
#[cfg(all(feature = "pem", feature = "std"))]
- #[cfg_attr(docsrs, doc(cfg(all(feature = "pem", feature = "std"))))]
fn write_public_key_pem_file(
&self,
path: impl AsRef<Path>,
line_ending: LineEnding,
) -> Result<()> {
let doc = self.to_public_key_der()?;
- Ok(doc.write_pem_file(path, SubjectPublicKeyInfo::PEM_LABEL, line_ending)?)
+ Ok(doc.write_pem_file(path, SubjectPublicKeyInfoRef::PEM_LABEL, line_ending)?)
+ }
+}
+
+/// Returns `AlgorithmIdentifier` associated with the structure.
+///
+/// This is useful for e.g. keys for digital signature algorithms.
+pub trait AssociatedAlgorithmIdentifier {
+ /// Algorithm parameters.
+ type Params: Tagged + EncodeValue;
+
+ /// `AlgorithmIdentifier` for this structure.
+ const ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params>;
+}
+
+/// Returns `AlgorithmIdentifier` associated with the structure.
+///
+/// This is useful for e.g. keys for digital signature algorithms.
+#[cfg(feature = "alloc")]
+pub trait DynAssociatedAlgorithmIdentifier {
+ /// `AlgorithmIdentifier` for this structure.
+ fn algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>;
+}
+
+#[cfg(feature = "alloc")]
+impl<T> DynAssociatedAlgorithmIdentifier for T
+where
+ T: AssociatedAlgorithmIdentifier,
+{
+ fn algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned> {
+ Ok(AlgorithmIdentifierOwned {
+ oid: T::ALGORITHM_IDENTIFIER.oid,
+ parameters: T::ALGORITHM_IDENTIFIER
+ .parameters
+ .as_ref()
+ .map(Any::encode_from)
+ .transpose()?,
+ })
+ }
+}
+
+/// Returns `AlgorithmIdentifier` associated with the signature system.
+///
+/// Unlike AssociatedAlgorithmIdentifier this is intended to be implemented for public and/or
+/// private keys.
+pub trait SignatureAlgorithmIdentifier {
+ /// Algorithm parameters.
+ type Params: Tagged + EncodeValue;
+
+ /// `AlgorithmIdentifier` for the corresponding singature system.
+ const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params>;
+}
+
+/// Returns `AlgorithmIdentifier` associated with the signature system.
+///
+/// Unlike AssociatedAlgorithmIdentifier this is intended to be implemented for public and/or
+/// private keys.
+#[cfg(feature = "alloc")]
+pub trait DynSignatureAlgorithmIdentifier {
+ /// `AlgorithmIdentifier` for the corresponding singature system.
+ fn signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned>;
+}
+
+#[cfg(feature = "alloc")]
+impl<T> DynSignatureAlgorithmIdentifier for T
+where
+ T: SignatureAlgorithmIdentifier,
+{
+ fn signature_algorithm_identifier(&self) -> Result<AlgorithmIdentifierOwned> {
+ Ok(AlgorithmIdentifierOwned {
+ oid: T::SIGNATURE_ALGORITHM_IDENTIFIER.oid,
+ parameters: T::SIGNATURE_ALGORITHM_IDENTIFIER
+ .parameters
+ .as_ref()
+ .map(Any::encode_from)
+ .transpose()?,
+ })
}
}
+
+/// Returns the `BitString` encoding of the signature.
+///
+/// X.509 and CSR structures require signatures to be BitString encoded.
+#[cfg(feature = "alloc")]
+pub trait SignatureBitStringEncoding {
+ /// `BitString` encoding for this signature.
+ fn to_bitstring(&self) -> der::Result<BitString>;
+}