/** * 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.")); }