blob: 5fb6972874f644d2d981d2894397eff32df9461d [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2001-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.security.ssl;
27
28import java.util.*;
29import java.math.BigInteger;
30
31import java.security.*;
32import java.security.interfaces.RSAPublicKey;
33import java.security.spec.RSAPublicKeySpec;
34import java.security.spec.*;
35
36import javax.crypto.*;
37
38// explicit import to override the Provider class in this package
39import java.security.Provider;
40
41// need internal Sun classes for FIPS tricks
42import sun.security.jca.Providers;
43import sun.security.jca.ProviderList;
44
45import sun.security.ec.ECParameters;
46import sun.security.ec.NamedCurve;
47
48import static sun.security.ssl.SunJSSE.cryptoProvider;
49
50/**
51 * This class contains a few static methods for interaction with the JCA/JCE
52 * to obtain implementations, etc.
53 *
54 * @author Andreas Sterbenz
55 */
56final class JsseJce {
57
58 private final static Debug debug = Debug.getInstance("ssl");
59
60 private final static ProviderList fipsProviderList;
61
62 // Flag indicating whether EC crypto is available.
63 // If null, then we have not checked yet.
64 // If yes, then all the EC based crypto we need is available.
65 private static volatile Boolean ecAvailable;
66
67 static {
68 // force FIPS flag initialization
69 // Because isFIPS() is synchronized and cryptoProvider is not modified
70 // after it completes, this also eliminates the need for any further
71 // synchronization when accessing cryptoProvider
72 if (SunJSSE.isFIPS() == false) {
73 fipsProviderList = null;
74 } else {
75 // Setup a ProviderList that can be used by the trust manager
76 // during certificate chain validation. All the crypto must be
77 // from the FIPS provider, but we also allow the required
78 // certificate related services from the SUN provider.
79 Provider sun = Security.getProvider("SUN");
80 if (sun == null) {
81 throw new RuntimeException
82 ("FIPS mode: SUN provider must be installed");
83 }
84 Provider sunCerts = new SunCertificates(sun);
85 fipsProviderList = ProviderList.newList(cryptoProvider, sunCerts);
86 }
87 }
88
89 private static final class SunCertificates extends Provider {
90 SunCertificates(final Provider p) {
91 super("SunCertificates", 1.0d, "SunJSSE internal");
92 AccessController.doPrivileged(new PrivilegedAction<Object>() {
93 public Object run() {
94 // copy certificate related services from the Sun provider
95 for (Map.Entry<Object,Object> entry : p.entrySet()) {
96 String key = (String)entry.getKey();
97 if (key.startsWith("CertPathValidator.")
98 || key.startsWith("CertPathBuilder.")
99 || key.startsWith("CertStore.")
100 || key.startsWith("CertificateFactory.")) {
101 put(key, entry.getValue());
102 }
103 }
104 return null;
105 }
106 });
107 }
108 }
109
110 /**
111 * JCE transformation string for RSA with PKCS#1 v1.5 padding.
112 * Can be used for encryption, decryption, signing, verifying.
113 */
114 final static String CIPHER_RSA_PKCS1 = "RSA/ECB/PKCS1Padding";
115 /**
116 * JCE transformation string for the stream cipher RC4.
117 */
118 final static String CIPHER_RC4 = "RC4";
119 /**
120 * JCE transformation string for DES in CBC mode without padding.
121 */
122 final static String CIPHER_DES = "DES/CBC/NoPadding";
123 /**
124 * JCE transformation string for (3-key) Triple DES in CBC mode
125 * without padding.
126 */
127 final static String CIPHER_3DES = "DESede/CBC/NoPadding";
128 /**
129 * JCE transformation string for AES in CBC mode
130 * without padding.
131 */
132 final static String CIPHER_AES = "AES/CBC/NoPadding";
133 /**
134 * JCA identifier string for DSA, i.e. a DSA with SHA-1.
135 */
136 final static String SIGNATURE_DSA = "DSA";
137 /**
138 * JCA identifier string for ECDSA, i.e. a ECDSA with SHA-1.
139 */
140 final static String SIGNATURE_ECDSA = "SHA1withECDSA";
141 /**
142 * JCA identifier string for Raw DSA, i.e. a DSA signature without
143 * hashing where the application provides the SHA-1 hash of the data.
144 * Note that the standard name is "NONEwithDSA" but we use "RawDSA"
145 * for compatibility.
146 */
147 final static String SIGNATURE_RAWDSA = "RawDSA";
148 /**
149 * JCA identifier string for Raw ECDSA, i.e. a DSA signature without
150 * hashing where the application provides the SHA-1 hash of the data.
151 */
152 final static String SIGNATURE_RAWECDSA = "NONEwithECDSA";
153 /**
154 * JCA identifier string for Raw RSA, i.e. a RSA PKCS#1 v1.5 signature
155 * without hashing where the application provides the hash of the data.
156 * Used for RSA client authentication with a 36 byte hash.
157 */
158 final static String SIGNATURE_RAWRSA = "NONEwithRSA";
159 /**
160 * JCA identifier string for the SSL/TLS style RSA Signature. I.e.
161 * an signature using RSA with PKCS#1 v1.5 padding signing a
162 * concatenation of an MD5 and SHA-1 digest.
163 */
164 final static String SIGNATURE_SSLRSA = "MD5andSHA1withRSA";
165
166 private JsseJce() {
167 // no instantiation of this class
168 }
169
170 static boolean isEcAvailable() {
171 if (ecAvailable == null) {
172 try {
173 JsseJce.getSignature(SIGNATURE_ECDSA);
174 JsseJce.getSignature(SIGNATURE_RAWECDSA);
175 JsseJce.getKeyAgreement("ECDH");
176 JsseJce.getKeyFactory("EC");
177 JsseJce.getKeyPairGenerator("EC");
178 ecAvailable = true;
179 } catch (Exception e) {
180 ecAvailable = false;
181 }
182 }
183 return ecAvailable;
184 }
185
186 static void clearEcAvailable() {
187 ecAvailable = null;
188 }
189
190 /**
191 * Return an JCE cipher implementation for the specified algorithm.
192 */
193 static Cipher getCipher(String transformation)
194 throws NoSuchAlgorithmException {
195 try {
196 if (cryptoProvider == null) {
197 return Cipher.getInstance(transformation);
198 } else {
199 return Cipher.getInstance(transformation, cryptoProvider);
200 }
201 } catch (NoSuchPaddingException e) {
202 throw new NoSuchAlgorithmException(e);
203 }
204 }
205
206 /**
207 * Return an JCA signature implementation for the specified algorithm.
208 * The algorithm string should be one of the constants defined
209 * in this class.
210 */
211 static Signature getSignature(String algorithm)
212 throws NoSuchAlgorithmException {
213 if (cryptoProvider == null) {
214 return Signature.getInstance(algorithm);
215 } else {
216 // reference equality
217 if (algorithm == SIGNATURE_SSLRSA) {
218 // The SunPKCS11 provider currently does not support this
219 // special algorithm. We allow a fallback in this case because
220 // the SunJSSE implementation does the actual crypto using
221 // a NONEwithRSA signature obtained from the cryptoProvider.
222 if (cryptoProvider.getService("Signature", algorithm) == null) {
223 // Calling Signature.getInstance() and catching the exception
224 // would be cleaner, but exceptions are a little expensive.
225 // So we check directly via getService().
226 try {
227 return Signature.getInstance(algorithm, "SunJSSE");
228 } catch (NoSuchProviderException e) {
229 throw new NoSuchAlgorithmException(e);
230 }
231 }
232 }
233 return Signature.getInstance(algorithm, cryptoProvider);
234 }
235 }
236
237 static KeyGenerator getKeyGenerator(String algorithm)
238 throws NoSuchAlgorithmException {
239 if (cryptoProvider == null) {
240 return KeyGenerator.getInstance(algorithm);
241 } else {
242 return KeyGenerator.getInstance(algorithm, cryptoProvider);
243 }
244 }
245
246 static KeyPairGenerator getKeyPairGenerator(String algorithm)
247 throws NoSuchAlgorithmException {
248 if (cryptoProvider == null) {
249 return KeyPairGenerator.getInstance(algorithm);
250 } else {
251 return KeyPairGenerator.getInstance(algorithm, cryptoProvider);
252 }
253 }
254
255 static KeyAgreement getKeyAgreement(String algorithm)
256 throws NoSuchAlgorithmException {
257 if (cryptoProvider == null) {
258 return KeyAgreement.getInstance(algorithm);
259 } else {
260 return KeyAgreement.getInstance(algorithm, cryptoProvider);
261 }
262 }
263
264 static Mac getMac(String algorithm)
265 throws NoSuchAlgorithmException {
266 if (cryptoProvider == null) {
267 return Mac.getInstance(algorithm);
268 } else {
269 return Mac.getInstance(algorithm, cryptoProvider);
270 }
271 }
272
273 static KeyFactory getKeyFactory(String algorithm)
274 throws NoSuchAlgorithmException {
275 if (cryptoProvider == null) {
276 return KeyFactory.getInstance(algorithm);
277 } else {
278 return KeyFactory.getInstance(algorithm, cryptoProvider);
279 }
280 }
281
282 static SecureRandom getSecureRandom() throws KeyManagementException {
283 if (cryptoProvider == null) {
284 return new SecureRandom();
285 }
286 // Try "PKCS11" first. If that is not supported, iterate through
287 // the provider and return the first working implementation.
288 try {
289 return SecureRandom.getInstance("PKCS11", cryptoProvider);
290 } catch (NoSuchAlgorithmException e) {
291 // ignore
292 }
293 for (Provider.Service s : cryptoProvider.getServices()) {
294 if (s.getType().equals("SecureRandom")) {
295 try {
296 return SecureRandom.getInstance(s.getAlgorithm(), cryptoProvider);
297 } catch (NoSuchAlgorithmException ee) {
298 // ignore
299 }
300 }
301 }
302 throw new KeyManagementException("FIPS mode: no SecureRandom "
303 + " implementation found in provider " + cryptoProvider.getName());
304 }
305
306 static MessageDigest getMD5() {
307 return getMessageDigest("MD5");
308 }
309
310 static MessageDigest getSHA() {
311 return getMessageDigest("SHA");
312 }
313
314 static MessageDigest getMessageDigest(String algorithm) {
315 try {
316 if (cryptoProvider == null) {
317 return MessageDigest.getInstance(algorithm);
318 } else {
319 return MessageDigest.getInstance(algorithm, cryptoProvider);
320 }
321 } catch (NoSuchAlgorithmException e) {
322 throw new RuntimeException
323 ("Algorithm " + algorithm + " not available", e);
324 }
325 }
326
327 static int getRSAKeyLength(PublicKey key) {
328 BigInteger modulus;
329 if (key instanceof RSAPublicKey) {
330 modulus = ((RSAPublicKey)key).getModulus();
331 } else {
332 RSAPublicKeySpec spec = getRSAPublicKeySpec(key);
333 modulus = spec.getModulus();
334 }
335 return modulus.bitLength();
336 }
337
338 static RSAPublicKeySpec getRSAPublicKeySpec(PublicKey key) {
339 if (key instanceof RSAPublicKey) {
340 RSAPublicKey rsaKey = (RSAPublicKey)key;
341 return new RSAPublicKeySpec(rsaKey.getModulus(),
342 rsaKey.getPublicExponent());
343 }
344 try {
345 KeyFactory factory = JsseJce.getKeyFactory("RSA");
346 return (RSAPublicKeySpec)factory.getKeySpec
347 (key, RSAPublicKeySpec.class);
348 } catch (Exception e) {
349 throw (RuntimeException)new RuntimeException().initCause(e);
350 }
351 }
352
353 static ECParameterSpec getECParameterSpec(String namedCurveOid) {
354 return NamedCurve.getECParameterSpec(namedCurveOid);
355 }
356
357 static String getNamedCurveOid(ECParameterSpec params) {
358 return ECParameters.getCurveName(params);
359 }
360
361 static ECPoint decodePoint(byte[] encoded, EllipticCurve curve)
362 throws java.io.IOException {
363 return ECParameters.decodePoint(encoded, curve);
364 }
365
366 static byte[] encodePoint(ECPoint point, EllipticCurve curve) {
367 return ECParameters.encodePoint(point, curve);
368 }
369
370 // In FIPS mode, set thread local providers; otherwise a no-op.
371 // Must be paired with endFipsProvider.
372 static Object beginFipsProvider() {
373 if (fipsProviderList == null) {
374 return null;
375 } else {
376 return Providers.beginThreadProviderList(fipsProviderList);
377 }
378 }
379
380 static void endFipsProvider(Object o) {
381 if (fipsProviderList != null) {
382 Providers.endThreadProviderList((ProviderList)o);
383 }
384 }
385
386}