synta 0.1.11

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# 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:

| OID | Name |
|---|---|
| `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);
```