mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-22 19:08:00 +01:00
Native support for notBefore and notAfter signature creation time constraints
This commit is contained in:
parent
6a108cb8c0
commit
099b160656
6 changed files with 68 additions and 45 deletions
|
@ -43,8 +43,8 @@ import org.pgpainless.util.Passphrase;
|
|||
*/
|
||||
public class ConsumerOptions {
|
||||
|
||||
private Date verifyNotBefore;
|
||||
private Date verifyNotAfter;
|
||||
private Date verifyNotBefore = null;
|
||||
private Date verifyNotAfter = new Date();
|
||||
|
||||
// Set of verification keys
|
||||
private final Set<PGPPublicKeyRing> certificates = new HashSet<>();
|
||||
|
@ -59,39 +59,45 @@ public class ConsumerOptions {
|
|||
|
||||
|
||||
/**
|
||||
* Consider signatures made before the given timestamp invalid.
|
||||
*
|
||||
* Note: This method does not have any effect yet.
|
||||
* TODO: Add support for custom signature validity date ranges
|
||||
* Consider signatures on the message made before the given timestamp invalid.
|
||||
* Null means no limitation.
|
||||
*
|
||||
* @param timestamp timestamp
|
||||
* @return options
|
||||
*/
|
||||
public ConsumerOptions verifyNotBefore(Date timestamp) {
|
||||
this.verifyNotBefore = timestamp;
|
||||
throw new NotYetImplementedException();
|
||||
// return this;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Date getVerifyNotBefore() {
|
||||
/**
|
||||
* Return the earliest creation date on which signatures on the message are considered valid.
|
||||
* Signatures made earlier than this date are considered invalid.
|
||||
*
|
||||
* @return earliest allowed signature creation date or null
|
||||
*/
|
||||
public @Nullable Date getVerifyNotBefore() {
|
||||
return verifyNotBefore;
|
||||
}
|
||||
|
||||
/**
|
||||
* Consider signatures made after the given timestamp invalid.
|
||||
*
|
||||
* Note: This method does not have any effect yet.
|
||||
* TODO: Add support for custom signature validity date ranges
|
||||
* Consider signatures on the message made after the given timestamp invalid.
|
||||
* Null means no limitation.
|
||||
*
|
||||
* @param timestamp timestamp
|
||||
* @return options
|
||||
*/
|
||||
public ConsumerOptions verifyNotAfter(Date timestamp) {
|
||||
this.verifyNotAfter = timestamp;
|
||||
throw new NotYetImplementedException();
|
||||
// return this;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the latest possible creation date on which signatures made on the message are considered valid.
|
||||
* Signatures made later than this date are considered invalid.
|
||||
*
|
||||
* @return Latest possible creation date or null.
|
||||
*/
|
||||
public Date getVerifyNotAfter() {
|
||||
return verifyNotAfter;
|
||||
}
|
||||
|
|
|
@ -213,7 +213,7 @@ public final class DecryptionStreamFactory {
|
|||
}
|
||||
|
||||
return new SignatureVerifyingInputStream(literalDataInputStream,
|
||||
objectFactory, verifiableOnePassSignatures, resultBuilder);
|
||||
objectFactory, verifiableOnePassSignatures, options, resultBuilder);
|
||||
}
|
||||
|
||||
private InputStream decrypt(@Nonnull PGPEncryptedDataList encryptedDataList)
|
||||
|
|
|
@ -17,12 +17,12 @@ package org.pgpainless.decryption_verification;
|
|||
|
||||
import static org.pgpainless.signature.SignatureValidator.signatureIsEffective;
|
||||
import static org.pgpainless.signature.SignatureValidator.signatureStructureIsAcceptable;
|
||||
import static org.pgpainless.signature.SignatureValidator.verifySignatureCreationTimeIsInBounds;
|
||||
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.security.SignatureException;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
@ -47,6 +47,7 @@ public class SignatureVerifyingInputStream extends FilterInputStream {
|
|||
|
||||
private final PGPObjectFactory objectFactory;
|
||||
private final Map<OpenPgpV4Fingerprint, OnePassSignature> onePassSignatures;
|
||||
private final ConsumerOptions options;
|
||||
private final OpenPgpMetadata.Builder resultBuilder;
|
||||
|
||||
private boolean validated = false;
|
||||
|
@ -54,9 +55,11 @@ public class SignatureVerifyingInputStream extends FilterInputStream {
|
|||
protected SignatureVerifyingInputStream(@Nonnull InputStream inputStream,
|
||||
@Nonnull PGPObjectFactory objectFactory,
|
||||
@Nonnull Map<OpenPgpV4Fingerprint, OnePassSignature> onePassSignatures,
|
||||
@Nonnull ConsumerOptions options,
|
||||
@Nonnull OpenPgpMetadata.Builder resultBuilder) {
|
||||
super(inputStream);
|
||||
this.objectFactory = objectFactory;
|
||||
this.options = options;
|
||||
this.resultBuilder = resultBuilder;
|
||||
this.onePassSignatures = onePassSignatures;
|
||||
|
||||
|
@ -116,7 +119,8 @@ public class SignatureVerifyingInputStream extends FilterInputStream {
|
|||
try {
|
||||
PGPPublicKey signingKey = onePassSignature.getVerificationKeys().getPublicKey(signature.getKeyID());
|
||||
signatureStructureIsAcceptable(signingKey, policy).verify(signature);
|
||||
signatureIsEffective(new Date()).verify(signature);
|
||||
verifySignatureCreationTimeIsInBounds(options.getVerifyNotBefore(), options.getVerifyNotAfter()).verify(signature);
|
||||
signatureIsEffective().verify(signature);
|
||||
|
||||
SignatureChainValidator.validateSigningKey(signature, onePassSignature.getVerificationKeys(), PGPainless.getPolicy());
|
||||
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.pgpainless.key.OpenPgpV4Fingerprint;
|
|||
import org.pgpainless.policy.Policy;
|
||||
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
|
||||
import org.pgpainless.util.BCUtil;
|
||||
import org.pgpainless.util.DateUtil;
|
||||
import org.pgpainless.util.NotationRegistry;
|
||||
|
||||
public abstract class SignatureValidator {
|
||||
|
@ -664,6 +665,15 @@ public abstract class SignatureValidator {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a signature is effective right now.
|
||||
*
|
||||
* @return validator
|
||||
*/
|
||||
public static SignatureValidator signatureIsEffective() {
|
||||
return signatureIsEffective(new Date());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a signature is effective at the given reference date.
|
||||
*
|
||||
|
@ -997,4 +1007,21 @@ public abstract class SignatureValidator {
|
|||
};
|
||||
}
|
||||
|
||||
public static SignatureValidator verifySignatureCreationTimeIsInBounds(Date notBefore, Date notAfter) {
|
||||
return new SignatureValidator() {
|
||||
@Override
|
||||
public void verify(PGPSignature signature) throws SignatureValidationException {
|
||||
Date timestamp = signature.getCreationTime();
|
||||
if (notBefore != null && timestamp.before(notBefore)) {
|
||||
throw new SignatureValidationException("Signature was made before the earliest allowed signature creation time. Created: " +
|
||||
DateUtil.formatUTCDate(timestamp) + " Earliest allowed: " + DateUtil.formatUTCDate(notBefore));
|
||||
}
|
||||
if (notAfter != null && timestamp.after(notAfter)) {
|
||||
throw new SignatureValidationException("Signature was made after the latest allowed signature creation time. Created: " +
|
||||
DateUtil.formatUTCDate(timestamp) + " Latest allowed: " + DateUtil.formatUTCDate(notAfter));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class DecryptImpl implements Decrypt {
|
|||
try {
|
||||
consumerOptions.verifyNotBefore(timestamp);
|
||||
} catch (NotYetImplementedException e) {
|
||||
// throw new SOPGPException.UnsupportedOption();
|
||||
throw new SOPGPException.UnsupportedOption();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ public class DecryptImpl implements Decrypt {
|
|||
try {
|
||||
consumerOptions.verifyNotAfter(timestamp);
|
||||
} catch (NotYetImplementedException e) {
|
||||
// throw new SOPGPException.UnsupportedOption();
|
||||
throw new SOPGPException.UnsupportedOption();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -91,7 +91,7 @@ public class DecryptImpl implements Decrypt {
|
|||
}
|
||||
|
||||
@Override
|
||||
public DecryptImpl withPassword(String password) throws SOPGPException.PasswordNotHumanReadable, SOPGPException.UnsupportedOption {
|
||||
public DecryptImpl withPassword(String password) {
|
||||
consumerOptions.addDecryptionPassphrase(Passphrase.fromPassword(password));
|
||||
String withoutTrailingWhitespace = removeTrailingWhitespace(password);
|
||||
if (!password.equals(withoutTrailingWhitespace)) {
|
||||
|
@ -158,17 +158,10 @@ public class DecryptImpl implements Decrypt {
|
|||
List<Verification> verificationList = new ArrayList<>();
|
||||
for (SubkeyIdentifier verifiedSigningKey : metadata.getVerifiedSignatures().keySet()) {
|
||||
PGPSignature signature = metadata.getVerifiedSignatures().get(verifiedSigningKey);
|
||||
Date verifyNotBefore = consumerOptions.getVerifyNotBefore();
|
||||
Date verifyNotAfter = consumerOptions.getVerifyNotAfter();
|
||||
|
||||
if (verifyNotAfter == null || !signature.getCreationTime().after(verifyNotAfter)) {
|
||||
if (verifyNotBefore == null || !signature.getCreationTime().before(verifyNotBefore)) {
|
||||
verificationList.add(new Verification(
|
||||
signature.getCreationTime(),
|
||||
verifiedSigningKey.getSubkeyFingerprint().toString(),
|
||||
verifiedSigningKey.getPrimaryKeyFingerprint().toString()));
|
||||
}
|
||||
}
|
||||
verificationList.add(new Verification(
|
||||
signature.getCreationTime(),
|
||||
verifiedSigningKey.getSubkeyFingerprint().toString(),
|
||||
verifiedSigningKey.getPrimaryKeyFingerprint().toString()));
|
||||
}
|
||||
|
||||
if (!consumerOptions.getCertificates().isEmpty()) {
|
||||
|
|
|
@ -44,7 +44,7 @@ public class VerifyImpl implements Verify {
|
|||
try {
|
||||
options.verifyNotBefore(timestamp);
|
||||
} catch (NotYetImplementedException e) {
|
||||
// throw new SOPGPException.UnsupportedOption();
|
||||
throw new SOPGPException.UnsupportedOption();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -54,7 +54,7 @@ public class VerifyImpl implements Verify {
|
|||
try {
|
||||
options.verifyNotAfter(timestamp);
|
||||
} catch (NotYetImplementedException e) {
|
||||
// throw new SOPGPException.UnsupportedOption();
|
||||
throw new SOPGPException.UnsupportedOption();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -97,17 +97,10 @@ public class VerifyImpl implements Verify {
|
|||
|
||||
for (SubkeyIdentifier verifiedSigningKey : metadata.getVerifiedSignatures().keySet()) {
|
||||
PGPSignature signature = metadata.getVerifiedSignatures().get(verifiedSigningKey);
|
||||
Date verifyNotBefore = options.getVerifyNotBefore();
|
||||
Date verifyNotAfter = options.getVerifyNotAfter();
|
||||
|
||||
if (verifyNotAfter == null || !signature.getCreationTime().after(verifyNotAfter)) {
|
||||
if (verifyNotBefore == null || !signature.getCreationTime().before(verifyNotBefore)) {
|
||||
verificationList.add(new Verification(
|
||||
signature.getCreationTime(),
|
||||
verifiedSigningKey.getSubkeyFingerprint().toString(),
|
||||
verifiedSigningKey.getPrimaryKeyFingerprint().toString()));
|
||||
}
|
||||
}
|
||||
verificationList.add(new Verification(
|
||||
signature.getCreationTime(),
|
||||
verifiedSigningKey.getSubkeyFingerprint().toString(),
|
||||
verifiedSigningKey.getPrimaryKeyFingerprint().toString()));
|
||||
}
|
||||
|
||||
if (!options.getCertificates().isEmpty()) {
|
||||
|
|
Loading…
Reference in a new issue