Erstellen Sie sichere Netzwerkanwendungen mit Zertifikaten, Teil 2

Um sichere Anwendungen zu erstellen, müssen Sie die Werkzeuge des Handels erlernen. Um Sie mit diesen Konzepten vertraut zu machen, habe ich Sie in Teil 1 mit der Kryptografie mit öffentlichen Schlüsseln vertraut gemacht und erläutert, wie die mit der Kryptografie mit geheimen Schlüsseln verbundenen Probleme beim Schlüsselaustausch vermieden werden. Ich untersuchte auch die Beziehung zwischen Vertrauen und der Skalierbarkeit der Kryptografie mit öffentlichem Schlüssel und erklärte, wie Zertifikate und eine Public-Key-Infrastruktur (PKI) Vertrauen in einem größeren Maßstab ermöglichen, als es die Kryptografie mit öffentlichem Schlüssel allein erreichen kann. Schließlich habe ich Zertifikate und Zertifikatsketten beschrieben und erklärt, wie sie sich auf Zertifizierungsstellen (Zertifizierungsstellen) beziehen.

Es stehen viele verschiedene Arten von Zertifikaten zur Verfügung, darunter SDSI (einfache verteilte Sicherheitsinfrastruktur), PGP (ziemlich guter Datenschutz) und X.509. Um Ihr Sicherheitsvokabular weiter zu erweitern, werde ich diesen Monat das Zertifikatformat beschreiben, das das Paket anführt und eine Schlüsselkomponente der aufkommenden PKI-Standards darstellt: das X.509-Zertifikat.

Sie können die ganze Serie auf Zertifikaten lesen:

  • Teil 1: Zertifikate bieten einen Mehrwert für die Kryptografie mit öffentlichen Schlüsseln
  • Teil 2: Erfahren Sie, wie Sie die X.509-Zertifikate verwenden
  • Teil 3: Verwenden Sie die Klassen Java CRL und X509CRL
  • Teil 4: Authentifizieren Sie Clients und Server und überprüfen Sie die Zertifikatketten

Das X.509-Format im Detail

Die International Telecommunication Union (ITU) hat das X.509-Zertifikatformat entwickelt und veröffentlicht, das von der Arbeitsgruppe Public Key Infrastructure X.509 (PKIX) der Internet Engineering Task Force (IETF) ausgewählt wurde. Wenn Akronyme Stärke anzeigen, hat X.509 eindeutig mächtige Verbündete.

Unter Verwendung einer Notation namens ASN.1 (Abstract Syntax Notation One) definiert der X.509-Standard das Format eines Zertifikats. ASN.1 ist eine standardisierte Sprache, die abstrakte Datentypen plattformunabhängig beschreibt.

Das von der PKIX-Arbeitsgruppe veröffentlichte Dokument "Internet X.509 Public Key Infrastructure - Zertifikat und CRL-Profil" (siehe Ressourcen für einen Link) beschreibt ein X.509-Zertifikatformat in Bezug auf die ASN.1-Notation. Es ist eine faszinierende Lektüre, wenn Sie an so etwas interessiert sind.

Ein in ASN.1 definierter Datentyp - beispielsweise ein Zertifikat - ist erst dann nützlich, wenn eindeutig definiert werden kann, wie eine Instanz eines Datentyps als eine Reihe von Bits dargestellt werden soll. Um dem Datentyp diese Funktionalität zu verleihen, verwendet ASN.1 die Distinguished Encoding Rules (DER), die definieren, wie ein ASN.1-Objekt eindeutig codiert wird.

Mit einer Kopie der ASN.1-Definition eines X.509-Zertifikats und Kenntnissen des DER können Sie eine Java-Anwendung schreiben, die X.509-Zertifikate liest und schreibt und mit ähnlichen Anwendungen zusammenarbeitet, die in anderen Programmiersprachen geschrieben sind. Glücklicherweise werden Sie wahrscheinlich nie so viele Probleme haben, da die Java 2 Platform Standard Edition (J2SE) eine integrierte Unterstützung für X.509-Zertifikate bietet.

X.509 für (fast) nichts

Alle zertifikatbezogenen Klassen und Schnittstellen befinden sich im Paket java.security.cert. Wie die anderen Mitglieder der Sun-Familie von Sicherheits-APIs wurde das Zertifikatspaket nach dem Factory-Paradigma entwickelt, bei dem eine oder mehrere Java-Klassen eine generische Schnittstelle zur beabsichtigten Funktionalität eines Pakets definieren. Die Klassen sind abstrakt, sodass Anwendungen sie nicht direkt instanziieren können. Stattdessen erstellt die Instanz einer Factory-Klasse Instanzen der bestimmten Untertypen der abstrakten Klassen und gibt sie zurück. Das Factory-Paradigma umgeht die starke Typisierung von Java, ermöglicht jedoch im Gegenzug die Ausführung des Codes ohne Neukompilierung in einem breiteren Bereich von Umgebungen.

Die Klassen java.security.cert.Certificateund java.security.cert.CRLabstract definieren die Schnittstelle. Sie repräsentieren Zertifikate bzw. Zertifikatsperrlisten (CRLs). Die CertificateFactoryKlasse ist ihre Fabrik.

Das java.security.certPaket enthält konkrete Implementierungen der Klassen Certificateund CRLabstract: the X509Certificateund X509CRLclasses. Diese beiden Klassen implementieren grundlegende Zertifikat- und CRL-Funktionen und erweitern sie dann um X.509-spezifische Funktionen. Wenn eine CertificateFactoryInstanz eine Instanz einer der Klassen zurückgibt, kann ein Programm sie entweder unverändert verwenden oder explizit in das X.509-Formular umwandeln.

Im java.security.certPaket X509Extensiondefiniert die Schnittstelle eine Schnittstelle zu den Erweiterungen eines X.509-Zertifikats. Erweiterungen sind optionale Komponenten, die Zertifikatserstellern einen Mechanismus bieten, um einem Zertifikat zusätzliche Informationen zuzuordnen. Beispielsweise kann ein Zertifikat die KeyUsageErweiterung verwenden, um anzugeben, dass es für die Codesignatur verwendet werden kann.

Das java.security.certPaket enthält auch eine SPI-Klasse (Service Provider Interface). Ein kryptografischer Dienstanbieter , der einen Zertifikatstyp unterstützen möchte, erweitert das SPI. Java 2 wird mit einem SPI für X.509-Zertifikate geliefert.

Schauen wir uns die Klassen und Schnittstellen im java.security.certPaket genauer an . Der Kürze halber werde ich nur die nützlichsten Methoden diskutieren. Für eine umfassendere Berichterstattung empfehle ich Ihnen, die Dokumentation von Sun zu lesen. (Siehe Ressourcen.)

java.security.cert.CertificateFactory

Die Geschichte beginnt mit java.security.cert.CertificateFactory. Die CertificateFactoryKlasse verfügt über statische Methoden, die eine CertificateFactoryInstanz für einen bestimmten Zertifikatstyp erstellen, und über Methoden, mit denen sowohl Zertifikate als auch CRLs aus Daten erstellt werden, die in einem Eingabestream bereitgestellt werden. Ich werde kurz die wichtigsten Methoden beschreiben und dann erklären, wie diese Methoden beim Generieren von X.509-Zertifikaten und CRLs verwendet werden. Später in diesem Artikel werde ich Code vorstellen, der die Methoden in Aktion demonstriert.

  • public static CertificateFactory getInstance(String stringType)und public static CertificateFactory getInstance(String stringType, String stringProvider)instantiate und gibt eine Instanz eines Zertifikat Fabrik für den Zertifikattyp durch den angegebenen stringTypeParameter. Wenn der Wert von stringTypebeispielsweise die Zeichenfolge "X.509" ist, geben beide Methoden eine Instanz der CertificateFactoryKlasse zurück, die zum Erstellen von Instanzen der Klassen X509Certificateund geeignet ist X509CRL. Die zweite Methode akzeptiert den Namen eines bestimmten kryptografischen Dienstanbieters als Argument und verwendet diesen Anbieter anstelle des Standardanbieters.
  • public final Certificate generateCertificate(InputStream inputstream)Instanziiert und gibt ein Zertifikat mit Daten zurück, die von der angegebenen InputStreamInstanz gelesen wurden . Wenn der Stream mehr als ein Zertifikat enthält und der Stream die Operationen mark()und reset()unterstützt, liest die Methode ein Zertifikat und lässt den Stream vor dem nächsten positioniert.
  • public final Collection generateCertificates(InputStream inputstream)Instanziiert und gibt eine Zertifikatsammlung mit Daten zurück, die von der bereitgestellten InputStreamInstanz gelesen wurden . Wenn der gegebene Strom nicht unterstützt mark()und reset()wird das Verfahren des gesamten Strom verbrauchen.
  • public final CRL generateCRL(InputStream inputstream)instanziiert und gibt eine CRL mit Daten zurück, die von der angegebenen InputStreamInstanz gelesen wurden . Wenn der Strom mehr als eine CRL und Träger enthält die mark()und reset()Operationen wird das Verfahren eine CRL lesen und den Strom vor dem nächsten positioniert verlassen.
  • public final Collection generateCRLs(InputStream inputstream)Instanziiert und gibt eine Sammlung von CRLs zurück, indem Daten verwendet werden, die von der bereitgestellten InputStreamInstanz gelesen wurden . Wenn der angegebene Stream nicht unterstützt mark()und reset(), public final Collection generateCRLs(InputStream inputstream)wird der gesamte Stream verbraucht.

Es ist wichtig zu verstehen, wie sich diese vier Methoden verhalten, wenn X.509-Instanzen aus einem Datenstrom generiert werden. Lass uns einen Blick darauf werfen.

Die Methoden generateCertificate()und generateCRL()erwarten, dass der Inhalt des Eingabestreams DER-codierte Darstellungen eines Zertifikats bzw. einer CRL enthält.

Sowohl die generateCertificates()als auch die generateCRLs()Methoden erwarten, dass der Inhalt des Eingabestreams entweder eine Folge von DER-codierten Darstellungen oder ein PKCS # 7-Zertifikat (Public-Key Cryptography Standard # 7) oder einen CRL-Satz enthält. (Links finden Sie unter Ressourcen.)

java.security.cert.Certificate

java.security.cert.CertificateDefiniert die Schnittstelle, die allen Arten von Zertifikaten gemeinsam ist: X.509, PGP und eine kleine Handvoll anderer. Die wichtigsten Methoden dieser Klasse sind:

  • public abstract PublicKey getPublicKey() Gibt den öffentlichen Schlüssel zurück, der sich auf die Zertifikatinstanz bezieht, für die diese Methode aufgerufen wird.
  • public abstract byte [] getEncoded() Gibt das verschlüsselte Formular dieses Zertifikats zurück.
  • public abstract void verify(PublicKey publickey)und public abstract void verify(PublicKey publickey, String stringProvider)überprüfen Sie, ob der private Schlüssel, der dem angegebenen öffentlichen Schlüssel entspricht, das betreffende Zertifikat signiert hat. Wenn die Schlüssel nicht übereinstimmen, werfen beide Methoden a SignatureException.

java.security.cert.X509Certificate

Die Klasse java.security.cert.X509Certificateerweitert die Certficateoben beschriebene Klasse und fügt X.509-spezifische Funktionen hinzu. Diese Klasse ist wichtig, da Sie normalerweise mit Zertifikaten auf dieser Ebene interagieren, nicht als Basisklasse.

  • public abstract byte [] getEncoded()Gibt die verschlüsselte Form dieses Zertifikats wie oben zurück. Die Methode verwendet die DER-Codierung für das Zertifikat.

Die meisten java.security.cert.X509Certificatezusätzlichen Funktionen bestehen aus Abfragemethoden, die Informationen zum Zertifikat zurückgeben. Ich habe die meisten dieser Informationen in Teil 1 vorgestellt. Hier sind die Methoden:

  • public abstract int getVersion() Gibt die Version des Zertifikats zurück.
  • public abstract Principal getSubjectDN() Gibt Informationen zurück, die den Betreff des Zertifikats identifizieren.
  • public abstract Principal getIssuerDN() Gibt Informationen zurück, die den Aussteller des Zertifikats identifizieren, bei dem es sich normalerweise um die Zertifizierungsstelle handelt. Sie können jedoch Gegenstand sein, wenn das Zertifikat selbst signiert ist.
  • public abstract Date getNotBefore()und public abstract Date getNotAfter()Rückgabewerte, die den Zeitraum einschränken, in dem der Emittent bereit ist, für den öffentlichen Schlüssel des Subjekts zu bürgen.
  • public abstract BigInteger getSerialNumber()Gibt die Seriennummer des Zertifikats zurück. Die Kombination aus dem Ausstellernamen und der Seriennummer eines Zertifikats ist seine eindeutige Identifikation. Diese Tatsache ist entscheidend für den Widerruf von Zertifikaten, auf die ich nächsten Monat näher eingehen werde.
  • public abstract String getSigAlgName()und public abstract String getSigAlgOID()Informationen über den Algorithmus zurückgeben, der zum Signieren des Zertifikats verwendet wird.

Die folgenden Methoden geben Informationen zu den für das Zertifikat definierten Erweiterungen zurück. Denken Sie daran, dass Erweiterungen Mechanismen zum Zuordnen von Informationen zu einem Zertifikat sind. Sie erscheinen nur auf Zertifikaten der Version 3.

  • public abstract int getBasicConstraints()Gibt die Länge des Einschränkungspfads eines Zertifikats von der BasicConstraintsErweiterung zurück, falls definiert. Der Einschränkungspfad gibt die maximale Anzahl von CA-Zertifikaten an, die diesem Zertifikat in einem Zertifizierungspfad folgen dürfen.
  • public abstract boolean [] getKeyUsage()Gibt den in der KeyUsageErweiterung codierten Zweck des Zertifikats zurück .
  • public Set getCriticalExtensionOIDs()und public Set getNonCriticalExtensionOIDs()eine Sammlung von Objektkennungen (OIDs) für die als kritisch bzw. unkritisch gekennzeichneten Erweiterungen zurückgeben. Eine OID ist eine Folge von Ganzzahlen, die eine Ressource universell identifizieren.

Ich möchte Sie nicht ohne Code zum Spielen belassen. Anstatt mich mit CRLs zu befassen, die ein komplettes Thema für sich sind, werde ich den Code präsentieren und CRLs für Teil 3 belassen.

Der Code

Die folgende Klasse zeigt, wie Sie eine Zertifikatfactory erhalten, wie Sie mit dieser Factory ein Zertifikat aus der DER-codierten Darstellung in einer Datei generieren und wie Sie Informationen zum Zertifikat extrahieren und anzeigen. Sie werden feststellen, wie wenig Sie sich um die zugrunde liegende Codierung kümmern müssen.