如何以编程方式将输入传递给Java keytool?

时间:2014-12-27 21:27:06

标签: java ssl keytool jcabi

我正在尝试解决开源项目jcabi-ssl-maven-plugin中的问题。

方法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())
    );
}

此代码的目的是

  1. 启动Java keytool程序和
  2. 在命令行上回答问题。
  3. 第一步涉及程序化调用,如"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

    然后,keytool会问你几个问题(见下文,翻译自德语):

    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
    

    上述代码不是手动输入答案(上面的A),而是使用writer.print(...);语句。

    但他们显然不能工作,因为当我运行一个涉及使用keytool(例如com.jcabi.ssl.maven.plugin.CacertsTest#importsCertificatesFromKeystore)的测试时,我得到以下错误:

    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)
    

    我认为这个问题的根本原因是writer.print(...);语句无法将其文本传递给keytool。

    如何解决此问题(请确保com.jcabi.ssl.maven.plugin.Keytool#genkey方法中writer.print(...);撰写的邮件正确传递到keytool)?

    更新1(2014年12月28日MSK):

    我想我找到了原因。我在Windows上运行测试,因此writer.print("localhost\n");之类的调用需要替换为writer.print("localhost" + System.getProperty("line.separator"));

    这很容易。

    但还有另一部分。这段代码的开发人员显然使用了英语版的keytool,所以最后它需要一个yes(参见上面示例输出keytool中的最后一个问题)。

    因此有声明

    writer.print("yes\n");
    

    但我使用的是德语版Windows,因此在我的情况下,正确的回复不是yes,而是Ja

    如果我更改这样的代码,它可以工作(测试不会失败):

    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);
    

    我很欣赏有关如何使用任何语言使这部分代码适用于操作系统的提示(如何避免硬编码yesJa)。

0 个答案:

没有答案