mbretter/acme2-library

0.7.1 2018-06-14 14:50 UTC

This package is auto-updated.

Last update: 2024-09-22 23:45:17 UTC


README

Coverage Status Build Status Latest Stable Version Total Downloads License

ACME2底层PHP库

此库是为了集成到应用程序中而构建的,而不是作为独立的ACME客户端。

ACME2规范:https://ietf-wg-acme.github.io/acme/draft-ietf-acme-acme.html

优势

  • 不依赖于其他包,如HTTP客户端
  • 它自带内置的HTTP客户端(基于PHP流),尽管也可以使用任何其他PSR-7兼容的HTTP客户端
  • PSR-7实现主要基于slim,并进行了一些修改
  • 它使用标准类和数组,不使用花哨的数据对象或复杂的数据模型
  • 它不关心数据存储,存储凭证/订单/状态的责任在你身上

命名空间

use Karl\Acme2;
use Karl\Acme2\Resources;

acme

Acme类是所有请求的管理器,它携带目录、私钥,获取nonce,并且是资源对象和HTTP客户端之间的接口。

$acme = new Acme2\Acme(); // without any args letsencrypt staging urls are used

$acme = new Acme2\Acme(true); // for letsencrypt production use

$acme = new Acme2\Acme('https://someca.example.com/acme'); // for any other acme compatible CA

$acme = new Acme2\Acme(true, $myHttpClient); // use your own http client

资源

你可以自己创建对象,如果你有自己的DI/容器系统,这很有用

$acme = new Acme2\Acme();

$key = new Acme2\Key\RSA($pemKey);
$acme->setKey($key);

$account = new Resources\Account($acme)
$accountData = $account->lookup();

另一种方法是使用acme对象检索资源对象,这更加流畅

$acme = new Acme2\Acme();

$key = new Acme2\Key\RSA($pemKey);
$acme->setKey($key);

$accountData = $acme->account()->lookup();
...

账户管理

在你可以发送任何其他请求之前,你必须订阅一个账户,这是通过生成你的私钥并提交创建调用来完成的。

$acme = new Acme2\Acme();

$key = new Acme2\Key\RSA(); // we use an RSA key
$key->generate();
$pem = $key->getPem(); // get the PEM, store your key somewhere

$acme->setKey($key); // acme needs a key to operate

$accountData = $acme->account()->create([
    'termsOfServiceAgreed' => true, 
    'contact' => ['mailto:example@example.com']
]);
$kid = $accountData->url; // acme uses the account url as keyId

你必须将私钥PEM和kid存储在系统的某个地方。

账户查找

如果你只有PEM,可以使用查找方法检索密钥ID

$acme = new Acme2\Acme();

$key = new Acme2\Key\RSA($pemKey);

$info = $acme->account()->lookup();
if ($info !== null)
{
    $key->setKid($info->url); // account location is used as kid
}

账户停用

$acme = new Acme2\Acme();
$key = new Acme2\Key\RSA($pemKey);
$acme->setKey($key);

$account = new Resources\Account($acme);
$account->deactivate($kid);

订单

创建新订单

$acme = new Acme2\Acme();
$key = new Acme2\Key\RSA($pemKey);
$key->setKid($kid);
$acme->setKey($key);

$newOrder = $acme->order()->addIdentifier(null, 'acme01.example.com'); // create a new order object 
$acme->order()->addIdentifier($newOrder, 'acme02.example.com'); // add another identifier

$orderData = $acme->order()->create($newOrder);

$orderUrl = $orderData->url; // store the orderUrl somewhere

为通配符域名创建订单

...
$newOrder = $acme->order()->addIdentifier(null, '*.example.com');

$orderData = $acme->order()->create($newOrder);

$orderUrl = $orderData->url; // store the orderUrl somewhere

注意:当使用通配符域名时,Let's Encrypt仅支持DNS验证。

获取现有订单

$order = new Acme2\Resources\Order($acme);

$orderData = $order->get($orderUrl);

print_r($orderData);

示例输出

stdClass Object
(
    [status] => valid
    [expires] => 2018-05-23T14:02:32Z
    [identifiers] => Array
        (
            [0] => stdClass Object
                (
                    [type] => dns
                    [value] => acme01.example.com
                )

        )

    [authorizations] => Array
        (
            [0] => https://acme-staging-v02.api.letsencrypt.org/acme/authz/AAAAA8
        )

    [finalize] => https://acme-staging-v02.api.letsencrypt.org/acme/finalize/999999/111111
    [certificate] => https://acme-staging-v02.api.letsencrypt.org/acme/cert/a83732947234cdef
    [url] => https://acme-staging-v02.api.letsencrypt.org/acme/order/999999/111111
)

授权

基本上有两种方法来验证你的订单,第一种是将密钥授权放在一个已知路径中,第二种是为DNS TXT记录提供认证密钥。

一旦你完成了这些步骤之一,你必须告诉CA验证订单,验证是通过查询DNS记录或从已知路径获取密钥授权来完成的。

对于订单中添加的每个标识符,都必须进行认证,每个认证通常提供DNS和HTTP方法,它们被称为挑战,对于通配符域名,仅支持DNS挑战。

$orderData = $acme->order()->get($orderUrl);

foreach ($orderData->authorizations as $a)
{
    $authData = $acme->authorization()->get($a);

    printf("authorization for: %s\n", $authData->identifier->value);

    $challengeData = $acme->authorization()->getChallenge($authData, 'dns-01');
    if ($challengeData === null)
        continue;

    // you have to add the $authKey to the DNS TXT record
    $authKey = $acme->challenge()->buildKeyAuthorization($challengeData);
    printf("DNS auth key is: %s\n", $authKey);

    // tell the CA to validate the challenge
    $acme->challenge()->validate($challengeData->url);

    $challengeData = $acme->authorization()->getChallenge($authData, 'http-01');
    if ($challengeData === null)
        continue;

    // you have to put the $authKey to the well known path
    $authKey = $acme->challenge()->buildKeyAuthorization($challengeData);
    printf("HTTP auth key is: %s\n", $authKey);

    // tell the CA to validate the challenge
    $acme->challenge()->validate($challengeData->url);
}

实际上,只需要一个挑战类型成功即可成功验证标识符。

DNS挑战

你必须放置认证密钥的DNS TXT记录,称为_acme-challenge,例如。

_acme-challenge.example.org 300 IN TXT "w2toDKxcQx2N8zcu4HnDboT1FceHs7lupLMTXsPbXCQ"。

你可以在那里放置多个具有相同名称的TXT记录,如果你使用通配符域名和域名中的替代主题名称,则需要这样做。

HTTP挑战

当使用HTTP挑战时,你必须将认证密钥放在路径下

/.well-known/acme-challenge/<token>

/.well-known/acme-challenge/LoqXcYV8q5ONbJQxbmR7SCTNo3tiAXDfowyjxAjEuX0

可以在挑战数据中找到token。

响应的内容类型必须是application/octet-stream。

重要:即使你有有效的证书,well-known路径也必须通过HTTP而不是HTTPS提供,否则在续订证书时会出现问题。

完成

待办事项

下载证书

待办事项

续订

待办事项

待办事项列表

  • EC密钥