LoginSignup
6
10

More than 5 years have passed since last update.

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

Posted at

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;
        }
    }
}
6
10
0

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
  3. You can use dark theme
What you can do with signing up
6
10