public static extern SafeCryptMsgHandle CryptMsgOpenToEncode( CMSG_ENCODING dwMsgEncodingType, uint dwFlags, uint dwMsgType, ref CMSG_SIGNED_ENCODE_INFO pvMsgEncodeInfo, string pszInnerContentObjID, IntPtr pStreamInfo );
internal static SignedCms NativeSign(CmsSigner cmsSigner, byte[] data, CngKey privateKey) { using (var hb = new HeapBlockRetainer()) { var certificateBlobs = new BLOB[cmsSigner.Certificates.Count]; for (var i = 0; i < cmsSigner.Certificates.Count; ++i) { var cert = cmsSigner.Certificates[i]; var context = Marshal.PtrToStructure <CERT_CONTEXT>(cert.Handle); certificateBlobs[i] = new BLOB() { cbData = context.cbCertEncoded, pbData = context.pbCertEncoded }; } byte[] encodedData; var signerInfo = CreateSignerInfo(cmsSigner, privateKey, hb); var signedInfo = new CMSG_SIGNED_ENCODE_INFO(); signedInfo.cbSize = Marshal.SizeOf(signedInfo); signedInfo.cSigners = 1; using (var signerInfoHandle = new SafeLocalAllocHandle(Marshal.AllocHGlobal(Marshal.SizeOf(signerInfo)))) { Marshal.StructureToPtr(signerInfo, signerInfoHandle.DangerousGetHandle(), fDeleteOld: false); signedInfo.rgSigners = signerInfoHandle.DangerousGetHandle(); signedInfo.cCertEncoded = certificateBlobs.Length; using (var certificatesHandle = new SafeLocalAllocHandle(Marshal.AllocHGlobal(Marshal.SizeOf(certificateBlobs[0]) * certificateBlobs.Length))) { for (var i = 0; i < certificateBlobs.Length; ++i) { Marshal.StructureToPtr(certificateBlobs[i], new IntPtr(certificatesHandle.DangerousGetHandle().ToInt64() + Marshal.SizeOf(certificateBlobs[i]) * i), fDeleteOld: false); } signedInfo.rgCertEncoded = certificatesHandle.DangerousGetHandle(); var hMsg = NativeMethods.CryptMsgOpenToEncode( NativeMethods.X509_ASN_ENCODING | NativeMethods.PKCS_7_ASN_ENCODING, dwFlags: 0, dwMsgType: NativeMethods.CMSG_SIGNED, pvMsgEncodeInfo: ref signedInfo, pszInnerContentObjID: null, pStreamInfo: IntPtr.Zero); ThrowIfFailed(!hMsg.IsInvalid); ThrowIfFailed(NativeMethods.CryptMsgUpdate( hMsg, data, (uint)data.Length, fFinal: true)); uint valueLength = 0; ThrowIfFailed(NativeMethods.CryptMsgGetParam( hMsg, CMSG_GETPARAM_TYPE.CMSG_CONTENT_PARAM, dwIndex: 0, pvData: null, pcbData: ref valueLength)); encodedData = new byte[(int)valueLength]; ThrowIfFailed(NativeMethods.CryptMsgGetParam( hMsg, CMSG_GETPARAM_TYPE.CMSG_CONTENT_PARAM, dwIndex: 0, pvData: encodedData, pcbData: ref valueLength)); } } var cms = new SignedCms(); cms.Decode(encodedData); return(cms); } }