#![cfg(feature = "builder")]
use crate::cert::CertificateChoices;
use crate::content_info::{CmsVersion, ContentInfo};
use crate::enveloped_data::{
EncryptedContentInfo, EncryptedKey, EnvelopedData, KekIdentifier, KeyTransRecipientInfo,
OriginatorIdentifierOrKey, OriginatorInfo, RecipientIdentifier, RecipientInfo, RecipientInfos,
UserKeyingMaterial,
};
use crate::revocation::{RevocationInfoChoice, RevocationInfoChoices};
use crate::signed_data::{
CertificateSet, DigestAlgorithmIdentifiers, EncapsulatedContentInfo, SignatureValue,
SignedAttributes, SignedData, SignerIdentifier, SignerInfo, SignerInfos, UnsignedAttributes,
};
use aes::{Aes128, Aes192, Aes256};
use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use cipher::block_padding::Pkcs7;
use cipher::rand_core::{CryptoRng, CryptoRngCore, RngCore};
use cipher::BlockEncryptMut;
use cipher::{Key, KeyIvInit, KeySizeUser};
use const_oid::ObjectIdentifier;
use core::cmp::Ordering;
use core::fmt;
use der::asn1::{BitString, OctetStringRef, SetOfVec};
use der::oid::db::DB;
use der::Tag::OctetString;
use der::{Any, AnyRef, DateTime, Decode, Encode, ErrorKind, Tag};
use digest::Digest;
use rsa::Pkcs1v15Encrypt;
use sha2::digest;
use signature::digest::DynDigest;
use signature::{Keypair, Signer};
use spki::{AlgorithmIdentifierOwned, DynSignatureAlgorithmIdentifier, SignatureBitStringEncoding};
use std::time::SystemTime;
use std::vec;
use x509_cert::attr::{Attribute, AttributeValue, Attributes};
use x509_cert::builder::Builder;
use zeroize::Zeroize;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Asn1(der::Error),
PublicKey(spki::Error),
Signature(signature::Error),
Builder(String),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::Asn1(err) => write!(f, "ASN.1 error: {}", err),
Error::PublicKey(err) => write!(f, "public key error: {}", err),
Error::Signature(err) => write!(f, "signature error: {}", err),
Error::Builder(message) => write!(f, "builder error: {message}"),
}
}
}
impl From<der::Error> for Error {
fn from(err: der::Error) -> Error {
Error::Asn1(err)
}
}
impl From<spki::Error> for Error {
fn from(err: spki::Error) -> Error {
Error::PublicKey(err)
}
}
impl From<signature::Error> for Error {
fn from(err: signature::Error) -> Error {
Error::Signature(err)
}
}
type Result<T> = core::result::Result<T, Error>;
pub struct SignerInfoBuilder<'s, S> {
signer: &'s S,
sid: SignerIdentifier,
digest_algorithm: AlgorithmIdentifierOwned,
signed_attributes: Option<Vec<Attribute>>,
unsigned_attributes: Option<Vec<Attribute>>,
encapsulated_content_info: &'s EncapsulatedContentInfo,
external_message_digest: Option<&'s [u8]>,
}
impl<'s, S> SignerInfoBuilder<'s, S>
where
S: Keypair + DynSignatureAlgorithmIdentifier,
{
pub fn new(
signer: &'s S,
sid: SignerIdentifier,
digest_algorithm: AlgorithmIdentifierOwned,
encapsulated_content_info: &'s EncapsulatedContentInfo,
external_message_digest: Option<&'s [u8]>,
) -> Result<Self> {
Ok(SignerInfoBuilder {
signer,
sid,
digest_algorithm,
signed_attributes: None,
unsigned_attributes: None,
encapsulated_content_info,
external_message_digest,
})
}
pub fn add_signed_attribute(&mut self, signed_attribute: Attribute) -> Result<&mut Self> {
if let Some(signed_attributes) = &mut self.signed_attributes {
signed_attributes.push(signed_attribute);
} else {
self.signed_attributes = Some(vec![signed_attribute]);
}
Ok(self)
}
pub fn add_unsigned_attribute(&mut self, unsigned_attribute: Attribute) -> Result<&mut Self> {
if let Some(unsigned_attributes) = &mut self.unsigned_attributes {
unsigned_attributes.push(unsigned_attribute);
} else {
self.unsigned_attributes = Some(vec![unsigned_attribute]);
}
Ok(self)
}
pub fn version(&self) -> CmsVersion {
match self.sid {
SignerIdentifier::IssuerAndSerialNumber(_) => CmsVersion::V1,
SignerIdentifier::SubjectKeyIdentifier(_) => CmsVersion::V3,
}
}
}
impl<'s, S> Builder for SignerInfoBuilder<'s, S>
where
S: Keypair + DynSignatureAlgorithmIdentifier,
{
type Signer = S;
type Output = SignerInfo;
fn signer(&self) -> &Self::Signer {
self.signer
}
fn finalize(&mut self) -> der::Result<Vec<u8>> {
let message_digest = match self.external_message_digest {
Some(external_content_digest) => {
if self.encapsulated_content_info.econtent.is_some() {
return Err(der::Error::from(ErrorKind::Failed));
}
Some(external_content_digest.to_vec())
}
None => match &self.encapsulated_content_info.econtent {
None => {
None
}
Some(content) => {
let mut hasher = get_hasher(&self.digest_algorithm).ok_or_else(|| {
der::Error::from(ErrorKind::Failed)
})?;
let content_value = content.value();
hasher.update(content_value);
Some(hasher.finalize_reset().to_vec())
}
},
};
if self.signed_attributes.is_none() {
self.signed_attributes = Some(vec![]);
}
let signed_attributes = self
.signed_attributes
.as_mut()
.expect("Signed attributes must be present.");
if let Some(message_digest) = message_digest {
signed_attributes.push(
create_message_digest_attribute(&message_digest)
.map_err(|_| der::Error::from(ErrorKind::Failed))?,
);
let econtent_type = self.encapsulated_content_info.econtent_type;
let signed_attributes_content_type = signed_attributes.iter().find(|attr| {
attr.oid.cmp(&const_oid::db::rfc5911::ID_CONTENT_TYPE) == Ordering::Equal
});
if let Some(signed_attributes_content_type) = signed_attributes_content_type {
if signed_attributes_content_type.oid != econtent_type {
return Err(der::Error::from(ErrorKind::Failed));
}
} else {
signed_attributes.push(
create_content_type_attribute(econtent_type)
.map_err(|_| der::Error::from(ErrorKind::Failed))?,
);
}
}
let signed_attributes = SignedAttributes::try_from(signed_attributes.to_owned())
.map_err(|_| der::Error::from(ErrorKind::Failed))?;
let mut signed_attributes_der = Vec::new();
signed_attributes.encode_to_vec(&mut signed_attributes_der)?;
Ok(signed_attributes_der)
}
fn assemble(
self,
signature: BitString,
) -> core::result::Result<Self::Output, x509_cert::builder::Error> {
let signed_attrs = self.signed_attributes.as_ref().map(|signed_attributes| {
SignedAttributes::try_from(signed_attributes.to_owned()).unwrap()
});
let unsigned_attrs = self
.unsigned_attributes
.as_ref()
.map(|unsigned_attributes| {
UnsignedAttributes::try_from(unsigned_attributes.to_owned()).unwrap()
});
let signature_value =
SignatureValue::new(signature.raw_bytes()).map_err(x509_cert::builder::Error::from)?;
let signature_algorithm = self.signer.signature_algorithm_identifier()?;
Ok(SignerInfo {
version: self.version(),
sid: self.sid.clone(),
digest_alg: self.digest_algorithm,
signed_attrs,
signature_algorithm,
signature: signature_value,
unsigned_attrs,
})
}
}
pub struct SignedDataBuilder<'s> {
digest_algorithms: Vec<AlgorithmIdentifierOwned>,
encapsulated_content_info: &'s EncapsulatedContentInfo,
certificates: Option<Vec<CertificateChoices>>,
crls: Option<Vec<RevocationInfoChoice>>,
signer_infos: Vec<SignerInfo>,
}
impl<'s> SignedDataBuilder<'s> {
pub fn new(encapsulated_content_info: &'s EncapsulatedContentInfo) -> SignedDataBuilder<'s> {
Self {
digest_algorithms: Vec::new(),
encapsulated_content_info,
certificates: None,
crls: None,
signer_infos: Vec::new(),
}
}
pub fn add_digest_algorithm(
&mut self,
digest_algorithm: AlgorithmIdentifierOwned,
) -> Result<&mut Self> {
self.digest_algorithms.push(digest_algorithm);
Ok(self)
}
pub fn add_certificate(&mut self, certificate: CertificateChoices) -> Result<&mut Self> {
if self.certificates.is_none() {
self.certificates = Some(Vec::new());
}
if let Some(certificates) = &mut self.certificates {
certificates.push(certificate);
}
Ok(self)
}
pub fn add_crl(&mut self, crl: RevocationInfoChoice) -> Result<&mut Self> {
if self.crls.is_none() {
self.crls = Some(Vec::new());
}
if let Some(crls) = &mut self.crls {
crls.push(crl);
}
Ok(self)
}
pub fn add_signer_info<S, Signature>(
&mut self,
signer_info_builder: SignerInfoBuilder<'_, S>,
) -> Result<&mut Self>
where
S: Keypair + DynSignatureAlgorithmIdentifier,
S: Signer<Signature>,
Signature: SignatureBitStringEncoding,
{
let signer_info = signer_info_builder
.build::<Signature>()
.map_err(|_| der::Error::from(ErrorKind::Failed))?;
self.signer_infos.push(signer_info);
Ok(self)
}
pub fn build(&mut self) -> Result<ContentInfo> {
let digest_algorithms =
DigestAlgorithmIdentifiers::try_from(self.digest_algorithms.to_owned()).unwrap();
let encap_content_info = self.encapsulated_content_info.clone();
let certificates = self
.certificates
.as_mut()
.map(|certificates| CertificateSet::try_from(certificates.to_owned()).unwrap());
let crls = self
.crls
.as_mut()
.map(|crls| RevocationInfoChoices::try_from(crls.to_owned()).unwrap());
let signer_infos = SignerInfos::try_from(self.signer_infos.clone()).unwrap();
let signed_data = SignedData {
version: self.calculate_version(),
digest_algorithms,
encap_content_info,
certificates,
crls,
signer_infos,
};
let signed_data_der = signed_data.to_der()?;
let content = AnyRef::try_from(signed_data_der.as_slice())?;
let signed_data = ContentInfo {
content_type: const_oid::db::rfc5911::ID_SIGNED_DATA,
content: Any::from(content),
};
Ok(signed_data)
}
fn calculate_version(&self) -> CmsVersion {
let other_certificates_are_present = if let Some(certificates) = &self.certificates {
certificates
.iter()
.any(|certificate| matches!(certificate, CertificateChoices::Other(_)))
} else {
false
};
let v2_certificates_are_present = false;
let v1_certificates_are_present = false;
let other_crls_are_present = if let Some(crls) = &self.crls {
crls.iter().any(|revocation_info_choice| {
matches!(revocation_info_choice, RevocationInfoChoice::Other(_))
})
} else {
false
};
let v3_signer_infos_present = self
.signer_infos
.iter()
.any(|signer_info| signer_info.version == CmsVersion::V3);
let content_not_data =
self.encapsulated_content_info.econtent_type != const_oid::db::rfc5911::ID_DATA;
if other_certificates_are_present || other_crls_are_present {
CmsVersion::V5
} else if v2_certificates_are_present {
CmsVersion::V4
} else if v1_certificates_are_present || v3_signer_infos_present || content_not_data {
CmsVersion::V3
} else {
CmsVersion::V1
}
}
}
pub trait RecipientInfoBuilder {
fn recipient_info_type(&self) -> RecipientInfoType;
fn recipient_info_version(&self) -> CmsVersion;
fn build(&mut self, content_encryption_key: &[u8]) -> Result<RecipientInfo>;
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum RecipientInfoType {
Ktri,
Kari,
Kekri,
Pwri,
Ori,
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum KeyEncryptionInfo {
Rsa(rsa::RsaPublicKey),
}
pub struct KeyTransRecipientInfoBuilder<'a, R>
where
R: CryptoRngCore,
{
pub rid: RecipientIdentifier,
pub key_encryption_info: KeyEncryptionInfo,
rng: &'a mut R,
}
impl<'a, R> KeyTransRecipientInfoBuilder<'a, R>
where
R: CryptoRngCore,
{
pub fn new(
rid: RecipientIdentifier,
key_encryption_info: KeyEncryptionInfo,
rng: &'a mut R,
) -> Result<KeyTransRecipientInfoBuilder<'a, R>> {
Ok(KeyTransRecipientInfoBuilder {
rid,
key_encryption_info,
rng,
})
}
}
impl<'a, R> RecipientInfoBuilder for KeyTransRecipientInfoBuilder<'a, R>
where
R: CryptoRngCore,
{
fn recipient_info_type(&self) -> RecipientInfoType {
RecipientInfoType::Ktri
}
fn recipient_info_version(&self) -> CmsVersion {
match self.rid {
RecipientIdentifier::IssuerAndSerialNumber(_) => CmsVersion::V0,
RecipientIdentifier::SubjectKeyIdentifier(_) => CmsVersion::V2,
}
}
fn build(&mut self, content_encryption_key: &[u8]) -> Result<RecipientInfo> {
let (encrypted_key, key_enc_alg) = match &self.key_encryption_info {
KeyEncryptionInfo::Rsa(recipient_public_key) => (
recipient_public_key
.encrypt(self.rng, Pkcs1v15Encrypt, content_encryption_key)
.map_err(|_| Error::Builder(String::from("Could not encrypt key")))?,
AlgorithmIdentifierOwned {
oid: const_oid::db::rfc5912::RSA_ENCRYPTION,
parameters: None,
},
),
};
let enc_key = EncryptedKey::new(encrypted_key)?;
Ok(RecipientInfo::Ktri(KeyTransRecipientInfo {
version: self.recipient_info_version(),
rid: self.rid.clone(),
key_enc_alg,
enc_key,
}))
}
}
pub struct KeyAgreeRecipientInfoBuilder {
pub originator: OriginatorIdentifierOrKey,
pub ukm: Option<UserKeyingMaterial>,
pub key_enc_alg: AlgorithmIdentifierOwned,
}
impl KeyAgreeRecipientInfoBuilder {
pub fn new(
originator: OriginatorIdentifierOrKey,
ukm: Option<UserKeyingMaterial>,
key_enc_alg: AlgorithmIdentifierOwned,
) -> Result<KeyAgreeRecipientInfoBuilder> {
Ok(KeyAgreeRecipientInfoBuilder {
originator,
ukm,
key_enc_alg,
})
}
}
impl RecipientInfoBuilder for KeyAgreeRecipientInfoBuilder {
fn recipient_info_type(&self) -> RecipientInfoType {
RecipientInfoType::Kari
}
fn recipient_info_version(&self) -> CmsVersion {
CmsVersion::V3
}
fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
Err(Error::Builder(String::from(
"Building KeyAgreeRecipientInfo is not implemented, yet.",
)))
}
}
pub struct KekRecipientInfoBuilder {
pub kek_id: KekIdentifier,
pub key_enc_alg: AlgorithmIdentifierOwned,
}
impl KekRecipientInfoBuilder {
pub fn new(
kek_id: KekIdentifier,
key_enc_alg: AlgorithmIdentifierOwned,
) -> Result<KekRecipientInfoBuilder> {
Ok(KekRecipientInfoBuilder {
kek_id,
key_enc_alg,
})
}
}
impl RecipientInfoBuilder for KekRecipientInfoBuilder {
fn recipient_info_type(&self) -> RecipientInfoType {
RecipientInfoType::Kekri
}
fn recipient_info_version(&self) -> CmsVersion {
CmsVersion::V4
}
fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
Err(Error::Builder(String::from(
"Building KekRecipientInfo is not implemented, yet.",
)))
}
}
pub struct PasswordRecipientInfoBuilder {
pub key_derivation_alg: Option<AlgorithmIdentifierOwned>,
pub key_enc_alg: AlgorithmIdentifierOwned,
}
impl PasswordRecipientInfoBuilder {
pub fn new(
key_derivation_alg: Option<AlgorithmIdentifierOwned>,
key_enc_alg: AlgorithmIdentifierOwned,
) -> Result<PasswordRecipientInfoBuilder> {
Ok(PasswordRecipientInfoBuilder {
key_derivation_alg,
key_enc_alg,
})
}
}
impl RecipientInfoBuilder for PasswordRecipientInfoBuilder {
fn recipient_info_type(&self) -> RecipientInfoType {
RecipientInfoType::Pwri
}
fn recipient_info_version(&self) -> CmsVersion {
CmsVersion::V0
}
fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
Err(Error::Builder(String::from(
"Building PasswordRecipientInfo is not implemented, yet.",
)))
}
}
pub struct OtherRecipientInfoBuilder {
pub ori_type: ObjectIdentifier,
pub ori_value: Any,
}
impl OtherRecipientInfoBuilder {
pub fn new(ori_type: ObjectIdentifier, ori_value: Any) -> Result<OtherRecipientInfoBuilder> {
Ok(OtherRecipientInfoBuilder {
ori_type,
ori_value,
})
}
}
impl RecipientInfoBuilder for OtherRecipientInfoBuilder {
fn recipient_info_type(&self) -> RecipientInfoType {
RecipientInfoType::Ori
}
fn recipient_info_version(&self) -> CmsVersion {
panic!("Ori has no CMSVersion")
}
fn build(&mut self, _content_encryption_key: &[u8]) -> Result<RecipientInfo> {
panic!("Ori has no common build method.")
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum ContentEncryptionAlgorithm {
Aes128Cbc,
Aes192Cbc,
Aes256Cbc,
}
impl ContentEncryptionAlgorithm {
pub fn oid(&self) -> ObjectIdentifier {
match self {
ContentEncryptionAlgorithm::Aes128Cbc => const_oid::db::rfc5911::ID_AES_128_CBC,
ContentEncryptionAlgorithm::Aes192Cbc => const_oid::db::rfc5911::ID_AES_192_CBC,
ContentEncryptionAlgorithm::Aes256Cbc => const_oid::db::rfc5911::ID_AES_256_CBC,
}
}
}
pub struct EnvelopedDataBuilder<'c> {
originator_info: Option<OriginatorInfo>,
recipient_infos: Vec<Box<dyn RecipientInfoBuilder + 'c>>,
unencrypted_content: &'c [u8],
content_encryption_algorithm: ContentEncryptionAlgorithm,
unprotected_attributes: Option<Attributes>,
}
impl<'c> EnvelopedDataBuilder<'c> {
pub fn new(
originator_info: Option<OriginatorInfo>,
unencrypted_content: &'c [u8],
content_encryption_algorithm: ContentEncryptionAlgorithm,
unprotected_attributes: Option<Attributes>,
) -> Result<EnvelopedDataBuilder<'c>> {
Ok(EnvelopedDataBuilder {
originator_info,
recipient_infos: Vec::new(),
unencrypted_content,
content_encryption_algorithm,
unprotected_attributes,
})
}
pub fn add_recipient_info(
&mut self,
recipient_info_builder: impl RecipientInfoBuilder + 'c,
) -> Result<&mut Self> {
self.recipient_infos.push(Box::new(recipient_info_builder));
Ok(self)
}
pub fn build_with_rng(&mut self, rng: &mut impl CryptoRngCore) -> Result<EnvelopedData> {
let (encrypted_content, mut content_encryption_key, content_enc_alg) = encrypt_data(
self.unencrypted_content,
&self.content_encryption_algorithm,
None,
rng,
)?;
let encrypted_content_octetstring = der::asn1::OctetString::new(encrypted_content)?;
let encrypted_content_info = EncryptedContentInfo {
content_type: const_oid::db::rfc5911::ID_DATA, content_enc_alg,
encrypted_content: Some(encrypted_content_octetstring), };
let recipient_infos_vec = self
.recipient_infos
.iter_mut()
.map(|ri| ri.build(&content_encryption_key))
.collect::<Result<Vec<RecipientInfo>>>()?;
content_encryption_key.zeroize();
let recip_infos = RecipientInfos::try_from(recipient_infos_vec).unwrap();
Ok(EnvelopedData {
version: self.calculate_version(),
originator_info: self.originator_info.clone(),
recip_infos,
encrypted_content: encrypted_content_info,
unprotected_attrs: self.unprotected_attributes.clone(),
})
}
fn calculate_version(&self) -> CmsVersion {
let originator_info_present = self.originator_info.is_some();
let other_certificates_present = if let Some(originator_info) = &self.originator_info {
if let Some(certificates) = &originator_info.certs {
certificates
.0
.iter()
.any(|certificate| matches!(certificate, CertificateChoices::Other(_)))
} else {
false
}
} else {
false
};
let other_crls_present = if let Some(originator_info) = &self.originator_info {
if let Some(crls) = &originator_info.crls {
crls.0
.iter()
.any(|crl| matches!(crl, RevocationInfoChoice::Other(_)))
} else {
false
}
} else {
false
};
let v2_certificates_present = false;
let pwri_recipient_info_present = self.recipient_infos.iter().any(|recipient_info| {
matches!(
recipient_info.recipient_info_type(),
RecipientInfoType::Pwri
)
});
let ori_recipient_info_present = self.recipient_infos.iter().any(|recipient_info| {
matches!(recipient_info.recipient_info_type(), RecipientInfoType::Ori)
});
let unprotected_attributes_present = self.unprotected_attributes.is_some();
let all_recipient_infos_are_v0 = self
.recipient_infos
.iter()
.all(|ri| ri.recipient_info_version() == CmsVersion::V0);
if originator_info_present && (other_certificates_present || other_crls_present) {
CmsVersion::V4
} else if (originator_info_present && v2_certificates_present)
|| pwri_recipient_info_present
|| ori_recipient_info_present
{
CmsVersion::V3
} else if !originator_info_present
&& !unprotected_attributes_present
&& all_recipient_infos_are_v0
{
CmsVersion::V0
} else {
CmsVersion::V2
}
}
}
fn get_hasher(
digest_algorithm_identifier: &AlgorithmIdentifierOwned,
) -> Option<Box<dyn DynDigest>> {
let digest_name = DB.by_oid(&digest_algorithm_identifier.oid)?;
match digest_name {
"id-sha1" => Some(Box::new(sha1::Sha1::new())),
"id-sha256" => Some(Box::new(sha2::Sha256::new())),
"id-sha384" => Some(Box::new(sha2::Sha384::new())),
"id-sha512" => Some(Box::new(sha2::Sha512::new())),
"id-sha224" => Some(Box::new(sha2::Sha224::new())),
"id-sha-3-224" => Some(Box::new(sha3::Sha3_224::new())),
"id-sha-3-256" => Some(Box::new(sha3::Sha3_256::new())),
"id-sha-3-384" => Some(Box::new(sha3::Sha3_384::new())),
"id-sha-3-512" => Some(Box::new(sha3::Sha3_512::new())),
_ => None,
}
}
macro_rules! encrypt_block_mode {
($data:expr, $block_mode:ident::$typ:ident<$alg:ident>, $key:expr, $rng:expr, $oid:expr) => {{
let (key, iv) = match $key {
None => $block_mode::$typ::<$alg>::generate_key_iv($rng),
Some(key) => {
if key.len() != $alg::key_size() {
return Err(Error::Builder(String::from(
"Invalid key size for chosen algorithm",
)));
}
(
Key::<$block_mode::$typ<$alg>>::from_slice(key).to_owned(),
$block_mode::$typ::<$alg>::generate_iv($rng),
)
}
};
let encryptor = $block_mode::$typ::<$alg>::new(&key.into(), &iv.into());
Ok((
encryptor.encrypt_padded_vec_mut::<Pkcs7>($data),
key.to_vec(),
AlgorithmIdentifierOwned {
oid: $oid,
parameters: Some(Any::new(OctetString, iv.to_vec())?),
},
))
}};
}
fn encrypt_data<R>(
data: &[u8],
encryption_algorithm_identifier: &ContentEncryptionAlgorithm,
key: Option<&[u8]>,
rng: &mut R,
) -> Result<(Vec<u8>, Vec<u8>, AlgorithmIdentifierOwned)>
where
R: CryptoRng + RngCore,
{
match encryption_algorithm_identifier {
ContentEncryptionAlgorithm::Aes128Cbc => encrypt_block_mode!(
data,
cbc::Encryptor<Aes128>,
key,
rng,
encryption_algorithm_identifier.oid()
),
ContentEncryptionAlgorithm::Aes192Cbc => encrypt_block_mode!(
data,
cbc::Encryptor<Aes192>,
key,
rng,
encryption_algorithm_identifier.oid()
),
ContentEncryptionAlgorithm::Aes256Cbc => encrypt_block_mode!(
data,
cbc::Encryptor<Aes256>,
key,
rng,
encryption_algorithm_identifier.oid()
),
}
}
pub fn create_content_type_attribute(content_type: ObjectIdentifier) -> Result<Attribute> {
let content_type_attribute_value =
AttributeValue::new(Tag::ObjectIdentifier, content_type.as_bytes())?;
let mut values = SetOfVec::new();
values.insert(content_type_attribute_value)?;
let attribute = Attribute {
oid: const_oid::db::rfc5911::ID_CONTENT_TYPE,
values,
};
Ok(attribute)
}
pub fn create_message_digest_attribute(message_digest: &[u8]) -> Result<Attribute> {
let message_digest_der = OctetStringRef::new(message_digest)?;
let message_digest_attribute_value =
AttributeValue::new(OctetString, message_digest_der.as_bytes())?;
let mut values = SetOfVec::new();
values.insert(message_digest_attribute_value)?;
let attribute = Attribute {
oid: const_oid::db::rfc5911::ID_MESSAGE_DIGEST,
values,
};
Ok(attribute)
}
pub fn create_signing_time_attribute() -> Result<Attribute> {
let now = DateTime::from_system_time(SystemTime::now())?;
let tag = if now.year() < 1950 || now.year() > 2049 {
Tag::GeneralizedTime
} else {
Tag::UtcTime
};
let time_der = if tag == Tag::GeneralizedTime {
der::asn1::GeneralizedTime::from_date_time(now).to_der()?
} else {
der::asn1::UtcTime::from_date_time(now)?.to_der()?
};
let signing_time_attribute_value = AttributeValue::from_der(&time_der)?;
let mut values = SetOfVec::<AttributeValue>::new();
values.insert(signing_time_attribute_value)?;
let attribute = Attribute {
oid: const_oid::db::rfc5911::ID_SIGNING_TIME,
values,
};
Ok(attribute)
}