//* Licensed Materials - Property of *
//* IBM *
//* *
//* eu.abc4trust.pabce.1.34 *
//* *
//* (C) Copyright IBM Corp. 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.util;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import eu.abc4trust.abce.internal.TokenManager;
import eu.abc4trust.abce.internal.user.credentialManager.CredentialManager;
import eu.abc4trust.abce.internal.user.credentialManager.CredentialManagerException;
import eu.abc4trust.abce.internal.user.evidenceGeneration.EvidenceGenerationOrchestration;
import eu.abc4trust.cryptoEngine.CryptoEngineException;
import eu.abc4trust.cryptoEngine.user.AbstractPseudonymSerializer;
import eu.abc4trust.keyManager.KeyManager;
import eu.abc4trust.keyManager.KeyManagerException;
import eu.abc4trust.util.attributeTypes.MyAttributeValue;
import eu.abc4trust.util.attributeTypes.MyAttributeValueFactory;
import eu.abc4trust.xml.ApplicationData;
import eu.abc4trust.xml.AttributeInPolicy;
import eu.abc4trust.xml.AttributeInRevocation;
import eu.abc4trust.xml.AttributeInToken;
import eu.abc4trust.xml.AttributePredicate;
import eu.abc4trust.xml.CredentialDescription;
import eu.abc4trust.xml.CredentialInPolicy;
import eu.abc4trust.xml.CredentialInPolicy.IssuerAlternatives.IssuerParametersUID;
import eu.abc4trust.xml.CredentialInToken;
import eu.abc4trust.xml.CredentialSpecification;
import eu.abc4trust.xml.FriendlyDescription;
import eu.abc4trust.xml.InspectorPublicKey;
import eu.abc4trust.xml.IssuerParameters;
import eu.abc4trust.xml.Message;
import eu.abc4trust.xml.ObjectFactory;
import eu.abc4trust.xml.PresentationPolicy;
import eu.abc4trust.xml.PresentationTokenDescription;
import eu.abc4trust.xml.PseudonymInPolicy;
import eu.abc4trust.xml.PseudonymInToken;
import eu.abc4trust.xml.PseudonymWithMetadata;
import eu.abc4trust.xml.SecretDescription;
import eu.abc4trust.xml.VerifierDrivenRevocationInPolicy;
import eu.abc4trust.xml.VerifierDrivenRevocationInToken;
import eu.abc4trust.xml.VerifierIdentity;
import eu.abc4trust.xml.util.XmlUtils;
public class MyPresentationPolicy {
private final PresentationPolicy policy;
private final static Logger logger = Logger.getLogger(MyPresentationPolicy.class.getName());
public MyPresentationPolicy(PresentationPolicy policy) {
this.policy = policy;
}
public PresentationPolicy getPolicy() {
return policy;
}
public boolean isSatisfiedBy(PresentationTokenDescription ptd, TokenManager tk, KeyManager km) {
if (!ptd.getPolicyUID().equals(policy.getPolicyUID())) {
logger.warning("Different policyUIDs.");
return false;
}
if (!messageEquals(ptd.getMessage(), policy.getMessage())) {
logger.warning("Messages don't match.");
return false;
}
if (!pseudonymListEquals(ptd.getPseudonym(), policy.getPseudonym())) {
logger.warning("Pseudonyms don't match");
return false;
}
if (!credentialsEquals(ptd.getCredential(), policy.getCredential(), km)) {
logger.warning("Credentials don't match");
return false;
}
if (!predicatesEquals(ptd.getAttributePredicate(), policy.getAttributePredicate())) {
logger.warning("Predicates don't match.");
return false;
}
if (!verifierDrivenRevocationListEquals(ptd.getVerifierDrivenRevocation(),
policy.getVerifierDrivenRevocation())) {
logger.warning("Verifier Driven Revocation don't match");
return false;
}
if(policy.isAllowSimpleProof() == false && ptd.isUsesSimpleProof()){
logger.warning("Policy does not allow simple proofs.");
return false;
}
if(ptd.isUsesSimpleProof() && ! checkIfSimpleProofAdmissible()) {
logger.warning("Policy is too complex for simple proof flag.");
}
if (tk != null) {
return checkEstablishedPseudonyms(ptd, tk);
} else {
return true;
}
}
private boolean pseudonymListEquals(List<PseudonymInToken> lhs, List<PseudonymInPolicy> rhs) {
if (lhs.size() != rhs.size()) {
logger.warning("Incorrect number of predicates");
return false;
}
Iterator<PseudonymInPolicy> rhsIter = rhs.iterator();
for (PseudonymInToken lhsPred : lhs) {
PseudonymInPolicy rhsPred = rhsIter.next();
if (!pseudonymEquals(lhsPred, rhsPred)) {
logger.warning("List of pseudonyms are not equal.");
return false;
}
}
return true;
}
private boolean myequals(Object lhs, Object rhs) {
return (lhs == rhs) || ((lhs != null) && lhs.equals(rhs));
}
private boolean myArrayEquals(byte[] lhs, byte[] rhs) {
if (lhs == null && rhs == null) {
return true;
} else if (lhs != null && rhs == null) {
return false;
} else if (lhs == null && rhs != null) {
return false;
} else {
return Arrays.equals(lhs, rhs);
}
}
private boolean predicatesEquals(List<AttributePredicate> lhs, List<AttributePredicate> rhs) {
if (lhs.size() != rhs.size()) {
logger.warning("Incorrect number of predicates");
return false;
}
Iterator<AttributePredicate> rhsIter = rhs.iterator();
for (AttributePredicate lhsPred : lhs) {
AttributePredicate rhsPred = rhsIter.next();
if (!predicateEquals(lhsPred, rhsPred)) {
logger.warning("List of predicates are not equal.");
return false;
}
}
return true;
}
private boolean predicateEquals(AttributePredicate lhs, AttributePredicate rhs) {
if (!myequals(lhs.getFunction(), rhs.getFunction())) {
logger.warning("Different function");
return false;
}
if (lhs.getAttributeOrConstantValue().size() != rhs.getAttributeOrConstantValue().size()) {
logger.warning("Different number of arguments");
return false;
}
Iterator<Object> lhsList = lhs.getAttributeOrConstantValue().iterator();
for (Object rhsObj : rhs.getAttributeOrConstantValue()) {
Object lhsObj = lhsList.next();
if (rhsObj instanceof AttributePredicate.Attribute) {
if (!(lhsObj instanceof AttributePredicate.Attribute)) {
logger.warning("Different classes of arguments.");
return false;
}
if (!attributeInPredicateEquals((AttributePredicate.Attribute) rhsObj,
(AttributePredicate.Attribute) lhsObj)) {
logger.warning("Different attribute predicates.");
return false;
}
} else {
if (!constantValueEquals(rhsObj, lhsObj, lhs.getFunction())) {
logger.warning("Different constant value.");
return false;
}
}
}
return true;
}
private boolean constantValueEquals(Object rhsObj, Object lhsObj, URI function) {
MyAttributeValue rhs = MyAttributeValueFactory.parseValueFromFunction(function, rhsObj);
MyAttributeValue lhs = MyAttributeValueFactory.parseValueFromFunction(function, lhsObj);
return rhs.isCompatibleAndEquals(lhs);
}
private boolean attributeInPredicateEquals(AttributePredicate.Attribute rhs,
AttributePredicate.Attribute lhs) {
if (!rhs.getAttributeType().equals(lhs.getAttributeType())) {
logger.warning("Different attribute type");
return false;
}
if (!rhs.getCredentialAlias().equals(lhs.getCredentialAlias())) {
logger.warning("Different credential alias");
return false;
}
if (!myequals(rhs.getDataHandlingPolicy(), lhs.getDataHandlingPolicy())) {
logger.warning("Different data handling policy");
return false;
}
return true;
}
private boolean credentialsEquals(List<CredentialInToken> lhs, List<CredentialInPolicy> rhs,
KeyManager keyManager) {
if (lhs.size() != rhs.size()) {
logger.warning("Different number of credentials");
return false;
}
// Credentials must be in the same order
Iterator<CredentialInToken> lhsIter = lhs.iterator();
Iterator<CredentialInPolicy> rhsIter = rhs.iterator();
while (lhsIter.hasNext() && rhsIter.hasNext()) {
CredentialInToken lhsCred = lhsIter.next();
CredentialInPolicy rhsCred = rhsIter.next();
if (!credentialEquals(lhsCred, rhsCred, keyManager)) {
logger.warning("Different credential");
return false;
}
}
return true;
}
private boolean credentialEquals(CredentialInToken lhs, CredentialInPolicy rhs, KeyManager keyManager) {
if (!myequals(lhs.getAlias(), rhs.getAlias())) {
logger.warning("Alias not the same");
return false;
}
if (!rhs.getCredentialSpecAlternatives().getCredentialSpecUID()
.contains(lhs.getCredentialSpecUID())) {
logger.warning("CredentialSpecification not among the alternatives");
logger.warning("Value was: " + lhs.getCredentialSpecUID());
return false;
}
if (!issuerAmongAlternatives(rhs.getIssuerAlternatives().getIssuerParametersUID(),
lhs.getIssuerParametersUID(), lhs.getRevocationInformationUID())) {
logger.warning("IssuerParameters and RevocationInformation not among alterntives");
logger.warning("Values were: " + lhs.getIssuerParametersUID() + " - "
+ lhs.getRevocationInformationUID());
return false;
}
if (!attributesEquals(lhs.getDisclosedAttribute(), rhs.getDisclosedAttribute())) {
logger.warning("Disclosed Attributes don't match");
return false;
}
if (!myequals(lhs.getSameKeyBindingAs(), rhs.getSameKeyBindingAs())) {
logger.warning("Different SameKeyBindingAs");
return false;
}
if(keyManager != null) {
if(!checkIssuerParameterCredentialSpecConsistency(lhs.getIssuerParametersUID(),
lhs.getCredentialSpecUID(), keyManager)) {
logger.warning("Incompatible issuer parameters and credential specification");
return false;
}
} else {
logger.warning("Did not check if issuer parameters are for the correct credential spec.");
}
return true;
}
private boolean checkIssuerParameterCredentialSpecConsistency(URI issuerParametersUID,
URI credentialSpecUID, KeyManager keyManager) {
try {
IssuerParameters ip = keyManager.getIssuerParameters(issuerParametersUID);
CredentialSpecification spec = keyManager.getCredentialSpecification(credentialSpecUID);
return ip.getMaximalNumberOfAttributes() >= spec.getAttributeDescriptions().getAttributeDescription().size();
} catch (KeyManagerException e) {
throw new RuntimeException(e);
}
}
private boolean verifierDrivenRevocationListEquals(List<VerifierDrivenRevocationInToken> lhs,
List<VerifierDrivenRevocationInPolicy> rhs) {
if (lhs.size() != rhs.size()) {
logger.warning("Incorrect size of verifier driven revocation list");
return false;
}
Iterator<VerifierDrivenRevocationInPolicy> rhsIter = rhs.iterator();
for (VerifierDrivenRevocationInToken lhsPred : lhs) {
VerifierDrivenRevocationInPolicy rhsPred = rhsIter.next();
if (!verifierDrivenRevocationEquals(lhsPred, rhsPred)) {
logger.warning("List of verifier driven revocation are not equal.");
return false;
}
}
return true;
}
private boolean verifierDrivenRevocationEquals(VerifierDrivenRevocationInToken lhs,
VerifierDrivenRevocationInPolicy rhs) {
// We don't compare the revocation parameters
if (!attributesInRevocationEquals(lhs.getAttribute(), rhs.getAttribute())) {
logger.warning("List of attributes in verifier driven revocation are not equal.");
return false;
}
return true;
}
private boolean attributesInRevocationEquals(List<AttributeInRevocation> lhs,
List<AttributeInRevocation> rhs) {
if (lhs.size() != rhs.size()) {
logger.warning("Incorrect size of verifier driven revocation attribute list");
return false;
}
Iterator<AttributeInRevocation> rhsIter = rhs.iterator();
for (AttributeInRevocation lhsPred : lhs) {
AttributeInRevocation rhsPred = rhsIter.next();
if (!attributeInRevocationEquals(lhsPred, rhsPred)) {
logger.warning("Attribute in verifier driven revocation are not equal.");
return false;
}
}
return true;
}
private boolean attributeInRevocationEquals(AttributeInRevocation lhs, AttributeInRevocation rhs) {
if (!lhs.getAttributeType().equals(rhs.getAttributeType())) {
logger.warning("AttributeType are not equal.");
return false;
}
if (!lhs.getCredentialAlias().equals(rhs.getCredentialAlias())) {
logger.warning("CredentialAlias are not equal.");
return false;
}
return true;
}
private boolean attributesEquals(List<AttributeInToken> lhs, List<AttributeInPolicy> rhs) {
if (lhs.size() != rhs.size()) {
logger.warning("Incorrect number of attributes.");
return false;
}
// Attributes must be in the same order
Iterator<AttributeInToken> lhsIter = lhs.iterator();
Iterator<AttributeInPolicy> rhsIter = rhs.iterator();
while (lhsIter.hasNext() && rhsIter.hasNext()) {
AttributeInToken lhsAtt = lhsIter.next();
AttributeInPolicy rhsAtt = rhsIter.next();
if (!attributeEquals(lhsAtt, rhsAtt)) {
logger.warning("Different attribute.");
return false;
}
}
return true;
}
private boolean attributeEquals(AttributeInToken lhs, AttributeInPolicy rhs) {
if (!lhs.getAttributeType().equals(rhs.getAttributeType())) {
logger.warning("Different attribute type.");
return false;
}
if (!myequals(lhs.getDataHandlingPolicy(), rhs.getDataHandlingPolicy())) {
logger.warning("Different data handling policy.");
return false;
}
if (!myequals(lhs.getInspectionGrounds(), rhs.getInspectionGrounds())) {
logger.warning("Different Inspection grounds.");
return false;
}
if (rhs.getInspectorAlternatives() != null) {
if (!rhs.getInspectorAlternatives().getInspectorPublicKeyUID().contains(lhs.getInspectorPublicKeyUID())) {
logger.warning("Inspector not among alternatives.");
return false;
}
} else {
// Expect that the attribute is revealed
if (lhs.getAttributeValue() == null) {
logger.warning("Attribute value must be revealed");
return false;
}
}
return true;
}
private boolean issuerAmongAlternatives(List<IssuerParametersUID> lhsList, URI rhsIssuerParams,
URI rhsRevocationInfo) {
for (IssuerParametersUID lhsElement : lhsList) {
if (lhsElement.getValue().equals(rhsIssuerParams)
&& myequals(lhsElement.getRevocationInformationUID(), rhsRevocationInfo)) {
return true;
}
}
return false;
}
private boolean pseudonymEquals(PseudonymInToken lhs, PseudonymInPolicy pseudonymInPolicy) {
if (lhs == null && pseudonymInPolicy == null) {
return true;
} else if (lhs == null && pseudonymInPolicy != null) {
logger.warning("Missing pseudonym.");
return false;
} else if (lhs != null && pseudonymInPolicy == null) {
logger.warning("Should not contain pseudonym.");
return false;
} else if (!lhs.getScope().equals(pseudonymInPolicy.getScope())) {
logger.warning("Different scopes");
return false;
} else if(pseudonymInPolicy.getPseudonymValue() != null && !Arrays.equals(pseudonymInPolicy.getPseudonymValue(), lhs.getPseudonymValue())) {
// No check if pseudonymInPolicy does not specify a value
logger.warning("Incorrect pseudonym value");
return false;
}
// Skipping isEstablished, since the pseudonym in PresentationToken doesn't set this value
else if (lhs.isExclusive() != pseudonymInPolicy.isExclusive()) {
logger.warning("Different isExclusive");
return false;
} else if (!myequals(lhs.getAlias(), pseudonymInPolicy.getAlias())) {
logger.warning("Different Alias");
return false;
} else if (!myequals(lhs.getSameKeyBindingAs(), pseudonymInPolicy.getSameKeyBindingAs())) {
logger.warning("Different SameKeyBindingAs");
return false;
} else {
return true;
}
}
private boolean messageEquals(Message lhs, Message rhs) {
if (lhs == null && rhs == null) {
return true;
} else if (lhs == null && rhs != null) {
logger.warning("Missing message.");
return false;
} else if (lhs != null && rhs == null) {
logger.warning("Should not contain message.");
return false;
} else if (!myArrayEquals(lhs.getNonce(), rhs.getNonce())) {
logger.warning("Nonces are different: " + Arrays.toString(lhs.getNonce()) + ":" + Arrays.toString(rhs.getNonce()));
return false;
} else if (! friendlyEquals(lhs.getFriendlyPolicyName(), rhs.getFriendlyPolicyName())) {
logger.warning("Friendly policy name are different");
return false;
} else if (! friendlyEquals(lhs.getFriendlyPolicyDescription(), rhs.getFriendlyPolicyDescription())) {
logger.warning("Friendly policy description are different");
return false;
} else if (!verifierIdentityEquals(lhs.getVerifierIdentity(), rhs.getVerifierIdentity())) {
logger.warning("Verifier identity is different");
return false;
} else if (!applicationDataEquals(lhs.getApplicationData(), rhs.getApplicationData())) {
logger.warning("Application data is different");
return false;
} else {
return true;
}
}
private boolean friendlyEquals(List<FriendlyDescription> lhs,
List<FriendlyDescription> rhs) {
if (lhs == null && rhs == null) {
return true;
} else if (lhs == null || rhs == null) {
logger.warning("List not present in both lhs and rhs");
return false;
} else if (lhs.size() != rhs.size()) {
logger.warning("List size different");
return false;
}
Iterator<FriendlyDescription> li = lhs.iterator();
for(FriendlyDescription r: rhs) {
FriendlyDescription l = li.next();
if (!friendlyEquals(l, r)) {
return false;
}
}
return true;
}
private boolean friendlyEquals(FriendlyDescription l, FriendlyDescription r) {
if (! l.getLang().equals(r.getLang())) {
logger.warning("Incorrect language: l=" + l.getLang() + " r=" + r.getLang());
return false;
}
if( ! l.getValue().equals(r.getValue())) {
logger.warning("Incorrect value: l=" + l.getValue() + " r=" + r.getValue());
return false;
}
return true;
}
private boolean applicationDataEquals(ApplicationData lhs, ApplicationData rhs) {
if (lhs == null && rhs == null) {
return true;
}
if (lhs == null && rhs != null) {
logger.warning("Missing application data.");
return false;
}
if (lhs != null && rhs == null) {
logger.warning("Should not contain application data.");
return false;
}
// TODO(enr): Currently the only way to compare a sequence of xs:any
ObjectFactory of = new ObjectFactory();
String lhsXml, rhsXml;
try {
lhsXml = XmlUtils.toNormalizedXML(of.createApplicationData(lhs));
rhsXml = XmlUtils.toNormalizedXML(of.createApplicationData(rhs));
} catch (Exception e) {
String errorMessage = "Could not serialize Application data: " + e.getMessage();
logger.severe(errorMessage);
e.printStackTrace();
throw new RuntimeException(errorMessage);
}
if (!lhsXml.equals(rhsXml)) {
logger.warning("Application data are not equal.");
return false;
}
return true;
}
private boolean verifierIdentityEquals(VerifierIdentity lhs, VerifierIdentity rhs) {
if (lhs == null && rhs == null) {
return true;
}
if (lhs == null && rhs != null) {
logger.warning("Missing verifier identity.");
return false;
}
if (lhs != null && rhs == null) {
logger.warning("Should not contain verifier identity.");
return false;
}
// TODO(enr): Currently the only way to compare a sequence of xs:any
ObjectFactory of = new ObjectFactory();
String lhsXml, rhsXml;
try {
lhsXml = XmlUtils.toNormalizedXML(of.createVerifierIdentity(lhs));
rhsXml = XmlUtils.toNormalizedXML(of.createVerifierIdentity(rhs));
} catch (Exception e) {
String errorMessage = "Could not serialize Verifier identity: " + e.getMessage();
logger.severe(errorMessage);
e.printStackTrace();
throw new RuntimeException(errorMessage);
}
if (!lhsXml.equals(rhsXml)) {
logger.warning("Verifier identities are not equal.");
return false;
}
return true;
}
public URI getPolicyUri() {
return policy.getPolicyUID();
}
public List<ArrayList<MyCredentialDescription>> findCredentialAssignment(String username,
CredentialManager credentialManager, KeyManager km)
throws CredentialManagerException, KeyManagerException {
List<List<MyCredentialDescription>> credentialsForPolicy =
new ArrayList<List<MyCredentialDescription>>();
for (CredentialInPolicy c : policy.getCredential()) {
credentialsForPolicy.add(getCredentialsMatchingSpec(username, credentialManager, km, c));
}
LinkedList<ArrayList<MyCredentialDescription>> credentialAssignments = null;
try {
credentialAssignments =
new LinkedList<ArrayList<MyCredentialDescription>>(
CartesianProduct.cartesianProduct(credentialsForPolicy));
} catch (Exception e) {
logger.severe("Cannot create credentialAssignments: " + e.getMessage());
return null;
}
Map<URI, Integer> credentialAliasMap = reverseLookupTable(getCredentialAliasList());
filterPredicates(credentialAssignments, credentialAliasMap, policy.getAttributePredicate());
return credentialAssignments;
}
public List<ArrayList<PseudonymWithMetadata>> findPseudonymAssignment(
List<List<PseudonymWithMetadata>> pseudonymChoice,
List<MyCredentialDescription> credAssign) {
List<ArrayList<PseudonymWithMetadata>> pseudonymAssignment = null;
try {
pseudonymAssignment = new LinkedList<ArrayList<PseudonymWithMetadata>>(
CartesianProduct.cartesianProduct(pseudonymChoice));
} catch (Exception e) {
logger.severe("Cannot create credentialAssignments: " + e.getMessage());
return null;
}
return pseudonymAssignment;
}
public boolean filterSecrets(List<ArrayList<PseudonymWithMetadata>> pseudonymAssignment,
List<MyCredentialDescription> credAssign) {
// Create map associating credential alias with secret URI
Map<URI, URI> secretAssignmentCred = new HashMap<URI, URI>();
{
Iterator<CredentialInPolicy> cipi = policy.getCredential().iterator();
for(MyCredentialDescription mycd: credAssign) {
CredentialInPolicy cip = cipi.next();
if (cip.getAlias() != null) {
if (secretAssignmentCred.containsKey(cip.getAlias())) {
throw new RuntimeException("Duplicate alias in Policy (cred) " + cip.getAlias());
}
secretAssignmentCred.put(cip.getAlias(), mycd.getSecretReference());
}
}
}
Iterator<ArrayList<PseudonymWithMetadata>> pwmli = pseudonymAssignment.iterator();
pseudonymloop:
while(pwmli.hasNext()) {
List<PseudonymWithMetadata> pwml = pwmli.next();
// Create map associating cred+nym alias with secret URI
Map<URI, URI> secretAssignment = new HashMap<URI, URI>(secretAssignmentCred);
{
Iterator<PseudonymInPolicy> psipi = policy.getPseudonym().iterator();
for(PseudonymWithMetadata pwm: pwml) {
PseudonymInPolicy pip = psipi.next();
if (pip.getAlias() != null) {
if (secretAssignment.containsKey(pip.getAlias())) {
throw new RuntimeException("Duplicate alias in Policy (nym) " + pip.getAlias());
}
secretAssignment.put(pip.getAlias(), pwm.getPseudonym().getSecretReference());
}
}
}
// Check if credentials has same secrets as...
{
Iterator<CredentialInPolicy> cipi = policy.getCredential().iterator();
for(MyCredentialDescription mycd: credAssign) {
CredentialInPolicy cip = cipi.next();
if (cip.getSameKeyBindingAs() != null) {
URI secretOfOther = secretAssignment.get(cip.getSameKeyBindingAs());
if (secretOfOther == null) {
throw new RuntimeException("Alias referenced by SameKeyBindingAs (cred) not found");
}
if (! secretOfOther.equals(mycd.getSecretReference())) {
pwmli.remove();
continue pseudonymloop;
}
}
}
}
// Check if credentials has same secrets as...
{
Iterator<PseudonymInPolicy> psipi = policy.getPseudonym().iterator();
for(PseudonymWithMetadata pwm: pwml) {
PseudonymInPolicy pip = psipi.next();
if (pip.getSameKeyBindingAs() != null) {
URI secretOfOther = secretAssignment.get(pip.getSameKeyBindingAs());
if (secretOfOther == null) {
throw new RuntimeException("Alias referenced by SameKeyBindingAs (nym) not found");
}
if (! secretOfOther.equals(pwm.getPseudonym().getSecretReference())) {
pwmli.remove();
continue pseudonymloop;
}
}
}
}
}
return pseudonymAssignment.size() > 0;
}
private void filterPredicates(
LinkedList<ArrayList<MyCredentialDescription>> credentialAssignments,
Map<URI, Integer> credentialAliasList, List<AttributePredicate> attributePredicates) {
Iterator<ArrayList<MyCredentialDescription>> iter = credentialAssignments.iterator();
while (iter.hasNext()) {
ArrayList<MyCredentialDescription> candidateAssignment = iter.next();
if (!satisfiesPredicate(candidateAssignment, credentialAliasList, attributePredicates)) {
iter.remove();
// logger.info("Removed " + candidateAssignment + " (predicate)");
}
}
}
private boolean satisfiesPredicate(ArrayList<MyCredentialDescription> candidateAssignment,
Map<URI, Integer> credentialAliasList, List<AttributePredicate> attributePredicates) {
for (AttributePredicate predicate : attributePredicates) {
URI function = predicate.getFunction();
List<MyAttributeValue> arguments = new ArrayList<MyAttributeValue>();
for (Object param : predicate.getAttributeOrConstantValue()) {
if (param instanceof AttributePredicate.Attribute) {
AttributePredicate.Attribute attParam = (AttributePredicate.Attribute) param;
URI credentialAlias = attParam.getCredentialAlias();
Integer credentialAliasIndex = credentialAliasList.get(credentialAlias);
if (credentialAliasIndex == null) {
logger.severe("Unknown credential alias: '" + credentialAlias + "'");
return false;
}
MyCredentialDescription credentialContainingAttribute =
candidateAssignment.get(credentialAliasIndex);
URI attributeType = attParam.getAttributeType();
MyAttributeValue value = credentialContainingAttribute.getAttributeValue(attributeType);
if (value == null) {
logger.severe("Unknown attribute type: '" + attributeType + "' for credential alias: '"
+ credentialAlias + "'" );
return false;
}
arguments.add(value);
} else {
MyAttributeValue constant =
MyAttributeValueFactory.parseValueFromFunction(function, param);
arguments.add(constant);
}
}
if (!MyAttributeValueFactory.evaulateFunction(function, arguments)) {
return false;
}
}
return true;
}
private LinkedList<MyCredentialDescription> getCredentialsMatchingSpec(String username,
CredentialManager credentialManager, KeyManager km, CredentialInPolicy c)
throws CredentialManagerException, KeyManagerException {
List<URI> credentialSpecs = c.getCredentialSpecAlternatives().getCredentialSpecUID();
List<URI> issuerParameters = new ArrayList<URI>();
for (IssuerParametersUID ipu : c.getIssuerAlternatives().getIssuerParametersUID()) {
issuerParameters.add(ipu.getValue());
}
List<CredentialDescription> credDescMatchingIssuer =
credentialManager.getCredentialDescription(username, issuerParameters, credentialSpecs);
LinkedList<MyCredentialDescription> candidateCredentials =
new LinkedList<MyCredentialDescription>();
for (CredentialDescription cd : credDescMatchingIssuer) {
if(!cd.isRevokedByIssuer()) {
candidateCredentials.add(new MyCredentialDescription(cd, km));
}
}
return candidateCredentials;
}
private <T> Map<T, Integer> reverseLookupTable(List<T> list) {
Map<T, Integer> reverseLookupMap = new HashMap<T, Integer>();
Integer i = Integer.valueOf(0);
for (T element : list) {
reverseLookupMap.put(element, i);
i++;
}
return reverseLookupMap;
}
public PresentationTokenDescription generateTokenDescription(
ArrayList<MyCredentialDescription> assignment, ContextGenerator contextGenerator) {
List<URI> credentialAliasList = getCredentialAliasList();
ObjectFactory of = new ObjectFactory();
PresentationTokenDescription ptd = of.createPresentationTokenDescription();
for (AttributePredicate pred : policy.getAttributePredicate()) {
ptd.getAttributePredicate().add(pred);
}
populateVerifierDrivenRevocation(ptd);
populateCredentialsInTokenDescription(ptd, assignment, credentialAliasList);
ptd.setMessage(policy.getMessage());
ptd.setPolicyUID(policy.getPolicyUID());
ptd.setUsesSimpleProof(policy.isAllowSimpleProof() && checkIfSimpleProofAdmissible());
for (PseudonymInPolicy policyPseudonym : policy.getPseudonym()) {
PseudonymInToken pseudonym = of.createPseudonymInToken();
ptd.getPseudonym().add(pseudonym);
pseudonym.setAlias(policyPseudonym.getAlias());
pseudonym.setExclusive(policyPseudonym.isExclusive());
pseudonym.setScope(policyPseudonym.getScope());
pseudonym.setSameKeyBindingAs(policyPseudonym.getSameKeyBindingAs());
// Pseudonym value will be filled out later
pseudonym.setPseudonymValue(null);
}
ptd.setTokenUID(contextGenerator.getUniqueContext(URI.create("abc4t://token")));
return ptd;
}
static final Set<URI> admissiblePredicatesForSimpleProof = new HashSet<URI>();
static {
admissiblePredicatesForSimpleProof.add(URI.create("urn:oasis:names:tc:xacml:1.0:function:boolean-equal"));
admissiblePredicatesForSimpleProof.add(URI.create("urn:oasis:names:tc:xacml:1.0:function:date-equal"));
admissiblePredicatesForSimpleProof.add(URI.create("urn:oasis:names:tc:xacml:1.0:function:integer-equal"));
admissiblePredicatesForSimpleProof.add(URI.create("urn:oasis:names:tc:xacml:1.0:function:date-equal"));
admissiblePredicatesForSimpleProof.add(URI.create("urn:oasis:names:tc:xacml:1.0:function:time-equal"));
admissiblePredicatesForSimpleProof.add(URI.create("urn:oasis:names:tc:xacml:1.0:function:dateTime-equal"));
admissiblePredicatesForSimpleProof.add(URI.create("urn:oasis:names:tc:xacml:1.0:function:anyURI-equal"));
}
private boolean checkIfSimpleProofAdmissible() {
if(policy.getPseudonym().size() != 0) {
logger.warning("Policy has pseudonyms: simple proofs not admissible.");
return false;
}
if(policy.getCredential().size() != 1) {
logger.warning("Policy has not exactly 1 credential: simple proofs not admissible.");
return false;
}
for(AttributeInPolicy a: policy.getCredential().get(0).getDisclosedAttribute()) {
if(a.getInspectorAlternatives() != null) {
logger.warning("Policy has inspectors: simple proofs not admissible.");
return false;
}
}
if(policy.getVerifierDrivenRevocation().size() != 0) {
logger.warning("Policy has verifier driven revocation: simple proofs not admissible.");
return false;
}
for(AttributePredicate a: policy.getAttributePredicate()) {
if(! admissiblePredicatesForSimpleProof.contains(a.getFunction())) {
logger.warning("Policy has attribute predicate not admissible for simple proofs.");
return false;
}
}
return true;
}
private void populateVerifierDrivenRevocation(PresentationTokenDescription ptd) {
ObjectFactory of = new ObjectFactory();
for (VerifierDrivenRevocationInPolicy vdrp : policy.getVerifierDrivenRevocation()) {
VerifierDrivenRevocationInToken vdrt = of.createVerifierDrivenRevocationInToken();
ptd.getVerifierDrivenRevocation().add(vdrt);
// TODO(enr): Where do we get that revocation information UID from?
vdrt.setRevocationInformationUID(URI.create("no:revocation:information:yet"));
vdrt.getAttribute().addAll(vdrp.getAttribute());
}
}
private List<URI> getCredentialAliasList() {
List<URI> credentialAliasList = new ArrayList<URI>();
for (CredentialInPolicy c : policy.getCredential()) {
credentialAliasList.add(c.getAlias());
}
return credentialAliasList;
}
private void populateCredentialsInTokenDescription(PresentationTokenDescription output,
ArrayList<MyCredentialDescription> assignments, List<URI> credentialAliasList) {
ObjectFactory of = new ObjectFactory();
Iterator<URI> aliases = credentialAliasList.iterator();
Iterator<CredentialInPolicy> credsInPolicy = policy.getCredential().iterator();
for (MyCredentialDescription myCredDesc : assignments) {
CredentialInPolicy credInPolicy = credsInPolicy.next();
URI alias = aliases.next();
CredentialInToken c = of.createCredentialInToken();
CredentialDescription credDesc = myCredDesc.getCredentialDescription();
c.setAlias(alias);
myCredDesc.populateDisclosedAttributes(c, credInPolicy);
c.setCredentialSpecUID(credDesc.getCredentialSpecificationUID());
c.setIssuerParametersUID(credDesc.getIssuerParametersUID());
IssuerParametersUID ipu =
locateIssuerParameterOrThrow(credInPolicy, credDesc.getIssuerParametersUID());
c.setRevocationInformationUID(ipu.getRevocationInformationUID());
c.setSameKeyBindingAs(credInPolicy.getSameKeyBindingAs());
output.getCredential().add(c);
}
}
private IssuerParametersUID locateIssuerParameterOrThrow(CredentialInPolicy credInPolicy, URI rhs) {
// TODO(enr): Linear search... surely we can do better
for (IssuerParametersUID ipu : credInPolicy.getIssuerAlternatives().getIssuerParametersUID()) {
if (ipu.getValue().equals(rhs)) {
return ipu;
}
}
String errorMessage = "Cannot find IssuerParameters '" + rhs + "' in CredentialInPolicy.";
logger.severe(errorMessage);
throw new RuntimeException(errorMessage);
}
public List<List<MyInspectableAttribute>> computeInspectorChoice(KeyManager keyManager) {
List<List<MyInspectableAttribute>> ret = new ArrayList<List<MyInspectableAttribute>>();
int credentialId = -1;
for (CredentialInPolicy cip : policy.getCredential()) {
credentialId++;
for (AttributeInPolicy aip : cip.getDisclosedAttribute()) {
if (aip.getInspectorAlternatives()!=null) {
List<MyInspectableAttribute> inspectorAlternative = new ArrayList<MyInspectableAttribute>();
for (URI inspectorUri: aip.getInspectorAlternatives().getInspectorPublicKeyUID()) {
InspectorPublicKey ipk = null;
try {
ipk = keyManager.getInspectorPublicKey(inspectorUri);
} catch(Exception e) {
throw new RuntimeException(e);
}
if (ipk != null) {
inspectorAlternative.add(new MyInspectableAttribute(ipk, credentialId, aip.getAttributeType(), aip.getDataHandlingPolicy(), aip.getInspectionGrounds()));
} else {
logger.severe("Could not find inspector with public key " + inspectorUri +
". Removing him from alternatives.");
}
}
if (inspectorAlternative.size() == 0) {
logger.severe("Could not find any inspectors for disclosed attribute " +
aip.getAttributeType() + ". Removing policy alternative.");
return null;
}
ret.add(inspectorAlternative);
}
}
}
return ret;
}
public List<List<PseudonymWithMetadata>> computePseudonymChoice(String username,
CredentialManager credentialManager, ContextGenerator contextGenerator,
EvidenceGenerationOrchestration evidenceOrchestration) throws CryptoEngineException {
try {
List<SecretDescription> secrets = credentialManager.listSecrets(username);
List<List<PseudonymWithMetadata>> ret = new ArrayList<List<PseudonymWithMetadata>>();
for (PseudonymInPolicy pseudonym : policy.getPseudonym()) {
String scope = pseudonym.getScope();
boolean canCreateNew = !pseudonym.isEstablished();
if(!pseudonym.isEstablished() && !pseudonym.isExclusive() && pseudonym.getPseudonymValue() != null) {
throw new RuntimeException("Cannot specify a value for pseudonym if it is not established and not exclusive");
}
List<PseudonymWithMetadata> list =
credentialManager.listPseudonyms(username, scope, pseudonym.isExclusive());
list = filterPseudonymsByValue(list, pseudonym.getPseudonymValue());
if (list.size() > 0 && pseudonym.isExclusive()) {
// Can't create a new pseudonym if we are asked a scope exclusive one, and we have one
// already
canCreateNew = false;
}
if (canCreateNew) {
for (SecretDescription sd: secrets) {
ObjectFactory of = new ObjectFactory();
PseudonymWithMetadata newPseudonym = of.createPseudonymWithMetadata();
newPseudonym.setPseudonym(of.createPseudonym());
// Secret reference
newPseudonym.getPseudonym().setSecretReference(sd.getSecretUID());
// Will be filled out by crypto engine
newPseudonym.setCryptoParams(null);
// Metadata example
if(! pseudonym.isExclusive()) {
Map<String, String> trans = new HashMap<String, String>();
//trans.put("en", "New pseudonym with scope %s and secret %s.");
//trans.put("el", "\u039d\u03ad\u03bf \u03c8\u03b5\u03c5\u03b4\u03ce\u03bd\u03c5\u03bc\u03bf \u03bc\u03b5 \u03c4\u03bf\u03bd \u03c4\u03bf\u03bc\u03ad\u03b1 %s \u03ba\u03b1\u03b9 \u03bc\u03c5\u03c3\u03c4\u03b9\u03ba\u03ae %s.");
//trans.put("sv", "Ny pseudonym med dom\u00e4n %s och hemliga %s.");
trans.put("en", "New Pseudonym %s");
trans.put("el", "\u039d\u03ad\u03bf \u03a8\u03b5\u03c5\u03b4\u03ce\u03bd\u03c5\u03bc\u03bf %s");
trans.put("sv", "Ny Pseudonym %s");
String now = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss").format(new Date());
newPseudonym.setPseudonymMetadata(of.createPseudonymMetadata());
for(String lang: trans.keySet()) {
FriendlyDescription desc = of.createFriendlyDescription();
desc.setLang(lang);
desc.setValue(String.format(trans.get(lang), now));
// System.err.println(desc.getValue());
newPseudonym.getPseudonymMetadata().getFriendlyPseudonymDescription().add(desc);
}
} else {
newPseudonym.setPseudonymMetadata(of.createPseudonymMetadata());
FriendlyDescription fd = AbstractPseudonymSerializer.generateFriendlyDescription(scope);
newPseudonym.getPseudonymMetadata().getFriendlyPseudonymDescription().add(fd);
}
newPseudonym.getPseudonym().setScope(scope);
URI prefix = URI.create("abc4t://nym");
if (pseudonym.isExclusive()) {
prefix = URI.create("abc4t://dnym");
}
newPseudonym.getPseudonym().setPseudonymUID(
contextGenerator.getUniqueContext(prefix));
newPseudonym.getPseudonym().setExclusive(pseudonym.isExclusive());
if(pseudonym.getPseudonymValue() != null && pseudonym.isExclusive()) {
// Ignore scope exclusive pseudonyms where the pseudonym value doesn't match
PseudonymWithMetadata newpwm = evidenceOrchestration.createPseudonym(username, newPseudonym.getPseudonym().getPseudonymUID(), pseudonym.getScope(), pseudonym.isExclusive(), sd.getSecretUID());
if(!Arrays.equals(newpwm.getPseudonym().getPseudonymValue(), pseudonym.getPseudonymValue())) {
continue;
}
}
// Will be filled out by Crypto Engine
newPseudonym.getPseudonym().setPseudonymValue(null);
list.add(newPseudonym);
}
}
ret.add(new ArrayList<PseudonymWithMetadata>(list));
}
return ret;
} catch (CredentialManagerException e) {
throw new RuntimeException(e);
}
}
private List<PseudonymWithMetadata> filterPseudonymsByValue(
List<PseudonymWithMetadata> list, byte[] pseudonymValue) {
if(pseudonymValue == null) {
return list;
}
List<PseudonymWithMetadata> ret = new ArrayList<PseudonymWithMetadata>();
for(PseudonymWithMetadata pwm: list) {
if(Arrays.equals(pwm.getPseudonym().getPseudonymValue(), pseudonymValue)) {
ret.add(pwm);
}
}
return ret;
}
public Message getMessage() {
return this.policy.getMessage();
}
private boolean checkEstablishedPseudonyms(PresentationTokenDescription td,
TokenManager tk) {
Iterator<PseudonymInToken> piti = td.getPseudonym().iterator();
for(PseudonymInPolicy pip: policy.getPseudonym()) {
PseudonymInToken pit = piti.next();
if (pip.isEstablished()) {
if (! tk.isEstablishedPseudonym(pit)) {
logger.severe("The pseudonym " + pip.getAlias() + " is not established.");
return false;
}
}
}
return true;
}
public void updateIssuerToRevocationInformationUidMap(Map<URI, URI> toUpdate) {
for(CredentialInPolicy cip: policy.getCredential()) {
for(IssuerParametersUID ipu: cip.getIssuerAlternatives().getIssuerParametersUID()) {
URI issuer = ipu.getValue();
URI riu = ipu.getRevocationInformationUID();
if (riu != null) {
URI oldRiu = toUpdate.get(issuer);
if(oldRiu == null || oldRiu.equals(riu)) {
toUpdate.put(issuer, riu);
} else {
throw new RuntimeException("There are two different revocationInformationUids for the same issuer.");
}
}
}
}
}
}