示例#1
0
 /**
  * Sign an X.509 certificate
  *
  * $issuer's private key needs to be loaded.
  * $subject can be either an existing X.509 cert (if you want to resign it),
  * a CSR or something with the DN and public key explicitly set.
  *
  * @param X509 $issuer
  * @param X509 $subject
  * @param String $signatureAlgorithm optional
  * @access public
  * @return Mixed
  */
 function sign($issuer, $subject, $signatureAlgorithm = 'sha1WithRSAEncryption')
 {
     if (!is_object($issuer->privateKey) || empty($issuer->dn)) {
         return false;
     }
     if (isset($subject->publicKey) && !($subjectPublicKey = $subject->_formatSubjectPublicKey())) {
         return false;
     }
     $currentCert = isset($this->currentCert) ? $this->currentCert : null;
     $signatureSubject = isset($this->signatureSubject) ? $this->signatureSubject : null;
     if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertificate'])) {
         $this->currentCert = $subject->currentCert;
         $this->currentCert['tbsCertificate']['signature']['algorithm'] = $signatureAlgorithm;
         $this->currentCert['signatureAlgorithm']['algorithm'] = $signatureAlgorithm;
         if (!empty($this->startDate)) {
             $this->currentCert['tbsCertificate']['validity']['notBefore'] = $this->_timeField($this->startDate);
         }
         if (!empty($this->endDate)) {
             $this->currentCert['tbsCertificate']['validity']['notAfter'] = $this->_timeField($this->endDate);
         }
         if (!empty($this->serialNumber)) {
             $this->currentCert['tbsCertificate']['serialNumber'] = $this->serialNumber;
         }
         if (!empty($subject->dn)) {
             $this->currentCert['tbsCertificate']['subject'] = $subject->dn;
         }
         if (!empty($subject->publicKey)) {
             $this->currentCert['tbsCertificate']['subjectPublicKeyInfo'] = $subjectPublicKey;
         }
         $this->removeExtension('id-ce-authorityKeyIdentifier');
         if (isset($subject->domains)) {
             $this->removeExtension('id-ce-subjectAltName');
         }
     } else {
         if (isset($subject->currentCert) && is_array($subject->currentCert) && isset($subject->currentCert['tbsCertList'])) {
             return false;
         } else {
             if (!isset($subject->publicKey)) {
                 return false;
             }
             $startDate = !empty($this->startDate) ? $this->startDate : @date('D, d M Y H:i:s O');
             $endDate = !empty($this->endDate) ? $this->endDate : @date('D, d M Y H:i:s O', strtotime('+1 year'));
             $serialNumber = !empty($this->serialNumber) ? $this->serialNumber : new BigInteger();
             $this->currentCert = array('tbsCertificate' => array('version' => 'v3', 'serialNumber' => $serialNumber, 'signature' => array('algorithm' => $signatureAlgorithm), 'issuer' => false, 'validity' => array('notBefore' => $this->_timeField($startDate), 'notAfter' => $this->_timeField($endDate)), 'subject' => $subject->dn, 'subjectPublicKeyInfo' => $subjectPublicKey), 'signatureAlgorithm' => array('algorithm' => $signatureAlgorithm), 'signature' => false);
             // Copy extensions from CSR.
             $csrexts = $subject->getAttribute('pkcs-9-at-extensionRequest', 0);
             if (!empty($csrexts)) {
                 $this->currentCert['tbsCertificate']['extensions'] = $csrexts;
             }
         }
     }
     $this->currentCert['tbsCertificate']['issuer'] = $issuer->dn;
     if (isset($issuer->currentKeyIdentifier)) {
         $this->setExtension('id-ce-authorityKeyIdentifier', array('keyIdentifier' => $issuer->currentKeyIdentifier));
         //$extensions = &$this->currentCert['tbsCertificate']['extensions'];
         //if (isset($issuer->serialNumber)) {
         //    $extensions[count($extensions) - 1]['authorityCertSerialNumber'] = $issuer->serialNumber;
         //}
         //unset($extensions);
     }
     if (isset($subject->currentKeyIdentifier)) {
         $this->setExtension('id-ce-subjectKeyIdentifier', $subject->currentKeyIdentifier);
     }
     $altName = array();
     if (isset($subject->domains) && count($subject->domains) > 1) {
         $altName = array_map(array('X509', '_dnsName'), $subject->domains);
     }
     if (isset($subject->ipAddresses) && count($subject->ipAddresses)) {
         // should an IP address appear as the CN if no domain name is specified? idk
         //$ips = count($subject->domains) ? $subject->ipAddresses : array_slice($subject->ipAddresses, 1);
         $ipAddresses = array();
         foreach ($subject->ipAddresses as $ipAddress) {
             $encoded = $subject->_ipAddress($ipAddress);
             if ($encoded !== false) {
                 $ipAddresses[] = $encoded;
             }
         }
         if (count($ipAddresses)) {
             $altName = array_merge($altName, $ipAddresses);
         }
     }
     if (!empty($altName)) {
         $this->setExtension('id-ce-subjectAltName', $altName);
     }
     if ($this->caFlag) {
         $keyUsage = $this->getExtension('id-ce-keyUsage');
         if (!$keyUsage) {
             $keyUsage = array();
         }
         $this->setExtension('id-ce-keyUsage', array_values(array_unique(array_merge($keyUsage, array('cRLSign', 'keyCertSign')))));
         $basicConstraints = $this->getExtension('id-ce-basicConstraints');
         if (!$basicConstraints) {
             $basicConstraints = array();
         }
         $this->setExtension('id-ce-basicConstraints', array_unique(array_merge(array('cA' => true), $basicConstraints)), true);
         if (!isset($subject->currentKeyIdentifier)) {
             $this->setExtension('id-ce-subjectKeyIdentifier', base64_encode($this->computeKeyIdentifier($this->currentCert)), false, false);
         }
     }
     // resync $this->signatureSubject
     // save $tbsCertificate in case there are any ASN1_Element objects in it
     $tbsCertificate = $this->currentCert['tbsCertificate'];
     $this->loadX509($this->saveX509($this->currentCert));
     $result = $this->_sign($issuer->privateKey, $signatureAlgorithm);
     $result['tbsCertificate'] = $tbsCertificate;
     $this->currentCert = $currentCert;
     $this->signatureSubject = $signatureSubject;
     return $result;
 }