README.md

# grisp_keychain

Common layer to access secrets and identities on GRiSP devices. The app provides a basic module limited to filesystem based handling, but it can be configured to use backends like [grisp_cryptoauth](https://github.com/grisp/grisp_cryptoauth).

## Build

    $ rebar3 compile

## Configuration

The `grisp_keychain` application provides flexible configuration options for TLS certificate and key management. Configuration is done through the application environment (typically in `sys.config`).

### Configuration

The implementation module to use for the keychain API.
Defaults to `grisp_keychain_filesystem`.

```erlang
{grisp_keychain, [
    {api_module, grisp_keychain_filesystem}
]}
```

### TLS Configuration Options for `grisp_keychain_filesystem`

#### `tls_use_client_certificate`
**Type:** `boolean()`
**Default:** `true`
**Description:** Enable or disable the use of client certificates for TLS connections.

```erlang
{tls_use_client_certificate, false}
```

#### `tls_verify`
**Type:** `verify_none | verify_peer`
**Default:** `verify_peer`
**Description:** Set the TLS verification mode.
- `verify_peer`: Verify the server certificate (recommended for production)
- `verify_none`: Skip server certificate verification (useful for testing)

```erlang
{tls_verify, verify_peer}
```

### Certificate and Key Paths

#### `client_certs`
**Type:** `path_spec()`
**Required:** Yes (if `tls_use_client_certificate` is `true`)
**Description:** Path to client certificate(s). Can point to a single file or a directory containing multiple certificates.

```erlang
{client_certs, {priv, my_app, "certs/client.pem"}}
```

#### `client_key`
**Type:** `path_spec()`
**Required:** Yes (if `tls_use_client_certificate` is `true`)
**Description:** Path to the client private key file.

```erlang
{client_key, {priv, my_app, "keys/client.key"}}
```

#### `tls_client_trusted_certs`
**Type:** `path_spec()`
**Default:** `{priv, grisp_keychain, ""}`
**Description:** Path to trusted client certificates (CA certificates that can verify the client cert).

```erlang
{tls_client_trusted_certs, {priv, my_app, "certs/ca"}}
```

#### `tls_server_trusted_certs`
**Type:** `path_spec()`
**Optional**
**Description:** Base path to server trusted certificates. When provided with a domain name, the system will look for certificates in `<base_path>/<domain_name>`.

```erlang
{tls_server_trusted_certs, {priv, my_app, "certs/servers"}}
```

### Certificate Callback Functions

#### `tls_client_trusted_certs_cb`
**Type:** `callback_spec()`
**Optional**
**Description:** Callback function that returns additional client trusted certificates.

```erlang
{tls_client_trusted_certs_cb, {my_module, get_client_certs}}
% or with arguments:
{tls_client_trusted_certs_cb, {my_module, get_certs, [client]}}
```

#### `tls_server_trusted_certs_cb`
**Type:** `callback_spec()`
**Optional**
**Description:** Callback function that returns additional server trusted certificates.

```erlang
{tls_server_trusted_certs_cb, {my_module, get_server_certs}}
```

### Path Specification Format

Paths can be specified in multiple formats:

1. **Absolute path as string:**
   ```erlang
   "/absolute/path/to/cert.pem"
   ```

2. **Binary path:**
   ```erlang
   <<"/absolute/path/to/cert.pem">>
   ```

3. **Tuple format (relative to application directory):**
   ```erlang
   {priv, AppName, RelativePath}  % Relative to priv directory
   {test, AppName, RelativePath}  % Relative to test directory
   ```

### Callback Specification Format

Callbacks can be specified as:

1. **Module and function:**
   ```erlang
   {ModuleName, FunctionName}
   ```

2. **Module, function, and arguments:**
   ```erlang
   {ModuleName, FunctionName, [Arg1, Arg2, ...]}
   ```

The callback function should return a list of certificates in DER format.

## API Usage

### `grisp_keychain:tls_options/1`

Get TLS options for a specific domain.

```erlang
Options = grisp_keychain:tls_options(<<"example.com">>),
ssl:connect("example.com", 443, Options).
```

The domain parameter can be:
- `atom()` - e.g., `'example.com'`
- `string()` - e.g., `"example.com"`
- `binary()` - e.g., `<<"example.com">>`
- `undefined` - disables Server Name Indication

### `grisp_keychain:read_cert/2`

Read the primary client certificate in DER format.

```erlang
DerCert = grisp_keychain:read_cert(primary, der).
```

## Example Configuration

```erlang
{grisp_keychain, [
    {api_module, grisp_keychain_filesystem},
    {tls_use_client_certificate, true},
    {tls_verify, verify_peer},
    {client_certs, {priv, my_app, "certs/client.pem"}},
    {client_key, {priv, my_app, "keys/client-key.pem"}},
    {tls_client_trusted_certs, {priv, my_app, "certs/ca"}},
    {tls_server_trusted_certs, {priv, my_app, "certs/servers"}}
]}
```

## Certificate File Formats

- **Certificates:** PEM format (`.pem` or `.crt` extensions)
- **Keys:** PEM format, unencrypted only
- **Directory loading:** When a directory path is provided, all `.pem` and `.crt` files in that directory will be loaded