我想使用C++在Win32中验证SSL证书。我想我想使用Cert* API,这样我就可以从Windows证书存储中获益。这就是我想出来的。
bool IsValidSSLCertificate( PCCERT_CONTEXT certificate, LPWSTR serverName )
{
LPTSTR usages[] = { szOID_PKIX_KP_SERVER_AUTH };
CERT_CHAIN_PARA params = { sizeof( params ) };
params.RequestedUsage.dwType = USAGE_MATCH_TYPE_AND;
params.RequestedUsage.Usage.cUsageIdentifier = _countof( usages );
params.RequestedUsage.Usage.rgpszUsageIdentifier = usages;
PCCERT_CHAIN_CONTEXT chainContext = 0;
if ( !CertGetCertificateChain( NULL,
certificate,
NULL,
NULL,
¶ms,
CERT_CHAIN_REVOCATION_CHECK_CHAIN,
NULL,
&chainContext ) )
{
return false;
}
SSL_EXTRA_CERT_CHAIN_POLICY_PARA sslPolicy = { sizeof( sslPolicy ) };
sslPolicy.dwAuthType = AUTHTYPE_SERVER;
sslPolicy.pwszServerName = serverName;
CERT_CHAIN_POLICY_PARA policy = { sizeof( policy ) };
policy.pvExtraPolicyPara = &sslPolicy;
CERT_CHAIN_POLICY_STATUS status = { sizeof( status ) };
BOOL verified = CertVerifyCertificateChainPolicy( CERT_CHAIN_POLICY_SSL,
chainContext,
&policy,
&status );
CertFreeCertificateChain( chainContext );
return verified && status.dwError == 0;
}
发布于 2014-02-28 21:53:10
您应该知道RFC3280 section 6.1和RFC5280 section 6.1。两者都描述了验证证书路径的算法。尽管Win32应用程序接口为您处理了一些事情,但了解该过程的大体情况仍然是有价值的。
此外,这里有一个(在我看来)非常值得信赖的参考:Chromium certificate verification code。
总的来说,我认为你的代码不是错误的。但是,如果我是你,我会考虑/改变一些事情:
1.单独的通用名称验证
铬与链分开验证证书通用名称。显然,他们注意到了其中的一些问题。请参阅评论以了解它们的基本原理:
cert_verify_proc.win.cc:731 // Certificate name validation happens separately, later, using an internal
cert_verify_proc.win.cc:732 // routine that has better support for RFC 6125 name matching.
2.使用CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT
of还使用CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT标志而不是CERT_CHAIN_REVOCATION_CHECK_CHAIN。实际上,在我找到他们的代码之前,我就已经开始研究这个问题了,这让我更加坚信你应该使用CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT.
尽管上述两个RFC都指定自签名信任锚不被视为链的一部分,但CertGetCertificateChain (http://msdn.microsoft.com/en-us/library/windows/desktop/aa376078(v=vs.85).aspx )的文档表示,如果可能,它会构建一个链,直到信任的根证书为止。受信任的根证书(在同一页上)定义为受信任的自签名证书。
这消除了*EXCLUDE_ROOT可能跳过对非根信任锚的撤销检查的可能性(Win32实际上要求信任锚是自签名的,即使它不是任何RFC所必需的。虽然这并没有正式的文档)。
现在,由于根CA证书不能撤销自身( CRL不能被签名/验证),在我看来这两个标志是相同的。
我用谷歌搜索了一下,偶然发现了这个论坛帖子:http://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/9f95882a-1a68-477a-80ee-0a7e3c7ae5cf/x509revocationflag-question?forum=windowssecurity。CDP产品组的一名成员(假设)声称,如果根是自签名的,那么实际上这些标志的作用是相同的(理论上,如果根证书包含.NET扩展,ENTIRE_CHAIN标志将检查根证书的吊销,但这不可能发生)。
他还建议使用*EXCLUDE_ROOT标志,因为如果自签名根CA包括CDP扩展,则其他标志可能会导致不必要的网络请求。
不幸的是:
为了完全确定可以使用CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT,,我在谷歌上搜索了一下,在回复的顶部找到了我链接的Chromium SSL证书验证码。
作为额外的好处,Chromium cert_verify_proc_win.cc文件包含以下有关IE验证码的提示:
618: // IE passes a non-NULL pTime argument that specifies the current system
619: // time. IE passes CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT as the
620: // chain_flags argument.
不知道他们是怎么知道的,但在这一点上,我会觉得使用CERT_CHAIN_REVOCATION_CHECK_EXCLUDE_ROOT很舒服。
3.不同的接受证书用法
我注意到Chromium还指定了3种证书用法,而不是1种:
szOID_PKIX_KP_SERVER_AUTH,
szOID_SERVER_GATED_CRYPTO,
szOID_SGC_NETSCAPE
从我通过Google收集到的信息来看,其他用法可能是较旧的web浏览器所必需的,否则它们可能无法建立安全连接。
如果Chromium认为适合包含这些用法,我也会效仿。
请注意,如果更改代码,还应将params.RequestedUsage.dwType设置为USAGE_MATCH_TYPE_OR而不是USAGE_MATCH_TYPE_AND。
-
目前我想不出任何其他的评论。但如果我是你,我会自己去看看Chromium源码(也许还有Firefox )--只是为了确保我没有错过任何东西。
发布于 2014-02-22 14:14:02
我认为最好的答案取决于你到底想做什么。
我要提醒您的是,SSL是基于两个端点都需要安全连接的假设。如果任何一个端点对维护安全性不感兴趣,那么就没有端点。
将字节码放入您的分布式代码中,只需为此函数返回true,这是一项微不足道的工作。这就是为什么windows将大量的验证转移到内核中的原因。但他们没有预料到人们会在虚拟硬件上运行windows,这使得绕过操作系统变得如此微不足道。
现在,假设您希望从某个来源获得证书,但又假装无法从可靠的来源获得相同的信息。然后把它交给你。因此,您不能依赖证书来“证明”任何人是特定的人。
从证书获得的唯一保护是防止外部人员(而不是端点)破坏正在传输的消息的机密性。
任何其他的使用都是注定要失败的,它最终也会失败,并带来潜在的灾难性后果。
很抱歉发了这么大的帖子。评论部分有字数限制。
发布于 2015-01-27 19:37:14
函数CertGetCertificateChain
和CertVerifyCertificatePolicy
一起使用。这部分是正确的。
对于CertGetCertificateChain
,如果要检查吊销,可以将该标志设置为以下三项中的任意一项:
只能使用其中一个,这三个选项不能为ORed
。除了这些标志之外,您还可以考虑应该如何创建链;使用local cache
,或者只使用CRL
或OCSP
。出于这些考虑,read this link。
执行函数时出错,或者更简单地说,如果返回值为0
,并不意味着证书无效,而是您无法执行操作。有关错误信息,请使用GetLastError()
。所以你返回false的逻辑是错误的,它更像是抛出错误,让客户端代码决定是重试还是继续做其他事情。
在this link中有一个名为“对错误进行分类”的部分,请阅读。基本上你应该检查一下certChainContext->TrustStatus.dwErrorStatus. Here a list of error statuses will be ORed. Please check CERT_TRUST_STATUS
的msdn参考。因此,您可以在这里拥有您的业务逻辑。例如,如果您发现证书吊销检查无法执行的值的错误状态(CERT_TRUST_REVOCATION_STATUS_UNKNOWN | CERT_TRUST_IS_OFFLINE_REVOCATION
),您可以选择您想要的证书(放弃证书或仍然将其标记为无效)。
因此,在调用CertVerifyCertificatePolicy
之前,您可以选择放弃或已标记验证错误。
如果你选择使用CertVerifyCertificatePolicy
,关于如何将policy_status.dwError映射到你的错误类/枚举,铬代码是一个很好的参考。
https://stackoverflow.com/questions/7340504
复制相似问题