[ Index ] |
|
Code source de Horde 3.1.3 |
1 <?php 2 3 require_once 'Horde/Crypt.php'; 4 5 /** 6 * Horde_Crypt_smime:: provides a framework for Horde applications to 7 * interact with the OpenSSL library and implement S/MIME. 8 * 9 * $Horde: framework/Crypt/Crypt/smime.php,v 1.49.2.12 2006/02/03 15:52:55 slusarz Exp $ 10 * 11 * Copyright 2002-2006 Mike Cochrane <mike@graftonhall.co.nz> 12 * 13 * See the enclosed file COPYING for license information (LGPL). If you 14 * did not receive this file, see http://www.fsf.org/copyleft/lgpl.html. 15 * 16 * @author Mike Cochrane <mike@graftonhall.co.nz> 17 * @since Horde 3.0 18 * @package Horde_Crypt 19 */ 20 class Horde_Crypt_smime extends Horde_Crypt { 21 22 /** 23 * Object Identifers to name array. 24 * 25 * @var array 26 */ 27 var $_oids = array( 28 '2.5.4.3' => 'CommonName', 29 '2.5.4.4' => 'Surname', 30 '2.5.4.6' => 'Country', 31 '2.5.4.7' => 'Location', 32 '2.5.4.8' => 'StateOrProvince', 33 '2.5.4.9' => 'StreetAddress', 34 '2.5.4.10' => 'Organisation', 35 '2.5.4.11' => 'OrganisationalUnit', 36 '2.5.4.12' => 'Title', 37 '2.5.4.20' => 'TelephoneNumber', 38 '2.5.4.42' => 'GivenName', 39 40 '2.5.29.14' => 'id-ce-subjectKeyIdentifier', 41 42 '2.5.29.14' => 'id-ce-subjectKeyIdentifier', 43 '2.5.29.15' => 'id-ce-keyUsage', 44 '2.5.29.17' => 'id-ce-subjectAltName', 45 '2.5.29.19' => 'id-ce-basicConstraints', 46 '2.5.29.31' => 'id-ce-CRLDistributionPoints', 47 '2.5.29.32' => 'id-ce-certificatePolicies', 48 '2.5.29.35' => 'id-ce-authorityKeyIdentifier', 49 '2.5.29.37' => 'id-ce-extKeyUsage', 50 51 '1.2.840.113549.1.9.1' => 'Email', 52 '1.2.840.113549.1.1.1' => 'RSAEncryption', 53 '1.2.840.113549.1.1.2' => 'md2WithRSAEncryption', 54 '1.2.840.113549.1.1.4' => 'md5withRSAEncryption', 55 '1.2.840.113549.1.1.5' => 'SHA-1WithRSAEncryption', 56 '1.2.840.10040.4.3' => 'id-dsa-with-sha-1', 57 58 '1.3.6.1.5.5.7.3.2' => 'id_kp_clientAuth', 59 60 '2.16.840.1.113730.1.1' => 'netscape-cert-type', 61 '2.16.840.1.113730.1.2' => 'netscape-base-url', 62 '2.16.840.1.113730.1.3' => 'netscape-revocation-url', 63 '2.16.840.1.113730.1.4' => 'netscape-ca-revocation-url', 64 '2.16.840.1.113730.1.7' => 'netscape-cert-renewal-url', 65 '2.16.840.1.113730.1.8' => 'netscape-ca-policy-url', 66 '2.16.840.1.113730.1.12' => 'netscape-ssl-server-name', 67 '2.16.840.1.113730.1.13' => 'netscape-comment', 68 ); 69 70 /** 71 * Constructor. 72 * 73 * @param array $params Parameter array. 74 * 'temp' => Location of temporary directory. 75 */ 76 function Horde_Crypt_smime($params) 77 { 78 $this->_tempdir = $params['temp']; 79 } 80 81 /** 82 * Verify a passphrase for a given private key. 83 * 84 * @param string $private_key The user's private key. 85 * @param string $passphrase The user's passphrase. 86 * 87 * @return boolean Returns true on valid passphrase, false on invalid 88 * passphrase. 89 * Returns PEAR_Error on error. 90 */ 91 function verifyPassphrase($private_key, $passphrase) 92 { 93 if (is_null($passphrase)) { 94 $res = openssl_pkey_get_private($private_key); 95 } else { 96 $res = openssl_pkey_get_private($private_key, $passphrase); 97 } 98 99 return is_resource($res); 100 } 101 102 /** 103 * Encrypt text using S/MIME. 104 * 105 * @param string $text The text to be encrypted. 106 * @param array $params The parameters needed for encryption. 107 * See the individual _encrypt*() functions for 108 * the parameter requirements. 109 * 110 * @return string The encrypted message. 111 * Returns PEAR_Error object on error. 112 */ 113 function encrypt($text, $params = array()) 114 { 115 /* Check for availability of OpenSSL PHP extension. */ 116 $openssl = $this->checkForOpenSSL(); 117 if (is_a($openssl, 'PEAR_Error')) { 118 return $openssl; 119 } 120 121 if (isset($params['type'])) { 122 if ($params['type'] === 'message') { 123 return $this->_encryptMessage($text, $params); 124 } elseif ($params['type'] === 'signature') { 125 return $this->_encryptSignature($text, $params); 126 } 127 } 128 } 129 130 /** 131 * Decrypt text via S/MIME. 132 * 133 * @param string $text The text to be smime decrypted. 134 * @param array $params The parameters needed for decryption. 135 * See the individual _decrypt*() functions for 136 * the parameter requirements. 137 * 138 * @return string The decrypted message. 139 * Returns PEAR_Error object on error. 140 */ 141 function decrypt($text, $params = array()) 142 { 143 /* Check for availability of OpenSSL PHP extension. */ 144 $openssl = $this->checkForOpenSSL(); 145 if (is_a($openssl, 'PEAR_Error')) { 146 return $openssl; 147 } 148 149 if (isset($params['type'])) { 150 if ($params['type'] === 'message') { 151 return $this->_decryptMessage($text, $params); 152 } elseif (($params['type'] === 'signature') || 153 ($params['type'] === 'detached-signature')) { 154 return $this->_decryptSignature($text, $params); 155 } 156 } 157 } 158 159 /** 160 * Verify a signature using via S/MIME. 161 * 162 * @param string $text The multipart/signed data to be verified. 163 * @param mixed $certs Either a single or array of root certificates. 164 * 165 * @return stdClass Object with the following elements: 166 * 'result' -> Returns true on success; 167 * PEAR_Error object on error. 168 * 'cert' -> The certificate of the signer stored 169 * in the message (in PEM format). 170 * 'email' -> The email of the signing person. 171 */ 172 function verify($text, $certs) 173 { 174 /* Check for availability of OpenSSL PHP extension. */ 175 $openssl = $this->checkForOpenSSL(); 176 if (is_a($openssl, 'PEAR_Error')) { 177 return $openssl; 178 } 179 180 /* Create temp files for input/output. */ 181 $input = $this->_createTempFile('horde-smime'); 182 $output = $this->_createTempFile('horde-smime'); 183 184 /* Write text to file */ 185 $fp = fopen($input, 'w+'); 186 fwrite($fp, $text); 187 fclose($fp); 188 189 $root_certs = array(); 190 if (!is_array($certs)) { 191 $certs = array($certs); 192 } 193 foreach ($certs as $file) { 194 if (file_exists($file)) { 195 $root_certs[] = $file; 196 } 197 } 198 199 $ob = &new stdClass; 200 201 if (!empty($root_certs)) { 202 $result = openssl_pkcs7_verify($input, 0, $output, $root_certs); 203 /* Message verified */ 204 if ($result === true) { 205 $ob->result = true; 206 $ob->cert = file_get_contents($output); 207 $ob->email = $this->getEmailFromKey($ob->cert); 208 return $ob; 209 } 210 } 211 212 /* Try again without verfying the signer's cert */ 213 $result = openssl_pkcs7_verify($input, PKCS7_NOVERIFY, $output); 214 215 if (($result === true) || ($result === -1)) { 216 $ob->result = PEAR::raiseError(_("Message Verified Successfully but the signer's certificate could not be verified."), 'horde.warning'); 217 } else { 218 $ob->result = PEAR::raiseError(_("Verification failed - this message may have been tampered with."), 'horde.error'); 219 } 220 221 $ob->cert = file_get_contents($output); 222 $ob->email = $this->getEmailFromKey($ob->cert); 223 224 return $ob; 225 } 226 227 /** 228 * Extract the contents from signed S/MIME data. 229 * 230 * @param string $data The signed S/MIME data. 231 * @param string $sslpath The path to the OpenSSL binary. 232 * 233 * @return string The contents embedded in the signed data. 234 * Returns PEAR_Error on error. 235 */ 236 function extractSignedContents($data, $sslpath) 237 { 238 $pipes_desc = array( 239 0 => array('pipe', 'r'), 240 1 => array('pipe', 'w') 241 ); 242 243 $fp = proc_open($sslpath . ' smime -verify -noverify -nochain', $pipes_desc, $pipes); 244 if (!is_resource($fp)) { 245 return PEAR::raiseError(_("OpenSSL error: Could not extract data from signed S/MIME part."), 'horde.error'); 246 } 247 248 $output = ''; 249 250 /* $pipes[0] => writeable handle connected to child stdin 251 $pipes[1] => readable handle connected to child stdout */ 252 fwrite($pipes[0], $data); 253 fclose($pipes[0]); 254 255 while (!feof($pipes[1])) { 256 $output .= fgets($pipes[1], 1024); 257 } 258 fclose($pipes[1]); 259 proc_close($fp); 260 261 return $output; 262 } 263 264 /** 265 * Sign a MIME_Part using S/MIME. 266 * 267 * @param MIME_Part $mime_part The MIME_Part object to sign. 268 * @param array $params The parameters required for signing. 269 * 270 * @return MIME_Part A MIME_Part object that is signed. 271 * Returns PEAR_Error object on error. 272 */ 273 function signMIMEPart($mime_part, $params) 274 { 275 require_once 'Horde/MIME/Part.php'; 276 require_once 'Horde/MIME/Structure.php'; 277 278 /* Sign the part as a message */ 279 $message = $this->encrypt($mime_part->toCanonicalString(), $params); 280 281 /* Break the result into its components */ 282 $mime_message = MIME_Structure::parseTextMIMEMessage($message); 283 284 $smime_sign = $mime_message->getPart(2); 285 $smime_sign->setDescription(_("S/MIME Cryptographic Signature")); 286 $smime_sign->transferDecodeContents(); 287 $smime_sign->setTransferEncoding('base64'); 288 289 $smime_part = &new MIME_Part('multipart/signed'); 290 $smime_part->setContents('This is a cryptographically signed message in MIME format.' . "\n"); 291 $smime_part->addPart($mime_part); 292 $smime_part->addPart($smime_sign); 293 $smime_part->setContentTypeParameter('protocol', 'application/pkcs7-signature'); 294 $smime_part->setContentTypeParameter('micalg', 'sha1'); 295 296 return $smime_part; 297 } 298 299 /** 300 * Encrypt a MIME_Part using S/MIME. 301 * 302 * @param MIME_Part $mime_part The MIME_Part object to encrypt. 303 * @param array $params The parameters required for encryption. 304 * 305 * @return MIME_Part A MIME_Part object that is encrypted. 306 * Returns PEAR_Error on error. 307 */ 308 function encryptMIMEPart($mime_part, $params = array()) 309 { 310 require_once 'Horde/MIME/Part.php'; 311 require_once 'Horde/MIME/Structure.php'; 312 313 /* Sign the part as a message */ 314 $message = $this->encrypt($mime_part->toCanonicalString(), $params); 315 if (is_a($message, 'PEAR_Error')) { 316 return $message; 317 } 318 319 /* Break the result into its components */ 320 $mime_message = MIME_Structure::parseTextMIMEMessage($message); 321 322 $smime_part = $mime_message->getBasePart(); 323 $smime_part->setDescription(_("S/MIME Encrypted Message")); 324 $smime_part->transferDecodeContents(); 325 $smime_part->setTransferEncoding('base64'); 326 $smime_part->setDisposition('inline'); 327 328 /* By default, encrypt() produces a message with type 329 * 'application/x-pkcs7-mime' and no 'smime-type' parameter. Per 330 * RFC 2311, the more correct MIME type is 'application/pkcs7-mime' 331 * and the smime-type should be 'enveloped-data'. */ 332 $smime_part->setType('application/pkcs7-mime'); 333 $smime_part->setContentTypeParameter('smime-type', 'enveloped-data'); 334 335 return $smime_part; 336 } 337 338 /** 339 * Encrypt a message in S/MIME format using a public key. 340 * 341 * @access private 342 * 343 * @param string $text The text to be encrypted. 344 * @param array $params The parameters needed for encryption. 345 * <pre> 346 * Parameters: 347 * =========== 348 * 'type' => 'message' (REQUIRED) 349 * 'pubkey' => public key. (REQUIRED) 350 * 'email' => E-mail address of recipient. If not present, or not found 351 * in the public key, the first e-mail address found in the 352 * key will be used instead. (Optional) 353 * </pre> 354 * 355 * @return string The encrypted message. 356 * Return PEAR_Error object on error. 357 */ 358 function _encryptMessage($text, $params) 359 { 360 $email = null; 361 362 /* Check for required parameters. */ 363 if (!isset($params['pubkey'])) { 364 return PEAR::raiseError(_("A public SMIME key is required to encrypt a message."), 'horde.error'); 365 } 366 367 /* Create temp files for input/output. */ 368 $input = $this->_createTempFile('horde-smime'); 369 $output = $this->_createTempFile('horde-smime'); 370 371 /* Store message in file. */ 372 $fp1 = fopen($input, 'w+'); 373 fputs($fp1, $text); 374 fclose($fp1); 375 376 if (isset($params['email'])) { 377 $email = $params['email']; 378 } else { 379 $email = $this->getEmailFromKey($params['pubkey']); 380 if (is_null($email)) { 381 return PEAR::raiseError(_("Could not determine the recipient's e-mail address."), 'horde.error'); 382 } 383 } 384 385 /* Encrypt the document. */ 386 if (openssl_pkcs7_encrypt($input, $output, $params['pubkey'], array('To' => $email))) { 387 $result = file_get_contents($output); 388 if (!empty($result)) { 389 return $this->_fixContentType($result, 'encrypt'); 390 } 391 } 392 393 return PEAR::raiseError(_("Could not S/MIME encrypt message."), 'horde.error'); 394 } 395 396 /** 397 * Sign a message in S/MIME format using a private key. 398 * 399 * @access private 400 * 401 * @param string $text The text to be signed. 402 * @param array $params The parameters needed for signing. 403 * <pre> 404 * Parameters: 405 * =========== 406 * 'certs' => Additional signing certs (Optional) 407 * 'passphrase' => Passphrase for key (REQUIRED) 408 * 'privkey' => Private key (REQUIRED) 409 * 'pubkey' => Public key (REQUIRED) 410 * 'sigtype' => Determine the signature type to use. (Optional) 411 * 'cleartext' -- Make a clear text signature 412 * 'detach' -- Make a detached signature (DEFAULT) 413 * 'type' => 'signature' (REQUIRED) 414 * </pre> 415 * 416 * @return string The signed message. 417 * Return PEAR_Error object on error. 418 */ 419 function _encryptSignature($text, $params) 420 { 421 /* Check for secure connection. */ 422 $secure_check = $this->requireSecureConnection(); 423 if (is_a($secure_check, 'PEAR_Error')) { 424 return $secure_check; 425 } 426 427 /* Check for required parameters. */ 428 if (!isset($params['pubkey']) || 429 !isset($params['privkey']) || 430 !array_key_exists('passphrase', $params)) { 431 return PEAR::raiseError(_("A public S/MIME key, private S/MIME key, and passphrase are required to sign a message."), 'horde.error'); 432 } 433 434 /* Create temp files for input/output/certificates. */ 435 $input = $this->_createTempFile('horde-smime'); 436 $output = $this->_createTempFile('horde-smime'); 437 $certs = $this->_createTempFile('horde-smime'); 438 439 /* Store message in temporary file. */ 440 $fp = fopen($input, 'w+'); 441 fputs($fp, $text); 442 fclose($fp); 443 444 /* Store additional certs in temporary file. */ 445 if (!empty($params['certs'])) { 446 $fp = fopen($certs, 'w+'); 447 fputs($fp, $params['certs']); 448 fclose($fp); 449 } 450 451 /* Determine the signature type to use. */ 452 if (isset($params['sigtype']) && ($params['sigtype'] == 'cleartext')) { 453 $flags = PKCS7_TEXT; 454 } else { 455 $flags = PKCS7_DETACHED; 456 } 457 458 $privkey = (is_null($params['passphrase'])) ? $params['privkey'] : array($params['privkey'], $params['passphrase']); 459 460 if (empty($params['certs'])) { 461 $res = openssl_pkcs7_sign($input, $output, $params['pubkey'], $privkey, array(), $flags); 462 } else { 463 $res = openssl_pkcs7_sign($input, $output, $params['pubkey'], $privkey, array(), $flags, $certs); 464 } 465 466 if (!$res) { 467 return PEAR::raiseError(_("Could not S/MIME sign message."), 'horde.error'); 468 } 469 470 $data = file_get_contents($output); 471 return $this->_fixContentType($data, 'signature'); 472 } 473 474 /** 475 * Decrypt an S/MIME encrypted message using a private/public keypair 476 * and a passhprase. 477 * 478 * @access private 479 * 480 * @param string $text The text to be decrypted. 481 * @param array $params The parameters needed for decryption. 482 * <pre> 483 * Parameters: 484 * =========== 485 * 'type' => 'message' (REQUIRED) 486 * 'pubkey' => public key. (REQUIRED) 487 * 'privkey' => private key. (REQUIRED) 488 * 'passphrase' => Passphrase for Key. (REQUIRED) 489 * </pre> 490 * 491 * @return string The decrypted message. 492 * Returns PEAR_Error object on error. 493 */ 494 function _decryptMessage($text, $params) 495 { 496 /* Check for secure connection. */ 497 $secure_check = $this->requireSecureConnection(); 498 if (is_a($secure_check, 'PEAR_Error')) { 499 return $secure_check; 500 } 501 502 /* Check for required parameters. */ 503 if (!isset($params['pubkey']) || 504 !isset($params['privkey']) || 505 !array_key_exists('passphrase', $params)) { 506 return PEAR::raiseError(_("A public S/MIME key, private S/MIME key, and passphrase are required to decrypt a message."), 'horde.error'); 507 } 508 509 /* Create temp files for input/output. */ 510 $input = $this->_createTempFile('horde-smime'); 511 $output = $this->_createTempFile('horde-smime'); 512 513 /* Store message in file. */ 514 $fp = fopen($input, 'w+'); 515 fputs($fp, trim($text)); 516 fclose($fp); 517 518 $privkey = (is_null($params['passphrase'])) ? $params['privkey'] : array($params['privkey'], $params['passphrase']); 519 if (openssl_pkcs7_decrypt($input, $output, $params['pubkey'], $privkey)) { 520 return file_get_contents($output); 521 } 522 523 return PEAR::raiseError(_("Could not decrypt S/MIME data."), 'horde.error'); 524 } 525 526 /** 527 * Sign and Encrypt a MIME_Part using S/MIME. 528 * 529 * @param MIME_Part $mime_part The MIME_Part object to sign and encrypt. 530 * @param array $sign_params The parameters required for signing. See 531 * _encryptSignature(). 532 * @param array $encrypt_params The parameters required for encryption. 533 * See _encryptMessage(). 534 * 535 * @return MIME_Part A MIME_Part object that is signed and encrypted. 536 * Returns PEAR_Error on error. 537 */ 538 function signAndEncryptMIMEPart($mime_part, $sign_params = array(), 539 $encrypt_params = array()) 540 { 541 include_once 'Horde/MIME/Part.php'; 542 543 $part = $this->signMIMEPart($mime_part, $sign_params); 544 if (is_a($part, 'PEAR_Error')) { 545 return $part; 546 } 547 $part = $this->encryptMIMEPart($part, $encrypt_params); 548 if (is_a($part, 'PEAR_Error')) { 549 return $part; 550 } 551 552 return $part; 553 } 554 555 /** 556 * Convert a PEM format certificate to readable HTML version 557 * 558 * @param string $cert PEM format certificate 559 * 560 * @return string HTML detailing the certificate. 561 */ 562 function certToHTML($cert) 563 { 564 /* Common Fields */ 565 $fieldnames = array( 566 'Email' => _("Email Address"), 567 'CommonName' => _("Common Name"), 568 'Organisation' => _("Organisation"), 569 'OrganisationalUnit' => _("Organisational Unit"), 570 'Country' => _("Country"), 571 'StateOrProvince' => _("State or Province"), 572 'Location' => _("Location"), 573 'StreetAddress' => _("Street Address"), 574 'TelephoneNumber' => _("Telephone Number"), 575 'Surname' => _("Surname"), 576 'GivenName' => _("Given Name") 577 ); 578 579 /* Netscape Extensions */ 580 $fieldnames += array( 581 'netscape-cert-type' => _("Netscape certificate type"), 582 'netscape-base-url' => _("Netscape Base URL"), 583 'netscape-revocation-url' => _("Netscape Revocation URL"), 584 'netscape-ca-revocation-url' => _("Netscape CA Revocation URL"), 585 'netscape-cert-renewal-url' => _("Netscape Renewal URL"), 586 'netscape-ca-policy-url' => _("Netscape CA policy URL"), 587 'netscape-ssl-server-name' => _("Netscape SSL server name"), 588 'netscape-comment' => _("Netscape certificate comment") 589 ); 590 591 /* X590v3 Extensions */ 592 $fieldnames += array( 593 'id-ce-extKeyUsage' => _("X509v3 Extended Key Usage"), 594 'id-ce-basicConstraints' => _("X509v3 Basic Constraints"), 595 'id-ce-subjectAltName' => _("X509v3 Subject Alternative Name"), 596 'id-ce-subjectKeyIdentifier' => _("X509v3 Subject Key Identifier"), 597 'id-ce-certificatePolicies' => _("Certificate Policies"), 598 'id-ce-CRLDistributionPoints' => _("CRL Distribution Points"), 599 'id-ce-keyUsage' => _("Key Usage") 600 ); 601 602 $cert_details = $this->parseCert($cert); 603 if (!is_array($cert_details)) { 604 return '<pre class="fixed">' . _("Unable to extract certificate details") . '</pre>'; 605 } 606 $certificate = $cert_details['certificate']; 607 608 $text = '<pre class="fixed">'; 609 610 /* Subject (a/k/a Certificate Owner) */ 611 if (isset($certificate['subject'])) { 612 $text .= "<strong>" . _("Certificate Owner") . ":</strong>\n"; 613 614 foreach ($certificate['subject'] as $key => $value) { 615 if (isset($fieldnames[$key])) { 616 $text .= sprintf(" %s: %s\n", $fieldnames[$key], $value); 617 } else { 618 $text .= sprintf(" *%s: %s\n", $key, $value); 619 } 620 } 621 $text .= "\n"; 622 } 623 624 /* Issuer */ 625 if (isset($certificate['issuer'])) { 626 $text .= "<strong>" . _("Issuer") . ":</strong>\n"; 627 628 foreach ($certificate['issuer'] as $key => $value) { 629 if (isset($fieldnames[$key])) { 630 $text .= sprintf(" %s: %s\n", $fieldnames[$key], $value); 631 } else { 632 $text .= sprintf(" *%s: %s\n", $key, $value); 633 } 634 } 635 $text .= "\n"; 636 } 637 638 /* Dates */ 639 $text .= "<strong>" . _("Validity") . ":</strong>\n"; 640 $text .= sprintf(" %s: %s\n", _("Not Before"), strftime("%x %X", $certificate['validity']['notbefore'])); 641 $text .= sprintf(" %s: %s\n", _("Not After"), strftime("%x %X", $certificate['validity']['notafter'])); 642 $text .= "\n"; 643 644 /* Certificate Owner - Public Key Info */ 645 $text .= "<strong>" . _("Public Key Info") . ":</strong>\n"; 646 $text .= sprintf(" %s: %s\n", _("Public Key Algorithm"), $certificate['subjectPublicKeyInfo']['algorithm']); 647 if ($certificate['subjectPublicKeyInfo']['algorithm'] == 'rsaEncryption') { 648 if (Util::extensionExists('bcmath')) { 649 $modulus = $certificate['subjectPublicKeyInfo']['subjectPublicKey']['modulus']; 650 $modulus_hex = ''; 651 while ($modulus != '0') { 652 $modulus_hex = dechex(bcmod($modulus, '16')) . $modulus_hex; 653 $modulus = bcdiv($modulus, '16', 0); 654 } 655 656 if ((strlen($modulus_hex) > 64) && 657 (strlen($modulus_hex) < 128)) { 658 str_pad($modulus_hex, 128, '0', STR_PAD_RIGHT); 659 } elseif ((strlen($modulus_hex) > 128) && 660 (strlen($modulus_hex) < 256)) { 661 str_pad($modulus_hex, 256, '0', STR_PAD_RIGHT); 662 } 663 664 $text .= " " . sprintf(_("RSA Public Key (%d bit)"), strlen($modulus_hex) * 4) . ":\n"; 665 666 $modulus_str = ''; 667 for ($i = 0; $i < strlen($modulus_hex); $i += 2) { 668 if (($i % 32) == 0) { 669 $modulus_str .= "\n "; 670 } 671 $modulus_str .= substr($modulus_hex, $i, 2) . ':'; 672 } 673 674 $text .= sprintf(" %s: %s\n", _("Modulus"), $modulus_str); 675 } 676 677 $text .= sprintf(" %s: %s\n", _("Exponent"), $certificate['subjectPublicKeyInfo']['subjectPublicKey']['publicExponent']); 678 } 679 $text .= "\n"; 680 681 /* X509v3 extensions */ 682 if (isset($certificate['extensions'])) { 683 $text .= "<strong>" . _("X509v3 extensions") . ":</strong>\n"; 684 685 foreach ($certificate['extensions'] as $key => $value) { 686 if (is_array($value)) { 687 $value = _("Unsupported Extension"); 688 } 689 if (isset($fieldnames[$key])) { 690 $text .= sprintf(" %s:\n %s\n", $fieldnames[$key], wordwrap($value, 40, "\n ")); 691 } else { 692 $text .= sprintf(" %s:\n %s\n", $key, wordwrap($value, 60, "\n ")); 693 } 694 } 695 696 $text .= "\n"; 697 } 698 699 /* Certificate Details */ 700 $text .= "<strong>" . _("Certificate Details") . ":</strong>\n"; 701 $text .= sprintf(" %s: %d\n", _("Version"), $certificate['version']); 702 $text .= sprintf(" %s: %d\n", _("Serial Number"), $certificate['serialNumber']); 703 704 foreach ($cert_details['fingerprints'] as $hash => $fingerprint) { 705 $label = sprintf(_("%s Fingerprint"), String::upper($hash)); 706 $fingerprint_str = ''; 707 for ($i = 0; $i < strlen($fingerprint); $i += 2) { 708 $fingerprint_str .= substr($fingerprint, $i, 2) . ':'; 709 } 710 $text .= sprintf(" %s:\n %s\n", $label, $fingerprint_str); 711 } 712 $text .= sprintf(" %s: %s\n", _("Signature Algorithm"), $cert_details['signatureAlgorithm']); 713 $text .= sprintf(" %s:", _("Signature")); 714 715 $sig_str = ''; 716 for ($i = 0; $i < strlen($cert_details['signature']); $i++) { 717 if (($i % 16) == 0) { 718 $sig_str .= "\n "; 719 } 720 $sig_str .= sprintf("%02x:", ord($cert_details['signature'][$i])); 721 } 722 723 return $text . $sig_str . "\n</pre>"; 724 } 725 726 /** 727 * Extract the contents of a PEM format certificate to an array. 728 * 729 * @param string $cert PEM format certificate 730 * 731 * @return array Array containing all extractable information about 732 * the certificate. 733 */ 734 function parseCert($cert) 735 { 736 $cert_split = preg_split('/(-----((BEGIN)|(END)) CERTIFICATE-----)/', $cert); 737 if (!isset($cert_split[1])) { 738 $raw_cert = base64_decode($cert); 739 } else { 740 $raw_cert = base64_decode($cert_split[1]); 741 } 742 743 $cert_data = $this->_parseASN($raw_cert); 744 if (!is_array($cert_data) || ($cert_data[0] == 'UNKNOWN')) { 745 return false; 746 } 747 748 $cert_details = array(); 749 $cert_details['fingerprints']['md5'] = md5($raw_cert); 750 if (Util::extensionExists('mhash')) { 751 $cert_details['fingerprints']['sha1'] = bin2hex(mhash(MHASH_SHA1, $raw_cert)); 752 } 753 754 $cert_details['certificate']['extensions'] = array(); 755 $cert_details['certificate']['version'] = $cert_data[1][0][1][0][1] + 1; 756 $cert_details['certificate']['serialNumber'] = $cert_data[1][0][1][1][1]; 757 $cert_details['certificate']['signature'] = $cert_data[1][0][1][2][1][0][1]; 758 $cert_details['certificate']['issuer'] = $cert_data[1][0][1][3][1]; 759 $cert_details['certificate']['validity'] = $cert_data[1][0][1][4][1]; 760 $cert_details['certificate']['subject'] = @$cert_data[1][0][1][5][1]; 761 $cert_details['certificate']['subjectPublicKeyInfo'] = $cert_data[1][0][1][6][1]; 762 763 $cert_details['signatureAlgorithm'] = $cert_data[1][1][1][0][1]; 764 $cert_details['signature'] = $cert_data[1][2][1]; 765 766 // issuer 767 $issuer = array(); 768 foreach ($cert_details['certificate']['issuer'] as $value) { 769 $issuer[$value[1][1][0][1]] = $value[1][1][1][1]; 770 } 771 $cert_details['certificate']['issuer'] = $issuer; 772 773 // subject 774 $subject = array(); 775 foreach ($cert_details['certificate']['subject'] as $value) { 776 $subject[$value[1][1][0][1]] = $value[1][1][1][1]; 777 } 778 $cert_details['certificate']['subject'] = $subject; 779 780 // validity 781 $vals = $cert_details['certificate']['validity']; 782 $cert_details['certificate']['validity'] = array(); 783 $cert_details['certificate']['validity']['notbefore'] = $vals[0][1]; 784 $cert_details['certificate']['validity']['notafter'] = $vals[1][1]; 785 foreach ($cert_details['certificate']['validity'] as $key => $val) { 786 $year = substr($val, 0, 2); 787 $month = substr($val, 2, 2); 788 $day = substr($val, 4, 2); 789 $hour = substr($val, 6, 2); 790 $minute = substr($val, 8, 2); 791 if (($val[11] == '-') || ($val[9] == '+')) { 792 // handle time zone offset here 793 $seconds = 0; 794 } elseif (String::upper($val[11]) == 'Z') { 795 $seconds = 0; 796 } else { 797 $seconds = substr($val, 10, 2); 798 if (($val[11] == '-') || ($val[9] == '+')) { 799 // handle time zone offset here 800 } 801 } 802 $cert_details['certificate']['validity'][$key] = mktime ($hour, $minute, $seconds, $month, $day, $year); 803 } 804 805 // Split the Public Key into components. 806 $subjectPublicKeyInfo = array(); 807 $subjectPublicKeyInfo['algorithm'] = $cert_details['certificate']['subjectPublicKeyInfo'][0][1][0][1]; 808 if ($subjectPublicKeyInfo['algorithm'] == 'rsaEncryption') { 809 $subjectPublicKey = $this->_parseASN($cert_details['certificate']['subjectPublicKeyInfo'][1][1]); 810 $subjectPublicKeyInfo['subjectPublicKey']['modulus'] = $subjectPublicKey[1][0][1]; 811 $subjectPublicKeyInfo['subjectPublicKey']['publicExponent'] = $subjectPublicKey[1][1][1]; 812 } 813 $cert_details['certificate']['subjectPublicKeyInfo'] = $subjectPublicKeyInfo; 814 815 if (isset($cert_data[1][0][1][7]) && 816 is_array($cert_data[1][0][1][7][1])) { 817 foreach ($cert_data[1][0][1][7][1] as $ext) { 818 $oid = $ext[1][0][1]; 819 $cert_details['certificate']['extensions'][$oid] = $ext[1][1]; 820 } 821 } 822 823 $i = 9; 824 while (isset($cert_data[1][0][1][$i])) { 825 $oid = $cert_data[1][0][1][$i][1][0][1]; 826 $cert_details['certificate']['extensions'][$oid] = $cert_data[1][0][1][$i][1][1]; 827 $i++; 828 } 829 830 foreach ($cert_details['certificate']['extensions'] as $oid => $val) { 831 switch ($oid) { 832 case 'netscape-base-url': 833 case 'netscape-revocation-url': 834 case 'netscape-ca-revocation-url': 835 case 'netscape-cert-renewal-url': 836 case 'netscape-ca-policy-url': 837 case 'netscape-ssl-server-name': 838 case 'netscape-comment': 839 $val = $this->_parseASN($val[1]); 840 $cert_details['certificate']['extensions'][$oid] = $val[1]; 841 break; 842 843 case 'id-ce-subjectAltName': 844 $val = $this->_parseASN($val[1]); 845 $cert_details['certificate']['extensions'][$oid] = ''; 846 foreach ($val[1] as $name) { 847 if (!empty($cert_details['certificate']['extensions'][$oid])) { 848 $cert_details['certificate']['extensions'][$oid] .= ', '; 849 } 850 $cert_details['certificate']['extensions'][$oid] .= $name[1]; 851 } 852 break; 853 854 case 'netscape-cert-type': 855 $val = $this->_parseASN($val[1]); 856 $val = ord($val[1]); 857 $newVal = ''; 858 859 if ($val & 0x80) { 860 $newVal .= empty($newVal) ? 'SSL client' : ', SSL client'; 861 } 862 if ($val & 0x40) { 863 $newVal .= empty($newVal) ? 'SSL server' : ', SSL server'; 864 } 865 if ($val & 0x20) { 866 $newVal .= empty($newVal) ? 'S/MIME' : ', S/MIME'; 867 } 868 if ($val & 0x10) { 869 $newVal .= empty($newVal) ? 'Object Signing' : ', Object Signing'; 870 } 871 if ($val & 0x04) { 872 $newVal .= empty($newVal) ? 'SSL CA' : ', SSL CA'; 873 } 874 if ($val & 0x02) { 875 $newVal .= empty($newVal) ? 'S/MIME CA' : ', S/MIME CA'; 876 } 877 if ($val & 0x01) { 878 $newVal .= empty($newVal) ? 'Object Signing CA' : ', Object Signing CA'; 879 } 880 881 $cert_details['certificate']['extensions'][$oid] = $newVal; 882 break; 883 884 case 'id-ce-extKeyUsage': 885 $val = $this->_parseASN($val[1]); 886 $val = $val[1]; 887 888 $newVal = ''; 889 if ($val[0][1] != 'sequence') { 890 $val = array($val); 891 } else { 892 $val = $val[1][1]; 893 } 894 foreach ($val as $usage) { 895 if ($usage[1] == 'id_kp_clientAuth') { 896 $newVal .= empty($newVal) ? 'TLS Web Client Authentication' : ', TLS Web Client Authentication'; 897 } else { 898 $newVal .= empty($newVal) ? $usage[1] : ', ' . $usage[1]; 899 } 900 } 901 $cert_details['certificate']['extensions'][$oid] = $newVal; 902 break; 903 904 case 'id-ce-subjectKeyIdentifier': 905 $val = $this->_parseASN($val[1]); 906 $val = $val[1]; 907 908 $newVal = ''; 909 910 for ($i = 0; $i < strlen($val); $i++) { 911 $newVal .= sprintf("%02x:", ord($val[$i])); 912 } 913 $cert_details['certificate']['extensions'][$oid] = $newVal; 914 break; 915 916 case 'id-ce-authorityKeyIdentifier': 917 $val = $this->_parseASN($val[1]); 918 if ($val[0] == 'string') { 919 $val = $val[1]; 920 921 $newVal = ''; 922 for ($i = 0; $i < strlen($val); $i++) { 923 $newVal .= sprintf("%02x:", ord($val[$i])); 924 } 925 $cert_details['certificate']['extensions'][$oid] = $newVal; 926 } else { 927 $cert_details['certificate']['extensions'][$oid] = _("Unsupported Extension"); 928 } 929 break; 930 931 case 'id-ce-basicConstraints': 932 case 'default': 933 $cert_details['certificate']['extensions'][$oid] = _("Unsupported Extension"); 934 break; 935 } 936 } 937 938 return $cert_details; 939 } 940 941 /** 942 * Attempt to parse ASN.1 formated data. 943 * 944 * @access private 945 * 946 * @param string $data ASN.1 formated data 947 * 948 * @return array Array contained the extracted values. 949 */ 950 function _parseASN($data) 951 { 952 $result = array(); 953 954 while (strlen($data) > 1) { 955 $class = ord($data[0]); 956 switch ($class) { 957 case 0x30: 958 // Sequence 959 $len = ord($data[1]); 960 $bytes = 0; 961 if ($len & 0x80) { 962 $bytes = $len & 0x0f; 963 $len = 0; 964 for ($i = 0; $i < $bytes; $i++) { 965 $len = ($len << 8) | ord($data[$i + 2]); 966 } 967 } 968 $sequence_data = substr($data, 2 + $bytes, $len); 969 $data = substr($data, 2 + $bytes + $len); 970 971 $values = $this->_parseASN($sequence_data); 972 if (!is_array($values) || is_string($values[0])) { 973 $values = array($values); 974 } 975 $sequence_values = array(); 976 $i = 0; 977 foreach ($values as $val) { 978 if ($val[0] == 'extension') { 979 $sequence_values['extensions'][] = $val; 980 } else { 981 $sequence_values[$i++] = $val; 982 } 983 } 984 $result[] = array('sequence', $sequence_values); 985 break; 986 987 case 0x31: 988 // Set of 989 $len = ord($data[1]); 990 $bytes = 0; 991 if ($len & 0x80) { 992 $bytes = $len & 0x0f; 993 $len = 0; 994 for ($i = 0; $i < $bytes; $i++) { 995 $len = ($len << 8) | ord($data[$i + 2]); 996 } 997 } 998 $sequence_data = substr($data, 2 + $bytes, $len); 999 $data = substr($data, 2 + $bytes + $len); 1000 $result[] = array('set', $this->_parseASN($sequence_data)); 1001 break; 1002 1003 case 0x01: 1004 // Boolean type 1005 $boolean_value = (ord($data[2]) == 0xff); 1006 $data = substr($data, 3); 1007 $result[] = array('boolean', $boolean_value); 1008 break; 1009 1010 case 0x02: 1011 // Integer type 1012 $len = ord($data[1]); 1013 $bytes = 0; 1014 if ($len & 0x80) { 1015 $bytes = $len & 0x0f; 1016 $len = 0; 1017 for ($i = 0; $i < $bytes; $i++) { 1018 $len = ($len << 8) | ord($data[$i + 2]); 1019 } 1020 } 1021 1022 $integer_data = substr($data, 2 + $bytes, $len); 1023 $data = substr($data, 2 + $bytes + $len); 1024 1025 $value = 0; 1026 if ($len <= 4) { 1027 /* Method works fine for small integers */ 1028 for ($i = 0; $i < strlen($integer_data); $i++) { 1029 $value = ($value << 8) | ord($integer_data[$i]); 1030 } 1031 } else { 1032 /* Method works for arbitrary length integers */ 1033 if (Util::extensionExists('bcmath')) { 1034 for ($i = 0; $i < strlen($integer_data); $i++) { 1035 $value = bcadd(bcmul($value, 256), ord($integer_data[$i])); 1036 } 1037 } else { 1038 $value = -1; 1039 } 1040 } 1041 $result[] = array('integer(' . $len . ')', $value); 1042 break; 1043 1044 case 0x03: 1045 // Bitstring type 1046 $len = ord($data[1]); 1047 $bytes = 0; 1048 if ($len & 0x80) { 1049 $bytes = $len & 0x0f; 1050 $len = 0; 1051 for ($i = 0; $i < $bytes; $i++) { 1052 $len = ($len << 8) | ord($data[$i + 2]); 1053 } 1054 } 1055 $bitstring_data = substr($data, 3 + $bytes, $len); 1056 $data = substr($data, 2 + $bytes + $len); 1057 $result[] = array('bit string', $bitstring_data); 1058 break; 1059 1060 case 0x04: 1061 // Octetstring type 1062 $len = ord($data[1]); 1063 $bytes = 0; 1064 if ($len & 0x80) { 1065 $bytes = $len & 0x0f; 1066 $len = 0; 1067 for ($i = 0; $i < $bytes; $i++) { 1068 $len = ($len << 8) | ord($data[$i + 2]); 1069 } 1070 } 1071 $octectstring_data = substr($data, 2 + $bytes, $len); 1072 $data = substr($data, 2 + $bytes + $len); 1073 $result[] = array('octet string', $octectstring_data); 1074 break; 1075 1076 case 0x05: 1077 // Null type 1078 $data = substr($data, 2); 1079 $result[] = array('null', null); 1080 break; 1081 1082 case 0x06: 1083 // Object identifier type 1084 $len = ord($data[1]); 1085 $bytes = 0; 1086 if ($len & 0x80) { 1087 $bytes = $len & 0x0f; 1088 $len = 0; 1089 for ($i = 0; $i < $bytes; $i++) { 1090 $len = ($len << 8) | ord($data[$i + 2]); 1091 } 1092 } 1093 $oid_data = substr($data, 2 + $bytes, $len); 1094 $data = substr($data, 2 + $bytes + $len); 1095 1096 // Unpack the OID 1097 $plain = floor(ord($oid_data[0]) / 40); 1098 $plain .= '.' . ord($oid_data[0]) % 40; 1099 1100 $value = 0; 1101 $i = 1; 1102 while ($i < strlen($oid_data)) { 1103 $value = $value << 7; 1104 $value = $value | (ord($oid_data[$i]) & 0x7f); 1105 1106 if (!(ord($oid_data[$i]) & 0x80)) { 1107 $plain .= '.' . $value; 1108 $value = 0; 1109 } 1110 $i++; 1111 } 1112 1113 if (isset($this->_oids[$plain])) { 1114 $result[] = array('oid', $this->_oids[$plain]); 1115 } else { 1116 $result[] = array('oid', $plain); 1117 } 1118 1119 break; 1120 1121 case 0x12: 1122 case 0x13: 1123 case 0x14: 1124 case 0x15: 1125 case 0x16: 1126 case 0x81: 1127 case 0x80: 1128 // Character string type 1129 $len = ord($data[1]); 1130 $bytes = 0; 1131 if ($len & 0x80) { 1132 $bytes = $len & 0x0f; 1133 $len = 0; 1134 for ($i = 0; $i < $bytes; $i++) { 1135 $len = ($len << 8) | ord($data[$i + 2]); 1136 } 1137 } 1138 $string_data = substr($data, 2 + $bytes, $len); 1139 $data = substr($data, 2 + $bytes + $len); 1140 $result[] = array('string', $string_data); 1141 break; 1142 1143 case 0x17: 1144 // Time types 1145 $len = ord($data[1]); 1146 $bytes = 0; 1147 if ($len & 0x80) { 1148 $bytes = $len & 0x0f; 1149 $len = 0; 1150 for ($i = 0; $i < $bytes; $i++) { 1151 $len = ($len << 8) | ord($data[$i + 2]); 1152 } 1153 } 1154 $time_data = substr($data, 2 + $bytes, $len); 1155 $data = substr($data, 2 + $bytes + $len); 1156 $result[] = array('utctime', $time_data); 1157 break; 1158 1159 case 0x82: 1160 // X509v3 extensions? 1161 $len = ord($data[1]); 1162 $bytes = 0; 1163 if ($len & 0x80) { 1164 $bytes = $len & 0x0f; 1165 $len = 0; 1166 for ($i = 0; $i < $bytes; $i++) { 1167 $len = ($len << 8) | ord($data[$i + 2]); 1168 } 1169 } 1170 $sequence_data = substr($data, 2 + $bytes, $len); 1171 $data = substr($data, 2 + $bytes + $len); 1172 $result[] = array('extension', 'X509v3 extensions'); 1173 $result[] = $this->_parseASN($sequence_data); 1174 break; 1175 1176 case 0xa0: 1177 case 0xa3: 1178 // Extensions 1179 $extension_data = substr($data, 0, 2); 1180 $data = substr($data, 2); 1181 $result[] = array('extension', dechex($extension_data)); 1182 break; 1183 1184 case 0xe6: 1185 $extension_data = substr($data, 0, 1); 1186 $data = substr($data, 1); 1187 $result[] = array('extension', dechex($extension_data)); 1188 break; 1189 1190 case 0xa1: 1191 $extension_data = substr($data, 0, 1); 1192 $data = substr($data, 6); 1193 $result[] = array('extension', dechex($extension_data)); 1194 break; 1195 1196 default: 1197 // Unknown 1198 $result[] = array('UNKNOWN', dechex($data)); 1199 $data = ''; 1200 break; 1201 } 1202 } 1203 1204 return (count($result) > 1) ? $result : array_pop($result); 1205 } 1206 1207 /** 1208 * Decrypt an S?MIME signed message using a public key. 1209 * 1210 * @access private 1211 * 1212 * @param string $text The text to be verified. 1213 * @param array $params The parameters needed for verification. 1214 * 1215 * @return string The verification message. 1216 * Returns PEAR_Error object on error. 1217 */ 1218 function _decryptSignature($text, $params) 1219 { 1220 return PEAR::raiseError('_decryptSignature() ' . _("not yet implemented")); 1221 } 1222 1223 /** 1224 * Check for the presence of the OpenSSL extension to PHP. 1225 * 1226 * @return boolean Returns true if the openssl extension is available. 1227 * Returns a PEAR_Error if not. 1228 */ 1229 function checkForOpenSSL() 1230 { 1231 if (!Util::extensionExists('openssl')) { 1232 return PEAR::raiseError(_("The openssl module is required for the Horde_Crypt_smime:: class.")); 1233 } 1234 } 1235 1236 /** 1237 * Extract the email address from a public key. 1238 * 1239 * @param string $key The public key. 1240 * 1241 * @return string Returns the email address, or null if none is found. 1242 */ 1243 function getEmailFromKey($key) 1244 { 1245 $key_info = openssl_x509_parse($key); 1246 if (is_array($key_info) && isset($key_info['subject'])) { 1247 if (isset($key_info['subject']['Email'])) { 1248 return $key_info['subject']['Email']; 1249 } elseif (isset($key_info['subject']['emailAddress'])) { 1250 return $key_info['subject']['emailAddress']; 1251 } 1252 } 1253 1254 return null; 1255 } 1256 1257 /** 1258 * Convert a PKCS 12 encrypted certificate package into a private key, 1259 * public key, and any additional keys. 1260 * 1261 * @param string $text The PKCS 12 data. 1262 * @param array $params The parameters needed for parsing. 1263 * <pre> 1264 * Parameters: 1265 * =========== 1266 * 'sslpath' => The path to the OpenSSL binary. (REQUIRED) 1267 * 'password' => The password to use to decrypt the data. (Optional) 1268 * 'newpassword' => The password to use to encrypt the private key. 1269 * (Optional) 1270 * </pre> 1271 * 1272 * @return stdClass An object. 1273 * 'private' - The private key in PEM format. 1274 * 'public' - The public key in PEM format. 1275 * 'certs' - An array of additional certs. 1276 * Returns PEAR_Error on error. 1277 */ 1278 function parsePKCS12Data($pkcs12, $params) 1279 { 1280 /* Check for availability of OpenSSL PHP extension. */ 1281 $openssl = $this->checkForOpenSSL(); 1282 if (is_a($openssl, 'PEAR_Error')) { 1283 return $openssl; 1284 } 1285 1286 if (!isset($params['sslpath'])) { 1287 return PEAR::raiseError(_("No path to the OpenSSL binary provided. The OpenSSL binary is necessary to work with PKCS 12 data."), 'horde.error'); 1288 } 1289 $sslpath = escapeshellcmd($params['sslpath']); 1290 1291 /* Create temp files for input/output. */ 1292 $input = $this->_createTempFile('horde-smime'); 1293 $output = $this->_createTempFile('horde-smime'); 1294 1295 $ob = &new stdClass; 1296 1297 /* Write text to file */ 1298 $fp = fopen($input, 'w+'); 1299 fwrite($fp, $pkcs12); 1300 fclose($fp); 1301 1302 /* Extract the private key from the file first. */ 1303 $cmdline = $sslpath . ' pkcs12 -in ' . $input . ' -out ' . $output . ' -nocerts'; 1304 if (isset($params['password'])) { 1305 $cmdline .= ' -passin stdin'; 1306 if (!empty($params['newpassword'])) { 1307 $cmdline .= ' -passout stdin'; 1308 } else { 1309 $cmdline .= ' -nodes'; 1310 } 1311 $fd = popen($cmdline, 'w'); 1312 fwrite($fd, $params['password'] . "\n"); 1313 if (!empty($params['newpassword'])) { 1314 fwrite($fd, $params['newpassword'] . "\n"); 1315 } 1316 pclose($fd); 1317 } else { 1318 $cmdline .= ' -nodes'; 1319 exec($cmdline); 1320 } 1321 $ob->private = trim(file_get_contents($output)); 1322 if (empty($ob->private)) { 1323 return PEAR::raiseError(_("Password incorrect"), 'horde.error'); 1324 } 1325 1326 /* Extract the public key next. */ 1327 $cmdline = $sslpath . ' pkcs12 -in ' . $input . ' -out ' . $output . ' -nokeys -clcerts'; 1328 if (isset($params['password'])) { 1329 $cmdline .= ' -passin stdin'; 1330 $fd = popen($cmdline, 'w'); 1331 fwrite($fd, $params['password'] . "\n"); 1332 pclose($fd); 1333 } else { 1334 exec($cmdline); 1335 } 1336 $ob->public = trim(file_get_contents($output)); 1337 1338 /* Extract the public key next. */ 1339 $cmdline = $sslpath . ' pkcs12 -in ' . $input . ' -out ' . $output . ' -nokeys -cacerts'; 1340 if (isset($params['password'])) { 1341 $cmdline .= ' -passin stdin'; 1342 $fd = popen($cmdline, 'w'); 1343 fwrite($fd, $params['password'] . "\n"); 1344 pclose($fd); 1345 } else { 1346 exec($cmdline); 1347 } 1348 $ob->certs = trim(file_get_contents($output)); 1349 1350 return $ob; 1351 } 1352 1353 /** 1354 * The Content-Type parameters PHP's openssl_pkcs7_* functions return are 1355 * deprecated. Fix these headers to the correct ones (see RFC 2311). 1356 * 1357 * @access private 1358 * 1359 * @param string $text The PKCS7 data. 1360 * @param string $type Is this 'message' or 'signature' data? 1361 * 1362 * @return string The PKCS7 data with the correct Content-Type parameter. 1363 */ 1364 function _fixContentType($text, $type) 1365 { 1366 if ($type == 'message') { 1367 $from = 'application/x-pkcs7-mime'; 1368 $to = 'application/pkcs7-mime'; 1369 } else { 1370 $from = 'application/x-pkcs7-signature'; 1371 $to = 'application/pkcs7-signature'; 1372 } 1373 return str_replace('Content-Type: ' . $from, 'Content-Type: ' . $to, $text); 1374 } 1375 1376 }
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
Généré le : Sun Feb 25 18:01:28 2007 | par Balluche grâce à PHPXref 0.7 |