Certificate Transparency mit OpenSSL

vorhergehende Artikel in: PKI-X.509-CA Linux
17.06.2023

Ich wollte schon lange einmal ausprobieren, ob ich das Konzept der Certificate Transparency (Logs) auf meine Lösung zur Verwaltung von PKI anwenden könnte.

Das würde natürlich bedeuten, dass dieses Konzept auf einfache Art und Weise mit OpenSSL funktionieren müsste. Ich weiß bereits, dass sich die entsprechende Poison Extension wie folgt in eine OpenSSL-Konfiguration integrieren lässt:

1.3.6.1.4.1.11129.2.4.3                = critical,ASN1:NULL:

Stellt man ein solches Zertifikat aus, kann man dieses dann an ein Certificate Transparency Log senden und erhält einen Signed Certificate Timestamps (SCT) zurück. Diesen gilt es anschließend in das eigentliche Endnutzer-Zertifikat zu integrieren und sobald dieses ausgestellt ist dem Endnutzer zuzuleiten.

Dieser gesamtw Workflow ist konzeptionell zum Beispiel hier ausführlich und sehr gut beschrieben.

Nun bestand die Frage, wie ich nachprüfen könnte, dass meine Experimente wirklich zum Ziel führen? Nun - wenn man sich Zertifikate herunterlädt und sie mittels der folgenden Kommandozeile

x509 -noout -text -in <some_cert.crt>

analysiert sieht man, dass OpenSSL weiß, was SCTs sind und sie entsprechend darstellt:

#...
X509v3 Basic Constraints:
	CA:FALSE
CT Precertificate SCTs:
	Signed Certificate Timestamp:
		Version   : v1 (0x0)
		Log ID    : DF:1C:2E:C1:15:00:94:52:47:A9:61:68:32:5D:DC:5C:
					79:59:E8:F7:C6:D3:88:FC:00:2E:0B:BD:3F:74:D7:64
		Timestamp : Apr  5 17:04:16.275 2013 GMT
		Extensions: none
		Signature : ecdsa-with-SHA256
					30:45:02:20:48:2F:67:51:AF:35:DB:A6:54:36:BE:1F:
					D6:64:0F:3D:BF:9A:41:42:94:95:92:45:30:28:8F:A3:
					E5:E2:3E:06:02:21:00:E4:ED:C0:DB:3A:C5:72:B1:E2:
					F5:E8:AB:6A:68:06:53:98:7D:CF:41:02:7D:FE:FF:A1:
					05:51:9D:89:ED:BF:08
Signature Algorithm: sha1WithRSAEncryption
#...

Bei einem der OpenSource-Projekte von Google findet man diverse Testdaten - unter anderem ein Zertifikat (einen Teil dessen Inhalts sahen wir oben) und ein SCT in Binärform. Wie kann man nun ein solches SCT in Binärform in die OpenSSL-Konfiguration integrieren, so dass ein Zertifikat entsteht, bei dem OpenSSL (und andere) das SCT korrekt extrahieren und verifizieren können?

Ich versuchte zunächst, das SCT mittels

hexdump -v -e '/1 "%02X"' /tmp/test-cert.proof >>sctextvalue.txt

in einen Hexadezimalstring umzuwandeln und ihn in die OpenSSL-Konfiguration einzufügen. Das reichte jedoch nicht - OpenSSL erkannte diese Daten nicht als SCT. Weitere Recherchen ergaben, dass SCTs in Zertifikaten in TLS-Kodierung vorliegen müssen - das, was ich als SCT vorliegen hatte, erfüllte diese Bedingung noch nicht: Der rohe SCT enthält die reinen Daten, die für die Integration in ein x509-Zertifikat notwendige Struktur muss darüber hinaus noch die Länge der Liste und jedes einzelnen SCTs darin enthalten. Ein sehr schönes Beispiel für die Kodierung findet man hier.

Ich benutzte dazu folgendes Skript, das den Namen des Binär-SCTs übergeben bekommt und den String für die Integration in OpenSSL-Konfigurationen auf der Standardausgabe ausgibt:

#!/bin/bash
sctlen=$(ls -l "$1" |cut -d ' ' -f 5)
sctlistlen=$(($sctlen + 2))
echo -n $(printf "%04x" $sctlistlen)>sctextvalue.txt
echo -n $(printf "%04x" $sctlen)>>sctextvalue.txt
hexdump -v -e '/1 "%02X"' "$1" >>sctextvalue.txt

Damit konnte ich eines meiner Zertifikate mit diesem vorgefertigten SCT vereinigen und OpenSSL erkannte diesen SCT daraufhin und zeigte mir die Daten wie im oben dargestellten Beispiel an.

Nun wollte ich aber auch den kompletten Prozess abbilden und selbst SCTs für meine eigenen Zertifikate erzeugen können. Dazu brauchte ich zunächst einmal mein eigenes Log, da öffentliche Logs Zertifikate nur annehmen, wenn die Wurzel der Kette des Vertrauens bei ihnen akkreditiert ist. Da dieser Prozess langwierig und sein Erfolg nicht sicher ist, suchte ich nach einer anderen Möglichkeit.

Und ich fand sie: Auf GitHub existiert dieses Repository, in dem jemand die Log-Lösung von Google in einen Container gepackt hat. Diesem Container muss man lediglich die Menge aller akkreditierten Root-Zertifikate und einen privaten Schlüssel über ein Volume zugänglich machen und schon hat mein sein persönliches Certificate Transparency Log.

Also erstellte ich ein Zertifikat für Testzwecke mit Poison Extension und sendete es mittels curl an den dafür vorgesehenen API-Endpunkt des Logs. Als Antwort erhielt ich eine JSON-Datenstruktur wie folgt:

{
"sct_version": 0,
"id": "RHVweYnWHXxK59iKUgBfC5FmPVfucw3JyLCDSeK3tTs=",
"timestamp": 1682764453410,
"extensions": "",
"signature": "BAECADZ8KJtSBips+ZEgyrFaejDoohxQcaM+qrXkl9VBcwN2GjhtVrq4DmIQkuFCQ6GuZ\/n6+spE50HK5T0gQSFENZzKlhyut9+HRPb14CKFVoSuKhxlMf5ppcDv\/fNLPINE7zXu\/oQU0bs\/Vk5pB7N14lIdSsOS69O1G5quyDNHOB2EMW1UjwRMklYmZFiqNiGzp8\/f+KdMpd6wjej9YRrpbXiMX2JYXdUxWrU4h1WO3gFVe58UKE2WroAlCC6Sf7dHJtl1yTqg8rlxXtvbolaABAF\/T6XVnszQwBM5\/1HYb0jlDPLxnwEMz\/\/36yHeH\/KCR\/5sMEN6eFJGB3K+6MdVIxxX0YLG7v0I2nr0pAFTO35usTMJB23SaT61ui3p06R69pUS3EnuIbGSC8wcxP5aezPcfZia1sEhBDLxMV3YyaywFyl\/uj3F0M9KRSdVrper4hHzYMwPduU5lc3d8yMEMlGG3VteZbH0NViWvwn2a+U0XhL7ZEV9\/h5Dh\/BfyEAeakRKaZUSCQs3fgWEENHYJ7tm4r6d6R85vW5cHfskcHuVd3sVTtNopY0l\/RB\/KNe+rEC9tGib70VWy9iBRgdo6STQ3y4peRtiw5IFBqCK+TxhZH04YW5Jb7T3VwpMhVnAhfRc\/DC3cSLbUq4PoedjP9zYRgT+5VSFBLr3VqURB2ot"
}

Wie man sieht, sieht das völlig anders aus als der Binär-SCT den ich bis dahin zum Testen benutzt hatte. Ich musste die enthaltenen Daten also zunächst in die Binärform umwandeln und diesen dann als SCTList wieder in die OpenSSL-Konfiguration integrieren.

Dazu war es zunächst nötig, den timestamp hexadezimal darzustellen - in unserem Beispiel ergäbe das entsprechende Kommando printf "%016x" 1682764453410 das Ergebnis 00000187cc93d622.

Anschließend gilt es, die beiden Werte id und signature aus ihrer Base64-Kodierung zu befreien und ebenfalls hexadezimal zu kodieren. Dazu wird der Befehl echo -n "RHVweYnWHXxK59iKUgBfC5FmPVfucw3JyLCDSeK3tTs=" | base64 -d |hexdump -v -e '/1 "%02X"' benutzt, dessen Ergebnisse hier zu sehen sind:

4475707989D61D7C4AE7D88A52005F0B91663D57EE730DC9C8B08349E2B7B53B

04010200367C289B52062A6CF99120CAB15A7A30E8A21C5071A33EAAB5E497D5417303761A386D56BAB80E621092E14243A1AE67F9FAFACA44E741CAE53D20412144359CCA961CAEB7DF8744F6F5E022855684AE2A1C6531FE69A5C0EFFDF34B3C8344EF35EEFE8414D1BB3F564E6907B375E2521D4AC392EBD3B51B9AAEC83347381D84316D548F044C9256266458AA3621B3A7CFDFF8A74CA5DEB08DE8FD611AE96D788C5F62585DD5315AB53887558EDE01557B9F14284D96AE8025082E927FB74726D975C93AA0F2B9715EDBDBA2568004017F4FA5D59ECCD0C01339FF51D86F48E50CF2F19F010CCFFFF7EB21DE1FF28247FE6C30437A7852460772BEE8C755231C57D182C6EEFD08DA7AF4A401533B7E6EB13309076DD2693EB5BA2DE9D3A47AF69512DC49EE21B1920BCC1CC4FE5A7B33DC7D989AD6C1210432F1315DD8C9ACB017297FBA3DC5D0CF4A452755AE97ABE211F360CC0F76E53995CDDDF32304325186DD5B5E65B1F4355896BF09F66BE5345E12FB64457DFE1E4387F05FC8401E6A444A699512090B377E058410D1D827BB66E2BE9DE91F39BD6E5C1DFB24707B95777B154ED368A58D25FD107F28D7BEAC40BDB4689BEF4556CBD881460768E924D0DF2E29791B62C3920506A08AF93C61647D38616E496FB4F7570A4C8559C085F45CFC30B77122DB52AE0FA1E7633FDCD84604FEE5548504BAF756A511076A2D

Mit diesen Angaben und denen zu den verwendeten Algorithmen und den Längen der einzelnen Einträge und der SCTList insgesamt ergeben sich folgende Aneinanderreihungen von Angaben für den Wert der Extension:

0235	#size of the structure
0233	#is the length of the SCT that follows (SignedCertificateTimestamp structure)
00		#is the version of the protocol (v1 = 0 decimal for RFC6962
4475707989D61D7C4AE7D88A52005F0B91663D57EE730DC9C8B08349E2B7B53B	#is the LogID, that is the SHA-256 hash of the DER-encoded public key of the CT log
00000187CC93D622	#timestamp value (milliseconds since epoch)
0000	#is the length of the extensions, not present
0403	#are two bytes that describe the signatures algorithms used for hashing (0x04 = SHA-256) and signing (0x03 = ECDSA)
0204	#is the length of the signature
04010200367C289B52062A6CF99120CAB15A7A30E8A21C5071A33EAAB5E497D5417303761A386D56BAB80E621092E14243A1AE67F9FAFACA44E741CAE53D20412144359CCA961CAEB7DF8744F6F5E022855684AE2A1C6531FE69A5C0EFFDF34B3C8344EF35EEFE8414D1BB3F564E6907B375E2521D4AC392EBD3B51B9AAEC83347381D84316D548F044C9256266458AA3621B3A7CFDFF8A74CA5DEB08DE8FD611AE96D788C5F62585DD5315AB53887558EDE01557B9F14284D96AE8025082E927FB74726D975C93AA0F2B9715EDBDBA2568004017F4FA5D59ECCD0C01339FF51D86F48E50CF2F19F010CCFFFF7EB21DE1FF28247FE6C30437A7852460772BEE8C755231C57D182C6EEFD08DA7AF4A401533B7E6EB13309076DD2693EB5BA2DE9D3A47AF69512DC49EE21B1920BCC1CC4FE5A7B33DC7D989AD6C1210432F1315DD8C9ACB017297FBA3DC5D0CF4A452755AE97ABE211F360CC0F76E53995CDDDF32304325186DD5B5E65B1F4355896BF09F66BE5345E12FB64457DFE1E4387F05FC8401E6A444A699512090B377E058410D1D827BB66E2BE9DE91F39BD6E5C1DFB24707B95777B154ED368A58D25FD107F28D7BEAC40BDB4689BEF4556CBD881460768E924D0DF2E29791B62C3920506A08AF93C61647D38616E496FB4F7570A4C8559C085F45CFC30B77122DB52AE0FA1E7633FDCD84604FEE5548504BAF756A511076A2D	#the signature itself

Setzt man das aneinandergereiht als Extension 1.3.6.1.4.1.11129.2.4.2 an der entsprechenden Stelle in der OpenSSL-Konfiguration zur Signierung von Zertifikaten ein,

1.3.6.1.4.1.11129.2.4.2 = ASN1:FORMAT:HEX,OCTETSTRING:02350233004475707989D61D7C4AE7D88A52005F0B91663D57EE730DC9C8B08349E2B7B53B000001
87CC93D62200000403020404010200367C289B52062A6CF99120CAB15A7A30E8A21C5071A33EAAB5E497D5417303761A386D56BAB80E621092E14243A1AE67F9FAFACA
44E741CAE53D20412144359CCA961CAEB7DF8744F6F5E022855684AE2A1C6531FE69A5C0EFFDF34B3C8344EF35EEFE8414D1BB3F564E6907B375E2521D4AC392EBD3B5
1B9AAEC83347381D84316D548F044C9256266458AA3621B3A7CFDFF8A74CA5DEB08DE8FD611AE96D788C5F62585DD5315AB53887558EDE01557B9F14284D96AE802508
2E927FB74726D975C93AA0F2B9715EDBDBA2568004017F4FA5D59ECCD0C01339FF51D86F48E50CF2F19F010CCFFFF7EB21DE1FF28247FE6C30437A7852460772BEE8C7
55231C57D182C6EEFD08DA7AF4A401533B7E6EB13309076DD2693EB5BA2DE9D3A47AF69512DC49EE21B1920BCC1CC4FE5A7B33DC7D989AD6C1210432F1315DD8C9ACB0
17297FBA3DC5D0CF4A452755AE97ABE211F360CC0F76E53995CDDDF32304325186DD5B5E65B1F4355896BF09F66BE5345E12FB64457DFE1E4387F05FC8401E6A444A69
9512090B377E058410D1D827BB66E2BE9DE91F39BD6E5C1DFB24707B95777B154ED368A58D25FD107F28D7BEAC40BDB4689BEF4556CBD881460768E924D0DF2E29791B
62C3920506A08AF93C61647D38616E496FB4F7570A4C8559C085F45CFC30B77122DB52AE0FA1E7633FDCD84604FEE5548504BAF756A511076A2D

erhält man ein Zertifikat, das - wiederum mit OpenSSL betrachtet - den erwarteten Inhalt aufweist:

CT Precertificate SCTs:
	Signed Certificate Timestamp:
		Version   : v1 (0x0)
		Log ID    : 44:75:70:79:89:D6:1D:7C:4A:E7:D8:8A:52:00:5F:0B:
					91:66:3D:57:EE:73:0D:C9:C8:B0:83:49:E2:B7:B5:3B
		Timestamp : Apr 29 10:34:13.410 2023 GMT
		Extensions: none
		Signature : ecdsa-with-SHA256
					04:01:02:00:36:7C:28:9B:52:06:2A:6C:F9:91:20:CA:
					B1:5A:7A:30:E8:A2:1C:50:71:A3:3E:AA:B5:E4:97:D5:
					41:73:03:76:1A:38:6D:56:BA:B8:0E:62:10:92:E1:42:
					43:A1:AE:67:F9:FA:FA:CA:44:E7:41:CA:E5:3D:20:41:
					21:44:35:9C:CA:96:1C:AE:B7:DF:87:44:F6:F5:E0:22:
					85:56:84:AE:2A:1C:65:31:FE:69:A5:C0:EF:FD:F3:4B:
					3C:83:44:EF:35:EE:FE:84:14:D1:BB:3F:56:4E:69:07:
					B3:75:E2:52:1D:4A:C3:92:EB:D3:B5:1B:9A:AE:C8:33:
					47:38:1D:84:31:6D:54:8F:04:4C:92:56:26:64:58:AA:
					36:21:B3:A7:CF:DF:F8:A7:4C:A5:DE:B0:8D:E8:FD:61:
					1A:E9:6D:78:8C:5F:62:58:5D:D5:31:5A:B5:38:87:55:
					8E:DE:01:55:7B:9F:14:28:4D:96:AE:80:25:08:2E:92:
					7F:B7:47:26:D9:75:C9:3A:A0:F2:B9:71:5E:DB:DB:A2:
					56:80:04:01:7F:4F:A5:D5:9E:CC:D0:C0:13:39:FF:51:
					D8:6F:48:E5:0C:F2:F1:9F:01:0C:CF:FF:F7:EB:21:DE:
					1F:F2:82:47:FE:6C:30:43:7A:78:52:46:07:72:BE:E8:
					C7:55:23:1C:57:D1:82:C6:EE:FD:08:DA:7A:F4:A4:01:
					53:3B:7E:6E:B1:33:09:07:6D:D2:69:3E:B5:BA:2D:E9:
					D3:A4:7A:F6:95:12:DC:49:EE:21:B1:92:0B:CC:1C:C4:
					FE:5A:7B:33:DC:7D:98:9A:D6:C1:21:04:32:F1:31:5D:
					D8:C9:AC:B0:17:29:7F:BA:3D:C5:D0:CF:4A:45:27:55:
					AE:97:AB:E2:11:F3:60:CC:0F:76:E5:39:95:CD:DD:F3:
					23:04:32:51:86:DD:5B:5E:65:B1:F4:35:58:96:BF:09:
					F6:6B:E5:34:5E:12:FB:64:45:7D:FE:1E:43:87:F0:5F:
					C8:40:1E:6A:44:4A:69:95:12:09:0B:37:7E:05:84:10:
					D1:D8:27:BB:66:E2:BE:9D:E9:1F:39:BD:6E:5C:1D:FB:
					24:70:7B:95:77:7B:15:4E:D3:68:A5:8D:25:FD:10:7F:
					28:D7:BE:AC:40:BD:B4:68:9B:EF:45:56:CB:D8:81:46:
					07:68:E9:24:D0:DF:2E:29:79:1B:62:C3:92:05:06:A0:
					8A:F9:3C:61:64:7D:38:61:6E:49:6F:B4:F7:57:0A:4C:
					85:59:C0:85:F4:5C:FC:30:B7:71:22:DB:52:AE:0F:A1:
					E7:63:3F:DC:D8:46:04:FE:E5:54:85:04:BA:F7:56:A5:
					11:07:6A:2D
X509v3 Subject Alternative Name:

Alle Artikel rss Wochenübersicht Monatsübersicht Github Repositories Gitlab Repositories Mastodon Über mich home xmpp


Vor 5 Jahren hier im Blog

  • Certstream, InfluxDB, Grafana und Netflix

    16.04.2019

    Nachdem ich vor kurzem über mein erstes Spielen mit dem certstream berichtete, habe ich weitere Experimente gemacht und die Daten zur besseren Auswertung in eine InfluxDB gepackt, um sie mit Grafana untersuchen zu können.

    Weiterlesen...

Neueste Artikel

  • Die sQLshell ist nun cloudnative!

    Die sQLshell hat eine weitere Integration erfahren - obwohl ich eigentlich selber nicht viel dazu tun musste: Es existiert ein Projekt/Produkt namens steampipe, dessen Slogan ist select * from cloud; - Im Prinzip eine Wrapperschicht um diverse (laut Eigenwerbung mehr als 140) (cloud) data sources.

    Weiterlesen...
  • LinkCollections 2024 III

    Nach der letzten losen Zusammenstellung (für mich) interessanter Links aus den Tiefen des Internet von 2024 folgt hier gleich die nächste:

    Weiterlesen...
  • Funktionen mit mehreren Rückgabewerten in Java

    Da ich seit nunmehr einem Jahr bei meinem neeun Arbeitgeber beschäftigt und damit seit ungefähr derselben Zeit für Geld mit Python arbeite, haben sich gewisse Antipathien gegenüber Python vertieft (ich kann mit typlosen Sprachen einfach nicht umgehen) - aber auch einige meiner Gründe, Python zu lieben sind ebenso stärker geworden. Einer davon ist der Fakt, dass eine Methode in Python mehr als einen Wert zurückgeben kann.

    Weiterlesen...

Manche nennen es Blog, manche Web-Seite - ich schreibe hier hin und wieder über meine Erlebnisse, Rückschläge und Erleuchtungen bei meinen Hobbies.

Wer daran teilhaben und eventuell sogar davon profitieren möchte, muß damit leben, daß ich hin und wieder kleine Ausflüge in Bereiche mache, die nichts mit IT, Administration oder Softwareentwicklung zu tun haben.

Ich wünsche allen Lesern viel Spaß und hin und wieder einen kleinen AHA!-Effekt...

PS: Meine öffentlichen GitHub-Repositories findet man hier - meine öffentlichen GitLab-Repositories finden sich dagegen hier.