Skip to content

Commit 06cfaa8

Browse files
committed
Add DH and DSA generators
1 parent d34e9f5 commit 06cfaa8

File tree

9 files changed

+232
-64
lines changed

9 files changed

+232
-64
lines changed

Generator/DhKey/DhKeyGenerator.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Acme PHP project.
5+
*
6+
* (c) Titouan Galopin <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace AcmePhp\Ssl\Generator\DhKey;
13+
14+
use AcmePhp\Ssl\Generator\KeyOption;
15+
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
16+
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
17+
use Webmozart\Assert\Assert;
18+
19+
/**
20+
* Generate random DH private key using OpenSSL.
21+
*
22+
* @author Jérémy Derussé <[email protected]>
23+
*/
24+
class DhKeyGenerator implements PrivateKeyGeneratorInterface
25+
{
26+
use OpensslPrivateKeyGeneratorTrait;
27+
28+
/**
29+
* @param DhKeyOption|KeyOption $keyOption
30+
*/
31+
public function generatePrivateKey(KeyOption $keyOption)
32+
{
33+
Assert::isInstanceOf($keyOption, DhKeyOption::class);
34+
35+
return $this->generatePrivateKeyFromOpensslOptions(
36+
[
37+
'private_key_type' => OPENSSL_KEYTYPE_DH,
38+
'dh' => [
39+
'p' => $keyOption->getPrime(),
40+
'g' => $keyOption->getGenerator(),
41+
],
42+
]
43+
);
44+
}
45+
46+
public function supportsKeyOption(KeyOption $keyOption)
47+
{
48+
return $keyOption instanceof DhKeyOption;
49+
}
50+
}

Generator/DhKey/DhKeyOption.php

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Acme PHP project.
5+
*
6+
* (c) Titouan Galopin <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace AcmePhp\Ssl\Generator\DhKey;
13+
14+
use AcmePhp\Ssl\Generator\KeyOption;
15+
16+
class DhKeyOption implements KeyOption
17+
{
18+
/** @var string */
19+
private $generator;
20+
/** @var string */
21+
private $prime;
22+
23+
/**
24+
* @param string $prime Hexadecimal representation of the prime
25+
* @param string $generator Hexadecimal representation of the generator: ie. 02
26+
*
27+
* @see https://tools.ietf.org/html/rfc3526 how to choose a prime and generator numbers
28+
*/
29+
public function __construct($prime, $generator = '02')
30+
{
31+
$this->generator = pack('H*', $generator);
32+
$this->prime = pack('H*', $prime);
33+
}
34+
35+
/**
36+
* @return string
37+
*/
38+
public function getGenerator()
39+
{
40+
return $this->generator;
41+
}
42+
43+
/**
44+
* @return string
45+
*/
46+
public function getPrime()
47+
{
48+
return $this->prime;
49+
}
50+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Acme PHP project.
5+
*
6+
* (c) Titouan Galopin <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace AcmePhp\Ssl\Generator\DsaKey;
13+
14+
use AcmePhp\Ssl\Generator\KeyOption;
15+
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
16+
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
17+
use Webmozart\Assert\Assert;
18+
19+
/**
20+
* Generate random DSA private key using OpenSSL.
21+
*
22+
* @author Jérémy Derussé <[email protected]>
23+
*/
24+
class DsaKeyGenerator implements PrivateKeyGeneratorInterface
25+
{
26+
use OpensslPrivateKeyGeneratorTrait;
27+
28+
/**
29+
* @param DsaKeyOption|KeyOption $keyOption
30+
*/
31+
public function generatePrivateKey(KeyOption $keyOption)
32+
{
33+
Assert::isInstanceOf($keyOption, DsaKeyOption::class);
34+
35+
return $this->generatePrivateKeyFromOpensslOptions(
36+
[
37+
'private_key_type' => OPENSSL_KEYTYPE_DSA,
38+
'private_key_bits' => $keyOption->getBits(),
39+
]
40+
);
41+
}
42+
43+
public function supportsKeyOption(KeyOption $keyOption)
44+
{
45+
return $keyOption instanceof DsaKeyOption;
46+
}
47+
}

Generator/DsaKey/DsaKeyOption.php

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Acme PHP project.
5+
*
6+
* (c) Titouan Galopin <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace AcmePhp\Ssl\Generator\DsaKey;
13+
14+
use AcmePhp\Ssl\Generator\KeyOption;
15+
use Webmozart\Assert\Assert;
16+
17+
class DsaKeyOption implements KeyOption
18+
{
19+
/** @var int */
20+
private $bits;
21+
22+
public function __construct($bits = 2048)
23+
{
24+
Assert::integer($bits);
25+
26+
$this->bits = $bits;
27+
}
28+
29+
/**
30+
* @return int
31+
*/
32+
public function getBits()
33+
{
34+
return $this->bits;
35+
}
36+
}

Generator/EcKey/EcKeyGenerator.php

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@
1111

1212
namespace AcmePhp\Ssl\Generator\EcKey;
1313

14-
use AcmePhp\Ssl\Exception\KeyGenerationException;
15-
use AcmePhp\Ssl\Exception\KeyPairGenerationException;
1614
use AcmePhp\Ssl\Generator\KeyOption;
15+
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
1716
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
18-
use AcmePhp\Ssl\PrivateKey;
1917
use Webmozart\Assert\Assert;
2018

2119
/**
@@ -25,32 +23,21 @@
2523
*/
2624
class EcKeyGenerator implements PrivateKeyGeneratorInterface
2725
{
26+
use OpensslPrivateKeyGeneratorTrait;
27+
2828
/**
2929
* @param EcKeyOption|KeyOption $keyOption
3030
*/
3131
public function generatePrivateKey(KeyOption $keyOption)
3232
{
3333
Assert::isInstanceOf($keyOption, EcKeyOption::class);
3434

35-
$resource = openssl_pkey_new(
35+
return $this->generatePrivateKeyFromOpensslOptions(
3636
[
3737
'private_key_type' => OPENSSL_KEYTYPE_EC,
3838
'curve_name' => $keyOption->getCurveName(),
3939
]
4040
);
41-
42-
if (!$resource) {
43-
throw new KeyGenerationException(
44-
sprintf('OpenSSL key creation failed during generation with error: %s', openssl_error_string())
45-
);
46-
}
47-
if (!openssl_pkey_export($resource, $privateKey)) {
48-
throw new KeyPairGenerationException(
49-
sprintf('OpenSSL key export failed during generation with error: %s', openssl_error_string())
50-
);
51-
}
52-
53-
return new PrivateKey($privateKey);
5441
}
5542

5643
public function supportsKeyOption(KeyOption $keyOption)

Generator/KeyPairGenerator.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313

1414
use AcmePhp\Ssl\Exception\KeyGenerationException;
1515
use AcmePhp\Ssl\Exception\KeyPairGenerationException;
16+
use AcmePhp\Ssl\Generator\DhKey\DhKeyGenerator;
17+
use AcmePhp\Ssl\Generator\DsaKey\DsaKeyGenerator;
1618
use AcmePhp\Ssl\Generator\EcKey\EcKeyGenerator;
1719
use AcmePhp\Ssl\Generator\RsaKey\RsaKeyGenerator;
1820
use AcmePhp\Ssl\Generator\RsaKey\RsaKeyOption;
@@ -34,6 +36,8 @@ public function __construct(PrivateKeyGeneratorInterface $generator = null)
3436
[
3537
new RsaKeyGenerator(),
3638
new EcKeyGenerator(),
39+
new DhKeyGenerator(),
40+
new DsaKeyGenerator(),
3741
]
3842
);
3943
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Acme PHP project.
5+
*
6+
* (c) Titouan Galopin <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace AcmePhp\Ssl\Generator;
13+
14+
use AcmePhp\Ssl\Exception\KeyGenerationException;
15+
use AcmePhp\Ssl\Exception\KeyPairGenerationException;
16+
use AcmePhp\Ssl\PrivateKey;
17+
18+
trait OpensslPrivateKeyGeneratorTrait
19+
{
20+
private function generatePrivateKeyFromOpensslOptions(array $opensslOptions)
21+
{
22+
$resource = openssl_pkey_new($opensslOptions);
23+
24+
if (!$resource) {
25+
throw new KeyGenerationException(
26+
sprintf('OpenSSL key creation failed during generation with error: %s', openssl_error_string())
27+
);
28+
}
29+
if (!openssl_pkey_export($resource, $privateKey)) {
30+
throw new KeyPairGenerationException(
31+
sprintf('OpenSSL key export failed during generation with error: %s', openssl_error_string())
32+
);
33+
}
34+
35+
return new PrivateKey($privateKey);
36+
}
37+
}

Generator/RsaKey/RsaKeyGenerator.php

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,9 @@
1111

1212
namespace AcmePhp\Ssl\Generator\RsaKey;
1313

14-
use AcmePhp\Ssl\Exception\KeyGenerationException;
15-
use AcmePhp\Ssl\Exception\KeyPairGenerationException;
1614
use AcmePhp\Ssl\Generator\KeyOption;
15+
use AcmePhp\Ssl\Generator\OpensslPrivateKeyGeneratorTrait;
1716
use AcmePhp\Ssl\Generator\PrivateKeyGeneratorInterface;
18-
use AcmePhp\Ssl\PrivateKey;
1917
use Webmozart\Assert\Assert;
2018

2119
/**
@@ -25,32 +23,21 @@
2523
*/
2624
class RsaKeyGenerator implements PrivateKeyGeneratorInterface
2725
{
26+
use OpensslPrivateKeyGeneratorTrait;
27+
2828
/**
2929
* @param RsaKeyOption|KeyOption $keyOption
3030
*/
3131
public function generatePrivateKey(KeyOption $keyOption)
3232
{
3333
Assert::isInstanceOf($keyOption, RsaKeyOption::class);
3434

35-
$resource = openssl_pkey_new(
35+
return $this->generatePrivateKeyFromOpensslOptions(
3636
[
3737
'private_key_type' => OPENSSL_KEYTYPE_RSA,
3838
'private_key_bits' => $keyOption->getBits(),
3939
]
4040
);
41-
42-
if (!$resource) {
43-
throw new KeyGenerationException(
44-
sprintf('OpenSSL key creation failed during generation with error: %s', openssl_error_string())
45-
);
46-
}
47-
if (!openssl_pkey_export($resource, $privateKey)) {
48-
throw new KeyPairGenerationException(
49-
sprintf('OpenSSL key export failed during generation with error: %s', openssl_error_string())
50-
);
51-
}
52-
53-
return new PrivateKey($privateKey);
5441
}
5542

5643
public function supportsKeyOption(KeyOption $keyOption)

Signer/DataSigner.php

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,36 +63,6 @@ public function signData($data, PrivateKey $privateKey, $algorithm = OPENSSL_ALG
6363
}
6464
}
6565

66-
/**
67-
* Convert a ECDSA signature into DER.
68-
*
69-
* The code is a copy/paste from another lib (web-token/jwt-core) which is not compatible with php <= 7.0
70-
*
71-
* @see https://github.com/web-token/jwt-core/blob/master/Util/ECSignature.php
72-
*/
73-
private function ECDSAtoDER($signature, $partLength)
74-
{
75-
$signature = \unpack('H*', $signature)[1];
76-
if (\mb_strlen($signature, '8bit') !== 2 * $partLength) {
77-
throw new DataSigningException('Invalid length.');
78-
}
79-
$R = \mb_substr($signature, 0, $partLength, '8bit');
80-
$S = \mb_substr($signature, $partLength, null, '8bit');
81-
82-
$R = $this->preparePositiveInteger($R);
83-
$Rl = \mb_strlen($R, '8bit') / 2;
84-
$S = $this->preparePositiveInteger($S);
85-
$Sl = \mb_strlen($S, '8bit') / 2;
86-
$der = \pack(
87-
'H*',
88-
'30'.($Rl + $Sl + 4 > 128 ? '81' : '').\dechex($Rl + $Sl + 4)
89-
.'02'.\dechex($Rl).$R
90-
.'02'.\dechex($Sl).$S
91-
);
92-
93-
return $der;
94-
}
95-
9666
/**
9767
* Convert a DER signature into ECDSA.
9868
*

0 commit comments

Comments
 (0)