FileDocCategorySizeDatePackage
JarVerifier.javaAPI DocJava SE 6 API10783Tue Jun 10 00:25:58 BST 2008java.util.jar

JarVerifier

public class JarVerifier extends Object
version
1.38 05/12/01
author
Roland Schemers

Fields Summary
static final Debug
debug
private Hashtable
verifiedSigners
private Hashtable
sigFileSigners
private Hashtable
sigFileData
private ArrayList
pendingBlocks
"queue" of pending PKCS7 blocks that we couldn't parse until we parsed the .SF file
private ArrayList
signerCache
private boolean
parsingBlockOrSF
private boolean
parsingMeta
private boolean
anyToVerify
private ByteArrayOutputStream
baos
private ManifestDigester
manDig
The ManifestDigester object
byte[]
manifestRawBytes
the bytes for the manDig object
Constructors Summary
public JarVerifier(byte[] rawBytes)


       
	manifestRawBytes = rawBytes;
	sigFileSigners = new Hashtable();
	verifiedSigners = new Hashtable();
	sigFileData = new Hashtable(11);
	pendingBlocks = new ArrayList();
	baos = new ByteArrayOutputStream();
    
Methods Summary
public voidbeginEntry(java.util.jar.JarEntry je, sun.security.util.ManifestEntryVerifier mev)
This method scans to see which entry we're parsing and keeps various state information depending on what type of file is being parsed.

	if (je == null)
	    return;

	if (debug != null) {
	    debug.println("beginEntry "+je.getName());
	}

	String name = je.getName();

	/*
	 * Assumptions:
	 * 1. The manifest should be the first entry in the META-INF directory.
	 * 2. The .SF/.DSA files follow the manifest, before any normal entries
	 * 3. Any of the following will throw a SecurityException:
	 *    a. digest mismatch between a manifest section and
	 *       the SF section.
	 *    b. digest mismatch between the actual jar entry and the manifest
	 */

	if (parsingMeta) {
	    String uname = name.toUpperCase(Locale.ENGLISH);
	    if ((uname.startsWith("META-INF/") ||
		 uname.startsWith("/META-INF/"))) {

		if (je.isDirectory()) {
		    mev.setEntry(null, je);
		    return;
		}

		if (SignatureFileVerifier.isBlockOrSF(uname)) {
		    /* We parse only DSA or RSA PKCS7 blocks. */
		    parsingBlockOrSF = true;
		    baos.reset();
		    mev.setEntry(null, je);
		}
		return;
	    }
	}

	if (parsingMeta) {
	    doneWithMeta();
	}

	if (je.isDirectory()) {
	    mev.setEntry(null, je);
	    return;
	}

	// be liberal in what you accept. If the name starts with ./, remove
	// it as we internally canonicalize it with out the ./.
	if (name.startsWith("./"))
	    name = name.substring(2);

	// be liberal in what you accept. If the name starts with /, remove
	// it as we internally canonicalize it with out the /.
	if (name.startsWith("/"))
	    name = name.substring(1);

	// only set the jev object for entries that have a signature
	if (sigFileSigners.get(name) != null) {
	    mev.setEntry(name, je);
	    return;
	}

	// don't compute the digest for this entry
	mev.setEntry(null, je);

	return;
    
voiddoneWithMeta()
called to let us know we have processed all the META-INF entries, and if we re-read one of them, don't re-process it. Also gets rid of any data structures we needed when parsing META-INF entries.

	parsingMeta = false;
	anyToVerify = !sigFileSigners.isEmpty();
	baos = null;
	sigFileData = null;
	pendingBlocks = null;
	signerCache = null;
	manDig = null;
    
public java.security.cert.Certificate[]getCerts(java.lang.String name)
Return an array of java.security.cert.Certificate objects for the given file in the jar.

	return mapSignersToCertArray(getCodeSigners(name));
    
public java.security.CodeSigner[]getCodeSigners(java.lang.String name)
return an array of CodeSigner objects for the given file in the jar. this array is not cloned.

	return (CodeSigner[])verifiedSigners.get(name);
    
private static java.security.cert.Certificate[]mapSignersToCertArray(java.security.CodeSigner[] signers)


	if (signers != null) {
	    ArrayList certChains = new ArrayList();
	    for (int i = 0; i < signers.length; i++) {
		certChains.addAll(
		    signers[i].getSignerCertPath().getCertificates());
	    }

	    // Convert into a Certificate[]
	    return (java.security.cert.Certificate[])
		certChains.toArray(
		    new java.security.cert.Certificate[certChains.size()]);
	}
	return null;
    
booleannothingToVerify()
returns true if there no files to verify. should only be called after all the META-INF entries have been processed.

	return (anyToVerify == false);
    
private voidprocessEntry(sun.security.util.ManifestEntryVerifier mev)
called when we reach the end of entry in one of the read() methods.

	if (!parsingBlockOrSF) {
	    JarEntry je = mev.getEntry();
	    if ((je != null) && (je.signers == null)) {
		je.signers = mev.verify(verifiedSigners, sigFileSigners);
		je.certs = mapSignersToCertArray(je.signers);
	    }
	} else {

	    try {
		parsingBlockOrSF = false;

		if (debug != null) {
		    debug.println("processEntry: processing block");
		}

		String uname = mev.getEntry().getName()
                                             .toUpperCase(Locale.ENGLISH);

		if (uname.endsWith(".SF")) {
		    String key = uname.substring(0, uname.length()-3);
		    byte bytes[] = baos.toByteArray();
		    // add to sigFileData in case future blocks need it
		    sigFileData.put(key, bytes);
		    // check pending blocks, we can now process
		    // anyone waiting for this .SF file
		    Iterator it = pendingBlocks.iterator();
		    while (it.hasNext()) {
			SignatureFileVerifier sfv =
			    (SignatureFileVerifier) it.next();
			if (sfv.needSignatureFile(key)) {
			    if (debug != null) {
				debug.println(
				 "processEntry: processing pending block");
			    }

			    sfv.setSignatureFile(bytes);
			    sfv.process(sigFileSigners);
			}
		    }
		    return;
		}

		// now we are parsing a signature block file

		String key = uname.substring(0, uname.lastIndexOf("."));

		if (signerCache == null)
		    signerCache = new ArrayList();

		if (manDig == null) {
		    synchronized(manifestRawBytes) {
			if (manDig == null) {
			    manDig = new ManifestDigester(manifestRawBytes);
			    manifestRawBytes = null;
			}
		    }
		}

		SignatureFileVerifier sfv =
		  new SignatureFileVerifier(signerCache,
					    manDig, uname, baos.toByteArray());

		if (sfv.needSignatureFileBytes()) {
		    // see if we have already parsed an external .SF file
		    byte[] bytes = (byte[]) sigFileData.get(key);

		    if (bytes == null) {
			// put this block on queue for later processing
			// since we don't have the .SF bytes yet
			// (uname, block);
			if (debug != null) {
			    debug.println("adding pending block");
			}
			pendingBlocks.add(sfv);
			return;
		    } else {
			sfv.setSignatureFile(bytes);
		    }
		}
		sfv.process(sigFileSigners);

	    } catch (sun.security.pkcs.ParsingException pe) {
		if (debug != null) debug.println("processEntry caught: "+pe);
		// ignore and treat as unsigned
	    } catch (IOException ioe) {
		if (debug != null) debug.println("processEntry caught: "+ioe);
		// ignore and treat as unsigned
	    } catch (SignatureException se) {
		if (debug != null) debug.println("processEntry caught: "+se);
		// ignore and treat as unsigned
	    } catch (NoSuchAlgorithmException nsae) {
		if (debug != null) debug.println("processEntry caught: "+nsae);
		// ignore and treat as unsigned
	    } catch (CertificateException ce) {
		if (debug != null) debug.println("processEntry caught: "+ce);
		// ignore and treat as unsigned
	    }
	}
    
public voidupdate(int b, sun.security.util.ManifestEntryVerifier mev)
update a single byte.

	if (b != -1) {
	    if (parsingBlockOrSF) {
		baos.write(b);
	    } else {
		mev.update((byte)b);
	    }
	} else {
	    processEntry(mev);
	}
    
public voidupdate(int n, byte[] b, int off, int len, sun.security.util.ManifestEntryVerifier mev)
update an array of bytes.

	if (n != -1) {
	    if (parsingBlockOrSF) {
		baos.write(b, off, n);
	    } else {
		mev.update(b, off, n);
	    }
	} else {
	    processEntry(mev);
	}