タイムスタンプサービス
無料でタイムスタンプトークンを発行するサービス、Free TSA Project に接続します。タイムスタンプリクエスト、タイムスタンプレスポンス、タイムスタンプトークンの生成、解析にはBouncy Castle Crypto APIsを使用しました。
タイムスタンププロトコル
タイムスタンプに関わる仕様は、RFC3161、RFC5816 で 定義されています。
HTTP通信で行う際の仕様が RFC3161 の 3.4 Time-Stamp Protocol via HTTP に記載されています。
Bouncy Castle Crypto APIs のダウンロード
LATEST JAVA RELEASESから最新版をダウンロードします。
必要なjarファイルは、Provider, ASN.1 Utility Classes, PKIX/CMS/EAC/PKCS/OCSP/TSP/OPENSSL の jar ファイルになります。
タイムスタンプサービスへの接続
今回は、HttpClientクラスを使用して、タイムスタンプサービスへ接続しました。
Content-Type に application/timestamp-query を指定し、ボディ句にDERエンコードした タイムスタンプリクエストを設定し、Postメソッドでタイムスタンプサービスに送ります。
サンプルプログラム
以下は、タイムスタンプサービスに接続し、タイムスタンプレスポンス、タイムスタンプトークンを出力するサンプルプログラムです。
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpClient.Version;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.bouncycastle.tsp.TSPAlgorithms;
import org.bouncycastle.tsp.TimeStampRequest;
import org.bouncycastle.tsp.TimeStampRequestGenerator;
import org.bouncycastle.tsp.TimeStampResponse;
import org.bouncycastle.tsp.TimeStampToken;
public class TimeStampHttpClient {
public static void main(String[] args) {
try {
//ハッシュ値の生成 SHA-256
MessageDigest sha256 = MessageDigest.getInstance("SHA-256");
byte[] sha256Byte = sha256.digest("Hello World".getBytes());
//タイムスタンプリクエストの作成
TimeStampRequestGenerator reqGen = new TimeStampRequestGenerator();
reqGen.setCertReq(true);
TimeStampRequest timeStampReq = reqGen.generate(TSPAlgorithms.SHA256, sha256Byte);
FileOutputStream fos1 = new FileOutputStream("HelloWorld.req");
fos1.write(timeStampReq.getEncoded());
fos1.close();
//タイムスタンプサービスに接続
HttpClient client = HttpClient.newBuilder().version(Version.HTTP_1_1).build();
HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("http://eswg.jnsa.org/freetsa"))
.header("Content-Type","application/timestamp-query")
.POST(HttpRequest.BodyPublishers.ofByteArray(timeStampReq.getEncoded()))
.build();
var res = client.send(req, HttpResponse.BodyHandlers.ofByteArray());
if ( res.statusCode() != 200 ) {
System.out.println("Error");
System.out.println(res.statusCode());
System.exit(-1);
}
//タイムスタンプレスポンスの出力
FileOutputStream fos2 = new FileOutputStream("HelloWorld.tsr");
byte[] resArray = res.body();
fos2.write(resArray);
fos2.close();
TimeStampResponse resp = new TimeStampResponse(resArray);
TimeStampToken token = resp.getTimeStampToken();
//タイムスタンプトークンの出力
FileOutputStream fos3 = new FileOutputStream("HelloWorld.tst");
fos3.write(token.getEncoded());
fos3.close();
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (Throwable e) {
e.printStackTrace();
}
}
}