/**************************************************************************
* Copyright (c) 2001 by Punch Telematix. All rights reserved. *
* *
* Redistribution and use in source and binary forms, with or without *
* modification, are permitted provided that the following conditions *
* are met: *
* 1. Redistributions of source code must retain the above copyright *
* notice, this list of conditions and the following disclaimer. *
* 2. Redistributions in binary form must reproduce the above copyright *
* notice, this list of conditions and the following disclaimer in the *
* documentation and/or other materials provided with the distribution. *
* 3. Neither the name of Punch Telematix nor the names of *
* other contributors may be used to endorse or promote products *
* derived from this software without specific prior written permission.*
* *
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED *
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF *
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. *
* IN NO EVENT SHALL PUNCH TELEMATIX OR OTHER CONTRIBUTORS BE LIABLE *
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR *
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF *
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR *
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, *
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE *
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN *
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
**************************************************************************/
/**
*
* @version $Id: CodeSource.java,v 1.3 2006/04/18 11:35:28 cvs Exp $
*
*/
package java.security;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.net.SocketPermission;
import java.net.URL;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Vector;
public class CodeSource implements Serializable {
private static final long serialVersionUID = 4977541819976013951L;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
int l = in.readInt();
if(l > 0){
certs = new Certificate[l];
for(int i = 0 ; i < l ; l++){
String type = (String) in.readObject();
in.readInt();
try {
certs[i] = CertificateFactory.getInstance(type).generateCertificate(in);
}
catch(java.security.cert.CertificateException ce){
throw new IOException(ce.toString());
}
}
}
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
int l = (certs == null ? 0 : certs.length);
out.writeInt(l);
for(int i = 0 ; i < l ; i++){
Certificate cert = certs[i];
out.writeObject(cert.getType());
try {
byte[] bytes = cert.getEncoded();
out.writeInt(bytes.length);
out.write(bytes);
}
catch(java.security.cert.CertificateEncodingException cee){
throw new IOException(cee.toString());
}
}
}
private URL url;
private transient Certificate[] certs;
/**
* Constructor CodeSource(URL,Certificate[]) creates a CodeSource
* with the given URL and a snapshot of the given Certificates's
* (else some joker could change the Certificate[] afterward).
*/
public CodeSource (URL url, Certificate[] certs) {
this.url = url;
if (certs != null) {
this.certs = (Certificate[])certs.clone();
}
else {
this.certs = null;
}
}
/**
* Method hashCode() returns a value which depends on the URL and
* on the certificates, but not on the order of the latter.
*/
public int hashCode() {
int hash = (url == null ? -12345 : url.hashCode());
if(certs != null){
for (int i = 0; i< this.certs.length; ++i) {
hash ^= this.certs[i].hashCode();
}
}
return hash;
}
/**
* Method equals(Object) returns true iff the Object is a CodeSource
* and is composed of the same location and the same Certificate's
* (but not necessarily in the same order).
*/
public boolean equals (Object obj) {
boolean answer = false;
if (obj instanceof CodeSource) {
CodeSource target = (CodeSource)obj;
if ( (url == null ? target.url == null : url.equals(target.url)) ) {
Certificate[] targetcerts = target.getCertificates();
if(certs == null || target.certs == null){
return (certs == target.certs);
}
if (certs.length == target.certs.length) {
// O.K., everything else checks and we just need to compare the Certificate's.
// We copy the target's certs into a Vector and look for each of the current
// CodeSource's certs in this Vector. Each time we find a match, we remove
// the corresponding item in the Vector, so the search gets shorter every time.
Vector targets = new Vector(certs.length);
for (int i = 0; i < certs.length; ++i) {
targets.addElement(targetcerts[i]);
}
int found = 0;
for (int i = 0; i < certs.length; ++i) {
found = targets.indexOf(certs[i]);
if (found >= 0) {
targets.removeElementAt(found);
}
else break;
}
answer = (found >= 0);
/*
Johan's code:
boolean notfound;
answer = true;
int i = 0;
int j;
while ((i<certs.length) && answer) {
j = certs.length -i -1;
notfound = true;
while (notfound && (j>=i)) {
if (certs[i].equals(targetcerts[j])) {
notfound = false;
targetcerts[j] = targetcerts[i];
}
j--;
}
answer = !notfound;
i++;
}
*/
}
}
}
return answer;
}
public final URL getLocation() {
return this.url;
}
public final Certificate[] getCertificates() {
return this.certs;
}
/**
* The specification used here is based on that given at
* http://java.sun.com/j2se/1.3/docs/api/java/security/CodeSource.html
*/
public boolean implies (CodeSource codesource) {
// 1. codesource must not be null.
if (codesource==null) {
return false;
}
// 2. If this object's certificates are not null, then all of them must be
// present in codesource's certificates.
if (certs != null) {
Certificate[] targetcerts = codesource.getCertificates();
if(targetcerts == null){
return false;
}
// We copy the target's certs into a Vector and look for each of the current
// CodeSource's certs in this Vector. Each time we find a match, we remove
// the corresponding item in the Vector, so the search gets shorter every time.
Vector targets = new Vector(certs.length);
for (int i = 0; i < certs.length; ++i) {
targets.addElement(targetcerts[i]);
}
int found = 0;
for (int i = 0; i < certs.length; ++i) {
found = targets.indexOf(certs[i]);
if (found >= 0) {
targets.removeElementAt(found);
}
else break;
}
if (found < 0) {
return false;
}
}
// 3. If this object's location is not null, then:
if (url != null) {
// 3a. codesource's location must not be null.
if (codesource.url == null) {
return false;
}
// 3b. If this location equals codesource's location, return true immediately.
if (codesource.url == this.url) {
return true;
}
// 3c. The protocol of this objects's location must be equal to the
// protocol of codesource's location.
if (! this.url.getProtocol().equals(codesource.url.getProtocol())) {
return false;
}
// 3d. If the host of this object's location is not null, then a
// SocketPermission for the host of this object's location must imply
// a SocketPermission for the host of codesource's location.
// (The spec doesn't mention the action, so we specify "resolve" on
// both sides).
String host = this.url.getHost();
if (host != null
&&! (new SocketPermission(host,"resolve")).implies(new SocketPermission(codesource.url.getHost(),"resolve"))) {
return false;
}
// 3e. If the port of this object's location is not -1, then it must be
// equal to the port of codesource's location.
int port = this.url.getPort();
if (port != -1 && ! (port == codesource.url.getPort())) {
return false;
}
// 3f. If the file part of this object's location does not equal the file
// part of codesource's location then one of the following must hold:
String thisfile = this.url.getFile();
String thatfile = codesource.url.getFile();
if (!thisfile.equals(thatfile)) {
int slash = thisfile.lastIndexOf('/');
int slashdash = thisfile.indexOf('-',slash);
int slashstar = thisfile.indexOf('*',slash);
// * If the file part of this object's location ends with "/-", the file
// part of codesource's location must contain the file part of this
// object's location, without the trailing "-", as a prefix.
if (slashdash == thisfile.length()-1
&& ! thatfile.startsWith(thisfile.substring(0,slashdash))) {
return false;
}
// * If the file part of this object's location ends with "/*", the file
// part of codesource's location must contain the file part of this
// object's location, without the trailing "*", as a prefix, and the
// remainder of the file part of codesource's location must not contain
// any '/' character.
else if (slashstar == thisfile.length()-1) {
int thatslash = thatfile.lastIndexOf('/');
if(! thatfile.startsWith(thisfile.substring(0,slashstar))) {
return false;
}
else if (thatslash > slashstar) {
return false;
}
}
// * If the file part of this object's location ends with '/', the file
// part of codesource's location must contain the file part of this
// object's location as a prefix.
else if (slash == thisfile.length()-1
&& ! thatfile.startsWith(thisfile)) {
return false;
}
// * Otherwise the file part of codesource's location must contain the
// file part of this object's location, with "/" appended, as a prefix.
else if (slash != thisfile.length()-1 &&
slashstar != thisfile.length()-1 &&
slashdash != thisfile.length()-1 &&
!thatfile.startsWith(thisfile + "/")) {
return false;
}
// 3g. If the reference part of this object's location is not null, it must
// equal the file part of codesource's location..
String thisref = this.url.getRef();
if (thisref != null && thisref.equals(codesource.getLocation().getRef())) {
return false;
}
}
}
return true;
/*
Johan's code :
boolean answer = false;
if (codesource != null) {
if (certs != null) {
boolean notfound;
Certificate[] targetcerts = codesource.getCertificates();
int i = 0;
answer = true;
while ( (i < certs.length) && answer ) {
int j = 0;
notfound = true;
while ( notfound && (j<targetcerts.length) ) {
notfound = !(certs[i].equals(targetcerts[j]));
j++;
}
answer = !notfound;
i++;
}
}
}
return answer;
*/
}
public String toString ()
{
return url + " " + certs;
}
}