Security

RSS for tag

Secure 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

Security Resources
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"
0
0
2.4k
Mar ’24
SecItem: Fundamentals
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.
0
0
2.2k
Sep ’23
Infer error domain and code from localizedDescription
I have been bitten by this repeatedly so I am finally going to ask: Is there a way to infer an error from its localizedDescription only? It sometimes happens that a user reaches out for support with just a localized error message, but no error code or error domain and it is really hard to correctly guess what the non-localized description may have been in order to search for it. For example I know from experience that "Der eingegebene Benutzername oder das Passwort ist ungültig." is the German localization of "The user name or passphrase you entered is not correct." which in turn is errSecAuthFailed (aka. -25293). It would be really helpful to be able to just look this up somewhere...
2
0
80
1d
Issues related to slow keychain access.
Hello Apple Developer, I have some questions regarding slow keychain access. We recently launched a product, and users with certain specific device models have reported slow performance. I'm not sure what's causing this issue and would appreciate your help in analyzing it.When using keychain groups, I didn’t specify a group, and on some devices, the queries are particularly slow. I'm unsure of the reason for this.I’m using kSecAttrTokenIDSecureEnclave, and each time I execute SecItemCopyMatching or SecItemDelete, the operation is particularly slow, taking around 2 seconds.It’s strange that when setting the default keychain group (team ID + bundle ID), the access is not slow. However, since the project has enabled the keychain group, if I set a keychain group, I cannot access the data that was stored before setting the keychain group. Here is a snippet of my code: NSMutableDictionary *parameters = [[NSMutableDictionary alloc] initWithObjectsAndKeys:(__bridge id)kSecAttrTokenIDSecureEnclave,(__bridge id)kSecAttrTokenID, (__bridge id)kSecAttrKeyTypeEC,(__bridge id)kSecAttrKeyType, @256,(__bridge id)kSecAttrKeySizeInBits, PrivateKeyAttrs,(__bridge id)kSecPrivateKeyAttrs,nil]; privateKey = SecKeyCreateRandomKey((__bridge CFDictionaryRef)parameters, &error); Here is a search of my code: SecKeyRef privateKey = NULL; //CFTypeRef *private = &privateKey; NSDictionary *query = nil; query = @{ (__bridge id)kSecClass: (__bridge id)kSecClassKey, (__bridge id)kSecAttrApplicationTag: serviceID, (__bridge id)kSecReturnRef: @YES }; OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, (CFTypeRef *)&privateKey); if (privateKey) { CFRelease(privateKey); }
2
0
133
5d
How to install root trusted certificate via SSH ?
How to install root trusted certificate via SSH ? I already read that SecTrustSettingsSetTrustSettings requires user interaction. That mean that it requires user login and password be entered. But is it possible to move that authetification to command line, outside UI session? I made a sample tool that try to do this. https://github.com/DanilKorotenko/certificateTool Accordingly to the documentation: https://developer.apple.com/library/archive/documentation/Security/Conceptual/authorization_concepts/02authconcepts/authconcepts.html#//apple_ref/doc/uid/TP30000995-CH205-CJBJBGAA If the timeout attribute is missing, the credential can be used to grant the right as long as the login session lasts, unless the credential is explicitly destroyed. When I call function AuthorizationCopyRights, I create a shared credential (login+password). Authorization rule com.apple.trust-settings.admin does not have timeout attribute. security authorizationdb read com.apple.trust-settings.admin <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>class</key> <string>rule</string> <key>comment</key> <string>For modifying Trust Settings in the Admin domain. Requires entitlement or admin authentication.</string> <key>created</key> <real>745942864.47938299</real> <key>k-of-n</key> <integer>1</integer> <key>modified</key> <real>745942864.47938299</real> <key>rule</key> <array> <string>entitled</string> <string>authenticate-admin</string> </array> <key>version</key> <integer>1</integer> </dict> </plist> But. If read authd log, when running this tool, in logs we can read this: default 18:28:43.117724+0300 authd Validating shared credential trustadmin (707) for authenticate-admin (engine 396) default 18:28:43.117733+0300 authd credential 707 expired '0.136439 > 0' (does NOT satisfy rule) (engine 396) It says that our credential is expired. But it should not be expired because the rule does not have timeout. In summary, accordingly to documentation, SecTrustSettingsSetTrustSettings should not require authentification, when calling process is running as root. Because, com.apple.trust-settings.admin right rule does not have timeout, and since that root authetification on process call will create shared credential which SecTrustSettingsSetTrustSettings will use. But in reality the behavior is different. I found, that on some other macs, that tool works as expected. It adds trust certificate silently. May be there is some special condition for exactly this roght? May be there is some special preferences, flags or environment variables? Steps To Reproduce Change this constants in code before build. const char *userLogin = "your-adminuser"; const char *userPass = "your-password"; const char *certificateName = "your-certificateFileName"; You may use testCertificate, or create our own. Build project. Connect to localhost by ssh ssh <youruser>@localhost Go to build folder. sudo ./certificateTool Actual result: The tool returns: SecTrustSettingsSetTrustSettings failure. Error: -60007 That means that user interaction is required. Expected result: User interaction does not required.
1
0
180
21h
Using SecIdentityRef to create a TLS connection
Hello, I'm developing an SDK that will allow iOS devices (iOS 13+) to connect to AWS IoT Core using Native C. The endpoint requires a mutual TLS handshake to connect. I have been able to successfully import a Certificate and Private Key into the keychain and generate a SecIdentityRef that combines the cert/key pair which I believe is necessary to establish a TCP TLS nw_connection. I've searched around and while I can find the individual pieces related to creating a TLS connection, I can't seem to find any that show how things go together. The goal would be to use nw_connection_create(endpoint, parameters); to establish a TLS connection. This is currently how I am creating the parameters for this connection. transport_ctx-&gt;secitem_identity is where the SecIdentityRef is kept. nw_parameters_create_secure_tcp( // nw_parameters_configure_protocol_block_t for configure_tls ^(nw_protocol_options_t tls_options) { sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(tls_options); // Set the minimum TLS version to TLS 1.2 sec_protocol_options_set_min_tls_protocol_version(sec_options, tls_protocol_version_TLSv12); // Set the maximum TLS version to TLS 1.3 sec_protocol_options_set_max_tls_protocol_version(sec_options, tls_protocol_version_TLSv13); sec_protocol_options_set_local_identity(sec_options, transport_ctx-&gt;secitem_identity); }, // nw_parameters_configure_protocol_block_t for configure_tcp // This is also manually set with a code block but not relevant to this q. NW_PARAMETERS_DEFAULT_CONFIGURATION); My question is whether or not I'm even on the right track with attempting to use these functions to setup the TLS options associated with the parameters? The sec_protocol_options_set_local_identity appears to be listed under "Security legacy reference" in the apple dev docs: https://developer.apple.com/documentation/security/sec_protocol_options_set_local_identity(_:_:)?language=objc And the surrounding documentation related to using TLS with a network connection feels sparse at best. Follow up question is whether there is any documentation or reading material available for setting up TLS with a TCP socket connection. I'd love to not have to take up time asking these questions if there's somewhere I can just learn it. Thanks!
12
0
214
9h
Mutual TLS using Private Key and Certificate
I'm developing an SDK that will allow iOS devices (iOS 13+) to connect to AWS IoT Core using Native C. The endpoint requires a mutual TLS handshake to connect. I have been able to successfully import a Certificate and Private Key into the keychain but am unable to generate a SecIdentityRef from them for use in setting up a nw_protocol_options_t. I've looked through other forum posts and have been unable to figure out what's going on (Some are from 5+ years ago and maybe things have changed since then). After prepping the raw data for the cert and key into expected formats I import the certificate: const void *add_keys[] = { kSecClass, kSecAttrLabel, kSecAttrSerialNumber, kSecValueData, kSecReturnRef }; const void *add_values[] = { kSecClassCertificate, label, serial_data, cert_data, kCFBooleanTrue }; attributes = CFDictionaryCreate( cf_alloc, add_keys, add_values, 5, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); status = SecItemAdd(attributes, (CFTypeRef *)out_certificate); Next I import the private key: const void *add_keys[] = { kSecClass, kSecAttrKeyClass, kSecAttrKeyType, kSecAttrApplicationLabel, kSecAttrLabel, kSecValueData, kSecReturnRef }; const void *add_values[] = { kSecClassKey, kSecAttrKeyClassPrivate, key_type, application_label, label, key_data, kCFBooleanTrue }; attributes = CFDictionaryCreate( cf_alloc, add_keys, add_values, 7, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); status = SecItemAdd(attributes, (CFTypeRef *)out_private_key); The full code handles duplicate items in which case attributes are updated. Following the successful import of the cert and key to the keychain, I attempt to retrieve the identity with the following: SecIdentityRef identity = NULL; CFDictionaryRef query = NULL; const void *query_keys[] = { kSecClass, kSecReturnRef, // kSecAttrSerialNumber, // kSecAttrLabel kSecMatchLimit }; const void *query_values[] = { kSecClassIdentity, kCFBooleanTrue, // cert_serial_data, // cert_label_ref kSecMatchLimitAll }; query = CFDictionaryCreate( cf_alloc, query_keys, query_values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); OSStatus identity_status = SecItemCopyMatching(query, (CFTypeRef *)&identity); I have attempted using various search parameters related to the label and the serial of the certificate. Based on other forum post suggestions I have also tried expanding the search to kSecMatchLimitAll to get back ANY stored kSecClassIdentity and all variations returned OSStatus of -25300 (errSecItemNotFound). Once I am able to retrieve the SecIdentityRef, my understanding is that I can add it to the following during creation of the socket: nw_protocol_options_t tls_options = nw_tls_create_options(); sec_protocol_options_t sec_options = nw_tls_copy_sec_protocol_options(tls_options); sec_protocol_options_set_min_tls_protocol_version(sec_options, tls_protocol_version_TLSv12); sec_protocol_options_set_max_tls_protocol_version(sec_options, tls_protocol_version_TLSv13); sec_protocol_options_set_local_identity(sec_options, SecIdentityRef); Am I missing some step that is required to create an identity from the certificate and private key? I have tested the cert/key pair and they connect properly when using the old deprecated SecItemImport and SecIdentityCreateWithCertificate (on our old macOS only implementation). I will continue to dig through Apple documentation as well as more forum posts but I feel like I'm hitting a wall and missing something very obvious as this seems like a very common networking task. Thanks! The provided links below are to the full code related to the work in progress iOS import functions: Link to import function https://github.com/awslabs/aws-c-io/blob/cad8639ef0ea08ba3cc74b72cfc1c9866adbb7e5/source/darwin/darwin_pki_utils.c#L735 Link to private key import: https://github.com/awslabs/aws-c-io/blob/cad8639ef0ea08ba3cc74b72cfc1c9866adbb7e5/source/darwin/darwin_pki_utils.c#L561 Link to certificate import: https://github.com/awslabs/aws-c-io/blob/cad8639ef0ea08ba3cc74b72cfc1c9866adbb7e5/source/darwin/darwin_pki_utils.c#L398
10
0
256
1w
App Attest fails only for App built with M processor
We are having trouble with App Attest when built with different processors. We need to build an IPA to send to our testers. When the app is built using Intel processor, everything works. But when we built using a mac with processor M, them the App Attest process fails. The error occurs in our backend while validating the attesation object. We are doing the validation as stated by this documentation: https://developer.apple.com/documentation/devicecheck/attestation-object-validation-guide The process of validating the Attesation Object fails in the step 4, this one: Obtain the value of the credCert extension with OID 1.2.840.113635.100.8.2, which is a DER-encoded ASN.1 sequence. Decode the sequence and extract the single octet string that it contains. Verify that the string equals nonce. The problem is that the validation fails only when the app is built in a M processor machine. In our server we do (using GO Lang) something like this: if !bytes.Equal(nonce[:], unMarshalledCredCert.Bytes) { // error } unMarshalledCredCert is the nonce extracted from the Attesation Object sent by the mobile application and nonce[:] is the nonce stored in our backend side cache. What can this be?
0
0
139
1w
[FB13622281]Sonoma: On any OS update, CryptoTokenKit extension doesn't get loaded automatically at login
On macOS OS updates/reboot, CryptoTokenKit extension doesn't get loaded automatically when the system boots back. It needs another reboot to get the extension loaded and working. After update: % security list-smartcards <No smart cards> .. and there is a crash for authorizationhosthelper.arm64 in keychain layer Thread 2 Crashed:: Dispatch queue: com.apple.security.keychain-cache-queue 0 libdispatch.dylib 0x18e2e499c dispatch_channel_cancel + 12 1 Security 0x1914ccfd0 invocation function for block in Security::KeychainCore::StorageManager::tickleKeychain(Security::KeychainCore::KeychainImpl*) + 44 2 libdispatch.dylib 0x18e2ce3e8 _dispatch_client_callout + 20 3 libdispatch.dylib 0x18e2d18ec _dispatch_continuation_pop + 600 4 libdispatch.dylib 0x18e2e57f0 _dispatch_source_latch_and_call + 420 5 libdispatch.dylib 0x18e2e43b4 _dispatch_source_invoke + 832 6 libdispatch.dylib 0x18e2d5898 _dispatch_lane_serial_drain + 368 7 libdispatch.dylib 0x18e2d6544 _dispatch_lane_invoke + 380 8 libdispatch.dylib 0x18e2e12d0 _dispatch_root_queue_drain_deferred_wlh + 288 9 libdispatch.dylib 0x18e2e0b44 _dispatch_workloop_worker_thread + 404 10 libsystem_pthread.dylib 0x18e47b00c _pthread_wqthread + 288 11 libsystem_pthread.dylib 0x18e479d28 start_wqthread + 8 Opening the parent app bundle as a Login item does not help. A reboot sometimes fixes it but this happens frequently and causes lot of enterprise endpoints not able to authenticate. After reboot: % security list-smartcards com.foo.tech.mac-device-check.SecureEnclaveTokenExtension:700D6B7E8943B529569D9CC81AC6F930 Please provide and prioritize a permanent fix/workaround for this issue. We have already reported this issue with crash and sysdiagnose logs in FB13622281 earlier this year.
1
0
284
2w
generate secIdentity from certificate & private key
Hi I want to create secIdentity from certificate &amp; key. I receive certificate from my server and I have private key of that. My certificate is like this -----BEGIN CERTIFICATE-----\nMIIEyTC...jix0=\n-----END CERTIFICATE----- And private key is like this -----BEGIN RSA PRIVATE KEY-----\nMIIEp...5KM=\n-----END RSA PRIVATE KEY-----\n I am trying to create secIdentity by saving certificate and key in keychain, but I am getting -25300 as error. To create the identity my code is like this. func deleteCertificateAndKey(certLabel:String, keyTag:Data) -&gt; Bool { // Query for the certificate let query: [String: Any] = [kSecClass as String: kSecClassCertificate, kSecAttrLabel as String: certLabel] // Attempt to delete the certificate let certificateDeleteStatus = SecItemDelete(query as CFDictionary) print("certificateDeleteStatus: \(certificateDeleteStatus)") // if certificateDeleteStatus == errSecSuccess { // print("Certificate Certificate deleted successfully.") // } else { // print("Failed to delete certificate Certificate. Error: \(certificateDeleteStatus)") // return false // } // // Query for the private key associated with the certificate let keyQuery: [String: Any] = [ kSecClass as String: kSecClassKey, kSecAttrApplicationTag as String: keyTag ] // Attempt to delete the private key let keyDeleteStatus = SecItemDelete(keyQuery as CFDictionary) print("keyDeleteStatus: \(keyDeleteStatus)") // if keyDeleteStatus == errSecSuccess { // print("Private key associated with Key deleted successfully.") // return true // } else { // print("Failed to delete private key for Key. Error: \(keyDeleteStatus)") // return false // } return true; } func stripPemHeaders(_ pemString: String) -&gt; String { var result = pemString // result = result.replacingOccurrences(of: "-----BEGIN RSA PRIVATE KEY-----\n", with: "") result = result.replacingOccurrences(of: "\n-----END RSA PRIVATE KEY-----\n", with: "") // result = result.replacingOccurrences(of: "-----BEGIN CERTIFICATE-----\n", with: "") result = result.replacingOccurrences(of: "\n-----END CERTIFICATE-----", with: "") return result } func loadIdentity(certificate: String, privateKey: String)-&gt; SecIdentity? { let strippedCertificate = stripPemHeaders(certificate) print("strippedCertificate : \(strippedCertificate)") guard let certData = Data(base64Encoded: strippedCertificate, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else { print("Unable to decode certificate PEM") return nil } print("certData: \(certData)") // Create certificate object guard let cert = SecCertificateCreateWithData(kCFAllocatorDefault, certData as CFData) else { print("Unable to create certificate") return nil } let addCertQuery: [String: Any] = [kSecClass as String: kSecClassCertificate, kSecValueRef as String: cert, kSecAttrLabel as String: "shahanshahAlam"] let tag = "fedvfdvjjkdf-tag".data(using: .utf8)! _ = deleteCertificateAndKey(certLabel: "shahanshahAlam",keyTag: tag ) // print("deleteStatus finished with status: \(deleteStatus)") let certAddStatus = SecItemAdd(addCertQuery as CFDictionary, nil) print("certAddStatus finished with status: \(certAddStatus)") let strippedPrivateKey = stripPemHeaders(privateKey) print("strippedPrivateKey : \(strippedPrivateKey)") guard let pemKeyData = Data(base64Encoded: strippedPrivateKey, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else { print("Error: couldn't parse the privateKeyString, pls check if headers were removed: \(privateKey)") return nil } print("pemKeyData finished with status: \(pemKeyData)") let sizeInBits = pemKeyData.count * 8 let keyDict: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: NSNumber(value: sizeInBits), kSecReturnPersistentRef: true ] var error: Unmanaged&lt;CFError&gt;? guard let key = SecKeyCreateWithData(pemKeyData as CFData, keyDict as CFDictionary, &amp;error) else { print("Failed creating a Certificate from data \(error.debugDescription)") return nil } let addKeyQuery: [String: Any] = [ kSecClass as String: kSecClassKey, kSecAttrIsPermanent as String: true, kSecValueRef as String: key, kSecAttrApplicationTag as String: tag ] let privKeyAddStatus = SecItemAdd(addKeyQuery as CFDictionary, nil) print("privKeyAddStatus status finished with status: \(privKeyAddStatus)") // query for all avaiable identities let getIdentityQuery = [ kSecClass : kSecClassIdentity, // kSecReturnData : true, // kSecReturnAttributes : true, kSecReturnRef : true, kSecAttrApplicationTag as String: tag, kSecMatchLimit : kSecMatchLimitAll ] as CFDictionary var identityItem: CFTypeRef? let status = SecItemCopyMatching(getIdentityQuery , &amp;identityItem) print("identityItem finished with status: \(String(describing: identityItem))") print("status finished with status: \(status)") guard status == errSecSuccess else { print("Unable to create identity") return nil } return (identityItem as! SecIdentity); } How can I fix that.
2
0
196
1w
Operation not permitted error when sandboxed daemon tries to write System Keychain
Hi, I'm writing a sandboxed Daemon that I register from my sandboxed application via SMAppService. The registration is successful, and the daemon is called based on logs. However when I'm trying to save a keychain item into the keychain, I see entries like this in the logs: (Security) SecItemAdd [com.apple.securityd:atomicfile] create /Library/Keychains/System.keychain.sb-1c133873-RPL9wo: Operation not permitted [com.apple.securityd:security_exception] UNIX error exception: 1 [com.apple.securityd:security_exception] CSSM Exception: 100001 UNIX[Operation not permitted] [com.apple.securityd:security_exception] CSSM Exception: 100001 UNIX[Operation not permitted] I'm attempting to create the item with the regular SecItemAdd function call: var query: [String: Any] = [ kSecClass as String: kSecClassGenericPassword, kSecAttrLabel as String: "[redacted string]", kSecAttrAccount as String: "[redacted string]", kSecAttrService as String: "[redacted string]", kSecValueData as String: secretData ] SecItemAdd(query as CFDictionary, nil) I'm guessing this is because the System keychain is outside of the sandbox for the daemon. Is there a way to create items for the System Keychain from a sandboxed daemon?
1
0
209
1w
Error EXC_BAD_ACCESS (code=2, address=0x2f30650004) in swift
I am trying to make https request in swift, with identity created from certificate and key. My code look like this To create the identity. func loadIdentity(certificate: String, privateKey: String)-> SecIdentity? { guard let certData = Data(base64Encoded: certificate, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else { print("Unable to decode certificate PEM") return nil } guard let cert = SecCertificateCreateWithData(kCFAllocatorDefault, certData as CFData) else { return nil } let addCertQuery: [String: Any] = [kSecClass as String: kSecClassCertificate, kSecValueRef as String: cert, kSecAttrLabel as String: "certificateLabel"] let tag = "fedvfdvdf-tag".data(using: .utf8)! _ = deleteCertificateAndKey(certLabel: "certificateLabel",keyTag: tag ) let certAddStatus = SecItemAdd(addCertQuery as CFDictionary, nil) guard let pemKeyData = Data(base64Encoded: privateKey, options:NSData.Base64DecodingOptions.ignoreUnknownCharacters) else { return nil } let sizeInBits = pemKeyData.count * 8 let keyDict: [CFString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: NSNumber(value: sizeInBits), kSecReturnPersistentRef: true ] var error: Unmanaged<CFError>? guard let key = SecKeyCreateWithData(pemKeyData as CFData, keyDict as CFDictionary, &error) else { return nil } let addKeyQuery: [String: Any] = [ kSecClass as String: kSecClassKey, kSecAttrIsPermanent as String: true, kSecValueRef as String: key, kSecAttrApplicationTag as String: tag ] let privKeyAddStatus = SecItemAdd(addKeyQuery as CFDictionary, nil) let getIdentityQuery = [ kSecClass : kSecClassIdentity, kSecReturnData : true, kSecReturnAttributes : true, kSecReturnRef : true, kSecMatchLimit : kSecMatchLimitAll ] as CFDictionary var identityItem: CFTypeRef? let status = SecItemCopyMatching(getIdentityQuery , &identityItem) print("identityItem finished with status: \(String(describing: identityItem))") print("status finished with status: \(status)") guard status == errSecSuccess else { print("Unable to create identity") return nil } return (identityItem as! SecIdentity); } o make api request. Code is breaking in this function, around this lines let task = session.dataTask(with: request) { (data, response, error) in and let session = URLSession(configuration: .default, delegate: URLSessionPinningDelegate(identity: identity), delegateQueue: nil) For testing I removed identity and just used default URLSession, and request start giving response (although it was 401 but it was not crashing), so my guess is error is because of URLSession. func makeAzureRequest(scopeId:String, registrationId:String, key:String, certificate:String, provisionHost:String, fileNameWithFolder:String, modelId:String, completion: @escaping (Result<String, Error>) -> Void ) throws { guard let identity = loadIdentity(certificate: certificate, privateKey: key) else { throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unable to create identity"]) } let session = URLSession(configuration: .default, delegate: URLSessionPinningDelegate(identity: identity), delegateQueue: nil) print("session: \(session)") guard let url = URL(string: "https://global.azure-devices-provisioning.net/\(scopeId)/registrations/\(registrationId)/register?api-version=2021-06-01") else { throw NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]) } var request = URLRequest(url: url) request.httpMethod = "PUT" request.setValue("application/json", forHTTPHeaderField: "Content-Type") request.setValue("utf-8", forHTTPHeaderField: "Content-Encoding") let body = ["registrationId": registrationId] request.httpBody = try? JSONSerialization.data(withJSONObject: body, options: []) let task = session.dataTask(with: request) { (data, response, error) in if let error = error { completion(.failure(error)) } else if let data = data, let responseString = String(data: data, encoding: .utf8) { completion(.success(responseString)) }else { completion(.failure(NSError(domain: "", code: -1, userInfo: [NSLocalizedDescriptionKey: "Unknown error occurred"]))) } } task.resume() } to call function where api function is triggered. @objc(AzureProvisionWithCertificate) class AzureProvisionWithCertificate: NSObject { @objc(provisionAndUploadFile:withRegistrationId:withKey:withCertificate:withProvisionHost:withFileNameWithFolder:withModelId:withResolver:withRejecter:) func provisionAndUploadFile(scopeId:String, registrationId:String, key:String, certificate:String, provisionHost:String, fileNameWithFolder:String, modelId:String, resolve:@escaping RCTPromiseResolveBlock, reject:@escaping RCTPromiseRejectBlock) -> Void { print("starting swift code here") do { try makeAzureRequest(scopeId: scopeId, registrationId:registrationId, key: key, certificate: certificate, provisionHost: provisionHost, fileNameWithFolder: fileNameWithFolder, modelId: modelId) { result in switch result { case .success(let responseString): // Handle success, perhaps update the UI or process the response case .failure(let error): // Handle failure, perhaps show an error message to the user } } } catch { print("Failed to initiate request: (error.localizedDescription)") } } } And URLSessionPinningDelegate class look like this to SSL pinning. import Foundation import Security class URLSessionPinningDelegate: NSObject, URLSessionDelegate { var identity: SecIdentity init(identity: SecIdentity) { self.identity = identity } func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { if challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodClientCertificate { let credential = URLCredential(identity: self.identity, certificates: nil, persistence: .forSession) completionHandler(.useCredential, credential) } else { completionHandler(.performDefaultHandling, nil) } } }
1
0
203
2w
Use EndpointSecurity to allow/block peripherals
Hi, I'm exploring ways to control wide range of peripherals such as Keyboard, Mouse, Monitor, Router etc form connecting to mac device. I was able to easily achieve the external storage mount and unmount but having trouble understanding on how can I control which peripheral is allowed to connect to mac. Can you help me understand what events and processes in ES can be used to control them? Is ES app the correct approach for this or something else like IOKit framework?
0
3
188
3w
Failing certificate on Client Authentication
Hello, we are developing an application that uses TLS client authentication with self-signed certificate. The app has multiple targets, including iOS and macOS clients. However, we are encountering issues with the client certificate on both platforms. Specifically, the client certificate is being rejected when making a URLRequest, and an AuthChallenge is triggered. The strange part is that the TLS handshake fails for every target except one iOS target, making it unclear whether the issue lies with the server or the system. Flow The connection uses TLS with Client Authentication. User is authenticated by client certificate, that is issued when user signs in. The certificate is self-signed. It is decoded from PKCS#12 blob into Swift.Data and then successfully imported with SecPKCS12Import. The Keychain uses access groups (separate for each target), kSecAttrSynchronizable is set to false and the items are accessible .afterFirstUnlock. The certificate is used for two types of connections - 1) Basic query request 2) Periodic status report First type of request never fails - it is successful, the problem arises with second type of requests. If the certificate is expired on didReceive challenge: URLAuthenticationChallenge, it is refreshed and then provided for verification with URLCredential Issue With default target everything works as expected. The issue arose when another targets with the same functionality (Different UI, Access Group, Bundle identifier) were added (different xcodeproj or same). Importing certificate is successful as are basic query requests. The issue are with the second type of requests - Periodic status report. Whenever this request is sent via URLSession, it fails. Here is the output in Xcode console: - boringssl_context_handle_fatal_alert(2072) [C1.1.1.1:2][0x13c0755a0] read alert, level: fatal, description: bad certificate - nw_read_request_report [C1] Receive failed with error "bad certificate format" - boringssl_session_handshake_error_print(44) [C1.1.1.1:2][0x13c0755a0] Error: 5266350496:error:10000412:SSL routines:OPENSSL_internal:SSLV3_ALERT_BAD_CERTIFICATE:/AppleInternal/Library/BuildRoots/a8fc4767-fd9e-11ee-8f2e-b26cde007628/Library/Caches/com.apple.xbs/Sources/boringssl/ssl/tls_record.cc:592:SSL alert number 42 - “Task <..>.<1> finished with error [-1202] Error Domain=NSURLErrorDomain Code=-1202 "The certificate for this server is invalid. You might be connecting to a server that is pretending to be “<redacted>” which could put your confidential information at risk.”“
 The certificate is in fact not invalid, since it works as expected for the other type of request and with the one specific target Here is the output from Console.app consoleoutput.txt I also noticed an additional error when I specifically searched for errors in Console.app. I'm not sure if it's connected, though it doesn't seem likely, as this error appears far more frequently than the requests.
 | Security | com.apple.security | trustd | SecKeyVerifySignature failed: Error Domain=NSOSStatusErrorDomain Code=-67808 "RSA signature verification failed, no match" UserInfo={numberOfErrorsDeep=0, NSDescription=RSA signature verification failed, no match} debug 21:56:54.822609+0200 | Security | com.apple.security | trustd | SecKeyVerifySignature failed: Error Domain=NSOSStatusErrorDomain Code=-50 "rsa_pub_crypt failed, ccerr=-7" (paramErr: error in user parameter list) UserInfo={numberOfErrorsDeep=0, NSDescription=rsa_pub_crypt failed, ccerr=-7} debug 21:56:43.954898+0200 On iOS an additional error appears.
 
SecKeyVerifySignature failed: Error Domain=NSOSStatusErrorDomain Code=-50 "<SecKeyRef algorithm id: 1, key type: RSAPublicKey, version: 4, 2048 bits (block size: 256), exponent: {hex: 10001, decimal: 65537}, modulus: F12EA3…97D85C5, addr: 0x7eca128c0>: sign - input buffer bad size (264 bytes)" UserInfo={numberOfErrorsDeep=0, NSDescription=<SecKeyRef algorithm id: 1, key type: RSAPublicKey, version: 4, 2048 bits (block size: 256), exponent: {hex: 10001, decimal: 65537}, modulus: F12EA31…A835FA7B With the message that says, "The certificate for this server is invalid...," it appears that the server certificate is failing. However, as mentioned, it works for another target that uses the exact same endpoint. When making a simple GET request to this endpoint, it passes as expected, probably since client certificate is not requested. I also checked the trust result on AuthenticationChallenge and it was successful. Could this be an issue with the client/server certificate itself? Or perhaps with how the client certificate is being handled—such as storing it inside the keychain, possible collisions? Thank you for your response.
1
1
209
3w
Security Framework: unreleased memory
I'm writing software that uses the security framework to get signing information from applications. I noticed that over time memory consumption goes up. After checking with Instruments, I saw an accumulation of objects coming from the internals of the security framework. These allocated objects don't seem to go away. Following is a standalone code sample that seems to cause the problem in my env. Running it by itself creates a big number of objects that are not released. I also attached a screenshot from Instruments. #include <Foundation/Foundation.h> #include <Security/Security.h> #include <unistd.h> OSStatus get_signing_info(const char* path) { SecStaticCodeRef codeRef = NULL; OSStatus status; NSString* str = [NSString stringWithUTF8String:path]; NSURL* url = [NSURL fileURLWithPath:str]; status = SecStaticCodeCreateWithPath((__bridge CFURLRef)url, kSecCSDefaultFlags, &codeRef); CFDictionaryRef _info = NULL; status = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &_info); NSDictionary* info = (__bridge_transfer NSDictionary *)_info; int flags = [[info objectForKey:(NSString *)kSecCodeInfoFlags] intValue]; NSLog(@"%d", flags); CFRelease(codeRef); return status; } int main(int argc, const char * argv[]) { @autoreleasepool { for (int i = 0; i < 1000; ++i) { @autoreleasepool { OSStatus status = get_signing_info(argv[1]); NSLog(@"i=%d, status=%d", i, status); } } sleep(100); } return 0; } Is there a way to get rid of these objects that clog up the memory? Or perhaps use the framework differently to avoid this issue?
1
0
215
3w
Create Identity from certificate and key
I have x509 certificate in pem format. CertificatePem -----BEGIN CERTIFICATE----- MIIC3jCCAcYCAQAw...9gBFNQUdahSccXF2bnZkv2Kh -----END CERTIFICATE----- PrivatekeyPem: -----BEGIN RSA PRIVATE KEY----- MIIEowIBAAKCAQE...ooxp1Nyl17zfP -----END RSA PRIVATE KEY----- And I convert it to base64 using this JS code const pemHeader = type === 'certificate'? '-----BEGIN CERTIFICATE-----' : '-----BEGIN RSA PRIVATE KEY-----'; const pemFooter = type === 'certificate'? '-----END CERTIFICATE-----':'-----END RSA PRIVATE KEY-----'; let base64Key = pemKey.replace(pemHeader, '').replace(pemFooter, ''); // Remove any newline characters base64Key = base64Key.replace(/\r?\n|\r/g, ''); return base64Key; }; And my CertificateBase64 look like: MIIC3jCCAcYCAQAw...9gBFNQUdahSccXF2bnZkv2Kh PrivateBase64: MIIEowIBAAKCAQE...ooxp1Nyl17zfP I want to create identity to use in https request. I am getting error: Unable to create identity: -25300 My loadIdentity function look like this: func loadIdentity(certificate: String, privateKey: String) -> SecIdentity? { print("privateKey: \(privateKey)") guard let certData = Data(base64Encoded: certificate) else { print("Unable to decode certificate PEM") return nil } print("certData: \(certData)") // Create certificate object guard let cert = SecCertificateCreateWithData(nil, certData as CFData) else { print("Unable to create certificate") return nil } // Add certificate to the keychain let certAddQuery: [NSString: Any] = [ kSecClass: kSecClassCertificate, kSecValueRef: cert, kSecAttrLabel: "myCertificate" ] var status = SecItemAdd(certAddQuery as CFDictionary, nil) if status != errSecSuccess && status != errSecDuplicateItem { print("Failed to add certificate to keychain: \(status)") return nil } guard let keyData = Data(base64Encoded: privateKey) else { print("Unable to decode private key PEM") return nil } print("keyData: \(keyData)") // Define attributes for the private key let keyDict: [NSString: Any] = [ kSecAttrKeyType: kSecAttrKeyTypeRSA, kSecAttrKeyClass: kSecAttrKeyClassPrivate, kSecAttrKeySizeInBits: 2048, kSecReturnPersistentRef: true ] // Create private key object var error: Unmanaged<CFError>? guard let privateKeyData = SecKeyCreateWithData(keyData as CFData, keyDict as CFDictionary, &error) else { // print("Unable to create private key: \(error?.takeRetainedValue() ?? "Unknown error" as CFError)") print("Unable to create private key") return nil } // Add private key to the keychain let keyAddQuery: [NSString: Any] = [ kSecClass: kSecClassKey, kSecValueRef: privateKeyData, kSecAttrLabel: "myPrivateKey", kSecAttrAccessible: kSecAttrAccessibleWhenUnlocked ] status = SecItemAdd(keyAddQuery as CFDictionary, nil) if status != errSecSuccess && status != errSecDuplicateItem { print("Failed to add private key to keychain: \(status)") return nil } // Query to retrieve the identity from the keychain let identityQuery: [NSString: Any] = [ kSecClass: kSecClassIdentity, kSecReturnRef: true, kSecAttrLabel: "myCertificate", kSecMatchItemList: [cert, privateKeyData] ] var identity: CFTypeRef? status = SecItemCopyMatching(identityQuery as CFDictionary, &identity) guard status == errSecSuccess else { print("Unable to create identity") return nil } return (identity as! SecIdentity) }
1
0
155
1w
After creating an hardlink sandboxed app cannot write to it anymore
I'm developing an application that uses hardlinks to track certain files created by the app. Initially, before the hardlink is created, the files behave as expected. For example, if the app generates a .number file, I can open and edit it with Numbers without any issues. However, once the hardlink is created, the file appears locked, and Numbers can no longer write to it. Checking the logs in the Console app, I see that Numbers throws an NSCocoaErrorDomain error with code 513. This problem only occurs with sandboxed apps—non-sandboxed apps like Visual Studio Code work fine. I’ve also tried creating the hardlink manually using the ln command in Terminal, but the behavior is the same. I'm currently on a M1 Pro mac running Sonoma 14.2.1. I've also tried on an intel one running Sonoma 14.4 and the behaviour is the exact same. This issue doesn’t occur with symlinks, but my application specifically requires hardlinks, and I haven't been able to find a workaround. Does anyone have any suggestions?
4
0
247
3w
macOS, SecPKCS12Import, changes in Sequoia
Hello, in macOS 14, SecPKCS12Import uses the P12 friendly name as keychain item label (i.e. the private key´s name). This seems to change with macOS 15, testing with beta 5. Now the private key label is always "Imported Private Key". Will this change stay, or is it just a beta issue? If it stays, will then SecPKCS12Import allow to hand over a custom label, via kSecImportItemLabel? This at least does not work under macOS 14. Thanks, Stephan
1
0
201
Aug ’24
`cp` ( & friends ) silent loss of extended attributes & file flags
Since the introduction of the siblings / and /System/Volumes/Data architecture, some very basic, critical commands seems to have a broken behaviour ( cp, rsync, tar, cpio…). As an example, ditto which was introduced more than 10 years ago to integrate correctly all the peculiarity of HFS Apple filesystem as compared to the UFS Unix filesystem is not behaving correctly. For example, from man ditto: --rsrc Preserve resource forks and HFS meta-data. ditto will store this data in Carbon-compatible ._ AppleDouble files on filesystems that do not natively support resource forks. As of Mac OS X 10.4, --rsrc is default behavior. [...] --extattr Preserve extended attributes (requires --rsrc). As of Mac OS X 10.5, --extattr is the default. and nonetheless: # ls -@delO /private/var/db/ConfigurationProfiles/Store drwx------@ 5 root wheel datavault 160 Jan 20 2024 /private/var/db/ConfigurationProfiles/Store                            ********* com.apple.rootless 28 *************************** # mkdir tmp # ditto /private/var/db/ConfigurationProfiles tmp ditto: /Users/alice/Security/Admin/Apple/APFS/tmp/Settings: Operation not permitted ditto: /Users/alice/Security/Admin/Apple/APFS/tmp/Store: Operation not permitted # ls -@delO tmp/Store drwx------ 5 root wheel - 160 Aug 8 13:55 tmp/Store                            * # The extended attribute on copied directory Store is empty, the file flags are missing, not preserved as documented and as usual behaviour of ditto was since a long time ( macOS 10.5 ). cp, rsync, tar, cpio exhibit the same misbehaviour. But I was using ditto to be sure to avoid any incompatibility with the Apple FS propriaitary modifications. As a consequence, all backup scripts and applications are failing more or less silently, and provide corrupted copies of files or directories. ( I was here investigating why one of my security backup shell script was making corrupted backups, and only on macOS ). How to recover the standard behaviour --extattr working on modern macOS?
1
0
186
Aug ’24
Server Trust Authentication with same URL Session has uncertain response time behavior
Hello Folks I have a Custom UrlSessionDeleagte which is checking server authentication by overriding method func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -&gt; Swift.Void) { if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) { let serverTrust = challenge.protectionSpace.serverTrust // Applying additional validations. if(validated) { completionHandler(.useCredential, URLCredential(trust:serverTrust)) } } else { completionHandler(.performDefaultHandling, nil) } Initialized URL Session as below and reusing it in subsequent requests. if(urlSession != nil) { urlSession = URLSession(configuration: URLSessionConfiguration.Default, delegate: customURLSessionDelegate, delegateQueue : nil) } Now the issue is the uncertainty in response time First request - say took approx 11 secs. Second request if send immediately (&lt; 2 secs difference from last call) - took only 0.2 secs or 1.2 secs. Third request if send after &gt;20 secs - took again 12 secs. I want to know whether it is an implementation issue, or iOS behavior of handling the Server trust Authentication process in this way? Because the time it took after initializing a DataTask to checking server Auth differes. Also when call is sent immdiately it does not checkk Authentication again, but when send a after ~20 secs debugger fall on the Authentication method again, even if the URlsession instance was same.
0
0
181
Aug ’24