package org.bouncycastle.asn1.x500.style;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1ParsingException;
import org.bouncycastle.asn1.DERUTF8String;
import org.bouncycastle.asn1.x500.AttributeTypeAndValue;
import org.bouncycastle.asn1.x500.RDN;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x500.X500NameStyle;
This class provides some default behavior and common implementation for a
X500NameStyle. It should be easily extendable to support implementing the
desired X500NameStyle.
/**
* This class provides some default behavior and common implementation for a
* X500NameStyle. It should be easily extendable to support implementing the
* desired X500NameStyle.
*/
public abstract class AbstractX500NameStyle
implements X500NameStyle
{
Tool function to shallow copy a Hashtable.
Params: - paramsMap – table to copy
Returns: the copy of the table
/**
* Tool function to shallow copy a Hashtable.
*
* @param paramsMap table to copy
* @return the copy of the table
*/
public static Hashtable copyHashTable(Hashtable paramsMap)
{
Hashtable newTable = new Hashtable();
Enumeration keys = paramsMap.keys();
while (keys.hasMoreElements())
{
Object key = keys.nextElement();
newTable.put(key, paramsMap.get(key));
}
return newTable;
}
private int calcHashCode(ASN1Encodable enc)
{
String value = IETFUtils.valueToString(enc);
value = IETFUtils.canonicalize(value);
return value.hashCode();
}
public int calculateHashCode(X500Name name)
{
int hashCodeValue = 0;
RDN[] rdns = name.getRDNs();
// this needs to be order independent, like equals
for (int i = 0; i != rdns.length; i++)
{
if (rdns[i].isMultiValued())
{
AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
for (int j = 0; j != atv.length; j++)
{
hashCodeValue ^= atv[j].getType().hashCode();
hashCodeValue ^= calcHashCode(atv[j].getValue());
}
}
else
{
hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
}
}
return hashCodeValue;
}
For all string values starting with '#' is assumed, that these are
already valid ASN.1 objects encoded in hex.
All other string values are send to encodeStringValue(ASN1ObjectIdentifier, String)
.
Subclasses should overwrite encodeStringValue(ASN1ObjectIdentifier, String)
to change the encoding of specific types. Params: - oid – the DN name of the value.
- value – the String representation of the value.
/**
* For all string values starting with '#' is assumed, that these are
* already valid ASN.1 objects encoded in hex.
* <p>
* All other string values are send to
* {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}.
* </p>
* Subclasses should overwrite
* {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}
* to change the encoding of specific types.
*
* @param oid the DN name of the value.
* @param value the String representation of the value.
*/
public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
{
if (value.length() != 0 && value.charAt(0) == '#')
{
try
{
return IETFUtils.valueFromHexString(value, 1);
}
catch (IOException e)
{
throw new ASN1ParsingException("can't recode value for oid " + oid.getId());
}
}
if (value.length() != 0 && value.charAt(0) == '\\')
{
value = value.substring(1);
}
return encodeStringValue(oid, value);
}
Encoded every value into a UTF8String.
Subclasses should overwrite
this method to change the encoding of specific types.
Params: - oid – the DN oid of the value
- value – the String representation of the value
Returns: a the value encoded into a ASN.1 object. Never returns null
.
/**
* Encoded every value into a UTF8String.
* <p>
* Subclasses should overwrite
* this method to change the encoding of specific types.
* </p>
*
* @param oid the DN oid of the value
* @param value the String representation of the value
* @return a the value encoded into a ASN.1 object. Never returns <code>null</code>.
*/
protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, String value)
{
return new DERUTF8String(value);
}
public boolean areEqual(X500Name name1, X500Name name2)
{
RDN[] rdns1 = name1.getRDNs();
RDN[] rdns2 = name2.getRDNs();
if (rdns1.length != rdns2.length)
{
return false;
}
boolean reverse = false;
if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
{
reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType()); // guess forward
}
for (int i = 0; i != rdns1.length; i++)
{
if (!foundMatch(reverse, rdns1[i], rdns2))
{
return false;
}
}
return true;
}
private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
{
if (reverse)
{
for (int i = possRDNs.length - 1; i >= 0; i--)
{
if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
{
possRDNs[i] = null;
return true;
}
}
}
else
{
for (int i = 0; i != possRDNs.length; i++)
{
if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
{
possRDNs[i] = null;
return true;
}
}
}
return false;
}
protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
{
return IETFUtils.rDNAreEqual(rdn1, rdn2);
}
}