Security /info/alibaba/ssl

Let's Encrypt Part 4

Date Created: June 12, 2018
Last Update: June 21, 2018

Table of Contents

Introduction
Example ACME Request
ACME API HTTP Request Body
JWS Protected Header
JWS Web Key (JWK)
Payload
Signature

Article Series

NeoPrime - Let's Encrypt Part 1
NeoPrime - Let's Encrypt Part 2
NeoPrime - Let's Encrypt Part 3
NeoPrime - Let's Encrypt Part 4
NeoPrime - Let's Encrypt Part 5

Introduction

In this multipart article, 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. The same principles apply to any computing service that supports X.509 SSL certificates.

In this part we will explain how 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. Reference the following documents:

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 keypairs.

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

The above demonstrates how the ACME API system works. In the next part we will examine how to perform DNS validation and how to create and modify DNS server resource records to support ACME dns validation.





Let's Encrypt Part 5.




15220 Main Street, Bellevue, WA 98007
T: 425-528-8500 - F: 425-528-8550 - E: neoprime@neoprime.io

Copyright 2018 NeoPrime LLC