blob: d1beab8db3f0afd005e808c455f20968f0348776 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2007 IBM Corporation and others. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*
* Contributors: IBM Corporation - initial API and implementation
******************************************************************************/
package org.eclipse.osgi.internal.verifier;
import java.io.*;
import java.security.cert.*;
import java.util.*;
import org.eclipse.osgi.baseadaptor.BaseData;
import org.eclipse.osgi.baseadaptor.hooks.StorageHook;
import org.eclipse.osgi.framework.util.KeyedElement;
import org.eclipse.osgi.internal.provisional.verifier.CertificateChain;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
public class SignedStorageHook implements StorageHook {
static final String KEY = SignedStorageHook.class.getName();
static final int HASHCODE = KEY.hashCode();
private static final int STORAGE_VERSION = 2;
private static ArrayList saveChainCache = new ArrayList(5);
private static long firstIDSaved = -1;
private static long lastIDSaved = -1;
private static ArrayList loadChainCache = new ArrayList(5);
private static long lastIDLoaded;
private BaseData bundledata;
SignedBundleFile signedBundleFile;
public int getStorageVersion() {
return STORAGE_VERSION;
}
public StorageHook create(BaseData bundledata) throws BundleException {
SignedStorageHook hook = new SignedStorageHook();
hook.bundledata = bundledata;
return hook;
}
public void initialize(Dictionary manifest) throws BundleException {
// do nothing
}
public StorageHook load(BaseData target, DataInputStream is) throws IOException {
if (lastIDLoaded > target.getBundleID())
loadChainCache.clear();
lastIDLoaded = target.getBundleID();
SignedStorageHook hook = new SignedStorageHook();
hook.bundledata = target;
boolean signed = is.readBoolean();
if (!signed)
return hook;
int numChains = is.readInt();
CertificateChain[] chains = new CertificateChain[numChains];
for (int i = 0; i < numChains; i++) {
int chainIdx = is.readInt();
if (chainIdx >= 0) {
chains[i] = (CertificateChain) loadChainCache.get(chainIdx);
if (chains[i] == null)
throw new IOException("Invalid chain cache."); //$NON-NLS-1$
continue;
}
String chain = is.readUTF();
boolean trusted = is.readBoolean();
int numCerts = is.readInt();
byte[][] certsBytes = new byte[numCerts][];
for (int j = 0; j < certsBytes.length; j++) {
int numBytes = is.readInt();
certsBytes[j] = new byte[numBytes];
is.readFully(certsBytes[j]);
}
long signingTime = is.readLong();
try {
chains[i] = new PKCS7Processor(chain, trusted, certsBytes, signingTime);
} catch (CertificateException e) {
throw new IOException(e.getMessage());
}
loadChainCache.add(chains[i]);
}
int numEntries = is.readInt();
Hashtable digests = null;
Hashtable results = null;
if (numEntries >= 0) {
digests = new Hashtable(numEntries);
results = new Hashtable(numEntries);
for (int i = 0; i < numEntries; i++) {
String entry = is.readUTF();
String md;
byte[] result;
if (is.readInt() == 0)
md = JarVerifierConstant.MD5_STR;
else
md = JarVerifierConstant.SHA1_STR;
result = new byte[is.readInt()];
is.readFully(result);
digests.put(entry, md);
results.put(entry, result);
}
}
String md5Result = null;
String shaResult = null;
if (is.readBoolean())
md5Result = is.readUTF();
if (is.readBoolean())
shaResult = is.readUTF();
hook.signedBundleFile = new SignedBundleFile(chains, digests, results, md5Result, shaResult);
return hook;
}
public void save(DataOutputStream os) throws IOException {
getFirstLastID();
if (firstIDSaved == bundledata.getBundleID())
saveChainCache.clear();
if (lastIDSaved == bundledata.getBundleID())
firstIDSaved = lastIDSaved = -1;
SignedBundleFile signedFile = signedBundleFile;
CertificateChain[] chains = null;
String md5Result = null;
String shaResult = null;
Hashtable digests = null;
Hashtable results = null;
if (signedFile != null) {
chains = signedFile.chains;
md5Result = signedFile.manifestMD5Result;
shaResult = signedFile.manifestSHAResult;
digests = signedFile.digests4entries;
results = signedFile.results4entries;
}
os.writeBoolean(chains != null);
if (chains == null)
return;
os.writeInt(chains.length);
for (int i = 0; i < chains.length; i++) {
int cacheIdx = saveChainCache.indexOf(chains[i]);
os.writeInt(cacheIdx);
if (cacheIdx >= 0)
continue;
saveChainCache.add(chains[i]);
os.writeUTF(chains[i].getChain());
os.writeBoolean(chains[i].isTrusted());
Certificate[] certs = chains[i].getCertificates();
os.writeInt(certs == null ? 0 : certs.length);
if (certs != null)
for (int j = 0; j < certs.length; j++) {
byte[] certBytes;
try {
certBytes = certs[j].getEncoded();
} catch (CertificateEncodingException e) {
throw new IOException(e.getMessage());
}
os.writeInt(certBytes.length);
os.write(certBytes);
}
os.writeLong(chains[i].getSigningTime() != null ? chains[i].getSigningTime().getTime() : Long.MIN_VALUE);
}
if (digests == null)
os.writeInt(-1);
else {
os.writeInt(digests.size());
for (Enumeration entries = digests.keys(); entries.hasMoreElements();) {
String entry = (String) entries.nextElement();
String md = (String) digests.get(entry);
byte[] result = (byte[]) results.get(entry);
os.writeUTF(entry);
if (md == JarVerifierConstant.MD2_STR)
os.writeInt(0);
else
os.writeInt(1);
os.writeInt(result.length);
os.write(result);
}
}
os.writeBoolean(md5Result != null);
if (md5Result != null)
os.writeUTF(md5Result);
os.writeBoolean(shaResult != null);
if (shaResult != null)
os.writeUTF(shaResult);
}
private void getFirstLastID() {
if (firstIDSaved >= 0)
return;
Bundle[] bundles = bundledata.getAdaptor().getContext().getBundles();
if (bundles.length > 1) {
firstIDSaved = bundles[1].getBundleId();
lastIDSaved = bundles[bundles.length - 1].getBundleId();
}
}
public void copy(StorageHook storageHook) {
// do nothing
}
public void validate() throws IllegalArgumentException {
// do nothing
}
public Dictionary getManifest(boolean firstLoad) throws BundleException {
// do nothing
return null;
}
public boolean forgetStatusChange(int status) {
// do nothing
return false;
}
public boolean forgetStartLevelChange(int startlevel) {
// do nothing
return false;
}
public boolean matchDNChain(String pattern) {
return signedBundleFile == null ? false : signedBundleFile.matchDNChain(pattern);
}
public int getKeyHashCode() {
return HASHCODE;
}
public boolean compare(KeyedElement other) {
return other.getKey() == KEY;
}
public Object getKey() {
return KEY;
}
}