153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giropackage org.bouncycastle.asn1.x500.style;
253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport java.io.IOException;
453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport java.util.Enumeration;
553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport java.util.Hashtable;
653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport org.bouncycastle.asn1.ASN1Encodable;
853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport org.bouncycastle.asn1.ASN1ObjectIdentifier;
9bdb7b3d37025690a0434040b4e0d0623d9fa74afSergio Giroimport org.bouncycastle.asn1.ASN1ParsingException;
1053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport org.bouncycastle.asn1.DERUTF8String;
1153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport org.bouncycastle.asn1.x500.AttributeTypeAndValue;
1253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport org.bouncycastle.asn1.x500.RDN;
1353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport org.bouncycastle.asn1.x500.X500Name;
1453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giroimport org.bouncycastle.asn1.x500.X500NameStyle;
1553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
1653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro/**
1753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro * This class provides some default behavior and common implementation for a
1853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro * X500NameStyle. It should be easily extendable to support implementing the
1953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro * desired X500NameStyle.
2053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro */
2153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giropublic abstract class AbstractX500NameStyle
2253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    implements X500NameStyle
2353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro{
2453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
2553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    /**
2653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * Tool function to shallow copy a Hashtable.
2753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     *
2853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * @param paramsMap table to copy
2953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * @return the copy of the table
3053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     */
3153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    public static Hashtable copyHashTable(Hashtable paramsMap)
3253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
3353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        Hashtable newTable = new Hashtable();
3453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
3553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        Enumeration keys = paramsMap.keys();
3653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        while (keys.hasMoreElements())
3753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
3853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            Object key = keys.nextElement();
3953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            newTable.put(key, paramsMap.get(key));
4053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
4153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
4253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return newTable;
4353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
4453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
4553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    private int calcHashCode(ASN1Encodable enc)
4653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
4753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        String value = IETFUtils.valueToString(enc);
4853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        value = IETFUtils.canonicalize(value);
4953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return value.hashCode();
5053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
5153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
5253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    public int calculateHashCode(X500Name name)
5353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
5453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        int hashCodeValue = 0;
5553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        RDN[] rdns = name.getRDNs();
5653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
5753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        // this needs to be order independent, like equals
5853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        for (int i = 0; i != rdns.length; i++)
5953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
6053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            if (rdns[i].isMultiValued())
6153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            {
6253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                AttributeTypeAndValue[] atv = rdns[i].getTypesAndValues();
6353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
6453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                for (int j = 0; j != atv.length; j++)
6553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                {
6653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                    hashCodeValue ^= atv[j].getType().hashCode();
6753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                    hashCodeValue ^= calcHashCode(atv[j].getValue());
6853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                }
6953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            }
7053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            else
7153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            {
7253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                hashCodeValue ^= rdns[i].getFirst().getType().hashCode();
7353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                hashCodeValue ^= calcHashCode(rdns[i].getFirst().getValue());
7453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            }
7553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
7653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
7753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return hashCodeValue;
7853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
7953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
8053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
8153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    /**
8253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * For all string values starting with '#' is assumed, that these are
8353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * already valid ASN.1 objects encoded in hex.
8453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * <p>
8553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * All other string values are send to
8653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}.
8753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * </p>
8853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * Subclasses should overwrite
8953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * {@link AbstractX500NameStyle#encodeStringValue(ASN1ObjectIdentifier, String)}
9053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * to change the encoding of specific types.
9153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     *
9253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * @param oid the DN name of the value.
9353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * @param value the String representation of the value.
9453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     */
9553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    public ASN1Encodable stringToValue(ASN1ObjectIdentifier oid, String value)
9653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
9753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        if (value.length() != 0 && value.charAt(0) == '#')
9853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
9953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            try
10053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            {
10153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                return IETFUtils.valueFromHexString(value, 1);
10253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            }
10353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            catch (IOException e)
10453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            {
105bdb7b3d37025690a0434040b4e0d0623d9fa74afSergio Giro                throw new ASN1ParsingException("can't recode value for oid " + oid.getId());
10653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            }
10753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
10853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
10953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        if (value.length() != 0 && value.charAt(0) == '\\')
11053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
11153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            value = value.substring(1);
11253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
11353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
11453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return encodeStringValue(oid, value);
11553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
11653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
11753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    /**
11853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * Encoded every value into a UTF8String.
11953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * <p>
12053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * Subclasses should overwrite
12153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * this method to change the encoding of specific types.
12253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * </p>
12353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     *
12453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * @param oid the DN oid of the value
12553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * @param value the String representation of the value
12653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     * @return a the value encoded into a ASN.1 object. Never returns <code>null</code>.
12753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro     */
12853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    protected ASN1Encodable encodeStringValue(ASN1ObjectIdentifier oid, String value)
12953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
13053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return new DERUTF8String(value);
13153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
13253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
13353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    public boolean areEqual(X500Name name1, X500Name name2)
13453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
13553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        RDN[] rdns1 = name1.getRDNs();
13653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        RDN[] rdns2 = name2.getRDNs();
13753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
13853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        if (rdns1.length != rdns2.length)
13953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
14053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            return false;
14153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
14253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
14353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        boolean reverse = false;
14453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
14553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        if (rdns1[0].getFirst() != null && rdns2[0].getFirst() != null)
14653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
14753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            reverse = !rdns1[0].getFirst().getType().equals(rdns2[0].getFirst().getType());  // guess forward
14853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
14953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
15053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        for (int i = 0; i != rdns1.length; i++)
15153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
15253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            if (!foundMatch(reverse, rdns1[i], rdns2))
15353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            {
15453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                return false;
15553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            }
15653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
15753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
15853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return true;
15953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
16053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
16153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    private boolean foundMatch(boolean reverse, RDN rdn, RDN[] possRDNs)
16253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
16353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        if (reverse)
16453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
16553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            for (int i = possRDNs.length - 1; i >= 0; i--)
16653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            {
16753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
16853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                {
16953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                    possRDNs[i] = null;
17053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                    return true;
17153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                }
17253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            }
17353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
17453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        else
17553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        {
17653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            for (int i = 0; i != possRDNs.length; i++)
17753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            {
17853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                if (possRDNs[i] != null && rdnAreEqual(rdn, possRDNs[i]))
17953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                {
18053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                    possRDNs[i] = null;
18153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                    return true;
18253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro                }
18353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro            }
18453b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        }
18553b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
18653b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return false;
18753b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
18853b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro
18953b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    protected boolean rdnAreEqual(RDN rdn1, RDN rdn2)
19053b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    {
19153b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro        return IETFUtils.rDNAreEqual(rdn1, rdn2);
19253b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro    }
19353b61f9fe9d58034fcc7021137e92460f91b70ceSergio Giro}
194