The problem. A certificate is revoked in the CA, but OCSP keeps answering
gooduntil that CA publishes its next CRL — which is usually minutes to hours later, and exactly when you needed the answer to berevoked.What this does. A native COM revocation provider for AD CS Online Responder that reads the CA certificate database instead of the CRL, so revocation shows up in about a minute. Rollback to the built-in CRL provider is one command.
中文:证书在 CA 里吊销了,OCSP 却还返回
good,要等这个 CA 重新发布 CRL 才变 —— 而这往往正是你最需要它是revoked的时候。本提供程序直接从 CA 数据库取吊销状态, 约 1 分钟生效;回滚到内置 CRL 提供程序只需一条命令。
Built-in ocsprevp.dll |
This provider | |
|---|---|---|
| Answer source | CRL | CA database snapshot (certutil -view) |
| Revocation visible after | next CRL publication | ~1 minute |
| Needs CRL distribution point | yes | no |
| Multi-CA | one provider per CA | per-CA sections in one provider.ini |
| Revoked reason / time | from CRL | from the database row |
中文摘要:给 AD CS 联机响应程序(OCSPSvc)用的原生 COM 吊销提供程序,吊销数据取自 CA 证书数据库快照而不是 CRL,吊销后约 1 分钟即可在 OCSP 中体现。支持多 CA、中英双语、x64/x86/ARM64。 仓库不含任何微软二进制文件。
The built-in provider (ocsprevp.dll) answers from the CRL. That means an OCSP client can
be told good for a certificate that was revoked minutes ago and whose new CRL has not been
published yet. This provider reads the CA database directly (via certutil -view), so
revocation is visible as soon as the database is written.
CA certificate database (CertLog\*.edb)
| certutil -view <- scheduled task, every minute, as SYSTEM
v
<install>\data\<ca-id>.dat <- snapshot: serial \t disposition \t revokedWhen \t reason \t notAfter
| in-memory cache, reloaded when the file mtime changes
v
OcspDbProvider.dll (native COM, CLSID {7B0C4B1E-93A1-4C0F-9E52-0D2A6A5B41C9})
| IOCSPRevInfoProvider::VerifySerialNumber
v
ocspsvc.exe -> IIS (/ocsp) -> clients
The interface contract was recovered by reverse engineering ocsprevp.dll and ocspsvc.exe;
the interesting parts (including two traps that corrupt the heap or misplace every timestamp)
are documented in docs/REVERSE-ENGINEERING.md(附 docs/REFERENCES.md:官方文档覆盖到哪、哪些只能逆向).
- Native C++ in-proc COM server — no CLR inside the responder process.
- CA database as the data source — revocation latency is bounded by the sync interval.
- Per-CA configuration and snapshots — several responders/CA configs can share one DLL.
- Bilingual configuration UI — English and Simplified Chinese, following the system UI
language, overridable with
OCSPDBPROVIDER_LANG. - Portable install location —
%ProgramData%\OcspDbProviderby default, fully overridable. - x64 / x86 / ARM64 build (ARM64 requires the VC ARM64 toolchain component).
- Windows 7 / Server 2008 R2 and later.
- Scripts for build, install, activate, deactivate, uninstall, snapshot sync and a self-check that runs without administrator rights.
- No Microsoft binaries in this repository. Only this project's own code.
Two ways, both produce the same artifacts:
- GitHub Actions (no local tooling): push a tag like
v2.0.0—.github/workflows/release.ymlbuilds the x64 and x86 setups on a Windows runner, runs the self check, writesSHA256SUMS.txtand publishes the release withdocs/RELEASE-NOTES-<version>.mdas the body. - Locally:
pwsh -File scripts/release.ps1builds both setups intodist/, writes the checksums and prints the exactgh release createcommand (or the web-UI steps) whenghis not available.
Download ADCS-CDBRP-Provider-Setup-<version>-<arch>.exe from
Releases, verify its SHA-256
against SHA256SUMS.txt, then run it as administrator:
.\ADCS-CDBRP-Provider-Setup-2.0.0-x64.exe # install (does not switch the responder)
.\ADCS-CDBRP-Provider-Setup-2.0.0-x64.exe -Mode activate # switch the responder to this provider
.\ADCS-CDBRP-Provider-Setup-2.0.0-x64.exe -Mode status # read-only overview, no elevationThe setup embeds the DLL, uitest.exe, the scripts and the license; it extracts to a temp
directory and runs the same install.ps1 described below, so there is only one install
implementation. --help, --list and --extract-only <dir> work without elevation.
The setup executables are unsigned — check the checksum before running.
Prerequisites: Windows with Visual Studio 2019/2022 (or Build Tools) including the Desktop development with C++ workload, and PowerShell 5.1+.
# build + run the self check (no admin needed, does not touch the registry)
pwsh -File scripts/test.ps1
# install: copy, regsvr32, provider.ini, first snapshot, scheduled task (elevated)
pwsh -File scripts/install.ps1 -Mode install -CAConfig 'SRV1\CORP-CA'
# switch the responder to this provider (elevated)
pwsh -File scripts/install.ps1 -Mode activate
# roll back to the built-in CRL provider
pwsh -File scripts/install.ps1 -Mode deactivate
# state overview
pwsh -File scripts/install.ps1 -Mode statusVerify with OpenSSL:
openssl ocsp -issuer ca.cer -serial 0x6200000003CC4141256F50414D000000000003 \
-url http://<responder>:<port>/ocsp -CAfile ca.cer -no_nonce
# Response verify OK%ProgramData%\OcspDbProvider\provider.ini (UTF-8, key=value, sections optional):
[default]
checkseconds=2 ; snapshot cache lifetime; 0 = re-check on every query
responseseconds=30 ; nextUpdate lifetime = how long the responder may serve a cached answer.
; The delay a client sees is bounded by max(refresh cadence, this value),
; not by their sum. Measured: 23 s end to end with a 20 s refresh cadence
; and responseseconds=20; the 30 s default keeps it inside a minute.
validstatus=0 ; dwStatus for "good"
revokedstatus=1 ; dwStatus for "revoked"
unknownstatus=0 ; dwStatus for serials not present in the snapshot
; (0 matches what the built-in CRL provider reports for unknown serials)
[ca:SRV1\CORP-CA] ; optional per-CA overrides
snapshot=C:\ProgramData\OcspDbProvider\data\CORP-CA.dat
unknownstatus=2 ; answer RFC 6960 "unknown" instead of "good"
responseseconds=15 ; this CA is busier, accept a slightly staler answerChanges to this file take effect within a couple of seconds — the provider watches its own mtime, so there is no need to restart the responder.
The snapshot refresh cadence is set by the installer (-SyncPerMinute, 1–6, default 3). The
scheduler cannot repeat faster than once a minute, so N>1 is implemented as N staggered
triggers; 3 gives a ~20 s cadence. Raise it for faster revocation visibility, lower it to cut
certutil -view load on a large CA.
A flat file with no sections is also accepted (legacy 1.x layout) and applies to every CA.
OcspConfig.exe ships next to the provider and edits every CA in one place:
& "$env:ProgramData\OcspDbProvider\OcspConfig.exe"It lists the CAs found in the responder configuration and in provider.ini, lets you edit
the snapshot path, cache seconds and the three status codes per CA, and shows the live state
of that CA's snapshot (resolved path, whether the file exists, its size, parsable rows and
modification time). Saving only touches that CA's [ca:<id>] section; removing one only
drops that section.
The same operations are scriptable:
OcspConfig.exe --dump
OcspConfig.exe --set CORP-A --snapshot C:\data\CORP-A.dat --unknown 2
OcspConfig.exe --remove CORP-B| Environment variable | Purpose |
|---|---|
OCSPDBPROVIDER_DIR |
Install directory (overrides the registry/ProgramData default) |
OCSPDBPROVIDER_LANG |
zh / en — force the UI language |
OCSPDBPROVIDER_CAPTURE |
1 — self-test mode: dump the dialog and auto-confirm |
OCSPDBPROVIDER_CAPTURE_DIR |
Where the dialog dump is written |
OCSPDBPROVIDER_CA |
Default CA id for uitest.exe |
Resolution order for the install directory: OCSPDBPROVIDER_DIR → HKLM\SOFTWARE\OcspDbProvider\InstallDir
→ %ProgramData%\OcspDbProvider.
src/native/ provider DLL, config model (shared), self-test harness, OcspConfig tool
src/setup/ setup EXE: embedded payload, self-elevation, runs install.ps1
src/legacy/managed/ earlier managed (.NET) prototype, unsupported
scripts/ build, build-installer, install, uninstall, sync, test, release
docs/ architecture, deployment, compatibility, reverse-engineering
test/ helpers to build a throw-away test PKI
dist/ release artifacts (generated, not committed)
| Document | Contents |
|---|---|
| docs/ARCHITECTURE.md | Interfaces, structures, data flow, multi-CA model |
| docs/DEPLOYMENT.md | Install, activate, verify, roll back, troubleshoot |
| docs/COMPATIBILITY.md | OS/arch/toolchain matrix, migration from 1.x |
| docs/REVERSE-ENGINEERING.md(附 docs/REFERENCES.md:官方文档覆盖到哪、哪些只能逆向) | Recovered COM contract and the traps |
| Symptom | Cause |
|---|---|
Every request returns unauthorized |
Provider not registered / ProviderCLSID not switched / responder cannot read the CA |
Every request returns 500 with a heap corruption event |
GetConfigInformation returned a byte buffer instead of a VARIANT-carried SAFEARRAY |
This Update: Bad time value in the OCSP response |
RevStatusInfo not packed to 1 byte (48 instead of 40 bytes) |
All serials answered as good |
Snapshot empty or unreadable; check provider-native.log and the task state |
| MMC snap-in crashes when the provider is selected | GetStatus must return a `VT_ARRAY |
0x800706BA when running certutil |
CA config string needs the host prefix (HOST\CA-NAME) |
MIT. No Microsoft binaries are redistributed; docs/REVERSE-ENGINEERING.md
contains observations about interfaces implemented by Microsoft software, made for
interoperability.
给 AD CS 联机响应程序(ocspsvc.exe)用的原生 COM 吊销提供程序:OCSP 的吊销状态来自
CA 证书数据库快照,不读 CRL。吊销后约 1 分钟即可在 OCSP 中看到,不用等 CRL 发布。
内置提供程序(ocsprevp.dll)读的是 CRL,因此会出现"证书刚被吊销、新 CRL 还没发布,OCSP 仍报 good"
的窗口。本提供程序直接读 CA 数据库(certutil -view),数据库一写入就能反映。
- 原生 C++ 进程内 COM,响应程序进程里没有 CLR;
- 多 CA:每个 CA 独立快照、独立状态码映射;
- 配置界面中英双语(跟随系统 UI 语言,可用
OCSPDBPROVIDER_LANG强制); - 安装目录默认
%ProgramData%\OcspDbProvider,可用环境变量/注册表覆盖; - x64 / x86 / ARM64 构建(ARM64 需要安装 VC 的 ARM64 工具链);
- 最低 Windows 7 / Server 2008 R2;
- 提供构建、安装、激活、回滚、卸载、快照同步与自检脚本;自检不需要管理员权限。
pwsh -File scripts/test.ps1 # 构建 + 自检(无需管理员)
pwsh -File scripts/install.ps1 -Mode install -CAConfig 'SRV1\CORP-CA' # 安装(需管理员)
pwsh -File scripts/install.ps1 -Mode activate # 切换响应程序到本提供程序回滚:scripts/install.ps1 -Mode deactivate(恢复内置 CRL 提供程序)。
%ProgramData%\OcspDbProvider\provider.ini,UTF-8,key=value:
[default]
checkseconds=2
validstatus=0
revokedstatus=1
unknownstatus=0
[ca:SRV1\CORP-CA]
snapshot=C:\ProgramData\OcspDbProvider\data\CORP-CA.dat
unknownstatus=2老的平铺格式(1.x)仍可直接使用,等价于 [default]。
GetConfigInformation的返回值不是字节块,而是CERTTRANSBLOB承载的 VARIANT (cb放 VARTYPE、pb是SAFEARRAY*);按字节缓冲返回会让ocspsvc.exe堆损坏崩溃。RevStatusInfo必须 1 字节紧密排列(40 字节),否则时间字段全错位,OCSP 里表现为Bad time value。IOCSPRevInfoProviderManager::GetStatus的状态值必须是VT_ARRAY|VT_BSTR,给单个BSTR会让托管 snapin 抛InvalidCastException并带崩mmc.exe。- 联机响应程序传进来的序列号是字节反序的,匹配前要按字节反转。
- CA 配置串必须带主机前缀(
机器名\CA名),裸 CA 名会报0x800706BA。
详见 docs/REVERSE-ENGINEERING.md(附 docs/REFERENCES.md:官方文档覆盖到哪、哪些只能逆向)。
| 想做什么 | 去哪 |
|---|---|
| 搭建、激活、多 CA 配置、排查「状态页显示 0 条」 | docs/DEPLOYMENT.md |
| 参与开发(构建、20 项自检、改动红线) | CONTRIBUTING.md |
| 参与时请遵守的行为准则 | CODE_OF_CONDUCT.md |
| 报告安全漏洞 | SECURITY.md —— 不要开公开 issue,用 Security → Report a vulnerability |
| 报 bug / 提需求 | 新建 issue,模板会要求贴状态页输出 |
报 bug 时最有用的两条命令:
& "$env:ProgramData\OcspDbProvider\uitest.exe" info -ca '<CA 名>'
& "$env:ProgramData\OcspDbProvider\OcspConfig.exe" --dump第一条会打印提供程序真正解析到的快照路径、文件是否存在、字节数和可解析行数 —— 绝大多数「0 条」的问题看这一行就能定位。
MIT。仓库不包含任何微软二进制文件。