diff --git a/lib/SimpleSAML/Metadata/SAMLParser.php b/lib/SimpleSAML/Metadata/SAMLParser.php index f5b26cadcf89e971e1d42f45ed8136024904ff01..cc5b84eef430243e2cb305f306480bacfb39faef 100644 --- a/lib/SimpleSAML/Metadata/SAMLParser.php +++ b/lib/SimpleSAML/Metadata/SAMLParser.php @@ -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. diff --git a/modules/metarefresh/bin/metarefresh.php b/modules/metarefresh/bin/metarefresh.php index 4af3dfb469118901508ad2f395b1cf529879911c..fd51caaabb42e9d99ab831037d8544c20b8d7853 100755 --- a/modules/metarefresh/bin/metarefresh.php +++ b/modules/metarefresh/bin/metarefresh.php @@ -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"); diff --git a/modules/metarefresh/config-templates/config-metarefresh.php b/modules/metarefresh/config-templates/config-metarefresh.php index 18bfd30f6a29f09c80ad53f7cca94ad73fa75618..8da56ebcc2c135d5710431d95fd2b4a964d7b2dc 100644 --- a/modules/metarefresh/config-templates/config-metarefresh.php +++ b/modules/metarefresh/config-templates/config-metarefresh.php @@ -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'), diff --git a/modules/metarefresh/lib/MetaLoader.php b/modules/metarefresh/lib/MetaLoader.php index 86e68b02fcea054094bd0d1e3d453377d043e1e2..c7871f592a3db163176030883976885131cdee65 100644 --- a/modules/metarefresh/lib/MetaLoader.php +++ b/modules/metarefresh/lib/MetaLoader.php @@ -108,9 +108,16 @@ class sspmod_metarefresh_MetaLoader { } } + 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(!$entity->validateFingerprint($source['validateFingerprint'])) { - SimpleSAML_Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature.' . "\n"); + SimpleSAML_Logger::info('Skipping "' . $entity->getEntityId() . '" - could not verify signature using fingerprint.' . "\n"); continue; } }