diff --git a/pgp-cert-d-java-jdbc-sqlite-lookup/src/main/java/pgp/cert_d/jdbc/sqlite/DatabaseSubkeyLookupFactory.java b/pgp-cert-d-java-jdbc-sqlite-lookup/src/main/java/pgp/cert_d/jdbc/sqlite/DatabaseSubkeyLookupFactory.java index d0a259a..d2cecd3 100644 --- a/pgp-cert-d-java-jdbc-sqlite-lookup/src/main/java/pgp/cert_d/jdbc/sqlite/DatabaseSubkeyLookupFactory.java +++ b/pgp-cert-d-java-jdbc-sqlite-lookup/src/main/java/pgp/cert_d/jdbc/sqlite/DatabaseSubkeyLookupFactory.java @@ -16,19 +16,9 @@ import java.sql.SQLException; */ public class DatabaseSubkeyLookupFactory implements SubkeyLookupFactory { - private String databaseName; - - public DatabaseSubkeyLookupFactory() { - this("_pgpainless_subkey_map.db"); - } - - public DatabaseSubkeyLookupFactory(String databaseName) { - this.databaseName = databaseName; - } - @Override public SubkeyLookup createFileBasedInstance(File baseDirectory) { - File databaseFile = new File(baseDirectory, databaseName); + File databaseFile = new File(baseDirectory, "_pgpainless_subkey_map.db"); SubkeyLookupDao dao; try { if (!databaseFile.exists()) { diff --git a/pgp-cert-d-java-jdbc-sqlite-lookup/src/test/java/pgp/cert_d/jdbc/sqlite/SqliteSubkeyLookupTest.java b/pgp-cert-d-java-jdbc-sqlite-lookup/src/test/java/pgp/cert_d/jdbc/sqlite/SqliteSubkeyLookupTest.java index 5539d12..b71337c 100644 --- a/pgp-cert-d-java-jdbc-sqlite-lookup/src/test/java/pgp/cert_d/jdbc/sqlite/SqliteSubkeyLookupTest.java +++ b/pgp-cert-d-java-jdbc-sqlite-lookup/src/test/java/pgp/cert_d/jdbc/sqlite/SqliteSubkeyLookupTest.java @@ -22,15 +22,15 @@ import org.junit.jupiter.api.Test; public class SqliteSubkeyLookupTest { - private File tempDir; + private File databaseFile; private DatabaseSubkeyLookup lookup; @BeforeEach - public void setupLookup() throws IOException { - tempDir = Files.createTempDirectory("pgp.cert.d").toFile(); - tempDir.deleteOnExit(); - lookup = (DatabaseSubkeyLookup) new DatabaseSubkeyLookupFactory() - .createFileBasedInstance(tempDir); + public void setupLookup() throws IOException, SQLException { + databaseFile = Files.createTempFile("pgp.cert.d-", "lookup.db").toFile(); + databaseFile.createNewFile(); + databaseFile.deleteOnExit(); + lookup = new DatabaseSubkeyLookup(SqliteSubkeyLookupDaoImpl.forDatabaseFile(databaseFile)); } @Test @@ -55,7 +55,7 @@ public class SqliteSubkeyLookupTest { assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), lookup.getCertificateFingerprintsForSubkeyId(1337)); // do the lookup using a second db instance on the same file - DatabaseSubkeyLookup secondInstance = (DatabaseSubkeyLookup) new DatabaseSubkeyLookupFactory().createFileBasedInstance(tempDir); + DatabaseSubkeyLookup secondInstance = new DatabaseSubkeyLookup(SqliteSubkeyLookupDaoImpl.forDatabaseFile(databaseFile)); assertEquals(Collections.singleton("eb85bb5fa33a75e15e944e63f231550c4f47e38e"), secondInstance.getCertificateFingerprintsForSubkeyId(1337)); } diff --git a/pgp-cert-d-java/build.gradle b/pgp-cert-d-java/build.gradle index 35032ca..a4b97b3 100644 --- a/pgp-cert-d-java/build.gradle +++ b/pgp-cert-d-java/build.gradle @@ -16,7 +16,7 @@ apply plugin: 'ru.vyarus.animalsniffer' dependencies { // animal sniffer for ensuring Android API compatibility - signature "net.sf.androidscents.signature:android-api-level-${minAndroidSdk}:8.0.0_r2@signature" + signature "net.sf.androidscents.signature:android-api-level-${minAndroidSdk}:2.3.3_r2@signature" // JUnit testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/BaseDirectoryProvider.java b/pgp-cert-d-java/src/main/java/pgp/cert_d/BaseDirectoryProvider.java index 386a5c7..0a24084 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/BaseDirectoryProvider.java +++ b/pgp-cert-d-java/src/main/java/pgp/cert_d/BaseDirectoryProvider.java @@ -6,16 +6,6 @@ package pgp.cert_d; import java.io.File; -/** - * Provider class that is responsible for resolving the pgp.cert.d base directory of the system. - * The result can be overwritten by setting the
PGP_CERT_D
environment variable. - * If this variable is not set, the system-specific default directory will be returned. - * - * On Windows systems, this is
%APPDATA%\pgp.cert.d
. - * On Linux systems it is either
$XDG_DATA_HOME/pgp.cert.d
or, if
$XDG_DATA_HOME
is not set, - * it is
$HOME/.local/share/pgp.cert.d
- * On Mac systems it is
$HOME/Library/Application Support/pgp.cert.d
. - */ public class BaseDirectoryProvider { public static File getDefaultBaseDir() { 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..2a0d8f5 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 @@ -17,23 +17,12 @@ import java.util.Iterator; import java.util.List; import java.util.Set; -/** - * Implementation of the Shared PGP Certificate Directory. - * - * @see Shared PGP Certificate Directory Specification - */ public class PGPCertificateDirectory implements ReadOnlyPGPCertificateDirectory, WritingPGPCertificateDirectory, SubkeyLookup { final Backend backend; final SubkeyLookup subkeyLookup; - /** - * Constructor for a PGP certificate directory. - * - * @param backend storage backend - * @param subkeyLookup subkey lookup mechanism to map subkey-ids to certificates - */ public PGPCertificateDirectory(Backend backend, SubkeyLookup subkeyLookup) { this.backend = backend; this.subkeyLookup = subkeyLookup; @@ -44,16 +33,6 @@ public class PGPCertificateDirectory return backend.readByFingerprint(fingerprint); } - @Override - public Certificate getByFingerprintIfChanged(String fingerprint, long tag) - throws IOException, BadNameException, BadDataException { - if (tag != backend.getTagForFingerprint(fingerprint)) { - return getByFingerprint(fingerprint); - } - return null; - } - - @Override public Certificate getBySpecialName(String specialName) throws BadNameException, BadDataException, IOException { @@ -64,15 +43,6 @@ public class PGPCertificateDirectory return null; } - @Override - public Certificate getBySpecialNameIfChanged(String specialName, long tag) - throws IOException, BadNameException, BadDataException { - if (tag != backend.getTagForSpecialName(specialName)) { - return getBySpecialName(specialName); - } - return null; - } - @Override public Certificate getTrustRootCertificate() throws IOException, BadDataException { @@ -83,15 +53,6 @@ public class PGPCertificateDirectory } } - @Override - public Certificate getTrustRootCertificateIfChanged(long tag) throws IOException, BadDataException { - try { - return getBySpecialNameIfChanged(SpecialNames.TRUST_ROOT, tag); - } catch (BadNameException e) { - throw new AssertionError("'" + SpecialNames.TRUST_ROOT + "' is an implementation MUST"); - } - } - @Override public Iterator items() { return backend.readItems(); @@ -200,119 +161,26 @@ public class PGPCertificateDirectory subkeyLookup.storeCertificateSubkeyIds(certificate, subkeyIds); } - /** - * Storage backend. - */ public interface Backend { - /** - * Get the locking mechanism to write-lock the backend. - * - * @return lock - */ LockingMechanism getLock(); - /** - * Read a {@link Certificate} by its OpenPGP fingerprint. - * - * @param fingerprint fingerprint - * @return certificate - * - * @throws BadNameException if the fingerprint is malformed - * @throws IOException in case of an IO error - * @throws BadDataException if the certificate contains bad data - */ Certificate readByFingerprint(String fingerprint) throws BadNameException, IOException, BadDataException; - /** - * Read a {@link Certificate} or {@link pgp.certificate_store.certificate.Key} by the given special name. - * - * @param specialName special name - * @return certificate or key - * - * @throws BadNameException if the special name is not known - * @throws IOException in case of an IO error - * @throws BadDataException if the certificate contains bad data - */ KeyMaterial readBySpecialName(String specialName) throws BadNameException, IOException, BadDataException; - /** - * Return an {@link Iterator} of all {@link Certificate Certificates} in the store, except for certificates - * stored under a special name. - * - * @return iterator - */ Iterator readItems(); - /** - * Insert a {@link pgp.certificate_store.certificate.Key} or {@link Certificate} as trust-root. - * - * @param data input stream containing the key material - * @param merge callback to merge the key material with existing key material - * @return merged or inserted key material - * - * @throws BadDataException if the data stream or existing key material contains bad data - * @throws IOException in case of an IO error - */ KeyMaterial doInsertTrustRoot(InputStream data, KeyMaterialMerger merge) throws BadDataException, IOException; - /** - * Insert a {@link Certificate} identified by its fingerprint into the directory. - * - * @param data input stream containing the certificate data - * @param merge callback to merge the certificate with existing key material - * @return merged or inserted certificate - * - * @throws IOException in case of an IO error - * @throws BadDataException if the data stream or existing certificate contains bad data - */ Certificate doInsert(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException; - /** - * Insert a {@link pgp.certificate_store.certificate.Key} or {@link Certificate} under the given special name. - * - * @param specialName special name to identify the key material with - * @param data data stream containing the key or certificate - * @param merge callback to merge the key/certificate with existing key material - * @return certificate component of the merged or inserted key material - * - * @throws IOException in case of an IO error - * @throws BadDataException if the data stream or existing key material contains bad data - * @throws BadNameException if the special name is not known - */ Certificate doInsertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, BadNameException; - - /** - * Calculate the tag of the certificate with the given fingerprint. - * - * @param fingerprint fingerprint - * @return tag - * - * @throws BadNameException if the fingerprint is malformed - * @throws IOException in case of an IO error - * @throws IllegalArgumentException if the certificate does not exist - */ - Long getTagForFingerprint(String fingerprint) throws BadNameException, IOException; - - /** - * Calculate the tag of the certificate identified by the given special name. - * - * @param specialName special name - * @return tag - * - * @throws BadNameException if the special name is not known - * @throws IOException in case of an IO error - * @throws IllegalArgumentException if the certificate or key does not exist - */ - Long getTagForSpecialName(String specialName) throws BadNameException, IOException; } - /** - * Interface for a write-locking mechanism. - */ public interface LockingMechanism { /** @@ -334,11 +202,6 @@ public class PGPCertificateDirectory */ boolean tryLockDirectory() throws IOException; - /** - * Return true if the lock is in locked state. - * - * @return true if locked - */ boolean isLocked(); /** diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateStoreAdapter.java b/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateStoreAdapter.java index 972d3aa..5d95e6f 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateStoreAdapter.java +++ b/pgp-cert-d-java/src/main/java/pgp/cert_d/PGPCertificateStoreAdapter.java @@ -37,16 +37,6 @@ public class PGPCertificateStoreAdapter implements PGPCertificateStore { } } - @Override - public Certificate getCertificateIfChanged(String identifier, Long tag) - throws IOException, BadNameException, BadDataException { - if (SpecialNames.lookupSpecialName(identifier) != null) { - return directory.getBySpecialNameIfChanged(identifier, tag); - } else { - return directory.getByFingerprintIfChanged(identifier.toLowerCase(), tag); - } - } - @Override public Iterator getCertificatesBySubkeyId(long subkeyId) throws IOException, BadDataException { diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/ReadOnlyPGPCertificateDirectory.java b/pgp-cert-d-java/src/main/java/pgp/cert_d/ReadOnlyPGPCertificateDirectory.java index 0b1416c..4c9fabc 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/ReadOnlyPGPCertificateDirectory.java +++ b/pgp-cert-d-java/src/main/java/pgp/cert_d/ReadOnlyPGPCertificateDirectory.java @@ -11,113 +11,18 @@ import pgp.certificate_store.exception.BadNameException; import java.io.IOException; import java.util.Iterator; -/** - * Interface for a read-only OpenPGP certificate directory. - */ public interface ReadOnlyPGPCertificateDirectory { - /** - * Get the trust-root certificate. This is a certificate which is stored under the special name - *
trust-root
. - * If no such certificate is found,
null
is returned. - * - * @return trust-root certificate - * - * @throws IOException in case of an IO error - * @throws BadDataException if the certificate contains bad data - */ Certificate getTrustRootCertificate() throws IOException, BadDataException; - /** - * Get the trust-root certificate if it has changed. - * This method uses the
tag
to calculate if the certificate might have changed. - * If the computed tag equals the given tag, the certificate has not changed, so
null
is returned. - * Otherwise. the changed certificate is returned. - * - * @param tag tag - * @return changed certificate, or null if the certificate is unchanged or not found. - * - * @throws IOException in case of an IO error - * @throws BadDataException if the certificate contains bad data - */ - Certificate getTrustRootCertificateIfChanged(long tag) - throws IOException, BadDataException; - - /** - * Get the certificate identified by the given fingerprint. - * If no such certificate is found, return
null
. - * - * @param fingerprint lower-case fingerprint of the certificate - * @return certificate or null if no such certificate has been found - * - * @throws IOException in case of an IO error - * @throws BadNameException if the fingerprint is malformed - * @throws BadDataException if the certificate contains bad data - */ Certificate getByFingerprint(String fingerprint) throws IOException, BadNameException, BadDataException; - /** - * Get the certificate identified by the given fingerprint if it has changed. - * This method uses the
tag
to calculate, if the certificate might have changed. - * If the computed tag equals the given tag, the certificate has not changed, so
null
is returned. - * Otherwise, the changed certificate is returned. - * - * @param fingerprint lower-case fingerprint of the certificate - * @param tag tag - * @return certificate or null if the certificate has not been changed or has not been found - * - * @throws IOException in case of an IO error - * @throws BadNameException if the fingerprint is malformed - * @throws BadDataException if the certificate contains bad data - */ - Certificate getByFingerprintIfChanged(String fingerprint, long tag) - throws IOException, BadNameException, BadDataException; - - /** - * Get the certificate identified by the given special name. - * If no such certificate is found,
null
is returned. - * - * @param specialName special name - * @return certificate or null - * - * @throws IOException in case of an IO error - * @throws BadNameException if the special name is not known - * @throws BadDataException if the certificate contains bad data - */ Certificate getBySpecialName(String specialName) throws IOException, BadNameException, BadDataException; - /** - * Get the certificate identified by the given special name or null, if it has not been changed. - * This method uses the
tag
to calculate, if the certificate might have changed. - * If the computed tag equals the given tag, the certificate has not changed, so
null
is returned. - * Otherwise, the changed certificate is returned. - * - * @param specialName special name - * @param tag tag - * @return certificate or null - * - * @throws IOException in case of an IO error - * @throws BadNameException if the special name is not known - * @throws BadDataException if the certificate contains bad data - */ - Certificate getBySpecialNameIfChanged(String specialName, long tag) - throws IOException, BadNameException, BadDataException; - - /** - * Get all certificates in the directory, except for certificates which are stored by special name. - * - * @return iterator of certificates - */ Iterator items(); - /** - * Get the fingerprints of all certificates in the directory, except for certificates which are stored by - * special name. - * - * @return iterator of fingerprints - */ Iterator fingerprints(); } diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/WritingPGPCertificateDirectory.java b/pgp-cert-d-java/src/main/java/pgp/cert_d/WritingPGPCertificateDirectory.java index e5371fc..2857165 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/WritingPGPCertificateDirectory.java +++ b/pgp-cert-d-java/src/main/java/pgp/cert_d/WritingPGPCertificateDirectory.java @@ -13,113 +13,26 @@ import pgp.certificate_store.exception.BadNameException; import java.io.IOException; import java.io.InputStream; -/** - * Interface for a writing OpenPGP certificate directory. - */ public interface WritingPGPCertificateDirectory { - /** - * Return the certificate or key identified by the special name
trust-root
. - * - * @return trust-root key or certificate - * - * @throws IOException in case of an IO error - * @throws BadDataException if the certificate contains bad data - */ KeyMaterial getTrustRoot() throws IOException, BadDataException; - /** - * Insert a key or certificate under the special name
trust-root
. - * This method blocks until the key material has been written. - * - * @param data input stream containing the key or certificate - * @param merge key material merger to merge the key or certificate with existing key material - * @return the merged or inserted key or certificate - * - * @throws IOException in case of an IO error - * @throws BadDataException if the data stream or the existing trust-root key material contains bad data - * @throws InterruptedException if the thread is interrupted - */ KeyMaterial insertTrustRoot(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, InterruptedException; - /** - * Insert a key or certificate under the special name
trust-root
. - * Contrary to {@link #insertTrustRoot(InputStream, KeyMaterialMerger)}, this method does not block. - * Instead, it returns null if the write-lock cannot be obtained. - * - * @param data input stream containing the key or certificate - * @param merge key material merger to merge the key or certificate with existing key material - * @return the merged or inserted key or certificate, or null if the write-lock cannot be obtained - * - * @throws IOException in case of an IO error - * @throws BadDataException if the thread is interrupted - */ KeyMaterial tryInsertTrustRoot(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException; - /** - * Insert a certificate identified by its fingerprint. - * This method blocks until the certificate has been written. - * - * @param data input stream containing the certificate data - * @param merge merge callback to merge the certificate with existing certificate material - * @return the merged or inserted certificate - * - * @throws IOException in case of an IO error - * @throws BadDataException if the data stream or existing certificate contains bad data - * @throws InterruptedException if the thread is interrupted - */ Certificate insert(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, InterruptedException; - /** - * Insert a certificate identified by its fingerprint. - * Contrary to {@link #insert(InputStream, KeyMaterialMerger)}, this method does not block. - * Instead, it returns null if the write-lock cannot be obtained. - * - * @param data input stream containing the certificate data - * @param merge merge callback to merge the certificate with existing certificate material - * @return the merged or inserted certificate - * - * @throws IOException in case of an IO error - * @throws BadDataException if the data stream or existing certificate contains bad data - */ Certificate tryInsert(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException; - /** - * Insert a certificate or key under the given special name. - * This method blocks until the certificate/key has been written. - * - * @param specialName special name under which the key material shall be inserted - * @param data input stream containing the key/certificate data - * @param merge callback to merge the key/certificate with existing key material - * @return certificate component of the merged or inserted key material data - * - * @throws IOException in case of an IO error - * @throws BadDataException if the data stream or the existing certificate contains bad data - * @throws BadNameException if the special name is not known - * @throws InterruptedException if the thread is interrupted - */ Certificate insertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, BadNameException, InterruptedException; - /** - * Insert a certificate or key under the given special name. - * Contrary to {@link #insertWithSpecialName(String, InputStream, KeyMaterialMerger)}, this method does not block. - * Instead, it returns null if the write-lock cannot be obtained. - * - * @param specialName special name under which the key material shall be inserted - * @param data input stream containing the key material - * @param merge callback to merge the key/certificate with existing key material - * @return certificate component of the merged or inserted key material - * - * @throws IOException in case of an IO error - * @throws BadDataException if the data stream or existing key material contains bad data - * @throws BadNameException if the special name is not known - */ Certificate tryInsertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, BadNameException; diff --git a/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/FileBasedCertificateDirectoryBackend.java b/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/FileBasedCertificateDirectoryBackend.java index e5750e8..5decae2 100644 --- a/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/FileBasedCertificateDirectoryBackend.java +++ b/pgp-cert-d-java/src/main/java/pgp/cert_d/backend/FileBasedCertificateDirectoryBackend.java @@ -7,7 +7,6 @@ package pgp.cert_d.backend; import pgp.cert_d.PGPCertificateDirectory; import pgp.cert_d.SpecialNames; import pgp.certificate_store.certificate.Certificate; -import pgp.certificate_store.certificate.Key; import pgp.certificate_store.certificate.KeyMaterial; import pgp.certificate_store.certificate.KeyMaterialMerger; import pgp.certificate_store.certificate.KeyMaterialReaderBackend; @@ -26,9 +25,6 @@ import java.io.InputStream; import java.io.RandomAccessFile; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributes; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; @@ -164,12 +160,10 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec return null; } - long tag = getTagForFingerprint(fingerprint); - FileInputStream fileIn = new FileInputStream(certFile); BufferedInputStream bufferedIn = new BufferedInputStream(fileIn); - Certificate certificate = reader.read(bufferedIn, tag).asCertificate(); + Certificate certificate = reader.read(bufferedIn).asCertificate(); if (!certificate.getFingerprint().equals(fingerprint)) { // TODO: Figure out more suitable exception throw new BadDataException(); @@ -185,11 +179,9 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec return null; } - long tag = getTagForSpecialName(specialName); - FileInputStream fileIn = new FileInputStream(certFile); BufferedInputStream bufferedIn = new BufferedInputStream(fileIn); - KeyMaterial keyMaterial = reader.read(bufferedIn, tag); + KeyMaterial keyMaterial = reader.read(bufferedIn); return keyMaterial; } @@ -222,8 +214,7 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec @Override Certificate get() throws BadDataException { try { - long tag = getTag(certFile); - Certificate certificate = reader.read(new FileInputStream(certFile), tag).asCertificate(); + Certificate certificate = reader.read(new FileInputStream(certFile)).asCertificate(); if (!(subdirectory.getName() + certFile.getName()).equals(certificate.getFingerprint())) { throw new BadDataException(); } @@ -255,7 +246,7 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec @Override public KeyMaterial doInsertTrustRoot(InputStream data, KeyMaterialMerger merge) throws BadDataException, IOException { - KeyMaterial newCertificate = reader.read(data, null); + KeyMaterial newCertificate = reader.read(data); KeyMaterial existingCertificate; File certFile; try { @@ -265,22 +256,18 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec throw new BadDataException(); } - if (existingCertificate != null) { + if (existingCertificate != null && !newCertificate.getTag().equals(existingCertificate.getTag())) { newCertificate = merge.merge(newCertificate, existingCertificate); } - long tag = writeToFile(newCertificate.getInputStream(), certFile); - if (newCertificate instanceof Key) { - newCertificate = new Key((Key) newCertificate, tag); - } else { - newCertificate = new Certificate((Certificate) newCertificate, tag); - } + writeToFile(newCertificate.getInputStream(), certFile); + return newCertificate; } @Override public Certificate doInsert(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException { - KeyMaterial newCertificate = reader.read(data, null); + KeyMaterial newCertificate = reader.read(data); Certificate existingCertificate; File certFile; try { @@ -290,17 +277,18 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec throw new BadDataException(); } - if (existingCertificate != null) { + if (existingCertificate != null && !newCertificate.getTag().equals(existingCertificate.getTag())) { newCertificate = merge.merge(newCertificate, existingCertificate); } - long tag = writeToFile(newCertificate.getInputStream(), certFile); - return new Certificate(newCertificate.asCertificate(), tag); + writeToFile(newCertificate.getInputStream(), certFile); + + return newCertificate.asCertificate(); } @Override public Certificate doInsertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, BadNameException { - KeyMaterial newCertificate = reader.read(data, null); + KeyMaterial newCertificate = reader.read(data); KeyMaterial existingCertificate; File certFile; try { @@ -310,41 +298,16 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec throw new BadDataException(); } - if (existingCertificate != null) { + if (existingCertificate != null && !newCertificate.getTag().equals(existingCertificate.getTag())) { newCertificate = merge.merge(newCertificate, existingCertificate); } - long tag = writeToFile(newCertificate.getInputStream(), certFile); - return new Certificate(newCertificate.asCertificate(), tag); + writeToFile(newCertificate.getInputStream(), certFile); + + return newCertificate.asCertificate(); } - @Override - public Long getTagForFingerprint(String fingerprint) throws BadNameException, IOException { - File file = resolver.getCertFileByFingerprint(fingerprint); - return getTag(file); - } - - @Override - public Long getTagForSpecialName(String specialName) throws BadNameException, IOException { - File file = resolver.getCertFileBySpecialName(specialName); - return getTag(file); - } - - private Long getTag(File file) throws IOException { - if (!file.exists()) { - throw new IllegalArgumentException("File MUST exist."); - } - Path path = file.toPath(); - BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class); - - // On UNIX file systems, for example, fileKey() will return the device ID and inode - int fileId = attrs.fileKey().hashCode(); - long lastMod = attrs.lastModifiedTime().toMillis(); - - return lastMod + (11L * fileId); - } - - private long writeToFile(InputStream inputStream, File certFile) + private void writeToFile(InputStream inputStream, File certFile) throws IOException { certFile.getParentFile().mkdirs(); if (!certFile.exists() && !certFile.createNewFile()) { @@ -361,7 +324,6 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec inputStream.close(); fileOut.close(); - return getTag(certFile); } public static class FilenameResolver { 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..26c6e2b 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 @@ -7,7 +7,6 @@ package pgp.cert_d.backend; import pgp.cert_d.PGPCertificateDirectory; import pgp.cert_d.SpecialNames; import pgp.certificate_store.certificate.Certificate; -import pgp.certificate_store.certificate.Key; import pgp.certificate_store.certificate.KeyMaterial; import pgp.certificate_store.certificate.KeyMaterialMerger; import pgp.certificate_store.certificate.KeyMaterialReaderBackend; @@ -92,7 +91,7 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect @Override public KeyMaterial doInsertTrustRoot(InputStream data, KeyMaterialMerger merge) throws BadDataException, IOException { - KeyMaterial update = reader.read(data, null); + KeyMaterial update = reader.read(data); KeyMaterial existing = null; try { existing = readBySpecialName(SpecialNames.TRUST_ROOT); @@ -101,11 +100,6 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect throw new RuntimeException(e); } KeyMaterial merged = merge.merge(update, existing); - if (merged instanceof Key) { - merged = new Key((Key) merged, System.currentTimeMillis()); - } else { - merged = new Certificate((Certificate) merged, System.currentTimeMillis()); - } keyMaterialSpecialNameMap.put(SpecialNames.TRUST_ROOT, merged); return merged; } @@ -114,10 +108,9 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect @Override public Certificate doInsert(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException { - KeyMaterial update = reader.read(data, null); + KeyMaterial update = reader.read(data); Certificate existing = readByFingerprint(update.getFingerprint()); Certificate merged = merge.merge(update, existing).asCertificate(); - merged = new Certificate(merged, System.currentTimeMillis()); certificateFingerprintMap.put(update.getFingerprint(), merged); return merged; } @@ -125,36 +118,10 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect @Override public Certificate doInsertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, BadNameException { - KeyMaterial keyMaterial = reader.read(data, null); + KeyMaterial keyMaterial = reader.read(data); KeyMaterial existing = readBySpecialName(specialName); KeyMaterial merged = merge.merge(keyMaterial, existing); - if (merged instanceof Key) { - merged = new Key((Key) merged, System.currentTimeMillis()); - } else { - merged = new Certificate((Certificate) merged, System.currentTimeMillis()); - } keyMaterialSpecialNameMap.put(specialName, merged); return merged.asCertificate(); } - - @Override - public Long getTagForFingerprint(String fingerprint) throws BadNameException, IOException { - Certificate certificate = certificateFingerprintMap.get(fingerprint); - if (certificate == null) { - return null; - } - return certificate.getTag(); - } - - @Override - public Long getTagForSpecialName(String specialName) throws BadNameException, IOException { - if (SpecialNames.lookupSpecialName(specialName) == null) { - throw new BadNameException("Invalid special name " + specialName); - } - KeyMaterial tagged = keyMaterialSpecialNameMap.get(specialName); - if (tagged == null) { - return null; - } - return tagged.getTag(); - } } 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..65cd558 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,17 +5,12 @@ package pgp.cert_d; import org.bouncycastle.util.io.Streams; -import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; -import pgp.cert_d.backend.FileBasedCertificateDirectoryBackend; -import pgp.cert_d.dummy.TestKeyMaterialMerger; -import pgp.cert_d.dummy.TestKeyMaterialReaderBackend; import pgp.cert_d.subkey_lookup.InMemorySubkeyLookup; import pgp.certificate_store.certificate.Certificate; import pgp.certificate_store.certificate.Key; import pgp.certificate_store.certificate.KeyMaterial; -import pgp.certificate_store.certificate.KeyMaterialMerger; import pgp.certificate_store.exception.BadDataException; import pgp.certificate_store.exception.BadNameException; import pgp.certificate_store.exception.NotAStoreException; @@ -23,7 +18,6 @@ import pgp.certificate_store.exception.NotAStoreException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; @@ -36,7 +30,6 @@ import java.util.stream.Stream; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -44,7 +37,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue; 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" + @@ -151,10 +143,7 @@ public class PGPCertificateDirectoryTest { "-----END PGP PUBLIC KEY BLOCK-----\n"; private static final String CEDRIC_FP = "5e75bf20646bc1a98d3b1bc2fe9cd472987c4021"; - private static final KeyMaterialMerger merger = new TestKeyMaterialMerger(); - - private static Stream provideTestSubjects() - throws IOException, NotAStoreException { + private static Stream provideTestSubjects() throws IOException, NotAStoreException { PGPCertificateDirectory inMemory = PGPCertificateDirectories.inMemoryCertificateDirectory( new TestKeyMaterialReaderBackend()); @@ -170,19 +159,18 @@ public class PGPCertificateDirectoryTest { @ParameterizedTest @MethodSource("provideTestSubjects") - public void lockDirectoryAndInsertWillFail(PGPCertificateDirectory directory) - throws IOException, InterruptedException, BadDataException { + public void lockDirectoryAndInsertWillFail(PGPCertificateDirectory directory) throws IOException, InterruptedException, BadDataException { // Manually lock the dir assertFalse(directory.backend.getLock().isLocked()); directory.backend.getLock().lockDirectory(); 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(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), new TestKeyMaterialMerger()); assertNull(inserted); directory.backend.getLock().releaseDirectory(); - inserted = directory.tryInsert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); + inserted = directory.tryInsert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), new TestKeyMaterialMerger()); assertNotNull(inserted); } @@ -200,7 +188,7 @@ public class PGPCertificateDirectoryTest { ByteArrayInputStream bytesIn = new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)); - Certificate certificate = directory.insert(bytesIn, merger); + Certificate certificate = directory.insert(bytesIn, new TestKeyMaterialMerger()); assertEquals(CEDRIC_FP, certificate.getFingerprint(), "Fingerprint of inserted cert MUST match"); Certificate get = directory.getByFingerprint(CEDRIC_FP); @@ -219,7 +207,7 @@ public class PGPCertificateDirectoryTest { assertNull(directory.getTrustRoot()); KeyMaterial trustRootMaterial = directory.insertTrustRoot( - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); + new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), new TestKeyMaterialMerger()); assertNotNull(trustRootMaterial); assertTrue(trustRootMaterial instanceof Key); assertEquals(HARRY_FP, trustRootMaterial.getFingerprint()); @@ -229,8 +217,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(new ByteArrayInputStream(RON_CERT.getBytes(UTF8)), new TestKeyMaterialMerger()); + directory.insert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), new TestKeyMaterialMerger()); Set expected = new HashSet<>(Arrays.asList(RON_FP, CEDRIC_FP)); @@ -242,104 +230,4 @@ public class PGPCertificateDirectoryTest { assertEquals(expected, actual); } - - @ParameterizedTest - @MethodSource("provideTestSubjects") - public void testGetTrustRootIfChanged(PGPCertificateDirectory directory) - throws BadDataException, IOException, InterruptedException { - KeyMaterial trustRootMaterial = directory.insertTrustRoot( - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); - - assertNotNull(trustRootMaterial.getTag()); - Long tag = trustRootMaterial.getTag(); - assertNull(directory.getTrustRootCertificateIfChanged(tag)); - assertNotNull(directory.getTrustRootCertificateIfChanged(tag + 1)); - - Long oldTag = tag; - // "update" key - trustRootMaterial = directory.insertTrustRoot( - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), merger); - tag = trustRootMaterial.getTag(); - - assertNotEquals(oldTag, tag); - assertNotNull(directory.getTrustRootCertificateIfChanged(oldTag)); - } - - @ParameterizedTest - @MethodSource("provideTestSubjects") - public void testGetBySpecialNameIfChanged(PGPCertificateDirectory directory) - throws BadDataException, IOException, InterruptedException, BadNameException { - KeyMaterial specialName = directory.insertWithSpecialName(SpecialNames.TRUST_ROOT, - new ByteArrayInputStream(HARRY_KEY.getBytes(UTF8)), 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); - 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 - public void testFileBasedCertificateDirectoryTagChangesWhenFileChanges() throws IOException, NotAStoreException, BadDataException, InterruptedException, BadNameException { - File tempDir = Files.createTempDirectory("file-based-changes").toFile(); - tempDir.deleteOnExit(); - PGPCertificateDirectory directory = PGPCertificateDirectories.fileBasedCertificateDirectory( - new TestKeyMaterialReaderBackend(), - tempDir, - new InMemorySubkeyLookup()); - FileBasedCertificateDirectoryBackend.FilenameResolver resolver = - new FileBasedCertificateDirectoryBackend.FilenameResolver(tempDir); - - // Insert certificate - Certificate certificate = directory.insert(new ByteArrayInputStream(CEDRIC_CERT.getBytes(UTF8)), merger); - Long tag = certificate.getTag(); - assertNotNull(tag); - assertNull(directory.getByFingerprintIfChanged(certificate.getFingerprint(), tag)); - - Long oldTag = tag; - - // Change the file on disk directly, this invalidates the tag due to changed modification date - File certFile = resolver.getCertFileByFingerprint(certificate.getFingerprint()); - FileOutputStream fileOut = new FileOutputStream(certFile); - Streams.pipeAll(certificate.getInputStream(), fileOut); - fileOut.close(); - - // Old invalidated tag indicates a change, so the modified certificate is returned - certificate = directory.getByFingerprintIfChanged(certificate.getFingerprint(), oldTag); - assertNotNull(certificate); - - // new tag is valid - tag = certificate.getTag(); - assertNotEquals(oldTag, tag); - assertNull(directory.getByFingerprintIfChanged(certificate.getFingerprint(), tag)); - } } diff --git a/pgp-cert-d-java/src/test/java/pgp/cert_d/dummy/TestKeyMaterialMerger.java b/pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeyMaterialMerger.java similarity index 94% rename from pgp-cert-d-java/src/test/java/pgp/cert_d/dummy/TestKeyMaterialMerger.java rename to pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeyMaterialMerger.java index 8ca24c3..6810f0b 100644 --- a/pgp-cert-d-java/src/test/java/pgp/cert_d/dummy/TestKeyMaterialMerger.java +++ b/pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeyMaterialMerger.java @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package pgp.cert_d.dummy; +package pgp.cert_d; import pgp.certificate_store.certificate.KeyMaterial; import pgp.certificate_store.certificate.KeyMaterialMerger; diff --git a/pgp-cert-d-java/src/test/java/pgp/cert_d/dummy/TestKeyMaterialReaderBackend.java b/pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeyMaterialReaderBackend.java similarity index 58% rename from pgp-cert-d-java/src/test/java/pgp/cert_d/dummy/TestKeyMaterialReaderBackend.java rename to pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeyMaterialReaderBackend.java index 2ef392d..d653837 100644 --- a/pgp-cert-d-java/src/test/java/pgp/cert_d/dummy/TestKeyMaterialReaderBackend.java +++ b/pgp-cert-d-java/src/test/java/pgp/cert_d/TestKeyMaterialReaderBackend.java @@ -2,7 +2,7 @@ // // SPDX-License-Identifier: Apache-2.0 -package pgp.cert_d.dummy; +package pgp.cert_d; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPKeyRing; @@ -33,22 +33,24 @@ public class TestKeyMaterialReaderBackend implements KeyMaterialReaderBackend { KeyFingerPrintCalculator fpCalc = new BcKeyFingerprintCalculator(); @Override - public KeyMaterial read(InputStream data, Long tag) throws IOException, BadDataException { + public KeyMaterial read(InputStream data) throws IOException, BadDataException { ByteArrayOutputStream out = new ByteArrayOutputStream(); Streams.pipeAll(data, out); try { - return readKey(new ByteArrayInputStream(out.toByteArray()), tag); + Key key = readKey(new ByteArrayInputStream(out.toByteArray())); + return key; } catch (IOException | PGPException e) { try { - return readCertificate(new ByteArrayInputStream(out.toByteArray()), tag); + Certificate certificate = readCertificate(new ByteArrayInputStream(out.toByteArray())); + return certificate; } catch (IOException e1) { throw new BadDataException(); } } } - private Key readKey(InputStream inputStream, Long tag) throws IOException, PGPException { + private Key readKey(InputStream inputStream) throws IOException, PGPException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); Streams.pipeAll(inputStream, buffer); inputStream.close(); @@ -58,21 +60,64 @@ public class TestKeyMaterialReaderBackend implements KeyMaterialReaderBackend { PGPSecretKeyRing secretKeys = new PGPSecretKeyRing(decoderStream, fpCalc); PGPPublicKeyRing cert = extractCert(secretKeys); ByteArrayInputStream encoded = new ByteArrayInputStream(cert.getEncoded()); - Certificate certificate = readCertificate(encoded, tag); + Certificate certificate = readCertificate(encoded); - return new Key(buffer.toByteArray(), certificate, tag); + return new Key() { + @Override + public Certificate getCertificate() { + return certificate; + } + + @Override + public String getFingerprint() { + return certificate.getFingerprint(); + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(buffer.toByteArray()); + } + + @Override + public String getTag() throws IOException { + return null; + } + + @Override + public List getSubkeyIds() throws IOException { + return certificate.getSubkeyIds(); + } + }; } - private Certificate readCertificate(InputStream inputStream, Long tag) throws IOException { + private Certificate readCertificate(InputStream inputStream) throws IOException { ByteArrayOutputStream buffer = new ByteArrayOutputStream(); Streams.pipeAll(inputStream, buffer); ByteArrayInputStream in = new ByteArrayInputStream(buffer.toByteArray()); InputStream decoderStream = PGPUtil.getDecoderStream(in); PGPPublicKeyRing cert = new PGPPublicKeyRing(decoderStream, fpCalc); - String fingerprint = Hex.toHexString(cert.getPublicKey().getFingerprint()).toLowerCase(); - List subKeyIds = getSubkeyIds(cert); - return new Certificate(buffer.toByteArray(), fingerprint, subKeyIds, tag); + return new Certificate() { + @Override + public String getFingerprint() { + return Hex.toHexString(cert.getPublicKey().getFingerprint()).toLowerCase(); + } + + @Override + public InputStream getInputStream() throws IOException { + return new ByteArrayInputStream(buffer.toByteArray()); + } + + @Override + public String getTag() throws IOException { + return null; + } + + @Override + public List getSubkeyIds() throws IOException { + return TestKeyMaterialReaderBackend.getSubkeyIds(cert); + } + }; } private PGPPublicKeyRing extractCert(PGPSecretKeyRing secretKeys) { @@ -81,7 +126,8 @@ public class TestKeyMaterialReaderBackend implements KeyMaterialReaderBackend { while (publicKeyIterator.hasNext()) { publicKeyList.add(publicKeyIterator.next()); } - return new PGPPublicKeyRing(publicKeyList); + PGPPublicKeyRing publicKeyRing = new PGPPublicKeyRing(publicKeyList); + return publicKeyRing; } private static List getSubkeyIds(PGPKeyRing keyRing) { diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/PGPCertificateStore.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/PGPCertificateStore.java index d0915b0..acca57e 100644 --- a/pgp-certificate-store/src/main/java/pgp/certificate_store/PGPCertificateStore.java +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/PGPCertificateStore.java @@ -32,23 +32,6 @@ public interface PGPCertificateStore { Certificate getCertificate(String identifier) throws IOException, BadNameException, BadDataException; - /** - * Return the certificate that matches the given identifier, but only if it has been changed. - * Whether it has been changed is determined by calculating the tag in the directory - * (e.g. by looking at the inode and last modification date) and comparing the result with the tag provided by - * the caller. - * - * @param identifier certificate identifier - * @param tag tag by the caller - * @return certificate if it has been changed, null otherwise - * - * @throws IOException in case of an IO-error - * @throws BadNameException if the identifier is invalid - * @throws BadDataException if the certificate file contains invalid data - */ - Certificate getCertificateIfChanged(String identifier, Long tag) - throws IOException, BadNameException, BadDataException; - /** * Return an {@link Iterator} over all certificates in the store that contain a subkey with the given * subkey id. @@ -59,7 +42,7 @@ public interface PGPCertificateStore { * @throws BadDataException if any of the certificate files contains invalid data */ Iterator getCertificatesBySubkeyId(long subkeyId) - throws IOException, BadDataException; + throws IOException, BadDataException; /** * Insert a certificate into the store. diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Certificate.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Certificate.java index 175f739..d2b1d1b 100644 --- a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Certificate.java +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Certificate.java @@ -4,67 +4,13 @@ package pgp.certificate_store.certificate; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.List; - /** * OpenPGP certificate (public key). */ -public class Certificate implements KeyMaterial { - - private final byte[] bytes; - private final String fingerprint; - private final List subkeyIds; - private final Long tag; - - /** - * Certificate constructor. - * - * @param bytes encoding of the certificate - * @param fingerprint fingerprint (lowercase hex characters) - * @param subkeyIds list of subkey ids - * @param tag tag - */ - public Certificate(byte[] bytes, String fingerprint, List subkeyIds, Long tag) { - this.bytes = bytes; - this.fingerprint = fingerprint; - this.subkeyIds = subkeyIds; - this.tag = tag; - } - - /** - * Copy constructor to assign a new tag to the {@link Certificate}. - * - * @param cert certificate - * @param tag tag - */ - public Certificate(Certificate cert, Long tag) { - this(cert.bytes, cert.fingerprint, cert.subkeyIds, tag); - } - - @Override - public String getFingerprint() { - return fingerprint; - } +public abstract class Certificate implements KeyMaterial { @Override public Certificate asCertificate() { return this; } - - @Override - public InputStream getInputStream() { - return new ByteArrayInputStream(bytes); - } - - @Override - public Long getTag() { - return tag; - } - - @Override - public List getSubkeyIds() { - return subkeyIds; - } } diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Key.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Key.java index a2a4aef..5d6d713 100644 --- a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Key.java +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/Key.java @@ -4,74 +4,21 @@ package pgp.certificate_store.certificate; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.util.List; - /** * OpenPGP key (secret key). */ -public class Key implements KeyMaterial { - - private final byte[] bytes; - private final Certificate certificate; - private final Long tag; - - /** - * Key constructor. - * - * @param bytes encoding of the key - * @param certificate associated certificate - * @param tag tag - */ - public Key(byte[] bytes, Certificate certificate, Long tag) { - this.bytes = bytes; - this.certificate = certificate; - this.tag = tag; - } - - /** - * Copy constructor to change the tag of both the {@link Key} and its {@link Certificate}. - * - * @param key key - * @param tag tag - */ - public Key(Key key, Long tag) { - this(key.bytes, new Certificate(key.certificate, tag), tag); - } +public abstract class Key implements KeyMaterial { /** * Return the certificate part of this OpenPGP key. * * @return OpenPGP certificate */ - public Certificate getCertificate() { - return new Certificate(certificate, getTag()); - } - - @Override - public String getFingerprint() { - return certificate.getFingerprint(); - } + public abstract Certificate getCertificate(); @Override public Certificate asCertificate() { return getCertificate(); } - @Override - public InputStream getInputStream() { - return new ByteArrayInputStream(bytes); - } - - @Override - public Long getTag() { - return tag; - } - - @Override - public List getSubkeyIds() { - return certificate.getSubkeyIds(); - } - } diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterial.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterial.java index 1438b47..5293edf 100644 --- a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterial.java +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterial.java @@ -4,6 +4,7 @@ package pgp.certificate_store.certificate; +import java.io.IOException; import java.io.InputStream; import java.util.List; import java.util.Set; @@ -18,34 +19,23 @@ public interface KeyMaterial { */ String getFingerprint(); - /** - * Return the {@link Certificate} belonging to this key material. - * If this is already a {@link Certificate}, return this. - * If this is a {@link Key}, extract the {@link Certificate} and return it. - * - * @return certificate - */ Certificate asCertificate(); /** * Return an {@link InputStream} of the binary representation of the secret key. * * @return input stream + * @throws IOException in case of an IO error */ - InputStream getInputStream(); + InputStream getInputStream() throws IOException; - /** - * Return the tag belonging to this key material. - * The tag can be used to keep an application cache in sync with what is in the directory. - * - * @return tag - */ - Long getTag(); + String getTag() throws IOException; /** * Return a {@link Set} containing key-ids of subkeys. * * @return subkeys + * @throws IOException in case of an IO error */ - List getSubkeyIds(); + List getSubkeyIds() throws IOException; } diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterialReaderBackend.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterialReaderBackend.java index c921d64..42b2bb4 100644 --- a/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterialReaderBackend.java +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/certificate/KeyMaterialReaderBackend.java @@ -15,11 +15,10 @@ public interface KeyMaterialReaderBackend { * Read a {@link KeyMaterial} (either {@link Key} or {@link Certificate}) from the given {@link InputStream}. * * @param data input stream containing the binary representation of the key. - * @param tag tag for the key material. Might be null. * @return key or certificate object * * @throws IOException in case of an IO error * @throws BadDataException in case that the data stream does not contain a valid OpenPGP key/certificate */ - KeyMaterial read(InputStream data, Long tag) throws IOException, BadDataException; + KeyMaterial read(InputStream data) throws IOException, BadDataException; } diff --git a/version.gradle b/version.gradle index 1951785..0287d07 100644 --- a/version.gradle +++ b/version.gradle @@ -6,7 +6,7 @@ allprojects { ext { shortVersion = '0.1.2' isSnapshot = true - minAndroidSdk = 26 + minAndroidSdk = 10 javaSourceCompatibility = 1.8 bouncycastleVersion = '1.71' slf4jVersion = '1.7.36'