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

Add metadata signing.

This patch adds metadata signing. It can be enabled globally by setting
the 'metadata.sign.enable' global option, or per SP/IdP by setting
the same option in the metadata of the SP/IdP.

To sign the metadata, both a private key and a certificate is used. The
following configuration options determine which key and certificate files
will be used:

- per SP/IdP metadata:
  'metadata.sign.privatekey' & 'metadata.sign.certificate'
- globally:
  'metadata.sign.privatekey' & 'metadata.sign.certificate'
- per SP/IdP metadata: (fallback)
  'privatekey' & 'certificate'


git-svn-id: https://simplesamlphp.googlecode.com/svn/trunk@593 44740490-163a-0410-bde0-09ae8108e29a
parent 6d9d1a7b
No related branches found
No related tags found
No related merge requests found
......@@ -363,6 +363,27 @@ $config = array (
'memcache_store.expires' => 36 * (60*60), // 36 hours.
/*
* Should signing of generated metadata be enabled by default.
*
* Metadata signing can also be enabled for a individual SP or IdP by setting the
* same option in the metadata for the SP or IdP.
*/
'metadata.sign.enable' => FALSE,
/*
* The default key & certificate which should be used to sign generated metadata. These
* are files stored in the cert dir.
* These values can be overridden by the options with the same names in the SP or
* IdP metadata.
*
* If these aren't specified here or in the metadata for the SP or IdP, then
* the 'certificate' and 'privatekey' option in the metadata will be used.
* if those aren't set, signing of metadata will fail.
*/
'metadata.sign.privatekey' => NULL,
'metadata.sign.certificate' => NULL,
);
......
<?php
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Configuration.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'xmlseclibs.php');
/**
* This class implements a helper function for signing of metadata.
*
* @author Olav Morken, UNINETT AS.
* @package simpleSAMLphp
* @version $Id$
*/
class SimpleSAML_Metadata_Signer {
/**
* This functions finds what key & certificate files should be used to sign the metadata
* for the given entity.
*
* @param $config Our SimpleSAML_Configuration instance.
* @param $entityMetadata The metadata of the entity.
* @param $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or 'Shib 1.3 SP'.
* @return An associative array with the keys 'privatekey' and 'certificate'.
*/
private static function findKeyCert($config, $entityMetadata, $type) {
/* First we look for metadata.privatekey and metadata.certificate in the metadata. */
if(array_key_exists('metadata.sign.privatekey', $entityMetadata)
|| array_key_exists('metadata.sign.certificate', $entityMetadata)) {
if(!array_key_exists('metadata.sign.privatekey', $entityMetadata)
|| !array_key_exists('metadata.sign.certificate', $entityMetadata)) {
throw new Exception('Missing either the "metadata.sign.privatekey" or the' .
' "metadata.sign.certificate" configuration option in the metadata for' .
' the ' . $type . ' "' . $entityMetadata['entityid'] . '". If one of' .
' these options is specified, then the other must also be specified.');
}
return array(
'privatekey' => $entityMetadata['metadata.sign.privatekey'],
'certificate' => $entityMetadata['metadata.sign.certificate']
);
}
/* Then we look for default values in the global configuration. */
$privatekey = $config->getValue('metadata.sign.privatekey', NULL);
$certificate = $config->getValue('metadata.sign.certificate', NULL);
if($privatekey !== NULL || $certificate !== NULL) {
if($privatekey === NULL || $certificate === NULL) {
throw new Exception('Missing either the "metadata.sign.privatekey" or the' .
' "metadata.sign.certificate" configuration option in the global' .
' configuration. If one of these options is specified, then the other'.
' must also be specified.');
}
return array('privatekey' => $privatekey, 'certificate' => $certificate);
}
/* As a last resort we attempt to use the privatekey and certificate option from the metadata. */
if(array_key_exists('privatekey', $entityMetadata)
|| array_key_exists('certificate', $entityMetadata)) {
if(!array_key_exists('privatekey', $entityMetadata)
|| !array_key_exists('certificate', $entityMetadata)) {
throw new Exception('Both the "privatekey" and the "certificate" option must' .
' be set in the metadata for the ' . $type .' "' .
$entityMetadata['entityid'] . '" before it is possible to sign metadata' .
' from this entity.');
}
return array(
'privatekey' => $entityMetadata['privatekey'],
'certificate' => $entityMetadata['certificate']
);
}
throw new Exception('Could not find what key & certificate should be used to sign the metadata' .
' for the ' . $type . ' "' . $entityMetadata['entityid'] . '".');
}
/**
* Determine whether metadata signing is enabled for the given metadata.
*
* @param $config Our SimpleSAML_Configuration instance.
* @param $entityMetadata The metadata of the entity.
* @param $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or 'Shib 1.3 SP'.
*/
private static function isMetadataSigningEnabled($config, $entityMetadata, $type) {
/* First check the metadata for the entity. */
if(array_key_exists('metadata.sign.enable', $entityMetadata)) {
if(!is_bool($entityMetadata['metadata.sign.enable'])) {
throw new Exception(
'Invalid value for the "metadata.sign.enable" configuration option for' .
' the ' . $type .' "' . $entityMetadata['entityid'] . '". This option' .
' should be a boolean.');
}
return $entityMetadata['metadata.sign.enable'];
}
$enabled = $config->getValue('metadata.sign.enable', FALSE);
if(!is_bool($enabled)) {
throw new Exception('Invalid value for the "metadata.sign.enable" configuration option.' .
' This option should be a boolean.');
}
return $enabled;
}
/**
* Signs the given metadata if metadata signing is enabled.
*
* @param $metadataString A string with the metadata.
* @param $entityMetadata The metadata of the entity.
* @param $type A string which describes the type entity this is, e.g. 'SAML 2 IdP' or 'Shib 1.3 SP'.
* @return The $metadataString with the signature embedded.
*/
public static function sign($metadataString, $entityMetadata, $type) {
$config = SimpleSAML_Configuration::getInstance();
/* Check if metadata signing is enabled. */
if (!self::isMetadataSigningEnabled($config, $entityMetadata, $type)) {
return $metadataString;
}
/* Find the key & certificate which should be used to sign the metadata. */
$keyCertFiles = self::findKeyCert($config, $entityMetadata, $type);
$keyFile = $config->getPathValue('certdir') . $keyCertFiles['privatekey'];
if (!file_exists($keyFile)) {
throw new Exception('Could not find private key file [' . $keyFile . '], which is needed to sign the metadata');
}
$keyData = file_get_contents($keyFile);
$certFile = $config->getPathValue('certdir') . $keyCertFiles['certificate'];
if (!file_exists($certFile)) {
throw new Exception('Could not find certificate file [' . $certFile . '], which is needed to sign the metadata');
}
$certData = file_get_contents($certFile);
/* Convert the metadata to a DOM tree. */
$xml = new DOMDocument();
if(!$xml->loadXML($metadataString)) {
throw new Exception('Error parsing self-generated metadata.');
}
/* Load the private key. */
$objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'private'));
$objKey->loadKey($keyData, FALSE);
/* Get the EntityDescriptor node we should sign. */
$rootNode = $xml->firstChild;
/* Sign the metadata with our private key. */
$objXMLSecDSig = new XMLSecurityDSig();
$objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
$objXMLSecDSig->addReferenceList(array($rootNode), XMLSecurityDSig::SHA1,
array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
array('id_name' => 'ID'));
$objXMLSecDSig->sign($objKey);
/* Add the certificate to the signature. */
$objXMLSecDSig->add509Cert($certData, true);
/* Add the signature to the metadata. */
$objXMLSecDSig->insertSignature($rootNode, $rootNode->firstChild);
/* Return the DOM tree as a string. */
return $xml->saveXML();
}
}
?>
\ No newline at end of file
......@@ -34,7 +34,7 @@ try {
foreach ($metalist AS $entityid => $mentry) {
$results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry,
array('entityid', 'host'),
array('request.signing','certificate','privatekey', 'NameIDFormat', 'ForceAuthn', 'AuthnContextClassRef', 'SPNameQualifier', 'attributemap', 'attributealter', 'attributes')
array('request.signing','certificate','privatekey', 'NameIDFormat', 'ForceAuthn', 'AuthnContextClassRef', 'SPNameQualifier', 'attributemap', 'attributealter', 'attributes', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate')
);
}
$et->data['metadata.saml20-sp-hosted'] = $results;
......@@ -57,7 +57,7 @@ try {
foreach ($metalist AS $entityid => $mentry) {
$results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry,
array('entityid', 'host', 'privatekey', 'certificate', 'auth'),
array('requireconsent','request.signing', 'authority', 'attributemap', 'attributealter', 'userid.attribute')
array('requireconsent','request.signing', 'authority', 'attributemap', 'attributealter', 'userid.attribute', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate')
);
}
$et->data['metadata.saml20-idp-hosted'] = $results;
......@@ -94,7 +94,7 @@ try {
foreach ($metalist AS $entityid => $mentry) {
$results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry,
array('entityid', 'SingleSignOnService', 'certFingerprint'),
array('name', 'description', 'base64attributes')
array('name', 'description', 'base64attributes', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate')
);
}
$et->data['metadata.shib13-idp-remote'] = $results;
......@@ -117,7 +117,7 @@ try {
foreach ($metalist AS $entityid => $mentry) {
$results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry,
array('entityid', 'AssertionConsumerService'),
array('base64attributes', 'audience', 'attributemap', 'attributealter', 'simplesaml.attributes', 'attributes', 'name', 'description')
array('base64attributes', 'audience', 'attributemap', 'attributealter', 'simplesaml.attributes', 'attributes', 'name', 'description', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate')
);
}
$et->data['metadata.shib13-sp-remote'] = $results;
......
......@@ -5,10 +5,9 @@ require_once('../../_include.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Utilities.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Session.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandler.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/Signer.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/XHTML/Template.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'xmlseclibs.php');
/* Load simpleSAMLphp, configuration and metadata */
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
......@@ -91,8 +90,10 @@ try {
</IDPSSODescriptor>
</EntityDescriptor>';
/* Sign the metadata if enabled. */
$metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta, 'SAML 2 IdP');
if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') {
$defaultidp = $config->getValue('default-saml20-idp');
......
......@@ -5,6 +5,7 @@ require_once('../../_include.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Utilities.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Session.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandler.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/Signer.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/XHTML/Template.php');
/* Load simpleSAMLphp, configuration and metadata */
......@@ -83,6 +84,9 @@ try {
</EntityDescriptor>';
/* Sign the metadata if enabled. */
$metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $spmeta, 'SAML 2 SP');
if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') {
$defaultidp = $config->getValue('default-saml20-idp');
......
......@@ -5,10 +5,9 @@ require_once('../../_include.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Utilities.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Session.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandler.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/Signer.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/XHTML/Template.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'xmlseclibs.php');
/* Load simpleSAMLphp, configuration and metadata */
$config = SimpleSAML_Configuration::getInstance();
$metadata = SimpleSAML_Metadata_MetaDataStorageHandler::getMetadataHandler();
......@@ -76,6 +75,9 @@ try {
</ContactPerson>
</EntityDescriptor>';
/* Sign the metadata if enabled. */
$metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $idpmeta, 'Shib 1.3 IdP');
if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') {
......
......@@ -5,6 +5,7 @@ require_once('../../_include.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Utilities.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Session.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/MetaDataStorageHandler.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/Metadata/Signer.php');
require_once((isset($SIMPLESAML_INCPREFIX)?$SIMPLESAML_INCPREFIX:'') . 'SimpleSAML/XHTML/Template.php');
/* Load simpleSAMLphp, configuration and metadata */
......@@ -55,6 +56,9 @@ try {
</EntityDescriptor>';
/* Sign the metadata if enabled. */
$metaxml = SimpleSAML_Metadata_Signer::sign($metaxml, $spmeta, 'Shib 1.3 SP');
if (array_key_exists('output', $_GET) && $_GET['output'] == 'xhtml') {
$defaultidp = $config->getValue('default-shib13-idp');
......
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