/** * Generate a Horde_Mime_Part object that contains a public key (RFC * 3156 [7]). * * @param mixed $key The public key. * * @return Horde_Mime_Part An object that contains the public key. */ public function publicKeyPart($key) { $key = Horde_Pgp_Element_PublicKey::create($key); $part = new Horde_Mime_Part(); $part->setType('application/pgp-keys'); $part->setHeaderCharset('UTF-8'); $part->setDescription(Horde_Crypt_Translation::t("PGP Public Key")); $part->setContents(strval($key), array('encoding' => '7bit')); return $part; }
/** * Returns the first matching key ID for an email address from a public * keyserver. * * @param string $address The email address of the PGP key. * * @return string The PGP key ID. * @throws Horde_Crypt_Exception */ public function getKeyId($address) { $pubkey = null; /* Connect to the public keyserver. */ $url = $this->_createUrl('/pks/lookup', array('op' => 'index', 'options' => 'mr', 'search' => $address)); try { $output = $this->_http->get($url)->getBody(); } catch (Horde_Http_Exception $e) { throw new Horde_Crypt_Exception($e); } if (strpos($output, '-----BEGIN PGP PUBLIC KEY BLOCK') !== false) { $pubkey = $output; } elseif (strpos($output, 'pub:') !== false) { $output = explode("\n", $output); $keyids = $keyuids = array(); $curid = null; foreach ($output as $line) { if (substr($line, 0, 4) == 'pub:') { $line = explode(':', $line); /* Ignore invalid lines and expired keys. */ if (count($line) != 7 || !empty($line[5]) && $line[5] <= time()) { continue; } $curid = $line[4]; $keyids[$curid] = $line[1]; } elseif (!is_null($curid) && substr($line, 0, 4) == 'uid:') { preg_match("/<([^>]+)>/", $line, $matches); $keyuids[$curid][] = $matches[1]; } } /* Remove keys without a matching UID. */ foreach ($keyuids as $id => $uids) { $match = false; foreach ($uids as $uid) { if ($uid == $address) { $match = true; break; } } if (!$match) { unset($keyids[$id]); } } /* Sort by timestamp to use the newest key. */ if (count($keyids)) { ksort($keyids); $pubkey = $this->get(array_pop($keyids)); } } if ($pubkey) { $sig = $this->_pgp->pgpPacketSignature($pubkey, $address); if (!empty($sig['keyid']) && (empty($sig['public_key']['expires']) || $sig['public_key']['expires'] > time())) { return substr($this->_pgp->getKeyIDString($sig['keyid']), 2); } } throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("Could not obtain public key from the keyserver.")); }
/** * Generates a Horde_Mime_Part object, in accordance with RFC 3156, that * contains a public key. * * @param string $key The public key. * * @return Horde_Mime_Part An object that contains the public key. */ public function publicKeyMIMEPart($key) { $part = new Horde_Mime_Part(); $part->setType('application/pgp-keys'); $part->setHeaderCharset('UTF-8'); $part->setDescription(Horde_Crypt_Translation::t("PGP Public Key")); $part->setContents($key, array('encoding' => '7bit')); return $part; }
/** * Function that handles interfacing with the GnuPG binary. * * @param array $options Options and commands to pass to GnuPG. * @param string $mode 'r' to read from stdout, 'w' to write to * stdin. * @param array $input Input to write to stdin. * @param boolean $output Collect and store output in object returned? * @param boolean $stderr Collect and store stderr in object returned? * @param boolean $parseable Is parseable output required? The gpg binary * would be executed with C locale then. * @param boolean $verbose Run GnuPG with verbose flag? * * @return stdClass Class with members output, stderr, and stdout. * @throws Horde_Crypt_Exception * @todo This method should be protected, but due to closures not having * proper access to $this without assigning it to another variable * which does not give it access to non-puplic members, we must * make this public until H6 when we can require at least PHP 5.4. */ public function _callGpg($options, $mode, $input = array(), $output = false, $stderr = false, $parseable = false, $verbose = false) { $data = new stdClass(); $data->output = null; $data->stderr = null; $data->stdout = null; /* Verbose output? */ if (!$verbose) { array_unshift($options, '--quiet'); } /* Create temp files for output. */ if ($output) { $output_file = $this->_createTempFile('horde-pgp', false); array_unshift($options, '--output ' . $output_file); /* Do we need standard error output? */ if ($stderr) { $stderr_file = $this->_createTempFile('horde-pgp', false); $options[] = '2> ' . $stderr_file; } } /* Silence errors if not requested. */ if (!$output || !$stderr) { $options[] = '2> /dev/null'; } /* Build the command line string now. */ $cmdline = implode(' ', array_merge($this->_gnupg, $options)); $language = getenv('LANGUAGE'); if ($parseable) { putenv('LANGUAGE=C'); } if ($mode == 'w') { if ($fp = popen($cmdline, 'w')) { putenv('LANGUAGE=' . $language); $win32 = !strncasecmp(PHP_OS, 'WIN', 3); if (!is_array($input)) { $input = array($input); } foreach ($input as $line) { if ($win32 && strpos($line, "\r\n") !== false) { $chunks = explode("\r\n", $line); foreach ($chunks as $chunk) { fputs($fp, $chunk . "\n"); } } else { fputs($fp, $line . "\n"); } } } else { putenv('LANGUAGE=' . $language); throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("Error while talking to pgp binary.")); } } elseif ($mode == 'r') { if ($fp = popen($cmdline, 'r')) { putenv('LANGUAGE=' . $language); while (!feof($fp)) { $data->stdout .= fgets($fp, 1024); } } else { putenv('LANGUAGE=' . $language); throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("Error while talking to pgp binary.")); } } pclose($fp); if ($output) { $data->output = file_get_contents($output_file); unlink($output_file); if ($stderr) { $data->stderr = file_get_contents($stderr_file); unlink($stderr_file); } } return $data; }
/** * Convert a PKCS 12 encrypted certificate package into a private key, * public key, and any additional keys. * * @param string $pkcs12 The PKCS 12 data. * @param array $params The parameters needed for parsing. * <pre> * Parameters: * =========== * 'sslpath' => The path to the OpenSSL binary. (REQUIRED) * 'password' => The password to use to decrypt the data. (Optional) * 'newpassword' => The password to use to encrypt the private key. * (Optional) * </pre> * * @return stdClass An object. * 'private' - The private key in PEM format. * 'public' - The public key in PEM format. * 'certs' - An array of additional certs. * @throws Horde_Crypt_Exception */ public function parsePKCS12Data($pkcs12, $params) { /* Check for availability of OpenSSL PHP extension. */ $this->checkForOpenSSL(); if (!isset($params['sslpath'])) { throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("No path to the OpenSSL binary provided. The OpenSSL binary is necessary to work with PKCS 12 data.")); } $sslpath = escapeshellcmd($params['sslpath']); /* Create temp files for input/output. */ $input = $this->_createTempFile('horde-smime'); $output = $this->_createTempFile('horde-smime'); $ob = new stdClass(); /* Write text to file */ file_put_contents($input, $pkcs12); unset($pkcs12); /* Extract the private key from the file first. */ $cmdline = $sslpath . ' pkcs12 -in ' . $input . ' -out ' . $output . ' -nocerts'; if (isset($params['password'])) { $cmdline .= ' -passin stdin'; if (!empty($params['newpassword'])) { $cmdline .= ' -passout stdin'; } else { $cmdline .= ' -nodes'; } } else { $cmdline .= ' -nodes'; } if ($fd = popen($cmdline, 'w')) { fwrite($fd, $params['password'] . "\n"); if (!empty($params['newpassword'])) { fwrite($fd, $params['newpassword'] . "\n"); } pclose($fd); } else { throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("Error while talking to smime binary.")); } $ob->private = trim(file_get_contents($output)); if (empty($ob->private)) { throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("Password incorrect")); } /* Extract the client public key next. */ $cmdline = $sslpath . ' pkcs12 -in ' . $input . ' -out ' . $output . ' -nokeys -clcerts'; if (isset($params['password'])) { $cmdline .= ' -passin stdin'; } if ($fd = popen($cmdline, 'w')) { fwrite($fd, $params['password'] . "\n"); pclose($fd); } else { throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("Error while talking to smime binary.")); } $ob->public = trim(file_get_contents($output)); /* Extract the CA public key next. */ $cmdline = $sslpath . ' pkcs12 -in ' . $input . ' -out ' . $output . ' -nokeys -cacerts'; if (isset($params['password'])) { $cmdline .= ' -passin stdin'; } if ($fd = popen($cmdline, 'w')) { fwrite($fd, $params['password'] . "\n"); pclose($fd); } else { throw new Horde_Crypt_Exception(Horde_Crypt_Translation::t("Error while talking to smime binary.")); } $ob->certs = trim(file_get_contents($output)); return $ob; }
/** * Returns the plural translation of a message. * * @param string $singular The singular version to translate. * @param string $plural The plural version to translate. * @param integer $number The number that determines singular vs. plural. * * @return string The string translation, or the original string if no * translation exists. */ public static function ngettext($singular, $plural, $number) { self::$_domain = 'Horde_Crypt'; self::$_directory = '@data_dir@' == '@' . 'data_dir' . '@' ? __DIR__ . '/../../../locale' : '@data_dir@/Horde_Crypt/locale'; return parent::ngettext($singular, $plural, $number); }