从 bash 执行 openssl 命令时出错,但可以从命令行运行

从 bash 执行 openssl 命令时出错,但可以从命令行运行

我经常处理 SSL 证书、私钥、CSR 等。我有许多小型 bash 脚本可以自动执行我的任务。其中一个脚本使用 openssl 为 SSL 证书生成新的私钥和 CSR。该脚本实际上只有一行加上错误检查 - 以节省我的输入:

#!/usr/bin/env bash

if [[ $# -ne 1 ]]; then
    echo "Format: $0 hostname"
    echo "   e.g. $0 www.example.com"
    exit 2
fi

openssl req -new -newkey rsa:2048 -nodes -keyout "$1.key" -out "$1.csr" \
            -subj "/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1"

cat "$1.csr"

这一直运作良好。然而最近我需要越来越多的带有 SAN 的证书,所以我修改了脚本,如下所示:

#!/usr/bin/env bash

if [[ $# -eq 0 ]]; then
    echo "Format: $0 hostname"
        echo "   e.g. $0 www.example.com [SAN1 SAN2 ...]"
        exit 2
fi

SANS=""
if [[ $# -gt 1 ]]; then
    SANS=""
    for san in "${@:2}"; do
        SANS="${SANS}DNS:${san}, "
    done
    SANS="-addext \"subjectAltName = ${SANS%,*}\""
fi


openssl req -new -newkey rsa:2048 -nodes -keyout "$1.key" -out "$1.csr" \
            -subj "/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1" \
            $SANS

cat "$1.csr"

现在脚本不再起作用,只需生成

req: Use -help for summary.

我修改了脚本的最后一点,如下所示:

CMD="openssl req -new -newkey rsa:2048 -nodes -keyout \"$1.key\" -out \"$1.csr\" \
            -subj \"/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1\" \
            $SANS"
echo $CMD
$CMD

这使我可以在执行命令之前查看该命令。该命令是正确的,当我将此命令复制/粘贴到 bash 提示符中时,我确实得到了正确的结果。那么,是什么原因导致该命令在从脚本执行时失败呢?

答案1

你的问题是你的SANS变量,它是一个字符串。您使用不带引号的变量,这意味着 shell 会将其拆分为空格(并对所有拆分部分应用文件名通配)。

而不是存储多个单独的字符串在一个字符串中,使用一个数组:

SANS=()
if [[ $# -gt 1 ]]; then
    subjAltNames=("${@:2}")
    IFS=,
    SANS=(-addext "subjectAltName = ${subjAltNames[*]}")
fi

如果$#大于 1,则给出SANS一个数组,其中包含两个元素-addext和字符串,subjectAltNames =后跟来自命令行参数的以逗号分隔的字符串列表。逗号分隔列表是从另一个数组创建的,subjAltNames通过将其用作,其元素与作为分隔符${subjAltNames[*]}的第一个字符连接起来(这就是我们预先设置为逗号的原因)。$IFSIFS

您稍后将使用SANSas"${SANS[@]}"来正确访问单独引用的元素的列表:

openssl req -new -newkey rsa:2048 -nodes -keyout "$1.key" -out "$1.csr" \
            -subj "/C=GB/ST=County/L=City/O=My Company Ltd./CN=$1" \
            "${SANS[@]}"

如果SANS数组为空,则不会向参数列表的末尾提供空参数。

相关内容