001/* 002 * $HeadURL: file:///opt/dev/not-yet-commons-ssl-SVN-repo/tags/commons-ssl-0.3.17/src/java/org/apache/commons/ssl/Util.java $ 003 * $Revision: 180 $ 004 * $Date: 2014-09-23 11:33:47 -0700 (Tue, 23 Sep 2014) $ 005 * 006 * ==================================================================== 007 * Licensed to the Apache Software Foundation (ASF) under one 008 * or more contributor license agreements. See the NOTICE file 009 * distributed with this work for additional information 010 * regarding copyright ownership. The ASF licenses this file 011 * to you under the Apache License, Version 2.0 (the 012 * "License"); you may not use this file except in compliance 013 * with the License. You may obtain a copy of the License at 014 * 015 * http://www.apache.org/licenses/LICENSE-2.0 016 * 017 * Unless required by applicable law or agreed to in writing, 018 * software distributed under the License is distributed on an 019 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 020 * KIND, either express or implied. See the License for the 021 * specific language governing permissions and limitations 022 * under the License. 023 * ==================================================================== 024 * 025 * This software consists of voluntary contributions made by many 026 * individuals on behalf of the Apache Software Foundation. For more 027 * information on the Apache Software Foundation, please see 028 * <http://www.apache.org/>. 029 * 030 */ 031 032package org.apache.commons.ssl; 033 034import org.apache.commons.ssl.util.ByteArrayReadLine; 035import org.apache.commons.ssl.util.IPAddressParser; 036 037import java.io.ByteArrayInputStream; 038import java.io.File; 039import java.io.FileInputStream; 040import java.io.IOException; 041import java.io.InputStream; 042import java.io.OutputStream; 043import java.net.InetAddress; 044import java.net.UnknownHostException; 045import java.security.KeyStore; 046import java.security.KeyStoreException; 047import java.security.cert.Certificate; 048import java.util.Arrays; 049import java.util.Enumeration; 050import java.util.LinkedList; 051import java.util.Map; 052import java.util.Set; 053import java.util.StringTokenizer; 054import java.util.TreeMap; 055import java.util.TreeSet; 056 057/** 058 * @author Credit Union Central of British Columbia 059 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a> 060 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a> 061 * @since 28-Feb-2006 062 */ 063public class Util { 064 public final static int SIZE_KEY = 0; 065 public final static int LAST_READ_KEY = 1; 066 067 /** 068 * True if the Keystores have the same # of entries, have the same set of aliases, and all the certificate-chains 069 * (of the certificate entries) match. Does not check the private keys for equality, since we 070 * don't bother taking the passwords to get at them. 071 */ 072 public static boolean equals(KeyStore ks1, KeyStore ks2) throws KeyStoreException { 073 if (ks1 == null || ks2 == null) { 074 return ks1 == null && ks2 == null; 075 } 076 Set<String> aliases1 = aliases(ks1); 077 Set<String> aliases2 = aliases(ks2); 078 if (aliases1.equals(aliases2)) { 079 for (String s : aliases1) { 080 if (ks1.isCertificateEntry(s) != ks2.isCertificateEntry(s)) { 081 return false; 082 } 083 if (ks1.isKeyEntry(s) != ks2.isKeyEntry(s)) { 084 return false; 085 } 086 if (ks1.isCertificateEntry(s)) { 087 Certificate[] cc1 = ks1.getCertificateChain(s); 088 Certificate[] cc2 = ks2.getCertificateChain(s); 089 if (!Arrays.equals(cc1, cc2)) { 090 return false; 091 } 092 093 Certificate c1 = ks1.getCertificate(s); 094 Certificate c2 = ks2.getCertificate(s); 095 if (!c1.equals(c2)) { 096 return false; 097 } 098 } 099 100 // should we bother checking keys? maybe one day.... 101 } 102 } 103 return true; 104 } 105 106 private static Set<String> aliases(KeyStore ks) throws KeyStoreException { 107 Set<String> aliases = new TreeSet<String>(); 108 Enumeration<String> en = ks.aliases(); 109 while (en.hasMoreElements()) { 110 aliases.add(en.nextElement()); 111 } 112 return aliases; 113 } 114 115 public static boolean isYes(String yesString) { 116 if (yesString == null) { 117 return false; 118 } 119 String s = yesString.trim().toUpperCase(); 120 return "1".equals(s) || "YES".equals(s) || "TRUE".equals(s) || 121 "ENABLE".equals(s) || "ENABLED".equals(s) || "Y".equals(s) || 122 "ON".equals(s); 123 } 124 125 public static String trim(final String s) { 126 if (s == null || "".equals(s)) { 127 return s; 128 } 129 int i = 0; 130 int j = s.length() - 1; 131 while (isWhiteSpace(s.charAt(i))) { 132 i++; 133 } 134 while (isWhiteSpace(s.charAt(j))) { 135 j--; 136 } 137 return j >= i ? s.substring(i, j + 1) : ""; 138 } 139 140 public static boolean isWhiteSpace(final char c) { 141 switch (c) { 142 case 0: 143 case ' ': 144 case '\t': 145 case '\n': 146 case '\r': 147 case '\f': 148 return true; 149 default: 150 return false; 151 } 152 } 153 154 public static void pipeStream(InputStream in, OutputStream out) 155 throws IOException { 156 pipeStream(in, out, true); 157 } 158 159 public static void pipeStream(InputStream in, OutputStream out, 160 boolean autoClose) 161 throws IOException { 162 byte[] buf = new byte[8192]; 163 IOException ioe = null; 164 try { 165 int bytesRead = in.read(buf); 166 while (bytesRead >= 0) { 167 if (bytesRead > 0) { 168 out.write(buf, 0, bytesRead); 169 } 170 bytesRead = in.read(buf); 171 } 172 } 173 finally { 174 // Probably it's best to let consumer call "close", but I'm usually 175 // the consumer, and I want to be lazy. [Julius, November 20th, 2006] 176 try { in.close(); } catch (IOException e) { ioe = e; } 177 if (autoClose) { 178 try { out.close(); } catch (IOException e) { ioe = e; } 179 } 180 } 181 if (ioe != null) { 182 throw ioe; 183 } 184 } 185 186 public static byte[] fileToBytes(final File f) throws IOException { 187 return streamToBytes(new FileInputStream(f)); 188 } 189 190 public static byte[] streamToBytes(final ByteArrayInputStream in, 191 int maxLength) { 192 byte[] buf = new byte[maxLength]; 193 int[] status = fill(buf, 0, in); 194 int size = status[SIZE_KEY]; 195 if (buf.length != size) { 196 byte[] smallerBuf = new byte[size]; 197 System.arraycopy(buf, 0, smallerBuf, 0, size); 198 buf = smallerBuf; 199 } 200 return buf; 201 } 202 203 public static byte[] streamToBytes(final InputStream in, int maxLength) 204 throws IOException { 205 byte[] buf = new byte[maxLength]; 206 int[] status = fill(buf, 0, in); 207 int size = status[SIZE_KEY]; 208 if (buf.length != size) { 209 byte[] smallerBuf = new byte[size]; 210 System.arraycopy(buf, 0, smallerBuf, 0, size); 211 buf = smallerBuf; 212 } 213 return buf; 214 } 215 216 public static byte[] streamToBytes(final InputStream in) throws IOException { 217 byte[] buf = new byte[4096]; 218 try { 219 int[] status = fill(buf, 0, in); 220 int size = status[SIZE_KEY]; 221 int lastRead = status[LAST_READ_KEY]; 222 while (lastRead != -1) { 223 buf = resizeArray(buf); 224 status = fill(buf, size, in); 225 size = status[SIZE_KEY]; 226 lastRead = status[LAST_READ_KEY]; 227 } 228 if (buf.length != size) { 229 byte[] smallerBuf = new byte[size]; 230 System.arraycopy(buf, 0, smallerBuf, 0, size); 231 buf = smallerBuf; 232 } 233 } 234 finally { 235 in.close(); 236 } 237 return buf; 238 } 239 240 public static byte[] streamToBytes(final ByteArrayInputStream in) { 241 byte[] buf = new byte[4096]; 242 int[] status = fill(buf, 0, in); 243 int size = status[SIZE_KEY]; 244 int lastRead = status[LAST_READ_KEY]; 245 while (lastRead != -1) { 246 buf = resizeArray(buf); 247 status = fill(buf, size, in); 248 size = status[SIZE_KEY]; 249 lastRead = status[LAST_READ_KEY]; 250 } 251 if (buf.length != size) { 252 byte[] smallerBuf = new byte[size]; 253 System.arraycopy(buf, 0, smallerBuf, 0, size); 254 buf = smallerBuf; 255 } 256 // in.close(); <-- this is a no-op on ByteArrayInputStream. 257 return buf; 258 } 259 260 public static int[] fill(final byte[] buf, final int offset, 261 final InputStream in) 262 throws IOException { 263 int read = in.read(buf, offset, buf.length - offset); 264 int lastRead = read; 265 if (read == -1) { 266 read = 0; 267 } 268 while (lastRead != -1 && read + offset < buf.length) { 269 lastRead = in.read(buf, offset + read, buf.length - read - offset); 270 if (lastRead != -1) { 271 read += lastRead; 272 } 273 } 274 return new int[]{offset + read, lastRead}; 275 } 276 277 public static int[] fill(final byte[] buf, final int offset, 278 final ByteArrayInputStream in) { 279 int read = in.read(buf, offset, buf.length - offset); 280 int lastRead = read; 281 if (read == -1) { 282 read = 0; 283 } 284 while (lastRead != -1 && read + offset < buf.length) { 285 lastRead = in.read(buf, offset + read, buf.length - read - offset); 286 if (lastRead != -1) { 287 read += lastRead; 288 } 289 } 290 return new int[]{offset + read, lastRead}; 291 } 292 293 public static byte[] resizeArray(final byte[] bytes) { 294 byte[] biggerBytes = new byte[bytes.length * 2]; 295 System.arraycopy(bytes, 0, biggerBytes, 0, bytes.length); 296 return biggerBytes; 297 } 298 299 public static String pad(String s, final int length, final boolean left) { 300 if (s == null) { 301 s = ""; 302 } 303 int diff = length - s.length(); 304 if (diff == 0) { 305 return s; 306 } else if (diff > 0) { 307 StringBuffer sb = new StringBuffer(); 308 if (left) { 309 for (int i = 0; i < diff; i++) { 310 sb.append(' '); 311 } 312 } 313 sb.append(s); 314 if (!left) { 315 for (int i = 0; i < diff; i++) { 316 sb.append(' '); 317 } 318 } 319 return sb.toString(); 320 } else { 321 return s; 322 } 323 } 324 325 public static Map parseArgs(final String[] cargs) { 326 Map args = new TreeMap(); 327 Map ARGS_MATCH = Ping.ARGS_MATCH; 328 329 int l = cargs.length; 330 final String[] EMPTY_VALUES = {""}; 331 for (int i = 0; i < l; i++) { 332 String k = cargs[i]; 333 Ping.Arg a = (Ping.Arg) ARGS_MATCH.get(k); 334 if (l > i + 1) { 335 String v = cargs[++i]; 336 while (ARGS_MATCH.containsKey(v)) { 337 args.put(a, EMPTY_VALUES); 338 a = (Ping.Arg) ARGS_MATCH.get(v); 339 v = ""; 340 if (l > i + 1) { 341 v = cargs[++i]; 342 } 343 } 344 String[] values = new String[1]; 345 values[0] = v; 346 args.put(a, values); 347 if (l > i + 1 && !ARGS_MATCH.containsKey(cargs[i + 1])) { 348 LinkedList list = new LinkedList(); 349 list.add(v); 350 while (l > i + 1 && !ARGS_MATCH.containsKey(cargs[i + 1])) { 351 v = cargs[++i]; 352 list.add(v); 353 } 354 args.put(a, list.toArray(new String[list.size()])); 355 } 356 } else { 357 args.put(a, EMPTY_VALUES); 358 } 359 } 360 return args; 361 } 362 363 public static HostPort toAddress(final String target, 364 final int defaultPort) 365 throws UnknownHostException { 366 String host = target; 367 int port = defaultPort; 368 StringTokenizer st = new StringTokenizer(target, ":"); 369 if (st.hasMoreTokens()) { 370 host = st.nextToken().trim(); 371 } 372 if (st.hasMoreTokens()) { 373 port = Integer.parseInt(st.nextToken().trim()); 374 } 375 if (st.hasMoreTokens()) { 376 throw new IllegalArgumentException("Invalid host: " + target); 377 } 378 return new HostPort(host, port); 379 } 380 381 public static String cipherToAuthType(String cipher) { 382 if (cipher == null) { 383 return null; 384 } 385 386 // SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA ==> "DHE_DSS_EXPORT" 387 // SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA ==> "DHE_DSS" 388 // SSL_RSA_WITH_3DES_EDE_CBC_SHA ==> "RSA" 389 390 StringTokenizer st = new StringTokenizer(cipher.trim(), "_"); 391 if (st.hasMoreTokens()) { 392 st.nextToken(); // always skip first token 393 } 394 if (st.hasMoreTokens()) { 395 String tok = st.nextToken(); 396 StringBuffer buf = new StringBuffer(); 397 buf.append(tok); 398 if (st.hasMoreTokens()) { 399 tok = st.nextToken(); 400 while (!"WITH".equalsIgnoreCase(tok)) { 401 buf.append('_'); 402 buf.append(tok); 403 tok = st.nextToken(); 404 } 405 } 406 return buf.toString(); 407 } 408 throw new IllegalArgumentException("not a valid cipher: " + cipher); 409 } 410 411 /** 412 * Utility method to make sure IP-literals don't trigger reverse-DNS lookups. 413 */ 414 public static InetAddress toInetAddress(String s) throws UnknownHostException { 415 byte[] ip = IPAddressParser.parseIPv4Literal(s); 416 if (ip == null) { 417 ip = IPAddressParser.parseIPv6Literal(s); 418 } 419 if (ip != null) { 420 // Strangely, this prevents Java's annoying SSL reverse-DNS lookup that it 421 // normally does, even with literal IP addresses. 422 return InetAddress.getByAddress(s, ip); 423 } else { 424 return InetAddress.getByName(s); 425 } 426 } 427 428 public static void main(String[] args) throws Exception { 429 String s = "line1\n\rline2\n\rline3"; 430 ByteArrayInputStream in = new ByteArrayInputStream(s.getBytes()); 431 ByteArrayReadLine readLine = new ByteArrayReadLine(in); 432 String line = readLine.next(); 433 while (line != null) { 434 System.out.println(line); 435 line = readLine.next(); 436 } 437 438 System.out.println("--------- test 2 ----------"); 439 440 s = "line1\n\rline2\n\rline3\n\r\n\r"; 441 in = new ByteArrayInputStream(s.getBytes()); 442 readLine = new ByteArrayReadLine(in); 443 line = readLine.next(); 444 while (line != null) { 445 System.out.println(line); 446 line = readLine.next(); 447 } 448 449 } 450 451 452}