On Fri, May 15, 2026 at 6:03 PM Mark Thomas <[email protected]> wrote:
>
> On 15/05/2026 16:50, Dimitris Soumis wrote:
> > https://github.com/apache/tomcat/blob/main/java/org/apache/tomcat/util/openssl/openssl_h.java#L82
> >
> > Maybe LibreSSL is loaded which doesn't support PQC?
>
> Almost. It was the usual multiple inter-related errors making debugging
> more difficult than usual.
>
> The sytem OpenSSL 3.0.x was being picked up. That was adding a lot of
> noise. Then OpenSSL master needed slightly different settings to OpenSSL
> 3.x. The following fixed the OpenSSL version issues (running in the IDE
> - equivalent settings would be required in build.properties)
>
> -Dtomcat.test.openssl.path=/home/mark/repos/openssl/build-master/bin/openssl
> -Djava.library.path=/home/mark/libs/tomcat-native-2.0.14-openssl-master/lib:/home/mark/repos/openssl/build-master/lib64
> -Dorg.apache.tomcat.util.openssl.USE_SYSTEM_LOAD_LIBRARY=true
>
> And with those in place I could switch between Native 2.0.14 and 2.0.x
> and OpenSSL 3.5.6 and master and get consistent errors. The errors look
> like an OpenSSL + Native + PQC bug that the tests are now exposing. That
> isn't fixed yet but I feel I am making progress.

This happened to me before (unfortunately ...).

Here's the build.properties I use to test the various impls with the testsuite:
#runtests.librarypath=-Djava.library.path=/home/remm/Work/tomcat/openssl
#runtests.librarypath=-Djava.library.path=/home/remm/Work/libressl-3.5.0/ssl/.libs:/home/remm/Work/libressl-3.5.0/crypto/.libs
#runtests.librarypath=-Djava.library.path=/home/remm/Work/libressl-3.3.6/ssl/.libs:/home/remm/Work/libressl-3.3.6/crypto/.libs
#runtests.librarypath=-Djava.library.path=/home/remm/Work/libressl-4.0.0/ssl/.libs:/home/remm/Work/libressl-4.0.0/crypto/.libs
#runtests.librarypath=-Djava.library.path=/home/remm/Work/boringssl/build
#openssl.ffm.1=-Dorg.apache.tomcat.util.openssl.USE_SYSTEM_LOAD_LIBRARY=true

I also have:
#openssl.ffm.2=-Dorg.apache.tomcat.util.openssl.CRYPTO_LIBRARY_NAME=crypto
but I don't remember why.

Rémy

> Mark
>
>
> >
> > Dimitris
> >
> > On Fri, May 15, 2026 at 5:35 PM Mark Thomas <[email protected]> wrote:
> >
> >> On 15/05/2026 15:12, Dimitris Soumis wrote:
> >>> PQC should be enabled by default.
> >>
> >> Agreed. And it appears to be.
> >>
> >>> dsoumis@192:~$ openssl list -signature-algorithms 2>&1 | grep -i mldsa
> >>>     { 2.16.840.1.101.3.4.3.17, id-ml-dsa-44, ML-DSA-44, MLDSA44 } @
> >> default
> >>>     { 2.16.840.1.101.3.4.3.18, id-ml-dsa-65, ML-DSA-65, MLDSA65 } @
> >> default
> >>>     { 2.16.840.1.101.3.4.3.19, id-ml-dsa-87, ML-DSA-87, MLDSA87 } @
> >> default
> >>
> >> That is what I see.
> >>
> >>> We should add an extra check for ML-DSA availability if that's the
> >>> issue instead of just checking the version number.
> >>> I will add this if you agree.
> >>
> >> I don't think that is the issue given I am seeing the same results as you.
> >>
> >> I am seeing slightly different behaviour with OpenSSL master.
> >>
> >> It is looking more like an environmental issue. I need to keep digging
> >> to figure out what is going wrong.
> >>
> >> Until I figure out what is going wrong, I don't think it is worth adding
> >> additional checks to the tests.
> >>
> >> Mark
> >>
> >>
> >>>
> >>> Dimitris
> >>>
> >>>
> >>> On Fri, May 15, 2026 at 4:55 PM Mark Thomas <[email protected]> wrote:
> >>>
> >>>> I'm seeing lots of failures with 3.5.5
> >>>>
> >>>> The root cause appears to be:
> >>>>
> >>>> 15-May-2026 12:59:58.147 SEVERE [main]
> >>>> org.apache.tomcat.util.net.openssl.panama.OpenSSLContext.logLastError
> >>>> Error loading certificate: [error:0A0000F7:SSL routines::unknown
> >>>> certificate type]
> >>>>
> >>>> and similar variations.
> >>>>
> >>>> Does PQC need to be explicitly enabled in the OpenSSL build?
> >>>>
> >>>> Mark
> >>>>
> >>>>
> >>>> On 15/05/2026 14:41, Dimitris Soumis wrote:
> >>>>> OpenSSL-FFM tests did pass for me though with Openssl 3.5.4. Could you
> >>>>> provide the failure logs if there are any pending or what version you
> >> are
> >>>>> using that triggers those failures?
> >>>>>
> >>>>> On Fri, May 15, 2026 at 4:16 PM Dimitris Soumis <[email protected]>
> >>>> wrote:
> >>>>>
> >>>>>> Apologies for the noise. Indeed, it wasn't tested properly. Thanks for
> >>>>>> fixing it.
> >>>>>>
> >>>>>> Dimitris
> >>>>>>
> >>>>>> On Fri, May 15, 2026 at 3:02 PM Mark Thomas <[email protected]> wrote:
> >>>>>>
> >>>>>>> On 13/05/2026 12:44, [email protected] wrote:
> >>>>>>>> This is an automated email from the ASF dual-hosted git repository.
> >>>>>>>>
> >>>>>>>> dsoumis pushed a commit to branch main
> >>>>>>>> in repository https://gitbox.apache.org/repos/asf/tomcat.git
> >>>>>>>>
> >>>>>>>>
> >>>>>>>> The following commit(s) were added to refs/heads/main by this push:
> >>>>>>>>          new 7ff10fab8e Add unit tests for PQC features
> >>>>>>>> 7ff10fab8e is described below
> >>>>>>>>
> >>>>>>>> commit 7ff10fab8ede061fe61524ef96b463fef637429f
> >>>>>>>> Author: Dimitrios Soumis <[email protected]>
> >>>>>>>> AuthorDate: Wed May 13 13:44:42 2026 +0200
> >>>>>>>>
> >>>>>>>>         Add unit tests for PQC features
> >>>>>>>
> >>>>>>> How well tested is this patch? And with which OpenSSL versions?
> >>>>>>>
> >>>>>>> The OpenSSL tests can never run because the version check is looking
> >> at
> >>>>>>> the OpenSSLStatus rather than AprStatus.
> >>>>>>>
> >>>>>>> With the above fixed, the OpenSSL tests still won't run because the
> >>>>>>> OpenSSL version isn't set until after the version check.
> >>>>>>>
> >>>>>>> With that fixed, most of the OpenSSL tests result in errors or
> >>>> failures.
> >>>>>>> The OpenSSL-FFM tests have a similar failure rate.
> >>>>>>>
> >>>>>>> Mark
> >>>>>>>
> >>>>>>>
> >>>>>>>> ---
> >>>>>>>>      test/org/apache/tomcat/util/net/TestPQC.java       | 331
> >>>>>>> +++++++++++++++++++++
> >>>>>>>>      .../tomcat/util/net/TesterKeystoreGenerator.java   |  65 ++++
> >>>>>>>>      2 files changed, 396 insertions(+)
> >>>>>>>>
> >>>>>>>> diff --git a/test/org/apache/tomcat/util/net/TestPQC.java
> >>>>>>> b/test/org/apache/tomcat/util/net/TestPQC.java
> >>>>>>>> new file mode 100644
> >>>>>>>> index 0000000000..db3f53ff60
> >>>>>>>> --- /dev/null
> >>>>>>>> +++ b/test/org/apache/tomcat/util/net/TestPQC.java
> >>>>>>>> @@ -0,0 +1,331 @@
> >>>>>>>> +/*
> >>>>>>>> + *  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;
> >>>>>>>> +
> >>>>>>>> +import java.io.File;
> >>>>>>>> +import java.util.ArrayList;
> >>>>>>>> +import java.util.Collection;
> >>>>>>>> +import java.util.List;
> >>>>>>>> +import java.util.Map;
> >>>>>>>> +import java.util.concurrent.TimeUnit;
> >>>>>>>> +
> >>>>>>>> +import javax.net.ssl.SSLContext;
> >>>>>>>> +import javax.net.ssl.SSLHandshakeException;
> >>>>>>>> +import javax.net.ssl.TrustManager;
> >>>>>>>> +
> >>>>>>>> +import org.junit.Assert;
> >>>>>>>> +import org.junit.Assume;
> >>>>>>>> +import org.junit.Test;
> >>>>>>>> +import org.junit.runner.RunWith;
> >>>>>>>> +import org.junit.runners.Parameterized;
> >>>>>>>> +import org.junit.runners.Parameterized.Parameter;
> >>>>>>>> +
> >>>>>>>> +import org.apache.catalina.Context;
> >>>>>>>> +import org.apache.catalina.connector.Connector;
> >>>>>>>> +import org.apache.catalina.startup.TesterServlet;
> >>>>>>>> +import org.apache.catalina.startup.Tomcat;
> >>>>>>>> +import org.apache.catalina.startup.TomcatBaseTest;
> >>>>>>>> +import org.apache.tomcat.util.buf.ByteChunk;
> >>>>>>>> +import org.apache.tomcat.util.net.SSLHostConfigCertificate.Type;
> >>>>>>>> +import org.apache.tomcat.util.net.openssl.OpenSSLStatus;
> >>>>>>>> +
> >>>>>>>> +@RunWith(Parameterized.class)
> >>>>>>>> +public class TestPQC extends TomcatBaseTest {
> >>>>>>>> +
> >>>>>>>> +    @Parameterized.Parameters(name = "{0}")
> >>>>>>>> +    public static Collection<Object[]> parameters() {
> >>>>>>>> +        List<Object[]> parameterSets = new ArrayList<>();
> >>>>>>>> +        parameterSets.add(new Object[] {
> >>>>>>>> +                "JSSE", Boolean.FALSE, "org.apache.tomcat.util.net
> >>>>>>> .jsse.JSSEImplementation"});
> >>>>>>>> +        parameterSets.add(new Object[] {
> >>>>>>>> +                "OpenSSL", Boolean.TRUE, "
> >> org.apache.tomcat.util.net
> >>>>>>> .openssl.OpenSSLImplementation"});
> >>>>>>>> +        parameterSets.add(new Object[] {
> >>>>>>>> +                "OpenSSL-FFM", Boolean.TRUE, "
> >>>>>>> org.apache.tomcat.util.net.openssl.panama.OpenSSLImplementation"});
> >>>>>>>> +        return parameterSets;
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Parameter(0)
> >>>>>>>> +    public String connectorName;
> >>>>>>>> +
> >>>>>>>> +    @Parameter(1)
> >>>>>>>> +    public boolean useOpenSSL;
> >>>>>>>> +
> >>>>>>>> +    @Parameter(2)
> >>>>>>>> +    public String sslImplementationName;
> >>>>>>>> +
> >>>>>>>> +    @Override
> >>>>>>>> +    public void setUp() throws Exception {
> >>>>>>>> +        super.setUp();
> >>>>>>>> +
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        Connector connector = tomcat.getConnector();
> >>>>>>>> +
> >>>>>>>> +        Assert.assertTrue(connector.setProperty("SSLEnabled",
> >>>> "true"));
> >>>>>>>> +        SSLHostConfig sslHostConfig = new SSLHostConfig();
> >>>>>>>> +        sslHostConfig.setProtocols(Constants.SSL_PROTO_TLSv1_3);
> >>>>>>>> +        connector.addSslHostConfig(sslHostConfig);
> >>>>>>>> +
> >>>>>>>> +        TesterSupport.configureSSLImplementation(tomcat,
> >>>>>>> sslImplementationName, useOpenSSL);
> >>>>>>>> +
> >>>>>>>> +        Context ctx = getProgrammaticRootContext();
> >>>>>>>> +        Tomcat.addServlet(ctx, "TesterServlet", new
> >> TesterServlet());
> >>>>>>>> +        ctx.addServletMappingDecoded("/*", "TesterServlet");
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostMLDSA44() throws Exception {
> >>>>>>>> +        File[] pqcFiles = configureHostMLDSA("ML-DSA-44");
> >>>>>>>> +        doTestWithOpenSSLClient(pqcFiles[0].getAbsolutePath(),
> >> null,
> >>>>>>> null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostMLDSA65() throws Exception {
> >>>>>>>> +        File[] pqcFiles = configureHostMLDSA("ML-DSA-65");
> >>>>>>>> +        doTestWithOpenSSLClient(pqcFiles[0].getAbsolutePath(),
> >> null,
> >>>>>>> null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostMLDSA87() throws Exception {
> >>>>>>>> +        File[] pqcFiles = configureHostMLDSA("ML-DSA-87");
> >>>>>>>> +        doTestWithOpenSSLClient(pqcFiles[0].getAbsolutePath(),
> >> null,
> >>>>>>> null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostRSAandMLDSA() throws Exception {
> >>>>>>>> +        configureHostRSA();
> >>>>>>>> +        configureHostMLDSA("ML-DSA-65");
> >>>>>>>> +        doTest();
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostECandMLDSA() throws Exception {
> >>>>>>>> +        configureHostEC();
> >>>>>>>> +        configureHostMLDSA("ML-DSA-65");
> >>>>>>>> +        doTest();
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostRSAwithX25519MLKEM768() throws Exception {
> >>>>>>>> +        configureHostRSA();
> >>>>>>>> +        configureHostWithGroup("X25519MLKEM768");
> >>>>>>>> +        doTestWithOpenSSLClient(new
> >>>>>>> File(TesterSupport.CA_CERT_PEM).getAbsolutePath(),
> >>>>>>>> +                "X25519MLKEM768", null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostRSAwithSecP256r1MLKEM768() throws
> >> Exception {
> >>>>>>>> +        configureHostRSA();
> >>>>>>>> +        configureHostWithGroup("SecP256r1MLKEM768");
> >>>>>>>> +        doTestWithOpenSSLClient(new
> >>>>>>> File(TesterSupport.CA_CERT_PEM).getAbsolutePath(),
> >>>>>>>> +                "SecP256r1MLKEM768", null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostRSAwithSecP384r1MLKEM1024() throws
> >> Exception
> >>>> {
> >>>>>>>> +        configureHostRSA();
> >>>>>>>> +        configureHostWithGroup("SecP384r1MLKEM1024");
> >>>>>>>> +        doTestWithOpenSSLClient(new
> >>>>>>> File(TesterSupport.CA_CERT_PEM).getAbsolutePath(),
> >>>>>>>> +                "SecP384r1MLKEM1024", null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostMLDSAwithX25519MLKEM768() throws Exception
> >> {
> >>>>>>>> +        File[] pqcFiles = configureHostMLDSA("ML-DSA-65");
> >>>>>>>> +        configureHostWithGroup("X25519MLKEM768");
> >>>>>>>> +        doTestWithOpenSSLClient(pqcFiles[0].getAbsolutePath(),
> >>>>>>> "X25519MLKEM768", null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testHostMLDSAwithSecP256r1MLKEM768() throws
> >>>> Exception {
> >>>>>>>> +        File[] pqcFiles = configureHostMLDSA("ML-DSA-65");
> >>>>>>>> +        configureHostWithGroup("SecP256r1MLKEM768");
> >>>>>>>> +        doTestWithOpenSSLClient(pqcFiles[0].getAbsolutePath(),
> >>>>>>> "SecP256r1MLKEM768", null, null);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testClientMLDSA() throws Exception {
> >>>>>>>> +        configureHostRSA();
> >>>>>>>> +        File[] clientFiles =
> >>>>>>> TesterKeystoreGenerator.generatePQCCertificate("testuser",
> >> "ML-DSA-65",
> >>>>>>>> +                null, null);
> >>>>>>>> +        SSLHostConfig sslHostConfig =
> >>>>>>> getTomcatInstance().getConnector().findSslHostConfigs()[0];
> >>>>>>>> +        sslHostConfig.setCertificateVerification("required");
> >>>>>>>> +
> >>>>>>> sslHostConfig.setCaCertificateFile(clientFiles[0].getAbsolutePath());
> >>>>>>>> +        doTestWithOpenSSLClient(new
> >>>>>>> File(TesterSupport.CA_CERT_PEM).getAbsolutePath(), null,
> >>>>>>>> +                clientFiles[0].getAbsolutePath(),
> >>>>>>> clientFiles[1].getAbsolutePath());
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test
> >>>>>>>> +    public void testClientMLDSAwithMLDSAServer() throws Exception {
> >>>>>>>> +        File[] serverFiles = configureHostMLDSA("ML-DSA-65");
> >>>>>>>> +        File[] clientFiles =
> >>>>>>> TesterKeystoreGenerator.generatePQCCertificate("testuser",
> >> "ML-DSA-65",
> >>>>>>>> +                null, null);
> >>>>>>>> +        SSLHostConfig sslHostConfig =
> >>>>>>> getTomcatInstance().getConnector().findSslHostConfigs()[0];
> >>>>>>>> +        sslHostConfig.setCertificateVerification("required");
> >>>>>>>> +
> >>>>>>> sslHostConfig.setCaCertificateFile(clientFiles[0].getAbsolutePath());
> >>>>>>>> +        doTestWithOpenSSLClient(serverFiles[0].getAbsolutePath(),
> >>>> null,
> >>>>>>>> +                clientFiles[0].getAbsolutePath(),
> >>>>>>> clientFiles[1].getAbsolutePath());
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    @Test(expected = SSLHandshakeException.class)
> >>>>>>>> +    public void testHostMLDSAHandshakeFailure() throws Exception {
> >>>>>>>> +        assumePQCSupported();
> >>>>>>>> +        configureHostMLDSA("ML-DSA-65");
> >>>>>>>> +
> >>>>>>>> +        SSLContext sc =
> >>>>>>> SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_2);
> >>>>>>>> +        sc.init(null, new TrustManager[] { new
> >>>>>>> TesterSupport.TrustAllCerts() }, null);
> >>>>>>>> +        TesterSupport.ClientSSLSocketFactory
> >> clientSSLSocketFactory =
> >>>>>>>> +                new
> >>>>>>> TesterSupport.ClientSSLSocketFactory(sc.getSocketFactory());
> >>>>>>>> +        clientSSLSocketFactory.setProtocols(new String[] {
> >>>>>>> Constants.SSL_PROTO_TLSv1_2 });
> >>>>>>>> +
> >>>>>>>
> >>>>
> >> javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(clientSSLSocketFactory);
> >>>>>>>> +
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        tomcat.start();
> >>>>>>>> +        getUrl("https://localhost:"; + getPort() + "/");
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +
> >>>>>>>> +    private void assumePQCSupported() {
> >>>>>>>> +        if (!useOpenSSL) {
> >>>>>>>> +            Assume.assumeTrue("JSSE does not yet support PQC",
> >>>> false);
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        Assume.assumeTrue("PQC requires OpenSSL 3.5+",
> >>>>>>>> +                OpenSSLStatus.getMajorVersion() > 3 ||
> >>>>>>>> +                    OpenSSLStatus.getMajorVersion() == 3 &&
> >>>>>>> OpenSSLStatus.getMinorVersion() >= 5);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    private File[] configureHostMLDSA(String algorithm) throws
> >>>>>>> Exception {
> >>>>>>>> +        File[] pqcFiles =
> >>>>>>> TesterKeystoreGenerator.generatePQCCertificate("localhost",
> >> algorithm,
> >>>>>>>> +                new String[] { "localhost" }, null);
> >>>>>>>> +
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        Connector connector = tomcat.getConnector();
> >>>>>>>> +        SSLHostConfig sslHostConfig =
> >>>>>>> connector.findSslHostConfigs()[0];
> >>>>>>>> +
> >>>>>>>> +        SSLHostConfigCertificate cert = new
> >>>>>>> SSLHostConfigCertificate(sslHostConfig, Type.MLDSA);
> >>>>>>>> +        cert.setCertificateFile(pqcFiles[0].getAbsolutePath());
> >>>>>>>> +        cert.setCertificateKeyFile(pqcFiles[1].getAbsolutePath());
> >>>>>>>> +        sslHostConfig.addCertificate(cert);
> >>>>>>>> +
> >>>>>>>> +        return pqcFiles;
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    private void configureHostRSA() {
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        Connector connector = tomcat.getConnector();
> >>>>>>>> +        SSLHostConfig sslHostConfig =
> >>>>>>> connector.findSslHostConfigs()[0];
> >>>>>>>> +
> >>>>>>>> +        SSLHostConfigCertificate cert = new
> >>>>>>> SSLHostConfigCertificate(sslHostConfig, Type.RSA);
> >>>>>>>> +        cert.setCertificateFile(new
> >>>>>>> File(TesterSupport.LOCALHOST_RSA_CERT_PEM).getAbsolutePath());
> >>>>>>>> +        cert.setCertificateKeyFile(new
> >>>>>>> File(TesterSupport.LOCALHOST_RSA_KEY_PEM).getAbsolutePath());
> >>>>>>>> +        cert.setCertificateKeyPassword(TesterSupport.JKS_PASS);
> >>>>>>>> +        sslHostConfig.addCertificate(cert);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    private void configureHostEC() {
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        Connector connector = tomcat.getConnector();
> >>>>>>>> +        SSLHostConfig sslHostConfig =
> >>>>>>> connector.findSslHostConfigs()[0];
> >>>>>>>> +
> >>>>>>>> +        SSLHostConfigCertificate cert = new
> >>>>>>> SSLHostConfigCertificate(sslHostConfig, Type.EC);
> >>>>>>>> +        cert.setCertificateFile(new
> >>>>>>> File(TesterSupport.LOCALHOST_EC_CERT_PEM).getAbsolutePath());
> >>>>>>>> +        cert.setCertificateKeyFile(new
> >>>>>>> File(TesterSupport.LOCALHOST_EC_KEY_PEM).getAbsolutePath());
> >>>>>>>> +        sslHostConfig.addCertificate(cert);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    private void configureHostWithGroup(String groupName) {
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        Connector connector = tomcat.getConnector();
> >>>>>>>> +        SSLHostConfig sslHostConfig =
> >>>>>>> connector.findSslHostConfigs()[0];
> >>>>>>>> +        sslHostConfig.setGroups(groupName);
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    private void doTest() throws Exception {
> >>>>>>>> +        assumePQCSupported();
> >>>>>>>> +        SSLContext sc =
> >>>>>>> SSLContext.getInstance(Constants.SSL_PROTO_TLSv1_3);
> >>>>>>>> +        sc.init(null, new TrustManager[] { new
> >>>>>>> TesterSupport.TrustAllCerts() }, null);
> >>>>>>>> +
> >>>>>>>
> >>>>
> >> javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        tomcat.start();
> >>>>>>>> +        ByteChunk res = getUrl("https://localhost:"; + getPort() +
> >>>>>>> "/");
> >>>>>>>> +        Assert.assertEquals("OK", res.toString());
> >>>>>>>> +    }
> >>>>>>>> +
> >>>>>>>> +    private void doTestWithOpenSSLClient(String caFile, String
> >>>> groups,
> >>>>>>>> +            String clientCert, String clientKey) throws Exception {
> >>>>>>>> +        assumePQCSupported();
> >>>>>>>> +
> >>>>>>>> +        Tomcat tomcat = getTomcatInstance();
> >>>>>>>> +        tomcat.start();
> >>>>>>>> +
> >>>>>>>> +        String openSSLPath =
> >>>>>>> System.getProperty("tomcat.test.openssl.path");
> >>>>>>>> +        String openSSLLibPath = null;
> >>>>>>>> +        if (openSSLPath == null || openSSLPath.length() == 0) {
> >>>>>>>> +            openSSLPath = "openssl";
> >>>>>>>> +        } else {
> >>>>>>>> +            openSSLLibPath = openSSLPath.substring(0,
> >>>>>>> openSSLPath.lastIndexOf('/'));
> >>>>>>>> +            openSSLLibPath = openSSLLibPath + "/../:" +
> >>>> openSSLLibPath
> >>>>>>> + "/../lib:" + openSSLLibPath + "/../lib64";
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        List<String> cmd = new ArrayList<>();
> >>>>>>>> +        cmd.add(openSSLPath);
> >>>>>>>> +        cmd.add("s_client");
> >>>>>>>> +        cmd.add("-connect");
> >>>>>>>> +        cmd.add("localhost:" + getPort());
> >>>>>>>> +        cmd.add("-CAfile");
> >>>>>>>> +        cmd.add(caFile);
> >>>>>>>> +        cmd.add("-tls1_3");
> >>>>>>>> +        if (groups != null) {
> >>>>>>>> +            cmd.add("-groups");
> >>>>>>>> +            cmd.add(groups);
> >>>>>>>> +        }
> >>>>>>>> +        if (clientCert != null) {
> >>>>>>>> +            cmd.add("-cert");
> >>>>>>>> +            cmd.add(clientCert);
> >>>>>>>> +            cmd.add("-key");
> >>>>>>>> +            cmd.add(clientKey);
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        ProcessBuilder pb = new ProcessBuilder(cmd);
> >>>>>>>> +
> >>>>>>>> +        if (openSSLLibPath != null) {
> >>>>>>>> +            Map<String,String> env = pb.environment();
> >>>>>>>> +            String libraryPath = env.get("LD_LIBRARY_PATH");
> >>>>>>>> +            if (libraryPath == null) {
> >>>>>>>> +                libraryPath = openSSLLibPath;
> >>>>>>>> +            } else {
> >>>>>>>> +                libraryPath = libraryPath + ":" + openSSLLibPath;
> >>>>>>>> +            }
> >>>>>>>> +            env.put("LD_LIBRARY_PATH", libraryPath);
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        pb.redirectErrorStream(true);
> >>>>>>>> +        Process p = pb.start();
> >>>>>>>> +
> >>>>>>>> +        p.getOutputStream().write("GET / HTTP/1.0\r\nHost:
> >>>>>>> localhost\r\n\r\n".getBytes());
> >>>>>>>> +        p.getOutputStream().flush();
> >>>>>>>> +
> >>>>>>>> +        String output = new
> >>>> String(p.getInputStream().readAllBytes());
> >>>>>>>> +
> >>>>>>>> +        Assert.assertTrue("Process did not complete in time",
> >>>>>>> p.waitFor(10, TimeUnit.SECONDS));
> >>>>>>>> +        Assert.assertTrue("TLS handshake failed:\n" + output,
> >>>>>>> output.contains("HTTP/1."));
> >>>>>>>> +        Assert.assertTrue("Unexpected response body:\n" + output,
> >>>>>>> output.contains("OK"));
> >>>>>>>> +    }
> >>>>>>>> +}
> >>>>>>>> diff --git
> >>>>>>> a/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
> >>>>>>> b/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
> >>>>>>>> index 9fd4affde6..00f1772fcc 100644
> >>>>>>>> --- a/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
> >>>>>>>> +++ b/test/org/apache/tomcat/util/net/TesterKeystoreGenerator.java
> >>>>>>>> @@ -19,6 +19,7 @@ package org.apache.tomcat.util.net;
> >>>>>>>>
> >>>>>>>>      import java.io.File;
> >>>>>>>>      import java.io.FileOutputStream;
> >>>>>>>> +import java.io.FileWriter;
> >>>>>>>>      import java.math.BigInteger;
> >>>>>>>>      import java.security.KeyPair;
> >>>>>>>>      import java.security.KeyPairGenerator;
> >>>>>>>> @@ -33,6 +34,8 @@ import org.bouncycastle.asn1.x509.GeneralNames;
> >>>>>>>>      import org.bouncycastle.cert.X509v3CertificateBuilder;
> >>>>>>>>      import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
> >>>>>>>>      import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
> >>>>>>>> +import org.bouncycastle.jce.provider.BouncyCastleProvider;
> >>>>>>>> +import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
> >>>>>>>>      import org.bouncycastle.operator.ContentSigner;
> >>>>>>>>      import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
> >>>>>>>>
> >>>>>>>> @@ -100,4 +103,66 @@ public final class TesterKeystoreGenerator {
> >>>>>>>>
> >>>>>>>>              return keystoreFile;
> >>>>>>>>          }
> >>>>>>>> +
> >>>>>>>> +    /**
> >>>>>>>> +     * Generate temporary PEM files containing a self-signed PQC
> >>>>>>> certificate and private key.
> >>>>>>>> +     *
> >>>>>>>> +     * @param cn        the Common Name for the certificate subject
> >>>>>>>> +     * @param algorithm the PQC algorithm name, e.g. {@code
> >>>>>>> "ML-DSA-44"}, {@code "ML-DSA-65"},
> >>>>>>>> +     *                  or {@code "ML-DSA-87"}
> >>>>>>>> +     * @param sanNames  DNS Subject Alternative Names to include,
> >> or
> >>>>>>> {@code null} for none
> >>>>>>>> +     * @param customizer callback to add extensions to the
> >>>>>>> certificate, or {@code null} for none
> >>>>>>>> +     *
> >>>>>>>> +     * @return a two-element array: {@code [0]} is the certificate
> >>>> PEM
> >>>>>>> file, {@code [1]} is the
> >>>>>>>> +     *         private key PEM file
> >>>>>>>> +     *
> >>>>>>>> +     * @throws Exception if certificate generation fails
> >>>>>>>> +     */
> >>>>>>>> +    public static File[] generatePQCCertificate(String cn, String
> >>>>>>> algorithm, String[] sanNames,
> >>>>>>>> +
> >>>>>>> CertificateExtensionsCustomizer customizer) throws Exception {
> >>>>>>>> +        BouncyCastleProvider bouncyCastleProvider = new
> >>>>>>> BouncyCastleProvider();
> >>>>>>>> +
> >>>>>>>> +        KeyPairGenerator keyPairGenerator =
> >>>>>>> KeyPairGenerator.getInstance(algorithm, bouncyCastleProvider);
> >>>>>>>> +        KeyPair keyPair = keyPairGenerator.generateKeyPair();
> >>>>>>>> +
> >>>>>>>> +        X500Name subject = new X500Name("CN=" + cn);
> >>>>>>>> +        BigInteger serial =
> >>>>>>> BigInteger.valueOf(System.currentTimeMillis());
> >>>>>>>> +        long oneDay = 86400000L;
> >>>>>>>> +        Date notBefore = new Date(System.currentTimeMillis() -
> >>>> oneDay);
> >>>>>>>> +        Date notAfter = new Date(System.currentTimeMillis() + 365L
> >> *
> >>>>>>> oneDay);
> >>>>>>>> +
> >>>>>>>> +        X509v3CertificateBuilder certBuilder = new
> >>>>>>> JcaX509v3CertificateBuilder(subject, serial, notBefore,
> >>>>>>>> +                notAfter, subject, keyPair.getPublic());
> >>>>>>>> +
> >>>>>>>> +        if (sanNames != null && sanNames.length > 0) {
> >>>>>>>> +            GeneralName[] generalNames = new
> >>>>>>> GeneralName[sanNames.length];
> >>>>>>>> +            for (int i = 0; i < sanNames.length; i++) {
> >>>>>>>> +                generalNames[i] = new
> >>>> GeneralName(GeneralName.dNSName,
> >>>>>>> sanNames[i]);
> >>>>>>>> +            }
> >>>>>>>> +
> >>>> certBuilder.addExtension(Extension.subjectAlternativeName,
> >>>>>>> false, new GeneralNames(generalNames));
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        if (customizer != null) {
> >>>>>>>> +            customizer.customize(keyPair, certBuilder);
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        ContentSigner signer = new
> >>>>>>> JcaContentSignerBuilder(algorithm).setProvider(bouncyCastleProvider)
> >>>>>>>> +                .build(keyPair.getPrivate());
> >>>>>>>> +        X509Certificate certificate = new
> >>>>>>> JcaX509CertificateConverter().setProvider(bouncyCastleProvider)
> >>>>>>>> +                .getCertificate(certBuilder.build(signer));
> >>>>>>>> +
> >>>>>>>> +        File certFile = File.createTempFile("test-pqc-cert-",
> >>>> ".pem");
> >>>>>>>> +        certFile.deleteOnExit();
> >>>>>>>> +        try (JcaPEMWriter writer = new JcaPEMWriter(new
> >>>>>>> FileWriter(certFile))) {
> >>>>>>>> +            writer.writeObject(certificate);
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        File keyFile = File.createTempFile("test-pqc-key-",
> >> ".pem");
> >>>>>>>> +        keyFile.deleteOnExit();
> >>>>>>>> +        try (JcaPEMWriter writer = new JcaPEMWriter(new
> >>>>>>> FileWriter(keyFile))) {
> >>>>>>>> +            writer.writeObject(keyPair.getPrivate());
> >>>>>>>> +        }
> >>>>>>>> +
> >>>>>>>> +        return new File[] { certFile, keyFile };
> >>>>>>>> +    }
> >>>>>>>>      }
> >>>>>>>>
> >>>>>>>>
> >>>>>>>>
> >> ---------------------------------------------------------------------
> >>>>>>>> To unsubscribe, e-mail: [email protected]
> >>>>>>>> For additional commands, e-mail: [email protected]
> >>>>>>>>
> >>>>>>>
> >>>>>>>
> >>>>>>> ---------------------------------------------------------------------
> >>>>>>> To unsubscribe, e-mail: [email protected]
> >>>>>>> For additional commands, e-mail: [email protected]
> >>>>>>>
> >>>>>>>
> >>>>>
> >>>>
> >>>>
> >>>> ---------------------------------------------------------------------
> >>>> To unsubscribe, e-mail: [email protected]
> >>>> For additional commands, e-mail: [email protected]
> >>>>
> >>>>
> >>>
> >>
> >>
> >> ---------------------------------------------------------------------
> >> To unsubscribe, e-mail: [email protected]
> >> For additional commands, e-mail: [email protected]
> >>
> >>
> >
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [email protected]
> For additional commands, e-mail: [email protected]
>

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

Reply via email to