Skip to content

Commit

Permalink
enh: fix code analysis
Browse files Browse the repository at this point in the history
Signed-off-by: Sang Au <[email protected]>
  • Loading branch information
auvansang committed Oct 21, 2024
1 parent 256b4ec commit 11e4075
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 27 deletions.
3 changes: 2 additions & 1 deletion src/CertGen/CommandOptions/CreateEcdsaCommandOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.CommandLine;
using System.CommandLine.Binding;
using System.Diagnostics.CodeAnalysis;

namespace Sisa.Security;

Expand Down Expand Up @@ -27,7 +28,7 @@ public sealed class CreateEcdsaCommandOptionsBinder(
commonName
)
{
protected override CreateEcdsaCommandOptions GetBoundValue(BindingContext bindingContext) =>
protected override CreateEcdsaCommandOptions GetBoundValue([NotNull] BindingContext bindingContext) =>
base.GetBoundValue(bindingContext) with
{
NamedCurve = bindingContext.ParseResult.GetValueForOption(namedCurve)
Expand Down
4 changes: 3 additions & 1 deletion src/CertGen/CommandOptions/CreateRsaCommandOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.CommandLine;
using System.CommandLine.Binding;
using System.Diagnostics.CodeAnalysis;

namespace Sisa.Security;

Expand Down Expand Up @@ -27,7 +28,8 @@ public sealed class CreateRsaCommandOptionsBinder(
commonName
)
{
protected override CreateRsaCommandOptions GetBoundValue(BindingContext bindingContext) =>
protected override CreateRsaCommandOptions GetBoundValue([NotNull
] BindingContext bindingContext) =>
base.GetBoundValue(bindingContext) with
{
KeySize = bindingContext.ParseResult.GetValueForOption(keySize)
Expand Down
5 changes: 3 additions & 2 deletions src/CertGen/CommandOptions/GlobalOptions.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System.CommandLine;
using System.CommandLine.Binding;
using System.Diagnostics.CodeAnalysis;

namespace Sisa.Security;

Expand All @@ -9,7 +10,7 @@ public record GlobalOptions

public Algorithm Algorithm { get; set; }

public string[] DnsNames { get; set; } = [];
public IReadOnlyCollection<string> DnsNames { get; set; } = [];
public string? PfxPassword { get; set; }

public string? OrganizationName { get; set; }
Expand All @@ -31,7 +32,7 @@ public abstract class GlobalOptionsBinder<TOptions>(
) : BinderBase<TOptions>
where TOptions : GlobalOptions, new()
{
protected override TOptions GetBoundValue(BindingContext bindingContext) =>
protected override TOptions GetBoundValue([NotNull] BindingContext bindingContext) =>
new()
{
CertName = bindingContext.ParseResult.GetValueForOption(certName)!,
Expand Down
24 changes: 16 additions & 8 deletions src/CertGen/Handlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ namespace Sisa.Security.Handlers;

public static class CommandHandler
{
private static readonly string RootCAName = "root-ca";
private static readonly string RootCACommonName = "Sisa Development Root CA";
private static string RootCAName { get; } = "root-ca";
private static string RootCACommonName { get; } = "Sisa Development Root CA";

public static Command Initialize()
{
Expand Down Expand Up @@ -197,25 +197,29 @@ private static async Task CreateEcdsaCommandHandleAsync(CreateEcdsaCommandOption
Console.WriteLine("Root CA exists");
Console.WriteLine("Loading root CA certificate");

#pragma warning disable CA2000 // Dispose objects before losing scope
rootCa = GenerateSslHelper.LoadRootCACertificate(rootCaFilePath, rootCaKeyFilePath);
#pragma warning restore CA2000 // Dispose objects before losing scope

if (rootCa == null)
{
await Console.Error.WriteLineAsync("Failed to load root CA certificate");
await Console.Error.WriteLineAsync("Failed to load root CA certificate").ConfigureAwait(false);

return;
}
}
else
{
var caSubjectName = GenerateSslHelper.BuildSubjectName(options.OrganizationName!, options.OrganizationUnitName!, RootCACommonName);
#pragma warning disable CA2000 // Dispose objects before losing scope
rootCa = GenerateSslHelper.CreateEcdsaRootCACertificate(caSubjectName);
#pragma warning restore CA2000 // Dispose objects before losing scope
}

HashAlgorithmName hashAlgorithm = GenerateSslHelper.GetHashAlgorithm(options.Algorithm);

var certSubjectName = GenerateSslHelper.BuildSubjectName(options.OrganizationName!, options.OrganizationUnitName!, options.CommonName!);
var cert = GenerateSslHelper.CreateEcdsaSelfSignCertificate(
using var cert = GenerateSslHelper.CreateEcdsaSelfSignCertificate(
rootCa,
certSubjectName,
hashAlgorithm,
Expand Down Expand Up @@ -267,11 +271,13 @@ private static async Task CreateRsaCommandHandleAsync(CreateRsaCommandOptions op
Console.WriteLine("Root CA exists");
Console.WriteLine("Loading root CA certificate");

#pragma warning disable CA2000 // Dispose objects before losing scope
rootCa = GenerateSslHelper.LoadRootCACertificate(rootCaFilePath, rootCaKeyFilePath);
#pragma warning restore CA2000 // Dispose objects before losing scope

if (rootCa == null)
{
await Console.Error.WriteLineAsync("Failed to load root CA certificate");
await Console.Error.WriteLineAsync("Failed to load root CA certificate").ConfigureAwait(false);

return;
}
Expand All @@ -282,14 +288,16 @@ private static async Task CreateRsaCommandHandleAsync(CreateRsaCommandOptions op
Console.WriteLine("Creating root CA certificate");

var caSubjectName = GenerateSslHelper.BuildSubjectName(options.OrganizationName!, options.OrganizationUnitName!, RootCACommonName);
#pragma warning disable CA2000 // Dispose objects before losing scope
rootCa = GenerateSslHelper.CreateRsaRootCACertificate(caSubjectName);
#pragma warning restore CA2000 // Dispose objects before losing scope
}

HashAlgorithmName hashAlgorithm = GenerateSslHelper.GetHashAlgorithm(options.Algorithm);
var certSubjectName = GenerateSslHelper.BuildSubjectName(options.OrganizationName!, options.OrganizationUnitName!, options.CommonName!);

Console.WriteLine("Creating self-signed certificate");
var cert = GenerateSslHelper.CreateRsaSelfSignCertificate(
using var cert = GenerateSslHelper.CreateRsaSelfSignCertificate(
rootCa,
certSubjectName,
hashAlgorithm,
Expand All @@ -300,7 +308,7 @@ private static async Task CreateRsaCommandHandleAsync(CreateRsaCommandOptions op
ExportCertificateHelper.EnsureOutFolderExists();

var keyFileName = $"{options.CertName}-rsa-key.pem";
var certFileName = $"{options.CertName}-rsa-key.pem";
var certFileName = $"{options.CertName}-rsa-cert.pem";

List<Task> tasks = [];

Expand Down Expand Up @@ -330,6 +338,6 @@ private static async Task CreateRsaCommandHandleAsync(CreateRsaCommandOptions op
tasks.Add(ExportCertificateHelper.ExportPfxAsync(cert, pfxFilePath, options.PfxPassword));
}

await Task.WhenAll(tasks);
await Task.WhenAll(tasks).ConfigureAwait(false);
}
}
18 changes: 10 additions & 8 deletions src/CertGen/Helpers/ExportCertificateHelper.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography.X509Certificates;

namespace Sisa.Security.Helpers;

public static class ExportCertificateHelper
{
private static readonly string OutFolder = "gen";
private static string OutFolder { get; } = "gen";

public static async Task ExportPfxAsync(X509Certificate2 certificate, string filePath, string password)
public static async Task ExportPfxAsync([NotNull] X509Certificate2 certificate, string filePath, string password)
{
byte[] pfxBytes = certificate.Export(X509ContentType.Pfx, password);

Expand All @@ -15,28 +17,28 @@ public static async Task ExportPfxAsync(X509Certificate2 certificate, string fil
Console.WriteLine("Certificate exported to {0}.", filePath);
}

public static async Task ExportCertificatePemAsync(X509Certificate2 certificate, string filePath)
public static async Task ExportCertificatePemAsync([NotNull] X509Certificate2 certificate, string filePath)
{
await File.WriteAllTextAsync(filePath, certificate.ExportCertificatePem());

Console.WriteLine("Certificate exported to {0}.", filePath);
}

public static async Task ExportRsaPrivateKeyPemAsync(X509Certificate2 certificate, string filePath)
public static async Task ExportRsaPrivateKeyPemAsync([NotNull] X509Certificate2 certificate, string filePath)
{
await File.WriteAllTextAsync(filePath, certificate.GetRSAPrivateKey()!.ExportRSAPrivateKeyPem());

Console.WriteLine("RSA private key exported to {0}.", filePath);
}

public static async Task ExportRsaPublicKeyPemAsync(X509Certificate2 certificate, string filePath)
public static async Task ExportRsaPublicKeyPemAsync([NotNull] X509Certificate2 certificate, string filePath)
{
await File.WriteAllTextAsync(filePath, certificate.GetRSAPublicKey()!.ExportRSAPublicKeyPem());

Console.WriteLine("RSA public key exported to {0}.", filePath);
}

public static async Task ExportEcdsaPrivateKeyPemAsync(X509Certificate2 certificate, string filePath)
public static async Task ExportEcdsaPrivateKeyPemAsync([NotNull] X509Certificate2 certificate, string filePath)
{
await File.WriteAllTextAsync(filePath, certificate.GetECDsaPrivateKey()!.ExportECPrivateKeyPem());

Expand Down Expand Up @@ -66,7 +68,7 @@ public static void EnsureOutFolderExists()
}
}

public static string BuildExportFilePath(string fileName)
public static string BuildExportFilePath([NotNull] string fileName)
{
string currentDirectory = Environment.CurrentDirectory;

Expand All @@ -76,7 +78,7 @@ public static string BuildExportFilePath(string fileName)

while (File.Exists(filePath))
{
filePath = Path.Combine(currentDirectory, OutFolder, fileName.Replace(".", $"-{i}."));
filePath = Path.Combine(currentDirectory, OutFolder, fileName.Replace(".", $"-{i}.", StringComparison.OrdinalIgnoreCase));
i++;
}

Expand Down
15 changes: 9 additions & 6 deletions src/CertGen/Helpers/GenerateSslHelper.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Diagnostics.CodeAnalysis;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

Expand All @@ -13,8 +14,10 @@ public static class GenerateSslHelper

return cert;
}
catch
catch(CryptographicException ex)
{
Console.WriteLine(ex.Message);

return null;
}
}
Expand All @@ -35,7 +38,7 @@ public static X509Certificate2 CreateRsaRootCACertificate(string subjectName)
return CreateRootCACertificate(certificateRequest);
}

public static X509Certificate2 CreateEcdsaSelfSignCertificate(X509Certificate2 issuerCertificate, string subjectName, HashAlgorithmName hashAlgorithm, NamedCurve namedCurve, string[] dnsNames)
public static X509Certificate2 CreateEcdsaSelfSignCertificate(X509Certificate2 issuerCertificate, string subjectName, HashAlgorithmName hashAlgorithm, NamedCurve namedCurve, [NotNull] IReadOnlyCollection<string> dnsNames)
{
var curve = namedCurve switch
{
Expand All @@ -47,17 +50,17 @@ public static X509Certificate2 CreateEcdsaSelfSignCertificate(X509Certificate2 i
using ECDsa key = ECDsa.Create(curve);
CertificateRequest certificateRequest = new(subjectName, key, hashAlgorithm);

var signedCert = CreateSelfSignCertificate(issuerCertificate, certificateRequest, dnsNames);
using var signedCert = CreateSelfSignCertificate(issuerCertificate, certificateRequest, dnsNames);

return signedCert.CopyWithPrivateKey(key);
}

public static X509Certificate2 CreateRsaSelfSignCertificate(X509Certificate2 issuerCertificate, string subjectName, HashAlgorithmName hashAlgorithm, int keySize, string[] dnsNames)
public static X509Certificate2 CreateRsaSelfSignCertificate(X509Certificate2 issuerCertificate, string subjectName, HashAlgorithmName hashAlgorithm, int keySize, [NotNull] IReadOnlyCollection<string> dnsNames)
{
using RSA key = RSA.Create(keySize);
CertificateRequest certificateRequest = new(subjectName, key, hashAlgorithm, RSASignaturePadding.Pkcs1);

var signedCert = CreateSelfSignCertificate(issuerCertificate, certificateRequest, dnsNames);
using var signedCert = CreateSelfSignCertificate(issuerCertificate, certificateRequest, dnsNames);

return signedCert.CopyWithPrivateKey(key);
}
Expand Down Expand Up @@ -95,7 +98,7 @@ private static X509Certificate2 CreateRootCACertificate(CertificateRequest certi
return certificate;
}

private static X509Certificate2 CreateSelfSignCertificate(X509Certificate2 issuerCertificate, CertificateRequest certificateRequest, string[] dnsNames)
private static X509Certificate2 CreateSelfSignCertificate(X509Certificate2 issuerCertificate, CertificateRequest certificateRequest, IReadOnlyCollection<string> dnsNames)
{
DateTimeOffset currentDate = DateTimeOffset.UtcNow;

Expand Down
6 changes: 5 additions & 1 deletion src/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,12 @@
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<AnalysisMode>All</AnalysisMode>
<AnalysisLevel>latest</AnalysisLevel>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<NoWarn>$(NoWarn);NU5104</NoWarn>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<NoWarn>$(NoWarn);NU5104,CA2007,CA1303</NoWarn>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<UseArtifactsOutput>true</UseArtifactsOutput>
<ArtifactsPath>$(MSBuildThisFileDirectory)artifacts</ArtifactsPath>
Expand Down

0 comments on commit 11e4075

Please sign in to comment.