Skip to content
Snippets Groups Projects
Commit ada5d43c authored by Olav Morken's avatar Olav Morken
Browse files

Validator: add support for public keys loaded by SimpleSAML_Utilities::loadPublicKey()

git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@925 44740490-163a-0410-bde0-09ae8108e29a
parent 13da7052
No related branches found
No related tags found
No related merge requests found
......@@ -24,14 +24,33 @@ class SimpleSAML_XML_Validator {
/**
* This function initializes the validator.
*
* @param $xmlNode The XML node which contains the Signature element.
* @param $idAttribute The ID attribute which is used in node references. If this attribute is
* NULL (the default), then we will use whatever is the default ID. Can be eigther
* a string with one value, or an array with multiple ID attrbute names.
* This function accepts an optional parameter $publickey, which is the public key
* or certificate which should be used to validate the signature. This parameter can
* take the following values:
* - NULL/FALSE: No validation will be performed. This is the default.
* - A string: Assumed to be a PEM-encoded certificate / public key.
* - An array: Assumed to be an array returned by SimpleSAML_Utilities::loadPublicKey.
*
* @param DOMNode $xmlNode The XML node which contains the Signature element.
* @param string|array $idAttribute The ID attribute which is used in node references. If
* this attribute is NULL (the default), then we will use whatever is the default
* ID. Can be eigther a string with one value, or an array with multiple ID
* attrbute names.
* @param array $publickey The public key / certificate which should be used to validate the XML node.
*/
public function __construct($xmlNode, $idAttribute = NULL, $publickey = FALSE) {
assert('$xmlNode instanceof DOMNode');
if ($publickey === NULL) {
$publickey = FALSE;
} elseif(is_string($publickey)) {
$publickey = array(
'PEM' => $publickey,
);
} else {
assert('$publickey === FALSE || is_array($publickey)');
}
/* Create an XML security object. */
$objXMLSecDSig = new XMLSecurityDSig();
......@@ -67,13 +86,35 @@ class SimpleSAML_XML_Validator {
}
/* Load the key data. */
if ($publickey) {
$objKey->loadKey($publickey);
if (array_key_exists('PEM', $publickey)) {
/* We have PEM data for the public key / certificate. */
$objKey->loadKey($publickey['PEM']);
} else {
/* No PEM data. Search for key in signature. */
if (!XMLSecEnc::staticLocateKeyInfo($objKey, $signatureElement)) {
throw new Exception('Error finding key data for XML signature validation.');
}
if ($publickey !== FALSE) {
/* $publickey is set, and should therefore contain one or more fingerprints.
* Check that the response contains a certificate with a matching
* fingerprint.
*/
assert('is_array($publickey["certFingerprint"])');
$certificate = $objKey->getX509Certificate();
if ($certificate === NULL) {
/* Wasn't signed with an X509 certificate. */
throw new Exception('Message wasn\'t signed with an X509 certificate,' .
' and no public key was provided in the metadata.');
}
self::validateCertificateFingerprint($certificate, $publickey['certFingerprint']);
/* Key OK. */
}
}
/* Check the signature. */
if (! $objXMLSecDSig->verify($objKey)) {
throw new Exception("Unable to validate Signature");
......@@ -140,6 +181,42 @@ class SimpleSAML_XML_Validator {
}
/**
* Helper function for validating the fingerprint.
*
* Checks the fingerprint of a certificate against an array of valid fingerprints.
* Will throw an exception if none of the fingerprints matches.
*
* @param string $certificate The X509 certificate we should validate.
* @param array $fingerprints The valid fingerprints.
*/
private static function validateCertificateFingerprint($certificate, $fingerprints) {
assert('is_string($certificate)');
assert('is_array($fingerprints)');
$certFingerprint = self::calculateX509Fingerprint($certificate);
if ($certFingerprint === NULL) {
/* Couldn't calculate fingerprint from X509 certificate. Should not happen. */
throw new Exception('Unable to calculate fingerprint from X509' .
' certificate. Maybe it isn\'t an X509 certificate?');
}
foreach ($fingerprints as $fp) {
assert('is_string($fp)');
if ($fp === $certFingerprint) {
/* The fingerprints matched. */
return;
}
}
/* None of the fingerprints matched. Throw an exception describing the error. */
throw new Exception('Invalid fingerprint of certificate. Expected one of [' .
implode('], [', $fingerprints) . '], but got [' . $certFingerprint . ']');
}
/**
* Validate the fingerprint of the certificate which was used to sign this document.
*
......@@ -156,28 +233,20 @@ class SimpleSAML_XML_Validator {
if($this->x509Certificate === NULL) {
throw new Exception('Key used to sign the message was not an X509 certificate.');
}
$certFingerprint = self::calculateX509Fingerprint($this->x509Certificate);
if(!is_array($fingerprints)) {
$fingerprints = array($fingerprints);
}
foreach($fingerprints as $fp) {
/* Normalize the fingerprints. */
foreach($fingerprints as &$fp) {
assert('is_string($fp)');
/* Make sure that the fingerprint is in the correct format. */
$fp = strtolower(str_replace(":", "", $fp));
if($fp === $certFingerprint) {
/* The fingerprints matched. */
return;
}
}
/* None of the fingerprints matched. Throw an exception describing the error. */
throw new Exception('Invalid fingerprint of certificate. Expected one of [' .
implode('], [', $fingerprints) . '], but got [' . $certFingerprint . ']');
self::validateCertificateFingerprint($this->x509Certificate, $fingerprints);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment