Na, Tobias ... Du bist genau der Richtige, der diese Anmerkung
bringt!!! Warum? Darum:
> Schlemmer / Agricolastr. 14-16, WGS 7109B |
>cand. math. / 09599 Freiberg
Ich schreibe im Rahmen meiner Dipl. Arbeit an der *TU Freiberg*
an einer Teilautomatisierung von CA-Aufgaben mit Hilfe von PHP.
Die CA soll PGP und X.509v3 Zertifikate ausstellen und selbst
durch die DFN-PCA zertifiziert werden.
>Hä? Versteh ich nicht. Gehts auch etwas genauer?
Klar: Ganz kurz:
*einfache* Quotes anstatt *doppelter* Quotes helfen, dass kein
Zeichen innerhalb der Quotes interpretiert wird.
Klar: Ganz lang: (Sorry, hab gar nicht gemerkt wie lang es wurde)
Ich bekomme nach der Prüfung eines Schlüssels und der
Nutzeranfrage (CA-Administrator) auf Zertifierung eben dieses
Schlüssels die Passphrase für den CA-Key per 'Post'. Diesen
gebe ich nun an die Funktion weiter, welche die PGP-Schlüssel
zertifiziert:
--- Main ---
$pass = HTTP_POST_VARS["pass"];
certify_pgp($sess_data, $pass);
--- Main ---
Dort füge ich ihn zum Keyring hinzu (-ka), stelle die Integrität
des Keyrings sicher (-kc) und schreite dann zum Heiligen Grahl:
der Zertifizierung (-ks). Die Passphrase kann ich übrigens nicht
weiter testen, außer dass sie ein string mit max. 255 Zeichen sein
muss. (Oder kann ich da noch was machen???) Gestern war dann mein
erster Versuch:
--- certify_pgp($data, $pass) ---
exec(escapeshellcmd(PGP." +batchmode -z \"$pass\" -ks \"$data[pgp_uid]\"),
$buffer, $retval); /\ /\ /\ /\
if($retval != 0) {
machwas_wegen_fehler();
}
--- certify_pgp() ---
Dabei hatte ich die Passphrase und die zu zertifizierende BenutzerID
in *doppelte* Quotes gesetzt. Das funkte nicht. Aus $irgenwas sollten
Variablen gemacht werden, aus '!!' wurde bangbang, etc.
>Ich glaube, Dein Problem liegt bei escapeshellcmd() die solltest Du
>nicht unbedingt verwenden. Stattdessen solltest Du selbst sicherstellen,
>dass die Eingabe keine gefährlichen Werte enthält. Vor allem würde ich
>nicht die gesamte Befehlszeile entschärfen, sondern nur das, wass Du da
>verwenden willst. Also statt
>system(escapeshellcmd("gpg -z 'Mikro $oft'"));
>würde ich
>
>system("gpg -z '".str_replace
> ("\","\\",str_replace("'","\'",'Mikro $oft'))."' -s ...");
>verwenden oder was noch Sichereres wie z.B. addslashes().
addslashes() hat mir (egal ob mit escapeshellcmd() oder ohne) die
Passphrase so entstellt, das Sie nicht mehr gültig war. Berichtige
mich, wenn ich falsch liege ... aber dein str_replace() gibt mir
folgendes:
gpg -z '\\'Mikro $oft\\'' -s ...
Das führt auch nicht zum Ziel. Anbei: bei GnuPG stellt -z die Kompressions-
stufe ein - bei PGP 2.6.3 gibt -z die Passphrase an. Ich muss leider noch
das alte PGP verwenden, da ich ja DFN-PCA zertifiziert werden möchte. Diese
unterstützt bislang nur V3 Signaturen. GnuPG macht V4. Die Scripte an gpg
anzupassen, sollte zu gegebener Zeit aber kein großes Problem darstellen.
>Eine ganz geniale Variante wäre natürlich, Du schickst das
>Passwort über eine Pipe. Man möge mich berichtigen, aber mir kommt das
>etwas sicherer vor. Da kann mein Mitbenutzer das Passwort nicht so ohne
>weiteres mittels "ps xa" rauskriegen.
Erstens: der zertifizierende Rechner ist ein Inselsystem. Er verfügt über
kein externes Netz. Mitbenutzer in diesem Sinne gibt es also nicht. Zweitens:
Dennoch sind gerade CA Passphrases extrem schützenswürdig. (...und sollten auch
auf einem Inselsystem in keiner history stehen!!!) Der Gedanke mit der Pipe
ist mir auch schon gekommen. Das macht pgp aber nicht mit. (Ich besprach das
schon einmal beim vorletzten Treffen mit ... Ich hab den Namen vergessen) :(
PGP will dann richtig interaktiv werden. Eine Lese/Schreibe pipe, die das Ganze
auch richtig interaktiv machen würde, gibt es aber nicht. Beispiel:
$pp = popen("pgp -ks $data[pgp_keyid]", "w"); /* write pipe open */
fputs($pp, $pass); /* Pass phrase hinterher */
pclose($pp); /* write pipe close */
gibt im error_log von Apache:
cannot open tty, using stdin
Unable to get terminal characteristics: ioctl: Inappropriate ioctl for device
Die Passphrase läuft damit total ins Leere.
Das Ganze irgendwie umzulenken ist mir auch nicht gelungen. Ausserdem habe ich
mit Lutz Donnerhacke gesprochen, der mir auch versicherte, dass es aus 'Religiösen'
Gründen auch nicht funktionieren soll. (Man könnte noch Umgebungsvariablen setzen,
die die Pass halten. Das will ich aber nicht.)
Ich habe dann gestern noch auf *einfache* Quotes umgestellt:
exec(PGP." +batchmode +force -z '$pass' -ks '$data[pgp_uid]'", $buffer, $retval);
Das Funktioniert nun... Naja, so gut wie... PGP gibt mit als return value, trotz
erfolgreichen signieren des Schlüssels, kein NULL sondern eine 4. Anfrage bei
Lutz Donnerhacke läuft bereits...
Tja, das ist die Ganze Erklärung. Wenn noch Fragen sind beantworte ich die gern.
Wenn Ihr irgendwo seht, wo in dieser Konstellation die Passphrase im Klartext auf
Platte kommt, so sagt mir bescheid ... und am Besten, wie ich es verhindern kann...
Bis denne,
Christian