1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-06-30 15:26:43 +02:00

Fix SOP encrypt-decrypt test

This commit is contained in:
Paul Schaub 2021-05-25 16:25:22 +02:00
parent b0692b4dc5
commit 3cd64b61ca
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
8 changed files with 88 additions and 72 deletions

View file

@ -112,7 +112,7 @@ public class KeyRingValidator {
} }
} }
} catch (SignatureValidationException e) { } catch (SignatureValidationException e) {
LOGGER.log(Level.INFO, "Rejecting user-id certification for user-id " + userId, e); LOGGER.log(Level.FINE, "Rejecting user-id certification for user-id " + userId, e);
} }
} }
} }

View file

@ -269,7 +269,11 @@ public class KeyRingInfo {
public String getPrimaryUserId() { public String getPrimaryUserId() {
String primaryUserId = null; String primaryUserId = null;
Date modificationDate = null; Date modificationDate = null;
for (String userId : getValidUserIds()) { List<String> validUserIds = getValidUserIds();
if (validUserIds.isEmpty()) {
return null;
}
for (String userId : validUserIds) {
PGPSignature signature = signatures.userIdCertifications.get(userId); PGPSignature signature = signatures.userIdCertifications.get(userId);
PrimaryUserID subpacket = SignatureSubpacketsUtil.getPrimaryUserId(signature); PrimaryUserID subpacket = SignatureSubpacketsUtil.getPrimaryUserId(signature);
if (subpacket != null && subpacket.isPrimaryUserID()) { if (subpacket != null && subpacket.isPrimaryUserID()) {
@ -282,7 +286,7 @@ public class KeyRingInfo {
} }
// Workaround for keys with only one user-id but no primary user-id packet. // Workaround for keys with only one user-id but no primary user-id packet.
if (primaryUserId == null) { if (primaryUserId == null) {
return getValidUserIds().get(0); return validUserIds.get(0);
} }
return primaryUserId; return primaryUserId;

View file

@ -26,6 +26,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bouncycastle.bcpg.sig.KeyFlags;
import org.bouncycastle.bcpg.sig.SignerUserID; import org.bouncycastle.bcpg.sig.SignerUserID;
import org.bouncycastle.openpgp.PGPPublicKey; import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
@ -123,7 +124,7 @@ public class SignatureChainValidator {
} }
} catch (SignatureValidationException e) { } catch (SignatureValidationException e) {
rejections.put(userIdSig, e); rejections.put(userIdSig, e);
LOGGER.log(Level.INFO, "Rejecting user-id signature.", e); LOGGER.log(Level.FINE, "Rejecting user-id signature.", e);
} }
} }
Collections.sort(signaturesOnUserId, new SignatureValidityComparator(SignatureCreationDateComparator.Order.NEW_TO_OLD)); Collections.sort(signaturesOnUserId, new SignatureValidityComparator(SignatureCreationDateComparator.Order.NEW_TO_OLD));
@ -200,8 +201,18 @@ public class SignatureChainValidator {
throw new SignatureValidationException("Subkey is revoked."); throw new SignatureValidationException("Subkey is revoked.");
} }
if (!KeyFlag.hasKeyFlag(SignatureSubpacketsUtil.getKeyFlags(currentSig).getFlags(), KeyFlag.SIGN_DATA)) { KeyFlags keyFlags = SignatureSubpacketsUtil.getKeyFlags(currentSig);
throw new SignatureValidationException("Signature was made by key which is not capable of signing."); if (keyFlags == null) {
if (directKeySignatures.isEmpty()) {
throw new SignatureValidationException("Signature was made by key which is not capable of signing (no keyflags on binding sig, no direct-key sig).");
}
PGPSignature directKeySig = directKeySignatures.get(0);
KeyFlags directKeyFlags = SignatureSubpacketsUtil.getKeyFlags(directKeySig);
if (!KeyFlag.hasKeyFlag(directKeyFlags.getFlags(), KeyFlag.SIGN_DATA)) {
throw new SignatureValidationException("Signature was made by key which is not capable of signing (no keyflags on binding sig, no SIGN flag on direct-key sig).");
}
} else if (!KeyFlag.hasKeyFlag(keyFlags.getFlags(), KeyFlag.SIGN_DATA)) {
throw new SignatureValidationException("Signature was made by key which is not capable of signing (no SIGN flag on binding sig).");
} }
} }
return true; return true;

View file

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
@ -41,4 +42,17 @@ public class SopKeyUtil {
} }
return secretKeyRings; return secretKeyRings;
} }
public static List<PGPPublicKeyRing> loadCertificatesFromFile(File... files) throws IOException {
List<PGPPublicKeyRing> publicKeyRings = new ArrayList<>();
for (File file : files) {
try (FileInputStream in = new FileInputStream(file)) {
publicKeyRings.add(PGPainless.readKeyRing().publicKeyRing(in));
} catch (IOException e) {
err_ln("Could not read certificate from file " + file.getName() + ": " + e.getMessage());
throw e;
}
}
return publicKeyRings;
}
} }

View file

@ -26,6 +26,7 @@ import java.io.PrintStream;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -40,7 +41,9 @@ import org.pgpainless.decryption_verification.DecryptionBuilderInterface;
import org.pgpainless.decryption_verification.DecryptionStream; import org.pgpainless.decryption_verification.DecryptionStream;
import org.pgpainless.decryption_verification.OpenPgpMetadata; import org.pgpainless.decryption_verification.OpenPgpMetadata;
import org.pgpainless.key.OpenPgpV4Fingerprint; import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.sop.SopKeyUtil;
import picocli.CommandLine; import picocli.CommandLine;
import sun.text.resources.CollationData;
@CommandLine.Command(name = "decrypt", @CommandLine.Command(name = "decrypt",
description = "Decrypt a message from standard input", description = "Decrypt a message from standard input",
@ -110,33 +113,27 @@ public class Decrypt implements Runnable {
} }
PGPSecretKeyRingCollection secretKeys; PGPSecretKeyRingCollection secretKeys;
List<PGPPublicKeyRing> verifyWith = null;
try { try {
List<PGPSecretKeyRing> secretKeyRings = loadKeysFromFiles(keys); List<PGPSecretKeyRing> secretKeyRings = loadKeysFromFiles(keys);
secretKeys = new PGPSecretKeyRingCollection(secretKeyRings); secretKeys = new PGPSecretKeyRingCollection(secretKeyRings);
} catch (PGPException | IOException e) { if (certs != null) {
verifyWith = SopKeyUtil.loadCertificatesFromFile(certs);
}
} catch (IOException | PGPException e) {
err_ln(e.getMessage()); err_ln(e.getMessage());
System.exit(1); System.exit(1);
return; return;
} }
List<PGPPublicKeyRing> verifyWith = new ArrayList<>();
if (certs != null) {
for (File f : certs) {
try {
verifyWith.add(PGPainless.readKeyRing().publicKeyRing(new FileInputStream(f)));
} catch (IOException e) {
}
}
}
DecryptionBuilderInterface.Verify builder = PGPainless.decryptAndOrVerify() DecryptionBuilderInterface.Verify builder = PGPainless.decryptAndOrVerify()
.onInputStream(System.in) .onInputStream(System.in)
.decryptWith(secretKeys); .decryptWith(secretKeys);
DecryptionStream decryptionStream = null; DecryptionStream decryptionStream = null;
try { try {
if (certs != null) { if (verifyWith != null) {
decryptionStream = builder.verifyWith(new HashSet<>(verifyWith)) decryptionStream = builder.verifyWith(new HashSet<>(verifyWith))
.ignoreMissingPublicKeys().build(); .ignoreMissingPublicKeys().build();
} else { } else {
@ -144,12 +141,14 @@ public class Decrypt implements Runnable {
.build(); .build();
} }
} catch (IOException | PGPException e) { } catch (IOException | PGPException e) {
err_ln("Error constructing decryption stream: " + e.getMessage());
System.exit(1); System.exit(1);
return; return;
} }
try { try {
Streams.pipeAll(decryptionStream, System.out); Streams.pipeAll(decryptionStream, System.out);
System.out.flush();
decryptionStream.close(); decryptionStream.close();
} catch (IOException e) { } catch (IOException e) {
err_ln("Unable to decrypt: " + e.getMessage()); err_ln("Unable to decrypt: " + e.getMessage());
@ -161,28 +160,32 @@ public class Decrypt implements Runnable {
OpenPgpMetadata metadata = decryptionStream.getResult(); OpenPgpMetadata metadata = decryptionStream.getResult();
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
for (OpenPgpV4Fingerprint fingerprint : metadata.getVerifiedSignatures().keySet()) {
PGPPublicKeyRing verifier = null;
for (PGPPublicKeyRing ring : verifyWith) {
if (ring.getPublicKey(fingerprint.getKeyId()) != null) {
verifier = ring;
break;
}
}
PGPSignature signature = metadata.getVerifiedSignatures().get(fingerprint);
sb.append(df.format(signature.getCreationTime())).append(' ')
.append(fingerprint).append(' ')
.append(new OpenPgpV4Fingerprint(verifier)).append('\n');
}
try { if (verifyWith != null) {
verifyOut.createNewFile(); for (OpenPgpV4Fingerprint fingerprint : metadata.getVerifiedSignatures().keySet()) {
PrintStream verifyPrinter = new PrintStream(new FileOutputStream(verifyOut)); PGPPublicKeyRing verifier = null;
// CHECKSTYLE:OFF for (PGPPublicKeyRing ring : verifyWith) {
verifyPrinter.println(sb.toString()); if (ring.getPublicKey(fingerprint.getKeyId()) != null) {
// CHECKSTYLE:ON verifier = ring;
verifyPrinter.close(); break;
} catch (IOException e) { }
}
PGPSignature signature = metadata.getVerifiedSignatures().get(fingerprint);
sb.append(df.format(signature.getCreationTime())).append(' ')
.append(fingerprint).append(' ')
.append(new OpenPgpV4Fingerprint(verifier)).append('\n');
}
try {
verifyOut.createNewFile();
PrintStream verifyPrinter = new PrintStream(new FileOutputStream(verifyOut));
// CHECKSTYLE:OFF
verifyPrinter.println(sb.toString());
// CHECKSTYLE:ON
verifyPrinter.close();
} catch (IOException e) {
err_ln("Error writing verifications file: " + e);
}
} }
} }
} }

View file

@ -16,14 +16,12 @@
package org.pgpainless.sop.commands; package org.pgpainless.sop.commands;
import static org.pgpainless.sop.Print.err_ln; import static org.pgpainless.sop.Print.err_ln;
import static org.pgpainless.sop.Print.print_ln;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Scanner; import java.util.List;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPPublicKeyRing;
@ -35,9 +33,8 @@ import org.pgpainless.encryption_signing.EncryptionOptions;
import org.pgpainless.encryption_signing.EncryptionStream; import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.encryption_signing.ProducerOptions; import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions; import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider; import org.pgpainless.sop.SopKeyUtil;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
import picocli.CommandLine; import picocli.CommandLine;
@ -87,38 +84,27 @@ public class Encrypt implements Runnable {
EncryptionOptions encOpt = new EncryptionOptions(); EncryptionOptions encOpt = new EncryptionOptions();
SigningOptions signOpt = new SigningOptions(); SigningOptions signOpt = new SigningOptions();
for (int i = 0 ; i < certs.length; i++) { try {
try (InputStream fileIn = new FileInputStream(certs[i])) { List<PGPPublicKeyRing> encryptionKeys = SopKeyUtil.loadCertificatesFromFile(certs);
PGPPublicKeyRing publicKey = PGPainless.readKeyRing().publicKeyRing(fileIn); for (PGPPublicKeyRing key : encryptionKeys) {
encOpt.addRecipient(publicKey); encOpt.addRecipient(key);
} catch (IOException e) {
err_ln("Cannot read certificate " + certs[i].getName());
err_ln(e.getMessage());
System.exit(1);
} }
} catch (IOException e) {
err_ln(e.getMessage());
System.exit(1);
return;
} }
for (int i = 0; i < withPassword.length; i++) { for (String s : withPassword) {
Passphrase passphrase = Passphrase.fromPassword(withPassword[i]); Passphrase passphrase = Passphrase.fromPassword(s);
encOpt.addPassphrase(passphrase); encOpt.addPassphrase(passphrase);
} }
final Scanner scanner = new Scanner(System.in); SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
for (int i = 0; i < signWith.length; i++) { for (int i = 0; i < signWith.length; i++) {
try (FileInputStream fileIn = new FileInputStream(signWith[i])) { try (FileInputStream fileIn = new FileInputStream(signWith[i])) {
PGPSecretKeyRing secretKey = PGPainless.readKeyRing().secretKeyRing(fileIn); PGPSecretKeyRing secretKey = PGPainless.readKeyRing().secretKeyRing(fileIn);
SecretKeyRingProtector protector = SecretKeyRingProtector.defaultSecretKeyRingProtector(
new SecretKeyPassphraseProvider() {
@Nullable
@Override
public Passphrase getPassphraseFor(Long keyId) {
print_ln("Please provide the passphrase for key " + new OpenPgpV4Fingerprint(secretKey));
String password = scanner.nextLine();
Passphrase passphrase = Passphrase.fromPassword(password.trim());
return passphrase;
}
}
);
signOpt.addInlineSignature(protector, secretKey, signOpt.addInlineSignature(protector, secretKey,
type == Type.text || type == Type.mime ? type == Type.text || type == Type.mime ?
DocumentSignatureType.CANONICAL_TEXT_DOCUMENT : DocumentSignatureType.BINARY_DOCUMENT); DocumentSignatureType.CANONICAL_TEXT_DOCUMENT : DocumentSignatureType.BINARY_DOCUMENT);

View file

@ -21,15 +21,12 @@ import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.util.io.Streams; import org.bouncycastle.util.io.Streams;
import org.pgpainless.PGPainless; import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.DocumentSignatureType; import org.pgpainless.algorithm.DocumentSignatureType;
import org.pgpainless.encryption_signing.EncryptionBuilderInterface;
import org.pgpainless.encryption_signing.EncryptionOptions;
import org.pgpainless.encryption_signing.EncryptionResult; import org.pgpainless.encryption_signing.EncryptionResult;
import org.pgpainless.encryption_signing.EncryptionStream; import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.encryption_signing.ProducerOptions; import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions; import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.key.SubkeyIdentifier; import org.pgpainless.key.SubkeyIdentifier;
import org.pgpainless.key.protection.SecretKeyRingProtector; import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.UnprotectedKeysProtector;
import org.pgpainless.sop.Print; import org.pgpainless.sop.Print;
import picocli.CommandLine; import picocli.CommandLine;

View file

@ -103,7 +103,8 @@ public class EncryptDecryptTest {
FileInputStream msgAscIn = new FileInputStream(msgAscFile); FileInputStream msgAscIn = new FileInputStream(msgAscFile);
System.setIn(msgAscIn); System.setIn(msgAscIn);
ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteArrayOutputStream out = new ByteArrayOutputStream();
System.setOut(new PrintStream(out)); PrintStream pOut = new PrintStream(out);
System.setOut(pOut);
new CommandLine(new PGPainlessCLI()).execute("decrypt", new CommandLine(new PGPainlessCLI()).execute("decrypt",
"--verify-out", verifyFile.getAbsolutePath(), "--verify-out", verifyFile.getAbsolutePath(),
"--verify-with", romeoCertFile.getAbsolutePath(), "--verify-with", romeoCertFile.getAbsolutePath(),