diff --git a/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php b/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php index 50b6057b..f05eee9d 100644 --- a/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php +++ b/phpseclib/Crypt/Common/Formats/Keys/PKCS8.php @@ -301,6 +301,9 @@ abstract class PKCS8 extends PKCS { $decoded = self::preParse($key); + $isPublic = str_contains($key, 'PUBLIC'); + $isPrivate = str_contains($key, 'PRIVATE'); + $meta = []; $decrypted = ASN1::asn1map($decoded[0], Maps\EncryptedPrivateKeyInfo::MAP); @@ -429,6 +432,10 @@ abstract class PKCS8 extends PKCS $private = ASN1::asn1map($decoded[0], Maps\OneAsymmetricKey::MAP); if (is_array($private)) { + if ($isPublic) { + throw new \UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key'); + } + if (isset($private['privateKeyAlgorithm']['parameters']) && !$private['privateKeyAlgorithm']['parameters'] instanceof ASN1\Element && isset($decoded[0]['content'][1]['content'][1])) { $temp = $decoded[0]['content'][1]['content'][1]; $private['privateKeyAlgorithm']['parameters'] = new ASN1\Element(substr($key, $temp['start'], $temp['length'])); @@ -458,6 +465,10 @@ abstract class PKCS8 extends PKCS $public = ASN1::asn1map($decoded[0], Maps\PublicKeyInfo::MAP); if (is_array($public)) { + if ($isPrivate) { + throw new \UnexpectedValueException('Human readable string claims private key but DER encoded string claims public key'); + } + if ($public['publicKey'][0] != "\0") { throw new UnexpectedValueException('The first byte of the public key should be null - not ' . bin2hex($public['publicKey'][0])); } diff --git a/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php b/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php index b1174bc9..ac0d31cc 100644 --- a/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php +++ b/phpseclib/Crypt/DH/Formats/Keys/PKCS8.php @@ -21,7 +21,6 @@ declare(strict_types=1); namespace phpseclib3\Crypt\DH\Formats\Keys; -use phpseclib3\Common\Functions\Strings; use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; use phpseclib3\Exception\RuntimeException; use phpseclib3\Exception\UnexpectedValueException; @@ -64,23 +63,10 @@ abstract class PKCS8 extends Progenitor */ public static function load($key, ?string $password = null): array { - if (!Strings::is_stringable($key)) { - throw new UnexpectedValueException('Key should be a string - not a ' . gettype($key)); - } - - $isPublic = str_contains($key, 'PUBLIC'); - $key = parent::load($key, $password); $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey'; - switch (true) { - case !$isPublic && $type == 'publicKey': - throw new UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key'); - case $isPublic && $type == 'privateKey': - throw new UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key'); - } - $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element); if (empty($decoded)) { throw new RuntimeException('Unable to decode BER of parameters'); diff --git a/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php b/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php index 1640dadf..7045ca19 100644 --- a/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php +++ b/phpseclib/Crypt/DSA/Formats/Keys/PKCS8.php @@ -25,7 +25,6 @@ declare(strict_types=1); namespace phpseclib3\Crypt\DSA\Formats\Keys; -use phpseclib3\Common\Functions\Strings; use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; use phpseclib3\Exception\RuntimeException; use phpseclib3\Exception\UnexpectedValueException; @@ -68,23 +67,10 @@ abstract class PKCS8 extends Progenitor */ public static function load($key, ?string $password = null): array { - if (!Strings::is_stringable($key)) { - throw new UnexpectedValueException('Key should be a string - not a ' . gettype($key)); - } - - $isPublic = str_contains($key, 'PUBLIC'); - $key = parent::load($key, $password); $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey'; - switch (true) { - case !$isPublic && $type == 'publicKey': - throw new UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key'); - case $isPublic && $type == 'privateKey': - throw new UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key'); - } - $decoded = ASN1::decodeBER($key[$type . 'Algorithm']['parameters']->element); if (!$decoded) { throw new RuntimeException('Unable to decode BER of parameters'); diff --git a/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php b/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php index 633353f5..421c98c8 100644 --- a/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php +++ b/phpseclib/Crypt/EC/Formats/Keys/PKCS8.php @@ -25,7 +25,6 @@ declare(strict_types=1); namespace phpseclib3\Crypt\EC\Formats\Keys; -use phpseclib3\Common\Functions\Strings; use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; use phpseclib3\Crypt\EC\BaseCurves\Base as BaseCurve; use phpseclib3\Crypt\EC\BaseCurves\Montgomery as MontgomeryCurve; @@ -77,23 +76,10 @@ abstract class PKCS8 extends Progenitor // one that's called self::initialize_static_variables(); - if (!Strings::is_stringable($key)) { - throw new UnexpectedValueException('Key should be a string - not a ' . gettype($key)); - } - - $isPublic = str_contains($key, 'PUBLIC'); - $key = parent::load($key, $password); $type = isset($key['privateKey']) ? 'privateKey' : 'publicKey'; - switch (true) { - case !$isPublic && $type == 'publicKey': - throw new UnexpectedValueException('Human readable string claims non-public key but DER encoded string claims public key'); - case $isPublic && $type == 'privateKey': - throw new UnexpectedValueException('Human readable string claims public key but DER encoded string claims private key'); - } - switch ($key[$type . 'Algorithm']['algorithm']) { case 'id-Ed25519': case 'id-Ed448': @@ -112,7 +98,7 @@ abstract class PKCS8 extends Progenitor $components = []; $components['curve'] = self::loadCurveByParam($params); - if ($isPublic) { + if ($type == 'publicKey') { $components['QA'] = self::extractPoint("\0" . $key['publicKey'], $components['curve']); return $components; diff --git a/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php b/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php index 818a5f0e..d8d1b8d1 100644 --- a/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php +++ b/phpseclib/Crypt/RSA/Formats/Keys/PKCS8.php @@ -27,7 +27,6 @@ declare(strict_types=1); namespace phpseclib3\Crypt\RSA\Formats\Keys; -use phpseclib3\Common\Functions\Strings; use phpseclib3\Crypt\Common\Formats\Keys\PKCS8 as Progenitor; use phpseclib3\Exception\UnexpectedValueException; use phpseclib3\File\ASN1; @@ -68,29 +67,13 @@ abstract class PKCS8 extends Progenitor */ public static function load($key, ?string $password = null): array { - if (!Strings::is_stringable($key)) { - throw new UnexpectedValueException('Key should be a string - not a ' . gettype($key)); - } - - if (str_contains($key, 'PUBLIC')) { - $components = ['isPublicKey' => true]; - } elseif (str_contains($key, 'PRIVATE')) { - $components = ['isPublicKey' => false]; - } else { - $components = []; - } - $key = parent::load($key, $password); if (isset($key['privateKey'])) { - if (!isset($components['isPublicKey'])) { - $components['isPublicKey'] = false; - } + $components['isPublicKey'] = false; $type = 'private'; } else { - if (!isset($components['isPublicKey'])) { - $components['isPublicKey'] = true; - } + $components['isPublicKey'] = true; $type = 'public'; } diff --git a/tests/Unit/Crypt/EC/KeyTest.php b/tests/Unit/Crypt/EC/KeyTest.php index dee1dcb8..53ed68ec 100644 --- a/tests/Unit/Crypt/EC/KeyTest.php +++ b/tests/Unit/Crypt/EC/KeyTest.php @@ -17,6 +17,7 @@ use phpseclib3\Crypt\EC\Formats\Keys\PKCS8; use phpseclib3\Crypt\EC\Formats\Keys\PuTTY; use phpseclib3\Crypt\EC\Formats\Keys\XML; use phpseclib3\Crypt\EC\PrivateKey; +use phpseclib3\Crypt\EC\PublicKey; use phpseclib3\Crypt\PublicKeyLoader; use phpseclib3\Tests\PhpseclibTestCase; @@ -672,4 +673,11 @@ MIIEDwIBADATBgcqhkjOPQIBBggqhkjOPQMBBwSCA/MwggPvAgEBBIID6P////// $this->assertTrue($key->verify($plaintext, $sig)); } + + public function testNakedPKCS8PubKey() + { + $key = 'MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAErPJyxEu2/oKCrJaaTVTrq39DKJ2XcN6W+k8UvGf+Y/lDWNbFitQocabsDUvSN0edHH3UKP5QPTz4cOlyIPMrXQ=='; + $key = PublicKeyLoader::load($key); + $this->assertInstanceOf(PublicKey::class, $key); + } }