# SignedData and SignerInfo
## SignedData
Encapsulates signed content plus signer information (RFC 5652 §5).
```python
class SignedData:
@staticmethod
def from_der(data: bytes) -> SignedData: ...
def to_der(self) -> bytes: ...
version: int
encap_content_type: ObjectIdentifier
encap_content: bytes | None # OCTET STRING value bytes
certificates: bytes | None # value bytes of the [0] IMPLICIT CertificateSet (no outer tag/length)
crls: bytes | None # value bytes of the [1] IMPLICIT RevocationInfoChoices (no outer tag/length)
signer_infos: list[SignerInfo]
```
### Usage
```python
from synta.cms import SignedData
import synta
# Parse a PKCS#7 SignedData blob (the [0] EXPLICIT wrapping from ContentInfo is
# handled internally when using synta.load_der_pkcs7_certificates; strip it
# manually if you have a raw ContentInfo).
data = open("message.p7s", "rb").read()
sd = SignedData.from_der(data)
print(f"version: {sd.version}")
print(f"content type: {sd.encap_content_type}")
print(f"signers: {len(sd.signer_infos)}")
# Access embedded certificates
if sd.certificates:
# certificates contains only the value bytes of the CertificateSet (no outer tag/length).
# Individual Certificate SEQUENCES are concatenated; decode them directly:
import synta
dec = synta.Decoder(sd.certificates, synta.Encoding.DER)
while not dec.is_empty():
cert_der = dec.decode_raw_tlv() # one DER Certificate TLV at a time
# Iterate signer infos
for si in sd.signer_infos:
print(f" digest alg: {si.digest_algorithm_oid}")
print(f" signature alg: {si.signature_algorithm_oid}")
```
---
## SignerInfo
Per-signer structure within `SignedData` (RFC 5652 §5.3).
```python
class SignerInfo:
@staticmethod
def from_der(data: bytes) -> SignerInfo: ...
def to_der(self) -> bytes: ...
version: int
sid: bytes
# Raw TLV bytes of the SignerIdentifier CHOICE:
# - SEQUENCE tag (0x30) → issuerAndSerialNumber
# - tag 0x80 → subjectKeyIdentifier
digest_algorithm_oid: ObjectIdentifier
digest_algorithm_params: bytes | None
signature_algorithm_oid: ObjectIdentifier
signature_algorithm_params: bytes | None
signature: bytes
signed_attrs: bytes | None
# Value bytes of the [0] IMPLICIT SignedAttributes (no outer tag/length).
# To hash for signature verification, prepend b'\x31' + DER-encoded length.
unsigned_attrs: bytes | None
# Value bytes of the [1] IMPLICIT UnsignedAttributes (no outer tag/length).
```
### Usage
```python
from synta.cms import SignedData
import synta
sd = SignedData.from_der(data)
for si in sd.signer_infos:
print(f"digest: {si.digest_algorithm_oid}")
print(f"signature: {si.signature_algorithm_oid}")
print(f"sig bytes: {si.signature.hex()}")
if si.signed_attrs:
# signed_attrs contains only the value bytes of the SignedAttributes SET
# (no outer tag or length). To produce a hashable SET TLV for CMS
# signature verification, prepend b'\x31' and a properly DER-encoded
# length header before hashing. The individual Attribute SEQUENCES can
# be iterated directly from the value bytes:
import synta
dec = synta.Decoder(si.signed_attrs, synta.Encoding.DER)
while not dec.is_empty():
attr_tlv = dec.decode_raw_tlv()
# each attr_tlv is a complete Attribute SEQUENCE
```
See also [CMS Overview](overview.md) and [PKCS Loaders](../pki/pkcs-loaders.md) for
`load_der_pkcs7_certificates` which extracts certificates from a `SignedData` automatically.