JsignCLITest.java
/*
* Copyright 2012 Emmanuel Bourg
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.jsign;
import java.io.File;
import java.io.FileOutputStream;
import java.net.ProxySelector;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.security.InvalidParameterException;
import java.security.Permission;
import java.security.ProviderException;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicBoolean;
import io.netty.handler.codec.http.HttpRequest;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.cms.CMSSignedData;
import org.junit.After;
import org.junit.Assume;
import org.junit.Before;
import org.junit.Test;
import org.littleshoot.proxy.HttpFilters;
import org.littleshoot.proxy.HttpFiltersSourceAdapter;
import org.littleshoot.proxy.HttpProxyServer;
import org.littleshoot.proxy.ProxyAuthenticator;
import org.littleshoot.proxy.impl.DefaultHttpProxyServer;
import net.jsign.msi.MSIFile;
import net.jsign.pe.PEFile;
import net.jsign.script.PowerShellScript;
import static net.jsign.DigestAlgorithm.*;
import static org.junit.Assert.*;
public class JsignCLITest {
private JsignCLI cli;
private File sourceFile = new File("target/test-classes/wineyes.exe");
private File targetFile = new File("target/test-classes/wineyes-signed-with-cli.exe");
private String keystore = "keystore.jks";
private String alias = "test";
private String keypass = "password";
private static final long SOURCE_FILE_CRC32 = 0xA6A363D8L;
@Before
public void setUp() throws Exception {
cli = new JsignCLI();
// remove the files signed previously
if (targetFile.exists()) {
assertTrue("Unable to remove the previously signed file", targetFile.delete());
}
assertEquals("Source file CRC32", SOURCE_FILE_CRC32, FileUtils.checksumCRC32(sourceFile));
Thread.sleep(100);
FileUtils.copyFile(sourceFile, targetFile);
}
@After
public void tearDown() {
// reset the proxy configuration
ProxySelector.setDefault(null);
}
@Test
public void testPrintHelp() {
JsignCLI.main("--help");
}
@Test
public void testMissingKeyStore() {
assertThrows(SignerException.class, () -> cli.execute("sign", "" + targetFile));
}
@Test
public void testUnsupportedKeyStoreType() {
assertThrows(IllegalArgumentException.class, () -> cli.execute("--keystore=keystore.jks", "--storetype=ABC", "" + targetFile));
}
@Test
public void testKeyStoreNotFound() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=keystore2.jks", "" + targetFile));
}
@Test
public void testCorruptedKeyStore() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=" + targetFile, "" + targetFile));
}
@Test
public void testEmptyKeystore() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore-empty.p12", "--alias=unknown", "" + targetFile));
assertTrue(e.getMessage().startsWith("No certificate found in the keystore"));
}
@Test
public void testMissingAlias() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "" + targetFile));
}
@Test
public void testAliasNotFound() throws Exception {
try {
cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=unknown", "" + targetFile);
} catch (SignerException e) {
assertEquals("message", "No certificate found under the alias 'unknown' in the keystore target/test-classes/keystores/keystore.jks (available aliases: test)", e.getMessage().replace('\\', '/'));
}
}
@Test
public void testMultipleAliases() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore-two-entries.p12", "" + targetFile));
assertEquals("message", "alias option must be set to select a certificate (available aliases: test, test2)", e.getMessage());
}
@Test
public void testCertificateNotFound() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=foo", "" + targetFile));
}
@Test
public void testMissingFile() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password"));
}
@Test
public void testFileNotFound() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password", "wineyes-foo.exe"));
}
@Test
public void testCorruptedFile() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password", "target/test-classes/keystore.jks"));
}
@Test
public void testConflictingAttributes() {
assertThrows(SignerException.class, () -> cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password", "--keyfile=privatekey.pvk", "--certfile=jsign-test-certificate-full-chain.spc", "" + targetFile));
}
@Test
public void testMissingCertFile() {
assertThrows(SignerException.class, () -> cli.execute("--keyfile=target/test-classes/keystores/privatekey.pvk", "" + targetFile));
}
@Test
public void testMissingKeyFile() {
assertThrows(SignerException.class, () -> cli.execute("--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "" + targetFile));
}
@Test
public void testCertFileNotFound() {
assertThrows(SignerException.class, () -> cli.execute("--certfile=target/test-classes/keystores/certificate2.spc", "--keyfile=target/test-classes/privatekey.pvk", "" + targetFile));
}
@Test
public void testKeyFileNotFound() {
assertThrows(SignerException.class, () -> cli.execute("--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "--keyfile=target/test-classes/privatekey2.pvk", "" + targetFile));
}
@Test
public void testCorruptedCertFile() {
assertThrows(SignerException.class, () -> cli.execute("--certfile=target/test-classes/keystores/privatekey.pvk", "--keyfile=target/test-classes/privatekey.pvk", "" + targetFile));
}
@Test
public void testCorruptedKeyFile() {
assertThrows(SignerException.class, () -> cli.execute("--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "--keyfile=target/test-classes/jsign-test-certificate-full-chain.spc", "" + targetFile));
}
@Test
public void testUnsupportedDigestAlgorithm() {
assertThrows(SignerException.class, () -> cli.execute("--alg=SHA-123", "--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password", "" + targetFile));
}
@Test
public void testSigning() throws Exception {
cli.execute("--name=WinEyes", "--url=http://www.steelblue.com/WinEyes", "--alg=SHA-1", "--keystore=target/test-classes/keystores/" + keystore, "--keypass=" + keypass, "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA1);
}
}
@Test
public void testSigningMultipleFiles() throws Exception {
cli.execute("--name=WinEyes", "--url=http://www.steelblue.com/WinEyes", "--alg=SHA-1", "--keystore=target/test-classes/keystores/" + keystore, "--keypass=" + keypass, "" + targetFile, "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA1, SHA1);
}
}
@Test
public void testSigningMultipleFilesWithListFile() throws Exception {
File listFile = new File("target/test-classes/files.txt");
Files.write(listFile.toPath(), Arrays.asList("# first file", '"' + targetFile.getPath() + '"', " ", "# second file", targetFile.getAbsolutePath()));
cli.execute("--name=WinEyes", "--url=http://www.steelblue.com/WinEyes", "--alg=SHA-1", "--keystore=target/test-classes/keystores/" + keystore, "--keypass=" + keypass, "@" + listFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA1, SHA1);
}
}
@Test
public void testSigningMultipleFilesWithListFileUTF16() throws Exception {
File listFile = new File("target/test-classes/files-utf16.txt");
try (FileOutputStream out = new FileOutputStream(listFile)) {
out.write(ByteOrderMark.UTF_16LE.getBytes());
IOUtils.writeLines(Arrays.asList(targetFile.getAbsolutePath(), targetFile.getAbsolutePath()), "\r\n", out, StandardCharsets.UTF_16LE);
}
cli.execute("--name=WinEyes", "--url=http://www.steelblue.com/WinEyes", "--alg=SHA-1", "--keystore=target/test-classes/keystores/" + keystore, "--keypass=" + keypass, "@" + listFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA1, SHA1);
}
}
@Test
public void testSigningMultipleFilesWithPattern() throws Exception {
File sourceFile = new File("target/test-classes/wineyes.exe");
File targetFile1 = new File("target/test-classes/wineyes-pattern1.exe");
targetFile1.delete();
File targetFile2 = new File("target/test-classes/wineyes-pattern2.exe");
targetFile2.delete();
FileUtils.copyFile(sourceFile, targetFile1);
FileUtils.copyFile(sourceFile, targetFile2);
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--keypass=" + keypass, "target/**/*-pattern*.exe");
try (PEFile peFile = new PEFile(targetFile1)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
try (PEFile peFile = new PEFile(targetFile2)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testSigningPowerShell() throws Exception {
File sourceFile = new File("target/test-classes/hello-world.ps1");
File targetFile = new File("target/test-classes/hello-world-signed-with-cli.ps1");
FileUtils.copyFile(sourceFile, targetFile);
cli.execute("--alg=SHA-1", "--replace", "--encoding=ISO-8859-1", "--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "" + targetFile);
PowerShellScript script = new PowerShellScript(targetFile);
SignatureAssert.assertSigned(script, SHA1);
}
@Test
public void testSigningPowerShellWithDefaultEncoding() throws Exception {
File sourceFile = new File("target/test-classes/hello-world.ps1");
File targetFile = new File("target/test-classes/hello-world-signed-with-cli.ps1");
FileUtils.copyFile(sourceFile, targetFile);
cli.execute("--alg=SHA-1", "--replace", "--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "" + targetFile);
PowerShellScript script = new PowerShellScript(targetFile);
SignatureAssert.assertSigned(script, SHA1);
}
@Test
public void testSigningMSI() throws Exception {
File sourceFile = new File("target/test-classes/minimal.msi");
File targetFile = new File("target/test-classes/minimal-signed-with-cli.msi");
FileUtils.copyFile(sourceFile, targetFile);
cli.execute("--alg=SHA-1", "--replace", "--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "" + targetFile);
try (MSIFile file = new MSIFile(targetFile)) {
SignatureAssert.assertSigned(file, SHA1);
}
}
@Test
public void testSigningPKCS12() throws Exception {
cli.execute("--name=WinEyes", "--url=http://www.steelblue.com/WinEyes", "--alg=SHA-256", "--keystore=target/test-classes/keystores/keystore.p12", "--alias=test", "--storepass=password", "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testSigningJCEKS() throws Exception {
cli.execute("--name=WinEyes", "--url=http://www.steelblue.com/WinEyes", "--alg=SHA-256", "--keystore=target/test-classes/keystores/keystore.jceks", "--alias=test", "--storepass=password", "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testSigningJKS() throws Exception {
cli.execute("--name=WinEyes", "--url=http://www.steelblue.com/WinEyes", "--alg=SHA-256", "--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--storepass=password", "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testSigningPVKSPC() throws Exception {
cli.execute("--url=http://www.steelblue.com/WinEyes", "--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "--keyfile=target/test-classes/keystores/privatekey-encrypted.pvk", "--storepass=password", "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testSigningPEM() throws Exception {
cli.execute("--certfile=target/test-classes/keystores/jsign-test-certificate.pem", "--keyfile=target/test-classes/keystores/privatekey.pkcs8.pem", "--keypass=password", "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testSigningEncryptedPEM() throws Exception {
cli.execute("--certfile=target/test-classes/keystores/jsign-test-certificate.pem", "--keyfile=target/test-classes/keystores/privatekey-encrypted.pkcs1.pem", "--keypass=password", "" + targetFile);
assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile));
try (PEFile peFile = new PEFile(targetFile)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testSigningWithYubikey() throws Exception {
Assume.assumeTrue("No Yubikey detected", YubiKey.isPresent());
cli.execute("--storetype=YUBIKEY", "--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "--storepass=123456", "--alias=X.509 Certificate for Digital Signature", "" + targetFile, "" + targetFile);
}
@Test
public void testTimestampingAuthenticode() throws Exception {
File targetFile2 = new File("target/test-classes/wineyes-timestamped-with-cli-authenticode.exe");
FileUtils.copyFile(sourceFile, targetFile2);
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "--tsaurl=http://timestamp.sectigo.com", "--tsmode=authenticode", "" + targetFile2);
assertTrue("The file " + targetFile2 + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile2));
try (PEFile peFile = new PEFile(targetFile2)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testTimestampingRFC3161() throws Exception {
File targetFile2 = new File("target/test-classes/wineyes-timestamped-with-cli-rfc3161.exe");
FileUtils.copyFile(sourceFile, targetFile2);
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "--tsaurl=http://timestamp.sectigo.com", "--tsmode=rfc3161", "" + targetFile2);
assertTrue("The file " + targetFile2 + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile2));
try (PEFile peFile = new PEFile(targetFile2)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
}
@Test
public void testTimestampingWithProxyUnauthenticated() throws Exception {
final AtomicBoolean proxyUsed = new AtomicBoolean(false);
HttpProxyServer proxy = DefaultHttpProxyServer.bootstrap().withPort(12543)
.withFiltersSource(new HttpFiltersSourceAdapter() {
@Override
public HttpFilters filterRequest(HttpRequest originalRequest) {
proxyUsed.set(true);
return super.filterRequest(originalRequest);
}
})
.start();
try {
File targetFile2 = new File("target/test-classes/wineyes-timestamped-with-cli-rfc3161-proxy-unauthenticated.exe");
FileUtils.copyFile(sourceFile, targetFile2);
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass,
"--tsaurl=http://timestamp.sectigo.com", "--tsmode=rfc3161", "--tsretries=1", "--tsretrywait=1",
"--proxyUrl=localhost:" + proxy.getListenAddress().getPort(),
"" + targetFile2);
assertTrue("The file " + targetFile2 + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile2));
assertTrue("The proxy wasn't used", proxyUsed.get());
try (PEFile peFile = new PEFile(targetFile2)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
} finally {
proxy.stop();
}
}
@Test
public void testTimestampingWithProxyAuthenticated() throws Exception {
final AtomicBoolean proxyUsed = new AtomicBoolean(false);
HttpProxyServer proxy = DefaultHttpProxyServer.bootstrap().withPort(12544)
.withFiltersSource(new HttpFiltersSourceAdapter() {
@Override
public HttpFilters filterRequest(HttpRequest originalRequest) {
proxyUsed.set(true);
return super.filterRequest(originalRequest);
}
})
.withProxyAuthenticator(new ProxyAuthenticator() {
@Override
public boolean authenticate(String username, String password) {
return "jsign".equals(username) && "jsign".equals(password);
}
@Override
public String getRealm() {
return "Jsign Tests";
}
})
.start();
try {
File targetFile2 = new File("target/test-classes/wineyes-timestamped-with-cli-rfc3161-proxy-authenticated.exe");
FileUtils.copyFile(sourceFile, targetFile2);
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass,
"--tsaurl=http://timestamp.sectigo.com", "--tsmode=rfc3161", "--tsretries=1", "--tsretrywait=1",
"--proxyUrl=http://localhost:" + proxy.getListenAddress().getPort(),
"--proxyUser=jsign",
"--proxyPass=jsign",
"" + targetFile2);
assertTrue("The file " + targetFile2 + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile2));
assertTrue("The proxy wasn't used", proxyUsed.get());
try (PEFile peFile = new PEFile(targetFile2)) {
SignatureAssert.assertSigned(peFile, SHA256);
}
} finally {
proxy.stop();
}
}
@Test
public void testReplaceSignature() throws Exception {
File targetFile2 = new File("target/test-classes/wineyes-re-signed.exe");
FileUtils.copyFile(sourceFile, targetFile2);
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "" + targetFile2);
assertTrue("The file " + targetFile2 + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile2));
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "--alg=SHA-512", "--replace", "" + targetFile2);
try (PEFile peFile = new PEFile(targetFile2)) {
SignatureAssert.assertSigned(peFile, SHA512);
}
}
@Test
public void testDetachedSignature() throws Exception {
File targetFile2 = new File("target/test-classes/wineyes-signed-detached.exe");
FileUtils.copyFile(sourceFile, targetFile2);
cli.execute("--keystore=target/test-classes/keystores/" + keystore, "--alias=" + alias, "--keypass=" + keypass, "--detached", "" + targetFile2);
assertTrue("Signature wasn't detached", new File("target/test-classes/wineyes-signed-detached.exe.sig").exists());
}
@Test
public void testExitOnError() {
NoExitSecurityManager manager = new NoExitSecurityManager();
System.setSecurityManager(manager);
try {
assertThrows("VM not terminated", SecurityException.class, () -> JsignCLI.main("foo.exe"));
assertEquals("Exit code", Integer.valueOf(1), manager.getStatus());
} finally {
System.setSecurityManager(null);
}
}
private static class NoExitSecurityManager extends SecurityManager {
private Integer status;
public Integer getStatus() {
return status;
}
public void checkPermission(Permission perm) { }
public void checkPermission(Permission perm, Object context) { }
public void checkExit(int status) {
this.status = status;
throw new SecurityException("Exit disabled");
}
}
@Test
public void testUnknownOption() {
assertThrows(ParseException.class, () -> cli.execute("--jsign"));
}
@Test
public void testUnknownPKCS11Provider() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("--storetype=PKCS11", "--keystore=SunPKCS11-jsigntest", "--keypass=password", "" + targetFile));
assertEquals("message", "Security provider SunPKCS11-jsigntest not found", e.getMessage());}
@Test
public void testMissingPKCS11Configuration() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("--storetype=PKCS11", "--keystore=jsigntest.cfg", "--keypass=password", "" + targetFile));
assertEquals("message", "keystore option should either refer to the SunPKCS11 configuration file or to the name of the provider configured in jre/lib/security/java.security", e.getMessage());
}
@Test
public void testBrokenPKCS11Configuration() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("--storetype=PKCS11", "--keystore=pom.xml", "--keypass=password", "" + targetFile));
assertTrue(e.getCause() instanceof ProviderException // JDK < 9
|| e.getCause().getCause() instanceof InvalidParameterException); // JDK 9+
}
@Test
public void testOverrideKeyStoreCertificate() throws Exception {
cli.execute("--keystore=target/test-classes/keystores/keystore-2022.p12", "--alias=test", "--storepass=password", "--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "" + targetFile);
try (Signable signable = Signable.of(targetFile)) {
SignatureAssert.assertSigned(signable, SHA256);
CMSSignedData signature = signable.getSignatures().get(0);
assertEquals("issuer", "CN=Jsign Code Signing CA 2024", signature.getSignerInfos().iterator().next().getSID().getIssuer().toString());
}
}
@Test
public void testUnknownCommand() {
Exception e = assertThrows(ParseException.class, () -> cli.execute("unsign", "" + targetFile));
assertEquals("message", "Unknown command 'unsign'", e.getMessage());
}
@Test
public void testExtract() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("extract", "--verbose", "" + targetFile));
assertEquals("message", "No signature found in " + targetFile.getPath(), e.getMessage());
}
@Test
public void testRemove() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("remove", "--debug", "xeyes.exe"));
assertEquals("message", "Couldn't find xeyes.exe", e.getMessage());
}
@Test
public void testTag() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("tag", "--value", "userid:1234-ABCD-5678-EFGH", "" + targetFile));
assertEquals("message", "No signature found in " + targetFile.getPath(), e.getMessage());
}
@Test
public void testTimestamp() {
Exception e = assertThrows(SignerException.class, () -> cli.execute("timestamp", "--quiet", "" + targetFile));
assertEquals("message", "No signature found in " + targetFile.getPath(), e.getMessage());
}
}