1 /* 2 * reserved comment block 3 * DO NOT REMOVE OR ALTER! 4 */ 5 /* 6 * Copyright 1999-2004 The Apache Software Foundation. 7 * 8 * Licensed under the Apache License, Version 2.0 (the "License"); 9 * you may not use this file except in compliance with the License. 10 * You may obtain a copy of the License at 11 * 12 * http://www.apache.org/licenses/LICENSE-2.0 13 * 14 * Unless required by applicable law or agreed to in writing, software 15 * distributed under the License is distributed on an "AS IS" BASIS, 16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 * See the License for the specific language governing permissions and 18 * limitations under the License. 19 * 20 */ 21 package com.sun.org.apache.xml.internal.security.utils; 22 23 24 25 import java.io.IOException; 26 import java.io.StringReader; 27 28 29 /** 30 * 31 * @author $Author: mullan $ 32 */ 33 public class RFC2253Parser { 34 35 36 /** {@link java.util.logging} logging facility */ 37 /* static java.util.logging.Logger log = 38 java.util.logging.Logger.getLogger(RFC2253Parser.class.getName()); 39 */ 40 41 static boolean _TOXML = true; 42 43 /** 44 * Method rfc2253toXMLdsig 45 * 46 * @param dn 47 * @return normalized string 48 * 49 */ 50 public static String rfc2253toXMLdsig(String dn) { 51 52 _TOXML = true; 53 54 // Transform from RFC1779 to RFC2253 55 String normalized = normalize(dn); 56 57 return rfctoXML(normalized); 58 } 59 60 /** 61 * Method xmldsigtoRFC2253 62 * 63 * @param dn 64 * @return normalized string 65 */ 66 public static String xmldsigtoRFC2253(String dn) { 67 68 _TOXML = false; 69 70 // Transform from RFC1779 to RFC2253 71 String normalized = normalize(dn); 72 73 return xmltoRFC(normalized); 74 } 75 76 /** 77 * Method normalize 78 * 79 * @param dn 80 * @return normalized string 81 */ 82 public static String normalize(String dn) { 83 84 //if empty string 85 if ((dn == null) || dn.equals("")) { 86 return ""; 87 } 88 89 try { 90 String _DN = semicolonToComma(dn); 91 StringBuffer sb = new StringBuffer(); 92 int i = 0; 93 int l = 0; 94 int k; 95 96 //for name component 97 for (int j = 0; (k = _DN.indexOf(",", j)) >= 0; j = k + 1) { 98 l += countQuotes(_DN, j, k); 99 100 if ((k > 0) && (_DN.charAt(k - 1) != '\\') && (l % 2) != 1) { 101 sb.append(parseRDN(_DN.substring(i, k).trim()) + ","); 102 103 i = k + 1; 104 l = 0; 105 } 106 } 107 108 sb.append(parseRDN(trim(_DN.substring(i)))); 109 110 return sb.toString(); 111 } catch (IOException ex) { 112 return dn; 113 } 114 } 115 116 /** 117 * Method parseRDN 118 * 119 * @param str 120 * @return normalized string 121 * @throws IOException 122 */ 123 static String parseRDN(String str) throws IOException { 124 125 StringBuffer sb = new StringBuffer(); 126 int i = 0; 127 int l = 0; 128 int k; 129 130 for (int j = 0; (k = str.indexOf("+", j)) >= 0; j = k + 1) { 131 l += countQuotes(str, j, k); 132 133 if ((k > 0) && (str.charAt(k - 1) != '\\') && (l % 2) != 1) { 134 sb.append(parseATAV(trim(str.substring(i, k))) + "+"); 135 136 i = k + 1; 137 l = 0; 138 } 139 } 140 141 sb.append(parseATAV(trim(str.substring(i)))); 142 143 return sb.toString(); 144 } 145 146 /** 147 * Method parseATAV 148 * 149 * @param str 150 * @return normalized string 151 * @throws IOException 152 */ 153 static String parseATAV(String str) throws IOException { 154 155 int i = str.indexOf("="); 156 157 if ((i == -1) || ((i > 0) && (str.charAt(i - 1) == '\\'))) { 158 return str; 159 } 160 String attrType = normalizeAT(str.substring(0, i)); 161 // only normalize if value is a String 162 String attrValue = null; 163 if (attrType.charAt(0) >= '0' && attrType.charAt(0) <= '9') { 164 attrValue = str.substring(i + 1); 165 } else { 166 attrValue = normalizeV(str.substring(i + 1)); 167 } 168 169 return attrType + "=" + attrValue; 170 171 } 172 173 /** 174 * Method normalizeAT 175 * 176 * @param str 177 * @return normalized string 178 */ 179 static String normalizeAT(String str) { 180 181 String at = str.toUpperCase().trim(); 182 183 if (at.startsWith("OID")) { 184 at = at.substring(3); 185 } 186 187 return at; 188 } 189 190 /** 191 * Method normalizeV 192 * 193 * @param str 194 * @return normalized string 195 * @throws IOException 196 */ 197 static String normalizeV(String str) throws IOException { 198 199 String value = trim(str); 200 201 if (value.startsWith("\"")) { 202 StringBuffer sb = new StringBuffer(); 203 StringReader sr = new StringReader(value.substring(1, 204 value.length() - 1)); 205 int i = 0; 206 char c; 207 208 for (; (i = sr.read()) > -1; ) { 209 c = (char) i; 210 211 //the following char is defined at 4.Relationship with RFC1779 and LDAPv2 inrfc2253 212 if ((c == ',') || (c == '=') || (c == '+') || (c == '<') 213 || (c == '>') || (c == '#') || (c == ';')) { 214 sb.append('\\'); 215 } 216 217 sb.append(c); 218 } 219 220 value = trim(sb.toString()); 221 } 222 223 if (_TOXML == true) { 224 if (value.startsWith("#")) { 225 value = '\\' + value; 226 } 227 } else { 228 if (value.startsWith("\\#")) { 229 value = value.substring(1); 230 } 231 } 232 233 return value; 234 } 235 236 /** 237 * Method rfctoXML 238 * 239 * @param string 240 * @return normalized string 241 */ 242 static String rfctoXML(String string) { 243 244 try { 245 String s = changeLess32toXML(string); 246 247 return changeWStoXML(s); 248 } catch (Exception e) { 249 return string; 250 } 251 } 252 253 /** 254 * Method xmltoRFC 255 * 256 * @param string 257 * @return normalized string 258 */ 259 static String xmltoRFC(String string) { 260 261 try { 262 String s = changeLess32toRFC(string); 263 264 return changeWStoRFC(s); 265 } catch (Exception e) { 266 return string; 267 } 268 } 269 270 /** 271 * Method changeLess32toRFC 272 * 273 * @param string 274 * @return normalized string 275 * @throws IOException 276 */ 277 static String changeLess32toRFC(String string) throws IOException { 278 279 StringBuffer sb = new StringBuffer(); 280 StringReader sr = new StringReader(string); 281 int i = 0; 282 char c; 283 284 for (; (i = sr.read()) > -1; ) { 285 c = (char) i; 286 287 if (c == '\\') { 288 sb.append(c); 289 290 char c1 = (char) sr.read(); 291 char c2 = (char) sr.read(); 292 293 //65 (A) 97 (a) 294 if ((((c1 >= 48) && (c1 <= 57)) || ((c1 >= 65) && (c1 <= 70)) || ((c1 >= 97) && (c1 <= 102))) 295 && (((c2 >= 48) && (c2 <= 57)) 296 || ((c2 >= 65) && (c2 <= 70)) 297 || ((c2 >= 97) && (c2 <= 102)))) { 298 char ch = (char) Byte.parseByte("" + c1 + c2, 16); 299 300 sb.append(ch); 301 } else { 302 sb.append(c1); 303 sb.append(c2); 304 } 305 } else { 306 sb.append(c); 307 } 308 } 309 310 return sb.toString(); 311 } 312 313 /** 314 * Method changeLess32toXML 315 * 316 * @param string 317 * @return normalized string 318 * @throws IOException 319 */ 320 static String changeLess32toXML(String string) throws IOException { 321 322 StringBuffer sb = new StringBuffer(); 323 StringReader sr = new StringReader(string); 324 int i = 0; 325 326 for (; (i = sr.read()) > -1; ) { 327 if (i < 32) { 328 sb.append('\\'); 329 sb.append(Integer.toHexString(i)); 330 } else { 331 sb.append((char) i); 332 } 333 } 334 335 return sb.toString(); 336 } 337 338 /** 339 * Method changeWStoXML 340 * 341 * @param string 342 * @return normalized string 343 * @throws IOException 344 */ 345 static String changeWStoXML(String string) throws IOException { 346 347 StringBuffer sb = new StringBuffer(); 348 StringReader sr = new StringReader(string); 349 int i = 0; 350 char c; 351 352 for (; (i = sr.read()) > -1; ) { 353 c = (char) i; 354 355 if (c == '\\') { 356 char c1 = (char) sr.read(); 357 358 if (c1 == ' ') { 359 sb.append('\\'); 360 361 String s = "20"; 362 363 sb.append(s); 364 } else { 365 sb.append('\\'); 366 sb.append(c1); 367 } 368 } else { 369 sb.append(c); 370 } 371 } 372 373 return sb.toString(); 374 } 375 376 /** 377 * Method changeWStoRFC 378 * 379 * @param string 380 * @return normalized string 381 */ 382 static String changeWStoRFC(String string) { 383 384 StringBuffer sb = new StringBuffer(); 385 int i = 0; 386 int k; 387 388 for (int j = 0; (k = string.indexOf("\\20", j)) >= 0; j = k + 3) { 389 sb.append(trim(string.substring(i, k)) + "\\ "); 390 391 i = k + 3; 392 } 393 394 sb.append(string.substring(i)); 395 396 return sb.toString(); 397 } 398 399 /** 400 * Method semicolonToComma 401 * 402 * @param str 403 * @return normalized string 404 */ 405 static String semicolonToComma(String str) { 406 return removeWSandReplace(str, ";", ","); 407 } 408 409 /** 410 * Method removeWhiteSpace 411 * 412 * @param str 413 * @param symbol 414 * @return normalized string 415 */ 416 static String removeWhiteSpace(String str, String symbol) { 417 return removeWSandReplace(str, symbol, symbol); 418 } 419 420 /** 421 * Method removeWSandReplace 422 * 423 * @param str 424 * @param symbol 425 * @param replace 426 * @return normalized string 427 */ 428 static String removeWSandReplace(String str, String symbol, String replace) { 429 430 StringBuffer sb = new StringBuffer(); 431 int i = 0; 432 int l = 0; 433 int k; 434 435 for (int j = 0; (k = str.indexOf(symbol, j)) >= 0; j = k + 1) { 436 l += countQuotes(str, j, k); 437 438 if ((k > 0) && (str.charAt(k - 1) != '\\') && (l % 2) != 1) { 439 sb.append(trim(str.substring(i, k)) + replace); 440 441 i = k + 1; 442 l = 0; 443 } 444 } 445 446 sb.append(trim(str.substring(i))); 447 448 return sb.toString(); 449 } 450 451 /** 452 * Returns the number of Quotation from i to j 453 * 454 * @param s 455 * @param i 456 * @param j 457 * @return number of quotes 458 */ 459 private static int countQuotes(String s, int i, int j) { 460 461 int k = 0; 462 463 for (int l = i; l < j; l++) { 464 if (s.charAt(l) == '"') { 465 k++; 466 } 467 } 468 469 return k; 470 } 471 472 //only for the end of a space character occurring at the end of the string from rfc2253 473 474 /** 475 * Method trim 476 * 477 * @param str 478 * @return the string 479 */ 480 static String trim(String str) { 481 482 String trimed = str.trim(); 483 int i = str.indexOf(trimed) + trimed.length(); 484 485 if ((str.length() > i) && trimed.endsWith("\\") 486 &&!trimed.endsWith("\\\\")) { 487 if (str.charAt(i) == ' ') { 488 trimed = trimed + " "; 489 } 490 } 491 492 return trimed; 493 } 494 495 /** 496 * Method main 497 * 498 * @param args 499 * @throws Exception 500 */ 501 public static void main(String[] args) throws Exception { 502 503 testToXML("CN=\"Steve, Kille\", O=Isode Limited, C=GB"); 504 testToXML("CN=Steve Kille , O=Isode Limited,C=GB"); 505 testToXML("\\ OU=Sales+CN=J. Smith,O=Widget Inc.,C=US\\ \\ "); 506 testToXML("CN=L. Eagle,O=Sue\\, Grabbit and Runn,C=GB"); 507 testToXML("CN=Before\\0DAfter,O=Test,C=GB"); 508 testToXML("CN=\"L. Eagle,O=Sue, = + < > # ;Grabbit and Runn\",C=GB"); 509 testToXML("1.3.6.1.4.1.1466.0=#04024869,O=Test,C=GB"); 510 511 { 512 StringBuffer sb = new StringBuffer(); 513 514 sb.append('L'); 515 sb.append('u'); 516 sb.append('\uc48d'); 517 sb.append('i'); 518 sb.append('\uc487'); 519 520 String test7 = "SN=" + sb.toString(); 521 522 testToXML(test7); 523 } 524 525 testToRFC("CN=\"Steve, Kille\", O=Isode Limited, C=GB"); 526 testToRFC("CN=Steve Kille , O=Isode Limited,C=GB"); 527 testToRFC("\\20OU=Sales+CN=J. Smith,O=Widget Inc.,C=US\\20\\20 "); 528 testToRFC("CN=L. Eagle,O=Sue\\, Grabbit and Runn,C=GB"); 529 testToRFC("CN=Before\\12After,O=Test,C=GB"); 530 testToRFC("CN=\"L. Eagle,O=Sue, = + < > # ;Grabbit and Runn\",C=GB"); 531 testToRFC("1.3.6.1.4.1.1466.0=\\#04024869,O=Test,C=GB"); 532 533 { 534 StringBuffer sb = new StringBuffer(); 535 536 sb.append('L'); 537 sb.append('u'); 538 sb.append('\uc48d'); 539 sb.append('i'); 540 sb.append('\uc487'); 541 542 String test7 = "SN=" + sb.toString(); 543 544 testToRFC(test7); 545 } 546 } 547 548 /** Field i */ 549 static int counter = 0; 550 551 /** 552 * Method test 553 * 554 * @param st 555 */ 556 static void testToXML(String st) { 557 558 System.out.println("start " + counter++ + ": " + st); 559 System.out.println(" " + rfc2253toXMLdsig(st)); 560 System.out.println(""); 561 } 562 563 /** 564 * Method testToRFC 565 * 566 * @param st 567 */ 568 static void testToRFC(String st) { 569 570 System.out.println("start " + counter++ + ": " + st); 571 System.out.println(" " + xmldsigtoRFC2253(st)); 572 System.out.println(""); 573 } 574 }