1 /* 2 * Copyright 2015 The gRPC Authors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package io.grpc.netty; 18 19 import java.lang.reflect.Method; 20 import java.security.AccessController; 21 import java.security.PrivilegedExceptionAction; 22 import javax.net.ssl.SSLContext; 23 import javax.net.ssl.SSLEngine; 24 25 /** 26 * Utility class for determining support for Jetty TLS ALPN/NPN. 27 */ 28 final class JettyTlsUtil { JettyTlsUtil()29 private JettyTlsUtil() { 30 } 31 32 private static Throwable jettyAlpnUnavailabilityCause; 33 private static Throwable jettyNpnUnavailabilityCause; 34 35 private static class Java9AlpnUnavailabilityCauseHolder { 36 37 static final Throwable cause = checkAlpnAvailability(); 38 checkAlpnAvailability()39 static Throwable checkAlpnAvailability() { 40 try { 41 SSLContext context = SSLContext.getInstance("TLS"); 42 context.init(null, null, null); 43 SSLEngine engine = context.createSSLEngine(); 44 Method getApplicationProtocol = 45 AccessController.doPrivileged(new PrivilegedExceptionAction<Method>() { 46 @Override 47 public Method run() throws Exception { 48 return SSLEngine.class.getMethod("getApplicationProtocol"); 49 } 50 }); 51 getApplicationProtocol.invoke(engine); 52 return null; 53 } catch (Throwable t) { 54 return t; 55 } 56 } 57 } 58 59 /** 60 * Indicates whether or not the Jetty ALPN jar is installed in the boot classloader. 61 */ isJettyAlpnConfigured()62 static synchronized boolean isJettyAlpnConfigured() { 63 try { 64 Class.forName("org.eclipse.jetty.alpn.ALPN", true, null); 65 return true; 66 } catch (ClassNotFoundException e) { 67 jettyAlpnUnavailabilityCause = e; 68 return false; 69 } 70 } 71 getJettyAlpnUnavailabilityCause()72 static synchronized Throwable getJettyAlpnUnavailabilityCause() { 73 // This case should be unlikely 74 if (jettyAlpnUnavailabilityCause == null) { 75 boolean discard = isJettyAlpnConfigured(); 76 } 77 return jettyAlpnUnavailabilityCause; 78 } 79 80 /** 81 * Indicates whether or not the Jetty NPN jar is installed in the boot classloader. 82 */ isJettyNpnConfigured()83 static synchronized boolean isJettyNpnConfigured() { 84 try { 85 Class.forName("org.eclipse.jetty.npn.NextProtoNego", true, null); 86 return true; 87 } catch (ClassNotFoundException e) { 88 jettyNpnUnavailabilityCause = e; 89 return false; 90 } 91 } 92 getJettyNpnUnavailabilityCause()93 static synchronized Throwable getJettyNpnUnavailabilityCause() { 94 // This case should be unlikely 95 if (jettyNpnUnavailabilityCause == null) { 96 boolean discard = isJettyNpnConfigured(); 97 } 98 return jettyNpnUnavailabilityCause; 99 } 100 101 /** 102 * Indicates whether Java 9 ALPN is available. 103 */ isJava9AlpnAvailable()104 static boolean isJava9AlpnAvailable() { 105 return getJava9AlpnUnavailabilityCause() == null; 106 } 107 getJava9AlpnUnavailabilityCause()108 static Throwable getJava9AlpnUnavailabilityCause() { 109 return Java9AlpnUnavailabilityCauseHolder.cause; 110 } 111 } 112