|
22 | 22 | import io.netty.util.AbstractReferenceCounted;
|
23 | 23 | import io.netty.util.Mapping;
|
24 | 24 | import io.netty.util.ReferenceCounted;
|
| 25 | +import io.netty.util.internal.EmptyArrays; |
| 26 | +import io.netty.util.internal.SystemPropertyUtil; |
| 27 | +import io.netty.util.internal.logging.InternalLogger; |
| 28 | +import io.netty.util.internal.logging.InternalLoggerFactory; |
25 | 29 | import org.jetbrains.annotations.Nullable;
|
26 | 30 |
|
27 | 31 | import javax.crypto.NoSuchPaddingException;
|
|
46 | 50 | import java.util.Arrays;
|
47 | 51 | import java.util.Collections;
|
48 | 52 | import java.util.Enumeration;
|
| 53 | +import java.util.Iterator; |
| 54 | +import java.util.LinkedHashSet; |
49 | 55 | import java.util.List;
|
50 | 56 | import java.util.NoSuchElementException;
|
| 57 | +import java.util.Set; |
51 | 58 | import java.util.concurrent.Executor;
|
52 | 59 | import java.util.function.BiConsumer;
|
53 | 60 | import java.util.function.LongFunction;
|
54 | 61 |
|
55 | 62 | import static io.netty.util.internal.ObjectUtil.checkNotNull;
|
56 | 63 |
|
57 | 64 | final class QuicheQuicSslContext extends QuicSslContext {
|
| 65 | + |
| 66 | + private static final InternalLogger LOGGER = InternalLoggerFactory.getInstance(QuicheQuicSslContext.class); |
| 67 | + |
| 68 | + // Use default that is supported in java 11 and earlier and also in OpenSSL / BoringSSL. |
| 69 | + // See https://github.com/netty/netty-tcnative/issues/567 |
| 70 | + // See https://www.java.com/en/configure_crypto.html for ordering |
| 71 | + private static final String[] DEFAULT_NAMED_GROUPS = { "x25519", "secp256r1", "secp384r1", "secp521r1" }; |
| 72 | + private static final String[] NAMED_GROUPS; |
| 73 | + |
| 74 | + static { |
| 75 | + String[] namedGroups = DEFAULT_NAMED_GROUPS; |
| 76 | + Set<String> defaultConvertedNamedGroups = new LinkedHashSet<>(namedGroups.length); |
| 77 | + for (int i = 0; i < namedGroups.length; i++) { |
| 78 | + defaultConvertedNamedGroups.add(GroupsConverter.toBoringSSL(namedGroups[i])); |
| 79 | + } |
| 80 | + |
| 81 | + final long sslCtx = BoringSSL.SSLContext_new(); |
| 82 | + try { |
| 83 | + // Let's filter out any group that is not supported from the default. |
| 84 | + Iterator<String> defaultGroupsIter = defaultConvertedNamedGroups.iterator(); |
| 85 | + while (defaultGroupsIter.hasNext()) { |
| 86 | + if (BoringSSL.SSLContext_set1_groups_list(sslCtx, defaultGroupsIter.next()) == 0) { |
| 87 | + // Not supported, let's remove it. This could for example be the case if we use |
| 88 | + // fips and the configure group is not supported when using FIPS. |
| 89 | + // See https://github.com/netty/netty-tcnative/issues/883 |
| 90 | + defaultGroupsIter.remove(); |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + String groups = SystemPropertyUtil.get("jdk.tls.namedGroups", null); |
| 95 | + if (groups != null) { |
| 96 | + String[] nGroups = groups.split(","); |
| 97 | + Set<String> supportedNamedGroups = new LinkedHashSet<>(nGroups.length); |
| 98 | + Set<String> supportedConvertedNamedGroups = new LinkedHashSet<>(nGroups.length); |
| 99 | + |
| 100 | + Set<String> unsupportedNamedGroups = new LinkedHashSet<>(); |
| 101 | + for (String namedGroup : nGroups) { |
| 102 | + String converted = GroupsConverter.toBoringSSL(namedGroup); |
| 103 | + if (BoringSSL.SSLContext_set1_groups_list(sslCtx, converted) == 0) { |
| 104 | + supportedConvertedNamedGroups.add(converted); |
| 105 | + supportedNamedGroups.add(namedGroup); |
| 106 | + } else { |
| 107 | + unsupportedNamedGroups.add(namedGroup); |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + if (supportedNamedGroups.isEmpty()) { |
| 112 | + namedGroups = defaultConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS); |
| 113 | + LOGGER.info("All configured namedGroups are not supported: {}. Use default: {}.", |
| 114 | + Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS)), |
| 115 | + Arrays.toString(DEFAULT_NAMED_GROUPS)); |
| 116 | + } else { |
| 117 | + String[] groupArray = supportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS); |
| 118 | + if (unsupportedNamedGroups.isEmpty()) { |
| 119 | + LOGGER.info("Using configured namedGroups -D 'jdk.tls.namedGroup': {} ", |
| 120 | + Arrays.toString(groupArray)); |
| 121 | + } else { |
| 122 | + LOGGER.info("Using supported configured namedGroups: {}. Unsupported namedGroups: {}. ", |
| 123 | + Arrays.toString(groupArray), |
| 124 | + Arrays.toString(unsupportedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS))); |
| 125 | + } |
| 126 | + namedGroups = supportedConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS); |
| 127 | + } |
| 128 | + } else { |
| 129 | + namedGroups = defaultConvertedNamedGroups.toArray(EmptyArrays.EMPTY_STRINGS); |
| 130 | + } |
| 131 | + } finally { |
| 132 | + BoringSSL.SSLContext_free(sslCtx); |
| 133 | + } |
| 134 | + NAMED_GROUPS = namedGroups; |
| 135 | + } |
| 136 | + |
58 | 137 | final ClientAuth clientAuth;
|
59 | 138 | private final boolean server;
|
60 | 139 | @SuppressWarnings("deprecation")
|
@@ -118,25 +197,43 @@ final class QuicheQuicSslContext extends QuicSslContext {
|
118 | 197 | server ? null : new BoringSSLSessionCallback(engineMap, sessionCache), privateKeyMethod,
|
119 | 198 | sessionTicketCallback, verifyMode,
|
120 | 199 | BoringSSL.subjectNames(trustManager.getAcceptedIssuers())));
|
121 |
| - apn = new QuicheQuicApplicationProtocolNegotiator(applicationProtocols); |
122 |
| - if (this.sessionCache != null) { |
123 |
| - // Cache is handled via our own implementation. |
124 |
| - this.sessionCache.setSessionCacheSize((int) sessionCacheSize); |
125 |
| - this.sessionCache.setSessionTimeout((int) sessionTimeout); |
126 |
| - } else { |
127 |
| - // Cache is handled by BoringSSL internally |
128 |
| - BoringSSL.SSLContext_setSessionCacheSize( |
129 |
| - nativeSslContext.address(), sessionCacheSize); |
130 |
| - this.sessionCacheSize = sessionCacheSize; |
| 200 | + boolean success = false; |
| 201 | + try { |
| 202 | + if (NAMED_GROUPS.length > 0 && BoringSSL.SSLContext_set1_groups_list(nativeSslContext.ctx, NAMED_GROUPS) == 0) { |
| 203 | + String msg = "failed to set curves / groups list: " + Arrays.toString(NAMED_GROUPS); |
| 204 | + String lastError = BoringSSL.ERR_last_error(); |
| 205 | + if (lastError != null) { |
| 206 | + // We have some more details about why the operations failed, include these into the message. |
| 207 | + msg += ". " + lastError; |
| 208 | + } |
| 209 | + throw new IllegalStateException(msg); |
| 210 | + } |
131 | 211 |
|
132 |
| - BoringSSL.SSLContext_setSessionCacheTimeout( |
133 |
| - nativeSslContext.address(), sessionTimeout); |
134 |
| - this.sessionTimeout = sessionTimeout; |
135 |
| - } |
136 |
| - if (earlyData != null) { |
137 |
| - BoringSSL.SSLContext_set_early_data_enabled(nativeSslContext.address(), earlyData); |
| 212 | + apn = new QuicheQuicApplicationProtocolNegotiator(applicationProtocols); |
| 213 | + if (this.sessionCache != null) { |
| 214 | + // Cache is handled via our own implementation. |
| 215 | + this.sessionCache.setSessionCacheSize((int) sessionCacheSize); |
| 216 | + this.sessionCache.setSessionTimeout((int) sessionTimeout); |
| 217 | + } else { |
| 218 | + // Cache is handled by BoringSSL internally |
| 219 | + BoringSSL.SSLContext_setSessionCacheSize( |
| 220 | + nativeSslContext.address(), sessionCacheSize); |
| 221 | + this.sessionCacheSize = sessionCacheSize; |
| 222 | + |
| 223 | + BoringSSL.SSLContext_setSessionCacheTimeout( |
| 224 | + nativeSslContext.address(), sessionTimeout); |
| 225 | + this.sessionTimeout = sessionTimeout; |
| 226 | + } |
| 227 | + if (earlyData != null) { |
| 228 | + BoringSSL.SSLContext_set_early_data_enabled(nativeSslContext.address(), earlyData); |
| 229 | + } |
| 230 | + sessionCtx = new QuicheQuicSslSessionContext(this); |
| 231 | + success = true; |
| 232 | + } finally { |
| 233 | + if (!success) { |
| 234 | + nativeSslContext.release(); |
| 235 | + } |
138 | 236 | }
|
139 |
| - sessionCtx = new QuicheQuicSslSessionContext(this); |
140 | 237 | }
|
141 | 238 |
|
142 | 239 | private X509ExtendedKeyManager chooseKeyManager(KeyManagerFactory keyManagerFactory) {
|
|
0 commit comments