Skip to content

Windows 证书存储模式 (TlsCertSubject)

概述

Windows 证书存储模式从操作系统的证书库中查找证书,无需指定文件路径。适合以下场景:

  • 企业环境中证书统一管理
  • 与 IIS 共用同一张证书
  • 通过组策略 (GPO) 分发证书
  • 证书自动续期(如 Windows Certificate Enrollment)
  • 不希望私钥文件暴露在磁盘上

函数签名

vb
Public Function TlsCertSubject( _
    ByVal CertSubject As String, _
    Optional ByVal AlpnProtocols As String = "...") As <组件类型>

参数

参数类型必要说明
CertSubjectString证书主题名称(Subject),用于在证书库中查找
AlpnProtocolsStringALPN 协议协商。各组件默认值不同
组件AlpnProtocols 默认值
cHttpServer"http/1.1"
cWinsock"http/1.1"
cWebSocketServer""(空)

CertSubject 参数详解

CertSubject 是 X.509 证书的 Subject 字段,用于在 Windows 证书存储中定位证书。

Subject 格式

X.509 Subject 使用 Distinguished Name (DN) 格式:

CN=www.example.com, O=Example Inc, L=Beijing, S=Beijing, C=CN

常用字段:

字段全称说明示例
CNCommon Name通用名称,通常是域名CN=www.example.com
OOrganization组织名称O=Example Inc
OUOrganizational Unit部门OU=IT Department
LLocality城市L=Beijing
SState省/州S=Beijing
CCountry国家代码C=CN

查找规则

底层使用 CertFindCertificateInStore API,按 Subject 进行模糊匹配:

  • 传入 "www.example.com" 会匹配 CN=www.example.com, O=...
  • 如果多个证书匹配,返回第一个找到的
  • 建议使用精确的 CN 值以避免匹配到错误证书

如何查看证书的 Subject

方法 1:证书管理器

1. Win+R → certmgr.msc(当前用户)或 certlm.msc(本地计算机)
2. 展开"个人" → "证书"
3. 双击证书 → "详细信息"选项卡 → "主题"字段

方法 2:命令行

cmd
certutil -store My

输出示例:

Cert Serial Number: ...
Issuer: CN=Example CA ...
NotBefore: ...
NotAfter: ...
Subject: CN=www.example.com, O=Example Inc, L=Beijing, S=Beijing, C=CN

方法 3:PowerShell

powershell
Get-ChildItem Cert:\LocalMachine\My | Select-Object Subject, Thumbprint, NotAfter

证书存储位置

Windows 证书存储有两大类:

存储位置管理工具适用场景
当前用户 (CurrentUser)certmgr.msc用户级证书
本地计算机 (LocalMachine)certlm.msc系统级证书,服务程序推荐

底层 API 查找顺序:

  1. MY 存储(个人证书,含私钥)
  2. 在 CurrentUser 和 LocalMachine 中查找

重要: 证书必须包含私钥才能用于 TLS 服务端。在证书管理器中,含私钥的证书图标上会有一个小钥匙标志。

各组件使用示例

cHttpServer(HTTPS)

vb
' 使用 IIS 同一张证书
Server.TlsCertSubject("www.example.com").Start 443

' 配合 WebRoot
Server.TlsCertSubject("www.example.com").WebRoot("C:\www").Start 443

cWinsock(TLS TCP 服务端)

vb
Dim svr As New cWinsock
svr.TlsCertSubject("tcp.example.com").Listen 443

cWebSocketServer(wss://)

vb
Dim wsSvr As New cWebSocketServer
wsSvr.TlsCertSubject("ws.example.com").Listen 443

证书安装

从 PFX 导入到证书存储

方法 1:证书管理器 GUI

1. certlm.msc → 右键"个人" → "所有任务" → "导入"
2. 选择 .pfx 文件
3. 输入密码
4. 选择"将所有的证书放入下列存储" → "个人"
5. 确保勾选"标记此密钥为可导出"(如需后续导出)

方法 2:命令行

cmd
certutil -p "password" -importpfx "C:\certs\server.pfx"

方法 3:PowerShell

powershell
$pwd = ConvertTo-SecureString -String "password" -AsPlainText -Force
Import-PfxCertificate -FilePath "C:\certs\server.pfx" -CertStoreLocation Cert:\LocalMachine\My -Password $pwd

授予私钥访问权限

Windows 服务或特定用户需要私钥读取权限:

1. certlm.msc → 找到证书 → 右键 → "所有任务" → "管理私钥"
2. 添加用户或组 → 授予"读取"权限

PowerShell:

powershell
$cert = Get-ChildItem Cert:\LocalMachine\My | Where-Object {$_.Subject -match "www.example.com"}
$rsaCert = [System.Security.Cryptography.X509Certificates.RSACertificateExtensions]::GetRSAPrivateKey($cert)
$file = Get-Item -Path $($rsaCert.keyuniquecontainername)
$acl = $file.GetAccessControl()
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule("IIS_IUSRS", "Read", "Allow")
$acl.AddAccessRule($rule)
$file.SetAccessControl($acl)

IIS 共用证书场景

当服务器同时运行 IIS 和 vbmanlib 应用时,共用同一张证书:

1. 在 IIS 管理器中绑定证书到 443 端口
2. 证书自动安装到 LocalMachine\My 存储
3. vbmanlib 应用使用 TlsCertSubject 引用同一张证书
4. IIS 监听 443,vbmanlib 监听其他端口(如 8443)
vb
' IIS 占用 443,vbmanlib 使用 8443
Server.TlsCertSubject("www.example.com").WebRoot("C:\www").Start 8443

证书续期

Windows 证书存储中的证书续期后 Subject 通常不变,但 Thumbprint 会变。底层 API 按 Subject 查找,会自动获取最新版本的证书。

vb
' 续期后无需改代码,自动使用新证书
Server.TlsCertSubject("www.example.com").Start 443

注意: 需要重启应用才能加载新证书,运行中不会自动热更新。

企业 AD 证书服务

大型企业通常使用 Active Directory Certificate Services (AD CS):

1. 管理员在 AD CS 中配置证书模板
2. 域内计算机自动注册证书(Auto-Enrollment)
3. 证书自动安装到 LocalMachine\My 存储
4. 应用程序通过 TlsCertSubject 直接使用

AD CS 优势:

  • 证书自动签发和续期
  • 组策略统一管理
  • 私钥不离开本机
  • 审计和追踪

常见问题

1. 找不到证书

LastError: 证书文件不存在或格式错误

排查步骤:

  1. 打开 certlm.msc 检查证书是否在"个人"存储中
  2. 确认证书包含私钥(图标有小钥匙)
  3. 确认 Subject CN 值拼写正确
  4. 检查证书是否已过期

2. 私钥访问被拒绝

应用启动时无错误,但 TLS 握手失败

解决: 授予运行应用的用户对私钥的读取权限(见上文"授予私钥访问权限")。

3. 多个证书匹配同一 Subject

底层返回第一个匹配的证书,可能不是期望的。

解决: 使用更精确的 Subject,或换用 TlsCertFile 直接指定文件。

4. 证书不在"个人"存储

只有 MY 存储中的证书包含私钥,其他存储(如"受信任的根证书")中的证书只有公钥。

解决: 确保证书导入到"个人"存储且包含私钥。

底层实现

vb
' cTlsSocket.InitServerTls 内部
If LenB(CertSubject) <> 0 Then
    If pvPkiSystemStoreImportCertificate(CertSubject, 0, cCerts, cPrivKey) Then
        GoTo StartTls
    End If
    pvSetLastError vbObjectError, MODULE_NAME & "." & FUNC_NAME, ERR_NO_CERTIFICATE
    GoTo QH
End If

pvPkiSystemStoreImportCertificate 使用 Windows CryptoAPI:

  1. CertOpenStore / CertOpenSystemStore 打开 "MY" 存储
  2. CertFindCertificateInStore 按 Subject 查找
  3. CertGetCertificateContextProperty 获取私钥句柄
  4. 将证书和私钥转换为 OpenSSL 可用的格式

与其他模式对比

特性TlsCertFileTlsCertSubjectTlsCertMemory
证书来源磁盘文件Windows 证书库内存 Collection
私钥安全文件系统操作系统保护进程内存
证书更新替换文件续期到存储重新加载
多应用共享文件共享天然共享各自独立
部署复杂度
企业适用性一般优秀一般

相关文档


最后更新: 2026-06-09

VB6及其LOGO版权为微软公司所有