Configuring two-way RSA and GOST authentication in an application on JBoss EAP 7



    Hello!

    Security in a modern business information environment is given one of the primary roles. Needless to say, in the Bank, where most of the products are built on Digital technologies, and at stake is trust, peace and well-being of customers, information security is at the forefront.

    In this article I’ll tell you how we use one of the tools to ensure information security in our activities.

    Authentication is the process of establishing the authenticity of a subject by its unique identifier and checking the right to access the information system.

    Two-way authentication is a mutual verification and authentication, in which the information system is also obliged to confirm its authenticity to the user.

    The Red Hat JBoss Enterprise Application Platform Server is one of the common and popular platforms for building enterprise Java applications.

    To configure, take the final release of JBoss EAP 7.0.0 from 05/10/2016 from a free source: Red Hat JBoss Enterprise Application Platform

    If you are registered with Red Hat, you can download additional patches: Red Hat Customer Portal and install the JBoss EAP instance through the console (http: / /localhost:9990/console/App.html#patching)



    Formulation of the problem


    For a corporate application with a thin client in a web browser, middle or backend servlets running on JBoss EAP, it is necessary to configure two-way authentication using the TLSv1.2 protocol using foreign cryptographic algorithms.

    The task is complicated by the fact that the application on the JBoss server, in turn, interacts, for example, with the PAK Certification Center CryptoPro software and hardware complex, where two-way authentication is required using the Transport Layer Security protocol (TLSv1.0) using Russian cryptographic algorithms.

    It turns out that in one application on the JBoss server you need to make friends of domestic and foreign cryptography.

    Authentication must be performed by a combined method with PKI tools, i.e. using client and server certificates.

    Preparing RSA authentication keys


    To authenticate the client and confirm the authenticity of the server to the client, both parties need to have their own key pairs with public key certificates. As well as a repository of root trusted certificates, where the root certificates of certification authorities that issued the final authentication certificates should be installed.



    Certification Authorities for the server and client may be different.

    The user must trust the certification authority that issued the certificate for the server.

    The server must trust the certification authority that issued the certificate for the client.



    There are many utilities and tools with a good description and examples that allow you to work with repositories and generate keys and certificate requests (keytool, openSSL, Portecle, XCA). Therefore, we will skip the process of preparing repositories and issuing certificates here.

    For example, here’s a good article and step-by-step instructions for setting up Two-way SSL with TLS1.2 for Oracle SOA Suiteusing openSSL and keytool. But, however, it partially lost its relevance and ceased to reflect the whole picture. Certificates issued on it will not be correctly interpreted in web browsers. So, for example, for Google Chrome browser version 58 and later, the subjectAlternativeName attribute of the Extensions block will be used in the TLS certificate to verify the domain name, rather than commonName, as before. Now the browser will give an error:





    Error: "Subject Alternative Name Missing" or NET :: ERR_CERT_COMMON_NAME_INVALID or "Your connection is not private"

    if it receives an SSL certificate without a domain from the server in the alternative name of the certification subject.

    This is what Support Google Chrome says about it.



    How to add subjectAlternativeName to the certificate using openSSL - you can see it here and here.

    Of course, this method of obtaining TLS certificates is suitable only for intracorporate applications.

    To interact with external clients, you need to contact trusted certification authorities whose root certificates are preinstalled in browsers, JREs, operating systems, and client devices. Sslshopper.com Certification Authorities Overview

    As a result, two repositories are created. File ssl-keystore.jkswith keys and a JBoss EAP server certificate for authentication to the client. And ssl-truststore.jks - with a CA trusted root certificate that issued a client authentication certificate.

    Preparing GOST authentication keys


    The process of mutual authentication of the JBoss server and CryptoPro CA server is essentially the same. The only difference is in cryptographic algorithms.



    Servers exchange certificates with GOST R 34.11 / 34.10-2001 signature algorithms and GOST R 34.11-94 signature hashing algorithms instead of sha256RSA and sha256 used in RSA TLSv1.2, respectively. The root certificate here is the ROOT certificate of the PAK CryptoPro CA itself.

    To generate a key pair and issue a GOST certificate, you can use the CryptoPro test certification center cryptopro.ru/solutions/test-ca

    Or, if available, a deployed corporate CA. At the same time, the cryptographic provider CryptoPro CSP should be installed on the workstation.



    After registration on a personal page, you can create requests, manage your certificates.



    When generating a key pair, CryptoPro CSP asks to choose a repository. This can be the MS Windows, eToken or JaCarta registry, if the drivers and the corresponding eToken PKI Client 5.1 SP1 environment are installed aladdin-rd.ru/support

    JBoss server through Java interfaces implemented in CryptoPro JCP and CryptoPro JCSP can work with the following types of storage : In order to have access to the eToken, in CryptoPro JCP it is necessary to follow the steps given in the CryptoPro instruction. Installation specifics using eToken electronic keys The OCF tab will appear in the CryptoPro JCP control panel and the ability to access eToken through OCFStore.

    JCP - CryptoPro Java Provider
    KeyStore - CertStore
    KeyStore - FloppyStore
    KeyStore - HDImageStore
    KeyStore - MemoryStore
    KeyStore - MemoryStore0- MemoryStore9
    KeyStore - OCFBase

    JCSP - CryptoPro Java CSP Provider
    KeyStore – FLASH
    KeyStore - HDIMAGE
    KeyStore – REGISTRY
    KeyStore – ARDS JaCarta
    KeyStore – Aladdin Token JC







    In this example, the JBoss EAP will be configured to work with the KeyStore repository - HDImageStore. This means that if the keys and certificate were generated in the Windows, eToken or JaCarta registry, then you need to solve the problem of transferring them to the HDImageStore format.

    If the keys are in the registry or JaCarta, then use CryptoPro CSP. Service tab “Copy”



    Select a container and copy it to eToken.





    Further, in the control panel of CryptoPro JCP, an opportunity appears in OCFStore to view and copy this container from eToken to the desired HDImageStore format.

    The path to the HDImageStore in CryptoPro JCP is configured on the Hardware tab



    Physically, containers with keys in the HDImageStore format are directories, each of which stores six files with the * .key extension.



    As a trusted root store with the root certificate PAK CryptoPro CA, the JBoss server will use truststore.cpks , which is connected to CryptoPro JCP on the tab Keys and certificates stores.



    JBoss server setup


    For JBoss EAP 7.0.0 server settings you need to make any changes to the configuration file-the EAP-the jboss 7.0.0 \ the standalone \ configuration \ standalone.xml

    in section settings are added that tell the server which providers and repositories to use for two-way GOST authentication:


    To configure RSA TLSv1.2 user and JBoss server authentication in a section


    need to add a security scope:


    Thus, for JBoss, all the required keystores and certificates are listed.

    To section


    to an existing http listener


    need to add https:


    The verify-client = "REQUESTED" attribute indicates to the server that it is necessary to request a user certificate in the browser when accessing the server via the https protocol.



    To section

    On Linux OS, where port 8443 is especially privileged, you can override it, for example:


    If you need to configure the JBoss application on a virtual host, go to


    add next to

    setting up your host:


    To section


    need to add the security domain of our application


    To authorize users, if necessary, as shown in the example, in the security domain, you can configure the login-module, which will determine the role of the user in the application by its authentication certificate. For this, the login module uses the prepared file /roles.properties.

    An example of the contents of the file is Subject X500Principal = role As part of the CryptoPro JCP delivery, there is an instruction for setting up the JBoss server jcp-2.0.39014 \ Doc \ WebServerIntegration \ JBoss \ Howto_set_gost_tls_jboss.docx
    #
    # user=role1,role2,...
    #
    C\=RU,\ L\=Moscow,\ O\=Alfabank,\ OU\=ORRPP,\ CN\=Vasiliy\ Burmistrov=admin
    C\=RU,\ L\=Moscow,\ O\=Alfabank,\ OU\=ORRPP,\ CN\=Ivan\ Petrov=user


    INTEGRATION JBOSS 6.1.0 Final (“Neo”) and JTLS 2.0. This document is about an outdated version of JBoss and the process of user authentication via Gost TLS directly on the server. This can be useful if the goal is to raise a channel protected by GOST between the user's browser or another front and the application server.

    Application setup


    In order for the deployment application to integrate with the settings on the server during installation, it is necessary to add a number of parameters to its configuration files.

    The security domain and virtual host of the application are specified in /WEB-INF/jboss-web.xml

    myAppmyApp

    The security restrictions are configured in the /WEB-INF/web.xml file :

    myApp/ui1/*/ui2/*GETPOST*CONFIDENTIAL

    and authentication method:

    CLIENT-CERTmyApp

    As a result of these settings, in the application on the JBoss server in Runtime, you can receive a certificate from a authenticated user from a request from a web browser or other front-system:

    X509Certificate[] certChain = (X509Certificate[]) request.getAttribute("javax.servlet.request.X509Certificate");
                X509Certificate userCert = certChain[0];
    

    Interacting with the PAK CryptoPro CA, the application uses the SOAP API, which is described in the documentation of ZHTIA.00067-02 20 01-LU (ZHTII.00067-02 90 16) "CryptoPro UZ hardware-software complex Certification Center Programmer's Guide"

    Web service is called using the Apache Axis 1.4 framework, an implementation of the JAX-WS interface.

    If, in addition to the authentication keys directly in CryptoPro CA, the keys for other applications and other purposes are stored in the HDImageStore, then a problem arises. When calling the CryptoPro CA service, Apache Axis grabs the first one from the store and, accordingly, authentication does not pass.

    To solve this problem, I needed to make my own implementation of SocketFactoryImpl.

    To do this, you need to inherit from org.apache.axis.components.net.JSSESocketFactory

    and implement the interface org.apache.axis.components.net.SecureSocketFactory

    Code for your own factory SocketFactoryImpl

    package ru.alfabank.orrpp.common.alfaca.ws;
    import java.io.FileInputStream;
    import java.io.IOException;
    import java.security.KeyStore;
    import java.security.PrivateKey;
    import java.security.cert.X509Certificate;
    import java.util.Hashtable;
    import java.util.logging.Logger;
    import javax.net.ssl.KeyManager;
    import javax.net.ssl.SSLContext;
    import javax.net.ssl.TrustManagerFactory;
    import org.apache.axis.components.net.JSSESocketFactory;
    import org.apache.axis.components.net.SecureSocketFactory;
    /**
     * SSL socket factory.
     */
    public class SocketFactoryImpl extends JSSESocketFactory implements SecureSocketFactory {
        public SocketFactoryImpl(Hashtable attributes) {
            super(attributes);
        }
        private static final Logger LOGGER = Logger.getLogger(SocketFactoryImpl.class.getName());
        private static final String SIGNER_KEY_ALIAS = "signer_CA";
        private static final String TRUST_CERT_ALIAS = "trust_CA";
        private static final char[] PASSWORD = "myPass".toCharArray();
        /**
         * Read the keystore, init the SSL socket factory
         * 
         * @throws IOException
         */
        protected void initFactory() throws IOException {
            try {
                //Configuration specified in wsdd.
                SSLContext context = getContext();
                sslFactory = context.getSocketFactory();
            } catch (Exception e) {
                if (e instanceof IOException) {
                    throw (IOException) e;
                }
                throw new IOException(e.getMessage());
            }
        }
        /**
         * gets a SSL Context
         * 
         * @return SSLContext
         * @throws Exception
         */
        protected SSLContext getContext() throws Exception {
            System.setProperty("ssl.KeyManagerFactory.algorithm", "GostX509");
            System.setProperty("ssl.TrustManagerFactory.algorithm", "GostX509");
            System.setProperty("ssl.SocketFactory.provider", "ru.CryptoPro.ssl.SSLSocketFactoryImpl");
            System.setProperty("ssl.ServerSocketFactory.provider", "ru.CryptoPro.ssl.SSLServerSocketFactoryImpl");
            System.setProperty("ru.CryptoPro.ssl.Provider", "JCP");
            System.out.println("javax.net.ssl.trustStore: " + System.getProperty("javax.net.ssl.trustStore"));
            KeyStore trustStore = KeyStore.getInstance(System.getProperty("javax.net.ssl.trustStoreType"));
            String trustStoreFileName = System.getProperty("javax.net.ssl.trustStore");
            trustStore.load(trustStoreFileName == null ? null : new FileInputStream(trustStoreFileName), System.getProperty("javax.net.ssl.trustStorePassword").toCharArray());
            KeyStore ks = KeyStore.getInstance(System.getProperty("javax.net.ssl.keyStoreType"));
            String keystoreFileName = System.getProperty("javax.net.ssl.keyStore");
            ks.load(keystoreFileName == null ? null : new FileInputStream(keystoreFileName), System.getProperty("javax.net.ssl.keyStorePassword").toCharArray());
            X509Certificate cert = (X509Certificate) ks.getCertificate(SIGNER_KEY_ALIAS);
            LOGGER.info("Signer found: " + ((X509Certificate) cert).getSubjectX500Principal().getName());
            PrivateKey privateKey = (PrivateKey) ks.getKey(SIGNER_KEY_ALIAS, PASSWORD);
            X509Certificate trustCert = (X509Certificate) trustStore.getCertificate(TRUST_CERT_ALIAS);
            LOGGER.info("Trust found: " + ((X509Certificate) trustCert).getSubjectX500Principal().getName());
            TrustManagerFactory tmf = TrustManagerFactory.getInstance("GostX509");
            tmf.init(trustStore);
            SSLContext context = SSLContext.getInstance("GostTLS", "JTLS");
            context.init(new KeyManager[] {new KeyManagerImpl(SIGNER_KEY_ALIAS, privateKey, new X509Certificate[] {cert})}, tmf.getTrustManagers(), null);
            return context;
        }
    }
    

    To force Apache Axis to use its own factory, in the @Stateless bean,
    where we construct the call to the CryptoPro CA service, we redefine the system property:

    AxisProperties.setProperty("axis.socketSecureFactory", "ru.alfabank.orrpp.common.alfaca.ws.SocketFactoryImpl");

    JRE setup


    It would seem that everything is configured, and should work. But no. One more important touch remains.

    In order to authenticate from the application on JBoss to CryptoPro CA using the Gost TLS protocol, the JBoss server needs to be launched in JRE with the installed CryptoPro JCP provider.

    When JCP is installed, changes are made to the JRE settings. In particular, in jre1.8.0_144 \ lib \ security \ java.security, the KeyManagerFactory and TrustManagerFactory algorithms are changed to Gost. If so, then an error will occur in JBoss at startup: To fix it, comment on the GostX509 java.security file and return the default settings to SunX509

    2017-10-12 17:44:13,376 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-7) MSC000001: Failed to start service jboss.security.security-domain.myApp: org.jboss.msc.service.StartException in service jboss.security.security-domain.myApp: WFLYSEC0012: Unable to start the SecurityDomainService service
    at org.jboss.as.security.service.SecurityDomainService.start(SecurityDomainService.java:105)
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.startService(ServiceControllerImpl.java:2032)
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1955)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
    Caused by: java.security.KeyStoreException: Default store provider (keyStore) is SUN but default config provider (cpSSL) is JCP. Check settings on the tab 'Algorithms' of JCP Pane.
    at ru.CryptoPro.ssl.r.(Unknown Source)
    at ru.CryptoPro.ssl.KeyManagerFactoryImpl.engineInit(Unknown Source)
    at javax.net.ssl.KeyManagerFactory.init(Unknown Source)
    at org.jboss.security.JBossJSSESecurityDomain.loadKeyAndTrustStore(JBossJSSESecurityDomain.java:488)
    at org.jboss.security.JBossJSSESecurityDomain.reloadKeyAndTrustStore(JBossJSSESecurityDomain.java:335)
    at org.jboss.as.security.service.SecurityDomainService.start(SecurityDomainService.java:102)
    ... 5 more





    #ssl.KeyManagerFactory.algorithm=GostX509
    #ssl.TrustManagerFactory.algorithm=GostX509


    ssl.KeyManagerFactory.algorithm=SunX509
    ssl.TrustManagerFactory.algorithm=PKIX

    results


    The application and the runtime with two-way authentication are configured, the data transmission channels are encrypted, reliable connections are established between the participants in the system.






    useful links


    1. Where to download JBoss EAP 7.0.0
    2. Red Hat Customer Portal
    3. Two-way SSL article with TLS1.2 for Oracle SOA Suite
    4. Google Support for “Subject Alternative Name Missing”
    5. How to add subjectAlternativeName here and here using openSSL
    6. Overview of Certification Authorities with Foreign Cryptographic Algorithms
    7. CryptoPro Test Certification Center
    8. Aladdin company, where to download eToken or JaCarta support drivers (eToken PKI Client 5.1 SP1)
    9. Instructions for setting up CryptoPro JCP to support eToken

    Also popular now: