Skip to main content
Skip table of contents

EJBCA REST Interface

The following covers information on the EJBCA REST Interface for Certificate Management and CA Administration operations.

API Overview

EJBCA Certificate Management REST API contains endpoints intended for integration with EJBCA, using CA Management, Crypto token management, Certificate management and ConfigDump RESTful Web Services. This allows for easy integration and lightweight HTTP interaction for the most crucial parts of EJBCA.

The scope of the API is limited compared to the full set of features provided by EJBCA and provides functionality such as certificate requests, enrollment, revocation, import and export of ConfigDump configurations, and more. For a full description of the functionality provided, see Resources.

EJBCA Community includes the Enrolment REST API for certificate enrolment and CA related APIs (handling CA specific operations), a subset of the full Management REST API included in EJBCA Enterprise. To help you get started and integrate with EJBCA Community, we provide an open-source REST client for EJBCA Community Edition, see Easy Rest Client for EJBCA on GitHub.


REST API Reference 

EJBCA software solution releases are bundled with an auto-generated REST API reference available at the URL https://localhost:8442/ejbca/doc/rest/ if deployed.

If you are using EJBCA deployment options without the reference docs available, see Open API Specification for information on how to leverage the Open API Specification and use tools such as Swagger Editor locally.

Swagger UI

Swagger UI allows you to visualize and interact with the API’s resources. The Swagger UI playground is available in your browser at the URL https://localhost:8443/ejbca/swagger-ui (use port 8443 since the REST API uses client certificate authentication).

The Swagger UI is only available if EJBCA is built in non-production mode and REST is activated as a protocol (see below). To build EJBCA in non-production mode, set ejbca.productionmode=false in the conf/ejbca.properties file, recompile the ejbca.ear file, and redeploy.

Note regarding Swagger generated clients

Swagger-codegen, openapi-generator, or similar tools can be employed to produce a client based on the swagger.json or swagger.yaml file. Note that these generators might not handle byte[] data types correctly. This issue arises particularly when dealing with responses from our REST APIs, where byte[] data types are commonly used, such as in the case of certificates and CRLs. Prior to using the generated client, it is necessary to manually address these scenarios. Please note that this problem stems from the code generator libraries themselves and is not something Keyfactor can remedy.

It is recommended to manually modify the generated client to replace List<byte[]> occurrences with byte[] in the following instances:

  • "CertificateRestResponse" for the "certificate" and "certificateChain" (list) fields.
  • "CertificateRestResponseV2" for the "certificate" field.
  • "CrlRestResponse" for the "crl" field.
  • "SshCertificateRestResponse" for the "certificate" field.

Open API Specification

The OpenAPI Specification (formerly known as Swagger) can be used in different tools to provide an overview of endpoints, parameters, and the corresponding documentation.

EJBCA Enterprise Open API Specification

To render the EJBCA Enterprise API specification visually and view the latest endpoints, see Open API Specification.

Use Swagger Editor

The Swagger Editor offers an easy way to render the EJBCA API specification visually by downloading the EJBCA Swagger JSON file and use the Swagger Editor on the web or on a local machine.

Use the Swagger Editor on the Web

To use the Swagger Editor on your machine:

  1. Download the EJBCA Swagger JSON file from the Open API Specification page or the EJBCA Community GitHub repository.
  2. Once downloaded, go to Swagger Editor and import the JSON file.
Use the Swagger Editor on a local machine

To use the Swagger Editor on your machine:

  1. Download the EJBCA Community Swagger JSON file from the Open API Specification page or the EJBCA Community GitHub repository
  2. Once downloaded, use Swagger UI to run the Swagger Editor locally.
  3. Place the downloaded swagger.json file in a readable directory (for example /tmp on your local machine).
  4. Run the following Docker command:

    BASH
    docker run -p 80:8080 -e SWAGGER_JSON=/foo/swagger.json -v /tmp:/foo swaggerapi/swagger-ui 


  5. Access the Swagger UI at http://localhost.

Getting Started

The EJBCA Certificate Management REST API is disabled by default. To enable the service, go to CA UI → System Configuration → Protocol Configuration and select Enable for the REST end point you want to use. The REST API requires access to an active (non-external) CA. The exceptions to this are ConfigDump and Crypto Token endpoints, which can also be used when only an external CA is available.

Integrating with the REST API and consuming the response can be done with any tool of choice. For basic GET requests, any web browser is sufficient and for improved integration, a REST library or similar tool is recommended.

The following shows an example of a basic request:

CODE
GET https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/status

Resulting in the following JSON response. Note that version and revision may vary.

CODE
{
	"status":"OK",
	"version":"1.0",
	"revision":"ALPHA"
}

You can access the URL above using for example cURL, your browser, or any other tool. Note that the REST API requires client certificate authentication, see Authentication.

Security for REST endpoint

All REST endpoints can be invoked from browsers. EJBCA REST endpoints may be maliciously invoked from administrator machines by clickjacking or CSRF methods. Authentication measures are also passed by default by the browser in these scenarios. Modern browsers ensure that cross-origin calls are safe to invoke by calling the HTTP OPTION method on the respective REST endpoint before sending the actual request. This preflight operation fails for EJBCA REST endpoints as OPTION is not implemented. Unfortunately, this check is only performed if the HTTP call is done by javascript. This still leaves it vulnerable to HTML form submissions for GET/POST requests which are supposed to be protected from the backend by proper validations. 

In EJBCA 7.11.0, this is addressed by mandating a custom header for calls coming from a browser. This custom header name can be modified in the Admin UI > System Configuration on the Available Protocol tab. It is active by default and may also be disabled from there. Backend service calls and browser calls are distinguished by the presence of any of the two forbidden headers "Sec-Fetch-Mode" and "Sec-Fetch-Dest". Hence, there should not be any impact on backend services unless these headers were being forwarded to EJBCA.

Furthermore, these forbidden headers are injected by most modern browsers except Safari. This protective measure is absent in the non-production mode of EJBCA.

Integrating with the REST API

Requests to the API are submitted using RESTful URLs with the standard HTTP methods: GET, POST, PUT. Additionally, some endpoints accept a JSON request body. Put together, each request consists of the HTTP method, endpoint URL, and (for some endpoints) a request body. Some endpoints require you to include an HTTP method header:

CODE
Content-Type: application/json

Generally, responses consist of an HTTP header including an RFC 2616 status code, and an application/json response body. For information on exceptions, see Responses.

In case of an error, the response body contains an appropriate error message describing the event.

Resources 

The certificate management REST API provides the following base resource URLs:

CODE
/ejbca/ejbca-rest-api/v1/ca_management/
/ejbca/ejbca-rest-api/v1/ca/
/ejbca/ejbca-rest-api/v1/certificate/
/ejbca/ejbca-rest-api/v1/configdump/ 
/ejbca/ejbca-rest-api/v1/cryptotoken/
/ejbca/ejbca-rest-api/v1/endentity/
/ejbca/ejbca-rest-api/v2/certificate/

Each resource provides endpoints of interaction:

  • Endpoints under the /ca_management/ resource allow manipulating CAs, for example activating and deactivating a CA. ENTERPRISE
  • The /ca/ resource allows retrieving CA certificates, CRLs, and so on.
  • The /certificate/ resource handles certificate enrollment, revocation and other workflows related to managing certificates.
  • The /configdump/ resource handles import and export of configurations (publishers, certification authorities, roles etc) via the ConfigDump tool. ENTERPRISE
  • The /cryptotoken/ resource handles crypto token activation, deactivation, and crypto token key generation. ENTERPRISE
  • The /endentity/ resource handles end entity management. ENTERPRISE

For a full set of all endpoints, required input, responses, and other endpoint descriptions, see REST API Reference or try it out in the Swagger UI.

Requests

Each endpoint URL is built in the same way by the following structure:

CODE
https://[DOMAIN_NAME]:[PORT]/ejbca/ejbca-rest-api/[API_VERSION]/[RESOURCE]/[IDENTIFIER]/[OPERATION]?[QUERY_PARAM]

Explanation

  • DOMAIN_NAME: Domain name of the EJBCA instance, for example: localhost.
  • PORT: Secure port of the EJBCA instance, for example: 8443.
  • API_VERSION: Version of the REST API, for example: v1.
  • RESOURCE: One of the two base resources /ca/ or /certificate/.
  • IDENTIFIER: Identifier of the entity to perform the operation on. This might be a Subject DN, serial number, or both combined. A composite identifier could look like .../{issuer_dn}/{certificate_serial_number_hex}/revocationstatus.
  • OPERATION: The operation to perform, for example: /revocationstatus.
  • QUERY_PARAM: HTTP query parameters. Some endpoints accept query parameters rather than a JSON body. For example .../revoke?reason=KEY_COMPROMISE.

Note that not all endpoints require the identifier or query parameters. For example, the following is not specific for an entity and does not accept an identifier:

CODE
GET https://localhost:8443/ejbca/ejbca-rest-api/v1/ca/status

Methods

Each request requires a specified HTTP method. The expected method for each endpoint can be seen in REST API Reference or the Swagger UI.

In general, the method used corresponds to the expected state change performed.

MethodDescriptionExample
GETUsed only to read data and not change it..../{issuer_dn}/{certificate_serial_number_hex}/revocationstatus
PUTUsed in operations that updates some entity state..../{issuer_dn}/{certificate_serial_number_hex}/revoke
POSTUsed in operations which creates some entity..../enrollkeystore
DELETEUsed in operations which deletes some entity.../endentity{endentity_name}

Request Body

As mentioned, some endpoints accept a request body containing the desired input data. Request bodies must only contain JSON formatted data and the header Content-Type: application/json must be set in the request for the request to be accepted. All input fields (not values) must be snake_case formatted, e.g. "key_alg" rather than "keyAlg" or "key alg".

The following example shows a request to enroll a keystore (using cURL):

CODE
curl -X POST -H 'Content-Type: application/json' -i 'https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/enrollkeystore' --data '{
"username":"testUser",
"password":"foo123",
"key_alg":"RSA",
"key_spec":"2048"
}'

Responses 

While integrating with the REST API, the most relevant information in the response is the status-line (HTTP status code), Content-Type header, and the response body.

Status Codes

Any response code within the range of 2xx - 3xx may be considered successful. This means that the server has accepted the request and sent an appropriate response. The typical response code from a GET request would be 200 - OK. When the operation requires an approval by another administrator, the response will be 201 - Accepted, meaning that the request has been accepted successfully and is awaiting approval.

Response codes in the range 4xx - 5xx should be considered errors. It may be an authentication failure, conflict or a general server error. For example, requesting an operation not allowed using your specific client certificate will generate 403 - Unauthorized, most likely followed by some response message in the response body.

For a complete list of codes that may occur while interacting with the API, see Status Codes.

Response Body

The content type of the response can be determined by the Content-Type header and most endpoints will always return application/json. Exceptions include for example calling .../ca/{issuer_dn}/certificate/download which returns a byte streamed .pem certificate. In this case, the wildcard header */* is used. All requests regardless of response code, which reach the server will retrieve a response body. Any response to a successful request will contain a body including the requested information, for example:

CODE
curl -X GET -i 'https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/CN%3DManagementCA%2CO%3DEJBCA%20Sample%2CC%3DSE/4b0b0ceb7a8e5f1f/revocationstatus'

Returns the following JSON body (given that the certificate is found):

CODE
{
  "issuer_dn": "CN=ManagementCA,O=EJBCA Sample,C=SE",
  "serial_number": "4b0b0ceb7a8e5f1f",
  "revocation_reason": "KEY_COMPROMISE",
  "revocation_date": "2018-06-27T08:07:52Z",
  "revoked": true
}

In the event of an error, a response body containing the status code (in addition to the header), and an appropriate error message are returned.

For example, if the request above was done for a CA which does not exist, the client could expect a response like: 

CODE
{
  "error_code": 404,
  "error_message": "CA 'CN=NonExistingCA,O=EJBCA Sample,C=SE' does not exist."
}

If a completely unexpected error occurs, the server will respond with 500 - General failure. If this occurs, verify the content of the request and next require that the CA Administrator checks the server log.

Authentication 

The REST API requires either a client certificate authentication or OAuth just as the Admin GUI does. If you have a working Admin GUI client certificate, you should also be able to use it for the REST API. How the certificate is passed with the request depends on your integration environment. To verify server response and authentication, attempt accessing the API through any web browser using your client certificate:

CODE
https://[DOMAIN_NAME]:[PORT]/ejbca/ejbca-rest-api/v1/ca/version

You can also use cURL or a similar tool by specifying --cert and --key.

If no certificate or an invalid certificate is provided, you'll most likely be presented with a "Bad certificate" error. However, if an attempt is made to request a resource above the privileges of a valid certificate, the response will contain a JSON formatted response body with the status code 403 - Unauthorized followed by an appropriate response message. For more information, see Status Codes.

ENTERPRISE This is an EJBCA Enterprise feature.

To use OAuth a header must be present that contains Authorization: Bearer {token}. The token must be obtained from the identity provider that EJBCA is configured to use for OAuth. An example of using cURL or a similar tool would look like the following:

CODE
curl -H "Authorization: Bearer {23dues7r3s93sc}" -H  "accept: application/json" -X GET "https://[DOMAIN_NAME]:[PORT]/ejbca/ejbca-rest-api/v1/ca/version" 

Debugging REST API

By default, EJBCA logs basic information about incoming requests and INFO level.

The following info is logged in INFO logging level:

  • remote address
  • "X-Forwarded-For" header value

Example:

CODE
13:31:07,976 INFO [org.ejbca.ui.web.rest.api.config.RestLoggingFilter] (default task-10) GET https://localhost:8443/ejbca/ejbca-rest-api/v1/ca/CN=Management%20CA,O=PK,C=SE/certificate/download received from 127.0.0.1 X-Forwarded-For: null

It is also possible to make EJBCA log the complete requests and responses at TRACE level.

The following info is logged in TRACE level:

  • request and response
  • time taken per request, i.e. endtime - starttime

As enabling TRACE logging globally, for all of EJBCA, may result in excessive logging, it is possible to enable it for the RestLoggingFilter only. On JBoss/WildFly this is done with simple commands in the jboss-cli:

CODE
/subsystem=logging/logger=org.ejbca.ui.web.rest.api.config:add
/subsystem=logging/logger=org.ejbca.ui.web.rest.api.config:write-attribute(name=level, value=TRACE) 

Example TRACE logging for a simple request is:

CODE
curl -X GET "https://localhost:8443/ejbca/ejbca-rest-api/v1/ca/CN=Management%20CA,O=PK,C=SE/certificate/download" --insecure --cert cert-superadmin.pem --key key-superadmin.pem
CODE
2018-08-07 13:31:08,038 TRACE [org.ejbca.ui.web.rest.api.config.RestLoggingFilter] (default task-10) GET https://localhost:8443/ejbca/ejbca-rest-api/v1/ca/CN=Management%20CA,O=PK,C=SE/certificate/download received from 127.0.0.1 X-Forwarded-For: null
Request headers:
  Accept: */*
  User-Agent: curl/7.47.0
  Host: localhost:8443
Request data:
  
Response data:
Subject: CN=Management CA,O=PK,C=SE
Issuer: CN=Management CA,O=PK,C=SE
-----BEGIN CERTIFICATE-----
MIIDTzCCAjegAwIBAgIIbbifeqpPKLcwDQYJKoZIhvcNAQELBQAwNTEWMBQGA1UE
<snip>
xdd9ycYOyym2nvM+SPydHlK8dAqwwXzICFFOCRADsQNakVU=
-----END CERTIFICATE-----

Time taken: 62ms

Status Codes

API status codes are exposed in standard HTTP response codes and JSON formatted messages. For example, the following example shows an HTTP 403 error:

CODE
{
  "error_code": 403,
  "error_message": "Not authorized to resource /administrator."
}

The response code will also be available in the HTTP response status line. The following table describes status codes that may be "expected" responses from the REST API and a few possible reasons.

HTTP Status CodeGeneral DescriptionEJBCA REST API Context
200OKSuccessful HTTP request, expect a proper response body. Typically received from a successful GET request.
201CreatedSuccessful HTTP request. Some entity has been created, e.g. certificate enrolled. Typically received after a successful POST request.
202AcceptedRequest accepted by the server but awaiting processing. Most likely waiting for administrator approval.
400Bad RequestA common error that can be caused by many conditions such as:
  • invalid input parameters / JSON body in the request
  • an invalid alias in the request path
  • the requested CA does not exists
  • error creating or renewing a certificate due to pre-conditions not being fulfilled by the request
    (this can be many things like trying to renew with the same public key when it's not allowed, etc, etc)

Hints on what caused the issue is typically returned in the message part of the HTTP error response and are logged in the server log file for administrators.

403ForbiddenRequest accepted but the operation is refused due to insufficient privileges, disabled features etc.
404Not FoundRequested entity was not found by EJBCA. Could occur if the input refers to a non-existing entity, such as a user or a CA.
409ConflictConflict occurred while processing request, e.g. trying to revoke an already revoked certificate.
413Payload Too LargeThe request is larger than the server is willing to process. Should not occur while using the API as intended.
422Unprocessable EntityWell-formed request but unable to process due to e.g. semantic errors. Could occur in case of invalid key algorithm, validity etc.
500Internal Server ErrorUnexpected error while calling the API. For additional details, refer to the server log (CA Administrator).
503Service UnavailablePossible reason could be that the CA is offline, CT log is unavailable etc.

API Version

All EJBCA REST resources use URI versioning.

Example: https://hostname:8443/ejbca/ejbca-rest-api/v1/certificate/search in which v1 defines the API version.

The API version will not change with new versions of EJBCA unless:

  • Any required endpoint parameter has changed.
  • The response format of any endpoint has changed.

Generally, such changes to existing endpoints will be avoided since they would break existing client integrations. If such a change is made, it will be in a major EJBCA release and clearly documented in the EJBCA Upgrade Notes.

However, the API continuously evolves with new endpoints. New endpoints do not affect the API version, nor if additional fields are added to an existing response (within the same response format).

Examples

Generate a CSR and Request a Certificate using Bash

You can use OpenSSL, jq, and cURL (version >7.57) to create a key and a CSR, create a JSON payload containing the CSR, and then enroll for a TLS server certificate using the configuration file and script below.

Configuration File Example

csr.conf

CODE
[req]
distinguished_name = req_distinguished_name
req_extensions = v3_req
prompt = no


[req_distinguished_name]
C = SE
O = PrimeKey Solutions AB
OU = Infra
CN = primekey.com

[v3_req]
keyUsage = keyEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = primekey.com

Script Example

The pkcs10enroll.sh script generates a new CSR if one does not already exist, requests a certificate from EJBCA, and then prints the JSON response to stdout.

To enable usage of self-signed certificates in development, add -k to the curl options. To view the error message from curl, remove -s.

pkcs10enroll.sh

BASH
#!/bin/sh

# Before running this script you need to do the following:

# 1. If you are contacting the CA directly:
#
#     Enable the REST API in System Configuration -> Protocol Configuration.
#
#     If you are contacting an external RA, you should enable the REST API for
#     the peer role on the CA.

hostname="172.16.31.14"

# 2. Specify profiles, CA and end entity to use for issuance

cert_profile_name="staging-cert"
ee_profile_name="staging-ee"
ca_name="Issuing CA"
# This user will be created if it does not exist. The status of an existing
# end entity will be set to NEW automatically.
username="pkcs10enroll_user"
# If the user already exists, specify the enrollment code here
enrollment_code="foo123"

# 3. Adjust the variable $client_cert to point to a client certificate.

client_cert="/opt/jboss/p12/SuperAdmin.p12:foo123"

if [ ! -f 'server.csr' ]; then
    openssl req -new -out server.csr -newkey rsa:2048 \
	    -nodes -sha256 -keyout server.key \
	    -config csr.conf > /dev/null 2>&1
fi
csr=$(cat server.csr)
template='{"certificate_request":$csr, "certificate_profile_name":$cp, "end_entity_profile_name":$eep, "certificate_authority_name":$ca, "username":$ee, "password":$pwd}'
json_payload=$(jq -n \
    --arg csr "$csr" \
    --arg cp "$cert_profile_name" \
    --arg eep "$ee_profile_name" \
    --arg ca "$ca_name" \
    --arg ee "$username" \
    --arg pwd "$enrollment_code" \
    "$template")
curl -X POST -s \
    --cert-type P12 \
    --cert "$client_cert" \
    -H 'Content-Type: application/json' \
    --data "$json_payload" \
    "https://$hostname/ejbca/ejbca-rest-api/v1/certificate/pkcs10enroll" \
    | jq .

A JSON request (to be used in swagger-ui for example) would look like this, a plain PKCS#10 CSR using \n as line breaks:

TEXT
{
"certificate_request":"-----BEGIN CERTIFICATE REQUEST-----\nMIIChTCCAW0CAQAwQDELMAkGA1UEBhMCU0UxDjAMBgNVBAgMBVNvbG5hMREwDwYD\nVQQKDAhQcmltZUtleTEOMAwGA1UEAwwFVG9tYXMwggEiMA0GCSqGSIb3DQEBAQUA\nA4IBDwAwggEKAoIBAQDfOpmUDnUsilYoaYpHUGN9AvAkK2AdHoYz4cTkKD4kPPvq\nErRdayyGWiuKrmhH6v+jPvh5ZYQoqL2viSTIkcvr7BIo9pgqSVswxvC5v4GGy3R4\nnme0El27oB5X0AJl3X5STT5GwIWw66XHcTeg1ux62bfY/N1RhiHanFOZ00DokPyW\n/s+dGcnZ9kBC5s5jcEEEwcGXCyKuyCoy60Z87asOraCsYeRlq3qqdms0BZEM7lLK\n7oP4HjIpk9VSLYihGlFsbophw96gNGtYjorX//CYvuyckUpA9TLdfx8IoQSiKlsJ\nCDdMeDXnkqOZAmXj3xos3qm1VJV2J9AVggzQ1SUnAgMBAAGgADANBgkqhkiG9w0B\nAQsFAAOCAQEAGcK8aMvmdhsTeCv+D1R21Bjc5fb+dmrXcYdR4RI8roW4GZDqGdBU\n8bYDZfO0SnV0q6m23G6upVhtYpzOrVcDaiQ4iFvGQkz8pfErZ+qqwZhE6yvbc+2p\n0BVuIIePbgdAW17acxkOF4p0Z5TkNazdNwePyjW8dfUvarVX//AA48l66bUXu6IM\nX2LU/OY1hcLETlAqV2o1iDPRsOTnF2OpV8FdmpBhD7VUa78h8n3w3l+WdmaAhcy4\njItzjKHi5CEoJ3s15Yo4zuwZt2g+bmGGfBqGcSKkPAlsQ+A79DMwzJXLN/Cs/joY\ngwObGYEkQqkX1DGjDNzYyw+RtvdzJV8shQ==\n-----END CERTIFICATE REQUEST-----",
"certificate_profile_name":"Client",
"end_entity_profile_name":"User",
"certificate_authority_name":"ManagementCA",
"username":"myuser",
"password":"foo123",
"include_chain":true,
"email": "useremail@domain.com",
"response_format": "DER"
}

email in pkcs10enroll

From version 7.10.0, "email" should be mentioned in pkcs10enroll request in REST interface. This can be used to update the end entity information. If the email is not mentioned, user email will be set to null in database.

The available response formats include PKCS7 (Base64 encoded PEM) and DER. If the response format is omitted from the JSON request, the certificate will be returned in the default DER format.


with the resulting curl command (using superadmin.p12 for RA authentication):

TEXT
curl -k --cert-type P12 --cert p12/superadmin.p12:ejbca -X POST "https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/pkcs10enroll" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{\"certificate_request\":\"-----BEGIN CERTIFICATE REQUEST-----\nMIIChTCCAW0CAQAwQDELMAkGA1UEBhMCU0UxDjAMBgNVBAgMBVNvbG5hMREwDwYD\nVQQKDAhQcmltZUtleTEOMAwGA1UEAwwFVG9tYXMwggEiMA0GCSqGSIb3DQEBAQUA\nA4IBDwAwggEKAoIBAQDfOpmUDnUsilYoaYpHUGN9AvAkK2AdHoYz4cTkKD4kPPvq\nErRdayyGWiuKrmhH6v+jPvh5ZYQoqL2viSTIkcvr7BIo9pgqSVswxvC5v4GGy3R4\nnme0El27oB5X0AJl3X5STT5GwIWw66XHcTeg1ux62bfY/N1RhiHanFOZ00DokPyW\n/s+dGcnZ9kBC5s5jcEEEwcGXCyKuyCoy60Z87asOraCsYeRlq3qqdms0BZEM7lLK\n7oP4HjIpk9VSLYihGlFsbophw96gNGtYjorX//CYvuyckUpA9TLdfx8IoQSiKlsJ\nCDdMeDXnkqOZAmXj3xos3qm1VJV2J9AVggzQ1SUnAgMBAAGgADANBgkqhkiG9w0B\nAQsFAAOCAQEAGcK8aMvmdhsTeCv+D1R21Bjc5fb+dmrXcYdR4RI8roW4GZDqGdBU\n8bYDZfO0SnV0q6m23G6upVhtYpzOrVcDaiQ4iFvGQkz8pfErZ+qqwZhE6yvbc+2p\n0BVuIIePbgdAW17acxkOF4p0Z5TkNazdNwePyjW8dfUvarVX//AA48l66bUXu6IM\nX2LU/OY1hcLETlAqV2o1iDPRsOTnF2OpV8FdmpBhD7VUa78h8n3w3l+WdmaAhcy4\njItzjKHi5CEoJ3s15Yo4zuwZt2g+bmGGfBqGcSKkPAlsQ+A79DMwzJXLN/Cs/joY\ngwObGYEkQqkX1DGjDNzYyw+RtvdzJV8shQ==\n-----END CERTIFICATE REQUEST-----\",\"certificate_profile_name\":\"Client\",\"end_entity_profile_name\":\"User\",\"certificate_authority_name\":\"ManagementCA\",\"username\":\"myuser\",\"password\":\"foo123\",\"include_chain\":true,\"email\": \"useremail@domain.com\"}"

Revocation Workflow Example

Follow the example below to first check the revocation status of a certificate and then revoke the certificate.

In this example, the certificate's DN is CN=CA1 and serial number (in hex) is 5CB3D42686039768D973E5694BF205377AF6.

  1. To check the revocation status of the certificate, call the GET /v1/certificate/{issuer_dn}/{certificate_serial_number}/revocationstatus REST method:

    CODE
    curl -X GET -s \
    --cert-type P12 \
    --cert "/opt/jboss/p12/SuperAdmin.p12:foo123" \
    -H "accept: application/json"
    "https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/CN%3DCA1/5CB3D42686039768D973E5694BF205377AF6/revocationstatus"
  2. From the response below, you can confirm that the certificate is active.

    CODE
    {
    	"issuer_dn": "CN=CA1",
    	"serial_number": "5CB3D42686039768D973E5694BF205377AF6",
    	"revocation_reason": "NOT_REVOKED",
    	"revoked": false
    }
  3. To revoke the certificate, call the PUT /v1/certificate/{issuer_dn}/{certificate_serial_number}/revoke REST method:

    CODE
    curl -X PUT -s \
    --cert-type P12 \
    --cert "/opt/jboss/p12/SuperAdmin.p12:foo123" \
    -H "accept: application/json"
    "https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/CN%3DCA1/5CB3D42686039768D973E5694BF205377AF6/revoke?reason=KEY_COMPROMISE"
  4. Confirm from the response that the certificate has been successfully revoked:

    CODE
    {
    	"issuer_dn": "CN=HT_REMOVAL_CA",
    	"serial_number": "5CB3D42686039768D973E5694BF205377AF6",
    	"revocation_reason": "KEY_COMPROMISE",
    	"revocation_date": "2019-05-27T15:02:56Z",
    	"message": "Successfully revoked",
    	"revoked": true
    }

Request a PKCS#12 Keystore Using Python

To request a PKCS#12 keystore using Python, do the following:

  1. Install the module requests_pkcs12 using pip.

    BASH
    pip3 install requests_pkcs12
  2. Authenticate with the client certificate stored in superadmin.p12 and request a PKCS12 file for the end entity python.

    PY
    import json
    from requests_pkcs12 import post
    response = post('https://myca:8443/ejbca/ejbca-rest-api/v1/certificate/enrollkeystore',
        json={
            'username': 'python',
            'password': 'foo123',
            'key_alg': 'RSA',
            'key_spec': '2048'
        },
        headers={ 
            'content-type': 'application/json' 
        },
        pkcs12_filename='/srv/superadmin.p12', 
        pkcs12_password='foo123', 
        verify='/srv/truststore.pem')
    
    print(json.dumps(json.loads(response.content), indent=4, sort_keys=True))

Request a PKCS#12 Keystore Using Node.js

To request a PKCS#12 keystore using Node.js, do the following:

  1. Install the node.js module called node-fetch.

    CODE
    npm install node-fetch
  2. Create a script which looks something like this: 

    JS
    const fs = require('fs');
    const https = require('https');
    const fetch = require('node-fetch');
    
    // Load the keystore used to authenticate to the REST API
    const pfx = fs.readFileSync('RA_Administrator.p12');
    const passphrase = 'foo123';
    const agent = https.Agent({ pfx, passphrase });
    
    // Load the enrollment code for the end entity
    const enrollmentCode = 'foo123'
    
    // Name of the end entity
    const deviceName = 'Company Device 1'
    
    // Request renewal of the device certificate
    fetch('https://nautilus:8443/ejbca/ejbca-rest-api/v1/endentity/' + deviceName + '/setstatus', {
          agent: agent,
          method: 'post',
          body: JSON.stringify({
            "password": enrollmentCode,
            "token": "P12",
            "status": "NEW"
          }),
          headers: { 'Content-Type': 'application/json' },
      })
      .then(res => {
        if (res.status != 200) {
          console.log('Renewal failed with status code ' + res.status + '.')
        } else {
          console.log('Renewal succeeded! Requesting new device certificate from EJBCA...')
          fetch('https://nautilus:8443/ejbca/ejbca-rest-api/v1/certificate/enrollkeystore', {
            agent: agent,
            method: 'post',
            body: JSON.stringify({
              "username": deviceName,
              "password": enrollmentCode,
              "key_alg": "RSA",
              "key_spec": "2048"
            }),
            headers: { 'Content-Type': 'application/json' },
          })
          .then(res => res.json())
          .then(json => console.log(json))
          .catch(error => console.log(error)) 
        }
      })
      .catch(error => console.log(error)) 

Search for Certificates

To search for certificates with multiple search criteria, use the search method.

Example JSON Search Request

The following shows an example JSON search request to search for ACTIVE certificates for the superadmin user, limiting the search to return a maximum of 10 certificates:

CODE
{
  "max_number_of_results": 10,
  "criteria": [
    {
      "property": "QUERY",
      "value": "superadmin",
      "operation": "EQUAL"
    },
    {
      "property": "STATUS",
      "value": "CERT_ACTIVE",
      "operation": "EQUAL"
    }
  ]
}

To search for DN or altName fields, for example, looking for a maximum of 10 certificates issued to a user with a Common Name like 'Firstname Lastname', use the following:

CODE
{
  "max_number_of_results": 10,
  "criteria": [
    {
      "property": "QUERY",
      "value": "Firstname Lastname",
      "operation": "LIKE"
    },
    {
      "property": "STATUS",
      "value": "CERT_ACTIVE",
      "operation": "EQUAL"
    }
  ]
}

To search for certificates based on the certificate serial number, use a query similar to the following. The QUERY property value is the certificate serial number in hex or decimal format:

CODE
{
  "max_number_of_results": 10,
  "criteria": [
    {
      "property": "QUERY",
      "value": "404762757874990468244089956248237274051937985705",
      "operation": "LIKE"
    },
    {
      "property": "STATUS",
      "value": "CERT_ACTIVE",
      "operation": "EQUAL"
    }
  ]
}


Search for Certificates Version 2

To search for certificates with multiple search criteria, pagination and sorting use the search method version 2.

Example JSON Search Request

The following shows an example JSON search request to search for ACTIVE certificates, returning the first page with page size of 1000, limiting the search to return a maximum of 1000 certificates, sorted by the last time updated:

CODE
{   
  "pagination": {
    "page_size": 1000,
    "current_page": 1
  },
  "sort": {
    "property": "UPDATE_TIME",
    "operation": "ASC"
  },   
  "criteria": [
    {
      "property": "STATUS",
      "value": "CERT_ACTIVE",
      "operation": "EQUAL"
    }
  ]
}

Each query must contain at least one criteria. pagination and sort are optional. If pagination is missing, the total number of certificates for the criteria given is returned. In this case sort is ignored if present in the request. page_size and current_page must be greater than 0. property of sort can be one of

  • USERNAME
  • ISSUER_DN
  • SUBJECT_DN
  • EXTERNAL_ACCOUNT_BINDING_ID
  • END_ENTITY_PROFILE
  • CERTIFICATE_PROFILE
  • STATUS
  • TAG
  • TYPE
  • UPDATE_TIME
  • ISSUED_DATE
  • EXPIRE_DATE or
  • REVOCATION_DATE


Search for End Entities

End entities can be searched using v1 API. Supported search criterias are:

  • QUERY
  • END_ENTITY_PROFILE
  • CERTIFICATE_PROFILE
  • CA, STATUS
  • MODIFIED_BEFORE
  • MODIFIED_AFTER

Note that, QUERY allows search with end entity name, subject distinguished name and subject alternate name.

Search end entities v1

CODE
{
  "max_number_of_results": 10,
  "current_page": 2,
  "criteria": [
    {
      "property": "QUERY",
      "value": "exampleUser",
      "operation": "LIKE"
    },
	{
      "property": "CA",
      "value": "exampleCA",
      "operation": "EQUAL"
    }
  ]
}

Search for End Entities Version 2

The v2 search API additionally supports sort operation. Sorting is allowed by:

  • USERNAME
  • SUBJECT_DN
  • SUBJECT_ALT_NAME
  • END_ENTITY_PROFILE
  • CERTIFICATE_PROFILE
  • STATUS
  • UPDATE_TIME
  • CREATED_TIME

and the results can be sorted ascending(ASC) or descending(DESC) manner. Note that in v2 search the current_page parameter must start at 1 and if more results are needed the page number should be increased sequentially in future queries. Skipping pages or jumping to arbitrary pages when searching using this end point is not supported.

search end entities v2

CODE
{
  "max_number_of_results": 10,
  "current_page": 2,
  "criteria": [
    {
      "property": "QUERY",
      "value": "exampleUser",
      "operation": "LIKE"
    },
	{
      "property": "CA",
      "value": "exampleCA",
      "operation": "EQUAL"
    }
  ],
  "sort_operation": {
    "property": "CREATED_TIME",
    "operation": "ASC"
  }
}


Example cURL Search Command

The following shows an example cURL command to search for ACTIVE certificates for the superadmin user, limiting the search to return a maximum of 10 certificates:

CODE
curl -X POST "https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/search" \
-H  "accept: application/json" -H  "Content-Type: application/json" \
-d "{  \"max_number_of_results\": 10,  \"criteria\": [    {      \"property\": \"QUERY\",      \"value\": \"tomastest1.primekey.com\",      \"operation\": \"EQUAL\"    },    {      \"property\": \"STATUS\",      \"value\": \"CERT_ACTIVE\",      \"operation\": \"EQUAL\"    }  ]}"

Add End Entity

ENTERPRISE

To add an end entity using the endentity endpoint, a JSON like this can be used:

TEXT
{
  "username": "tomas44",
  "password": "foo123",
  "subject_dn": "CN=tomas44",
  "subject_alt_name": "",
  "email": "",
  "extension_data": [
    {
      "name": "1.3.6.1.5.5.7.1.24",
      "value": "3003020105"
    }
  ],   
  "custom_data": [
    {
      "name": "customdata_STARTTIME",
      "value": "2022-12-13 00:00:00"
    },
    {
      "name": "customdata_ENDTIME",
      "value": "2024-12-13 00:00:00"
    }
  ],    "ca_name": "ManagementCA",
  "certificate_profile_name": "Client",
  "end_entity_profile_name": "User",
  "token": "P12"
}

extension_data and custom_data are optional, and cURL, with custom_data left out looks like:

TEXT
curl -X POST "https://localhost:8443/ejbca/ejbca-rest-api/v1/endentity" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{  \"username\": \"tomas44\",  \"password\": \"foo123\",  \"subject_dn\": \"CN=tomas44\",  \"subject_alt_name\": \"\",  \"email\": \"\",  \"extension_data\": [    {      \"name\": \"1.3.6.1.5.5.7.1.24\",      \"value\": \"3003020105\"    }  ],  \"ca_name\": \"ManagementCA\",  \"certificate_profile_name\": \"Client\",  \"end_entity_profile_name\": \"User\",  \"token\": \"P12\"}"

After adding an end entity like that, you can enroll for a PKCS#12 keystore with the certificate/enrollkeystore endpoint:

TEXT
{
  "username": "tomas44",
  "password": "foo123",
  "key_alg": "RSA",
  "key_spec": "2048"
}

and cURL:

TEXT
curl -X POST "https://localhost:8443/ejbca/ejbca-rest-api/v1/certificate/enrollkeystore" -H  "accept: application/json" -H  "Content-Type: application/json" -d "{  \"username\": \"tomas44\",  \"password\": \"foo123\",  \"key_alg\": \"RSA\",  \"key_spec\": \"2048\"}"

Add extension_data and custom_data

There are different types of extra information you can add to an end entity. The first is extension_data field in the JSON request.

  • Extension Data, which is data put into custom certificate extensions

For the certificate extension data, the parameter look like  <oid>[.<type>]=value. The key '1.2.3.4' is same as the '1.2.3.4.value'.

Note that any extra fields added need also be configured to be allowed and used in end entity- and certificate profiles, or as dynamic custom extensions.

Example:

CODE
1.2.840.113634.100.6.1.1=00aa00bb

The second type of data is custom_data:

  • Fields used for customizing the end entity, either to be used when issuing certificates or as meta-data
    • encoded as variable name prepended with customdata_
    • or with the plain variable name

Custom data attributes can be found in ExtendedInformation, some starting with CUSTOM, for example:

CODE
customdata_STARTTIME="2022-12-13 00:00:00+00:00" or "days:hours:minutes"
customdata_ENDTIME=like above	

The following displays example code on how to add extended information in the REST request:

CODE
"extension_data": [
  {
    "name": "1.3.6.1.5.5.7.1.24",
    "value": "3003020105"
  },     
],    
"custom_data": [ 
  {
    "name": "customdata_STARTTIME",
    "value": "2022-12-13 00:00:00+00:00"
  },
  {
    "name": "customdata_ENDTIME",
    "value": "2024-12-13 00:00:00+00:00"
  },
  {
    "name": "customdata_REVOCATIONREASON",
    "value": "0"
  }
],

which translates into:

CODE
extensiondata_1.3.6.1.5.5.7.1.24=3003020105
customdata_STARTTIME=2022-12-13 00:00:00+00:00
customdata_ENDTIME=2024-12-13 00:00:00+00:00
customdata_REVOCATIONREASON=0

Other fields are also found in ExtendedInformation not starting with customdata_.

These fields are a bit hard to use. Use this with care as the string data set must match the intended type used when retrieving values from org.cesecore.certificates.endentity.ExtendedInformation, or the End Entity may be rendered unusable.

For example CERTIFICATESERIALNUMBER must be a Base64 encoded BigInteger (Base64.encode(sn.toByteArray()), or trying to use the number will throw a NumberFormatException.

For example, for custom certificate serial number, the parameter looks like CERTIFICATESERIALNUMBER=<base64 encoded BigInteger>.

Example (serial number 123456789, or in Java BigInteger.valueOf(1234567889L):

CODE
CERTIFICATESERIALNUMBER=B1vNFQ== 

For ETSI PSD2 QC Statement, the parameters (all required) look like qcetsipsd2rolesofpsp=oid;name', qcetsipsd2ncaname='NCA Name', qcetsipsd2ncaid='NCA ID. An optional CAB forum organization identifier parameter (as part of extended information) provided to the command with an example format like the following:

CODE
cabforganizationidentifier=VATSE-123456789

The following displays example code on how to add such field in the REST request:

CODE
"custom_data": [ 
  {
    "name": "qcetsipsd2rolesofpsp",
    "value": "0.4.0.19495.1.1;PSP_AS"
  },
  {
    "name": "cabforganizationidentifier",
    "value": "VATSE-123456789"
  },
  {
    "name": "CERTIFICATESERIALNUMBER",
    "value": "B1vNFQ=="
  }
],

which translates into:

CODE
qcetsipsd2rolesofpsp=0.4.0.19495.1.1;PSP_AS
cabforganizationidentifier=VATSE-123456789
CERTIFICATESERIALNUMBERB1vNFQ==

Use Email Notifications

When adding an end entity and:

  • The end entity profile has the setting Send Notification - Use
  • The endentity REST call set an email attribute

then the Notification setting will be set to true for the added end entity and if the end entity profile is configured to send email notifications, a notification will be sent.

Exporting Configuration with ConfigDump

ENTERPRISE

Export and import of configurations support parameters like ignoreerrors, include, exclude, and so on. For more information about available parameters, see Swagger UI, the generated EJBCA REST Interface#REST API Reference, or ConfigDump Tool.

The configuration can be exported in different ways: the whole configuration, by type, by type and setting, or as a ZIP file containing YAML formatted ConfigDump export.

Exporting All Configuration

Example cURL command for exporting all configuration as JSON format:

BASH
curl -X GET "https://localhost:8443/ejbca/ejbca-rest-api/v1/configdump?ignoreerrors=true&defaults=false&externalcas=false"  \
-H "accept: application/json"

Example cURL command for exporting all configuration as a ZIP file:

BASH
curl -X GET "https://localhost:8443/ejbca/ejbca-rest-api/v1/configdump/configdump.zip?ignoreerrors=false&defaults=false&externalcas=false"  \
-H "accept: application/zip"

Exporting Publishers via ConfigDump (/configdump/{type} resource)

Different types can be used (PUBLISHER for publishers, CRYPTOTOKEN for crypto tokens, etc). For a complete list of types, refer to the generated EJBCA REST Interface#REST API Reference descriptions.

BASH
curl -X GET "https://localhost:8443/ejbca/ejbca-rest-api/v1/configdump/PUBLISHER?ignoreerrors=false&defaults=false&externalcas=false"  \
-H "accept: application/json"

Exporting a Publisher name "test" (/configdump/{type}/{setting} resource)

BASH
curl -X GET "https://localhost:8443/ejbca/ejbca-rest-api/v1/configdump/PUBLISHER/test?ignoreerrors=false&defaults=false"  \
-H "accept: application/json"

Importing Configuration with ConfigDump

ENTERPRISE

JSON data for the body part of an import POST request follows the convention: attribute values are exactly the same as when importing and/or exporting through the ConfigDump CLI with YAML files.

JS
{
  "<configuration type>": {
    "<configuration name>": {
      "<attribute field>": "<value>",
    },
	"<configuration name>": {
      "<attribute field>": "<value>",
    }
  }
}

An example JSON body for importing a single approval profile:

JS
{
  "approval-profiles": {
    "Test Approval Profile": {
      "Object Type": "Approval Profile",
      "Version": 1,
      "ID": 526448739,
      "Type": "ACCUMULATIVE_APPROVAL",
      "Name": "Test Approval Profile",
      "Approval Expiration Period": "8h",
      "Request Expiration Period": "8h",
      "Max Extension Time": "0d",
      "Allow Self-Approved Request Editing": false,
      "Number of Approvals Required": 1
    }
  }
}

And the expected cURL command for the above JSON body: 

BASH
curl -X POST "https://localhost:8443/ejbca/ejbca-rest-api/v1/configdump?ignoreerrors=false&initialize=false&continue=false&overwrite=abort&resolve=abort"  \
-H "accept: application/json" -H "Content-Type: application/json" \
-d "{ \"approval-profiles\": { \"Test Approval Profile\": { \"Object Type\": \"Approval Profile\", \"Version\": 1, \"ID\": 526448739, \"Type\": \"ACCUMULATIVE_APPROVAL\", \"Name\": \"Test Approval Profile\", \"Approval Expiration Period\": \"8h\", \"Request Expiration Period\": \"8h\", \"Max Extension Time\": \"0d\", \"Allow Self-Approved Request Editing\": false, \"Number of Approvals Required\": 1 } }}"

Importing a ZIP file Configuration

BASH
# Prepare the ZIP file
cd <working-directory> 
zip -r configdump.zip .

# Example cURL command that uses above ZIP file (which has the folder/file structure an CLI ConfigDump would create)
curl -X POST "https://localhost:8443/ejbca/ejbca-rest-api/v1/configdump/configdump.zip" \ 
-H "accept: application/json" -H "Content-Type: multipart/form-data"  \
-F "zipfile=@configdump.zip;type=application/zip" -F "overwrite=abort" -F "resolve=abort"

Creating a New Keypair in a Crypto Token

ENTERPRISE

The endpoint for generating a new keypair includes the name of the crypto token:

BASH
https://localhost:8443/ejbca/ejbca-rest-api/v1/cryptotoken/{cryptotoken_name}/generatekeys

The JSON configuration for the new keypair requires an alias, an optional algorithm, and a required curve type (ECDSA keypair) or size (RSA keypair).

The key algorithm is RSA for RSA keypairs and must be left blank for ECDSA keypairs. Here is an example of the JSON payload for creating an ECDSA keypair based on the prime256v1 ECC curve:

JS
{
  "key_pair_alias": "MyNewKeypair-ECC",
  "key_alg": "",
  "key_spec": "prime256v1"
}

and the expected cURL command for the above JSON body to modify a crypto token named OEM_Token:

BASH
curl -X POST "https://localhost:8443/ejbca/ejbca-rest-api/v1/cryptotoken/OEM_Token/generatekeys"  \
-H "accept: application/json" -H "Content-Type: application/json" \
-d "{ \"key_pair_alias\": \"MyNewKeypair-ECC\", \"key_alg\": \"\", \"key_spec\": \"prime256v1\" }"

Troubleshooting

Certificate Request Encoding

An exception like the following may be caused by an encoding issue:

IOException while decoding certificate request from PEM: -----END CERTIFICATE REQUEST

The issue can be resolved by manually replacing the linebreaks with \n.

Finding the Cause of Error Codes Returned to the Client

When you get an error message back, such as an HTTP 404 (BAD_REQUEST) the cause of the error can often be found in a message returned as part of the HTTP error. The full cause of the error is also typically visible in the server log file for administrators to see.

Converting DER format responses into PEM

Binary DER files have usually .cer, .crt or .der extensions, while PEM is strictly specified with PEM headers -----BEGIN / END CERTIFICATE----- and line breaks every 64 characters. More details in RFC7468.

Some REST calls return a DER certificate encoded in base64 within the JSON response body, in order to transfer the binary data in a JSON structure. It is identified with “response_format": "DER” in the JSON itself, and can be converted to PEM where required.

For instance, after a successful call to /v1/certificate/pkcs10enroll, the JSON output will contain a certificate object in base64, which can be extracted:

Process the JSON response with jq to extract the base64 DER data and output to a file

BASH
jq -r .certificate response_1617122570566.json > certificate-base64.b64

The base64 data can be decoded into the binary DER format:

Decode the DER back to binary

BASH
openssl base64 -d -A -in certificate-base64.b64 -out certificate-bin.crt

You can convert it to PEM, for example with openssl:

Convert DER to PEM using openssl

BASH
openssl x509 -inform der -in certificate-bin.crt -out certificate.pem

and openssl can also be used to back and forth between PEM and DER:

You could also convert from PEM to DER using openssl

BASH
openssl x509 -outform der -in certificate.pem -out certificate-bin.crt
JavaScript errors detected

Please note, these errors can depend on your browser setup.

If this problem persists, please contact our support.