2727import java .security .PublicKey ;
2828import java .security .cert .X509Certificate ;
2929import java .security .spec .AlgorithmParameterSpec ;
30+ import java .util .ArrayList ;
31+ import java .util .List ;
32+ import java .util .Objects ;
3033
3134import javax .crypto .SecretKey ;
3235
3336import org .apache .xml .security .algorithms .SignatureAlgorithm ;
3437import org .apache .xml .security .c14n .Canonicalizer ;
3538import org .apache .xml .security .exceptions .XMLSecurityException ;
39+ import org .apache .xml .security .extension .SignatureProcessor ;
3640import org .apache .xml .security .keys .KeyInfo ;
3741import org .apache .xml .security .keys .content .X509Data ;
3842import org .apache .xml .security .transforms .Transforms ;
@@ -249,6 +253,10 @@ public final class XMLSignature extends SignatureElementProxy {
249253 private static final int MODE_VERIFY = 1 ;
250254 private int state = MODE_SIGN ;
251255
256+
257+ private final List <SignatureProcessor > preProcessors = new ArrayList <>();
258+ private final List <SignatureProcessor > postProcessors = new ArrayList <>();
259+
252260 /**
253261 * This creates a new <CODE>ds:Signature</CODE> Element and adds an empty
254262 * <CODE>ds:SignedInfo</CODE>.
@@ -631,6 +639,29 @@ public XMLSignature(Element element, String baseURI, boolean secureValidation, P
631639 this .state = MODE_VERIFY ;
632640 }
633641
642+
643+ /**
644+ * Registers a pre-processor that is invoked before digest values are computed.
645+ * Pre-processors run in registration order.
646+ *
647+ * @param processor the pre-processor to register; must not be {@code null}
648+ */
649+ public void addPreProcessor (SignatureProcessor processor ) {
650+ Objects .requireNonNull (processor , "processor" );
651+ preProcessors .add (processor );
652+ }
653+
654+ /**
655+ * Registers a post-processor that is invoked after the {@code ds:SignatureValue}
656+ * element has been populated. Post-processors run in registration order.
657+ *
658+ * @param processor the post-processor to register; must not be {@code null}
659+ */
660+ public void addPostProcessor (SignatureProcessor processor ) {
661+ Objects .requireNonNull (processor , "processor" );
662+ postProcessors .add (processor );
663+ }
664+
634665 /**
635666 * Sets the <code>Id</code> attribute
636667 *
@@ -690,6 +721,32 @@ private void setSignatureValueElement(byte[] bytes) {
690721 signatureValueElement .appendChild (t );
691722 }
692723
724+ /**
725+ * Sets an {@code Id} attribute on the {@code ds:SignatureValue} element so
726+ * it can be referenced from unsigned signature properties (e.g., XAdES-T).
727+ *
728+ * @param id the identifier value; {@code null} removes an existing attribute
729+ */
730+ public void setSignatureValueId (String id ) {
731+ if (id != null ) {
732+ signatureValueElement .setAttributeNS (null , Constants ._ATT_ID , id );
733+ signatureValueElement .setIdAttributeNS (null , Constants ._ATT_ID , true );
734+ } else {
735+ signatureValueElement .removeAttributeNS (null , Constants ._ATT_ID );
736+ }
737+ }
738+
739+ /**
740+ * Returns the {@code Id} attribute value of the {@code ds:SignatureValue}
741+ * element, or {@code null} if none has been set.
742+ *
743+ * @return the identifier, or {@code null}
744+ */
745+ public String getSignatureValueId () {
746+ String id = signatureValueElement .getAttributeNS (null , Constants ._ATT_ID );
747+ return id .isEmpty () ? null : id ;
748+ }
749+
693750 /**
694751 * Returns the KeyInfo child. If we are in signing mode and the KeyInfo
695752 * does not exist yet, it is created on demand and added to the Signature.
@@ -794,6 +851,17 @@ public void sign(Key signingKey) throws XMLSignatureException {
794851 );
795852 }
796853
854+
855+ // snapshot the lists so that concurrent registration during sign() cannot
856+ // cause ConcurrentModificationException or skip newly added processors
857+ List <SignatureProcessor > preSnapshot = List .copyOf (preProcessors );
858+ List <SignatureProcessor > postSnapshot = List .copyOf (postProcessors );
859+
860+ // invoke pre-processors before digests are computed
861+ for (SignatureProcessor processor : preSnapshot ) {
862+ processor .processSignature (this );
863+ }
864+
797865 //Create a SignatureAlgorithm object
798866 SignedInfo si = this .getSignedInfo ();
799867 SignatureAlgorithm sa = si .getSignatureAlgorithm ();
@@ -816,6 +884,11 @@ public void sign(Key signingKey) throws XMLSignatureException {
816884 } catch (XMLSecurityException | IOException ex ) {
817885 throw new XMLSignatureException (ex );
818886 }
887+
888+ // invoke post-processors after the signature value has been set
889+ for (SignatureProcessor processor : postSnapshot ) {
890+ processor .processSignature (this );
891+ }
819892 }
820893
821894 /**
0 commit comments