diff options
author | Thomas Watson | 2012-07-31 20:58:23 +0000 |
---|---|---|
committer | Thomas Watson | 2012-08-01 20:56:57 +0000 |
commit | 66c6af17ae5302064ecd7489eaf29fa1532fab90 (patch) | |
tree | 9e17c46ae9185029927684855d966ee901798ea0 | |
parent | 6a3e9c363c1b9c9a3623207fabb0fff01d042881 (diff) | |
download | rt.equinox.framework-66c6af17ae5302064ecd7489eaf29fa1532fab90.tar.gz rt.equinox.framework-66c6af17ae5302064ecd7489eaf29fa1532fab90.tar.xz rt.equinox.framework-66c6af17ae5302064ecd7489eaf29fa1532fab90.zip |
update signed content impl for new container
10 files changed, 345 insertions, 548 deletions
diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/BundleInstallListener.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/BundleInstallListener.java deleted file mode 100644 index 47c8066fe..000000000 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/BundleInstallListener.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2007, 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 org.eclipse.osgi.baseadaptor.BaseData; -import org.eclipse.osgi.framework.internal.core.AbstractBundle; -import org.eclipse.osgi.internal.provisional.service.security.AuthorizationEngine; -import org.eclipse.osgi.signedcontent.SignedContent; -import org.osgi.framework.*; - -public class BundleInstallListener implements SynchronousBundleListener { - - public void bundleChanged(BundleEvent event) { - Bundle bundle = event.getBundle(); - switch (event.getType()) { - case BundleEvent.UPDATED : - // fall through to INSTALLED - case BundleEvent.INSTALLED : - TrustEngineListener listener = TrustEngineListener.getInstance(); - AuthorizationEngine authEngine = listener == null ? null : listener.getAuthorizationEngine(); - if (authEngine != null) { - BaseData baseData = (BaseData) ((AbstractBundle) bundle).getBundleData(); - SignedStorageHook hook = (SignedStorageHook) baseData.getStorageHook(SignedStorageHook.KEY); - SignedContent signedContent = hook != null ? hook.signedContent : null; - authEngine.authorize(signedContent, bundle); - } - break; - default : - break; - } - } -} diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/DigestedInputStream.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/DigestedInputStream.java index 7eac65521..fe68bd3d9 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/DigestedInputStream.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/DigestedInputStream.java @@ -11,14 +11,14 @@ package org.eclipse.osgi.internal.signedcontent; -import org.eclipse.osgi.storage.bundlefile.BundleEntry; -import org.eclipse.osgi.storage.bundlefile.BundleFile; - import java.io.FilterInputStream; import java.io.IOException; import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import org.eclipse.osgi.signedcontent.InvalidContentException; import org.eclipse.osgi.signedcontent.SignerInfo; +import org.eclipse.osgi.storage.bundlefile.BundleEntry; +import org.eclipse.osgi.storage.bundlefile.BundleFile; import org.eclipse.osgi.util.NLS; /** @@ -42,15 +42,16 @@ class DigestedInputStream extends FilterInputStream { * @param signerInfos the signers. * @param results the expected digest. * @throws IOException + * @throws NoSuchAlgorithmException */ - DigestedInputStream(BundleEntry entry, BundleFile bundleFile, SignerInfo[] signerInfos, byte results[][], long size) throws IOException { + DigestedInputStream(BundleEntry entry, BundleFile bundleFile, SignerInfo[] signerInfos, byte results[][], long size) throws IOException, NoSuchAlgorithmException { super(entry.getInputStream()); this.entry = entry; this.bundleFile = bundleFile; this.remaining = size; this.digests = new MessageDigest[signerInfos.length]; for (int i = 0; i < signerInfos.length; i++) - this.digests[i] = SignatureBlockProcessor.getMessageDigest(signerInfos[i].getMessageDigestAlgorithm()); + this.digests[i] = MessageDigest.getInstance(signerInfos[i].getMessageDigestAlgorithm()); this.result = results; } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/PKCS7Processor.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/PKCS7Processor.java index a1267a8e1..7650083bd 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/PKCS7Processor.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/PKCS7Processor.java @@ -16,7 +16,6 @@ import java.security.cert.Certificate; import java.text.*; import java.util.*; import javax.security.auth.x500.X500Principal; -import org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.util.NLS; /** @@ -30,7 +29,8 @@ public class PKCS7Processor implements SignedContentConstants { try { certFact = CertificateFactory.getInstance("X.509"); //$NON-NLS-1$ } catch (CertificateException e) { - SignedBundleHook.log(e.getMessage(), FrameworkLogEntry.ERROR, e); + // TODO this is bad and will lead to NPEs + // Should we just throw a runtime exception to fail <clinit>? } } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java index 1b3e0b5c4..dc20915ba 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignatureBlockProcessor.java @@ -8,9 +8,6 @@ ******************************************************************************/ package org.eclipse.osgi.internal.signedcontent; -import org.eclipse.osgi.storage.bundlefile.BundleEntry; -import org.eclipse.osgi.storage.bundlefile.BundleFile; - import java.io.IOException; import java.io.InputStream; import java.security.*; @@ -19,6 +16,8 @@ import java.security.cert.CertificateException; import java.util.*; import org.eclipse.osgi.framework.log.FrameworkLogEntry; import org.eclipse.osgi.signedcontent.SignerInfo; +import org.eclipse.osgi.storage.bundlefile.BundleEntry; +import org.eclipse.osgi.storage.bundlefile.BundleFile; import org.eclipse.osgi.util.NLS; public class SignatureBlockProcessor implements SignedContentConstants { @@ -28,10 +27,12 @@ public class SignatureBlockProcessor implements SignedContentConstants { // map of tsa singers keyed by SignerInfo -> {tsa_SignerInfo, signingTime} private Map<SignerInfo, Object[]> tsaSignerInfos; private final int supportFlags; + private final SignedBundleHook signedBundleHook; - public SignatureBlockProcessor(SignedBundleFile signedContent, int supportFlags) { + public SignatureBlockProcessor(SignedBundleFile signedContent, int supportFlags, SignedBundleHook signedBundleHook) { this.signedBundle = signedContent; this.supportFlags = supportFlags; + this.signedBundleHook = signedBundleHook; } public SignedContentImpl process() throws IOException, InvalidKeyException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException { @@ -155,7 +156,7 @@ public class SignatureBlockProcessor implements SignedContentConstants { // check if the the computed digest value of manifest file equals to the digest value in the .sf file if (!digestValue.equals(manifestDigest)) { SignatureException se = new SignatureException(NLS.bind(SignedContentMessages.Security_File_Is_Tampered, new String[] {signedBundle.getBaseFile().toString()})); - SignedBundleHook.log(se.getMessage(), FrameworkLogEntry.ERROR, se); + signedBundleHook.log(se.getMessage(), FrameworkLogEntry.ERROR, se); throw se; } } @@ -309,11 +310,11 @@ public class SignatureBlockProcessor implements SignedContentConstants { return new String(Base64.encode(digest.digest(bytes))); } - static synchronized MessageDigest getMessageDigest(String algorithm) { + synchronized MessageDigest getMessageDigest(String algorithm) { try { return MessageDigest.getInstance(algorithm); } catch (NoSuchAlgorithmException e) { - SignedBundleHook.log(e.getMessage(), FrameworkLogEntry.ERROR, e); + signedBundleHook.log(e.getMessage(), FrameworkLogEntry.ERROR, e); } return null; } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java index a6ead3f06..010ce5b3c 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleFile.java @@ -11,19 +11,15 @@ package org.eclipse.osgi.internal.signedcontent; -import org.eclipse.osgi.storage.bundlefile.BundleEntry; -import org.eclipse.osgi.storage.bundlefile.BundleFile; - import java.io.*; import java.net.URL; import java.security.*; import java.security.cert.*; -import java.security.cert.Certificate; import java.util.Date; import java.util.Enumeration; -import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.service.security.TrustEngine; import org.eclipse.osgi.signedcontent.*; +import org.eclipse.osgi.storage.bundlefile.BundleEntry; +import org.eclipse.osgi.storage.bundlefile.BundleFile; import org.eclipse.osgi.util.NLS; /** @@ -35,60 +31,23 @@ public class SignedBundleFile extends BundleFile implements SignedContentConstan private BundleFile wrappedBundleFile; SignedContentImpl signedContent; private final int supportFlags; + private final SignedBundleHook signedBundleHook; - SignedBundleFile(SignedContentImpl signedContent, int supportFlags) { + SignedBundleFile(SignedContentImpl signedContent, int supportFlags, SignedBundleHook signedBundleHook) { + super(null); this.signedContent = signedContent; this.supportFlags = supportFlags; + this.signedBundleHook = signedBundleHook; } void setBundleFile(BundleFile bundleFile) throws IOException, InvalidKeyException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException { wrappedBundleFile = bundleFile; if (signedContent == null) { - SignatureBlockProcessor signatureProcessor = new SignatureBlockProcessor(this, supportFlags); + SignatureBlockProcessor signatureProcessor = new SignatureBlockProcessor(this, supportFlags, signedBundleHook); signedContent = signatureProcessor.process(); if (signedContent != null) - determineTrust(signedContent, supportFlags); - } - } - - static void determineTrust(SignedContentImpl trustedContent, int supportFlags) { - TrustEngine[] engines = null; - SignerInfo[] signers = trustedContent.getSignerInfos(); - for (int i = 0; i < signers.length; i++) { - // first check if we need to find an anchor - if (signers[i].getTrustAnchor() == null) { - // no anchor set ask the trust engines - if (engines == null) - engines = SignedBundleHook.getTrustEngines(); - // check trust of singer certs - Certificate[] signerCerts = signers[i].getCertificateChain(); - ((SignerInfoImpl) signers[i]).setTrustAnchor(findTrustAnchor(signerCerts, engines, supportFlags)); - // if signer has a tsa check trust of tsa certs - SignerInfo tsaSignerInfo = trustedContent.getTSASignerInfo(signers[i]); - if (tsaSignerInfo != null) { - Certificate[] tsaCerts = tsaSignerInfo.getCertificateChain(); - ((SignerInfoImpl) tsaSignerInfo).setTrustAnchor(findTrustAnchor(tsaCerts, engines, supportFlags)); - } - } - } - } - - private static Certificate findTrustAnchor(Certificate[] certs, TrustEngine[] engines, int supportFlags) { - if ((supportFlags & SignedBundleHook.VERIFY_TRUST) == 0) - // we are not searching the engines; in this case we just assume the root cert is trusted - return certs != null && certs.length > 0 ? certs[certs.length - 1] : null; - for (int i = 0; i < engines.length; i++) { - try { - Certificate anchor = engines[i].findTrustAnchor(certs); - if (anchor != null) - // found an anchor - return anchor; - } catch (IOException e) { - // log the exception and continue - SignedBundleHook.log("TrustEngine failure: " + engines[i].getName(), FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ - } + signedBundleHook.determineTrust(signedContent, supportFlags); } - return null; } public File getFile(String path, boolean nativeCode) { diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java index c823a609c..66ade8aab 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedBundleHook.java @@ -10,94 +10,90 @@ *******************************************************************************/ package org.eclipse.osgi.internal.signedcontent; -import org.eclipse.osgi.internal.framework.FilterImpl; - import java.io.File; import java.io.IOException; -import java.net.*; +import java.lang.reflect.Field; +import java.net.MalformedURLException; +import java.net.URL; import java.security.*; +import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.util.*; -import org.eclipse.osgi.baseadaptor.*; -import org.eclipse.osgi.baseadaptor.hooks.AdaptorHook; -import org.eclipse.osgi.baseadaptor.hooks.BundleFileWrapperFactoryHook; -import org.eclipse.osgi.framework.adaptor.BundleData; -import org.eclipse.osgi.framework.adaptor.FrameworkAdaptor; -import org.eclipse.osgi.framework.internal.core.*; -import org.eclipse.osgi.framework.log.FrameworkLog; import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.internal.provisional.service.security.AuthorizationEngine; -import org.eclipse.osgi.internal.provisional.verifier.CertificateVerifierFactory; -import org.eclipse.osgi.internal.service.security.DefaultAuthorizationEngine; +import org.eclipse.osgi.internal.framework.*; +import org.eclipse.osgi.internal.hookregistry.*; import org.eclipse.osgi.internal.service.security.KeyStoreTrustEngine; +import org.eclipse.osgi.internal.signedcontent.SignedStorageHook.StorageHookImpl; import org.eclipse.osgi.service.security.TrustEngine; -import org.eclipse.osgi.signedcontent.SignedContent; -import org.eclipse.osgi.signedcontent.SignedContentFactory; +import org.eclipse.osgi.signedcontent.*; +import org.eclipse.osgi.storage.BundleInfo.Generation; import org.eclipse.osgi.storage.bundlefile.*; import org.eclipse.osgi.util.ManifestElement; import org.eclipse.osgi.util.NLS; import org.osgi.framework.*; -import org.osgi.framework.Constants; import org.osgi.util.tracker.ServiceTracker; +import org.osgi.util.tracker.ServiceTrackerCustomizer; /** * Implements signed bundle hook support for the framework */ -public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHook, HookConfigurator, SignedContentFactory { +public class SignedBundleHook implements ActivatorHookFactory, BundleFileWrapperFactoryHook, HookConfigurator, SignedContentFactory { static final int VERIFY_CERTIFICATE = 0x01; static final int VERIFY_TRUST = 0x02; static final int VERIFY_RUNTIME = 0x04; - static final int VERIFY_AUTHORITY = 0x08; - static final int VERIFY_ALL = VERIFY_CERTIFICATE | VERIFY_TRUST | VERIFY_RUNTIME | VERIFY_AUTHORITY; - private static String SUPPORT_CERTIFICATE = "certificate"; //$NON-NLS-1$ - private static String SUPPORT_TRUST = "trust"; //$NON-NLS-1$ - private static String SUPPORT_RUNTIME = "runtime"; //$NON-NLS-1$ - private static String SUPPORT_AUTHORITY = "authority"; //$NON-NLS-1$ - private static String SUPPORT_ALL = "all"; //$NON-NLS-1$ - private static String SUPPORT_TRUE = "true"; //$NON-NLS-1$ + static final int VERIFY_ALL = VERIFY_CERTIFICATE | VERIFY_TRUST | VERIFY_RUNTIME; + private final static String SUPPORT_CERTIFICATE = "certificate"; //$NON-NLS-1$ + private final static String SUPPORT_TRUST = "trust"; //$NON-NLS-1$ + private final static String SUPPORT_RUNTIME = "runtime"; //$NON-NLS-1$ + private final static String SUPPORT_ALL = "all"; //$NON-NLS-1$ + private final static String SUPPORT_TRUE = "true"; //$NON-NLS-1$ //TODO: comes from configuration!; - private static String CACERTS_PATH = System.getProperty("java.home") + File.separatorChar + "lib" + File.separatorChar + "security" + File.separatorChar + "cacerts"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ - private static String CACERTS_TYPE = "JKS"; //$NON-NLS-1$ - private static ServiceTracker<TrustEngine, TrustEngine> trustEngineTracker; - private static BaseAdaptor ADAPTOR; - private static String SIGNED_BUNDLE_SUPPORT = "osgi.support.signature.verify"; //$NON-NLS-1$ - private static String SIGNED_CONTENT_SUPPORT = "osgi.signedcontent.support"; //$NON-NLS-1$ - private static String OSGI_KEYSTORE = "osgi.framework.keystore"; //$NON-NLS-1$ - private static int supportSignedBundles; - private TrustEngineListener trustEngineListener; - private BundleInstallListener installListener; + private final static String CACERTS_PATH = System.getProperty("java.home") + File.separatorChar + "lib" + File.separatorChar + "security" + File.separatorChar + "cacerts"; //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$//$NON-NLS-4$ + private final static String CACERTS_TYPE = "JKS"; //$NON-NLS-1$ + private final static String SIGNED_BUNDLE_SUPPORT = "osgi.support.signature.verify"; //$NON-NLS-1$ + private final static String SIGNED_CONTENT_SUPPORT = "osgi.signedcontent.support"; //$NON-NLS-1$ + private final static String OSGI_KEYSTORE = "osgi.framework.keystore"; //$NON-NLS-1$ + private int supportSignedBundles; + TrustEngineListener trustEngineListener; + private String trustEngineNameProp; private ServiceRegistration<?> signedContentFactoryReg; private ServiceRegistration<?> systemTrustEngineReg; - private ServiceRegistration<?> defaultAuthEngineReg; private List<ServiceRegistration<?>> osgiTrustEngineReg; - private ServiceRegistration<?> legacyFactoryReg; + private ServiceTracker<TrustEngine, TrustEngine> trustEngineTracker; + private BundleContext context; + private EquinoxContainer container; + + @Override + public BundleActivator createActivator() { + return new BundleActivator() { + + @Override + public void start(BundleContext bc) throws Exception { + frameworkStart(bc); + } - public void initialize(BaseAdaptor adaptor) { - SignedBundleHook.ADAPTOR = adaptor; + @Override + public void stop(BundleContext bc) throws Exception { + frameworkStop(bc); + } + }; } - /** - * @throws BundleException - */ - public void frameworkStart(BundleContext context) throws BundleException { - // check if load time authority is enabled - if ((supportSignedBundles & VERIFY_AUTHORITY) != 0) { - // install the default bundle install listener - installListener = new BundleInstallListener(); - context.addBundleListener(installListener); - // register the default authorization engine - Dictionary<String, Object> properties = new Hashtable<String, Object>(7); - properties.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE)); - properties.put(SignedContentConstants.AUTHORIZATION_ENGINE, SignedContentConstants.DEFAULT_AUTHORIZATION_ENGINE); - defaultAuthEngineReg = context.registerService(AuthorizationEngine.class.getName(), new DefaultAuthorizationEngine(context, ADAPTOR.getState()), properties); - } + BundleContext getContext() { + return context; + } + void frameworkStart(BundleContext bc) { + this.context = bc; + if ((supportSignedBundles & VERIFY_TRUST) != 0) + // initialize the trust engine listener only if trust is being established with a trust engine + trustEngineListener = new TrustEngineListener(context, this); // always register the trust engine Dictionary<String, Object> trustEngineProps = new Hashtable<String, Object>(7); trustEngineProps.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE)); trustEngineProps.put(SignedContentConstants.TRUST_ENGINE, SignedContentConstants.DEFAULT_TRUST_ENGINE); - KeyStoreTrustEngine systemTrustEngine = new KeyStoreTrustEngine(CACERTS_PATH, CACERTS_TYPE, null, "System"); //$NON-NLS-1$ + KeyStoreTrustEngine systemTrustEngine = new KeyStoreTrustEngine(CACERTS_PATH, CACERTS_TYPE, null, "System", this); //$NON-NLS-1$ systemTrustEngineReg = context.registerService(TrustEngine.class.getName(), systemTrustEngine, trustEngineProps); String osgiTrustPath = context.getProperty(OSGI_KEYSTORE); if (osgiTrustPath != null) { @@ -107,10 +103,10 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo trustEngineProps.put(SignedContentConstants.TRUST_ENGINE, OSGI_KEYSTORE); String path = url.getPath(); osgiTrustEngineReg = new ArrayList<ServiceRegistration<?>>(1); - osgiTrustEngineReg.add(context.registerService(TrustEngine.class.getName(), new KeyStoreTrustEngine(path, CACERTS_TYPE, null, OSGI_KEYSTORE), trustEngineProps)); + osgiTrustEngineReg.add(context.registerService(TrustEngine.class.getName(), new KeyStoreTrustEngine(path, CACERTS_TYPE, null, OSGI_KEYSTORE, this), trustEngineProps)); } } catch (MalformedURLException e) { - SignedBundleHook.log("Invalid setting for " + OSGI_KEYSTORE, FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ + log("Invalid setting for " + OSGI_KEYSTORE, FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ } } else { String osgiTrustRepoPaths = context.getProperty(Constants.FRAMEWORK_TRUST_REPOSITORIES); @@ -120,26 +116,15 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo osgiTrustEngineReg = new ArrayList<ServiceRegistration<?>>(1); while (st.hasMoreTokens()) { String trustRepoPath = st.nextToken(); - osgiTrustEngineReg.add(context.registerService(TrustEngine.class.getName(), new KeyStoreTrustEngine(trustRepoPath, CACERTS_TYPE, null, OSGI_KEYSTORE), trustEngineProps)); + osgiTrustEngineReg.add(context.registerService(TrustEngine.class.getName(), new KeyStoreTrustEngine(trustRepoPath, CACERTS_TYPE, null, OSGI_KEYSTORE, this), trustEngineProps)); } } } - if ((supportSignedBundles & VERIFY_TRUST) != 0) - // initialize the trust engine listener only if trust is being established with a trust engine - trustEngineListener = new TrustEngineListener(context); // always register the signed content factory signedContentFactoryReg = context.registerService(SignedContentFactory.class.getName(), this, null); - legacyFactoryReg = context.registerService(CertificateVerifierFactory.class.getName(), new LegacyVerifierFactory(this), null); } - /** - * @throws BundleException - */ - public void frameworkStop(BundleContext context) throws BundleException { - if (legacyFactoryReg != null) { - legacyFactoryReg.unregister(); - legacyFactoryReg = null; - } + void frameworkStop(BundleContext bc) { if (signedContentFactoryReg != null) { signedContentFactoryReg.unregister(); signedContentFactoryReg = null; @@ -153,61 +138,26 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo it.next().unregister(); osgiTrustEngineReg = null; } - if (defaultAuthEngineReg != null) { - defaultAuthEngineReg.unregister(); - defaultAuthEngineReg = null; - } - if (trustEngineListener != null) { - trustEngineListener.stopTrustEngineListener(); - trustEngineListener = null; - } - if (installListener != null) { - context.removeBundleListener(installListener); - installListener = null; - } if (trustEngineTracker != null) { trustEngineTracker.close(); trustEngineTracker = null; } } - public void frameworkStopping(BundleContext context) { - // do nothing - } - - public void addProperties(Properties properties) { - // do nothing - } - - /** - * @throws IOException - */ - public URLConnection mapLocationToURLConnection(String location) throws IOException { - return null; - } - - public void handleRuntimeError(Throwable error) { - // do nothing - } - - public FrameworkLog createFrameworkLog() { - return null; - } - - public BundleFile wrapBundleFile(BundleFile bundleFile, Object content, BaseData data, boolean base) { + public BundleFile wrapBundleFile(BundleFile bundleFile, Generation generation, boolean base) { try { if (bundleFile != null) { - SignedStorageHook hook = (SignedStorageHook) data.getStorageHook(SignedStorageHook.KEY); + StorageHookImpl hook = generation.getStorageHook(SignedStorageHook.class); SignedBundleFile signedBaseFile; if (base && hook != null) { - signedBaseFile = new SignedBundleFile(hook.signedContent, supportSignedBundles); + signedBaseFile = new SignedBundleFile(hook.signedContent, supportSignedBundles, this); if (hook.signedContent == null) { signedBaseFile.setBundleFile(bundleFile); SignedContentImpl signedContent = signedBaseFile.getSignedContent(); hook.signedContent = signedContent != null && signedContent.isSigned() ? signedContent : null; } } else - signedBaseFile = new SignedBundleFile(null, supportSignedBundles); + signedBaseFile = new SignedBundleFile(null, supportSignedBundles, this); signedBaseFile.setBundleFile(bundleFile); SignedContentImpl signedContent = signedBaseFile.getSignedContent(); if (signedContent != null && signedContent.isSigned()) { @@ -217,16 +167,17 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo } } } catch (IOException e) { - SignedBundleHook.log("Bad bundle file: " + bundleFile.getBaseFile(), FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ + log("Bad bundle file: " + bundleFile.getBaseFile(), FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ } catch (GeneralSecurityException e) { - SignedBundleHook.log("Bad bundle file: " + bundleFile.getBaseFile(), FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ + log("Bad bundle file: " + bundleFile.getBaseFile(), FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ } return bundleFile; } public void addHooks(HookRegistry hookRegistry) { - hookRegistry.addAdaptorHook(this); - String[] support = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(SIGNED_CONTENT_SUPPORT, FrameworkProperties.getProperty(SIGNED_BUNDLE_SUPPORT)), ","); //$NON-NLS-1$ + container = hookRegistry.getContainer(); + hookRegistry.addActivatorHookFactory(this); + String[] support = ManifestElement.getArrayFromList(hookRegistry.getConfiguration().getConfiguration(SIGNED_CONTENT_SUPPORT, hookRegistry.getConfiguration().getConfiguration(SIGNED_BUNDLE_SUPPORT)), ","); //$NON-NLS-1$ for (int i = 0; i < support.length; i++) { if (SUPPORT_CERTIFICATE.equals(support[i])) supportSignedBundles |= VERIFY_CERTIFICATE; @@ -234,13 +185,13 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo supportSignedBundles |= VERIFY_CERTIFICATE | VERIFY_TRUST; else if (SUPPORT_RUNTIME.equals(support[i])) supportSignedBundles |= VERIFY_CERTIFICATE | VERIFY_RUNTIME; - else if (SUPPORT_AUTHORITY.equals(support[i])) - supportSignedBundles |= VERIFY_CERTIFICATE | VERIFY_TRUST | VERIFY_AUTHORITY; else if (SUPPORT_TRUE.equals(support[i]) || SUPPORT_ALL.equals(support[i])) supportSignedBundles |= VERIFY_ALL; } + trustEngineNameProp = hookRegistry.getConfiguration().getConfiguration(SignedContentConstants.TRUST_ENGINE); + if ((supportSignedBundles & VERIFY_CERTIFICATE) != 0) { - hookRegistry.addStorageHook(new SignedStorageHook()); + hookRegistry.addStorageHookFactory(new SignedStorageHook()); hookRegistry.addBundleFileWrapperFactoryHook(this); } } @@ -252,8 +203,8 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo if (content.isDirectory()) contentBundleFile = new DirBundleFile(content); else - contentBundleFile = new ZipBundleFile(content, null); - SignedBundleFile result = new SignedBundleFile(null, VERIFY_ALL); + contentBundleFile = new ZipBundleFile(content, null, null); + SignedBundleFile result = new SignedBundleFile(null, VERIFY_ALL, this); try { result.setBundleFile(contentBundleFile); } catch (InvalidKeyException e) { @@ -271,20 +222,18 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo } public SignedContent getSignedContent(Bundle bundle) throws IOException, InvalidKeyException, SignatureException, CertificateException, NoSuchAlgorithmException, NoSuchProviderException, IllegalArgumentException { - final BundleData data = ((AbstractBundle) bundle).getBundleData(); - if (!(data instanceof BaseData)) - throw new IllegalArgumentException("Invalid bundle object. No BaseData found."); //$NON-NLS-1$ - SignedStorageHook hook = (SignedStorageHook) ((BaseData) data).getStorageHook(SignedStorageHook.KEY); + final Generation generation = (Generation) ((EquinoxBundle) bundle).getModule().getCurrentRevision().getRevisionInfo(); + StorageHookImpl hook = generation.getStorageHook(SignedStorageHook.class); SignedContent result = hook != null ? hook.signedContent : null; if (result != null) return result; // just reuse the signed content the storage hook // must create a new signed content using the raw file if (System.getSecurityManager() == null) - return getSignedContent(((BaseData) data).getBundleFile().getBaseFile()); + return getSignedContent(generation.getBundleFile().getBaseFile()); try { return AccessController.doPrivileged(new PrivilegedExceptionAction<SignedContent>() { public SignedContent run() throws Exception { - return getSignedContent(((BaseData) data).getBundleFile().getBaseFile()); + return getSignedContent(generation.getBundleFile().getBaseFile()); } }); } catch (PrivilegedActionException e) { @@ -304,41 +253,27 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo } } - public static void log(String msg, int severity, Throwable t) { - if (SignedBundleHook.ADAPTOR == null) { - System.err.println(msg); - t.printStackTrace(); - return; - } - FrameworkLogEntry entry = new FrameworkLogEntry(FrameworkAdaptor.FRAMEWORK_SYMBOLICNAME, severity, 0, msg, 0, t, null); - SignedBundleHook.ADAPTOR.getFrameworkLog().log(entry); - } - - static BundleContext getContext() { - if (ADAPTOR == null) - return null; - return ADAPTOR.getContext(); + public void log(String msg, int severity, Throwable t) { + container.getLogServices().log(EquinoxContainer.NAME, severity, msg, t); } - static TrustEngine[] getTrustEngines() { + private TrustEngine[] getTrustEngines() { // find all the trust engines available - BundleContext context = SignedBundleHook.getContext(); if (context == null) return new TrustEngine[0]; if (trustEngineTracker == null) { // read the trust provider security property - String trustEngineProp = FrameworkProperties.getProperty(SignedContentConstants.TRUST_ENGINE); Filter filter = null; - if (trustEngineProp != null) + if (trustEngineNameProp != null) try { - filter = FilterImpl.newInstance("(&(" + Constants.OBJECTCLASS + "=" + TrustEngine.class.getName() + ")(" + SignedContentConstants.TRUST_ENGINE + "=" + trustEngineProp + "))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$ + filter = FilterImpl.newInstance("(&(" + Constants.OBJECTCLASS + "=" + TrustEngine.class.getName() + ")(" + SignedContentConstants.TRUST_ENGINE + "=" + trustEngineNameProp + "))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$ } catch (InvalidSyntaxException e) { - SignedBundleHook.log("Invalid trust engine filter", FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ + log("Invalid trust engine filter", FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ } if (filter != null) { - trustEngineTracker = new ServiceTracker<TrustEngine, TrustEngine>(context, filter, null); + trustEngineTracker = new ServiceTracker<TrustEngine, TrustEngine>(context, filter, new TrustEngineCustomizer()); } else - trustEngineTracker = new ServiceTracker<TrustEngine, TrustEngine>(context, TrustEngine.class.getName(), null); + trustEngineTracker = new ServiceTracker<TrustEngine, TrustEngine>(context, TrustEngine.class.getName(), new TrustEngineCustomizer()); trustEngineTracker.open(); } Object[] services = trustEngineTracker.getServices(); @@ -349,4 +284,74 @@ public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHo } return new TrustEngine[0]; } + + class TrustEngineCustomizer implements ServiceTrackerCustomizer<TrustEngine, TrustEngine> { + + @Override + public TrustEngine addingService(ServiceReference<TrustEngine> reference) { + TrustEngine engine = getContext().getService(reference); + if (engine != null) { + try { + Field trustEngineListenerField = TrustEngine.class.getDeclaredField("trustEngineListener"); //$NON-NLS-1$ + trustEngineListenerField.setAccessible(true); + trustEngineListenerField.set(engine, SignedBundleHook.this.trustEngineListener); + } catch (Exception e) { + log("Unable to set the trust engine listener.", FrameworkLogEntry.ERROR, e); //$NON-NLS-1$ + } + + } + return engine; + } + + @Override + public void modifiedService(ServiceReference<TrustEngine> reference, TrustEngine service) { + // nothing + } + + @Override + public void removedService(ServiceReference<TrustEngine> reference, TrustEngine service) { + // nothing + } + + } + + void determineTrust(SignedContentImpl trustedContent, int supportFlags) { + TrustEngine[] engines = null; + SignerInfo[] signers = trustedContent.getSignerInfos(); + for (int i = 0; i < signers.length; i++) { + // first check if we need to find an anchor + if (signers[i].getTrustAnchor() == null) { + // no anchor set ask the trust engines + if (engines == null) + engines = getTrustEngines(); + // check trust of singer certs + Certificate[] signerCerts = signers[i].getCertificateChain(); + ((SignerInfoImpl) signers[i]).setTrustAnchor(findTrustAnchor(signerCerts, engines, supportFlags)); + // if signer has a tsa check trust of tsa certs + SignerInfo tsaSignerInfo = trustedContent.getTSASignerInfo(signers[i]); + if (tsaSignerInfo != null) { + Certificate[] tsaCerts = tsaSignerInfo.getCertificateChain(); + ((SignerInfoImpl) tsaSignerInfo).setTrustAnchor(findTrustAnchor(tsaCerts, engines, supportFlags)); + } + } + } + } + + private Certificate findTrustAnchor(Certificate[] certs, TrustEngine[] engines, int supportFlags) { + if ((supportFlags & SignedBundleHook.VERIFY_TRUST) == 0) + // we are not searching the engines; in this case we just assume the root cert is trusted + return certs != null && certs.length > 0 ? certs[certs.length - 1] : null; + for (int i = 0; i < engines.length; i++) { + try { + Certificate anchor = engines[i].findTrustAnchor(certs); + if (anchor != null) + // found an anchor + return anchor; + } catch (IOException e) { + // log the exception and continue + log("TrustEngine failure: " + engines[i].getName(), FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ + } + } + return null; + } } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentConstants.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentConstants.java index 115621a91..38302584e 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentConstants.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentConstants.java @@ -59,10 +59,6 @@ public interface SignedContentConstants { public static final String TRUST_ENGINE = "osgi.signedcontent.trust.engine"; //$NON-NLS-1$ public static final Object DEFAULT_TRUST_ENGINE = "org.eclipse.osgi"; //$NON-NLS-1$ - // constants for authorization engine service - public static final String AUTHORIZATION_ENGINE = "osgi.signedcontent.authorization.engine"; //$NON-NLS-1$ - public static final Object DEFAULT_AUTHORIZATION_ENGINE = "org.eclipse.osgi"; //$NON-NLS-1$ - // constant for the timestamp related public static final int TIMESTAMP_OID[] = {1, 2, 840, 113549, 1, 9, 16, 2, 14}; public static final int TIMESTAMP_TST_OID[] = {1, 2, 840, 113549, 1, 9, 16, 1, 4}; diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentImpl.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentImpl.java index e9746df84..64f6a01e3 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentImpl.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/SignedContentImpl.java @@ -8,14 +8,14 @@ ******************************************************************************/ package org.eclipse.osgi.internal.signedcontent; -import org.eclipse.osgi.storage.bundlefile.BundleEntry; -import org.eclipse.osgi.storage.bundlefile.BundleFile; - import java.io.IOException; import java.io.InputStream; +import java.security.NoSuchAlgorithmException; import java.security.cert.*; import java.util.*; import org.eclipse.osgi.signedcontent.*; +import org.eclipse.osgi.storage.bundlefile.BundleEntry; +import org.eclipse.osgi.storage.bundlefile.BundleFile; import org.eclipse.osgi.util.NLS; public class SignedContentImpl implements SignedContent { @@ -126,7 +126,11 @@ public class SignedContentImpl implements SignedContent { Object[] mdResult = (Object[]) contentMDResults.get(nestedEntry.getName()); if (mdResult == null) return null; - return new DigestedInputStream(nestedEntry, content, (SignerInfo[]) mdResult[0], (byte[][]) mdResult[1], nestedEntry.getSize()); + try { + return new DigestedInputStream(nestedEntry, content, (SignerInfo[]) mdResult[0], (byte[][]) mdResult[1], nestedEntry.getSize()); + } catch (NoSuchAlgorithmException e) { + throw new IOException(e); + } } public class SignedContentEntryImpl implements SignedContentEntry { 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 index 2fe55e59c..df5cbbab7 100644 --- 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 @@ -11,233 +11,177 @@ 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.internal.hookregistry.StorageHookFactory; import org.eclipse.osgi.signedcontent.SignedContent; import org.eclipse.osgi.signedcontent.SignerInfo; -import org.osgi.framework.Bundle; +import org.eclipse.osgi.storage.BundleInfo.Generation; 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 class SignedStorageHook extends StorageHookFactory<List<SignerInfo>, List<SignerInfo>, SignedStorageHook.StorageHookImpl> { + private static final int STORAGE_VERSION = 4; public int getStorageVersion() { return STORAGE_VERSION; } - /** - * @throws BundleException - */ - public StorageHook create(BaseData data) throws BundleException { - SignedStorageHook hook = new SignedStorageHook(); - hook.bundledata = data; - return hook; + @Override + public List<SignerInfo> createSaveContext() { + return new ArrayList<SignerInfo>(); } - /** - * @throws BundleException - */ - public void initialize(Dictionary<String, String> manifest) throws BundleException { - // do nothing + @Override + public List<SignerInfo> createLoadContext(int version) { + return new ArrayList<SignerInfo>(); } - 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}); - } + @Override + public StorageHookImpl createStorageHook(Generation generation) { + return new StorageHookImpl(generation); + } + + static class StorageHookImpl extends StorageHookFactory.StorageHook<List<SignerInfo>, List<SignerInfo>> { + SignedContentImpl signedContent; + + public StorageHookImpl(Generation generation) { + super(generation, SignedStorageHook.class); } - 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); + + @SuppressWarnings("unused") + @Override + public void initialize(Dictionary<String, String> manifest) throws BundleException { + // do nothing } - 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]); + @Override + public void load(List<SignerInfo> loadContext, DataInputStream is) throws IOException { + boolean signed = is.readBoolean(); + if (!signed) + return; + int numSigners = is.readInt(); + SignerInfo[] signerInfos = new SignerInfo[numSigners]; + for (int i = 0; i < numSigners; i++) + signerInfos[i] = readSignerInfo(is, loadContext); + + 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, loadContext); + int resultSize = is.readInt(); + entryResults[j] = new byte[resultSize]; + is.readFully(entryResults[j]); + } + contentMDResults.put(path, new Object[] {entrySigners, entryResults}); } } - - 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); + SignedContentImpl result = new SignedContentImpl(signerInfos, contentMDResults); + for (int i = 0; i < numSigners; i++) { + boolean hasTSA = is.readBoolean(); + if (!hasTSA) + continue; + SignerInfo tsaSigner = readSignerInfo(is, loadContext); + Date signingDate = new Date(is.readLong()); + result.addTSASignerInfo(signerInfos[i], tsaSigner, signingDate); + } + signedContent = result; } - } - 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; + private SignerInfo readSignerInfo(DataInputStream is, List<SignerInfo> loadContext) throws IOException { + int index = is.readInt(); + if (index >= 0) + return loadContext.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 { - certBytes = certs[i].getEncoded(); - } catch (CertificateEncodingException e) { + certs[i] = PKCS7Processor.certFact.generateCertificate(new ByteArrayInputStream(certBytes)); + } catch (CertificateException 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); - } + int anchorIdx = is.readInt(); + SignerInfoImpl result = new SignerInfoImpl(certs, anchorIdx >= 0 ? certs[anchorIdx] : null, is.readUTF()); + loadContext.add(result); + return result; + } - 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); + @Override + public void save(List<SignerInfo> saveContext, DataOutputStream os) throws IOException { + 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, saveContext); + + // 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, saveContext); + 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, saveContext); + Date signingTime = signedContent.getSigningTime(signerInfos[i]); + os.writeLong(signingTime != null ? signingTime.getTime() : Long.MIN_VALUE); } } - 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(); + private void saveSignerInfo(SignerInfo signerInfo, DataOutputStream os, List<SignerInfo> saveContext) throws IOException { + int cacheIdx = saveContext.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()); + saveContext.add(signerInfo); } - } - 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; + public SignedContent getSignedContent() { + return signedContent; + } } } diff --git a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/TrustEngineListener.java b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/TrustEngineListener.java index ba10d0f5a..f5746e133 100644 --- a/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/TrustEngineListener.java +++ b/bundles/org.eclipse.osgi/container/src/org/eclipse/osgi/internal/signedcontent/TrustEngineListener.java @@ -8,110 +8,45 @@ ******************************************************************************/ package org.eclipse.osgi.internal.signedcontent; -import org.eclipse.osgi.internal.framework.FilterImpl; - import java.security.cert.Certificate; import java.util.*; -import org.eclipse.osgi.baseadaptor.BaseData; -import org.eclipse.osgi.framework.internal.core.*; -import org.eclipse.osgi.framework.log.FrameworkLogEntry; -import org.eclipse.osgi.internal.provisional.service.security.AuthorizationEngine; +import org.eclipse.osgi.internal.framework.EquinoxBundle; +import org.eclipse.osgi.internal.signedcontent.SignedStorageHook.StorageHookImpl; import org.eclipse.osgi.signedcontent.SignerInfo; -import org.osgi.framework.*; -import org.osgi.framework.Constants; -import org.osgi.service.packageadmin.PackageAdmin; -import org.osgi.util.tracker.ServiceTracker; +import org.eclipse.osgi.storage.BundleInfo.Generation; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; public class TrustEngineListener { - // this is a singleton listener; see SignedBundleHook for initialization - private volatile static TrustEngineListener instance; private final BundleContext context; - private final ServiceTracker<AuthorizationEngine, AuthorizationEngine> authorizationTracker; + private final SignedBundleHook signedBundleHook; - TrustEngineListener(BundleContext context) { + TrustEngineListener(BundleContext context, SignedBundleHook signedBundleHook) { this.context = context; - // read the trust provider security property - String authEngineProp = FrameworkProperties.getProperty(SignedContentConstants.AUTHORIZATION_ENGINE); - Filter filter = null; - if (authEngineProp != null) - try { - filter = FilterImpl.newInstance("(&(" + Constants.OBJECTCLASS + "=" + AuthorizationEngine.class.getName() + ")(" + SignedContentConstants.AUTHORIZATION_ENGINE + "=" + authEngineProp + "))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$ - } catch (InvalidSyntaxException e) { - SignedBundleHook.log("Invalid authorization filter", FrameworkLogEntry.WARNING, e); //$NON-NLS-1$ - } - if (filter != null) - authorizationTracker = new ServiceTracker<AuthorizationEngine, AuthorizationEngine>(context, filter, null); - else - authorizationTracker = new ServiceTracker<AuthorizationEngine, AuthorizationEngine>(context, AuthorizationEngine.class.getName(), null); - authorizationTracker.open(); - instance = this; - } - - public static TrustEngineListener getInstance() { - return instance; - } - - void stopTrustEngineListener() { - authorizationTracker.close(); - instance = null; + this.signedBundleHook = signedBundleHook; } public void addedTrustAnchor(Certificate anchor) { // find any SignedContent with SignerInfos that do not have an anchor; // re-evaluate trust and check authorization for these SignedContents Bundle[] bundles = context.getBundles(); - Set<Bundle> unresolved = new HashSet<Bundle>(); for (int i = 0; i < bundles.length; i++) { SignedContentImpl signedContent = getSignedContent(bundles[i]); if (signedContent != null && signedContent.isSigned()) { // check the SignerInfos for this content SignerInfo[] infos = signedContent.getSignerInfos(); for (int j = 0; j < infos.length; j++) { - if (infos[j].getTrustAnchor() == null) + if (infos[j].getTrustAnchor() == null) { // one of the signers is not trusted - unresolved.add(bundles[i]); - SignerInfo tsa = signedContent.getTSASignerInfo(infos[j]); - if (tsa != null && tsa.getTrustAnchor() == null) - // one of the tsa signers is not trusted - unresolved.add(bundles[i]); + signedBundleHook.determineTrust(signedContent, SignedBundleHook.VERIFY_TRUST); + } else { + SignerInfo tsa = signedContent.getTSASignerInfo(infos[j]); + if (tsa != null && tsa.getTrustAnchor() == null) + // one of the tsa signers is not trusted + signedBundleHook.determineTrust(signedContent, SignedBundleHook.VERIFY_TRUST); + } } } - if (unresolved.contains(bundles[i])) { - // found an untrusted signer for this bundle re-evaluate trust - SignedBundleFile.determineTrust(signedContent, SignedBundleHook.VERIFY_TRUST); - // now check the authorization handler - checkAuthorization(signedContent, bundles[i]); - } - } - // try to resolve - if (unresolved.size() > 0) - resolveBundles(unresolved.toArray(new Bundle[unresolved.size()]), false); - } - - private void checkAuthorization(SignedContentImpl signedContent, Bundle bundle) { - AuthorizationEngine authEngine = getAuthorizationEngine(); - if (authEngine != null) - authEngine.authorize(signedContent, bundle); - } - - AuthorizationEngine getAuthorizationEngine() { - return authorizationTracker.getService(); - } - - private void resolveBundles(Bundle[] bundles, boolean refresh) { - ServiceReference<?> ref = context.getServiceReference(PackageAdmin.class.getName()); - if (ref == null) - return; - PackageAdmin pa = (PackageAdmin) context.getService(ref); - if (pa == null) - return; - try { - if (refresh) - pa.refreshPackages(bundles); - else - pa.resolveBundles(bundles); - } finally { - context.ungetService(ref); } } @@ -144,26 +79,18 @@ public class TrustEngineListener { // remove trust anchors from untrusted signers for (Iterator<SignerInfo> untrusted = untrustedSigners.iterator(); untrusted.hasNext();) ((SignerInfoImpl) untrusted.next()).setTrustAnchor(null); - // re-establish trust and check authorization + // re-establish trust for (Iterator<Bundle> untrustedBundles = usingAnchor.iterator(); untrustedBundles.hasNext();) { Bundle bundle = untrustedBundles.next(); SignedContentImpl signedContent = getSignedContent(bundle); // found an signer using the anchor for this bundle re-evaluate trust - SignedBundleFile.determineTrust(signedContent, SignedBundleHook.VERIFY_TRUST); - // now check the authorization handler - checkAuthorization(signedContent, bundle); + signedBundleHook.determineTrust(signedContent, SignedBundleHook.VERIFY_TRUST); } - // TODO an optimization here would be to check for real DisabledInfo objects for each bundle - // try to refresh - if (usingAnchor.size() > 0) - resolveBundles(usingAnchor.toArray(new Bundle[usingAnchor.size()]), true); } private SignedContentImpl getSignedContent(Bundle bundle) { - BaseData data = (BaseData) ((AbstractBundle) bundle).getBundleData(); - SignedStorageHook hook = (SignedStorageHook) data.getStorageHook(SignedStorageHook.KEY); - if (hook == null) - return null; - return (SignedContentImpl) hook.getSignedContent(); + Generation generation = (Generation) ((EquinoxBundle) bundle).getModule().getCurrentRevision().getRevisionInfo(); + StorageHookImpl hook = generation.getStorageHook(SignedStorageHook.class); + return hook != null ? hook.signedContent : null; } } |