1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-23 11:27:57 +01:00

Fix sop encrypt --sign-with allowing for protected keys

This commit is contained in:
Paul Schaub 2022-06-19 17:50:31 +02:00
parent 75455f1a3c
commit d64e749f22
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
3 changed files with 43 additions and 14 deletions

View file

@ -8,6 +8,8 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.HashSet;
import java.util.Set;
import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
@ -23,6 +25,8 @@ import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions; import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.exception.KeyException; import org.pgpainless.exception.KeyException;
import org.pgpainless.exception.WrongPassphraseException; import org.pgpainless.exception.WrongPassphraseException;
import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.util.Passphrase; import org.pgpainless.util.Passphrase;
import sop.Ready; import sop.Ready;
import sop.enums.EncryptAs; import sop.enums.EncryptAs;
@ -35,6 +39,7 @@ public class EncryptImpl implements Encrypt {
EncryptionOptions encryptionOptions = new EncryptionOptions(); EncryptionOptions encryptionOptions = new EncryptionOptions();
SigningOptions signingOptions = null; SigningOptions signingOptions = null;
MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector(); MatchMakingSecretKeyRingProtector protector = new MatchMakingSecretKeyRingProtector();
private final Set<PGPSecretKeyRing> signingKeys = new HashSet<>();
private EncryptAs encryptAs = EncryptAs.Binary; private EncryptAs encryptAs = EncryptAs.Binary;
boolean armor = true; boolean armor = true;
@ -63,23 +68,15 @@ public class EncryptImpl implements Encrypt {
if (keys.size() != 1) { if (keys.size() != 1) {
throw new SOPGPException.BadData(new AssertionError("Exactly one secret key at a time expected. Got " + keys.size())); throw new SOPGPException.BadData(new AssertionError("Exactly one secret key at a time expected. Got " + keys.size()));
} }
PGPSecretKeyRing signingKey = keys.iterator().next(); PGPSecretKeyRing signingKey = keys.iterator().next();
protector.addSecretKey(signingKey);
try { KeyRingInfo info = PGPainless.inspectKeyRing(signingKey);
signingOptions.addInlineSignature( if (info.getSigningSubkeys().isEmpty()) {
protector, throw new SOPGPException.KeyCannotSign("Key " + OpenPgpFingerprint.of(signingKey) + " cannot sign.");
signingKey,
(encryptAs == EncryptAs.Binary ? DocumentSignatureType.BINARY_DOCUMENT : DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)
);
} catch (IllegalArgumentException e) {
throw new SOPGPException.KeyCannotSign();
} catch (WrongPassphraseException e) {
throw new SOPGPException.KeyIsProtected();
} catch (PGPException e) {
throw new SOPGPException.BadData(e);
} }
protector.addSecretKey(signingKey);
signingKeys.add(signingKey);
} catch (IOException | PGPException e) { } catch (IOException | PGPException e) {
throw new SOPGPException.BadData(e); throw new SOPGPException.BadData(e);
} }
@ -122,6 +119,22 @@ public class EncryptImpl implements Encrypt {
producerOptions.setAsciiArmor(armor); producerOptions.setAsciiArmor(armor);
producerOptions.setEncoding(encryptAsToStreamEncoding(encryptAs)); producerOptions.setEncoding(encryptAsToStreamEncoding(encryptAs));
for (PGPSecretKeyRing signingKey : signingKeys) {
try {
signingOptions.addInlineSignature(
protector,
signingKey,
(encryptAs == EncryptAs.Binary ? DocumentSignatureType.BINARY_DOCUMENT : DocumentSignatureType.CANONICAL_TEXT_DOCUMENT)
);
} catch (KeyException.UnacceptableSigningKeyException e) {
throw new SOPGPException.KeyCannotSign();
} catch (WrongPassphraseException e) {
throw new SOPGPException.KeyIsProtected();
} catch (PGPException e) {
throw new SOPGPException.BadData(e);
}
}
try { try {
ProxyOutputStream proxy = new ProxyOutputStream(); ProxyOutputStream proxy = new ProxyOutputStream();
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign() EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()

View file

@ -38,6 +38,7 @@ public class EncryptDecryptRoundTripTest {
sop = new SOPImpl(); sop = new SOPImpl();
aliceKey = sop.generateKey() aliceKey = sop.generateKey()
.userId("Alice <alice@pgpainless.org>") .userId("Alice <alice@pgpainless.org>")
.withKeyPassword("wonderland.is.c00l")
.generate() .generate()
.getBytes(); .getBytes();
aliceCert = sop.extractCert() aliceCert = sop.extractCert()
@ -56,6 +57,7 @@ public class EncryptDecryptRoundTripTest {
public void basicRoundTripWithKey() throws IOException, SOPGPException.KeyCannotSign { public void basicRoundTripWithKey() throws IOException, SOPGPException.KeyCannotSign {
byte[] encrypted = sop.encrypt() byte[] encrypted = sop.encrypt()
.signWith(aliceKey) .signWith(aliceKey)
.withKeyPassword("wonderland.is.c00l")
.withCert(aliceCert) .withCert(aliceCert)
.withCert(bobCert) .withCert(bobCert)
.plaintext(message) .plaintext(message)
@ -426,6 +428,15 @@ public class EncryptDecryptRoundTripTest {
assertArrayEquals(message, bytesAndResult.getBytes()); assertArrayEquals(message, bytesAndResult.getBytes());
} }
@Test
public void testEncryptWithWrongPassphraseThrowsKeyIsProtected() {
assertThrows(SOPGPException.KeyIsProtected.class, () -> sop.encrypt()
.withKeyPassword("falsePassphrase")
.signWith(aliceKey)
.withCert(bobCert)
.plaintext(message));
}
@Test @Test
public void testDecryptionWithSessionKey_VerificationWithCert() throws IOException { public void testDecryptionWithSessionKey_VerificationWithCert() throws IOException {
byte[] plaintext = "This is a test message.\nSit back and relax.\n".getBytes(StandardCharsets.UTF_8); byte[] plaintext = "This is a test message.\nSit back and relax.\n".getBytes(StandardCharsets.UTF_8);

View file

@ -64,4 +64,9 @@ public class IncapableKeysTest {
assertThrows(SOPGPException.KeyCannotSign.class, () -> sop.detachedSign().key(nonSigningKey)); assertThrows(SOPGPException.KeyCannotSign.class, () -> sop.detachedSign().key(nonSigningKey));
assertThrows(SOPGPException.KeyCannotSign.class, () -> sop.inlineSign().key(nonSigningKey)); assertThrows(SOPGPException.KeyCannotSign.class, () -> sop.inlineSign().key(nonSigningKey));
} }
@Test
public void encryptAndSignWithNonSigningKeyFails() {
assertThrows(SOPGPException.KeyCannotSign.class, () -> sop.encrypt().signWith(nonSigningKey));
}
} }