davoc bradley
davoc bradley

Reputation: 220

MonoTouch can't get value of existing keychain item

I can't seem to get a value out of the keychain as it always returns ItemNotFound. The code I'm using is as follows:

private static Guid GetID()
    {           
        Guid returnGuid = Guid.Empty;
        SecStatusCode code;
        SecRecord queryRec = new SecRecord (SecKind.GenericPassword) { Service = KEYCHAIN_SERVICE, Label = KEYCHAIN_SERVICE, Account = KEYCHAIN_ACCOUNT };
        queryRec = SecKeyChain.QueryAsRecord (queryRec, out code);

        if (code == SecStatusCode.Success && queryRec != null && queryRec.Generic != null )
        {
            returnGuid = new Guid(NSString.FromData(queryRec.Generic, NSStringEncoding.UTF8));
        }

        return returnGuid;

    }

When I try and set the value it returns DuplicateItem with the following code:

private static SecStatusCode SetID (Guid setID)
    {           
        SecStatusCode code = SecKeyChain.Add (new SecRecord (SecKind.GenericPassword) {
            Service = KEYCHAIN_SERVICE,
            Label = KEYCHAIN_SERVICE,
            Account = KEYCHAIN_ACCOUNT,
            Generic = NSData.FromString(Convert.ToString(setID), NSStringEncoding.UTF8),
            Accessible = SecAccessible.Always
        } );

        return code;
    }

Any help would be great!

Upvotes: 3

Views: 1533

Answers (1)

poupou
poupou

Reputation: 43553

I copy-pasted your code into a Touch.Unit solution and it works on both the simulator and devices.

    [Test]
    public void CheckId ()
    {
        Guid g = Guid.NewGuid ();
        SetID (g);
        Assert.That (g, Is.EqualTo (GetID ()), "same guid");
    }

The only thing I had to change was your KEYCHAIN_* constants to strings, I kept the same values (i.e. just added quotes).

Now if you execute the code a second time you'll get the DuplicateItem error code, because SetID is trying to set the same item again and when you query the Guid you'll get the first one - leading to an error.

You have two choice, delete the existing item or update it. E.g. to delete an existing item...

    static SecStatusCode SetID (Guid setID)
    {
        SecRecord queryRec = new SecRecord (SecKind.GenericPassword) { 
            Service = "KEYCHAIN_SERVICE", 
            Label = "KEYCHAIN_SERVICE", 
            Account = "KEYCHAIN_ACCOUNT" 
        };
        var record = new SecRecord (SecKind.GenericPassword) {
            Service = "KEYCHAIN_SERVICE",
            Label = "KEYCHAIN_SERVICE",
            Account = "KEYCHAIN_ACCOUNT",
            Generic = NSData.FromString (Convert.ToString (setID), NSStringEncoding.UTF8),
            Accessible = SecAccessible.Always
        };
        SecStatusCode code = SecKeyChain.Add (record);
        if (code == SecStatusCode.DuplicateItem) {
            code = SecKeyChain.Remove (queryRec);
            if (code == SecStatusCode.Success)
                code = SecKeyChain.Add (record);
        }
        return code;
    }

Note: I never got a ItemNotFound while testing this.

Upvotes: 3

Related Questions