Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New BoringSSL context option - SSL_CTX_set1_sigalgs #765

Merged
merged 19 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
0aa0f31
- New boring SSL context option - SSL_CTX_set1_sigalgs
jaymansfield Dec 8, 2024
a618d22
Made BoringSSLCertificateCallback class public to access static membe…
jaymansfield Dec 9, 2024
ab559c7
Merge branch 'netty:main' into config
jaymansfield Dec 9, 2024
24f4bce
Update codec-classes-quic/src/main/java/io/netty/incubator/codec/quic…
jaymansfield Dec 12, 2024
483d58b
Update codec-classes-quic/src/main/java/io/netty/incubator/codec/quic…
jaymansfield Dec 12, 2024
7fe6f08
New SSLContextOption's for server and client key types
jaymansfield Dec 12, 2024
3c6e41f
Merge remote-tracking branch 'origin/config' into config
jaymansfield Dec 12, 2024
fc289bf
updates
jaymansfield Dec 12, 2024
b805432
Merge branch 'netty:main' into config
jaymansfield Dec 12, 2024
6c95065
unit test for key type change
jaymansfield Dec 13, 2024
bbd373d
Merge remote-tracking branch 'origin/config' into config
jaymansfield Dec 13, 2024
2a57ad5
unit test for key type change (intended to fail)
jaymansfield Dec 13, 2024
dd18b8c
unit test for key type change (intended to fail)
jaymansfield Dec 13, 2024
27eef58
changes requested
jaymansfield Dec 18, 2024
d90b9bc
Merge branch 'netty:main' into config
jaymansfield Dec 19, 2024
b752af2
updated unit test
jaymansfield Dec 20, 2024
67ec8f7
Merge remote-tracking branch 'origin/config' into config
jaymansfield Dec 20, 2024
4ab07b4
Update codec-classes-quic/src/main/java/io/netty/incubator/codec/quic…
jaymansfield Dec 23, 2024
d5aa1a4
remove wildcard
jaymansfield Dec 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,22 @@ static int SSLContext_set1_groups_list(long ctx, String... groups) {
return SSLContext_set1_groups_list(ctx, sb.toString());
}

static int SSLContext_set1_sigalgs_list(long ctx, String... sigalgs) {
if (sigalgs.length == 0) {
throw new IllegalArgumentException();
}
StringBuilder sb = new StringBuilder();
for (String sigalg: sigalgs) {
sb.append(sigalg);
// Groups are separated by : as explained in the manpage.
sb.append(':');
}
sb.setLength(sb.length() - 1);
return SSLContext_set1_sigalgs_list(ctx, sb.toString());
}
jaymansfield marked this conversation as resolved.
Show resolved Hide resolved

private static native int SSLContext_set1_sigalgs_list(long context, String sigalgs);

private static native int SSLContext_set1_groups_list(long context, String groups);
static native void SSLContext_free(long context);
static long SSL_new(long context, boolean server, String hostname) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
package io.netty.incubator.codec.quic;


import io.netty.handler.ssl.SslContextOption;
jaymansfield marked this conversation as resolved.
Show resolved Hide resolved
import io.netty.util.CharsetUtil;
import org.jetbrains.annotations.Nullable;

Expand Down Expand Up @@ -90,11 +91,22 @@ final class BoringSSLCertificateCallback {
private final QuicheQuicSslEngineMap engineMap;
private final X509ExtendedKeyManager keyManager;
private final String password;
private Map<String, String> serverKeyTypeOverride;
private Set<String> clientKeyTypeOverride;

BoringSSLCertificateCallback(QuicheQuicSslEngineMap engineMap, @Nullable X509ExtendedKeyManager keyManager, String password) {
BoringSSLCertificateCallback(QuicheQuicSslEngineMap engineMap, @Nullable X509ExtendedKeyManager keyManager, String password, Map.Entry<SslContextOption<?>, Object>[] ctxOptions) {
this.engineMap = engineMap;
this.keyManager = keyManager;
this.password = password;

for (Map.Entry<SslContextOption<?>, Object> ctxOpt : ctxOptions) {
jaymansfield marked this conversation as resolved.
Show resolved Hide resolved
SslContextOption<?> option = ctxOpt.getKey();
if (option == BoringSSLContextOption.CLIENT_KEY_TYPES && ctxOpt.getValue() instanceof Set) {
this.clientKeyTypeOverride = (Set<String>) ctxOpt.getValue();
} else if (option == BoringSSLContextOption.SERVER_KEY_TYPES && ctxOpt.getValue() instanceof Map) {
this.serverKeyTypeOverride = (Map<String, String>) ctxOpt.getValue();
}
}
}

@SuppressWarnings("unused")
Expand Down Expand Up @@ -151,12 +163,17 @@ final class BoringSSLCertificateCallback {
throw new SSLHandshakeException("Unable to find key material");
}

Map<String, String> keyTypes = KEY_TYPES;
if(serverKeyTypeOverride != null) {
keyTypes = serverKeyTypeOverride;
}

// authMethods may contain duplicates or may result in the same type
// but call chooseServerAlias(...) may be expensive. So let's ensure
// we filter out duplicates.
Set<String> typeSet = new HashSet<String>(KEY_TYPES.size());
Set<String> typeSet = new HashSet<String>(keyTypes.size());
for (String authMethod : authMethods) {
String type = KEY_TYPES.get(authMethod);
String type = keyTypes.get(authMethod);
if (type != null && typeSet.add(type)) {
String alias = chooseServerAlias(engine, type);
if (alias != null) {
Expand Down Expand Up @@ -243,8 +260,11 @@ private String chooseServerAlias(QuicheQuicSslEngine engine, String type) {
* @return supported key types that can be used in {@code X509KeyManager.chooseClientAlias} and
* {@code X509ExtendedKeyManager.chooseEngineClientAlias}.
*/
private static Set<String> supportedClientKeyTypes(byte @Nullable[] clientCertificateTypes) {
private Set<String> supportedClientKeyTypes(byte @Nullable[] clientCertificateTypes) {
if (clientCertificateTypes == null) {
if(clientKeyTypeOverride != null) {
return clientKeyTypeOverride;
}
// Try all of the supported key types.
return SUPPORTED_KEY_TYPES;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

import io.netty.handler.ssl.SslContextOption;

import java.util.Map;
import java.util.Set;

/**
* {@link SslContextOption}s that are specific to BoringSSL.
*
Expand All @@ -34,4 +37,22 @@ private BoringSSLContextOption(String name) {
* SSL_CTX_set1_groups_list</a>.
*/
public static final BoringSSLContextOption<String[]> GROUPS = new BoringSSLContextOption<>("GROUPS");

/**
* Set the signature algorithms that should be used.
* <p>
* See <a href="https://github.com/google/boringssl/blob/master/include/openssl/ssl.h#L5166">
* SSL_CTX_set1_sigalgs</a>.
*/
public static final BoringSSLContextOption<String[]> SIGNATURE_ALGORITHMS = new BoringSSLContextOption<>("SIGNATURE_ALGORITHMS");

/**
* Set the supported client key/certificate types used in BoringSSLCertificateCallback
*/
public static final BoringSSLContextOption<Set<String>> CLIENT_KEY_TYPES = new BoringSSLContextOption<>("CLIENT_KEY_TYPES");

/**
* Set the supported server key/certificate types used in BoringSSLCertificateCallback
*/
public static final BoringSSLContextOption<Map<String, String>> SERVER_KEY_TYPES = new BoringSSLContextOption<>("SERVER_KEY_TYPES");
}
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ final class QuicheQuicSslContext extends QuicSslContext {
keyManager = chooseKeyManager(keyManagerFactory);
}
String[] groups = NAMED_GROUPS;
String[] sigalgs = EmptyArrays.EMPTY_STRINGS;
if (ctxOptions != null) {
for (Map.Entry<SslContextOption<?>, Object> ctxOpt : ctxOptions) {
SslContextOption<?> option = ctxOpt.getKey();
Expand All @@ -197,6 +198,13 @@ final class QuicheQuicSslContext extends QuicSslContext {
groupsSet.add(GroupsConverter.toBoringSSL(group));
}
groups = groupsSet.toArray(EmptyArrays.EMPTY_STRINGS);
} else if (option == BoringSSLContextOption.SIGNATURE_ALGORITHMS) {
String[] sigalgsArray = (String[]) ctxOpt.getValue();
Set<String> sigalgsSet = new LinkedHashSet<String>(sigalgsArray.length);
for (String sigalg : sigalgsArray) {
sigalgsSet.add(sigalg);
}
sigalgs = sigalgsSet.toArray(EmptyArrays.EMPTY_STRINGS);
} else {
LOGGER.debug("Skipping unsupported " + SslContextOption.class.getSimpleName()
+ ": " + ctxOpt.getKey());
Expand All @@ -214,7 +222,7 @@ final class QuicheQuicSslContext extends QuicSslContext {
int verifyMode = server ? boringSSLVerifyModeForServer(this.clientAuth) : BoringSSL.SSL_VERIFY_PEER;
nativeSslContext = new NativeSslContext(BoringSSL.SSLContext_new(server, applicationProtocols,
new BoringSSLHandshakeCompleteCallback(engineMap),
new BoringSSLCertificateCallback(engineMap, keyManager, password),
new BoringSSLCertificateCallback(engineMap, keyManager, password, ctxOptions),
new BoringSSLCertificateVerifyCallback(engineMap, trustManager),
mapping == null ? null : new BoringSSLTlsextServernameCallback(engineMap, mapping),
keylog == null ? null : new BoringSSLKeylogCallback(engineMap, keylog),
Expand All @@ -233,6 +241,16 @@ final class QuicheQuicSslContext extends QuicSslContext {
throw new IllegalStateException(msg);
}

if (sigalgs.length > 0 && BoringSSL.SSLContext_set1_sigalgs_list(nativeSslContext.ctx, sigalgs) == 0) {
String msg = "failed to set signature algorithm list: " + Arrays.toString(sigalgs);
String lastError = BoringSSL.ERR_last_error();
if (lastError != null) {
// We have some more details about why the operations failed, include these into the message.
msg += ". " + lastError;
}
throw new IllegalStateException(msg);
}

apn = new QuicheQuicApplicationProtocolNegotiator(applicationProtocols);
if (this.sessionCache != null) {
// Cache is handled via our own implementation.
Expand Down
8 changes: 8 additions & 0 deletions codec-native-quic/src/main/c/netty_quic_boringssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1427,6 +1427,13 @@ jint netty_boringssl_SSLContext_set1_groups_list(JNIEnv* env, jclass clazz, jlon
return (jint) ret;
}

jint netty_boringssl_SSLContext_set1_sigalgs_list(JNIEnv* env, jclass clazz, jlong ctx, jstring sigalgs) {
const char *nativeString = (*env)->GetStringUTFChars(env, sigalgs, 0);
int ret = SSL_CTX_set1_sigalgs_list((SSL_CTX *) ctx, nativeString);
(*env)->ReleaseStringUTFChars(env, sigalgs, nativeString);
return (jint) ret;
}

// JNI Registered Methods End

// JNI Method Registration Table Begin
Expand Down Expand Up @@ -1464,6 +1471,7 @@ static const JNINativeMethod fixed_method_table[] = {
{ "SSLContext_set_early_data_enabled", "(JZ)V", (void *) netty_boringssl_SSLContext_set_early_data_enabled },
{ "SSLContext_setSessionTicketKeys", "(JZ)V", (void *) netty_boringssl_SSLContext_setSessionTicketKeys },
{ "SSLContext_set1_groups_list", "(JLjava/lang/String;)I", (void *) netty_boringssl_SSLContext_set1_groups_list },
{ "SSLContext_set1_sigalgs_list", "(JLjava/lang/String;)I", (void *) netty_boringssl_SSLContext_set1_sigalgs_list },
{ "SSL_new0", "(JZLjava/lang/String;)J", (void *) netty_boringssl_SSL_new0 },
{ "SSL_free", "(J)V", (void *) netty_boringssl_SSL_free },
{ "SSL_getTask", "(J)Ljava/lang/Runnable;", (void *) netty_boringssl_SSL_getTask },
Expand Down