Giter Club home page Giter Club logo

acmecert's Introduction

ACMECert

PHP client library for Let's Encrypt and other ACME v2 - RFC 8555 compatible Certificate Authorities.
Version: 3.4.0

Description

ACMECert is designed to help you to setup an automated SSL/TLS-certificate/renewal process with a few lines of PHP.

It is self contained and contains a set of functions allowing you to:

see Function Reference for a full list

It abstracts away the complexity of the ACME protocol to get a certificate (create order, fetch authorizations, compute challenge tokens, polling for status, generate CSR, finalize order, request certificate) into a single function getCertificateChain (or getCertificateChains to also get all alternate chains), where you specify a set of domains you want to get a certificate for and which challenge type to use (all challenge types are supported). This function takes as third argument a user-defined callback function which gets invoked every time a challenge needs to be fulfilled. It is up to you to set/remove the challenge tokens:

$handler=function($opts){
  // Write code to setup the challenge token here.

  // Return a function that gets called when the challenge token should be removed again:
  return function($opts){
    // Write code to remove previously setup challenge token.
  };
};

$ac->getCertificateChain(..., ..., $handler);

see description of getCertificateChain for details about the callback function.

also see the Get Certificate examples below.

Instead of returning FALSE on error, every function in ACMECert throws an Exception if it fails or an ACME_Exception if the ACME-Server reponded with an error message.

Requirements

Require ACMECert

manual download: https://github.com/skoerfgen/ACMECert/archive/master.zip

usage:

require 'ACMECert.php';

use skoerfgen\ACMECert\ACMECert;

or download it using git:

git clone https://github.com/skoerfgen/ACMECert

usage:

require 'ACMECert/ACMECert.php';

use skoerfgen\ACMECert\ACMECert;

or download it using composer:

composer require skoerfgen/acmecert

usage:

require 'vendor/autoload.php';

use skoerfgen\ACMECert\ACMECert;

Usage / Examples

Choose Certificate Authority (CA)

Live CA

$ac=new ACMECert('https://acme-v02.api.letsencrypt.org/directory');

Staging CA

$ac=new ACMECert('https://acme-staging-v02.api.letsencrypt.org/directory');

Live CA

$ac=new ACMECert('https://api.buypass.com/acme/directory');

Staging CA

$ac=new ACMECert('https://api.test4.buypass.no/acme/directory');

Live CA

$ac=new ACMECert('https://dv.acme-v02.api.pki.goog/directory');

Staging CA

$ac=new ACMECert('https://dv.acme-v02.test-api.pki.goog/directory');

Live CA

$ac=new ACMECert('https://acme.ssl.com/sslcom-dv-rsa');

Live CA

$ac=new ACMECert('https://acme.zerossl.com/v2/DV90');
or any other (ACME v2 - RFC 8555) compatible CA
$ac=new ACMECert('INSERT_URL_TO_AMCE_CA_DIRECTORY_HERE');

Generate RSA Private Key

$key=$ac->generateRSAKey(2048);
file_put_contents('account_key.pem',$key);

Equivalent to: openssl genrsa -out account_key.pem 2048

Generate EC Private Key

$key=$ac->generateECKey('P-384');
file_put_contents('account_key.pem',$key);

Equivalent to: openssl ecparam -name secp384r1 -genkey -noout -out account_key.pem

Register Account Key with CA

$ac->loadAccountKey('file://'.'account_key.pem');
$ret=$ac->register(true,'[email protected]');
print_r($ret);

Register Account Key with CA using External Account Binding

$ac->loadAccountKey('file://'.'account_key.pem');
$ret=$ac->registerEAB(true,'INSERT_EAB_KEY_ID_HERE','INSERT_EAB_HMAC_HERE','[email protected]');
print_r($ret);

Get Certificate using http-01 challenge

$ac->loadAccountKey('file://'.'account_key.pem');

$domain_config=array(
  'test1.example.com'=>array('challenge'=>'http-01','docroot'=>'/var/www/vhosts/test1.example.com'),
  'test2.example.com'=>array('challenge'=>'http-01','docroot'=>'/var/www/vhosts/test2.example.com')
);

$handler=function($opts){
  $fn=$opts['config']['docroot'].$opts['key'];
  @mkdir(dirname($fn),0777,true);
  file_put_contents($fn,$opts['value']);
  return function($opts){
    unlink($opts['config']['docroot'].$opts['key']);
  };
};

// Generate new certificate key
$private_key=$ac->generateRSAKey(2048);

$fullchain=$ac->getCertificateChain($private_key,$domain_config,$handler);
file_put_contents('fullchain.pem',$fullchain);
file_put_contents('private_key.pem',$private_key);

Get Certificate using all (http-01,dns-01 and tls-alpn-01) challenge types together

$ac->loadAccountKey('file://'.'account_key.pem');

$domain_config=array(
  'example.com'=>array('challenge'=>'http-01','docroot'=>'/var/www/vhosts/example.com'),
  '*.example.com'=>array('challenge'=>'dns-01'),
  'test.example.org'=>array('challenge'=>'tls-alpn-01')
);

$handler=function($opts) use ($ac){
  switch($opts['config']['challenge']){
    case 'http-01': // automatic example: challenge directory/file is created..
      $fn=$opts['config']['docroot'].$opts['key'];
      @mkdir(dirname($fn),0777,true);
      file_put_contents($fn,$opts['value']);
      return function($opts) use ($fn){ // ..and removed after validation completed
        unlink($fn);
      };
    break;
    case 'dns-01': // manual example:
      echo 'Create DNS-TXT-Record '.$opts['key'].' with value '.$opts['value']."\n";
      readline('Ready?');
      return function($opts){
        echo 'Remove DNS-TXT-Record '.$opts['key'].' with value '.$opts['value']."\n";
      };
    break;
    case 'tls-alpn-01':
      $cert=$ac->generateALPNCertificate('file://'.'some_private_key.pem',$opts['domain'],$opts['value']);
      // Use $cert and some_private_key.pem(<- does not have to be a specific key,
      // just make sure you generated one) to serve the certificate for $opts['domain']


      // This example uses an included ALPN Responder - a standalone https-server
      // written in a few lines of node.js - which is able to complete this challenge.

      // store the generated verification certificate to be used by the ALPN Responder.
      file_put_contents('alpn_cert.pem',$cert);

      // To keep this example simple, the included Example ALPN Responder listens on port 443,
      // so - for the sake of this example - you have to stop the webserver here, like:
      shell_exec('/etc/init.d/apache2 stop');

      // Start ALPN Responder (requires node.js)
      $resource=proc_open(
        'node alpn_responder.js some_private_key.pem alpn_cert.pem',
        array(
          0=>array('pipe','r'),
          1=>array('pipe','w')
        ),
        $pipes
      );

      // wait until alpn responder is listening
      fgets($pipes[1]);

      return function($opts) use ($resource,$pipes){
        // Stop ALPN Responder
        fclose($pipes[0]);
        fclose($pipes[1]);
        proc_close($resource);
        shell_exec('/etc/init.d/apache2 start');
      };
    break;
  }
};

// Example for using a pre-generated CSR as input to getCertificateChain instead of a private key:
// $csr=$ac->generateCSR('file://'.'cert_private_key.pem',array_keys($domain_config));
// $fullchain=$ac->getCertificateChain($csr,$domain_config,$handler);

$fullchain=$ac->getCertificateChain('file://'.'cert_private_key.pem',$domain_config,$handler);
file_put_contents('fullchain.pem',$fullchain);

Get alternate chains

$chains=$ac->getCertificateChains('file://'.'cert_private_key.pem',$domain_config,$handler);
if (isset($chains['ISRG Root X1'])){ // use alternate chain 'ISRG Root X1'
  $fullchain=$chains['ISRG Root X1'];
}else{ // use default chain if 'ISRG Root X1' is not present
  $fullchain=reset($chains);
}
file_put_contents('fullchain.pem',$fullchain);

Revoke Certificate

$ac->loadAccountKey('file://'.'account_key.pem');
$ac->revoke('file://'.'fullchain.pem');

Get Account Information

$ac->loadAccountKey('file://'.'account_key.pem');
$ret=$ac->getAccount();
print_r($ret);

Account Key Roll-over

$ac->loadAccountKey('file://'.'account_key.pem');
$ret=$ac->keyChange('file://'.'new_account_key.pem');
print_r($ret);

Deactivate Account

$ac->loadAccountKey('file://'.'account_key.pem');
$ret=$ac->deactivateAccount();
print_r($ret);

Get/Use ACME Renewal Information

$ret=$ac->getARI('file://'.'fullchain.pem',$ari_cert_id);
if ($ret['suggestedWindow']['start']-time()>0) {
  die('Certificate still good, exiting..');
}

$settings=array(
  'replaces'=>$ari_cert_id
);
$ac->getCertificateChain(..., ..., ..., $settings);

Get Remaining Percentage

$percent=$ac->getRemainingPercent('file://'.'fullchain.pem'); // certificate or certificate-chain
if ($precent>33.333) { // certificate has still more than 1/3 (33.333%) of its lifetime left
  die('Certificate still good, exiting..');
}
// get new certificate here..

This allows you to run your renewal script without the need to time it exactly, just run it often enough. (cronjob)

Get Remaining Days

$days=$ac->getRemainingDays('file://'.'fullchain.pem'); // certificate or certificate-chain
if ($days>30) { // renew 30 days before expiry
  die('Certificate still good, exiting..');
}
// get new certificate here..

Logging

By default ACMECert logs its actions using error_log which logs messages to stderr in PHP CLI so it is easy to log to a file instead:

error_reporting(E_ALL);
ini_set('log_errors',1);
ini_set('error_log',dirname(__FILE__).'/ACMECert.log');

To disable the default logging, you can use setLogger, Exceptions are nevertheless thrown:

$ac->setLogger(false);

Or you can you set it to a custom callback function:

$ac->setLogger(function($txt){
	echo 'Log Message: '.$txt."\n";
});

ACME_Exception

If the ACME-Server responded with an error message an \skoerfgen\ACMECert\ACME_Exception is thrown. (ACME_Exception extends Exception)

ACME_Exception has two additional functions:

  • getType() to get the ACME error code:
use skoerfgen\ACMECert\ACME_Exception;

try {
  echo $ac->getAccountID().PHP_EOL;
}catch(ACME_Exception $e){
  if ($e->getType()=='urn:ietf:params:acme:error:accountDoesNotExist'){
    echo 'Account does not exist'.PHP_EOL;
  }else{
    throw $e; // another error occured
  }
}
  • getSubproblems() to get an array of ACME_Exceptions if there is more than one error returned from the ACME-Server:
try {
  $cert=$ac->getCertificateChain('file://'.'cert_private_key.pem',$domain_config,$handler);
} catch (\skoerfgen\ACMECert\ACME_Exception $e){
  $ac->log($e->getMessage()); // log original error
  foreach($e->getSubproblems() as $subproblem){
    $ac->log($subproblem->getMessage()); // log sub errors
  }
}

Function Reference

ACMECert::__construct

Creates a new ACMECert instance.

public ACMECert::__construct ( string $ca_url = 'https://acme-v02.api.letsencrypt.org/directory' )
Parameters

ca_url

A string containing the URL to an ACME CA directory endpoint.

Return Values

Returns a new ACMECert instance.


ACMECert::generateRSAKey

Generate RSA private key (used as account key or private key for a certificate).

public string ACMECert::generateRSAKey ( int $bits = 2048 )
Parameters

bits

RSA key size in bits.

Return Values

Returns the generated RSA private key as PEM encoded string.

Errors/Exceptions

Throws an Exception if the RSA key could not be generated.


ACMECert::generateECKey

Generate Elliptic Curve (EC) private key (used as account key or private key for a certificate).

public string ACMECert::generateECKey ( string $curve_name = 'P-384' )
Parameters

curve_name

Supported Curves by Let’s Encrypt:

  • P-256 (prime256v1)
  • P-384 (secp384r1)
  • P-521 (secp521r1)
Return Values

Returns the generated EC private key as PEM encoded string.

Errors/Exceptions

Throws an Exception if the EC key could not be generated.


ACMECert::loadAccountKey

Load account key.

public void ACMECert::loadAccountKey ( mixed $account_key_pem )
Parameters

account_key_pem

can be one of the following:

  • a string containing a PEM formatted private key.
  • a string beginning with file:// containing the filename to read a PEM formatted private key from.
Return Values

No value is returned.

Errors/Exceptions

Throws an Exception if the account key could not be loaded.


ACMECert::register

Associate the loaded account key with the CA account and optionally specify contacts.

public array ACMECert::register ( bool $termsOfServiceAgreed = FALSE [, mixed $contacts = array() ] )
Parameters

termsOfServiceAgreed

By passing TRUE, you agree to the Terms Of Service of the selected CA. (Must be set to TRUE in order to successully register an account.)

Hint: Use getTermsURL() to get the link to the current Terms Of Service.

contacts

can be one of the following:

  1. A string containing an e-mail address
  2. Array of e-mail adresses
Return Values

Returns an array containing the account information.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other registration error occured.


ACMECert::registerEAB

Associate the loaded account key with the CA account using External Account Binding (EAB) credentials and optionally specify contacts.

public array ACMECert::registerEAB ( bool $termsOfServiceAgreed, string $eab_kid, string $eab_hmac [, mixed $contacts = array() ] )
Parameters

termsOfServiceAgreed

By passing TRUE, you agree to the Terms Of Service of the selected CA. (Must be set to TRUE in order to successully register an account.)

Hint: Use getTermsURL() to get the link to the current Terms Of Service.

eab_kid

a string specifying the EAB Key Identifier

eab_hmac

a string specifying the EAB HMAC Key

contacts

can be one of the following:

  1. A string containing an e-mail address
  2. Array of e-mail adresses
Return Values

Returns an array containing the account information.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other registration error occured.


ACMECert::update

Update account contacts.

public array ACMECert::update ( mixed $contacts = array() )
Parameters

contacts

can be one of the following:

  • A string containing an e-mail address
  • Array of e-mail adresses
Return Values

Returns an array containing the account information.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured updating the account.


ACMECert::getAccount

Get Account Information.

public array ACMECert::getAccount()
Return Values

Returns an array containing the account information.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured getting the account information.


ACMECert::getAccountID

Get Account ID.

public string ACMECert::getAccountID()
Return Values

Returns the Account ID

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured getting the account id.


ACMECert::keyChange

Account Key Roll-over (exchange the current account key with another one).

If the Account Key Roll-over succeeded, the new account key is automatically loaded via loadAccountKey

public array ACMECert::keyChange ( mixed $new_account_key_pem )
Parameters

new_account_key_pem

can be one of the following:

  • a string containing a PEM formatted private key.
  • a string beginning with file:// containing the filename to read a PEM formatted private key from.
Return Values

Returns an array containing the account information.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured during key change.


ACMECert::deactivateAccount

Deactivate account.

public array ACMECert::deactivateAccount()
Return Values

Returns an array containing the account information.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured during account deactivation.


ACMECert::getCertificateChain

Get certificate-chain (certificate + the intermediate certificate(s)).

This is what Apache >= 2.4.8 needs for SSLCertificateFile, and what Nginx needs for ssl_certificate.

public string ACMECert::getCertificateChain ( mixed $pem, array $domain_config, callable $callback, array $settings = array() )
Parameters

pem

A Private Key used for the certificate (the needed CSR is generated automatically using the given key in this case) or an already existing CSR in one of the following formats:

  • a string containing a PEM formatted private key.
  • a string beginning with file:// containing the filename to read a PEM encoded private key from.
    or
  • a string beginning with file:// containing the filename to read a PEM encoded CSR from.
  • a string containing the content of a CSR, PEM encoded, may start with -----BEGIN CERTIFICATE REQUEST-----

domain_config

An Array defining the domains and the corresponding challenge types to get a certificate for.

The first domain name in the array is used as Common Name for the certificate if it does not exceed 64 characters, otherwise the Common Name field will be empty.

Here is an example structure:

$domain_config=array(
  '*.example.com'=>array('challenge'=>'dns-01'),
  'test.example.org'=>array('challenge'=>'tls-alpn-01')
  'test.example.net'=>array('challenge'=>'http-01','docroot'=>'/var/www/vhosts/test1.example.com'),
);

Hint: Wildcard certificates (*.example.com) are only supported with the dns-01 challenge type.

challenge is mandatory and has to be one of http-01, dns-01 or tls-alpn-01. All other keys are optional and up to you to be used and are later available in the callback function as $opts['config'] (see the http-01 example where docroot is used this way)

callback

Callback function which gets invoked every time a challenge needs to be fulfilled.

callable callback ( array $opts )

Inside a callback function you can return another callback function, which gets invoked after the verification completed and the challenge tokens can be removed again.

Hint: To get access to variables of the parent scope inside the callback function use the use languange construct:

$handler=function($opts) use ($variable_from_parent_scope){};
                         ^^^

The $opts array passed to the callback function contains the following keys:

$opts['domain']

Domain name to be validated.

$opts['config']

Corresponding element of the domain_config array.

$opts['key'] and $opts['value']

Contain the following, depending on the chosen challenge type:

Challenge Type $opts['key'] $opts['value']
http-01 path + filename file contents
dns-01 TXT Resource Record Name TXT Resource Record Value
tls-alpn-01 unused token used in the acmeIdentifier extension of the verification certificate; use generateALPNCertificate to generate the verification certificate from that token. (see the tls-alpn-01 example)

settings (optional)

This array can have the following keys:

authz_reuse (boolean / default: TRUE)

If FALSE the callback function is always called for each domain and does not get skipped due to possibly already valid authorizations (authz) that are reused. This is achieved by deactivating already valid authorizations before getting new ones.

Hint: Under normal circumstances this is only needed when testing the callback function, not in production!

notBefore / notAfter (mixed)

can be one of the following:

  • a string containing a RFC 3339 formated date
  • a timestamp (integer)

Example: Certificate valid for 3 days:

array( 'notAfter' => time() + (60*60*24) * 3 )

or

array( 'notAfter' => '1970-01-01T01:22:17+01:00' )

replaces (string)

The ARI CertID uniquely identifying a previously-issued certificate which this order is intended to replace.

Use: getARI to get the ARI CertID for a certificate.

Example: Get/Use ACME Renewal Information

Return Values

Returns a PEM encoded certificate chain.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured obtaining the certificate.


ACMECert::getCertificateChains

Get all (default and alternate) certificate-chains. This function takes the same arguments as the getCertificateChain function above, but it returns an array of certificate chains instead of a single chain.

public string ACMECert::getCertificateChains ( mixed $pem, array $domain_config, callable $callback, array $settings = array() )
Return Values

Returns an array of PEM encoded certificate chains.

The keys of the returned array correspond to the issuer Common Name (CN) of the topmost (closest to the root certificate) intermediate certificate.

The first element of the returned array is the default chain.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured obtaining the certificate chains.


ACMECert::revoke

Revoke certificate.

public void ACMECert::revoke ( mixed $pem )
Parameters

pem

can be one of the following:

  • a string beginning with file:// containing the filename to read a PEM encoded certificate or certificate-chain from.
  • a string containing the content of a certificate or certificate-chain, PEM encoded, may start with -----BEGIN CERTIFICATE-----
Return Values

No value is returned.

If the function completes without Exception, the certificate was successully revoked.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured revoking the certificate.


ACMECert::generateCSR

Generate CSR for a set of domains.

public string ACMECert::generateCSR ( mixed $private_key, array $domains )
Parameters

private_key

can be one of the following:

  • a string containing a PEM formatted private key.
  • a string beginning with file:// containing the filename to read a PEM formatted private key from.

domains

Array of domains

Return Values

Returns the generated CSR as string.

Errors/Exceptions

Throws an Exception if the CSR could not be generated.


ACMECert::generateALPNCertificate

Generate a self signed verification certificate containing the acmeIdentifier extension used in tls-alpn-01 challenge.

public string ACMECert::generateALPNCertificate ( mixed $private_key, string $domain, string $token )
Parameters

private_key

private key used for the certificate.

can be one of the following:

  • a string containing a PEM formatted private key.
  • a string beginning with file:// containing the filename to read a PEM formatted private key from.

domain

domain name to be validated.

token

verification token.

Return Values

Returns a PEM encoded verification certificate.

Errors/Exceptions

Throws an Exception if the certificate could not be generated.


ACMECert::parseCertificate

Get information about a certificate.

public array ACMECert::parseCertificate ( mixed $pem )
Parameters

pem

can be one of the following:

  • a string beginning with file:// containing the filename to read a PEM encoded certificate or certificate-chain from.
  • a string containing the content of a certificate or certificate-chain, PEM encoded, may start with -----BEGIN CERTIFICATE-----
Return Values

Returns an array containing information about the certificate.

Errors/Exceptions

Throws an Exception if the certificate could not be parsed.


ACMECert::getRemainingPercent

Get the percentage the certificate is still valid.

public float ACMECert::getRemainingPercent( mixed $pem )
Parameters

pem

can be one of the following:

  • a string beginning with file:// containing the filename to read a PEM encoded certificate or certificate-chain from.
  • a string containing the content of a certificate or certificate-chain, PEM encoded, may start with -----BEGIN CERTIFICATE-----
Return Values

A float value containing the percentage the certificate is still valid.

Errors/Exceptions

Throws an Exception if the certificate could not be parsed.


ACMECert::getRemainingDays

Get the number of days the certificate is still valid.

public float ACMECert::getRemainingDays ( mixed $pem )
Parameters

pem

can be one of the following:

  • a string beginning with file:// containing the filename to read a PEM encoded certificate or certificate-chain from.
  • a string containing the content of a certificate or certificate-chain, PEM encoded, may start with -----BEGIN CERTIFICATE-----
Return Values

Returns how many days the certificate is still valid.

Errors/Exceptions

Throws an Exception if the certificate could not be parsed.


ACMECert::splitChain

Split a string containing a PEM encoded certificate chain into an array of individual certificates.

public array ACMECert::splitChain ( string $pem )
Parameters

pem

  • a certificate-chain as string, PEM encoded.
Return Values

Returns an array of PEM encoded individual certificates.

Errors/Exceptions

None


ACMECert::getCAAIdentities

Get a list of all CAA Identities for the selected CA. (Useful for setting up CAA DNS Records)

public array ACMECert::getCAAIdentities()
Return Values

Returns an array containing all CAA Identities for the selected CA.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured getting the CAA Identities.


ACMECert::getSAN

Get all Subject Alternative Names of given certificate.

public array ACMECert::getSAN( mixed $pem )
Parameters

pem

can be one of the following:

  • a string beginning with file:// containing the filename to read a PEM encoded certificate or certificate-chain from.
  • a string containing the content of a certificate or certificate-chain, PEM encoded, may start with -----BEGIN CERTIFICATE-----
Return Values

Returns an array containing all Subject Alternative Names of given certificate.

Errors/Exceptions

Throws an Exception if an error occured getting the Subject Alternative Names.


ACMECert::getTermsURL

Get URL to Terms Of Service for the selected CA.

public array ACMECert::getTermsURL()
Return Values

Returns a string containing a URL to the Terms Of Service for the selected CA.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured getting the Terms Of Service.


ACMECert::setLogger

Turn on/off logging to stderr using error_log or provide a custom callback function.

public void ACMECert::setLogger( bool|callable $value = TRUE )
Parameters

value

  • If TRUE, logging to stderr using error_log is enabled. (default)
  • If FALSE, logging is disabled.
  • If a callback function is provided, the function gets called with the log message as first argument:
void callback( string $txt )

see Logging

Return Values

No value is returned.

Errors/Exceptions

Throws an Exception if the value provided is not boolean or a callable function.


ACMECert::getARI

Get ACME Renewal Information (ARI) for a given certificate.

public array ACMECert::getARI( mixed $pem, string &$ari_cert_id = null )
Parameters

pem

can be one of the following:

  • a string beginning with file:// containing the filename to read a PEM encoded certificate or certificate-chain from.
  • a string containing the content of a certificate or certificate-chain, PEM encoded, may start with -----BEGIN CERTIFICATE-----

ari_cert_id

If this parameter is present, it will be set to the ARI CertID of the given certificate.

See the documentation of getCertificateChain where the ARI CertID can be used to replace an existing certificate.

Example: Get/Use ACME Renewal Information

Return Values

Returns an Array with the following keys:

suggestedWindow (array)

An Array with two keys, start and end, whose values are unix timestamps, which bound the window of time in which the CA recommends renewing the certificate.

explanationURL (string, optional)

A URL pointing to a page which may explain why the suggested renewal window is what it is. For example, it may be a page explaining the CA's dynamic load-balancing strategy, or a page documenting which certificates are affected by a mass revocation event.

Errors/Exceptions

Throws an ACME_Exception if the server responded with an error message or an Exception if an other error occured getting the ACME Renewal Information.


MIT License

Copyright (c) 2018 Stefan Körfgen

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

acmecert's People

Contributors

alphp avatar bizarrus avatar encedo avatar skoerfgen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

acmecert's Issues

memory leak

i don't know where but there must be an memory leak when u try to get a lot of certificates in a loop.

code example test.php to reproduce,

require 'ACMECert/ACMECert.php';
use skoerfgen\ACMECert\ACMECert;

for($i=0;$i<100;$i++) {

	$ac=new ACMECert('https://acme-staging-v02.api.letsencrypt.org/directory');
	$ac->loadAccountKey('file://'.'account_key.pem');

	$hostname=substr(md5(uniqid().microtime()),0,5).'.hostname.tld';

	$private_host_key=$ac->generateECKey('P-384');
	file_put_contents("cert_private_key.$hostname.pem",$private_host_key);

	$domain_config=array(
		$hostname=>array('challenge'=>'http-01','docroot'=>'/var/www/vhosts/wildcard.hostname.tld/')
	);

	$handler=function($opts){
		$fn=$opts['config']['docroot'].$opts['key'];
		@mkdir(dirname($fn),0777,true);
		file_put_contents($fn,$opts['value']);
		return function($opts){
			unlink($opts['config']['docroot'].$opts['key']);
		};
	};

	$fullchain=$ac->getCertificateChain('file://'."cert_private_key.$hostname.pem",$domain_config,$handler);
	file_put_contents("fullchain.$hostname.pem",$fullchain);

	echo "$i: memory_get_usage=".(memory_get_usage()/1024)."kB\n";
	
}

example output of a cli php test.php | grep memory_get_usage using php8.2

memory_get_usage=579.96875kB
memory_get_usage=597.1328125kB
memory_get_usage=614.28125kB
memory_get_usage=631.4296875kB
memory_get_usage=648.578125kB
memory_get_usage=665.7265625kB
memory_get_usage=682.875kB
memory_get_usage=700.0234375kB
memory_get_usage=717.171875kB
memory_get_usage=734.3203125kB
memory_get_usage=751.46875kB
memory_get_usage=768.6171875kB
memory_get_usage=785.765625kB
memory_get_usage=802.9140625kB

i know the PHP GC cleans it up, but the script itself should do it

asn1: syntax error: sequence truncated (urn:ietf:params:acme:error:malformed)

I am using the latest ACMECert.php file and testing my script against Let's Encrypt Staging.

My account info is fine but when I use the getCertificateChain method to get a signed cert for my wildcard cert for my domain, I get the following in the console.

I created the CSR myself and passing that into getCertificateChain via file://


Getting account info
Initializing ACME v2 staging environment
Using cURL
https://acme-staging-v02.api.letsencrypt.org/directory [200] (0.26s)
Initialized
https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce [200] (0.06s)
https://acme-staging-v02.api.letsencrypt.org/acme/new-acct [200] (0.12s)
AccountID: https://acme-staging-v02.api.letsencrypt.org/acme/acct/********
Account info retrieved
Using provided CSR
Creating Order
https://acme-staging-v02.api.letsencrypt.org/acme/new-order [201] (0.14s)
Order created: https://acme-staging-v02.api.letsencrypt.org/acme/order/********/66862812
All authorizations already valid, skipping validation altogether
Finalizing Order
https://acme-staging-v02.api.letsencrypt.org/acme/finalize/********/66862812 [400] (0.12s)
PHP Fatal error: Uncaught ACME_Exception: Error parsing certificate request: asn1: syntax error: sequence truncated (urn:ietf:params:acme:error:malformed) in /home/dhuv/git/ACMECert/ACMECert.php:718
Stack trace:
#0 /home/dhuv/git/ACMECert/ACMECert.php(561): ACMEv2->http_request('https://acme-st...', '{"protected":"e...')
#1 /home/dhuv/git/ACMECert/ACMECert.php(234): ACMEv2->request('_tmp', Array)
#2 /home/dhuv/lets-encrypt/acme-test(29): ACMECert->getCertificateChain('file:///home/dh...', Array, Object(Closure))
#3 {main}
thrown in /home/dhuv/git/ACMECert/ACMECert.php on line 718


I went to line 718 and the $headers variable was the following:


Array
(
[server] => nginx
[date] => Mon, 23 Dec 2019 02:32:05 GMT
[content-type] => application/problem+json
[content-length] => 158
[connection] => keep-alive
[boulder-requester] => ********
[cache-control] => public, max-age=0, no-cache
[link] => https://acme-staging-v02.api.letsencrypt.org/directory;rel="index"
[replay-nonce] => 0002i5_LDNIh8N_0PrIb8p7r6DO5Q1MwPXjL_2qGk9ahO5g
)


Are Wildcard Certificates http-01 challenges possible?

Hi, is it possible to request a certificate with http-01 challenges which includes many certificates in one?

For example: website.com, *.website.com, *.sub1.website.com, *.sub2.website.com, *.sub3.website.com

Thank you

Error in GnuTLS initialization: Failed to acquire random data.

I'm running identical scripts on two different severs. It's working properly at one server, but on a shared hosting it's running into the following error, whenever trying to create a CSR (generateCSR) or key (generateKey):

Error in GnuTLS initialization: Failed to acquire random data.

Both servers are running on PHP version 7.2.29-he.0 and have OpenSSL/1.0.1t enabled. Any ideas of what needs to be enabled/updated/changed on the shared hosting?

dns-01 issue

there is a small TTL delay between 2 DNS requests to the identical zone. this is an issue if your're going to sign a certificate for a domain AND a wildcard.

so when you set up the first TXT record for *.example.com and LE will validate it, the second validation for example.com will fail, because LE resolver still has only the TXT record for the first request in cache

Fix: you should be able to set up all TXT records for a zone and THEN fire the validation request

// example code
// (replaced my domain with example.com in code and log)
$ac=new ACMECert(false);
$ac->loadAccountKey('file://account_key.pem');
$privkey=$ac->generateRSAKey();
$domain_config=array(
'example.com'=>array('challenge'=>'dns-01'),
'*.example.com'=>array('challenge'=>'dns-01')
);
$handler=function($opts) use ($ac){
echo 'Create DNS-TXT-Record '.$opts['key'].' with value '.$opts['value']."\n";
// code to set up DNS TXT record
return function($opts){
// code to remove this TXT record
};
};
$fullchain=$ac->getCertificateChain($privkey,$domain_config,$handler);

// log:
Generating CSR
Getting account info
Initializing ACME v2 staging environment
https://acme-staging-v02.api.letsencrypt.org/directory [200 OK] (0.35s)
Initialized
https://acme-staging-v02.api.letsencrypt.org/acme/new-nonce [200 OK] (0.32s)
https://acme-staging-v02.api.letsencrypt.org/acme/new-acct [200 OK] (0.23s)
AccountID: https://acme-staging-v02.api.letsencrypt.org/acme/acct/118150
Account info retrieved
Creating Order
https://acme-staging-v02.api.letsencrypt.org/acme/new-order [201 Created] (2.16s)
Order created: https://acme-staging-v02.api.letsencrypt.org/acme/order/118150/24075821
Fetching authorization (1/2)
https://acme-staging-v02.api.letsencrypt.org/acme/authz/cMwkKLmHSg2pAXGcwsd_10531NhE3_hz05TXkM822e8 [200 OK] (0.24s)
Triggering challenge callback for example.com [dns-01]
Create DNS-TXT-Record _acme-challenge.example.com with value cpFMEUlL6CcefDIiSsiMlhCCcrihB0-mh2rqAwSa4WE
Notifying server for validation
https://acme-staging-v02.api.letsencrypt.org/acme/challenge/cMwkKLmHSg2pAXGcwsd_10531NhE3_hz05TXkM822e8/251283352 [200 OK] (0.25s)
Waiting for server challenge validation
https://acme-staging-v02.api.letsencrypt.org/acme/authz/cMwkKLmHSg2pAXGcwsd_10531NhE3_hz05TXkM822e8 [200 OK] (0.24s)
Validation successful: example.com
Fetching authorization (2/2)
https://acme-staging-v02.api.letsencrypt.org/acme/authz/Kw4FP2B5oQPq-XUigqcE6wkO662pIqhJMsKcmbCYE88 [200 OK] (0.23s)
Triggering challenge callback for *.example.com [dns-01]
Create DNS-TXT-Record _acme-challenge.example.com with value okw-z8Pz5bda50LleTR8S_hv9W_s1xTdSKBINucQNgA
Notifying server for validation
https://acme-staging-v02.api.letsencrypt.org/acme/challenge/Kw4FP2B5oQPq-XUigqcE6wkO662pIqhJMsKcmbCYE88/251283351 [200 OK] (0.24s)
Waiting for server challenge validation
https://acme-staging-v02.api.letsencrypt.org/acme/authz/Kw4FP2B5oQPq-XUigqcE6wkO662pIqhJMsKcmbCYE88 [200 OK] (0.24s)
Validation failed: *.example.com
PHP Fatal error: Uncaught exception 'Exception' with message 'Challenge validation failed: Incorrect TXT record "cpFMEUlL6CcefDIiSsiMlhCCcrihB0-mh2rqAwSa4WE" found at _acme-challenge.example.com (urn:ietf:params:acme:error:unauthorized)' in ACMECert.php:178
Stack trace:
#0 acmev2.php(98): ACMECert->getCertificateChain('-----BEGIN PRIV...', Array, Object(Closure))
#1 {main}
thrown in ACMECert.php on line 178

Fatal error: Uncaught exception 'Exception' with message 'Challenge validation failed: Incorrect TXT record "cpFMEUlL6CcefDIiSsiMlhCCcrihB0-mh2rqAwSa4WE" found at _acme-challenge.example.com (urn:ietf:params:acme:error:unauthorized)' in ACMECert.php:178
Stack trace:
#0 acmev2.php(98): ACMECert->getCertificateChain('-----BEGIN PRIV...', Array, Object(Closure))
#1 {main}
thrown in ACMECert.php on line 178

token for manual http-01 challenge

Hi, thank you for this awsome work.

  • I'm trying to make a manual process for certifying with http-01 challenge (somthing like sslforfree). I have read all of the functions mentioned in the documentation but i couldn't find how can i get the html challenge token string to place it in "/.well-known/acme-challenge". i know it shall be in $opt function but if it is possible give me more information about it.

  • also i have discovered that it is necessary to locate "cacert.pem" in "php.ini" to run ACMECert correctly on "wamp/xampp" (I didn't test it on actual server yet) . users should uncomment "curl.cainfo" and "openssl.cafile" in php.ini with the cacert address.

Two DNS-names in one wildcard certificate

Dear Stefan, is it possible to specify two DNS-names in one wildcard certificate? If I write:

$domain_config=array(
  'example.com'=>array('challenge'=>'dns-01'),
  '*.example.com'=>array('challenge'=>'dns-01')
);

then it will require me two DNS-TXT records. And also I cannot use this code, it will cause an error:

$domain_config=array(
  'example.com,*.example.com'=>array('challenge'=>'dns-01')
);

In certbot, when creating a certificate, you can use the following command, this will add two DNS-names to the certificate:

certbot certonly --manual --email [email protected] -d *.example.com -d example.com --agree-tos --manual-public-ip-logging-ok --preferred-challenges dns-01 --server https://acme-v02.api.letsencrypt.org/directory

but I don’t understand how to do it in ACMECert?
image

Pending authorizations rate limit

Hi, the limit of pending authorizations is at 300 per account. Is this lib making sure those are always getting trigger to avoid reaching the pending limit? Thanks!

PHP 8.1 support

There are some issues with PHP 8.1, I will try to do PR with a fix later this week once I have time.

Deprecated: Optional parameter $termsOfServiceAgreed declared before required parameter $eab_hmac is implicitly treated as a required parameter in ACMECert.php on line 43
Fatal error: Uncaught Exception: Could not load Private Key or CSR (Optional parameter $termsOfServiceAgreed declared before required parameter $eab_hmac is implicitly treated as a required parameter | error:02001002:system library:fopen:No such file or directory): file://cert_private_key.pem in ACMECert.php:294

I think moving the option param $termsOfServiceAgreed to the end would fix it.

Basic Authentification / htaccess secured domains + http-01 challenges?

First of all, thank you so much for developing this awesome tool! I highly appreciate all of you guys putting in the hours of work to make this happen.

I'm trying to use http-01 challenges on a Basic Authentification (htaccess + htpasswd) secured domain.

Without any additional efforts, I'm getting the following response. Unfortunately I don't know how to "fix" this.

Fatal error: Uncaught ACME_Exception: Challenge validation failed: Invalid response from http://_securedomain.tld_/.well-known/acme-challenge/2DPe2qEWB4LEYLJqJFRhdRooDJAlDXUBVzpeYxTjX3o [2a01:488:42:1000:b24d:6bf2:fff9:445d]: "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\"\n \"http://www.w3.org/TR/xhtml1/D" (urn:ietf:params:acme:error:unauthorized) in /is/htdocs/.../ACMECert/ACMECert.php:220

PS: Edited out the exact path and domain info for security reasons.

At which point is file cert_private_key.pem created?

At which point is file cert_private_key.pem created? I keep getting an error that cert_private_key.pem doesn't exist:

$fullchain=$ac->getCertificateChain('file://'.'cert_private_key.pem',$domain_config,$handler);
file_put_contents('fullchain.pem',$fullchain);

Is this something I need to create manually? I seem to be missing something.

Error when generating CSR

When I try to generate CSR key and parse it like this:

$domain_private_key = $ac->generateRSAKey(2048);
//$domain_private_key = preg_replace("/^\xEF\xBB\xBF/", '', $domain_private_key);
$domain_csr = $ac->generateCSR($domain_private_key, ['apple.highschoolhelper.org']);
$ret = $ac->parseCertificate($domain_csr);


echo "<pre>";
print_r($ret);
echo "</pre>";

Then I get this exception:

Warning: openssl_x509_read(): supplied parameter cannot be coerced into an X509 certificate! 
in /var/www/html/apple.highschoolhelper.org/public_html/libs/ACMECert/ACMECert.php on line 313

Fatal error: Uncaught Exception: Could not load certificate:
 -----BEGIN CERTIFICATE REQUEST----- MIICojCCAYoCAQAwJTEjMCEGA1UEAwwaYXBwbGUuaGlnaHNjaG9vbGhlbHBlci5v cmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUcL30x/uEDLoVl3Sw +fadN5ElHEohR33z/5oNAun+tpGATRplNiiO7mfWHXLY6g39anhPaHFBGLd3KSSF hZobM7D7B+F6A1Q2IAJLQ//6xopUagIUl6IuMn6xgXCNoV75D97vAAYjM8Q8iwOM mCo3ayhtOjRlmf5XiIiSBq5jbQgCVUn5wcGp2XGseofYYiK4ZA+54b9k5UJJ3pHh 5rERJ93G3JgSUQaXPLtgOpBB2XSS8trfedQWbx79Fb2rSPYdMeZCwV78pkl6gSAR DfeGvatCsVAZcerRLVbCZlfK1RSQ7hQA7HkZJIbU4Bk8hMF9yeJV33q6oYBnP6xZ Rm33AgMBAAGgODA2BgkqhkiG9w0BCQ4xKTAnMCUGA1UdEQQeMByCGmFwcGxlLmhp Z2hzY2hvb2xoZWxwZXIub3JnMA0GCSqGSIb3DQEBDQUAA4IBAQAdfcUvD5csPYFF Asgc8wlPFWcKOWEfTBKCTLLN9f5p0rOJB7YYxrG0nvlbSrDNgB+G60hFcdXfRgeY 1P0JAplLZTYv4JyfFTJyNtwZidjwq0IPe171Mqv7GzXiaGj1qgZTUBeLqwybX+K9 v81zGKrRrx5B30YViNBY/b3/ErFaDnFzX5NOHKBRHrhXkUFQTDRxpXBGJrIb61l4 Ix4cnHbGwHAMVO+8A0cEWHqG4W3lYdRwMb+/jyf8RJ3/qTq4EAtdY7xMMs2kJsnM nFwq12z1CwOStETUSErDhmRzzYGuG29bg4sn2GQHtTP8B2e8vpFJJVlDYIH/SPi8 nuA0v3cW -----END CERTIFICATE 
in /var/www/html/apple.highschoolhelper.org/public_html/libs/ACMECert/ACMECert.php on line 314

EAB authorization support

Hi Stefan

Have you been thinking about adding EAB authorization to the lib? ZeroSSL is a new kid on the block but requires EAB support. BuyPASS works out of the box (only CA's URL need to be added). Look at the acme.sh or ACMEphp projects for details on how it works.

ZeroSSL is a very interesting CA as there are almost no rate limits.

Chris

Deprecated function on PHP8

Hi,

I recently upgraded my PHP installation to php 8 and the function openssl_pkey_free() triggers a deprecated message.

Thank you

Error:0E06D06C when Loading account key

Hello,

Thanks for your work, PHP Fatal error: Uncaught Exception: Could not load account key: 'account_key.pem ' (error:0E06D06C:configuration file routines:NCONF_get_string:no value)

Do you know what is wrong ?

I'm using a WAMP Server with php 7.3

Thank you,

.pem to .crt and .key

Hi,

Thanks for this great library. Was able to get to the end and get a fullchain.pem file.

I need a .crt and .key file for apache, and not able to figure out how to get that.

Tried the following two:

openssl rsa -in fullchain.pem -out keyfileOutName.key
openssl pkey -in fullchain.pem -out foo.key

but get an error:

unable to load key
648:error:0906D06C:PEM routines:PEM_read_bio:no start line:.\crypto\pem\pem_lib.c:701:Expecting: ANY PRIVATE KEY

Any help greatly appreciated.

Virtual subdomain issues

I am creating a multitenant solution in PHP, every user that signup will get a subdomain name like e.g john.domain.com, peter.domain.com.

Im using a DNS TXT record to route all subdomains to www.domain.com, where I do some PHP magic to extract the subdomain name, e.g john and then server john the correct content.

Of course I want the john.domain.com to be secure, using let's encrypt certificate, so that the user have to enter https://john.domain.com

As far as I understand I have to run a function on every signup, e.g when john signup I have to issue a new certificate on the subdomain john.domain.com using this code:

$domain_config=array('john.example.com'=>array('challenge'=>'dns-01'));

And then every 80 days or so I have to run through all subdomains to revalidate them, something like this:

$domain_config=array('john.example.com'=>array('challenge'=>'dns-01'));
$domain_config=array('peter.example.com'=>array('challenge'=>'dns-01'));

Is this correct or am I completely wrong?

Or is a better approach using:

$domain_config=array('*.example.com'=>array('challenge'=>'dns-01'))

Google Trust Services dns-01 issue

Google Trust Services dns-01 verification method constantly says invalid as an answer and cannot verify. I would be glad if you could check it.

Alternate chain X1

Would it be possible to look into implementing alternate trust paths please? Last week LetsEncrypts DST Root CA X3 expired, causing a lot of trouble for older SSL implementations, especially on servers. There's a really easy fix available: using an alternate trust path. While this breaks Android-4 trust it fixes trust for OpenSSL/LibreSSL.

When you download the certificates in the last step, the ACME server may provide a header in this format:
link: https://acme-v02.api.letsencrypt.org/acme/cert/0123456789abcdef0123456789abcdef/1;rel="alternate"
That is the link to an alternative trust path that a sysadmin may choose to use instead of the default path.

Resources:
https://letsencrypt.org/2020/12/21/extending-android-compatibility.html
https://datatracker.ietf.org/doc/html/rfc8555#section-7.4.2

I created a quick and dirty fix that suits my needs, but it would be great if this were a supported feature.

error:02001002:system library:fopen:No such file or directory

Hi, I'm getting an error

[15-Apr-2020 18:22:27 Asia/Krasnoyarsk] PHP Fatal error:  Uncaught exception 'Exception' with message 'Could not load account key: file://account_key.pem (error:02001002:system library:fopen:No such file or directory)' in ...\ACMECert.php:464
Stack trace:
#0 ...\ACMECert\index.php(26): ACMEv2->loadAccountKey('file://account_...')
#1 {main}
  thrown in ...\ACMECert.php on line 464

in PHP version 5.6.40 x64. But I do not get errors in version 5.6.31 x86. Searching the Internet, I assume that openssl cannot find the configuration file, can I specify it somewhere in the code?
My code:

if(isset($_POST['Register_Account_Key_with_Lets_Encrypt'])){
	require 'ACMECert.php';
	$ac = new ACMECert();
	$ac->loadAccountKey('file://'.'account_key.pem');
	$ret=$ac->register(true,'[email protected]');
	print_r($ret);
	echo '<a href="./">back</a>';
	exit;
}

No Function Comments in classes and Methods

Hello
Really love your work especially with this multi Ca feature (i.e ability to use the class not for just LetsEncrypt alone but also ZeroSsl and BuyPass).

In the comments you promised to merge this branch with Master. May I make a suggestion ?

Observation #1 : No Function Comments in classes and Methods

I noticed none of the class methods and function have comments / comment headers e.g

public function generateECKey() {
}

ought to look this way

/**
 * Generate Elliptic Curve (EC) private key (used as account key or private key for a certificate).
 * @param  string $curve_name Default is  'P-384' 
 * Supported Curves by Let’s Encrypt: P-256 (prime256v1), P-384 (secp384r1), P-521 (secp521r1)
 * @return Returns the generated EC private key as PEM encoded string. Throws an Exception if the EC key could not be generated.
 * /
public function generateECKey() {
}

Would have made the changes myself BUT don't know Git much. Guess when I have more time, would try knowing some GIT.

I understand these information already are on the index page but we need not always consult that page to get more information on what a class method does.

Once again, Really appreciate the work.

Thanks

[dns-01] A way for delaying?

Not all DNS servers have a fast TTL. A DNS entry can take up to 24/48 hours to be published.

Is there a way to get the callanges without waiting for the ACME protocol?

I would like to use a database entry that first makes DNS requests before it is processed by the ACME protocol to ensure that the `_acme-challenge? entry is already published.

If I solve the whole thing (as it exists now in the example) via a cronjob, then the process waits until if i execute the script further. It generates creates overhead unnecessarily.

case 'dns-01':
    echo 'Create DNS-TXT-Record '.$opts['key'].' with value '.$opts['value']."\n";

    // Wait here up to 24/48 hours, because the DNS entry is not published
    // If the _acme-challenge with $opts['value'] is currently not available
    // the script will be waiting here, but it generates lots of overhead because
    // the script is here running all the time until the challenges exist
    // and the script then continues

    return function($opts){
        echo 'Remove DNS-TXT-Record '.$opts['key'].' with value '.$opts['value']."\n";
     };
break;

A quick question

How do we make this script support

Elliptic Curve Parameters

Diffie-Hellman Parameters

I believe it would be much beneficial to all users of this script.

saw an implementation but uses proc_open , proc_close , etc most of which are disabled in some hosting.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.