Implement storing of trust-root key

This commit is contained in:
Paul Schaub 2022-07-04 20:12:42 +02:00
parent fca9a8ef91
commit ee1fd669ed
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
13 changed files with 357 additions and 104 deletions

View file

@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.certificate_store;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.bouncycastle.util.encoders.Base64;
import org.pgpainless.PGPainless;
import pgp.certificate_store.Certificate;
import pgp.certificate_store.Key;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class KeyFactory {
public static Key keyFromSecretKeyRing(PGPSecretKeyRing secretKeyRing) {
return new Key() {
@Override
public Certificate getCertificate() {
PGPPublicKeyRing publicKeys = PGPainless.extractCertificate(secretKeyRing);
return CertificateFactory.certificateFromPublicKeyRing(publicKeys);
}
@Override
public InputStream getInputStream() throws IOException {
return new ByteArrayInputStream(secretKeyRing.getEncoded());
}
@Override
public String getTag() throws IOException {
MessageDigest digest;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new AssertionError("No MessageDigest for SHA-256 instantiated, although BC is on the classpath: " + e.getMessage());
}
digest.update(secretKeyRing.getEncoded());
return Base64.toBase64String(digest.digest());
}
};
}
}

View file

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package org.pgpainless.certificate_store;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.pgpainless.PGPainless;
import pgp.certificate_store.Key;
import pgp.certificate_store.KeyReaderBackend;
import pgp.certificate_store.exception.BadDataException;
import java.io.IOException;
import java.io.InputStream;
public class KeyReader implements KeyReaderBackend {
@Override
public Key readKey(InputStream data) throws IOException, BadDataException {
final PGPSecretKeyRing key = PGPainless.readKeyRing().secretKeyRing(data);
return KeyFactory.keyFromSecretKeyRing(key);
}
}

View file

@ -15,8 +15,10 @@ import pgp.cert_d.SharedPGPCertificateDirectory;
import pgp.cert_d.SpecialNames;
import pgp.certificate_store.Certificate;
import pgp.certificate_store.CertificateDirectory;
import pgp.certificate_store.CertificateMerger;
import pgp.certificate_store.CertificateStore;
import pgp.certificate_store.MergeCallback;
import pgp.certificate_store.Key;
import pgp.certificate_store.KeyMerger;
import pgp.certificate_store.SubkeyLookup;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
@ -66,7 +68,7 @@ public class SharedPGPCertificateDirectoryAdapter
}
@Override
public Certificate insertCertificate(InputStream data, MergeCallback merge)
public Certificate insertCertificate(InputStream data, CertificateMerger merge)
throws IOException, InterruptedException, BadDataException {
Certificate certificate = directory.insert(data, merge);
storeIdentifierForSubkeys(certificate);
@ -74,7 +76,7 @@ public class SharedPGPCertificateDirectoryAdapter
}
@Override
public Certificate tryInsertCertificate(InputStream data, MergeCallback merge)
public Certificate tryInsertCertificate(InputStream data, CertificateMerger merge)
throws IOException, BadDataException {
Certificate certificate = directory.tryInsert(data, merge);
storeIdentifierForSubkeys(certificate);
@ -82,13 +84,13 @@ public class SharedPGPCertificateDirectoryAdapter
}
@Override
public Certificate insertCertificateBySpecialName(String specialName, InputStream data, MergeCallback merge)
public Certificate insertCertificateBySpecialName(String specialName, InputStream data, CertificateMerger merge)
throws IOException, InterruptedException, BadDataException, BadNameException {
return directory.insertWithSpecialName(specialName, data, merge);
}
@Override
public Certificate tryInsertCertificateBySpecialName(String specialName, InputStream data, MergeCallback merge)
public Certificate tryInsertCertificateBySpecialName(String specialName, InputStream data, CertificateMerger merge)
throws IOException, BadDataException, BadNameException {
return directory.tryInsertWithSpecialName(specialName, data, merge);
}
@ -120,4 +122,24 @@ public class SharedPGPCertificateDirectoryAdapter
public void storeCertificateSubkeyIds(String certificate, List<Long> subkeyIds) throws IOException {
subkeyLookup.storeCertificateSubkeyIds(certificate, subkeyIds);
}
@Override
public Key getTrustRoot() throws IOException, BadDataException {
return directory.getTrustRoot();
}
@Override
public Key getTrustRootIfChanged(String tag) throws IOException, BadDataException {
return directory.getTrustRootIfChanged(tag);
}
@Override
public Key insertTrustRoot(InputStream data, KeyMerger keyMerger) throws IOException, InterruptedException, BadDataException {
return directory.insertTrustRoot(data, keyMerger);
}
@Override
public Key tryInsertTrustRoot(InputStream data, KeyMerger keyMerger) throws IOException, BadDataException {
return directory.tryInsertTrustRoot(data, keyMerger);
}
}

View file

@ -27,6 +27,7 @@ import org.bouncycastle.util.io.Streams;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.pgpainless.certificate_store.CertificateReader;
import org.pgpainless.certificate_store.KeyReader;
import org.pgpainless.certificate_store.SharedPGPCertificateDirectoryAdapter;
import pgp.cert_d.InMemorySubkeyLookup;
import pgp.cert_d.SharedPGPCertificateDirectoryImpl;
@ -50,7 +51,7 @@ public class SharedPGPCertificateDirectoryAdapterTest {
@BeforeEach
public void setupInstance() throws IOException, NotAStoreException {
adapter = new SharedPGPCertificateDirectoryAdapter(
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader()),
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader()),
new InMemorySubkeyLookup());
store = adapter;
}

View file

@ -33,6 +33,7 @@ import org.junit.jupiter.params.provider.MethodSource;
import org.pgpainless.PGPainless;
import org.pgpainless.algorithm.KeyFlag;
import org.pgpainless.certificate_store.CertificateReader;
import org.pgpainless.certificate_store.KeyReader;
import org.pgpainless.key.OpenPgpFingerprint;
import org.pgpainless.key.generation.KeySpec;
import org.pgpainless.key.generation.type.KeyType;
@ -41,15 +42,15 @@ import pgp.cert_d.CachingSharedPGPCertificateDirectoryWrapper;
import pgp.cert_d.FileLockingMechanism;
import pgp.cert_d.SharedPGPCertificateDirectory;
import pgp.cert_d.SharedPGPCertificateDirectoryImpl;
import pgp.certificate_store.CertificateMerger;
import pgp.certificate_store.exception.BadDataException;
import pgp.certificate_store.exception.BadNameException;
import pgp.certificate_store.exception.NotAStoreException;
import pgp.certificate_store.Certificate;
import pgp.certificate_store.MergeCallback;
public class SharedPGPCertificateDirectoryTest {
private static MergeCallback dummyMerge = new MergeCallback() {
private static CertificateMerger dummyMerge = new CertificateMerger() {
@Override
public Certificate merge(Certificate data, Certificate existing) {
return data;
@ -58,9 +59,9 @@ public class SharedPGPCertificateDirectoryTest {
private static Stream<SharedPGPCertificateDirectory> provideTestSubjects() throws IOException, NotAStoreException {
return Stream.of(
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader()),
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader()),
new CachingSharedPGPCertificateDirectoryWrapper(
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader()))
new SharedPGPCertificateDirectoryImpl(tempDir(), new CertificateReader(), new KeyReader()))
);
}