1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2024-12-23 03:17:58 +01:00

Work on signaturePicker

This commit is contained in:
Paul Schaub 2021-05-21 16:30:48 +02:00
parent a30767eb91
commit 6cb9091b2a
9 changed files with 614 additions and 337 deletions

View file

@ -16,17 +16,132 @@
package org.pgpainless.key;
import java.util.List;
import java.util.Map;
import javax.annotation.Nullable;
import org.bouncycastle.bcpg.UserAttributePacket;
import org.bouncycastle.openpgp.PGPSignature;
import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.exception.SignatureValidationException;
import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.util.NonEmptyList;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
public interface EvaluatedKeyRing {
PGPSignature getUserIdCertification(String userId);
class EvaluatedSignature {
private final PGPSignature signature;
private final SignatureValidationException exception;
PGPSignature getUserIdRevocation(String userId);
PGPSignature getValidSignature() throws SignatureValidationException {
if (getException() != null) {
throw new SignatureValidationException("Signature is not valid.", getException());
}
return signature;
}
SignatureValidationException getException() {
return exception;
}
public EvaluatedSignature(PGPSignature signature, SignatureValidationException exception) {
this.signature = signature;
this.exception = exception;
}
}
/**
* Return a {@link Map} of user-ids and associated user-id certification signatures.
* Each map entry consists of a user-id and a {@link NonEmptyList} of associated certification signatures which
* contains the latest non-revoking certification signature as its first element.
*
* @return map of user-ids and certifications
*/
Map<String, NonEmptyList<PGPSignature>> getUserIdCertifications();
/**
* Return the latest user-id certification signature associated to the provided user-id.
*
* @param userId user-id
* @return latest user-id certification signature
* @throws IllegalArgumentException if the key doesn't have at least one certification signature for the
* provided user-id.
*/
default PGPSignature getUserIdCertification(String userId) {
NonEmptyList<PGPSignature> userIdCerts = getUserIdCertifications().get(userId);
if (userIdCerts == null) {
throw new IllegalArgumentException("No user-id '" + userId + "' found on the key.");
}
return userIdCerts.get();
}
/**
* Return a {@link Map} of user-ids and associated user-id revocation signatures.
*
* @return map of user-ids and revocations
*/
Map<String, List<PGPSignature>> getUserIdRevocations();
/**
* Return the latest, hardest revocation signature for the passed in user-id.
*
* @param userId user-id
* @return latest hardest revocation signature
* @throws IllegalArgumentException if the key doesn't have at least one certification signature for the given user-id.
*/
default PGPSignature getUserIdRevocation(String userId) {
List<PGPSignature> userIdRevs = getUserIdRevocations().get(userId);
if (userIdRevs == null) {
throw new IllegalArgumentException("No user-id '" + userId + "' found on the key.");
}
return userIdRevs.isEmpty() ? null : userIdRevs.get(0);
}
default boolean isRevoked(String userId) {
PGPSignature latestCertification = getUserIdCertification(userId);
PGPSignature latestRevocation = getUserIdRevocation(userId);
if (latestRevocation == null) {
return false;
}
return latestRevocation.getCreationTime().after(latestCertification.getCreationTime())
|| SignatureUtils.isHardRevocation(latestRevocation);
}
/**
* Return a {@link Map} of {@link UserAttributePacket UserAttributePackets} and associated certification signatures.
* Each map entry consists of a {@link UserAttributePacket} and a {@link NonEmptyList} of associated certification
* signatures which contains the latest non-revoking certification signtaure as its first element.
*
* @return map of user-attributes and certifications
*/
Map<UserAttributePacket, NonEmptyList<PGPSignature>> getUserAttributeCertifications();
/**
* Return the latest certification signature for the provided {@link UserAttributePacket}.
*
* @param userAttribute user attribute
* @return latest certification signature
* @throws IllegalArgumentException if the key doesn't carry such user-attribute
*/
default PGPSignature getUserAttributeCertification(UserAttributePacket userAttribute) {
NonEmptyList<PGPSignature> userAttrCerts = getUserAttributeCertifications().get(userAttribute);
if (userAttrCerts == null) {
throw new IllegalArgumentException("No such user-attribute found on the key.");
}
return userAttrCerts.get();
}
Map<UserAttributePacket, List<PGPSignature>> getUserAttributeRevocations();
default PGPSignature getUserAttributeRevocation(UserAttributePacket userAttribute) {
List<PGPSignature> userAttrRevs = getUserAttributeRevocations().get(userAttribute);
if (userAttrRevs == null) {
throw new IllegalArgumentException("No such user-attribute found on the key.");
}
return userAttrRevs.isEmpty() ? null : userAttrRevs.get(0);
}
PGPSignature getSubkeyBinding(long subkeyId);

View file

@ -26,17 +26,13 @@ import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyRing;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.PGPUserAttributeSubpacketVector;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.key.info.KeyRingInfo;
import org.pgpainless.key.util.KeyRingUtils;
import org.pgpainless.policy.Policy;
import org.pgpainless.signature.SelectSignatureFromKey;
import org.pgpainless.signature.SignatureCreationDateComparator;
import org.pgpainless.exception.SignatureValidationException;
import org.pgpainless.implementation.ImplementationFactory;
import org.pgpainless.policy.Policy;
import org.pgpainless.signature.SignatureCreationDateComparator;
import org.pgpainless.signature.SignatureValidator;
import org.pgpainless.util.CollectionUtils;
@ -146,115 +142,4 @@ public class KeyRingValidator {
return blank;
}
public static <R extends PGPKeyRing> R getKeyRingAtDate(R keyRing, KeyRingInfo info) {
Iterator<PGPPublicKey> iterator = keyRing.getPublicKeys();
while (iterator.hasNext()) {
PGPPublicKey publicKey = iterator.next();
if (publicKey.isMasterKey()) {
keyRing = assessPrimaryKeyAtDate(publicKey, keyRing, info);
} else {
keyRing = assessSubkeyAtDate(publicKey, keyRing, info);
}
}
return keyRing;
}
private static <R extends PGPKeyRing> R assessPrimaryKeyAtDate(PGPPublicKey primaryKey, PGPKeyRing keyRing, KeyRingInfo info) {
if (!primaryKey.isMasterKey()) {
throw new IllegalArgumentException("Passed in key is not a primary key");
}
// Direct Key Signatures
PGPSignature latestSelfSig = info.getCurrentDirectKeySelfSignature();
PGPSignature latestSelfRevocation = info.getRevocationSelfSignature();
// User-ID certifications
Iterator<String> userIdIterator = primaryKey.getUserIDs();
while (userIdIterator.hasNext()) {
String userId = userIdIterator.next();
boolean isUserIdBound = false;
Iterator<PGPSignature> userIdSigIterator = primaryKey.getSignaturesForID(userId);
while (userIdSigIterator.hasNext()) {
PGPSignature userIdSig = userIdSigIterator.next();
if (!SelectSignatureFromKey.isValidSignatureOnUserId(userId, primaryKey)
.accept(userIdSig, primaryKey, keyRing)) {
primaryKey = PGPPublicKey.removeCertification(primaryKey, userId, userIdSig);
continue;
}
isUserIdBound = true;
}
if (!isUserIdBound) {
primaryKey = PGPPublicKey.removeCertification(primaryKey, userId);
}
}
// Revocations
Iterator<PGPSignature> revocationSignatures = primaryKey.getSignaturesOfType(SignatureType.KEY_REVOCATION.getCode());
while (revocationSignatures.hasNext()) {
PGPSignature revocationSig = revocationSignatures.next();
if (!SelectSignatureFromKey.isValidKeyRevocationSignature(primaryKey)
.accept(revocationSig, primaryKey, keyRing)) {
primaryKey = PGPPublicKey.removeCertification(primaryKey, revocationSig);
}
}
return (R) replacePublicKey(keyRing, primaryKey);
}
private static <R extends PGPKeyRing> R assessSubkeyAtDate(PGPPublicKey subkey, PGPKeyRing keyRing, KeyRingInfo info) {
if (subkey.isMasterKey()) {
throw new IllegalArgumentException("Passed in key is not a subkey");
}
// Subkey binding sigs
Iterator<PGPSignature> subkeyBindingSigIterator = subkey.getSignaturesOfType(SignatureType.SUBKEY_BINDING.getCode());
while (subkeyBindingSigIterator.hasNext()) {
PGPSignature signature = subkeyBindingSigIterator.next();
if (!SelectSignatureFromKey.isValidSubkeyBindingSignature(keyRing.getPublicKey(), subkey)
.accept(signature, subkey, keyRing)) {
subkey = PGPPublicKey.removeCertification(subkey, signature);
}
}
// Subkey revocation sigs
Iterator<PGPSignature> revocationSigIterator = subkey.getSignaturesOfType(SignatureType.SUBKEY_REVOCATION.getCode());
while (revocationSigIterator.hasNext()) {
PGPSignature signature = revocationSigIterator.next();
if (!SelectSignatureFromKey.isValidSubkeyRevocationSignature().accept(signature, subkey, keyRing)) {
subkey = PGPPublicKey.removeCertification(subkey, signature);
}
}
Iterator<PGPSignature> directKeySigIterator = subkey.getSignaturesOfType(SignatureType.DIRECT_KEY.getCode());
while (directKeySigIterator.hasNext()) {
PGPSignature signature = directKeySigIterator.next();
PGPPublicKey creator = keyRing.getPublicKey(signature.getKeyID());
if (creator == null) {
// remove external signature
subkey = PGPPublicKey.removeCertification(subkey, signature);
continue;
}
if (!SelectSignatureFromKey.isValidDirectKeySignature(creator, subkey)
.accept(signature, subkey, keyRing)) {
subkey = PGPPublicKey.removeCertification(subkey, signature);
}
}
return (R) replacePublicKey(keyRing, subkey);
}
private static PGPKeyRing replacePublicKey(PGPKeyRing keyRing, PGPPublicKey publicKey) {
if (keyRing instanceof PGPPublicKeyRing) {
keyRing = PGPPublicKeyRing.insertPublicKey((PGPPublicKeyRing) keyRing, publicKey);
} else if (keyRing instanceof PGPSecretKeyRing) {
PGPSecretKeyRing secretKeys = (PGPSecretKeyRing) keyRing;
PGPPublicKeyRing publicKeys = KeyRingUtils.publicKeyRingFrom(secretKeys);
publicKeys = PGPPublicKeyRing.insertPublicKey(publicKeys, publicKey);
secretKeys = PGPSecretKeyRing.replacePublicKeys(secretKeys, publicKeys);
keyRing = secretKeys;
}
return keyRing;
}
}

View file

@ -629,8 +629,8 @@ public class KeyRingInfo {
private final Map<Long, PGPSignature> subkeyBindings;
public Signatures(PGPKeyRing keyRing, Date evaluationDate, Policy policy) {
primaryKeyRevocation = SignaturePicker.pickCurrentRevocationSelfSignature(keyRing, evaluationDate);
primaryKeySelfSignature = SignaturePicker.pickCurrentDirectKeySelfSignature(keyRing, evaluationDate);
primaryKeyRevocation = SignaturePicker.pickCurrentRevocationSelfSignature(keyRing, policy, evaluationDate);
primaryKeySelfSignature = SignaturePicker.pickLatestDirectKeySignature(keyRing, policy, evaluationDate);
userIdRevocations = new HashMap<>();
userIdCertifications = new HashMap<>();
subkeyRevocations = new HashMap<>();
@ -638,11 +638,11 @@ public class KeyRingInfo {
for (Iterator<String> it = keyRing.getPublicKey().getUserIDs(); it.hasNext(); ) {
String userId = it.next();
PGPSignature revocation = SignaturePicker.pickCurrentUserIdRevocationSignature(keyRing, userId, evaluationDate);
PGPSignature revocation = SignaturePicker.pickCurrentUserIdRevocationSignature(keyRing, userId, policy, evaluationDate);
if (revocation != null) {
userIdRevocations.put(userId, revocation);
}
PGPSignature certification = SignaturePicker.pickCurrentUserIdCertificationSignature(keyRing, userId, evaluationDate);
PGPSignature certification = SignaturePicker.pickLatestUserIdCertificationSignature(keyRing, userId, policy, evaluationDate);
if (certification != null) {
userIdCertifications.put(userId, certification);
}
@ -652,11 +652,11 @@ public class KeyRingInfo {
keys.next(); // Skip primary key
while (keys.hasNext()) {
PGPPublicKey subkey = keys.next();
PGPSignature subkeyRevocation = SignaturePicker.pickCurrentSubkeyBindingRevocationSignature(keyRing, subkey, evaluationDate);
PGPSignature subkeyRevocation = SignaturePicker.pickCurrentSubkeyBindingRevocationSignature(keyRing, subkey, policy, evaluationDate);
if (subkeyRevocation != null) {
subkeyRevocations.put(subkey.getKeyID(), subkeyRevocation);
}
PGPSignature subkeyBinding = SignaturePicker.pickCurrentSubkeyBindingSignature(keyRing, subkey, evaluationDate);
PGPSignature subkeyBinding = SignaturePicker.pickLatestSubkeyBindingSignature(keyRing, subkey, policy, evaluationDate);
if (subkeyBinding != null) {
subkeyBindings.put(subkey.getKeyID(), subkeyBinding);
}

View file

@ -20,17 +20,12 @@ import java.util.Date;
import java.util.Iterator;
import java.util.List;
import org.bouncycastle.bcpg.sig.RevocationReason;
import org.bouncycastle.bcpg.sig.SignatureCreationTime;
import org.bouncycastle.openpgp.PGPKeyRing;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPSignature;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.SignatureType;
import org.pgpainless.exception.SignatureValidationException;
import org.pgpainless.key.util.RevocationAttributes;
import org.pgpainless.policy.Policy;
import org.pgpainless.signature.subpackets.SignatureSubpacketsUtil;
import org.pgpainless.util.CollectionUtils;
/**
@ -49,14 +44,14 @@ import org.pgpainless.util.CollectionUtils;
public class SignaturePicker {
/**
* Pick the most current (at the time of evaluation) key revocation signature.
* If there is a hard revocation signature, it is picked, regardless of expiration or creation time.
* Pick the, at validation date most recent valid key revocation signature.
* If there are hard revocation signatures, the latest hard revocation sig is picked, even if it was created after
* validationDate or if it is already expired.
*
* @param keyRing key ring
* @return most recent, valid key revocation signature
*/
public static PGPSignature pickCurrentRevocationSelfSignature(PGPKeyRing keyRing, Date validationDate) {
Policy policy = PGPainless.getPolicy();
public static PGPSignature pickCurrentRevocationSelfSignature(PGPKeyRing keyRing, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
List<PGPSignature> signatures = getSortedSignaturesOfType(primaryKey, SignatureType.KEY_REVOCATION);
@ -76,42 +71,36 @@ public class SignaturePicker {
}
/**
* Pick the current direct key self-signature on the primary key.
* Pick the, at validationDate most recent, valid direct key signature.
* This method might return null, if there is no direct key self-signature which is valid at validationDate.
*
* @param keyRing key ring
* @param validationDate validation date
* @return direct-key self-signature
*/
public static PGPSignature pickCurrentDirectKeySelfSignature(PGPKeyRing keyRing, Date validationDate) {
public static PGPSignature pickCurrentDirectKeySelfSignature(PGPKeyRing keyRing, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
return pickCurrentDirectKeySignature(primaryKey, primaryKey, keyRing, validationDate);
return pickCurrentDirectKeySignature(primaryKey, primaryKey, policy, validationDate);
}
/**
* Pick the current direct-key signature made by the signing key on the signed key.
* Pick the, at validationDate, latest, valid direct key signature made by signingKey on signedKey.
* This method might return null, if there is no direct key self signature which is valid at validationDate.
*
* @param signingKey key that created the signature
* @param signedKey key that carries the signature
* @param keyRing key ring
* @param validationDate validation date
* @return direct key sig
*/
public static PGPSignature pickCurrentDirectKeySignature(PGPPublicKey signingKey, PGPPublicKey signedKey, PGPKeyRing keyRing, Date validationDate) {
public static PGPSignature pickCurrentDirectKeySignature(PGPPublicKey signingKey, PGPPublicKey signedKey, Policy policy, Date validationDate) {
List<PGPSignature> directKeySignatures = getSortedSignaturesOfType(signedKey, SignatureType.DIRECT_KEY);
PGPSignature mostRecentDirectKeySigBySigningKey = null;
for (PGPSignature signature : directKeySignatures) {
if (!SelectSignatureFromKey.isWellFormed().accept(signature, signingKey, keyRing)) {
// signature is not well formed
continue;
}
if (!SelectSignatureFromKey.isValidAt(validationDate).accept(signature, signedKey, keyRing)) {
// Signature is either expired or not yet valid
continue;
}
if (!SelectSignatureFromKey.isValidDirectKeySignature(signingKey, signedKey).accept(signature, signedKey, keyRing)) {
// signature does not check out.
try {
SignatureValidator.verifyDirectKeySignature(signature, signingKey, signedKey, policy, validationDate);
} catch (SignatureValidationException e) {
// Direct key sig is not valid
continue;
}
mostRecentDirectKeySigBySigningKey = signature;
@ -121,57 +110,94 @@ public class SignaturePicker {
}
/**
* Pick the most recent user-id revocation signature.
* Pick the, at validationDate, latest direct key signature.
* This method might return an expired signature.
* If there are more than one direct-key signature, and some of those are not expired, the latest non-expired
* yet already effective direct-key signature will be returned.
*
* @param keyRing key ring
* @param validationDate validation date
* @return latest direct key signature
*/
public static PGPSignature pickLatestDirectKeySignature(PGPKeyRing keyRing, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
return pickLatestDirectKeySignature(primaryKey, primaryKey, policy, validationDate);
}
/**
* Pick the, at validationDate, latest direct key signature made by signingKey on signedKey.
* This method might return an expired signature.
* If a non-expired direct-key signature exists, the latest non-expired yet already effective direct-key
* signature will be returned.
*
* @param signingKey signing key (key that made the sig)
* @param signedKey signed key (key that carries the sig)
* @param validationDate date of validation
* @return latest direct key sig
*/
public static PGPSignature pickLatestDirectKeySignature(PGPPublicKey signingKey, PGPPublicKey signedKey, Policy policy, Date validationDate) {
List<PGPSignature> signatures = getSortedSignaturesOfType(signedKey, SignatureType.DIRECT_KEY);
PGPSignature latestDirectKeySignature = null;
for (PGPSignature signature : signatures) {
try {
SignatureValidator.signatureIsOfType(SignatureType.DIRECT_KEY).verify(signature);
SignatureValidator.signatureStructureIsAcceptable(signingKey, policy).verify(signature);
SignatureValidator.signatureIsAlreadyEffective(validationDate).verify(signature);
// if the currently latest signature is not yet expired, check if the next candidate is not yet expired
if (latestDirectKeySignature != null && !SignatureUtils.isSignatureExpired(latestDirectKeySignature, validationDate)) {
SignatureValidator.signatureIsNotYetExpired(validationDate).verify(signature);
}
SignatureValidator.correctSignatureOverKey(signingKey, signedKey).verify(signature);
} catch (SignatureValidationException e) {
// Direct key signature is not valid
continue;
}
latestDirectKeySignature = signature;
}
return latestDirectKeySignature;
}
/**
* Pick the, at validationDate most recent, valid user-id revocation signature.
* If there are hard revocation signatures, the latest hard revocation sig is picked, even if it was created after
* validationDate or if it is already expired.
*
* @param keyRing key ring
* @param userId user-Id that gets revoked
* @param validationDate validation date
* @return revocation signature
*/
public static PGPSignature pickCurrentUserIdRevocationSignature(PGPKeyRing keyRing, String userId, Date validationDate) {
public static PGPSignature pickCurrentUserIdRevocationSignature(PGPKeyRing keyRing, String userId, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
List<PGPSignature> signatures = getSortedSignaturesOfType(primaryKey, SignatureType.CERTIFICATION_REVOCATION);
Iterator<PGPSignature> certificationRevocations = primaryKey.getSignaturesOfType(SignatureType.CERTIFICATION_REVOCATION.getCode());
List<PGPSignature> signatures = CollectionUtils.iteratorToList(certificationRevocations);
Collections.sort(signatures, new SignatureCreationDateComparator());
PGPSignature mostRecentUserIdRevocation = null;
PGPSignature latestUserIdRevocation = null;
for (PGPSignature signature : signatures) {
if (!SelectSignatureFromKey.isWellFormed().accept(signature, primaryKey, keyRing)) {
// Sig is not well formed.
try {
SignatureValidator.verifyUserIdRevocation(userId, signature, primaryKey, policy, validationDate);
} catch (SignatureValidationException e) {
// User-id revocation is not valid
continue;
}
RevocationReason reason = SignatureSubpacketsUtil.getRevocationReason(signature);
if (reason != null && !RevocationAttributes.Reason.isHardRevocation(reason.getRevocationReason())) {
// reason code states soft revocation
if (!SelectSignatureFromKey.isValidAt(validationDate).accept(signature, primaryKey, keyRing)) {
// Soft revocation is either expired or not yet valid
continue;
}
}
if (!SelectSignatureFromKey.isValidCertificationRevocationSignature(primaryKey, userId)
.accept(signature, primaryKey, keyRing)) {
// sig does not check out for userid
continue;
}
mostRecentUserIdRevocation = signature;
latestUserIdRevocation = signature;
}
return mostRecentUserIdRevocation;
return latestUserIdRevocation;
}
/**
* Pick the most current certification self-signature for the given user-id.
* Pick the, at validationDate latest, valid certification self-signature for the given user-id.
* This method might return null, if there is no certification self signature for that user-id which is valid
* at validationDate.
*
* @param keyRing keyring
* @param userId userid
* @param validationDate validation date
* @return user-id certification
*/
public static PGPSignature pickCurrentUserIdCertificationSignature(PGPKeyRing keyRing, String userId, Date validationDate) {
public static PGPSignature pickCurrentUserIdCertificationSignature(PGPKeyRing keyRing, String userId, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
Iterator<PGPSignature> userIdSigIterator = primaryKey.getSignaturesForID(userId);
@ -180,21 +206,12 @@ public class SignaturePicker {
PGPSignature mostRecentUserIdCertification = null;
for (PGPSignature signature : signatures) {
if (!SelectSignatureFromKey.isWellFormed().accept(signature, primaryKey, keyRing)) {
// Sig not well formed
try {
SignatureValidator.verifyUserIdCertification(userId, signature, primaryKey, policy, validationDate);
} catch (SignatureValidationException e) {
// User-id certification is not valid
continue;
}
if (!SelectSignatureFromKey.isValidAt(validationDate).accept(signature, primaryKey, keyRing)) {
// Sig is either expired or not valid yet
continue;
}
if (!SelectSignatureFromKey.isValidSignatureOnUserId(userId, primaryKey).accept(signature, primaryKey, keyRing)) {
// Sig does not check out
continue;
}
mostRecentUserIdCertification = signature;
}
@ -202,57 +219,88 @@ public class SignaturePicker {
}
/**
* Return the current subkey binding revocation signature for the given subkey.
* Pick the, at validationDate latest certification self-signature for the given user-id.
* This method might return an expired signature.
* If a non-expired user-id certification signature exists, the latest non-expired yet already effective
* user-id certification signature for the given user-id will be returned.
*
* @param keyRing keyring
* @param userId userid
* @param validationDate validation date
* @return user-id certification
*/
public static PGPSignature pickLatestUserIdCertificationSignature(PGPKeyRing keyRing, String userId, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
Iterator<PGPSignature> userIdSigIterator = primaryKey.getSignaturesForID(userId);
List<PGPSignature> signatures = CollectionUtils.iteratorToList(userIdSigIterator);
Collections.sort(signatures, new SignatureCreationDateComparator());
PGPSignature latestUserIdCert = null;
for (PGPSignature signature : signatures) {
try {
SignatureValidator.signatureIsCertification().verify(signature);
SignatureValidator.signatureStructureIsAcceptable(primaryKey, policy).verify(signature);
SignatureValidator.signatureIsAlreadyEffective(validationDate).verify(signature);
// if the currently latest signature is not yet expired, check if the next candidate is not yet expired
if (latestUserIdCert != null && !SignatureUtils.isSignatureExpired(latestUserIdCert, validationDate)) {
SignatureValidator.signatureIsNotYetExpired(validationDate).verify(signature);
}
SignatureValidator.correctSignatureOverUserId(userId, primaryKey, primaryKey).verify(signature);
} catch (SignatureValidationException e) {
// User-id certification is not valid
continue;
}
latestUserIdCert = signature;
}
return latestUserIdCert;
}
/**
* Pick the, at validationDate most recent, valid subkey revocation signature.
* If there are hard revocation signatures, the latest hard revocation sig is picked, even if it was created after
* validationDate or if it is already expired.
*
* @param keyRing keyring
* @param subkey subkey
* @param validationDate validation date
* @return subkey revocation signature
*/
public static PGPSignature pickCurrentSubkeyBindingRevocationSignature(PGPKeyRing keyRing, PGPPublicKey subkey, Date validationDate) {
public static PGPSignature pickCurrentSubkeyBindingRevocationSignature(PGPKeyRing keyRing, PGPPublicKey subkey, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
if (primaryKey.getKeyID() == subkey.getKeyID()) {
throw new IllegalArgumentException("Primary key cannot have subkey binding revocations.");
}
List<PGPSignature> subkeyRevocationSigs = getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_BINDING);
PGPSignature mostRecentSubkeyRevocation = null;
List<PGPSignature> signatures = getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_BINDING);
PGPSignature latestSubkeyRevocation = null;
for (PGPSignature signature : subkeyRevocationSigs) {
if (!SelectSignatureFromKey.isWellFormed().accept(signature, primaryKey, keyRing)) {
// Signature is not well formed
for (PGPSignature signature : signatures) {
try {
SignatureValidator.verifySubkeyBindingRevocation(signature, primaryKey, subkey, policy, validationDate);
} catch (SignatureValidationException e) {
// subkey binding revocation is not valid
continue;
}
RevocationReason reason = SignatureSubpacketsUtil.getRevocationReason(signature);
if (reason != null && !RevocationAttributes.Reason.isHardRevocation(reason.getRevocationReason())) {
// reason code states soft revocation
if (!SelectSignatureFromKey.isValidAt(validationDate).accept(signature, primaryKey, keyRing)) {
// Soft revocation is either expired or not yet valid
continue;
}
}
if (!SelectSignatureFromKey.isValidSubkeyRevocationSignature().accept(signature, subkey, keyRing)) {
// Signature does not check out
continue;
}
mostRecentSubkeyRevocation = signature;
latestSubkeyRevocation = signature;
}
return mostRecentSubkeyRevocation;
return latestSubkeyRevocation;
}
/**
* Return the (at the time of validation) most recent, valid subkey binding signature
* made by the primary key of the key ring on the subkey.
* Pick the, at validationDate latest, valid subkey binding signature for the given subkey.
* This method might return null, if there is no subkey binding signature which is valid
* at validationDate.
*
* @param keyRing key ring
* @param subkey subkey
* @param validationDate date of validation
* @return most recent valid subkey binding signature
*/
public static PGPSignature pickCurrentSubkeyBindingSignature(PGPKeyRing keyRing, PGPPublicKey subkey, Date validationDate) {
public static PGPSignature pickCurrentSubkeyBindingSignature(PGPKeyRing keyRing, PGPPublicKey subkey, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
if (primaryKey.getKeyID() == subkey.getKeyID()) {
throw new IllegalArgumentException("Primary key cannot have subkey binding signature.");
@ -262,35 +310,68 @@ public class SignaturePicker {
PGPSignature mostCurrentValidSig = null;
for (PGPSignature signature : subkeyBindingSigs) {
// has hashed creation time, does not predate signing key creation date
if (!SelectSignatureFromKey.isWellFormed().accept(signature, primaryKey, keyRing)) {
// Signature is not well-formed. Reject.
try {
SignatureValidator.verifySubkeyBindingSignature(signature, primaryKey, subkey, policy, validationDate);
} catch (SignatureValidationException validationException) {
// Subkey binding sig is not valid
continue;
}
SignatureCreationTime creationTime = SignatureSubpacketsUtil.getSignatureCreationTime(signature);
if (creationTime.getTime().after(validationDate)) {
// signature is not yet valid
continue;
}
if (SignatureUtils.isSignatureExpired(signature, validationDate)) {
// Signature is expired
continue;
}
if (!SelectSignatureFromKey.isValidSubkeyBindingSignature(primaryKey, subkey)
.accept(signature, subkey, keyRing)) {
// Invalid subkey binding signature
continue;
}
mostCurrentValidSig = signature;
}
return mostCurrentValidSig;
}
/**
* Pick the, at validationDate latest subkey binding signature for the given subkey.
* This method might return an expired signature.
* If a non-expired subkey binding signature exists, the latest non-expired yet already effective
* subkey binding signature for the given subkey will be returned.
*
* @param keyRing key ring
* @param subkey subkey
* @param validationDate validationDate
* @return subkey binding signature
*/
public static PGPSignature pickLatestSubkeyBindingSignature(PGPKeyRing keyRing, PGPPublicKey subkey, Policy policy, Date validationDate) {
PGPPublicKey primaryKey = keyRing.getPublicKey();
if (primaryKey.getKeyID() == subkey.getKeyID()) {
throw new IllegalArgumentException("Primary key cannot have subkey binding signature.");
}
List<PGPSignature> signatures = getSortedSignaturesOfType(subkey, SignatureType.SUBKEY_BINDING);
PGPSignature latestSubkeyBinding = null;
for (PGPSignature signature : signatures) {
try {
SignatureValidator.signatureIsOfType(SignatureType.SUBKEY_BINDING).verify(signature);
SignatureValidator.signatureStructureIsAcceptable(primaryKey, policy).verify(signature);
SignatureValidator.signatureIsAlreadyEffective(validationDate).verify(signature);
// if the currently latest signature is not yet expired, check if the next candidate is not yet expired
if (latestSubkeyBinding != null && !SignatureUtils.isSignatureExpired(latestSubkeyBinding, validationDate)) {
SignatureValidator.signatureIsNotYetExpired(validationDate).verify(signature);
}
SignatureValidator.correctSubkeyBindingSignature(primaryKey, subkey).verify(signature);
} catch (SignatureValidationException e) {
// Subkey binding sig is not valid
continue;
}
latestSubkeyBinding = signature;
}
return latestSubkeyBinding;
}
/**
* Return a list of all signatures of the given {@link SignatureType} on the given key, sorted using a
* {@link SignatureCreationDateComparator}.
*
* The returned list will be sorted first by ascending signature creation time.
*
* @param key key
* @param type type of signatures which shall be collected and sorted
* @return sorted list of signatures
*/
private static List<PGPSignature> getSortedSignaturesOfType(PGPPublicKey key, SignatureType type) {
Iterator<PGPSignature> signaturesOfType = key.getSignaturesOfType(type.getCode());
List<PGPSignature> signatureList = CollectionUtils.iteratorToList(signaturesOfType);

View file

@ -178,7 +178,7 @@ public abstract class SignatureValidator {
signatureStructureIsAcceptable(primaryKey, policy).verify(signature);
signatureIsEffective(validationDate).verify(signature);
hasValidPrimaryKeyBindingSignatureIfRequired(primaryKey, subkey, policy, validationDate).verify(signature);
correctSignatureOverKey(primaryKey, subkey).verify(signature);
correctSubkeyBindingSignature(primaryKey, subkey).verify(signature);
return true;
}
@ -274,22 +274,34 @@ public abstract class SignatureValidator {
@Override
public void verify(PGPSignature signature) throws SignatureValidationException {
HashAlgorithm hashAlgorithm = HashAlgorithm.fromId(signature.getHashAlgorithm());
Policy.HashAlgorithmPolicy hashAlgorithmPolicy = null;
SignatureType type = SignatureType.valueOf(signature.getSignatureType());
if (type == SignatureType.CERTIFICATION_REVOCATION || type == SignatureType.KEY_REVOCATION || type == SignatureType.SUBKEY_REVOCATION) {
hashAlgorithmPolicy = policy.getRevocationSignatureHashAlgorithmPolicy();
} else {
hashAlgorithmPolicy = policy.getSignatureHashAlgorithmPolicy();
}
Policy.HashAlgorithmPolicy hashAlgorithmPolicy = getHashAlgorithmPolicyForSignature(signature, policy);
if (!hashAlgorithmPolicy.isAcceptable(signature.getHashAlgorithm())) {
throw new SignatureValidationException("Signature uses inacceptable hash algorithm " + hashAlgorithm);
throw new SignatureValidationException("Signature uses unacceptable hash algorithm " + hashAlgorithm);
}
}
};
}
/**
* Return the applicable {@link Policy.HashAlgorithmPolicy} for the given {@link PGPSignature}.
* Revocation signatures are being policed using a different policy than non-revocation signatures.
*
* @param signature signature
* @param policy revocation policy for revocation sigs, normal policy for non-rev sigs
* @return policy
*/
private static Policy.HashAlgorithmPolicy getHashAlgorithmPolicyForSignature(PGPSignature signature, Policy policy) {
Policy.HashAlgorithmPolicy hashAlgorithmPolicy = null;
SignatureType type = SignatureType.valueOf(signature.getSignatureType());
if (type == SignatureType.CERTIFICATION_REVOCATION || type == SignatureType.KEY_REVOCATION || type == SignatureType.SUBKEY_REVOCATION) {
hashAlgorithmPolicy = policy.getRevocationSignatureHashAlgorithmPolicy();
} else {
hashAlgorithmPolicy = policy.getSignatureHashAlgorithmPolicy();
}
return hashAlgorithmPolicy;
}
public static SignatureValidator signatureDoesNotHaveCriticalUnknownNotations(NotationRegistry registry) {
return new SignatureValidator() {
@Override
@ -324,15 +336,39 @@ public abstract class SignatureValidator {
}
public static SignatureValidator signatureIsEffective(Date validationDate) {
return new SignatureValidator() {
@Override
public void verify(PGPSignature signature) throws SignatureValidationException {
signatureIsAlreadyEffective(validationDate).verify(signature);
signatureIsNotYetExpired(validationDate).verify(signature);
}
};
}
public static SignatureValidator signatureIsAlreadyEffective(Date validationDate) {
return new SignatureValidator() {
@Override
public void verify(PGPSignature signature) throws SignatureValidationException {
Date signatureCreationTime = SignatureSubpacketsUtil.getSignatureCreationTime(signature).getTime();
// For hard revocations, skip the creation time check
if (!SignatureUtils.isHardRevocation(signature)) {
if (signatureCreationTime.after(validationDate)) {
throw new SignatureValidationException("Signature was created at " + signatureCreationTime + " and is therefore not yet valid at " + validationDate);
}
// Hard revocations are always effective
if (SignatureUtils.isHardRevocation(signature)) {
return;
}
if (signatureCreationTime.after(validationDate)) {
throw new SignatureValidationException("Signature was created at " + signatureCreationTime + " and is therefore not yet valid at " + validationDate);
}
}
};
}
public static SignatureValidator signatureIsNotYetExpired(Date validationDate) {
return new SignatureValidator() {
@Override
public void verify(PGPSignature signature) throws SignatureValidationException {
// Hard revocations do not expire
if (SignatureUtils.isHardRevocation(signature)) {
return;
}
Date signatureExpirationTime = SignatureSubpacketsUtil.getSignatureExpirationTimeAsDate(signature);
@ -420,6 +456,26 @@ public abstract class SignatureValidator {
};
}
public static SignatureValidator correctSubkeyBindingSignature(PGPPublicKey primaryKey, PGPPublicKey subkey) {
return new SignatureValidator() {
@Override
public void verify(PGPSignature signature) throws SignatureValidationException {
if (primaryKey.getKeyID() == subkey.getKeyID()) {
throw new SignatureValidationException("Primary key cannot be its own subkey.");
}
try {
signature.init(ImplementationFactory.getInstance().getPGPContentVerifierBuilderProvider(), primaryKey);
boolean valid = signature.verifyCertification(primaryKey, subkey);
if (!valid) {
throw new SignatureValidationException("Signature is not correct.");
}
} catch (PGPException e) {
throw new SignatureValidationException("Cannot verify subkey binding signature correctness", e);
}
}
};
}
public static SignatureValidator correctPrimaryKeyBindingSignature(PGPPublicKey primaryKey, PGPPublicKey subkey) {
return new SignatureValidator() {
@Override

View file

@ -0,0 +1,88 @@
/*
* Copyright 2021 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pgpainless.util;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import javax.annotation.Nonnull;
/**
* Utility class of an immutable list which cannot be empty.
* The first element can be accessed via {@link #get()} which is guaranteed to return a non-null value.
* The rest of the list can be accessed via {@link #getOthers()}, which is guaranteed to return a non-null list which is possibly empty.
* Lastly, the whole list can be accessed via {@link #getAll()}, which is guaranteed to return a non-empty list.
*
* @param <E> element type
*/
public class NonEmptyList<E> {
private final List<E> elements;
/**
* Create a singleton list from the given element.
*
* @param element element
*/
public NonEmptyList(E element) {
if (element == null) {
throw new IllegalArgumentException("Singleton element cannot be null.");
}
this.elements = Collections.singletonList(element);
}
/**
* Create a non-empty list from the given list of elements.
*
* @param elements elements
* @throws IllegalArgumentException if the provided list of elements is empty.
*/
public NonEmptyList(List<E> elements) {
if (elements.isEmpty()) {
throw new IllegalArgumentException("Underlying list cannot be empty.");
}
this.elements = Collections.unmodifiableList(elements);
}
/**
* Return the first element of the list.
*
* @return first
*/
public @Nonnull E get() {
return elements.get(0);
}
/**
* Return a list of all elements of the list except the first.
*
* @return list of all but the first element
*/
public @Nonnull List<E> getOthers() {
List<E> others = new LinkedList<>(elements);
others.remove(0);
return Collections.unmodifiableList(others);
}
/**
* Return a non-empty list of all elements of this list.
*
* @return all elements
*/
public List<E> getAll() {
return elements;
}
}

View file

@ -0,0 +1,35 @@
/*
* Copyright 2021 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pgpainless.util;
public class SignatureTree {
public interface Node {
long getKeyId();
}
public interface PrimaryKeyNode extends Node {
}
public interface SubkeyNode extends Node {
}
public interface SignatureNode extends Node {
}
}

View file

@ -0,0 +1,62 @@
/*
* Copyright 2021 Paul Schaub.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.pgpainless.util;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.jupiter.api.Test;
public class NonEmptyListTest {
@Test
public void testEmptyListThrows() {
assertThrows(IllegalArgumentException.class, () -> new NonEmptyList<>(Collections.emptyList()));
}
@Test
public void testSingleElementList() {
List<String> singleElement = Collections.singletonList("Hello");
NonEmptyList<String> nonEmpty = new NonEmptyList<>(singleElement);
assertEquals("Hello", nonEmpty.get());
assertTrue(nonEmpty.getOthers().isEmpty());
assertEquals(1, nonEmpty.getAll().size());
assertTrue(nonEmpty.getAll().contains("Hello"));
}
@Test
public void testSingletonElement() {
assertThrows(IllegalArgumentException.class, () -> new NonEmptyList<>((String) null));
NonEmptyList<String> nonEmpty = new NonEmptyList<>("Foo");
assertEquals("Foo", nonEmpty.get());
assertTrue(nonEmpty.getOthers().isEmpty());
assertEquals(Collections.singletonList("Foo"), nonEmpty.getAll());
}
@Test
public void testMultipleElements() {
List<String> multipleElements = Arrays.asList("Foo", "Bar", "Baz");
NonEmptyList<String> nonEmpty = new NonEmptyList<>(multipleElements);
assertEquals("Foo", nonEmpty.get());
assertEquals(Arrays.asList("Bar", "Baz"), nonEmpty.getOthers());
assertEquals(multipleElements, nonEmpty.getAll());
}
}

View file

@ -22,28 +22,22 @@ import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import javax.annotation.Nullable;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKey;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.util.io.Streams;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.DocumentSignatureType;
import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.algorithm.SymmetricKeyAlgorithm;
import org.pgpainless.encryption_signing.EncryptionBuilderInterface;
import org.pgpainless.encryption_signing.EncryptionOptions;
import org.pgpainless.encryption_signing.EncryptionStream;
import org.pgpainless.encryption_signing.ProducerOptions;
import org.pgpainless.encryption_signing.SigningOptions;
import org.pgpainless.key.OpenPgpV4Fingerprint;
import org.pgpainless.key.protection.KeyRingProtectionSettings;
import org.pgpainless.key.protection.CachingSecretKeyRingProtector;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.key.protection.passphrase_provider.SecretKeyPassphraseProvider;
import org.pgpainless.util.Passphrase;
import picocli.CommandLine;
@ -90,96 +84,57 @@ public class Encrypt implements Runnable {
System.exit(19);
}
PGPPublicKeyRing[] pubKeysArray = new PGPPublicKeyRing[certs.length];
EncryptionOptions encOpt = new EncryptionOptions();
SigningOptions signOpt = new SigningOptions();
for (int i = 0 ; i < certs.length; i++) {
try (InputStream fileIn = new FileInputStream(certs[i])) {
PGPPublicKeyRing publicKey = PGPainless.readKeyRing().publicKeyRing(fileIn);
pubKeysArray[i] = publicKey;
encOpt.addRecipient(publicKey);
} catch (IOException e) {
err_ln("Cannot read certificate " + certs[i].getName());
err_ln(e.getMessage());
System.exit(1);
}
}
PGPPublicKeyRingCollection publicKeys;
try {
publicKeys = new PGPPublicKeyRingCollection(Arrays.asList(pubKeysArray));
} catch (IOException | PGPException e) {
err_ln("Cannot construct public key collection.");
err_ln(e.getMessage());
System.exit(1);
return;
for (int i = 0; i < withPassword.length; i++) {
Passphrase passphrase = Passphrase.fromPassword(withPassword[i]);
encOpt.addPassphrase(passphrase);
}
PGPSecretKeyRing[] secretKeys = new PGPSecretKeyRing[signWith.length];
final Scanner scanner = new Scanner(System.in);
for (int i = 0; i < signWith.length; i++) {
try (FileInputStream fileIn = new FileInputStream(signWith[i])) {
PGPSecretKeyRing secretKey = PGPainless.readKeyRing().secretKeyRing(fileIn);
secretKeys[i] = secretKey;
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,
type == Type.text || type == Type.mime ?
DocumentSignatureType.CANONICAL_TEXT_DOCUMENT : DocumentSignatureType.BINARY_DOCUMENT);
} catch (IOException | PGPException e) {
err_ln("Cannot read secret key from file " + signWith[i].getName());
err_ln(e.getMessage());
System.exit(1);
}
}
Passphrase[] passphraseArray = new Passphrase[withPassword.length];
for (int i = 0; i < withPassword.length; i++) {
String password = withPassword[i];
passphraseArray[i] = Passphrase.fromPassword(password);
}
Map<Long, Passphrase> passphraseMap = new HashMap<>();
Scanner scanner = null;
for (PGPSecretKeyRing ring : secretKeys) {
for (PGPSecretKey key : ring) {
// Skip non-signing keys
PGPSignature signature = (PGPSignature) key.getPublicKey().getSignatures().next();
int flags = signature.getHashedSubPackets().getKeyFlags();
if (!key.isSigningKey() || !KeyFlag.hasKeyFlag(flags, KeyFlag.SIGN_DATA)) {
// Key cannot sign
continue;
}
if (key.getKeyEncryptionAlgorithm() == SymmetricKeyAlgorithm.NULL.getAlgorithmId()) {
passphraseMap.put(key.getKeyID(), Passphrase.emptyPassphrase());
} else {
print_ln("Please provide the passphrase for key " + new OpenPgpV4Fingerprint(key));
if (scanner == null) {
scanner = new Scanner(System.in);
}
String password = scanner.nextLine();
Passphrase passphrase = Passphrase.fromPassword(password.trim());
passphraseMap.put(key.getKeyID(), passphrase);
}
}
}
EncryptionBuilderInterface.ToRecipientsOrSign builder = PGPainless.encryptAndOrSign()
.onOutputStream(System.out)
.toRecipients(publicKeys)
.and();
for (Passphrase passphrase : passphraseArray) {
builder = builder.forPassphrase(passphrase).and();
}
EncryptionBuilderInterface.Armor builder_armor = null;
EncryptionBuilderInterface.SignWith builder1 = builder;
try {
if (signWith.length != 0) {
for (int i = 0; i < signWith.length; i++) {
PGPSecretKeyRing secretKeyRing = secretKeys[i];
EncryptionBuilderInterface.AdditionalSignWith additionalSignWith = builder1.signInlineWith(
SecretKeyRingProtector.unlockAllKeysWith(
passphraseMap.get(secretKeyRing.getPublicKey().getKeyID()),
secretKeyRing),
secretKeyRing, null,
type == Type.text || type == Type.mime ?
DocumentSignatureType.CANONICAL_TEXT_DOCUMENT : DocumentSignatureType.BINARY_DOCUMENT);
builder_armor = additionalSignWith;
builder1 = additionalSignWith.and();
}
} else {
builder_armor = builder.doNotSign();
}
EncryptionStream encryptionStream = !armor ? builder_armor.noArmor() : builder_armor.asciiArmor();
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
.onOutputStream(System.out)
.withOptions(ProducerOptions
.signAndEncrypt(encOpt, signOpt)
.setAsciiArmor(armor));
Streams.pipeAll(System.in, encryptionStream);