Ich dachte ja, ich mag PHP. Aber wenn man in solche Fallen wie heute rennt, hört das ganz schnell auf.
Folgendes Szenario: Ein Server (node.js) soll sich bei einem Client ausweisen. Also erstellt der Server eine Zufallszahl, signiert die, schickt die Zahl und die Signatur an den Client. Im Grunde so:
function generateNonce() {
return Math.floor(Math.random()*100001);
}
function generateSignature(nonce) {
var signer = crypto.createSign('RSA-SHA256');
signer.update(""+nonce);
var private_key = fs.readFileSync('./privateKey.pem', "utf8");
return signer.sign(private_key, output_format='base64');
}
Jetzt müsste nur noch der PHP-Client das mit dem PublicKey entschlüsseln und schauen, ob die Signatur gilt. Sollte ja nicht wirklich schwer sein, openssl kann das ja - doch die Dokumentation dazu ist unterstes Niveau. Dort wird nichtmal angegeben, in welchem Format (hex, base64?) die Signatur erwartet wird. Dank diesem (Signatur als reiner String, also selbst dekodieren) und diesem Kommentar (erklärt, im Gegensatz zur Dokumentation verständlich, wie man überhaupt Schlüssel lädt) ließ sich das jetzt nach Stunden des Ausprobierens so zusammensetzen:
$nonce = $_POST['nonce'];
$sig = base64_decode($_POST['sig']);
$publicKey = openssl_get_publickey(file_get_contents(dirname(__FILE__). '/publicKey.pem'));
$valid = openssl_verify($nonce, $sig, $publicKey, "RSA-SHA256");