Skip to content

Commit

Permalink
Initialize pins from PINENTRY_USER_DATA. Remember what PIN is being r…
Browse files Browse the repository at this point in the history
…equested and search for it in the user data when GETPIN is called.
  • Loading branch information
gauthierm committed Feb 26, 2013
1 parent f4e8e07 commit 6c27584
Showing 1 changed file with 102 additions and 3 deletions.
105 changes: 102 additions & 3 deletions Crypt/GPG/PinEntry.php
Expand Up @@ -49,6 +49,21 @@ class Crypt_GPG_PinEntry
*/
protected $parser = null;

/**
* @var array
*/
protected $pins = array();

/**
* @var array
*/
protected $triedPins = array();

/**
* @var array|null
*/
protected $currentPin = null;

public function __invoke()
{
$this->parser = $this->getParser();
Expand All @@ -60,6 +75,7 @@ public function __invoke()
$this->logFilename = $result->options['log'];

$this->connect();
$this->initPinsFromEnv();

$this->send($this->ok('Crypt_GPG pinentry ready and waiting'));
while (($line = fgets($this->stdin, self::READ_BUFFER_LENGTH)) !== false) {
Expand Down Expand Up @@ -134,6 +150,8 @@ protected function parseCommand($line)

switch ($command) {
case 'SETDESC':
return $this->setDescription($data);

case 'SETPROMPT':
case 'SETERROR':
case 'SETOK':
Expand Down Expand Up @@ -188,6 +206,20 @@ protected function connect()
}
}

protected function initPinsFromEnv()
{
if (($userData = getenv('PINENTRY_USER_DATA')) !== false) {
$pins = json_decode($userData, true);
if ($pins !== null) {
$this->pins = $pins;
}
$this->log(
'-- got user data ' . $userData . PHP_EOL,
self::VERBOSITY_ALL
);
}
}

protected function disconnect()
{
fflush($this->stdout);
Expand All @@ -204,9 +236,50 @@ protected function disconnect()
}
}

/**
* Sends an OK response for a not implemented feature
*
* @return void
*/
protected function notImplementedOk()
{
// not implemented
$this->send($this->ok());
}

/**
* Parses the currently requested key identifier and user identifier from
* the description passed to this pinentry
*
* @param string $text the raw description sent from gpg-agent.
*
* @return void
*/
protected function setDescription($text)
{
$text = rawurldecode($text);
$matches = array();
// TODO: handle user id with quotation marks
$exp = '/\n"(.+)"\n.*\sID ([A-Z0-9]+),\n/mu';
if (preg_match($exp, $text, $matches) === 1) {
$userId = $matches[1];
$keyId = $matches[2];

// only reset tried pins for new requested pin
if ( $this->currentPin === null
|| $this->currentPin['keyId'] !== $keyId
) {
$this->currentPin = array(
'userId' => $userId,
'keyId' => $keyId
);
$this->triedPins = array();
$this->log(
'-- looking for PIN for ' . $keyId . PHP_EOL,
self::VERBOSITY_ALL
);
}
}

$this->send($this->ok());
}

Expand All @@ -227,8 +300,34 @@ protected function buttonInfo($text)

protected function getPin()
{
// TODO: grab from pipe
$this->send($this->data('test'));
$foundPin = '';

if (is_array($this->currentPin)) {
$keyIdLength = mb_strlen($this->currentPin['keyId'], '8bit');

// search for the pin
foreach ($this->pins as $pin) {
// only check pins we haven't tried
if (!isset($this->triedPins[$pin['keyId']])) {

// get last X characters of key identifier to compare
$keyId = mb_substr(
$pin['keyId'],
-$keyIdLength,
mb_strlen($pin['keyId'], '8bit'),
'8bit'
);

if ($keyId === $this->currentPin['keyId']) {
$foundPin = $pin['passphrase'];
$this->triedPins[$pin['keyId']] = $pin;
break;
}
}
}
}

$this->send($this->data($foundPin));
$this->send($this->ok());
}

Expand Down

0 comments on commit 6c27584

Please sign in to comment.