blob: 50c8440ce3b8446b9158d6d99f1bcb795665573f [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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.update.internal.verifier;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.jar.JarFile;
import java.util.zip.ZipException;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.osgi.signedcontent.*;
import org.eclipse.osgi.util.NLS;
import org.eclipse.update.core.*;
import org.eclipse.update.internal.core.Messages;
import org.eclipse.update.internal.core.UpdateCore;
/**
* The JarVerifier will check the integrity of the JAR.
* If the Jar is signed and the integrity is validated,
* it will check if one of the certificate of each file
* is in one of the keystore.
*
*/
public class CertVerifier extends Verifier {
private CertVerificationResult result;
private boolean acceptUnsignedFiles;
private IProgressMonitor monitor;
private File jarFile;
private SignedContentFactory factory;
private List trustedSignerInfos;
/*
* Default Constructor
*/
public CertVerifier(SignedContentFactory factory) {
this.factory = factory;
initialize();
}
/*
*
*/
private void initialize() {
result = null;
acceptUnsignedFiles = false;
}
/*
* init
*/
private void init(IFeature feature, ContentReference contentRef) throws CoreException {
jarFile = null;
if (contentRef instanceof JarContentReference) {
JarContentReference jarReference = (JarContentReference) contentRef;
try {
jarFile = jarReference.asFile();
if (UpdateCore.DEBUG && UpdateCore.DEBUG_SHOW_INSTALL)
UpdateCore.debug("Attempting to read JAR file:"+jarFile); //$NON-NLS-1$
// # of entries
if (!jarFile.exists()) throw new IOException();
JarFile jar = new JarFile(jarFile);
if (jar !=null){
try {
jar.close();
} catch (IOException ex) {
// unchecked
}
}
} catch (ZipException e){
throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_InvalidJar, (new String[] { jarReference.toString() })), e);
} catch (IOException e) {
throw Utilities.newCoreException(NLS.bind(Messages.JarVerifier_UnableToAccessJar, (new String[] { jarReference.toString() })), e);
}
}
result = new CertVerificationResult();
result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
result.setResultException(null);
result.setFeature(feature);
result.setContentReference(contentRef);
}
/*
* @param newMonitor org.eclipse.core.runtime.IProgressMonitor
*/
private void setMonitor(IProgressMonitor newMonitor) {
monitor = newMonitor;
}
/*
* @see IVerifier#verify(IFeature,ContentReference,boolean, InstallMonitor)
*/
public IVerificationResult verify(
IFeature feature,
ContentReference reference,
boolean isFeatureVerification,
InstallMonitor monitor)
throws CoreException {
if (reference == null)
return result;
// if parent knows how to verify, ask the parent first
if (getParent() != null) {
IVerificationResult vr =
getParent().verify(feature, reference, isFeatureVerification, monitor);
if (vr.getVerificationCode() != IVerificationResult.TYPE_ENTRY_UNRECOGNIZED)
return vr;
}
// the parent couldn't verify
setMonitor(monitor);
init(feature, reference);
result.isFeatureVerification(isFeatureVerification);
if (jarFile!=null) {
result = verify(jarFile.getAbsolutePath(), reference.getIdentifier());
} else {
result.setVerificationCode(IVerificationResult.TYPE_ENTRY_UNRECOGNIZED);
}
return result;
}
/*
*
*/
private CertVerificationResult verify(String file, String identifier) {
try {
SignedContent verifier = factory.getSignedContent(new File(file));
// verify integrity
verifyIntegrity(verifier, identifier);
//if user already said yes
result.alreadySeen(alreadyValidated());
// save the fact the file is not signed, so the user will not be prompted again
if (result.getVerificationCode()
== IVerificationResult.TYPE_ENTRY_NOT_SIGNED) {
acceptUnsignedFiles = true;
}
} catch (Exception e) {
result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
result.setResultException(e);
}
if (monitor != null) {
monitor.worked(1);
if (monitor.isCanceled()) {
result.setVerificationCode(IVerificationResult.VERIFICATION_CANCELLED);
}
}
return result;
}
/*
* Verifies the integrity of the JAR
*/
private void verifyIntegrity(SignedContent verifier, String identifier) {
try {
if (verifier.isSigned()) {
// If the JAR is signed and invalid then mark as corrupted
if (hasValidContent(verifier.getSignedEntries())) {
result.setSignedContent(verifier);
SignerInfo[] signers = verifier.getSignerInfos();
for (int i = 0; i < signers.length; i++)
if (signers[i].isTrusted()) {
result.setVerificationCode(IVerificationResult.TYPE_ENTRY_SIGNED_RECOGNIZED);
break;
}
if (result.getVerificationCode() != IVerificationResult.TYPE_ENTRY_SIGNED_RECOGNIZED)
result.setVerificationCode(IVerificationResult.TYPE_ENTRY_SIGNED_UNRECOGNIZED);
} else
result.setVerificationCode(IVerificationResult.TYPE_ENTRY_CORRUPTED);
} else {
result.setVerificationCode(IVerificationResult.TYPE_ENTRY_NOT_SIGNED);
return;
}
} catch (Exception e) {
result.setVerificationCode(IVerificationResult.UNKNOWN_ERROR);
result.setResultException(e);
}
}
private boolean hasValidContent(SignedContentEntry[] signedEntries) {
try {
for (int i = 0; i < signedEntries.length; i++)
signedEntries[i].verify();
} catch (InvalidContentException e) {
return false;
} catch (IOException e) {
return false;
}
return true;
}
/*
*
*/
private boolean alreadyValidated() {
int verifyCode = result.getVerificationCode();
if (verifyCode == IVerificationResult.TYPE_ENTRY_NOT_SIGNED)
return (acceptUnsignedFiles);
if (verifyCode == IVerificationResult.UNKNOWN_ERROR)
return false;
if (result.getSigners() != null) { //getTrustedCertificates() can't be null as it is lazy initialized
Iterator iter = getTrustedInfos().iterator();
SignerInfo[] signers = result.getSigners();
// check if this is not a user accepted certificate for this feature
while (iter.hasNext()) {
SignerInfo chain = (SignerInfo) iter.next();
for (int i = 0; i < signers.length; i++)
if (chain.equals(signers[i]))
return true;
}
// if certificate pair not found in trusted add it for next time
for (int i = 0; i < signers.length; i++) {
addTrustedSignerInfo(signers[i]);
}
}
return false;
}
/*
*
*/
private void addTrustedSignerInfo(SignerInfo signer) {
if (trustedSignerInfos == null)
trustedSignerInfos = new ArrayList();
if (signer != null)
trustedSignerInfos.add(signer);
}
/*
*
*/
private List getTrustedInfos() {
if (trustedSignerInfos == null)
trustedSignerInfos = new ArrayList();
return trustedSignerInfos;
}
/**
* @see IVerifier#setParent(IVerifier)
*/
public void setParent(IVerifier parentVerifier) {
super.setParent(parentVerifier);
initialize();
}
}