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/src/Utils/XPath.php b/src/Utils/XPath.php index 8cdc48e1..e2e668e4 100644 --- a/src/Utils/XPath.php +++ b/src/Utils/XPath.php @@ -4,14 +4,26 @@ class XPath { - const ALPHANUMERIC = '\w\d'; - const NUMERIC = '\d'; - const LETTERS = '\w'; - const EXTENDED_ALPHANUMERIC = '\w\d\s\-_:\.'; + /** @var string */ + public const ALPHANUMERIC = '\w\d'; - const SINGLE_QUOTE = '\''; - const DOUBLE_QUOTE = '"'; - const ALL_QUOTES = '[\'"]'; + /** @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,9 +34,9 @@ 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); + return preg_replace('#' . $quotes . '#', '', $value); } @@ -32,13 +44,13 @@ 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); + return preg_replace('#[^' . $allow . ']#', '', $name); } } diff --git a/src/XMLSecEnc.php b/src/XMLSecEnc.php index b9df7611..36101928 100644 --- a/src/XMLSecEnc.php +++ b/src/XMLSecEnc.php @@ -1,4 +1,5 @@ + /** @var string */ + 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#'; + /** @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 null|DOMDocument */ + /** @var string */ + public const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#'; + + /** @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 */ - private $references = array(); + private $references = []; + public function __construct() { - $this->_resetTemplate(); + $this->resetTemplate(); } - private function _resetTemplate() + + /** + * @retun void + */ + private function resetTemplate(): void { $this->encdoc = new DOMDocument(); - $this->encdoc->loadXML(self::template); + $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(); + $this->resetTemplate(); $encdoc = $this->encdoc; $this->encdoc = $curencdoc; $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]; } + /** - * @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 bool $replace Whether the encrypted node should be replaced in the original tree. Default is true. - * @throws Exception + * @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 * - * @return DOMElement The -element. + * @return \DOMNode|false The -element. */ - public function encryptNode($objKey, $replace = true) + 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) { + + 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): + 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) { + 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'); } - $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); @@ -167,14 +192,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); @@ -187,15 +212,17 @@ 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; - foreach ($this->references AS $name => $reference) { + foreach ($this->references as $name => $reference) { $this->encdoc = $reference["encnode"]; $this->rawNode = $reference["node"]; $this->type = $reference["type"]; @@ -212,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'); @@ -233,12 +261,13 @@ public function getCipherValue() $node = $nodeset->item(0); if (!$node) { - return null; + return null; } return base64_decode($node->nodeValue); } + /** * Decrypt this encrypted node. * @@ -247,14 +276,16 @@ 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 XML document with the decrypted data. The default is true. + * @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) { + if (!($objKey instanceof XMLSecurityKey)) { throw new Exception('Invalid Key'); } @@ -263,7 +294,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) { @@ -272,7 +303,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 { @@ -294,55 +325,64 @@ 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)) { + 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)); + $encMethod->setAttribute('Algorithm', $srcKey->getAlgorithm()); + 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); } } - 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) { + if (!$encKey->isEncrypted) { throw new Exception("Key is not Encrypted"); } if (empty($encKey->key)) { @@ -351,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."']"; + $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) { + + 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')); + $objKey = new XMLSecurityKey($attrAlgorithm, ['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)) { + if (empty($node) || !($node instanceof DOMNode)) { return null; } + $doc = $node->ownerDocument; if (!$doc) { return null; @@ -424,12 +476,13 @@ 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; } - foreach ($encmeth->childNodes AS $child) { + foreach ($encmeth->childNodes as $child) { switch ($child->localName) { case 'KeyName': if (! empty($objBaseKey)) { @@ -437,7 +490,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 +525,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'."); @@ -485,8 +538,9 @@ public static function staticLocateKeyInfo($objBaseKey=null, $node=null) if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) { 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 = str_replace(["\r", "\n", " "], "", $x509cert); + $x509cert = "-----BEGIN CERTIFICATE-----\n" + . chunk_split($x509cert, 64, "\n") . "-----END CERTIFICATE-----\n"; $objBaseKey->loadKey($x509cert, false, true); } } @@ -496,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 9986123e..4de3d431 100644 --- a/src/XMLSecurityDSig.php +++ b/src/XMLSecurityDSig.php @@ -1,4 +1,5 @@ - - - -'; - - const BASE_TEMPLATE = ' + /** @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 */ - public $idKeys = array(); + public $idKeys = []; /** @var array */ - public $idNS = array(); + public $idNS = []; /** @var string|null */ private $signedInfo = null; - /** @var DomXPath|null */ + /** @var \DomXPath|null */ private $xPathCtx = null; /** @var string|null */ @@ -104,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); @@ -196,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); + + 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; } + /** * @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': @@ -236,13 +254,14 @@ public function setCanonicalMethod($method) default: 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); } @@ -251,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) { @@ -279,7 +303,11 @@ 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->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) { @@ -296,54 +324,59 @@ private function canonicalizeData($node, $canonicalmethod, $arXPath=null, $prefi 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); $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)); if (count($arpfx) > 0) { - $prefixList = array_merge($prefixList ? $prefixList : array(), $arpfx); + $prefixList = array_merge($prefixList ? $prefixList : [], $arpfx); } } } } } + $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: @@ -366,19 +399,21 @@ public function calculateDigest($digestAlgorithm, $data, $encode = true) } $digest = hash($alg, $data, true); + if ($encode) { $digest = base64_encode($digest); } - return $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); @@ -387,16 +422,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 + * @return \DOMNode|string */ - public function processTransforms($refNode, $objData, $includeCommentNodes = true) + public function processTransforms(DOMNode $refNode, DOMNode $objData, bool $includeCommentNodes = true) { $data = $objData; $xpath = new DOMXPath($refNode->ownerDocument); @@ -406,12 +443,13 @@ 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. @@ -425,9 +463,9 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru while ($node) { if ($node->localName == 'InclusiveNamespaces') { if ($pfx = $node->getAttribute('PrefixList')) { - $arpfx = array(); + $arpfx = []; $pfxlist = explode(" ", $pfx); - foreach ($pfxlist AS $pfx) { + foreach ($pfxlist as $pfx) { $val = trim($pfx); if (! empty($val)) { $arpfx[] = $val; @@ -441,7 +479,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) { @@ -458,11 +496,11 @@ public function processTransforms($refNode, $objData, $includeCommentNodes = tru $node = $transform->firstChild; while ($node) { if ($node->localName == 'XPath') { - $arXPath = array(); - $arXPath['query'] = '(.//. | .//@* | .//namespace::*)['.$node->nodeValue.']'; - $arXPath['namespaces'] = array(); + $arXPath = []; + $arXPath['query'] = '(.//. | .//@* | .//namespace::*)[' . $node->nodeValue . ']'; + $arXPath['namespaces'] = []; $nslist = $xpath->query('./namespace::*', $node); - foreach ($nslist AS $nsnode) { + foreach ($nslist as $nsnode) { if ($nsnode->localName != "xml") { $arXPath['namespaces'][$nsnode->localName] = $nsnode->nodeValue; } @@ -474,17 +512,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; @@ -498,7 +539,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 +550,16 @@ 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; @@ -531,6 +573,7 @@ public function processRefNode($refNode) $dataObject = $refNode->ownerDocument; } + $data = $this->processTransforms($refNode, $dataObject, $includeCommentNodes); if (!$this->validateDigest($refNode, $data)) { return false; @@ -548,84 +591,103 @@ 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(); + $refids = []; $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) { + + 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 (!$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"); } /* Initialize/reset the list of validated nodes. */ - $this->validatedNodes = array(); + $this->validatedNodes = []; - 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"); } } + 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'; @@ -641,23 +703,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 +728,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 +752,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); @@ -701,56 +769,73 @@ private function addRefInternal($sinfoNode, $node, $algorithm, $arTransforms=nul $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) { + foreach ($arNodes as $node) { $this->addRefInternal($sInfo, $node, $algorithm, $arTransforms, $options); } } } } + /** - * @param DOMElement|string $data - * @param null|string $mimetype - * @param null|string $encoding - * @return DOMElement + * @param \DOMElement $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)) { + + if (!empty($mimetype)) { $objNode->setAttribute('MimeType', $mimetype); } - if (! empty($encoding)) { + + if (!empty($encoding)) { $objNode->setAttribute('Encoding', $encoding); } @@ -759,40 +844,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) { + + 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')); + $objKey = new XMLSecurityKey($algorithm, ['type' => 'public']); } catch (Exception $e) { return null; } + return $objKey; } } + return null; } + /** * Returns: * Bool when verifying HMAC_SHA1; @@ -805,38 +897,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) { @@ -844,9 +941,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); @@ -855,6 +954,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 { @@ -864,16 +964,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); } @@ -885,14 +990,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); @@ -903,45 +1007,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)) { + + 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(); + $certlist = []; $arCert = explode("\n", $certs); $inData = false; - foreach ($arCert AS $curData) { - if (! $inData) { + + foreach ($arCert as $curData) { + if (!$inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = true; } @@ -955,31 +1065,41 @@ public static function staticGet509XCerts($certs, $isPEMFormat=true) $data .= trim($curData); } } + return $certlist; } else { - return array($certs); + return [$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) - { + public static function staticAdd509Cert( + 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) { + + 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); @@ -989,28 +1109,33 @@ 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); + if ($sObject = $nodeset->item(0)) { $sObject->parentNode->insertBefore($keyInfo, $sObject); $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,16 +1143,17 @@ 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; $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; } } @@ -1035,11 +1161,15 @@ 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) { + $parts = []; + foreach ($certData['subject'] as $key => $value) { if (is_array($value)) { foreach ($value as $valueElement) { array_unshift($parts, "$key=$valueElement"); @@ -1052,13 +1182,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) { + $parts = []; + foreach ($certData['issuer'] as $key => $value) { array_unshift($parts, "$key=$value"); } $issuerName = implode(',', $parts); @@ -1066,45 +1200,55 @@ 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); } } + /** * @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; @@ -1118,14 +1262,16 @@ 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 +1280,7 @@ public function appendToKeyInfo($node) $inserted = true; } - if (! $inserted) { + if (!$inserted) { $parentRef->appendChild($keyInfo); } } @@ -1144,6 +1290,7 @@ public function appendToKeyInfo($node) return $keyInfo; } + /** * This function retrieves an associative array of the validated nodes. * @@ -1155,7 +1302,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 90665c95..2ad9ca8b 100644 --- a/src/XMLSecurityKey.php +++ b/src/XMLSecurityKey.php @@ -1,4 +1,5 @@ type = $type; } + /** * Retrieve the key size for the symmetric encryption algorithm.. * @@ -258,29 +292,30 @@ 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 . '".'); } $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,26 +330,26 @@ public function generateSessionKey() $key[$i] = chr($byte); } } - + $this->key = $key; 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) { + foreach ($arCert as $curData) { + if (!$inData) { if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { $inData = true; } @@ -326,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); @@ -356,24 +394,26 @@ public function loadKey($key, $isFile=false, $isCert = false) } else { $this->x509Certificate = null; } + 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'); } @@ -385,174 +425,217 @@ 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'])) { - if (version_compare(PHP_VERSION, '7.1.0') < 0) { - throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); - } + + 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($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()); } + 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'])) { - if (version_compare(PHP_VERSION, '7.1.0') < 0) { - throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms'); - } + + 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; $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()); } + 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'])) { + 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'])) { + 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'])) { + 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'])) { + 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'])) { + 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; } + /** * Verifies the given data (string) belonging to the given signature using the openssl-extension * @@ -569,22 +652,25 @@ 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'])) { + 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 */ - public function encryptData($data) + public function encryptData(string $data) { if ($this->cryptParams['library'] === 'openssl') { switch ($this->cryptParams['type']) { @@ -598,13 +684,15 @@ 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 */ - public function decryptData($data) + public function decryptData(string $data) { if ($this->cryptParams['library'] === 'openssl') { switch ($this->cryptParams['type']) { @@ -618,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': @@ -634,8 +723,10 @@ 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, @@ -650,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': @@ -661,39 +752,32 @@ 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: - 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,16 +785,18 @@ 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; } + return $output; } + /** * * Hint: Modulus and Exponent must already be base64 decoded @@ -718,48 +804,52 @@ 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); $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"; } + /** * @param mixed $parent */ - public function serializeKey($parent) + public function serializeKey($parent): void { - } + /** * Retrieve the X509 certificate this key represents. * * 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() + public function getX509Certificate(): ?string { return $this->x509Certificate; } + /** * Get the thumbprint of this X509 certificate. * @@ -767,9 +857,9 @@ public function getX509Certificate() * 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() + public function getX509Thumbprint(): ?string { return $this->X509Thumbprint; } @@ -778,23 +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()) { + + 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; } - } 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 @@ +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); $enc->encryptKey($siteKey, $objKey); -$enc->type = XMLSecEnc::Content; +$enc->type = XMLSecEnc::CONTENT; $encNode = $enc->encryptNode($objKey); $nodeOrder = array( @@ -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/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/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..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-- 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..f5e01114 --- 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,30 +21,24 @@ $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 - if ((substr($testName, 0, 3) === "AES") && (version_compare(PHP_VERSION, '7.1.0') < 0)) { - print "Passed\n"; - continue; - } - $doc->load(dirname(__FILE__) . "/$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 +48,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 +74,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 +92,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..1cce0e7f 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'); @@ -32,13 +27,13 @@ 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); $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 a342f08f..586f5a0b 100644 --- a/tests/xmlsec-encrypt-content.phpt +++ b/tests/xmlsec-encrypt-content.phpt @@ -16,14 +16,14 @@ $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); $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-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..0c8f344c 100644 --- a/tests/xmlsec-encrypt.phpt +++ b/tests/xmlsec-encrypt.phpt @@ -16,14 +16,14 @@ $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); $enc->encryptKey($siteKey, $objKey); -$enc->type = XMLSecEnc::Element; +$enc->type = XMLSecEnc::ELEMENT; $encNode = $enc->encryptNode($objKey); $dom->save(dirname(__FILE__) . '/oaep_sha1.xml'); 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..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-- '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 +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.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.": ";