From f34c6d7735885ccc5dd3afccc426fa5609dd93f0 Mon Sep 17 00:00:00 2001 From: Paul Schaub Date: Wed, 24 Aug 2022 23:18:54 +0200 Subject: [PATCH] Add tests for PGPCertificateStoreAdapter --- pgp-cert-d-java/README.md | 6 +- .../pgp/cert_d/PGPCertificateDirectory.java | 5 + .../InMemoryCertificateDirectoryBackend.java | 16 +- .../cert_d/PGPCertificateDirectoryTest.java | 162 +++--------------- .../PGPCertificateStoreAdapterTest.java | 124 ++++++++++++++ .../src/test/java/pgp/cert_d/TestKeys.java | 130 ++++++++++++++ 6 files changed, 295 insertions(+), 148 deletions(-) create mode 100644 pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateStoreAdapterTest.java create mode 100644 pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeys.java diff --git a/pgp-cert-d-java/README.md b/pgp-cert-d-java/README.md index 58e29d7..49302bb 100644 --- a/pgp-cert-d-java/README.md +++ b/pgp-cert-d-java/README.md @@ -13,9 +13,11 @@ Backend-agnostic implementation of the [Shared PGP Certificate Directory Specifi This module implements the non-OpenPGP parts of the spec, e.g. locating the directory, resolving certificate file paths, locking the directory for writes etc. +This library can be used on Android API level 26 and up. + To get a useful implementation, a backend implementation such as `pgpainless-cert-d` is required, which needs to provide support for reading and merging certificates. -`pgp-cert-d-java` can be used as an implementation of `pgp-certificate-store`. +`pgp-cert-d-java` can be used as an implementation of `pgp-certificate-store` using the `PGPCertificateStoreAdapter` class. -Note: This is a library module. For a command line interface, see [pgpainless-cert-d-cli](https://github.com/pgpainless/cert-d-pgpainless/tree/main/pgpainless-cert-d-cli). \ No newline at end of file +Note: This is a library module. For a command line interface, see [pgpainless-cert-d-cli](https://github.com/pgpainless/cert-d-pgpainless/tree/main/pgpainless-cert-d-cli). diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateDirectory.java b/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateDirectory.java index 3a3a9d7..1d54212 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateDirectory.java +++ b/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateDirectory.java @@ -16,6 +16,7 @@ import java.io.InputStream; import java.util.Iterator; import java.util.List; import java.util.Set; +import java.util.regex.Pattern; /** * Implementation of the Shared PGP Certificate Directory. @@ -27,6 +28,7 @@ public class PGPCertificateDirectory final Backend backend; final SubkeyLookup subkeyLookup; + private final Pattern openPgpV4FingerprintPattern = Pattern.compile("^[a-f0-9]{40}$"); /** * Constructor for a PGP certificate directory. @@ -41,6 +43,9 @@ public class PGPCertificateDirectory @Override public Certificate getByFingerprint(String fingerprint) throws BadDataException, BadNameException, IOException { + if (!openPgpV4FingerprintPattern.matcher(fingerprint).matches()) { + throw new BadNameException(); + } return backend.readByFingerprint(fingerprint); } diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/InMemoryCertificateDirectoryBackend.java b/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/InMemoryCertificateDirectoryBackend.java index 60069c8..b3c3bd6 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/InMemoryCertificateDirectoryBackend.java +++ b/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/InMemoryCertificateDirectoryBackend.java @@ -19,6 +19,7 @@ import java.io.InputStream; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.concurrent.atomic.AtomicLong; public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirectory.Backend { @@ -60,6 +61,7 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect private final Map keyMaterialSpecialNameMap = new HashMap<>(); private final PGPCertificateDirectory.LockingMechanism lock = new ObjectLockingMechanism(); private final KeyMaterialReaderBackend reader; + private final AtomicLong nonce = new AtomicLong(1); public InMemoryCertificateDirectoryBackend(KeyMaterialReaderBackend reader) { this.reader = reader; @@ -102,9 +104,9 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect } KeyMaterial merged = merge.merge(update, existing); if (merged instanceof Key) { - merged = new Key((Key) merged, System.currentTimeMillis()); + merged = new Key((Key) merged, newTag()); } else { - merged = new Certificate((Certificate) merged, System.currentTimeMillis()); + merged = new Certificate((Certificate) merged, newTag()); } keyMaterialSpecialNameMap.put(SpecialNames.TRUST_ROOT, merged); return merged; @@ -117,7 +119,7 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect KeyMaterial update = reader.read(data, null); Certificate existing = readByFingerprint(update.getFingerprint()); Certificate merged = merge.merge(update, existing).asCertificate(); - merged = new Certificate(merged, System.currentTimeMillis()); + merged = new Certificate(merged, newTag()); certificateFingerprintMap.put(update.getFingerprint(), merged); return merged; } @@ -129,9 +131,9 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect KeyMaterial existing = readBySpecialName(specialName); KeyMaterial merged = merge.merge(keyMaterial, existing); if (merged instanceof Key) { - merged = new Key((Key) merged, System.currentTimeMillis()); + merged = new Key((Key) merged, newTag()); } else { - merged = new Certificate((Certificate) merged, System.currentTimeMillis()); + merged = new Certificate((Certificate) merged, newTag()); } keyMaterialSpecialNameMap.put(specialName, merged); return merged.asCertificate(); @@ -157,4 +159,8 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect } return tagged.getTag(); } + + private Long newTag() { + return System.currentTimeMillis() + nonce.incrementAndGet(); + } } diff --git a/pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateDirectoryTest.java b/pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateDirectoryTest.java index a3803c2..8605f0e 100644 --- a/pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateDirectoryTest.java +++ b/pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateDirectoryTest.java @@ -5,8 +5,10 @@ package pgp.cert_d; import org.bouncycastle.util.io.Streams; +import org.junit.jupiter.api.Named; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import pgp.cert_d.backend.FileBasedCertificateDirectoryBackend; import pgp.cert_d.dummy.TestKeyMaterialMerger; @@ -20,7 +22,6 @@ import pgp.certificate_store.exception.BadDataException; import pgp.certificate_store.exception.BadNameException; import pgp.certificate_store.exception.NotAStoreException; -import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; @@ -41,119 +42,16 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import static pgp.cert_d.TestKeys.CEDRIC_FP; +import static pgp.cert_d.TestKeys.HARRY_FP; +import static pgp.cert_d.TestKeys.RON_FP; public class PGPCertificateDirectoryTest { - @SuppressWarnings("CharsetObjectCanBeUsed") - private static final Charset UTF8 = Charset.forName("UTF8"); - - private static final String HARRY_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + - "Comment: 2357 8FD1 7F20 7FDF 62F7 976C 4E9D 9891 7AD8 4522\n" + - "Comment: Harry Potter \n" + - "\n" + - "xVgEYwTP0hYJKwYBBAHaRw8BAQdAPVcWeaMiUVG+vECWpoytSoF3wNJQG/JsnCbj\n" + - "uQtv0REAAP0cS3GCmrIMO/FqNm1FG1mKw4P+mvZ1JBFILN7Laooq7A/QwsARBB8W\n" + - "CgCDBYJjBM/SBYkFn6YAAwsJBwkQTp2YkXrYRSJHFAAAAAAAHgAgc2FsdEBub3Rh\n" + - "dGlvbnMuc2VxdW9pYS1wZ3Aub3JnRSvJhQu9P/3bpFqFdB2c5Mfg9JIdyic1tsAt\n" + - "lZ7o4k4DFQoIApsBAh4BFiEEI1eP0X8gf99i95dsTp2YkXrYRSIAAK2cAP9juDnY\n" + - "qB6XuXVx76MzDlFemqJ/r2TIlN22O33ITp23cQEAiMk/rULVdfmlFi3QBvXgtPI2\n" + - "QQYFI0UnyGLmJSa1cwzNIEhhcnJ5IFBvdHRlciA8aGFycnlAcG90dGVyLm1vcmU+\n" + - "wsAUBBMWCgCGBYJjBM/SBYkFn6YAAwsJBwkQTp2YkXrYRSJHFAAAAAAAHgAgc2Fs\n" + - "dEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn0o9na1p+a9kY3y3+xUSFFnxbuxNM\n" + - "5zvth0SAfJIH2C8DFQoIApkBApsBAh4BFiEEI1eP0X8gf99i95dsTp2YkXrYRSIA\n" + - "AC1zAP0e2qRXH4zCnjvdYwGP0tIY3dwBsm1bvk+wVFHm8h68iwEAh2uyyQ+O5iQH\n" + - "7NN/lV5dUKKsKaimj/vVGpSW3NtFZQDHWARjBM/SFgkrBgEEAdpHDwEBB0BUqcZu\n" + - "VsEO6fmW8q3S5ll9WohcTOWRX7Spg5wS3DIqPgABALzJ9ZImb4U94WqRtftSSaeF\n" + - "0w6rHCn2DiTT8pxjefGQEW7CwMUEGBYKATcFgmMEz9IFiQWfpgAJEE6dmJF62EUi\n" + - "RxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ+HPX0u5kyKR\n" + - "5IwErbomgGKVCGuvR6oSKc7CDQYMJS9eApsCvqAEGRYKAG8FgmMEz9IJEKk0hrvR\n" + - "6Jc7RxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ8Chba26\n" + - "1nQ6ZEZ/rVH8wMhYznGNa/Ux28sodM04wU6dFiEEli7ijJ6quX9gSoSbqTSGu9Ho\n" + - "lzsAAG1wAQDVvKVWaMOBELROkF72oBH58X6lrOmr08W5FJQxehywhQEAwetpgL1V\n" + - "DNj4qcvuCJJ2agAM1tA22WMPpQQeA5CCgwcWIQQjV4/RfyB/32L3l2xOnZiRethF\n" + - "IgAAsWEA/RfOKexMYEtzlpM71MB9SL+emHXf+w1TNAvBxrifU8bMAPoDmWHkWjZQ\n" + - "N6upbHKssRywPLKCMPLnFYtBNxDrMYr0BMddBGMEz9ISCisGAQQBl1UBBQEBB0CR\n" + - "p5dCIlSpV/EvXX2+YZnZSRtc8eTFXkph8RArNi0QPAMBCAcAAP9seqRo6mbmvS4h\n" + - "fkxmV5zap3wIemzW4iabNU2VbWJbEBALwsAGBBgWCgB4BYJjBM/SBYkFn6YACRBO\n" + - "nZiRethFIkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmdx\n" + - "uRLJ/h81azzvGn5zgJ+jdfkdM6iO+f1CLgfnHUH9ugKbDBYhBCNXj9F/IH/fYveX\n" + - "bE6dmJF62EUiAACObgEAk4whKEo2nzpWht65tpFjrEXdakj00mA/P612P2CUdPQB\n" + - "ANNn+VUiu9rtnLcP4NlaUVOwsgN7yyed0orbmG1VvSMF\n" + - "=cBAn\n" + - "-----END PGP PRIVATE KEY BLOCK-----\n"; - private static final String HARRY_FP = "23578fd17f207fdf62f7976c4e9d98917ad84522"; - - private static final String RON_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "Comment: B798 AF18 6BFE 4C19 902D 4950 5647 F001 37EF 4C41\n" + - "Comment: Ron Weasley \n" + - "\n" + - "xjMEYwTRXBYJKwYBBAHaRw8BAQdAPHyiu4nwvo3OY3wLG1tUmS6qeTeT1zd3BrL+\n" + - "6/5Ys3jCwBEEHxYKAIMFgmME0VwFiQWfpgADCwkHCRBWR/ABN+9MQUcUAAAAAAAe\n" + - "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfEPNi/1ObPMwDwS094Lcyq\n" + - "dRNRk2FRzvhoXKrqF/GHfQMVCggCmwECHgEWIQS3mK8Ya/5MGZAtSVBWR/ABN+9M\n" + - "QQAAR/oBAJWxxUJqOAzYG4uAd6SSF55LZVl00t3bGhgEyGmrB/ppAQCZTpWu0rwU\n" + - "GVv/MoeqRwX+P8sHS4FSu/hSYJpbNwysCM0gUm9uIFdlYXNsZXkgPHJvbkB3ZWFz\n" + - "bGV5LmJ1cnJvdz7CwBQEExYKAIYFgmME0VwFiQWfpgADCwkHCRBWR/ABN+9MQUcU\n" + - "AAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmf43PjsP9w1eGYP\n" + - "CLm6O+K27EQPiCf2cW71QnQ0RunupgMVCggCmQECmwECHgEWIQS3mK8Ya/5MGZAt\n" + - "SVBWR/ABN+9MQQAA7rYA/3U2aaw5PFa9L90PbxygOwFrgIVWLiOpnKfjqDJqEgva\n" + - "AQDxTIbpUYEAYmTpmAm1tiQSlpp9P96vqCMIj2OqtYCNAs4zBGME0VwWCSsGAQQB\n" + - "2kcPAQEHQGzhRPzKRkkce0v1NjuTV2stn8CEMVgnUxsMPtd0h2M9wsDFBBgWCgE3\n" + - "BYJjBNFcBYkFn6YACRBWR/ABN+9MQUcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5z\n" + - "ZXF1b2lhLXBncC5vcmd6UNkzsh0jKRPQAKX2PoUhMN4QfhTK9IC6L+QbyL1rFgKb\n" + - "Ar6gBBkWCgBvBYJjBNFcCRCuGMJD3GUsUUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + - "cy5zZXF1b2lhLXBncC5vcmcUTns9+sw7XKKO5ZOYQninRAchypKHbqV2LinV46Hi\n" + - "bxYhBI+SjTgn0fulukOYj64YwkPcZSxRAADZtAEApse3UJi1iuSFvnyXxuYIOm4d\n" + - "0sOaOtd18venqfWGyX4BALf7T7LknMY688vaW6/xkw2fonG6Y5VxreIHlMZAcX0H\n" + - "FiEEt5ivGGv+TBmQLUlQVkfwATfvTEEAAFQ3AQCGSLEt8wgJZXlljPdk1eQ3uvW3\n" + - "VHryNAc3/vbSOvByFAD/WKXY8Pqki2r9XVUW33Q88firoiKVuGmBxklEG3ACjALO\n" + - "OARjBNFcEgorBgEEAZdVAQUBAQdARnMlx3ST0EHPiErN7lOF+lhtJ8FmW9arc46u\n" + - "sHFMgUMDAQgHwsAGBBgWCgB4BYJjBNFcBYkFn6YACRBWR/ABN+9MQUcUAAAAAAAe\n" + - "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfv1PKQX1GMihAdj3ftW/yS\n" + - "bnPYdE+0h5rGCuhYl7sjaQKbDBYhBLeYrxhr/kwZkC1JUFZH8AE370xBAABWugEA\n" + - "rWOEHQjzoQkxxsErVEVZjqr05SLMmo6+HMJ/4Sgur10A/0+4FSbaKKNGiCnCMRsZ\n" + - "BEswoD99mUaBXl1nPH+Hg38O\n" + - "=+pb5\n" + - "-----END PGP PUBLIC KEY BLOCK-----\n"; - private static final String RON_FP = "b798af186bfe4c19902d49505647f00137ef4c41"; - - private static final String CEDRIC_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + - "Comment: 5E75 BF20 646B C1A9 8D3B 1BC2 FE9C D472 987C 4021\n" + - "Comment: Cedric Diggory \n" + - "\n" + - "xjMEYwTIyhYJKwYBBAHaRw8BAQdA80cyaoAEfh/ENuHw8XtWqrxDoPQ/x44LQzyO\n" + - "TLhMN+PCwBEEHxYKAIMFgmMEyMoFiQWfpgADCwkHCRD+nNRymHxAIUcUAAAAAAAe\n" + - "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmf0ckQJQzwOKkXPe8rFP5B+\n" + - "CbAshRG5OKD3Dp+hScGFXgMVCggCmwECHgEWIQRedb8gZGvBqY07G8L+nNRymHxA\n" + - "IQAA9WYBAP5rQCq/W3KV90T/wpxf5pcXoCB4tCC9Gi/1AiuGhQdAAP48PIX9fH+T\n" + - "g7N+tU0xzzCc2nWxG3cIuvGFsg94pKL8As0gQ2VkcmljIERpZ2dvcnkgPGNlZHJp\n" + - "Y0BkaWdnby5yeT7CwBQEExYKAIYFgmMEyMoFiQWfpgADCwkHCRD+nNRymHxAIUcU\n" + - "AAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmdkUL5mF5SwIXja\n" + - "bCxhI3lvqiUURSoLY13K6YvHYLz7bwMVCggCmQECmwECHgEWIQRedb8gZGvBqY07\n" + - "G8L+nNRymHxAIQAA6SwA/jiM8k/Z0ljnHdFxsdoLhdnTZ0yJT/7RxreSZ3aITrDs\n" + - "AP9V8bAYy4hK0C7i4FmNcos3HQs2Si6ee2/EZjo8LqxeCc4zBGMEyMoWCSsGAQQB\n" + - "2kcPAQEHQIu0hKMngTnmIPXlZ/p9WOZmLB0s9v9yZJLdZ5ICKn7jwsDFBBgWCgE3\n" + - "BYJjBMjKBYkFn6YACRD+nNRymHxAIUcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5z\n" + - "ZXF1b2lhLXBncC5vcmdCT1SyOVJwTPp4OEDWFNEgxKD12H+Dya9EzOMJ3I9frwKb\n" + - "Ar6gBBkWCgBvBYJjBMjKCRDNPli8d9EIkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + - "cy5zZXF1b2lhLXBncC5vcmccLTSNIhZOiNFaTj76iAutuAkUCImFp5ptMICZRo7E\n" + - "TRYhBESzEAYRbxRfM3ub5c0+WLx30QiRAAAZtwD/WRJrSxzJRsnZs4w+QgZjqOZx\n" + - "bOGwGObfbEHaExG0cKEA/R+BFODg5oPOvK9W7n0Kt9O171Po+zXB0UDmBiEhh0YL\n" + - "FiEEXnW/IGRrwamNOxvC/pzUcph8QCEAAEneAQDnOv/cf1/qmjfLnorEi+Z4gRWQ\n" + - "fp3Rp/gI4SLUQxT0PQD/USZIP0bNMGGC1TRQa+8nK6opSqtIvsatt0tQuu178A7O\n" + - "OARjBMjKEgorBgEEAZdVAQUBAQdAazcEUsYtY9f9o4A+ePR7ACMIDScVEUWS83+I\n" + - "SwJQz3QDAQgHwsAGBBgWCgB4BYJjBMjKBYkFn6YACRD+nNRymHxAIUcUAAAAAAAe\n" + - "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmc/qxMatwD+6zaKDZGlVdn/\n" + - "TWumSgLtuyYonaOupIfMEAKbDBYhBF51vyBka8GpjTsbwv6c1HKYfEAhAADPiwEA\n" + - "vQ7fTnAHcdZlMVnNPkc0pZSp1+kO5Z789I5Pp4HloNIBAMoC84ja83PjvcpIyxgR\n" + - "kspLC9BliezVbFSHIK9NQ/wC\n" + - "=VemI\n" + - "-----END PGP PUBLIC KEY BLOCK-----\n"; - private static final String CEDRIC_FP = "5e75bf20646bc1a98d3b1bc2fe9cd472987c4021"; private static final KeyMaterialMerger merger = new TestKeyMaterialMerger(); - private static Stream provideTestSubjects() + private static Stream provideTestSubjects() throws IOException, NotAStoreException { PGPCertificateDirectory inMemory = PGPCertificateDirectories.inMemoryCertificateDirectory( new TestKeyMaterialReaderBackend()); @@ -165,7 +63,9 @@ public class PGPCertificateDirectoryTest { tempDir, new InMemorySubkeyLookup()); - return Stream.of(inMemory, fileBased); + return Stream.of( + Arguments.of(Named.of("InMemoryCertificateDirectory", inMemory)), + Arguments.of(Named.of("FileBasedCertificateDirectory", fileBased))); } @ParameterizedTest @@ -178,11 +78,11 @@ public class PGPCertificateDirectoryTest { assertTrue(directory.backend.getLock().isLocked()); assertFalse(directory.backend.getLock().tryLockDirectory()); - Certificate inserted = directory.tryInsert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); + Certificate inserted = directory.tryInsert(TestKeys.getCedricCert(), merger); assertNull(inserted); directory.backend.getLock().releaseDirectory(); - inserted = directory.tryInsert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); + inserted = directory.tryInsert(TestKeys.getCedricCert(), merger); assertNotNull(inserted); } @@ -198,15 +98,13 @@ public class PGPCertificateDirectoryTest { throws BadDataException, IOException, InterruptedException, BadNameException { assertNull(directory.getByFingerprint(CEDRIC_FP), "Empty directory MUST NOT contain certificate"); - ByteArrayInputStream bytesIn = new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)); - - Certificate certificate = directory.insert(bytesIn, merger); + Certificate certificate = directory.insert(TestKeys.getCedricCert(), merger); assertEquals(CEDRIC_FP, certificate.getFingerprint(), "Fingerprint of inserted cert MUST match"); Certificate get = directory.getByFingerprint(CEDRIC_FP); assertEquals(CEDRIC_FP, get.getFingerprint(), "Fingerprint of retrieved cert MUST match"); - byte[] expected = CEDRIC_CERT.getBytes(UTF8); + byte[] expected = TestKeys.CEDRIC_CERT.getBytes(Charset.forName("UTF8")); ByteArrayOutputStream actual = new ByteArrayOutputStream(); Streams.pipeAll(get.getInputStream(), actual); assertArrayEquals(expected, actual.toByteArray(), "InputStream of cert MUST match what we gave in"); @@ -219,7 +117,7 @@ public class PGPCertificateDirectoryTest { assertNull(directory.getTrustRoot()); KeyMaterial trustRootMaterial = directory.insertTrustRoot( - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); + TestKeys.getHarryKey(), merger); assertNotNull(trustRootMaterial); assertTrue(trustRootMaterial instanceof Key); assertEquals(HARRY_FP, trustRootMaterial.getFingerprint()); @@ -229,8 +127,8 @@ public class PGPCertificateDirectoryTest { Certificate trustRootCert = directory.getTrustRootCertificate(); assertEquals(HARRY_FP, trustRootCert.getFingerprint()); - directory.tryInsert(new ByteArrayInputStream(RON_CERT.getBytes(UTF8)), merger); - directory.insert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); + directory.tryInsert(TestKeys.getRonCert(), merger); + directory.insert(TestKeys.getCedricCert(), merger); Set expected = new HashSet<>(Arrays.asList(RON_FP, CEDRIC_FP)); @@ -248,7 +146,7 @@ public class PGPCertificateDirectoryTest { public void testGetTrustRootIfChanged(PGPCertificateDirectory directory) throws BadDataException, IOException, InterruptedException { KeyMaterial trustRootMaterial = directory.insertTrustRoot( - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); + TestKeys.getHarryKey(), merger); assertNotNull(trustRootMaterial.getTag()); Long tag = trustRootMaterial.getTag(); @@ -258,7 +156,7 @@ public class PGPCertificateDirectoryTest { Long oldTag = tag; // "update" key trustRootMaterial = directory.insertTrustRoot( - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); + TestKeys.getHarryKey(), merger); tag = trustRootMaterial.getTag(); assertNotEquals(oldTag, tag); @@ -270,42 +168,24 @@ public class PGPCertificateDirectoryTest { public void testGetBySpecialNameIfChanged(PGPCertificateDirectory directory) throws BadDataException, IOException, InterruptedException, BadNameException { KeyMaterial specialName = directory.insertWithSpecialName(SpecialNames.TRUST_ROOT, - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); + TestKeys.getHarryKey(), merger); assertNotNull(specialName.getTag()); Long tag = specialName.getTag(); assertNull(directory.getBySpecialNameIfChanged(SpecialNames.TRUST_ROOT, tag)); assertNotNull(directory.getBySpecialNameIfChanged(SpecialNames.TRUST_ROOT, tag + 1)); - - Long oldTag = tag; - // "update" key - specialName = directory.insertWithSpecialName(SpecialNames.TRUST_ROOT, - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); - tag = specialName.getTag(); - - assertNotEquals(oldTag, tag); - assertNotNull(directory.getBySpecialNameIfChanged(SpecialNames.TRUST_ROOT, oldTag)); } @ParameterizedTest @MethodSource("provideTestSubjects") public void testGetByFingerprintIfChanged(PGPCertificateDirectory directory) throws BadDataException, IOException, InterruptedException, BadNameException { - Certificate certificate = directory.insert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); + Certificate certificate = directory.insert(TestKeys.getCedricCert(), merger); Long tag = certificate.getTag(); assertNotNull(tag); assertNull(directory.getByFingerprintIfChanged(certificate.getFingerprint(), tag)); assertNotNull(directory.getByFingerprintIfChanged(certificate.getFingerprint(), tag + 1)); - - Long oldTag = tag; - // "update" cert - certificate = directory.insert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); - tag = certificate.getTag(); - - assertNotEquals(oldTag, tag); - assertNull(directory.getByFingerprintIfChanged(certificate.getFingerprint(), tag)); - assertNotNull(directory.getByFingerprintIfChanged(certificate.getFingerprint(), oldTag)); } @Test @@ -320,7 +200,7 @@ public class PGPCertificateDirectoryTest { new FileBasedCertificateDirectoryBackend.FilenameResolver(tempDir); // Insert certificate - Certificate certificate = directory.insert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); + Certificate certificate = directory.insert(TestKeys.getCedricCert(), merger); Long tag = certificate.getTag(); assertNotNull(tag); assertNull(directory.getByFingerprintIfChanged(certificate.getFingerprint(), tag)); diff --git a/pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateStoreAdapterTest.java b/pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateStoreAdapterTest.java new file mode 100644 index 0000000..56fdac6 --- /dev/null +++ b/pgp-cert-d-java/src/test/java/pgp/cert_d/PGPCertificateStoreAdapterTest.java @@ -0,0 +1,124 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.cert_d; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import pgp.cert_d.backend.InMemoryCertificateDirectoryBackend; +import pgp.cert_d.dummy.TestKeyMaterialMerger; +import pgp.cert_d.dummy.TestKeyMaterialReaderBackend; +import pgp.cert_d.subkey_lookup.InMemorySubkeyLookupFactory; +import pgp.certificate_store.certificate.Certificate; +import pgp.certificate_store.exception.BadDataException; +import pgp.certificate_store.exception.BadNameException; + +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertThrows; + +public class PGPCertificateStoreAdapterTest { + + private PGPCertificateDirectory directory; + private PGPCertificateStoreAdapter adapter; + + private static final TestKeyMaterialMerger merger = new TestKeyMaterialMerger(); + + @BeforeEach + public void setup() { + directory = new PGPCertificateDirectory( + new InMemoryCertificateDirectoryBackend(new TestKeyMaterialReaderBackend()), + new InMemorySubkeyLookupFactory().createFileBasedInstance(null)); + adapter = new PGPCertificateStoreAdapter(directory); + } + + @Test + public void testBadFPWithInvalidCharsYieldsBadNameException() { + assertThrows(BadNameException.class, () -> adapter.getCertificate("XYZ78fd17f207fdf62f7976c4e9d98917ad84522")); + } + + @Test + public void testBadFPWithTooFewCharsYieldsBadNameException() { + assertThrows(BadNameException.class, () -> adapter.getCertificate("23578fd17f207fdf62f7976c4e9d98917ad")); + } + + @Test + public void testInsertGetCertificate() + throws BadDataException, IOException, InterruptedException, BadNameException { + assertNull(adapter.getCertificate(TestKeys.CEDRIC_FP)); + assertFalse(adapter.getCertificates().hasNext()); + + Certificate certificate = adapter.insertCertificate(TestKeys.getCedricCert(), merger); + assertNotNull(certificate); + assertEquals(TestKeys.CEDRIC_FP, certificate.getFingerprint()); + + certificate = adapter.getCertificate(TestKeys.CEDRIC_FP.toUpperCase()); + assertEquals(TestKeys.CEDRIC_FP, certificate.getFingerprint(), "We can also fetch with uppercase fps"); + + Iterator fingerprints = adapter.getFingerprints(); + assertEquals(TestKeys.CEDRIC_FP, fingerprints.next()); + assertFalse(fingerprints.hasNext()); + } + + @Test + public void testInsertGetTrustRoot() + throws BadDataException, BadNameException, IOException, InterruptedException { + assertNull(adapter.getCertificate(SpecialNames.TRUST_ROOT)); + + Certificate certificate = adapter.insertCertificateBySpecialName( + SpecialNames.TRUST_ROOT, TestKeys.getHarryKey(), merger); + assertNotNull(certificate); + assertEquals(TestKeys.HARRY_FP, certificate.getFingerprint()); + + assertFalse(adapter.getCertificates().hasNext(), "Special-named certs are not returned by getCertificates()"); + assertFalse(adapter.getFingerprints().hasNext()); + } + + @Test + public void testGetCertificateIfChanged() + throws BadDataException, IOException, InterruptedException, BadNameException { + Certificate certificate = adapter.insertCertificate(TestKeys.getRonCert(), merger); + Long tag = certificate.getTag(); + + assertNull(adapter.getCertificateIfChanged(TestKeys.RON_FP, tag), "Cert has not changed, tag is still valid"); + assertNotNull(adapter.getCertificateIfChanged(TestKeys.RON_FP, tag + 1)); + } + + @Test + public void testGetTrustRootIfChanged() + throws BadDataException, BadNameException, IOException, InterruptedException { + Certificate certificate = adapter.insertCertificateBySpecialName(SpecialNames.TRUST_ROOT, TestKeys.getHarryKey(), merger); + Long tag = certificate.getTag(); + + assertNull(adapter.getCertificateIfChanged(SpecialNames.TRUST_ROOT, tag)); + assertNotNull(adapter.getCertificateIfChanged(SpecialNames.TRUST_ROOT, tag * 2)); + } + + @Test + public void testGetCertificateBySubkeyId() + throws BadDataException, IOException, InterruptedException { + // Insert some certs + adapter.insertCertificate(TestKeys.getCedricCert(), merger); + adapter.insertCertificate(TestKeys.getHarryKey(), merger); + // Now insert Ron + Certificate certificate = adapter.insertCertificate(TestKeys.getRonCert(), merger); + List subkeyIds = certificate.getSubkeyIds(); + + assertFalse(adapter.getCertificatesBySubkeyId(0).hasNext()); + + for (Long subkeyId : subkeyIds) { + Iterator certsWithSubkey = adapter.getCertificatesBySubkeyId(subkeyId); + Certificate certWithSubkey = certsWithSubkey.next(); + assertFalse(certsWithSubkey.hasNext()); + + assertEquals(TestKeys.RON_FP, certWithSubkey.getFingerprint()); + } + } +} diff --git a/pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeys.java b/pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeys.java new file mode 100644 index 0000000..fd2d8f1 --- /dev/null +++ b/pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeys.java @@ -0,0 +1,130 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.cert_d; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.nio.charset.Charset; + +public class TestKeys { + @SuppressWarnings("CharsetObjectCanBeUsed") + private static final Charset UTF8 = Charset.forName("UTF8"); + + public static final String HARRY_KEY = "-----BEGIN PGP PRIVATE KEY BLOCK-----\n" + + "Comment: 2357 8FD1 7F20 7FDF 62F7 976C 4E9D 9891 7AD8 4522\n" + + "Comment: Harry Potter \n" + + "\n" + + "xVgEYwTP0hYJKwYBBAHaRw8BAQdAPVcWeaMiUVG+vECWpoytSoF3wNJQG/JsnCbj\n" + + "uQtv0REAAP0cS3GCmrIMO/FqNm1FG1mKw4P+mvZ1JBFILN7Laooq7A/QwsARBB8W\n" + + "CgCDBYJjBM/SBYkFn6YAAwsJBwkQTp2YkXrYRSJHFAAAAAAAHgAgc2FsdEBub3Rh\n" + + "dGlvbnMuc2VxdW9pYS1wZ3Aub3JnRSvJhQu9P/3bpFqFdB2c5Mfg9JIdyic1tsAt\n" + + "lZ7o4k4DFQoIApsBAh4BFiEEI1eP0X8gf99i95dsTp2YkXrYRSIAAK2cAP9juDnY\n" + + "qB6XuXVx76MzDlFemqJ/r2TIlN22O33ITp23cQEAiMk/rULVdfmlFi3QBvXgtPI2\n" + + "QQYFI0UnyGLmJSa1cwzNIEhhcnJ5IFBvdHRlciA8aGFycnlAcG90dGVyLm1vcmU+\n" + + "wsAUBBMWCgCGBYJjBM/SBYkFn6YAAwsJBwkQTp2YkXrYRSJHFAAAAAAAHgAgc2Fs\n" + + "dEBub3RhdGlvbnMuc2VxdW9pYS1wZ3Aub3Jn0o9na1p+a9kY3y3+xUSFFnxbuxNM\n" + + "5zvth0SAfJIH2C8DFQoIApkBApsBAh4BFiEEI1eP0X8gf99i95dsTp2YkXrYRSIA\n" + + "AC1zAP0e2qRXH4zCnjvdYwGP0tIY3dwBsm1bvk+wVFHm8h68iwEAh2uyyQ+O5iQH\n" + + "7NN/lV5dUKKsKaimj/vVGpSW3NtFZQDHWARjBM/SFgkrBgEEAdpHDwEBB0BUqcZu\n" + + "VsEO6fmW8q3S5ll9WohcTOWRX7Spg5wS3DIqPgABALzJ9ZImb4U94WqRtftSSaeF\n" + + "0w6rHCn2DiTT8pxjefGQEW7CwMUEGBYKATcFgmMEz9IFiQWfpgAJEE6dmJF62EUi\n" + + "RxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ+HPX0u5kyKR\n" + + "5IwErbomgGKVCGuvR6oSKc7CDQYMJS9eApsCvqAEGRYKAG8FgmMEz9IJEKk0hrvR\n" + + "6Jc7RxQAAAAAAB4AIHNhbHRAbm90YXRpb25zLnNlcXVvaWEtcGdwLm9yZ8Chba26\n" + + "1nQ6ZEZ/rVH8wMhYznGNa/Ux28sodM04wU6dFiEEli7ijJ6quX9gSoSbqTSGu9Ho\n" + + "lzsAAG1wAQDVvKVWaMOBELROkF72oBH58X6lrOmr08W5FJQxehywhQEAwetpgL1V\n" + + "DNj4qcvuCJJ2agAM1tA22WMPpQQeA5CCgwcWIQQjV4/RfyB/32L3l2xOnZiRethF\n" + + "IgAAsWEA/RfOKexMYEtzlpM71MB9SL+emHXf+w1TNAvBxrifU8bMAPoDmWHkWjZQ\n" + + "N6upbHKssRywPLKCMPLnFYtBNxDrMYr0BMddBGMEz9ISCisGAQQBl1UBBQEBB0CR\n" + + "p5dCIlSpV/EvXX2+YZnZSRtc8eTFXkph8RArNi0QPAMBCAcAAP9seqRo6mbmvS4h\n" + + "fkxmV5zap3wIemzW4iabNU2VbWJbEBALwsAGBBgWCgB4BYJjBM/SBYkFn6YACRBO\n" + + "nZiRethFIkcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmdx\n" + + "uRLJ/h81azzvGn5zgJ+jdfkdM6iO+f1CLgfnHUH9ugKbDBYhBCNXj9F/IH/fYveX\n" + + "bE6dmJF62EUiAACObgEAk4whKEo2nzpWht65tpFjrEXdakj00mA/P612P2CUdPQB\n" + + "ANNn+VUiu9rtnLcP4NlaUVOwsgN7yyed0orbmG1VvSMF\n" + + "=cBAn\n" + + "-----END PGP PRIVATE KEY BLOCK-----\n"; + public static final String HARRY_FP = "23578fd17f207fdf62f7976c4e9d98917ad84522"; + + public static final String RON_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "Comment: B798 AF18 6BFE 4C19 902D 4950 5647 F001 37EF 4C41\n" + + "Comment: Ron Weasley \n" + + "\n" + + "xjMEYwTRXBYJKwYBBAHaRw8BAQdAPHyiu4nwvo3OY3wLG1tUmS6qeTeT1zd3BrL+\n" + + "6/5Ys3jCwBEEHxYKAIMFgmME0VwFiQWfpgADCwkHCRBWR/ABN+9MQUcUAAAAAAAe\n" + + "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfEPNi/1ObPMwDwS094Lcyq\n" + + "dRNRk2FRzvhoXKrqF/GHfQMVCggCmwECHgEWIQS3mK8Ya/5MGZAtSVBWR/ABN+9M\n" + + "QQAAR/oBAJWxxUJqOAzYG4uAd6SSF55LZVl00t3bGhgEyGmrB/ppAQCZTpWu0rwU\n" + + "GVv/MoeqRwX+P8sHS4FSu/hSYJpbNwysCM0gUm9uIFdlYXNsZXkgPHJvbkB3ZWFz\n" + + "bGV5LmJ1cnJvdz7CwBQEExYKAIYFgmME0VwFiQWfpgADCwkHCRBWR/ABN+9MQUcU\n" + + "AAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmf43PjsP9w1eGYP\n" + + "CLm6O+K27EQPiCf2cW71QnQ0RunupgMVCggCmQECmwECHgEWIQS3mK8Ya/5MGZAt\n" + + "SVBWR/ABN+9MQQAA7rYA/3U2aaw5PFa9L90PbxygOwFrgIVWLiOpnKfjqDJqEgva\n" + + "AQDxTIbpUYEAYmTpmAm1tiQSlpp9P96vqCMIj2OqtYCNAs4zBGME0VwWCSsGAQQB\n" + + "2kcPAQEHQGzhRPzKRkkce0v1NjuTV2stn8CEMVgnUxsMPtd0h2M9wsDFBBgWCgE3\n" + + "BYJjBNFcBYkFn6YACRBWR/ABN+9MQUcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5z\n" + + "ZXF1b2lhLXBncC5vcmd6UNkzsh0jKRPQAKX2PoUhMN4QfhTK9IC6L+QbyL1rFgKb\n" + + "Ar6gBBkWCgBvBYJjBNFcCRCuGMJD3GUsUUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmcUTns9+sw7XKKO5ZOYQninRAchypKHbqV2LinV46Hi\n" + + "bxYhBI+SjTgn0fulukOYj64YwkPcZSxRAADZtAEApse3UJi1iuSFvnyXxuYIOm4d\n" + + "0sOaOtd18venqfWGyX4BALf7T7LknMY688vaW6/xkw2fonG6Y5VxreIHlMZAcX0H\n" + + "FiEEt5ivGGv+TBmQLUlQVkfwATfvTEEAAFQ3AQCGSLEt8wgJZXlljPdk1eQ3uvW3\n" + + "VHryNAc3/vbSOvByFAD/WKXY8Pqki2r9XVUW33Q88firoiKVuGmBxklEG3ACjALO\n" + + "OARjBNFcEgorBgEEAZdVAQUBAQdARnMlx3ST0EHPiErN7lOF+lhtJ8FmW9arc46u\n" + + "sHFMgUMDAQgHwsAGBBgWCgB4BYJjBNFcBYkFn6YACRBWR/ABN+9MQUcUAAAAAAAe\n" + + "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmfv1PKQX1GMihAdj3ftW/yS\n" + + "bnPYdE+0h5rGCuhYl7sjaQKbDBYhBLeYrxhr/kwZkC1JUFZH8AE370xBAABWugEA\n" + + "rWOEHQjzoQkxxsErVEVZjqr05SLMmo6+HMJ/4Sgur10A/0+4FSbaKKNGiCnCMRsZ\n" + + "BEswoD99mUaBXl1nPH+Hg38O\n" + + "=+pb5\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + public static final String RON_FP = "b798af186bfe4c19902d49505647f00137ef4c41"; + + public static final String CEDRIC_CERT = "-----BEGIN PGP PUBLIC KEY BLOCK-----\n" + + "Comment: 5E75 BF20 646B C1A9 8D3B 1BC2 FE9C D472 987C 4021\n" + + "Comment: Cedric Diggory \n" + + "\n" + + "xjMEYwTIyhYJKwYBBAHaRw8BAQdA80cyaoAEfh/ENuHw8XtWqrxDoPQ/x44LQzyO\n" + + "TLhMN+PCwBEEHxYKAIMFgmMEyMoFiQWfpgADCwkHCRD+nNRymHxAIUcUAAAAAAAe\n" + + "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmf0ckQJQzwOKkXPe8rFP5B+\n" + + "CbAshRG5OKD3Dp+hScGFXgMVCggCmwECHgEWIQRedb8gZGvBqY07G8L+nNRymHxA\n" + + "IQAA9WYBAP5rQCq/W3KV90T/wpxf5pcXoCB4tCC9Gi/1AiuGhQdAAP48PIX9fH+T\n" + + "g7N+tU0xzzCc2nWxG3cIuvGFsg94pKL8As0gQ2VkcmljIERpZ2dvcnkgPGNlZHJp\n" + + "Y0BkaWdnby5yeT7CwBQEExYKAIYFgmMEyMoFiQWfpgADCwkHCRD+nNRymHxAIUcU\n" + + "AAAAAAAeACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmdkUL5mF5SwIXja\n" + + "bCxhI3lvqiUURSoLY13K6YvHYLz7bwMVCggCmQECmwECHgEWIQRedb8gZGvBqY07\n" + + "G8L+nNRymHxAIQAA6SwA/jiM8k/Z0ljnHdFxsdoLhdnTZ0yJT/7RxreSZ3aITrDs\n" + + "AP9V8bAYy4hK0C7i4FmNcos3HQs2Si6ee2/EZjo8LqxeCc4zBGMEyMoWCSsGAQQB\n" + + "2kcPAQEHQIu0hKMngTnmIPXlZ/p9WOZmLB0s9v9yZJLdZ5ICKn7jwsDFBBgWCgE3\n" + + "BYJjBMjKBYkFn6YACRD+nNRymHxAIUcUAAAAAAAeACBzYWx0QG5vdGF0aW9ucy5z\n" + + "ZXF1b2lhLXBncC5vcmdCT1SyOVJwTPp4OEDWFNEgxKD12H+Dya9EzOMJ3I9frwKb\n" + + "Ar6gBBkWCgBvBYJjBMjKCRDNPli8d9EIkUcUAAAAAAAeACBzYWx0QG5vdGF0aW9u\n" + + "cy5zZXF1b2lhLXBncC5vcmccLTSNIhZOiNFaTj76iAutuAkUCImFp5ptMICZRo7E\n" + + "TRYhBESzEAYRbxRfM3ub5c0+WLx30QiRAAAZtwD/WRJrSxzJRsnZs4w+QgZjqOZx\n" + + "bOGwGObfbEHaExG0cKEA/R+BFODg5oPOvK9W7n0Kt9O171Po+zXB0UDmBiEhh0YL\n" + + "FiEEXnW/IGRrwamNOxvC/pzUcph8QCEAAEneAQDnOv/cf1/qmjfLnorEi+Z4gRWQ\n" + + "fp3Rp/gI4SLUQxT0PQD/USZIP0bNMGGC1TRQa+8nK6opSqtIvsatt0tQuu178A7O\n" + + "OARjBMjKEgorBgEEAZdVAQUBAQdAazcEUsYtY9f9o4A+ePR7ACMIDScVEUWS83+I\n" + + "SwJQz3QDAQgHwsAGBBgWCgB4BYJjBMjKBYkFn6YACRD+nNRymHxAIUcUAAAAAAAe\n" + + "ACBzYWx0QG5vdGF0aW9ucy5zZXF1b2lhLXBncC5vcmc/qxMatwD+6zaKDZGlVdn/\n" + + "TWumSgLtuyYonaOupIfMEAKbDBYhBF51vyBka8GpjTsbwv6c1HKYfEAhAADPiwEA\n" + + "vQ7fTnAHcdZlMVnNPkc0pZSp1+kO5Z789I5Pp4HloNIBAMoC84ja83PjvcpIyxgR\n" + + "kspLC9BliezVbFSHIK9NQ/wC\n" + + "=VemI\n" + + "-----END PGP PUBLIC KEY BLOCK-----\n"; + public static final String CEDRIC_FP = "5e75bf20646bc1a98d3b1bc2fe9cd472987c4021"; + + public static InputStream getHarryKey() { + return new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)); + } + + public static InputStream getRonCert() { + return new ByteArrayInputStream(RON_CERT.getBytes(UTF8)); + } + + public static InputStream getCedricCert() { + return new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)); + } +}