View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  
19  package org.apache.geronimo.util.asn1.x509;
20  
21  import java.io.ByteArrayInputStream;
22  import java.io.IOException;
23  
24  import org.apache.geronimo.util.asn1.ASN1InputStream;
25  import org.apache.geronimo.util.asn1.DERObject;
26  import org.apache.geronimo.util.asn1.DERObjectIdentifier;
27  
28  /**
29   * It turns out that the number of standard ways the fields in a DN should be
30   * encoded into their ASN.1 counterparts is rapidly approaching the
31   * number of machines on the internet. By default the X509Name class
32   * will produce PrintableStrings if the field value will decode to that,
33   * next UTF8Strings if the field value will decode to that, and finally BMPStrings
34   * if 16 bit characters are required.
35   * <p>
36   * The way this is done is with a default encoder which is
37   * implemented as follows:
38   * <pre>
39   * public class X509DefaultEntryConverter
40   *     extends X509NameEntryConverter
41   * {
42   *     public DERObject getConvertedValue(
43   *         DERObjectIdentifier  oid,
44   *         String               value)
45   *     {
46   *         if (str.length() != 0 && str.charAt(0) == '#')
47   *         {
48   *             return convertHexEncoded(str, 1);
49   *         }
50   *         if (oid.equals(EmailAddress))
51   *         {
52   *             return new DERIA5String(str);
53   *         }
54   *         else if (canBePrintable(str))
55   *         {
56   *             return new DERPrintableString(str);
57   *         }
58   *         else if (canBeUTF8(str))
59   *         {
60   *             return new DERUTF8String(str);
61   *         }
62   *         else
63   *         {
64   *             return new DERBMPString(str);
65   *         }
66   *     }
67   * }
68   */
69  public abstract class X509NameEntryConverter
70  {
71      /**
72       * Convert an inline encoded hex string rendition of an ASN.1
73       * object back into its corresponding ASN.1 object.
74       *
75       * @param str the hex encoded object
76       * @param off the index at which the encoding starts
77       * @return the decoded object
78       */
79      protected DERObject convertHexEncoded(
80          String  str,
81          int     off)
82          throws IOException
83      {
84          str = str.toLowerCase();
85          byte[]    data = new byte[str.length() / 2];
86          for (int index = 0; index != data.length; index++)
87          {
88              char left = str.charAt((index * 2) + off);
89              char right = str.charAt((index * 2) + off + 1);
90  
91              if (left < 'a')
92              {
93                  data[index] = (byte)((left - '0') << 4);
94              }
95              else
96              {
97                  data[index] = (byte)((left - 'a' + 10) << 4);
98              }
99              if (right < 'a')
100             {
101                 data[index] |= (byte)(right - '0');
102             }
103             else
104             {
105                 data[index] |= (byte)(right - 'a' + 10);
106             }
107         }
108 
109         ASN1InputStream aIn = new ASN1InputStream(
110                                             new ByteArrayInputStream(data));
111 
112         return aIn.readObject();
113     }
114 
115     /**
116      * return true if the passed in String can be represented without
117      * loss as a PrintableString, false otherwise.
118      */
119     protected boolean canBePrintable(
120         String  str)
121     {
122         for (int i = str.length() - 1; i >= 0; i--)
123         {
124             char    ch = str.charAt(i);
125 
126             if (str.charAt(i) > 0x007f)
127             {
128                 return false;
129             }
130 
131             if ('a' <= ch && ch <= 'z')
132             {
133                 continue;
134             }
135 
136             if ('A' <= ch && ch <= 'Z')
137             {
138                 continue;
139             }
140 
141             if ('0' <= ch && ch <= '9')
142             {
143                 continue;
144             }
145 
146             switch (ch)
147             {
148             case ' ':
149             case '\'':
150             case '(':
151             case ')':
152             case '+':
153             case '-':
154             case '.':
155             case ':':
156             case '=':
157             case '?':
158                 continue;
159             }
160 
161             return false;
162         }
163 
164         return true;
165     }
166 
167     /**
168      * return true if the passed in String can be represented without
169      * loss as a UTF8String, false otherwise.
170      */
171     protected boolean canBeUTF8(
172         String  str)
173     {
174         for (int i = str.length() - 1; i >= 0; i--)
175         {
176             if (str.charAt(i) > 0x00ff)
177             {
178                 return false;
179             }
180         }
181 
182         return true;
183     }
184 
185     /**
186      * Convert the passed in String value into the appropriate ASN.1
187      * encoded object.
188      *
189      * @param oid the oid associated with the value in the DN.
190      * @param value the value of the particular DN component.
191      * @return the ASN.1 equivalent for the value.
192      */
193     public abstract DERObject getConvertedValue(DERObjectIdentifier oid, String value);
194 }