Zum Inhalt springen
ecdsa.com

RSA-PSS vs. PKCS#1 v1.5: Padding für RSA-Signaturen

Dieselben RSA-Schlüssel, dieselben Größen, dasselbe Tempo. PSS hat einen Sicherheitsbeweis und ist für Handshakes in TLS 1.3 vorgeschrieben; PKCS#1 v1.5 ist überall im Einsatz, und bei korrekter Prüfung gibt es keinen praktischen Angriff darauf.

Bei RSA-PSS vs. PKCS#1 v1.5 geht es darum, wie ein Hash vor der RSA-Operation mit dem privaten Schlüssel kodiert wird. Beide stammen aus PKCS #1 (RFC 8017), beide sind in FIPS 186-5 zugelassen, und beide funktionieren mit demselben RSA-Schlüsselpaar. Sie unterscheiden sich in ihren Sicherheitsargumenten, in ihrem Determinismus und in den Parametern, die bei Signierer und Verifizierer übereinstimmen müssen.

Auf einen Blick

RSASSA-PSSRSASSA-PKCS1-v1_5
SpezifikationRFC 8017 §8.1, Kodierung EMSA-PSS §9.1RFC 8017 §8.2, Kodierung EMSA-PKCS1-v1_5 §9.2
KodierungHash mit Salt, maskiert mit MGF10x00 01 FF…FF 00 ‖ DigestInfo
RandomisiertJa (außer bei Salt-Länge 0)Nein: Gleicher Schlüssel und gleiche Nachricht ergeben dieselbe Signatur
SicherheitsbeweisEnge Reduktion auf RSA im Random-Oracle-ModellKein vergleichbarer Beweis; kein praktischer Angriff auf korrekte Verifizierer
Zu vereinbarende ParameterHash, MGF-Hash, Salt-Länge, TrailerNur der Hash
SignaturgrößeGröße des Moduls (256 Byte bei RSA-2048)Gleich
GeschwindigkeitGleiche RSA-OperationGleich
JOSEPS256, PS384, PS512 (Salt = Hashlänge)RS256, RS384, RS512
TLS 1.3Pflicht für CertificateVerify mit RSA (rsa_pss_rsae_sha256 0x0804, rsa_pss_pss_sha256 0x0809)Nur für Signaturen in Zertifikaten (rsa_pkcs1_sha256 0x0401)
X.509id-RSASSA-PSS 1.2.840.113549.1.1.10 mit Parameternsha256WithRSAEncryption 1.2.840.113549.1.1.11
Vorgabe in FIPS 186-5Salt-Länge zwischen 0 und der HashlängePrüfungen von DigestInfo in §5.4(h)

Unterschiede bei der Sicherheit

Das Signatur-Padding nach PKCS#1 v1.5 stammt aus dem Jahr 1991. Es ist deterministisch und hatte nie einen so sauberen Sicherheitsbeweis wie PSS, doch auch nach drei Jahrzehnten gibt es keinen praktischen Fälschungsangriff auf Verifizierer, die den gesamten kodierten Block prüfen. Die Brüche in der Praxis waren Implementierungsfehler: Bleichenbachers Angriff von 2006 fälschte Signaturen für den öffentlichen Exponenten 3 und zielte auf Parser, die überzählige Bytes hinter der Struktur DigestInfo ignorierten, und Varianten dieses Fehlers tauchten in Bibliotheken wie NSS (BERserk, 2014) und anderen wieder auf. RFC 8017 §8.2.2 vermeidet die ganze Fehlerklasse, indem es den erwarteten Block neu kodiert und die Bytes vergleicht, und FIPS 186-5 §5.4(h) schreibt die Prüfungen fest.

RSASSA-PSS (Bellare und Rogaway, standardisiert in PKCS #1 v2.1, 2002) hasht ein zufälliges Salt zusammen mit dem Hash der Nachricht und maskiert das Ergebnis mit MGF1. Seine Sicherheit lässt sich im Random-Oracle-Modell eng auf das RSA-Problem reduzieren, und dank der Randomisierung verrät ein Rechenfehler oder ein Seitenkanal bei einer einzelnen Signatur weniger. Mit einem Salt der Länge null wird PSS deterministisch, behält seinen Beweis aber unter leicht anderen Annahmen.

Verwechsle keines der beiden mit dem Padding von PKCS #1 v1.5 für die Verschlüsselung, das durch Padding-Oracle-Angriffe (Bleichenbacher 1998, ROBOT 2017) tatsächlich gebrochen ist und aus TLS 1.3 entfernt wurde. Signatur-Padding und Verschlüsselungs-Padding sind getrennte Verfahren, die sich den Namen teilen.

Interoperabilität: die Falle mit der Salt-Länge

Bei PSS müssen sich Signierer und Verifizierer auf drei Parameter einigen: den Hash, den MGF1-Hash und die Salt-Länge. JOSE legt alle drei fest (PS256 bedeutet SHA-256, MGF1-SHA-256 und ein 32-Byte-Salt), und TLS 1.3 verlangt, dass die Salt-Länge der Hashlänge entspricht. Überall sonst musst du nachprüfen: OpenSSL 1.1.1 und 3.0 signierten standardmäßig mit dem maximalen Salt (222 Byte bei RSA-2048 mit SHA-256), während OpenSSL 3.1 und neuer standardmäßig auto-digestmax verwenden, was ein Salt in der Größe des Digests ergibt. Verifizierer, die auf eine feste Salt-Länge eingestellt sind, lehnen dann Signaturen der jeweils anderen Generation ab.

Das folgende Skript, ausgeführt mit OpenSSL 3.6.5, zeigt beide Effekte.

OpenSSL: Determinismus und Prüfung der PSS-Salt-Länge
#!/bin/sh
dir=$(mktemp -d)
cd "$dir" || exit 1
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:2048 -out key.pem 2>/dev/null
openssl pkey -in key.pem -pubout -out pub.pem
printf 'hello' > msg

openssl dgst -sha256 -sign key.pem -out v15a.sig msg
openssl dgst -sha256 -sign key.pem -out v15b.sig msg
cmp -s v15a.sig v15b.sig && echo "PKCS#1 v1.5: identical signatures" || echo "PKCS#1 v1.5: different signatures"

openssl dgst -sha256 -sign key.pem -sigopt rsa_padding_mode:pss -out pssa.sig msg
openssl dgst -sha256 -sign key.pem -sigopt rsa_padding_mode:pss -out pssb.sig msg
cmp -s pssa.sig pssb.sig && echo "PSS: identical signatures" || echo "PSS: different signatures"

for saltlen in digest max; do
  printf 'verify PSS with rsa_pss_saltlen:%s -> ' "$saltlen"
  openssl dgst -sha256 -verify pub.pem -sigopt rsa_padding_mode:pss \
    -sigopt "rsa_pss_saltlen:$saltlen" -signature pssa.sig msg 2>&1 | grep -o -E "Verified OK|salt length check failed"
done
cd / && rm -rf "$dir"
Ausgabe
PKCS#1 v1.5: identical signatures
PSS: different signatures
verify PSS with rsa_pss_saltlen:digest -> Verified OK
verify PSS with rsa_pss_saltlen:max -> salt length check failed

Verifizierer, die auto akzeptieren, erkennen die Salt-Länge anhand der Signatur; das ist die kompatibelste Einstellung, wenn der Signierer nicht in deiner Hand liegt.

Schlüssel und Zertifikate

Derselbe RSA-Schlüssel kann beide Arten von Signaturen erzeugen, und ein Schlüssel vom Typ rsaEncryption in einem Zertifikat ist für beide nutzbar (TLS nennt das rsa_pss_rsae). X.509 definiert außerdem Schlüssel vom Typ id-RSASSA-PSS, deren Parameter sie auf PSS beschränken (rsa_pss_pss in TLS); sie verhindern, dass ein Schlüssel für beide Verfahren genutzt wird. Viele Tools und manche Browser kommen aber schlecht mit ihnen zurecht. Die praktische Wahl sind daher Schlüssel vom Typ rsaEncryption, die mit PSS signieren. Zertifikatssignaturen in der WebPKI nutzen fast ausnahmslos PKCS#1 v1.5 oder ECDSA, und schon deshalb müssen Verifizierer v1.5 unterstützen.

Wann welches Verfahren passt

  • Handshakes in TLS 1.3: PSS, verpflichtend; deine Bibliothek erledigt das bei jedem RSA-Zertifikat automatisch.
  • JWTs: PS256, wenn alle Empfänger es unterstützen, sonst RS256; noch besser: Zieh ES256 in Betracht (siehe ES256 vs. RS256).
  • X.509-Zertifikate und CRLs, die du ausstellst: PKCS#1 v1.5 (sha256WithRSAEncryption) für maximale Kompatibilität, es sei denn, ein geschlossenes Ökosystem hat sich auf PSS festgelegt.
  • Neue Signaturen für Dokumente, Firmware oder APIs mit RSA-Schlüsseln: PSS mit einer Salt-Länge, die der Hashlänge entspricht.
  • Interoperabilität mit HSMs und Cloud-KMS: Beide werden unterstützt (zum Beispiel RSASSA_PSS_SHA_256 und RSASSA_PKCS1_V1_5_SHA_256 in AWS KMS); richte dich nach den Erwartungen des Verifizierers.
  • Prüfung bei beiden Verfahren: Nutze die High-Level-Prüffunktion einer Bibliothek und dekodiere die kodierte Nachricht nie von Hand.

Hinweise zur Migration

Der Umstieg von v1.5 auf PSS braucht keine neuen Schlüssel und lässt sich deshalb leicht schrittweise umsetzen.

  1. Bring zuerst den Verifizierern PSS bei: Erlaube in JOSE PS256 für den Schlüssel (weiterhin gilt die Regel „ein Algorithmus pro Schlüssel“, veröffentliche also dasselbe Schlüsselmaterial unter einem neuen Wert für kid mit PS256 als alg, oder rotiere den Schlüssel).
  2. Lege die Parameter ausdrücklich fest: Hash SHA-256, MGF1 SHA-256, Salt-Länge 32 Byte; vermeide Standardwerte von Bibliotheken, die sich von Version zu Version unterscheiden.
  3. Stelle die Signierer um und achte auf Fehler bei der Prüfung, die die Salt-Länge oder das Padding erwähnen.
  4. Akzeptiere v1.5 nicht mehr für diese Schlüssel, sobald alte Signaturen abgelaufen sind, und behalte v1.5 nur dort, wo Zertifikate oder Dritte es verlangen.
  5. Wenn du die Schlüssel ohnehin rotierst, erwäge stattdessen ECDSA P-256 oder Ed25519: Beide sind kleiner und signieren schneller als RSA mit jedem beliebigen Padding.

Quellen

Alle Vergleiche