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)
}
}
}
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
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?
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.
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?
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)
}
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?
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
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?
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?) -> 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 (< 2 secs difference from last call) - took only 0.2 secs or 1.2 secs.
Third request if send after >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.
As a system & security administrator I started to install a lot of Unixes, 20 years ago with a dual volume for security purpose, inside critical
infrastructures:
volume mount options
------------------------------------------------
/ ro
/var rw, nosuid, nodev
Everything which could be end user or admin modifiable and to be referenced from / was defined through simple symbolic links:
/tmp --> /var/tmp
/home --> /var/home
/local --> /var/local
/opt --> /var/opt
/private --> /var/private
And through many tests, and real attacks pressure of every day, with such a configuration, even as root, it was impossible to damage the system. Many attacks struck us ( ~ 20 / day )… none succeeded ( at
least as I was aware of, and as I wasn't fired ).
Why did Apple chose a rather more complex way similar architectures with the 2 volumes:
volume mount options
------------------------------------------------
/ ro
/System/Volumes/Data rw, nosuid, nodev
with a new concept of firmlinks which is not compatible with any
other Unix FS, which brought Apple to put fundamental components of their new APFS outside of the FS internals ( in plain old files ) and which is rather very tricky to understand and to manage for system and security administrator?
To give just one example of an highly deceiving point:
it isn't now possible to make a quick carbon copy of a volume with
tools as simple as cp or rsync because of new extended attributes.
Real life teach us everyday that complexity is one of the biggest enemy of performance and security.
What are the advantages of this sibling volumes architecture?
( I am not talking here of the real internal advantages of APFS versus
HFS and traditionnal Unix UFS or ZFS, which I much easily grasped and verified in real life. ).
My app already has an app lock system which includes text & biometric combinations. Now iOS 18 has introduced a passcode lock for every app. So if users want to enable the app lock provided by us (developer), we want to inform them that you have enabled the iOS-provided app lock, in addition to that do you want to allow app-specific lock? For this, developers want to know whether iOS-provided app lock is enabled.
-Rajdurai
Hello,
When we detect that our user has not configured a pin or biometric security on their phone, we'd like to prompt them to configure a pin code from our iOS app. Reading through the security doc, I didn't see an API to do so. Is there a way to do such?
Thanks
I regularly see questions, both here on DevForums and via DTS code-level support requests, from developers who are working with a security auditor. This is a tricky topic, and I’m using this post to collect my thoughts on it.
If you have questions or comments, please start a new thread. Put it in Privacy & Security > General and tag it with Security; that way I’m more likely to see it.
Share and Enjoy
—
Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"
Security Audit Thoughts
DTS is a technical support organisation, not a security auditing service. Moreover, we don’t work with security auditors directly. However, we regularly get questions from developers who are working with a security auditor, and those often land in my queue. Given that, I’ve created this post to collect my ideas on this topic.
I see two types of security audits:
static analysis — This looks at the built code but doesn’t run it.
dynamic analysis — This runs the code and looks at its run-time behaviour.
While both techniques are valid, it’s critical that you interpret the resulting issues correctly. Without that, you run the risk of wasting a lot of time investigating issues that are not a problem in practice. In some cases it’s simply impossible to resolve an issue. And even if it is possible to resolve an issue, it might be a better use of your time to focus on other, more important work.
A good security auditor should understand the behaviour of the platform you’re targeting and help you prioritise issues based on that. My experience is that many security auditors are not that good )-:
Static Analysis
The most common issue I see relates to static analysis. The security auditor runs their auditing tool over your built product, it highlights an issue, and they report that to you.
These issues are usually reported with logic like this:
Routine f could be insecure.
Your program imports routine f.
Therefore your program is insecure.
This is logically unsound. The problem is with step 1: Just because a routine might be insecure, doesn’t mean that your use of that function is insecure.
Now, there are routines that are fundamentally insecure (I’m looking at your gets!). Your security auditor is right to highlight those. However, there are many routines that are secure as long as you call them correctly. Your security auditor should understand the difference.
The canonical example of this is malloc. Calling malloc is not a fundamentally insecure operation. Sure, the world would be a better place if everyone used memory-safe languages [1], but that’s not the world we live in.
If your security auditor highlights such a routine, you have two options:
Rewrite your code to avoid that routine.
Audit your use of that routine to ensure that it’s correct.
This is something that you’ll have to negotiate with you security auditor.
[1] Or would it? (-: The act of rewriting all that code is likely to produce its own crop of security bugs.
Tracking Down the Call Site
In most cases it’s easy to find the call site of a specific routine. Let’s say your security auditor notices that you’re calling gets and you agree that this is something you really should fix. To find the call site, just search your source code for gets.
In some case it’s not that simple. The call site might be within a framework, a static library, or even inserted by the compiler. I have a couple of posts that explain how to track down such elusive call sites:
Using a Link Map to Track Down a Symbol’s Origin
Determining Why a Symbol is Referenced
The first is short and simple; the second is longer but comprehensive.
Apple Call Sites
In some cases the call site might be within Apple code. You most commonly see this when the Apple code is inserted in your product by the toolchain, that is, programs like the compiler and linker that are used to build your product.
There are two ways you can audit such call sites:
Disassemble the code and audit the assembly language.
Locate the source of the code and audit that.
The latter only works when the toolchain code is open source. That’s commonly true, but not universally.
If you’re unable to track down the source for an Apple call site, please start a thread here on DevForums with the details and we’ll try to help out.
If you’re analysis of the Apple call site indicates that it uses a routine incorrectly, you should absolutely file a bug about that.
Note Don’t file a bug that says “The Swift compiler inserted a call to malloc and that’s insecure.” That just wastes everyones time. Only file a bug if you can show that the code uses malloc incorrectly.
Dynamic Analysis
The vast majority of security audit questions come from static analysis, but every now and again I’ll see one based on dynamic analysis. However, that doesn’t change the fundamentals: Dynamic analysis is not immune from faulty logic. For example, the following sequence suffers from exactly the same logic problem that I highlighted for static analysis:
Routine f could be insecure.
Something in your process calls routine f.
Therefore your program is insecure.
However, there are two additional wrinkles. The first is that you might not have any control over the code in question. Let’s say you’re using some Apple framework and it calls gets [1]. What can you do about that?
The obvious thing is not use that framework. But what if that framework is absolutely critical to your product. Again, this is something you need to negotiate with your security auditor.
The second wrinkle is the misidentification of code. Your program might use some open source library and an Apple framework might have its own copy of that open source library [2]. Are you sure your security auditor is looking at the right one?
[1] Gosh, I hope that’s never the case. But if you do see such an obvious security problem in Apple’s code, you know what to do.
[2] That library’s symbols might even be exported, a situation that’s not ambiguous because of the two-level namespace used by the dynamic linker on Apple platforms. See An Apple Library Primer for more on that.
Hi Apple,
Recently, we transferred an app from one Team ID to another (keeping the same App ID) and noticed that the app distributed with the new Team ID has lost access to the keychain values created by the old Team ID. We found an article on the Apple Developer Forums (https://developer.apple.com/forums/thread/706128) that explains this issue, but we want to confirm if this is still true.
A client asked why we can't detect other apps installed on a device without an MDM profile, we explained this isn't possible due to privacy and security restrictions on iOS. A regular app cannot find other apps that are installed unless part of the same group.
The client then told us to download SpyBuster (on the App Store) which somehow is collecting a list of Bundle IDs or names of all installed apps somehow.
We were skeptical, but sure enough, the app showed us a list of apps we had installed. How is it doing this?!?! No MDM profile associated with the app. No special permissions requested. No access to anything shown in privacy & security in settings.
Is there a special entitlement we're not aware of?
Just seems like they must be using a private API call to get this info but that would of course mean it should be pulled from the App Store. We'd love to have this capability in our apps if it's legit and accepted by App Store review.
Thanks!
We are interested in using a hardware-bound key to sign requests made to a server prior to a user being logged in. We would do this using a launch daemon. The goal here is to have a high degree of assurance that a request came from a particular device.
The normal way to do this would be with a private key in the Secure Enclave.
Based on these threads:
https://forums.developer.apple.com/forums/thread/719342
https://forums.developer.apple.com/forums/thread/115833
and the write-up about the Data Protection Keychain, it doesn't appear possible with the SE. Rather, it seems that we must wait until we have a logged-in user context before we can use the SE.
My questions are:
am I correct in that the SE is not usable in the system context prior to login?
is there any other way on macOS to sign a request in such a way that we know it comes from a specific device?
Thanks.
Hi everyone,
I'm currently developing a custom authorization plugin for macOS and have encountered an issue that I need help with. I've modified the auth DB to use my custom plugin instead of the default login window. Although I'm able to set both the name and password as context values, the login process is failing, and I'm seeing the following error in the security agent log:
<string>builtin:prelogin</string>
<string>builtin:policy-banner</string>
<string>MyPlugin:login</string>
<string>MyPlugin:value</string>
<string>builtin:login-begin</string>
<string>builtin:reset-password,privileged</string>
<string>loginwindow:FDESupport,privileged</string>
<string>builtin:forward-login,privileged</string>
<string>builtin:auto-login,privileged</string>
<string>builtin:authenticate,privileged</string>
<string>PKINITMechanism:auth,privileged</string>
<string>builtin:login-success</string>
<string>loginwindow:success</string>
<string>HomeDirMechanism:login,privileged</string>
<string>HomeDirMechanism:status</string>
<string>MCXMechanism:login</string>
<string>CryptoTokenKit:login</string>
<string>PSSOAuthPlugin:login-auth</string>
<string>loginwindow:done</string>
I am setting name and password in MyPlugin:login and also able to see same in MyPlugin:value mechanics.
2
2024-07-25 06:53:30.813047-0700 0x2e3b Info 0x0 822 0 SecurityAgentHelper-x86_64: (MyPlugin) *****The name and password is test and test1234****
But
2024-07-25 02:33:00.777530-0700 0x8772 Debug 0x0 1527 0 SecurityAgent: (MCXMechanism) [com.apple.ManagedClient:MCXSecurityPlugin] MCXSecurityAgent.invoke kAuthorizationEnvironmentName is NULL
2024-07-25 02:33:00.777530-0700 0x8772 Debug 0x0 1527 0 SecurityAgent: (MCXMechanism) [com.apple.ManagedClient:MCXSecurityPlugin] MCXSecurityAgent.invoke - user logging in is '(null)'
Has anyone encountered this issue before or have any insights into what might be causing the kAuthorizationEnvironmentName is NULL error and why the user logging in is shown as '(null)'? Any guidance or suggestions on how to resolve this would be greatly appreciated.
Hello!
I have a question regarding AVSpeechSynthesizer and privacy concerns.
Does the processing in AVSpeechSynthesizer occur on device, or is any part of the audio or text shared with Apple for service improvement or other purposes?
I created a simple web browser using WKWebView, but as far as I can tell, there is not a way to auto-populate credentials or save credentials a user enters into a login form at a 3rd-party website like Netflix (i.e., not my own app domain).
Is this correct?
If this is wrong, what are the APIs to support this?
My use case is that I want to create an immersive app in visionOS that includes a window that lets the user surf the web (among other things). Ideally, I could just use a Safari window in my immersive app, but I don't think this is possible either. My work around is to create my own web browser... which works, minus the credential issue.
Is it possible to bring a Safari window into an immersive visionOS app's experience? (IMHO, that would be a great feature)
Hi Folks,
I have a need to create and store a 256 bit symmetric key that I use to encrypt and decrypt data stored on disk. There is also a need to continue to do this both in the backgroud and in the application extensions.
As far as I know, SE does not work with symmetric key, but there is an option to encrypt the symmetric key with an SE-protected asymmetric key. The question arises, how is this different from just storing the key in Keychain, since I can't take advantage of SE's main advantage of not storing the key in memory, even for a short time. (Anyway, I can't not store the key in memory anyway, because the key is used by a third-party framework.)
Should I also use SE for this purpose, decrypt my symmetric key, give the symmetric key to the framework for a short time and then zeroize it?