1b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampackage org.bouncycastle.asn1.x509;
2b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
34c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstromimport java.io.IOException;
44c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom
5b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.asn1.ASN1InputStream;
64c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstromimport org.bouncycastle.asn1.ASN1ObjectIdentifier;
74c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstromimport org.bouncycastle.asn1.ASN1Primitive;
8c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstromimport org.bouncycastle.asn1.DERPrintableString;
9b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallamimport org.bouncycastle.util.Strings;
10b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
11b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam/**
12b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * It turns out that the number of standard ways the fields in a DN should be
13b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * encoded into their ASN.1 counterparts is rapidly approaching the
14b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * number of machines on the internet. By default the X509Name class
15b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * will produce UTF8Strings in line with the current recommendations (RFC 3280).
16b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * <p>
17b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * An example of an encoder look like below:
18b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * <pre>
19b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * public class X509DirEntryConverter
20b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *     extends X509NameEntryConverter
21b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * {
224c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom *     public ASN1Primitive getConvertedValue(
234c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom *         ASN1ObjectIdentifier  oid,
24b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         String               value)
25b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *     {
26b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         if (str.length() != 0 && str.charAt(0) == '#')
27b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         {
28b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *             return convertHexEncoded(str, 1);
29b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         }
30b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         if (oid.equals(EmailAddress))
31b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         {
32b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *             return new DERIA5String(str);
33b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         }
34b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         else if (canBePrintable(str))
35b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         {
36b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *             return new DERPrintableString(str);
37b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         }
38b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         else if (canBeUTF8(str))
39b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         {
40b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *             return new DERUTF8String(str);
41b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         }
42b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         else
43b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         {
44b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *             return new DERBMPString(str);
45b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *         }
46b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam *     }
47b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam * }
48b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam */
49b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallampublic abstract class X509NameEntryConverter
50b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam{
51b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
52b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Convert an inline encoded hex string rendition of an ASN.1
53b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * object back into its corresponding ASN.1 object.
54b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
55b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param str the hex encoded object
56b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param off the index at which the encoding starts
57b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the decoded object
58b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
594c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    protected ASN1Primitive convertHexEncoded(
60b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String  str,
61b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        int     off)
62b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        throws IOException
63b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
64b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        str = Strings.toLowerCase(str);
65b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        byte[] data = new byte[(str.length() - off) / 2];
66b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        for (int index = 0; index != data.length; index++)
67b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        {
68b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            char left = str.charAt((index * 2) + off);
69b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            char right = str.charAt((index * 2) + off + 1);
70b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
71b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (left < 'a')
72b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
73b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                data[index] = (byte)((left - '0') << 4);
74b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
75b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
76b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
77b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                data[index] = (byte)((left - 'a' + 10) << 4);
78b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
79b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            if (right < 'a')
80b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
81b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                data[index] |= (byte)(right - '0');
82b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
83b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            else
84b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            {
85b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam                data[index] |= (byte)(right - 'a' + 10);
86b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam            }
87b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        }
88b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
89b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        ASN1InputStream aIn = new ASN1InputStream(data);
90b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
91b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        return aIn.readObject();
92b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
93b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
94b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
95b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * return true if the passed in String can be represented without
96b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * loss as a PrintableString, false otherwise.
97b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
98b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    protected boolean canBePrintable(
99b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam        String  str)
100b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    {
101c37f4a04ef89e73a39a59f3c5a179af8c8ab5974Brian Carlstrom        return DERPrintableString.isPrintableString(str);
102b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    }
103b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam
104b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam    /**
105b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * Convert the passed in String value into the appropriate ASN.1
106b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * encoded object.
107b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     *
108b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param oid the oid associated with the value in the DN.
109b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @param value the value of the particular DN component.
110b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     * @return the ASN.1 equivalent for the value.
111b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam     */
1124c111300c39cb2e27f07fc2ae3b00e23ed4443b2Brian Carlstrom    public abstract ASN1Primitive getConvertedValue(ASN1ObjectIdentifier oid, String value);
113b61a96e7ef1a78acf013bbf08fe537e5b5f129caPeter Hallam}
114