mirror of
https://github.com/pgpainless/pgpainless.git
synced 2024-12-22 19:08:00 +01:00
Implement signature verification with certificate stores as cert source
This commit is contained in:
parent
22abb62443
commit
4594b494a9
4 changed files with 257 additions and 53 deletions
|
@ -6,10 +6,12 @@ package org.pgpainless.decryption_verification;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -23,6 +25,7 @@ import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.bouncycastle.openpgp.PGPSignature;
|
import org.bouncycastle.openpgp.PGPSignature;
|
||||||
import org.bouncycastle.openpgp.operator.PublicKeyDataDecryptorFactory;
|
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.InMemoryMultiPassStrategy;
|
||||||
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy;
|
import org.pgpainless.decryption_verification.cleartext_signatures.MultiPassStrategy;
|
||||||
import org.pgpainless.key.SubkeyIdentifier;
|
import org.pgpainless.key.SubkeyIdentifier;
|
||||||
|
@ -30,6 +33,9 @@ import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
import org.pgpainless.signature.SignatureUtils;
|
import org.pgpainless.signature.SignatureUtils;
|
||||||
import org.pgpainless.util.Passphrase;
|
import org.pgpainless.util.Passphrase;
|
||||||
import org.pgpainless.util.SessionKey;
|
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.
|
* Options for decryption and signature verification.
|
||||||
|
@ -43,8 +49,7 @@ public class ConsumerOptions {
|
||||||
private Date verifyNotBefore = null;
|
private Date verifyNotBefore = null;
|
||||||
private Date verifyNotAfter = new Date();
|
private Date verifyNotAfter = new Date();
|
||||||
|
|
||||||
// Set of verification keys
|
private final CertificateSource certificates = new CertificateSource();
|
||||||
private final Set<PGPPublicKeyRing> certificates = new HashSet<>();
|
|
||||||
private final Set<PGPSignature> detachedSignatures = new HashSet<>();
|
private final Set<PGPSignature> detachedSignatures = new HashSet<>();
|
||||||
private MissingPublicKeyCallback missingCertificateCallback = null;
|
private MissingPublicKeyCallback missingCertificateCallback = null;
|
||||||
|
|
||||||
|
@ -113,7 +118,7 @@ public class ConsumerOptions {
|
||||||
* @return options
|
* @return options
|
||||||
*/
|
*/
|
||||||
public ConsumerOptions addVerificationCert(PGPPublicKeyRing verificationCert) {
|
public ConsumerOptions addVerificationCert(PGPPublicKeyRing verificationCert) {
|
||||||
this.certificates.add(verificationCert);
|
this.certificates.addCertificate(verificationCert);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,6 +135,11 @@ public class ConsumerOptions {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConsumerOptions addVerificationCerts(PGPCertificateStore certificateStore) {
|
||||||
|
this.certificates.addStore(certificateStore);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public ConsumerOptions addVerificationOfDetachedSignatures(InputStream signatureInputStream) throws IOException, PGPException {
|
public ConsumerOptions addVerificationOfDetachedSignatures(InputStream signatureInputStream) throws IOException, PGPException {
|
||||||
List<PGPSignature> signatures = SignatureUtils.readSignatures(signatureInputStream);
|
List<PGPSignature> signatures = SignatureUtils.readSignatures(signatureInputStream);
|
||||||
return addVerificationOfDetachedSignatures(signatures);
|
return addVerificationOfDetachedSignatures(signatures);
|
||||||
|
@ -266,8 +276,19 @@ public class ConsumerOptions {
|
||||||
return Collections.unmodifiableSet(decryptionPassphrases);
|
return Collections.unmodifiableSet(decryptionPassphrases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the explicitly set verification certificates.
|
||||||
|
*
|
||||||
|
* @deprecated use {@link #getCertificateSource()} instead.
|
||||||
|
* @return verification certs
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public @Nonnull Set<PGPPublicKeyRing> getCertificates() {
|
public @Nonnull Set<PGPPublicKeyRing> getCertificates() {
|
||||||
return Collections.unmodifiableSet(certificates);
|
return certificates.getExplicitCertificates();
|
||||||
|
}
|
||||||
|
|
||||||
|
public @Nonnull CertificateSource getCertificateSource() {
|
||||||
|
return certificates;
|
||||||
}
|
}
|
||||||
|
|
||||||
public @Nullable MissingPublicKeyCallback getMissingCertificateCallback() {
|
public @Nullable MissingPublicKeyCallback getMissingCertificateCallback() {
|
||||||
|
@ -385,4 +406,68 @@ public class ConsumerOptions {
|
||||||
public MultiPassStrategy getMultiPassStrategy() {
|
public MultiPassStrategy getMultiPassStrategy() {
|
||||||
return multiPassStrategy;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,18 @@ package org.pgpainless.encryption_signing;
|
||||||
import org.bouncycastle.openpgp.PGPException;
|
import org.bouncycastle.openpgp.PGPException;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
import org.bouncycastle.openpgp.PGPPublicKeyRing;
|
||||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRing;
|
||||||
|
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||||
import org.bouncycastle.util.io.Streams;
|
import org.bouncycastle.util.io.Streams;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.pgpainless.PGPainless;
|
import org.pgpainless.PGPainless;
|
||||||
import org.pgpainless.certificate_store.MergeCallbacks;
|
import org.pgpainless.certificate_store.MergeCallbacks;
|
||||||
import org.pgpainless.certificate_store.PGPainlessCertD;
|
import org.pgpainless.certificate_store.PGPainlessCertD;
|
||||||
|
import org.pgpainless.decryption_verification.ConsumerOptions;
|
||||||
|
import org.pgpainless.decryption_verification.DecryptionStream;
|
||||||
|
import org.pgpainless.decryption_verification.OpenPgpMetadata;
|
||||||
import org.pgpainless.key.OpenPgpFingerprint;
|
import org.pgpainless.key.OpenPgpFingerprint;
|
||||||
|
import org.pgpainless.key.protection.SecretKeyRingProtector;
|
||||||
import pgp.cert_d.PGPCertificateStoreAdapter;
|
import pgp.cert_d.PGPCertificateStoreAdapter;
|
||||||
import pgp.certificate_store.certificate.Certificate;
|
import pgp.certificate_store.certificate.Certificate;
|
||||||
import pgp.certificate_store.exception.BadDataException;
|
import pgp.certificate_store.exception.BadDataException;
|
||||||
|
@ -26,60 +32,116 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
public class EncryptWithKeyFromKeyStoreTest {
|
public class EncryptWithKeyFromKeyStoreTest {
|
||||||
|
|
||||||
|
// Collection of 3 keys (fingerprints below)
|
||||||
|
private static final String KEY_COLLECTION = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" +
|
||||||
|
"Version: BCPG v1.71\n" +
|
||||||
|
"\n" +
|
||||||
|
"lFgEYwerQBYJKwYBBAHaRw8BAQdAl3XjFMXQdmhMuFEIbE7IJUP1k+5utUT6IAW3\n" +
|
||||||
|
"zlWguvQAAQDK7Qh5Q9EAB5cTh2OWsPeydfDqRmnuxlZjlwf4WWQLhRAltBRBIDxh\n" +
|
||||||
|
"QHBncGFpbmxlc3Mub3JnPoiPBBMWCgBBBQJjB6tBCRBoj2Vso6FpsxYhBNqK9ZX8\n" +
|
||||||
|
"QfcbxPJmCGiPZWyjoWmzAp4BApsBBRYCAwEABAsJCAcFFQoJCAsCmQEAACEaAP9P\n" +
|
||||||
|
"49Q/E19vyx2rV8EjQd+XBFnDuYxBjw80ZVC0TaKJNgEAgWsQqcg/ARkG9XGxaE3X\n" +
|
||||||
|
"IE9tFHh4wpjQhnK1Ta/wJAOcXQRjB6tBEgorBgEEAZdVAQUBAQdATJM1XKfKVF+C\n" +
|
||||||
|
"B2/xrGU+F89Ir9viOut4sna4aWfvwHoDAQgHAAD/UN84yv5jxKsPgfw/XZCDwoey\n" +
|
||||||
|
"Y69ompSiBuZjzOWrjegToIh1BBgWCgAdBQJjB6tBAp4BApsMBRYCAwEABAsJCAcF\n" +
|
||||||
|
"FQoJCAsACgkQaI9lbKOhabP/PAEApov4hYuhIENq26z+w4s3A1gakN+gax54F7+M\n" +
|
||||||
|
"YSUm16sBAPiuEdpVJOwTk3WMXKyLOYaVU3JstlP2H1ouguvYTt4CnFgEYwerQRYJ\n" +
|
||||||
|
"KwYBBAHaRw8BAQdA5xpeGHNy9v+QUbl+Rs7Mx0c6D913gksW1eZ4Qeg31B0AAQCx\n" +
|
||||||
|
"6b3P5lRBAraZstlRupymrt6vF2JpeJB8JOOQ+rdVYBJpiNUEGBYKAH0FAmMHq0EC\n" +
|
||||||
|
"ngECmwIFFgIDAQAECwkIBwUVCgkIC18gBBkWCgAGBQJjB6tBAAoJENH9GnI3A/RM\n" +
|
||||||
|
"IVMA/1GU9E+vA8bs0vJVDjp1ri3J4S7u+abwmlivDw8g8XCWAPwKWWfHLgJCsAHk\n" +
|
||||||
|
"INuDgJdqbNPATFiXxH9FqYnOvWy6DAAKCRBoj2Vso6Fps884AP9D5ZOwuBEXyT/j\n" +
|
||||||
|
"0G8CWBZ0lT14kRGFucjQi9kZStAuVgEA5cd3eUWofnekd/P6R3UgmvhVOqvxwUUg\n" +
|
||||||
|
"Y3mEArH7+waUWARjB6tBFgkrBgEEAdpHDwEBB0BCYWjTs0pfBnKYgO0O07djiMSB\n" +
|
||||||
|
"tUJVpUFo6zrVK92RgAAA/38G6IEK5rJs1OCusmmhHJk1vDu0hbesK7JH7dh75mVY\n" +
|
||||||
|
"Ep20FEIgPGJAcGdwYWlubGVzcy5vcmc+iI8EExYKAEEFAmMHq0EJEAnsE6FTTHNl\n" +
|
||||||
|
"FiEE2/L5HBba6IFDHu8cCewToVNMc2UCngECmwEFFgIDAQAECwkIBwUVCgkICwKZ\n" +
|
||||||
|
"AQAAS7MBAI74uYLK7XR6oCwWYk7C6nwdgu3t478MaEpVHQz/9nEGAQCvJCYqqOd6\n" +
|
||||||
|
"cAG6fwFaIJ3h99/Y5o2NaiN17S2zOXEZDJxdBGMHq0ESCisGAQQBl1UBBQEBB0BU\n" +
|
||||||
|
"EjXQCT4xwJryksXsMLaFo43pFTwWaTzduiWgCy2KMgMBCAcAAP9lXlnMYtBfXpgH\n" +
|
||||||
|
"doUZZk3cvWBOH3awc12V3jZSLtSE8BAJiHUEGBYKAB0FAmMHq0ECngECmwwFFgID\n" +
|
||||||
|
"AQAECwkIBwUVCgkICwAKCRAJ7BOhU0xzZf5lAQDOgzMhqg3fE8Hg4Hbt4+B0fAD0\n" +
|
||||||
|
"kp6EJgsKRWT7KbZ0SQD/aVGFv7VRVqiiqOT/YMQKBBwHnq/CGJqxUwUmavBMRAqc\n" +
|
||||||
|
"WARjB6tBFgkrBgEEAdpHDwEBB0A5kv3bpsnlxs2LrAzeBx4RgtXQNBhGRhzko1to\n" +
|
||||||
|
"4q+ebQAA/1SU1hvrqd9gNmcc4wff1iwJ1dnqnrbGbO1Yz9rYZjXRE4iI1QQYFgoA\n" +
|
||||||
|
"fQUCYwerQQKeAQKbAgUWAgMBAAQLCQgHBRUKCQgLXyAEGRYKAAYFAmMHq0EACgkQ\n" +
|
||||||
|
"pYWdiAVpxGRW4AD+Lade9kJrvcBMSq8EERhYTH6DFka4eMgFB76kH31WmpQA+gOU\n" +
|
||||||
|
"7kwqKmtyVsXVgCLGMcdTvbZr+73C5m8R7LsdY5kEAAoJEAnsE6FTTHNl7BAA/2v8\n" +
|
||||||
|
"Wzfmg1OO6IWCohmmNgF4rIDBW8Q9s3+1I/mWlMyjAP9YGR+fnN/YOQrlSG9UiXE5\n" +
|
||||||
|
"fGwUhaPB0LEGWp0wmmQYA5RYBGMHq0EWCSsGAQQB2kcPAQEHQI8C53+C8crLCQ48\n" +
|
||||||
|
"OKQa1dEKc8XWQSA6Ckg5j73tOJRLAAD/VRvioGU2M9G6+eKTn68mBVZ8G512HELr\n" +
|
||||||
|
"apK9M5UFGUMPXLQUQyA8Y0BwZ3BhaW5sZXNzLm9yZz6IjwQTFgoAQQUCYwerQQkQ\n" +
|
||||||
|
"ommXHYx1l94WIQQp+Mrw86EV1myUgUKiaZcdjHWX3gKeAQKbAQUWAgMBAAQLCQgH\n" +
|
||||||
|
"BRUKCQgLApkBAAAQ5wEAvahnnRuwY+Y7EPSQG+sqhsdvSTumleYPtEOnHfKctpkA\n" +
|
||||||
|
"/iaTp4OoUw/RtyWUAk8MLN47CAW5wwhFUbVfZOaS88wMnF0EYwerQRIKKwYBBAGX\n" +
|
||||||
|
"VQEFAQEHQNz/s68ZGUBfDmMz510cFgHz+mAdC2nXeE4hHKV/HIVsAwEIBwAA/1HB\n" +
|
||||||
|
"vRl84B8r/PY+5j/X6A+4J08QB/vd5wIHVdkrX+xQELGIdQQYFgoAHQUCYwerQQKe\n" +
|
||||||
|
"AQKbDAUWAgMBAAQLCQgHBRUKCQgLAAoJEKJplx2MdZfeqzYA/jLtjRmy42MCOxnF\n" +
|
||||||
|
"3A95WZIDoEohFU0QAeE/yVTLGoDTAP4xhTznleABK7VbD9GJXfD6DkEC749tOsST\n" +
|
||||||
|
"eYO/GOxKDpxYBGMHq0EWCSsGAQQB2kcPAQEHQFnvyWSgOv4gn3Ch3RY74pRg+7hX\n" +
|
||||||
|
"OBJAf6ybwvx9t4olAAEAwYG1CL0JozVD1216yrENkP8La132O1MI28kqMsoF6FcP\n" +
|
||||||
|
"I4jVBBgWCgB9BQJjB6tBAp4BApsCBRYCAwEABAsJCAcFFQoJCAtfIAQZFgoABgUC\n" +
|
||||||
|
"YwerQQAKCRB8jJGVps/ENgz7AP9ZMENJH+rIKMjynb9WPBlvJ8yJ9dMhzCxcssxg\n" +
|
||||||
|
"EVZYXAEA5ZsE5xJLQC/cVMGFvqaQ8iPo5jhDZpQJ8RCVlb8XzQwACgkQommXHYx1\n" +
|
||||||
|
"l96SkgD/f0FYkK4yB8FWuntJ3n0FUfE31wDwpxvvpvP+o3d2GB4BAP9LRKBXMwj4\n" +
|
||||||
|
"jzJc4ViKmwiNJAPttDQCpYjzJT7LUKAA\n" +
|
||||||
|
"=EAvh\n" +
|
||||||
|
"-----END PGP PRIVATE KEY BLOCK-----";
|
||||||
|
|
||||||
// Collection of 3 certificates (fingerprints below)
|
// Collection of 3 certificates (fingerprints below)
|
||||||
private static final String CERT_COLLECTION = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
private static final String CERT_COLLECTION = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" +
|
||||||
"Version: BCPG v1.71\n" +
|
"Version: BCPG v1.71\n" +
|
||||||
"\n" +
|
"\n" +
|
||||||
"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\n" +
|
||||||
"Pr2snaTp6/NukIbg3D/YMXm+mM6119v7HJkO\n" +
|
"Mwj4jzJc4ViKmwiNJAPttDQCpYjzJT7LUKAA\n" +
|
||||||
"=KVYs\n" +
|
"=WaRm\n" +
|
||||||
"-----END PGP PUBLIC KEY BLOCK-----";
|
"-----END PGP PUBLIC KEY BLOCK-----";
|
||||||
private static final OpenPgpFingerprint cert1fp = OpenPgpFingerprint.parse("76324A41CC19C0AA33B3C1F6070730D6CC6AAE26");
|
private static final OpenPgpFingerprint cert1fp = OpenPgpFingerprint.parse("DA8AF595FC41F71BC4F26608688F656CA3A169B3");
|
||||||
private static final OpenPgpFingerprint cert2fp = OpenPgpFingerprint.parse("C7CD4DE07F1C972E04D338600E64F63484F50F82");
|
private static final OpenPgpFingerprint cert2fp = OpenPgpFingerprint.parse("DBF2F91C16DAE881431EEF1C09EC13A1534C7365");
|
||||||
private static final OpenPgpFingerprint cert3fp = OpenPgpFingerprint.parse("9165E83E17F979BD2631FEFD545DC02306859824");
|
private static final OpenPgpFingerprint cert3fp = OpenPgpFingerprint.parse("29F8CAF0F3A115D66C948142A269971D8C7597DE");
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void encryptWithKeyFromStore() throws PGPException, IOException, BadDataException, InterruptedException, BadNameException {
|
public void encryptWithCertFromCertificateStore() throws PGPException, IOException, BadDataException, InterruptedException, BadNameException {
|
||||||
// In-Memory certificate store
|
// In-Memory certificate store
|
||||||
PGPainlessCertD certificateDirectory = PGPainlessCertD.inMemory();
|
PGPainlessCertD certificateDirectory = PGPainlessCertD.inMemory();
|
||||||
PGPCertificateStoreAdapter adapter = new PGPCertificateStoreAdapter(certificateDirectory);
|
PGPCertificateStoreAdapter adapter = new PGPCertificateStoreAdapter(certificateDirectory);
|
||||||
|
@ -108,4 +170,61 @@ public class EncryptWithKeyFromKeyStoreTest {
|
||||||
// check if message was encrypted for cert
|
// check if message was encrypted for cert
|
||||||
assertTrue(encryptionStream.getResult().isEncryptedFor(publicKeys));
|
assertTrue(encryptionStream.getResult().isEncryptedFor(publicKeys));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void verifyWithCertFromCertificateStore()
|
||||||
|
throws PGPException, IOException, BadDataException, InterruptedException, BadNameException {
|
||||||
|
// In-Memory certificate store
|
||||||
|
PGPainlessCertD certificateDirectory = PGPainlessCertD.inMemory();
|
||||||
|
PGPCertificateStoreAdapter adapter = new PGPCertificateStoreAdapter(certificateDirectory);
|
||||||
|
|
||||||
|
// Populate store
|
||||||
|
PGPPublicKeyRingCollection certificates = PGPainless.readKeyRing().publicKeyRingCollection(CERT_COLLECTION);
|
||||||
|
for (PGPPublicKeyRing cert : certificates) {
|
||||||
|
certificateDirectory.insert(new ByteArrayInputStream(cert.getEncoded()), MergeCallbacks.mergeWithExisting());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare keys
|
||||||
|
OpenPgpFingerprint cryptFp = cert3fp;
|
||||||
|
OpenPgpFingerprint signFp = cert1fp;
|
||||||
|
PGPSecretKeyRingCollection secretKeys = PGPainless.readKeyRing().secretKeyRingCollection(KEY_COLLECTION);
|
||||||
|
PGPSecretKeyRing signingKey = secretKeys.getSecretKeyRing(signFp.getKeyId());
|
||||||
|
PGPSecretKeyRing decryptionKey = secretKeys.getSecretKeyRing(cryptFp.getKeyId());
|
||||||
|
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
|
||||||
|
|
||||||
|
// Encrypt and sign message
|
||||||
|
ByteArrayInputStream plaintextIn = new ByteArrayInputStream(
|
||||||
|
"This message was encrypted with a cert from a store and gets verified with a cert from a store as well".getBytes());
|
||||||
|
ByteArrayOutputStream ciphertext = new ByteArrayOutputStream();
|
||||||
|
EncryptionStream encryptionStream = PGPainless.encryptAndOrSign()
|
||||||
|
.onOutputStream(ciphertext)
|
||||||
|
.withOptions(
|
||||||
|
ProducerOptions.signAndEncrypt(
|
||||||
|
EncryptionOptions.encryptCommunications()
|
||||||
|
.addRecipient(adapter, cryptFp),
|
||||||
|
SigningOptions.get()
|
||||||
|
.addSignature(protector, signingKey)
|
||||||
|
));
|
||||||
|
Streams.pipeAll(plaintextIn, encryptionStream);
|
||||||
|
encryptionStream.close();
|
||||||
|
|
||||||
|
// Prepare ciphertext for decryption
|
||||||
|
ByteArrayInputStream ciphertextIn = new ByteArrayInputStream(ciphertext.toByteArray());
|
||||||
|
ByteArrayOutputStream plaintextOut = new ByteArrayOutputStream();
|
||||||
|
// Decrypt and verify
|
||||||
|
DecryptionStream decryptionStream = PGPainless.decryptAndOrVerify()
|
||||||
|
.onInputStream(ciphertextIn)
|
||||||
|
.withOptions(
|
||||||
|
new ConsumerOptions()
|
||||||
|
.addDecryptionKey(decryptionKey, protector)
|
||||||
|
.addVerificationCerts(adapter));
|
||||||
|
Streams.pipeAll(decryptionStream, plaintextOut);
|
||||||
|
decryptionStream.close();
|
||||||
|
|
||||||
|
// Check that message can be decrypted and is verified
|
||||||
|
OpenPgpMetadata result = decryptionStream.getResult();
|
||||||
|
assertTrue(result.isEncrypted());
|
||||||
|
assertTrue(result.isVerified());
|
||||||
|
assertTrue(result.containsVerifiedSignatureFrom(signFp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class DetachedVerifyImpl implements DetachedVerify {
|
||||||
verificationList.add(map(signatureVerification));
|
verificationList.add(map(signatureVerification));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.getCertificates().isEmpty()) {
|
if (!options.getCertificateSource().getExplicitCertificates().isEmpty()) {
|
||||||
if (verificationList.isEmpty()) {
|
if (verificationList.isEmpty()) {
|
||||||
throw new SOPGPException.NoSignature();
|
throw new SOPGPException.NoSignature();
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ public class InlineVerifyImpl implements InlineVerify {
|
||||||
verificationList.add(map(signatureVerification));
|
verificationList.add(map(signatureVerification));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.getCertificates().isEmpty()) {
|
if (!options.getCertificateSource().getExplicitCertificates().isEmpty()) {
|
||||||
if (verificationList.isEmpty()) {
|
if (verificationList.isEmpty()) {
|
||||||
throw new SOPGPException.NoSignature();
|
throw new SOPGPException.NoSignature();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue