1page.title=Updating Your Security Provider to Protect Against SSL Exploits
2page.tags="network","certificates"
3
4page.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
33provide secure network communications. However, from time to time,
34vulnerabilities are found in the default security provider. To protect against
35these vulnerabilities, <a href="{@docRoot}google/play-services/">Google Play
36services</a> provides a way to automatically update a device's security provider
37to protect against known exploits. By calling Google Play services methods, your
38app can ensure that it's running on a device that has the latest updates to
39protect 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>)
43that can leave apps open to a "man-in-the-middle" attack that decrypts
44secure traffic without either side knowing. With Google Play services version
455.0, a fix is available, but apps must ensure that this fix is installed. By
46using the Google Play services methods, your app can ensure that it's running
47on a device that's secured against that attack.</p>
48
49<p class="caution"><strong>Caution: </strong>Updating a device's security {@link
50java.security.Provider Provider} does <em>not</em> update {@link
51android.net.SSLCertificateSocketFactory
52android.net.SSLCertificateSocketFactory}. Rather than using this class, we
53encourage app developers to use high-level methods for interacting with
54cryptography. Most apps can use APIs like {@link
55javax.net.ssl.HttpsURLConnection} without needing to set a custom
56{@link javax.net.ssl.TrustManager} or create an {@link
57android.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>
63class. You can verify that the security provider is up-to-date (and update it,
64if necessary) by calling
65that 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>)
67method.</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>
71does 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>
91method behaves similarly, except that instead of
92throwing exceptions, it calls the appropriate callback method to indicate
93success 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>
96needs to install a new {@link java.security.Provider Provider}, this can take
97anywhere from 30-50 milliseconds (on more recent devices) to 350 ms (on older
98devices). If the security provider is already up-to-date, the method takes a
99negligible 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>
122is unable to install an updated {@link java.security.Provider Provider},
123your device's security provider might be vulnerable  to known exploits. Your app
124should behave as if all HTTP communication is unencrypted.</p>
125
126<p>Once the {@link java.security.Provider Provider} is updated, all calls to
127security APIs (including SSL APIs) are routed through it.
128(However, this does not apply to  {@link android.net.SSLCertificateSocketFactory
129android.net.SSLCertificateSocketFactory}, which remains vulnerable to such
130exploits 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
136method <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>.
137This is appropriate if user experience won't be affected by the thread blocking
138while 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
141adapter runs in the background, it's okay if the thread blocks while waiting
142for 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
144update the security provider. If the method returns normally, the sync adapter
145knows the security provider is up-to-date. If the method throws an exception,
146the sync adapter can take appropriate action (such as prompting the user to
147update Google Play services).</p>
148
149<pre>/**
150 * Sample sync adapter using {&#64;link ProviderInstaller}.
151 */
152public 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
192older devices). If you're doing the update on a thread that directly affects
193user experience, such as the UI thread, you don't want to make a synchronous
194call to update the provider, since that can result in the app or device
195freezing until the operation finishes. Instead, you should use the asynchronous
196method
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>.
198That 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
201activity 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>
202to update the provider, and designates itself as the listener to receive success
203or failure notifications. If the security provider is up-to-date or is
204successfully updated, the activity's
205<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstalled()">{@code onProviderInstalled()}</a>
206method is called, and the activity knows communication is secure. If the
207provider 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>
209method is called, and the activity can take appropriate action (such as
210prompting the user to update Google Play services).</p>
211
212<pre>/**
213 * Sample activity using {&#64;link ProviderInstaller}.
214 */
215public 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