mbretter / acme2-library
ACME2底层库
Requires
- php: >=7.1.0
- psr/http-message: ^1.0
Requires (Dev)
- phpunit/phpunit: ^7.1
README
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密钥