maxgoedjen / secretive

Store SSH keys in the Secure Enclave
MIT License
6.99k stars 155 forks source link

icloud #542

Closed aschw closed 2 months ago

aschw commented 2 months ago

Is it possible to synchronize Secretive's 256-bit EC keys to iCloud keychain? Doing so might provide a backup option and make it easier to migrate to new machines.

orazioedoardo commented 2 months ago

No it's not, private keys are not even available to macOS, let alone be exported.

aschw commented 2 months ago

I understand there are security tradeoffs here, but if the user were to opt in, would specifying kSecAttrSynchronizable be straightforward?

maxgoedjen commented 2 months ago

@aschw theoretically someone could build a Secretive-like app that uses iCloud Keychain for key storage instead of the Secure Enclave – setting kSecAttrSynchronizable wouldn't be sufficient alone, but there's nothing to prevent someone from storing a key in the keychain and performing signing operations with that.

This is pretty explicitly contradictory to the purpose of this project though – this project is built around the Secure Enclave and its associated security guarantees, so we probably won't be pursuing it here.

aschw commented 2 months ago

I recognize the importance of the Secure Enclave’s role in this project and its significant security benefits. However, transitioning to a new macOS device under the current setup can be notably burdensome, primarily because users need to track down all the uses of their old public key and update them.

Enabling kSecAttrSynchronizable for keys in the Secure Enclave may reduce their security attributes, but compromising these keys would still require overcoming robust security measures—specifically, breaching the Secure Enclave itself or obtaining the user's iCloud credentials and successfully adding a new device to their iCloud account, which involves additional verification steps. The Secure Enclave remains crucial to each signing operation, ensuring that keys stay secure even if an attacker obtains an unencrypted copy of the Mac's hard drive[1].

The evolution of WebAuthn and Passkeys in Safari echoes this situation. With the release of Safari 14, WebAuthn platform authenticators like Face ID or Touch ID were introduced without iCloud sync capability. It was only in Safari 15 that Passkeys, which synchronize with the iCloud Keychain, were made available. This shift towards integrating user-friendly features without fully compromising security has been well-received as a positive development. Many users of Secretive are likely using iCloud-synchronized Passkeys and would appreciate similar features for ease of device migration and backup in the Secretive project, especially when replacing a lost device or transitioning to a new one.

[1] https://www.slashid.dev/blog/passkeys-deepdive/

maxgoedjen commented 2 months ago

@aschw interesting link – I'm not... 100% confident that what that article is describing is accurate (at least for third party apps), but I'm also not 100% I'm correct here either ;)

When a user enables iCloud Keychain for the first time, the device establishes a circle of trust and creates a syncing identity for itself. The syncing identity consists of a private key and a public key, and is stored in the device’s keychain. The public key of the syncing identity is put in the circle, and the circle is signed twice: first by the private key of the syncing identity, and then again with an asymmetric elliptical key (using P-256) derived from the user’s iCloud account password. Also stored with the circle are the parameters (random salt and iterations) used to create the key that’s based on the user’s iCloud password.

I'm not positive I agree with their reading of this statement – what this is describing, as far as I can tell, is how general synchronizable items in the keychain behave, not SEP-backed ones specifically.

That being said, I'm not sure how to reconcile the source code they linked with my understanding of the current limitations of the SEP – my understanding was that iCloud Keychain keys were in the data protection keychain but not processed by the SEP itself. It's possible that code they linked is an artifact of a previous beta incarnation of passkeys where that was (iirc) the case.

Apple's security guide itself does not mentioned the SEP at all when discussion passkeys: https://support.apple.com/en-us/102195

Anyway, I'll poke around this a little more.

maxgoedjen commented 2 months ago

Admittedly my disassembly reading is very weak so I could be wrong here, but I think they might have misread that assembly as a pure "add the sync key" when it actually reassigns the attributes dict to a new object without that key.

local_160 = *(undefined8 *)__got::_kSecAttrTokenIDSecureEnclave; gets stuffed into uVar4 = __auth_stubs::_objc_msgSend (&_OBJC_CLASS_$_NSDictionary,"dictionaryWithObjects:forKeys:count:",&local_160, &local_180,4);

in the iVar1 = __auth_stubs::_objc_msgSend(uVar5,"shouldUseAlternateCredentialStore"); codepath, uvar4 is rewritten to a new dictionary, one that (afaict) does not have the SEP attribute applied.

aschw commented 2 months ago

I'm definitely out of my depth, but this is worth a look: https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_attribute_keys_and_values#2557909

I might be looking in the wrong place, but it looks like kSecAttrSynchronizable is discussed right next to kSecAttrTokenIDSecureEnclave without any discussion of them being mutually exclusive.

aschw commented 2 months ago

Is it worth reopening the issue?

maxgoedjen commented 2 months ago

Just for experimentation's sake, I did try this and it didn't appear to sync (I'm surprised it allowed creation at all without throwing an error tbh):

image

Screenshot 2024-04-17 at 5 07 19 PM

aschw commented 2 months ago

I’d also expect it to either work or throw an error…

Out of curiosity, did you try specifying kSecAttrSynchronizable and not kSecAttrTokenIDSecureEnclave to ensure that configuration syncs?

bblacey commented 2 months ago

FYI, for what it is worth, I recently "reset" an Apple Silicon Mac running macOS Sonoma and then "migrated" from a SuperDuper! backup and all my Secretive private keys were migrated/preserved. So somehow, the private keys were exported from the Secure Enclave and restored via Migration or the "Reset" didn't correctly erase the Secure Enclave. I believe the case is the former and not the later and therefore, then "syncing" may work if implemented correctly.

aschw commented 2 months ago

FYI, for what it is worth, I recently "reset" an Apple Silicon Mac running macOS Sonoma and then "migrated" from a SuperDuper! backup and all my Secretive private keys were migrated/preserved. So somehow, the private keys were exported from the Secure Enclave and restored via Migration or the "Reset" didn't correctly erase the Secure Enclave. I believe the case is the former and not the later and therefore, then "syncing" may work if implemented correctly.

This seems unlikely. For example, a few weeks ago, I migrated from an M1 Macbook Air to an M3 Macbook Air, and all of my Secretive private keys disappeared.

If you believe your experience accurately reflects how the migration process preserves data within the Secure Enclave, it might be best to open a separate issue to discuss this, as it isn't directly relevant to the current discussion. This will help keep the focus here while properly addressing your observations.

The scenario you describe is not particularly relevant to the interplay between kSecAttrSynchronizable and kSecAttrTokenIDSecureEnclave.

aschw commented 2 months ago

Just for experimentation's sake, I did try this and it didn't appear to sync (I'm surprised it allowed creation at all without throwing an error tbh):

@maxgoedjen There seems to be some configuration needed in the Apple developer portal. For example:

https://developer.apple.com/help/account/manage-identifiers/enable-app-capabilities/ https://developer.apple.com/documentation/xcode/configuring-keychain-sharing