| /******************************************************************************* |
| * Copyright (c) 2006, 2008 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 java.util.Map.Entry; |
| 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 ArrayList savedSignerInfo = new ArrayList(5); |
| private static long firstIDSaved = -1; |
| private static long lastIDSaved = -1; |
| private static ArrayList loadedSignerInfo = new ArrayList(5); |
| private static long lastIDLoaded; |
| |
| private BaseData bundledata; |
| SignedContentImpl signedContent; |
| |
| 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()) |
| 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(); |
| HashMap contentMDResults = null; |
| if (resultsSize > 0) { |
| contentMDResults = new HashMap(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)} |
| HashMap contentMDResults = signedContent.getContentMDResults(); |
| os.writeInt(contentMDResults == null ? -1 : contentMDResults.size()); |
| if (contentMDResults != null) |
| for (Iterator iResults = contentMDResults.entrySet().iterator(); iResults.hasNext();) { |
| Entry entry = (Entry) iResults.next(); |
| String path = (String) 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 new IOException(e.getMessage()); |
| } |
| 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 (SignerInfo) 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 new IOException(e.getMessage()); |
| } |
| } |
| 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 |
| } |
| |
| 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 int getKeyHashCode() { |
| return HASHCODE; |
| } |
| |
| public boolean compare(KeyedElement other) { |
| return other.getKey() == KEY; |
| } |
| |
| public Object getKey() { |
| return KEY; |
| } |
| |
| public SignedContent getSignedContent() { |
| return signedContent; |
| } |
| |
| } |