openssl-nodejs 在生成密钥和 CSR 时总是 return 错误

openssl-nodejs always return error while generating key and CSR

我正在使用 openssl-nodejs 包来使用 openssl 命令生成 CSR 和私钥。 我们使用以下代码成功生成了 CSR 和私钥文件。但是,它总是返回错误响应。

async function generateCsr(){
let subject = '';
let password = 'DummyPassword';

subject = `/CN=y1212.website.com/OU=Dp-PD/O=Dummy org/L=mars/C=DJ/emailAddress=abcd@website.com`;

openssl(
    [
        'req',
        '-sha256',
        '-newkey',
        'rsa:2048',
        '-keyout',
        'y1212.website.com-privkey.pem',
        '-out',
        'y1212.website.com.csr',
        '-subj',
        `${subject}`,
        '-passout',
        `pass:${password}`
    ], function (err, buffer) {
            if (err) console.log('OpenSSL error: ' + err); // RETURNS ERROR DESPITE OF GENERATING CORRECT FIELS
            console.log("string", buffer.toString()); // THIS IS NULL
});
}

generateCsr();

输出:

OpenSSL process ends with code 0
OpenSSL error: Generating a 2048 bit RSA private key
writing new private key to 'openssl/y1212.website.com-privkey.pem'

问题:为什么生成了正确的CSR和私钥却总是返回错误?因此,我们无法处理错误处理。我们如何解决这个问题?

因为我也很好奇这个问题。 挖了openssl,终于知道问题了

给用户的消息继续 stderrstdout 是 openssl 命令的结果。

默认情况下,除非您使用 -in-out,否则 openssl 从 stdin 获取数据并在 stdout 上写出数据(结果类似于 pem 文件).

例如,在shell中,我们有以下脚本来解密key-enc.pem文件并输出解密文件key-dec.pem.

openssl rsa -in key-enc.pem -output key-dec.pem -passin pass:123

一样
openssl rsa -passin pass:123 < key-enc.pem > key-dec.pem 

如您所见,您不希望发送给用户的消息最终出现在输出文件 key-dec.pem 中,这就是它们在 stderr.

上发布的原因

让我们回到 openssl 的 NodeJs 实现,看一个真实的例子。

下面的js和上面一样,不同的是我们没有用-output指定输出,所以NodeJs会在回调函数里帮我们把输出取到stdout .

const child_process = require("child_process");
const password = "123";

child_process.exec(
    `openssl rsas -in key-enc.pem -passin pass:${password}`,
    (error, stdout, stderr) => {
        if (error) {
            console.error(`exec error: ${error}`);
            return;
        }
        console.log(`stdout: ${stdout}`);
        console.error(`stderr: ${stderr}`);
    }
);

如果一切顺利,我们可以看到如下输出:

stdout: 
-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQCqGKukO1De7shrT8ebHkTz2eplU9VQQSQzY1oZMVX8i1m5
WUTLPz2yLJIBQVdXqhMCQBGoiuSoSjafUhV7i1cEGpb88h5NBYZzWXGZ37sJ5QsW
+sJyoNde3xH8vdXhzU7eT82D6X/scw9RZz+/6rCJ4p0=
-----END RSA PRIVATE KEY-----

stderr: 
writing RSA key

可以看到stdout就是我们想要的输出。此外,您可以看到 stderr 仍然输出消息 writing RSA key 即使没有错误。这就是我在上面的句子 you don't want the messages to the user to end up in the output 中的意思。这就是为什么消息被定向到 stderr 即使没有错误。

现在我们的问题是如何区分有无错误?

如果命令有错误,比如我把rsa改成rsas如下

child_process.exec(
    `openssl rsas -in key-enc.pem -output key-dec.pem -passin pass:${password}`,
    (error, stdout, stderr) => {
        if (error) {
            console.error(`exec error: ${error}`);
            return;
        }
        console.log(`stdout: ${stdout}`);
        console.error(`stderr: ${stderr}`);
    }
);

回调函数将捕获 if (error) 的错误。 错误输出如下所示:

注意:不要像示例中那样在控制台中显示您的密码。

exec error: Error: Command failed: openssl rsas -in private-key-enc.pem -passin pass:123
Invalid command 'rsas'; type "help" for a list.

我检查了你使用的库的 source code,发现它调用了 callback 函数,如下所示:

const stdout = [];
const stderr = [];

openSSLProcess.stdout.on("data", data => {
    stdout.push(data);
});

openSSLProcess.stderr.on("data", data => {
    stderr.push(data);
});

openSSLProcess.on("close", code => {
    console.log(`OpenSSL process ends with code ${code}`);
    callback.call(null, stderr, stdout);
});

如您所见,err 总是作为数组从 callback 函数返回,并且由于我上面提到的原因,里面总会有一些数据。

我建议您只使用 child_process.exec() 而不是您现在使用的库。