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/
CODE

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: 
}
CODE

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\
		}
	}
}
CODE

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\
		}
	  }
	}
]
CODE

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"
]
CODE

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'
CODE

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/
	]
}
CODE

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'
CODE

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\
		}
	   }
	]
}
CODE

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
}
CODE

Get /:account/agents

Retrieve the list of agents registered under account.

Path Parameters

  • account - The account name. This is the same value as the name field of 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"
]
CODE

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 under 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"
]
CODE

GET /:account/agents/:agent

Query a specific agent.

Path Parameters

  • account - The account name. This is the same value as the name field of the account
  •  who's agent is retrieved.
  • agent - The agent name. This is the same value as the name field of the agent that is retrieved.

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\}
}
CODE

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

  • account - The account name. This is the same value as the name field of the account who's agent is unregistered.
  • agent - The agent name. This is the same value as the name field of the agent being unregistered.

Curl Example

curl \
	--key client.key --cert client.crt \
	--request DELETE \
	https://api.url.com/Acme%20Co./agents/Fred%20Dobler
CODE

POST /:account/agents/:agent/heartbeat

Let us know client agent is still alive.

Path Parameters

  • account - The account name. This is the same value as the name field of the account who's agent you heartbeat.
  • agent - The agent name. This is the same value as the name field of the agent to heartbeat.

Curl Example

curl \
	--key client.key --cert client.crt \
	--request POST \
https://api.url.com/Acme%20Co./agents/Fred%20Dobler
CODE

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 by the agent who's name 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/
]
CODE

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) - The 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
CODE

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/
]
CODE

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\
}
CODE

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 ]
}
CODE

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) 
JS

thumbprint

A hash of something.

 {
	"alg": hashAlgorithm, 
	"hash": base64 hash
} 
CODE

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
	}
}
CODE

account

{
	“lastAgentUpdateTimestamp”: unixTime,
	“lastAgentHeartbeatTimestamp”: unixTime,
	“name”: pathComponent,
	“cas”: [ certificateAuthority ],
	“agents”: [ uri ],
	“contacts”: [ email address ],
	“creationTimestamp”: unixTime
}
CODE

certificateAuthority

{
	“name”: JSON String,
	“validCerts”: positive integer,
	“revokedCerts”: positive integer,
	“totalCerts”: positive integer
}
CODE

certificate

{
	“thumbprint”: thumbprint,
	“status”: status,
	“timestamp”: unixTime,
	“revocationReason”: reason,
	“pem”: certificate in PEM format
}
CODE

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
}
CODE