3
3
using System . IO ;
4
4
using System . Linq ;
5
5
using System . Reflection ;
6
+ using System . Runtime . InteropServices ;
6
7
using System . Security . Cryptography . X509Certificates ;
7
8
using System . Text ;
8
9
using System . Threading . Tasks ;
9
10
10
11
namespace DynamoUtilities
11
12
{
13
+ internal sealed class WinTrustInterop
14
+ {
15
+ #region WinTrustData struct field enums
16
+ enum WinTrustDataUIChoice : uint
17
+ {
18
+ All = 1 ,
19
+ None = 2 ,
20
+ NoBad = 3 ,
21
+ NoGood = 4
22
+ }
23
+
24
+ enum WinTrustDataRevocationChecks : uint
25
+ {
26
+ None = 0x00000000 ,
27
+ WholeChain = 0x00000001
28
+ }
29
+
30
+ enum WinTrustDataChoice : uint
31
+ {
32
+ File = 1 ,
33
+ Catalog = 2 ,
34
+ Blob = 3 ,
35
+ Signer = 4 ,
36
+ Certificate = 5
37
+ }
38
+
39
+ enum WinTrustDataStateAction : uint
40
+ {
41
+ Ignore = 0x00000000 ,
42
+ Verify = 0x00000001 ,
43
+ Close = 0x00000002 ,
44
+ AutoCache = 0x00000003 ,
45
+ AutoCacheFlush = 0x00000004
46
+ }
47
+
48
+ [ FlagsAttribute ]
49
+ enum WinTrustDataProvFlags : uint
50
+ {
51
+ UseIe4TrustFlag = 0x00000001 ,
52
+ NoIe4ChainFlag = 0x00000002 ,
53
+ NoPolicyUsageFlag = 0x00000004 ,
54
+ RevocationCheckNone = 0x00000010 ,
55
+ RevocationCheckEndCert = 0x00000020 ,
56
+ RevocationCheckChain = 0x00000040 ,
57
+ RevocationCheckChainExcludeRoot = 0x00000080 ,
58
+ SaferFlag = 0x00000100 , // Used by software restriction policies. Should not be used.
59
+ HashOnlyFlag = 0x00000200 ,
60
+ UseDefaultOsverCheck = 0x00000400 ,
61
+ LifetimeSigningFlag = 0x00000800 ,
62
+ CacheOnlyUrlRetrieval = 0x00001000 , // affects CRL retrieval and AIA retrieval
63
+ DisableMD2andMD4 = 0x00002000 // Win7 SP1+: Disallows use of MD2 or MD4 in the chain except for the root
64
+ }
65
+
66
+ enum WinTrustDataUIContext : uint
67
+ {
68
+ Execute = 0 ,
69
+ Install = 1
70
+ }
71
+ #endregion
72
+
73
+ #region WinTrust structures
74
+ [ StructLayout ( LayoutKind . Sequential , CharSet = CharSet . Unicode ) ]
75
+ class WinTrustFileInfo
76
+ {
77
+ UInt32 StructSize = ( UInt32 ) Marshal . SizeOf ( typeof ( WinTrustFileInfo ) ) ;
78
+ IntPtr pszFilePath ; // required, file name to be verified
79
+ IntPtr hFile = IntPtr . Zero ; // optional, open handle to FilePath
80
+ IntPtr pgKnownSubject = IntPtr . Zero ; // optional, subject type if it is known
81
+
82
+ public WinTrustFileInfo ( String _filePath )
83
+ {
84
+ pszFilePath = Marshal . StringToCoTaskMemAuto ( _filePath ) ;
85
+ }
86
+ public void Dispose ( )
87
+ {
88
+ if ( pszFilePath != IntPtr . Zero ) {
89
+ Marshal . FreeCoTaskMem ( pszFilePath ) ;
90
+ pszFilePath = IntPtr . Zero ;
91
+ }
92
+ }
93
+ }
94
+
95
+ [ StructLayout ( LayoutKind . Sequential , CharSet = CharSet . Unicode ) ]
96
+ class WinTrustData
97
+ {
98
+ UInt32 StructSize = ( UInt32 ) Marshal . SizeOf ( typeof ( WinTrustData ) ) ;
99
+ IntPtr PolicyCallbackData = IntPtr . Zero ;
100
+ IntPtr SIPClientData = IntPtr . Zero ;
101
+ // required: UI choice
102
+ WinTrustDataUIChoice UIChoice = WinTrustDataUIChoice . None ;
103
+ // required: certificate revocation check options
104
+ WinTrustDataRevocationChecks RevocationChecks = WinTrustDataRevocationChecks . None ;
105
+ // required: which structure is being passed in?
106
+ WinTrustDataChoice UnionChoice = WinTrustDataChoice . File ;
107
+ // individual file
108
+ IntPtr FileInfoPtr ;
109
+ WinTrustDataStateAction StateAction = WinTrustDataStateAction . Ignore ;
110
+ IntPtr StateData = IntPtr . Zero ;
111
+ String URLReference = null ;
112
+ WinTrustDataProvFlags ProvFlags = WinTrustDataProvFlags . RevocationCheckChainExcludeRoot ;
113
+ WinTrustDataUIContext UIContext = WinTrustDataUIContext . Execute ;
114
+
115
+ // constructor for silent WinTrustDataChoice.File check
116
+ public WinTrustData ( WinTrustFileInfo _fileInfo )
117
+ {
118
+ // On Win7SP1+, don't allow MD2 or MD4 signatures
119
+ if ( ( Environment . OSVersion . Version . Major > 6 ) ||
120
+ ( ( Environment . OSVersion . Version . Major == 6 ) && ( Environment . OSVersion . Version . Minor > 1 ) ) ||
121
+ ( ( Environment . OSVersion . Version . Major == 6 ) && ( Environment . OSVersion . Version . Minor == 1 ) && ! String . IsNullOrEmpty ( Environment . OSVersion . ServicePack ) ) )
122
+ {
123
+ ProvFlags |= WinTrustDataProvFlags . DisableMD2andMD4 ;
124
+ }
125
+
126
+ WinTrustFileInfo wtfiData = _fileInfo ;
127
+ FileInfoPtr = Marshal . AllocCoTaskMem ( Marshal . SizeOf ( typeof ( WinTrustFileInfo ) ) ) ;
128
+ Marshal . StructureToPtr ( wtfiData , FileInfoPtr , false ) ;
129
+ }
130
+ public void Dispose ( )
131
+ {
132
+ if ( FileInfoPtr != IntPtr . Zero ) {
133
+ Marshal . FreeCoTaskMem ( FileInfoPtr ) ;
134
+ FileInfoPtr = IntPtr . Zero ;
135
+ }
136
+ }
137
+ }
138
+ #endregion
139
+
140
+ enum WinVerifyTrustResult : uint
141
+ {
142
+ Success = 0 ,
143
+ ProviderUnknown = 0x800b0001 , // Trust provider is not recognized on this system
144
+ ActionUnknown = 0x800b0002 , // Trust provider does not support the specified action
145
+ SubjectFormUnknown = 0x800b0003 , // Trust provider does not support the form specified for the subject
146
+ SubjectNotTrusted = 0x800b0004 , // Subject failed the specified verification action
147
+ FileNotSigned = 0x800B0100 , // TRUST_E_NOSIGNATURE - File was not signed
148
+ SubjectExplicitlyDistrusted = 0x800B0111 , // Signer's certificate is in the Untrusted Publishers store
149
+ SignatureOrFileCorrupt = 0x80096010 , // TRUST_E_BAD_DIGEST - file was probably corrupt
150
+ SubjectCertExpired = 0x800B0101 , // CERT_E_EXPIRED - Signer's certificate was expired
151
+ SubjectCertificateRevoked = 0x800B010C , // CERT_E_REVOKED Subject's certificate was revoked
152
+ UntrustedRoot = 0x800B0109 // CERT_E_UNTRUSTEDROOT - A certification chain processed correctly but terminated in a root certificate that is not trusted by the trust provider.
153
+ }
154
+
155
+ public class WinTrust
156
+ {
157
+ private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr ( - 1 ) ;
158
+ // GUID of the action to perform
159
+ private const string WINTRUST_ACTION_GENERIC_VERIFY_V2 = "{00AAC56B-CD44-11d0-8CC2-00C04FC295EE}" ;
160
+
161
+ [ DllImport ( "wintrust.dll" , ExactSpelling = true , SetLastError = false , CharSet = CharSet . Unicode ) ]
162
+ static extern WinVerifyTrustResult WinVerifyTrust (
163
+ [ In ] IntPtr hwnd ,
164
+ [ In ] [ MarshalAs ( UnmanagedType . LPStruct ) ] Guid pgActionID ,
165
+ [ In ] WinTrustData pWVTData
166
+ ) ;
167
+
168
+ // call WinTrust.WinVerifyTrust() to check embedded file signature
169
+ public static bool VerifyEmbeddedSignature ( string fileName )
170
+ {
171
+ WinTrustFileInfo winTrustFileInfo = null ;
172
+ WinTrustData winTrustData = null ;
173
+
174
+ try
175
+ {
176
+ winTrustFileInfo = new WinTrustFileInfo ( fileName ) ;
177
+ winTrustData = new WinTrustData ( winTrustFileInfo ) ;
178
+ Guid guidAction = new Guid ( WINTRUST_ACTION_GENERIC_VERIFY_V2 ) ;
179
+ WinVerifyTrustResult result = WinVerifyTrust ( INVALID_HANDLE_VALUE , guidAction , winTrustData ) ;
180
+ bool ret = ( result == WinVerifyTrustResult . Success ) ;
181
+ return ret ;
182
+ }
183
+ finally
184
+ {
185
+ // free the locally-held unmanaged memory in the data structures
186
+ if ( winTrustFileInfo != null ) winTrustFileInfo . Dispose ( ) ;
187
+ if ( winTrustData != null ) winTrustData . Dispose ( ) ;
188
+ }
189
+ }
190
+ private WinTrust ( ) { }
191
+ }
192
+ }
193
+
12
194
public class CertificateVerification
13
195
{
14
196
/// <summary>
@@ -21,45 +203,37 @@ public static bool CheckAssemblyForValidCertificate(string assemblyPath)
21
203
//Verify the assembly exists
22
204
if ( ! File . Exists ( assemblyPath ) )
23
205
{
24
- throw new Exception ( String . Format (
25
- "A dll file was not found at {0}. No certificate was able to be verified." , assemblyPath ) ) ;
206
+ throw new FileNotFoundException ( String . Format (
207
+ "A dll file was not found at {0}. No certificate was able to be verified." , assemblyPath ) , assemblyPath ) ;
26
208
}
27
209
28
- //Verify that you can load the assembly into a Reflection only context
29
- Assembly asm ;
210
+ //Verify the node library file has a verified signed certificate
30
211
try
31
212
{
32
- asm = Assembly . ReflectionOnlyLoadFrom ( assemblyPath ) ;
213
+ var validCert = WinTrustInterop . WinTrust . VerifyEmbeddedSignature ( assemblyPath ) ;
214
+ if ( validCert )
215
+ {
216
+ return true ;
217
+ }
33
218
}
34
219
catch
35
220
{
36
- throw new Exception ( String . Format (
37
- "A dll file found at {0} could not be loaded." , assemblyPath ) ) ;
221
+ throw new AssemblyCertificateCheckException ( assemblyPath ) ;
38
222
}
39
223
40
- //Verify the node library has a verified signed certificate
41
- X509Certificate cert ;
42
- try
43
- {
44
- cert = X509Certificate . CreateFromSignedFile ( assemblyPath ) ;
45
- }
46
- catch
47
- {
48
- throw new Exception ( String . Format (
49
- "A dll file found at {0} did not have a certificate attached." , assemblyPath ) ) ;
50
- }
224
+ throw new UnTrustedAssemblyException ( assemblyPath ) ;
225
+ }
51
226
52
- if ( cert != null )
53
- {
54
- var cert2 = new System . Security . Cryptography . X509Certificates . X509Certificate2 ( cert ) ;
55
- if ( cert2 . Verify ( ) )
56
- {
57
- return true ;
58
- }
59
- }
227
+ public class UnTrustedAssemblyException : Exception
228
+ {
229
+ public UnTrustedAssemblyException ( string assemblyPath ) : base ( String . Format (
230
+ "A dll file found at {0} did not have a signed certificate." , assemblyPath ) ) { }
231
+ }
60
232
61
- throw new Exception ( String . Format (
62
- "A dll file found at {0} did not have a signed certificate." , assemblyPath ) ) ;
233
+ public class AssemblyCertificateCheckException : Exception
234
+ {
235
+ public AssemblyCertificateCheckException ( string assemblyPath ) : base ( String . Format (
236
+ "Could not verify the dll file found at {0} has a signed certificate." , assemblyPath ) ) { }
63
237
}
64
238
}
65
239
}
0 commit comments