Skip to content

Latest commit

 

History

History
280 lines (211 loc) · 15.8 KB

File metadata and controls

280 lines (211 loc) · 15.8 KB

CA Handler for Microsoft ICertPassage Remote Protocol (MS-ICPR)

This CA handler enrolls certificates through the Microsoft ICertPassage Remote Protocol (MS-ICPR) RPC interface used by Active Directory Certificate Services. Request/response structures align with concepts from MS-WCCE, but transport is MS-ICPR (not DCOM). The handler incorporates code from Certipy.

Compatibility: The previous module name acme2certifier.cahandlers.mswcce_ca_handler remains available as a deprecated alias. Prefer msicpr_ca_handler. See also the legacy doc page mswcce.md.

Limitations

Be aware of the following limitations when using this handler:

  • The CA certificate chain is taken from the MS-ICPR enrollment response (pctbCert / CMS) when the CA returns it. Configure ca_bundle only as a local PEM fallback if the response has no usable chain. ca_bundle does not authenticate the CA endpoint. Enrollment uses SMB/DCE-RPC with RPC packet privacy, not HTTPS/TLS verification.
  • HTTP(S) proxy_server_list settings are ignored. MS-ICPR does not use HTTP(S) and cannot be routed through an HTTP proxy.
  • Revocation operations are not yet supported.
  • Pending (manager-approved) enrollments return the CA request_id as the ACME poll identifier, but poll() is not implemented yet, so pending requests cannot be completed via ACME.

Preparation

  1. Active Directory Certificate Services (AD-CS) must be enabled and properly configured.
  2. The CA handler communicates with the CA over SMB/named pipes and DCE-RPC (MS-ICPR). The CA must be reachable on TCP port 445. When named-pipe binding is unavailable, the handler falls back to the RPC Endpoint Mapper (TCP 135) and a dynamic high TCP port returned by the CA.
  3. (Optional): If installing from RPM or DEB and planning to use Kerberos authentication, ensure you have an updated Impacket module (version 0.11 or higher), as older versions have issues handling UTF-8 encoded passwords. You can find updated packages in the A2C GitHub repository.
  4. You need a set of credentials with sufficient permissions to access the service and enrollment templates.

Note on RPC Port Requirements

When using the MS-ICPR handler, acme2certifier communicates with the Microsoft CA through the MS-ICPR RPC interface. This interface does not honor static DCOM endpoint configuration for "CertSrv Request" and will resolve dynamic RPC ports via the CA’s RPC Endpoint Mapper when TCP transport is used. As a result, RPC high ports (or an explicitly allowed dynamic range) must be open between acme2certifier and the CA when named-pipe enrollment is not sufficient—even if the CA has been configured to use a fixed DCOM port for certificate requests.

Local Installation

Important:

Some malware scanners, such as Microsoft Defender, classify Impacket as a hacking tool (see Fortra Impacket Issue #1762 or Fortra Impacket Issue #1271). These alerts are triggered mainly by example scripts included in the package, not the library itself.

To avoid issues with your security team, consider installing a stripped-down version of Impacket without flagged scripts. Pre-packaged versions are available for RHEL 8 and RHEL 9 in the SBOM repository.

If installing from pip or source, follow these steps:

  • Download the Impacket package:
pip3 download impacket --no-deps
  • Unpack the archive:
tar xvfz impacket-0.11.0.tar.gz
  • Remove all files and subdirectories in the examples directory:
rm -rf impacket-0.11.0/examples/*
  • Install the package:
pip install .
# or: pip install acme2certifier

Configuration

Modify the server configuration (acme_srv/acme_srv.cfg) and add the following parameters:

[CAhandler]
handler_module: acme2certifier.cahandlers.msicpr_ca_handler
host: <hostname>
user: <username>
password: <password>
krb5_auth_backend: impacket
krb5_principal: <principal@REALM>
krb5_keytab: </path/to/keytab>
krb5_cache: </path/to/ccache>
krb5_config: </path/to/krb5.conf>
krb5_kinit_path: </path/to/kinit>
target_domain: <domain_name>
domain_controller: <IP_of_domain_controller>
ca_name: <ca_name>
ca_bundle: <filename>
template: <template_name>
timeout: 5
use_kerberos: False
allowed_templates: ["WebServer", "WebServerModified"]
allowed_domainlist: ["example.com", "*.example2.com"]

Parameter Explanations

  • host – The hostname of the system providing the enrollment service. Multiple hosts can be specified as server1, server2, server3; a random host will be selected.
  • host_variable (optional) – Environment variable containing the host address (overridden if host is set in acme_srv.cfg).
  • ca_name – Certificate authority name. Multiple CA names can be specified as ca1, ca2, ca3; a random entry will be chosen.
  • user – Username for accessing the service.
  • user_variable (optional) – Environment variable containing the username (overridden if user is set in acme_srv.cfg).
  • password – Password for authentication.
  • password_variable (optional) – Environment variable containing the password (overridden if password is set in acme_srv.cfg).
  • krb5_auth_backend (optional) – Kerberos backend selection. Supported values are impacket and python. Default is impacket. If use_kerberos=True and both krb5_principal and krb5_keytab are configured, the handler auto-selects python when krb5_auth_backend is not explicitly set. For python, the handler loads a TGT from the ccache and passes it to impacket explicitly (no process-wide KRB5CCNAME mutation during enrollment).
  • krb5_principal (optional, required for keytab mode) – Kerberos principal, for example svc-a2c-enroll@EXAMPLE.COM.
  • krb5_principal_variable (optional) – Environment variable containing the Kerberos principal (overridden if krb5_principal is set in acme_srv.cfg).
  • krb5_keytab (optional, required for keytab mode) – Path to the Kerberos keytab file used by the service account.
  • krb5_keytab_variable (optional) – Environment variable containing the keytab path (overridden if krb5_keytab is set in acme_srv.cfg).
  • krb5_cache (optional) – Path to the Kerberos credential cache (ccache). Required when using krb5_auth_backend=impacket together with keytab mode. For krb5_auth_backend=python, a temporary ccache is created automatically if not configured. If you set a shared path used by multiple worker processes or threads, concurrent kinit/ticket refresh can race on the same file; prefer a per-process temporary cache, or a dedicated cache with a single writer and clear operational ownership.
  • krb5_cache_variable (optional) – Environment variable containing the ccache path (overridden if krb5_cache is set in acme_srv.cfg).
  • krb5_config (optional) – Path to a custom krb5.conf file. Used by the kinit fallback path.
  • krb5_config_variable (optional) – Environment variable containing the krb5.conf path (overridden if krb5_config is set in acme_srv.cfg).
  • krb5_kinit_path (optional) – Full path to the kinit binary used by the kinit fallback path. Defaults to kinit resolved from PATH. If set, the value must be an absolute path whose basename is exactly kinit (for example /usr/bin/kinit). Symlink targets such as Debian/Ubuntu kinit.mit / kinit.heimdal are accepted after resolution. Other values are rejected and the kinit fallback fails.
  • krb5_kinit_path_variable (optional) – Environment variable containing the kinit binary path (overridden if krb5_kinit_path is set in acme_srv.cfg).
  • target_domain (optional) – Active Directory domain name.
  • domain_controller (optional) – Domain controller endpoint. You can provide either an IP address or an FQDN. If an FQDN is configured, acme2certifier resolves it via DNS and uses the first returned IP address.
  • dns_server (optional) – IP address of the DNS server.
  • ca_bundle (optional) – Local CA certificate chain in PEM format used as a packaging fallback when the enrollment response does not include a CMS chain. Appended to the issued certificate only; it does not verify the AD CS enrollment endpoint.
  • template – Certificate template used for enrollment.
  • allowed_templates (optional) – JSON list of ADCS templates permitted for enrollment (including templates selected via ACME profiles, header_info, or EAB). An empty or unset list allows any template and logs a warning (backwards compatible). When non-empty, enrollment is rejected if the selected template is not listed. EAB per-account template restrictions still apply on top of this global ceiling. MS-ICPR has no Web Enrollment template discovery API; CA-side membership checks are mscertsrv-only.
  • timeout (optional) – Enrollment timeout in seconds (default: 5).
  • use_kerberos – Use Kerberos for authentication. If False, authentication is done via NTLM. Due to Microsoft's October 2023 announcement, Kerberos is recommended, but NTLM remains the default for backward compatibility. Startup logs a warning when Kerberos is disabled.
  • allowed_domainlist (optional) – List of allowed domains for enrollment (JSON format).
  • enrollment_config_log (optional) – Log enrollment parameters (default: False). This handler omits password, Kerberos credential locations (krb5_keytab, krb5_cache, krb5_config, krb5_kinit_path), and runtime TGT objects from that dump.
  • enrollment_config_log_skip_list (optional) – List of enrollment parameters to exclude from logs (JSON format).

Keytab Support

Keytab-based Kerberos authentication allows the CA handler to authenticate without storing a reusable plaintext password in acme_srv.cfg. This reduces credential exposure risk in configuration management systems, log archives, and backup snapshots as

  • Passwords no longer need to be kept in clear text in the CA handler configuration.
  • Service-account credentials can be rotated and scoped following AD operational controls.
  • Keytab files can be protected with strict filesystem ACLs and isolated runtime identities.

Generate a Keytab on the Domain Controller

The usual approach is to create or reuse a dedicated service account and generate a keytab with ktpass.

  1. Open an elevated command prompt or PowerShell on a domain controller.
  2. Generate the keytab (example):
ktpass /princ svc-a2c-enroll@EXAMPLE.COM /mapuser EXAMPLE\svc-a2c-enroll /crypto AES256-SHA1 /ptype KRB5_NT_PRINCIPAL /out C:\Temp\svc-a2c-enroll.keytab /pass *
  1. Securely copy the keytab to the acme2certifier host (for example /etc/acme2certifier/svc-a2c-enroll.keytab).
  2. Restrict file permissions so only the service user can read it.

Notes:

  • ktpass can reset or affect account password/key material depending on options and AD state. Validate your AD policy and coordinate with AD administrators before running it in production.
  • Prefer modern encryption types (for example AES256) and avoid legacy ciphers.

Configure acme2certifier for Keytab Mode

[CAhandler]
handler_module: acme2certifier.cahandlers.msicpr_ca_handler
host: <ca-hostname>
target_domain: EXAMPLE.COM
domain_controller: <dc-ip-or-name>
ca_name: <ca-name>
ca_bundle: <ca-bundle-path>
template: <template-name>
use_kerberos: True
krb5_principal: svc-a2c-enroll@EXAMPLE.COM
krb5_keytab: /etc/acme2certifier/svc-a2c-enroll.keytab

# Optional
krb5_auth_backend: python
krb5_cache: /var/www/acme2certifier/volume/krb5cc_a2c

krb5_config: /etc/krb5.conf
krb5_kinit_path: /usr/bin/kinit

Validate with kinit and klist

Before starting production enrollment, verify Kerberos ticket acquisition from the acme2certifier host:

kdestroy || true
export KRB5CCNAME=/tmp/krb5cc_a2c_test
kinit -k -t /etc/acme2certifier/svc-a2c-enroll.keytab svc-a2c-enroll@EXAMPLE.COM
klist
klist -k /etc/acme2certifier/svc-a2c-enroll.keytab

Expected result:

  • kinit exits successfully.
  • klist shows a valid TGT for the service principal.
  • Keytab entries are visible with klist -k.

Passing a Template from Client to Server

acme2certifier supports the Automated Certificate Management Environment (ACME) Profiles Extension draft, allowing an acme-client to specify a template parameter to be submitted to the CA server.

The list of supported profiles must be configured in acme_srv.cfg

[Order]
profiles: {"template1": "http://foo.bar/template1", "template2": "http://foo.bar/template2", "template3": "http://foo.bar/template3"}

Once enabled, a client can specify the template to be used as part of an order request. Below an example for lego:

docker run -i -v $PWD/lego:/.lego/ --rm --name lego goacme/lego run --tls-skip-verify -s https://<acme-srv> -a --email "lego@example.com" -d <fqdn> --http --profile template2

Further, this handler uses the header_info_list feature, allowing an ACME client to specify a template name for certificate enrollment. To enable this feature, update acme_srv.cfg:

[Order]
header_info_list: ["HTTP_USER_AGENT"]

Example Usage

  • acme.sh:
docker exec -i acme-sh acme.sh --server http://<acme-srv> --issue -d <fqdn> --standalone --useragent template=foo --debug 3 --output-insecure
  • lego:
docker run -i -v $PWD/lego:/.lego/ --rm --name lego goacme/lego run --tls-skip-verify -s https://<acme-srv> -a --email "lego@example.com" --user-agent template=foo -d <fqdn> --http

EAB Profiling

This handler supports EAB profiling, which allows individual enrollment configurations per ACME account and restricts CN/SANs in the CSR. To enable this feature, update acme_srv.cfg:

[EABhandler]
eab_handler_module: acme2certifier.eabhandlers.kid_profile_handler
key_file: <profile_file>
eab_profiling: True

[CAhandler]
...

Example Key File

{
  "keyid_00": {
    "hmac": "example_hmac_value",
    "cahandler": {
      "template": ["WebServerModified", "WebServer"],
      "allowed_domainlist": ["www.example.com", "www.example.org", "*.acme"],
      "unknown_key": "unknown_value"
    }
  },
  "keyid_01": {
    "hmac": "YW5vdXRoZXJfdmVyeV9sb25nX2htYWNfZm9yX2tleWlkXzAxX3doaWNoIHdpbGxfYmUgdXNlZF9kdXJpbmcgcmVncmVzc2lvbg",
    "cahandler": {
      "template": "WebServerModified",
      "allowed_domainlist": ["www.example.com", "www.example.org", "*.acme"],
      "unknown_key": "unknown_value"
    }
  },
  "keyid_02": {
    "hmac": "dGhpc19pc19hX3ZlcnlfbG9uZ19obWFjX3RvX21ha2Vfc3VyZV90aGF0X2l0c19tb3JlX3RoYW5fMjU2X2JpdHM",
    "cahandler": {
      "allowed_domainlist": ["www.example.com", "www.example.org"]
    }
  },
  "keyid_03": {
    "hmac": "YW5kX2ZpbmFsbHlfdGhlX2xhc3RfaG1hY19rZXlfd2hpY2hfaXNfbG9uZ2VyX3RoYW5fMjU2X2JpdHNfYW5kX3Nob3VsZF93b3Jr"
  }
}

This setup ensures that individual accounts can have specific enrollment configurations and domain restrictions.