synta 0.2.3

ASN.1 parser, decoder, and encoder library with DER/BER support and C FFI
Documentation
# X.509 PKI


This page documents the X.509 PKI APIs: certificates, CRLs, CSRs, OCSP
responses, PEM encoding/decoding, and PKCS#7 / PKCS#12 container formats.

All getter functions that return `SyntaByteArray` with `owned == 0` return
**borrowed** slices pointing directly into the parsed object.  The data is
valid while the parent handle is alive.  Do not call `synta_byte_array_free()`
on borrowed arrays.

## Certificate API

### synta_certificate_parse_der

Parse an X.509 certificate from DER bytes.  Returns NULL on error.

```c
SyntaCertificate *synta_certificate_parse_der(const uint8_t *data, uintptr_t len);
```

**Memory:** Must be freed with `synta_certificate_free()`.

### synta_certificate_free

```c
void synta_certificate_free(SyntaCertificate *cert);
```

### Certificate Getters

```c
/* Version: v1=0, v2=1, v3=2 */
SyntaErrorCode synta_certificate_get_version(const SyntaCertificate *cert,
                                              int64_t *out);

/* Serial number, issuer DN, subject DN โ€” borrowed SyntaByteArray (owned == 0) */
SyntaErrorCode synta_certificate_get_serial_number(const SyntaCertificate *cert,
                                                    SyntaByteArray *out);
SyntaErrorCode synta_certificate_get_issuer_der(const SyntaCertificate *cert,
                                                 SyntaByteArray *out);
SyntaErrorCode synta_certificate_get_subject_der(const SyntaCertificate *cert,
                                                  SyntaByteArray *out);

/* Signature algorithm OID as a dotted-decimal string.
   Pass (cert, NULL, 0) to query the required buffer length (including NUL).
   The OID is computed and cached on first call; repeated calls are allocation-free. */
uintptr_t synta_certificate_get_signature_algorithm(const SyntaCertificate *cert,
                                                     char *buffer,
                                                     uintptr_t buffer_len);

/* Raw DER bytes of the signature AlgorithmIdentifier โ€” borrowed SyntaByteArray */
SyntaErrorCode synta_certificate_get_signature_algorithm_der(
    const SyntaCertificate *cert, SyntaByteArray *out);
SyntaErrorCode synta_certificate_get_outer_signature_algorithm_der(
    const SyntaCertificate *cert, SyntaByteArray *out);
```

**Example:**
```c
SyntaCertificate *cert = synta_certificate_parse_der(der, der_len);
if (!cert) {
    fprintf(stderr, "%s\n", synta_get_last_error_message());
    return 1;
}

SyntaByteArray subject = {0};
synta_certificate_get_subject_der(cert, &subject);
/* subject.owned == 0: do not free */

uintptr_t needed = synta_certificate_get_signature_algorithm(cert, NULL, 0);
char sig_alg[64];
if (needed <= sizeof(sig_alg))
    synta_certificate_get_signature_algorithm(cert, sig_alg, sizeof(sig_alg));

synta_certificate_free(cert);
```

## CRL API

Parse and inspect X.509 Certificate Revocation Lists (RFC 5280 ยง5).

```c
/* Parse from DER or PEM (first block only); returns NULL on error */
SyntaCrl *synta_crl_parse_der(const uint8_t *data, uintptr_t len);
SyntaCrl *synta_crl_parse_pem(const uint8_t *data, uintptr_t len);
void synta_crl_free(SyntaCrl *crl);

/* All getters return borrowed SyntaByteArray (owned == 0) */
SyntaErrorCode synta_crl_get_issuer_der(const SyntaCrl *crl, SyntaByteArray *out);
SyntaErrorCode synta_crl_get_signature_algorithm_der(const SyntaCrl *crl,
                                                       SyntaByteArray *out);
SyntaErrorCode synta_crl_get_signature_value_der(const SyntaCrl *crl,
                                                   SyntaByteArray *out);
SyntaErrorCode synta_crl_get_this_update_der(const SyntaCrl *crl, SyntaByteArray *out);

/* nextUpdate: out->len == 0 when absent */
SyntaErrorCode synta_crl_get_next_update_der(const SyntaCrl *crl, SyntaByteArray *out);

/* Number of revokedCertificates entries (0 when absent or empty) */
SyntaErrorCode synta_crl_get_revoked_count(const SyntaCrl *crl, uintptr_t *out);
```

## CSR API

Parse and inspect PKCS#10 Certificate Signing Requests (RFC 2986).

```c
/* Parse from DER or PEM (first block only); returns NULL on error */
SyntaCsr *synta_csr_parse_der(const uint8_t *data, uintptr_t len);
SyntaCsr *synta_csr_parse_pem(const uint8_t *data, uintptr_t len);
void synta_csr_free(SyntaCsr *csr);

/* All getters return borrowed SyntaByteArray (owned == 0) */
SyntaErrorCode synta_csr_get_version(const SyntaCsr *csr, int64_t *out);
SyntaErrorCode synta_csr_get_subject_der(const SyntaCsr *csr, SyntaByteArray *out);
SyntaErrorCode synta_csr_get_signature_algorithm_der(const SyntaCsr *csr,
                                                       SyntaByteArray *out);
SyntaErrorCode synta_csr_get_signature_der(const SyntaCsr *csr, SyntaByteArray *out);
SyntaErrorCode synta_csr_get_public_key_der(const SyntaCsr *csr, SyntaByteArray *out);
```

## OCSP API

Parse and inspect OCSP responses (RFC 6960).

```c
/* Parse from DER; returns NULL on error */
SyntaOcsp *synta_ocsp_parse_der(const uint8_t *data, uintptr_t len);
void synta_ocsp_free(SyntaOcsp *ocsp);

/* Numeric status: 0=successful, 1=malformedRequest, 2=internalError,
   3=tryLater, 5=sigRequired, 6=unauthorized */
SyntaErrorCode synta_ocsp_get_status_code(const SyntaOcsp *ocsp, int32_t *out);

/* Status as NUL-terminated string โ€” size-query pattern (pass NULL to get length) */
uintptr_t synta_ocsp_get_status(const SyntaOcsp *ocsp,
                                  char *buffer, uintptr_t buffer_len);

/* responseType OID string (size-query pattern; absent when status != successful) */
uintptr_t synta_ocsp_get_response_type_oid(const SyntaOcsp *ocsp,
                                             char *buffer, uintptr_t buffer_len);

/* OCTET STRING content of responseBytes (out->len == 0 when absent) */
SyntaErrorCode synta_ocsp_get_response_bytes_der(const SyntaOcsp *ocsp,
                                                   SyntaByteArray *out);
```

## PEM API

Dependency-free PEM encode/decode following RFC 7468.

```c
/* Decode all PEM blocks; returns opaque SyntaDerList, or NULL on error */
SyntaDerList *synta_pem_to_der(const uint8_t *data, uintptr_t len);
void synta_der_list_free(SyntaDerList *list);
uintptr_t synta_der_list_count(const SyntaDerList *list);

/* Get the index-th DER entry as a borrowed SyntaByteArray */
SyntaErrorCode synta_der_list_get_der(const SyntaDerList *list, uintptr_t index,
                                       SyntaByteArray *out);

/* Encode DER as a PEM block; returns owned SyntaByteArray (must free) */
SyntaByteArray synta_der_to_pem(const uint8_t *data, uintptr_t len,
                                  const char *label);
```

## PKCS#7 and PKCS#12 API

Extract X.509 certificates from container formats.

### synta_read_pki_file

Auto-detect encoding (PEM, PKCS#7, PKCS#12, or raw DER) and return every
X.509 certificate as a DER blob.  Recommended when the input format is
unknown in advance.

```c
SyntaDerList *synta_read_pki_file(const uint8_t *data, uintptr_t len,
                                   const uint8_t *password,
                                   uintptr_t password_len);
```

**Example:**
```c
SyntaDerList *list = synta_read_pki_file(buf, n, NULL, 0);
if (!list) { fprintf(stderr, "%s\n", synta_get_last_error_message()); }
uintptr_t count = synta_der_list_count(list);
for (uintptr_t i = 0; i < count; i++) {
    SyntaByteArray der = {0};
    synta_der_list_get_der(list, i, &der);
    /* use der.data / der.len */
}
synta_der_list_free(list);
```

### synta_pkcs7_certs_from_der

```c
SyntaDerList *synta_pkcs7_certs_from_der(const uint8_t *data, uintptr_t len);
```

### synta_pkcs7_certs_from_pem

```c
SyntaDerList *synta_pkcs7_certs_from_pem(const uint8_t *data, uintptr_t len);
```

### synta_pkcs12_certs_from_der

Extract DER certificates from a PKCS#12 PFX archive.  `password` may be NULL
for unencrypted archives.  Encrypted bags require the library to be built with
the `openssl` feature.

```c
SyntaDerList *synta_pkcs12_certs_from_der(const uint8_t *data, uintptr_t len,
                                            const uint8_t *password,
                                            uintptr_t password_len);
```