This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch 2_4_x-fixes
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git
The following commit(s) were added to refs/heads/2_4_x-fixes by this push:
new dcf0920af Only set trust validation for Signature when we have a
trusted source (#705)
dcf0920af is described below
commit dcf0920afc91ba1866c223d02a91dc565cf6f381
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Fri Sep 18 09:53:42 2026 +0100
Only set trust validation for Signature when we have a trusted source (#705)
---
.../wss4j/dom/engine/WSSecurityEngineResult.java | 9 ++++
.../wss4j/dom/processor/SignatureProcessor.java | 20 +++++--
.../apache/wss4j/dom/message/SignatureTest.java | 4 ++
.../wss4j/dom/message/SymmetricSignatureTest.java | 61 +++++++++++++++++++++-
.../wss4j/dom/saml/SignedSamlTokenHOKTest.java | 5 ++
5 files changed, 93 insertions(+), 6 deletions(-)
diff --git
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSecurityEngineResult.java
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSecurityEngineResult.java
index 552252865..08462f3ba 100644
---
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSecurityEngineResult.java
+++
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/engine/WSSecurityEngineResult.java
@@ -110,6 +110,15 @@ public class WSSecurityEngineResult extends
java.util.HashMap<String, Object> {
* and so this is not set. Note that this is set for the NoOpValidator if
it is
* configured.
*
+ * For a Signature result this tag is only set when a trust decision was
actually taken
+ * on the signing credential: either a Validator was invoked on it, or the
credential
+ * carries its own trust (for example the key of a signed holder-of-key
SAML assertion,
+ * or a previously validated BinarySecurityToken). It is deliberately NOT
set when the
+ * signature was verified with a symmetric key, because a symmetric key
carries no
+ * identity that a Validator could check. Such a signature establishes the
integrity of
+ * the signed parts, not the identity of the sender - see the
"False-friend properties"
+ * section of THREAT-MODEL.md.
+ *
* The value under this tag is a Boolean instance.
*/
public static final String TAG_VALIDATED_TOKEN = "validated-token";
diff --git
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java
index 4bde12efb..dee8a3c5c 100644
---
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java
+++
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/processor/SignatureProcessor.java
@@ -136,6 +136,11 @@ public class SignatureProcessor implements Processor {
REFERENCE_TYPE referenceType = null;
Credential credential = new Credential();
+ // Whether trust in the signing credential was actually established:
either a
+ // Validator ran on it, or the credential carries its own trust (a
signed
+ // holder-of-key SAML assertion, a previously validated BST). Only
then may the
+ // result advertise TAG_VALIDATED_TOKEN.
+ boolean trustEstablished = false;
Validator validator = data.getValidator(WSConstants.SIGNATURE);
if (keyInfoElement == null) {
certs = getDefaultCerts(data.getSigVerCrypto());
@@ -165,6 +170,7 @@ public class SignatureProcessor implements Processor {
principal = new PublicKeyPrincipalImpl(publicKey);
credential.setPrincipal(principal);
credential = validator.validate(credential, data);
+ trustEstablished = true;
}
} else {
STRParserParameters parameters = new STRParserParameters();
@@ -182,15 +188,17 @@ public class SignatureProcessor implements Processor {
secretKey = parserResult.getSecretKey();
referenceType = parserResult.getCertificatesReferenceType();
- boolean trusted = parserResult.isTrustedCredential();
- if (trusted) {
+ trustEstablished = parserResult.isTrustedCredential();
+ if (trustEstablished) {
LOG.debug("Direct Trust for SAML/BST credential");
}
- if (!trusted && (publicKey != null || certs != null) &&
validator != null) {
+ if (!trustEstablished && (publicKey != null || certs != null
&& certs.length > 0)
+ && validator != null) {
credential.setPublicKey(publicKey);
credential.setCertificates(certs);
credential.setPrincipal(principal);
credential = validator.validate(credential, data);
+ trustEstablished = true;
}
}
}
@@ -261,7 +269,11 @@ public class SignatureProcessor implements Processor {
result.put(WSSecurityEngineResult.TAG_PUBLIC_KEY, publicKey);
result.put(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE,
referenceType);
result.put(WSSecurityEngineResult.TAG_TOKEN_ELEMENT, elem);
- if (validator != null) {
+ // The mere presence of a registered Validator establishes nothing:
stamp the result
+ // as validated only when a trust decision was actually taken on this
credential.
+ // In particular a signature verified with a symmetric key is not
stamped, as a
+ // symmetric key carries no identity for a Validator to check.
+ if (validator != null && trustEstablished) {
result.put(WSSecurityEngineResult.TAG_VALIDATED_TOKEN,
Boolean.TRUE);
if (credential != null) {
result.put(WSSecurityEngineResult.TAG_SUBJECT,
credential.getSubject());
diff --git
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureTest.java
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureTest.java
index 865338c04..12d5cfb7d 100644
---
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureTest.java
+++
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SignatureTest.java
@@ -120,6 +120,10 @@ public class SignatureTest {
REFERENCE_TYPE referenceType =
(REFERENCE_TYPE)actionResult.get(WSSecurityEngineResult.TAG_X509_REFERENCE_TYPE);
assertTrue(referenceType == REFERENCE_TYPE.ISSUER_SERIAL);
+
+ // Trust in the signing certificate was established by the Signature
Validator
+
assertTrue((Boolean)actionResult.get(WSSecurityEngineResult.TAG_VALIDATED_TOKEN),
+ "An X.509 signature that passed trust validation must be reported
as validated");
}
@Test
diff --git
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SymmetricSignatureTest.java
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SymmetricSignatureTest.java
index 84819491d..bf4bbeccd 100644
---
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SymmetricSignatureTest.java
+++
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/SymmetricSignatureTest.java
@@ -37,6 +37,7 @@ import org.apache.wss4j.dom.common.SecretKeyCallbackHandler;
import org.apache.wss4j.dom.engine.WSSConfig;
import org.apache.wss4j.dom.engine.WSSecurityEngine;
+import org.apache.wss4j.dom.engine.WSSecurityEngineResult;
import org.apache.wss4j.common.crypto.Crypto;
import org.apache.wss4j.common.crypto.CryptoFactory;
import org.apache.wss4j.common.ext.WSPasswordCallback;
@@ -45,11 +46,16 @@ import org.apache.wss4j.common.util.XMLUtils;
import org.apache.wss4j.dom.handler.HandlerAction;
import org.apache.wss4j.dom.handler.RequestData;
import org.apache.wss4j.dom.handler.WSHandlerConstants;
+import org.apache.wss4j.dom.handler.WSHandlerResult;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.w3c.dom.Document;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
/**
* Test symmetric key signature created using an encrypted key
@@ -250,6 +256,55 @@ public class SymmetricSignatureTest implements
CallbackHandler {
}
+ /**
+ * A signature verified with a symmetric key that arrived in an
EncryptedKey establishes
+ * the integrity of the signed parts, but it does not authenticate the
sender: anybody
+ * holding this service's certificate can wrap a key of their choosing and
sign with it.
+ * No trust decision is taken on such a credential - a symmetric key
carries no identity
+ * for a Validator to check - so the result must not advertise itself as a
validated
+ * token, even though a Validator is registered for the Signature action
by default.
+ */
+ @Test
+ public void testSymmetricSignatureIsNotReportedAsValidated() throws
Exception {
+ Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+
+ WSSecHeader secHeader = new WSSecHeader(doc);
+ secHeader.insertSecurityHeader();
+
+ WSSecEncryptedKey encrKey = new WSSecEncryptedKey(secHeader);
+ encrKey.setKeyIdentifierType(WSConstants.ISSUER_SERIAL);
+ encrKey.setUserInfo("wss40", "security");
+
+ KeyGenerator keyGen = KeyUtils.getKeyGenerator(WSConstants.AES_192);
+ SecretKey symmetricKey = keyGen.generateKey();
+ encrKey.prepare(crypto, symmetricKey);
+
+ WSSecSignature sign = new WSSecSignature(secHeader);
+ sign.setKeyIdentifierType(WSConstants.CUSTOM_SYMM_SIGNING);
+ sign.setCustomTokenId(encrKey.getId());
+ sign.setSecretKey(symmetricKey.getEncoded());
+ sign.setSignatureAlgorithm(SignatureMethod.HMAC_SHA1);
+ sign.setCustomTokenValueType(WSConstants.WSS_ENC_KEY_VALUE_TYPE);
+
+ Document signedDoc = sign.build(crypto);
+ encrKey.prependToHeader();
+
+ WSHandlerResult results = verify(signedDoc);
+
+ WSSecurityEngineResult actionResult =
+ results.getActionResults().get(WSConstants.SIGN).get(0);
+ assertNotNull(actionResult);
+
+ // The signature was keyed by the symmetric key, not by a certificate
or public key
+ assertNotNull(actionResult.get(WSSecurityEngineResult.TAG_SECRET));
+
assertNull(actionResult.get(WSSecurityEngineResult.TAG_X509_CERTIFICATES));
+ assertNull(actionResult.get(WSSecurityEngineResult.TAG_PUBLIC_KEY));
+
+
assertFalse((Boolean)actionResult.get(WSSecurityEngineResult.TAG_VALIDATED_TOKEN),
+ "A signature keyed by an EncryptedKey secret must not be reported
as a "
+ + "validated token: no trust decision was taken on the key");
+ }
+
/**
* Verifies the soap envelope
* <p/>
@@ -257,14 +312,16 @@ public class SymmetricSignatureTest implements
CallbackHandler {
* @param doc
* @throws Exception Thrown when there is a problem in verification
*/
- private void verify(Document doc) throws Exception {
- secEngine.processSecurityHeader(doc, null, callbackHandler, null,
crypto);
+ private WSHandlerResult verify(Document doc) throws Exception {
+ WSHandlerResult results =
+ secEngine.processSecurityHeader(doc, null, callbackHandler, null,
crypto);
if (LOG.isDebugEnabled()) {
LOG.debug("Verfied and decrypted message:");
String outputString =
XMLUtils.prettyDocumentToString(doc);
LOG.debug(outputString);
}
+ return results;
}
public void handle(Callback[] callbacks)
diff --git
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java
index f556528d1..d7bb524ff 100644
---
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java
+++
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/saml/SignedSamlTokenHOKTest.java
@@ -177,6 +177,11 @@ public class SignedSamlTokenHOKTest {
refs = (List<WSDataRef>)
actionResult.get(WSSecurityEngineResult.TAG_DATA_REF_URIS);
assertTrue(refs.size() == 1);
+ // The key comes from a signed holder-of-key assertion, so the
credential carries its
+ // own trust and is reported as validated even though no separate
Validator call ran
+
assertTrue((Boolean)actionResult.get(WSSecurityEngineResult.TAG_VALIDATED_TOKEN),
+ "A signature keyed by a signed holder-of-key assertion must be
reported as validated");
+
wsDataRef = refs.get(0);
xpath = wsDataRef.getXpath();
assertEquals("/SOAP-ENV:Envelope/SOAP-ENV:Body", xpath);