1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package libcore.javax.net.ssl;
18
19import junit.framework.Assert;
20import libcore.java.security.StandardNames;
21import java.io.IOException;
22import java.util.Arrays;
23import java.util.Collections;
24import java.util.HashSet;
25import java.util.Set;
26import javax.net.ssl.SSLContext;
27import javax.net.ssl.SSLEngine;
28import javax.net.ssl.SSLParameters;
29import javax.net.ssl.SSLServerSocket;
30import javax.net.ssl.SSLServerSocketFactory;
31import javax.net.ssl.SSLSocket;
32import javax.net.ssl.SSLSocketFactory;
33
34/**
35 * Assertions about the configuration of TLS/SSL primitives.
36 */
37public class SSLConfigurationAsserts extends Assert {
38
39  /** Hidden constructor to prevent instantiation. */
40  private SSLConfigurationAsserts() {}
41
42  /**
43   * Asserts that the provided {@link SSLContext} has the expected default configuration, and that
44   * {@link SSLSocketFactory}, {@link SSLServerSocketFactory}, {@link SSLSocket},
45   * {@link SSLServerSocket} and {@link SSLEngine} instances created from the context match the
46   * configuration.
47   */
48  public static void assertSSLContextDefaultConfiguration(SSLContext sslContext)
49      throws IOException {
50    SSLParameters defaultParameters = sslContext.getDefaultSSLParameters();
51    StandardNames.assertSSLContextEnabledProtocols(sslContext.getProtocol(),
52        defaultParameters.getProtocols());
53    StandardNames.assertDefaultCipherSuites(defaultParameters.getCipherSuites());
54    assertFalse(defaultParameters.getWantClientAuth());
55    assertFalse(defaultParameters.getNeedClientAuth());
56
57    SSLParameters supportedParameters = sslContext.getSupportedSSLParameters();
58    StandardNames.assertSupportedCipherSuites(supportedParameters.getCipherSuites());
59    StandardNames.assertSupportedProtocols(supportedParameters.getProtocols());
60    assertFalse(supportedParameters.getWantClientAuth());
61    assertFalse(supportedParameters.getNeedClientAuth());
62
63    assertContainsAll("Unsupported enabled cipher suites", supportedParameters.getCipherSuites(),
64        defaultParameters.getCipherSuites());
65    assertContainsAll("Unsupported enabled protocols", supportedParameters.getProtocols(),
66        defaultParameters.getProtocols());
67
68    assertSSLSocketFactoryConfigSameAsSSLContext(sslContext.getSocketFactory(), sslContext);
69    assertSSLServerSocketFactoryConfigSameAsSSLContext(sslContext.getServerSocketFactory(),
70        sslContext);
71
72    SSLEngine sslEngine = sslContext.createSSLEngine();
73    assertFalse(sslEngine.getUseClientMode());
74    assertSSLEngineConfigSameAsSSLContext(sslEngine, sslContext);
75  }
76
77  /**
78   * Asserts that the provided {@link SSLSocketFactory} has the expected default configuration and
79   * that {@link SSLSocket} instances created by the factory match the configuration.
80   */
81  public static void assertSSLSocketFactoryDefaultConfiguration(
82      SSLSocketFactory sslSocketFactory) throws Exception {
83    assertSSLSocketFactoryConfigSameAsSSLContext(sslSocketFactory,
84        SSLContext.getDefault());
85  }
86
87  /**
88   * Asserts that {@link SSLSocketFactory}'s configuration matches {@code SSLContext}'s
89   * configuration, and that {@link SSLSocket} instances obtained from the factory match this
90   * configuration as well.
91   */
92  private static void assertSSLSocketFactoryConfigSameAsSSLContext(
93      SSLSocketFactory sslSocketFactory, SSLContext sslContext) throws IOException {
94    assertCipherSuitesEqual(sslContext.getDefaultSSLParameters().getCipherSuites(),
95        sslSocketFactory.getDefaultCipherSuites());
96    assertCipherSuitesEqual(sslContext.getSupportedSSLParameters().getCipherSuites(),
97        sslSocketFactory.getSupportedCipherSuites());
98
99    try (SSLSocket sslSocket = (SSLSocket) sslSocketFactory.createSocket()) {
100      assertTrue(sslSocket.getUseClientMode());
101      assertTrue(sslSocket.getEnableSessionCreation());
102      assertSSLSocketConfigSameAsSSLContext(sslSocket, sslContext);
103    }
104  }
105
106  /**
107   * Asserts that the provided {@link SSLSocket} has the expected default configuration.
108   */
109  public static void assertSSLSocketDefaultConfiguration(SSLSocket sslSocket) throws Exception {
110    assertTrue(sslSocket.getUseClientMode());
111    assertTrue(sslSocket.getEnableSessionCreation());
112    assertSSLSocketConfigSameAsSSLContext(sslSocket, SSLContext.getDefault());
113  }
114
115  /**
116   * Asserts that {@link SSLSocket}'s configuration matches {@code SSLContext's} configuration.
117   */
118  private static void assertSSLSocketConfigSameAsSSLContext(SSLSocket sslSocket,
119      SSLContext sslContext) {
120    assertSSLParametersEqual(sslSocket.getSSLParameters(), sslContext.getDefaultSSLParameters());
121    assertCipherSuitesEqual(sslSocket.getEnabledCipherSuites(),
122        sslContext.getDefaultSSLParameters().getCipherSuites());
123    assertProtocolsEqual(sslSocket.getEnabledProtocols(),
124        sslContext.getDefaultSSLParameters().getProtocols());
125
126    assertCipherSuitesEqual(sslSocket.getSupportedCipherSuites(),
127        sslContext.getSupportedSSLParameters().getCipherSuites());
128    assertProtocolsEqual(sslSocket.getSupportedProtocols(),
129        sslContext.getSupportedSSLParameters().getProtocols());
130  }
131
132  /**
133   * Asserts that the provided {@link SSLServerSocketFactory} has the expected default
134   * configuration, and that {@link SSLServerSocket} instances created by the factory match the
135   * configuration.
136   */
137  public static void assertSSLServerSocketFactoryDefaultConfiguration(
138      SSLServerSocketFactory sslServerSocketFactory) throws Exception {
139    assertSSLServerSocketFactoryConfigSameAsSSLContext(sslServerSocketFactory,
140        SSLContext.getDefault());
141  }
142
143  /**
144   * Asserts that {@link SSLServerSocketFactory}'s configuration matches {@code SSLContext}'s
145   * configuration, and that {@link SSLServerSocket} instances obtained from the factory match this
146   * configuration as well.
147   */
148  private static void assertSSLServerSocketFactoryConfigSameAsSSLContext(
149      SSLServerSocketFactory sslServerSocketFactory, SSLContext sslContext)  throws IOException {
150    assertCipherSuitesEqual(sslContext.getDefaultSSLParameters().getCipherSuites(),
151        sslServerSocketFactory.getDefaultCipherSuites());
152    assertCipherSuitesEqual(sslContext.getSupportedSSLParameters().getCipherSuites(),
153        sslServerSocketFactory.getSupportedCipherSuites());
154    try (SSLServerSocket sslServerSocket =
155        (SSLServerSocket) sslServerSocketFactory.createServerSocket()) {
156      assertFalse(sslServerSocket.getUseClientMode());
157      assertTrue(sslServerSocket.getEnableSessionCreation());
158      assertSSLServerSocketConfigSameAsSSLContext(sslServerSocket, sslContext);
159    }
160  }
161
162  /**
163   * Asserts that the provided {@link SSLServerSocket} has the expected default configuration.
164   */
165  public static void assertSSLServerSocketDefaultConfiguration(SSLServerSocket sslServerSocket)
166      throws Exception {
167    assertFalse(sslServerSocket.getUseClientMode());
168    assertTrue(sslServerSocket.getEnableSessionCreation());
169    assertSSLServerSocketConfigSameAsSSLContext(sslServerSocket, SSLContext.getDefault());
170    // TODO: Check SSLParameters when supported by SSLServerSocket API
171  }
172
173  /**
174   * Asserts that {@link SSLServerSocket}'s configuration matches {@code SSLContext's}
175   * configuration.
176   */
177  private static void assertSSLServerSocketConfigSameAsSSLContext(SSLServerSocket sslServerSocket,
178      SSLContext sslContext) {
179    assertCipherSuitesEqual(sslServerSocket.getEnabledCipherSuites(),
180        sslContext.getDefaultSSLParameters().getCipherSuites());
181    assertProtocolsEqual(sslServerSocket.getEnabledProtocols(),
182        sslContext.getDefaultSSLParameters().getProtocols());
183
184    assertCipherSuitesEqual(sslServerSocket.getSupportedCipherSuites(),
185        sslContext.getSupportedSSLParameters().getCipherSuites());
186    assertProtocolsEqual(sslServerSocket.getSupportedProtocols(),
187        sslContext.getSupportedSSLParameters().getProtocols());
188
189    assertEquals(sslServerSocket.getNeedClientAuth(),
190        sslContext.getDefaultSSLParameters().getNeedClientAuth());
191    assertEquals(sslServerSocket.getWantClientAuth(),
192        sslContext.getDefaultSSLParameters().getWantClientAuth());
193  }
194
195  /**
196   * Asserts that the provided {@link SSLEngine} has the expected default configuration.
197   */
198  public static void assertSSLEngineDefaultConfiguration(SSLEngine sslEngine) throws Exception {
199    assertFalse(sslEngine.getUseClientMode());
200    assertTrue(sslEngine.getEnableSessionCreation());
201    assertSSLEngineConfigSameAsSSLContext(sslEngine, SSLContext.getDefault());
202  }
203
204  /**
205   * Asserts that {@link SSLEngine}'s configuration matches {@code SSLContext's} configuration.
206   */
207  private static void assertSSLEngineConfigSameAsSSLContext(SSLEngine sslEngine,
208      SSLContext sslContext) {
209    assertSSLParametersEqual(sslEngine.getSSLParameters(), sslContext.getDefaultSSLParameters());
210    assertCipherSuitesEqual(sslEngine.getEnabledCipherSuites(),
211        sslContext.getDefaultSSLParameters().getCipherSuites());
212    assertProtocolsEqual(sslEngine.getEnabledProtocols(),
213        sslContext.getDefaultSSLParameters().getProtocols());
214
215    assertCipherSuitesEqual(sslEngine.getSupportedCipherSuites(),
216        sslContext.getSupportedSSLParameters().getCipherSuites());
217    assertProtocolsEqual(sslEngine.getSupportedProtocols(),
218        sslContext.getSupportedSSLParameters().getProtocols());
219  }
220
221  private static void assertSSLParametersEqual(SSLParameters expected, SSLParameters actual) {
222    assertCipherSuitesEqual(expected.getCipherSuites(), actual.getCipherSuites());
223    assertProtocolsEqual(expected.getProtocols(), actual.getProtocols());
224    assertEquals(expected.getNeedClientAuth(), actual.getNeedClientAuth());
225    assertEquals(expected.getWantClientAuth(), actual.getWantClientAuth());
226  }
227
228  private static void assertCipherSuitesEqual(String[] expected, String[] actual) {
229    assertEquals(Arrays.asList(expected), Arrays.asList(actual));
230  }
231
232  private static void assertProtocolsEqual(String[] expected, String[] actual) {
233    // IMPLEMENTATION NOTE: The order of protocols versions does not matter. Similarly, it only
234    // matters whether a protocol version is present or absent in the array. These arrays are
235    // supposed to represent sets of protocol versions. Thus, we treat them as such.
236    assertEquals(new HashSet<String>(Arrays.asList(expected)),
237        new HashSet<String>(Arrays.asList(actual)));
238  }
239
240  /**
241   * Asserts that the {@code container} contains all the {@code elements}.
242   */
243  private static void assertContainsAll(String message, String[] container, String[] elements) {
244    Set<String> elementsNotInContainer = new HashSet<String>(Arrays.asList(elements));
245    elementsNotInContainer.removeAll(Arrays.asList(container));
246    assertEquals(message, Collections.EMPTY_SET, elementsNotInContainer);
247  }
248}
249