• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * 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,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package org.conscrypt;
18 
19 import java.io.IOException;
20 import java.nio.ByteBuffer;
21 import java.nio.ReadOnlyBufferException;
22 import java.security.cert.CertificateEncodingException;
23 import java.security.cert.CertificateException;
24 
25 import javax.crypto.SecretKey;
26 import javax.net.ssl.SSLEngine;
27 import javax.net.ssl.SSLEngineResult;
28 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
29 import javax.net.ssl.SSLEngineResult.Status;
30 import javax.net.ssl.SSLException;
31 import javax.net.ssl.SSLHandshakeException;
32 import javax.net.ssl.SSLSession;
33 import javax.net.ssl.X509ExtendedKeyManager;
34 import javax.net.ssl.X509KeyManager;
35 import javax.net.ssl.X509TrustManager;
36 import javax.security.auth.x500.X500Principal;
37 
38 /**
39  * Implements the {@link SSLEngine} API using OpenSSL's non-blocking interfaces.
40  */
41 public class OpenSSLEngineImpl extends SSLEngine implements NativeCrypto.SSLHandshakeCallbacks,
42         SSLParametersImpl.AliasChooser, SSLParametersImpl.PSKCallbacks {
43     private final SSLParametersImpl sslParameters;
44 
45     /**
46      * Protects handshakeStarted and handshakeCompleted.
47      */
48     private final Object stateLock = new Object();
49 
50     private static enum EngineState {
51         /**
52          * The {@link OpenSSLSocketImpl} object is constructed, but {@link #beginHandshake()}
53          * has not yet been called.
54          */
55         NEW,
56         /**
57          * {@link #setUseClientMode(boolean)} has been called at least once.
58          */
59         MODE_SET,
60         /**
61          * {@link #beginHandshake()} has been called at least once.
62          */
63         HANDSHAKE_WANTED,
64         /**
65          * Handshake task has been started.
66          */
67         HANDSHAKE_STARTED,
68         /**
69          * Handshake has been completed, but {@link #beginHandshake()} hasn't returned yet.
70          */
71         HANDSHAKE_COMPLETED,
72         /**
73          * {@link #beginHandshake()} has completed but the task hasn't
74          * been called. This is expected behaviour in cut-through mode, where SSL_do_handshake
75          * returns before the handshake is complete. We can now start writing data to the socket.
76          */
77         READY_HANDSHAKE_CUT_THROUGH,
78         /**
79          * {@link #beginHandshake()} has completed and socket is ready to go.
80          */
81         READY,
82         CLOSED_INBOUND,
83         CLOSED_OUTBOUND,
84         /**
85          * Inbound and outbound has been called.
86          */
87         CLOSED,
88     }
89 
90     // @GuardedBy("stateLock");
91     private EngineState engineState = EngineState.NEW;
92 
93     /**
94      * Protected by synchronizing on stateLock. Starts as 0, set by
95      * startHandshake, reset to 0 on close.
96      */
97     // @GuardedBy("stateLock");
98     private long sslNativePointer;
99 
100     /** Used during handshake when {@link #wrap(ByteBuffer, ByteBuffer)} is called. */
101     // TODO: make this use something similar to BIO_s_null() in native code
102     private static OpenSSLBIOSource nullSource = OpenSSLBIOSource.wrap(ByteBuffer.allocate(0));
103 
104     /** A BIO sink written to only during handshakes. */
105     private OpenSSLBIOSink handshakeSink;
106 
107     /** A BIO sink written to during regular operation. */
108     private final OpenSSLBIOSink localToRemoteSink = OpenSSLBIOSink.create();
109 
110     /** Set during startHandshake. */
111     private OpenSSLSessionImpl sslSession;
112 
113     /** Used during handshake callbacks. */
114     private OpenSSLSessionImpl handshakeSession;
115 
116     /**
117      * Private key for the TLS Channel ID extension. This field is client-side
118      * only. Set during startHandshake.
119      */
120     OpenSSLKey channelIdPrivateKey;
121 
OpenSSLEngineImpl(SSLParametersImpl sslParameters)122     public OpenSSLEngineImpl(SSLParametersImpl sslParameters) {
123         this.sslParameters = sslParameters;
124     }
125 
OpenSSLEngineImpl(String host, int port, SSLParametersImpl sslParameters)126     public OpenSSLEngineImpl(String host, int port, SSLParametersImpl sslParameters) {
127         super(host, port);
128         this.sslParameters = sslParameters;
129     }
130 
131     @Override
beginHandshake()132     public void beginHandshake() throws SSLException {
133         synchronized (stateLock) {
134             if (engineState == EngineState.CLOSED || engineState == EngineState.CLOSED_OUTBOUND
135                     || engineState == EngineState.CLOSED_INBOUND) {
136                 throw new IllegalStateException("Engine has already been closed");
137             }
138             if (engineState == EngineState.HANDSHAKE_STARTED) {
139                 throw new IllegalStateException("Handshake has already been started");
140             }
141             if (engineState != EngineState.MODE_SET) {
142                 throw new IllegalStateException("Client/server mode must be set before handshake");
143             }
144             if (getUseClientMode()) {
145                 engineState = EngineState.HANDSHAKE_WANTED;
146             } else {
147                 engineState = EngineState.HANDSHAKE_STARTED;
148             }
149         }
150 
151         boolean releaseResources = true;
152         try {
153             final AbstractSessionContext sessionContext = sslParameters.getSessionContext();
154             final long sslCtxNativePointer = sessionContext.sslCtxNativePointer;
155             sslNativePointer = NativeCrypto.SSL_new(sslCtxNativePointer);
156             sslSession = sslParameters.getSessionToReuse(
157                     sslNativePointer, getPeerHost(), getPeerPort());
158             sslParameters.setSSLParameters(sslCtxNativePointer, sslNativePointer, this, this,
159                     getPeerHost());
160             sslParameters.setCertificateValidation(sslNativePointer);
161             sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey);
162             if (getUseClientMode()) {
163                 NativeCrypto.SSL_set_connect_state(sslNativePointer);
164             } else {
165                 NativeCrypto.SSL_set_accept_state(sslNativePointer);
166             }
167             handshakeSink = OpenSSLBIOSink.create();
168             releaseResources = false;
169         } catch (IOException e) {
170             // Write CCS errors to EventLog
171             String message = e.getMessage();
172             // Must match error reason string of SSL_R_UNEXPECTED_CCS (in ssl/ssl_err.c)
173             if (message.contains("unexpected CCS")) {
174                 String logMessage = String.format("ssl_unexpected_ccs: host=%s", getPeerHost());
175                 Platform.logEvent(logMessage);
176             }
177             throw new SSLException(e);
178         } finally {
179             if (releaseResources) {
180                 synchronized (stateLock) {
181                     engineState = EngineState.CLOSED;
182                 }
183                 shutdownAndFreeSslNative();
184             }
185         }
186     }
187 
188     @Override
closeInbound()189     public void closeInbound() throws SSLException {
190         synchronized (stateLock) {
191             if (engineState == EngineState.CLOSED) {
192                 return;
193             }
194             if (engineState == EngineState.CLOSED_OUTBOUND) {
195                 engineState = EngineState.CLOSED;
196             } else {
197                 engineState = EngineState.CLOSED_INBOUND;
198             }
199         }
200         // TODO anything else to notify OpenSSL layer?
201     }
202 
203     @Override
closeOutbound()204     public void closeOutbound() {
205         synchronized (stateLock) {
206             if (engineState == EngineState.CLOSED || engineState == EngineState.CLOSED_OUTBOUND) {
207                 return;
208             }
209             if (engineState != EngineState.MODE_SET && engineState != EngineState.NEW) {
210                 shutdownAndFreeSslNative();
211             }
212             if (engineState == EngineState.CLOSED_INBOUND) {
213                 engineState = EngineState.CLOSED;
214             } else {
215                 engineState = EngineState.CLOSED_OUTBOUND;
216             }
217         }
218         shutdown();
219     }
220 
221     @Override
getDelegatedTask()222     public Runnable getDelegatedTask() {
223         /* This implementation doesn't use any delegated tasks. */
224         return null;
225     }
226 
227     @Override
getEnabledCipherSuites()228     public String[] getEnabledCipherSuites() {
229         return sslParameters.getEnabledCipherSuites();
230     }
231 
232     @Override
getEnabledProtocols()233     public String[] getEnabledProtocols() {
234         return sslParameters.getEnabledProtocols();
235     }
236 
237     @Override
getEnableSessionCreation()238     public boolean getEnableSessionCreation() {
239         return sslParameters.getEnableSessionCreation();
240     }
241 
242     @Override
getHandshakeStatus()243     public HandshakeStatus getHandshakeStatus() {
244         synchronized (stateLock) {
245             switch (engineState) {
246                 case HANDSHAKE_WANTED:
247                     if (getUseClientMode()) {
248                         return HandshakeStatus.NEED_WRAP;
249                     } else {
250                         return HandshakeStatus.NEED_UNWRAP;
251                     }
252                 case HANDSHAKE_STARTED:
253                     if (handshakeSink.available() > 0) {
254                         return HandshakeStatus.NEED_WRAP;
255                     } else {
256                         return HandshakeStatus.NEED_UNWRAP;
257                     }
258                 case HANDSHAKE_COMPLETED:
259                     if (handshakeSink.available() == 0) {
260                         handshakeSink = null;
261                         engineState = EngineState.READY;
262                         return HandshakeStatus.FINISHED;
263                     } else {
264                         return HandshakeStatus.NEED_WRAP;
265                     }
266                 case NEW:
267                 case MODE_SET:
268                 case CLOSED:
269                 case CLOSED_INBOUND:
270                 case CLOSED_OUTBOUND:
271                 case READY:
272                 case READY_HANDSHAKE_CUT_THROUGH:
273                     return HandshakeStatus.NOT_HANDSHAKING;
274                 default:
275                     break;
276             }
277             throw new IllegalStateException("Unexpected engine state: " + engineState);
278         }
279     }
280 
281     @Override
getNeedClientAuth()282     public boolean getNeedClientAuth() {
283         return sslParameters.getNeedClientAuth();
284     }
285 
286     @Override
getSession()287     public SSLSession getSession() {
288         if (sslSession == null) {
289             return SSLNullSession.getNullSession();
290         }
291         return sslSession;
292     }
293 
294     @Override
getSupportedCipherSuites()295     public String[] getSupportedCipherSuites() {
296         return NativeCrypto.getSupportedCipherSuites();
297     }
298 
299     @Override
getSupportedProtocols()300     public String[] getSupportedProtocols() {
301         return NativeCrypto.getSupportedProtocols();
302     }
303 
304     @Override
getUseClientMode()305     public boolean getUseClientMode() {
306         return sslParameters.getUseClientMode();
307     }
308 
309     @Override
getWantClientAuth()310     public boolean getWantClientAuth() {
311         return sslParameters.getWantClientAuth();
312     }
313 
314     @Override
isInboundDone()315     public boolean isInboundDone() {
316         if (sslNativePointer == 0) {
317             synchronized (stateLock) {
318                 return engineState == EngineState.CLOSED
319                         || engineState == EngineState.CLOSED_INBOUND;
320             }
321         }
322         return (NativeCrypto.SSL_get_shutdown(sslNativePointer)
323                 & NativeConstants.SSL_RECEIVED_SHUTDOWN) != 0;
324     }
325 
326     @Override
isOutboundDone()327     public boolean isOutboundDone() {
328         if (sslNativePointer == 0) {
329             synchronized (stateLock) {
330                 return engineState == EngineState.CLOSED
331                         || engineState == EngineState.CLOSED_OUTBOUND;
332             }
333         }
334         return (NativeCrypto.SSL_get_shutdown(sslNativePointer)
335                 & NativeConstants.SSL_SENT_SHUTDOWN) != 0;
336     }
337 
338     @Override
setEnabledCipherSuites(String[] suites)339     public void setEnabledCipherSuites(String[] suites) {
340         sslParameters.setEnabledCipherSuites(suites);
341     }
342 
343     @Override
setEnabledProtocols(String[] protocols)344     public void setEnabledProtocols(String[] protocols) {
345         sslParameters.setEnabledProtocols(protocols);
346     }
347 
348     @Override
setEnableSessionCreation(boolean flag)349     public void setEnableSessionCreation(boolean flag) {
350         sslParameters.setEnableSessionCreation(flag);
351     }
352 
353     @Override
setNeedClientAuth(boolean need)354     public void setNeedClientAuth(boolean need) {
355         sslParameters.setNeedClientAuth(need);
356     }
357 
358     @Override
setUseClientMode(boolean mode)359     public void setUseClientMode(boolean mode) {
360         synchronized (stateLock) {
361             if (engineState != EngineState.MODE_SET && engineState != EngineState.NEW) {
362                 throw new IllegalArgumentException(
363                         "Can not change mode after handshake: engineState == " + engineState);
364             }
365             engineState = EngineState.MODE_SET;
366         }
367         sslParameters.setUseClientMode(mode);
368     }
369 
370     @Override
setWantClientAuth(boolean want)371     public void setWantClientAuth(boolean want) {
372         sslParameters.setWantClientAuth(want);
373     }
374 
checkIndex(int length, int offset, int count)375     private static void checkIndex(int length, int offset, int count) {
376         if (offset < 0) {
377             throw new IndexOutOfBoundsException("offset < 0");
378         } else if (count < 0) {
379             throw new IndexOutOfBoundsException("count < 0");
380         } else if (offset > length) {
381             throw new IndexOutOfBoundsException("offset > length");
382         } else if (offset > length - count) {
383             throw new IndexOutOfBoundsException("offset + count > length");
384         }
385     }
386 
387     @Override
unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length)388     public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length)
389             throws SSLException {
390         if (src == null) {
391             throw new IllegalArgumentException("src == null");
392         } else if (dsts == null) {
393             throw new IllegalArgumentException("dsts == null");
394         }
395         checkIndex(dsts.length, offset, length);
396         int dstRemaining = 0;
397         for (int i = 0; i < dsts.length; i++) {
398             ByteBuffer dst = dsts[i];
399             if (dst == null) {
400                 throw new IllegalArgumentException("one of the dst == null");
401             } else if (dst.isReadOnly()) {
402                 throw new ReadOnlyBufferException();
403             }
404             if (i >= offset && i < offset + length) {
405                 dstRemaining += dst.remaining();
406             }
407         }
408 
409         synchronized (stateLock) {
410             // If the inbound direction is closed. we can't send anymore.
411             if (engineState == EngineState.CLOSED || engineState == EngineState.CLOSED_INBOUND) {
412                 return new SSLEngineResult(Status.CLOSED, getHandshakeStatus(), 0, 0);
413             }
414             if (engineState == EngineState.NEW || engineState == EngineState.MODE_SET) {
415                 beginHandshake();
416             }
417         }
418 
419         // If we haven't completed the handshake yet, just let the caller know.
420         HandshakeStatus handshakeStatus = getHandshakeStatus();
421         if (handshakeStatus == HandshakeStatus.NEED_UNWRAP) {
422             int positionBeforeHandshake = src.position();
423             OpenSSLBIOSource source = OpenSSLBIOSource.wrap(src);
424             long sslSessionCtx = 0L;
425             try {
426                 sslSessionCtx = NativeCrypto.SSL_do_handshake_bio(sslNativePointer,
427                         source.getContext(), handshakeSink.getContext(), this, getUseClientMode(),
428                         sslParameters.npnProtocols, sslParameters.alpnProtocols);
429                 if (sslSessionCtx != 0) {
430                     if (sslSession != null && engineState == EngineState.HANDSHAKE_STARTED) {
431                         engineState = EngineState.READY_HANDSHAKE_CUT_THROUGH;
432                     }
433                     sslSession = sslParameters.setupSession(sslSessionCtx, sslNativePointer, sslSession,
434                             getPeerHost(), getPeerPort(), true);
435                 }
436                 int bytesWritten = handshakeSink.position();
437                 int bytesConsumed = (src.position() - positionBeforeHandshake);
438                 return new SSLEngineResult((bytesConsumed > 0) ? Status.OK : Status.BUFFER_UNDERFLOW,
439                         getHandshakeStatus(), bytesConsumed, bytesWritten);
440             } catch (Exception e) {
441                 throw (SSLHandshakeException) new SSLHandshakeException("Handshake failed")
442                         .initCause(e);
443             } finally {
444                 if (sslSession == null && sslSessionCtx != 0) {
445                     NativeCrypto.SSL_SESSION_free(sslSessionCtx);
446                 }
447                 source.release();
448             }
449         } else if (handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) {
450             return new SSLEngineResult(Status.OK, handshakeStatus, 0, 0);
451         }
452 
453         if (dstRemaining == 0) {
454             return new SSLEngineResult(Status.BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
455         }
456 
457         ByteBuffer srcDuplicate = src.duplicate();
458         OpenSSLBIOSource source = OpenSSLBIOSource.wrap(srcDuplicate);
459         try {
460             int positionBeforeRead = srcDuplicate.position();
461             int produced = 0;
462             boolean shouldStop = false;
463 
464             while (!shouldStop) {
465                 ByteBuffer dst = getNextAvailableByteBuffer(dsts, offset, length);
466                 if (dst == null) {
467                     shouldStop = true;
468                     continue;
469                 }
470                 ByteBuffer arrayDst = dst;
471                 if (dst.isDirect()) {
472                     arrayDst = ByteBuffer.allocate(dst.remaining());
473                 }
474 
475                 int dstOffset = arrayDst.arrayOffset() + arrayDst.position();
476 
477                 int internalProduced = NativeCrypto.SSL_read_BIO(sslNativePointer,
478                         arrayDst.array(), dstOffset, dst.remaining(), source.getContext(),
479                         localToRemoteSink.getContext(), this);
480                 if (internalProduced <= 0) {
481                     shouldStop = true;
482                     continue;
483                 }
484                 arrayDst.position(arrayDst.position() + internalProduced);
485                 produced += internalProduced;
486                 if (dst != arrayDst) {
487                     arrayDst.flip();
488                     dst.put(arrayDst);
489                 }
490             }
491 
492             int consumed = srcDuplicate.position() - positionBeforeRead;
493             src.position(srcDuplicate.position());
494             return new SSLEngineResult((consumed > 0) ? Status.OK : Status.BUFFER_UNDERFLOW,
495                     getHandshakeStatus(), consumed, produced);
496         } catch (IOException e) {
497             throw new SSLException(e);
498         } finally {
499             source.release();
500         }
501     }
502 
503     /** Returns the next non-empty ByteBuffer. */
getNextAvailableByteBuffer(ByteBuffer[] buffers, int offset, int length)504     private ByteBuffer getNextAvailableByteBuffer(ByteBuffer[] buffers, int offset, int length) {
505         for (int i = offset; i < length; ++i) {
506             if (buffers[i].remaining() > 0) {
507                 return buffers[i];
508             }
509         }
510         return null;
511     }
512 
513     @Override
wrap(ByteBuffer[] srcs, int offset, int length, ByteBuffer dst)514     public SSLEngineResult wrap(ByteBuffer[] srcs, int offset, int length, ByteBuffer dst)
515             throws SSLException {
516         if (srcs == null) {
517             throw new IllegalArgumentException("srcs == null");
518         } else if (dst == null) {
519             throw new IllegalArgumentException("dst == null");
520         } else if (dst.isReadOnly()) {
521             throw new ReadOnlyBufferException();
522         }
523         for (ByteBuffer src : srcs) {
524             if (src == null) {
525                 throw new IllegalArgumentException("one of the src == null");
526             }
527         }
528         checkIndex(srcs.length, offset, length);
529 
530         if (dst.remaining() < NativeConstants.SSL3_RT_MAX_PACKET_SIZE) {
531             return new SSLEngineResult(Status.BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0);
532         }
533 
534         synchronized (stateLock) {
535             // If the outbound direction is closed. we can't send anymore.
536             if (engineState == EngineState.CLOSED || engineState == EngineState.CLOSED_OUTBOUND) {
537                 return new SSLEngineResult(Status.CLOSED, getHandshakeStatus(), 0, 0);
538             }
539             if (engineState == EngineState.NEW || engineState == EngineState.MODE_SET) {
540                 beginHandshake();
541             }
542         }
543 
544         // If we haven't completed the handshake yet, just let the caller know.
545         HandshakeStatus handshakeStatus = getHandshakeStatus();
546         if (handshakeStatus == HandshakeStatus.NEED_WRAP) {
547             if (handshakeSink.available() == 0) {
548                 long sslSessionCtx = 0L;
549                 try {
550                     sslSessionCtx = NativeCrypto.SSL_do_handshake_bio(sslNativePointer,
551                             nullSource.getContext(), handshakeSink.getContext(), this,
552                             getUseClientMode(), sslParameters.npnProtocols,
553                             sslParameters.alpnProtocols);
554                     if (sslSessionCtx != 0) {
555                         if (sslSession != null && engineState == EngineState.HANDSHAKE_STARTED) {
556                             engineState = EngineState.READY_HANDSHAKE_CUT_THROUGH;
557                         }
558                         sslSession = sslParameters.setupSession(sslSessionCtx, sslNativePointer, sslSession,
559                                 getPeerHost(), getPeerPort(), true);
560                     }
561                 } catch (Exception e) {
562                     throw (SSLHandshakeException) new SSLHandshakeException("Handshake failed")
563                             .initCause(e);
564                 } finally {
565                     if (sslSession == null && sslSessionCtx != 0) {
566                         NativeCrypto.SSL_SESSION_free(sslSessionCtx);
567                     }
568                 }
569             }
570             int bytesWritten = writeSinkToByteBuffer(handshakeSink, dst);
571             return new SSLEngineResult(Status.OK, getHandshakeStatus(), 0, bytesWritten);
572         } else if (handshakeStatus != HandshakeStatus.NOT_HANDSHAKING) {
573             return new SSLEngineResult(Status.OK, handshakeStatus, 0, 0);
574         }
575 
576         try {
577             int totalRead = 0;
578             byte[] buffer = null;
579 
580             for (ByteBuffer src : srcs) {
581                 int toRead = src.remaining();
582                 if (buffer == null || toRead > buffer.length) {
583                     buffer = new byte[toRead];
584                 }
585                 /*
586                  * We can't just use .mark() here because the caller might be
587                  * using it.
588                  */
589                 src.duplicate().get(buffer, 0, toRead);
590                 int numRead = NativeCrypto.SSL_write_BIO(sslNativePointer, buffer, toRead,
591                         localToRemoteSink.getContext(), this);
592                 if (numRead > 0) {
593                     src.position(src.position() + numRead);
594                     totalRead += numRead;
595                 }
596             }
597 
598             return new SSLEngineResult(Status.OK, getHandshakeStatus(), totalRead,
599                     writeSinkToByteBuffer(localToRemoteSink, dst));
600         } catch (IOException e) {
601             throw new SSLException(e);
602         }
603     }
604 
605     /** Writes data available in a BIO sink to a ByteBuffer. */
writeSinkToByteBuffer(OpenSSLBIOSink sink, ByteBuffer dst)606     private static int writeSinkToByteBuffer(OpenSSLBIOSink sink, ByteBuffer dst) {
607         int toWrite = Math.min(sink.available(), dst.remaining());
608         dst.put(sink.toByteArray(), sink.position(), toWrite);
609         sink.skip(toWrite);
610         return toWrite;
611     }
612 
613     @Override
clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key)614     public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
615         return sslParameters.clientPSKKeyRequested(identityHint, identity, key, this);
616     }
617 
618     @Override
serverPSKKeyRequested(String identityHint, String identity, byte[] key)619     public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
620         return sslParameters.serverPSKKeyRequested(identityHint, identity, key, this);
621     }
622 
623     @Override
onSSLStateChange(long sslSessionNativePtr, int type, int val)624     public void onSSLStateChange(long sslSessionNativePtr, int type, int val) {
625         synchronized (stateLock) {
626             switch (type) {
627                 case NativeConstants.SSL_CB_HANDSHAKE_DONE:
628                     if (engineState != EngineState.HANDSHAKE_STARTED &&
629                         engineState != EngineState.READY_HANDSHAKE_CUT_THROUGH) {
630                         throw new IllegalStateException("Completed handshake while in mode "
631                                 + engineState);
632                     }
633                     engineState = EngineState.HANDSHAKE_COMPLETED;
634                     break;
635                 case NativeConstants.SSL_CB_HANDSHAKE_START:
636                     // For clients, this will allow the NEED_UNWRAP status to be
637                     // returned.
638                     engineState = EngineState.HANDSHAKE_STARTED;
639                     break;
640             }
641         }
642     }
643 
644     @Override
verifyCertificateChain(long sslSessionNativePtr, long[] certRefs, String authMethod)645     public void verifyCertificateChain(long sslSessionNativePtr, long[] certRefs,
646             String authMethod) throws CertificateException {
647         try {
648             X509TrustManager x509tm = sslParameters.getX509TrustManager();
649             if (x509tm == null) {
650                 throw new CertificateException("No X.509 TrustManager");
651             }
652             if (certRefs == null || certRefs.length == 0) {
653                 throw new SSLException("Peer sent no certificate");
654             }
655             OpenSSLX509Certificate[] peerCertChain = new OpenSSLX509Certificate[certRefs.length];
656             for (int i = 0; i < certRefs.length; i++) {
657                 peerCertChain[i] = new OpenSSLX509Certificate(certRefs[i]);
658             }
659 
660             // Used for verifyCertificateChain callback
661             handshakeSession = new OpenSSLSessionImpl(sslSessionNativePtr, null, peerCertChain,
662                     getPeerHost(), getPeerPort(), null);
663 
664             boolean client = sslParameters.getUseClientMode();
665             if (client) {
666                 Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this);
667             } else {
668                 String authType = peerCertChain[0].getPublicKey().getAlgorithm();
669                 Platform.checkClientTrusted(x509tm, peerCertChain, authType, this);
670             }
671         } catch (CertificateException e) {
672             throw e;
673         } catch (Exception e) {
674             throw new CertificateException(e);
675         } finally {
676             // Clear this before notifying handshake completed listeners
677             handshakeSession = null;
678         }
679     }
680 
681     @Override
clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)682     public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
683             throws CertificateEncodingException, SSLException {
684         sslParameters.chooseClientCertificate(keyTypeBytes, asn1DerEncodedPrincipals,
685                 sslNativePointer, this);
686     }
687 
shutdown()688     private void shutdown() {
689         try {
690             NativeCrypto.SSL_shutdown_BIO(sslNativePointer, nullSource.getContext(),
691                     localToRemoteSink.getContext(), this);
692         } catch (IOException ignored) {
693             /*
694              * TODO: The RI ignores close failures in SSLSocket, but need to
695              * investigate whether it does for SSLEngine.
696              */
697         }
698     }
699 
shutdownAndFreeSslNative()700     private void shutdownAndFreeSslNative() {
701         try {
702             shutdown();
703         } finally {
704             free();
705         }
706     }
707 
free()708     private void free() {
709         if (sslNativePointer == 0) {
710             return;
711         }
712         NativeCrypto.SSL_free(sslNativePointer);
713         sslNativePointer = 0;
714     }
715 
716     @Override
finalize()717     protected void finalize() throws Throwable {
718         try {
719             free();
720         } finally {
721             super.finalize();
722         }
723     }
724 
725     // Comment annotation to compile Conscrypt unbundled with Java 6.
726     /* @Override */
getHandshakeSession()727     public SSLSession getHandshakeSession() {
728         return handshakeSession;
729     }
730 
731     @Override
chooseServerAlias(X509KeyManager keyManager, String keyType)732     public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
733         if (keyManager instanceof X509ExtendedKeyManager) {
734             X509ExtendedKeyManager ekm = (X509ExtendedKeyManager) keyManager;
735             return ekm.chooseEngineServerAlias(keyType, null, this);
736         } else {
737             return keyManager.chooseServerAlias(keyType, null, null);
738         }
739     }
740 
741     @Override
chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes)742     public String chooseClientAlias(X509KeyManager keyManager, X500Principal[] issuers,
743             String[] keyTypes) {
744         if (keyManager instanceof X509ExtendedKeyManager) {
745             X509ExtendedKeyManager ekm = (X509ExtendedKeyManager) keyManager;
746             return ekm.chooseEngineClientAlias(keyTypes, issuers, this);
747         } else {
748             return keyManager.chooseClientAlias(keyTypes, issuers, null);
749         }
750     }
751 
752     @Override
chooseServerPSKIdentityHint(PSKKeyManager keyManager)753     public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
754         return keyManager.chooseServerKeyIdentityHint(this);
755     }
756 
757     @Override
chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint)758     public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
759         return keyManager.chooseClientKeyIdentity(identityHint, this);
760     }
761 
762     @Override
getPSKKey(PSKKeyManager keyManager, String identityHint, String identity)763     public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
764         return keyManager.getKey(identityHint, identity, this);
765     }
766 }
767