1<?php 2namespace RobRichards\XMLSecLibs; 3 4use DOMElement; 5use Exception; 6 7/** 8 * xmlseclibs.php 9 * 10 * Copyright (c) 2007-2019, Robert Richards <rrichards@cdatazone.org>. 11 * All rights reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * * Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * * Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * * Neither the name of Robert Richards nor the names of his 26 * contributors may be used to endorse or promote products derived 27 * from this software without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 32 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 33 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 34 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 35 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 36 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 37 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 39 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 40 * POSSIBILITY OF SUCH DAMAGE. 41 * 42 * @author Robert Richards <rrichards@cdatazone.org> 43 * @copyright 2007-2019 Robert Richards <rrichards@cdatazone.org> 44 * @license http://www.opensource.org/licenses/bsd-license.php BSD License 45 */ 46 47class XMLSecurityKey 48{ 49 const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'; 50 const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; 51 const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; 52 const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; 53 const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; 54 const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; 55 const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1'; 56 const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; 57 const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; 58 const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'; 59 const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'; 60 const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1'; 61 62 /** @var array */ 63 private $cryptParams = array(); 64 65 /** @var int|string */ 66 public $type = 0; 67 68 /** @var mixed|null */ 69 public $key = null; 70 71 /** @var string */ 72 public $passphrase = ""; 73 74 /** @var string|null */ 75 public $iv = null; 76 77 /** @var string|null */ 78 public $name = null; 79 80 /** @var mixed|null */ 81 public $keyChain = null; 82 83 /** @var bool */ 84 public $isEncrypted = false; 85 86 /** @var XMLSecEnc|null */ 87 public $encryptedCtx = null; 88 89 /** @var mixed|null */ 90 public $guid = null; 91 92 /** 93 * This variable contains the certificate as a string if this key represents an X509-certificate. 94 * If this key doesn't represent a certificate, this will be null. 95 * @var string|null 96 */ 97 private $x509Certificate = null; 98 99 /** 100 * This variable contains the certificate thumbprint if we have loaded an X509-certificate. 101 * @var string|null 102 */ 103 private $X509Thumbprint = null; 104 105 /** 106 * @param string $type 107 * @param null|array $params 108 * @throws Exception 109 */ 110 public function __construct($type, $params=null) 111 { 112 switch ($type) { 113 case (self::TRIPLEDES_CBC): 114 $this->cryptParams['library'] = 'openssl'; 115 $this->cryptParams['cipher'] = 'des-ede3-cbc'; 116 $this->cryptParams['type'] = 'symmetric'; 117 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc'; 118 $this->cryptParams['keysize'] = 24; 119 $this->cryptParams['blocksize'] = 8; 120 break; 121 case (self::AES128_CBC): 122 $this->cryptParams['library'] = 'openssl'; 123 $this->cryptParams['cipher'] = 'aes-128-cbc'; 124 $this->cryptParams['type'] = 'symmetric'; 125 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc'; 126 $this->cryptParams['keysize'] = 16; 127 $this->cryptParams['blocksize'] = 16; 128 break; 129 case (self::AES192_CBC): 130 $this->cryptParams['library'] = 'openssl'; 131 $this->cryptParams['cipher'] = 'aes-192-cbc'; 132 $this->cryptParams['type'] = 'symmetric'; 133 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc'; 134 $this->cryptParams['keysize'] = 24; 135 $this->cryptParams['blocksize'] = 16; 136 break; 137 case (self::AES256_CBC): 138 $this->cryptParams['library'] = 'openssl'; 139 $this->cryptParams['cipher'] = 'aes-256-cbc'; 140 $this->cryptParams['type'] = 'symmetric'; 141 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc'; 142 $this->cryptParams['keysize'] = 32; 143 $this->cryptParams['blocksize'] = 16; 144 break; 145 case (self::RSA_1_5): 146 $this->cryptParams['library'] = 'openssl'; 147 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; 148 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5'; 149 if (is_array($params) && ! empty($params['type'])) { 150 if ($params['type'] == 'public' || $params['type'] == 'private') { 151 $this->cryptParams['type'] = $params['type']; 152 break; 153 } 154 } 155 throw new Exception('Certificate "type" (private/public) must be passed via parameters'); 156 case (self::RSA_OAEP_MGF1P): 157 $this->cryptParams['library'] = 'openssl'; 158 $this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING; 159 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p'; 160 $this->cryptParams['hash'] = null; 161 if (is_array($params) && ! empty($params['type'])) { 162 if ($params['type'] == 'public' || $params['type'] == 'private') { 163 $this->cryptParams['type'] = $params['type']; 164 break; 165 } 166 } 167 throw new Exception('Certificate "type" (private/public) must be passed via parameters'); 168 case (self::RSA_SHA1): 169 $this->cryptParams['library'] = 'openssl'; 170 $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1'; 171 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; 172 if (is_array($params) && ! empty($params['type'])) { 173 if ($params['type'] == 'public' || $params['type'] == 'private') { 174 $this->cryptParams['type'] = $params['type']; 175 break; 176 } 177 } 178 throw new Exception('Certificate "type" (private/public) must be passed via parameters'); 179 case (self::RSA_SHA256): 180 $this->cryptParams['library'] = 'openssl'; 181 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256'; 182 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; 183 $this->cryptParams['digest'] = 'SHA256'; 184 if (is_array($params) && ! empty($params['type'])) { 185 if ($params['type'] == 'public' || $params['type'] == 'private') { 186 $this->cryptParams['type'] = $params['type']; 187 break; 188 } 189 } 190 throw new Exception('Certificate "type" (private/public) must be passed via parameters'); 191 case (self::RSA_SHA384): 192 $this->cryptParams['library'] = 'openssl'; 193 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384'; 194 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; 195 $this->cryptParams['digest'] = 'SHA384'; 196 if (is_array($params) && ! empty($params['type'])) { 197 if ($params['type'] == 'public' || $params['type'] == 'private') { 198 $this->cryptParams['type'] = $params['type']; 199 break; 200 } 201 } 202 throw new Exception('Certificate "type" (private/public) must be passed via parameters'); 203 case (self::RSA_SHA512): 204 $this->cryptParams['library'] = 'openssl'; 205 $this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512'; 206 $this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING; 207 $this->cryptParams['digest'] = 'SHA512'; 208 if (is_array($params) && ! empty($params['type'])) { 209 if ($params['type'] == 'public' || $params['type'] == 'private') { 210 $this->cryptParams['type'] = $params['type']; 211 break; 212 } 213 } 214 throw new Exception('Certificate "type" (private/public) must be passed via parameters'); 215 case (self::HMAC_SHA1): 216 $this->cryptParams['library'] = $type; 217 $this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1'; 218 break; 219 default: 220 throw new Exception('Invalid Key Type'); 221 } 222 $this->type = $type; 223 } 224 225 /** 226 * Retrieve the key size for the symmetric encryption algorithm.. 227 * 228 * If the key size is unknown, or this isn't a symmetric encryption algorithm, 229 * null is returned. 230 * 231 * @return int|null The number of bytes in the key. 232 */ 233 public function getSymmetricKeySize() 234 { 235 if (! isset($this->cryptParams['keysize'])) { 236 return null; 237 } 238 return $this->cryptParams['keysize']; 239 } 240 241 /** 242 * Generates a session key using the openssl-extension. 243 * In case of using DES3-CBC the key is checked for a proper parity bits set. 244 * @return string 245 * @throws Exception 246 */ 247 public function generateSessionKey() 248 { 249 if (!isset($this->cryptParams['keysize'])) { 250 throw new Exception('Unknown key size for type "' . $this->type . '".'); 251 } 252 $keysize = $this->cryptParams['keysize']; 253 254 $key = openssl_random_pseudo_bytes($keysize); 255 256 if ($this->type === self::TRIPLEDES_CBC) { 257 /* Make sure that the generated key has the proper parity bits set. 258 * Mcrypt doesn't care about the parity bits, but others may care. 259 */ 260 for ($i = 0; $i < strlen($key); $i++) { 261 $byte = ord($key[$i]) & 0xfe; 262 $parity = 1; 263 for ($j = 1; $j < 8; $j++) { 264 $parity ^= ($byte >> $j) & 1; 265 } 266 $byte |= $parity; 267 $key[$i] = chr($byte); 268 } 269 } 270 271 $this->key = $key; 272 return $key; 273 } 274 275 /** 276 * Get the raw thumbprint of a certificate 277 * 278 * @param string $cert 279 * @return null|string 280 */ 281 public static function getRawThumbprint($cert) 282 { 283 284 $arCert = explode("\n", $cert); 285 $data = ''; 286 $inData = false; 287 288 foreach ($arCert AS $curData) { 289 if (! $inData) { 290 if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { 291 $inData = true; 292 } 293 } else { 294 if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) { 295 break; 296 } 297 $data .= trim($curData); 298 } 299 } 300 301 if (! empty($data)) { 302 return strtolower(sha1(base64_decode($data))); 303 } 304 305 return null; 306 } 307 308 /** 309 * Loads the given key, or - with isFile set true - the key from the keyfile. 310 * 311 * @param string $key 312 * @param bool $isFile 313 * @param bool $isCert 314 * @throws Exception 315 */ 316 public function loadKey($key, $isFile=false, $isCert = false) 317 { 318 if ($isFile) { 319 $this->key = file_get_contents($key); 320 } else { 321 $this->key = $key; 322 } 323 if ($isCert) { 324 $this->key = openssl_x509_read($this->key); 325 openssl_x509_export($this->key, $str_cert); 326 $this->x509Certificate = $str_cert; 327 $this->key = $str_cert; 328 } else { 329 $this->x509Certificate = null; 330 } 331 if ($this->cryptParams['library'] == 'openssl') { 332 switch ($this->cryptParams['type']) { 333 case 'public': 334 if ($isCert) { 335 /* Load the thumbprint if this is an X509 certificate. */ 336 $this->X509Thumbprint = self::getRawThumbprint($this->key); 337 } 338 $this->key = openssl_get_publickey($this->key); 339 if (! $this->key) { 340 throw new Exception('Unable to extract public key'); 341 } 342 break; 343 344 case 'private': 345 $this->key = openssl_get_privatekey($this->key, $this->passphrase); 346 break; 347 348 case'symmetric': 349 if (strlen($this->key) < $this->cryptParams['keysize']) { 350 throw new Exception('Key must contain at least 25 characters for this cipher'); 351 } 352 break; 353 354 default: 355 throw new Exception('Unknown type'); 356 } 357 } 358 } 359 360 /** 361 * ISO 10126 Padding 362 * 363 * @param string $data 364 * @param integer $blockSize 365 * @throws Exception 366 * @return string 367 */ 368 private function padISO10126($data, $blockSize) 369 { 370 if ($blockSize > 256) { 371 throw new Exception('Block size higher than 256 not allowed'); 372 } 373 $padChr = $blockSize - (strlen($data) % $blockSize); 374 $pattern = chr($padChr); 375 return $data . str_repeat($pattern, $padChr); 376 } 377 378 /** 379 * Remove ISO 10126 Padding 380 * 381 * @param string $data 382 * @return string 383 */ 384 private function unpadISO10126($data) 385 { 386 $padChr = substr($data, -1); 387 $padLen = ord($padChr); 388 return substr($data, 0, -$padLen); 389 } 390 391 /** 392 * Encrypts the given data (string) using the openssl-extension 393 * 394 * @param string $data 395 * @return string 396 */ 397 private function encryptSymmetric($data) 398 { 399 $this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher'])); 400 $data = $this->padISO10126($data, $this->cryptParams['blocksize']); 401 $encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); 402 if (false === $encrypted) { 403 throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string()); 404 } 405 return $this->iv . $encrypted; 406 } 407 408 /** 409 * Decrypts the given data (string) using the openssl-extension 410 * 411 * @param string $data 412 * @return string 413 */ 414 private function decryptSymmetric($data) 415 { 416 $iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']); 417 $this->iv = substr($data, 0, $iv_length); 418 $data = substr($data, $iv_length); 419 $decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv); 420 if (false === $decrypted) { 421 throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string()); 422 } 423 return $this->unpadISO10126($decrypted); 424 } 425 426 /** 427 * Encrypts the given public data (string) using the openssl-extension 428 * 429 * @param string $data 430 * @return string 431 * @throws Exception 432 */ 433 private function encryptPublic($data) 434 { 435 if (! openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { 436 throw new Exception('Failure encrypting Data (openssl public) - ' . openssl_error_string()); 437 } 438 return $encrypted; 439 } 440 441 /** 442 * Decrypts the given public data (string) using the openssl-extension 443 * 444 * @param string $data 445 * @return string 446 * @throws Exception 447 */ 448 private function decryptPublic($data) 449 { 450 if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { 451 throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string()); 452 } 453 return $decrypted; 454 } 455 456 /** 457 * Encrypts the given private data (string) using the openssl-extension 458 * 459 * @param string $data 460 * @return string 461 * @throws Exception 462 */ 463 private function encryptPrivate($data) 464 { 465 if (! openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) { 466 throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string()); 467 } 468 return $encrypted; 469 } 470 471 /** 472 * Decrypts the given private data (string) using the openssl-extension 473 * 474 * @param string $data 475 * @return string 476 * @throws Exception 477 */ 478 private function decryptPrivate($data) 479 { 480 if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) { 481 throw new Exception('Failure decrypting Data (openssl private) - ' . openssl_error_string()); 482 } 483 return $decrypted; 484 } 485 486 /** 487 * Signs the given data (string) using the openssl-extension 488 * 489 * @param string $data 490 * @return string 491 * @throws Exception 492 */ 493 private function signOpenSSL($data) 494 { 495 $algo = OPENSSL_ALGO_SHA1; 496 if (! empty($this->cryptParams['digest'])) { 497 $algo = $this->cryptParams['digest']; 498 } 499 if (! openssl_sign($data, $signature, $this->key, $algo)) { 500 throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo); 501 } 502 return $signature; 503 } 504 505 /** 506 * Verifies the given data (string) belonging to the given signature using the openssl-extension 507 * 508 * Returns: 509 * 1 on succesful signature verification, 510 * 0 when signature verification failed, 511 * -1 if an error occurred during processing. 512 * 513 * NOTE: be very careful when checking the return value, because in PHP, 514 * -1 will be cast to True when in boolean context. So always check the 515 * return value in a strictly typed way, e.g. "$obj->verify(...) === 1". 516 * 517 * @param string $data 518 * @param string $signature 519 * @return int 520 */ 521 private function verifyOpenSSL($data, $signature) 522 { 523 $algo = OPENSSL_ALGO_SHA1; 524 if (! empty($this->cryptParams['digest'])) { 525 $algo = $this->cryptParams['digest']; 526 } 527 return openssl_verify($data, $signature, $this->key, $algo); 528 } 529 530 /** 531 * Encrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor. 532 * 533 * @param string $data 534 * @return mixed|string 535 */ 536 public function encryptData($data) 537 { 538 if ($this->cryptParams['library'] === 'openssl') { 539 switch ($this->cryptParams['type']) { 540 case 'symmetric': 541 return $this->encryptSymmetric($data); 542 case 'public': 543 return $this->encryptPublic($data); 544 case 'private': 545 return $this->encryptPrivate($data); 546 } 547 } 548 } 549 550 /** 551 * Decrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor. 552 * 553 * @param string $data 554 * @return mixed|string 555 */ 556 public function decryptData($data) 557 { 558 if ($this->cryptParams['library'] === 'openssl') { 559 switch ($this->cryptParams['type']) { 560 case 'symmetric': 561 return $this->decryptSymmetric($data); 562 case 'public': 563 return $this->decryptPublic($data); 564 case 'private': 565 return $this->decryptPrivate($data); 566 } 567 } 568 } 569 570 /** 571 * Signs the data (string) using the extension assigned to the type in the constructor. 572 * 573 * @param string $data 574 * @return mixed|string 575 */ 576 public function signData($data) 577 { 578 switch ($this->cryptParams['library']) { 579 case 'openssl': 580 return $this->signOpenSSL($data); 581 case (self::HMAC_SHA1): 582 return hash_hmac("sha1", $data, $this->key, true); 583 } 584 } 585 586 /** 587 * Verifies the data (string) against the given signature using the extension assigned to the type in the constructor. 588 * 589 * Returns in case of openSSL: 590 * 1 on succesful signature verification, 591 * 0 when signature verification failed, 592 * -1 if an error occurred during processing. 593 * 594 * NOTE: be very careful when checking the return value, because in PHP, 595 * -1 will be cast to True when in boolean context. So always check the 596 * return value in a strictly typed way, e.g. "$obj->verify(...) === 1". 597 * 598 * @param string $data 599 * @param string $signature 600 * @return bool|int 601 */ 602 public function verifySignature($data, $signature) 603 { 604 switch ($this->cryptParams['library']) { 605 case 'openssl': 606 return $this->verifyOpenSSL($data, $signature); 607 case (self::HMAC_SHA1): 608 $expectedSignature = hash_hmac("sha1", $data, $this->key, true); 609 return strcmp($signature, $expectedSignature) == 0; 610 } 611 } 612 613 /** 614 * @deprecated 615 * @see getAlgorithm() 616 * @return mixed 617 */ 618 public function getAlgorith() 619 { 620 return $this->getAlgorithm(); 621 } 622 623 /** 624 * @return mixed 625 */ 626 public function getAlgorithm() 627 { 628 return $this->cryptParams['method']; 629 } 630 631 /** 632 * 633 * @param int $type 634 * @param string $string 635 * @return null|string 636 */ 637 public static function makeAsnSegment($type, $string) 638 { 639 switch ($type) { 640 case 0x02: 641 if (ord($string) > 0x7f) 642 $string = chr(0).$string; 643 break; 644 case 0x03: 645 $string = chr(0).$string; 646 break; 647 } 648 649 $length = strlen($string); 650 651 if ($length < 128) { 652 $output = sprintf("%c%c%s", $type, $length, $string); 653 } else if ($length < 0x0100) { 654 $output = sprintf("%c%c%c%s", $type, 0x81, $length, $string); 655 } else if ($length < 0x010000) { 656 $output = sprintf("%c%c%c%c%s", $type, 0x82, $length / 0x0100, $length % 0x0100, $string); 657 } else { 658 $output = null; 659 } 660 return $output; 661 } 662 663 /** 664 * 665 * Hint: Modulus and Exponent must already be base64 decoded 666 * @param string $modulus 667 * @param string $exponent 668 * @return string 669 */ 670 public static function convertRSA($modulus, $exponent) 671 { 672 /* make an ASN publicKeyInfo */ 673 $exponentEncoding = self::makeAsnSegment(0x02, $exponent); 674 $modulusEncoding = self::makeAsnSegment(0x02, $modulus); 675 $sequenceEncoding = self::makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding); 676 $bitstringEncoding = self::makeAsnSegment(0x03, $sequenceEncoding); 677 $rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500"); 678 $publicKeyInfo = self::makeAsnSegment(0x30, $rsaAlgorithmIdentifier.$bitstringEncoding); 679 680 /* encode the publicKeyInfo in base64 and add PEM brackets */ 681 $publicKeyInfoBase64 = base64_encode($publicKeyInfo); 682 $encoding = "-----BEGIN PUBLIC KEY-----\n"; 683 $offset = 0; 684 while ($segment = substr($publicKeyInfoBase64, $offset, 64)) { 685 $encoding = $encoding.$segment."\n"; 686 $offset += 64; 687 } 688 return $encoding."-----END PUBLIC KEY-----\n"; 689 } 690 691 /** 692 * @param mixed $parent 693 */ 694 public function serializeKey($parent) 695 { 696 697 } 698 699 /** 700 * Retrieve the X509 certificate this key represents. 701 * 702 * Will return the X509 certificate in PEM-format if this key represents 703 * an X509 certificate. 704 * 705 * @return string The X509 certificate or null if this key doesn't represent an X509-certificate. 706 */ 707 public function getX509Certificate() 708 { 709 return $this->x509Certificate; 710 } 711 712 /** 713 * Get the thumbprint of this X509 certificate. 714 * 715 * Returns: 716 * The thumbprint as a lowercase 40-character hexadecimal number, or null 717 * if this isn't a X509 certificate. 718 * 719 * @return string Lowercase 40-character hexadecimal number of thumbprint 720 */ 721 public function getX509Thumbprint() 722 { 723 return $this->X509Thumbprint; 724 } 725 726 727 /** 728 * Create key from an EncryptedKey-element. 729 * 730 * @param DOMElement $element The EncryptedKey-element. 731 * @throws Exception 732 * 733 * @return XMLSecurityKey The new key. 734 */ 735 public static function fromEncryptedKeyElement(DOMElement $element) 736 { 737 738 $objenc = new XMLSecEnc(); 739 $objenc->setNode($element); 740 if (! $objKey = $objenc->locateKey()) { 741 throw new Exception("Unable to locate algorithm for this Encrypted Key"); 742 } 743 $objKey->isEncrypted = true; 744 $objKey->encryptedCtx = $objenc; 745 XMLSecEnc::staticLocateKeyInfo($objKey, $element); 746 return $objKey; 747 } 748 749} 750