Stuck in my basement with no real domain I'm having trouble setting up SSL/TLS on an embedded tomcat instance. And I'm very lost, having tried more dead ends than I can remember. I used this to generate cert and key openssl req -out localhost.crt -key localhost.key \ -newkey rsa:2048 -nodes -sha256 \ -subj '/CN=localhost' -extensions EXT -config <( \ printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment\nextendedKeyUsage=serverAuth") and try to apply those with -Djavax.net.ssl.trustStore=/tmp/key/localhost.crt -Djavax.net.ssl.trustStorePassword=changeit -Djavax.net.ssl.trustStoreType=PKCS12 -Djavax.net.ssl.keyStore=/tmp/key/localhost.key -Djavax.net.ssl.keyStorePassword=changeit -Dhttps.protocols=TLSv1.2,TLSv1.3 -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3 I get "toDerInputStream rejects tag type 45". That error rears its ugly head in several places such when adding those same two localhost files to a pkcs12 rendition of the OS's cacerts file using below. The crt goes in quietly. (I'm couldn't convince my self of the openssl equivalent of this command) root@gitanmax:/tmp/key# keytool -importkeystore -srckeystore localhost.key -srckeypass changeit -srcstoretype pkcs12 -destkeystore cacerts.pkcs12 -deststoretype pkcs12 -srcalias localhost -destalias tomcatlocal Importing keystore localhost.key to cacerts.pkcs12... Enter destination keystore password: changeit Enter source keystore password: changeit keytool error: java.io.IOException: toDerInputStream rejects tag type 45 My actual first attempt was to just use keytool to generate a cert interactively, filling in my own bogus values but that hit the domain name mismatch gotcha. Then, there's confusion on the java side as well. My plan was to add a connector for my webapp embeddedTomcat = new Tomcat(); logger.debug("handing in CATALINA_HOME as " + System.getenv("CATALINA_HOME")); embeddedTomcat.setPort(tomcatPort-1); embeddedTomcat.enableNaming(); Connector defaultConnector = embeddedTomcat.getConnector(); // an init, really defaultConnector.setSecure(true); // force https? Service service = embeddedTomcat.getService(); service.addConnector(addTLSConnector(tomcatPort)); logger.info("tomcatd listening on port " + tomcatPort); String contextRootPath = System.getenv("CATALINA_HOME"); logger.debug("contextRootPath is {}", contextRootPath); Context contextTomcat = embeddedTomcat.addContext("", new File(contextRootPath + "/sgs").getAbsolutePath()); logger.debug("host: {}, general context basename {}", embeddedTomcat.getHost(), contextTomcat.getBaseName()); //TODO: cut from here ... java.time.LocalDateTime bootDT = java.time.LocalDateTime.now(); Tomcat.addServlet(contextTomcat, "monitor", new HttpServlet() { @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ServletOutputStream out = resp.getOutputStream(); out.write("SGS Agent monitor: SGS_OK\n".getBytes()); out.write(("Up since " + bootDT.toString()).getBytes()); out.write(("\nTime now " + java.time.LocalDateTime.now().toString()).getBytes()); out.flush(); out.close(); } }); contextTomcat.addServletMappingDecoded("/monitor", "monitor"); // My webapp Context sgsContext = embeddedTomcat.addWebapp("/sgs", contextRootPath + "/sgs"); // /sgs.war embeddedTomcat.start(); embeddedTomcat.getServer().await(); private Connector addTLSConnector(Connector connector, int tcport) { File keyFile = new File (System.getProperty("SGSSRVR_keystoreFile")); if (! keyFile.exists()) throw new RuntimeException("where's the keystore?"); connector.setPort(tcport); connector.setSecure(true); connector.setScheme("https"); connector.setProperty("protocol", "HTTP/1.1"); connector.setProperty("sslProtocol", "TLS"); connector.setProperty("address","127.0.0.1"); connector.setProperty("clientAuth", "false"); connector.setProperty("maxThreads", "200"); connector.setProperty("protocol", "org.apache.coyote.http11.Http11NioProtocol"); connector.setProperty("SSLEnabled", "true"); return connector; } private Connector addTLSConnector(int tcport) { Connector connector = new Connector(); addTLSConnector(connector, tcport); return connector; } That "monitor" works, on a separate port, on either http or https as per defaultConnector.setSecure(isHttps); but possibly because I've diddle with chrome's security settings. I have a similar "monitor" as a servlet which I use as my is-anybody-home call to start my analyses. And of course can also use it via the browser at /seg/webmonitor. All these behave when SSL is not in play, but I'm forced, very much against my will, to use SSL so here I am bother the good folks on this list for more help. |
On 19/01/2021 04:02, Rob Sargent wrote:
> > Stuck in my basement with no real domain I'm having trouble setting up > SSL/TLS on an embedded tomcat instance. And I'm very lost, having tried > more dead ends than I can remember. > > I used this to generate cert and key > openssl req -out localhost.crt -key localhost.key \ > -newkey rsa:2048 -nodes -sha256 \ > -subj '/CN=localhost' -extensions EXT -config <( \ > printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = > dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature, > nonRepudiation, keyEncipherment, > dataEncipherment\nextendedKeyUsage=serverAuth") That isn't a certificate and key. It is a certificate signing request (csr) and a key. You might want to take a look at: http://tomcat.apache.org/presentations.html search for "TLS key/certificate generation". That creates a private CA and then uses it to issue a cert for localhost. Having a private CA lets you test stuff things client certificate authentication. Note that this dates from before the subjectAltName requirements so it will need some tweaks (-ext san=dns:localhost) Alternatively, grab the (and I can't emphasis this enough) *TEST* keys and certs from the Tomcat unit tests and use those: https://github.com/apache/tomcat/tree/master/test/org/apache/tomcat/util/net > and try to apply those with > > -Djavax.net.ssl.trustStore=/tmp/key/localhost.crt > -Djavax.net.ssl.trustStorePassword=changeit > -Djavax.net.ssl.trustStoreType=PKCS12 > -Djavax.net.ssl.keyStore=/tmp/key/localhost.key > -Djavax.net.ssl.keyStorePassword=changeit > -Dhttps.protocols=TLSv1.2,TLSv1.3 > -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3 As a general rule it is always better to configure a Tomcat connector explicitly rather than relay on the fallback to the system properties. > I get "toDerInputStream rejects tag type 45". > > That error rears its ugly head in several places such when adding those > same two localhost files to a pkcs12 rendition of the OS's cacerts file > using below. The crt goes in quietly. (I'm couldn't convince my self of > the openssl equivalent of this command) > root@gitanmax:/tmp/key# keytool -importkeystore -srckeystore > localhost.key -srckeypass changeit -srcstoretype pkcs12 -destkeystore > cacerts.pkcs12 -deststoretype pkcs12 -srcalias localhost -destalias > tomcatlocal > Importing keystore localhost.key to cacerts.pkcs12... > Enter destination keystore password: changeit > Enter source keystore password: changeit > keytool error: java.io.IOException: toDerInputStream rejects tag type 45 > > My actual first attempt was to just use keytool to generate a cert > interactively, filling in my own bogus values but that hit the domain > name mismatch gotcha. "-ext san=dns:localhost" should help > Then, there's confusion on the java side as well. > > My plan was to add a connector for my webapp > > embeddedTomcat = new Tomcat(); > logger.debug("handing in CATALINA_HOME as " + > System.getenv("CATALINA_HOME")); > embeddedTomcat.setPort(tomcatPort-1); > embeddedTomcat.enableNaming(); > Connector defaultConnector = embeddedTomcat.getConnector(); // an init, > really > defaultConnector.setSecure(true); // force https? Nope. That simply tells Tomcat to treat connections as secure. You don't want that except in some proxy scenarios. > Service service = embeddedTomcat.getService(); > service.addConnector(addTLSConnector(tomcatPort)); > > logger.info("tomcatd listening on port " + tomcatPort); > String contextRootPath = System.getenv("CATALINA_HOME"); > logger.debug("contextRootPath is {}", contextRootPath); > Context contextTomcat = embeddedTomcat.addContext("", new > File(contextRootPath + "/sgs").getAbsolutePath()); > logger.debug("host: {}, general context basename {}", > embeddedTomcat.getHost(), contextTomcat.getBaseName()); > //TODO: cut from here ... > java.time.LocalDateTime bootDT = java.time.LocalDateTime.now(); > Tomcat.addServlet(contextTomcat, "monitor", new HttpServlet() { > @Override > protected void doGet(HttpServletRequest req, HttpServletResponse resp) > throws ServletException, IOException { > ServletOutputStream out = resp.getOutputStream(); > out.write("SGS Agent monitor: SGS_OK\n".getBytes()); > out.write(("Up since " + bootDT.toString()).getBytes()); > out.write(("\nTime now " + > java.time.LocalDateTime.now().toString()).getBytes()); > out.flush(); > out.close(); > } > }); > contextTomcat.addServletMappingDecoded("/monitor", "monitor"); > // My webapp > Context sgsContext = embeddedTomcat.addWebapp("/sgs", contextRootPath + > "/sgs"); // /sgs.war > embeddedTomcat.start(); > embeddedTomcat.getServer().await(); > > private Connector addTLSConnector(Connector connector, int tcport) { > File keyFile = new File (System.getProperty("SGSSRVR_keystoreFile")); > if (! keyFile.exists()) throw new RuntimeException("where's the > keystore?"); > connector.setPort(tcport); > connector.setSecure(true); > connector.setScheme("https"); > connector.setProperty("protocol", "HTTP/1.1"); > connector.setProperty("sslProtocol", "TLS"); > connector.setProperty("address","127.0.0.1"); > connector.setProperty("clientAuth", "false"); > connector.setProperty("maxThreads", "200"); > connector.setProperty("protocol", > "org.apache.coyote.http11.Http11NioProtocol"); > connector.setProperty("SSLEnabled", "true"); This the line the enables TLS. > return connector; > } > > private Connector addTLSConnector(int tcport) { > Connector connector = new Connector(); > addTLSConnector(connector, tcport); > return connector; > } > > That "monitor" works, on a separate port, on either http or https as per > defaultConnector.setSecure(isHttps); > but possibly because I've diddle with chrome's security settings. > > I have a similar "monitor" as a servlet which I use as my > is-anybody-home call to start my analyses. And of course can also use > it via the browser at /seg/webmonitor. > > All these behave when SSL is not in play, but I'm forced, very much > against my will, to use SSL so here I am bother the good folks on this > list for more help. My recommendation would be: - start with the test certs from the Tomcat unit tests as they are known to work - get your code working so you know the code is good - they try with your own keys certificates Mark --------------------------------------------------------------------- To unsubscribe, e-mail: [hidden email] For additional commands, e-mail: [hidden email] |
> My recommendation would be: > - start with the test certs from the Tomcat unit tests as they are known > to work > - get your code working so you know the code is good > - they try with your own keys certificates > > Mark > That's exactly what I'll do next. Thank you very much. rjs |
In reply to this post by Rob Sargent
On Tue, Jan 19, 2021 at 5:02 AM Rob Sargent <[hidden email]> wrote:
> > Stuck in my basement with no real domain I'm having trouble setting up > SSL/TLS on an embedded tomcat instance. And I'm very lost, having tried > more dead ends than I can remember. > > I used this to generate cert and key > openssl req -out localhost.crt -key localhost.key \ > -newkey rsa:2048 -nodes -sha256 \ > -subj '/CN=localhost' -extensions EXT -config <( \ > printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = > dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature, > nonRepudiation, keyEncipherment, > dataEncipherment\nextendedKeyUsage=serverAuth") > > and try to apply those with > > -Djavax.net.ssl.trustStore=/tmp/key/localhost.crt > -Djavax.net.ssl.trustStorePassword=changeit > -Djavax.net.ssl.trustStoreType=PKCS12 > -Djavax.net.ssl.keyStore=/tmp/key/localhost.key > -Djavax.net.ssl.keyStorePassword=changeit > -Dhttps.protocols=TLSv1.2,TLSv1.3 > -Djdk.tls.client.protocols=TLSv1.2,TLSv1.3 > > I get "toDerInputStream rejects tag type 45". > > That error rears its ugly head in several places such when adding those > same two localhost files to a pkcs12 rendition of the OS's cacerts file > using below. The crt goes in quietly. (I'm couldn't convince my self of > the openssl equivalent of this command) > root@gitanmax:/tmp/key# keytool -importkeystore -srckeystore > localhost.key -srckeypass changeit -srcstoretype pkcs12 -destkeystore > cacerts.pkcs12 -deststoretype pkcs12 -srcalias localhost -destalias > tomcatlocal > Importing keystore localhost.key to cacerts.pkcs12... > Enter destination keystore password: changeit > Enter source keystore password: changeit > keytool error: java.io.IOException: toDerInputStream rejects tag type 45 > > My actual first attempt was to just use keytool to generate a cert > interactively, filling in my own bogus values but that hit the domain > name mismatch gotcha. > > Then, there's confusion on the java side as well. > > My plan was to add a connector for my webapp > > embeddedTomcat = new Tomcat(); > logger.debug("handing in CATALINA_HOME as " + > System.getenv("CATALINA_HOME")); > embeddedTomcat.setPort(tomcatPort-1); > embeddedTomcat.enableNaming(); > Connector defaultConnector = embeddedTomcat.getConnector(); // an init, > really > defaultConnector.setSecure(true); // force https? > > Service service = embeddedTomcat.getService(); > service.addConnector(addTLSConnector(tomcatPort)); > > logger.info("tomcatd listening on port " + tomcatPort); > String contextRootPath = System.getenv("CATALINA_HOME"); > logger.debug("contextRootPath is {}", contextRootPath); > Context contextTomcat = embeddedTomcat.addContext("", new > File(contextRootPath + "/sgs").getAbsolutePath()); > logger.debug("host: {}, general context basename {}", > embeddedTomcat.getHost(), contextTomcat.getBaseName()); > //TODO: cut from here ... > java.time.LocalDateTime bootDT = java.time.LocalDateTime.now(); > Tomcat.addServlet(contextTomcat, "monitor", new HttpServlet() { > @Override > protected void doGet(HttpServletRequest req, HttpServletResponse resp) > throws ServletException, IOException { > ServletOutputStream out = resp.getOutputStream(); > out.write("SGS Agent monitor: SGS_OK\n".getBytes()); > out.write(("Up since " + bootDT.toString()).getBytes()); > out.write(("\nTime now " + > java.time.LocalDateTime.now().toString()).getBytes()); > out.flush(); > out.close(); > } > }); > contextTomcat.addServletMappingDecoded("/monitor", "monitor"); > // My webapp > Context sgsContext = embeddedTomcat.addWebapp("/sgs", contextRootPath + > "/sgs"); // /sgs.war > embeddedTomcat.start(); > embeddedTomcat.getServer().await(); > > private Connector addTLSConnector(Connector connector, int tcport) { > File keyFile = new File (System.getProperty("SGSSRVR_keystoreFile")); > if (! keyFile.exists()) throw new RuntimeException("where's the > keystore?"); > connector.setPort(tcport); > connector.setSecure(true); > connector.setScheme("https"); > connector.setProperty("protocol", "HTTP/1.1"); > connector.setProperty("sslProtocol", "TLS"); > connector.setProperty("address","127.0.0.1"); > connector.setProperty("clientAuth", "false"); > connector.setProperty("maxThreads", "200"); > connector.setProperty("protocol", > "org.apache.coyote.http11.Http11NioProtocol"); > connector.setProperty("SSLEnabled", "true"); > return connector; > } > > private Connector addTLSConnector(int tcport) { > Connector connector = new Connector(); > addTLSConnector(connector, tcport); > return connector; > } > > That "monitor" works, on a separate port, on either http or https as per > defaultConnector.setSecure(isHttps); > but possibly because I've diddle with chrome's security settings. > > I have a similar "monitor" as a servlet which I use as my > is-anybody-home call to start my analyses. And of course can also use > it via the browser at /seg/webmonitor. > > All these behave when SSL is not in play, but I'm forced, very much > against my will, to use SSL so here I am bother the good folks on this > list for more help. > Dealing with a complex configuration using the embedded API can be a bit problematic. If you're using a recent Tomcat 9 (9.0.38+), you could use the code generator that was designed for ahead of time compilation to help you out: it will produce Tomcat embedded equivalent code to the server.xml you're using. I would think server.xml is easier to get right, and there are probably tons of examples that you can use to help out. Then you can cut and paste the generated code and refine it as needed. If you want to try it out, you can add "-generateCode" to the Tomcat command line, such as "./bin/catalina.sh run -generateCode". The code will be generated in the work directory. Of course, that won't help you get the certificates right. Good luck ! Rémy |
On 1/20/21 8:15 AM, Rémy Maucherat wrote: > On Tue, Jan 19, 2021 at 5:02 AM Rob Sargent <[hidden email]> wrote: > > Dealing with a complex configuration using the embedded API can be a bit > problematic. If you're using a recent Tomcat 9 (9.0.38+), you could use the > code generator that was designed for ahead of time compilation to help you > out: it will produce Tomcat embedded equivalent code to the server.xml > you're using. I would think server.xml is easier to get right, and there > are probably tons of examples that you can use to help out. Then you can > cut and paste the generated code and refine it as needed. > > If you want to try it out, you can add "-generateCode" to the Tomcat > command line, such as "./bin/catalina.sh run -generateCode". The code will > be generated in the work directory. > > Of course, that won't help you get the certificates right. Good luck ! > > Rémy catalina.sh and no server.xml. My intent was to avoid the addition of the entire customary web site infrastructure when all I really wanted was the correct handling of a Selector (and https communication on same). And now, thanks to Mark's suggestion about Tomcat's own test keys I have reached my goal, at least in a dev environment. Now on to scaling and AWS deployment. Wish me luck. |
For completeness, I must admit that I was unable to use PKCS12 files. I had to use JKS format. I copied and transformed my cacerts files as per keytool recommendation: keytool -importkeystore -srckeystore /usr/lib/jvm/java-15-oracle/lib/security/cacerts -destkeystore /tmp/key/cacerts.pkcs12 -deststoretype pkcs12 Then add tomcat's localhost key keytool -importkeystore -srckeystore localhost-rsa-key.pem -srcstoretype pkcs12 -destkeystore /tmp/key/cacerts.pkcs12 -deststoretype pkcs12 -srcalias tomcat -destalias tomcat keytool error: java.io.IOException: toDerInputStream rejects tag type 45 Try to get the alias from the .pems keytool -list -keystore localhost-rsa-cert.pem -storetype pkcs12 keytool error: java.io.IOException: toDerInputStream rejects tag type 67 keytool -list -keystore localhost-rsa-key.pem -storetype pkcs12 keytool error: java.io.IOException: toDerInputStream rejects tag type 45 I'm certainly doing something wrong, but I'm sticking with JKS for now. > > > |
Rob,
On 1/22/21 15:21, Rob Sargent wrote: > > For completeness, I must admit that I was unable to use PKCS12 files. I > had to use JKS format. > > I copied and transformed my cacerts files as per keytool recommendation: > > keytool -importkeystore -srckeystore > /usr/lib/jvm/java-15-oracle/lib/security/cacerts -destkeystore > /tmp/key/cacerts.pkcs12 -deststoretype pkcs12 > > Then add tomcat's localhost key > > keytool -importkeystore -srckeystore localhost-rsa-key.pem > -srcstoretype pkcs12 -destkeystore /tmp/key/cacerts.pkcs12 > -deststoretype pkcs12 -srcalias tomcat -destalias tomcat > keytool error: java.io.IOException: toDerInputStream rejects tag > type 45 You are telling keytool to read-in localhost-rsa-key.pem as a PKCS12 file, which is most likely wrong. You don't want to import a keystore, you want to import a key. Unfortunately, keytool doesn't allow that. But openssl does: $ openssl pkcs12 -export -in localhost-rsa.crt -inkey localhost-rsa-key.pem -certfile CA-intermediate.crt -out localhost.p12 -chain Now you can import that keystore into your cacerts file: $ keytool -importkeystore -srckeystore localhost.p12 -srcstoretype pkcs12 -destkeystore /tmp/key/cacerts.pkcs12 -deststoretype pkcs12 -srcalias tomcat -destalias tomcat > Try to get the alias from the .pems > > keytool -list -keystore localhost-rsa-cert.pem -storetype pkcs12 > keytool error: java.io.IOException: toDerInputStream rejects tag > type 67 > keytool -list -keystore localhost-rsa-key.pem -storetype pkcs12 > keytool error: java.io.IOException: toDerInputStream rejects tag > type 45 > > I'm certainly doing something wrong, but I'm sticking with JKS for now. PEM files aren't keystores, so keytool can do almost nothing with them. You cam import a PEM certificate, but not its key (directly). Why are you copying everything from the JVM's cacerts file into your keystore? Maybe I'm confused about what you are trying to do. Most people just want to mint a key+cert and have Tomcat use that for TLS. You can do that very simply: $ keytool -genkey -keyalg RSA -sigalg SHA256withRSA -keysize 4096 -alias ${HOSTNAME} -keystore ${HOSTNAME}.p12 -storetype PKCS12 -ext san=dns:${HOSTNAME} Fill-out all the stuff. This gives you a new RSA key and a self-signed certificate. If self-signed is okay with you, you are done. If you want to have that signed by a CA, then you: $ keytool -certreq -alias ${HOSTNAME} -file ${HOSTNAME}.csr -keystore ${HOSTNAME}.p12 -storetype PKCS12 Now you have a CSR in ${HOSTNAME}.csr. Send it to your CA For signature. Now import their signed cert into your keystore: (CA's root first, if necessary) $ keytool -import -alias [Authority.CA] -trustcacerts -file [authority's CA cert] -keystore ${HOSTNAME}.jks (CA's intermediate, if necessary) $ keytool -import -alias [Authority.intermediate] -trustcacerts -file [authority's intermediate cert] -keystore ${HOSTNAME}.jks (Finally, your server's newly-signed cert) $ keytool -import -alias ${HOSTNAME} -file ${HOSTNAME}.crt -keystore ${HOSTNAME}.jks Configure localhost.p12 as your keystore in <Certificate> and you should be done. There is no need to merge-in the JVM's trust store into your server's key store. Even better, if you like working with PEM files better (I do!), you don't every have to run keytool or use a PKCS12 or JKS file. Just use the PEM file in: <Certificate type="RSA" certicicateKeyFile=".key file goes here" certificateFile=".crt file goes here" /> Hope that helps, -chris --------------------------------------------------------------------- To unsubscribe, e-mail: [hidden email] For additional commands, e-mail: [hidden email] |
On 1/22/21 3:06 PM, Christopher Schultz wrote: > > You are telling keytool to read-in localhost-rsa-key.pem as a PKCS12 > file, which is most likely wrong. You don't want to import a keystore, > you want to import a key. Unfortunately, keytool doesn't allow that. > But openssl does: > > $ openssl pkcs12 -export -in localhost-rsa.crt -inkey > localhost-rsa-key.pem -certfile CA-intermediate.crt -out localhost.p12 > -chain > > Now you can import that keystore into your cacerts file: > > $ keytool -importkeystore -srckeystore localhost.p12 > -srcstoretype pkcs12 -destkeystore /tmp/key/cacerts.pkcs12 > -deststoretype pkcs12 -srcalias tomcat -destalias tomcat > > PEM files aren't keystores, so keytool can do almost nothing with > them. You cam import a PEM certificate, but not its key (directly). > > Why are you copying everything from the JVM's cacerts file into your > keystore? Maybe I'm confused about what you are trying to do. > First for practice/sandbox. Then if it worked I could do the same to actual cacerts and have the JVM find it without further ado. I will take the remainder of your message under strong advisement. Thank you, very very much. (I'm not sure, but I think I can get away with a self-sign cert.) |
Free forum by Nabble | Edit this page |