#域名 #TLS 证书 #ACME #Let's Encrypt #加密 #密钥 #客户端

bin+lib acme-client

易于使用的 ACME 客户端库,用于颁发、续订和撤销 TLS 证书

19 个版本

使用旧的 Rust 2015

0.5.3 2018 年 8 月 16 日
0.5.2 2018 年 3 月 4 日
0.5.1 2018 年 2 月 28 日
0.4.5 2017 年 11 月 19 日
0.1.5 2016 年 11 月 8 日

#667 in 密码学

38 每月下载量
用于 sozu-acme

MIT 许可证

79KB
1K SLoC

acme-client

Build Status License Crates.io docs.rs.io

易于使用的与 Let's Encrypt 兼容的 ACME 客户端,用于颁发、续订和撤销 TLS 证书。

内容

安装

默认情况下,acme-client 包含一个方便的命令行界面。您可以使用以下命令安装 acme-client:cargo install acme-client 或者您可以在 发布 页面下载预构建的 Linux 版 acme-client 二进制文件。

使用方法

acme-client 使用 OpenSSL 库生成所有必需的密钥和证书签名请求。您不需要运行任何 openssl 命令。如果您想使用已经生成的密钥和 CSR,您不需要在运行 acme-client 时获得 root 权限。

acme-client 使用简单的 HTTP 验证来通过 Let's Encrypt 的 DNS 验证挑战。您需要一个工作着的 HTTP 服务器来托管挑战文件。

签署证书

acme-client sign -D example.org -P /var/www -k domain.key -o domain.crt

此命令将生成用户密钥、域名密钥和 X509 证书签名请求。它将注册新的用户账户,并通过将所需的挑战令牌放入 /var/www/.well-known/acme-challenge/ 来识别域名所有权。如果一切顺利,它将保存域名私钥到 domain.key 并将已签署的证书保存到 domain.crt

您还可以使用 --email 选项在注册时提供联系地址。

使用自己的密钥和 CSR

您可以使用自己的 RSA 密钥进行用户注册和域名。例如

acme-client sign \
  --user-key user.key \
  --domain-key domain.key \
  --domain-csr domain.csr \
  -P /var/www \
  -o domain.crt

这不会生成任何密钥,它将使用提供的密钥来签署证书。它还将从提供的 CSR 文件中获取域名。

使用 DNS 验证

您可以使用 --dns 标志触发 DNS 验证而不是 HTTP。此选项要求用户为域名生成 TXT 记录。以下是一个 DNS 验证示例

$ acme-client sign --dns -D onur.im -E [email protected] \
    -k /tmp/onur.im.key -o /tmp/onur.im.crt
Please create a TXT record for _acme-challenge.onur.im: fDdTmWl4RMuGqj9acJiTC13hF6dVOZUNm3FujCIz3jc
Press enter to continue

撤销已签署的证书

acme-client 还可以撤销已签名的证书。您需要使用您的用户密钥和已签名的证书来撤销。

acme-client revoke --user-key user.key --signed-crt signed.crt

选项

您可以通过运行 acme-client sign --helpacme-client revoke --help 来获取所有可用选项的列表。

$ acme-client sign --help
acme-client-sign
Signs a certificate

USAGE:
    acme-client sign [FLAGS] [OPTIONS]

FLAGS:
    -d, --dns        Use DNS challenge instead of HTTP. This option requires
                     user to generate a TXT record for domain.
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -A, --directory <DIRECTORY>
            Set ACME directory URL [default: https://acme-v01.api.letsencrypt.org/directory]
    -D, --domain <DOMAIN>...
            Domain name to obtain certificate. You can use more than one domain name.
    -P, --public-dir <PUBLIC_DIR>
            Directory to save ACME simple HTTP challenge. This option is
            required unless --dns option is being used.
    -U, --user-key <USER_KEY_PATH>
            Path to load user private key to use it in account registration.
            This is optional and acme-client will generate one if it's not supplied.
    -C, --csr <DOMAIN_CSR>
            Path to load domain certificate signing request. acme-client can also use CSR to get domain names.
            This is optional and acme-client will generate one if it's not supplied.
    -K, --domain-key <DOMAIN_KEY_PATH>
            Path to load private domain key.
            This is optional and acme-client will generate one if it's not supplied.
    -E, --email <EMAIL>
            Contact email address (optional).
    -c, --save-chained-crt <SAVE_CHAINED_CERTIFICATE>
            Chain signed certificate with Let's Encrypt Authority X3
            (IdenTrust cross-signed) intermediate certificate and save to given path.
    -r, --save-csr <SAVE_DOMAIN_CSR>
            Path to save domain certificate signing request generated by acme-client.
    -k, --save-domain-key <SAVE_DOMAIN_KEY>
            Path to save domain private key generated by acme-client.
    -i, --save-intermediate-crt <SAVE_INTERMEDIATE_CERTIFICATE>
            Path to save intermediate certificate.
    -o, --save-crt <SAVE_SIGNED_CERTIFICATE>
            Path to save signed certificate. Default is STDOUT.
    -u, --save-user-key <SAVE_USER_KEY>
            Path to save private user key.
$ acme-client revoke --help
acme-client-revoke
Revokes a signed certificate

USAGE:
    acme-client revoke --user-key <USER_KEY> --signed-crt <SIGNED_CRT>

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

OPTIONS:
    -C, --signed-crt <SIGNED_CRT>    Path to signed domain certificate to revoke.
    -K, --user-key <USER_KEY>        User or domain private key path.

还有 genkeygencsr 子命令来生成 RSA 私钥和 CSR。您可以使用多个 - 标志以获取详细输出。

您可以在 docs.rs 中阅读整个 API 文档。您可以通过将以下行添加到您的 Cargo.toml 中来使用 acme-client 库。

[dependencies]
acme-client = "0.5"

默认情况下,acme-client 将构建 CLI。您可以使用以下命令禁用此操作:

[dependencies.acme-client]
version = "0.5"
default-features = false

API 概述

要为域名成功签发 SSL 证书,您需要识别域名的所有权。您还可以为多个域名识别和签署证书,并明确使用您自己的私钥和证书签名请求 (CSR),否则此库将生成它们。acme-client 的基本用法如下:

use acme_client::Directory;

let directory = Directory::lets_encrypt()?;
let account = directory.account_registration().register()?;

// Create a identifier authorization for example.com
let authorization = account.authorization("example.com")?;

// Validate ownership of example.com with http challenge
let http_challenge = authorization.get_http_challenge().ok_or("HTTP challenge not found")?;
http_challenge.save_key_authorization("/var/www")?;
http_challenge.validate()?;

let cert = account.certificate_signer(&["example.com"]).sign_certificate()?;
cert.save_signed_certificate("certificate.pem")?;
cert.save_private_key("certificate.key")?;

acme-client 支持使用 SAN 为多个域名签署证书。您需要验证每个域名的所有权。

use acme_client::Directory;

let directory = Directory::lets_encrypt()?;
let account = directory.account_registration().register()?;

let domains = ["example.com", "example.org"];

for domain in domains.iter() {
    let authorization = account.authorization(domain)?;
    // ...
}

let cert = account.certificate_signer(&domains).sign_certificate()?;
cert.save_signed_certificate("certificate.pem")?;
cert.save_private_key("certificate.key")?;

账户注册

use acme_client::Directory;

let directory = Directory::lets_encrypt()?;
let account = directory.account_registration()
                       .email("[email protected]")
                       .register()?;

联系电子邮件地址是可选的。您也可以在注册时使用您自己的私钥。有关更多信息,请参阅 AccountRegistration 帮助器。

如果您之前已使用自己的密钥注册,您仍然需要使用 register 方法,在这种情况下,它将识别您的用户账户而不是创建一个新账户。

识别域名所有权

在向 ACME 服务器发送证书签名请求之前,您需要识别您想要为其签署证书的域名的所有权。为此,您需要为域名创建一个授权对象并至少完成一个挑战(对于 Let's Encrypt,是 http 或 dns)。

要为域名创建授权对象

let authorization = account.authorization("example.com")?;

Authorization 对象将包含由 ACME 服务器创建的挑战。您可以创建任意数量的 Authorization 对象来验证域名的所有权。例如,如果您想为 example.comexample.org 签署证书

let domains = ["example.com", "example.org"];
for domain in domains.iter() {
    let authorization = account.authorization(domain)?;
    // ...
}

标识符验证挑战

当您向 ACME 服务器发送授权请求时,它将生成标识验证挑战,以提供账户持有者也是控制该标识的实体的保证。

HTTP 挑战

使用 HTTP 验证时,ACME 事务中的客户端通过证明它可以配置一个响应该域名的 HTTP 服务器上的资源来证明其对域名的主控权。

acme-clientsave_key_authorization 方法来将验证文件保存到公共目录中。此目录必须对外界可访问。

let authorization = account.authorization("example.com")?;
let http_challenge = authorization.get_http_challenge().ok_or("HTTP challenge not found")?;

// This method will save key authorization into
// /var/www/.well-known/acme-challenge/ directory.
http_challenge.save_key_authorization("/var/www")?;

// Validate ownership of example.com with http challenge
http_challenge.validate()?;

在验证过程中,ACME 服务器将检查 http://example.com/.well-known/acme-challenge/{token} 以识别域名的所有权。您需要确保标记是公开可访问的。

DNS 挑战

DNS 挑战要求客户端在特定的验证域名下配置包含指定值的 TXT 记录。

acme-client 可以使用 signature 方法生成此值。

用户通过在待验证的域名前添加标签 "_acme-challenge" 来构建验证域名,然后在那个名称下创建一个带有摘要值的TXT记录。例如,如果待验证的域名是 "example.com",则客户端会创建以下DNS记录

_acme-challenge.example.com: dns_challenge.signature()

使用DNS挑战的示例验证

let authorization = account.authorization("example.com")?;
let dns_challenge = authorization.get_dns_challenge().ok_or("DNS challenge not found")?;
let signature = dns_challenge.signature()?;

// User creates a TXT record for _acme-challenge.example.com with the value of signature.

// Validate ownership of example.com with DNS challenge
dns_challenge.validate()?;

签署证书

在验证所有域名后,您可以发送签名证书请求。acme-client为此提供了CertificateSigner辅助器。您可以使用自己的密钥和CSR,或者让CertificateSigner为您生成它们。

let domains = ["example.com", "example.org"];

// ... validate ownership of domain names

let certificate_signer = account.certificate_signer(&domains);
let cert = certificate_signer.sign_certificate()?;
cert.save_signed_certificate("certificate.pem")?;
cert.save_private_key("certificate.key")?;

撤销已签署的证书

您可以使用revoke_certificaterevoke_certificate_from_file方法撤销已签名的证书。您需要使用之前注册的相同私钥来成功撤销已签名的证书。您也可以使用生成CSR时使用的私钥。

let account = directory.account_registration()
                       .pkey_from_file("user.key")?
                       .register()?;
account.revoke_certificate_from_file("certificate.pem")?;

参考

依赖项

~10-22MB
~341K SLoC