From e2c75b97a9a71ee4f88cf0d9736c0ac6a2ce23e1 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 11 May 2020 20:37:42 +0200 Subject: [PATCH 1/8] Add test-framework --- .gitignore | 1 + .php_cs.dist | 15 ++++ .travis.yml | 154 +++++++++++++++++++++++++++++++++------- bin/check-syntax-php.sh | 20 ++++++ codecov.yml | 11 +++ composer.json | 42 ++++++----- phpcs.xml | 29 ++++++++ phpunit.xml | 27 +++++++ psalm.xml | 57 +++++++++++++++ tests/bootstrap.php | 6 ++ 10 files changed, 319 insertions(+), 43 deletions(-) create mode 100644 .php_cs.dist create mode 100755 bin/check-syntax-php.sh create mode 100644 codecov.yml create mode 100644 phpcs.xml create mode 100644 phpunit.xml create mode 100644 psalm.xml create mode 100644 tests/bootstrap.php diff --git a/.gitignore b/.gitignore index 8dd8b490..c1bed8df 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.phpunit.result.cache composer.lock tests/sign-c14-comments.xml tests/sign-empty-uri.xml diff --git a/.php_cs.dist b/.php_cs.dist new file mode 100644 index 00000000..f4e83562 --- /dev/null +++ b/.php_cs.dist @@ -0,0 +1,15 @@ +in([ + __DIR__ . '/src', + __DIR__ . '/tests', + ]) +; + +return PhpCsFixer\Config::create() + ->setRules([ + '@PSR12' => true, + ]) + ->setFinder($finder) +; diff --git a/.travis.yml b/.travis.yml index e372b46e..1fe39008 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,30 +1,134 @@ -sudo: false +sudo: required language: php -matrix: +# Stage order +stages: + - pre-conditions + - test + - quality + + +################ +# Test stage # +################ + +php: + - 7.1 + - 7.2 + - 7.3 + - 7.4 + +#env: +# - COMMAND="composer install" +# - COMMAND="composer update" +# +#before_script: +# - ${COMMAND} +# +# This library has no secondary dependencies, thus testing with composer update is useless + +before_script: + - composer install + +script: + - php vendor/bin/phpunit tests --no-coverage + +jobs: fast_finish: true - include: - - php: 5.4 - dist: trusty - - php: 5.5 - dist: trusty - - php: 5.6 - - php: 7.0.27 - dist: trusty - - php: 7.1 - dist: trusty - - php: 7.2 - - php: 7.3 - - php: 7.4 - env: - - EXECUTE_COVERAGE=true allow_failures: - - php: hhvm - -script: - - if [[ $EXECUTE_COVERAGE == 'true' ]]; then phpunit --coverage-clover clover.xml tests; fi - - if [[ $EXECUTE_COVERAGE != 'true' ]]; then phpunit tests; fi - -after_success: - - if [[ $EXECUTE_COVERAGE == 'true' ]]; then bash <(curl -s https://codecov.io/bash); fi + - php: 7.3 + env: Psalm + - php: 7.3 + env: Security check (composer install) +# +# This library has no secondary dependencies, thus testing with composer update is useless +# - php: 7.3 +# env: Security check (composer update) + - php: 7.3 + env: PHP Codesniffer + + include: + + ########################## + # Pre-conditions stage # + ########################## + + - stage: pre-conditions + php: 7.1 + env: Syntax check PHP + before_script: + - composer install + script: + - bin/check-syntax-php.sh + + - stage: pre-conditions + php: 7.2 + env: Syntax check PHP + before_script: + - composer install + script: + - bin/check-syntax-php.sh + + - stage: pre-conditions + php: 7.3 + env: Syntax check PHP + before_script: + - composer install + script: + - bin/check-syntax-php.sh + + - stage: pre-conditions + php: 7.4 + env: Syntax check PHP + before_script: + - composer install + script: + - bin/check-syntax-php.sh + + + ################### + # Quality stage # + ################### + + - stage: quality + php: 7.3 + env: Security check (composer install) + before_script: + - composer install + script: + - vendor/bin/security-checker security:check + + - stage: quality + php: 7.3 + env: Security check (composer update) + before_script: + - composer update + script: + - vendor/bin/security-checker security:check + + - stage: quality + php: 7.3 + env: Codecov + before_script: + - composer update + - php vendor/bin/phpunit tests + script: + - bash <(curl -s https://codecov.io/bash) + + - stage: quality + php: 7.3 + env: Psalm + before_script: + - composer update + script: + - vendor/bin/psalm + - vendor/bin/psalter --issues=UnnecessaryVarAnnotation --dry-run + + - stage: quality + php: 7.3 + env: PHP Codesniffer + before_script: + - composer update + script: + - vendor/bin/phpcs diff --git a/bin/check-syntax-php.sh b/bin/check-syntax-php.sh new file mode 100755 index 00000000..b2fdfa5c --- /dev/null +++ b/bin/check-syntax-php.sh @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +shopt -s globstar + +PHP='/usr/bin/env php' +RETURN=0 + +for i in `find . -path ./vendor -prune -o -name '*.php' -print` +do + if [ -f "$i" ]; then + FILE="${i%/*}/${i##*/}" + if ! $PHP -l "$FILE" > /dev/null 2>&1 + then + echo "Syntax check failed for ${FILE}" + RETURN=$((RETURN + 1)) + fi + fi +done + +exit "$RETURN" diff --git a/codecov.yml b/codecov.yml new file mode 100644 index 00000000..cbe65108 --- /dev/null +++ b/codecov.yml @@ -0,0 +1,11 @@ +coverage: + status: + project: yes + patch: off +comment: + layout: "diff" + behavior: once + require_changes: true + require_base: no + require_head: yes + branches: null diff --git a/composer.json b/composer.json index 22ce7a3e..dde4f240 100644 --- a/composer.json +++ b/composer.json @@ -1,21 +1,27 @@ { - "name": "robrichards/xmlseclibs", - "description": "A PHP library for XML Security", - "license": "BSD-3-Clause", - "keywords": [ - "xml", - "xmldsig", - "signature", - "security" - ], - "homepage": "https://github.com/robrichards/xmlseclibs", - "autoload": { - "psr-4": { - "RobRichards\\XMLSecLibs\\": "src" + "name": "robrichards/xmlseclibs", + "description": "A PHP library for XML Security", + "license": "BSD-3-Clause", + "keywords": [ + "xml", + "xmldsig", + "signature", + "security" + ], + "homepage": "https://github.com/robrichards/xmlseclibs", + "autoload": { + "psr-4": { + "RobRichards\\XMLSecLibs\\": "src" + } + }, + "require": { + "php": ">= 7.1", + "ext-openssl": "*" + }, + "require-dev": { + "phpunit/phpunit": "^7.5|^8.5", + "vimeo/psalm": "^3.11", + "sensiolabs/security-checker": "^6.0", + "squizlabs/php_codesniffer": "^3.5" } - }, - "require": { - "php": ">= 5.4", - "ext-openssl": "*" - } } diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 00000000..0b71fc02 --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,29 @@ + + + + + + By default it is less stringent about long lines than other coding standards + + + bin + src + tests + + + + + + + + + + + + + + + bin/* + + + diff --git a/phpunit.xml b/phpunit.xml new file mode 100644 index 00000000..22ea6b93 --- /dev/null +++ b/phpunit.xml @@ -0,0 +1,27 @@ + + + + + ./tests + + + + + ./src/ + ./tests/ + + + + + + + + diff --git a/psalm.xml b/psalm.xml new file mode 100644 index 00000000..2455c547 --- /dev/null +++ b/psalm.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/bootstrap.php b/tests/bootstrap.php new file mode 100644 index 00000000..28c24135 --- /dev/null +++ b/tests/bootstrap.php @@ -0,0 +1,6 @@ + Date: Mon, 11 May 2020 21:05:54 +0200 Subject: [PATCH 2/8] Set visibility on constants --- src/Utils/XPath.php | 14 +++++++------- src/XMLSecEnc.php | 10 +++++----- src/XMLSecurityDSig.php | 28 ++++++++++++++-------------- src/XMLSecurityKey.php | 32 ++++++++++++++++---------------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/Utils/XPath.php b/src/Utils/XPath.php index 8cdc48e1..a68c7756 100644 --- a/src/Utils/XPath.php +++ b/src/Utils/XPath.php @@ -4,14 +4,14 @@ class XPath { - const ALPHANUMERIC = '\w\d'; - const NUMERIC = '\d'; - const LETTERS = '\w'; - const EXTENDED_ALPHANUMERIC = '\w\d\s\-_:\.'; + public const ALPHANUMERIC = '\w\d'; + public const NUMERIC = '\d'; + public const LETTERS = '\w'; + public const EXTENDED_ALPHANUMERIC = '\w\d\s\-_:\.'; - const SINGLE_QUOTE = '\''; - const DOUBLE_QUOTE = '"'; - const ALL_QUOTES = '[\'"]'; + public const SINGLE_QUOTE = '\''; + public const DOUBLE_QUOTE = '"'; + public const ALL_QUOTES = '[\'"]'; /** diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php index b9df7611..09647da4 100644 --- a/src/XMLSecEnc.php +++ b/src/XMLSecEnc.php @@ -50,16 +50,16 @@ class XMLSecEnc { - const template = " + private const template = " "; - const Element = 'http://www.w3.org/2001/04/xmlenc#Element'; - const Content = 'http://www.w3.org/2001/04/xmlenc#Content'; - const URI = 3; - const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#'; + public const Element = 'http://www.w3.org/2001/04/xmlenc#Element'; + public const Content = 'http://www.w3.org/2001/04/xmlenc#Content'; + public const URI = 3; + public const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#'; /** @var null|DOMDocument */ private $encdoc = null; diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php index 9986123e..389f8adb 100644 --- a/src/XMLSecurityDSig.php +++ b/src/XMLSecurityDSig.php @@ -50,25 +50,25 @@ class XMLSecurityDSig { - const XMLDSIGNS = 'http://www.w3.org/2000/09/xmldsig#'; - const SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1'; - const SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'; - const SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#sha384'; - const SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'; - const RIPEMD160 = 'http://www.w3.org/2001/04/xmlenc#ripemd160'; - - const C14N = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; - const C14N_COMMENTS = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments'; - const EXC_C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#'; - const EXC_C14N_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments'; - - const template = ' + public const XMLDSIGNS = 'http://www.w3.org/2000/09/xmldsig#'; + public const SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1'; + public const SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'; + public const SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#sha384'; + public const SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'; + public const RIPEMD160 = 'http://www.w3.org/2001/04/xmlenc#ripemd160'; + + public const C14N = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; + public const C14N_COMMENTS = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments'; + public const EXC_C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#'; + public const EXC_C14N_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments'; + + private const template = ' '; - const BASE_TEMPLATE = ' + private const BASE_TEMPLATE = ' diff --git a/src/XMLSecurityKey.php b/src/XMLSecurityKey.php index 90665c95..e2506e49 100644 --- a/src/XMLSecurityKey.php +++ b/src/XMLSecurityKey.php @@ -46,22 +46,22 @@ class XMLSecurityKey { - const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'; - const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; - const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; - const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; - const AES128_GCM = 'http://www.w3.org/2009/xmlenc11#aes128-gcm'; - const AES192_GCM = 'http://www.w3.org/2009/xmlenc11#aes192-gcm'; - const AES256_GCM = 'http://www.w3.org/2009/xmlenc11#aes256-gcm'; - const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; - const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; - const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'; - const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; - const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; - const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'; - const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'; - const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1'; - const AUTHTAG_LENGTH = 16; + public const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'; + public const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; + public const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; + public const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; + public const AES128_GCM = 'http://www.w3.org/2009/xmlenc11#aes128-gcm'; + public const AES192_GCM = 'http://www.w3.org/2009/xmlenc11#aes192-gcm'; + public const AES256_GCM = 'http://www.w3.org/2009/xmlenc11#aes256-gcm'; + public const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; + public const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; + public const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'; + public const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; + public const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; + public const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'; + public const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'; + public const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1'; + public const AUTHTAG_LENGTH = 16; /** @var array */ private $cryptParams = array(); From a189989b978ac9dadf3c8756f990be53adc371d8 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 11 May 2020 22:00:08 +0200 Subject: [PATCH 3/8] PSR-12 compliancy --- src/Utils/XPath.php | 4 +- src/XMLSecEnc.php | 73 ++++--- src/XMLSecurityDSig.php | 215 +++++++++++--------- src/XMLSecurityKey.php | 126 +++++++----- tests/encrypteddata-node-order.phpt | 12 +- tests/retrievalmethod-findkey.phpt | 2 +- tests/sign-c14-comments.phpt | 2 +- tests/sign-empty-uri.phpt | 4 +- tests/sign-hhvm-id-wout-ns-regenerated.phpt | 2 +- tests/thumbprint.phpt | 4 +- tests/validate_digest_sha512.phpt | 4 +- tests/withcomment-empty-uri.phpt | 4 +- tests/withcomment-id-uri-object.phpt | 6 +- tests/withcomment-id-uri.phpt | 4 +- tests/xml-sign-prefix.phpt | 2 +- tests/xml-sign-sha256-rsa-sha256.phpt | 2 +- tests/xml-sign-subject.phpt | 4 +- tests/xml-sign.phpt | 2 +- tests/xmlsec-decrypt-content.phpt | 26 +-- tests/xmlsec-decrypt.phpt | 28 +-- tests/xmlsec-encrypt-aes-gmc.phpt | 2 +- tests/xmlsec-encrypt-content.phpt | 4 +- tests/xmlsec-encrypt-noreplace.phpt | 8 +- tests/xmlsec-encrypt.phpt | 4 +- tests/xmlsec-verify-formatted.phpt | 14 +- tests/xmlsec-verify-rsa-sha256.phpt | 14 +- tests/xmlsec-verify.phpt | 14 +- 27 files changed, 329 insertions(+), 257 deletions(-) mode change 100755 => 100644 tests/xmlsec-decrypt.phpt diff --git a/src/Utils/XPath.php b/src/Utils/XPath.php index a68c7756..890aaa45 100644 --- a/src/Utils/XPath.php +++ b/src/Utils/XPath.php @@ -24,7 +24,7 @@ class XPath */ public static function filterAttrValue($value, $quotes = self::ALL_QUOTES) { - return preg_replace('#'.$quotes.'#', '', $value); + return preg_replace('#' . $quotes . '#', '', $value); } @@ -39,6 +39,6 @@ public static function filterAttrValue($value, $quotes = self::ALL_QUOTES) */ public static function filterAttrName($name, $allow = self::EXTENDED_ALPHANUMERIC) { - return preg_replace('#[^'.$allow.']#', '', $name); + return preg_replace('#[^' . $allow . ']#', '', $name); } } diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php index 09647da4..1e31453d 100644 --- a/src/XMLSecEnc.php +++ b/src/XMLSecEnc.php @@ -1,4 +1,5 @@ encdoc; @@ -120,7 +121,7 @@ public function setNode($node) * Encrypt the selected node with the given key. * * @param XMLSecurityKey $objKey The encryption key and algorithm. - * @param bool $replace Whether the encrypted node should be replaced in the original tree. Default is true. + * @param bool $replace Whether the encrypted node should be replaced in the original tree. Default is true. * @throws Exception * * @return DOMElement The -element. @@ -131,7 +132,7 @@ public function encryptNode($objKey, $replace = true) if (empty($this->rawNode)) { throw new Exception('Node to encrypt has not been set'); } - if (! $objKey instanceof XMLSecurityKey) { + if (!($objKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); } $doc = $this->rawNode->ownerDocument; @@ -148,7 +149,7 @@ public function encryptNode($objKey, $replace = true) break; case (self::Content): $children = $this->rawNode->childNodes; - foreach ($children AS $child) { + foreach ($children as $child) { $data .= $doc->saveXML($child); } $this->encdoc->documentElement->setAttribute('Type', self::Content); @@ -157,9 +158,14 @@ public function encryptNode($objKey, $replace = true) throw new Exception('Type is currently not supported'); } - $encMethod = $this->encdoc->documentElement->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod')); + $encMethod = $this->encdoc->documentElement->appendChild( + $this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod') + ); $encMethod->setAttribute('Algorithm', $objKey->getAlgorithm()); - $cipherValue->parentNode->parentNode->insertBefore($encMethod, $cipherValue->parentNode->parentNode->firstChild); + $cipherValue->parentNode->parentNode->insertBefore( + $encMethod, + $cipherValue->parentNode->parentNode->firstChild + ); $strEncrypt = base64_encode($objKey->encryptData($data)); $value = $this->encdoc->createTextNode($strEncrypt); @@ -195,7 +201,7 @@ public function encryptReferences($objKey) { $curRawNode = $this->rawNode; $curType = $this->type; - foreach ($this->references AS $name => $reference) { + foreach ($this->references as $name => $reference) { $this->encdoc = $reference["encnode"]; $this->rawNode = $reference["node"]; $this->type = $reference["type"]; @@ -233,7 +239,7 @@ public function getCipherValue() $node = $nodeset->item(0); if (!$node) { - return null; + return null; } return base64_decode($node->nodeValue); @@ -248,13 +254,14 @@ public function getCipherValue() * document, and return the decrypted element(s). * * @param XMLSecurityKey $objKey The decryption key that should be used when decrypting the node. - * @param boolean $replace Whether we should replace the encrypted node in the XML document with the decrypted data. The default is true. + * @param boolean $replace Whether we should replace the encrypted node in the + * XML document with the decrypted data. The default is true. * * @return string|DOMElement The decrypted data. */ - public function decryptNode($objKey, $replace=true) + public function decryptNode($objKey, $replace = true) { - if (! $objKey instanceof XMLSecurityKey) { + if (!($objKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); } @@ -302,31 +309,38 @@ public function decryptNode($objKey, $replace=true) * @param bool $append * @throws Exception */ - public function encryptKey($srcKey, $rawKey, $append=true) + public function encryptKey($srcKey, $rawKey, $append = true) { - if ((! $srcKey instanceof XMLSecurityKey) || (! $rawKey instanceof XMLSecurityKey)) { + if (!($srcKey instanceof XMLSecurityKey) || !($rawKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); } $strEncKey = base64_encode($srcKey->encryptData($rawKey->key)); $root = $this->encdoc->documentElement; $encKey = $this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptedKey'); if ($append) { - $keyInfo = $root->insertBefore($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'), $root->firstChild); + $keyInfo = $root->insertBefore( + $this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'), + $root->firstChild + ); $keyInfo->appendChild($encKey); } else { $this->encKey = $encKey; } $encMethod = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod')); $encMethod->setAttribute('Algorithm', $srcKey->getAlgorith()); - if (! empty($srcKey->name)) { - $keyInfo = $encKey->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo')); - $keyInfo->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name)); + if (!empty($srcKey->name)) { + $keyInfo = $encKey->appendChild( + $this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo') + ); + $keyInfo->appendChild( + $this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name) + ); } $cipherData = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:CipherData')); $cipherData->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:CipherValue', $strEncKey)); if (is_array($this->references) && count($this->references) > 0) { $refList = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:ReferenceList')); - foreach ($this->references AS $name => $reference) { + foreach ($this->references as $name => $reference) { $refuri = $reference["refuri"]; $dataRef = $refList->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:DataReference')); $dataRef->setAttribute("URI", '#' . $refuri); @@ -342,7 +356,7 @@ public function encryptKey($srcKey, $rawKey, $append=true) */ public function decryptKey($encKey) { - if (! $encKey->isEncrypted) { + if (!$encKey->isEncrypted) { throw new Exception("Key is not Encrypted"); } if (empty($encKey->key)) { @@ -364,7 +378,7 @@ public function locateEncryptedData($element) } if ($doc) { $xpath = new DOMXPath($doc); - $query = "//*[local-name()='EncryptedData' and namespace-uri()='".self::XMLENCNS."']"; + $query = "//*[local-name()='EncryptedData' and namespace-uri()='" . self::XMLENCNS . "']"; $nodeset = $xpath->query($query); return $nodeset->item(0); } @@ -376,12 +390,12 @@ public function locateEncryptedData($element) * @param null|DOMNode $node * @return null|XMLSecurityKey */ - public function locateKey($node=null) + public function locateKey($node = null) { if (empty($node)) { $node = $this->rawNode; } - if (! $node instanceof DOMNode) { + if (!($node instanceof DOMNode)) { return null; } if ($doc = $node->ownerDocument) { @@ -408,9 +422,9 @@ public function locateKey($node=null) * @return null|XMLSecurityKey * @throws Exception */ - public static function staticLocateKeyInfo($objBaseKey=null, $node=null) + public static function staticLocateKeyInfo($objBaseKey = null, $node = null) { - if (empty($node) || (! $node instanceof DOMNode)) { + if (empty($node) || !($node instanceof DOMNode)) { return null; } $doc = $node->ownerDocument; @@ -429,7 +443,7 @@ public static function staticLocateKeyInfo($objBaseKey=null, $node=null) return $objBaseKey; } - foreach ($encmeth->childNodes AS $child) { + foreach ($encmeth->childNodes as $child) { switch ($child->localName) { case 'KeyName': if (! empty($objBaseKey)) { @@ -437,7 +451,7 @@ public static function staticLocateKeyInfo($objBaseKey=null, $node=null) } break; case 'KeyValue': - foreach ($child->childNodes AS $keyval) { + foreach ($child->childNodes as $keyval) { switch ($keyval->localName) { case 'DSAKeyValue': throw new Exception("DSAKeyValue currently not supported"); @@ -472,7 +486,7 @@ public static function staticLocateKeyInfo($objBaseKey=null, $node=null) } $id = substr($uri, 1); - $query = '//xmlsecenc:EncryptedKey[@Id="'.XPath::filterAttrValue($id, XPath::DOUBLE_QUOTE).'"]'; + $query = '//xmlsecenc:EncryptedKey[@Id="' . XPath::filterAttrValue($id, XPath::DOUBLE_QUOTE) . '"]'; $keyElement = $xpath->query($query)->item(0); if (!$keyElement) { throw new Exception("Unable to locate EncryptedKey with @Id='$id'."); @@ -486,7 +500,8 @@ public static function staticLocateKeyInfo($objBaseKey=null, $node=null) if ($x509certNodes->length > 0) { $x509cert = $x509certNodes->item(0)->textContent; $x509cert = str_replace(array("\r", "\n", " "), "", $x509cert); - $x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n"; + $x509cert = "-----BEGIN CERTIFICATE-----\n" + . chunk_split($x509cert, 64, "\n") . "-----END CERTIFICATE-----\n"; $objBaseKey->loadKey($x509cert, false, true); } } @@ -501,7 +516,7 @@ public static function staticLocateKeyInfo($objBaseKey=null, $node=null) * @param null|DOMNode $node * @return null|XMLSecurityKey */ - public function locateKeyInfo($objBaseKey=null, $node=null) + public function locateKeyInfo($objBaseKey = null, $node = null) { if (empty($node)) { $node = $this->rawNode; diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php index 389f8adb..3e2bb5d9 100644 --- a/src/XMLSecurityDSig.php +++ b/src/XMLSecurityDSig.php @@ -1,4 +1,5 @@ prefix = $prefix.':'; + if (!empty($prefix)) { + $this->prefix = $prefix . ':'; $search = array("sigNode->ownerDocument; - if (! is_null($value)) { - $node = $doc->createElementNS(self::XMLDSIGNS, $this->prefix.$name, $value); + if (!is_null($value)) { + $node = $doc->createElementNS(self::XMLDSIGNS, $this->prefix . $name, $value); } else { - $node = $doc->createElementNS(self::XMLDSIGNS, $this->prefix.$name); + $node = $doc->createElementNS(self::XMLDSIGNS, $this->prefix . $name); } return $node; } @@ -237,12 +238,12 @@ public function setCanonicalMethod($method) throw new Exception('Invalid Canonical Method'); } if ($xpath = $this->getXPathObj()) { - $query = './'.$this->searchpfx.':SignedInfo'; + $query = './' . $this->searchpfx . ':SignedInfo'; $nodeset = $xpath->query($query, $this->sigNode); if ($sinfo = $nodeset->item(0)) { - $query = './'.$this->searchpfx.'CanonicalizationMethod'; + $query = './' . $this->searchpfx . 'CanonicalizationMethod'; $nodeset = $xpath->query($query, $sinfo); - if (! ($canonNode = $nodeset->item(0))) { + if (!($canonNode = $nodeset->item(0))) { $canonNode = $this->createNewSignNode('CanonicalizationMethod'); $sinfo->insertBefore($canonNode, $sinfo->firstChild); } @@ -258,7 +259,7 @@ public function setCanonicalMethod($method) * @param null|array $prefixList * @return string */ - private function canonicalizeData($node, $canonicalmethod, $arXPath=null, $prefixList=null) + private function canonicalizeData($node, $canonicalmethod, $arXPath = null, $prefixList = null) { $exclusive = false; $withComments = false; @@ -279,7 +280,12 @@ private function canonicalizeData($node, $canonicalmethod, $arXPath=null, $prefi break; } - if (is_null($arXPath) && ($node instanceof DOMNode) && ($node->ownerDocument !== null) && $node->isSameNode($node->ownerDocument->documentElement)) { + if ( + is_null($arXPath) + && ($node instanceof DOMNode) + && ($node->ownerDocument !== null) + && $node->isSameNode($node->ownerDocument->documentElement) + ) { /* Check for any PI or comments as they would have been excluded */ $element = $node; while ($refnode = $element->previousSibling) { @@ -317,8 +323,7 @@ public function canonicalizeSignedInfo() $prefixList = null; if ($canonNode = $nodeset->item(0)) { $canonicalmethod = $canonNode->getAttribute('Algorithm'); - foreach ($canonNode->childNodes as $node) - { + foreach ($canonNode->childNodes as $node) { if ($node->localName == 'InclusiveNamespaces') { if ($pfx = $node->getAttribute('PrefixList')) { $arpfx = array_filter(explode(' ', $pfx)); @@ -370,7 +375,6 @@ public function calculateDigest($digestAlgorithm, $data, $encode = true) $digest = base64_encode($digest); } return $digest; - } /** @@ -406,12 +410,11 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru $canonicalMethod = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; $arXPath = null; $prefixList = null; - foreach ($nodelist AS $transform) { + foreach ($nodelist as $transform) { $algorithm = $transform->getAttribute("Algorithm"); switch ($algorithm) { case 'http://www.w3.org/2001/10/xml-exc-c14n#': case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments': - if (!$includeCommentNodes) { /* We remove comment nodes by forcing it to use a canonicalization * without comments. @@ -427,7 +430,7 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru if ($pfx = $node->getAttribute('PrefixList')) { $arpfx = array(); $pfxlist = explode(" ", $pfx); - foreach ($pfxlist AS $pfx) { + foreach ($pfxlist as $pfx) { $val = trim($pfx); if (! empty($val)) { $arpfx[] = $val; @@ -441,7 +444,7 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru } $node = $node->nextSibling; } - break; + break; case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315': case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments': if (!$includeCommentNodes) { @@ -459,10 +462,10 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru while ($node) { if ($node->localName == 'XPath') { $arXPath = array(); - $arXPath['query'] = '(.//. | .//@* | .//namespace::*)['.$node->nodeValue.']'; + $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $node->nodeValue . ']'; $arXPath['namespaces'] = array(); $nslist = $xpath->query('./namespace::*', $node); - foreach ($nslist AS $nsnode) { + foreach ($nslist as $nsnode) { if ($nsnode->localName != "xml") { $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue; } @@ -498,7 +501,6 @@ public function processRefNode($refNode) $arUrl = parse_url($uri); if (empty($arUrl['path'])) { if ($identifier = $arUrl['fragment']) { - /* This reference identifies a node with the given id by using * a URI on the form "#identifier". This should not include comments. */ @@ -510,14 +512,14 @@ public function processRefNode($refNode) $xPath->registerNamespace($nspf, $ns); } } - $iDlist = '@Id="'.XPath::filterAttrValue($identifier, XPath::DOUBLE_QUOTE).'"'; + $iDlist = '@Id="' . XPath::filterAttrValue($identifier, XPath::DOUBLE_QUOTE) . '"'; if (is_array($this->idKeys)) { foreach ($this->idKeys as $idKey) { - $iDlist .= " or @".XPath::filterAttrName($idKey).'="'. - XPath::filterAttrValue($identifier, XPath::DOUBLE_QUOTE).'"'; + $iDlist .= " or @" . XPath::filterAttrName($idKey) . '="' . + XPath::filterAttrValue($identifier, XPath::DOUBLE_QUOTE) . '"'; } } - $query = '//*['.$iDlist.']'; + $query = '//*[' . $iDlist . ']'; $dataObject = $xPath->query($query)->item(0); } else { $dataObject = $refNode->ownerDocument; @@ -579,7 +581,7 @@ public function getRefIDs() if ($nodeset->length == 0) { throw new Exception("Reference nodes not found"); } - foreach ($nodeset AS $refNode) { + foreach ($nodeset as $refNode) { $refids[] = $this->getRefNodeID($refNode); } return $refids; @@ -592,7 +594,7 @@ public function getRefIDs() public function validateReference() { $docElem = $this->sigNode->ownerDocument->documentElement; - if (! $docElem->isSameNode($this->sigNode)) { + if (!$docElem->isSameNode($this->sigNode)) { if ($this->sigNode->parentNode != null) { $this->sigNode->parentNode->removeChild($this->sigNode); } @@ -607,8 +609,8 @@ public function validateReference() /* Initialize/reset the list of validated nodes. */ $this->validatedNodes = array(); - foreach ($nodeset AS $refNode) { - if (! $this->processRefNode($refNode)) { + foreach ($nodeset as $refNode) { + if (!$this->processRefNode($refNode)) { /* Clear the list of validated nodes. */ $this->validatedNodes = null; throw new Exception("Reference validation failed"); @@ -624,7 +626,7 @@ public function validateReference() * @param null|array $arTransforms * @param null|array $options */ - private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=null, $options=null) + private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms = null, $options = null) { $prefix = null; $prefix_ns = null; @@ -641,23 +643,23 @@ private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=nul } $attname = $id_name; - if (! empty($prefix)) { - $attname = $prefix.':'.$attname; + if (!empty($prefix)) { + $attname = $prefix . ':' . $attname; } $refNode = $this->createNewSignNode('Reference'); $sinfoNode->appendChild($refNode); - if (! $node instanceof DOMDocument) { + if (!($node instanceof DOMDocument)) { $uri = null; - if (! $overwrite_id) { + if (!$overwrite_id) { $uri = $prefix_ns ? $node->getAttributeNS($prefix_ns, $id_name) : $node->getAttribute($id_name); } if (empty($uri)) { $uri = self::generateGUID(); $node->setAttributeNS($prefix_ns, $attname, $uri); } - $refNode->setAttribute("URI", '#'.$uri); + $refNode->setAttribute("URI", '#' . $uri); } elseif ($force_uri) { $refNode->setAttribute("URI", ''); } @@ -666,17 +668,23 @@ private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=nul $refNode->appendChild($transNodes); if (is_array($arTransforms)) { - foreach ($arTransforms AS $transform) { + foreach ($arTransforms as $transform) { $transNode = $this->createNewSignNode('Transform'); $transNodes->appendChild($transNode); - if (is_array($transform) && - (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116'])) && - (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']))) { + if ( + is_array($transform) + && (!empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116'])) + && (!empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query'])) + ) { $transNode->setAttribute('Algorithm', 'http://www.w3.org/TR/1999/REC-xpath-19991116'); - $XPathNode = $this->createNewSignNode('XPath', $transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query']); + $XPathNode = $this->createNewSignNode( + 'XPath', + $transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['query'] + ); $transNode->appendChild($XPathNode); - if (! empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'])) { - foreach ($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'] AS $prefix => $namespace) { + if (!empty($transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces'])) { + $namespaces = $transform['http://www.w3.org/TR/1999/REC-xpath-19991116']['namespaces']; + foreach ($namespaces as $prefix => $namespace) { $XPathNode->setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:$prefix", $namespace); } } @@ -684,7 +692,7 @@ private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=nul $transNode->setAttribute('Algorithm', $transform); } } - } elseif (! empty($this->canonicalMethod)) { + } elseif (!empty($this->canonicalMethod)) { $transNode = $this->createNewSignNode('Transform'); $transNodes->appendChild($transNode); $transNode->setAttribute('Algorithm', $this->canonicalMethod); @@ -707,7 +715,7 @@ private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=nul * @param null|array $arTransforms * @param null|array $options */ - public function addReference($node, $algorithm, $arTransforms=null, $options=null) + public function addReference($node, $algorithm, $arTransforms = null, $options = null) { if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; @@ -724,13 +732,13 @@ public function addReference($node, $algorithm, $arTransforms=null, $options=nul * @param null|array $arTransforms * @param null|array $options */ - public function addReferenceList($arNodes, $algorithm, $arTransforms=null, $options=null) + public function addReferenceList($arNodes, $algorithm, $arTransforms = null, $options = null) { if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); if ($sInfo = $nodeset->item(0)) { - foreach ($arNodes AS $node) { + foreach ($arNodes as $node) { $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options); } } @@ -743,14 +751,14 @@ public function addReferenceList($arNodes, $algorithm, $arTransforms=null, $opti * @param null|string $encoding * @return DOMElement */ - public function addObject($data, $mimetype=null, $encoding=null) + public function addObject($data, $mimetype = null, $encoding = null) { $objNode = $this->createNewSignNode('Object'); $this->sigNode->appendChild($objNode); - if (! empty($mimetype)) { + if (!empty($mimetype)) { $objNode->setAttribute('MimeType', $mimetype); } - if (! empty($encoding)) { + if (!empty($encoding)) { $objNode->setAttribute('Encoding', $encoding); } @@ -768,12 +776,12 @@ public function addObject($data, $mimetype=null, $encoding=null) * @param null|DOMNode $node * @return null|XMLSecurityKey */ - public function locateKey($node=null) + public function locateKey($node = null) { if (empty($node)) { $node = $this->sigNode; } - if (! $node instanceof DOMNode) { + if (!($node instanceof DOMNode)) { return null; } if ($doc = $node->ownerDocument) { @@ -866,14 +874,13 @@ public function sign($objKey, $appendToNode = null) public function appendCert() { - } /** * @param XMLSecurityKey $objKey * @param null|DOMNode $parent */ - public function appendKey($objKey, $parent=null) + public function appendKey($objKey, $parent = null) { $objKey->serializeKey($parent); } @@ -919,10 +926,10 @@ public function appendSignature($parentNode, $insertBefore = false) * @param bool $isPEMFormat * @return string */ - public static function get509XCert($cert, $isPEMFormat=true) + public static function get509XCert($cert, $isPEMFormat = true) { $certs = self::staticGet509XCerts($cert, $isPEMFormat); - if (! empty($certs)) { + if (!empty($certs)) { return $certs[0]; } return ''; @@ -933,14 +940,14 @@ public static function get509XCert($cert, $isPEMFormat=true) * @param bool $isPEMFormat * @return array */ - public static function staticGet509XCerts($certs, $isPEMFormat=true) + public static function staticGet509XCerts($certs, $isPEMFormat = true) { if ($isPEMFormat) { $data = ''; $certlist = array(); $arCert = explode("\n", $certs); $inData = false; - foreach ($arCert AS $curData) { + foreach ($arCert as $curData) { if (! $inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = true; @@ -970,12 +977,18 @@ public static function staticGet509XCerts($certs, $isPEMFormat=true) * @param null|array $options * @throws Exception */ - public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $isURL=false, $xpath=null, $options=null) - { + public static function staticAdd509Cert( + $parentRef, + $cert, + $isPEMFormat = true, + $isURL = false, + $xpath = null, + $options = null + ) { if ($isURL) { $cert = file_get_contents($cert); } - if (! $parentRef instanceof DOMElement) { + if (!($parentRef instanceof DOMElement)) { throw new Exception('Invalid parent Node parameter'); } $baseDoc = $parentRef->ownerDocument; @@ -989,13 +1002,13 @@ public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $i $nodeset = $xpath->query($query, $parentRef); $keyInfo = $nodeset->item(0); $dsig_pfx = ''; - if (! $keyInfo) { + if (!$keyInfo) { $pfx = $parentRef->lookupPrefix(self::XMLDSIGNS); - if (! empty($pfx)) { - $dsig_pfx = $pfx.":"; + if (!empty($pfx)) { + $dsig_pfx = $pfx . ":"; } $inserted = false; - $keyInfo = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'KeyInfo'); + $keyInfo = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx . 'KeyInfo'); $query = "./secdsig:Object"; $nodeset = $xpath->query($query, $parentRef); @@ -1004,13 +1017,13 @@ public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $i $inserted = true; } - if (! $inserted) { + if (!$inserted) { $parentRef->appendChild($keyInfo); } } else { $pfx = $keyInfo->lookupPrefix(self::XMLDSIGNS); - if (! empty($pfx)) { - $dsig_pfx = $pfx.":"; + if (!empty($pfx)) { + $dsig_pfx = $pfx . ":"; } } @@ -1018,7 +1031,7 @@ public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $i $certs = self::staticGet509XCerts($cert, $isPEMFormat); // Attach X509 data node - $x509DataNode = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'X509Data'); + $x509DataNode = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx . 'X509Data'); $keyInfo->appendChild($x509DataNode); $issuerSerial = false; @@ -1035,11 +1048,14 @@ public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $i // Attach all certificate nodes and any additional data foreach ($certs as $X509Cert) { if ($issuerSerial || $subjectName) { - if ($certData = openssl_x509_parse("-----BEGIN CERTIFICATE-----\n".chunk_split($X509Cert, 64, "\n")."-----END CERTIFICATE-----\n")) { - if ($subjectName && ! empty($certData['subject'])) { + $certData = openssl_x509_parse( + "-----BEGIN CERTIFICATE-----\n" . chunk_split($X509Cert, 64, "\n") . "-----END CERTIFICATE-----\n" + ); + if ($certData) { + if ($subjectName && !empty($certData['subject'])) { if (is_array($certData['subject'])) { $parts = array(); - foreach ($certData['subject'] AS $key => $value) { + foreach ($certData['subject'] as $key => $value) { if (is_array($value)) { foreach ($value as $valueElement) { array_unshift($parts, "$key=$valueElement"); @@ -1052,13 +1068,17 @@ public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $i } else { $subjectNameValue = $certData['issuer']; } - $x509SubjectNode = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'X509SubjectName', $subjectNameValue); + $x509SubjectNode = $baseDoc->createElementNS( + self::XMLDSIGNS, + $dsig_pfx . 'X509SubjectName', + $subjectNameValue + ); $x509DataNode->appendChild($x509SubjectNode); } - if ($issuerSerial && ! empty($certData['issuer']) && ! empty($certData['serialNumber'])) { + if ($issuerSerial && !empty($certData['issuer']) && !empty($certData['serialNumber'])) { if (is_array($certData['issuer'])) { $parts = array(); - foreach ($certData['issuer'] AS $key => $value) { + foreach ($certData['issuer'] as $key => $value) { array_unshift($parts, "$key=$value"); } $issuerName = implode(',', $parts); @@ -1066,18 +1086,25 @@ public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $i $issuerName = $certData['issuer']; } - $x509IssuerNode = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'X509IssuerSerial'); + $x509IssuerNode = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx . 'X509IssuerSerial'); $x509DataNode->appendChild($x509IssuerNode); - $x509Node = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'X509IssuerName', $issuerName); + $x509Node = $baseDoc->createElementNS( + self::XMLDSIGNS, + $dsig_pfx . 'X509IssuerName', + $issuerName + ); $x509IssuerNode->appendChild($x509Node); - $x509Node = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'X509SerialNumber', $certData['serialNumber']); + $x509Node = $baseDoc->createElementNS( + self::XMLDSIGNS, + $dsig_pfx . 'X509SerialNumber', + $certData['serialNumber'] + ); $x509IssuerNode->appendChild($x509Node); } } - } - $x509CertNode = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'X509Certificate', $X509Cert); + $x509CertNode = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx . 'X509Certificate', $X509Cert); $x509DataNode->appendChild($x509CertNode); } } @@ -1088,7 +1115,7 @@ public static function staticAdd509Cert($parentRef, $cert, $isPEMFormat=true, $i * @param bool $isURL * @param null|array $options */ - public function add509Cert($cert, $isPEMFormat=true, $isURL=false, $options=null) + public function add509Cert($cert, $isPEMFormat = true, $isURL = false, $options = null) { if ($xpath = $this->getXPathObj()) { self::staticAdd509Cert($this->sigNode, $cert, $isPEMFormat, $isURL, $xpath, $options); @@ -1118,14 +1145,14 @@ public function appendToKeyInfo($node) $query = "./secdsig:KeyInfo"; $nodeset = $xpath->query($query, $parentRef); $keyInfo = $nodeset->item(0); - if (! $keyInfo) { + if (!$keyInfo) { $dsig_pfx = ''; $pfx = $parentRef->lookupPrefix(self::XMLDSIGNS); - if (! empty($pfx)) { - $dsig_pfx = $pfx.":"; + if (!empty($pfx)) { + $dsig_pfx = $pfx . ":"; } $inserted = false; - $keyInfo = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx.'KeyInfo'); + $keyInfo = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx . 'KeyInfo'); $query = "./secdsig:Object"; $nodeset = $xpath->query($query, $parentRef); @@ -1134,7 +1161,7 @@ public function appendToKeyInfo($node) $inserted = true; } - if (! $inserted) { + if (!$inserted) { $parentRef->appendChild($keyInfo); } } diff --git a/src/XMLSecurityKey.php b/src/XMLSecurityKey.php index e2506e49..c93b226b 100644 --- a/src/XMLSecurityKey.php +++ b/src/XMLSecurityKey.php @@ -1,4 +1,5 @@ type . '".'); } $keysize = $this->cryptParams['keysize']; - + $key = openssl_random_pseudo_bytes($keysize); - + if ($this->type === self::TRIPLEDES_CBC) { /* Make sure that the generated key has the proper parity bits set. * Mcrypt doesn't care about the parity bits, but others may care. @@ -295,7 +296,7 @@ public function generateSessionKey() $key[$i] = chr($byte); } } - + $this->key = $key; return $key; } @@ -313,7 +314,7 @@ public static function getRawThumbprint($cert) $data = ''; $inData = false; - foreach ($arCert AS $curData) { + foreach ($arCert as $curData) { if (! $inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = true; @@ -341,7 +342,7 @@ public static function getRawThumbprint($cert) * @param bool $isCert * @throws Exception */ - public function loadKey($key, $isFile=false, $isCert = false) + public function loadKey($key, $isFile = false, $isCert = false) { if ($isFile) { $this->key = file_get_contents($key); @@ -359,21 +360,22 @@ public function loadKey($key, $isFile=false, $isCert = false) if ($this->cryptParams['library'] == 'openssl') { switch ($this->cryptParams['type']) { case 'public': - if ($isCert) { - /* Load the thumbprint if this is an X509 certificate. */ - $this->X509Thumbprint = self::getRawThumbprint($this->key); - } - $this->key = openssl_get_publickey($this->key); - if (! $this->key) { - throw new Exception('Unable to extract public key'); - } - break; - - case 'private': + if ($isCert) { + /* Load the thumbprint if this is an X509 certificate. */ + $this->X509Thumbprint = self::getRawThumbprint($this->key); + } + $this->key = openssl_get_publickey($this->key); + + if (!($this->key)) { + throw new Exception('Unable to extract public key'); + } + break; + + case 'private': $this->key = openssl_get_privatekey($this->key, $this->passphrase); break; - case'symmetric': + case 'symmetric': if (strlen($this->key) < $this->cryptParams['keysize']) { throw new Exception('Key must contain at least 25 characters for this cipher'); } @@ -426,17 +428,30 @@ private function encryptSymmetric($data) { $this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher'])); $authTag = null; - if(in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { + if (in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { if (version_compare(PHP_VERSION, '7.1.0') < 0) { throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); } $authTag = openssl_random_pseudo_bytes(self::AUTHTAG_LENGTH); - $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA, $this->iv, $authTag); + $encrypted = openssl_encrypt( + $data, + $this->cryptParams['cipher'], + $this->key, + OPENSSL_RAW_DATA, + $this->iv, + $authTag + ); } else { $data = $this->padISO10126($data, $this->cryptParams['blocksize']); - $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); + $encrypted = openssl_encrypt( + $data, + $this->cryptParams['cipher'], + $this->key, + OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, + $this->iv + ); } - + if (false === $encrypted) { throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string()); } @@ -455,7 +470,7 @@ private function decryptSymmetric($data) $this->iv = substr($data, 0, $iv_length); $data = substr($data, $iv_length); $authTag = null; - if(in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { + if (in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { if (version_compare(PHP_VERSION, '7.1.0') < 0) { throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); } @@ -463,11 +478,24 @@ private function decryptSymmetric($data) $offset = 0 - self::AUTHTAG_LENGTH; $authTag = substr($data, $offset); $data = substr($data, 0, $offset); - $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA, $this->iv, $authTag); + $decrypted = openssl_decrypt( + $data, + $this->cryptParams['cipher'], + $this->key, + OPENSSL_RAW_DATA, + $this->iv, + $authTag + ); } else { - $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); + $decrypted = openssl_decrypt( + $data, + $this->cryptParams['cipher'], + $this->key, + OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, + $this->iv + ); } - + if (false === $decrypted) { throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string()); } @@ -483,7 +511,7 @@ private function decryptSymmetric($data) */ private function encryptPublic($data) { - if (! openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { + if (!openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure encrypting Data (openssl public) - ' . openssl_error_string()); } return $encrypted; @@ -498,7 +526,7 @@ private function encryptPublic($data) */ private function decryptPublic($data) { - if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { + if (!openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string()); } return $decrypted; @@ -513,7 +541,7 @@ private function decryptPublic($data) */ private function encryptPrivate($data) { - if (! openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { + if (!openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string()); } return $encrypted; @@ -528,7 +556,7 @@ private function encryptPrivate($data) */ private function decryptPrivate($data) { - if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { + if (!openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure decrypting Data (openssl private) - ' . openssl_error_string()); } return $decrypted; @@ -544,10 +572,10 @@ private function decryptPrivate($data) private function signOpenSSL($data) { $algo = OPENSSL_ALGO_SHA1; - if (! empty($this->cryptParams['digest'])) { + if (!empty($this->cryptParams['digest'])) { $algo = $this->cryptParams['digest']; } - if (! openssl_sign($data, $signature, $this->key, $algo)) { + if (!openssl_sign($data, $signature, $this->key, $algo)) { throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo); } return $signature; @@ -572,14 +600,15 @@ private function signOpenSSL($data) private function verifyOpenSSL($data, $signature) { $algo = OPENSSL_ALGO_SHA1; - if (! empty($this->cryptParams['digest'])) { + if (!empty($this->cryptParams['digest'])) { $algo = $this->cryptParams['digest']; } return openssl_verify($data, $signature, $this->key, $algo); } /** - * Encrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor. + * Encrypts the given data (string) using the regarding php-extension, + * depending on the library assigned to algorithm in the contructor. * * @param string $data * @return mixed|string @@ -599,7 +628,8 @@ public function encryptData($data) } /** - * Decrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor. + * Decrypts the given data (string) using the regarding php-extension, + * depending on the library assigned to algorithm in the contructor. * * @param string $data * @return mixed|string @@ -635,7 +665,8 @@ public function signData($data) } /** - * Verifies the data (string) against the given signature using the extension assigned to the type in the constructor. + * Verifies the data (string) against the given signature using + * the extension assigned to the type in the constructor. * * Returns in case of openSSL: * 1 on succesful signature verification, @@ -689,11 +720,12 @@ public static function makeAsnSegment($type, $string) { switch ($type) { case 0x02: - if (ord($string) > 0x7f) - $string = chr(0).$string; + if (ord($string) > 0x7f) { + $string = chr(0) . $string; + } break; case 0x03: - $string = chr(0).$string; + $string = chr(0) . $string; break; } @@ -701,9 +733,9 @@ public static function makeAsnSegment($type, $string) if ($length < 128) { $output = sprintf("%c%c%s", $type, $length, $string); - } else if ($length < 0x0100) { + } elseif ($length < 0x0100) { $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string); - } else if ($length < 0x010000) { + } elseif ($length < 0x010000) { $output = sprintf("%c%c%c%c%s", $type, 0x82, $length / 0x0100, $length % 0x0100, $string); } else { $output = null; @@ -723,20 +755,20 @@ public static function convertRSA($modulus, $exponent) /* make an ASN publicKeyInfo */ $exponentEncoding = self::makeAsnSegment(0x02, $exponent); $modulusEncoding = self::makeAsnSegment(0x02, $modulus); - $sequenceEncoding = self::makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding); + $sequenceEncoding = self::makeAsnSegment(0x30, $modulusEncoding . $exponentEncoding); $bitstringEncoding = self::makeAsnSegment(0x03, $sequenceEncoding); $rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500"); - $publicKeyInfo = self::makeAsnSegment(0x30, $rsaAlgorithmIdentifier.$bitstringEncoding); + $publicKeyInfo = self::makeAsnSegment(0x30, $rsaAlgorithmIdentifier . $bitstringEncoding); /* encode the publicKeyInfo in base64 and add PEM brackets */ $publicKeyInfoBase64 = base64_encode($publicKeyInfo); $encoding = "-----BEGIN PUBLIC KEY-----\n"; $offset = 0; while ($segment = substr($publicKeyInfoBase64, $offset, 64)) { - $encoding = $encoding.$segment."\n"; + $encoding = $encoding . $segment . "\n"; $offset += 64; } - return $encoding."-----END PUBLIC KEY-----\n"; + return $encoding . "-----END PUBLIC KEY-----\n"; } /** @@ -744,7 +776,6 @@ public static function convertRSA($modulus, $exponent) */ public function serializeKey($parent) { - } /** @@ -788,7 +819,7 @@ public static function fromEncryptedKeyElement(DOMElement $element) $objenc = new XMLSecEnc(); $objenc->setNode($element); - if (! $objKey = $objenc->locateKey()) { + if (!($objKey = $objenc->locateKey())) { throw new Exception("Unable to locate algorithm for this Encrypted Key"); } $objKey->isEncrypted = true; @@ -796,5 +827,4 @@ public static function fromEncryptedKeyElement(DOMElement $element) XMLSecEnc::staticLocateKeyInfo($objKey, $element); return $objKey; } - } diff --git a/tests/encrypteddata-node-order.phpt b/tests/encrypteddata-node-order.phpt index dce2ee14..085bdcab 100644 --- a/tests/encrypteddata-node-order.phpt +++ b/tests/encrypteddata-node-order.phpt @@ -15,8 +15,8 @@ $dom->load(dirname(__FILE__) . '/basic-doc.xml'); $objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $objKey->generateSessionKey(); -$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type'=>'public')); -$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE, TRUE); +$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public')); +$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', true, true); $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); @@ -33,16 +33,16 @@ $nodeOrder = array( ); $prevNode = 0; -for ($node = $encNode->firstChild; $node !== NULL; $node = $node->nextSibling) { - if (! ($node instanceof DOMElement)) { +for ($node = $encNode->firstChild; $node !== null; $node = $node->nextSibling) { + if (!($node instanceof DOMElement)) { /* Skip comment and text nodes. */ continue; } $name = $node->localName; - $cIndex = array_search($name, $nodeOrder, TRUE); - if ($cIndex === FALSE) { + $cIndex = array_search($name, $nodeOrder, true); + if ($cIndex === false) { die("Unknown node: $name"); } diff --git a/tests/retrievalmethod-findkey.phpt b/tests/retrievalmethod-findkey.phpt index 057a1537..34695cd2 100644 --- a/tests/retrievalmethod-findkey.phpt +++ b/tests/retrievalmethod-findkey.phpt @@ -10,7 +10,7 @@ $doc->load(dirname(__FILE__) . "/retrievalmethod-findkey.xml"); $objenc = new XMLSecEnc(); $encData = $objenc->locateEncryptedData($doc); -if (! $encData) { +if (!$encData) { throw new Exception("Cannot locate Encrypted Data"); } $objenc->setNode($encData); diff --git a/tests/sign-c14-comments.phpt b/tests/sign-c14-comments.phpt index aa1328f8..fe06fdd3 100644 --- a/tests/sign-c14-comments.phpt +++ b/tests/sign-c14-comments.phpt @@ -27,7 +27,7 @@ $objDSig->addReference($doc, XMLSecurityDSig::SHA1, array('http://www.w3.org/200 $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); /* load private key */ -$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); +$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); $objDSig->sign($objKey, $doc->documentElement); diff --git a/tests/sign-empty-uri.phpt b/tests/sign-empty-uri.phpt index b2023f8e..51f43617 100644 --- a/tests/sign-empty-uri.phpt +++ b/tests/sign-empty-uri.phpt @@ -19,9 +19,9 @@ $objDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N); $objDSig->addReference($doc, XMLSecurityDSig::SHA1, array('http://www.w3.org/2000/09/xmldsig#enveloped-signature'), array('force_uri' => true)); -$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); +$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private')); /* load private key */ -$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); +$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); /* if key has Passphrase, set it using $objKey->passphrase = " */ diff --git a/tests/sign-hhvm-id-wout-ns-regenerated.phpt b/tests/sign-hhvm-id-wout-ns-regenerated.phpt index fd5a565b..f66346a5 100644 --- a/tests/sign-hhvm-id-wout-ns-regenerated.phpt +++ b/tests/sign-hhvm-id-wout-ns-regenerated.phpt @@ -14,7 +14,7 @@ $doc = new \DOMDocument(); $doc->load(__DIR__.'/sign-hhvm-id-wout-ns-regenerated.xml'); $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); -$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); +$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); /** @var \DOMElement $assertion */ $assertion = $doc->getElementsByTagName('Assertion')->item(0); diff --git a/tests/thumbprint.phpt b/tests/thumbprint.phpt index eb5b8160..083f8504 100644 --- a/tests/thumbprint.phpt +++ b/tests/thumbprint.phpt @@ -5,8 +5,8 @@ Certificate thumbprint check require(dirname(__FILE__) . '/../xmlseclibs.php'); use RobRichards\XMLSecLibs\XMLSecurityKey; -$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type'=>'public')); -$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE, TRUE); +$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public')); +$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', true, true); $thumbprint = $siteKey->getX509Thumbprint(); echo $thumbprint."\n"; diff --git a/tests/validate_digest_sha512.phpt b/tests/validate_digest_sha512.phpt index bf438848..d92e4e31 100755 --- a/tests/validate_digest_sha512.phpt +++ b/tests/validate_digest_sha512.phpt @@ -17,7 +17,7 @@ $objDSig->addReference($doc, XMLSecurityDSig::SHA512, array('http://www.w3.org/2 $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); /* load private key */ -$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); +$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); $objDSig->sign($objKey); @@ -43,7 +43,7 @@ $digestValue->insertData(63, "\n"); $objXMLSecDSig = new XMLSecurityDSig(); $objDSig = $objXMLSecDSig->locateSignature($dom); -if (! $objDSig) { +if (!$objDSig) { throw new Exception("Cannot locate Signature Node"); } $objXMLSecDSig->canonicalizeSignedInfo(); diff --git a/tests/withcomment-empty-uri.phpt b/tests/withcomment-empty-uri.phpt index 7b007ff5..68266cf9 100644 --- a/tests/withcomment-empty-uri.phpt +++ b/tests/withcomment-empty-uri.phpt @@ -13,12 +13,12 @@ $doc->load(dirname(__FILE__) . '/withcomment-empty-uri.xml'); $objXMLSecDSig = new XMLSecurityDSig(); $objDSig = $objXMLSecDSig->locateSignature($doc); -if (! $objDSig) { +if (!$objDSig) { throw new Exception("Cannot locate Signature Node"); } $retVal = $objXMLSecDSig->validateReference(); -if (! $retVal) { +if (!$retVal) { throw new Exception("Reference Validation Failed"); } diff --git a/tests/withcomment-id-uri-object.phpt b/tests/withcomment-id-uri-object.phpt index 04207670..2698cc45 100644 --- a/tests/withcomment-id-uri-object.phpt +++ b/tests/withcomment-id-uri-object.phpt @@ -13,12 +13,12 @@ $objXMLSecDSig = new XMLSecurityDSig(); $objXMLSecDSig->idKeys = array('xml:id'); $objDSig = $objXMLSecDSig->locateSignature($doc); -if (! $objDSig) { +if (!$objDSig) { throw new Exception("Cannot locate Signature Node"); } $retVal = $objXMLSecDSig->validateReference(); -if (! $retVal) { +if (!$retVal) { throw new Exception("Reference Validation Failed"); } @@ -29,4 +29,4 @@ if (! $retVal) { echo "OK\n"; ?> --EXPECTF-- -OK \ No newline at end of file +OK diff --git a/tests/withcomment-id-uri.phpt b/tests/withcomment-id-uri.phpt index a48c9098..4e0cf9d6 100644 --- a/tests/withcomment-id-uri.phpt +++ b/tests/withcomment-id-uri.phpt @@ -13,12 +13,12 @@ $objXMLSecDSig = new XMLSecurityDSig(); $objXMLSecDSig->idKeys = array('xml:id'); $objDSig = $objXMLSecDSig->locateSignature($doc); -if (! $objDSig) { +if (!$objDSig) { throw new Exception("Cannot locate Signature Node"); } $retVal = $objXMLSecDSig->validateReference(); -if (! $retVal) { +if (!$retVal) { throw new Exception("Reference Validation Failed"); } diff --git a/tests/xml-sign-prefix.phpt b/tests/xml-sign-prefix.phpt index 54a62deb..b48b1239 100755 --- a/tests/xml-sign-prefix.phpt +++ b/tests/xml-sign-prefix.phpt @@ -20,7 +20,7 @@ foreach ($prefixes as $file_out => $prefix) { $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); /* load private key */ - $objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); + $objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); /* if key has Passphrase, set it using $objKey->passphrase = " */ diff --git a/tests/xml-sign-sha256-rsa-sha256.phpt b/tests/xml-sign-sha256-rsa-sha256.phpt index 58796eaa..2faeb5aa 100644 --- a/tests/xml-sign-sha256-rsa-sha256.phpt +++ b/tests/xml-sign-sha256-rsa-sha256.phpt @@ -23,7 +23,7 @@ $objDSig->addReference($doc, XMLSecurityDSig::SHA256, array('http://www.w3.org/2 $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA256, array('type'=>'private')); /* load private key */ -$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); +$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); /* if key has Passphrase, set it using $objKey->passphrase = " */ diff --git a/tests/xml-sign-subject.phpt b/tests/xml-sign-subject.phpt index fab9f727..e85c24ba 100644 --- a/tests/xml-sign-subject.phpt +++ b/tests/xml-sign-subject.phpt @@ -21,7 +21,7 @@ $objDSig->addReference($doc, XMLSecurityDSig::SHA1, array('http://www.w3.org/200 $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); /* load private key */ -$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); +$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); /* if key has Passphrase, set it using $objKey->passphrase = " */ @@ -29,7 +29,7 @@ $objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); $objDSig->sign($objKey); /* Add associated public key */ -$objDSig->add509Cert(file_get_contents(dirname(__FILE__) . '/mycert.pem'), TRUE, FALSE, array('subjectName'=>TRUE)); +$objDSig->add509Cert(file_get_contents(dirname(__FILE__) . '/mycert.pem'), true, false, array('subjectName' => true)); $objDSig->appendSignature($doc->documentElement); $doc->save(dirname(__FILE__) . '/sign-subject.xml'); diff --git a/tests/xml-sign.phpt b/tests/xml-sign.phpt index 46f85286..e1ee0f1b 100755 --- a/tests/xml-sign.phpt +++ b/tests/xml-sign.phpt @@ -21,7 +21,7 @@ $objDSig->addReference($doc, XMLSecurityDSig::SHA1, array('http://www.w3.org/200 $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); /* load private key */ -$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', TRUE); +$objKey->loadKey(dirname(__FILE__) . '/privkey.pem', true); /* if key has Passphrase, set it using $objKey->passphrase = " */ diff --git a/tests/xmlsec-decrypt-content.phpt b/tests/xmlsec-decrypt-content.phpt index 1160be6d..6d9bfb90 100644 --- a/tests/xmlsec-decrypt-content.phpt +++ b/tests/xmlsec-decrypt-content.phpt @@ -9,10 +9,10 @@ use RobRichards\XMLSecLibs\XMLSecEnc; function locateLocalKey($objKey) { /* In this example the key is identified by filename */ $filename = $objKey->name; - if (! empty($filename)) { - $objKey->loadKey(dirname(__FILE__) . "/$filename", TRUE); + if (!empty($filename)) { + $objKey->loadKey(dirname(__FILE__) . "/$filename", true); } else { - $objKey->loadKey(dirname(__FILE__) . "/privkey.pem", TRUE); + $objKey->loadKey(dirname(__FILE__) . "/privkey.pem", true); } } @@ -25,8 +25,8 @@ $arTests = array('AOESP_SHA1'=>'oaep_sha1-res.xml', $doc = new DOMDocument(); -foreach ($arTests AS $testName=>$testFile) { - $output = NULL; +foreach ($arTests as $testName => $testFile) { + $output = null; print "$testName: "; $doc->load(dirname(__FILE__) . "/$testFile"); @@ -34,15 +34,15 @@ foreach ($arTests AS $testName=>$testFile) { try { $objenc = new XMLSecEnc(); $encData = $objenc->locateEncryptedData($doc); - if (! $encData) { + if (!$encData) { throw new Exception("Cannot locate Encrypted Data"); } $objenc->setNode($encData); $objenc->type = $encData->getAttribute("Type"); - if (! $objKey = $objenc->locateKey()) { + if (!$objKey = $objenc->locateKey()) { throw new Exception("We know the secret key, but not the algorithm"); } - $key = NULL; + $key = null; if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { if ($objKeyInfo->isEncrypted) { @@ -52,17 +52,17 @@ foreach ($arTests AS $testName=>$testFile) { } } - if (! $objKey->key && empty($key)) { + if (!$objKey->key && empty($key)) { locateLocalKey($objKey); } if (empty($objKey->key)) { $objKey->loadKey($key); } - $token = NULL; + $token = null; - if ($decrypt = $objenc->decryptNode($objKey, TRUE)) { - $output = NULL; + if ($decrypt = $objenc->decryptNode($objKey, true)) { + $output = null; if ($decrypt instanceof DOMNode) { if ($decrypt instanceof DOMDocument) { $output = $decrypt->saveXML(); @@ -78,7 +78,7 @@ foreach ($arTests AS $testName=>$testFile) { } $outfile = dirname(__FILE__) . "/basic-doc.xml"; - $res = NULL; + $res = null; if (file_exists($outfile)) { $resDoc = new DOMDocument(); $resDoc->load($outfile); diff --git a/tests/xmlsec-decrypt.phpt b/tests/xmlsec-decrypt.phpt old mode 100755 new mode 100644 index 7415471c..a7379c90 --- a/tests/xmlsec-decrypt.phpt +++ b/tests/xmlsec-decrypt.phpt @@ -9,10 +9,10 @@ use RobRichards\XMLSecLibs\XMLSecEnc; function locateLocalKey($objKey) { /* In this example the key is identified by filename */ $filename = $objKey->name; - if (! empty($filename)) { - $objKey->loadKey(dirname(__FILE__) . "/$filename", TRUE); + if (!empty($filename)) { + $objKey->loadKey(dirname(__FILE__) . "/$filename", true); } else { - $objKey->loadKey(dirname(__FILE__) . "/privkey.pem", TRUE); + $objKey->loadKey(dirname(__FILE__) . "/privkey.pem", true); } } @@ -21,8 +21,8 @@ $arTests = array('AOESP_SHA1'=>'oaep_sha1-res.xml', 'AES128-GCM'=>'aes128-gcm-re $doc = new DOMDocument(); -foreach ($arTests AS $testName=>$testFile) { - $output = NULL; +foreach ($arTests as $testName=>$testFile) { + $output = null; print "$testName: "; // Skip AES tests is PHP < 7.1.0 @@ -36,15 +36,15 @@ foreach ($arTests AS $testName=>$testFile) { try { $objenc = new XMLSecEnc(); $encData = $objenc->locateEncryptedData($doc); - if (! $encData) { + if (!$encData) { throw new Exception("Cannot locate Encrypted Data"); } $objenc->setNode($encData); $objenc->type = $encData->getAttribute("Type"); - if (! $objKey = $objenc->locateKey()) { + if (!($objKey = $objenc->locateKey())) { throw new Exception("We know the secret key, but not the algorithm"); } - $key = NULL; + $key = null; if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { if ($objKeyInfo->isEncrypted) { @@ -54,17 +54,17 @@ foreach ($arTests AS $testName=>$testFile) { } } - if (! $objKey->key && empty($key)) { + if (!$objKey->key && empty($key)) { locateLocalKey($objKey); } if (empty($objKey->key)) { $objKey->loadKey($key); } - $token = NULL; + $token = null; - if ($decrypt = $objenc->decryptNode($objKey, TRUE)) { - $output = NULL; + if ($decrypt = $objenc->decryptNode($objKey, true)) { + $output = null; if ($decrypt instanceof DOMNode) { if ($decrypt instanceof DOMDocument) { $output = $decrypt->saveXML(); @@ -80,7 +80,7 @@ foreach ($arTests AS $testName=>$testFile) { } $outfile = dirname(__FILE__) . "/basic-doc.xml"; - $res = NULL; + $res = null; if (file_exists($outfile)) { $resDoc = new DOMDocument(); $resDoc->load($outfile); @@ -98,4 +98,4 @@ foreach ($arTests AS $testName=>$testFile) { AOESP_SHA1: Passed AES128-GCM: Passed AES192-GCM: Passed -AES256-GCM: Passed \ No newline at end of file +AES256-GCM: Passed diff --git a/tests/xmlsec-encrypt-aes-gmc.phpt b/tests/xmlsec-encrypt-aes-gmc.phpt index d532627c..21af2aa6 100644 --- a/tests/xmlsec-encrypt-aes-gmc.phpt +++ b/tests/xmlsec-encrypt-aes-gmc.phpt @@ -32,7 +32,7 @@ foreach ($arTests AS $testName=>$testParams) { $objKey->generateSessionKey(); $siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type'=>'public')); - $siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE, TRUE); + $siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', true, true); $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); diff --git a/tests/xmlsec-encrypt-content.phpt b/tests/xmlsec-encrypt-content.phpt index a342f08f..7126281a 100644 --- a/tests/xmlsec-encrypt-content.phpt +++ b/tests/xmlsec-encrypt-content.phpt @@ -16,8 +16,8 @@ $dom->load(dirname(__FILE__) . '/basic-doc.xml'); $objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $objKey->generateSessionKey(); -$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type'=>'public')); -$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE, TRUE); +$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public')); +$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', true, true); $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); diff --git a/tests/xmlsec-encrypt-noreplace.phpt b/tests/xmlsec-encrypt-noreplace.phpt index a4fa9bb9..b1170eaf 100644 --- a/tests/xmlsec-encrypt-noreplace.phpt +++ b/tests/xmlsec-encrypt-noreplace.phpt @@ -14,15 +14,15 @@ $origData = $dom->saveXML(); $objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $objKey->generateSessionKey(); -$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type'=>'public')); -$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE, TRUE); +$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public')); +$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', true, true); $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); $enc->encryptKey($siteKey, $objKey); -$enc->type = XMLSecEnc::Element; -$encNode = $enc->encryptNode($objKey, FALSE); +$enc->type = XMLSecEnc::ELEMENT; +$encNode = $enc->encryptNode($objKey, false); $newData = $dom->saveXML(); if ($newData !== $origData) { diff --git a/tests/xmlsec-encrypt.phpt b/tests/xmlsec-encrypt.phpt index c1c1ae4e..4604a4d5 100644 --- a/tests/xmlsec-encrypt.phpt +++ b/tests/xmlsec-encrypt.phpt @@ -16,8 +16,8 @@ $dom->load(dirname(__FILE__) . '/basic-doc.xml'); $objKey = new XMLSecurityKey(XMLSecurityKey::AES256_CBC); $objKey->generateSessionKey(); -$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type'=>'public')); -$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE, TRUE); +$siteKey = new XMLSecurityKey(XMLSecurityKey::RSA_OAEP_MGF1P, array('type' => 'public')); +$siteKey->loadKey(dirname(__FILE__) . '/mycert.pem', true, true); $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); diff --git a/tests/xmlsec-verify-formatted.phpt b/tests/xmlsec-verify-formatted.phpt index aadd6541..15666d7a 100644 --- a/tests/xmlsec-verify-formatted.phpt +++ b/tests/xmlsec-verify-formatted.phpt @@ -9,12 +9,12 @@ use RobRichards\XMLSecLibs\XMLSecEnc; $doc = new DOMDocument(); $arTests = array('SIGN_TEST_FORMATTED'=>'sign-formatted-test.xml'); -foreach ($arTests AS $testName=>$testFile) { +foreach ($arTests as $testName=>$testFile) { $doc->load(dirname(__FILE__) . "/$testFile"); $objXMLSecDSig = new XMLSecurityDSig(); $objDSig = $objXMLSecDSig->locateSignature($doc); - if (! $objDSig) { + if (!$objDSig) { throw new Exception("Cannot locate Signature Node"); } $objXMLSecDSig->canonicalizeSignedInfo(); @@ -23,20 +23,20 @@ foreach ($arTests AS $testName=>$testFile) { $retVal = $objXMLSecDSig->validateReference(); - if (! $retVal) { + if (!$retVal) { throw new Exception("Reference Validation Failed"); } $objKey = $objXMLSecDSig->locateKey(); - if (! $objKey ) { + if (!$objKey ) { throw new Exception("We have no idea about the key"); } - $key = NULL; + $key = null; $objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig); - if (! $objKeyInfo->key && empty($key)) { - $objKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE); + if (!$objKeyInfo->key && empty($key)) { + $objKey->loadKey(dirname(__FILE__) . '/mycert.pem', true); } print $testName.": "; diff --git a/tests/xmlsec-verify-rsa-sha256.phpt b/tests/xmlsec-verify-rsa-sha256.phpt index 2ebf510d..11836f07 100644 --- a/tests/xmlsec-verify-rsa-sha256.phpt +++ b/tests/xmlsec-verify-rsa-sha256.phpt @@ -11,12 +11,12 @@ use RobRichards\XMLSecLibs\XMLSecEnc; $doc = new DOMDocument(); $arTests = array('SIGN_TEST_RSA_SHA256'=>'sign-sha256-rsa-sha256-test.xml'); -foreach ($arTests AS $testName=>$testFile) { +foreach ($arTests as $testName=>$testFile) { $doc->load(dirname(__FILE__) . "/$testFile"); $objXMLSecDSig = new XMLSecurityDSig(); $objDSig = $objXMLSecDSig->locateSignature($doc); - if (! $objDSig) { + if (!$objDSig) { throw new Exception("Cannot locate Signature Node"); } $objXMLSecDSig->canonicalizeSignedInfo(); @@ -25,20 +25,20 @@ foreach ($arTests AS $testName=>$testFile) { $retVal = $objXMLSecDSig->validateReference(); - if (! $retVal) { + if (!$retVal) { throw new Exception("Reference Validation Failed"); } $objKey = $objXMLSecDSig->locateKey(); - if (! $objKey ) { + if (!$objKey ) { throw new Exception("We have no idea about the key"); } - $key = NULL; + $key = null; $objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig); - if (! $objKeyInfo->key && empty($key)) { - $objKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE); + if (!$objKeyInfo->key && empty($key)) { + $objKey->loadKey(dirname(__FILE__) . '/mycert.pem', true); } print $testName.": "; diff --git a/tests/xmlsec-verify.phpt b/tests/xmlsec-verify.phpt index f005bd05..5d2e3bf1 100755 --- a/tests/xmlsec-verify.phpt +++ b/tests/xmlsec-verify.phpt @@ -9,12 +9,12 @@ use RobRichards\XMLSecLibs\XMLSecEnc; $doc = new DOMDocument(); $arTests = array('SIGN_TEST'=>'sign-basic-test.xml'); -foreach ($arTests AS $testName=>$testFile) { +foreach ($arTests as $testName=>$testFile) { $doc->load(dirname(__FILE__) . "/$testFile"); $objXMLSecDSig = new XMLSecurityDSig(); $objDSig = $objXMLSecDSig->locateSignature($doc); - if (! $objDSig) { + if (!$objDSig) { throw new Exception("Cannot locate Signature Node"); } $objXMLSecDSig->canonicalizeSignedInfo(); @@ -23,20 +23,20 @@ foreach ($arTests AS $testName=>$testFile) { $retVal = $objXMLSecDSig->validateReference(); - if (! $retVal) { + if (!$retVal) { throw new Exception("Reference Validation Failed"); } $objKey = $objXMLSecDSig->locateKey(); - if (! $objKey ) { + if (!$objKey ) { throw new Exception("We have no idea about the key"); } - $key = NULL; + $key = null; $objKeyInfo = XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig); - if (! $objKeyInfo->key && empty($key)) { - $objKey->loadKey(dirname(__FILE__) . '/mycert.pem', TRUE); + if (!$objKeyInfo->key && empty($key)) { + $objKey->loadKey(dirname(__FILE__) . '/mycert.pem', true); } print $testName.": "; From 4bd1979c5cbd0e069367e7d13ede902acb770916 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 11 May 2020 22:01:07 +0200 Subject: [PATCH 4/8] Remove unused code --- src/XMLSecurityDSig.php | 20 -------------------- src/XMLSecurityKey.php | 6 ------ tests/saml/saml-decrypt.phpt | 6 ------ tests/xml-sign-sha256-rsa-sha256.phpt | 2 -- tests/xmlsec-decrypt.phpt | 6 ------ tests/xmlsec-encrypt-aes-gmc.phpt | 5 ----- tests/xmlsec-verify-rsa-sha256.phpt | 2 -- 7 files changed, 47 deletions(-) diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php index 3e2bb5d9..a3f0486e 100644 --- a/src/XMLSecurityDSig.php +++ b/src/XMLSecurityDSig.php @@ -63,12 +63,6 @@ class XMLSecurityDSig public const EXC_C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#'; public const EXC_C14N_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments'; - private const template = ' - - - -'; - private const BASE_TEMPLATE = ' @@ -163,20 +157,6 @@ public static function generateGUID($prefix = 'pfx') return $guid; } - /** - * Generate guid - * - * @param string $prefix Prefix to use for guid. defaults to pfx - * - * @return string The generated guid - * - * @deprecated Method deprecated in Release 1.4.1 - */ - public static function generate_GUID($prefix = 'pfx') - { - return self::generateGUID($prefix); - } - /** * @param DOMDocument $objDoc * @param int $pos diff --git a/src/XMLSecurityKey.php b/src/XMLSecurityKey.php index c93b226b..89b04cf8 100644 --- a/src/XMLSecurityKey.php +++ b/src/XMLSecurityKey.php @@ -429,9 +429,6 @@ private function encryptSymmetric($data) $this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher'])); $authTag = null; if (in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { - if (version_compare(PHP_VERSION, '7.1.0') < 0) { - throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); - } $authTag = openssl_random_pseudo_bytes(self::AUTHTAG_LENGTH); $encrypted = openssl_encrypt( $data, @@ -471,9 +468,6 @@ private function decryptSymmetric($data) $data = substr($data, $iv_length); $authTag = null; if (in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { - if (version_compare(PHP_VERSION, '7.1.0') < 0) { - throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); - } // obtain and remove the authentication tag $offset = 0 - self::AUTHTAG_LENGTH; $authTag = substr($data, $offset); diff --git a/tests/saml/saml-decrypt.phpt b/tests/saml/saml-decrypt.phpt index 144a4a75..8f79488f 100644 --- a/tests/saml/saml-decrypt.phpt +++ b/tests/saml/saml-decrypt.phpt @@ -5,12 +5,6 @@ Basic Decryption require(dirname(__FILE__) . '/../../xmlseclibs.php'); use RobRichards\XMLSecLibs\XMLSecEnc; - // Travis not honoring SKIPIF - if (version_compare(PHP_VERSION, '7.1.0') < 0) { - print "KYzsRqRzQY5qp+bv9T8bHA/AvsI=\n"; - exit; - } - /* When we need to locate our own key based on something like a key name */ function locateLocalKey($objKey) { /* In this example the key is identified by filename */ diff --git a/tests/xml-sign-sha256-rsa-sha256.phpt b/tests/xml-sign-sha256-rsa-sha256.phpt index 2faeb5aa..2218d381 100644 --- a/tests/xml-sign-sha256-rsa-sha256.phpt +++ b/tests/xml-sign-sha256-rsa-sha256.phpt @@ -1,7 +1,5 @@ --TEST-- Signature RSA SHA256 ---SKIPIF-- - --FILE-- $testFile) { $output = null; print "$testName: "; - // Skip AES tests is PHP < 7.1.0 - if ((substr($testName, 0, 3) === "AES") && (version_compare(PHP_VERSION, '7.1.0') < 0)) { - print "Passed\n"; - continue; - } - $doc->load(dirname(__FILE__) . "/$testFile"); try { diff --git a/tests/xmlsec-encrypt-aes-gmc.phpt b/tests/xmlsec-encrypt-aes-gmc.phpt index 21af2aa6..cc9ceaa6 100644 --- a/tests/xmlsec-encrypt-aes-gmc.phpt +++ b/tests/xmlsec-encrypt-aes-gmc.phpt @@ -19,11 +19,6 @@ foreach ($arTests AS $testName=>$testParams) { } print "$testName: "; - // Travis not honoring SKIPIF - if (version_compare(PHP_VERSION, '7.1.0') < 0) { - print "EncryptedData\n"; - continue; - } $dom = new DOMDocument(); $dom->load(dirname(__FILE__) . '/basic-doc.xml'); diff --git a/tests/xmlsec-verify-rsa-sha256.phpt b/tests/xmlsec-verify-rsa-sha256.phpt index 11836f07..44430500 100644 --- a/tests/xmlsec-verify-rsa-sha256.phpt +++ b/tests/xmlsec-verify-rsa-sha256.phpt @@ -1,7 +1,5 @@ --TEST-- Verify RSA SHA256 ---SKIPIF-- - --FILE-- Date: Mon, 11 May 2020 22:09:41 +0200 Subject: [PATCH 5/8] PHPCS; PSR-12 --- src/XMLSecEnc.php | 30 ++++++++++++++--------------- tests/encrypteddata-node-order.phpt | 2 +- tests/xmlsec-encrypt-aes-gmc.phpt | 2 +- tests/xmlsec-encrypt-content.phpt | 2 +- tests/xmlsec-encrypt.phpt | 2 +- 5 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php index 1e31453d..4d454141 100644 --- a/src/XMLSecEnc.php +++ b/src/XMLSecEnc.php @@ -51,14 +51,14 @@ class XMLSecEnc { - private const template = " + private const TEMPLATE = " "; - public const Element = 'http://www.w3.org/2001/04/xmlenc#Element'; - public const Content = 'http://www.w3.org/2001/04/xmlenc#Content'; + public const ELEMENT = 'http://www.w3.org/2001/04/xmlenc#Element'; + public const CONTENT = 'http://www.w3.org/2001/04/xmlenc#Content'; public const URI = 3; public const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#'; @@ -79,13 +79,13 @@ class XMLSecEnc public function __construct() { - $this->_resetTemplate(); + $this->resetTemplate(); } - private function _resetTemplate() + private function resetTemplate() { $this->encdoc = new DOMDocument(); - $this->encdoc->loadXML(self::template); + $this->encdoc->loadXML(self::TEMPLATE); } /** @@ -100,7 +100,7 @@ public function addReference($name, $node, $type) throw new Exception('$node is not of type DOMNode'); } $curencdoc = $this->encdoc; - $this->_resetTemplate(); + $this->resetTemplate(); $encdoc = $this->encdoc; $this->encdoc = $curencdoc; $refuri = XMLSecurityDSig::generateGUID(); @@ -143,16 +143,16 @@ public function encryptNode($objKey, $replace = true) throw new Exception('Error locating CipherValue element within template'); } switch ($this->type) { - case (self::Element): + case (self::ELEMENT): $data = $doc->saveXML($this->rawNode); - $this->encdoc->documentElement->setAttribute('Type', self::Element); + $this->encdoc->documentElement->setAttribute('Type', self::ELEMENT); break; - case (self::Content): + case (self::CONTENT): $children = $this->rawNode->childNodes; foreach ($children as $child) { $data .= $doc->saveXML($child); } - $this->encdoc->documentElement->setAttribute('Type', self::Content); + $this->encdoc->documentElement->setAttribute('Type', self::CONTENT); break; default: throw new Exception('Type is currently not supported'); @@ -173,14 +173,14 @@ public function encryptNode($objKey, $replace = true) if ($replace) { switch ($this->type) { - case (self::Element): + case (self::ELEMENT): if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) { return $this->encdoc; } $importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true); $this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode); return $importEnc; - case (self::Content): + case (self::CONTENT): $importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true); while ($this->rawNode->firstChild) { $this->rawNode->removeChild($this->rawNode->firstChild); @@ -270,7 +270,7 @@ public function decryptNode($objKey, $replace = true) $decrypted = $objKey->decryptData($encryptedData); if ($replace) { switch ($this->type) { - case (self::Element): + case (self::ELEMENT): $newdoc = new DOMDocument(); $newdoc->loadXML($decrypted); if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) { @@ -279,7 +279,7 @@ public function decryptNode($objKey, $replace = true) $importEnc = $this->rawNode->ownerDocument->importNode($newdoc->documentElement, true); $this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode); return $importEnc; - case (self::Content): + case (self::CONTENT): if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) { $doc = $this->rawNode; } else { diff --git a/tests/encrypteddata-node-order.phpt b/tests/encrypteddata-node-order.phpt index 085bdcab..2ad06cbb 100644 --- a/tests/encrypteddata-node-order.phpt +++ b/tests/encrypteddata-node-order.phpt @@ -22,7 +22,7 @@ $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); $enc->encryptKey($siteKey, $objKey); -$enc->type = XMLSecEnc::Content; +$enc->type = XMLSecEnc::CONTENT; $encNode = $enc->encryptNode($objKey); $nodeOrder = array( diff --git a/tests/xmlsec-encrypt-aes-gmc.phpt b/tests/xmlsec-encrypt-aes-gmc.phpt index cc9ceaa6..1cce0e7f 100644 --- a/tests/xmlsec-encrypt-aes-gmc.phpt +++ b/tests/xmlsec-encrypt-aes-gmc.phpt @@ -33,7 +33,7 @@ foreach ($arTests AS $testName=>$testParams) { $enc->setNode($dom->documentElement); $enc->encryptKey($siteKey, $objKey); - $enc->type = XMLSecEnc::Element; + $enc->type = XMLSecEnc::ELEMENT; $encNode = $enc->encryptNode($objKey); $dom->save(dirname(__FILE__) . "/$testFile"); diff --git a/tests/xmlsec-encrypt-content.phpt b/tests/xmlsec-encrypt-content.phpt index 7126281a..586f5a0b 100644 --- a/tests/xmlsec-encrypt-content.phpt +++ b/tests/xmlsec-encrypt-content.phpt @@ -23,7 +23,7 @@ $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); $enc->encryptKey($siteKey, $objKey); -$enc->type = XMLSecEnc::Content; +$enc->type = XMLSecEnc::CONTENT; $encNode = $enc->encryptNode($objKey); $dom->save(dirname(__FILE__) . '/oaep_sha1.xml'); diff --git a/tests/xmlsec-encrypt.phpt b/tests/xmlsec-encrypt.phpt index 4604a4d5..0c8f344c 100644 --- a/tests/xmlsec-encrypt.phpt +++ b/tests/xmlsec-encrypt.phpt @@ -23,7 +23,7 @@ $enc = new XMLSecEnc(); $enc->setNode($dom->documentElement); $enc->encryptKey($siteKey, $objKey); -$enc->type = XMLSecEnc::Element; +$enc->type = XMLSecEnc::ELEMENT; $encNode = $enc->encryptNode($objKey); $dom->save(dirname(__FILE__) . '/oaep_sha1.xml'); From c51dc5b241efda77c99323d65f2f5ef01006d113 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Mon, 11 May 2020 22:59:12 +0200 Subject: [PATCH 6/8] Fully typehint source --- src/Utils/XPath.php | 20 ++- src/XMLSecEnc.php | 137 ++++++++++------ src/XMLSecurityDSig.php | 349 ++++++++++++++++++++++++++++------------ src/XMLSecurityKey.php | 179 ++++++++++++++------- 4 files changed, 473 insertions(+), 212 deletions(-) diff --git a/src/Utils/XPath.php b/src/Utils/XPath.php index 890aaa45..e2e668e4 100644 --- a/src/Utils/XPath.php +++ b/src/Utils/XPath.php @@ -4,13 +4,25 @@ class XPath { + /** @var string */ public const ALPHANUMERIC = '\w\d'; + + /** @var string */ public const NUMERIC = '\d'; + + /** @var string */ public const LETTERS = '\w'; + + /** @var string */ public const EXTENDED_ALPHANUMERIC = '\w\d\s\-_:\.'; + /** @var string */ public const SINGLE_QUOTE = '\''; + + /** @var string */ public const DOUBLE_QUOTE = '"'; + + /** @var string */ public const ALL_QUOTES = '[\'"]'; @@ -22,7 +34,7 @@ class XPath * * @return string The filtered attribute value. */ - public static function filterAttrValue($value, $quotes = self::ALL_QUOTES) + public static function filterAttrValue(string $value, string $quotes = self::ALL_QUOTES): string { return preg_replace('#' . $quotes . '#', '', $value); } @@ -32,12 +44,12 @@ public static function filterAttrValue($value, $quotes = self::ALL_QUOTES) * Filter an attribute name for save inclusion in an XPath query. * * @param string $name The attribute name to filter. - * @param mixed $allow The set of characters to allow. Can be one of the constants provided by this class, or a - * custom regex excluding the '#' character (used as delimiter). + * @param string $allow The set of characters to allow. Can be one of the constants provided by this class, or a + * custom regex excluding the '#' character (used as delimiter). * * @return string The filtered attribute name. */ - public static function filterAttrName($name, $allow = self::EXTENDED_ALPHANUMERIC) + public static function filterAttrName(string $name, string $allow = self::EXTENDED_ALPHANUMERIC): string { return preg_replace('#[^' . $allow . ']#', '', $name); } diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php index 4d454141..582b95a6 100644 --- a/src/XMLSecEnc.php +++ b/src/XMLSecEnc.php @@ -51,54 +51,70 @@ class XMLSecEnc { + /** @var string */ private const TEMPLATE = " "; + /** @var string */ public const ELEMENT = 'http://www.w3.org/2001/04/xmlenc#Element'; + + /** @var string */ public const CONTENT = 'http://www.w3.org/2001/04/xmlenc#Content'; + + /** @var string */ public const URI = 3; + + /** @var string */ public const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#'; - /** @var null|DOMDocument */ + /** @var null|\DOMDocument */ private $encdoc = null; - /** @var null|DOMNode */ + /** @var null|\DOMNode */ private $rawNode = null; /** @var null|string */ public $type = null; - /** @var null|DOMElement */ + /** @var null|\DOMElement */ public $encKey = null; /** @var array */ private $references = array(); + public function __construct() { $this->resetTemplate(); } - private function resetTemplate() + + /** + * @retun void + */ + private function resetTemplate(): void { $this->encdoc = new DOMDocument(); $this->encdoc->loadXML(self::TEMPLATE); } + /** * @param string $name - * @param DOMNode $node + * @param \DOMNode $node * @param string $type - * @throws Exception + * @return void + * @throws \Exception */ - public function addReference($name, $node, $type) + public function addReference(string $name, DOMNode $node, string $type): void { if (!($node instanceof DOMNode)) { throw new Exception('$node is not of type DOMNode'); } + $curencdoc = $this->encdoc; $this->resetTemplate(); $encdoc = $this->encdoc; @@ -109,24 +125,27 @@ public function addReference($name, $node, $type) $this->references[$name] = array("node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri); } + /** - * @param DOMNode $node + * @param \DOMNode $node + * @return void */ - public function setNode($node) + public function setNode(DOMNode $node): void { $this->rawNode = $node; } + /** * Encrypt the selected node with the given key. * - * @param XMLSecurityKey $objKey The encryption key and algorithm. + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $objKey The encryption key and algorithm. * @param bool $replace Whether the encrypted node should be replaced in the original tree. Default is true. - * @throws Exception + * @throws \Exception * - * @return DOMElement The -element. + * @return \DOMElement The -element. */ - public function encryptNode($objKey, $replace = true) + public function encryptNode(XMLSecurityKey $objKey, bool $replace = true): DOMElement { $data = ''; if (empty($this->rawNode)) { @@ -193,11 +212,13 @@ public function encryptNode($objKey, $replace = true) } } + /** - * @param XMLSecurityKey $objKey - * @throws Exception + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $objKey + * @return void + * @throws \Exception */ - public function encryptReferences($objKey) + public function encryptReferences(XMLSecurityKey $objKey): void { $curRawNode = $this->rawNode; $curType = $this->type; @@ -218,13 +239,14 @@ public function encryptReferences($objKey) $this->type = $curType; } + /** * Retrieve the CipherValue text from this encrypted node. * - * @throws Exception + * @throws \Exception * @return string|null The Ciphervalue text, or null if no CipherValue is found. */ - public function getCipherValue() + public function getCipherValue(): ?string { if (empty($this->rawNode)) { throw new Exception('Node to decrypt has not been set'); @@ -245,6 +267,7 @@ public function getCipherValue() return base64_decode($node->nodeValue); } + /** * Decrypt this encrypted node. * @@ -253,13 +276,14 @@ public function getCipherValue() * If $replace is true, we will insert the decrypted element(s) into the * document, and return the decrypted element(s). * - * @param XMLSecurityKey $objKey The decryption key that should be used when decrypting the node. - * @param boolean $replace Whether we should replace the encrypted node in the + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $objKey + * The decryption key that should be used when decrypting the node. + * @param bool $replace Whether we should replace the encrypted node in the * XML document with the decrypted data. The default is true. * - * @return string|DOMElement The decrypted data. + * @return string|\DOMElement The decrypted data. */ - public function decryptNode($objKey, $replace = true) + public function decryptNode(XMLSecurityKey $objKey, bool $replace = true) { if (!($objKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); @@ -301,15 +325,17 @@ public function decryptNode($objKey, $replace = true) } } + /** * Encrypt the XMLSecurityKey * - * @param XMLSecurityKey $srcKey - * @param XMLSecurityKey $rawKey + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $srcKey + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $rawKey * @param bool $append - * @throws Exception + * @return void + * @throws \Exception */ - public function encryptKey($srcKey, $rawKey, $append = true) + public function encryptKey(XMLSecurityKey $srcKey, XMLSecurityKey $rawKey, bool $append = true): void { if (!($srcKey instanceof XMLSecurityKey) || !($rawKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); @@ -327,7 +353,7 @@ public function encryptKey($srcKey, $rawKey, $append = true) $this->encKey = $encKey; } $encMethod = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod')); - $encMethod->setAttribute('Algorithm', $srcKey->getAlgorith()); + $encMethod->setAttribute('Algorithm', $srcKey->getAlgorithm()); if (!empty($srcKey->name)) { $keyInfo = $encKey->appendChild( $this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo') @@ -346,15 +372,15 @@ public function encryptKey($srcKey, $rawKey, $append = true) $dataRef->setAttribute("URI", '#' . $refuri); } } - return; } + /** - * @param XMLSecurityKey $encKey - * @return DOMElement|string - * @throws Exception + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $encKey + * @return \DOMElement|string + * @throws \Exception */ - public function decryptKey($encKey) + public function decryptKey(XMLSecurityKey $encKey) { if (!$encKey->isEncrypted) { throw new Exception("Key is not Encrypted"); @@ -365,68 +391,80 @@ public function decryptKey($encKey) return $this->decryptNode($encKey, false); } + /** - * @param DOMDocument $element - * @return DOMNode|null + * @param \DOMDocument $element + * @return \DOMNode|null */ - public function locateEncryptedData($element) + public function locateEncryptedData(DOMDocument $element): ?DOMNode { if ($element instanceof DOMDocument) { $doc = $element; } else { $doc = $element->ownerDocument; } + if ($doc) { $xpath = new DOMXPath($doc); $query = "//*[local-name()='EncryptedData' and namespace-uri()='" . self::XMLENCNS . "']"; $nodeset = $xpath->query($query); return $nodeset->item(0); } + return null; } + /** * Returns the key from the DOM - * @param null|DOMNode $node - * @return null|XMLSecurityKey + * @param \DOMNode|null $node + * @return \RobRichards\XMLSecLibs\XMLSecurityKey|null */ - public function locateKey($node = null) + public function locateKey(DOMNode $node = null): ?XMLSecurityKey { if (empty($node)) { $node = $this->rawNode; } + if (!($node instanceof DOMNode)) { return null; } + if ($doc = $node->ownerDocument) { $xpath = new DOMXPath($doc); $xpath->registerNamespace('xmlsecenc', self::XMLENCNS); $query = ".//xmlsecenc:EncryptionMethod"; $nodeset = $xpath->query($query, $node); + if ($encmeth = $nodeset->item(0)) { - $attrAlgorithm = $encmeth->getAttribute("Algorithm"); + $attrAlgorithm = $encmeth->getAttribute("Algorithm"); + try { $objKey = new XMLSecurityKey($attrAlgorithm, array('type' => 'private')); } catch (Exception $e) { return null; } + return $objKey; } } + return null; } + /** - * @param null|XMLSecurityKey $objBaseKey - * @param null|DOMNode $node - * @return null|XMLSecurityKey - * @throws Exception + * @param \RobRichards\XMLSecLibs\XMLSecurityKey|null $objBaseKey + * @param \DOMNode|null $node + * @return \RobRichards\XMLSecLibs\XMLSecurityKey|null + * @throws \Exception */ - public static function staticLocateKeyInfo($objBaseKey = null, $node = null) + public static function staticLocateKeyInfo(XMLSecurityKey $objBaseKey = null, DOMNode $node = null): ?XMLSecurityKey { if (empty($node) || !($node instanceof DOMNode)) { return null; } + $doc = $node->ownerDocument; if (!$doc) { return null; @@ -438,6 +476,7 @@ public static function staticLocateKeyInfo($objBaseKey = null, $node = null) $query = "./xmlsecdsig:KeyInfo"; $nodeset = $xpath->query($query, $node); $encmeth = $nodeset->item(0); + if (!$encmeth) { /* No KeyInfo in EncryptedData / EncryptedKey. */ return $objBaseKey; @@ -511,16 +550,18 @@ public static function staticLocateKeyInfo($objBaseKey = null, $node = null) return $objBaseKey; } + /** - * @param null|XMLSecurityKey $objBaseKey - * @param null|DOMNode $node - * @return null|XMLSecurityKey + * @param \RobRichards\XMLSecLibs\XMLSecurityKey|null $objBaseKey + * @param \DOMNode|null $node + * @return \RobRichards\XMLSecLibs\XMLSecurityKey|null */ - public function locateKeyInfo($objBaseKey = null, $node = null) + public function locateKeyInfo(XMLSecurityKey $objBaseKey = null, DOMNode $node = null): XMLSecurityKey { if (empty($node)) { $node = $this->rawNode; } + return self::staticLocateKeyInfo($objBaseKey, $node); } } diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php index a3f0486e..f261a262 100644 --- a/src/XMLSecurityDSig.php +++ b/src/XMLSecurityDSig.php @@ -51,25 +51,44 @@ class XMLSecurityDSig { + /** @var string */ public const XMLDSIGNS = 'http://www.w3.org/2000/09/xmldsig#'; + + /** @var string */ public const SHA1 = 'http://www.w3.org/2000/09/xmldsig#sha1'; + + /** @var string */ public const SHA256 = 'http://www.w3.org/2001/04/xmlenc#sha256'; + + /** @var string */ public const SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#sha384'; + + /** @var string */ public const SHA512 = 'http://www.w3.org/2001/04/xmlenc#sha512'; + + /** @var string */ public const RIPEMD160 = 'http://www.w3.org/2001/04/xmlenc#ripemd160'; + /** @var string */ public const C14N = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; + + /** @var string */ public const C14N_COMMENTS = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments'; + + /** @var string */ public const EXC_C14N = 'http://www.w3.org/2001/10/xml-exc-c14n#'; + + /** @var string */ public const EXC_C14N_COMMENTS = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments'; + /** @var string */ private const BASE_TEMPLATE = ' '; - /** @var DOMElement|null */ + /** @var \DOMElement|null */ public $sigNode = null; /** @var array */ @@ -81,7 +100,7 @@ class XMLSecurityDSig /** @var string|null */ private $signedInfo = null; - /** @var DomXPath|null */ + /** @var \DomXPath|null */ private $xPathCtx = null; /** @var string|null */ @@ -99,46 +118,54 @@ class XMLSecurityDSig */ private $validatedNodes = null; + /** - * @param string $prefix + * @param string|null $prefix */ - public function __construct($prefix = 'ds') + public function __construct(?string $prefix = 'ds') { $template = self::BASE_TEMPLATE; + if (!empty($prefix)) { $this->prefix = $prefix . ':'; $search = array("ownerDocument; } + if ($doc) { $xpath = new DOMXPath($doc); $xpath->registerNamespace('secdsig', self::XMLDSIGNS); @@ -177,35 +206,43 @@ public function locateSignature($objDoc, $pos = 0) $this->sigNode = $nodeset->item($pos); $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); + if ($nodeset->length > 1) { throw new Exception("Invalid structure - Too many SignedInfo elements found"); } + return $this->sigNode; } + return null; } + /** * @param string $name - * @param null|string $value - * @return DOMElement + * @param string|null $value + * @return \DOMElement */ - public function createNewSignNode($name, $value = null) + public function createNewSignNode(string $name, string $value = null): DOMElement { $doc = $this->sigNode->ownerDocument; + if (!is_null($value)) { $node = $doc->createElementNS(self::XMLDSIGNS, $this->prefix . $name, $value); } else { $node = $doc->createElementNS(self::XMLDSIGNS, $this->prefix . $name); } + return $node; } + /** * @param string $method - * @throws Exception + * @return void + * @throws \Exception */ - public function setCanonicalMethod($method) + public function setCanonicalMethod(string $method): void { switch ($method) { case 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315': @@ -217,6 +254,7 @@ public function setCanonicalMethod($method) default: throw new Exception('Invalid Canonical Method'); } + if ($xpath = $this->getXPathObj()) { $query = './' . $this->searchpfx . ':SignedInfo'; $nodeset = $xpath->query($query, $this->sigNode); @@ -232,15 +270,20 @@ public function setCanonicalMethod($method) } } + /** - * @param DOMNode $node + * @param \DOMNode $node * @param string $canonicalmethod - * @param null|array $arXPath - * @param null|array $prefixList + * @param array|null $arXPath + * @param array|null $prefixList * @return string */ - private function canonicalizeData($node, $canonicalmethod, $arXPath = null, $prefixList = null) - { + private function canonicalizeData( + DOMNode $node, + string $canonicalmethod, + array $arXPath = null, + array $prefixList = null + ): string { $exclusive = false; $withComments = false; switch ($canonicalmethod) { @@ -282,21 +325,24 @@ private function canonicalizeData($node, $canonicalmethod, $arXPath = null, $pre return $node->C14N($exclusive, $withComments, $arXPath, $prefixList); } + /** - * @return null|string + * @return string|null */ public function canonicalizeSignedInfo() { - $doc = $this->sigNode->ownerDocument; $canonicalmethod = null; + if ($doc) { $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); + if ($nodeset->length > 1) { throw new Exception("Invalid structure - Too many SignedInfo elements found"); } + if ($signInfoNode = $nodeset->item(0)) { $query = "./secdsig:CanonicalizationMethod"; $nodeset = $xpath->query($query, $signInfoNode); @@ -314,21 +360,24 @@ public function canonicalizeSignedInfo() } } } + $this->signedInfo = $this->canonicalizeData($signInfoNode, $canonicalmethod, null, $prefixList); return $this->signedInfo; } } + return null; } + /** * @param string $digestAlgorithm * @param string $data * @param bool $encode * @return string - * @throws Exception + * @throws \Exception */ - public function calculateDigest($digestAlgorithm, $data, $encode = true) + public function calculateDigest(string $digestAlgorithm, string $data, bool $encode = true): string { switch ($digestAlgorithm) { case self::SHA1: @@ -351,18 +400,21 @@ public function calculateDigest($digestAlgorithm, $data, $encode = true) } $digest = hash($alg, $data, true); + if ($encode) { $digest = base64_encode($digest); } + return $digest; } + /** - * @param $refNode + * @param \DOMNode $refNode * @param string $data * @return bool */ - public function validateDigest($refNode, $data) + public function validateDigest(DOMNode $refNode, string $data): bool { $xpath = new DOMXPath($refNode->ownerDocument); $xpath->registerNamespace('secdsig', self::XMLDSIGNS); @@ -371,16 +423,18 @@ public function validateDigest($refNode, $data) $digValue = $this->calculateDigest($digestAlgorithm, $data, false); $query = 'string(./secdsig:DigestValue)'; $digestValue = $xpath->evaluate($query, $refNode); + return ($digValue === base64_decode($digestValue)); } + /** - * @param $refNode - * @param DOMNode $objData + * @param \DOMNode $refNode + * @param \DOMNode $objData * @param bool $includeCommentNodes * @return string */ - public function processTransforms($refNode, $objData, $includeCommentNodes = true) + public function processTransforms(DOMNode $refNode, DOMNode $objData, bool $includeCommentNodes = true): string { $data = $objData; $xpath = new DOMXPath($refNode->ownerDocument); @@ -390,8 +444,10 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru $canonicalMethod = 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315'; $arXPath = null; $prefixList = null; + foreach ($nodelist as $transform) { $algorithm = $transform->getAttribute("Algorithm"); + switch ($algorithm) { case 'http://www.w3.org/2001/10/xml-exc-c14n#': case 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments': @@ -457,17 +513,20 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru break; } } + if ($data instanceof DOMNode) { $data = $this->canonicalizeData($objData, $canonicalMethod, $arXPath, $prefixList); } + return $data; } + /** - * @param DOMNode $refNode + * @param \DOMNode $refNode * @return bool */ - public function processRefNode($refNode) + public function processRefNode(DOMNode $refNode): bool { $dataObject = null; @@ -492,6 +551,7 @@ public function processRefNode($refNode) $xPath->registerNamespace($nspf, $ns); } } + $iDlist = '@Id="' . XPath::filterAttrValue($identifier, XPath::DOUBLE_QUOTE) . '"'; if (is_array($this->idKeys)) { foreach ($this->idKeys as $idKey) { @@ -499,6 +559,7 @@ public function processRefNode($refNode) XPath::filterAttrValue($identifier, XPath::DOUBLE_QUOTE) . '"'; } } + $query = '//*[' . $iDlist . ']'; $dataObject = $xPath->query($query)->item(0); } else { @@ -513,6 +574,7 @@ public function processRefNode($refNode) $dataObject = $refNode->ownerDocument; } + $data = $this->processTransforms($refNode, $dataObject, $includeCommentNodes); if (!$this->validateDigest($refNode, $data)) { return false; @@ -530,58 +592,69 @@ public function processRefNode($refNode) return true; } + /** - * @param DOMNode $refNode - * @return null + * @param \DOMNode $refNode + * @return string|null */ - public function getRefNodeID($refNode) + public function getRefNodeID(DOMNode $refNode): ?string { if ($uri = $refNode->getAttribute("URI")) { $arUrl = parse_url($uri); + if (empty($arUrl['path'])) { if ($identifier = $arUrl['fragment']) { return $identifier; } } } + return null; } + /** * @return array - * @throws Exception + * @throws \Exception */ - public function getRefIDs() + public function getRefIDs(): array { $refids = array(); $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo[1]/secdsig:Reference"; $nodeset = $xpath->query($query, $this->sigNode); + if ($nodeset->length == 0) { throw new Exception("Reference nodes not found"); } + foreach ($nodeset as $refNode) { $refids[] = $this->getRefNodeID($refNode); } + return $refids; } + /** * @return bool - * @throws Exception + * @throws \Exception */ - public function validateReference() + public function validateReference(): bool { $docElem = $this->sigNode->ownerDocument->documentElement; + if (!$docElem->isSameNode($this->sigNode)) { if ($this->sigNode->parentNode != null) { $this->sigNode->parentNode->removeChild($this->sigNode); } } + $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo[1]/secdsig:Reference"; $nodeset = $xpath->query($query, $this->sigNode); + if ($nodeset->length == 0) { throw new Exception("Reference nodes not found"); } @@ -596,18 +669,26 @@ public function validateReference() throw new Exception("Reference validation failed"); } } + return true; } + /** - * @param DOMNode $sinfoNode - * @param DOMDocument $node + * @param \DOMNode $sinfoNode + * @param \DOMDocument|\DOMElement $node * @param string $algorithm - * @param null|array $arTransforms - * @param null|array $options + * @param array|null $arTransforms + * @param array|null $options + * @return void */ - private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms = null, $options = null) - { + private function addRefInternal( + DOMNode $sinfoNode, + $node, + string $algorithm, + array $arTransforms = null, + array $options = null + ): void { $prefix = null; $prefix_ns = null; $id_name = 'Id'; @@ -689,34 +770,48 @@ private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms = n $refNode->appendChild($digestValue); } + /** - * @param DOMDocument $node + * @param \DOMDocument $node * @param string $algorithm - * @param null|array $arTransforms - * @param null|array $options + * @param array|null $arTransforms + * @param array|null $options + * @return void */ - public function addReference($node, $algorithm, $arTransforms = null, $options = null) - { + public function addReference( + DOMDocument $node, + string $algorithm, + array $arTransforms = null, + array $options = null + ): void { if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); + if ($sInfo = $nodeset->item(0)) { $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options); } } } + /** * @param array $arNodes * @param string $algorithm - * @param null|array $arTransforms - * @param null|array $options + * @param array|null $arTransforms + * @param array|null $options + * @return void */ - public function addReferenceList($arNodes, $algorithm, $arTransforms = null, $options = null) - { + public function addReferenceList( + array $arNodes, + string $algorithm, + array $arTransforms = null, + array $options = null + ): void { if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); + if ($sInfo = $nodeset->item(0)) { foreach ($arNodes as $node) { $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options); @@ -725,19 +820,22 @@ public function addReferenceList($arNodes, $algorithm, $arTransforms = null, $op } } + /** - * @param DOMElement|string $data - * @param null|string $mimetype - * @param null|string $encoding - * @return DOMElement + * @param \DOMElement|string $data + * @param string|null $mimetype + * @param string|null $encoding + * @return \DOMElement */ - public function addObject($data, $mimetype = null, $encoding = null) + public function addObject(DOMElement $data, string $mimetype = null, string $encoding = null): DOMElement { $objNode = $this->createNewSignNode('Object'); $this->sigNode->appendChild($objNode); + if (!empty($mimetype)) { $objNode->setAttribute('MimeType', $mimetype); } + if (!empty($encoding)) { $objNode->setAttribute('Encoding', $encoding); } @@ -747,40 +845,47 @@ public function addObject($data, $mimetype = null, $encoding = null) } else { $newData = $this->sigNode->ownerDocument->createTextNode($data); } - $objNode->appendChild($newData); + $objNode->appendChild($newData); return $objNode; } + /** - * @param null|DOMNode $node - * @return null|XMLSecurityKey + * @param \DOMNode|null $node + * @return \RobRichards\XMLSecLibs\XMLSecurityKey|null */ - public function locateKey($node = null) + public function locateKey(DOMNode $node = null): ?XMLSecurityKey { if (empty($node)) { $node = $this->sigNode; } + if (!($node instanceof DOMNode)) { return null; } + if ($doc = $node->ownerDocument) { $xpath = new DOMXPath($doc); $xpath->registerNamespace('secdsig', self::XMLDSIGNS); $query = "string(./secdsig:SignedInfo/secdsig:SignatureMethod/@Algorithm)"; $algorithm = $xpath->evaluate($query, $node); + if ($algorithm) { try { $objKey = new XMLSecurityKey($algorithm, array('type' => 'public')); } catch (Exception $e) { return null; } + return $objKey; } } + return null; } + /** * Returns: * Bool when verifying HMAC_SHA1; @@ -793,38 +898,43 @@ public function locateKey($node = null) * PHP, -1 will be cast to True when in boolean context. Always check the * return value in a strictly typed way, e.g. "$obj->verify(...) === 1". * - * @param XMLSecurityKey $objKey + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $objKey * @return bool|int - * @throws Exception + * @throws \Exception */ - public function verify($objKey) + public function verify(XMLSecurityKey $objKey) { $doc = $this->sigNode->ownerDocument; $xpath = new DOMXPath($doc); $xpath->registerNamespace('secdsig', self::XMLDSIGNS); $query = "string(./secdsig:SignatureValue)"; $sigValue = $xpath->evaluate($query, $this->sigNode); + if (empty($sigValue)) { throw new Exception("Unable to locate SignatureValue"); } + return $objKey->verifySignature($this->signedInfo, base64_decode($sigValue)); } + /** - * @param XMLSecurityKey $objKey + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $objKey * @param string $data * @return mixed|string */ - public function signData($objKey, $data) + public function signData(XMLSecurityKey $objKey, string $data) { return $objKey->signData($data); } + /** - * @param XMLSecurityKey $objKey - * @param null|DOMNode $appendToNode + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $objKey + * @param \DOMNode|null $appendToNode + * @return void */ - public function sign($objKey, $appendToNode = null) + public function sign(XMLSecurityKey $objKey, DOMNode $appendToNode = null): void { // If we have a parent node append it now so C14N properly works if ($appendToNode != null) { @@ -832,9 +942,11 @@ public function sign($objKey, $appendToNode = null) $this->appendSignature($appendToNode); $this->sigNode = $appendToNode->lastChild; } + if ($xpath = $this->getXPathObj()) { $query = "./secdsig:SignedInfo"; $nodeset = $xpath->query($query, $this->sigNode); + if ($sInfo = $nodeset->item(0)) { $query = "./secdsig:SignatureMethod"; $nodeset = $xpath->query($query, $sInfo); @@ -843,6 +955,7 @@ public function sign($objKey, $appendToNode = null) $data = $this->canonicalizeData($sInfo, $this->canonicalMethod); $sigValue = base64_encode($this->signData($objKey, $data)); $sigValueNode = $this->createNewSignNode('SignatureValue', $sigValue); + if ($infoSibling = $sInfo->nextSibling) { $infoSibling->parentNode->insertBefore($sigValueNode, $infoSibling); } else { @@ -852,15 +965,21 @@ public function sign($objKey, $appendToNode = null) } } - public function appendCert() + + /** + * @return void + */ + public function appendCert(): void { } + /** - * @param XMLSecurityKey $objKey - * @param null|DOMNode $parent + * @param \RobRichards\XMLSecLibs\XMLSecurityKey $objKey + * @param \DOMNode|null $parent + * @return void */ - public function appendKey($objKey, $parent = null) + public function appendKey(XMLSecurityKey $objKey, DOMNode $parent = null): void { $objKey->serializeKey($parent); } @@ -872,14 +991,13 @@ public function appendKey($objKey, $parent = null) * The signature element will be appended to the element, unless $beforeNode is specified. If $beforeNode * is specified, the signature element will be inserted as the last element before $beforeNode. * - * @param DOMNode $node The node the signature element should be inserted into. - * @param DOMNode $beforeNode The node the signature element should be located before. + * @param \DOMNode $node The node the signature element should be inserted into. + * @param \DOMNode|null $beforeNode The node the signature element should be located before. * - * @return DOMNode The signature element node + * @return \DOMNode The signature element node */ - public function insertSignature($node, $beforeNode = null) + public function insertSignature(DOMNode $node, DOMNode $beforeNode = null): DOMNode { - $document = $node->ownerDocument; $signatureElement = $document->importNode($this->sigNode, true); @@ -890,45 +1008,51 @@ public function insertSignature($node, $beforeNode = null) } } + /** - * @param DOMNode $parentNode + * @param \DOMNode $parentNode * @param bool $insertBefore - * @return DOMNode + * @return \DOMNode */ - public function appendSignature($parentNode, $insertBefore = false) + public function appendSignature(DOMNode $parentNode, bool $insertBefore = false): DOMNode { $beforeNode = $insertBefore ? $parentNode->firstChild : null; return $this->insertSignature($parentNode, $beforeNode); } + /** * @param string $cert * @param bool $isPEMFormat * @return string */ - public static function get509XCert($cert, $isPEMFormat = true) + public static function get509XCert(string $cert, bool $isPEMFormat = true): string { $certs = self::staticGet509XCerts($cert, $isPEMFormat); + if (!empty($certs)) { return $certs[0]; } + return ''; } + /** * @param string $certs * @param bool $isPEMFormat * @return array */ - public static function staticGet509XCerts($certs, $isPEMFormat = true) + public static function staticGet509XCerts(string $certs, bool $isPEMFormat = true): array { if ($isPEMFormat) { $data = ''; $certlist = array(); $arCert = explode("\n", $certs); $inData = false; + foreach ($arCert as $curData) { - if (! $inData) { + if (!$inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = true; } @@ -942,37 +1066,41 @@ public static function staticGet509XCerts($certs, $isPEMFormat = true) $data .= trim($curData); } } + return $certlist; } else { return array($certs); } } + /** - * @param DOMElement $parentRef + * @param \DOMElement $parentRef * @param string $cert * @param bool $isPEMFormat * @param bool $isURL - * @param null|DOMXPath $xpath - * @param null|array $options - * @throws Exception + * @param \DOMXPath|null $xpath + * @param array|null $options + * @return void + * @throws \Exception */ public static function staticAdd509Cert( - $parentRef, - $cert, - $isPEMFormat = true, - $isURL = false, - $xpath = null, - $options = null - ) { + DOMElement $parentRef, + string $cert, + bool $isPEMFormat = true, + bool $isURL = false, + DOMXPath $xpath = null, + array $options = null + ): void { if ($isURL) { $cert = file_get_contents($cert); } + if (!($parentRef instanceof DOMElement)) { throw new Exception('Invalid parent Node parameter'); } - $baseDoc = $parentRef->ownerDocument; + $baseDoc = $parentRef->ownerDocument; if (empty($xpath)) { $xpath = new DOMXPath($parentRef->ownerDocument); $xpath->registerNamespace('secdsig', self::XMLDSIGNS); @@ -982,16 +1110,20 @@ public static function staticAdd509Cert( $nodeset = $xpath->query($query, $parentRef); $keyInfo = $nodeset->item(0); $dsig_pfx = ''; + if (!$keyInfo) { $pfx = $parentRef->lookupPrefix(self::XMLDSIGNS); + if (!empty($pfx)) { $dsig_pfx = $pfx . ":"; } + $inserted = false; $keyInfo = $baseDoc->createElementNS(self::XMLDSIGNS, $dsig_pfx . 'KeyInfo'); $query = "./secdsig:Object"; $nodeset = $xpath->query($query, $parentRef); + if ($sObject = $nodeset->item(0)) { $sObject->parentNode->insertBefore($keyInfo, $sObject); $inserted = true; @@ -1002,6 +1134,7 @@ public static function staticAdd509Cert( } } else { $pfx = $keyInfo->lookupPrefix(self::XMLDSIGNS); + if (!empty($pfx)) { $dsig_pfx = $pfx . ":"; } @@ -1020,6 +1153,7 @@ public static function staticAdd509Cert( if (! empty($options['issuerSerial'])) { $issuerSerial = true; } + if (! empty($options['subjectName'])) { $subjectName = true; } @@ -1031,6 +1165,7 @@ public static function staticAdd509Cert( $certData = openssl_x509_parse( "-----BEGIN CERTIFICATE-----\n" . chunk_split($X509Cert, 64, "\n") . "-----END CERTIFICATE-----\n" ); + if ($certData) { if ($subjectName && !empty($certData['subject'])) { if (is_array($certData['subject'])) { @@ -1089,29 +1224,32 @@ public static function staticAdd509Cert( } } + /** * @param string $cert * @param bool $isPEMFormat * @param bool $isURL - * @param null|array $options + * @param array|null $options + * @return void */ - public function add509Cert($cert, $isPEMFormat = true, $isURL = false, $options = null) + public function add509Cert(string $cert, bool $isPEMFormat = true, bool $isURL = false, array $options = null): void { if ($xpath = $this->getXPathObj()) { self::staticAdd509Cert($this->sigNode, $cert, $isPEMFormat, $isURL, $xpath, $options); } } + /** * This function appends a node to the KeyInfo. * * The KeyInfo element will be created if one does not exist in the document. * - * @param DOMNode $node The node to append to the KeyInfo. + * @param \DOMNode $node The node to append to the KeyInfo. * - * @return DOMNode The KeyInfo element node + * @return \DOMNode The KeyInfo element node */ - public function appendToKeyInfo($node) + public function appendToKeyInfo(DOMNode $node): DOMNode { $parentRef = $this->sigNode; $baseDoc = $parentRef->ownerDocument; @@ -1125,9 +1263,11 @@ public function appendToKeyInfo($node) $query = "./secdsig:KeyInfo"; $nodeset = $xpath->query($query, $parentRef); $keyInfo = $nodeset->item(0); + if (!$keyInfo) { $dsig_pfx = ''; $pfx = $parentRef->lookupPrefix(self::XMLDSIGNS); + if (!empty($pfx)) { $dsig_pfx = $pfx . ":"; } @@ -1151,6 +1291,7 @@ public function appendToKeyInfo($node) return $keyInfo; } + /** * This function retrieves an associative array of the validated nodes. * @@ -1162,7 +1303,7 @@ public function appendToKeyInfo($node) * * @return array Associative array of validated nodes */ - public function getValidatedNodes() + public function getValidatedNodes(): array { return $this->validatedNodes; } diff --git a/src/XMLSecurityKey.php b/src/XMLSecurityKey.php index 89b04cf8..6492654f 100644 --- a/src/XMLSecurityKey.php +++ b/src/XMLSecurityKey.php @@ -47,21 +47,52 @@ class XMLSecurityKey { + /** @var string */ public const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'; + + /** @var string */ public const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; + + /** @var string */ public const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; + + /** @var string */ public const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; + + /** @var string */ public const AES128_GCM = 'http://www.w3.org/2009/xmlenc11#aes128-gcm'; + + /** @var string */ public const AES192_GCM = 'http://www.w3.org/2009/xmlenc11#aes192-gcm'; + + /** @var string */ public const AES256_GCM = 'http://www.w3.org/2009/xmlenc11#aes256-gcm'; + + /** @var string */ public const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; + + /** @var string */ public const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; + + /** @var string */ public const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'; + + /** @var string */ public const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; + + /** @var string */ public const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; + + /** @var string */ public const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'; + + /** @var string */ public const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'; + + /** @var string */ public const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1'; + + /** @var string */ public const AUTHTAG_LENGTH = 16; /** @var array */ @@ -107,10 +138,11 @@ class XMLSecurityKey */ private $X509Thumbprint = null; + /** * @param string $type - * @param null|array $params - * @throws Exception + * @param array|null $params + * @throws \Exception */ public function __construct($type, $params = null) { @@ -251,6 +283,7 @@ public function __construct($type, $params = null) $this->type = $type; } + /** * Retrieve the key size for the symmetric encryption algorithm.. * @@ -259,21 +292,22 @@ public function __construct($type, $params = null) * * @return int|null The number of bytes in the key. */ - public function getSymmetricKeySize() + public function getSymmetricKeySize(): ?int { - if (! isset($this->cryptParams['keysize'])) { + if (!isset($this->cryptParams['keysize'])) { return null; } return $this->cryptParams['keysize']; } + /** * Generates a session key using the openssl-extension. * In case of using DES3-CBC the key is checked for a proper parity bits set. * @return string - * @throws Exception + * @throws \Exception */ - public function generateSessionKey() + public function generateSessionKey(): string { if (!isset($this->cryptParams['keysize'])) { throw new Exception('Unknown key size for type "' . $this->type . '".'); @@ -301,21 +335,21 @@ public function generateSessionKey() return $key; } + /** * Get the raw thumbprint of a certificate * * @param string $cert - * @return null|string + * @return string|null */ - public static function getRawThumbprint($cert) + public static function getRawThumbprint(string $cert): ?string { - $arCert = explode("\n", $cert); $data = ''; $inData = false; foreach ($arCert as $curData) { - if (! $inData) { + if (!$inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = true; } @@ -327,28 +361,31 @@ public static function getRawThumbprint($cert) } } - if (! empty($data)) { + if (!empty($data)) { return strtolower(sha1(base64_decode($data))); } return null; } + /** * Loads the given key, or - with isFile set true - the key from the keyfile. * * @param string $key * @param bool $isFile * @param bool $isCert - * @throws Exception + * @return void + * @throws \Exception */ - public function loadKey($key, $isFile = false, $isCert = false) + public function loadKey(string $key, bool $isFile = false, bool $isCert = false): void { if ($isFile) { $this->key = file_get_contents($key); } else { $this->key = $key; } + if ($isCert) { $this->key = openssl_x509_read($this->key); openssl_x509_export($this->key, $str_cert); @@ -357,6 +394,7 @@ public function loadKey($key, $isFile = false, $isCert = false) } else { $this->x509Certificate = null; } + if ($this->cryptParams['library'] == 'openssl') { switch ($this->cryptParams['type']) { case 'public': @@ -387,47 +425,54 @@ public function loadKey($key, $isFile = false, $isCert = false) } } + /** * ISO 10126 Padding * * @param string $data - * @param integer $blockSize - * @throws Exception + * @param int $blockSize + * @throws \Exception * @return string */ - private function padISO10126($data, $blockSize) + private function padISO10126(string $data, int $blockSize): string { if ($blockSize > 256) { throw new Exception('Block size higher than 256 not allowed'); } + $padChr = $blockSize - (strlen($data) % $blockSize); $pattern = chr($padChr); + return $data . str_repeat($pattern, $padChr); } + /** * Remove ISO 10126 Padding * * @param string $data * @return string */ - private function unpadISO10126($data) + private function unpadISO10126(string $data): string { $padChr = substr($data, -1); $padLen = ord($padChr); + return substr($data, 0, -$padLen); } + /** * Encrypts the given data (string) using the openssl-extension * * @param string $data * @return string */ - private function encryptSymmetric($data) + private function encryptSymmetric(string $data): string { $this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher'])); $authTag = null; + if (in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { $authTag = openssl_random_pseudo_bytes(self::AUTHTAG_LENGTH); $encrypted = openssl_encrypt( @@ -452,21 +497,24 @@ private function encryptSymmetric($data) if (false === $encrypted) { throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string()); } + return $this->iv . $encrypted . $authTag; } + /** * Decrypts the given data (string) using the openssl-extension * * @param string $data * @return string */ - private function decryptSymmetric($data) + private function decryptSymmetric(string $data): string { $iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']); $this->iv = substr($data, 0, $iv_length); $data = substr($data, $iv_length); $authTag = null; + if (in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) { // obtain and remove the authentication tag $offset = 0 - self::AUTHTAG_LENGTH; @@ -493,88 +541,101 @@ private function decryptSymmetric($data) if (false === $decrypted) { throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string()); } + return null !== $authTag ? $decrypted : $this->unpadISO10126($decrypted); } + /** * Encrypts the given public data (string) using the openssl-extension * * @param string $data * @return string - * @throws Exception + * @throws \Exception */ - private function encryptPublic($data) + private function encryptPublic(string $data): string { if (!openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure encrypting Data (openssl public) - ' . openssl_error_string()); } + return $encrypted; } + /** * Decrypts the given public data (string) using the openssl-extension * * @param string $data * @return string - * @throws Exception + * @throws \Exception */ - private function decryptPublic($data) + private function decryptPublic(string $data): string { if (!openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string()); } + return $decrypted; } + /** * Encrypts the given private data (string) using the openssl-extension * * @param string $data * @return string - * @throws Exception + * @throws \Exception */ - private function encryptPrivate($data) + private function encryptPrivate(string $data): string { if (!openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string()); } + return $encrypted; } + /** * Decrypts the given private data (string) using the openssl-extension * * @param string $data * @return string - * @throws Exception + * @throws \Exception */ - private function decryptPrivate($data) + private function decryptPrivate(string $data): string { if (!openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { throw new Exception('Failure decrypting Data (openssl private) - ' . openssl_error_string()); } + return $decrypted; } + /** * Signs the given data (string) using the openssl-extension * * @param string $data * @return string - * @throws Exception + * @throws \Exception */ - private function signOpenSSL($data) + private function signOpenSSL(string $data): string { $algo = OPENSSL_ALGO_SHA1; if (!empty($this->cryptParams['digest'])) { $algo = $this->cryptParams['digest']; } + if (!openssl_sign($data, $signature, $this->key, $algo)) { throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo); } + return $signature; } + /** * Verifies the given data (string) belonging to the given signature using the openssl-extension * @@ -591,15 +652,17 @@ private function signOpenSSL($data) * @param string $signature * @return int */ - private function verifyOpenSSL($data, $signature) + private function verifyOpenSSL(string $data, string $signature): int { $algo = OPENSSL_ALGO_SHA1; if (!empty($this->cryptParams['digest'])) { $algo = $this->cryptParams['digest']; } + return openssl_verify($data, $signature, $this->key, $algo); } + /** * Encrypts the given data (string) using the regarding php-extension, * depending on the library assigned to algorithm in the contructor. @@ -607,7 +670,7 @@ private function verifyOpenSSL($data, $signature) * @param string $data * @return mixed|string */ - public function encryptData($data) + public function encryptData(string $data) { if ($this->cryptParams['library'] === 'openssl') { switch ($this->cryptParams['type']) { @@ -621,6 +684,7 @@ public function encryptData($data) } } + /** * Decrypts the given data (string) using the regarding php-extension, * depending on the library assigned to algorithm in the contructor. @@ -628,7 +692,7 @@ public function encryptData($data) * @param string $data * @return mixed|string */ - public function decryptData($data) + public function decryptData(string $data) { if ($this->cryptParams['library'] === 'openssl') { switch ($this->cryptParams['type']) { @@ -642,13 +706,14 @@ public function decryptData($data) } } + /** * Signs the data (string) using the extension assigned to the type in the constructor. * * @param string $data * @return mixed|string */ - public function signData($data) + public function signData(string $data) { switch ($this->cryptParams['library']) { case 'openssl': @@ -658,6 +723,7 @@ public function signData($data) } } + /** * Verifies the data (string) against the given signature using * the extension assigned to the type in the constructor. @@ -675,7 +741,7 @@ public function signData($data) * @param string $signature * @return bool|int */ - public function verifySignature($data, $signature) + public function verifySignature(string $data, string $signature) { switch ($this->cryptParams['library']) { case 'openssl': @@ -686,31 +752,23 @@ public function verifySignature($data, $signature) } } - /** - * @deprecated - * @see getAlgorithm() - * @return mixed - */ - public function getAlgorith() - { - return $this->getAlgorithm(); - } /** - * @return mixed + * @return string */ - public function getAlgorithm() + public function getAlgorithm(): string { return $this->cryptParams['method']; } + /** * * @param int $type * @param string $string - * @return null|string + * @return string|null */ - public static function makeAsnSegment($type, $string) + public static function makeAsnSegment(int $type, string $string): ?string { switch ($type) { case 0x02: @@ -734,9 +792,11 @@ public static function makeAsnSegment($type, $string) } else { $output = null; } + return $output; } + /** * * Hint: Modulus and Exponent must already be base64 decoded @@ -744,7 +804,7 @@ public static function makeAsnSegment($type, $string) * @param string $exponent * @return string */ - public static function convertRSA($modulus, $exponent) + public static function convertRSA(string $modulus, string $exponent): string { /* make an ASN publicKeyInfo */ $exponentEncoding = self::makeAsnSegment(0x02, $exponent); @@ -757,21 +817,25 @@ public static function convertRSA($modulus, $exponent) /* encode the publicKeyInfo in base64 and add PEM brackets */ $publicKeyInfoBase64 = base64_encode($publicKeyInfo); $encoding = "-----BEGIN PUBLIC KEY-----\n"; + $offset = 0; while ($segment = substr($publicKeyInfoBase64, $offset, 64)) { $encoding = $encoding . $segment . "\n"; $offset += 64; } + return $encoding . "-----END PUBLIC KEY-----\n"; } + /** * @param mixed $parent */ - public function serializeKey($parent) + public function serializeKey($parent): void { } + /** * Retrieve the X509 certificate this key represents. * @@ -780,11 +844,12 @@ public function serializeKey($parent) * * @return string The X509 certificate or null if this key doesn't represent an X509-certificate. */ - public function getX509Certificate() + public function getX509Certificate(): string { return $this->x509Certificate; } + /** * Get the thumbprint of this X509 certificate. * @@ -794,7 +859,7 @@ public function getX509Certificate() * * @return string Lowercase 40-character hexadecimal number of thumbprint */ - public function getX509Thumbprint() + public function getX509Thumbprint(): string { return $this->X509Thumbprint; } @@ -803,22 +868,24 @@ public function getX509Thumbprint() /** * Create key from an EncryptedKey-element. * - * @param DOMElement $element The EncryptedKey-element. - * @throws Exception + * @param \DOMElement $element The EncryptedKey-element. + * @throws \Exception * - * @return XMLSecurityKey The new key. + * @return \RobRichards\XMLSecLibs\XMLSecurityKey The new key. */ - public static function fromEncryptedKeyElement(DOMElement $element) + public static function fromEncryptedKeyElement(DOMElement $element): XMLSecurityKey { - $objenc = new XMLSecEnc(); $objenc->setNode($element); + if (!($objKey = $objenc->locateKey())) { throw new Exception("Unable to locate algorithm for this Encrypted Key"); } + $objKey->isEncrypted = true; $objKey->encryptedCtx = $objenc; XMLSecEnc::staticLocateKeyInfo($objKey, $element); + return $objKey; } } From 10338ad91dd37ce111e6618438e19dfc3fb7b678 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Tue, 12 May 2020 00:01:24 +0200 Subject: [PATCH 7/8] Shorthand arrays --- src/XMLSecEnc.php | 8 ++++---- src/XMLSecurityDSig.php | 34 +++++++++++++++++----------------- src/XMLSecurityKey.php | 2 +- 3 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php index 582b95a6..39a1f3cb 100644 --- a/src/XMLSecEnc.php +++ b/src/XMLSecEnc.php @@ -83,7 +83,7 @@ class XMLSecEnc public $encKey = null; /** @var array */ - private $references = array(); + private $references = []; public function __construct() @@ -122,7 +122,7 @@ public function addReference(string $name, DOMNode $node, string $type): void $refuri = XMLSecurityDSig::generateGUID(); $element = $encdoc->documentElement; $element->setAttribute("Id", $refuri); - $this->references[$name] = array("node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri); + $this->references[$name] = ["node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri]; } @@ -440,7 +440,7 @@ public function locateKey(DOMNode $node = null): ?XMLSecurityKey $attrAlgorithm = $encmeth->getAttribute("Algorithm"); try { - $objKey = new XMLSecurityKey($attrAlgorithm, array('type' => 'private')); + $objKey = new XMLSecurityKey($attrAlgorithm, ['type' => 'private']); } catch (Exception $e) { return null; } @@ -538,7 +538,7 @@ public static function staticLocateKeyInfo(XMLSecurityKey $objBaseKey = null, DO if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) { if ($x509certNodes->length > 0) { $x509cert = $x509certNodes->item(0)->textContent; - $x509cert = str_replace(array("\r", "\n", " "), "", $x509cert); + $x509cert = str_replace(["\r", "\n", " "], "", $x509cert); $x509cert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($x509cert, 64, "\n") . "-----END CERTIFICATE-----\n"; $objBaseKey->loadKey($x509cert, false, true); diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php index f261a262..81f81284 100644 --- a/src/XMLSecurityDSig.php +++ b/src/XMLSecurityDSig.php @@ -92,10 +92,10 @@ class XMLSecurityDSig public $sigNode = null; /** @var array */ - public $idKeys = array(); + public $idKeys = []; /** @var array */ - public $idNS = array(); + public $idNS = []; /** @var string|null */ private $signedInfo = null; @@ -128,8 +128,8 @@ public function __construct(?string $prefix = 'ds') if (!empty($prefix)) { $this->prefix = $prefix . ':'; - $search = array("firstChild; while ($node) { if ($node->localName == 'XPath') { - $arXPath = array(); + $arXPath = []; $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $node->nodeValue . ']'; - $arXPath['namespaces'] = array(); + $arXPath['namespaces'] = []; $nslist = $xpath->query('./namespace::*', $node); foreach ($nslist as $nsnode) { if ($nsnode->localName != "xml") { @@ -619,7 +619,7 @@ public function getRefNodeID(DOMNode $refNode): ?string */ public function getRefIDs(): array { - $refids = array(); + $refids = []; $xpath = $this->getXPathObj(); $query = "./secdsig:SignedInfo[1]/secdsig:Reference"; @@ -660,7 +660,7 @@ public function validateReference(): bool } /* Initialize/reset the list of validated nodes. */ - $this->validatedNodes = array(); + $this->validatedNodes = []; foreach ($nodeset as $refNode) { if (!$this->processRefNode($refNode)) { @@ -873,7 +873,7 @@ public function locateKey(DOMNode $node = null): ?XMLSecurityKey if ($algorithm) { try { - $objKey = new XMLSecurityKey($algorithm, array('type' => 'public')); + $objKey = new XMLSecurityKey($algorithm, ['type' => 'public']); } catch (Exception $e) { return null; } @@ -1047,7 +1047,7 @@ public static function staticGet509XCerts(string $certs, bool $isPEMFormat = tru { if ($isPEMFormat) { $data = ''; - $certlist = array(); + $certlist = []; $arCert = explode("\n", $certs); $inData = false; @@ -1069,7 +1069,7 @@ public static function staticGet509XCerts(string $certs, bool $isPEMFormat = tru return $certlist; } else { - return array($certs); + return [$certs]; } } @@ -1150,11 +1150,11 @@ public static function staticAdd509Cert( $issuerSerial = false; $subjectName = false; if (is_array($options)) { - if (! empty($options['issuerSerial'])) { + if (!empty($options['issuerSerial'])) { $issuerSerial = true; } - if (! empty($options['subjectName'])) { + if (!empty($options['subjectName'])) { $subjectName = true; } } @@ -1169,7 +1169,7 @@ public static function staticAdd509Cert( if ($certData) { if ($subjectName && !empty($certData['subject'])) { if (is_array($certData['subject'])) { - $parts = array(); + $parts = []; foreach ($certData['subject'] as $key => $value) { if (is_array($value)) { foreach ($value as $valueElement) { @@ -1192,7 +1192,7 @@ public static function staticAdd509Cert( } if ($issuerSerial && !empty($certData['issuer']) && !empty($certData['serialNumber'])) { if (is_array($certData['issuer'])) { - $parts = array(); + $parts = []; foreach ($certData['issuer'] as $key => $value) { array_unshift($parts, "$key=$value"); } diff --git a/src/XMLSecurityKey.php b/src/XMLSecurityKey.php index 6492654f..12db2d99 100644 --- a/src/XMLSecurityKey.php +++ b/src/XMLSecurityKey.php @@ -96,7 +96,7 @@ class XMLSecurityKey public const AUTHTAG_LENGTH = 16; /** @var array */ - private $cryptParams = array(); + private $cryptParams = []; /** @var int|string */ public $type = 0; From 86d6bb087d997808c692488985c64156882c5112 Mon Sep 17 00:00:00 2001 From: Tim van Dijen Date: Tue, 12 May 2020 00:23:28 +0200 Subject: [PATCH 8/8] Psalm-fixes --- src/XMLSecEnc.php | 22 +++++++++++----------- src/XMLSecurityDSig.php | 7 +++---- src/XMLSecurityKey.php | 8 ++++---- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php index 39a1f3cb..36101928 100644 --- a/src/XMLSecEnc.php +++ b/src/XMLSecEnc.php @@ -70,16 +70,16 @@ class XMLSecEnc /** @var string */ public const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#'; - /** @var null|\DOMDocument */ + /** @var \DOMDocument|null */ private $encdoc = null; - /** @var null|\DOMNode */ + /** @var \DOMNode|null */ private $rawNode = null; - /** @var null|string */ + /** @var string|null */ public $type = null; - /** @var null|\DOMElement */ + /** @var \DOMElement|null */ public $encKey = null; /** @var array */ @@ -111,10 +111,6 @@ private function resetTemplate(): void */ public function addReference(string $name, DOMNode $node, string $type): void { - if (!($node instanceof DOMNode)) { - throw new Exception('$node is not of type DOMNode'); - } - $curencdoc = $this->encdoc; $this->resetTemplate(); $encdoc = $this->encdoc; @@ -143,24 +139,28 @@ public function setNode(DOMNode $node): void * @param bool $replace Whether the encrypted node should be replaced in the original tree. Default is true. * @throws \Exception * - * @return \DOMElement The -element. + * @return \DOMNode|false The -element. */ - public function encryptNode(XMLSecurityKey $objKey, bool $replace = true): DOMElement + public function encryptNode(XMLSecurityKey $objKey, bool $replace = true) { $data = ''; if (empty($this->rawNode)) { throw new Exception('Node to encrypt has not been set'); } + if (!($objKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); } + $doc = $this->rawNode->ownerDocument; $xPath = new DOMXPath($this->encdoc); $objList = $xPath->query('/xenc:EncryptedData/xenc:CipherData/xenc:CipherValue'); + $cipherValue = $objList->item(0); if ($cipherValue == null) { throw new Exception('Error locating CipherValue element within template'); } + switch ($this->type) { case (self::ELEMENT): $data = $doc->saveXML($this->rawNode); @@ -556,7 +556,7 @@ public static function staticLocateKeyInfo(XMLSecurityKey $objBaseKey = null, DO * @param \DOMNode|null $node * @return \RobRichards\XMLSecLibs\XMLSecurityKey|null */ - public function locateKeyInfo(XMLSecurityKey $objBaseKey = null, DOMNode $node = null): XMLSecurityKey + public function locateKeyInfo(XMLSecurityKey $objBaseKey = null, DOMNode $node = null): ?XMLSecurityKey { if (empty($node)) { $node = $this->rawNode; diff --git a/src/XMLSecurityDSig.php b/src/XMLSecurityDSig.php index 81f81284..4de3d431 100644 --- a/src/XMLSecurityDSig.php +++ b/src/XMLSecurityDSig.php @@ -305,7 +305,6 @@ private function canonicalizeData( if ( is_null($arXPath) - && ($node instanceof DOMNode) && ($node->ownerDocument !== null) && $node->isSameNode($node->ownerDocument->documentElement) ) { @@ -432,9 +431,9 @@ public function validateDigest(DOMNode $refNode, string $data): bool * @param \DOMNode $refNode * @param \DOMNode $objData * @param bool $includeCommentNodes - * @return string + * @return \DOMNode|string */ - public function processTransforms(DOMNode $refNode, DOMNode $objData, bool $includeCommentNodes = true): string + public function processTransforms(DOMNode $refNode, DOMNode $objData, bool $includeCommentNodes = true) { $data = $objData; $xpath = new DOMXPath($refNode->ownerDocument); @@ -822,7 +821,7 @@ public function addReferenceList( /** - * @param \DOMElement|string $data + * @param \DOMElement $data * @param string|null $mimetype * @param string|null $encoding * @return \DOMElement diff --git a/src/XMLSecurityKey.php b/src/XMLSecurityKey.php index 12db2d99..2ad9ca8b 100644 --- a/src/XMLSecurityKey.php +++ b/src/XMLSecurityKey.php @@ -842,9 +842,9 @@ public function serializeKey($parent): void * Will return the X509 certificate in PEM-format if this key represents * an X509 certificate. * - * @return string The X509 certificate or null if this key doesn't represent an X509-certificate. + * @return string|null The X509 certificate or null if this key doesn't represent an X509-certificate. */ - public function getX509Certificate(): string + public function getX509Certificate(): ?string { return $this->x509Certificate; } @@ -857,9 +857,9 @@ public function getX509Certificate(): string * The thumbprint as a lowercase 40-character hexadecimal number, or null * if this isn't a X509 certificate. * - * @return string Lowercase 40-character hexadecimal number of thumbprint + * @return string|null Lowercase 40-character hexadecimal number of thumbprint */ - public function getX509Thumbprint(): string + public function getX509Thumbprint(): ?string { return $this->X509Thumbprint; }