Запуск Openssl из сценария bash в Windows - тема не начинается с '/'

83

В моем сценарии есть:

openssl req \
  -x509 \
  -new \
  -nodes \
  -key certs/ca/my-root-ca.key.pem \
  -days 3652 \
  -out certs/ca/my-root-ca.crt.pem \
  -subj "/C=GB/ST=someplace/L=Provo/O=Achme/CN=${FQDN}"

Запуск этого в Windows в Git Bash 3.1 дает:

Subject does not start with '/'.

Пытался экранировать subj следующим образом: -subj \ "/ C = UK / ST = someplace / L = Provo / O = Achme / CN = $ {FQDN} \"

По-прежнему не работает. Есть идеи?

iss42
источник
1
Стандартный первый вопрос: есть ли в вашем файле сценария окончания строки в стиле DOS / Windows (возврат каретки + перевод строки) или в стиле unix (только перевод строки)? Попробуйте напечатать сценарий с помощью cat -vet /path/to/scriptи посмотрите, заканчиваются ли строки на «^ M $» (стиль Windows) или просто «$» (стиль unix).
Гордон Дэвиссон
1
Это сценарий на bash? В какой среде работать? Что добавляется set -vxв начало показа сценария для этой строки?
Etan Reisner
@EtanReisner set -vxполезно спасибо! Среда - Windows, Git bash 3.1. С -vx я получаю, + openssl req -x509 -new -nodes -key certs/ca/my-root-ca.key.pem -days 3652 -out certs/ca/my-root-ca.crt.pem -subj /C=GB/ST=someplace/L=Provo/O=Achme/CN=domain.comчто показывает -subjстроку без кавычек . Но я не могу понять, как перевести это в цитируемую форму из сценария.
iss42
@GordonDavisson, спасибо! в скрипте есть окончания строки '^ M $'
iss42
1
Аргумент без кавычек в -vxвыводе не вызывает удивления или проблемы. Кавычки предназначены для синтаксического анализа оболочки, а не для самого выполнения команды. Мне этот вывод кажется правильным. Окончания строк DOS, как правило, не являются хорошей идеей, но, похоже, не вызывают здесь каких-либо проблем (если только их удаление не решает проблему, и в этом случае я немного смущен сообщением об ошибке).
Etan Reisner

Ответы:

197

Эта проблема характерна для MinGW / MSYS, который обычно используется как часть пакета Git для Windows .

Решение состоит в том, чтобы передать -subjаргумент с ведущими //(двойные косые черты вперед), а затем использовать \(обратные косые черты) для разделения пар ключ / значение. Как это:

"//O=Org\CN=Name"

Затем это будет волшебным образом передано opensslв ожидаемой форме:

"/O=Org/CN=Name"

Итак, чтобы ответить на конкретный вопрос, вы должны изменить -subjстроку в своем скрипте на следующую.

-subj "//C=GB\ST=someplace\L=Provo\O=Achme\CN=${FQDN}"

Это должно быть все, что вам нужно.

Что это за магия?

Для тех, кому интересно, что именно здесь происходит, я могу объяснить эту загадку. Причина в том, что MSYS разумно предполагает, что аргументы, содержащие косую черту, на самом деле являются путями. И когда эти аргументы передаются исполняемому файлу, который не был скомпилирован специально для MSYS (как opensslв этом случае), он преобразует пути POSIX в пути Win32 . Правила для этого преобразования довольно сложны, поскольку MSYS изо всех сил пытается охватить наиболее распространенные сценарии взаимодействия. Это также объясняет, почему использование opensslиз командной строки Windows ( cmd.exe) работает нормально, потому что никаких волшебных преобразований не производится.

Вы можете протестировать преобразование следующим образом.

$ cmd //c echo "/CN=Name"
"C:/Program Files (x86)/Git/CN=Name"

Мы не можем использовать echoисполняемый файл, поставляемый с MSYS, поскольку он был скомпилирован для MSYS, вместо этого мы будем использовать echoвстроенный в cmd. Обратите внимание: поскольку cmdпереключатели начинаются с /(общего для команд Windows), нам нужно обрабатывать это с помощью двойных слэшей. Как мы видим в выходных данных, аргумент был расширен до пути Windows, и становится ясно, почему opensslэто действительно так Subject does not start with '/'..

Посмотрим еще несколько конверсий.

$ cmd //c echo "//CN=Name"
/CN=Name

Двойная косая черта заставляет MSYS полагать, что аргумент является переключателем стиля Windows, который приводит к удалению /только (без преобразования пути). Вы могли подумать, что с этим мы могли бы просто использовать косую черту, чтобы добавить больше пар ключ / значение. Давай попробуем.

$ cmd //c echo "//O=Org/CN=Name"
//O=Org/CN=Name

Внезапно двойные косые черты в начале не удаляются. Это потому, что теперь, когда после начальных двойных косых черт ставится косая черта, MSYS считает, что мы ссылаемся на путь UNC (например, // server / path). Если бы это было передано opensslему, первое слово ключ / значение пропустило бы Subject Attribute /O has no known NID, skipped.

Вот соответствующее правило из вики MinGW, объясняющее это поведение:

  • Аргумент, начинающийся с 2 или более /, считается экранированным переключателем стиля Windows и будет передан с удалением ведущего / и изменением всего \ на /.
    • За исключением того, что если за ведущим блоком / следует /, аргумент считается UNC-путем, а ведущий / не удаляется.

В этом правиле мы можем увидеть метод, который мы могли бы использовать для создания нужного нам аргумента. Поскольку все, \что следует за аргументом, начинающимся с, //будет преобразовано в простой /. Давай попробуем.

$ cmd //c echo "//O=Org\CN=Name"
/O=Org/CN=Name

И, как мы видим, это действительно работает.

Надеюсь, это немного проясняет магию.

Корроз
источник
1
Отличное объяснение.
trebor
4
Что делать, если я использую тот же bashсценарий для генерации ключей в среде Linux? Как можно было бы интерпретировать эти ведущие двойные косые черты и обратные косые черты в середине строки?
Томилов Анатолий
3
@Orient Linux нуждается в косых чертах в другом направлении, поэтому вам нужно определить, на каком типе системы он работает - вот ответ, который использует caseоператор и uname -sопределяет среду, которую вы затем можете использовать с помощью, ifчтобы использовать соответствующий слэши - stackoverflow.com/questions/3466166/…
Тим Льюис
Просто восхитительно. Меня поймали с той же проблемой, и я полностью забыл о преобразовании пути из POSIX в Win32. Все думал, что цитирую неправильно.
davewasthere
0

Я лично обнаружил, что это характерно для используемого двоичного файла OpenSSL. В моей системе, использующей msys2 / mingw64, я заметил, что присутствуют два разных двоичных файла OpenSSL, например:

$ whereis openssl; echo; which openssl
openssl: /usr/bin/openssl.exe /usr/lib/openssl /mingw64/bin/openssl.exe /usr/share/man/man1/openssl.1ssl.gz

/mingw64/bin/openssl

Я считаю, что для использования /mingw64/bin/opensslэтого требуется использование темы, которая начинается с //, однако я не уверен, относится ли это к пакету / сборке или версии OpenSSL, поэтому, чтобы быть уверенным, версия каждого двоичного файла приведена ниже:

$ while read -r _openSslBin; do printf "${_openSslBin}: "; ${_openSslBin} version; done < <(whereis openssl | egrep -o '[^ ]+?\.exe ')
/usr/bin/openssl.exe: OpenSSL 1.0.2p  14 Aug 2018
/mingw64/bin/openssl.exe: OpenSSL 1.1.1  11 Sep 2018

Я нашел следующий пример кода bash для выбора правильного двоичного файла на основе версии OpenSSL при использовании msys / mingw для работы на моем компьютере:

# determine openssl binary to use based on OS
# -------------------------------------------
_os="$(uname -s | awk 'BEGIN{FS="_"} {print $1}' | egrep -o '[A-Za-z]+')"
if [ "${_os,,}" = "mingw" ] || [ "${_os,,}" == "msys" ]; then
  while read -r _currentOpenSslBin; do
    if [[ "$(${_currentOpenSslBin}  version | awk '{print $2}')" =~ ^(1\.0\.[0-9].*|0\.\9\.8.*)$ ]]; then
      _openSslBin="${_currentOpenSslBin}"
    fi
  done < <(whereis openssl | egrep -o '\/[^ ]+?\.exe ' | egrep -v 'mingw')
  if [ -n "${_openSslBin}" ]; then
    printf "OpenSSL Binary: ${_openSslBin} (v. $(${_openSslBin}  version | awk '{print $2}'))\n"
  else
    printf "Unable to find compatible version of OpenSSL for use with '${_os}' OS, now exiting...\n"
    exit 1
  fi
else
  _openSslBin="openssl"
fi

# display selected openssl binary and it's version
# ------------------------------------------------
printf "${_openSslBin}: "; ${_openSslBin} version

В дополнение к исправлению проблем с передачей строки темы я также обнаружил, что это решает проблемы с размером DN (я передал настраиваемый openssl.cnf с политикой, которая не устанавливала max_size ни для одного из полей и у которой все еще были проблемы при использовании /mingw64/bin/openssl.exe).

Роб Фрей
источник