Статус: Активный участник
Группы: Участники
Зарегистрирован: 04.06.2008(UTC) Сообщений: 41 Откуда: Москва
Сказал(а) «Спасибо»: 1 раз
|
Пытаюсь конвертировать пример создания подписи CAdES-BES (упрощённые функции) (из SDK ЭЦП) на C#. На выходе дает ошибку "CadesSignMessage() failed": Основной код: Код: UInt32 dwError = 0;
ActivationContextHelper actCtxHelper = new ActivationContextHelper();
UInt32 savedCookie = actCtxHelper.CreateAndActivate("app.manifest", "", out dwError);
// Вызвать нужные функции
SignCpp(Encoding.UTF8.GetBytes(txtContent.Text));
// Деактивировать и освободить контекст
if (!actCtxHelper.DeactivateContext(savedCookie, out dwError))
{
// …
}
if (!actCtxHelper.ReleaseContext(out dwError))
{
// …
}
Код SignCpp.cs: Код: byte[] message = new byte[0];
IntPtr pcrpara = IntPtr.Zero;
IntPtr pdata = IntPtr.Zero;
IntPtr pbToBeSigned = IntPtr.Zero;
IntPtr pSignedMessage = IntPtr.Zero;
try
{
X509Certificate2 clientX509 = GetCertificateX509();
if (clientX509.Handle.Equals(IntPtr.Zero))
{
MessageBox.Show("Не выбран сертификат.");
return null;
}
CryptoApiHelper.CRYPT_SIGN_MESSAGE_PARA signPara = new CryptoApiHelper.CRYPT_SIGN_MESSAGE_PARA();
signPara.cbSize = Marshal.SizeOf(signPara);
signPara.dwMsgEncodingType = CryptoApiHelper.X509_ASN_ENCODING | CryptoApiHelper.PKCS_7_ASN_ENCODING;
signPara.HashAlgorithm.pszObjId = CryptoApiHelper.szOID_OIWSEC_sha1;
signPara.pSigningCert = clientX509.Handle;
CadesHelper.CADES_SIGN_PARA cadesSignPara = new CadesHelper.CADES_SIGN_PARA();
cadesSignPara.dwSize = (uint)Marshal.SizeOf(cadesSignPara);
cadesSignPara.dwCadesType = CadesHelper.CADES_BES;
CadesHelper.CADES_SIGN_MESSAGE_PARA para = new CadesHelper.CADES_SIGN_MESSAGE_PARA();
para.dwSize = (uint)Marshal.SizeOf(para);
pcrpara = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(CryptoApiHelper.CRYPT_SIGN_MESSAGE_PARA)));
Marshal.StructureToPtr(signPara, pcrpara, false);
para.pSignMessagePara = pcrpara;
para.pCadesSignPara = IntPtr.Zero;
//std::vector<BYTE> data(10,25);
byte[] data = pSignature; //new byte[250];
//const BYTE *pbToBeSigned[] = { &data[0] };
pbToBeSigned = new IntPtr(data[0]);
//DWORD cbToBeSigned[] = { (DWORD)data.size() };
uint cbToBeSigned = (uint)data.Length;
pSignedMessage = IntPtr.Zero;
if (!CadesHelper.CadesSignMessage(ref para, false, 1, pbToBeSigned, cbToBeSigned, out pSignedMessage))
{
MessageBox.Show("CadesSignMessage() failed");
return null;
}
//std::vector<BYTE> message(pSignedMessage->cbData);
// здесь попытка конвертации провалилась, поэтому следующая строчка закомментирована
//byte[] message = pSignedMessage.cbData;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
Marshal.FreeHGlobal(pdata);
Marshal.FreeHGlobal(pcrpara);
CadesHelper.CadesFreeBlob(pbToBeSigned);
if (!CadesHelper.CadesFreeBlob(pSignedMessage))
{
MessageBox.Show("CadesFreeBlob() failed");
}
}
return null; // message;
Код CadesHelper.cs: Код: public static class CadesHelper
{
public const int CADES_BES = 1;
public const int CADES_DEFAULT = 0;
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CADES_SIGN_PARA
{
public uint dwSize;
public uint dwCadesType;
public IntPtr pSignerCert;
public string szHashAlgorithm;
public IntPtr hAdditionalStore;
public IntPtr pTspConnectionPara;
public IntPtr pProxyPara;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CADES_SIGN_MESSAGE_PARA
{
public uint dwSize;
public IntPtr pSignMessagePara;
public IntPtr pCadesSignPara;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CADES_VERIFY_MESSAGE_PARA
{
public uint dwSize;
public IntPtr pVerifyMessagePara;
public IntPtr pCadesVerifyPara;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CADES_VERIFICATION_INFO
{
public uint dwSize;
public uint dwStatus;
public IntPtr pSignerCert;
public IntPtr pSigningTime;
public IntPtr pReserved;
public IntPtr pSignatureTimeStampTime;
}
/*
[DllImport("cades.dll", EntryPoint = "CadesSignMessage", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CadesSignMessage(
ref CADES_SIGN_MESSAGE_PARA pSignPara,
bool fDetachedSignature,
uint cToBeSigned,
String[] rgpbToBeSigned,
uint[] rgcbToBeSigned,
out IntPtr ppSignedBlob);
*/
[DllImport("cades.dll", EntryPoint = "CadesSignMessage", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CadesSignMessage(
ref CADES_SIGN_MESSAGE_PARA pSignPara,
bool fDetachedSignature,
uint cToBeSigned,
IntPtr rgpbToBeSigned,
uint rgcbToBeSigned,
out IntPtr ppSignedBlob);
[DllImport("cades.dll", EntryPoint = "CadesVerifyMessage", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CadesVerifyMessage(
ref CADES_VERIFY_MESSAGE_PARA pVerifyPara,
int dwSignerIndex,
IntPtr pbSignedBlob,
uint cbSignedBlob,
out IntPtr ppDecodedBlob,
out IntPtr ppVerificationInfo);
[DllImport("cades.dll", EntryPoint = "CadesFreeBlob", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CadesFreeBlob(
IntPtr pBlob);
[DllImport("cades.dll", EntryPoint = "CadesFreeVerificationInfo", SetLastError = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool CadesFreeVerificationInfo(
IntPtr pVerificationInfo);
}
Код CryptoApiHelper.cs: Код: public static class CryptoApiHelper
{
public const int X509_ASN_ENCODING = 0x00000001;
public const int PKCS_7_ASN_ENCODING = 0x00010000;
//public const uint CERT_FIND_SUBJECT_STR = 0x00080007;
public const string GOST_34_11_94 = "1.2.643.2.2.9";
public const string szOID_OIWSEC_sha1 = "1.3.14.3.2.26";
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_ALGORITHM_IDENTIFIER
{
[MarshalAs(UnmanagedType.LPStr)]
public String pszObjId;
public CRYPTOAPI_BLOB Parameters;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPT_SIGN_MESSAGE_PARA
{
public int cbSize;
public int dwMsgEncodingType;
public IntPtr pSigningCert;
public CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm;
public IntPtr pvHashAuxInfo;
public int cMsgCert;
public IntPtr rgpMsgCert;
public int cMsgCrl;
public IntPtr rgpMsgCrl;
public int cAuthAttr;
public IntPtr rgAuthAttr;
public int cUnauthAttr;
public IntPtr rgUnauthAttr;
public int dwFlags;
public int dwInnerContentType;
public CRYPT_ALGORITHM_IDENTIFIER HashEncryptionAlgorithm;
public IntPtr pvHashEncryptionAuxInfo;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPT_VERIFY_MESSAGE_PARA
{
public uint cbSize;
public uint dwMsgAndCertEncodingType;
public IntPtr hCryptProv;
public IntPtr pfnGetSignerCertificate;
public IntPtr pvGetArg;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPTOAPI_BLOB
{
public int cbData;
public IntPtr pbData;
}
[DllImport("crypt32.dll")]
public static extern int CryptSignMessage(
ref CRYPT_SIGN_MESSAGE_PARA pSignPara,
int fDetachedSignature,
int cToBeSigned,
IntPtr[] rgpbToBeSigned,
int[] rgcbToBeSigned,
byte[] pbSignedBlob,
ref int pcbSignedBlob);
[DllImport("crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenSystemStore(
IntPtr hCryptProv,
string storename);
[DllImport("crypt32.dll", EntryPoint = "CertOpenStore", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenStoreStringPara(int storeProvider, int encodingType,
IntPtr hcryptProv, int flags, String pvPara);
[DllImport("crypt32.dll", EntryPoint = "CertOpenStore", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertOpenStoreIntPtrPara(int storeProvider, int encodingType,
IntPtr hcryptProv, int flags, IntPtr pvPara);
[DllImport("crypt32.dll", SetLastError = true)]
public static extern bool CertCloseStore(
IntPtr hCertStore,
uint dwFlags);
[DllImport("crypt32.dll", SetLastError = true)]
public static extern IntPtr CertFindCertificateInStore(
IntPtr hCertStore,
uint dwCertEncodingType,
uint dwFindFlags,
uint dwFindType,
[In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString,
IntPtr pPrevCertCntxt);
[DllImport("crypt32.dll", SetLastError = true)]
public static extern bool CertFreeCertificateContext(
IntPtr hCertStore);
}
Код ActivationContextHelper.cs: Код: public class ActivationContextHelper : IDisposable
{
#region PrivateData
// Activation Context API Functions
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern IntPtr CreateActCtx(ref ACTCTX actctx);
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern bool ActivateActCtx(IntPtr hActCtx, out uint cookie);
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern bool DeactivateActCtx(uint dwFlags, uint cookie);
[DllImport("Kernel32.dll", SetLastError = true)]
private static extern void ReleaseActCtx(IntPtr hActCtx);
[DllImport("Kernel32.dll", SetLastError = true)]
public static extern UInt32 GetCurrentThreadId();
// Activation context structure
private struct ACTCTX
{
public int cbSize;
public uint dwFlags;
public string lpSource;
public ushort wProcessorArchitecture;
public ushort wLangId;
public string lpAssemblyDirectory;
public string lpResourceName;
public string lpApplicationName;
}
// Helpful constants
private const int ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID = 0x004;
private const int INVALID_HANDLE_VALUE = -1;
// Variables holding information on the activation context
private IntPtr m_hActCtx = (IntPtr)0;
#endregion
// Some helpful error codes // Most likely indicate:
public const UInt32 ERROR_INVALID_PARAMETER = 87; // Missing or empty parameters
public const UInt32 ERROR_ALREADY_INITIALIZED = 1247; // Context already created or active
public const UInt32 ERROR_INVALID_HANDLE = 6; // Context not yet created or not active
/// <summary>
/// Constructor
/// </summary>
public ActivationContextHelper()
{
// This is superfluous - just document zero default
m_hActCtx = (IntPtr)0;
}
/// <summary>
/// Release Windows resources
/// </summary>
void IDisposable.Dispose()
{
Clear();
}
/// <summary>
/// Force the release of Windows resources
/// </summary>
public void Clear()
{
lock (this)
{
if (0 != m_hActCtx.ToInt32())
ReleaseActCtx(m_hActCtx);
m_hActCtx = (IntPtr)0;
}
}
/// <summary>
/// Method to explicitly load a manifest and create an activation context
/// </summary>
/// <param name="manifestPath">Full path to the manifest file</param>
/// <param name="rootFolder">'null' or the root assembly probing directory</param>
/// <returns>'true' - success, 'false' - failure</returns>
public bool CreateContext(string manifestPath, string rootFolder, out UInt32 dwError)
{
// Verify parameters, exit if not acceptable
if (null == manifestPath || "" == manifestPath)
{
dwError = ERROR_INVALID_PARAMETER;
return false;
}
// Build the activation context information structure
ACTCTX info = new ACTCTX();
info.cbSize = Marshal.SizeOf(typeof(ACTCTX));
info.dwFlags = 0;
info.lpSource = manifestPath;
if (null != rootFolder && "" != rootFolder)
{
info.lpAssemblyDirectory = rootFolder;
info.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
}
bool bOK = true;
dwError = 0;
// Protect from changes by multiple threads
lock (this)
{
// It is illegal to create a context while one is already created
if (0 != m_hActCtx.ToInt32())
{
dwError = ERROR_ALREADY_INITIALIZED;
bOK = false;
}
else
{
// Create the activation context
m_hActCtx = CreateActCtx(ref info);
if (-1 == m_hActCtx.ToInt32())
{
dwError = (UInt32)Marshal.GetLastWin32Error();
m_hActCtx = (IntPtr)0;
bOK = false;
}
}
}
return bOK;
}
/// <summary>
/// Activate the previously created activation context
/// </summary>
/// <returns>'true' - success, 'false' - failure</returns>
public UInt32 ActivateContext(out UInt32 dwError)
{
UInt32 cookie = 0;
dwError = 0;
lock (this)
{
// We cannot activate a context if we do not have it.
if (0 == m_hActCtx.ToInt32())
{
dwError = ERROR_INVALID_HANDLE;
}
else
{
// Activate the context
if (!ActivateActCtx(m_hActCtx, out cookie))
{
cookie = 0;
dwError = (UInt32)Marshal.GetLastWin32Error();
}
}
}
return cookie;
}
/// <summary>
/// Create the activation context, if one is not created yet then
/// immediately activate it.
/// </summary>
/// <param name="manifestPath"></param>
/// <param name="rootFolder"></param>
/// <param name="dwError"></param>
/// <returns></returns>
public UInt32 CreateAndActivate(string manifestPath, string rootFolder, out UInt32 dwError)
{
UInt32 cookie = 0;
lock (this)
{
// If we already have a context or we successfully create one - activate.
if (0 != m_hActCtx.ToInt32() || CreateContext(manifestPath, rootFolder, out dwError))
{
cookie = ActivateContext(out dwError);
}
}
return cookie;
}
/// <summary>
/// Deactivate the previously activated activation context
/// </summary>
/// <returns>'true' - success, 'false' - failure</returns>
public bool DeactivateContext(UInt32 cookie, out UInt32 dwError)
{
bool bOK = true;
dwError = 0;
lock (this)
{
// We cannot deactivate a context if we do not have it or it is not activated
if (0 == m_hActCtx.ToInt32() || 0 == cookie)
{
dwError = ERROR_INVALID_HANDLE;
bOK = false;
}
else
{
// Deactivate the context, may throw an exception if bad sequence
if (!DeactivateActCtx(0, cookie))
{
dwError = (UInt32)Marshal.GetLastWin32Error();
bOK = false;
}
}
}
return bOK;
}
/// <summary>
/// Release the previously created activation context. Note that the
/// context is silently released by 'Clear' and 'Dispose'.
/// </summary>
/// <returns>'true' - success, 'false' - failure</returns>
public bool ReleaseContext(out UInt32 dwError)
{
bool bOK = true;
dwError = 0;
lock (this)
{
if (0 == m_hActCtx.ToInt32())
{
dwError = ERROR_INVALID_HANDLE;
bOK = false;
}
else
{
ReleaseActCtx(m_hActCtx);
m_hActCtx = (IntPtr)0;
bOK = true;
}
}
return bOK;
}
}
|