Skip to content

Commit fb9b86c

Browse files
authored
fix: msPKI-RA-Application-Policies parsing (#88)
1 parent da92d29 commit fb9b86c

4 files changed

Lines changed: 61 additions & 3 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using System;
2+
3+
namespace SharpHoundCommonLib.Enums
4+
{
5+
// from https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/f6122d87-b999-4b92-bff8-f465e8949667
6+
[Flags]
7+
public enum PKIPrivateKeyFlag : uint
8+
{
9+
REQUIRE_PRIVATE_KEY_ARCHIVAL = 0x00000001,
10+
EXPORTABLE_KEY = 0x00000010,
11+
STRONG_KEY_PROTECTION_REQUIRED = 0x00000020,
12+
REQUIRE_ALTERNATE_SIGNATURE_ALGORITHM = 0x00000040,
13+
REQUIRE_SAME_KEY_RENEWAL = 0x00000080,
14+
USE_LEGACY_PROVIDER = 0x00000100,
15+
ATTEST_NONE = 0x00000000,
16+
ATTEST_REQUIRED = 0x00002000,
17+
ATTEST_PREFERRED = 0x00001000,
18+
ATTESTATION_WITHOUT_POLICY = 0x00004000,
19+
EK_TRUST_ON_USE = 0x00000200,
20+
EK_VALIDATE_CERT = 0x00000400,
21+
EK_VALIDATE_KEY = 0x00000800,
22+
HELLO_LOGON_KEY = 0x00200000
23+
}
24+
}

src/CommonLib/LDAPProperties.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ public static class LDAPProperties
5959
public const string PKINameFlag = "mspki-certificate-name-flag";
6060
public const string ExtendedKeyUsage = "pkiextendedkeyusage";
6161
public const string NumSignaturesRequired = "mspki-ra-signature";
62+
public const string PKIPrivateKeyFlag = "mspki-private-key-flag";
6263
public const string ApplicationPolicies = "mspki-ra-application-policies";
6364
public const string IssuancePolicies = "mspki-ra-policies";
6465
public const string CertificateApplicationPolicy = "mspki-certificate-application-policy";

src/CommonLib/LDAPQueries/CommonProperties.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ public static class CommonProperties
8484
LDAPProperties.PKIEnrollmentFlag, LDAPProperties.DisplayName, LDAPProperties.Name, LDAPProperties.TemplateSchemaVersion, LDAPProperties.CertTemplateOID,
8585
LDAPProperties.PKIOverlappedPeriod, LDAPProperties.PKIExpirationPeriod, LDAPProperties.ExtendedKeyUsage, LDAPProperties.NumSignaturesRequired,
8686
LDAPProperties.CertificateApplicationPolicy, LDAPProperties.IssuancePolicies, LDAPProperties.CrossCertificatePair,
87-
LDAPProperties.ApplicationPolicies
87+
LDAPProperties.ApplicationPolicies, LDAPProperties.PKIPrivateKeyFlag
8888
};
8989
}
9090
}

src/CommonLib/Processors/LDAPPropertyProcessor.cs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -514,9 +514,15 @@ public static Dictionary<string, object> ReadCertTemplateProperties(ISearchResul
514514
if (entry.GetIntProperty(LDAPProperties.NumSignaturesRequired, out var authorizedSignatures))
515515
props.Add("authorizedsignatures", authorizedSignatures);
516516

517-
props.Add("applicationpolicies", entry.GetArrayProperty(LDAPProperties.ApplicationPolicies));
518-
props.Add("issuancepolicies", entry.GetArrayProperty(LDAPProperties.IssuancePolicies));
517+
bool hasUseLegacyProvider = false;
518+
if (entry.GetIntProperty(LDAPProperties.PKIPrivateKeyFlag, out var privateKeyFlagsRaw))
519+
{
520+
var privateKeyFlags = (PKIPrivateKeyFlag)privateKeyFlagsRaw;
521+
hasUseLegacyProvider = privateKeyFlags.HasFlag(PKIPrivateKeyFlag.USE_LEGACY_PROVIDER);
522+
}
519523

524+
props.Add("applicationpolicies", ParseCertTemplateApplicationPolicies(entry.GetArrayProperty(LDAPProperties.ApplicationPolicies), schemaVersion, hasUseLegacyProvider));
525+
props.Add("issuancepolicies", entry.GetArrayProperty(LDAPProperties.IssuancePolicies));
520526

521527
// Construct effectiveekus
522528
string[] effectiveekus = schemaVersion == 1 & ekus.Length > 0 ? ekus : certificateapplicationpolicy;
@@ -578,6 +584,33 @@ public Dictionary<string, object> ParseAllProperties(ISearchResultEntry entry)
578584
return props;
579585
}
580586

587+
/// <summary>
588+
/// Parse CertTemplate attribute msPKI-RA-Application-Policies
589+
/// </summary>
590+
/// <param name="applicationPolicies"></param>
591+
/// <param name="schemaVersion"></param>
592+
/// <param name="hasUseLegacyProvider"></param>
593+
private static string[] ParseCertTemplateApplicationPolicies(string[] applicationPolicies, int schemaVersion, bool hasUseLegacyProvider)
594+
{
595+
if (applicationPolicies == null
596+
|| applicationPolicies.Length == 0
597+
|| schemaVersion == 1
598+
|| schemaVersion == 2
599+
|| (schemaVersion == 4 && hasUseLegacyProvider)) {
600+
return applicationPolicies;
601+
} else {
602+
// Format: "Name`Type`Value`Name`Type`Value`..."
603+
// (https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-crtd/c55ec697-be3f-4117-8316-8895e4399237)
604+
// Return the Value of Name = "msPKI-RA-Application-Policies" entries
605+
string[] entries = applicationPolicies[0].Split('`');
606+
return Enumerable.Range(0, entries.Length / 3)
607+
.Select(i => entries.Skip(i * 3).Take(3).ToArray())
608+
.Where(parts => parts.Length == 3 && parts[0].Equals(LDAPProperties.ApplicationPolicies, StringComparison.OrdinalIgnoreCase))
609+
.Select(parts => parts[2])
610+
.ToArray();
611+
}
612+
}
613+
581614
/// <summary>
582615
/// Does a best guess conversion of the property to a type useable by the UI
583616
/// </summary>

0 commit comments

Comments
 (0)