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

Fix keychains that rely on kSecAttrAccessGroup on macOS Catalina #193

Merged
merged 27 commits into from
Jan 14, 2020

Conversation

dfed
Copy link
Collaborator

@dfed dfed commented Dec 22, 2019

It looks like Catalina broke our logic for finding a sharedAccessGroupPrefix. There's new documentation for kSecAttrAccessGroup in macOS Catalina:

image

This PR adds kSecUseDataProtectionKeychain to all keychain queries on macOS. This follows Apple's recommendation:

image

Copy link
Collaborator

@NickEntin NickEntin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this going to affect accessing values set using older versions of Valet?

Use it unless you specifically need access to items previously stored in a legacy keychain in macOS.

Not sure what a "legacy" keychain is in this context. If it includes anything before this attribute was set, that might be problematic.

@dfed
Copy link
Collaborator Author

dfed commented Dec 22, 2019

Is this going to affect accessing values set using older versions of Valet

Good catch! I've added a commit that adds this field when setting a value, but doesn't require it when reading values out of the keychain.

Note that I've run all macOS tests locally in a signed environment, and they are passing with this latest update. These tests include our tests that Legacy Valet instances can write values that current Valet instances can read. Given that those are passing, I think we're good to go.

@dfed dfed force-pushed the dfed--fix-shared-access-group-catalina branch from 8e35ea5 to e1baeba Compare December 23, 2019 06:46
@dfed dfed force-pushed the dfed--fix-shared-access-group-catalina branch from 2ccc52a to 63c3397 Compare December 29, 2019 21:11
@dfed
Copy link
Collaborator Author

dfed commented Jan 4, 2020

Would love to get this fix into a release so that Mac apps can recover from this issue. Can I get another review?

@NickEntin
Copy link
Collaborator

Based on testing, it appears that SecItemAdd is the only place where the kSecUseDataProtectionKeychain property validation is currently occurring. There is some potential for the future appearance of data loss here - specifically if Apple begins to enforce that kSecUseDataProtectionKeychain be included when utilizing SecItemDelete and SecItemCopyMatching as described in the documentation. In this case, items could be written to the Valet, but not read or deleted from it. The fix for this is to specify kSecUseDataProtectionKeychain when reading and deleting.

The trade-off here is that if we kSecUseDataProtectionKeychain on read, we will cause data loss when data is written to a Valet on macOS 10.14 or earlier and the system is subsequently updated to macOS 10.15. Leaving kSecUseDataProtectionKeychain out on read means that we could potentially read in data from a Valet with the same identifier but different accessibility level or access group, since kSecAttrAccessible and kSecAttrAccessGroup only apply when kSecUseDataProtectionKeychain is true.

@dfed
Copy link
Collaborator Author

dfed commented Jan 5, 2020

I've updated this PR to always use kSecUseDataProtectionKeychain, and I've added func migrateObjectsFromPreCatalina() to Valet. I need to add a README blurb on how to use that method still.

@dfed
Copy link
Collaborator Author

dfed commented Jan 6, 2020

Leaving kSecUseDataProtectionKeychain out on read means that we could potentially read in data from a Valet with the same identifier but different accessibility level or access group, since kSecAttrAccessible and kSecAttrAccessGroup only apply when kSecUseDataProtectionKeychain is true.

Upon further investigation, this isn't entirely true. We encode the accessibility in the kSecAttrService, so we can't read data from another Valet with the same identifier but a different accessibility level.

Additionally, since kSecAttrAccessGroup is derived from the identifier, it is impossible to have a Valet with the same identifier but different kSecAttrAccessGroup value.

That said, I still think protecting against a future where Apple enforces the presence of kSecUseDataProtectionKeychain on read or delete.

kSecAttrAccessible : Accessibility.alwaysThisDeviceOnly.secAccessibilityAttribute,
]

if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no harm in using kSecUseDataProtectionKeychain when looking up the sharedAccessGroupPrefix on all operating systems.


if #available(iOS 13.0, tvOS 13.0, watchOS 6.0, macOS 10.15, *) {
// Update the account to be distinct, since we're changing the query.
query[kSecAttrAccount] = "SharedAccessGroupAlwaysAccessiblePrefixPlaceholderWithDataProtection"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't do this, a SharedAccessGroupAlwaysAccessiblePrefixPlaceholder that was added without kSecUseDataProtectionKeychain wouldn't be found on SecItemCopy, but trying to add that account/data to the keychain would return a errSecDuplicateItem.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind. Looks like errSecDuplicateItem is only returned when a kSecAttrService or kSecAttrAccount overlaps. Removing this line.



#if os(macOS)
if #available(macOS 10.15, *) {
Copy link
Collaborator Author

@dfed dfed Jan 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I only add kSecUseDataProtectionKeychain to our base query on macOS, since macOS is the only OS that needs this value.

Adding this value to the base query is a breaking change, since anything some items written to the keychain without kSecUseDataProtectionKeychain set will not be read when kSecUseDataProtectionKeychain is in the base query. I wrote migrateObjectsFromPreCatalina to solve this issue on macOS, but decided to allow non-Mac customers to continue using the keychain without migrating objects to include kSecUseDataProtectionKeychain.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After sleeping on it: I realize we can use kSecUseDataProtectionKeychain on all platforms. I had written a test to prove this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From Apple's documentation:

It’s highly recommended that you set the value of this key to true for all keychain operations. This key helps to improve the portability of your code across platforms. Use it unless you specifically need access to items previously stored in a legacy keychain in macOS.

Fixed in 0c9799c

@dfed
Copy link
Collaborator Author

dfed commented Jan 6, 2020

@NickEntin this PR is now ready for review again.

@dfed dfed force-pushed the dfed--fix-shared-access-group-catalina branch from 471507f to f4de2d4 Compare January 6, 2020 05:30
@dfed dfed force-pushed the dfed--fix-shared-access-group-catalina branch from f4de2d4 to f60f87d Compare January 6, 2020 05:30
@dfed dfed requested a review from fdiaz January 13, 2020 19:57
@dfed dfed merged commit 7447d16 into master Jan 14, 2020
@dfed dfed deleted the dfed--fix-shared-access-group-catalina branch January 14, 2020 23: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.

2 participants