# CMS
Parse and inspect Cryptographic Message Syntax (CMS, RFC 5652) structures:
`SignedData`, `EnvelopedData`, `EncryptedData`, and `DigestedData`.
The recommended entry point is `synta_cms_content_info_parse_der`, which parses
the outer `ContentInfo` SEQUENCE and gives access to the inner content type
through borrowed pointers.
**Ownership model:** Pointers returned by `synta_cms_content_info_get0_*`
functions are **borrowed** from the `SyntaCmsContentInfo` handle. Do not
free them separately. Free only the `SyntaCmsContentInfo` itself with
`synta_cms_content_info_free()`.
## ContentInfo API
### synta_cms_content_info_parse_der
Parse a DER-encoded `ContentInfo` SEQUENCE (RFC 5652 §3). Returns NULL on error.
```c
SyntaCmsContentInfo *synta_cms_content_info_parse_der(const uint8_t *data,
uintptr_t len);
```
**Memory:** Must be freed with `synta_cms_content_info_free()`.
**Example:**
```c
SyntaCmsContentInfo *ci = synta_cms_content_info_parse_der(buf, len);
if (!ci) {
fprintf(stderr, "%s\n", synta_get_last_error_message());
return 1;
}
/* ... access inner content ... */
synta_cms_content_info_free(ci);
```
### synta_cms_content_info_free
```c
void synta_cms_content_info_free(SyntaCmsContentInfo *ci);
```
Safe to call with NULL.
### synta_cms_content_info_get_content_type
Return the `contentType` OID string using the size-query pattern: call with
`buffer == NULL` to get the required length (including NUL), then call again
with an allocated buffer.
```c
uintptr_t synta_cms_content_info_get_content_type(const SyntaCmsContentInfo *ci,
char *buffer,
uintptr_t buffer_len);
```
Known content type OIDs:
| `1.2.840.113549.1.7.1` | `id-data` |
| `1.2.840.113549.1.7.2` | `id-signedData` |
| `1.2.840.113549.1.7.3` | `id-envelopedData` |
| `1.2.840.113549.1.7.5` | `id-digestedData` |
| `1.2.840.113549.1.7.6` | `id-encryptedData` |
### get0 Functions
```c
/* Non-NULL only when contentType == id-signedData */
const SyntaCmsSignedData *synta_cms_content_info_get0_signed_data(
const SyntaCmsContentInfo *ci);
/* Non-NULL only when contentType == id-envelopedData */
const SyntaCmsEnvelopedData *synta_cms_content_info_get0_enveloped_data(
const SyntaCmsContentInfo *ci);
/* Non-NULL only when contentType == id-encryptedData */
const SyntaCmsEncryptedData *synta_cms_content_info_get0_encrypted_data(
const SyntaCmsContentInfo *ci);
/* Non-NULL only when contentType == id-digestedData */
const SyntaCmsDigestedData *synta_cms_content_info_get0_digested_data(
const SyntaCmsContentInfo *ci);
```
## SignedData API
Obtain a `SyntaCmsSignedData *` via
`synta_cms_content_info_get0_signed_data`. The pointer is borrowed from the
`SyntaCmsContentInfo` and must not be freed separately.
```c
/* CMS version field */
SyntaErrorCode synta_cms_signed_data_get_version(
const SyntaCmsSignedData *sd, int64_t *out);
/* encapContentInfo contentType OID (size-query pattern) */
uintptr_t synta_cms_signed_data_get_encap_content_type(
const SyntaCmsSignedData *sd, char *buffer, uintptr_t buffer_len);
/* encapContentInfo eContent raw bytes (borrowed; out->len==0 if absent) */
SyntaErrorCode synta_cms_signed_data_get_encap_content(
const SyntaCmsSignedData *sd, SyntaByteArray *out);
/* Embedded certificates as DER (borrowed; out->len==0 if absent) */
SyntaErrorCode synta_cms_signed_data_get_certificates_der(
const SyntaCmsSignedData *sd, SyntaByteArray *out);
/* CRLs DER (borrowed; out->len==0 if absent) */
SyntaErrorCode synta_cms_signed_data_get_crls_der(
const SyntaCmsSignedData *sd, SyntaByteArray *out);
/* Number of SignerInfo entries */
SyntaErrorCode synta_cms_signed_data_get_signer_info_count(
const SyntaCmsSignedData *sd, uintptr_t *out);
/* DER bytes for the index-th SignerInfo (borrowed) */
SyntaErrorCode synta_cms_signed_data_get_signer_info_der(
const SyntaCmsSignedData *sd, uintptr_t index, SyntaByteArray *out);
```
## SignerInfo API
Parse an individual `SignerInfo` structure (RFC 5652 §5.3) from its DER bytes.
Obtain the DER bytes from `synta_cms_signed_data_get_signer_info_der`.
```c
SyntaCmsSignerInfo *synta_cms_signer_info_parse_der(const uint8_t *data,
uintptr_t len);
void synta_cms_signer_info_free(SyntaCmsSignerInfo *si);
SyntaErrorCode synta_cms_signer_info_get_version(
const SyntaCmsSignerInfo *si, int64_t *out);
/* SID: IssuerAndSerialNumber or SubjectKeyIdentifier DER */
SyntaErrorCode synta_cms_signer_info_get_sid_der(
const SyntaCmsSignerInfo *si, SyntaByteArray *out);
/* digestAlgorithm AlgorithmIdentifier DER */
SyntaErrorCode synta_cms_signer_info_get_digest_algorithm_der(
const SyntaCmsSignerInfo *si, SyntaByteArray *out);
/* digestAlgorithm OID string (size-query pattern) */
uintptr_t synta_cms_signer_info_get_digest_algorithm_oid(
const SyntaCmsSignerInfo *si, char *buffer, uintptr_t buffer_len);
/* signedAttrs DER (out->len==0 if absent) */
SyntaErrorCode synta_cms_signer_info_get_signed_attrs_der(
const SyntaCmsSignerInfo *si, SyntaByteArray *out);
/* signatureAlgorithm AlgorithmIdentifier DER */
SyntaErrorCode synta_cms_signer_info_get_signature_algorithm_der(
const SyntaCmsSignerInfo *si, SyntaByteArray *out);
/* signatureAlgorithm OID string (size-query pattern) */
uintptr_t synta_cms_signer_info_get_signature_algorithm_oid(
const SyntaCmsSignerInfo *si, char *buffer, uintptr_t buffer_len);
/* signature bytes */
SyntaErrorCode synta_cms_signer_info_get_signature(
const SyntaCmsSignerInfo *si, SyntaByteArray *out);
/* unsignedAttrs DER (out->len==0 if absent) */
SyntaErrorCode synta_cms_signer_info_get_unsigned_attrs_der(
const SyntaCmsSignerInfo *si, SyntaByteArray *out);
```
## EnvelopedData API
Obtain via `synta_cms_content_info_get0_enveloped_data`; the pointer is
borrowed and must not be freed.
```c
SyntaErrorCode synta_cms_enveloped_data_get_version(
const SyntaCmsEnvelopedData *ed, int64_t *out);
/* All RecipientInfo entries as a single DER blob */
SyntaErrorCode synta_cms_enveloped_data_get_recipient_infos_der(
const SyntaCmsEnvelopedData *ed, SyntaByteArray *out);
/* encryptedContentInfo contentType OID (size-query pattern) */
uintptr_t synta_cms_enveloped_data_get_content_type(
const SyntaCmsEnvelopedData *ed, char *buffer, uintptr_t buffer_len);
/* contentEncryptionAlgorithm AlgorithmIdentifier DER */
SyntaErrorCode synta_cms_enveloped_data_get_content_encryption_algorithm_der(
const SyntaCmsEnvelopedData *ed, SyntaByteArray *out);
/* contentEncryptionAlgorithm OID string (size-query pattern) */
uintptr_t synta_cms_enveloped_data_get_content_encryption_algorithm_oid(
const SyntaCmsEnvelopedData *ed, char *buffer, uintptr_t buffer_len);
/* encryptedContent bytes (out->len==0 if absent) */
SyntaErrorCode synta_cms_enveloped_data_get_encrypted_content(
const SyntaCmsEnvelopedData *ed, SyntaByteArray *out);
```
## EncryptedData API
Obtain via `synta_cms_content_info_get0_encrypted_data` (borrowed pointer from
a `SyntaCmsContentInfo`). The returned pointer is valid while the parent
`SyntaCmsContentInfo` is alive and must **not** be freed separately.
```c
SyntaErrorCode synta_cms_encrypted_data_get_version(
const SyntaCmsEncryptedData *ed, int64_t *out);
/* contentType OID (size-query pattern) */
uintptr_t synta_cms_encrypted_data_get_content_type(
const SyntaCmsEncryptedData *ed, char *buffer, uintptr_t buffer_len);
/* contentEncryptionAlgorithm AlgorithmIdentifier DER */
SyntaErrorCode synta_cms_encrypted_data_get_content_encryption_algorithm_der(
const SyntaCmsEncryptedData *ed, SyntaByteArray *out);
/* contentEncryptionAlgorithm OID string (size-query pattern) */
uintptr_t synta_cms_encrypted_data_get_content_encryption_algorithm_oid(
const SyntaCmsEncryptedData *ed, char *buffer, uintptr_t buffer_len);
/* encryptedContent bytes (out->len==0 if absent) */
SyntaErrorCode synta_cms_encrypted_data_get_encrypted_content(
const SyntaCmsEncryptedData *ed, SyntaByteArray *out);
```
### synta_cms_encrypted_data_decrypt
Decrypt the `EncryptedData` content under a raw symmetric key. Requires the
library to be built with the `openssl` Cargo feature.
```c
SyntaErrorCode synta_cms_encrypted_data_decrypt(const SyntaCmsEncryptedData *ed,
const uint8_t *key, uintptr_t key_len,
SyntaByteArray *out);
```
Returns plaintext as an owned `SyntaByteArray`. Caller must call
`synta_byte_array_free()` when done.
### synta_cms_encrypted_data_create
Encrypt plaintext under a key and produce a DER-encoded `EncryptedData`
SEQUENCE. A fresh random IV is generated for each call. Requires the
`openssl` feature.
```c
SyntaErrorCode synta_cms_encrypted_data_create(
const uint8_t *plaintext, uintptr_t plaintext_len,
const uint8_t *key, uintptr_t key_len,
const uint8_t *content_type_oid_der, uintptr_t content_type_oid_der_len,
const uint8_t *enc_alg_oid_der, uintptr_t enc_alg_oid_der_len,
SyntaByteArray *der_out);
```
**Example:**
```c
/* AES-128-CBC OID: 2.16.840.1.101.3.4.1.2 */
static const uint8_t AES128_CBC_OID[] = {
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x01, 0x02
};
uint8_t key[16] = { /* 128-bit key */ };
SyntaByteArray der = {0};
SyntaErrorCode rc = synta_cms_encrypted_data_create(
plaintext, plaintext_len, key, sizeof(key),
NULL, 0, /* id-data content type */
AES128_CBC_OID, sizeof(AES128_CBC_OID),
&der);
if (rc == SyntaErrorCode_Success) {
/* use der.data / der.len */
synta_byte_array_free(&der);
}
```
## DigestedData API
Obtain via `synta_cms_content_info_get0_digested_data`; the pointer is borrowed.
```c
SyntaErrorCode synta_cms_digested_data_get_version(
const SyntaCmsDigestedData *dd, int64_t *out);
/* digestAlgorithm AlgorithmIdentifier DER */
SyntaErrorCode synta_cms_digested_data_get_digest_algorithm_der(
const SyntaCmsDigestedData *dd, SyntaByteArray *out);
/* digestAlgorithm OID string (size-query pattern) */
uintptr_t synta_cms_digested_data_get_digest_algorithm_oid(
const SyntaCmsDigestedData *dd, char *buffer, uintptr_t buffer_len);
/* encapContentInfo contentType OID (size-query pattern) */
uintptr_t synta_cms_digested_data_get_encap_content_type(
const SyntaCmsDigestedData *dd, char *buffer, uintptr_t buffer_len);
/* encapContentInfo eContent raw bytes (out->len==0 if absent) */
SyntaErrorCode synta_cms_digested_data_get_encap_content(
const SyntaCmsDigestedData *dd, SyntaByteArray *out);
/* digest OCTET STRING bytes */
SyntaErrorCode synta_cms_digested_data_get_digest(
const SyntaCmsDigestedData *dd, SyntaByteArray *out);
```