Cert Safe REST API
The Cert Safe REST API allows storing and retrieving information about certificates.
Using the Cert Safe REST API, the Cert Safe Publisher allows you to configure EJBCA to publish certificate issuance and lifecycle events over HTTPS to a Cert Safe server, see Cert Safe Publisher.
Client Validation
There is a two-tier system of clients. At the top, there are accounts, each having many agents underneath. An account is provided for an organization, and may create agents to interact with the service.
Agents are useful for partitioning clients under an account, but they are not necessary. Interaction with the service solely through an account client is perfectly fine.
A client (account or agent) is identified to the service by an X.509 certificate.
For example, to validate to the service with curl:
curl \
--key client.key --cert client.crt \
https:
//api.url.com/
Example Data
All of the examples in this document pretend the following situation:
Acme Co. has an account under which they have registered two agents, Fred Dobler and Nancy Willson, named after the sysadmins who are responsible for those clients.
Fred has POSTed two certificates to the service; Nancy has posted 20. Acme Co. uses Acme CA as its certificate authority.
Errors and Response Codes
Cert Safe attempts to return relevant HTTP Status codes to all requests. Error status codes (4XX and 5XX) are accompanied by an error JSON object containing an explanation for the error.
Here is an example error json response.
{
"error"
:
"an
error
message
goes
here"
}
Example Curl
> curl -i \
--key client.key --cert client.crt \
https:
//api.url.com/phil
HTTP/
1.1
401
Unauthorized
...
{
"error"
: "attempt to access account `https:
//api.url.com/phil' failed. available accounts:
}
Lists of Resources
Cert Safe provides a uniform interface to resources which are lists of other resources.
Common Request Parameters
details
If "true", instead of returning an array of URIs to resources, return an array of link objects, which are dicts with the two keys: 'uri' and 'data', containing the URI of the resource and the (expanded) resource, respectively.
An example link object.
{
"uri"
:
"https://api.url.com/Acme%20Co./agents/Nancy%20Willson"
,
"data"
: {
"name"
:
"Nancy%20Willson"
,
"lastHeartbeat"
:
"1389738970"
,
"apiCertificate"
: {
"thumbprint"
: {
"alg"
:
"SHA-256"
,
"hash"
:
"c98a6d2d2c9ccb3f63a6494e982f1d05022d4985f2186443e299a5afd55d6a3c"
},
"pem"
: "-----BEGIN CERTIFICATE-----\nMIID2zCCAsOgAwIBAgIJAPpN61MIpHHJMA0GCSqGSIb3DQEBBQUAMIGDMQswCQYD\
}
}
}
Curl Examples
With details = “true”.
curl \
--key client.key --cert client.crt \
'https://api.url.com/Acme%20Co./agents?details=true'
[
{
"uri"
:
"https://api.url.com/Acme%20Co./agents/Fred%20Dobler"
,
"data"
: {
"name"
:
"Fred%20Dobler"
,
"lastHeartbeat"
:
"1389738970"
,
"apiCertificate"
: {
"thumbprint"
: {
"alg"
:
"SHA-256"
,
"hash"
:
"243f1fddc99c31d3e0fa6124b7f89fbda9e669ca2d6251029b0751cff3b6477c"
},
"pem"
: "-----BEGIN CERTIFICATE-----\nMIID2TCCAsGgAwIBAgIJAMnlAFWbfUZOMA0GCSqGSIb3DQEBBQUAMIGCMQswCQYD\
}
}
},
{
"uri"
:
"https://api.url.com/Acme%20Co./agents/Nancy%20Willson"
,
"data"
: {
"name"
:
"Nancy%20Willson"
,
"lastHeartbeat"
:
"1389738970"
,
"apiCertificate"
: {
"thumbprint"
: {
"alg"
:
"SHA-256"
,
"hash"
:
"c98a6d2d2c9ccb3f63a6494e982f1d05022d4985f2186443e299a5afd55d6a3c"
},
"pem"
: "-----BEGIN CERTIFICATE-----\nMIID2zCCAsOgAwIBAgIJAPpN61MIpHHJMA0GCSqGSIb3DQEBBQUAMIGDMQswCQYD\
}
}
}
]
With details != “true”.
curl \
--key client.key --cert client.crt \
https:
//api.url.com/Acme%20Co./agents
[
"https://api.url.com/Acme%20Co./agents/Fred%20Dobler"
,
"https://api.url.com/Acme%20Co./agents/Nancy%20Willson"
]
Pagination Parameters
If requesting all elements of a list is too much, results can be paged by setting any of the following parameters. Paging returns an array of elements wrapped in a cursor.
*after* The identifier of an element after which to return elements.
*before* The identifier of an element before which to return elements.
*limit* The maximum number of elements returned.
Curl Examples
An example setting all pagination-related parameters in the request.
curl \
--key client.key --cert client.crt \
'https://api.url.com/Acme%20Co./certificates?limit=5'
response:
{
"paging"
: {
"before"
:
"9e3910d77f33896f0d06280f2cd8b632c2e9758e4101af7ee43e6464036a7f62.1389738983"
,
"after"
:
"52fc245a4b2987ca75aff6f9eab946319c53d94ef2e170837eeeadf6d33cabd0.1389738983"
,
"next"
:
"https://api.url.com/Acme%20Co./certificates?limit=5&after=52fc245a4b2987ca75aff6f9eab946319c53d94ef2e170837eeeadf6d33cabd0.1389738983"
},
"data"
: [
"https://api.url.com/Acme%20Co./certificates/9e3910d77f33896f0d06280f2cd8b632c2e9758e4101af7ee43e6464036a7f62/"
https:
//api.url.com/Acme%20Co./certificates/e68fafbac9d1efe4c63ebeb31acb3ea9bcb4c74e1ab652c5fb7d6a37d80f1b7d/"
https:
//api.url.com/Acme%20Co./certificates/4e686b2a8993c7c9ac130785a19c7b530dd0a7c79abc75f09369f0a6b6bae269/"
https:
//api.url.com/Acme%20Co./certificates/93eab1340011da735c6133ecdc521968eb3648a20b710bad5b0cbbc8d4011122/"
https:
//api.url.com/Acme%20Co./certificates/52fc245a4b2987ca75aff6f9eab946319c53d94ef2e170837eeeadf6d33cabd0/
]
}
An example using details=true with pagination.
curl \
--key client.key --cert client.crt \
'https://api.url.com/Acme%20Co./certificates?details=true&limit=2'
response:
{
"paging"
: {
"before"
:
"e68fafbac9d1efe4c63ebeb31acb3ea9bcb4c74e1ab652c5fb7d6a37d80f1b7d.1389738983"
,
"after"
:
"9e3910d77f33896f0d06280f2cd8b632c2e9758e4101af7ee43e6464036a7f62.1389738983"
,
"next"
:
"https://api.url.com/Acme%20Co./certificates?details=true&limit=2after=9e3910d77f33896f0d06280f2cd8b632c2e9758e4101af7ee43e6464036a7f62.1389738983"
},
"data"
: [ {
"uri"
:
"https://api.url.com/Acme%20Co./certificates/e68fafbac9d1efe4c63ebeb31acb3ea9bcb4c74e1ab652c5fb7d6a37d80f1b7d/"
data": {
"status"
:
"active"
,
"thumbprint"
: {
"alg"
:
"SHA-256"
,
"hash"
:
"e68fafbac9d1efe4c63ebeb31acb3ea9bcb4c74e1ab652c5fb7d6a37d80f1b7d"
},
"timestamp"
:
"1389738983"
,
"revocationReason"
:
"caComprimise"
,
"pem"
: "-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIJAMdwFqDi3hUUMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV\
}
},
{
"uri"
: "https:
//api.url.com/Acme%20Co./certificates/9e3910d77f33896f0d06280f2cd8b632c2e9758e4101af7ee43e6464036a7f62/
"data"
: {
"status"
:
"active"
,
"thumbprint"
: {
"alg"
:
"SHA-256"
,
"hash"
:
"9e3910d77f33896f0d06280f2cd8b632c2e9758e4101af7ee43e6464036a7f62"
},
"timestamp"
:
"1389738983"
,
"revocationReason"
:
"privilegeWithdrawn"
,
"pem"
: "-----BEGIN CERTIFICATE-----\nMIIDdzCCAl+gAwIBAgIJAJSbDSeDItscMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV\
}
}
]
}
Resources
GET /:account
Retrieve metadata about an account.
Path Parameters
account - The account name. This is the same value as the name field of the account to be retrieved.
Curl Example
curl \
--key client.key --cert client.crt \
https:
//api.url.com/Acme%20Co.
{
"lastAgentUpdated"
:
1389147041
,
"lastAgentHeartbeat"
:
1389147041
,
"name"
:
"Acme%20Co."
,
"cas"
: [
{
"name"
:
"Acme CA"
,
"validCerts"
:
5001
,
"revokedCerts"
:
4000
,
"totalCerts"
:
9001
}
],
"agents"
: [
"https://api.url.com/Acme%20Co./agents/Fred%20Dobler"
,
"https://api.url.com/Acme%20Co./agents/Nancy%20Willson"
],
"contacts"
: [
"fred@example.com"
,
"nancy.example.com"
],
"creationDate"
:
1389147041
}
Get /:account/agents
Retrieve the list o f agents registe red under account.
Path Parameters
account - The account name. This is the same value as the name field o f the account who's agents are retrieved.
Curl Example
curl \
--key client.key --cert client.crt \
https:
//api.url.com/Acme%20Co./agents
[
"https://api.url.com/Acme%20Co./Fred%20Dobler"
,
"https://api.url.com/Acme%20Co./agents/Nancy%20Willson"
]
POST /:account/agents
Register a new agent under account. This operation can only be performed with the root account validation certificate. All requests made with an agent certificate will be refused with a 403 HTTP error code.
Path Parameters
account - The account name. This is the same value as the name field of the account un der which you are registering an agent.
Request Body
The request body should be a json object with the following fields:
name - A unique name to identify the agent by. This is required to be a valid pathComponent.
certificate - The certificate the agent will use to interact with the API, in PEM format.
Curl Example
agent.json
{
"name"
:
"Fran%20Dresser"
,
"certificate"
: "-----BEGIN CERTIFICATE-----\nMIIDzTCCArWgAwIBAgIJAIdzifeP5GrKMA0GCSqGSIb3DQEBBQUAMH0xCzAJBgNV\
}
curl \
-x POST \
--key client.key --cert client.crt \
--Header
"Content-Type: application/json"
\
--data
@agent
.json \
https:
//api.url.com/Acme%20Co./agents
[
"https://api.url.com/Acme%20Co./agents/Fred%20Dobler"
]
GET /:account/agents/:agent
Query a specific agent.
Path Parameters
Curl Example
curl \
--key client.key --cert client.crt \
https:
//api.url.com/Acme%20Co./agents/Fred%20Dobler
{
"name"
:
"Fred%20Dobler"
,
"lastHeartbeat"
:
1389147892
,
"apiCertificate"
: {
"thumbprint"
: {
"alg"
:
"SHA-256"
,
"hash"
:
"a790e34c004019fb401e18764063053f8eabd718297d5d47f821f9a44628723b"
},
"pem"
: "-----BEGIN CERTIFICATE-----\nMIIE4jCCA8qgAwIBAgISESHa7VrcABc10XWhUrsLeaqcMA0GCSqGSIb3DQEBBQUA\}
}
DELETE /:account/agents/:agent
Unregister an agent. This operation can only be performed with the root account certificate. All requests made with an agent certificate are refused with an HTTP 403.
Path Parameters
Curl Example
curl \
--key client.key --cert client.crt \
--request DELETE \
https:
//api.url.com/Acme%20Co./agents/Fred%20Dobler
POST /:account/agents/:agent/heartbeat
Let us know client agent is still alive.
Path Parameters
Curl Example
curl \
--key client.key --cert client.crt \
--request POST \
https:
//api.url.com/Acme%20Co./agents/Fred%20Dobler
GET /:account/certificates
Retrieve a list of certificates ordered from most recent to least recent.
Path Parameters
account - The account name. This is the same value as the name field of the account who's certificates are retrieved.
Request Parameters
All request parameters are optional.
agent - Retrieve only certificates which have been updated b y the agent who's nam e field matches this value.
status - Retrieve only certificates whose status field is this value.
Curl Example
curl \
--key client.key --cert client.crt \
https:
//api.url.com/Acme%20Co./certificates
[
"https:
//api.url.com/Acme%20Co./certificates/dcbc8bfb416999122770b500f9aaa4b73e3b7ec7bb674c8fdc1ab60acb52c272/
]
POST /:account/certificates
Create a new certificate entry.
Path Parameters
account - The account name. This is the same value as the name field of the account who's certificates are retrieved.
Request Body
The request body should be a json object with the following fields:
status (required) - T he status in the status field of the certificate.
revocationReason (optional) - The reason in the reason field of the certificate. Defaults to "unspecified". If the certificate's status is not "revoked", it is an error to set this value to anything other than "unspecified".
pem (required) - The certificate in PEM format.
Curl Example
certificate.json
{
"status"
:
"revoked"
,
"revocationReason"
:
"keyComprimise"
,
"pem"
: "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIJAMlXXOH8xC0QMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV\
}
curl \
-x POST \
--key client.key --cert client.crt \
--Header
"Content-Type: application/json"
\
--data
@certificate
.json \
https:
//api.url.com/Acme%20Co./certificates
GET /:account/certificates/:certificate-thumbprint
A list of the states a certificate identified by thumbprint has been in.
Path Parameters
account - The account name. This is the same value as the name field of the account who's certificates are retrieved.
certificate-thumbprint - The hash of the certificate you want to retrieve the history of.
Curl Example
curl \
--key client.key --cert client.crt \
https:
//api.url.com/Acme%20Co./certificates/dcbc8bfb416999122770b500f9aaa4b73e3b7ec7bb674c8fdc1ab60acb52c272
[
"https:
//api.url.com/Acme%20Co./certificates/dcbc8bfb416999122770b500f9aaa4b73e3b7ec7bb674c8fdc1ab60acb52c272/
]
GET /:account/certificates/:certificate-thumbprint/:timestamp
Retrieve a specific state that the certificate indicated by certificate-thumbprint transitioned to at timestamp.
Path Parameters
account - The account name. This is the same value as the name field of the account who's certificates are retrieved.
certificate-thumbprint - The hash of the certificate you want to retrieve a specific state for.
timestamp - The same unixTime as the timestamp field of the certificate resource to retrieve.
Curl Example
curl \
--key client.key --cert client.crt \
https:
//api.url.com/Acme%20Co./certificates/dcbc8bfb416999122770b500f9aaa4b73e3b7ec7bb674c8fdc1ab60acb52c272/
{
"thumbprint"
: {
"alg"
:
"SHA-256"
,
"hash"
:
"a790e34c004019fb401e18764063053f8eabd718297d5d47f821f9a44628723b"
},
"status"
:
"active"
,
"timestamp"
:
1389640253
,
"revocationReason"
:
"unspecified"
,
"pem"
: "-----BEGIN CERTIFICATE-----\nMIIE4jCCA8qgAwIBAgISESHa7VrcABc10XWhUrsLeaqcMA0GCSqGSIb3DQEBBQUA\
}
Schema
cursor
The next and prev fields point to the previous and next pages. after is an identifier for the last element of this page. before is an identifier for the first element of this page. They are named this way because after is what you would set the “after” query parameter to get the next page, and before is what you would set the “before” query parameter to get the previous page.
{
“paging” {
“after”: elemnt identifier,
“before”: element identifier,
“next”: uri,
“prev”: uri
},
“data”: [ element ]
}
pathComponent
A percent encoded string. It is intended that a web-ui user inputs and sees the percent-decoded value. An API user is expected to perform encoding and decoding.
unixTime
A whole number representing milliseconds since the Unix epoch. This can be conveniently transformed into a date object in many languages. For example, in JavaScript:
var
date =
new
Date(unixTime)
thumbprint
A hash of something.
{
"alg"
: hashAlgorithm,
"hash"
: base64 hash
}
hashAlgorithm
The set of possible hash algorithms may grow in the future, but an element will never be removed. Currently the list is as follows:
"SHA-256"
agent
{
“name”: pathComponent,
“lastHeartbeat”: unixTime,
“apiCertificate”: {
“thumbprint”: thumbprint,
“pem”: certificate in PEM format
}
}
account
{
“lastAgentUpdateTimestamp”: unixTime,
“lastAgentHeartbeatTimestamp”: unixTime,
“name”: pathComponent,
“cas”: [ certificateAuthority ],
“agents”: [ uri ],
“contacts”: [ email address ],
“creationTimestamp”: unixTime
}
certificateAuthority
{
“name”: JSON String,
“validCerts”: positive integer,
“revokedCerts”: positive integer,
“totalCerts”: positive integer
}
certificate
{
“thumbprint”: thumbprint,
“status”: status,
“timestamp”: unixTime,
“revocationReason”: reason,
“pem”: certificate in PEM format
}
status
One of the following strings:
"hold"
"active"
"revoked"
"suspended"
reason
One of the following strings:
"unspecified"
"keyComprimise"
"caComprimise"
"aaComprimise"
"affiliationChanged"
"superseded"
"cessationOfOperation"
"certificateHold"
"removeFromCrl"
"privilegeWithdrawn"
error
{
“error”: string
}