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