1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /** 6 * Licensed to the Apache Software Foundation (ASF) under one 7 * or more contributor license agreements. See the NOTICE file 8 * distributed with this work for additional information 9 * regarding copyright ownership. The ASF licenses this file 10 * to you under the Apache License, Version 2.0 (the 11 * "License"); you may not use this file except in compliance 12 * with the License. You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, 17 * software distributed under the License is distributed on an 18 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 19 * KIND, either express or implied. See the License for the 20 * specific language governing permissions and limitations 21 * under the License. 22 */ 23 package com.sun.org.apache.xml.internal.security.utils; 24 25 import java.io.IOException; 26 import java.io.StringReader; 27 28 public class RFC2253Parser { 29 30 /** 31 * Method rfc2253toXMLdsig 32 * 33 * @param dn 34 * @return normalized string 35 */ 36 public static String rfc2253toXMLdsig(String dn) { 37 // Transform from RFC1779 to RFC2253 38 String normalized = normalize(dn, true); 39 40 return rfctoXML(normalized); 41 } 42 43 /** 44 * Method xmldsigtoRFC2253 45 * 46 * @param dn 47 * @return normalized string 48 */ 49 public static String xmldsigtoRFC2253(String dn) { 50 // Transform from RFC1779 to RFC2253 51 String normalized = normalize(dn, false); 52 53 return xmltoRFC(normalized); 54 } 55 56 /** 57 * Method normalize 58 * 59 * @param dn 60 * @return normalized string 61 */ 62 public static String normalize(String dn) { 63 return normalize(dn, true); 64 } 65 66 /** 67 * Method normalize 68 * 69 * @param dn 70 * @param toXml 71 * @return normalized string 72 */ 73 public static String normalize(String dn, boolean toXml) { 74 //if empty string 75 if ((dn == null) || dn.equals("")) { 76 return ""; 77 } 78 79 try { 80 String DN = semicolonToComma(dn); 81 StringBuilder sb = new StringBuilder(); 82 int i = 0; 83 int l = 0; 84 int k; 85 86 //for name component 87 for (int j = 0; (k = DN.indexOf(',', j)) >= 0; j = k + 1) { 88 l += countQuotes(DN, j, k); 89 90 if ((k > 0) && (DN.charAt(k - 1) != '\\') && (l % 2) == 0) { 91 sb.append(parseRDN(DN.substring(i, k).trim(), toXml)).append(','); 92 93 i = k + 1; 94 l = 0; 95 } 96 } 97 98 sb.append(parseRDN(trim(DN.substring(i)), toXml)); 99 100 return sb.toString(); 101 } catch (IOException ex) { 102 return dn; 103 } 104 } 105 106 /** 107 * Method parseRDN 108 * 109 * @param str 110 * @param toXml 111 * @return normalized string 112 * @throws IOException 113 */ 114 static String parseRDN(String str, boolean toXml) throws IOException { 115 StringBuilder sb = new StringBuilder(); 116 int i = 0; 117 int l = 0; 118 int k; 119 120 for (int j = 0; (k = str.indexOf('+', j)) >= 0; j = k + 1) { 121 l += countQuotes(str, j, k); 122 123 if ((k > 0) && (str.charAt(k - 1) != '\\') && (l % 2) == 0) { 124 sb.append(parseATAV(trim(str.substring(i, k)), toXml)).append('+'); 125 126 i = k + 1; 127 l = 0; 128 } 129 } 130 131 sb.append(parseATAV(trim(str.substring(i)), toXml)); 132 133 return sb.toString(); 134 } 135 136 /** 137 * Method parseATAV 138 * 139 * @param str 140 * @param toXml 141 * @return normalized string 142 * @throws IOException 143 */ 144 static String parseATAV(String str, boolean toXml) throws IOException { 145 int i = str.indexOf('='); 146 147 if ((i == -1) || ((i > 0) && (str.charAt(i - 1) == '\\'))) { 148 return str; 149 } 150 String attrType = normalizeAT(str.substring(0, i)); 151 // only normalize if value is a String 152 String attrValue = null; 153 if (attrType.charAt(0) >= '0' && attrType.charAt(0) <= '9') { 154 attrValue = str.substring(i + 1); 155 } else { 156 attrValue = normalizeV(str.substring(i + 1), toXml); 157 } 158 159 return attrType + "=" + attrValue; 160 161 } 162 163 /** 164 * Method normalizeAT 165 * 166 * @param str 167 * @return normalized string 168 */ 169 static String normalizeAT(String str) { 170 171 String at = str.toUpperCase().trim(); 172 173 if (at.startsWith("OID")) { 174 at = at.substring(3); 175 } 176 177 return at; 178 } 179 180 /** 181 * Method normalizeV 182 * 183 * @param str 184 * @param toXml 185 * @return normalized string 186 * @throws IOException 187 */ 188 static String normalizeV(String str, boolean toXml) throws IOException { 189 String value = trim(str); 190 191 if (value.startsWith("\"")) { 192 StringBuilder sb = new StringBuilder(); 193 StringReader sr = new StringReader(value.substring(1, value.length() - 1)); 194 int i = 0; 195 char c; 196 197 while ((i = sr.read()) > -1) { 198 c = (char) i; 199 200 //the following char is defined at 4.Relationship with RFC1779 and LDAPv2 inrfc2253 201 if ((c == ',') || (c == '=') || (c == '+') || (c == '<') 202 || (c == '>') || (c == '#') || (c == ';')) { 203 sb.append('\\'); 204 } 205 206 sb.append(c); 207 } 208 209 value = trim(sb.toString()); 210 } 211 212 if (toXml) { 213 if (value.startsWith("#")) { 214 value = '\\' + value; 215 } 216 } else { 217 if (value.startsWith("\\#")) { 218 value = value.substring(1); 219 } 220 } 221 222 return value; 223 } 224 225 /** 226 * Method rfctoXML 227 * 228 * @param string 229 * @return normalized string 230 */ 231 static String rfctoXML(String string) { 232 try { 233 String s = changeLess32toXML(string); 234 235 return changeWStoXML(s); 236 } catch (Exception e) { 237 return string; 238 } 239 } 240 241 /** 242 * Method xmltoRFC 243 * 244 * @param string 245 * @return normalized string 246 */ 247 static String xmltoRFC(String string) { 248 try { 249 String s = changeLess32toRFC(string); 250 251 return changeWStoRFC(s); 252 } catch (Exception e) { 253 return string; 254 } 255 } 256 257 /** 258 * Method changeLess32toRFC 259 * 260 * @param string 261 * @return normalized string 262 * @throws IOException 263 */ 264 static String changeLess32toRFC(String string) throws IOException { 265 StringBuilder sb = new StringBuilder(); 266 StringReader sr = new StringReader(string); 267 int i = 0; 268 char c; 269 270 while ((i = sr.read()) > -1) { 271 c = (char) i; 272 273 if (c == '\\') { 274 sb.append(c); 275 276 char c1 = (char) sr.read(); 277 char c2 = (char) sr.read(); 278 279 //65 (A) 97 (a) 280 if ((((c1 >= 48) && (c1 <= 57)) || ((c1 >= 65) && (c1 <= 70)) || ((c1 >= 97) && (c1 <= 102))) 281 && (((c2 >= 48) && (c2 <= 57)) 282 || ((c2 >= 65) && (c2 <= 70)) 283 || ((c2 >= 97) && (c2 <= 102)))) { 284 char ch = (char) Byte.parseByte("" + c1 + c2, 16); 285 286 sb.append(ch); 287 } else { 288 sb.append(c1); 289 sb.append(c2); 290 } 291 } else { 292 sb.append(c); 293 } 294 } 295 296 return sb.toString(); 297 } 298 299 /** 300 * Method changeLess32toXML 301 * 302 * @param string 303 * @return normalized string 304 * @throws IOException 305 */ 306 static String changeLess32toXML(String string) throws IOException { 307 StringBuilder sb = new StringBuilder(); 308 StringReader sr = new StringReader(string); 309 int i = 0; 310 311 while ((i = sr.read()) > -1) { 312 if (i < 32) { 313 sb.append('\\'); 314 sb.append(Integer.toHexString(i)); 315 } else { 316 sb.append((char) i); 317 } 318 } 319 320 return sb.toString(); 321 } 322 323 /** 324 * Method changeWStoXML 325 * 326 * @param string 327 * @return normalized string 328 * @throws IOException 329 */ 330 static String changeWStoXML(String string) throws IOException { 331 StringBuilder sb = new StringBuilder(); 332 StringReader sr = new StringReader(string); 333 int i = 0; 334 char c; 335 336 while ((i = sr.read()) > -1) { 337 c = (char) i; 338 339 if (c == '\\') { 340 char c1 = (char) sr.read(); 341 342 if (c1 == ' ') { 343 sb.append('\\'); 344 345 String s = "20"; 346 347 sb.append(s); 348 } else { 349 sb.append('\\'); 350 sb.append(c1); 351 } 352 } else { 353 sb.append(c); 354 } 355 } 356 357 return sb.toString(); 358 } 359 360 /** 361 * Method changeWStoRFC 362 * 363 * @param string 364 * @return normalized string 365 */ 366 static String changeWStoRFC(String string) { 367 StringBuilder sb = new StringBuilder(); 368 int i = 0; 369 int k; 370 371 for (int j = 0; (k = string.indexOf("\\20", j)) >= 0; j = k + 3) { 372 sb.append(trim(string.substring(i, k))).append("\\ "); 373 374 i = k + 3; 375 } 376 377 sb.append(string.substring(i)); 378 379 return sb.toString(); 380 } 381 382 /** 383 * Method semicolonToComma 384 * 385 * @param str 386 * @return normalized string 387 */ 388 static String semicolonToComma(String str) { 389 return removeWSandReplace(str, ";", ","); 390 } 391 392 /** 393 * Method removeWhiteSpace 394 * 395 * @param str 396 * @param symbol 397 * @return normalized string 398 */ 399 static String removeWhiteSpace(String str, String symbol) { 400 return removeWSandReplace(str, symbol, symbol); 401 } 402 403 /** 404 * Method removeWSandReplace 405 * 406 * @param str 407 * @param symbol 408 * @param replace 409 * @return normalized string 410 */ 411 static String removeWSandReplace(String str, String symbol, String replace) { 412 StringBuilder sb = new StringBuilder(); 413 int i = 0; 414 int l = 0; 415 int k; 416 417 for (int j = 0; (k = str.indexOf(symbol, j)) >= 0; j = k + 1) { 418 l += countQuotes(str, j, k); 419 420 if ((k > 0) && (str.charAt(k - 1) != '\\') && (l % 2) == 0) { 421 sb.append(trim(str.substring(i, k))).append(replace); 422 423 i = k + 1; 424 l = 0; 425 } 426 } 427 428 sb.append(trim(str.substring(i))); 429 430 return sb.toString(); 431 } 432 433 /** 434 * Returns the number of Quotation from i to j 435 * 436 * @param s 437 * @param i 438 * @param j 439 * @return number of quotes 440 */ 441 private static int countQuotes(String s, int i, int j) { 442 int k = 0; 443 444 for (int l = i; l < j; l++) { 445 if (s.charAt(l) == '"') { 446 k++; 447 } 448 } 449 450 return k; 451 } 452 453 //only for the end of a space character occurring at the end of the string from rfc2253 454 455 /** 456 * Method trim 457 * 458 * @param str 459 * @return the string 460 */ 461 static String trim(String str) { 462 463 String trimed = str.trim(); 464 int i = str.indexOf(trimed) + trimed.length(); 465 466 if ((str.length() > i) && trimed.endsWith("\\") 467 && !trimed.endsWith("\\\\") && (str.charAt(i) == ' ')) { 468 trimed = trimed + " "; 469 } 470 471 return trimed; 472 } 473 474 }