Prioritize user privacy and data security in your app. Discuss best practices for data handling, user consent, and security measures to protect user information.

All subtopics

Post

Replies

Boosts

Views

Activity

Is it possible to override kSecAttrCanSign for SecKeyCreateSignature?
I am having trouble creating a CSR to renew a SecIdentity whose private SecKey is stored in slot 9d of a smartcard. For slot 9a, I am able to accomplish this by way of SecKeyCreateSignature using CertificateSigningRequest from a gently-modified fork of swift-certificates/swift-crypto to sort out all the details. But for the SecKey associated with slot 9d, the Security framework instantly returns an "algorithm not supported by the key" error when I call SecKeyCreateSignature, without even prompting for a PIN. I believe the difference is that kSecAttrCanSign is true for slot 9a but false for slot 9d. The value makes some sense for day-to-day usage because this identity is usually not used for signing, but if we are to occasionally sign a CSR for this key an exception would need to be made. Is there any way to basically force this exception with the Security framework? Again the actual private key material is not available so the only access as far as I'm aware is via the enumerated SecKey reference. Is there any way to SecKeyCreateWithData a secondary reference to the same underlying (but unexportable!) key but with allowed-usage attributes of my own choosing?
1
0
779
Sep ’23
Including Third-Party SDK Required API Reasons in App's Manifest
Hello, I've been going through Apple's documentation on describing the use of required reason APIs in the privacy manifest file, and I have a question about handling APIs from third-party SDKs. If we've already integrated the manifest file provided by the third-party SDK into our project, do we still need to list the reasons for the APIs from the third-party SDK in our app's manifest file?
2
0
1.1k
Sep ’23
App rejected based on 5.1.1 guidelines
My app was rejected because I use the word 'Enable' on a button, which triggers the system permissions request. I've attached below the the rejection reason, along with the screenshot they provided. I made an appeal for this rejection last week, but haven't heard anything since. So I thought I'd ask for opinions. My issue with the rejection is that not only can I not find any violation of Privacy guidelines, but the suggestion from the reviewer is worse and would be a confusing UX. My flow is a typical onboarding flow, describing features and asking for permissions up-front to ensure the app works properly from the start - something lots of apps do. Sure it could be improved but this is the first version & release. Does anyone have any thoughts on this issue, or even a better suggestion than the one the reviewer provided?
1
0
508
Sep ’23
Why doesn't my website support Private Relay?
When a user with iCloud+ has private relay enabled (at least on iPhones), they have a warning before visiting my web application, that "This website does not support secure connections and iCloud Private Relay cannot hide your connection from this website. If you continue and open "...", your IP address will be visible" (this is a translation from german, as I don't speak it). What should I do for my website to support Private Relay? It is an Angular application, that makes requests to Java Spring Boot backend.
0
0
324
Sep ’23
What is the owner of a keychain item?
I have items written to the keychain by an XPC service. On disk, it's just a plain binary. There are times when this service shows a system authentication dialog via LAContext. By default, the application icon is a tiny version of a terminal. We found that if we wrap the binary in a bundle, we can include an icon and it will show up in the authentication dialog. The problem is that this new bundle seems to be different, as updates to an existing keychain item (created by the old, standalone binary) fail with errSecInvalidOwnerEdit. The bundle ID of the embedded binary has not changed. How does the system decide who is the owner of a keychain item and is there any way to do a migration like this without affecting item ownership?
3
0
385
Sep ’23
Urgent: Recovering keychain items after iCloud Restore
Hi Apple team, Our app stores a private key in keychain services (kSecClassGenericPassword) via expo-secure-store. We need urgent help in recovering an item stored in the keychain AFTER an iCloud Restore has happened. The private key is specifically stored with the kSecAttrAccessible trait of kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly. STEPS TO REPRODUCE (iPhone 14 Pro, iOS 16.7) Write an item to the keychain via expo-secure-store using the described attributes (on an app that's dispatched via Testflight) await SecureStore.setItemAsync("private_key", private_key, { requireAuthentication: true, authenticationPrompt: "Unlock your private key", keychainAccessible: SecureStore.WHEN_UNLOCKED_THIS_DEVICE_ONLY, }), Create an iCloud Backup for the device. Factory Reset the iPhone (Erase all content, apps, and settings) Restore the iOS backup from earlier and then attempt to retrieve the keychain item. Is there any way at all of retrieving this keychain item after an iCloud backup has been restored? Note. Our app has only been deployed via Testflight and there is no store listing. After restoring the device from an iCloud backup, our app icon has a small "download"/cloud icon beside it. When tapped, we get an error saying "Unable to install " because the app is not listed in the App Store. Is it possible that being on TestFlight is causing the keychain items to be wiped?
1
0
408
Sep ’23
SDK data use in privacy manifests depends on how it is used
Hi everyone, I work on a third-party SDK and am creating the privacy manifest and seek advice on how to fill out the "Describing data use in privacy manifests" section. NSPrivacyCollectedDataTypeLinked: Whether a data type is linked to user identity depends on how the SDK consumer is using it. The SDK supports identified users so data would be linked, but it also allows the use case for all users to be completely anonymous. NSPrivacyCollectedDataTypePurposes: For each data type, the reasons we collect the data also depends on how the SDK consumer is using it. For example, we collect product interaction, and this data could be used by SDK consumers for analytics or advertising or some other reason. The SDK has the ability to collect additional data, for example, emails and phone numbers, but only if the SDK consumer chooses to share this data. I assume we do not need to include this type of data in the privacy manifest since many SDK consumers will not be using this feature?
0
1
410
Oct ’23
Ship fat framework with Privacy manifest file containing required reason API also with code signing
Hi I have built framework that I distribute to other organization and they use it in their App. Since I ship the Fat framework (.framework) and not the .xcframework, does Fat framework(from Xcode 15) containing privacy manifest file will be supported? Or do I have to convert the fat framework to the xcframework in order to use privacy manifest file and also code signing? Thanks in the advance.
4
0
505
Oct ’23
How to identify whether a passkey is created from an Apple device (iCloud Keychain)
Hi, I am currently implementing the ability to allow users to add a Passkey to their account by using the webuathn api. My current issue is that I would like to identify what type of device/authenticator the user has used to create their passkey so that we can automatically set a nickname for the passkey for the user to help the user experience (E.g. if a user has setup a passkey on an Apple device, we would auto set the nickname as iCloud Keychain so its clear to the user that the passkey is not specific to just the device they set it up on). After some reading, it seems like when trying to create a new passkey via an Apple device, it will not send a populated attestation with any sort of attestation statement, aaguid, fmt etc... and this is what I have been seeing in my testing of my implementation. My question is, instead of using an aaguid, is there an alternative way to identify that the user has created a passkey via iCloud Keychain? I can see that when creating a passkey to my Google account via my iPhone/Macbook, they seem to be able to identify when a passkey is created on an Apple Device and labels it automatically as ("iCloud Keychain") and this applies to both doing it via platform and cross-platform. I essentially want to be able to achieve this but I'm not sure how this can be done.
2
0
1.1k
Oct ’23
Endpoint Security event muting issue
Recently we've discovered an issue affecting our products in regards to using the Monterey+ provided new api calls to selectively mute events. Specifically, whenever using es_mute_process_events or es_mute_path_events, the ES_EVENT_TYPE_NOTIFY_OPEN event is ignored for muting (meaning the call will return success, but the event will keep coming). This is true only for this event as far as I can tell, its AUTH counterpart stays muted (along lots of other processes: clone, rename, close, unlink, fork etc). It fails if either the event is in a list of events or if the event is singled out in 1 sized vector of events. When using a dedicated client for this event and using the previous api, es_mute_process or es_mute_path muting works as intended. Tested on ventura 13.5 and 13.6. Is there something that can be done to prevent dedicated clients or is this a known issue?
5
0
734
Oct ’23
Lock Screen does not invoke Authorization Plugin as expected on macOS 14.0
I'm the developer of a Mac app that uses an authorization plugin to perform 2FA (password and approve in mobile app). There are four authorization use cases which we handle by updating the corresponding entries in the authorization database. The plugin is installed in the authorization database as follows: system.login.console -> login Replace: loginwindow:login With: TrusonaAuthorizationPlugin:trusonaLogin authenticate -> privilege escalation Replace: builtin:authenticate With: TrusonaAuthorizationPlugin:trusonaLogin system.login.screensaver -> lock screen Replace: use-login-window-ui With: authenticate-session-owner-or-admin system.login.fus -> fast user switching Replace: loginwindow:login With: TrusonaAuthorizationPlugin:trusonaLogin Im macOS Sonoma 14.0 attempting to unlock the screen invokes the Privilege Escalation mechanism regardless of whether the "system.login.screensaver" record in the authorization database points to our authorization plugin or not. When our authorization plugin is enabled for Lock Screen, clicking on the Lock Screen item in the Apple Menu invokes our authorization plugin for 2FA saying you need to authenticate to unlock the screen even though the desktop is not hidden. Filed as FB13238136
0
0
372
Oct ’23
EC signature verification failed (ccerr -7)
Hello, I am working on simple task, i have a JWT and I need to verify it's signature. My sample data: JWT eyJhbGciOiJFUzI1NiIsImtpZCI6IjhEWVpUTFRPVUtNSjdUU0w4SFZVVTlUVEdXMV9NTVVSSURJV1JUVE0iLCJ0eXAiOiJKV1QifQ.eyJub25jZSI6Indkd2R3ZHdkIiwiZGF0ZVRpbWUiOiIyMDIzLTEwLTEzVDEyOjQ4OjQwWiJ9.nWBfRne9VOKV4NGt32gWtoA5fUKzu0RzkhUYSYwUA7cvalsABUcWrpEk0fhztPZDK7KrDF8P2Pquhoxq4p-FUg Public key (JWK) { "kid": "8DYZTLTOUKMJ7TSL8HVUU9TTGW1_MMURIDIWRTTM", "use": "sig", "kty": "EC", "alg": "ES256", "crv": "P-256", "x": "8dyzTlToUkMJ7tsl8HVuU9tTGw1_mmuridIWrttMRCs", "y": "AVqGlqJ88QgP_uVLea7gIUnA-p9iYwnJyYt7o-uH4oU" } When you put the data to the [https://jwt.io] you get "Signature Verified" message. So the data should be ok. I have implementation in Objective-C, but i get this weird error message when the SecKeyVerifySignature is called. Here is my code: #import <Cocoa/Cocoa.h> #import <CommonCrypto/CommonDigest.h> NSString* base64StringWithPadding(NSString *encodedString) { NSString* stringTobeEncoded = [[encodedString stringByReplacingOccurrencesOfString:@"-" withString:@"+"] stringByReplacingOccurrencesOfString:@"_" withString:@"/"]; int paddingCount = encodedString.length % 4; for (int i = 0; i < paddingCount; i++) { stringTobeEncoded = [stringTobeEncoded stringByAppendingString:@"="]; } return stringTobeEncoded; } SecKeyRef restorePublicKey(NSString *x, NSString *y) { NSString *xBase64Padd = base64StringWithPadding(x); NSString *yBase64Padd = base64StringWithPadding(y); NSData *xData = [[NSData alloc] initWithBase64EncodedString:xBase64Padd options:kNilOptions]; //32bytes NSData *yData = [[NSData alloc] initWithBase64EncodedString:yBase64Padd options:kNilOptions]; //32bytes NSMutableData *publicKeyData = [NSMutableData data]; // Append the constant byte '04' to indicate uncompressed format const unsigned char uncompressedByte = 0x04; [publicKeyData appendBytes:&uncompressedByte length:1]; // Append the X-coordinate and Y-coordinate [publicKeyData appendData:xData]; [publicKeyData appendData:yData]; NSDictionary *keyAttributes = @{ (id)kSecAttrKeyType: (id)kSecAttrKeyTypeECSECPrimeRandom, (id)kSecAttrKeyClass: (id)kSecAttrKeyClassPublic, (id)kSecAttrKeySizeInBits: @256, (id)kSecAttrIsPermanent:@NO }; CFErrorRef error = NULL; SecKeyRef publicKeyRef = SecKeyCreateWithData( (__bridge CFDataRef)publicKeyData, (__bridge CFDictionaryRef)keyAttributes, &error ); if(!publicKeyRef) { NSError *err = CFBridgingRelease(error); NSLog(@"%@", err.description); } return publicKeyRef; } int main(int argc, const char * argv[]) { @autoreleasepool { NSDictionary *jwk = @{ @"kid": @"8DYZTLTOUKMJ7TSL8HVUU9TTGW1_MMURIDIWRTTM", @"use": @"sig", @"kty": @"EC", @"alg": @"ES256", @"crv": @"P-256", @"x": @"8dyzTlToUkMJ7tsl8HVuU9tTGw1_mmuridIWrttMRCs", @"y": @"AVqGlqJ88QgP_uVLea7gIUnA-p9iYwnJyYt7o-uH4oU" }; SecKeyRef publicKeyRef = restorePublicKey(jwk[@"x"], jwk[@"y"]); NSString* header = @"eyJhbGciOiJFUzI1NiIsImtpZCI6IjhEWVpUTFRPVUtNSjdUU0w4SFZVVTlUVEdXMV9NTVVSSURJV1JUVE0iLCJ0eXAiOiJKV1QifQ"; NSString* payload = @"eyJub25jZSI6Indkd2R3ZHdkIiwiZGF0ZVRpbWUiOiIyMDIzLTEwLTEzVDEyOjQ4OjQwWiJ9"; NSString* signature = @"nWBfRne9VOKV4NGt32gWtoA5fUKzu0RzkhUYSYwUA7cvalsABUcWrpEk0fhztPZDK7KrDF8P2Pquhoxq4p-FUg"; NSString *headerAndPayload = [NSString stringWithFormat:@"%@.%@", header, payload]; NSData *signedData = [headerAndPayload dataUsingEncoding:NSUTF8StringEncoding]; NSString *signatureBase64Padd = base64StringWithPadding(signature); NSData *signatureData = [[NSData alloc] initWithBase64EncodedString:signatureBase64Padd options:kNilOptions]; bool canVerify = SecKeyIsAlgorithmSupported(publicKeyRef, kSecKeyOperationTypeVerify, kSecKeyAlgorithmECDSASignatureMessageX962SHA256); if(canVerify) { CFErrorRef error = NULL; BOOL verifyStatus = SecKeyVerifySignature( publicKeyRef, kSecKeyAlgorithmECDSASignatureMessageX962SHA256, (__bridge CFDataRef)signedData, (__bridge CFDataRef)signatureData, &error ); if(error) { NSError *err = CFBridgingRelease(error); NSLog(@"%@", err.description); } } else { NSLog(@"Cannot verify."); } } return NSApplicationMain(argc, argv); } I dont know where is the problem. I've tried everything.
2
0
344
Oct ’23
DeviceActivityReportExtension working on IOS 17 device but not on IOS 16 device
When I run it on my IOS 16 device I get this error message. When I run it on my device with IOS 17 I get none of these logs. My build target for both the widget and app are 16.0. "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=66, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler} 2023-10-19 13:49:44.565845-0400 Halo[87980:7963095] [db] Failed to initialize client context with error Error Domain=NSOSStatusErrorDomain Code=-54 "process may not map database" UserInfo={NSDebugDescription=process may not map database, _LSLine=66, _LSFunction=_LSServer_GetServerStoreForConnectionWithCompletionHandler} 2023-10-19 13:49:44.569345-0400 Halo[87980:7963095] Metal API Validation Enabled
2
1
524
Oct ’23
codesign not signing helper executable in AppleScript bundle
My AppleScript .app bundle contains a helper executable. Table 3 of TN2206 says that executables may be in either Contents/MacOS or Contents/Helpers, but Quinn's first reply in this post says that Contents/MacOS is better. So I put the helper in Contents/MacOS, alongside applet. I sign the AppleScript .app bundle for Developer ID and Hardened Runtime by running the codesign command with arguments recommended by Quinn in this post. Result: Notary Service rejects the .app bundle due to 3 issues with the helper: is not signed with a valid Developer ID certificate does not include a secure timestamp does not have the hardened runtime enabled (Possibly it still has a years-old signature without Developer ID and Hardened Runtime). So it seems that the the helper is not being (re-)signed. If, instead of signing the .app bundle, I run Quinn's codesign comand twice, once on the applet and once on the second executable, then Notary Service is happy with the bundle. I was hoping that, after all these years, codesign is now smart enough to find and sign all of the executables inside a bundle. Both executables are x86_64 non-fat (I guess I should fatten those) and I have installed Xcode 15.1 Beta. Should I file a bug, or am I doing something wrong?
1
0
473
Oct ’23
Are financial/banking aggregators not allowed in the App Store?
Hi! After over a year published in the App Store and with all 5-star ratings, my free, ad-free and open source app has been rejected this week during a routine bugfix update (literally a 1-line change in the code). The reviewer claims my app breaks this rule: (ix) Apps that provide services in highly regulated fields (such as banking and financial services, healthcare, gambling, legal cannabis use, and air travel) or that require sensitive user information should be submitted by a legal entity that provides the services, and not by an individual developer. Apps that facilitate the legal sale of cannabis must be geo-restricted to the corresponding legal jurisdiction. All my app does is use an open, public and free API offered by an investment firm in my country that allows their customers to access their account data programatically. This allows them to integrate things like their account balance or history in spreadsheets, websites, widgets, etc. For instance, people are already using Scriptable to create homescreen widgets that show their live balance in the homescreen. You just log in to the official firm's website, generate a personal token, and then input that token in whichever app/spreadsheet you want in order to make the corresponding HTTP requests. Now, my app does NOT collect any data whatsoever. When you open it, the app fetches your account data from these GET (read-only) endpoints and shows it to you with a nice presentation, including pleasant interactive charts that users really like. But the data only lives in memory, and as soon as you exit the app, it's all gone. No account creation, no data collection, no data storage, nothing. Zero. It's like sending a Postman request, but having the response plotted in nice charts for you. That's all. The ONLY thing that can (optionally) be stored locally in your device is your access token, so you don't have to copy and paste it every time you open the app. And it is securely encrypted in your iPhone and protected biometrically. That's it. The reviewer claims that, because my app presents sensitive financial information to the user, it must be published directly through the official company account of the investment firm, not by me. But isn't that what hundreds of popular banking/brokerage aggregators do? They just use read-only, open APIs to consolidate all your positions across banks/broker accounts, then present it to you in a single place. I understand these apps are not breaking any rules, right? So how is my app different? Am I missing something? To add to this, the investment firm is well aware of the existence of my app, and they not only approve of it, but are highly supportive and have encouraged me to continue improving it, as it shows the kind of things that are possible with their API. They've repeatedly helped me solve technical doubts whenever I've had any issues. So this is really a win-win for everyone and there's zero conflicts here. Do you think the reviewer is right? Or is he misinterpreting the policy? My impression is that the policy is aimed at apps that COLLECT sensitive data, not those who just PRESENT it to the user. But even though I've tried to explain this to him, he won't budge. What options do I have? Just to be clear, my app doesn't offer "financial services" of any kind on top of this. It simply shows you the same information you can see in the raw JSON that the API returns, or in the official app/website, but in a nicer format. It's clean, aseptic, unadulterated data, without any commercial business behind it. No offering or soliciting of any other products, just a pure and clean presentation of the data. Any advice would be greatly appreciated, as I'd like to get a second opinion before sending a FOURTH reply to the reviewer. I'd hate having to make my app an Android exclusive because of a simple policy misinterpretation :(
4
0
569
Oct ’23
Not using "Required Reason API", but actually receiving same output through invoking system call
stat() is in the "Required Reason API" list. https://developer.apple.com/documentation/bundleresources/privacy_manifest_files/describing_use_of_required_reason_api I do not use stat() in my app, but I use assembler instruction to invoke stat system call. And for a security purpose, I use its return value to check existence of some files and directories outside the app container. I use system call instead of API for a security reason. Q. Do I have to declare that my app uses "Required Reason API"?
3
0
411
Oct ’23