save
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator;
|
||||
|
||||
use AcmePhp\Ssl\PrivateKey;
|
||||
|
||||
/**
|
||||
* Generate random RSA private key using OpenSSL.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
class ChainPrivateKeyGenerator implements PrivateKeyGeneratorInterface
|
||||
{
|
||||
/** @var PrivateKeyGeneratorInterface[] */
|
||||
private $generators;
|
||||
|
||||
/**
|
||||
* @param PrivateKeyGeneratorInterface[] $generators
|
||||
*/
|
||||
public function __construct(iterable $generators)
|
||||
{
|
||||
$this->generators = $generators;
|
||||
}
|
||||
|
||||
public function generatePrivateKey(KeyOption $keyOption): PrivateKey
|
||||
{
|
||||
foreach ($this->generators as $generator) {
|
||||
if ($generator->supportsKeyOption($keyOption)) {
|
||||
return $generator->generatePrivateKey($keyOption);
|
||||
}
|
||||
}
|
||||
|
||||
throw new \LogicException(sprintf('Unable to find a generator for a key option of type %s', \get_class($keyOption)));
|
||||
}
|
||||
|
||||
public function supportsKeyOption(KeyOption $keyOption): bool
|
||||
{
|
||||
foreach ($this->generators as $generator) {
|
||||
if ($generator->supportsKeyOption($keyOption)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\DhKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
|
||||
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
|
||||
use AcmePhp\Ssl\PrivateKey;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* Generate random DH private key using OpenSSL.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
class DhKeyGenerator implements PrivateKeyGeneratorInterface
|
||||
{
|
||||
use OpensslPrivateKeyGeneratorTrait;
|
||||
|
||||
public function generatePrivateKey(KeyOption $keyOption): PrivateKey
|
||||
{
|
||||
Assert::isInstanceOf($keyOption, DhKeyOption::class);
|
||||
|
||||
return $this->generatePrivateKeyFromOpensslOptions([
|
||||
'private_key_type' => OPENSSL_KEYTYPE_DH,
|
||||
'dh' => [
|
||||
'p' => $keyOption->getPrime(),
|
||||
'g' => $keyOption->getGenerator(),
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public function supportsKeyOption(KeyOption $keyOption): bool
|
||||
{
|
||||
return $keyOption instanceof DhKeyOption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\DhKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
|
||||
class DhKeyOption implements KeyOption
|
||||
{
|
||||
/** @var string */
|
||||
private $generator;
|
||||
|
||||
/** @var string */
|
||||
private $prime;
|
||||
|
||||
/**
|
||||
* @param string $prime Hexadecimal representation of the prime
|
||||
* @param string $generator Hexadecimal representation of the generator: ie. 02
|
||||
*
|
||||
* @see https://tools.ietf.org/html/rfc3526 how to choose a prime and generator numbers
|
||||
*/
|
||||
public function __construct(string $prime, string $generator = '02')
|
||||
{
|
||||
$this->generator = pack('H*', $generator);
|
||||
$this->prime = pack('H*', $prime);
|
||||
}
|
||||
|
||||
public function getGenerator(): string
|
||||
{
|
||||
return $this->generator;
|
||||
}
|
||||
|
||||
public function getPrime(): string
|
||||
{
|
||||
return $this->prime;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\DsaKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
|
||||
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
|
||||
use AcmePhp\Ssl\PrivateKey;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* Generate random DSA private key using OpenSSL.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
class DsaKeyGenerator implements PrivateKeyGeneratorInterface
|
||||
{
|
||||
use OpensslPrivateKeyGeneratorTrait;
|
||||
|
||||
public function generatePrivateKey(KeyOption $keyOption): PrivateKey
|
||||
{
|
||||
Assert::isInstanceOf($keyOption, DsaKeyOption::class);
|
||||
|
||||
return $this->generatePrivateKeyFromOpensslOptions([
|
||||
'private_key_type' => OPENSSL_KEYTYPE_DSA,
|
||||
'private_key_bits' => $keyOption->getBits(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function supportsKeyOption(KeyOption $keyOption): bool
|
||||
{
|
||||
return $keyOption instanceof DsaKeyOption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\DsaKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
|
||||
class DsaKeyOption implements KeyOption
|
||||
{
|
||||
/** @var int */
|
||||
private $bits;
|
||||
|
||||
public function __construct(int $bits = 2048)
|
||||
{
|
||||
$this->bits = $bits;
|
||||
}
|
||||
|
||||
public function getBits(): int
|
||||
{
|
||||
return $this->bits;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\EcKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
|
||||
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
|
||||
use AcmePhp\Ssl\PrivateKey;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* Generate random EC private key using OpenSSL.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
class EcKeyGenerator implements PrivateKeyGeneratorInterface
|
||||
{
|
||||
use OpensslPrivateKeyGeneratorTrait;
|
||||
|
||||
public function generatePrivateKey(KeyOption $keyOption): PrivateKey
|
||||
{
|
||||
Assert::isInstanceOf($keyOption, EcKeyOption::class);
|
||||
|
||||
return $this->generatePrivateKeyFromOpensslOptions([
|
||||
'private_key_type' => OPENSSL_KEYTYPE_EC,
|
||||
'curve_name' => $keyOption->getCurveName(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function supportsKeyOption(KeyOption $keyOption): bool
|
||||
{
|
||||
return $keyOption instanceof EcKeyOption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\EcKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
class EcKeyOption implements KeyOption
|
||||
{
|
||||
/** @var string */
|
||||
private $curveName;
|
||||
|
||||
public function __construct(string $curveName = 'secp384r1')
|
||||
{
|
||||
Assert::oneOf($curveName, openssl_get_curve_names(), 'The given curve %s is not supported. Available curves are: %s');
|
||||
|
||||
$this->curveName = $curveName;
|
||||
}
|
||||
|
||||
public function getCurveName(): string
|
||||
{
|
||||
return $this->curveName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator;
|
||||
|
||||
interface KeyOption
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator;
|
||||
|
||||
use AcmePhp\Ssl\Exception\KeyGenerationException;
|
||||
use AcmePhp\Ssl\Exception\KeyPairGenerationException;
|
||||
use AcmePhp\Ssl\Generator\DhKey\DhKeyGenerator;
|
||||
use AcmePhp\Ssl\Generator\DsaKey\DsaKeyGenerator;
|
||||
use AcmePhp\Ssl\Generator\EcKey\EcKeyGenerator;
|
||||
use AcmePhp\Ssl\Generator\RsaKey\RsaKeyGenerator;
|
||||
use AcmePhp\Ssl\Generator\RsaKey\RsaKeyOption;
|
||||
use AcmePhp\Ssl\KeyPair;
|
||||
|
||||
/**
|
||||
* Generate random KeyPair using OpenSSL.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
class KeyPairGenerator
|
||||
{
|
||||
private $generator;
|
||||
|
||||
public function __construct(PrivateKeyGeneratorInterface $generator = null)
|
||||
{
|
||||
$this->generator = $generator ?: new ChainPrivateKeyGenerator(
|
||||
[
|
||||
new RsaKeyGenerator(),
|
||||
new EcKeyGenerator(),
|
||||
new DhKeyGenerator(),
|
||||
new DsaKeyGenerator(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param KeyOption|null $keyOption configuration of the key to generate
|
||||
*
|
||||
* @throws KeyPairGenerationException when OpenSSL failed to generate keys
|
||||
*/
|
||||
public function generateKeyPair(KeyOption $keyOption = null): KeyPair
|
||||
{
|
||||
if (null === $keyOption) {
|
||||
$keyOption = new RsaKeyOption();
|
||||
}
|
||||
|
||||
try {
|
||||
$privateKey = $this->generator->generatePrivateKey($keyOption);
|
||||
} catch (KeyGenerationException $e) {
|
||||
throw new KeyPairGenerationException('Fail to generate a KeyPair with the given options', 0, $e);
|
||||
}
|
||||
|
||||
return new KeyPair(
|
||||
$privateKey->getPublicKey(),
|
||||
$privateKey
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator;
|
||||
|
||||
use AcmePhp\Ssl\Exception\KeyGenerationException;
|
||||
use AcmePhp\Ssl\Exception\KeyPairGenerationException;
|
||||
use AcmePhp\Ssl\PrivateKey;
|
||||
|
||||
trait OpensslPrivateKeyGeneratorTrait
|
||||
{
|
||||
private function generatePrivateKeyFromOpensslOptions(array $opensslOptions): PrivateKey
|
||||
{
|
||||
$resource = openssl_pkey_new($opensslOptions);
|
||||
|
||||
if (!$resource) {
|
||||
throw new KeyGenerationException(sprintf('OpenSSL key creation failed during generation with error: %s', openssl_error_string()));
|
||||
}
|
||||
if (!openssl_pkey_export($resource, $privateKey)) {
|
||||
throw new KeyPairGenerationException(sprintf('OpenSSL key export failed during generation with error: %s', openssl_error_string()));
|
||||
}
|
||||
|
||||
// PHP 8 automatically frees the key instance and deprecates the function
|
||||
if (\PHP_VERSION_ID < 80000) {
|
||||
openssl_free_key($resource);
|
||||
}
|
||||
|
||||
return new PrivateKey($privateKey);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator;
|
||||
|
||||
use AcmePhp\Ssl\Exception\KeyGenerationException;
|
||||
use AcmePhp\Ssl\PrivateKey;
|
||||
|
||||
/**
|
||||
* Generate random private key.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
interface PrivateKeyGeneratorInterface
|
||||
{
|
||||
/**
|
||||
* Generate a PrivateKey.
|
||||
*
|
||||
* @param KeyOption $keyOption configuration of the key to generate
|
||||
*
|
||||
* @throws KeyGenerationException when OpenSSL failed to generate keys
|
||||
*/
|
||||
public function generatePrivateKey(KeyOption $keyOption): PrivateKey;
|
||||
|
||||
/**
|
||||
* Returns whether the instance is able to generator a private key from the given option.
|
||||
*
|
||||
* @param KeyOption $keyOption configuration of the key to generate
|
||||
*/
|
||||
public function supportsKeyOption(KeyOption $keyOption): bool;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\RsaKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
|
||||
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
|
||||
use AcmePhp\Ssl\PrivateKey;
|
||||
use Webmozart\Assert\Assert;
|
||||
|
||||
/**
|
||||
* Generate random RSA private key using OpenSSL.
|
||||
*
|
||||
* @author Jérémy Derussé <jeremy@derusse.com>
|
||||
*/
|
||||
class RsaKeyGenerator implements PrivateKeyGeneratorInterface
|
||||
{
|
||||
use OpensslPrivateKeyGeneratorTrait;
|
||||
|
||||
public function generatePrivateKey(KeyOption $keyOption): PrivateKey
|
||||
{
|
||||
Assert::isInstanceOf($keyOption, RsaKeyOption::class);
|
||||
|
||||
return $this->generatePrivateKeyFromOpensslOptions([
|
||||
'private_key_type' => OPENSSL_KEYTYPE_RSA,
|
||||
'private_key_bits' => $keyOption->getBits(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function supportsKeyOption(KeyOption $keyOption): bool
|
||||
{
|
||||
return $keyOption instanceof RsaKeyOption;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Acme PHP project.
|
||||
*
|
||||
* (c) Titouan Galopin <galopintitouan@gmail.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace AcmePhp\Ssl\Generator\RsaKey;
|
||||
|
||||
use AcmePhp\Ssl\Generator\KeyOption;
|
||||
|
||||
class RsaKeyOption implements KeyOption
|
||||
{
|
||||
/** @var int */
|
||||
private $bits;
|
||||
|
||||
public function __construct(int $bits = 4096)
|
||||
{
|
||||
$this->bits = $bits;
|
||||
}
|
||||
|
||||
public function getBits(): int
|
||||
{
|
||||
return $this->bits;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user