General:
Apple Platform Security support document
Security Overview
Cryptography:
DevForums 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 DevForums post
SecItem attributes for keys DevForums post
CryptoCompatibility sample code
Keychain:
DevForums tags: Security
Security > Keychain Items documentation
TN3137 On Mac keychain APIs and implementations
SecItem Fundamentals DevForums post
SecItem Pitfalls and Best Practices DevForums post
Investigating hard-to-reproduce keychain problems DevForums post
Smart cards and other secure tokens:
DevForums tag: CryptoTokenKit
CryptoTokenKit framework documentation
Mac-specific frameworks:
DevForums tags: Security Foundation, Security Interface
Security Foundation framework documentation
Security Interface framework documentation
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"
Security
RSS for tagSecure the data your app manages and control access to your app using the Security framework.
Posts under Security tag
200 Posts
Sort by:
Post
Replies
Boosts
Views
Activity
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 implementations: the original file-based keychain and the iOS-style data protection keychain. If you’re able to use the data protection keychain, do so. It’ll make your life easier.
TN3137 On Mac keychain APIs and implementations explains this distinction in depth.
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
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.
I'm using this library for encoding / decoding RSA keys. https://github.com/Kitura/BlueRSA
It's worked fine up until macOS sequoia. The issue I'm having is the tests pass when in Debug mode, but the moment I switch to Release mode, the library no longer works.
I ruled this down the swift optimization level.
If I change the Release mode to no optimization, the library works again. Wondering where in the code this could be an issue? How would optimization break the functionality?
I am getting issue on my application that my device is jailbroken security message I updated my device 18.2 what the solution
Hi there,
I have a Multiplatform app with just one app target with an iPhone, iPad and Мас Destination. On the Mac my app is a developer singed App that is being distributed outside of the Mac App Store.
I want to use App Groups, but as long as there are multiple destinations, Xcode only allows Group Identifiers starting with group.. However, for macOS I need to have a group ID that starts with the TeamID as explained here.
So I created two separate entitlements, which are identical, but with different group IDs:
With Automatic Code Signing enabled, I get this warning:
Xcode still seems thinks it has to use the macOS Group ID for the iOS version. In the App Groups section, the mac Group ID is red and the iOS Group ID is not checked.
The app builds and runs without issues on all platforms. The App Store Connect validation (for the iOS version) also works without any errors.
Am I doing something wrong? Do I need a separate Mac target because Xcode does not support separate Group IDs for Multiplatform apps?
Since this file is protected by SIP, it can't just be changed by an installer/app without prompting the user. If the user chooses to deny the request, the sudo file won't be updated with a security critical pam module.
I need to insert our custom pam module into /etc/pam.d/sudo without the user being able to deny the operation.
Hi,
I have recently encountered an app with some odd behaviour and wanted to clarify some details about the way sandboxing works with iOS apps installed on a Mac. I am unsure whether this is due to a misunderstanding of system behaviour or whether this is a bug.
The app was installed from the Mac App Store, designed for iPad.
The developer of the app informed me that in lieu of a sign-in process, the app tries to persistently store a UUID of the user on the device so that when the app is deleted and reinstalled, the user is automatically logged in again.
The developer says that two mechanisms are being used: 1) NSUserDefaults (via Flutter shared prefs) and 2) identifierForVendor.
In the case of 1), my understanding is that these are managed by cfprefsd. Using the 'defaults domain' command, the domain of the app appears. However, there are no keys or values stored. Using the 'defaults write' and 'defaults read' and 'defaults delete' commands on that bundle identifier works as expected, but since it starts out empty, it cannot be read or deleted.
Furthermore, the app's data is supposed to be sandboxed in /Library/Containers. When the app is uninstalled from Launchpad, I have confirmed that the folder is missing. When reinstalled, the app's settings and data are missing, but crucially, the cloud identifier is still persistent and is evident after 'setup'.
In the case of 2), the developer documentation states that identifierForVendor changes when all apps from a developer have been removed from a device. The app in question is the only app that was installed from this developer, so logically this identifier should have changed when the app was deleted and reinstalled.
I have confirmed that iCloud drive is not being used to store this data as there is no data in iCloud for this app.
In any case, when the app is uninstalled and reinstalled, the app automatically logs the user into the "account" it was previously logged into, along with all of that user's data in the cloud.
I have a sense that this type of persistent identifier tracking is what sandboxing was meant to address, but I am unsure why I have been unable to remove the UUID tag from my system. Any insight would be greatly appreciated!
We are using device certificates for authentication when logging into our web page. After updating an iPhone 12 to iOS 18, the authentication process takes up to two minutes to respond.
Upon investigating IIS, it was found that the certificate is not being presented from the iPhone, resulting in a timeout.
This issue is affecting our operations, and we need a solution urgently.
Could you please advise on how to resolve this?
I generate a keys using :
let attributes: NSDictionary = [
kSecAttrLabel: label,
kSecUseKeychain: getSystemKeychain()!,
kSecAttrKeyType: kSecAttrKeyTypeEC,
kSecAttrKeyType: kSecAttrKeyTypeECSECPrimeRandom,
kSecAttrKeySizeInBits: 256,
kSecPrivateKeyAttrs: [
kSecAttrIsPermanent: true,
kSecAttrApplicationTag: tag,
] as [CFString : Any]
]
var error: Unmanaged<CFError>?
// Generate a new private key
guard let privateKey = SecKeyCreateRandomKey(attributes, &error) else {
logger.error("failed to create a keypair \(String(describing: error))")
return (nil, nil)
}
I keep getting this error :
failed to create a keypair Optional(Swift.Unmanaged<__C.CFErrorRef>(_value: Error Domain=NSOSStatusErrorDomain Code=-2070 "internal error" (internalComponentErr) UserInfo={numberOfErrorsDeep=0, NSDescription=internal error}))
The above code works absolutely fine on macOS Sonoma and older OS. This looks like a regression in the Apple API SecKeyCreateRandomKey(). What is a good workaround for this ?
We currently are using private web security certificates for our URLs. Our users download, install, and enable a Root Certificate on their devices to reach our website (trusted). The web security certificates have expirations that are less than 13 months from expiration.
Since the deployment of iOS 18, our users are now getting a "This Connection is not Private" warning in the web browser on both Mac and iOS devices.
What change was implemented in iOS 18 that is causing this issue? Other than changing our web security certificates to Public ones, what solutions should be implemented to prevent this from occurring?
I have implemented SSL pinning by following this article https://developer.apple.com/news/?id=g9ejcf8y , however pen testing team was able to bypass SSL pinning using Objection & Frida tools.
I am using URLSession for API calls. I used Xcode 16. My app's minimum iOS deployment version is 16 onwards.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSPinnedDomains</key>
<dict>
<key>*.mydomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSPinnedCAIdentities</key>
<array>
<dict>
<key>SPKI-SHA256-BASE64</key>
<string>my SHA256 key</string>
</dict>
</array>
</dict>
</dict>
</dict>
Could anyone suggest how to mitigate this bypass mechanism?
Wake up this morning and see this very concerning sticky message in Notification Center:
bash was prevented from modifying apps
It didn't say what parent program called `bash' so I clicked on the N.C. message to see if there was more information and it just disappeared (as if I had chosen to click on the X to clear the message-I wish I had taken a screenshot first). I have already sent in a request to Apple for them to give more detailed information on events like this. If there is an existing threat on a device it needs to be removed.
The only thing that I know of that happened overnight was a SPAM email from "Norton Antivirus" came into my Gmail Inbox that wasn't filtered as SPAM and macOS announced it in Notification Center. I don't see anything funny in the RAW data of the email - and reported it to spamcop.
Is it possible that a malicious email could contain html code that runs when it's announced via macOS Notification Center?
Hello,
I have a system, which is able to execute bash/zsh scripts on a set of machines.
The default behaviour is that the signature of the script is checked on the machine, which is executing it, and in case if it is not signed properly, the system rejects the execution.
An own certificate has to be created for signing the scripts, which means that the certificate has to be installed and marked as trusted on the target machines (which are executing the script).
I've been using :
"/usr/bin/security add-trusted-cert ..."
command to install the certificate on the machines as trusted.
Since macOS Big Sur, the above command was prompting the local user for admin credentials. To avoid this, Apple suggested to use the following command to temporarily disable and re-enable the confirmation dialog :
1.:
/usr/bin/security authorizationdb write com.apple.trust-settings.admin allow
2.:
/usr/bin/security authorizationdb write com.apple.trust-settings.admin admin
Now with the release of macOS Sequoia, the above command :
"/usr/bin/security authorizationdb write com.apple.trust-settings.admin allow"
does not work any more.
It gives the following output :
NO (-60005)
I have the following questions :
1.: Could you please suggest an alternative way for IT administrators to install certificates on their machines, without any user confirmation?
2.: Could you please suggest how the same could be achieved using a bash/zsh script? In which context could the above commands :
"/usr/bin/security authorizationdb write com.apple.trust-settings.admin allow"
and
"/usr/bin/security authorizationdb write com.apple.trust-settings.admin admin"
still work?
Thank you for your help in advance!
Option 1: Kurz und prägnant
"Hilfe in jeder Situation! Unsere App alarmiert schnell und unkompliziert die Rettungskräfte. Egal wo du bist, wir helfen dir in Notfällen."
Option 2: Detaillierter
"Schnelle Hilfe für alle! Mit unserer App hast du rund um die Uhr einen zuverlässigen Helfer an deiner Seite. Ob du selbst in Not bist oder Zeugen eines Unfalls werden – mit nur einem Klick alarmierst du die Rettungskräfte und erhältst wichtige Informationen. Funktioniert für iOS und Android."
Option 3: Fokus auf die Zielgruppe "Alle"
"Für jeden ein Lebensretter! Egal, ob jung oder alt, sportlich oder weniger beweglich – unsere App ist für alle gedacht, die in einer Notlage schnell Hilfe benötigen. Einfach, intuitiv und immer für dich da."
Option 4: Betonung der Notfallfunktion
"Dein persönlicher Notfallhelfer! In kritischen Situationen zählt jede Sekunde. Unsere App sorgt dafür, dass die Rettungskräfte schnellstmöglich bei dir sind. Perfekt für unterwegs, zu Hause oder am Arbeitsplatz."
Option 5: Hervorhebung der Plattformunabhängigkeit
"Hilfe ohne Grenzen! Unsere App ist für iOS und Android Geräte verfügbar und sorgt dafür, dass du immer und überall Hilfe bekommst. Egal, welches Smartphone du hast, wir sind für dich da."
Möchtest du, dass ich einen Text entwerfe, der alle deine Punkte vereint? Oder hast du weitere Wünsche oder Vorstellungen?
I am building a NEPacketTunnelProvider, and in its configuration I set a SecIdentity persistent reference. That reference is passed to the tunnel provider but when I try to use it there, I get an errSecInteractionNotAllowed error. The private key for that identity is protected by .userPresence. If I remove the protection, the network extension can access the identity and the private key.
Is there any way that a VPN network extension can use a keychain item protected by .userPresence?
Hi,
our IOS App will use the OpenSSL library for a secure websocket communication with network devices.
As far as i have understood we need to provide "Export compliance documentation" because we are using "standard encryption algorithm instead of, or in addition to, using or accessing the encryption within Apple's OS".
But the documentation here does not indicate that we need to provide anything.
Independently of that, the App needs to include a Privacy Manifest,
right ? How does that look like ?
Thanks in advance
Hello ,
I have obtained three strings from the server: ca (the root certificate), cert (the client certificate), and privateKey (the private key) for authentication between the iOS client and server. I have successfully used ca for server authentication.
However, I am having trouble generating an NSURLCredential from the cert and privateKey strings for client authentication. Can anyone guide me on how to convert these strings into an NSURLCredential? Any example code would be greatly appreciated!
Thank you for your help!
Hi, team.
So, I'm working on reading certificates from the keychain that have been stored or saved by other apps into it.
I understand that kSecAttrAccessGroupToken allows us to achieve that.
It is a requirement to use com.apple.token group in the entitlements file.
Having done that, I cannot store SecSertificates into the keychain, and into the security group. I can do it without the security group, but after adding in the dictionary the kSecAttrAccessGroup: kSecAttrAccessGroupToken, I can no longer add certificates.
I get the famous -34018. No entitlement found.
However, when I try to read certificates in the same access group, I do not get a -34018 error back. I instead get a -25300, which I understand means no keychain item was found in this access group.
How can this be happening?
Reading, the entitlement works, writing does not.
Here are my queries:
For adding:
let addQuery = [
kSecClass: kSecClassCertificate,
kSecValueRef: secCertificate as Any,
kSecAttrLabel: certificateName,
kSecAttrAccessGroup: kSecAttrAccessGroupToken
] as [CFString: Any]
let status = SecItemAdd(addQuery as CFDictionary, nil)
For reading:
var item: CFTypeRef?
let query = [
kSecClass: kSecClassCertificate,
kSecMatchLimit: kSecMatchLimitAll,
kSecReturnRef: kCFBooleanTrue as Any,
kSecAttrAccessGroup: kSecAttrAccessGroupToken
] as [CFString: Any]
let status = SecItemCopyMatching(query as CFDictionary, &item)
I have read that iOS data protection ensures most of the files to be stored encrypted. However, I saw someone insisting (elcomsoft blog) very few files are not encrypted. Are app’s cache files or tmp files not stored encrypted? For example, are safari history.db file and cache files stored in the flash encrypted?
Hello!
My company makes use of SSL interception for its managed laptops (for various information security reasons). We've yet to find a good solution to avoid SSL cert errors in the Xcode Preview app. We've successfully installed/trusted our certs in the Xcode Simulator, but can't find any information on how to do the equivalent for the Xcode Preview. The inability to make use of the Preview App profoundly impacts productivity.
It appears the Xcode Preview doesn't share the same certificate store as the Simulator, nor does it make use of the Mac's system keychain (where the certificates are also installed and trusted). If there’s anyone you can think of who might know a way around this issue it would be greatly appreciated.
Many thanks!
Hi, I'm leveraging ASAuthorizationSecurityKeyPublicKeyCredentialProvider to authenticate users to an internal service using security keys or passkeys. I'm not using Sign in with Apple - registration is done in another internal service. We're using associated domains. This is on MacOS only.
I'm wondering whether I can programatically determine whether the user has a passkey enrolled with our super-secret-internal-service.com domain already?
The reason I'm asking is simply better UX - if the user doesn't have a passkey enrolled, I'd like to avoid offering them an option to use a platform authenticator and only offer them to tap their security key. We can assume that all users already have their security keys enrolled already.
So something like the following:
let securityKeyProvider = ASAuthorizationSecurityKeyPublicKeyCredentialProvider(relyingPartyIdentifier: options.rpId)
let securityKeyRequest = securityKeyProvider.createCredentialAssertionRequest(challenge: options.challenge.data(using: .utf8) ?? Data())
let platformProvider = ASAuthorizationPlatformPublicKeyCredentialProvider(relyingPartyIdentifier: options.rpId)
let platformKeyRequest = platformProvider.createCredentialAssertionRequest(challenge: options.challenge.data(using: .utf8) ?? Data())
var authRequests: [ASAuthorizationRequest] = [securityKeyRequest]
if (userHasPasskeyForDomain("super-secret-internal-service.com")) { // TODO how do I check this??
authRequests.append(platformKeyRequest)
}
let authController = ASAuthorizationController(authorizationRequests: [platformKeyRequest, securityKeyRequest])
Many thanks!
Hello. I’m running the 18.3 beta on an 15 pro and have noticed the green camera indicator light turns on when I switch apps. I also am unable to use my flashlight until it turns off (usually a second or two). I’ve checked my privacy and access settings and nothing looks out of the norm. I’ve also closed all rubbing apps, but the issue continues.