JsignCLI { void execute(String... args) throws SignerException, ParseException { DefaultParser parser = new DefaultParser(); CommandLine cmd = parser.parse(options, args); if (cmd.hasOption("help") || args.length == 0) { printHelp(); return; } SignerHelper helper = new SignerHelper(new StdOutConsole(1), "option"); setOption(PARAM_KEYSTORE, helper, cmd); setOption(PARAM_STOREPASS, helper, cmd); setOption(PARAM_STORETYPE, helper, cmd); setOption(PARAM_ALIAS, helper, cmd); setOption(PARAM_KEYPASS, helper, cmd); setOption(PARAM_KEYFILE, helper, cmd); setOption(PARAM_CERTFILE, helper, cmd); setOption(PARAM_ALG, helper, cmd); setOption(PARAM_TSAURL, helper, cmd); setOption(PARAM_TSMODE, helper, cmd); setOption(PARAM_TSRETRIES, helper, cmd); setOption(PARAM_TSRETRY_WAIT, helper, cmd); setOption(PARAM_NAME, helper, cmd); setOption(PARAM_URL, helper, cmd); setOption(PARAM_PROXY_URL, helper, cmd); setOption(PARAM_PROXY_USER, helper, cmd); setOption(PARAM_PROXY_PASS, helper, cmd); helper.replace(cmd.hasOption(PARAM_REPLACE)); setOption(PARAM_ENCODING, helper, cmd); File file = cmd.getArgList().isEmpty() ? null : new File(cmd.getArgList().get(0)); helper.sign(file); } JsignCLI(); static void main(String... args);  }
@Test(expected = SignerException.class) public void testMissingFile() throws Exception { cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password"); }
@Test(expected = SignerException.class) public void testFileNotFound() throws Exception { cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password", "wineyes-foo.exe"); }
@Test(expected = SignerException.class) public void testCorruptedFile() throws Exception { cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password", "target/test-classes/keystore.jks"); }
@Test(expected = SignerException.class) public void testConflictingAttributes() throws Exception { 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(expected = SignerException.class) public void testMissingCertFile() throws Exception { cli.execute("--keyfile=target/test-classes/keystores/privatekey.pvk", "" + targetFile); }
@Test(expected = SignerException.class) public void testMissingKeyFile() throws Exception { cli.execute("--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "" + targetFile); }
@Test(expected = SignerException.class) public void testCertFileNotFound() throws Exception { cli.execute("--certfile=target/test-classes/keystores/certificate2.spc", "--keyfile=target/test-classes/privatekey.pvk", "" + targetFile); }
@Test(expected = SignerException.class) public void testKeyFileNotFound() throws Exception { cli.execute("--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "--keyfile=target/test-classes/privatekey2.pvk", "" + targetFile); }
@Test(expected = SignerException.class) public void testCorruptedCertFile() throws Exception { cli.execute("--certfile=target/test-classes/keystores/privatekey.pvk", "--keyfile=target/test-classes/privatekey.pvk", "" + targetFile); }
@Test(expected = SignerException.class) public void testCorruptedKeyFile() throws Exception { 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(expected = SignerException.class) public void testMissingKeyStore() throws Exception { cli.execute("" + targetFile); }
@Test(expected = SignerException.class) public void testUnsupportedDigestAlgorithm() throws Exception { 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: assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile)); try (PEFile peFile = new PEFile(targetFile)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@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); List<CMSSignedData> signatures = script.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); }
@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); List<CMSSignedData> signatures = script.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); }
@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)) { List<CMSSignedData> signatures = file.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@Test public void testSigningPKCS12() throws Exception { cli.execute("--name=WinEyes", "--url=http: assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile)); try (PEFile peFile = new PEFile(targetFile)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@Test public void testSigningPVKSPC() throws Exception { cli.execute("--url=http: assertTrue("The file " + targetFile + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile)); try (PEFile peFile = new PEFile(targetFile)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@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)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@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)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@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: assertTrue("The file " + targetFile2 + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile2)); try (PEFile peFile = new PEFile(targetFile2)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@Test(expected = SignerException.class) public void testUnsupportedKeyStoreType() throws Exception { cli.execute("--keystore=keystore.jks", "--storetype=ABC", "" + targetFile); }
@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: assertTrue("The file " + targetFile2 + " wasn't changed", SOURCE_FILE_CRC32 != FileUtils.checksumCRC32(targetFile2)); try (PEFile peFile = new PEFile(targetFile2)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } }
@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: "--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)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } } 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: "--proxyUrl=http: "--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)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); CMSSignedData signature = signatures.get(0); assertNotNull(signature); } } 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)) { List<CMSSignedData> signatures = peFile.getSignatures(); assertNotNull(signatures); assertEquals(1, signatures.size()); assertNotNull(signatures.get(0)); assertEquals("Digest algorithm", DigestAlgorithm.SHA512.oid, signatures.get(0).getDigestAlgorithmIDs().iterator().next().getAlgorithm()); } }
@Test(expected = ParseException.class) public void testUnknownOption() throws Exception { cli.execute("--jsign"); }
@Test public void testUnknownPKCS11Provider() throws Exception { try { cli.execute("--storetype=PKCS11", "--keystore=SunPKCS11-jsigntest", "--keypass=password", "" + targetFile); fail("No exception thrown"); } catch (SignerException e) { assertEquals("exception message", "Security provider SunPKCS11-jsigntest not found", e.getMessage()); } }
@Test public void testMissingPKCS11Configuration() throws Exception { try { cli.execute("--storetype=PKCS11", "--keystore=jsigntest.cfg", "--keypass=password", "" + targetFile); fail("No exception thrown"); } catch (SignerException e) { assertEquals("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() throws Exception { try { cli.execute("--storetype=PKCS11", "--keystore=pom.xml", "--keypass=password", "" + targetFile); fail("No exception thrown"); } catch (SignerException e) { assertTrue(e.getCause().getCause() instanceof ProviderException || e.getCause().getCause() instanceof InvalidParameterException); } }
@Test public void testExplicitCertificateChainOnlyOnSingleEntry() throws Exception { try { cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=test", "--keypass=password", "--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain.spc", "" + targetFile); fail("No exception thrown"); } catch (SignerException e) { assertEquals("exception message", "certfile option can only be specified if the certificate from the keystore contains only one entry", e.getMessage()); } }
@Test(expected = SignerException.class) public void testKeyStoreNotFound() throws Exception { cli.execute("--keystore=keystore2.jks", "" + targetFile); }
@Test public void testExplicitCertificateChainOnlyOnSingleEntryWhenFirst() throws Exception { try { cli.execute("--keystore=target/test-classes/keystores/keystore-no-chain.jks", "--alias=test", "--keypass=password", "--certfile=target/test-classes/keystores/jsign-test-certificate-full-chain-reversed.spc", "" + targetFile); fail("No exception thrown"); } catch (SignerException e) { assertEquals("exception message", "The certificate chain in target/test-classes/keystores/jsign-test-certificate-full-chain-reversed.spc does not match the chain from the keystore", e.getMessage().replace('\\', '/')); } }
@Test(expected = SignerException.class) public void testCorruptedKeyStore() throws Exception { cli.execute("--keystore=" + targetFile, "" + targetFile); }
@Test public void testEmptyKeystore() throws Exception { try { cli.execute("--keystore=target/test-classes/keystores/keystore-empty.p12", "--alias=unknown", "" + targetFile); fail("No exception thrown"); } catch (SignerException e) { assertTrue(e.getMessage().startsWith("No certificate found in the keystore")); } }
@Test(expected = SignerException.class) public void testMissingAlias() throws Exception { 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("exception 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() throws Exception { try { cli.execute("--keystore=target/test-classes/keystores/keystore-two-entries.p12", "" + targetFile); fail("No exception thrown"); } catch (SignerException e) { assertEquals("exception message", "alias option must be set to select a certificate (available aliases: test, test2)", e.getMessage()); } }
@Test(expected = SignerException.class) public void testCertificateNotFound() throws Exception { cli.execute("--keystore=target/test-classes/keystores/keystore.jks", "--alias=foo", "" + targetFile); }