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

commit 6cce788bb7f589fe380ee9d87057ddcff6f06b3e
Author: Colm O hEigeartaigh <[email protected]>
AuthorDate: Tue Sep 22 10:01:43 2026 +0100

    Finishing DER work (#727)
---
 src/site/asciidoc/wss4j40.adoc                     | 38 ++++++++++---
 .../wss4j/common/crypto/BouncyCastleUtils.java     | 65 ++++++++++++++++++++++
 ...ierTest.java => X509KeyIdentifierUtilTest.java} | 31 +++++++++--
 3 files changed, 122 insertions(+), 12 deletions(-)

diff --git a/src/site/asciidoc/wss4j40.adoc b/src/site/asciidoc/wss4j40.adoc
index 9d25ca610..db0f3eaea 100644
--- a/src/site/asciidoc/wss4j40.adoc
+++ b/src/site/asciidoc/wss4j40.adoc
@@ -17,10 +17,34 @@
 // under the License.
 //
 
-=== Apache WSS4J 4.0.0 Migration Guide
+=== Apache WSS4J 4.0.x Migration Guide
 
-This section is a migration guide for helping Apache WSS4J 3.0.x users to 
migrate
-to the 4.0.x releases.
+This section covers changes within the 4.0.x releases that may affect existing
+code. Everything described below was introduced in 4.0.2.
+
+==== BouncyCastleUtils renamed to X509KeyIdentifierUtil
+
+`org.apache.wss4j.common.crypto.BouncyCastleUtils` is now
+`org.apache.wss4j.common.crypto.X509KeyIdentifierUtil`. The class no longer 
uses
+Bouncy Castle, so the old name was misleading. Its two methods,
+`getSubjectKeyIdentifierBytes` and `getAuthorityKeyIdentifierBytes`, keep their
+names and signatures.
+
+`BouncyCastleUtils` is retained as a deprecated class that delegates to the new
+one, so code written against 4.0.1 and earlier keeps working. It is marked for
+removal and will be dropped in a later release, so move to
+`X509KeyIdentifierUtil` when convenient.
+
+==== DOMX509SKI signals a malformed SubjectKeyIdentifier
+
+`org.apache.wss4j.common.token.DOMX509SKI`'s
+`DOMX509SKI(Document, X509Certificate)` constructor now declares
+`throws WSSecurityException`, raised when the certificate's 
SubjectKeyIdentifier
+extension is present but will not decode. Previously it threw an unchecked
+exception from a constructor with no throws clause.
+
+Code constructing this class directly must handle or propagate the exception.
+This is a source compatibility change only; existing compiled callers still 
link.
 
 ==== Stricter DER decoding of X.509 key identifiers
 
@@ -45,10 +69,10 @@ The encodings that change behaviour are:
   the `[0]` field.
 
 Such a certificate now causes an `IllegalArgumentException` from
-`BouncyCastleUtils.getSubjectKeyIdentifierBytes` and
-`BouncyCastleUtils.getAuthorityKeyIdentifierBytes`, and a `WSSecurityException`
-from `Crypto.getSKIBytesFromCert`. This surfaces when signing with an SKI key
-identifier (`DOMX509SKI`) and when establishing trust with `MerlinAKI`.
+`X509KeyIdentifierUtil.getSubjectKeyIdentifierBytes` and
+`X509KeyIdentifierUtil.getAuthorityKeyIdentifierBytes`, and a
+`WSSecurityException` from `Crypto.getSKIBytesFromCert`, from `DOMX509SKI` when
+signing with an SKI key identifier, and from `MerlinAKI` when establishing 
trust.
 
 If you hit this, the certificate is malformed and should be reissued. There is 
no
 configuration option to restore the previous tolerance.
diff --git 
a/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/BouncyCastleUtils.java
 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/BouncyCastleUtils.java
new file mode 100644
index 000000000..b498e17c6
--- /dev/null
+++ 
b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/BouncyCastleUtils.java
@@ -0,0 +1,65 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.wss4j.common.crypto;
+
+import java.security.cert.X509Certificate;
+
+/**
+ * Decodes the X.509 key identifier extensions.
+ *
+ * @deprecated the decoding no longer uses Bouncy Castle, so this class was 
renamed to
+ *             {@link X509KeyIdentifierUtil}. This name is retained for 
callers compiled against
+ *             4.0.1 and earlier, and delegates to the new class. Use
+ *             {@link X509KeyIdentifierUtil} instead.
+ */
+public final class BouncyCastleUtils {
+
+    private BouncyCastleUtils() {
+        // complete
+    }
+
+    /**
+     * Read the keyIdentifier of the AuthorityKeyIdentifier extension 
(2.5.29.35) of the
+     * given certificate.
+     *
+     * @param cert the certificate to read the AuthorityKeyIdentifier from.
+     * @return an empty array if the certificate has no AuthorityKeyIdentifier 
extension, null if
+     *         the extension is present but carries no keyIdentifier, 
otherwise the keyIdentifier.
+     * @throws IllegalArgumentException if the extension is present but is not 
valid DER.
+     * @deprecated use {@link 
X509KeyIdentifierUtil#getAuthorityKeyIdentifierBytes(X509Certificate)}
+     */
+    public static byte[] getAuthorityKeyIdentifierBytes(X509Certificate cert) {
+        return X509KeyIdentifierUtil.getAuthorityKeyIdentifierBytes(cert);
+    }
+
+    /**
+     * Read the SubjectKeyIdentifier extension (2.5.29.14) of the given 
certificate.
+     *
+     * @param cert the certificate to read the SubjectKeyIdentifier from.
+     * @return an empty array if the certificate has no SubjectKeyIdentifier 
extension, otherwise
+     *         the key identifier.
+     * @throws IllegalArgumentException if the extension is present but is not 
valid DER.
+     * @deprecated use {@link 
X509KeyIdentifierUtil#getSubjectKeyIdentifierBytes(X509Certificate)}
+     */
+    public static byte[] getSubjectKeyIdentifierBytes(X509Certificate cert) {
+        return X509KeyIdentifierUtil.getSubjectKeyIdentifierBytes(cert);
+    }
+
+}
diff --git 
a/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/AuthorityKeyIdentifierTest.java
 
b/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/X509KeyIdentifierUtilTest.java
similarity index 84%
rename from 
ws-security-common/src/test/java/org/apache/wss4j/common/crypto/AuthorityKeyIdentifierTest.java
rename to 
ws-security-common/src/test/java/org/apache/wss4j/common/crypto/X509KeyIdentifierUtilTest.java
index 95c6e1a37..f63bd31d0 100644
--- 
a/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/AuthorityKeyIdentifierTest.java
+++ 
b/ws-security-common/src/test/java/org/apache/wss4j/common/crypto/X509KeyIdentifierUtilTest.java
@@ -36,12 +36,12 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.junit.jupiter.api.Assertions.fail;
 
 /**
- * This is a test for extracting AuthorityKeyIdentifier/SubjectKeyIdentifier 
information from
- * certificates.
+ * This is a test for X509KeyIdentifierUtil, which extracts 
AuthorityKeyIdentifier and
+ * SubjectKeyIdentifier information from certificates.
  */
-public class AuthorityKeyIdentifierTest {
+public class X509KeyIdentifierUtilTest {
 
-    public AuthorityKeyIdentifierTest() {
+    public X509KeyIdentifierUtilTest() {
         WSProviderConfig.init();
     }
 
@@ -120,6 +120,27 @@ public class AuthorityKeyIdentifierTest {
         );
     }
 
+    /**
+     * BouncyCastleUtils is the pre-4.0.2 name of this class, kept as a 
deprecated delegate so
+     * that code written against 4.0.1 and earlier still compiles and behaves 
the same.
+     */
+    @Test
+    @SuppressWarnings("removal")
+    public void testDeprecatedBouncyCastleUtilsDelegates() throws Exception {
+        KeyStore keyStore = loadKeyStore("keys/wss40.jks", "security");
+        X509Certificate cert = 
(X509Certificate)keyStore.getCertificate("wss40");
+        assertNotNull(cert);
+
+        assertArrayEquals(
+            X509KeyIdentifierUtil.getAuthorityKeyIdentifierBytes(cert),
+            BouncyCastleUtils.getAuthorityKeyIdentifierBytes(cert)
+        );
+        assertArrayEquals(
+            X509KeyIdentifierUtil.getSubjectKeyIdentifierBytes(cert),
+            BouncyCastleUtils.getSubjectKeyIdentifierBytes(cert)
+        );
+    }
+
     @Test
     public void testMerlinAKI() throws Exception {
         // Load the keystore
@@ -153,7 +174,7 @@ public class AuthorityKeyIdentifierTest {
 
     private KeyStore loadKeyStore(String path, String password) throws 
Exception {
         KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
-        ClassLoader loader = 
Loader.getClassLoader(AuthorityKeyIdentifierTest.class);
+        ClassLoader loader = 
Loader.getClassLoader(X509KeyIdentifierUtilTest.class);
         InputStream input = Merlin.loadInputStream(loader, path);
         keyStore.load(input, password.toCharArray());
         input.close();

Reply via email to