Skip to content

caldav: fix event signing to use address key#11

Open
haurucknde wants to merge 2 commits into
acheong08:mainfrom
haurucknde:fix/caldav-address-key-signing
Open

caldav: fix event signing to use address key#11
haurucknde wants to merge 2 commits into
acheong08:mainfrom
haurucknde:fix/caldav-address-key-signing

Conversation

@haurucknde

Copy link
Copy Markdown

Summary

Fixes CalDAV PUT operations failing with Proton API error:

[2001] Invalid event data (Provide data signed using the address key)
  • makeUpdateData() was using getUserKeys() which returns the first key in the keyring (index 0). After the Unlock() change in carddav: fix contact encryption key selection (user key vs address key) #10 (user keys before address keys for correct contact encryption), index 0 became the user key instead of an address key.
  • Proton's calendar API requires event cards to be signed with the address key matching the calendar member's email.
  • Added getAddressKeyForEmail() to look up the correct address key by email identity, with fallback to legacy behavior.
  • Moved FindMemberViewFromKeyring() call before the signing section (was at the end of the function) since we need the member email to select the key.

Context

This is the calendar-side counterpart of #10:

Proton's official web client (ProtonMail/WebClients) confirms this — getCreationKeys() explicitly requires the primary address key for calendar event signing.

Test plan

  • Build succeeds (go build ./cmd/ferroxide/)
  • CalDAV PROPFIND returns 207 (reads unaffected)
  • CalDAV PUT returns 201 (event created in Proton Calendar)
  • CalDAV DELETE returns 204 (event cleanup)
  • Verified event appears in Proton web UI

Note: Depends on #10 being merged first (this branch is based on fix/carddav-user-key-encryption).

🤖 Generated with Claude Code

haurucknde and others added 2 commits March 1, 2026 16:32
Unlock() returned only address keys in the key ring. However, Proton's
web client encrypts and signs contacts using the user key (the master
account key), not the address key. On accounts where the user key and
address key differ — which is the case for all modern Proton accounts —
contacts written via CardDAV cannot be decrypted by the Proton client,
resulting in "The decryption of the encrypted content failed" errors.

Unlock() now includes user keys in the returned key ring (user keys
first, then address keys) and tracks the primary user key ID separately.
The CardDAV handler encrypts and signs contact data using the primary
user key, matching the behaviour of Proton's own clients.
… key

Proton's calendar API requires event data to be signed with the address
key (the key associated with the user's email), not the account-level
user key. When Unlock() was updated to return user keys before address
keys (for correct contact encryption), the getUserKeys() function in
makeUpdateData() started returning the user key at index 0 instead of
the address key that was previously at that position.

This caused all CalDAV PUT operations to fail with:
  [2001] Invalid event data (Provide data signed using the address key)

Fix: Add getAddressKeyForEmail() which looks up the key entity matching
the calendar member's email address, and use it for signing in
makeUpdateData() instead of the blind getUserKeys() index-0 lookup.

The member lookup (FindMemberViewFromKeyring) is moved before the signing
section since we need the member email to select the correct key. This
also removes the duplicate member lookup that was at the end of the
function.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant