Content
The CA domain will be reffered as "CA.com"
and you should replace it with the CA of your choise like "letsencrypt.org".
Your domain will be reffered as "YourDomain.com"
and should be replaced with your domain like "smakdev.net".
1. Getting all dirs: // Firs of all you need to get all of the directories from the CA of your choice
To get the dirs you need to send a GET request to the servers /dir path like this:
GET /dir HTTP/1.1
en
CA.com
And the server should answer with something like this:
HTTP/1.1 200 OK
application/json
{
"newNonce": "https://CA.com/acme/new-nonce",
"newAccount": "https://CA.com/acme/new-account",
"newOrder": "https://CA.com/acme/new-order",
"newAuthz": "https://CA.com/acme/new-authz",
"revokeCert": "https://CA.com/acme/revoke-cert",
"keyChange": "https://CA.com/acme/key-change",
"meta": {
"termsOfService": "https://CA.com/acme/terms/2017-5-30",
"website": "https://CA.com/",
"caaIdentities": ["CA.com"],
"externalAccountRequired": false
}
}
These values should be saved for later use.
Sources:
rfc8555 section 7.1.1
2. Getting a Nonce: // The nonce will be used when making other requests to the server
To get a nonce you send a HEAD request with the "newNonce" directory from part 1.
HEAD /acme/newNonce HTTP/1.1
CA.com
And you will get something like this if successfull:
HTTP/1.1 200 OK
oFvnlFP1wIhRlYS2jTaXbA
no-store
<https://CA.com/acme/directory>;rel="index"
Take the value from the Replay-Nonce header and store it.
Sources:
rfc8555 section 7.2
3. Create account: // An account is needed if you want to do anything
This will be a long one.
To get an account you need to send a POST request to the "newAccount" directory from part 1.
POST /acme/new-account HTTP/1.1
CA.com
application/jose+json
{
"protected": base64url({
"alg": "ES256",
"jwk": {...},
"nonce": "6S8IqOGY7eL2lsGoTZYifg",
"url": "https://CA.com/acme/new-account"
}),
"payload": base64url({
"termsOfServiceAgreed": true
}),
"signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
}
This request is in jose format wich means there are some needed headers, so we will go through them a litle bit.
The "protected" header is like your id card.
The "alg"(algorithm) part is for algorithm type you use for the signature.
The "jwk" will be taken up later.
The "nonce" should be your nonce from part 2.
The "url" should be the entire url for a new account from part 1.
The "payload" header is like your bag with all of your stuff.
The "termsOfServiceAgreed" can be needed to be true to create an account.
The "signature" should be: base64url(ES256(base64url(protected)+'.'+base64url(payload))).
The base64url() means that everything inside should be base64url encoded before they are sent.
JWK
{
"kty": "EC",
"crv": "P-256",
"x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
}
The "kty" says what ryptographic algorithm family is used in the key, the recomended one is "EC".
The "crv" says what curve is used.
The "x" is the x possition of the curve.
The "y" is the y possition of the curve.
If you have done it right it should look something like this:
HTTP/1.1 201 Created
public, max-age=0, no-cache
application/json; charset=utf-8
https://CA.com/my-account/4
EksZN31XagCtew6Aev4RCA
Sat, 08 Jan 2022 16:50:35 GMT
232
{
"status": "valid",
"contact": null,
"key": {
"kty": "EC",
"crv": "P-256",
"x": "f83OJ3D2xF1Bg8vub9tLe1gHMzV76e8Tus9uPHvRVEU",
"y": "x_FEzRu9m36HLN_tue659LNpXW6pCyStikYjKIWI5a0"
},
"ID": "4"
}
You will need the value of the header.
Sources:
rfc7515
rfc8555 section 7.3
4. Create order:
To get a certificate you first need to place an order for you domain(s).
So send a POST request to the "newOrder" directory from part 1.
POST /acme/new-order HTTP/1.1
127.0.0.1
application/jose+json
{
"protected": base64url({
"alg": "ES256",
"kid": "https://CA.com/acme/acct/evOfKhNU60wg",
"nonce": "5XJ1L3lEkMG7tR6pA00clA",
"url": "https://CA.com/acme/new-order"
}),
"payload": base64url({
"identifiers": [
{ "type": "dns", "value": "www.YourDomain.com" },
{ "type": "dns", "value": "YourDomain.com" }
],
"notBefore": "2016-01-01T00:04:00+04:00",
"notAfter": "2016-01-08T00:04:00+04:00"
}),
"signature": "H6ZXtGjTZyUnPeKn...wEA4TklBdh3e454g"
}
And the result should be something like this:
HTTP/1.1 201 Created
MYAuvOpaoIiywTezizk5vw
<https://CA.com/acme/directory>;rel="index"
https://CA.com/acme/order/TOlocE8rfgo
{
"status": "pending",
"expires": "2016-01-05T14:09:07.99Z",
"notBefore": "2016-01-01T00:00:00Z",
"notAfter": "2016-01-08T00:00:00Z",
"identifiers": [
{ "type": "dns", "value": "www.yourSite.org" },
{ "type": "dns", "value": "yourSite.org" }
],
"authorizations": [
"https://CA.com/acme/authz/PAniVnsZcis",
"https://CA.com/acme/authz/r4HqLzrSrpI"
],
"finalize": "https://CA.com/acme/order/TOlocE8rfgo/finalize"
}
Save "authorizations" and "finalize" for later use.
5. Authorize domains:
To show to the CA that you own the domain you need to do challanges for all of the requested "identifiers".
You do this by first getting the identifier info by using the urls in "authorizations".
POST /acme/authz/PAniVnsZcis HTTP/1.1
CA.com
application/jose+json
{
"protected": base64url({
"alg": "ES256",
"kid": "https://CA.com/acme/acct/evOfKhNU60wg",
"nonce": "uQpSjlRb4vQVCjVYAyyUWg",
"url": "https://CA.com/acme/authz/PAniVnsZcis"
}),
"payload": "",
"signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
}
And you should get something like this
HTTP/1.1 200 OK
application/json
<https://CA.com/acme/directory>;rel="index"
{
"status": "pending",
"expires": "2016-01-02T14:09:30Z",
"identifier": {
"type": "dns",
"value": "YourDomain.com"
},
"challenges": [
{
"type": "http-01",
"url": "https://CA.com/acme/chall/prV_B7yEyA4",
"token": "DGyRejmCefe7v4NfDGDKfA"
}
]
}
This tutorial only covers the challenge type of "http-01".
You need to save the "challanges"[i]."type" for later and
give the token to your server so it can give it to your CA when requested.
Now it's time to inform the CA that we are ready for the challange.
You do this by sending a request to the challange url.
POST /acme/chall/prV_B7yEyA4 HTTP/1.1
CA.com
application/jose+json
{
"protected": base64url({
"alg": "ES256",
"kid": "https://CA.com/acme/acct/evOfKhNU60wg",
"nonce": "Q_s3MWoqT05TrdkM2MTDcw",
"url": "https://CA.com/acme/chall/prV_B7yEyA4"
}),
"payload": base64url({}),
"signature": "9cbg5JO1Gf5YLjjz...SpkUfcdPai9uVYYQ"
}
This should return an updated version of last response.
After the "status" of all the domains has become "valid"
you should be able to use the "finalize" directory
POST /acme/order/TOlocE8rfgo/finalize HTTP/1.1
example.com
application/jose+json
{
"protected": base64url({
"alg": "ES256",
"kid": "https://CA.com/acme/acct/evOfKhNU60wg",
"nonce": "MSF2j2nawWHPxxkE3ZJtKQ",
"url": "https://CA.com/acme/order/TOlocE8rfgo/finalize"
}),
"payload": base64url({
"csr": "MIIBPTCBxAIBADBFMQ...FS6aKdZeGsysoCo4H9P",
}),
"signature": "uOrUfIIk5RyQ...nw62Ay1cl6AB"
}
And this should return the order with a new "certificate" field
HTTP/1.1 200 OK
CGf81JWBsq8QyIgPCi9Q9X
<https://CA.com/acme/directory>;rel="index"
https://CA.com/acme/order/TOlocE8rfgo
{
"status": "valid",
"expires": "2016-01-20T14:09:07.99Z",
"notBefore": "2016-01-01T00:00:00Z",
"notAfter": "2016-01-08T00:00:00Z",
"identifiers": [
{ "type": "dns", "value": "www.YourDomain.com" },
{ "type": "dns", "value": "YourDomain.com" }
],
"authorizations": [
"https://CA.com/acme/authz/PAniVnsZcis",
"https://CA.com/acme/authz/r4HqLzrSrpI"
],
"finalize": "https://CA.com/acme/order/TOlocE8rfgo/finalize",
"certificate": "https://CA.com/acme/cert/mAt3xBGaobw"
}
Make a request to the "certificate" url
POST /acme/cert/mAt3xBGaobw HTTP/1.1
CA.com
application/jose+json
application/pem-certificate-chain
{
"protected": base64url({
"alg": "ES256",
"kid": "https://CA.com/acme/acct/evOfKhNU60wg",
"nonce": "uQpSjlRb4vQVCjVYAyyUWg",
"url": "https://CA.com/acme/cert/mAt3xBGaobw"
}),
"payload": "",
"signature": "nuSDISbWG8mMgE7H...QyVUL68yzf3Zawps"
}
Wich should return the issued cettificates.
HTTP/1.1 200 OK
application/pem-certificate-chain
<https://CA.com/acme/directory>;rel="index"
-----BEGIN CERTIFICATE-----
[End-entity certificate contents]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[Issuer certificate contents]
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
[Other certificate contents]
-----END CERTIFICATE-----
Now it's just to save them and use them in your program!