> For the complete documentation index, see [llms.txt](https://docs.akenza.io/akenza.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.akenza.io/akenza.io/get-started/your-data-flow/device-connector/coap/dtls-device-client-certificates.md).

# DTLS Device Client Certificates

This guide walks through generating a Custom **Device Certificate Authority (CA)** and individual **Device Client Certificates** for your devices to achieve mutual DTLS authentication.

#### Prerequisites

* `openssl` 3.x (Verify using `openssl version`)
* A dedicated working directory for your PKI files (e.g., `~/coap-pki/`)

#### Constraints & Requirements

* **Private Key Format:** Private keys must be in PKCS#8 format (`-----BEGIN PRIVATE KEY-----`). OpenSSL generates PKCS#1 by default for RSA -an extra conversion step is required.
* **Device Identity:** The device client certificate's Common Name (CN) is used as the device identity identifier in akenza. Set it to the exact device identifier (e.g. serial number) you want to authenticate. It must match the deviceId used to provision a device in akenza.
* **Cipher Suites:** Both RSA 2048 and ECDSA P-256 are supported. ECDSA produces significantly smaller certificates and is highly recommended for constrained IoT devices.

#### Option A - ECDSA (P-256, recommended)

**1. Create the Device Certificate Authority (CA)**

{% hint style="warning" %}
Never store your Root CA private key on an internet-facing device. Keep it in an offline, air-gapped environment or within a hardware security module (HSM). If the CA key is leaked, an attacker can issue valid certificates for any device identity.
{% endhint %}

{% hint style="info" %}
[Submit](mailto:support@akenza.io) the Device CA certificate file to akenza and also include the akenza device connector id(s) that are in scope for this CA.
{% endhint %}

```
mkdir -p ~/coap-pki && cd ~/coap-pki

# CA private key (PKCS#8 unencrypted)
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 -out ca.key

# Self-signed CA certificate (10-year validity)
openssl req -new -x509 -key ca.key -sha256 -days 3650 \
  -subj "/CN=akenza CoAP CA" \
  -out ca.crt
```

**2. Create a Device Client Certificate**

The CN becomes the device identifier in akenza. Repeat this block for each device.

{% hint style="warning" %}
Store device private keys securely on the hardware (e.g., inside a Secure Element, TPM, or hardware-backed keystore) rather than in plain-text application files where they might be extracted during a physical or remote firmware breach.
{% endhint %}

```
DEVICE_ID="B6.EC.9C.9C.6E.E2"   # <- Must match the device ID in akenza

# Generate client key
openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 \
  -out "client-${DEVICE_ID}.key"

# Generate certificate signing request (CSR)
openssl req -new -key "client-${DEVICE_ID}.key" -sha256 \
  -subj "/CN=${DEVICE_ID}" \
  -out "client-${DEVICE_ID}.csr"

# Sign with your CA
openssl x509 -req -in "client-${DEVICE_ID}.csr" \
  -CA ca.crt -CAkey ca.key -CAcreateserial -sha256 -days 825 \
  -out "client-${DEVICE_ID}.crt"

# Verify validity
openssl verify -CAfile ca.crt "client-${DEVICE_ID}.crt"
```

#### Option B - RSA 2048

**1. Create the Device Certificate Authority (CA)**

{% hint style="warning" %}
Never store your Root CA private key on an internet-facing gateway, server, or device. Keep it in an offline, air-gapped environment or within a hardware security module (HSM). If the CA key is leaked, an attacker can issue valid certificates for any device identity.
{% endhint %}

{% hint style="info" %}
[Submit](mailto:support@akenza.io) the Device CA certificate file to akenza and also include the akenza device connector id(s) that are in scope for this CA.
{% endhint %}

```
mkdir -p ~/coap-pki && cd ~/coap-pki

# CA private key — RSA default output is PKCS#1, convert to PKCS#8
openssl genrsa -out ca-pkcs1.key 2048
openssl pkcs8 -topk8 -nocrypt -in ca-pkcs1.key -out ca.key
rm ca-pkcs1.key

openssl req -new -x509 -key ca.key -sha256 -days 3650 \
  -subj "/CN=akenza CoAP CA" \
  -out ca.crt
```

**2. Create a Device Client Certificate**

{% hint style="warning" %}
Store device private keys securely on the hardware (e.g., inside a Secure Element, TPM, or hardware-backed keystore) rather than in plain-text application files where they might be extracted during a physical or remote firmware breach.
{% endhint %}

```
DEVICE_ID="B6.EC.9C.9C.6E.E2"   # <- Must match the device ID in akenza

# Generate RSA key and convert to PKCS#8
openssl genrsa -out "client-${DEVICE_ID}-pkcs1.key" 2048
openssl pkcs8 -topk8 -nocrypt \
  -in "client-${DEVICE_ID}-pkcs1.key" \
  -out "client-${DEVICE_ID}.key"
rm "client-${DEVICE_ID}-pkcs1.key"

openssl req -new -key "client-${DEVICE_ID}.key" -sha256 \
  -subj "/CN=${DEVICE_ID}" \
  -out "client-${DEVICE_ID}.csr"

openssl x509 -req -in "client-${DEVICE_ID}.csr" \
  -CA ca.crt -CAkey ca.key -CAcreateserial -sha256 -days 825 \
  -out "client-${DEVICE_ID}.crt"

openssl verify -CAfile ca.crt "client-${DEVICE_ID}.crt"
```

### Test the Connection

You can verify the connection utilizing `coap-client` (from the `libcoap` [package](https://libcoap.net/install.html)):

```
# Install via: 'brew install libcoap' or 'apt install libcoap2-bin'
coap-client -m post \
  -e '{"sensor":"temp","value":23.5}' \
  -t "application/json" \
  --cert "client-${DEVICE_ID}.crt" \
  --key  "client-${DEVICE_ID}.key" \
  --ca-file ca.crt \
  "coaps://coap.akenza.io:5684/v3/capture"
```

* **Success Response:** Returns a payload structure like `{"message":"ok","id":"<uuid>"}`.
* **Handshake Failure:** If the certificate validation or handshake fails, the client will timeout without a response, as the gateway silently drops unauthorized requests at the TLS layer.

### Utility Tools

#### Bulk Device Client Certificate Generation

Save this automation script as `gen-certs.sh` to quickly issue device credentials:

```
#!/usr/bin/env bash
set -euo pipefail

CA_CERT=ca.crt
CA_KEY=ca.key
VALIDITY_DAYS=825

for DEVICE_ID in "$@"; do
  echo "Generating certificate for device: ${DEVICE_ID}"

  openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:P-256 \
    -out "client-${DEVICE_ID}.key" 2>/dev/null

  openssl req -new -key "client-${DEVICE_ID}.key" -sha256 \
    -subj "/CN=${DEVICE_ID}" \
    -out "client-${DEVICE_ID}.csr" 2>/dev/null

  openssl x509 -req -in "client-${DEVICE_ID}.csr" \
    -CA "${CA_CERT}" -CAkey "${CA_KEY}" -CAcreateserial -sha256 \
    -days "${VALIDITY_DAYS}" \
    -out "client-${DEVICE_ID}.crt" 2>/dev/null

  rm "client-${DEVICE_ID}.csr"
  echo "  -> client-${DEVICE_ID}.crt / client-${DEVICE_ID}.key"
done
```

Usage: `./gen-certs.sh dev-abc123 dev-def456 dev-ghi789`

#### Inspection Commands

```
# Confirm the Common Name (CN) mapping to a device ID
openssl x509 -in "client-${DEVICE_ID}.crt" -noout -subject

# Confirm client key algorithm details and underlying format structures
openssl pkey -in "client-${DEVICE_ID}.key" -noout -text | head -5

# Verify that the device certificate chains back cleanly to your CA
openssl verify -CAfile ca.crt "client-${DEVICE_ID}.crt"
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.akenza.io/akenza.io/get-started/your-data-flow/device-connector/coap/dtls-device-client-certificates.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
