This is an automated email from the ASF dual-hosted git repository.

coheigea pushed a commit to branch 3_0_x-fixes
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git


The following commit(s) were added to refs/heads/3_0_x-fixes by this push:
     new f0e726731 WSS-717 Encryption with key identifier X509SKI (#438)
f0e726731 is described below

commit f0e72673123d5cb94692955bb9aa73dc16193d0a
Author: Robin K. <139983390+koes-sop...@users.noreply.github.com>
AuthorDate: Wed Feb 5 12:06:11 2025 +0100

    WSS-717 Encryption with key identifier X509SKI (#438)
    
    * WSS-717 Added support for encryption with key identifier type X509_SKI - 
a base64 encoded plain X.509 SKI extension value wrapped in X509Data as a 
direct child of a KeyInfo element
    
    * Merge and compatibility adjustments after #418
    
    * Enhanced unit test for X509SKI
    
    * Unused import
    
    * DOMX509SKI: restore "final" for instance variable skiBytes
    
    * Restored the "else" clause in 
WSSecEncryptedKey#createEncryptedKeyElement, added a new "else if" clause for 
X509SKI, extracted the KeyInfo generation into a new method as it is needed for 
X509SKI and the "old" cases
---
 .../org/apache/wss4j/common/token/DOMX509Data.java | 10 ++++
 .../org/apache/wss4j/common/token/DOMX509SKI.java  | 17 +++++++
 .../java/org/apache/wss4j/dom/WSConstants.java     |  6 +++
 .../wss4j/dom/message/WSSecEncryptedKey.java       | 57 ++++++++++++++--------
 .../apache/wss4j/dom/message/EncryptionTest.java   | 46 +++++++++++++++++
 5 files changed, 115 insertions(+), 21 deletions(-)

diff --git 
a/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509Data.java
 
b/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509Data.java
index d21f00c7b..93a934d25 100644
--- 
a/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509Data.java
+++ 
b/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509Data.java
@@ -58,6 +58,16 @@ public final class DOMX509Data {
         element.appendChild(domIssuerSerial.getElement());
     }
 
+    /**
+     * Constructor.
+     */
+    public DOMX509Data(Document doc, DOMX509SKI x509SKI) {
+        element =
+                doc.createElementNS(WSS4JConstants.SIG_NS, "ds:X509Data");
+
+        element.appendChild(x509SKI.getElement());
+    }
+
     /**
      * Return true if this X509Data element contains a X509IssuerSerial element
      */
diff --git 
a/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509SKI.java
 
b/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509SKI.java
index cf05cf486..b9bfc2476 100644
--- 
a/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509SKI.java
+++ 
b/ws-security-common/src/main/java/org/apache/wss4j/common/token/DOMX509SKI.java
@@ -19,10 +19,15 @@
 
 package org.apache.wss4j.common.token;
 
+import org.apache.wss4j.common.WSS4JConstants;
+import org.apache.wss4j.common.crypto.BouncyCastleUtils;
 import org.apache.wss4j.common.util.DOM2Writer;
+import org.w3c.dom.Document;
 import org.apache.wss4j.common.util.XMLUtils;
 import org.w3c.dom.Element;
 
+import java.security.cert.X509Certificate;
+
 
 /**
  * An X.509 SKI token.
@@ -31,6 +36,18 @@ public final class DOMX509SKI {
     private final Element element;
     private final byte[] skiBytes;
 
+    /**
+     * Constructor.
+     */
+    public DOMX509SKI(Document doc, X509Certificate remoteCertificate) {
+        skiBytes = 
BouncyCastleUtils.getSubjectKeyIdentifierBytes(remoteCertificate);
+
+        element = doc.createElementNS(WSS4JConstants.SIG_NS, "ds:X509SKI");
+        element.setTextContent(
+                org.apache.xml.security.utils.XMLUtils.encodeToString(skiBytes
+        ));
+    }
+
     /**
      * Constructor.
      */
diff --git 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSConstants.java 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSConstants.java
index 34f92ef71..fcaa1dc95 100644
--- a/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSConstants.java
+++ b/ws-security-dom/src/main/java/org/apache/wss4j/dom/WSConstants.java
@@ -341,6 +341,12 @@ public final class WSConstants extends WSS4JConstants {
      */
     public static final int ISSUER_SERIAL_QUOTE_FORMAT = 15;
 
+    /**
+     * <code>X509_SKI</code> is used to set a ds:X509Data/ds:KeyValue element 
to refer to
+     * the base64 encoded plain value of a X509 V.3 SubjectKeyIdentifier 
extension
+     */
+    public static final int X509_SKI = 16;
+
     /*
      * The following values are bits that can be combined to form a set.
      * Be careful when adding new constants.
diff --git 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecEncryptedKey.java
 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecEncryptedKey.java
index 204c311a4..77e8c80d1 100644
--- 
a/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecEncryptedKey.java
+++ 
b/ws-security-dom/src/main/java/org/apache/wss4j/dom/message/WSSecEncryptedKey.java
@@ -260,10 +260,10 @@ public class WSSecEncryptedKey extends WSSecBase {
     }
 
     /**
-     * Now we need to setup the EncryptedKey header block:
+     * Now we need to set up the EncryptedKey header block:
      *  1) create a EncryptedKey element and set a wsu:Id for it
-     *  2) Generate ds:KeyInfo element, this wraps the 
wsse:SecurityTokenReference
-     *  3) Create and set up the SecurityTokenReference according to the 
keyIdentifier parameter
+     *  2) Generate ds:KeyInfo element
+     *  3) Create and set up the ds:KeyInfo child element - this can either be 
a SecurityTokenReference or X509Data/X509SKI
      *  4) Create the CipherValue element structure and insert the encrypted 
session key
      */
     protected void createEncryptedKeyElement(X509Certificate remoteCert, 
Crypto crypto, KeyAgreementParameters dhSpec)
@@ -276,6 +276,12 @@ public class WSSecEncryptedKey extends WSSecBase {
 
         if (customEKKeyInfoElement != null) {
             
encryptedKeyElement.appendChild(getDocument().adoptNode(customEKKeyInfoElement));
+        } else if (keyIdentifierType == WSConstants.X509_SKI) {
+            DOMX509SKI x509SKI = new DOMX509SKI(getDocument(), remoteCert);
+            DOMX509Data x509Data = new DOMX509Data(getDocument(), x509SKI);
+
+            Element keyInfoElement = 
createKeyInfoElement(x509Data.getElement(), dhSpec);
+            encryptedKeyElement.appendChild(keyInfoElement);
         } else {
             SecurityTokenReference secToken = new 
SecurityTokenReference(getDocument());
             if (addWSUNamespace) {
@@ -378,29 +384,38 @@ public class WSSecEncryptedKey extends WSSecBase {
                 throw new 
WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId",
                                               new Object[] 
{keyIdentifierType});
             }
-            Element keyInfoElement =
+
+            Element keyInfoElement = 
createKeyInfoElement(secToken.getElement(), dhSpec);
+            encryptedKeyElement.appendChild(keyInfoElement);
+        }
+    }
+
+    /**
+     * Method builds and returns a ds:KeyInfo element wrapping the provided 
child element.
+     */
+    private Element createKeyInfoElement(Element childElement, 
KeyAgreementParameters dhSpec) throws WSSecurityException {
+        Element keyInfoElement =
                 getDocument().createElementNS(
-                    WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + 
WSConstants.KEYINFO_LN
+                        WSConstants.SIG_NS, WSConstants.SIG_PREFIX + ":" + 
WSConstants.KEYINFO_LN
                 );
-            keyInfoElement.setAttributeNS(
+        keyInfoElement.setAttributeNS(
                 WSConstants.XMLNS_NS, "xmlns:" + WSConstants.SIG_PREFIX, 
WSConstants.SIG_NS
-            );
-            if (isKeyAgreementConfigured(keyAgreementMethod)) {
-                try {
-                    AgreementMethodImpl agreementMethod = new 
AgreementMethodImpl(getDocument(), dhSpec);
-                    
agreementMethod.getRecipientKeyInfo().addUnknownElement(secToken.getElement());
-                    Element agreementMethodElement = 
agreementMethod.getElement();
-                    keyInfoElement.appendChild(agreementMethodElement);
-                } catch (XMLSecurityException e) {
-                    throw new 
WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId",
-                            new Object[] {keyIdentifierType});
-                }
-
-            } else {
-                keyInfoElement.appendChild(secToken.getElement());
+        );
+        if (isKeyAgreementConfigured(keyAgreementMethod)) {
+            try {
+                AgreementMethodImpl agreementMethod = new 
AgreementMethodImpl(getDocument(), dhSpec);
+                
agreementMethod.getRecipientKeyInfo().addUnknownElement(childElement);
+                Element agreementMethodElement = agreementMethod.getElement();
+                keyInfoElement.appendChild(agreementMethodElement);
+            } catch (XMLSecurityException e) {
+                throw new 
WSSecurityException(WSSecurityException.ErrorCode.FAILURE, "unsupportedKeyId",
+                                              new Object[] 
{keyIdentifierType});
             }
-            encryptedKeyElement.appendChild(keyInfoElement);
+
+        } else {
+            keyInfoElement.appendChild(childElement);
         }
+        return keyInfoElement;
     }
 
     /**
diff --git 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
index cbcf1ada0..6e44a441b 100644
--- 
a/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
+++ 
b/ws-security-dom/src/test/java/org/apache/wss4j/dom/message/EncryptionTest.java
@@ -575,6 +575,52 @@ public class EncryptionTest {
         verify(encryptedDoc, encCrypto, keystoreCallbackHandler);
     }
 
+
+    /**
+     * Test that encrypts a WS-Security envelope.
+     * The test uses the X509_SKI key identifier type.
+     */
+    @Test
+    public void testEncryptionX509SKI() throws Exception {
+        Crypto encCrypto = CryptoFactory.getInstance("wss-ecdh.properties");
+
+        Document doc = SOAPUtil.toSOAPPart(SOAPUtil.SAMPLE_SOAP_MSG);
+        WSSecHeader secHeader = new WSSecHeader(doc);
+        secHeader.insertSecurityHeader();
+
+        WSSecEncrypt builder = new WSSecEncrypt(secHeader);
+        builder.setUserInfo("secp256r1");
+        builder.setKeyEncAlgo(WSConstants.KEYWRAP_AES128);
+        builder.setKeyAgreementMethod(WSConstants.AGREEMENT_METHOD_ECDH_ES);
+        builder.setKeyDerivationMethod(WSConstants.KEYDERIVATION_CONCATKDF);
+        builder.setDigestAlgorithm(WSS4JConstants.SHA256);
+        builder.setKeyIdentifierType(WSConstants.X509_SKI);
+
+        LOG.info("Before Encrypting X509SKI");
+        KeyGenerator keyGen = 
KeyUtils.getKeyGenerator(WSConstants.AES_128_GCM);
+        SecretKey symmetricKey = keyGen.generateKey();
+
+        Document encryptedDoc = builder.build(encCrypto, symmetricKey);
+        LOG.info("After Encrypting X509SKI");
+
+        String outputString =
+                XMLUtils.prettyDocumentToString(encryptedDoc);
+
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Encrypted message with X509SKI:");
+            LOG.debug(outputString);
+        }
+
+        assertTrue(outputString.contains("X509Data"));
+        assertTrue(outputString.contains("X509SKI"));
+
+        RequestData data = new RequestData();
+        data.setCallbackHandler(keystoreCallbackHandler);
+        data.setDecCrypto(encCrypto);
+        data.setIgnoredBSPRules(Collections.singletonList(BSPRule.R5426));
+        new WSSecurityEngine().processSecurityHeader(encryptedDoc, data);
+    }
+
     /**
      * Test that encrypts using EncryptedKeySHA1, where it uses a symmetric 
key, rather than a
      * generated session key which is then encrypted using a public key.

Reply via email to