diff --git a/config-templates/config.php b/config-templates/config.php index d9fa2dde5f41815ebb7057652acb42d43df00e84..812e93985b4a04f4de85bb778fe4b789e539ba9f 100644 --- a/config-templates/config.php +++ b/config-templates/config.php @@ -382,6 +382,7 @@ $config = array ( * if those aren't set, signing of metadata will fail. */ 'metadata.sign.privatekey' => NULL, + 'metadata.sign.privatekey_pass' => NULL, 'metadata.sign.certificate' => NULL, diff --git a/docs/source/simplesamlphp-advancedfeatures.xml b/docs/source/simplesamlphp-advancedfeatures.xml index 26bd79974cb8f2f63fc7617e2c3e5e5cd4678bdb..d8d2f74297b41844fcc0805156d2bf7d28c03511 100644 --- a/docs/source/simplesamlphp-advancedfeatures.xml +++ b/docs/source/simplesamlphp-advancedfeatures.xml @@ -369,7 +369,7 @@ foreach($_SERVER as $key=>$value) { <title>Metadata signing</title> <para>simpleSAMLphp supports signing of the metadata it generates. - Metadata signing is configured by three options:</para> + Metadata signing is configured by four options:</para> <itemizedlist> <listitem> @@ -384,6 +384,13 @@ foreach($_SERVER as $key=>$value) { file must exist in in the <literal>cert</literal> directory.</para> </listitem> + <listitem> + <para><literal>metadata.sign.privatekey_pass</literal>: 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.</para> + </listitem> + <listitem> <para><literal>metadata.sign.certificate</literal>: Name of the file with the certificate which matches the private key. This file must @@ -400,9 +407,9 @@ foreach($_SERVER as $key=>$value) { <para>There is also an additional fallback for the private key and the certificate. If <literal>metadata.sign.privatekey</literal> and <literal>metadata.sign.certificate</literal> isn't configured, - simpleSAMLphp will use the <literal>privatekey</literal> and - <literal>certificate</literal> options in the metadata for the - SP/IdP.</para> + simpleSAMLphp will use the <literal>privatekey</literal>, + <literal>privatekey_pass</literal> and <literal>certificate</literal> + options in the metadata for the SP/IdP.</para> </section> diff --git a/docs/source/simplesamlphp-idp.xml b/docs/source/simplesamlphp-idp.xml index 2469347cf5ab78449be0d1a2430b3040c3fa640a..689f26b4a4b5433f734d15797197b4da8382e226 100644 --- a/docs/source/simplesamlphp-idp.xml +++ b/docs/source/simplesamlphp-idp.xml @@ -401,6 +401,14 @@ openssl x509 -req -days 60 -in server2.csr -signkey server2.key -out server2.crt <title>Optional metadata fields</title> <glosslist> + <glossentry> + <glossterm>privatekey_pass</glossterm> + + <glossdef> + <para>Passphrase for the private key.</para> + </glossdef> + </glossentry> + <glossentry> <glossterm>requireconsent</glossterm> diff --git a/docs/source/simplesamlphp-sp.xml b/docs/source/simplesamlphp-sp.xml index f21449f92ece93c1c433d9eb15c80e405b2de81c..51d272805981951d039568bb7e2efb8b1c1f36ec 100644 --- a/docs/source/simplesamlphp-sp.xml +++ b/docs/source/simplesamlphp-sp.xml @@ -326,6 +326,15 @@ generate SAML 2.0 Metadata for export to the IdP.</para> </glossdef> </glossentry> + + <glossentry> + <glossterm>privatekey_pass</glossterm> + + <glossdef> + <para>Optional field with the passphrase for the private + key.</para> + </glossdef> + </glossentry> </glosslist> <example> @@ -560,6 +569,15 @@ key.</para> </glossdef> </glossentry> + + <glossentry> + <glossterm>privatekey_pass</glossterm> + + <glossdef> + <para>Optional field with the passphrase for the private + key.</para> + </glossdef> + </glossentry> </glosslist> <example> diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php b/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php index 24f1bd8b3ee9c54c4af83cd2936104dc5a823e2e..ed9ee715abe5fed44df5d7914b830758fcfcfc1e 100644 --- a/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php +++ b/lib/SimpleSAML/Bindings/SAML20/HTTPPost.php @@ -118,6 +118,13 @@ class SimpleSAML_Bindings_SAML20_HTTPPost { /* create new XMLSecKey using RSA-SHA-1 and type is private key */ $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); + /* Set the passphrase which should be used to open the key, if this attribute is + * set in the metadata. + */ + if(array_key_exists('privatekey_pass', $idpmd)) { + $objKey->passphrase = $idpmd['privatekey_pass']; + } + /* load the private key from file - last arg is bool if key in file (TRUE) or is string (FALSE) */ $objKey->loadKey($privatekey,TRUE); diff --git a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php index 52436bd3e554571f1951695d87ae8cf37d0ed76b..2bf82072d968bc651efb76dfd72140cc01a809bb 100644 --- a/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php +++ b/lib/SimpleSAML/Bindings/SAML20/HTTPRedirect.php @@ -52,6 +52,14 @@ class SimpleSAML_Bindings_SAML20_HTTPRedirect { $query = $query . "&" . "SigAlg=" . urlencode($algURI); $xmlseckey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); + + /* Set the passphrase which should be used to open the key, if this attribute is + * set in the metadata. + */ + if(array_key_exists('privatekey_pass', $md)) { + $xmlseckey->passphrase = $md['privatekey_pass']; + } + $xmlseckey->loadKey($privatekey,TRUE); $signature = $xmlseckey->signData($query); diff --git a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php index 189a9ee3c975193e2dea6a77104677e6734eb63c..37adb633a7cba8d30a1091c248ea4f1f1950cc00 100644 --- a/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php +++ b/lib/SimpleSAML/Bindings/Shib13/HTTPPost.php @@ -118,9 +118,14 @@ class SimpleSAML_Bindings_Shib13_HTTPPost { /* create new XMLSecKey using RSA-SHA-1 and type is private key */ $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type'=>'private')); - - //$objKey->passphrase = '1234'; - + + /* Set the passphrase which should be used to open the key, if this attribute is + * set in the metadata. + */ + if(array_key_exists('privatekey_pass', $idpmd)) { + $objKey->passphrase = $idpmd['privatekey_pass']; + } + /* load the private key from file - last arg is bool if key in file (TRUE) or is string (FALSE) */ #$objKey->loadKey($privatekey_pem,false); $objKey->loadKey($privatek,false); diff --git a/lib/SimpleSAML/Metadata/Signer.php b/lib/SimpleSAML/Metadata/Signer.php index eacf55cbec5484958af8697a99133b926061cc11..8d433aea0bb151bede58e9afbbbd0426198eb623 100644 --- a/lib/SimpleSAML/Metadata/Signer.php +++ b/lib/SimpleSAML/Metadata/Signer.php @@ -16,7 +16,7 @@ class SimpleSAML_Metadata_Signer { * @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'. + * @return An associative array with the keys 'privatekey', 'certificate', and optionally 'privatekey_pass'. */ private static function findKeyCert($config, $entityMetadata, $type) { @@ -32,10 +32,17 @@ class SimpleSAML_Metadata_Signer { ' the ' . $type . ' "' . $entityMetadata['entityid'] . '". If one of' . ' these options is specified, then the other must also be specified.'); } - return array( + + $ret = array( 'privatekey' => $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. */ @@ -48,7 +55,14 @@ class SimpleSAML_Metadata_Signer { ' configuration. If one of these options is specified, then the other'. ' must also be specified.'); } - return array('privatekey' => $privatekey, 'certificate' => $certificate); + $ret = array('privatekey' => $privatekey, 'certificate' => $certificate); + + $privatekey_pass = $config->getValue('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. */ @@ -63,11 +77,16 @@ class SimpleSAML_Metadata_Signer { ' from this entity.'); } - return array( + $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' . @@ -149,6 +168,9 @@ class SimpleSAML_Metadata_Signer { /* 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. */ diff --git a/www/admin/metadata.php b/www/admin/metadata.php index 765f6174fa03da95406d0b4b98d4a36f4c6d2ead..ebf0972f07da2e514c1a9daded80d41e2c5b4593 100644 --- a/www/admin/metadata.php +++ b/www/admin/metadata.php @@ -29,7 +29,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', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate') + array('request.signing','certificate','privatekey', 'privatekey_pass', 'NameIDFormat', 'ForceAuthn', 'AuthnContextClassRef', 'SPNameQualifier', 'attributemap', 'attributealter', 'attributes', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.privatekey_pass', 'metadata.sign.certificate') ); } $et->data['metadata.saml20-sp-hosted'] = $results; @@ -52,7 +52,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', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate') + array('requireconsent','request.signing', 'privatekey_pass', 'authority', 'attributemap', 'attributealter', 'userid.attribute', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.privatekey_pass', 'metadata.sign.certificate') ); } $et->data['metadata.saml20-idp-hosted'] = $results; @@ -89,7 +89,7 @@ try { foreach ($metalist AS $entityid => $mentry) { $results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry, array('entityid', 'SingleSignOnService', 'certFingerprint'), - array('name', 'description', 'base64attributes', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate') + array('name', 'description', 'base64attributes', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.privatekey_pass', 'metadata.sign.certificate') ); } $et->data['metadata.shib13-idp-remote'] = $results; @@ -102,7 +102,7 @@ try { foreach ($metalist AS $entityid => $mentry) { $results[$entityid] = SimpleSAML_Utilities::checkAssocArrayRules($mentry, array('entityid', 'host', 'privatekey', 'certificate', 'auth'), - array('requireconsent', 'authority') + array('requireconsent', 'authority', 'privatekey_pass') ); } $et->data['metadata.shib13-idp-hosted'] = $results; @@ -112,7 +112,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', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.certificate') + array('base64attributes', 'audience', 'attributemap', 'attributealter', 'simplesaml.attributes', 'attributes', 'name', 'description', 'metadata.sign.enable', 'metadata.sign.privatekey', 'metadata.sign.privatekey_pass', 'metadata.sign.certificate') ); } $et->data['metadata.shib13-sp-remote'] = $results;