1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-06-27 22:14:50 +02:00

Fix more tests

This commit is contained in:
Paul Schaub 2022-10-24 17:56:33 +02:00
parent aa398f9963
commit e0b2145793
2 changed files with 59 additions and 18 deletions

View file

@ -4,7 +4,6 @@
package org.pgpainless.decryption_verification; package org.pgpainless.decryption_verification;
import java.io.BufferedInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
@ -37,7 +36,6 @@ import org.bouncycastle.openpgp.operator.PBEDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider; import org.bouncycastle.openpgp.operator.PGPContentVerifierBuilderProvider;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory; import org.bouncycastle.openpgp.operator.SessionKeyDataDecryptorFactory;
import org.bouncycastle.util.io.Streams;
import org.bouncycastle.util.io.TeeInputStream; import org.bouncycastle.util.io.TeeInputStream;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.CompressionAlgorithm; import org.pgpainless.algorithm.CompressionAlgorithm;
@ -210,6 +208,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
} }
switch (type) { switch (type) {
case standard: case standard:
// tee out packet bytes for signature verification // tee out packet bytes for signature verification
packetInputStream = new TeeBCPGInputStream(BCPGInputStream.wrap(inputStream), this.signatures); packetInputStream = new TeeBCPGInputStream(BCPGInputStream.wrap(inputStream), this.signatures);
@ -217,20 +216,22 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
// *omnomnom* // *omnomnom*
consumePackets(); consumePackets();
break; break;
case cleartext_signed: case cleartext_signed:
resultBuilder.setCleartextSigned();
MultiPassStrategy multiPassStrategy = options.getMultiPassStrategy(); MultiPassStrategy multiPassStrategy = options.getMultiPassStrategy();
PGPSignatureList detachedSignatures = ClearsignedMessageUtil PGPSignatureList detachedSignatures = ClearsignedMessageUtil
.detachSignaturesFromInbandClearsignedMessage( .detachSignaturesFromInbandClearsignedMessage(
inputStream, multiPassStrategy.getMessageOutputStream()); inputStream, multiPassStrategy.getMessageOutputStream());
for (PGPSignature signature : detachedSignatures) { for (PGPSignature signature : detachedSignatures) {
options.addVerificationOfDetachedSignature(signature); signatures.addDetachedSignature(signature);
} }
options.forceNonOpenPgpData(); options.forceNonOpenPgpData();
packetInputStream = null;
nestedInputStream = new TeeInputStream(multiPassStrategy.getMessageInputStream(), this.signatures); nestedInputStream = new TeeInputStream(multiPassStrategy.getMessageInputStream(), this.signatures);
break; break;
case non_openpgp: case non_openpgp:
packetInputStream = null; packetInputStream = null;
nestedInputStream = new TeeInputStream(inputStream, this.signatures); nestedInputStream = new TeeInputStream(inputStream, this.signatures);
@ -348,14 +349,14 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
metadata.depth + 1); metadata.depth + 1);
LOGGER.debug("Compressed Data Packet (" + compressionLayer.algorithm + ") at depth " + metadata.depth + " encountered"); LOGGER.debug("Compressed Data Packet (" + compressionLayer.algorithm + ") at depth " + metadata.depth + " encountered");
InputStream decompressed = compressedData.getDataStream(); InputStream decompressed = compressedData.getDataStream();
nestedInputStream = new OpenPgpMessageInputStream(buffer(decompressed), options, compressionLayer, policy); nestedInputStream = new OpenPgpMessageInputStream(decompressed, options, compressionLayer, policy);
} }
private void processOnePassSignature() throws PGPException, IOException { private void processOnePassSignature() throws PGPException, IOException {
syntaxVerifier.next(InputAlphabet.OnePassSignature); syntaxVerifier.next(InputAlphabet.OnePassSignature);
PGPOnePassSignature onePassSignature = packetInputStream.readOnePassSignature(); PGPOnePassSignature onePassSignature = packetInputStream.readOnePassSignature();
LOGGER.debug("One-Pass-Signature Packet by key " + KeyIdUtil.formatKeyId(onePassSignature.getKeyID()) + LOGGER.debug("One-Pass-Signature Packet by key " + KeyIdUtil.formatKeyId(onePassSignature.getKeyID()) +
"at depth " + metadata.depth + " encountered"); " at depth " + metadata.depth + " encountered");
signatures.addOnePassSignature(onePassSignature); signatures.addOnePassSignature(onePassSignature);
} }
@ -434,7 +435,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
InputStream decrypted = skesk.getDataStream(decryptorFactory); InputStream decrypted = skesk.getDataStream(decryptorFactory);
encryptedData.sessionKey = sessionKey; encryptedData.sessionKey = sessionKey;
IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, skesk, options); IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, skesk, options);
nestedInputStream = new OpenPgpMessageInputStream(buffer(integrityProtected), options, encryptedData, policy); nestedInputStream = new OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy);
LOGGER.debug("Successfully decrypted data with provided session key"); LOGGER.debug("Successfully decrypted data with provided session key");
return true; return true;
} else if (esk instanceof PGPPublicKeyEncryptedData) { } else if (esk instanceof PGPPublicKeyEncryptedData) {
@ -442,7 +443,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
InputStream decrypted = pkesk.getDataStream(decryptorFactory); InputStream decrypted = pkesk.getDataStream(decryptorFactory);
encryptedData.sessionKey = sessionKey; encryptedData.sessionKey = sessionKey;
IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, pkesk, options); IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, pkesk, options);
nestedInputStream = new OpenPgpMessageInputStream(buffer(integrityProtected), options, encryptedData, policy); nestedInputStream = new OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy);
LOGGER.debug("Successfully decrypted data with provided session key"); LOGGER.debug("Successfully decrypted data with provided session key");
return true; return true;
} else { } else {
@ -579,7 +580,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
encryptedData.sessionKey = sessionKey; encryptedData.sessionKey = sessionKey;
LOGGER.debug("Successfully decrypted data with passphrase"); LOGGER.debug("Successfully decrypted data with passphrase");
IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, skesk, options); IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, skesk, options);
nestedInputStream = new OpenPgpMessageInputStream(buffer(integrityProtected), options, encryptedData, policy); nestedInputStream = new OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy);
return true; return true;
} catch (UnacceptableAlgorithmException e) { } catch (UnacceptableAlgorithmException e) {
throw e; throw e;
@ -606,7 +607,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
LOGGER.debug("Successfully decrypted data with key " + decryptionKeyId); LOGGER.debug("Successfully decrypted data with key " + decryptionKeyId);
IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, pkesk, options); IntegrityProtectedInputStream integrityProtected = new IntegrityProtectedInputStream(decrypted, pkesk, options);
nestedInputStream = new OpenPgpMessageInputStream(buffer(integrityProtected), options, encryptedData, policy); nestedInputStream = new OpenPgpMessageInputStream(integrityProtected, options, encryptedData, policy);
return true; return true;
} catch (UnacceptableAlgorithmException e) { } catch (UnacceptableAlgorithmException e) {
throw e; throw e;
@ -631,10 +632,6 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
} }
} }
private static InputStream buffer(InputStream inputStream) {
return new BufferedInputStream(inputStream);
}
private List<Tuple<PGPSecretKeyRing, PGPSecretKey>> findPotentialDecryptionKeys(PGPPublicKeyEncryptedData pkesk) { private List<Tuple<PGPSecretKeyRing, PGPSecretKey>> findPotentialDecryptionKeys(PGPPublicKeyEncryptedData pkesk) {
int algorithm = pkesk.getAlgorithm(); int algorithm = pkesk.getAlgorithm();
List<Tuple<PGPSecretKeyRing, PGPSecretKey>> decryptionKeyCandidates = new ArrayList<>(); List<Tuple<PGPSecretKeyRing, PGPSecretKey>> decryptionKeyCandidates = new ArrayList<>();
@ -665,7 +662,9 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
@Override @Override
public int read() throws IOException { public int read() throws IOException {
if (nestedInputStream == null) { if (nestedInputStream == null) {
syntaxVerifier.assertValid(); if (packetInputStream != null) {
syntaxVerifier.assertValid();
}
return -1; return -1;
} }
@ -699,7 +698,6 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
@Override @Override
public int read(@Nonnull byte[] b, int off, int len) public int read(@Nonnull byte[] b, int off, int len)
throws IOException { throws IOException {
if (nestedInputStream == null) { if (nestedInputStream == null) {
if (packetInputStream != null) { if (packetInputStream != null) {
syntaxVerifier.assertValid(); syntaxVerifier.assertValid();
@ -768,6 +766,7 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
if (!closed) { if (!closed) {
throw new IllegalStateException("Stream must be closed before access to metadata can be granted."); throw new IllegalStateException("Stream must be closed before access to metadata can be granted.");
} }
return new MessageMetadata((MessageMetadata.Message) metadata); return new MessageMetadata((MessageMetadata.Message) metadata);
} }
@ -857,6 +856,9 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
final Stack<List<OnePassSignatureCheck>> opsUpdateStack; final Stack<List<OnePassSignatureCheck>> opsUpdateStack;
List<OnePassSignatureCheck> literalOPS = new ArrayList<>(); List<OnePassSignatureCheck> literalOPS = new ArrayList<>();
final List<PGPSignature> correspondingSignatures; final List<PGPSignature> correspondingSignatures;
final List<SignatureVerification.Failure> prependedSignaturesWithMissingCert = new ArrayList<>();
final List<SignatureVerification.Failure> inbandSignaturesWithMissingCert = new ArrayList<>();
final List<SignatureVerification.Failure> detachedSignaturesWithMissingCert = new ArrayList<>();
boolean isLiteral = true; boolean isLiteral = true;
private Signatures(ConsumerOptions options) { private Signatures(ConsumerOptions options) {
@ -876,15 +878,29 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
void addDetachedSignature(PGPSignature signature) { void addDetachedSignature(PGPSignature signature) {
SignatureCheck check = initializeSignature(signature); SignatureCheck check = initializeSignature(signature);
long keyId = SignatureUtils.determineIssuerKeyId(signature);
if (check != null) { if (check != null) {
detachedSignatures.add(check); detachedSignatures.add(check);
} else {
LOGGER.debug("No suitable certificate for verification of signature by key " + KeyIdUtil.formatKeyId(keyId) + " found.");
this.detachedSignaturesWithMissingCert.add(new SignatureVerification.Failure(
new SignatureVerification(signature, null),
new SignatureValidationException("Missing verification key")
));
} }
} }
void addPrependedSignature(PGPSignature signature) { void addPrependedSignature(PGPSignature signature) {
SignatureCheck check = initializeSignature(signature); SignatureCheck check = initializeSignature(signature);
long keyId = SignatureUtils.determineIssuerKeyId(signature);
if (check != null) { if (check != null) {
this.prependedSignatures.add(check); this.prependedSignatures.add(check);
} else {
LOGGER.debug("No suitable certificate for verification of signature by key " + KeyIdUtil.formatKeyId(keyId) + " found.");
this.prependedSignaturesWithMissingCert.add(new SignatureVerification.Failure(
new SignatureVerification(signature, null),
new SignatureValidationException("Missing verification key")
));
} }
} }
@ -916,11 +932,14 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
} }
void addCorrespondingOnePassSignature(PGPSignature signature, MessageMetadata.Layer layer, Policy policy) { void addCorrespondingOnePassSignature(PGPSignature signature, MessageMetadata.Layer layer, Policy policy) {
boolean found = false;
long keyId = SignatureUtils.determineIssuerKeyId(signature);
for (int i = onePassSignatures.size() - 1; i >= 0; i--) { for (int i = onePassSignatures.size() - 1; i >= 0; i--) {
OnePassSignatureCheck onePassSignature = onePassSignatures.get(i); OnePassSignatureCheck onePassSignature = onePassSignatures.get(i);
if (onePassSignature.getOnePassSignature().getKeyID() != signature.getKeyID()) { if (onePassSignature.getOnePassSignature().getKeyID() != keyId) {
continue; continue;
} }
found = true;
if (onePassSignature.getSignature() != null) { if (onePassSignature.getSignature() != null) {
continue; continue;
@ -942,6 +961,13 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
} }
break; break;
} }
if (!found) {
LOGGER.debug("No suitable certificate for verification of signature by key " + KeyIdUtil.formatKeyId(keyId) + " found.");
inbandSignaturesWithMissingCert.add(new SignatureVerification.Failure(
new SignatureVerification(signature, null),
new SignatureValidationException("Missing verification key.")));
}
} }
void enterNesting() { void enterNesting() {
@ -983,6 +1009,10 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
return cert; return cert;
} }
} }
if (options.getMissingCertificateCallback() != null) {
return options.getMissingCertificateCallback().onMissingPublicKeyEncountered(keyId);
}
return null; // TODO: Missing cert for sig return null; // TODO: Missing cert for sig
} }
@ -1066,6 +1096,18 @@ public class OpenPgpMessageInputStream extends DecryptionStream {
layer.addRejectedPrependedSignature(new SignatureVerification.Failure(verification, e)); layer.addRejectedPrependedSignature(new SignatureVerification.Failure(verification, e));
} }
} }
for (SignatureVerification.Failure rejected : inbandSignaturesWithMissingCert) {
layer.addRejectedOnePassSignature(rejected);
}
for (SignatureVerification.Failure rejected : prependedSignaturesWithMissingCert) {
layer.addRejectedPrependedSignature(rejected);
}
for (SignatureVerification.Failure rejected : detachedSignaturesWithMissingCert) {
layer.addRejectedDetachedSignature(rejected);
}
} }
@Override @Override

View file

@ -98,7 +98,6 @@ public class TeeBCPGInputStream {
public void close() throws IOException { public void close() throws IOException {
this.packetInputStream.close(); this.packetInputStream.close();
this.delayedTee.close();
} }
public static class DelayedTeeInputStreamInputStream extends InputStream { public static class DelayedTeeInputStreamInputStream extends InputStream {