# Understanding the enumerate_templates Function in Doom: AD Certificate Template Discovery

> Discover Active Directory Certificate Templates with Doom's enumerate_templates function. This tool performs LDAP searches and parses attributes for security auditing.

- Repository: [000pp/doom](https://github.com/000pp/doom)
- Tags: deep-dive
- Published: 2026-02-22

---

**The `enumerate_templates` function in Doom performs targeted LDAP subtree searches to discover Active Directory Certificate Templates, parsing raw LDAP attributes into enriched, human-readable property dictionaries for security auditing.**

Active Directory Certificate Services (AD CS) exposes certificate templates via LDAP, but raw directory entries contain opaque flag values and binary attributes. The Doom open-source tool abstracts this complexity through the `enumerate_templates` function, which queries the directory, normalizes attribute values, and derives high-level security properties. This article examines the implementation in [`src/doom/modules/enumerate_templates.py`](https://github.com/000pp/doom/blob/main/src/doom/modules/enumerate_templates.py) and explains how the function transforms raw LDAP data into actionable intelligence.

## What Does the enumerate_templates Function Do?

The `enumerate_templates` function serves as the discovery engine for AD certificate templates. It executes a targeted LDAP search and processes the results into structured Python dictionaries.

The function begins by constructing the distinguished name (DN) for the Certificate Templates container, typically `CN=Certificate Templates,<base_dn>`. It then issues an LDAP subtree search for objects of class `pKICertificateTemplate` (lines 5-7 in [`src/doom/modules/enumerate_templates.py`](https://github.com/000pp/doom/blob/main/src/doom/modules/enumerate_templates.py)).

When the search returns entries, the function iterates through `ldap_connection.entries` and performs three critical transformations:

1. **Identity extraction** – Retrieves the template's `cn` (common name) and `displayName` using the `safe_ldap_attr` helper to handle missing attributes gracefully (lines 29-31).
2. **Attribute normalization** – Collects every LDAP attribute, preserving raw values while passing them through `parse_attribute` to convert binary or specialized formats into Python-native types (lines 34-38).
3. **Property derivation** – Invokes `analyze_template_properties` to decode low-level flag integers into boolean security properties like `Auto_Enrollment` or `Exportable_Key` (lines 39-42).

The final output is a list of dictionaries, each containing `name`, `display_name`, `dn`, `attributes`, and the original LDAP `entry` object for advanced use.

## Key Implementation Details in enumerate_templates

### LDAP Search Scope and Object Filtering

The function targets a specific container within Active Directory. It constructs the search base by appending to the provided `base_dn`:

```python

# Conceptual representation based on source lines 5-7

search_base = f"CN=Certificate Templates,{base_dn}"
search_filter = "(objectClass=pKICertificateTemplate)"

```

This ensures the query only returns certificate template objects, ignoring other directory entries.

### Safe Attribute Extraction with safe_ldap_attr

Working with LDAP entries requires handling potentially missing or malformed attributes. The function utilizes `safe_ldap_attr` from [`src/doom/protocols/ldap.py`](https://github.com/000pp/doom/blob/main/src/doom/protocols/ldap.py) to safely retrieve values:

```python

# Lines 29-31 reference

name = safe_ldap_attr(entry, 'cn')
display_name = safe_ldap_attr(entry, 'displayName')

```

This helper prevents `KeyError` exceptions when attributes are absent, returning `None` or empty strings instead.

### Parsing Raw LDAP Values

Raw LDAP attributes often contain binary data, distinguished names, or specialized formats. The `parse_attribute` function (located in [`src/doom/parsers/attribute.py`](https://github.com/000pp/doom/blob/main/src/doom/parsers/attribute.py)) handles conversion to Python-native types:

```python

# Lines 34-38 reference

for attr in entry.entry_attributes:
    raw_value = entry[attr].value
    parsed_value = parse_attribute(attr, raw_value)
    attributes[attr] = parsed_value

```

This normalization step ensures downstream modules receive consistent data types regardless of LDAP schema variations.

### Property Analysis and Flag Conversion

Certificate templates store security-relevant settings as bit flags in attributes like `msPKI-Certificate-Name-Flag` and `pKIExtendedKeyUsage`. The `analyze_template_properties` helper decodes these into human-readable booleans:

```python

# Lines 39-42 reference

properties = analyze_template_properties(attributes)
attributes.update(properties)

```

This produces flags such as:
- **Auto_Enrollment**: Whether the template allows automatic certificate enrollment
- **Exportable_Key**: Whether the private key can be exported
- **Client_Authentication**: Whether the template supports client authentication EKUs

## Practical Usage Example

The following example demonstrates how to invoke `enumerate_templates` within the Doom framework:

```python
from doom.protocols.ldap import get_ldap_connection
from doom.modules.enumerate_templates import enumerate_templates

# 1️⃣ Establish an LDAP connection (example uses default credentials)

ldap_conn, base_dn = get_ldap_connection()

# 2️⃣ Retrieve all certificate templates

templates = enumerate_templates(ldap_conn, base_dn)

# 3️⃣ Iterate and display useful info

for tmpl in templates:
    print(f"Template: {tmpl['display_name']} ({tmpl['name']})")
    print(f"  DN: {tmpl['dn']}")
    print("  Properties:")
    for prop, value in tmpl['attributes'].items():
        # Show only the boolean flag properties

        if isinstance(value, bool):
            print(f"    {prop}: {value}")
    print("-" * 40)

```

This script connects to Active Directory, retrieves all certificate templates, and prints the derived security properties for each template.

## Source Code Architecture

The `enumerate_templates` function relies on several supporting modules within the Doom codebase:

- **[`src/doom/modules/enumerate_templates.py`](https://github.com/000pp/doom/blob/main/src/doom/modules/enumerate_templates.py)** – Implements `enumerate_templates` and the `analyze_template_properties` helper that decodes certificate template flags.
- **[`src/doom/protocols/ldap.py`](https://github.com/000pp/doom/blob/main/src/doom/protocols/ldap.py)** – Provides the `safe_ldap_attr` helper and LDAP connection utilities used to safely extract attribute values.
- **[`src/doom/parsers/attribute.py`](https://github.com/000pp/doom/blob/main/src/doom/parsers/attribute.py)** – Contains `parse_attribute`, which translates raw LDAP values into Python-native types.
- **[`src/doom/__main__.py`](https://github.com/000pp/doom/blob/main/src/doom/__main__.py)** – Entry point of the Doom tool where template enumeration can be triggered from the command line interface.

## Summary

- The `enumerate_templates` function performs targeted LDAP subtree searches to discover Active Directory Certificate Templates.
- It constructs the search base targeting `CN=Certificate Templates` and filters for `pKICertificateTemplate` object class.
- Raw LDAP attributes are normalized through `parse_attribute` and safely extracted via `safe_ldap_attr`.
- The function derives high-level security properties by analyzing bit flags through `analyze_template_properties`.
- Output includes structured dictionaries with names, distinguished names, and enriched attribute sets suitable for security auditing.

## Frequently Asked Questions

### What LDAP object class does enumerate_templates search for?

The function searches for objects of class `pKICertificateTemplate`. It constructs an LDAP filter targeting this specific object class within the `CN=Certificate Templates` container to ensure only certificate template definitions are returned.

### How does enumerate_templates handle malformed LDAP attributes?

The function utilizes the `safe_ldap_attr` helper from [`src/doom/protocols/ldap.py`](https://github.com/000pp/doom/blob/main/src/doom/protocols/ldap.py) to safely retrieve attribute values. This helper prevents `KeyError` exceptions by returning `None` or empty strings when attributes are missing or malformed, ensuring the enumeration continues without crashing.

### What properties are derived from the raw certificate template flags?

The `analyze_template_properties` helper decodes low-level bit flags into boolean properties such as **Auto_Enrollment** (indicating automatic certificate enrollment capability), **Exportable_Key** (indicating if private keys can be exported), and **Client_Authentication** (indicating Extended Key Usage support for client authentication).

### Where is the enumerate_templates function located in the Doom repository?

The function is implemented in [`src/doom/modules/enumerate_templates.py`](https://github.com/000pp/doom/blob/main/src/doom/modules/enumerate_templates.py). It is imported and utilized by the main entry point in [`src/doom/__main__.py`](https://github.com/000pp/doom/blob/main/src/doom/__main__.py) and depends on helper functions defined in [`src/doom/protocols/ldap.py`](https://github.com/000pp/doom/blob/main/src/doom/protocols/ldap.py) and [`src/doom/parsers/attribute.py`](https://github.com/000pp/doom/blob/main/src/doom/parsers/attribute.py).