diff --git a/src/KeyConverter/ECKey.php b/src/KeyConverter/ECKey.php index ed2e7a8d..eed78143 100644 --- a/src/KeyConverter/ECKey.php +++ b/src/KeyConverter/ECKey.php @@ -67,8 +67,11 @@ private function loadPEM($data) $asnObject = Object::fromBinary($data); Assertion::isInstanceOf($asnObject, Sequence::class); - $children = $asnObject->getChildren(); + if (self::isPKCS8($children)) { + $children = self::loadPKCS8($children); + } + if (4 === count($children)) { return $this->loadPrivatePEM($children); } elseif (2 === count($children)) { @@ -77,6 +80,41 @@ private function loadPEM($data) throw new \Exception('Unable to load the key'); } + /** + * @param array $children + * + * @return array + */ + private function loadPKCS8(array $children) + { + $binary = hex2bin($children[2]->getContent()); + $asnObject = Object::fromBinary($binary); + Assertion::isInstanceOf($asnObject, Sequence::class); + + return $asnObject->getChildren(); + } + + /** + * @param array $children + * + * @return bool + */ + private function isPKCS8(array $children) + { + if (3 !== count($children)) { + return false; + } + + $classes = [0 => Integer::class, 1 => Sequence::class, 2 => OctetString::class]; + foreach ($classes as $k => $class) { + if (!$children[$k] instanceof $class) { + return false; + } + } + + return true; + } + /** * @param array $jwk */ @@ -202,7 +240,6 @@ private function getD(Object $children) private function loadPrivatePEM(array $children) { $this->verifyVersion($children[0]); - $x = null; $y = null; $d = $this->getD($children[1]); diff --git a/src/KeyConverter/KeyConverter.php b/src/KeyConverter/KeyConverter.php index 46c245d7..0056835b 100644 --- a/src/KeyConverter/KeyConverter.php +++ b/src/KeyConverter/KeyConverter.php @@ -149,6 +149,8 @@ private static function loadKeyFromPEM($pem, $password = null) $pem = self::decodePem($pem, $matches, $password); } + self::sanitizePEM($pem); + $res = openssl_pkey_get_private($pem); if ($res === false) { $res = openssl_pkey_get_public($pem); @@ -173,6 +175,21 @@ private static function loadKeyFromPEM($pem, $password = null) } } + /** + * This method modify the PEM to get 64 char lines and fix bug with old OpenSSL versions. + * + * @param string $pem + */ + private static function sanitizePEM(&$pem) + { + preg_match_all('#(-.*-)#', $pem, $matches, PREG_PATTERN_ORDER); + $ciphertext = preg_replace('#-.*-|\r|\n| #', '', $pem); + + $pem = $matches[0][0].PHP_EOL; + $pem .= chunk_split($ciphertext, 64, PHP_EOL); + $pem .= $matches[0][1].PHP_EOL; + } + /** * @param array $x5c * diff --git a/tests/Unit/Keys/EC/private.es256.from.APN.key b/tests/Unit/Keys/EC/private.es256.from.APN.key new file mode 100644 index 00000000..13f64021 --- /dev/null +++ b/tests/Unit/Keys/EC/private.es256.from.APN.key @@ -0,0 +1,3 @@ +-----BEGIN PRIVATE KEY----- +MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg13n3isfsEktzl+CtH5ECpRrKk+40prVuCbldkP77gamgCgYIKoZIzj0DAQehRANCAARhwgxSRqXBt54BWRQXoU/doFWULOWrER3uLS43/iugDW1PMDliQZEzWetYAdf+Mafq/PrlbEAfA+l7JfmijAsv +-----END PRIVATE KEY----- diff --git a/tests/Unit/Keys/ECKeysTest.php b/tests/Unit/Keys/ECKeysTest.php index 989eaf66..b52b0007 100644 --- a/tests/Unit/Keys/ECKeysTest.php +++ b/tests/Unit/Keys/ECKeysTest.php @@ -29,6 +29,23 @@ public function testKeyTypeNotSupported() KeyConverter::loadFromKeyFile($file); } + /** + * @see https://github.com/Spomky-Labs/jose/issues/141 + * @see https://gist.github.com/Spomky/246eca6aaeeb7a40f11d3a2d98960282 + */ + public function testLoadPrivateEC256KeyGenerateByAPN() + { + $pem = file_get_contents('file://'.__DIR__.DIRECTORY_SEPARATOR.'EC'.DIRECTORY_SEPARATOR.'private.es256.from.APN.key'); + $details = KeyConverter::loadFromKey($pem); + $this->assertEquals($details, [ + 'kty' => 'EC', + 'crv' => 'P-256', + 'd' => '13n3isfsEktzl-CtH5ECpRrKk-40prVuCbldkP77gak', + 'x' => 'YcIMUkalwbeeAVkUF6FP3aBVlCzlqxEd7i0uN_4roA0', + 'y' => 'bU8wOWJBkTNZ61gB1_4xp-r8-uVsQB8D6Xsl-aKMCy8', + ]); + } + public function testLoadPublicEC256Key() { $pem = file_get_contents('file://'.__DIR__.DIRECTORY_SEPARATOR.'EC'.DIRECTORY_SEPARATOR.'public.es256.key'); @@ -38,7 +55,6 @@ public function testLoadPublicEC256Key() 'crv' => 'P-256', 'x' => 'vuYsP-QnrqAbM7Iyhzjt08hFSuzapyojCB_gFsBt65U', 'y' => 'oq-E2K-X0kPeqGuKnhlXkxc5fnxomRSC6KLby7Ij8AE', - ]); $ec_key = new ECKey($details);