Zertifikate per Skript erzeugen

Alles rund um sicherheitsrelevante Fragen und Probleme.
Antworten
mod3

Zertifikate per Skript erzeugen

Beitrag von mod3 » 27.01.2017 10:51:29

Hallo zusammen,

schreibe mir gerade ein einfaches Skript, um in Zukunft eine CA mitsamt Server- und Clientzertifikaten zu erzeugen.
Habe u.A. eine Schleife, welche die Clients anlegen soll.
Komisch ist: Das funktioniert nicht. Nutze ich die selben Befehle jedoch händisch, klappt es einwandfrei:

Code: Alles auswählen

clients()
{
while read line
do
   clear
   echo "Erzeuge den Client" $line
   OPENSSL_CONF=openssl.cnf openssl req -new -sha512 -keyout new/key_$line.pem -out new/req_$line.pem
   OPENSSL_CONF=openssl.cnf openssl ca -out new/cert_$line.pem -infiles new/req_$line.pem
   OPENSSL_CONF=openssl.cnf openssl req -new -sha512 -keyout new/key_$line.pem -out new/req_$line.pem  OPENSSL_CONF=openssl.cnf openssl pkcs12 -export -in new/cert_$line.pem -inkey new/key_$line.pem -out export/cert_$line.p12 -clcerts
done < $clients
}
Beim Anlegen erhalte ich dann folgende Fehlermeldung:

Code: Alles auswählen

Erzeuge den Client hubert
Generating a 4096 bit RSA private key
....................................................................................................++
.....................++
writing new private key to 'new/key_hubert.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:string is too long, it needs to be less than  2 bytes long
Country Name (2 letter code) [AU]:string is too long, it needs to be less than  2 bytes long
Country Name (2 letter code) [AU]:problems making Certificate Request
Using configuration from openssl.cnf
Enter pass phrase for /server/test/CA/private/cakey.pem:
Habt ihr eine Idee? Wie gesagt: händisch klappt's einwandfrei.

mod3

Re: Zertifikate per Skript erzeugen

Beitrag von mod3 » 27.01.2017 12:21:24

Edit:

Ich werde übrigens garnicht erst gefragt, ob ich Daten wie etwa den Länder-Code eingeben möchte.
Es wird mir direkt gemeldet, der eingegebene sei zu kurz.
Bei händischem Ausführen werden alle Daten entsprechend meiner Vorgaben in der openssl.conf abgefragt.

breakthewall
Beiträge: 507
Registriert: 30.12.2016 23:48:51

Re: Zertifikate per Skript erzeugen

Beitrag von breakthewall » 29.01.2017 04:56:45

Hallo

Hab mir mal dein Shellscript angesehen, und ein paar Fehler vorgefunden. Als erstes sollte man Funktionen nicht wie Variablen aufrufen, mittels $VAR, sondern schlicht den Namen der Funktion außerhalb der Funktion schreiben. Zum anderen sollte man Variablen mit Doublequotes "$VAR" versehen, was die Variable vor Word-Splitting und Shell-Globbing schützt. Auch war eine der Kommandozeilen doppelt vorhanden, und wenn man schon Kommandozeilen hintereinander ausführen will, dann entweder via Semikolon trennen oder untereinander schreiben. Lediglich Leerzeichen dazwischen funktioniert nicht. Ebenso solltest darauf achten, dass die OpenSSL-Parameter korrekt geschrieben sind. Doch deine Variable OPENSSL_CONF ist in deinem Shellscript zwar definiert, aber wird soweit ersichtlich von nichts genutzt. Es reicht auch völlig sie einmal zu definieren, statt viermal. Ein local vor einer Variable ist sinnvoll in Funktionen, um eine Variable ausschließlich für diese Funktion verfügbar zu machen. Somit wäre sie nur für OpenSSL nutzbar, und nicht außerhalb der Funktion, was sinnvoll wäre bei z.B. sensiblen Inhalten.

Code: Alles auswählen

#! /bin/bash

clients() {
clear
while read -p "Neuen Clientnamen eingeben: " line
        do
            [ -z "$line" ] && echo "Leere Eingabe." && continue
            [[ ! "$line" =~ ^[[:alpha:]]{4,}$ ]] && echo "Ungültige Eingabe. (Minimum: 4 Zeichen, a-z|A-Z)" && continue
            echo "Erzeuge Client $line"
            local OPENSSL_CONF="openssl.cnf"
            openssl req -new -sha512 -keyout new/key_"$line".pem -out new/req_"$line".pem
            openssl ca -out new/cert_"$line".pem -infiles new/req_"$line".pem
            openssl pkcs12 -export -in new/cert_"$line".pem -inkey new/key_"$line".pem -out -export/cert_"$line".p12 -clcerts
            break
done
}

while true
        do

        clients

        clear
        read -p "Wollen Sie weitere Clients anlegen? (Y/N): " line
        case "$line" in
              y|Y)
                    continue;;
            *|n|N)
                    echo "Abbruch."
                    exit 0;;
        esac
done
Das wäre eine etwas erweiterte und robuster gestaltete Version. Einerseits um zwei Eingabe-Prüfungen ergänzt, der Robustheit wegen, damit nicht beliebige Werte an OpenSSL übergeben werden, die ggf. Fehlermeldungen provozieren könnten. Auch ein break wurde eingefügt, damit die while-Schleife nicht endlos läuft, wenn sie ohnehin keine Zertifikate automatisiert erstellen soll. Daher ein Abbruch nach dem ersten Client-Zertifikat, mit anschließender Frage wie weiter verfahren werden soll.
Zuletzt geändert von breakthewall am 29.01.2017 22:40:56, insgesamt 4-mal geändert.

mod3

Re: Zertifikate per Skript erzeugen

Beitrag von mod3 » 29.01.2017 10:14:18

Guten Morgen!

Super, ich bin immer dankbar für Anregungen im Bereich Shell-Programmierung, da das wirklich nicht meine Stärke ist ;-)
Mir war aber trotzdem natürlich klar, dass das Skript die reinste Schönwetter-Programmierung ist. Wäre in dem Fall nicht schlimm, ich bin ohnehin der Einzige, der es benutzt.
Die Eingabe über eine while-Schleife war aber schon so gedacht, da ich in einem txt-Dokument eine Liste mit Usern übergeben möchte, die angelegt werden sollen.
Hast du das Skript so schon getestet? Also werden dann auch wirklich die einzugebenden Werte abgefragt? Oder ist es zwar robuster, aber stürzt dafür an derselben Stelle ab?

Grüße

breakthewall
Beiträge: 507
Registriert: 30.12.2016 23:48:51

Re: Zertifikate per Skript erzeugen

Beitrag von breakthewall » 30.01.2017 01:14:18

mod3 hat geschrieben:Guten Morgen!

Super, ich bin immer dankbar für Anregungen im Bereich Shell-Programmierung, da das wirklich nicht meine Stärke ist ;-)
Müsste hier eine Korrektur einfließen lassen, aufgrund eines Fehlers meinerseits. Habe das Shellscript nochmals geändert, und die Variablen/Funktionen nun klein geschrieben. Ich persönlich mache das anders, was aber auch voraussetzt, dass man um Shellvariablen und Umgebungsvariablen weiß, um diese nicht versehentlich zu überschreiben. Mitunter kann das ungünstige Probleme verursachen, weshalb es gerade für Anfänger besser ist, Variablen/Funktionen klein zu schreiben. Eine Alternative wäre auch, einen Variablennamen wie _VAR="...." zu wählen, was aufgrund des vorangehenden Zeichens wieder sicher wäre.
mod3 hat geschrieben:Mir war aber trotzdem natürlich klar, dass das Skript die reinste Schönwetter-Programmierung ist. Wäre in dem Fall nicht schlimm, ich bin ohnehin der Einzige, der es benutzt.
War nur als Erläuterung gedacht, da es in Zukunft sicherlich auch noch andere oder komplexere Shellscripte geben wird, wo solche Sachverhalte ziemlich ernste Probleme verursachen können.
mod3 hat geschrieben:Die Eingabe über eine while-Schleife war aber schon so gedacht, da ich in einem txt-Dokument eine Liste mit Usern übergeben möchte, die angelegt werden sollen.
Wenn das so ist, dann wird eine Eingabe via read und while-Schleife völlig überflüssig. Dann würde sich eine for-Schleife anbieten, die die Liste einliest, und Punkt für Punkt die Namen übergibt.

Das könnte bspw. so aussehen:

Code: Alles auswählen

#! /bin/bash


file=$(cat file)
OPENSSL_CONF="openssl.cnf"

for name in "$file"
     do
         if [[ ! "$name" =~ ^[[:alpha:]]{4,}$ ]]
             then
                   echo
                   echo "Ungültiger Name $name wurde übersprungen."
                   continue
         fi
         echo
         echo ">>>>>>>> Erzeuge Client $name <<<<<<<<"
         echo
         openssl req -new -sha512 -keyout new/key_"$name".pem -out new/req_"$name".pem
         echo
         openssl ca -out new/cert_"$name".pem -infiles new/req_"$name".pem
         echo
         openssl pkcs12 -export -in new/cert_"$name".pem -inkey new/key_"$name".pem -out -export/cert_"$name".p12 -clcerts
         echo
         echo ">>>>>>>> Client $name wurde erzeugt <<<<<<<<"
         echo
done
mod3 hat geschrieben:Hast du das Skript so schon getestet? Also werden dann auch wirklich die einzugebenden Werte abgefragt? Oder ist es zwar robuster, aber stürzt dafür an derselben Stelle ab?

Grüße
An sich funktioniert das soweit bzw. mangels konfigurierter openssl.cnf und eigener CA, kommt eine andere Fehlermeldung auf. Da bei dir jedoch beides gegeben ist, dürftest entsprechend nach dem Passwort gefragt werden, um deine Zertifikate zu signieren. Am besten mal austesten. Ist längere Zeit her als ich mit OpenSSL zu tun hatte.

Code: Alles auswählen

140312908129408:error:0906406D:PEM routines:PEM_def_callback:problems getting password:crypto/pem/pem_lib.c:64:
140312908129408:error:0907E06F:PEM routines:do_pk8pkey:read key:crypto/pem/pem_pk8.c:83:

Using configuration from /usr/lib/ssl/openssl.cnf
Can't open ./demoCA/private/cakey.pem for reading, No such file or directory
139899318887552:error:02001002:system library:fopen:No such file or directory:crypto/bio/bss_file.c:74:fopen('./demoCA/private/cakey.pem','r')
139899318887552:error:2006D080:BIO routines:BIO_new_file:no such file:crypto/bio/bss_file.c:81:
unable to load CA private key

pkcs12: Cannot open input file new/cert_user.pem, No such file or directory
pkcs12: Use -help for summary.

mod3

Re: Zertifikate per Skript erzeugen

Beitrag von mod3 » 30.01.2017 17:39:53

Ich habe deine Funktion mal etwas angepasst:

Code: Alles auswählen

clients()
{
for name in "$clients"
     do
         if [[ ! "$name" =~ ^[[:alpha:]]{4,}$ ]]
             then
                   echo
                   echo "Ungültiger Name $name wurde übersprungen."
                   continue
         fi
         clear
         echo ">>>>>>>> Erzeuge Client $name <<<<<<<<"
         OPENSSL_CONF=openssl.cnf openssl req -new -sha512 -keyout new/"$name"_key.pem -out new/"$name"_req.pem
         OPENSSL_CONF=openssl.cnf openssl ca -out new/"$name"_cert.pem -infiles new/"$name"_req.pem
         OPENSSL_CONF=openssl.cnf openssl pkcs12 -export -in new/"$name"_cert.pem -inkey new/"$name"_key.pem -out export/"$name"_cert.p12 -clcerts
done
}
Sind aber nur kosmetische Änderungen. (Lass das OPENSSL_CONF für den Moment einfach mal dran, schad' ja nix).
Aber die if-Abfrage scheint falsch:

Code: Alles auswählen

./create_certs.sh 

Ungültiger Name peter
manfred
dietmar
horst wurde übersprungen.
Außerdem scheint er ja quasi alle Namen auf einmal einzulesen?
In der clients.txt steht in jeder Zeile einfach ein Name.

breakthewall
Beiträge: 507
Registriert: 30.12.2016 23:48:51

Re: Zertifikate per Skript erzeugen

Beitrag von breakthewall » 31.01.2017 00:28:04

mod3 hat geschrieben: Aber die if-Abfrage scheint falsch:

Code: Alles auswählen

./create_certs.sh 

Ungültiger Name peter
manfred
dietmar
horst wurde übersprungen.
Außerdem scheint er ja quasi alle Namen auf einmal einzulesen?
In der clients.txt steht in jeder Zeile einfach ein Name.
Richtig. Alle Namen werden auf einmal eingelesen, und pro Schleifendurchgang nacheinander abgearbeitet, bis nichts mehr vorhanden ist und die Schleife endet.

Wie schon gesagt, benötigst für so eine Aufgabe, weder eine Funktion noch eine while-Schleife. Kannst ganz weg lassen wenn nur eine Liste abarbeiten willst, für die eine for-Schleife prädestiniert wäre. Und das in eine Funktion zu packen macht wenig Sinn, wenn das Ganze im Shellscript nur einmalig pro Nutzung läuft. Hast dagegen Vorgänge, die sich wieder und wieder an etlichen Stellen in Shellscripten wiederholen müssen, dann sind Funktionen ausserordentlich praktisch.

Du scheinst das Shellscript mittels sh sprich Dash auszuführen, was so nicht funktioniert. Die Dash ist die Posix-Shell die sich gänzlich an allgemeine Standards hält. Jeglicher Code der damit ausführbar ist, ist auch entsprechend kompatibel zum Posix-Standard. Nur ein Konstrukt wie [[ "$VAR" =~ REGEX ]] ist eine Bash-Eigenheit und nicht posix-kompatibel. Um das korrekt auszuführen, lässt entweder die IF-Anweisung weg, oder startest das Shellscript mittels bash SHELLSCRIPT, oder du gibst dem Shellscript die Dateiendung .bash. Generell nicht vergessen im Shellscript die Shebang-Line auf die entsprechende Shell zu setzen, wie hier auf die #! /bin/bash.

Allgemein lässt sich aber sagen, dass die Dash zwar die eigentliche Posix-Shell ist, die zu mehreren Plattformen Kompatibilität schafft. Doch die Bash hat heute eine derartige Verbreitung, dass es kaum noch Plätze gibt wo sie nicht vorhanden wäre. Daher ist die Frage der Kompatibilität, nur noch in speziellen Fällen relevant.

Antworten