Add back support for getXIfChanged(Y, tag)

This commit is contained in:
Paul Schaub 2022-08-24 13:04:28 +02:00
parent d050cb5516
commit 27f4598437
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
15 changed files with 423 additions and 101 deletions

View file

@ -33,6 +33,16 @@ public class PGPCertificateDirectory
return backend.readByFingerprint(fingerprint);
}
@Override
public Certificate getByFingerprintIfChanged(String fingerprint, long tag)
throws IOException, BadNameException, BadDataException {
if (tag != backend.getTagForFingerprint(fingerprint)) {
return getByFingerprint(fingerprint);
}
return null;
}
@Override
public Certificate getBySpecialName(String specialName)
throws BadNameException, BadDataException, IOException {
@ -43,6 +53,15 @@ public class PGPCertificateDirectory
return null;
}
@Override
public Certificate getBySpecialNameIfChanged(String specialName, long tag)
throws IOException, BadNameException, BadDataException {
if (tag != backend.getTagForSpecialName(specialName)) {
return getBySpecialName(specialName);
}
return null;
}
@Override
public Certificate getTrustRootCertificate()
throws IOException, BadDataException {
@ -53,6 +72,15 @@ public class PGPCertificateDirectory
}
}
@Override
public Certificate getTrustRootCertificateIfChanged(long tag) throws IOException, BadDataException {
try {
return getBySpecialNameIfChanged(SpecialNames.TRUST_ROOT, tag);
} catch (BadNameException e) {
throw new AssertionError("'" + SpecialNames.TRUST_ROOT + "' is an implementation MUST");
}
}
@Override
public Iterator<Certificate> items() {
return backend.readItems();
@ -179,6 +207,10 @@ public class PGPCertificateDirectory
Certificate doInsertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge)
throws IOException, BadDataException, BadNameException;
Long getTagForFingerprint(String fingerprint) throws BadNameException, IOException;
Long getTagForSpecialName(String specialName) throws BadNameException, IOException;
}
public interface LockingMechanism {

View file

@ -37,6 +37,16 @@ public class PGPCertificateStoreAdapter implements PGPCertificateStore {
}
}
@Override
public Certificate getCertificateIfChanged(String identifier, Long tag)
throws IOException, BadNameException, BadDataException {
if (SpecialNames.lookupSpecialName(identifier) != null) {
return directory.getBySpecialNameIfChanged(identifier, tag);
} else {
return directory.getByFingerprintIfChanged(identifier.toLowerCase(), tag);
}
}
@Override
public Iterator<Certificate> getCertificatesBySubkeyId(long subkeyId)
throws IOException, BadDataException {

View file

@ -16,12 +16,21 @@ public interface ReadOnlyPGPCertificateDirectory {
Certificate getTrustRootCertificate()
throws IOException, BadDataException;
Certificate getTrustRootCertificateIfChanged(long tag)
throws IOException, BadDataException;
Certificate getByFingerprint(String fingerprint)
throws IOException, BadNameException, BadDataException;
Certificate getByFingerprintIfChanged(String fingerprint, long tag)
throws IOException, BadNameException, BadDataException;
Certificate getBySpecialName(String specialName)
throws IOException, BadNameException, BadDataException;
Certificate getBySpecialNameIfChanged(String specialName, long tag)
throws IOException, BadNameException, BadDataException;
Iterator<Certificate> items();
Iterator<String> fingerprints();

View file

@ -7,6 +7,7 @@ package pgp.cert_d.backend;
import pgp.cert_d.PGPCertificateDirectory;
import pgp.cert_d.SpecialNames;
import pgp.certificate_store.certificate.Certificate;
import pgp.certificate_store.certificate.Key;
import pgp.certificate_store.certificate.KeyMaterial;
import pgp.certificate_store.certificate.KeyMaterialMerger;
import pgp.certificate_store.certificate.KeyMaterialReaderBackend;
@ -25,6 +26,9 @@ import java.io.InputStream;
import java.io.RandomAccessFile;
import java.nio.channels.FileLock;
import java.nio.channels.OverlappingFileLockException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
@ -160,10 +164,12 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
return null;
}
long tag = getTagForFingerprint(fingerprint);
FileInputStream fileIn = new FileInputStream(certFile);
BufferedInputStream bufferedIn = new BufferedInputStream(fileIn);
Certificate certificate = reader.read(bufferedIn).asCertificate();
Certificate certificate = reader.read(bufferedIn, tag).asCertificate();
if (!certificate.getFingerprint().equals(fingerprint)) {
// TODO: Figure out more suitable exception
throw new BadDataException();
@ -179,9 +185,11 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
return null;
}
long tag = getTagForSpecialName(specialName);
FileInputStream fileIn = new FileInputStream(certFile);
BufferedInputStream bufferedIn = new BufferedInputStream(fileIn);
KeyMaterial keyMaterial = reader.read(bufferedIn);
KeyMaterial keyMaterial = reader.read(bufferedIn, tag);
return keyMaterial;
}
@ -214,7 +222,8 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
@Override
Certificate get() throws BadDataException {
try {
Certificate certificate = reader.read(new FileInputStream(certFile)).asCertificate();
long tag = getTag(certFile);
Certificate certificate = reader.read(new FileInputStream(certFile), tag).asCertificate();
if (!(subdirectory.getName() + certFile.getName()).equals(certificate.getFingerprint())) {
throw new BadDataException();
}
@ -246,7 +255,7 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
@Override
public KeyMaterial doInsertTrustRoot(InputStream data, KeyMaterialMerger merge) throws BadDataException, IOException {
KeyMaterial newCertificate = reader.read(data);
KeyMaterial newCertificate = reader.read(data, null);
KeyMaterial existingCertificate;
File certFile;
try {
@ -256,18 +265,22 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
throw new BadDataException();
}
if (existingCertificate != null && !newCertificate.getTag().equals(existingCertificate.getTag())) {
if (existingCertificate != null) {
newCertificate = merge.merge(newCertificate, existingCertificate);
}
writeToFile(newCertificate.getInputStream(), certFile);
long tag = writeToFile(newCertificate.getInputStream(), certFile);
if (newCertificate instanceof Key) {
newCertificate = new Key((Key) newCertificate, tag);
} else {
newCertificate = new Certificate((Certificate) newCertificate, tag);
}
return newCertificate;
}
@Override
public Certificate doInsert(InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException {
KeyMaterial newCertificate = reader.read(data);
KeyMaterial newCertificate = reader.read(data, null);
Certificate existingCertificate;
File certFile;
try {
@ -277,18 +290,17 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
throw new BadDataException();
}
if (existingCertificate != null && !newCertificate.getTag().equals(existingCertificate.getTag())) {
if (existingCertificate != null) {
newCertificate = merge.merge(newCertificate, existingCertificate);
}
writeToFile(newCertificate.getInputStream(), certFile);
return newCertificate.asCertificate();
long tag = writeToFile(newCertificate.getInputStream(), certFile);
return new Certificate(newCertificate.asCertificate(), tag);
}
@Override
public Certificate doInsertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge) throws IOException, BadDataException, BadNameException {
KeyMaterial newCertificate = reader.read(data);
KeyMaterial newCertificate = reader.read(data, null);
KeyMaterial existingCertificate;
File certFile;
try {
@ -298,16 +310,41 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
throw new BadDataException();
}
if (existingCertificate != null && !newCertificate.getTag().equals(existingCertificate.getTag())) {
if (existingCertificate != null) {
newCertificate = merge.merge(newCertificate, existingCertificate);
}
writeToFile(newCertificate.getInputStream(), certFile);
return newCertificate.asCertificate();
long tag = writeToFile(newCertificate.getInputStream(), certFile);
return new Certificate(newCertificate.asCertificate(), tag);
}
private void writeToFile(InputStream inputStream, File certFile)
@Override
public Long getTagForFingerprint(String fingerprint) throws BadNameException, IOException {
File file = resolver.getCertFileByFingerprint(fingerprint);
return getTag(file);
}
@Override
public Long getTagForSpecialName(String specialName) throws BadNameException, IOException {
File file = resolver.getCertFileBySpecialName(specialName);
return getTag(file);
}
private Long getTag(File file) throws IOException {
if (!file.exists()) {
throw new IllegalArgumentException("File MUST exist.");
}
Path path = file.toPath();
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);
// On UNIX file systems, for example, fileKey() will return the device ID and inode
int fileId = attrs.fileKey().hashCode();
long lastMod = attrs.lastModifiedTime().toMillis();
return lastMod + (11L * fileId);
}
private long writeToFile(InputStream inputStream, File certFile)
throws IOException {
certFile.getParentFile().mkdirs();
if (!certFile.exists() && !certFile.createNewFile()) {
@ -324,6 +361,7 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
inputStream.close();
fileOut.close();
return getTag(certFile);
}
public static class FilenameResolver {

View file

@ -7,6 +7,7 @@ package pgp.cert_d.backend;
import pgp.cert_d.PGPCertificateDirectory;
import pgp.cert_d.SpecialNames;
import pgp.certificate_store.certificate.Certificate;
import pgp.certificate_store.certificate.Key;
import pgp.certificate_store.certificate.KeyMaterial;
import pgp.certificate_store.certificate.KeyMaterialMerger;
import pgp.certificate_store.certificate.KeyMaterialReaderBackend;
@ -91,7 +92,7 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect
@Override
public KeyMaterial doInsertTrustRoot(InputStream data, KeyMaterialMerger merge)
throws BadDataException, IOException {
KeyMaterial update = reader.read(data);
KeyMaterial update = reader.read(data, null);
KeyMaterial existing = null;
try {
existing = readBySpecialName(SpecialNames.TRUST_ROOT);
@ -100,6 +101,11 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect
throw new RuntimeException(e);
}
KeyMaterial merged = merge.merge(update, existing);
if (merged instanceof Key) {
merged = new Key((Key) merged, System.currentTimeMillis());
} else {
merged = new Certificate((Certificate) merged, System.currentTimeMillis());
}
keyMaterialSpecialNameMap.put(SpecialNames.TRUST_ROOT, merged);
return merged;
}
@ -108,9 +114,10 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect
@Override
public Certificate doInsert(InputStream data, KeyMaterialMerger merge)
throws IOException, BadDataException {
KeyMaterial update = reader.read(data);
KeyMaterial update = reader.read(data, null);
Certificate existing = readByFingerprint(update.getFingerprint());
Certificate merged = merge.merge(update, existing).asCertificate();
merged = new Certificate(merged, System.currentTimeMillis());
certificateFingerprintMap.put(update.getFingerprint(), merged);
return merged;
}
@ -118,10 +125,36 @@ public class InMemoryCertificateDirectoryBackend implements PGPCertificateDirect
@Override
public Certificate doInsertWithSpecialName(String specialName, InputStream data, KeyMaterialMerger merge)
throws IOException, BadDataException, BadNameException {
KeyMaterial keyMaterial = reader.read(data);
KeyMaterial keyMaterial = reader.read(data, null);
KeyMaterial existing = readBySpecialName(specialName);
KeyMaterial merged = merge.merge(keyMaterial, existing);
if (merged instanceof Key) {
merged = new Key((Key) merged, System.currentTimeMillis());
} else {
merged = new Certificate((Certificate) merged, System.currentTimeMillis());
}
keyMaterialSpecialNameMap.put(specialName, merged);
return merged.asCertificate();
}
@Override
public Long getTagForFingerprint(String fingerprint) throws BadNameException, IOException {
Certificate certificate = certificateFingerprintMap.get(fingerprint);
if (certificate == null) {
return null;
}
return certificate.getTag();
}
@Override
public Long getTagForSpecialName(String specialName) throws BadNameException, IOException {
if (SpecialNames.lookupSpecialName(specialName) == null) {
throw new BadNameException("Invalid special name " + specialName);
}
KeyMaterial tagged = keyMaterialSpecialNameMap.get(specialName);
if (tagged == null) {
return null;
}
return tagged.getTag();
}
}