-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from stonemax/develop
1.0.0
- Loading branch information
Showing
28 changed files
with
2,981 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,6 @@ | ||
# acme2 | ||
Another PHP client for acme protocal (version 2) implementation, used for generating letsencrypt's free ssl certificate. | ||
|
||
## docs | ||
* [English](https://github.com/stonemax/acme2/blob/develop/docs/README.md) | ||
* [简体中文](https://github.com/stonemax/acme2/blob/develop/docs/README-ZH.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
1.0.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,158 @@ | ||
# ACME2 | ||
stonemax/acme2 是一个简单的 PHP 工具,用于生成符合 ACME(Version 2) 协议的CA证书,目前主要用于 [Let's Encrypt](https://letsencrypt.org/) 的证书签发,同时支持 RSA 和 ECDSA 类型证书的签发。本工具仅用于生成证书,并不会如官方工具一样帮助您配置 Web Server 或者 DNS 记录,因此,在域名的校验过程中,无论是在 Web Server 上设置校验文件,还是设置 DNS 记录,都需要您自己处理,您可以手动处理,也可以通过代码中的钩子进行自动化处理。 | ||
|
||
|
||
## 1. 当前版本 | ||
stonemax/acme2 当前的版本是 `1.0.0`。 | ||
|
||
|
||
## 2. 先决条件 | ||
由于使用了命名空间、三元运算符简写形式等 PHP 特性,因此使用本工具的最低 PHP 版本要求为 5.4.0+(含5.4.0)。但是当您要生成 ECDSA 类型的证书时,需要的 PHP 版本最低为 7.1.0+(含7.1.0)。此外,我们还需要开启 openssl 扩展。 | ||
虽然stonemax/acme2 使用了 composer 作为包管理器,但是仅将其作为文件的自动加载器使用,实际上并未使用任何外部依赖 | ||
|
||
|
||
## 3. 安装 | ||
将代码下载到某个文件夹下,进入此文件夹,在当前目录下执行以下命令即可完成安装: | ||
|
||
```bash | ||
cd example-directory | ||
git clone [email protected]:stonemax/acme2.git . | ||
|
||
composer install | ||
``` | ||
|
||
|
||
## 4. 使用 | ||
在这里,我们将介绍 stonemax/acme2 中对外暴露的方法,通过认识这些方法,您就大致知道如何使用了,我们也提供了一份案例代码,位于 [examples/](https://github.com/stonemax/acme2/tree/develop/examples) 目录下。 | ||
|
||
#### 4.1. 初始化客户端 | ||
|
||
```php | ||
$emailList = ['[email protected]']; // 邮箱列表,在适当时机,Let's Encrypt 会发送邮件到此邮箱,例如:证书即将过期 | ||
$storagePath = './data'; // 账户数据以及生成的证书存储的目录 | ||
$staging = TRUE; // 是否使用 staging 环境 | ||
|
||
|
||
$client = new Client($emailList, $storagePath, $staging); // 初始化客户端 | ||
``` | ||
|
||
初始化一个客户端时,工具会自动生成一个 Let's Encrypt 账户,账户数据存储在 `$storagePath/account` 目录下,当您再次初始化客户端时,如果账户数据已经存在,则不会再创建新的账户。 | ||
|
||
#### 4.2. 账户相关方法 | ||
|
||
```php | ||
$account = $client->getAccount(); // 获取账户实例 | ||
|
||
$account->updateAccountContact($emailList); // 更新账户的联系邮件 | ||
$account->updateAccountKey(); // 重新生成 private/public 密钥对,并使用新的密钥对替换原有的 | ||
$account->deactivateAccount(); // 销毁账户 | ||
``` | ||
|
||
#### 4.3. 订单相关方法 | ||
证书的生成,主要使用的就是订单的相关方法。 | ||
|
||
```php | ||
/* 证书包含的域名及其验证信息 */ | ||
$domainInfo = [ | ||
CommonConstant::CHALLENGE_TYPE_HTTP => [ | ||
'abc.example.com' | ||
], | ||
|
||
CommonConstant::CHALLENGE_TYPE_DNS => [ | ||
'*.www.example.com', | ||
'www.example.com', | ||
], | ||
]; | ||
|
||
$algorithm = CommonConstant::KEY_PAIR_TYPE_RSA; // 生成 RSA 类型的证书,使用 `CommonConstant::KEY_PAIR_TYPE_EC` 生成 ECDSA 证书 | ||
$renew = FALSE; // 是否重新生成证书,一般用于证书快过期时,用于证书续期(实际上是重新生成了证书) | ||
|
||
$order = $client->getOrder($domainInfo, $algorithm, $renew); // 获取订单实例 | ||
|
||
$order->getPendingChallengeList(); // 获取 ChallengeService 实例列表,该列表中存储了域名验证的相关信息 | ||
$order->getCertificateFile(); // 获取证书的相关信息,包含:证书位置、生成证书的密钥对文件位置、证书有效期 | ||
$order->revokeCertificate($reason); // 吊销证书,证书吊销后就不能再使用了,需要重新生成 | ||
``` | ||
|
||
#### 4.4. 证书验证相关方法 | ||
|
||
```php | ||
$challengeList = $order->getPendingChallengeList(); | ||
|
||
foreach ($challengeList as $challenge) | ||
{ | ||
$challenge->getType(); // 认证方式,http-01 或者 dns-01 | ||
$challenge->getCredential(); // 认证的具体信息,如果认证方式是 http-01,返回的数据中包含文件名和文件内容,如果是 dns-01,则包含 DNS 的记录值 | ||
$challenge->verify(); // 验证域名,这是一个无限循环,直到证书验证成功才返回 | ||
} | ||
``` | ||
|
||
|
||
## 5. 域名验证 | ||
在生成证书时,Let's Encrypt 需要校验域名的所有权和有效性,主要有两种认证方式:域名下的文件校验(http-01)和域名 DNS 的 TXT 记录值认证(dns-01)。下文中,我们一律以 www.example.com 进行举例说明。 | ||
|
||
#### 5.1. HTTP 认证 | ||
在这种认证方式下,需要在域名对应站点的相应位置放置一个特定文件,文件内包含特定的文件内容,Let's Encrypt 会访问该文件以校验域名。 | ||
在此种情况下,`$challenge` 的相关信息如下所示。 | ||
|
||
```php | ||
echo $challenge->getType(); | ||
|
||
/* output */ | ||
'http-01' | ||
|
||
|
||
print_r($challenge->getCredential()); | ||
|
||
/* output */ | ||
[ | ||
'identifier' => 'www.example.com', | ||
'fileName' => 'RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y', | ||
'fileContent' => 'RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y.CNWZAGtAHIUpstBEckq9W_-0ZKxO-IbxF9Y8J_svbqo', | ||
]; | ||
``` | ||
|
||
此时,Let's Encrypt 会访问以下地址来进行域名认证:`http://www.example.com/.well-known/acme-challenge/HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y`。 | ||
|
||
#### 5.2. DNS 认证 | ||
在这种方式下,需要在相应域名的 DNS 记录中增加 TXT 记录,这时 `$challenge` 的相关信息如下所示。 | ||
|
||
```php | ||
echo $challenge->getType(); | ||
|
||
/* output */ | ||
'dns-01' | ||
|
||
|
||
print_r($challenge->getCredential()); | ||
|
||
/* output */ | ||
[ | ||
'identifier' => 'www.example.com', | ||
'dnsContent' => 'xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk', | ||
]; | ||
``` | ||
|
||
此时,需要增加主机记录为 `_acme-challenge.www.example.com`,类型为 TXT 的 DNS 记录,记录值为:`xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk`。值得注意的是,记录的 TTL 值需要设置的尽量小,以便尽快生效。 | ||
|
||
#### 5.3. 通配符域名认证 | ||
ACME2支持通配符证书的生成,但仅能使用 DNS 认证。拿 `*.www.example.com` 举例来说,当进行 DNS 认证时,其实是针对域名 `www.example.com` 进行校验的。下面针对 DNS 认证的各种情况做一个说明。 | ||
|
||
| 域名 | DNS 记录名 | 类型 | TTL | DNS 记录值 | | ||
| ------------------ | -------------------------------- | ---- | --- | ------------------------------------------- | | ||
| example.com | \_acme-challenge.example.com | TXT | 60 | xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk | | ||
| \*.example.com | \_acme-challenge.example.com | TXT | 60 | G2dOkzSjW3ohib5doPRDrz5a5l8JB1qU8CxURtzF7aE | | ||
| www.example.com | \_acme-challenge.www.example.com | TXT | 60 | x1sc0pIwN5Sbqx0NO0QQeu8LxIfhbM2eTjwdWliYxF1 | | ||
| \*.www.example.com | \_acme-challenge.www.example.com | TXT | 60 | eZ9ViY12gKfdruYHOO7Lu74ICXeQRMDLp5GuHLvPsf7 | | ||
|
||
|
||
## 6. 完整例子 | ||
stonemax/acme2 随代码附上了一个完整的例子,位于 [examples/](https://github.com/stonemax/acme2/tree/develop/examples) 目录下,也可以点击 [examples/example.php](https://github.com/stonemax/acme2/blob/develop/examples/example.php) 直接查看。 | ||
|
||
|
||
## 7. 感谢 | ||
[yourivw/LEClient](https://github.com/yourivw/LEClient) 项目对本项目有很大帮助,在此表示感谢! | ||
|
||
|
||
## 8. 许可证 | ||
此项目使用的是 MIT 许可证,[查看许可证信息](https://github.com/stonemax/acme2/blob/develop/LICENSE)。 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
# ACME2 | ||
|
||
stonemax/acme2 is a simple PHP tool to manage TLS certificates with ACME-compliant CAs, it's mainly used with let's Encrypt, support for both ESA and ECDSA certifacates. It will not set challenge file or DNS record for you, you can do these jobs manually, or automaticlly with you own code and hooks in stonemax/acme2. | ||
|
||
|
||
## 1. Current Version | ||
The current version is `1.0.0`. | ||
|
||
|
||
## 2. Prerequisites | ||
This version works with PHP-5.4.0 or higher, if you need to generate ECDSA certificates, PHP version should be 7.1.0 or higher. PHP need openssl extenson enabled in addition. | ||
Although acme2 uses composer, but composer is just uesd as an autoloader, this porject has no any third party dependencies. | ||
|
||
|
||
## 3. Install | ||
Clone this project and run `compose install`. | ||
|
||
```bash | ||
cd example-directory | ||
git clone [email protected]:stonemax/acme2.git . | ||
|
||
composer install | ||
``` | ||
|
||
|
||
## 4. Usage | ||
The basic methods and its necessary arguments are shown here. An example is supplied in [examples/](https://github.com/stonemax/acme2/tree/develop/examples). | ||
|
||
#### 4.1. Client | ||
|
||
```php | ||
$emailList = ['[email protected]']; // Email list as contact info | ||
$storagePath = './data'; // Account data and certificates files will be stored here | ||
$staging = TRUE; // Using stage environment or not | ||
|
||
|
||
$client = new Client($emailList, $storagePath, $staging); // Initiating a client | ||
``` | ||
|
||
After `Client` had been initiated, a Let's Encrypt account will be created and the account data will be placed in `$storagePath`. | ||
When you reinitialize the client, the accout will not be created again. | ||
|
||
#### 4.2. Account | ||
|
||
```php | ||
$account = $client->getAccount(); // Get account service instance | ||
|
||
$account->updateAccountContact($emailList); // Update account contact info with an email list | ||
$account->updateAccountKey(); // Regenerate private/public key pair,the old will be replaced by the new | ||
$account->deactivateAccount(); // Deactive the account | ||
``` | ||
|
||
#### 4.3. Order | ||
These methods bellow are mainly used for generating certificates. | ||
|
||
```php | ||
/* Domains and challenges info */ | ||
$domainInfo = [ | ||
CommonConstant::CHALLENGE_TYPE_HTTP => [ | ||
'abc.example.com' | ||
], | ||
|
||
CommonConstant::CHALLENGE_TYPE_DNS => [ | ||
'*.www.example.com', | ||
'www.example.com', | ||
], | ||
]; | ||
|
||
$algorithm = CommonConstant::KEY_PAIR_TYPE_RSA; // Generate RSA certificates, `CommonConstant::KEY_PAIR_TYPE_EC` for ECDSA certificates | ||
$renew = FALSE; // Renew certificates | ||
|
||
$order = $client->getOrder($domainInfo, $algorithm, $renew); // Get an order service instance | ||
|
||
$order->getPendingChallengeList(); // Get all authorization challenges for domains | ||
$order->getCertificateFile(); // Get certificates, such as certificates path, private/public key pair path, valid time | ||
$order->revokeCertificate($reason); // Revoke certificates, the certificaes ara unavailable after revoked | ||
``` | ||
|
||
#### 4.4. Challenge | ||
|
||
```php | ||
$challengeList = $order->getPendingChallengeList(); | ||
|
||
foreach ($challengeList as $challenge) | ||
{ | ||
$challenge->getType(); // Challenge type, http-01 or dns-01 | ||
$challenge->getCredential(); // Challenge detail, http-01 with file name and file content, dns-01 with dns record value | ||
$challenge->verify(); // Do verifying operation, this method will loop infinitely until verification passed | ||
} | ||
``` | ||
|
||
|
||
## 5. Domain Verification | ||
When generating a certificate, Let's Encrypt need to verify the ownership and validity of the domain. There are two types of verification: http-01, dns-01. | ||
In the following, we take `www.example.com` as an example. | ||
|
||
#### 5.1. http-01 | ||
As this type, Let's Encrypt will access a specific file under web server to verify domain. | ||
As this time, the `$challenge` info is like bellow. | ||
|
||
```php | ||
echo $challenge->getType(); | ||
|
||
/* output */ | ||
'http-01' | ||
|
||
|
||
print_r($challenge->getCredential()); | ||
|
||
/* output */ | ||
[ | ||
'identifier' => 'www.example.com', | ||
'fileName' => 'RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y', | ||
'fileContent' => 'RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y.CNWZAGtAHIUpstBEckq9W_-0ZKxO-IbxF9Y8J_svbqo', | ||
]; | ||
``` | ||
|
||
With the aboved `$challenge` info, Let's Encrypt will access "http://www.example.com/.well-known/acme-challenge/HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y", and the file content will be expected as "RzMY-HDa1P0DwZalmRyB7wLBNI8fb11LkxdXzNrhA1Y.CNWZAGtAHIUpstBEckq9W_-0ZKxO-IbxF9Y8J_svbqo". | ||
|
||
#### 5.2. dns-01 | ||
As this type, you should add a DNS TXT record for domain, Let's Encrypt will check domain's specific TXT record value for verification. | ||
As this time, the `$challenge` info is like bellow. | ||
|
||
```php | ||
echo $challenge->getType(); | ||
|
||
/* output */ | ||
'dns-01' | ||
|
||
|
||
print_r($challenge->getCredential()); | ||
|
||
/* output */ | ||
[ | ||
'identifier' => 'www.example.com', | ||
'dnsContent' => 'xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk', | ||
]; | ||
``` | ||
|
||
With the aboved `$challenge` info, you shuoud add a TXT record for domain `www.example.com`, the record name should be "_acme-challenge.www.example.com", the record value should be "xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk". | ||
It's worth noting that you should set TTL as short as possible to let the record take effect as soon as possible. | ||
|
||
#### 5.3. Wildcard domain verification | ||
This tool supports generating certificates for wildcard domains. | ||
A wildcard domain, like `*.www.example.com`, will be verified as `www.example.com`, this means the DNS record name should be `_acme-challenge.www.example.com`. | ||
Here is a simple summary for dns-01 challenges about domain and DNS record. | ||
|
||
| Domain | DNS record name | Type | TTL | DNS record value(just examples) | | ||
| ------------------ | -------------------------------- | ---- | --- | ------------------------------------------- | | ||
| example.com | \_acme-challenge.example.com | TXT | 60 | xQwerUEsL8UVc6tIahwIVY4e8N5MAf1xhyY20AELurk | | ||
| \*.example.com | \_acme-challenge.example.com | TXT | 60 | G2dOkzSjW3ohib5doPRDrz5a5l8JB1qU8CxURtzF7aE | | ||
| www.example.com | \_acme-challenge.www.example.com | TXT | 60 | x1sc0pIwN5Sbqx0NO0QQeu8LxIfhbM2eTjwdWliYxF1 | | ||
| \*.www.example.com | \_acme-challenge.www.example.com | TXT | 60 | eZ9ViY12gKfdruYHOO7Lu74ICXeQRMDLp5GuHLvPsf7 | | ||
|
||
|
||
## 6. Full example | ||
Project supplies a [full example](https://github.com/stonemax/acme2/blob/develop/examples/example.php) under directory [examples/](https://github.com/stonemax/acme2/tree/develop/examples). | ||
|
||
|
||
## 7. Thanks | ||
This Project had got a lot of inspirations from [yourivw/LEClient](https://github.com/yourivw/LEClient). Thanks! | ||
|
||
|
||
## 8. License | ||
This project is licensed under the MIT License, see the [LICENSE](https://github.com/stonemax/acme2/blob/develop/LICENSE) file for detail. |
Oops, something went wrong.