View Javadoc

1   /*
2    * Copyright 2014 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package org.jboss.netty.handler.ssl;
17  
18  import org.apache.tomcat.jni.Buffer;
19  import org.apache.tomcat.jni.SSL;
20  import org.jboss.netty.logging.InternalLogger;
21  import org.jboss.netty.logging.InternalLoggerFactory;
22  import org.jboss.netty.util.internal.EmptyArrays;
23  
24  import javax.net.ssl.SSLEngine;
25  import javax.net.ssl.SSLEngineResult;
26  import javax.net.ssl.SSLException;
27  import javax.net.ssl.SSLSession;
28  import javax.net.ssl.SSLSessionContext;
29  import javax.security.cert.X509Certificate;
30  import java.nio.ByteBuffer;
31  import java.nio.ReadOnlyBufferException;
32  import java.security.Principal;
33  import java.security.cert.Certificate;
34  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
35  
36  import static javax.net.ssl.SSLEngineResult.HandshakeStatus.*;
37  import static javax.net.ssl.SSLEngineResult.Status.*;
38  
39  /**
40   * Implements a {@link SSLEngine} using
41   * <a href="https://www.openssl.org/docs/crypto/BIO_s_bio.html#EXAMPLE">OpenSSL BIO abstractions</a>.
42   */
43  public final class OpenSslEngine extends SSLEngine {
44  
45      private static final InternalLogger logger = InternalLoggerFactory.getInstance(OpenSslEngine.class);
46  
47      private static final Certificate[] EMPTY_CERTIFICATES = new Certificate[0];
48      private static final X509Certificate[] EMPTY_X509_CERTIFICATES = new X509Certificate[0];
49  
50      private static final SSLException ENGINE_CLOSED = new SSLException("engine closed");
51      private static final SSLException RENEGOTIATION_UNSUPPORTED = new SSLException("renegotiation unsupported");
52      private static final SSLException ENCRYPTED_PACKET_OVERSIZED = new SSLException("encrypted packet oversized");
53  
54      static {
55          ENGINE_CLOSED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
56          RENEGOTIATION_UNSUPPORTED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
57          ENCRYPTED_PACKET_OVERSIZED.setStackTrace(EmptyArrays.EMPTY_STACK_TRACE);
58      }
59  
60      private static final int MAX_PLAINTEXT_LENGTH = 16 * 1024; // 2^14
61      private static final int MAX_COMPRESSED_LENGTH = MAX_PLAINTEXT_LENGTH + 1024;
62      private static final int MAX_CIPHERTEXT_LENGTH = MAX_COMPRESSED_LENGTH + 1024;
63  
64      // Header (5) + Data (2^14) + Compression (1024) + Encryption (1024) + MAC (20) + Padding (256)
65      static final int MAX_ENCRYPTED_PACKET_LENGTH = MAX_CIPHERTEXT_LENGTH + 5 + 20 + 256;
66  
67      private static final AtomicIntegerFieldUpdater<OpenSslEngine> DESTROYED_UPDATER =
68              AtomicIntegerFieldUpdater.newUpdater(OpenSslEngine.class, "destroyed");
69  
70      // OpenSSL state
71      private long ssl;
72      private long networkBIO;
73  
74      /**
75       * 0 - not accepted, 1 - accepted implicitly via wrap()/unwrap(), 2 - accepted explicitly via beginHandshake() call
76       */
77      private int accepted;
78      private boolean handshakeFinished;
79      private boolean receivedShutdown;
80      @SuppressWarnings("UnusedDeclaration")
81      private volatile int destroyed;
82  
83      private String cipher;
84      private volatile String applicationProtocol;
85  
86      // SSL Engine status variables
87      private boolean isInboundDone;
88      private boolean isOutboundDone;
89      private boolean engineClosed;
90  
91      private int lastPrimingReadResult;
92  
93      private final SslBufferPool bufPool;
94      private final String fallbackApplicationProtocol;
95      private SSLSession session;
96  
97      /**
98       * Creates a new instance
99       *
100      * @param sslCtx an OpenSSL {@code SSL_CTX} object
101      * @param bufPool the {@link SslBufferPool} that will be used by this engine
102      */
103     public OpenSslEngine(long sslCtx, SslBufferPool bufPool, String fallbackApplicationProtocol) {
104         OpenSsl.ensureAvailability();
105         if (sslCtx == 0) {
106             throw new NullPointerException("sslContext");
107         }
108         if (bufPool == null) {
109             throw new NullPointerException("bufPool");
110         }
111 
112         this.bufPool = bufPool;
113         ssl = SSL.newSSL(sslCtx, true);
114         networkBIO = SSL.makeNetworkBIO(ssl);
115         this.fallbackApplicationProtocol = fallbackApplicationProtocol;
116     }
117 
118     /**
119      * Destroys this engine.
120      */
121     public synchronized void shutdown() {
122         if (DESTROYED_UPDATER.compareAndSet(this, 0, 1)) {
123             SSL.freeSSL(ssl);
124             SSL.freeBIO(networkBIO);
125             ssl = networkBIO = 0;
126 
127             // internal errors can cause shutdown without marking the engine closed
128             isInboundDone = isOutboundDone = engineClosed = true;
129         }
130     }
131 
132     /**
133      * Write plaintext data to the OpenSSL internal BIO
134      *
135      * Calling this function with src.remaining == 0 is undefined.
136      */
137     private int writePlaintextData(final ByteBuffer src) {
138         final int pos = src.position();
139         final int limit = src.limit();
140         final int len = Math.min(limit - pos, MAX_PLAINTEXT_LENGTH);
141         final int sslWrote;
142 
143         if (src.isDirect()) {
144             final long addr = Buffer.address(src) + pos;
145             sslWrote = SSL.writeToSSL(ssl, addr, len);
146             if (sslWrote > 0) {
147                 src.position(pos + sslWrote);
148                 return sslWrote;
149             }
150         } else {
151             final ByteBuffer buf = bufPool.acquireBuffer();
152             try {
153                 assert buf.isDirect();
154                 assert len <= buf.capacity() : "buffer pool write overflow";
155                 final long addr = Buffer.address(buf);
156 
157                 src.limit(pos + len);
158 
159                 buf.put(src);
160                 src.limit(limit);
161 
162                 sslWrote = SSL.writeToSSL(ssl, addr, len);
163                 if (sslWrote > 0) {
164                     src.position(pos + sslWrote);
165                     return sslWrote;
166                 } else {
167                     src.position(pos);
168                 }
169             } finally {
170                 bufPool.releaseBuffer(buf);
171             }
172         }
173 
174         throw new IllegalStateException("SSL.writeToSSL() returned a non-positive value: " + sslWrote);
175     }
176 
177     /**
178      * Write encrypted data to the OpenSSL network BIO
179      */
180     private int writeEncryptedData(final ByteBuffer src) {
181         final int pos = src.position();
182         final int len = src.remaining();
183         if (src.isDirect()) {
184             final long addr = Buffer.address(src) + pos;
185             final int netWrote = SSL.writeToBIO(networkBIO, addr, len);
186             if (netWrote >= 0) {
187                 src.position(pos + netWrote);
188                 lastPrimingReadResult = SSL.readFromSSL(ssl, addr, 0); // priming read
189                 return netWrote;
190             }
191         } else {
192             final ByteBuffer buf = bufPool.acquireBuffer();
193             try {
194                 assert buf.isDirect();
195                 assert len <= buf.capacity();
196                 final long addr = Buffer.address(buf);
197 
198                 buf.put(src);
199 
200                 final int netWrote = SSL.writeToBIO(networkBIO, addr, len);
201                 if (netWrote >= 0) {
202                     src.position(pos + netWrote);
203                     lastPrimingReadResult = SSL.readFromSSL(ssl, addr, 0); // priming read
204                     return netWrote;
205                 } else {
206                     src.position(pos);
207                 }
208             } finally {
209                 bufPool.releaseBuffer(buf);
210             }
211         }
212 
213         return 0;
214     }
215 
216     /**
217      * Read plaintext data from the OpenSSL internal BIO
218      */
219     private int readPlaintextData(final ByteBuffer dst) {
220         if (dst.isDirect()) {
221             final int pos = dst.position();
222             final long addr = Buffer.address(dst) + pos;
223             final int len = dst.limit() - pos;
224             final int sslRead = SSL.readFromSSL(ssl, addr, len);
225             if (sslRead > 0) {
226                 dst.position(pos + sslRead);
227                 return sslRead;
228             }
229         } else {
230             final ByteBuffer buf = bufPool.acquireBuffer();
231             try {
232                 assert buf.isDirect();
233                 final long addr = Buffer.address(buf);
234                 final int len = Math.min(buf.capacity(), dst.remaining());
235                 buf.limit(len);
236                 final int sslRead = SSL.readFromSSL(ssl, addr, len);
237                 if (sslRead > 0) {
238                     buf.limit(sslRead);
239                     dst.put(buf);
240                     return sslRead;
241                 }
242             } finally {
243                 bufPool.releaseBuffer(buf);
244             }
245         }
246 
247         return 0;
248     }
249 
250     /**
251      * Read encrypted data from the OpenSSL network BIO
252      */
253     private int readEncryptedData(final ByteBuffer dst, final int pending) {
254         if (dst.isDirect() && dst.remaining() >= pending) {
255             final int pos = dst.position();
256             final long addr = Buffer.address(dst) + pos;
257             final int bioRead = SSL.readFromBIO(networkBIO, addr, pending);
258             if (bioRead > 0) {
259                 dst.position(pos + bioRead);
260                 return bioRead;
261             }
262         } else {
263             final ByteBuffer buf = bufPool.acquireBuffer();
264             try {
265                 assert buf.isDirect();
266                 final long addr = Buffer.address(buf);
267                 assert buf.capacity() >= pending :
268                         "network BIO read overflow (pending: " + pending + ", capacity: " + buf.capacity() + ')';
269 
270                 final int bioRead = SSL.readFromBIO(networkBIO, addr, pending);
271                 if (bioRead > 0) {
272                     buf.limit(bioRead);
273                     dst.put(buf);
274                     return bioRead;
275                 }
276             } finally {
277                 bufPool.releaseBuffer(buf);
278             }
279         }
280 
281         return 0;
282     }
283 
284     @Override
285     public synchronized SSLEngineResult wrap(
286             final ByteBuffer[] srcs, final int offset, final int length, final ByteBuffer dst) throws SSLException {
287 
288         // Check to make sure the engine has not been closed
289         if (destroyed != 0) {
290             return new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
291         }
292 
293         // Throw required runtime exceptions
294         if (srcs == null) {
295             throw new NullPointerException("srcs");
296         }
297         if (dst == null) {
298             throw new NullPointerException("dst");
299         }
300 
301         if (offset >= srcs.length || offset + length > srcs.length) {
302             throw new IndexOutOfBoundsException(
303                     "offset: " + offset + ", length: " + length +
304                             " (expected: offset <= offset + length <= srcs.length (" + srcs.length + "))");
305         }
306 
307         if (dst.isReadOnly()) {
308             throw new ReadOnlyBufferException();
309         }
310 
311         // Prepare OpenSSL to work in server mode and receive handshake
312         if (accepted == 0) {
313             beginHandshakeImplicitly();
314         }
315 
316         // In handshake or close_notify stages, check if call to wrap was made
317         // without regard to the handshake status.
318         SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
319         if ((!handshakeFinished || engineClosed) && handshakeStatus == NEED_UNWRAP) {
320             return new SSLEngineResult(getEngineStatus(), NEED_UNWRAP, 0, 0);
321         }
322 
323         int bytesProduced = 0;
324         int pendingNet;
325 
326         // Check for pending data in the network BIO
327         pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO);
328         if (pendingNet > 0) {
329             // Do we have enough room in dst to write encrypted data?
330             int capacity = dst.remaining();
331             if (capacity < pendingNet) {
332                 return new SSLEngineResult(BUFFER_OVERFLOW, handshakeStatus, 0, bytesProduced);
333             }
334 
335             // Write the pending data from the network BIO into the dst buffer
336             try {
337                 bytesProduced += readEncryptedData(dst, pendingNet);
338             } catch (Exception e) {
339                 throw new SSLException(e);
340             }
341 
342             // If isOuboundDone is set, then the data from the network BIO
343             // was the close_notify message -- we are not required to wait
344             // for the receipt the peer's close_notify message -- shutdown.
345             if (isOutboundDone) {
346                 shutdown();
347             }
348 
349             return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), 0, bytesProduced);
350         }
351 
352         // There was no pending data in the network BIO -- encrypt any application data
353         int bytesConsumed = 0;
354         for (int i = offset; i < length; ++ i) {
355             final ByteBuffer src = srcs[i];
356             while (src.hasRemaining()) {
357 
358                 // Write plaintext application data to the SSL engine
359                 try {
360                     bytesConsumed += writePlaintextData(src);
361                 } catch (Exception e) {
362                     throw new SSLException(e);
363                 }
364 
365                 // Check to see if the engine wrote data into the network BIO
366                 pendingNet = SSL.pendingWrittenBytesInBIO(networkBIO);
367                 if (pendingNet > 0) {
368                     // Do we have enough room in dst to write encrypted data?
369                     int capacity = dst.remaining();
370                     if (capacity < pendingNet) {
371                         return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed, bytesProduced);
372                     }
373 
374                     // Write the pending data from the network BIO into the dst buffer
375                     try {
376                         bytesProduced += readEncryptedData(dst, pendingNet);
377                     } catch (Exception e) {
378                         throw new SSLException(e);
379                     }
380 
381                     return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), bytesConsumed, bytesProduced);
382                 }
383             }
384         }
385 
386         return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), bytesConsumed, bytesProduced);
387     }
388 
389     @Override
390     public synchronized SSLEngineResult unwrap(
391             final ByteBuffer src, final ByteBuffer[] dsts, final int offset, final int length) throws SSLException {
392 
393         // Check to make sure the engine has not been closed
394         if (destroyed != 0) {
395             return new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
396         }
397 
398         // Throw requried runtime exceptions
399         if (src == null) {
400             throw new NullPointerException("src");
401         }
402         if (dsts == null) {
403             throw new NullPointerException("dsts");
404         }
405         if (offset >= dsts.length || offset + length > dsts.length) {
406             throw new IndexOutOfBoundsException(
407                     "offset: " + offset + ", length: " + length +
408                             " (expected: offset <= offset + length <= dsts.length (" + dsts.length + "))");
409         }
410 
411         int capacity = 0;
412         final int endOffset = offset + length;
413         for (int i = offset; i < endOffset; i ++) {
414             ByteBuffer dst = dsts[i];
415             if (dst == null) {
416                 throw new IllegalArgumentException();
417             }
418             if (dst.isReadOnly()) {
419                 throw new ReadOnlyBufferException();
420             }
421             capacity += dst.remaining();
422         }
423 
424         // Prepare OpenSSL to work in server mode and receive handshake
425         if (accepted == 0) {
426             beginHandshakeImplicitly();
427         }
428 
429         // In handshake or close_notify stages, check if call to unwrap was made
430         // without regard to the handshake status.
431         SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
432         if ((!handshakeFinished || engineClosed) && handshakeStatus == NEED_WRAP) {
433             return new SSLEngineResult(getEngineStatus(), NEED_WRAP, 0, 0);
434         }
435 
436         // protect against protocol overflow attack vector
437         if (src.remaining() > MAX_ENCRYPTED_PACKET_LENGTH) {
438             isInboundDone = true;
439             isOutboundDone = true;
440             engineClosed = true;
441             shutdown();
442             throw ENCRYPTED_PACKET_OVERSIZED;
443         }
444 
445         // Write encrypted data to network BIO
446         int bytesConsumed = 0;
447         lastPrimingReadResult = 0;
448         try {
449             bytesConsumed += writeEncryptedData(src);
450         } catch (Exception e) {
451             throw new SSLException(e);
452         }
453 
454         // Check for OpenSSL errors caused by the priming read
455         String error = SSL.getLastError();
456         if (error != null && !error.startsWith(OpenSsl.IGNORABLE_ERROR_PREFIX)) {
457             if (logger.isInfoEnabled()) {
458                 logger.info(
459                         "SSL_read failed: primingReadResult: " + lastPrimingReadResult +
460                                 "; OpenSSL error: '" + error + '\'');
461             }
462 
463             // There was an internal error -- shutdown
464             shutdown();
465             throw new SSLException(error);
466         }
467 
468         // There won't be any application data until we're done handshaking
469         int pendingApp = SSL.isInInit(ssl) == 0 ? SSL.pendingReadableBytesInSSL(ssl) : 0;
470 
471         // Do we have enough room in dsts to write decrypted data?
472         if (capacity < pendingApp) {
473             return new SSLEngineResult(BUFFER_OVERFLOW, getHandshakeStatus(), bytesConsumed, 0);
474         }
475 
476         // Write decrypted data to dsts buffers
477         int bytesProduced = 0;
478         int idx = offset;
479         while (idx < endOffset) {
480             ByteBuffer dst = dsts[idx];
481             if (!dst.hasRemaining()) {
482                 idx ++;
483                 continue;
484             }
485 
486             if (pendingApp <= 0) {
487                 break;
488             }
489 
490             int bytesRead;
491             try {
492                 bytesRead = readPlaintextData(dst);
493             } catch (Exception e) {
494                 throw new SSLException(e);
495             }
496 
497             if (bytesRead == 0) {
498                 break;
499             }
500 
501             bytesProduced += bytesRead;
502             pendingApp -= bytesRead;
503 
504             if (!dst.hasRemaining()) {
505                 idx ++;
506             }
507         }
508 
509         // Check to see if we received a close_notify message from the peer
510         if (!receivedShutdown && (SSL.getShutdown(ssl) & SSL.SSL_RECEIVED_SHUTDOWN) == SSL.SSL_RECEIVED_SHUTDOWN) {
511             receivedShutdown = true;
512             closeOutbound();
513             closeInbound();
514         }
515 
516         return new SSLEngineResult(getEngineStatus(), getHandshakeStatus(), bytesConsumed, bytesProduced);
517     }
518 
519     @Override
520     public Runnable getDelegatedTask() {
521         // Currently, we do not delegate SSL computation tasks
522         // TODO: in the future, possibly create tasks to do encrypt / decrypt async
523 
524         return null;
525     }
526 
527     @Override
528     public synchronized void closeInbound() throws SSLException {
529         if (isInboundDone) {
530             return;
531         }
532 
533         isInboundDone = true;
534         engineClosed = true;
535 
536         if (accepted != 0) {
537             if (!receivedShutdown) {
538                 shutdown();
539                 throw new SSLException("close_notify has not been received");
540             }
541         } else {
542             // engine closing before initial handshake
543             shutdown();
544         }
545     }
546 
547     @Override
548     public synchronized boolean isInboundDone() {
549         return isInboundDone || engineClosed;
550     }
551 
552     @Override
553     public synchronized void closeOutbound() {
554         if (isOutboundDone) {
555             return;
556         }
557 
558         isOutboundDone = true;
559         engineClosed = true;
560 
561         if (accepted != 0 && destroyed == 0) {
562             int mode = SSL.getShutdown(ssl);
563             if ((mode & SSL.SSL_SENT_SHUTDOWN) != SSL.SSL_SENT_SHUTDOWN) {
564                 SSL.shutdownSSL(ssl);
565             }
566         } else {
567             // engine closing before initial handshake
568             shutdown();
569         }
570     }
571 
572     @Override
573     public synchronized boolean isOutboundDone() {
574         return isOutboundDone;
575     }
576 
577     @Override
578     public String[] getSupportedCipherSuites() {
579         return EmptyArrays.EMPTY_STRINGS;
580     }
581 
582     @Override
583     public String[] getEnabledCipherSuites() {
584         return EmptyArrays.EMPTY_STRINGS;
585     }
586 
587     @Override
588     public void setEnabledCipherSuites(String[] strings) {
589         throw new UnsupportedOperationException();
590     }
591 
592     @Override
593     public String[] getSupportedProtocols() {
594         return EmptyArrays.EMPTY_STRINGS;
595     }
596 
597     @Override
598     public String[] getEnabledProtocols() {
599         return EmptyArrays.EMPTY_STRINGS;
600     }
601 
602     @Override
603     public void setEnabledProtocols(String[] strings) {
604         throw new UnsupportedOperationException();
605     }
606 
607     @Override
608     public SSLSession getSession() {
609         SSLSession session = this.session;
610         if (session == null) {
611             this.session = session = new SSLSession() {
612                 public byte[] getId() {
613                     return String.valueOf(ssl).getBytes();
614                 }
615 
616                 public SSLSessionContext getSessionContext() {
617                     return null;
618                 }
619 
620                 public long getCreationTime() {
621                     return 0;
622                 }
623 
624                 public long getLastAccessedTime() {
625                     return 0;
626                 }
627 
628                 public void invalidate() {
629                 }
630 
631                 public boolean isValid() {
632                     return false;
633                 }
634 
635                 public void putValue(String s, Object o) {
636                 }
637 
638                 public Object getValue(String s) {
639                     return null;
640                 }
641 
642                 public void removeValue(String s) {
643                 }
644 
645                 public String[] getValueNames() {
646                     return EmptyArrays.EMPTY_STRINGS;
647                 }
648 
649                 public Certificate[] getPeerCertificates() {
650                     return EMPTY_CERTIFICATES;
651                 }
652 
653                 public Certificate[] getLocalCertificates() {
654                     return EMPTY_CERTIFICATES;
655                 }
656 
657                 public X509Certificate[] getPeerCertificateChain() {
658                     return EMPTY_X509_CERTIFICATES;
659                 }
660 
661                 public Principal getPeerPrincipal() {
662                     return null;
663                 }
664 
665                 public Principal getLocalPrincipal() {
666                     return null;
667                 }
668 
669                 public String getCipherSuite() {
670                     return cipher;
671                 }
672 
673                 public String getProtocol() {
674                     // TODO: Figure out how to get the current protocol.
675                     String applicationProtocol = OpenSslEngine.this.applicationProtocol;
676                     if (applicationProtocol == null) {
677                         return "unknown";
678                     } else {
679                         return "unknown:" + applicationProtocol;
680                     }
681                 }
682 
683                 public String getPeerHost() {
684                     return null;
685                 }
686 
687                 public int getPeerPort() {
688                     return 0;
689                 }
690 
691                 public int getPacketBufferSize() {
692                     return MAX_ENCRYPTED_PACKET_LENGTH;
693                 }
694 
695                 public int getApplicationBufferSize() {
696                     return MAX_PLAINTEXT_LENGTH;
697                 }
698             };
699         }
700 
701         return session;
702     }
703 
704     @Override
705     public synchronized void beginHandshake() throws SSLException {
706         if (engineClosed) {
707             throw ENGINE_CLOSED;
708         }
709 
710         switch (accepted) {
711             case 0:
712                 SSL.doHandshake(ssl);
713                 accepted = 2;
714                 break;
715             case 1:
716                 // A user did not start handshake by calling this method by him/herself,
717                 // but handshake has been started already by wrap() or unwrap() implicitly.
718                 // Because it's the user's first time to call this method, it is unfair to
719                 // raise an exception.  From the user's standpoint, he or she never asked
720                 // for renegotiation.
721 
722                 accepted = 2; // Next time this method is invoked by the user, we should raise an exception.
723                 break;
724             case 2:
725                 throw RENEGOTIATION_UNSUPPORTED;
726             default:
727                 throw new Error();
728         }
729     }
730 
731     private synchronized void beginHandshakeImplicitly() throws SSLException {
732         if (engineClosed) {
733             throw ENGINE_CLOSED;
734         }
735 
736         if (accepted == 0) {
737             SSL.doHandshake(ssl);
738             accepted = 1;
739         }
740     }
741 
742     private SSLEngineResult.Status getEngineStatus() {
743         return engineClosed? CLOSED : OK;
744     }
745 
746     @Override
747     public synchronized SSLEngineResult.HandshakeStatus getHandshakeStatus() {
748         if (accepted == 0 || destroyed != 0) {
749             return NOT_HANDSHAKING;
750         }
751 
752         // Check if we are in the initial handshake phase
753         if (!handshakeFinished) {
754             // There is pending data in the network BIO -- call wrap
755             if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
756                 return NEED_WRAP;
757             }
758 
759             // No pending data to be sent to the peer
760             // Check to see if we have finished handshaking
761             if (SSL.isInInit(ssl) == 0) {
762                 handshakeFinished = true;
763                 cipher = SSL.getCipherForSSL(ssl);
764                 String applicationProtocol = SSL.getNextProtoNegotiated(ssl);
765                 if (applicationProtocol == null) {
766                     applicationProtocol = fallbackApplicationProtocol;
767                 }
768                 if (applicationProtocol != null) {
769                     this.applicationProtocol = applicationProtocol.replace(':', '_');
770                 } else {
771                     this.applicationProtocol = null;
772                 }
773                 return FINISHED;
774             }
775 
776             // No pending data and still handshaking
777             // Must be waiting on the peer to send more data
778             return NEED_UNWRAP;
779         }
780 
781         // Check if we are in the shutdown phase
782         if (engineClosed) {
783             // Waiting to send the close_notify message
784             if (SSL.pendingWrittenBytesInBIO(networkBIO) != 0) {
785                 return NEED_WRAP;
786             }
787 
788             // Must be waiting to receive the close_notify message
789             return NEED_UNWRAP;
790         }
791 
792         return NOT_HANDSHAKING;
793     }
794 
795     @Override
796     public void setUseClientMode(boolean clientMode) {
797         if (clientMode) {
798             throw new UnsupportedOperationException();
799         }
800     }
801 
802     @Override
803     public boolean getUseClientMode() {
804         return false;
805     }
806 
807     @Override
808     public void setNeedClientAuth(boolean b) {
809         if (b) {
810             throw new UnsupportedOperationException();
811         }
812     }
813 
814     @Override
815     public boolean getNeedClientAuth() {
816         return false;
817     }
818 
819     @Override
820     public void setWantClientAuth(boolean b) {
821         if (b) {
822             throw new UnsupportedOperationException();
823         }
824     }
825 
826     @Override
827     public boolean getWantClientAuth() {
828         return false;
829     }
830 
831     @Override
832     public void setEnableSessionCreation(boolean b) {
833         if (b) {
834             throw new UnsupportedOperationException();
835         }
836     }
837 
838     @Override
839     public boolean getEnableSessionCreation() {
840         return false;
841     }
842 }