/**
  * @group delete-private
  */
 public function testDeletePrivateKey()
 {
     $keyId = '*****@*****.**';
     $this->gpg->deletePrivateKey($keyId);
     $expectedKeys = array();
     // {{{ first-keypair@example.com
     $key = new Crypt_GPG_Key();
     $expectedKeys[] = $key;
     $userId = new Crypt_GPG_UserId();
     $userId->setName('First Keypair Test Key');
     $userId->setComment('do not encrypt important data with this key');
     $userId->setEmail('*****@*****.**');
     $key->addUserId($userId);
     $subKey = new Crypt_GPG_SubKey();
     $subKey->setId('C097D9EC94C06363');
     $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA);
     $subKey->setFingerprint('8D2299D9C5C211128B32BBB0C097D9EC94C06363');
     $subKey->setLength(1024);
     $subKey->setCreationDate(1221785805);
     $subKey->setExpirationDate(0);
     $subKey->setCanSign(true);
     $subKey->setCanEncrypt(false);
     $subKey->setHasPrivate(false);
     $key->addSubKey($subKey);
     $subKey = new Crypt_GPG_SubKey();
     $subKey->setId('9F93F9116728EF12');
     $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC);
     $subKey->setFingerprint('C9C65B3BBF040E40D0EA27B79F93F9116728EF12');
     $subKey->setLength(2048);
     $subKey->setCreationDate(1221785821);
     $subKey->setExpirationDate(0);
     $subKey->setCanSign(false);
     $subKey->setCanEncrypt(true);
     $subKey->setHasPrivate(false);
     $key->addSubKey($subKey);
     // }}}
     $keys = $this->gpg->getKeys($keyId);
     $this->assertEquals($expectedKeys, $keys);
 }
Example #2
0
 /**
  * Parses a user id object from a user id string
  *
  * A user id string is of the form:
  * <b><kbd>name (comment) <email-address></kbd></b> with the <i>comment</i>
  * and <i>email-address</i> fields being optional.
  *
  * @param string $string the user id string to parse.
  *
  * @return Crypt_GPG_UserId the user id object parsed from the string.
  */
 public static function parse($string)
 {
     $userId = new Crypt_GPG_UserId();
     $email = '';
     $comment = '';
     // get email address from end of string if it exists
     $matches = array();
     if (preg_match('/^(.+?) <([^>]+)>$/', $string, $matches) === 1) {
         $string = $matches[1];
         $email = $matches[2];
     }
     // get comment from end of string if it exists
     $matches = array();
     if (preg_match('/^(.+?) \\(([^\\)]+)\\)$/', $string, $matches) === 1) {
         $string = $matches[1];
         $comment = $matches[2];
     }
     $name = $string;
     $userId->setName($name);
     $userId->setComment($comment);
     $userId->setEmail($email);
     return $userId;
 }
Example #3
0
 /**
  * Gets a user id object from parameters
  *
  * @param string|Crypt_GPG_UserId $name    either a {@link Crypt_GPG_UserId}
  *                                         object, or a string containing
  *                                         the name of the user id.
  * @param string                  $email   optional. If <i>$name</i> is
  *                                         specified as a string, this is
  *                                         the email address of the user id.
  * @param string                  $comment optional. If <i>$name</i> is
  *                                         specified as a string, this is
  *                                         the comment of the user id.
  *
  * @return Crypt_GPG_UserId a user id object for the specified parameters.
  */
 protected function getUserId($name, $email = '', $comment = '')
 {
     if ($name instanceof Crypt_GPG_UserId) {
         $userId = $name;
     } else {
         $userId = new Crypt_GPG_UserId();
         $userId->setName($name)->setEmail($email)->setComment($comment);
     }
     return $userId;
 }
Example #4
0
 /**
  * @group fluent
  */
 public function testFluentInterface()
 {
     $userId = new Crypt_GPG_UserId();
     $returnedUserId = $userId->setName('Alice');
     $this->assertEquals($userId, $returnedUserId, 'Failed asserting fluent interface works for setName() method.');
     $userId = new Crypt_GPG_UserId();
     $returnedUserId = $userId->setComment('encryption is fun');
     $this->assertEquals($userId, $returnedUserId, 'Failed asserting fluent interface works for setComment() method.');
     $userId = new Crypt_GPG_UserId();
     $returnedUserId = $userId->setEmail('*****@*****.**');
     $this->assertEquals($userId, $returnedUserId, 'Failed asserting fluent interface works for setEmail() method.');
     $userId = new Crypt_GPG_UserId();
     $returnedUserId = $userId->setRevoked(true);
     $this->assertEquals($userId, $returnedUserId, 'Failed asserting fluent interface works for setRevoked() method.');
     $userId = new Crypt_GPG_UserId();
     $returnedUserId = $userId->setValid(true);
     $this->assertEquals($userId, $returnedUserId, 'Failed asserting fluent interface works for setValid() method.');
 }
Example #5
0
 /**
  * Parses a user id object from a user id string
  *
  * A user id string is of the form:
  * <b><kbd>name (comment) <email-address></kbd></b> with the <i>comment</i>
  * and <i>email-address</i> fields being optional.
  *
  * @param string $string the user id string to parse.
  *
  * @return Crypt_GPG_UserId the user id object parsed from the string.
  */
 public static function parse($string)
 {
     $userId = new Crypt_GPG_UserId();
     $name = '';
     $email = '';
     $comment = '';
     // get email address from end of string if it exists
     $matches = array();
     if (preg_match('/^(.*?)<([^>]+)>$/', $string, $matches) === 1) {
         $string = trim($matches[1]);
         $email = $matches[2];
     }
     // get comment from end of string if it exists
     $matches = array();
     if (preg_match('/^(.+?) \\(([^\\)]+)\\)$/', $string, $matches) === 1) {
         $string = $matches[1];
         $comment = $matches[2];
     }
     // there can be an email without a name
     if (!$email && preg_match('/^[\\S]+@[\\S]+$/', $string, $matches) === 1) {
         $email = $string;
     } else {
         $name = $string;
     }
     $userId->setName($name);
     $userId->setComment($comment);
     $userId->setEmail($email);
     return $userId;
 }
Example #6
0
 /**
  * Handles error values in the status output from GPG
  *
  * This method is responsible for setting the
  * {@link self::$errorCode}. See <b>doc/DETAILS</b> in the
  * {@link http://www.gnupg.org/download/ GPG distribution} for detailed
  * information on GPG's status output.
  *
  * @param string $line the status line to handle.
  *
  * @return void
  */
 public function handleStatus($line)
 {
     $tokens = explode(' ', $line);
     switch ($tokens[0]) {
         case 'NODATA':
             $this->errorCode = Crypt_GPG::ERROR_NO_DATA;
             break;
         case 'DECRYPTION_OKAY':
             // If the message is encrypted, this is the all-clear signal.
             $this->data['DecryptionOkay'] = true;
             $this->errorCode = Crypt_GPG::ERROR_NONE;
             break;
         case 'DELETE_PROBLEM':
             if ($tokens[1] == '1') {
                 $this->errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
                 break;
             } elseif ($tokens[1] == '2') {
                 $this->errorCode = Crypt_GPG::ERROR_DELETE_PRIVATE_KEY;
                 break;
             }
             break;
         case 'IMPORT_OK':
             $this->data['Import']['fingerprint'] = $tokens[2];
             if (empty($this->data['Import']['fingerprints'])) {
                 $this->data['Import']['fingerprints'] = array($tokens[2]);
             } else {
                 if (!in_array($tokens[2], $this->data['Import']['fingerprints'])) {
                     $this->data['Import']['fingerprints'][] = $tokens[2];
                 }
             }
             break;
         case 'IMPORT_RES':
             $this->data['Import']['public_imported'] = intval($tokens[3]);
             $this->data['Import']['public_unchanged'] = intval($tokens[5]);
             $this->data['Import']['private_imported'] = intval($tokens[11]);
             $this->data['Import']['private_unchanged'] = intval($tokens[12]);
             break;
         case 'NO_PUBKEY':
         case 'NO_SECKEY':
             $this->data['ErrorKeyId'] = $tokens[1];
             if ($this->errorCode != Crypt_GPG::ERROR_MISSING_PASSPHRASE && $this->errorCode != Crypt_GPG::ERROR_BAD_PASSPHRASE) {
                 $this->errorCode = Crypt_GPG::ERROR_KEY_NOT_FOUND;
             }
             // note: this message is also received if there are multiple
             // recipients and a previous key had a correct passphrase.
             $this->data['MissingKeys'][$tokens[1]] = $tokens[1];
             // @FIXME: remove missing passphrase registered in ENC_TO handler
             //         This is for GnuPG 2.1
             unset($this->data['MissingPassphrases'][$tokens[1]]);
             break;
         case 'KEY_CONSIDERED':
             // In GnuPG 2.1.x exporting/importing a secret key requires passphrase
             // However, no NEED_PASSPRASE is returned, https://bugs.gnupg.org/gnupg/issue2667
             // So, handling KEY_CONSIDERED and GET_HIDDEN is needed.
             if (!array_key_exists('KeyConsidered', $this->data)) {
                 $this->data['KeyConsidered'] = $tokens[1];
             }
             break;
         case 'USERID_HINT':
             // remember the user id for pretty exception messages
             // GnuPG 2.1.15 gives me: "USERID_HINT 0000000000000000 [?]"
             $keyId = $tokens[1];
             if (strcspn($keyId, '0')) {
                 $username = implode(' ', array_splice($tokens, 2));
                 $this->data['BadPassphrases'][$keyId] = $username;
             }
             break;
         case 'ENC_TO':
             // Now we know the message is encrypted. Set flag to check if
             // decryption succeeded.
             $this->data['DecryptionOkay'] = false;
             // this is the new key message
             $this->data['CurrentSubKeyId'] = $keyId = $tokens[1];
             // For some reason in GnuPG 2.1.11 I get only ENC_TO and no
             // NEED_PASSPHRASE/MISSING_PASSPHRASE/USERID_HINT
             // This is not needed for GnuPG 2.1.15
             if (!empty($_ENV['PINENTRY_USER_DATA'])) {
                 $passphrases = json_decode($_ENV['PINENTRY_USER_DATA'], true);
             } else {
                 $passphrases = array();
             }
             // @TODO: Get user name/email
             $this->data['BadPassphrases'][$keyId] = $keyId;
             if (empty($passphrases) || empty($passphrases[$keyId])) {
                 $this->data['MissingPassphrases'][$keyId] = $keyId;
             }
             break;
         case 'GOOD_PASSPHRASE':
             // if we got a good passphrase, remove the key from the list of
             // bad passphrases.
             if (isset($this->data['CurrentSubKeyId'])) {
                 unset($this->data['BadPassphrases'][$this->data['CurrentSubKeyId']]);
                 unset($this->data['MissingPassphrases'][$this->data['CurrentSubKeyId']]);
             }
             $this->needPassphrase--;
             break;
         case 'BAD_PASSPHRASE':
             $this->errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE;
             break;
         case 'MISSING_PASSPHRASE':
             if (isset($this->data['CurrentSubKeyId'])) {
                 $this->data['MissingPassphrases'][$this->data['CurrentSubKeyId']] = $this->data['CurrentSubKeyId'];
             }
             $this->errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
             break;
         case 'GET_HIDDEN':
             if ($tokens[1] == 'passphrase.enter' && isset($this->data['KeyConsidered'])) {
                 $tokens[1] = $this->data['KeyConsidered'];
             } else {
                 break;
             }
             // no break
         // no break
         case 'NEED_PASSPHRASE':
             $passphrase = $this->getPin($tokens[1]);
             $this->engine->sendCommand($passphrase);
             if ($passphrase === '') {
                 $this->needPassphrase++;
             }
             break;
         case 'SIG_CREATED':
             $this->data['SigCreated'] = $line;
             break;
         case 'SIG_ID':
             // note: signature id comes before new signature line and may not
             // exist for some signature types
             $this->data['SignatureId'] = $tokens[1];
             break;
         case 'EXPSIG':
         case 'EXPKEYSIG':
         case 'REVKEYSIG':
         case 'BADSIG':
         case 'ERRSIG':
             $this->errorCode = Crypt_GPG::ERROR_BAD_SIGNATURE;
             // no break
         // no break
         case 'GOODSIG':
             $signature = new Crypt_GPG_Signature();
             // if there was a signature id, set it on the new signature
             if (!empty($this->data['SignatureId'])) {
                 $signature->setId($this->data['SignatureId']);
                 $this->data['SignatureId'] = '';
             }
             // Detect whether fingerprint or key id was returned and set
             // signature values appropriately. Key ids are strings of either
             // 16 or 8 hexadecimal characters. Fingerprints are strings of 40
             // hexadecimal characters. The key id is the last 16 characters of
             // the key fingerprint.
             if (mb_strlen($tokens[1], '8bit') > 16) {
                 $signature->setKeyFingerprint($tokens[1]);
                 $signature->setKeyId(mb_substr($tokens[1], -16, null, '8bit'));
             } else {
                 $signature->setKeyId($tokens[1]);
             }
             // get user id string
             if ($tokens[0] != 'ERRSIG') {
                 $string = implode(' ', array_splice($tokens, 2));
                 $string = rawurldecode($string);
                 $signature->setUserId(Crypt_GPG_UserId::parse($string));
             }
             $this->data['Signatures'][] = $signature;
             break;
         case 'VALIDSIG':
             if (empty($this->data['Signatures'])) {
                 break;
             }
             $signature = end($this->data['Signatures']);
             $signature->setValid(true);
             $signature->setKeyFingerprint($tokens[1]);
             if (strpos($tokens[3], 'T') === false) {
                 $signature->setCreationDate($tokens[3]);
             } else {
                 $signature->setCreationDate(strtotime($tokens[3]));
             }
             if (array_key_exists(4, $tokens)) {
                 if (strpos($tokens[4], 'T') === false) {
                     $signature->setExpirationDate($tokens[4]);
                 } else {
                     $signature->setExpirationDate(strtotime($tokens[4]));
                 }
             }
             break;
         case 'KEY_CREATED':
             if (isset($this->data['Handle']) && $tokens[3] == $this->data['Handle']) {
                 $this->data['KeyCreated'] = $tokens[2];
             }
             break;
         case 'KEY_NOT_CREATED':
             if (isset($this->data['Handle']) && $tokens[1] == $this->data['Handle']) {
                 $this->errorCode = Crypt_GPG::ERROR_KEY_NOT_CREATED;
             }
             break;
         case 'PROGRESS':
             // todo: at some point, support reporting status async
             break;
             // GnuPG 2.1 uses FAILURE and ERROR responses
         // GnuPG 2.1 uses FAILURE and ERROR responses
         case 'FAILURE':
         case 'ERROR':
             $errnum = (int) $tokens[2];
             $source = $errnum >> 24;
             $errcode = $errnum & 0xffffff;
             switch ($errcode) {
                 case 11:
                     // bad passphrase
                 // bad passphrase
                 case 87:
                     // bad PIN
                     $this->errorCode = Crypt_GPG::ERROR_BAD_PASSPHRASE;
                     break;
                 case 177:
                     // no passphrase
                 // no passphrase
                 case 178:
                     // no PIN
                     $this->errorCode = Crypt_GPG::ERROR_MISSING_PASSPHRASE;
                     break;
                 case 58:
                     $this->errorCode = Crypt_GPG::ERROR_NO_DATA;
                     break;
             }
             break;
     }
 }
 /**
  * Handles a status line
  *
  * @param string $line the status line to handle.
  *
  * @return void
  */
 public function handle($line)
 {
     $tokens = explode(' ', $line);
     switch ($tokens[0]) {
         case 'GOODSIG':
         case 'EXPSIG':
         case 'EXPKEYSIG':
         case 'REVKEYSIG':
         case 'BADSIG':
             $signature = new Crypt_GPG_Signature();
             // if there was a signature id, set it on the new signature
             if ($this->signatureId != '') {
                 $signature->setId($this->signatureId);
                 $this->signatureId = '';
             }
             // Detect whether fingerprint or key id was returned and set
             // signature values appropriately. Key ids are strings of either
             // 16 or 8 hexadecimal characters. Fingerprints are strings of 40
             // hexadecimal characters. The key id is the last 16 characters of
             // the key fingerprint.
             if (strlen($tokens[1]) > 16) {
                 $signature->setKeyFingerprint($tokens[1]);
                 $signature->setKeyId(substr($tokens[1], -16));
             } else {
                 $signature->setKeyId($tokens[1]);
             }
             // get user id string
             $string = implode(' ', array_splice($tokens, 2));
             $string = rawurldecode($string);
             $signature->setUserId(Crypt_GPG_UserId::parse($string));
             $this->index++;
             $this->signatures[$this->index] = $signature;
             break;
         case 'ERRSIG':
             $signature = new Crypt_GPG_Signature();
             // if there was a signature id, set it on the new signature
             if ($this->signatureId != '') {
                 $signature->setId($this->signatureId);
                 $this->signatureId = '';
             }
             // Detect whether fingerprint or key id was returned and set
             // signature values appropriately. Key ids are strings of either
             // 16 or 8 hexadecimal characters. Fingerprints are strings of 40
             // hexadecimal characters. The key id is the last 16 characters of
             // the key fingerprint.
             if (strlen($tokens[1]) > 16) {
                 $signature->setKeyFingerprint($tokens[1]);
                 $signature->setKeyId(substr($tokens[1], -16));
             } else {
                 $signature->setKeyId($tokens[1]);
             }
             $this->index++;
             $this->signatures[$this->index] = $signature;
             break;
         case 'VALIDSIG':
             if (!array_key_exists($this->index, $this->signatures)) {
                 break;
             }
             $signature = $this->signatures[$this->index];
             $signature->setValid(true);
             $signature->setKeyFingerprint($tokens[1]);
             if (strpos($tokens[3], 'T') === false) {
                 $signature->setCreationDate($tokens[3]);
             } else {
                 $signature->setCreationDate(strtotime($tokens[3]));
             }
             if (array_key_exists(4, $tokens)) {
                 if (strpos($tokens[4], 'T') === false) {
                     $signature->setExpirationDate($tokens[4]);
                 } else {
                     $signature->setExpirationDate(strtotime($tokens[4]));
                 }
             }
             break;
         case 'SIG_ID':
             // note: signature id comes before new signature line and may not
             // exist for some signature types
             $this->signatureId = $tokens[1];
             break;
     }
 }
 /**
  * @group generate-key
  */
 public function testGenerateKeyWithExpirationDate()
 {
     if (!$this->config['enable-key-generation']) {
         $this->markTestSkipped('Key generation tests are disabled. To run key generation ' . 'tests, enable them in the test configuration. See the ' . 'configuration in \'config.php.dist\' for an exampe.');
     }
     // {{{ generate-test@example.com
     $expectedKey = new Crypt_GPG_Key();
     $userId = new Crypt_GPG_UserId();
     $userId->setName('Test Keypair');
     $userId->setEmail('*****@*****.**');
     $expectedKey->addUserId($userId);
     $subKey = new Crypt_GPG_SubKey();
     $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_DSA);
     $subKey->setLength(1024);
     $subKey->setExpirationDate(1999998000);
     // truncated to day
     $subKey->setCanSign(true);
     $subKey->setCanEncrypt(false);
     $subKey->setHasPrivate(true);
     $expectedKey->addSubKey($subKey);
     $subKey = new Crypt_GPG_SubKey();
     $subKey->setAlgorithm(Crypt_GPG_SubKey::ALGORITHM_ELGAMAL_ENC);
     $subKey->setLength(2048);
     $subKey->setExpirationDate(1999998000);
     // truncated to day
     $subKey->setCanSign(false);
     $subKey->setCanEncrypt(true);
     $subKey->setHasPrivate(true);
     $expectedKey->addSubKey($subKey);
     // }}}
     $key = $this->generator->setExpirationDate(2000000000)->generateKey(new Crypt_GPG_UserId('Test Keypair <*****@*****.**>'));
     $this->assertKeyEquals($expectedKey, $key);
 }
Example #9
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
  */
 public 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 Crypt_GPG::ERROR_NONE:
         case Crypt_GPG::ERROR_KEY_NOT_FOUND:
             // ignore not found key errors
             break;
         case Crypt_GPG::ERROR_FILE_PERMISSIONS:
             $filename = $this->engine->getErrorFilename();
             if ($filename) {
                 throw new Crypt_GPG_FileException(sprintf('Error reading GnuPG data file \'%s\'. Check to make ' . 'sure it is readable by the current user.', $filename), $code, $filename);
             }
             throw new Crypt_GPG_FileException('Error reading GnuPG data file. Check to make GnuPG data ' . 'files are readable by the current user.', $code);
         default:
             throw new Crypt_GPG_Exception('Unknown error getting keys. Please use the \'debug\' option ' . 'when creating the Crypt_GPG object, and file a bug report ' . 'at ' . self::BUG_URI, $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 Crypt_GPG::ERROR_NONE:
         case Crypt_GPG::ERROR_KEY_NOT_FOUND:
             // ignore not found key errors
             break;
         case Crypt_GPG::ERROR_FILE_PERMISSIONS:
             $filename = $this->engine->getErrorFilename();
             if ($filename) {
                 throw new Crypt_GPG_FileException(sprintf('Error reading GnuPG data file \'%s\'. Check to make ' . 'sure it is readable by the current user.', $filename), $code, $filename);
             }
             throw new Crypt_GPG_FileException('Error reading GnuPG data file. Check to make GnuPG data ' . 'files are readable by the current user.', $code);
         default:
             throw new Crypt_GPG_Exception('Unknown error getting keys. Please use the \'debug\' option ' . 'when creating the Crypt_GPG object, and file a bug report ' . 'at ' . self::BUG_URI, $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 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;
 }
Example #10
0
    /**
     * @group file
     */
    public function testVerifyFileDualDetachedSignature()
    {
        // {{{ first signature
        $firstSignature = new Crypt_GPG_Signature();
        $firstSignature->setId('T7+toJbsFr8KMTWN+M7lF3xSmmA');
        $firstSignature->setKeyFingerprint('8D2299D9C5C211128B32BBB0C097D9EC94C06363');
        $firstSignature->setKeyId('C097D9EC94C06363');
        $firstSignature->setCreationDate(1221960707);
        $firstSignature->setExpirationDate(0);
        $firstSignature->setValid(true);
        $userId = new Crypt_GPG_UserId();
        $userId->setName('First Keypair Test Key');
        $userId->setComment('do not encrypt important data with this key');
        $userId->setEmail('*****@*****.**');
        $firstSignature->setUserId($userId);
        // }}}
        // {{{ second signature
        $secondSignature = new Crypt_GPG_Signature();
        $secondSignature->setId('HJd1yvMbEbW5facuxkDtvwymKrw');
        $secondSignature->setKeyFingerprint('880922DBEA733E906693E4A903CC890AFA1DAD4B');
        $secondSignature->setKeyId('03CC890AFA1DAD4B');
        $secondSignature->setCreationDate(1221960707);
        $secondSignature->setExpirationDate(0);
        $secondSignature->setValid(true);
        $userId = new Crypt_GPG_UserId();
        $userId->setName('Second Keypair Test Key');
        $userId->setComment('do not encrypt important data with this key');
        $userId->setEmail('*****@*****.**');
        $secondSignature->setUserId($userId);
        // }}}
        // {{{ signature data
        $signatureData = <<<TEXT
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)

iD8DBQBI1aQDwJfZ7JTAY2MRAvkzAKDPnJ030GdYE15mE8smz2oV7zYziwCeJFxf
UaTrAgP1Dck9DhHOBhvhwLuIPwMFAEjVpAMDzIkK+h2tSxEC+TMAn38yx3mXk6wP
JaPThD7lRVE9ve57AJ0Yy7JwiT9sGXomln4JtRvuSpGtsg==
=Gw9D
-----END PGP SIGNATURE-----

TEXT;
        // }}}
        $expectedSignatures = array($firstSignature, $secondSignature);
        $filename = $this->getDataFilename('testFileMedium.plain');
        $signatures = $this->gpg->verifyFile($filename, $signatureData);
        $this->assertSignaturesEquals($expectedSignatures, $signatures);
    }
Example #11
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;
 }
Example #12
0
 /**
  * @group file
  */
 public function testDecryptVerifyFileSignedOnly()
 {
     // {{{ signature
     $signature = new Crypt_GPG_Signature();
     $signature->setId('vctnI/HnsRYmqcVwCJcJhS60lKU');
     $signature->setKeyFingerprint('8D2299D9C5C211128B32BBB0C097D9EC94C06363');
     $signature->setKeyId('C097D9EC94C06363');
     $signature->setCreationDate(1221960707);
     $signature->setExpirationDate(0);
     $signature->setValid(true);
     $userId = new Crypt_GPG_UserId();
     $userId->setName('First Keypair Test Key');
     $userId->setComment('do not encrypt important data with this key');
     $userId->setEmail('*****@*****.**');
     $signature->setUserId($userId);
     // }}}
     $expectedMd5Sum = 'f96267d87551ee09bfcac16921e351c1';
     $expectedResults = array('data' => null, 'signatures' => array($signature));
     $inputFilename = $this->getDataFilename('testVerifyFileNormalSignedData.asc');
     $outputFilename = $this->getTempFilename('testDecryptVerifyFileSignedData.plain');
     $results = $this->gpg->decryptAndVerifyFile($inputFilename, $outputFilename);
     $this->assertDecryptAndVerifyResultsEquals($expectedResults, $results);
     $md5Sum = $this->getMd5Sum($outputFilename);
     $this->assertEquals($expectedMd5Sum, $md5Sum);
 }