Just An Application

August 14, 2014

And Another One: Part Twelve — JarVerifier.initEntry

File

    $(ANDROID_SRC)/libcore/luni/src/main/java/java/util/jar/JarVerifier.java

Source

    ...
    
    VerifierEntry initEntry(String name) {
        // If no manifest is present by the time an entry is found,
        // verification cannot occur. If no signature files have
        // been found, do not verify.
        if (man == null || signatures.size() == 0) {
            return null;
        }
    
        Attributes attributes = man.getAttributes(name);
        // entry has no digest
        if (attributes == null) {
            return null;
        }
    
        ArrayList<Certificate> certs = new ArrayList<Certificate>();
        Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
            HashMap<String, Attributes> hm = entry.getValue();
            if (hm.get(name) != null) {
                // Found an entry for entry name in .SF file
                String signatureFile = entry.getKey();
                certs.addAll(getSignerCertificates(signatureFile, certificates));
            }
        }
                    
        // entry is not signed
        if (certs.isEmpty()) {
            return null;
        }
        Certificate[] certificatesArray = certs.toArray(new Certificate[certs.size()]);
                    
        for (int i = 0; i < DIGEST_ALGORITHMS.length; i++) {
            final String algorithm = DIGEST_ALGORITHMS[i];
            final String hash = attributes.getValue(algorithm + "-Digest");
            if (hash == null) {
                continue;
            }
            byte[] hashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
                    
            try {
                return new VerifierEntry(name, MessageDigest.getInstance(algorithm), hashBytes,
                        certificatesArray);
            } catch (NoSuchAlgorithmException e) {
                // ignored
            }
        }
        return null;
    }

    ...

JarVerifier State

At the point the initEntry method is called the JarFile.getInputStream has already executed all the initialization code in its first half

Given

  • a JAR file with a Manifest containing digests for all the members of the JAR file not in the META-INF directory,

  • a signature file (DIGESTS.SF) containing the correct digests for the entry digest sections present in the Manifest, and

  • a signed signature file (DIGESTS.RSA) containing the correct signature for the signature file

then

  • the man instance variable will reference the Manifest instance created by the JarFile.getManifest method.

  • the signatures Hashtable will contain, for the key "DIGESTS.SF", the HashMap of per member attributes created during the call to the verifyCertificate method .

  • the certificates Hashtable will contain, for the key "DIGESTS.SF", the array of certificates returned by the JarUtils.verifySignature method.

The initEntry Method

Given the state described above the method starts by iterating over the contents of the signatures HashMap.

        ...

        Iterator<Map.Entry<String, HashMap<String, Attributes>>> it = signatures.entrySet().iterator();
        while (it.hasNext()) {
            Map.Entry<String, HashMap<String, Attributes>> entry = it.next();
            HashMap<String, Attributes> hm = entry.getValue();
            if (hm.get(name) != null) {
                // Found an entry for entry name in .SF file
                String signatureFile = entry.getKey();
                certs.addAll(getSignerCertificates(signatureFile, certificates));
            }
        }
        
        ...

It will find the signature file attributes for the named member of the JAR and then call the getSignerCertificates method
and add the result to the list of certificates certs.

The getSignerCertificates method gets the certificates for the given signature file from the certificates HashMap.

Note that if there were multiple signature files each defining attributes for the entry, all the certificates associated with the corresponding signed signature files would be added to certs.

It then looks for a digest attribute in the Manifest attributes for the given entry in the JAR

        ...
    
        for (int i = 0; i < DIGEST_ALGORITHMS.length; i++) {
            final String algorithm = DIGEST_ALGORITHMS[i];
            final String hash = attributes.getValue(algorithm + "-Digest");
            if (hash == null) {
                continue;
            }
            byte[] hashBytes = hash.getBytes(StandardCharsets.ISO_8859_1);
    
            try {
                return new VerifierEntry(name, MessageDigest.getInstance(algorithm), hashBytes,
                        certificatesArray);
            } catch (NoSuchAlgorithmException e) {
                // ignored
            }
        }

        ...

If it finds one it returns a new instance of the inner class VerifierEntry, which is constructed with the name of the member of the JAR,
an appropriate MessageDigest instance , and the set of certificates computed previously.


Copyright (c) 2014 By Simon Lewis. All Rights Reserved.

Unauthorized use and/or duplication of this material without express and written permission from this blog’s author and owner Simon Lewis is strictly prohibited.

Excerpts and links may be used, provided that full and clear credit is given to Simon Lewis and justanapplication.wordpress.com with appropriate and specific direction to the original content.

Advertisements

1 Comment »

  1. […] As we have seen a VerifierEntry instance is created by the JarVerifier method initEntry. […]

    Pingback by And Another One: Part Fourteen — JarVerifier.VerifierEntry.verify | Just An Application — August 15, 2014 @ 8:03 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: