diff options
Diffstat (limited to 'bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedStorageHook.java')
-rw-r--r-- | bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedStorageHook.java | 243 |
1 files changed, 243 insertions, 0 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedStorageHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedStorageHook.java new file mode 100644 index 000000000..2fe55e59c --- /dev/null +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedStorageHook.java @@ -0,0 +1,243 @@ +/******************************************************************************* + * Copyright (c) 2006, 2010 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.signedcontent; + +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.signedcontent.SignedContent; +import org.eclipse.osgi.signedcontent.SignerInfo; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleException; + +public class SignedStorageHook implements StorageHook { + public static final String KEY = SignedStorageHook.class.getName(); + public static final int HASHCODE = KEY.hashCode(); + private static final int STORAGE_VERSION = 3; + private static List<SignerInfo> savedSignerInfo = new ArrayList<SignerInfo>(5); + private static long firstIDSaved = -1; + private static long lastIDSaved = -1; + private static List<SignerInfo> loadedSignerInfo = new ArrayList<SignerInfo>(5); + private static long lastIDLoaded; + + private BaseData bundledata; + SignedContentImpl signedContent; + + public int getStorageVersion() { + return STORAGE_VERSION; + } + + /** + * @throws BundleException + */ + public StorageHook create(BaseData data) throws BundleException { + SignedStorageHook hook = new SignedStorageHook(); + hook.bundledata = data; + return hook; + } + + /** + * @throws BundleException + */ + public void initialize(Dictionary<String, String> manifest) throws BundleException { + // do nothing + } + + public StorageHook load(BaseData target, DataInputStream is) throws IOException { + if (lastIDLoaded > target.getBundleID()) + loadedSignerInfo.clear(); + lastIDLoaded = target.getBundleID(); + SignedStorageHook hook = new SignedStorageHook(); + hook.bundledata = target; + boolean signed = is.readBoolean(); + if (!signed) + return hook; + int numSigners = is.readInt(); + SignerInfo[] signerInfos = new SignerInfo[numSigners]; + for (int i = 0; i < numSigners; i++) + signerInfos[i] = readSignerInfo(is); + + int resultsSize = is.readInt(); + Map<String, Object> contentMDResults = null; + if (resultsSize > 0) { + contentMDResults = new HashMap<String, Object>(resultsSize); + for (int i = 0; i < resultsSize; i++) { + String path = is.readUTF(); + int numEntrySigners = is.readInt(); + SignerInfo[] entrySigners = new SignerInfo[numEntrySigners]; + byte[][] entryResults = new byte[numEntrySigners][]; + for (int j = 0; j < numEntrySigners; j++) { + entrySigners[j] = readSignerInfo(is); + int resultSize = is.readInt(); + entryResults[j] = new byte[resultSize]; + is.readFully(entryResults[j]); + } + contentMDResults.put(path, new Object[] {entrySigners, entryResults}); + } + } + SignedContentImpl result = new SignedContentImpl(signerInfos, contentMDResults); + for (int i = 0; i < numSigners; i++) { + boolean hasTSA = is.readBoolean(); + if (!hasTSA) + continue; + SignerInfo tsaSigner = readSignerInfo(is); + Date signingDate = new Date(is.readLong()); + result.addTSASignerInfo(signerInfos[i], tsaSigner, signingDate); + } + hook.signedContent = result; + return hook; + } + + public void save(DataOutputStream os) throws IOException { + getFirstLastID(); + if (firstIDSaved == bundledata.getBundleID()) + savedSignerInfo.clear(); + if (lastIDSaved == bundledata.getBundleID()) + firstIDSaved = lastIDSaved = -1; + os.writeBoolean(signedContent != null); + if (signedContent == null) + return; + SignerInfo[] signerInfos = signedContent.getSignerInfos(); + os.writeInt(signerInfos.length); + for (int i = 0; i < signerInfos.length; i++) + saveSignerInfo(signerInfos[i], os); + + // keyed by entry path -> {SignerInfo[] infos, byte[][] results)} + Map<String, Object> contentMDResults = signedContent.getContentMDResults(); + os.writeInt(contentMDResults == null ? -1 : contentMDResults.size()); + if (contentMDResults != null) + for (Map.Entry<String, Object> entry : contentMDResults.entrySet()) { + String path = entry.getKey(); + os.writeUTF(path); + Object[] signerResults = (Object[]) entry.getValue(); + SignerInfo[] entrySigners = (SignerInfo[]) signerResults[0]; + byte[][] entryResults = (byte[][]) signerResults[1]; + os.writeInt(entrySigners.length); + for (int i = 0; i < entrySigners.length; i++) { + saveSignerInfo(entrySigners[i], os); + os.writeInt(entryResults[i].length); + os.write(entryResults[i]); + } + } + + for (int i = 0; i < signerInfos.length; i++) { + SignerInfo tsaInfo = signedContent.getTSASignerInfo(signerInfos[i]); + os.writeBoolean(tsaInfo != null); + if (tsaInfo == null) + continue; + saveSignerInfo(tsaInfo, os); + Date signingTime = signedContent.getSigningTime(signerInfos[i]); + os.writeLong(signingTime != null ? signingTime.getTime() : Long.MIN_VALUE); + } + } + + private void saveSignerInfo(SignerInfo signerInfo, DataOutputStream os) throws IOException { + int cacheIdx = savedSignerInfo.indexOf(signerInfo); + os.writeInt(cacheIdx); + if (cacheIdx >= 0) + return; + Certificate[] certs = signerInfo.getCertificateChain(); + int anchorIndex = -1; + os.writeInt(certs == null ? 0 : certs.length); + if (certs != null) + for (int i = 0; i < certs.length; i++) { + if (certs[i].equals(signerInfo.getTrustAnchor())) + anchorIndex = i; + byte[] certBytes; + try { + certBytes = certs[i].getEncoded(); + } catch (CertificateEncodingException e) { + throw (IOException) new IOException(e.getMessage()).initCause(e); + } + os.writeInt(certBytes.length); + os.write(certBytes); + } + os.writeInt(anchorIndex); + os.writeUTF(signerInfo.getMessageDigestAlgorithm()); + savedSignerInfo.add(signerInfo); + } + + private SignerInfo readSignerInfo(DataInputStream is) throws IOException { + int index = is.readInt(); + if (index >= 0) + return loadedSignerInfo.get(index); + int numCerts = is.readInt(); + Certificate[] certs = new Certificate[numCerts]; + for (int i = 0; i < numCerts; i++) { + int certSize = is.readInt(); + byte[] certBytes = new byte[certSize]; + is.readFully(certBytes); + try { + certs[i] = PKCS7Processor.certFact.generateCertificate(new ByteArrayInputStream(certBytes)); + } catch (CertificateException e) { + throw (IOException) new IOException(e.getMessage()).initCause(e); + } + } + int anchorIdx = is.readInt(); + SignerInfoImpl result = new SignerInfoImpl(certs, anchorIdx >= 0 ? certs[anchorIdx] : null, is.readUTF()); + loadedSignerInfo.add(result); + return result; + } + + 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 + } + + /** + * @throws BundleException + */ + public Dictionary<String, String> 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 int getKeyHashCode() { + return HASHCODE; + } + + public boolean compare(KeyedElement other) { + return other.getKey() == KEY; + } + + public Object getKey() { + return KEY; + } + + public SignedContent getSignedContent() { + return signedContent; + } + +} |