blob: d7ed6f349871087b1bbf7b43d92f7069bc452ebe [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006 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.File;
import java.io.IOException;
import java.net.URLConnection;
import java.security.Security;
import java.util.Hashtable;
import java.util.Properties;
import org.eclipse.osgi.baseadaptor.*;
import org.eclipse.osgi.baseadaptor.bundlefile.*;
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.AbstractBundle;
import org.eclipse.osgi.framework.internal.core.FrameworkProperties;
import org.eclipse.osgi.framework.log.FrameworkLog;
import org.eclipse.osgi.framework.log.FrameworkLogEntry;
import org.eclipse.osgi.internal.provisional.verifier.*;
import org.eclipse.osgi.util.ManifestElement;
import org.osgi.framework.*;
import org.osgi.util.tracker.ServiceTracker;
/**
* Implements signed bundle hook support for the framework
*/
public class SignedBundleHook implements AdaptorHook, BundleFileWrapperFactoryHook, HookConfigurator, CertificateVerifierFactory {
static final int VERIFY_CERTIFICATE = 0x01;
static final int VERIFY_TRUST = 0x02;
static final int VERIFY_RUNTIME = 0x04;
static final int VERIFY_ALL = VERIFY_CERTIFICATE | VERIFY_TRUST | VERIFY_RUNTIME;
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_ALL = "all"; //$NON-NLS-1$
private static String SUPPORT_TRUE = "true"; //$NON-NLS-1$
private static ServiceTracker trustAuthorityTracker;
private static BaseAdaptor ADAPTOR;
private static String SIGNED_BUNDLE_SUPPORT = "osgi.support.signature.verify"; //$NON-NLS-1$
private static int supportSignedBundles;
private ServiceRegistration certVerifierReg;
private ServiceRegistration trustAuthorityReg;
private CertificateTrustAuthority trustAuthority = new DefaultTrustAuthority(VERIFY_ALL);
public boolean matchDNChain(String pattern, String dnChain[]) {
boolean satisfied = false;
if (dnChain != null) {
for (int i = 0; i < dnChain.length; i++)
if (DNChainMatching.match(dnChain[i], pattern)) {
satisfied = true;
break;
}
}
return satisfied;
}
public void initialize(BaseAdaptor adaptor) {
SignedBundleHook.ADAPTOR = adaptor;
}
public void frameworkStart(BundleContext context) throws BundleException {
certVerifierReg = context.registerService(CertificateVerifierFactory.class.getName(), this, null);
Hashtable properties = new Hashtable(7);
properties.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE));
properties.put(JarVerifierConstant.TRUST_AUTHORITY, JarVerifierConstant.DEFAULT_TRUST_AUTHORITY);
trustAuthorityReg = context.registerService(CertificateTrustAuthority.class.getName(), trustAuthority, properties);
}
public void frameworkStop(BundleContext context) throws BundleException {
if (certVerifierReg != null) {
certVerifierReg.unregister();
certVerifierReg = null;
}
if (trustAuthorityReg != null) {
trustAuthorityReg.unregister();
trustAuthorityReg = null;
}
if (trustAuthorityTracker != null) {
trustAuthorityTracker.close();
trustAuthorityTracker = null;
}
}
public void frameworkStopping(BundleContext context) {
// do nothing
}
public void addProperties(Properties properties) {
// do nothing
}
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) {
try {
if (bundleFile != null) {
SignedStorageHook hook = (SignedStorageHook) data.getStorageHook(SignedStorageHook.KEY);
SignedBundleFile signedBaseFile;
if (base && hook != null && hook.signedBundleFile != null)
signedBaseFile = hook.signedBundleFile;
else
signedBaseFile = new SignedBundleFile();
signedBaseFile.setBundleFile(bundleFile, supportSignedBundles);
if (signedBaseFile.isSigned()) // only use the signed file if there are certs
bundleFile = signedBaseFile;
}
} catch (IOException e) {
// do nothing; its not your responsibility the error will be addressed later
}
return bundleFile;
}
public void addHooks(HookRegistry hookRegistry) {
hookRegistry.addAdaptorHook(this);
String[] support = ManifestElement.getArrayFromList(FrameworkProperties.getProperty(SIGNED_BUNDLE_SUPPORT), ","); //$NON-NLS-1$
for (int i = 0; i < support.length; i++) {
if (SUPPORT_CERTIFICATE.equals(support[i]))
supportSignedBundles |= VERIFY_CERTIFICATE;
else if (SUPPORT_TRUST.equals(support[i]))
supportSignedBundles |= VERIFY_CERTIFICATE | VERIFY_TRUST;
else if (SUPPORT_RUNTIME.equals(support[i]))
supportSignedBundles |= VERIFY_CERTIFICATE | VERIFY_RUNTIME;
else if (SUPPORT_TRUE.equals(support[i]) || SUPPORT_ALL.equals(support[i]))
supportSignedBundles |= VERIFY_ALL;
}
if ((supportSignedBundles & VERIFY_CERTIFICATE) != 0) {
hookRegistry.addStorageHook(new SignedStorageHook());
hookRegistry.addBundleFileWrapperFactoryHook(this);
}
}
public CertificateVerifier getVerifier(File content) throws IOException {
if (content == null)
throw new IllegalArgumentException("null content"); //$NON-NLS-1$
BundleFile contentBundleFile;
if (content.isDirectory())
contentBundleFile = new DirBundleFile(content);
else
contentBundleFile = new ZipBundleFile(content, null);
SignedBundleFile result = new SignedBundleFile();
result.setBundleFile(contentBundleFile, VERIFY_ALL);
return result;
}
public CertificateVerifier getVerifier(Bundle bundle) throws IOException {
BundleData data = ((AbstractBundle) bundle).getBundleData();
if (!(data instanceof BaseData))
throw new IllegalArgumentException("Invalid bundle object. No BaseData found."); //$NON-NLS-1$
BundleFile bundleFile = ((BaseData) data).getBundleFile();
if (bundleFile instanceof SignedBundleFile)
return (SignedBundleFile) bundleFile; // just reuse the verifier from the bundle file
return getVerifier(bundleFile.getBaseFile()); // must create a new verifier using the raw file
}
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();
}
static CertificateTrustAuthority getTrustAuthority() {
// read the certs chain security property and open the service tracker if not null
if (trustAuthorityTracker == null) {
// read the trust provider security property
String trustAuthority = Security.getProperty(JarVerifierConstant.TRUST_AUTHORITY);
Filter filter = null;
if (trustAuthority != null)
try {
filter = FrameworkUtil.createFilter("(&(" + Constants.OBJECTCLASS + "=" + CertificateTrustAuthority.class.getName() + ")(" + JarVerifierConstant.TRUST_AUTHORITY + "=" + trustAuthority + "))"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$//$NON-NLS-5$
} catch (InvalidSyntaxException e) {
e.printStackTrace();
// do nothing just use no filter TODO we may want to log something
}
if (filter != null) {
trustAuthorityTracker = new ServiceTracker(SignedBundleHook.getContext(), filter, null);
}
else
trustAuthorityTracker = new ServiceTracker(SignedBundleHook.getContext(), CertificateTrustAuthority.class.getName(), null);
trustAuthorityTracker.open();
}
return (CertificateTrustAuthority) trustAuthorityTracker.getService();
}
}