View Javadoc
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    *   https://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.netty5.handler.ssl;
17  
18  import javax.net.ssl.SSLHandshakeException;
19  import java.util.Collections;
20  import java.util.List;
21  import java.util.Set;
22  
23  import static io.netty5.handler.ssl.ApplicationProtocolUtil.toList;
24  import static java.util.Objects.requireNonNull;
25  
26  /**
27   * Common base class for {@link JdkApplicationProtocolNegotiator} classes to inherit from.
28   */
29  class JdkBaseApplicationProtocolNegotiator implements JdkApplicationProtocolNegotiator {
30      private final List<String> protocols;
31      private final ProtocolSelectorFactory selectorFactory;
32      private final ProtocolSelectionListenerFactory listenerFactory;
33      private final SslEngineWrapperFactory wrapperFactory;
34  
35      /**
36       * Create a new instance.
37       * @param wrapperFactory Determines which application protocol will be used by wrapping the SSLEngine in use.
38       * @param selectorFactory How the peer selecting the protocol should behave.
39       * @param listenerFactory How the peer being notified of the selected protocol should behave.
40       * @param protocols The order of iteration determines the preference of support for protocols.
41       */
42      JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
43              ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
44              Iterable<String> protocols) {
45          this(wrapperFactory, selectorFactory, listenerFactory, toList(protocols));
46      }
47  
48      /**
49       * Create a new instance.
50       * @param wrapperFactory Determines which application protocol will be used by wrapping the SSLEngine in use.
51       * @param selectorFactory How the peer selecting the protocol should behave.
52       * @param listenerFactory How the peer being notified of the selected protocol should behave.
53       * @param protocols The order of iteration determines the preference of support for protocols.
54       */
55      JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
56              ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
57              String... protocols) {
58          this(wrapperFactory, selectorFactory, listenerFactory, toList(protocols));
59      }
60  
61      /**
62       * Create a new instance.
63       * @param wrapperFactory Determines which application protocol will be used by wrapping the SSLEngine in use.
64       * @param selectorFactory How the peer selecting the protocol should behave.
65       * @param listenerFactory How the peer being notified of the selected protocol should behave.
66       * @param protocols The order of iteration determines the preference of support for protocols.
67       */
68      private JdkBaseApplicationProtocolNegotiator(SslEngineWrapperFactory wrapperFactory,
69              ProtocolSelectorFactory selectorFactory, ProtocolSelectionListenerFactory listenerFactory,
70              List<String> protocols) {
71          this.wrapperFactory = requireNonNull(wrapperFactory, "wrapperFactory");
72          this.selectorFactory = requireNonNull(selectorFactory, "selectorFactory");
73          this.listenerFactory = requireNonNull(listenerFactory, "listenerFactory");
74          this.protocols = Collections.unmodifiableList(requireNonNull(protocols, "protocols"));
75      }
76  
77      @Override
78      public List<String> protocols() {
79          return protocols;
80      }
81  
82      @Override
83      public ProtocolSelectorFactory protocolSelectorFactory() {
84          return selectorFactory;
85      }
86  
87      @Override
88      public ProtocolSelectionListenerFactory protocolListenerFactory() {
89          return listenerFactory;
90      }
91  
92      @Override
93      public SslEngineWrapperFactory wrapperFactory() {
94          return wrapperFactory;
95      }
96  
97      static final ProtocolSelectorFactory FAIL_SELECTOR_FACTORY = (engine, supportedProtocols) ->
98              new FailProtocolSelector((JdkSslEngine) engine, supportedProtocols);
99  
100     static final ProtocolSelectorFactory NO_FAIL_SELECTOR_FACTORY = (engine, supportedProtocols) ->
101             new NoFailProtocolSelector((JdkSslEngine) engine, supportedProtocols);
102 
103     static final ProtocolSelectionListenerFactory FAIL_SELECTION_LISTENER_FACTORY = (engine, supportedProtocols) ->
104                     new FailProtocolSelectionListener((JdkSslEngine) engine, supportedProtocols);
105 
106     static final ProtocolSelectionListenerFactory NO_FAIL_SELECTION_LISTENER_FACTORY = (engine, supportedProtocols) ->
107             new NoFailProtocolSelectionListener((JdkSslEngine) engine, supportedProtocols);
108 
109     static class NoFailProtocolSelector implements ProtocolSelector {
110         private final JdkSslEngine engineWrapper;
111         private final Set<String> supportedProtocols;
112 
113         NoFailProtocolSelector(JdkSslEngine engineWrapper, Set<String> supportedProtocols) {
114             this.engineWrapper = engineWrapper;
115             this.supportedProtocols = supportedProtocols;
116         }
117 
118         @Override
119         public void unsupported() {
120             engineWrapper.setNegotiatedApplicationProtocol(null);
121         }
122 
123         @Override
124         public String select(List<String> protocols) throws Exception {
125             for (String p : supportedProtocols) {
126                 if (protocols.contains(p)) {
127                     engineWrapper.setNegotiatedApplicationProtocol(p);
128                     return p;
129                 }
130             }
131             return noSelectMatchFound();
132         }
133 
134         public String noSelectMatchFound() throws Exception {
135             engineWrapper.setNegotiatedApplicationProtocol(null);
136             return null;
137         }
138     }
139 
140     private static final class FailProtocolSelector extends NoFailProtocolSelector {
141         FailProtocolSelector(JdkSslEngine engineWrapper, Set<String> supportedProtocols) {
142             super(engineWrapper, supportedProtocols);
143         }
144 
145         @Override
146         public String noSelectMatchFound() throws Exception {
147             throw new SSLHandshakeException("Selected protocol is not supported");
148         }
149     }
150 
151     private static class NoFailProtocolSelectionListener implements ProtocolSelectionListener {
152         private final JdkSslEngine engineWrapper;
153         private final List<String> supportedProtocols;
154 
155         NoFailProtocolSelectionListener(JdkSslEngine engineWrapper, List<String> supportedProtocols) {
156             this.engineWrapper = engineWrapper;
157             this.supportedProtocols = supportedProtocols;
158         }
159 
160         @Override
161         public void unsupported() {
162             engineWrapper.setNegotiatedApplicationProtocol(null);
163         }
164 
165         @Override
166         public void selected(String protocol) throws Exception {
167             if (supportedProtocols.contains(protocol)) {
168                 engineWrapper.setNegotiatedApplicationProtocol(protocol);
169             } else {
170                 noSelectedMatchFound(protocol);
171             }
172         }
173 
174         protected void noSelectedMatchFound(String protocol) throws Exception {
175             // Will never be called.
176         }
177     }
178 
179     private static final class FailProtocolSelectionListener extends NoFailProtocolSelectionListener {
180         FailProtocolSelectionListener(JdkSslEngine engineWrapper, List<String> supportedProtocols) {
181             super(engineWrapper, supportedProtocols);
182         }
183 
184         @Override
185         protected void noSelectedMatchFound(String protocol) throws Exception {
186             throw new SSLHandshakeException("No compatible protocols found");
187         }
188     }
189 }