Posts

Post not yet marked as solved
3 Replies
299 Views
We generated key pair and imported associated cert into keychain. We stored value of kSecAttrPublicKeyHash and use it to find matching certificate and private key later. However we have some legacy code that requests to get SecIdentityRef. We can retrieve SecCertificateRef with matched value of kSecAttrPublicKeyHash and private key with kSecAttrApplicationLabel. But we don't know how to generate/query SecIdentityRef with SecCertificateRef and SecKeyRef. API SecIdentityCreateWithCertificate is only available on macOS. Is there any equivalent API on iOS? Thanks, Ying
Posted
by yingha.
Last updated
.
Post marked as solved
5 Replies
564 Views
We generate key pair and import cert with access flag kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly in our application. We then have notification extension that access shared keychain to retrieve the identity when device is locked. We use SecItemCopyMatching to get all SecIdentity with its attributes as below: let queryDict: [String: Any] = [ kSecClass as String: kSecClassIdentity, kSecReturnAttributes as String: true, kSecReturnRef as String: true, kSecMatchLimit as String: kSecMatchLimitAll ] var oss = SecItemCopyMatching(queryDict as CFDictionary, &attrs) When the code runs on notification extension with locked device, it failed on some devices (not on all devices) with error -25308. The sysdiagnose shows: default securityd 2024-03-14 10:49:13.844996 -0400 129 0x110115 SecDbKeychainItemV7: cannot decrypt metadata key because the keychain is locked (-25308) default securityd 2024-03-14 10:49:13.845036 -0400 129 0x110091 NSExtension[2222]/1#7 LF=0 copy_matching Error Domain=NSOSStatusErrorDomain Code=-25308 "ks_crypt: e00002e2 failed to 'od' item (class 6, bag: 0) Access to item attempted while keychain is locked." UserInfo={numberOfErrorsDeep=0, NSDescription=ks_crypt: e00002e2 failed to 'od' item (class 6, bag: 0) Access to item attempted while keychain is locked.} We also try to use access flag kSecAttrAccessibleAlwaysThisDeviceOnly, but it doesn't make difference. Since securityd reports "cannot decrypt metadata key because keychain is locked". I wonder if it is because we query attributes for all identity. Is it a bug on Security framework? Thanks, Ying
Posted
by yingha.
Last updated
.
Post not yet marked as solved
5 Replies
517 Views
We have app and notification extension both loading an agent lib to access the same files with read/write/delete operations. To avoid app and notification extension access the file simultaneously, we use boost::interprocess::file_lock when app enters foreground and notification extension didReceive notifications. If extension failed to grab file lock, it will skip loading agent and returns. If app failed to grab file lock, it will start a timer to keep trying while UI will display spinner. Sometimes we saw crash report from our app with: Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: RUNNINGBOARD 3735883980 Triggered by Thread: 0 The code 3735883980 indicate "deadlock" - The operating system terminated the app because it held on to a file lock or SQLite database lock during suspension. In sysdiagnose, we also see "[osservice<com.apple.InputUI>:1496] check if suspended process is holding locks" in runningboardd process. Does it mean that our app fail to unlock? We did lock when app enters foreground and unlock when app goes to background. Is there anything we did wrong? @implementation FileLock -(id)init { self = [super init]; if (nil != self) { // Find empty lock file, created if it doesn't exist. FILE *file = fopen(lockFile.c_str(), "a"); if (file) { fclose(file); } m_lock = boost::make_shared<boost::interprocess::file_lock>(lockFile.c_str()); } return self; } -(BOOL)lock { return m_lock->try_lock(); } -(void)unlock { return m_lock->unlock(); } @end func applicationDidBecomeActive(_ application: UIApplication) { if !bFileLockAcquired { if fileLock.lock() { bFileLockAcquired = true // load agent } else { lockTimer = Timer.scheduledTimer(withTimeInterval: 1.0, repeats: true, block: { _ in DispatchQueue.main.async { if fileLock.lock() { self.lockTimer?.invalidate() self.lockTimer = nil bFileLockAcquired = true // load agent } } }) } } func applicationDidEnterBackground(_ application: UIApplication) { self.lockTimer?.invalidate() self.lockTimer = nil fileLock.unlock() bFileLockAcquired = false }
Posted
by yingha.
Last updated
.
Post marked as solved
1 Replies
313 Views
We use OSLog to log message in our iOS app and retrieve logs to save into local file when app goes to background. This way we will be able to persist logs after app terminated. However, when logs become large, retrieving logs takes more than 5 seconds during background transition that cause our app being killed by the system with below info: Exception Type: EXC_CRASH (SIGKILL) Exception Codes: 0x0000000000000000, 0x0000000000000000 Termination Reason: FRONTBOARD 2343432205 <RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-update watchdog transgression: app<com.cisco.secureclient.zta(B7AB7300-8A17-4C71-88BC-BA3D55AF6666)>:1261 exhausted real (wall clock) time allowance of 10.00 seconds ProcessVisibility: Background ProcessState: Running WatchdogEvent: scene-update WatchdogVisibility: Background WatchdogCPUStatistics: ( "Elapsed total CPU time (seconds): 13.500 (user 10.890, system 2.610), 21% CPU", "Elapsed application CPU time (seconds): 2.119, 3% CPU" ) reportType:CrashLog maxTerminationResistance:Interactive> Triggered by Thread: 0 Thread 0 name: Dispatch queue: com.apple.main-thread Thread 0 Crashed: 0 libsystem_kernel.dylib 0x1ed6e01d8 mach_msg2_trap + 8 1 libsystem_kernel.dylib 0x1ed6dff70 mach_msg2_internal + 80 2 libsystem_kernel.dylib 0x1ed6dfe88 mach_msg_overwrite + 436 3 libsystem_kernel.dylib 0x1ed6dfcc8 mach_msg + 24 4 libdispatch.dylib 0x1aea4df00 _dispatch_mach_send_and_wait_for_reply + 540 5 libdispatch.dylib 0x1aea4e2a0 dispatch_mach_send_with_result_and_wait_for_reply + 60 6 libxpc.dylib 0x20fd406d0 xpc_connection_send_message_with_reply_sync + 264 7 Foundation 0x1a5ad96c0 NSXPCCONNECTION_IS_WAITING_FOR_A_SYNCHRONOUS_REPLY + 16 8 Foundation 0x1a5ac13bc -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 2160 9 Foundation 0x1a5aec6cc -[NSXPCConnection _sendSelector:withProxy:arg1:] + 116 10 Foundation 0x1a5aec604 _NSXPCDistantObjectSimpleMessageSend1 + 60 11 OSLog 0x1f4b98118 -[OSLogCurrentProcessEnumerator nextObject] + 192 12 libswiftOSLog.dylib 0x213983270 OSLogStore.PrivateIterator.next() + 32 13 libswiftOSLog.dylib 0x213983324 protocol witness for IteratorProtocol.next() in conformance OSLogStore.PrivateIterator + 28 14 libswiftCore.dylib 0x1a0050ed0 _IteratorBox.next() + 108 15 MyApp 0x104359e28 static MyLogger.getFormattedLogs() (in MyApp ) (MyLogger.swift:63) + 122408 Here is our code to retrieve logs: struct MyLogger { public var log: Logger init(subsystem: String = getSubsystem(), file: String = #file, function: String = #function, line: Int = #line, context: String = "myapp") { let category = "\(context): \(file): \(line): \(function): " log = Logger(subsystem: subsystem, category: category) } static func getFormattedLogs() -> [String] { do { // Combine log message with timestamp and category with // file/line/function information let df = DateFormatter() df.dateFormat = ZtaConstants.DATE_FORMAT let store = try OSLogStore.init(scope: .currentProcessIdentifier) let logEntries = try store.getEntries() .compactMap{ $0 as? OSLogEntryLog} .filter { $0.subsystem.contains(getSubsystem() } .map{df.string(from: $0.date) + " " + String(format:"0x%02x", $0.threadIdentifier) + " " + String(format:"0x%x", $0.activityIdentifier) + " " + String($0.processIdentifier) + " " + $0.category + " " + $0.composedMessage} return formattedLogs } catch let err { ZtaLogger().log.error("Failed to collect log: \(err)") return [] } } } It looks like getFormattedLogs() takes long time because we use filter to get message that logged by our app and format the log entry. Since compactMap is O(m+n) complexity, filter and map are O(n) that cause performance issue. Is there a better way to get logs from our app via OSLog? Could retrieving logs be called in appDidEnterBackground()? Thanks, Ying
Posted
by yingha.
Last updated
.
Post marked as solved
1 Replies
341 Views
We have implemented a Notification Service Extension in our app to handle remote notification and access keychain to get certificate and identity to refresh network relay configuration. Using SecItemCopyMatching to get SecIdentityRef works when device is unlocked. Whenever push notification arrives and device is locked, our notification service extension failed to access keychain to get identity reference with error code -25308 errSecInteractionNotAllowed. It looks like keychain is locked when device is locked. Is there a way to make keychain unlocked?
Posted
by yingha.
Last updated
.
Post not yet marked as solved
1 Replies
307 Views
We have an Enterprise Apple developer account “Cisco System, Inc. “STBU” - JBF29L28EJ”. We use it to make in-house distribution for QE testing. I found that development provisioning profile in this account includes new “relay” capability in the entitlement, but in-house distribution provisioning profile doesn’t have it. Below is the entitlement list in in-house distribution provisioning profile that doesn't include "relay": Entitlements &amp;lt;dict&amp;gt; &amp;lt;key&amp;gt;com.apple.developer.networking.networkextension&amp;lt;/key&amp;gt; &amp;lt;array&amp;gt; &amp;lt;string&amp;gt;app-proxy-provider&amp;lt;/string&amp;gt; &amp;lt;string&amp;gt;content-filter-provider&amp;lt;/string&amp;gt; &amp;lt;string&amp;gt;packet-tunnel-provider&amp;lt;/string&amp;gt; &amp;lt;string&amp;gt;dns-proxy&amp;lt;/string&amp;gt; &amp;lt;string&amp;gt;dns-settings&amp;lt;/string&amp;gt; &amp;lt;/array&amp;gt; &amp;lt;key&amp;gt;aps-environment&amp;lt;/key&amp;gt; &amp;lt;string&amp;gt;production&amp;lt;/string&amp;gt; We now cannot make in-house distribution build without this entitlement.
Posted
by yingha.
Last updated
.
Post not yet marked as solved
0 Replies
380 Views
After installed iOS 17 beta 6 image on iPhone 14 Pro Max, the "Developer Mode" disappeared from system settings. Now Xcode doesn't recognize my device because Developer Mode is off. Is there anyway to turn it on? The previous iOS 17 beta 3 image works fine.
Posted
by yingha.
Last updated
.
Post not yet marked as solved
9 Replies
2.2k Views
I try to use SecPKCS12Import to retrieve SecIdentityRef from PKCS#12 blob and store SecCertificateRef &amp; SecKeyRef into keychain separately, so that I can use kSecAttrAccessControl to only protect private key with TouchID. The same code works on iOS, but not on Mac. The problem is SecPKCS12Import already saved the identity into keychain. I tried to delete the stored identity, however, no matter using SecItemDelete with transient reference or persistent reference of identity or delete both SecCertficateRef and SecKeyRef, the record will be deleted from keychain -&gt; My Certificates and keychain -&gt; Keys, but alwasy leave the certficate in keychain -&gt; Certificates. If I use SecItemAdd to add certificate back, I got errSecDuplicateItem, using SecItemCopyMatching or SecItemDelete, I got errSecItemNotFound. The strange part is, even I open keychain app to manually delete the cert, I got error prompt saying deleting item not found, but after that, the cert disppear from keychain -&gt; Certificates.Since I cannot delete identity and the add it back with access control attributes. I tried to use SecItemImport to avoid saving identity into keychain. However, this API only returns list of SecCertificateRef instead of SecIdentityRef. I found similar issue discussed on https://forums.developer.apple.com/thread/31711Is there anyway to retreive identity from PKCS#12 blob and make kSecAttrAccessControl protect the private key only?
Posted
by yingha.
Last updated
.
Post not yet marked as solved
0 Replies
548 Views
Hi, we uses WKWebView to load IDP login page and the client cert authentication is also required after user credential submitted. We implemented didReceiveAuthenticationChallenge function to retrieve the client cert from our app and create NSURLCredential with NSURLCredentialPersistenceNone. However, we found the client cert get cached. When IDP issues a new client cert and the old cert become invalid, although the user import the new cert into our app, the cache of the old cert is used, didReceiveAuthenticationChallenge is not called. We tried to use WKWebsiteData to delete all cookies and website data include WKWebsiteDataTypeMemoryCache, disckCache and localStorage, but no luck. The only workaround is terminate our app and restart it will clear the cache. Is there anything we missed? Thanks, Ying
Posted
by yingha.
Last updated
.