Throw NoSuchElementException for non-existent certificates/keys

Fixes #2
This commit is contained in:
Paul Schaub 2022-08-27 12:16:53 +02:00
parent eab31b8c12
commit a248e0d717
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
4 changed files with 75 additions and 10 deletions

View file

@ -15,6 +15,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Set;
import java.util.regex.Pattern;
@ -46,13 +48,17 @@ public class PGPCertificateDirectory
if (!openPgpV4FingerprintPattern.matcher(fingerprint).matches()) {
throw new BadNameException();
}
return backend.readByFingerprint(fingerprint);
Certificate certificate = backend.readByFingerprint(fingerprint);
if (certificate == null) {
throw new NoSuchElementException();
}
return certificate;
}
@Override
public Certificate getByFingerprintIfChanged(String fingerprint, long tag)
throws IOException, BadNameException, BadDataException {
if (tag != backend.getTagForFingerprint(fingerprint)) {
if (!Objects.equals(tag, backend.getTagForFingerprint(fingerprint))) {
return getByFingerprint(fingerprint);
}
return null;
@ -66,13 +72,13 @@ public class PGPCertificateDirectory
if (keyMaterial != null) {
return keyMaterial.asCertificate();
}
return null;
throw new NoSuchElementException();
}
@Override
public Certificate getBySpecialNameIfChanged(String specialName, long tag)
throws IOException, BadNameException, BadDataException {
if (tag != backend.getTagForSpecialName(specialName)) {
if (!Objects.equals(tag, backend.getTagForSpecialName(specialName))) {
return getBySpecialName(specialName);
}
return null;
@ -121,7 +127,11 @@ public class PGPCertificateDirectory
@Override
public KeyMaterial getTrustRoot() throws IOException, BadDataException {
try {
return backend.readBySpecialName(SpecialNames.TRUST_ROOT);
KeyMaterial keyMaterial = backend.readBySpecialName(SpecialNames.TRUST_ROOT);
if (keyMaterial == null) {
throw new NoSuchElementException();
}
return keyMaterial;
} catch (BadNameException e) {
throw new AssertionError("'" + SpecialNames.TRUST_ROOT + "' is implementation MUST");
}

View file

@ -33,6 +33,7 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.regex.Pattern;
/**
@ -348,7 +349,7 @@ public class FileBasedCertificateDirectoryBackend implements PGPCertificateDirec
private Long getTag(File file) throws IOException {
if (!file.exists()) {
throw new IllegalArgumentException("File MUST exist.");
throw new NoSuchElementException();
}
Path path = file.toPath();
BasicFileAttributes attrs = Files.readAttributes(path, BasicFileAttributes.class);

View file

@ -31,6 +31,7 @@ import java.nio.file.Files;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.stream.Stream;
@ -68,6 +69,55 @@ public class PGPCertificateDirectoryTest {
Arguments.of(Named.of("FileBasedCertificateDirectory", fileBased)));
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void getNonExistentCertByFingerprintThrowsNoSuchElementException(PGPCertificateDirectory directory) {
assertThrows(NoSuchElementException.class, () ->
directory.getByFingerprint("0000000000000000000000000000000000000000"));
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void getNonExistentCertByFingerprintIfChangedThrowsNoSuchElementException(PGPCertificateDirectory directory) {
assertThrows(NoSuchElementException.class, () ->
directory.getByFingerprintIfChanged("0000000000000000000000000000000000000000", 12));
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void getNonExistentCertBySpecialNameThrowsNoSuchElementException(PGPCertificateDirectory directory) {
assertThrows(NoSuchElementException.class, () ->
directory.getBySpecialName(SpecialNames.TRUST_ROOT));
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void getNonExistentCertBySpecialNameIfChangedThrowsNoSuchElementException(PGPCertificateDirectory directory) {
assertThrows(NoSuchElementException.class, () ->
directory.getBySpecialNameIfChanged(SpecialNames.TRUST_ROOT, 12));
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void getNonExistentTrustRootThrowsNoSuchElementException(PGPCertificateDirectory directory) {
assertThrows(NoSuchElementException.class, () ->
directory.getTrustRoot());
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void getNonExistentTrustRootIfChangedThrowsNoSuchElementException(PGPCertificateDirectory directory) {
assertThrows(NoSuchElementException.class, () ->
directory.getTrustRootCertificateIfChanged(12));
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void getNonExistentTrustRootCertificateThrowsNoSuchElementException(PGPCertificateDirectory directory) {
assertThrows(NoSuchElementException.class, () ->
directory.getTrustRootCertificate());
}
@ParameterizedTest
@MethodSource("provideTestSubjects")
public void lockDirectoryAndTryInsertWillFail(PGPCertificateDirectory directory)
@ -130,7 +180,7 @@ public class PGPCertificateDirectoryTest {
@MethodSource("provideTestSubjects")
public void testInsertAndGetSingleCert(PGPCertificateDirectory directory)
throws BadDataException, IOException, InterruptedException, BadNameException {
assertNull(directory.getByFingerprint(CEDRIC_FP), "Empty directory MUST NOT contain certificate");
assertThrows(NoSuchElementException.class, () -> directory.getByFingerprint(CEDRIC_FP), "Empty directory MUST NOT contain certificate");
Certificate certificate = directory.insert(TestKeys.getCedricCert(), merger);
assertEquals(CEDRIC_FP, certificate.getFingerprint(), "Fingerprint of inserted cert MUST match");
@ -148,7 +198,7 @@ public class PGPCertificateDirectoryTest {
@MethodSource("provideTestSubjects")
public void testInsertAndGetTrustRootAndCert(PGPCertificateDirectory directory)
throws BadDataException, IOException, InterruptedException {
assertNull(directory.getTrustRoot());
assertThrows(NoSuchElementException.class, () -> directory.getTrustRoot());
KeyMaterial trustRootMaterial = directory.insertTrustRoot(
TestKeys.getHarryKey(), merger);
@ -188,6 +238,7 @@ public class PGPCertificateDirectoryTest {
assertNotNull(directory.getTrustRootCertificateIfChanged(tag + 1));
Long oldTag = tag;
Thread.sleep(10);
// "update" key
trustRootMaterial = directory.insertTrustRoot(
TestKeys.getHarryKey(), merger);
@ -241,10 +292,12 @@ public class PGPCertificateDirectoryTest {
Long oldTag = tag;
Thread.sleep(10);
// Change the file on disk directly, this invalidates the tag due to changed modification date
File certFile = resolver.getCertFileByFingerprint(certificate.getFingerprint());
FileOutputStream fileOut = new FileOutputStream(certFile);
Streams.pipeAll(certificate.getInputStream(), fileOut);
fileOut.write("\n".getBytes());
fileOut.close();
// Old invalidated tag indicates a change, so the modified certificate is returned

View file

@ -17,6 +17,7 @@ import pgp.certificate_store.exception.BadNameException;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@ -52,7 +53,7 @@ public class PGPCertificateStoreAdapterTest {
@Test
public void testInsertGetCertificate()
throws BadDataException, IOException, InterruptedException, BadNameException {
assertNull(adapter.getCertificate(TestKeys.CEDRIC_FP));
assertThrows(NoSuchElementException.class, () -> adapter.getCertificate(TestKeys.CEDRIC_FP));
assertFalse(adapter.getCertificates().hasNext());
Certificate certificate = adapter.insertCertificate(TestKeys.getCedricCert(), merger);
@ -70,7 +71,7 @@ public class PGPCertificateStoreAdapterTest {
@Test
public void testInsertGetTrustRoot()
throws BadDataException, BadNameException, IOException, InterruptedException {
assertNull(adapter.getCertificate(SpecialNames.TRUST_ROOT));
assertThrows(NoSuchElementException.class, () -> adapter.getCertificate(SpecialNames.TRUST_ROOT));
Certificate certificate = adapter.insertCertificateBySpecialName(
SpecialNames.TRUST_ROOT, TestKeys.getHarryKey(), merger);