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は、キーの名前に「、」が含まれないという事実に依存します。そのため、最初に「=」で分割し、次に最後の「、」で分割します。おそらく、そのトリックを実行する正規表現がそこにあります。(残念ながら、正規表現は私には完全に読めません。)メソッドは私には機能しますが、可能性のある末尾のスペースを削除する必要があるかどうか疑問に思います。
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;
}