使用Java ProcessBuilder使用“openssl ca”命令签署.csr文件(通过cmd.exe或openssl.exe)

qmelpv7a  于 2022-10-01  发布在  Java
关注(0)|答案(1)|浏览(161)

我正在尝试自动生成用于Web授权的.p12签名证书的手动生成过程。

KeyPair(.p12)和CertReq(.csr)文件是使用JDK的KeyTool程序生成的。现在,我需要使用OpenSSL用一个中间证书来签署.p12,但与在ProcessBuilder或e1d1e中执行“keyTool”命令不同,OpenSSL很难处理Java的进程对象。我不知道它出了什么问题。

我需要执行的命令如下:

openssl ca -config ./CA_config.cnf -extensions my_client_cert -infiles ./CA_certreqs/MY_CLIENT_AAAAAA.csr

它有3个时刻等待用户输入并在它们之间输出文本:

1.输入CA_certificate.crt密码(.crt文件CA_config.cnf指向);
1.签署证书-[y/n];
1.提交结果--[y/n]。

下面提供了代码快照。为了更容易阅读,大多数变量都被替换为硬代码。

private static void signCertReqWithOpenSSL2() throws IOException {
    String command = "openssl ca -config ./CA_config.cnf -extensions my_client_cert -infiles ./CA_certreqs/MY_CLIENT_AAAAAA.csr"
    String[] commandSeparated = command.split(" ");

    //init cmd process
    ProcessBuilder pb = new ProcessBuilder("cmd.exe");
    pb.redirectErrorStream(true);
    pb.directory(new File("../dir1/dir2/").getAbsoluteFile());
    pb.command(commandSeparated);
    Process process = pb.start();

    try (InputStream in = process.getInputStream());
         OutputStream out = process.getOutputStream()) {
        System.out.println("--- begin---");

        readAllConsoleOutputFromBuffer(in, 80); //93 bytes actually

        //enter CA_certificate.crt password
        enterUserInputToOutputStream(out, caPassword);
        readAllConsoleOutputFromBuffer(in, 10); //350

        //sign the certificate
        enterUserInputToOutputStream(out, "y");
        readAllConsoleOutputFromBuffer(in, 10); //56

        //commit the certification
        enterUserInputToOutputStream(out, "y");
        readAllConsoleOutputFromBuffer(process.getInputStream(), 10); //4815

        System.out.println("--- end ---");
    }
    process.destroy();
}

private static void enterUserInputToOutputStream(OutputStream out, String input) throws IOException {
    out.write(String.format("%s%n", input).getBytes());
    out.flush();
}

//if the stream has enough text to be printed (indicating that it's probably ready for user input), print it
private static void readAllConsoleOutputFromBuffer(InputStream in, int minTextSizeInBytes) throws IOException {
//loop is made just to make it scanning the stream during some time. I know there're better ways
    for (int i = 0; i < 100000; i++) {
        if (in.available() > minTextSizeInBytes) {
            String line;
            BufferedReader buff = new BufferedReader(new InputStreamReader(in));
            while ((line = buff.readLine()) != null) {
                System.out.println(line);
            }
            break;
        }
    }
}

问题:我不能让它到达末尾,所以它生成一个新的.pem文件和/或在控制台中输出“Begin certifect”文本以供我进一步处理。

它甚至没有到达我需要输入CA_certificate.crt密码的第一个输入点。充其量,我捕捉到了第一个输出行“Using configuration from./CA_config.cnf”。

我相信一切都安排得很好。

  • %PATH%;中存在OpenSSL目录
  • 所有文件和文件夹都存在,OpenSSL会找到它们(如果我在CA_config.cnf中出错或删除了执行所需的任何文件,我会在控制台输出中发现找不到某些东西的错误)。

我试过的是:

  • 忽略控制台输出(与InputStream交互);
  • 等待一段时间的各种方式,这样OpenSSL就可以准备好消费来自我的输入(Thread.Slear,其他线程检查条件或睡眠,for loop进行一些时间流逝等);
  • 使用openssl.exe作为可执行文件,而不是cmd.exe-我重写了命令和CA_config.cnf中的路径,并获得了与cmd.exe及其相对路径相同的结果。
  • 处理字符串和编码,以防它在读取第一个输出行后以某种方式卡在行终止符,即使我怀疑这是根本原因。

除了将命令分离到.bat文件之外,还有什么帮助或想法可以让它正常工作吗?也许我没有以正确的方式与Process对象的输入流和输出流交互。

如有任何帮助,我们不胜感激!

操作系统:Windows 10 x64

0lvr5msh

0lvr5msh1#

它甚至没有到达我需要输入CA_certificate.crt密码的第一个输入点。

您可以使用BufferedReader.readLine,当且仅当它读取行终止符(也就是行尾/EOL)时,它才会返回--在Unix上通常是LF,在Windows上通常是CRLF,在经典Mac上通常是CR,但在任何类型的系统上,它都可以接受这三种类型中的任何一种--或者输入流命中文件结尾/EOF,并且由于从子进程的stdout或stderr(如果将它们组合在一起)的连接是管道,只有当子进程关闭其管道末端或退出时才会发生EOF。通常,提示既不会以LF/CRLF/CR结束,也不会紧跟在关闭或退出之后,因此您的代码不会读取它。但对于This提示,请参见下面的更多内容。

等待一段时间的各种方式,以便OpenSSL准备使用来自我的输入

这是不必要的,也是无用的;与子进程的stdin的连接也是一个管道,管道是缓冲的,所以即使子进程还没有准备好读取,您也可以写入至少几千字节。

您的实际问题是opensslpassphrase提示不使用stderr(或stdout)和stdin,而是直接使用ProcessBuilder无法捕获或处理的控制台。与其尝试回答这个提示,不如在命令中添加两个额外的参数-passin pass:<value>

这样做之后,您可以回答y+eol(无论是否事先阅读)‘Sign’和‘Commit’提示,但更容易的是,您可以添加另一个*参数-batch,它完全跳过这些提示。

旁白:既然您已经在使用KeyTool,您是否考虑过使用keytool -gencert从CSR生成(子)证书,而不是使用openssl?它不像openssl ca那样为你维护一个‘数据库’,但如果你真的想要,你可以用Java自己做,甚至可能更好。

相关问题