目前我正在尝试验证来自第三方的邮件。 我遇到的问题是无法创建信任链。 原因是主题名称(X509SubjectName)中的项目顺序在证书中与从包含的证书中提取它们时的顺序不同。
每个例子: 在xades-t消息中,x509SubjectName标记具有: “C = NL,O =测试公司,CN = testuser,SERIALNUMBER = 1” 其中包含在证书中的x509SubjectName具有: “SERIALNUMBER = 1,CN = testuser,O =测试公司,C = NL”
我的问题是这是否允许。 如何更改Xades4j行为以验证这些签名消息。 因为我似乎没有SignatureUtils类中的证书。代码似乎能够处理但是使用的地图是空的。
此致 皮姆
答案 0 :(得分:1)
在RFC2253文件第2.1节中,它说:
2.1。转换RDNSequence
如果RDNSequence为空序列,则结果为空或 零长度字符串。
否则,输出由每个字符串编码组成 RDNSequence中的RelativeDistinguishedName(根据2.2),
从序列的最后一个元素开始并向后移动
走向第一个。相邻RelativeDistinguishedNames的编码是分开的 用逗号字符(','ASCII 44)。
因此,无论顺序是什么,您都需要颠倒顺序。因此,我认为您应首先检查您的实现,并确保您反转相对专有名称的顺序。
答案 1 :(得分:0)
由于我没有找到任何文档,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将依赖于关键命名不包含','的事实。因此,我首先拆分'=',然后拆分最后','。 可行的是regexp outthere也可以做到这一点。 (不幸的是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;
}