1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.ssl;
17
18 import io.netty.buffer.ByteBufUtil;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.channel.ChannelInboundHandlerAdapter;
21 import io.netty.util.internal.ReflectionUtil;
22 import io.netty.util.internal.SystemPropertyUtil;
23 import io.netty.util.internal.logging.InternalLogger;
24 import io.netty.util.internal.logging.InternalLoggerFactory;
25
26 import javax.crypto.SecretKey;
27 import javax.crypto.spec.SecretKeySpec;
28 import javax.net.ssl.SSLEngine;
29 import javax.net.ssl.SSLSession;
30 import java.lang.reflect.Field;
31
32
33
34
35
36
37
38 public abstract class SslMasterKeyHandler extends ChannelInboundHandlerAdapter {
39
40 private static final InternalLogger logger = InternalLoggerFactory.getInstance(SslMasterKeyHandler.class);
41
42
43
44
45 private static final Class<?> SSL_SESSIONIMPL_CLASS;
46
47
48
49
50 private static final Field SSL_SESSIONIMPL_MASTER_SECRET_FIELD;
51
52
53
54
55
56
57 public static final String SYSTEM_PROP_KEY = "io.netty.ssl.masterKeyHandler";
58
59
60
61
62 private static final Throwable UNAVAILABILITY_CAUSE;
63
64 static {
65 Throwable cause;
66 Class<?> clazz = null;
67 Field field = null;
68 try {
69 clazz = Class.forName("sun.security.ssl.SSLSessionImpl");
70 field = clazz.getDeclaredField("masterSecret");
71 cause = ReflectionUtil.trySetAccessible(field, true);
72 } catch (Throwable e) {
73 cause = e;
74 if (logger.isTraceEnabled()) {
75 logger.debug("sun.security.ssl.SSLSessionImpl is unavailable.", e);
76 } else {
77 logger.debug("sun.security.ssl.SSLSessionImpl is unavailable: {}", e.getMessage());
78 }
79 }
80 UNAVAILABILITY_CAUSE = cause;
81 SSL_SESSIONIMPL_CLASS = clazz;
82 SSL_SESSIONIMPL_MASTER_SECRET_FIELD = field;
83 }
84
85
86
87
88 protected SslMasterKeyHandler() {
89 }
90
91
92
93
94
95 public static void ensureSunSslEngineAvailability() {
96 if (UNAVAILABILITY_CAUSE != null) {
97 throw new IllegalStateException(
98 "Failed to find SSLSessionImpl on classpath", UNAVAILABILITY_CAUSE);
99 }
100 }
101
102
103
104
105
106
107 public static Throwable sunSslEngineUnavailabilityCause() {
108 return UNAVAILABILITY_CAUSE;
109 }
110
111
112
113 public static boolean isSunSslEngineAvailable() {
114 return UNAVAILABILITY_CAUSE == null;
115 }
116
117
118
119
120
121
122 protected abstract void accept(SecretKey masterKey, SSLSession session);
123
124 @Override
125 public final void userEventTriggered(ChannelHandlerContext ctx, Object evt) {
126
127 if (evt == SslHandshakeCompletionEvent.SUCCESS && masterKeyHandlerEnabled()) {
128 final SslHandler handler = ctx.pipeline().get(SslHandler.class);
129 final SSLEngine engine = handler.engine();
130 final SSLSession sslSession = engine.getSession();
131
132
133 if (isSunSslEngineAvailable() && sslSession.getClass().equals(SSL_SESSIONIMPL_CLASS)) {
134 final SecretKey secretKey;
135 try {
136 secretKey = (SecretKey) SSL_SESSIONIMPL_MASTER_SECRET_FIELD.get(sslSession);
137 } catch (IllegalAccessException e) {
138 throw new IllegalArgumentException("Failed to access the field 'masterSecret' " +
139 "via reflection.", e);
140 }
141 accept(secretKey, sslSession);
142 } else if (OpenSsl.isAvailable() && engine instanceof ReferenceCountedOpenSslEngine) {
143 SecretKeySpec secretKey = ((ReferenceCountedOpenSslEngine) engine).masterKey();
144 accept(secretKey, sslSession);
145 }
146 }
147
148 ctx.fireUserEventTriggered(evt);
149 }
150
151
152
153
154
155
156
157
158 protected boolean masterKeyHandlerEnabled() {
159 return SystemPropertyUtil.getBoolean(SYSTEM_PROP_KEY, false);
160 }
161
162
163
164
165
166
167
168
169 public static SslMasterKeyHandler newWireSharkSslMasterKeyHandler() {
170 return new WiresharkSslMasterKeyHandler();
171 }
172
173
174
175
176
177
178
179
180
181
182 private static final class WiresharkSslMasterKeyHandler extends SslMasterKeyHandler {
183
184 private static final InternalLogger wireshark_logger =
185 InternalLoggerFactory.getInstance("io.netty.wireshark");
186
187 @Override
188 protected void accept(SecretKey masterKey, SSLSession session) {
189 if (masterKey.getEncoded().length != 48) {
190 throw new IllegalArgumentException("An invalid length master key was provided.");
191 }
192 final byte[] sessionId = session.getId();
193 wireshark_logger.warn("RSA Session-ID:{} Master-Key:{}",
194 ByteBufUtil.hexDump(sessionId).toLowerCase(),
195 ByteBufUtil.hexDump(masterKey.getEncoded()).toLowerCase());
196 }
197 }
198
199 }