private static CRYPT_ATTRIBUTE GetCryptAttributeForData(byte[] data, string attributeOid, HeapBlockRetainer hb) { var unmanagedData = hb.Alloc(data.Length); Marshal.Copy(data, 0, unmanagedData, data.Length); var blob = new CRYPT_INTEGER_BLOB() { cbData = (uint)data.Length, pbData = unmanagedData }; var unmanagedBlob = hb.Alloc(Marshal.SizeOf(blob)); Marshal.StructureToPtr(blob, unmanagedBlob, fDeleteOld: false); var attr = new CRYPT_ATTRIBUTE() { pszObjId = hb.AllocAsciiString(attributeOid), cValue = 1, rgValue = unmanagedBlob }; return(attr); }
private unsafe static CMSG_SIGNER_ENCODE_INFO CreateSignerInfo( CmsSigner cmsSigner, CngKey privateKey, HeapBlockRetainer hb) { var signerInfo = new CMSG_SIGNER_ENCODE_INFO(); signerInfo.cbSize = (uint)Marshal.SizeOf(signerInfo); signerInfo.pCertInfo = Marshal.PtrToStructure <CERT_CONTEXT>(cmsSigner.Certificate.Handle).pCertInfo; signerInfo.hCryptProvOrhNCryptKey = privateKey.Handle.DangerousGetHandle(); signerInfo.HashAlgorithm.pszObjId = cmsSigner.DigestAlgorithm.Value; if (cmsSigner.SignerIdentifierType == SubjectIdentifierType.SubjectKeyIdentifier) { var certContextHandle = IntPtr.Zero; try { certContextHandle = NativeMethods.CertDuplicateCertificateContext(cmsSigner.Certificate.Handle); uint cbData = 0; var pbData = IntPtr.Zero; ThrowIfFailed(NativeMethods.CertGetCertificateContextProperty( certContextHandle, NativeMethods.CERT_KEY_IDENTIFIER_PROP_ID, pbData, ref cbData)); if (cbData > 0) { pbData = hb.Alloc((int)cbData); ThrowIfFailed(NativeMethods.CertGetCertificateContextProperty( certContextHandle, NativeMethods.CERT_KEY_IDENTIFIER_PROP_ID, pbData, ref cbData)); signerInfo.SignerId.dwIdChoice = NativeMethods.CERT_ID_KEY_IDENTIFIER; signerInfo.SignerId.KeyId.cbData = cbData; signerInfo.SignerId.KeyId.pbData = pbData; } } finally { if (certContextHandle != IntPtr.Zero) { NativeMethods.CertFreeCertificateContext(certContextHandle); } } } if (cmsSigner.SignedAttributes.Count != 0) { signerInfo.cAuthAttr = cmsSigner.SignedAttributes.Count; checked { var attributeSize = Marshal.SizeOf <CRYPT_ATTRIBUTE>(); var blobSize = Marshal.SizeOf <CRYPT_INTEGER_BLOB>(); var attributesArray = (CRYPT_ATTRIBUTE *)hb.Alloc(attributeSize * cmsSigner.SignedAttributes.Count); var currentAttribute = attributesArray; foreach (var attribute in cmsSigner.SignedAttributes) { currentAttribute->pszObjId = hb.AllocAsciiString(attribute.Oid.Value); currentAttribute->cValue = (uint)attribute.Values.Count; currentAttribute->rgValue = hb.Alloc(blobSize); foreach (var value in attribute.Values) { var attrData = value.RawData; if (attrData.Length > 0) { var blob = (CRYPT_INTEGER_BLOB *)currentAttribute->rgValue; blob->cbData = (uint)attrData.Length; blob->pbData = hb.Alloc(value.RawData.Length); Marshal.Copy(attrData, 0, blob->pbData, attrData.Length); } } currentAttribute++; } signerInfo.rgAuthAttr = new IntPtr(attributesArray); } } return(signerInfo); }
internal unsafe void AddTimestamp(byte[] timeStampCms) { using (var hb = new HeapBlockRetainer()) { var unmanagedTimestamp = hb.Alloc(timeStampCms.Length); Marshal.Copy(timeStampCms, 0, unmanagedTimestamp, timeStampCms.Length); var blob = new CRYPT_INTEGER_BLOB() { cbData = (uint)timeStampCms.Length, pbData = unmanagedTimestamp }; var unmanagedBlob = hb.Alloc(Marshal.SizeOf(blob)); Marshal.StructureToPtr(blob, unmanagedBlob, fDeleteOld: false); var attr = new CRYPT_ATTRIBUTE() { pszObjId = hb.AllocAsciiString(Oids.SignatureTimeStampTokenAttribute), cValue = 1, rgValue = unmanagedBlob }; var unmanagedAttr = hb.Alloc(Marshal.SizeOf(attr)); Marshal.StructureToPtr(attr, unmanagedAttr, fDeleteOld: false); 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)); } } var unmanagedEncoded = hb.Alloc((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()); } var addAttr = new CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR_PARA() { dwSignerIndex = 0, BLOB = new CRYPT_INTEGER_BLOB() { cbData = encodedLength, pbData = unmanagedEncoded } }; addAttr.cbSize = (uint)Marshal.SizeOf(addAttr); var unmanagedAddAttr = hb.Alloc(Marshal.SizeOf(addAttr)); Marshal.StructureToPtr(addAttr, unmanagedAddAttr, fDeleteOld: false); if (!NativeMethods.CryptMsgControl( _handle, dwFlags: 0, dwCtrlType: CMSG_CONTROL_TYPE.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, pvCtrlPara: unmanagedAddAttr)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } } }
internal unsafe void AddTimestampToRepositoryCountersignature(SignedCms timestamp) { using (var hb = new HeapBlockRetainer()) { var repositoryCountersignature = GetRepositoryCountersignature(hb); if (repositoryCountersignature == null) { throw new SignatureException(Strings.Error_NotOneRepositoryCounterSignature); } // Remove repository countersignature from message var countersignatureDelAttr = new CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR_PARA() { dwSignerIndex = 0, dwUnauthAttrIndex = repositoryCountersignature.Value.dwUnauthAttrIndex }; countersignatureDelAttr.cbSize = (uint)Marshal.SizeOf(countersignatureDelAttr); var unmanagedCountersignatureDelAttr = hb.Alloc(Marshal.SizeOf(countersignatureDelAttr)); Marshal.StructureToPtr(countersignatureDelAttr, unmanagedCountersignatureDelAttr, fDeleteOld: false); if (!NativeMethods.CryptMsgControl( _handle, dwFlags: 0, dwCtrlType: CMSG_CONTROL_TYPE.CMSG_CTRL_DEL_SIGNER_UNAUTH_ATTR, pvCtrlPara: unmanagedCountersignatureDelAttr)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } // Add timestamp attribute to existing unsigned attributes var signerInfo = repositoryCountersignature.Value.SignerInfo; var unauthAttrCount = signerInfo.UnauthAttrs.cAttr + 1; var sizeOfCryptAttribute = MarshalUtility.SizeOf <CRYPT_ATTRIBUTE>(); var attributesArray = (CRYPT_ATTRIBUTE *)hb.Alloc((int)(sizeOfCryptAttribute * unauthAttrCount)); var currentAttribute = attributesArray; // Copy existing unsigned attributes for (var i = 0; i < unauthAttrCount - 1; ++i) { var existingAttributePointer = new IntPtr( (long)signerInfo.UnauthAttrs.rgAttr + (i * sizeOfCryptAttribute)); var existingAttribute = MarshalUtility.PtrToStructure <CRYPT_ATTRIBUTE>(existingAttributePointer); currentAttribute->pszObjId = existingAttribute.pszObjId; currentAttribute->cValue = existingAttribute.cValue; currentAttribute->rgValue = existingAttribute.rgValue; currentAttribute++; } // Add timestamp attribute *currentAttribute = GetCryptAttributeForData(timestamp.Encode(), Oids.SignatureTimeStampTokenAttribute, hb); signerInfo.UnauthAttrs = new CRYPT_ATTRIBUTES() { cAttr = unauthAttrCount, rgAttr = new IntPtr(attributesArray) }; // Encode signer info var unmanagedSignerInfo = hb.Alloc(Marshal.SizeOf(signerInfo)); Marshal.StructureToPtr(signerInfo, unmanagedSignerInfo, fDeleteOld: false); uint encodedLength = 0; if (!NativeMethods.CryptEncodeObjectEx( CMSG_ENCODING.Any, lpszStructType: new IntPtr(NativeMethods.PKCS7_SIGNER_INFO), pvStructInfo: unmanagedSignerInfo, 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)); } } var unmanagedEncoded = hb.Alloc((int)encodedLength); if (!NativeMethods.CryptEncodeObjectEx( CMSG_ENCODING.Any, lpszStructType: new IntPtr(NativeMethods.PKCS7_SIGNER_INFO), pvStructInfo: unmanagedSignerInfo, dwFlags: 0, pEncodePara: IntPtr.Zero, pvEncoded: unmanagedEncoded, pcbEncoded: ref encodedLength)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } var encondedSignerBlob = new CRYPT_INTEGER_BLOB() { cbData = encodedLength, pbData = unmanagedEncoded }; var unmanagedBlob = hb.Alloc(Marshal.SizeOf(encondedSignerBlob)); Marshal.StructureToPtr(encondedSignerBlob, unmanagedBlob, fDeleteOld: false); var signerInfoAttr = new CRYPT_ATTRIBUTE() { pszObjId = hb.AllocAsciiString(Oids.Countersignature), cValue = 1, rgValue = unmanagedBlob }; // Create add unauth for signer info var signerInfoAddAttr = CreateUnsignedAddAttribute(signerInfoAttr, hb); // Add repository countersignature back to message signerInfoAddAttr.cbSize = (uint)Marshal.SizeOf(signerInfoAddAttr); var unmanagedSignerInfoAddAttr = hb.Alloc(Marshal.SizeOf(signerInfoAddAttr)); Marshal.StructureToPtr(signerInfoAddAttr, unmanagedSignerInfoAddAttr, fDeleteOld: false); if (!NativeMethods.CryptMsgControl( _handle, dwFlags: 0, dwCtrlType: CMSG_CONTROL_TYPE.CMSG_CTRL_ADD_SIGNER_UNAUTH_ATTR, pvCtrlPara: unmanagedSignerInfoAddAttr)) { Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error()); } } }