Add support for Base64 encoded signature
To simplify debugging, we are planning to publish the log list signature
as a Base64 encoded string.
It might take a while for the changes to the signature publishing pipeline
to reach prod, and we do not know exactly when that will happen. To avoid
accidental crashes, I added a fallback path to the verifier code that
reverts to use the signature as raw (not Base64 encoded) bytes. I will
remove the fallback path once the signature publishing changes are
finalized.
Bug: 374719543
Test: atest NetworkSecurityUnitTests
Change-Id: Ia785b554b840940dc81b47ac9bc2121c0b410ab0
diff --git a/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java b/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java
index 96488fc..67ef63f 100644
--- a/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java
+++ b/networksecurity/service/src/com/android/server/net/ct/SignatureVerifier.java
@@ -21,6 +21,7 @@
import android.content.Context;
import android.net.Uri;
import android.os.Build;
+import android.util.Log;
import androidx.annotation.VisibleForTesting;
@@ -62,10 +63,15 @@
}
void setPublicKey(String publicKey) throws GeneralSecurityException {
+ byte[] decodedPublicKey = null;
+ try {
+ decodedPublicKey = Base64.getDecoder().decode(publicKey);
+ } catch (IllegalArgumentException e) {
+ throw new GeneralSecurityException("Invalid public key base64 encoding", e);
+ }
setPublicKey(
KeyFactory.getInstance("RSA")
- .generatePublic(
- new X509EncodedKeySpec(Base64.getDecoder().decode(publicKey))));
+ .generatePublic(new X509EncodedKeySpec(decodedPublicKey)));
}
@VisibleForTesting
@@ -82,10 +88,21 @@
verifier.initVerify(mPublicKey.get());
ContentResolver contentResolver = mContext.getContentResolver();
+ boolean success = false;
try (InputStream fileStream = contentResolver.openInputStream(file);
InputStream signatureStream = contentResolver.openInputStream(signature)) {
verifier.update(fileStream.readAllBytes());
- return verifier.verify(signatureStream.readAllBytes());
+
+ byte[] signatureBytes = signatureStream.readAllBytes();
+ try {
+ success = verifier.verify(Base64.getDecoder().decode(signatureBytes));
+ } catch (IllegalArgumentException e) {
+ Log.w("CertificateTransparencyDownloader", "Invalid signature base64 encoding", e);
+ // TODO: remove the fallback once the signature base64 is published
+ Log.i("CertificateTransparencyDownloader", "Signature verification as raw bytes");
+ success = verifier.verify(signatureBytes);
+ }
}
+ return success;
}
}
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
index 2f57fc9..78e7272 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
@@ -235,8 +235,8 @@
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
- verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
- anyInt(), anyInt());
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEventWithDownloadStatus(anyInt(), anyInt());
}
@Test
@@ -309,8 +309,8 @@
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
- verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
- anyInt(), anyInt());
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEventWithDownloadStatus(anyInt(), anyInt());
}
@Test
@@ -387,8 +387,8 @@
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
- verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
- anyInt(), anyInt());
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEventWithDownloadStatus(anyInt(), anyInt());
}
@Test
@@ -606,8 +606,8 @@
Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
.isEqualTo(1);
verify(mLogger, never()).logCTLogListUpdateFailedEvent(anyInt(), anyInt());
- verify(mLogger, never()).logCTLogListUpdateFailedEventWithDownloadStatus(
- anyInt(), anyInt());
+ verify(mLogger, never())
+ .logCTLogListUpdateFailedEventWithDownloadStatus(anyInt(), anyInt());
}
@Test
@@ -793,7 +793,7 @@
try (InputStream fileStream = new FileInputStream(file);
OutputStream outputStream = new FileOutputStream(signatureFile)) {
signer.update(fileStream.readAllBytes());
- outputStream.write(signer.sign());
+ outputStream.write(Base64.getEncoder().encode(signer.sign()));
}
return signatureFile;