Reintroduce pgp-certificate-store layer

This commit is contained in:
Paul Schaub 2022-08-12 14:10:09 +02:00
parent f91c5065fc
commit a3162f0cf9
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
25 changed files with 330 additions and 49 deletions

View file

@ -0,0 +1,13 @@
<!--
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

@ -0,0 +1,36 @@
// 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

@ -0,0 +1,104 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store;
import pgp.certificate_store.certificate.Certificate;
import pgp.certificate_store.certificate.KeyMaterialMerger;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
/**
* Interface for an OpenPGP certificate (public key) store.
*/
public interface PGPCertificateStore {
/**
* 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 an {@link Iterator} over all certificates in the store that contain a subkey with the given
* subkey id.
* @param subkeyId id of the subkey
* @return iterator
*
* @throws IOException in case of an IO error
* @throws BadDataException if any of the certificate files contains invalid data
*/
Iterator<Certificate> getCertificatesBySubkeyId(long subkeyId)
throws IOException, 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.
*
* @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.
* 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.
*
* @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;
/**
* 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();
}

View file

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.certificate;
/**
* OpenPGP certificate (public key).
*/
public abstract class Certificate implements KeyMaterial {
@Override
public Certificate asCertificate() {
return this;
}
}

View file

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.certificate;
/**
* OpenPGP key (secret key).
*/
public abstract class Key implements KeyMaterial {
/**
* Return the certificate part of this OpenPGP key.
*
* @return OpenPGP certificate
*/
public abstract Certificate getCertificate();
@Override
public Certificate asCertificate() {
return getCertificate();
}
}

View file

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.certificate;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Set;
public interface KeyMaterial {
/**
* Return the fingerprint of the certificate as 40 lowercase hex characters.
* TODO: Allow OpenPGP V5 fingerprints
*
* @return fingerprint
*/
String getFingerprint();
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() throws IOException;
String getTag() throws IOException;
/**
* Return a {@link Set} containing key-ids of subkeys.
*
* @return subkeys
* @throws IOException in case of an IO error
*/
List<Long> getSubkeyIds() throws IOException;
}

View file

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.certificate;
import java.io.IOException;
/**
* Merge a given {@link Key} (update) with an existing {@link Key}.
*/
public interface KeyMaterialMerger {
/**
* Merge the given key material with an existing copy and return the result.
* If no existing {@link KeyMaterial} is found (i.e. if existing is null), this method returns the unmodified data.
*
* @param data key material
* @param existing optional already existing copy of the key material
* @return merged key material
*
* @throws IOException in case of an IO error
*/
KeyMaterial merge(KeyMaterial data, KeyMaterial existing) throws IOException;
}

View file

@ -0,0 +1,24 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.certificate;
import pgp.certificate_store.exception.BadDataException;
import java.io.IOException;
import java.io.InputStream;
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.
* @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) throws IOException, BadDataException;
}

View file

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* General OpenPGP Certificate Storage related classes.
*/
package pgp.certificate_store.certificate;

View file

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.exception;
/**
* The data was not a valid OpenPGP cert or key in binary format.
*/
public class BadDataException extends Exception {
}

View file

@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.exception;
/**
* Provided name was neither a valid fingerprint, nor a known special name.
*/
public class BadNameException extends Exception {
public BadNameException() {
super();
}
public BadNameException(String message) {
super(message);
}
}

View file

@ -0,0 +1,19 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store.exception;
/**
* The base dir cannot possibly contain a store.
*/
public class NotAStoreException extends Exception {
public NotAStoreException() {
super();
}
public NotAStoreException(String message) {
super(message);
}
}

View file

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Exceptions.
*/
package pgp.certificate_store.exception;

View file

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* Abstract definitions of an OpenPGP certificate store.
*/
package pgp.certificate_store;

View file

@ -0,0 +1,16 @@
// 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);
}
}