001 /*
002 * CDDL HEADER START
003 *
004 * The contents of this file are subject to the terms of the
005 * Common Development and Distribution License, Version 1.0 only
006 * (the "License"). You may not use this file except in compliance
007 * with the License.
008 *
009 * You can obtain a copy of the license at
010 * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011 * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012 * See the License for the specific language governing permissions
013 * and limitations under the License.
014 *
015 * When distributing Covered Code, include this CDDL HEADER in each
016 * file and include the License file at
017 * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable,
018 * add the following below this CDDL HEADER, with the fields enclosed
019 * by brackets "[]" replaced with your own identifying information:
020 * Portions Copyright [yyyy] [name of copyright owner]
021 *
022 * CDDL HEADER END
023 *
024 *
025 * Copyright 2006-2008 Sun Microsystems, Inc.
026 */
027 package org.opends.server.extensions;
028
029
030
031 import java.io.IOException;
032 import java.net.InetAddress;
033 import java.net.Socket;
034 import java.nio.ByteBuffer;
035 import java.nio.channels.SocketChannel;
036 import java.security.cert.Certificate;
037 import javax.net.ssl.SSLContext;
038 import javax.net.ssl.SSLEngine;
039 import javax.net.ssl.SSLEngineResult;
040 import javax.net.ssl.SSLSession;
041
042 import org.opends.messages.Message;
043 import org.opends.server.api.ClientConnection;
044 import org.opends.server.api.ConnectionSecurityProvider;
045 import org.opends.server.api.KeyManagerProvider;
046 import org.opends.server.api.TrustManagerProvider;
047 import org.opends.server.config.ConfigEntry;
048 import org.opends.server.config.ConfigException;
049 import org.opends.server.core.DirectoryServer;
050 import org.opends.server.loggers.debug.DebugTracer;
051 import org.opends.server.types.DebugLogLevel;
052 import org.opends.server.types.DirectoryException;
053 import org.opends.server.types.DisconnectReason;
054 import org.opends.server.types.InitializationException;
055 import org.opends.server.types.SSLClientAuthPolicy;
056 import org.opends.server.util.SelectableCertificateKeyManager;
057
058 import static org.opends.messages.ExtensionMessages.*;
059 import static org.opends.server.loggers.debug.DebugLogger.*;
060 import static org.opends.server.util.StaticUtils.*;
061
062
063
064 /**
065 * This class provides an implementation of a connection security provider that
066 * uses SSL/TLS to encrypt the communication to and from the client. It uses
067 * the {@code javax.net.ssl.SSLEngine} class to provide the actual SSL
068 * communication layer, and the Directory Server key and trust store providers
069 * to determine which key and trust stores to use.
070 */
071 public class TLSConnectionSecurityProvider
072 extends ConnectionSecurityProvider
073 {
074 /**
075 * The tracer object for the debug logger.
076 */
077 private static final DebugTracer TRACER = getTracer();
078
079
080
081 /**
082 * The SSL context name that should be used for this TLS connection security
083 * provider.
084 */
085 private static final String SSL_CONTEXT_INSTANCE_NAME = "TLS";
086
087
088
089 // The buffer that will be used when reading clear-text data.
090 private ByteBuffer clearInBuffer;
091
092 // The buffer that will be used when writing clear-text data.
093 private ByteBuffer clearOutBuffer;
094
095 // The buffer that will be used when reading encrypted data.
096 private ByteBuffer sslInBuffer;
097
098 // The buffer that willa be used when writing encrypted data.
099 private ByteBuffer sslOutBuffer;
100
101 // The client connection with which this security provider is associated.
102 private ClientConnection clientConnection;
103
104 // The size in bytes that should be used for the buffer holding clear-text
105 // data.
106 private int clearBufferSize;
107
108 // The size in bytes that should be used for the buffer holding the encrypted
109 // data.
110 private int sslBufferSize;
111
112 // The socket channel that may be used to communicate with the client.
113 private SocketChannel socketChannel;
114
115 // The SSL client certificate policy.
116 private SSLClientAuthPolicy sslClientAuthPolicy;
117
118 // The SSL context that will be used for all SSL/TLS communication.
119 private SSLContext sslContext;
120
121 // The SSL engine that will be used for this connection.
122 private SSLEngine sslEngine;
123
124 // The set of cipher suites to allow.
125 private String[] enabledCipherSuites;
126
127 // The set of protocols to allow.
128 private String[] enabledProtocols;
129
130
131
132 /**
133 * Creates a new instance of this connection security provider. Note that
134 * no initialization should be done here, since it should all be done in the
135 * {@code initializeConnectionSecurityProvider} method. Also note that this
136 * instance should only be used to create new instances that are associated
137 * with specific client connections. This instance itself should not be used
138 * to attempt secure communication with the client.
139 */
140 public TLSConnectionSecurityProvider()
141 {
142 super();
143
144 }
145
146
147
148 /**
149 * Creates a new instance of this connection security provider that will be
150 * associated with the provided client connection.
151 *
152 * @param clientConnection The client connection with which this connection
153 * security provider should be associated.
154 * @param socketChannel The socket channel that may be used to
155 * communicate with the client.
156 * @param parentProvider A reference to the parent TLS connection security
157 * provider that is being used to create this
158 * instance.
159 */
160 private TLSConnectionSecurityProvider(ClientConnection clientConnection,
161 SocketChannel socketChannel,
162 TLSConnectionSecurityProvider
163 parentProvider)
164 throws DirectoryException
165 {
166 super();
167
168
169 this.clientConnection = clientConnection;
170 this.socketChannel = socketChannel;
171
172 Socket socket = socketChannel.socket();
173 InetAddress inetAddress = socketChannel.socket().getInetAddress();
174
175
176 // Create an SSL session based on the configured key and trust stores in the
177 // Directory Server.
178 KeyManagerProvider keyManagerProvider =
179 DirectoryServer.getKeyManagerProvider(
180 clientConnection.getKeyManagerProviderDN());
181 if (keyManagerProvider == null)
182 {
183 keyManagerProvider = new NullKeyManagerProvider();
184 }
185
186 TrustManagerProvider trustManagerProvider =
187 DirectoryServer.getTrustManagerProvider(
188 clientConnection.getTrustManagerProviderDN());
189 if (trustManagerProvider == null)
190 {
191 trustManagerProvider = new NullTrustManagerProvider();
192 }
193
194 try
195 {
196 // FIXME -- Is it bad to create a new SSLContext for each connection?
197 sslContext = SSLContext.getInstance(SSL_CONTEXT_INSTANCE_NAME);
198
199 String alias = clientConnection.getCertificateAlias();
200 if (alias == null)
201 {
202 sslContext.init(keyManagerProvider.getKeyManagers(),
203 trustManagerProvider.getTrustManagers(), null);
204 }
205 else
206 {
207 sslContext.init(SelectableCertificateKeyManager.wrap(
208 keyManagerProvider.getKeyManagers(), alias),
209 trustManagerProvider.getTrustManagers(), null);
210 }
211 }
212 catch (Exception e)
213 {
214 if (debugEnabled())
215 {
216 TRACER.debugCaught(DebugLogLevel.ERROR, e);
217 }
218
219 Message message = ERR_TLS_SECURITY_PROVIDER_CANNOT_INITIALIZE.get(
220 getExceptionMessage(e));
221 throw new DirectoryException(DirectoryServer.getServerErrorResultCode(),
222 message, e);
223 }
224
225 sslEngine = sslContext.createSSLEngine(inetAddress.getHostName(),
226 socket.getPort());
227 sslEngine.setUseClientMode(false);
228
229 enabledProtocols = parentProvider.enabledProtocols;
230 if (enabledProtocols != null)
231 {
232 sslEngine.setEnabledProtocols(enabledProtocols);
233 }
234
235 enabledCipherSuites = parentProvider.enabledCipherSuites;
236 if (enabledCipherSuites != null)
237 {
238 sslEngine.setEnabledCipherSuites(enabledCipherSuites);
239 }
240
241 sslClientAuthPolicy = parentProvider.sslClientAuthPolicy;
242 if (sslClientAuthPolicy == null)
243 {
244 sslClientAuthPolicy = SSLClientAuthPolicy.OPTIONAL;
245 }
246 switch (sslClientAuthPolicy)
247 {
248 case REQUIRED:
249 sslEngine.setWantClientAuth(true);
250 sslEngine.setNeedClientAuth(true);
251 break;
252
253 case DISABLED:
254 sslEngine.setNeedClientAuth(false);
255 sslEngine.setWantClientAuth(false);
256 break;
257
258 case OPTIONAL:
259 default:
260 sslEngine.setNeedClientAuth(false);
261 sslEngine.setWantClientAuth(true);
262 break;
263 }
264
265 SSLSession sslSession = sslEngine.getSession();
266
267 clearBufferSize = sslSession.getApplicationBufferSize();
268 clearInBuffer = ByteBuffer.allocate(clearBufferSize);
269 clearOutBuffer = ByteBuffer.allocate(clearBufferSize);
270
271 sslBufferSize = sslSession.getPacketBufferSize();
272 sslInBuffer = ByteBuffer.allocate(sslBufferSize);
273 sslOutBuffer = ByteBuffer.allocate(sslBufferSize);
274 }
275
276
277
278 /**
279 * {@inheritDoc}
280 */
281 @Override()
282 public void initializeConnectionSecurityProvider(ConfigEntry configEntry)
283 throws ConfigException, InitializationException
284 {
285 // Initialize default values for the connection-specific variables.
286 clientConnection = null;
287 socketChannel = null;
288
289 clearInBuffer = null;
290 clearOutBuffer = null;
291 sslInBuffer = null;
292 sslOutBuffer = null;
293 clearBufferSize = -1;
294 sslBufferSize = -1;
295
296 sslEngine = null;
297
298 enabledProtocols = null;
299 enabledCipherSuites = null;
300 sslClientAuthPolicy = SSLClientAuthPolicy.OPTIONAL;
301 }
302
303
304
305 /**
306 * {@inheritDoc}
307 */
308 @Override()
309 public void finalizeConnectionSecurityProvider()
310 {
311 // No implementation is required.
312 }
313
314
315
316 /**
317 * {@inheritDoc}
318 */
319 @Override()
320 public String getSecurityMechanismName()
321 {
322 return SSL_CONTEXT_INSTANCE_NAME;
323 }
324
325
326
327 /**
328 * {@inheritDoc}
329 */
330 @Override()
331 public boolean isSecure()
332 {
333 // This should be considered secure.
334 return true;
335 }
336
337
338
339 /**
340 * {@inheritDoc}
341 */
342 @Override()
343 public ConnectionSecurityProvider newInstance(ClientConnection
344 clientConnection,
345 SocketChannel socketChannel)
346 throws DirectoryException
347 {
348 return new TLSConnectionSecurityProvider(clientConnection, socketChannel,
349 this);
350 }
351
352
353
354 /**
355 * {@inheritDoc}
356 */
357 @Override()
358 public void disconnect(boolean connectionValid)
359 {
360 if (connectionValid)
361 {
362 try
363 {
364 sslEngine.closeInbound();
365 sslEngine.closeOutbound();
366
367 while (true)
368 {
369 switch (sslEngine.getHandshakeStatus())
370 {
371 case FINISHED:
372 case NOT_HANDSHAKING:
373 // We don't need to do anything else.
374 return;
375
376 case NEED_TASK:
377 // We need to process some task before continuing.
378 Runnable task = sslEngine.getDelegatedTask();
379 task.run();
380 break;
381
382 case NEED_WRAP:
383 // We need to send data to the client.
384 clearOutBuffer.clear();
385 sslOutBuffer.clear();
386 sslEngine.wrap(clearOutBuffer, sslOutBuffer);
387 sslOutBuffer.flip();
388 while (sslOutBuffer.hasRemaining())
389 {
390 socketChannel.write(sslOutBuffer);
391 }
392 break;
393
394 case NEED_UNWRAP:
395 // We need to read data from the client. We can do this if it's
396 // immediately available, but otherwise, ignore it because
397 // otherwise it could chew up a lot of time.
398 if (sslInBuffer.hasRemaining())
399 {
400 clearInBuffer.clear();
401 sslEngine.unwrap(sslInBuffer, clearInBuffer);
402 clearInBuffer.flip();
403 }
404 else
405 {
406 sslInBuffer.clear();
407 clearInBuffer.clear();
408 int bytesRead = socketChannel.read(sslInBuffer);
409 if (bytesRead <= 0)
410 {
411 return;
412 }
413 sslEngine.unwrap(sslInBuffer, clearInBuffer);
414 clearInBuffer.flip();
415 }
416 }
417 }
418 }
419 catch (Exception e)
420 {
421 if (debugEnabled())
422 {
423 TRACER.debugCaught(DebugLogLevel.ERROR, e);
424 }
425 }
426 }
427 }
428
429
430
431 /**
432 * {@inheritDoc}
433 */
434 @Override()
435 public int getClearBufferSize()
436 {
437 return clearBufferSize;
438 }
439
440
441
442 /**
443 * {@inheritDoc}
444 */
445 @Override()
446 public int getEncodedBufferSize()
447 {
448 return sslBufferSize;
449 }
450
451
452
453 /**
454 * {@inheritDoc}
455 */
456 @Override()
457 public boolean readData()
458 {
459 while (true)
460 {
461 try
462 {
463 sslInBuffer.clear();
464 int bytesRead = socketChannel.read(sslInBuffer);
465 sslInBuffer.flip();
466
467 if (bytesRead < 0)
468 {
469 // The client connection has been closed. Disconnect and return.
470 clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT, false,
471 null);
472 return false;
473 }
474
475
476 // See if there is any preliminary handshake work to do.
477 handshakeLoop:
478 while (true)
479 {
480 switch (sslEngine.getHandshakeStatus())
481 {
482 case NEED_TASK:
483 Runnable task = sslEngine.getDelegatedTask();
484 task.run();
485 break;
486
487 case NEED_WRAP:
488 clearOutBuffer.clear();
489 sslOutBuffer.clear();
490 sslEngine.wrap(clearOutBuffer, sslOutBuffer);
491 sslOutBuffer.flip();
492
493 while (sslOutBuffer.hasRemaining())
494 {
495 int bytesWritten = socketChannel.write(sslOutBuffer);
496 if (bytesWritten < 0)
497 {
498 // The client connection has been closed. Disconnect and
499 // return.
500 clientConnection.disconnect(
501 DisconnectReason.CLIENT_DISCONNECT, false, null);
502 return false;
503 }
504 }
505 break;
506
507 default:
508 break handshakeLoop;
509 }
510 }
511
512 if (bytesRead == 0)
513 {
514 // We don't have any data to process, and we've already done any
515 // necessary handshaking, so we can break out and wait for more data
516 // to arrive.
517 return true;
518 }
519
520
521 // Read any SSL-encrypted data provided by the client.
522 while (sslInBuffer.hasRemaining())
523 {
524 clearInBuffer.clear();
525 SSLEngineResult unwrapResult = sslEngine.unwrap(sslInBuffer,
526 clearInBuffer);
527 clearInBuffer.flip();
528
529 switch (unwrapResult.getStatus())
530 {
531 case OK:
532 // This is fine.
533 break;
534
535 case CLOSED:
536 // The client connection (or at least the SSL side of it) has been
537 // closed.
538 // FIXME -- Allow for closing the SSL channel without closing the
539 // underlying connection.
540 clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
541 false, null);
542 return false;
543
544 default:
545 // This should not have happened.
546 clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
547 false,
548 ERR_TLS_SECURITY_PROVIDER_UNEXPECTED_UNWRAP_STATUS.get(
549 String.valueOf(unwrapResult.getStatus())));
550 return false;
551 }
552
553 switch (unwrapResult.getHandshakeStatus())
554 {
555 case NEED_TASK:
556 Runnable task = sslEngine.getDelegatedTask();
557 task.run();
558 break;
559
560 case NEED_WRAP:
561 clearOutBuffer.clear();
562 sslOutBuffer.clear();
563 sslEngine.wrap(clearOutBuffer, sslOutBuffer);
564 sslOutBuffer.flip();
565
566 while (sslOutBuffer.hasRemaining())
567 {
568 int bytesWritten = socketChannel.write(sslOutBuffer);
569 if (bytesWritten < 0)
570 {
571 // The client connection has been closed. Disconnect and
572 // return.
573 clientConnection.disconnect(
574 DisconnectReason.CLIENT_DISCONNECT, false, null);
575 return false;
576 }
577 }
578 break;
579 }
580
581 // If there is any clear-text data, then process it.
582 if (! clientConnection.processDataRead(clearInBuffer))
583 {
584 // If this happens, then the client connection disconnect method
585 // should have already been called, so we don't need to do it again.
586 return false;
587 }
588 }
589 }
590 catch (IOException ioe)
591 {
592 if (debugEnabled())
593 {
594 TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
595 }
596
597 // An error occurred while trying to communicate with the client.
598 // Disconnect and return.
599 clientConnection.disconnect(DisconnectReason.IO_ERROR, false, null);
600 return false;
601 }
602 catch (Exception e)
603 {
604 if (debugEnabled())
605 {
606 TRACER.debugCaught(DebugLogLevel.ERROR, e);
607 }
608
609 // An unexpected error occurred while trying to process the data read.
610 // Disconnect and return.
611 clientConnection.disconnect(DisconnectReason.SERVER_ERROR, true,
612 ERR_TLS_SECURITY_PROVIDER_READ_ERROR.get(
613 getExceptionMessage(e)));
614 return false;
615 }
616 }
617 }
618
619
620
621 /**
622 * {@inheritDoc}
623 */
624 @Override()
625 public boolean writeData(ByteBuffer clearData)
626 {
627 int originalPosition = clearData.position();
628 int originalLimit = clearData.limit();
629 int length = originalLimit - originalPosition;
630
631 try
632 {
633 if (length > clearBufferSize)
634 {
635 // There is more data to write than we can deal with in one chunk, so
636 // break it up.
637 int pos = originalPosition;
638 int lim = originalPosition + clearBufferSize;
639
640 while (pos < originalLimit)
641 {
642 clearData.position(pos);
643 clearData.limit(lim);
644
645 if (! writeInternal(clearData))
646 {
647 return false;
648 }
649
650 pos = lim;
651 lim = Math.min(originalLimit, pos+clearBufferSize);
652 }
653
654 return true;
655 }
656 else
657 {
658 return writeInternal(clearData);
659 }
660 }
661 finally
662 {
663 clearData.position(originalPosition);
664 clearData.limit(originalLimit);
665 }
666 }
667
668
669
670 /**
671 * Writes the data contained in the provided clear-text buffer to the client,
672 * performing any necessary encoding in the process. The amount of data in
673 * the provided buffer must be less than or equal to the value returned by the
674 * {@code getClearBufferSize} method.
675 *
676 * @param clearData The buffer containing the clear-text data to write to
677 * the client.
678 *
679 * @return {@code true} if all the data in the provided buffer was written to
680 * the client and the connection may remain established, or
681 * {@code false} if a problem occurred and the client connection is
682 * no longer valid. Note that if this method does return
683 * {@code false}, then it must have already disconnected the client.
684 */
685 private boolean writeInternal(ByteBuffer clearData)
686 {
687 try
688 {
689 // See if there is any preliminary handshake work to be done.
690 handshakeStatusLoop:
691 while (true)
692 {
693 switch (sslEngine.getHandshakeStatus())
694 {
695 case NEED_TASK:
696 Runnable task = sslEngine.getDelegatedTask();
697 task.run();
698 break;
699
700 case NEED_WRAP:
701 clearOutBuffer.clear();
702 sslOutBuffer.clear();
703 sslEngine.wrap(clearOutBuffer, sslOutBuffer);
704 sslOutBuffer.flip();
705
706 while (sslOutBuffer.hasRemaining())
707 {
708 int bytesWritten = socketChannel.write(sslOutBuffer);
709 if (bytesWritten < 0)
710 {
711 // The client connection has been closed. Disconnect and
712 // return.
713 clientConnection.disconnect(
714 DisconnectReason.CLIENT_DISCONNECT, false, null);
715 return false;
716 }
717 else if (bytesWritten == 0)
718 {
719 return NullConnectionSecurityProvider.writeWithTimeout(
720 clientConnection, socketChannel, sslOutBuffer);
721 }
722 }
723 break;
724
725 case NEED_UNWRAP:
726 // We need to read data from the client before the negotiation can
727 // continue. This is bad, because we don't know if there is data
728 // available but we do know that we can't write until we have read.
729 // See if there is something available for reading, and if not, then
730 // we can't afford to wait for it because otherwise we would be
731 // potentially blocking reads from other clients. Our only recourse
732 // is to close the connection.
733 sslInBuffer.clear();
734 clearInBuffer.clear();
735 int bytesRead = socketChannel.read(sslInBuffer);
736 if (bytesRead < 0)
737 {
738 // The client connection is already closed, so we don't need to
739 // worry about it.
740 clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
741 false, null);
742 return false;
743 }
744 else if (bytesRead == 0)
745 {
746 // We didn't get the data that we need. We'll have to disconnect
747 // to avoid blocking other clients.
748 clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
749 false, ERR_TLS_SECURITY_PROVIDER_WRITE_NEEDS_UNWRAP.get());
750 return false;
751 }
752 else
753 {
754 // We were lucky and got the data we were looking for, so read and
755 // process it.
756 sslEngine.unwrap(sslInBuffer, clearInBuffer);
757 clearInBuffer.flip();
758 }
759 break;
760
761 default:
762 break handshakeStatusLoop;
763 }
764 }
765
766
767 while (clearData.hasRemaining())
768 {
769 sslOutBuffer.clear();
770 SSLEngineResult wrapResult = sslEngine.wrap(clearData, sslOutBuffer);
771 sslOutBuffer.flip();
772
773 switch (wrapResult.getStatus())
774 {
775 case OK:
776 // This is fine.
777 break;
778
779 case CLOSED:
780 // The client connection (or at least the SSL side of it) has been
781 // closed.
782 // FIXME -- Allow for closing the SSL channel without closing the
783 // underlying connection.
784 clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
785 false, null);
786 return false;
787
788 default:
789 // This should not have happened.
790 clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
791 false, ERR_TLS_SECURITY_PROVIDER_UNEXPECTED_WRAP_STATUS.get(
792 String.valueOf(wrapResult.getStatus())));
793 return false;
794 }
795
796 switch (wrapResult.getHandshakeStatus())
797 {
798 case NEED_TASK:
799 Runnable task = sslEngine.getDelegatedTask();
800 task.run();
801 break;
802
803 case NEED_WRAP:
804 // FIXME -- Could this overwrite the SSL out that we just wrapped?
805 // FIXME -- Is this even a feasible result?
806 clearOutBuffer.clear();
807 sslOutBuffer.clear();
808 sslEngine.wrap(clearOutBuffer, sslOutBuffer);
809 sslOutBuffer.flip();
810
811 while (sslOutBuffer.hasRemaining())
812 {
813 int bytesWritten = socketChannel.write(sslOutBuffer);
814 if (bytesWritten < 0)
815 {
816 // The client connection has been closed. Disconnect and
817 // return.
818 clientConnection.disconnect(
819 DisconnectReason.CLIENT_DISCONNECT, false, null);
820 return false;
821 }
822 else if (bytesWritten == 0)
823 {
824 return NullConnectionSecurityProvider.writeWithTimeout(
825 clientConnection, socketChannel, sslOutBuffer);
826 }
827 }
828 break;
829
830 case NEED_UNWRAP:
831 // We need to read data from the client before the negotiation can
832 // continue. This is bad, because we don't know if there is data
833 // available but we do know that we can't write until we have read.
834 // See if there is something available for reading, and if not, then
835 // we can't afford to wait for it because otherwise we would be
836 // potentially blocking reads from other clients. Our only recourse
837 // is to close the connection.
838 sslInBuffer.clear();
839 clearInBuffer.clear();
840 int bytesRead = socketChannel.read(sslInBuffer);
841 if (bytesRead < 0)
842 {
843 // The client connection is already closed, so we don't need to
844 // worry about it.
845 clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
846 false, null);
847 return false;
848 }
849 else if (bytesRead == 0)
850 {
851 // We didn't get the data that we need. We'll have to disconnect
852 // to avoid blocking other clients.
853 clientConnection.disconnect(DisconnectReason.SECURITY_PROBLEM,
854 false, ERR_TLS_SECURITY_PROVIDER_WRITE_NEEDS_UNWRAP.get());
855 return false;
856 }
857 else
858 {
859 // We were lucky and got the data we were looking for, so read and
860 // process it.
861 sslEngine.unwrap(sslInBuffer, clearInBuffer);
862 clearInBuffer.flip();
863 }
864 break;
865 }
866
867 while (sslOutBuffer.hasRemaining())
868 {
869 int bytesWritten = socketChannel.write(sslOutBuffer);
870 if (bytesWritten < 0)
871 {
872 // The client connection has been closed.
873 clientConnection.disconnect(DisconnectReason.CLIENT_DISCONNECT,
874 false, null);
875 return false;
876 }
877 else if (bytesWritten == 0)
878 {
879 return NullConnectionSecurityProvider.writeWithTimeout(
880 clientConnection, socketChannel, sslOutBuffer);
881 }
882 }
883 }
884
885
886 // If we've gotten here, then everything must have been written
887 // successfully.
888 return true;
889 }
890 catch (IOException ioe)
891 {
892 if (debugEnabled())
893 {
894 TRACER.debugCaught(DebugLogLevel.ERROR, ioe);
895 }
896
897 // An error occurred while trying to communicate with the client.
898 // Disconnect and return.
899 clientConnection.disconnect(DisconnectReason.IO_ERROR, false, null);
900 return false;
901 }
902 catch (Exception e)
903 {
904 if (debugEnabled())
905 {
906 TRACER.debugCaught(DebugLogLevel.ERROR, e);
907 }
908
909 // An unexpected error occurred while trying to process the data read.
910 // Disconnect and return.
911 clientConnection.disconnect(DisconnectReason.SERVER_ERROR, true,
912 ERR_TLS_SECURITY_PROVIDER_WRITE_ERROR.get(
913 getExceptionMessage(e)));
914 return false;
915 }
916 }
917
918
919
920 /**
921 * Retrieves the set of SSL protocols that will be allowed.
922 *
923 * @return The set of SSL protocols that will be allowed, or {@code null} if
924 * the default set will be used.
925 */
926 public String[] getEnabledProtocols()
927 {
928 return enabledProtocols;
929 }
930
931
932
933 /**
934 * Specifies the set of SSL protocols that will be allowed.
935 *
936 * @param enabledProtocols The set of SSL protocols that will be allowed, or
937 * {@code null} if the default set will be used.
938 */
939 public void setEnabledProtocols(String[] enabledProtocols)
940 {
941 this.enabledProtocols = enabledProtocols;
942 }
943
944
945
946 /**
947 * Retrieves the set of SSL cipher suites that will be allowed.
948 *
949 * @return The set of SSL cipher suites that will be allowed.
950 */
951 public String[] getEnabledCipherSuites()
952 {
953 return enabledCipherSuites;
954 }
955
956
957
958 /**
959 * Specifies the set of SSL cipher suites that will be allowed.
960 *
961 * @param enabledCipherSuites The set of SSL cipher suites that will be
962 * allowed.
963 */
964 public void setEnabledCipherSuites(String[] enabledCipherSuites)
965 {
966 this.enabledCipherSuites = enabledCipherSuites;
967 }
968
969
970
971 /**
972 * Retrieves the policy that should be used for SSL client authentication.
973 *
974 * @return The policy that should be used for SSL client authentication.
975 */
976 public SSLClientAuthPolicy getSSLClientAuthPolicy()
977 {
978 return sslClientAuthPolicy;
979 }
980
981
982
983 /**
984 * Specifies the policy that should be used for SSL client authentication.
985 *
986 * @param sslClientAuthPolicy The policy that should be used for SSL client
987 * authentication.
988 */
989 public void setSSLClientAuthPolicy(SSLClientAuthPolicy sslClientAuthPolicy)
990 {
991 this.sslClientAuthPolicy = sslClientAuthPolicy;
992 }
993
994
995
996 /**
997 * Retrieves the SSL session associated with this client connection.
998 *
999 * @return The SSL session associated with this client connection.
1000 */
1001 public SSLSession getSSLSession()
1002 {
1003 return sslEngine.getSession();
1004 }
1005
1006
1007
1008 /**
1009 * Retrieves the certificate chain that the client presented to the server
1010 * during the handshake process. The client's certificate will be the first
1011 * listed, followed by the certificates of any issuers in the chain.
1012 *
1013 * @return The certificate chain that the client presented to the server
1014 * during the handshake process, or {@code null} if the client did
1015 * not present a certificate.
1016 */
1017 public Certificate[] getClientCertificateChain()
1018 {
1019 try
1020 {
1021 return sslEngine.getSession().getPeerCertificates();
1022 }
1023 catch (Exception e)
1024 {
1025 if (debugEnabled())
1026 {
1027 TRACER.debugCaught(DebugLogLevel.ERROR, e);
1028 }
1029
1030 return null;
1031 }
1032 }
1033 }
1034