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 }