为什么某些证书的Request.ClientCertificate为空,而另一些证书则为空?

时间:2018-11-01 19:01:25

标签: c# ssl iis ssl-certificate

我正在尝试构建一个AuthorizeAttribute,该属性要求HTTPRequest包含指定的客户端证书。

我发现我认为是Andras Nemes撰写的一系列有关此问题的博客文章,

我有一个在VS2015中运行的测试Web API项目,针对在我的本地IIS(而不是IIS Express)上运行的站点进行调试,并配置了https和SSL设置以允许客户端证书。

我非常确定它的设置正确,因为它对于我创建的证书之一都可以正常工作。

我的属性很简单:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class KtRequireClientCertAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        byte[] cert = HttpContext.Current.Request.ClientCertificate.Certificate;
        // if the ClientCertificate is empty, pass null
        X509Certificate2 suppliedCert = cert.Any() ? new X509Certificate2(cert) : null;

        if (suppliedCert != null && isExpectedCert(suppliedCert)
            return;

        base.OnAuthorization(actionContext);
    }
}

我的问题-上周我按照安德拉斯(Andras)的指示创建的其中一张证书可以正常工作。

ClientCertificate.Certificate是一个包含808个元素的byte [],X509Certificate2可以正确构造,并且我的验证逻辑可以按预期工作。

但是对于我今天尝试创建的每个证书,HttpContext.Current.Request.ClientCertificate.Certificate为空。

我正在制作证书:

MAKECERT.EXE -ic DevRootCertificate.cer -iv DevRootCertificate.pvk -pe -sv testclientcert.pvk -a sha1 -n "CN=testclientcert" -len 2048 -b 01/01/2015 -e 01/01/2030 -sky exchange testclientcert.cer -eku 1.3.6.1.5.5.7.3.2

我的测试客户端应用很简单:

using (var requestHandler = new WebRequestHandler())
{
    var certificate = new X509Certificate2(certificateFile);
    requestHandler.ClientCertificates.Add(certificate);

    var url = new Uri(baseUrl);
    using (var client = new HttpClient(requestHandler){BaseAddress = url})
    {
        var response = client.GetAsync(endPoint).Result;
        response.EnsureSuccessStatusCode();

        var content = response.Content.ReadAsStringAsync().Result;

        Console.Out.WriteLine(JToken.Parse(content).ToString(Formatting.Indented));
    }
}

问题是为什么一个证书传递给属性,而另一个证书不传递给属性?


其他信息:

我正在同一台服务器上运行同一客户端,并在本地计算机上的IIS上运行。该网站配置为接受但不要求客户证书。

一个有效的测试运行与一个无效的测试运行之间的唯一区别是,我从哪个.cer文件加载了证书。

我不确定有效的证书是否具有私钥,但有效的文件是.cer,而不是.pfx。

无效的文件也是.cer。而且我知道它没有签名。因此,我创建了一个签名证书,并尝试使用.pfx文件构造X509Certificate2()。我没有连服务器都收到403错误。

1 个答案:

答案 0 :(得分:0)

第一个问题

  • 为什么在没有真正进入控制器动作的情况下出现403错误?

Web服务器和客户端协商客户端将发送什么证书。服务器发送将接受的签名授权机构列表,客户端发送可接受的证书。

如果您正在使用自签名证书,则要做的第一件事就是创建一个根证书,并将其公钥作为“受信任的根证书颁发机构”导入到当前的用户证书存储中。

然后,您需要对运行Web服务器的计算机的计算机存储区执行相同的操作。客户端和服务器都需要将根证书视为受信任的权威,否则,他们将永远不会同意由它签名的任何证书。

第二个问题

  • 为什么我几天前创建的客户证书有效,而自那以后我创建的客户证书为什么有效?

一个有效的文件是.cer文件,为什么当其他.cer文件不起作用时又可以工作?

当然是私钥。

但是,您说.cer文件没有私钥。是的,他们没有。但是.cer文件对我有用,是从用户存储中导出的。

也就是说,我将证书创建为.cer和.pvk文件,然后将两者组合成.pfx文件。

我将.pfx文件导入到我的用户存储中,然后将其导出到.cer文件中。

当我的客户端加载export.cer文件时,它知道私钥是有效的,因为它位于用户存储中,因此在创建X509Certificate2对象时不需要提供密码。

当我尝试对用户存储区中没有的证书执行相同操作时,无法使用.cer文件。使用.pfx文件可以-如果我提供了密码。

var certificate = new X509Certificate2("testcert.pfx", "Password1");