From 00b6eaf507475ab7797fdca7716f72e80a81be91 Mon Sep 17 00:00:00 2001 From: terrafrost Date: Mon, 29 Apr 2019 21:45:17 -0500 Subject: [PATCH] ECDSA/Keys/PKCS8: correctly convert private keys to public --- phpseclib/Crypt/Common/Keys/PKCS8.php | 8 +++++++- phpseclib/Crypt/ECDSA/Keys/PKCS8.php | 2 +- tests/Unit/Crypt/ECDSA/KeyTest.php | 12 +++++++++++- 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/phpseclib/Crypt/Common/Keys/PKCS8.php b/phpseclib/Crypt/Common/Keys/PKCS8.php index c6b3eae4..73d6eeab 100644 --- a/phpseclib/Crypt/Common/Keys/PKCS8.php +++ b/phpseclib/Crypt/Common/Keys/PKCS8.php @@ -477,6 +477,12 @@ abstract class PKCS8 extends PKCS throw new UnsupportedAlgorithmException('Only ' . static::OID_NAME . ' keys are supported; this is a ' . $private['privateKeyAlgorithm']['algorithm'] . ' key'); } } + if (isset($private['publicKey'])) { + if ($private['publicKey'][0] != "\0") { + throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($val)); + } + $private['publicKey'] = substr($private['publicKey'], 1); + } return $private + $meta; } @@ -488,7 +494,7 @@ abstract class PKCS8 extends PKCS if (is_array($public)) { if ($public['publicKey'][0] != "\0") { - throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . Hex::encode($val)); + throw new \UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($val)); } if (is_array(static::OID_NAME)) { if (!in_array($public['publicKeyAlgorithm']['algorithm'], static::OID_NAME)) { diff --git a/phpseclib/Crypt/ECDSA/Keys/PKCS8.php b/phpseclib/Crypt/ECDSA/Keys/PKCS8.php index 89f31671..3306e066 100644 --- a/phpseclib/Crypt/ECDSA/Keys/PKCS8.php +++ b/phpseclib/Crypt/ECDSA/Keys/PKCS8.php @@ -153,7 +153,7 @@ abstract class PKCS8 extends Progenitor $components['curve'] = $key['publicKeyAlgorithm']['algorithm'] == 'id-Ed25519' ? new Ed25519() : new Ed448(); } - $components['QA'] = self::extractPoint(substr($key['publicKey'], 1), $components['curve']); + $components['QA'] = self::extractPoint($key['publicKey'], $components['curve']); } if (isset($key['privateKey']) && !isset($components['QA'])) { diff --git a/tests/Unit/Crypt/ECDSA/KeyTest.php b/tests/Unit/Crypt/ECDSA/KeyTest.php index a47117a4..47fbbc2c 100644 --- a/tests/Unit/Crypt/ECDSA/KeyTest.php +++ b/tests/Unit/Crypt/ECDSA/KeyTest.php @@ -238,7 +238,7 @@ MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= // https://security.stackexchange.com/q/110330/15922 elaborates on // why phpseclib is encoding the NULL as opposed to omitting it. $expected = '-----BEGIN PUBLIC KEY----- -MCwwBwYDK2VwBQADIQC/RAlphM3+hUG6wWfcO5bIUIaqMLa2ywxcOK1wMWZhgA== +MCwwBwYDK2VwBQADIQAZv0QJaYTN/oVBusFn3DuWyFCGqjC2tssMXDitcDFm4Q== -----END PUBLIC KEY-----'; $this->assertSame($expected, $key->getPublicKey('PKCS8')); } @@ -459,6 +459,16 @@ pomV7r6gmoMYteGVABfgAAAAD3ZhZ3JhbnRAdmFncmFudAECAwQFBg== $this->assertSame($expected, $actual); } + public function testToPublicKey() + { + $key = new ECDSA; + $key->load('-----BEGIN PRIVATE KEY----- +MFICAQEwBwYDK2VwBQAEIgQgS5tTLrcNRaml4g5CgGeMvptuXuSrcrFbl+zVSxHD +H76BIDXmiVv2hLjr5MhZENlKIuz0ak1hUO8MdZ2vgY/nGcUV +-----END PRIVATE KEY-----'); + $this->assertInternalType('string', (string) $key->getPublicKey()); + } + public static function assertSame($expected, $actual, $message = '') { $expected = str_replace("\r\n", "\n", $expected);