2016-05-26 16:06:52 +03:00
|
|
|
// Copyright 2011, 2013 Xamarin Inc. All rights reserved
|
|
|
|
|
|
|
|
using System;
|
|
|
|
using System.Runtime.InteropServices;
|
|
|
|
using System.IO;
|
|
|
|
using System.Reflection;
|
|
|
|
|
|
|
|
|
|
|
|
#if XAMCORE_2_0
|
|
|
|
using Foundation;
|
|
|
|
using Security;
|
|
|
|
using ObjCRuntime;
|
|
|
|
#else
|
|
|
|
using MonoTouch;
|
|
|
|
using MonoTouch.Foundation;
|
|
|
|
using MonoTouch.Security;
|
|
|
|
#endif
|
|
|
|
using NUnit.Framework;
|
|
|
|
|
|
|
|
namespace MonoTouchFixtures.Security {
|
|
|
|
|
|
|
|
[TestFixture]
|
|
|
|
[Preserve (AllMembers = true)]
|
|
|
|
public class KeyChainTest {
|
|
|
|
|
|
|
|
[DllImport (Constants.CoreFoundationLibrary)]
|
|
|
|
extern static int CFGetRetainCount (IntPtr handle);
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void Add_Certificate ()
|
|
|
|
{
|
2017-01-12 21:13:56 +03:00
|
|
|
#if MONOMAC
|
|
|
|
Stream certStream = typeof (KeyChainTest).Assembly.GetManifestResourceStream ("xammac_tests.Security.openssl_crt.der");
|
|
|
|
#else
|
2016-05-26 16:06:52 +03:00
|
|
|
Stream certStream = typeof(KeyChainTest).Assembly.GetManifestResourceStream ("monotouchtest.Security.openssl_crt.der");
|
2017-01-12 21:13:56 +03:00
|
|
|
#endif
|
2016-05-26 16:06:52 +03:00
|
|
|
NSData data = NSData.FromStream (certStream);
|
|
|
|
|
|
|
|
var rec = new SecRecord (SecKind.Certificate) {
|
|
|
|
Label = "MyCert"
|
|
|
|
};
|
|
|
|
rec.SetValueRef (new SecCertificate (data));
|
|
|
|
|
|
|
|
var rc = SecKeyChain.Add (rec);
|
|
|
|
Assert.IsTrue (rc == SecStatusCode.Success || rc == SecStatusCode.DuplicateItem, "Add_Certificate");
|
|
|
|
}
|
|
|
|
|
2017-01-12 21:13:56 +03:00
|
|
|
#if !MONOMAC // No QueryAsConcreteType on Mac
|
2016-05-26 16:06:52 +03:00
|
|
|
[Test]
|
|
|
|
public void AddQueryRemove_Identity ()
|
|
|
|
{
|
|
|
|
using (SecRecord rec = new SecRecord (SecKind.Identity))
|
|
|
|
using (var id = IdentityTest.GetIdentity ()) {
|
|
|
|
rec.SetValueRef (id);
|
|
|
|
SecStatusCode code = SecKeyChain.Add (rec);
|
|
|
|
Assert.True (code == SecStatusCode.DuplicateItem || code == SecStatusCode.Success);
|
|
|
|
}
|
|
|
|
|
2016-05-31 20:13:25 +03:00
|
|
|
if (!TestRuntime.CheckXcodeVersion (5, 0))
|
2016-05-26 16:06:52 +03:00
|
|
|
Assert.Inconclusive ("QueryAsConcreteType does not work before iOS7");
|
|
|
|
|
|
|
|
using (SecRecord rec = new SecRecord (SecKind.Identity)) {
|
|
|
|
SecStatusCode code;
|
|
|
|
var match = SecKeyChain.QueryAsConcreteType (rec, out code);
|
|
|
|
if ((match == null) && (code == SecStatusCode.ItemNotFound))
|
|
|
|
Assert.Inconclusive ("Test randomly fails (race condition between addtion/commit/query?");
|
|
|
|
|
|
|
|
Assert.That (code, Is.EqualTo (SecStatusCode.Success), "QueryAsRecord-2");
|
|
|
|
Assert.NotNull (match, "match-2");
|
|
|
|
|
|
|
|
code = SecKeyChain.Remove (rec);
|
|
|
|
Assert.That (code, Is.EqualTo (SecStatusCode.Success), "Remove");
|
|
|
|
|
|
|
|
match = SecKeyChain.QueryAsConcreteType (rec, out code);
|
|
|
|
Assert.That (code, Is.EqualTo (SecStatusCode.ItemNotFound), "QueryAsRecord-3");
|
|
|
|
Assert.Null (match, "match-3");
|
|
|
|
}
|
|
|
|
}
|
2017-01-12 21:13:56 +03:00
|
|
|
#endif
|
2016-05-26 16:06:52 +03:00
|
|
|
|
|
|
|
[DllImport ("/System/Library/Frameworks/Security.framework/Security")]
|
|
|
|
internal extern static SecStatusCode SecItemAdd (IntPtr cfDictRef, IntPtr result);
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
// same as Add_Identity but directly p/invoking - shows that the type MUST NOT be included for Identity
|
|
|
|
public void SecItemAdd_Identity ()
|
|
|
|
{
|
|
|
|
using (NSString valueref = new NSString ("v_Ref"))
|
|
|
|
using (NSMutableDictionary data = new NSMutableDictionary ())
|
|
|
|
using (var id = IdentityTest.GetIdentity ()) {
|
|
|
|
data.LowlevelSetObject (id.Handle, valueref.Handle);
|
|
|
|
SecStatusCode code = SecItemAdd (data.Handle, IntPtr.Zero);
|
2018-07-03 18:09:49 +03:00
|
|
|
var expected = Is.EqualTo (SecStatusCode.DuplicateItem).Or.EqualTo (SecStatusCode.Success);
|
|
|
|
#if __MACOS__
|
2018-07-04 12:44:14 +03:00
|
|
|
if (!TestRuntime.CheckSystemVersion (PlatformName.MacOSX, 10, 9))
|
2018-07-03 18:09:49 +03:00
|
|
|
expected = Is.EqualTo (SecStatusCode.Param);
|
|
|
|
#endif
|
|
|
|
Assert.That (code, expected);
|
2016-05-26 16:06:52 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2017-08-24 18:31:49 +03:00
|
|
|
|
|
|
|
[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);
|
|
|
|
}
|
|
|
|
}
|
2016-05-26 16:06:52 +03:00
|
|
|
|
|
|
|
static SecStatusCode SetID (Guid setID)
|
|
|
|
{
|
|
|
|
var queryRec = new SecRecord (SecKind.GenericPassword) {
|
|
|
|
Service = "KEYCHAIN_SERVICE",
|
|
|
|
Label = "KEYCHAIN_SERVICE",
|
|
|
|
Account = "KEYCHAIN_ACCOUNT"
|
|
|
|
};
|
|
|
|
var record = queryRec.Clone ();
|
|
|
|
record.Generic = NSData.FromString (Convert.ToString (setID), NSStringEncoding.UTF8);
|
|
|
|
record.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;
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void CheckId ()
|
|
|
|
{
|
2018-07-03 18:09:49 +03:00
|
|
|
TestRuntime.AssertXcodeVersion (5, 1); // macOS 10.9
|
2016-05-26 16:06:52 +03:00
|
|
|
// test case from http://stackoverflow.com/questions/9481860/monotouch-cant-get-value-of-existing-keychain-item
|
|
|
|
// not a bug (no class lib fix) just a misuse of the API wrt status codes
|
|
|
|
Guid g = Guid.NewGuid ();
|
|
|
|
SetID (g);
|
|
|
|
Assert.That (g, Is.EqualTo (GetID ()), "same guid");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|