public void AddCertificates(IEnumerable <byte[]> encodedCertificates) { foreach (var cert in encodedCertificates) { // Construct the blob IntPtr unmanagedCert = IntPtr.Zero; IntPtr unmanagedBlob = IntPtr.Zero; try { // Build blob holder unmanagedCert = Marshal.AllocHGlobal(cert.Length); Marshal.Copy(cert, 0, unmanagedCert, cert.Length); var blob = new CRYPT_INTEGER_BLOB_INTPTR() { cbData = (uint)cert.Length, pbData = unmanagedCert }; // Copy it to unmanaged memory unmanagedBlob = Marshal.AllocHGlobal(Marshal.SizeOf(blob)); Marshal.StructureToPtr(blob, unmanagedBlob, fDeleteOld: false); // Invoke the request if (!NativeMethods.CryptMsgControl( _handle, dwFlags: 0, dwCtrlType: CMSG_CONTROL_TYPE.CMSG_CTRL_ADD_CERT, pvCtrlPara: unmanagedBlob)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } } finally { NativeUtils.SafeFree(unmanagedCert); NativeUtils.SafeFree(unmanagedBlob); } } }
public void AddTimestamp(byte[] timeStampCms) { IntPtr unmanagedTimestamp = IntPtr.Zero; IntPtr unmanagedBlob = IntPtr.Zero; IntPtr unmanagedAttr = IntPtr.Zero; IntPtr unmanagedEncoded = IntPtr.Zero; IntPtr unmanagedAddAttr = IntPtr.Zero; try { // Wrap the timestamp in a CRYPT_INTEGER_BLOB and copy that to unmanaged memory unmanagedTimestamp = Marshal.AllocHGlobal(timeStampCms.Length); Marshal.Copy(timeStampCms, 0, unmanagedTimestamp, timeStampCms.Length); var blob = new CRYPT_INTEGER_BLOB_INTPTR() { cbData = (uint)timeStampCms.Length, pbData = unmanagedTimestamp }; unmanagedBlob = Marshal.AllocHGlobal(Marshal.SizeOf(blob)); Marshal.StructureToPtr(blob, unmanagedBlob, fDeleteOld: false); // Wrap it in a CRYPT_ATTRIBUTE and copy that too! var attr = new CRYPT_ATTRIBUTE() { pszObjId = Constants.SignatureTimeStampTokenAttributeOid.Value, cValue = 1, rgValue = unmanagedBlob }; unmanagedAttr = Marshal.AllocHGlobal(Marshal.SizeOf(attr)); Marshal.StructureToPtr(attr, unmanagedAttr, fDeleteOld: false); // Now encode the object using ye olde double-call-to-find-out-the-length mechanism :) uint encodedLength = 0; if (!NativeMethods.CryptEncodeObjectEx( dwCertEncodingType: NativeMethods.X509_ASN_ENCODING | NativeMethods.PKCS_7_ASN_ENCODING, lpszStructType: new IntPtr(NativeMethods.PKCS_ATTRIBUTE), pvStructInfo: unmanagedAttr, dwFlags: 0, pEncodePara: IntPtr.Zero, pvEncoded: IntPtr.Zero, pcbEncoded: ref encodedLength)) { var err = Marshal.GetLastWin32Error(); if (err != NativeMethods.ERROR_MORE_DATA) { Marshal.ThrowExceptionForHR(NativeMethods.GetHRForWin32Error(err)); } } unmanagedEncoded = Marshal.AllocHGlobal((int)encodedLength); if (!NativeMethods.CryptEncodeObjectEx( dwCertEncodingType: NativeMethods.X509_ASN_ENCODING | NativeMethods.PKCS_7_ASN_ENCODING, lpszStructType: new IntPtr(NativeMethods.PKCS_ATTRIBUTE), pvStructInfo: unmanagedAttr, dwFlags: 0, pEncodePara: IntPtr.Zero, pvEncoded: unmanagedEncoded, pcbEncoded: ref encodedLength)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } // Create the structure used to add the attribute var addAttr = new CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA() { dwSignerIndex = 0, BLOB = new CRYPT_INTEGER_BLOB_INTPTR() { cbData = encodedLength, pbData = unmanagedEncoded } }; addAttr.cbSize = (uint)Marshal.SizeOf(addAttr); unmanagedAddAttr = Marshal.AllocHGlobal(Marshal.SizeOf(addAttr)); Marshal.StructureToPtr(addAttr, unmanagedAddAttr, fDeleteOld: false); // Now store the timestamp in the message... FINALLY if (!NativeMethods.CryptMsgControl( _handle, dwFlags: 0, dwCtrlType: CMSG_CONTROL_TYPE.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, pvCtrlPara: unmanagedAddAttr)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } } finally { NativeUtils.SafeFree(unmanagedTimestamp); NativeUtils.SafeFree(unmanagedBlob); NativeUtils.SafeFree(unmanagedAttr); NativeUtils.SafeFree(unmanagedEncoded); NativeUtils.SafeFree(unmanagedAddAttr); } }