/** * Gets the available keys in the keyring. * * Calls GPG with the <kbd>--list-keys</kbd> command and grabs keys. See * the first section of <b>doc/DETAILS</b> in the * {@link http://www.gnupg.org/download/ GPG package} for a detailed * description of how the GPG command output is parsed. * * @param string $keyId optional. Only keys with that match the specified * pattern are returned. The pattern may be part of * a user id, a key id or a key fingerprint. If not * specified, all keys are returned. * * @return array an array of {@link Crypt_GPG_Key} objects. If no keys * match the specified <kbd>$keyId</kbd> an empty array is * returned. * * @throws Exception if an unknown or unexpected error occurs. * Use the <kbd>debug</kbd> option and file a bug report if these * exceptions occur. * * @see Crypt_GPG_Key */ protected function _getKeys($keyId = '') { // get private key fingerprints if ($keyId == '') { $operation = '--list-secret-keys'; } else { $operation = '--list-secret-keys ' . escapeshellarg($keyId); } // According to The file 'doc/DETAILS' in the GnuPG distribution, using // double '--with-fingerprint' also prints the fingerprint for subkeys. $arguments = array('--with-colons', '--with-fingerprint', '--with-fingerprint', '--fixed-list-mode'); $output = ''; $this->engine->reset(); $this->engine->setOutput($output); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: case self::ERROR_KEY_NOT_FOUND: // ignore not found key errors break; case self::ERROR_FILE_PERMISSIONS: $filename = $this->engine->getErrorFilename(); if ($filename) { throw new \Exception(sprintf('Error reading GnuPG data file \'%s\'. Check to make ' . 'sure it is readable by the current user.', $filename), $code); } throw new \Exception('Error reading GnuPG data file. Check to make GnuPG data ' . 'files are readable by the current user.', $code); default: throw new \Exception('Unknown error getting keys. Please use the \'debug\' option ', $code); } $privateKeyFingerprints = array(); $lines = explode(PHP_EOL, $output); foreach ($lines as $line) { $lineExp = explode(':', $line); if ($lineExp[0] == 'fpr') { $privateKeyFingerprints[] = $lineExp[9]; } } // get public keys if ($keyId == '') { $operation = '--list-public-keys'; } else { $operation = '--list-public-keys ' . escapeshellarg($keyId); } $output = ''; $this->engine->reset(); $this->engine->setOutput($output); $this->engine->setOperation($operation, $arguments); $this->engine->run(); $code = $this->engine->getErrorCode(); switch ($code) { case self::ERROR_NONE: case self::ERROR_KEY_NOT_FOUND: // ignore not found key errors break; case self::ERROR_FILE_PERMISSIONS: $filename = $this->engine->getErrorFilename(); if ($filename) { throw new \Exception(sprintf('Error reading GnuPG data file \'%s\'. Check to make ' . 'sure it is readable by the current user.', $filename), $code); } throw new \Exception('Error reading GnuPG data file. Check to make GnuPG data ' . 'files are readable by the current user.', $code); default: throw new \Exception('Unknown error getting keys. Please use the \'debug\' option ', $code); } $keys = array(); $key = null; // current key $subKey = null; // current sub-key $lines = explode(PHP_EOL, $output); foreach ($lines as $line) { $lineExp = explode(':', $line); if ($lineExp[0] == 'pub') { // new primary key means last key should be added to the array if ($key !== null) { $keys[] = $key; } $key = new Key(); $subKey = self::parseSubKeyLine($line); $key->addSubKey($subKey); } elseif ($lineExp[0] == 'sub') { $subKey = self::parseSubKeyLine($line); $key->addSubKey($subKey); } elseif ($lineExp[0] == 'fpr') { $fingerprint = $lineExp[9]; // set current sub-key fingerprint $subKey->setFingerprint($fingerprint); // if private key exists, set has private to true if (in_array($fingerprint, $privateKeyFingerprints)) { $subKey->setHasPrivate(true); } } elseif ($lineExp[0] == 'uid') { $string = stripcslashes($lineExp[9]); // as per documentation $userId = self::parseUserIdLine($string); // isRevoked if (strpos($lineExp[1], 'r') !== false) { $userId->setIsRevoked(true); } // isValid if (strpos($lineExp[1], 'i') !== false) { $userId->setIsValid(false); } // isValid if (strpos($lineExp[1], 'd') !== false) { $userId->setDisabled(true); } // validity if (strpos($lineExp[1], 'n') !== false) { //NEVER } elseif (strpos($lineExp[1], 'm') !== false) { //MARGINAL } elseif (strpos($lineExp[1], 'f') !== false) { //FULL } elseif (strpos($lineExp[1], 'u') !== false) { //ULTIMATE } $key->addUserId($userId); } } // add last key if ($key !== null) { $keys[] = $key; } return $keys; }
public function getKeys($keyId = null) { $keys = array(); $data = $this->getResource()->keyinfo($keyId); foreach ($data as $kd) { $key = new Key(); foreach ($kd['subkeys'] as $skd) { $subKey = new SubKey(); $subKey->setCanEncrypt($skd['can_encrypt']); $subKey->setCanSign($skd['can_sign']); $subKey->setCreationDate($skd['timestamp']); $subKey->setExpirationDate($skd['expires']); $subKey->setFingerprint($skd['fingerprint']); $subKey->setHasPrivate(false); $subKey->setId($skd['keyid']); $subKey->setRevoked($skd['revoked']); $subKey->setDisabled($skd['disabled']); //$subKey->setLength($skd['can_encrypt']); //$subKey->setAlgorithm(); $key->addSubKey($subKey); } foreach ($kd['uids'] as $uid) { $userId = new UserId(); $userId->setName($uid['name']); $userId->setComment($uid['comment']); $userId->setEmail($uid['email']); $userId->setUid($uid['uid']); $userId->setIsRevoked($uid['revoked']); $userId->setIsValid($uid['invalid'] ? false : true); $key->addUserId($userId); } $keys[] = $key; } return $keys; }