diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java index 20b6637..d7d29fb 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Import.java @@ -10,7 +10,7 @@ import org.bouncycastle.openpgp.PGPPublicKeyRingCollection; import org.pgpainless.PGPainless; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import pgp.cert_d.cli.MergeCallbacks; +import org.pgpainless.certificate_store.MergeCallbacks; import pgp.cert_d.cli.PGPCertDCli; import pgp.certificate_store.certificate.Certificate; import pgp.certificate_store.exception.BadDataException; diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java index b73e51a..c88ead0 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Insert.java @@ -6,7 +6,7 @@ package pgp.cert_d.cli.commands; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import pgp.cert_d.cli.MergeCallbacks; +import org.pgpainless.certificate_store.MergeCallbacks; import pgp.cert_d.cli.PGPCertDCli; import pgp.certificate_store.certificate.Certificate; import pgp.certificate_store.exception.BadDataException; diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java index bb94de7..0178e0a 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java +++ b/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/commands/Setup.java @@ -15,7 +15,7 @@ import org.pgpainless.key.generation.type.eddsa.EdDSACurve; import org.pgpainless.util.Passphrase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import pgp.cert_d.cli.MergeCallbacks; +import org.pgpainless.certificate_store.MergeCallbacks; import pgp.cert_d.cli.PGPCertDCli; import pgp.certificate_store.exception.BadDataException; import picocli.CommandLine; diff --git a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/MergeCallbacks.java b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/MergeCallbacks.java similarity index 50% rename from pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/MergeCallbacks.java rename to pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/MergeCallbacks.java index 014f7b2..242ed49 100644 --- a/pgpainless-cert-d-cli/src/main/java/pgp/cert_d/cli/MergeCallbacks.java +++ b/pgpainless-cert-d/src/main/java/org/pgpainless/certificate_store/MergeCallbacks.java @@ -2,18 +2,21 @@ // // SPDX-License-Identifier: Apache-2.0 -package pgp.cert_d.cli; +package org.pgpainless.certificate_store; 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.pgpainless.PGPainless; -import org.pgpainless.certificate_store.CertificateFactory; import org.pgpainless.key.OpenPgpFingerprint; import pgp.certificate_store.certificate.KeyMaterial; import pgp.certificate_store.certificate.KeyMaterialMerger; +import pgp.certificate_store.exception.BadDataException; import java.io.IOException; +import java.util.Arrays; import java.util.Iterator; public class MergeCallbacks { @@ -29,20 +32,66 @@ public class MergeCallbacks { @Override public KeyMaterial merge(KeyMaterial data, KeyMaterial existing) throws IOException { + if (data == null) { + return existing; + } + if (existing == null) { + return data; + } + try { - PGPPublicKeyRing existingCert = PGPainless.readKeyRing().publicKeyRing(existing.getInputStream()); - PGPPublicKeyRing updatedCert = PGPainless.readKeyRing().publicKeyRing(data.getInputStream()); - PGPPublicKeyRing mergedCert = PGPPublicKeyRing.join(existingCert, updatedCert); + PGPKeyRing existingKeyRing = PGPainless.readKeyRing().keyRing(existing.getInputStream()); + PGPKeyRing updatedKeyRing = PGPainless.readKeyRing().keyRing(data.getInputStream()); - printOutDifferences(existingCert, mergedCert); + PGPKeyRing mergedKeyRing; + + if (existingKeyRing instanceof PGPPublicKeyRing) { + PGPPublicKeyRing existingCert = (PGPPublicKeyRing) existingKeyRing; + if (updatedKeyRing instanceof PGPPublicKeyRing) { + mergedKeyRing = PGPPublicKeyRing.join(existingCert, (PGPPublicKeyRing) updatedKeyRing); + } else if (updatedKeyRing instanceof PGPSecretKeyRing) { + PGPPublicKeyRing updatedPublicKeys = PGPainless.extractCertificate((PGPSecretKeyRing) updatedKeyRing); + PGPPublicKeyRing mergedPublicKeys = PGPPublicKeyRing.join(existingCert, updatedPublicKeys); + updatedKeyRing = PGPSecretKeyRing.replacePublicKeys((PGPSecretKeyRing) updatedKeyRing, mergedPublicKeys); + mergedKeyRing = updatedKeyRing; + } else { + throw new IOException(new BadDataException()); + } + } else if (existingKeyRing instanceof PGPSecretKeyRing) { + PGPSecretKeyRing existingKey = (PGPSecretKeyRing) existingKeyRing; + PGPPublicKeyRing existingCert = PGPainless.extractCertificate(existingKey); + if (updatedKeyRing instanceof PGPPublicKeyRing) { + PGPPublicKeyRing updatedCert = (PGPPublicKeyRing) updatedKeyRing; + PGPPublicKeyRing mergedCert = PGPPublicKeyRing.join(existingCert, updatedCert); + mergedKeyRing = PGPSecretKeyRing.replacePublicKeys(existingKey, mergedCert); + } else if (updatedKeyRing instanceof PGPSecretKeyRing) { + PGPSecretKeyRing updatedKey = (PGPSecretKeyRing) updatedKeyRing; + if (!Arrays.equals(existingKey.getEncoded(), updatedKey.getEncoded())) { + // Merging secret keys is not supported. + return existing; + } + mergedKeyRing = existingKeyRing; + } else { + throw new IOException(new BadDataException()); + } + } else { + throw new IOException(new BadDataException()); + } + + printOutDifferences(existingKeyRing, mergedKeyRing); + + if (mergedKeyRing instanceof PGPPublicKeyRing) { + return CertificateFactory.certificateFromPublicKeyRing((PGPPublicKeyRing) mergedKeyRing); + } else { + return KeyFactory.keyFromSecretKeyRing((PGPSecretKeyRing) mergedKeyRing); + } - return CertificateFactory.certificateFromPublicKeyRing(mergedCert); } catch (PGPException e) { throw new RuntimeException(e); } } - private void printOutDifferences(PGPPublicKeyRing existingCert, PGPPublicKeyRing mergedCert) { + private void printOutDifferences(PGPKeyRing existingCert, PGPKeyRing mergedCert) { int numSigsBefore = countSigs(existingCert); int numSigsAfter = countSigs(mergedCert); int newSigs = numSigsAfter - numSigsBefore; @@ -74,9 +123,11 @@ public class MergeCallbacks { } } - private int countSigs(PGPPublicKeyRing keys) { + private int countSigs(PGPKeyRing keys) { int numSigs = 0; - for (PGPPublicKey key : keys) { + Iterator iterator = keys.getPublicKeys(); + while (iterator.hasNext()) { + PGPPublicKey key = iterator.next(); numSigs += count(key.getSignatures()); } return numSigs; diff --git a/version.gradle b/version.gradle index 90264e0..45efb59 100644 --- a/version.gradle +++ b/version.gradle @@ -12,7 +12,7 @@ allprojects { logbackVersion = '1.2.11' junitVersion = '5.8.2' mockitoVersion = '4.5.1' - pgpainlessVersion = '1.3.5-SNAPSHOT' + pgpainlessVersion = '1.3.5' pgpCertDJavaVersion = '0.1.2-SNAPSHOT' picocliVersion = '4.6.3' }