Upstream applied no content-encryption check at all on decrypt, and ran every decryption through the liner engine — which registers DES-CBC, 3DES-CBC and RC2-CBC. Those OIDs exist in crypto-engine.js for PKCS#12 password-based encryption; the CMS content path merely reused the same engine and inherited them. A crafted message could therefore be decrypted under a broken cipher, and unauthenticated plaintext was handed straight to the renderer — the EFAIL precondition. The obvious fix would have been wrong. Accepting only AEAD breaks most real S/MIME mail: RFC 5751 makes AES-128-CBC the MUST-implement content cipher, Outlook and Thunderbird default to CBC, and AES-GCM in CMS (RFC 5084) is barely deployed. An AEAD-only allowlist is a functionality catastrophe wearing a security fix's clothes. Three layers instead: 1. Allowlist the AES family and refuse everything else, with the gate running before any private key is touched. CBC stays for interop; DES/3DES/RC2 are refused. 2. Take the mail path off the legacy engine. Normal decryption now uses nativeEngine(); the liner engine is reachable only when a genuine legacy RSAES-PKCS1-v1_5 key is in play. This removes the weak ciphers structurally rather than by policy — native WebCrypto handles RSA-OAEP key transport and AES-CBC/GCM content perfectly well. 3. Refuse to render unauthenticated plaintext as HTML. CBC output is malleable and HTML is EFAIL's exfiltration channel. The host does block remote content by default (allowExternalContent starts false), but that is a user/admin setting this plugin cannot observe, so we don't lean on it. New renderUnauthenticatedHtml setting (default false) is the documented opt-out. Our own encrypt path always uses AES-GCM, so mail we send renders fully; only legacy inbound CBC degrades to text. Built from source with the repo's own pipeline (esbuild, 1.69 MB) and packaged to smime-vnc.zip (0.27 MB). All four fixes verified present in the built bundle. Build output is gitignored — never vendor a prebuilt bundle, which was the upstream mistake. Correcting an earlier assumption: this bundle does NOT trip the B-01 pattern scanner (zero matches on all five patterns), so the override is not needed to install it. B-01 remains correct — it closed a real entrypoint-only coverage gap — but it isn't load-bearing here. verify-fixes.mjs now carries 36 assertions covering all three fixes, including source checks that fail if a guard is removed, if a legacy CBC OID reappears in the allowlist, or if the mail path stops using the native engine. Findings 4 (unlocked keys persisted to IndexedDB), 5 (parser DoS) and 6 (PKCS1v1.5 oracle surface) remain open. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
73 lines
3.1 KiB
JSON
73 lines
3.1 KiB
JSON
{
|
|
"id": "smime",
|
|
"name": "S/MIME",
|
|
"version": "1.0.2",
|
|
"author": "Bulwark Mail Community",
|
|
"description": "End-to-end S/MIME for webmail: sign and encrypt outgoing messages, and automatically verify signatures and decrypt incoming CMS (PKCS#7) mail. Private keys are imported from a PKCS#12 (.p12/.pfx) file, encrypted at rest with a passphrase, and unlocked into non-extractable WebCrypto keys that never leave your browser. Runs in the privileged (same-origin) plugin tier so all cryptography happens locally with bundled pkijs/asn1js.",
|
|
"type": "ui-extension",
|
|
"tier": "privileged",
|
|
"permissions": [
|
|
"crypto:full",
|
|
"email:blob-read",
|
|
"email:raw-send",
|
|
"email:render-takeover",
|
|
"email:read",
|
|
"email:send",
|
|
"smime:read",
|
|
"auth:observe",
|
|
"ui:composer-toolbar",
|
|
"ui:email-banner",
|
|
"ui:settings-section",
|
|
"app:lifecycle"
|
|
],
|
|
"entrypoint": "index.js",
|
|
"minAppVersion": "1.7.6",
|
|
"icon": "media/icon.svg",
|
|
"banner": "media/banner.svg",
|
|
"settingsSchema": {
|
|
"encryptionStrength": {
|
|
"type": "select",
|
|
"label": "Content encryption algorithm",
|
|
"description": "Symmetric cipher used to encrypt the message body. AES-256-GCM is recommended; AES-128-GCM is slightly smaller and still strong.",
|
|
"default": "aes-256",
|
|
"options": ["aes-256", "aes-128"]
|
|
},
|
|
"autoImportSignerCerts": {
|
|
"type": "boolean",
|
|
"label": "Auto-save signer certificates",
|
|
"description": "When a validly signed message is opened, remember the signer's certificate so you can later send them encrypted mail without importing it manually.",
|
|
"default": true
|
|
},
|
|
"lockOnLogout": {
|
|
"type": "boolean",
|
|
"label": "Lock keys on logout",
|
|
"description": "Wipe all unlocked private keys from memory when you sign out or switch accounts. Leave on unless you have a specific reason not to.",
|
|
"default": true
|
|
},
|
|
"renderUnauthenticatedHtml": {
|
|
"type": "boolean",
|
|
"label": "Render HTML in legacy-encrypted mail",
|
|
"description": "Messages encrypted with AES-CBC carry no integrity protection, so their contents can be tampered with in transit. By default such mail is shown as plain text, which prevents a known attack that can leak the decrypted message. Turn this on only if you need HTML rendering for older encrypted mail and accept that risk. Mail encrypted with AES-GCM is unaffected and always renders fully.",
|
|
"default": false
|
|
},
|
|
"warnOnSelfSigned": {
|
|
"type": "boolean",
|
|
"label": "Warn on self-signed signer",
|
|
"description": "Show a caution banner when an incoming signature validates against a self-signed certificate (not chained to a trusted CA).",
|
|
"default": true
|
|
}
|
|
},
|
|
"locales": {
|
|
"en": {
|
|
"banner.signed_valid": "Signature valid",
|
|
"banner.signed_invalid": "Signature invalid",
|
|
"banner.encrypted": "Encrypted message",
|
|
"banner.decrypted": "Decrypted",
|
|
"banner.locked": "Encrypted — unlock your key to read",
|
|
"toolbar.sign": "Sign",
|
|
"toolbar.encrypt": "Encrypt",
|
|
"settings.title": "S/MIME keys & certificates"
|
|
}
|
|
}
|
|
}
|