//* 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.services; import java.io.FileNotFoundException; import java.net.URI; import java.util.List; import java.util.logging.Logger; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.xml.bind.JAXBElement; import org.w3c.dom.Element; import eu.abc4trust.guice.ProductionModuleFactory.CryptoEngine; import eu.abc4trust.keyManager.KeyManager; import eu.abc4trust.ri.servicehelper.issuer.IssuanceHelper; import eu.abc4trust.util.CryptoUriUtil; import eu.abc4trust.xml.ABCEBoolean; import eu.abc4trust.xml.Attribute; import eu.abc4trust.xml.CredentialSpecification; import eu.abc4trust.xml.CredentialTemplate; import eu.abc4trust.xml.FriendlyDescription; import eu.abc4trust.xml.IssuanceLogEntry; import eu.abc4trust.xml.IssuanceMessage; import eu.abc4trust.xml.IssuanceMessageAndBoolean; import eu.abc4trust.xml.IssuancePolicy; import eu.abc4trust.xml.IssuancePolicyAndAttributes; import eu.abc4trust.xml.IssuerParameters; import eu.abc4trust.xml.IssuerParametersInput; import eu.abc4trust.xml.Message; import eu.abc4trust.xml.ObjectFactory; import eu.abc4trust.xml.PresentationPolicy; import eu.abc4trust.xml.RevocationAuthorityParameters; import eu.abc4trust.xml.SystemParameters; @Path("/issuer") public class IssuanceService { private static final URI CRYPTOMECHANISM_URI_IDEMIX = URI .create("urn:abc4trust:1.0:algorithm:idemix"); private static final URI CRYPTOMECHANISM_URI_UPROVE = URI .create("urn:abc4trust:1.0:algorithm:uprove"); private final ObjectFactory of = new ObjectFactory(); private final Logger log = Logger .getLogger(IssuanceService.class.getName()); private final String issuerParamsPrefix = "issuer_resources/"; private final String fileStoragePrefix = "issuer_storage/"; public IssuanceService() { } private void initializeHelper() { this.log.info("IssuanceService loading..."); try { if (IssuanceHelper.isInit()) { this.log.info("IssuanceHelper is initialized"); IssuanceHelper.verifyFiles(false, this.fileStoragePrefix); } else { this.log.info("Initializing IssuanceHelper..."); IssuanceHelper.initInstanceForService(this.issuerParamsPrefix, this.fileStoragePrefix); this.log.info("IssuanceHelper is initialized"); } } catch (Exception e) { System.out.println("Create Domain FAILED " + e); e.printStackTrace(); } } /** * This method generates a fresh set of system parameters for the given * security level, expressed as the bitlength of a symmetric key with * comparable security, and cryptographic mechanism. Issuers can generate * their own system parameters, but can also reuse system parameters * generated by a different entity. More typically, a central party (e.g., a * standardization body) will generate and publish system parameters for a * number of different key lengths that will be used by many Issuers. * Security levels 80 and 128 MUST be supported; other values MAY also be * supported. * * Currently, the supported mechanism URIs are * urn:abc4trust:1.0:algorithm:idemix for Identity Mixer and * urn:abc4trust:1.0:algorithm:uprove for U-Prove. * * This method will overwrite any existing system parameters. * * @param securityLevel * @param cryptoMechanism * @return * @throws Exception */ @POST() @Path("/setupSystemParameters/") @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) @Produces(MediaType.TEXT_XML) public JAXBElement<SystemParameters> setupSystemParameters( @QueryParam("keyLength") int keyLength) throws Exception { this.log.info("IssuanceService - setupSystemParameters " + keyLength); this.initializeHelper(); IssuanceHelper issuanceHelper = IssuanceHelper.getInstance(); SystemParameters systemParameters = issuanceHelper.createNewSystemParametersKeylength(keyLength); return this.of.createSystemParameters(systemParameters); } private CryptoEngine parseCryptoMechanism(URI cryptoMechanism) { if (cryptoMechanism == null) { throw new RuntimeException("No cryptographic mechanism specified"); } if (cryptoMechanism.equals(CRYPTOMECHANISM_URI_IDEMIX)) { return CryptoEngine.IDEMIX; } if (cryptoMechanism.equals(CRYPTOMECHANISM_URI_UPROVE)) { return CryptoEngine.UPROVE; } throw new IllegalArgumentException("Unkown crypto mechanism: \"" + cryptoMechanism + "\""); } // H2.1 Update(jdn): added crypto engine. /** * This method generates a fresh issuance key and the corresponding Issuer * parameters. The issuance key is stored in the Issuers key store, the * Issuer parameters are returned as output of the method. The input to this * method specify the credential specification credspec of the credentials * that will be issued with these parameters, the system parameters syspars, * the unique identifier uid of the generated parameters, the hash algorithm * identifier hash, and, optionally, the parameters identifier for any * Issuer-driven Revocation Authority. * * Currently, the only supported hash algorithm is SHA-256 with identifier * urn:abc4trust:1.0:hashalgorithm:sha-256. * * @return * @throws Exception */ /* * curl --header "Content-Type:application/xml" -X POST -d @credSpecAndSysParams.xml http://localhost:9500/abce-services/issuer/setupIssuerParameters/?cryptoEngine=IDEMIX\&issuerParametersUid=urn%3A%2F%2Ftest%2Ffoobar\&hash=urn:abc4trust:1.0:hashalgorithm:sha-256 */ @POST() @Path("/setupIssuerParameters/") @Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML}) @Produces(MediaType.TEXT_XML) public JAXBElement<IssuerParameters> setupIssuerParameters( IssuerParametersInput issuerParametersInput) throws Exception { this.log.info("IssuanceService - setupIssuerParameters "); CryptoEngine cryptoEngine = this .parseCryptoMechanism(issuerParametersInput.getAlgorithmID()); this.initializeHelper(); this.validateInput(issuerParametersInput); URI hashAlgorithm = issuerParametersInput.getHashAlgorithm(); this.loadCredentialSpecifications(); String systemAndIssuerParamsPrefix = Constants.ISSUER_RESOURCES_FOLDER + "/"; IssuanceHelper instance = IssuanceHelper.getInstance(); KeyManager keyManager = instance.keyManager; SystemParameters systemParameters = keyManager.getSystemParameters(); URI credentialSpecUid = issuerParametersInput.getCredentialSpecUID(); CredentialSpecification credspec = keyManager .getCredentialSpecification(credentialSpecUid); if (credspec == null) { throw new IllegalStateException( "Could not find credential specification \"" + credentialSpecUid + "\""); } URI issuerParametersUid = issuerParametersInput.getParametersUID(); URI hash = hashAlgorithm; URI revocationParametersUid = issuerParametersInput .getRevocationParametersUID(); List<FriendlyDescription> friendlyDescriptions = issuerParametersInput .getFriendlyIssuerDescription(); System.out.println("FriendlyIssuerDescription: " + friendlyDescriptions.size()); IssuerParameters issuerParameters = instance.setupIssuerParameters( cryptoEngine, credspec, systemParameters, issuerParametersUid, hash, revocationParametersUid, systemAndIssuerParamsPrefix, friendlyDescriptions); this.log.info("IssuanceService - issuerParameters generated"); // SystemParameters serializeSp = SystemParametersUtil // .serialize(systemParameters); // // issuerParameters.setSystemParameters(serializeSp); return this.of.createIssuerParameters(issuerParameters); } private void validateInput(IssuerParametersInput issuerParametersTemplate) { if (issuerParametersTemplate == null) { throw new IllegalArgumentException( "issuer paramters input is required"); } if (issuerParametersTemplate.getCredentialSpecUID() == null) { throw new IllegalArgumentException( "Credential specifation UID is required"); } if (issuerParametersTemplate.getParametersUID() == null) { throw new IllegalArgumentException( "Issuer parameters UID is required"); } if (issuerParametersTemplate.getAlgorithmID() == null) { throw new IllegalArgumentException( "Crypto Algorithm ID is required"); } if (issuerParametersTemplate.getHashAlgorithm() == null) { throw new IllegalArgumentException("Hash algorithm is required"); } if (!issuerParametersTemplate.getHashAlgorithm().equals( CryptoUriUtil.getHashSha256())) { throw new IllegalArgumentException("Unknown hashing algorithm"); } } /** * This method is invoked by the Issuer to initiate an issuance protocol * based on the given issuance policy ip and the list of attribute * type-value pairs atts to be embedded in the new credential. It returns an * IssuanceMessage that is to be sent to the User and fed to the * issuanceProtocolStep method on the Users side. The IssuanceMessage * contains a Context attribute that will be the same for all message * exchanges in this issuance protocol, to facilitate linking the different * flows of the protocol. * * In case of an issuance from scratch, i.e., for which the User does not * have to prove ownership of existing credentials or established * pseudonyms, the given issuance policy ip merely specifies the credential * specification and the issuer parameters for the credential to be issued. * In this case, the returned issuance message is the first message in the * actual cryptographic issuance protocol. * * In case of an advanced issuance, i.e., where the User has to prove * ownership of existing credentials or pseudonyms to carry over attributes, * a user secret, or a device secret, the returned IssuanceMessage is simply * a wrapper around the issuance policy ip with a fresh Context attribute. * The returned boolean indicates whether this is the last flow of the * issuance protocol. If the IssuanceMessage is not the final one, the * Issuer will subsequently invoke its issuanceProtocolStep method on the * next incoming IssuanceMessage from the User. The issuer also returns the * uid of the stored issuance log entry that contains an issuance token * together with the attribute values provided by the issuer to keep track * of the issued credentials. */ @POST() @Path("/initIssuanceProtocol/") @Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML}) @Produces(MediaType.TEXT_XML) public JAXBElement<IssuanceMessageAndBoolean> initIssuanceProtocol( JAXBElement<IssuancePolicyAndAttributes> rawIssuancePolicyAndAttributes) throws Exception { try{ this.log.info("IssuanceService - initIssuanceProtocol "); IssuancePolicyAndAttributes issuancePolicyAndAttributes = rawIssuancePolicyAndAttributes.getValue(); IssuancePolicy ip = issuancePolicyAndAttributes.getIssuancePolicy(); List<Attribute> attributes = issuancePolicyAndAttributes.getAttribute(); this.initializeHelper(); this.initIssuanceProtocolValidateInput(issuancePolicyAndAttributes); IssuanceHelper issuanceHelper = IssuanceHelper.getInstance(); this.loadCredentialSpecifications(); this.loadIssuerParameters(); IssuanceMessageAndBoolean issuanceMessageAndBoolean = issuanceHelper.initIssuanceProtocol(ip, attributes); return this.of .createIssuanceMessageAndBoolean(issuanceMessageAndBoolean); }catch(Exception e){ e.printStackTrace(); throw e; } } private void loadCredentialSpecifications() throws FileNotFoundException { IssuanceHelper issuanceHelper = IssuanceHelper.getInstance(); ServiceResourceStorage serviceResourceStorage = ServiceResourceStorage .getInstance(); String[] credSpecResourceList = serviceResourceStorage .loadCredentialSpecificationResourceList(); issuanceHelper.addCredentialSpecifications(credSpecResourceList); } private void loadIssuerParameters() throws FileNotFoundException { IssuanceHelper issuanceHelper = IssuanceHelper.getInstance(); ServiceResourceStorage serviceResourceStorage = ServiceResourceStorage .getInstance(); String[] issuerParametersResourceList = serviceResourceStorage .loadIssuerParametersResourceList(); issuanceHelper.addIssuerParameters(issuerParametersResourceList); } private void initIssuanceProtocolValidateInput( IssuancePolicyAndAttributes issuancePolicyAndAttributes) { if (issuancePolicyAndAttributes == null) { throw new IllegalArgumentException( "\"issuancePolicyAndAttributes\" is required."); } if (issuancePolicyAndAttributes.getIssuancePolicy() == null) { throw new IllegalArgumentException( "\"Issuance policy\" is required."); } if (issuancePolicyAndAttributes.getAttribute() == null) { throw new IllegalArgumentException("\"Attributes\" are required."); } } /** * This method performs one step in an interactive issuance protocol. On * input an incoming issuance message m received from the User, it returns * the outgoing issuance message that is to be sent back to the User, a * boolean indicating whether this is the last message in the protocol, and * the uid of the stored issuance log entry that contains an issuance token * together with the attribute values provided by the issuer to keep track * of the issued credentials. The Context attribute of the outgoing message * has the same value as that of the incoming message, allowing the Issuer * to link the different messages of this issuance protocol. */ @POST() @Path("/issuanceProtocolStep") @Consumes({MediaType.APPLICATION_XML, MediaType.TEXT_XML}) @Produces(MediaType.TEXT_XML) public JAXBElement<IssuanceMessageAndBoolean> issuanceProtocolStep( final JAXBElement<IssuanceMessage> rawIssuanceMessage) { IssuanceMessage issuanceMessage = rawIssuanceMessage.getValue(); this.log.info("IssuanceService - step - context : " + issuanceMessage.getContext()); this.initializeHelper(); IssuanceMessageAndBoolean response; try { response = IssuanceHelper.getInstance().issueStep(issuanceMessage); } catch (Exception e) { this.log.info("- got Exception from IssuaceHelper/ABCE Engine - processing IssuanceMessage from user..."); e.printStackTrace(); throw new IllegalStateException("Failed to proces IssuanceMessage from user"); } IssuanceMessage issuanceMessageFromResponce = response .getIssuanceMessage(); if (response.isLastMessage()) { this.log.info(" - last message for context : " + issuanceMessageFromResponce.getContext()); } else { this.log.info(" - more steps context : " + issuanceMessageFromResponce.getContext()); } return this.of.createIssuanceMessageAndBoolean(response); } /** * This method looks up an issuance log entry of previously issued * credentials that contains a verified issuance token together with the * attribute values provided by the issuer. The issuance log entry * identifier issuanceEntryUid is the identifier that was included in the * issuance token description that was returned when the token was verified. */ @GET() @Path("/getIssuanceLogEntry/") @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) @Produces(MediaType.TEXT_XML) public JAXBElement<IssuanceLogEntry> getIssuanceLogEntry( @QueryParam("issuanceEntryUid") URI issuanceEntryUid) throws Exception { this.log.info("IssuanceService - getIssuanceLogEntry: \"" + issuanceEntryUid + "\""); this.initializeHelper(); IssuanceLogEntry response; try { response = IssuanceHelper.getInstance().getIssuanceLogEntry(issuanceEntryUid); } catch (Exception e) { this.log.info("- got Exception from IssuaceHelper/ABCE Engine - processing IssuanceLogEntry from user..."); e.printStackTrace(); throw new IllegalStateException( "Failed to proces IssuanceLogEntry from user"); } return this.of.createIssuanceLogEntry(response); } @PUT() @Path("/storeCredentialSpecification/{credentialSpecifationUid}") @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) @Produces(MediaType.TEXT_XML) public JAXBElement<ABCEBoolean> storeCredentialSpecification( @PathParam("credentialSpecifationUid") URI credentialSpecifationUid, CredentialSpecification credSpec) { this.log.info("IssuanceService - storeCredentialSpecification: \"" + credentialSpecifationUid + "\""); try { this.initializeHelper(); KeyManager keyManager = IssuanceHelper.getInstance().keyManager; boolean r1 = keyManager.storeCredentialSpecification( credentialSpecifationUid, credSpec); ABCEBoolean createABCEBoolean = this.of.createABCEBoolean(); createABCEBoolean.setValue(r1); return this.of.createABCEBoolean(createABCEBoolean); } catch (Exception ex) { throw new WebApplicationException(ex, Response.Status.INTERNAL_SERVER_ERROR); } } @PUT() @Path("/storeIssuerParameters/{issuerParametersUid}") @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) @Produces(MediaType.TEXT_XML) public JAXBElement<ABCEBoolean> storeIssuerParameters( @PathParam("issuerParametersUid") URI issuerParametersUid, IssuerParameters issuerParameters) { this.log.info("IssuanceService - storeIssuerParameters "); this.log.info("IssuanceService - storeIssuerParameters - issuerParametersUid: " + issuerParametersUid + ", " + issuerParameters.getParametersUID()); try { KeyManager keyManager = IssuanceHelper.getInstance().keyManager; boolean r = keyManager.storeIssuerParameters(issuerParametersUid, issuerParameters); ABCEBoolean createABCEBoolean = this.of.createABCEBoolean(); createABCEBoolean.setValue(r); this.log.info("UserService - storeIssuerParameters - done "); return this.of.createABCEBoolean(createABCEBoolean); } catch (Exception ex) { throw new WebApplicationException(ex, Response.Status.INTERNAL_SERVER_ERROR); } } @PUT() @Path("/storeRevocationAuthorityParameters/{revocationAuthorityParametersUid}") @Consumes({ MediaType.APPLICATION_XML, MediaType.TEXT_XML }) @Produces(MediaType.TEXT_XML) public JAXBElement<ABCEBoolean> storeRevocationAuthorityParameters( @PathParam("revocationAuthorityParametersUid") URI revocationAuthorityParametersUid, RevocationAuthorityParameters revocationAuthorityParameters) { this.log.info("IssuanceService - storeRevocationAuthorityParameters: \"" + revocationAuthorityParameters + "\""); if (revocationAuthorityParameters.getParametersUID().compareTo( revocationAuthorityParametersUid) != 0) { throw new WebApplicationException(new RuntimeException( "Detected inconsistency in the revocation parameters UID found in the revocation parameters and the revocationAuthorityParametersUid"), Response.Status.INTERNAL_SERVER_ERROR); } try { KeyManager keyManager = IssuanceHelper.getInstance().keyManager; boolean r1 = keyManager.storeRevocationAuthorityParameters( revocationAuthorityParametersUid, revocationAuthorityParameters); ABCEBoolean createABCEBoolean = this.of.createABCEBoolean(); createABCEBoolean.setValue(r1); return this.of.createABCEBoolean(createABCEBoolean); } catch (Exception ex) { throw new WebApplicationException(ex, Response.Status.INTERNAL_SERVER_ERROR); } } @GET() @Path("/status") @Consumes({MediaType.TEXT_PLAIN}) public Response issuerStatus() { this.log.info("IssuanceService - status : running"); return Response.ok().build(); } }