/************************************************************************* * * * SignServer: The OpenSource Automated Signing Server * * * * This software is free software; you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public * * License as published by the Free Software Foundation; either * * version 2.1 of the License, or any later version. * * * * See terms of license at gnu.org. * * * *************************************************************************/ package org.signserver.server; import java.security.cert.Certificate; import org.apache.log4j.Logger; import org.junit.FixMethodOrder; import org.junit.runners.MethodSorters; import org.signserver.common.*; import org.signserver.testutils.ModulesTestCase; import static org.junit.Assert.*; import org.junit.Before; import org.junit.Test; /** * Tests limits for the key usages. * * @author Markus Kilas * @version $Id: LimitKeyUsagesTest.java 3465 2013-05-01 10:24:46Z netmackan $ */ @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class LimitKeyUsagesTest extends ModulesTestCase { /** Logger for this class. */ private static final Logger LOG = Logger.getLogger( LimitKeyUsagesTest.class); /** WORKERID used in this test case. */ private static final int WORKERID_1 = 5802; /** * Test with this number of signings. */ private static final int LIMIT = 10; @Before public void setUp() throws Exception { SignServerUtil.installBCProvider(); } @Test public void test00SetupDatabase() throws Exception { addSoftDummySigner(WORKERID_1, "TestLimitKeyUsageSigner", "AAAAojCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArIHGOBjP7WZdbgVbw61FzswgtZYhnsVW4ZRskPYcYbjXFO7Hf5zBWC6c/C+vb9w4AvdgEFvzHLtP9qJ+bcJAZw6VvFcZnLgEbPHCwXSVVFIsY2/OJ6ys6GOAAX/inLpvTjkUSzCoB28s4yYGaZXv7v77pjsjODYpDz4W5UCx9AcCAwEAAQAAAnowggJ2AgEAMA0GCSqGSIb3DQEBAQUABIICYDCCAlwCAQACgYEArIHGOBjP7WZdbgVbw61FzswgtZYhnsVW4ZRskPYcYbjXFO7Hf5zBWC6c/C+vb9w4AvdgEFvzHLtP9qJ+bcJAZw6VvFcZnLgEbPHCwXSVVFIsY2/OJ6ys6GOAAX/inLpvTjkUSzCoB28s4yYGaZXv7v77pjsjODYpDz4W5UCx9AcCAwEAAQKBgF2f/WXayZbuFM0uqVQ1SYroLOSA+/RA5FuAA8BVYqgC+vDIe4weFq12dwtEEjJi0h+CBSg7z2GLo+WW4YlOgUbHwK/QTaFpqrhGSeQlH34aCwxsPnU3RK8vsDajrbnQPL/1p+ORvxv8uaEYCLIb0cv/6CJg7CHpKs6yLR4o8znBAkEA7cPmWaZAXHNVUP11VwhSR8+GJQo9xYMnZI2D04/w8DNsPSauDr9ZeJc7w5fvkaZZPCARR/gmbrs7AL5NpT5QpwJBALm8pJ3ld+2mIzcvd+zXnQP/0Iz+2VCykE25y6u66bOD541HP0D3rGNho/JV4BPgnwa0nRx2aWkyc9bjDuipTaECQQDSzk/byHVkArXwGukAg1ZAaRSsnonqJsC0fGwXFZYvwcgD59mHJcy0CJJqdrlnz69qiZwIzVF19/b2T8QT8E4dAkBDhlOKm+wX1/ihjX5Z+qE43P3i5Jv4/JH9z/g9vLxN6Tx7XlWetuxTTSIfbh0C3PyzoWIlAN+dwRvgGbhH2ZVBAkB+XCVH/XwrsQbewvyflwqZI1AWfSvpgakCPQ/PYtlfPV/zgFby/RTJchypM28dnQLnZByBM0Av+qTQ1eu+kLW9", "MIIEoDCCAoigAwIBAgIIOM0BlA53koswDQYJKoZIhvcNAQELBQAwTTEXMBUGA1UEAwwORFNTIFJvb3QgQ0EgMTAxEDAOBgNVBAsMB1Rlc3RpbmcxEzARBgNVBAoMClNpZ25TZXJ2ZXIxCzAJBgNVBAYTAlNFMB4XDTExMTEwNDA2MDcxNVoXDTIxMTEwNDA2MDcxNVowUjEcMBoGA1UEAwwTdGVzdF9rZXl1c2FnZWxpbWl0MTEQMA4GA1UECwwHVGVzdGluZzETMBEGA1UECgwKU2lnblNlcnZlcjELMAkGA1UEBhMCU0UwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCkmfrPNs6C9uAIOYltwytmzdJm6PwpCdCiCdNvtuqpsSjhbqyCehSUjjsqyfAFtbyIuen38YPmexO8LUAT3ooinJya1BJ1BUX2IGYX9Vz8psVVik+TioAVFWpZMkQAGSt8Ywt7x4qu7/Fn+unR95lBfiFJNm4ODaak59UGtceZKvJokUDJCSb6KNh0iI3H/GxDRf5tUfRVHReaqVVZfYZgI/XVM/CMjjN6WNEc8UzBXOZ1IZzPcs/1BkrXcvOPej/6d2DOoFR153gJ+LoRRx5YEUuWw/qZ6UPSNl9gkyG/vApIFlnTAvM4QvqhWGhGFnVusVXgSXgRDOs6ta7yhxXrAgMBAAGjfzB9MB0GA1UdDgQWBBQ217GiTEGjZPrU+TmRoqFOPovkQjAMBgNVHRMBAf8EAjAAMB8GA1UdIwQYMBaAFCB6Id7orbsCqPtxWKQJYrnYWAWiMA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwQwDQYJKoZIhvcNAQELBQADggIBABHhLDcjhfWyACzP7oxOKO0Cvdwb9CZiPSoGCSbbO1LuBLZ9raGL1ZSBaxaHyTcifMz7UW5daGMY5N5XLswC2NrXSkoN/ijZFlz64JLIFe/eI+IqEFTHxHFZIFWHgf/KHCeX1nC89UqGUmu64/daZIPbh96EfEZla9/KB7RwC4JSDlniisXuqnQ3rtP4Zxl9PjapZ307gxHFbtCXVYeZ0CEkanCZhtom13d1IbKvTE1jW/ey1zRR2soGl/DZ6G7Kz9KOSWmkKMls5LyyU8QUctnzKy+8IreDDu7toyyvWRGtoSfTrlvcWwojdSFXyBYQmpGwg7r72Qkxl7BLQ48wBEnAQdIb+S4QmYslrDZ7tKtrvpRNFS64XJt5vAlSxhwTHWcIQEtylSFzw3W6uS6vCshaaen0nrMNPs2C0BLYCKuYdWAbTUfJptB3pi8M4S2QBUGrDJl1yaZe91/X8+HZhvbwLnE+QK+8MLQAyzFOR4pH126B/3YSDmq+Wy1lEylQjN3bFp8hiZPCjX4ZVEcA6bTEZFZq13FZUoo7kI3W3M5+cPV+zm7wYj+3kVCkpz6N1Z+L7V+DuhnBxtCkZilb9dlkQqQkaWL5T7KPgvPbLbkYx5bV5mjTJlGYcZejJJsQ/lb6yelAxflsMW5Jp2n6Ex+CLuxesMM5S0X4Fou9s6a8;MIICXjCCAcegAwIBAgIIVfqFvbhubAgwDQYJKoZIhvcNAQEFBQAwPzERMA8GA1UEAwwIRGVtb0NBMTAxHTAbBgNVBAoMFERlbW8gT3JnYW5pemF0aW9uIDEwMQswCQYDVQQGEwJTRTAeFw0xMDA0MDMyMjE4NDRaFw0yMDA0MDIyMjE4NDRaMD8xETAPBgNVBAMMCERlbW9DQTEwMR0wGwYDVQQKDBREZW1vIE9yZ2FuaXphdGlvbiAxMDELMAkGA1UEBhMCU0UwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ1J0yCi7uzd3Qhyxt6IJ5UOdrjbrZfEKts2sNOfFDpCRJUrUx0nHb+rY5/hvQXEDqz/apHoHq+RX+QOaYSOMDsMRb/O/uNkyitk1i8zSj2CMp+ts7CEG8PomzbaQA57haZ5tA9ppNJLx9+ukF1CYxCDLLKq0H9rB/JtzwfRuXmRAgMBAAGjYzBhMB0GA1UdDgQWBBSM0aVi0y2nWS6QGUds9UUqipREbjAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFIzRpWLTLadZLpAZR2z1RSqKlERuMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQUFAAOBgQA/93lyqxAqcbxRpW5AUSle4N+ikuBAWcL/JHUijMRi//OaDOOCupHnm3lsWfzUfOmUmm4mV80L3kWsws+6yIHaj9UpFxFlGpEbB91rHLw7Oc9yMraiwM6r3RqEhVxZNuam1AnUzeSTFu4X9i3AseUD4xBoxUXHWeqmWTHeXH42Pw=="); workerSession.reloadConfiguration(WORKERID_1); } /** * Do signings up to KEYUSAGELIMIT and then check that the next signing * fails. * * Assumption: The configured key (test_keyusagelimit1.p12) is not used by * any other tests. * * @throws Exception in case of exception */ @Test public void test01Limit() throws Exception { final long oldValue = workerSession.getKeyUsageCounterValue(WORKERID_1); workerSession.setWorkerProperty(WORKERID_1, "KEYUSAGELIMIT", String.valueOf(oldValue + LIMIT)); workerSession.reloadConfiguration(WORKERID_1); // Do a number of signings LIMIT try { for (int i = 0; i < LIMIT; i++) { LOG.debug("Signing " + i); doSign(); } } catch (CryptoTokenOfflineException ex) { fail(ex.getMessage()); } try { doSign(); fail("Should have failed now"); } catch (CryptoTokenOfflineException ok) { } } @Test public void test02NoIncreaseWhenOffline() throws Exception { // Increase key usage limit so we should be able to do two more signings final long oldValue = workerSession.getKeyUsageCounterValue(WORKERID_1); workerSession.setWorkerProperty(WORKERID_1, "KEYUSAGELIMIT", String.valueOf(oldValue + 2)); workerSession.reloadConfiguration(WORKERID_1); // Do one signing just to see that it works doSign(); // Make the signer offline and do one signing that should not increase //counter, which means that after activating it again we should be able //to do one more signing workerSession.deactivateSigner(WORKERID_1); doSignOffline(); // Should be able to do one signing now workerSession.activateSigner(WORKERID_1, "foo123"); doSign(); } /** * Tests that when the key usage counter is not disabled it will increase * after a signing. */ @Test public void test03IncreaseWhenNotDisabled() throws Exception { // Remove any limits just in case workerSession.removeWorkerProperty(WORKERID_1, "KEYUSAGELIMIT"); // Set to not disabled = enabled workerSession.setWorkerProperty(WORKERID_1, "DISABLEKEYUSAGECOUNTER", "FaLsE"); workerSession.reloadConfiguration(WORKERID_1); final long oldValue = workerSession.getKeyUsageCounterValue(WORKERID_1); if (oldValue < 0) { throw new Exception("Test case assumes non negative counter value"); } doSign(); // Counter should have increased final long actual = workerSession.getKeyUsageCounterValue(WORKERID_1); assertEquals("counter should have increased", oldValue + 1, actual); } /** * Tests that when the key usage counter is disabled and there is no * key usage limit a signing will not increase the counter. */ @Test public void test04NoIncreaseWhenDisabled() throws Exception { // Remove any limits just in case workerSession.removeWorkerProperty(WORKERID_1, "KEYUSAGELIMIT"); // Set to be disabled workerSession.setWorkerProperty(WORKERID_1, "DISABLEKEYUSAGECOUNTER", "TrUe"); workerSession.reloadConfiguration(WORKERID_1); final long oldValue = workerSession.getKeyUsageCounterValue(WORKERID_1); if (oldValue < 0) { throw new Exception("Test case assumes non negative counter value"); } doSign(); // Counter should not have increased final long actual = workerSession.getKeyUsageCounterValue(WORKERID_1); assertEquals("counter should not have increased", oldValue, actual); } /** * Tests that when the key usage counter is disabled but there is a limit * it will still count. This is actually a configuration error but we want * to treat it the safe way which is to still honor the limit. */ @Test public void test05IncreaseWhenDisabledButThereIsALimit() throws Exception { // Set a limit so we should still to counting workerSession.setWorkerProperty(WORKERID_1, "KEYUSAGELIMIT", "100000"); // Set to disabled workerSession.setWorkerProperty(WORKERID_1, "DISABLEKEYUSAGECOUNTER", "TRUE"); workerSession.reloadConfiguration(WORKERID_1); final long oldValue = workerSession.getKeyUsageCounterValue(WORKERID_1); if (oldValue < 0) { throw new Exception("Test case assumes non negative counter value"); } doSign(); // Counter should have increased final long actual = workerSession.getKeyUsageCounterValue(WORKERID_1); assertEquals("counter should have increased", oldValue + 1, actual); } @Test public void test06() throws Exception { final long oldValue = workerSession.getKeyUsageCounterValue(WORKERID_1); if (oldValue < 0) { throw new Exception("Test case assumes non negative counter value"); } // Set a limit so we can only do one signing workerSession.setWorkerProperty(WORKERID_1, "KEYUSAGELIMIT", String.valueOf(oldValue + 1)); // Set to disabled workerSession.setWorkerProperty(WORKERID_1, "DISABLEKEYUSAGECOUNTER", "TRUE"); workerSession.reloadConfiguration(WORKERID_1); // One signing is ok doSign(); // Next the signer should be offline doSignOffline(); } /** Do a dummy sign. */ private void doSign() throws Exception { final RequestContext context = new RequestContext(); final GenericSignRequest request = new GenericSignRequest(1, "".getBytes()); GenericSignResponse res; // Send request to dispatcher res = (GenericSignResponse) workerSession.process(WORKERID_1, request, context); Certificate cert = res.getSignerCertificate(); assertNotNull(cert); } /** Do a dummy sign and expect failure. */ private void doSignOffline() throws Exception { try { final RequestContext context = new RequestContext(); final GenericSignRequest request = new GenericSignRequest(1, "".getBytes()); // Send request to dispatcher workerSession.process(WORKERID_1, request, context); } catch (CryptoTokenOfflineException ok) { // OK } catch (Exception ex) { LOG.error("Signer offline but other exception", ex); fail("Signer offline but other exception: " + ex.getMessage()); } } @Test public void test99TearDownDatabase() throws Exception { removeWorker(WORKERID_1); } }