Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for automatically reloading CA certificates #125

Merged
merged 1 commit into from
Jan 16, 2025
Merged

Conversation

chenxiaolong
Copy link
Owner

@chenxiaolong chenxiaolong commented Jan 16, 2025

The initial implementation of loading Android's CA trust stores wrote the certificates to a temporary file and then passed them to rclone via the CaCert config option. This would only get loaded when a new backend Fs instance was created. If the backend was already created, the user would need to delete and recreate the remote or force quit RSAF, which is a terrible user experience.

Unfortunately, reloading by recreating the Fs and VFS instances would not provide a good experience either. The VFS would need to be shut down, interrupting VFS writeback, and we need to wait for the garbage collector to clean up the VFS instance so that the corresponding Fs instance would be unpinned from the cache. This precludes the CA reloading process from being automatic.

Instead, this commit makes use of a per-request hook to set the trusted CA certificates on every connection. This requires a soft-fork of rclone to add a hook point to fshttp.(*Transport).RoundTrip(). The patch is extremely simple and is easy to port to future versions of rclone. No other patches will be added to the fork and I plan to switch back to the upstream version if another good solution is found, even if hacky.

Some other approaches I tried or considered:

  • Replace fshttp.isCertificateExpired() using go:linkname and in the replacement, update the tls.Config.RootCAs in addition to executing a copy of the original code. This function would be called during each RoundTrip() invocation. This approach does not work with how gomobile builds rcbridge as a library and causes duplicate symbol errors during linking.
  • Add the code as is done in this commit, except via a -toolexec program that preprocesses the AST of the go sources. This approach does not work because -toolexec is not invoked at the necessary points when compiling with gomobile.
  • Patch fshttp.isCertificateExpired() at runtime by inserting a jump call to our own implementation. This is error prone, requires specific assembly code for each CPU architecture, and does not work if the function we want to patch was inlined.

This commit also fixes a bug where a remote's Fs instance is not properly removed from rclone's cache when deleting the remote.

Issue: #119

@chenxiaolong chenxiaolong self-assigned this Jan 16, 2025
@chenxiaolong chenxiaolong force-pushed the reload branch 2 times, most recently from b90b12f to f723889 Compare January 16, 2025 04:25
The initial implementation of loading Android's CA trust stores wrote
the certificates to a temporary file and then passed them to rclone via
the CaCert config option. This would only get loaded when a new backend
Fs instance was created. If the backend was already created, the user
would need to delete and recreate the remote or force quit RSAF, which
is a terrible user experience.

Unfortunately, reloading by recreating the Fs and VFS instances would
not provide a good experience either. The VFS would need to be shut
down, interrupting VFS writeback, and we need to wait for the garbage
collector to clean up the VFS instance so that the corresponding Fs
instance would be unpinned from the cache. This precludes the CA
reloading process from being automatic.

Instead, this commit makes use of a per-request hook to set the trusted
CA certificates on every connection. This requires a soft-fork of rclone
to add a hook point to fshttp.(*Transport).RoundTrip(). The patch is
extremely simple and is easy to port to future versions of rclone. No
other patches will be added to the fork and I plan to switch back to the
upstream version if another good solution is found, even if hacky.

Some other approaches I tried or considered:

* Replace fshttp.isCertificateExpired() using go:linkname and in the
  replacement, update the tls.Config.RootCAs in addition to executing a
  copy of the original code. This function would be called during each
  RoundTrip() invocation. This approach does not work with how gomobile
  builds rcbridge as a library and causes duplicate symbol errors during
  linking.
* Add the code as is done in this commit, except via a -toolexec program
  that preprocesses the AST of the go sources. This approach does not
  work because -toolexec is not invoked at the necessary points when
  compiling with gomobile.
* Patch fshttp.isCertificateExpired() at runtime by inserting a jump
  call to our own implementation. This is error prone, requires specific
  assembly code for each CPU architecture, and does not work if the
  function we want to patch was inlined.

This commit also fixes a bug where a remote's Fs instance is not
properly removed from rclone's cache when deleting the remote.

Issue: #119

Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
chenxiaolong added a commit that referenced this pull request Jan 16, 2025
Signed-off-by: Andrew Gunnerson <accounts+github@chiller3.com>
@chenxiaolong chenxiaolong merged commit 7b4b5f6 into master Jan 16, 2025
1 check passed
@chenxiaolong chenxiaolong deleted the reload branch January 16, 2025 05:13
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