You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2020/05/29 15:18:13 UTC

[tomcat] branch master updated: Implement more of the SSL env

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

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


The following commit(s) were added to refs/heads/master by this push:
     new d381b0b  Implement more of the SSL env
d381b0b is described below

commit d381b0b84a168681944e202a63a294766a11926d
Author: remm <re...@apache.org>
AuthorDate: Fri May 29 17:17:51 2020 +0200

    Implement more of the SSL env
    
    With a test case to see the result. The rest seems difficult to
    implement.
---
 .../catalina/valves/rewrite/ResolverImpl.java      |  68 +++++++++--
 .../apache/tomcat/util/net/TestResolverSSL.java    | 134 +++++++++++++++++++++
 2 files changed, 189 insertions(+), 13 deletions(-)

diff --git a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java
index ea44acc..51566f0 100644
--- a/java/org/apache/catalina/valves/rewrite/ResolverImpl.java
+++ b/java/org/apache/catalina/valves/rewrite/ResolverImpl.java
@@ -18,15 +18,21 @@ package org.apache.catalina.valves.rewrite;
 
 import java.io.IOException;
 import java.nio.charset.Charset;
+import java.security.cert.CertificateEncodingException;
 import java.security.cert.X509Certificate;
 import java.util.Calendar;
+import java.util.Set;
 import java.util.concurrent.TimeUnit;
 
 import org.apache.catalina.WebResource;
 import org.apache.catalina.WebResourceRoot;
 import org.apache.catalina.connector.Request;
+import org.apache.tomcat.util.codec.binary.Base64;
 import org.apache.tomcat.util.http.FastHttpDateFormat;
 import org.apache.tomcat.util.net.SSLSupport;
+import org.apache.tomcat.util.net.openssl.ciphers.Cipher;
+import org.apache.tomcat.util.net.openssl.ciphers.EncryptionLevel;
+import org.apache.tomcat.util.net.openssl.ciphers.OpenSSLCipherConfigurationParser;
 
 public class ResolverImpl extends Resolver {
 
@@ -139,20 +145,39 @@ public class ResolverImpl extends Resolver {
     public String resolveSsl(String key) {
         SSLSupport sslSupport = (SSLSupport) request.getAttribute(SSLSupport.SESSION_MGR);
         try {
-            // FIXME SSL_SESSION_RESUMED
-            // FIXME SSL_SECURE_RENEG
-            // FIXME SSL_CIPHER_EXPORT
-            // FIXME SSL_CIPHER_ALGKEYSIZE
-            // FIXME SSL_COMPRESS_METHOD
+            // FIXME SSL_SESSION_RESUMED in SSLHostConfig
+            // FIXME SSL_SECURE_RENEG in SSLHostConfig
+            // FIXME SSL_COMPRESS_METHOD in SSLHostConfig
+            // FIXME SSL_TLS_SNI from handshake
             // FIXME SSL_SRP_USER
             // FIXME SSL_SRP_USERINFO
-            // FIXME SSL_TLS_SNI
-            if (key.equals("SSL_PROTOCOL")) {
+            if (key.equals("HTTPS")) {
+                return String.valueOf(sslSupport != null);
+            } else if (key.equals("SSL_PROTOCOL")) {
                 return sslSupport.getProtocol();
             } else if (key.equals("SSL_SESSION_ID")) {
                 return sslSupport.getSessionId();
             } else if (key.equals("SSL_CIPHER")) {
                 return sslSupport.getCipherSuite();
+            } else if (key.equals("SSL_CIPHER_EXPORT")) {
+                String cipherSuite = sslSupport.getCipherSuite();
+                Set<Cipher> cipherList = OpenSSLCipherConfigurationParser.parse(cipherSuite);
+                if (cipherList.size() == 1) {
+                    Cipher cipher = cipherList.iterator().next();
+                    if (cipher.getLevel().equals(EncryptionLevel.EXP40)
+                            || cipher.getLevel().equals(EncryptionLevel.EXP56)) {
+                        return "true";
+                    } else {
+                        return "false";
+                    }
+                }
+            } else if (key.equals("SSL_CIPHER_ALGKEYSIZE")) {
+                String cipherSuite = sslSupport.getCipherSuite();
+                Set<Cipher> cipherList = OpenSSLCipherConfigurationParser.parse(cipherSuite);
+                if (cipherList.size() == 1) {
+                    Cipher cipher = cipherList.iterator().next();
+                    return String.valueOf(cipher.getAlg_bits());
+                }
             } else if (key.equals("SSL_CIPHER_USEKEYSIZE")) {
                 return sslSupport.getKeySize().toString();
             } else if (key.startsWith("SSL_CLIENT_")) {
@@ -166,9 +191,9 @@ public class ResolverImpl extends Resolver {
                         key = key.substring("SAN_OTHER_msUPN_".length());
                         // FIXME return certificates[0].getSubjectAlternativeNames()
                     } else if (key.equals("CERT_RFC4523_CEA")) {
-                        // FIXME return certificates[0];
+                        // FIXME return certificates[0]
                     } else if (key.equals("VERIFY")) {
-                        // FIXME return certificates[0];
+                        // FIXME return verification state
                     }
                 }
             } else if (key.startsWith("SSL_SERVER_")) {
@@ -199,7 +224,7 @@ public class ResolverImpl extends Resolver {
             return certificates[0].getSubjectDN().getName();
         } else if (key.startsWith("S_DN_")) {
             key = key.substring("S_DN_".length());
-            // FIXME return certificates[0].getSubjectX500Principal().?;
+            // FIXME would need access to X500Name from X500Principal
         } else if (key.startsWith("SAN_Email_")) {
             key = key.substring("SAN_Email_".length());
             // FIXME return certificates[0].getSubjectAlternativeNames()
@@ -210,7 +235,7 @@ public class ResolverImpl extends Resolver {
             return certificates[0].getIssuerDN().getName();
         } else if (key.startsWith("I_DN_")) {
             key = key.substring("I_DN_".length());
-            // FIXME return certificates[0].getIssuerX500Principal().?;
+            // FIXME would need access to X500Name from X500Principal
         } else if (key.equals("V_START")) {
             return String.valueOf(certificates[0].getNotBefore().getTime());
         } else if (key.equals("V_END")) {
@@ -227,14 +252,31 @@ public class ResolverImpl extends Resolver {
         } else if (key.equals("A_KEY")) {
             return certificates[0].getPublicKey().getAlgorithm();
         } else if (key.equals("CERT")) {
-            // FIXME return certificates[0] to pem
+            try {
+                return toPEM(certificates[0]);
+            } catch (CertificateEncodingException e) {
+            }
         } else if (key.startsWith("CERT_CHAIN_")) {
             key = key.substring("CERT_CHAIN_".length());
-            // FIXME return certificates[n] to pem
+            try {
+                return toPEM(certificates[Integer.parseInt(key)]);
+            } catch (NumberFormatException | CertificateEncodingException e) {
+                // Ignore
+            }
         }
         return null;
     }
 
+    private String toPEM(X509Certificate certificate) throws CertificateEncodingException {
+        StringBuilder result = new StringBuilder();
+        result.append("-----BEGIN CERTIFICATE-----");
+        result.append(System.lineSeparator());
+        Base64 b64 = new Base64(64);
+        result.append(b64.encodeAsString(certificate.getEncoded()));
+        result.append("-----END CERTIFICATE-----");
+        return result.toString();
+    }
+
     @Override
     public String resolveHttp(String key) {
         String header = request.getHeader(key);
diff --git a/test/org/apache/tomcat/util/net/TestResolverSSL.java b/test/org/apache/tomcat/util/net/TestResolverSSL.java
new file mode 100644
index 0000000..d58c3bc
--- /dev/null
+++ b/test/org/apache/tomcat/util/net/TestResolverSSL.java
@@ -0,0 +1,134 @@
+/*
+ * 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.IOException;
+import java.io.PrintWriter;
+
+import jakarta.servlet.ServletException;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import org.apache.catalina.Container;
+import org.apache.catalina.connector.Request;
+import org.apache.catalina.connector.Response;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.catalina.valves.ValveBase;
+import org.apache.catalina.valves.rewrite.Resolver;
+import org.apache.catalina.valves.rewrite.ResolverImpl;
+import org.apache.tomcat.util.buf.ByteChunk;
+
+public class TestResolverSSL extends TomcatBaseTest {
+
+    @Test
+    public void testSslEnv() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        Container root = tomcat.getHost().findChild("");
+        root.getPipeline().addValve(new ResolverTestValve());
+
+        tomcat.start();
+        ByteChunk res = getUrl("https://localhost:" + getPort() + "/protected");
+        // Just look a bit at the result
+        System.out.println(res.toString());
+        Assert.assertTrue(res.toString().indexOf("OK") > 0);
+    }
+
+    // List from https://httpd.apache.org/docs/2.4/mod/mod_ssl.html#envvars
+    private static final String[] keys = {
+            "HTTPS",
+            "SSL_PROTOCOL",
+            "SSL_SESSION_ID",
+            "SSL_SESSION_RESUMED",
+            "SSL_SECURE_RENEG",
+            "SSL_CIPHER",
+            "SSL_CIPHER_EXPORT",
+            "SSL_CIPHER_USEKEYSIZE",
+            "SSL_CIPHER_ALGKEYSIZE",
+            "SSL_COMPRESS_METHOD",
+            "SSL_VERSION_INTERFACE",
+            "SSL_VERSION_LIBRARY",
+            "SSL_CLIENT_M_VERSION",
+            "SSL_CLIENT_M_SERIAL",
+            "SSL_CLIENT_S_DN",
+            "SSL_CLIENT_S_DN_CN", // CN component
+            "SSL_CLIENT_S_DN_O", // O component
+            "SSL_CLIENT_S_DN_C", // C component
+            "SSL_CLIENT_SAN_Email_n", // FXIME: n
+            "SSL_CLIENT_SAN_DNS_n", // FXIME: n
+            "SSL_CLIENT_SAN_OTHER_msUPN_n", // FXIME: n
+            "SSL_CLIENT_I_DN",
+            "SSL_CLIENT_I_DN_x509", // FXIME: x509
+            "SSL_CLIENT_V_START",
+            "SSL_CLIENT_V_END",
+            "SSL_CLIENT_V_REMAIN",
+            "SSL_CLIENT_A_SIG",
+            "SSL_CLIENT_A_KEY",
+            "SSL_CLIENT_CERT",
+            "SSL_CLIENT_CERT_CHAIN_0",
+            "SSL_CLIENT_CERT_RFC4523_CEA",
+            "SSL_CLIENT_VERIFY",
+            "SSL_SERVER_M_VERSION",
+            "SSL_SERVER_M_SERIAL",
+            "SSL_SERVER_S_DN",
+            "SSL_SERVER_SAN_Email_n", // FXIME: n
+            "SSL_SERVER_SAN_DNS_n", // FXIME: n
+            "SSL_SERVER_SAN_OTHER_dnsSRV_n", // FXIME: n
+            "SSL_SERVER_S_DN_CN", // CN component
+            "SSL_SERVER_S_DN_O", // O component
+            "SSL_SERVER_S_DN_C", // C component
+            "SSL_SERVER_I_DN",
+            "SSL_SERVER_I_DN_x509", // FXIME: x509
+            "SSL_SERVER_V_START",
+            "SSL_SERVER_V_END",
+            "SSL_SERVER_A_SIG",
+            "SSL_SERVER_A_KEY",
+            "SSL_SERVER_CERT",
+            "SSL_SRP_USER",
+            "SSL_SRP_USERINFO",
+            "SSL_TLS_SNI" };
+
+    public class ResolverTestValve extends ValveBase {
+
+        @Override
+        public void invoke(Request request, Response response)
+                throws IOException, ServletException {
+            PrintWriter writer = response.getWriter();
+            Resolver resolver = new ResolverImpl(request);
+            for (String key : keys) {
+                resolve(key, resolver, writer);
+            }
+            writer.println("OK");
+        }
+
+        private void resolve(String key, Resolver resolver, PrintWriter writer) {
+            writer.println("[" + key + "] " + resolver.resolveSsl(key));
+        }
+    }
+
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+
+        Tomcat tomcat = getTomcatInstance();
+
+        TesterSupport.configureClientCertContext(tomcat);
+
+        TesterSupport.configureClientSsl();
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org