static unsafe SecStatusCode AddInternetPassword(byte[] label, byte[] desc, SecAuthenticationType auth, byte[] user, byte[] passwd, SecProtocolType protocol, byte[] host, int port, byte[] path) { // Note: the following code does more-or-less the same as: //SecKeychainAddInternetPassword (CurrentKeychain, (uint) host.Length, host, 0, null, // (uint) user.Length, user, (uint) path.Length, path, (ushort) port, // protocol, auth, (uint) passwd.Length, passwd, ref item); fixed(byte *labelPtr = label, descPtr = desc, userPtr = user, hostPtr = host, pathPtr = path) { SecKeychainAttribute *attrs = stackalloc SecKeychainAttribute [8]; int *protoPtr = (int *)&protocol; int *authPtr = (int *)&auth; int *portPtr = &port; int n = 0; attrs[n++] = new SecKeychainAttribute(SecItemAttr.Label, (uint)label.Length, (IntPtr)labelPtr); if (desc != null) { attrs[n++] = new SecKeychainAttribute(SecItemAttr.Description, (uint)desc.Length, (IntPtr)descPtr); } attrs[n++] = new SecKeychainAttribute(SecItemAttr.Account, (uint)user.Length, (IntPtr)userPtr); attrs[n++] = new SecKeychainAttribute(SecItemAttr.Protocol, (uint)4, (IntPtr)protoPtr); attrs[n++] = new SecKeychainAttribute(SecItemAttr.AuthType, (uint)4, (IntPtr)authPtr); attrs[n++] = new SecKeychainAttribute(SecItemAttr.Server, (uint)host.Length, (IntPtr)hostPtr); attrs[n++] = new SecKeychainAttribute(SecItemAttr.Port, (uint)4, (IntPtr)portPtr); attrs[n++] = new SecKeychainAttribute(SecItemAttr.Path, (uint)path.Length, (IntPtr)pathPtr); SecKeychainAttributeList attrList = new SecKeychainAttributeList(n, (IntPtr)attrs); var result = SecKeychainItemCreateFromContent(SecItemClass.InternetPassword, &attrList, (uint)passwd.Length, passwd, CurrentKeychain, IntPtr.Zero, IntPtr.Zero); return(result); } }
private static byte[] GetAccountNameAttributeData(IntPtr itemRef) { IntPtr tagArrayPtr = IntPtr.Zero; IntPtr formatArrayPtr = IntPtr.Zero; IntPtr attrListPtr = IntPtr.Zero; // SecKeychainAttributeList try { // Extract the user name by querying for the item's 'account' attribute tagArrayPtr = Marshal.AllocCoTaskMem(sizeof(SecKeychainAttrType)); Marshal.Copy(new[] { (int)SecKeychainAttrType.AccountItem }, 0, tagArrayPtr, 1); formatArrayPtr = Marshal.AllocCoTaskMem(sizeof(CssmDbAttributeFormat)); Marshal.Copy(new[] { (int)CssmDbAttributeFormat.String }, 0, formatArrayPtr, 1); var attributeInfo = new SecKeychainAttributeInfo { Count = 1, Tag = tagArrayPtr, Format = formatArrayPtr, }; ThrowOnError( SecKeychainItemCopyAttributesAndData( itemRef, ref attributeInfo, IntPtr.Zero, out attrListPtr, out var _, IntPtr.Zero) ); SecKeychainAttributeList attrList = Marshal.PtrToStructure <SecKeychainAttributeList>(attrListPtr); Debug.Assert(attrList.Count == 1); byte[] attrListArrayBytes = NativeMethods.ToByteArray( attrList.Attributes, Marshal.SizeOf <SecKeychainAttribute>() * attrList.Count); SecKeychainAttribute[] attributes = NativeMethods.ToStructArray <SecKeychainAttribute>(attrListArrayBytes); Debug.Assert(attributes.Length == 1); return(NativeMethods.ToByteArray(attributes[0].Data, attributes[0].Length)); } finally { if (tagArrayPtr != IntPtr.Zero) { Marshal.FreeCoTaskMem(tagArrayPtr); } if (formatArrayPtr != IntPtr.Zero) { Marshal.FreeCoTaskMem(formatArrayPtr); } if (attrListPtr != IntPtr.Zero) { SecKeychainItemFreeAttributesAndData(attrListPtr, IntPtr.Zero); } } }
private static byte[] GetAccountNameAttributeData(IntPtr itemRef) { IntPtr tagArrayPtr = IntPtr.Zero; IntPtr formatArrayPtr = IntPtr.Zero; IntPtr attrListPtr = IntPtr.Zero; // SecKeychainAttributeList try { // Extract the user name by querying for the item's 'account' attribute tagArrayPtr = Marshal.AllocHGlobal(sizeof(SecKeychainAttrType)); Marshal.WriteInt32(tagArrayPtr, (int)SecKeychainAttrType.AccountItem); formatArrayPtr = Marshal.AllocHGlobal(sizeof(CssmDbAttributeFormat)); Marshal.WriteInt32(formatArrayPtr, (int)CssmDbAttributeFormat.String); var attributeInfo = new SecKeychainAttributeInfo { Count = 1, Tag = tagArrayPtr, Format = formatArrayPtr, }; ThrowIfError( SecKeychainItemCopyAttributesAndData( itemRef, ref attributeInfo, IntPtr.Zero, out attrListPtr, out _, IntPtr.Zero) ); SecKeychainAttributeList attrList = Marshal.PtrToStructure <SecKeychainAttributeList>(attrListPtr); Debug.Assert(attrList.Count == 1, "Only expecting a list structure containing one attribute to be returned"); SecKeychainAttribute attribute = Marshal.PtrToStructure <SecKeychainAttribute>(attrList.Attributes); return(InteropUtils.ToByteArray(attribute.Data, attribute.Length)); } finally { if (tagArrayPtr != IntPtr.Zero) { Marshal.FreeHGlobal(tagArrayPtr); } if (formatArrayPtr != IntPtr.Zero) { Marshal.FreeHGlobal(formatArrayPtr); } if (attrListPtr != IntPtr.Zero) { SecKeychainItemFreeAttributesAndData(attrListPtr, IntPtr.Zero); } } }
static unsafe OSStatus ReplaceInternetPassword(IntPtr item, byte[] desc, byte[] passwd) { fixed(byte *descPtr = desc) { SecKeychainAttribute *attrs = stackalloc SecKeychainAttribute [1]; int n = 0; if (desc != null) { attrs[n++] = new SecKeychainAttribute(SecItemAttr.Description, (uint)desc.Length, (IntPtr)descPtr); } SecKeychainAttributeList attrList = new SecKeychainAttributeList(n, (IntPtr)attrs); return(SecKeychainItemModifyAttributesAndData(item, &attrList, (uint)passwd.Length, passwd)); } }
public static unsafe bool ContainsCertificate(X509Certificate2 certificate) { // Note: we don't have to use an alias attribute, it's just that it might be faster to use it (fewer certificates we have to compare raw data for) byte[] alias = Encoding.UTF8.GetBytes(GetCertificateCommonName(certificate)); IntPtr searchRef, itemRef; bool found = false; byte[] certData; OSStatus status; fixed(byte *aliasPtr = alias) { SecKeychainAttribute *attrs = stackalloc SecKeychainAttribute [1]; int n = 0; if (alias != null) { attrs[n++] = new SecKeychainAttribute(SecItemAttr.Alias, (uint)alias.Length, (IntPtr)aliasPtr); } SecKeychainAttributeList attrList = new SecKeychainAttributeList(n, (IntPtr)attrs); status = SecKeychainSearchCreateFromAttributes(CurrentKeychain, SecItemClass.Certificate, &attrList, out searchRef); if (status != OSStatus.Ok) { throw new Exception("Could not enumerate certificates from the keychain. Error:\n" + GetError(status)); } // we cache certificate.RawData to avoid unneccessary duplication (X509Certificate2.RawData clones the byte[] each time) certData = certificate.RawData; while (!found && (status = SecKeychainSearchCopyNext(searchRef, out itemRef)) == OSStatus.Ok) { SecItemClass itemClass = 0; IntPtr data = IntPtr.Zero; uint length = 0; status = SecKeychainItemCopyContent(itemRef, ref itemClass, IntPtr.Zero, ref length, ref data); if (status == OSStatus.Ok) { if (certData.Length == (int)length) { byte[] rawData = new byte[(int)length]; Marshal.Copy(data, rawData, 0, (int)length); found = true; for (int i = 0; i < rawData.Length; i++) { if (rawData[i] != certData[i]) { found = false; break; } } } SecKeychainItemFreeContent(IntPtr.Zero, data); } CFRelease(itemRef); } CFRelease(searchRef); } return(found); }
static unsafe OSStatus AddInternetPassword (byte[] label, byte[] desc, SecAuthenticationType auth, byte[] user, byte[] passwd, SecProtocolType protocol, byte[] host, int port, byte[] path) { // Note: the following code does more-or-less the same as: //SecKeychainAddInternetPassword (CurrentKeychain, (uint) host.Length, host, 0, null, // (uint) user.Length, user, (uint) path.Length, path, (ushort) port, // protocol, auth, (uint) passwd.Length, passwd, ref item); fixed (byte* labelPtr = label, descPtr = desc, userPtr = user, hostPtr = host, pathPtr = path) { SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [8]; int* protoPtr = (int*) &protocol; int* authPtr = (int*) &auth; int* portPtr = &port; int n = 0; attrs[n++] = new SecKeychainAttribute (SecItemAttr.Label, (uint) label.Length, (IntPtr) labelPtr); if (desc != null) attrs[n++] = new SecKeychainAttribute (SecItemAttr.Description, (uint) desc.Length, (IntPtr) descPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Account, (uint) user.Length, (IntPtr) userPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Protocol, (uint) 4, (IntPtr) protoPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.AuthType, (uint) 4, (IntPtr) authPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Server, (uint) host.Length, (IntPtr) hostPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Port, (uint) 4, (IntPtr) portPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Path, (uint) path.Length, (IntPtr) pathPtr); SecKeychainAttributeList attrList = new SecKeychainAttributeList (n, (IntPtr) attrs); var item = IntPtr.Zero; var result = SecKeychainItemCreateFromContent (SecItemClass.InternetPassword, &attrList, (uint) passwd.Length, passwd, CurrentKeychain, IntPtr.Zero, ref item); CFRelease (item); return result; } }
static unsafe OSStatus ReplaceInternetPassword (IntPtr item, byte[] desc, byte[] passwd) { fixed (byte* descPtr = desc) { SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [1]; int n = 0; if (desc != null) attrs[n++] = new SecKeychainAttribute (SecItemAttr.Description, (uint) desc.Length, (IntPtr) descPtr); SecKeychainAttributeList attrList = new SecKeychainAttributeList (n, (IntPtr) attrs); return SecKeychainItemModifyAttributesAndData (item, &attrList, (uint) passwd.Length, passwd); } }
public static unsafe bool ContainsCertificate (X509Certificate2 certificate) { // Note: we don't have to use an alias attribute, it's just that it might be faster to use it (fewer certificates we have to compare raw data for) byte[] alias = Encoding.UTF8.GetBytes (GetCertificateCommonName (certificate)); IntPtr searchRef, itemRef; bool found = false; byte[] certData; OSStatus status; fixed (byte* aliasPtr = alias) { SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [1]; int n = 0; if (alias != null) attrs[n++] = new SecKeychainAttribute (SecItemAttr.Alias, (uint) alias.Length, (IntPtr) aliasPtr); SecKeychainAttributeList attrList = new SecKeychainAttributeList (n, (IntPtr) attrs); status = SecKeychainSearchCreateFromAttributes (CurrentKeychain, SecItemClass.Certificate, &attrList, out searchRef); if (status != OSStatus.Ok) throw new Exception ("Could not enumerate certificates from the keychain. Error:\n" + GetError (status)); // we cache certificate.RawData to avoid unneccessary duplication (X509Certificate2.RawData clones the byte[] each time) certData = certificate.RawData; while (!found && (status = SecKeychainSearchCopyNext (searchRef, out itemRef)) == OSStatus.Ok) { SecItemClass itemClass = 0; IntPtr data = IntPtr.Zero; uint length = 0; status = SecKeychainItemCopyContent (itemRef, ref itemClass, IntPtr.Zero, ref length, ref data); if (status == OSStatus.Ok) { if (certData.Length == (int) length) { byte[] rawData = new byte[(int) length]; Marshal.Copy (data, rawData, 0, (int) length); found = true; for (int i = 0; i < rawData.Length; i++) { if (rawData[i] != certData[i]) { found = false; break; } } } SecKeychainItemFreeContent (IntPtr.Zero, data); } CFRelease (itemRef); } CFRelease (searchRef); } return found; }
static extern unsafe OSStatus SecKeychainItemModifyAttributesAndData (IntPtr itemRef, SecKeychainAttributeList *attrList, uint length, byte [] data);
static extern unsafe OSStatus SecKeychainItemCopyAttributesAndData (IntPtr itemRef, SecKeychainAttributeInfo* info, ref SecItemClass itemClass, SecKeychainAttributeList** attrList, ref uint length, ref IntPtr outData);
static extern unsafe OSStatus SecKeychainItemCreateFromContent (SecItemClass itemClass, SecKeychainAttributeList *attrList, uint passwordLength, byte[] password, IntPtr keychain, IntPtr initialAccess, ref IntPtr itemRef);
static extern unsafe OSStatus SecKeychainSearchCreateFromAttributes (IntPtr keychainOrArray, SecItemClass itemClass, SecKeychainAttributeList *attrList, out IntPtr searchRef);
public static unsafe void AddInternetPassword (Uri uri, string password) { byte[] path = Encoding.UTF8.GetBytes (string.Join (string.Empty, uri.Segments).Substring (1)); // don't include the leading '/' byte[] user = Encoding.UTF8.GetBytes (Uri.UnescapeDataString (uri.UserInfo)); byte[] passwd = Encoding.UTF8.GetBytes (password); byte[] host = Encoding.UTF8.GetBytes (uri.Host); var auth = GetSecAuthenticationType (uri.Query); var protocol = GetSecProtocolType (uri.Scheme); IntPtr passwordPtr = IntPtr.Zero; IntPtr itemRef = IntPtr.Zero; uint passwordLength = 0; int port = uri.Port; byte[] desc = null; if (auth == SecAuthenticationType.HTMLForm) desc = WebFormPassword; // See if there is already a password there for this uri var result = SecKeychainFindInternetPassword (IntPtr.Zero, (uint) host.Length, host, 0, null, (uint) user.Length, user, (uint) path.Length, path, (ushort) port, protocol, auth, out passwordLength, out passwordPtr, ref itemRef); if (result == OSStatus.Ok) { // If there is, replace it with the new one fixed (byte* descPtr = desc) { SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [1]; int n = 0; if (desc != null) attrs[n++] = new SecKeychainAttribute (SecItemAttr.Description, (uint) desc.Length, (IntPtr) descPtr); SecKeychainAttributeList attrList = new SecKeychainAttributeList (n, (IntPtr) attrs); result = SecKeychainItemModifyAttributesAndData (itemRef, &attrList, (uint) passwd.Length, passwd); CFRelease (itemRef); } } else { // Otherwise add a new entry with the password // result = SecKeychainAddInternetPassword (IntPtr.Zero, (uint) uri.Host.Length, uri.Host, 0, null, // (uint) user.Length, user, (uint) path.Length, path, (ushort) uri.Port, // (int) protocol, (int) auth, (uint) passwordBytes.Length, passwordBytes, ref itemRef); var label = Encoding.UTF8.GetBytes (string.Format ("{0} ({1})", uri.Host, Uri.UnescapeDataString (uri.UserInfo))); fixed (byte* labelPtr = label, descPtr = desc, userPtr = user, hostPtr = host, pathPtr = path) { SecKeychainAttribute* attrs = stackalloc SecKeychainAttribute [8]; int* protoPtr = (int*) &protocol; int* authPtr = (int*) &auth; int* portPtr = &port; int n = 0; attrs[n++] = new SecKeychainAttribute (SecItemAttr.Label, (uint) label.Length, (IntPtr) labelPtr); if (desc != null) attrs[n++] = new SecKeychainAttribute (SecItemAttr.Description, (uint) desc.Length, (IntPtr) descPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Account, (uint) user.Length, (IntPtr) userPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Protocol, (uint) 4, (IntPtr) protoPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.AuthType, (uint) 4, (IntPtr) authPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Server, (uint) host.Length, (IntPtr) hostPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Port, (uint) 4, (IntPtr) portPtr); attrs[n++] = new SecKeychainAttribute (SecItemAttr.Path, (uint) path.Length, (IntPtr) pathPtr); SecKeychainAttributeList attrList = new SecKeychainAttributeList (n, (IntPtr) attrs); itemRef = IntPtr.Zero; result = SecKeychainItemCreateFromContent (SecItemClass.InternetPassword, &attrList, (uint) passwd.Length, passwd, IntPtr.Zero, IntPtr.Zero, ref itemRef); CFRelease (itemRef); } } if (result != OSStatus.Ok) throw new Exception ("Could not add internet password to keychain: " + GetError (result)); }