LoginSignup
9

More than 5 years have passed since last update.

posted at

JavaのXMLデジタル署名APIを利用してXML署名を検証する。

XML署名検証プロセスのイメージ

2016-09-20_173605.png

XML署名付与は、こちらを参照する。

署名検証の手順

1.署名要素と署名対象要素の特定

// 署名要素(Signature)の特定
Element sigNode = (Element) doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
// 署名検証対象要素(Product)の取得
Element targetNode = (Element)doc.getElementsByTagName("Product").item(0);

2.KeySelectorクラスの実装
KeySelector は、XMLSignature の検証に必要な鍵をKeyInfo要素から取得するために使用される。
※検証対象XMLにKeyInfo要素がない場合に、別途で鍵を用意する必要がある。
※下記の例には、KeyInfoから取得した鍵が信頼できるかどうかの判定は実施していない。

/**
 * KeySelectorの実装
 */
public class KeySelectorImp extends KeySelector {

    /**
     * 鍵の取得
     */
    @Override
    public KeySelectorResult select(KeyInfo keyInfo, Purpose purpose,
            AlgorithmMethod method, XMLCryptoContext context)
            throws KeySelectorException {

        if (keyInfo == null) {
            throw new KeySelectorException("KeyInfo is null");
        }

        // KeyInfo配下に検索し、X509サーバ証明書を取得する
        // サーバ証明書から公開鍵を取得し、KeySelectorResultを返却する
        for (Object keyInfoContent : keyInfo.getContent()) {
            if (keyInfoContent instanceof X509Data) {
                for (Object x509Content : ((X509Data)keyInfoContent).getContent()) {
                    X509Certificate cert = (X509Certificate)x509Content;
                    return new KeySelectorResultImp(cert.getPublicKey());
                }
            }
        }

        throw new KeySelectorException("Can't get KeySelectorResult from keyInfo");
    }

    /**
     * KeySelectorResultの実装(インナークラス)
     */
    private class KeySelectorResultImp implements KeySelectorResult {

        private Key key;

        public KeySelectorResultImp(Key key) {
            this.key = key;
        }

        @Override
        public Key getKey() {
            return this.key;
        }
    }
}

3.検証コンテキストの作成
署名を検証するためのXMLValidateContextインスタンスを作成する。

DOMValidateContext validateContext = new DOMValidateContext(new KeySelectorImp(), sigNode);
validateContext.setIdAttributeNS(targetNode, null, "id");

4.XML 署名の非整列化(XML文書⇒オブジェクト)
XMLSignatureFactory オブジェクトのunmarshalXMLSignatureメソッドを利用して署名要素をXMLSignatureオブジェクトに変換する。

XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM");
XMLSignature signature = signatureFactory.unmarshalXMLSignature(validateContext);

5.署名検証
XMLSignature オブジェクトで validate メソッドを呼び出して署名検証する。

boolean result = signature.validate(validateContext);

上記手順のまとめ

/**
 * XML署名検証
 * 
 * @param doc
 * @return
 * @throws MarshalException
 * @throws XMLSignatureException
 */
public boolean validate(Document doc) throws MarshalException, XMLSignatureException {

    // 署名要素(Signature)の取得
    Element sigNode = (Element) doc.getElementsByTagNameNS(XMLSignature.XMLNS, "Signature").item(0);
    // 署名検証対象要素(Product)の取得
    Element targetNode = (Element)doc.getElementsByTagName("Product").item(0);

    // 検証コンテキストの作成
    DOMValidateContext validateContext = new DOMValidateContext(new KeySelectorImp(), sigNode);
    validateContext.setIdAttributeNS(targetNode, null, "id");

    // 署名要素の非整列化 
    XMLSignatureFactory signatureFactory = XMLSignatureFactory.getInstance("DOM");
    XMLSignature signature = signatureFactory.unmarshalXMLSignature(validateContext);

    // 署名検証
    boolean result = signature.validate(validateContext);

    return result;
}

/**
 * KeySelectorの実装(インナークラス)
 */
private class KeySelectorImp extends KeySelector {

    /**
     * 鍵の取得
     */
    @Override
    public KeySelectorResult select(KeyInfo keyInfo, Purpose purpose,
            AlgorithmMethod method, XMLCryptoContext context)
            throws KeySelectorException {

        if (keyInfo == null) {
            throw new KeySelectorException("KeyInfo is null");
        }

        // KeyInfo配下に検索し、X509サーバ証明書を取得する
        // サーバ証明書から公開鍵を取得し、KeySelectorResultを返却する
        for (Object keyInfoContent : keyInfo.getContent()) {
            if (keyInfoContent instanceof X509Data) {
                for (Object x509Content : ((X509Data)keyInfoContent).getContent()) {
                    X509Certificate cert = (X509Certificate)x509Content;
                    return new KeySelectorResultImp(cert.getPublicKey());
                }
            }
        }

        throw new KeySelectorException("Can't get key from keyInfo");
    }

    /**
     * KeySelectorResultの実装(インナークラス)
     */
    private class KeySelectorResultImp implements KeySelectorResult {

        private Key key;

        public KeySelectorResultImp(Key key) {
            this.key = key;
        }

        @Override
        public Key getKey() {
            return this.key;
        }
    }
}

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
9