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}, {@link org.apache.http.client.HttpClient}, 56and {@link android.net.http.AndroidHttpClient} without needing to set a custom 57{@link javax.net.ssl.TrustManager} or create an {@link 58android.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> 64class. You can verify that the security provider is up-to-date (and update it, 65if necessary) by calling 66that 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>) 68method.</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> 72does 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> 92method behaves similarly, except that instead of 93throwing exceptions, it calls the appropriate callback method to indicate 94success 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> 97needs to install a new {@link java.security.Provider Provider}, this can take 98anywhere from 30-50 milliseconds (on more recent devices) to 350 ms (on older 99devices). If the security provider is already up-to-date, the method takes a 100negligible 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> 123is unable to install an updated {@link java.security.Provider Provider}, 124your device's security provider might be vulnerable to known exploits. Your app 125should behave as if all HTTP communication is unencrypted.</p> 126 127<p>Once the {@link java.security.Provider Provider} is updated, all calls to 128security APIs (including SSL APIs) are routed through it. 129(However, this does not apply to {@link android.net.SSLCertificateSocketFactory 130android.net.SSLCertificateSocketFactory}, which remains vulnerable to such 131exploits 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 137method <a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.html##installIfNeeded(android.content.Context)">{@code installIfNeeded()}</a>. 138This is appropriate if user experience won't be affected by the thread blocking 139while 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 142adapter runs in the background, it's okay if the thread blocks while waiting 143for 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 145update the security provider. If the method returns normally, the sync adapter 146knows the security provider is up-to-date. If the method throws an exception, 147the sync adapter can take appropriate action (such as prompting the user to 148update Google Play services).</p> 149 150<pre>/** 151 * Sample sync adapter using {@link ProviderInstaller}. 152 */ 153public 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 @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 193older devices). If you're doing the update on a thread that directly affects 194user experience, such as the UI thread, you don't want to make a synchronous 195call to update the provider, since that can result in the app or device 196freezing until the operation finishes. Instead, you should use the asynchronous 197method 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>. 199That 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 202activity 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> 203to update the provider, and designates itself as the listener to receive success 204or failure notifications. If the security provider is up-to-date or is 205successfully updated, the activity's 206<a href="{@docRoot}reference/com/google/android/gms/security/ProviderInstaller.ProviderInstallListener.html#onProviderInstalled()">{@code onProviderInstalled()}</a> 207method is called, and the activity knows communication is secure. If the 208provider 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> 210method is called, and the activity can take appropriate action (such as 211prompting the user to update Google Play services).</p> 212 213<pre>/** 214 * Sample activity using {@link ProviderInstaller}. 215 */ 216public 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 @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 @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 @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 @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 @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 @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