General:
Forums topic: Privacy & Security
Apple Platform Security support document
Developer > Security
Enabling enhanced security for your app documentation article
Creating enhanced security helper extensions documentation article
Security Audit Thoughts forums post
Cryptography:
Forums tags: Security, Apple CryptoKit
Security framework documentation
Apple CryptoKit framework documentation
Common Crypto man pages — For the full list of pages, run:
% man -k 3cc
For more information about man pages, see Reading UNIX Manual Pages.
On Cryptographic Key Formats forums post
SecItem attributes for keys forums post
CryptoCompatibility sample code
Keychain:
Forums tags: Security
Security > Keychain Items documentation
TN3137 On Mac keychain APIs and implementations
SecItem Fundamentals forums post
SecItem Pitfalls and Best Practices forums post
Investigating hard-to-reproduce keychain problems forums post
App ID Prefix Change and Keychain Access forums post
Smart cards and other secure tokens:
Forums tag: CryptoTokenKit
CryptoTokenKit framework documentation
Mac-specific resources:
Forums tags: Security Foundation, Security Interface
Security Foundation framework documentation
Security Interface framework documentation
BSD Privilege Escalation on macOS
Related:
Networking Resources — This covers high-level network security, including HTTPS and TLS.
Network Extension Resources — This covers low-level network security, including VPN and content filters.
Code Signing Resources
Notarisation Resources
Trusted Execution Resources — This includes Gatekeeper.
App Sandbox Resources
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
General
RSS for tagPrioritize user privacy and data security in your app. Discuss best practices for data handling, user consent, and security measures to protect user information.
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
General:
Forums topic: Privacy & Security
Privacy Resources
Security Resources
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Topic:
Privacy & Security
SubTopic:
General
Hello,
I am working on a script to update an application which bundle ID changed. Only the bundle ID was modified; all other aspects remain unchanged.
This application requires access to "Screen & System Audio Recording" permissions, which are currently granted to the old bundle ID.
The script performs the following steps:
launchctl bootout gui/$(id -u) /Library/LaunchAgents/com.my_agent_1.plist
pkgutil --forget com.my_agent_1
tccutil reset All com.my_agent_1
rm /Library/LaunchAgents/com.my_agent_1.plist
rm -rf </path/to/com_my_agent_1>
installer -dumplog -allowUntrusted -pkg </path/to/com_my_agent_2.pkg> -target /
...
When running steps #1-6 without a restart between steps #5 and #6, the old bundle ID (com.my_agent_1) remains visible in TCC.db (verified via SQL queries).
Looks like this is the reason why "com.my_agent_2" is not automatically added to the permission list (requiring manual add).
Moreover, "tccutil reset All com.my_agent_1" does not work anymore, the error:
tccutil: No such bundle identifier "com.my_agent_1": The operation couldn’t be completed. (OSStatus error -10814.)
Is there any way to completely clear the "Privacy & Security" permissions without requiring a system restart?
Thank you a lot for your help in advance!
Hi,
My MACOS app has sensitive content and dont want user to take screenshot or to record the screen.
I tries window.sharingType=none. With this user can still record the screen.
I know that user can record with external device. But we dont want him to record using screen capture.
Can you please tell me how to detect when screen recording is active in MACOs apps? or how to prevent screen recording in MACOs apps.
Thanks
Hi,
I am developing a Platform SSO in order to have integrated with our IdP, which I am also adapting to provide the right endpoints for Platform SSO.
I have a few questions about the implementation:
does the client-request-id need to be present on all requests? Is it unique per request, or requests that are bound together like those requesting a nonce and those who will use that nonce should use the same client-request-id?
I am not sure how the loginManager.presentRegistrationViewController works. I'd like to get the user to authenticate to my IdP before device registration. So I am not sure if I should provide my own Webview or something similar or if this method should do something for me;
My idea is to request user authentication once, save the state when performing device registration, so that I avoid asking for user authentication twice when performing user registration. Is this the right way to do it?
How does platform SSO handles tokens? If one application of my IdP requests the authentication on a common OIDC/OAuth2 flow, should I perform some sort of token exchange?
How about SAML? Platform SSO seems to be token-centric, but how does one handle SAML flows? Is it by using WebView as well?
Hello everyone,
I’ve been working on ways to implement stricter accountability systems for personal use, especially to prevent access to NSFW content in apps like Reddit and Twitter. The main challenge is that iOS sandboxing and privacy policies block apps from monitoring or interacting with other apps on the system.
While Apple’s focus on privacy is important, there’s a clear need for an opt-in exception for accountability tools. These tools could be allowed enhanced permissions under stricter oversight to help users maintain accountability and integrity without compromising safety.
Here are a few ideas I’ve been thinking about:
1. Vetted Apps with Enhanced Permissions: Allow trusted applications to bypass sandbox restrictions with user consent and close monitoring by Apple.
2. Improved Parental Controls: Add options to send notifications to moderators (like accountability partners) when restrictions are bypassed or disabled.
3. Custom Keyboard or API Access: Provide a framework for limited system-wide text monitoring for specific use cases, again with user consent.
If anyone has ideas for how to address this within current policies—or suggestions for advocating for more flexibility—I’d appreciate the input. I’m curious how others have handled similar challenges or if there are better approaches I haven’t considered.
Hello,
we're currently evaluating the side effects of transferring our app to a different Apple developer account. Our users use SIWA to sign in to our platform which uses Auth0.
As I understand it, the identifiers provided by Apple will change, and as such Auth0 will not recognise them and treat them as new users. I've read conflicting documentation, reports, discussions, etc, so it would be great if I could get some clarification on the topic.
Furthermore we're concerned about the Hide My Email functionality. A lot of our users use this feature. Will the relay email for each user change with the transfer? If so, does the 'old' relay email stop working as soon as the transfer happens?
Thanks in advance!
News link: https://developer.apple.com/news/?id=12m75xbj
If your app offers Sign in with Apple, you’ll need to use the Sign in with Apple REST API to revoke user tokens when deleting an account.
I'm not good English. I'm confused about the above sentence
Do I have to use REST API unconditionally or can I just delete to the account data?
Topic:
Privacy & Security
SubTopic:
General
Tags:
App Review
Sign in with Apple REST API
Sign in with Apple
Is there a way (in code or on the OAuth2 server/webpage) to specify the desired window size when using ASWebAuthenticationSession on macOS? I haven't found anything, and we would prefer the window to be narrower. For one of our users, the window is even stretched to the full screen width which looks completely broken…
Hey there, I used our team's account to configure sign in with Apple, the mode is pop up, my clientId scope redirectUrl state are both correct. I got Failed to verify your identity. Try again., actually my account is valid because I can login to my mac and every apple website. I have tried many apple accounts and still got this error. That was so weird, I didn't find a solution online. Pls help me thanks.
Hello,
We received a rejection on one of our IOS applications because we were doing Microsoft MSAL login through the user's browser. The representative recommended that we use Webview to do in-app logins. However when we tried to handle the custom app uri redirection (looking like myapp://auth/), Webview does not seem to send the user back to the application. Does anyone have a fix for this?
Thanks!
Topic:
Privacy & Security
SubTopic:
General
Tags:
Safari and Web
UI Frameworks
Authentication Services
WebKit
When developing and testing using my phone I got prompted for allowing app tracking. I later uploaded a build to TestFlight, deleted the old testing app and installed the TestFlight build. I am now stuck in an infinite loop of not getting prompted for allowing app tracking for the app. When entering the app settings the toggle for tracking never appears which leaves me not able to enter the app's content. My guess is that the prompt can only be shown once for the app bundle, but there has to be a way for me to get prompted again without changing the app bundle id. Help is appreciated since this app is scheduled to be published in a week.
Hey there,
I’m currently exploring the possibility of integrating Sign in with Apple into my iOS app and backend.
Regarding the iOS app, I’ve read that when a user is signed in, you always need to call getCredentialState on the app’s launch. Is this true? If so, how is it possible to sign the user out then?
I intend to incorporate SwiftData and CloudKit into my application. In light of this, I’m curious about your approach to user management. Specifically, I’m wondering if you would store the user’s data in a Redis database after successful authentication on the backend. Or, would you separate the user data and save it using SwiftData/ CloudKit?
I am using Auth0 as a login manager for our app. The way Auth0 handles login is that their SDK will create a web view where the login is actually handled. Once the login is finished the session will end and the app will gain control. We are not set up for passkeys in their system and can't set up quickly to do that. Unfortunately with the new iOS "passkey is the primary login" way iOS is set up now, users are asked to use passkey when it's not supported on the backend. I don't have direct control of the login screens. Is there any way, at the app level, to tell the app to not use passkeys so that it quits showing up as an option for the users? I can't find any documentation on doing this. How can I stop passkey in my app entirely?
Topic:
Privacy & Security
SubTopic:
General
Tags:
Passkeys in iCloud Keychain
Authentication Services
We're experiencing crashes in our production iOS app related to Apple's DeviceCheck framework. The crash occurs in DCAnalytics internal performance tracking, affecting some specific versions of iOS 18 (18.4.1, 18.5.0).
Crash Signature
CoreFoundation: -[__NSDictionaryM setObject:forKeyedSubscript:] + 460
DeviceCheck: -[DCAnalytics sendPerformanceForCategory:eventType:] + 236
Observed Patterns
Scenario 1 - Token Generation:
Crashed: com.appQueue
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000010
DeviceCheck: -[DCDevice generateTokenWithCompletionHandler:]
Thread: Background dispatch queue
Scenario 2 - Support Check:
Crashed: com.apple.main-thread
EXC_BAD_ACCESS KERN_INVALID_ADDRESS 0x0000000000000008
DeviceCheck: -[DCDevice _isSupportedReturningError:]
DeviceCheck: -[DCDevice isSupported]
Thread: Main thread
Root Cause Analysis
The DCAnalytics component within DeviceCheck attempts to insert a nil value into an NSMutableDictionary when recording performance metrics, indicating missing nil validation before dictionary operations.
Reproduction Context
Crashes occur during standard DeviceCheck API usage:
Calling DCDevice.isSupported property
Calling DCDevice.generateToken(completionHandler:) (triggered by Firebase App Check SDK)
Both operations invoke internal analytics that fail with nil insertion attempts.
Concurrency Considerations
We've implemented sequential access guards around DeviceCheck token generation to prevent race conditions, yet crashes persist. This suggests the issue likely originates within the DeviceCheck framework's internal implementation rather than concurrent access from our application code.
Note: Scenario 2 occurs through Firebase SDK's App Check integration, which internally uses DeviceCheck for attestation.
Request
Can Apple engineering confirm if this is a known issue with DeviceCheck's analytics subsystem? Is there a recommended workaround to disable DCAnalytics or ensure thread-safe DeviceCheck API usage?
Any guidance on preventing these crashes would be appreciated.
This post is an extension to Importing Cryptographic Keys that covers one specific common case: importing a PEM-based RSA private key and its certificate to form a digital identity.
If you have questions or comments, start a new thread in Privacy & Security > General. Tag your thread with Security so that I see it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Importing a PEM-based RSA Private Key and its Certificate
I regularly see folks struggle to import an RSA private key and its corresponding certificate. Importing Cryptographic Keys outlines various options for importing keys, but in this post I want to cover one specific case, namely, a PEM-based RSA private key and its corresponding certificate. Together these form a digital identity, represented as a SecIdentity object.
IMPORTANT If you can repackage your digital identity as a PKCS#12, please do. It’s easy to import that using SecPKCS12Import. If you can switch to an elliptic curve (EC) private key, please do. It’s generally better and Apple CryptoKit has direct support for importing an EC PEM.
Assuming that’s not the case, let’s explore how to import a PEM-base RSA private key and its corresponding certificate to form a digital identity.
Note The code below was built with Xcode 16.2 and tested on the iOS 18.2 simulator. It uses the helper routines from Calling Security Framework from Swift.
This code assumes the data protection keychain. If you’re targeting macOS, add kSecUseDataProtectionKeychain to all the keychain calls. See TN3137 On Mac keychain APIs and implementations for more background to that.
Unwrap the PEM
To start, you need to get the data out of the PEM:
/// Extracts the data from a PEM.
///
/// As PEM files can contain a large range of data types, you must supply the
/// expected prefix and suffix strings. For example, for a certificate these
/// are `"-----BEGIN CERTIFICATE-----` and `-----END CERTIFICATE-----`.
///
/// - important: This assumes the simplest possible PEM format. It does not
/// handle metadata at the top of the PEM or PEMs with multiple items in them.
func dataFromPEM(_ pem: String, _ expectedPrefix: String, _ expectedSuffix: String) -> Data? {
let lines = pem.split(separator: "\n")
guard
let first = lines.first,
first == expectedPrefix,
let last = lines.last,
last == expectedSuffix
else { return nil }
let base64 = lines.dropFirst().dropLast().joined()
guard let data = Data(base64Encoded: base64) else { return nil }
return data
}
IMPORTANT Read the doc comment to learn about some important limitations with this code.
Import a Certificate
When adding a digital identity to the keychain, it’s best to import the certificate and the key separately and then add them to the keychain. That makes it easier to track down problems you encounter.
To import a PEM-based certificate, extract the data from the PEM and call SecCertificateCreateWithData:
/// Import a certificate in PEM format.
///
/// - important: See ``dataFromPEM(_:_:_:)`` for some important limitations.
func importCertificatePEM(_ pem: String) throws -> SecCertificate {
guard
let data = dataFromPEM(pem, "-----BEGIN CERTIFICATE-----", "-----END CERTIFICATE-----"),
let cert = SecCertificateCreateWithData(nil, data as NSData)
else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(errSecParam), userInfo: nil) }
return cert
}
Here’s an example that shows this in action:
let benjyCertificatePEM = """
-----BEGIN CERTIFICATE-----
MIIC4TCCAcmgAwIBAgIBCzANBgkqhkiG9w0BAQsFADAfMRAwDgYDVQQDDAdNb3Vz
ZUNBMQswCQYDVQQGEwJHQjAeFw0xOTA5MzAxNDI0NDFaFw0yOTA5MjcxNDI0NDFa
MB0xDjAMBgNVBAMMBUJlbmp5MQswCQYDVQQGEwJHQjCCASIwDQYJKoZIhvcNAQEB
BQADggEPADCCAQoCggEBAOQe5ai68FQhTVIgpsDK+UOPIrgKzqJcW+wwLnJRp6GV
V9EmifJq7wjrXeqmP1XgcNtu7cVhDx+/ONKl/8hscak54HTQrgwE6mK628RThld9
BmZoOjaWWCkoU5bH7ZIYgrKF1tAO5uTAmVJB9v7DQQvKERwjQ10ZbFOW6v8j2gDL
esZQbFIC7f/viDXLsPq8dUZuyyb9BXrpEJpXpFDi/wzCV3C1wmtOUrU27xz4gBzi
3o9O6U4QmaF91xxaTk0Ot+/RLI70mR7TYa+u6q7UW/KK9q1+8LeTVs1x24VA5csx
HCAQf+xvMoKlocmUxCDBYkTFkmtyhmGRN52XucHgu0kCAwEAAaMqMCgwDgYDVR0P
AQH/BAQDAgWgMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMCMA0GCSqGSIb3DQEBCwUA
A4IBAQAyrArH7+IyHTyEOrv/kZr3s3h4HWczSVeiO9qWD03/fVew84J524DiSBK4
mtAy3V/hqXrzrQEbsfyT7ZhQ6EqB/W0flpVYbku10cSVgoeSfjgBJLqgJRZKFonv
OQPjTf9HEDo5A1bQdnUF1y6SwdFaY16lH9mZ5B8AI57mduSg90c6Ao1GvtbAciNk
W8y4OTQp4drh18hpHegrgTIbuoWwgy8V4MX6W39XhkCUNhrQUUJk3mEfbC/yqfIG
YNds0NRI3QCTJCUbuXvDrLEn4iqRfbzq5cbulQBxBCUtLZFFjKE4M42fJh6D6oRR
yZSx4Ac3c+xYqTCjf0UdcUGxaxF/
-----END CERTIFICATE-----
"""
print(try? importCertificatePEM(benjyCertificatePEM))
If you run this it prints:
Optional(<cert(0x11e304c10) s: Benjy i: MouseCA>)
Import a Private Key
To import a PEM-base RSA private key, extract the data from the PEM and call SecKeyCreateWithData:
/// Import an 2048-bit RSA private key in PEM format.
///
/// Don’t use this code if:
///
/// * If you can switch to an EC key. EC keys are generally better and, for
/// this specific case, there’s support for importing them in Apple CryptoKit.
///
/// * You can switch to using a PKCS#12. In that case, use the system’s
/// `SecPKCS12Import` routine instead.
///
/// - important: See ``dataFromPEM(_:_:_:)`` for some important limitations.
func importRSA2048PrivateKeyPEM(_ pem: String) throws -> SecKey {
// Most private key PEMs are in PKCS#8 format. There’s no way to import
// that directly. Instead you need to strip the header to get to the
// `RSAPrivateKey` data structure encapsulated within the PKCS#8. Doing that
// in the general case is hard. In the specific case of an 2048-bit RSA
// key, the following hack works.
let rsaPrefix: [UInt8] = [
0x30, 0x82, 0x04, 0xBE, 0x02, 0x01, 0x00, 0x30,
0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x01, 0x01, 0x05, 0x00, 0x04, 0x82,
0x04, 0xA8,
]
guard
let pkcs8 = dataFromPEM(pem, "-----BEGIN PRIVATE KEY-----", "-----END PRIVATE KEY-----"),
pkcs8.starts(with: rsaPrefix)
else { throw NSError(domain: NSOSStatusErrorDomain, code: Int(errSecParam), userInfo: nil) }
let rsaPrivateKey = pkcs8.dropFirst(rsaPrefix.count)
return try secCall { SecKeyCreateWithData(rsaPrivateKey as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
] as NSDictionary, $0) }
}
IMPORTANT This code only works with 2048-bit RSA private keys. The comments explain more about that limitation.
Here’s an example that shows this in action:
let benjyPrivateKeyPEM = """
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDkHuWouvBUIU1S
IKbAyvlDjyK4Cs6iXFvsMC5yUaehlVfRJonyau8I613qpj9V4HDbbu3FYQ8fvzjS
pf/IbHGpOeB00K4MBOpiutvEU4ZXfQZmaDo2llgpKFOWx+2SGIKyhdbQDubkwJlS
Qfb+w0ELyhEcI0NdGWxTlur/I9oAy3rGUGxSAu3/74g1y7D6vHVGbssm/QV66RCa
V6RQ4v8MwldwtcJrTlK1Nu8c+IAc4t6PTulOEJmhfdccWk5NDrfv0SyO9Jke02Gv
ruqu1FvyivatfvC3k1bNcduFQOXLMRwgEH/sbzKCpaHJlMQgwWJExZJrcoZhkTed
l7nB4LtJAgMBAAECggEBAKOPF6ED776SZgrliEog/dmXrhABB6jXybytyw+CRkuP
dXhrRmr+isZ9Y0gTzMN4+dILVgW4EozzoP0/sgZ04oWwDqQS30eU2qzRRzMbo+3k
oYsZXeu3nhxcYppwXIDsfAEd/ygMFzaadRPKYhrFykR2rA/dpLYCvW2tfm5SuULp
RxnKykFlVi8yVT64AovVm0XGOy/QTO5BBbUdftvZY9QCjGn/IEL8QFEz0rxZsb2L
s0HgVMUcB1My38RksZQRKLMWCtqLqWnez3oCnPka+dxFQj5RU//vNtRoVh1ExbmW
txHz48v00AKQvaudC4ujIspZlY8+UPdYQT0TNjhsfoUCgYEA+7yEvyCgRtYwUNm6
jHTg67LoSldHwENOry63qGZp3rCkWBkPXle7ulgRtuw+e11g4MoMMAgkIGyIGB/Z
6YvnQGmJCTMw+HHIyw3k/OvL1iz4DM+QlxDuD79Zu2j2UIL4maDG0ZDskiJujVAf
sFOy4r36TvYedmd7qgh9pgpsFl8CgYEA5/v8PZDs2I1wSDGllGfTr6aeQcxvw98I
p8l/8EV/lYpdKQMFndeFZI+dnJCcTeBbeXMmPNTAdL5gOTwDReXamIAdr93k7/x6
iKMHzBrpQZUMEhepSd8zdR1+vLvyszvUU6lvNXcfjwbu7gJQkwbA6kSoXRN+C1Cv
i5/w66t0f1cCgYBt02FWwTUrsmaB33uzq4o1SmhthoaXKsY5R3h4z7WAojAQ/13l
GwGb2rBfzdG0oJiTeZK3odWhD7iQTdUUPyU0xNY0XVEQExQ3AmjUr0rOte/CJww9
2/UAicrsKG7N0VYEMFCNPVz4pGz22e35T4rLwXZi3J2NqrgZBntK5WEioQKBgEyx
L4ii+sn0qGQVlankUUVGjhcuoNxeRZxCrzsdnrovTfEbAKZX88908yQpYqMUQul5
ufBuXVm6/lCtmF9pR8UWxbm4X9E+5Lt7Oj6tvuNhhOYOUHcNhRN4tsdqUygR5XXr
E8rXIOXF4wNoXH7ewrQwEoECyq6u8/ny3FDtE8xtAoGBALNFxRGikbQMXhUXj7FA
lLwWlNydCxCc7/YwlHfmekDaJRv59+z7SWAR15azhbjqS9oXWJUQ9uvpKF75opE7
MT0GzblkKAYu/3uhTENCjQg+9RFfu5w37E5RTWHD2hANV0YqXUlmH3d+f5uO0xN7
7bpqwYuYzSv1hBfU/yprDco6
-----END PRIVATE KEY-----
"""
print(try? importRSA2048PrivateKeyPEM(benjyPrivateKeyPEM))
If you run this it prints:
Optional(<SecKeyRef algorithm id: 1, key type: RSAPrivateKey, version: 4, 2048 bits (block size: 256), addr: 0x600000c5ce50>)
Form a Digital Identity
There are two common ways to form a digital identity:
SecPKCSImport
SecItemCopyMatching
SecPKCSImport is the most flexible because it gives you an in-memory digital identity. You can then choose to add it to the keychain or not. However, it requires a PKCS#12 as input. If you’re starting out with separate private key and certificate PEMs, you have to use SecItemCopyMatching.
Note macOS also has SecIdentityCreateWithCertificate, but it has some seriously limitations. First, it’s only available on macOS. Second, it requires the key to be in the keychain. If you’re going to add the key to the keychain anyway, you might as well use SecItemCopyMatching.
To form a digital identity from a separate private key and certificate:
Add the certificate to the keychain.
Add the private key to the keychain.
Call SecItemCopyMatching to get back a digital identity.
Here’s an example of that in action:
/// Imports a digital identity composed of separate certificate and private key PEMs.
///
/// - important: See ``dataFromPEM(_:_:_:)`` for some important limitations.
/// See ``importRSA2048PrivateKeyPEM(_:)`` for alternative strategies that are
/// much easier to deploy.
func addRSA2048DigitalIdentityPEMToKeychain(certificate: String, privateKey: String) throws -> SecIdentity {
// First import the certificate and private key. This has the advantage in
// that it triggers an early failure if the data is in the wrong format.
let certificate = try importCertificatePEM(certificate)
let privateKey = try importRSA2048PrivateKeyPEM(privateKey)
// Check that the private key matches the public key in the certificate. If
// not, someone has given you bogus credentials.
let certificatePublicKey = try secCall { SecCertificateCopyKey(certificate) }
let publicKey = try secCall { SecKeyCopyPublicKey(privateKey) }
guard CFEqual(certificatePublicKey, publicKey) else {
throw NSError(domain: NSOSStatusErrorDomain, code: Int(errSecPublicKeyInconsistent))
}
// Add the certificate first. If that fails — and the most likely error is
// `errSecDuplicateItem` — we want to stop immediately.
try secCall { SecItemAdd([
kSecValueRef: certificate,
] as NSDictionary, nil) }
// The add the private key.
do {
try secCall { SecItemAdd([
kSecValueRef: privateKey,
] as NSDictionary, nil) }
} catch let error as NSError {
// We ignore a `errSecDuplicateItem` error when adding the key. It’s
// possible to have multiple digital identities that share the same key,
// so if you try to add the key and it’s already in the keychain then
// that’s fine.
guard error.domain == NSOSStatusErrorDomain, error.code == errSecDuplicateItem else {
throw error
}
}
// Finally, search for the resulting identity.
//
// I originally tried querying for the identity based on the certificate’s
// attributes — the ones that contribute to uniqueness, namely
// `kSecAttrCertificateType`, `kSecAttrIssuer`, and `kSecAttrSerialNumber` —
// but that failed for reasons I don't fully understand (r. 144152660). So
// now I get all digital identities and find the one with our certificate.
let identities = try secCall { SecItemCopyMatching([
kSecClass: kSecClassIdentity,
kSecMatchLimit: kSecMatchLimitAll,
kSecReturnRef: true,
] as NSDictionary, $0) } as! [SecIdentity]
let identityQ = try identities.first { i in
try secCall { SecIdentityCopyCertificate(i, $0) } == certificate
}
return try secCall(Int(errSecItemNotFound)) { identityQ }
}
IMPORTANT This code is quite subtle. Read the comments for an explanation as to why it works the way it does.
Further reading
For more information about the APIs and techniques used above, see:
Importing Cryptographic Keys
On Cryptographic Keys Formats
SecItem: Fundamentals
SecItem: Pitfalls and Best Practices
Calling Security Framework from Swift
TN3137 On Mac keychain APIs and implementations
Finally, for links to documentation and other resources, see Security Resources.
Revision History
2025-02-13 Added code to check for mismatched private key and certificate.
2025-02-04 First posted.
We are currently trying to fix a bug when using SignIn with Apple. It appears that on some occasions we are not receiving a user's profile info (name, email) when a new account is created.
After doing some investigation we believe this bug is due to the same Apple login being used as an already deleted account. ASF only appears to send profile info the very first time an Apple login is used. If that account is deleted and another is created with the same apple login we won't receive the profile info.
As a result we are not in compliance with Apple's guidelines requiring that we use the provided profile info with Apple SigIn, and need to prompt users to enter it again.
Is there a process in place to properly "clear" a user after their account is deleted in our system, so that the next time a user creates an account with the same Apple login, we receive their profile info again?
Developers of our e-shop are preparing to enable Apple Sign In for account login.
Apple ID verification is conducted via the domain appleid.apple.com, and the responses should be coming back from the following two Apple IP addresses:
IPv4 Address: 17.32.194.6
IPv4 Address: 17.32.194.37
Question is whether these addresses are correct and if they remain unchanged over time. Alternatively, it is existing an official list of IP addresses that may be used for Apple Sign In verification response?
This is necessary to ensure precise network communication settings and protection by F5 security solution.
Thanks a lot for answers.
From watching the video on App Attest the answer would appear to be no, but the video is a few years old so in hope, I thought I would post this question anyway.
There's several scenarios where I would like a notification service extension to be able to use App Attest in communications with the back end(for example to send a receipt to the backend acknowledging receipt of the push, fetching an image from a url in the push payload, a few others).
Any change App Attest can be used in by a notification service extension?
this is my monitor image that shows DeviceCheck api responding very slowly.
Hi Apple Devs,
For our app, we utilize passkeys for account creation (not MFA). This is mainly for user privacy, as there is 0 PII associated with passkey account creation, but it additionally also satisfies the 4.8: Login Services requirement for the App Store.
However, we're getting blocked in Apple Review. Because the AASA does not get fetched immediately upon app install, the reviewers are not able to create an account immediately via passkeys, and then they reject the build.
I'm optimistic I can mitigate the above. But even if we pass Apple Review, this is a pretty catastrophic issue for user security and experience. There are reports that 5% of users cannot create passkeys immediately (https://developer.apple.com/forums/thread/756740). That is a nontrivial amount of users, and this large of an amount distorts how app developers design onboarding and authentication flows towards less secure experiences:
App developers are incentivized to not require MFA setup on account creation because requiring it causes significant churn, which is bad for user security.
If they continue with it anyways, for mitigation, developers are essentially forced to add in copy into their app saying something along the lines of "We have no ability to force Apple to fetch the config required to continue sign up, so try again in a few minutes, you'll just have to wait."
You can't even implement a fallback method. There's no way to check if the AASA is available before launching the ASAuthorizationController so you can't mitigate a portion of users encountering an error!!
Any app that wants to use the PRF extension to encrypt core functionality (again, good for user privacy) simply cannot exist because the app simply does not work for an unspecified amount of time for a nontrivial portion of users.
It feels like a. Apple should provide a syscall API that we can call to force SWCD to verify the AASA or b. implement a config based on package name for the app store such that the installation will immediately include a verified AASA from Apple's CDN. Flicking the config on would require talking with Apple. If this existed, this entire class of error would go away.
It feels pretty shocking that there isn't a mitigation in place for this already given that it incentivizes app developers to pursue strictly less secure and less private authentication practices.
Topic:
Privacy & Security
SubTopic:
General
Tags:
Authentication Services
Universal Links
Passkeys in iCloud Keychain