Search code examples
gradlegroovykeytool

keytool with -dname containing spaces in Gradle: illegal option


I am trying to create a task that would involve the Java keytool binary, but apparently I am unable to pass the dname argument properly. Spaces seem to be the problem, but only when run as a Gradle script. When I copy-paste the same command into a terminal it works. (I believe in both cases the same keytool binary is being used.)

This is my script:

task generateTomcatKeystore() {
  doLast {
      def serverAlias = "server_debug"
      def serverStorePass = "changeit_server"
      def serverKeyPass = "changeit_server"

      def ourDomain = "domain.net"
      def ourName = "Company"

      def dName = /CN=$ourDomain, OU=Backend, O=$ourName, L=Prague, S=Czech Republic, C=CZ/
      def keytoolCommand = /keytool -genkeypair -alias $serverAlias -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -dname "$dName" -validity 365 -keypass $serverKeyPass -keystore tomcat.jks -storepass $serverStorePass/;

      // what exactly am I executing?
      println keytoolCommand

      def outputErr = keytoolCommand.execute().err.text
      // errors?
      println outputErr

      // am I calling the right binary? ...apparently yes
      println 'which keytool'.execute().text
  }
}

This is the complaint I am getting:

Illegal option:  OU=Backend,

When I eliminate all the spaces in between the dname components like this:

def dName = /CN=$ourDomain,OU=Backend,O=$ourName,L=Prague,S=Czech Republic,C=CZ/

the error changes to:

Illegal option:  Republic,C=CZ"

...so clearly the spaces are the issue. But only when run from within Gradle.

Note that my -dname is enclosed by double quotes:

keytool -genkeypair -alias server_debug -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -dname "CN=domain.net,OU=Backend,O=Company,L=Prague,S=Czech Republic,C=CZ" -validity 365 -keypass changeit_server -keystore tomcat.jks -storepass changeit_server

According to Oracle only commas have to be escaped within the dname argument, see for yourself.


Solution

  • Under the hood, groovy has added an execute() method to java.lang.String that splits your string into an array. It probably does this by splitting on space characters. See String.execute()

    I suggest you use Gradle's Project.exec(Closure) instead. You could do something like

    ByteArrayOutputStream errorOut = new ByteArrayOutputStream() 
    exec {
      workingDir = "$javaHome/bin" 
      errorOutput = errorOut
      args "keytool -genkeypair -alias $serverAlias -keyalg RSA -keysize 2048 -sigalg SHA1withRSA -dname".split(' ') 
      args dName
      args "-validity 365 -keypass $serverKeyPass -keystore tomcat.jks -storepass $serverStorePass".split(' ') 
    } 
    String errors = errorOut.toString()