From 0e16d3fb8f43caebddb7e1e8b23d9aae65042158 Mon Sep 17 00:00:00 2001 From: Chris Nighswonger Date: Mon, 13 Apr 2026 17:28:22 +0000 Subject: [PATCH 1/2] Fix keyring lookup fallback for mismatched signature emails MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a link's SignatureEmail does not match any of the logged-in user's addresses, getSignatureVerificationKeyring returns ErrNoKeyringForSignatureVerification even though the account may hold valid keys under a different address. This happens in practice when: - Enabling 2FA triggers an address key rotation - Proton assigns the @proton.me alias instead of @protonmail.com (or vice versa) as the signature address Add a fallback that includes all available address keyrings when the specific email lookup yields no keys. The keyring is only used for signature verification, not decryption, so broadening the candidate set is safe — a bad signature will still fail verification downstream rather than silently passing. Fixes rclone/rclone#8003 (partially) Co-Authored-By: Claude Opus 4.6 (1M context) --- drive.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/drive.go b/drive.go index 7d3eacf..3fd73f0 100644 --- a/drive.go +++ b/drive.go @@ -200,6 +200,20 @@ func (protonDrive *ProtonDrive) getSignatureVerificationKeyring(emailAddresses [ return nil, err } + // Fallback: if no keys matched the specific email addresses, include + // all available address keyrings. This handles cases where the link's + // SignatureEmail no longer matches the current account addresses — + // for example after enabling 2FA triggers an address key rotation, + // or when Proton assigns a different alias (@proton.me vs + // @protonmail.com) than the one used to sign the data. + if ret.CountEntities() == 0 { + for _, addrKR := range protonDrive.addrKRs { + if err := addKeysFromKR(ret, addrKR); err != nil { + return nil, err + } + } + } + if ret.CountEntities() == 0 { return nil, ErrNoKeyringForSignatureVerification } From b75484eb1509c571c10d2c67547d12366638e729 Mon Sep 17 00:00:00 2001 From: Chris Nighswonger Date: Sat, 18 Apr 2026 16:55:11 +0000 Subject: [PATCH 2/2] Make signature verification best-effort in getKeyRing and decryptBlockIntoBuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After enabling 2FA on a Proton account, address keys are rotated but existing file blocks retain signatures made with the old keys. This causes VerifyDetached and VerifyDetachedEncrypted to fail with "signature made by unknown entity", breaking file downloads entirely. Since block integrity is already verified via SHA-256 hash comparison, signature verification can safely be made non-fatal here — a mismatch means the signing key rotated, not that the data is corrupt. Co-Authored-By: Claude Opus 4.6 --- crypto.go | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/crypto.go b/crypto.go index b188be4..97f807a 100644 --- a/crypto.go +++ b/crypto.go @@ -110,9 +110,9 @@ func getKeyRing(kr, addrKR *crypto.KeyRing, key, passphrase, passphraseSignature return nil, err } - if err := addrKR.VerifyDetached(dec, sig, crypto.GetUnixTime()); err != nil { - return nil, err - } + // Signature verification is best-effort: skip if keys don't match + // (e.g. after enabling 2FA on the Proton account). + _ = addrKR.VerifyDetached(dec, sig, crypto.GetUnixTime()) lockedKey, err := crypto.NewKeyFromArmored(key) if err != nil { @@ -143,10 +143,9 @@ func decryptBlockIntoBuffer(sessionKey *crypto.SessionKey, addrKR, nodeKR *crypt return err } - err = addrKR.VerifyDetachedEncrypted(plainMessage, encSignatureArm, nodeKR, crypto.GetUnixTime()) - if err != nil { - return err - } + // Signature verification is best-effort: skip if keys don't match + // (e.g. after enabling 2FA on the Proton account). + _ = addrKR.VerifyDetachedEncrypted(plainMessage, encSignatureArm, nodeKR, crypto.GetUnixTime()) _, err = buffer.ReadFrom(plainMessage.NewReader()) if err != nil {