プライマリ・コンテンツに移動
Java Platform, Standard Editionセキュリティ開発者ガイド
リリース9
E91919-01
目次へ移動
目次

前
次
次へ

Java XMLデジタル署名API仕様

このドキュメントでは、Java XMLデジタル署名API仕様(JSR 105)について説明します。このJSRの目的は、XML署名を生成および検証するための標準のJava APIを定義することです。

この仕様が完成すると、このAPIの機能について説明するリファレンス実装が作成されることになり、この仕様のオペレーションの定義が提供されます。この仕様の実装に対応しているかどうかを確認するためのTechnology Compatibility Kit (TCK)も使用可能になります。Java Community Process 2.1に従ってこれらが必要になります。

JSR 105 APIは、次の2種類のユーザーをターゲットにしています。

謝辞

JSR 105エキスパート・グループ:

  • Nicolas Catania、HP社

  • Donald E.Eastlake 3rd、Motorola社

  • Christian Geuer-Pollmann、Apache Software Foundation

  • Hans Granqvist、VeriSign社

  • Kazuyuki Harada、富士通

  • Anthony Ho、DSTC社

  • Merlin Hughes、Baltimore Technologies

  • Joyce Leung、IBM社

  • Gregor Karlinger、IAIK

  • Serge Mister、Entrust Technologies

  • Takuya Mori、NEC Corporation

  • Sean Mullan、Sun Microsystems (共同仕様リード)

  • Anthony Nadalin、IBM (共同仕様リード)

  • Erwin van der Koogh、Apache Software Foundation

  • Chris Yeung、XML Asia

また、次のメンバーにも感謝を捧げます。Sun MicrosystemsのValerie Peng、Vincent Ryan、Sharon Liu、Chok Poh、K. Venugopal Rao.、Paul Rank、Alexey Gavrilov、Bill Situ、Eric Jendrock、Andrew Fan、Manveen Kaur、Tom Amiro、Michael Mi、Dmitri Silaev、Roman Makarchuk、Vanitha Venkatraman, Arkadiy Sutchilin, Scott Fordin、ApacheのVishal Mahajan、IAIKのMartin Centner。

要件

このドキュメントのキーワード「MUST」、「MUST NOT」、「REQUIRED」、「SHALL」、「SHALL NOT」、「SHOULD」、「SHOULD NOT」、「RECOMMENDED」、「MAY」、および「OPTIONAL」は、RFC 2119に説明されているとおりに解釈されます。

  1. W3C勧告、XML署名の構文と処理

    • APIを使用して、プログラマはW3C勧告で規定されているSHOULDおよびMUSTのすべての要件を満たすXML署名を生成および検証できる必要があります。

    • APIを使用して、W3C勧告で規定されているSHOULDおよびMUSTのすべての要件を満たすAPIの実装を作成できる必要があります。

  2. 実装は、W3C Recommendation, XML-Signature XPath Filter Transform 2.0をサポートする必要があります。

  3. 実装は、W3C Recommendation, Exclusive XML Canonicalization Version 1.0をサポートする必要があります。

  4. DOMに依存しないAPI。APIは、DOMなどの特定のXML表現に依存していない必要があります。DOM、JDOMdom4jなど、様々なXML処理およびメカニズム表現のためのAPIの実装を作成できる必要があります。

  5. 拡張可能なプロバイダ・ベースのAPI。サード・パーティが、暗号化アルゴリズムや変換アルゴリズムの管理や作成、URIの間接参照、およびXMLのオブジェクトの整列化を行う実装を作成およびプラグインすることができる必要があります。

  6. デフォルトのXMLメカニズム・タイプDOMのサポート。実装は、デフォルトのメカニズム・タイプDOMを最低限サポートする必要があります。これにより、JSR 105のすべての実装で最低レベルの機能性が保証されます。実装は、ほかのメカニズム・タイプもサポートできます。

  7. デフォルトのXMLメカニズム・タイプDOMの相互運用性。APIは、DOM実装を使用するアプリケーションで移植性および相互運用性を保証する必要があります。

  8. J2SEの要件。このテクノロジの実装はJ2SE 1.2以降をサポートできますが、最低限J2SEのバージョン1.4をサポートする必要があります。

APIの依存性

目標にしない事項

  1. 非DOM実装のサポート。APIでは非DOM実装を作成できる必要がありますが、DOM以外の実装間での相互運用性を保証することは最初のバージョンの範囲外です。追加の標準サービス・プロバイダ・タイプが今後追加されたり、JSR 105の保守バージョンで必要なAPIの拡張機能が検討される可能性があります。

  2. 高レベルのAPIのサポート。プログラマは、JSR 105 APIに基づいて構築される高レベルのAPIを設計して、低レベルの詳細を非表示にしたり、共通のユース・ケースに対処したり、プロファイリングの制限を適用できます。ただし、これらの要件をサポートすることは最初のバージョンの範囲外です。高レベルのAPIは、JSR 105の保守リリースで考慮される可能性があります。

  3. ユーザープラガブル・アルゴリズム(javax.xml.crypto.dsig.TransformServiceクラスでサポートされている変換アルゴリズムおよび正規化アルゴリズム以外)のサポート。開発者が完全なJSR 105実装を作成せずに独自のXML署名アルゴリズム実装をプラグインできるようにすることは、有用なことだと考えられますが、JSR 105のこのリリースでは必要ありません。Java SEの後続リリースでは、基礎となるJCA/JCEを拡張して、XMLセキュリティ・アルゴリズム、パラメータ、鍵情報の登録、解析および処理のサポートを追加するソリューションを検討しています。

パッケージの概要

JSR 105 APIは、次の6つのパッケージで構成されています。

javax.xml.cryptoパッケージには、XML署名の生成やXMLデータの暗号化など、XML暗号化操作を行う場合に使用する一般的なクラスが含まれています。このパッケージ内の主要なクラスには次の2つがあります。KeySelectorクラスを使用すると、開発者は、KeyInfoオブジェクトに含まれている情報を使用して鍵を検出して任意に検証する実装を提供できます。URIDereferencerクラスを使用すると、開発者は、実装を間接参照する独自のURIを作成および指定できます。

javax.xml.crypto.dsigパッケージには、W3C XMLデジタル署名仕様で定義されているコア要素を表すインタフェースが含まれています。最も重要なのはXMLSignatureクラスです。このクラスを使用すると、XMLデジタル署名の署名および検証を行うことができます。ほとんどのXML署名構造または要素は、対応するインタフェースによって表されます(KeyInfo構造を除きます。これは独自のパッケージに含まれており、次の段落で説明します)。これらのインタフェースには、SignedInfoCanonicalizationMethodSignatureMethodReferenceTransformDigestMethodXMLObjectManifestSignaturePropertyおよびSignaturePropertiesなどがあります。XMLSignatureFactoryクラスは、これらのインタフェースを実装するオブジェクトを作成する場合に使用する抽象ファクトリです。

javax.xml.crypto.dsig.keyinfoパッケージには、KeyInfoKeyNameKeyValueX509DataX509IssuerSerialRetrievalMethodおよびPGPDataなど、W3C XMLデジタル署名勧告で定義されているほとんどのKeyInfo構造を表すインタフェースが含まれています。KeyInfoFactoryクラスは、これらのインタフェースを実装するオブジェクトを作成する場合に使用する抽象ファクトリです。

javax.xml.crypto.dsig.specパッケージには、ダイジェスト、署名、変換、またはXML署名の処理で使用される正規化アルゴリズム用の入力パラメータを表すインタフェースおよびクラスが含まれています。

最後に、javax.xml.crypto.domおよびjavax.xml.crypto.dsig.domパッケージには、javax.xml.cryptoおよびjavax.xml.crypto.dsigパッケージ用のDOM固有のクラスがそれぞれ含まれています。DOMベースのXMLSignatureFactoryまたはKeyInfoFactory実装を作成または使用する開発者およびユーザーのみが、これらのパッケージを直接使用する必要があります。

サービス・プロバイダ

JSR 105暗号化サービスは、XMLSignatureFactoryおよびKeyInfoFactory抽象クラスの固定実装であり、XML署名やKeyInfo構造を解析、生成および検証するオブジェクトやアルゴリズムを作成します。XMLSignatureFactoryの固定実装は、XML署名に関するW3C勧告に規定されているように、必要なそれぞれのアルゴリズムをサポートしている必要があります。この固定実装は、W3C勧告やほかの仕様に規定されているように、ほかのアルゴリズムをサポートできます。

JSR 105は、JCAプロバイダ・モデルを使用して(Providerクラスを参照)、XMLSignatureFactoryおよびKeyInfoFactory実装を登録およびロードします。

固定実装XMLSignatureFactoryまたはKeyInfoFactoryはそれぞれ、XML署名やKeyInfo構造を解析および生成するときに実装によって内部で使用されるXML処理メカニズムを識別する、特定のXMLメカニズム・タイプをサポートしています。このJSRは標準タイプDOMをサポートしています。新しい標準タイプ(JDOMなど)のサポートは、今後追加される可能性があります。

JSR 105実装は、java.security.Signaturejava.security.MessageDigestなど、ベースとなるJCAエンジン・クラスを使用して暗号化操作を行う必要があります。

XMLSignatureFactoryおよびKeyInfoFactoryクラス以外に、JSR 105は、変換および正規化アルゴリズム用のサービス・プロバイダ・インタフェースもサポートしています。TransformServiceクラスを使用すると、特定のXMLメカニズム・タイプ用の固有の変換または正規化アルゴリズムの実装を開発およびプラグインできます。TransformServiceクラスは、実装を登録およびロードするときに標準JCAプロバイダ・モデルを使用します。各JSR 105実装はTransformServiceクラスを使用して、生成または検証しているXML署名で変換アルゴリズムおよび正規化アルゴリズムをサポートするプロバイダを見つける必要があります。

DOMメカニズムの要件

相互運用性の問題を最小限にするために、DOMベースのXMLSignatureFactoryKeyInfoFactory、またはTransformServiceを実装する場合は、次の要件に従う必要があります。

  1. XMLSignatureFactoryunmarshalXMLSignatureメソッドは、DOMValidateContext型をサポートする必要があります。型がDOMValidateContextの場合は、Signature型の要素を含む必要があります。また、unmarshalXMLSignatureメソッドは渡されるDOMValidateContextのID/要素マッピングを生成できます。

  2. XMLSignatureFactoryによって生成されるXMLSignaturesignメソッドはDOMSignContext型をサポートし、validateメソッドはDOMValidateContext型をサポートする必要があります。この要件は、SignatureValuevalidateメソッド、およびReferencevalidateメソッドにも当てはまります。

  3. 実装は、アプリケーションが拡張可能なコンテンツ(任意の要素または混合コンテンツ)を指定するためのメカニズムとして、DOMStructureをサポートする必要があります。

  4. ユーザー指定のURIDereferencerdereferenceメソッドがNodeSetDataオブジェクトを返す場合、iteratorメソッドは型org.w3c.dom.Nodeのオブジェクトの繰返しを返す必要があります。

  5. ユーザー指定のURIDereferencersのdereferenceメソッドに渡されたURIReferenceオブジェクトは型DOMURIReferenceである必要があり、XMLCryptoContextオブジェクトはDOMCryptoContextを実装する必要があります。

  6. 直前の2つの要件は、XMLSignatureFactoryおよびKeyInfoFactorygetURIDereferencerメソッドによって返されるURIDereferencersにも当てはまります。

  7. KeyInfoFactoryunmarshalKeyInfoメソッドはDOMStructure型をサポートする必要があります。型がDOMStructureの場合は、KeyInfo型の要素を含む必要があります。

  8. TransformtransformメソッドはDOMCryptoContextコンテキスト・パラメータ型をサポートする必要があります。

  9. XMLSignatureFactorynewtransformおよびnewCanonicalizationMethodメソッドはDOMStructureパラメータ型をサポートする必要があります。

  10. TransformServiceinitおよびmarshalParamsメソッドはDOMStructureおよびDOMCryptoContext型をサポートする必要があります。

  11. XMLSignatureFactoryunmarshalXMLSignatureメソッドは、DOMStructure型をサポートする必要があります。型がDOMStructureの場合は、Signature型の要素を含む必要があります。

  12. KeyInfomarshalメソッドはDOMStructureおよびDOMCryptoContextパラメータ型をサポートする必要があります。

DOM実装は、相互運用性に影響しない場合、DOM以外のXML解析APIを内部的に使用できます。たとえば、XMLSignatureFactoryのDOM実装は、内部的にSAXパーサーを使用してデータを正規化することができます。

オープンAPIの問題

オープンAPIの問題は、次のとおりです。

  1. 外部XMLドキュメント参照のID属性の登録がサポートされていません。次の参照について検討してみます。

    外部ドキュメントの間接参照によってオクテット・ストリームが生成され、それがJSR 105実装によってNodeSetに変換されています。ただし、APIでは外部ドキュメントのID属性を登録するためのメカニズムが提供されていないため、XPath変換実装は「foo」IDを識別できない可能性があります。

<Reference URI="document.xml">
  <Transforms>
    <Transform Algorithm="http://www.w3.org/TR/1999/REC-xpath-19991116">
      <XPath>id("foo")</XPath>
    </Transform>
  </Transforms>
</Reference> 

プログラミング例

次の例1 - 3では、JSR 105 APIを使用してさまざまなタイプの単純なXMLデジタル署名を生成する方法について説明します。例1では、DSA署名アルゴリズムを使用して分離署名を生成する方法について説明します。例2では、エンベロープされた署名を生成する方法について説明します。例3では、エンベロープされた署名を生成する方法について説明します。例4では、XML署名を検証する方法について説明します。

例11-1 1.分離されたXMLデジタル署名の生成

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Collections;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

/**
 * This is a simple example of generating a Detached XML
 * Signature using the JSR 105 API. The resulting signature will look
 * like (key and signature values will be different):
 *
 * <pre><code>
 * <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
 *   <SignedInfo>
 *     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
 *     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha256"/>
 *     <Reference URI="http://www.w3.org/TR/xml-stylesheet">
 *       <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
 *       <DigestValue>60NvZvtdTB+7UnlLp/H24p7h4bs=</DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     DpEylhQoiUKBoKWmYfajXO7LZxiDYgVtUtCNyTgwZgoChzorA2nhkQ==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *         <P>
 *           rFto8uPQM6y34FLPmDh40BLJ1rVrC8VeRquuhPZ6jYNFkQuwxnu/wCvIAMhukPBL
 *           FET8bJf/b2ef+oqxZajEb+88zlZoyG8g/wMfDBHTxz+CnowLahnCCTYBp5kt7G8q
 *           UobJuvjylwj1st7V9Lsu03iXMXtbiriUjFa5gURasN8=
 *         </P>
 *         <Q>
 *           kEjAFpCe4lcUOdwphpzf+tBaUds=
 *         </Q>
 *         <G>
 *           oe14R2OtyKx+s+60O5BRNMOYpIg2TU/f15N3bsDErKOWtKXeNK9FS7dWStreDxo2
 *           SSgOonqAd4FuJ/4uva7GgNL4ULIqY7E+mW5iwJ7n/WTELh98mEocsLXkNh24HcH4
 *           BZfSCTruuzmCyjdV1KSqX/Eux04HfCWYmdxN3SQ/qqw=
 *         </G>
 *         <Y>
 *           pA5NnZvcd574WRXuOA7ZfC/7Lqt4cB0MRLWtHubtJoVOao9ib5ry4rTk0r6ddnOv
 *           AIGKktutzK3ymvKleS3DOrwZQgJ+/BDWDW8kO9R66o6rdjiSobBi/0c2V1+dkqOg
 *           jFmKz395mvCOZGhC7fqAVhHat2EjGPMfgSZyABa7+1k=
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 * </Signature>
 * </code></pre>
 */
public class GenDetached {

    //
    // Synopsis: java GenDetached [output]
    //
    // where output is the name of the file that will contain the detached
    // signature. If not specified, standard output is used.
    //
    public static void main(String[] args) throws Exception {

        // First, create a DOM XMLSignatureFactory that will be used to
        // generate the XMLSignature and marshal it to DOM.
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a Reference to an external URI that will be digested
        // using the SHA256 digest algorithm
        Reference ref = fac.newReference("http://www.w3.org/TR/xml-stylesheet",
            fac.newDigestMethod(DigestMethod.SHA256, null));

        // Create the SignedInfo
        SignedInfo si = fac.newSignedInfo(
            fac.newCanonicalizationMethod
                (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
                 (C14NMethodParameterSpec) null),
            fac.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#dsa-sha256", null),
            Collections.singletonList(ref));

        // Create a DSA KeyPair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();

        // Create a KeyValue containing the DSA PublicKey that was generated
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());

        // Create a KeyInfo and add the KeyValue to it
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        // Create the XMLSignature (but don't sign it yet)
        XMLSignature signature = fac.newXMLSignature(si, ki);

        // Create the Document that will hold the resulting XMLSignature
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true); // must be set
        Document doc = dbf.newDocumentBuilder().newDocument();

        // Create a DOMSignContext and set the signing Key to the DSA
        // PrivateKey and specify where the XMLSignature should be inserted
        // in the target document (in this case, the document root)
        DOMSignContext signContext = new DOMSignContext(kp.getPrivate(), doc);

        // Marshal, generate (and sign) the detached XMLSignature. The DOM
        // Document will contain the XML Signature if this method returns
        // successfully.
        signature.sign(signContext);

        // output the resulting document
        OutputStream os;
        if (args.length > 0) {
           os = new FileOutputStream(args[0]);
        } else {
           os = System.out;
        }

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}

例11-2 2.エンベロープされたXMLデジタル署名の生成

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.*;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Collections;
import java.util.Iterator;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;

/**
 * This is a simple example of generating an Enveloped XML
 * Signature using the JSR 105 API. The resulting signature will look
 * like (key and signature values will be different):
 *
 * <pre><code>
 *<Envelope xmlns="urn:envelope">
 * <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
 *   <SignedInfo>
 *     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315"/>
 *     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha256"/>
 *     <Reference URI="">
 *       <Transforms>
 *         <Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
 *       </Transforms>
 *       <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
 *       <DigestValue>K8M/lPbKnuMDsO0Uzuj75lQtzQI=<DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     DpEylhQoiUKBoKWmYfajXO7LZxiDYgVtUtCNyTgwZgoChzorA2nhkQ==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *         <P>
 *           rFto8uPQM6y34FLPmDh40BLJ1rVrC8VeRquuhPZ6jYNFkQuwxnu/wCvIAMhukPBL
 *           FET8bJf/b2ef+oqxZajEb+88zlZoyG8g/wMfDBHTxz+CnowLahnCCTYBp5kt7G8q
 *           UobJuvjylwj1st7V9Lsu03iXMXtbiriUjFa5gURasN8=
 *         </P>
 *         <Q>
 *           kEjAFpCe4lcUOdwphpzf+tBaUds=
 *         </Q>
 *         <G>
 *           oe14R2OtyKx+s+60O5BRNMOYpIg2TU/f15N3bsDErKOWtKXeNK9FS7dWStreDxo2
 *           SSgOonqAd4FuJ/4uva7GgNL4ULIqY7E+mW5iwJ7n/WTELh98mEocsLXkNh24HcH4
 *           BZfSCTruuzmCyjdV1KSqX/Eux04HfCWYmdxN3SQ/qqw=
 *         </G>
 *         <Y>
 *           pA5NnZvcd574WRXuOA7ZfC/7Lqt4cB0MRLWtHubtJoVOao9ib5ry4rTk0r6ddnOv
 *           AIGKktutzK3ymvKleS3DOrwZQgJ+/BDWDW8kO9R66o6rdjiSobBi/0c2V1+dkqOg
 *           jFmKz395mvCOZGhC7fqAVhHat2EjGPMfgSZyABa7+1k=
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 * </Signature>
 *</Envelope>
 * </code></pre>
 */
public class GenEnveloped {

    //
    // Synopsis: java GenEnveloped [document] [output]
    //
    //    where "document" is the name of a file containing the XML document
    //    to be signed, and "output" is the name of the file to store the
    //    signed document. The 2nd argument is optional - if not specified,
    //    standard output will be used.
    //
    public static void main(String[] args) throws Exception {

        // Create a DOM XMLSignatureFactory that will be used to generate the
        // enveloped signature
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a Reference to the enveloped document (in this case we are
        // signing the whole document, so a URI of "" signifies that) and
        // also specify the SHA256 digest algorithm and the ENVELOPED Transform.
        Reference ref = fac.newReference
            ("", fac.newDigestMethod(DigestMethod.SHA256, null),
             Collections.singletonList
              (fac.newTransform
                (Transform.ENVELOPED, (TransformParameterSpec) null)),
             null, null);

        // Create the SignedInfo
        SignedInfo si = fac.newSignedInfo
            (fac.newCanonicalizationMethod
             (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
              (C14NMethodParameterSpec) null),
             fac.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#dsa-sha256", null),
             Collections.singletonList(ref));

        // Create a DSA KeyPair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();

        // Create a KeyValue containing the DSA PublicKey that was generated
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());

        // Create a KeyInfo and add the KeyValue to it
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        // Instantiate the document to be signed
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc =
            dbf.newDocumentBuilder().parse(new FileInputStream(args[0]));

        // Create a DOMSignContext and specify the DSA PrivateKey and
        // location of the resulting XMLSignature's parent element
        DOMSignContext dsc = new DOMSignContext
            (kp.getPrivate(), doc.getDocumentElement());

        // Create the XMLSignature (but don't sign it yet)
        XMLSignature signature = fac.newXMLSignature(si, ki);

        // Marshal, generate (and sign) the enveloped signature
        signature.sign(dsc);

        // output the resulting document
        OutputStream os;
        if (args.length > 1) {
           os = new FileOutputStream(args[1]);
        } else {
           os = System.out;
        }

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}

例11-3 3.エンベロープするXMLデジタル署名の生成

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMSignContext;
import javax.xml.crypto.dsig.keyinfo.*;
import javax.xml.crypto.dsig.spec.C14NMethodParameterSpec;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.security.*;
import java.util.Arrays;
import java.util.Collections;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

/**
 * This is a simple example of generating an Enveloping XML
 * Signature using the JSR 105 API. The signature in this case references a
 * local URI that points to an Object element.
 * The resulting signature will look like (certificate and
 * signature values will be different):
 *
 * <pre><code>
 * <Signature xmlns="http://www.w3.org/2000/09/xmldsig#">
 *   <SignedInfo>
 *     <CanonicalizationMethod Algorithm="http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments"/>
 *     <SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#dsa-sha256"/>
 *     <Reference URI="#object">
 *       <DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
 *       <DigestValue>7/XTsHaBSOnJ/jXD5v0zL6VKYsk=</DigestValue>
 *     </Reference>
 *   </SignedInfo>
 *   <SignatureValue>
 *     RpMRbtMHLa0siSS+BwUpLIEmTfh/0fsld2JYQWZzCzfa5kBTz25+XA==
 *   </SignatureValue>
 *   <KeyInfo>
 *     <KeyValue>
 *       <DSAKeyValue>
 *         <P>
 *           /KaCzo4Syrom78z3EQ5SbbB4sF7ey80etKII864WF64B81uRpH5t9jQTxeEu0Imbz
 *           RMqzVDZkVG9xD7nN1kuFw==
 *         </P>
 *         <Q>
 *           li7dzDacuo67Jg7mtqEm2TRuOMU=
 *         </Q>
 *         <G>
 *           Z4Rxsnqc9E7pGknFFH2xqaryRPBaQ01khpMdLRQnG541Awtx/XPaF5Bpsy4pNWMOH
 *           CBiNU0NogpsQW5QvnlMpA==
 *         </G>
 *         <Y>
 *           wbEUaCgHZXqK4qLvbdYrAc6+Do0XVcsziCJqxzn4cJJRxwc3E1xnEXHscVgr1Cql9
 *           i5fanOKQbFXzmb+bChqig==
 *         </Y>
 *       </DSAKeyValue>
 *     </KeyValue>
 *   </KeyInfo>
 *   <Object Id="object">some text</Object>
 * </Signature>
 *
 * </code></pre>
 */
public class GenEnveloping {

    //
    // Synopis: java GenEnveloping [output]
    //
    //   where "output" is the name of a file that will contain the
    //   generated signature. If not specified, standard ouput will be used.
    //
    public static void main(String[] args) throws Exception {

        // First, create the DOM XMLSignatureFactory that will be used to
        // generate the XMLSignature
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Next, create a Reference to a same-document URI that is an Object
        // element and specify the SHA256 digest algorithm
        Reference ref = fac.newReference("#object",
            fac.newDigestMethod(DigestMethod.SHA256, null));

        // Next, create the referenced Object
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc = dbf.newDocumentBuilder().newDocument();
        Node text = doc.createTextNode("some text");
        XMLStructure content = new DOMStructure(text);
        XMLObject obj = fac.newXMLObject
            (Collections.singletonList(content), "object", null, null);

        // Create the SignedInfo
        SignedInfo si = fac.newSignedInfo(
            fac.newCanonicalizationMethod
                (CanonicalizationMethod.INCLUSIVE_WITH_COMMENTS,
                 (C14NMethodParameterSpec) null),
            fac.newSignatureMethod("http://www.w3.org/2000/09/xmldsig#dsa-sha256", null),
            Collections.singletonList(ref));

        // Create a DSA KeyPair
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("DSA");
        kpg.initialize(2048);
        KeyPair kp = kpg.generateKeyPair();

        // Create a KeyValue containing the DSA PublicKey that was generated
        KeyInfoFactory kif = fac.getKeyInfoFactory();
        KeyValue kv = kif.newKeyValue(kp.getPublic());

        // Create a KeyInfo and add the KeyValue to it
        KeyInfo ki = kif.newKeyInfo(Collections.singletonList(kv));

        // Create the XMLSignature (but don't sign it yet)
        XMLSignature signature = fac.newXMLSignature(si, ki,
            Collections.singletonList(obj), null, null);

        // Create a DOMSignContext and specify the DSA PrivateKey for signing
        // and the document location of the XMLSignature
        DOMSignContext dsc = new DOMSignContext(kp.getPrivate(), doc);

        // Lastly, generate the enveloping signature using the PrivateKey
        signature.sign(dsc);

        // output the resulting document
        OutputStream os;
        if (args.length > 0) {
           os = new FileOutputStream(args[0]);
        } else {
           os = System.out;
        }

        TransformerFactory tf = TransformerFactory.newInstance();
        Transformer trans = tf.newTransformer();
        trans.transform(new DOMSource(doc), new StreamResult(os));
    }
}

例11-4 4.XMLデジタル署名の検証

import javax.xml.crypto.*;
import javax.xml.crypto.dsig.*;
import javax.xml.crypto.dom.*;
import javax.xml.crypto.dsig.dom.DOMValidateContext;
import javax.xml.crypto.dsig.keyinfo.*;
import java.io.FileInputStream;
import java.security.*;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;

/**
 * This is a simple example of validating an XML
 * Signature using the JSR 105 API. It assumes the key needed to
 * validate the signature is contained in a KeyValue KeyInfo.
 */
public class Validate {

    //
    // Synopsis: java Validate [document]
    //
    //    where "document" is the name of a file containing the XML document
    //    to be validated.
    //
    public static void main(String[] args) throws Exception {

        // Instantiate the document to be validated
        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
        dbf.setNamespaceAware(true);
        Document doc =
            dbf.newDocumentBuilder().parse(new FileInputStream(args[0]));

        // Find Signature element
        NodeList nl =
            doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature");
        if (nl.getLength() == 0) {
            throw new Exception("Cannot find Signature element");
        }

        // Create a DOM XMLSignatureFactory that will be used to unmarshal the
        // document containing the XMLSignature
        XMLSignatureFactory fac = XMLSignatureFactory.getInstance("DOM");

        // Create a DOMValidateContext and specify a KeyValue KeySelector
        // and document context
        DOMValidateContext valContext = new DOMValidateContext
            (new KeyValueKeySelector(), nl.item(0));

        // unmarshal the XMLSignature
        XMLSignature signature = fac.unmarshalXMLSignature(valContext);

        // Validate the XMLSignature (generated above)
        boolean coreValidity = signature.validate(valContext);

        // Check core validation status
        if (coreValidity == false) {
            System.err.println("Signature failed core validation");
            boolean sv = signature.getSignatureValue().validate(valContext);
            System.out.println("signature validation status: " + sv);
            // check the validation status of each Reference
            Iterator i = signature.getSignedInfo().getReferences().iterator();
            for (int j=0; i.hasNext(); j++) {
                boolean refValid =
                    ((Reference) i.next()).validate(valContext);
                System.out.println("ref["+j+"] validity status: " + refValid);
            }
        } else {
            System.out.println("Signature passed core validation");
        }
    }

    /**
     * KeySelector which retrieves the public key out of the
     * KeyValue element and returns it.
     * NOTE: If the key algorithm doesn't match signature algorithm,
     * then the public key will be ignored.
     */
    private static class KeyValueKeySelector extends KeySelector {
        public KeySelectorResult select(KeyInfo keyInfo,
                                        KeySelector.Purpose purpose,
                                        AlgorithmMethod method,
                                        XMLCryptoContext context)
            throws KeySelectorException {
            if (keyInfo == null) {
                throw new KeySelectorException("Null KeyInfo object!");
            }
            SignatureMethod sm = (SignatureMethod) method;
            List list = keyInfo.getContent();

            for (int i = 0; i < list.size(); i++) {
                XMLStructure xmlStructure = (XMLStructure) list.get(i);
                if (xmlStructure instanceof KeyValue) {
                    PublicKey pk = null;
                    try {
                        pk = ((KeyValue)xmlStructure).getPublicKey();
                    } catch (KeyException ke) {
                        throw new KeySelectorException(ke);
                    }
                    // make sure algorithm is compatible with method
                    if (algEquals(sm.getAlgorithm(), pk.getAlgorithm())) {
                        return new SimpleKeySelectorResult(pk);
                    }
                }
            }
            throw new KeySelectorException("No KeyValue element found!");
        }

        //@@@FIXME: this should also work for key types other than DSA/RSA
        static boolean algEquals(String algURI, String algName) {
            if (algName.equalsIgnoreCase("DSA") &&
                algURI.equalsIgnoreCase("http://www.w3.org/2000/09/xmldsig#dsa-sha256")) {
                return true;
            } else if (algName.equalsIgnoreCase("RSA") &&
                       algURI.equalsIgnoreCase("http://www.w3.org/2000/09/xmldsig#dsa-sha256")) {
                return true;
            } else {
                return false;
            }
        }
    }

    private static class SimpleKeySelectorResult implements KeySelectorResult {
        private PublicKey pk;
        SimpleKeySelectorResult(PublicKey pk) {
            this.pk = pk;
        }

        public Key getKey() { return pk; }
    }
}