use std::time::Duration;
use cms::builder::{SignedDataBuilder, SignerInfoBuilder};
use cms::cert::CertificateChoices;
use cms::signed_data::{EncapsulatedContentInfo, SignerIdentifier};
use const_oid::db::rfc5911::ID_DATA;
use const_oid::db::rfc5912::ID_SHA_256;
use der::{Decode, Encode};
use rsa::pkcs1v15::{Signature, SigningKey};
use rsa::pkcs8::DecodePrivateKey;
use rsa::RsaPrivateKey;
use sha2::{Digest, Sha256};
use spki::AlgorithmIdentifierOwned;
use x509_cert::Certificate;
use crate::net::SigningTransport;
use crate::Result;
const SIGNER_CERT_DER: &[u8] = include_bytes!("pki/testdata/test_signer_cert.der");
const SIGNER_KEY_DER: &[u8] = include_bytes!("pki/testdata/test_signer_key.der");
#[must_use]
pub(crate) fn signer_certificate() -> Certificate {
Certificate::from_der(SIGNER_CERT_DER).expect("committed test certificate must parse")
}
#[must_use]
pub(crate) fn sign_cms_detached(content: &[u8]) -> Vec<u8> {
let private_key =
RsaPrivateKey::from_pkcs8_der(SIGNER_KEY_DER).expect("committed test key must parse");
let signing_key = SigningKey::<Sha256>::new(private_key);
let certificate = signer_certificate();
let sid = SignerIdentifier::IssuerAndSerialNumber(cms::cert::IssuerAndSerialNumber {
issuer: certificate.tbs_certificate.issuer.clone(),
serial_number: certificate.tbs_certificate.serial_number.clone(),
});
let digest_algorithm = AlgorithmIdentifierOwned {
oid: ID_SHA_256,
parameters: None,
};
let encap = EncapsulatedContentInfo {
econtent_type: ID_DATA,
econtent: None,
};
let message_digest = Sha256::digest(content);
let signer_info = SignerInfoBuilder::new(
&signing_key,
sid,
digest_algorithm.clone(),
&encap,
Some(&message_digest),
)
.expect("signer info builder must accept a detached digest");
let content_info = SignedDataBuilder::new(&encap)
.add_digest_algorithm(digest_algorithm)
.expect("digest algorithm must be accepted")
.add_certificate(CertificateChoices::Certificate(certificate))
.expect("certificate must be accepted")
.add_signer_info::<SigningKey<Sha256>, Signature>(signer_info)
.expect("signing must succeed")
.build()
.expect("SignedData must assemble");
content_info
.to_der()
.expect("assembled SignedData must encode")
}
pub(crate) struct TestSigner;
impl SigningTransport for TestSigner {
fn sign_data(&self, data: &[u8], _: &str, _: &str, _: Duration) -> Result<Vec<u8>> {
Ok(sign_cms_detached(data))
}
fn sign_hash(&self, hash: &[u8], _: &str, _: &str, _: Duration) -> Result<Vec<u8>> {
Ok(sign_cms_detached(hash))
}
fn sign_pdf_detached(&self, pdf: &[u8], _: &str, _: &str, _: Duration) -> Result<Vec<u8>> {
Ok(sign_cms_detached(pdf))
}
}