Make Key and Certificate extend KeyMaterial,

get rid of CertificateReader
This commit is contained in:
Paul Schaub 2022-08-08 13:50:59 +02:00
parent 2b5da18fc6
commit 942b287beb
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
7 changed files with 55 additions and 62 deletions

View file

@ -4,14 +4,11 @@
package pgp.cert_d; package pgp.cert_d;
import pgp.certificate_store.CertificateReaderBackend;
import pgp.certificate_store.CertificateMerger; import pgp.certificate_store.CertificateMerger;
import pgp.certificate_store.KeyReaderBackend; import pgp.certificate_store.KeyReaderBackend;
public abstract class BackendProvider { public abstract class BackendProvider {
public abstract CertificateReaderBackend provideCertificateReaderBackend();
public abstract KeyReaderBackend provideKeyReaderBackend(); public abstract KeyReaderBackend provideKeyReaderBackend();
public abstract CertificateMerger provideDefaultMergeCallback(); public abstract CertificateMerger provideDefaultMergeCallback();

View file

@ -17,54 +17,47 @@ import java.util.Iterator;
import java.util.List; import java.util.List;
import pgp.certificate_store.Key; import pgp.certificate_store.Key;
import pgp.certificate_store.KeyMaterial;
import pgp.certificate_store.KeyMerger; import pgp.certificate_store.KeyMerger;
import pgp.certificate_store.KeyReaderBackend; import pgp.certificate_store.KeyReaderBackend;
import pgp.certificate_store.exception.BadDataException; import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException; import pgp.certificate_store.exception.BadNameException;
import pgp.certificate_store.exception.NotAStoreException; import pgp.certificate_store.exception.NotAStoreException;
import pgp.certificate_store.Certificate; import pgp.certificate_store.Certificate;
import pgp.certificate_store.CertificateReaderBackend;
import pgp.certificate_store.CertificateMerger; import pgp.certificate_store.CertificateMerger;
public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDirectory { public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDirectory {
private final FilenameResolver resolver; private final FilenameResolver resolver;
private final LockingMechanism writeLock; private final LockingMechanism writeLock;
private final CertificateReaderBackend certificateReaderBackend;
private final KeyReaderBackend keyReaderBackend; private final KeyReaderBackend keyReaderBackend;
public SharedPGPCertificateDirectoryImpl(BackendProvider backendProvider) public SharedPGPCertificateDirectoryImpl(BackendProvider backendProvider)
throws NotAStoreException { throws NotAStoreException {
this(backendProvider.provideCertificateReaderBackend(), backendProvider.provideKeyReaderBackend()); this(backendProvider.provideKeyReaderBackend());
} }
public SharedPGPCertificateDirectoryImpl(CertificateReaderBackend certificateReaderBackend, public SharedPGPCertificateDirectoryImpl(KeyReaderBackend keyReaderBackend)
KeyReaderBackend keyReaderBackend)
throws NotAStoreException { throws NotAStoreException {
this( this(
BaseDirectoryProvider.getDefaultBaseDir(), BaseDirectoryProvider.getDefaultBaseDir(),
certificateReaderBackend,
keyReaderBackend); keyReaderBackend);
} }
public SharedPGPCertificateDirectoryImpl(File baseDirectory, public SharedPGPCertificateDirectoryImpl(File baseDirectory,
CertificateReaderBackend certificateReaderBackend,
KeyReaderBackend keyReaderBackend) KeyReaderBackend keyReaderBackend)
throws NotAStoreException { throws NotAStoreException {
this( this(
certificateReaderBackend,
keyReaderBackend, keyReaderBackend,
new FilenameResolver(baseDirectory), new FilenameResolver(baseDirectory),
FileLockingMechanism.defaultDirectoryFileLock(baseDirectory)); FileLockingMechanism.defaultDirectoryFileLock(baseDirectory));
} }
public SharedPGPCertificateDirectoryImpl( public SharedPGPCertificateDirectoryImpl(
CertificateReaderBackend certificateReaderBackend,
KeyReaderBackend keyReaderBackend, KeyReaderBackend keyReaderBackend,
FilenameResolver filenameResolver, FilenameResolver filenameResolver,
LockingMechanism writeLock) LockingMechanism writeLock)
throws NotAStoreException { throws NotAStoreException {
this.certificateReaderBackend = certificateReaderBackend;
this.keyReaderBackend = keyReaderBackend; this.keyReaderBackend = keyReaderBackend;
this.resolver = filenameResolver; this.resolver = filenameResolver;
this.writeLock = writeLock; this.writeLock = writeLock;
@ -96,8 +89,8 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
FileInputStream fileIn = new FileInputStream(certFile); FileInputStream fileIn = new FileInputStream(certFile);
BufferedInputStream bufferedIn = new BufferedInputStream(fileIn); BufferedInputStream bufferedIn = new BufferedInputStream(fileIn);
Certificate certificate = certificateReaderBackend.readCertificate(bufferedIn);
Certificate certificate = readCertificate(bufferedIn);
if (!certificate.getFingerprint().equals(fingerprint)) { if (!certificate.getFingerprint().equals(fingerprint)) {
// TODO: Figure out more suitable exception // TODO: Figure out more suitable exception
throw new BadDataException(); throw new BadDataException();
@ -106,6 +99,28 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
return certificate; return certificate;
} }
private Certificate readCertificate(InputStream inputStream) throws BadDataException, IOException {
KeyMaterial record = keyReaderBackend.read(inputStream);
Certificate certificate = null;
if (record instanceof Certificate) {
certificate = (Certificate) record;
} else if (record instanceof Key) {
Key key = (Key) record;
certificate = key.getCertificate();
} else {
throw new BadDataException();
}
return certificate;
}
private Key readKey(InputStream inputStream) throws BadDataException, IOException {
KeyMaterial record = keyReaderBackend.read(inputStream);
if (record instanceof Key) {
return (Key) record;
}
throw new BadDataException();
}
@Override @Override
public Certificate getBySpecialName(String specialName) public Certificate getBySpecialName(String specialName)
throws IOException, BadNameException, BadDataException { throws IOException, BadNameException, BadDataException {
@ -116,7 +131,7 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
FileInputStream fileIn = new FileInputStream(certFile); FileInputStream fileIn = new FileInputStream(certFile);
BufferedInputStream bufferedIn = new BufferedInputStream(fileIn); BufferedInputStream bufferedIn = new BufferedInputStream(fileIn);
Certificate certificate = certificateReaderBackend.readCertificate(bufferedIn); Certificate certificate = readCertificate(bufferedIn);
return certificate; return certificate;
} }
@ -155,7 +170,7 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
} }
FileInputStream fileIn = new FileInputStream(keyFile); FileInputStream fileIn = new FileInputStream(keyFile);
BufferedInputStream bufferedInputStream = new BufferedInputStream(fileIn); BufferedInputStream bufferedInputStream = new BufferedInputStream(fileIn);
Key key = keyReaderBackend.readKey(bufferedInputStream); Key key = readKey(bufferedInputStream);
return key; return key;
} }
@ -197,7 +212,7 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
private Certificate _insert(InputStream data, CertificateMerger merge) private Certificate _insert(InputStream data, CertificateMerger merge)
throws IOException, BadDataException { throws IOException, BadDataException {
Certificate newCertificate = certificateReaderBackend.readCertificate(data); Certificate newCertificate = readCertificate(data);
Certificate existingCertificate; Certificate existingCertificate;
File certFile; File certFile;
try { try {
@ -218,7 +233,7 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
private Key _insertTrustRoot(InputStream data, KeyMerger merge) private Key _insertTrustRoot(InputStream data, KeyMerger merge)
throws IOException, BadDataException { throws IOException, BadDataException {
Key newKey = keyReaderBackend.readKey(data); Key newKey = readKey(data);
Key existingKey; Key existingKey;
File keyFile; File keyFile;
try { try {
@ -297,7 +312,7 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
private Certificate _insertSpecial(String specialName, InputStream data, CertificateMerger merge) private Certificate _insertSpecial(String specialName, InputStream data, CertificateMerger merge)
throws IOException, BadNameException, BadDataException { throws IOException, BadNameException, BadDataException {
Certificate newCertificate = certificateReaderBackend.readCertificate(data); Certificate newCertificate = readCertificate(data);
Certificate existingCertificate = getBySpecialName(specialName); Certificate existingCertificate = getBySpecialName(specialName);
File certFile = resolver.getCertFileBySpecialName(specialName); File certFile = resolver.getCertFileBySpecialName(specialName);
@ -338,7 +353,7 @@ public class SharedPGPCertificateDirectoryImpl implements SharedPGPCertificateDi
@Override @Override
Certificate get() throws BadDataException { Certificate get() throws BadDataException {
try { try {
Certificate certificate = certificateReaderBackend.readCertificate(new FileInputStream(certFile)); Certificate certificate = readCertificate(new FileInputStream(certFile));
if (!(subdirectory.getName() + certFile.getName()).equals(certificate.getFingerprint())) { if (!(subdirectory.getName() + certFile.getName()).equals(certificate.getFingerprint())) {
throw new BadDataException(); throw new BadDataException();
} }

View file

@ -11,14 +11,7 @@ import java.util.Set;
/** /**
* OpenPGP certificate (public key). * OpenPGP certificate (public key).
*/ */
public abstract class Certificate { public abstract class Certificate implements KeyMaterial {
/**
* Return the fingerprint of the certificate as 40 lowercase hex characters.
* TODO: Allow OpenPGP V5 fingerprints
*
* @return fingerprint
*/
public abstract String getFingerprint();
/** /**
* Return an {@link InputStream} of the binary representation of the certificate. * Return an {@link InputStream} of the binary representation of the certificate.

View file

@ -1,29 +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 java.io.IOException;
import java.io.InputStream;
/**
* Interface definition for a class that can read {@link Certificate Certificates} from binary
* {@link InputStream InputStreams}.
*/
public interface CertificateReaderBackend {
/**
* Read a {@link Certificate} from the given {@link InputStream}.
*
* @param inputStream input stream containing the binary representation of the certificate.
* @return certificate object
*
* @throws IOException in case of an IO error
* @throws BadDataException in case that the input stream does not contain OpenPGP certificate data
*/
Certificate readCertificate(InputStream inputStream) throws IOException, BadDataException;
}

View file

@ -10,7 +10,7 @@ import java.io.InputStream;
/** /**
* OpenPGP key (secret key). * OpenPGP key (secret key).
*/ */
public abstract class Key { public abstract class Key implements KeyMaterial {
/** /**
* Return the certificate part of this OpenPGP key. * Return the certificate part of this OpenPGP key.

View file

@ -0,0 +1,17 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.certificate_store;
public interface KeyMaterial {
/**
* Return the fingerprint of the certificate as 40 lowercase hex characters.
* TODO: Allow OpenPGP V5 fingerprints
*
* @return fingerprint
*/
String getFingerprint();
}

View file

@ -12,13 +12,13 @@ import java.io.InputStream;
public interface KeyReaderBackend { public interface KeyReaderBackend {
/** /**
* Read a {@link Key} from the given {@link InputStream}. * 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 data input stream containing the binary representation of the key.
* @return key object * @return key or certificate object
* *
* @throws IOException in case of an IO error * @throws IOException in case of an IO error
* @throws BadDataException in case that the data stream does not contain a valid OpenPGP key * @throws BadDataException in case that the data stream does not contain a valid OpenPGP key/certificate
*/ */
Key readKey(InputStream data) throws IOException, BadDataException; KeyMaterial read(InputStream data) throws IOException, BadDataException;
} }