[security] Fix SecKeyChain.QueryAsData (#2485)

- Fixes bug #58720: SecKeychain.QueryAsData returns invalid data type
(https://bugzilla.xamarin.com/show_bug.cgi?id=58720)

As per Apple's doc: https://developer.apple.com/documentation/security/keychain_services/keychain_items/item_return_result_keys?language=objc
when multiple return types are requested (when wantPersistentReference is set to true),
the underlying native return type is an NSDictionary not an NSData.

As per https://bugzilla.xamarin.com/show_bug.cgi?id=58720#c3
when trying to access the byte property of the NSData object, we'd get an "unrecognized selector sent to instance".
This is confirmed by the added test.
This commit is contained in:
Vincent Dondain 2017-08-24 11:31:49 -04:00 коммит произвёл GitHub
Родитель dbc78103d0
Коммит a628b5c799
2 изменённых файлов: 34 добавлений и 2 удалений

Просмотреть файл

@ -110,9 +110,10 @@ namespace XamCore.Security {
using (var copy = NSMutableDictionary.FromDictionary (query.queryDict)){
SetLimit (copy, 1);
copy.LowlevelSetObject (CFBoolean.True.Handle, SecItem.ReturnData);
if (wantPersistentReference)
copy.LowlevelSetObject (CFBoolean.True.Handle, SecItem.ReturnPersistentRef);
else
copy.LowlevelSetObject (CFBoolean.True.Handle, SecItem.ReturnData);
IntPtr ptr;
status = SecItem.SecItemCopyMatching (copy.Handle, out ptr);
@ -129,9 +130,10 @@ namespace XamCore.Security {
using (var copy = NSMutableDictionary.FromDictionary (query.queryDict)){
var n = SetLimit (copy, max);
copy.LowlevelSetObject (CFBoolean.True.Handle, SecItem.ReturnData);
if (wantPersistentReference)
copy.LowlevelSetObject (CFBoolean.True.Handle, SecItem.ReturnPersistentRef);
else
copy.LowlevelSetObject (CFBoolean.True.Handle, SecItem.ReturnData);
IntPtr ptr;
status = SecItem.SecItemCopyMatching (copy.Handle, out ptr);

Просмотреть файл

@ -112,6 +112,36 @@ namespace MonoTouchFixtures.Security {
return returnGuid;
}
[Test]
public void QueryAsData ()
{
SecStatusCode code;
SecRecord queryRec = new SecRecord (SecKind.GenericPassword) {
Service = "KEYCHAIN_SERVICE",
Label = "KEYCHAIN_SERVICE",
Account = "KEYCHAIN_ACCOUNT"
};
var data = SecKeyChain.QueryAsData (queryRec, true, out code);
if (code == SecStatusCode.Success && queryRec != null) {
Assert.NotNull (data.Bytes);
}
}
[Test]
public void QueryAsDataArray ()
{
SecStatusCode code;
SecRecord queryRec = new SecRecord (SecKind.GenericPassword) {
Service = "KEYCHAIN_SERVICE",
Label = "KEYCHAIN_SERVICE",
Account = "KEYCHAIN_ACCOUNT"
};
var data = SecKeyChain.QueryAsData (queryRec, true, 1, out code);
if (code == SecStatusCode.Success && queryRec != null) {
Assert.NotNull (data [0].Bytes);
}
}
static SecStatusCode SetID (Guid setID)
{