Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 7 additions & 9 deletions der/src/asn1/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ pub struct Any<'a> {
}

impl<'a> Any<'a> {
/// [`Any`] representation of the ASN.1 `NULL` type.
pub const NULL: Self = Self {
tag: Tag::Null,
value: ByteSlice::EMPTY,
};

/// Create a new [`Any`] from the provided [`Tag`] and byte slice.
pub fn new(tag: Tag, bytes: &'a [u8]) -> Result<Self> {
let value = ByteSlice::new(bytes).map_err(|_| ErrorKind::Length { tag })?;
Expand Down Expand Up @@ -57,15 +63,7 @@ impl<'a> Any<'a> {

/// Is this value an ASN.1 `NULL` value?
pub fn is_null(self) -> bool {
self == Any::null()
}

/// Create an [`Any`] value representing ASN.1 `NULL`.
pub const fn null() -> Self {
Any {
tag: Tag::Null,
value: ByteSlice::empty(),
}
self == Self::NULL
}

/// Attempt to decode an ASN.1 `BIT STRING`.
Expand Down
14 changes: 6 additions & 8 deletions der/src/byte_slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ pub(crate) struct ByteSlice<'a> {
}

impl<'a> ByteSlice<'a> {
/// Constant value representing an empty byte slice.
pub const EMPTY: Self = Self {
length: Length::ZERO,
inner: &[],
};

/// Create a new [`ByteSlice`], ensuring that the provided `slice` value
/// is shorter than `Length::max()`.
pub fn new(slice: &'a [u8]) -> Result<Self> {
Expand All @@ -40,14 +46,6 @@ impl<'a> ByteSlice<'a> {
pub fn is_empty(self) -> bool {
self.len() == Length::ZERO
}

/// Create an empty [`ByteSlice`].
pub const fn empty() -> Self {
Self {
length: Length::ZERO,
inner: &[],
}
}
}

impl AsRef<[u8]> for ByteSlice<'_> {
Expand Down
3 changes: 2 additions & 1 deletion pkcs1/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ rust-version = "1.56"
der = { version = "0.5", features = ["bigint", "oid"], path = "../der" }

# optional dependencies
pkcs8 = { version = "=0.8.0-pre", optional = true, default-features = false, path = "../pkcs8" }
zeroize = { version = "1", optional = true, default-features = false, features = ["alloc"] }

[dev-dependencies]
hex-literal = "0.3"

[features]
alloc = ["der/alloc", "zeroize"]
alloc = ["der/alloc", "pkcs8/alloc", "zeroize"]
pem = ["alloc", "der/pem"]
std = ["der/std"]

Expand Down
20 changes: 20 additions & 0 deletions pkcs1/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ pub enum Error {
/// a number expected to be a prime was not a prime.
Crypto,

/// PKCS#8 errors.
#[cfg(feature = "pkcs8")]
Pkcs8(pkcs8::Error),

/// Version errors
Version,
}
Expand All @@ -29,6 +33,8 @@ impl fmt::Display for Error {
match self {
Error::Asn1(err) => write!(f, "PKCS#1 ASN.1 error: {}", err),
Error::Crypto => f.write_str("PKCS#1 cryptographic error"),
#[cfg(feature = "pkcs8")]
Error::Pkcs8(err) => write!(f, "{}", err),
Error::Version => f.write_str("PKCS#1 version error"),
}
}
Expand All @@ -40,5 +46,19 @@ impl From<der::Error> for Error {
}
}

#[cfg(feature = "pkcs8")]
impl From<pkcs8::Error> for Error {
fn from(err: pkcs8::Error) -> Error {
Error::Pkcs8(err)
}
}

#[cfg(feature = "pkcs8")]
impl From<pkcs8::spki::Error> for Error {
fn from(err: pkcs8::spki::Error) -> Error {
Error::Pkcs8(pkcs8::Error::PublicKey(err))
}
}

#[cfg(feature = "std")]
impl std::error::Error for Error {}
4 changes: 4 additions & 0 deletions pkcs1/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ mod public_key;
mod traits;
mod version;

#[cfg(feature = "pkcs8")]
#[cfg_attr(docsrs, doc(cfg(feature = "pkcs8")))]
mod pkcs8;

pub use der::{self, asn1::UIntBytes};

pub use self::{
Expand Down
66 changes: 66 additions & 0 deletions pkcs1/src/pkcs8.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! Blanket impl of PKCS#1 support for types with PKCS#8 support.

use crate::{
DecodeRsaPrivateKey, DecodeRsaPublicKey, EncodeRsaPrivateKey, EncodeRsaPublicKey, Result,
RsaPrivateKeyDocument, RsaPublicKeyDocument,
};
use pkcs8::{
der::asn1::{Any, Null},
AlgorithmIdentifier, ObjectIdentifier,
};

#[cfg(feature = "alloc")]
use der::Document;

/// `rsaEncryption` Object Identifier (OID)
pub const ALGORITHM_OID: ObjectIdentifier = ObjectIdentifier::new("1.2.840.113549.1.1.1");

/// `AlgorithmIdentifier` for RSA.
pub const ALGORITHM_ID: AlgorithmIdentifier<'static> = AlgorithmIdentifier {
oid: ALGORITHM_OID,
parameters: Some(Any::NULL),
};

impl<T: pkcs8::DecodePrivateKey> DecodeRsaPrivateKey for T {
fn from_pkcs1_der(private_key: &[u8]) -> Result<Self> {
let algorithm = AlgorithmIdentifier {
oid: ALGORITHM_OID,
parameters: Some(Null.into()),
};

Ok(Self::from_pkcs8_private_key_info(pkcs8::PrivateKeyInfo {
algorithm,
private_key,
public_key: None,
})?)
}
}

impl<T: pkcs8::DecodePublicKey> DecodeRsaPublicKey for T {
fn from_pkcs1_der(public_key: &[u8]) -> Result<Self> {
Ok(Self::from_spki(pkcs8::SubjectPublicKeyInfo {
algorithm: ALGORITHM_ID,
subject_public_key: public_key,
})?)
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T: pkcs8::EncodePrivateKey> EncodeRsaPrivateKey for T {
fn to_pkcs1_der(&self) -> Result<RsaPrivateKeyDocument> {
let doc = self.to_pkcs8_der()?;
Ok(RsaPrivateKeyDocument::from_der(doc.decode().private_key)?)
}
}

#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
impl<T: pkcs8::EncodePublicKey> EncodeRsaPublicKey for T {
fn to_pkcs1_der(&self) -> Result<RsaPublicKeyDocument> {
let doc = self.to_public_key_der()?;
Ok(RsaPublicKeyDocument::from_der(
doc.decode().subject_public_key,
)?)
}
}
4 changes: 0 additions & 4 deletions pkcs1/src/private_key/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ impl<'a> Document<'a> for RsaPrivateKeyDocument {
}

impl DecodeRsaPrivateKey for RsaPrivateKeyDocument {
fn from_pkcs1_private_key(private_key: RsaPrivateKey<'_>) -> Result<Self> {
Ok(Self::from_msg(&private_key)?)
}

fn from_pkcs1_der(bytes: &[u8]) -> Result<Self> {
Ok(Self::from_der(bytes)?)
}
Expand Down
4 changes: 0 additions & 4 deletions pkcs1/src/public_key/document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,6 @@ impl<'a> Document<'a> for RsaPublicKeyDocument {
}

impl DecodeRsaPublicKey for RsaPublicKeyDocument {
fn from_pkcs1_public_key(public_key: RsaPublicKey<'_>) -> Result<Self> {
Ok(Self::from_msg(&public_key)?)
}

fn from_pkcs1_der(bytes: &[u8]) -> Result<Self> {
Ok(Self::from_der(bytes)?)
}
Expand Down
30 changes: 9 additions & 21 deletions pkcs1/src/traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Traits for parsing objects from PKCS#1 encoded documents

use crate::{Result, RsaPrivateKey, RsaPublicKey};
use crate::Result;

#[cfg(feature = "alloc")]
use crate::{RsaPrivateKeyDocument, RsaPublicKeyDocument};
Expand All @@ -16,14 +16,9 @@ use {der::Document, zeroize::Zeroizing};

/// Parse an [`RsaPrivateKey`] from a PKCS#1-encoded document.
pub trait DecodeRsaPrivateKey: Sized {
/// Parse the [`RsaPrivateKey`] from a PKCS#1-encoded document.
fn from_pkcs1_private_key(private_key: RsaPrivateKey<'_>) -> Result<Self>;

/// Deserialize PKCS#1 private key from ASN.1 DER-encoded data
/// (binary format).
fn from_pkcs1_der(bytes: &[u8]) -> Result<Self> {
Self::from_pkcs1_private_key(RsaPrivateKey::try_from(bytes)?)
}
fn from_pkcs1_der(bytes: &[u8]) -> Result<Self>;

/// Deserialize PKCS#1-encoded private key from PEM.
///
Expand All @@ -35,8 +30,7 @@ pub trait DecodeRsaPrivateKey: Sized {
#[cfg(feature = "pem")]
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
fn from_pkcs1_pem(s: &str) -> Result<Self> {
RsaPrivateKeyDocument::from_pkcs1_pem(s)
.and_then(|doc| Self::from_pkcs1_private_key(doc.decode()))
RsaPrivateKeyDocument::from_pkcs1_pem(s).and_then(|doc| Self::from_pkcs1_der(doc.as_der()))
}

/// Load PKCS#1 private key from an ASN.1 DER-encoded file on the local
Expand All @@ -45,7 +39,7 @@ pub trait DecodeRsaPrivateKey: Sized {
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self> {
RsaPrivateKeyDocument::read_pkcs1_der_file(path)
.and_then(|doc| Self::from_pkcs1_private_key(doc.decode()))
.and_then(|doc| Self::from_pkcs1_der(doc.as_der()))
}

/// Load PKCS#1 private key from a PEM-encoded file on the local filesystem.
Expand All @@ -54,20 +48,15 @@ pub trait DecodeRsaPrivateKey: Sized {
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
RsaPrivateKeyDocument::read_pkcs1_pem_file(path)
.and_then(|doc| Self::from_pkcs1_private_key(doc.decode()))
.and_then(|doc| Self::from_pkcs1_der(doc.as_der()))
}
}

/// Parse a [`RsaPublicKey`] from a PKCS#1-encoded document.
pub trait DecodeRsaPublicKey: Sized {
/// Parse [`RsaPublicKey`] into a [`RsaPublicKey`].
fn from_pkcs1_public_key(public_key: RsaPublicKey<'_>) -> Result<Self>;

/// Deserialize object from ASN.1 DER-encoded [`RsaPublicKey`]
/// (binary format).
fn from_pkcs1_der(bytes: &[u8]) -> Result<Self> {
Self::from_pkcs1_public_key(RsaPublicKey::try_from(bytes)?)
}
fn from_pkcs1_der(bytes: &[u8]) -> Result<Self>;

/// Deserialize PEM-encoded [`RsaPublicKey`].
///
Expand All @@ -79,8 +68,7 @@ pub trait DecodeRsaPublicKey: Sized {
#[cfg(feature = "pem")]
#[cfg_attr(docsrs, doc(cfg(feature = "pem")))]
fn from_pkcs1_pem(s: &str) -> Result<Self> {
RsaPublicKeyDocument::from_pkcs1_pem(s)
.and_then(|doc| Self::from_pkcs1_public_key(doc.decode()))
RsaPublicKeyDocument::from_pkcs1_pem(s).and_then(|doc| Self::from_pkcs1_der(doc.as_der()))
}

/// Load [`RsaPublicKey`] from an ASN.1 DER-encoded file on the local
Expand All @@ -89,7 +77,7 @@ pub trait DecodeRsaPublicKey: Sized {
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn read_pkcs1_der_file(path: impl AsRef<Path>) -> Result<Self> {
RsaPublicKeyDocument::read_pkcs1_der_file(path)
.and_then(|doc| Self::from_pkcs1_public_key(doc.decode()))
.and_then(|doc| Self::from_pkcs1_der(doc.as_der()))
}

/// Load [`RsaPublicKey`] from a PEM-encoded file on the local filesystem.
Expand All @@ -98,7 +86,7 @@ pub trait DecodeRsaPublicKey: Sized {
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
fn read_pkcs1_pem_file(path: impl AsRef<Path>) -> Result<Self> {
RsaPublicKeyDocument::read_pkcs1_pem_file(path)
.and_then(|doc| Self::from_pkcs1_public_key(doc.decode()))
.and_then(|doc| Self::from_pkcs1_der(doc.as_der()))
}
}

Expand Down