//* Licensed Materials - Property of *
//* IBM *
//* Miracle A/S *
//* Alexandra Instituttet A/S *
//* *
//* eu.abc4trust.pabce.1.34 *
//* *
//* (C) Copyright IBM Corp. 2014. All Rights Reserved. *
//* (C) Copyright Miracle A/S, Denmark. 2014. All Rights Reserved. *
//* (C) Copyright Alexandra Instituttet A/S, Denmark. 2014. All *
//* Rights Reserved. *
//* US Government Users Restricted Rights - Use, duplication or *
//* disclosure restricted by GSA ADP Schedule Contract with IBM Corp. *
//* *
//* This file is 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 eu.abc4trust.abce.integrationtests;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;
import javax.xml.bind.JAXBException;
import org.junit.Test;
import org.xml.sax.SAXException;
import com.google.inject.Guice;
import com.google.inject.Injector;
import eu.abc4trust.TestConfiguration;
import eu.abc4trust.abce.external.issuer.IssuerAbcEngine;
import eu.abc4trust.abce.external.revocation.RevocationAbcEngine;
import eu.abc4trust.abce.external.user.UserAbcEngine;
import eu.abc4trust.abce.internal.revocation.RevocationConstants;
import eu.abc4trust.abce.internal.user.credentialManager.CredentialManager;
import eu.abc4trust.abce.testharness.IntegrationModuleFactory;
import eu.abc4trust.abce.testharness.IssuanceHelper;
import eu.abc4trust.cryptoEngine.CryptoEngineException;
import eu.abc4trust.exceptions.TokenVerificationException;
import eu.abc4trust.guice.ProductionModuleFactory.CryptoEngine;
import eu.abc4trust.keyManager.KeyManager;
import eu.abc4trust.keyManager.KeyManagerException;
import eu.abc4trust.revocationProxy.revauth.RevocationProxyAuthority;
import eu.abc4trust.xml.Attribute;
import eu.abc4trust.xml.CredentialDescription;
import eu.abc4trust.xml.CredentialSpecification;
import eu.abc4trust.xml.FriendlyDescription;
import eu.abc4trust.xml.IssuancePolicy;
import eu.abc4trust.xml.IssuerParameters;
import eu.abc4trust.xml.PresentationToken;
import eu.abc4trust.xml.Reference;
import eu.abc4trust.xml.RevocationAuthorityParameters;
import eu.abc4trust.xml.RevocationInformation;
import eu.abc4trust.xml.SystemParameters;
import eu.abc4trust.xml.util.XmlUtils;
/**
* This test checks that a user can get issued a simple identity card with firstname, lastname, and
* birthday.
*/
public class RevocationTest {
private static final String USERNAME = "defaultUser";
private static final URI REVOCATION_PARAMETERS_UID = IntegrationTestUtil.REVOCATION_PARAMETERS_UID;
private static final String ISSUANCE_POLICY_ID_CARD = IntegrationTestUtil.ISSUANCE_POLICY_ID_CARD;
private static final String CREDENTIAL_SPECIFICATION_ID_CARD = IntegrationTestUtil.CREDENTIAL_SPECIFICATION_ID_CARD;
@Test(timeout = TestConfiguration.TEST_TIMEOUT)
public void simpleRevocationIdemixTest() throws Exception {
URI cl_technology = Helper.getSignatureTechnologyURI("cl");
int keyLength = 1024;
Entities entities = new Entities();
entities.addEntity("ISSUER", cl_technology, true);
entities.addEntity("USER", true);
entities.addEntity("VERIFIER", true);
runTestSimple(keyLength, entities);
}
@Test(timeout = TestConfiguration.TEST_TIMEOUT)
public void simpleRevocationUproveTest() throws Exception {
URI uprove_technology = Helper.getSignatureTechnologyURI("brands");
int keyLength = 1024;
Entities entities = new Entities();
entities.addEntity("ISSUER", uprove_technology, true);
entities.addEntity("USER", true);
entities.addEntity("VERIFIER", true);
runTestSimple(keyLength, entities);
}
@Test(timeout = TestConfiguration.TEST_TIMEOUT)
public void multipleRevokeRevocationIdemixTest() throws Exception {
URI cl_technology = Helper.getSignatureTechnologyURI("cl");
int keyLength = 1024;
Entities entities = new Entities();
entities.addEntity("ISSUER", cl_technology, true);
entities.addEntity("USER", true);
entities.addEntity("VERIFIER", true);
runTestMulti(keyLength, entities);
}
@Test(timeout = TestConfiguration.TEST_TIMEOUT)
public void multipleRevokeRevocationUProveTest() throws Exception {
URI uprove_technology = Helper.getSignatureTechnologyURI("brands");
int keyLength = 1024;
Entities entities = new Entities();
entities.addEntity("ISSUER", uprove_technology, true);
entities.addEntity("USER", true);
entities.addEntity("VERIFIER", true);
runTestMulti(keyLength, entities);
}
private void runTestSimple(int keyLength, Entities entities) throws Exception {
// Setp up engines
Injector revocationInjector = Guice
.createInjector(IntegrationModuleFactory.newModule(new Random(1231),
CryptoEngine.IDEMIX));
RevocationProxyAuthority revocationProxyAuthority = revocationInjector
.getInstance(RevocationProxyAuthority.class);
KeyManager revocationKeyManager = revocationInjector
.getInstance(KeyManager.class);
Collection<Injector> injectors = createEntities(entities, revocationProxyAuthority);
SystemParameters systemParameters = Entities.setupSystemParameters(entities, keyLength);
revocationKeyManager.storeSystemParameters(systemParameters);
List<Object> parametersList = new ArrayList<Object>();
RevocationAbcEngine revocationEngine = revocationInjector
.getInstance(RevocationAbcEngine.class);
RevocationAuthorityParameters revocationAuthorityParameters = this.setupRevocationEngine(revocationInjector, REVOCATION_PARAMETERS_UID, keyLength);
// Setup issuer and inspector
URI credentialTechnology = entities.getTechnology("ISSUER");
URI issuerParametersGovernmentUID =
getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_ID_CARD);
parametersList.add(setupIssuer(entities.getInjector("ISSUER"), systemParameters,
credentialTechnology, issuerParametersGovernmentUID, 4, REVOCATION_PARAMETERS_UID));
// Store all issuer and inspector parameters to all key managers
entities.storePublicParametersToKeyManagers(parametersList);
// Store all credential specifications to all key managers
storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_ID_CARD);
addRevocationKeyManagers(entities, revocationAuthorityParameters);
IssuanceHelper issuanceHelper = new IssuanceHelper();
// Step 1. Get identity card.
CredentialDescription cd =
IntegrationTestUtil.issueAndStoreIdCard(entities.getInjector("ISSUER"), entities.getInjector("USER"), issuanceHelper,
"1995-05-05Z");
// Step 2. log in to some service using the identity card.
PresentationToken pt =
IntegrationTestUtil.loginWithIdCard(entities.getInjector("USER"), entities.getInjector("VERIFIER"), issuanceHelper,
IntegrationTestUtil.REVOCATION_PARAMETERS_UID);
assertNotNull(pt);
UserAbcEngine userEngine = entities.getInjector("USER").getInstance(UserAbcEngine.class);
URI credUid = cd.getCredentialUID();
assertTrue(!userEngine.isRevoked(USERNAME, credUid));
Attribute revocationHandleAttribute = RevocationTest.this.getRevocationHandle(cd);
// Step 3. Revoke credential.
RevocationTest.this.revokeCredential(revocationInjector, issuanceHelper, REVOCATION_PARAMETERS_UID,
revocationHandleAttribute);
assertTrue(userEngine.isRevoked(USERNAME, credUid));
// The verifier needs to retrive the latest revocation information
// in order to put in the UID in the presentation policy.
RevocationInformation revocationInformation =
revocationEngine.updateRevocationInformation(REVOCATION_PARAMETERS_UID);
// Step 4. Verify revoked credential is revoked.
RevocationTest.this.revokedCredentialsShouldNotBeAllowed(entities.getInjector("USER"),
entities.getInjector("VERIFIER"), issuanceHelper, revocationInformation, 0);
}
private void runTestMulti(int keyLength, Entities entities) throws Exception {
// Setp up engines
Injector revocationInjector = Guice
.createInjector(IntegrationModuleFactory.newModule(new Random(1231),
CryptoEngine.IDEMIX));
RevocationProxyAuthority revocationProxyAuthority = revocationInjector
.getInstance(RevocationProxyAuthority.class);
KeyManager revocationKeyManager = revocationInjector
.getInstance(KeyManager.class);
Collection<Injector> injectors = createEntities(entities, revocationProxyAuthority);
SystemParameters systemParameters = Entities.setupSystemParameters(entities, keyLength);
revocationKeyManager.storeSystemParameters(systemParameters);
List<Object> parametersList = new ArrayList<Object>();
RevocationAbcEngine revocationEngine = revocationInjector
.getInstance(RevocationAbcEngine.class);
RevocationAuthorityParameters revocationAuthorityParameters = this.setupRevocationEngine(revocationInjector, REVOCATION_PARAMETERS_UID, keyLength);
// Setup issuer and inspector
URI credentialTechnology = entities.getTechnology("ISSUER");
URI issuerParametersGovernmentUID =
getIssuanceParametersUIDFromIssuancePolicy(ISSUANCE_POLICY_ID_CARD);
parametersList.add(setupIssuer(entities.getInjector("ISSUER"), systemParameters,
credentialTechnology, issuerParametersGovernmentUID, 4, REVOCATION_PARAMETERS_UID));
// Store all issuer and inspector parameters to all key managers
entities.storePublicParametersToKeyManagers(parametersList);
// Store all credential specifications to all key managers
storeCredentialSpecificationToKeyManagers(injectors, CREDENTIAL_SPECIFICATION_ID_CARD);
addRevocationKeyManagers(entities, revocationAuthorityParameters);
IssuanceHelper issuanceHelper = new IssuanceHelper();
// Step 1. Get identity card.
CredentialDescription cd1 =
IntegrationTestUtil.issueAndStoreIdCard(entities.getInjector("ISSUER"), entities.getInjector("USER"), issuanceHelper,
"1995-05-05Z");
CredentialDescription cd2 =
IntegrationTestUtil.issueAndStoreIdCard(entities.getInjector("ISSUER"), entities.getInjector("USER"), issuanceHelper,
"1995-05-05Z");
CredentialDescription cd3 =
IntegrationTestUtil.issueAndStoreIdCard(entities.getInjector("ISSUER"), entities.getInjector("USER"), issuanceHelper,
"1995-05-05Z");
// Step 2. log in to some service using the identity card.
PresentationToken pt =
IntegrationTestUtil.loginWithIdCard(entities.getInjector("USER"), entities.getInjector("VERIFIER"), issuanceHelper,
IntegrationTestUtil.REVOCATION_PARAMETERS_UID);
assertNotNull(pt);
// Step 3. Revoke credentials.
// Step 3a. Check that the credentials are not revoked.
UserAbcEngine userEngine = entities.getInjector("USER").getInstance(UserAbcEngine.class);
URI credUid1 = cd1.getCredentialUID();
assertTrue(!userEngine.isRevoked(USERNAME, credUid1));
URI credUid2 = cd2.getCredentialUID();
assertTrue(!userEngine.isRevoked(USERNAME, credUid2));
URI credUid3 = cd3.getCredentialUID();
assertTrue(!userEngine.isRevoked(USERNAME, credUid3));
// 3b. Revoke credentials
Attribute revocationHandleAttribute = RevocationTest.this.getRevocationHandle(cd1);
RevocationTest.this.revoke(revocationInjector, issuanceHelper, REVOCATION_PARAMETERS_UID,
revocationHandleAttribute);
assertTrue(userEngine.isRevoked(USERNAME, credUid1));
revocationHandleAttribute = RevocationTest.this.getRevocationHandle(cd2);
RevocationTest.this.revoke(revocationInjector, issuanceHelper, REVOCATION_PARAMETERS_UID,
revocationHandleAttribute);
assertTrue(userEngine.isRevoked(USERNAME, credUid2));
assertTrue(!userEngine.isRevoked(USERNAME, credUid3));
// The verifier needs to retrive the latest revocation information
// in order to put in the UID in the presentation policy.
RevocationInformation revocationInformation =
revocationEngine.updateRevocationInformation(REVOCATION_PARAMETERS_UID);
// User and verifier must manually obtain the latest revocation information
// and update credentials accordingly.
entities.getInjector("USER").getInstance(KeyManager.class).getLatestRevocationInformation(REVOCATION_PARAMETERS_UID);
entities.getInjector("USER").getInstance(CredentialManager.class).updateNonRevocationEvidence(USERNAME);
entities.getInjector("VERIFIER").getInstance(KeyManager.class).getLatestRevocationInformation(REVOCATION_PARAMETERS_UID);
// Step 4. Log in using the identity card.
RevocationTest.this.revokedCredentialsShouldNotBeAllowed(entities.getInjector("USER"),
entities.getInjector("VERIFIER"),
issuanceHelper, revocationInformation, cd1.getCredentialUID());
RevocationTest.this.revokedCredentialsShouldNotBeAllowed(entities.getInjector("USER"),
entities.getInjector("VERIFIER"),
issuanceHelper, revocationInformation, cd2.getCredentialUID());
RevocationTest.this.nonRevokedCredentialsShouldBeAllowed(entities.getInjector("USER"),
entities.getInjector("VERIFIER"),
issuanceHelper, revocationInformation, cd3.getCredentialUID());
RevocationTest.this.nonRevokedCredentialsShouldBeAllowed(entities.getInjector("USER"),
entities.getInjector("VERIFIER"),
issuanceHelper, revocationInformation, cd3.getCredentialUID());
}
private void revoke(Injector revocationInjector, IssuanceHelper issuanceHelper, URI revParamsUid,
Attribute revocationHandleAttribute) throws CryptoEngineException {
RevocationTest.this.revokeCredential(revocationInjector, issuanceHelper, revParamsUid,
revocationHandleAttribute);
}
private void nonRevokedCredentialsShouldBeAllowed(Injector userInjector,
Injector verifierInjector, IssuanceHelper issuanceHelper,
RevocationInformation revocationInformation, URI chosenCredential) throws Exception {
try {
IntegrationTestUtil.loginToAccount(userInjector, verifierInjector, issuanceHelper,
IntegrationTestUtil.REVOCATION_PARAMETERS_UID, chosenCredential,
revocationInformation);
assertTrue("We expect the verification to validate because the credential is not revoked",
true);
} catch (TokenVerificationException ex) {
ex.printStackTrace();
fail("We should be able to log in with a non-revoked credential");
}
}
private void revokedCredentialsShouldNotBeAllowed(Injector userInjector,
Injector verifierInjector, IssuanceHelper issuanceHelper,
RevocationInformation revocationInformation, URI chosenPresentationToken) throws Exception {
try {
IntegrationTestUtil.loginToAccount(userInjector, verifierInjector, issuanceHelper,
IntegrationTestUtil.REVOCATION_PARAMETERS_UID, chosenPresentationToken,
revocationInformation);
fail("We should not be allowed to log in with a revoked credential");
} catch (TokenVerificationException ex) {
// StringWriter sw = new StringWriter();
// PrintWriter pw = new PrintWriter(sw);
// ex.printStackTrace(pw);
// assertTrue(sw.toString().contains("Incorrect T-value at position"));
assertTrue("We expect the verification to fail due to a revoked credential", ex.getMessage()
.startsWith("The crypto evidence in the presentation token is not valid"));
} catch (RuntimeException ex) {
assertTrue("We expect failure to generate a presentation Token",
ex.getMessage().startsWith("Cannot generate presentationToken")
|| ex.getMessage().startsWith("Cannot choose credential, URI does not exist!"));
}
}
private void revokedCredentialsShouldNotBeAllowed(Injector userInjector,
Injector verifierInjector, IssuanceHelper issuanceHelper,
RevocationInformation revocationInformation, int chosenPresentationToken) throws Exception {
try {
IntegrationTestUtil.loginToAccount(userInjector, verifierInjector, issuanceHelper,
IntegrationTestUtil.REVOCATION_PARAMETERS_UID, revocationInformation);//,
//chosenPresentationToken);
fail("We should not be allowed to log in with a revoked credential");
} catch (TokenVerificationException ex) {
// StringWriter sw = new StringWriter();
// PrintWriter pw = new PrintWriter(sw);
// ex.printStackTrace(pw);
// assertTrue(sw.toString().contains("Incorrect T-value at position"));
assertTrue("We expect the verification to fail due to a revoked credential", ex.getMessage()
.startsWith("The crypto evidence in the presentation token is not valid"));
} catch (RuntimeException ex) {
assertTrue("We expect failure to generate a presentation Token",
ex.getMessage().startsWith("Cannot generate presentationToken"));
}
}
private Attribute getRevocationHandle(CredentialDescription cd) {
for (Attribute attribute : cd.getAttribute()) {
if (attribute.getAttributeDescription().getType()
.compareTo(RevocationConstants.REVOCATION_HANDLE) == 0) {
return attribute;
}
}
return null;
}
private void revokeCredential(Injector revocationInjector, IssuanceHelper issuanceHelper,
URI revParamsUid, Attribute revocationHandleAttribute) throws CryptoEngineException {
issuanceHelper.revokeCredential(revocationInjector, revParamsUid, revocationHandleAttribute);
}
private Collection<Injector> createEntities(Entities entities, RevocationProxyAuthority revocationProxyAuthority) {
entities.initInjectors(revocationProxyAuthority);
return entities.getInjectors();
}
private RevocationAuthorityParameters setupRevocationEngine(Injector revocationInjector, URI revParamsUid, int keyLength) throws Exception{
RevocationAbcEngine revocationEngine = revocationInjector
.getInstance(RevocationAbcEngine.class);
Reference revocationInfoReference = new Reference();
revocationInfoReference.setReferenceType(URI.create("url"));
revocationInfoReference.getReferences().add(URI.create("https://example.org/"));
Reference nonRevocationEvidenceReference = new Reference();
nonRevocationEvidenceReference.setReferenceType(URI.create("url"));
nonRevocationEvidenceReference.getReferences().add(URI.create("https://example.org/"));
Reference nonRrevocationUpdateReference = new Reference();
nonRrevocationUpdateReference.setReferenceType(URI.create("url"));
nonRrevocationUpdateReference.getReferences().add(URI.create("https://example.org/"));
return revocationEngine.setupRevocationAuthorityParameters(keyLength,
Helper.getRevocationTechnologyURI("cl"), revParamsUid,
revocationInfoReference,
nonRevocationEvidenceReference,
nonRrevocationUpdateReference);
}
private void addRevocationKeyManagers(Entities entities, RevocationAuthorityParameters revAuthParams)
throws KeyManagerException{
for(Injector injector: entities.getInjectors()){
KeyManager keyManager = injector.getInstance(KeyManager.class);
keyManager.storeRevocationAuthorityParameters(revAuthParams.getParametersUID(), revAuthParams);
}
}
private URI getIssuanceParametersUIDFromIssuancePolicy(String pathToIssuancePolicy)
throws UnsupportedEncodingException, JAXBException, SAXException {
// Load issuance policy
IssuancePolicy issuancePolicy =
(IssuancePolicy) XmlUtils.getObjectFromXML(
this.getClass().getResourceAsStream(pathToIssuancePolicy), true);
// Get issuer parameters UID from credential template
return issuancePolicy.getCredentialTemplate().getIssuerParametersUID();
}
private IssuerParameters setupIssuer(Injector issuerInjector, SystemParameters systemParameters,
URI credentialTechnology, URI issuanceParametersUID,
int maximalNumberOfAttributes, URI revocationAuthority) throws CryptoEngineException {
// Generate issuer parameters.
IssuerAbcEngine issuerEngine = issuerInjector.getInstance(IssuerAbcEngine.class);
IssuerParameters issuerParameters =
issuerEngine.setupIssuerParameters(systemParameters,
maximalNumberOfAttributes, credentialTechnology, issuanceParametersUID, revocationAuthority, new LinkedList<FriendlyDescription>());
return issuerParameters;
}
private void storeCredentialSpecificationToKeyManagers(Collection<Injector> injectors,
String pathToCredentialSpecification) throws KeyManagerException,
UnsupportedEncodingException, JAXBException, SAXException {
// Load credential specifications.
CredentialSpecification credSpec =
(CredentialSpecification) XmlUtils.getObjectFromXML(
this.getClass().getResourceAsStream(pathToCredentialSpecification), true);
// Store credential specifications.
URI specificationUID = credSpec.getSpecificationUID();
for (Injector injector : injectors) {
KeyManager keyManager = injector.getInstance(KeyManager.class);
keyManager.storeCredentialSpecification(specificationUID, credSpec);
}
}
}