#acme-client #domain-name #acme #certificate #letsencrypt #tls-certificate #key

acmev02

ACME客户端库,用于颁发、续订和吊销TLS证书

1 个不稳定版本

0.1.0 2021年7月26日

#1811 in 加密学

MIT许可证

71KB
918

acme-client

Build Status License Crates.io docs.rs.io

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

分支

这个分支的分支发布为 acmev02。由于升级了reqwest,所以去掉了openssl 0.9的依赖,这解决了我的rust-musl-builder构建问题。尚未更新README。

内容

安装

默认情况下,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。您可以使用多个-v标志以获得详细输出。

您可以在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服务器发送证书签名请求之前,您需要识别您想要为其签署证书的域名的所有权。为此,您需要为域名创建一个授权对象并至少完成一个挑战(http或dns用于Let's Encrypt)。

要为域名创建授权对象

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-client具有save_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")?;

参考资料

依赖项

~12–26MB
~421K SLoC