Analogic\ACME\Lescript::signDomains PHP Метод

signDomains() публичный метод

public signDomains ( array $domains, $reuseCsr = false )
$domains array
    public function signDomains(array $domains, $reuseCsr = false)
    {
        $this->log('Starting certificate generation process for domains');
        $privateAccountKey = $this->readPrivateKey($this->accountKeyPath);
        $accountKeyDetails = openssl_pkey_get_details($privateAccountKey);
        // start domains authentication
        // ----------------------------
        foreach ($domains as $domain) {
            // 1. getting available authentication options
            // -------------------------------------------
            $this->log("Requesting challenge for {$domain}");
            $response = $this->signedRequest("/acme/new-authz", array("resource" => "new-authz", "identifier" => array("type" => "dns", "value" => $domain)));
            if (empty($response['challenges'])) {
                throw new \RuntimeException("HTTP Challenge for {$domain} is not available. Whole response: " . json_encode($response));
            }
            $self = $this;
            $challenge = array_reduce($response['challenges'], function ($v, $w) use(&$self) {
                return $v ? $v : ($w['type'] == $self->challenge ? $w : false);
            });
            if (!$challenge) {
                throw new \RuntimeException("HTTP Challenge for {$domain} is not available. Whole response: " . json_encode($response));
            }
            $this->log("Got challenge token for {$domain}");
            $location = $this->client->getLastLocation();
            // 2. saving authentication token for web verification
            // ---------------------------------------------------
            $directory = $this->webRootDir . '/.well-known/acme-challenge';
            $tokenPath = $directory . '/' . $challenge['token'];
            if (!file_exists($directory) && !@mkdir($directory, 0755, true)) {
                throw new \RuntimeException("Couldn't create directory to expose challenge: {$tokenPath}");
            }
            $header = array("e" => Base64UrlSafeEncoder::encode($accountKeyDetails["rsa"]["e"]), "kty" => "RSA", "n" => Base64UrlSafeEncoder::encode($accountKeyDetails["rsa"]["n"]));
            $payload = $challenge['token'] . '.' . Base64UrlSafeEncoder::encode(hash('sha256', json_encode($header), true));
            file_put_contents($tokenPath, $payload);
            chmod($tokenPath, 0644);
            // 3. verification process itself
            // -------------------------------
            $uri = "http://{$domain}/.well-known/acme-challenge/{$challenge['token']}";
            $this->log("Token for {$domain} saved at {$tokenPath} and should be available at {$uri}");
            // simple self check
            if ($payload !== trim(@file_get_contents($uri))) {
                throw new \RuntimeException("Please check {$uri} - token not available");
            }
            $this->log("Sending request to challenge");
            // send request to challenge
            $result = $this->signedRequest($challenge['uri'], array("resource" => "challenge", "type" => $this->challenge, "keyAuthorization" => $payload, "token" => $challenge['token']));
            // waiting loop
            do {
                if (empty($result['status']) || $result['status'] == "invalid") {
                    throw new \RuntimeException("Verification ended with error: " . json_encode($result));
                }
                $ended = !($result['status'] === "pending");
                if (!$ended) {
                    $this->log("Verification pending, sleeping 1s");
                    sleep(1);
                }
                $result = $this->client->get($location);
            } while (!$ended);
            $this->log("Verification ended with status: {$result['status']}");
            @unlink($tokenPath);
        }
        // requesting certificate
        // ----------------------
        $domainPath = $this->getDomainPath(reset($domains));
        // generate private key for domain if not exist
        if (!is_dir($domainPath) || !is_file($domainPath . '/private.pem')) {
            $this->generateKey($domainPath);
        }
        // load domain key
        $privateDomainKey = $this->readPrivateKey($domainPath . '/private.pem');
        $this->client->getLastLinks();
        $csr = $reuseCsr && is_file($domainPath . "/last.csr") ? $this->getCsrContent($domainPath . "/last.csr") : $this->generateCSR($privateDomainKey, $domains);
        // request certificates creation
        $result = $this->signedRequest("/acme/new-cert", array('resource' => 'new-cert', 'csr' => $csr));
        if ($this->client->getLastCode() !== 201) {
            throw new \RuntimeException("Invalid response code: " . $this->client->getLastCode() . ", " . json_encode($result));
        }
        $location = $this->client->getLastLocation();
        // waiting loop
        $certificates = array();
        while (1) {
            $this->client->getLastLinks();
            $result = $this->client->get($location);
            if ($this->client->getLastCode() == 202) {
                $this->log("Certificate generation pending, sleeping 1s");
                sleep(1);
            } else {
                if ($this->client->getLastCode() == 200) {
                    $this->log("Got certificate! YAY!");
                    $certificates[] = $this->parsePemFromBody($result);
                    foreach ($this->client->getLastLinks() as $link) {
                        $this->log("Requesting chained cert at {$link}");
                        $result = $this->client->get($link);
                        $certificates[] = $this->parsePemFromBody($result);
                    }
                    break;
                } else {
                    throw new \RuntimeException("Can't get certificate: HTTP code " . $this->client->getLastCode());
                }
            }
        }
        if (empty($certificates)) {
            throw new \RuntimeException('No certificates generated');
        }
        $this->log("Saving fullchain.pem");
        file_put_contents($domainPath . '/fullchain.pem', implode("\n", $certificates));
        $this->log("Saving cert.pem");
        file_put_contents($domainPath . '/cert.pem', array_shift($certificates));
        $this->log("Saving chain.pem");
        file_put_contents($domainPath . "/chain.pem", implode("\n", $certificates));
        $this->log("Done !!§§!");
    }