This project provides classes around openssl_* functions in order to make working with keys and certificates a bit more palable. It is still a work in progress. Patches and bug reports welcome.
- PHP >=7.1
- Make
- (for first setup) internet connection
Make sure that you use strict types in your code!
<?php declare(strict_types=1);
In order to make a self-signed CA, you need a key.
$caPrivKey = new PrivateKey( new OpenSSLConfig( OpenSSLConfig::KEY_EC ) );
// Instead of OpenSSLConfig::KEY_EC you could use OpenSSLConfig::KEY_RSA.
From this key we will make a signing request.
$caCsr = CSR::generate(
new DN( ['CN' => 'fyrkat example CA'] ), // Subject
$caPrivKey // CA key
);
This request can now be self-signed.
$caCertificate = $caCsr->sign(
null, // CA certificate
$caPrivKey, // CA key
18250, // Validity in days
new OpenSSLConfig( OpenSSLConfig::X509_CA ) // EKU
);
// We need the same $caPrivKey again because self-sign means you sign with your own key.
// OpenSSLConfig::X509_CA means that the resulting certificate is to be used as a CA.
// Other options are OpenSSLConfig::X509_SERVER and OpenSSLConfig::X509_CLIENT.
If you already have your own CA, import it.
// Update these three lines to your own liking.
$caPrivPem = getMyPrivateKeyPemFromSomewhere();
$caPrivPemPassphrase = 'supersecret'; // or null if no passphrase.
$caCertificatePem = getMyPrivateKeyPemFromSomewhere();
$caPrivKey = new PrivateKey( $caPrivPem, $passphrase );
$caCertificate = new X509( $caCertificatePem );
Now we have $caPrivKey
and $caCertificate
to work with.
$serverPrivKey = new PrivateKey( new OpenSSLConfig( OpenSSLConfig::KEY_EC ) );
// Instead of OpenSSLConfig::KEY_EC you could use OpenSSLConfig::KEY_RSA.
$serverCsr = CSR::generate(
new DN( ['CN' => 'example.com'] ), // Subject
$serverPrivKey // Server key
);
$serverCertificate = $caCsr->sign(
$caCertificate, // CA certificate
$caPrivKey, // CA key
1095, // Validity in days
new OpenSSLConfig( OpenSSLConfig::X509_SERVER ) // EKU
);
// Using $caCertificate ensures the resulting certificate is signed by $caCertificate,
// instead of being self-signed.
// OpenSSLConfig::X509_SERVER indicates that this will be a server certificate.
We can also make a client certificate.
$clientPrivKey = new PrivateKey( new OpenSSLConfig( OpenSSLConfig::KEY_EC ) );
$clientCsr = CSR::generate(
new DN( ['CN' => 'jornane@example.com'] ), // Subject
$clientPrivKey // Client key
);
$clientCertificate = $caCsr->sign(
$caCertificate, // CA certificate
$caPrivKey, // CA key
1095, // Validity in days
new OpenSSLConfig( OpenSSLConfig::X509_CLIENT ) // EKU
);
Classes holding public key material have a __toString()
method, which allows you to use them as strings.
echo $serverCertificate; // PEM output
However, PrivateKey
does not have this feature, to avoid accidentally leaking data.
All classes have a function to get a PEM string.
$caCertificatePem = $caCertificate->getX509Pem();
$serverCertificatePem = $serverCertificate->getX509Pem();
$serverPrivKeyPem = $serverPrivKey->getPrivateKeyPem( 'supersecret' );
// Instead of 'supersecret', you can use null if you don't want the output encrypted
// Additionally, you could export just the public key, but it might not be that useful
$pkPem = $serverCertificate->getPublicKey()->getPublicKeyPem();
Limitations in openssl_csr_sign
- When signing a CSR, the expire date is an integer amount of days from the current date/time.
- When signing a CSR, it is not possible to set the not before date. This is always the current date/time.
- There is no shorthand to use altNames (#4)
- It is not possible to filter extensions in a CSR, making it a risk to allow user input CSR (#3)
make test
Before committing, run
make camera-ready