Generieren Sie ein schwaches X509-Zertifikat

Ich muss ein schwaches Zertifikat für die CTF-Herausforderung mit RSA und kleinem Modul generieren, damit es faktorisierbar ist. Es sollten ungefähr 64 Bit sein.

Ich habe versucht, das mit OpenSSL zu generieren, wie ich es mit dem normalen tun würde, aber es verbietet aus Sicherheitsgründen das Erstellen eines Zertifikats mit einem Modul von weniger als 512 Bit. Also habe ich die Quelldateien von OpenSSL so geändert, dass die Bitlänge nicht überprüft wird, und das erneut kompiliert. Ich war dann in der Lage, einen privaten Schlüssel mit einem kleineren Modulus zu erstellen, aber der Versuch, ein Zertifikat mit diesem Schlüssel (oder einem neuen kleinen) zu erstellen, hat einen neuen Fehler hervorgerufen, den ich nicht vollständig verstehe. Ich wollte sogar das OpenSSL-Problem mit Python überhaupt umgehen, aber das zeigte nur, dass es auch OpenSSL verwendet und genau die gleichen Probleme hatte.

Kleinen privaten Schlüssel generieren:

$ openssl genrsa -out acn.pem 64
-----BEGIN PRIVATE KEY-----
MFQCAQAwDQYJKoZIhvcNAQEBBQAEQDA+AgEAAgkAlz0xJ3uUx5UCAwEAAQIIR1Zs
1Wo4EQECBQDHPJNVAgUAwlPjQQIFAKqNunkCBClt4QECBHlHx1Q=
-----END PRIVATE KEY-----

Zertifikat erstellen:

$ openssl req -key acn.pem -new -out domain.csr
...
140561480598848:error:04075070:rsa routines:RSA_sign:digest too big for rsa key:../crypto/rsa/rsa_sign.c:100:
140561480598848:error:0D0DC006:asn1 encoding routines:ASN1_item_sign_ctx:EVP lib:../crypto/asn1/a_sign.c:224:

Ich fand, dass dieser Thread hilfreich sein könnte, da ich sogar meine eigenen Nummern wählen konnte, aber die Methode hat bei mir nicht funktioniert:

Wie erzeuge ich RSA-Schlüssel mit bestimmten Eingabenummern in Openssl?

Hier ist ein Musterzertifikat von PicoCTF. Ich möchte ein ähnliches erstellen.

-----BEGIN CERTIFICATE-----
MIIB6zCB1AICMDkwDQYJKoZIhvcNAQECBQAwEjEQMA4GA1UEAxMHUGljb0NURjAe
Fw0xOTA3MDgwNzIxMThaFw0xOTA2MjYxNzM0MzhaMGcxEDAOBgNVBAsTB1BpY29D
VEYxEDAOBgNVBAoTB1BpY29DVEYxEDAOBgNVBAcTB1BpY29DVEYxEDAOBgNVBAgT
B1BpY29DVEYxCzAJBgNVBAYTAlVTMRAwDgYDVQQDEwdQaWNvQ1RGMCIwDQYJKoZI
hvcNAQEBBQADEQAwDgIHEaTUUhKxfwIDAQABMA0GCSqGSIb3DQEBAgUAA4IBAQAH
al1hMsGeBb3rd/Oq+7uDguueopOvDC864hrpdGubgtjv/hrIsph7FtxM2B4rkkyA
eIV708y31HIplCLruxFdspqvfGvLsCynkYfsY70i6I/dOA6l4Qq/NdmkPDx7edqO
T/zK4jhnRafebqJucXFH8Ak+G6ASNRWhKfFZJTWj5CoyTMIutLU9lDiTXng3rDU1
BhXg04ei1jvAf0UrtpeOA6jUyeCLaKDFRbrOm35xI79r28yO8ng1UAzTRclvkORt
b8LMxw7e+vdIntBGqf7T25PLn/MycGPPvNXyIsTzvvY/MXXJHnAqpI5DlqwzbRHz
q16/S1WLvzg4PsElmv1f
-----END CERTIFICATE-----

1
33
1

Antwort:

Gelöst

I need to generate weak certificate for CTF challenge using RSA and small modulus so it's factorable. It should be about 64 bits.

Als selbst signiert-Zertifikat ist dies nicht möglich, da eine ordnungsgemäße RSA-Signatur mit so kleinen Schlüsseln nicht funktionieren kann.

RSA-SSA-PKCS1_v1.5 ist die kürzeste strukturierte RSA-Signaturauffüllung und ist wie folgt strukturiert (gemäß https://datatracker.ietf.org/doc/html/rfc8017#section-9.2):

DigestInfo ::= SEQUENCE {
    digestAlgorithm AlgorithmIdentifier,
    digest OCTET STRING
}

Die kürzestmögliche Codierung für diese Struktur ist 9 Bytes ... und das mit einem 0-Byte-Hash-Algorithmus:

30 07 // SEQUENCE (7 content bytes)
   30 03 // digestAlgorithm: SEQUENCE (3 bytes)
      06 01 00 // OBJECT IDENTIFIER 0.0 ({itu-t(0) recommendation(0)})
      // omit implicit NULL
   04 00 // digest (empty)

Also müssen wir mit unserem leeren Hash weitermachen:

  1. If emLen < tLen + 11, output "intended encoded message length too short" and stop.

emLen ist die Länge des Moduls (in Bytes) und tLen ist die Länge unserer codierten Struktur (9 Bytes+).

Das macht 20 Byte (160 Bit) zum kürzestmöglichen RSA-Schlüssel, um alles zu tun, was eine Chance hat, als RSA-Signatur angesehen zu werden ... was eine sinnlose Signatur erzeugt (da alles unter einem 0-Bit-Hash kollidiert).

Wenn Sie bequem auf eine 1-Byte-OID für Ihre CTF stampfen, müsste Ihr RSA-Schlüsselmodul 20 Bytes + die Länge des beabsichtigten Hashs (in Bytes) betragen. Da es keine 1-Byte-OID gibt, die einen vorhandenen Hash-Algorithmus identifiziert (und keinen definierten Hash-Algorithmus zur Verwendung mit so kleinen Zertifikaten), kann dies kein vorhandenes einfach zu verwendendes Tool für Sie tun.


Sie könnten natürlich eine neue Form der RSA-Signaturauffüllung erfinden, indem Sie so etwas wie einen 60-Bit-Hash verwenden, der direkt mit Ihrem 64-Bit-Schlüssel verarbeitet wird. Das erfordert noch weitere Arbeit von Ihrer Seite.

Sie sind im Grunde darauf beschränkt, einen DER-Schreiber zu verwenden (oder Ihren eigenen zu schreiben), um ein Zertifikat von Hand zu erstellen.

Here's sample certificate from PicoCTF. I would like to create similar one.

Dieses Zertifikat ist nicht selbstsigniert. Es hat eine 2048-Bit-Zertifikatsignatur von RSA-SSA-PKCS1_v1.5 mit MD2. Während es also einen kurzen RSA-Schlüssel (53-Bit-Modulus) beschreibt, wurde es mit etwas "Richtigem" signiert. Wenn Sie danach suchen, wäre der allgemeine Ablauf so etwas wie

  • Erstellen Sie ein normales selbstsigniertes Zertifikat
  • Erstellen Sie Ihren kleinen RSA-Schlüssel
  • Erstellen Sie ein neues Zertifikat, das vom ersten Zertifikat signiert ist und den kleinen RSA-Schlüssel enthält.

Es ist schwierig, eine CSR für den kleinen Schlüssel zu codieren (weil er die Anfrage nicht selbst signieren kann), aber vielleicht gibt es eine Möglichkeit, openssl req -new dazu zu bringen, etwas anderes als die Selbstsignierung zu tun, was das Überspringen der Zwischen-CSR ermöglichen würde. (Oder verwenden Sie Bibliothekstools wie .NETs CertificateRequest oder die APIs von OpenSSL anstelle ihres CLI-Tools oder was auch immer.)