This is an automated email from the ASF dual-hosted git repository.

remm pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 5bcfe17a178fa0128b0e53f1ee79078d215723df
Author: remm <[email protected]>
AuthorDate: Fri Sep 5 16:26:03 2025 +0200

    Add extraction of group and signature information from client hello
    
    The information should be enough to select which certificate to present
    to the client.
---
 .../tomcat/util/net/TLSClientHelloExtractor.java   | 50 +++++++++++++
 .../tomcat/util/net/openssl/ciphers/Group.java     | 77 +++++++++++++++++++
 .../net/openssl/ciphers/SignatureAlgorithm.java    | 86 ++++++++++++++++++++++
 3 files changed, 213 insertions(+)

diff --git a/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java 
b/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
index 36940cff64..33546453d3 100644
--- a/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
+++ b/java/org/apache/tomcat/util/net/TLSClientHelloExtractor.java
@@ -29,6 +29,8 @@ import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.HexUtils;
 import org.apache.tomcat.util.http.parser.HttpParser;
 import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
+import org.apache.tomcat.util.net.openssl.ciphers.Group;
+import org.apache.tomcat.util.net.openssl.ciphers.SignatureAlgorithm;
 import org.apache.tomcat.util.res.StringManager;
 
 /**
@@ -45,10 +47,14 @@ public class TLSClientHelloExtractor {
     private final String sniValue;
     private final List<String> clientRequestedApplicationProtocols;
     private final List<String> clientRequestedProtocols;
+    private final List<Group> clientSupportedGroups;
+    private final List<SignatureAlgorithm> clientSignatureAlgorithms;
 
     private static final int TLS_RECORD_HEADER_LEN = 5;
 
     private static final int TLS_EXTENSION_SERVER_NAME = 0;
+    private static final int TLS_EXTENSION_SUPPORTED_GROUPS = 10;
+    private static final int TLS_EXTENSION_SIGNATURE_ALGORITHMS = 13;
     private static final int TLS_EXTENSION_ALPN = 16;
     private static final int TLS_EXTENSION_SUPPORTED_VERSION = 43;
 
@@ -77,6 +83,8 @@ public class TLSClientHelloExtractor {
         List<String> clientRequestedCipherNames = new ArrayList<>();
         List<String> clientRequestedApplicationProtocols = new ArrayList<>();
         List<String> clientRequestedProtocols = new ArrayList<>();
+        List<Group> clientSupportedGroups = new ArrayList<>();
+        List<SignatureAlgorithm> clientSignatureAlgorithms = new ArrayList<>();
         String sniValue = null;
         try {
             // Switch to read mode.
@@ -158,6 +166,12 @@ public class TLSClientHelloExtractor {
                         sniValue = readSniExtension(netInBuffer);
                         break;
                     }
+                    case TLS_EXTENSION_SUPPORTED_GROUPS:
+                        readSupportedGroups(netInBuffer, 
clientSupportedGroups);
+                        break;
+                    case TLS_EXTENSION_SIGNATURE_ALGORITHMS:
+                        readSignatureAlgorithms(netInBuffer, 
clientSignatureAlgorithms);
+                        break;
                     case TLS_EXTENSION_ALPN:
                         readAlpnExtension(netInBuffer, 
clientRequestedApplicationProtocols);
                         break;
@@ -182,6 +196,14 @@ public class TLSClientHelloExtractor {
             this.clientRequestedApplicationProtocols = 
clientRequestedApplicationProtocols;
             this.sniValue = sniValue;
             this.clientRequestedProtocols = clientRequestedProtocols;
+            this.clientSupportedGroups = clientSupportedGroups;
+            this.clientSignatureAlgorithms = clientSignatureAlgorithms;
+            if (log.isTraceEnabled()) {
+                log.trace("TLS Client Hello: " + clientRequestedCiphers + " 
Names " + clientRequestedCipherNames +
+                        " Protocols " + clientRequestedApplicationProtocols + 
" sniValue " + sniValue +
+                        " clientRequestedProtocols " + 
clientRequestedProtocols + " clientSupportedGroups " + clientSupportedGroups +
+                        " clientSignatureAlgorithms " + 
clientSignatureAlgorithms);
+            }
             // Whatever happens, return the buffer to its original state
             netInBuffer.limit(limit);
             netInBuffer.position(pos);
@@ -424,6 +446,34 @@ public class TLSClientHelloExtractor {
     }
 
 
+    private static void readSupportedGroups(ByteBuffer bb, List<Group> groups) 
{
+        // First 2 bytes are size of the group list
+        int toRead = bb.getChar() / 2;
+        // Then the list of protocols
+        for (int i = 0; i < toRead; i++) {
+            char id = bb.getChar();
+            Group group = Group.valueOf(id);
+            if (group != null) {
+                groups.add(group);
+            }
+        }
+    }
+
+
+    private static void readSignatureAlgorithms(ByteBuffer bb, 
List<SignatureAlgorithm> signatureAlgorithms) {
+        // First 2 bytes are size of the signature algorithm list
+        int toRead = bb.getChar() / 2;
+        // Then the list of protocols
+        for (int i = 0; i < toRead; i++) {
+            char id = bb.getChar();
+            SignatureAlgorithm signatureAlgorithm = 
SignatureAlgorithm.valueOf(id);
+            if (signatureAlgorithm != null) {
+                signatureAlgorithms.add(signatureAlgorithm);
+            }
+        }
+    }
+
+
     public enum ExtractorResult {
         COMPLETE,
         NOT_PRESENT,
diff --git a/java/org/apache/tomcat/util/net/openssl/ciphers/Group.java 
b/java/org/apache/tomcat/util/net/openssl/ciphers/Group.java
new file mode 100644
index 0000000000..801fe80095
--- /dev/null
+++ b/java/org/apache/tomcat/util/net/openssl/ciphers/Group.java
@@ -0,0 +1,77 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.tomcat.util.net.openssl.ciphers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum Group {
+
+    // Elliptic Curve Groups (ECDHE)
+    secp256r1(0x0017),
+    secp384r1(0x0018),
+    secp521r1(0x0019),
+    x25519(0x001D),
+    x448(0x001E),
+
+    // Finite Field Groups (DHE)
+    ffdhe2048(0x0100),
+    ffdhe3072(0x0101),
+    ffdhe4096(0x0102),
+    ffdhe6144(0x0103),
+    ffdhe8192(0x0104),
+
+    // Post-Quantum Key Exchange
+    mlkem512(0x0200),
+    mlkem768(0x0201),
+    mlkem1024(0x0202),
+
+    // Hybrid Key Exchange
+    SecP256r1MLKEM768(0x11EB),
+    X25519MLKEM768(0x11EC),
+    SecP384r1MLKEM1024(0x11ED);
+
+    private final int id;
+
+    Group(int id) {
+        this.id = id;
+    }
+
+    /**
+     * @return the id
+     */
+    public int getId() {
+        return this.id;
+    }
+
+    private static final Map<Integer,Group> idMap = new HashMap<>();
+
+    static {
+        for (Group group : values()) {
+            int id = group.getId();
+
+            if (id > 0 && id < 0xFFFF) {
+                idMap.put(Integer.valueOf(id), group);
+            }
+        }
+    }
+
+
+    public static Group valueOf(int groupId) {
+        return idMap.get(Integer.valueOf(groupId));
+    }
+}
diff --git 
a/java/org/apache/tomcat/util/net/openssl/ciphers/SignatureAlgorithm.java 
b/java/org/apache/tomcat/util/net/openssl/ciphers/SignatureAlgorithm.java
new file mode 100644
index 0000000000..8adde314d7
--- /dev/null
+++ b/java/org/apache/tomcat/util/net/openssl/ciphers/SignatureAlgorithm.java
@@ -0,0 +1,86 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.tomcat.util.net.openssl.ciphers;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public enum SignatureAlgorithm {
+
+    // RSASSA-PKCS1-v1_5 algorithms
+    rsa_pkcs1_sha256(0x0401),
+    rsa_pkcs1_sha384(0x0501),
+    rsa_pkcs1_sha512(0x0601),
+
+    // ECDSA algorithms
+    ecdsa_secp256r1_sha256(0x0403),
+    ecdsa_secp384r1_sha384(0x0503),
+    ecdsa_secp521r1_sha512(0x0603),
+
+    // RSASSA-PSS algorithms with public key OID rsaEncryption
+    rsa_pss_rsae_sha256(0x0804),
+    rsa_pss_rsae_sha384(0x0805),
+    rsa_pss_rsae_sha512(0x0806),
+
+    // EdDSA algorithms */
+    ed25519(0x0807),
+    ed448(0x0808),
+
+    // RSASSA-PSS algorithms with public key OID RSASSA-PSS
+    rsa_pss_pss_sha256(0x0809),
+    rsa_pss_pss_sha384(0x080a),
+    rsa_pss_pss_sha512(0x080b),
+
+    // Legacy algorithms */
+    rsa_pkcs1_sha1(0x0201),
+    ecdsa_sha1(0x0203),
+
+    // ML-DSA algorithms
+    mldsa44(0x0904),
+    mldsa65(0x0905),
+    mldsa87(0x0906);
+
+    private final int id;
+
+    SignatureAlgorithm(int id) {
+        this.id = id;
+    }
+
+    /**
+     * @return the id
+     */
+    public int getId() {
+        return this.id;
+    }
+
+    private static final Map<Integer,SignatureAlgorithm> idMap = new 
HashMap<>();
+
+    static {
+        for (SignatureAlgorithm group : values()) {
+            int id = group.getId();
+
+            if (id > 0 && id < 0xFFFF) {
+                idMap.put(Integer.valueOf(id), group);
+            }
+        }
+    }
+
+
+    public static SignatureAlgorithm valueOf(int groupId) {
+        return idMap.get(Integer.valueOf(groupId));
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to