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