问题描述
我正在针对执行客户端证书身份验证的 Web 服务器编写代码.我用我的证书链创建了一个 WebRequestHandler,将它传递给一个 HttpClient 对象,然后在 HttpClient 上调用 PostAsync.这适用于未撤销的信任链上的有效证书.当证书被吊销(正如预期的那样)并且 Exception 成员包含此聚合异常时,HttpResponseMessage 任务会出错:
I'm writing code against a web server that does client certificate authentication. I make a WebRequestHandler with my certificate chain, pass that into a HttpClient object and then call PostAsync on the HttpClient. This works fine with a valid certificate on the chain of trust that is not revoked. The HttpResponseMessage task faults when the certificate is revoked (as is expected) and Exception member contains this aggregate exception:
发送请求时出错.
请求被中止:无法创建 SSL/TLS 安全通道.
The request was aborted: Could not create SSL/TLS secure channel.
我的问题是我需要一个更详细的错误.如果我从 Chrome 执行相同的操作(提交相同的已撤销客户端证书),则会出现此错误:
My problem is that I need a more verbose error. If I do the same thing (submit the same revoked client certificate) from Chrome I get this error:
ERR_BAD_SSL_CLIENT_AUTH_CERT
ERR_BAD_SSL_CLIENT_AUTH_CERT
来自 Internet Explorer:
And from Internet Explorer:
ERROR_INTERNET_SEC_CERT_REVOKED
ERROR_INTERNET_SEC_CERT_REVOKED
我怎么能得到这样的错误?我不仅需要告诉用户它没有用,还要告诉用户为什么.浏览器得到更精确的错误这一事实似乎表明更多信息正在返回,而不仅仅是错误异常.似乎不是因为故意混淆.
How can I get such an error? I need to tell the user not only that it didn't work but WHY. The fact that browsers get a more precise error seems to indicate that more information is coming back that just the fault exception. It doesn't seem to be because of intentional obfuscation.
代码示例:
WebRequestHandler handler = new WebRequestHandler();
if (certCol != null)
{
foreach (X509Certificate2 cert in certCol)
{
handler.ClientCertificates.Add(cert);
}
}
else
{
sLastErr = "Could not find client certificate to communicate. Certificate collection is NULL.";
LogHelper.LogGenericError(
_logger,
sLastErr
);
return false;
}
_HttpClient = new HttpClient(handler);
_HttpClient.PostAsync(uriCM, reqContent).ContinueWith(requestTask =>
{
HttpResponseMessage httpRespContent = null;
bool bSuccess = false;
if (requestTask.IsCompleted)
{
if (requestTask.Status == TaskStatus.RanToCompletion)
{
httpRespContent = requestTask.Result;
bSuccess = true;
}
else if(requestTask.Status == TaskStatus.Faulted)
{
if (requestTask.Exception != null)
{
LogHelper.LogErrorWithAggregateException(_logger, "PostAsync call faulted.", requestTask.Exception);
//exception messages in aggregate exception:
//An error occurred while sending the request.
//The request was aborted: Could not create SSL/TLS secure channel.
}
else
LogHelper.LogError(_logger, "PostAsync call faulted.");
}
else
{
LogHelper.LogError(_logger, "PostAsync call failed.");
}
}
else
{
LogHelper.LogError(_logger, "PostAsync call never completed. Communication Failure.");
}
if (bSuccess)
{
//it worked, do stuff... }
}
});
推荐答案
SslStream 抛出一个 Win32 异常,报告证书被吊销(如果证书被吊销).就像浏览器一样.似乎在较低级别击中 Schannel 或一些非托管代码并将其管道化.如果 HttpClient 返回 TLS 错误,我会运行我的代码以尝试建立 SslStream+TcpClient 连接并报告异常.我猜 HttpClient 只是隐藏了错误细节,而 SslStream 将它暴露在一个内部异常中.解决了我的问题.
SslStream throws a Win32 exception that reports that the certificate is revoked if it is revoked. Like the browsers. Seems to be hitting Schannel or some un-managed code at a lower level and piping it up. If HttpClient returns a TLS error, I run my code to try to make a SslStream+TcpClient connection and report the exception. I guess HttpClient just buries the error details and SslStream exposes it in an inner exception. Solves my problem.
示例代码:
public bool VerifyThatCanAuthenticateAsClient()
{
bool bSuccess = false;
TcpClient tcpClient = null;
SslStream sslStream = null;
try
{
tcpClient = new TcpClient(
_sHostname,
_iPort
);
bSuccess = true;
}
catch(Exception ex)
{
//log exception
}
if(bSuccess)
{
bSuccess = false;
try
{
sslStream = new SslStream(
tcpClient.GetStream(),
false,
new RemoteCertificateValidationCallback(ValidateServerCertificate),
new LocalCertificateSelectionCallback(SelectLocalCertificate),
EncryptionPolicy.RequireEncryption
);
bSuccess = true;
}
catch (Exception ex)
{
//log exception
}
}
if (bSuccess)
{
bSuccess = false;
try
{
sslStream.AuthenticateAsClient(
_sHostname,
null,
System.Security.Authentication.SslProtocols.Tls12,
false
);
bSuccess = true;
}
catch (Exception ex)
{
//log ex.message exception
if(ex.InnerException != null)
{
//log ex.innerexception.message
//this is what gives me the low level error that means its revoked if it is, or other specific tls error
}
}
}
if(sslStream != null)
{
sslStream.Dispose();
}
if(tcpClient != null)
{
tcpClient.Dispose();
}
return bSuccess;
}
这篇关于在吊销的证书上从 HttpClient 返回更详细的错误消息?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!