Trying to use kSecACLAuthorizationPartitionID

Hi,


I am trying to figure out how I can set the kSecACLAuthorizationPartitionID when creating a private key that will later be used by the macOS system ("apple:"). This key is to be used for things like Wi-Fi (eapolagent) and so on.


I have been experimenting with the below code, the private key is created correctly, ACL is set and it is added to the keychain, however it seems it is overwritten when I add the key to the keychain:


    // create standard access
    SecAccessRef access = SecAccessCreateWithOwnerAndACL(0, 0, kSecUseOnlyUID, NULL, &error);

    // build partitions list
    NSMutableArray* partitions = [[NSMutableArray alloc] init];

    // we want the apple system to be able to sign with this key
    [partitions addObject:@"apple:"];

    NSMutableDictionary *descriptionDict = [[NSMutableDictionary alloc] init];

    [descriptionDict setObject:(__bridge id)partitions
                        forKey:(__bridge id)@"Partitions"];

    NSData *xmlData = [NSPropertyListSerialization dataFromPropertyList:descriptionDict
                                                                 format:NSPropertyListXMLFormat_v1_0
                                                       errorDescription:&error];

    SecACLRef newAcl = NULL;

    status = SecACLCreateWithSimpleContents(access, NULL, (CFStringRef)[self hexStringValue:xmlData], kSecKeychainPromptRequirePassphase, &newAcl);

    NSArray* authorizations = @[(__bridge id)kSecACLAuthorizationPartitionID];

    // update ACL
    status = SecACLUpdateAuthorizations(newAcl, (__bridge CFArrayRef) authorizations);


At this point, if I loop through the access ACLS, all look well.And I proceed to create the key:


SecKeyRef privateKey = SecKeyCreateFromData((CFDictionaryRef)attributes, (CFDataRef)encodedKeyData, &error);


And then add this to the keychain with the access I created above


            NSMutableDictionary *attributes = [[NSMutableDictionary alloc] init];
            [attributes setObject:(__bridge id)privateKey
                           forKey:(id)kSecValueRef];
            [attributes setObject:(id)kSecClassKey
                           forKey:(id)kSecClass];
            [attributes setObject:tag
                           forKey:(id)kSecAttrApplicationTag];
            [attributes setObject:(__bridge id)access
                           forKey:(__bridge id)kSecAttrAccess ];

             err = SecItemAdd((__bridge CFDictionaryRef)attributes, NULL);


All this runs without error, however dumping the keychain, I can see the ACL as follows:


    entry 0:
        authorizations (1): any
        don't-require-password
        description: <NULL>
        applications: <null>
    entry 1:
        authorizations (1): partition_id
        don't-require-password
        description: unsigned:
        applications: <null>
    entry 2:
        authorizations (1): change_acl
        don't-require-password
        description: <NULL>
        applications: <null>

The "unsigned:" is I assume due to me running the app in debug mode, but it looks like the ACL I set is ignored and the keychain API hardcodes this to the caller partition_id.

I have also tried to set the partition_id after adding the key to the keychain, but this requires the password of the User, something we do not want to request for obvious reasons.


Is what I am trying even possible? Can you set the partition_id when creating a key?


Thanks,


S.

Answered by DTS Engineer in 298751022

Is what I am trying even possible?

No it is not. I recently explored this in a different context (r. 33635514) and the response I got from keychain engineering is that there’s no supported way for you to create keychain items which will be silently used by other apps (or the system). User consent must be acquired.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Accepted Answer

Is what I am trying even possible?

No it is not. I recently explored this in a different context (r. 33635514) and the response I got from keychain engineering is that there’s no supported way for you to create keychain items which will be silently used by other apps (or the system). User consent must be acquired.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

do you know if they will be changing this to using something similar to rhe authorization api? instead of requiring the password via command line or api?


if we start asking the users password in our application we will be bombarded by complaints.. it is such a bad way of getting user consent,it really baffles me apple chose this route...


i was also wonderinf if there is a way to give any access wirhout requiring consent?


S.

do you know if they will be changing this to using something similar to rhe authorization api?

Sorry, but I can’t talk about The Future™.

i was also wonderinf if there is a way to give any access wirhout requiring consent?

I’m not sure I understood this part of your question because it’s seems to be directly answered by my previous point.

I think you need to take a step back and look at the big picture. Earlier you wrote:

I am trying to figure out how I can set the

kSecACLAuthorizationPartitionID
when creating a private key that will later be used by the macOS system ("apple:"). This key is to be used for things like Wi-Fi (eapolagent) and so on.

I’m not super familiar with the Wi-Fi side of things but in other parts of the system, like

NEVPNManager
, the API that you use to create the configuration is responsible for putting the necessary credentials in the keychain such that it can be accessed by the underlying system components [1]. So, rather than look at the keychain minutiae, I recommend that you look at the high-level API you’re using to configure the Wi-Fi.

Are you using CoreWLAN for this? Is it not doing the right thing with regards keychain access?

Finally, are you doing this for an enterprise deployment? If so, you might want to look at using a configuration profile, which is much easier than writing a bunch of code.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

[1] In fact

NEVPNManager
does not do this properly, which is how I got into this issue in the first place.

> Sorry, but I can’t talk about The Future™.

yes, and we have an outstanding bug, however due to it being tagged as duplicate we have no way of knowing if this will be fixed and can just pray for a "fixed" status change and reading the Apple release notes...



> I’m not super familiar with the Wi-Fi side of things but in other parts of the system, like

NEVPNManager
, the API that you use to create the configuration is responsible for putting the necessary credentials in the keychain such that it can be accessed by the underlying system components [1].and to c


The problem is simply, we create a private key (using our partition_id) and when macOS tries to access this it does this via eapolagent (using the partition_id "apple:") which prompts the user 2 or more times. We also tried using import via pkcs12 using the security cmd line tool, but the same issue occurs, it creates uses the partition_id "apple-tool" which again means eapolagent has to prompt. If we could create the key with the partition_id of "apple:" things would be fine.


> Finally, are you doing this for an enterprise deployment? If so, you might want to look at using a configuration profile, which is much easier than writing a bunch of code.


Unfortunatly the .mobileconfig creates the private key as Exportable which is simply not secure enough for our needs.

yes, and we have an outstanding bug

What’s that bug number?

Unfortunatly the .mobileconfig creates the private key as Exportable which is simply not secure enough for our needs.

I think an enhancement request for a way to control that is warranted here.

How are you creating the Wi-Fi itself? Via CoreWLAN? Or via a configuration profile?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi,


> What’s that bug number?


37536047 (duplicate of 38179303)

> I think an enhancement request for a way to control that is warranted here.


ok


> How are you creating the Wi-Fi itself? Via CoreWLAN? Or via a configuration profile?


We currently imported the key via pkcs12 and we create it the Wi-Fi configuration via a configuration profile (.mobileconfig).


S.

We currently imported the key via pkcs12 and we create it the Wi-Fi configuration via a configuration profile (.mobileconfig).

So you’re mixing programmatic creation of the digital identity in the keychain and a configuration profile to create the Wi-Fi configuration itself. Right?

Have you tried doing the whole thing CoreWLAN?

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi,
I believe we ran into other issues when using the CoreWLAN.


I also feel this will not help the issue, currently we need the password if we want to correctly setup our keys for use with the eapolagent...


S.

I believe we ran into other issues when using the CoreWLAN.

Hmmm, that’s kinda vague.

The reason I keep pushing on the CoreWLAN side of things is that there is very little chance of you being able to create a keychain item that will be used by the system without some sort of user consent. This isn’t an accidental omission but an explicitly security feature.

On the other hand, if you set this up using CoreWLAN then the system has more information about the context of your request and you may find that things Just Work™. Or, if they don’t, you can file an enhancement request that has some hope for a successful resolution.

Notably, CoreWLAN already has high-level APIs for manipulating Wi-Fi credentials, namely, the routines in

<CoreWLAN/CoreWLANUtil.h>
.

I also feel this will not help the issue, currently we need the password if we want to correctly setup our keys for use with the eapolagent...

I’m not sure what you mean by this.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

So this is what the key looks like when importing a key via SCEP/mobileconfig:


   entry 0:
        authorizations (6): decrypt derive export_clear export_wrapped mac sign
        don't-require-password
        description: Config Profiles Cert Access
        applications (7):
            0: /System/Library/PrivateFrameworks/ConfigurationProfiles.framework/XPCServices/CertificateService.xpc (OK)
            1: 0x67726F75703A2F2F436F6E66696775726174696F6E50726F66696C657300  "group://ConfigurationProfiles\000"
            2: /System/Library/CoreServices/ManagedClient.app (OK)
            3: /usr/libexec/mdmclient (OK)
            4: /System/Library/SystemConfiguration/EAPOLController.bundle/Contents/Resources/eapolclient (OK)
            5: /System/Library/CoreServices/SystemUIServer.app (OK)
            6: 0x67726F75703A2F2F416972506F727400  "group://AirPort\000"
    entry 1:
        authorizations (1): encrypt
        don't-require-password
        description: Config Profiles Cert Access
        applications: <null>
    entry 2:
        authorizations (1): integrity
        don't-require-password
        description: cd63ddbeeff94b4b1cef3977c835c60a88bd2ce88b518f1b4a517315b019a854
        applications: <null>
    entry 3:
        authorizations (1): change_acl
        don't-require-password
        description: Config Profiles Cert Access
        applications (2):
            0: 0x67726F75703A2F2F436F6E66696775726174696F6E50726F66696C657300  "group://ConfigurationProfiles\000"
            1: /usr/libexec/nehelper (OK)

As you can see the partition_id is NOT set. By doing this pretty much anyone can access the key. You can see they add the eapolclient and the Airport as trusted applications.


What I need to know is how did they do this??


If I import the private key I always end up with this:


   entry 0: 
        authorizations (1): any 
        don't-require-password 
        description: <NULL> 
        applications: <null> 
    entry 1: 
        authorizations (1): partition_id 
        don't-require-password 
        description: unsigned: 
        applications: <null> 
    entry 2: 
        authorizations (1): change_acl 
        don't-require-password 
        description: <NULL> 
        applications: <null>

Any ideas?


S.

I am still waiting for 1 on my responses to be unmoderated...


But in response to your previous questions:


> On the other hand, if you set this up using CoreWLAN then the system has more information about the context of your request and you may find that things Just Work™.

> I’m not sure what you mean by this.


COREWLAN still expects a SecSecurityIdentityRef when setting up the WLAN for TLS:


- (BOOL)associateToEnterpriseNetwork:(CWNetwork *)network
                            identity:(SecIdentityRef)identity
                            username:(NSString *)username
                            password:(NSString *)password
                               error:(out NSError * _Nullable *)error;

Utils:


OSStatus CWKeychainSetWiFiEAPIdentity( CWKeychainDomain domain, NSData *ssid, __nullable SecIdentityRef identity ) NS_AVAILABLE_MAC(10_9);


So we are still stuck with the original error, how do you create a key that would allow the COREWLAN (eapolagent) to use the key?


Or are you saying the key we create with locked down partition_id will magically™ work for the eapolagent, meaning it circumvents this security...?

UPDATE: tried the above commands with an in memory SecIdentityRef just for the heck of it and it returns "Unable to allocate memory" which seems to me a like a typical error message when someone cannot load a something from the keychain. Trying this with a key in the keychain results in the prompt I am trying to prevent "eapolagent wants to access... [Always allow][allow]".


The .mobileconfig frameworks somehow manages to create a key WITHOUT partition_id, as you can see in my previous post that is currently being moderated. This means anyone in the Application list can use it and it does not request the password from the User directly, it uses the normal Security Authorization as far as I can tell.


S.

Small update, I managed to get the partition_id in there..



entry 1:
        authorizations (1): partition_id
        don't-require-password
        description: apple:
        applications: <null>
    entry 2:
        authorizations (1): encrypt
        don't-require-password
        description: Config Profiles Cert Access
        applications: <null>
    entry 3:
        authorizations (1): integrity
        don't-require-password
        description: aae8f8a0190cac7f58f401891447ed4085a0b868772275b691963e99aaabeaa8
        applications: <null>
    entry 4:
        authorizations (1): partition_id
        don't-require-password
        description: unsigned:
        applications: <null>


But now it has 2 entries...

S.

What I need to know is how did they do this??

This isn’t a huge mystery. System components have a more flexibility when it comes to configure keychain item access control. Consider entry 0 in the ACL you posted, where the last item is

group://AirPort
. Group access is another thing that’s not supported for third-party developers.

Which brings me back to the CoreWLAN framework. As part of the system it may be possible to get it to set things up correctly. Or, if that’s not possible, it could be made to do that.

At this point I think this issue is beyond what I can reasonably help you with on DevForums. If you’d like more in-depth with it, I recommend that you open a DTS tech support incident and we can pick it up in that context.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Hi,


Well tbh, I have managed to get it all setup, but as you can see I end up with 2 entries for the partition_id. I was hoping the apple framework would grab the first partition_id it finds, but looks like this is not the case 😟


> Group access is another thing that’s not supported for third-party developers.
This you mean?


/ * Create an application group reference. */
OSStatus SecTrustedApplicationCreateApplicationGroup(const char *groupName,
SecCertificateRef anchor, SecTrustedApplicationRef *appRef)


> Which brings me back to the CoreWLAN framework. As part of the system it may be possible to get it to set things up correctly. Or, if that’s not possible, >it could be made to do that.

Can you explain this some more? I have looked at the CoreWLAN framework and I do not see a way to create a private key that can be used by the eapolagent using any of these functions.


> At this point I think this issue is beyond what I can reasonably help you with on DevForums. If you’d like more in-depth with it, I recommend that you open > a DTS tech support incident and we can pick it up in that context.


Thanks, I have opened a case.


S.

Despite the age of this post, it seems the circumstance and issue (above) has not changed on macOS 11.4 as of 2021-08-09.

Just wondering @secure whether DTS was able to assist with your usage and if so, whether their solution may be shared for the benefit of the broader community? Or perhaps Apple requires others with same need to open DTS cases? I can open case, but only if it appears they may be able to help find a workable solution.

Thanks for your detailed post on this rather esoteric topic.

Trying to use kSecACLAuthorizationPartitionID
 
 
Q