diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/Key.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/Key.java new file mode 100644 index 0000000..00cc5c6 --- /dev/null +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/Key.java @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.certificate_store; + +import java.io.IOException; +import java.io.InputStream; + +/** + * OpenPGP key (secret key). + */ +public abstract class Key { + + /** + * Return the certificate part of this OpenPGP key. + * + * @return OpenPGP certificate + */ + public abstract Certificate getCertificate(); + + /** + * Return an {@link InputStream} of the binary representation of the secret key. + * + * @return input stream + * @throws IOException in case of an IO error + */ + public abstract InputStream getInputStream() throws IOException; + + public abstract String getTag() throws IOException; + +} diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/KeyMerger.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/KeyMerger.java new file mode 100644 index 0000000..3a7a7c5 --- /dev/null +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/KeyMerger.java @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.certificate_store; + +import java.io.IOException; + +/** + * Merge a given {@link Key} (update) with an existing {@link Key}. + */ +public interface KeyMerger { + + /** + * Merge the given key data with the existing {@link Key} and return the result. + * If no existing {@link Key} is found (i.e. if existing is null), this method returns the unmodified data. + * + * @param data key + * @param existing optional already existing copy of the key + * @return merged key + * + * @throws IOException in case of an IO error + */ + Key merge(Key data, Key existing) throws IOException; +} diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/KeyReaderBackend.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/KeyReaderBackend.java new file mode 100644 index 0000000..f774150 --- /dev/null +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/KeyReaderBackend.java @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.certificate_store; + +import pgp.certificate_store.exception.BadDataException; + +import java.io.IOException; +import java.io.InputStream; + +public interface KeyReaderBackend { + + /** + * Read a {@link Key} from the given {@link InputStream}. + * + * @param data input stream containing the binary representation of the key. + * @return key object + * + * @throws IOException in case of an IO error + * @throws BadDataException in case that the data stream does not contain a valid OpenPGP key + */ + Key readKey(InputStream data) throws IOException, BadDataException; +} diff --git a/pgp-certificate-store/src/main/java/pgp/certificate_store/TrustRootStore.java b/pgp-certificate-store/src/main/java/pgp/certificate_store/TrustRootStore.java new file mode 100644 index 0000000..4e9f118 --- /dev/null +++ b/pgp-certificate-store/src/main/java/pgp/certificate_store/TrustRootStore.java @@ -0,0 +1,82 @@ +// SPDX-FileCopyrightText: 2022 Paul Schaub +// +// SPDX-License-Identifier: Apache-2.0 + +package pgp.certificate_store; + +import pgp.certificate_store.exception.BadDataException; + +import java.io.IOException; +import java.io.InputStream; + +/** + * Secret key store definition for trust-root keys. + */ +public interface TrustRootStore { + + /** + * Return the current trust-root key. + * If no trust-root key is present, return null. + * + * @return trust-root key + * + * @throws IOException in case of an IO error + * @throws BadDataException if the key datum contains invalid data + */ + Key getTrustRoot() + throws IOException, BadDataException; + + /** + * Return the current trust-root key, but only iff it changed since the last invocation of this method. + * To compare the key against its last returned result, the given tag is used. + * If the tag of the currently found key matches the given argument, return null. + * + * @param tag tag to compare freshness + * @return changed key or null + * + * @throws IOException in case of an IO error + * @throws BadDataException if the key datum contains invalid data + */ + Key getTrustRootIfChanged(String tag) + throws IOException, BadDataException; + + /** + * Insert the given trust-root key into the store. + * If the key store already holds a trust-root key, the given {@link KeyMerger} callback will be used to merge + * the two instances into one {@link Key}. The result will be stored in the store and returned. + * + * This method will not block. Instead, if the store is already write-locked, this method will simply return null + * without writing anything. + * However, if the write-lock is available, this method will acquire the lock, write to the store, release the lock + * and return the written key. + * + * @param data input stream containing the new trust-root key + * @param keyMerger callback for merging with an existing key instance + * @return merged key + * + * @throws IOException in case of an IO error + * @throws InterruptedException in case the inserting thread gets interrupted + * @throws BadDataException if the data stream does not contain a valid OpenPGP key + */ + Key insertTrustRoot(InputStream data, KeyMerger keyMerger) + throws IOException, InterruptedException, BadDataException; + + /** + * Insert the given trust-root key into the store. + * If the key store already holds a trust-root key, the given {@link KeyMerger} callback will be used to merge + * the two instances into one {@link Key}. The result will be stored in the store and returned. + * + * This method will block until a write-lock on the store can be acquired. If you cannot afford blocking, + * consider using {@link #tryInsertTrustRoot(InputStream, KeyMerger)} instead. + * + * @param data input stream containing the new trust-root key + * @param keyMerger callback for merging with an existing key instance + * @return merged key + * + * @throws IOException in case of an IO error + * @throws InterruptedException in case the inserting thread gets interrupted + * @throws BadDataException if the data stream does not contain a valid OpenPGP key + */ + Key tryInsertTrustRoot(InputStream data, KeyMerger keyMerger) + throws IOException, BadDataException; +}