You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by co...@apache.org on 2026/09/22 08:46:18 UTC
(ws-wss4j) 01/01: Finishing DER work
This is an automated email from the ASF dual-hosted git repository.
coheigea pushed a commit to branch coheigea/der-part3
in repository https://gitbox.apache.org/repos/asf/ws-wss4j.git
commit af9d682212137ef588f98ad8dbc4c6ed9ba6f5a1
Author: Colm O hEigeartaigh <co...@apache.org>
AuthorDate: Tue Sep 22 09:45:51 2026 +0100
Finishing DER work
---
src/site/asciidoc/wss4j40.adoc | 38 +++++++++---
.../wss4j/common/crypto/BouncyCastleUtils.java | 68 ++++++++++++++++++++++
...ierTest.java => X509KeyIdentifierUtilTest.java} | 31 ++++++++--
3 files changed, 125 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..f7966328d
--- /dev/null
+++ b/ws-security-common/src/main/java/org/apache/wss4j/common/crypto/BouncyCastleUtils.java
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ */
+@Deprecated(since = "4.0.2", forRemoval = true)
+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)}
+ */
+ @Deprecated(since = "4.0.2", forRemoval = true)
+ 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)}
+ */
+ @Deprecated(since = "4.0.2", forRemoval = true)
+ 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();