Verify error stack is empty after each operation when using ReferenceCountedOpenSslEngine. (#7943)

Motivation:

https://github.com/netty/netty/pull/7941 proved that its easy to not correctly clear the error stack sometimes. We should do carefully test this.

Modifications:

Add a new SSLEngine wrapper that is used during tests, which verifies that the error stack is empty after each method call.

Result:

Better testing.
This commit is contained in:
Norman Maurer 2018-05-16 13:50:37 +02:00 committed by GitHub
parent 69c644bb98
commit 932d77b83e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 546 additions and 64 deletions

View File

@ -20,6 +20,7 @@ import org.conscrypt.OpenSSLProvider;
import javax.net.ssl.SNIMatcher; import javax.net.ssl.SNIMatcher;
import javax.net.ssl.SNIServerName; import javax.net.ssl.SNIServerName;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLParameters; import javax.net.ssl.SSLParameters;
import java.security.Provider; import java.security.Provider;
import java.util.Collections; import java.util.Collections;
@ -41,4 +42,14 @@ final class Java8SslTestUtils {
static Provider conscryptProvider() { static Provider conscryptProvider() {
return new OpenSSLProvider(); return new OpenSSLProvider();
} }
/**
* Wraps the given {@link SSLEngine} to add extra tests while executing methods if possible / needed.
*/
static SSLEngine wrapSSLEngineForTesting(SSLEngine engine) {
if (engine instanceof ReferenceCountedOpenSslEngine) {
return new OpenSslErrorStackAssertSSLEngine((ReferenceCountedOpenSslEngine) engine);
}
return engine;
}
} }

View File

@ -20,6 +20,7 @@ import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
import javax.net.ssl.SSLEngine;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
@ -105,4 +106,9 @@ public class JdkOpenSslEngineInteroptTest extends SSLEngineTest {
// TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause); return super.mySetupMutualAuthServerIsValidClientException(cause) || causedBySSLException(cause);
} }
@Override
protected SSLEngine wrapEngine(SSLEngine engine) {
return Java8SslTestUtils.wrapSSLEngineForTesting(engine);
}
} }

View File

@ -87,7 +87,7 @@ public class OpenSslEngineTest extends SSLEngineTest {
@Override @Override
public void tearDown() throws InterruptedException { public void tearDown() throws InterruptedException {
super.tearDown(); super.tearDown();
Assert.assertEquals("SSL error stack not correctly consumed", 0, SSL.getLastErrorNumber()); assertEquals("SSL error stack not correctly consumed", 0, SSL.getLastErrorNumber());
} }
@Override @Override
@ -215,8 +215,8 @@ public class OpenSslEngineTest extends SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
handshake(clientEngine, serverEngine); handshake(clientEngine, serverEngine);
ByteBuffer src = allocateBuffer(1024 * 10); ByteBuffer src = allocateBuffer(1024 * 10);
@ -249,8 +249,8 @@ public class OpenSslEngineTest extends SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
handshake(clientEngine, serverEngine); handshake(clientEngine, serverEngine);
// Allocate a buffer which is small enough and set the limit to the capacity to mark its whole content // Allocate a buffer which is small enough and set the limit to the capacity to mark its whole content
@ -259,9 +259,9 @@ public class OpenSslEngineTest extends SSLEngineTest {
ByteBuffer src = allocateBuffer(srcLen); ByteBuffer src = allocateBuffer(srcLen);
ByteBuffer dstTooSmall = allocateBuffer( ByteBuffer dstTooSmall = allocateBuffer(
src.capacity() + ((ReferenceCountedOpenSslEngine) clientEngine).maxWrapOverhead() - 1); src.capacity() + unwrapEngine(clientEngine).maxWrapOverhead() - 1);
ByteBuffer dst = allocateBuffer( ByteBuffer dst = allocateBuffer(
src.capacity() + ((ReferenceCountedOpenSslEngine) clientEngine).maxWrapOverhead()); src.capacity() + unwrapEngine(clientEngine).maxWrapOverhead());
// Check that we fail to wrap if the dst buffers capacity is not at least // Check that we fail to wrap if the dst buffers capacity is not at least
// src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH // src.capacity() + ReferenceCountedOpenSslEngine.MAX_TLS_RECORD_OVERHEAD_LENGTH
@ -300,15 +300,15 @@ public class OpenSslEngineTest extends SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
handshake(clientEngine, serverEngine); handshake(clientEngine, serverEngine);
ByteBuffer src = allocateBuffer(1024); ByteBuffer src = allocateBuffer(1024);
ByteBuffer src2 = src.duplicate(); ByteBuffer src2 = src.duplicate();
ByteBuffer dst = allocateBuffer(src.capacity() ByteBuffer dst = allocateBuffer(src.capacity()
+ ((ReferenceCountedOpenSslEngine) clientEngine).maxWrapOverhead()); + unwrapEngine(clientEngine).maxWrapOverhead());
SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 }, dst); SSLEngineResult result = clientEngine.wrap(new ByteBuffer[] { src, src2 }, dst);
assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
@ -336,8 +336,8 @@ public class OpenSslEngineTest extends SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
handshake(clientEngine, serverEngine); handshake(clientEngine, serverEngine);
ByteBuffer src = allocateBuffer(1024); ByteBuffer src = allocateBuffer(1024);
@ -353,7 +353,7 @@ public class OpenSslEngineTest extends SSLEngineTest {
ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]); ByteBuffer[] srcs = srcList.toArray(new ByteBuffer[srcList.size()]);
ByteBuffer dst = allocateBuffer( ByteBuffer dst = allocateBuffer(
((ReferenceCountedOpenSslEngine) clientEngine).maxEncryptedPacketLength() - 1); unwrapEngine(clientEngine).maxEncryptedPacketLength() - 1);
SSLEngineResult result = clientEngine.wrap(srcs, dst); SSLEngineResult result = clientEngine.wrap(srcs, dst);
assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus()); assertEquals(SSLEngineResult.Status.BUFFER_OVERFLOW, result.getStatus());
@ -596,13 +596,13 @@ public class OpenSslEngineTest extends SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine client = wrapEngine(clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine server = wrapEngine(serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
try { try {
// Choose buffer size small enough that we can put multiple buffers into one buffer and pass it into the // Choose buffer size small enough that we can put multiple buffers into one buffer and pass it into the
@ -673,13 +673,13 @@ public class OpenSslEngineTest extends SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine client = wrapEngine(clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine server = wrapEngine(serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
try { try {
ByteBuffer plainClient = allocateBuffer(MAX_PLAINTEXT_LENGTH + 100); ByteBuffer plainClient = allocateBuffer(MAX_PLAINTEXT_LENGTH + 100);
@ -757,13 +757,13 @@ public class OpenSslEngineTest extends SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine client = wrapEngine(clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine server = wrapEngine(serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
try { try {
ByteBuffer plainClient = allocateBuffer(1024); ByteBuffer plainClient = allocateBuffer(1024);
@ -832,13 +832,13 @@ public class OpenSslEngineTest extends SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine client = wrapEngine(clientSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine(); SSLEngine server = wrapEngine(serverSslCtx.newHandler(UnpooledByteBufAllocator.DEFAULT).engine());
try { try {
ByteBuffer plainClient = allocateBuffer(1024); ByteBuffer plainClient = allocateBuffer(1024);
@ -913,8 +913,8 @@ public class OpenSslEngineTest extends SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
clientEngine.setEnabledCipherSuites(new String[] { cipher }); clientEngine.setEnabledCipherSuites(new String[] { cipher });
clientEngine.setEnabledProtocols(new String[] { protocol }); clientEngine.setEnabledProtocols(new String[] { protocol });
serverEngine.setEnabledCipherSuites(new String[] { cipher }); serverEngine.setEnabledCipherSuites(new String[] { cipher });
@ -944,7 +944,7 @@ public class OpenSslEngineTest extends SSLEngineTest {
private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException { private void testWrapDstBigEnough(SSLEngine engine, int srcLen) throws SSLException {
ByteBuffer src = allocateBuffer(srcLen); ByteBuffer src = allocateBuffer(srcLen);
ByteBuffer dst = allocateBuffer(srcLen + ((ReferenceCountedOpenSslEngine) engine).maxWrapOverhead()); ByteBuffer dst = allocateBuffer(srcLen + unwrapEngine(engine).maxWrapOverhead());
SSLEngineResult result = engine.wrap(src, dst); SSLEngineResult result = engine.wrap(src, dst);
assertEquals(SSLEngineResult.Status.OK, result.getStatus()); assertEquals(SSLEngineResult.Status.OK, result.getStatus());
@ -966,7 +966,7 @@ public class OpenSslEngineTest extends SSLEngineTest {
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine engine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
SSLParameters parameters = new SSLParameters(); SSLParameters parameters = new SSLParameters();
Java8SslTestUtils.setSNIMatcher(parameters); Java8SslTestUtils.setSNIMatcher(parameters);
@ -984,7 +984,7 @@ public class OpenSslEngineTest extends SSLEngineTest {
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine engine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine engine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
SSLParameters parameters = new SSLParameters(); SSLParameters parameters = new SSLParameters();
parameters.setAlgorithmConstraints(new AlgorithmConstraints() { parameters.setAlgorithmConstraints(new AlgorithmConstraints() {
@ -1029,4 +1029,19 @@ public class OpenSslEngineTest extends SSLEngineTest {
SelectedListenerFailureBehavior.ACCEPT, SelectedListenerFailureBehavior.ACCEPT,
supportedProtocols); supportedProtocols);
} }
@Override
protected SSLEngine wrapEngine(SSLEngine engine) {
if (PlatformDependent.javaVersion() >= 8) {
return Java8SslTestUtils.wrapSSLEngineForTesting(engine);
}
return engine;
}
ReferenceCountedOpenSslEngine unwrapEngine(SSLEngine engine) {
if (engine instanceof JdkSslEngine) {
return (ReferenceCountedOpenSslEngine) ((JdkSslEngine) engine).getWrappedEngine();
}
return (ReferenceCountedOpenSslEngine) engine;
}
} }

View File

@ -0,0 +1,440 @@
/*
* Copyright 2018 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.handler.ssl;
import io.netty.internal.tcnative.SSL;
import io.netty.util.ReferenceCounted;
import io.netty.util.internal.PlatformDependent;
import org.junit.Assert;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLEngineResult;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLParameters;
import javax.net.ssl.SSLSession;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.function.BiFunction;
/**
* Special {@link SSLEngine} which allows to wrap a {@link ReferenceCountedOpenSslEngine} and verify that that
* Error stack is empty after each method call.
*/
final class OpenSslErrorStackAssertSSLEngine extends JdkSslEngine implements ReferenceCounted {
OpenSslErrorStackAssertSSLEngine(ReferenceCountedOpenSslEngine engine) {
super(engine);
}
@Override
public String getPeerHost() {
try {
return getWrappedEngine().getPeerHost();
} finally {
assertErrorStackEmpty();
}
}
@Override
public int getPeerPort() {
try {
return getWrappedEngine().getPeerPort();
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLEngineResult wrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
try {
return getWrappedEngine().wrap(src, dst);
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLEngineResult wrap(ByteBuffer[] srcs, ByteBuffer dst) throws SSLException {
try {
return getWrappedEngine().wrap(srcs, dst);
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLEngineResult wrap(ByteBuffer[] byteBuffers, int i, int i1, ByteBuffer byteBuffer) throws SSLException {
try {
return getWrappedEngine().wrap(byteBuffers, i, i1, byteBuffer);
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer dst) throws SSLException {
try {
return getWrappedEngine().unwrap(src, dst);
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts) throws SSLException {
try {
return getWrappedEngine().unwrap(src, dsts);
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLEngineResult unwrap(ByteBuffer byteBuffer, ByteBuffer[] byteBuffers, int i, int i1) throws SSLException {
try {
return getWrappedEngine().unwrap(byteBuffer, byteBuffers, i, i1);
} finally {
assertErrorStackEmpty();
}
}
@Override
public Runnable getDelegatedTask() {
try {
return getWrappedEngine().getDelegatedTask();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void closeInbound() throws SSLException {
try {
getWrappedEngine().closeInbound();
} finally {
assertErrorStackEmpty();
}
}
@Override
public boolean isInboundDone() {
try {
return getWrappedEngine().isInboundDone();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void closeOutbound() {
try {
getWrappedEngine().closeOutbound();
} finally {
assertErrorStackEmpty();
}
}
@Override
public boolean isOutboundDone() {
try {
return getWrappedEngine().isOutboundDone();
} finally {
assertErrorStackEmpty();
}
}
@Override
public String[] getSupportedCipherSuites() {
try {
return getWrappedEngine().getSupportedCipherSuites();
} finally {
assertErrorStackEmpty();
}
}
@Override
public String[] getEnabledCipherSuites() {
try {
return getWrappedEngine().getEnabledCipherSuites();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void setEnabledCipherSuites(String[] strings) {
try {
getWrappedEngine().setEnabledCipherSuites(strings);
} finally {
assertErrorStackEmpty();
}
}
@Override
public String[] getSupportedProtocols() {
try {
return getWrappedEngine().getSupportedProtocols();
} finally {
assertErrorStackEmpty();
}
}
@Override
public String[] getEnabledProtocols() {
try {
return getWrappedEngine().getEnabledProtocols();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void setEnabledProtocols(String[] strings) {
try {
getWrappedEngine().setEnabledProtocols(strings);
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLSession getSession() {
try {
return getWrappedEngine().getSession();
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLSession getHandshakeSession() {
try {
return getWrappedEngine().getHandshakeSession();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void beginHandshake() throws SSLException {
try {
getWrappedEngine().beginHandshake();
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLEngineResult.HandshakeStatus getHandshakeStatus() {
try {
return getWrappedEngine().getHandshakeStatus();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void setUseClientMode(boolean b) {
try {
getWrappedEngine().setUseClientMode(b);
} finally {
assertErrorStackEmpty();
}
}
@Override
public boolean getUseClientMode() {
try {
return getWrappedEngine().getUseClientMode();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void setNeedClientAuth(boolean b) {
try {
getWrappedEngine().setNeedClientAuth(b);
} finally {
assertErrorStackEmpty();
}
}
@Override
public boolean getNeedClientAuth() {
try {
return getWrappedEngine().getNeedClientAuth();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void setWantClientAuth(boolean b) {
try {
getWrappedEngine().setWantClientAuth(b);
} finally {
assertErrorStackEmpty();
}
}
@Override
public boolean getWantClientAuth() {
try {
return getWrappedEngine().getWantClientAuth();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void setEnableSessionCreation(boolean b) {
try {
getWrappedEngine().setEnableSessionCreation(b);
} finally {
assertErrorStackEmpty();
}
}
@Override
public boolean getEnableSessionCreation() {
try {
return getWrappedEngine().getEnableSessionCreation();
} finally {
assertErrorStackEmpty();
}
}
@Override
public SSLParameters getSSLParameters() {
try {
return getWrappedEngine().getSSLParameters();
} finally {
assertErrorStackEmpty();
}
}
@Override
public void setSSLParameters(SSLParameters params) {
try {
getWrappedEngine().setSSLParameters(params);
} finally {
assertErrorStackEmpty();
}
}
public String getApplicationProtocol() {
if (PlatformDependent.javaVersion() >= 9) {
try {
return Java9SslUtils.getApplicationProtocol(getWrappedEngine());
} finally {
assertErrorStackEmpty();
}
}
throw new UnsupportedOperationException();
}
public String getHandshakeApplicationProtocol() {
if (PlatformDependent.javaVersion() >= 9) {
try {
return Java9SslUtils.getHandshakeApplicationProtocol(getWrappedEngine());
} finally {
assertErrorStackEmpty();
}
}
throw new UnsupportedOperationException();
}
public void setHandshakeApplicationProtocolSelector(BiFunction<SSLEngine, List<String>, String> selector) {
if (PlatformDependent.javaVersion() >= 9) {
try {
Java9SslUtils.setHandshakeApplicationProtocolSelector(getWrappedEngine(), selector);
} finally {
assertErrorStackEmpty();
}
}
throw new UnsupportedOperationException();
}
public BiFunction<SSLEngine, List<String>, String> getHandshakeApplicationProtocolSelector() {
if (PlatformDependent.javaVersion() >= 9) {
try {
return Java9SslUtils.getHandshakeApplicationProtocolSelector(getWrappedEngine());
} finally {
assertErrorStackEmpty();
}
}
throw new UnsupportedOperationException();
}
@Override
public int refCnt() {
return getWrappedEngine().refCnt();
}
@Override
public OpenSslErrorStackAssertSSLEngine retain() {
getWrappedEngine().retain();
return this;
}
@Override
public OpenSslErrorStackAssertSSLEngine retain(int increment) {
getWrappedEngine().retain(increment);
return this;
}
@Override
public OpenSslErrorStackAssertSSLEngine touch() {
getWrappedEngine().touch();
return this;
}
@Override
public OpenSslErrorStackAssertSSLEngine touch(Object hint) {
getWrappedEngine().touch(hint);
return this;
}
@Override
public boolean release() {
return getWrappedEngine().release();
}
@Override
public boolean release(int decrement) {
return getWrappedEngine().release();
}
@Override
public String getNegotiatedApplicationProtocol() {
return getWrappedEngine().getNegotiatedApplicationProtocol();
}
@Override
void setNegotiatedApplicationProtocol(String applicationProtocol) {
throw new UnsupportedOperationException();
}
@Override
public ReferenceCountedOpenSslEngine getWrappedEngine() {
return (ReferenceCountedOpenSslEngine) super.getWrappedEngine();
}
private static void assertErrorStackEmpty() {
Assert.assertEquals("SSL error stack non-empty", 0, SSL.getLastErrorNumber());
}
}

View File

@ -19,6 +19,7 @@ import org.junit.BeforeClass;
import org.junit.Ignore; import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import javax.net.ssl.SSLEngine;
import javax.net.ssl.SSLException; import javax.net.ssl.SSLException;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized; import org.junit.runners.Parameterized;
@ -111,4 +112,9 @@ public class OpenSslJdkSslEngineInteroptTest extends SSLEngineTest {
// TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException. // TODO(scott): work around for a JDK issue. The exception should be SSLHandshakeException.
return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause); return super.mySetupMutualAuthServerIsValidServerException(cause) || causedBySSLException(cause);
} }
@Override
protected SSLEngine wrapEngine(SSLEngine engine) {
return Java8SslTestUtils.wrapSSLEngineForTesting(engine);
}
} }

View File

@ -909,7 +909,7 @@ public abstract class SSLEngineTest {
sb.channel(NioServerSocketChannel.class); sb.channel(NioServerSocketChannel.class);
sb.childHandler(new ChannelInitializer<Channel>() { sb.childHandler(new ChannelInitializer<Channel>() {
@Override @Override
protected void initChannel(Channel ch) throws Exception { protected void initChannel(Channel ch) {
ch.config().setAllocator(new TestByteBufAllocator(ch.config().getAllocator(), type)); ch.config().setAllocator(new TestByteBufAllocator(ch.config().getAllocator(), type));
ChannelPipeline p = ch.pipeline(); ChannelPipeline p = ch.pipeline();
@ -1054,7 +1054,7 @@ public abstract class SSLEngineTest {
.sslContextProvider(clientSslContextProvider()).build(); .sslContextProvider(clientSslContextProvider()).build();
SSLEngine engine = null; SSLEngine engine = null;
try { try {
engine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); engine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
assertTrue(engine.getSession().getCreationTime() <= System.currentTimeMillis()); assertTrue(engine.getSession().getCreationTime() <= System.currentTimeMillis());
} finally { } finally {
cleanupClientSslEngine(engine); cleanupClientSslEngine(engine);
@ -1076,8 +1076,8 @@ public abstract class SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
handshake(clientEngine, serverEngine); handshake(clientEngine, serverEngine);
SSLSession session = serverEngine.getSession(); SSLSession session = serverEngine.getSession();
@ -1106,8 +1106,8 @@ public abstract class SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
// Before the handshake the id should have length == 0 // Before the handshake the id should have length == 0
assertEquals(0, clientEngine.getSession().getId().length); assertEquals(0, clientEngine.getSession().getId().length);
@ -1247,7 +1247,7 @@ public abstract class SSLEngineTest {
.sslContextProvider(serverSslContextProvider()) .sslContextProvider(serverSslContextProvider())
.build(); .build();
sslEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); sslEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
// Disable all protocols // Disable all protocols
sslEngine.setEnabledProtocols(EmptyArrays.EMPTY_STRINGS); sslEngine.setEnabledProtocols(EmptyArrays.EMPTY_STRINGS);
@ -1597,13 +1597,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
byte[] bytes = "Hello World".getBytes(CharsetUtil.US_ASCII); byte[] bytes = "Hello World".getBytes(CharsetUtil.US_ASCII);
@ -1688,14 +1688,14 @@ public abstract class SSLEngineTest {
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.protocols(clientProtocols) .protocols(clientProtocols)
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.protocols(serverProtocols) .protocols(serverProtocols)
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
handshake(client, server); handshake(client, server);
@ -1727,8 +1727,8 @@ public abstract class SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
handshake(clientEngine, serverEngine); handshake(clientEngine, serverEngine);
} finally { } finally {
cleanupClientSslEngine(clientEngine); cleanupClientSslEngine(clientEngine);
@ -1758,8 +1758,8 @@ public abstract class SSLEngineTest {
SSLEngine clientEngine = null; SSLEngine clientEngine = null;
SSLEngine serverEngine = null; SSLEngine serverEngine = null;
try { try {
clientEngine = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); clientEngine = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverEngine = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); serverEngine = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
handshake(clientEngine, serverEngine); handshake(clientEngine, serverEngine);
} finally { } finally {
cleanupClientSslEngine(clientEngine); cleanupClientSslEngine(clientEngine);
@ -1777,13 +1777,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
// Allocate an buffer that is bigger then the max plain record size. // Allocate an buffer that is bigger then the max plain record size.
@ -1816,7 +1816,7 @@ public abstract class SSLEngineTest {
.forClient() .forClient()
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
ByteBuffer src = allocateBuffer(client.getSession().getApplicationBufferSize()); ByteBuffer src = allocateBuffer(client.getSession().getApplicationBufferSize());
@ -1844,7 +1844,7 @@ public abstract class SSLEngineTest {
.forClient() .forClient()
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
client.closeInbound(); client.closeInbound();
@ -1868,13 +1868,13 @@ public abstract class SSLEngineTest {
.forClient() .forClient()
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
testBeginHandshakeCloseOutbound(client); testBeginHandshakeCloseOutbound(client);
@ -1915,13 +1915,13 @@ public abstract class SSLEngineTest {
.forClient() .forClient()
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
testCloseInboundAfterBeginHandshake(client); testCloseInboundAfterBeginHandshake(client);
@ -1952,13 +1952,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
ByteBuffer plainClientOut = allocateBuffer(client.getSession().getApplicationBufferSize()); ByteBuffer plainClientOut = allocateBuffer(client.getSession().getApplicationBufferSize());
@ -2093,13 +2093,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
ByteBuffer dst = allocateBuffer(client.getSession().getPacketBufferSize()); ByteBuffer dst = allocateBuffer(client.getSession().getPacketBufferSize());
@ -2132,13 +2132,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
// Choose buffer size small enough that we can put multiple buffers into one buffer and pass it into the // Choose buffer size small enough that we can put multiple buffers into one buffer and pass it into the
@ -2207,13 +2207,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
ByteBuffer plainClientOut = allocateBuffer(4096); ByteBuffer plainClientOut = allocateBuffer(4096);
@ -2257,13 +2257,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
ByteBuffer plainClient = allocateBuffer(1024); ByteBuffer plainClient = allocateBuffer(1024);
@ -2328,13 +2328,13 @@ public abstract class SSLEngineTest {
.trustManager(cert.cert()) .trustManager(cert.cert())
.sslProvider(sslClientProvider()) .sslProvider(sslClientProvider())
.build(); .build();
SSLEngine client = clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine client = wrapEngine(clientSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
serverSslCtx = SslContextBuilder serverSslCtx = SslContextBuilder
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(serverSslCtx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
ByteBuffer plainServerOut = allocateBuffer(server.getSession().getApplicationBufferSize() / 2); ByteBuffer plainServerOut = allocateBuffer(server.getSession().getApplicationBufferSize() / 2);
@ -2380,7 +2380,7 @@ public abstract class SSLEngineTest {
.forServer(cert.certificate(), cert.privateKey()) .forServer(cert.certificate(), cert.privateKey())
.sslProvider(sslServerProvider()) .sslProvider(sslServerProvider())
.build(); .build();
SSLEngine server = ctx.newEngine(UnpooledByteBufAllocator.DEFAULT); SSLEngine server = wrapEngine(ctx.newEngine(UnpooledByteBufAllocator.DEFAULT));
try { try {
Set<String> supported = new HashSet<String>(Arrays.asList(server.getSupportedProtocols())); Set<String> supported = new HashSet<String>(Arrays.asList(server.getSupportedProtocols()));
@ -2388,10 +2388,10 @@ public abstract class SSLEngineTest {
server.setEnabledProtocols(server.getSupportedProtocols()); server.setEnabledProtocols(server.getSupportedProtocols());
Assert.assertEquals(supported, new HashSet<String>(Arrays.asList(server.getSupportedProtocols()))); Assert.assertEquals(supported, new HashSet<String>(Arrays.asList(server.getSupportedProtocols())));
for (String disabled: disabledProtocols) { for (String disabled : disabledProtocols) {
supported.remove(disabled); supported.remove(disabled);
} }
if (supported.contains(SslUtils.PROTOCOL_SSL_V2_HELLO) && supported.size() == 1) { if (supported.contains(PROTOCOL_SSL_V2_HELLO) && supported.size() == 1) {
// It's not allowed to set only PROTOCOL_SSL_V2_HELLO if using JDK SSLEngine. // It's not allowed to set only PROTOCOL_SSL_V2_HELLO if using JDK SSLEngine.
return; return;
} }
@ -2405,4 +2405,8 @@ public abstract class SSLEngineTest {
cert.delete(); cert.delete();
} }
} }
protected SSLEngine wrapEngine(SSLEngine engine) {
return engine;
}
} }