Home > Enterprise >  How to use GoDaddy SSL Certificate with Spring Boot Embedded Tomcat Server?
How to use GoDaddy SSL Certificate with Spring Boot Embedded Tomcat Server?

Time:11-07

I am working on a website I inherited. The website is made in Spring Boot with embedded Tomcat server. It is using a .jks file for HTTPS. The SSL certificate has expired and I am trying to make a ne .jks file from the files received from Godaddy. There is a document that states how to go about it but something is missing.

These are the steps in document to create .jks file:

Security Settings
C:\trash\keyproc>openssl req -new -newkey rsa:2048 -nodes -keyout website_name_here.key -out website_name_here.csr
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:XX
State or Province Name (full name) [Some-State]:XXXXX
Locality Name (eg, city) []:XXXX
Organization Name (eg, company) [Internet Widgits Pty Ltd]:XXXXX
Organizational Unit Name (eg, section) []:Software Development
Common Name (e.g. server FQDN or YOUR name) []:website_name_here.co
Email Address []:[email protected]

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:pwd_here
An optional company name []:xxxxx
Two files are generated website_name_here.key & website_name_here.csr
Use website_name_here.csr generated to get certificate from Godaddy.
Get SSL cetrificate from Godaddy and extract to this folder.

####################  Java Version 17 was active from hereon #################################################################

Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.


C:\trash\keyproc>keytool -importkeystore -deststorepass pwd_here -destkeystore website_name_here.jks -srckeystore website_name_here.p12 -srcstoretype PKCS12
Importing keystore website_name_here.p12 to website_name_here.jks...
Enter source keystore password:
Entry for alias website_name_here.co successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore website_name_here.jks -destkeystore website_name_here.jks -deststoretype pkcs12".

C:\trash\keyproc>

After this just import  main CRT file not bundle file using keytool.

In the above steps it is not mentioned where website_name_here.p12 file is coming from. What it could be?

The code that uses the .jks file is as follows:

import lombok.SneakyThrows;
import org.apache.catalina.connector.Connector;
import org.apache.coyote.http11.Http11NioProtocol;
import org.apache.tomcat.util.descriptor.web.SecurityCollection;
import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
import org.springframework.stereotype.Component;

import java.net.InetAddress;
import java.util.Optional;
//@Profile("dev")
@Component
public class TomcatEmbedServerCustomConfiguration implements WebServerFactoryCustomizer<TomcatServletWebServerFactory>
{
    private static final Logger logger = LoggerFactory.getLogger(TomcatEmbedServerCustomConfiguration.class);

    IWebApplicationServerSettingsRepository appSettinsRepository;

    ApplicationHttpsSettingsEntityRepository applicationHttpsSettingsEntityRepository;

    public TomcatEmbedServerCustomConfiguration(IWebApplicationServerSettingsRepository appSettinsRepository, ApplicationHttpsSettingsEntityRepository applicationHttpsSettingsEntityRepository)
    {
        this.appSettinsRepository = appSettinsRepository;
        this.applicationHttpsSettingsEntityRepository = applicationHttpsSettingsEntityRepository;
    }

    @SneakyThrows
    @Override
    public void customize(TomcatServletWebServerFactory factory)
    {
        logger.info("Setting the Tomcat specific configurations. started");
        try
        {

            Optional<WebApplicationServerSettingEntity> serverSettingEntity = appSettinsRepository.findById(1);

            if (serverSettingEntity.isPresent())
            {
                factory.setPort(serverSettingEntity.get().getPort().getPORT());
                factory.setAddress(InetAddress.getByName(serverSettingEntity.get().getHost()));
            }
            factory.setServerHeader("Server header of tomcat");

// HTTPS Settings - Begin

            Optional<ApplicationHttpsSettingsEntity> applicationHttpsSettingsEntity = applicationHttpsSettingsEntityRepository.findById(1);

            if(applicationHttpsSettingsEntity.isPresent())
            {
                logger.info("Setting HTTPS settings....");
                if(applicationHttpsSettingsEntity.get().getUseHttps() !=0)
                {
                    factory.addAdditionalTomcatConnectors(createSslConnector());
                    factory.addContextCustomizers(context ->
                                                  {
                                                      logger.info("Setting HTTPS settings....setting...");
                                                      SecurityConstraint securityConstraint = new SecurityConstraint();
                                                      securityConstraint.setUserConstraint("CONFIDENTIAL");
                                                      SecurityCollection collection = new SecurityCollection();
                                                      collection.addPattern("/*");
                                                      securityConstraint.addCollection(collection);
                                                      context.addConstraint(securityConstraint);
                                                      logger.info("Setting HTTPS settings....setting...Done");
                                                  });
                }
                logger.info("Setting HTTPS settings....End");
            }
// HTTPS Settings - end
            logger.info("Tomcat Server Configuration Host=["   factory.getAddress()   "] Port=["   factory.getPort()   "]");
            logger.info("Setting the Tomcat specific configurations. ended");
        }
        catch (Exception e)
        {
            logger.error(e.getMessage());
            throw e;
        }
    }

// HTTPS Settings - Begin
    private Connector createSslConnector() {


        Optional<ApplicationHttpsSettingsEntity> applicationHttpsSettingsEntity = applicationHttpsSettingsEntityRepository.findById(1);

        if(applicationHttpsSettingsEntity.isPresent())
        {
            logger.info("Creating SSL Connector...");

            Connector connector = new Connector("org.apache.coyote.http11.Http11NioProtocol");
            Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
            //            File keystore = new ClassPathResource("website_name.jks").getFile();
//            File truststore = new ClassPathResource("keystore").getFile();
            connector.setScheme("https");
            connector.setSecure(applicationHttpsSettingsEntity.get().getUseHttps() != 0);
            connector.setPort(applicationHttpsSettingsEntity.get().getBroadcaster().getPORT());
            protocol.setSSLEnabled(applicationHttpsSettingsEntity.get().getUseHttps() != 0);
//            protocol.setKeystoreFile("file:///c://trash//website_name_here.jks");
            protocol.setKeystoreFile(applicationHttpsSettingsEntity.get().getKeyStore());
//            protocol.setKeystorePass("pwd_here");
            protocol.setKeystorePass(applicationHttpsSettingsEntity.get().getKeyStorePassword());
//            protocol.setTruststoreFile(truststore.getAbsolutePath());
//            protocol.setTruststorePass("changeit");
            protocol.setKeyAlias(applicationHttpsSettingsEntity.get().getKeyAlias());
            logger.info("Creating SSL Connector...Done");
            return connector;
        }

        return null;
    }
// HTTPS Settings - End
}

And

@Configuration
//@Profile("production")
public class SecurityConfig
{
// HTTPS Settings - Begin
    @Bean
    public TomcatServletWebServerFactory httpsRedirectConfig()
    {
        return new TomcatServletWebServerFactory()
        {
            @Override
            protected void postProcessContext(Context context)
            {
                SecurityConstraint securityConstraint = new SecurityConstraint();
                securityConstraint.setUserConstraint("CONFIDENTIAL");
                SecurityCollection collection = new SecurityCollection();
                collection.addPattern("/*");
                securityConstraint.addCollection(collection);
                context.addConstraint(securityConstraint);
            }
        };
    }
// HTTPS Settings - End
}

CodePudding user response:

One of the correct procedures to set up a Java SSL/TLS (including HTTPS) server like Tomcat is:

  1. openssl req -new -newkey ... to create the key and CSR, both in PEM

  2. send CSR to Certificate Authority aka CA (here GoDaddy) and provide proof you own or control the specified domain(s), and (depending on the CA) payment, and get back a server (leaf) cert plus one or more chain cert(s) (often labelled intermediate) and possibly/probably a root cert, all usually in PEM; if not you must convert to PEM before continuing

  3. (your missing step) openssl pkcs12 -export -in cert1PEM -inkey keyPEM [-certfile cert2PEM] [-friendlyname somename] -out p12file

    cert1PEM must contain at least the server cert, and may contain the other (chain/intermediate and optionally root) cert(s); if it doesn't contain the latter, those must be in -certfile cert2PEM. -friendlyname somename is optional but your displayed output from keytool implies it was used (Java including keytool shows it as the alias)

  4. keytool -importkeystore -srckeystore p12file -destkeystore jksfile ...

    But I disbelieve your comment that 'Java 17 was active' unless the .jks file already existed, which it shouldn't have. Java 9 up, including 17, creates new keystore files as PKCS12 by default, not JKS, and wouldn't produce that warning. Recent updates of Java 8 would. (That is, all updates of j8 default output to JKS, and recent updates give the warning when doing so.)

    In any case, step 4 is obsolete and unnecessary. All versions of Java since 8u60 in 2015 can read PKCS12 (as produced by step 3) by default and don't need a JKS file at all. Even older versions (back to 2000 or so) could read PKCS12 with only a slight change to the configuration, which I would recommend precisely because JKS is 'proprietary' (as the warning now says) and also weak (which the warning doesn't say).

  • Related