Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

EST Endpoints

kipuka implements the six operations defined by RFC 7030 (Enrollment over Secure Transport) and the clarifications in RFC 8951. All EST operations are served under the /.well-known/est/ path on the EST listener (default port 9443).

Base URL and EST labels

The base URL for all operations is:

https://<host>:9443/.well-known/est/

When EST labels are configured, a label segment is inserted between /est/ and the operation name to route the request to a specific CA:

https://<host>:9443/.well-known/est/{label}/simpleenroll

For example, if two labels are configured – iot-fleet backed by a hardware-HSM CA and corp-devices backed by a Dogtag CA – clients target the appropriate CA by including the label in the URL:

/.well-known/est/iot-fleet/simpleenroll
/.well-known/est/corp-devices/simpleenroll

Requests to the unlabeled path (/.well-known/est/simpleenroll) use the default CA. See EST Labels for configuration details.

Content types

EST uses CMS (PKCS #7) encoding throughout. All request and response bodies are base64-encoded DER unless otherwise noted.

DirectionContent-TypeEncoding
CSR requestapplication/pkcs10base64-encoded DER PKCS #10
Certificate responseapplication/pkcs7-mime; smime-type=certs-onlybase64-encoded DER PKCS #7
CMC requestapplication/pkcs7-mime; smime-type=CMC-requestbase64-encoded DER CMS
CMC responseapplication/pkcs7-mime; smime-type=CMC-responsebase64-encoded DER CMS
Server keygen responsemultipart/mixedSee Server-Side Key Generation
CSR attributesapplication/csrattrsbase64-encoded DER

GET /cacerts

Retrieve the CA certificate chain. This operation requires no authentication and is typically the first call a client makes to bootstrap trust.

Authentication: None

Response: 200 OK with Content-Type application/pkcs7-mime; smime-type=certs-only. The body is a base64-encoded PKCS #7 certs-only message containing the CA certificate chain in order from the issuing CA to the root.

Example

# Fetch the CA chain (no auth required)
curl -o cacerts.p7b \
  https://est.example.com:9443/.well-known/est/cacerts

# Decode the base64 PKCS#7 and view the certificates
base64 -d cacerts.p7b | openssl pkcs7 -inform DER -print_certs -noout

# Save decoded certificates to a PEM file
base64 -d cacerts.p7b | openssl pkcs7 -inform DER -print_certs -out ca-chain.pem

With an EST label:

curl -o cacerts.p7b \
  https://est.example.com:9443/.well-known/est/iot-fleet/cacerts

POST /simpleenroll

Submit a PKCS #10 certificate signing request (CSR) for initial enrollment. The server validates the request, signs the certificate using the configured CA, and returns the signed certificate in a PKCS #7 response.

Authentication: OTP (HTTP Basic) or mTLS (client certificate).

For initial enrollment of a device that does not yet have a certificate, use OTP authentication. For enrollment of a device that already holds a valid certificate from a trusted CA, use mTLS.

Request body: base64-encoded DER PKCS #10 CSR, Content-Type application/pkcs10.

Response: 200 OK with Content-Type application/pkcs7-mime; smime-type=certs-only.

Example with OTP authentication

# Generate a private key and CSR
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
  -keyout device.key -out device.csr -nodes \
  -subj "/CN=device-001.example.com"

# Base64-encode the CSR (DER format)
openssl req -in device.csr -outform DER | base64 > device.csr.b64

# Enroll using OTP (entity-id:otp-value as HTTP Basic auth)
curl -X POST \
  --cacert ca-chain.pem \
  -u "device-001:a7f3b9c2d1e4" \
  -H "Content-Type: application/pkcs10" \
  --data-binary @device.csr.b64 \
  -o enrolled.p7b \
  https://est.example.com:9443/.well-known/est/simpleenroll

# Decode the response to get the signed certificate
base64 -d enrolled.p7b | openssl pkcs7 -inform DER -print_certs -out device.crt

Example with mTLS authentication

# Enroll using an existing client certificate for authentication
curl -X POST \
  --cacert ca-chain.pem \
  --cert existing-device.crt \
  --key existing-device.key \
  -H "Content-Type: application/pkcs10" \
  --data-binary @device.csr.b64 \
  -o enrolled.p7b \
  https://est.example.com:9443/.well-known/est/simpleenroll

Example with an EST label

curl -X POST \
  --cacert ca-chain.pem \
  -u "device-001:a7f3b9c2d1e4" \
  -H "Content-Type: application/pkcs10" \
  --data-binary @device.csr.b64 \
  -o enrolled.p7b \
  https://est.example.com:9443/.well-known/est/corp-devices/simpleenroll

POST /simplereenroll

Renew or rekey an existing certificate. The client authenticates with its current certificate via mTLS and submits a new CSR. The server validates that the CSR subject matches the authenticated client certificate (or that the change is permitted by policy) and returns a fresh certificate.

Authentication: mTLS required. The client must present the certificate being renewed.

Request body: base64-encoded DER PKCS #10 CSR, Content-Type application/pkcs10.

Response: 200 OK with Content-Type application/pkcs7-mime; smime-type=certs-only.

Example

# Generate a new CSR using the existing key (or a new key for rekeying)
openssl req -new -key device.key -out renew.csr -nodes \
  -subj "/CN=device-001.example.com"

# Base64-encode the CSR
openssl req -in renew.csr -outform DER | base64 > renew.csr.b64

# Re-enroll using the current device certificate for mTLS auth
curl -X POST \
  --cacert ca-chain.pem \
  --cert device.crt \
  --key device.key \
  -H "Content-Type: application/pkcs10" \
  --data-binary @renew.csr.b64 \
  -o renewed.p7b \
  https://est.example.com:9443/.well-known/est/simplereenroll

# Decode the renewed certificate
base64 -d renewed.p7b | openssl pkcs7 -inform DER -print_certs -out device-renewed.crt

POST /fullcmc

Full Certificate Management over CMS (RFC 5272). This operation accepts a full CMC request wrapped in a CMS SignedData structure and returns a full CMC response. Full CMC supports advanced features not available through simple enrollment: certificate revocation, key update with proof-of-possession, and batch operations.

Authentication: The CMC request itself carries authentication (the CMS SignedData is signed by the requester). mTLS may also be required depending on server policy.

Request body: base64-encoded DER CMS, Content-Type application/pkcs7-mime; smime-type=CMC-request.

Response: 200 OK with Content-Type application/pkcs7-mime; smime-type=CMC-response.

Example

# Full CMC requests are typically constructed by a CMC-aware client library.
# This example uses a pre-built CMC request.
curl -X POST \
  --cacert ca-chain.pem \
  --cert ra-agent.crt \
  --key ra-agent.key \
  -H "Content-Type: application/pkcs7-mime; smime-type=CMC-request" \
  --data-binary @cmc-request.b64 \
  -o cmc-response.p7b \
  https://est.example.com:9443/.well-known/est/fullcmc

# Decode the CMC response
base64 -d cmc-response.p7b | openssl cms -inform DER -cmsout -print

Note: Full CMC support requires the fullcmc feature in the server configuration. When Dogtag PKI is the back-end CA, CMC requests are forwarded to the Dogtag CMC profile.


POST /serverkeygen

Request server-side key generation. The server generates a key pair, signs the certificate, and returns both the certificate and the encrypted private key. This operation is used in environments where the client device cannot generate strong keys locally, or where key escrow through a Key Recovery Authority (KRA) is required.

Authentication: OTP (HTTP Basic) or mTLS.

Request body: base64-encoded DER PKCS #10 CSR, Content-Type application/pkcs10. The CSR provides the subject and requested attributes; the public key in the CSR is replaced by the server-generated key.

Response: 200 OK with Content-Type multipart/mixed. The response contains two parts:

PartContent-TypeContents
1application/pkcs7-mime; smime-type=certs-onlySigned certificate (base64 PKCS #7)
2application/pkcs8Encrypted private key (base64 PKCS #8)

The private key is encrypted to the client using the asymmetric key from the CSR or a pre-shared symmetric key, depending on configuration.

Example

# Generate a throwaway CSR (the server will generate the real key pair)
openssl req -new -newkey ec -pkeyopt ec_paramgen_curve:P-256 \
  -keyout throwaway.key -out serverkeygen.csr -nodes \
  -subj "/CN=device-002.example.com"

# Base64-encode
openssl req -in serverkeygen.csr -outform DER | base64 > serverkeygen.csr.b64

# Request server-side key generation
curl -X POST \
  --cacert ca-chain.pem \
  -u "device-002:b8e4c1d5f2a7" \
  -H "Content-Type: application/pkcs10" \
  --data-binary @serverkeygen.csr.b64 \
  -o serverkeygen-response.mime \
  https://est.example.com:9443/.well-known/est/serverkeygen

# The response is multipart/mixed -- extract the certificate and key
# (exact parsing depends on the MIME boundary in the response headers)

Note: Server-side key generation requires a KRA (Key Recovery Authority) when key escrow is mandated by policy. With Dogtag PKI, the KRA subsystem handles key archival automatically.


GET /csrattrs

Retrieve the set of CSR attributes that the server expects or recommends clients include in their certificate signing requests. The response is an ASN.1 sequence of OIDs and attribute definitions.

Authentication: None (or mTLS, depending on server policy).

Response: 200 OK with Content-Type application/csrattrs. The body is a base64-encoded DER CsrAttrs structure as defined in RFC 7030 Section 4.5.2.

Example

# Fetch supported CSR attributes
curl --cacert ca-chain.pem \
  -o csrattrs.b64 \
  https://est.example.com:9443/.well-known/est/csrattrs

# Decode and inspect (requires ASN.1 tools)
base64 -d csrattrs.b64 | openssl asn1parse -inform DER

Typical attributes returned include:

  • ecPublicKey with secp256r1 or secp384r1 – indicating preferred key algorithms
  • challengePassword – when the server requires a challenge in the CSR
  • Extension requests – specific X.509v3 extensions the server will honor

Error responses

All EST endpoints return standard HTTP error codes. The response body for errors is application/json on the admin API and plain text on the EST endpoints.

StatusMeaningWhen returned
400 Bad RequestMalformed CSR, invalid base64 encoding, missing Content-Type, or CSR fails policy validation.Any POST endpoint
401 UnauthorizedMissing or invalid authentication. For OTP: the OTP value is wrong, expired, or already consumed. For mTLS: no client certificate presented or the certificate is not trusted./simpleenroll, /simplereenroll, /serverkeygen
403 ForbiddenAuthentication succeeded but the client is not authorized for the requested operation. Common cause: re-enrollment with a certificate whose subject does not match the CSR./simplereenroll
404 Not FoundUnknown EST label.Any endpoint with an invalid label
500 Internal Server ErrorServer-side failure: HSM unreachable, database error, or CA signing failure.Any endpoint
503 Service UnavailableThe requested CA is temporarily unavailable (all replicas down, HSM session exhausted).Any endpoint

Retry-After

When an operation requires asynchronous processing (for example, a Dogtag PKI back-end that queues signing requests for RA approval), the server returns 202 Accepted with a Retry-After header indicating the number of seconds the client should wait before polling.

HTTP/1.1 202 Accepted
Retry-After: 30
Content-Length: 0

The client should repeat the same request (with the same CSR and authentication) after the indicated interval. The server tracks pending requests and returns the signed certificate when it becomes available, or another 202 if the request is still pending.

Example: handling a 401

# A failed OTP enrollment returns 401
curl -v -X POST \
  --cacert ca-chain.pem \
  -u "device-001:wrong-otp-value" \
  -H "Content-Type: application/pkcs10" \
  --data-binary @device.csr.b64 \
  https://est.example.com:9443/.well-known/est/simpleenroll

# Response:
# < HTTP/1.1 401 Unauthorized
# < WWW-Authenticate: Basic realm="est"

TLS requirements

The EST listener enforces TLS 1.2 or 1.3 for all connections. The server certificate must be configured in [tls] in the kipuka configuration file.

For mTLS-authenticated endpoints, the server’s TLS configuration must include a client_ca trust anchor that covers the certificates clients present. See TLS Configuration for details.

# Verify server TLS configuration
openssl s_client -connect est.example.com:9443 -showcerts </dev/null