【问题标题】:How to validate Xades-t message when the order of the attributes in the x509SubjectName differ from the order in the certificate当 x509SubjectName 中的属性顺序与证书中的顺序不同时如何验证 Xades-t 消息
【发布时间】:2012-12-04 20:12:05
【问题描述】:

目前我正在尝试验证来自第三方的消息。 我遇到的问题是无法创建信任链。 原因是主题名称(X509SubjectName)中的项目在证书中的顺序与从包含的证书中提取它们时的顺序不同。

例如: 在 xades-t 消息中,x509SubjectName 标记具有: "C=NL,O=测试公司,CN=testuser,SERIALNUMBER=1" 其中证书中包含的 x509SubjectName 具有: "SERIALNUMBER=1,CN=testuser,O=Test company,C=NL"

我的问题是这是否被允许。 以及如何更改 Xades4j 行为以验证这些签名消息。 因为我似乎没有 SignatureUtils 类中的证书。代码好像可以处理,但是使用的地图是空的。

问候, 皮姆

【问题讨论】:

  • DN 应该是等价的。你确定这是你的问题的原因吗?我只记得有一个比较 DN 的地方是发行人的 DN,而不是主题的。
  • 你好,我写了一个具体的类来测试一下情况。
  • 嗨,我写了一个特定的类来测试情况。在一个实例中,我从 xades 消息中获得了 DN。哪个失败了。 (错误消息是它无法验证信任链)第二次调用我使用了相同的证书,但从证书本身检索了 DN。然后我得到了一个验证器。所以也不例外。因此我打印了两个版本的 DN。这给了我上面的细节。
  • 问题出在类 xades4j.utils.PropertiesUtils.java 中。在方法 processKeyInfo 中,如果从签名中检索 DN。然后使用它来实例化 KeyInfo 对象。在 xades4j.providers.impl.PKIXCertificateValidatinProvidor 中使用它来实例化 java.security.cert.certPathBuilder。在此实例化期间,“错误”DN 用于构建信任链。错误意味着从 DN 中纠正项目但顺序错误。 (要明确证书顺序是奇怪的。DN,从 xades 消息中,顺序符合 LDAP 结构)

标签: xades4j


【解决方案1】:

在 RFC2253 文档第 2.1 节中,它说:

2.1。转换 RDNS 序列

如果 RDNSequence 为空序列,则结果为空或 零长度字符串。

否则,输出由每个字符串编码组成
RDNSequence中的RelativeDistinguishedName(根据2.2),
从序列的最后一个元素开始并向后移动
走向第一。

相邻的RelativeDistinguishedNames的编码是分开的 通过逗号字符 (',' ASCII 44)。

所以,无论顺序是什么,您都需要颠倒顺序。因此,我认为您应该首先检查您的实现,并确保您颠倒了相对可分辨名称的顺序。

【讨论】:

  • 您好,感谢您的回复。我认为这是问题的原因。但是,需要对框架进行更改。
【解决方案2】:

通过更改 xades4j 行为的解决方法。

因为我没有找到任何文档证明 X509SubjectName 中的属性顺序需要与关联证书中的 DN 顺序相同。我认为稳健性需要以下补丁。

如果 xades4j.verification.SignatureUtil.java 决定依赖主题名。它不应该只是继续使用它,而是应该验证主题名是否与证书中的主题名相同。这不能通过比较完整的字符串来完成。取而代之的是,两个主题名称都需要解组并根据它们的关联进行比较。

首先选择行为需要改变一点: 不要只使用主题名,而是首先从证书中检索 DN,然后比较它们的值。如果它们使用完整的字符串不匹配,它们应该可以匹配它们的实际内容。因此,我们需要获取两个 DN 的属性。当没有发现差异时,我们仍在处理相同的 DN。 在这种情况下,框架不能依赖主题名从证书存储中检索证书。而是将证书提供给 KeyInfo 对象。 (那会被发现的!)

        if (x509Data.containsIssuerSerial()) {
            issuerSerial = x509Data.itemIssuerSerial(0);
            certSelector.setIssuer(new X500Principal(issuerSerial.getIssuerName()));
            certSelector.setSerialNumber(issuerSerial.getSerialNumber());
        } else if (x509Data.containsSubjectName()) {
            String subjectName = x509Data.itemSubjectName(0).getSubjectName();
            X500Principal msgPrincipal = new X500Principal(subjectName);
            String name = msgPrincipal.getName();

            X509Certificate crt = x509Data.itemCertificate(0).getX509Certificate();
            X500Principal crtPrincipal = crt.getSubjectX500Principal();

            X500Principal prinFromCrt = crt.getSubjectX500Principal();
            if(prinFromCrt.getName().equals(msgPrincipal.getName())){
                // Continue using the xades specified subjectname
                 certSelector.setSubject(msgPrincipal);
            } else {
                //so the subject names are not equal.
                //However the ietf specifications indicate you cannot rely on the order of the attributed.
                //Therefor we need to compare all attributes seperately to know for sure.

               boolean hasSameKeyValues = compareUnmarshelledX500PrincipalAttr(crtPrincipal,msgPrincipal);
               if (hasSameKeyValues){

                   if (x509Data.containsCertificate()) {
                       certSelector.setCertificate(x509Data.itemCertificate(0).getX509Certificate());
                   }
               }    
            }

        } else if (x509Data.containsCertificate()) {
            certSelector.setCertificate(x509Data.itemCertificate(0).getX509Certificate());
            if (x509Data.containsSubjectName()){
                //if(!(isEqualX500Elements(new X500Principal(x509Data.itemSubjectName(0).getSubjectName()), x509Data.itemCertificate(0).getX509Certificate()))){
                //     throw new InvalidKeyInfoDataException("X509Subject name differs from Subject name in certificate.");
                //}
            }
        } else
        // No criteria to select the leaf certificate.
        // Improvement: search the SigningCertiticate property and try to
        // find the "bottom" certificate.
        {
            throw new InvalidKeyInfoDataException("No criteria to select the leaf certificate");
        }

下面是一个方法,它接受 DN 并请求包含键及其值的 HashMap。 无论它们是否相同,它都会返回一个布尔值。

       private static boolean compareUnmarshelledX500PrincipalAttr(X500Principal DN1, X500Principal DN2) {
       HashMap attrDNCrt = splitDNAttr(DN1.getName());
       HashMap attrDNMsg = splitDNAttr(DN2.getName());

       if(attrDNCrt.keySet().equals(attrDNMsg.keySet())){
           Set ks = attrDNCrt.keySet();
           Iterator iKS = ks.iterator();
           while (iKS.hasNext()){
               String key = (String) iKS.next();
               if(!attrDNCrt.get(key).toString().equals(attrDNMsg.get(key).toString())){
                   //Value of attribute is different. So not identical
                   return false;
               }
           }
           //Yes, despite possible differences in order the key value pairs are identical.");
           return true;
       } else {
           //"KeySets differ so they are different"
           return false;
       }
}

splitDNAttr 将依赖于密钥命名不包含“,”这一事实。因此,我首先在“=”上拆分,然后在最后一个“,”上拆分。 可能有正则表达式也可以解决问题。 (不幸的是,RegEx 对我来说完全不可读。) 这些方法对我有用,但我想知道是否需要删除可能的尾随空格”?

static private HashMap splitDNAttr(String inputStr){
    String[] strings;
    List looseElements;
    looseElements = new ArrayList();
    //First split on the = which normally isn't escaped.
    strings = inputStr.split("=");        
    looseElements.add(strings[0]);
    //Loop Through string members

    int i=1;
    while (i<strings.length){
        String[] subStrings;
        //Look for the last comma, everything after is a key! This is because we have splitted the string on '='
        int splitPos = strings[i].lastIndexOf(",");
        if(splitPos>=0){
            //Add all found items to a list. Order must be maintained!
            String A = strings[i].substring(0,splitPos);
            looseElements.add(strings[i].substring(0,splitPos));
            String B = strings[i].substring(splitPos+1);
            looseElements.add(strings[i].substring(splitPos+1));
        } else {
            looseElements.add(strings[i]);
        }
        i++;
    }

    // Put key and values in a HashMap
    HashMap dnAttr = new HashMap();
    Iterator iLooseElements;
    iLooseElements = looseElements.iterator();
    String a;
    String b;
    while(iLooseElements.hasNext()){
        a = (String) iLooseElements.next();
        b = (String) iLooseElements.next();
        dnAttr.put(a, b);
    }
    return dnAttr;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-07-19
    • 2012-01-21
    • 2023-03-04
    • 2010-11-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多