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/java/security/CodeSource.java
38829 views
1
/*
2
* Copyright (c) 1997, 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
package java.security;
27
28
29
import java.net.URL;
30
import java.net.SocketPermission;
31
import java.util.ArrayList;
32
import java.util.List;
33
import java.util.Hashtable;
34
import java.io.ByteArrayInputStream;
35
import java.io.IOException;
36
import java.security.cert.*;
37
import sun.misc.IOUtils;
38
39
/**
40
*
41
* <p>This class extends the concept of a codebase to
42
* encapsulate not only the location (URL) but also the certificate chains
43
* that were used to verify signed code originating from that location.
44
*
45
* @author Li Gong
46
* @author Roland Schemers
47
*/
48
49
public class CodeSource implements java.io.Serializable {
50
51
private static final long serialVersionUID = 4977541819976013951L;
52
53
/**
54
* The code location.
55
*
56
* @serial
57
*/
58
private URL location;
59
60
/*
61
* The code signers.
62
*/
63
private transient CodeSigner[] signers = null;
64
65
/*
66
* The code signers. Certificate chains are concatenated.
67
*/
68
private transient java.security.cert.Certificate certs[] = null;
69
70
// cached SocketPermission used for matchLocation
71
private transient SocketPermission sp;
72
73
// for generating cert paths
74
private transient CertificateFactory factory = null;
75
76
/**
77
* Constructs a CodeSource and associates it with the specified
78
* location and set of certificates.
79
*
80
* @param url the location (URL).
81
*
82
* @param certs the certificate(s). It may be null. The contents of the
83
* array are copied to protect against subsequent modification.
84
*/
85
public CodeSource(URL url, java.security.cert.Certificate certs[]) {
86
this.location = url;
87
88
// Copy the supplied certs
89
if (certs != null) {
90
this.certs = certs.clone();
91
}
92
}
93
94
/**
95
* Constructs a CodeSource and associates it with the specified
96
* location and set of code signers.
97
*
98
* @param url the location (URL).
99
* @param signers the code signers. It may be null. The contents of the
100
* array are copied to protect against subsequent modification.
101
*
102
* @since 1.5
103
*/
104
public CodeSource(URL url, CodeSigner[] signers) {
105
this.location = url;
106
107
// Copy the supplied signers
108
if (signers != null) {
109
this.signers = signers.clone();
110
}
111
}
112
113
/**
114
* Returns the hash code value for this object.
115
*
116
* @return a hash code value for this object.
117
*/
118
@Override
119
public int hashCode() {
120
if (location != null)
121
return location.hashCode();
122
else
123
return 0;
124
}
125
126
/**
127
* Tests for equality between the specified object and this
128
* object. Two CodeSource objects are considered equal if their
129
* locations are of identical value and if their signer certificate
130
* chains are of identical value. It is not required that
131
* the certificate chains be in the same order.
132
*
133
* @param obj the object to test for equality with this object.
134
*
135
* @return true if the objects are considered equal, false otherwise.
136
*/
137
@Override
138
public boolean equals(Object obj) {
139
if (obj == this)
140
return true;
141
142
// objects types must be equal
143
if (!(obj instanceof CodeSource))
144
return false;
145
146
CodeSource cs = (CodeSource) obj;
147
148
// URLs must match
149
if (location == null) {
150
// if location is null, then cs.location must be null as well
151
if (cs.location != null) return false;
152
} else {
153
// if location is not null, then it must equal cs.location
154
if (!location.equals(cs.location)) return false;
155
}
156
157
// certs must match
158
return matchCerts(cs, true);
159
}
160
161
/**
162
* Returns the location associated with this CodeSource.
163
*
164
* @return the location (URL).
165
*/
166
public final URL getLocation() {
167
/* since URL is practically immutable, returning itself is not
168
a security problem */
169
return this.location;
170
}
171
172
/**
173
* Returns the certificates associated with this CodeSource.
174
* <p>
175
* If this CodeSource object was created using the
176
* {@link #CodeSource(URL url, CodeSigner[] signers)}
177
* constructor then its certificate chains are extracted and used to
178
* create an array of Certificate objects. Each signer certificate is
179
* followed by its supporting certificate chain (which may be empty).
180
* Each signer certificate and its supporting certificate chain is ordered
181
* bottom-to-top (i.e., with the signer certificate first and the (root)
182
* certificate authority last).
183
*
184
* @return A copy of the certificates array, or null if there is none.
185
*/
186
public final java.security.cert.Certificate[] getCertificates() {
187
if (certs != null) {
188
return certs.clone();
189
190
} else if (signers != null) {
191
// Convert the code signers to certs
192
ArrayList<java.security.cert.Certificate> certChains =
193
new ArrayList<>();
194
for (int i = 0; i < signers.length; i++) {
195
certChains.addAll(
196
signers[i].getSignerCertPath().getCertificates());
197
}
198
certs = certChains.toArray(
199
new java.security.cert.Certificate[certChains.size()]);
200
return certs.clone();
201
202
} else {
203
return null;
204
}
205
}
206
207
/**
208
* Returns the code signers associated with this CodeSource.
209
* <p>
210
* If this CodeSource object was created using the
211
* {@link #CodeSource(URL url, java.security.cert.Certificate[] certs)}
212
* constructor then its certificate chains are extracted and used to
213
* create an array of CodeSigner objects. Note that only X.509 certificates
214
* are examined - all other certificate types are ignored.
215
*
216
* @return A copy of the code signer array, or null if there is none.
217
*
218
* @since 1.5
219
*/
220
public final CodeSigner[] getCodeSigners() {
221
if (signers != null) {
222
return signers.clone();
223
224
} else if (certs != null) {
225
// Convert the certs to code signers
226
signers = convertCertArrayToSignerArray(certs);
227
return signers.clone();
228
229
} else {
230
return null;
231
}
232
}
233
234
/**
235
* Returns true if this CodeSource object "implies" the specified CodeSource.
236
* <p>
237
* More specifically, this method makes the following checks.
238
* If any fail, it returns false. If they all succeed, it returns true.
239
* <ul>
240
* <li> <i>codesource</i> must not be null.
241
* <li> If this object's certificates are not null, then all
242
* of this object's certificates must be present in <i>codesource</i>'s
243
* certificates.
244
* <li> If this object's location (getLocation()) is not null, then the
245
* following checks are made against this object's location and
246
* <i>codesource</i>'s:
247
* <ul>
248
* <li> <i>codesource</i>'s location must not be null.
249
*
250
* <li> If this object's location
251
* equals <i>codesource</i>'s location, then return true.
252
*
253
* <li> This object's protocol (getLocation().getProtocol()) must be
254
* equal to <i>codesource</i>'s protocol, ignoring case.
255
*
256
* <li> If this object's host (getLocation().getHost()) is not null,
257
* then the SocketPermission
258
* constructed with this object's host must imply the
259
* SocketPermission constructed with <i>codesource</i>'s host.
260
*
261
* <li> If this object's port (getLocation().getPort()) is not
262
* equal to -1 (that is, if a port is specified), it must equal
263
* <i>codesource</i>'s port or default port
264
* (codesource.getLocation().getDefaultPort()).
265
*
266
* <li> If this object's file (getLocation().getFile()) doesn't equal
267
* <i>codesource</i>'s file, then the following checks are made:
268
* If this object's file ends with "/-",
269
* then <i>codesource</i>'s file must start with this object's
270
* file (exclusive the trailing "-").
271
* If this object's file ends with a "/*",
272
* then <i>codesource</i>'s file must start with this object's
273
* file and must not have any further "/" separators.
274
* If this object's file doesn't end with a "/",
275
* then <i>codesource</i>'s file must match this object's
276
* file with a '/' appended.
277
*
278
* <li> If this object's reference (getLocation().getRef()) is
279
* not null, it must equal <i>codesource</i>'s reference.
280
*
281
* </ul>
282
* </ul>
283
* <p>
284
* For example, the codesource objects with the following locations
285
* and null certificates all imply
286
* the codesource with the location "http://java.sun.com/classes/foo.jar"
287
* and null certificates:
288
* <pre>
289
* http:
290
* http://*.sun.com/classes/*
291
* http://java.sun.com/classes/-
292
* http://java.sun.com/classes/foo.jar
293
* </pre>
294
*
295
* Note that if this CodeSource has a null location and a null
296
* certificate chain, then it implies every other CodeSource.
297
*
298
* @param codesource CodeSource to compare against.
299
*
300
* @return true if the specified codesource is implied by this codesource,
301
* false if not.
302
*/
303
304
public boolean implies(CodeSource codesource)
305
{
306
if (codesource == null)
307
return false;
308
309
return matchCerts(codesource, false) && matchLocation(codesource);
310
}
311
312
/**
313
* Returns true if all the certs in this
314
* CodeSource are also in <i>that</i>.
315
*
316
* @param that the CodeSource to check against.
317
* @param strict If true then a strict equality match is performed.
318
* Otherwise a subset match is performed.
319
*/
320
private boolean matchCerts(CodeSource that, boolean strict)
321
{
322
boolean match;
323
324
// match any key
325
if (certs == null && signers == null) {
326
if (strict) {
327
return (that.certs == null && that.signers == null);
328
} else {
329
return true;
330
}
331
// both have signers
332
} else if (signers != null && that.signers != null) {
333
if (strict && signers.length != that.signers.length) {
334
return false;
335
}
336
for (int i = 0; i < signers.length; i++) {
337
match = false;
338
for (int j = 0; j < that.signers.length; j++) {
339
if (signers[i].equals(that.signers[j])) {
340
match = true;
341
break;
342
}
343
}
344
if (!match) return false;
345
}
346
return true;
347
348
// both have certs
349
} else if (certs != null && that.certs != null) {
350
if (strict && certs.length != that.certs.length) {
351
return false;
352
}
353
for (int i = 0; i < certs.length; i++) {
354
match = false;
355
for (int j = 0; j < that.certs.length; j++) {
356
if (certs[i].equals(that.certs[j])) {
357
match = true;
358
break;
359
}
360
}
361
if (!match) return false;
362
}
363
return true;
364
}
365
366
return false;
367
}
368
369
370
/**
371
* Returns true if two CodeSource's have the "same" location.
372
*
373
* @param that CodeSource to compare against
374
*/
375
private boolean matchLocation(CodeSource that) {
376
if (location == null)
377
return true;
378
379
if ((that == null) || (that.location == null))
380
return false;
381
382
if (location.equals(that.location))
383
return true;
384
385
if (!location.getProtocol().equalsIgnoreCase(that.location.getProtocol()))
386
return false;
387
388
int thisPort = location.getPort();
389
if (thisPort != -1) {
390
int thatPort = that.location.getPort();
391
int port = thatPort != -1 ? thatPort
392
: that.location.getDefaultPort();
393
if (thisPort != port)
394
return false;
395
}
396
397
if (location.getFile().endsWith("/-")) {
398
// Matches the directory and (recursively) all files
399
// and subdirectories contained in that directory.
400
// For example, "/a/b/-" implies anything that starts with
401
// "/a/b/"
402
String thisPath = location.getFile().substring(0,
403
location.getFile().length()-1);
404
if (!that.location.getFile().startsWith(thisPath))
405
return false;
406
} else if (location.getFile().endsWith("/*")) {
407
// Matches the directory and all the files contained in that
408
// directory.
409
// For example, "/a/b/*" implies anything that starts with
410
// "/a/b/" but has no further slashes
411
int last = that.location.getFile().lastIndexOf('/');
412
if (last == -1)
413
return false;
414
String thisPath = location.getFile().substring(0,
415
location.getFile().length()-1);
416
String thatPath = that.location.getFile().substring(0, last+1);
417
if (!thatPath.equals(thisPath))
418
return false;
419
} else {
420
// Exact matches only.
421
// For example, "/a/b" and "/a/b/" both imply "/a/b/"
422
if ((!that.location.getFile().equals(location.getFile()))
423
&& (!that.location.getFile().equals(location.getFile()+"/"))) {
424
return false;
425
}
426
}
427
428
if (location.getRef() != null
429
&& !location.getRef().equals(that.location.getRef())) {
430
return false;
431
}
432
433
String thisHost = location.getHost();
434
String thatHost = that.location.getHost();
435
if (thisHost != null) {
436
if (("".equals(thisHost) || "localhost".equals(thisHost)) &&
437
("".equals(thatHost) || "localhost".equals(thatHost))) {
438
// ok
439
} else if (!thisHost.equals(thatHost)) {
440
if (thatHost == null) {
441
return false;
442
}
443
if (this.sp == null) {
444
this.sp = new SocketPermission(thisHost, "resolve");
445
}
446
if (that.sp == null) {
447
that.sp = new SocketPermission(thatHost, "resolve");
448
}
449
if (!this.sp.implies(that.sp)) {
450
return false;
451
}
452
}
453
}
454
// everything matches
455
return true;
456
}
457
458
/**
459
* Returns a string describing this CodeSource, telling its
460
* URL and certificates.
461
*
462
* @return information about this CodeSource.
463
*/
464
@Override
465
public String toString() {
466
StringBuilder sb = new StringBuilder();
467
sb.append("(");
468
sb.append(this.location);
469
470
if (this.certs != null && this.certs.length > 0) {
471
for (int i = 0; i < this.certs.length; i++) {
472
sb.append( " " + this.certs[i]);
473
}
474
475
} else if (this.signers != null && this.signers.length > 0) {
476
for (int i = 0; i < this.signers.length; i++) {
477
sb.append( " " + this.signers[i]);
478
}
479
} else {
480
sb.append(" <no signer certificates>");
481
}
482
sb.append(")");
483
return sb.toString();
484
}
485
486
/**
487
* Writes this object out to a stream (i.e., serializes it).
488
*
489
* @serialData An initial {@code URL} is followed by an
490
* {@code int} indicating the number of certificates to follow
491
* (a value of "zero" denotes that there are no certificates associated
492
* with this object).
493
* Each certificate is written out starting with a {@code String}
494
* denoting the certificate type, followed by an
495
* {@code int} specifying the length of the certificate encoding,
496
* followed by the certificate encoding itself which is written out as an
497
* array of bytes. Finally, if any code signers are present then the array
498
* of code signers is serialized and written out too.
499
*/
500
private void writeObject(java.io.ObjectOutputStream oos)
501
throws IOException
502
{
503
oos.defaultWriteObject(); // location
504
505
// Serialize the array of certs
506
if (certs == null || certs.length == 0) {
507
oos.writeInt(0);
508
} else {
509
// write out the total number of certs
510
oos.writeInt(certs.length);
511
// write out each cert, including its type
512
for (int i = 0; i < certs.length; i++) {
513
java.security.cert.Certificate cert = certs[i];
514
try {
515
oos.writeUTF(cert.getType());
516
byte[] encoded = cert.getEncoded();
517
oos.writeInt(encoded.length);
518
oos.write(encoded);
519
} catch (CertificateEncodingException cee) {
520
throw new IOException(cee.getMessage());
521
}
522
}
523
}
524
525
// Serialize the array of code signers (if any)
526
if (signers != null && signers.length > 0) {
527
oos.writeObject(signers);
528
}
529
}
530
531
/**
532
* Restores this object from a stream (i.e., deserializes it).
533
*/
534
private void readObject(java.io.ObjectInputStream ois)
535
throws IOException, ClassNotFoundException
536
{
537
CertificateFactory cf;
538
Hashtable<String, CertificateFactory> cfs = null;
539
List<java.security.cert.Certificate> certList = null;
540
541
ois.defaultReadObject(); // location
542
543
// process any new-style certs in the stream (if present)
544
int size = ois.readInt();
545
if (size > 0) {
546
// we know of 3 different cert types: X.509, PGP, SDSI, which
547
// could all be present in the stream at the same time
548
cfs = new Hashtable<String, CertificateFactory>(3);
549
certList = new ArrayList<>(size > 20 ? 20 : size);
550
} else if (size < 0) {
551
throw new IOException("size cannot be negative");
552
}
553
554
for (int i = 0; i < size; i++) {
555
// read the certificate type, and instantiate a certificate
556
// factory of that type (reuse existing factory if possible)
557
String certType = ois.readUTF();
558
if (cfs.containsKey(certType)) {
559
// reuse certificate factory
560
cf = cfs.get(certType);
561
} else {
562
// create new certificate factory
563
try {
564
cf = CertificateFactory.getInstance(certType);
565
} catch (CertificateException ce) {
566
throw new ClassNotFoundException
567
("Certificate factory for " + certType + " not found");
568
}
569
// store the certificate factory so we can reuse it later
570
cfs.put(certType, cf);
571
}
572
// parse the certificate
573
byte[] encoded = IOUtils.readExactlyNBytes(ois, ois.readInt());
574
ByteArrayInputStream bais = new ByteArrayInputStream(encoded);
575
try {
576
certList.add(cf.generateCertificate(bais));
577
} catch (CertificateException ce) {
578
throw new IOException(ce.getMessage());
579
}
580
bais.close();
581
}
582
583
if (certList != null) {
584
this.certs = certList.toArray(
585
new java.security.cert.Certificate[size]);
586
}
587
// Deserialize array of code signers (if any)
588
try {
589
this.signers = ((CodeSigner[])ois.readObject()).clone();
590
} catch (IOException ioe) {
591
// no signers present
592
}
593
}
594
595
/*
596
* Convert an array of certificates to an array of code signers.
597
* The array of certificates is a concatenation of certificate chains
598
* where the initial certificate in each chain is the end-entity cert.
599
*
600
* @return An array of code signers or null if none are generated.
601
*/
602
private CodeSigner[] convertCertArrayToSignerArray(
603
java.security.cert.Certificate[] certs) {
604
605
if (certs == null) {
606
return null;
607
}
608
609
try {
610
// Initialize certificate factory
611
if (factory == null) {
612
factory = CertificateFactory.getInstance("X.509");
613
}
614
615
// Iterate through all the certificates
616
int i = 0;
617
List<CodeSigner> signers = new ArrayList<>();
618
while (i < certs.length) {
619
List<java.security.cert.Certificate> certChain =
620
new ArrayList<>();
621
certChain.add(certs[i++]); // first cert is an end-entity cert
622
int j = i;
623
624
// Extract chain of certificates
625
// (loop while certs are not end-entity certs)
626
while (j < certs.length &&
627
certs[j] instanceof X509Certificate &&
628
((X509Certificate)certs[j]).getBasicConstraints() != -1) {
629
certChain.add(certs[j]);
630
j++;
631
}
632
i = j;
633
CertPath certPath = factory.generateCertPath(certChain);
634
signers.add(new CodeSigner(certPath, null));
635
}
636
637
if (signers.isEmpty()) {
638
return null;
639
} else {
640
return signers.toArray(new CodeSigner[signers.size()]);
641
}
642
643
} catch (CertificateException e) {
644
return null; //TODO - may be better to throw an ex. here
645
}
646
}
647
}
648
649