ACME
ENTERPRISE This is an EJBCA Enterprise feature.
ACME Overview
The Automatic Certificate Management Environment (ACME) is a protocol that a Certificate Authority (CA) and an applicant can use to automate the process of verification and certificate issuance.
Supported Operations
The ACME RFC Internet-Draft is a working document. The EJBCA implementation currently complies with IETF - ACME Draft 12.
Operation |
URL |
Description |
Draft Reference |
directory |
/ejbca/acme/directory |
Provides a JSON object describing the other commands. |
|
newNonce |
/ejbca/acme/newNonce |
Before any POST action is performed, the client needs to retrieve an anti-replay nonce from the server. |
|
newAccount |
/ejbca/acme/newAccount |
||
updateAccount |
/ejbca/acme/acct/{accountId} |
||
newOrder |
/ejbca/acme/newOrder |
||
challengeResponse |
/ejbca/acme/acct/{accountId}/authz/{authorizationId}/{challengeId} |
||
newAuthz |
/ejbca/acme/newAuthz |
Only if Pre-Authorization Allowed is enabled in the Alias configuration. |
|
finalizeOrder |
/ejbca/acme/acct/{accountId}/orders/{orderId}/finalize |
||
revokeCert |
/ejbca/acme/revokeCert |
||
keyChange |
/ejbca/acme/keyChange |
URL Endpoints and Aliases
The ACME service is available on the following URLs.
Default alias with client authentication |
https://<server>:8443/ejbca/acme/directory |
Default alias without client authentication |
https://<server>:8442/ejbca/acme/directory |
Custom alias <alias_name> with client authentication |
https://<server>:8443/ejbca/acme/directory?configurationId=<alias_name> |
Custom alias <alias_name> without client authentication |
https://<server>:8442/ejbca/acme/directory?configurationId=<alias_name> |
EJBCA Specifics
Approvals in EJBCA for certificate issuance and revocation cannot be used with ACME.
All ACME operations are performed over the peers protocol. Thus it is perfectly possible to use an external RA running EJBCA as an ACME proxy.
Validators for CAA checking etc. are configured as described in Validators.
You need to set up separate aliases for each end entity profile/certificate profile and CA.
Configuration
Enabling ACME
The ACME protocol is by default disabled. To enable the service, go to Admin Web > System Configuration > Protocol Configuration and select Enable for ACME.
Managing ACME Configurations
Much like other protocols in EJBCA, several different ACME configurations can be maintained at the same time using aliases.
To configure ACME, select ACME Configuration under the System Configuration menu.
Global Fields
The following fields are defined globally for all ACME operations.
Field |
Description |
Default ACME Configuration |
The configuration to use if the specified alias doesn't exist. |
Replay Nonce Validity Number |
Defines the validity in milliseconds of a generated replay nonce. |
Alias Specific Fields
The following table lists ACME specific fields for each individual alias.
Field |
Description |
End Entity Profile |
The end entity profile to use for end entities enrolled using this alias. The CA signing the certificate is the default CA of this end entity profile, and the certificate profile used for the certificate is the default certificate profile of this end entity profile. |
Pre-Authorization Allowed |
Pre-authorization, as defined in section 7.4.1 of the draft. |
Wildcard Certificate Issuance Allowed |
Whether this alias can be used to issue certificates with wildcard DNS names in their SANs. See section 7.1.3 of the draft. |
Site URL |
URL to a website describing this CA. Optional. See section 7.1.1 of the draft. |
Terms of Service URL |
URL to your terms of service for ACME. Optional. See section 7.1.1 of the draft. |
Require client approval for Terms of Service changes |
Specifies whether users must approve the new version if the Terms of Service URL is changed. |
DNS Resolver |
A specified DNS resolver, used when processing dns01 challenges. |
DNS Port |
Port used for DNS communications. |
DNSSEC Trust Anchor |
The ICANN trust anchor, configurable should it ever change. |
The optional feature External Account Binding is not supported in this release. The corresponding field in the directory output (externalAccountRequired) is disabled by default and not editable.
End Entity Profile Configuration
The following settings should be used for an end entity profile used with ACME.
Field |
Value |
Username |
Auto-generated |
Password (or Enrollment Code) |
Leave empty |
Batch generation (clear text pwd storage) |
Use |
End Entity E-mail |
Use, Required, Modifiable |
Subject DN Attributes |
|
CN, Common name |
Required, Modifiable |
Default Certificate Profile |
<The certificate profile to use> |
Default CA |
<The CA signing the certificate> |
Default Token |
User Generated |
Authentication and Validation
EJBCA currently supports the two validation methods http01 and dns01, defined in section 8 of the draft.
HTTP Challenge (http01)
If the client chooses to use the http01 challenge type, it intends to prove that it controls the domain requested in the certificate by provisioning a resource under the same domain name. As per the draft, EJBCA will send out a challenge to the client, which the client will sign using its private key and provide on the domain in a known location for EJBCA to retrieve. EJBCA will then be able to use the public key provided in the original request to verify domain control.
DNS Challenge (dns01)
If the client chooses to use the dns01 challenge type, it instead obligates itself to supply a TXT record containing the same token response as described above. As per the draft, DNSSEC is required for dns01 challenges.
Compatibility with ACME Clients
EJBCA is compatible with the following ACME clients (taken from Letsencrypt's list of compatible ACME clients):
EJBCA ACME with Certbot
Certbot used to be Let's Encrypt's official client but is now maintained by the Electronic Frontier Foundation. It is one of the most used ACME clients, supporting issuance, renewal and revocation operations, which are all supported by EJBCA. For more information, refer to the Certbot Documentation.
Certbot by default uses Let's Encrypts servers. To specify an alternative server URL, use the --server option:
--server https:
//localhost:8442/ejbca/acme/directory
Note that you can also use the server option in cli.ini.
Certbot Examples
The following HTTP Validation and DNS Validation examples assume that a Ubuntu machine with JBoss 6.4 is used and that EJBCA is accessible under https://localhost:8442 public HTTPS, using certbot 0.26.1.
First, run the following command in the command line to ensure that a connection to the ACME server is up and running:
curl -k https:
//localhost:8442/ejbca/acme/directory
The successful output of the above command should be as follows (showing the resources available in the EJBCA ACME server), otherwise the scenarios will fail:
{
"newNonce"
:
"https://localhost:8442/ejbca/acme/newNonce"
,
"newAccount"
:
"https://localhost:8442/ejbca/acme/newAccount"
,
"newOrder"
:
"https://localhost:8442/ejbca/acme/newOrder"
,
"revokeCert"
:
"https://localhost:8442/ejbca/acme/revokeCert"
,
"keyChange"
:
"https://localhost:8442/ejbca/acme/keyChange"
,
"meta"
:{
"termsOfService"
:
"https://example.com/acme/terms"
,
"website"
:
"https://www.example.com/"
,
"caaIdentities"
:[],
"externalAccountRequired"
:
false
}}
HTTP Validation Example
This example covers setting up a local HTTP server, issuing a certificate for an identifier using HTTP validation, and also shows how to revoke the certificate.
1) Setup a Local HTTP Server
The following describes setting up a local HTTP server. Note that you can optionally use the temporary web server (or any other supported HTTP server plugins) provided by Certbot. For more information, refer to the Certbot Documentation on Getting certificates (and choosing plugins).
Follow the steps below to setup a local HTTP server (for example Apache with the default working directory /var/www/html):
Add the following virtual host under /etc/apache2/sites-available/example.com.conf:
<VirtualHost *:
80
>
ServerName example.com
DocumentRoot
"/var/www/html/"
</VirtualHost>
Enable the site using the a2ensite command:
sudo a2ensite example.com
Reload the Apache configuration using the reload command:
sudo service apache2 reload
Next, restart Apache:
sudo /etc/init.d/apache2 restart
Then add the following line to your /etc/hosts file:
127.0
.
0.1
example.com
2) Obtain a Certificate using Certbot
To issue a certificate for an identifier (in this case example.com) using Certbot, do the following. It requires that you have Certbot installed on your machine, and that EJBCA is up and running with ACME enabled and with an ACME alias configured with an appropriate end entity profile.
To obtain the certificate, run the Certbot certonly sub command:
sudo certbot --no-verify-ssl certonly --webroot -w /var/www/html/ -d example.com --server https:
//localhost:8442/ejbca/acme/directory
Alternatively, to instead issue a certificate for a wildcard domain, enable the Wildcard Certificate Issuance Allowed option on the ACME Configuration Alias page (see Alias Specific Fields) and run the Certbot certonly sub command providing a wildcard domain as identifier:
sudo certbot --no-verify-ssl certonly --webroot -w /var/www/html/ -d *.example.com --server https:
//localhost:8442/ejbca/acme/directory
If successful, a message similar to the following is displayed:
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/example.com/privkey.pem Your cert will expire on 2020-08-21. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew"
If you run the same certbot certonly command twice, Certbot asks if you want to renew the current certificate. To allow renewal using the same Subject DN name, the Enforce Unique DN field on the Edit CA page must be cleared. For more information, see CA Fields.
To verify the obtained certificate, go to the EJBCA Admin Web, search for End Entities, and check that there is a End Entity certificate with the status Generated and CN = example.com.
The error message The client lacks sufficient authorization :: The client lacks sufficient authorization indicates a conflict between the new account creation and existing ACME accounts. To resolve, remove everything under /etc/letsencrypt/live, /etc/letsencrypt/accounts and /etc/letsencrypt/keys and try again.
3) Revoke Certificate
This example covers how to revoke the certificate issued in the previous step.
To revoke the issued certificate, run the Certbot revoke command:
sudo certbot --no-verify-ssl --server https:
//localhost:8442/ejbca/acme/directory revoke --cert-path /etc/letsencrypt/live/example.com/fullchain.pem
When asked to verify deleting the issued certificate, reply with Y. The following success message displays:
Congratulations! You have successfully revoked the certificate that was located at /etc/letsencrypt/live/example.com/fullchain.pem
To verify, go to EJBCA Admin Web and check the status for the corresponding End Entity certificate and ensure that it is revoked.
DNS Validation Example
This example covers verifying your DNS server setup, issuing a certificate for an identifier using Domain Name System Security Extensions ( DNSSEC ) validation, and also shows how to revoke the certificate.
1) Verifying DNS Server Setup
Ensure that you have a DNS server setup which you can add TXT records to. In this example, dnsmasq is used, included in most Linux distributions.
The EJBCA ACME server currently supports DNSSEC validation and this example uses allow.klaan.nu to be able to pass DNSSEC validation.
2) Obtain a Certificate using Certbot
To issue a certificate for an identifier (in this case allow.klaan.nu) using Domain Name System Security Extensions ( DNSSEC ) validation , do the following.
To obtain the certificate, run the Certbot certonly sub command and specify the --manual flag to run Certbot interactively and allow preparing the DNS server with the DNS challenge offered by the ACME server:
sudo certbot --no-verify-ssl certonly --manual --preferred-challenges=dns -d allow.klaan.nu --server https:
//localhost:8442/ejbca/acme/directory
Alternatively, to instead issue a certificate for a wildcard domain, enable the Wildcard Certificate Issuance Allowed option on the ACME Configuration Alias page (see Alias Specific Fields) and run the Certbot certonly sub command providing a wildcard domain as identifier:
sudo certbot --no-verify-ssl certonly --manual --preferred-challenges=dns -d *.allow.klaan.nu --server https:
//localhost:8442/ejbca/acme/directory
Agree to your IP being logged by replying Yes to the following:
Are you OK with your IP being logged? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o:
Certbot displays the TXT record challenge offered by the ACME server which have to be provisioned in the DNS server. Before pressing Enter, run the following command to provision the TXT record in dnsmasq:
sudo dnsmasq --port=
"1453"
--txt-record=
"_acme-challenge.allow.klaan.nu, pULO3RjCbzqjWH0JK2FQ5BDe-5SI2Eo2Vn1l_fmrtdk"
--listen-address=
"127.0.0.1"
--
interface
=
"lo"
--bind-interfaces
The port number used above is just an example. Note that the port number must equal the port set for the ACME Alias currently used by the EJBCA ACME server, configured in Admin Web>System Configuration>ACME Configuration. In addition, the DNS Resolver field needs to be set to localhost in the ACME Configuration Alias page, see Alias Specific Fields.
After running the above command, press Enter in the Certbot command prompt to continue. A message similar to the following is displayed for a successful certificate issuance:
IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/allow.klaan.nu/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/allow.klaan.nu/privkey.pem Your cert will expire on 2020-08-21. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew"
To verify that the certificate is issued in EJBCA, go to the EJBCA Admin Web, and check that the End Entity Search page includes a row with CN = allow.klaan.nu and a valid certificate.
3) Revoke Certificate
This example covers how to revoke the certificate issued in the previous step.
To revoke the issued certificate, run the Certbot revoke command:
sudo certbot --no-verify-ssl --server https:
//localhost:8442/ejbca/acme/directory revoke --cert-path /etc/letsencrypt/live/allow.klaan.nu/fullchain.pem
If successful, the following message displays:
Congratulations! You have successfully revoked the certificate that was located at /etc/letsencrypt/live/allow.klaan.nu/fullchain.pem
To verify, ensure that the certificate is revoked with the reason Unspecified by checking its status in the EJBCA Admin Web End Entity Search page.
EJBCA ACME with PJAC
Porunov Java ACME Client (PJAC) is an application based on acme4j , a Java ACME library implementation. To try out EJBCA with PJAC, just follow these guides for Example scenarios.
EJBCA is tested with the following PJAC flows:
Get a certificate for multiple domains
Renew a certificate for multiple domains
Get a wildcard certificate
Revoke certificate
Deactivate account
HTTP01 and DNS01 challenge types
Note that you need to configure PJAC to have the EJBCA instance as its ACME service, by adding the following extra parameter to every acme_client.jar command execution:
-u https:
//localhost:8442/ejbca/acme/directory
For example, the 5th step in the Get a certificate for multiple domains guide would look like this:
java -jar acme_client.jar --
command
register -a
/etc/pjac/account
.key
--with-agreement-update -u https:
//localhost
:8442
/ejbca/acme/directory
EJBCA ACME with ACME Tiny
Clone the repository:
git clone https:
//github.com/diafygi/acme-tiny.git
Change EJBCA ACME URLs:
-DEFAULT_CA =
"https://acme-v02.api.letsencrypt.org"
# DEPRECATED! USE DEFAULT_DIRECTORY_URL INSTEAD
-DEFAULT_DIRECTORY_URL =
"https://acme-v02.api.letsencrypt.org/directory"
+
+DEFAULT_CA =
"https://{ejbca_url}:8442"
# DEPRECATED! USE DEFAULT_DIRECTORY_URL INSTEAD
+DEFAULT_DIRECTORY_URL =
"https://{ejbca_url}:8442/ejbca/acme/directory"
Prepare input for ACME:
# Generate
private
key
openssl genrsa
4096
> account.key
# Generate CSR
openssl req -
new
-sha256 -key account.key -subj
"/emailAddress=acme_test@primekey.com/CN=my.acme"
> account.csr
Launch ACME Tiny (Tested with Python2):
sudo python acme_tiny.py --account-key ./account.key --csr ./account.csr --acme-dir ./acme-dir/ --contact
'mailto:acme@primekey.com'
> ./signed_chain.crt
where --acme-dir ./acme-dir/ might be integrated and/or point to your current web server, for example Apache2 /var/www/html/.well-known/acme-challenge/.
Workflow Examples
The following lists ACME calls to perform in order to get a certificate.
getDirectory request
Verifies that the EJBCA ACME service is up and running.
GET /acme/directory HTTP/
1.1
{
"newNonce"
:
"https://footrust.local:8443/ejbca/acme/newNonce"
,
"newAccount"
:
"https://footrust.local:8443/ejbca/acme/newAccount"
,
"newOrder"
:
"https://footrust.local:8443/ejbca/acme/newOrder"
,
"newAuthz"
:
"https://footrust.local:8443/ejbca/acme/newAuthz"
,
"revokeCert"
:
"https://footrust.local:8443/ejbca/acme/revokeCert"
,
"keyChange"
:
"https://footrust.local:8443/ejbca/acme/keyChange"
,
"meta"
:{
"termsOfService"
:
"https://footrust.com/acme/terms"
,
"website"
:
"https://footrust.com"
,
"caaIdentities"
:[
"footrust.com"
],
"externalAccountRequired"
:
false
}
}
newAccount
Creates a new ACME account to EJBCA. EJBCA uses a public key to verify the JWS (that is, the jwk element of the JWS header) to authenticate future requests from the account. EJBCA supports RSA and EC key types.
POST https:
//localhost:8442/ejbca/acme/newAccount HTTP/1.1
Content-Type: application/jose+json
{
"protected"
: base64url({
"alg"
:
"ES256"
,
"jwk"
: {...},
"nonce"
:
"6S8IqOGY7eL2lsGoTZYifg"
,
"url"
:
"https://example.com/acme/newAccount"
}),
"payload"
: base64url({
"termsOfServiceAgreed"
:
true
,
"contact"
: [
"mailto:cert-admin@example.com"
,
"tel:+12025551212"
]
}),
"signature"
:
"RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
}
newOrder request
To create a new ACME order.
POST /acme/newOrder HTTP/
1.1
Content-Type: application/jose+json
{
"protected"
: base64url({
"alg"
:
"ES256"
,
"kid"
:
"https://example.com/acme/acct/1"
,
"nonce"
:
"5XJ1L3lEkMG7tR6pA00clA"
,
"url"
:
"https://example.com/acme/new-order"
}),
"payload"
: base64url({
"identifiers"
: [
{
"type"
:
"dns"
,
"value"
:
"example.com"
}
],
"notBefore"
:
"2016-01-01T00:00:00Z"
,
"notAfter"
:
"2016-01-08T00:00:00Z"
}),
"signature"
:
"H6ZXtGjTZyUnPeKn...wEA4TklBdh3e454g"
}
The newOrder response contains information about challenges. For more information, refer to the section 7.5.1 of the draft.
newAuthz request
POST /acme/newAuthz HTTP/
1.1
Host: example.com
Content-Type: application/jose+json
{
"protected"
: base64url({
"alg"
:
"ES256"
,
"jwk"
: {...},
"nonce"
:
"uQpSjlRb4vQVCjVYAyyUWg"
,
"url"
:
"https://example.com/acme/newAuthz"
}),
"payload"
: base64url({
"identifier"
: {
"type"
:
"dns"
,
"value"
:
"example.net"
}
}),
"signature"
:
"nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
}
challengeResponse request
To prove to EJBCA's ACME service that you possess control over the domain.
POST /acme/acct/{accountId}/authz/{authorizationId}/{challengeId} HTTP/
1.1
Content-Type: application/jose+json
{
"protected"
: base64url({
"alg"
:
"ES256"
,
"kid"
:
"https://example.com/acme/acct/1"
,
"nonce"
:
"Q_s3MWoqT05TrdkM2MTDcw"
,
"url"
:
"https://example.com/acme/authz/1234/0"
}),
"payload"
: base64url({}),
"signature"
:
"9cbg5JO1Gf5YLjjz...SpkUfcdPai9uVYYQ"
}
finalizeOrder request
To generate the certificate.
POST /acme/acct/{accountId}/orders/{orderId}/finalize HTTP
1.1
Content-Type: application/jose+json
{
"protected"
: base64url({
"alg"
:
"ES256"
,
"kid"
:
"https://example.com/acme/acct/1"
,
"nonce"
:
"MSF2j2nawWHPxxkE3ZJtKQ"
,
"url"
:
"https://example.com/acme/order/asdf/finalize"
}),
"payload"
: base64url({
"csr"
:
"MIIBPTCBxAIBADBFMQ...FS6aKdZeGsysoCo4H9P"
,
}),
"signature"
:
"uOrUfIIk5RyQ...nw62Ay1cl6AB"
}
The response to the finalizeOrder call is the certificate.
Status Codes
HTTP Status Code |
Description |
200 |
Success |
201 |
Created |
204 |
No content |
400 |
Bad request |
401 |
Unauthorized |
403 |
Forbidden |
404 |
Not found |
409 |
Conflict |