View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  
21  package org.waarp.common.digest;
22  
23  import io.netty.handler.ssl.ClientAuth;
24  import io.netty.handler.ssl.OpenSsl;
25  import io.netty.handler.ssl.SslContext;
26  import io.netty.handler.ssl.SslContextBuilder;
27  
28  import javax.net.ssl.KeyManagerFactory;
29  import javax.net.ssl.SSLContext;
30  import javax.net.ssl.SSLException;
31  import java.security.NoSuchAlgorithmException;
32  import java.security.NoSuchProviderException;
33  import java.security.Provider;
34  import java.security.SecureRandom;
35  import java.security.Security;
36  import java.security.cert.X509Certificate;
37  import java.util.List;
38  
39  public class WaarpBC {
40    public static final String PROTOCOL = "TLS";
41    public static final long DEFAULT_SESSIONCACHE_TIMEOUTSEC = 60;
42    public static final long DEFAULT_SESSIONCACHE_SIZE = 20480;
43    private static volatile boolean initialized = false;
44    private static boolean specialSecureRandom = false;
45  
46    static {
47      initializedTlsContext();
48    }
49  
50    public static void initializedTlsContext() {
51      try {
52        if (!initialized) {
53          addBcProvider();
54          registerRandomSecure();
55          initialized = true;
56        }
57      } catch (final Throwable throwable) {//NOSONAR
58        throwable.printStackTrace();//NOSONAR
59        System.err //NOSONAR
60                   .println("Error occurs at startup: " +//NOSONAR
61                            throwable.getMessage());//NOSONAR
62      }
63    }
64  
65    /**
66     * Called at first
67     */
68    private static void addBcProvider() {
69      OpenSsl.isAvailable();
70    }
71  
72    /**
73     * To fix issue on SecureRandom using bad algotithm
74     * </br>
75     * Called at second place
76     */
77    private static void registerRandomSecure() {
78      if (System.getProperty("os.name").contains("Windows")) {
79        final Provider provider = Security.getProvider("SunMSCAPI");
80        if (provider != null) {
81          Security.removeProvider(provider.getName());
82          Security.insertProviderAt(provider, 1);
83          specialSecureRandom = true;
84        }
85      } else {
86        System.setProperty("java.security.egd", "file:/dev/./urandom");
87        final Provider provider = Security.getProvider("SUN");
88        final String type = "SecureRandom";
89        final String alg = "NativePRNGNonBlocking";
90        if (provider != null) {
91          final String name = String.format("%s.%s", type, alg);
92          final Provider.Service service = provider.getService(type, alg);
93          if (service != null) {
94            Security.insertProviderAt(
95                new Provider(name, provider.getVersion(), "Waarp quick fix for SecureRandom using urandom") {
96                  private static final long serialVersionUID = 1001L;
97  
98                  {
99                    System.setProperty(name, service.getClassName());
100                 }
101 
102               }, 1);
103           specialSecureRandom = true;
104         }
105       }
106     }
107   }
108 
109   public static SecureRandom getSecureRandom() {
110     if (!specialSecureRandom) {
111       return new SecureRandom();
112     }
113     if (System.getProperty("os.name").contains("Windows")) {
114       try {
115         return SecureRandom.getInstance("Windows-PRNG", "SunMSCAPI");
116       } catch (final NoSuchAlgorithmException e) {
117         return new SecureRandom();
118       } catch (final NoSuchProviderException e) {
119         return new SecureRandom();
120       }
121     } else {
122       try {
123         return SecureRandom.getInstance("NativePRNGNonBlocking", "SUN");
124       } catch (final NoSuchAlgorithmException e) {
125         return new SecureRandom();
126       } catch (final NoSuchProviderException e) {
127         return new SecureRandom();
128       }
129     }
130   }
131 
132   public static SslContext getInstanceForServer(final KeyManagerFactory keyManagerFactory,
133                                                 final X509Certificate[] x509Certificates,
134                                                 final boolean clientNeedAuthentication,
135                                                 final boolean startTls, final List<String> ciphers,
136                                                 final String... protocols) throws SSLException {
137     final SslContextBuilder builder =
138         SslContextBuilder.forServer(keyManagerFactory).sslProvider(SslContext.defaultServerProvider());
139     if (x509Certificates != null) {
140       builder.trustManager(x509Certificates);
141     }
142     builder.clientAuth(clientNeedAuthentication? ClientAuth.REQUIRE : ClientAuth.NONE);
143     if (ciphers != null && !ciphers.isEmpty()) {
144       builder.ciphers(ciphers);
145     }
146     if (protocols != null && protocols.length > 0) {
147       builder.protocols(protocols);
148     }
149     builder.sessionCacheSize(DEFAULT_SESSIONCACHE_SIZE).sessionTimeout(DEFAULT_SESSIONCACHE_TIMEOUTSEC)
150            .startTls(startTls);
151     return builder.build();
152   }
153 
154   public static SslContext getInstanceForClient(final KeyManagerFactory keyManagerFactory,
155                                                 final X509Certificate[] x509Certificates)
156       throws NoSuchAlgorithmException, NoSuchProviderException, SSLException {
157     final SslContextBuilder builder =
158         SslContextBuilder.forClient().sslProvider(SslContext.defaultClientProvider())
159                          .keyManager(keyManagerFactory);
160     if (x509Certificates != null) {
161       builder.trustManager(x509Certificates);
162     }
163     builder.sessionCacheSize(DEFAULT_SESSIONCACHE_SIZE).sessionTimeout(DEFAULT_SESSIONCACHE_TIMEOUTSEC);
164     return builder.build();
165   }
166 
167   public static SSLContext getInstanceJDK() throws NoSuchAlgorithmException {
168     return SSLContext.getInstance(PROTOCOL);
169   }
170 
171   private WaarpBC() {
172     // Nothing
173   }
174 }