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

##XML署名検証プロセスのイメージ
![2016-09-20_173605.png](https://qiita-image-store.s3.amazonaws.com/0/123138/38c590f4-112d-6974-aa9a-9ab4a2bc4b70.png)


XML署名付与は、[こちら](http://qiita.com/KevinFQ/items/4e2484a659b618530e72)を参照する。

##署名検証の手順
１．署名要素と署名対象要素の特定

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

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

```java
/**
 * 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;
		}
	}
}
```

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

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

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

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

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

```java
boolean result = signature.validate(validateContext);
```

##上記手順のまとめ

```java
/**
 * 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;
		}
	}
}
```