public static IEnumerable <Timestamp> GetTimestamps(string path) { if (String.IsNullOrEmpty(path)) { return(null); } var timestamps = new List <Timestamp>(); int msgAndCertEncodingType; int msgContentType; int formatType; // NULL indicates that information is unneeded IntPtr certStore = IntPtr.Zero; IntPtr msg = IntPtr.Zero; IntPtr context = IntPtr.Zero; if (!WinCrypt.CryptQueryObject( WinCrypt.CERT_QUERY_OBJECT_FILE, Marshal.StringToHGlobalUni(path), WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED | WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_UNSIGNED | WinCrypt.CERT_QUERY_CONTENT_FLAG_PKCS7_SIGNED_EMBED, WinCrypt.CERT_QUERY_FORMAT_FLAG_ALL, 0, out msgAndCertEncodingType, out msgContentType, out formatType, ref certStore, ref msg, ref context)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } int cbData = 0; // Passing in NULL to pvData retrieves the size of the encoded message if (!WinCrypt.CryptMsgGetParam(msg, WinCrypt.CMSG_ENCODED_MESSAGE, 0, IntPtr.Zero, ref cbData)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } byte[] vData = new byte[cbData]; if (!WinCrypt.CryptMsgGetParam(msg, WinCrypt.CMSG_ENCODED_MESSAGE, 0, vData, ref cbData)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var signedCms = new SignedCms(); signedCms.Decode(vData); // Timestamp information can be stored in multiple sections. // A single SHA1 stores the timestamp as a counter sign in the unsigned attributes // Multiple authenticode signatures will store additional information as a nested signature // In the case of SHA2 signatures, we need to find and decode the timestamp token (RFC3161). // Luckily NuGet implemented a proper TST and DER parser to decode this foreach (SignerInfo signerInfo in signedCms.SignerInfos) { foreach (CryptographicAttributeObject unsignedAttribute in signerInfo.UnsignedAttributes) { if (String.Equals(unsignedAttribute.Oid.Value, WinCrypt.szOID_RSA_counterSign, StringComparison.OrdinalIgnoreCase)) { foreach (SignerInfo counterSign in signerInfo.CounterSignerInfos) { foreach (CryptographicAttributeObject signedAttribute in counterSign.SignedAttributes) { if (String.Equals(signedAttribute.Oid.Value, WinCrypt.szOID_RSA_signingTime, StringComparison.OrdinalIgnoreCase)) { var st = (Pkcs9SigningTime)signedAttribute.Values[0]; X509Certificate2 cert = counterSign.Certificate; var timeStamp = new Timestamp { SignedOn = st.SigningTime.ToLocalTime(), EffectiveDate = Convert.ToDateTime(cert.GetEffectiveDateString()).ToLocalTime(), ExpiryDate = Convert.ToDateTime(cert.GetExpirationDateString()).ToLocalTime(), SignatureAlgorithm = cert.SignatureAlgorithm.FriendlyName }; timestamps.Add(timeStamp); } } } } else if (String.Equals(unsignedAttribute.Oid.Value, WinCrypt.szOID_RFC3161_counterSign, StringComparison.OrdinalIgnoreCase)) { timestamps.AddRange(GetTimestampsFromCounterSignature(unsignedAttribute.Values[0])); } else if (String.Equals(unsignedAttribute.Oid.Value, WinCrypt.szOID_NESTED_SIGNATURE, StringComparison.OrdinalIgnoreCase)) { var nestedSignature = new Pkcs9AttributeObject(unsignedAttribute.Values[0]); SignedCms nestedSignatureMessage = new SignedCms(); nestedSignatureMessage.Decode(nestedSignature.RawData); foreach (SignerInfo nestedSignerInfo in nestedSignatureMessage.SignerInfos) { foreach (CryptographicAttributeObject nestedUnsignedAttribute in nestedSignerInfo.UnsignedAttributes) { if (String.Equals(nestedUnsignedAttribute.Oid.Value, WinCrypt.szOID_RFC3161_counterSign, StringComparison.OrdinalIgnoreCase)) { timestamps.AddRange(GetTimestampsFromCounterSignature(nestedUnsignedAttribute.Values[0])); } } } } } } return(timestamps); }
public static bool IsTimestamped(string filename) { try { int encodingType; int contentType; int formatType; IntPtr certStore = IntPtr.Zero; IntPtr cryptMsg = IntPtr.Zero; IntPtr context = IntPtr.Zero; if (!WinCrypt.CryptQueryObject( WinCrypt.CERT_QUERY_OBJECT_FILE, Marshal.StringToHGlobalUni(filename), WinCrypt.CERT_QUERY_CONTENT_FLAG_ALL, WinCrypt.CERT_QUERY_FORMAT_FLAG_ALL, 0, out encodingType, out contentType, out formatType, ref certStore, ref cryptMsg, ref context)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } //expecting contentType=10; CERT_QUERY_CONTENT_PKCS7_SIGNED_EMBED //Logger.LogInfo(string.Format("Querying file '{0}':", filename)); //Logger.LogInfo(string.Format(" Encoding Type: {0}", encodingType)); //Logger.LogInfo(string.Format(" Content Type: {0}", contentType)); //Logger.LogInfo(string.Format(" Format Type: {0}", formatType)); //Logger.LogInfo(string.Format(" Cert Store: {0}", certStore.ToInt32())); //Logger.LogInfo(string.Format(" Crypt Msg: {0}", cryptMsg.ToInt32())); //Logger.LogInfo(string.Format(" Context: {0}", context.ToInt32())); // Get size of the encoded message. int cbData = 0; if (!WinCrypt.CryptMsgGetParam( cryptMsg, WinCrypt.CMSG_ENCODED_MESSAGE, //Crypt32.CMSG_SIGNER_INFO_PARAM, 0, IntPtr.Zero, ref cbData)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var vData = new byte[cbData]; // Get the encoded message. if (!WinCrypt.CryptMsgGetParam( cryptMsg, WinCrypt.CMSG_ENCODED_MESSAGE, //Crypt32.CMSG_SIGNER_INFO_PARAM, 0, vData, ref cbData)) { throw new Win32Exception(Marshal.GetLastWin32Error()); } var signedCms = new SignedCms(); signedCms.Decode(vData); foreach (var signerInfo in signedCms.SignerInfos) { foreach (var unsignedAttribute in signerInfo.UnsignedAttributes) { if (unsignedAttribute.Oid.Value == WinCrypt.szOID_RSA_counterSign) { foreach (var counterSignInfo in signerInfo.CounterSignerInfos) { foreach (var signedAttribute in counterSignInfo.SignedAttributes) { if (signedAttribute.Oid.Value == WinCrypt.szOID_RSA_signingTime) { var fileTime = new FILETIME(); int fileTimeSize = Marshal.SizeOf(fileTime); IntPtr fileTimePtr = Marshal.AllocCoTaskMem(fileTimeSize); Marshal.StructureToPtr(fileTime, fileTimePtr, true); var buffdata = new byte[fileTimeSize]; Marshal.Copy(fileTimePtr, buffdata, 0, fileTimeSize); var buffSize = (uint)buffdata.Length; uint encoding = WinCrypt.X509_ASN_ENCODING | WinCrypt.PKCS_7_ASN_ENCODING; var rsaSigningTime = (UIntPtr)(uint)Marshal.StringToHGlobalAnsi(WinCrypt.szOID_RSA_signingTime); byte[] pbData = signedAttribute.Values[0].RawData; var ucbData = (uint)pbData.Length; bool workie = WinCrypt.CryptDecodeObject(encoding, rsaSigningTime, pbData, ucbData, 0, buffdata, ref buffSize); if (workie) { IntPtr fileTimePtr2 = Marshal.AllocCoTaskMem(buffdata.Length); Marshal.Copy(buffdata, 0, fileTimePtr2, buffdata.Length); var fileTime2 = (FILETIME)Marshal.PtrToStructure(fileTimePtr2, typeof(FILETIME)); long hFT2 = (((long)fileTime2.dwHighDateTime) << 32) + ((uint)fileTime2.dwLowDateTime); DateTime dte = DateTime.FromFileTime(hFT2); Console.WriteLine(dte.ToString()); } else { throw new Win32Exception(Marshal.GetLastWin32Error()); } } } } return(true); } } } } catch (Exception) { // no logging } return(false); }