Запуск 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 = whereplace / L = Provo / O = Achme / CN = $ {FQDN} \"

Досі не працює. Будь-які ідеї?


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 (наприклад, // сервер / шлях). Якби це було передано, 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
Чудове пояснення.
требор

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

Я знайшов наступний приклад баш-коду, щоб вибрати правильний двійковий файл на основі версії 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 ).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.