function check_certificate_purpose($purpose) { //$this->clear_debug_buffer(); $ok = openssl_x509_checkpurpose($this->certificate_resource, $purpose); //$this->debug("check_certificate_purpose"); return $ok; }
/** * Archive creator for phar, tar, tgz and zip archives. * * @param string path to primary archive * @param string|false stub or false to use default stub of phar archives * @param int one of Phar::TAR, Phar::PHAR, or Phar::ZIP * @param int if the archive can be compressed (phar and tar), one of Phar::GZ, Phar::BZ2 or Phar::NONE * for no compression * @param array an array of arrays containing information on additional archives to create. The indices are: * * 0. extension (tar/tgz/zip) * 1. format (Phar::TAR, Phar::ZIP, Phar::PHAR) * 2. compression (Phar::GZ, Phar::BZ2, Phar::NONE) * @param string PKCS12 certificate to be used to sign the archive. This must be a certificate issued * by a certificate authority, self-signed certs will not be accepted by Pyrus * @param string passphrase, if any, for the PKCS12 certificate. */ function __construct($path, $stub = false, $fileformat = \Phar::TAR, $compression = \Phar::GZ, array $others = null, $releaser = null, \PEAR2\Pyrus\Package $new = null, $pkcs12 = null, $passphrase = '') { if (!class_exists('Phar')) { throw new \PEAR2\Pyrus\Developer\Creator\Exception('Phar extension is not available'); } if (!\Phar::canWrite() || !\Phar::isValidPharFilename($path, true)) { $this->_classname = 'PharData'; } $this->path = $path; $this->compression = $compression; $this->format = $fileformat; $this->others = $others; $this->stub = $stub; if ($pkcs12 && !extension_loaded('openssl')) { throw new \PEAR2\Pyrus\Developer\Creator\Exception('Unable to use ' . 'OpenSSL signing of phars, enable the openssl PHP extension'); } $this->pkcs12 = $pkcs12; $this->passphrase = $passphrase; if (null !== $this->pkcs12) { $cert = array(); $pkcs = openssl_pkcs12_read(file_get_contents($this->pkcs12), $cert, $this->passphrase); if (!$pkcs) { throw new \PEAR2\Pyrus\Developer\Creator\Exception('Unable to process openssl key'); } $private = openssl_pkey_get_private($cert['pkey']); if (!$private) { throw new \PEAR2\Pyrus\Developer\Creator\Exception('Unable to extract private openssl key'); } $pub = openssl_pkey_get_public($cert['cert']); $info = openssl_x509_parse($cert['cert']); $details = openssl_pkey_get_details($pub); if (true !== openssl_x509_checkpurpose($cert['cert'], X509_PURPOSE_SSL_SERVER, \PEAR2\Pyrus\Channel\RemotePackage::authorities())) { throw new \PEAR2\Pyrus\Developer\Creator\Exception('releasing maintainer\'s certificate is invalid'); } // now verify that this cert is in fact the releasing maintainer's certificate // by verifying that alternate name is the releaser's email address if (!isset($info['subject']) || !isset($info['subject']['emailAddress'])) { throw new \PEAR2\Pyrus\Developer\Creator\Exception('releasing maintainer\'s certificate does not contain' . ' an alternate name corresponding to the releaser\'s email address'); } if ($info['subject']['emailAddress'] != $new->maintainer[$releaser]->email) { throw new \PEAR2\Pyrus\Developer\Creator\Exception('releasing maintainer\'s certificate ' . 'alternate name does not match the releaser\'s email address ' . $new->maintainer[$releaser]->email); } $pkey = ''; openssl_pkey_export($private, $pkey); $this->x509cert = $cert['cert']; $this->publickey = $details['key']; $this->privatekey = $pkey; } }
/** * Handles the ValidateCert command * * @param int $commandCode * * @access public * @return boolean */ public function Handle($commandCode) { // Parse input if (!self::$decoder->getElementStartTag(SYNC_VALIDATECERT_VALIDATECERT)) { return false; } $validateCert = new SyncValidateCert(); $validateCert->Decode(self::$decoder); $cert_der = base64_decode($validateCert->certificates[0]); $cert_pem = "-----BEGIN CERTIFICATE-----\n" . chunk_split(base64_encode($cert_der), 64, "\n") . "-----END CERTIFICATE-----\n"; $checkpurpose = defined('CAINFO') && CAINFO ? openssl_x509_checkpurpose($cert_pem, X509_PURPOSE_SMIME_SIGN, array(CAINFO)) : openssl_x509_checkpurpose($cert_pem, X509_PURPOSE_SMIME_SIGN); if ($checkpurpose === true) { $status = SYNC_VALIDATECERTSTATUS_SUCCESS; } else { $status = SYNC_VALIDATECERTSTATUS_CANTVALIDATESIG; } if (!self::$decoder->getElementEndTag()) { return false; } // SYNC_VALIDATECERT_VALIDATECERT self::$encoder->startWBXML(); self::$encoder->startTag(SYNC_VALIDATECERT_VALIDATECERT); self::$encoder->startTag(SYNC_VALIDATECERT_STATUS); self::$encoder->content($status); self::$encoder->endTag(); // SYNC_VALIDATECERT_STATUS self::$encoder->startTag(SYNC_VALIDATECERT_CERTIFICATE); self::$encoder->startTag(SYNC_VALIDATECERT_STATUS); self::$encoder->content($status); self::$encoder->endTag(); // SYNC_VALIDATECERT_STATUS self::$encoder->endTag(); // SYNC_VALIDATECERT_CERTIFICATE self::$encoder->endTag(); // SYNC_VALIDATECERT_VALIDATECERT return true; }
function HandleValidateCert($backend, $devid, $protocolversion) { global $zpushdtd; global $input, $output; $decoder = new WBXMLDecoder($input, $zpushdtd); $encoder = new WBXMLEncoder($output, $zpushdtd); if (!$decoder->getElementStartTag(SYNC_VALIDATECERT_VALIDATECERT)) { return false; } while (($field = $decoder->getElementStartTag(SYNC_VALIDATECERT_CERTIFICATES) ? SYNC_VALIDATECERT_CERTIFICATES : ($decoder->getElementStartTag(SYNC_VALIDATECERT_CERTIFICATECHAIN) ? SYNC_VALIDATECERT_CERTIFICATECHAIN : ($decoder->getElementStartTag(SYNC_VALIDATECERT_CHECKCRL) ? SYNC_VALIDATECERT_CHECKCRL : -1))) != -1) { if ($field == SYNC_VALIDATECERT_CERTIFICATES) { while ($decoder->getElementStartTag(SYNC_VALIDATECERT_CERTIFICATE)) { $certificates[] = $decoder->getElementContent(); if (!$decoder->getElementEndTag()) { return false; } } if (!$decoder->getElementEndTag()) { return false; } } else { if ($field == SYNC_VALIDATECERT_CERTIFICATECHAIN) { while ($decoder->getElementStartTag(SYNC_VALIDATECERT_CERTIFICATE)) { $chain_certificates[] = $decoder->getElementContent(); if (!$decoder->getElementEndTag()) { return false; } } if (!$decoder->getElementEndTag()) { return false; } } else { if ($field == SYNC_VALIDATECERT_CHECKCRL) { $checkcrl = $decoder->getElementContent(); if (!$decoder->getElementEndTag()) { return false; } } } } } if (isset($checkcrl)) { debugLog("validatecert: checkcrl: " . $checkcrl); } if (isset($chain_certificates)) { foreach ($chain_certificates as $certificate) { debugLog("validatecert: certificatechain: " . print_r($certificate, true)); } } foreach ($certificates as $certificate) { $cert_der = base64_decode($certificate); $cert_pem = "-----BEGIN CERTIFICATE-----\n" . chunk_split(base64_encode($cert_der), 64, "\n") . "-----END CERTIFICATE-----\n"; $cert_fn = VERIFYCERT_TEMP . "validatecert" . rand(1000, 99999) . ".pem"; file_put_contents($cert_fn, $cert_pem); $now = time(); if (!($cert_content = openssl_x509_parse($cert_pem))) { $status = 10; } else { if ($cert_content['validFrom_time_t'] >= $now || $cert_content['validTo_time_t'] <= $now) { $status = 7; } else { if (openssl_x509_checkpurpose($cert_pem, X509_PURPOSE_SMIME_SIGN, array(VERIFYCERT_CERTSTORE)) != 1) { $status = 9; } else { if ($checkcrl == 1) { if (isset($cert_content['extensions']['crlDistributionPoints'])) { $crlDistributionPoints = explode("\n", str_replace("\r", '', $cert_content['extensions']['crlDistributionPoints'])); foreach ($crlDistributionPoints as $entry) { $line = explode("URI:", $entry); if (isset($line[1]) && substr($line[1], 0, 5) == "http:") { $crl_urls[] = $line[1]; } } } if (isset($cert_content['extensions']['authorityInfoAccess'])) { $authorityInfoAccess = explode("\n", str_replace("\r", '', $cert_content['extensions']['authorityInfoAccess'])); foreach ($authorityInfoAccess as $entry) { $line = explode(" - URI:", $entry); if (strtolower(trim($line[0])) == 'ocsp') { $ocsp_urls[] = $line[1]; } if (strtolower(trim($line[0])) == 'ca issuers') { $ca_issuers[] = $line[1]; } } } $result = preg_split('/[\\r\\n]/', shell_exec(VERIFYCERT_SSLBIN . " x509 -in " . $cert_fn . " -issuer_hash -noout")); $issuer_cer_name = $result[0] . '.0'; $issuer_crl_name = $result[0] . '.r0'; if (!file_exists(VERIFYCERT_CERTSTORE . $issuer_cer_name)) { if (isset($ca_issuers)) { foreach ($ca_issuers as $ca_issuer) { $ca_cert = file_get_contents($ca_issuer); if (strpos($ca_cert, '----BEGIN CERTIFICATE-----') == false) { $ca_cert = der2pem($ca_cert); } if (!openssl_x509_parse($ca_cert)) { $status = 5; } else { file_put_contents(VERIFYCERT_CERTSTORE . $issuer_cer_name, $ca_cert); } } } else { $status = 4; } } if (isset($ocsp_urls)) { $command = VERIFYCERT_SSLBIN . " ocsp -VAfile " . VERIFYCERT_CERTSTORE . $issuer_cer_name . " -issuer " . VERIFYCERT_CERTSTORE . $issuer_cer_name . " -CApath " . VERIFYCERT_CERTSTORE . " -no_nonce -cert " . $cert_fn . " -url " . $ocsp_urls[0]; $result = preg_split('/[\\r\\n]/', shell_exec($command)); $status = 14; foreach ($result as $line) { $values = explode(":", $line); if (trim($values[0]) == $cert_fn) { switch (strtolower(trim($values[1]))) { case 'good': $status = 1; break; default: $status = 13; } } } } else { if (isset($crl_urls)) { echo "Verfication using crl!<br>\n"; $nextupdate = time() - 1; if (file_exists(VERIFYCERT_CERTSTORE . $issuer_crl_name)) { $command = VERIFYCERT_SSLBIN . " crl -in " . VERIFYCERT_CERTSTORE . $issuer_crl_name . " -nextupdate -noout"; $result = preg_split('/[\\r\\n]/', shell_exec($command)); foreach ($result as $line) { $values = explode("=", $line); if (strtolower(trim($values[0])) == 'nextupdate') { $nextupdate = strtotime($values[1]); } } } if (!file_exists(VERIFYCERT_CERTSTORE . $issuer_crl_name) || $nextupdate < time()) { if ($nextupdate < time()) { echo "CRL File needs update!\n"; } foreach ($crl_urls as $crl_url) { if ($crl_cert = file_get_contents($crl_url)) { if (strstr($crl_cert, '----BEGIN X509 CRL-----') == false) { file_put_contents(VERIFYCERT_TEMP . $issuer_crl_name, $crl_cert); $command = VERIFYCERT_SSLBIN . " crl -in " . VERIFYCERT_TEMP . $issuer_crl_name . " -inform der -out " . VERIFYCERT_CERTSTORE . $issuer_crl_name . " -outform pem"; $result = preg_split('/[\\r\\n]/', shell_exec($command)); foreach ($result as $line) { echo $line . "\n"; } } else { file_put_contents(VERIFYCERT_CERTSTORE . $issuer_crl_name, $crl_cert); } } else { $status = 14; } } } if (file_exists(VERIFYCERT_CERTSTORE . $issuer_crl_name)) { $command = VERIFYCERT_SSLBIN . " verify -verbose -CApath " . VERIFYCERT_CERTSTORE . " -crl_check " . $cert_fn; $result = preg_split('/[\\r\\n]/', shell_exec($command)); foreach ($result as $line) { $values = explode(":", $line); if (trim($values[0]) == $cert_fn) { switch (strtolower(trim($values[1]))) { case 'ok': $status = 1; break; default: $status = 13; } } } } else { $status = 16; } } else { $status = 16; } } } else { $status = 1; } } } } unlink($cert_fn); } $encoder->startWBXML(); $encoder->startTag(SYNC_VALIDATECERT_VALIDATECERT); $encoder->startTag(SYNC_VALIDATECERT_STATUS); $encoder->content(1); $encoder->endTag(); // end SYNC_VALIDATECERT_STATUS $encoder->startTag(SYNC_VALIDATECERT_CERTIFICATE); $encoder->startTag(SYNC_VALIDATECERT_STATUS); $encoder->content($status); $encoder->endTag(); // end SYNC_VALIDATECERT_STATUS $encoder->endTag(); // end SYNC_VALIDATECERT_CERTIFICATE $encoder->endTag(); // end SYNC_VALIDATECERT_VALIDATECERT return true; }
/** * Automatic authentication: checks if the username is set in the * configured header. * * @return boolean Whether or not the client is allowed. */ public function transparent() { if (!is_callable('openssl_x509_parse')) { throw new Horde_Auth_Exception('SSL not enabled on server.'); } if (empty($_SERVER[$this->_params['username_field']]) || empty($_SERVER[$this->_params['certificate_field']])) { return false; } // Valid for client auth? $cert = openssl_x509_read($_SERVER[$this->_params['certificate_field']]); if (!$this->_params['ignore_purpose'] && !openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_CLIENT) && !openssl_x509_checkpurpose($cert, X509_PURPOSE_ANY)) { return false; } $c_parsed = openssl_x509_parse($cert); foreach ($this->_params['filter'] as $key => $value) { $keys = explode(':', $key); $c = $c_parsed; foreach ($keys as $k) { $c = $c[$k]; } if ($c != $value) { return false; } } // Handle any custom validation added by sub classes. if (!$this->_validate($cert)) { return false; } // Free resources. openssl_x509_free($cert); // Set credentials $this->setCredential('userId', $_SERVER[$this->_params['username_field']]); $cred = array('certificate_id' => $c_parsed['hash']); if (!empty($this->_params['password'])) { $cred['password'] = $this->_params['password']; } $this->setCredential('credentials', $cred); return true; }
/** * Adds a server ssl certificate for specific domain using the sni feature * * @param string $domain The domain for the certificate to use * @param string $certPath The path to the bundled certificate file * @param bool $overwrite If an existing domain entry should be overwritten or not * * @return bool true on success or false on failure */ public function addSniServerCert($domain, $certPath, $overwrite = true) { // get existing server certs $sniServerCerts = $this->getOption('ssl', 'SNI_server_certs'); // check if sni server certs are set already or new should be started if (!is_array($sniServerCerts)) { $sniServerCerts = array(); } // check if domain key exists and no overwrite is wanted if (isset($sniServerCerts[$domain]) && $overwrite === false) { return false; } // check if cert exists if (!is_file($certPath)) { throw new ServerException(sprintf("SSL certificate '%s' does not exist for domain '%s'.", $certPath, $domain)); } // check if cert is valid for server usage $x509_res = openssl_x509_read(file_get_contents($certPath)); $valid = openssl_x509_checkpurpose($x509_res, X509_PURPOSE_SSL_SERVER, array($certPath)); if ($valid === true) { // if its valid, add it to sni server certs $sniServerCerts[$domain] = $certPath; } else { throw new ServerException(sprintf("SSL certificate '%s' is not valid for domain '%s'.", $certPath, $domain)); } // add it to array $sniServerCerts[$domain] = $certPath; // add sni server certs array back to stream context resource instance return $this->setOption('ssl', 'SNI_server_certs', $sniServerCerts); }
/** * Add or update an SSL certificate * * @throws iMSCP_Exception * @throws iMSCP_Exception_Database * @param int $domainId domain unique identifier * @param string $domainType Domain type (dmn|als|sub|alssub) * @return void */ function client_addSslCert($domainId, $domainType) { $config = iMSCP_Registry::get('config'); $domainName = _client_getDomainName($domainId, $domainType); $selfSigned = isset($_POST['selfsigned']); if ($domainName === false) { showBadRequestErrorPage(); } if ($selfSigned && !client_generateSelfSignedCert($domainName)) { set_page_message(tr('Could not generate SSL certificate. An unexpected error occurred.'), 'error'); return; } if (!isset($_POST['passphrase']) || !isset($_POST['private_key']) || !isset($_POST['certificate']) || !isset($_POST['ca_bundle']) || !isset($_POST['cert_id'])) { showBadRequestErrorPage(); } $passPhrase = clean_input($_POST['passphrase']); $privateKey = clean_input($_POST['private_key']); $certificate = clean_input($_POST['certificate']); $caBundle = clean_input($_POST['ca_bundle']); $certId = intval($_POST['cert_id']); if (!$selfSigned) { // Validate SSL certificate (private key, SSL certificate and certificate chain) $privateKey = @openssl_pkey_get_private($privateKey, $passPhrase); if (!is_resource($privateKey)) { set_page_message(tr('Invalid private key or passphrase.'), 'error'); return; } $certificateStr = $certificate; $certificate = @openssl_x509_read($certificate); if (!is_resource($certificate)) { set_page_message(tr('Invalid SSL certificate.'), 'error'); return; } if (!@openssl_x509_check_private_key($certificate, $privateKey)) { set_page_message(tr("The private key doesn't belong to the provided SSL certificate."), 'error'); return; } if (!($tmpfname = @tempnam(sys_get_temp_dir(), intval($_SESSION['user_id']) . 'ssl-ca'))) { write_log('Could not create temporary file for CA bundle..', E_USER_ERROR); set_page_message(tr('Could not add/update SSL certificate. An unexpected error occurred.'), 'error'); return; } register_shutdown_function(function ($file) { @unlink($file); }, $tmpfname); if ($caBundle !== '') { if (!@file_put_contents($tmpfname, $caBundle)) { write_log('Could not export customer CA bundle in temporary file.', E_USER_ERROR); set_page_message(tr('Could not add/update SSL certificate. An unexpected error occurred.'), 'error'); return; } // Note: Here we also add the CA bundle in the trusted chain to support self-signed certificates if (@openssl_x509_checkpurpose($certificate, X509_PURPOSE_SSL_SERVER, array($config['DISTRO_CA_BUNDLE'], $tmpfname), $tmpfname)) { set_page_message(tr('At least one intermediate certificate is invalid or missing.'), 'error'); return; } } else { @file_put_contents($tmpfname, $certificateStr); // Note: Here we also add the certificate in the trusted chain to support self-signed certificates if (!@openssl_x509_checkpurpose($certificate, X509_PURPOSE_SSL_SERVER, array($config['DISTRO_CA_BUNDLE'], $tmpfname))) { set_page_message(tr('At least one intermediate certificate is invalid or missing.'), 'error'); return; } } } // Preparing data for insertion in database if (!$selfSigned) { if (!@openssl_pkey_export($privateKey, $privateKeyStr)) { write_log('Could not export private key.', E_USER_ERROR); set_page_message(tr('Could not add/update SSL certificate. An unexpected error occurred.'), 'error'); return; } @openssl_pkey_free($privateKey); if (!@openssl_x509_export($certificate, $certificateStr)) { write_log('Could not export SSL certificate.', E_USER_ERROR); set_page_message(tr('Could not add/update SSL certificate. An unexpected error occurred.'), 'error'); return; } @openssl_x509_free($certificate); $caBundleStr = str_replace("\r\n", "\n", $caBundle); } else { $privateKeyStr = $privateKey; $certificateStr = $certificate; $caBundleStr = $caBundle; } $db = iMSCP_Database::getInstance(); try { $db->beginTransaction(); if ($certId == 0) { // Add new certificate exec_query(' INSERT INTO ssl_certs ( domain_id, domain_type, private_key, certificate, ca_bundle, status ) VALUES ( ?, ?, ?, ?, ?, ? ) ', array($domainId, $domainType, $privateKeyStr, $certificateStr, $caBundleStr, 'toadd')); } else { // Update existing certificate exec_query(' UPDATE ssl_certs SET private_key = ?, certificate = ?, ca_bundle = ?, status = ? WHERE cert_id = ? AND domain_id = ? AND domain_type = ? ', array($privateKeyStr, $certificateStr, $caBundleStr, 'tochange', $certId, $domainId, $domainType)); } _client_updateDomainStatus($domainType, $domainId); $db->commit(); send_request(); if (!$certId) { set_page_message(tr('SSL certificate successfully scheduled for addition.'), 'success'); write_log(sprintf('%s added a new SSL certificate for the %s domain', decode_idna($_SESSION['user_logged']), decode_idna($domainName)), E_USER_NOTICE); } else { set_page_message(tr('SSL certificate successfully scheduled for update.'), 'success'); write_log(sprintf('%s updated an SSL certificate for the %s domain', decode_idna($_SESSION['user_logged']), $domainName), E_USER_NOTICE); } redirectTo("cert_view.php?domain_id={$domainId}&domain_type={$domainType}"); } catch (iMSCP_Exception_Database $e) { $db->rollBack(); write_log('Unable to add/update SSL certificate in database', E_USER_ERROR); set_page_message('An unexpected error occurred. Please contact your reseller.'); } }
/** * __checkSignatureAndGetSigner - Checks the signature and extracts the signer certificate and it's serialnumber * #params string Base64 encoded signature * #params string verification of the message that should have been signed * #params string location of Certificate Authority file that should be used during verificaton * @return boolean */ private function __checkSignatureAndGetSigner($signature, $message, $cafile) { assert('is_string($signature)'); assert('is_string($message)'); assert('is_string($cafile)'); /* Check for provided file existence */ if (!file_exists($cafile)) { trigger_error('mobileid::__checkSignatureAndGetSigner: file not found ' . $cafile, E_USER_WARNING); } /* Define temporary files */ $tmpfile = tempnam(sys_get_temp_dir(), '_mid_'); $file_sig = $tmpfile . '.sig'; $file_sig_cert = $tmpfile . '.crt'; $file_sig_msg = $tmpfile . '.msg'; /* Chunk spliting the signature */ $signature = chunk_split($signature, 64, "\n"); /* This because the openssl_pkcs7_verify() function needs some mime headers to make it work */ $signature = "MIME-Version: 1.0\nContent-Disposition: attachment;\n filename=\"dummy.p7m\"\nContent-Type: application/x-pkcs7-mime;\n name=\"dummy.p7m\"\nContent-Transfer-Encoding: base64\n\n" . $signature; /* Write the signature into temp files */ file_put_contents($file_sig, $signature); /* Signature checks must explicitly succeed */ $ok = false; /* Get the signer certificate */ $status = openssl_pkcs7_verify($file_sig, PKCS7_NOVERIFY, $file_sig_cert); if ($status == true && file_exists($file_sig_cert)) { /* Get the signer certificate and details */ $this->mid_certificate = file_get_contents($file_sig_cert); $certificate = openssl_x509_parse($this->mid_certificate); $this->mid_serialnumber = $certificate['subject']['serialNumber']; /* Verify message has been signed */ $data = ''; $status = openssl_pkcs7_verify($file_sig, PKCS7_NOVERIFY, $file_sig_cert, array($cafile), $file_sig_cert, $file_sig_msg); if (file_exists($file_sig_msg)) { $data = file_get_contents($file_sig_msg); if ($data === $message) { $ok = true; } } else { trigger_error('mobileid::__checkSignatureAndGetSigner: signed message ' . openssl_error_string(), E_USER_NOTICE); } /* Verify signer issued by trusted CA */ $status = openssl_x509_checkpurpose($this->mid_certificate, X509_PURPOSE_SSL_CLIENT, array($cafile)); if ($status != true) { $ok = false; trigger_error('mobileid::__checkSignatureAndGetSigner: certificate check ' . openssl_error_string(), E_USER_NOTICE); } } else { trigger_error('mobileid::__checkSignatureAndGetSigner: signer certificate ' . openssl_error_string(), E_USER_NOTICE); } /* Cleanup of temporary files */ if (file_exists($tmpfile)) { unlink($tmpfile); } if (file_exists($file_sig)) { unlink($file_sig); } if (file_exists($file_sig_cert)) { unlink($file_sig_cert); } if (file_exists($file_sig_msg)) { unlink($file_sig_msg); } /* Signature checks failed? */ if (!$ok) { $this->statuscode = '503'; $this->statusmessage = 'INVALID_SIGNATURE'; } return $ok; }
/** * Checks the purpose of this certificate. If using PURPOSE_ANY, make sure openssl is on the PATH. * A bug in PHP prevents the certificate from being checked via the api for that specific purpose. * @param int $purpose The purpose to check the certificate for. * @param array $caInfo List of files and directories that contain root certificates. * @return boolean */ public function checkPurpose($purpose, array $caInfo) { if ($purpose == self::PURPOSE_ANY) { $caPathDirsArray = array(); $caPathFilesArray = array(); foreach ($caInfo as $caPath) { if (is_dir($caPath)) { $caPathDirsArray[] = $caPath; } else { $caPathFilesArray[] = $caPath; } } $caPathDirs = implode(PATH_SEPARATOR, $caPathDirsArray); if (!empty($caPathDirs)) { $caPathDirs = " -CApath {$caPathDirs}"; } $caPathFiles = implode(PATH_SEPARATOR, $caPathFilesArray); if (!empty($caPathFiles)) { $caPathFiles = " -CAfile {$caPathFiles}"; } $tempCrt = tempnam(sys_get_temp_dir(), 'crt'); file_put_contents($tempCrt, $this->clearText); exec("openssl verify{$caPathDirs}{$caPathFiles} -purpose any {$tempCrt}", $output); unlink($tempCrt); // return code of openssl is always 0, so we need to check the actual output return $output[0] == "{$tempCrt}: OK"; } return openssl_x509_checkpurpose($this->certResource, $purpose, $caInfo); }
function download() { $url = $this->getDownloadURL(); $errs = new \PEAR2\MultiErrors(); $certdownloaded = false; if (extension_loaded('openssl')) { // try to download openssl x509 signature certificate for our release try { $cert = \PEAR2\Pyrus\Main::download($url . '.pem'); $cert = $cert->body; $certdownloaded = true; } catch (\PEAR2\Pyrus\HTTPException $e) { // file does not exist, ignore } if ($certdownloaded) { $info = openssl_x509_parse($cert); if (!$info) { throw new \PEAR2\Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate is not a certificate'); } if (true !== openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER, self::authorities())) { throw new \PEAR2\Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate is invalid'); } // now verify that this cert is in fact the releasing maintainer's certificate // by verifying that alternate name is the releaser's email address if (!isset($info['subject']) || !isset($info['subject']['emailAddress'])) { throw new \PEAR2\Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate does not contain' . ' an alternate name corresponding to the releaser\'s email address'); } // retrieve releaser's email address if ($info['subject']['emailAddress'] != $this->maintainer[$this->remoteAbridgedInfo['m']]->email) { throw new \PEAR2\Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate ' . 'alternate name does not match the releaser\'s email address ' . $this->maintainer[$this->remoteAbridgedInfo['m']]->email); } $key = openssl_pkey_get_public($cert); $key = openssl_pkey_get_details($key); $key = $key['key']; } } // first try to download .phar, then .tgz, then .tar, then .zip // if a public key was downloaded, save it where ext/phar will // look to validate the openssl signature foreach (array('.phar', '.tgz', '.tar') as $ext) { try { if ($certdownloaded) { if (!file_exists(Config::current()->download_dir)) { mkdir(Config::current()->download_dir, 0755, true); } file_put_contents($pubkey = Config::current()->download_dir . DIRECTORY_SEPARATOR . basename($url) . $ext . '.pubkey', $key); } $ret = new \PEAR2\Pyrus\Package\Remote($url . $ext); if ($certdownloaded) { if ($ext == '.tar' || $ext == '.tgz') { if (phpversion() == '5.3.0') { Logger::log(0, 'WARNING: ' . $url . $ext . ' may not be installable ' . 'with PHP version 5.3.0, the PHP extension phar ' . 'has a bug verifying openssl signatures for ' . 'tar and tgz files. Either upgrade to PHP 5.3.1 ' . 'or install the .zip version'); } } } return $ret; } catch (\PEAR2\Pyrus\HTTPException $e) { if ($certdownloaded && file_exists($pubkey)) { unlink($pubkey); } $errs->E_ERROR[] = $e; } catch (\Exception $e) { if ($certdownloaded && file_exists($pubkey)) { unlink($pubkey); } $errs->E_ERROR[] = $e; throw new \PEAR2\Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name, $errs); } } try { // phar does not support signatures for zip archives $ret = new \PEAR2\Pyrus\Package\Remote($url . '.zip'); return $ret; } catch (\PEAR2\Pyrus\HTTPException $e) { $errs->E_ERROR[] = $e; throw new \PEAR2\Pyrus\Package\Exception('Could not download abstract package ' . $this->channel . '/' . $this->name, $errs); } catch (\Exception $e) { $errs->E_ERROR[] = $e; throw new \PEAR2\Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name, $errs); } }
/** * @param int $purpose X509_PURPOSE_* * @param array $cainfo * @param string $untrusted * * @return bool */ public function checkPurpose(int $purpose, array $cainfo = [], string $untrusted = NULL) : bool { if ($untrusted === NULL) { $status = openssl_x509_checkpurpose($this->getHandle(), $purpose, $cainfo); } else { $status = openssl_x509_checkpurpose($this->getHandle(), $purpose, $cainfo, $untrusted); } if (!is_bool($status)) { throw new RuntimeException('Failed to check purpose'); } return $status; }
/** * Validate a certificate against a CA file, by using the builtin * openssl_x509_checkpurpose function * * @param string $certificate The certificate, in PEM format. * @param string $caFile File with trusted certificates, in PEM-format. * @return boolean|string TRUE on success, or a string with error messages if it failed. * @deprecated */ private static function validateCABuiltIn($certificate, $caFile) { assert('is_string($certificate)'); assert('is_string($caFile)'); /* Clear openssl errors. */ while (openssl_error_string() !== FALSE) { } $res = openssl_x509_checkpurpose($certificate, X509_PURPOSE_ANY, array($caFile)); $errors = ''; /* Log errors. */ while (($error = openssl_error_string()) !== FALSE) { $errors .= ' [' . $error . ']'; } if ($res !== TRUE) { return $errors; } return TRUE; }
/** * @param string $certificate * @return boolean */ private function checkAttest($certificate) { if (!$this->config->getAttestDir()) { return TRUE; } // @todo Original purpose is -1 which is undocumented. Is ANY ok to use here? // https://github.com/Yubico/php-u2flib-server/blob/cd49f97017c8415be3e190397565719b5319d2d6/src/u2flib_server/U2F.php#L192 return openssl_x509_checkpurpose($certificate, X509_PURPOSE_ANY, array_map(function ($file) { return $file->getPathName(); }, iterator_to_array(Finder::findFiles('*.pem')->from($this->config->getAttestDir()), FALSE))) === TRUE; }
function test_openssl_x509_checkpurpose() { $fcert = file_get_contents(__DIR__ . "/test_x509.crt"); $cert = openssl_x509_read($fcert); VS(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_CLIENT), 0); VS(openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER), 0); }
function validate_chain($certs) { // Since we may have multiple certs in the XML, save the chain to a temp file // so we an pass as a list of untrusted certs to verify. $cert = array_shift($certs); $untrusted_file = $this->save_cert_chain($certs); $trusted = openssl_x509_checkpurpose($cert, X509_PURPOSE_ANY, $this->trust_roots, $untrusted_file); unlink($untrusted_file); return $trusted > 0; }
/** * Handle request * * @return boolean * @throws Horde_ActiveSync_Exception */ protected function _handle() { $this->_logger->info(sprintf('[%s] Handling ValidateCertificate command.', $this->_device->id)); if (!$this->_decoder->getElementStartTag(self::VALIDATECERT_VALIDATECERT)) { throw new Horde_ActiveSync_Exception('Protocol Error'); } $certificates = array(); $chain_certificates = array(); while (($field = $this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATES) ? self::VALIDATECERT_CERTIFICATES : ($this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATECHAIN) ? self::VALIDATECERT_CERTIFICATECHAIN : ($this->_decoder->getElementStartTag(self::VALIDATECERT_CHECKCRL) ? self::VALIDATECERT_CHECKCRL : -1))) != -1) { if ($field == self::VALIDATECERT_CERTIFICATES) { while ($this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATE)) { $certificates[] = $this->_decoder->getElementContent(); $this->_logger->info('VALIDATE CERT: ' . $certificates[count($certificates) - 1]); if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } } if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } } elseif ($field == self::VALIDATECERT_CERTIFICATECHAIN) { while ($this->_decoder->getElementStartTag(self::VALIDATECERT_CERTIFICATE)) { $chain_certificates[] = $this->_decoder->getElementContent(); $this->_logger->info('CHAIN CERT: ' . $chain_certificates[count($chain_certificates) - 1]); if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } } if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } } elseif ($field == self::VALIDATECERT_CHECKCRL) { $checkcrl = $this->_decoder->getElementContent(); if (!$this->_decoder->getElementEndTag()) { throw new Horde_ActiveSync_Exception('Protocol Error'); } } } $cert_status = array(); foreach ($certificates as $key => $certificate) { $cert_der = base64_decode($certificate); $cert_pem = "-----BEGIN CERTIFICATE-----\n" . chunk_split(base64_encode($cert_der), 64, "\n") . "-----END CERTIFICATE-----\n"; // Parsable? if (!($parsed = openssl_x509_parse($cert_pem, false))) { $cert_status[$key] = self::STATUS_MISSING_INFO; continue; } // Valid times? $now = time(); if ($parsed['validFrom_time_t'] >= $now || $parsed['validTo_time_t'] <= $now) { $cert_status[$key] = self::STATUS_EXPIRED; continue; } // Valid purpose/trusted? // @TODO: CRL support, CHAIN support $result = openssl_x509_checkpurpose($cert_pem, X509_PURPOSE_SMIME_SIGN, array($this->_activeSync->certPath)); if ($result === false) { // @TODO: // checkpurpose returns false if either the purpose is invalid OR // the certificate is untrusted, so we should validate the // trust before we send back any errors. $cert_status[$key] = self::STATUS_PURPOSE_INVALID; } elseif ($results == -1) { // Unspecified error. $cert_status[$key] = self::STATUS_UNKNOWN; } else { // If checkpurpose passes, it's valid AND trusted. $cert_status[$key] = self::STATUS_SUCCESS; } } $this->_encoder->startWBXML(); $this->_encoder->startTag(self::VALIDATECERT_VALIDATECERT); $this->_encoder->startTag(self::VALIDATECERT_STATUS); $this->_encoder->content(1); $this->_encoder->endTag(); foreach ($certificates as $key => $certificate) { $this->_encoder->startTag(self::VALIDATECERT_CERTIFICATE); $this->_encoder->startTag(self::VALIDATECERT_STATUS); $this->_encoder->content($cert_status[$key]); $this->_encoder->endTag(); $this->_encoder->endTag(); } $this->_encoder->endTag(); return true; }
/** * Called to verify and unpack a registration message. * @param RegisterRequest $request this is a reply to * @param object $response response from a user * @param bool $includeCert set to true if the attestation certificate should be * included in the returned Registration object * @return Registration * @throws Error */ public function doRegister($request, $response, $includeCert = true) { if (!is_object($request)) { throw new \InvalidArgumentException('$request of doRegister() method only accepts object.'); } if (!is_object($response)) { throw new \InvalidArgumentException('$response of doRegister() method only accepts object.'); } if (property_exists($response, 'errorCode')) { throw new Error('User-agent returned error. Error code: ' . $response->errorCode, ERR_BAD_UA_RETURNING); } if (!is_bool($includeCert)) { throw new \InvalidArgumentException('$include_cert of doRegister() method only accepts boolean.'); } $rawReg = $this->base64u_decode($response->registrationData); $regData = array_values(unpack('C*', $rawReg)); $clientData = $this->base64u_decode($response->clientData); $cli = json_decode($clientData); if ($cli->challenge !== $request->challenge) { throw new Error('Registration challenge does not match', ERR_UNMATCHED_CHALLENGE); } $registration = new Registration(); $offs = 1; $pubKey = substr($rawReg, $offs, PUBKEY_LEN); $offs += PUBKEY_LEN; // decode the pubKey to make sure it's good $tmpKey = $this->pubkey_to_pem($pubKey); if ($tmpKey === null) { throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE); } $registration->publicKey = base64_encode($pubKey); $khLen = $regData[$offs++]; $kh = substr($rawReg, $offs, $khLen); $offs += $khLen; $registration->keyHandle = $this->base64u_encode($kh); // length of certificate is stored in byte 3 and 4 (excluding the first 4 bytes) $certLen = 4; $certLen += $regData[$offs + 2] << 8; $certLen += $regData[$offs + 3]; $rawCert = $this->fixSignatureUnusedBits(substr($rawReg, $offs, $certLen)); $offs += $certLen; $pemCert = "-----BEGIN CERTIFICATE-----\r\n"; $pemCert .= chunk_split(base64_encode($rawCert), 64); $pemCert .= "-----END CERTIFICATE-----"; if ($includeCert) { $registration->certificate = base64_encode($rawCert); } if ($this->attestDir) { if (openssl_x509_checkpurpose($pemCert, -1, $this->get_certs()) !== true) { throw new Error('Attestation certificate can not be validated', ERR_ATTESTATION_VERIFICATION); } } if (!openssl_pkey_get_public($pemCert)) { throw new Error('Decoding of public key failed', ERR_PUBKEY_DECODE); } $signature = substr($rawReg, $offs); $dataToVerify = chr(0); $dataToVerify .= hash('sha256', $request->appId, true); $dataToVerify .= hash('sha256', $clientData, true); $dataToVerify .= $kh; $dataToVerify .= $pubKey; if (openssl_verify($dataToVerify, $signature, $pemCert, 'sha256') === 1) { return $registration; } else { throw new Error('Attestation signature does not match', ERR_ATTESTATION_SIGNATURE); } }
function matches() { // Des vérifications supplémentaires pourraient être intéressantes (FORWARDED FOR, etc). if ($_SERVER) { if ($_SERVER['REMOTE_ADDR'] == $this->proxy) { if ($_SERVER['HTTP_SSL_CLIENT_CERT']) { $cert = "-----BEGIN CERTIFICATE-----\n"; $tmp = str_replace("-----BEGIN CERTIFICATE----- ", "", $_SERVER['HTTP_SSL_CLIENT_CERT']); $tmp = str_replace("-----END CERTIFICATE-----", "", $tmp); $cert .= str_replace(" ", "\n", $tmp); $cert .= "-----END CERTIFICATE----- "; $cainfo = array(); $cainfo[] = '/etc/apache2/ssl/cacert.pem'; // FIXME param $this->ssl = openssl_x509_parse($cert); if (openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_CLIENT, $cainfo)) { return 1; } } } } return 0; }
function download() { $url = $this->getDownloadURL(); $errs = new \PEAR2\MultiErrors(); $certdownloaded = false; if (extension_loaded('openssl')) { // try to download openssl x509 signature certificate for our release try { $cert = \Pyrus\Main::download($url . '.pem'); // ensure this is supposed to be a valid certificate $contentType = $cert->headers['content-type']; if (null !== $contentType) { // ignore parameters during comparison. $contentType = (string) substr($contentType, 0, strcspn($contentType, ';')); if (!strcasecmp($contentType, 'application/x-x509-ca-cert')) { $cert = $cert->body; $certdownloaded = true; } } } catch (\Pyrus\HTTPException $e) { // file does not exist, ignore } if ($certdownloaded) { $info = openssl_x509_parse($cert); if (!$info) { throw new \Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate is not a certificate'); } if (true !== openssl_x509_checkpurpose($cert, X509_PURPOSE_SSL_SERVER, self::authorities())) { throw new \Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate is invalid'); } // now verify that this cert is in fact the releasing maintainer's certificate // by verifying that alternate name is the releaser's email address if (!isset($info['subject']) || !isset($info['subject']['emailAddress'])) { throw new \Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate does not contain' . ' an alternate name corresponding to the releaser\'s email address'); } // retrieve releaser's email address if ($info['subject']['emailAddress'] != $this->maintainer[$this->remoteAbridgedInfo['m']]->email) { throw new \Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name . ' - releasing maintainer\'s certificate ' . 'alternate name does not match the releaser\'s email address ' . $this->maintainer[$this->remoteAbridgedInfo['m']]->email); } $key = openssl_pkey_get_public($cert); $key = openssl_pkey_get_details($key); $key = $key['key']; } } // first try to download .phar, then .tgz, then .tar, then .zip // if a public key was downloaded, save it where ext/phar will // look to validate the openssl signature foreach (array('.phar', '.tgz', '.tar') as $ext) { try { if ($certdownloaded) { if (!file_exists(Config::current()->download_dir)) { mkdir(Config::current()->download_dir, 0755, true); } file_put_contents($pubkey = Config::current()->download_dir . DIRECTORY_SEPARATOR . basename($url) . $ext . '.pubkey', $key); } $ret = new \Pyrus\Package\Remote($url . $ext); return $ret; } catch (\Exception $e) { if ($certdownloaded && file_exists($pubkey)) { unlink($pubkey); } $errs->E_ERROR[] = $e; } } try { // phar does not support signatures for zip archives $ret = new \Pyrus\Package\Remote($url . '.zip'); return $ret; } catch (\Pyrus\HTTPException $e) { $errs->E_ERROR[] = $e; throw new \Pyrus\Package\Exception('Could not download abstract package ' . $this->channel . '/' . $this->name, $errs); } catch (\Exception $e) { $errs->E_ERROR[] = $e; throw new \Pyrus\Package\Exception('Invalid abstract package ' . $this->channel . '/' . $this->name, $errs); } }
function valida_ca($pubkeyid) { $ca = array(__DIR__ . "/raiz/"); $ok = openssl_x509_checkpurpose($pubkeyid, X509_PURPOSE_ANY, $ca); if ($ok) { echo "<h3>Certificado emitido por el SAT</h3>"; } else { echo "<h3>Certificado apocrifo, No es del SAT</h3>"; } }
function check_cert() { global $file_x509, $file_pkcs12, $file_ca_x509; global $pass; $pkcs12 = file_get_contents($file_pkcs12); $x509 = file_get_contents($file_x509); // 可以检查证书有效期 // 有效期和系统时间有关(date) if ($ret = openssl_x509_checkpurpose($x509, X509_PURPOSE_ANY, [$file_ca_x509])) { echo "+Ok, check public key succ!\n"; } else { if (false === $ret) { echo "-Err, public key cannot be used!(" . __LINE__ . ")\n"; exit(1); } elseif (-1 === $ret) { echo "-Err, check public key on error!(" . __LINE__ . ")\n"; exit(1); } } openssl_pkcs12_read($pkcs12, $certs, $pass); if (openssl_x509_check_private_key($x509, $certs['pkey'])) { echo "+Ok, match public key with private key succ!\n"; } else { echo "-Err, match public key with private key fail!(" . __LINE__ . ")\n"; exit(1); } }
function check_cert($cert) { // 只能是文件路径,可以是多个 x509 证书 // 不能是 pem 格式字符串和 OpenSSL X.509 资源 $cainfo = __DIR__ . '/ca/ca_cert.cer'; $purpose = [X509_PURPOSE_SSL_CLIENT, X509_PURPOSE_SSL_SERVER, X509_PURPOSE_NS_SSL_SERVER, X509_PURPOSE_SMIME_SIGN, X509_PURPOSE_SMIME_ENCRYPT, X509_PURPOSE_CRL_SIGN, X509_PURPOSE_ANY]; foreach ($purpose as $p) { var_dump(openssl_x509_checkpurpose($cert, $p, [$cainfo])); } }