Better GPG error handling

This commit is contained in:
the-djmaze 2024-03-04 11:02:12 +01:00
parent 464d22d69a
commit d57300dd75
4 changed files with 30 additions and 43 deletions

View file

@ -362,9 +362,10 @@ abstract class Base
$result = $this->exec([ $result = $this->exec([
'--dry-run', '--dry-run',
'--passwd', '--passwd',
$fingerprint $passphrase
]); ]);
*/ */
// $this->export($keyId, $passphrase);
$this->pinentries[$keyId] = $passphrase; $this->pinentries[$keyId] = $passphrase;
// $this->pinentries[\substr($keyId, -16)] = $passphrase; // $this->pinentries[\substr($keyId, -16)] = $passphrase;
return $this; return $this;

View file

@ -238,14 +238,19 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
return false; return false;
} }
protected function _exportKey($keyId, bool $private = false) /**
* Exports a public or private key
*/
public function export(string $fingerprint, ?SensitiveString $passphrase = null) /*: string|false*/
{ {
$keys = $this->keyInfo($keyId, $private); // \SnappyMail\Log::debug('GnuPG', "export({$fingerprint}, {$passphrase})");
$private = null !== $passphrase;
$keys = $this->keyInfo($fingerprint, $private);
if (!$keys) { if (!$keys) {
throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $keyId); throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $fingerprint);
} }
if ($private && $this->pinentries) { if ($private) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode(\array_map('strval', $this->pinentries)); $_ENV['PINENTRY_USER_DATA'] = \json_encode([$fingerprint => \strval($passphrase)]);
} }
$result = $this->exec([ $result = $this->exec([
$private ? '--export-secret-keys' : '--export', $private ? '--export-secret-keys' : '--export',
@ -255,20 +260,6 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
return $result['output']; return $result['output'];
} }
/**
* Exports a public or private key
*/
public function export(string $fingerprint, ?SensitiveString $passphrase = null) /*: string|false*/
{
// \SnappyMail\Log::debug('GnuPG', "export({$fingerprint}, {$passphrase})");
if (null !== $passphrase) {
return $this
->addPinentry($fingerprint, $passphrase)
->_exportKey($fingerprint, true);
}
return $this->_exportKey($fingerprint);
}
/** /**
* Returns the errortext, if a function fails * Returns the errortext, if a function fails
*/ */
@ -1121,8 +1112,11 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
if (\in_array($fdError, $inputStreams, true)) { if (\in_array($fdError, $inputStreams, true)) {
$this->_debug('error stream ready for reading'); $this->_debug('error stream ready for reading');
foreach ($this->_openPipes->readPipeLines(self::FD_ERROR) as $line) { foreach ($this->_openPipes->readPipeLines(self::FD_ERROR) as $line) {
$errors[] = $line;
$this->_debug("\t{$line}"); $this->_debug("\t{$line}");
$errors[] = \preg_replace('/^gpg: /', '', $line);
}
if ($throw && $errors) {
break;
} }
} }
@ -1188,7 +1182,7 @@ class PGP extends Base implements \SnappyMail\PGP\PGPInterface
$this->_output = null; $this->_output = null;
if ($throw && $exitCode && $errors) { if ($throw && $exitCode && $errors) {
throw new \RuntimeException(\implode("\n", $errors), $exitCode); throw new \RuntimeException(\implode(".\n", $errors), $exitCode);
} }
return [ return [

View file

@ -237,14 +237,18 @@ class SMIME extends Base
return false; return false;
} }
protected function _exportKey($keyId, bool $private = false) /**
* Exports a public or private key
*/
public function export(string $fingerprint, ?SensitiveString $passphrase = null) /*: string|false*/
{ {
$keys = $this->keyInfo($keyId, $private); $private = null !== $passphrase;
$keys = $this->keyInfo($fingerprint, $private);
if (!$keys) { if (!$keys) {
throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $keyId); throw new \Exception(($private ? 'Private' : 'Public') . ' key not found: ' . $fingerprint);
} }
if ($private && $this->pinentries) { if ($private) {
$_ENV['PINENTRY_USER_DATA'] = \json_encode($this->pinentries); $_ENV['PINENTRY_USER_DATA'] = \json_encode([$fingerprint => \strval($passphrase)]);
} }
$result = $this->exec([ $result = $this->exec([
$private ? '--export-secret-key-p12' : '--export', $private ? '--export-secret-key-p12' : '--export',
@ -254,19 +258,6 @@ class SMIME extends Base
return $result['output']; return $result['output'];
} }
/**
* Exports a public or private key
*/
public function export(string $fingerprint, ?SensitiveString $passphrase = null) /*: string|false*/
{
if ($passphrase) {
return $this
->addPinentry($fingerprint, $passphrase)
->_exportKey($fingerprint, true);
}
return $this->_exportKey($fingerprint);
}
protected function _importKey($input) /*: array|false*/ protected function _importKey($input) /*: array|false*/
{ {
$arguments = ['--import']; $arguments = ['--import'];
@ -666,7 +657,7 @@ class SMIME extends Base
return $info['ENC_TO']; return $info['ENC_TO'];
} }
private function exec(array $arguments) /*: array|false*/ private function exec(array $arguments, bool $throw = true) /*: array|false*/
{ {
if (\version_compare($this->version, '2.2.5', '<')) { if (\version_compare($this->version, '2.2.5', '<')) {
\SnappyMail\Log::error('GPG', "{$this->version} too old"); \SnappyMail\Log::error('GPG', "{$this->version} too old");

View file

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