証明書を使用して安全なネットワークアプリケーションを構築する、パート2

安全なアプリケーションを構築するには、業界のツールを学ぶ必要があります。これらの概念を理解しやすくするために、パート1で公開鍵暗号を紹介し、秘密鍵暗号に伴う鍵交換の問題を回避する方法を説明しました。また、信頼と公開鍵暗号のスケーラビリティとの関係を調査し、証明書と公開鍵インフラストラクチャ(PKI)によって、公開鍵暗号が単独で実現できるよりも広い規模で信頼を実現する方法について説明しました。最後に、証明書と証明書チェーンについて説明し、それらがCA(認証局)とどのように関連しているかを説明しました。

SDSI(単純な分散セキュリティインフラストラクチャ)、PGP(非常に優れたプライバシー)、X.509など、さまざまな種類の証明書を利用できます。今月は、セキュリティ用語をさらに拡張するために、パックをリードし、新しいPKI標準の主要コンポーネントであるX.509証明書について説明します。

証明書に関するシリーズ全体を読むことができます。

  • パート1:証明書は公開鍵暗号に価値を付加します
  • パート2:X.509証明書の使用方法を学ぶ
  • パート3:JavaCRLおよびX509CRLクラスを使用する
  • パート4:クライアントとサーバーを認証し、証明書チェーンを検証する

X.509形式の詳細

国際電気通信連合(ITU)は、インターネット技術特別調査委員会(IETF)の公開鍵インフラストラクチャX.509(PKIX)ワーキンググループによって選択されたX.509証明書形式を開発および公開しました。頭字語が強さを示している場合、X.509には明らかに強力な味方がいます。

X.509標準は、ASN.1(Abstract Syntax Notation One)と呼ばれる表記法を使用して、証明書の形式を定義します。ASN.1は、プラットフォームに依存しない方法で抽象データ型を記述する標準化された言語です。

PKIXワーキンググループによって発行された「インターネットX.509公開鍵インフラストラクチャ-証明書とCRLプロファイル」ドキュメント(リンクについては「参考文献」を参照)では、ASN.1表記の観点からX.509証明書形式について説明しています。そのようなことに興味があるなら、それは魅力的な読み物です。

ASN.1で定義されているデータ型(証明書など)は、データ型のインスタンスを一連のビットとして表す方法を明確に定義できるようになるまで役に立ちません。データ型にその機能を与えるために、ASN.1はDistinguished Encoding Rules(DER)を使用します。これは、ASN.1オブジェクトを一意にエンコードする方法を定義します。

X.509証明書のASN.1定義のコピーとDERの知識があれば、X.509証明書を読み書きし、他のプログラミング言語で記述された同様のアプリケーションと相互運用するJavaアプリケーションを作成できます。幸いなことに、Java 2 Platform、Standard Edition(J2SE)にはX.509証明書のサポートが組み込まれているため、それほど多くの問題に直面する必要はありません。

X.509(ほとんど)なし

証明書関連のクラスとインターフェイスはすべてパッケージに含まれていますjava.security.cert。 SunのセキュリティAPIファミリの他のメンバーと同様に、証明書パッケージは、1つ以上のJavaクラスがパッケージの目的の機能への汎用インターフェイスを定義するファクトリパラダイムに基づいて設計されました。クラスは抽象的であるため、アプリケーションはそれらを直接インスタンス化できません。代わりに、ファクトリクラスのインスタンスは、抽象クラスの特定のサブタイプのインスタンスを作成して返します。ファクトリパラダイムは、Javaの強い型付けを回避しますが、その見返りとして、より広い範囲の環境で再コンパイルせずにコードを実行できるようにします。

抽象クラスは、インターフェイスを定義します。これらは、それぞれ証明書と証明書失効リスト(CRL)を表します。クラスは、その工場です。java.security.cert.Certificatejava.security.cert.CRLCertificateFactory

java.security.certパッケージには、具体的な実装が含まCertificateCRL:抽象クラスX509CertificateX509CRLクラスを。これらの2つのクラスは、基本的な証明書とCRL機能を実装し、X.509固有の機能で拡張します。ときにCertificateFactoryインスタンスがいずれかのクラスのインスタンスを返し、プログラムはどちらか、あるとしてそれを使用するか、または明示的にX.509形式にキャストすることができます。

ではjava.security.cert、パッケージ、インタフェースは、X509ExtensionX.509証明書の拡張へのインタフェースを定義します。拡張機能は、証明書の作成者が追加情報を証明書に関連付けるためのメカニズムを提供するオプションのコンポーネントです。たとえば、証明書はKeyUsage拡張子を使用して、コード署名に使用できることを示す場合があります。

このjava.security.certパッケージには、サービスプロバイダーインターフェイス(SPI)クラスも含まれています。暗号化サービスプロバイダ証明書の種類をサポートしたいSPIを拡張します。Java 2には、X.509証明書用のSPIが付属しています。

java.security.certパッケージ内のクラスとインターフェイスをさらに詳しく見てみましょう。簡潔にするために、最も有用な方法についてのみ説明します。より包括的なカバレッジについては、Sunのドキュメントを読むことをお勧めします。(「参考文献」を参照してください。)

java.security.cert.CertificateFactory

物語はで始まりますjava.security.cert.CertificateFactory。このCertificateFactoryクラスにはCertificateFactory、特定の種類の証明書のインスタンスを作成する静的メソッドと、入力ストリームで提供されるデータから証明書とCRLの両方を作成するメソッドがあります。最も重要な方法について簡単に説明した後、X.509証明書とCRLを生成するときにこれらの方法を使用する方法を説明します。この記事の後半で、実際のメソッドを示すコードを紹介します。

  • public static CertificateFactory getInstance(String stringType)そしてpublic static CertificateFactory getInstance(String stringType, String stringProvider)インスタンス化とによって指定された証明書タイプの証明書ファクトリのインスタンスを返すstringTypeパラメータ。たとえば、の値がstringType文字列「X.509」の場合、両方のメソッドはCertificateFactory、クラスX509Certificateとのインスタンスの作成に適したクラスのインスタンスを返しますX509CRL。2番目の方法は、特定の暗号化サービスプロバイダーの名前を引数として受け入れ、デフォルトの代わりにそのプロバイダーを使用します。
  • public final Certificate generateCertificate(InputStream inputstream)提供されたInputStreamインスタンスから読み取られたデータを使用して、証明書をインスタンス化して返します。ストリームに複数の証明書が含まれていて、ストリームがmark()andreset()操作をサポートしている場合、メソッドは1つの証明書を読み取り、ストリームを次の証明書の前に配置したままにします。
  • public final Collection generateCertificates(InputStream inputstream)提供されたInputStreamインスタンスから読み取られたデータを使用して、証明書コレクションをインスタンス化し、返します。指定されたストリームをサポートしていない場合mark()reset()、この方法は、ストリーム全体を消費します。
  • public final CRL generateCRL(InputStream inputstream)提供されたInputStreamインスタンスから読み取られたデータを使用して、CRLをインスタンス化して返します。ストリームに複数のCRLが含まれ、mark()andreset()操作をサポートしている場合、メソッドは1つのCRLを読み取り、ストリームを次の前に配置したままにします。
  • public final Collection generateCRLs(InputStream inputstream)提供されたInputStreamインスタンスから読み取られたデータを使用して、CRLのコレクションをインスタンス化して返します。指定されたストリームをサポートしていない場合mark()reset()public final Collection generateCRLs(InputStream inputstream)ストリーム全体を消費します。

データのストリームからX.509インスタンスを生成する場合、これら4つのメソッドがどのように動作するかを理解することが重要です。見てみましょう。

generateCertificate()及びgenerateCRL()方法は、入力ストリームの内容は、それぞれ、証明書またはCRLのDER符号化された表現を含むことを期待します。

両方generateCertificates()及びgenerateCRLs()方法は、入力ストリームの内容がDERエンコード表現の配列またはPKCS#7(公開鍵暗号標準#7)準拠の証明書またはCRLのセットのいずれかを含有することが予想されます。(リンクについては、「参考文献」を参照してください。)

java.security.cert.Certificate

java.security.cert.CertificateX.509、PGP、およびその他の少数の証明書など、すべての種類の証明書に共通のインターフェイスを定義します。このクラスの最も重要なメソッドは次のとおりです。

  • public abstract PublicKey getPublicKey() このメソッドが呼び出されている証明書インスタンスに関連する公開鍵を返します。
  • public abstract byte [] getEncoded() その証明書のエンコードされた形式を返します。
  • public abstract void verify(PublicKey publickey)そして、public abstract void verify(PublicKey publickey, String stringProvider)付属公開鍵に対応する秘密鍵が問題の証明書に署名したことを確認してください。キーが一致しない場合、両方のメソッドがSignatureException。をスローします。

java.security.cert.X509Certificate

このクラスjava.security.cert.X509Certificateは、Certficate上記のクラスを拡張し、X.509固有の機能を追加します。通常、基本クラスとしてではなく、このレベルで証明書を操作するため、このクラスは重要です。

  • public abstract byte [] getEncoded()上記のように、その証明書のエンコードされた形式を返します。この方法では、証明書にDERエンコーディングを使用します。

java.security.cert.X509Certificateの追加機能のほとんどは、証明書に関する情報を返すクエリメソッドで構成されています。その情報のほとんどをパート1で紹介しました。方法は次のとおりです。

  • public abstract int getVersion() 証明書のバージョンを返します。
  • public abstract Principal getSubjectDN() 証明書のサブジェクトを識別する情報を返します。
  • public abstract Principal getIssuerDN() 証明書の発行者(通常はCA)を識別する情報を返しますが、証明書が自己署名されている場合はサブジェクトになる可能性があります。
  • public abstract Date getNotBefore()そして、public abstract Date getNotAfter()発行者が対象者の公開鍵を保証するために喜んでいる時間帯を制限する値を返します。
  • public abstract BigInteger getSerialNumber()証明書のシリアル番号を返します。証明書の発行者名とシリアル番号の組み合わせは、証明書の一意のIDです。この事実は、証明書の失効にとって非常に重要です。これについては、来月詳しく説明します。
  • public abstract String getSigAlgName()public abstract String getSigAlgOID()証明書の署名に使用されたアルゴリズムに関する情報を返します。

次のメソッドは、証明書に定義されている拡張機能に関する情報を返します。拡張機能は、情報を証明書に関連付けるためのメカニズムであることを忘れないでください。これらはバージョン3の証明書にのみ表示されます。

  • public abstract int getBasicConstraints()BasicConstraints定義されている場合、拡張機能からの証明書の制約パスの長さを返します。制約パスは、証明書パスでこの証明書に続く可能性のあるCA証明書の最大数を指定します。
  • public abstract boolean [] getKeyUsage()KeyUsage拡張機能にエンコードされた証明書の目的を返します。
  • public Set getCriticalExtensionOIDs()そしてpublic Set getNonCriticalExtensionOIDs()、それぞれクリティカルおよび非クリティカルとマークされた拡張機能のオブジェクト識別子(OID)のコレクションを返します。OIDは、リソースを普遍的に識別する整数のシーケンスです。

遊ぶためのコードがないままにしたくないので、それ自体が完全なトピックであるCRLを掘り下げるのではなく、コードを提示してCRLをパート3に残します。

コード

次のクラスは、証明書ファクトリを取得する方法、そのファクトリを使用してファイル内のDERエンコード表現から証明書を生成する方法、および証明書に関する情報を抽出して表示する方法を示しています。基礎となるエンコーディングについて心配する必要がほとんどないことに気付くでしょう。