001/* 002 * $HeadURL: file:///opt/dev/not-yet-commons-ssl-SVN-repo/tags/commons-ssl-0.3.17/src/java/org/apache/commons/ssl/Ping.java $ 003 * $Revision: 142 $ 004 * $Date: 2008-03-04 00:13:37 -0800 (Tue, 04 Mar 2008) $ 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.ReadLine; 035 036import javax.net.ssl.SSLSocket; 037import java.io.File; 038import java.io.InputStream; 039import java.io.OutputStream; 040import java.net.InetAddress; 041import java.net.Socket; 042import java.security.cert.X509Certificate; 043import java.util.Collections; 044import java.util.HashMap; 045import java.util.Iterator; 046import java.util.Map; 047import java.util.SortedSet; 048import java.util.TreeSet; 049 050/** 051 * @author Credit Union Central of British Columbia 052 * @author <a href="http://www.cucbc.com/">www.cucbc.com</a> 053 * @author <a href="mailto:juliusdavies@cucbc.com">juliusdavies@cucbc.com</a> 054 * @since 30-Mar-2006 055 */ 056public class Ping { 057 protected static SortedSet ARGS = new TreeSet(); 058 protected static Map ARGS_MATCH = new HashMap(); 059 protected final static Arg ARG_TARGET = new Arg("-t", "--target", "[hostname[:port]] default port=443", true); 060 protected final static Arg ARG_BIND = new Arg("-b", "--bind", "[hostname[:port]] default port=0 \"ANY\""); 061 protected final static Arg ARG_PROXY = new Arg("-r", "--proxy", "[hostname[:port]] default port=80"); 062 protected final static Arg ARG_TRUST_CERT = new Arg("-tm", "--trust-cert", "[path to trust material] {pem, der, crt, jks}"); 063 protected final static Arg ARG_CLIENT_CERT = new Arg("-km", "--client-cert", "[path to client's private key] {jks, pkcs12, pkcs8}"); 064 protected final static Arg ARG_CERT_CHAIN = new Arg("-cc", "--cert-chain", "[path to client's cert chain for pkcs8/OpenSSL key]"); 065 protected final static Arg ARG_PASSWORD = new Arg("-p", "--password", "[client cert password]"); 066 protected final static Arg ARG_HOST_HEADER = new Arg("-h", "--host-header", "[http-host-header] in case -t is an IP address"); 067 protected final static Arg ARG_PATH = new Arg("-u", "--path", "[path for GET/HEAD request] default=/"); 068 protected final static Arg ARG_METHOD = new Arg("-m", "--method", "[http method to use] default=HEAD"); 069 070 private static HostPort target; 071 private static HostPort local; 072 private static HostPort proxy; 073 private static String hostHeader; 074 private static String httpMethod = "HEAD"; 075 private static String path = "/"; 076 private static InetAddress targetAddress; 077 private static InetAddress localAddress; 078 private static int targetPort = 443; 079 private static int localPort = 0; 080 private static File clientCert; 081 private static File certChain; 082 private static char[] password; 083 private static TrustChain trustChain = null; 084 085 static { 086 ARGS = Collections.unmodifiableSortedSet(ARGS); 087 ARGS_MATCH = Collections.unmodifiableMap(ARGS_MATCH); 088 } 089 090 public static void main(String[] args) throws Exception { 091 boolean showUsage = args.length == 0; 092 Exception parseException = null; 093 if (!showUsage) { 094 try { 095 parseArgs(args); 096 } 097 catch (Exception e) { 098 parseException = e; 099 showUsage = true; 100 } 101 } 102 if (showUsage) { 103 if (parseException != null) { 104 System.out.println(); 105 System.out.println("* Error: " + parseException.getMessage() + "."); 106 parseException.printStackTrace(System.out); 107 System.out.println(); 108 } 109 System.out.println("Usage: java -jar not-yet-commons-ssl-" + Version.VERSION + ".jar [options]"); 110 System.out.println(Version.versionString()); 111 System.out.println("Options: (*=required)"); 112 Iterator it = ARGS.iterator(); 113 while (it.hasNext()) { 114 Arg a = (Arg) it.next(); 115 String s = Util.pad(a.shortArg, 3, false); 116 String l = Util.pad(a.longArg, 18, false); 117 String required = a.isRequired ? "*" : " "; 118 String d = a.description; 119 System.out.println(required + " " + s + " " + l + " " + d); 120 } 121 System.out.println(); 122 String example = "java -jar commons-ssl.jar -t host.com:443 -c ./client.pfx -p `cat ./pass.txt` "; 123 System.out.println("Example:"); 124 System.out.println(); 125 System.out.println(example); 126 System.out.println(); 127 System.exit(1); 128 return; 129 } 130 131 SSLClient ssl = new SSLClient(); 132 Socket s = null; 133 InputStream in = null; 134 OutputStream out = null; 135 Exception socketException = null; 136 Exception trustException = null; 137 Exception hostnameException = null; 138 Exception crlException = null; 139 Exception expiryException = null; 140 String sslCipher = null; 141 try { 142 try { 143 ssl.setCheckHostname(false); 144 ssl.setCheckExpiry(false); 145 ssl.setCheckCRL(false); 146 ssl.addTrustMaterial(TrustMaterial.TRUST_ALL); 147 if (clientCert != null) { 148 149 KeyMaterial km; 150 if (certChain != null) { 151 km = new KeyMaterial(clientCert, certChain, password); 152 } else { 153 km = new KeyMaterial(clientCert, password); 154 } 155 if (password != null) { 156 for (int i = 0; i < password.length; i++) { 157 password[i] = 0; 158 } 159 } 160 ssl.setKeyMaterial(km); 161 } 162 163 if (trustChain != null) { 164 ssl.addTrustMaterial(trustChain); 165 } 166 167 ssl.setSoTimeout(10000); 168 ssl.setConnectTimeout(5000); 169 170 if (proxy != null) { 171 s = new Socket(proxy.host, proxy.port, 172 local.addr, local.port); 173 s.setSoTimeout(10000); 174 in = s.getInputStream(); 175 out = s.getOutputStream(); 176 String targetHost = target.host; 177 String line1 = "CONNECT " + targetHost + ":" + targetPort + " HTTP/1.1\r\n"; 178 String line2 = "Proxy-Connection: keep-alive\r\n"; 179 String line3 = "Host: " + targetHost + "\r\n\r\n"; 180 out.write(line1.getBytes()); 181 out.write(line2.getBytes()); 182 out.write(line3.getBytes()); 183 out.flush(); 184 185 ReadLine readLine = new ReadLine(in); 186 String read1 = readLine.next(); 187 if (read1.startsWith("HTTP/1.1 200")) { 188 int avail = in.available(); 189 in.skip(avail); 190 Thread.yield(); 191 avail = in.available(); 192 while (avail != 0) { 193 in.skip(avail); 194 Thread.yield(); 195 avail = in.available(); 196 } 197 s = ssl.createSocket(s, targetHost, targetPort, true); 198 } else { 199 System.out.print(line1); 200 System.out.print(line2); 201 System.out.print(line3); 202 System.out.println("Server returned unexpected proxy response!"); 203 System.out.println("============================================="); 204 System.out.println(read1); 205 String line = readLine.next(); 206 while (line != null) { 207 System.out.println(line); 208 line = readLine.next(); 209 } 210 System.exit(1); 211 } 212 } else { 213 s = ssl.createSocket(targetAddress, targetPort, 214 localAddress, localPort); 215 } 216 217 sslCipher = ((SSLSocket) s).getSession().getCipherSuite(); 218 System.out.println("Cipher: " + sslCipher); 219 System.out.println("================================================================================"); 220 221 String line1 = httpMethod + " " + path + " HTTP/1.1"; 222 if (hostHeader == null) { 223 hostHeader = targetAddress.getHostName(); 224 } 225 String line2 = "Host: " + hostHeader; 226 byte[] crlf = {'\r', '\n'}; 227 228 System.out.println("Writing: "); 229 System.out.println("================================================================================"); 230 System.out.println(line1); 231 System.out.println(line2); 232 System.out.println(); 233 234 out = s.getOutputStream(); 235 out.write(line1.getBytes()); 236 out.write(crlf); 237 out.write(line2.getBytes()); 238 out.write(crlf); 239 out.write(crlf); 240 out.flush(); 241 242 in = s.getInputStream(); 243 244 int c = in.read(); 245 StringBuffer buf = new StringBuffer(); 246 System.out.println("Reading: "); 247 System.out.println("================================================================================"); 248 while (c >= 0) { 249 byte b = (byte) c; 250 buf.append((char) b); 251 System.out.print((char) b); 252 if (-1 == buf.toString().indexOf("\r\n\r\n")) { 253 c = in.read(); 254 } else { 255 break; 256 } 257 } 258 } 259 catch (Exception e) { 260 socketException = e; 261 } 262 trustException = testTrust(ssl, sslCipher, trustChain); 263 hostnameException = testHostname(ssl); 264 crlException = testCRL(ssl); 265 expiryException = testExpiry(ssl); 266 } 267 finally { 268 if (out != null) { 269 out.close(); 270 } 271 if (in != null) { 272 in.close(); 273 } 274 if (s != null) { 275 s.close(); 276 } 277 278 X509Certificate[] peerChain = ssl.getCurrentServerChain(); 279 if (peerChain != null) { 280 String title = "Server Certificate Chain for: "; 281 title = peerChain.length > 1 ? title : "Server Certificate for: "; 282 System.out.println(title + "[" + target + "]"); 283 System.out.println("================================================================================"); 284 for (int i = 0; i < peerChain.length; i++) { 285 X509Certificate cert = peerChain[i]; 286 String certAsString = Certificates.toString(cert); 287 String certAsPEM = Certificates.toPEMString(cert); 288 if (i > 0) { 289 System.out.println(); 290 } 291 System.out.print(certAsString); 292 System.out.print(certAsPEM); 293 } 294 } 295 if (hostnameException != null) { 296 hostnameException.printStackTrace(); 297 System.out.println(); 298 } 299 if (crlException != null) { 300 crlException.printStackTrace(); 301 System.out.println(); 302 } 303 if (expiryException != null) { 304 expiryException.printStackTrace(); 305 System.out.println(); 306 } 307 if (trustException != null) { 308 trustException.printStackTrace(); 309 System.out.println(); 310 } 311 if (socketException != null) { 312 socketException.printStackTrace(); 313 System.out.println(); 314 } 315 } 316 } 317 318 private static Exception testTrust(SSLClient ssl, String cipher, 319 TrustChain tc) { 320 try { 321 X509Certificate[] chain = ssl.getCurrentServerChain(); 322 String authType = Util.cipherToAuthType(cipher); 323 if (authType == null) { 324 // default of "RSA" just for Ping's purposes. 325 authType = "RSA"; 326 } 327 if (chain != null) { 328 if (tc == null) { 329 tc = TrustMaterial.DEFAULT; 330 } 331 Object[] trustManagers = tc.getTrustManagers(); 332 for (int i = 0; i < trustManagers.length; i++) { 333 JavaImpl.testTrust(trustManagers[i], chain, authType); 334 } 335 } 336 } 337 catch (Exception e) { 338 return e; 339 } 340 return null; 341 } 342 343 private static Exception testHostname(SSLClient ssl) { 344 try { 345 X509Certificate[] chain = ssl.getCurrentServerChain(); 346 if (chain != null) { 347 String hostName = target.host; 348 HostnameVerifier.DEFAULT.check(hostName, chain[0]); 349 } 350 } 351 catch (Exception e) { 352 return e; 353 } 354 return null; 355 } 356 357 private static Exception testCRL(SSLClient ssl) { 358 try { 359 X509Certificate[] chain = ssl.getCurrentServerChain(); 360 if (chain != null) { 361 for (int i = 0; i < chain.length; i++) { 362 Certificates.checkCRL(chain[i]); 363 } 364 } 365 } 366 catch (Exception e) { 367 return e; 368 } 369 return null; 370 } 371 372 private static Exception testExpiry(SSLClient ssl) { 373 try { 374 X509Certificate[] chain = ssl.getCurrentServerChain(); 375 if (chain != null) { 376 for (int i = 0; i < chain.length; i++) { 377 chain[i].checkValidity(); 378 } 379 } 380 } 381 catch (Exception e) { 382 return e; 383 } 384 return null; 385 } 386 387 388 public static class Arg implements Comparable { 389 public final String shortArg; 390 public final String longArg; 391 public final String description; 392 public final boolean isRequired; 393 private final int id; 394 395 public Arg(String s, String l, String d) { 396 this(s, l, d, false); 397 } 398 399 public Arg(String s, String l, String d, boolean isRequired) { 400 this.isRequired = isRequired; 401 this.shortArg = s; 402 this.longArg = l; 403 this.description = d; 404 this.id = ARGS.size(); 405 ARGS.add(this); 406 if (s != null && s.length() >= 2) { 407 ARGS_MATCH.put(s, this); 408 } 409 if (l != null && l.length() >= 3) { 410 ARGS_MATCH.put(l, this); 411 } 412 } 413 414 public int compareTo(Object o) { 415 return id - ((Arg) o).id; 416 } 417 418 public String toString() { 419 return shortArg + "/" + longArg; 420 } 421 } 422 423 private static void parseArgs(String[] cargs) throws Exception { 424 Map args = Util.parseArgs(cargs); 425 Iterator it = args.entrySet().iterator(); 426 while (it.hasNext()) { 427 Map.Entry entry = (Map.Entry) it.next(); 428 Arg arg = (Arg) entry.getKey(); 429 String[] values = (String[]) entry.getValue(); 430 if (arg == ARG_TARGET) { 431 target = Util.toAddress(values[0], 443); 432 targetAddress = target.addr; 433 targetPort = target.port; 434 } else if (arg == ARG_BIND) { 435 local = Util.toAddress(values[0], 443); 436 localAddress = local.addr; 437 localPort = local.port; 438 } else if (arg == ARG_PROXY) { 439 proxy = Util.toAddress(values[0], 80); 440 } else if (arg == ARG_CLIENT_CERT) { 441 clientCert = new File(values[0]); 442 } else if (arg == ARG_CERT_CHAIN) { 443 certChain = new File(values[0]); 444 } else if (arg == ARG_PASSWORD) { 445 password = values[0].toCharArray(); 446 } else if (arg == ARG_METHOD) { 447 httpMethod = values[0].trim(); 448 } else if (arg == ARG_PATH) { 449 path = values[0].trim(); 450 } else if (arg == ARG_HOST_HEADER) { 451 hostHeader = values[0].trim(); 452 } else if (arg == ARG_TRUST_CERT) { 453 for (int i = 0; i < values.length; i++) { 454 File f = new File(values[i]); 455 if (f.exists()) { 456 if (trustChain == null) { 457 trustChain = new TrustChain(); 458 } 459 TrustMaterial tm = new TrustMaterial(f); 460 trustChain.addTrustMaterial(tm); 461 } 462 } 463 } 464 } 465 args.clear(); 466 for (int i = 0; i < cargs.length; i++) { 467 cargs[i] = null; 468 } 469 470 if (targetAddress == null) { 471 throw new IllegalArgumentException("\"" + ARG_TARGET + "\" is mandatory"); 472 } 473 } 474}