Skip to content
Snippets Groups Projects
Commit e24c2fa1 authored by Jaime Pérez Crespo's avatar Jaime Pérez Crespo
Browse files

Merge pull request #179 from s-hal/check_sig

Add metadata signature verification by using pub key from certificate
parents 501d8921 36db6536
No related branches found
No related tags found
No related merge requests found
......@@ -75,7 +75,10 @@ Here's an example of a possible configuration for both the Kalmar Federation and
'sources' => array(
array(
'src' => 'https://kalmar.feide.no/simplesaml/module.php/aggregator/?id=kalmarcentral&mimetype=text/plain&exclude=norway',
'validateFingerprint' => '591d4b4670463eeda91fcc816dc0af2a092aa801',
'certificates' => array(
'current.crt',
'rollover.crt',
),
'template' => array(
'tags' => array('kalmar'),
'authproc' => array(
......@@ -134,6 +137,14 @@ Each metadata source has the following options:
`src`
: The source URL where the metadata will be fetched from.
`certificates`
: An array of certificate files, the filename is relative to the `cert/`-directory,
that will be used to verify the signature of the metadata. The public key will
be extracted from the certificate and everything else will be ignored. So it is
possible to use a self signed certificate that has expired. Add more than one
certificate to be able to handle key rollover. This takes precedence over
validateFingerprint.
`validateFingerprint`
: The fingerprint of the certificate used to sign the metadata. You
don't need this option if you don't want to validate the signature
......
......@@ -1301,6 +1301,39 @@ class SimpleSAML_Metadata_SAMLParser {
}
/**
* If this EntityDescriptor was signed this function use the public key to check the signature.
*
* @param $certificates One ore more certificates with the public key. This makes it possible
* to do a key rollover.
* @return TRUE if it is possible to check the signature with the certificate, FALSE otherwise.
*/
public function validateSignature($certificates) {
foreach ($certificates as $cert) {
assert('is_string($cert)');
$certFile = SimpleSAML_Utilities::resolveCert($cert);
if (!file_exists($certFile)) {
throw new Exception('Could not find certificate file [' . $certFile . '], which is needed to validate signature');
}
$certData = file_get_contents($certFile);
foreach ($this->validators as $validator) {
$key = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'public'));
$key->loadKey($certData);
try {
if ($validator->validate($key)) {
return TRUE;
}
} catch (Exception $e) {
/* This certificate does not sign this element. */
}
}
}
SimpleSAML_Logger::debug('Could not validate signature');
return FALSE;
}
/**
* This function checks if this EntityDescriptor was signed with a certificate with the
* given fingerprint.
......
......@@ -34,6 +34,11 @@ $outputDir = $baseDir . '/metadata-generated';
*/
$toStdOut = FALSE;
/* $certificates contains the certificates which should be used to check the signature of the signed
* EntityDescriptor in the metadata, or NULL if signature verification shouldn't be done.
*/
$certificates = NULL;
/* $validateFingerprint contains the fingerprint of the certificate which should have been used
* to sign the EntityDescriptor in the metadata, or NULL if fingerprint validation shouldn't be
* done.
......@@ -78,6 +83,14 @@ foreach($argv as $a) {
}
switch($a) {
case '--certificate':
if($v === NULL || strlen($v) === 0) {
echo('The --certficate option requires an parameter.' . "\n");
echo('Please run `' . $progName . ' --help` for usage information.' . "\n");
exit(1);
}
$certificates[] = $v;
break;
case '--validate-fingerprint':
if($v === NULL || strlen($v) === 0) {
echo('The --validate-fingerprint option requires an parameter.' . "\n");
......@@ -120,6 +133,7 @@ $metaloader = new sspmod_metarefresh_MetaLoader();
foreach($files as $f) {
$source = array('src' => $f);
if (isset($certificates)) $source['certificates'] = $certificates;
if (isset($validateFingerprint)) $source['validateFingerprint'] = $validateFingerprint;
$metaloader->loadSource($source);
}
......@@ -145,6 +159,12 @@ function printHelp() {
echo('be added to the metadata files in metadata/.' . "\n");
echo("\n");
echo('Options:' . "\n");
echo(' --certificate=<FILE> The certificate which should be used' . "\n");
echo(' to check the signature of the metadata.' . "\n");
echo(' The file are stored in the cert dir.' . "\n");
echo(' It is possibility to add multiple' . "\n");
echo(' --certificate options to handle' . "\n");
echo(' key rollover.' . "\n");
echo(' --validate-fingerprint=<FINGERPRINT>' . "\n");
echo(' Check the signature of the metadata,' . "\n");
echo(' and check the fingerprint of the' . "\n");
......
......@@ -40,6 +40,10 @@ $config = array(
#'conditionalGET' => TRUE,
'src' => 'https://kalmar2.org/simplesaml/module.php/aggregator/?id=kalmarcentral&set=saml2&exclude=norway',
'certificates' => array(
'current.crt',
'rollover.crt',
),
'validateFingerprint' => '59:1D:4B:46:70:46:3E:ED:A9:1F:CC:81:6D:C0:AF:2A:09:2A:A8:01',
'template' => array(
'tags' => array('kalmar'),
......
......@@ -108,13 +108,24 @@ class sspmod_metarefresh_MetaLoader {
}
}
if(array_key_exists('validateFingerprint', $source) && $source['validateFingerprint'] !== NULL) {
if(!$entity->validateFingerprint($source['validateFingerprint'])) {
SimpleSAML_Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature.' . "\n");
if(array_key_exists('certificates', $source) && $source['certificates'] !== NULL) {
if(!$entity->validateSignature($source['certificates'])) {
SimpleSAML_Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature using certificate.' . "\n");
continue;
}
}
if(array_key_exists('validateFingerprint', $source) && $source['validateFingerprint'] !== NULL) {
if(!array_key_exists('certificates', $source) || $source['certificates'] == NULL) {
if(!$entity->validateFingerprint($source['validateFingerprint'])) {
SimpleSAML_Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature using fingerprint.' . "\n");
continue;
}
} else {
SimpleSAML_Logger::info('Skipping validation with fingerprint since option certificate is set.' . "\n");
}
}
$template = NULL;
if (array_key_exists('template', $source)) $template = $source['template'];
......
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