package com.zenika.xml.signature; import com.google.common.base.Function; import com.google.common.collect.Lists; import javax.xml.crypto.dsig.*; import javax.xml.crypto.dsig.spec.*; import java.security.InvalidAlgorithmParameterException; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; /** * A builder for generating Reference node af an xml signature. */ public class ReferenceBuilder { private final SignedInfoBuilder signedInfoBuilder; private final XMLSignatureFactory xmlSignatureFactory; private List<Transform> transforms = new ArrayList<Transform>(); private DigestMethod digestMethod; private String uri = ""; public ReferenceBuilder(SignedInfoBuilder signedInfoBuilder) { this.signedInfoBuilder = signedInfoBuilder; this.xmlSignatureFactory = signedInfoBuilder.getXmlSignatureFactory(); } /** * Add a SHA256 digest transformation * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withSHA256Digest() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withDigest(DigestMethod.SHA256); } /** * Add a SHA1 digest transformation * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withSHA1Digest() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withDigest(DigestMethod.SHA1); } /** * Add a SHA512 digest transformation * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withSHA512Digest() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withDigest(DigestMethod.SHA512); } /** * Add a digest transformation using the given algorithm (W3C URI identification) * @param algorithm * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withDigest(String algorithm) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { digestMethod = xmlSignatureFactory.newDigestMethod(algorithm, null); return this; } /** * Add a base 64 transformation * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withBase64() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withTransformation(Transform.BASE64); } /** * Discard the signature containing this element from the digest calculation of this same element * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withEnvelopedTransformation() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withTransformation(Transform.ENVELOPED); } public ReferenceBuilder withXPath2(XPathType... xPaths) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withTransformation(Transform.XPATH2, new XPathFilter2ParameterSpec(Lists.newArrayList(xPaths))); } public ReferenceBuilder withXPath2(String... expressions) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { List xPaths = Lists.transform(Lists.newArrayList(expressions), new Function<String, Object>() { @Override public XPathType apply(String expression) { return new XPathType(expression, XPathType.Filter.INTERSECT); } }); return withTransformation(Transform.XPATH2, new XPathFilter2ParameterSpec(xPaths)); } public ReferenceBuilder withXPath(String expression) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withTransformation(Transform.XPATH, new XPathFilterParameterSpec(expression)); } /** * Add a transformation using the given algorithm (W3C URI identification) * @param algorithm * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withTransformation(String algorithm) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withTransformation(algorithm, null); } /** * Add a transformation using the given algorithm (W3C URI identification) * @param algorithm * @return * @throws InvalidAlgorithmParameterException * @throws NoSuchAlgorithmException */ public ReferenceBuilder withTransformation(String algorithm, TransformParameterSpec parameterSpec) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { transforms.add(xmlSignatureFactory.newTransform(algorithm, parameterSpec)); return this; } /** * Add an inclusive canonicalization * @return * @throws java.security.InvalidAlgorithmParameterException * @throws java.security.NoSuchAlgorithmException */ public ReferenceBuilder withInclusiveCanonicalization() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withCanonicalization(CanonicalizationMethod.INCLUSIVE); } /** * Add an exclusive canonicalization * @return * @throws java.security.InvalidAlgorithmParameterException * @throws java.security.NoSuchAlgorithmException */ public ReferenceBuilder withExclusiveCanonicalization() throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { return withCanonicalization(CanonicalizationMethod.EXCLUSIVE); } /** * Add a canonicalization according to the given algorithm. * @param algorithm * @return * @throws java.security.InvalidAlgorithmParameterException * @throws java.security.NoSuchAlgorithmException */ public ReferenceBuilder withCanonicalization(String algorithm) throws InvalidAlgorithmParameterException, NoSuchAlgorithmException { CanonicalizationMethod canonicalizationMethod = xmlSignatureFactory.newCanonicalizationMethod(algorithm, (C14NMethodParameterSpec) null); transforms.add(canonicalizationMethod); return this; } /** * Set the uri attribute of this reference * @param uri * @return */ public ReferenceBuilder withURI(String uri) { this.uri = uri; return this; } /** * Build the corresponding reference * @return */ protected Reference build() { return xmlSignatureFactory.newReference(uri, digestMethod, transforms, null, null); } /** * Build the corresponding reference and attached it to the XmlSignatureBuilder * @return */ public SignedInfoBuilder buildAndAttach() { return signedInfoBuilder.withReference(build()); } }