Skip to content

Commit

Permalink
cms: adds support for AsyncSigner
Browse files Browse the repository at this point in the history
  • Loading branch information
baloo committed Sep 27, 2024
1 parent 0cde010 commit 3dac355
Show file tree
Hide file tree
Showing 4 changed files with 124 additions and 2 deletions.
2 changes: 2 additions & 0 deletions Cargo.lock

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

4 changes: 3 additions & 1 deletion cms/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const-oid = { version = "0.10.0-rc.0", features = ["db"] }

# optional dependencies
aes = { version = "=0.9.0-pre.1", optional = true }
async-signature = { version = "=0.6.0-pre.4", features = ["digest", "rand_core"], optional = true }
cbc = { version = "=0.2.0-pre.1", optional = true }
cipher = { version = "=0.5.0-pre.6", features = ["alloc", "block-padding", "rand_core"], optional = true }
rsa = { version = "=0.10.0-pre.2", optional = true }
Expand All @@ -40,11 +41,12 @@ rand = "0.8.5"
rsa = { version = "=0.10.0-pre.2", features = ["sha2"] }
ecdsa = { version = "=0.17.0-pre.9", features = ["digest", "pem"] }
p256 = "=0.14.0-pre.2"
tokio = { version = "1.40.0", features = ["macros", "rt"] }

[features]
alloc = ["der/alloc"]
std = ["der/std", "spki/std"]
builder = ["aes", "cbc", "cipher", "rsa", "sha1", "sha2", "sha3", "signature", "std", "spki/alloc", "x509-cert/builder", "zeroize"]
builder = ["aes", "async-signature", "cbc", "cipher", "rsa", "sha1", "sha2", "sha3", "signature", "std", "spki/alloc", "x509-cert/builder", "zeroize"]
pem = ["alloc", "der/pem"]

[package.metadata.docs.rs]
Expand Down
48 changes: 47 additions & 1 deletion cms/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use alloc::borrow::ToOwned;
use alloc::boxed::Box;
use alloc::string::String;
use alloc::vec::Vec;
use async_signature::{AsyncRandomizedSigner, AsyncSigner};
use cipher::{
block_padding::Pkcs7,
rand_core::{self, CryptoRng, CryptoRngCore, RngCore},
Expand All @@ -43,7 +44,7 @@ use spki::{
use std::time::SystemTime;
use std::vec;
use x509_cert::attr::{Attribute, AttributeValue, Attributes};
use x509_cert::builder::{self, Builder};
use x509_cert::builder::{self, AsyncBuilder, Builder};
use zeroize::Zeroize;

/// Error type
Expand Down Expand Up @@ -404,6 +405,51 @@ impl<'s> SignedDataBuilder<'s> {
Ok(self)
}

/// Add a signer info. The signature will be calculated. Note that the encapsulated content
/// must not be changed after the first signer info was added.
pub async fn add_signer_info_async<S, Signature>(
&mut self,
signer_info_builder: SignerInfoBuilder<'_>,
signer: &S,
) -> Result<&mut Self>
where
S: Keypair + DynSignatureAlgorithmIdentifier,
S: AsyncSigner<Signature>,
S::VerifyingKey: EncodePublicKey,
Signature: SignatureBitStringEncoding,
{
let signer_info = signer_info_builder
.build_async::<S, Signature>(signer)
.await
.map_err(|_| der::Error::from(ErrorKind::Failed))?;
self.signer_infos.push(signer_info);

Ok(self)
}

/// Add a signer info. The signature will be calculated. Note that the encapsulated content
/// must not be changed after the first signer info was added.
pub async fn add_signer_info_with_rng_async<S, Signature>(
&mut self,
signer_info_builder: SignerInfoBuilder<'_>,
signer: &S,
rng: &mut impl CryptoRngCore,
) -> Result<&mut Self>
where
S: Keypair + DynSignatureAlgorithmIdentifier,
S: AsyncRandomizedSigner<Signature>,
S::VerifyingKey: EncodePublicKey,
Signature: SignatureBitStringEncoding,
{
let signer_info = signer_info_builder
.build_with_rng_async::<S, Signature>(signer, rng)
.await
.map_err(|_| der::Error::from(ErrorKind::Failed))?;
self.signer_infos.push(signer_info);

Ok(self)
}

/// This method returns a `ContentInfo` of type `signedData`.
pub fn build(&mut self) -> Result<ContentInfo> {
let digest_algorithms =
Expand Down
72 changes: 72 additions & 0 deletions cms/tests/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -569,3 +569,75 @@ fn test_create_signing_attribute() {
"Invalid tag number in signing time attribute value"
);
}

#[tokio::test]
async fn async_builder() {
// Make some content
let content = EncapsulatedContentInfo {
econtent_type: const_oid::db::rfc5911::ID_DATA,
econtent: Some(
Any::new(
Tag::OctetString,
OctetString::new(vec![48]).unwrap().to_der().unwrap(),
)
.unwrap(),
),
};
// Create multiple signer infos
let signer_1 = rsa_pkcs1v15_signer();
let digest_algorithm = AlgorithmIdentifierOwned {
oid: const_oid::db::rfc5912::ID_SHA_256,
parameters: None,
};
let external_message_digest = None;
let signer_info_builder_1 = SignerInfoBuilder::new(
signer_identifier(1),
digest_algorithm.clone(),
&content,
external_message_digest,
)
.expect("Could not create RSA SignerInfoBuilder");

let signer_3 = rsa_pss_signer();
let digest_algorithm = AlgorithmIdentifierOwned {
oid: const_oid::db::rfc5912::ID_SHA_256,
parameters: None,
};
let external_message_digest = None;
let signer_info_builder_3 = SignerInfoBuilder::new(
signer_identifier(3),
digest_algorithm.clone(),
&content,
external_message_digest,
)
.expect("Could not create RSA SignerInfoBuilder");

let mut builder = SignedDataBuilder::new(&content);

let signed_data_pkcs7 = builder
.add_digest_algorithm(digest_algorithm)
.expect("could not add a digest algorithm")
.add_signer_info_async::<pkcs1v15::SigningKey<Sha256>, rsa::pkcs1v15::Signature>(
signer_info_builder_1,
&signer_1,
)
.await
.expect("error adding PKCS1v15 RSA signer info")
.add_signer_info_with_rng_async::<pss::SigningKey<Sha256>, pss::Signature>(
signer_info_builder_3,
&signer_3,
&mut OsRng,
)
.await
.expect("error adding PKCS1v15 RSA signer info")
.build()
.expect("building signed data failed");
let signed_data_pkcs7_der = signed_data_pkcs7
.to_der()
.expect("conversion of signed data to DER failed.");
println!(
"{}",
pem_rfc7468::encode_string("PKCS7", LineEnding::LF, &signed_data_pkcs7_der)
.expect("PEM encoding of signed data DER failed")
);
}

0 comments on commit 3dac355

Please sign in to comment.