OpenSSLEngineImpl.java revision 5ac8e317836e901e7b241b224b92f00cba2ed701
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/*
18 * Copyright 2016 The Netty Project
19 *
20 * The Netty Project licenses this file to you under the Apache License,
21 * version 2.0 (the "License"); you may not use this file except in compliance
22 * with the License. You may obtain a copy of the License at:
23 *
24 *   http://www.apache.org/licenses/LICENSE-2.0
25 *
26 * Unless required by applicable law or agreed to in writing, software
27 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
28 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
29 * License for the specific language governing permissions and limitations
30 * under the License.
31 */
32
33package org.conscrypt;
34
35import static javax.net.ssl.SSLEngineResult.HandshakeStatus.FINISHED;
36import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
37import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NEED_WRAP;
38import static javax.net.ssl.SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
39import static javax.net.ssl.SSLEngineResult.Status.BUFFER_OVERFLOW;
40import static javax.net.ssl.SSLEngineResult.Status.BUFFER_UNDERFLOW;
41import static javax.net.ssl.SSLEngineResult.Status.CLOSED;
42import static javax.net.ssl.SSLEngineResult.Status.OK;
43import static org.conscrypt.NativeConstants.SSL3_RT_HEADER_LENGTH;
44import static org.conscrypt.NativeConstants.SSL3_RT_MAX_PACKET_SIZE;
45import static org.conscrypt.NativeConstants.SSL3_RT_MAX_PLAIN_LENGTH;
46import static org.conscrypt.NativeConstants.SSL_CB_HANDSHAKE_DONE;
47import static org.conscrypt.NativeConstants.SSL_CB_HANDSHAKE_START;
48import static org.conscrypt.NativeConstants.SSL_ERROR_NONE;
49import static org.conscrypt.NativeConstants.SSL_ERROR_WANT_READ;
50import static org.conscrypt.NativeConstants.SSL_ERROR_WANT_WRITE;
51import static org.conscrypt.NativeConstants.SSL_ERROR_ZERO_RETURN;
52import static org.conscrypt.NativeConstants.SSL_RECEIVED_SHUTDOWN;
53import static org.conscrypt.NativeConstants.SSL_SENT_SHUTDOWN;
54import static org.conscrypt.SSLUtils.calculateOutNetBufSize;
55import static org.conscrypt.SSLUtils.toSSLHandshakeException;
56
57import java.io.IOException;
58import java.nio.ByteBuffer;
59import java.nio.ReadOnlyBufferException;
60import java.security.cert.CertificateEncodingException;
61import java.security.cert.CertificateException;
62import javax.crypto.SecretKey;
63import javax.net.ssl.SSLEngine;
64import javax.net.ssl.SSLEngineResult;
65import javax.net.ssl.SSLEngineResult.HandshakeStatus;
66import javax.net.ssl.SSLEngineResult.Status;
67import javax.net.ssl.SSLException;
68import javax.net.ssl.SSLHandshakeException;
69import javax.net.ssl.SSLSession;
70import javax.net.ssl.X509ExtendedKeyManager;
71import javax.net.ssl.X509KeyManager;
72import javax.net.ssl.X509TrustManager;
73import javax.security.auth.x500.X500Principal;
74
75/**
76 * Implements the {@link SSLEngine} API using OpenSSL's non-blocking interfaces.
77 */
78public final class OpenSSLEngineImpl extends SSLEngine
79        implements NativeCrypto.SSLHandshakeCallbacks, SSLParametersImpl.AliasChooser,
80                   SSLParametersImpl.PSKCallbacks {
81    private static final SSLEngineResult NEED_UNWRAP_OK =
82            new SSLEngineResult(OK, NEED_UNWRAP, 0, 0);
83    private static final SSLEngineResult NEED_UNWRAP_CLOSED =
84            new SSLEngineResult(CLOSED, NEED_UNWRAP, 0, 0);
85    private static final SSLEngineResult NEED_WRAP_OK = new SSLEngineResult(OK, NEED_WRAP, 0, 0);
86    private static final SSLEngineResult NEED_WRAP_CLOSED =
87            new SSLEngineResult(CLOSED, NEED_WRAP, 0, 0);
88    private static final SSLEngineResult CLOSED_NOT_HANDSHAKING =
89            new SSLEngineResult(CLOSED, NOT_HANDSHAKING, 0, 0);
90    private static final ByteBuffer EMPTY = ByteBuffer.allocateDirect(0);
91    private static final long EMPTY_ADDR = NativeCrypto.getDirectBufferAddress(EMPTY);
92
93    /**
94     * Similar in concept to {@link javax.net.ssl.HandshakeCompletedListener}. Allows the caller to be
95     * notified immediately upon completion of the TLS handshake.
96     */
97    public interface HandshakeListener {
98
99        /**
100         * Called by the engine when the TLS handshake has completed.
101         */
102        void onHandshakeFinished() throws SSLException;
103    }
104
105    private final SSLParametersImpl sslParameters;
106
107    /**
108     * Protects {@link #engineState} and {@link #handshakeFinished}.
109     */
110    private final Object stateLock = new Object();
111
112    private enum EngineState {
113        /**
114         * The {@link OpenSSLSocketImpl} object is constructed, but {@link #beginHandshake()} has
115         * not yet been called.
116         */
117        NEW,
118        /**
119         * {@link #setUseClientMode(boolean)} has been called at least once.
120         */
121        MODE_SET,
122        /**
123         * Handshake task has been started.
124         */
125        HANDSHAKE_STARTED,
126        /**
127         * Handshake has been completed, but {@link #beginHandshake()} hasn't returned yet.
128         */
129        HANDSHAKE_COMPLETED,
130        /**
131         * {@link #beginHandshake()} has completed but the task hasn't been called. This is expected
132         * behaviour in cut-through mode, where SSL_do_handshake returns before the handshake is
133         * complete. We can now start writing data to the socket.
134         */
135        READY_HANDSHAKE_CUT_THROUGH,
136        /**
137         * {@link #beginHandshake()} has completed and socket is ready to go.
138         */
139        READY,
140        CLOSED_INBOUND,
141        CLOSED_OUTBOUND,
142        /**
143         * Inbound and outbound has been called.
144         */
145        CLOSED,
146    }
147
148    // @GuardedBy("stateLock");
149    private EngineState engineState = EngineState.NEW;
150    private boolean handshakeFinished;
151
152    /**
153     * Protected by synchronizing on stateLock. Starts as 0, set by startHandshake, reset to 0 on
154     * close.
155     */
156    // @GuardedBy("stateLock");
157    private long sslNativePointer;
158
159    /**
160     * Protected by synchronizing on stateLock. Starts as 0, set by startHandshake, reset to 0 on
161     * close.
162     */
163    // @GuardedBy("stateLock");
164    private long networkBio;
165
166    /**
167     * Set during startHandshake.
168     */
169    private AbstractOpenSSLSession sslSession;
170
171    /**
172     * Used during handshake callbacks.
173     */
174    private AbstractOpenSSLSession handshakeSession;
175
176    /**
177     * Private key for the TLS Channel ID extension. This field is client-side only. Set during
178     * startHandshake.
179     */
180    OpenSSLKey channelIdPrivateKey;
181
182    private int maxSealOverhead;
183
184    private HandshakeListener handshakeListener;
185
186    private final ByteBuffer[] singleSrcBuffer = new ByteBuffer[1];
187    private final ByteBuffer[] singleDstBuffer = new ByteBuffer[1];
188
189    public OpenSSLEngineImpl(SSLParametersImpl sslParameters) {
190        this.sslParameters = sslParameters;
191    }
192
193    public OpenSSLEngineImpl(String host, int port, SSLParametersImpl sslParameters) {
194        super(host, port);
195        this.sslParameters = sslParameters;
196    }
197
198    /**
199     * Returns the maximum overhead, in bytes, of sealing a record with SSL.
200     */
201    public final int maxSealOverhead() {
202        return maxSealOverhead;
203    }
204
205    /**
206     * Sets the listener for the completion of the TLS handshake.
207     */
208    public OpenSSLEngineImpl setHandshakeListener(HandshakeListener handshakeListener) {
209        switch(engineState) {
210            case NEW:
211            case MODE_SET:
212                // Allowed.
213                break;
214            default:
215                // Disallow anything else.
216                throw new IllegalStateException("Handshake listener must be set before starting the handshake.");
217        }
218        this.handshakeListener = handshakeListener;
219        return this;
220    }
221
222    @Override
223    public void beginHandshake() throws SSLException {
224        synchronized (stateLock) {
225            beginHandshakeInternal();
226        }
227    }
228
229    private void beginHandshakeInternal() throws SSLException {
230        switch (engineState) {
231            case MODE_SET:
232                // This is the only allowed state.
233                break;
234            case HANDSHAKE_STARTED:
235                throw new IllegalStateException("Handshake has already been started");
236            case CLOSED_INBOUND:
237            case CLOSED_OUTBOUND:
238            case CLOSED:
239                throw new IllegalStateException("Engine has already been closed");
240            default:
241                throw new IllegalStateException("Client/server mode must be set before handshake");
242        }
243
244        engineState = EngineState.HANDSHAKE_STARTED;
245
246        boolean releaseResources = true;
247        try {
248            final AbstractSessionContext sessionContext = sslParameters.getSessionContext();
249            sslNativePointer = NativeCrypto.SSL_new(sessionContext.sslCtxNativePointer);
250            networkBio = NativeCrypto.SSL_BIO_new(sslNativePointer);
251            sslSession =
252                    sslParameters.getSessionToReuse(sslNativePointer, getPeerHost(), getPeerPort());
253            sslParameters.setSSLParameters(sslNativePointer, this, this, getPeerHost());
254            sslParameters.setCertificateValidation(sslNativePointer);
255            sslParameters.setTlsChannelId(sslNativePointer, channelIdPrivateKey);
256            if (getUseClientMode()) {
257                NativeCrypto.SSL_set_connect_state(sslNativePointer);
258            } else {
259                NativeCrypto.SSL_set_accept_state(sslNativePointer);
260            }
261            maxSealOverhead = NativeCrypto.SSL_max_seal_overhead(sslNativePointer);
262            handshake();
263            releaseResources = false;
264        } catch (IOException e) {
265            // Write CCS errors to EventLog
266            String message = e.getMessage();
267            // Must match error reason string of SSL_R_UNEXPECTED_CCS (in ssl/ssl_err.c)
268            if (message.contains("unexpected CCS")) {
269                String logMessage = String.format("ssl_unexpected_ccs: host=%s", getPeerHost());
270                Platform.logEvent(logMessage);
271            }
272            throw new SSLException(e);
273        } finally {
274            if (releaseResources) {
275                engineState = EngineState.CLOSED;
276                shutdownAndFreeSslNative();
277            }
278        }
279    }
280
281    @Override
282    public void closeInbound() throws SSLException {
283        synchronized (stateLock) {
284            if (engineState == EngineState.CLOSED) {
285                return;
286            }
287            if (engineState == EngineState.CLOSED_OUTBOUND) {
288                engineState = EngineState.CLOSED;
289            } else {
290                engineState = EngineState.CLOSED_INBOUND;
291            }
292        }
293        // TODO anything else to notify OpenSSL layer?
294    }
295
296    @Override
297    public void closeOutbound() {
298        synchronized (stateLock) {
299            if (engineState == EngineState.CLOSED || engineState == EngineState.CLOSED_OUTBOUND) {
300                return;
301            }
302            if (engineState != EngineState.MODE_SET && engineState != EngineState.NEW) {
303                shutdownAndFreeSslNative();
304            }
305            if (engineState == EngineState.CLOSED_INBOUND) {
306                engineState = EngineState.CLOSED;
307            } else {
308                engineState = EngineState.CLOSED_OUTBOUND;
309            }
310        }
311        shutdown();
312    }
313
314    @Override
315    public Runnable getDelegatedTask() {
316        // This implementation doesn't use any delegated tasks.
317        return null;
318    }
319
320    @Override
321    public String[] getEnabledCipherSuites() {
322        return sslParameters.getEnabledCipherSuites();
323    }
324
325    @Override
326    public String[] getEnabledProtocols() {
327        return sslParameters.getEnabledProtocols();
328    }
329
330    @Override
331    public boolean getEnableSessionCreation() {
332        return sslParameters.getEnableSessionCreation();
333    }
334
335    @Override
336    public HandshakeStatus getHandshakeStatus() {
337        synchronized (stateLock) {
338            return getHandshakeStatusInternal();
339        }
340    }
341
342    private HandshakeStatus getHandshakeStatusInternal() {
343        if (handshakeFinished) {
344            return HandshakeStatus.NOT_HANDSHAKING;
345        }
346        switch (engineState) {
347            case HANDSHAKE_STARTED:
348                return pendingStatus(pendingOutboundEncryptedBytes());
349            case HANDSHAKE_COMPLETED:
350                return HandshakeStatus.NEED_WRAP;
351            case NEW:
352            case MODE_SET:
353            case CLOSED:
354            case CLOSED_INBOUND:
355            case CLOSED_OUTBOUND:
356            case READY:
357            case READY_HANDSHAKE_CUT_THROUGH:
358                return HandshakeStatus.NOT_HANDSHAKING;
359            default:
360                break;
361        }
362        throw new IllegalStateException("Unexpected engine state: " + engineState);
363    }
364
365    private int pendingOutboundEncryptedBytes() {
366        return NativeCrypto.SSL_pending_written_bytes_in_BIO(networkBio);
367    }
368
369    private int pendingInboundCleartextBytes() {
370        return NativeCrypto.SSL_pending_readable_bytes(sslNativePointer);
371    }
372
373    private int pendingInboundCleartextBytes(HandshakeStatus handshakeStatus) {
374        // There won't be any application data until we're done handshaking.
375        // We first check handshakeFinished to eliminate the overhead of extra JNI call if possible.
376        return handshakeStatus == HandshakeStatus.FINISHED ? pendingInboundCleartextBytes() : 0;
377    }
378
379    private static SSLEngineResult.HandshakeStatus pendingStatus(int pendingOutboundBytes) {
380        // Depending on if there is something left in the BIO we need to WRAP or UNWRAP
381        return pendingOutboundBytes > 0 ? NEED_WRAP : NEED_UNWRAP;
382    }
383
384    @Override
385    public boolean getNeedClientAuth() {
386        return sslParameters.getNeedClientAuth();
387    }
388
389    @Override
390    public SSLSession getSession() {
391        if (sslSession == null) {
392            return handshakeSession != null ? handshakeSession : SSLNullSession.getNullSession();
393        }
394        return sslSession;
395    }
396
397    @Override
398    public String[] getSupportedCipherSuites() {
399        return NativeCrypto.getSupportedCipherSuites();
400    }
401
402    @Override
403    public String[] getSupportedProtocols() {
404        return NativeCrypto.getSupportedProtocols();
405    }
406
407    @Override
408    public boolean getUseClientMode() {
409        return sslParameters.getUseClientMode();
410    }
411
412    @Override
413    public boolean getWantClientAuth() {
414        return sslParameters.getWantClientAuth();
415    }
416
417    @Override
418    public boolean isInboundDone() {
419        if (sslNativePointer == 0) {
420            synchronized (stateLock) {
421                return engineState == EngineState.CLOSED
422                        || engineState == EngineState.CLOSED_INBOUND;
423            }
424        }
425        return (NativeCrypto.SSL_get_shutdown(sslNativePointer) & SSL_RECEIVED_SHUTDOWN) != 0;
426    }
427
428    @Override
429    public boolean isOutboundDone() {
430        if (sslNativePointer == 0) {
431            synchronized (stateLock) {
432                return engineState == EngineState.CLOSED
433                        || engineState == EngineState.CLOSED_OUTBOUND;
434            }
435        }
436        return (NativeCrypto.SSL_get_shutdown(sslNativePointer) & SSL_SENT_SHUTDOWN) != 0;
437    }
438
439    @Override
440    public void setEnabledCipherSuites(String[] suites) {
441        sslParameters.setEnabledCipherSuites(suites);
442    }
443
444    @Override
445    public void setEnabledProtocols(String[] protocols) {
446        sslParameters.setEnabledProtocols(protocols);
447    }
448
449    @Override
450    public void setEnableSessionCreation(boolean flag) {
451        sslParameters.setEnableSessionCreation(flag);
452    }
453
454    @Override
455    public void setNeedClientAuth(boolean need) {
456        sslParameters.setNeedClientAuth(need);
457    }
458
459    @Override
460    public void setUseClientMode(boolean mode) {
461        synchronized (stateLock) {
462            if (engineState != EngineState.MODE_SET && engineState != EngineState.NEW) {
463                throw new IllegalArgumentException(
464                        "Can not change mode after handshake: engineState == " + engineState);
465            }
466            engineState = EngineState.MODE_SET;
467        }
468        sslParameters.setUseClientMode(mode);
469    }
470
471    @Override
472    public void setWantClientAuth(boolean want) {
473        sslParameters.setWantClientAuth(want);
474    }
475
476    @Override
477    public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
478        synchronized (stateLock) {
479            try {
480                return unwrap(singleSrcBuffer(src), singleDstBuffer(dst));
481            } finally {
482                resetSingleSrcBuffer();
483                resetSingleDstBuffer();
484            }
485        }
486    }
487
488    @Override
489    public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
490        synchronized (stateLock) {
491            try {
492                return unwrap(singleSrcBuffer(src), dsts);
493            } finally {
494                resetSingleSrcBuffer();
495            }
496        }
497    }
498
499    @Override
500    public SSLEngineResult unwrap(final ByteBuffer src, final ByteBuffer[] dsts, final int offset,
501            final int length) throws SSLException {
502        synchronized (stateLock) {
503            try {
504                return unwrap(singleSrcBuffer(src), 0, 1, dsts, offset, length);
505            } finally {
506                resetSingleSrcBuffer();
507            }
508        }
509    }
510
511    public SSLEngineResult unwrap(final ByteBuffer[] srcs, final ByteBuffer[] dsts)
512            throws SSLException {
513        checkNotNull(srcs, "srcs");
514        checkNotNull(dsts, "dsts");
515        return unwrap(srcs, 0, srcs.length, dsts, 0, dsts.length);
516    }
517
518    public SSLEngineResult unwrap(final ByteBuffer[] srcs, int srcsOffset, final int srcsLength,
519            final ByteBuffer[] dsts, final int dstsOffset, final int dstsLength)
520            throws SSLException {
521        checkNotNull(srcs, "srcs");
522        checkNotNull(dsts, "dsts");
523
524        checkIndex(srcs.length, srcsOffset, srcsLength, "srcs");
525        checkIndex(dsts.length, dstsOffset, dstsLength, "dsts");
526
527        // Determine the output capacity.
528        int capacity = 0;
529        final int endOffset = dstsOffset + dstsLength;
530        for (int i = 0; i < dsts.length; i++) {
531            ByteBuffer dst = dsts[i];
532            checkNotNull(dst, "one of the dst");
533            if (dst.isReadOnly()) {
534                throw new ReadOnlyBufferException();
535            }
536            if (i >= dstsOffset && i < dstsOffset + dstsLength) {
537                capacity += dst.remaining();
538            }
539        }
540
541        final int srcsEndOffset = srcsOffset + srcsLength;
542        long len = 0;
543        for (int i = srcsOffset; i < srcsEndOffset; i++) {
544            ByteBuffer src = srcs[i];
545            if (src == null) {
546                throw new IllegalArgumentException("srcs[" + i + "] is null");
547            }
548            len += src.remaining();
549        }
550
551        synchronized (stateLock) {
552            switch (engineState) {
553                case MODE_SET:
554                    // Begin the handshake implicitly.
555                    beginHandshakeInternal();
556                    break;
557                case CLOSED_INBOUND:
558                case CLOSED:
559                    // If the inbound direction is closed. we can't send anymore.
560                    return new SSLEngineResult(Status.CLOSED, getHandshakeStatusInternal(), 0, 0);
561                case NEW:
562                    throw new IllegalStateException(
563                            "Client/server mode must be set before calling unwrap");
564                default:
565                    break;
566            }
567
568            HandshakeStatus handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
569            if (!handshakeFinished) {
570                handshakeStatus = handshake();
571                if (handshakeStatus == NEED_WRAP) {
572                    return NEED_WRAP_OK;
573                }
574                if (engineState == EngineState.CLOSED) {
575                    return NEED_WRAP_CLOSED;
576                }
577                // NEED_UNWRAP - just fall through to perform the unwrap.
578            }
579
580            if (len < SSL3_RT_HEADER_LENGTH) {
581                return new SSLEngineResult(BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0);
582            }
583
584            int packetLength = SSLUtils.getEncryptedPacketLength(srcs, srcsOffset);
585            if (packetLength < 0) {
586                throw new SSLException("Unable to parse TLS packet header");
587            }
588
589            if (len < packetLength) {
590                // We either have not enough data to read the packet header or not enough for
591                // reading the whole packet.
592                return new SSLEngineResult(BUFFER_UNDERFLOW, getHandshakeStatus(), 0, 0);
593            }
594
595            // Write all of the source data to the networkBio
596            int bytesConsumed = 0;
597            if (srcsOffset < srcsEndOffset) {
598                int packetLengthRemaining = packetLength;
599                do {
600                    ByteBuffer src = srcs[srcsOffset];
601                    int remaining = src.remaining();
602                    if (remaining == 0) {
603                        // We must skip empty buffers as BIO_write will return 0 if asked to write
604                        // something
605                        // with length 0.
606                        srcsOffset++;
607                        continue;
608                    }
609                    // Write the source encrypted data to the networkBio.
610                    int written =
611                            writeEncryptedData(src, Math.min(packetLengthRemaining, remaining));
612                    if (written > 0) {
613                        packetLengthRemaining -= written;
614                        if (packetLengthRemaining == 0) {
615                            // A whole packet has been consumed.
616                            break;
617                        }
618
619                        if (written == remaining) {
620                            srcsOffset++;
621                        } else {
622                            // We were not able to write everything into the BIO so break the write
623                            // loop as otherwise
624                            // we will produce an error on the next write attempt, which will
625                            // trigger a SSL.clearError()
626                            // later.
627                            break;
628                        }
629                    } else {
630                        // BIO_write returned a negative or zero number, this means we could not
631                        // complete the write
632                        // operation and should retry later.
633                        // We ignore BIO_* errors here as we use in memory BIO anyway and will do
634                        // another SSL_* call
635                        // later on in which we will produce an exception in case of an error
636                        NativeCrypto.SSL_clear_error();
637                        break;
638                    }
639                } while (srcsOffset < srcsEndOffset);
640                bytesConsumed = packetLength - packetLengthRemaining;
641            }
642
643            // Now read any available plaintext data.
644            int bytesProduced = 0;
645            if (capacity > 0) {
646                // Write decrypted data to dsts buffers
647                for (int idx = dstsOffset; idx < endOffset; ++idx) {
648                    ByteBuffer dst = dsts[idx];
649                    if (!dst.hasRemaining()) {
650                        continue;
651                    }
652
653                    int bytesRead = readPlaintextData(dst);
654
655                    if (bytesRead > 0) {
656                        bytesProduced += bytesRead;
657                        if (!dst.hasRemaining()) {
658                            continue;
659                        }
660
661                        // We read everything return now.
662                        return newResult(bytesConsumed, bytesProduced, handshakeStatus);
663                    }
664
665                    // Return an appropriate result based on the error code.
666                    int sslError = NativeCrypto.SSL_get_error(sslNativePointer, bytesRead);
667                    switch (sslError) {
668                        case SSL_ERROR_ZERO_RETURN:
669                            // This means the connection was shutdown correctly, close inbound and
670                            // outbound
671                            closeAll();
672                            return newResult(bytesConsumed, bytesProduced, handshakeStatus);
673                        case SSL_ERROR_WANT_READ:
674                        case SSL_ERROR_WANT_WRITE:
675                            return newResult(bytesConsumed, bytesProduced, handshakeStatus);
676                        default:
677                            return sslReadErrorResult(NativeCrypto.SSL_get_last_error_number(),
678                                    bytesConsumed, bytesProduced);
679                    }
680                }
681            } else {
682                // If the capacity of all destination buffers is 0 we need to trigger a SSL_read
683                // anyway to ensure
684                // everything is flushed in the BIO pair and so we can detect it in the
685                // pendingInboundCleartextBytes() call.
686                try {
687                    if (NativeCrypto.ENGINE_SSL_read_direct(sslNativePointer, EMPTY_ADDR, 0, this)
688                            <= 0) {
689                        // We do not check SSL_get_error as we are not interested in any error that
690                        // is not fatal.
691                        int err = NativeCrypto.SSL_get_last_error_number();
692                        if (err != SSL_ERROR_NONE) {
693                            return sslReadErrorResult(err, bytesConsumed, bytesProduced);
694                        }
695                    }
696                } catch (IOException e) {
697                    throw new SSLException(e);
698                }
699            }
700            if (pendingInboundCleartextBytes(handshakeStatus) > 0) {
701                // We filled all buffers but there is still some data pending in the BIO buffer,
702                // return BUFFER_OVERFLOW.
703                return new SSLEngineResult(BUFFER_OVERFLOW,
704                        mayFinishHandshake(handshakeStatus == FINISHED
705                                        ? handshakeStatus
706                                        : getHandshakeStatusInternal()),
707                        bytesConsumed, bytesProduced);
708            }
709
710            return newResult(bytesConsumed, bytesProduced, handshakeStatus);
711        }
712    }
713
714    private SSLEngineResult.HandshakeStatus handshake() throws SSLException {
715        long sslSessionCtx = 0L;
716        try {
717            // Only actually perform the handshake if we haven't already just completed it
718            // via BIO operations.
719            int code = NativeCrypto.ENGINE_SSL_do_handshake(sslNativePointer, this);
720            if (code <= 0) {
721                int sslError = NativeCrypto.SSL_get_error(sslNativePointer, code);
722                switch (sslError) {
723                    case SSL_ERROR_WANT_READ:
724                    case SSL_ERROR_WANT_WRITE:
725                        return pendingStatus(pendingOutboundEncryptedBytes());
726                    default:
727                        // Everything else is considered as error
728                        throw shutdownWithError("SSL_do_handshake");
729                }
730            }
731
732            // Handshake is finished!
733            sslSessionCtx = NativeCrypto.SSL_get1_session(sslNativePointer);
734            if (sslSessionCtx == 0) {
735                // TODO(nathanmittler): Should we throw here?
736                // return pendingStatus(pendingOutboundBytes());
737                throw shutdownWithError("Failed to obtain session after handshake completed");
738            }
739            sslSession = sslParameters.setupSession(sslSessionCtx, sslNativePointer, sslSession,
740                    getPeerHost(), getPeerPort(), true);
741            if (sslSession != null && engineState == EngineState.HANDSHAKE_STARTED) {
742                engineState = EngineState.READY_HANDSHAKE_CUT_THROUGH;
743            } else {
744                engineState = EngineState.READY;
745            }
746            finishHandshake();
747            return FINISHED;
748        } catch (Exception e) {
749            throw toSSLHandshakeException(e);
750        } finally {
751            if (sslSession == null && sslSessionCtx != 0) {
752                NativeCrypto.SSL_SESSION_free(sslSessionCtx);
753            }
754        }
755    }
756
757    private void finishHandshake() throws SSLException {
758        handshakeFinished = true;
759        // Notify the listener, if provided.
760        if (handshakeListener != null) {
761            handshakeListener.onHandshakeFinished();
762        }
763    }
764    /**
765     * Write plaintext data to the OpenSSL internal BIO
766     *
767     * Calling this function with src.remaining == 0 is undefined.
768     */
769    private int writePlaintextData(final ByteBuffer src, int len) throws SSLException {
770        try {
771            final int pos = src.position();
772            final int sslWrote;
773
774            if (src.isDirect()) {
775                long addr = NativeCrypto.getDirectBufferAddress(src) + pos;
776                sslWrote = NativeCrypto.ENGINE_SSL_write_direct(sslNativePointer, addr, len, this);
777            } else {
778                ByteBuffer heapSrc = toHeapBuffer(src, len);
779                sslWrote = NativeCrypto.ENGINE_SSL_write_heap(sslNativePointer, heapSrc.array(),
780                        heapSrc.arrayOffset() + heapSrc.position(), len, this);
781            }
782            if (sslWrote > 0) {
783                src.position(pos + sslWrote);
784            }
785            return sslWrote;
786        } catch (Exception e) {
787            throw convertException(e);
788        }
789    }
790
791    /**
792     * Read plaintext data from the OpenSSL internal BIO
793     */
794    private int readPlaintextData(final ByteBuffer dst) throws SSLException {
795        try {
796            final int sslRead;
797            final int pos = dst.position();
798            final int limit = dst.limit();
799            final int len = Math.min(SSL3_RT_MAX_PACKET_SIZE, limit - pos);
800            if (dst.isDirect()) {
801                long addr = NativeCrypto.getDirectBufferAddress(dst) + pos;
802                sslRead = NativeCrypto.ENGINE_SSL_read_direct(sslNativePointer, addr, len, this);
803                if (sslRead > 0) {
804                    dst.position(pos + sslRead);
805                }
806            } else if (dst.hasArray()) {
807                sslRead = NativeCrypto.ENGINE_SSL_read_heap(
808                        sslNativePointer, dst.array(), dst.arrayOffset() + pos, len, this);
809                if (sslRead > 0) {
810                    dst.position(pos + sslRead);
811                }
812            } else {
813                byte[] data = new byte[len];
814                sslRead = NativeCrypto.ENGINE_SSL_read_heap(sslNativePointer, data, 0, len, this);
815                if (sslRead > 0) {
816                    dst.put(data, 0, sslRead);
817                }
818            }
819            return sslRead;
820        } catch (Exception e) {
821            throw convertException(e);
822        }
823    }
824
825    private SSLException convertException(Throwable e) {
826        if (e instanceof SSLHandshakeException || !handshakeFinished) {
827            return SSLUtils.toSSLHandshakeException(e);
828        }
829        return SSLUtils.toSSLException(e);
830    }
831
832    /**
833     * Write encrypted data to the OpenSSL network BIO.
834     */
835    private int writeEncryptedData(final ByteBuffer src, int len) throws SSLException {
836        try {
837            final int pos = src.position();
838            final int netWrote;
839            if (src.isDirect()) {
840                long addr = NativeCrypto.getDirectBufferAddress(src) + pos;
841                netWrote = NativeCrypto.ENGINE_SSL_write_BIO_direct(
842                        sslNativePointer, networkBio, addr, len, this);
843            } else {
844                ByteBuffer heapSrc = toHeapBuffer(src, len);
845                netWrote = NativeCrypto.ENGINE_SSL_write_BIO_heap(sslNativePointer, networkBio,
846                        heapSrc.array(), heapSrc.arrayOffset() + heapSrc.position(), len, this);
847            }
848
849            if (netWrote >= 0) {
850                src.position(pos + netWrote);
851            }
852
853            return netWrote;
854        } catch (IOException e) {
855            throw new SSLException(e);
856        }
857    }
858
859    private SSLEngineResult readPendingBytesFromBIO(ByteBuffer dst, int bytesConsumed,
860            int bytesProduced, SSLEngineResult.HandshakeStatus status) throws SSLException {
861        try {
862            // Check to see if the engine wrote data into the network BIO
863            int pendingNet = pendingOutboundEncryptedBytes();
864            if (pendingNet > 0) {
865                // Do we have enough room in dst to write encrypted data?
866                int capacity = dst.remaining();
867                if (capacity < pendingNet) {
868                    return new SSLEngineResult(BUFFER_OVERFLOW,
869                            mayFinishHandshake(
870                                    status == FINISHED ? status : getHandshakeStatus(pendingNet)),
871                            bytesConsumed, bytesProduced);
872                }
873
874                // Write the pending data from the network BIO into the dst buffer
875                int produced = readEncryptedData(dst, pendingNet);
876
877                if (produced <= 0) {
878                    // We ignore BIO_* errors here as we use in memory BIO anyway and will do another
879                    // SSL_* call later
880                    // on in which we will produce an exception in case of an error
881                    NativeCrypto.SSL_clear_error();
882                } else {
883                    bytesProduced += produced;
884                    pendingNet -= produced;
885                }
886
887                return new SSLEngineResult(getEngineStatus(),
888                        mayFinishHandshake(
889                                status == FINISHED ? status : getHandshakeStatus(pendingNet)),
890                        bytesConsumed, bytesProduced);
891            }
892            return null;
893        } catch (Exception e) {
894            throw convertException(e);
895        }
896    }
897
898    /**
899     * Read encrypted data from the OpenSSL network BIO
900     */
901    private int readEncryptedData(final ByteBuffer dst, final int pending) throws SSLException {
902        try {
903            int bioRead = 0;
904            if (dst.remaining() >= pending) {
905                final int pos = dst.position();
906                final int limit = dst.limit();
907                final int len = Math.min(pending, limit - pos);
908                if (dst.isDirect()) {
909                    long addr = NativeCrypto.getDirectBufferAddress(dst) + pos;
910                    bioRead = NativeCrypto.ENGINE_SSL_read_BIO_direct(
911                            sslNativePointer, networkBio, addr, len, this);
912                    if (bioRead > 0) {
913                        dst.position(pos + bioRead);
914                        return bioRead;
915                    }
916                } else if (dst.hasArray()) {
917                    bioRead = NativeCrypto.ENGINE_SSL_read_BIO_heap(sslNativePointer, networkBio,
918                            dst.array(), dst.arrayOffset() + pos, pending, this);
919                    if (bioRead > 0) {
920                        dst.position(pos + bioRead);
921                        return bioRead;
922                    }
923                } else {
924                    byte[] data = new byte[len];
925                    bioRead = NativeCrypto.ENGINE_SSL_read_BIO_heap(
926                            sslNativePointer, networkBio, data, 0, pending, this);
927                    if (bioRead > 0) {
928                        dst.put(data, 0, bioRead);
929                        return bioRead;
930                    }
931                }
932            }
933            return bioRead;
934        } catch (Exception e) {
935            throw convertException(e);
936        }
937    }
938
939    private SSLEngineResult.HandshakeStatus mayFinishHandshake(
940            SSLEngineResult.HandshakeStatus status) throws SSLException {
941        if (!handshakeFinished
942                && status
943                        == NOT_HANDSHAKING /*|| engineState == EngineState.HANDSHAKE_COMPLETED)*/) {
944            // If the status was NOT_HANDSHAKING and we not finished the handshake we need to call
945            // SSL_do_handshake() again
946            return handshake();
947        }
948        return status;
949    }
950
951    private SSLEngineResult.HandshakeStatus getHandshakeStatus(int pending) {
952        // Check if we are in the initial handshake phase or shutdown phase
953        return !handshakeFinished ? pendingStatus(pending) : NOT_HANDSHAKING;
954    }
955
956    private SSLEngineResult.Status getEngineStatus() {
957        switch (engineState) {
958            case CLOSED_INBOUND:
959            case CLOSED_OUTBOUND:
960            case CLOSED:
961                return CLOSED;
962            default:
963                return OK;
964        }
965    }
966
967    private void closeAll() throws SSLException {
968        closeOutbound();
969        closeInbound();
970    }
971
972    private SSLEngineResult sslReadErrorResult(int err, int bytesConsumed, int bytesProduced)
973            throws SSLException {
974        if (!handshakeFinished && pendingOutboundEncryptedBytes() > 0) {
975            return new SSLEngineResult(OK, NEED_WRAP, bytesConsumed, bytesProduced);
976        }
977        throw shutdownWithError(NativeCrypto.SSL_get_error_string(err));
978    }
979
980    private SSLException shutdownWithError(String err) {
981        // There was an internal error -- shutdown
982        shutdown();
983        if (getHandshakeStatusInternal() == HandshakeStatus.FINISHED) {
984            return new SSLException(err);
985        }
986        return new SSLHandshakeException(err);
987    }
988
989    private SSLEngineResult newResult(int bytesConsumed, int bytesProduced,
990            SSLEngineResult.HandshakeStatus status) throws SSLException {
991        return new SSLEngineResult(getEngineStatus(),
992                mayFinishHandshake(status == FINISHED ? status : getHandshakeStatusInternal()),
993                bytesConsumed, bytesProduced);
994    }
995
996    @Override
997    public final SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
998        synchronized (stateLock) {
999            try {
1000                return wrap(singleSrcBuffer(src), dst);
1001            } finally {
1002                resetSingleSrcBuffer();
1003            }
1004        }
1005    }
1006
1007    @Override
1008    public SSLEngineResult wrap(ByteBuffer[] srcs, int offset, int length, ByteBuffer dst)
1009            throws SSLException {
1010        checkNotNull(srcs, "srcs");
1011        checkNotNull(dst, "dst");
1012        checkIndex(srcs.length, offset, length, "srcs");
1013        if (dst.isReadOnly()) {
1014            throw new ReadOnlyBufferException();
1015        }
1016
1017        synchronized (stateLock) {
1018            switch (engineState) {
1019                case MODE_SET:
1020                    // Begin the handshake implicitly.
1021                    beginHandshakeInternal();
1022                    break;
1023                case CLOSED_OUTBOUND:
1024                case CLOSED:
1025                    return new SSLEngineResult(Status.CLOSED, getHandshakeStatusInternal(), 0, 0);
1026                case NEW:
1027                    throw new IllegalStateException(
1028                            "Client/server mode must be set before calling wrap");
1029            }
1030
1031            // If we haven't completed the handshake yet, just let the caller know.
1032            HandshakeStatus handshakeStatus = HandshakeStatus.NOT_HANDSHAKING;
1033            // Prepare OpenSSL to work in server mode and receive handshake
1034            if (!handshakeFinished) {
1035                handshakeStatus = handshake();
1036                if (handshakeStatus == NEED_UNWRAP) {
1037                    return NEED_UNWRAP_OK;
1038                }
1039
1040                if (engineState == EngineState.CLOSED) {
1041                    return NEED_UNWRAP_CLOSED;
1042                }
1043                // NEED_WRAP - just fall through to perform the wrap.
1044            }
1045
1046            int srcsLen = 0;
1047            final int endOffset = offset + length;
1048            for (int i = offset; i < endOffset; ++i) {
1049                final ByteBuffer src = srcs[i];
1050                if (src == null) {
1051                    throw new IllegalArgumentException("srcs[" + i + "] is null");
1052                }
1053                if (srcsLen == SSL3_RT_MAX_PLAIN_LENGTH) {
1054                    continue;
1055                }
1056
1057                srcsLen += src.remaining();
1058                if (srcsLen > SSL3_RT_MAX_PLAIN_LENGTH || srcsLen < 0) {
1059                    // If srcLen > MAX_PLAINTEXT_LENGTH or secLen < 0 just set it to MAX_PLAINTEXT_LENGTH.
1060                    // This also help us to guard against overflow.
1061                    // We not break out here as we still need to check for null entries in srcs[].
1062                    srcsLen = SSL3_RT_MAX_PLAIN_LENGTH;
1063                }
1064            }
1065
1066            if (dst.remaining() < calculateOutNetBufSize(srcsLen)) {
1067                return new SSLEngineResult(
1068                        Status.BUFFER_OVERFLOW, getHandshakeStatusInternal(), 0, 0);
1069            }
1070
1071            int bytesProduced = 0;
1072            int bytesConsumed = 0;
1073        loop:
1074            for (int i = offset; i < endOffset; ++i) {
1075                final ByteBuffer src = srcs[i];
1076                checkNotNull(src, "srcs[%d] is null", i);
1077                while (src.hasRemaining()) {
1078                    final SSLEngineResult pendingNetResult;
1079                    // Write plaintext application data to the SSL engine
1080                    int result = writePlaintextData(src,
1081                            Math.min(src.remaining(), SSL3_RT_MAX_PLAIN_LENGTH - bytesConsumed));
1082                    if (result > 0) {
1083                        bytesConsumed += result;
1084
1085                        pendingNetResult = readPendingBytesFromBIO(
1086                                dst, bytesConsumed, bytesProduced, handshakeStatus);
1087                        if (pendingNetResult != null) {
1088                            if (pendingNetResult.getStatus() != OK) {
1089                                return pendingNetResult;
1090                            }
1091                            bytesProduced = pendingNetResult.bytesProduced();
1092                        }
1093                        if (bytesConsumed == SSL3_RT_MAX_PLAIN_LENGTH) {
1094                            // If we consumed the maximum amount of bytes for the plaintext length
1095                            // break out of the loop and start to fill the dst buffer.
1096                            break loop;
1097                        }
1098                    } else {
1099                        int sslError = NativeCrypto.SSL_get_error(sslNativePointer, result);
1100                        switch (sslError) {
1101                            case SSL_ERROR_ZERO_RETURN:
1102                                // This means the connection was shutdown correctly, close inbound
1103                                // and outbound
1104                                closeAll();
1105                                pendingNetResult = readPendingBytesFromBIO(
1106                                        dst, bytesConsumed, bytesProduced, handshakeStatus);
1107                                return pendingNetResult != null ? pendingNetResult
1108                                                                : CLOSED_NOT_HANDSHAKING;
1109                            case SSL_ERROR_WANT_READ:
1110                                // If there is no pending data to read from BIO we should go back to
1111                                // event loop and try
1112                                // to read more data [1]. It is also possible that event loop will
1113                                // detect the socket
1114                                // has been closed. [1]
1115                                // https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
1116                                pendingNetResult = readPendingBytesFromBIO(
1117                                        dst, bytesConsumed, bytesProduced, handshakeStatus);
1118                                return pendingNetResult != null
1119                                        ? pendingNetResult
1120                                        : new SSLEngineResult(getEngineStatus(), NEED_UNWRAP,
1121                                                  bytesConsumed, bytesProduced);
1122                            case SSL_ERROR_WANT_WRITE:
1123                                // SSL_ERROR_WANT_WRITE typically means that the underlying
1124                                // transport is not writable
1125                                // and we should set the "want write" flag on the selector and try
1126                                // again when the
1127                                // underlying transport is writable [1]. However we are not directly
1128                                // writing to the
1129                                // underlying transport and instead writing to a BIO buffer. The
1130                                // OpenSsl documentation
1131                                // says we should do the following [1]:
1132                                //
1133                                // "When using a buffering BIO, like a BIO pair, data must be
1134                                // written into or retrieved
1135                                // out of the BIO before being able to continue."
1136                                //
1137                                // So we attempt to drain the BIO buffer below, but if there is no
1138                                // data this condition
1139                                // is undefined and we assume their is a fatal error with the
1140                                // openssl engine and close.
1141                                // [1] https://www.openssl.org/docs/manmaster/ssl/SSL_write.html
1142                                pendingNetResult = readPendingBytesFromBIO(
1143                                        dst, bytesConsumed, bytesProduced, handshakeStatus);
1144                                return pendingNetResult != null ? pendingNetResult
1145                                                                : NEED_WRAP_CLOSED;
1146                            default:
1147                                // Everything else is considered as error
1148                                throw shutdownWithError("SSL_write");
1149                        }
1150                    }
1151                }
1152            }
1153            // We need to check if pendingWrittenBytesInBIO was checked yet, as we may not checked
1154            // if the srcs was
1155            // empty, or only contained empty buffers.
1156            if (bytesConsumed == 0) {
1157                SSLEngineResult pendingNetResult =
1158                        readPendingBytesFromBIO(dst, 0, bytesProduced, handshakeStatus);
1159                if (pendingNetResult != null) {
1160                    return pendingNetResult;
1161                }
1162            }
1163
1164            // return new SSLEngineResult(OK, getHandshakeStatusInternal(), bytesConsumed,
1165            // bytesProduced);
1166            return newResult(bytesConsumed, bytesProduced, handshakeStatus);
1167        }
1168    }
1169
1170    @Override
1171    public int clientPSKKeyRequested(String identityHint, byte[] identity, byte[] key) {
1172        return sslParameters.clientPSKKeyRequested(identityHint, identity, key, this);
1173    }
1174
1175    @Override
1176    public int serverPSKKeyRequested(String identityHint, String identity, byte[] key) {
1177        return sslParameters.serverPSKKeyRequested(identityHint, identity, key, this);
1178    }
1179
1180    @Override
1181    public void onSSLStateChange(int type, int val) {
1182        synchronized (stateLock) {
1183            switch (type) {
1184                case SSL_CB_HANDSHAKE_DONE:
1185                    if (engineState != EngineState.HANDSHAKE_STARTED &&
1186                        engineState != EngineState.READY_HANDSHAKE_CUT_THROUGH) {
1187                        throw new IllegalStateException(
1188                                "Completed handshake while in mode " + engineState);
1189                    }
1190                    engineState = EngineState.HANDSHAKE_COMPLETED;
1191                    break;
1192                case SSL_CB_HANDSHAKE_START:
1193                    // For clients, this will allow the NEED_UNWRAP status to be
1194                    // returned.
1195                    engineState = EngineState.HANDSHAKE_STARTED;
1196                    break;
1197            }
1198        }
1199    }
1200
1201    @Override
1202    public void verifyCertificateChain(long[] certRefs, String authMethod)
1203            throws CertificateException {
1204        try {
1205            X509TrustManager x509tm = sslParameters.getX509TrustManager();
1206            if (x509tm == null) {
1207                throw new CertificateException("No X.509 TrustManager");
1208            }
1209            if (certRefs == null || certRefs.length == 0) {
1210                throw new SSLException("Peer sent no certificate");
1211            }
1212            OpenSSLX509Certificate[] peerCertChain =
1213                    OpenSSLX509Certificate.createCertChain(certRefs);
1214
1215            byte[] ocspData = NativeCrypto.SSL_get_ocsp_response(sslNativePointer);
1216            byte[] tlsSctData = NativeCrypto.SSL_get_signed_cert_timestamp_list(sslNativePointer);
1217
1218            // Used for verifyCertificateChain callback
1219            handshakeSession = new OpenSSLSessionImpl(
1220                    NativeCrypto.SSL_get1_session(sslNativePointer), null, peerCertChain, ocspData,
1221                    tlsSctData, getPeerHost(), getPeerPort(), null);
1222
1223            boolean client = sslParameters.getUseClientMode();
1224            if (client) {
1225                Platform.checkServerTrusted(x509tm, peerCertChain, authMethod, this);
1226            } else {
1227                String authType = peerCertChain[0].getPublicKey().getAlgorithm();
1228                Platform.checkClientTrusted(x509tm, peerCertChain, authType, this);
1229            }
1230        } catch (CertificateException e) {
1231            throw e;
1232        } catch (Exception e) {
1233            throw new CertificateException(e);
1234        } finally {
1235            handshakeSession = null;
1236        }
1237    }
1238
1239    @Override
1240    public void clientCertificateRequested(byte[] keyTypeBytes, byte[][] asn1DerEncodedPrincipals)
1241            throws CertificateEncodingException, SSLException {
1242        sslParameters.chooseClientCertificate(
1243                keyTypeBytes, asn1DerEncodedPrincipals, sslNativePointer, this);
1244    }
1245
1246    private void shutdown() {
1247        try {
1248            NativeCrypto.ENGINE_SSL_shutdown(sslNativePointer, this);
1249        } catch (IOException ignored) {
1250            // TODO: The RI ignores close failures in SSLSocket, but need to
1251            // investigate whether it does for SSLEngine.
1252        }
1253    }
1254
1255    private void shutdownAndFreeSslNative() {
1256        try {
1257            shutdown();
1258        } finally {
1259            free();
1260        }
1261    }
1262
1263    private void free() {
1264        if (sslNativePointer == 0) {
1265            return;
1266        }
1267        NativeCrypto.SSL_free(sslNativePointer);
1268        NativeCrypto.BIO_free_all(networkBio);
1269        sslNativePointer = 0;
1270        networkBio = 0;
1271    }
1272
1273    @Override
1274    protected void finalize() throws Throwable {
1275        try {
1276            free();
1277        } finally {
1278            super.finalize();
1279        }
1280    }
1281
1282    /* @Override */
1283    @SuppressWarnings("MissingOverride")  // For compilation with Java 6.
1284    public SSLSession getHandshakeSession() {
1285        return handshakeSession;
1286    }
1287
1288    @Override
1289    public String chooseServerAlias(X509KeyManager keyManager, String keyType) {
1290        if (keyManager instanceof X509ExtendedKeyManager) {
1291            X509ExtendedKeyManager ekm = (X509ExtendedKeyManager) keyManager;
1292            return ekm.chooseEngineServerAlias(keyType, null, this);
1293        } else {
1294            return keyManager.chooseServerAlias(keyType, null, null);
1295        }
1296    }
1297
1298    @Override
1299    public String chooseClientAlias(
1300            X509KeyManager keyManager, X500Principal[] issuers, String[] keyTypes) {
1301        if (keyManager instanceof X509ExtendedKeyManager) {
1302            X509ExtendedKeyManager ekm = (X509ExtendedKeyManager) keyManager;
1303            return ekm.chooseEngineClientAlias(keyTypes, issuers, this);
1304        } else {
1305            return keyManager.chooseClientAlias(keyTypes, issuers, null);
1306        }
1307    }
1308
1309    @Override
1310    @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
1311    public String chooseServerPSKIdentityHint(PSKKeyManager keyManager) {
1312        return keyManager.chooseServerKeyIdentityHint(this);
1313    }
1314
1315    @Override
1316    @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
1317    public String chooseClientPSKIdentity(PSKKeyManager keyManager, String identityHint) {
1318        return keyManager.chooseClientKeyIdentity(identityHint, this);
1319    }
1320
1321    @Override
1322    @SuppressWarnings("deprecation") // PSKKeyManager is deprecated, but in our own package
1323    public SecretKey getPSKKey(PSKKeyManager keyManager, String identityHint, String identity) {
1324        return keyManager.getKey(identityHint, identity, this);
1325    }
1326
1327    /**
1328     * This method enables session ticket support.
1329     *
1330     * @param useSessionTickets True to enable session tickets
1331     */
1332    public void setUseSessionTickets(boolean useSessionTickets) {
1333        sslParameters.setUseSessionTickets(useSessionTickets);
1334    }
1335
1336    /**
1337     * This method does nothing and is kept for backward compatibility.
1338     */
1339    public void setNpnProtocols(byte[] npnProtocols) {}
1340
1341    /**
1342     * Sets the list of ALPN protocols. This method internally converts the protocols to their
1343     * wire-format form.
1344     *
1345     * @param alpnProtocols the list of ALPN protocols
1346     * @see #setAlpnProtocols(byte[])
1347     */
1348    public void setAlpnProtocols(String[] alpnProtocols) {
1349        sslParameters.setAlpnProtocols(alpnProtocols);
1350    }
1351
1352    /**
1353     * Alternate version of {@link #setAlpnProtocols(String[])} that directly sets the list of
1354     * ALPN in the wire-format form used by BoringSSL (length-prefixed 8-bit strings).
1355     * Requires that all strings be encoded with US-ASCII.
1356     *
1357     * @param alpnProtocols the encoded form of the ALPN protocol list
1358     * @see #setAlpnProtocols(String[])
1359     */
1360    public void setAlpnProtocols(byte[] alpnProtocols) {
1361        sslParameters.setAlpnProtocols(alpnProtocols);
1362    }
1363
1364    /**
1365     * Returns null always for backward compatibility.
1366     */
1367    public byte[] getNpnSelectedProtocol() {
1368        return null;
1369    }
1370
1371    /**
1372     * Returns the protocol agreed upon by client and server, or {@code null} if no protocol was
1373     * agreed upon.
1374     */
1375    public byte[] getAlpnSelectedProtocol() {
1376        return NativeCrypto.SSL_get0_alpn_selected(sslNativePointer);
1377    }
1378
1379    private ByteBuffer toHeapBuffer(ByteBuffer buffer, int len) {
1380        if (buffer.hasArray()) {
1381            return buffer;
1382        }
1383
1384        // Need to copy to a heap buffer.
1385        final ByteBuffer heapBuffer = ByteBuffer.allocate(len);
1386        final int pos = buffer.position();
1387        final int limit = buffer.limit();
1388        buffer.limit(pos + len);
1389        try {
1390            heapBuffer.put(buffer);
1391            heapBuffer.flip();
1392            return heapBuffer;
1393        } finally {
1394            buffer.limit(limit);
1395            buffer.position(pos);
1396        }
1397    }
1398
1399    private ByteBuffer[] singleSrcBuffer(ByteBuffer src) {
1400        singleSrcBuffer[0] = src;
1401        return singleSrcBuffer;
1402    }
1403
1404    private void resetSingleSrcBuffer() {
1405        singleSrcBuffer[0] = null;
1406    }
1407
1408    private ByteBuffer[] singleDstBuffer(ByteBuffer src) {
1409        singleDstBuffer[0] = src;
1410        return singleDstBuffer;
1411    }
1412
1413    private void resetSingleDstBuffer() {
1414        singleDstBuffer[0] = null;
1415    }
1416
1417    private static void checkIndex(int arrayLength, int offset, int length, String arrayName) {
1418        if ((offset | length) < 0 || offset + length > arrayLength) {
1419            throw new IndexOutOfBoundsException("offset: " + offset + ", length: " + length
1420                    + " (expected: offset <= offset + length <= " + arrayName + ".length ("
1421                    + arrayLength + "))");
1422        }
1423    }
1424
1425    private static <T> T checkNotNull(T obj, String fmt, Object... args) {
1426        if (obj == null) {
1427            throw new IllegalArgumentException(String.format(fmt, args));
1428        }
1429        return obj;
1430    }
1431}
1432