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 {@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 @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 {@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 @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 @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 @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 @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 @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 @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