FileDocCategorySizeDatePackage
SecureInstaller.javaAPI DocJ2ME MIDP 2.09758Thu Nov 07 12:02:24 GMT 2002com.sun.midp.midletsuite

SecureInstaller

public class SecureInstaller extends Installer
This class is able to verify JAD's signed according to the wireless extension specification.

Fields Summary
private static final String
SIG_PROP
MIDlet property for the application signature
private static final String
CERT_PROP
MIDlet property for the content provider certificates
private String
lastCa
Set to the issuer of last certificate chain checked.
private X509Certificate
cpCert
Authenticated content provider certificate.
Constructors Summary
Methods Summary
private intcheckCertChain(int chainNum)
Check to see if a provider certificate chain is issued by a known CA. Set the lastCA field to name of the CA in any case. Authenticate the chain and set the cpCert field to the provider's certificate if the CA is known.

param
chainNum the number of the chain
return
1 if the CA of the chain is known, 0 if not, -1 if the chain is not found
exception
InvalidJadException if something other wrong with a other than an unknown CA

        int certNum;
        Vector derCerts = new Vector();
        String base64Cert;
        byte[] derCert;

        for (certNum = 1; ; certNum++) {
            base64Cert = state.getAppProperty(CERT_PROP + 
                                              chainNum + "-" + certNum);
            if (base64Cert == null) {
                break;
            }

            try {
                derCert = Base64.decode(base64Cert);
                derCerts.addElement(X509Certificate.generateCertificate(
                    derCert, 0, derCert.length));
            } catch (Exception e) {
                throw new InvalidJadException(
                    InvalidJadException.CORRUPT_PROVIDER_CERT);
            }
        }

        if (certNum == 1) {
            // Chain not found
            return -1;
        }

        try {
            lastCa = X509Certificate.verifyChain(derCerts,
                         X509Certificate.DIGITAL_SIG_KEY_USAGE,
                         X509Certificate.CODE_SIGN_EXT_KEY_USAGE,
                         WebPublicKeyStore.getTrustedKeyStore()).getIssuer();
            cpCert = (X509Certificate)derCerts.elementAt(0);

            // Authenticated
            return 1;
        } catch (CertificateException ce) {
            switch (ce.getReason()) {
            case CertificateException.UNRECOGNIZED_ISSUER:
                lastCa = ce.getCertificate().getIssuer();

                // Issuer not found
                return 0;

            case CertificateException.EXPIRED:
            case CertificateException.NOT_YET_VALID:
                throw new InvalidJadException(
                    InvalidJadException.EXPIRED_PROVIDER_CERT,
                    ce.getCertificate().getSubject());

            case CertificateException.ROOT_CA_EXPIRED:
                throw new InvalidJadException(
                    InvalidJadException.EXPIRED_CA_KEY,
                    ce.getCertificate().getIssuer());
            }

            throw new InvalidJadException(
                InvalidJadException.INVALID_PROVIDER_CERT,
                ce.getCertificate().getSubject());
        }
    
private voidfindProviderCert()
Find the first provider certificate that is signed by a known CA. Set the lastCA field to name of the CA. Set the cpCert field to the provider certificate.

exception
InvalidJadException if the JAR is not valid or the provider certificate is missing or a general certificate error

        int chain;
        int result;

        /*
         * To save memory for applications that do not use PKI,
         * the public keys of the certificate authorities may not
         * have been loaded yet.
         */
        WebPublicKeyStore.loadCertificateAuthorities();

        for (chain = 1; ; chain++) {
            result = checkCertChain(chain); // sets the lastCa and cpCert
            if (result == 1) {
                // we found the good chain
                return;
            }

            if (result == -1) {
                // chain not found, done
                break;
            }
        }

        if (chain == 1) {
            throw new
                InvalidJadException(InvalidJadException.MISSING_PROVIDER_CERT);
        }

        // None of the certificates were issued by a known CA
        throw new
            InvalidJadException(InvalidJadException.UNKNOWN_CA, lastCa);
    
protected java.lang.StringgetSecurityDomainName(java.lang.String storageName, java.lang.String ca)
Looks up the domain of a MIDlet suite.

param
storageName storage name of a MIDlet suite
param
ca CA of an installed suite
return
security domain of the MIDlet suite


                                       
          
        Vector keys;
        String domain;

        /*
         * look up the domain owner, then get the domain from the
         * trusted key store and set the security domain
         */
        try {
            keys = WebPublicKeyStore.getTrustedKeyStore().
                         findKeys(ca);

            domain = ((PublicKeyInfo)keys.elementAt(0)).getDomain();
        } catch (Exception e) {
            domain = "untrusted";
        }

        return domain;
    
protected voidverifyJar(RandomAccessStream jarStorage, java.lang.String jarFilename)
Verifies a Jar. On success set the name of the domain owner in the install state. Post any error back to the server.

param
jarStorage System store for applications
param
jarFilename name of the jar to read.
exception
IOException if any error prevents the reading of the JAR
exception
InvalidJadException if the JAR is not valid or the provider certificate is missing

        InputStream jarStream;
        String jarSig;

        jarSig = state.getAppProperty(SIG_PROP);
        if (jarSig == null) {
            // no signature to verify
            return;
        }

        findProviderCert(); // This will fill in the cpCert and lastCa fields
        jarStorage.connect(jarFilename, Connector.READ);

        try {
            jarStream = jarStorage.openInputStream();
            try {
                verifyStream(jarStream, jarSig);
                state.ca = lastCa;
            } finally {
                jarStream.close();
            }
        } finally {
            jarStorage.disconnect();
        }
    
private voidverifyStream(java.io.InputStream stream, java.lang.String base64Signature)
Common routine that verifies a stream of bytes. The cpCert field must be set before calling.

param
stream stream to verify
param
base64Signature The base64 encoding of the PKCS v1.5 SHA with RSA signature of this stream.
exception
NullPointerException if the public keystore has not been established.
exception
InvalidJadException the JAR signature is not valid
exception
IOException if any error prevents the reading of the JAR

        PublicKey cpKey;
        byte[] sig;
        Signature sigVerifier;
        byte[] temp;
        int bytesRead;
        byte[] hash;

        try {
            cpKey = cpCert.getPublicKey();
        } catch (CertificateException e) {
            throw new
                InvalidJadException(InvalidJadException.INVALID_PROVIDER_CERT);
        }

        try {
            sig = Base64.decode(base64Signature);
        } catch (IOException e) {
            throw new
                InvalidJadException(InvalidJadException.CORRUPT_SIGNATURE);
        }

        try {
            // verify the jad signature
            sigVerifier = Signature.getInstance(Signature.ALG_RSA_SHA_PKCS1,
                                                false);
            sigVerifier.init(cpKey, Signature.MODE_VERIFY);

            temp = new byte[1024];
            for (; ; ) {
                bytesRead = stream.read(temp);
                if (bytesRead == -1) {
                    break;
                }

                sigVerifier.update(temp, 0, bytesRead);
            }
            
            if (!sigVerifier.verify(null, 0, 0,
                    sig, (short)0, (short)sig.length)) {
                throw new
                    InvalidJadException(InvalidJadException.INVALID_SIGNATURE);
            }
        } catch (CryptoException e) {
            throw new
                InvalidJadException(InvalidJadException.INVALID_SIGNATURE);
        }