1～オープンソースでタイムスタンプを使おう編～

2018-05-23
Naoto Miyachi（miyachi@langedge.jp）

LangEdge,Inc.

2

Q:何故「Re:」が付いているの?
A:2年前の春祭りでFreeXAdESを公開したのに放置していたものを再開したから…です…(^^;

LangEdge,Inc.

2年前のおさらい3

まず前回(2年前)のおさらい「第1回 〜XAdES-BES編〜」

LangEdge,Inc.

2年前のおさらい

4

FreeXAdES
⼊⾨/勉強⽤にシンプルなXAdESを実装※ ⾼度な機能が必要なら弊社製品版のご検討を…(^^;

Java標準機能で実装（他に依存しない）
 簡単でシンプルに使えること。
 ただしJava8以降の機能が必要。
Base64(Java8), XMLSignature(Java6)

XAdESレベル毎に勉強会で説明して⾏く
MPL v2.0 (Mozilla Public License) で公開

http://mozilla.org/MPL/2.0/
 商⽤利⽤も可能です。

LangEdge,Inc.

5

2年前のおさらいMPL v2 ライセンス
ソース公開義務

GPLMPLBSD

OSS本体への修正/追加分

〇

〇

×××

OSSを利⽤した
プログラム

公開必須

〇

公開必須

公開必須 公開不要

公開不要 公開不要

私の理解：間違っていたらご指摘ご指導をm(_ _)m FreeXAdESを使うプログラム/システムはソース公開義務無し
 FreeXAdES自体を修正したら修正部はソース公開義務あり※ GitHubで修正分をプルリクエストしてください!

LangEdge,Inc.

6

2年前のおさらい

XML署名と⻑期署名XAdES
注:XML署名済みファイルをXAdES化はできない！
機能

XML署名

XAdESレベル

デジタル署名〇
署名証明書保護▲ ※1
署名時刻証明 × TS使えない〇 XAdES-B

検証情報保持⻑期保管（⻑期署名）▲ ※2（XAdES-BES）〇 XAdES-T〇 XAdES-LT（XAdES-X Long）

XAdES-LTA× TS使えない 〇 （XAdES-A）※1 KeyInfo を参照（Reference）追加すれば可能。
※2 証明書認証パスの証明書群は KeyInfo の下に格納可能。

LangEdge,Inc.

7

2年前のおさらい

XAdESのXML構造例
Signature（XmlDsig：ルート）
SignedInfo（XmlDsig：署名情報）

XML署名要素にXAdES要素を追加することでXAdES化

Reference URI=“#Sign-Target”（XmlDsig：署名対象参照）
Reference URI=“#XAdES-Sign-Atrb”（XmlDsig：XAdES参照）
SignatureValue（XmlDsig：署名値）
KeyInfo（XmlDsig：鍵/証明書情報）

ハッシュ値

Object（XmlDsig：XAdESオブジェクト）
QualifyingProperties（XAdES：属性情報）

SignedProperties Id=“XAdES-Sign-Atrb” (XAdES：署名属性領域)
UnsignedProperties (XAdES：⾮署名属性領域)
UnsignedSignatureProperties（XAdES）
SignatureTimeStamp (XAdES：署名タイムスタンプ)
Object Id=“Sign-Target”（XmlDsig：署名対象）

今回の追加要素LangEdge,Inc.

2年前のおさらい

8

以上で「おさらい」は終了。
XML署名/XAdESの基本部であるXAdES-Bについては前回の資料を参照してください。

☟

http://eswg.jnsa.org/matsuri/201605/20160523-S4-miyachi.pdf

LangEdge,Inc.

9

さて今回のテーマは、オープンソースでタイムスタンプを使おう編LangEdge,Inc.

10⻑期署名とタイムスタンプ(RFC 3161)
XAdESレベル機能（長期署名の内容）

XAdES-B

署名のみ（前回の FreeXAdES β1版）
署名タイムスタンプ追加（β2版）

XAdES-T※ 署名値の保護と署名時刻の証明

検証情報（証明書と失効情報）追加
XAdES-LTA アーカイブタイムスタンプ追加
XAdES-LT（XAdES-A）※ 長期保管：直前までの内容の保護

⻑期署名のタイムスタンプは⽬的別に2種類ある。

 署名タイムスタンプとアーカイブタイムスタンプ（対象が異なる）
 どちらもタイムスタンプ⾃体は RFC 3161 に準拠※ 今回はXAdES-Tの⽣成までを実装。

LangEdge,Inc.

11

署名タイムスタンプのXML表現
SignatureTimeStamp要素 （XAdES v1.3）
署名タイムスタンプ用の主要素

EncapsulatedTimeStamp要素 （XAdES v1.3）
タイムスタンプトークンをBase64で指定する要素
ArchiveTimeStamp要素等でも利用される形式<xades:SignatureTimeStamp><xades:EncapsulatedTimeStamp>

MIILMAYJKoZIhvcNAQcCoIILITCCCx0CAQMxCzAJBgUrDgMCGgUAMIHZBgsqhkiG9w0BCRABBKCByQSBxjCBwwIBAQYEVR0gADAvMAsGCWCGSAFlAwQCAQQgQuDEa604gDa6Mn6aFVrrykYTZDxzc59F
eNhORleCiaACAhFYGA8yMDE4MDUxMTAwNTUwNlowCgIBAYACAfSBAWQBAf8CCIoF/NG9J+ZRoFmk（略）
rVNQt0Bx3YkMKQa3pOV3zuSS4m/KjYfMA/Tm1J5//ZGYkXVMGQ8zr0FDsU8MIGmOZQFEpcD7/xkj
4HS6KEEKEQZYS89FnSD/nnNmt/sDGwk4iU/4wTdvDaKdh6rXuKnxEHYm1Mna0/rM7InO4UNvCfUX/033OHgJWo0n/X29JSikvFZk</xades:EncapsulatedTimeStamp></xades:SignatureTimeStamp>

Base64化されたタイムスタンプトークン
RFC 3161準拠のTimeStampToken※ RFC 3161準拠タイムスタンプトークンが必要!

LangEdge,Inc.

12

PKIハンズオン資料から抜粋

参考：タイムスタンプサービスの構成※ タイムスタンプはサーバ署名（署名対象に時刻を含む）である！
時刻認証局:TSA(TimeStamping Authority)

NTA （国家時刻標準機関）

認証局:CATSAに証明書を提供

タイムスタンプサーバ運用

CA （認証局）

TSA （タイムスタンプ局）
証明書

TA （時刻配信局）
時刻

時刻配信局:TA(Time Authority)
厳正で信頼できる時刻を保持し、TSAに提供
クライアントはTSAのサーバURLの情報が必要

秘密鍵

TSA証明書

HTTP(HTTPS)

RFC 3161 over HTTP

通信
クライアント（利用者）
タイムスタンプ
クライアントクライアントアプリ
TSAのサーバに対してRFC 3161のリクエストを送信
レスポンスからタイムスタンプトークンを取得する

LangEdge,Inc.

13

TSクライアントアプリに必要な機能
1. タイムスタンプトークン取得① ハッシュ値からタイムスタンプリクエストの⽣成② タイムスタンプリクエストをサーバへ送信③ タイムスタンプレスポンスの確認とトークン取得

2. タイムスタンプトークン解析① ASN.1/DERの解析機能② タイムスタンプ時刻の取り出し③ タイムスタンプトークンの検証（ハッシュ値取り出し）

どちらもJava標準機能/クラスには無い!

LangEdge,Inc.

14

FreeXAdESは、Java標準機能だけで実装すると宣⾔しているので…
フルスクラッチで実装するしかない！
（良い⼦はマネをしないよーにw）（素直にBouncyCastle使えよ…）

LangEdge,Inc.

15

タイムスタンプトークンの取得
実は2015年に実施した、「電⼦署名（PKI）ハンズオン」

にて、タイムスタンプの解説と取得の為のJava実装は公開済み。
資料の43ページから62ページを参照！
タイムスタンプの仕組みも分かります。

http://eswg.jnsa.org/sandbox/handson/ESig-PKI-handson-doc-v100.pdf

FreeTimeStampクラスのgetFromServerメソッドとして再実装した。

LangEdge,Inc.

16

タイムスタンプトークンの取得API/** タイムスタンプをサーバ（TSA）から取得する */public int getFromServer (byte[] hash,// タイムスタンプ対象のハッシュ値をバイナリで指定
String url,// タイムスタンプサーバのURLを指定
String userid,// Basic認証が必要な場合にユーザIDを指定
String passwd// Basic認証が必要な場合にパスワードを指定);/** 取得済みタイムスタンプからタイムスタンプトークンを取得する */public byte[] getToken ();利用例：// FreeTimeStampインスタンス⽣成
FreeTimeStamp timestamp = new FreeTimeStamp();// ハッシュ対象の⽤意（FreePKI.getHashによりハッシュ計算可能）
byte[] hash = FreePKI.getHash(target.getBytes(), "SHA-256");// タイムスタンプのサーバからの取得（ネットワーク接続/HTTP通信）
rc = timestamp.getFromServer(hash, tsUrl, tsUserid, tsPasswd);// タイムスタンプトークンの取得
byte[] token = timestamp.getToken();LangEdge,Inc.

17

PKIハンズオン資料から抜粋

参考：タイムスタンプ取得手順

データは全てASN.1/DER 形式

1. 対象データのハッシュ値を計算
2. ハッシュ値を埋め込んだタイムスタンプリクエスト生成
タイムスタンプリクエスト
ハッシュ値

通常nonceも必要です

3. タイムスタンプリクエストをサーバに送信
4. サーバからタイムスタンプレスポンスを取得
ハッシュ値

タイムスタンプレスポンス

ステータス

タイムスタンプトークン
署名
時刻

TSA証明書nonceも確認

5. タイムスタンプレスポンスのステータスを確認
6. レスポンスからタイムスタンプトークンを取り出し利用
ハッシュ値

タイムスタンプトークン
署名
時刻

TSA証明書LangEdge,Inc.

PKIハンズオン資料から抜粋

参考：タイムスタンプ リクエスト

18※ FreeTimeStampではSHA-256/512のみ対応// SHA-1タイムスタンプリクエスト情報BER定義
byte[] sha1req = {全て固定長なので0x30, 0x31,// Request SEQUENCE (49バイト)
バイナリで準備を0x02, 0x01, 0x01,// Version INTEGER (1バイト) value:1しておけば良い。
0x30, 0x1f,// MessageImprint SEQUENCE (31バイト)
Javaソース参照。
0x30, 0x07,// AlgorithmOID SEQUENCE (7バイト)
0x06, 0x05,// OID (5バイト)
0x2b, 0x0e, 0x03, 0x02, 0x1a,// OIDSHA1 value: 1.3.14.3.2.26 SHA-1なら20バイトの0x04, 0x14,// Hash OCTET STRING (20バイト) ハッシュ値をセットすれ0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
ば良い
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x02, 0x08,// Nonce INTEGER (8バイト)
Nonceは8バイト（任意）固定
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,0x01, 0x01, 0xff// RequestCertificate BOOLEAN (1バイト) value:true};
TimeStampReq ::= SEQUENCE {versionINTEGER { v1(1) },messageImprint MessageImprint,
reqPolicy
TSAPolicyId OPTIONAL,
nonce
INTEGER OPTIONAL,
certReq
BOOLEAN DEFAULT FALSE,
extensions[0] IMPLICIT Extensions OPTIONAL}

MessageImprint ::= SEQUENCE {hashAlgorithm AlgorithmIdentifier,hashedMessage OCTET STRING}

LangEdge,Inc.

19

PKIハンズオン資料から抜粋

参考：タイムスタンプ レスポンス
TimeStampResp ::= SEQUENCE {成功（granted）ならタイムスタンプトークン
status
PKIStatusInfo,が含まれる
timeStampToken TimeStampToken OPTIONAL}
PKIStatusInfo ::= SEQUENCE {status
PKIStatus,
statusをチェックする
statusString PKIFreeText OPTIONAL,
failInfo
PKIFailureInfo OPTIONAL}// レスポンスのステータス
PKIStatus ::= INTEGER {granted(0),grantedWithMods(1),rejection(2),waiting(3),
revocationWarning(4),
revocationNotification (5)}// TSTを含む// TSTを含み、プライベート拡張を含む// TSTを含まず、拒否された// TSTを含まず、レシートのみ含む// TSTを含まず、TSA証明書の失効が近い// TSTを含まず、TSA証明書が失効しているOK

簡単な構造だけどここでもASN.1/DERの解析が必要になる。
タイムスタンプレスポンスの解析にも後述のFreePKIを利用。

LangEdge,Inc.

20

タイムスタンプトークンの解析
ASN.1/DER解析の為に新たに、FreePKIクラスをフルスクラッチで実装し、FreeTimeStampクラスのsetTokenメソッドにトークン解析を実装。
byte[] getToken();
String getTimeStampDate();byte[] getSerial();byte[] getNonce();
String getMsgImprintAlg();
byte[] getMsgImprint();
X509Certificate getSignerCert();
X509Certificate[] getAllCerts();// タイムスタンプトークンの取得// タイムスタンプ時刻の取得// タイムスタンプシリアル番号の取得// タイムスタンプナンスの取得// タイムスタンプ対象ハッシュアルゴリズムの取得// タイムスタンプ対象ハッシュ値の取得// タイムスタンプ(TSA)証明書の取得// タイムスタンプに含まれる全証明書の取得※ ASN.1/DERについてはPKIハンズオン資料の18ページから22ページで解説。

LangEdge,Inc.

21

タイムスタンプトークンの解析API/** 取得済みのタイムスタンプトークンのバイナリをセットして検証する※ getFromServerの実⾏済みならsetTokenは不要 */public int setToken (byte[] token// 取得済みタイムスタンプトークンをバイナリで指定);/** タイムスタンプトークンを検証 (TSA証明書検証はsetTokenで実⾏済み) */public int verify (byte[] hash// タイムスタンプ対象のハッシュ値をバイナリで指定);
利用例：// FreeTimeStampインスタンス⽣成
FreeTimeStamp timestamp = new FreeTimeStamp();// 取得済みタイムスタンプのセット（XAdESの署名タイムスタンプ等）
rc = timestamp.setToken(token);// タイムスタンプの情報取得（他getTimeStampDate等APIあり 前ページ参照）
String info = timestamp.getInfo();// タイムスタンプの検証（MessageImprintハッシュ値の確認等）
rc = timestamp.verify(hash);LangEdge,Inc.

22

参考：タイムスタンプトークンの検証
TimestampTokenTSTInfos
MessageImprint : タイムスタンプ対象ハッシュ値

verify()対象

GeneralizedTime : タイムスタンプ時刻
Certificatescertificate : EE（TSA証明書）
certificate : ROOT（ルート証明書）

setToken()

SignerInfos
SignedAttributes
MessageDigest : TSTInfosのハッシュ値
SignatureValue : SignedAttributes のハッシュ値（署名）
setToken()

LangEdge,Inc.

23

FreeXAdES XAdES-Tの⽣成API/** 署名タイムスタンプを追加する */public int addEsT (String url,// タイムスタンプサーバのURLを指定
String userid,// Basic認証が必要な場合にユーザIDを指定
String passwd, // Basic認証が必要な場合にパスワードを指定
String id,// SignatureTimeStamp要素に付けるIdの指定
String xpath// 対象となるSignature要素をXPathで指定);
利用例：// FreeXAdESインスタンス⽣成
FreeXAdES xades = new FreeXAdES();// XAdES-Bファイルの読み込み（XAdES-B署名済みのファイルを⽤意）
rc = xades.loadXml("xades-b.xml", IFreeXAdES.FXAT_FILE_PATH);// 署名タイムスタンプの追加
rc = xades.addEsT(tsUrl, tsUserid, tsPasswd, "ES-T-test", xpath);// XAdES-Tの検証（仮：XAdES-Tのタイムスタンプ検証も⾏う）
rc = xades.verifySign(IFreeXAdES.FXVF_NONE, xpath);// XAdES-Tファイルの保存
rc = xades.saveXml("xades-t.xml");LangEdge,Inc.

24

FreeXAdES β2版のまとめ新たに2つのクラスを実装した。
FreeTimeStamp クラス→ タイムスタンプの取得と解析の実装

FreePKI クラス→ ASN.1/DER解析やハッシュ値取得等の実装

FreeXAdESクラスにaddEsTメソッドを追加。

FreeXAdESでXAdES-Tが使えるようになった！

LangEdge,Inc.

25

タイムスタンプ利⽤のすゝめ
タイムスタンプはREST API的に使える。

異なる点はJSON/XMLでは無くASN.1/DERを使うところ。
→ FreeTimeStampを使えばASN.1/DERは使える。

システムログの保護であったり研究資料の保護にも使えるタイムスタンプ！

FreeTimeStampクラスはFreePKIクラスにのみに依存！
単独でも気軽に使えます！

LangEdge,Inc.

26

次回予告
XAdES-LT（XAdES-X Long）への対応。

検証…いよいよに着⼿します…
検証はPKIの基本であり最も重要な機能です!

果たして秋祭りで発表できるのか?
それとも来年の春祭りなのかっ?
「Re:Re:」 にならないように…
ご期待ください！（誰も待って無いってwLangEdge,Inc.

27

おまけ：FreeXAdESを試す
公開リポジトリhttps://github.com/miyachi/FreeXAdES

開発環境
Eclipse IDE for Java Developers
Version：Mars or after (ex:Oxygen)
Java：Java8 or after
Other：JUnit4（eclipse標準）

LangEdge,Inc.

おまけ：FreeXAdESを試す⼿順1
Menu: [File]-[Import…]
Select: [Git]-[Projects from Git] click [Next>]
Select: [Clone URI] click [Next>]

28

LangEdge,Inc.

29

おまけ：FreeXAdESを試す⼿順2
URI: “https://github.com/miyachi/FreeXAdES” click [Next>]
Branch Selection: click [Next>]

LangEdge,Inc.

30

おまけ：FreeXAdESを試す⼿順3
Directory: “C:¥Users¥XXX¥workspace¥FreeXAdES” click [Next>]
注：Directoryの設定パスはワークスペース下のFreeXAdESにすること。

このパスが手順5のLocationパスと同じである必要があります。

LangEdge,Inc.

31

おまけ：FreeXAdESを試す⼿順4
Select: [Import using the New Project wizard] click [Next>]
Wizards: [Java]-[Java Project] click [Next>]

LangEdge,Inc.

32

おまけ：FreeXAdESを試す⼿順5
Poject name: “FreeXAdES” click [Next>]
注：Locationが “C:¥Users¥XXX¥workspace¥FreeXAdES” になること。

このパスが手順3のDirectoryパスと同じになっていないとエラーになるので注意してください。

LangEdge,Inc.

おまけ：FreeXAdESを試す⼿順6
Libraries: click [Add Library]
Add Library: select [JUnit] click [Next>]

33

LangEdge,Inc.

おまけ：FreeXAdESを試す⼿順7
JUnit Library version: select [JUnit 4] click [Finish]
Java Setting: click [Finish]

34

LangEdge,Inc.

35

おまけ：FreeXAdESのJUnit実⾏
Open: FreeXAdeS/src/jp/langedge/FreeXAdES/IFreeXAdESTest.java
Menu: [Run]-[Run]LangEdge,Inc.

36

おまけ：FreeXAdESのSample実⾏
Windows:> cd test
> FxSample.bat
Sample Compile.
Sample Execute.
- create.
- add Detached.
- exec Sign.
- add ES-T.
- save XAdES-T.
- exec Verify = [OK]- done.
Sample Finished.
>Eclipse/JUnit不要

Linux:$ cd test$ chmod +x *.sh
$ ./FxSample.shSample Compile.
Sample Execute.
- create.
- add Detached.
- exec Sign.
- add ES-T.
- save XAdES-T.
- exec Verify = [OK]- done.
Sample Finished.
$