diff --git a/docs/simplesamlphp-advancedfeatures.md b/docs/simplesamlphp-advancedfeatures.md index afeef27f4c6dffbb8fd4e1a677be3f69ed0c2c13..71abf8f56072b624191d758697b6f1bbe314f520 100644 --- a/docs/simplesamlphp-advancedfeatures.md +++ b/docs/simplesamlphp-advancedfeatures.md @@ -93,6 +93,13 @@ SimpleSAMLphp supports signing of the metadata it generates. Metadata signing is - `metadata.sign.privatekey`: Name of the file with the private key which should be used to sign the metadata. This file must exist in in the `cert` directory. - `metadata.sign.privatekey_pass`: Passphrase which should be used to open the private key. This parameter is optional, and should be left out if the private key is unencrypted. - `metadata.sign.certificate`: Name of the file with the certificate which matches the private key. This file must exist in in the `cert` directory. +- `metadata.sign.algorithm`: The algorithm to use when signing metadata for this entity. Defaults to RSA-SHA1. Possible values: + + * `http://www.w3.org/2000/09/xmldsig#rsa-sha1` + *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future. + * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha256` + * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha384` + * `http://www.w3.org/2001/04/xmldsig-more#rsa-sha512` These options can be configured globally in the `config/config.php`-file, or per SP/IdP by adding them to the hosted metadata for the SP/IdP. The configuration in the metadata for the SP/IdP takes precedence over the global configuration. diff --git a/lib/SimpleSAML/Metadata/Signer.php b/lib/SimpleSAML/Metadata/Signer.php index 7ed716703a1b18ea141969413e7e38d33e7135bd..f737b92a63cff646477b3f2afdd491eee3e5ea1d 100644 --- a/lib/SimpleSAML/Metadata/Signer.php +++ b/lib/SimpleSAML/Metadata/Signer.php @@ -142,6 +142,70 @@ class SimpleSAML_Metadata_Signer } + /** + * Determine the signature and digest algorithms to use when signing metadata. + * + * This method will look for the 'metadata.sign.algorithm' key in the $entityMetadata array, or look for such + * a configuration option in the $config object. + * + * @param SimpleSAML_Configuration $config The global configuration. + * @param array $entityMetadata An array containing the metadata related to this entity. + * @param string $type A string describing the type of entity. E.g. 'SAML 2 IdP' or 'Shib 1.3 SP'. + * + * @return array An array with two keys, 'algorithm' and 'digest', corresponding to the signature and digest + * algorithms to use, respectively. + * + * @throws \SimpleSAML\Error\CriticalConfigurationError + * + * @todo change to SHA256 by default. + */ + private static function getMetadataSigningAlgorithm($config, $entityMetadata, $type) + { + // configure the algorithm to use + if (array_key_exists('metadata.sign.algorithm', $entityMetadata)) { + if (!is_string($entityMetadata['metadata.sign.algorithm'])) { + throw new \SimpleSAML\Error\CriticalConfigurationError( + "Invalid value for the 'metadata.sign.algorithm' configuration option for the ".$type. + "'".$entityMetadata['entityid']."'. This option has restricted values" + ); + } + $alg = $entityMetadata['metadata.sign.algorithm']; + } else { + $alg = $config->getString('metadata.sign.algorithm', XMLSecurityKey::RSA_SHA1); + } + + $supported_algs = array( + XMLSecurityKey::RSA_SHA1, + XMLSecurityKey::RSA_SHA256, + XMLSecurityKey::RSA_SHA384, + XMLSecurityKey::RSA_SHA512, + ); + + if (!in_array($alg, $supported_algs)) { + throw new \SimpleSAML\Error\CriticalConfigurationError("Unknown signature algorithm '$alg'"); + } + + switch ($alg) { + case XMLSecurityKey::RSA_SHA256: + $digest = XMLSecurityDSig::SHA256; + break; + case XMLSecurityKey::RSA_SHA384: + $digest = XMLSecurityDSig::SHA384; + break; + case XMLSecurityKey::RSA_SHA512: + $digest = XMLSecurityDSig::SHA512; + break; + default: + $digest = XMLSecurityDSig::SHA1; + } + + return array( + 'algorithm' => $alg, + 'digest' => $digest, + ); + } + + /** * Signs the given metadata if metadata signing is enabled. * @@ -186,8 +250,10 @@ class SimpleSAML_Metadata_Signer throw new Exception('Error parsing self-generated metadata.'); } + $signature_cf = self::getMetadataSigningAlgorithm($config, $entityMetadata, $type); + // load the private key - $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private')); + $objKey = new XMLSecurityKey($signature_cf['algorithm'], array('type' => 'private')); if (array_key_exists('privatekey_pass', $keyCertFiles)) { $objKey->passphrase = $keyCertFiles['privatekey_pass']; } @@ -207,7 +273,7 @@ class SimpleSAML_Metadata_Signer $objXMLSecDSig->addReferenceList( array($rootNode), - XMLSecurityDSig::SHA1, + $signature_cf['digest'], array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N), array('id_name' => 'ID') );