# PEM Parser

```c
#define FIO_PEM
#include "fio-stl.h"
```

PEM wraps DER bytes in Base64 armor:

```text
-----BEGIN <label>-----
<base64 DER>
-----END <label>-----
```

This module extracts PEM blocks, decodes certificates, and parses private keys used by the TLS/X.509 helpers.

**Limit:** encrypted private keys are not supported. If the key asks for a password, this parser politely leaves the room.

## Supported Labels

- `CERTIFICATE`
- `PRIVATE KEY` (PKCS#8)
- `RSA PRIVATE KEY` (legacy PKCS#1)
- `EC PRIVATE KEY` (legacy SEC1)

Private-key parsing supports RSA, P-256, and Ed25519 where the required crypto modules are available.

## Types

### `fio_pem_key_type_e`

```c
typedef enum {
  FIO_PEM_KEY_UNKNOWN = 0,
  FIO_PEM_KEY_RSA = 1,
  FIO_PEM_KEY_ECDSA_P256 = 2,
  FIO_PEM_KEY_ED25519 = 3,
} fio_pem_key_type_e;
```

### `fio_pem_s`

```c
typedef struct {
  const uint8_t *der;
  size_t der_len;
  const char *label;
  size_t label_len;
} fio_pem_s;
```

A decoded PEM block. `der` points into the caller-provided DER output buffer. `label` points into the original PEM input.

### `fio_pem_private_key_s`

```c
typedef struct fio_pem_private_key_s fio_pem_private_key_s;
```

Parsed private-key material. The active union member depends on `type`:

- RSA: fixed-size byte arrays for `n`, `e`, `d`, optional `p`, `q`, `dP`, `dQ`, and `qInv`, each with a length.
- P-256: 32-byte private scalar, optional 65-byte uncompressed public key.
- Ed25519: 32-byte seed, optional 32-byte public key.

Call `fio_pem_private_key_clear` when done.

## API

### `fio_pem_parse`

```c
SFUNC size_t fio_pem_parse(fio_pem_s *out,
                           uint8_t *der_buf,
                           size_t der_buf_len,
                           const char *pem_data,
                           size_t pem_len);
```

Finds the next PEM block, decodes its Base64 body into `der_buf`, and fills `out`.

Returns the number of bytes consumed from `pem_data`, or `0` on error. To parse a file with multiple PEM blocks, advance by the returned count and call again.

### `fio_pem_parse_certificate`

```c
SFUNC int fio_pem_parse_certificate(fio_x509_cert_s *cert,
                                    const char *pem_data,
                                    size_t pem_len);
```

Finds a `CERTIFICATE` block, decodes it, and parses the DER certificate with the X.509 parser. Returns `0` on success, `-1` on error.

Requires the X.509 module for the certificate parse.

### `fio_pem_parse_private_key`

```c
SFUNC int fio_pem_parse_private_key(fio_pem_private_key_s *key,
                                    const char *pem_data,
                                    size_t pem_len);
```

Parses a PEM private key into `key`.

Supported forms:

| PEM label | Format | Supported keys |
| --- | --- | --- |
| `PRIVATE KEY` | PKCS#8 | RSA, P-256, Ed25519 |
| `RSA PRIVATE KEY` | PKCS#1 | RSA |
| `EC PRIVATE KEY` | SEC1 | P-256 |

Returns `0` on success, `-1` on unsupported format, missing dependency, encrypted key, or malformed input.

### `fio_pem_get_certificate_der`

```c
SFUNC size_t fio_pem_get_certificate_der(uint8_t *der_out,
                                         size_t der_out_len,
                                         const char *pem_data,
                                         size_t pem_len);
```

Extracts a `CERTIFICATE` block as raw DER without parsing the X.509 structure. Returns the DER length written, or `0` on error.

### `fio_pem_private_key_clear`

```c
FIO_IFUNC void fio_pem_private_key_clear(fio_pem_private_key_s *key);
```

Securely zeros a parsed private-key structure.

## Example: Extract Certificate DER

```c
#define FIO_PEM
#include "fio-stl.h"

size_t load_der(uint8_t *der, size_t der_cap, const char *pem, size_t pem_len) {
  return fio_pem_get_certificate_der(der, der_cap, pem, pem_len);
}
```

## Example: Parse Multiple Blocks

```c
#define FIO_PEM
#include "fio-stl.h"

void scan_pem(const char *pem, size_t len) {
  uint8_t der[8192];
  while (len) {
    fio_pem_s block;
    size_t used = fio_pem_parse(&block, der, sizeof(der), pem, len);
    if (!used)
      break;

    /* block.label / block.label_len name the PEM type. */
    /* block.der / block.der_len hold the decoded DER bytes. */

    pem += used;
    len -= used;
  }
}
```

## Dependency Notes

- Generic `fio_pem_parse` needs only the PEM/base64 helpers.
- Certificate parsing needs X.509 support.
- Private key parsing uses ASN.1, and RSA/P-256/Ed25519 support depends on the matching crypto headers.

------------------------------------------------------------
