Add a consecutive failure count to the CT DataStore
We plan on only logging failure metrics after 10 consecutive failures, so we need some way of storing it. Fixes: 384473786 Test: atest NetworkSecurityUnitTests Change-Id: Ib316309864c536893d08be2dc59b8a70965ebde6
This commit is contained in:
parent
8a6d83dfe0
commit
6ae4c31703
3 changed files with 219 additions and 4 deletions
|
|
@ -13,6 +13,7 @@
|
|||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.net.ct;
|
||||
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
|
@ -201,9 +202,8 @@ class CertificateTransparencyDownloader extends BroadcastReceiver {
|
|||
|
||||
String version = null;
|
||||
try (InputStream inputStream = mContext.getContentResolver().openInputStream(contentUri)) {
|
||||
version =
|
||||
new JSONObject(new String(inputStream.readAllBytes(), UTF_8))
|
||||
.getString("version");
|
||||
version = new JSONObject(new String(inputStream.readAllBytes(), UTF_8))
|
||||
.getString("version");
|
||||
} catch (JSONException | IOException e) {
|
||||
Log.e(TAG, "Could not extract version from log list", e);
|
||||
return;
|
||||
|
|
@ -219,13 +219,44 @@ class CertificateTransparencyDownloader extends BroadcastReceiver {
|
|||
if (success) {
|
||||
// Update information about the stored version on successful install.
|
||||
mDataStore.setProperty(Config.VERSION, version);
|
||||
|
||||
// Reset the number of consecutive log list failure updates back to zero.
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* value= */ 0L);
|
||||
mDataStore.store();
|
||||
} else {
|
||||
if (updateFailureCount()) {
|
||||
// TODO(378626065): Report FAILURE_VERSION_ALREADY_EXISTS failure via statsd.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void handleDownloadFailed(DownloadStatus status) {
|
||||
Log.e(TAG, "Download failed with " + status);
|
||||
// TODO(378626065): Report failure via statsd.
|
||||
|
||||
if (updateFailureCount()) {
|
||||
// TODO(378626065): Report download failure via statsd.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the data store with the current number of consecutive log list update failures.
|
||||
*
|
||||
* @return whether the failure count exceeds the threshold and should be logged.
|
||||
*/
|
||||
private boolean updateFailureCount() {
|
||||
long failure_count = mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L);
|
||||
long new_failure_count = failure_count + 1L;
|
||||
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, new_failure_count);
|
||||
mDataStore.store();
|
||||
|
||||
boolean shouldReport = new_failure_count >= Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD;
|
||||
if (shouldReport) {
|
||||
Log.e(TAG,
|
||||
"Log list update failure count exceeds threshold: " + new_failure_count);
|
||||
}
|
||||
return shouldReport;
|
||||
}
|
||||
|
||||
private long download(String url) {
|
||||
|
|
|
|||
|
|
@ -54,10 +54,14 @@ final class Config {
|
|||
static final String METADATA_DOWNLOAD_ID = "metadata_download_id";
|
||||
static final String PUBLIC_KEY_URL = "public_key_url";
|
||||
static final String PUBLIC_KEY_DOWNLOAD_ID = "public_key_download_id";
|
||||
static final String LOG_LIST_UPDATE_FAILURE_COUNT = "log_list_update_failure_count";
|
||||
|
||||
// URLs
|
||||
static final String URL_PREFIX = "https://www.gstatic.com/android/certificate_transparency/";
|
||||
static final String URL_LOG_LIST = URL_PREFIX + "log_list.json";
|
||||
static final String URL_SIGNATURE = URL_PREFIX + "log_list.sig";
|
||||
static final String URL_PUBLIC_KEY = URL_PREFIX + "log_list.pub";
|
||||
|
||||
// Threshold amounts
|
||||
static final long LOG_LIST_UPDATE_FAILURE_THRESHOLD = 10L;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -185,6 +185,47 @@ public class CertificateTransparencyDownloaderTest {
|
|||
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_publicKeyDownloadFail_failureThresholdExceeded_logsFailure()
|
||||
throws Exception {
|
||||
long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
|
||||
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
|
||||
setFailedDownload(
|
||||
publicKeyId, // Failure cases where we give up on the download.
|
||||
DownloadManager.ERROR_INSUFFICIENT_SPACE,
|
||||
DownloadManager.ERROR_HTTP_DATA_ERROR);
|
||||
Intent downloadCompleteIntent = makeDownloadCompleteIntent(publicKeyId);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
|
||||
// TODO(378626065): Verify logged failure via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_publicKeyDownloadFail_failureThresholdNotMet_doesNotLog()
|
||||
throws Exception {
|
||||
long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload();
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
|
||||
setFailedDownload(
|
||||
publicKeyId, // Failure cases where we give up on the download.
|
||||
DownloadManager.ERROR_INSUFFICIENT_SPACE,
|
||||
DownloadManager.ERROR_HTTP_DATA_ERROR);
|
||||
Intent downloadCompleteIntent = makeDownloadCompleteIntent(publicKeyId);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(1);
|
||||
// TODO(378626065): Verify no failure logged via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_metadataDownloadSuccess_startContentDownload() {
|
||||
long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
|
||||
|
|
@ -214,6 +255,49 @@ public class CertificateTransparencyDownloaderTest {
|
|||
assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_metadataDownloadFail_failureThresholdExceeded_logsFailure()
|
||||
throws Exception {
|
||||
long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
|
||||
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
|
||||
setFailedDownload(
|
||||
metadataId,
|
||||
// Failure cases where we give up on the download.
|
||||
DownloadManager.ERROR_INSUFFICIENT_SPACE,
|
||||
DownloadManager.ERROR_HTTP_DATA_ERROR);
|
||||
Intent downloadCompleteIntent = makeDownloadCompleteIntent(metadataId);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
|
||||
// TODO(378626065): Verify logged failure via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_metadataDownloadFail_failureThresholdNotMet_doesNotLog()
|
||||
throws Exception {
|
||||
long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
|
||||
setFailedDownload(
|
||||
metadataId,
|
||||
// Failure cases where we give up on the download.
|
||||
DownloadManager.ERROR_INSUFFICIENT_SPACE,
|
||||
DownloadManager.ERROR_HTTP_DATA_ERROR);
|
||||
Intent downloadCompleteIntent = makeDownloadCompleteIntent(metadataId);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(1);
|
||||
// TODO(378626065): Verify no failure logged via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_contentDownloadSuccess_installSuccess_updateDataStore()
|
||||
throws Exception {
|
||||
|
|
@ -253,6 +337,49 @@ public class CertificateTransparencyDownloaderTest {
|
|||
assertNoVersionIsInstalled();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_contentDownloadFail_failureThresholdExceeded_logsFailure()
|
||||
throws Exception {
|
||||
long contentId = mCertificateTransparencyDownloader.startContentDownload();
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
|
||||
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
|
||||
setFailedDownload(
|
||||
contentId,
|
||||
// Failure cases where we give up on the download.
|
||||
DownloadManager.ERROR_INSUFFICIENT_SPACE,
|
||||
DownloadManager.ERROR_HTTP_DATA_ERROR);
|
||||
Intent downloadCompleteIntent = makeDownloadCompleteIntent(contentId);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
|
||||
// TODO(378626065): Verify logged failure via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_contentDownloadFail_failureThresholdNotMet_doesNotLog()
|
||||
throws Exception {
|
||||
long contentId = mCertificateTransparencyDownloader.startContentDownload();
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
|
||||
setFailedDownload(
|
||||
contentId,
|
||||
// Failure cases where we give up on the download.
|
||||
DownloadManager.ERROR_INSUFFICIENT_SPACE,
|
||||
DownloadManager.ERROR_HTTP_DATA_ERROR);
|
||||
Intent downloadCompleteIntent = makeDownloadCompleteIntent(contentId);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent);
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(1);
|
||||
// TODO(378626065): Verify no failure logged via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_contentDownloadSuccess_installFail_doNotUpdateDataStore()
|
||||
throws Exception {
|
||||
|
|
@ -274,6 +401,59 @@ public class CertificateTransparencyDownloaderTest {
|
|||
assertNoVersionIsInstalled();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
testDownloader_contentDownloadSuccess_installFail_failureThresholdExceeded_logsFailure()
|
||||
throws Exception {
|
||||
File logListFile = makeLogListFile("456");
|
||||
File metadataFile = sign(logListFile);
|
||||
mSignatureVerifier.setPublicKey(mPublicKey);
|
||||
long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
|
||||
setSuccessfulDownload(metadataId, metadataFile);
|
||||
long contentId = mCertificateTransparencyDownloader.startContentDownload();
|
||||
setSuccessfulDownload(contentId, logListFile);
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT,
|
||||
Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
|
||||
when(mCertificateTransparencyInstaller.install(
|
||||
eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
|
||||
.thenReturn(false);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(
|
||||
mContext, makeDownloadCompleteIntent(contentId));
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
|
||||
// TODO(378626065): Verify logged failure via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
testDownloader_contentDownloadSuccess_installFail_failureThresholdNotMet_doesNotLog()
|
||||
throws Exception {
|
||||
File logListFile = makeLogListFile("456");
|
||||
File metadataFile = sign(logListFile);
|
||||
mSignatureVerifier.setPublicKey(mPublicKey);
|
||||
long metadataId = mCertificateTransparencyDownloader.startMetadataDownload();
|
||||
setSuccessfulDownload(metadataId, metadataFile);
|
||||
long contentId = mCertificateTransparencyDownloader.startContentDownload();
|
||||
setSuccessfulDownload(contentId, logListFile);
|
||||
// Set the failure count to just below the threshold
|
||||
mDataStore.setPropertyLong(Config.LOG_LIST_UPDATE_FAILURE_COUNT, 0);
|
||||
when(mCertificateTransparencyInstaller.install(
|
||||
eq(Config.COMPATIBILITY_VERSION), any(), anyString()))
|
||||
.thenReturn(false);
|
||||
|
||||
mCertificateTransparencyDownloader.onReceive(
|
||||
mContext, makeDownloadCompleteIntent(contentId));
|
||||
|
||||
assertThat(mDataStore.getPropertyLong(
|
||||
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0L))
|
||||
.isEqualTo(1);
|
||||
// TODO(378626065): Verify no failure logged via statsd.
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDownloader_contentDownloadSuccess_verificationFail_doNotInstall()
|
||||
throws Exception {
|
||||
|
|
|
|||
Loading…
Reference in a new issue