Log when an IOException when reading the public key, content or metadata

file for CT signature verification

Flag: com.android.net.ct.flags.certificate_transparency_service
Bug: 378626065
Test: atest NetworkSecurityUnitTests
Change-Id: I2df5933f4cb39b82620f8bdd391ca800dfcf8ede
This commit is contained in:
Bessie Jiang 2025-03-27 18:34:39 +00:00
commit 0bf58dac22
6 changed files with 60 additions and 12 deletions

View file

@ -150,14 +150,7 @@ class CertificateTransparencyDownloader extends BroadcastReceiver {
return;
}
LogListUpdateStatus updateStatus;
try {
updateStatus = mSignatureVerifier.setPublicKeyFrom(publicKeyUri);
} catch (IOException e) {
Log.e(TAG, "Error setting the public Key", e);
return;
}
LogListUpdateStatus updateStatus = mSignatureVerifier.setPublicKeyFrom(publicKeyUri);
if (!updateStatus.isPublicKeySet()) {
mLogger.logCTLogListUpdateStateChangedEvent(updateStatus);
return;

View file

@ -43,6 +43,7 @@ public interface CertificateTransparencyLogger {
SIGNATURE_NOT_FOUND,
SIGNATURE_VERIFICATION_FAILED,
SUCCESS,
UNABLE_TO_READ_FILE,
VERSION_ALREADY_EXISTS
}
}

View file

@ -29,6 +29,7 @@ import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFIC
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_SIGNATURE_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_SIGNATURE_VERIFICATION;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_TOO_MANY_REDIRECTS;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_UNABLE_TO_READ_FILE;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_UNKNOWN;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_VERSION_ALREADY_EXISTS;
import static com.android.server.net.ct.CertificateTransparencyStatsLog.CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__PENDING_WAITING_FOR_WIFI;
@ -149,6 +150,8 @@ class CertificateTransparencyLoggerImpl implements CertificateTransparencyLogger
return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_SIGNATURE_VERIFICATION;
case SUCCESS:
return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__SUCCESS;
case UNABLE_TO_READ_FILE:
return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_UNABLE_TO_READ_FILE;
case VERSION_ALREADY_EXISTS:
return CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_STATE_CHANGED__UPDATE_STATUS__FAILURE_VERSION_ALREADY_EXISTS;
case UNKNOWN_STATE:

View file

@ -22,6 +22,7 @@ import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListU
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_VERIFICATION_FAILED;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SUCCESS;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.UNABLE_TO_READ_FILE;
import com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState;
@ -45,7 +46,9 @@ public abstract class LogListUpdateStatus {
boolean isPublicKeySet() {
// Check that none of the public key setting failures have been set as the state
return state() != PUBLIC_KEY_INVALID && state() != PUBLIC_KEY_NOT_ALLOWED;
return state() != PUBLIC_KEY_INVALID
&& state() != PUBLIC_KEY_NOT_ALLOWED
&& state() != UNABLE_TO_READ_FILE;
}
boolean isSignatureVerified() {
@ -53,7 +56,8 @@ public abstract class LogListUpdateStatus {
return state() != PUBLIC_KEY_NOT_FOUND
&& state() != SIGNATURE_INVALID
&& state() != SIGNATURE_NOT_FOUND
&& state() != SIGNATURE_VERIFICATION_FAILED;
&& state() != SIGNATURE_VERIFICATION_FAILED
&& state() != UNABLE_TO_READ_FILE;
}
boolean hasSignature() {

View file

@ -21,6 +21,7 @@ import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListU
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_INVALID;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_NOT_FOUND;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.SIGNATURE_VERIFICATION_FAILED;
import static com.android.server.net.ct.CertificateTransparencyLogger.CTLogListUpdateState.UNABLE_TO_READ_FILE;
import android.annotation.NonNull;
import android.annotation.RequiresApi;
@ -86,9 +87,12 @@ public class SignatureVerifier {
mPublicKey = Optional.empty();
}
LogListUpdateStatus setPublicKeyFrom(Uri file) throws IOException {
LogListUpdateStatus setPublicKeyFrom(Uri file) {
try (InputStream fileStream = mContext.getContentResolver().openInputStream(file)) {
return setPublicKey(new String(fileStream.readAllBytes()));
} catch (IOException e) {
Log.e(TAG, "Could not read the public key file", e);
return LogListUpdateStatus.builder().setState(UNABLE_TO_READ_FILE).build();
}
}
@ -153,7 +157,11 @@ public class SignatureVerifier {
Log.e(TAG, "Key invalid for log list verification", e);
statusBuilder.setState(SIGNATURE_INVALID);
return statusBuilder.build();
} catch (IOException | GeneralSecurityException e) {
} catch (IOException e) {
Log.e(TAG, "Could not read log list file", e);
statusBuilder.setState(UNABLE_TO_READ_FILE);
return statusBuilder.build();
} catch (GeneralSecurityException e) {
Log.e(TAG, "Could not verify new log list", e);
statusBuilder.setState(SIGNATURE_VERIFICATION_FAILED);
return statusBuilder.build();

View file

@ -182,6 +182,24 @@ public class CertificateTransparencyDownloaderTest {
assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse();
}
@Test
public void testDownloader_publicKeyDownloadSuccess_publicKeyFileNotRead_logsFailure()
throws Exception {
mCertificateTransparencyDownloader.startPublicKeyDownload();
File publicKeyFile = writePublicKeyToFile(mPublicKey);
// Set the public key file to not be readable to simulate an IOException being thrown
publicKeyFile.setReadable(false);
mCertificateTransparencyDownloader.onReceive(
mContext, makePublicKeyDownloadCompleteIntent(publicKeyFile));
verify(mLogger, times(1))
.logCTLogListUpdateStateChangedEvent(
LogListUpdateStatus.builder()
.setState(CTLogListUpdateState.UNABLE_TO_READ_FILE)
.build());
}
@Test
public void
testDownloader_publicKeyDownloadSuccess_publicKeyNotAllowed_logsFailure()
@ -400,6 +418,27 @@ public class CertificateTransparencyDownloaderTest {
.isEqualTo(CTLogListUpdateState.PUBLIC_KEY_NOT_FOUND);
}
@Test
public void testDownloader_contentDownloadSuccess_signatureFileNotRead_logsSingleFailure()
throws Exception {
File logListFile = makeLogListFile("456");
File metadataFile = sign(logListFile);
mSignatureVerifier.setPublicKey(mPublicKey);
mCertificateTransparencyDownloader.startMetadataDownload();
mCertificateTransparencyDownloader.onReceive(
mContext, makeMetadataDownloadCompleteIntent(mCompatVersion, metadataFile));
// Set the log list file to not be readable to simulate an IOException being thrown
logListFile.setReadable(false);
mCertificateTransparencyDownloader.onReceive(
mContext, makeContentDownloadCompleteIntent(mCompatVersion, logListFile));
verify(mLogger, times(1))
.logCTLogListUpdateStateChangedEvent(mUpdateStatusCaptor.capture());
assertThat(mUpdateStatusCaptor.getValue().state())
.isEqualTo(CTLogListUpdateState.UNABLE_TO_READ_FILE);
}
@Test
public void testDownloader_contentDownloadSuccess_wrongSignatureAlgo_logsSingleFailure()
throws Exception {