1
0
Fork 0
mirror of https://github.com/pgpainless/pgpainless.git synced 2025-12-10 06:11:08 +01:00

Implement signature verification with certificate stores as cert source

This commit is contained in:
Paul Schaub 2022-08-25 19:46:28 +02:00
parent 22abb62443
commit 4594b494a9
4 changed files with 257 additions and 53 deletions

View file

@ -6,10 +6,12 @@ package org.pgpainless.decryption_verification;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -23,6 +25,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPSignature;
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
import org.pgpainless.PGPainless;
import org.pgpainless.decryption_verification.cleartext_signatures.InMemoryMultiPassStrategy;
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy;
import org.pgpainless.key.SubkeyIdentifier;
@ -30,6 +33,9 @@ import org.pgpainless.key.protection.SecretKeyRingProtector;
import org.pgpainless.signature.SignatureUtils;
import org.pgpainless.util.Passphrase;
import org.pgpainless.util.SessionKey;
import pgp.certificate_store.PGPCertificateStore;
import pgp.certificate_store.certificate.Certificate;
import pgp.certificate_store.exception.BadDataException;
/**
* Options for decryption and signature verification.
@ -43,8 +49,7 @@ public class ConsumerOptions {
private Date verifyNotBefore = null;
private Date verifyNotAfter = new Date();
// Set of verification keys
private final Set<PGPPublicKeyRing> certificates = new HashSet<>();
private final CertificateSource certificates = new CertificateSource();
private final Set<PGPSignature> detachedSignatures = new HashSet<>();
private MissingPublicKeyCallback missingCertificateCallback = null;
@ -113,7 +118,7 @@ public class ConsumerOptions {
* @return options
*/
public ConsumerOptions addVerificationCert(PGPPublicKeyRing verificationCert) {
this.certificates.add(verificationCert);
this.certificates.addCertificate(verificationCert);
return this;
}
@ -130,6 +135,11 @@ public class ConsumerOptions {
return this;
}
public ConsumerOptions addVerificationCerts(PGPCertificateStore certificateStore) {
this.certificates.addStore(certificateStore);
return this;
}
public ConsumerOptions addVerificationOfDetachedSignatures(InputStream signatureInputStream) throws IOException, PGPException {
List<PGPSignature> signatures = SignatureUtils.readSignatures(signatureInputStream);
return addVerificationOfDetachedSignatures(signatures);
@ -266,8 +276,19 @@ public class ConsumerOptions {
return Collections.unmodifiableSet(decryptionPassphrases);
}
/**
* Return the explicitly set verification certificates.
*
* @deprecated use {@link #getCertificateSource()} instead.
* @return verification certs
*/
@Deprecated
public @Nonnull Set<PGPPublicKeyRing> getCertificates() {
return Collections.unmodifiableSet(certificates);
return certificates.getExplicitCertificates();
}
public @Nonnull CertificateSource getCertificateSource() {
return certificates;
}
public @Nullable MissingPublicKeyCallback getMissingCertificateCallback() {
@ -385,4 +406,68 @@ public class ConsumerOptions {
public MultiPassStrategy getMultiPassStrategy() {
return multiPassStrategy;
}
public static class CertificateSource {
private List<PGPCertificateStore> stores = new ArrayList<>();
private Set<PGPPublicKeyRing> explicitCertificates = new HashSet<>();
/**
* Add a certificate store as source for verification certificates.
*
* @param certificateStore cert store
*/
public void addStore(PGPCertificateStore certificateStore) {
this.stores.add(certificateStore);
}
/**
* Add a certificate as verification cert explicitly.
*
* @param certificate certificate
*/
public void addCertificate(PGPPublicKeyRing certificate) {
this.explicitCertificates.add(certificate);
}
/**
* Return the set of explicitly set verification certificates.
* @return explicitly set verification certs
*/
public Set<PGPPublicKeyRing> getExplicitCertificates() {
return Collections.unmodifiableSet(explicitCertificates);
}
/**
* Return a certificate which contains a subkey with the given keyId.
* This method first checks all explicitly set verification certs and if no cert is found it consults
* the certificate stores.
*
* @param keyId key id
* @return certificate
*/
public PGPPublicKeyRing getCertificate(long keyId) {
for (PGPPublicKeyRing cert : explicitCertificates) {
if (cert.getPublicKey(keyId) != null) {
return cert;
}
}
for (PGPCertificateStore store : stores) {
try {
Iterator<Certificate> certs = store.getCertificatesBySubkeyId(keyId);
if (!certs.hasNext()) {
continue;
}
Certificate cert = certs.next();
PGPPublicKeyRing publicKey = PGPainless.readKeyRing().publicKeyRing(cert.getInputStream());
return publicKey;
} catch (IOException | BadDataException e) {
continue;
}
}
return null;
}
}
}