The Certificate Templates console shows you a tidy, tabbed version of a template. Underneath, a template is just an Active Directory object with a few dozen attributes, and most of the real configuration lives in bitmask integers that the console quietly translates for you. When you are auditing a PKI, scripting template creation, or working out why an issued certificate came out wrong, you end up reading those raw attributes directly.
This is a reference for what each attribute means, written for people who already know what a certificate template is and want to read one without the GUI in the way.
You can dump a template two ways. certutil -dsTemplate <TemplateName> gives you the human-decoded view used throughout this article. Or you can read the object straight out of LDAP under CN=Certificate Templates,CN=Public Key Services,CN=Services,CN=Configuration,DC=..., which is what tools (and attackers enumerating ESC paths) actually do. The full list of attributes and their flag tables is documented by Microsoft in the MS-CRTD specification.
The matrix
The Editable column means: is this a property you legitimately configure to define the template (true), or is it AD/system metadata you should not hand-edit (false). A few are not clean booleans and are footnoted.
| Attribute | Editable | Purpose |
|---|---|---|
objectClass | false | Marks the object as top + pKICertificateTemplate. |
cn | false¹ | Internal template name (no spaces). The object's identity. |
name | false¹ | Mirrors cn. |
displayName | true | Friendly name shown in the console. |
distinguishedName | false | Derived from cn and the object's location. |
instanceType | false | AD object instance type. System. |
whenCreated / whenChanged | false | Create and last-modify timestamps. System. |
uSNCreated / uSNChanged | false | Replication sequence numbers. System. |
showInAdvancedViewOnly | true | Hides the object from default ADUC views. |
nTSecurityDescriptor | true | The ACL: who can Read, Enroll, Autoenroll, and Write. |
objectGUID | false | Immutable object identifier. |
objectCategory | false | Schema class pointer. |
revision | false² | Major version. Auto-incremented on edit. |
msPKI-Template-Minor-Revision | false² | Minor version. Auto-incremented on edit. |
msPKI-Template-Schema-Version | true³ | Template generation, 1 through 4. |
flags | true | Legacy general-enrollment flags. |
pKIDefaultKeySpec | true | Legacy CAPI key spec: 1 = key exchange, 2 = signature. |
pKIKeyUsage | true | Key Usage extension bits stamped into issued certs. |
pKIMaxIssuingDepth | true | Path length constraint for CA templates. |
pKICriticalExtensions | true | OIDs marked critical in issued certs. |
pKIExpirationPeriod | true | Validity period of issued certs. |
pKIOverlapPeriod | true | Renewal window before expiry. |
pKIExtendedKeyUsage | true | EKU OIDs. |
pKIDefaultCSPs | true | Ordered list of cryptographic providers. |
dSCorePropagationData | false | Replication metadata. System. |
msPKI-RA-Signature | true | Number of registration-authority signatures required. |
msPKI-Enrollment-Flag | true | Enrollment behaviour bitmask. |
msPKI-Private-Key-Flag | true | Private-key handling plus min CA/client OS gates. |
msPKI-Certificate-Name-Flag | true | Subject and SAN sourcing. |
msPKI-Minimal-Key-Size | true | Minimum key size. |
msPKI-Cert-Template-OID | false | Immutable OID identifying this template. |
msPKI-Certificate-Application-Policy | true | Application Policy OIDs (V2+ EKU equivalent). |
cnandnameare set once at creation and are effectively immutable. Renaming a template means creating a new object.revisionand the minor revision are system-maintained and auto-increment when you edit a template. You can write them through ADSI, and admins sometimes bump them deliberately to force autoenrollment re-issue, but they are not normal configuration knobs.msPKI-Template-Schema-Versionis writable but not free-form. It is tied to the compatibility settings, and those also live inmsPKI-Private-Key-Flag. More on that below.
The metadata you don't touch
The first dozen rows are Active Directory plumbing. objectClass, objectCategory, instanceType, objectGUID, the timestamps, and the USN counters are all set and maintained by AD. distinguishedName is derived from where the object lives. cn and name are the template's internal identity and do not change in place.
displayName and showInAdvancedViewOnly are the two metadata-adjacent attributes you do edit: one is the friendly name in the console, the other controls whether the object appears in the default ADUC view.
msPKI-Cert-Template-OID deserves one note. It is the unique OID that identifies the template, assigned at creation and never changed. If you duplicate a template, the copy gets its own OID. Issued certificates carry this OID in the Certificate Template Information extension, which is how a CA and a relying party know which template produced a given cert.
The two sets of flags that look identical
This is the single most common source of confusion when reading a template, so it is worth being explicit.
There are two unrelated bitmask attributes that both use CT_FLAG_ constant names, and some of those names appear in both with the same value. They are different attributes governing different things.
The legacy flags attribute is the general-enrollment flags attribute. It carries broad template characteristics, several of which the system sets for you based on template type and EKUs. The bits you will actually see here include CT_FLAG_MACHINE_TYPE (0x40, this is a computer template), CT_FLAG_IS_CA (0x80, this is a CA template), CT_FLAG_PUBLISH_TO_DS (0x8), CT_FLAG_EXPORTABLE_KEY (0x10), CT_FLAG_ADD_TEMPLATE_NAME (0x200), and CT_FLAG_AUTO_ENROLLMENT (0x20).
The msPKI-Enrollment-Flag attribute is the V2-and-later enrollment flags. This is the one that holds the modern enrollment controls. The bits worth knowing:
CT_FLAG_PEND_ALL_REQUESTS(0x2) turns on CA certificate manager approval. Every request lands in the pending queue.CT_FLAG_PUBLISH_TO_DS(0x8) writes the issued cert to the user object'suserCertificateattribute.CT_FLAG_AUTO_ENROLLMENT(0x20) enables autoenrollment for the template.CT_FLAG_ADD_OCSP_NOCHECK(0x400) stamps the ocsp-nocheck extension, used on OCSP responder signing certs.CT_FLAG_NO_SECURITY_EXTENSION(0x20000) suppresses the SID security extension. This one has teeth, covered below.
So flags = "131642" and msPKI-Enrollment-Flag = "33" are two separate integers decoded against two separate tables. Seeing CT_FLAG_AUTO_ENROLLMENT in both is not a duplicate, it is two different attributes that happen to share a name.
The SID extension flag is the one to audit
CT_FLAG_NO_SECURITY_EXTENSION (0x20000 in msPKI-Enrollment-Flag) tells the CA not to add the szOID_NTDS_CA_SECURITY_EXT extension (OID 1.3.6.1.4.1.311.25.2) to issued certificates. That extension carries the requester's account SID and is what makes a certificate strongly mapped.
Since KB5014754, domain controllers moving to Full Enforcement reject certificate-based logons that lack a strong mapping. If this flag is set on an authentication template while your KDCs are enforcing, those certificates fail to authenticate. The flag exists for legitimate reasons (some non-AD relying parties choke on the unknown extension), but on a domain-auth template it is a finding. Check it before any enforcement deadline, not after.
Private key handling, and where the 2012-versus-2016 question actually lives
msPKI-Private-Key-Flag does two jobs in one integer. The low bits control how the private key is handled. The high bits encode the minimum CA and client operating system, which is what the console's Compatibility tab is really reading and writing. Microsoft documents the flag table in MS-CRTD and the AD schema entry in Win32.
The low bits you will see:
CT_FLAG_REQUIRE_PRIVATE_KEY_ARCHIVAL(0x1) sends the private key to the CA for key recovery.CT_FLAG_EXPORTABLE_KEY(0x10) lets the key be exported to a PFX later. On an authentication template this weakens the assumption that the key stays on the device, so it is worth a second look.CT_FLAG_STRONG_KEY_PROTECTION_REQUIRED(0x20) prompts or requires user protection on the key.CT_FLAG_USE_LEGACY_PROVIDER(0x100) forces CAPI/CSP processing instead of CNG/KSP. You set this deliberately when a KSP path is causing trouble, for example certain HSM or NDES scenarios.- The attestation bits (
CT_FLAG_ATTEST_NONE,_PREFERRED,_REQUIRED) govern TPM key attestation.
The high bits are the part people miss. Per MS-WCCE, the value AND 0x000F0000 is the minimum CA version, and the value AND 0x0F000000 is the minimum client version. Those two nibbles are the Compatibility tab.
Here is the practical consequence. Schema version 4 is the ceiling. Microsoft never shipped a schema 5, so Server 2012, 2012 R2, 2016, 2019, and 2022 all report msPKI-Template-Schema-Version = 4. The schema number alone cannot tell 2012 from 2016 apart. The distinction is entirely in these version nibbles:
0x40000/0x4000000= Windows 8 / Server 20120x50000/0x5000000= Windows 8.1 / Server 2012 R20x60000/0x6000000= Windows 10 / Server 2016
So if you create a template programmatically, set schema 4, and leave the nibbles at the 2012 default, the console will correctly report "Server 2012" and never move to 2016. To raise it you have to rewrite those nibbles in msPKI-Private-Key-Flag. They are multi-bit fields, so you clear the nibble first, then set the new value. Do not just OR the new bits in or you will corrupt the field:
# raise CA version to Server 2016 (Threshold)
$pkf = $pkf -band (-bnot 0x000F0000)
$pkf = $pkf -bor 0x00060000
# raise client version to Windows 10 / Server 2016
$pkf = $pkf -band (-bnot 0x0F000000)
$pkf = $pkf -bor 0x06000000
One caution: raising the client floor drops any older OS off the template silently. Set it because you mean to, not by reflex.
Subject and SAN sourcing
msPKI-Certificate-Name-Flag decides where the subject and Subject Alternative Name come from, and it is the attribute that decides whether a template is dangerous. The full flag table is in MS-CRTD.
The two modes:
CT_FLAG_ENROLLEE_SUPPLIES_SUBJECT(0x1) lets the requester name themselves. The CA takes the subject and SAN from the request.- The
SUBJECT_REQUIRE_*andSUBJECT_ALT_REQUIRE_*bits build the subject and SAN from the requester's AD object instead. For exampleCT_FLAG_SUBJECT_ALT_REQUIRE_UPN(0x2000000) adds the UPN,CT_FLAG_SUBJECT_REQUIRE_COMMON_NAME(0x40000000) sets the CN from AD.
An enrollee-supplies-subject template that also issues an authentication EKU and allows broad enrollment is the classic ESC1 shape: a low-privileged requester names themselves as someone else and gets an auth cert for that identity. When you read this attribute, the question is always whether the subject is built from AD or supplied by the requester.
Cryptography and issuance properties
The remaining attributes are the straightforward ones.
pKIDefaultKeySpec is the legacy CAPI key spec: 1 is key exchange (sign and encrypt), 2 is signature only. It is meaningful for CSP-based templates and inert under CNG.
pKIKeyUsage holds the Key Usage extension bits as an octet string. a0 00 is Digital Signature plus Key Encipherment. pKICriticalExtensions lists the OIDs marked critical, usually Key Usage (2.5.29.15).
pKIExtendedKeyUsage and msPKI-Certificate-Application-Policy both carry purpose OIDs. EKU is the V1-style list, Application Policy is the V2-and-later equivalent. On modern templates they usually match. Client Authentication is 1.3.6.1.5.5.7.3.2, Server Authentication is .3.1.
pKIDefaultCSPs is the ordered list of cryptographic providers offered at enrollment, CSP or KSP. msPKI-Minimal-Key-Size is the floor, commonly 2048 for RSA.
pKIExpirationPeriod and pKIOverlapPeriod are the validity period and the renewal window, stored as binary time deltas that certutil decodes for you into values like "1 Years" and "6 Weeks."
pKIMaxIssuingDepth is the path length constraint, and it only matters on CA templates. It sets how many further CA levels can sit below a CA issued from this template. On an end-entity template it is inert.
msPKI-RA-Signature is the count of registration-authority (enrollment-agent) signatures a request must carry before the CA will issue. Zero means none required.
Who can use the template
nTSecurityDescriptor is the ACL, and it is the other half of an ESC1-style finding. Enroll and Autoenroll are extended rights granted to the principals listed here. The combination that matters is broad enrollment rights plus a permissive name flag plus an authentication EKU. A clean template grants Read to Authenticated Users and Enroll only to a specific group, never Enroll to Authenticated Users on a sensitive template.
When you read a template, read the security descriptor with it. The flags tell you what the certificate will be. The ACL tells you who can ask for one.
How to read one yourself
certutil -dsTemplate YourTemplateName > template.txt
The output lists every flag value in full, with set flags shown bare and unset flags shown in parentheses. That convention is easy to miss the first time: a long list of CT_FLAG_* names does not mean they are all on. Read the bare ones.
Everything above is governed by the public MS-CRTD specification, which is the authoritative reference when a decoded value does not match what the console shows you.
