Add wkd-test-suite module

This commit is contained in:
Paul Schaub 2022-03-02 17:01:30 +01:00
parent 79af7ccab6
commit 049c14b779
Signed by: vanitasvitae
GPG key ID: 62BEE9264BF17311
12 changed files with 677 additions and 2 deletions

View file

@ -73,6 +73,7 @@ allprojects {
junitVersion = '5.8.2'
slf4jVersion = '1.7.32'
logbackVersion = '1.2.10'
pgpainlessVersion = '1.1.1'
rootConfigDir = new File(rootDir, 'config')
gitCommit = getGitCommit()
isContinuousIntegrationEnvironment = Boolean.parseBoolean(System.getenv('CI'))

View file

@ -5,5 +5,6 @@
rootProject.name = 'WKD-Java'
include 'wkd-java',
'wkd-java-cli'
'wkd-java-cli',
'wkd-test-suite'

View file

@ -20,7 +20,7 @@ dependencies {
testImplementation 'com.ginsberg:junit5-system-exit:1.1.2'
testImplementation 'org.mockito:mockito-core:4.3.1'
implementation("org.pgpainless:pgpainless-core:1.1.0")
implementation("org.pgpainless:pgpainless-core:$pgpainlessVersion")
implementation project(':wkd-java')
implementation "info.picocli:picocli:4.6.3"

78
wkd-test-suite/README.md Normal file
View file

@ -0,0 +1,78 @@
<!--
SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
SPDX-License-Identifier: Apache-2.0
-->
# WKD Test Suite Generator
This module contains a CLI application that can be used to generate WKD test vectors.
```shell
$ java -jar wkd-test-suite.jar help
Usage: wkd-test-suite [-hV] [--json-summary[=<jsonOutputFiles>]]...
[--xml-summary[=<xmlOutputFiles>]]... -d=<domain>
[-m={direct|advanced}] -o=<rootDir>
-d, --domain=<domain> Root domain
-h, --help Show this help message and exit.
--json-summary[=<jsonOutputFiles>]
Write JSON summary to file
-m, --method={direct|advanced}
Method for key discovery
-o, --output-dir=<rootDir>
Output directory
-V, --version Print version information and exit.
--xml-summary[=<xmlOutputFiles>]
Write XML summary to file
```
Example output summary.json:
```json
{
"version" : "0.1",
"testCases" : [ {
"expectSuccess" : true,
"testTitle" : "Base Case",
"testDescription" : "Certificate has a single, valid user-id 'WKD-Test Base Case <base-case@pgpainless.github.io>'",
"lookupMailAddress" : "base-case@pgpainless.github.io",
"certificatePath" : ".well-known/openpgpkey/hu/6q1ubufxsqh8fjuewbachy5ocz9seanp",
"lookupUri" : "https://pgpainless.github.io/.well-known/openpgpkey/hu/6q1ubufxsqh8fjuewbachy5ocz9seanp?l=base-case"
}, {
"expectSuccess" : false,
"testTitle" : "Wrong User-ID",
"testDescription" : "Certificate has a single, valid user-id 'WKD-Test Different User-ID <different-userid@pgpainless.github.io>', but is deposited for mail address 'wrong-userid@pgpainless.github.io'.",
"lookupMailAddress" : "wrong-userid@pgpainless.github.io",
"certificatePath" : ".well-known/openpgpkey/hu/87rxmyhh4paokf1apw6qiej8hk6nwuxy",
"lookupUri" : "https://pgpainless.github.io/.well-known/openpgpkey/hu/87rxmyhh4paokf1apw6qiej8hk6nwuxy?l=wrong-userid"
}, {
"expectSuccess" : false,
"testTitle" : "No User-ID",
"testDescription" : "Certificate has no user-id, but is deposited for mail address 'absent-userid@pgpainless.github.io'.",
"lookupMailAddress" : "absent-userid@pgpainless.github.io",
"certificatePath" : ".well-known/openpgpkey/hu/caky1x1mawkc6gg4kge1icod96wqaeax",
"lookupUri" : "https://pgpainless.github.io/.well-known/openpgpkey/hu/caky1x1mawkc6gg4kge1icod96wqaeax?l=absent-userid"
}, {
"expectSuccess" : true,
"testTitle" : "Multi-User-ID - Primary User-ID Lookup",
"testDescription" : "Certificate has multiple, valid user-ids. Is looked up via primary user-id 'WKD-Test Primary User-ID <primary-uid@pgpainless.github.io>' using mail address 'primary-uid@pgpainless.github.io'.",
"lookupMailAddress" : "primary-uid@pgpainless.github.io",
"certificatePath" : ".well-known/openpgpkey/hu/iz5jxf9oi1mbc1p45s3nxcuxn38qazkw",
"lookupUri" : "https://pgpainless.github.io/.well-known/openpgpkey/hu/iz5jxf9oi1mbc1p45s3nxcuxn38qazkw?l=primary-uid"
}, {
"expectSuccess" : true,
"testTitle" : "Multi-User-ID - Secondary User-ID Lookup",
"testDescription" : "Certificate has multiple, valid user-ids. Is looked up via secondary user-id 'WKD-Test Secondary User-ID <secondary-uid@pgpainless.github.io>' using mail address 'secondary-uid@pgpainless.github.io'.",
"lookupMailAddress" : "secondary-uid@pgpainless.github.io",
"certificatePath" : ".well-known/openpgpkey/hu/34i6oasjuzeunw5uwam7yqbtit1rtmjp",
"lookupUri" : "https://pgpainless.github.io/.well-known/openpgpkey/hu/34i6oasjuzeunw5uwam7yqbtit1rtmjp?l=secondary-uid"
}, {
"expectSuccess" : false,
"testTitle" : "Secret Key Material",
"testDescription" : "Certificate file contains secret key material.",
"lookupMailAddress" : "test-secret-key@pgpainless.github.io",
"certificatePath" : ".well-known/openpgpkey/hu/4uoqyth19ibwszqjaokiafhxc5sh6usu",
"lookupUri" : "https://pgpainless.github.io/.well-known/openpgpkey/hu/4uoqyth19ibwszqjaokiafhxc5sh6usu?l=test-secret-key"
} ]
}
```

View file

@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
plugins {
id 'application'
}
group 'org.pgpainless'
repositories {
mavenCentral()
}
dependencies {
// Testing
testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion"
testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:$junitVersion"
// Logging
implementation "org.slf4j:slf4j-api:$slf4jVersion"
testImplementation "ch.qos.logback:logback-classic:$logbackVersion"
// WKD and OpenPGP
implementation project (":wkd-java")
implementation "org.pgpainless:pgpainless-core:$pgpainlessVersion"
// CLI
implementation "info.picocli:picocli:4.6.3"
// Object Mapping
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.13.1'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.1'
}
mainClassName = 'pgp.wkd.test_suite.Main'
jar {
duplicatesStrategy(DuplicatesStrategy.EXCLUDE)
manifest {
attributes 'Main-Class': "$mainClassName"
}
from {
configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) }
} {
exclude "META-INF/*.SF"
exclude "META-INF/*.DSA"
exclude "META-INF/*.RSA"
}
}
test {
useJUnitPlatform()
}

View file

@ -0,0 +1,122 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.test_suite;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
import com.fasterxml.jackson.databind.json.JsonMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import picocli.CommandLine;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
@CommandLine.Command(name = "wkd-test-suite", mixinStandardHelpOptions = true, version = "0.1")
public class Main implements Runnable {
private static final Pattern PATTERN_DOMAIN = Pattern.compile("^[a-zA-Z0-9.-]+$");
@CommandLine.Option(names = {"--output-dir", "-o"},
description = "Output directory",
required = true)
private File rootDir;
@CommandLine.Option(names = "--xml-summary",
description = "Write XML summary to file",
arity = "0..1")
private List<File> xmlOutputFiles = new ArrayList<>();
@CommandLine.Option(names = "--json-summary",
description = "Write JSON summary to file",
arity = "0..1")
private List<File> jsonOutputFiles = new ArrayList<>();
@CommandLine.Option(names = {"--domain", "-d"},
description = "Root domain",
required = true, arity = "1")
private String domain;
@CommandLine.Option(names = {"--method", "-m"},
paramLabel = "{direct|advanced}",
description = "Method for key discovery. If absent, assume direct.")
private TestSuiteGenerator.Method method = TestSuiteGenerator.Method.direct;
@CommandLine.Spec // injected by picocli
CommandLine.Model.CommandSpec spec;
public static void main(String[] args) {
System.exit(new CommandLine(new Main()).execute(args));
}
@Override
public void run() {
validate();
TestSuiteGenerator generator = new TestSuiteGenerator(domain);
try {
TestSuite suite = generator.generateTestSuiteInDirectory(rootDir, method);
writeSummaries(suite);
} catch (Exception e) {
throw new AssertionError(e);
}
}
private void validate() {
if (missing(xmlOutputFiles) && missing(jsonOutputFiles)) {
throw new CommandLine.ParameterException(spec.commandLine(),
"Missing option. At least on of '--xml-summary' or '--json-summary' options must be specified.");
}
if (!PATTERN_DOMAIN.matcher(domain).matches()) {
throw new CommandLine.ParameterException(spec.commandLine(),
"Value of option '--domain' must be a valid domain string.");
}
}
private boolean missing(List<?> list) {
return list == null || list.isEmpty();
}
private void writeSummaries(TestSuite suite) {
ObjectMapper xmlMapper = new XmlMapper();
xmlMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
ObjectMapper jsonMapper = new JsonMapper();
jsonMapper.setVisibility(PropertyAccessor.FIELD, JsonAutoDetect.Visibility.ANY);
ObjectWriter xmlWriter = xmlMapper.writer().withDefaultPrettyPrinter();
for (File destination : xmlOutputFiles) {
writeSummary(suite, destination, xmlWriter);
}
ObjectWriter jsonWriter = jsonMapper.writer().withDefaultPrettyPrinter();
for (File destination : jsonOutputFiles) {
writeSummary(suite, destination, jsonWriter);
}
}
private void writeSummary(TestSuite suite, File destination, ObjectWriter objWriter) {
try {
destination.createNewFile();
} catch (IOException e) {
// Skip?
return;
}
try (FileOutputStream fileOut = new FileOutputStream(destination); OutputStreamWriter osWriter = new OutputStreamWriter(fileOut, Charset.forName("UTF8"))) {
objWriter.writeValue(osWriter, suite);
} catch (IOException e) {
// Skip?
}
}
}

View file

@ -0,0 +1,27 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.test_suite;
import java.net.URI;
import java.nio.file.Path;
public class TestCase {
final boolean expectSuccess;
final String testTitle;
final String testDescription;
final String lookupMailAddress;
final String certificatePath;
final URI lookupUri;
public TestCase(boolean expectSuccess, String testTitle, String description, String lookupMailAddress, Path certificatePath, URI lookupUri) {
this.expectSuccess = expectSuccess;
this.testTitle = testTitle;
this.testDescription = description;
this.lookupMailAddress = lookupMailAddress;
this.certificatePath = certificatePath.toString();
this.lookupUri = lookupUri;
}
}

View file

@ -0,0 +1,18 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.test_suite;
import java.util.List;
public class TestSuite {
final String version;
final List<TestCase> testCases;
public TestSuite(String version, List<TestCase> testCases) {
this.version = version;
this.testCases = testCases;
}
}

View file

@ -0,0 +1,204 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.test_suite;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.bouncycastle.openpgp.PGPPublicKeyRing;
import org.bouncycastle.openpgp.PGPSecretKeyRing;
import org.pgpainless.PGPainless;
import org.pgpainless.key.protection.SecretKeyRingProtector;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
import java.security.InvalidAlgorithmParameterException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
public class TestSuiteGenerator {
public enum Method {
direct,
advanced
}
private final String domain;
public TestSuiteGenerator(String domain) {
this.domain = domain;
}
public TestSuite generateTestSuiteInDirectory(File directory, Method method) throws Exception {
WkdDirectoryStructure structure = directoryStructureForMethod(directory, method);
structure.mkdirs();
List<TestCase> tests = new ArrayList<>();
tests.add(baseCase(structure));
tests.add(wrongUserId(structure));
tests.add(noUserId(structure));
tests.addAll(baseCaseMultiUserIds(structure));
tests.add(secretKeyMaterial(structure));
return new TestSuite("0.1", tests);
}
private WkdDirectoryStructure directoryStructureForMethod(File directory, Method method) {
WkdDirectoryStructure structure;
if (method == Method.direct) {
structure = new WkdDirectoryStructure.DirectMethod(directory, domain);
} else if (method == Method.advanced) {
structure = new WkdDirectoryStructure.AdvancedMethod(directory, domain);
} else {
throw new IllegalArgumentException("Invalid value for parameter 'method'.");
}
return structure;
}
private PGPPublicKeyRing certificate(String userId) throws PGPException, InvalidAlgorithmParameterException, NoSuchAlgorithmException {
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing(userId, null);
PGPPublicKeyRing publicKeys = PGPainless.extractCertificate(secretKeys);
return publicKeys;
}
private TestCase baseCase(WkdDirectoryStructure directoryStructure) throws Exception {
String lookupMail = "base-case@" + domain;
String userId = "WKD-Test Base Case <base-case@" + domain + ">";
String description = "Certificate has a single, valid user-id '" + userId + "'";
PGPPublicKeyRing publicKeys = certificate(userId);
URI lookupUri = directoryStructure.getAddress(lookupMail);
Path path = directoryStructure.getRelativeCertificatePath(lookupMail);
File file = directoryStructure.resolve(path);
if (!file.exists() && !file.createNewFile()) {
throw new IOException("Cannot create file " + file.getAbsolutePath());
}
try (FileOutputStream fileOut = new FileOutputStream(file)) {
publicKeys.encode(fileOut);
}
return new TestCase(true, "Base Case", description, lookupMail, path, lookupUri);
}
private List<TestCase> baseCaseMultiUserIds(WkdDirectoryStructure directoryStructure) throws Exception {
String primaryLookupMail = "primary-uid@" + domain;
String secondaryLookupMail = "secondary-uid@" + domain;
String primaryUserId = "WKD-Test Primary User-ID <" + primaryLookupMail + ">";
String secondaryUserId = "WKD-Test Secondary User-ID <" + secondaryLookupMail + ">";
String primaryDescription = "Certificate has multiple, valid user-ids. Is looked up via primary user-id '" + primaryUserId + "' using mail address '" + primaryLookupMail + "'.";
String secondaryDescription = "Certificate has multiple, valid user-ids. Is looked up via secondary user-id '" + secondaryUserId + "' using mail address '" + secondaryLookupMail + "'.";
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing(primaryUserId, null);
SecretKeyRingProtector protector = SecretKeyRingProtector.unprotectedKeys();
secretKeys = PGPainless.modifyKeyRing(secretKeys)
.addUserId(secondaryUserId, protector)
.done();
PGPPublicKeyRing publicKeys = PGPainless.extractCertificate(secretKeys);
Path primaryPath = directoryStructure.getRelativeCertificatePath(primaryLookupMail);
Path secondaryPath = directoryStructure.getRelativeCertificatePath(secondaryLookupMail);
File primaryFile = directoryStructure.resolve(primaryPath);
File secondaryFile = directoryStructure.resolve(secondaryPath);
if (!primaryFile.exists() && !primaryFile.createNewFile()) {
throw new IOException("Cannot create file " + primaryFile.getAbsolutePath());
}
if (!secondaryFile.exists() && !secondaryFile.createNewFile()) {
throw new IOException("Cannot create file " + secondaryFile.getAbsolutePath());
}
try (FileOutputStream fileOut = new FileOutputStream(primaryFile)) {
publicKeys.encode(fileOut);
}
try (FileOutputStream fileOut = new FileOutputStream(secondaryFile)) {
publicKeys.encode(fileOut);
}
return Arrays.asList(
new TestCase(true, "Multi-User-ID - Primary User-ID Lookup",
primaryDescription, primaryLookupMail, primaryPath, directoryStructure.getAddress(primaryLookupMail)),
new TestCase(true, "Multi-User-ID - Secondary User-ID Lookup",
secondaryDescription, secondaryLookupMail, secondaryPath, directoryStructure.getAddress(secondaryLookupMail))
);
}
private TestCase wrongUserId(WkdDirectoryStructure directoryStructure) throws Exception {
String lookupMail = "wrong-userid@" + domain;
String userId = "WKD-Test Different User-ID <different-userid@" + domain + ">";
String description = "Certificate has a single, valid user-id '" + userId + "', but is deposited for mail address '" + lookupMail + "'.";
PGPPublicKeyRing publicKeys = certificate(userId);
Path path = directoryStructure.getRelativeCertificatePath(lookupMail);
File file = directoryStructure.resolve(path);
if (!file.exists() && !file.createNewFile()) {
throw new IOException("Cannot create file " + file.getAbsolutePath());
}
try (FileOutputStream fileOut = new FileOutputStream(file)) {
publicKeys.encode(fileOut);
}
return new TestCase(false, "Wrong User-ID", description, lookupMail, path, directoryStructure.getAddress(lookupMail));
}
private TestCase noUserId(WkdDirectoryStructure directoryStructure) throws Exception {
String lookupMail = "absent-userid@" + domain;
String description = "Certificate has no user-id, but is deposited for mail address '" + lookupMail + "'.";
// Generate certificate with temp user-id
PGPPublicKeyRing publicKeys = certificate("DeleteMe");
// delete user-id
List<PGPPublicKey> keys = new ArrayList<>();
Iterator<PGPPublicKey> publicKeyIterator = publicKeys.iterator();
PGPPublicKey primaryKey = publicKeyIterator.next();
primaryKey = PGPPublicKey.removeCertification(primaryKey, "DeleteMe");
keys.add(primaryKey);
while (publicKeyIterator.hasNext()) {
keys.add(publicKeyIterator.next());
}
publicKeys = new PGPPublicKeyRing(keys);
Path path = directoryStructure.getRelativeCertificatePath(lookupMail);
File file = directoryStructure.resolve(path);
if (!file.exists() && !file.createNewFile()) {
throw new IOException("Cannot create file " + file.getAbsolutePath());
}
try (FileOutputStream fileOut = new FileOutputStream(file)) {
publicKeys.encode(fileOut);
}
return new TestCase(false, "No User-ID", description, lookupMail, path, directoryStructure.getAddress(lookupMail));
}
private TestCase secretKeyMaterial(WkdDirectoryStructure directoryStructure) throws Exception {
String lookupMail = "test-secret-key@" + domain;
String description = "Certificate file contains secret key material.";
PGPSecretKeyRing secretKeys = PGPainless.generateKeyRing().modernKeyRing("WKD-Test Secret Key <" + lookupMail + ">", null);
Path path = directoryStructure.getRelativeCertificatePath(lookupMail);
File file = directoryStructure.resolve(path);
if (!file.exists() && !file.createNewFile()) {
throw new IOException("Cannot create file " + file.getAbsolutePath());
}
try (FileOutputStream fileOut = new FileOutputStream(file)) {
secretKeys.encode(fileOut);
}
return new TestCase(false, "Secret Key Material", description, lookupMail, path, directoryStructure.getAddress(lookupMail));
}
}

View file

@ -0,0 +1,131 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
package pgp.wkd.test_suite;
import pgp.wkd.WKDAddress;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Path;
public abstract class WkdDirectoryStructure {
protected final String domain;
protected final File rootDir;
protected final File wellKnown;
protected final File openpgpkey;
public WkdDirectoryStructure(File rootDirectory, String domain) {
this.domain = domain;
this.rootDir = rootDirectory;
wellKnown = new File(rootDirectory, ".well-known");
openpgpkey = new File(wellKnown, "openpgpkey");
}
public abstract File getHu();
public abstract Path getRelativeCertificatePath(String mailAddress);
public abstract void mkdirs() throws IOException;
protected void mkdir(File dir) throws IOException {
if (!dir.exists() && !dir.mkdirs()) {
throw new IOException("Cannot create directory '" + dir.getAbsolutePath() + "'.");
}
if (dir.isFile()) {
throw new IOException("Cannot create directory '" + dir.getAbsolutePath() + "': Is a file.");
}
}
public abstract URI getAddress(String mail);
public abstract File resolve(Path path);
public static class DirectMethod extends WkdDirectoryStructure {
private final File hu;
public DirectMethod(File rootDirectory, String domain) {
super(rootDirectory, domain);
this.hu = new File(openpgpkey, "hu");
}
@Override
public File getHu() {
return hu;
}
@Override
public Path getRelativeCertificatePath(String mailAddress) {
WKDAddress address = WKDAddress.fromEmail(mailAddress);
String path = address.getDirectMethodURI().getPath();
String fileName = path.substring(path.lastIndexOf('/') + 1);
return rootDir.toPath().relativize(new File(getHu(), fileName).toPath());
}
@Override
public void mkdirs() throws IOException {
mkdir(rootDir);
mkdir(wellKnown);
mkdir(openpgpkey);
mkdir(hu);
}
@Override
public URI getAddress(String mail) {
return WKDAddress.fromEmail(mail).getDirectMethodURI();
}
@Override
public File resolve(Path path) {
return rootDir.toPath().resolve(path).toFile();
}
}
public static class AdvancedMethod extends WkdDirectoryStructure {
private final File domainFile;
private final File hu;
public AdvancedMethod(File rootDir, String domain) {
super(rootDir, domain);
this.domainFile = new File(openpgpkey, domain);
this.hu = new File(domainFile, "hu");
}
@Override
public File getHu() {
return hu;
}
@Override
public Path getRelativeCertificatePath(String mailAddress) {
WKDAddress address = WKDAddress.fromEmail(mailAddress);
String path = address.getAdvancedMethodURI().getPath();
String fileName = path.substring(path.lastIndexOf('/') + 1);
return rootDir.toPath().relativize(new File(getHu(), fileName).toPath());
}
@Override
public void mkdirs() throws IOException {
mkdir(rootDir);
mkdir(wellKnown);
mkdir(openpgpkey);
mkdir(domainFile);
mkdir(hu);
}
@Override
public URI getAddress(String mail) {
return WKDAddress.fromEmail(mail).getAdvancedMethodURI();
}
@Override
public File resolve(Path path) {
return rootDir.toPath().resolve(path).toFile();
}
}
}

View file

@ -0,0 +1,8 @@
// SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
//
// SPDX-License-Identifier: Apache-2.0
/**
* WKD Test Suite Generator.
*/
package pgp.wkd.test_suite;

View file

@ -0,0 +1,31 @@
<!--
SPDX-FileCopyrightText: 2022 Paul Schaub <vanitasvitae@fsfe.org>
SPDX-License-Identifier: Apache-2.0
-->
# WKD Test Suite
The purpose of the WKD test suite is to generate a set of certificates which can be published to a WKD.
The certificates cover different scenarios and edge cases and can be used to validate WKD implementations experimentally.
## Test Vectors
| Test Case | Description |
|-----------------------------------|----------------------------------------------------------------------------------------|
| Base Case | Certificate with a single valid user-id A identified by A |
| Advanced Base Case | Certificate with multiple user-ids A and B identified by A, B |
| Wrong User-ID | Certificate with a single valid user-id A identified by B |
| Missing User-ID | Certificate without a user-id identified by A |
| Unbound User-ID | Certificate with a single unbound user-id A identified by A |
| Expired User-ID | Certificate with a single expired user-id A identified by A |
| Invalidly bound User-ID | Certificate with a single user-id A with broken binding identified by A |
| Revoked User-ID | Certificate with a single revoked user-id A identified by A |
| Revoked Certificate | Certificate with a single user-id A, with direct-key revocation identified by A |
| Third-Party User-ID | Certificate with an additional user-id B certified by third party, identified by B |
| Broken Data | Certificate file contains garbage |
| Secret Key | Certificate file contains secret key material |
| Signatures | Certificate file contains certification signatures only |
| Multiple Certificates | Certificate file contains multiple certificates (with valid user-id A) identified by A |
| Armored Certificate | Certificate file contains armored certificate |
| Duplicate mail address in user-id | Certificate contains user-id of form ".*<A>.*<B>.*" |