synta 0.1.5

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# API Overview


## Header File

```c
#include <synta.h>
```

The header is auto-generated by cbindgen from the Rust source.  Include it
once; all types, constants, and function prototypes are in the global
namespace with the `Synta` prefix.

## Linking

```bash
# With pkg-config (recommended)
gcc myapp.c $(pkg-config --cflags --libs csynta) -o myapp

# With CMake
find_package(Synta REQUIRED)
target_link_libraries(myapp Synta::Synta)

# Manual
gcc myapp.c -I/path/to/include -L/path/to/lib -lcsynta -lpthread -ldl -lm -o myapp
```

## Encoding Rules

```c
typedef enum SyntaEncoding {
    SyntaEncoding_Der = 0,
    SyntaEncoding_Ber = 1,
    SyntaEncoding_Cer = 2,
} SyntaEncoding;
```

Pass `SyntaEncoding_Der` for strict DER (X.509, CMS, PKCS formats).
Pass `SyntaEncoding_Ber` for lenient BER parsing.

## Error Model

Every function that can fail returns `SyntaErrorCode`.  On failure:

1. The return value is a non-zero `SyntaErrorCode`.
2. A detailed message is stored in thread-local storage and can be retrieved
   with `synta_get_last_error_message()`.

Functions that return a pointer (e.g. `synta_decoder_new`,
`synta_certificate_parse_der`) return `NULL` on failure.

```c
SyntaCertificate *cert = synta_certificate_parse_der(data, len);
if (!cert) {
    fprintf(stderr, "Parse error: %s\n", synta_get_last_error_message());
    return -1;
}
```

See [Errors](errors.md) for the full error code table and error functions.

## Thread Safety

- **Encoder / Decoder handles** — not thread-safe.  Each thread must use its
  own encoder and decoder instances.
- **Error messages** — thread-local.  `synta_get_last_error_message()` and
  `synta_clear_last_error()` are thread-safe between threads.
- **PKI handles** (`SyntaCertificate *`, `SyntaCrl *`, etc.) — read-only
  operations (getters) are thread-safe after construction; mutations require
  external synchronization.
- **Helper functions** (`synta_oid_*`, `synta_integer_*`, etc.) — thread-safe
  for read-only operations; mutations require external synchronization.

## Core Types

| C Type | Description |
|--------|-------------|
| `SyntaDecoder *` | Opaque decoder handle |
| `SyntaEncoder *` | Opaque encoder handle |
| `SyntaByteArray` | Borrowed or owned byte slice (16 bytes: `data`, `len: uint32_t`, `owned: uint32_t`) |
| `SyntaDecoderConfig` | DoS-protection limits (max depth, elements, length; all `uintptr_t`) |
| `SyntaEncoding` | `SyntaEncoding_Der`, `SyntaEncoding_Ber`, `SyntaEncoding_Cer` |
| `SyntaErrorCode` | Return code; `SyntaErrorCode_Success == 0` |
| `SyntaInteger *` | Opaque arbitrary-precision integer |
| `SyntaOctetString *` | Opaque byte string |
| `SyntaObjectIdentifier *` | Opaque OID |
| `SyntaCertificate *` | Opaque parsed X.509 certificate |
| `SyntaCrl *` | Opaque parsed X.509 CRL (RFC 5280 §5) |
| `SyntaCsr *` | Opaque parsed PKCS#10 CSR (RFC 2986) |
| `SyntaOcsp *` | Opaque parsed OCSP response (RFC 6960) |
| `SyntaDerList *` | Opaque list of DER byte vectors (PEM decode result) |
| `SyntaCmsContentInfo *` | Opaque CMS ContentInfo handle |

## SyntaByteArray

`SyntaByteArray` is a 16-byte struct:

```c
typedef struct {
    const uint8_t *data;
    uint32_t       len;
    uint32_t       owned;  /* 0 = borrowed, non-zero = owned */
} SyntaByteArray;
```

When `owned != 0`, the caller must call `synta_byte_array_free()` to release
the allocation.  When `owned == 0`, the bytes are borrowed from a parent
object (e.g. a decoded certificate) and must not be freed independently.

```c
SyntaByteArray ba = {0};
if (synta_certificate_get_subject_der(cert, &ba) == SyntaErrorCode_Success) {
    /* ba.owned == 0: borrowed, valid while cert is alive */
    process(ba.data, ba.len);
    /* do NOT call synta_byte_array_free(&ba) */
}
```

See [Memory Management](../memory.md) for the full ownership model.