From 370fbec300554b42de3b259c01620c19afa99fbf Mon Sep 17 00:00:00 2001 From: terrafrost Date: Mon, 28 Nov 2016 18:50:21 -0600 Subject: [PATCH] ASN1: don't require octet / bit strings be base64-encoded --- phpseclib/Crypt/Common/PKCS8.php | 29 ++++++++++++++--------------- phpseclib/Crypt/RSA.php | 2 +- phpseclib/File/ASN1.php | 4 ++-- phpseclib/File/X509.php | 31 +++++++++++++------------------ tests/Unit/File/X509/X509Test.php | 2 +- 5 files changed, 31 insertions(+), 37 deletions(-) diff --git a/phpseclib/Crypt/Common/PKCS8.php b/phpseclib/Crypt/Common/PKCS8.php index a06baca0..0b193fc3 100644 --- a/phpseclib/Crypt/Common/PKCS8.php +++ b/phpseclib/Crypt/Common/PKCS8.php @@ -368,8 +368,8 @@ class PKCS8 extends PKCS $temp = ASN1::decodeBER($decrypted['encryptionAlgorithm']['parameters']); extract(ASN1::asn1map($temp[0], Maps\PBEParameter::MAP)); $iterationCount = (int) $iterationCount->toString(); - $cipher->setPassword($password, $kdf, $hash, Base64::decode($salt), $iterationCount); - $key = $cipher->decrypt(Base64::decode($decrypted['encryptedData'])); + $cipher->setPassword($password, $kdf, $hash, $salt, $iterationCount); + $key = $cipher->decrypt($decrypted['encryptedData']); $decoded = ASN1::decodeBER($key); if (empty($decoded)) { return false; @@ -391,7 +391,7 @@ class PKCS8 extends PKCS extract($temp); if (!$cipher instanceof RC2) { - $cipher->setIV(Base64::decode($encryptionScheme['parameters']['octetString'])); + $cipher->setIV($encryptionScheme['parameters']['octetString']); } else { $temp = ASN1::decodeBER($encryptionScheme['parameters']); extract(ASN1::asn1map($temp[0], Maps\RC2CBCParameter::MAP)); @@ -408,7 +408,7 @@ class PKCS8 extends PKCS break; //default: // should be >= 256 } - $cipher->setIV(Base64::decode($iv)); + $cipher->setIV($iv); $cipher->setKeyLength($effectiveKeyLength); } @@ -425,14 +425,14 @@ class PKCS8 extends PKCS $password, 'pbkdf2', $hash, - Base64::decode($salt), + $salt, (int) $iterationCount->toString() ]; if (isset($keyLength)) { $params[] = (int) $keyLength->toString(); } call_user_func_array([$cipher, 'setPassword'], $params); - $key = $cipher->decrypt(Base64::decode($decrypted['encryptedData'])); + $key = $cipher->decrypt($decrypted['encryptedData']); $decoded = ASN1::decodeBER($key); if (empty($decoded)) { return false; @@ -462,11 +462,10 @@ class PKCS8 extends PKCS // bit strings wanting a non-zero amount of bits trimmed are not supported $public = ASN1::asn1map($decoded[0], Maps\PublicKeyInfo::MAP); if (is_array($public)) { - $public['publicKey'] = base64_decode($public['publicKey']); if ($public['publicKey'][0] != "\0") { return false; } - $public['publicKey'] = base64_encode(substr($public['publicKey'], 1)); + $public['publicKey'] = substr($public['publicKey'], 1); return $public; } @@ -490,7 +489,7 @@ class PKCS8 extends PKCS $key = [ 'version' => 'v1', 'privateKeyAlgorithm' => ['algorithm' => $algorithm], // parameters are not currently supported - 'privateKey' => Base64::encode($key) + 'privateKey' => $key ]; if (!empty($attr)) { $key['attributes'] = $attr; @@ -507,18 +506,18 @@ class PKCS8 extends PKCS $iv = Random::string($crypto->getBlockLength() >> 3); $PBKDF2params = [ - 'salt' => Base64::encode($salt), + 'salt' => $salt, 'iterationCount' => $iterationCount, 'prf' => ['algorithm' => self::$defaultPRF, 'parameters' => null] ]; $PBKDF2params = ASN1::encodeDER($PBKDF2params, Maps\PBKDF2params::MAP); if (!$crypto instanceof RC2) { - $params = ['octetString' => Base64::encode($iv)]; + $params = ['octetString' => $iv]; } else { $params = [ 'rc2ParametersVersion' => 58, - 'iv' => Base64::encode($iv) + 'iv' => $iv ]; $params = ASN1::encodeDER($params, Maps\RC2CBCParameter::MAP); $params = new ASN1\Element($params); @@ -543,7 +542,7 @@ class PKCS8 extends PKCS $kdf = self::getPBES1KDF(self::$defaultEncryptionAlgorithm); $params = [ - 'salt' => Base64::encode($salt), + 'salt' => $salt, 'iterationCount' => $iterationCount ]; $params = ASN1::encodeDER($params, Maps\PBEParameter::MAP); @@ -556,7 +555,7 @@ class PKCS8 extends PKCS 'algorithm' => self::$defaultEncryptionAlgorithm, 'parameters' => new ASN1\Element($params) ], - 'encryptedData' => Base64::encode($key) + 'encryptedData' => $key ]; $key = ASN1::encodeDER($key, Maps\EncryptedPrivateKeyInfo::MAP); @@ -587,7 +586,7 @@ class PKCS8 extends PKCS 'algorithm' => $algorithm, 'parameters' => null // parameters are not currently supported ], - 'publicKey' => Base64::encode("\0" . $key) + 'publicKey' => "\0" . $key ]; $key = ASN1::encodeDER($key, Maps\PublicKeyInfo::MAP); diff --git a/phpseclib/Crypt/RSA.php b/phpseclib/Crypt/RSA.php index 67d26cbf..506c3443 100644 --- a/phpseclib/Crypt/RSA.php +++ b/phpseclib/Crypt/RSA.php @@ -2051,7 +2051,7 @@ class RSA $hash; $hash = new Hash($hash); $em = $hash->hash($m); - $em2 = Base64::decode($decoded['digest']); + $em2 = $decoded['digest']; return self::_equals($em, $em2); } diff --git a/phpseclib/File/ASN1.php b/phpseclib/File/ASN1.php index 22db5cd3..5d13ba01 100644 --- a/phpseclib/File/ASN1.php +++ b/phpseclib/File/ASN1.php @@ -793,7 +793,7 @@ class ASN1 return $values; } case self::TYPE_OCTET_STRING: - return Base64::encode($decoded['content']); + return $decoded['content']; case self::TYPE_NULL: return ''; case self::TYPE_BOOLEAN: @@ -1051,7 +1051,7 @@ class ASN1 the number of unused bits in the final subsequent octet. The number shall be in the range zero to seven. -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#page=16 */ - $value = Base64::decode($source); + $value = $source; break; case self::TYPE_OBJECT_IDENTIFIER: if (!preg_match('#(?:\d+\.)+#', $source)) { diff --git a/phpseclib/File/X509.php b/phpseclib/File/X509.php index 2692e417..ba766b3f 100644 --- a/phpseclib/File/X509.php +++ b/phpseclib/File/X509.php @@ -583,7 +583,6 @@ class X509 for ($i = 0; $i < count($extensions); $i++) { $id = $extensions[$i]['extnId']; $value = &$extensions[$i]['extnValue']; - $value = Base64::decode($value); $decoded = ASN1::decodeBER($value); /* [extnValue] contains the DER encoding of an ASN.1 value corresponding to the extension type identified by extnID */ @@ -609,8 +608,6 @@ class X509 } } } - } else { - $value = Base64::encode($value); } } } @@ -674,8 +671,7 @@ class X509 unset($extensions[$i]); } } else { - $temp = ASN1::encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP'))); - $value = Base64::encode($temp); + $value = ASN1::encodeDER($value, $map, array('iPAddress' => array($this, '_encodeIP'))); } } } @@ -713,7 +709,7 @@ class X509 $this->_mapInExtensions($values, $j); } } elseif ($map) { - $values[$j] = Base64::encode($value); + $values[$j] = $value; } } } @@ -1149,7 +1145,7 @@ class X509 $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], - substr(Base64::decode($this->currentCert['signature']), 1), + substr($this->currentCert['signature'], 1), $this->signatureSubject ); case isset($this->currentCert['certificationRequestInfo']): @@ -1157,7 +1153,7 @@ class X509 $this->currentCert['certificationRequestInfo']['subjectPKInfo']['algorithm']['algorithm'], $this->currentCert['certificationRequestInfo']['subjectPKInfo']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], - substr(Base64::decode($this->currentCert['signature']), 1), + substr($this->currentCert['signature'], 1), $this->signatureSubject ); case isset($this->currentCert['publicKeyAndChallenge']): @@ -1165,7 +1161,7 @@ class X509 $this->currentCert['publicKeyAndChallenge']['spki']['algorithm']['algorithm'], $this->currentCert['publicKeyAndChallenge']['spki']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], - substr(Base64::decode($this->currentCert['signature']), 1), + substr($this->currentCert['signature'], 1), $this->signatureSubject ); case isset($this->currentCert['tbsCertList']): @@ -1193,7 +1189,7 @@ class X509 $signingCert['tbsCertificate']['subjectPublicKeyInfo']['algorithm']['algorithm'], $signingCert['tbsCertificate']['subjectPublicKeyInfo']['subjectPublicKey'], $this->currentCert['signatureAlgorithm']['algorithm'], - substr(Base64::decode($this->currentCert['signature']), 1), + substr($this->currentCert['signature'], 1), $this->signatureSubject ); default: @@ -1266,7 +1262,7 @@ class X509 // subjectPublicKey is stored as a bit string in X.509 certs. the first byte of a bit string represents how many bits // in the last byte should be ignored. the following only supports non-zero stuff but as none of the X.509 certs Firefox // uses as a cert authority actually use a non-zero bit I think it's safe to assume that none do. - chunk_split(Base64::encode(substr(Base64::decode($key), 1)), 64) . + chunk_split(Base64::encode(substr($key, 1)), 64) . '-----END RSA PUBLIC KEY-----'; default: return $key; @@ -1284,7 +1280,7 @@ class X509 */ function _decodeIP($ip) { - return inet_ntop(Base64::decode($ip)); + return inet_ntop($ip); } /** @@ -1298,7 +1294,7 @@ class X509 */ function _encodeIP($ip) { - return Base64::encode(inet_pton($ip)); + return inet_pton($ip); } /** @@ -2464,7 +2460,7 @@ class X509 ); if (!isset($subject->currentKeyIdentifier)) { - $this->setExtension('id-ce-subjectKeyIdentifier', Base64::encode($this->computeKeyIdentifier($this->currentCert)), false, false); + $this->setExtension('id-ce-subjectKeyIdentifier', $this->computeKeyIdentifier($this->currentCert), false, false); } } @@ -2759,7 +2755,7 @@ class X509 case 'sha512WithRSAEncryption': $key->setHash(preg_replace('#WithRSAEncryption$#', '', $signatureAlgorithm)); - $this->currentCert['signature'] = Base64::encode("\0" . $key->sign($this->signatureSubject, RSA::PADDING_PKCS1)); + $this->currentCert['signature'] = "\0" . $key->sign($this->signatureSubject, RSA::PADDING_PKCS1); return $this->currentCert; default: throw new UnsupportedAlgorithmException('Signature algorithm unsupported'); @@ -3339,7 +3335,7 @@ class X509 if (empty($value)) { unset($this->currentKeyIdentifier); } else { - $this->currentKeyIdentifier = Base64::encode($value); + $this->currentKeyIdentifier = $value; } } @@ -3386,7 +3382,6 @@ class X509 if (empty($raw)) { return false; } - $raw = Base64::decode($raw); // If the key is private, compute identifier from its corresponding public key. $key = new RSA(); if (!$key->load($raw)) { @@ -3439,7 +3434,7 @@ class X509 if ($this->publicKey instanceof RSA) { // the following two return statements do the same thing. i dunno.. i just prefer the later for some reason. // the former is a good example of how to do fuzzing on the public key - //return new Element(Base64::decode(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey()))); + //return new Element(preg_replace('#-.+-|[\r\n]#', '', $this->publicKey->getPublicKey())); return array( 'algorithm' => array('algorithm' => 'rsaEncryption'), 'subjectPublicKey' => $this->publicKey->getPublicKey('PKCS1') diff --git a/tests/Unit/File/X509/X509Test.php b/tests/Unit/File/X509/X509Test.php index ae97e7d3..5e64fdae 100644 --- a/tests/Unit/File/X509/X509Test.php +++ b/tests/Unit/File/X509/X509Test.php @@ -107,7 +107,7 @@ k6m17mi63YW/+iPCGOWZ2qXmY5HPEyyF2L4L4IDryFJ+8xLyw3pH9/yp5aHZDtp6 $cert = $x509->loadX509($test); - $this->assertEquals('MDUwDgYIKoZIhvcNAwICAgCAMA4GCCqGSIb3DQMEAgIAgDAHBgUrDgMCBzAKBggqhkiG9w0DBw==', $cert['tbsCertificate']['extensions'][8]['extnValue']); + $this->assertEquals(base64_decode('MDUwDgYIKoZIhvcNAwICAgCAMA4GCCqGSIb3DQMEAgIAgDAHBgUrDgMCBzAKBggqhkiG9w0DBw=='), $cert['tbsCertificate']['extensions'][8]['extnValue']); } public function testSaveUnsupportedExtension()