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