Get rid of certificate-store abstraction

This commit is contained in:
Paul Schaub 2022-08-09 18:00:27 +02:00
parent 7c39781d15
commit 7cc0ef5037
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
30 changed files with 31 additions and 399 deletions

View file

@ -11,7 +11,7 @@ import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import pgp.certificate_store.SubkeyLookup; import pgp.cert_d.SubkeyLookup;
public class DatabaseSubkeyLookup implements SubkeyLookup { public class DatabaseSubkeyLookup implements SubkeyLookup {

View file

@ -3,6 +3,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
/** /**
* Implementation of a {@link pgp.certificate_store.SubkeyLookup} mechanism using an SQLite Database. * Implementation of a {@link pgp.cert_d.SubkeyLookup} mechanism using an SQLite Database.
*/ */
package pgp.cert_d.jdbc.sqlite; package pgp.cert_d.jdbc.sqlite;

View file

@ -28,9 +28,6 @@ dependencies {
// SQL Subkey table // SQL Subkey table
testImplementation project(":pgp-cert-d-java-jdbc-sqlite-lookup") testImplementation project(":pgp-cert-d-java-jdbc-sqlite-lookup")
// Certificate store
api project(":pgp-certificate-store")
} }
animalsniffer { animalsniffer {

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.exception; package pgp.cert_d;
/** /**
* The data was not a valid OpenPGP cert or key in binary format. * The data was not a valid OpenPGP cert or key in binary format.

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.exception; package pgp.cert_d;
/** /**
* Provided name was neither a valid fingerprint, nor a known special name. * Provided name was neither a valid fingerprint, nor a known special name.

View file

@ -4,13 +4,10 @@
package pgp.cert_d; package pgp.cert_d;
import pgp.certificate_store.Certificate; import pgp.certificate.Certificate;
import pgp.certificate_store.KeyMaterial; import pgp.certificate.KeyMaterial;
import pgp.certificate_store.KeyMaterialMerger; import pgp.certificate.KeyMaterialMerger;
import pgp.certificate_store.KeyMaterialReaderBackend; import pgp.certificate.KeyMaterialReaderBackend;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import pgp.certificate_store.exception.NotAStoreException;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.File; import java.io.File;

View file

@ -4,12 +4,10 @@
package pgp.cert_d; package pgp.cert_d;
import pgp.certificate_store.Certificate; import pgp.certificate.Certificate;
import pgp.certificate_store.KeyMaterial; import pgp.certificate.KeyMaterial;
import pgp.certificate_store.KeyMaterialMerger; import pgp.certificate.KeyMaterialMerger;
import pgp.certificate_store.KeyMaterialReaderBackend; import pgp.certificate.KeyMaterialReaderBackend;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;

View file

@ -11,8 +11,6 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import pgp.certificate_store.SubkeyLookup;
public class InMemorySubkeyLookup implements SubkeyLookup { public class InMemorySubkeyLookup implements SubkeyLookup {
private static final Map<Long, Set<String>> subkeyMap = new HashMap<>(); private static final Map<Long, Set<String>> subkeyMap = new HashMap<>();

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.exception; package pgp.cert_d;
/** /**
* The base dir cannot possibly contain a store. * The base dir cannot possibly contain a store.

View file

@ -4,8 +4,7 @@
package pgp.cert_d; package pgp.cert_d;
import pgp.certificate_store.KeyMaterialReaderBackend; import pgp.certificate.KeyMaterialReaderBackend;
import pgp.certificate_store.exception.NotAStoreException;
import java.io.File; import java.io.File;

View file

@ -4,11 +4,9 @@
package pgp.cert_d; package pgp.cert_d;
import pgp.certificate_store.Certificate; import pgp.certificate.Certificate;
import pgp.certificate_store.KeyMaterial; import pgp.certificate.KeyMaterial;
import pgp.certificate_store.KeyMaterialMerger; import pgp.certificate.KeyMaterialMerger;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;

View file

@ -4,9 +4,7 @@
package pgp.cert_d; package pgp.cert_d;
import pgp.certificate_store.Certificate; import pgp.certificate.Certificate;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import java.io.IOException; import java.io.IOException;
import java.util.Iterator; import java.util.Iterator;

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store; package pgp.cert_d;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;

View file

@ -4,11 +4,9 @@
package pgp.cert_d; package pgp.cert_d;
import pgp.certificate_store.Certificate; import pgp.certificate.Certificate;
import pgp.certificate_store.KeyMaterial; import pgp.certificate.KeyMaterial;
import pgp.certificate_store.KeyMaterialMerger; import pgp.certificate.KeyMaterialMerger;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store; package pgp.certificate;
/** /**
* OpenPGP certificate (public key). * OpenPGP certificate (public key).

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store; package pgp.certificate;
/** /**
* OpenPGP key (secret key). * OpenPGP key (secret key).

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store; package pgp.certificate;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;

View file

@ -2,7 +2,7 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store; package pgp.certificate;
import java.io.IOException; import java.io.IOException;

View file

@ -2,9 +2,9 @@
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store; package pgp.certificate;
import pgp.certificate_store.exception.BadDataException; import pgp.cert_d.BadDataException;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;

View file

@ -3,6 +3,6 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
/** /**
* Abstract definitions of an OpenPGP certificate store. * General OpenPGP Certificate Storage related classes.
*/ */
package pgp.certificate_store; package pgp.certificate;

View file

@ -6,7 +6,6 @@ package pgp.cert_d;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import pgp.certificate_store.exception.BadNameException;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;

View file

@ -24,7 +24,6 @@ import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import pgp.cert_d.jdbc.sqlite.DatabaseSubkeyLookup; import pgp.cert_d.jdbc.sqlite.DatabaseSubkeyLookup;
import pgp.cert_d.jdbc.sqlite.SqliteSubkeyLookupDaoImpl; import pgp.cert_d.jdbc.sqlite.SqliteSubkeyLookupDaoImpl;
import pgp.certificate_store.SubkeyLookup;
public class SubkeyLookupTest { public class SubkeyLookupTest {

View file

@ -1,13 +0,0 @@
<!--
SPDX-FileCopyrightText: 2022 Paul Schaub <info@pgpainless.org>
SPDX-License-Identifier: Apache-2.0
-->
# PGP Certificate Store Definitions
[![javadoc](https://javadoc.io/badge2/org.pgpainless/pgp-certificate-store/javadoc.svg)](https://javadoc.io/doc/org.pgpainless/pgp-certificate-store)
[![Maven Central](https://badgen.net/maven/v/maven-central/org.pgpainless/pgp-certificate-store)](https://search.maven.org/artifact/org.pgpainless/pgp-certificate-store)
This module contains API definitions for an OpenPGP certificate store.
A certificate store is used to store public key certificates only.

View file

@ -1,36 +0,0 @@
// SPDX-FileCopyrightText: 2021 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
plugins {
id 'java-library'
}
group 'org.pgpainless'
repositories {
mavenCentral()
}
apply plugin: 'ru.vyarus.animalsniffer'
dependencies {
// animal sniffer for ensuring Android API compatibility
signature "net.sf.androidscents.signature:android-api-level-${minAndroidSdk}:2.3.3_r2@signature"
// JUnit for testing
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
// Logging
api "org.slf4j:slf4j-api:$slf4jVersion"
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
}
animalsniffer {
sourceSets = [sourceSets.main]
}
test {
useJUnitPlatform()
}

View file

@ -1,39 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import java.io.IOException;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
public abstract class AbstractCertificateStore implements CertificateStore {
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractCertificateStore.class);
public Set<Certificate> getCertificatesBySubkeyId(long subkeyId)
throws IOException {
Set<String> identifiers = getCertificateFingerprintsForSubkeyId(subkeyId);
if (identifiers.isEmpty()) {
return Collections.emptySet();
}
Set<Certificate> certificates = new HashSet<>();
for (String identifier : identifiers) {
try {
certificates.add(getCertificate(identifier));
} catch (BadNameException | BadDataException e) {
LOGGER.warn("Could not read certificate.", e);
}
}
return certificates;
}
}

View file

@ -1,225 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
/**
* Certificate storage definition.
* This interface defines methods to insert and retrieve {@link Certificate Certificates} to and from a store.
*
* {@link Certificate Certificates} are hereby identified by identifiers. An identifier can either be a fingerprint
* or a special name. Special names are implementation-defined identifiers for certificates.
*
* Fingerprints are expected to be hexadecimal lowercase character sequences.
*/
public interface CertificateDirectory {
/**
* Return the certificate that matches the given identifier.
* If no matching certificate can be found, return null.
*
* @param identifier identifier for a certificate.
* @return certificate or null
*
* @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 getCertificate(String identifier)
throws IOException, BadNameException, BadDataException;
/**
* Return the certificate that matches the given identifier, but only iff it changed since the last invocation.
* To compare the certificate against its last returned result, the given tag is used.
* If the tag of the currently found certificate matches the given argument, return null.
*
* @param identifier identifier for a certificate
* @param tag tag to compare freshness
* @return changed certificate or null
*
* @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, String tag)
throws IOException, BadNameException, BadDataException;
/**
* Insert a certificate into the store.
* If an instance of the certificate is already present in the store, the given {@link KeyMaterialMerger} will be
* used to merge both the existing and the new instance of the {@link Certificate}. The resulting merged certificate
* 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 to use {@link #tryInsertCertificate(InputStream, KeyMaterialMerger)} instead.
*
* @param data input stream containing the new certificate instance
* @param merge callback for merging with an existing certificate instance
* @return merged certificate
*
* @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 valid OpenPGP data
*/
Certificate insertCertificate(InputStream data, KeyMaterialMerger merge)
throws IOException, InterruptedException, BadDataException;
/**
* Insert a certificate into the store.
* If an instance of the certificate is already present in the store, the given {@link KeyMaterialMerger} will be
* used to merge both the existing and the new instance of the {@link Certificate}. The resulting merged certificate
* 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 any writing.
* However, if the write-lock is available, this method will acquire the lock, write to the store, release the lock
* and return the written certificate.
*
* @param data input stream containing the new certificate instance
* @param merge callback for merging with an existing certificate instance
* @return merged certificate or null if the store cannot be locked
*
* @throws IOException in case of an IO-error
* @throws BadDataException if the data stream does not contain valid OpenPGP data
*/
Certificate tryInsertCertificate(InputStream data, KeyMaterialMerger merge)
throws IOException, BadDataException;
/**
* Insert a certificate into the store.
* The certificate will be stored under the given special name instead of its fingerprint.
*
* If an instance of the certificate is already present under the special name in the store, the given {@link KeyMaterialMerger} will be
* used to merge both the existing and the new instance of the {@link Certificate}. The resulting merged certificate
* 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 to use {@link #tryInsertCertificateBySpecialName(String, InputStream, KeyMaterialMerger)} instead.
*
* @param specialName special name of the certificate
* @param data input stream containing the new certificate instance
* @param merge callback for merging with an existing certificate instance
* @return merged certificate or null if the store cannot be locked
*
* @throws IOException in case of an IO-error
* @throws InterruptedException if the thread is interrupted
* @throws BadDataException if the certificate file does not contain valid OpenPGP data
* @throws BadNameException if the special name is unknown
*/
Certificate insertCertificateBySpecialName(String specialName, InputStream data, KeyMaterialMerger merge)
throws IOException, InterruptedException, BadDataException, BadNameException;
/**
* Insert a certificate into the store.
* The certificate will be stored under the given special name instead of its fingerprint.
*
* If an instance of the certificate is already present under the special name in the store, the given {@link KeyMaterialMerger} will be
* used to merge both the existing and the new instance of the {@link Certificate}. The resulting merged certificate
* 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 any writing.
* However, if the write-lock is available, this method will acquire the lock, write to the store, release the lock
* and return the written certificate.
*
* @param specialName special name for the certificate
* @param data input stream containing the new certificate instance
* @param merge callback for merging with an existing certificate instance
* @return merged certificate or null if the store cannot be locked
*
* @throws IOException in case of an IO-error
* @throws BadDataException if the data stream does not contain valid OpenPGP data
* @throws BadNameException if the special name is not known
*/
Certificate tryInsertCertificateBySpecialName(String specialName, InputStream data, KeyMaterialMerger merge)
throws IOException, BadDataException, BadNameException;
/**
* Return an {@link Iterator} containing all certificates in the store.
* The iterator will contain both certificates addressed by special names and by fingerprints.
*
* @return certificates
*/
Iterator<Certificate> getCertificates();
/**
* Return an {@link Iterator} containing all certificate fingerprints from the store.
* Note that this only includes the fingerprints of certificate primary keys, not those of subkeys.
*
* @return fingerprints
*/
Iterator<String> getFingerprints();
/**
* 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 KeyMaterialMerger} 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, KeyMaterialMerger 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 KeyMaterialMerger} 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, KeyMaterialMerger)} 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 BadDataException if the data stream does not contain a valid OpenPGP key
*/
Key tryInsertTrustRoot(InputStream data, KeyMaterialMerger keyMerger)
throws IOException, BadDataException;
}

View file

@ -1,9 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store;
public interface CertificateStore extends CertificateDirectory, SubkeyLookup {
}

View file

@ -1,10 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Exceptions defined by the Shared PGP Certificate Directory.
*
* @see <a href="https://sequoia-pgp.gitlab.io/pgp-cert-d/#name-failure-modes">Failure Modes</a>
*/
package pgp.certificate_store.exception;

View file

@ -1,16 +0,0 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class DummyTest {
@Test
public void test() {
assertTrue(true);
}
}

View file

@ -5,6 +5,5 @@
rootProject.name = 'cert-d-java' rootProject.name = 'cert-d-java'
include 'pgp-cert-d-java', include 'pgp-cert-d-java',
'pgp-cert-d-java-jdbc-sqlite-lookup', 'pgp-cert-d-java-jdbc-sqlite-lookup'
'pgp-certificate-store'