Skip to content

Commit f8af84d

Browse files
committed
ALPN should allow handshake failure if no compatible protocols found
Motivation: If there are no common protocols in the ALPN protocol exchange we still compete the handshake successfully. This handshake should fail according to http://tools.ietf.org/html/rfc7301#section-3.2 with a status of no_application_protocol. The specification also allows for the server to "play dumb" and not advertise that it supports ALPN in this case (see MAY clauses in http://tools.ietf.org/html/rfc7301#section-3.1) Modifications: -Upstream project used for ALPN (alpn-boot) does not support this. So a PR jetty-project/jetty-alpn#3 was submitted. -The netty code using alpn-boot should support the new interface (return null on existing method). -Version number of alpn-boot must be updated in pom.xml files Result: -Netty fails the SSL handshake if ALPN is used and there are no common protocols.
1 parent 41d9830 commit f8af84d

31 files changed

Lines changed: 1805 additions & 611 deletions

example/src/main/java/io/netty/example/http2/client/Http2Client.java

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,16 @@
2929
import io.netty.handler.codec.http.HttpHeaders;
3030
import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol;
3131
import io.netty.handler.codec.http2.Http2SecurityUtil;
32-
import io.netty.handler.ssl.JettyAlpnSslEngineWrapper;
32+
import io.netty.handler.ssl.ApplicationProtocolConfig;
33+
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
34+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
35+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
3336
import io.netty.handler.ssl.SslContext;
3437
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
3538
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
3639
import io.netty.util.CharsetUtil;
3740

3841
import java.net.URI;
39-
import java.util.Arrays;
4042
import java.util.concurrent.TimeUnit;
4143

4244
/**
@@ -63,8 +65,12 @@ public static void main(String[] args) throws Exception {
6365
/* NOTE: the following filter may not include all ciphers required by the HTTP/2 specification
6466
* Please refer to the HTTP/2 specification for cipher requirements. */
6567
SupportedCipherSuiteFilter.INSTANCE,
66-
Arrays.asList(SelectedProtocol.HTTP_2.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
67-
JettyAlpnSslEngineWrapper.instance(),
68+
new ApplicationProtocolConfig(
69+
Protocol.ALPN,
70+
SelectorFailureBehavior.FATAL_ALERT,
71+
SelectedListenerFailureBehavior.FATAL_ALERT,
72+
SelectedProtocol.HTTP_2.protocolName(),
73+
SelectedProtocol.HTTP_1_1.protocolName()),
6874
0, 0);
6975
} else {
7076
sslCtx = null;

example/src/main/java/io/netty/example/http2/server/Http2Server.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,14 @@
2626
import io.netty.handler.codec.http2.Http2SecurityUtil;
2727
import io.netty.handler.logging.LogLevel;
2828
import io.netty.handler.logging.LoggingHandler;
29-
import io.netty.handler.ssl.JettyAlpnSslEngineWrapper;
29+
import io.netty.handler.ssl.ApplicationProtocolConfig;
30+
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
31+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
32+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
3033
import io.netty.handler.ssl.SslContext;
3134
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
3235
import io.netty.handler.ssl.util.SelfSignedCertificate;
3336

34-
import java.util.Arrays;
35-
3637
/**
3738
* A HTTP/2 Server that responds to requests with a Hello World. Once started, you can test the
3839
* server with the example client.
@@ -53,10 +54,12 @@ public static void main(String[] args) throws Exception {
5354
/* NOTE: the following filter may not include all ciphers required by the HTTP/2 specification
5455
* Please refer to the HTTP/2 specification for cipher requirements. */
5556
SupportedCipherSuiteFilter.INSTANCE,
56-
Arrays.asList(
57+
new ApplicationProtocolConfig(
58+
Protocol.ALPN,
59+
SelectorFailureBehavior.FATAL_ALERT,
60+
SelectedListenerFailureBehavior.FATAL_ALERT,
5761
SelectedProtocol.HTTP_2.protocolName(),
5862
SelectedProtocol.HTTP_1_1.protocolName()),
59-
JettyAlpnSslEngineWrapper.instance(),
6063
0, 0);
6164
} else {
6265
sslCtx = null;

example/src/main/java/io/netty/example/memcache/binary/MemcacheClient.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,20 @@
2424
import io.netty.channel.nio.NioEventLoopGroup;
2525
import io.netty.channel.socket.SocketChannel;
2626
import io.netty.channel.socket.nio.NioSocketChannel;
27-
import io.netty.handler.codec.http2.Http2SecurityUtil;
2827
import io.netty.handler.codec.http2.Http2OrHttpChooser.SelectedProtocol;
28+
import io.netty.handler.codec.http2.Http2SecurityUtil;
2929
import io.netty.handler.codec.memcache.binary.BinaryMemcacheClientCodec;
3030
import io.netty.handler.codec.memcache.binary.BinaryMemcacheObjectAggregator;
31-
import io.netty.handler.ssl.JettyAlpnSslEngineWrapper;
31+
import io.netty.handler.ssl.ApplicationProtocolConfig;
32+
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
33+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
34+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
3235
import io.netty.handler.ssl.SslContext;
3336
import io.netty.handler.ssl.SupportedCipherSuiteFilter;
3437
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
3538

3639
import java.io.BufferedReader;
3740
import java.io.InputStreamReader;
38-
import java.util.Arrays;
3941

4042
/**
4143
* Simple memcache client that demonstrates get and set commands against a memcache server.
@@ -55,8 +57,12 @@ public static void main(String[] args) throws Exception {
5557
/* NOTE: the following filter may not include all ciphers required by the HTTP/2 specification
5658
* Please refer to the HTTP/2 specification for cipher requirements. */
5759
SupportedCipherSuiteFilter.INSTANCE,
58-
Arrays.asList(SelectedProtocol.HTTP_2.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
59-
JettyAlpnSslEngineWrapper.instance(),
60+
new ApplicationProtocolConfig(
61+
Protocol.ALPN,
62+
SelectorFailureBehavior.FATAL_ALERT,
63+
SelectedListenerFailureBehavior.FATAL_ALERT,
64+
SelectedProtocol.HTTP_2.protocolName(),
65+
SelectedProtocol.HTTP_1_1.protocolName()),
6066
0, 0);
6167
} else {
6268
sslCtx = null;

example/src/main/java/io/netty/example/spdy/client/SpdyClient.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,14 @@
2727
import io.netty.handler.codec.http.HttpRequest;
2828
import io.netty.handler.codec.http.HttpVersion;
2929
import io.netty.handler.codec.spdy.SpdyOrHttpChooser.SelectedProtocol;
30+
import io.netty.handler.ssl.ApplicationProtocolConfig;
31+
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
32+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
33+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
3034
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
31-
import io.netty.handler.ssl.JettyNpnSslEngineWrapper;
3235
import io.netty.handler.ssl.SslContext;
3336
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
3437

35-
import java.util.Arrays;
36-
3738
/**
3839
* An SPDY client that allows you to send HTTP GET to a SPDY server.
3940
* <p>
@@ -57,8 +58,12 @@ public static void main(String[] args) throws Exception {
5758
// Configure SSL.
5859
final SslContext sslCtx = SslContext.newClientContext(
5960
null, InsecureTrustManagerFactory.INSTANCE, null, IdentityCipherSuiteFilter.INSTANCE,
60-
Arrays.asList(SelectedProtocol.SPDY_3_1.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
61-
JettyNpnSslEngineWrapper.instance(),
61+
new ApplicationProtocolConfig(
62+
Protocol.NPN,
63+
SelectorFailureBehavior.FATAL_ALERT,
64+
SelectedListenerFailureBehavior.FATAL_ALERT,
65+
SelectedProtocol.SPDY_3_1.protocolName(),
66+
SelectedProtocol.HTTP_1_1.protocolName()),
6267
0, 0);
6368

6469
HttpResponseClientHandler httpResponseHandler = new HttpResponseClientHandler();

example/src/main/java/io/netty/example/spdy/server/SpdyServer.java

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,14 @@
2424
import io.netty.handler.codec.spdy.SpdyOrHttpChooser.SelectedProtocol;
2525
import io.netty.handler.logging.LogLevel;
2626
import io.netty.handler.logging.LoggingHandler;
27+
import io.netty.handler.ssl.ApplicationProtocolConfig;
28+
import io.netty.handler.ssl.ApplicationProtocolConfig.Protocol;
29+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectedListenerFailureBehavior;
30+
import io.netty.handler.ssl.ApplicationProtocolConfig.SelectorFailureBehavior;
2731
import io.netty.handler.ssl.IdentityCipherSuiteFilter;
28-
import io.netty.handler.ssl.JettyNpnSslEngineWrapper;
2932
import io.netty.handler.ssl.SslContext;
3033
import io.netty.handler.ssl.util.SelfSignedCertificate;
3134

32-
import java.util.Arrays;
33-
3435
/**
3536
* A SPDY Server that responds to a GET request with a Hello World.
3637
* <p>
@@ -58,8 +59,12 @@ public static void main(String[] args) throws Exception {
5859
SelfSignedCertificate ssc = new SelfSignedCertificate();
5960
SslContext sslCtx = SslContext.newServerContext(
6061
ssc.certificate(), ssc.privateKey(), null, null, IdentityCipherSuiteFilter.INSTANCE,
61-
Arrays.asList(SelectedProtocol.SPDY_3_1.protocolName(), SelectedProtocol.HTTP_1_1.protocolName()),
62-
JettyNpnSslEngineWrapper.instance(),
62+
new ApplicationProtocolConfig(
63+
Protocol.NPN,
64+
SelectorFailureBehavior.FATAL_ALERT,
65+
SelectedListenerFailureBehavior.FATAL_ALERT,
66+
SelectedProtocol.SPDY_3_1.protocolName(),
67+
SelectedProtocol.HTTP_1_1.protocolName()),
6368
0, 0);
6469

6570
// Configure the server.
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/*
2+
* Copyright 2014 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. 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, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.ssl;
17+
18+
import static io.netty.handler.ssl.ApplicationProtocolUtil.toList;
19+
import static io.netty.util.internal.ObjectUtil.checkNotNull;
20+
21+
import java.util.Collections;
22+
import java.util.List;
23+
24+
import javax.net.ssl.SSLEngine;
25+
26+
/**
27+
* Provides an {@link SSLEngine} agnostic way to configure a {@link ApplicationProtocolNegotiator}.
28+
*/
29+
public final class ApplicationProtocolConfig {
30+
private final List<String> supportedProtocols;
31+
private final Protocol protocol;
32+
private final SelectorFailureBehavior selectorBehavior;
33+
private final SelectedListenerFailureBehavior selectedBehavior;
34+
35+
/**
36+
* Create a new instance.
37+
* @param protocol The application protocol functionality to use.
38+
* @param selectorBehavior How the peer selecting the protocol should behave.
39+
* @param selectedBehavior How the peer being notified of the selected protocol should behave.
40+
* @param supportedProtocols The order of iteration determines the preference of support for protocols.
41+
*/
42+
public ApplicationProtocolConfig(Protocol protocol, SelectorFailureBehavior selectorBehavior,
43+
SelectedListenerFailureBehavior selectedBehavior, Iterable<String> supportedProtocols) {
44+
this(protocol, selectorBehavior, selectedBehavior, toList(supportedProtocols));
45+
}
46+
47+
/**
48+
* Create a new instance.
49+
* @param protocol The application protocol functionality to use.
50+
* @param selectorBehavior How the peer selecting the protocol should behave.
51+
* @param selectedBehavior How the peer being notified of the selected protocol should behave.
52+
* @param supportedProtocols The order of iteration determines the preference of support for protocols.
53+
*/
54+
public ApplicationProtocolConfig(Protocol protocol, SelectorFailureBehavior selectorBehavior,
55+
SelectedListenerFailureBehavior selectedBehavior, String... supportedProtocols) {
56+
this(protocol, selectorBehavior, selectedBehavior, toList(supportedProtocols));
57+
}
58+
59+
/**
60+
* Create a new instance.
61+
* @param protocol The application protocol functionality to use.
62+
* @param selectorBehavior How the peer selecting the protocol should behave.
63+
* @param selectedBehavior How the peer being notified of the selected protocol should behave.
64+
* @param supportedProtocols The order of iteration determines the preference of support for protocols.
65+
*/
66+
private ApplicationProtocolConfig(Protocol protocol, SelectorFailureBehavior selectorBehavior,
67+
SelectedListenerFailureBehavior selectedBehavior, List<String> supportedProtocols) {
68+
this.supportedProtocols = Collections.unmodifiableList(checkNotNull(supportedProtocols, "supportedProtocols"));
69+
this.protocol = checkNotNull(protocol, "protocol");
70+
this.selectorBehavior = checkNotNull(selectorBehavior, "selectorBehavior");
71+
this.selectedBehavior = checkNotNull(selectedBehavior, "selectedBehavior");
72+
}
73+
74+
/**
75+
* Defines which application level protocol negotiation to use.
76+
*/
77+
public enum Protocol {
78+
NONE, NPN, ALPN, NPN_AND_ALPN
79+
}
80+
81+
/**
82+
* Defines the most common behaviors for the peer that selects the application protocol.
83+
*/
84+
public enum SelectorFailureBehavior {
85+
FATAL_ALERT, NO_ADVERTISE, CHOOSE_MY_LAST_PROTOCOL
86+
}
87+
88+
/**
89+
* Defines the most common behaviors for the peer which is notified of the selected protocol.
90+
*/
91+
public enum SelectedListenerFailureBehavior {
92+
ACCEPT, FATAL_ALERT, CHOOSE_MY_LAST_PROTOCOL
93+
}
94+
95+
/**
96+
* The application level protocols supported.
97+
*/
98+
public List<String> supportedProtocols() {
99+
return supportedProtocols;
100+
}
101+
102+
/**
103+
* Get which application level protocol negotiation to use.
104+
*/
105+
public Protocol protocol() {
106+
return protocol;
107+
}
108+
109+
/**
110+
* Get the desired behavior for the peer who selects the application protocol.
111+
*/
112+
public SelectorFailureBehavior selectorFailureBehavior() {
113+
return selectorBehavior;
114+
}
115+
116+
/**
117+
* Get the desired behavior for the peer who is notified of the selected protocol.
118+
*/
119+
public SelectedListenerFailureBehavior selectedListenerFailureBehavior() {
120+
return selectedBehavior;
121+
}
122+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2014 The Netty Project
3+
*
4+
* The Netty Project licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. 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, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
package io.netty.handler.ssl;
17+
18+
import java.util.List;
19+
20+
/**
21+
* Interface to support Application Protocol Negotiation.
22+
* <p>
23+
* Default implementations are provided for:
24+
* <ul>
25+
* <li><a href="https://technotes.googlecode.com/git/nextprotoneg.html">Next Protocol Negotiation</a></li>
26+
* <li><a href="http://tools.ietf.org/html/rfc7301">Application-Layer Protocol Negotiation</a></li>
27+
* </ul>
28+
*/
29+
public interface ApplicationProtocolNegotiator {
30+
/**
31+
* Get the collection of application protocols supported by this application (in preference order).
32+
*/
33+
List<String> protocols();
34+
}

0 commit comments

Comments
 (0)