diff --git a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java
index 4cb8eadcb256c..46748166060b4 100644
--- a/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java
+++ b/src/java.xml.crypto/share/classes/javax/xml/crypto/dsig/dom/DOMSignContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,10 @@
import javax.xml.crypto.dsig.XMLSignContext;
import javax.xml.crypto.dsig.XMLSignature;
import java.security.Key;
+import java.security.PrivateKey;
+import java.security.SecureRandom;
+import java.security.Signature;
+
import org.w3c.dom.Node;
/**
@@ -46,6 +50,17 @@
* (for example, you should not use the same DOMSignContext
* instance to sign two different {@link XMLSignature} objects).
*
+ * @implNote
+ * The JDK implementation supports the following property that can be set
+ * using the {@link #setProperty setProperty} method.
+ *
+ * jdk.xmldsig.SecureRandom
: value must be a
+ * {@link SecureRandom}. If specified, this object will be
+ * used to initialize the underlying {@code Signature} during signing
+ * using the {@link Signature#initSign(PrivateKey, SecureRandom)}
+ * method.
+ *
+ *
* @author Sean Mullan
* @author JSR 105 Expert Group
* @since 1.6
diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java
index c131ab689d735..253bca298badc 100644
--- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java
+++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMRSAPSSSignatureMethod.java
@@ -21,7 +21,7 @@
* under the License.
*/
/*
- * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
*/
package org.jcp.xml.dsig.internal.dom;
@@ -33,6 +33,7 @@
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.AlgorithmParameterSpec;
@@ -59,6 +60,7 @@
public abstract class DOMRSAPSSSignatureMethod extends AbstractDOMSignatureMethod {
private static final String DOM_SIGNATURE_PROVIDER = "org.jcp.xml.dsig.internal.dom.SignatureProvider";
+ private static final String DOM_SIGNATURE_RANDOM = "jdk.xmldsig.SecureRandom";
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DOMRSAPSSSignatureMethod.class);
@@ -324,7 +326,12 @@ byte[] sign(Key key, SignedInfo si, XMLSignContext context)
throw new XMLSignatureException(nsae);
}
}
- signature.initSign((PrivateKey)key);
+ SecureRandom sr = (SecureRandom)context.getProperty(DOM_SIGNATURE_RANDOM);
+ if (sr != null) {
+ signature.initSign((PrivateKey) key, sr);
+ } else {
+ signature.initSign((PrivateKey) key);
+ }
try {
signature.setParameter(spec);
} catch (InvalidAlgorithmParameterException e) {
diff --git a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java
index 6523b93935da8..984b2aa9cf49e 100644
--- a/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java
+++ b/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMSignatureMethod.java
@@ -21,7 +21,7 @@
* under the License.
*/
/*
- * Copyright (c) 2005, 2021, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2005, 2025, Oracle and/or its affiliates. All rights reserved.
*/
package org.jcp.xml.dsig.internal.dom;
@@ -33,6 +33,7 @@
import java.security.PrivateKey;
import java.security.Provider;
import java.security.PublicKey;
+import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.DSAKey;
@@ -64,6 +65,7 @@
public abstract class DOMSignatureMethod extends AbstractDOMSignatureMethod {
private static final String DOM_SIGNATURE_PROVIDER = "org.jcp.xml.dsig.internal.dom.SignatureProvider";
+ private static final String DOM_SIGNATURE_RANDOM = "jdk.xmldsig.SecureRandom";
private static final com.sun.org.slf4j.internal.Logger LOG =
com.sun.org.slf4j.internal.LoggerFactory.getLogger(DOMSignatureMethod.class);
@@ -390,7 +392,12 @@ byte[] sign(Key key, SignedInfo si, XMLSignContext context)
throw new XMLSignatureException(nsae);
}
}
- signature.initSign((PrivateKey)key);
+ SecureRandom sr = (SecureRandom)context.getProperty(DOM_SIGNATURE_RANDOM);
+ if (sr != null) {
+ signature.initSign((PrivateKey) key, sr);
+ } else {
+ signature.initSign((PrivateKey) key);
+ }
LOG.debug("Signature provider: {}", signature.getProvider());
LOG.debug("JCA Algorithm: {}", getJCAAlgorithm());
diff --git a/test/jdk/javax/xml/crypto/dsig/Properties.java b/test/jdk/javax/xml/crypto/dsig/Properties.java
new file mode 100644
index 0000000000000..6e257823011b9
--- /dev/null
+++ b/test/jdk/javax/xml/crypto/dsig/Properties.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+import jdk.test.lib.Asserts;
+import jdk.test.lib.security.SeededSecureRandom;
+import jdk.test.lib.security.XMLUtils;
+import org.w3c.dom.Document;
+
+import javax.xml.crypto.dsig.XMLSignatureException;
+import java.security.KeyPairGenerator;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import java.util.Base64;
+
+/**
+ * @test
+ * @bug 8359395
+ * @summary ensure properties are used
+ * @library /test/lib
+ */
+public class Properties {
+
+ private static final String DOM_SIGNATURE_PROVIDER
+ = "org.jcp.xml.dsig.internal.dom.SignatureProvider";
+ private static final String DOM_SIGNATURE_RANDOM
+ = "jdk.xmldsig.SecureRandom";
+
+ public static void main(String[] args) throws Exception {
+ // Do not test on RSA. It's always deterministic.
+ test("EC");
+ test("RSASSA-PSS");
+ }
+
+ static void test(String alg) throws Exception {
+ var kp = KeyPairGenerator.getInstance(alg).generateKeyPair();
+ var signer = XMLUtils.signer(kp.getPrivate(), kp.getPublic());
+
+ var n1 = getSignature(signer.sign("hello")); // random one
+ var n2 = getSignature(signer.sign("hello")); // another random one
+
+ signer.prop(DOM_SIGNATURE_RANDOM, new SeededSecureRandom(1L));
+ var s1 = getSignature(signer.sign("hello")); // deterministic one
+
+ signer.prop(DOM_SIGNATURE_RANDOM, new SeededSecureRandom(1L));
+ var s1again = getSignature(signer.sign("hello")); // deterministic one repeated
+
+ signer.prop(DOM_SIGNATURE_RANDOM, new SeededSecureRandom(2L));
+ var s2 = getSignature(signer.sign("hello")); // deterministic two
+
+ Asserts.assertEqualsByteArray(s1, s1again);
+ assertsAllDifferent(n1, n2, s1, s2);
+
+ signer.prop(DOM_SIGNATURE_PROVIDER, Security.getProvider("SunJCE"));
+ // Asserts throwing XMLSignatureException with cause NoSuchAlgorithmException
+ Asserts.assertEquals(
+ Asserts.assertThrows(XMLSignatureException.class,
+ () -> signer.sign("hello")).getCause().getClass(),
+ NoSuchAlgorithmException.class);
+ }
+
+ private static void assertsAllDifferent(byte[]... inputs) {
+ for (var a : inputs) {
+ for (var b : inputs) {
+ if (a != b) {
+ Asserts.assertNotEqualsByteArray(a, b);
+ }
+ }
+ }
+ }
+
+ static byte[] getSignature(Document doc) {
+ for (var n = doc.getDocumentElement().getFirstChild();
+ n != null; n = n.getNextSibling()) {
+ if ("SignatureValue".equals(n.getLocalName())) {
+ return Base64.getMimeDecoder().decode(n.getTextContent());
+ }
+ }
+ throw new IllegalArgumentException("Not found");
+ }
+}