diff --git a/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs b/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs index 7535c6bd..bfe4ae21 100644 --- a/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs +++ b/PInvoke/Cryptography/Crypt32/Wincrypt.Key.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.Runtime.InteropServices; +using Vanara.Extensions; using Vanara.InteropServices; namespace Vanara.PInvoke @@ -22,11 +24,11 @@ namespace Vanara.PInvoke // *pvArg, DWORD cProp, DWORD *rgdwPropId, void **rgpvData, DWORD *rgcbData ) {...} [PInvokeData("wincrypt.h", MSDNShortId = "c4461b79-d216-4d4a-bd5d-9260ec897c14")] [return: MarshalAs(UnmanagedType.Bool)] - public delegate bool PFN_CRYPT_ENUM_KEYID_PROP(in CRYPTOAPI_BLOB pKeyIdentifier, [Optional] uint dwFlags, [Optional] IntPtr pvReserved, [Optional] IntPtr pvArg, uint cProp, [In] uint[] rgdwPropId, [In] IntPtr[] rgpvData, [In] uint[] rgcbData); + public delegate bool PFN_CRYPT_ENUM_KEYID_PROP([In, Optional] IntPtr pKeyIdentifier, [Optional] uint dwFlags, [Optional] IntPtr pvReserved, [Optional] IntPtr pvArg, uint cProp, [In] uint[] rgdwPropId, [In] IntPtr[] rgpvData, [In] uint[] rgcbData); /// Blob type specifier for PUBLICKEYSTRUC. [PInvokeData("wincrypt.h", MSDNShortId = "99d41222-b4ca-40f3-a240-52b0a9b3a9aa")] - public enum BlobType : byte + public enum BlobType : uint { /// The BLOB is a key state BLOB. KEYSTATEBLOB = 0xC, @@ -411,8 +413,178 @@ namespace Vanara.PInvoke [DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)] [PInvokeData("wincrypt.h", MSDNShortId = "6e57d935-4cfb-44af-b1c6-6c399c959452")] [return: MarshalAs(UnmanagedType.Bool)] - public static extern bool CryptEnumKeyIdentifierProperties(in CRYPTOAPI_BLOB pKeyIdentifier, uint dwPropId, CryptKeyIdFlags dwFlags, [MarshalAs(UnmanagedType.LPWStr)] string pwszComputerName, - [Optional] IntPtr pvReserved, [In, Out, Optional] IntPtr pvArg, [MarshalAs(UnmanagedType.FunctionPtr)] PFN_CRYPT_ENUM_KEYID_PROP pfnEnum); + public static extern bool CryptEnumKeyIdentifierProperties(in CRYPTOAPI_BLOB pKeyIdentifier, [In, Optional] uint dwPropId, CryptKeyIdFlags dwFlags, + [Optional, MarshalAs(UnmanagedType.LPWStr)] string pwszComputerName, [In, Optional] IntPtr pvReserved, [In, Optional] IntPtr pvArg, + [MarshalAs(UnmanagedType.FunctionPtr)] PFN_CRYPT_ENUM_KEYID_PROP pfnEnum); + + /// + /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier. + /// If pKeyIdentifier is NULL, the function enumerates all key identifiers. + /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier. + /// Indicates the property identifier to be listed. + /// If dwPropId is set to zero, this function calls the callback function with all the properties. + /// + /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that + /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped. + /// + /// Any certificate property identifier can be used. + /// + /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key + /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not + /// NULL) is searched. For more information, see pwszComputerName. + /// + /// + /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is + /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is + /// set to NULL. + /// + /// Reserved for future use and must be NULL. + /// + /// A pointer to data to be passed to the callback function. The type is a void that allows the application to declare, define, and + /// initialize a structure or argument to hold any information. + /// + /// + /// A pointer to an application-defined callback function that is executed for each key identifier entry that matches the input + /// parameters. For details about the callback functions parameters, see CRYPT_ENUM_KEYID_PROP. + /// + /// + /// + /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier. + /// If pKeyIdentifier is NULL, the function enumerates all key identifiers. + /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier. + /// + /// + /// Indicates the property identifier to be listed. + /// If dwPropId is set to zero, this function calls the callback function with all the properties. + /// + /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that + /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped. + /// + /// Any certificate property identifier can be used. + /// + /// + /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key + /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not + /// NULL) is searched. For more information, see pwszComputerName. + /// + /// + /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is + /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is + /// set to NULL. + /// + /// Reserved for future use and must be NULL. + /// + /// A pointer to data to be passed to the callback function. The type is a void that allows the application to declare, define, and + /// initialize a structure or argument to hold any information. + /// + /// + /// A pointer to an application-defined callback function that is executed for each key identifier entry that matches the input + /// parameters. For details about the callback functions parameters, see CRYPT_ENUM_KEYID_PROP. + /// + /// + /// + /// The CryptEnumKeyIdentifierProperties function repeatedly calls the CRYPT_ENUM_KEYID_PROP callback function until the last + /// key identifier is enumerated or the callback function returns FALSE. + /// + /// If the main function succeeds, the function returns nonzero ( TRUE). + /// If the function fails, it returns zero ( FALSE). For extended error information, call GetLastError. + /// To continue enumeration, the function returns TRUE. + /// To stop enumeration, the function returns FALSE and sets the last error code. + /// + /// + /// A key identifier can have the same properties as a certificate context. + /// Examples + /// For an example that uses this function, see Example C Program: Working with Key Identifiers. + /// + // https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptenumkeyidentifierproperties BOOL + // CryptEnumKeyIdentifierProperties( const CRYPT_HASH_BLOB *pKeyIdentifier, DWORD dwPropId, DWORD dwFlags, LPCWSTR pwszComputerName, + // void *pvReserved, void *pvArg, PFN_CRYPT_ENUM_KEYID_PROP pfnEnum ); + [DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)] + [PInvokeData("wincrypt.h", MSDNShortId = "6e57d935-4cfb-44af-b1c6-6c399c959452")] + [return: MarshalAs(UnmanagedType.Bool)] + public static extern bool CryptEnumKeyIdentifierProperties([In, Optional] IntPtr pKeyIdentifier, [In, Optional] uint dwPropId, CryptKeyIdFlags dwFlags, + [Optional, MarshalAs(UnmanagedType.LPWStr)] string pwszComputerName, [In, Optional] IntPtr pvReserved, [In, Optional] IntPtr pvArg, + [MarshalAs(UnmanagedType.FunctionPtr)] PFN_CRYPT_ENUM_KEYID_PROP pfnEnum); + + /// + /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier. + /// If pKeyIdentifier is NULL, the function enumerates all key identifiers. + /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier. + /// Indicates the property identifier to be listed. + /// If dwPropId is set to zero, this function calls the callback function with all the properties. + /// + /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that + /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped. + /// + /// Any certificate property identifier can be used. + /// + /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key + /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not + /// NULL) is searched. For more information, see pwszComputerName. + /// + /// + /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is + /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is + /// set to NULL. + /// + /// Reserved for future use and must be NULL. + /// + /// A pointer to data to be passed to the callback function. The type is a void that allows the application to declare, define, and + /// initialize a structure or argument to hold any information. + /// + /// + /// A pointer to an application-defined callback function that is executed for each key identifier entry that matches the input + /// parameters. For details about the callback functions parameters, see CRYPT_ENUM_KEYID_PROP. + /// + /// + /// + /// A pointer to a CRYPT_HASH_BLOB structure that contains the key identifier. + /// If pKeyIdentifier is NULL, the function enumerates all key identifiers. + /// If pKeyIdentifier is not NULL, the callback function pfnEnum is only called for the specified key identifier. + /// + /// + /// Indicates the property identifier to be listed. + /// If dwPropId is set to zero, this function calls the callback function with all the properties. + /// + /// If dwPropId is not zero and pKeyIdentifier is NULL, the callback function is called only for those key identifiers that + /// have the specified property (sets the cProp parameter of pfnEnum to one). All key identifiers that do not have the property are skipped. + /// + /// Any certificate property identifier can be used. + /// + /// + /// By default, the list of key identifiers for the CurrentUser is searched. If CRYPT_KEYID_MACHINE_FLAG is set, the list of key + /// identifiers of the LocalMachine (if pwszComputerName is NULL) or of a remote computer (if pwszComputerName is not + /// NULL) is searched. For more information, see pwszComputerName. + /// + /// + /// A pointer to the name of a remote computer to be searched. If CRYPT_KEYID_MACHINE_FLAG is set in dwFlags, the remote computer is + /// searched for a list of key identifiers. If the local computer is to be searched and not a remote computer, pwszComputerName is + /// set to NULL. + /// + /// A sequence of tuples containing the key identifier and an array of property identifiers and values as byte arrays. + public static IEnumerable<(byte[] keyId, (uint propId, byte[] data)[] props)> CryptEnumKeyIdentifierProperties(CRYPTOAPI_BLOB? pKeyIdentifier = null, + uint dwPropId = 0, CryptKeyIdFlags dwFlags = CryptKeyIdFlags.CRYPT_KEYID_MACHINE_FLAG, string pwszComputerName = null) + { + List<(byte[] keyId, (uint propId, byte[] data)[] props)> output = new(); + using SafeCoTaskMemStruct pKeyId = pKeyIdentifier.HasValue ? new(pKeyIdentifier.Value) : SafeCoTaskMemStruct.Null; + Win32Error.ThrowLastErrorIfFalse(CryptEnumKeyIdentifierProperties(pKeyId, dwPropId, dwFlags, pwszComputerName, default, default, fn)); + return output; + + unsafe bool fn(IntPtr pKeyIdentifier, uint dwFlags, IntPtr pvReserved, IntPtr pvArg, uint cProp, uint[] rgdwPropId, IntPtr[] rgpvData, uint[] rgcbData) + { + try + { + var id = pKeyIdentifier == IntPtr.Zero ? null : ((CRYPTOAPI_BLOB*)(void*)pKeyIdentifier)->GetBytes(); + var props = new (uint propId, byte[] data)[(int)cProp]; + for (uint i = 0; i < cProp; i++) + props[i] = (rgdwPropId[i], rgpvData[i].AsReadOnlySpan((int)rgcbData[i]).ToArray()); + output.Add((id, props)); + return true; + } + catch { } + return false; + } + } /// /// A pointer to the CRYPT_HASH_BLOB that contains the key identifier. @@ -686,6 +858,8 @@ namespace Vanara.PInvoke [StructLayout(LayoutKind.Sequential)] public struct PUBLICKEYSTRUC { + private byte _bType; + /// /// Contains the key BLOB type. /// @@ -731,7 +905,7 @@ namespace Vanara.PInvoke /// /// /// - public BlobType bType; + public BlobType bType { get => (BlobType)_bType; set => _bType = (byte)bType; } /// /// Contains the version number of the key BLOB format. For example, if the BLOB is a Digital Signature Standard (DSS) version 3