Konstruera säkra nätverksapplikationer med certifikat, del 2

För att bygga säkra applikationer måste du lära dig verktygen i branschen. För att hjälpa dig att bekanta dig med dessa begrepp introducerade jag dig till kryptografi med public key i del 1 och förklarade hur det undviker nyckelutbytesproblemen som åtföljer kryptografi med secret key. Jag undersökte också förhållandet mellan förtroende och skalbarheten för kryptografi med public key och förklarade hur certifikat och en PKI (public key key infrastructure) möjliggör förtroende i större skala än kryptografi med public key kan uppnå på egen hand. Slutligen beskrev jag certifikat och certifikatkedjor och förklarade hur de relaterar till certifikatutfärdare.

Många olika varianter av certifikat finns tillgängliga, inklusive SDSI (enkel distribuerad säkerhetsinfrastruktur), PGP (ganska bra integritet) och X.509. Den här månaden, för att ytterligare utöka ditt säkerhetsordförråd, kommer jag att beskriva certifikatformatet som leder paketet och är en nyckelkomponent i de framväxande PKI-standarderna: X.509-certifikatet.

Du kan läsa hela serien om certifikat:

  • Del 1: Certifikat lägger till värde i kryptografi med public key
  • Del 2: Lär dig att använda X.509-certifikaten
  • Del 3: Använd klasserna Java CRL och X509CRL
  • Del 4: Autentisera klienter och servrar och verifiera certifikatkedjor

X.509-formatet i detalj

International Telecommunication Union (ITU) utvecklade och publicerade certifikatformatet X.509, som valdes av Public Key Infrastructure X.509 (PKIX) arbetsgrupp för Internet Engineering Task Force (IETF). Om akronymer anger styrka har X.509 tydligt kraftfulla allierade.

Med hjälp av en notation som heter ASN.1 (Abstract Syntax Notation One) definierar X.509-standarden ett certifikats format. ASN.1 är ett standardiserat språk som beskriver abstrakta datatyper på ett plattformsoberoende sätt.

Dokumentet "Internet X.509 Public Key Infrastructure - Certificate and CRL Profile" (se Resurser för en länk) publicerad av PKIX-arbetsgruppen beskriver ett X.509-certifikatformat i termer av ASN.1-notering. Det är en fascinerande läsning om du är intresserad av den typen av saker.

En datatyp - som ett certifikat - definierad i ASN.1 är inte användbar förrän den otvetydigt kan definiera hur en förekomst av en datatyp ska representeras som en serie bitar. För att ge datatypen den funktionaliteten använder ASN.1 Distinguished Encoding Rules (DER), som definierar hur man unikt kodar alla ASN.1-objekt.

Med en kopia av ett X.509-certifikats ASN.1-definition och kunskap om DER kan du skriva ett Java-program som läser och skriver X.509-certifikat och samverkar med liknande applikationer skrivna på andra programmeringsspråk. Lyckligtvis kommer du förmodligen aldrig att behöva göra så mycket besvär eftersom Java 2 Platform, Standard Edition (J2SE) levereras med inbyggt stöd för X.509-certifikat.

X.509 för (nästan) ingenting

Alla certifikatrelaterade klasser och gränssnitt finns i paketet java.security.cert. Liksom de andra medlemmarna i Suns familj av säkerhets-API: er utformades certifikatpaketet runt fabriksparadigmet, där en eller flera Java-klasser definierar ett generiskt gränssnitt för ett paketets avsedda funktionalitet. Klasserna är abstrakta, så applikationer kan inte initiera dem direkt. Istället skapar och returnerar en fabriksklass instanser av abstraktklassernas särskilda undertyper. Fabriksparadigmet kringgår Java: s starka typning, men i gengäld tillåter koden att köras utan rekompilering i ett bredare spektrum av miljöer.

Den java.security.cert.Certificateoch java.security.cert.CRLabstrakta klasser definierar gränssnittet. De representerar certifikat respektive certifikatåterkallningslistor (CRL). Den CertificateFactoryklassen är deras fabrik.

I java.security.certPaketet innehåller konkreta implementeringar av Certificateoch CRLabstrakta klasser: den X509Certificateoch X509CRLklasser. Dessa två klasser implementerar grundcertifikat och CRL-funktionalitet och utökar det sedan med X.509-specifik funktionalitet. När en CertificateFactoryinstans returnerar en instans av endera klassen kan ett program antingen använda den som den är eller uttryckligen kasta den till X.509-formuläret.

I java.security.certpaketet X509Extensiondefinierar gränssnittet ett gränssnitt till ett X.509-certifikats tillägg. Tillägg är valfria komponenter som ger en mekanism för certifikatskapare att associera ytterligare information till ett certifikat. Till exempel kan ett certifikat använda KeyUsagetillägget för att indikera att det kan användas för kodsignering.

I java.security.certpaketet ingår även en tjänsteleverantör Interface (SPI) klass. En kryptografisk tjänsteleverantör som vill stödja en certifikattyp utökar SPI. Java 2 levereras med ett SPI för X.509-certifikat.

Låt oss ta en mer detaljerad titt på klasserna och gränssnitten i java.security.certpaketet. För korthetens skull kommer jag bara att diskutera de mest användbara metoderna. För mer omfattande täckning rekommenderar jag att du läser Suns dokumentation. (Se resurser.)

java.security.cert.CertificateFactory

Historien börjar med java.security.cert.CertificateFactory. Den CertificateFactoryklass har statiska metoder som skapar en CertificateFactoryinstans för en specifik typ av certifikat, och metoder som skapar både certifikat och CRL: er från uppgifter i en inmatningsström. Jag kommer kort att beskriva de viktigaste metoderna och sedan förklara hur man använder dessa metoder när jag genererar X.509-certifikat och CRL. Senare i artikeln presenterar jag kod som visar metoderna i aktion.

  • public static CertificateFactory getInstance(String stringType)och public static CertificateFactory getInstance(String stringType, String stringProvider)instansera och returnera en instans av en certifikatfabrik för den certifikattyp som anges av stringTypeparametern. Om värdet till exempel stringTypeär strängen "X.509" returnerar båda metoderna en instans av CertificateFactoryklassen som är lämplig för att skapa instanser av klasserna X509Certificateoch X509CRL. Den andra metoden accepterar namnet på en specifik kryptografisk tjänsteleverantör som ett argument och använder den leverantören istället för standard.
  • public final Certificate generateCertificate(InputStream inputstream)startar och returnerar ett certifikat med hjälp av data som läses från den medföljande InputStreaminstansen. Om strömmen innehåller mer än ett certifikat och strömmen stöder mark()och reset()-operationerna läser metoden ett certifikat och lämnar strömmen placerad före nästa.
  • public final Collection generateCertificates(InputStream inputstream)startar och returnerar en certifikatsamling med hjälp av data som lästs från den medföljande InputStreaminstansen. Om den givna strömmen inte stöder mark()och reset()metoden förbrukar hela strömmen.
  • public final CRL generateCRL(InputStream inputstream)startar och returnerar en CRL med hjälp av data som läses från den medföljande InputStreaminstansen. Om strömmen innehåller mer än en CRL och stöder mark()och reset()-operationerna läser metoden en CRL och lämnar strömmen placerad före nästa.
  • public final Collection generateCRLs(InputStream inputstream)startar och returnerar en samling CRL: er med hjälp av data som lästs från den medföljande InputStreaminstansen. Om den givna strömmen inte stöder mark()och reset(), public final Collection generateCRLs(InputStream inputstream)kommer att förbruka hela strömmen.

Det är viktigt att förstå hur dessa fyra metoder beter sig när man genererar X.509-instanser från en dataström. Låt oss ta en titt.

Den generateCertificate()och generateCRL()metoder förväntar ingångsströmmen innehåll för att innehålla DER-kodade representationer av ett certifikat eller en CRL, respektive.

Både generateCertificates()och generateCRLs()metoderna förväntar sig att innehållet i ingångsströmmen innehåller antingen en sekvens av DER-kodade representationer eller ett PKCS # 7 (Public-Key Cryptography Standard # 7) -kompatibelt certifikat eller CRL-uppsättning. (Se Resurser för länkar.)

java.security.cert.Certificate

java.security.cert.Certificatedefinierar gränssnittet som är gemensamt för alla typer av certifikat: X.509, PGP och en liten handfull andra. Den här klassens viktigaste metoder är:

  • public abstract PublicKey getPublicKey() returnerar den offentliga nyckeln som är relaterad till certifikatinstansen där den här metoden anropas.
  • public abstract byte [] getEncoded() returnerar certifikatets kodade formulär.
  • public abstract void verify(PublicKey publickey)och public abstract void verify(PublicKey publickey, String stringProvider)verifiera att den privata nyckeln som motsvarar den levererade offentliga nyckeln undertecknade certifikatet i fråga. Om tangenterna inte matchar, kasta båda metoderna a SignatureException.

java.security.cert.X509Certificate

Klassen java.security.cert.X509Certificateutökar Certficateklassen som beskrivs ovan och lägger till X.509-specifik funktionalitet. Den här klassen är viktig eftersom du vanligtvis interagerar med certifikat på denna nivå, inte som basklassen.

  • public abstract byte [] getEncoded()returnerar den kodade formen för certifikatet, som ovan. Metoden använder DER-kodningen för certifikatet.

De flesta av dess java.security.cert.X509Certificateextra funktioner består av frågemetoder som returnerar information om certifikatet. Jag presenterade det mesta av den informationen i del 1. Här är metoderna:

  • public abstract int getVersion() returnerar certifikatets version.
  • public abstract Principal getSubjectDN() returnerar information som identifierar certifikatets ämne.
  • public abstract Principal getIssuerDN() returnerar information som identifierar certifikatets utfärdare, som vanligtvis är CA, men kan vara ämnet om certifikatet är självsignerat.
  • public abstract Date getNotBefore()och public abstract Date getNotAfter()returnera värden som begränsar den tidsperiod under vilken emittenten är villig att garantera ämnets offentliga nyckel.
  • public abstract BigInteger getSerialNumber()returnerar certifikatets serienummer. Kombinationen av certifikatets utfärdarnamn och serienummer är dess unika identifikation. Det faktum är avgörande för att återkalla certifikat, vilket jag kommer att diskutera mer detaljerat nästa månad.
  • public abstract String getSigAlgName()och public abstract String getSigAlgOID()returnera information om algoritmen som används för att underteckna certifikatet.

Följande metoder returnerar information om de tillägg som definierats för certifikatet. Kom ihåg att tillägg är mekanismer för att associera information till ett certifikat. de visas bara på version 3-certifikat.

  • public abstract int getBasicConstraints()returnerar längden på ett certifikats begränsningssökväg från BasicConstraintstillägget, om det är definierat. Begränsningsvägen anger det maximala antalet CA-certifikat som kan följa detta certifikat i en certifieringssökväg.
  • public abstract boolean [] getKeyUsage()returnerar syftet med certifikatet som kodat i KeyUsagetillägget.
  • public Set getCriticalExtensionOIDs()och public Set getNonCriticalExtensionOIDs()returnera en samling objektidentifierare (OID) för tilläggen markerade som kritiska respektive icke-kritiska. En OID är en sekvens av heltal som universellt identifierar en resurs.

Jag vill inte lämna dig utan kod att leka med, så i stället för att gräva i CRL, vilket är ett komplett ämne på egen hand, presenterar jag koden och lämnar CRL för del 3.

Koden

Följande klass visar hur man skaffar ett certifikatfabrik, hur man använder fabriken för att generera ett certifikat från den DER-kodade representationen i en fil och hur man extraherar och visar information om certifikatet. Du kommer att märka hur lite du behöver oroa dig för den underliggande kodningen.