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