Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/javax/crypto/CryptoPolicyParser.java
38829 views
1
/*
2
* Copyright (c) 1999, 2012, 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
package javax.crypto;
27
28
import java.io.*;
29
import java.util.Enumeration;
30
import java.util.Hashtable;
31
import java.util.Vector;
32
import static java.util.Locale.ENGLISH;
33
34
import java.security.GeneralSecurityException;
35
import java.security.spec.AlgorithmParameterSpec;
36
import java.lang.reflect.*;
37
38
/**
39
* JCE has two pairs of jurisdiction policy files: one represents U.S. export
40
* laws, and the other represents the local laws of the country where the
41
* JCE will be used.
42
*
43
* The jurisdiction policy file has the same syntax as JDK policy files except
44
* that JCE has new permission classes called javax.crypto.CryptoPermission
45
* and javax.crypto.CryptoAllPermission.
46
*
47
* The format of a permission entry in the jurisdiction policy file is:
48
*
49
* permission <crypto permission class name>[, <algorithm name>
50
* [[, <exemption mechanism name>][, <maxKeySize>
51
* [, <AlgrithomParameterSpec class name>, <parameters
52
* for constructing an AlgrithomParameterSpec object>]]]];
53
*
54
* @author Sharon Liu
55
*
56
* @see java.security.Permissions
57
* @see java.security.spec.AlgorithmParameterSpec
58
* @see javax.crypto.CryptoPermission
59
* @see javax.crypto.CryptoAllPermission
60
* @see javax.crypto.CryptoPermissions
61
* @since 1.4
62
*/
63
64
final class CryptoPolicyParser {
65
66
private Vector<GrantEntry> grantEntries;
67
68
// Convenience variables for parsing
69
private StreamTokenizer st;
70
private int lookahead;
71
72
/**
73
* Creates a CryptoPolicyParser object.
74
*/
75
CryptoPolicyParser() {
76
grantEntries = new Vector<GrantEntry>();
77
}
78
79
/**
80
* Reads a policy configuration using a Reader object. <p>
81
*
82
* @param policy the policy Reader object.
83
*
84
* @exception ParsingException if the policy configuration
85
* contains a syntax error.
86
*
87
* @exception IOException if an error occurs while reading
88
* the policy configuration.
89
*/
90
91
void read(Reader policy)
92
throws ParsingException, IOException
93
{
94
if (!(policy instanceof BufferedReader)) {
95
policy = new BufferedReader(policy);
96
}
97
98
/*
99
* Configure the stream tokenizer:
100
* Recognize strings between "..."
101
* Don't convert words to lowercase
102
* Recognize both C-style and C++-style comments
103
* Treat end-of-line as white space, not as a token
104
*/
105
st = new StreamTokenizer(policy);
106
107
st.resetSyntax();
108
st.wordChars('a', 'z');
109
st.wordChars('A', 'Z');
110
st.wordChars('.', '.');
111
st.wordChars('0', '9');
112
st.wordChars('_', '_');
113
st.wordChars('$', '$');
114
st.wordChars(128 + 32, 255);
115
st.whitespaceChars(0, ' ');
116
st.commentChar('/');
117
st.quoteChar('\'');
118
st.quoteChar('"');
119
st.lowerCaseMode(false);
120
st.ordinaryChar('/');
121
st.slashSlashComments(true);
122
st.slashStarComments(true);
123
st.parseNumbers();
124
125
/*
126
* The crypto jurisdiction policy must be consistent. The
127
* following hashtable is used for checking consistency.
128
*/
129
Hashtable<String, Vector<String>> processedPermissions = null;
130
131
/*
132
* The main parsing loop. The loop is executed once for each entry
133
* in the policy file. The entries are delimited by semicolons. Once
134
* we've read in the information for an entry, go ahead and try to
135
* add it to the grantEntries.
136
*/
137
lookahead = st.nextToken();
138
while (lookahead != StreamTokenizer.TT_EOF) {
139
if (peek("grant")) {
140
GrantEntry ge = parseGrantEntry(processedPermissions);
141
if (ge != null)
142
grantEntries.addElement(ge);
143
} else {
144
throw new ParsingException(st.lineno(), "expected grant " +
145
"statement");
146
}
147
match(";");
148
}
149
}
150
151
/**
152
* parse a Grant entry
153
*/
154
private GrantEntry parseGrantEntry(
155
Hashtable<String, Vector<String>> processedPermissions)
156
throws ParsingException, IOException
157
{
158
GrantEntry e = new GrantEntry();
159
160
match("grant");
161
match("{");
162
163
while(!peek("}")) {
164
if (peek("Permission")) {
165
CryptoPermissionEntry pe =
166
parsePermissionEntry(processedPermissions);
167
e.add(pe);
168
match(";");
169
} else {
170
throw new
171
ParsingException(st.lineno(), "expected permission entry");
172
}
173
}
174
match("}");
175
176
return e;
177
}
178
179
/**
180
* parse a CryptoPermission entry
181
*/
182
private CryptoPermissionEntry parsePermissionEntry(
183
Hashtable<String, Vector<String>> processedPermissions)
184
throws ParsingException, IOException
185
{
186
CryptoPermissionEntry e = new CryptoPermissionEntry();
187
188
match("Permission");
189
e.cryptoPermission = match("permission type");
190
191
if (e.cryptoPermission.equals("javax.crypto.CryptoAllPermission")) {
192
// Done with the CryptoAllPermission entry.
193
e.alg = CryptoAllPermission.ALG_NAME;
194
e.maxKeySize = Integer.MAX_VALUE;
195
return e;
196
}
197
198
// Should see the algorithm name.
199
if (peek("\"")) {
200
// Algorithm name - always convert to upper case after parsing.
201
e.alg = match("quoted string").toUpperCase(ENGLISH);
202
} else {
203
// The algorithm name can be a wildcard.
204
if (peek("*")) {
205
match("*");
206
e.alg = CryptoPermission.ALG_NAME_WILDCARD;
207
} else {
208
throw new ParsingException(st.lineno(),
209
"Missing the algorithm name");
210
}
211
}
212
213
peekAndMatch(",");
214
215
// May see the exemption mechanism name.
216
if (peek("\"")) {
217
// Exemption mechanism name - convert to upper case too.
218
e.exemptionMechanism = match("quoted string").toUpperCase(ENGLISH);
219
}
220
221
peekAndMatch(",");
222
223
// Check whether this entry is consistent with other permission entries
224
// that have been read.
225
if (!isConsistent(e.alg, e.exemptionMechanism, processedPermissions)) {
226
throw new ParsingException(st.lineno(), "Inconsistent policy");
227
}
228
229
// Should see the maxKeySize if not at the end of this entry yet.
230
if (peek("number")) {
231
e.maxKeySize = match();
232
} else {
233
if (peek("*")) {
234
match("*");
235
e.maxKeySize = Integer.MAX_VALUE;
236
} else {
237
if (!peek(";")) {
238
throw new ParsingException(st.lineno(),
239
"Missing the maximum " +
240
"allowable key size");
241
} else {
242
// At the end of this permission entry
243
e.maxKeySize = Integer.MAX_VALUE;
244
}
245
}
246
}
247
248
peekAndMatch(",");
249
250
// May see an AlgorithmParameterSpec class name.
251
if (peek("\"")) {
252
// AlgorithmParameterSpec class name.
253
String algParamSpecClassName = match("quoted string");
254
255
Vector<Integer> paramsV = new Vector<>(1);
256
while (peek(",")) {
257
match(",");
258
if (peek("number")) {
259
paramsV.addElement(new Integer(match()));
260
} else {
261
if (peek("*")) {
262
match("*");
263
paramsV.addElement(new Integer(Integer.MAX_VALUE));
264
} else {
265
throw new ParsingException(st.lineno(),
266
"Expecting an integer");
267
}
268
}
269
}
270
271
Integer[] params = new Integer[paramsV.size()];
272
paramsV.copyInto(params);
273
274
e.checkParam = true;
275
e.algParamSpec = getInstance(algParamSpecClassName, params);
276
}
277
278
return e;
279
}
280
281
private static final AlgorithmParameterSpec getInstance(String type,
282
Integer[] params)
283
throws ParsingException
284
{
285
AlgorithmParameterSpec ret = null;
286
287
try {
288
Class<?> apsClass = Class.forName(type);
289
Class<?>[] paramClasses = new Class<?>[params.length];
290
291
for (int i = 0; i < params.length; i++) {
292
paramClasses[i] = int.class;
293
}
294
295
Constructor<?> c = apsClass.getConstructor(paramClasses);
296
ret = (AlgorithmParameterSpec) c.newInstance((Object[]) params);
297
} catch (Exception e) {
298
throw new ParsingException("Cannot call the constructor of " +
299
type + e);
300
}
301
return ret;
302
}
303
304
305
private boolean peekAndMatch(String expect)
306
throws ParsingException, IOException
307
{
308
if (peek(expect)) {
309
match(expect);
310
return true;
311
}
312
return false;
313
}
314
315
private boolean peek(String expect) {
316
boolean found = false;
317
318
switch (lookahead) {
319
320
case StreamTokenizer.TT_WORD:
321
if (expect.equalsIgnoreCase(st.sval))
322
found = true;
323
break;
324
case StreamTokenizer.TT_NUMBER:
325
if (expect.equalsIgnoreCase("number")) {
326
found = true;
327
}
328
break;
329
case ',':
330
if (expect.equals(","))
331
found = true;
332
break;
333
case '{':
334
if (expect.equals("{"))
335
found = true;
336
break;
337
case '}':
338
if (expect.equals("}"))
339
found = true;
340
break;
341
case '"':
342
if (expect.equals("\""))
343
found = true;
344
break;
345
case '*':
346
if (expect.equals("*"))
347
found = true;
348
break;
349
case ';':
350
if (expect.equals(";"))
351
found = true;
352
break;
353
default:
354
break;
355
}
356
return found;
357
}
358
359
/**
360
* Excepts to match a non-negative number.
361
*/
362
private int match()
363
throws ParsingException, IOException
364
{
365
int value = -1;
366
int lineno = st.lineno();
367
String sValue = null;
368
369
switch (lookahead) {
370
case StreamTokenizer.TT_NUMBER:
371
value = (int)st.nval;
372
if (value < 0) {
373
sValue = String.valueOf(st.nval);
374
}
375
lookahead = st.nextToken();
376
break;
377
default:
378
sValue = st.sval;
379
break;
380
}
381
if (value <= 0) {
382
throw new ParsingException(lineno, "a non-negative number",
383
sValue);
384
}
385
return value;
386
}
387
388
private String match(String expect)
389
throws ParsingException, IOException
390
{
391
String value = null;
392
393
switch (lookahead) {
394
case StreamTokenizer.TT_NUMBER:
395
throw new ParsingException(st.lineno(), expect,
396
"number "+String.valueOf(st.nval));
397
case StreamTokenizer.TT_EOF:
398
throw new ParsingException("expected "+expect+", read end of file");
399
case StreamTokenizer.TT_WORD:
400
if (expect.equalsIgnoreCase(st.sval)) {
401
lookahead = st.nextToken();
402
}
403
else if (expect.equalsIgnoreCase("permission type")) {
404
value = st.sval;
405
lookahead = st.nextToken();
406
}
407
else
408
throw new ParsingException(st.lineno(), expect, st.sval);
409
break;
410
case '"':
411
if (expect.equalsIgnoreCase("quoted string")) {
412
value = st.sval;
413
lookahead = st.nextToken();
414
} else if (expect.equalsIgnoreCase("permission type")) {
415
value = st.sval;
416
lookahead = st.nextToken();
417
}
418
else
419
throw new ParsingException(st.lineno(), expect, st.sval);
420
break;
421
case ',':
422
if (expect.equals(","))
423
lookahead = st.nextToken();
424
else
425
throw new ParsingException(st.lineno(), expect, ",");
426
break;
427
case '{':
428
if (expect.equals("{"))
429
lookahead = st.nextToken();
430
else
431
throw new ParsingException(st.lineno(), expect, "{");
432
break;
433
case '}':
434
if (expect.equals("}"))
435
lookahead = st.nextToken();
436
else
437
throw new ParsingException(st.lineno(), expect, "}");
438
break;
439
case ';':
440
if (expect.equals(";"))
441
lookahead = st.nextToken();
442
else
443
throw new ParsingException(st.lineno(), expect, ";");
444
break;
445
case '*':
446
if (expect.equals("*"))
447
lookahead = st.nextToken();
448
else
449
throw new ParsingException(st.lineno(), expect, "*");
450
break;
451
default:
452
throw new ParsingException(st.lineno(), expect,
453
new String(new char[] {(char)lookahead}));
454
}
455
return value;
456
}
457
458
CryptoPermission[] getPermissions() {
459
Vector<CryptoPermission> result = new Vector<>();
460
461
Enumeration<GrantEntry> grantEnum = grantEntries.elements();
462
while (grantEnum.hasMoreElements()) {
463
GrantEntry ge = grantEnum.nextElement();
464
Enumeration<CryptoPermissionEntry> permEnum =
465
ge.permissionElements();
466
while (permEnum.hasMoreElements()) {
467
CryptoPermissionEntry pe = permEnum.nextElement();
468
if (pe.cryptoPermission.equals(
469
"javax.crypto.CryptoAllPermission")) {
470
result.addElement(CryptoAllPermission.INSTANCE);
471
} else {
472
if (pe.checkParam) {
473
result.addElement(new CryptoPermission(
474
pe.alg,
475
pe.maxKeySize,
476
pe.algParamSpec,
477
pe.exemptionMechanism));
478
} else {
479
result.addElement(new CryptoPermission(
480
pe.alg,
481
pe.maxKeySize,
482
pe.exemptionMechanism));
483
}
484
}
485
}
486
}
487
488
CryptoPermission[] ret = new CryptoPermission[result.size()];
489
result.copyInto(ret);
490
491
return ret;
492
}
493
494
private boolean isConsistent(String alg, String exemptionMechanism,
495
Hashtable<String, Vector<String>> processedPermissions) {
496
String thisExemptionMechanism =
497
exemptionMechanism == null ? "none" : exemptionMechanism;
498
499
if (processedPermissions == null) {
500
processedPermissions = new Hashtable<String, Vector<String>>();
501
Vector<String> exemptionMechanisms = new Vector<>(1);
502
exemptionMechanisms.addElement(thisExemptionMechanism);
503
processedPermissions.put(alg, exemptionMechanisms);
504
return true;
505
}
506
507
if (processedPermissions.containsKey(CryptoAllPermission.ALG_NAME)) {
508
return false;
509
}
510
511
Vector<String> exemptionMechanisms;
512
513
if (processedPermissions.containsKey(alg)) {
514
exemptionMechanisms = processedPermissions.get(alg);
515
if (exemptionMechanisms.contains(thisExemptionMechanism)) {
516
return false;
517
}
518
} else {
519
exemptionMechanisms = new Vector<String>(1);
520
}
521
522
exemptionMechanisms.addElement(thisExemptionMechanism);
523
processedPermissions.put(alg, exemptionMechanisms);
524
return true;
525
}
526
527
/**
528
* Each grant entry in the policy configuration file is represented by a
529
* GrantEntry object. <p>
530
*
531
* <p>
532
* For example, the entry
533
* <pre>
534
* grant {
535
* permission javax.crypto.CryptoPermission "DES", 56;
536
* };
537
*
538
* </pre>
539
* is represented internally
540
* <pre>
541
*
542
* pe = new CryptoPermissionEntry("javax.crypto.CryptoPermission",
543
* "DES", 56);
544
*
545
* ge = new GrantEntry();
546
*
547
* ge.add(pe);
548
*
549
* </pre>
550
*
551
* @see java.security.Permission
552
* @see javax.crypto.CryptoPermission
553
* @see javax.crypto.CryptoPermissions
554
*/
555
556
private static class GrantEntry {
557
558
private Vector<CryptoPermissionEntry> permissionEntries;
559
560
GrantEntry() {
561
permissionEntries = new Vector<CryptoPermissionEntry>();
562
}
563
564
void add(CryptoPermissionEntry pe)
565
{
566
permissionEntries.addElement(pe);
567
}
568
569
boolean remove(CryptoPermissionEntry pe)
570
{
571
return permissionEntries.removeElement(pe);
572
}
573
574
boolean contains(CryptoPermissionEntry pe)
575
{
576
return permissionEntries.contains(pe);
577
}
578
579
/**
580
* Enumerate all the permission entries in this GrantEntry.
581
*/
582
Enumeration<CryptoPermissionEntry> permissionElements(){
583
return permissionEntries.elements();
584
}
585
586
}
587
588
/**
589
* Each crypto permission entry in the policy configuration file is
590
* represented by a CryptoPermissionEntry object. <p>
591
*
592
* <p>
593
* For example, the entry
594
* <pre>
595
* permission javax.crypto.CryptoPermission "DES", 56;
596
* </pre>
597
* is represented internally
598
* <pre>
599
*
600
* pe = new CryptoPermissionEntry("javax.crypto.cryptoPermission",
601
* "DES", 56);
602
* </pre>
603
*
604
* @see java.security.Permissions
605
* @see javax.crypto.CryptoPermission
606
* @see javax.crypto.CryptoAllPermission
607
*/
608
609
private static class CryptoPermissionEntry {
610
611
String cryptoPermission;
612
String alg;
613
String exemptionMechanism;
614
int maxKeySize;
615
boolean checkParam;
616
AlgorithmParameterSpec algParamSpec;
617
618
CryptoPermissionEntry() {
619
// Set default values.
620
maxKeySize = 0;
621
alg = null;
622
exemptionMechanism = null;
623
checkParam = false;
624
algParamSpec = null;
625
}
626
627
/**
628
* Calculates a hash code value for the object. Objects
629
* which are equal will also have the same hashcode.
630
*/
631
public int hashCode() {
632
int retval = cryptoPermission.hashCode();
633
if (alg != null) retval ^= alg.hashCode();
634
if (exemptionMechanism != null) {
635
retval ^= exemptionMechanism.hashCode();
636
}
637
retval ^= maxKeySize;
638
if (checkParam) retval ^= 100;
639
if (algParamSpec != null) {
640
retval ^= algParamSpec.hashCode();
641
}
642
return retval;
643
}
644
645
public boolean equals(Object obj) {
646
if (obj == this)
647
return true;
648
649
if (!(obj instanceof CryptoPermissionEntry))
650
return false;
651
652
CryptoPermissionEntry that = (CryptoPermissionEntry) obj;
653
654
if (this.cryptoPermission == null) {
655
if (that.cryptoPermission != null) return false;
656
} else {
657
if (!this.cryptoPermission.equals(
658
that.cryptoPermission))
659
return false;
660
}
661
662
if (this.alg == null) {
663
if (that.alg != null) return false;
664
} else {
665
if (!this.alg.equalsIgnoreCase(that.alg))
666
return false;
667
}
668
669
if (!(this.maxKeySize == that.maxKeySize)) return false;
670
671
if (this.checkParam != that.checkParam) return false;
672
673
if (this.algParamSpec == null) {
674
if (that.algParamSpec != null) return false;
675
} else {
676
if (!this.algParamSpec.equals(that.algParamSpec))
677
return false;
678
}
679
680
// everything matched -- the 2 objects are equal
681
return true;
682
}
683
}
684
685
static final class ParsingException extends GeneralSecurityException {
686
687
private static final long serialVersionUID = 7147241245566588374L;
688
689
/**
690
* Constructs a ParsingException with the specified
691
* detail message.
692
* @param msg the detail message.
693
*/
694
ParsingException(String msg) {
695
super(msg);
696
}
697
698
ParsingException(int line, String msg) {
699
super("line " + line + ": " + msg);
700
}
701
702
ParsingException(int line, String expect, String actual) {
703
super("line "+line+": expected '"+expect+"', found '"+actual+"'");
704
}
705
}
706
}
707
708