#89 GnuPG verify cleartext messages

This commit is contained in:
the-djmaze 2022-02-03 12:05:33 +01:00
parent 73fa215e22
commit 45a714ee08
3 changed files with 78 additions and 54 deletions

View file

@ -177,19 +177,23 @@ export const PgpUserStore = new class {
} }
async verify(message) { async verify(message) {
const plain = message.plain(); const signed = message.pgpSigned();
if (/-----BEGIN PGP SIGNED MESSAGE-----/.test(plain) && /-----BEGIN PGP SIGNATURE-----/.test(plain)) { if (signed) {
return await OpenPGPUserStore.verify(message); const sender = message.from[0].email,
} gnupg = GnuPGUserStore.hasPublicKeyForEmails([sender]),
if (message.pgpSigned()) { openpgp = OpenPGPUserStore.hasPublicKeyForEmails([sender]);
const sender = message.from[0].email; // Detached signature use GnuPG first, else we must download whole message
let mode = await this.hasPublicKeyForEmails([sender]); if (gnupg && signed.SigPartId) {
if ('gnupg' === mode) {
return GnuPGUserStore.verify(message); return GnuPGUserStore.verify(message);
} }
if ('openpgp' === mode) { if (openpgp) {
return OpenPGPUserStore.verify(message); return OpenPGPUserStore.verify(message);
} }
if (gnupg) {
return GnuPGUserStore.verify(message);
}
// Mailvelope can't
// https://github.com/mailvelope/mailvelope/issues/434
} }
} }

View file

@ -673,22 +673,22 @@ trait Messages
$oImapClient->FolderExamine($sFolderName); $oImapClient->FolderExamine($sFolderName);
$aParts = [ $aParts = [
FetchType::BODY_PEEK.'['.$sBodyPartId.']' FetchType::BODY_PEEK.'['.$sBodyPartId.']',
];
if ($sSigPartId) {
// An empty section specification refers to the entire message, including the header. // An empty section specification refers to the entire message, including the header.
// But Dovecot does not return it with BODY.PEEK[1], so we also use BODY.PEEK[1.MIME]. // But Dovecot does not return it with BODY.PEEK[1], so we also use BODY.PEEK[1.MIME].
$aParts[] = FetchType::BODY_PEEK.'['.$sBodyPartId.'.MIME]'; FetchType::BODY_PEEK.'['.$sBodyPartId.'.MIME]'
];
if ($sSigPartId) {
$aParts[] = FetchType::BODY_PEEK.'['.$sSigPartId.']'; $aParts[] = FetchType::BODY_PEEK.'['.$sSigPartId.']';
} }
$oFetchResponse = $oImapClient->Fetch($aParts, $iUid, true)[0]; $oFetchResponse = $oImapClient->Fetch($aParts, $iUid, true)[0];
$sBodyMime = $oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sBodyPartId.'.MIME]');
if ($sSigPartId) { if ($sSigPartId) {
$result = [ $result = [
'text' => \preg_replace('/\\R/s', "\r\n", 'text' => \preg_replace('/\\R/s', "\r\n",
$oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sBodyPartId.'.MIME]') $sBodyMime . $oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sBodyPartId.']')
. $oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sBodyPartId.']')
), ),
'signature' => preg_replace('/[^\x00-\x7F]/', '', 'signature' => preg_replace('/[^\x00-\x7F]/', '',
$oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sSigPartId.']') $oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sSigPartId.']')
@ -697,18 +697,26 @@ trait Messages
} else { } else {
// clearsigned text // clearsigned text
$result = [ $result = [
'text' => \preg_replace('/\\R/s', "\r\n", 'text' => $oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sBodyPartId.']'),
$oFetchResponse->GetFetchValue(FetchType::BODY.'['.$sBodyPartId.']')
),
'signature' => '' 'signature' => ''
]; ];
$decode = (new \MailSo\Mime\HeaderCollection($sBodyMime))->ValueByName(\MailSo\Mime\Enumerations\Header::CONTENT_TRANSFER_ENCODING);
if ('base64' === $decode) {
$result['text'] = \base64_decode($result['text']);
} else if ('quoted-printable' === $decode) {
$result['text'] = \quoted_printable_decode($result['text']);
}
} }
if ($this->GetActionParam('GnuPG', 1)) { if ($this->GetActionParam('GnuPG', 1)) {
$GPG = $this->GnuPG(); $GPG = $this->GnuPG();
if ($GPG) { if ($GPG) {
$info = $this->GnuPG()->verify($result['text'], $result['signature'])[0]; $info = $this->GnuPG()->verify($result['text'], $result['signature']);
// $info = $this->GnuPG()->verifyStream($fp, $result['signature'])[0]; // $info = $this->GnuPG()->verifyStream($fp, $result['signature']);
if (empty($info[0])) {
$result = false;
} else {
$info = $info[0];
/** /**
* https://code.woboq.org/qt5/include/gpg-error.h.html * https://code.woboq.org/qt5/include/gpg-error.h.html
@ -745,6 +753,9 @@ trait Messages
}, ARRAY_FILTER_USE_KEY)) }, ARRAY_FILTER_USE_KEY))
]; ];
} }
} else {
$result = false;
}
} }
return $this->DefaultResponse(__FUNCTION__, $result); return $this->DefaultResponse(__FUNCTION__, $result);

View file

@ -365,9 +365,18 @@ class GnuPG
*/ */
public function verify(string $signed_text, string $signature, string &$plaintext = null) /*: array|false*/ public function verify(string $signed_text, string $signature, string &$plaintext = null) /*: array|false*/
{ {
return $this->GnuPG $result = $this->GnuPG
? $this->GnuPG->verify($signed_text, $signature, $plaintext) ? $this->GnuPG->verify($signed_text, $signature ?: false, $plaintext)
: $this->GPG->verify($signed_text, $signature, $plaintext); : $this->GPG->verify($signed_text, $signature, $plaintext);
if (!$result) {
if ($this->GnuPG) {
\error_log('gnupg_verify() failed: ' . $this->GnuPG->geterror() . "\n\n{$signed_text}\n\n{$signature}" );
\error_log(\print_r($this->GnuPG->geterrorinfo(),1));
} else {
\error_log('GPG->verify() failed');
}
}
return $result;
} }
/** /**