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:
parent
75455f1a3c
commit
d64e749f22
3 changed files with 43 additions and 14 deletions
|
@ -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()
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue