Get S/MIME encryption working #259

This commit is contained in:
the-djmaze 2024-02-20 12:38:57 +01:00
parent 196dffa8d8
commit 1762198642
4 changed files with 60 additions and 39 deletions

View file

@ -1545,24 +1545,34 @@ export class ComposePopupView extends AbstractViewPopup {
}
}
if (encrypt) {
Object.entries(PgpUserStore.getPublicKeyOfEmails(recipients) || {}).forEach(([k,v]) =>
params.autocrypt.push({addr:k, keydata:v.replace(/-----(BEGIN|END) PGP PUBLIC KEY BLOCK-----/g, '').trim()})
);
const autocrypt = () =>
Object.entries(PgpUserStore.getPublicKeyOfEmails(recipients) || {}).forEach(([k,v]) =>
params.autocrypt.push({
addr: k,
keydata: v.replace(/-----(BEGIN|END) PGP PUBLIC KEY BLOCK-----/g, '').trim()
})
);
if ('openpgp' == encrypt) {
// Doesn't encrypt attachments
params.encrypted = await OpenPGPUserStore.encrypt(data.toString(), recipients);
params.signed = '';
autocrypt();
} else if ('gnupg' == encrypt) {
// Does encrypt attachments
params.encryptFingerprints = JSON.stringify(GnuPGUserStore.getPublicKeyFingerprints(recipients));
// } else {
// // S/MIME
// params.encryptCertificates = [];
autocrypt();
/*
} else if (identity && identity.smimeCertificate()) {
// TODO: S/MIME certificates of all recipients
params.encryptCertificates = [identity.smimeCertificate()];
}
*/
} else {
throw 'Encryption with ' + encrypt + ' not yet implemented';
}
}
}
return params;
}
}

View file

@ -194,14 +194,14 @@ class Part
return \MailSo\Base\StreamWrappers\SubStreams::CreateStream($aSubStreams);
}
public function addEncrypted(string $sEncrypted, string $sType)
public function addPgpEncrypted(string $sEncrypted)
{
$oPart = new self;
$oPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'multipart/encrypted; protocol="'.$sType.'"');
$oPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'multipart/encrypted; protocol="application/pgp-encrypted"');
$this->SubParts->append($oPart);
$oSubPart = new self;
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, $sType);
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'application/pgp-encrypted');
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_DISPOSITION, 'attachment');
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TRANSFER_ENCODING, '7Bit');
$oSubPart->Body = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString('Version: 1');
@ -209,27 +209,12 @@ class Part
$oSubPart = new self;
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TYPE, 'application/octet-stream');
if ('application/pgp-encrypted' === $sType) {
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_DISPOSITION, 'inline; filename="msg.asc"');
}
if ('application/pkcs7-mime' === $sType) {
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_DISPOSITION, 'inline; filename="msg.p7m"');
}
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_DISPOSITION, 'inline; filename="msg.asc"');
$oSubPart->Headers->AddByName(Enumerations\Header::CONTENT_TRANSFER_ENCODING, '7Bit');
$oSubPart->Body = \MailSo\Base\ResourceRegistry::CreateMemoryResourceFromString($sEncrypted);
$oPart->SubParts->append($oSubPart);
}
public function addPgpEncrypted(string $sEncrypted)
{
$this->addEncrypted($sEncrypted, 'application/pgp-encrypted');
}
public function addSMimeEncrypted(string $sEncrypted)
{
$this->addEncrypted($sEncrypted, 'application/pkcs7-mime');
}
public function addPlain(string $sPlain)
{
$oPart = new self;

View file

@ -1179,22 +1179,31 @@ trait Messages
}
$oMessage->addPgpEncrypted($GPG->encryptStream($fp));
} else {
$aCertificates = \json_decode($this->GetActionParam('encryptCertificates', ''), true);
$aCertificates = $this->GetActionParam('encryptCertificates', []);
if ($aCertificates) {
$tmp = new \SnappyMail\File\Temporary('mimepart');
$tmp->writeFromStream($oMessage->GetRootPart()->ToStream());
$oBody = $oMessage->GetRootPart();
$resource = $oBody->ToStream();
\MailSo\Base\StreamFilters\LineEndings::appendTo($resource);
$tmp = new \SnappyMail\File\Temporary('mimepart');
$tmp->writeFromStream($resource);
$oBody->Body = null;
$oBody->SubParts->Clear();
$oMessage->SubParts->Clear();
$oMessage->Attachments()->Clear();
$SMIME = $this->SMIME();
/*
foreach ($aCertificates as $sCertificate) {
$SMIME->addEncryptKey($sCertificate);
}
*/
$sEncrypted = $SMIME->encrypt($tmp, $aCertificates);
$oMessage->addSMimeEncrypted($sEncrypted);
$oPart = new MimePart;
$oMessage->SubParts->append($oPart);
$oPart->Headers->AddByName(
MimeEnumHeader::CONTENT_TYPE,
'application/pkcs7-mime; smime-type=enveloped-data; name="smime.p7m"'
);
$oPart->Headers->AddByName(MimeEnumHeader::CONTENT_TRANSFER_ENCODING, 'base64');
$oPart->Body = $sEncrypted;
}
}

View file

@ -162,7 +162,24 @@ class OpenSSL
)) {
throw new \RuntimeException('OpenSSL encrypt: ' . \openssl_error_string());
}
return $output->getContents();
/**
* Only fetch the body part
*/
$fp = $output->fopen();
// Skip headers
while (\trim(\fgets($fp)));
// Fetch the body
$encrypted = '';
do {
$line = \fgets($fp);
if (!\trim($line)) {
return $encrypted;
}
$encrypted .= $line;
} while (true);
return $data;
}
public function sign(/*string|Temporary*/$input, bool $detached = true)
@ -188,7 +205,7 @@ class OpenSSL
}
/**
* Only fetch the signed part
* Only fetch the signed body part
*/
$fp = $output->fopen();
$micalg = '';
@ -209,13 +226,13 @@ class OpenSSL
// Skip headers
while (\trim(\fgets($fp)));
// Fetch the body
$data = '';
$signature = '';
do {
$line = \fgets($fp);
if (!\trim($line)) {
return $data;
return $signature;
}
$data .= $line;
$signature .= $line;
} while (true);
}
}