Keychain Access Controls Not Working

Hi, I'm currently trying to impose access controls on keychain entries in the mobile app I'm developing. I'm interfacing the keychain through rust that is bound to objective c.

I can execute successful crud on the keychain service and when I add access control via kSecAttrAccessControls in the CFDictionary I pass into SecItemAdd it seems to work well as this is the dictionary printed before being passed into SecItemAdd:

{
    accc = "<SecAccessControlRef: aku;prp(true);odel(true);oe(true);od(cbio(pbioc()))>";
    acct = "app-user";
    class = genp;
    labl = App;
    svce = "com.app";
    "u_AuthCtx" = "LAContext[1:1704:3894]";
    "v_Data" = {length = 10, bytes = 0x50617373776f72643121};
}

The aku in the input accc field is recognized in the result as you can see in the pdmn field but accc field is unknown, this is the result of calling SecItemCopyMatching:

UUID: "90DAA5D5-A21A-45AA-97D8-E3B99C763476"
accc: "unknown"
acct: "app-user"
agrp: "***.com.app"
cdat: "2023-07-12 10:57:08 +0000"
class: "genp"
labl: "App"
mdat: "2023-07-12 10:57:08 +0000"
musr: ""
pdmn: "aku"
sha1: "����\u0016\\�;\u000f�K���Z�?0��"
svce: "com.app"
sync: "unknown"
tomb: "unknown"
v_Data: "Hello"

As well this is for SecAccessControl created with flags for Biometry_any or Application_Password but I've tried with just Application Password as well and same result.

Any ideas why this would not be working?

I’m not sure what this unknown stuff is. It’s not something I recognise, and I suspect it’s related to your bridging infrastructure. But, just to set baseline, pasted in below you’ll find some Swift code that protects a secret using biometrics. When I run this on my device and tap the Add and then the Copy button, I see it print this:

will add
did add
will copy
did copy, result: {
    accc = "<SecAccessControlRef: ak;od(cbio(pbioc(3D3EB4198249B9BE43B4D179BB0835C0)));odel(true);oe(true)>";
    acct = mrgumby;
    agrp = "SKMME9E2Y8.com.example.apple-samplecode.Test733702";
    cdat = "2023-07-13 09:14:17 +0000";
    mdat = "2023-07-13 09:14:17 +0000";
    musr = {length = 0, bytes = 0x};
    pdmn = ak;
    sha1 = {length = 20, bytes = 0x8d3a6c92312eb79e165a830b13649e130043b52b};
    svce = test;
    sync = 0;
    tomb = 0;
    "v_Data" = {length = 8, bytes = 0x6f70656e646f6f72};
}

Note This code uses the helpers from here.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

func addAction() {
    do {
        print("will add")
        let access = try secCall {
            SecAccessControlCreateWithFlags(nil, kSecAttrAccessibleWhenUnlocked, [.biometryAny], $0)
        }
        try secCall {
            SecItemAdd([
                kSecClass: kSecClassGenericPassword,
                kSecAttrAccessControl: access,
                kSecAttrService: "test",
                kSecAttrAccount: "mrgumby",
                kSecValueData: Data("opendoor".utf8),
            ] as NSDictionary, nil)
        }
        print("did add")
    } catch {
        print("did not add, error: \(error)")
    }
}

func copyAction() {
    do {
        print("will copy")
        let items = try secCall {
            SecItemCopyMatching([
                kSecClass: kSecClassGenericPassword,
                kSecReturnAttributes: true,
                kSecReturnData: true,
            ] as NSDictionary, $0)
        }
        print("did copy, result: \(items)")
    } catch {
        print("did not copy, error: \(error)")
    }
}

func resetAction() {
    do {
        print("will reset")
        try secCall {
            SecItemDelete([
                kSecClass: kSecClassGenericPassword,
            ] as NSDictionary)
        }
        print("did reset")
    } catch {
        print("did not reset, error: \(error)")
    }
}

I fixed the parsing of the response and lo and behold it is actually there, then my question becomes why does it not prompt me for authentication. Could this be a simulator problem ?

New Response:

UUID: "A9DEE9C7-5051-4E45-AB32-5E8E634B5803"
accc: "<SecAccessControlRef: aku;prp(true);dacl(true)>"
acct: "app-user"
agrp: "***.com.App"
cdat: "2023-07-13 16:32:52 +0000"
class: "genp"
labl: "App"
mdat: "2023-07-13 16:32:52 +0000"
musr: ""
pdmn: "aku"
sha1: "�Da���7�\u001b�2\b���em\u0003��"
svce: "com.app"
sync: "<CFNumber 0x600001310d60 [0x600002610f70]>{value = +0, type = kCFNumberSInt64Type}"
tomb: "<CFNumber 0x600001310d90 [0x600002610f70]>{value = +0, type = kCFNumberSInt64Type}"
v_Data: "Hello"

Could this be a simulator problem?

Quite possibly. Did you enable Face ID on your simulator? If not, choose Features > Face ID > Enrolled.

ps You should never ask this question [1] because, if you think you have a simulator problem, you should retest on the device. The simulator is a great tool, but the device is the source of truth.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

[1] Well, except for visionOS code, where devices aren’t yet available (-:

Keychain Access Controls Not Working
 
 
Q