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
This commit is contained in:
parent
d2459f373c
commit
ed61bfc39d
2 changed files with 29 additions and 12 deletions
|
|
@ -21,6 +21,7 @@ import android.content.ContentResolver;
|
|||
import android.content.Context;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
|
||||
|
|
@ -62,10 +63,15 @@ public class SignatureVerifier {
|
|||
}
|
||||
|
||||
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 @@ public class SignatureVerifier {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -235,8 +235,8 @@ public class CertificateTransparencyDownloaderTest {
|
|||
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 @@ public class CertificateTransparencyDownloaderTest {
|
|||
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 @@ public class CertificateTransparencyDownloaderTest {
|
|||
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 @@ public class CertificateTransparencyDownloaderTest {
|
|||
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 @@ public class CertificateTransparencyDownloaderTest {
|
|||
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;
|
||||
|
|
|
|||
Loading…
Reference in a new issue