Skip to content

Commit 93ed97a

Browse files
committed
Add argument checks
1 parent af7b270 commit 93ed97a

File tree

4 files changed

+103
-8
lines changed

4 files changed

+103
-8
lines changed

src/EasySign.Cli/packages.lock.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@
2020
"resolved": "2.0.0-beta4.22272.1",
2121
"contentHash": "1uqED/q2H0kKoLJ4+hI2iPSBSEdTuhfCYADeJrAqERmiGQ2NNacYKRNEQ+gFbU4glgVyK8rxI+ZOe1onEtr/Pg=="
2222
},
23+
"Ensure.That": {
24+
"type": "Transitive",
25+
"resolved": "10.1.0",
26+
"contentHash": "rzTMSs0lQnu0WsesvTjs/zDzqiZXb9r5dv+wFQcPg/iIZqXb5BzwpIWEwi8Q3HA0TS4ytRcY129aSek6IzuOmA=="
27+
},
2328
"Microsoft.Extensions.DependencyInjection": {
2429
"type": "Transitive",
2530
"resolved": "8.0.1",
@@ -85,6 +90,7 @@
8590
"SAPTeam.EasySign": {
8691
"type": "Project",
8792
"dependencies": {
93+
"Ensure.That": "[10.1.0, )",
8894
"Microsoft.Extensions.Logging": "[8.0.1, )"
8995
}
9096
}
@@ -108,6 +114,11 @@
108114
"resolved": "2.0.0-beta4.22272.1",
109115
"contentHash": "1uqED/q2H0kKoLJ4+hI2iPSBSEdTuhfCYADeJrAqERmiGQ2NNacYKRNEQ+gFbU4glgVyK8rxI+ZOe1onEtr/Pg=="
110116
},
117+
"Ensure.That": {
118+
"type": "Transitive",
119+
"resolved": "10.1.0",
120+
"contentHash": "rzTMSs0lQnu0WsesvTjs/zDzqiZXb9r5dv+wFQcPg/iIZqXb5BzwpIWEwi8Q3HA0TS4ytRcY129aSek6IzuOmA=="
121+
},
111122
"Microsoft.Extensions.DependencyInjection": {
112123
"type": "Transitive",
113124
"resolved": "9.0.3",
@@ -162,6 +173,7 @@
162173
"SAPTeam.EasySign": {
163174
"type": "Project",
164175
"dependencies": {
176+
"Ensure.That": "[10.1.0, )",
165177
"Microsoft.Extensions.Logging": "[9.0.3, )"
166178
}
167179
}
@@ -185,6 +197,11 @@
185197
"resolved": "2.0.0-beta4.22272.1",
186198
"contentHash": "1uqED/q2H0kKoLJ4+hI2iPSBSEdTuhfCYADeJrAqERmiGQ2NNacYKRNEQ+gFbU4glgVyK8rxI+ZOe1onEtr/Pg=="
187199
},
200+
"Ensure.That": {
201+
"type": "Transitive",
202+
"resolved": "10.1.0",
203+
"contentHash": "rzTMSs0lQnu0WsesvTjs/zDzqiZXb9r5dv+wFQcPg/iIZqXb5BzwpIWEwi8Q3HA0TS4ytRcY129aSek6IzuOmA=="
204+
},
188205
"Microsoft.Extensions.DependencyInjection": {
189206
"type": "Transitive",
190207
"resolved": "9.0.3",
@@ -233,6 +250,7 @@
233250
"SAPTeam.EasySign": {
234251
"type": "Project",
235252
"dependencies": {
253+
"Ensure.That": "[10.1.0, )",
236254
"Microsoft.Extensions.Logging": "[9.0.3, )"
237255
}
238256
}

src/EasySign/Bundle.cs

Lines changed: 66 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using System.Text.Json.Serialization;
1313
using System.Threading.Tasks;
1414

15+
using EnsureThat;
16+
1517
using Microsoft.Extensions.Logging;
1618
using Microsoft.Extensions.Logging.Abstractions;
1719

@@ -96,6 +98,8 @@ public class Bundle
9698
/// <param name="logger">The logger to use for logging.</param>
9799
public Bundle(string rootPath, string bundleName, ILogger? logger = null) : this(rootPath, logger)
98100
{
101+
Ensure.String.IsNotNullOrEmpty(bundleName.Trim(), nameof(bundleName));
102+
99103
_bundleName = bundleName;
100104
}
101105

@@ -106,6 +110,8 @@ public Bundle(string rootPath, string bundleName, ILogger? logger = null) : this
106110
/// <param name="logger">The logger to use for logging.</param>
107111
public Bundle(string rootPath, ILogger? logger = null)
108112
{
113+
Ensure.String.IsNotNullOrEmpty(rootPath.Trim(), nameof(rootPath));
114+
109115
RootPath = Path.GetFullPath(rootPath);
110116
Logger = logger ?? NullLogger.Instance;
111117
}
@@ -115,10 +121,16 @@ public Bundle(string rootPath, ILogger? logger = null)
115121
/// </summary>
116122
private void EnsureWritable()
117123
{
124+
Logger.LogDebug("Checking if bundle is read-only");
125+
118126
if (IsReadOnly)
119127
{
120-
throw new InvalidOperationException("Bundle is read-only");
128+
Logger.LogError("Bundle is read-only");
129+
130+
throw new InvalidOperationException("Bundle is read-only"); ;
121131
}
132+
133+
Logger.LogDebug("Bundle is writable");
122134
}
123135

124136
/// <summary>
@@ -178,6 +190,8 @@ public void LoadFromBytes(byte[] bundleContent)
178190
throw new InvalidOperationException("The bundle is already loaded");
179191
}
180192

193+
Ensure.Collection.HasItems(bundleContent, nameof(bundleContent));
194+
181195
IsReadOnly = true;
182196
_rawZipContents = bundleContent;
183197

@@ -231,6 +245,13 @@ public void AddEntry(string path, string destinationPath = "./", string? rootPat
231245
{
232246
EnsureWritable();
233247

248+
Ensure.String.IsNotNullOrEmpty(path.Trim(), nameof(path));
249+
250+
if (!File.Exists(path))
251+
{
252+
throw new FileNotFoundException("File not found", path);
253+
}
254+
234255
Logger.LogInformation("Adding file: {path}", path);
235256

236257
if (!destinationPath.EndsWith('/'))
@@ -267,10 +288,12 @@ public void Sign(X509Certificate2 certificate, RSA privateKey)
267288
{
268289
EnsureWritable();
269290

291+
Ensure.Any.IsNotNull(certificate, nameof(certificate));
292+
Ensure.Any.IsNotNull(privateKey, nameof(privateKey));
293+
270294
Logger.LogInformation("Signing bundle with certificate: {name}", certificate.Subject);
271295

272-
var manifestData = Export(Manifest, SourceGenerationManifestContext.Default);
273-
var signature = privateKey.SignData(manifestData, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
296+
Logger.LogDebug("Exporting certificate");
274297
var cert = Convert.ToBase64String(certificate.Export(X509ContentType.Cert));
275298
var name = certificate.GetCertHashString();
276299

@@ -280,6 +303,10 @@ public void Sign(X509Certificate2 certificate, RSA privateKey)
280303
pemBuilder.AppendLine("-----END CERTIFICATE-----");
281304
string pemContents = pemBuilder.ToString();
282305

306+
Logger.LogDebug("Signing manifest");
307+
var manifestData = Export(Manifest, SourceGenerationManifestContext.Default);
308+
var signature = privateKey.SignData(manifestData, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
309+
283310
Logger.LogDebug("Embedding file: {name} in the bundle", name);
284311
_newEmbeddedFiles[name] = Encoding.UTF8.GetBytes(pemContents);
285312

@@ -294,6 +321,8 @@ public void Sign(X509Certificate2 certificate, RSA privateKey)
294321
/// <returns>True if the file is valid; otherwise, false.</returns>
295322
public bool VerifyFileIntegrity(string entryName)
296323
{
324+
Ensure.String.IsNotNullOrEmpty(entryName.Trim(), nameof(entryName));
325+
297326
Logger.LogInformation("Verifying file integrity: {name}", entryName);
298327

299328
byte[] hash;
@@ -328,15 +357,16 @@ public bool VerifyFileIntegrity(string entryName)
328357
/// <returns>True if the signature is valid; otherwise, false.</returns>
329358
public bool VerifySignature(string certificateHash)
330359
{
360+
Ensure.String.IsNotNullOrEmpty(certificateHash.Trim(), nameof(certificateHash));
361+
byte[] hash = Signatures.Entries[certificateHash];
362+
331363
X509Certificate2 certificate = GetCertificate(certificateHash);
332-
var pubKey = certificate.GetRSAPublicKey();
364+
var pubKey = certificate.GetRSAPublicKey() ?? throw new CryptographicException("Public key not found");
333365

334366
Logger.LogInformation("Verifying signature with certificate: {name}", certificate.Subject);
335367

336-
if (pubKey == null) return false;
337-
338368
var manifestData = Export(Manifest, SourceGenerationManifestContext.Default);
339-
bool result = pubKey.VerifyData(manifestData, Signatures.Entries[certificateHash], HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
369+
bool result = pubKey.VerifyData(manifestData, hash, HashAlgorithmName.SHA512, RSASignaturePadding.Pkcs1);
340370

341371
Logger.LogInformation("Signature verification result for certificate {name}: {result}", certificate.Subject, result);
342372

@@ -352,6 +382,8 @@ public bool VerifySignature(string certificateHash)
352382
/// <returns>True if the certificate is valid; otherwise, false.</returns>
353383
public bool VerifyCertificate(string certificateHash, out X509ChainStatus[] statuses, X509ChainPolicy? policy = null)
354384
{
385+
Ensure.String.IsNotNullOrEmpty(certificateHash.Trim(), nameof(certificateHash));
386+
355387
X509Certificate2 certificate = GetCertificate(certificateHash);
356388
return VerifyCertificate(certificate, out statuses, policy);
357389
}
@@ -376,6 +408,8 @@ public bool VerifyCertificate(string certificateHash, X509ChainPolicy? policy =
376408
/// <returns>True if the certificate is valid; otherwise, false.</returns>
377409
public bool VerifyCertificate(X509Certificate2 certificate, out X509ChainStatus[] statuses, X509ChainPolicy? policy = null)
378410
{
411+
Ensure.Any.IsNotNull(certificate, nameof(certificate));
412+
379413
X509Chain chain = new X509Chain
380414
{
381415
ChainPolicy = policy ?? new X509ChainPolicy()
@@ -414,6 +448,8 @@ public bool VerifyCertificate(X509Certificate2 certificate, X509ChainPolicy? pol
414448
/// <returns>The certificate.</returns>
415449
public X509Certificate2 GetCertificate(string certificateHash)
416450
{
451+
Ensure.String.IsNotNullOrEmpty(certificateHash.Trim(), nameof(certificateHash));
452+
417453
Logger.LogInformation("Getting certificate with hash: {hash}", certificateHash);
418454

419455
if (!_certCache.TryGetValue(certificateHash, out X509Certificate2? certificate))
@@ -435,7 +471,7 @@ public X509Certificate2 GetCertificate(string certificateHash)
435471
Logger.LogDebug("Certificate with hash {hash} found in cache", certificateHash);
436472
}
437473

438-
return certificate;
474+
return certificate;
439475
}
440476

441477
/// <summary>
@@ -445,6 +481,8 @@ public X509Certificate2 GetCertificate(string certificateHash)
445481
/// <returns>A stream for the file.</returns>
446482
public Stream GetFileStream(string entryName)
447483
{
484+
Ensure.String.IsNotNullOrEmpty(entryName.Trim(), nameof(entryName));
485+
448486
Logger.LogInformation("Getting file stream for entry: {name}", entryName);
449487

450488
if (Manifest.StoreOriginalFiles)
@@ -471,6 +509,8 @@ public Stream GetFileStream(string entryName)
471509
/// <returns>The bytes of the file.</returns>
472510
public byte[] GetFileBytes(string entryName)
473511
{
512+
Ensure.String.IsNotNullOrEmpty(entryName.Trim(), nameof(entryName));
513+
474514
Logger.LogInformation("Getting file data for entry: {name}", entryName);
475515

476516
if (Manifest.StoreOriginalFiles)
@@ -497,6 +537,9 @@ public byte[] GetFileBytes(string entryName)
497537
/// <returns>A byte array containing the exported data.</returns>
498538
protected byte[] Export(object structuredData, JsonSerializerContext jsonSerializerContext)
499539
{
540+
Ensure.Any.IsNotNull(structuredData, nameof(structuredData));
541+
Ensure.Any.IsNotNull(jsonSerializerContext, nameof(jsonSerializerContext));
542+
500543
Logger.LogInformation("Exporting data from a {type} object as byte array", structuredData.GetType().Name);
501544

502545
var data = JsonSerializer.Serialize(structuredData, structuredData.GetType(), jsonSerializerContext);
@@ -516,6 +559,8 @@ protected byte[] Export(object structuredData, JsonSerializerContext jsonSeriali
516559
#endif
517560
protected byte[] Export(object structuredData)
518561
{
562+
Ensure.Any.IsNotNull(structuredData, nameof(structuredData));
563+
519564
Logger.LogInformation("Exporting data from a {type} object as byte array", structuredData.GetType().Name);
520565

521566
var data = JsonSerializer.Serialize(structuredData, SerializerOptions);
@@ -560,6 +605,9 @@ public void Update()
560605
/// <returns>A byte array containing the entry data.</returns>
561606
protected byte[] ReadEntry(ZipArchive zip, string entryName)
562607
{
608+
Ensure.Any.IsNotNull(zip, nameof(zip));
609+
Ensure.String.IsNotNullOrEmpty(entryName.Trim(), nameof(entryName));
610+
563611
if (!_fileCache.TryGetValue(entryName, out var data))
564612
{
565613
Logger.LogDebug("Entry {name} not found in cache", entryName);
@@ -589,6 +637,8 @@ protected byte[] ReadEntry(ZipArchive zip, string entryName)
589637
/// <returns>A byte array containing the stream data.</returns>
590638
private static byte[] ReadStream(Stream stream)
591639
{
640+
Ensure.Any.IsNotNull(stream, nameof(stream));
641+
592642
MemoryStream ms = new();
593643
stream.CopyTo(ms);
594644
return ms.ToArray();
@@ -603,6 +653,10 @@ private static byte[] ReadStream(Stream stream)
603653
/// <param name="data">The data to write.</param>
604654
protected void WriteEntry(ZipArchive zip, string entryName, byte[] data)
605655
{
656+
Ensure.Any.IsNotNull(zip, nameof(zip));
657+
Ensure.String.IsNotNullOrEmpty(entryName.Trim(), nameof(entryName));
658+
Ensure.Collection.HasItems(data, nameof(data));
659+
606660
Logger.LogDebug("Writing entry: {name} to the bundle", entryName);
607661

608662
ZipArchiveEntry? tempEntry;
@@ -635,6 +689,8 @@ protected void WriteEntry(ZipArchive zip, string entryName, byte[] data)
635689
/// <returns>A byte array containing the hash.</returns>
636690
static byte[] ComputeSHA512Hash(Stream stream)
637691
{
692+
Ensure.Any.IsNotNull(stream, nameof(stream));
693+
638694
using var sha512 = SHA512.Create();
639695
return sha512.ComputeHash(stream);
640696
}
@@ -646,6 +702,8 @@ static byte[] ComputeSHA512Hash(Stream stream)
646702
/// <returns>A byte array containing the hash.</returns>
647703
static byte[] ComputeSHA512Hash(byte[] data)
648704
{
705+
Ensure.Collection.HasItems(data, nameof(data));
706+
649707
using var sha512 = SHA512.Create();
650708
return sha512.ComputeHash(data);
651709
}

src/EasySign/EasySign.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
</ItemGroup>
2424

2525
<ItemGroup>
26+
<PackageReference Include="Ensure.That" Version="10.1.0" />
2627
<PackageReference Include="Microsoft.Extensions.Logging" Version="8.0.1" />
2728
</ItemGroup>
2829

src/EasySign/packages.lock.json

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@
88
"resolved": "1.2.25",
99
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
1010
},
11+
"Ensure.That": {
12+
"type": "Direct",
13+
"requested": "[10.1.0, )",
14+
"resolved": "10.1.0",
15+
"contentHash": "rzTMSs0lQnu0WsesvTjs/zDzqiZXb9r5dv+wFQcPg/iIZqXb5BzwpIWEwi8Q3HA0TS4ytRcY129aSek6IzuOmA=="
16+
},
1117
"Microsoft.Extensions.Logging": {
1218
"type": "Direct",
1319
"requested": "[8.0.1, )",
@@ -184,6 +190,12 @@
184190
"resolved": "1.2.25",
185191
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
186192
},
193+
"Ensure.That": {
194+
"type": "Direct",
195+
"requested": "[10.1.0, )",
196+
"resolved": "10.1.0",
197+
"contentHash": "rzTMSs0lQnu0WsesvTjs/zDzqiZXb9r5dv+wFQcPg/iIZqXb5BzwpIWEwi8Q3HA0TS4ytRcY129aSek6IzuOmA=="
198+
},
187199
"Microsoft.Extensions.Logging": {
188200
"type": "Direct",
189201
"requested": "[8.0.1, )",
@@ -281,6 +293,12 @@
281293
"resolved": "1.2.25",
282294
"contentHash": "xCXiw7BCxHJ8pF6wPepRUddlh2dlQlbr81gXA72hdk4FLHkKXas7EH/n+fk5UCA/YfMqG1Z6XaPiUjDbUNBUzg=="
283295
},
296+
"Ensure.That": {
297+
"type": "Direct",
298+
"requested": "[10.1.0, )",
299+
"resolved": "10.1.0",
300+
"contentHash": "rzTMSs0lQnu0WsesvTjs/zDzqiZXb9r5dv+wFQcPg/iIZqXb5BzwpIWEwi8Q3HA0TS4ytRcY129aSek6IzuOmA=="
301+
},
284302
"Microsoft.Extensions.Logging": {
285303
"type": "Direct",
286304
"requested": "[9.0.3, )",

0 commit comments

Comments
 (0)