/// <summary> /// Deletes an app's token from MacOS KeyChain. /// </summary> /// <param name="appId">An app/client id.</param> public static void DeleteToken(string appId) { if (string.IsNullOrEmpty(appId)) { throw new ArgumentNullException(string.Format( CultureInfo.CurrentCulture, ErrorConstants.Message.NullOrEmptyParameter, nameof(appId))); } IntPtr passwordDataPtr = IntPtr.Zero; IntPtr itemPtr = IntPtr.Zero; try { int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword( keychainOrArray: IntPtr.Zero, serviceNameLength: (uint)Constants.TokenCacheServiceName.Length, serviceName: Constants.TokenCacheServiceName, accountNameLength: (uint)appId.Length, accountName: appId, passwordLength: out uint passwordLength, passwordData: out passwordDataPtr, itemRef: out itemPtr); if (resultStatus == MacNativeKeyChain.SecResultCodes.errSecItemNotFound || itemPtr == IntPtr.Zero) { return; } else if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception(string.Format( CultureInfo.CurrentCulture, ErrorConstants.Message.MacKeyChainFailed, "SecKeychainFindGenericPassword", resultStatus)); } resultStatus = MacNativeKeyChain.SecKeychainItemDelete(itemPtr); if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception(string.Format( CultureInfo.CurrentCulture, ErrorConstants.Message.MacKeyChainFailed, "SecKeychainItemDelete", resultStatus)); } } finally { FreePointers(ref itemPtr, ref passwordDataPtr); } }
/// <summary> /// Frees up memory referenced by a keychain data and/or a CFType object after use. /// </summary> /// <param name="itemPtr">A pointer to a generic password item.</param> /// <param name="passwordDataPtr">A pointer to the data buffer to release.</param> private static void FreePointers(ref IntPtr itemPtr, ref IntPtr passwordDataPtr) { if (itemPtr != IntPtr.Zero) { MacNativeKeyChain.CFRelease(itemPtr); itemPtr = IntPtr.Zero; } if (passwordDataPtr != IntPtr.Zero) { MacNativeKeyChain.SecKeychainItemFreeContent(attrList: IntPtr.Zero, data: passwordDataPtr); passwordDataPtr = IntPtr.Zero; } }
public static void Remove(string appId) { IntPtr passwordDataPtr = IntPtr.Zero; IntPtr itemPtr = IntPtr.Zero; try { int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword( keychainOrArray: IntPtr.Zero, serviceNameLength: (uint)ServiceName.Length, serviceName: ServiceName, accountNameLength: (uint)appId.Length, accountName: appId, passwordLength: out uint passwordLength, passwordData: out passwordDataPtr, itemRef: out itemPtr); if (resultStatus == MacNativeKeyChain.SecResultCodes.errSecItemNotFound) { return; } else if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception($"SecKeychainFindGenericPassword failed with {resultStatus}"); } if (itemPtr == IntPtr.Zero) { return; } resultStatus = MacNativeKeyChain.SecKeychainItemDelete(itemPtr); if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception($"SecKeychainItemDelete failed with {resultStatus}"); } } finally { FreePointers(ref itemPtr, ref passwordDataPtr); } }
/// <summary> /// Adds or updates an app's token to MacOS KeyChain. /// </summary> /// <param name="appId">An app/client id.</param> /// <param name="plainContent">The content to store.</param> public static void SetToken(string appId, byte[] plainContent) { if (string.IsNullOrEmpty(appId)) { throw new ArgumentNullException(string.Format( CultureInfo.CurrentCulture, ErrorConstants.Message.NullOrEmptyParameter, nameof(appId))); } if (plainContent == null || plainContent.Length == 0) { return; } IntPtr passwordDataPtr = IntPtr.Zero; IntPtr itemPtr = IntPtr.Zero; try { int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword( keychainOrArray: IntPtr.Zero, serviceNameLength: (uint)Constants.TokenCacheServiceName.Length, serviceName: Constants.TokenCacheServiceName, accountNameLength: (uint)appId.Length, accountName: appId, passwordLength: out uint passwordLength, passwordData: out passwordDataPtr, itemRef: out itemPtr); switch (resultStatus) { case MacNativeKeyChain.SecResultCodes.errSecSuccess: // Key exists, let's update it. resultStatus = MacNativeKeyChain.SecKeychainItemModifyAttributesAndData( itemRef: itemPtr, attrList: IntPtr.Zero, passwordLength: (uint)plainContent.Length, passwordData: plainContent); if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception(string.Format( CultureInfo.CurrentCulture, ErrorConstants.Message.MacKeyChainFailed, "SecKeychainItemModifyAttributesAndData", resultStatus)); } break; case MacNativeKeyChain.SecResultCodes.errSecItemNotFound: // Key not found, let's create a new one in the default keychain. resultStatus = MacNativeKeyChain.SecKeychainAddGenericPassword( keychain: IntPtr.Zero, serviceNameLength: (uint)Constants.TokenCacheServiceName.Length, serviceName: Constants.TokenCacheServiceName, accountNameLength: (uint)appId.Length, accountName: appId, passwordLength: (uint)plainContent.Length, passwordData: plainContent, itemRef: out itemPtr); if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception(string.Format( CultureInfo.CurrentCulture, ErrorConstants.Message.MacKeyChainFailed, "SecKeychainAddGenericPassword", resultStatus)); } break; default: throw new Exception(string.Format( CultureInfo.CurrentCulture, ErrorConstants.Message.MacKeyChainFailed, "SecKeychainFindGenericPassword", resultStatus)); } } finally { FreePointers(ref itemPtr, ref passwordDataPtr); } }
public static void AddOrUpdate(string appId, byte[] plainContent) { IntPtr passwordDataPtr = IntPtr.Zero; IntPtr itemPtr = IntPtr.Zero; try { int resultStatus = MacNativeKeyChain.SecKeychainFindGenericPassword( keychainOrArray: IntPtr.Zero, serviceNameLength: (uint)ServiceName.Length, serviceName: ServiceName, accountNameLength: (uint)appId.Length, accountName: appId, passwordLength: out uint passwordLength, passwordData: out passwordDataPtr, itemRef: out itemPtr); if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess && resultStatus != MacNativeKeyChain.SecResultCodes.errSecItemNotFound) { throw new Exception($"SecKeychainFindGenericPassword failed with {resultStatus}"); } if (itemPtr != IntPtr.Zero) { // Key exists, let's update it. resultStatus = MacNativeKeyChain.SecKeychainItemModifyAttributesAndData( itemRef: itemPtr, attrList: IntPtr.Zero, passwordLength: (uint)plainContent.Length, passwordData: plainContent); if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception($"SecKeychainItemModifyAttributesAndData failed with {resultStatus}"); } } else { // Key not found, let's create a new one in the default keychain. resultStatus = MacNativeKeyChain.SecKeychainAddGenericPassword( keychain: IntPtr.Zero, serviceNameLength: (uint)ServiceName.Length, serviceName: ServiceName, accountNameLength: (uint)appId.Length, accountName: appId, passwordLength: (uint)plainContent.Length, passwordData: plainContent, itemRef: out itemPtr); if (resultStatus != MacNativeKeyChain.SecResultCodes.errSecSuccess) { throw new Exception($"SecKeychainAddGenericPassword failed with {resultStatus}"); } } } finally { FreePointers(ref itemPtr, ref passwordDataPtr); } }