解析“;证书策略”;扩大

本文关键字:扩大 策略 证书 解析 | 更新日期: 2023-09-27 18:25:39

我的应用程序中有一个证书(X509Certificate2),我可以枚举所有证书的扩展。其中一个扩展是证书策略,OID为2.5.29.32。这个扩展应该只是一个OID序列,我需要在那里搜索特定的OID。问题是这个扩展被编码为DER八位字节字符串。如何获取我感兴趣的OID?我必须手动解析DER八位字节字符串吗?我该怎么做?

编辑:我想看看Bouncy Castle能提供什么,但我想知道在.NET框架中是否有现成的解决方案。框架解析证书和其他DER结构,因此可能内置DER解码器。

BOUNTY:我已经找到了一个解决方案,但我正在寻求改进。如果Bounty满足以下一个或多个条件,则返回其他解决方案,按相关性排序:

  1. 它使用标准的.NET库函数
  2. 它使用了成熟的或经过验证的源代码或库,比BouncyCastle小(我只需要解析,不需要所有其他)
  3. 它只是在我认为有价值的事情上改进了我现有的代码

BUMP:赏金今天到期。如果没有其他人提供答案,那就交给卡拉狄格杰洛。

解析“;证书策略”;扩大

我能够使用extension.Format():获得字符串表示

foreach (X509Extension extension in certificate.Extensions)
{
    if(extension.Oid.FriendlyName.Equals("Certificate Policies"))
    {
        Console.WriteLine(extension.Format(true));
    }
}

我得到的输出看起来是这样的:

[1]Certificate Policy:
    Policy Identifier=2.16.356.100.2.3

这正是使用certmgr.msc工具查看证书时显示的内容。这告诉我CCA印度定义的证书类别。例如,这是一个3级证书。

我就是这样做的(但也阅读下面的更新)。Bouncy Castle用于解析ASN.1 DER。

using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.Asn1.X509;
string GetMeTheOidThatIWant(byte[] certificate)
{
    X509CertificateParser parser = new X509CertificateParser();
    X509Certificate cert1 = parser.ReadCertificate(certificate);
    X509Extension certPolicies =
        cert1.CertificateStructure.TbsCertificate.Extensions.GetExtension(X509Extensions.CertificatePolicies);
    DerSequence seq = certPolicies.GetParsedValue() as DerSequence;
    foreach (Asn1Encodable seqItem in seq)
    {
        DerSequence subSeq = seqItem as DerSequence;
        if (subSeq == null)
            continue;
        foreach (Asn1Encodable subSeqItem in subSeq)
        {
            DerObjectIdentifier oid = subSeqItem as DerObjectIdentifier;
            if (oid == null)
                continue;
            if (ThisIsTheOneIWant(oid))
                return oid.Id;
        }
    }
}

更新:我最近偶然发现CryptFormatObject函数支持证书策略OID(szOID_CERT_POLICIES)。没有尝试该功能,但它看起来很有用。5分钟后,我注意到这正是Kinjal Dixit在回答中所描述的。

如果您只想减少解析ASN.1所需的代码,您可以查看ASN.1编辑器项目的LCLib部分。

它是一个简单的ASN.1处理器库。

使用样本DER编码的测试串"0";test1@rsa.com":

16 0d 74 65 73 74 31 40 72 73 61 2e 63 6f 6d

using (var stm = new MemoryStream(new byte[] { 0x16, 0x0d, 0x74, 0x65, 0x73, 0x74, 0x31, 0x40, 0x72, 0x73, 0x61, 0x2e, 0x63, 0x6f, 0x6d })) 
{ 
    Asn1Parser parser = new Asn1Parser(); 
    parser.LoadData(stm); 
    var decoded = parser.ToString(); 
} 

提供格式化输出:

偏移|Len|LenByte|

===============================

 0|    13|      1| IA5 STRING : 'test1@rsa.com'

您可以遍历树,并根据需要处理节点。

一年前我遇到了这个问题。我找到了一个对我帮助很大的小图书馆(网站)。这个库将文件密钥转换为xml(使用.exe),然后我们可以在C#上读取它。

我不喜欢用XML转换密钥。我请求库的开发人员在我的项目中使用开源代码,幸运的是他接受了。所以我做了一个叉子,正好可以满足我的需要。

经过很长时间,我在Mono项目中找到了另一个实现,可以在这里找到

这里是使用CryptoLib的助手类,这里是一个示例:

public IRegistryService Connect(String name, RSACryptoServiceProvider privateKey, X509Certificate2 acsCertificate) {
  if ((String.IsNullOrEmpty(name)) || (acsCertificate == null) || (privateKey == null))
    throw new ArgumentException("....");
  if (!String.IsNullOrEmpty(this.Credential.identifier))
    throw new ACSLoginFailureException("....");
  byte[] challenge = this.acs.getChallenge(name);      
  byte[] answer = new byte[0];
  try {
    answer = Crypto.GenerateAnswer(challenge, privateKey, acsCertificate);
  }
  catch (CryptographicException e) {
    throw new ACSLoginFailureException("....", e);
  }
  bool connect = this.acs.loginByCertificate(name, answer, out this.credential, out leaseTime);      
  // ...
}

这里的问题是证书策略字段的格式不标准。其内容不是由IETF RFC定义的,而是由CA浏览器论坛定义的。它用于表示扩展验证证书。

这是来自"www.bankofamerica.com"的字段

顺序:ObjectIdentifier:2.5.29.32证书策略八进制字符串:(48,59,48,57,6,11,96,134,72,1,134,248,69,1,7,23,6,48,42,48,40,6,8,43,6,1,5,5,7,2,1,22,28,104,116,116,112,115,58,47,47,119,119,46,118,101,114,105,105,103,110,46,99,111,109,47,114,112,97)ASCII形式的OctetString:"0;09''x06''x0b`''x86H''x01''x86''x68E''x01''x07''x17''x60*0(''x06''x08+''x06''x01''x05''x07''x02''x01''x16''x1chttps://www.verisign.com/rpa'

这是用一个使用Python库"pyasn1"的小程序转储的,该库可以解析DER和PEM格式的数据。问题是CertificatePolicy的值是ASN1类型的"OctetString",这意味着它只是ASN1的原始字节。大多数其他字段都是有用的类型,如PrintableText、Integer或Date,但这一个没有。

1999年的RFC2527只是对此挥手致意;有一个地方应该填写这些信息,但没有。OpenSSL文档(http://www.openssl.org/docs/apps/x509v3_config.html)说:"原始扩展的语法由扩展代码控制:例如,它可以包含多个部分中的数据。使用的正确语法由扩展码本身定义:例如,查看证书策略扩展。"CAB论坛EV证书指南(http://www.cabforum.org/EV_Certificate_Guidelines.pdf)定义该字段中的内容(请参阅附录B),但格式请参阅RFC3280。RFC3280表示:"证书策略扩展包含一个或多个策略信息项的序列,每个项都由对象标识符(OID)和可选限定符组成。可能存在的可选限定符不会更改策略的定义。"因此,它应该是包含OID和"可选限定符"的ASN1项序列。但这并不是电动汽车证书实际包含的内容。

至于电动汽车证书允许的OID,没有公开的官方名单。CA浏览器论坛有一个与其成员共享的私人列表。但在维基百科上找一个非官方的。

稍后我会弄清楚格式。