package won.protocol.message.processor.impl; import org.apache.jena.query.Dataset; import org.apache.jena.rdf.model.Model; import org.apache.jena.rdf.model.ModelFactory; import org.apache.jena.rdf.model.Resource; import won.cryptography.rdfsign.SignatureVerificationState; import won.cryptography.rdfsign.SigningStage; import won.cryptography.rdfsign.WonSigner; import won.cryptography.rdfsign.WonVerifier; import won.protocol.message.WonMessage; import won.protocol.message.WonSignatureData; import won.protocol.util.WonRdfUtils; import won.protocol.vocabulary.WONMSG; import java.security.PrivateKey; import java.security.PublicKey; import java.util.List; import java.util.Map; /** * User: ypanchenko * Date: 08.04.2015 */ public class WonMessageSignerVerifier { public static WonMessage sign(PrivateKey privateKey, PublicKey publicKey, String privateKeyUri, WonMessage message) throws Exception { Dataset msgDataset = message.getCompleteDataset(); SigningStage sigStage = new SigningStage(message); addUnreferencedSigReferences(msgDataset, sigStage); WonSigner signer = new WonSigner(msgDataset); signContents(msgDataset, sigStage, signer, privateKey, privateKeyUri, publicKey); signEnvelopes(msgDataset, sigStage, signer, privateKey, privateKeyUri, publicKey); return new WonMessage(msgDataset); } /** * If the provided signing stage has unsigned content graphs, sign them, add signature graphs * to the dataset, and add signatures to the envelope graph * that has contains envelope property referencing signed by that signature envelope graph * @param msgDataset * @param sigStage * @param signer * @param privateKey * @param privateKeyUri */ private static void signEnvelopes(final Dataset msgDataset, final SigningStage sigStage, final WonSigner signer, final PrivateKey privateKey, final String privateKeyUri, final PublicKey publicKey) throws Exception { List<String> envUris = sigStage.getUnsignedEnvUrisOrderedByContainment(); WonSignatureData wonSignatureData = null; String outerEnvUri = null; for (String envUri : sigStage.getUnsignedEnvUrisOrderedByContainment()) { if (wonSignatureData != null) { //this is the signature of the envelope we signed in the last iteration. //add it to the current one: addSignature(wonSignatureData, envUri, msgDataset, true); } wonSignatureData = signer.sign(privateKey, privateKeyUri, publicKey, envUri).get(0); outerEnvUri = envUri; } //this is the signature of the outermost envelopoe. put it in a new graph. msgDataset.addNamedModel(wonSignatureData.getSignatureUri(), ModelFactory.createDefaultModel()); addSignature(wonSignatureData, wonSignatureData.getSignatureUri(), msgDataset, false); } /** * Adds the signature to the specified graph. * @param sigData * @param graphUri * @param msgDataset * @param graphIsEnvelope if true, a msg:containsSignature property is added to the graph URI */ public static void addSignature(final WonSignatureData sigData, final String graphUri, final Dataset msgDataset, boolean graphIsEnvelope) { Model envelopeGraph = msgDataset.getNamedModel(graphUri); Resource envelopeResource = envelopeGraph.createResource(graphUri); Resource sigNode = envelopeGraph.createResource(sigData.getSignatureUri()); if (graphIsEnvelope) { //only connect envelope to signature. pure signature graphs are not connected this way. envelopeResource.addProperty(WONMSG.CONTAINS_SIGNATURE_PROPERTY, sigNode); } WonRdfUtils.SignatureUtils.addSignature(sigNode, sigData); } /** * If the provided signing stage has unsigned content graphs, sign them. * This adds the signature triples to the graph, add signature graphs * to the dataset, and add signature references of those signatures into the envelope graph * that has has content property referencing signed by that signature content graph * @param msgDataset * @param sigStage * @param signer * @param privateKey * @param privateKeyUri */ private static void signContents(final Dataset msgDataset, final SigningStage sigStage, final WonSigner signer, final PrivateKey privateKey, final String privateKeyUri, final PublicKey publicKey) throws Exception { List<WonSignatureData> sigRefs = signer.sign(privateKey, privateKeyUri, publicKey, sigStage.getUnsignedContentUris()); for (WonSignatureData sigRef : sigRefs) { String envUri = sigStage.getEnvelopeUriContainingContent(sigRef.getSignedGraphUri()); addSignature(sigRef, envUri, msgDataset,true); } } /** * If the provided signing stage has signature graphs that are not referenced from any envelope graphs, they * should be moved to the innermost not-signed envelope graph. The signature graph is to be deleted. * @param msgDataset * @param sigStage */ private static void addUnreferencedSigReferences(final Dataset msgDataset, final SigningStage sigStage) { String innemostUnsignedEnvUri = null; List<String> envUris = sigStage.getUnsignedEnvUrisOrderedByContainment(); if (envUris.isEmpty()) { return; } else { innemostUnsignedEnvUri = envUris.get(0); } WonSignatureData sigRef = sigStage.getOutermostSignature(); if (sigRef != null) { addSignature(sigRef, innemostUnsignedEnvUri, msgDataset,true); msgDataset.removeNamedModel(sigRef.getSignatureUri()); } } public static SignatureVerificationState verify(Map<String,PublicKey> keys, WonMessage message) throws Exception { Dataset dataset = message.getCompleteDataset(); WonVerifier verifier = new WonVerifier(dataset); verifier.verify(keys); return verifier.getVerificationResult(); } }