c++ - 使用 wincrypt 将主题备用名称添加到自签名证书
问题描述
如何在证书中添加主题备用名称。使用 wincrypt,我创建了证书并将其添加到“MY”和“root”路径,其中 CN 可以是机器完全限定的域名或主机名或 IP。作为主题备用名称,我想添加以下内容:DNS 名称=完全限定域名、DNS 名称=主机名和 DNS 名称=IP 如何执行此操作?我不想使用openssl。
LPCTSTR cnName= fqdn;
DWORD cbEncoded = 0;
if (!CertStrToName(X509_ASN_ENCODING, cnName, CERT_X500_NAME_STR, NULL,
pbdata, &cbData, NULL))
{
_tprintf(_T("CertStrToName failed 0x%x\n"), GetLastError());
return 0;
}
if (!(pbdata = (BYTE *)malloc(cbData)))
{
_tprintf(_T("malloc Error 0x%x\n"), GetLastError());
return 0;
}
if (!CertStrToName(X509_ASN_ENCODING, cnName, CERT_X500_NAME_STR, NULL, pbdata, &cbData, NULL))
{
_tprintf(_T("CertStrToName failed 0x%x\n"), GetLastError());
return 0;
}
CERT_NAME_BLOB IssuerBlob;
IssuerBlob.cbData = cbEncoded;
IssuerBlob.pbData = pbEncoded;
CertCreateSelfSignCertificate(NULL, &IssuerBlob, 0, &KeyProvInfo, &Alg, 0, &EndTime, 0);
OpenandAddCertificateToStore(pCertContext, L"MY");
OpenandAddCertificateToStore(pCertContext, L"Root");
这将创建证书并将其添加到证书中没有 SAN 的存储区
我尝试通过如下扩展列表:
CertCreateSelfSignCertificate(NULL, &IssuerBlob, 0, &KeyProvInfo, &Alg, 0, &EndTime, &myExtns_list);
CERT_EXTENSION myExtn;
myExtn.fCritical = TRUE;
myExtn.pszObjId = szOID_SUBJECT_ALT_NAME;
myExtn.Value = myBlobdata;
CERT_EXTENSIONS myExtns_list;
myExtns_list.cExtension = 1;
myExtns_list.rgExtension = &myExtn;
char cb[20] = { "DNS Names=abc.com" };
BYTE *pbData = (BYTE*)cb;
CERT_NAME_BLOB myBlobdata;
myBlobdata.cbData = 20;
myBlobdata.pbData = pbData;
有了这个,我可以在左窗格中以字节格式获取 SAN,右窗格显示我的字符串“DNS Names=abc.com”。
但我的要求是仅显示 SAN 中的 DNS 名称。
解决方案
我假设您的扩展数据的构建实际上发生在您调用之前CertCreateSelfSignedCertificate
(同样,您的构建myBlobdata
发生在使用它之前)。
主要问题是您使用了一个 SAN 条目(某种)作为整个 SAN 扩展;这意味着您丢失了一些编码包装器。第二个问题是您使用了 ,这是您实际想要的szOID_SUBJECT_ALT_NAME
主题备用名称的不正确 OID...。szOID_SUBJECT_ALT_NAME2
我要添加以下内容:DNS 名称=完全限定域名、DNS 名称=主机名和 DNS 名称=IP
添加 IP 地址作为 DNS 名称是非标准的,应该会导致匹配失败。您实际上希望将 IP 地址添加为 IP 地址 SAN 条目。
CERT_ALT_NAME_ENTRY entries[3];
entries[0] = { CERT_ALT_NAME_DNS_NAME };
entries[0].pwszDNSName = L"example.org";
// IPv4 Address 10.12.1.130
BYTE ip4Bytes[] = { 10, 12, 1, 130 };
entries[1] = { CERT_ALT_NAME_IP_ADDRESS };
entries[1].IPAddress = { sizeof(ip4Bytes), ip4Bytes };
// ::1, big-endian
BYTE ip6Bytes[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
entries[2] = { CERT_ALT_NAME_IP_ADDRESS };
entries[2].IPAddress = { sizeof(ip6Bytes), ip6Bytes };
CERT_NAME_BLOB name = { cbEncoded, buf };
BYTE extBuf[1024] = { 0 };
cbEncoded = sizeof(extBuf);
CERT_ALT_NAME_INFO info = { sizeof(entries) / sizeof(CERT_ALT_NAME_ENTRY), entries };
if (!CryptEncodeObjectEx(
X509_ASN_ENCODING,
X509_ALTERNATE_NAME,
&info,
0,
nullptr,
extBuf,
&cbEncoded))
{
// Whatever your error handling story is.
//
// Note I didn't do a 0 buffer or CRYPT_ENCODE_ALLOC; I just knew
// that my buffer would be big enough.
}
CERT_EXTENSION extension = { 0 };
extension.fCritical = 0;
extension.pszObjId = szOID_SUBJECT_ALT_NAME2;
extension.Value = { cbEncoded, extBuf };
CERT_EXTENSIONS extensions = { 1, &extension };
...
PCCERT_CONTEXT cert = CertCreateSelfSignCertificate(
0,
&name,
0,
&keyProvInfo,
&sigAlg,
0,
&certExpirationDate,
&extensions);
在 CertUI 中,它给了我期望的主题备用名称值:
DNS Name=example.org
IP Address=10.12.1.130
IP Address=0000:0000:0000:0000:0000:0000:0000:0001
推荐阅读
- python - 自动确定绘图大小 matplotlib
- ruby-on-rails - 控制器“params”在测试环境和开发环境中表现不同
- c# - COM 端口在看似随机的时间变得忙碌
- node.js - 我在 Mongoose 中使用“创建”变得不确定
- vue.js - 从 vuex 和 Vue-native-websocket 插件接收 WebSockets 数据
- reactjs - 部署到 github 后我得到一个空白页面,没有任何错误
- actions-on-google - 是否有可以让我向 Google Assistant 发送命令的 API
- excel - 如何文本框检查自身
- python - Python3在文件夹中创建图像列表
- r - 在 R 中绘制社区矩阵