Пример #1
0
	public function testTransforms() 
	{
		$trans = new Zend_InfoCard_Xml_Security_Transform();

		try {
			$trans->addTransform("foo");
			$this->fail("Expected Exception Not Thrown");
		} catch(Exception $e) {
			/* yay */
		}
		
		$this->assertTrue(is_array($trans->getTransformList()));
		
	}
Пример #2
0
    /**
     * Validates the signature of a provided XML block
     *
     * @param  string $strXMLInput An XML block containing a Signature
     * @return bool True if the signature validated, false otherwise
     * @throws Zend_InfoCard_Xml_Security_Exception
     */
    static public function validateXMLSignature($strXMLInput)
    {
        if(!extension_loaded('openssl')) {
            throw new Zend_InfoCard_Xml_Security_Exception("You must have the openssl extension installed to use this class");
        }

        $sxe = simplexml_load_string($strXMLInput);

        if(!isset($sxe->Signature)) {
            throw new Zend_InfoCard_Xml_Security_Exception("Could not identify XML Signature element");
        }

        if(!isset($sxe->Signature->SignedInfo)) {
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a SignedInfo block");
        }

        if(!isset($sxe->Signature->SignatureValue)) {
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a SignatureValue block");
        }

        if(!isset($sxe->Signature->KeyInfo)) {
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a KeyInfo block");
        }

        if(!isset($sxe->Signature->KeyInfo->KeyValue)) {
            throw new Zend_InfoCard_Xml_Security_Exception("Signature is missing a KeyValue block");
        }

        switch((string)$sxe->Signature->SignedInfo->CanonicalizationMethod['Algorithm']) {
            case self::CANONICAL_METHOD_C14N_EXC:
                $cMethod = (string)$sxe->Signature->SignedInfo->CanonicalizationMethod['Algorithm'];
                break;
            default:
                throw new Zend_InfoCard_Xml_Security_Exception("Unknown or unsupported CanonicalizationMethod Requested");
        }

        switch((string)$sxe->Signature->SignedInfo->SignatureMethod['Algorithm']) {
            case self::SIGNATURE_METHOD_SHA1:
                $sMethod = (string)$sxe->Signature->SignedInfo->SignatureMethod['Algorithm'];
                break;
            default:
                throw new Zend_InfoCard_Xml_Security_Exception("Unknown or unsupported SignatureMethod Requested");
        }

        switch((string)$sxe->Signature->SignedInfo->Reference->DigestMethod['Algorithm']) {
            case self::DIGEST_METHOD_SHA1:
                $dMethod = (string)$sxe->Signature->SignedInfo->Reference->DigestMethod['Algorithm'];
                break;
            default:
                throw new Zend_InfoCard_Xml_Security_Exception("Unknown or unsupported DigestMethod Requested");
        }

        $dValue = base64_decode((string)$sxe->Signature->SignedInfo->Reference->DigestValue, true);

        $signatureValue = base64_decode((string)$sxe->Signature->SignatureValue, true);

        $transformer = new Zend_InfoCard_Xml_Security_Transform();

        foreach($sxe->Signature->SignedInfo->Reference->Transforms->children() as $transform) {
            $transformer->addTransform((string)$transform['Algorithm']);
        }

        $transformed_xml = $transformer->applyTransforms($strXMLInput);

        $transformed_xml_binhash = pack("H*", sha1($transformed_xml));

        if($transformed_xml_binhash != $dValue) {
            throw new Zend_InfoCard_Xml_Security_Exception("Locally Transformed XML does not match XML Document. Cannot Verify Signature");
        }

        $public_key = null;

        switch(true) {
            case isset($sxe->Signature->KeyInfo->KeyValue->X509Certificate):

                $certificate = (string)$sxe->Signature->KeyInfo->KeyValue->X509Certificate;


                $pem = "-----BEGIN CERTIFICATE-----\n" .
                       wordwrap($certificate, 64, "\n", true) .
                       "\n-----END CERTIFICATE-----";

                $public_key = openssl_pkey_get_public($pem);

                if(!$public_key) {
                    throw new Zend_InfoCard_Xml_Security_Exception("Unable to extract and prcoess X509 Certificate from KeyValue");
                }

                break;
            case isset($sxe->Signature->KeyInfo->KeyValue->RSAKeyValue):

                if(!isset($sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Modulus) ||
                   !isset($sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Exponent)) {
                    throw new Zend_InfoCard_Xml_Security_Exception("RSA Key Value not in Modulus/Exponent form");
                }

                $modulus = base64_decode((string)$sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Modulus);
                $exponent = base64_decode((string)$sxe->Signature->KeyInfo->KeyValue->RSAKeyValue->Exponent);

                $pem_public_key = self::_getPublicKeyFromModExp($modulus, $exponent);

                $public_key = openssl_pkey_get_public ($pem_public_key);

                break;
            default:
                throw new Zend_InfoCard_Xml_Security_Exception("Unable to determine or unsupported representation of the KeyValue block");
        }

        $transformer = new Zend_InfoCard_Xml_Security_Transform();
        $transformer->addTransform((string)$sxe->Signature->SignedInfo->CanonicalizationMethod['Algorithm']);

        // The way we are doing our XML processing requires that we specifically add this
        // (even though it's in the <Signature> parent-block).. otherwise, our canonical form
        // fails signature verification
        $sxe->Signature->SignedInfo->addAttribute('xmlns', 'http://www.w3.org/2000/09/xmldsig#');

        $canonical_signedinfo = $transformer->applyTransforms($sxe->Signature->SignedInfo->asXML());

        if(@openssl_verify($canonical_signedinfo, $signatureValue, $public_key)) {
            return (string)$sxe->Signature->SignedInfo->Reference['URI'];
        }

        return false;
    }
 /**
  * Validates the signature of a provided XML block
  *
  * @param  string $strXMLInput An XML block containing a Signature
  * @return bool True if the signature validated, false otherwise
  * @throws Exception
  */
 public static function validateXMLSignature($strXMLInput, $sts_crt = NULL)
 {
     if (!extension_loaded('openssl')) {
         throw new Exception("You must have the openssl extension installed to use this class");
     }
     $sxe = simplexml_load_string($strXMLInput);
     if ($sts_crt != NULL) {
         $sxe->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
         list($keyValue) = $sxe->xpath("//ds:Signature/ds:KeyInfo");
         $keyValue->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
         list($x509cert) = $keyValue->xpath("ds:X509Data/ds:X509Certificate");
         list($rsaKeyValue) = $keyValue->xpath("ds:KeyValue/ds:RSAKeyValue");
         //Extract the XMLToken issuer public key
         switch (true) {
             case isset($x509cert):
                 SimpleSAML\Logger::debug("Public Key: x509cert");
                 $certificate = (string) $x509cert;
                 $cert_issuer = "-----BEGIN CERTIFICATE-----\n" . wordwrap($certificate, 64, "\n", true) . "\n-----END CERTIFICATE-----";
                 if (!($t_key = openssl_pkey_get_public($cert_issuer))) {
                     throw new Exception("Wrong token certificate");
                 }
                 $t_det = openssl_pkey_get_details($t_key);
                 $pem_issuer = $t_det['key'];
                 break;
             case isset($rsaKeyValue):
                 $rsaKeyValue->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
                 list($modulus) = $rsaKeyValue->xpath("ds:Modulus");
                 list($exponent) = $rsaKeyValue->xpath("ds:Exponent");
                 if (!isset($modulus) || !isset($exponent)) {
                     throw new Exception("RSA Key Value not in Modulus/Exponent form");
                 }
                 $modulus = base64_decode((string) $modulus);
                 $exponent = base64_decode((string) $exponent);
                 $pem_issuer = self::_getPublicKeyFromModExp($modulus, $exponent);
                 break;
             default:
                 SimpleSAML\Logger::debug("Public Key: Unknown");
                 throw new Exception("Unable to determine or unsupported representation of the KeyValue block");
         }
         //Check isuer public key against configured one
         $checkcert = file_get_contents($sts_crt);
         $check_key = openssl_pkey_get_public($checkcert);
         $checkData = openssl_pkey_get_details($check_key);
         $pem_local = $checkData['key'];
         if (strcmp($pem_issuer, $pem_local) != 0) {
             SimpleSAML\Logger::debug("Configured STS cert and received STS cert mismatch");
             openssl_free_key($check_key);
             throw new Exception("Configured STS cert and received STS cert mismatch");
         }
         //Validate XML signature
         $sxe->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
         list($canonMethod) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:CanonicalizationMethod");
         switch ((string) $canonMethod['Algorithm']) {
             case self::CANONICAL_METHOD_C14N_EXC:
                 $cMethod = (string) $canonMethod['Algorithm'];
                 break;
             default:
                 throw new Exception("Unknown or unsupported CanonicalizationMethod Requested");
         }
         list($signatureMethod) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:SignatureMethod");
         switch ((string) $signatureMethod['Algorithm']) {
             case self::SIGNATURE_METHOD_SHA1:
                 $sMethod = (string) $signatureMethod['Algorithm'];
                 break;
             default:
                 throw new Exception("Unknown or unsupported SignatureMethod Requested");
         }
         list($digestMethod) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference/ds:DigestMethod");
         switch ((string) $digestMethod['Algorithm']) {
             case self::DIGEST_METHOD_SHA1:
                 $dMethod = (string) $digestMethod['Algorithm'];
                 break;
             default:
                 throw new Exception("Unknown or unsupported DigestMethod Requested");
         }
         $base64DecodeSupportsStrictParam = version_compare(PHP_VERSION, '5.2.0', '>=');
         list($digestValue) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference/ds:DigestValue");
         if ($base64DecodeSupportsStrictParam) {
             $dValue = base64_decode((string) $digestValue, true);
         } else {
             $dValue = base64_decode((string) $digestValue);
         }
         list($signatureValueElem) = $sxe->xpath("//ds:Signature/ds:SignatureValue");
         if ($base64DecodeSupportsStrictParam) {
             $signatureValue = base64_decode((string) $signatureValueElem, true);
         } else {
             $signatureValue = base64_decode((string) $signatureValueElem);
         }
         $transformer = new Zend_InfoCard_Xml_Security_Transform();
         $transforms = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference/ds:Transforms/ds:Transform");
         while (list(, $transform) = each($transforms)) {
             $transformer->addTransform((string) $transform['Algorithm']);
         }
         $transformed_xml = $transformer->applyTransforms($strXMLInput);
         $transformed_xml_binhash = pack("H*", sha1($transformed_xml));
         if ($transformed_xml_binhash != $dValue) {
             throw new Exception("Locally Transformed XML (" . $transformed_xml_binhash . ") does not match XML Document  (" . $dValue . "). Cannot Verify Signature");
         }
         $transformer = new Zend_InfoCard_Xml_Security_Transform();
         $transformer->addTransform((string) $canonMethod['Algorithm']);
         list($signedInfo) = $sxe->xpath("//ds:Signature/ds:SignedInfo");
         //SimpleSAML\Logger::debug
         //print ("signedinfo ".$sxe->saveXML());
         $signedInfoXML = self::addNamespace($signedInfo, "http://www.w3.org/2000/09/xmldsig#");
         SimpleSAML\Logger::debug("canonicalizo " . $signedInfoXML);
         $canonical_signedinfo = $transformer->applyTransforms($signedInfoXML);
         if (openssl_verify($canonical_signedinfo, $signatureValue, $check_key)) {
             list($reference) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference");
             openssl_free_key($check_key);
             return (string) $reference['URI'];
         } else {
             openssl_free_key($check_key);
             throw new Exception("Could not validate the XML signature");
         }
     } else {
         $sxe->registerXPathNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
         list($reference) = $sxe->xpath("//ds:Signature/ds:SignedInfo/ds:Reference");
         return (string) $reference['URI'];
     }
     return false;
 }