Esempio n. 1
0
 /**
  * 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;
 }
Esempio n. 2
0
 /**
  * Decrypts and verifies encrypted, signed data
  *
  * @param string  $data       the encrypted signed data to be decrypted and
  *                            verified.
  * @param boolean $isFile     whether or not the data is a filename.
  * @param string  $outputFile the name of the file to which the decrypted
  *                            data should be written. If null, the decrypted
  *                            data is returned in the results array.
  *
  * @return array two element array. The array has an element 'data'
  *               containing the decrypted data and an element
  *               'signatures' containing an array of
  *               {@link Crypt_GPG_Signature} objects for the signed data.
  *               If the decrypted data is written to a file, the 'data'
  *               element is null.
  *
  * @throws Crypt_GPG_KeyNotFoundException if the private key needed to
  *         decrypt the data is not in the user's keyring or it the public
  *         key needed for verification is not in the user's keyring.
  *
  * @throws Crypt_GPG_NoDataException if specified data does not contain
  *         GPG signed, encrypted data.
  *
  * @throws Crypt_GPG_BadPassphraseException if a required passphrase is
  *         incorrect or if a required passphrase is not specified. See
  *         {@link Crypt_GPG::addDecryptKey()}.
  *
  * @throws Crypt_GPG_FileException if the output file is not writeable or
  *         if the input file is not readable.
  *
  * @throws Crypt_GPG_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_Signature
  */
 protected function _decryptAndVerify($data, $isFile, $outputFile)
 {
     if ($isFile) {
         $input = @fopen($data, 'rb');
         if ($input === false) {
             throw new Crypt_GPG_FileException('Could not open input file "' . $data . '" for decrypting and verifying.', 0, $data);
         }
     } else {
         $input = strval($data);
         if ($input == '') {
             throw new Crypt_GPG_NoDataException('No valid encrypted signed data found.', self::ERROR_NO_DATA);
         }
     }
     if ($outputFile === null) {
         $output = '';
     } else {
         $output = @fopen($outputFile, 'wb');
         if ($output === false) {
             if ($isFile) {
                 fclose($input);
             }
             throw new Crypt_GPG_FileException('Could not open output file "' . $outputFile . '" for storing decrypted data.', 0, $outputFile);
         }
     }
     $verifyHandler = new Crypt_GPG_VerifyStatusHandler();
     $decryptHandler = new Crypt_GPG_DecryptStatusHandler($this->engine, $this->decryptKeys);
     // If using gpg-agent, set the decrypt pins used by the pinentry
     $this->_setPinEntryEnv($this->decryptKeys);
     $this->engine->reset();
     $this->engine->addStatusHandler(array($verifyHandler, 'handle'));
     $this->engine->addStatusHandler(array($decryptHandler, 'handle'));
     $this->engine->setInput($input);
     $this->engine->setOutput($output);
     $this->engine->setOperation('--decrypt');
     $this->engine->run();
     if ($isFile) {
         fclose($input);
     }
     if ($outputFile !== null) {
         fclose($output);
     }
     $return = array('data' => null, 'signatures' => $verifyHandler->getSignatures());
     // if there was any problem decrypting the data, the handler will
     // deal with it here.
     try {
         $decryptHandler->throwException();
     } catch (Exception $e) {
         if ($e instanceof Crypt_GPG_KeyNotFoundException) {
             throw new Crypt_GPG_KeyNotFoundException('Public key required for data verification not in ', 'the keyring. Either no suitable private decryption key ' . 'is in the keyring or the public key required for data ' . 'verification is not in the keyring. Import a suitable ' . 'key before trying to decrypt and verify this data.', self::ERROR_KEY_NOT_FOUND, $this->engine->getErrorKeyId());
         }
         if ($e instanceof Crypt_GPG_NoDataException) {
             throw new Crypt_GPG_NoDataException('Cannot decrypt and verify data. No PGP encrypted data ' . 'was found in the provided data.', self::ERROR_NO_DATA);
         }
         throw $e;
     }
     if ($outputFile === null) {
         $return['data'] = $output;
     }
     return $return;
 }
Esempio n. 3
0
 /**
  * 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 Crypt_GPG_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 = '--utf8-strings --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();
     $privateKeyFingerprints = array();
     foreach (explode(PHP_EOL, $output) as $line) {
         $lineExp = explode(':', $line);
         if ($lineExp[0] == 'fpr') {
             $privateKeyFingerprints[] = $lineExp[9];
         }
     }
     // get public keys
     if ($keyId == '') {
         $operation = '--list-public-keys';
     } else {
         $operation = '--utf8-strings --list-public-keys ' . escapeshellarg($keyId);
     }
     $output = '';
     $this->engine->reset();
     $this->engine->setOutput($output);
     $this->engine->setOperation($operation, $arguments);
     $this->engine->run();
     $keys = array();
     $key = null;
     // current key
     $subKey = null;
     // current sub-key
     foreach (explode(PHP_EOL, $output) 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 Crypt_GPG_Key();
             $subKey = Crypt_GPG_SubKey::parse($line);
             $key->addSubKey($subKey);
         } elseif ($lineExp[0] == 'sub') {
             $subKey = Crypt_GPG_SubKey::parse($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 = new Crypt_GPG_UserId($string);
             if ($lineExp[1] == 'r') {
                 $userId->setRevoked(true);
             }
             $key->addUserId($userId);
         }
     }
     // add last key
     if ($key !== null) {
         $keys[] = $key;
     }
     return $keys;
 }