How do I programmatically pass input to a Java keytool?

I am trying to fix an issue on open source project jcabi-ssl-maven-plugin .

The problem arises in the method com.jcabi.ssl.maven.plugin.Keytool#genkey

:

@Loggable(Loggable.DEBUG)
public void genkey() throws IOException {
    final Process proc = this.proc(
        "-genkeypair",
        "-alias",
        "localhost",
        "-keyalg",
        "RSA",
        "-keysize",
        "2048",
        "-keypass",
        this.password
    ).start(); // Here we launch the keytool
    final PrintWriter writer = new PrintWriter(
        new OutputStreamWriter(proc.getOutputStream())
    );
    writer.print("localhost\n"); // These and other writer.print(...) statements 
    writer.print("ACME Co.\n"); // write answers to questions of keytool
    writer.print("software developers\n");
    writer.print("San Francisco\n");
    writer.print("California\n");
    writer.print("US\n");
    writer.print("yes\n");
    writer.close();
    new VerboseProcess(proc).stdout();
    Logger.info(
        this,
        "Keystore created in '%s' (%s)",
        this.keystore,
        FileUtils.byteCountToDisplaySize(this.keystore.length())
    );
}

      

The purpose of this code is

  • run Java keytool program and
  • answer your questions on the command line.

The first step involves calling the type programmatically "C:\Program Files\Java\jdk1.8.0\jre\bin\keytool" -genkeypair -alias localhost -keyalg RSA -keysize 2048 -keypass some-password -storetype jks -noprompt -storepass some-password -keystore C:\Users\DP118M\AppData\Local\Temp\junit4133348108660376680\keystore.jks

.

Then keytool asks you a few questions (see below, translated from German):

What is your name?
  [Unknown]:  A
What is the name of your organizational unit?
  [Unknown]:  A
What is the name of your organisation?
  [Unknown]:  A
What is the name of your city or county?
  [Unknown]:  A
What is the name of your state?
  [Unknown]:  A
What is the country code of your organizational unit?
  [Unknown]:  A
Is CN=A, OU=A, O=A, L=A, ST=A, C=A correct?
  [No]:  Yes

      

Instead of manually entering answers ( A

above), the above code uses instructions writer.print(...);

.

But they obviously don't work because when I run a test that involves using a keytool (eg com.jcabi.ssl.maven.plugin. CacertsTest # importCertificatesFromKeystore ) I get the following error:

java.lang.IllegalArgumentException: Non-zero exit code 1: Keytool Error: java.lang.RuntimeException: Too many repeated attempts. Program will be terminated.
\n
    at com.jcabi.log.VerboseProcess.stdout(VerboseProcess.java:220)
    at com.jcabi.log.VerboseProcess.stdout(VerboseProcess.java:158)
    at com.jcabi.ssl.maven.plugin.Keytool.genkey(Keytool.java:116)
    at com.jcabi.ssl.maven.plugin.Keystore.activate(Keystore.java:121)
    at com.jcabi.ssl.maven.plugin.CacertsTest.importsCertificatesFromKeystore(CacertsTest.java:64)

      

I guess the root cause of this problem is that the operators writer.print(...);

cannot deliver their texts to the keytool.

How can I fix this (make sure in the method the com.jcabi.ssl.maven.plugin.Keytool#genkey

messages written writer.print(...);

are correctly delivered to keytool

)?

Update 1 (28.12.2014 MSK):

I think I have found the reason. I am running my test on Windows, so the type calls writer.print("localhost\n");

should be replaced with writer.print("localhost" + System.getProperty("line.separator"));

.

It's easy.

But there is another part. The developers of this code obviously worked on the English version of keytool, so it expects at the end yes

(see the last question in the example above, keytool).

Therefore, there is a statement

writer.print("yes\n");

      

But I am using the German version of Windows, so in my case the correct answer is not yes

, but Ja

.

If I change the code like this it works (test does not break):

final String newLine = System.getProperty("line.separator");
writer.print("localhost" + newLine);
writer.print("ACME Co." + newLine);
writer.print("software developers" + newLine);
writer.print("San Francisco" + newLine);
writer.print("California" + newLine);
writer.print("US" + newLine);
writer.print("Ja" + newLine);

      

I appreciate the hints on how I can get this piece of code to work with operating systems in any language (how can I avoid hardcoding yes

and Ja

).

+3


source to share





All Articles