×
Community Blog Let's Encrypt ACME with Alibaba Cloud API Gateway and CDN – Part 4

Let's Encrypt ACME with Alibaba Cloud API Gateway and CDN – Part 4

In this multi-part article, we will learn how to use the Let's Encrypt ACME version 2 API using Python for SSL certificates.

By John Hanley, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud’s incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

In this multipart article, we will discuss about SSL certificates in detail to remove any doubts on this topic. We will learn how to use the Let's Encrypt ACME version 2 API using Python to develop software that can create, install, renew and revoke SSL certificates for Alibaba Cloud. Although we have used Alibaba Cloud products for the tutorial, the same principles apply to any computing service that supports X.509 SSL certificates.

In Part 3, we explained about ACME endpoints, and talked about getting the ACME directory, creating an ACME account, and retrieving your ACME account information.
In this part, we will explain in detail on how to construct ACME requests and sign the JWS payload.

Example ACME Request

Let's look at an example to create a new account. This pseudo-code example shows the HTTP POST, the HTTP headers and the HTTP body. The "based64_encode" is not actually part of the HTTP body but shows that the code should based64 encode the data before sending to the ACME server.

POST /acme/new-account HTTP/1.1
Host: acme-staging-v02.api.letsencrypt.org
Content-Type: application/jose+json

{
    "protected": base64_encode({
        "alg": "ES256",
        "jwk": {...},
        "nonce": "6S8IqOGY7eL2lsGoTZYifg",
        "url": "https://acme-staging-v02.api.letsencrypt.org/acme/new-acct"
    }),
    "payload": base64_encode({
        "termsOfServiceAgreed": true,
        "contact": [
            "mailto:cert-admin@example.com",
            "mailto:admin@example.com"
        ]
    }),
    "signature": "RZPOnYoPs1PhjszF...-nh6X1qtOFPB519I"
}

ACME API HTTP Request Body

An ACME request is encapsulated in a JSON Web Signature (JWS) object.

The JWS object consists of three parts. The JWS Protected Header, the API command parameters (payload) and the signature. We will cover each part below. Each part is separately base64 encoded and then combined into one JSON object.

{
    "protected": base64_encode(jws_protected_header),
    "payload": base64_encode(payload),
    "signature": based64_encode(signature)
}

JWS Protected Header

Within the JWS object is the JWS Protected Header. The JWS Protected Header contains the following fields:

Field Description
alg Algorithm. This is the MAC based algorithm used to sign the request. Supported algorithms are ES256 and RS256. Reference RFC 7518. In these examples we will be using RS256 (RSASSA-PKCS1-v1_5 using SH-256). Simplified description: RS256 means signing with an RSA private key and validating with the corresponding RSA public key.
jwk JSON Web Key. The JWK is used for all requests that are not signed using an existing account. For example: "New Account". The JWK is a JSON object that we will cover later in this article.
kid Key ID. The KID is used for all requests that are signed using an existing account. For example, Get Account Information.
nonce Nonce. A unique value used to prevent replay attacks. This value is returned by the NewNonce API and in the response header "Replay-Nonce" after each successful ACME API call. The Replay-Nonce value is used for the next ACME API call.
url URL. This header parameter encodes the URL to which the client is directing the request. Consult each ACME API for the required value.

The "jwk" and "kid" fields are mutually exclusive. Servers MUST reject requests that contain both.

The ACME API will specify using one or the other.

JWS Web Key (JWK)

The JWK parameters vary based upon the type of cryptographic signing. For the examples in this series we are using RSA key pairs.

Field Description
e Public Exponent. This is the public exponent from the RSA keypair.
kty Key Type. The method used to sign the JWS. The value is RSA when using RSA keypairs. Reference RFC 7638 for detailed information.
n Modulus. This is the modulus from the RSA keypair. For a 2048-bit key, the field "n" value is 256 octets in length when decoded.
{
    "e": base64_encode(public_exponent),
    "kty": "RSA",
    "n": base64_encode(modulus),
}

Payload

The payload contains the API call parameters. These will be different for each API. The contents of the payload json object are base64 encoded. The following examples shows the payload for the New Account API. There are two parameters: "termsOfServiceAgreed" and "contact". The payload is part of the JSON Web Signature (JWS) included in the HTTP body.

"payload": base64_encode({
    "termsOfServiceAgreed": true,
    "contact": [
        "mailto:cert-admin@example.com",
        "mailto:admin@example.com"
    ]
})

Signature

The signature is a SHA-256 message digest using the RSA private key. The ACME server validates the signature using the corresponding public key.

def sign(data, keyfile):
    """ Create the ACME API Signature """

    # Load the RSA Private Key from the file (RSA PKCS #1)
    pkey = load_private_key(keyfile)

    # Create the signature
    sig = crypto.sign(pkey, data, "sha256")

    return sig

Summary

The above demonstrates how the ACME API system works.

In the next and final part, we will examine how to perform DNS validation and how to create and modify DNS server resource records to support ACME DNS validation.

1 0 0
Share on

Alibaba Clouder

1,029 posts | 162 followers

You may also like

Comments

282604745917283389 December 28, 2018 at 1:33 pm

Where is the link to Part V