1/*
2 * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26
27package sun.security.ssl;
28
29import java.security.*;
30import static sun.security.util.SecurityConstants.PROVIDER_VER;
31
32/**
33 * The JSSE provider.
34 *
35 * The RSA implementation has been removed from JSSE, but we still need to
36 * register the same algorithms for compatibility. We just point to the RSA
37 * implementation in the SunRsaSign provider. This works because all classes
38 * are in the bootclasspath and therefore loaded by the same classloader.
39 *
40 * SunJSSE now supports an experimental FIPS compliant mode when used with an
41 * appropriate FIPS certified crypto provider. In FIPS mode, we:
42 *  . allow only TLS 1.0 or later
43 *  . allow only FIPS approved ciphersuites
44 *  . perform all crypto in the FIPS crypto provider
45 *
46 * It is currently not possible to use both FIPS compliant SunJSSE and
47 * standard JSSE at the same time because of the various static data structures
48 * we use.
49 *
50 * However, we do want to allow FIPS mode to be enabled at runtime and without
51 * editing the java.security file. That means we need to allow
52 * Security.removeProvider("SunJSSE") to work, which creates an instance of
53 * this class in non-FIPS mode. That is why we delay the selection of the mode
54 * as long as possible. This is until we open an SSL/TLS connection and the
55 * data structures need to be initialized or until SunJSSE is initialized in
56 * FIPS mode.
57 *
58 */
59public abstract class SunJSSE extends java.security.Provider {
60
61    private static final long serialVersionUID = 3231825739635378733L;
62
63    private static String info = "Sun JSSE provider" +
64        "(PKCS12, SunX509/PKIX key/trust factories, " +
65        "SSLv3/TLSv1/TLSv1.1/TLSv1.2/DTLSv1.0/DTLSv1.2)";
66
67    private static String fipsInfo =
68        "Sun JSSE provider (FIPS mode, crypto provider ";
69
70    // tri-valued flag:
71    // null  := no final decision made
72    // false := data structures initialized in non-FIPS mode
73    // true  := data structures initialized in FIPS mode
74    private static Boolean fips;
75
76    // the FIPS certificate crypto provider that we use to perform all crypto
77    // operations. null in non-FIPS mode
78    static java.security.Provider cryptoProvider;
79
80    protected static synchronized boolean isFIPS() {
81        if (fips == null) {
82            fips = false;
83        }
84        return fips;
85    }
86
87    // ensure we can use FIPS mode using the specified crypto provider.
88    // enable FIPS mode if not already enabled.
89    private static synchronized void ensureFIPS(java.security.Provider p) {
90        if (fips == null) {
91            fips = true;
92            cryptoProvider = p;
93        } else {
94            if (fips == false) {
95                throw new ProviderException
96                    ("SunJSSE already initialized in non-FIPS mode");
97            }
98            if (cryptoProvider != p) {
99                throw new ProviderException
100                    ("SunJSSE already initialized with FIPS crypto provider "
101                    + cryptoProvider);
102            }
103        }
104    }
105
106    // standard constructor
107    protected SunJSSE() {
108        super("SunJSSE", PROVIDER_VER, info);
109        subclassCheck();
110        if (Boolean.TRUE.equals(fips)) {
111            throw new ProviderException
112                ("SunJSSE is already initialized in FIPS mode");
113        }
114        registerAlgorithms(false);
115    }
116
117    // preferred constructor to enable FIPS mode at runtime
118    protected SunJSSE(java.security.Provider cryptoProvider){
119        this(checkNull(cryptoProvider), cryptoProvider.getName());
120    }
121
122    // constructor to enable FIPS mode from java.security file
123    protected SunJSSE(String cryptoProvider){
124        this(null, checkNull(cryptoProvider));
125    }
126
127    private static <T> T checkNull(T t) {
128        if (t == null) {
129            throw new ProviderException("cryptoProvider must not be null");
130        }
131        return t;
132    }
133
134    private SunJSSE(java.security.Provider cryptoProvider,
135            String providerName) {
136        super("SunJSSE", PROVIDER_VER, fipsInfo + providerName + ")");
137        subclassCheck();
138        if (cryptoProvider == null) {
139            // Calling Security.getProvider() will cause other providers to be
140            // loaded. That is not good but unavoidable here.
141            cryptoProvider = Security.getProvider(providerName);
142            if (cryptoProvider == null) {
143                throw new ProviderException
144                    ("Crypto provider not installed: " + providerName);
145            }
146        }
147        ensureFIPS(cryptoProvider);
148        registerAlgorithms(true);
149    }
150
151    private void registerAlgorithms(final boolean isfips) {
152        AccessController.doPrivileged(new PrivilegedAction<>() {
153            @Override
154            public Object run() {
155                doRegister(isfips);
156                return null;
157            }
158        });
159    }
160
161    private void doRegister(boolean isfips) {
162        if (isfips == false) {
163            put("KeyFactory.RSA",
164                "sun.security.rsa.RSAKeyFactory");
165            put("Alg.Alias.KeyFactory.1.2.840.113549.1.1", "RSA");
166            put("Alg.Alias.KeyFactory.OID.1.2.840.113549.1.1", "RSA");
167
168            put("KeyPairGenerator.RSA",
169                "sun.security.rsa.RSAKeyPairGenerator");
170            put("Alg.Alias.KeyPairGenerator.1.2.840.113549.1.1", "RSA");
171            put("Alg.Alias.KeyPairGenerator.OID.1.2.840.113549.1.1", "RSA");
172
173            put("Signature.MD2withRSA",
174                "sun.security.rsa.RSASignature$MD2withRSA");
175            put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA");
176            put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2",
177                "MD2withRSA");
178
179            put("Signature.MD5withRSA",
180                "sun.security.rsa.RSASignature$MD5withRSA");
181            put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
182            put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4",
183                "MD5withRSA");
184
185            put("Signature.SHA1withRSA",
186                "sun.security.rsa.RSASignature$SHA1withRSA");
187            put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA");
188            put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5",
189                "SHA1withRSA");
190            put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA");
191            put("Alg.Alias.Signature.OID.1.3.14.3.2.29", "SHA1withRSA");
192
193        }
194        put("Signature.MD5andSHA1withRSA",
195            "sun.security.ssl.RSASignature");
196
197        put("KeyManagerFactory.SunX509",
198            "sun.security.ssl.KeyManagerFactoryImpl$SunX509");
199        put("KeyManagerFactory.NewSunX509",
200            "sun.security.ssl.KeyManagerFactoryImpl$X509");
201        put("Alg.Alias.KeyManagerFactory.PKIX", "NewSunX509");
202
203        put("TrustManagerFactory.SunX509",
204            "sun.security.ssl.TrustManagerFactoryImpl$SimpleFactory");
205        put("TrustManagerFactory.PKIX",
206            "sun.security.ssl.TrustManagerFactoryImpl$PKIXFactory");
207        put("Alg.Alias.TrustManagerFactory.SunPKIX", "PKIX");
208        put("Alg.Alias.TrustManagerFactory.X509", "PKIX");
209        put("Alg.Alias.TrustManagerFactory.X.509", "PKIX");
210
211        put("SSLContext.TLSv1",
212            "sun.security.ssl.SSLContextImpl$TLS10Context");
213        put("SSLContext.TLSv1.1",
214            "sun.security.ssl.SSLContextImpl$TLS11Context");
215        put("SSLContext.TLSv1.2",
216            "sun.security.ssl.SSLContextImpl$TLS12Context");
217        put("SSLContext.TLS",
218            "sun.security.ssl.SSLContextImpl$TLSContext");
219        if (isfips == false) {
220            put("Alg.Alias.SSLContext.SSL", "TLS");
221            put("Alg.Alias.SSLContext.SSLv3", "TLSv1");
222        }
223
224        put("SSLContext.DTLSv1.0",
225            "sun.security.ssl.SSLContextImpl$DTLS10Context");
226        put("SSLContext.DTLSv1.2",
227            "sun.security.ssl.SSLContextImpl$DTLS12Context");
228        put("SSLContext.DTLS",
229            "sun.security.ssl.SSLContextImpl$DTLSContext");
230
231        put("SSLContext.Default",
232            "sun.security.ssl.SSLContextImpl$DefaultSSLContext");
233
234        /*
235         * KeyStore
236         */
237        put("KeyStore.PKCS12",
238            "sun.security.pkcs12.PKCS12KeyStore");
239    }
240
241    // com.sun.net.ssl.internal.ssl.Provider has been deprecated since JDK 9
242    @SuppressWarnings("deprecation")
243    private void subclassCheck() {
244        if (getClass() != com.sun.net.ssl.internal.ssl.Provider.class) {
245            throw new AssertionError("Illegal subclass: " + getClass());
246        }
247    }
248
249    @Override
250    @SuppressWarnings("deprecation")
251    protected final void finalize() throws Throwable {
252        // empty
253        super.finalize();
254    }
255
256}
257