22
22
*/
23
23
24
24
import cz .seznam .euphoria .shaded .guava .com .google .common .base .Joiner ;
25
+ import io .netty .buffer .ByteBufAllocator ;
25
26
import io .netty .channel .Channel ;
26
27
import io .netty .channel .ChannelHandler ;
27
28
import io .netty .channel .ChannelHandlerContext ;
28
- import io .netty .handler .ssl .ApplicationProtocolConfig ;
29
29
import io .netty .handler .ssl .NotSslRecordException ;
30
30
import io .netty .handler .ssl .SslContext ;
31
31
import io .netty .handler .ssl .SslContextBuilder ;
32
+ import io .netty .handler .ssl .SslHandler ;
32
33
import org .elasticsearch .common .logging .Loggers ;
33
34
import org .elasticsearch .common .network .NetworkService ;
34
35
import org .elasticsearch .common .settings .Settings ;
41
42
import tech .beshu .ror .commons .settings .BasicSettings ;
42
43
import tech .beshu .ror .commons .shims .es .LoggerShim ;
43
44
45
+ import javax .net .ssl .SSLEngine ;
46
+ import javax .net .ssl .SSLHandshakeException ;
44
47
import java .io .ByteArrayInputStream ;
45
48
import java .nio .charset .StandardCharsets ;
46
- import java .util .List ;
47
- import java .util .Optional ;
48
49
49
50
public class SSLTransportNetty4 extends Netty4HttpServerTransport {
50
51
52
+ protected final LoggerShim logger ;
51
53
private final BasicSettings basicSettings ;
52
- private final LoggerShim logger ;
54
+ protected SslContext sslContext ;
55
+
53
56
54
57
public SSLTransportNetty4 (Settings settings , NetworkService networkService , BigArrays bigArrays ,
55
58
ThreadPool threadPool , NamedXContentRegistry xContentRegistry ) {
@@ -62,15 +65,51 @@ public SSLTransportNetty4(Settings settings, NetworkService networkService, BigA
62
65
if (basicSettings .isSSLEnabled ()) {
63
66
logger .info ("creating SSL transport" );
64
67
}
68
+
69
+
70
+ new SSLCertParser (basicSettings , logger , (certChain , privateKey ) -> {
71
+
72
+ try {
73
+ // #TODO expose configuration of sslPrivKeyPem password? Letsencrypt never sets one..
74
+ SslContextBuilder sslcb = SslContextBuilder .forServer (
75
+ new ByteArrayInputStream (certChain .getBytes (StandardCharsets .UTF_8 )),
76
+ new ByteArrayInputStream (privateKey .getBytes (StandardCharsets .UTF_8 )),
77
+ null
78
+ );
79
+
80
+ // Creating one SSL engine just for protocol/cipher validation and logging
81
+ sslContext = sslcb .build ();
82
+ SSLEngine eng = sslContext .newEngine (ByteBufAllocator .DEFAULT );
83
+ String [] defaultProtocols = eng .getEnabledProtocols ();
84
+
85
+ logger .info ("ROR SSL: Using SSL provider: " + SslContext .defaultServerProvider ().name ());
86
+
87
+ logger .info ("ROR SSL: Available ciphers: " + Joiner .on ("," ).join (sslContext .cipherSuites ()));
88
+ baseSettings .getAllowedSSLProtocols ()
89
+ .ifPresent (_x -> logger .info ("ROR SSL: Restricting to ciphers: " + Joiner .on ("," ).join (eng .getEnabledProtocols ())));
90
+
91
+ logger .info ("ROR SSL: Avaliable SSL protocols: " + Joiner .on ("," ).join (defaultProtocols ));
92
+ baseSettings .getAllowedSSLCiphers ()
93
+ .ifPresent (_x -> logger .info ("ROR SSL: Restricting to SSL protocols: " + Joiner .on ("," ).join (eng .getEnabledProtocols ())));
94
+
95
+ logger .info ("ROR SSL: Available ciphers: " + Joiner .on ("," ).join (sslContext .cipherSuites ()));
96
+
97
+ } catch (Exception e ) {
98
+ logger .error ("Failed to load SSL CertChain & private key from Keystore! "
99
+ + e .getClass ().getSimpleName () + ": " + e .getMessage (), e );
100
+ }
101
+ });
65
102
}
66
103
104
+
67
105
protected void exceptionCaught (final ChannelHandlerContext ctx , final Throwable cause ) throws Exception {
68
106
if (!this .lifecycle .started ()) {
69
107
return ;
70
108
}
71
- if (cause .getCause () instanceof NotSslRecordException ) {
109
+ if (cause .getCause () instanceof NotSslRecordException || cause . getCause () instanceof SSLHandshakeException ) {
72
110
logger .warn (cause .getMessage ());
73
111
}
112
+
74
113
else {
75
114
cause .printStackTrace ();
76
115
super .exceptionCaught (ctx , cause );
@@ -80,56 +119,26 @@ protected void exceptionCaught(final ChannelHandlerContext ctx, final Throwable
80
119
81
120
public ChannelHandler configureServerChannelHandler () {
82
121
SSLHandler handler = new SSLHandler (this );
83
- logger .info ("ROR SSL accepted ciphers: " + Joiner .on ("," ).join (handler .context .get ().cipherSuites ()));
84
122
return handler ;
85
123
}
86
124
87
125
private class SSLHandler extends Netty4HttpServerTransport .HttpChannelHandler {
88
- private Optional <SslContext > context = Optional .empty ();
89
126
90
127
SSLHandler (final Netty4HttpServerTransport transport ) {
91
128
super (transport , SSLTransportNetty4 .this .detailedErrorsEnabled , SSLTransportNetty4 .this .threadPool .getThreadContext ());
92
-
93
- new SSLCertParser (basicSettings , logger , (certChain , privateKey ) -> {
94
- try {
95
- // #TODO expose configuration of sslPrivKeyPem password? Letsencrypt never sets one..
96
- SslContextBuilder sslcb = SslContextBuilder .forServer (
97
- new ByteArrayInputStream (certChain .getBytes (StandardCharsets .UTF_8 )),
98
- new ByteArrayInputStream (privateKey .getBytes (StandardCharsets .UTF_8 )),
99
- null
100
- );
101
-
102
- if (basicSettings .getAllowedSSLCiphers ().isPresent ()) {
103
- sslcb .ciphers (basicSettings .getAllowedSSLCiphers ().get ());
104
- }
105
-
106
- if (basicSettings .getAllowedSSLProtocols ().isPresent ()) {
107
- List <String > protocols = basicSettings .getAllowedSSLProtocols ().get ();
108
- sslcb .applicationProtocolConfig (new ApplicationProtocolConfig (
109
- ApplicationProtocolConfig .Protocol .NONE ,
110
- ApplicationProtocolConfig .SelectorFailureBehavior .CHOOSE_MY_LAST_PROTOCOL ,
111
- ApplicationProtocolConfig .SelectedListenerFailureBehavior .ACCEPT ,
112
- protocols
113
- ));
114
-
115
- logger .info ("ROR SSL accepted protocols: " + Joiner .on ("," ).join (protocols ));
116
- }
117
-
118
- context = Optional .of (sslcb .build ());
119
-
120
- } catch (Exception e ) {
121
- context = Optional .empty ();
122
- logger .error ("Failed to load SSL CertChain & private key from Keystore! "
123
- + e .getClass ().getSimpleName () + ": " + e .getMessage (), e );
124
- }
125
- });
126
129
}
127
130
128
131
protected void initChannel (final Channel ch ) throws Exception {
129
132
super .initChannel (ch );
130
- context .ifPresent (sslCtx -> {
131
- ch .pipeline ().addFirst ("ssl_netty4_handler" , sslCtx .newHandler (ch .alloc ()));
132
- });
133
+ SSLEngine eng = sslContext .newEngine (ch .alloc ());
134
+
135
+ basicSettings .getAllowedSSLProtocols ()
136
+ .ifPresent (p -> eng .setEnabledProtocols (p .toArray (new String [p .size ()])));
137
+ basicSettings .getAllowedSSLCiphers ()
138
+ .ifPresent (c -> eng .setEnabledCipherSuites (c .toArray (new String [c .size ()])));
139
+
140
+ ch .pipeline ().addFirst ("ssl_netty4_handler" , new SslHandler (eng ));
141
+
133
142
}
134
143
}
135
144
}
0 commit comments