-
Notifications
You must be signed in to change notification settings - Fork 5.8k
/
Copy pathJceSecurity.java.template
433 lines (381 loc) · 15.7 KB
/
JceSecurity.java.template
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
/*
* Copyright (c) 1997, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* README README README README README README README README README
*
* This file is the template for generating the JceSecurity.java source
* file.
*
* In the current jdk builds, this file is first preprocessed to replace
* @@JCE_DEFAULT_POLICY@ [sic] with "limited" or "unlimited" which is
* determined by the $(UNLIMTED_CRYPTO) make variable. This variable is
* set by top-level configure script, using either
* --disable-unlimited-crypto or --enable-unlimited-crypto [default].
*
* Since this file is a generated source, incremental changes to
* this file require regenerating the source. Compilation options:
*
* (fewer dependencies/"faster" ones first)
*
* 1. make JDK_FILTER=javax/crypto java.base-gensrc-only java.base-java-only
* 2. make java.base-gensrc-only java.base-java-only
* 3. make java.base-gensrc-only java.base-only
* 4. make java.base-only
* 5. make
*/
package javax.crypto;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.io.*;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.net.URL;
import java.nio.file.*;
import java.security.*;
import java.security.Provider.Service;
import jdk.internal.util.StaticProperty;
import sun.security.jca.*;
import sun.security.jca.GetInstance.Instance;
import sun.security.util.Debug;
/**
* This class instantiates implementations of JCE engine classes from
* providers registered with the java.security.Security object.
*
* @author Jan Luehe
* @author Sharon Liu
* @since 1.4
*/
final class JceSecurity {
private static final Debug debug = Debug.getInstance("jca");
// The defaultPolicy and exemptPolicy will be set up
// in the static initializer.
private static CryptoPermissions defaultPolicy = null;
private static CryptoPermissions exemptPolicy = null;
// Map of the providers we already have verified.
// If verified ok, value == PROVIDER_VERIFIED, otherwise
// the cause of verification failure is stored as value.
private static final Map<WeakIdentityWrapper, Object>
verificationResults = new ConcurrentHashMap<>();
// Map<Provider,?> of the providers currently being verified
private static final Map<Provider, Object> verifyingProviders =
new IdentityHashMap<>();
// weak references queued by GC
private static final ReferenceQueue<Object> queue = new ReferenceQueue<>();
private static final boolean isRestricted;
/*
* Don't let anyone instantiate this.
*/
private JceSecurity() {
}
static {
try {
setupJurisdictionPolicies();
isRestricted = defaultPolicy.implies(
CryptoAllPermission.INSTANCE) ? false : true;
} catch (Exception e) {
throw new SecurityException(
"Can not initialize cryptographic mechanism", e);
}
}
static Instance getInstance(String type, Class<?> clazz, String algorithm,
String provider) throws NoSuchAlgorithmException,
NoSuchProviderException {
Service s = GetInstance.getService(type, algorithm, provider);
Exception ve = getVerificationResult(s.getProvider());
if (ve != null) {
String msg = "JCE cannot authenticate the provider " + provider;
throw (NoSuchProviderException)
new NoSuchProviderException(msg).initCause(ve);
}
return GetInstance.getInstance(s, clazz);
}
static Instance getInstance(String type, Class<?> clazz, String algorithm,
Provider provider) throws NoSuchAlgorithmException {
Service s = GetInstance.getService(type, algorithm, provider);
Exception ve = JceSecurity.getVerificationResult(provider);
if (ve != null) {
String msg = "JCE cannot authenticate the provider "
+ provider.getName();
throw new SecurityException(msg, ve);
}
return GetInstance.getInstance(s, clazz);
}
static Instance getInstance(String type, Class<?> clazz, String algorithm)
throws NoSuchAlgorithmException {
Iterator<Service> t = GetInstance.getServices(type, algorithm);
NoSuchAlgorithmException failure = null;
while (t.hasNext()) {
Service s = t.next();
if (canUseProvider(s.getProvider()) == false) {
// allow only signed providers
continue;
}
try {
Instance instance = GetInstance.getInstance(s, clazz);
return instance;
} catch (NoSuchAlgorithmException e) {
failure = e;
}
}
throw new NoSuchAlgorithmException("Algorithm " + algorithm
+ " not available", failure);
}
/**
* Verify if the JAR at URL codeBase is a signed exempt application
* JAR file and returns the permissions bundled with the JAR.
*
* @throws Exception on error
*/
static CryptoPermissions verifyExemptJar(URL codeBase) throws Exception {
ProviderVerifier pv = new ProviderVerifier(codeBase, true);
pv.verify();
return pv.getPermissions();
}
/**
* Verify if the JAR at URL codeBase is a signed provider JAR file.
*
* @throws Exception on error
*/
static void verifyProvider(URL codeBase, Provider p) throws Exception {
// Verify the provider JAR file and all
// supporting JAR files if there are any.
ProviderVerifier pv = new ProviderVerifier(codeBase, p, false);
pv.verify();
}
private static final Object PROVIDER_VERIFIED = Boolean.TRUE;
/*
* Verify that the provider JAR files are signed properly, which
* means the signer's certificate can be traced back to a
* JCE trusted CA.
* Return null if ok, failure Exception if verification failed.
*/
static Exception getVerificationResult(Provider p) {
expungeStaleWrappers();
WeakIdentityWrapper pKey = new WeakIdentityWrapper(p, queue);
try {
Object o = verificationResults.computeIfAbsent(pKey, new Function<>() {
public Object apply(WeakIdentityWrapper key) {
// no mapping found
if (verifyingProviders.get(p) != null) {
// recursion; return failure now
throw new IllegalStateException();
}
Object result;
try {
verifyingProviders.put(p, Boolean.FALSE);
URL providerURL = getCodeBase(p.getClass());
verifyProvider(providerURL, p);
result = PROVIDER_VERIFIED;
} catch (Exception e) {
result = e;
} finally {
verifyingProviders.remove(p);
}
if (debug != null) {
debug.println("Provider " + p.getName() +
" verification result: " + result);
}
return result;
}
});
return (o == PROVIDER_VERIFIED? null : (Exception) o);
} catch (IllegalStateException ise) {
// recursive update detected
return new NoSuchProviderException
("Recursion during verification");
}
}
/**
* Removes weakly reachable keys from history.
*/
static void expungeStaleWrappers() {
WeakIdentityWrapper key;
while ((key = (WeakIdentityWrapper) queue.poll()) != null) {
verificationResults.remove(key);
}
}
// return whether this provider is properly signed and can be used by JCE
static boolean canUseProvider(Provider p) {
Exception e = getVerificationResult(p);
if (debug != null && e != null) {
debug.println("Provider verification result: " + e);
}
return e == null;
}
// dummy object to represent null
private static final URL NULL_URL;
static {
try {
@SuppressWarnings("deprecation")
var _unused = NULL_URL = new URL("http://null.oracle.com/");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// reference to a Map we use as a cache for codebases
private static final Map<Class<?>, URL> codeBaseCacheRef =
new WeakHashMap<>();
/*
* Returns the CodeBase for the given class.
*/
static URL getCodeBase(final Class<?> clazz) {
synchronized (codeBaseCacheRef) {
URL url = codeBaseCacheRef.get(clazz);
if (url == null) {
url = NULL_URL;
ProtectionDomain pd = clazz.getProtectionDomain();
if (pd != null) {
CodeSource cs = pd.getCodeSource();
if (cs != null) {
url = cs.getLocation();
}
}
codeBaseCacheRef.put(clazz, url);
}
return (url == NULL_URL) ? null : url;
}
}
private static void setupJurisdictionPolicies() throws Exception {
// Sanity check the crypto.policy Security property. Single
// directory entry, no pseudo-directories (".", "..", leading/trailing
// path separators). normalize()/getParent() will help later.
String cryptoPolicyProperty = Security.getProperty("crypto.policy");
/*
* In case no property is present, rather than fail catastrophically,
* we at least try for a "sane" value, which is what we were
* built with. We first preprocess this file to plug in that
* value, then compile the result gensrc.
*
* Log the warning first.
*/
if (cryptoPolicyProperty == null) {
cryptoPolicyProperty = "@@JCE_DEFAULT_POLICY@@";
if (debug != null) {
debug.println(
"Security Property 'crypto.policy' not found: "
+ "using '" + cryptoPolicyProperty + "' as fallback");
}
}
Path cpPath = Paths.get(cryptoPolicyProperty);
if ((cpPath.getNameCount() != 1) ||
(cpPath.compareTo(cpPath.getFileName()) != 0)) {
throw new SecurityException(
"Invalid policy directory name format: " +
cryptoPolicyProperty);
}
// Prepend java.home to get the full path. normalize() in
// case an extra "." or ".." snuck in somehow.
String javaHomeProperty = StaticProperty.javaHome();
Path javaHomePolicyPath = Paths.get(javaHomeProperty, "conf",
"security", "policy").normalize();
Path cryptoPolicyPath = Paths.get(javaHomeProperty, "conf", "security",
"policy", cryptoPolicyProperty).normalize();
if (cryptoPolicyPath.getParent().compareTo(javaHomePolicyPath) != 0) {
throw new SecurityException(
"Invalid cryptographic jurisdiction policy directory path: " +
cryptoPolicyProperty);
}
if (!Files.isDirectory(cryptoPolicyPath)
|| !Files.isReadable(cryptoPolicyPath)) {
throw new SecurityException(
"Can't read cryptographic policy directory: " +
cryptoPolicyProperty);
}
try (DirectoryStream<Path> stream = Files.newDirectoryStream(
cryptoPolicyPath, "{default,exempt}_*.policy")) {
for (Path entry : stream) {
try (InputStream is = new BufferedInputStream(
Files.newInputStream(entry))) {
String filename = entry.getFileName().toString();
CryptoPermissions tmpPerms = new CryptoPermissions();
tmpPerms.load(is);
if (filename.startsWith("default_")) {
// Did we find a default perms?
defaultPolicy = ((defaultPolicy == null) ? tmpPerms :
defaultPolicy.getMinimum(tmpPerms));
} else if (filename.startsWith("exempt_")) {
// Did we find a exempt perms?
exemptPolicy = ((exemptPolicy == null) ? tmpPerms :
exemptPolicy.getMinimum(tmpPerms));
} else {
// This should never happen. newDirectoryStream
// should only throw return "{default,exempt}_*.policy"
throw new SecurityException(
"Unexpected jurisdiction policy files in : " +
cryptoPolicyProperty);
}
} catch (Exception e) {
throw new SecurityException(
"Couldn't parse jurisdiction policy files in: " +
cryptoPolicyProperty);
}
}
} catch (DirectoryIteratorException ex) {
// I/O error encountered during the iteration,
// the cause is an IOException
throw new SecurityException(
"Couldn't iterate through the jurisdiction policy files: " +
cryptoPolicyProperty);
}
// Must have a default policy
if ((defaultPolicy == null) || defaultPolicy.isEmpty()) {
throw new SecurityException(
"Missing mandatory jurisdiction policy files: " +
cryptoPolicyProperty);
}
// If there was an empty exempt policy file, ignore it.
if ((exemptPolicy != null) && exemptPolicy.isEmpty()) {
exemptPolicy = null;
}
}
static CryptoPermissions getDefaultPolicy() {
return defaultPolicy;
}
static CryptoPermissions getExemptPolicy() {
return exemptPolicy;
}
static boolean isRestricted() {
return isRestricted;
}
private static final class WeakIdentityWrapper extends WeakReference<Object> {
final int hash;
WeakIdentityWrapper(Provider obj, ReferenceQueue<Object> queue) {
super(obj, queue);
hash = System.identityHashCode(obj);
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
return o instanceof WeakIdentityWrapper w && get() == w.get();
}
@Override
public int hashCode() {
return hash;
}
}
}