web-dev-qa-db-fra.com

Lancer Openssl à partir d'un script bash sous Windows - Le sujet ne commence pas par '/'

Dans mon script j'ai:

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}"

L'exécuter sur Windows dans Git Bash 3.1 donne:

Subject does not start with '/'.

Essayé d'échapper au sujet comme ça: -subj\"/ C = UK/ST = un endroit/L = Provo/O = Achme/CN = $ {FQDN} \"

Ça ne marche toujours pas. Des idées?

62
iss42

Ce problème est spécifique à MinGW/MSYS, qui est couramment utilisé dans le cadre du package Git pour Windows.

La solution consiste à passer l'argument -subj avec le préfixe // (doubles barres obliques), puis à utiliser \ (barres obliques inverses) pour séparer les paires clé/valeur. Comme ça:

"//O=Org\CN=Name"

Comme par magie, ceci sera passé à openssl sous la forme attendue:

"/O=Org/CN=Name"

Donc, pour répondre à la question spécifique, vous devez modifier la ligne -subj de votre script comme suit.

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

Cela devrait être tout ce dont vous avez besoin.

Quelle est cette magie?

Pour ceux qui sont curieux de savoir exactement ce qui se passe ici, je peux expliquer ce mystère. La raison en est que MSYS suppose raisonnablement que les arguments contenant des barres obliques sont en réalité des chemins. Et lorsque ces arguments sont passés à un exécutable qui n'a pas été compilé spécifiquement pour MSYS (comme openssl dans ce cas), il sera alors convertir les chemins POSIX en chemins Win32 . Les règles de cette conversion sont assez complexes car MSYS fait de son mieux pour couvrir les scénarios d'interopérabilité les plus courants. Cela explique également pourquoi l'utilisation de openssl à partir d'une commande Windows Invite (cmd.exe) fonctionne correctement, car aucune conversion magique n'est effectuée.

Vous pouvez tester la conversion comme ceci.

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

Nous ne pouvons pas utiliser l'exécutable echo fourni avec MSYS puisqu'il a été compilé pour MSYS; nous utiliserons plutôt le echo intégré dans cmd. Notez que puisque les commutateurs cmd commencent par / (commun aux commandes Windows), nous devons le gérer avec des doubles barres obliques. Comme nous pouvons le voir dans la sortie, l'argument a été étendu à un chemin Windows et nous comprenons pourquoi openssl prétend en effet que Subject does not start with '/'..

Voyons encore quelques conversions.

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

Les doubles barres obliques font croire à MSYS que l'argument est un commutateur de style Windows, ce qui entraîne la suppression d'un / uniquement (pas de conversion de chemin). On pourrait penser qu'avec cela, nous pourrions simplement utiliser des barres obliques pour ajouter plus de paires clé/valeur. Essayons ça.

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

Tout à coup, les doubles barres obliques au départ ne sont pas effacées. En effet, MSYS pense désormais que nous référons à un chemin UNC (par exemple, // serveur/chemin) après les barres doubles. Si ceci est passé à openssl, la première clé/valeur sera omise en disant Subject Attribute /O has no known NID, skipped.

Voici la règle pertinente du wiki de MinGW expliquant ce comportement:

  • Un argument commençant par 2 ou plus/est considéré comme un commutateur de style Windows échappé et sera passé avec le préfixe/supprimé et tous les\remplacés par /.
    • Sauf que s'il y a un/suivant le bloc de /, l'argument est considéré comme un chemin UNC et que le/ne est pas supprimé.

Dans cette règle, nous pouvons voir la méthode que nous pourrions utiliser pour créer l'argument que nous voulons. Puisque tous les \ qui suivent dans un argument commençant par // seront convertis en plain /. Essayons ça.

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

Et comme on peut le constater, cela fonctionne.

J'espère que cela démystifie un peu la magie.

144
Korroz

J'ai personnellement trouvé que cela était spécifique au binaire OpenSSL utilisé. Sur mon système utilisant msys2/mingw64, j'ai remarqué la présence de deux binaires OpenSSL différents, par exemple:

$ 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

Je crois que c'est l'utilisation de /mingw64/bin/openssl qui nécessite l'utilisation d'un sujet qui commence par //, mais je ne suis pas sûr que cela soit spécifique au package/build ou à la version d'OpenSSL. Pour être sûr, la version de chaque binaire est au dessous de:

$ 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

J'ai trouvé l'exemple suivant de code bash permettant de sélectionner le bon binaire basé sur la version OpenSSL lors de l'utilisation de msys/mingw pour travailler sur ma machine:

# 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

En plus de la résolution des problèmes liés à la transmission de la chaîne de sujet, j’ai également constaté que cette méthode permettait de résoudre les problèmes liés à la taille du nom distinctif (j’ai passé un openssl.cnf personnalisé avec une stratégie qui ne définissait pas de taille maximale pour aucun des champs et qui posait toujours des problèmes. en utilisant /mingw64/bin/openssl.exe).

0
Rob Frey