javacommons/security/javasrc/com/nokia/mj/impl/security/midp/authentication/AuthenticationModule.java
changeset 21 2a9601315dfc
child 48 e0d6e9bd3ca7
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 package com.nokia.mj.impl.security.midp.authentication;
       
    19 
       
    20 import com.nokia.mj.impl.utils.Uid;
       
    21 import com.nokia.mj.impl.utils.Tokenizer;
       
    22 import com.nokia.mj.impl.security.common.InstallerSecurityException;
       
    23 import com.nokia.mj.impl.security.common.RuntimeSecurityException;
       
    24 import com.nokia.mj.impl.utils.InstallerDetailedErrorMessage;
       
    25 import com.nokia.mj.impl.utils.InstallerErrorMessage;
       
    26 import com.nokia.mj.impl.utils.OtaStatusCode;
       
    27 import com.nokia.mj.impl.security.utils.SecurityErrorMessage;
       
    28 import com.nokia.mj.impl.security.utils.SecurityDetailedErrorMessage;
       
    29 import com.nokia.mj.impl.security.utils.TelUtils;
       
    30 import com.nokia.mj.impl.security.midp.common.AuthenticationCredentials;
       
    31 import com.nokia.mj.impl.security.midp.common.AuthenticationInfo;
       
    32 import com.nokia.mj.impl.security.midp.common.AuthenticationAttribute;
       
    33 import com.nokia.mj.impl.security.midp.common.SecurityAttributes;
       
    34 import com.nokia.mj.impl.security.common.Certificate;
       
    35 import com.nokia.mj.impl.security.common.SecurityCommsMessages;
       
    36 import com.nokia.mj.impl.security.midp.common.ProtectionDomain;
       
    37 import com.nokia.mj.impl.security.midp.common.SigningCertificate;
       
    38 import com.nokia.mj.impl.security.midp.common.SigningInfo;
       
    39 import com.nokia.mj.impl.security.midp.common.GeneralSecuritySettings;
       
    40 import com.nokia.mj.impl.security.midp.storage.*;
       
    41 import com.nokia.mj.impl.storage.StorageSession;
       
    42 import com.nokia.mj.impl.rt.support.Jvm;
       
    43 import com.nokia.mj.impl.rt.support.ApplicationInfo;
       
    44 import com.nokia.mj.impl.security.utils.Logger;
       
    45 import com.nokia.mj.impl.comms.CommsEndpoint;
       
    46 import com.nokia.mj.impl.comms.CommsMessage;
       
    47 import com.nokia.mj.impl.comms.exception.CommsException;
       
    48 import com.nokia.mj.impl.fileutils.DriveUtilities;
       
    49 import com.nokia.mj.impl.fileutils.DriveInfo;
       
    50 import java.util.Hashtable;
       
    51 import java.util.Vector;
       
    52 
       
    53 /**
       
    54  * MIDP authentication is build around X.509 Public Key Infrastructure so that
       
    55  * MIDlet suites are signed using public key certificates and therefore
       
    56  * authenticated by verifying the authenticity of the MIDlet suite's signing
       
    57  * certificates with the help of trusted (root) certificates.
       
    58  * As a result of authentication a MIDlet suite is bound to a protection domain
       
    59  * which will be used as a criteria for granting the MIDlet access to protected
       
    60  * functionality.
       
    61  * This class is used for authenticating MIDlet suites.
       
    62  */
       
    63 public final class AuthenticationModule
       
    64 {
       
    65     static
       
    66     {
       
    67         Jvm.loadSystemLibrary("javasecurity");
       
    68     }
       
    69 
       
    70     /*
       
    71      * Hashtable containing the all of the authentication credentials
       
    72      * of different aplications being installed
       
    73      */
       
    74     private Hashtable iAuthCredentials;
       
    75 
       
    76     /*
       
    77      * Hashtable containing the selected authentication credentials of
       
    78      * different aplications being installed
       
    79      */
       
    80     private Hashtable iSelectedAuthCredentials;
       
    81 
       
    82     /*
       
    83      * Hashtable containing the ocsp checkers corresponding to
       
    84      * installation of various MIDlet suites
       
    85      */
       
    86     private Hashtable iOcspCheckers;
       
    87 
       
    88     /*
       
    89      * Hashtable containing the ocsp event listeners corresponding to
       
    90      * ocsp checks of various MIDlet suites
       
    91      */
       
    92     private Hashtable iOcspEventListeners;
       
    93 
       
    94     // self
       
    95     private static AuthenticationModule self;
       
    96 
       
    97     // data structure which holds the flags about different suites
       
    98     // being legacy suites or not; the flag info is available at
       
    99     // authentication JAD operation time, but not available at
       
   100     // authentication JAR operation time -> this hashtable carries
       
   101     // the flag between authenticating JAD and JAR operations for
       
   102     // same suite
       
   103     private static Hashtable iLegacySuiteFlags = new Hashtable();
       
   104 
       
   105     /**
       
   106      * The ocsp settings
       
   107      */
       
   108     private static OcspSettings iOcspSettings;
       
   109     private static OcspUserPreferences iOcspUserPreferences;
       
   110 
       
   111     /*
       
   112      * The security warnings mode
       
   113      */
       
   114     private static int iSecurityWarningsMode = GeneralSecuritySettings.UNINITIALIZED_SECURITY_MODE;
       
   115 
       
   116     /**
       
   117      * Creates an instance of the AuthenticationModule
       
   118      *
       
   119      * @return An instance of AuthenticationModule
       
   120      */
       
   121     public static AuthenticationModule getInstance()
       
   122     {
       
   123         if (self == null)
       
   124         {
       
   125             self = new AuthenticationModule();
       
   126         }
       
   127         return self;
       
   128     }
       
   129 
       
   130     /**
       
   131      * Authenticates a certain MIDlet suite. This method is called
       
   132      * when/if the JAD is available
       
   133      *
       
   134      * @param msUID    the UID if the MIDlet suite being authenticated
       
   135      * @param oldMSUID the UID if the MIDlet suite being updated
       
   136      *                 (if applicable)
       
   137      * @param authInfo the authentication info based on which the MIDlet suite
       
   138      *                 is authenticated
       
   139      * @return         a set of credentials assigned to the MIDlet suite
       
   140      */
       
   141     public AuthenticationCredentials[] authenticateJad(
       
   142         Uid msUID,
       
   143         Uid oldMSUID,
       
   144         AuthenticationInfo[] authInfo)
       
   145     {
       
   146         Vector allAuthCredentials = null;
       
   147         if (authInfo == null || authInfo.length == 0)
       
   148         {
       
   149             // this is untrusted MIDlet -> save the protection domain only
       
   150             allAuthCredentials = verifyUpdate(
       
   151                                      new Credentials[] {new Credentials("UnidentifiedThirdParty",
       
   152                                                                         ApplicationInfo.UNIDENTIFIED_THIRD_PARTY_DOMAIN,
       
   153                                                                         null, null, -1, null)
       
   154                                                        }, oldMSUID);
       
   155         }
       
   156         else
       
   157         {
       
   158             try
       
   159             {
       
   160                 // save all the credentials as candidates -> after having the JAR,
       
   161                 // based on its hash we will select the protection_domain,
       
   162                 // root_hash and the validated_chain_indexes
       
   163                 allAuthCredentials = verifyUpdate(
       
   164                                          authInfo[0].getLegacyInfo(),
       
   165                                          _validateChainsAndSignatures(authInfo), oldMSUID,
       
   166                                          true /* order the result */);
       
   167                 // start an OCSP client if the ocsp checks are enabled
       
   168                 if (performOcsp())
       
   169                 {
       
   170                     // start the OCSP checks for all the succesfully validated chains
       
   171                     if (allAuthCredentials.size() > 0)
       
   172                     {
       
   173                         OcspData[] ocspData = new OcspData[allAuthCredentials.size()];
       
   174                         for (int i=0; i<allAuthCredentials.size(); i++)
       
   175                         {
       
   176                             Credentials authCredentials =
       
   177                                 (Credentials)allAuthCredentials.elementAt(i);
       
   178                             // need to add the root the to chain when doing the ocsp checks
       
   179                             String[] certChain  = authInfo[(authCredentials
       
   180                                                             .validatedChainIndex - 1)].getCertChain();
       
   181                             String root = getRoot(authCredentials.rootHashValue);
       
   182                             if (root != null)
       
   183                             {
       
   184                                 String[] completeCertChain =
       
   185                                     new String[certChain.length + 1];
       
   186                                 int j;
       
   187                                 for (j=0; j<certChain.length; j++)
       
   188                                 {
       
   189                                     completeCertChain[j] = certChain[j];
       
   190                                 }
       
   191                                 completeCertChain[j] = root;
       
   192                                 certChain = completeCertChain;
       
   193                             }
       
   194                             ocspData[i] = new OcspData(certChain);
       
   195                         }
       
   196                         // build the ocspChecker with the newly built cert chains
       
   197                         OcspChecker ocspChecker = new OcspChecker(ocspData,
       
   198                                 iOcspSettings,
       
   199                                 iOcspUserPreferences,
       
   200                                 (OcspEventListener)iOcspEventListeners.get(msUID));
       
   201                         iOcspCheckers.put(msUID, ocspChecker);
       
   202                         // start the OCSP check
       
   203                         ocspChecker.start();
       
   204                     }
       
   205                 }
       
   206             }
       
   207             catch (AuthenticationException e)
       
   208             {
       
   209                 Logger.log(e);
       
   210                 switch (e.getErrorCode())
       
   211                 {
       
   212                 case AuthenticationException.CONNECTION_TO_CAPTAIN_FAILED:
       
   213                 case AuthenticationException.SENDING_MSG_TO_CAPTAIN_FAILED:
       
   214                     throw new InstallerSecurityException(
       
   215                         InstallerErrorMessage.INST_UNEXPECTED_ERR,
       
   216                         null, /* no params for short msg */
       
   217                         InstallerDetailedErrorMessage.INTERNAL_ERROR,
       
   218                         new String[] {"Internal communication problem."},
       
   219                         OtaStatusCode.INTERNAL_ERROR);
       
   220                 case AuthenticationException.CERT_VERIFICATION_FAILED:
       
   221                 case AuthenticationException.CERT_NOT_YET_VALID:
       
   222                 case AuthenticationException.CERT_EXPIRED:
       
   223                 case AuthenticationException.ROOT_CERT_IN_CHAIN:
       
   224                 case AuthenticationException.MISSING_ROOT:
       
   225                 case AuthenticationException.UNKNOWN_EXT_KEY_USAGE:
       
   226                     throw new InstallerSecurityException(
       
   227                         InstallerErrorMessage.INST_AUTHENTICATION_ERR,
       
   228                         null, /* no params for short msg */
       
   229                         InstallerDetailedErrorMessage.CERT_UNSUPPORTED,
       
   230                         null, /* no params for detailed msg */
       
   231                         OtaStatusCode.APPLICATION_AUTHENTICATION_FAILURE);
       
   232                 case AuthenticationException.SIG_VERIFICATION_FAILED:
       
   233                     throw new InstallerSecurityException(
       
   234                         InstallerErrorMessage.INST_AUTHORIZATION_ERR,
       
   235                         null, /* no params for short msg */
       
   236                         InstallerDetailedErrorMessage.ATTR_HANDLING_FAILED,
       
   237                         new String[] {AuthenticationAttribute
       
   238                                       .SECOND_LEGACY_ATTRIBUTE_NAME
       
   239                                      },
       
   240                         OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
       
   241                 case AuthenticationException.MISSING_DOMAIN_MAPPING:
       
   242                     throw new InstallerSecurityException(
       
   243                         InstallerErrorMessage.INST_AUTHORIZATION_ERR,
       
   244                         null, /* no params for short msg */
       
   245                         InstallerDetailedErrorMessage.CERT_UNSUPPORTED,
       
   246                         null, /* no params for detailed msg */
       
   247                         OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
       
   248                 }
       
   249             }
       
   250         }
       
   251         iAuthCredentials.put(msUID, allAuthCredentials);
       
   252         Credentials[] credentials = new Credentials[allAuthCredentials.size()];
       
   253         allAuthCredentials.copyInto(credentials);
       
   254         Logger.logAuthenticationCredentials(allAuthCredentials);
       
   255         return credentials;
       
   256     }
       
   257 
       
   258     /**
       
   259      * Authenticates a certain MIDlet suite. This method is called
       
   260      * when the JAR is available
       
   261      *
       
   262      * @param storageSession the JavaStorage session to be used when
       
   263      *                       storing security data
       
   264      * @param msUID          the UID if the MIDlet suite being authenticated
       
   265      * @param oldMSUID       the UID if the MIDlet suite being updated
       
   266      *                       (if applicable)
       
   267      * @param appJARPath     the path to the JAR being authenticated
       
   268      */
       
   269     public void authenticateJar(
       
   270         StorageSession storageSession,
       
   271         Uid msUID,
       
   272         Uid oldMSUID,
       
   273         String appJARPath,
       
   274         boolean drmContent)
       
   275     {
       
   276         AuthenticationStorageData data = null;
       
   277         try
       
   278         {
       
   279             Vector allAuthCredentials = (Vector)iAuthCredentials.get(msUID);
       
   280             String jarHash = _computeHash(appJARPath);
       
   281             if (jarHash == null || jarHash.length() == 0)
       
   282             {
       
   283                 // could not compute hash for the given application
       
   284                 Logger.logWarning("Could not compute hash for " + appJARPath);
       
   285                 throw new InstallerSecurityException(
       
   286                     InstallerErrorMessage.INST_UNEXPECTED_ERR,
       
   287                     null, /* no params for short msg */
       
   288                     InstallerDetailedErrorMessage.INTERNAL_ERROR,
       
   289                     new String[] {"Could not compute hash for " + appJARPath},
       
   290                     OtaStatusCode.INTERNAL_ERROR);
       
   291             }
       
   292             if (allAuthCredentials == null
       
   293                     || (allAuthCredentials.size() == 1
       
   294                         && ((Credentials)allAuthCredentials.elementAt(0))
       
   295                         .getProtectionDomainCategory().equals(
       
   296                             ApplicationInfo.UNIDENTIFIED_THIRD_PARTY_DOMAIN)))
       
   297             {
       
   298                 data = new AuthenticationStorageData(
       
   299                     "UnidentifiedThirdParty",
       
   300                     ApplicationInfo.UNIDENTIFIED_THIRD_PARTY_DOMAIN,
       
   301                     jarHash,
       
   302                     null /*rootHashValue*/,
       
   303                     null /*validatedChainIndexes*/,
       
   304                     null /* jarPath*/,
       
   305                     iSecurityWarningsMode);
       
   306                 verifyUpdate(
       
   307                     new Credentials[] {new Credentials(
       
   308                                            data.getProtectionDomain(),
       
   309                                            data.getProtectionDomainCategory(),
       
   310                                            jarHash,
       
   311                                            null /* root hash */,
       
   312                                            -1 /* validated chain index*/,
       
   313                                            null /* signing cert */)
       
   314                                       },
       
   315                     oldMSUID);
       
   316             }
       
   317             else
       
   318             {
       
   319                 // get the authentication credential candidates and select the right
       
   320                 // domain/root_hash and validated_chain_index based on the hash of
       
   321                 // the JAR
       
   322                 String protectionDomainName = null;
       
   323                 String protectionDomainCategory = null;
       
   324                 String jarHashValue = null;
       
   325                 String rootHashValue = null;
       
   326                 Vector validatedChainIndexes = new Vector();
       
   327                 Credentials selectedCredentials = selectCredentials(jarHash, allAuthCredentials, validatedChainIndexes);
       
   328                 if (selectedCredentials == null
       
   329                         || selectedCredentials.getProtectionDomainName() == null)
       
   330                 {
       
   331                     if (!drmContent)
       
   332                     {
       
   333                         Logger.logWarning("Signature verification failure: the computed and the decrypted JAR hashes do not match");
       
   334                         throw new InstallerSecurityException(
       
   335                             InstallerErrorMessage.INST_AUTHORIZATION_ERR,
       
   336                             null, /* no params for short msg */
       
   337                             InstallerDetailedErrorMessage.ATTR_HANDLING_FAILED,
       
   338                             new String[] {AuthenticationAttribute
       
   339                                           .SECOND_LEGACY_ATTRIBUTE_NAME
       
   340                                          },
       
   341                             OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
       
   342                     }
       
   343                     else
       
   344                     {
       
   345                         // give it one more try
       
   346                         String drmJarHash = _drmDecryptAndComputeHash(appJARPath);
       
   347                         validatedChainIndexes.removeAllElements();
       
   348                         selectedCredentials = selectCredentials(drmJarHash, allAuthCredentials, validatedChainIndexes);
       
   349                         if (selectedCredentials == null
       
   350                                 || selectedCredentials.getProtectionDomainName() == null)
       
   351                         {
       
   352                             Logger.logWarning("Signature verification failure: the computed and the decrypted JAR hashes do not match");
       
   353                             throw new InstallerSecurityException(
       
   354                                 InstallerErrorMessage.INST_AUTHORIZATION_ERR,
       
   355                                 null, /* no params for short msg */
       
   356                                 InstallerDetailedErrorMessage.ATTR_HANDLING_FAILED,
       
   357                                 new String[] {AuthenticationAttribute
       
   358                                               .SECOND_LEGACY_ATTRIBUTE_NAME
       
   359                                              },
       
   360                                 OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
       
   361                         }
       
   362                         // re-set the jar hash to the hash of what acts as JAR
       
   363                         // (not the JAR from inside the DRM content), so no
       
   364                         // need to do the DRM decrypting when doing the
       
   365                         // tamper detection at runtime
       
   366                         selectedCredentials.jarHashValue = jarHash;
       
   367                     }
       
   368                 }
       
   369                 data = new AuthenticationStorageData(
       
   370                     selectedCredentials.getProtectionDomainName(),
       
   371                     selectedCredentials.getProtectionDomainCategory(),
       
   372                     selectedCredentials.jarHashValue,
       
   373                     selectedCredentials.rootHashValue,
       
   374                     validatedChainIndexes,
       
   375                     iSecurityWarningsMode);
       
   376             }
       
   377 
       
   378             writeAuthenticationStorageData(storageSession, msUID, data, (oldMSUID != null && oldMSUID.equals(msUID)));
       
   379         }
       
   380         finally
       
   381         {
       
   382             // remove all the auth credentials with the selection
       
   383             if (data != null)
       
   384             {
       
   385                 iSelectedAuthCredentials.put(msUID, data);
       
   386             }
       
   387         }
       
   388     }
       
   389 
       
   390     /**
       
   391      */
       
   392     public void authenticateJar(
       
   393         StorageSession storageSession,
       
   394         Uid uid,
       
   395         Uid oldUid,
       
   396         ProtectionDomain protectionDomain,
       
   397         String appJARPath)
       
   398     {
       
   399         if (protectionDomain == null
       
   400                 || (!protectionDomain.equals(ProtectionDomain.getManufacturerDomain())
       
   401                     && !protectionDomain.equals(ProtectionDomain.getOperatorDomain())
       
   402                     && !protectionDomain.equals(ProtectionDomain.getIdentifiedThirdPartyDomain())
       
   403                     && !protectionDomain.equals(ProtectionDomain.getUnidentifiedThirdPartyDomain())))
       
   404         {
       
   405             Logger.logWarning("Unknown protection domain " + protectionDomain);
       
   406             throw new InstallerSecurityException(
       
   407                 InstallerErrorMessage.INST_UNEXPECTED_ERR,
       
   408                 null, /* no params for short msg */
       
   409                 InstallerDetailedErrorMessage.INTERNAL_ERROR,
       
   410                 new String[] {"Unknown protection domain " + protectionDomain},
       
   411                 OtaStatusCode.INTERNAL_ERROR);
       
   412         }
       
   413         String jarHash = _computeHash(appJARPath);
       
   414         if (jarHash == null || jarHash.length() == 0)
       
   415         {
       
   416             // could not compute hash for the given application
       
   417             Logger.logWarning("Could not compute hash for " + appJARPath);
       
   418             throw new InstallerSecurityException(
       
   419                 InstallerErrorMessage.INST_UNEXPECTED_ERR,
       
   420                 null, /* no params for short msg */
       
   421                 InstallerDetailedErrorMessage.INTERNAL_ERROR,
       
   422                 new String[] {"Could not compute hash for " + appJARPath},
       
   423                 OtaStatusCode.INTERNAL_ERROR);
       
   424         }
       
   425         AuthenticationStorageData data = new AuthenticationStorageData(
       
   426             protectionDomain.getName(),
       
   427             protectionDomain.getCategory(),
       
   428             jarHash,
       
   429             null /*rootHashValue*/,
       
   430             null /*validatedChainIndexes*/,
       
   431             null /* jarPath*/,
       
   432             iSecurityWarningsMode);
       
   433         verifyUpdate(
       
   434             new Credentials[] {new Credentials(
       
   435                                    data.getProtectionDomain(),
       
   436                                    data.getProtectionDomainCategory(),
       
   437                                    jarHash,
       
   438                                    null /* root hash */,
       
   439                                    -1 /* validated chain index*/,
       
   440                                    null /* signing cert */)
       
   441                               },
       
   442             oldUid);
       
   443 
       
   444         writeAuthenticationStorageData(storageSession, uid, data, (oldUid != null && oldUid.equals(uid)));
       
   445     }
       
   446 
       
   447     /**
       
   448      * Registers a listener for ocsp events corresponding to the
       
   449      * installation of a certain MIDlet suite
       
   450      *
       
   451      * @param aMsUid    the uid of the MIDlet suite on behalf
       
   452      *                  of which the listener is registered
       
   453      * @param aListener the ocsp events listener
       
   454      */
       
   455     public void registerOcspEventListener(Uid aMsUid,
       
   456                                           OcspEventListener aListener)
       
   457     {
       
   458         if (aMsUid != null && aListener != null)
       
   459         {
       
   460             Logger.log("OcspEventListener registered on behalf of the suite " + aMsUid.toString());
       
   461             iOcspEventListeners.put(aMsUid, aListener);
       
   462         }
       
   463     }
       
   464 
       
   465     /**
       
   466      * Unregisters the listener for ocsp events corresponding to the
       
   467      * installation of a certain MIDlet suite
       
   468      *
       
   469      * @param aMsUid    the uid of the MIDlet suite on behalf
       
   470      *                  of which the listener is unregistered
       
   471      */
       
   472     public void unregisterOcspEventListener(Uid aMsUid)
       
   473     {
       
   474         if (aMsUid != null)
       
   475         {
       
   476             Logger.log("OcspEventListener unregistered on behalf of the suite " + aMsUid.toString());
       
   477             iOcspEventListeners.remove(aMsUid);
       
   478         }
       
   479     }
       
   480 
       
   481     /**
       
   482      * Cancels any Ocsp checks (if any)
       
   483      *
       
   484      * @param msUid the UID if the MIDlet suite oh whose behalf the ocsp
       
   485      *              checks are canceled
       
   486      */
       
   487     public void cancelOcspCheck(Uid msUid)
       
   488     {
       
   489         OcspChecker ocspChecker = (OcspChecker)iOcspCheckers.get(msUid);
       
   490         if (ocspChecker != null)
       
   491         {
       
   492             ocspChecker.cancel();
       
   493         }
       
   494     }
       
   495 
       
   496     /**
       
   497      * Returns the signing info of certain application suite
       
   498      *
       
   499      * @param aAppSuiteName    the name of the application suite for which the
       
   500                                signing info is queried
       
   501      * @param aAppSuiteVersion the version of the application suite for which
       
   502      *                         the signing info is queried
       
   503      * @param aAppSuiteVendor  the vendor of the application suite for which
       
   504                                the signing info is queried
       
   505      * @return                 The signing info if the queried application
       
   506      *                         suite has been signed or NULL otherwise
       
   507      */
       
   508     public SigningInfo getSigningInfo(String aAppSuiteName,
       
   509                                       String aAppSuiteVersion,
       
   510                                       String aAppSuiteVendor)
       
   511     {
       
   512         SecurityStorage storage = new SecurityStorage();
       
   513         try
       
   514         {
       
   515             AuthenticationStorageData authData = storage.
       
   516                                                  readAuthenticationStorageData(
       
   517                                                      aAppSuiteName, aAppSuiteVersion, aAppSuiteVendor,
       
   518                                                      SecurityStorage.AUTHENTICATION_DOMAIN_NAME_QUERY
       
   519                                                      | SecurityStorage.AUTHENTICATION_DOMAIN_CATEGORY_QUERY
       
   520                                                      | SecurityStorage.AUTHENTICATION_ROOT_HASH_QUERY);
       
   521             if (authData != null)
       
   522             {
       
   523                 Certificate signingCert = null;
       
   524                 Certificate rootCert = null;
       
   525                 AppAccessAuthorizationStorageData appAccesAuthData = storage
       
   526                         .readAppAccessAuthorizationStorageData(aAppSuiteName,
       
   527                                                                aAppSuiteVersion, aAppSuiteVendor,
       
   528                                                                SecurityStorage.APP_ACCESS_AUTH_SIGNERS_LIST_QUERY);
       
   529                 if (appAccesAuthData != null && appAccesAuthData.getSignersList() != null
       
   530                         && appAccesAuthData.getSignersList().length > 0)
       
   531                 {
       
   532                     signingCert = _parseCertificate(
       
   533                                       appAccesAuthData.getSignersList()[0]);
       
   534                     rootCert = _getRootCertificate(
       
   535                                    authData.getRootHashValue());
       
   536                 }
       
   537                 return new SigningInfo(signingCert, rootCert,
       
   538                                        new ProtectionDomain(authData.getProtectionDomain(),
       
   539                                                             authData.getProtectionDomainCategory()));
       
   540             }
       
   541             return null;
       
   542         }
       
   543         finally
       
   544         {
       
   545             storage.close();
       
   546         }
       
   547     }
       
   548 
       
   549 
       
   550     /**
       
   551      * Removes all the security data related to a certain MIDlet suite
       
   552      *
       
   553      * @param sessionID the JavaStorage session to be used when
       
   554      *                  removing the security data
       
   555      * @param msUID     the UID if the MIDlet suite whose security data is
       
   556      *                  being removed
       
   557      */
       
   558     public void removeSecurityData(StorageSession storageSession, Uid msUID)
       
   559     {
       
   560         Logger.log("Remove authentication data");
       
   561         SecurityStorage storage = new SecurityStorage(storageSession);
       
   562         storage.removeAuthenticationStorageData(msUID);
       
   563         // clean the caches as well
       
   564         iAuthCredentials.remove(msUID);
       
   565         iSelectedAuthCredentials.remove(msUID);
       
   566         iLegacySuiteFlags.remove(msUID);
       
   567         OcspChecker ocspChecker = (OcspChecker)iOcspCheckers.remove(msUID);
       
   568         if (ocspChecker != null)
       
   569         {
       
   570             ocspChecker.destroy();
       
   571         }
       
   572         iOcspEventListeners.remove(msUID);
       
   573     }
       
   574 
       
   575     /**
       
   576      * Returns the details of the certificates used for authenticating a
       
   577      * MIDlet suite. This method is used at installation time.
       
   578      *
       
   579      * @param sessionID the JavaStorage session to be used when
       
   580      *                  retrieving the certificates details
       
   581      * @param msUID     the UID if the MIDlet suite whose certificate details
       
   582      *                  are queried
       
   583      * @return          the details of the certificate used for authenticating
       
   584      *                  the MIDlet suite or null if the details are not
       
   585      *                  available
       
   586      */
       
   587     public SigningCertificate[] getCertificatesDetails(StorageSession storageSession, Uid msUID)
       
   588     {
       
   589         Vector allAuthCredentials = (Vector)iAuthCredentials.get(msUID);
       
   590         SigningCertificate[] certDetails = null;
       
   591         if (allAuthCredentials != null && allAuthCredentials.size() > 0)
       
   592         {
       
   593             Vector vCertDetails = new Vector();
       
   594             for (int i=0; i<allAuthCredentials.size(); i++)
       
   595             {
       
   596                 Credentials credentials = ((Credentials)allAuthCredentials
       
   597                                            .elementAt(i));
       
   598                 Certificate cert = credentials.signingCert;
       
   599                 if (cert != null)
       
   600                 {
       
   601                     vCertDetails.addElement(new SigningCertificate(
       
   602                                                 cert, credentials.rootHashValue,
       
   603                                                 credentials.getProtectionDomainName(),
       
   604                                                 credentials.getProtectionDomainCategory()));
       
   605                 }
       
   606             }
       
   607             if (vCertDetails.size() > 0)
       
   608             {
       
   609                 certDetails = new SigningCertificate[vCertDetails.size()];
       
   610                 vCertDetails.copyInto(certDetails);
       
   611             }
       
   612         }
       
   613         else
       
   614         {
       
   615             // if cert details are not found in cache, retrieve the signing
       
   616             // certificate from storage and extract the details from it
       
   617             SecurityStorage storage = new SecurityStorage(storageSession);
       
   618             SigningCertificate signingCertificate = retrieveSigningCertificate(
       
   619                                                         storage, msUID);
       
   620             if (signingCertificate != null)
       
   621             {
       
   622                 certDetails = new SigningCertificate[1];
       
   623                 certDetails[0] = signingCertificate;
       
   624             }
       
   625         }
       
   626         return certDetails;
       
   627     }
       
   628 
       
   629     /**
       
   630      * Returns the protection domain info of a certain MIDlet suite. This
       
   631      * method is used at uninstallation time.
       
   632      *
       
   633      * @param sessionID the JavaStorage session to be used when
       
   634      *                  retrieving the domain category
       
   635      * @param msUID     the UID if the MIDlet suite whose protection
       
   636      *                  domain info is queried
       
   637      * @param           one of the constants defined in ApplicationInfo
       
   638      */
       
   639     public String getProtectionDomainCategory(StorageSession storageSession, Uid msUID)
       
   640     {
       
   641         SecurityStorage storage = new SecurityStorage(storageSession);
       
   642         return storage.readProtectionDomainCategory(msUID);
       
   643     }
       
   644 
       
   645     /**
       
   646      * Notification about the media where a certain MIDlet suite is installed.
       
   647      *
       
   648      * @param aStorageSession the JavaStorage session to be used when/if
       
   649      *                        making storage operations related to this
       
   650      *                        notification
       
   651      * @param aMsUid          the UID of the MIDlet suite whose media info is
       
   652      *                        notified
       
   653      * @param aMediaId        the identifier of the media where the MIDlet
       
   654      *                        suite is installed
       
   655      */
       
   656     public void setMediaId(StorageSession aStorageSession, Uid aMsUid, int aMediaId)
       
   657     {
       
   658         // store the jar hash only if the suite was installed on a non-protected media
       
   659         if (isDriveProtected(aMediaId))
       
   660         {
       
   661             SecurityStorage storage = new SecurityStorage(aStorageSession);
       
   662             try
       
   663             {
       
   664                 AuthenticationStorageData authStorageData =
       
   665                     (AuthenticationStorageData)iSelectedAuthCredentials.get(
       
   666                         aMsUid);
       
   667                 if (authStorageData != null)
       
   668                 {
       
   669                     Logger.log("Suite installed on protected media -> the runtime tamper detection is disabled");
       
   670                     authStorageData.setJarHashValue(null);
       
   671                     storage.writeAuthenticationStorageData(aMsUid,
       
   672                                                            authStorageData,
       
   673                                                            true /* this is an update */);
       
   674                 }
       
   675             }
       
   676             finally
       
   677             {
       
   678                 iSelectedAuthCredentials.remove(aMsUid);
       
   679             }
       
   680 
       
   681         }
       
   682     }
       
   683 
       
   684     /**
       
   685      * Setter for the OCSP settings
       
   686      */
       
   687     public void setOCSPFlags(OcspSettings ocspSettings)
       
   688     {
       
   689         Logger.log("Ocsp settings = " + ocspSettings.toString());
       
   690         iOcspSettings = ocspSettings;
       
   691     }
       
   692 
       
   693     /**
       
   694      * Performs a cleanup (e.g. on cached data)
       
   695      *
       
   696      */
       
   697     public void cleanup()
       
   698     {
       
   699         Logger.log("Cleanup authentication module cache");
       
   700         iAuthCredentials.clear();
       
   701         iSelectedAuthCredentials.clear();
       
   702         iLegacySuiteFlags.clear();
       
   703         iOcspCheckers.clear();
       
   704         iOcspEventListeners.clear();
       
   705     }
       
   706 
       
   707     /**
       
   708      * Verifies the authenticity of MIDlet suites
       
   709      *
       
   710      * @param msUid           The Uid of the MIDlet suite whose authenticity
       
   711      *                        is verified
       
   712      * @param authStorageData The stored authentication data assigned to the
       
   713      *                        MIDlet suite whose authenticity is verified
       
   714      *
       
   715      */
       
   716     public void verifyMIDletSuiteAuthenticity(Uid msUid, AuthenticationStorageData authStorageData)
       
   717     {
       
   718         Logger.log("Verifying the authenticity of the suite " + msUid.toString());
       
   719         // for the operator MIDlets, check if there are any network restrictions
       
   720         if (ApplicationInfo.OPERATOR_DOMAIN.equals(
       
   721                     authStorageData.getProtectionDomainCategory()))
       
   722         {
       
   723             Logger.log("  Checking network restrictions for operator signed suites");
       
   724             // get the restrictions from storage
       
   725             SecurityStorage storage = new SecurityStorage();
       
   726             String networkRestrictions = storage.readNetworkRestrictions(msUid);
       
   727             storage.close();
       
   728             if (networkRestrictions != null
       
   729                     && networkRestrictions.length() > 0)
       
   730             {
       
   731                 // get the real network codes
       
   732                 TelUtils.NetworkCodes networkCodes = TelUtils.getNetworkCodes();
       
   733                 boolean found = false;
       
   734                 if (networkCodes != null)
       
   735                 {
       
   736                     Logger.log("    Network restrictions: " + networkRestrictions);
       
   737                     Logger.log("    Network codes: mcc(" + networkCodes.mcc + ") mnc(" + networkCodes.mnc + ")");
       
   738                     // go through the list of restrictions and try to find a match
       
   739                     // the list of restrictions is a space-separated list of MCC-MNC*/
       
   740                     String[] tuples = Tokenizer.split(networkRestrictions, " ");
       
   741                     if (tuples != null)
       
   742                     {
       
   743                         for (int i=0; i<tuples.length; i++)
       
   744                         {
       
   745                             int mccEndPos = tuples[i].indexOf('-');
       
   746                             String mcc = tuples[i].substring(0, mccEndPos);
       
   747                             String mnc = tuples[i].substring(mccEndPos + 1);
       
   748                             if (mcc.equals(networkCodes.mcc)
       
   749                                     && mnc.equals(networkCodes.mnc))
       
   750                             {
       
   751                                 found = true;
       
   752                                 break;
       
   753                             }
       
   754                         }
       
   755                     }
       
   756                 }
       
   757                 if (!found)
       
   758                 {
       
   759                     Logger.logWarning("  -> the network restrictions are violated");
       
   760                     throw new RuntimeSecurityException(
       
   761                         SecurityErrorMessage.NETWORK_RESTRICTION_VIOLATION,
       
   762                         null, /* no params for short msg */
       
   763                         SecurityDetailedErrorMessage.NETWORK_RESTRICTION_VIOLATION,
       
   764                         null /* no params for detailed msg */);
       
   765                 }
       
   766                 Logger.log("  -> the network restrictions are obeyed");
       
   767             }
       
   768         }
       
   769 
       
   770         // check the root validity (if applicable)
       
   771         if (authStorageData.getRootHashValue() != null
       
   772                 && authStorageData.getRootHashValue().length() > 0)
       
   773         {
       
   774             Logger.log("  Checking validity of the root certificate used in authentication");
       
   775             switch (retrieveRootState(authStorageData.getRootHashValue()))
       
   776             {
       
   777             case SecurityCommsMessages.JAVA_CERT_STORE_STATE_ENABLED:
       
   778                 // ok -> just go on
       
   779                 Logger.log("    Root ok");
       
   780                 break;
       
   781             case SecurityCommsMessages.JAVA_CERT_STORE_STATE_DISABLED:
       
   782                 Logger.logWarning("    Root disabled");
       
   783                 throw new RuntimeSecurityException(
       
   784                     SecurityErrorMessage.CERT_NOT_AVAILABLE,
       
   785                     null, /* no params for short msg */
       
   786                     SecurityDetailedErrorMessage.CERT_DISABLED,
       
   787                     null /* no params for detailed msg */);
       
   788             case SecurityCommsMessages.JAVA_CERT_STORE_STATE_DELETED:
       
   789                 Logger.logWarning("    Root deleted");
       
   790                 throw new RuntimeSecurityException(
       
   791                     SecurityErrorMessage.CERT_NOT_AVAILABLE,
       
   792                     null, /* no params for short msg */
       
   793                     SecurityDetailedErrorMessage.CERT_DELETED,
       
   794                     null /* no params for detailed msg */);
       
   795             case SecurityCommsMessages.JAVA_CERT_STORE_STATE_NOT_PRESENT:
       
   796                 Logger.logWarning("    Root not available");
       
   797                 throw new RuntimeSecurityException(
       
   798                     SecurityErrorMessage.CERT_NOT_AVAILABLE,
       
   799                     null, /* no params for short msg */
       
   800                     SecurityDetailedErrorMessage.SIM_CHANGED,
       
   801                     null /* no params for detailed msg */);
       
   802             case SecurityCommsMessages.JAVA_CERT_STORE_STATE_UNKNOWN:
       
   803                 Logger.logWarning("    Root unknown");
       
   804                 throw new RuntimeSecurityException(
       
   805                     SecurityErrorMessage.CERT_NOT_AVAILABLE,
       
   806                     null, /* no params for short msg */
       
   807                     SecurityDetailedErrorMessage.UNIDENTIFIED_APPLICATION,
       
   808                     null /* no params for detailed msg */);
       
   809             }
       
   810         }
       
   811 
       
   812         if (authStorageData.getJarPath() == null
       
   813                 || authStorageData.getJarPath().length() == 0)
       
   814         {
       
   815             Logger.logWarning("  JarPath not available");
       
   816             throw new RuntimeSecurityException(
       
   817                 SecurityErrorMessage.UNEXPECTED_ERR,
       
   818                 null, /* no params for short msg */
       
   819                 SecurityDetailedErrorMessage.UNIDENTIFIED_APPLICATION,
       
   820                 null /* no params for detailed msg */);
       
   821         }
       
   822 
       
   823         // do the tamper detection
       
   824         if (authStorageData.getJarHashValue() != null
       
   825                 && authStorageData.getJarHashValue().length() > 0)
       
   826         {
       
   827             Logger.log("  Doing tamper detection");
       
   828             String computedJarHash = _computeHash(authStorageData.getJarPath());
       
   829             // do the tampering check: compute the hash and compare it with the stored hash
       
   830             if (computedJarHash == null || !computedJarHash.equals(
       
   831                         authStorageData.getJarHashValue()))
       
   832             {
       
   833                 Logger.logWarning("    Application has been tampered");
       
   834                 throw new RuntimeSecurityException(
       
   835                     SecurityErrorMessage.JAR_TAMPERED,
       
   836                     null, /* no params for short msg */
       
   837                     SecurityDetailedErrorMessage.JAR_TAMPERED,
       
   838                     null /* no params for detailed msg */);
       
   839             }
       
   840         }
       
   841     }
       
   842 
       
   843     private AuthenticationModule()
       
   844     {
       
   845         iAuthCredentials = new Hashtable();
       
   846         iSelectedAuthCredentials = new Hashtable();
       
   847         iOcspCheckers = new Hashtable();
       
   848         iOcspEventListeners = new Hashtable();
       
   849         // default ocsp settings
       
   850         iOcspSettings = new OcspSettings(
       
   851             OcspSettings.OCSP_MODE_UNDEFINED,
       
   852             OcspSettings.OCSP_WARNING_UNDEFINED,
       
   853             false /* silent*/,
       
   854             "0" /* iap */,
       
   855             "0" /* snap */);
       
   856         iOcspUserPreferences = new OcspUserPreferences();
       
   857         iSecurityWarningsMode = GeneralSecuritySettings
       
   858                                 .getDefaultSecurityWarningsMode();
       
   859         Logger.log("Ocsp user preferences = " + iOcspUserPreferences.toString());
       
   860     }
       
   861 
       
   862     private SigningCertificate retrieveSigningCertificate(SecurityStorage storage, Uid msUID)
       
   863     {
       
   864         SigningCertificate signingCertificate = null;
       
   865         AppAccessAuthorizationStorageData authData = storage
       
   866                 .readAppAccessAuthorizationStorageData(msUID,
       
   867                                                        SecurityStorage.APP_ACCESS_AUTH_SIGNERS_LIST_QUERY);
       
   868         if (authData != null && authData.getSignersList() != null
       
   869                 && authData.getSignersList().length > 0)
       
   870         {
       
   871             Certificate cert = _parseCertificate(authData
       
   872                                                  .getSignersList()[0]);
       
   873             if (cert != null)
       
   874             {
       
   875                 AuthenticationStorageData signingData = storage.
       
   876                                                         readAuthenticationStorageData(msUID);
       
   877                 signingCertificate = new SigningCertificate(cert,
       
   878                         signingData.getRootHashValue(),
       
   879                         signingData.getProtectionDomain(),
       
   880                         signingData.getProtectionDomainCategory());
       
   881             }
       
   882         }
       
   883         return signingCertificate;
       
   884     }
       
   885 
       
   886     private Vector verifyUpdate(Credentials[] credentials, Uid oldMSUID)
       
   887     {
       
   888         return verifyUpdate(isLegacySuite(oldMSUID), credentials, oldMSUID, false /* don't order the returned credentials */);
       
   889     }
       
   890 
       
   891     // Security rules for update:
       
   892     // 1. the old and the new MIDlet suites must be bound to the same
       
   893     // protection domain
       
   894     // 2. Only for MIDP3 MIDlets, the the old and the new MIDlet
       
   895     // suites MUST share at least one common signer (for legacy MIDlets
       
   896     // it is ok not to share a common signer, case in which the update
       
   897     // is decided by the user)
       
   898     //
       
   899     // Common signer is defined as matching the Organization field
       
   900     // within the Subject field of the signing certificate of MIDlet
       
   901     // Suite update and the signing certificate of the original MIDlet
       
   902     // Suite, where the signing certificates are validated against
       
   903     // the same Protection Domain Root Certificate)
       
   904     //
       
   905     // This method discards the credentials which do not obey the rules
       
   906     // mentioned above and returns either all credentials which have same
       
   907     // signer OR all credentials which do NOT have same signer,
       
   908     // but not any combination
       
   909     private Vector verifyUpdate(boolean legacyMIDletSuite, Credentials[] credentials, Uid oldMSUID, boolean orderResult)
       
   910     {
       
   911         Vector allCredentials = new Vector(credentials.length);
       
   912         for (int i=0; i<credentials.length; i++)
       
   913         {
       
   914             allCredentials.addElement(credentials[i]);
       
   915         }
       
   916         if (oldMSUID != null)
       
   917         {
       
   918             SecurityStorage storage = new SecurityStorage();
       
   919             Vector sameSignerCredentials = new Vector();
       
   920             Vector differentSignerCredentials = new Vector();
       
   921             try
       
   922             {
       
   923                 ProtectionDomain oldProtectionDomain = new ProtectionDomain(
       
   924                     storage.readProtectionDomain(oldMSUID),
       
   925                     storage.readProtectionDomainCategory(oldMSUID));
       
   926                 for (int i=0; i<credentials.length; i++)
       
   927                 {
       
   928                     if (oldProtectionDomain.equals(
       
   929                                 credentials[i].getProtectionDomain()))
       
   930                     {
       
   931                         SigningCertificate oldSigningCertificate =
       
   932                             retrieveSigningCertificate(storage, oldMSUID);
       
   933                         SigningCertificate newSigningCertificate =
       
   934                             new SigningCertificate(credentials[i].signingCert,
       
   935                                                    credentials[i].rootHashValue,
       
   936                                                    credentials[i].getProtectionDomainName(),
       
   937                                                    credentials[i].getProtectionDomainCategory());
       
   938                         if (newSigningCertificate.isSameSigner(
       
   939                                     oldSigningCertificate))
       
   940                         {
       
   941                             sameSignerCredentials.addElement(credentials[i]);
       
   942                         }
       
   943                         else if (legacyMIDletSuite)
       
   944                         {
       
   945                             differentSignerCredentials.addElement(credentials[i]);
       
   946                         }
       
   947                     }
       
   948                     else if (legacyMIDletSuite
       
   949                              && !ApplicationInfo.UNIDENTIFIED_THIRD_PARTY_DOMAIN.equals(
       
   950                                  credentials[i].getProtectionDomain().getCategory()))
       
   951                     {
       
   952                         differentSignerCredentials.addElement(credentials[i]);
       
   953                     }
       
   954                 }
       
   955                 if (sameSignerCredentials.size() != 0)
       
   956                 {
       
   957                     allCredentials = sameSignerCredentials;
       
   958                 }
       
   959                 else if (differentSignerCredentials.size() != 0)
       
   960                 {
       
   961                     allCredentials = differentSignerCredentials;
       
   962                 }
       
   963                 else
       
   964                 {
       
   965                     throw new InstallerSecurityException(
       
   966                         InstallerErrorMessage.INST_AUTHORIZATION_ERR,
       
   967                         null, /* no params for short msg */
       
   968                         InstallerDetailedErrorMessage.DIFFERENT_SIGNERS,
       
   969                         null, /* no params for the detailed msg*/
       
   970                         OtaStatusCode.APPLICATION_AUTHORIZATION_FAILURE);
       
   971                 }
       
   972             }
       
   973             finally
       
   974             {
       
   975                 storage.close();
       
   976             }
       
   977         }
       
   978         if (orderResult)
       
   979         {
       
   980             // put the credentials with domain info first
       
   981             int i=0;
       
   982             int size = allCredentials.size();
       
   983             while (i<size)
       
   984             {
       
   985                 Credentials current = (Credentials)allCredentials.elementAt(i);
       
   986                 if (current.getProtectionDomainName() == null
       
   987                         || current.getProtectionDomainCategory() == null)
       
   988                 {
       
   989                     // swap the current element with the last one
       
   990                     Object last = allCredentials.lastElement();
       
   991                     allCredentials.setElementAt(last,i);
       
   992                     allCredentials.setElementAt(current,(size-1));
       
   993                     size--;
       
   994                 }
       
   995                 else
       
   996                 {
       
   997                     i++;
       
   998                 }
       
   999             }
       
  1000         }
       
  1001         return allCredentials;
       
  1002     }
       
  1003 
       
  1004     private boolean isLegacySuite(Uid msUID)
       
  1005     {
       
  1006         if (msUID == null)
       
  1007         {
       
  1008             return true;
       
  1009         }
       
  1010         Boolean tmp = (Boolean)iLegacySuiteFlags.remove(msUID);
       
  1011         if (tmp != null)
       
  1012         {
       
  1013             return tmp.booleanValue();
       
  1014         }
       
  1015         else
       
  1016         {
       
  1017             SecurityStorage storage = new SecurityStorage();
       
  1018             String suiteVersion = storage.readSuiteVersion(msUID);
       
  1019             storage.close();
       
  1020             if (suiteVersion != null)
       
  1021             {
       
  1022                 boolean legacySuite = !suiteVersion.equalsIgnoreCase(
       
  1023                                           SecurityAttributes.MIDP3_VERSION_ATTRIBUTE_VALUE);
       
  1024                 iLegacySuiteFlags.put(msUID, new Boolean(legacySuite));
       
  1025                 return legacySuite;
       
  1026             }
       
  1027             return true;
       
  1028         }
       
  1029     }
       
  1030 
       
  1031     private String getRoot(String rootHash)
       
  1032     {
       
  1033         CommsEndpoint comms = null;
       
  1034         try
       
  1035         {
       
  1036             comms = new CommsEndpoint();
       
  1037             comms.connect(CommsEndpoint.JAVA_CAPTAIN);
       
  1038             CommsMessage sMessage = new CommsMessage();
       
  1039             sMessage.setMessageId(SecurityCommsMessages.JAVA_CERT_STORE_MSG_ID_REQUEST);
       
  1040             sMessage.setModuleId(SecurityCommsMessages.PLUGIN_ID_JAVA_CERT_STORE_EXTENSION);
       
  1041             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_OPERATION_QUERY_CERTS);
       
  1042             // add filter
       
  1043             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_FILTER_ID_STATE);
       
  1044             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_STATE_ENABLED);
       
  1045             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_FILTER_ID_HASH);
       
  1046             sMessage.write(rootHash);
       
  1047             // add the query ID
       
  1048             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_QUERY_ID_CERT_CONTENT_PEM);
       
  1049             CommsMessage rMessage = comms.sendReceive(sMessage, 10);
       
  1050             // read the reply
       
  1051             String tmp = rMessage.readString();
       
  1052             if (tmp != null && tmp.length() > 0)
       
  1053             {
       
  1054                 return rMessage.readString();
       
  1055             }
       
  1056         }
       
  1057         catch (CommsException e)
       
  1058         {
       
  1059             // fall through
       
  1060         }
       
  1061         finally
       
  1062         {
       
  1063             if (comms != null)
       
  1064             {
       
  1065                 comms.destroy();
       
  1066             }
       
  1067         }
       
  1068         return null;
       
  1069     }
       
  1070 
       
  1071     private int retrieveRootState(String rootHash)
       
  1072     {
       
  1073 
       
  1074         CommsEndpoint comms = null;
       
  1075         try
       
  1076         {
       
  1077             comms = new CommsEndpoint();
       
  1078             comms.connect(CommsEndpoint.JAVA_CAPTAIN);
       
  1079             CommsMessage sMessage = new CommsMessage();
       
  1080             sMessage.setMessageId(SecurityCommsMessages.JAVA_CERT_STORE_MSG_ID_REQUEST);
       
  1081             sMessage.setModuleId(SecurityCommsMessages.PLUGIN_ID_JAVA_CERT_STORE_EXTENSION);
       
  1082             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_OPERATION_QUERY_CERTS);
       
  1083             // add filter
       
  1084             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_FILTER_ID_HASH);
       
  1085             sMessage.write(rootHash);
       
  1086             // add the query ID
       
  1087             sMessage.write(SecurityCommsMessages.JAVA_CERT_STORE_QUERY_ID_STATE);
       
  1088             CommsMessage rMessage = comms.sendReceive(sMessage, 10);
       
  1089             // read the reply
       
  1090             return rMessage.readInt();
       
  1091         }
       
  1092         catch (CommsException e)
       
  1093         {
       
  1094             // fall through
       
  1095         }
       
  1096         finally
       
  1097         {
       
  1098             if (comms != null)
       
  1099             {
       
  1100                 comms.destroy();
       
  1101             }
       
  1102         }
       
  1103         return SecurityCommsMessages.JAVA_CERT_STORE_STATE_UNKNOWN;
       
  1104     }
       
  1105 
       
  1106     private boolean performOcsp()
       
  1107     {
       
  1108         if (iOcspSettings.ocspMode
       
  1109                 != OcspSettings.OCSP_MODE_UNDEFINED)
       
  1110         {
       
  1111             return (iOcspSettings.ocspMode == OcspSettings.OCSP_MODE_ENABLED);
       
  1112         }
       
  1113         // check the user preferences
       
  1114         return (iOcspUserPreferences.getOcspMode()
       
  1115                 == OcspUserPreferences.OCSP_MODE_ON
       
  1116                 || iOcspUserPreferences.getOcspMode()
       
  1117                 == OcspUserPreferences.OCSP_MODE_MUST);
       
  1118     }
       
  1119 
       
  1120     private boolean isDriveProtected(int aMediaId)
       
  1121     {
       
  1122         DriveInfo[] allDrives = DriveUtilities.getAllDrives();
       
  1123         if (allDrives != null)
       
  1124         {
       
  1125             for (int i=0; i<allDrives.length; i++)
       
  1126             {
       
  1127                 if (aMediaId == allDrives[i].iId)
       
  1128                 {
       
  1129                     if (allDrives[i].iIsRemovable)
       
  1130                     {
       
  1131                         return false;
       
  1132                     }
       
  1133                     if (allDrives[i].iIsExternallyMountable)
       
  1134                     {
       
  1135                         return false;
       
  1136                     }
       
  1137                     return true;
       
  1138                 }
       
  1139             }
       
  1140         }
       
  1141         return false;
       
  1142     }
       
  1143 
       
  1144     private Credentials selectCredentials(String selectedJarHash, Vector allAuthCredentials, Vector validatedChainIndexes)
       
  1145     {
       
  1146         Credentials selectedCredentials = null;
       
  1147         if (selectedJarHash != null)
       
  1148         {
       
  1149             for (int i=0; i<allAuthCredentials.size(); i++)
       
  1150             {
       
  1151                 Credentials authCredentials =
       
  1152                     (Credentials)allAuthCredentials.elementAt(i);
       
  1153                 if (selectedJarHash.equalsIgnoreCase(authCredentials.jarHashValue))
       
  1154                 {
       
  1155                     // the first one wins
       
  1156                     if (selectedCredentials == null)
       
  1157                     {
       
  1158                         selectedCredentials = new Credentials(
       
  1159                             authCredentials.getProtectionDomainName(),
       
  1160                             authCredentials.getProtectionDomainCategory(),
       
  1161                             authCredentials.jarHashValue,
       
  1162                             authCredentials.rootHashValue,
       
  1163                             -1,
       
  1164                             null);
       
  1165                     }
       
  1166                     // collect the validated chain indexes
       
  1167                     validatedChainIndexes.addElement(
       
  1168                         new Integer(authCredentials.validatedChainIndex));
       
  1169                 }
       
  1170             }
       
  1171         }
       
  1172         return selectedCredentials;
       
  1173     }
       
  1174 
       
  1175     private void writeAuthenticationStorageData(StorageSession storageSession, Uid uid, AuthenticationStorageData data, boolean isUpdate)
       
  1176     {
       
  1177         if (storageSession == null)
       
  1178         {
       
  1179             return;
       
  1180         }
       
  1181         SecurityStorage storage = new SecurityStorage(storageSession);
       
  1182         storage.writeAuthenticationStorageData(uid, data, isUpdate);
       
  1183         Logger.logAuthenticationData(data);
       
  1184     }
       
  1185 
       
  1186     private native Credentials[] _validateChainsAndSignatures(AuthenticationInfo[] authInfo);
       
  1187     private native String _computeHash(String appJARPath);
       
  1188     private native String _drmDecryptAndComputeHash(String appJARPath);
       
  1189     private native Certificate _parseCertificate(String rawCert);
       
  1190     private native Certificate _getRootCertificate(String certHash);
       
  1191 }