1 /* 2 * Copyright 2017 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 package org.conscrypt; 17 18 import static io.netty.handler.ssl.SslProvider.OPENSSL; 19 import static io.netty.handler.ssl.SslProvider.OPENSSL_REFCNT; 20 import static org.conscrypt.TestUtils.initClientSslContext; 21 import static org.conscrypt.TestUtils.initServerSslContext; 22 23 import io.netty.buffer.PooledByteBufAllocator; 24 import io.netty.handler.ssl.ApplicationProtocolConfig; 25 import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol; 26 import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior; 27 import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior; 28 import io.netty.handler.ssl.ApplicationProtocolNames; 29 import io.netty.handler.ssl.SslContext; 30 import io.netty.handler.ssl.SslContextBuilder; 31 import io.netty.util.ReferenceCountUtil; 32 import java.security.KeyStore.PrivateKeyEntry; 33 import java.security.NoSuchAlgorithmException; 34 import java.security.cert.X509Certificate; 35 import javax.net.ssl.SSLContext; 36 import javax.net.ssl.SSLEngine; 37 import javax.net.ssl.SSLException; 38 import org.conscrypt.java.security.TestKeyStore; 39 40 final class OpenJdkEngineFactoryConfig { OpenJdkEngineFactoryConfig()41 private OpenJdkEngineFactoryConfig() {} 42 43 static final ApplicationProtocolConfig NETTY_ALPN_CONFIG = 44 new ApplicationProtocolConfig(Protocol.ALPN, SelectorFailureBehavior.NO_ADVERTISE, 45 SelectedListenerFailureBehavior.ACCEPT, ApplicationProtocolNames.HTTP_2); 46 static final String PROTOCOL = "TLSv1.2"; 47 } 48 49 /** 50 * Enumeration of various types of engines for use with engine-based benchmarks. 51 */ 52 @SuppressWarnings({"ImmutableEnumChecker", "unused"}) 53 public enum OpenJdkEngineFactory implements EngineFactory { 54 JDK { 55 private final SSLContext clientContext = initClientSslContext(newContext()); 56 private final SSLContext serverContext = initServerSslContext(newContext()); 57 58 @Override newClientEngine(String cipher, boolean useAlpn)59 public SSLEngine newClientEngine(String cipher, boolean useAlpn) { 60 if (useAlpn) { 61 throw new UnsupportedOperationException("ALPN not supported for JDK"); 62 } 63 return initEngine(clientContext.createSSLEngine(), cipher, true); 64 } 65 66 @Override newServerEngine(String cipher, boolean useAlpn)67 public SSLEngine newServerEngine(String cipher, boolean useAlpn) { 68 if (useAlpn) { 69 throw new UnsupportedOperationException("ALPN not supported for JDK"); 70 } 71 return initEngine(serverContext.createSSLEngine(), cipher, false); 72 } 73 newContext()74 private SSLContext newContext() { 75 try { 76 return SSLContext.getInstance(OpenJdkEngineFactoryConfig.PROTOCOL); 77 } catch (NoSuchAlgorithmException e) { 78 throw new RuntimeException(e); 79 } 80 } 81 }, 82 CONSCRYPT_UNPOOLED { 83 private final SSLContext clientContext = newConscryptClientContext(); 84 private final SSLContext serverContext = newConscryptServerContext(); 85 86 @Override newClientEngine(String cipher, boolean useAlpn)87 public SSLEngine newClientEngine(String cipher, boolean useAlpn) { 88 SSLEngine engine = initEngine(clientContext.createSSLEngine(), cipher, true); 89 if (useAlpn) { 90 Conscrypt.setApplicationProtocols(engine, new String[] {ApplicationProtocolNames.HTTP_2}); 91 } 92 return engine; 93 } 94 95 @Override newServerEngine(String cipher, boolean useAlpn)96 public SSLEngine newServerEngine(String cipher, boolean useAlpn) { 97 SSLEngine engine = initEngine(serverContext.createSSLEngine(), cipher, false); 98 if (useAlpn) { 99 Conscrypt.setApplicationProtocols(engine, new String[] {ApplicationProtocolNames.HTTP_2}); 100 } 101 return engine; 102 } 103 newContext()104 private SSLContext newContext() { 105 try { 106 return SSLContext.getInstance( 107 OpenJdkEngineFactoryConfig.PROTOCOL, new OpenSSLProvider()); 108 } catch (NoSuchAlgorithmException e) { 109 throw new RuntimeException(e); 110 } 111 } 112 }, 113 CONSCRYPT_POOLED { 114 private final SSLContext clientContext = newConscryptClientContext(); 115 private final SSLContext serverContext = newConscryptServerContext(); 116 117 @Override newClientEngine(String cipher, boolean useAlpn)118 public SSLEngine newClientEngine(String cipher, boolean useAlpn) { 119 SSLEngine engine = initEngine(clientContext.createSSLEngine(), cipher, true); 120 Conscrypt.setBufferAllocator(engine, NettyBufferAllocator.getInstance()); 121 if (useAlpn) { 122 Conscrypt.setApplicationProtocols(engine, new String[] {ApplicationProtocolNames.HTTP_2}); 123 } 124 return engine; 125 } 126 127 @Override newServerEngine(String cipher, boolean useAlpn)128 public SSLEngine newServerEngine(String cipher, boolean useAlpn) { 129 SSLEngine engine = initEngine(serverContext.createSSLEngine(), cipher, false); 130 Conscrypt.setBufferAllocator(engine, NettyBufferAllocator.getInstance()); 131 if (useAlpn) { 132 Conscrypt.setApplicationProtocols(engine, new String[] {ApplicationProtocolNames.HTTP_2}); 133 } 134 return engine; 135 } 136 newContext()137 private SSLContext newContext() { 138 try { 139 return SSLContext.getInstance( 140 OpenJdkEngineFactoryConfig.PROTOCOL, new OpenSSLProvider()); 141 } catch (NoSuchAlgorithmException e) { 142 throw new RuntimeException(e); 143 } 144 } 145 }, 146 NETTY { 147 private final SslContext clientContext = newNettyClientContext(OPENSSL, false); 148 private final SslContext clientContextAlpn = newNettyClientContext(OPENSSL, true); 149 private final SslContext serverContext = newNettyServerContext(OPENSSL, false); 150 private final SslContext serverContextAlpn = newNettyServerContext(OPENSSL, true); 151 152 @Override newClientEngine(String cipher, boolean useAlpn)153 public SSLEngine newClientEngine(String cipher, boolean useAlpn) { 154 return initEngine( 155 clientContext(useAlpn).newEngine(PooledByteBufAllocator.DEFAULT), cipher, true); 156 } 157 158 @Override newServerEngine(String cipher, boolean useAlpn)159 public SSLEngine newServerEngine(String cipher, boolean useAlpn) { 160 return initEngine(serverContext(useAlpn).newEngine(PooledByteBufAllocator.DEFAULT), 161 cipher, false); 162 } 163 clientContext(boolean useAlpn)164 private SslContext clientContext(boolean useAlpn) { 165 return useAlpn ? clientContextAlpn : clientContext; 166 } 167 serverContext(boolean useAlpn)168 private SslContext serverContext(boolean useAlpn) { 169 return useAlpn ? serverContextAlpn : serverContext; 170 } 171 172 @Override dispose(SSLEngine engine)173 public void dispose(SSLEngine engine) { 174 super.dispose(engine); 175 ReferenceCountUtil.release(engine); 176 } 177 }, 178 NETTY_REF_CNT { 179 private final SslContext clientContext = newNettyClientContext(OPENSSL_REFCNT, false); 180 private final SslContext clientContextAlpn = newNettyClientContext(OPENSSL_REFCNT, true); 181 private final SslContext serverContext = newNettyServerContext(OPENSSL_REFCNT, false); 182 private final SslContext serverContextAlpn = newNettyServerContext(OPENSSL_REFCNT, true); 183 184 @Override newClientEngine(String cipher, boolean useAlpn)185 public SSLEngine newClientEngine(String cipher, boolean useAlpn) { 186 return initEngine( 187 clientContext(useAlpn).newEngine(PooledByteBufAllocator.DEFAULT), cipher, true); 188 } 189 190 @Override newServerEngine(String cipher, boolean useAlpn)191 public SSLEngine newServerEngine(String cipher, boolean useAlpn) { 192 return initEngine(serverContext(useAlpn).newEngine(PooledByteBufAllocator.DEFAULT), 193 cipher, false); 194 } 195 196 @Override dispose(SSLEngine engine)197 public void dispose(SSLEngine engine) { 198 super.dispose(engine); 199 ReferenceCountUtil.release(engine); 200 } 201 clientContext(boolean useAlpn)202 private SslContext clientContext(boolean useAlpn) { 203 return useAlpn ? clientContextAlpn : clientContext; 204 } 205 serverContext(boolean useAlpn)206 private SslContext serverContext(boolean useAlpn) { 207 return useAlpn ? serverContextAlpn : serverContext; 208 } 209 }; 210 211 @Override dispose(SSLEngine engine)212 public void dispose(SSLEngine engine) { 213 engine.closeOutbound(); 214 } 215 newConscryptClientContext()216 private static SSLContext newConscryptClientContext() { 217 return TestUtils.newClientSslContext(TestUtils.getConscryptProvider()); 218 } 219 newConscryptServerContext()220 private static SSLContext newConscryptServerContext() { 221 return TestUtils.newServerSslContext(TestUtils.getConscryptProvider()); 222 } 223 newNettyClientContext( io.netty.handler.ssl.SslProvider sslProvider, boolean useAlpn)224 private static SslContext newNettyClientContext( 225 io.netty.handler.ssl.SslProvider sslProvider, boolean useAlpn) { 226 try { 227 TestKeyStore server = TestKeyStore.getServer(); 228 SslContextBuilder ctx = 229 SslContextBuilder.forClient() 230 .sslProvider(sslProvider) 231 .trustManager((X509Certificate[]) server.getPrivateKey("RSA", "RSA") 232 .getCertificateChain()); 233 if (useAlpn) { 234 ctx.applicationProtocolConfig(OpenJdkEngineFactoryConfig.NETTY_ALPN_CONFIG); 235 } 236 return ctx.build(); 237 } catch (SSLException e) { 238 throw new RuntimeException(e); 239 } 240 } 241 newNettyServerContext( io.netty.handler.ssl.SslProvider sslProvider, boolean useAlpn)242 private static SslContext newNettyServerContext( 243 io.netty.handler.ssl.SslProvider sslProvider, boolean useAlpn) { 244 try { 245 PrivateKeyEntry server = TestKeyStore.getServer().getPrivateKey("RSA", "RSA"); 246 SslContextBuilder ctx = 247 SslContextBuilder 248 .forServer(server.getPrivateKey(), 249 (X509Certificate[]) server.getCertificateChain()) 250 .sslProvider(sslProvider); 251 if (useAlpn) { 252 ctx.applicationProtocolConfig(OpenJdkEngineFactoryConfig.NETTY_ALPN_CONFIG); 253 } 254 return ctx.build(); 255 } catch (SSLException e) { 256 throw new RuntimeException(e); 257 } 258 } 259 initEngine(SSLEngine engine, String cipher, boolean client)260 static SSLEngine initEngine(SSLEngine engine, String cipher, boolean client) { 261 engine.setEnabledProtocols(new String[]{OpenJdkEngineFactoryConfig.PROTOCOL}); 262 engine.setEnabledCipherSuites(new String[] {cipher}); 263 engine.setUseClientMode(client); 264 return engine; 265 } 266 } 267