1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace JWX\JWK\EC; |
4
|
|
|
|
5
|
|
|
use CryptoUtil\ASN1\EC\ECPrivateKey; |
6
|
|
|
use CryptoUtil\ASN1\EC\ECPublicKey; |
7
|
|
|
use CryptoUtil\Conversion\ECConversion; |
8
|
|
|
use CryptoUtil\PEM\PEM; |
9
|
|
|
use JWX\JWK\Feature\AsymmetricPrivateKey; |
10
|
|
|
use JWX\JWK\JWK; |
11
|
|
|
use JWX\JWK\Parameter\CurveParameter; |
12
|
|
|
use JWX\JWK\Parameter\ECCPrivateKeyParameter; |
13
|
|
|
use JWX\JWK\Parameter\JWKParameter; |
14
|
|
|
use JWX\JWK\Parameter\KeyTypeParameter; |
15
|
|
|
use JWX\JWK\Parameter\RegisteredJWKParameter; |
16
|
|
|
use JWX\JWK\Parameter\XCoordinateParameter; |
17
|
|
|
use JWX\JWK\Parameter\YCoordinateParameter; |
18
|
|
|
|
19
|
|
|
|
20
|
|
|
/** |
21
|
|
|
* Class representing elliptic curve private key as a JWK. |
22
|
|
|
* |
23
|
|
|
* @link https://tools.ietf.org/html/rfc7517#section-4 |
24
|
|
|
* @link https://tools.ietf.org/html/rfc7518#section-6.2 |
25
|
|
|
* @link https://tools.ietf.org/html/rfc7518#section-6.2.2 |
26
|
|
|
*/ |
27
|
|
|
class ECPrivateKeyJWK extends JWK implements AsymmetricPrivateKey |
28
|
|
|
{ |
29
|
|
|
/** |
30
|
|
|
* Parameter names managed by this class. |
31
|
|
|
* |
32
|
|
|
* @internal |
33
|
|
|
* |
34
|
|
|
* @var string[] |
35
|
|
|
*/ |
36
|
|
|
const MANAGED_PARAMS = array( |
37
|
|
|
/* @formatter:off */ |
38
|
|
|
RegisteredJWKParameter::PARAM_KEY_TYPE, |
39
|
|
|
RegisteredJWKParameter::PARAM_CURVE, |
40
|
|
|
RegisteredJWKParameter::PARAM_X_COORDINATE, |
41
|
|
|
RegisteredJWKParameter::PARAM_ECC_PRIVATE_KEY |
42
|
|
|
/* @formatter:on */ |
43
|
|
|
); |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* Constructor |
47
|
|
|
* |
48
|
|
|
* @param JWKParameter ...$params |
49
|
|
|
* @throws \UnexpectedValueException If missing required parameter |
50
|
|
|
*/ |
51
|
9 |
View Code Duplication |
public function __construct(JWKParameter ...$params) { |
|
|
|
|
52
|
9 |
|
parent::__construct(...$params); |
53
|
9 |
|
foreach (self::MANAGED_PARAMS as $name) { |
54
|
9 |
|
if (!$this->has($name)) { |
55
|
1 |
|
throw new \UnexpectedValueException("Missing '$name' parameter."); |
56
|
|
|
} |
57
|
8 |
|
} |
58
|
8 |
|
if ($this->keyTypeParameter()->value() != KeyTypeParameter::TYPE_EC) { |
59
|
1 |
|
throw new \UnexpectedValueException("Invalid key type."); |
60
|
|
|
} |
61
|
|
|
// cast ECC private key parameter to correct class |
62
|
7 |
|
$key = RegisteredJWKParameter::PARAM_ECC_PRIVATE_KEY; |
63
|
7 |
|
$this->_parameters[$key] = new ECCPrivateKeyParameter( |
64
|
7 |
|
$this->_parameters[$key]->value()); |
65
|
7 |
|
} |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* Initialize from ECPrivateKey. |
69
|
|
|
* |
70
|
|
|
* @param ECPrivateKey $pk |
71
|
|
|
* @throws \UnexpectedValueException |
72
|
|
|
* @return self |
73
|
|
|
*/ |
74
|
3 |
|
public static function fromECPrivateKey(ECPrivateKey $pk) { |
75
|
3 |
|
if (!$pk->hasNamedCurve()) { |
76
|
1 |
|
throw new \UnexpectedValueException("No curve name."); |
77
|
|
|
} |
78
|
2 |
|
$curve = CurveParameter::fromOID($pk->namedCurve()); |
79
|
2 |
|
$pubkey = $pk->publicKey(); |
80
|
2 |
|
list($x, $y) = $pubkey->curvePointOctets(); |
81
|
2 |
|
$xcoord = XCoordinateParameter::fromString($x); |
82
|
2 |
|
$ycoord = YCoordinateParameter::fromString($y); |
83
|
2 |
|
$priv = ECCPrivateKeyParameter::fromString($pk->privateKeyOctets()); |
84
|
2 |
|
$key_type = new KeyTypeParameter(KeyTypeParameter::TYPE_EC); |
85
|
2 |
|
return new self($key_type, $curve, $xcoord, $ycoord, $priv); |
86
|
|
|
} |
87
|
|
|
|
88
|
|
|
/** |
89
|
|
|
* Initialize from PEM. |
90
|
|
|
* |
91
|
|
|
* @param PEM $pem |
92
|
|
|
* @return self |
93
|
|
|
*/ |
94
|
2 |
|
public static function fromPEM(PEM $pem) { |
95
|
2 |
|
return self::fromECPrivateKey(ECPrivateKey::fromPEM($pem)); |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* Get the public key component of the EC private key. |
100
|
|
|
* |
101
|
|
|
* @return ECPublicKeyJWK |
102
|
|
|
*/ |
103
|
7 |
|
public function publicKey() { |
104
|
7 |
|
$kty = $this->keyTypeParameter(); |
105
|
7 |
|
$curve = $this->curveParameter(); |
106
|
7 |
|
$xcoord = $this->XCoordinateParameter(); |
107
|
7 |
|
$ycoord = $this->YCoordinateParameter(); |
108
|
7 |
|
return new ECPublicKeyJWK($kty, $curve, $xcoord, $ycoord); |
109
|
|
|
} |
110
|
|
|
|
111
|
|
|
/** |
112
|
|
|
* Convert EC private key to PEM. |
113
|
|
|
* |
114
|
|
|
* @return PEM |
115
|
|
|
*/ |
116
|
5 |
|
public function toPEM() { |
117
|
5 |
|
$curve_oid = CurveParameter::nameToOID($this->curveParameter()->value()); |
118
|
5 |
|
$x = ECConversion::octetsToNumber( |
119
|
5 |
|
$this->XCoordinateParameter()->coordinateOctets()); |
120
|
5 |
|
$y = ECConversion::octetsToNumber( |
121
|
5 |
|
$this->YCoordinateParameter()->coordinateOctets()); |
122
|
5 |
|
$pubkey = ECPublicKey::fromCoordinates($x, $y, $curve_oid); |
123
|
5 |
|
$priv = $this->ECCPrivateKeyParameter()->privateKeyOctets(); |
124
|
5 |
|
$ec = new ECPrivateKey($priv, $curve_oid, $pubkey->ECPoint()); |
125
|
5 |
|
return $ec->privateKeyInfo()->toPEM(); |
126
|
|
|
} |
127
|
|
|
} |
128
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.