new job get-certificate-info

This commit is contained in:
2025-11-02 18:32:52 +01:00
parent 85c0354d2a
commit fbe64afd41
50 changed files with 445 additions and 127 deletions

View File

@@ -1,4 +1,4 @@
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public class CertGenException : Exception
{

View File

@@ -1,4 +1,4 @@
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public enum CertificateAlgorithm
{

View File

@@ -5,7 +5,7 @@ using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Exceptions;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
internal abstract class CertificateGeneratorBase<TAlgorithm, TSettings> : ICertificateGenerator
where TAlgorithm : AsymmetricAlgorithm

View File

@@ -2,7 +2,7 @@
using CertMgr.Core.Exceptions;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public sealed class CertificateManager
{

View File

@@ -4,7 +4,7 @@ using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Utils;
using CertMgr.Core.Validation;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public sealed class CertificateSettings
{

View File

@@ -3,7 +3,7 @@ using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Exceptions;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
internal sealed class EcdsaCertificateGenerator : CertificateGeneratorBase<ECDsa, EcdsaGeneratorSettings>
{

View File

@@ -1,4 +1,4 @@
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public enum EcdsaCurve
{

View File

@@ -2,7 +2,7 @@
using CertMgr.Core.Exceptions;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public sealed class EcdsaGeneratorSettings : GeneratorSettings
{

View File

@@ -1,6 +1,6 @@
using System.Diagnostics;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public abstract class GeneratorSettings
{

View File

@@ -1,4 +1,4 @@
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public enum GeneratorType
{

View File

@@ -1,4 +1,4 @@
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public enum HashAlgorithm
{

View File

@@ -1,6 +1,6 @@
using System.Security.Cryptography.X509Certificates;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public interface ICertificateGenerator : IAsyncDisposable
{

View File

@@ -1,6 +1,6 @@
using System.Security.Cryptography.X509Certificates;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
[Flags]
public enum KeyUsage

View File

@@ -3,7 +3,7 @@ using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Exceptions;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
internal sealed class RsaCertificateGenerator : CertificateGeneratorBase<RSA, RsaGeneratorSettings>
{

View File

@@ -2,7 +2,7 @@
using CertMgr.Core.Exceptions;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public sealed class RsaGeneratorSettings : GeneratorSettings
{

View File

@@ -1,4 +1,4 @@
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public enum RsaKeySize
{

View File

@@ -1,4 +1,4 @@
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public enum SANKind
{

View File

@@ -1,6 +1,6 @@
using System.Diagnostics;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public sealed class SubjectAlternateName : IEquatable<SubjectAlternateName>
{

View File

@@ -3,7 +3,7 @@
using CertMgr.Core.Log;
using CertMgr.Core.Utils;
namespace CertMgr.CertGen;
namespace CertMgr.Certificates.CertGen;
public sealed class SubjectAlternateNames : IReadOnlyCollection<SubjectAlternateName>
{

View File

@@ -1,6 +1,6 @@
using CertMgr.Core.Utils;
namespace CertMgr.CertGen.Utils;
namespace CertMgr.Certificates.CertGen.Utils;
public sealed class CollectionEquivalencyComparer<T> : IEqualityComparer<IEnumerable<T>> where T : notnull
{

View File

@@ -4,7 +4,7 @@ using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Validation;
namespace CertMgr.CertGen.Utils;
namespace CertMgr.Certificates.CertGen.Utils;
public sealed class SubjectValidator : IValueValidator<string>
{

View File

@@ -0,0 +1,42 @@
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Filters;
using CertMgr.Jobs;
namespace CertMgr.Certificates;
public sealed class CertStoreSearcher
{
public CertStoreSearcher(CertStore store)
{
Store = store;
}
private CertStore Store { [DebuggerStepThrough] get; }
public async Task<IReadOnlyList<X509Certificate2>> SearchAsync(IFilter<X509Certificate2> filter, CancellationToken cancellationToken)
{
List<X509Certificate2> certificates = new List<X509Certificate2>();
using (X509Store store = new X509Store((StoreName)Store.Name, (StoreLocation)Store.Location))
{
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 cert in store.Certificates)
{
if (await filter.IsMatchAsync(cert, cancellationToken))
{
certificates.Add(cert);
}
}
}
return certificates;
}
public override string ToString()
{
return string.Format("store = {0}/{1}", Store.Location, Store.Name);
}
}

View File

@@ -0,0 +1,21 @@
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
namespace CertMgr.Certificates.Filters;
internal sealed class ByThumbprintFilter : CertificateFilter
{
internal ByThumbprintFilter(string thumbprint)
: base(CertificateFilterType.Thumbprint)
{
Thumbprint = thumbprint;
}
private string Thumbprint { [DebuggerStepThrough] get; }
protected override Task<bool> DoIsMatchAsync(X509Certificate2 value, CancellationToken cancellationToken)
{
bool result = string.Equals(value.Thumbprint, Thumbprint, StringComparison.OrdinalIgnoreCase);
return Task.FromResult(result);
}
}

View File

@@ -0,0 +1,21 @@
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Filters;
namespace CertMgr.Certificates.Filters;
public abstract class CertificateFilter : Filter<X509Certificate2>
{
internal CertificateFilter(CertificateFilterType type)
{
Type = type;
}
public CertificateFilterType Type { [DebuggerStepThrough] get; }
public override string ToString()
{
return string.Format("type = {0}", Type);
}
}

View File

@@ -0,0 +1,6 @@
namespace CertMgr.Certificates.Filters;
public enum CertificateFilterType
{
Thumbprint = 1
}

View File

@@ -0,0 +1,16 @@
using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Filters;
namespace CertMgr.Certificates.Filters;
public static class KnownFilters
{
public static class Certificate
{
public static IFilter<X509Certificate2> ByThumbprint(string thumbprint)
{
return new ByThumbprintFilter(thumbprint);
}
}
}

View File

@@ -1,4 +1,4 @@
using CertMgr.Core.Utils;
/*using CertMgr.Core.Utils;
namespace CertMgr.Core;
@@ -13,3 +13,4 @@ public class CertMgrException : Exception
{
}
}
*/

View File

@@ -1,6 +0,0 @@
namespace CertMgr.Core.Converters;
public class ConverterContext
{
public static readonly ConverterContext Empty = new ConverterContext();
}

View File

@@ -1,13 +0,0 @@
using System.Diagnostics;
namespace CertMgr.Core.Converters;
public class EnumConverterContext : ConverterContext
{
internal EnumConverterContext(Type targetType)
{
TargetType = targetType;
}
public Type TargetType { [DebuggerStepThrough] get; }
}

View File

@@ -4,38 +4,20 @@ namespace CertMgr.Core.Converters.Impl;
internal class StorageKindConverter : ValueConverter<IStorage>
{
// private const char Separator = '|';
protected override Task<IStorage?> DoConvertAsync(string rawValue, Type targetType, CancellationToken cancellationToken)
{
ReadOnlySpan<char> storageTypeSpan = rawValue.AsSpan();
// int storageTypeSplitIndex = rawSpan.IndexOf(Separator);
// if (storageTypeSplitIndex == -1)
// {
// return Task.FromResult((IStorage?)EmptyStorage.Empty);
// }
IStorage? storage;
// ReadOnlySpan<char> storageTypeSpan = rawSpan.Slice(0, storageTypeSplitIndex);
// ReadOnlySpan<char> storageDefinition = rawSpan.Slice(storageTypeSplitIndex + 1);
switch (storageTypeSpan)
{
case "file":
storage = new FileStorage();
// if (!TryGetFileStore(storageDefinition, out storage))
// {
// storage = EmptyStorage.Empty;
// }
break;
case "certstore":
case "cert-store":
storage = new CertStoreStorage();
//if (!TryGetCertStore(storageDefinition, out storage))
//{
// storage = EmptyStorage.Empty;
//}
break;
default:
storage = EmptyStorage.Empty;

View File

@@ -2,7 +2,7 @@
using CertMgr.Core.Utils;
namespace CertMgr.Core.Storage;
namespace CertMgr.Core.Filters;
public abstract class Filter<T> : IFilter<T>
{

View File

@@ -1,4 +1,4 @@
namespace CertMgr.Core.Storage;
namespace CertMgr.Core.Filters;
public interface IFilter<T>
{

View File

@@ -45,6 +45,10 @@ internal sealed class JobExecutor
errorLevel = result.ErrorLevel;
CLog.Info("Executing job '{0}'... done (finished with error-level {1}, took {2})", job.Name, errorLevel, sw.Elapsed);
if (!string.IsNullOrEmpty(result.Message))
{
CLog.Info(result.Message);
}
}
catch (Exception e)
{

View File

@@ -1,6 +1,7 @@
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Filters;
using CertMgr.Core.Utils;
namespace CertMgr.Core.Storage;

View File

@@ -1,27 +0,0 @@
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
namespace CertMgr.Core.Storage;
public static class CertificateFilter
{
private abstract class CertFilter : Filter<X509Certificate2>
{
}
private sealed class ByThumbprintFilter : CertFilter
{
public ByThumbprintFilter(string thumbprint)
{
Thumbprint = thumbprint;
}
public string Thumbprint { [DebuggerStepThrough] get; }
protected override Task<bool> DoIsMatchAsync(X509Certificate2 value, CancellationToken cancellationToken)
{
bool result = string.Equals(value.Thumbprint, Thumbprint, StringComparison.OrdinalIgnoreCase);
return Task.FromResult(result);
}
}
}

View File

@@ -1,6 +1,7 @@
namespace CertMgr.Core.Storage;
/*namespace CertMgr.Core.Storage;
public enum StorageType
{
File = 1
}
*/

View File

@@ -25,7 +25,7 @@ internal static class Extenders
{ typeof(object), "object" },
};
public static string ToSeparatedList<T>(this IEnumerable<T> items, Func<T, string> formatter, string itemSeparator, string? lastItemSeparator = null)
public static string ToSeparatedList<T>(this IEnumerable<T> items, Func<T, string?>? formatter = null, string? itemSeparator = ",", string? lastItemSeparator = null)
{
using StringBuilderCache.ScopedBuilder lease = StringBuilderCache.AcquireScoped();
StringBuilder sb = lease.Builder;
@@ -35,7 +35,7 @@ internal static class Extenders
return sb.ToString();
}
public static void ToSeparatedList<T>(this IEnumerable<T> items, StringBuilder sb, Func<T, string> formatter, string itemSeparator, string? lastItemSeparator = null)
public static void ToSeparatedList<T>(this IEnumerable<T> items, StringBuilder sb, Func<T, string?>? formatter, string? itemSeparator = null, string? lastItemSeparator = null)
{
if (!items.Any())
{
@@ -245,4 +245,9 @@ internal static class Extenders
return isOneOf;
}
public static void AppendFormatLine(this StringBuilder sb, string format, params object[] args)
{
sb.AppendFormat(format, args);
sb.AppendLine();
}
}

23
certmgr/Jobs/CertStore.cs Normal file
View File

@@ -0,0 +1,23 @@
using System.Diagnostics;
using CertMgr.Core.Storage;
namespace CertMgr.Jobs;
public sealed class CertStore
{
public CertStore(CertStoreLocation location, CertStoreName name)
{
Location = location;
Name = name;
}
public CertStoreLocation Location { [DebuggerStepThrough] get; }
public CertStoreName Name { [DebuggerStepThrough] get; }
public override string ToString()
{
return string.Format("{0}/{1}", Location, Name);
}
}

View File

@@ -0,0 +1,48 @@
using CertMgr.Core.Converters;
using CertMgr.Core.Log;
using CertMgr.Core.Storage;
using CertMgr.Core.Utils;
namespace CertMgr.Jobs;
internal sealed class CertStoreConverter : ValueConverter<CertStore>
{
protected override Task<CertStore?> DoConvertAsync(string rawValue, Type targetType, CancellationToken cancellationToken)
{
CertStore? store = null;
if (string.IsNullOrEmpty(rawValue))
{
return Task.FromResult(store);
}
ReadOnlySpan<char> span = rawValue.AsSpan();
int separatorIndex = span.IndexOf('/');
if (separatorIndex > -1 && separatorIndex < span.Length - 1)
{
ReadOnlySpan<char> locationSpan = span.Slice(0, separatorIndex);
if (Enum.TryParse(locationSpan, true, out CertStoreLocation location) && Enum.IsDefined(location))
{
ReadOnlySpan<char> nameSpan = span.Slice(separatorIndex + 1, span.Length - separatorIndex - 1);
if (Enum.TryParse(nameSpan, true, out CertStoreName name) && Enum.IsDefined(name))
{
store = new CertStore(location, name);
}
else
{
CLog.Error("Failed to parse cert-store name from value '{0}'. Value '{1}' is not valid name (available values: {2})", rawValue, nameSpan.ToString(), Enum.GetNames<CertStoreName>().ToSeparatedList());
}
}
else
{
CLog.Error("Failed to parse cert-store location from value '{0}'. Value '{1}' is not valid location (available values: {2})", rawValue, locationSpan.ToString(), Enum.GetNames<CertStoreLocation>().ToSeparatedList());
}
}
else
{
CLog.Error("Cannot parse cert-store from value '{0}'. Value must be '<location>/<name>'", rawValue);
}
return Task.FromResult(store);
}
}

View File

@@ -0,0 +1,52 @@
using System.Security.Cryptography.X509Certificates;
using CertMgr.Certificates.Filters;
using CertMgr.Core.Converters;
using CertMgr.Core.Filters;
using CertMgr.Core.Log;
using CertMgr.Core.Utils;
namespace CertMgr.Jobs;
internal sealed class CertificateFilterConverter : ValueConverter<IFilter<X509Certificate2>>
{
protected override Task<IFilter<X509Certificate2>?> DoConvertAsync(string rawValue, Type targetType, CancellationToken cancellationToken)
{
IFilter<X509Certificate2>? filter = null;
if (string.IsNullOrEmpty(rawValue))
{
return Task.FromResult(filter);
}
ReadOnlySpan<char> span = rawValue.AsSpan();
int separatorIndex = span.IndexOf(':');
if (separatorIndex > -1 && separatorIndex < span.Length - 1)
{
ReadOnlySpan<char> filterTypeSpan = span.Slice(0, separatorIndex);
if (Enum.TryParse(filterTypeSpan, true, out CertificateFilterType filterType) && Enum.IsDefined(filterType))
{
ReadOnlySpan<char> nameSpan = span.Slice(separatorIndex + 1, span.Length - separatorIndex - 1);
string value = nameSpan.ToString();
switch (filterType)
{
case CertificateFilterType.Thumbprint:
filter = KnownFilters.Certificate.ByThumbprint(value);
break;
default:
break;
}
}
else
{
CLog.Error("Failed to parse filter type from value '{0}'. (available values: {1})", rawValue, Enum.GetNames<CertificateFilterType>().ToSeparatedList());
}
}
else
{
CLog.Error("Cannot parse filter from value '{0}'. Value must be '<filter-type>:<filtering-value>'", rawValue);
}
return Task.FromResult(filter);
}
}

View File

@@ -1,6 +1,6 @@
using System.Security.Cryptography.X509Certificates;
using CertMgr.CertGen;
using CertMgr.Certificates.CertGen;
using CertMgr.Core.Exceptions;
using CertMgr.Core.Jobs;
using CertMgr.Core.Log;
@@ -9,17 +9,17 @@ using CertMgr.Core.Utils;
namespace CertMgr.Jobs;
public sealed class CreateCertificateJob : Job<CertificateSettings>
public sealed class CreateCertificateJob : Job<CreateCertificateSettings>
{
public const string ID = "create-certificate";
protected override async Task<JobResult> DoExecuteAsync(CancellationToken cancellationToken)
{
CertificateSettings cs = Settings;
CreateCertificateSettings cs = Settings;
CLog.Info("creating certificate using settings: subject = '{0}', algorithm = '{1}', curve = '{2}'", cs.Subject, cs.Algorithm?.ToString() ?? "<null>", cs.Curve);
GeneratorSettings gs = CreateGeneratorSettings();
CertGen.CertificateSettings cgcs = await CreateCertificateSettingsAsync(cancellationToken).ConfigureAwait(false);
CertificateSettings cgcs = await CreateCertificateSettingsAsync(cancellationToken).ConfigureAwait(false);
CertificateManager cm = new CertificateManager();
using (X509Certificate2 cert = await cm.CreateAsync(cgcs, gs, cancellationToken).ConfigureAwait(false))
@@ -65,11 +65,11 @@ public sealed class CreateCertificateJob : Job<CertificateSettings>
return gs;
}
private async Task<CertGen.CertificateSettings> CreateCertificateSettingsAsync(CancellationToken cancellationToken)
private async Task<CertificateSettings> CreateCertificateSettingsAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
CertGen.CertificateSettings cgcs = new CertGen.CertificateSettings();
CertificateSettings cgcs = new CertificateSettings();
cgcs.SubjectName = Settings.Subject;
cgcs.ValidityPeriod = Settings.ValidityPeriod.HasValue ? Settings.ValidityPeriod.Value : TimeSpan.FromDays(365);

View File

@@ -1,7 +1,7 @@
using System.Diagnostics;
using CertMgr.CertGen;
using CertMgr.CertGen.Utils;
using CertMgr.Certificates.CertGen;
using CertMgr.Certificates.CertGen.Utils;
using CertMgr.Core.Attributes;
using CertMgr.Core.Converters.Impl;
using CertMgr.Core.Jobs;
@@ -11,13 +11,13 @@ using CertMgr.Core.Validation;
namespace CertMgr.Jobs;
public sealed class CertificateSettings : JobSettings
public sealed class CreateCertificateSettings : JobSettings
{
public CertificateSettings()
public CreateCertificateSettings()
{
Algorithm = CertificateAlgorithm.ECDsa;
Curve = EcdsaCurve.P384;
HashAlgorithm = CertGen.HashAlgorithm.Sha384;
HashAlgorithm = Certificates.CertGen.HashAlgorithm.Sha384;
ValidityPeriod = TimeSpan.FromDays(365);
}
@@ -35,7 +35,7 @@ public sealed class CertificateSettings : JobSettings
[Setting("friendly-name")]
public string? FriendlyName { [DebuggerStepThrough] get; [DebuggerStepThrough] set; }
[Setting("key-usage", Default = CertGen.KeyUsage.None, Converter = typeof(EnumConverter))]
[Setting("key-usage", Default = Certificates.CertGen.KeyUsage.None, Converter = typeof(EnumConverter))]
public KeyUsage? KeyUsage { [DebuggerStepThrough] get; [DebuggerStepThrough] set; }
[Setting("algorithm", Default = CertificateAlgorithm.ECDsa, Converter = typeof(EnumConverter))]

View File

@@ -0,0 +1,107 @@
using System.Security.Cryptography.X509Certificates;
using System.Text;
using CertMgr.Certificates;
using CertMgr.Core.Jobs;
using CertMgr.Core.Log;
using CertMgr.Core.Utils;
namespace CertMgr.Jobs;
public sealed class GetCertificateInfoJob : Job<GetCertificateInfoSettings>
{
public const string ID = "get-certificate-info";
protected override async Task<JobResult> DoExecuteAsync(CancellationToken cancellationToken)
{
X509Certificate2? cert = null;
if (!string.IsNullOrEmpty(Settings.File))
{
if (File.Exists(Settings.File))
{
try
{
cert = X509CertificateLoader.LoadPkcs12FromFile(Settings.File, Settings.Password);
}
catch (Exception e)
{
throw new Exception(string.Format("Failed to load certificate from file '{0}'", Settings.File), e);
}
}
else
{
CLog.Error("File doesn't exist: '{0}'", Settings.File);
}
}
else if (Settings.Store != null)
{
if (Settings.Filter != null)
{
CertStoreSearcher searcher = new CertStoreSearcher(Settings.Store);
IReadOnlyList<X509Certificate2> certs = await searcher.SearchAsync(Settings.Filter, cancellationToken).ConfigureAwait(false);
cert = certs.FirstOrDefault();
}
else
{
CLog.Error("Filter must be specified when info on certificate from cert-store is requested");
}
}
else
{
CLog.Error("Either file or cert-store must be specified when requesting info on certificate");
}
if (cert != null)
{
using (StringBuilderCache.ScopedBuilder lease = StringBuilderCache.AcquireScoped(256))
{
int padSize = 24;
StringBuilder sb = lease.Builder;
sb.AppendLine();
AppendWithPadding(sb, "Subject", cert.Subject.StartsWith("CN=") ? cert.Subject.Substring(3) : cert.Subject, padSize);
AppendWithPadding(sb, "Issuer", cert.Issuer.StartsWith("CN=") ? cert.Issuer.Substring(3) : cert.Issuer, padSize);
AppendWithPadding(sb, "Not Before", cert.NotBefore.ToString("s"), padSize);
AppendWithPadding(sb, "Not After", cert.NotAfter.ToString("s"), padSize);
AppendWithPadding(sb, "Signature Algorithm", cert.SignatureAlgorithm.FriendlyName, padSize);
AppendWithPadding(sb, "Thumbprint", cert.Thumbprint, padSize);
if (!string.IsNullOrEmpty(cert.FriendlyName))
{
AppendWithPadding(sb, "FriendlyName", cert.FriendlyName, padSize);
}
foreach (X509Extension ext in cert.Extensions)
{
string[] values = ext.Format(true).TrimEnd(Environment.NewLine.ToCharArray()).Split(Environment.NewLine);
if ((values.Length > 1 && !string.IsNullOrEmpty(values[values.Length - 1])) || values.Length > 2)
{
AppendWithPadding(sb, ext.Oid?.FriendlyName ?? ext.Oid?.Value, string.Empty, padSize);
foreach (string value in values)
{
if (string.IsNullOrEmpty(value))
{
continue;
}
sb.AppendFormatLine(" - {0}", value);
}
}
else
{
AppendWithPadding(sb, ext.Oid?.FriendlyName ?? ext.Oid?.Value, values[0], padSize);
}
}
return CreateSuccess(sb.ToString());
}
}
else
{
return CreateFailure("No certificate");
}
}
private static void AppendWithPadding(StringBuilder sb, string name, string value, int padSize)
{
string padStr = padSize >= name.Length ? new string(' ', padSize - name.Length) : string.Empty;
sb.AppendFormatLine("{0}{1}: {2}", name, padStr, value);
}
}

View File

@@ -0,0 +1,23 @@
using System.Diagnostics;
using System.Security.Cryptography.X509Certificates;
using CertMgr.Core.Attributes;
using CertMgr.Core.Filters;
using CertMgr.Core.Jobs;
namespace CertMgr.Jobs;
public sealed class GetCertificateInfoSettings : JobSettings
{
[Setting("file")]
public string? File { [DebuggerStepThrough] get; [DebuggerStepThrough] set; }
[Setting("cert-store", Converter = typeof(CertStoreConverter))]
public CertStore? Store { [DebuggerStepThrough] get; [DebuggerStepThrough] set; }
[Setting("filter", Converter = typeof(CertificateFilterConverter))]
public IFilter<X509Certificate2>? Filter { [DebuggerStepThrough] get; [DebuggerStepThrough] set; }
[Setting("password", IsSecret = true)]
public string? Password { [DebuggerStepThrough] get; [DebuggerStepThrough] set; }
}

View File

@@ -1,4 +1,4 @@
using CertMgr.CertGen;
using CertMgr.Certificates.CertGen;
using CertMgr.Core.Converters;
namespace CertMgr.Jobs;

View File

@@ -6,30 +6,41 @@ internal static class Program
{
private static async Task<int> Main(string[] args)
{
// args = [
// "--job=get-certificate-info",
// "--file=c:\\mycert-ecdsa.pfx",
// "--password="
// ];
args = [
"--job=create-certificate",
"--issuer-kind=file",
"--issuer-file=o|c:\\friend2.pfx",
"--issuer-password=aaa",
"--subject=CN=hello",
"--san=world",
"--san=DNS:zdrastvujte",
"--san=IP:192.168.131.1",
"--algorithm=ecdsa",
"--ecdsa-curve=p384",
"--validity-period=2d",
"--job=get-certificate-info",
"--cert-store=user/my",
"--filter=thumbprint:b395149b6079553eea92d9a73ffc97463e8976ff"
];
// "--certificate-target=file|w|c:\\mycert-ecdsa.pfx",
// "--certificate-password=aaa",
// "--target-kind=file",
// "--target-file=w|c:\\mycert-ecdsa.pfx",
// "--target-password=aaa",
"--target-kind=certstore",
"--target-certstore=machine|my|exportable",
"--target-password=aaa"
];
// args = [
// "--job=create-certificate",
// "--issuer-kind=file",
// "--issuer-file=o|c:\\friend2.pfx",
// "--issuer-password=aaa",
// "--subject=CN=hello",
// "--san=world",
// "--san=DNS:zdrastvujte",
// "--san=IP:192.168.131.1",
// "--algorithm=ecdsa",
// "--ecdsa-curve=p384",
// "--validity-period=2d",
//
// // "--certificate-target=file|w|c:\\mycert-ecdsa.pfx",
// // "--certificate-password=aaa",
//
// // "--target-kind=file",
// // "--target-file=w|c:\\mycert-ecdsa.pfx",
// // "--target-password=aaa",
//
// "--target-kind=certstore",
// "--target-certstore=machine|my|exportable",
// "--target-password=aaa"
// ];
// --certificate-target=certstore|machine|my

View File

@@ -1,4 +1,4 @@
using CertMgr.CertGen.Utils;
using CertMgr.Certificates.CertGen.Utils;
using CertMgr.Core.Validation;
using NUnit.Framework;