Skip to content
Closed
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
9 changes: 9 additions & 0 deletions pkcs12/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,12 @@ rust-version = "1.65"
[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]

[dependencies]
der = { version = "=0.7.0-pre", features = ["oid", "pem"], path = "../der" }
spki = { version = "=0.7.0-pre", path = "../spki" }
x509-cert = { version = "=0.2.0-pre", path = "../x509-cert" }
pkcs7 = { version = "=0.4.0-pre.0", path = "../pkcs7" }
pkcs8 = { version = "=0.10.0-pre", features = ["pkcs5"], path = "../pkcs8" }
[dev-dependencies]
hex-literal = "0.3.3"
163 changes: 163 additions & 0 deletions pkcs12/src/authenticated_safe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
use alloc::vec::Vec;
use der::{
asn1::{ContextSpecific, OctetStringRef},
Decode, DecodeValue, Encode, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader,
Sequence, Tag, TagMode, TagNumber, Writer,
};
use pkcs7::encrypted_data_content::EncryptedDataContent;
use pkcs8::ObjectIdentifier;

use crate::safe_bag::SafeContents;

const CONTENT_TAG: TagNumber = TagNumber::new(0);

/// sequence of AuthenticatedSafeItems
pub type AuthenticatedSafe<'a> = Vec<AuthenticatedSafeItem<'a>>;

/// TODO
#[derive(Clone, Debug)]
pub enum AuthenticatedSafeItem<'a> {
/// data safe
Data(Option<SafeContents<'a>>),
/// encrypted data safe
EncryptedData(Option<EncryptedDataContent<'a>>),
/// enveloped data safe
EnvelopedData(Option<SafeContents<'a>>),
}

impl<'a> AuthenticatedSafeItem<'a> {
/// return content type of content info
pub fn content_type(&self) -> AuthenticatedSafeContentType {
match self {
Self::Data(_) => AuthenticatedSafeContentType::Data,
Self::EncryptedData(_) => AuthenticatedSafeContentType::EncryptedData,
Self::EnvelopedData(_) => AuthenticatedSafeContentType::EnvelopedData,
}
}
}

impl<'a> DecodeValue<'a> for AuthenticatedSafeItem<'a> {
fn decode_value<R: Reader<'a>>(
reader: &mut R,
header: Header,
) -> der::Result<AuthenticatedSafeItem<'a>> {
reader.read_nested(header.length, |reader| {
let bag_type = reader.decode()?;
match bag_type {
AuthenticatedSafeContentType::Data => {
let inner = reader
.context_specific::<OctetStringRef<'a>>(CONTENT_TAG, TagMode::Explicit)?;
let contents = SafeContents::from_der(inner.unwrap().as_bytes())?;
Ok(AuthenticatedSafeItem::Data(Some(contents)))
}
AuthenticatedSafeContentType::EncryptedData => {
Ok(AuthenticatedSafeItem::EncryptedData(
reader.context_specific::<EncryptedDataContent<'a>>(
CONTENT_TAG,
TagMode::Explicit,
)?,
))
}
AuthenticatedSafeContentType::EnvelopedData => {
Ok(AuthenticatedSafeItem::EnvelopedData(
reader
.context_specific::<SafeContents<'a>>(CONTENT_TAG, TagMode::Explicit)?,
))
}
}
})
}
}

impl<'a> Sequence<'a> for AuthenticatedSafeItem<'a> {
fn fields<F, T>(&self, f: F) -> der::Result<T>
where
F: FnOnce(&[&dyn Encode]) -> der::Result<T>,
{
match self {
AuthenticatedSafeItem::Data(data) => f(&[
&self.content_type(),
&data.as_ref().map(|d| ContextSpecific {
tag_number: CONTENT_TAG,
tag_mode: TagMode::Explicit,
value: d.clone(),
}),
]),
AuthenticatedSafeItem::EncryptedData(data) => f(&[
&self.content_type(),
&data.as_ref().map(|d| ContextSpecific {
tag_number: CONTENT_TAG,
tag_mode: TagMode::Explicit,
value: d.clone(),
}),
]),
AuthenticatedSafeItem::EnvelopedData(data) => f(&[
&self.content_type(),
&data.as_ref().map(|d| ContextSpecific {
tag_number: CONTENT_TAG,
tag_mode: TagMode::Explicit,
value: d.clone(),
}),
]),
}
}
Comment on lines +73 to +103

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, this method was removed in #828

Here's a similar example, although it could probably be cleaned up a bit / DRYed out: https://github.com/RustCrypto/formats/pull/828/files#diff-7eada31819a5738c81669b63773252d75c0ae287f02296637ee5862e36b18408

}

/// Indicates the type of content.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum AuthenticatedSafeContentType {
/// Plain data content type
Data,

/// Enveloped-data content type
EnvelopedData,

/// Encrypted-data content type
EncryptedData,
}

impl<'a> DecodeValue<'a> for AuthenticatedSafeContentType {
fn decode_value<R: Reader<'a>>(
reader: &mut R,
header: Header,
) -> der::Result<AuthenticatedSafeContentType> {
ObjectIdentifier::decode_value(reader, header)?.try_into()
}
}

impl EncodeValue for AuthenticatedSafeContentType {
fn value_len(&self) -> der::Result<Length> {
ObjectIdentifier::from(*self).value_len()
}

fn encode_value(&self, writer: &mut dyn Writer) -> der::Result<()> {
ObjectIdentifier::from(*self).encode_value(writer)
}
}

impl FixedTag for AuthenticatedSafeContentType {
const TAG: Tag = Tag::ObjectIdentifier;
}

impl From<AuthenticatedSafeContentType> for ObjectIdentifier {
fn from(content_type: AuthenticatedSafeContentType) -> ObjectIdentifier {
match content_type {
AuthenticatedSafeContentType::Data => pkcs7::PKCS_7_DATA_OID,
AuthenticatedSafeContentType::EnvelopedData => pkcs7::PKCS_7_ENVELOPED_DATA_OID,
AuthenticatedSafeContentType::EncryptedData => pkcs7::PKCS_7_ENCRYPTED_DATA_OID,
}
}
}

impl TryFrom<ObjectIdentifier> for AuthenticatedSafeContentType {
type Error = der::Error;

fn try_from(oid: ObjectIdentifier) -> der::Result<Self> {
match oid {
pkcs7::PKCS_7_DATA_OID => Ok(Self::Data),
pkcs7::PKCS_7_ENVELOPED_DATA_OID => Ok(Self::EnvelopedData),
pkcs7::PKCS_7_ENCRYPTED_DATA_OID => Ok(Self::EncryptedData),
_ => Err(ErrorKind::OidUnknown { oid }.into()),
}
}
}
73 changes: 73 additions & 0 deletions pkcs12/src/bag_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
use der::asn1::ObjectIdentifier;
use der::{DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Tag, Writer};

/// Indicates the type of content.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum BagType {
/// Plain data content type
Key,

/// Signed-data content type
Pkcs8,

/// Enveloped-data content type
Cert,

/// Signed-and-enveloped-data content type
Crl,

/// Digested-data content type
Secret,

/// Encrypted-data content type
SafeContents,
}

impl<'a> DecodeValue<'a> for BagType {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<BagType> {
ObjectIdentifier::decode_value(reader, header)?.try_into()
}
}

impl EncodeValue for BagType {
fn value_len(&self) -> der::Result<Length> {
ObjectIdentifier::from(*self).value_len()
}

fn encode_value(&self, writer: &mut dyn Writer) -> der::Result<()> {
ObjectIdentifier::from(*self).encode_value(writer)
}
}

impl FixedTag for BagType {
const TAG: Tag = Tag::ObjectIdentifier;
}

impl From<BagType> for ObjectIdentifier {
fn from(content_type: BagType) -> ObjectIdentifier {
match content_type {
BagType::Key => crate::PKCS_12_KEY_BAG_OID,
BagType::Pkcs8 => crate::PKCS_12_PKCS8_KEY_BAG_OID,
BagType::Cert => crate::PKCS_12_CERT_BAG_OID,
BagType::Crl => crate::PKCS_12_CRL_BAG_OID,
BagType::Secret => crate::PKCS_12_SECRET_BAG_OID,
BagType::SafeContents => crate::PKCS_12_SAFE_CONTENTS_BAG_OID,
}
}
}

impl TryFrom<ObjectIdentifier> for BagType {
type Error = der::Error;

fn try_from(oid: ObjectIdentifier) -> der::Result<Self> {
match oid {
crate::PKCS_12_KEY_BAG_OID => Ok(Self::Key),
crate::PKCS_12_PKCS8_KEY_BAG_OID => Ok(Self::Pkcs8),
crate::PKCS_12_CERT_BAG_OID => Ok(Self::Cert),
crate::PKCS_12_CRL_BAG_OID => Ok(Self::Crl),
crate::PKCS_12_SECRET_BAG_OID => Ok(Self::Secret),
crate::PKCS_12_SAFE_CONTENTS_BAG_OID => Ok(Self::SafeContents),
_ => Err(ErrorKind::OidUnknown { oid }.into()),
}
}
}
19 changes: 19 additions & 0 deletions pkcs12/src/cert_bag_content.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use der::{asn1::OctetString, Sequence, ValueOrd};

use crate::cert_type::CertType;

/// ```text
/// CertBag ::= SEQUENCE {
/// certId BAG-TYPE.&id ({CertTypes}),
/// certValue [0] EXPLICIT BAG-TYPE.&Type ({CertTypes}{@certId})
/// }
/// ```
#[derive(Clone, Debug, Eq, PartialEq, Sequence, ValueOrd)]
pub struct CertBagContent {
/// the cert id
pub id: CertType,

/// the cert value
#[asn1(context_specific = "0", tag_mode = "EXPLICIT", optional = "true")]
pub bytes: Option<OctetString>,
}
63 changes: 63 additions & 0 deletions pkcs12/src/cert_type.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
use core::cmp::Ordering;

use der::asn1::ObjectIdentifier;
use der::{
DecodeValue, EncodeValue, ErrorKind, FixedTag, Header, Length, Reader, Tag, ValueOrd, Writer,
};

/// Indicates the type of content.
#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub enum CertType {
/// Plain data content type
X509,

/// Signed-data content type
Sdsi,
}

impl<'a> DecodeValue<'a> for CertType {
fn decode_value<R: Reader<'a>>(reader: &mut R, header: Header) -> der::Result<CertType> {
ObjectIdentifier::decode_value(reader, header)?.try_into()
}
}

impl EncodeValue for CertType {
fn value_len(&self) -> der::Result<Length> {
ObjectIdentifier::from(*self).value_len()
}

fn encode_value(&self, writer: &mut dyn Writer) -> der::Result<()> {
ObjectIdentifier::from(*self).encode_value(writer)
}
}

impl FixedTag for CertType {
const TAG: Tag = Tag::ObjectIdentifier;
}

impl From<CertType> for ObjectIdentifier {
fn from(content_type: CertType) -> ObjectIdentifier {
match content_type {
CertType::X509 => crate::PKCS_12_X509_CERT_OID,
CertType::Sdsi => crate::PKCS_12_SDSI_CERT_OID,
}
}
}

impl TryFrom<ObjectIdentifier> for CertType {
type Error = der::Error;

fn try_from(oid: ObjectIdentifier) -> der::Result<Self> {
match oid {
crate::PKCS_12_X509_CERT_OID => Ok(Self::X509),
crate::PKCS_12_SDSI_CERT_OID => Ok(Self::Sdsi),
_ => Err(ErrorKind::OidUnknown { oid }.into()),
}
}
}

impl ValueOrd for CertType {
fn value_cmp(&self, other: &Self) -> der::Result<Ordering> {
Ok(self.cmp(other))
}
}
Loading