filtering (cert-store)
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
11
certmgr/Certificates/Filters/ByIssuerFilter.cs
Normal file
11
certmgr/Certificates/Filters/ByIssuerFilter.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using CertMgr.Core.Filters;
|
||||||
|
|
||||||
|
namespace CertMgr.Certificates.Filters;
|
||||||
|
|
||||||
|
internal sealed class ByIssuerFilter : CertificateFilter
|
||||||
|
{
|
||||||
|
public ByIssuerFilter(string pattern, FilteringFlags flags)
|
||||||
|
: base(pattern, flags, cert => cert.Issuer)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
11
certmgr/Certificates/Filters/BySubjectFilter.cs
Normal file
11
certmgr/Certificates/Filters/BySubjectFilter.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using CertMgr.Core.Filters;
|
||||||
|
|
||||||
|
namespace CertMgr.Certificates.Filters;
|
||||||
|
|
||||||
|
internal sealed class BySubjectFilter : CertificateFilter
|
||||||
|
{
|
||||||
|
public BySubjectFilter(string pattern, FilteringFlags flags)
|
||||||
|
: base(pattern, flags, cert => cert.Subject)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,21 +1,11 @@
|
|||||||
using System.Diagnostics;
|
using CertMgr.Core.Filters;
|
||||||
using System.Security.Cryptography.X509Certificates;
|
|
||||||
|
|
||||||
namespace CertMgr.Certificates.Filters;
|
namespace CertMgr.Certificates.Filters;
|
||||||
|
|
||||||
internal sealed class ByThumbprintFilter : CertificateFilter
|
internal sealed class ByThumbprintFilter : CertificateFilter
|
||||||
{
|
{
|
||||||
internal ByThumbprintFilter(string thumbprint)
|
public ByThumbprintFilter(string pattern, FilteringFlags flags)
|
||||||
: base(CertificateFilterType.Thumbprint)
|
: base(pattern, flags, cert => cert.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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,17 +5,51 @@ using CertMgr.Core.Filters;
|
|||||||
|
|
||||||
namespace CertMgr.Certificates.Filters;
|
namespace CertMgr.Certificates.Filters;
|
||||||
|
|
||||||
public abstract class CertificateFilter : Filter<X509Certificate2>
|
internal abstract class CertificateFilter : Filter<X509Certificate2>
|
||||||
{
|
{
|
||||||
internal CertificateFilter(CertificateFilterType type)
|
protected CertificateFilter(string pattern, FilteringFlags flags, Func<X509Certificate2, string> propertyGetter)
|
||||||
{
|
{
|
||||||
Type = type;
|
Pattern = pattern;
|
||||||
|
PropertyGetter = propertyGetter;
|
||||||
|
|
||||||
|
Worker = GetWorker(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
public CertificateFilterType Type { [DebuggerStepThrough] get; }
|
private string Pattern { [DebuggerStepThrough] get; }
|
||||||
|
|
||||||
public override string ToString()
|
private Func<X509Certificate2, string> PropertyGetter { [DebuggerStepThrough] get; }
|
||||||
|
|
||||||
|
private IFilter<string> Worker { [DebuggerStepThrough] get; }
|
||||||
|
|
||||||
|
protected sealed override async Task<bool> DoIsMatchAsync(X509Certificate2 value, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
return string.Format("type = {0}", Type);
|
string property = PropertyGetter(value);
|
||||||
|
bool result = await Worker.IsMatchAsync(property, cancellationToken).ConfigureAwait(false);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IFilter<string> GetWorker(FilteringFlags flags)
|
||||||
|
{
|
||||||
|
IFilter<string> worker;
|
||||||
|
|
||||||
|
if (flags.HasFlag(FilteringFlags.Exact))
|
||||||
|
{
|
||||||
|
worker = Core.Filters.KnownFilters.String.ExactMatch(Pattern, flags.HasFlag(FilteringFlags.CaseSensitive));
|
||||||
|
}
|
||||||
|
else if (flags.HasFlag(FilteringFlags.Wildcard))
|
||||||
|
{
|
||||||
|
worker = Core.Filters.KnownFilters.String.Wildcard(Pattern, flags.HasFlag(FilteringFlags.CaseSensitive));
|
||||||
|
}
|
||||||
|
else if (flags.HasFlag(FilteringFlags.Regex))
|
||||||
|
{
|
||||||
|
worker = Core.Filters.KnownFilters.String.Regex(Pattern, flags.HasFlag(FilteringFlags.CaseSensitive));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// default search is 'Exact'
|
||||||
|
worker = Core.Filters.KnownFilters.String.ExactMatch(Pattern, flags.HasFlag(FilteringFlags.CaseSensitive));
|
||||||
|
}
|
||||||
|
|
||||||
|
return worker;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,5 +2,7 @@
|
|||||||
|
|
||||||
public enum CertificateFilterType
|
public enum CertificateFilterType
|
||||||
{
|
{
|
||||||
Thumbprint = 1
|
Thumbprint = 1,
|
||||||
|
Subject,
|
||||||
|
Issuer
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,9 +8,19 @@ public static class KnownFilters
|
|||||||
{
|
{
|
||||||
public static class Certificate
|
public static class Certificate
|
||||||
{
|
{
|
||||||
public static IFilter<X509Certificate2> ByThumbprint(string thumbprint)
|
public static IFilter<X509Certificate2> ByThumbprint(string thumbprint, FilteringFlags flags)
|
||||||
{
|
{
|
||||||
return new ByThumbprintFilter(thumbprint);
|
return new ByThumbprintFilter(thumbprint, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IFilter<X509Certificate2> BySubject(string subjectName, FilteringFlags flags)
|
||||||
|
{
|
||||||
|
return new BySubjectFilter(subjectName, flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IFilter<X509Certificate2> ByIssuer(string issuerName, FilteringFlags flags)
|
||||||
|
{
|
||||||
|
return new ByIssuerFilter(issuerName, flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,11 @@ public abstract class Filter<T> : IFilter<T>
|
|||||||
|
|
||||||
protected abstract Task<bool> DoIsMatchAsync(T value, CancellationToken cancellationToken);
|
protected abstract Task<bool> DoIsMatchAsync(T value, CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("type = {0}", GetType().ToString(false));
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class EmptyFilter : Filter<T>
|
private sealed class EmptyFilter : Filter<T>
|
||||||
{
|
{
|
||||||
internal EmptyFilter(bool result)
|
internal EmptyFilter(bool result)
|
||||||
|
|||||||
13
certmgr/Core/Filters/FilteringFlags.cs
Normal file
13
certmgr/Core/Filters/FilteringFlags.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
namespace CertMgr.Core.Filters;
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum FilteringFlags
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
|
||||||
|
CaseSensitive = 1 << 1,
|
||||||
|
|
||||||
|
Exact = 1 << 3,
|
||||||
|
Wildcard = 1 << 4,
|
||||||
|
Regex = 1 << 5,
|
||||||
|
}
|
||||||
29
certmgr/Core/Filters/Impl/ExactMatchStringFilter.cs
Normal file
29
certmgr/Core/Filters/Impl/ExactMatchStringFilter.cs
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
|
||||||
|
using CertMgr.Core.Utils;
|
||||||
|
|
||||||
|
namespace CertMgr.Core.Filters.Impl;
|
||||||
|
|
||||||
|
internal sealed class ExactMatchStringFilter : Filter<string>
|
||||||
|
{
|
||||||
|
internal ExactMatchStringFilter(string pattern, bool caseSensitive)
|
||||||
|
{
|
||||||
|
Pattern = pattern;
|
||||||
|
CaseSensitive = caseSensitive;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string Pattern { [DebuggerStepThrough] get; }
|
||||||
|
|
||||||
|
private bool CaseSensitive { [DebuggerStepThrough] get; }
|
||||||
|
|
||||||
|
protected override Task<bool> DoIsMatchAsync(string value, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
bool ismatch = string.Equals(Pattern, value, CaseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase);
|
||||||
|
return Task.FromResult(ismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("type = {0}, pattern = '{1}', case-sensitive = {2}", GetType().ToString(false), Pattern, CaseSensitive ? "yes" : "no");
|
||||||
|
}
|
||||||
|
}
|
||||||
27
certmgr/Core/Filters/Impl/RegexStringFilter.cs
Normal file
27
certmgr/Core/Filters/Impl/RegexStringFilter.cs
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
using CertMgr.Core.Utils;
|
||||||
|
|
||||||
|
namespace CertMgr.Core.Filters.Impl;
|
||||||
|
|
||||||
|
internal sealed class RegexStringFilter : Filter<string>
|
||||||
|
{
|
||||||
|
internal RegexStringFilter(string regexPattern, bool caseSensitive)
|
||||||
|
{
|
||||||
|
Regex = new Regex(regexPattern, caseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Regex Regex { [DebuggerStepThrough] get; }
|
||||||
|
|
||||||
|
protected override Task<bool> DoIsMatchAsync(string value, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
bool ismatch = Regex.IsMatch(value);
|
||||||
|
return Task.FromResult(ismatch);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return string.Format("type = {0}, pattern = '{1}', case-sensitive = {2}", GetType().ToString(false), Regex, Regex.Options.HasFlag(RegexOptions.IgnoreCase) ? "no" : "yes");
|
||||||
|
}
|
||||||
|
}
|
||||||
21
certmgr/Core/Filters/Impl/WildcardStringFilter.cs
Normal file
21
certmgr/Core/Filters/Impl/WildcardStringFilter.cs
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace CertMgr.Core.Filters.Impl;
|
||||||
|
|
||||||
|
internal sealed class WildcardStringFilter : Filter<string>
|
||||||
|
{
|
||||||
|
internal WildcardStringFilter(string pattern, bool caseSensitive)
|
||||||
|
{
|
||||||
|
string regexPattern = "^" + Regex.Escape(pattern).Replace("\\?", ".").Replace("\\*", ".*") + "$";
|
||||||
|
Regex = new Regex(regexPattern, caseSensitive ? RegexOptions.None : RegexOptions.IgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Regex Regex { [DebuggerStepThrough] get; }
|
||||||
|
|
||||||
|
protected override Task<bool> DoIsMatchAsync(string value, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
bool ismatch = Regex.IsMatch(value);
|
||||||
|
return Task.FromResult(ismatch);
|
||||||
|
}
|
||||||
|
}
|
||||||
24
certmgr/Core/Filters/KnownFilters.cs
Normal file
24
certmgr/Core/Filters/KnownFilters.cs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
using CertMgr.Core.Filters.Impl;
|
||||||
|
|
||||||
|
namespace CertMgr.Core.Filters;
|
||||||
|
|
||||||
|
public static class KnownFilters
|
||||||
|
{
|
||||||
|
public static class String
|
||||||
|
{
|
||||||
|
public static IFilter<string> ExactMatch(string pattern, bool caseSensitive)
|
||||||
|
{
|
||||||
|
return new ExactMatchStringFilter(pattern, caseSensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IFilter<string> Wildcard(string pattern, bool caseSensitive)
|
||||||
|
{
|
||||||
|
return new WildcardStringFilter(pattern, caseSensitive);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IFilter<string> Regex(string pattern, bool caseSensitive)
|
||||||
|
{
|
||||||
|
return new RegexStringFilter(pattern, caseSensitive);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
8
certmgr/Core/Filters/StringFilterType.cs
Normal file
8
certmgr/Core/Filters/StringFilterType.cs
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
namespace CertMgr.Core.Filters;
|
||||||
|
|
||||||
|
public enum StringFilterType
|
||||||
|
{
|
||||||
|
ExactMatch = 1,
|
||||||
|
Wildcard,
|
||||||
|
Regex
|
||||||
|
}
|
||||||
@@ -26,12 +26,34 @@ internal sealed class CertificateFilterConverter : ValueConverter<IFilter<X509Ce
|
|||||||
ReadOnlySpan<char> filterTypeSpan = span.Slice(0, separatorIndex);
|
ReadOnlySpan<char> filterTypeSpan = span.Slice(0, separatorIndex);
|
||||||
if (Enum.TryParse(filterTypeSpan, true, out CertificateFilterType filterType) && Enum.IsDefined(filterType))
|
if (Enum.TryParse(filterTypeSpan, true, out CertificateFilterType filterType) && Enum.IsDefined(filterType))
|
||||||
{
|
{
|
||||||
ReadOnlySpan<char> nameSpan = span.Slice(separatorIndex + 1, span.Length - separatorIndex - 1);
|
ReadOnlySpan<char> valueSpan = span.Slice(separatorIndex + 1, span.Length - separatorIndex - 1);
|
||||||
string value = nameSpan.ToString();
|
separatorIndex = valueSpan.IndexOf(':');
|
||||||
|
|
||||||
|
string pattern;
|
||||||
|
FilteringFlags flags;
|
||||||
|
|
||||||
|
if (separatorIndex == -1)
|
||||||
|
{
|
||||||
|
pattern = valueSpan.ToString();
|
||||||
|
flags = FilteringFlags.Exact;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> flagsSpan = valueSpan.Slice(0, separatorIndex);
|
||||||
|
flags = GetFilteringFlags(flagsSpan);
|
||||||
|
pattern = valueSpan.Slice(separatorIndex + 1).ToString();
|
||||||
|
}
|
||||||
|
|
||||||
switch (filterType)
|
switch (filterType)
|
||||||
{
|
{
|
||||||
case CertificateFilterType.Thumbprint:
|
case CertificateFilterType.Thumbprint:
|
||||||
filter = KnownFilters.Certificate.ByThumbprint(value);
|
filter = Certificates.Filters.KnownFilters.Certificate.ByThumbprint(pattern, flags);
|
||||||
|
break;
|
||||||
|
case CertificateFilterType.Subject:
|
||||||
|
filter = Certificates.Filters.KnownFilters.Certificate.BySubject(pattern, flags);
|
||||||
|
break;
|
||||||
|
case CertificateFilterType.Issuer:
|
||||||
|
filter = Certificates.Filters.KnownFilters.Certificate.ByIssuer(pattern, flags);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -39,7 +61,7 @@ internal sealed class CertificateFilterConverter : ValueConverter<IFilter<X509Ce
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
CLog.Error("Failed to parse filter type from value '{0}'. (available values: {1})", rawValue, Enum.GetNames<CertificateFilterType>().ToSeparatedList());
|
CLog.Error("Failed to parse filter type from value '{0}'. (available values = {1})", rawValue, Enum.GetNames<CertificateFilterType>().ToSeparatedList());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -49,4 +71,21 @@ internal sealed class CertificateFilterConverter : ValueConverter<IFilter<X509Ce
|
|||||||
|
|
||||||
return Task.FromResult(filter);
|
return Task.FromResult(filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private FilteringFlags GetFilteringFlags(ReadOnlySpan<char> flagsSpan)
|
||||||
|
{
|
||||||
|
FilteringFlags flags = FilteringFlags.None;
|
||||||
|
|
||||||
|
MemoryExtensions.SpanSplitEnumerator<char> enu = flagsSpan.Split(',');
|
||||||
|
while (enu.MoveNext())
|
||||||
|
{
|
||||||
|
ReadOnlySpan<char> currentFlag = flagsSpan[enu.Current].Trim();
|
||||||
|
if (Enum.TryParse(currentFlag, true, out FilteringFlags tmp) && Enum.IsDefined(tmp))
|
||||||
|
{
|
||||||
|
flags |= tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public sealed class GetCertificateInfoJob : Job<GetCertificateInfoSettings>
|
|||||||
|
|
||||||
protected override async Task<JobResult> DoExecuteAsync(CancellationToken cancellationToken)
|
protected override async Task<JobResult> DoExecuteAsync(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
X509Certificate2? cert = null;
|
List<X509Certificate2> certs = new List<X509Certificate2>();
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(Settings.File))
|
if (!string.IsNullOrEmpty(Settings.File))
|
||||||
{
|
{
|
||||||
@@ -22,7 +22,8 @@ public sealed class GetCertificateInfoJob : Job<GetCertificateInfoSettings>
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
cert = X509CertificateLoader.LoadPkcs12FromFile(Settings.File, Settings.Password);
|
X509Certificate2 cert = X509CertificateLoader.LoadPkcs12FromFile(Settings.File, Settings.Password);
|
||||||
|
certs.Add(cert);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -39,8 +40,8 @@ public sealed class GetCertificateInfoJob : Job<GetCertificateInfoSettings>
|
|||||||
if (Settings.Filter != null)
|
if (Settings.Filter != null)
|
||||||
{
|
{
|
||||||
CertStoreSearcher searcher = new CertStoreSearcher(Settings.Store);
|
CertStoreSearcher searcher = new CertStoreSearcher(Settings.Store);
|
||||||
IReadOnlyList<X509Certificate2> certs = await searcher.SearchAsync(Settings.Filter, cancellationToken).ConfigureAwait(false);
|
IReadOnlyList<X509Certificate2> searchResult = await searcher.SearchAsync(Settings.Filter, cancellationToken).ConfigureAwait(false);
|
||||||
cert = certs.FirstOrDefault();
|
certs.AddRange(searchResult);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -52,42 +53,48 @@ public sealed class GetCertificateInfoJob : Job<GetCertificateInfoSettings>
|
|||||||
CLog.Error("Either file or cert-store must be specified when requesting info on certificate");
|
CLog.Error("Either file or cert-store must be specified when requesting info on certificate");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cert != null)
|
if (certs.Count > 0)
|
||||||
{
|
{
|
||||||
using (StringBuilderCache.ScopedBuilder lease = StringBuilderCache.AcquireScoped(256))
|
using (StringBuilderCache.ScopedBuilder lease = StringBuilderCache.AcquireScoped(512 * certs.Count))
|
||||||
{
|
{
|
||||||
int padSize = 24;
|
|
||||||
StringBuilder sb = lease.Builder;
|
StringBuilder sb = lease.Builder;
|
||||||
sb.AppendLine();
|
|
||||||
AppendWithPadding(sb, "Subject", cert.Subject.StartsWith("CN=") ? cert.Subject.Substring(3) : cert.Subject, padSize);
|
foreach (X509Certificate2 cert in certs)
|
||||||
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);
|
int padSize = 24;
|
||||||
}
|
sb.AppendLine();
|
||||||
foreach (X509Extension ext in cert.Extensions)
|
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);
|
||||||
string[] values = ext.Format(true).TrimEnd(Environment.NewLine.ToCharArray()).Split(Environment.NewLine);
|
AppendWithPadding(sb, "Not Before", cert.NotBefore.ToString("s"), padSize);
|
||||||
if ((values.Length > 1 && !string.IsNullOrEmpty(values[values.Length - 1])) || values.Length > 2)
|
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, ext.Oid?.FriendlyName ?? ext.Oid?.Value, string.Empty, padSize);
|
AppendWithPadding(sb, "FriendlyName", cert.FriendlyName, padSize);
|
||||||
foreach (string value in values)
|
}
|
||||||
|
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)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(value))
|
AppendWithPadding(sb, ext.Oid?.FriendlyName ?? ext.Oid?.Value, string.Empty, padSize);
|
||||||
|
foreach (string value in values)
|
||||||
{
|
{
|
||||||
continue;
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
sb.AppendFormatLine(" - {0}", value);
|
||||||
}
|
}
|
||||||
sb.AppendFormatLine(" - {0}", value);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
AppendWithPadding(sb, ext.Oid?.FriendlyName ?? ext.Oid?.Value, values[0], padSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
sb.Append("----------------------------------------------------------------");
|
||||||
AppendWithPadding(sb, ext.Oid?.FriendlyName ?? ext.Oid?.Value, values[0], padSize);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return CreateSuccess(sb.ToString());
|
return CreateSuccess(sb.ToString());
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ internal static class Program
|
|||||||
args = [
|
args = [
|
||||||
"--job=get-certificate-info",
|
"--job=get-certificate-info",
|
||||||
"--cert-store=user/my",
|
"--cert-store=user/my",
|
||||||
"--filter=thumbprint:b395149b6079553eea92d9a73ffc97463e8976ff"
|
"--filter=thumbprint:regex:b39.+"
|
||||||
];
|
];
|
||||||
|
|
||||||
// args = [
|
// args = [
|
||||||
|
|||||||
Reference in New Issue
Block a user