markus / MarkusAutoUpdate / src / NetSparkle / SignatureVerifiers / DSAChecker.cs @ d8f5045e
이력 | 보기 | 이력해설 | 다운로드 (7.45 KB)
1 |
using System; |
---|---|
2 |
using System.Diagnostics; |
3 |
using System.Linq; |
4 |
using System.IO; |
5 |
using System.Reflection; |
6 |
using System.Security.Cryptography; |
7 |
using NetSparkleUpdater.Enums; |
8 |
using NetSparkleUpdater.Interfaces; |
9 |
|
10 |
namespace NetSparkleUpdater.SignatureVerifiers |
11 |
{ |
12 |
/// <summary> |
13 |
/// Class to verify a DSA signature |
14 |
/// </summary> |
15 |
public class DSAChecker : ISignatureVerifier |
16 |
{ |
17 |
private DSACryptoServiceProvider _cryptoProvider; |
18 |
|
19 |
/// <summary> |
20 |
/// Determines if a public key exists |
21 |
/// </summary> |
22 |
/// <returns><c>bool</c></returns> |
23 |
public bool HasValidKeyInformation() |
24 |
{ |
25 |
return _cryptoProvider != null; |
26 |
} |
27 |
|
28 |
/// <summary> |
29 |
/// Create a DSAChecker object from the given parameters |
30 |
/// </summary> |
31 |
/// <param name="mode">The security mode of the validator. Controls what needs to be set in order to validate |
32 |
/// an app cast and its items.</param> |
33 |
/// <param name="publicKey">the public key as string (will be preferred before the file)</param> |
34 |
/// <param name="publicKeyFile">the public key file</param> |
35 |
public DSAChecker(SecurityMode mode, string publicKey = null, string publicKeyFile = "NetSparkle_DSA.pub") |
36 |
{ |
37 |
SecurityMode = mode; |
38 |
|
39 |
string key = publicKey; |
40 |
|
41 |
if (string.IsNullOrEmpty(key)) |
42 |
{ |
43 |
Stream data = TryGetResourceStream(publicKeyFile); |
44 |
if (data == null) |
45 |
{ |
46 |
data = TryGetFileResource(publicKeyFile, data); |
47 |
} |
48 |
|
49 |
if (data != null) |
50 |
{ |
51 |
using (StreamReader reader = new StreamReader(data)) |
52 |
{ |
53 |
key = reader.ReadToEnd(); |
54 |
} |
55 |
} |
56 |
} |
57 |
|
58 |
if (!string.IsNullOrEmpty(key)) |
59 |
{ |
60 |
try |
61 |
{ |
62 |
_cryptoProvider = new DSACryptoServiceProvider(); |
63 |
_cryptoProvider.FromXmlString(key); |
64 |
} |
65 |
catch |
66 |
{ |
67 |
_cryptoProvider = null; |
68 |
} |
69 |
} |
70 |
} |
71 |
|
72 |
/// <summary> |
73 |
/// <inheritdoc/> |
74 |
/// </summary> |
75 |
public SecurityMode SecurityMode { get; set; } |
76 |
|
77 |
private bool CheckSecurityMode(string signature, ref ValidationResult result) |
78 |
{ |
79 |
switch (SecurityMode) |
80 |
{ |
81 |
case SecurityMode.UseIfPossible: |
82 |
// if we have a DSA key, we only accept non-null signatures |
83 |
if (HasValidKeyInformation() && string.IsNullOrEmpty(signature)) |
84 |
{ |
85 |
result = ValidationResult.Invalid; |
86 |
return false; |
87 |
} |
88 |
// if we don't have an dsa key, we accept any signature |
89 |
if (!HasValidKeyInformation()) |
90 |
{ |
91 |
result = ValidationResult.Unchecked; |
92 |
return false; |
93 |
} |
94 |
break; |
95 |
|
96 |
case SecurityMode.Strict: |
97 |
// only accept if we have both a public key and a non-null signature |
98 |
if (!HasValidKeyInformation() || string.IsNullOrEmpty(signature)) |
99 |
{ |
100 |
result = ValidationResult.Invalid; |
101 |
return false; |
102 |
} |
103 |
break; |
104 |
|
105 |
case SecurityMode.Unsafe: |
106 |
// always accept anything |
107 |
// If we don't have a signature, make sure to note this as "Unchecked" since we |
108 |
// didn't end up checking anything due to a lack of public key/signature |
109 |
if (!HasValidKeyInformation() || string.IsNullOrEmpty(signature)) |
110 |
{ |
111 |
result = ValidationResult.Unchecked; |
112 |
return false; |
113 |
} |
114 |
break; |
115 |
|
116 |
case SecurityMode.OnlyVerifySoftwareDownloads: |
117 |
// If we don't have a signature, make sure to note this as "Unchecked" since we |
118 |
// didn't end up checking anything due to a lack of public key/signature |
119 |
if (!HasValidKeyInformation() || string.IsNullOrEmpty(signature)) |
120 |
{ |
121 |
result = ValidationResult.Unchecked; |
122 |
return false; |
123 |
} |
124 |
break; |
125 |
} |
126 |
return true; |
127 |
} |
128 |
|
129 |
/// <inheritdoc/> |
130 |
public ValidationResult VerifySignature(string signature, byte[] dataToVerify) |
131 |
{ |
132 |
ValidationResult res = ValidationResult.Invalid; |
133 |
if (!CheckSecurityMode(signature, ref res)) |
134 |
{ |
135 |
return res; |
136 |
} |
137 |
|
138 |
// convert signature |
139 |
byte[] bHash = Convert.FromBase64String(signature); |
140 |
|
141 |
// verify |
142 |
return _cryptoProvider.VerifyData(dataToVerify, bHash) ? ValidationResult.Valid : ValidationResult.Invalid; |
143 |
} |
144 |
|
145 |
/// <inheritdoc/> |
146 |
public ValidationResult VerifySignatureOfFile(string signature, string binaryPath) |
147 |
{ |
148 |
using (Stream inputStream = File.OpenRead(binaryPath)) |
149 |
{ |
150 |
return VerifySignature(signature, Utilities.ConvertStreamToByteArray(inputStream)); |
151 |
} |
152 |
} |
153 |
|
154 |
/// <inheritdoc/> |
155 |
public ValidationResult VerifySignatureOfString(string signature, string data) |
156 |
{ |
157 |
// creating stream from string |
158 |
using (var stream = new MemoryStream()) |
159 |
using (var writer = new StreamWriter(stream)) |
160 |
{ |
161 |
writer.Write(data); |
162 |
writer.Flush(); |
163 |
stream.Position = 0; |
164 |
|
165 |
return VerifySignature(signature, Utilities.ConvertStreamToByteArray(stream)); |
166 |
} |
167 |
} |
168 |
|
169 |
/// <summary> |
170 |
/// Gets a file resource |
171 |
/// </summary> |
172 |
/// <param name="publicKey">the public key</param> |
173 |
/// <param name="data">the data stream</param> |
174 |
/// <returns>the data stream</returns> |
175 |
private static Stream TryGetFileResource(string publicKey, Stream data) |
176 |
{ |
177 |
if (File.Exists(publicKey)) |
178 |
{ |
179 |
data = File.OpenRead(publicKey); |
180 |
} |
181 |
return data; |
182 |
} |
183 |
|
184 |
/// <summary> |
185 |
/// Get a resource stream |
186 |
/// </summary> |
187 |
/// <param name="publicKey">the public key</param> |
188 |
/// <returns>a stream</returns> |
189 |
private static Stream TryGetResourceStream(string publicKey) |
190 |
{ |
191 |
Stream data = null; |
192 |
foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies()) |
193 |
{ |
194 |
string[] resources; |
195 |
try |
196 |
{ |
197 |
resources = asm.GetManifestResourceNames(); |
198 |
} |
199 |
catch (NotSupportedException) |
200 |
{ |
201 |
continue; |
202 |
} |
203 |
var resourceName = resources.FirstOrDefault(s => s.IndexOf(publicKey, StringComparison.OrdinalIgnoreCase) > -1); |
204 |
if (!string.IsNullOrEmpty(resourceName)) |
205 |
{ |
206 |
data = asm.GetManifestResourceStream(resourceName); |
207 |
if (data != null) |
208 |
{ |
209 |
break; |
210 |
} |
211 |
} |
212 |
} |
213 |
return data; |
214 |
} |
215 |
} |
216 |
} |