GPG use pinentries for decrypt, sign and export

This commit is contained in:
the-djmaze 2024-03-04 10:14:14 +01:00
parent 7d485813e5
commit 464d22d69a
4 changed files with 62 additions and 36 deletions

View file

@ -43,10 +43,8 @@ abstract class Base
protected
$binary,
$version = '2.0',
$passphrases = [],
$signKeys = [],
$pinentries = [],
$encryptKeys = [],
$decryptKeys = [],
// Create PEM encoded output
$armor = true,
@ -284,8 +282,7 @@ abstract class Base
*/
public function addDecryptKey(string $fingerprint, SensitiveString $passphrase) : bool
{
$this->decryptKeys[$fingerprint] = $passphrase;
// $this->decryptKeys[\substr($fingerprint, -16)] = $passphrase;
$this->addPinentry($fingerprint, $passphrase);
return true;
}
@ -303,9 +300,15 @@ abstract class Base
*/
public function addSignKey(string $fingerprint, SensitiveString $passphrase) : bool
{
$this->signKeys[$fingerprint] = $passphrase;
// $this->signKeys[\substr($fingerprint, -16)] = $passphrase;
return false;
$this->addPinentry($fingerprint, $passphrase);
return true;
}
public function clear() : bool
{
$this->clearPinentries();
$this->clearEncryptKeys();
return true;
}
/**
@ -313,8 +316,7 @@ abstract class Base
*/
public function clearDecryptKeys() : bool
{
$this->decryptKeys = [];
return true;
return $this->clearPinentries();
}
/**
@ -331,8 +333,7 @@ abstract class Base
*/
public function clearSignKeys() : bool
{
$this->signKeys = [];
return true;
return $this->clearPinentries();
}
/**
@ -348,12 +349,36 @@ abstract class Base
];
}
public function addPassphrase($keyId, SensitiveString $passphrase)
/**
* Add private key passphrase for decrypt, sign or export
* $keyId or fingerprint
*/
public function addPinentry(string $keyId, SensitiveString $passphrase)
{
$this->passphrases[$keyId] = $passphrase;
/**
* Test first?
* gpg --dry-run --passwd <your-user-id>
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', [$keyId => $passphrase]));
$result = $this->exec([
'--dry-run',
'--passwd',
$fingerprint
]);
*/
$this->pinentries[$keyId] = $passphrase;
// $this->pinentries[\substr($keyId, -16)] = $passphrase;
return $this;
}
/**
* Removes all keys which were set for decryption, signing and export
*/
public function clearPinentries() : bool
{
$this->pinentries = [];
return true;
}
/**
* Toggle the armored output
* When true the output is ASCII

View file

@ -96,8 +96,8 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
$fclose = $this->setOutput($output);
if ($this->decryptKeys) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->decryptKeys));
if ($this->pinentries) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->pinentries));
}
$result = $this->exec(['--decrypt','--skip-verify']);
@ -244,8 +244,8 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
if (!$keys) {
throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $keyId);
}
if ($private && $this->passphrases) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->passphrases));
if ($private && $this->pinentries) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->pinentries));
}
$result = $this->exec([
$private ? '--export-secret-keys' : '--export',
@ -263,7 +263,7 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
// \SnappyMail\Log::debug('GnuPG', "export({$fingerprint}, {$passphrase})");
if (null !== $passphrase) {
return $this
->addPassphrase($fingerprint, $passphrase)
->addPinentry($fingerprint, $passphrase)
->_exportKey($fingerprint, true);
}
return $this->_exportKey($fingerprint);
@ -365,8 +365,8 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
{
$arguments = ['--import'];
if ($this->passphrases) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->passphrases));
if ($this->pinentries) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->pinentries));
} else {
$arguments[] = '--batch';
}
@ -618,7 +618,7 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
protected function _sign(/*string|resource*/ $input, /*string|resource*/ $output = null, bool $textmode = true) /*: string|false*/
{
if (empty($this->signKeys)) {
if (empty($this->pinentries)) {
throw new \Exception('No signing keys specified.');
}
@ -649,11 +649,11 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
$arguments[] = '--textmode';
}
if ($this->signKeys) {
foreach ($this->signKeys as $fingerprint => $pass) {
if ($this->pinentries) {
foreach ($this->pinentries as $fingerprint => $pass) {
$arguments[] = '--local-user ' . \escapeshellarg($fingerprint);
}
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->signKeys));
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->pinentries));
}
$result = $this->exec($arguments);

View file

@ -97,8 +97,8 @@ class SMIME extends Base
$fclose = $this->setOutput($output);
if ($this->decryptKeys) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->decryptKeys);
if ($this->pinentries) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->pinentries);
}
$result = $this->exec(['--decrypt','--skip-verify']);
@ -243,8 +243,8 @@ class SMIME extends Base
if (!$keys) {
throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $keyId);
}
if ($private && $this->passphrases) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->passphrases);
if ($private && $this->pinentries) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->pinentries);
}
$result = $this->exec([
$private ? '--export-secret-key-p12' : '--export',
@ -261,7 +261,7 @@ class SMIME extends Base
{
if ($passphrase) {
return $this
->addPassphrase($fingerprint, $passphrase)
->addPinentry($fingerprint, $passphrase)
->_exportKey($fingerprint, true);
}
return $this->_exportKey($fingerprint);
@ -271,8 +271,8 @@ class SMIME extends Base
{
$arguments = ['--import'];
if ($this->passphrases) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->passphrases);
if ($this->pinentries) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->pinentries);
} else {
$arguments[] = '--batch';
}
@ -482,7 +482,7 @@ class SMIME extends Base
protected function _sign(/*string|resource*/ $input, /*string|resource*/ $output = null) /*: string|false*/
{
if (empty($this->signKeys)) {
if (empty($this->pinentries)) {
throw new \Exception('No signing keys specified.');
}
@ -498,11 +498,11 @@ class SMIME extends Base
$arguments[] = '--armor';
}
if ($this->signKeys) {
foreach ($this->signKeys as $fingerprint => $pass) {
if ($this->pinentries) {
foreach ($this->pinentries as $fingerprint => $pass) {
$arguments[] = '--local-user ' . \escapeshellarg($fingerprint);
}
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->signKeys);
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->pinentries);
}
$result = $this->exec($arguments);

View file

@ -7,6 +7,7 @@ use SnappyMail\SensitiveString;
interface PGPInterface
{
public static function isSupported() : bool;
// public function addPinentry(string $keyId, SensitiveString $passphrase) : bool;
public function addDecryptKey(string $fingerprint, SensitiveString $passphrase) : bool;
public function addEncryptKey(string $fingerprint) : bool;
public function addSignKey(string $fingerprint, SensitiveString $passphrase) : bool;