Costruisci applicazioni di rete sicure con certificati, Parte 2

Per creare applicazioni sicure, devi imparare gli strumenti del mestiere. Per aiutarti a familiarizzare con questi concetti, ti ho introdotto alla crittografia a chiave pubblica nella Parte 1 e ho spiegato come evita i problemi di scambio di chiavi che accompagnano la crittografia a chiave segreta. Ho anche esplorato la relazione tra fiducia e scalabilità della crittografia a chiave pubblica e ho spiegato come i certificati e un'infrastruttura a chiave pubblica (PKI) consentono la fiducia su una scala più ampia di quella che la crittografia a chiave pubblica può ottenere da sola. Infine, ho descritto i certificati e le catene di certificati e ho spiegato come si riferiscono alle CA (autorità di certificazione).

Sono disponibili molti tipi diversi di certificati, inclusi SDSI (semplice infrastruttura di sicurezza distribuita), PGP (privacy piuttosto buona) e X.509. Questo mese, per espandere ulteriormente il tuo vocabolario sulla sicurezza, descriverò il formato del certificato che guida il pacchetto ed è un componente chiave degli standard PKI emergenti: il certificato X.509.

Puoi leggere l'intera serie sui certificati:

  • Parte 1: i certificati aggiungono valore alla crittografia a chiave pubblica
  • Parte 2: impara a utilizzare i certificati X.509
  • Parte 3: utilizzare le classi Java CRL e X509CRL
  • Parte 4: autenticare client e server e verificare le catene di certificati

Il formato X.509 in dettaglio

L'International Telecommunication Union (ITU) ha sviluppato e pubblicato il formato del certificato X.509, che è stato selezionato dal gruppo di lavoro Public Key Infrastructure X.509 (PKIX) dell'Internet Engineering Task Force (IETF). Se gli acronimi indicano forza, X.509 ha chiaramente potenti alleati.

Utilizzando una notazione chiamata ASN.1 (Abstract Syntax Notation One), lo standard X.509 definisce il formato di un certificato. ASN.1 è un linguaggio standardizzato che descrive i tipi di dati astratti in modo indipendente dalla piattaforma.

Il documento "Internet X.509 Public Key Infrastructure - Certificate and CRL Profile" (vedere Risorse per un collegamento) pubblicato dal gruppo di lavoro PKIX descrive un formato di certificato X.509 in termini di notazione ASN.1. È una lettura affascinante se sei interessato a questo genere di cose.

Un tipo di dati, come un certificato, definito in ASN.1 non è utile fino a quando non può definire in modo univoco come rappresentare un'istanza di un tipo di dati come una serie di bit. Per fornire al tipo di dati tale funzionalità, ASN.1 utilizza le Distinguished Encoding Rules (DER), che definiscono come codificare in modo univoco qualsiasi oggetto ASN.1.

Con una copia della definizione ASN.1 di un certificato X.509 e una conoscenza del DER, è possibile scrivere un'applicazione Java che leggerà e scriverà certificati X.509 e interagirà con applicazioni simili scritte in altri linguaggi di programmazione. Fortunatamente, probabilmente non dovrai mai darti così tanti problemi perché Java 2 Platform, Standard Edition (J2SE) viene fornito con il supporto integrato per i certificati X.509.

X.509 per (quasi) niente

Tutte le classi e le interfacce relative al certificato risiedono nel pacchetto java.security.cert. Come gli altri membri della famiglia di API di sicurezza di Sun, il pacchetto del certificato è stato progettato attorno al paradigma di fabbrica, in cui una o più classi Java definiscono un'interfaccia generica per la funzionalità prevista di un pacchetto. Le classi sono astratte, quindi le applicazioni non possono istanziarle direttamente. Invece, l'istanza di una classe factory crea e restituisce istanze dei sottotipi particolari delle classi astratte. Il paradigma di fabbrica elude la forte digitazione di Java, ma in cambio consente al codice di essere eseguito senza ricompilazione in una gamma più ampia di ambienti.

Le classi java.security.cert.Certificatee java.security.cert.CRLabstract definiscono l'interfaccia. Rappresentano rispettivamente i certificati e gli elenchi di revoca dei certificati (CRL). La CertificateFactoryclasse è la loro fabbrica.

Il java.security.certpacchetto contiene implementazioni concrete delle classi astratte Certificatee CRL: le classi X509Certificatee X509CRL. Queste due classi implementano il certificato di base e la funzionalità CRL, quindi le estendono con funzionalità specifiche di X.509. Quando CertificateFactoryun'istanza restituisce un'istanza di una delle classi, un programma può usarla così com'è o eseguirne il cast esplicito nel modulo X.509.

Nel java.security.certpacchetto, l'interfaccia X509Extensiondefinisce un'interfaccia per le estensioni di un certificato X.509. Le estensioni sono componenti opzionali che forniscono un meccanismo ai creatori di certificati per associare informazioni aggiuntive a un certificato. Ad esempio, un certificato può utilizzare l' KeyUsageestensione per indicare che può essere utilizzato per la firma del codice.

Il java.security.certpacchetto include anche una classe SPI (Service Provider Interface). Un fornitore di servizi crittografici che desidera supportare un tipo di certificato estende l'SPI. Java 2 viene fornito con uno SPI per i certificati X.509.

Diamo uno sguardo più dettagliato alle classi e alle interfacce nel java.security.certpacchetto. Per brevità, tratterò solo i metodi più utili. Per una copertura più completa, vi incoraggio a leggere la documentazione di Sun. (Vedi risorse.)

java.security.cert.CertificateFactory

La storia inizia con java.security.cert.CertificateFactory. La CertificateFactoryclasse ha metodi statici che creano CertificateFactoryun'istanza per un tipo specifico di certificato e metodi che creano sia certificati che CRL dai dati forniti in un flusso di input. Descriverò brevemente i metodi più importanti, quindi spiegherò come utilizzare questi metodi durante la generazione di certificati X.509 e CRL. Più avanti nell'articolo, presenterò il codice che dimostra i metodi in azione.

  • public static CertificateFactory getInstance(String stringType)e public static CertificateFactory getInstance(String stringType, String stringProvider)creare un'istanza e restituire un'istanza di una factory di certificati per il tipo di certificato specificato dal stringTypeparametro. Ad esempio, se il valore di stringTypeè la stringa "X.509", entrambi i metodi restituiranno un'istanza della CertificateFactoryclasse adatta per creare istanze delle classi X509Certificatee X509CRL. Il secondo metodo accetta il nome di uno specifico provider di servizi crittografici come argomento e utilizza quel provider invece del valore predefinito.
  • public final Certificate generateCertificate(InputStream inputstream)crea un'istanza e restituisce un certificato utilizzando i dati letti InputStreamdall'istanza fornita . Se il flusso contiene più di un certificato e il flusso supporta le operazioni mark()e reset(), il metodo leggerà un certificato e lascerà il flusso posizionato prima del successivo.
  • public final Collection generateCertificates(InputStream inputstream)crea un'istanza e restituisce una raccolta di certificati utilizzando i dati letti InputStreamdall'istanza fornita . Se il flusso specificato non supporta mark()e reset(), il metodo consumerà l'intero flusso.
  • public final CRL generateCRL(InputStream inputstream)crea un'istanza e restituisce un CRL utilizzando i dati letti InputStreamdall'istanza fornita . Se il flusso contiene più di un CRL e supporta le operazioni mark()e reset(), il metodo leggerà un CRL e lascerà il flusso posizionato prima del successivo.
  • public final Collection generateCRLs(InputStream inputstream)crea un'istanza e restituisce una raccolta di CRL utilizzando i dati letti dall'istanza fornita InputStream. Se il flusso specificato non supporta mark()e reset(), public final Collection generateCRLs(InputStream inputstream)consumerà l'intero flusso.

È importante capire come si comportano questi quattro metodi durante la generazione di istanze X.509 da un flusso di dati. Diamo un'occhiata.

I metodi generateCertificate()e generateCRL()prevedono che il contenuto del flusso di input contenga rappresentazioni con codifica DER di un certificato o di un CRL, rispettivamente.

Entrambi i metodi generateCertificates()e generateCRLs()prevedono che il contenuto del flusso di input contenga una sequenza di rappresentazioni con codifica DER o un certificato conforme a PKCS # 7 (Public-Key Cryptography Standard # 7) o un set CRL. (Vedere Risorse per i collegamenti.)

java.security.cert.Certificate

java.security.cert.Certificatedefinisce l'interfaccia comune a tutti i tipi di certificati: X.509, PGP e una piccola manciata di altri. I metodi più importanti di questa classe sono:

  • public abstract PublicKey getPublicKey() restituisce la chiave pubblica relativa all'istanza del certificato su cui viene chiamato questo metodo.
  • public abstract byte [] getEncoded() restituisce la forma codificata del certificato.
  • public abstract void verify(PublicKey publickey)e public abstract void verify(PublicKey publickey, String stringProvider)verificare che la chiave privata corrispondente alla chiave pubblica fornita abbia firmato il certificato in questione. Se le chiavi non corrispondono, entrambi i metodi generano un file SignatureException.

java.security.cert.X509Certificate

La classe java.security.cert.X509Certificateestende la Certficateclasse sopra descritta e aggiunge funzionalità specifiche di X.509. Questa classe è importante perché di solito interagisci con i certificati a questo livello, non come classe base.

  • public abstract byte [] getEncoded()restituisce la forma codificata di quel certificato, come sopra. Il metodo utilizza la codifica DER per il certificato.

La maggior parte delle java.security.cert.X509Certificatefunzionalità aggiuntive di è costituita da metodi di query che restituiscono informazioni sul certificato. Ho presentato la maggior parte di queste informazioni nella Parte 1. Ecco i metodi:

  • public abstract int getVersion() restituisce la versione del certificato.
  • public abstract Principal getSubjectDN() restituisce informazioni che identificano l'oggetto del certificato.
  • public abstract Principal getIssuerDN() restituisce informazioni che identificano l'emittente del certificato, che in genere è la CA, ma può essere l'oggetto se il certificato è autofirmato.
  • public abstract Date getNotBefore()e public abstract Date getNotAfter()restituire valori che limitano il periodo di tempo in cui l'emittente è disposto a garantire la chiave pubblica del soggetto.
  • public abstract BigInteger getSerialNumber()restituisce il numero di serie del certificato. La combinazione del nome dell'emittente di un certificato e del numero di serie è la sua identificazione univoca. Questo fatto è fondamentale per la revoca del certificato, di cui parlerò più dettagliatamente il mese prossimo.
  • public abstract String getSigAlgName()e public abstract String getSigAlgOID()restituire le informazioni sull'algoritmo utilizzato per firmare il certificato.

I metodi seguenti restituiscono informazioni sulle estensioni definite per il certificato. Ricorda, le estensioni sono meccanismi per associare informazioni a un certificato; compaiono solo sui certificati della versione 3.

  • public abstract int getBasicConstraints()restituisce la lunghezza del percorso dei vincoli di un certificato BasicConstraintsdall'estensione, se definita. Il percorso dei vincoli specifica il numero massimo di certificati CA che possono seguire questo certificato in un percorso di certificazione.
  • public abstract boolean [] getKeyUsage()restituisce lo scopo del certificato come codificato KeyUsagenell'estensione.
  • public Set getCriticalExtensionOIDs()e public Set getNonCriticalExtensionOIDs()restituisce una raccolta di identificatori di oggetto (OID) per le estensioni contrassegnate rispettivamente come critiche e non critiche. Un OID è una sequenza di numeri interi che identifica universalmente una risorsa.

Non voglio lasciarti senza codice con cui giocare, quindi invece di approfondire i CRL, che è un argomento completo a sé stante, presenterò il codice e lascerò i CRL per la Parte 3.

Il codice

La classe seguente mostra come ottenere una factory di certificati, come utilizzare quella factory per generare un certificato dalla rappresentazione con codifica DER in un file e come estrarre e visualizzare le informazioni sul certificato. Noterai quanto poco devi preoccuparti della codifica sottostante.