Just An Application

August 16, 2014

And Another One: Part Sixteen — Spot The Deliberate Mistake

If you have made it this far through the labyrinth of method calls you will undoubtedly have noticed that at no point has there been any attempt made to determine whether the certificates that were included in the signed signature file and that were returned by the call to the JarUtils.createChain method actually have any relationship to one another, that is, whether the supposed issuer of each certificate did in fact sign that certificate.

It is not difficult to do so

There is a very helpful method on the class java.security.certificate.Certificate

    public abstract void verify(PublicKey key)
                         throws
                             CertificateException,
                             NoSuchAlgorithmException,
                             InvalidKeyException,
                             NoSuchProviderException,
                             SignatureException

which

Verifies that this certificate was signed using the private key that corresponds to the specified public key.

Verifying A Certificate Chain

This is a modified version of the original application which uses the java.security.certificate.Certificate verify method to verify its certificates as encapsulated in its signatures.


    package xper.android.app.saithe;
    
    import java.io.ByteArrayInputStream;
    import java.security.Principal;
    import java.security.cert.CertificateFactory;
    import java.security.cert.X509Certificate;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.content.pm.PackageInfo;
    import android.content.pm.PackageManager;
    import android.content.pm.Signature;
    import android.view.Menu;
    
    public class MainActivity
                 extends
                     Activity
    {
        @Override
        protected void onCreate(Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            PackageManager pm = getPackageManager();
            
            try
            {
                PackageInfo pi = pm.getPackageInfo("xper.android.app.saithe", PackageManager.GET_SIGNATURES);
    
                boolean verified = verifyCertificates(pi.signatures);
    
                System.out.println("verified == " + verified);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
        }
    
        @Override
        public boolean onCreateOptionsMenu(Menu menu)
        {
            // Inflate the menu; this adds items to the action bar if it is present.
            getMenuInflater().inflate(R.menu.main, menu);
            return true;
        }

        private boolean verifyCertificates(Signature[] theSignatures)
                        throws
                            Exception
        {
            X509Certificate[] certificates = makeCertificates(theSignatures);
        
            return verifyCertificates(certificates[0], certificates);
        }
        
        private boolean verifyCertificates(X509Certificate theSignerCertificate, X509Certificate[] theCertificates)
                        throws
                            Exception
        {
            X509Certificate current = theSignerCertificate;
		
            while (true)
            {
                System.out.println("current subject == " + current.getSubjectDN());
        
                Principal issuer = current.getIssuerDN();
        
                System.out.println("current issuer  == " + issuer);
        
                X509Certificate issuerCertificate = findCertificate(issuer, theCertificates);
        
                if (issuerCertificate == null)
                {
                    return false;
                }
                current.verify(issuerCertificate.getPublicKey());
                if (current.getSubjectDN().equals(issuer))
                {
                    return true;
                }
                current = issuerCertificate;
            }
        }
        
        private X509Certificate findCertificate(Principal theIssuer, X509Certificate[] theCertificates)
        {
            for (X509Certificate c : theCertificates)
            {
                if (c.getSubjectDN().equals(theIssuer))
                {
                    return c;
                }
            }
            return null;
        }
        
        private X509Certificate[] makeCertificates(Signature[] theSignatures)
                                  throws
                                      Exception
        {
            CertificateFactory cf            = CertificateFactory.getInstance("X.509");
            int                nCertificates = theSignatures.length;
            X509Certificate[]  certificates  = new X509Certificate[nCertificates];
		
            for (int i = 0; i < nCertificates; i++)
            {
                certificates[i] = (X509Certificate)cf.generateCertificate(
                                                          new ByteArrayInputStream(
                                                                  theSignatures[i].toByteArray()));
            }
            return certificates;
        }
    }

and this is what happens when you run it

    ...
    
    I/ActivityManager(  516): Start proc xper.android.app.saithe for activity xper.android.app.saithe/.MainActivity: pid=2296 uid=10077 gids={50077, 1028}
    D/dalvikvm( 2296): Late-enabling CheckJNI
    I/System.out( 2296): current subject == CN=AndroidApplication Saithe, OU=AndroidApplication Saithe Group, \
        O=ASH Two, L=Emerald City, ST=Erehwon, C=OZ
    I/System.out( 2296): current issuer  == CN=Adobe Systems Incorporated, OU=Information Systems,  \
        O=Adobe Systems Incorporated, L=San Jose, ST=California, C=US
    W/System.err( 2296): java.security.SignatureException: error:04091077:rsa routines:INT_RSA_VERIFY:wrong signature length
    W/System.err( 2296): 	at org.apache.harmony.xnet.provider.jsse.NativeCrypto.X509_verify(Native Method)
    W/System.err( 2296): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLX509Certificate.verifyOpenSSL(OpenSSLX509Certificate.java:333)
    W/System.err( 2296): 	at org.apache.harmony.xnet.provider.jsse.OpenSSLX509Certificate.verify(OpenSSLX509Certificate.java:366)
    W/System.err( 2296): 	at xper.android.app.saithe.MainActivity.verifyCertificates(MainActivity.java:122)
    W/System.err( 2296): 	at xper.android.app.saithe.MainActivity.verifyCertificates(MainActivity.java:99)
    W/System.err( 2296): 	at xper.android.app.saithe.MainActivity.onCreate(MainActivity.java:40)
    W/System.err( 2296): 	at android.app.Activity.performCreate(Activity.java:5133)
    W/System.err( 2296): 	at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
    W/System.err( 2296): 	at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
    W/System.err( 2296): 	at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
    W/System.err( 2296): 	at android.app.ActivityThread.access$600(ActivityThread.java:141)
    W/System.err( 2296): 	at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
    W/System.err( 2296): 	at android.os.Handler.dispatchMessage(Handler.java:99)
    W/System.err( 2296): 	at android.os.Looper.loop(Looper.java:137)
    W/System.err( 2296): 	at android.app.ActivityThread.main(ActivityThread.java:5103)
    W/System.err( 2296): 	at java.lang.reflect.Method.invokeNative(Native Method)
    W/System.err( 2296): 	at java.lang.reflect.Method.invoke(Method.java:525)
    W/System.err( 2296): 	at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
    W/System.err( 2296): 	at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
    W/System.err( 2296): 	at dalvik.system.NativeStart.main(Native Method)
    
    ...

Not very surprising really.

Given that I do not know the private key corresponding to the public key in the Adobe certificate, there was no way the certificate I created for the public key corresponding to the private key I signed the application with could possibly be verified.

The extent of my sleight of hand was simply to ensure that the issuer of the certificate I created was the same as that of the subject of the Adobe certificate.

Arguably it was not really even a sleight of hand.

I do have a second certificate whose subject is the same as that of the Adobe certificate and it does specify the public key corresponding to the private key with which the first certificate was signed.

It just wasn’t the one that got included in the signed signature file.


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.

Create a free website or blog at WordPress.com.