ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
Signer.php
Go to the documentation of this file.
1 <?php
2 
3 
11 {
12 
25  private static function findKeyCert($config, $entityMetadata, $type)
26  {
27  // first we look for metadata.privatekey and metadata.certificate in the metadata
28  if (array_key_exists('metadata.sign.privatekey', $entityMetadata)
29  || array_key_exists('metadata.sign.certificate', $entityMetadata)
30  ) {
31  if (!array_key_exists('metadata.sign.privatekey', $entityMetadata)
32  || !array_key_exists('metadata.sign.certificate', $entityMetadata)
33  ) {
34  throw new Exception(
35  'Missing either the "metadata.sign.privatekey" or the'.
36  ' "metadata.sign.certificate" configuration option in the metadata for'.
37  ' the '.$type.' "'.$entityMetadata['entityid'].'". If one of'.
38  ' these options is specified, then the other must also be specified.'
39  );
40  }
41 
42  $ret = array(
43  'privatekey' => $entityMetadata['metadata.sign.privatekey'],
44  'certificate' => $entityMetadata['metadata.sign.certificate']
45  );
46 
47  if (array_key_exists('metadata.sign.privatekey_pass', $entityMetadata)) {
48  $ret['privatekey_pass'] = $entityMetadata['metadata.sign.privatekey_pass'];
49  }
50 
51  return $ret;
52  }
53 
54  // then we look for default values in the global configuration
55  $privatekey = $config->getString('metadata.sign.privatekey', null);
56  $certificate = $config->getString('metadata.sign.certificate', null);
57  if ($privatekey !== null || $certificate !== null) {
58  if ($privatekey === null || $certificate === null) {
59  throw new Exception(
60  'Missing either the "metadata.sign.privatekey" or the'.
61  ' "metadata.sign.certificate" configuration option in the global'.
62  ' configuration. If one of these options is specified, then the other'.
63  ' must also be specified.'
64  );
65  }
66  $ret = array('privatekey' => $privatekey, 'certificate' => $certificate);
67 
68  $privatekey_pass = $config->getString('metadata.sign.privatekey_pass', null);
69  if ($privatekey_pass !== null) {
70  $ret['privatekey_pass'] = $privatekey_pass;
71  }
72 
73  return $ret;
74  }
75 
76  // as a last resort we attempt to use the privatekey and certificate option from the metadata
77  if (array_key_exists('privatekey', $entityMetadata)
78  || array_key_exists('certificate', $entityMetadata)
79  ) {
80  if (!array_key_exists('privatekey', $entityMetadata)
81  || !array_key_exists('certificate', $entityMetadata)
82  ) {
83  throw new Exception(
84  'Both the "privatekey" and the "certificate" option must'.
85  ' be set in the metadata for the '.$type.' "'.
86  $entityMetadata['entityid'].'" before it is possible to sign metadata'.
87  ' from this entity.'
88  );
89  }
90 
91  $ret = array(
92  'privatekey' => $entityMetadata['privatekey'],
93  'certificate' => $entityMetadata['certificate']
94  );
95 
96  if (array_key_exists('privatekey_pass', $entityMetadata)) {
97  $ret['privatekey_pass'] = $entityMetadata['privatekey_pass'];
98  }
99 
100  return $ret;
101  }
102 
103  throw new Exception(
104  'Could not find what key & certificate should be used to sign the metadata'.
105  ' for the '.$type.' "'.$entityMetadata['entityid'].'".'
106  );
107  }
108 
109 
121  private static function isMetadataSigningEnabled($config, $entityMetadata, $type)
122  {
123  // first check the metadata for the entity
124  if (array_key_exists('metadata.sign.enable', $entityMetadata)) {
125  if (!is_bool($entityMetadata['metadata.sign.enable'])) {
126  throw new Exception(
127  'Invalid value for the "metadata.sign.enable" configuration option for'.
128  ' the '.$type.' "'.$entityMetadata['entityid'].'". This option'.
129  ' should be a boolean.'
130  );
131  }
132 
133  return $entityMetadata['metadata.sign.enable'];
134  }
135 
136  $enabled = $config->getBoolean('metadata.sign.enable', false);
137 
138  return $enabled;
139  }
140 
141 
157  private static function getMetadataSigningAlgorithm($config, $entityMetadata, $type)
158  {
159  // configure the algorithm to use
160  if (array_key_exists('metadata.sign.algorithm', $entityMetadata)) {
161  if (!is_string($entityMetadata['metadata.sign.algorithm'])) {
162  throw new \SimpleSAML\Error\CriticalConfigurationError(
163  "Invalid value for the 'metadata.sign.algorithm' configuration option for the ".$type.
164  "'".$entityMetadata['entityid']."'. This option has restricted values"
165  );
166  }
167  $alg = $entityMetadata['metadata.sign.algorithm'];
168  } else {
169  $alg = $config->getString('metadata.sign.algorithm', XMLSecurityKey::RSA_SHA256);
170  }
171 
172  $supported_algs = array(
173  XMLSecurityKey::RSA_SHA1,
174  XMLSecurityKey::RSA_SHA256,
175  XMLSecurityKey::RSA_SHA384,
176  XMLSecurityKey::RSA_SHA512,
177  );
178 
179  if (!in_array($alg, $supported_algs, true)) {
180  throw new \SimpleSAML\Error\CriticalConfigurationError("Unknown signature algorithm '$alg'");
181  }
182 
183  switch ($alg) {
184  case XMLSecurityKey::RSA_SHA256:
185  $digest = XMLSecurityDSig::SHA256;
186  break;
187  case XMLSecurityKey::RSA_SHA384:
188  $digest = XMLSecurityDSig::SHA384;
189  break;
190  case XMLSecurityKey::RSA_SHA512:
191  $digest = XMLSecurityDSig::SHA512;
192  break;
193  default:
194  $digest = XMLSecurityDSig::SHA1;
195  }
196 
197  return array(
198  'algorithm' => $alg,
199  'digest' => $digest,
200  );
201  }
202 
203 
214  public static function sign($metadataString, $entityMetadata, $type)
215  {
217 
218  // check if metadata signing is enabled
219  if (!self::isMetadataSigningEnabled($config, $entityMetadata, $type)) {
220  return $metadataString;
221  }
222 
223  // find the key & certificate which should be used to sign the metadata
224  $keyCertFiles = self::findKeyCert($config, $entityMetadata, $type);
225 
226  $keyFile = \SimpleSAML\Utils\Config::getCertPath($keyCertFiles['privatekey']);
227  if (!file_exists($keyFile)) {
228  throw new Exception('Could not find private key file ['.$keyFile.'], which is needed to sign the metadata');
229  }
230  $keyData = file_get_contents($keyFile);
231 
232  $certFile = \SimpleSAML\Utils\Config::getCertPath($keyCertFiles['certificate']);
233  if (!file_exists($certFile)) {
234  throw new Exception(
235  'Could not find certificate file ['.$certFile.'], which is needed to sign the metadata'
236  );
237  }
238  $certData = file_get_contents($certFile);
239 
240 
241  // convert the metadata to a DOM tree
242  try {
243  $xml = \SAML2\DOMDocumentFactory::fromString($metadataString);
244  } catch (Exception $e) {
245  throw new Exception('Error parsing self-generated metadata.');
246  }
247 
248  $signature_cf = self::getMetadataSigningAlgorithm($config, $entityMetadata, $type);
249 
250  // load the private key
251  $objKey = new XMLSecurityKey($signature_cf['algorithm'], array('type' => 'private'));
252  if (array_key_exists('privatekey_pass', $keyCertFiles)) {
253  $objKey->passphrase = $keyCertFiles['privatekey_pass'];
254  }
255  $objKey->loadKey($keyData, false);
256 
257  // get the EntityDescriptor node we should sign
258  $rootNode = $xml->firstChild;
259 
260  // sign the metadata with our private key
261  $objXMLSecDSig = new XMLSecurityDSig();
262 
263  $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N);
264 
265  $objXMLSecDSig->addReferenceList(
266  array($rootNode),
267  $signature_cf['digest'],
268  array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N),
269  array('id_name' => 'ID')
270  );
271 
272  $objXMLSecDSig->sign($objKey);
273 
274  // add the certificate to the signature
275  $objXMLSecDSig->add509Cert($certData, true);
276 
277  // add the signature to the metadata
278  $objXMLSecDSig->insertSignature($rootNode, $rootNode->firstChild);
279 
280  // return the DOM tree as a string
281  return $xml->saveXML();
282  }
283 }
$config
Definition: bootstrap.php:15
$type
static findKeyCert($config, $entityMetadata, $type)
This functions finds what key & certificate files should be used to sign the metadata for the given e...
Definition: Signer.php:25
if(@file_exists(dirname(__FILE__).'/lang/eng.php')) $certificate
Definition: example_052.php:77
static getMetadataSigningAlgorithm($config, $entityMetadata, $type)
Determine the signature and digest algorithms to use when signing metadata.
Definition: Signer.php:157
static sign($metadataString, $entityMetadata, $type)
Signs the given metadata if metadata signing is enabled.
Definition: Signer.php:214
static isMetadataSigningEnabled($config, $entityMetadata, $type)
Determine whether metadata signing is enabled for the given metadata.
Definition: Signer.php:121
static getCertPath($path)
Resolves a path that may be relative to the cert-directory.
Definition: Config.php:22
$ret
Definition: parser.php:6
static getInstance($instancename='simplesaml')
Get a configuration file by its instance name.