From 91b56edf3ef228cb8e29df9e57a6605a5ce9557c Mon Sep 17 00:00:00 2001
From: jvergara <jvergara@localhost>
Date: Wed, 02 Apr 2008 13:00:55 +0000
Subject: [PATCH] Fix for issue 3075 (ads-truststore creation failure and exception handling) 1. There is a problem with the default cipher algorithm provided in the CryptoManager  configuration (RSA/ECB/OAEPWITHSHA-1ANDMGF1PADDING) since it does not work in IBM Java.  RSA/ECB/PKCS1Padding must be used instead in default Java 5 AIX installations.  This issue may apply to any other JVM that do not include the same ciphers as Sun JCE.        A fix to handle this case corresponds to the modifications performed in ConfigureDS.java. ConfigureDS checks whether the default cipher can be used with the JVM and if not, tries to use an alternative cipher.  If the default cipher does not work and an alternative cipher is found, the configuration of the CryptoManager is updated.

---
 opends/src/server/org/opends/server/util/CertificateManager.java |   56 +++++++++++++++---
 opends/src/messages/messages/tools.properties                    |    2 
 opends/src/server/org/opends/server/config/ConfigConstants.java  |    6 ++
 opends/src/server/org/opends/server/tools/ConfigureDS.java       |   94 +++++++++++++++++++++++++++++++
 opends/src/server/org/opends/server/util/SetupUtils.java         |    2 
 5 files changed, 149 insertions(+), 11 deletions(-)

diff --git a/opends/src/messages/messages/tools.properties b/opends/src/messages/messages/tools.properties
index 78957b3..2ad48f1 100644
--- a/opends/src/messages/messages/tools.properties
+++ b/opends/src/messages/messages/tools.properties
@@ -2343,4 +2343,6 @@
 INFO_INSTALLDS_CONFIRM_INSTALL_1604=Setup the server with the parameters above
 INFO_INSTALLDS_PROVIDE_DATA_AGAIN_1605=Provide the setup parameters again
 INFO_INSTALLDS_CANCEL_1606=Cancel the setup
+SEVERE_ERR_CONFIGDS_CANNOT_UPDATE_CRYPTO_MANAGER_1607=An error occurred while \
+ attempting to update the crypto manager in the Directory Server: %s
 
diff --git a/opends/src/server/org/opends/server/config/ConfigConstants.java b/opends/src/server/org/opends/server/config/ConfigConstants.java
index 06d5586..f97d57a 100644
--- a/opends/src/server/org/opends/server/config/ConfigConstants.java
+++ b/opends/src/server/org/opends/server/config/ConfigConstants.java
@@ -2915,6 +2915,12 @@
   public static final String ATTR_CRYPTO_CIPHER_TRANSFORMATION_NAME =
        "ds-cfg-cipher-transformation-name";
 
+  /**
+   * The name of the attribute that is used to hold the key wrapping
+   * transformation used by the Crypto Manager.
+   */
+  public static final String ATTR_CRYPTO_CIPHER_KEY_WRAPPING_TRANSFORMATION =
+    "ds-cfg-key-wrapping-transformation";
 
   /**
    * The name of the attribute that is used to hold the name of a
diff --git a/opends/src/server/org/opends/server/tools/ConfigureDS.java b/opends/src/server/org/opends/server/tools/ConfigureDS.java
index ac34bd8..c3a72cb 100644
--- a/opends/src/server/org/opends/server/tools/ConfigureDS.java
+++ b/opends/src/server/org/opends/server/tools/ConfigureDS.java
@@ -29,11 +29,19 @@
 
 
 
+import java.security.GeneralSecurityException;
+import java.util.Collection;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.Set;
 import java.io.File;
 
+import javax.crypto.Cipher;
+
+import org.opends.server.admin.DefaultBehaviorProvider;
+import org.opends.server.admin.DefinedDefaultBehaviorProvider;
+import org.opends.server.admin.StringPropertyDefinition;
+import org.opends.server.admin.std.meta.CryptoManagerCfgDefn;
 import org.opends.server.api.ConfigHandler;
 import org.opends.server.config.BooleanConfigAttribute;
 import org.opends.server.config.ConfigEntry;
@@ -127,6 +135,11 @@
   private static final String DN_ROOT_USER =
        "cn=Directory Manager," + DN_ROOT_DN_CONFIG_BASE;
 
+  /**
+   * The DN of the Crypto Manager.
+   */
+  private static final String DN_CRYPTO_MANAGER = "cn=Crypto Manager,cn=config";
+
 
 
   /**
@@ -988,6 +1001,59 @@
       }
 
 
+      // Check that the cipher specified is supported.  This is intended to
+      // fix issues with JVM that do not support the default cipher (see
+      // issue 3075 for instance).
+      CryptoManagerCfgDefn cryptoManager = CryptoManagerCfgDefn.getInstance();
+      StringPropertyDefinition prop =
+        cryptoManager.getKeyWrappingTransformationPropertyDefinition();
+      String defaultCipher = null;
+      DefaultBehaviorProvider p = prop.getDefaultBehaviorProvider();
+      if (p instanceof DefinedDefaultBehaviorProvider)
+      {
+        Collection<?> defaultValues =
+          ((DefinedDefaultBehaviorProvider)p).getDefaultValues();
+        if (!defaultValues.isEmpty())
+        {
+          defaultCipher = defaultValues.iterator().next().toString();
+        }
+      }
+      if (defaultCipher != null)
+      {
+        // Check that the default cipher is supported by the JVM.
+        try
+        {
+          Cipher.getInstance(defaultCipher);
+        }
+        catch (GeneralSecurityException ex)
+        {
+          // The cipher is not supported: try to find an alternative one.
+          String alternativeCipher = getAlternativeCipher();
+          if (alternativeCipher != null)
+          {
+            try
+            {
+              DN cipherDN = DN.decode(DN_CRYPTO_MANAGER);
+              ConfigEntry configEntry = configHandler.getConfigEntry(cipherDN);
+
+              // Set the alternative cipher
+              StringConfigAttribute keyWrappingTransformation =
+                new StringConfigAttribute(
+                    ATTR_CRYPTO_CIPHER_KEY_WRAPPING_TRANSFORMATION,
+                    Message.EMPTY, false, false, true, alternativeCipher);
+              configEntry.putConfigAttribute(keyWrappingTransformation);
+            }
+            catch (Exception e)
+            {
+              Message message = ERR_CONFIGDS_CANNOT_UPDATE_CRYPTO_MANAGER.get(
+                  String.valueOf(e));
+              System.err.println(wrapText(message, MAX_LINE_WIDTH));
+              return 1;
+            }
+          }
+        }
+      }
+
       // Write the updated configuration.
       try
       {
@@ -1013,5 +1079,33 @@
     // If we've gotten here, then everything was successful.
     return 0;
   }
+
+  /**
+   * Returns a cipher that is supported by the JVM we are running at.
+   * Returns <CODE>null</CODE> if no alternative cipher could be found.
+   * @return a cipher that is supported by the JVM we are running at.
+   */
+  private static String getAlternativeCipher()
+  {
+    final String[] preferredAlternativeCiphers =
+    {
+        "RSA/ECB/OAEPWITHSHA1ANDMGF1PADDING",
+        "RSA/ECB/PKCS1Padding"
+    };
+    String alternativeCipher = null;
+    for (String cipher : preferredAlternativeCiphers)
+    {
+      try
+      {
+        Cipher.getInstance(cipher);
+        alternativeCipher = cipher;
+        break;
+      }
+      catch (Throwable t)
+      {
+      }
+    }
+    return alternativeCipher;
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/util/CertificateManager.java b/opends/src/server/org/opends/server/util/CertificateManager.java
index 37c358c..bb420ee 100644
--- a/opends/src/server/org/opends/server/util/CertificateManager.java
+++ b/opends/src/server/org/opends/server/util/CertificateManager.java
@@ -40,6 +40,7 @@
 import java.util.ArrayList;
 import java.util.Enumeration;
 
+import org.opends.server.types.OperatingSystem;
 
 
 /**
@@ -443,13 +444,12 @@
     // invoking the KeyTool command.
     keyStore = null;
 
-
     // First, we need to run with the "-genkey" command to create the private
     // key.
     String[] commandElements =
     {
       KEYTOOL_COMMAND,
-      "-genkey",
+      getGenKeyCommand(),
       "-alias", alias,
       "-dname", subjectDN,
       "-keyalg", "rsa",
@@ -541,7 +541,7 @@
     String[] commandElements =
     {
       KEYTOOL_COMMAND,
-      "-genkey",
+      getGenKeyCommand(),
       "-alias", alias,
       "-dname", subjectDN,
       "-keyalg", "rsa",
@@ -553,6 +553,7 @@
     // Next, we need to run with the "-certreq" command to generate the
     // certificate signing request.
     File csrFile = File.createTempFile("CertificateManager-", ".csr");
+    csrFile.deleteOnExit();
     commandElements = new String[]
     {
       KEYTOOL_COMMAND,
@@ -743,11 +744,11 @@
       KEY_STORE_TYPE_PKCS11.equals(keyStoreType);
 
     boolean isNewKeyStorePassword = !keyStoreDefined &&
-      ("-genkey".equalsIgnoreCase(commandElements[1]) ||
+      (getGenKeyCommand().equalsIgnoreCase(commandElements[1]) ||
       "-import".equalsIgnoreCase(commandElements[1]));
 
     boolean isNewStorePassword =
-      "-genkey".equalsIgnoreCase(commandElements[1]);
+      getGenKeyCommand().equalsIgnoreCase(commandElements[1]);
 
     boolean askForStorePassword =
       !"-import".equalsIgnoreCase(commandElements[1]);
@@ -762,15 +763,34 @@
       Process process = processBuilder.start();
       InputStream inputStream = process.getInputStream();
       OutputStream out = process.getOutputStream();
+      if (!isJDK15() &&
+          (SetupUtils.getOperatingSystem() == OperatingSystem.AIX))
+      {
+        // This is required when using JDK 1.6 on AIX to be able to write
+        // on the OutputStream.
+        try
+        {
+          Thread.sleep(1500);
+        } catch (Throwable t) {}
+      }
       out.write(keyStorePassword.getBytes()) ;
       out.write(lineSeparator.getBytes()) ;
       out.flush() ;
       // With Java6 and above, keytool asks for the password twice.
       if (!isJDK15() && isNewKeyStorePassword)
       {
-         out.write(keyStorePassword.getBytes()) ;
-         out.write(lineSeparator.getBytes()) ;
-         out.flush() ;
+        if (SetupUtils.getOperatingSystem() == OperatingSystem.AIX)
+        {
+          // This is required when using JDK 1.6 on AIX to be able to write
+          // on the OutputStream.
+          try
+          {
+            Thread.sleep(1500);
+          } catch (Throwable t) {}
+        }
+        out.write(keyStorePassword.getBytes()) ;
+        out.write(lineSeparator.getBytes()) ;
+        out.flush() ;
       }
 
       if (askForStorePassword)
@@ -779,8 +799,10 @@
         out.write(lineSeparator.getBytes()) ;
         out.flush() ;
 
-        // With Java6 and above, keytool asks for the password twice!
-        if (!isJDK15() && isNewStorePassword)
+        // With Java6 and above, keytool asks for the password twice (if we
+        // are not running AIX).
+        if (!isJDK15() && isNewStorePassword &&
+            (SetupUtils.getOperatingSystem() != OperatingSystem.AIX))
         {
           out.write(storePassword.getBytes()) ;
           out.write(lineSeparator.getBytes()) ;
@@ -934,6 +956,20 @@
     }
     return isJDK15;
   }
+
+  private String getGenKeyCommand()
+  {
+    String genKeyCommand;
+    if (!isJDK15())
+    {
+      genKeyCommand = "-genkeypair";
+    }
+    else
+    {
+      genKeyCommand = "-genkey";
+    }
+    return genKeyCommand;
+  }
 }
 
 
diff --git a/opends/src/server/org/opends/server/util/SetupUtils.java b/opends/src/server/org/opends/server/util/SetupUtils.java
index 90774cd..15499d0 100644
--- a/opends/src/server/org/opends/server/util/SetupUtils.java
+++ b/opends/src/server/org/opends/server/util/SetupUtils.java
@@ -260,7 +260,7 @@
    * Commodity method to help identifying the OS we are running on.
    * @return the OperatingSystem we are running on.
    */
-  private static OperatingSystem getOperatingSystem()
+  public static OperatingSystem getOperatingSystem()
   {
     return OperatingSystem.forName(System.getProperty("os.name"));
   }

--
Gitblit v1.10.0