mirror of
https://github.com/sparrowwallet/sparrow.git
synced 2026-10-05 11:08:25 +00:00
support inline signed manifests in the download verifier by reading hashes from the verified signature content
This commit is contained in:
+1
-1
Submodule drongo updated: 00aa6ec07e...3a60bd6453
@@ -312,7 +312,8 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
PGPVerificationResult result = pgpVerifyService.getValue();
|
SignedManifest signedManifest = pgpVerifyService.getValue();
|
||||||
|
PGPVerificationResult result = signedManifest.result();
|
||||||
|
|
||||||
String message = result.userId() + " on " + signatureDateFormat.format(result.signatureTimestamp()) + (result.expired() ? " (key expired)" : "");
|
String message = result.userId() + " on " + signatureDateFormat.format(result.signatureTimestamp()) + (result.expired() ? " (key expired)" : "");
|
||||||
signedBy.setText(message);
|
signedBy.setText(message);
|
||||||
@@ -332,7 +333,7 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||||||
releaseVerified.setGraphic(GlyphUtils.getSuccessGlyph());
|
releaseVerified.setGraphic(GlyphUtils.getSuccessGlyph());
|
||||||
releaseLink.setText(release.get().getName());
|
releaseLink.setText(release.get().getName());
|
||||||
} else {
|
} else {
|
||||||
verifyManifest(verification);
|
verifyManifest(verification, signedManifest.content());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
pgpVerifyService.setOnFailed(event -> {
|
pgpVerifyService.setOnFailed(event -> {
|
||||||
@@ -374,10 +375,9 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||||||
releaseLink.setText("");
|
releaseLink.setText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void verifyManifest(long verification) {
|
private void verifyManifest(long verification, byte[] manifestContent) {
|
||||||
File releaseFile = release.get();
|
File releaseFile = release.get();
|
||||||
if(releaseFile != null && releaseFile.exists()) {
|
if(releaseFile != null && releaseFile.exists()) {
|
||||||
File manifestFile = manifest.get();
|
|
||||||
hashService = new FileSha256Service(releaseFile);
|
hashService = new FileSha256Service(releaseFile);
|
||||||
hashService.setOnRunning(event -> {
|
hashService.setOnRunning(event -> {
|
||||||
if(verification != verificationCount) {
|
if(verification != verificationCount) {
|
||||||
@@ -398,7 +398,11 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||||||
|
|
||||||
String calculatedHash = hashService.getValue();
|
String calculatedHash = hashService.getValue();
|
||||||
try {
|
try {
|
||||||
Map<File, String> manifestMap = getManifest(manifestFile);
|
if(manifestContent == null || manifestContent.length > MAX_VALID_MANIFEST_SIZE) {
|
||||||
|
throw new InvalidManifestException("Manifest file is larger than " + (MAX_VALID_MANIFEST_SIZE / 1024) + "KB");
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<File, String> manifestMap = getManifest(new ByteArrayInputStream(manifestContent));
|
||||||
String manifestHash = getManifestHash(releaseFile.getName(), manifestMap);
|
String manifestHash = getManifestHash(releaseFile.getName(), manifestMap);
|
||||||
if(calculatedHash.equalsIgnoreCase(manifestHash)) {
|
if(calculatedHash.equalsIgnoreCase(manifestHash)) {
|
||||||
releaseHash.setText("Matched manifest hash");
|
releaseHash.setText("Matched manifest hash");
|
||||||
@@ -775,7 +779,9 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class PGPVerifyService extends Service<PGPVerificationResult> {
|
private record SignedManifest(PGPVerificationResult result, byte[] content) { }
|
||||||
|
|
||||||
|
private static class PGPVerifyService extends Service<SignedManifest> {
|
||||||
private final File signature;
|
private final File signature;
|
||||||
private final File manifest;
|
private final File manifest;
|
||||||
private final File publicKey;
|
private final File publicKey;
|
||||||
@@ -787,15 +793,30 @@ public class DownloadVerifierDialog extends Dialog<ButtonBar.ButtonData> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Task<PGPVerificationResult> createTask() {
|
protected Task<SignedManifest> createTask() {
|
||||||
return new Task<>() {
|
return new Task<>() {
|
||||||
protected PGPVerificationResult call() throws IOException, PGPVerificationException {
|
protected SignedManifest call() throws IOException, PGPVerificationException {
|
||||||
boolean detachedSignature = !manifest.equals(signature);
|
boolean detachedSignature = !manifest.equals(signature);
|
||||||
|
|
||||||
|
//Retain at most one byte more than a valid manifest, so the content of a manifest that is too large can be rejected without holding all of it
|
||||||
|
ByteArrayOutputStream signedContent = manifest.length() > MAX_VALID_MANIFEST_SIZE ? null : new ByteArrayOutputStream();
|
||||||
|
OutputStream signedContentStream = signedContent == null ? null : new OutputStream() {
|
||||||
|
@Override
|
||||||
|
public void write(int b) {
|
||||||
|
write(new byte[] { (byte)b }, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] b, int off, int len) {
|
||||||
|
signedContent.write(b, off, (int)Math.max(0, Math.min(len, MAX_VALID_MANIFEST_SIZE + 1 - signedContent.size())));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
try(InputStream publicKeyStream = publicKey == null ? null : new FileInputStream(publicKey);
|
try(InputStream publicKeyStream = publicKey == null ? null : new FileInputStream(publicKey);
|
||||||
InputStream contentStream = new BufferedInputStream(new FileInputStream(manifest));
|
InputStream contentStream = new BufferedInputStream(new FileInputStream(manifest));
|
||||||
InputStream detachedSignatureStream = detachedSignature ? new FileInputStream(signature) : null) {
|
InputStream detachedSignatureStream = detachedSignature ? new FileInputStream(signature) : null) {
|
||||||
return PGPUtils.verify(publicKeyStream, contentStream, detachedSignatureStream);
|
PGPVerificationResult result = PGPUtils.verify(publicKeyStream, contentStream, detachedSignatureStream, signedContentStream);
|
||||||
|
return new SignedManifest(result, signedContent == null ? null : signedContent.toByteArray());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user