Coverage Report - com.sun.grizzly.util.SSLUtils
 
Classes in this File Line Coverage Branch Coverage Complexity
SSLUtils
40 %
74/185
41 %
45/111
0
SSLUtils$1
100 %
2/2
N/A
0
 
 1  
 /*
 2  
  * 
 3  
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 4  
  * 
 5  
  * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
 6  
  * 
 7  
  * The contents of this file are subject to the terms of either the GNU
 8  
  * General Public License Version 2 only ("GPL") or the Common Development
 9  
  * and Distribution License("CDDL") (collectively, the "License").  You
 10  
  * may not use this file except in compliance with the License. You can obtain
 11  
  * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 12  
  * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
 13  
  * language governing permissions and limitations under the License.
 14  
  * 
 15  
  * When distributing the software, include this License Header Notice in each
 16  
  * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
 17  
  * Sun designates this particular file as subject to the "Classpath" exception
 18  
  * as provided by Sun in the GPL Version 2 section of the License file that
 19  
  * accompanied this code.  If applicable, add the following below the License
 20  
  * Header, with the fields enclosed by brackets [] replaced by your own
 21  
  * identifying information: "Portions Copyrighted [year]
 22  
  * [name of copyright owner]"
 23  
  * 
 24  
  * Contributor(s):
 25  
  * 
 26  
  * If you wish your version of this file to be governed by only the CDDL or
 27  
  * only the GPL Version 2, indicate your decision by adding "[Contributor]
 28  
  * elects to include this software in this distribution under the [CDDL or GPL
 29  
  * Version 2] license."  If you don't indicate a single choice of license, a
 30  
  * recipient has the option to distribute your version of this file under
 31  
  * either the CDDL, the GPL Version 2 or to extend the choice of license to
 32  
  * its licensees as provided above.  However, if you add GPL Version 2 code
 33  
  * and therefore, elected the GPL Version 2 license, then the option applies
 34  
  * only if the new code is made subject to such option by the copyright
 35  
  * holder.
 36  
  *
 37  
  */
 38  
 
 39  
 package com.sun.grizzly.util;
 40  
 
 41  
 import com.sun.grizzly.Controller;
 42  
 import java.io.ByteArrayInputStream;
 43  
 import java.io.EOFException;
 44  
 import java.io.IOException;
 45  
 import java.nio.ByteBuffer;
 46  
 import java.nio.channels.SelectableChannel;
 47  
 import java.security.cert.Certificate;
 48  
 import java.security.cert.CertificateFactory;
 49  
 import java.security.cert.X509Certificate;
 50  
 import java.util.logging.Level;
 51  
 import java.util.logging.Logger;
 52  
 import javax.net.ssl.SSLEngine;
 53  
 import javax.net.ssl.SSLEngineResult;
 54  
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 55  
 import javax.net.ssl.SSLEngineResult.Status;
 56  
 
 57  
 /**
 58  
  * SSL over NIO utility class. The class handle the SSLEngine operations 
 59  
  * needed to support SSL over NIO. 
 60  
  *
 61  
  * TODO: Create an object that Wrap SSLEngine and its associated buffers.
 62  
  *
 63  
  * @author Jeanfrancois Arcand
 64  
  */
 65  0
 public class SSLUtils {
 66  
     
 67  
     /**
 68  
      * The maximum size a ByteBuffer can take.
 69  
      */
 70  
     public final static int MAX_BB_SIZE = 48 * 4096;
 71  
 
 72  
     
 73  
     /*
 74  
      * An empty ByteBuffer used for handshaking
 75  
      */
 76  1
     protected final static ByteBuffer hsBB = ByteBuffer.allocate(0);
 77  
    
 78  
     
 79  
     /**
 80  
      * The time to wait before timing out when reading bytes
 81  
      */
 82  1
     private static int readTimeout = 30000;    
 83  
     
 84  
     
 85  
     /**
 86  
      * Read and decrypt bytes from the underlying SSL connections.
 87  
      * @param socketChannel underlying socket channel
 88  
      * @param sslEngine{@link SSLEngine}
 89  
      * @param byteBuffer buffer for application decrypted data
 90  
      * @param inputBB buffer for reading enrypted data from socket
 91  
      * @return  number of bytes read
 92  
      * @throws java.io.IOException 
 93  
      */    
 94  
     public static int doSecureRead(SelectableChannel channel, SSLEngine sslEngine,
 95  
             ByteBuffer byteBuffer, ByteBuffer inputBB) throws IOException {
 96  
         
 97  91
         int initialPosition = byteBuffer.position();
 98  91
         int byteRead = 0;
 99  
         
 100  
         // We need to make sure the unwrap worked properly and we have all
 101  
         // the packets properly read. If the SSLEngine fail to unwrap all the 
 102  
         // bytes, the byteBuffer will be empty event if some encrypted bytes
 103  
         // are available. 
 104  181
         while (byteBuffer.position() == initialPosition){
 105  91
             int currentRead = SSLUtils.doRead(channel, inputBB,
 106  
                     sslEngine,readTimeout);
 107  
 
 108  91
             if (currentRead > 0) {
 109  90
                 byteRead += currentRead;
 110  
             }
 111  
             
 112  91
             if (currentRead > 0 || inputBB.position() > 0) {
 113  
                 try{
 114  90
                     byteBuffer = SSLUtils.unwrapAll(byteBuffer,
 115  
                             inputBB, sslEngine);
 116  
                     
 117  90
                     if (currentRead == -1 && 
 118  
                             byteBuffer.position() == initialPosition) {
 119  
                         // if last read was -1 and unwrap decoded nothing then return -1
 120  0
                         byteRead = -1;
 121  0
                         break;
 122  
                     }
 123  0
                 } catch (IOException ex){
 124  0
                     Logger logger = Controller.logger();
 125  0
                     if ( logger.isLoggable(Level.FINE) )
 126  0
                         logger.log(Level.FINE,"SSLUtils.unwrapAll",ex);
 127  0
                     return -1;
 128  90
                 }
 129  1
             } else if (currentRead == -1) {
 130  1
                 byteRead = -1;
 131  1
                 break;
 132  
             } else {
 133  
                 break;
 134  
             }   
 135  90
         }
 136  
 
 137  91
         return byteRead;
 138  
     }   
 139  
 
 140  
     /**
 141  
      * Read encrypted bytes using an{@link SSLEngine}.
 142  
      * @param channel The {@link SelectableChannel}
 143  
      * @param inputBB The byteBuffer to store encrypted bytes
 144  
      * @param sslEngine The{@link SSLEngine} uses to manage the 
 145  
      *                  SSL operations.
 146  
      * @param timeout The Selector.select() timeout value. A value of 0 will
 147  
      *                be exectuted as a Selector.selectNow();
 148  
      * @return the bytes read.
 149  
      */
 150  
     public static int doRead(SelectableChannel channel, ByteBuffer inputBB, 
 151  
             SSLEngine sslEngine, int timeout) { 
 152  
         
 153  659
         if (channel == null) return -1;
 154  
 
 155  
         try {
 156  659
             int bytesRead = Utils.readWithTemporarySelector(channel, 
 157  
                     inputBB, timeout);
 158  
             
 159  659
             if (bytesRead == -1) {
 160  
                 try {
 161  1
                     sslEngine.closeInbound();
 162  1
                 } catch (IOException ex) {
 163  0
                 }
 164  
             }
 165  
 
 166  659
             return bytesRead;
 167  0
         } catch (Throwable t){
 168  0
             Logger logger = Controller.logger();
 169  0
             if ( logger.isLoggable(Level.FINEST) ){
 170  0
                 logger.log(Level.FINEST,"doRead",t);
 171  
             }            
 172  0
             return -1;
 173  
         }
 174  
     } 
 175  
     
 176  
     
 177  
     /**
 178  
      * Unwrap all encrypted bytes from <code>inputBB</code> to 
 179  
      * {@link ByteBuffer} using the{@link SSLEngine}
 180  
      * @param byteBuffer the decrypted ByteBuffer
 181  
      * @param inputBB the encrypted ByteBuffer
 182  
      * @param sslEngine The SSLEngine used to manage the SSL operations.
 183  
      * @return the decrypted ByteBuffer
 184  
      * @throws java.io.IOException 
 185  
      */
 186  
     public static ByteBuffer unwrapAll(ByteBuffer byteBuffer, 
 187  
             ByteBuffer inputBB, SSLEngine sslEngine) throws IOException{
 188  
         
 189  53973
         SSLEngineResult result = null;
 190  
         do{
 191  
             try{
 192  510505
                result = unwrap(byteBuffer,inputBB,sslEngine);
 193  0
             } catch (Throwable ex){
 194  0
                 Logger logger = Controller.logger();
 195  0
                 if ( logger.isLoggable(Level.FINE) ){
 196  0
                     logger.log(Level.FINE,"unwrap",ex);
 197  
                 }
 198  0
                 inputBB.compact();
 199  510505
             }
 200  
 
 201  510505
             if (result != null){
 202  1
                 switch (result.getStatus()) {
 203  
 
 204  
                     case BUFFER_UNDERFLOW:
 205  
                     case CLOSED:
 206  
                         // Closed or need more data.
 207  224
                         break;
 208  
                     case OK:
 209  510281
                         if (result.getHandshakeStatus() 
 210  
                                 == HandshakeStatus.NEED_TASK) {
 211  0
                             executeDelegatedTask(sslEngine);
 212  
                         }
 213  
                         break;
 214  
                     case BUFFER_OVERFLOW:
 215  0
                          byteBuffer = reallocate(byteBuffer);
 216  0
                          break;
 217  
                     default:                       
 218  0
                         throw new 
 219  0
                              IOException("Unwrap error: "+ result.getStatus());
 220  
                  }   
 221  
              }
 222  
         } while (inputBB.position() > 0 && result!= null &&
 223  510505
                 result.getStatus() != Status.BUFFER_UNDERFLOW);
 224  53973
         return byteBuffer;
 225  
     }
 226  
     
 227  
     
 228  
     /**
 229  
      * Unwrap available encrypted bytes from <code>inputBB</code> to 
 230  
      * {@link ByteBuffer} using the{@link SSLEngine}
 231  
      * @param byteBuffer the decrypted ByteBuffer
 232  
      * @param inputBB the encrypted ByteBuffer
 233  
      * @param sslEngine The SSLEngine used to manage the SSL operations.
 234  
      * @return SSLEngineResult of the SSLEngine.unwrap operation.
 235  
      * @throws java.io.IOException 
 236  
      */
 237  
     public static SSLEngineResult unwrap(ByteBuffer byteBuffer, 
 238  
             ByteBuffer inputBB, SSLEngine sslEngine) throws IOException{
 239  
 
 240  
         // Logging block
 241  511404
         if (Controller.logger().isLoggable(Level.FINE)) {
 242  0
             Controller.logger().log(Level.FINE, "start unwrap. buffer: " + 
 243  
                     byteBuffer + " secured: " + inputBB);
 244  0
             if (Controller.logger().isLoggable(Level.FINER)) {
 245  0
                 StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
 246  0
                 StringBuffer buffer = new StringBuffer();
 247  0
                 for (StackTraceElement element : stackTraceElements) {
 248  0
                     buffer.append('\n');
 249  0
                     buffer.append(element);
 250  
                 }
 251  
 
 252  0
                 Controller.logger().log(Level.FINER, buffer.toString());
 253  
             }
 254  
         }
 255  
 
 256  511404
         inputBB.flip();        
 257  511404
         SSLEngineResult result = sslEngine.unwrap(inputBB, byteBuffer);
 258  511402
         inputBB.compact();
 259  
         
 260  
         // Logging block
 261  511402
         if (Controller.logger().isLoggable(Level.FINE)) {
 262  0
             int bytesProduced = result.bytesProduced();
 263  0
             Controller.logger().log(Level.FINE, "after unwrap. buffer: " + 
 264  
                     byteBuffer + " secured: " + inputBB + " consumed: " + 
 265  
                     result.bytesConsumed() + " produced: " + bytesProduced + 
 266  
                     " status: " + result.getStatus());
 267  0
             if (bytesProduced > 0 && Controller.logger().isLoggable(Level.FINER)) {
 268  0
                 byteBuffer.position(byteBuffer.position() - bytesProduced);
 269  0
                 byte[] producedBytes = new byte[bytesProduced];
 270  0
                 byteBuffer.get(producedBytes);
 271  0
                 Controller.logger().log(Level.FINER, new String(producedBytes));
 272  
             }
 273  
         }
 274  
         
 275  511402
         return result;
 276  
     }
 277  
     
 278  
     
 279  
     /**
 280  
      * Encrypt bytes.
 281  
      * @param byteBuffer the decrypted ByteBuffer
 282  
      * @param outputBB the encrypted ByteBuffer
 283  
      * @param sslEngine The SSLEngine used to manage the SSL operations.
 284  
      * @return SSLEngineResult of the SSLEngine.wrap operation.
 285  
      * @throws java.io.IOException 
 286  
      */
 287  
     public static SSLEngineResult wrap(ByteBuffer byteBuffer,
 288  
             ByteBuffer outputBB, SSLEngine sslEngine) throws IOException {        
 289  
         
 290  1294
         outputBB.clear();   
 291  1294
         SSLEngineResult result = sslEngine.wrap(byteBuffer, outputBB);
 292  1294
         outputBB.flip();
 293  1294
         return result;
 294  
     }
 295  
     
 296  
     
 297  
     /**
 298  
      * Resize a ByteBuffer.
 299  
      * @param byteBuffer  {@link ByteBuffer} to re-allocate
 300  
      * @return  {@link ByteBuffer} reallocted
 301  
      * @throws java.io.IOException 
 302  
      */
 303  
     private static ByteBuffer reallocate(ByteBuffer byteBuffer) 
 304  
             throws IOException{
 305  
         
 306  0
         if (byteBuffer.capacity() > MAX_BB_SIZE){
 307  0
             throw new IOException("Unwrap error: BUFFER_OVERFLOW");
 308  
         }
 309  0
         ByteBuffer tmp = ByteBuffer.allocate(byteBuffer.capacity() * 2);
 310  0
         byteBuffer.flip();
 311  0
         tmp.put(byteBuffer);
 312  0
         byteBuffer = tmp;
 313  0
         return byteBuffer;
 314  
     }
 315  
     
 316  
      
 317  
     /**
 318  
      * Complete hanshakes operations.
 319  
      * @param sslEngine The SSLEngine used to manage the SSL operations.
 320  
      * @return SSLEngineResult.HandshakeStatus
 321  
      */
 322  
     public static SSLEngineResult.HandshakeStatus 
 323  
             executeDelegatedTask(SSLEngine sslEngine) {
 324  
 
 325  
         Runnable runnable;
 326  662
         while ((runnable = sslEngine.getDelegatedTask()) != null) {
 327  331
             runnable.run();
 328  
         }
 329  331
         return sslEngine.getHandshakeStatus();
 330  
     }
 331  
     
 332  
     
 333  
     /**
 334  
      * Perform an SSL handshake using the SSLEngine. 
 335  
      * Note: If handshake was done successfully - outputBB will be cleared out,
 336  
      *       but this is *not* ready data to be written.
 337  
      * 
 338  
      * @param channel the {@link SelectableChannel}
 339  
      * @param byteBuffer The application {@link ByteBuffer}
 340  
      * @param inputBB The encrypted input {@link ByteBuffer}
 341  
      * @param outputBB The encrypted output {@link ByteBuffer}
 342  
      * @param sslEngine The SSLEngine used.
 343  
      * @param handshakeStatus The current handshake status
 344  
      * @return byteBuffer the new ByteBuffer
 345  
      * @throws java.io.IOException 
 346  
      * @throw IOException if the handshake fail.
 347  
      */
 348  
     public static ByteBuffer doHandshake(SelectableChannel channel,
 349  
             ByteBuffer byteBuffer, ByteBuffer inputBB, ByteBuffer outputBB,
 350  
             SSLEngine sslEngine, HandshakeStatus handshakeStatus) 
 351  
             throws IOException {
 352  103
         return doHandshake(channel, byteBuffer, inputBB, outputBB,
 353  
                 sslEngine, handshakeStatus, readTimeout);
 354  
     }
 355  
 
 356  
     
 357  
     /**
 358  
      * Perform an SSL handshake using the SSLEngine. 
 359  
      * Note: If handshake was done successfully - outputBB will be cleared out,
 360  
      *       but this is *not* ready data to be written.
 361  
      * 
 362  
      * @param channel the {@link SelectableChannel}
 363  
      * @param byteBuffer The application {@link ByteBuffer}
 364  
      * @param inputBB The encrypted input {@link ByteBuffer}
 365  
      * @param outputBB The encrypted output {@link ByteBuffer}
 366  
      * @param sslEngine The SSLEngine used.
 367  
      * @param handshakeStatus The current handshake status
 368  
      * @param timeout 
 369  
      * @return byteBuffer the new ByteBuffer
 370  
      * @throws java.io.IOException 
 371  
      * @throws IOException if the handshake fail.
 372  
      */
 373  
     public static ByteBuffer doHandshake(SelectableChannel channel,
 374  
             ByteBuffer byteBuffer, ByteBuffer inputBB, ByteBuffer outputBB,
 375  
             SSLEngine sslEngine, HandshakeStatus handshakeStatus,int timeout) 
 376  
             throws IOException {
 377  219
         return doHandshake(channel, byteBuffer, inputBB, outputBB,
 378  
                 sslEngine, handshakeStatus, timeout, inputBB.position() > 0);
 379  
     }
 380  
 
 381  
     /**
 382  
      * Perform an SSL handshake using the SSLEngine.
 383  
      * Note: If handshake was done successfully - outputBB will be cleared out,
 384  
      *       but this is *not* ready data to be written.
 385  
      * 
 386  
      * @param channel the {@link SelectableChannel}
 387  
      * @param byteBuffer The application {@link ByteBuffer}
 388  
      * @param inputBB The encrypted input {@link ByteBuffer}
 389  
      * @param outputBB The encrypted output {@link ByteBuffer}
 390  
      * @param sslEngine The SSLEngine used.
 391  
      * @param handshakeStatus The current handshake status
 392  
      * @param timeout 
 393  
      * @param useReadyBuffer does method need to read data before UNWRAP or use
 394  
      *                       a data from inputBB
 395  
      * @return byteBuffer the new ByteBuffer
 396  
      * @throws java.io.IOException 
 397  
      * @throws IOException if the handshake fail.
 398  
      */
 399  
     public static ByteBuffer doHandshake(SelectableChannel channel,
 400  
             ByteBuffer byteBuffer, ByteBuffer inputBB, ByteBuffer outputBB,
 401  
             SSLEngine sslEngine, HandshakeStatus handshakeStatus,
 402  
             int timeout,boolean useReadyBuffer)
 403  
             throws IOException {
 404  
         
 405  
         SSLEngineResult result;
 406  219
         int eof = timeout > 0 ? 0 : -1;
 407  1105
         while (handshakeStatus != HandshakeStatus.FINISHED){
 408  991
             switch (handshakeStatus) {
 409  
                case NEED_UNWRAP:
 410  568
                     if (!useReadyBuffer) {
 411  568
                         if (doRead(channel, inputBB, sslEngine, timeout) <= eof) {
 412  
                             try {
 413  0
                                 sslEngine.closeInbound();
 414  0
                             } catch (IOException ex) {
 415  0
                                 Logger logger = Controller.logger();
 416  0
                                 if (logger.isLoggable(Level.FINE)) {
 417  0
                                     logger.log(Level.FINE, "closeInbound", ex);
 418  
                                 }
 419  0
                             }
 420  0
                             throw new EOFException("Connection closed");
 421  
                         }
 422  
                     } else {
 423  0
                         useReadyBuffer = false;
 424  
                     }
 425  
                     
 426  1230
                     while (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
 427  899
                         result = unwrap(byteBuffer,inputBB,sslEngine);
 428  897
                         handshakeStatus = result.getHandshakeStatus();
 429  
                         
 430  897
                         if (result.getStatus() == Status.BUFFER_UNDERFLOW){
 431  132
                             break;
 432  
                         }
 433  
                         
 434  765
                         switch (result.getStatus()) {
 435  
                             case OK:
 436  1
                                 switch (handshakeStatus) {
 437  
                                     case NOT_HANDSHAKING:
 438  0
                                         throw new IOException("No Hanshake");
 439  
 
 440  
                                     case NEED_TASK:
 441  331
                                         handshakeStatus = 
 442  
                                                 executeDelegatedTask(sslEngine);
 443  331
                                         break;                               
 444  
 
 445  
                                     case FINISHED:
 446  103
                                        return byteBuffer;
 447  
                                 }
 448  662
                                 break;
 449  
                             case BUFFER_OVERFLOW:
 450  0
                                 byteBuffer = reallocate(byteBuffer);     
 451  0
                                 break;
 452  
                             default: 
 453  0
                                 throw new IOException("Handshake exception: " + 
 454  
                                         result.getStatus());
 455  
                         }
 456  
                     }  
 457  
 
 458  463
                     if (handshakeStatus != HandshakeStatus.NEED_WRAP) {
 459  132
                         break;
 460  
                     }
 461  
                 case NEED_WRAP:
 462  754
                     result = wrap(hsBB,outputBB,sslEngine);
 463  754
                     handshakeStatus = result.getHandshakeStatus();
 464  754
                     switch (result.getStatus()) {
 465  
                         case OK:
 466  
 
 467  754
                             if (handshakeStatus == HandshakeStatus.NEED_TASK) {
 468  0
                                 handshakeStatus = executeDelegatedTask(sslEngine);
 469  
                             }
 470  
 
 471  
                             // Flush all Server bytes to the client.
 472  754
                             if (channel != null) {
 473  754
                                 OutputWriter.flushChannel(
 474  
                                         channel, outputBB);
 475  754
                                 outputBB.clear();
 476  
                             }
 477  
                             break;
 478  
                         default: 
 479  0
                             throw new IOException("Handshaking error: " 
 480  
                                     + result.getStatus());
 481  
                         }
 482  
                         break;
 483  
                 default: 
 484  0
                     throw new RuntimeException("Invalid Handshaking State" +
 485  
                             handshakeStatus);
 486  
             } 
 487  
         }
 488  114
         return byteBuffer;
 489  
     }
 490  
 
 491  
     
 492  
     /**
 493  
      * Get the peer certificate list by initiating a new handshake.
 494  
      * @param channel {@link SelectableChannel}
 495  
      * @param needClientAuth 
 496  
      * @return Object[] An array of X509Certificate.
 497  
      * @throws java.io.IOException 
 498  
      */
 499  
     public static Object[] doPeerCertificateChain(SelectableChannel channel,
 500  
             ByteBuffer byteBuffer, ByteBuffer inputBB, ByteBuffer outputBB,
 501  
             SSLEngine sslEngine, boolean needClientAuth, int timeout) throws IOException {
 502  
         
 503  0
         Logger logger = Controller.logger();
 504  
     
 505  0
         Certificate[] certs=null;
 506  
         try {
 507  0
             certs = sslEngine.getSession().getPeerCertificates();
 508  0
         } catch( Throwable t ) {
 509  0
             if ( logger.isLoggable(Level.FINE))
 510  0
                 logger.log(Level.FINE,"Error getting client certs",t);
 511  0
         }
 512  
  
 513  0
         if (certs == null && needClientAuth){
 514  0
             sslEngine.getSession().invalidate();
 515  0
             sslEngine.setNeedClientAuth(true);
 516  0
             sslEngine.beginHandshake();         
 517  
                       
 518  0
             ByteBuffer origBB = byteBuffer;
 519  
             // In case the application hasn't read all the body bytes.
 520  0
             if ( origBB.position() != origBB.limit() ){
 521  0
                 byteBuffer = ByteBuffer.allocate(origBB.capacity());
 522  
             } else {
 523  0
                 byteBuffer.clear();
 524  
             }
 525  0
             outputBB.position(0);
 526  0
             outputBB.limit(0); 
 527  
             
 528  
             // We invalidate ssl seesion, so no need for unwrap
 529  
             try{
 530  0
                 doHandshake(channel, byteBuffer, inputBB, outputBB, 
 531  
                         sslEngine, HandshakeStatus.NEED_WRAP, timeout);
 532  0
             } catch (Throwable ex){
 533  0
                 if ( logger.isLoggable(Level.FINE))
 534  0
                     logger.log(Level.FINE,"Error during handshake",ex);   
 535  0
                 return null;
 536  
             } finally {
 537  0
                 byteBuffer = origBB;
 538  0
                 byteBuffer.clear();
 539  0
             }            
 540  
             
 541  
             try {
 542  0
                 certs = sslEngine.getSession().getPeerCertificates();
 543  0
             } catch( Throwable t ) {
 544  0
                 if ( logger.isLoggable(Level.FINE))
 545  0
                     logger.log(Level.FINE,"Error getting client certs",t);
 546  0
             }
 547  
         }
 548  
         
 549  0
         if( certs==null ) return null;
 550  
         
 551  0
         X509Certificate[] x509Certs = new X509Certificate[certs.length];
 552  0
         for(int i=0; i < certs.length; i++) {
 553  0
             if( certs[i] instanceof X509Certificate ) {
 554  0
                 x509Certs[i] = (X509Certificate)certs[i];
 555  
             } else {
 556  
                 try {
 557  0
                     byte [] buffer = certs[i].getEncoded();
 558  0
                     CertificateFactory cf =
 559  
                     CertificateFactory.getInstance("X.509");
 560  0
                     ByteArrayInputStream stream = new ByteArrayInputStream(buffer);
 561  0
                     x509Certs[i] = (X509Certificate)
 562  
                     cf.generateCertificate(stream);
 563  0
                 } catch(Exception ex) { 
 564  0
                     logger.log(Level.INFO,"Error translating cert " + certs[i],
 565  
                                      ex);
 566  0
                     return null;
 567  0
                 }
 568  
             }
 569  
             
 570  0
             if(logger.isLoggable(Level.FINE))
 571  0
                 logger.log(Level.FINE,"Cert #" + i + " = " + x509Certs[i]);
 572  
         }
 573  
         
 574  0
         if(x509Certs.length < 1)
 575  0
             return null;
 576  
             
 577  0
         return x509Certs;
 578  
     }
 579  
     
 580  
     
 581  
     public static int getReadTimeout() {
 582  116
         return readTimeout;
 583  
     }
 584  
 
 585  
     
 586  
     public static void setReadTimeout(int aReadTimeout) {
 587  0
         readTimeout = aReadTimeout;
 588  0
     }
 589  
 
 590  
 }