Skip to content

Commit

Permalink
Merge branch 'master' of https://github.com/lordelph/yaac into lordel…
Browse files Browse the repository at this point in the history
…ph-master
  • Loading branch information
bakkerpeter committed Mar 18, 2020
2 parents 03914ce + eec278c commit 0090165
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 0 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,53 @@ foreach ($authorizations as $authorization) {
The method above will perform 15 attempts to ask LetsEncrypt to validate the challenge (with 1 second intervals) and
retrieve an updated status (it might take Lets Encrypt a few seconds to validate the challenge).

### Alternative ownership validation via DNS

You can also use DNS validation - to do this, you will need access to an API for your DNS
provider to create TXT records for the target domains.

```php

//store a map of domain=>TXT record we can use to wait with
$dnsRecords[];

foreach ($authorizations as $authorization) {
$challenge = $authorization->getDnsChallenge();

$txtRecord = $authorization->getTxtRecord($challenge);

$domain=$authorization->getDomain();
$validationDomain='_acme-challenge.'.$domain;

//remember the record we're about to set
$dnsRecords[$validationDomain] = $txtRecord;

//set TXT record for $validationDomain to $txtRecord value
//--
//-- you need to add code for your DNS provider here
//--
}
```

A helper is included which will allow you to wait until you can see the
DNS changes before asking Let's Encrypt to validate it, e.g.

```php
//wait up to 60 seconds for all our DNS updates to propagate
if (!Helper::waitForDNS($dnsRecords, 60)) {
throw new \Exception('Unable to verify TXT record update');
}
```

Once this passes we can ask Let's Encrypt to do the same...

```php
foreach ($authorizations as $authorization) {
$ok = $client->validate($authorization->getDnsChallenge(), 15);
}
```


### Get the certificate

Now to know if validation was successful, test if the order is ready as follows:
Expand Down
5 changes: 5 additions & 0 deletions src/Client.php
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ class Client
*/
const VALIDATION_HTTP = 'http-01';

/**
* DNS validation
*/
const VALIDATION_DNS = 'dns-01';

/**
* @var string
*/
Expand Down
26 changes: 26 additions & 0 deletions src/Data/Authorization.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Afosto\Acme\Data;

use Afosto\Acme\Client;
use Afosto\Acme\Helper;

class Authorization
{
Expand Down Expand Up @@ -78,6 +79,20 @@ public function getHttpChallenge()
return false;
}

/**
* @return Challenge|bool
*/
public function getDnsChallenge()
{
foreach ($this->getChallenges() as $challenge) {
if ($challenge->getType() == Client::VALIDATION_DNS) {
return $challenge;
}
}

return false;
}

/**
* @param Challenge $challenge
* @return File|bool
Expand All @@ -90,4 +105,15 @@ public function getFile(Challenge $challenge)
}
return false;
}

/**
* @param Challenge $challenge
* @return string containing TXT record for DNS challenge
*/
public function getTxtRecord(Challenge $challenge)
{
$raw=$challenge->getToken() . '.' . $this->digest;
$hash=hash('sha256', $raw, true);
return Helper::toSafeString($hash);
}
}
33 changes: 33 additions & 0 deletions src/Helper.php
Original file line number Diff line number Diff line change
Expand Up @@ -135,4 +135,37 @@ public static function getKeyDetails($key): array

return $accountDetails;
}

/**
* Wait until a set of DNS records return specific TXT record values
*
* @param array mapping domain to desired TXT record value
* @param $txtRecord
* @param int $maxSeconds to wait
* @return bool true if record found, false otherwise
*/
public static function waitForDNS(array $records, $maxSeconds=60)
{
$waitUntil = time() + $maxSeconds;

do {
//validate all remaining records..
foreach($records as $domain=>$txtRecord) {
$record=dns_get_record($domain, DNS_TXT);
if (isset($record[0]['txt']) && ($record[0]['txt']===$txtRecord)) {
unset($records[$domain]);
}
}

//did we find them all?
if (empty($records)) {
return true;
}

//otherwise still domains to check...have a short sleep
sleep(1);
} while(time() < $waitUntil);

return false;
}
}

0 comments on commit 0090165

Please sign in to comment.