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