From 3b20faae34218cdbb72008a3695f748b34cdff4a Mon Sep 17 00:00:00 2001
From: Maxim Thomas <maxim.thomas@gmail.com>
Date: Tue, 20 Oct 2026 06:45:08 +0000
Subject: [PATCH] [#1056] Add the RSASVE/KDF-SHA256/AESKWP key wrapping transformation for runtimes without RSA-OAEP (#1194)
---
opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java | 69 ++++++++++++++++++++++++++--------
1 files changed, 53 insertions(+), 16 deletions(-)
diff --git a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
index a2eb090..9c85361 100644
--- a/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
+++ b/opendj-server-legacy/src/main/java/org/opends/server/crypto/CryptoManagerImpl.java
@@ -26,6 +26,7 @@
import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
+import java.security.KeyPair;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
@@ -459,17 +460,25 @@
}
/**
- * Checks that this Java runtime provides the key wrapping transformation. Only a refusal here
- * names the key-wrapping-transformation property: the wrap which follows it also needs a MAC
- * key of the mac-algorithm property, and changing the key wrapping property does not help when
- * that is what the runtime refuses.
+ * Checks that this Java runtime provides the key wrapping transformation, or every algorithm the
+ * RSASVE scheme needs when the transformation names that scheme. Only a refusal here names the
+ * key-wrapping-transformation property: the wrap which follows it also needs a MAC key of the
+ * mac-algorithm property, and changing the key wrapping property does not help when that is what
+ * the runtime refuses.
*/
private static boolean isKeyWrappingTransformationSupported(
final String transformation, final List<LocalizableMessage> unacceptableReasons)
{
try
{
- Cipher.getInstance(transformation);
+ if (RsaSveKeyTransport.isScheme(transformation))
+ {
+ RsaSveKeyTransport.checkSupported();
+ }
+ else
+ {
+ Cipher.getInstance(transformation);
+ }
return true;
}
catch (GeneralSecurityException ex)
@@ -847,6 +856,9 @@
* wrappedKeyAlgorithm ::= e.g., DESede
* hexifiedwrappedKey ::= 0123456789abcdef01...
* </pre>
+ * The wrapping transformation is a transformation of the Java runtime, or
+ * RSASVE/KDF-SHA256/AESKWP, the scheme of {@link RsaSveKeyTransport}, whose
+ * wrapped key is the one {@link RsaSveKeyTransport#wrap} returns.
*
* @param wrappingKeyID The key identifier of the wrapping key. This
* parameter is the first field in the encoded value and identifies
@@ -915,10 +927,17 @@
= CertificateFactory.getInstance("X.509");
final Certificate certificate = cf.generateCertificate(
new ByteArrayInputStream(wrappingKeyCertificateData));
- final Cipher wrapper
- = Cipher.getInstance(wrappingTransformationName);
- wrapper.init(Cipher.WRAP_MODE, certificate);
- byte[] wrappedKey = wrapper.wrap(secretKey);
+ final byte[] wrappedKey;
+ if (RsaSveKeyTransport.isScheme(wrappingTransformationName)) {
+ wrappedKey = RsaSveKeyTransport.wrap(certificate,
+ secretKey, wrappingKeyID, secureRandom);
+ }
+ else {
+ final Cipher wrapper
+ = Cipher.getInstance(wrappingTransformationName);
+ wrapper.init(Cipher.WRAP_MODE, certificate);
+ wrappedKey = wrapper.wrap(secretKey);
+ }
wrappedKeyElement = StaticUtils.bytesToHexNoSpace(wrappedKey);
}
catch (GeneralSecurityException ex) {
@@ -938,6 +957,8 @@
* Takes an encoded ds-cfg-symmetric-key attribute value and the
* associated key algorithm name, and returns an initialized
* {@code java.security.Key} object.
+ * <p>
+ * Package private for testing.
* @param symmetricKeyAttribute The encoded
* ds-cfg-symmetric-key-attribute value.
* @return A SecretKey object instantiated with the key data,
@@ -946,7 +967,7 @@
* @throws CryptoManagerException If there is a problem decomposing
* the supplied attribute value or unwrapping the encoded key.
*/
- private SecretKey decodeSymmetricKeyAttribute(
+ SecretKey decodeSymmetricKeyAttribute(
final String symmetricKeyAttribute)
throws CryptoManagerException {
// Initial decomposition.
@@ -983,7 +1004,9 @@
}
// Confirm key can be unwrapped at this instance.
- final String instanceKeyID = getInstanceKeyID();
+ final byte[] instanceKeyCertificate =
+ getInstanceKeyCertificateFromLocalTruststore();
+ final String instanceKeyID = getInstanceKeyID(instanceKeyCertificate);
if (! wrappingKeyIDElement.equals(instanceKeyID)) {
return null;
}
@@ -1008,11 +1031,25 @@
// Unwrap secret key.
SecretKey secretKey;
try {
- final Cipher unwrapper
- = Cipher.getInstance(wrappingTransformationElement);
- unwrapper.init(Cipher.UNWRAP_MODE, privateKey);
- secretKey = (SecretKey)unwrapper.unwrap(wrappedKeyCipherTextElement,
- wrappedKeyAlgorithmElement, Cipher.SECRET_KEY);
+ if (RsaSveKeyTransport.isScheme(wrappingTransformationElement)) {
+ // The public key comes from the instance key certificate whose
+ // identifier was just matched: a private key held by a token does
+ // not always expose its modulus.
+ final Certificate certificate = CertificateFactory.getInstance("X.509")
+ .generateCertificate(
+ new ByteArrayInputStream(instanceKeyCertificate));
+ secretKey = RsaSveKeyTransport.unwrap(
+ new KeyPair(certificate.getPublicKey(), privateKey),
+ wrappedKeyCipherTextElement, wrappedKeyAlgorithmElement,
+ wrappingKeyIDElement);
+ }
+ else {
+ final Cipher unwrapper
+ = Cipher.getInstance(wrappingTransformationElement);
+ unwrapper.init(Cipher.UNWRAP_MODE, privateKey);
+ secretKey = (SecretKey)unwrapper.unwrap(wrappedKeyCipherTextElement,
+ wrappedKeyAlgorithmElement, Cipher.SECRET_KEY);
+ }
} catch(GeneralSecurityException ex) {
logger.traceException(ex);
throw new CryptoManagerException(
--
Gitblit v1.10.0