import datetime
import synta
import synta.cms as cms
import synta.ext as ext
import synta.oids as oids
def section(title):
print(f"\n{'─' * 60}\n{title}\n{'─' * 60}")
def _strip_explicit0(data: bytes) -> bytes:
inner = synta.Decoder(data, synta.Encoding.DER).decode_explicit_tag(0)
return inner.remaining_bytes()
def _make_ca():
key = synta.PrivateKey.generate_ec("P-256")
name = synta.NameBuilder().common_name("CMS Example CA").build()
now = datetime.datetime(2025, 1, 1, tzinfo=datetime.timezone.utc)
later = datetime.datetime(2027, 1, 1, tzinfo=datetime.timezone.utc)
cert = (
synta.CertificateBuilder()
.issuer_name(name).subject_name(name)
.public_key(key.public_key).serial_number(1)
.not_valid_before_utc(now).not_valid_after_utc(later)
.add_extension(str(oids.BASIC_CONSTRAINTS), True, ext.basic_constraints(ca=True))
.sign(key, "sha256")
)
return key, cert
def demo_attached_signature():
section("Attached (encapsulating) SignedData")
key, cert = _make_ca()
content = b"The quick brown fox jumps over the lazy dog."
try:
ci_der = (
cms.SignedDataBuilder(content)
.add_signer(key, cert.to_der(), hash_algorithm="sha256")
.add_cert(cert.to_der())
.build()
)
except (NotImplementedError, AttributeError) as e:
print(f" Skipped: {e}")
return
print(f" ContentInfo DER: {len(ci_der)} bytes")
ci = cms.ContentInfo.from_der(ci_der)
print(f" content_type_oid: {ci.content_type_oid}")
assert ci.content_type_oid == cms.ID_SIGNED_DATA
sd = cms.SignedData.from_der(_strip_explicit0(ci.content))
print(f" SignedData version : {sd.version}")
print(f" encapContentType : {sd.encap_content_type}")
print(f" encapContent len : {len(sd.encap_content or b'')} bytes")
print(f" signer count : {len(sd.signer_infos)}")
for si in sd.signer_infos:
print(f" SignerInfo digest alg: {si.digest_algorithm_oid}")
print(f" SignerInfo sig alg : {si.signature_algorithm_oid}")
def demo_detached_signature():
section("Detached SignedData")
key, cert = _make_ca()
content = b"Content whose hash is signed but not embedded."
try:
ci_der = (
cms.SignedDataBuilder(content, detached=True)
.add_signer(key, cert.to_der(), hash_algorithm="sha256")
.build()
)
except (NotImplementedError, AttributeError) as e:
print(f" Skipped: {e}")
return
print(f" Detached ContentInfo DER: {len(ci_der)} bytes")
ci = cms.ContentInfo.from_der(ci_der)
sd = cms.SignedData.from_der(_strip_explicit0(ci.content))
print(f" encap_content (should be None): {sd.encap_content!r}")
assert sd.encap_content is None
def demo_multiple_hash_algorithms():
section("SHA-256 vs SHA-384 digest")
key, cert = _make_ca()
content = b"Compare digest sizes."
for hash_alg in ("sha256", "sha384"):
try:
ci_der = (
cms.SignedDataBuilder(content)
.add_signer(key, cert.to_der(), hash_algorithm=hash_alg)
.build()
)
ci = cms.ContentInfo.from_der(ci_der)
sd = cms.SignedData.from_der(_strip_explicit0(ci.content))
si = sd.signer_infos[0]
print(f" hash_alg={hash_alg:6s} digest_oid={si.digest_algorithm_oid}")
except (NotImplementedError, AttributeError) as e:
print(f" {hash_alg}: skipped ({e})")
def main():
print("=" * 60)
print("CMS SignedData builder")
print("=" * 60)
demo_attached_signature()
demo_detached_signature()
demo_multiple_hash_algorithms()
print("\nAll CMS SignedData examples completed.")
if __name__ == "__main__":
main()