History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/security/CodeSource.java (1 of 18352 files). Show all

Unified · Split

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