Example #1
0
    /**
     * {@inheritdoc}
     */
    public function generate(KeyPair $keyPair, array $domains)
    {
        if (!($privateKey = openssl_pkey_get_private($keyPair->getPrivate()))) {
            // TODO: Improve error message
            throw new AcmeException("Couldn't use private key.");
        }
        $san = implode(",", array_map(function ($dns) {
            return "DNS:{$dns}";
        }, $domains));
        // http://www.heise.de/netze/rfc/rfcs/rfc7633.shtml
        // http://www.heise.de/netze/rfc/rfcs/rfc6066.shtml
        $mustStaple = $this->mustStaple ? "tlsfeature = status_request" : "";
        $tempFile = tempnam(sys_get_temp_dir(), "acme-openssl-config-");
        $tempConf = <<<EOL
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req
{$mustStaple}

[ req_distinguished_name ]

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = digitalSignature, nonRepudiation
subjectAltName = {$san}
EOL;
        (yield \Amp\File\put($tempFile, $tempConf));
        $csr = openssl_csr_new(["CN" => reset($domains)], $privateKey, ["digest_alg" => "sha256", "config" => $tempFile]);
        (yield \Amp\File\unlink($tempFile));
        if (!$csr) {
            // TODO: Improve error message
            throw new AcmeException("CSR could not be generated.");
        }
        (yield new CoroutineResult(openssl_csr_export($csr, $csr)));
    }
Example #2
0
 private function doDelete($name)
 {
     Assert::string($name, "Name must be a string. Got: %s");
     foreach ((yield \Amp\File\scandir($this->root . "/" . $name)) as $file) {
         (yield \Amp\File\unlink($this->root . "/" . $name . "/" . $file));
     }
     (yield \Amp\File\rmdir($this->root . "/" . $name));
 }
Example #3
0
 private function doDelete($token)
 {
     Assert::string($token, "Token must be a string. Got: %s");
     $path = $this->docroot . "/.well-known/acme-challenge/{$token}";
     $realpath = realpath($path);
     if ($realpath) {
         (yield \Amp\File\unlink($realpath));
     }
 }
Example #4
0
    private function doRequestCertificate(KeyPair $keyPair, array $domains)
    {
        if (empty($domains)) {
            throw new AcmeException("Parameter \$domains must not be empty.");
        }
        if (!($privateKey = openssl_pkey_get_private($keyPair->getPrivate()))) {
            // TODO: Improve error message
            throw new AcmeException("Couldn't use private key.");
        }
        $tempFile = tempnam(sys_get_temp_dir(), "acme_openssl_config_");
        $tempConf = <<<EOL
[ req ]
distinguished_name = req_distinguished_name
req_extensions = v3_req

[ req_distinguished_name ]

[ v3_req ]
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @san

[ san ]
EOL;
        $i = 0;
        $san = implode("\n", array_map(function ($dns) use(&$i) {
            $i++;
            return "DNS.{$i} = {$dns}";
        }, $domains));
        (yield \Amp\File\put($tempFile, $tempConf . "\n" . $san . "\n"));
        $csr = openssl_csr_new(["CN" => reset($domains), "ST" => "Germany", "C" => "DE", "O" => "Unknown"], $privateKey, ["digest_alg" => "sha256", "req_extensions" => "v3_req", "config" => $tempFile]);
        (yield \Amp\File\unlink($tempFile));
        if (!$csr) {
            // TODO: Improve error message
            throw new AcmeException("CSR could not be generated.");
        }
        openssl_csr_export($csr, $csr);
        $begin = "REQUEST-----";
        $end = "----END";
        $csr = substr($csr, strpos($csr, $begin) + strlen($begin));
        $csr = substr($csr, 0, strpos($csr, $end));
        $enc = new Base64UrlSafeEncoder();
        /** @var Response $response */
        $response = (yield $this->acmeClient->post(AcmeResource::NEW_CERTIFICATE, ["csr" => $enc->encode(base64_decode($csr))]));
        if ($response->getStatus() === 201) {
            if (!$response->hasHeader("location")) {
                throw new AcmeException("Protocol Violation: No Location Header");
            }
            (yield new CoroutineResult(current($response->getHeader("location"))));
            return;
        }
        throw $this->generateException($response);
    }