$entityMetadata['metadata.sign.privatekey'], 'certificate' => $entityMetadata['metadata.sign.certificate'] ); if(array_key_exists('metadata.sign.privatekey_pass', $entityMetadata)) { $ret['privatekey_pass'] = $entityMetadata['metadata.sign.privatekey_pass']; } return $ret; } /* Then we look for default values in the global configuration. */ $privatekey = $config->getString('metadata.sign.privatekey', NULL); $certificate = $config->getString('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.'); } $ret = array('privatekey' => $privatekey, 'certificate' => $certificate); $privatekey_pass = $config->getString('metadata.sign.privatekey_pass', NULL); if($privatekey_pass !== NULL) { $ret['privatekey_pass'] = $privatekey_pass; } return $ret; } /* 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.'); } $ret = array( 'privatekey' => $entityMetadata['privatekey'], 'certificate' => $entityMetadata['certificate'] ); if(array_key_exists('privatekey_pass', $entityMetadata)) { $ret['privatekey_pass'] = $entityMetadata['privatekey_pass']; } return $ret; } 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->getBoolean('metadata.sign.enable', FALSE); 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 = SimpleSAML_Utilities::resolveCert($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 = SimpleSAML_Utilities::resolveCert($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')); if(array_key_exists('privatekey_pass', $keyCertFiles)) { $objKey->passphrase = $keyCertFiles['privatekey_pass']; } $objKey->loadKey($keyData, FALSE); /* Get the EntityDescriptor node we should sign. */ $rootNode = $xml->firstChild; /* Sign the metadata with our private key. */ if ($type == 'ADFS IdP') { $objXMLSecDSig = new sspmod_adfs_XMLSecurityDSig($metadataString); } else { $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(); } } ?>