I need to sign XML in Java using Digital Signatures.
I have a key pair using signature algorithm RSASSA-PSS:
- SunRsaSign RSASSA-PSS private CRT key, 2048 bits
- Sun RSASSA-PSS public key, 2048 bits
See this code here from the OpenJDK test framework: https://github.com/openjdk/jdk/blob/master/test/lib/jdk/test/lib/security/XMLUtils.java
I’m using this utility to load the value:
Document doc = XMLUtils.string2doc("<a><b>Text</b>Raw</a>");
KeyPairGenerator instance = KeyPairGenerator.getInstance("RSASSA-PSS");
instance.initialize(2048);
KeyPair keyPair = instance.generateKeyPair();
PSSParameterSpec pspec = new PSSParameterSpec("SHA-384", "MGF1",
MGF1ParameterSpec.SHA512, 48, TRAILER_FIELD_BC);
Document signed = XMLUtils.signer(keyPair.getPrivate(), keyPair.getPublic())
.dm(DigestMethod.SHA384)
.sm(SignatureMethod.RSA_PSS, new RSAPSSParameterSpec(pspec))
.sign(doc);
System.out.println(XMLUtils.doc2string(signed));
System.out.println("Good? " + XMLUtils.validator().validate(signed, keyPair.getPublic()));
Unfortunately, this is not working
Exception in thread "main" java.security.KeyException: unsupported key algorithm: RSASSA-PSS
at java.xml.crypto/org.jcp.xml.dsig.internal.dom.DOMKeyInfoFactory.newKeyValue(DOMKeyInfoFactory.java:85)
because:
@Override
public KeyValue newKeyValue(PublicKey key) throws KeyException {
String algorithm = key.getAlgorithm();
if ("DSA".equals(algorithm)) {
return new DOMKeyValue.DSA((DSAPublicKey) key);
} else if ("RSA".equals(algorithm)) {
return new DOMKeyValue.RSA((RSAPublicKey) key);
} else if ("EC".equals(algorithm)) {
return new DOMKeyValue.EC((ECPublicKey) key);
} else {
throw new KeyException("unsupported key algorithm: " + algorithm);
}
}
It does not allow “RSASSA-PSS”.
It appears that if it were to be changed to:
} else if ("RSASSA-PSS".equals(algorithm) || "RSA".equals(algorithm)) {
return new DOMKeyValue.RSA((RSAPublicKey) key);
That appears to work? Or maybe it just looks like it’s working.
If this were changed KeyPairGenerator.getInstance("RSA")
that also works but then it wouldn’t be the algorithm that I need.
Here is a recent change to the JDK related to this:
https://github.com/openjdk/jdk/commit/8dbf7aa1#diff-fa025c90d09b130fe3a8da89b4ebc5fc3ec157ded54b858dabe8241d383880abR66
I notice that they convert the public key into a “self certificate” before using it in the XML signature.
X509Certificate cert = g.getSelfCertificate(new X500Name("CN=Me"), 100);
Those classes aren’t public to Java so I can’t use them. What is this doing exactly?
How do I properly sign an XML Signature using the RSASSA-PSS algorithm?