import datetime
import traceback
import pytest
import synta
import synta.cms as cms
import synta.ext as ext
import synta.oids as oids
def _make_ca():
key = synta.PrivateKey.generate_ec("P-256")
name = synta.NameBuilder().common_name("CMS Test 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 _skip_if_unavailable(exc):
if isinstance(exc, (ValueError, NotImplementedError, AttributeError)):
pytest.skip(f"SignedDataBuilder not available: {exc}")
raise exc
def test_signed_data_builder_basic():
key, cert = _make_ca()
try:
ci_der = (
cms.SignedDataBuilder(b"Hello, world!")
.add_signer(key, cert.to_der())
.build()
)
except Exception as e:
_skip_if_unavailable(e)
assert isinstance(ci_der, bytes)
assert ci_der[0] == 0x30
def test_signed_data_builder_is_content_info():
key, cert = _make_ca()
try:
ci_der = (
cms.SignedDataBuilder(b"Test content")
.add_signer(key, cert.to_der(), hash_algorithm="sha256")
.build()
)
except Exception as e:
_skip_if_unavailable(e)
ci = cms.ContentInfo.from_der(ci_der)
assert ci.content_type_oid == cms.ID_SIGNED_DATA
def test_signed_data_builder_with_embedded_cert():
key, cert = _make_ca()
cert_der = cert.to_der()
try:
ci_der = (
cms.SignedDataBuilder(b"data with cert")
.add_signer(key, cert_der)
.add_cert(cert_der)
.build()
)
except Exception as e:
_skip_if_unavailable(e)
ci = cms.ContentInfo.from_der(ci_der)
assert ci.content_type_oid == cms.ID_SIGNED_DATA
def test_signed_data_builder_sha384():
key, cert = _make_ca()
try:
ci_der = (
cms.SignedDataBuilder(b"SHA-384 content")
.add_signer(key, cert.to_der(), hash_algorithm="sha384")
.build()
)
except Exception as e:
_skip_if_unavailable(e)
assert isinstance(ci_der, bytes)
def _strip_explicit0(data: bytes) -> bytes:
inner = synta.Decoder(data, synta.Encoding.DER).decode_explicit_tag(0)
return inner.remaining_bytes()
def test_signed_data_builder_detached():
key, cert = _make_ca()
try:
ci_der = (
cms.SignedDataBuilder(b"Detached content", detached=True)
.add_signer(key, cert.to_der())
.build()
)
except Exception as e:
_skip_if_unavailable(e)
assert isinstance(ci_der, bytes)
ci = cms.ContentInfo.from_der(ci_der)
assert ci.content_type_oid == cms.ID_SIGNED_DATA
sd = cms.SignedData.from_der(_strip_explicit0(ci.content))
assert sd.encap_content is None
def test_signed_data_builder_no_signers_raises():
with pytest.raises((ValueError, AttributeError)):
cms.SignedDataBuilder(b"data").build()
def main():
tests = [
test_signed_data_builder_basic,
test_signed_data_builder_is_content_info,
test_signed_data_builder_with_embedded_cert,
test_signed_data_builder_sha384,
test_signed_data_builder_detached,
test_signed_data_builder_no_signers_raises,
]
passed = failed = skipped = 0
for t in tests:
try:
t()
print(f" ok {t.__name__}")
passed += 1
except pytest.skip.Exception as e:
print(f" skip {t.__name__}: {e}")
skipped += 1
except Exception as e:
print(f" FAIL {t.__name__}: {e}")
traceback.print_exc()
failed += 1
print(f"\n{passed} passed, {skipped} skipped, {failed} failed")
if failed:
raise SystemExit(1)
if __name__ == "__main__":
main()