Alibaba CloudでACMEを暗号化：ACMEリクエストを構築し、JWSペイロードに署名

今回の多部構成の記事では、**Python**を使ったLet's Encrypt ACME version 2 APIを**SSL証明書**に利用する方法を学びます。

*本ブログは英語版からの翻訳です。オリジナルは[こちら](https://www.alibabacloud.com/blog/let%27s-encrypt-acme-with-alibaba-cloud-api-gateway-and-cdn-%E2%80%93-part-4_593786)からご確認いただけます。一部機械翻訳を使用しております。翻訳の間違いがありましたら、ご指摘いただけると幸いです。*

#ACMEリクエスト例
新しいアカウントを作成する例を見てみましょう。この擬似コード例は、HTTP POST、HTTPヘッダ、HTTPボディを示しています。based64_encode」は実際にはHTTPボディの一部ではありませんが、ACMEサーバに送信する前にコードがデータをbase64エンコードする必要があることを示しています。

```
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リクエストボディ
ACMEリクエストは、JSON Web Signature(JWS)オブジェクトにカプセル化されます。

JWSオブジェクトは3つの部分で構成されています。JWS Protected Header、APIコマンドパラメータ(ペイロード)、シグネチャです。以下、各部分について説明します。各部分は個別にbase64エンコードされ、1つのJSONオブジェクトにまとめられます。

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

#JWS保護されたヘッダー
JWS オブジェクトの中には、JWS Protected Header があります。JWS Protected Headerには以下のフィールドが含まれています。



|フィールド　　| 説明|
|:-----------|:---------------|
|alg　|アルゴリズム。リクエストの署名に使用されるMACベースのアルゴリズムです。サポートされているアルゴリズムはES256とRS256です。参照 RFC 7518 を参照してください。これらの例では、RS256 (SH-256 を使用した RSASSA-PKCS1-v1_5) を使用します。簡単に説明します。RS256とは、RSA秘密鍵で署名し、対応するRSA公開鍵で検証することを意味します。|
|jwk　| JSON Web Key。jwkは、既存のアカウントを使用して署名されていないすべてのリクエストに使用されます。例えば、以下のようになります。"新規アカウント"。jwkは、この記事で後述するJSONオブジェクトです。|
|kid |　キー ID。kidは、既存のアカウントを使用して署名されているすべてのリクエストに使用されます。例えば、「アカウント情報の取得」などです。|
|nonce| Nonce。リプレイ攻撃を防ぐために使用される一意の値。この値は、NewNonce APIによって返され、各成功したACME API呼び出しの後の応答ヘッダー「Replay-Nonce」で返されます。|Nonce 値は、次の ACME API 呼び出しで使用されます。|
|url | URL。このヘッダーパラメータは、クライアントがリクエストを指示しているURLをエンコードします。必要な値については、各ACME APIを参照してください。|

「jwk」と「kid」フィールドは相互に排他的です。サーバーは両方を含むリクエストを拒否しなければいけません。

ACME APIは、どちらか一方を使用し、指定します。

#JWSウェブキー(JWK)
JWK のパラメータは、暗号署名の種類によって異なる。このシリーズの例では、RSA 鍵ペアを使用しています。

|フィールド　|説明|
|:----------|--------|
|e |公開指数。これは、RSA 鍵ペアの公開指数。|
|kty |Key Type。JWS の署名に使用される方式です。RSA 鍵ペアを使用する場合は RSA になります。詳細はRFC 7638を参照のこと。
|n |Modulus（モジュラス）。RSA 鍵ペアからのモジュラスです。2048 ビットの鍵の場合、フィールド「n」の値はデコード時に 256 オクテットの長さになります。|

```
{
    "e": base64_encode(public_exponent),
    "kty": "RSA",
    "n": base64_encode(modulus),
}
```

#ペイロード
ペイロードにはAPIコールパラメータが含まれます。これらはAPIごとに異なります。ペイロードの json オブジェクトの内容は base64 エンコードされています。次の例は、New Account API のペイロードを示しています。パラメータは2つあります。"termsOfServiceAgreed "と "contact "です。ペイロードは、HTTPボディに含まれるJSON Web Signature(JWS)の一部です。

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

```

#署名
署名は、RSA 秘密鍵を使用した SHA-256 メッセージ・ダイジェストです。ACME サーバは、対応する公開鍵を使用して署名を検証します。



```
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
```

#概要
以上、ACME APIシステムがどのように動作するかを示しました。

次の最後の部分では、DNS検証の実行方法と、ACME DNS検証をサポートするためのDNSサーバーリソースレコードの作成と修正方法を見ていきます。


*アリババクラウドは日本に２つのデータセンターを有し、世界で60を超えるアベラビリティーゾーンを有するアジア太平洋地域No.1(2019ガートナー)のクラウドインフラ事業者です。
アリババクラウドの詳細は、こちらからご覧ください。
[アリババクラウドジャパン公式ページ](https://www.alibabacloud.com/ja)*