public function canValidate(SAML2_SignedElement $signedElement, SAML2_Configuration_CertificateProvider $configuration) { if ($configuration->getCertificateFingerprints() === NULL) { $this->logger->debug('Configuration does not have "certFingerprint" value, cannot validate signature with fingerprint'); return FALSE; } // use internal cache to prevent doing certificate extraction twice. $this->certificates = $signedElement->getCertificates(); if (empty($this->certificates)) { $this->logger->debug('Signed element does not have certificates, cannot validate signature with fingerprint'); return FALSE; } return TRUE; }
/** * Check the signature on a SAML2 message or assertion. * * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender. * @param SAML2_SignedElement $element Either a SAML2_Response or a SAML2_Assertion. */ public static function checkSign(SimpleSAML_Configuration $srcMetadata, SAML2_SignedElement $element) { /* Find the public key that should verify signatures by this entity. */ $keys = $srcMetadata->getPublicKeys('signing'); if ($keys !== NULL) { $pemKeys = array(); foreach ($keys as $key) { switch ($key['type']) { case 'X509Certificate': $pemKeys[] = "-----BEGIN CERTIFICATE-----\n" . chunk_split($key['X509Certificate'], 64) . "-----END CERTIFICATE-----\n"; break; default: SimpleSAML_Logger::debug('Skipping unknown key type: ' . $key['type']); } } } elseif ($srcMetadata->hasValue('certFingerprint')) { $certFingerprint = $srcMetadata->getArrayizeString('certFingerprint'); foreach ($certFingerprint as &$fp) { $fp = strtolower(str_replace(':', '', $fp)); } $certificates = $element->getCertificates(); /* * We don't have the full certificate stored. Try to find it * in the message or the assertion instead. */ if (count($certificates) === 0) { /* We need the full certificate in order to match it against the fingerprint. */ SimpleSAML_Logger::debug('No certificate in message when validating against fingerprint.'); return FALSE; } else { SimpleSAML_Logger::debug('Found ' . count($certificates) . ' certificates in ' . get_class($element)); } $pemCert = self::findCertificate($certFingerprint, $certificates); $pemKeys = array($pemCert); } else { throw new SimpleSAML_Error_Exception('Missing certificate in metadata for ' . var_export($srcMetadata->getString('entityid'), TRUE)); } SimpleSAML_Logger::debug('Has ' . count($pemKeys) . ' candidate keys for validation.'); $lastException = NULL; foreach ($pemKeys as $i => $pem) { $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public')); $key->loadKey($pem); try { /* * Make sure that we have a valid signature on either the response * or the assertion. */ $res = $element->validate($key); if ($res) { SimpleSAML_Logger::debug('Validation with key #' . $i . ' succeeded.'); return TRUE; } SimpleSAML_Logger::debug('Validation with key #' . $i . ' failed without exception.'); } catch (Exception $e) { SimpleSAML_Logger::debug('Validation with key #' . $i . ' failed with exception: ' . $e->getMessage()); $lastException = $e; } } /* We were unable to validate the signature with any of our keys. */ if ($lastException !== NULL) { throw $lastException; } else { return FALSE; } }
/** * Check the signature on a SAML2 message or assertion. * * @param SimpleSAML_Configuration $srcMetadata The metadata of the sender. * @param SAML2_SignedElement $element Either a SAML2_Response or a SAML2_Assertion. */ public static function checkSign(SimpleSAML_Configuration $srcMetadata, SAML2_SignedElement $element) { $certificates = $element->getCertificates(); SimpleSAML_Logger::debug('Found ' . count($certificates) . ' certificates in ' . get_class($element)); /* Find the certificate that should verify signatures by this entity. */ $certArray = SimpleSAML_Utilities::loadPublicKey($srcMetadata, FALSE); if ($certArray !== NULL) { if (array_key_exists('PEM', $certArray)) { $pemCert = $certArray['PEM']; } else { /* * We don't have the full certificate stored. Try to find it * in the message or the assertion instead. */ if (count($certificates) === 0) { /* We need the full certificate in order to match it against the fingerprint. */ SimpleSAML_Logger::debug('No certificate in message when validating against fingerprint.'); return FALSE; } $certFingerprints = $certArray['certFingerprint']; if (count($certFingerprints) === 0) { /* For some reason, we have a certFingerprint entry without any fingerprints. */ throw new SimpleSAML_Error_Exception('certFingerprint array was empty.'); } $pemCert = self::findCertificate($certFingerprints, $certificates); } } else { /* Attempt CA validation. */ $caFile = $srcMetadata->getString('caFile', NULL); if ($caFile === NULL) { throw new SimpleSAML_Error_Exception('Missing certificate in metadata for ' . var_export($srcMetadata->getString('entityid'), TRUE)); } $caFile = SimpleSAML_Utilities::resolveCert($caFile); if (count($certificates) === 0) { /* We need the full certificate in order to check it against the CA file. */ SimpleSAML_Logger::debug('No certificate in message when validating with CA.'); return FALSE; } /* We assume that it is the first certificate that was used to sign the message. */ $pemCert = "-----BEGIN CERTIFICATE-----\n" . chunk_split($certificates[0], 64) . "-----END CERTIFICATE-----\n"; SimpleSAML_Utilities::validateCA($pemCert, $caFile); } /* Extract the public key from the certificate for validation. */ $key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public')); $key->loadKey($pemCert); /* * Make sure that we have a valid signature on either the response * or the assertion. */ return $element->validate($key); }