1 module hunt.net.ssl.SSLParameters;
2 
3 
4 import hunt.Exceptions;
5 import hunt.collection;
6 
7 import std.conv;
8 
9 /**
10  * Encapsulates parameters for an SSL/TLS connection. The parameters
11  * are the list of ciphersuites to be accepted in an SSL/TLS handshake,
12  * the list of protocols to be allowed, the endpoint identification
13  * algorithm during SSL/TLS handshaking, the Server Name Indication (SNI),
14  * the algorithm constraints and whether SSL/TLS servers should request
15  * or require client authentication, etc.
16  * <p>
17  * SSLParameters can be created via the constructors in this class.
18  * Objects can also be obtained using the <code>getSSLParameters()</code>
19  * methods in
20  * {@link SSLSocket#getSSLParameters SSLSocket} and
21  * {@link SSLServerSocket#getSSLParameters SSLServerSocket} and
22  * {@link SSLEngine#getSSLParameters SSLEngine} or the
23  * {@link SSLContext#getDefaultSSLParameters getDefaultSSLParameters()} and
24  * {@link SSLContext#getSupportedSSLParameters getSupportedSSLParameters()}
25  * methods in <code>SSLContext</code>.
26  * <p>
27  * SSLParameters can be applied to a connection via the methods
28  * {@link SSLSocket#setSSLParameters SSLSocket.setSSLParameters()} and
29  * {@link SSLServerSocket#setSSLParameters SSLServerSocket.setSSLParameters()}
30  * and {@link SSLEngine#setSSLParameters SSLEngine.setSSLParameters()}.
31  *
32  * @see SSLSocket
33  * @see SSLEngine
34  * @see SSLContext
35  *
36  */
37 class SSLParameters {
38 
39     private string[] cipherSuites;
40     private string[] protocols;
41     private bool wantClientAuth;
42     private bool needClientAuth;
43     private string identificationAlgorithm;
44     // private Map!(int, SNIServerName) sniNames = null;
45     // private Map!(int, SNIMatcher) sniMatchers = null;
46     private bool preferLocalCipherSuites;
47 
48     /**
49      * Constructs SSLParameters.
50      * <p>
51      * The values of cipherSuites, protocols, cryptographic algorithm
52      * constraints, endpoint identification algorithm, server names and
53      * server name matchers are set to <code>null</code>, useCipherSuitesOrder,
54      * wantClientAuth and needClientAuth are set to <code>false</code>.
55      */
56     this() {
57         // empty
58     }
59 
60     /**
61      * Constructs SSLParameters from the specified array of ciphersuites.
62      * <p>
63      * Calling this constructor is equivalent to calling the no-args
64      * constructor followed by
65      * <code>setCipherSuites(cipherSuites);</code>.
66      *
67      * @param cipherSuites the array of ciphersuites (or null)
68      */
69     this(string[] cipherSuites) {
70         setCipherSuites(cipherSuites);
71     }
72 
73     /**
74      * Constructs SSLParameters from the specified array of ciphersuites
75      * and protocols.
76      * <p>
77      * Calling this constructor is equivalent to calling the no-args
78      * constructor followed by
79      * <code>setCipherSuites(cipherSuites); setProtocols(protocols);</code>.
80      *
81      * @param cipherSuites the array of ciphersuites (or null)
82      * @param protocols the array of protocols (or null)
83      */
84     this(string[] cipherSuites, string[] protocols) {
85         setCipherSuites(cipherSuites);
86         setProtocols(protocols);
87     }
88 
89     private static string[] clone(string[] s) {
90         return (s is null) ? null : s.dup;
91     }
92 
93     /**
94      * Returns a copy of the array of ciphersuites or null if none
95      * have been set.
96      *
97      * @return a copy of the array of ciphersuites or null if none
98      * have been set.
99      */
100     string[] getCipherSuites() {
101         return clone(cipherSuites);
102     }
103 
104     /**
105      * Sets the array of ciphersuites.
106      *
107      * @param cipherSuites the array of ciphersuites (or null)
108      */
109     void setCipherSuites(string[] cipherSuites) {
110         this.cipherSuites = clone(cipherSuites);
111     }
112 
113     /**
114      * Returns a copy of the array of protocols or null if none
115      * have been set.
116      *
117      * @return a copy of the array of protocols or null if none
118      * have been set.
119      */
120     string[] getProtocols() {
121         return clone(protocols);
122     }
123 
124     /**
125      * Sets the array of protocols.
126      *
127      * @param protocols the array of protocols (or null)
128      */
129     void setProtocols(string[] protocols) {
130         this.protocols = clone(protocols);
131     }
132 
133     /**
134      * Returns whether client authentication should be requested.
135      *
136      * @return whether client authentication should be requested.
137      */
138     bool getWantClientAuth() {
139         return wantClientAuth;
140     }
141 
142     /**
143      * Sets whether client authentication should be requested. Calling
144      * this method clears the <code>needClientAuth</code> flag.
145      *
146      * @param wantClientAuth whether client authentication should be requested
147      */
148     void setWantClientAuth(bool wantClientAuth) {
149         this.wantClientAuth = wantClientAuth;
150         this.needClientAuth = false;
151     }
152 
153     /**
154      * Returns whether client authentication should be required.
155      *
156      * @return whether client authentication should be required.
157      */
158     bool getNeedClientAuth() {
159         return needClientAuth;
160     }
161 
162     /**
163      * Sets whether client authentication should be required. Calling
164      * this method clears the <code>wantClientAuth</code> flag.
165      *
166      * @param needClientAuth whether client authentication should be required
167      */
168     void setNeedClientAuth(bool needClientAuth) {
169         this.wantClientAuth = false;
170         this.needClientAuth = needClientAuth;
171     }
172 
173     /**
174      * Returns the cryptographic algorithm constraints.
175      *
176      * @return the cryptographic algorithm constraints, or null if the
177      *     constraints have not been set
178      *
179      * @see #setAlgorithmConstraints(AlgorithmConstraints)
180      *
181      */
182     // AlgorithmConstraints getAlgorithmConstraints() {
183     //     return algorithmConstraints;
184     // }
185 
186     /**
187      * Sets the cryptographic algorithm constraints, which will be used
188      * in addition to any configured by the runtime environment.
189      * <p>
190      * If the <code>constraints</code> parameter is non-null, every
191      * cryptographic algorithm, key and algorithm parameters used in the
192      * SSL/TLS handshake must be permitted by the constraints.
193      *
194      * @param constraints the algorithm constraints (or null)
195      *
196      */
197     // void setAlgorithmConstraints(AlgorithmConstraints constraints) {
198     //     // the constraints object is immutable
199     //     this.algorithmConstraints = constraints;
200     // }
201 
202     /**
203      * Gets the endpoint identification algorithm.
204      *
205      * @return the endpoint identification algorithm, or null if none
206      * has been set.
207      *
208      * @see X509ExtendedTrustManager
209      * @see #setEndpointIdentificationAlgorithm(string)
210      *
211      */
212     string getEndpointIdentificationAlgorithm() {
213         return identificationAlgorithm;
214     }
215 
216     /**
217      * Sets the endpoint identification algorithm.
218      * <p>
219      * If the <code>algorithm</code> parameter is non-null or non-empty, the
220      * endpoint identification/verification procedures must be handled during
221      * SSL/TLS handshaking.  This is to prevent man-in-the-middle attacks.
222      *
223      * @param algorithm The standard string name of the endpoint
224      *     identification algorithm (or null).  See Appendix A in the <a href=
225      *   "{@docRoot}/../technotes/guides/security/crypto/CryptoSpec.html#AppA">
226      *     Java Cryptography Architecture API Specification &amp; Reference </a>
227      *     for information about standard algorithm names.
228      *
229      * @see X509ExtendedTrustManager
230      *
231      */
232     void setEndpointIdentificationAlgorithm(string algorithm) {
233         this.identificationAlgorithm = algorithm;
234     }
235 
236     /**
237      * Sets the desired {@link SNIServerName}s of the Server Name
238      * Indication (SNI) parameter.
239      * <P>
240      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
241      * operating in client mode.
242      * <P>
243      * Note that the {@code serverNames} list is cloned
244      * to protect against subsequent modification.
245      *
246      * @param  serverNames
247      *         the list of desired {@link SNIServerName}s (or null)
248      *
249      * @throws NullPointerException if the {@code serverNames}
250      *         contains {@code null} element
251      * @throws IllegalArgumentException if the {@code serverNames}
252      *         contains more than one name of the same name type
253      *
254      * @see SNIServerName
255      * @see #getServerNames()
256      *
257      */
258     // void setServerNames(List!SNIServerName serverNames) {
259     //     if (serverNames !is null) {
260     //         if (!serverNames.isEmpty()) {
261     //             sniNames = new HashMap!(int, SNIServerName)(serverNames.size()); // LinkedHashMap<>(serverNames.size());
262     //             foreach (SNIServerName serverName ; serverNames) {
263     //                 if (sniNames.put(serverName.getType(),
264     //                                             serverName) !is null) {
265     //                     throw new IllegalArgumentException(
266     //                                 "Duplicated server name of type " ~
267     //                                 serverName.getType().to!string());
268     //                 }
269     //             }
270     //         } else {
271     //             sniNames = Collections.emptyMap!(int, SNIServerName)();
272     //         }
273     //     } else {
274     //         sniNames = null;
275     //     }
276     // }
277 
278     /**
279      * Returns a {@link List} containing all {@link SNIServerName}s of the
280      * Server Name Indication (SNI) parameter, or null if none has been set.
281      * <P>
282      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
283      * operating in client mode.
284      * <P>
285      * For SSL/TLS connections, the underlying SSL/TLS provider
286      * may specify a default value for a certain server name type.  In
287      * client mode, it is recommended that, by default, providers should
288      * include the server name indication whenever the server can be located
289      * by a supported server name type.
290      * <P>
291      * It is recommended that providers initialize default Server Name
292      * Indications when creating {@code SSLSocket}/{@code SSLEngine}s.
293      * In the following examples, the server name could be represented by an
294      * instance of {@link SNIHostName} which has been initialized with the
295      * hostname "www.example.com" and type
296      * {@link StandardConstants#SNI_HOST_NAME}.
297      *
298      * <pre>
299      *     Socket socket =
300      *         sslSocketFactory.createSocket("www.example.com", 443);
301      * </pre>
302      * or
303      * <pre>
304      *     SSLEngine engine =
305      *         sslContext.createSSLEngine("www.example.com", 443);
306      * </pre>
307      * <P>
308      *
309      * @return null or an immutable list of non-null {@link SNIServerName}s
310      *
311      * @see List
312      * @see #setServerNames(List)
313      *
314      */
315     // List!SNIServerName getServerNames() {
316     //     if (sniNames !is null) {
317     //         if (!sniNames.isEmpty()) {
318     //             return new ArrayList!(SNIServerName)(sniNames.values());
319     //         } else {
320     //             return new EmptyList!(SNIServerName)();
321     //         }
322     //     }
323 
324     //     return null;
325     // }
326 
327     /**
328      * Sets the {@link SNIMatcher}s of the Server Name Indication (SNI)
329      * parameter.
330      * <P>
331      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
332      * operating in server mode.
333      * <P>
334      * Note that the {@code matchers} collection is cloned to protect
335      * against subsequent modification.
336      *
337      * @param  matchers
338      *         the collection of {@link SNIMatcher}s (or null)
339      *
340      * @throws NullPointerException if the {@code matchers}
341      *         contains {@code null} element
342      * @throws IllegalArgumentException if the {@code matchers}
343      *         contains more than one name of the same name type
344      *
345      * @see Collection
346      * @see SNIMatcher
347      * @see #getSNIMatchers()
348      *
349      */
350     // void setSNIMatchers(Collection!SNIMatcher matchers) {
351     //     if (matchers !is null) {
352     //         if (!matchers.isEmpty()) {
353     //             sniMatchers = new HashMap!(int, SNIMatcher)(matchers.size());
354     //             foreach (SNIMatcher matcher ; matchers) {
355     //                 if (sniMatchers.put(matcher.getType(),
356     //                                             matcher) !is null) {
357     //                     throw new IllegalArgumentException(
358     //                                 "Duplicated server name of type " ~
359     //                                 matcher.getType().to!string());
360     //                 }
361     //             }
362     //         } else {
363     //             sniMatchers = Collections.emptyMap!(int, SNIMatcher)(); 
364     //         }
365     //     } else {
366     //         sniMatchers = null;
367     //     }
368     // }
369 
370     /**
371      * Returns a {@link Collection} containing all {@link SNIMatcher}s of the
372      * Server Name Indication (SNI) parameter, or null if none has been set.
373      * <P>
374      * This method is only useful to {@link SSLSocket}s or {@link SSLEngine}s
375      * operating in server mode.
376      * <P>
377      * For better interoperability, providers generally will not define
378      * default matchers so that by default servers will ignore the SNI
379      * extension and continue the handshake.
380      *
381      * @return null or an immutable collection of non-null {@link SNIMatcher}s
382      *
383      * @see SNIMatcher
384      * @see #setSNIMatchers(Collection)
385      *
386      */
387     // Collection!SNIMatcher getSNIMatchers() {
388     //     if (sniMatchers !is null) {
389     //         if (!sniMatchers.isEmpty()) {
390     //             return new ArrayList!(SNIMatcher)(sniMatchers.values());
391     //         } else {
392     //             return new EmptyList!(SNIMatcher)();
393     //         }
394     //     }
395 
396     //     return null;
397     // }
398 
399     /**
400      * Sets whether the local cipher suites preference should be honored.
401      *
402      * @param honorOrder whether local cipher suites order in
403      *        {@code #getCipherSuites} should be honored during
404      *        SSL/TLS handshaking.
405      *
406      * @see #getUseCipherSuitesOrder()
407      *
408      */
409     void setUseCipherSuitesOrder(bool honorOrder) {
410         this.preferLocalCipherSuites = honorOrder;
411     }
412 
413     /**
414      * Returns whether the local cipher suites preference should be honored.
415      *
416      * @return whether local cipher suites order in {@code #getCipherSuites}
417      *         should be honored during SSL/TLS handshaking.
418      *
419      * @see #setUseCipherSuitesOrder(bool)
420      *
421      */
422     bool getUseCipherSuitesOrder() {
423         return preferLocalCipherSuites;
424     }
425 }