Home | History | Annotate | Download | only in articles
      1 page.title=Updating Your Security Provider to Protect Against SSL Exploits
      2 page.tags="network","certificates"
      3 
      4 page.article=true
      5 @jd:body
      6 
      7 <div id="tb-wrapper">
      8 <div id="tb">
      9 <h2>In this document</h2>
     10 <ol class="nolist">
     11   <li><a href="#patching">Patching the Security Provider with
     12       ProviderInstaller</a></li>
     13   <li><a href="#example_sync">Patching Synchronously</a></li>
     14   <li><a href="#example_async">Patching Asynchronously</a></li>
     15 
     16 </ol>
     17 
     18 
     19 <h2>See also</h2>
     20 <ul>
     21   <li><a href="{@docRoot}google/play-services/">Google Play Services</a></li>
     22   <li><a href="https://www.openssl.org/news/secadv_20140605.txt">OpenSSL
     23    Security Advisory [05 Jun 2014]: SSL/TLS MITM vulnerability
     24    (CVE-2014-0224)</a></li>
     25   <li><a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0224">
     26     Vulnerability Summary for CVE-2014-0224</a></li>
     27 </ul>
     28 </div>
     29 </div>
     30 
     31 
     32 <p> Android relies on a security {@link java.security.Provider Provider} to
     33 provide secure network communications. However, from time to time,
     34 vulnerabilities are found in the default security provider. To protect against
     35 these vulnerabilities, <a href="{@docRoot}google/play-services/">Google Play
     36 services</a> provides a way to automatically update a device's security provider
     37 to protect against known exploits. By calling Google Play services methods, your
     38 app can ensure that it's running on a device that has the latest updates to
     39 protect against known exploits.</p>
     40 
     41 <p>For example, a vulnerability was discovered in OpenSSL
     42 (<a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0224">CVE-2014-0224</a>)
     43 that can leave apps open to a "man-in-the-middle" attack that decrypts
     44 secure traffic without either side knowing. With Google Play services version
     45 5.0, a fix is available, but apps must ensure that this fix is installed. By
     46 using the Google Play services methods, your app can ensure that it's running
     47 on a device that's secured against that attack.</p>
     48 
     49 <p class="caution"><strong>Caution: </strong>Updating a device's security {@link
     50 java.security.Provider Provider} does <em>not</em> update {@link
     51 android.net.SSLCertificateSocketFactory
     52 android.net.SSLCertificateSocketFactory}. Rather than using this class, we
     53 encourage app developers to use high-level methods for interacting with
     54 cryptography. Most apps can use APIs like {@link
     55 javax.net.ssl.HttpsURLConnection}, {@link org.apache.http.client.HttpClient},
     56 and {@link android.net.http.AndroidHttpClient} without needing to set a custom
     57 {@link javax.net.ssl.TrustManager} or create an {@link
     58 android.net.SSLCertificateSocketFactory}.</p>
     59 
     60 <h2 id="patching">Patching the Security Provider with ProviderInstaller</h2>
     61 
     62 <p>To update a device's security provider, use the
     63 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
     64 class. You can verify that the security provider is up-to-date (and update it,
     65 if necessary) by calling
     66 that class's <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>
     67 (or <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>)
     68 method.</p>
     69 
     70 <p>When you call <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>, the
     71 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
     72 does the following:</p>
     73 
     74 <ul>
     75   <li>If the device's {@link java.security.Provider Provider} is successfully
     76     updated (or is already up-to-date), the method returns normally.</li>
     77   <li>If the device's Google Play services library is out of date, the method
     78     throws
     79     <a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesRepairableException.html">{@code GooglePlayServicesRepairableException}</a>.
     80     The app can then catch this exception and show
     81     the user an appropriate dialog box to update Google Play services.</li>
     82     <li>If a non-recoverable error occurs, the method throws
     83     <a href="{@docRoot}reference/com/google/android/gms/common/GooglePlayServicesNotAvailableException.html">{@code GooglePlayServicesNotAvailableException}</a>
     84     to indicate that it is unable to update the {@link java.security.Provider
     85     Provider}. The app can then catch the exception and choose an appropriate
     86     course of action, such as displaying the standard
     87     <a href="{@docRoot}reference/com/google/android/gms/common/SupportErrorDialogFragment.html">fix-it flow diagram</a>.</li>
     88 </ul>
     89 
     90 <p>The
     91 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>
     92 method behaves similarly, except that instead of
     93 throwing exceptions, it calls the appropriate callback method to indicate
     94 success or failure.</p>
     95 
     96 <p>If <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>
     97 needs to install a new {@link java.security.Provider Provider}, this can take
     98 anywhere from 30-50 milliseconds (on more recent devices) to 350 ms (on older
     99 devices). If the security provider is already up-to-date, the method takes a
    100 negligible amount of time. To avoid affecting user experience:</p>
    101 
    102 <ul>
    103   <li>Call
    104   <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>
    105   from background networking threads immediately when the threads are loaded,
    106   instead of waiting for the thread to try to use the network. (There's no harm
    107   in calling the method multiple times, since it returns immediately if the
    108   security provider doesn't need updating.)</li>
    109 
    110   <li>If user experience will be affected by the thread blocking--for example,
    111   if the call is from an activity in the UI thread--call the asynchronous
    112   version of the method,
    113   <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>.
    114   (Of course, if you do this, you need to wait for the operation to finish
    115   before you attempt any secure communications. The
    116   <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
    117   calls your listener's <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstalled()">{@code onProviderInstalled()}</a>
    118   method to signal success.)</li>
    119 </ul>
    120 
    121 <p class="warning"><strong>Warning:</strong> If the
    122 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html">{@code ProviderInstaller}</a>
    123 is unable to install an updated {@link java.security.Provider Provider},
    124 your device's security provider might be vulnerable  to known exploits. Your app
    125 should behave as if all HTTP communication is unencrypted.</p>
    126 
    127 <p>Once the {@link java.security.Provider Provider} is updated, all calls to
    128 security APIs (including SSL APIs) are routed through it.
    129 (However, this does not apply to  {@link android.net.SSLCertificateSocketFactory
    130 android.net.SSLCertificateSocketFactory}, which remains vulnerable to such
    131 exploits as
    132 <a href="http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-2014-0224">CVE-2014-0224</a>.)</p>
    133 
    134 <h2 id="example_sync">Patching Synchronously</h2>
    135 
    136 <p>The simplest way to patch the security provider is to call the synchronous
    137 method <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>.
    138 This is appropriate if user experience won't be affected by the thread blocking
    139 while it waits for the operation to finish.</p>
    140 
    141 <p>For example, here's an implementation of a <a href="{@docRoot}training/sync-adapters">sync adapter</a> that updates the security provider. Since a sync
    142 adapter runs in the background, it's okay if the thread blocks while waiting
    143 for the security provider to be updated. The sync adapter calls
    144 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a> to
    145 update the security provider. If the method returns normally, the sync adapter
    146 knows the security provider is up-to-date. If the method throws an exception,
    147 the sync adapter can take appropriate action (such as prompting the user to
    148 update Google Play services).</p>
    149 
    150 <pre>/**
    151  * Sample sync adapter using {&#64;link ProviderInstaller}.
    152  */
    153 public class SyncAdapter extends AbstractThreadedSyncAdapter {
    154 
    155   ...
    156 
    157   // This is called each time a sync is attempted; this is okay, since the
    158   // overhead is negligible if the security provider is up-to-date.
    159   &#64;Override
    160   public void onPerformSync(Account account, Bundle extras, String authority,
    161       ContentProviderClient provider, SyncResult syncResult) {
    162     try {
    163       ProviderInstaller.installIfNeeded(getContext());
    164     } catch (GooglePlayServicesRepairableException e) {
    165 
    166       // Indicates that Google Play services is out of date, disabled, etc.
    167 
    168       // Prompt the user to install/update/enable Google Play services.
    169       GooglePlayServicesUtil.showErrorNotification(
    170           e.getConnectionStatusCode(), getContext());
    171 
    172       // Notify the SyncManager that a soft error occurred.
    173       syncResult.stats.numIOExceptions++;
    174       return;
    175 
    176     } catch (GooglePlayServicesNotAvailableException e) {
    177       // Indicates a non-recoverable error; the ProviderInstaller is not able
    178       // to install an up-to-date Provider.
    179 
    180       // Notify the SyncManager that a hard error occurred.
    181       syncResult.stats.numAuthExceptions++;
    182       return;
    183     }
    184 
    185     // If this is reached, you know that the provider was already up-to-date,
    186     // or was successfully updated.
    187   }
    188 }</pre>
    189 
    190 <h2 id="example_async">Patching Asynchronously</h2>
    191 
    192 <p>Updating the security provider can take as much as 350 milliseconds (on
    193 older devices). If you're doing the update on a thread that directly affects
    194 user experience, such as the UI thread, you don't want to make a synchronous
    195 call to update the provider, since that can result in the app or device
    196 freezing until the operation finishes. Instead, you should use the asynchronous
    197 method
    198 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>.
    199 That method indicates its success or failure by calling callbacks.</p>
    200 
    201 <p>For example, here's some code that updates the security provider in an
    202 activity in the UI thread. The activity calls <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html#installIfNeededAsync(android.content.Context, com.google.android.gms.security.ProviderInstaller.ProviderInstallListener)">{@code installIfNeededAsync()}</a>
    203 to update the provider, and designates itself as the listener to receive success
    204 or failure notifications. If the security provider is up-to-date or is
    205 successfully updated, the activity's
    206 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstalled()">{@code onProviderInstalled()}</a>
    207 method is called, and the activity knows communication is secure. If the
    208 provider cannot be updated, the activity's
    209 <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstallFailed(int, android.content.Intent)">{@code onProviderInstallFailed()}</a>
    210 method is called, and the activity can take appropriate action (such as
    211 prompting the user to update Google Play services).</p>
    212 
    213 <pre>/**
    214  * Sample activity using {&#64;link ProviderInstaller}.
    215  */
    216 public class MainActivity extends Activity
    217     implements ProviderInstaller.ProviderInstallListener {
    218 
    219   private static final int ERROR_DIALOG_REQUEST_CODE = 1;
    220 
    221   private boolean mRetryProviderInstall;
    222 
    223   //Update the security provider when the activity is created.
    224   &#64;Override
    225   protected void onCreate(Bundle savedInstanceState) {
    226     super.onCreate(savedInstanceState);
    227     ProviderInstaller.installIfNeededAsync(this, this);
    228   }
    229 
    230   /**
    231    * This method is only called if the provider is successfully updated
    232    * (or is already up-to-date).
    233    */
    234   &#64;Override
    235   protected void onProviderInstalled() {
    236     // Provider is up-to-date, app can make secure network calls.
    237   }
    238 
    239   /**
    240    * This method is called if updating fails; the error code indicates
    241    * whether the error is recoverable.
    242    */
    243   &#64;Override
    244   protected void onProviderInstallFailed(int errorCode, Intent recoveryIntent) {
    245     if (GooglePlayServicesUtil.isUserRecoverableError(errorCode)) {
    246       // Recoverable error. Show a dialog prompting the user to
    247       // install/update/enable Google Play services.
    248       GooglePlayServicesUtil.showErrorDialogFragment(
    249           errorCode,
    250           this,
    251           ERROR_DIALOG_REQUEST_CODE,
    252           new DialogInterface.OnCancelListener() {
    253             &#64;Override
    254             public void onCancel(DialogInterface dialog) {
    255               // The user chose not to take the recovery action
    256               onProviderInstallerNotAvailable();
    257             }
    258           });
    259     } else {
    260       // Google Play services is not available.
    261       onProviderInstallerNotAvailable();
    262     }
    263   }
    264 
    265   &#64;Override
    266   protected void onActivityResult(int requestCode, int resultCode,
    267       Intent data) {
    268     super.onActivityResult(requestCode, resultCode, data);
    269     if (requestCode == ERROR_DIALOG_REQUEST_CODE) {
    270       // Adding a fragment via GooglePlayServicesUtil.showErrorDialogFragment
    271       // before the instance state is restored throws an error. So instead,
    272       // set a flag here, which will cause the fragment to delay until
    273       // onPostResume.
    274       mRetryProviderInstall = true;
    275     }
    276   }
    277 
    278   /**
    279    * On resume, check to see if we flagged that we need to reinstall the
    280    * provider.
    281    */
    282   &#64;Override
    283   protected void onPostResume() {
    284     super.onPostResult();
    285     if (mRetryProviderInstall) {
    286       // We can now safely retry installation.
    287       ProviderInstall.installIfNeededAsync(this, this);
    288     }
    289     mRetryProviderInstall = false;
    290   }
    291 
    292   private void onProviderInstallerNotAvailable() {
    293     // This is reached if the provider cannot be updated for some reason.
    294     // App should consider all HTTP communication to be vulnerable, and take
    295     // appropriate action.
    296   }
    297 }
    298 </pre>
    299