mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-11-26 22:32:07 +01:00
Make KO-countermeasures configurable (off by default)
This commit is contained in:
parent
cfba77dea5
commit
bfbaa30e4c
3 changed files with 39 additions and 1 deletions
|
@ -9,6 +9,7 @@ import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKey;
|
import org.bouncycastle.openpgp.PGPSecretKey;
|
||||||
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
import org.bouncycastle.openpgp.operator.PBESecretKeyDecryptor;
|
||||||
|
import org.pgpainless.PGPainless;
|
||||||
import org.pgpainless.exception.KeyIntegrityException;
|
import org.pgpainless.exception.KeyIntegrityException;
|
||||||
import org.pgpainless.exception.WrongPassphraseException;
|
import org.pgpainless.exception.WrongPassphraseException;
|
||||||
import org.pgpainless.key.info.KeyInfo;
|
import org.pgpainless.key.info.KeyInfo;
|
||||||
|
@ -51,7 +52,9 @@ public final class UnlockSecretKey {
|
||||||
throw new PGPException("Cannot decrypt secret key.");
|
throw new PGPException("Cannot decrypt secret key.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (PGPainless.getPolicy().isEnableKeyParameterValidation()) {
|
||||||
PublicKeyParameterValidationUtil.verifyPublicKeyParameterIntegrity(privateKey, secretKey.getPublicKey());
|
PublicKeyParameterValidationUtil.verifyPublicKeyParameterIntegrity(privateKey, secretKey.getPublicKey());
|
||||||
|
}
|
||||||
|
|
||||||
return privateKey;
|
return privateKey;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,6 +49,8 @@ public final class Policy {
|
||||||
// Signers User-ID is soon to be deprecated.
|
// Signers User-ID is soon to be deprecated.
|
||||||
private SignerUserIdValidationLevel signerUserIdValidationLevel = SignerUserIdValidationLevel.DISABLED;
|
private SignerUserIdValidationLevel signerUserIdValidationLevel = SignerUserIdValidationLevel.DISABLED;
|
||||||
|
|
||||||
|
private boolean enableKeyParameterValidation = false;
|
||||||
|
|
||||||
public enum SignerUserIdValidationLevel {
|
public enum SignerUserIdValidationLevel {
|
||||||
/**
|
/**
|
||||||
* PGPainless will verify {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets in signatures strictly.
|
* PGPainless will verify {@link org.bouncycastle.bcpg.sig.SignerUserID} subpackets in signatures strictly.
|
||||||
|
@ -701,4 +703,31 @@ public final class Policy {
|
||||||
this.signerUserIdValidationLevel = signerUserIdValidationLevel;
|
this.signerUserIdValidationLevel = signerUserIdValidationLevel;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable validation of public key parameters when unlocking private keys.
|
||||||
|
* Disabled by default.
|
||||||
|
* When enabled, PGPainless will validate, whether public key parameters have been tampered with.
|
||||||
|
* This is a countermeasure against possible attacks described in the paper
|
||||||
|
* "Victory by KO: Attacking OpenPGP Using Key Overwriting" by Lara Bruseghini, Daniel Huigens, and Kenneth G. Paterson.
|
||||||
|
* Since these attacks are only possible in very special conditions (attacker has access to the encrypted private key),
|
||||||
|
* and the countermeasures are very costly, they are disabled by default, but can be enabled using this method.
|
||||||
|
*
|
||||||
|
* @see <a href="https://www.kopenpgp.com/#paper">KOpenPGP.com</a>
|
||||||
|
* @param enable boolean
|
||||||
|
* @return this
|
||||||
|
*/
|
||||||
|
public Policy setEnableKeyParameterValidation(boolean enable) {
|
||||||
|
this.enableKeyParameterValidation = enable;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true, if countermeasures against the KOpenPGP attacks are enabled, false otherwise.
|
||||||
|
*
|
||||||
|
* @return true if countermeasures are enabled, false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isEnableKeyParameterValidation() {
|
||||||
|
return enableKeyParameterValidation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -212,10 +212,12 @@ public class ModifiedPublicKeysInvestigation {
|
||||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("12345678"));
|
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("12345678"));
|
||||||
PGPSecretKeyRing dsa = PGPainless.readKeyRing().secretKeyRing(DSA);
|
PGPSecretKeyRing dsa = PGPainless.readKeyRing().secretKeyRing(DSA);
|
||||||
|
|
||||||
|
PGPainless.getPolicy().setEnableKeyParameterValidation(true);
|
||||||
assertThrows(KeyIntegrityException.class, () ->
|
assertThrows(KeyIntegrityException.class, () ->
|
||||||
UnlockSecretKey.unlockSecretKey(dsa.getSecretKey(KeyIdUtil.fromLongKeyId("b1bd1f049ec87f3d")), protector));
|
UnlockSecretKey.unlockSecretKey(dsa.getSecretKey(KeyIdUtil.fromLongKeyId("b1bd1f049ec87f3d")), protector));
|
||||||
assertThrows(KeyIntegrityException.class, () ->
|
assertThrows(KeyIntegrityException.class, () ->
|
||||||
UnlockSecretKey.unlockSecretKey(dsa.getSecretKey(KeyIdUtil.fromLongKeyId("f5ffdf6d71dd5789")), protector));
|
UnlockSecretKey.unlockSecretKey(dsa.getSecretKey(KeyIdUtil.fromLongKeyId("f5ffdf6d71dd5789")), protector));
|
||||||
|
PGPainless.getPolicy().setEnableKeyParameterValidation(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -223,8 +225,10 @@ public class ModifiedPublicKeysInvestigation {
|
||||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("12345678"));
|
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("12345678"));
|
||||||
PGPSecretKeyRing elgamal = PGPainless.readKeyRing().secretKeyRing(ELGAMAL);
|
PGPSecretKeyRing elgamal = PGPainless.readKeyRing().secretKeyRing(ELGAMAL);
|
||||||
|
|
||||||
|
PGPainless.getPolicy().setEnableKeyParameterValidation(true);
|
||||||
assertThrows(KeyIntegrityException.class, () ->
|
assertThrows(KeyIntegrityException.class, () ->
|
||||||
UnlockSecretKey.unlockSecretKey(elgamal.getSecretKey(KeyIdUtil.fromLongKeyId("f5ffdf6d71dd5789")), protector));
|
UnlockSecretKey.unlockSecretKey(elgamal.getSecretKey(KeyIdUtil.fromLongKeyId("f5ffdf6d71dd5789")), protector));
|
||||||
|
PGPainless.getPolicy().setEnableKeyParameterValidation(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -232,8 +236,10 @@ public class ModifiedPublicKeysInvestigation {
|
||||||
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(INJECTED_KEY);
|
PGPSecretKeyRing secretKeys = PGPainless.readKeyRing().secretKeyRing(INJECTED_KEY);
|
||||||
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("pass"));
|
SecretKeyRingProtector protector = SecretKeyRingProtector.unlockAnyKeyWith(Passphrase.fromPassword("pass"));
|
||||||
|
|
||||||
|
PGPainless.getPolicy().setEnableKeyParameterValidation(true);
|
||||||
assertThrows(KeyIntegrityException.class, () ->
|
assertThrows(KeyIntegrityException.class, () ->
|
||||||
UnlockSecretKey.unlockSecretKey(secretKeys.getSecretKey(), protector));
|
UnlockSecretKey.unlockSecretKey(secretKeys.getSecretKey(), protector));
|
||||||
|
PGPainless.getPolicy().setEnableKeyParameterValidation(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Reference in a new issue