AFAIU a new screen capture notification was added within the Control Center in Sequoia 15.2, see attached examples:
My question is whether there is some way to suppress this notification preferably via an MDM configuration profile.
See also https://discussions.apple.com/thread/255886645?sortBy=rank for more information.
Thanks,
Doron.
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
E aí pessoal, tudo certo?
Estou desenvolvendo um app com React Native no front-end e Node.js no back-end, usando o Firebase como banco de dados (e possivelmente para autenticação também, dependendo da solução). Preciso implementar o "Sign in with Apple" e estou com algumas dúvidas em como integrar tudo isso.
A ideia é: o usuário clica no botão "Entrar com a Apple" no app (React Native), o backend (Node.js) processa a autenticação com a Apple e, em seguida, armazena as informações necessárias (nome, email, etc.) no Firebase.
Se alguém já trabalhou com essa combinação (React Native, Node.js, Firebase e Sign in with Apple) e puder compartilhar alguma experiência, dicas, exemplos de código ou até mesmo um boilerplate, seria de grande ajuda!
I regularly see folks confused by the difference in behaviour of app groups between macOS and iOS. There have been substantial changes in this space recently. While much of this is now covered in the official docs (r. 92322409), I’ve updated this post to go into all the gory details.
If you have questions or comments, start a new thread with the details. Put it in the App & System Services > Core OS topic area and tag it with Code Signing and Entitlements. Oh, and if your question is about app group containers, also include Files and Storage.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
App Groups: macOS vs iOS: Working Towards Harmony
There are two styles of app group ID:
iOS-style app group IDs start with group., for example, group.eskimo1.test.
macOS-style app group IDs start with your Team ID, for example, SKMME9E2Y8.eskimo1.test.
This difference has been the source of numerous weird problems over the years. Starting in Feb 2025, iOS-style app group IDs are fully supported on macOS for all product types [1]. If you’re writing new code that uses app groups, use an iOS-style app group ID. If you have existing code that uses a macOS-style app group ID, consider how you might transition to the iOS style.
IMPORTANT The Feb 2025 changes aren’t tied to an OS release but rather to a Developer website update. For more on this, see Feb 2025 Changes, below.
[1] If your product is a standalone executable, like a daemon or agent, wrap it in an app-like structure, as explained in Signing a daemon with a restricted entitlement.
iOS-Style App Group IDs
An iOS-style app group ID has the following features:
It starts with the group. prefix, for example, group.eskimo1.test.
You allocate it on the Developer website. This assigns the app group ID to your team.
You then claim access to it by listing it in the App Groups entitlement (com.apple.security.application-groups) entitlement.
That claim must be authorised by a provisioning profile [1]. The Developer website will only let you include your team’s app group IDs in your profile.
For more background on provisioning profiles, see TN3125 Inside Code Signing: Provisioning Profiles.
iOS-style app group IDs originated on iOS with iOS 3.0. They’ve always been supported on iOS’s child platforms (iPadOS, tvOS, visionOS, and watchOS). On the Mac:
They’ve been supported by Mac Catalyst since that technology was introduced.
Likewise for iOS Apps on Mac.
Starting in Feb 2025, they’re supported for other Mac products.
[1] Strictly speaking macOS does not require that, but if your claim is not authorised by a profile then you might run into other problems. See Entitlements-Validated Flag, below.
macOS-Style App Group IDs
A macOS-style app group ID has the following features:
It should start with your Team ID [1], for example, SKMME9E2Y8.eskimo1.test.
It can’t be explicitly allocated on the Developer website.
Code that isn’t sandboxed doesn’t need to claim the app group ID in the App Groups entitlement. [2]
To use an app group, claim the app group ID in the App Groups entitlement.
The App Groups entitlement is not restricted on macOS, meaning that this claim doesn’t need to be authorised by a provisioning profile [3].
However, if you claim an app group ID that’s not authorised in some way, you might run into problems. More on that later in this post.
If you submit an app to the Mac App Store, the submission process checks that your app group IDs make sense, that is, they either start with your Team ID (macOS style) or are assigned to your team (iOS style).
[1] This is “should” because, historically, macOS has not actually required it. However, that’s now changing, with things like app group container protection.
[2] This was true prior to macOS 15. It may still technically be true in macOS 15 and later, but the most important thing, access to the app group container, requires the entitlement because of app group container protection.
[3] Technically it’s a validation-required entitlement, something that we’ll come back to in the Entitlements-Validated Flag section.
Feb 2025 Changes
On 21 Feb 2025 we rolled out a change to the Developer website that completes the support for iOS-style app group IDs on the Mac. Specifically, it’s now possible to create a Mac provisioning profile that authorises the use of an iOS-style app group ID.
Note This change doesn’t affect Mac Catalyst or iOS Apps on Mac, which have always been able to use iOS-style app group IDs on the Mac.
Prior to this change it was possible to use an iOS-style app group ID on the Mac but that might result in some weird behaviour. Later sections of this post describe some of those problems. Of course, that information is now only of historical interest because, if you’re using an iOS-style app group, you can and should authorise that use with a provisioning profile.
We also started seeding Xcode 16.3, which has since been release. This is aware of the Developer website change, and its Signing & Capabilities editor actively encourages you to use iOS-style app groups IDs in all products.
Note This Xcode behaviour is the only option for iOS and its child platforms. With Xcode 16.3, it’s now the default for macOS as well. If you have existing project, enable this behaviour using the Register App Groups build setting.
Finally, we updated a number of app group documentation pages, including App Groups entitlement and Configuring app groups.
Crossing the Streams
In some circumstances you might need to have a single app that accesses both an iOS- and a macOS-style app group. For example:
You have a macOS app.
You want to migrate to an iOS-style app group ID, perhaps because you want to share an app group container with a Mac Catalyst app.
But you also need to access existing content in a container identified by a macOS-style app group ID.
Historically this caused problems (FB16664827) but, as of Jun 2025, this is fully supported (r. 148552377).
When the Developer website generates a Mac provisioning profile for an App ID with the App Groups capability, it automatically adds TEAM_ID.* to the list of app group IDs authorised by that profile (where TEAM_ID is your Team ID). This allows the app to claim access to every iOS-style app group ID associated with the App ID and any macOS-style app group IDs for that team. This helps in two circumstances:
It avoids any Mac App Store Connect submission problems, because App Store Connect can see that the app’s profile authorises its use of all the it app group IDs it claims access to.
Outside of App Store — for example, when you directly distribute an app using Developer ID signing — you no longer have to rely on macOS granting implicit access to macOS-style app group IDs. Rather, such access is explicitly authorised by your profile. That ensures that your entitlements remain validated, as discussed in the Entitlements-Validated Flag, below.
A Historical Interlude
These different styles of app group IDs have historical roots:
On iOS, third-party apps have always used provisioning profiles, and thus the App Groups entitlement is restricted just like any other entitlement.
On macOS, support for app groups was introduced before macOS had general support for provisioning profiles [1], and thus the App Groups entitlement is unrestricted.
The unrestricted nature of this entitlement poses two problems. The first is accidental collisions. How do you prevent folks from accidentally using an app group ID that’s in use by some other developer?
On iOS this is easy: The Developer website assigns each app group ID to a specific team, which guarantees uniqueness. macOS achieved a similar result by using the Team ID as a prefix.
The second problem is malicious reuse. How do you prevent a Mac app from accessing the app group containers of some other team?
Again, this isn’t an issue on iOS because the App Groups entitlement is restricted. On macOS the solution was for the Mac App Store to prevent you from publishing an app that used an app group ID that’s used by another team.
However, this only works for Mac App Store apps. Directly distributed apps were free to access app group containers of any other app. That was considered acceptable back when the Mac App Store was first introduced. That’s no longer the case, which is why macOS 15 introduced app group container protection. See App Group Container Protection, below.
[1] I’m specifically talking about provisioning profiles for directly distributed apps, that is, apps using Developer ID signing.
Entitlements-Validated Flag
The fact that the App Groups entitlement is unrestricted on macOS is, when you think about it, a little odd. The purpose of entitlements is to gate access to functionality. If an entitlement isn’t restricted, it’s not much of a gate!
For most unrestricted entitlements that’s not a problem. Specifically, for both the App Sandbox and Hardened Runtime entitlements, those are things you opt in to, so macOS is happy to accept the entitlement at face value. After all, if you want to cheat you can just not opt in [1].
However, this isn’t the case for the App Groups entitlement, which actually gates access to functionality. Dealing with this requires macOS to walk a fine line between security and compatibility. Part of that solution is the entitlements-validated flag.
When a process runs an executable, macOS checks its entitlements. There are two categories:
Restricted entitlements must be authorised by a provisioning profile. If your process runs an executable that claims a restricted entitlement that’s not authorised by a profile, the system traps.
Unrestricted entitlements don’t have to be authorised by a provisioning profile; they can be used by any code at any time.
However, the App Groups entitlement is a special type of unrestricted entitlement called a validation-required entitlement. If a process runs an executable that claims a validation-required entitlement and that claim is not authorised by a profile, the system allows the process to continue running but clears its entitlements-validated flag.
Some subsystems gate functionality on the entitlements-validated flag. For example, the data protection keychain uses entitlements as part of its access control model, but refuses to honour those entitlements if the entitlement-validated flag has been cleared.
Note If you’re curious about this flag, use the procinfo subcommand of launchctl to view it. For example:
% sudo launchctl procinfo `pgrep Test20230126`
…
code signing info = valid
…
entitlements validated
…
If the flag has been cleared, this line will be missing from the code signing info section.
Historically this was a serious problem because it prevented you from creating an app that uses both app groups and the data protection keychain [2] (r. 104859788). Fortunately that’s no longer an issue because the Developer website now lets you include the App Groups entitlement in macOS provisioning profiles.
[1] From the perspective of macOS checking entitlements at runtime. There are other checks:
The App Sandbox is mandatory for Mac App Store apps, but that’s checked when you upload the app to App Store Connect.
Directly distributed apps must be notarised to pass Gatekeeper, and the notary service requires that all executables enable the hardened runtime.
[2] See TN3137 On Mac keychain APIs and implementations for more about the data protection keychain.
App Groups and the Keychain
The differences described above explain a historical oddity associated with keychain access. The Sharing access to keychain items among a collection of apps article says:
Application groups
When you collect related apps into an application group using
the App Groups entitlement, they share access to a
group container, and gain the ability to message each other in
certain ways. You can use app group names as keychain access
group names, without adding them to the Keychain Access Groups
entitlement.
On iOS this makes a lot of sense:
The App Groups entitlement is a restricted entitlement on iOS.
The Developer website assigns each iOS-style app group ID to a specific team, which guarantees uniqueness.
The required group. prefix means that these keychain access groups can’t collide with other keychain access groups, which all start with an App ID prefix (there’s also Apple-only keychain access groups that start with other prefixes, like apple).
However, this didn’t work on macOS [1] because the App Groups entitlement is unrestricted there. However, with the Feb 2025 changes it should now be possible to use an iOS-style app group ID as a keychain access group on macOS.
Note I say “should” because I’ve not actually tried it (-:
Keep in mind that standard keychain access groups are protected the same way on all platforms, using the restricted Keychain Access Groups entitlement (keychain-access-groups).
[1] Except for Mac Catalyst apps and iOS Apps on Mac.
Not Entirely Unsatisfied
When you launch a Mac app that uses app groups you might see this log entry:
type: error
time: 10:41:35.858009+0000
process: taskgated-helper
subsystem: com.apple.ManagedClient
category: ProvisioningProfiles
message: com.example.apple-samplecode.Test92322409: Unsatisfied entitlements: com.apple.security.application-groups
Note The exact format of that log entry, and the circumstances under which it’s generated, varies by platform. On macOS 13.0.1 I was able to generate it by running a sandboxed app that claims a macOS-style app group ID in the App Groups entitlement and also claims some other restricted entitlement.
This looks kinda worrying and can be the source of problems. It means that the App Groups entitlement claims an entitlement that’s not authorised by a provisioning profile. On iOS this would trap, but on macOS the system allows the process to continue running. It does, however, clear the entitlements-validate flag. See Entitlements-Validated Flag for an in-depth discussion of this.
The easiest way to avoid this problem is to authorise your app group ID claims with a provisioning profile. If there’s some reason you can’t do that, watch out for potential problems with:
The data protection keychain — See the discussion of that in the Entitlements-Validated Flag and App Groups and the Keychain sections, both above.
App group container protection — See App Group Container Protection, below.
App Group Container Protection
macOS 15 introduced app group container protection. To access an app group container without user intervention:
Claim access to the app group by listing its ID in the App Groups entitlement.
Locate the container by calling the containerURL(forSecurityApplicationGroupIdentifier:) method.
Ensure that at least one of the following criteria are met:
Your app is deployed via the Mac App Store (A).
Or via TestFlight when running on macOS 15.1 or later (B).
Or the app group ID starts with your app’s Team ID (C).
Or your app’s claim to the app group is authorised by a provisioning profile embedded in the app (D) [1].
If your app doesn’t follow these rules, the system prompts the user to approve its access to the container. If granted, that consent applies only for the duration of that app instance.
For more on this, see:
The System Integrity Protection section of the macOS Sequoia 15 Release Notes
The System Integrity Protection section of the macOS Sequoia 15.1 Release Notes
WWDC 2024 Session 10123 What’s new in privacy, starting at 12:23
The above criteria mean that you rarely run into the app group authorisation prompt. If you encounter a case where that happens, feel free to start a thread here on DevForums. See the top of this post for info on the topic and tags to use.
Note Prior to the Feb 2025 change, things generally worked out fine when you app was deployed but you might’ve run into problems during development. That’s no longer the case.
[1] This is what allows Mac Catalyst and iOS Apps on Mac to work.
Revision History
2025-08-12 Added a reference to the Register App Groups build setting.
2025-07-28 Updated the Crossing the Streams section for the Jun 2025 change. Made other minor editorial changes.
2025-04-16 Rewrote the document now that iOS-style app group IDs are fully supported on the Mac. Changed the title from App Groups: macOS vs iOS: Fight! to App Groups: macOS vs iOS: Working Towards Harmony
2025-02-25 Fixed the Xcode version number mentioned in yesterday’s update.
2025-02-24 Added a quick update about the iOS-style app group IDs on macOS issue.
2024-11-05 Further clarified app group container protection. Reworked some other sections to account for this new reality.
2024-10-29 Clarified the points in App Group Container Protection.
2024-10-23 Fleshed out the discussion of app group container protection on macOS 15.
2024-09-04 Added information about app group container protection on macOS 15.
2023-01-31 Renamed the Not Entirely Unsatisfactory section to Not Entirely Unsatisfied. Updated it to describe the real impact of that log message.
2022-12-12 First posted.
We have 2 developers:
Developer A created a Bundle ID and configured Sign in with Apple, but didn't create a corresponding App. This Bundle ID is only used for login on our official website.
Developer B created a Bundle ID, configured Sign in with Apple, and has a corresponding App.
The issue we're encountering is that because these two Bundle IDs are under different teams, when using the same Apple ID to log into these two applications, different accounts are generated. (We've tested that when creating Service IDs under the same team, logging in with Bundle IDs under the same team generates the same account.)
Since Developer A's Bundle ID doesn't have a created app, it cannot be transferred to Developer B. Therefore, we'd like to know if there's any way to make the accounts generated from logging in with the same Apple ID be identical across these two teams?
Topic:
Privacy & Security
SubTopic:
General
Tags:
Sign in with Apple REST API
Sign in with Apple
Sign in with Apple JS
My application is supporting hybrid transport on FIDO2 webAuthn specs to create credential and assertion. And it support legacy passkeys which only mean to save to 1 device and not eligible to backup.
However In my case, if i set the Backup Eligibility and Backup State flag to false, it fails on the completion of the registrationRequest to save the passkey credential within credential extension, the status is false instead of true.
self.extension.completeRegistrationRequest(using: passkeyRegistrationCredential)
The attestation and assertion flow only works when both flags set to true.
Can advice why its must have to set both to true in this case?
I'm facing a bug about App Tracking Transparency permission, my app still shows this permission popup before, and that version was still working fine. I don't understand why today it doesn't show the permission popup anymore, is anyone else having the same problem?
Hi,
I have a question about UIDevice identifierForVendor.
I am distributing 3 apps using an enterprise account. All apps use the same developer account and certificates.
The bundle IDs of the apps are as follows:
com.abc.inhouse.mail
com.abc.searchent
com.abc.noteent
In the Enterprise builds, apps 1 and 2 share the same identifierForVendor (IDFV). However, app 3 has a different IDFV value.
According to Apple documentation, the IDFV is determined based on the bundle ID when distributing through Enterprise.
Why does app 3 have a different IDFV?
Are there any other factors besides the bundle ID that affect the IDFV in Enterprise builds?
Please help me figure this out.
Thank you for your time!
Topic:
Privacy & Security
SubTopic:
General
Trusted execution is a generic name for a Gatekeeper and other technologies that aim to protect users from malicious code.
General:
Forums topic: Code Signing
Forums tag: Gatekeeper
Developer > Signing Mac Software with Developer ID
Apple Platform Security support document
Safely open apps on your Mac support article
Hardened Runtime document
WWDC 2022 Session 10096 What’s new in privacy covers some important Gatekeeper changes in macOS 13 (starting at 04: 32), most notably app bundle protection
WWDC 2023 Session 10053 What’s new in privacy covers an important change in macOS 14 (starting at 17:46), namely, app container protection
WWDC 2024 Session 10123 What’s new in privacy covers an important change in macOS 15 (starting at 12:23), namely, app group container protection
Updates to runtime protection in macOS Sequoia news post
Testing a Notarised Product forums post
Resolving Trusted Execution Problems forums post
App Translocation Notes forums post
Most trusted execution problems are caused by code signing or notarisation issues. See Code Signing Resources and Notarisation Resources.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
I regularly help developers with keychain problems, both here on DevForums and for my Day Job™ in DTS. Many of these problems are caused by a fundamental misunderstanding of how the keychain works. This post is my attempt to explain that. I wrote it primarily so that Future Quinn™ can direct folks here rather than explain everything from scratch (-:
If you have questions or comments about any of this, put them in a new thread and apply the Security tag so that I see it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
SecItem: Fundamentals
or How I Learned to Stop Worrying and Love the SecItem API
The SecItem API seems very simple. After all, it only has four function calls, how hard can it be? In reality, things are not that easy. Various factors contribute to making this API much trickier than it might seem at first glance.
This post explains the fundamental underpinnings of the keychain. For information about specific issues, see its companion post, SecItem: Pitfalls and Best Practices.
Keychain Documentation
Your basic starting point should be Keychain Items.
If your code runs on the Mac, also read TN3137 On Mac keychain APIs and implementations.
Read the doc comments in <Security/SecItem.h>. In many cases those doc comments contain critical tidbits.
When you read keychain documentation [1] and doc comments, keep in mind that statements specific to iOS typically apply to iPadOS, tvOS, and watchOS as well (r. 102786959). Also, they typically apply to macOS when you target the data protection keychain. Conversely, statements specific to macOS may not apply when you target the data protection keychain.
[1] Except TN3137, which is very clear about this (-:
Caveat Mac Developer
macOS supports two different keychain implementations: the original file-based keychain and the iOS-style data protection keychain.
IMPORTANT If you’re able to use the data protection keychain, do so. It’ll make your life easier. See the Careful With that Shim, Mac Developer section of SecItem: Pitfalls and Best Practices for more about this.
TN3137 On Mac keychain APIs and implementations explains this distinction. It also says:
The file-based keychain is on the road to deprecation.
This is talking about the implementation, not any specific API. The SecItem API can’t be deprecated because it works with both the data protection keychain and the file-based keychain. However, Apple has deprecated many APIs that are specific to the file-based keychain, for example, SecKeychainCreate.
TN3137 also notes that some programs, like launchd daemons, can’t use the file-based keychain. If you’re working on such a program then you don’t have to worry about the deprecation of these file-based keychain APIs. You’re already stuck with the file-based keychain implementation, so using a deprecated file-based keychain API doesn’t make things worse.
The Four Freedoms^H^H^H^H^H^H^H^H Functions
The SecItem API contains just four functions:
SecItemAdd(_:_:)
SecItemCopyMatching(_:_:)
SecItemUpdate(_:_:)
SecItemDelete(_:)
These directly map to standard SQL database operations:
SecItemAdd(_:_:) maps to INSERT.
SecItemCopyMatching(_:_:) maps to SELECT.
SecItemUpdate(_:_:) maps to UPDATE.
SecItemDelete(_:) maps to DELETE.
You can think of each keychain item class (generic password, certificate, and so on) as a separate SQL table within the database. The rows of that table are the individual keychain items for that class and the columns are the attributes of those items.
Note Except for the digital identity class, kSecClassIdentity, where the values are split across the certificate and key tables. See Digital Identities Aren’t Real in SecItem: Pitfalls and Best Practices.
This is not an accident. The data protection keychain is actually implemented as an SQLite database. If you’re curious about its structure, examine it on the Mac by pointing your favourite SQLite inspection tool — for example, the sqlite3 command-line tool — at the keychain database in ~/Library/Keychains/UUU/keychain-2.db, where UUU is a UUID.
WARNING Do not depend on the location and structure of this file. These have changed in the past and are likely to change again in the future. If you embed knowledge of them into a shipping product, it’s likely that your product will have binary compatibility problems at some point in the future. The only reason I’m mentioning them here is because I find it helpful to poke around in the file to get a better understanding of how the API works.
For information about which attributes are supported by each keychain item class — that is, what columns are in each table — see the Note box at the top of Item Attribute Keys and Values. Alternatively, look at the Attribute Key Constants doc comment in <Security/SecItem.h>.
Uniqueness
A critical part of the keychain model is uniqueness. How does the keychain determine if item A is the same as item B? It turns out that this is class dependent. For each keychain item class there is a set of attributes that form the uniqueness constraint for items of that class. That is, if you try to add item A where all of its attributes are the same as item B, the add fails with errSecDuplicateItem. For more information, see the errSecDuplicateItem page. It has lists of attributes that make up this uniqueness constraint, one for each class.
These uniqueness constraints are a major source of confusion, as discussed in the Queries and the Uniqueness Constraints section of SecItem: Pitfalls and Best Practices.
Parameter Blocks Understanding
The SecItem API is a classic ‘parameter block’ API. All of its inputs are dictionaries, and you have to know which properties to set in each dictionary to achieve your desired result. Likewise for when you read properties in output dictionaries.
There are five different property groups:
The item class property, kSecClass, determines the class of item you’re operating on: kSecClassGenericPassword, kSecClassCertificate, and so on.
The item attribute properties, like kSecAttrAccessGroup, map directly to keychain item attributes.
The search properties, like kSecMatchLimit, control how the system runs a query.
The return type properties, like kSecReturnAttributes, determine what values the query returns.
The value type properties, like kSecValueRef perform multiple duties, as explained below.
There are other properties that perform a variety of specific functions. For example, kSecUseDataProtectionKeychain tells macOS to use the data protection keychain instead of the file-based keychain. These properties are hard to describe in general; for the details, see the documentation for each such property.
Inputs
Each of the four SecItem functions take dictionary input parameters of the same type, CFDictionary, but these dictionaries are not the same. Different dictionaries support different property groups:
The first parameter of SecItemAdd(_:_:) is an add dictionary. It supports all property groups except the search properties.
The first parameter of SecItemCopyMatching(_:_:) is a query and return dictionary. It supports all property groups.
The first parameter of SecItemUpdate(_:_:) is a pure query dictionary. It supports all property groups except the return type properties.
Likewise for the only parameter of SecItemDelete(_:).
The second parameter of SecItemUpdate(_:_:) is an update dictionary. It supports the item attribute and value type property groups.
Outputs
Two of the SecItem functions, SecItemAdd(_:_:) and SecItemCopyMatching(_:_:), return values. These output parameters are of type CFTypeRef because the type of value you get back depends on the return type properties you supply in the input dictionary:
If you supply a single return type property, except kSecReturnAttributes, you get back a value appropriate for that return type.
If you supply multiple return type properties or kSecReturnAttributes, you get back a dictionary. This supports the item attribute and value type property groups. To get a non-attribute value from this dictionary, use the value type property that corresponds to its return type property. For example, if you set kSecReturnPersistentRef in the input dictionary, use kSecValuePersistentRef to get the persistent reference from the output dictionary.
In the single item case, the type of value you get back depends on the return type property and the keychain item class:
For kSecReturnData you get back the keychain item’s data. This makes most sense for password items, where the data holds the password. It also works for certificate items, where you get back the DER-encoded certificate. Using this for key items is kinda sketchy. If you want to export a key, called SecKeyCopyExternalRepresentation. Using this for digital identity items is nonsensical.
For kSecReturnRef you get back an object reference. This only works for keychain item classes that have an object representation, namely certificates, keys, and digital identities. You get back a SecCertificate, a SecKey, or a SecIdentity, respectively.
For kSecReturnPersistentRef you get back a data value that holds the persistent reference.
Value Type Subtleties
There are three properties in the value type property group:
kSecValueData
kSecValueRef
kSecValuePersistentRef
Their semantics vary based on the dictionary type.
For kSecValueData:
In an add dictionary, this is the value of the item to add. For example, when adding a generic password item (kSecClassGenericPassword), the value of this key is a Data value containing the password.
This is not supported in a query dictionary.
In an update dictionary, this is the new value for the item.
For kSecValueRef:
In add and query dictionaries, the system infers the class property and attribute properties from the supplied object. For example, if you supply a certificate object (SecCertificate, created using SecCertificateCreateWithData), the system will infer a kSecClass value of kSecClassCertificate and various attribute values, like kSecAttrSerialNumber, from that certificate object.
This is not supported in an update dictionary.
For kSecValuePersistentRef:
For query dictionaries, this uniquely identifies the item to operate on.
This is not supported in add and update dictionaries.
Revision History
2025-05-28 Expanded the Caveat Mac Developer section to cover some subtleties associated with the deprecation of the file-based keychain.
2023-09-12 Fixed various bugs in the revision history. Added a paragraph explaining how to determine which attributes are supported by each keychain item class.
2023-02-22 Made minor editorial changes.
2023-01-28 First posted.
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.
I am developing an app that uses Sign In with Apple for authentication, and I need to test different scenarios, such as when a user chooses not to share their email.
However, after logging in for the first time, I cannot reset the permissions flow to test again. Even after uninstalling the app, revoking access to the Apple ID in ‘Settings > Apps Using Apple ID,’ and attempting to log in again, only the token (identityToken) is returned, while the full information (email, name, surname) is no longer provided.
This makes it difficult to simulate the initial user behavior, especially when choosing to share or not share their email.
I would like to know:
1. Is there a way to completely reset the permissions flow so I can test as if it were the first time using the same Apple ID?
2. Are there any recommended solutions for development scenarios without needing to create multiple Apple IDs?
Thank you for any guidance on how to proceed.
Feedback report id: FB16605524
I'm trying to send emails to private relay service addresses using AWS SES and emails are not received. My emails are sent from dev@mydomain.fr and I've set a custom FROM domain of mail.mydomain.fr. I've added both domains and the dev@mydomain.fr adress to the "Certificates, Identifies & Profiles" section. I've set up DKIM and SPF for both.
Attached a redacted version of email headers.
email_headers_redacted.txt
Hi,
We are trying to open an application "xyz.app"
It worked fine until 15.1.1 versions. But facing issues with 15.2 and 15.3
The application is working fine when we navigate to xyz.app/Contents/MacOS/ and run applet in this directory.
But the error ""Not authorized to send Apple events to Finder"" occurs when we are trying to open the app directly.
Could someone please help me understand what might be causing this issue and how to resolve it?
Topic:
Privacy & Security
SubTopic:
General
https://developer.apple.com/documentation/apptrackingtransparency/attrackingmanager/authorizationstatus/notdetermined
Note:
Discussion
If you call ATTrackingManager.trackingAuthorizationStatus in macOS, the result is always ATTrackingManager.AuthorizationStatus.notDetermined.
So, does macOS support getting ATT?
Hello everyone,
I'm developing a FIDO2 service using the AuthenticationServices framework. I've run into an issue when a user manually deletes a passkey from their password manager.
When this happens, the ASAuthorizationError I get doesn't clearly indicate that the passkey is missing. The error code is 1001, and the localizedDescription is "The operation couldn't be completed. No credentials available for login." The userInfo also contains "NSLocalizedFailureReason": "No credentials available for login."
My concern is that these localized strings will change depending on the user's device language, making it unreliable for me to programmatically check for a "no credentials" scenario.
Is there a more precise way to determine that the user has no passkey, without relying on localized string values?
Thank you for your help.
Topic:
Privacy & Security
SubTopic:
General
Tags:
Authentication Services
Passkeys in iCloud Keychain
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!
I regularly see folks having problems importing cryptographic keys, so I thought I’d write down some hints and tips on how to recognise and import the various key formats. This post describes how to import each type of key. A companion post, On Cryptographic Keys Formats, discusses how to recognise the format of the data you have.
If you have questions about any of this stuff, put them a new thread in Privacy & Security > General. Tag your thread with Security or Apple CrytoKit, or both!, so that I see it.
Finally, if you want to see a specific example of these techniques in action, see Importing a PEM-based RSA Private Key and its Certificate.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Importing Cryptographic Keys
Apple platforms support 5 different key types:
RSA (Security framework only)
SECG secp256r1, aka NIST P-256 (Security framework and Apple CryptoKit)
SECG secp384r1, aka NIST P-384 (Security framework and Apple CryptoKit)
SECG secp521r1, aka NIST P-521 (Security framework and Apple CryptoKit)
Curve 25519 (Apple CryptoKit only)
This post explains how to import each type of key. If you’re not sure what type of key you have, or how its encoded, or you run into weird problems and suspect that you might be using the wrong key type or encoding, read On Cryptographic Keys Formats.
Note This post focuses on APIs available on all Apple platforms. Some Mac-specific APIs can import other formats.
The Security framework uses the SecKey type for all key types that it supports.
Apple CryptoKit has a different approach: It uses different types for different key types, which helps catch common programming mistakes at compile time. There are 4 top-level enums:
P256, for SECG secp256r1
P384, for SECG secp384r1
P521, for SECG secp521r1
Curve25519, for Curve 25519
Each of those enums contains a KeyAgreement enum and a Signing enum, where you express the intended purpose for your key. In this post I always use Signing but the code will work the same if you choose KeyAgreement.
Finally, in each of those enums you’ll find both Public and Private types; these are structs that represent a specific public or private key.
Undo PEM Encoding
Writing a full-featured PEM parser is tricky. It is, however, relatively straightforward to undo the PEM encoding of a known simple PEM file. For example, if you have this file:
% cat p256-private-key.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmGp6kcu19PgWNuga
r/CDWncdxmhlxAeo6ERpz2q4pHehRANCAASXR+mBqrjqcaJVzZoVYoWMQGAG8eQY
Jg0x4ad/bCs1qaMTLyMtsANR2dgANIfU7lKEeZAxPap8ch+I1LtW2pHH
-----END PRIVATE KEY-----
Decode it like so:
let u = URL(fileURLWithPath: "p256-private-key.pem")
guard let pem = try? String(contentsOf: u) else {
… handle error …
}
let pemBase64 = pem
.split(separator: "\n")
.dropFirst()
.dropLast()
.joined()
guard let pemData = Data(base64Encoded: String(pemBase64)) else {
… handle error …
}
debugPrint(pemData as NSData)
// prints:
// <30818702 01003013 06072a86 48ce3d02 0106082a 8648ce3d … d4bb56da 91c7>
Import RSA Keys
Use SecKeyCreateWithData to import an RSA key. If you have an RSAPublicKey structure like this:
% xxd -p rsa-public-key.der
3082010a0282010100cf243c324b262470131648614b62ee9c52af43319c
2498a7c16ba9790bb3a881f960f7b0303f8f49e86fedd6813be5fa888393
55d04426df0050dbb771eb683773b7dd929949695093f910c8dcdb633674
de986ada8d643e0e819b7cd5ab3bde4372103797472dc843a2711699e21a
4afddeed9f62810316903457342c345a35ebb2f06da019fed2afa56e7856
6e75a0d712849ae255155d9304348318930611b3b4f1153d77ee5970f076
299c548c8afff53157205048ade26d40930af2ecc96d4f77e8591523b767
fa3cdbc45a8a210339c4a556cea2e0dfa3ee819b62e463f75d87a53c2fbd
1bbcb8ec8fe2e8000ce37235fa903113c7b37d9c2a8b39c54b0203010001
%
% dumpasn1 -p -a rsa-public-key.der
SEQUENCE {
INTEGER
00 CF 24 3C 32 4B 26 24 70 13 16 48 61 4B 62 EE
9C 52 AF 43 31 9C 24 98 A7 C1 6B A9 79 0B B3 A8
81 F9 60 F7 B0 30 3F 8F 49 E8 6F ED D6 81 3B E5
FA 88 83 93 55 D0 44 26 DF 00 50 DB B7 71 EB 68
37 73 B7 DD 92 99 49 69 50 93 F9 10 C8 DC DB 63
36 74 DE 98 6A DA 8D 64 3E 0E 81 9B 7C D5 AB 3B
DE 43 72 10 37 97 47 2D C8 43 A2 71 16 99 E2 1A
4A FD DE ED 9F 62 81 03 16 90 34 57 34 2C 34 5A
35 EB B2 F0 6D A0 19 FE D2 AF A5 6E 78 56 6E 75
A0 D7 12 84 9A E2 55 15 5D 93 04 34 83 18 93 06
11 B3 B4 F1 15 3D 77 EE 59 70 F0 76 29 9C 54 8C
8A FF F5 31 57 20 50 48 AD E2 6D 40 93 0A F2 EC
C9 6D 4F 77 E8 59 15 23 B7 67 FA 3C DB C4 5A 8A
21 03 39 C4 A5 56 CE A2 E0 DF A3 EE 81 9B 62 E4
63 F7 5D 87 A5 3C 2F BD 1B BC B8 EC 8F E2 E8 00
0C E3 72 35 FA 90 31 13 C7 B3 7D 9C 2A 8B 39 C5
4B
INTEGER 65537
}
Import it with this code:
let u = URL(fileURLWithPath: "rsa-public-key.der")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let privateKey = SecKeyCreateWithData(keyBytes as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
] as NSDictionary, nil) else {
… handle error …
}
print(privateKey)
// prints:
// <SecKeyRef algorithm id: 1, key type: RSAPublicKey, version: 4, block size: 2048 bits, exponent: {hex: 10001, decimal: 65537}, modulus: …, addr: …>
Note You don’t need to include any other attributes in the dictionary you pass to SecKeyCreateWithData. Specifically, many folks think that they need to pass in the kSecAttrKeySizeInBits attribute. This isn’t the case; SecKeyCreateWithData will work out the key size from the key data.
If you have an RSAPrivateKey structure like this:
% xxd -p rsa-private-key.der
308204a30201000282010100cf243c324b262470131648614b62ee9c52af
43319c2498a7c16ba9790bb3a881f960f7b0303f8f49e86fedd6813be5fa
88839355d04426df0050dbb771eb683773b7dd929949695093f910c8dcdb
633674de986ada8d643e0e819b7cd5ab3bde4372103797472dc843a27116
99e21a4afddeed9f62810316903457342c345a35ebb2f06da019fed2afa5
6e78566e75a0d712849ae255155d9304348318930611b3b4f1153d77ee59
70f076299c548c8afff53157205048ade26d40930af2ecc96d4f77e85915
23b767fa3cdbc45a8a210339c4a556cea2e0dfa3ee819b62e463f75d87a5
3c2fbd1bbcb8ec8fe2e8000ce37235fa903113c7b37d9c2a8b39c54b0203
0100010282010044b694716a946089fd0aeb3fbb2e3a5108ecb2b186466d
8d58904a4ba92213c7e9ddcccc5974fc275c3fa4f9ff2ccb816c3f996462
0df9870827ca7af4034f32f5e40c505121151a71bbb161b041e68b6e0159
363901a63b1fbcc6c3866da3127bf51e84125ebe452c8a7a513102dc0dfc
61331a2826fbcb4452d88aaa0f43ccfe436e1554f95bdd883c41e7e8529f
acd7556ba539af3e083e7143ddf8637f67b59eea494b02396ff5089a1964
48dc8f7eb236d2f92a3358d0d6f5af1443205400bbd2758d3ec7cb208c11
7d78d68409f987fd6e43a93a26961c10c05f85458821594d242f8106856c
393f3b971cae1bfc20319e37147b22d2d2179ed5844e8102818100f27c96
e84d6ff814c56996a0e143fa85106d74e2eaa848347d8681bbcc396d85fc
b51d318f543ad25090fe087e0e1ee0202f2ee8674e58609c22cc56e305c5
c55b016d0ca45c847ac88b59dd8a597388b09d7d5f86e2cdf60cb7660d94
a5e4e6f539506a6aacdf67fb9458b016a63d72392129eff5faa210a1739d
948ef0453b02818100daaf65e651382baed753222ab53dfb2f79ef96c6bd
ec1c2822e5b8405900cf9203b2a0e015d12042cc9e686bbf3e5d2d732ed7
45e2a1cc1787637b8f14727dd5da11261d3a7cbe3521296f269cdf2a16ea
2974a710b14f3e61484d2580fef9c5bf4965a7a9ee6055a8c27867609408
7ef1643e81ab17307ca40b79166b693f310281803ed463719ba6f87bc14f
039579e8d83fa42b084f478804f57cd4de469fbafd92eb10ae98c9cf8452
3c47e55aa3f6daaf2e07abbad211adba929a3da201bedc28afd4e5c191d0
db0ec969ba063a33c548d4a269fad7836ae467151a1f48b5d762b4857e3d
a4985866a3fc2322b52babde2dc95709730dd6f2423327d0775cf0430281
8100c4f14336c99c6992bb2e8e4da20de0c21ff14a7b4f9d6cba24bb7754
d412ebdc96e1ef09fffbe72ee172239e2d8c2f83f8008e34cce663942904
c9c8d0644fb920fb62b4ddf06ba813666a487eec67ce5d31da717e920048
b079d9a855e4caf270d3dbedc416fec1060ba53d8c77a4b31617ee46fedb
127a9d8e0b8dca4bed710281800c2fe643bfc8c81b39f1a574c751d2c5ee
0ce836a772197350f2f0a6a4d5248790a0cdf0c25a69a8834d645ea3c96e
e740d95adeea689259ac4ce36a7310c86c9c35441fdd96ff8cec89a65f8c
8666bbc2a42cd2a58e70b1e8b2269ed6307c5a2143cbd41de4682dea4a38
8a7c8d2f4088e9a2008fa986f9b0e92fa517ecc77b
%
% dumpasn1 -p -a rsa-private-key.der
SEQUENCE {
INTEGER 0
INTEGER
00 CF 24 3C 32 4B 26 24 70 13 16 48 61 4B 62 EE
9C 52 AF 43 31 9C 24 98 A7 C1 6B A9 79 0B B3 A8
81 F9 60 F7 B0 30 3F 8F 49 E8 6F ED D6 81 3B E5
FA 88 83 93 55 D0 44 26 DF 00 50 DB B7 71 EB 68
37 73 B7 DD 92 99 49 69 50 93 F9 10 C8 DC DB 63
36 74 DE 98 6A DA 8D 64 3E 0E 81 9B 7C D5 AB 3B
DE 43 72 10 37 97 47 2D C8 43 A2 71 16 99 E2 1A
4A FD DE ED 9F 62 81 03 16 90 34 57 34 2C 34 5A
35 EB B2 F0 6D A0 19 FE D2 AF A5 6E 78 56 6E 75
A0 D7 12 84 9A E2 55 15 5D 93 04 34 83 18 93 06
11 B3 B4 F1 15 3D 77 EE 59 70 F0 76 29 9C 54 8C
8A FF F5 31 57 20 50 48 AD E2 6D 40 93 0A F2 EC
C9 6D 4F 77 E8 59 15 23 B7 67 FA 3C DB C4 5A 8A
21 03 39 C4 A5 56 CE A2 E0 DF A3 EE 81 9B 62 E4
63 F7 5D 87 A5 3C 2F BD 1B BC B8 EC 8F E2 E8 00
0C E3 72 35 FA 90 31 13 C7 B3 7D 9C 2A 8B 39 C5
4B
INTEGER 65537
INTEGER
44 B6 94 71 6A 94 60 89 FD 0A EB 3F BB 2E 3A 51
08 EC B2 B1 86 46 6D 8D 58 90 4A 4B A9 22 13 C7
E9 DD CC CC 59 74 FC 27 5C 3F A4 F9 FF 2C CB 81
6C 3F 99 64 62 0D F9 87 08 27 CA 7A F4 03 4F 32
F5 E4 0C 50 51 21 15 1A 71 BB B1 61 B0 41 E6 8B
6E 01 59 36 39 01 A6 3B 1F BC C6 C3 86 6D A3 12
7B F5 1E 84 12 5E BE 45 2C 8A 7A 51 31 02 DC 0D
FC 61 33 1A 28 26 FB CB 44 52 D8 8A AA 0F 43 CC
FE 43 6E 15 54 F9 5B DD 88 3C 41 E7 E8 52 9F AC
D7 55 6B A5 39 AF 3E 08 3E 71 43 DD F8 63 7F 67
B5 9E EA 49 4B 02 39 6F F5 08 9A 19 64 48 DC 8F
7E B2 36 D2 F9 2A 33 58 D0 D6 F5 AF 14 43 20 54
00 BB D2 75 8D 3E C7 CB 20 8C 11 7D 78 D6 84 09
F9 87 FD 6E 43 A9 3A 26 96 1C 10 C0 5F 85 45 88
21 59 4D 24 2F 81 06 85 6C 39 3F 3B 97 1C AE 1B
FC 20 31 9E 37 14 7B 22 D2 D2 17 9E D5 84 4E 81
INTEGER
00 F2 7C 96 E8 4D 6F F8 14 C5 69 96 A0 E1 43 FA
85 10 6D 74 E2 EA A8 48 34 7D 86 81 BB CC 39 6D
85 FC B5 1D 31 8F 54 3A D2 50 90 FE 08 7E 0E 1E
E0 20 2F 2E E8 67 4E 58 60 9C 22 CC 56 E3 05 C5
C5 5B 01 6D 0C A4 5C 84 7A C8 8B 59 DD 8A 59 73
88 B0 9D 7D 5F 86 E2 CD F6 0C B7 66 0D 94 A5 E4
E6 F5 39 50 6A 6A AC DF 67 FB 94 58 B0 16 A6 3D
72 39 21 29 EF F5 FA A2 10 A1 73 9D 94 8E F0 45
3B
INTEGER
00 DA AF 65 E6 51 38 2B AE D7 53 22 2A B5 3D FB
2F 79 EF 96 C6 BD EC 1C 28 22 E5 B8 40 59 00 CF
92 03 B2 A0 E0 15 D1 20 42 CC 9E 68 6B BF 3E 5D
2D 73 2E D7 45 E2 A1 CC 17 87 63 7B 8F 14 72 7D
D5 DA 11 26 1D 3A 7C BE 35 21 29 6F 26 9C DF 2A
16 EA 29 74 A7 10 B1 4F 3E 61 48 4D 25 80 FE F9
C5 BF 49 65 A7 A9 EE 60 55 A8 C2 78 67 60 94 08
7E F1 64 3E 81 AB 17 30 7C A4 0B 79 16 6B 69 3F
31
INTEGER
3E D4 63 71 9B A6 F8 7B C1 4F 03 95 79 E8 D8 3F
A4 2B 08 4F 47 88 04 F5 7C D4 DE 46 9F BA FD 92
EB 10 AE 98 C9 CF 84 52 3C 47 E5 5A A3 F6 DA AF
2E 07 AB BA D2 11 AD BA 92 9A 3D A2 01 BE DC 28
AF D4 E5 C1 91 D0 DB 0E C9 69 BA 06 3A 33 C5 48
D4 A2 69 FA D7 83 6A E4 67 15 1A 1F 48 B5 D7 62
B4 85 7E 3D A4 98 58 66 A3 FC 23 22 B5 2B AB DE
2D C9 57 09 73 0D D6 F2 42 33 27 D0 77 5C F0 43
INTEGER
00 C4 F1 43 36 C9 9C 69 92 BB 2E 8E 4D A2 0D E0
C2 1F F1 4A 7B 4F 9D 6C BA 24 BB 77 54 D4 12 EB
DC 96 E1 EF 09 FF FB E7 2E E1 72 23 9E 2D 8C 2F
83 F8 00 8E 34 CC E6 63 94 29 04 C9 C8 D0 64 4F
B9 20 FB 62 B4 DD F0 6B A8 13 66 6A 48 7E EC 67
CE 5D 31 DA 71 7E 92 00 48 B0 79 D9 A8 55 E4 CA
F2 70 D3 DB ED C4 16 FE C1 06 0B A5 3D 8C 77 A4
B3 16 17 EE 46 FE DB 12 7A 9D 8E 0B 8D CA 4B ED
71
INTEGER
0C 2F E6 43 BF C8 C8 1B 39 F1 A5 74 C7 51 D2 C5
EE 0C E8 36 A7 72 19 73 50 F2 F0 A6 A4 D5 24 87
90 A0 CD F0 C2 5A 69 A8 83 4D 64 5E A3 C9 6E E7
40 D9 5A DE EA 68 92 59 AC 4C E3 6A 73 10 C8 6C
9C 35 44 1F DD 96 FF 8C EC 89 A6 5F 8C 86 66 BB
C2 A4 2C D2 A5 8E 70 B1 E8 B2 26 9E D6 30 7C 5A
21 43 CB D4 1D E4 68 2D EA 4A 38 8A 7C 8D 2F 40
88 E9 A2 00 8F A9 86 F9 B0 E9 2F A5 17 EC C7 7B
}
Import it with this code:
let u = URL(fileURLWithPath: "rsa-private-key.der")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let privateKey = SecKeyCreateWithData(keyBytes as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
] as NSDictionary, nil) else {
… handle error …
}
print(privateKey)
// prints:
// <SecKeyRef algorithm id: 1, key type: RSAPrivateKey, version: 4, block size: 2048 bits, addr: …>
Finally, an oft-forgotten feature of SecKeyCreateWithData is that it can undo a SubjectPublicKeyInfo wrapper. So, if you have an RSA public key wrapped in a SubjectPublicKeyInfo like this:
% xxd -p public-key-rsa.der
30820122300d06092a864886f70d01010105000382010f003082010a0282
010100bce736006d9b0a2a49508f32e8d66f2b26236263a476f5a2eaf6af
34f0055b12b3bea5f5a62f3aab82274c3e3b21d15cc741100c670dd7687d
9c7e5c012d95bf5177993087df441c9944d10dff0767abfd6e412df279e4
e518b905e5582f967b6b2a64eeaeef712c594268fbff9cc2e63833ebffb7
f00c61fd7224ae2328047e13bbb904899e9ad5c9f44cfff5cd9a2df5a5b6
29bec605d6ecdce5dacba40cb119695f7c3dbd19e6fcd86a13700dfe6818
d1894aca9172a1e857540641971f7d7c9533aee2047c16c1c4f125e830b2
7d5e80d445c2fe09fa5586ee0bb105800fd1e8489e44b2f123eeef1cceeb
eb1ba2d094923944181c513208c1f37fca31e50203010001
%
% dumpasn1 -p -a public-key-rsa.der
SEQUENCE {
SEQUENCE {
OBJECT IDENTIFIER rsaEncryption (1 2 840 113549 1 1 1)
NULL
}
BIT STRING, encapsulates {
SEQUENCE {
INTEGER
00 BC E7 36 00 6D 9B 0A 2A 49 50 8F 32 E8 D6 6F
2B 26 23 62 63 A4 76 F5 A2 EA F6 AF 34 F0 05 5B
12 B3 BE A5 F5 A6 2F 3A AB 82 27 4C 3E 3B 21 D1
5C C7 41 10 0C 67 0D D7 68 7D 9C 7E 5C 01 2D 95
BF 51 77 99 30 87 DF 44 1C 99 44 D1 0D FF 07 67
AB FD 6E 41 2D F2 79 E4 E5 18 B9 05 E5 58 2F 96
7B 6B 2A 64 EE AE EF 71 2C 59 42 68 FB FF 9C C2
E6 38 33 EB FF B7 F0 0C 61 FD 72 24 AE 23 28 04
7E 13 BB B9 04 89 9E 9A D5 C9 F4 4C FF F5 CD 9A
2D F5 A5 B6 29 BE C6 05 D6 EC DC E5 DA CB A4 0C
B1 19 69 5F 7C 3D BD 19 E6 FC D8 6A 13 70 0D FE
68 18 D1 89 4A CA 91 72 A1 E8 57 54 06 41 97 1F
7D 7C 95 33 AE E2 04 7C 16 C1 C4 F1 25 E8 30 B2
7D 5E 80 D4 45 C2 FE 09 FA 55 86 EE 0B B1 05 80
0F D1 E8 48 9E 44 B2 F1 23 EE EF 1C CE EB EB 1B
A2 D0 94 92 39 44 18 1C 51 32 08 C1 F3 7F CA 31
E5
INTEGER 65537
}
}
}
Import it with this code:
let u = URL(fileURLWithPath: "public-key-rsa.der")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let privateKey = SecKeyCreateWithData(keyBytes as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeRSA,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
] as NSDictionary, nil) else {
… handle error …
}
print(privateKey)
// prints:
// <SecKeyRef algorithm id: 1, key type: RSAPublicKey, version: 4, block size: 2048 bits, exponent: {hex: 10001, decimal: 65537}, modulus: …, addr: …>
Import SECG Keys with Security Framework
If you’re working with Security framework, use SecKeyCreateWithData to import an SECG key. If you have a secp256r1 public key in X9.63 format:
% xxd p256-public-key.dat
00000000: 0497 47e9 81aa b8ea 71a2 55cd 9a15 6285 ..G.....q.U...b.
00000010: 8c40 6006 f1e4 1826 0d31 e1a7 7f6c 2b35 .@`....&.1...l+5
00000020: a9a3 132f 232d b003 51d9 d800 3487 d4ee .../#-..Q...4...
00000030: 5284 7990 313d aa7c 721f 88d4 bb56 da91 R.y.1=.|r....V..
00000040: c7 .
Import it with this code:
let u = URL(fileURLWithPath: "p256-public-key.dat")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let privateKey = SecKeyCreateWithData(keyBytes as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeyClass: kSecAttrKeyClassPublic,
] as NSDictionary, nil) else {
… handle error …
}
print(privateKey)
// prints:
// <SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPublicKey, version: 4, block size: 256 bits, y: …, x: …, addr: …>
Note I’m using secp256r1 as an example. The code in this section will work for the other SECG key types, secp384r1 and secp521r1.
And if you have a secp256r1 private key in X9.63 format:
% xxd p256-private-key.dat
00000000: 0497 47e9 81aa b8ea 71a2 55cd 9a15 6285 ..G.....q.U...b.
00000010: 8c40 6006 f1e4 1826 0d31 e1a7 7f6c 2b35 .@`....&.1...l+5
00000020: a9a3 132f 232d b003 51d9 d800 3487 d4ee .../#-..Q...4...
00000030: 5284 7990 313d aa7c 721f 88d4 bb56 da91 R.y.1=.|r....V..
00000040: c798 6a7a 91cb b5f4 f816 36e8 1aaf f083 ..jz......6.....
00000050: 5a77 1dc6 6865 c407 a8e8 4469 cf6a b8a4 Zw..he....Di.j..
00000060: 77 w
Import it with this code:
let u = URL(fileURLWithPath: "p256-private-key.dat")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let privateKey = SecKeyCreateWithData(keyBytes as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
] as NSDictionary, nil) else {
… handle error …
}
print(privateKey)
// prints:
// <SecKeyRef curve type: kSecECCurveSecp256r1, algorithm id: 3, key type: ECPrivateKey, version: 4, block size: 256 bits, addr: …>
Import SECG Keys with Apple CryptoKit
Apple CryptoKit can import SECG keys in three different ways:
X9.63 raw key bytes
DER encoding
PEM encoding
If you have a secp256r1 public key in X9.63 format, import it with this code:
let u = URL(fileURLWithPath: "p256-public-key.dat")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let publicKey = try? P256.Signing.PublicKey(x963Representation: keyBytes) else {
… handle error …
}
print(publicKey)
// prints:
// PublicKey(impl: CryptoKit.CoreCryptoNISTCurvePublicKeyImpl<CryptoKit.P256.CurveDetails>(keyBytes: […]]))
Note I’m using secp256r1 as an example. The code in this section will work for the other SECG key types, secp384r1 and secp521r1.
If you have a secp256r1 private key in X9.63 format import it with this code:
let u = URL(fileURLWithPath: "p256-private-key.dat")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let privateKey = try? P256.Signing.PrivateKey(x963Representation: keyBytes) else {
… handle error …
}
print(privateKey)
// prints:
// PrivateKey(impl: CryptoKit.CoreCryptoNISTCurvePrivateKeyImpl<CryptoKit.P256.CurveDetails>(key: CryptoKit.SecureBytes(backing: CryptoKit.SecureBytes.Backing)))
CryptoKit can also import a DER-encoded SECG key. For example, it can import the following using the init(derRepresentation:) initialiser:
% xxd -p public-key-p256.der
3059301306072a8648ce3d020106082a8648ce3d030107034200042c21f3
7049d4464afbf01813c51a4e1ef7a8101d2aa12b6a889635bc7c37e9011b
fdd54006fdebdaef0d86a6d662561347982c95276013d1c1cd2d7865aff0
23
%
% dumpasn1 -p -a public-key-p256.der
SEQUENCE {
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
}
BIT STRING
04 2C 21 F3 70 49 D4 46 4A FB F0 18 13 C5 1A 4E
1E F7 A8 10 1D 2A A1 2B 6A 88 96 35 BC 7C 37 E9
01 1B FD D5 40 06 FD EB DA EF 0D 86 A6 D6 62 56
13 47 98 2C 95 27 60 13 D1 C1 CD 2D 78 65 AF F0
23
}
%
% xxd -p private-key-p256.der
308187020100301306072a8648ce3d020106082a8648ce3d030107046d30
6b0201010420986a7a91cbb5f4f81636e81aaff0835a771dc66865c407a8
e84469cf6ab8a477a144034200049747e981aab8ea71a255cd9a1562858c
406006f1e418260d31e1a77f6c2b35a9a3132f232db00351d9d8003487d4
ee52847990313daa7c721f88d4bb56da91c7
%
% dumpasn1 -p -a private-key-p256.der
SEQUENCE {
INTEGER 0
SEQUENCE {
OBJECT IDENTIFIER ecPublicKey (1 2 840 10045 2 1)
OBJECT IDENTIFIER prime256v1 (1 2 840 10045 3 1 7)
}
OCTET STRING, encapsulates {
SEQUENCE {
INTEGER 1
OCTET STRING
98 6A 7A 91 CB B5 F4 F8 16 36 E8 1A AF F0 83 5A
77 1D C6 68 65 C4 07 A8 E8 44 69 CF 6A B8 A4 77
[1] {
BIT STRING
04 97 47 E9 81 AA B8 EA 71 A2 55 CD 9A 15 62 85
8C 40 60 06 F1 E4 18 26 0D 31 E1 A7 7F 6C 2B 35
A9 A3 13 2F 23 2D B0 03 51 D9 D8 00 34 87 D4 EE
52 84 79 90 31 3D AA 7C 72 1F 88 D4 BB 56 DA 91
C7
}
}
}
}
Finally, CryptoKit can import a PEM-encoded SECG. For example, it can import the following using the init(pemRepresentation:) initialiser:
% cat public-key-p256.pem
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAELCHzcEnURkr78BgTxRpOHveoEB0q
oStqiJY1vHw36QEb/dVABv3r2u8NhqbWYlYTR5gslSdgE9HBzS14Za/wIw==
-----END PUBLIC KEY-----
% cat private-key-p256.pem
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgmGp6kcu19PgWNuga
r/CDWncdxmhlxAeo6ERpz2q4pHehRANCAASXR+mBqrjqcaJVzZoVYoWMQGAG8eQY
Jg0x4ad/bCs1qaMTLyMtsANR2dgANIfU7lKEeZAxPap8ch+I1LtW2pHH
-----END PRIVATE KEY-----
Mapping SECG Keys between Apple CryptoKit and Security Framework
If you need to map an SECG key from Apple CryptoKit to Security framework, or vice versa, use the X9.63 format.
Imagine that you’re working in Security framework but you need to import a PEM key. SecKeyCreateWithData will not accept an SECG key in PEM format; it requires that the key be in X9.63 format. CryptoKit can import a PEM key but you want to continue using your existing Security framework code. Fortunately there’s a way out of this bind:
Import the PEM key using Apple CryptoKit.
Get the X9.63 representation.
Create the Security framework key from that.
For example, the following routine imports a PEM secp256r1 private key and returns a SecKey object:
func createSecKeyWithPEMSecp256r1Private(_ pem: String) throws -> SecKey {
let privateKeyCK = try P256.Signing.PrivateKey(pemRepresentation: pem)
let x963Data = privateKeyCK.x963Representation
var errorQ: Unmanaged<CFError>? = nil
guard let privateKeySF = SecKeyCreateWithData(x963Data as NSData, [
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeyClass: kSecAttrKeyClassPrivate,
] as NSDictionary, &errorQ) else {
throw errorQ!.takeRetainedValue()
}
return privateKeySF
}
To go the other way, from Security framework to CryptoKit, call SecKeyCopyExternalRepresentation to get the X9.63 representation of the key and then create a CryptoKit value using the init(x963Representation:) initialiser.
Importing Curve 25519 Keys
Apple CryptoKit supports Curve 25519 keys. If you have the raw bytes of a Curve 25519 public key:
% xxd curve25519-public-key.dat
00000000: 910b f46f 0c0d c836 878f a708 60fd de21 ...o...6....`..!
00000010: 9d5f 6265 0a83 a7c5 923d 2ab7 4b81 76c5 ._be.....=*.K.v.
Import it with this code:
let u = URL(fileURLWithPath: "curve25519-public-key.dat")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let publicKey = try? Curve25519.Signing.PublicKey(rawRepresentation: keyBytes) else {
… handle error …
}
print(publicKey)
// prints:
// PublicKey(baseKey: CryptoKit.Curve25519.Signing.CoreCryptoCurve25519PublicKeyImpl(keyBytes: […]))
If you have the raw bytes of a Curve 25519 private key:
% xxd curve25519-private-key.dat
00000000: 9fd9 0805 255b ae86 a6c3 035b 2de8 37e9 ....%[.....[-.7.
00000010: 29ea 792e a11f d466 e67e d0b2 65c0 a999 ).y....f.~..e...
Import it with this code:
let u = URL(fileURLWithPath: "curve25519-private-key.dat")
guard let keyBytes = try? Data(contentsOf: u) else {
… handle error …
}
guard let privateKey = try? Curve25519.Signing.PrivateKey(rawRepresentation: keyBytes) else {
… handle error …
}
print(privateKey)
// prints:
// PrivateKey(baseKey: CryptoKit.Curve25519.Signing.CoreCryptoCurve25519PrivateKeyImpl(key: CryptoKit.SecureBytes(backing: CryptoKit.SecureBytes.Backing)))
Revision History
2025-02-04 Added a link to Importing a PEM-based RSA Private Key and its Certificate. Made other minor editorial changes.
2021-05-23 First posted.
completeRequestWithTextToInsert is used to return text into an arbitrary textfield via the context menu AutoFill/Passwords from a 3rd party password manager (or presumably the Passwords App) in iOS 18.
While testing this feature in the debugger, it would often fail on the first invocation. It also appears to happen intermittently in the released app extension. Subsequent testing using the Passwords App shows it too may fail to return a value.
I have confirmed this behaviour is repeatable with the Passwords App on an iPhone running iOS 18.3.1
Reboot the iPhone.
Show the App Library, and right click Autofill.
Select Passwords
Select Passwords (App)
Select a password.
Nothing will be inserted (intermittently).
Feedback assistant report: FB16788563
I'm currently working on a project in Swift where I need to digitally sign a PDF file. I have the following resources available:
Private Key stored in the iOS Keychain with a tag. Public Key also stored in the iOS Keychain with a tag. A valid certificate stored as a PEM string. I need to digitally sign a PDF file with the above keys and certificate, but I'm struggling to find a clear and straightforward example or guidance on how to achieve this in Swift.
Specifically, I’m looking for help with:
Creating the digital signature using the private key and certificate. Embedding this signature into the PDF file. Any considerations I should be aware of regarding the format of the signed PDF (e.g., CMS, PKCS7, etc.). If anyone has experience with digitally signing PDFs in Swift, I would greatly appreciate your guidance or code examples.
Thank you in advance!
I have configured DKIM and amazon's default spf. but can't get emails using Amazon Send, do I have to configure a custom domain name here for this to work, I'd like to get a definitive conclusion!