C#で無料のタイムスタンプサービスに接続する

## タイムスタンプサービス

無料でタイムスタンプトークンを発行するサービスはいくつかありますが、今回は以下に接続しました。

[Free TSA Project](http://eswg.jnsa.org/sandbox/freetsa/)


## タイムスタンププロトコル

タイムスタンプに関わる仕様は、[RFC3161](https://datatracker.ietf.org/doc/html/rfc3161)、[RFC5816](https://datatracker.ietf.org/doc/html/rfc5816) で 定義されています。

HTTP通信で行う際の仕様が [RFC3161 の 3.4 Time-Stamp Protocol via HTTP](https://datatracker.ietf.org/doc/html/rfc3161#section-3.4) に記載されています。

## タイムスタンプサービスへの接続

[HttpClientクラス](https://learn.microsoft.com/ja-jp/dotnet/api/system.net.http.httpclient?view=net-7.0)を使用して、タイムスタンプサービスへ接続します。

Content-Type に application/timestamp-query を指定し、ボディ句にDERエンコードした タイムスタンプリクエストを設定し、Postメソッドでタイムスタンプサービスに送ります。

## タイムスタンプレスポンスからタイムスタンプトークンの取り出し

Rfc3161TimestampRequestクラスの[ProcessResponseメソッド](https://learn.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.pkcs.rfc3161timestamprequest.processresponse?view=dotnet-plat-ext-7.0#system-security-cryptography-pkcs-rfc3161timestamprequest-processresponse(system-readonlymemory((system-byte))-system-int32@))でタイムスタンプレスポンスからタイムスタンプトークンを取り出します。

## タイムスタンプトークンのDERエンコード
Rfc3161TimestampToken クラスから直接、DERエンコードするメソッドは存在しませんでした。その代わりに、タイムスタンプトークンは SignedData 型でもあるので、タイムスタンプトークンをSingedData型として扱うメソッド [AsSignedCms](https://learn.microsoft.com/ja-jp/dotnet/api/system.security.cryptography.pkcs.rfc3161timestamptoken.assignedcms?view=dotnet-plat-ext-7.0#system-security-cryptography-pkcs-rfc3161timestamptoken-assignedcms)を経由してDERエンコードしました。

## サンプルプログラム

以下は、タイムスタンプサービスに接続し、タイムスタンプレスポンス、タイムスタンプトークンを出力するサンプルプログラムです。

```c#
// See https://aka.ms/new-console-template for more information
using System.Security.Cryptography;
using System.Security.Cryptography.Pkcs;
using System.Text;
using System.Net.Http;
using static System.Net.Mime.MediaTypeNames;

// 文字列
string str = "Hello World";
byte[] beforeByteArray = Encoding.UTF8.GetBytes(str);


//タイムスタンプリクエストの作成
Rfc3161TimestampRequest req = Rfc3161TimestampRequest.CreateFromData(beforeByteArray, HashAlgorithmName.SHA256, null, null, true);
byte[] reqByteArray = req.Encode();

//タイムスタンプサービスへの接続
//Content-Type に application/timestamp-query を指定
//ボディ句にDERエンコードした タイムスタンプリクエストを設定し、Postメソッドでタイムスタンプサービスに送ります。
var content = new ByteArrayContent(reqByteArray);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(@"application/timestamp-query");

HttpClient client = new HttpClient();

var response = await client.PostAsync($"http://eswg.jnsa.org/freetsa", content);

if ( response.IsSuccessStatusCode )
{
    var respByteArray = await response.Content.ReadAsByteArrayAsync();

    //タイムスタンプレスポンスを出力
    string fileName1 = @"HelloWorld.tsr";
    using (var writer = new BinaryWriter(new FileStream(fileName1, FileMode.Create)))
        //書き込み処理
        writer.Write(respByteArray);

    var timeStampToken = req.ProcessResponse(respByteArray, out int length);

    //タイムスタンプトークンを出力
    string fileName2 = @"HelloWorld.tst";
    using (var writer = new BinaryWriter(new FileStream(fileName2, FileMode.Create)))
        //書き込み処理
        writer.Write(timeStampToken.AsSignedCms().Encode());
    
}
```
## タイムスタンプレスポンスの解析

タイムスタンプサービスから返されたタイムスタンプレスポンスをOpenSSLで解析します。

```
> openssl ts -reply -in HelloWorld.tsr -text
Using configuration from C:\Program Files\Common Files\SSL/openssl.cnf
Status info:
Status: Granted.
Status description: unspecified
Failure info: unspecified

TST info:
Version: 1
Policy OID: X509v3 Any Policy
Hash Algorithm: sha256
Message data:
    0000 - a5 91 a6 d4 0b f4 20 40-4a 01 17 33 cf b7 b1 90   ...... @J..3....
    0010 - d6 2c 65 bf 0b cd a3 2b-57 b2 77 d9 ad 9f 14 6e   .,e....+W.w....n
Serial number: 0x081196
Time stamp: Jan  5 12:27:53 2023 GMT
Accuracy: 0x01 seconds, 0x01F4 millis, 0x64 micros
Ordering: yes
Nonce: unspecified
TSA: DirName:/C=JP/O=JNSA/OU=ESWG/CN=JNSA PKI Sandbox FreeTSA 300001
Extensions:
```

## タイムスタンプトークンを解析する

C#のプログラムでタイムスタンプレスポンスから取り出したタイムスタンプトークンをOpenSSLで解析した結果です。

```
> openssl asn1parse -inform DER -in HelloWorld.tst
    0:d=0  hl=4 l=2857 cons: SEQUENCE
    4:d=1  hl=2 l=   9 prim: OBJECT            :pkcs7-signedData
   15:d=1  hl=4 l=2842 cons: cont [ 0 ]
   19:d=2  hl=4 l=2838 cons: SEQUENCE
   23:d=3  hl=2 l=   1 prim: INTEGER           :03
   26:d=3  hl=2 l=  11 cons: SET
   28:d=4  hl=2 l=   9 cons: SEQUENCE
   30:d=5  hl=2 l=   5 prim: OBJECT            :sha1
   37:d=5  hl=2 l=   0 prim: NULL
   39:d=3  hl=3 l= 210 cons: SEQUENCE
   42:d=4  hl=2 l=  11 prim: OBJECT            :id-smime-ct-TSTInfo
   55:d=4  hl=3 l= 194 cons: cont [ 0 ]
   58:d=5  hl=3 l= 191 prim: OCTET STRING      [HEX DUMP]:3081BC0201010604551D20003031300D060960864801650304020105000420A591A6D40BF420404A011733CFB7B190D62C65BF0BCDA32B57B277D9AD9F146E0203081196180F32303233303130353132323735335A300A020101800201F48101640101FFA059A4573055310B3009060355040613024A50310D300B060355040A13044A4E5341310D300B060355040B130445535747312830260603550403131F4A4E534120504B492053616E64626F78204672656554534120333030303031
  252:d=3  hl=4 l=2076 cons: cont [ 0 ]
  256:d=4  hl=4 l= 991 cons: SEQUENCE
  260:d=5  hl=4 l= 711 cons: SEQUENCE
  264:d=6  hl=2 l=   3 cons: cont [ 0 ]
  266:d=7  hl=2 l=   1 prim: INTEGER           :02
  269:d=6  hl=2 l=   7 prim: INTEGER           :038D7EA4C68002
  278:d=6  hl=2 l=  13 cons: SEQUENCE
  280:d=7  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
  291:d=7  hl=2 l=   0 prim: NULL
  293:d=6  hl=2 l=  80 cons: SEQUENCE
  295:d=7  hl=2 l=  11 cons: SET
  297:d=8  hl=2 l=   9 cons: SEQUENCE
  299:d=9  hl=2 l=   3 prim: OBJECT            :countryName
  304:d=9  hl=2 l=   2 prim: PRINTABLESTRING   :JP
  308:d=7  hl=2 l=  13 cons: SET
  310:d=8  hl=2 l=  11 cons: SEQUENCE
  312:d=9  hl=2 l=   3 prim: OBJECT            :organizationName
  317:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :JNSA
  323:d=7  hl=2 l=  13 cons: SET
  325:d=8  hl=2 l=  11 cons: SEQUENCE
  327:d=9  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
  332:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :ESWG
  338:d=7  hl=2 l=  35 cons: SET
  340:d=8  hl=2 l=  33 cons: SEQUENCE
  342:d=9  hl=2 l=   3 prim: OBJECT            :commonName
  347:d=9  hl=2 l=  26 prim: PRINTABLESTRING   :JNSA PKI Sandbox CA Root 2
  375:d=6  hl=2 l=  30 cons: SEQUENCE
  377:d=7  hl=2 l=  13 prim: UTCTIME           :150225051928Z
  392:d=7  hl=2 l=  13 prim: UTCTIME           :250304051928Z
  407:d=6  hl=2 l=  80 cons: SEQUENCE
  409:d=7  hl=2 l=  11 cons: SET
  411:d=8  hl=2 l=   9 cons: SEQUENCE
  413:d=9  hl=2 l=   3 prim: OBJECT            :countryName
  418:d=9  hl=2 l=   2 prim: PRINTABLESTRING   :JP
  422:d=7  hl=2 l=  13 cons: SET
  424:d=8  hl=2 l=  11 cons: SEQUENCE
  426:d=9  hl=2 l=   3 prim: OBJECT            :organizationName
  431:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :JNSA
  437:d=7  hl=2 l=  13 cons: SET
  439:d=8  hl=2 l=  11 cons: SEQUENCE
  441:d=9  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
  446:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :ESWG
  452:d=7  hl=2 l=  35 cons: SET
  454:d=8  hl=2 l=  33 cons: SEQUENCE
  456:d=9  hl=2 l=   3 prim: OBJECT            :commonName
  461:d=9  hl=2 l=  26 prim: PRINTABLESTRING   :JNSA PKI Sandbox CA Root 2
  489:d=6  hl=4 l= 290 cons: SEQUENCE
  493:d=7  hl=2 l=  13 cons: SEQUENCE
  495:d=8  hl=2 l=   9 prim: OBJECT            :rsaEncryption
  506:d=8  hl=2 l=   0 prim: NULL
  508:d=7  hl=4 l= 271 prim: BIT STRING
  783:d=6  hl=3 l= 189 cons: cont [ 3 ]
  786:d=7  hl=3 l= 186 cons: SEQUENCE
  789:d=8  hl=2 l=  11 cons: SEQUENCE
  791:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Key Usage
  796:d=9  hl=2 l=   4 prim: OCTET STRING      [HEX DUMP]:03020106
  802:d=8  hl=2 l=  29 cons: SEQUENCE
  804:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Subject Key Identifier
  809:d=9  hl=2 l=  22 prim: OCTET STRING      [HEX DUMP]:0414D24B314B551A3C5A2D868CD7ECDEE83FDA5FCF83
  833:d=8  hl=2 l= 126 cons: SEQUENCE
  835:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Authority Key Identifier
  840:d=9  hl=2 l= 119 prim: OCTET STRING      [HEX DUMP]:30758014D24B314B551A3C5A2D868CD7ECDEE83FDA5FCF83A154A4523050310B3009060355040613024A50310D300B060355040A13044A4E5341310D300B060355040B130445535747312330210603550403131A4A4E534120504B492053616E64626F7820434120526F6F7420328207038D7EA4C68002
  961:d=8  hl=2 l=  12 cons: SEQUENCE
  963:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Basic Constraints
  968:d=9  hl=2 l=   5 prim: OCTET STRING      [HEX DUMP]:30030101FF
  975:d=5  hl=2 l=  13 cons: SEQUENCE
  977:d=6  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
  988:d=6  hl=2 l=   0 prim: NULL
  990:d=5  hl=4 l= 257 prim: BIT STRING
 1251:d=4  hl=4 l=1077 cons: SEQUENCE
 1255:d=5  hl=4 l= 797 cons: SEQUENCE
 1259:d=6  hl=2 l=   3 cons: cont [ 0 ]
 1261:d=7  hl=2 l=   1 prim: INTEGER           :02
 1264:d=6  hl=2 l=   3 prim: INTEGER           :300001
 1269:d=6  hl=2 l=  13 cons: SEQUENCE
 1271:d=7  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
 1282:d=7  hl=2 l=   0 prim: NULL
 1284:d=6  hl=2 l=  80 cons: SEQUENCE
 1286:d=7  hl=2 l=  11 cons: SET
 1288:d=8  hl=2 l=   9 cons: SEQUENCE
 1290:d=9  hl=2 l=   3 prim: OBJECT            :countryName
 1295:d=9  hl=2 l=   2 prim: PRINTABLESTRING   :JP
 1299:d=7  hl=2 l=  13 cons: SET
 1301:d=8  hl=2 l=  11 cons: SEQUENCE
 1303:d=9  hl=2 l=   3 prim: OBJECT            :organizationName
 1308:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :JNSA
 1314:d=7  hl=2 l=  13 cons: SET
 1316:d=8  hl=2 l=  11 cons: SEQUENCE
 1318:d=9  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
 1323:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :ESWG
 1329:d=7  hl=2 l=  35 cons: SET
 1331:d=8  hl=2 l=  33 cons: SEQUENCE
 1333:d=9  hl=2 l=   3 prim: OBJECT            :commonName
 1338:d=9  hl=2 l=  26 prim: PRINTABLESTRING   :JNSA PKI Sandbox CA Root 2
 1366:d=6  hl=2 l=  30 cons: SEQUENCE
 1368:d=7  hl=2 l=  13 prim: UTCTIME           :150225063024Z
 1383:d=7  hl=2 l=  13 prim: UTCTIME           :250222063024Z
 1398:d=6  hl=2 l=  85 cons: SEQUENCE
 1400:d=7  hl=2 l=  11 cons: SET
 1402:d=8  hl=2 l=   9 cons: SEQUENCE
 1404:d=9  hl=2 l=   3 prim: OBJECT            :countryName
 1409:d=9  hl=2 l=   2 prim: PRINTABLESTRING   :JP
 1413:d=7  hl=2 l=  13 cons: SET
 1415:d=8  hl=2 l=  11 cons: SEQUENCE
 1417:d=9  hl=2 l=   3 prim: OBJECT            :organizationName
 1422:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :JNSA
 1428:d=7  hl=2 l=  13 cons: SET
 1430:d=8  hl=2 l=  11 cons: SEQUENCE
 1432:d=9  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
 1437:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :ESWG
 1443:d=7  hl=2 l=  40 cons: SET
 1445:d=8  hl=2 l=  38 cons: SEQUENCE
 1447:d=9  hl=2 l=   3 prim: OBJECT            :commonName
 1452:d=9  hl=2 l=  31 prim: PRINTABLESTRING   :JNSA PKI Sandbox FreeTSA 300001
 1485:d=6  hl=4 l= 290 cons: SEQUENCE
 1489:d=7  hl=2 l=  13 cons: SEQUENCE
 1491:d=8  hl=2 l=   9 prim: OBJECT            :rsaEncryption
 1502:d=8  hl=2 l=   0 prim: NULL
 1504:d=7  hl=4 l= 271 prim: BIT STRING
 1779:d=6  hl=4 l= 273 cons: cont [ 3 ]
 1783:d=7  hl=4 l= 269 cons: SEQUENCE
 1787:d=8  hl=2 l=  11 cons: SEQUENCE
 1789:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Key Usage
 1794:d=9  hl=2 l=   4 prim: OCTET STRING      [HEX DUMP]:030206C0
 1800:d=8  hl=2 l=  22 cons: SEQUENCE
 1802:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Extended Key Usage
 1807:d=9  hl=2 l=   1 prim: BOOLEAN           :255
 1810:d=9  hl=2 l=  12 prim: OCTET STRING      [HEX DUMP]:300A06082B06010505070308
 1824:d=8  hl=2 l=  29 cons: SEQUENCE
 1826:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Subject Key Identifier
 1831:d=9  hl=2 l=  22 prim: OCTET STRING      [HEX DUMP]:04148B1997D03F0768CE93E79343DBED80992B9C5A09
 1855:d=8  hl=2 l= 126 cons: SEQUENCE
 1857:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Authority Key Identifier
 1862:d=9  hl=2 l= 119 prim: OCTET STRING      [HEX DUMP]:30758014D24B314B551A3C5A2D868CD7ECDEE83FDA5FCF83A154A4523050310B3009060355040613024A50310D300B060355040A13044A4E5341310D300B060355040B130445535747312330210603550403131A4A4E534120504B492053616E64626F7820434120526F6F7420328207038D7EA4C68002
 1983:d=8  hl=2 l=   9 cons: SEQUENCE
 1985:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 Basic Constraints
 1990:d=9  hl=2 l=   2 prim: OCTET STRING      [HEX DUMP]:3000
 1994:d=8  hl=2 l=  60 cons: SEQUENCE
 1996:d=9  hl=2 l=   3 prim: OBJECT            :X509v3 CRL Distribution Points
 2001:d=9  hl=2 l=  53 prim: OCTET STRING      [HEX DUMP]:30333031A02FA02D862B687474703A2F2F657377672E6A6E73612E6F72672F73616E64626F782F6672656563612F6361322E63726C
 2056:d=5  hl=2 l=  13 cons: SEQUENCE
 2058:d=6  hl=2 l=   9 prim: OBJECT            :sha256WithRSAEncryption
 2069:d=6  hl=2 l=   0 prim: NULL
 2071:d=5  hl=4 l= 257 prim: BIT STRING
 2332:d=3  hl=4 l= 525 cons: SET
 2336:d=4  hl=4 l= 521 cons: SEQUENCE
 2340:d=5  hl=2 l=   1 prim: INTEGER           :01
 2343:d=5  hl=2 l=  87 cons: SEQUENCE
 2345:d=6  hl=2 l=  80 cons: SEQUENCE
 2347:d=7  hl=2 l=  11 cons: SET
 2349:d=8  hl=2 l=   9 cons: SEQUENCE
 2351:d=9  hl=2 l=   3 prim: OBJECT            :countryName
 2356:d=9  hl=2 l=   2 prim: PRINTABLESTRING   :JP
 2360:d=7  hl=2 l=  13 cons: SET
 2362:d=8  hl=2 l=  11 cons: SEQUENCE
 2364:d=9  hl=2 l=   3 prim: OBJECT            :organizationName
 2369:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :JNSA
 2375:d=7  hl=2 l=  13 cons: SET
 2377:d=8  hl=2 l=  11 cons: SEQUENCE
 2379:d=9  hl=2 l=   3 prim: OBJECT            :organizationalUnitName
 2384:d=9  hl=2 l=   4 prim: PRINTABLESTRING   :ESWG
 2390:d=7  hl=2 l=  35 cons: SET
 2392:d=8  hl=2 l=  33 cons: SEQUENCE
 2394:d=9  hl=2 l=   3 prim: OBJECT            :commonName
 2399:d=9  hl=2 l=  26 prim: PRINTABLESTRING   :JNSA PKI Sandbox CA Root 2
 2427:d=6  hl=2 l=   3 prim: INTEGER           :300001
 2432:d=5  hl=2 l=   9 cons: SEQUENCE
 2434:d=6  hl=2 l=   5 prim: OBJECT            :sha1
 2441:d=6  hl=2 l=   0 prim: NULL
 2443:d=5  hl=3 l= 140 cons: cont [ 0 ]
 2446:d=6  hl=2 l=  26 cons: SEQUENCE
 2448:d=7  hl=2 l=   9 prim: OBJECT            :contentType
 2459:d=7  hl=2 l=  13 cons: SET
 2461:d=8  hl=2 l=  11 prim: OBJECT            :id-smime-ct-TSTInfo
 2474:d=6  hl=2 l=  28 cons: SEQUENCE
 2476:d=7  hl=2 l=   9 prim: OBJECT            :signingTime
 2487:d=7  hl=2 l=  15 cons: SET
 2489:d=8  hl=2 l=  13 prim: UTCTIME           :230105122753Z
 2504:d=6  hl=2 l=  35 cons: SEQUENCE
 2506:d=7  hl=2 l=   9 prim: OBJECT            :messageDigest
 2517:d=7  hl=2 l=  22 cons: SET
 2519:d=8  hl=2 l=  20 prim: OCTET STRING      [HEX DUMP]:131B9BE044D9D5F0F990A4918DFAD154E0A06771
 2541:d=6  hl=2 l=  43 cons: SEQUENCE
 2543:d=7  hl=2 l=  11 prim: OBJECT            :id-smime-aa-signingCertificate
 2556:d=7  hl=2 l=  28 cons: SET
 2558:d=8  hl=2 l=  26 cons: SEQUENCE
 2560:d=9  hl=2 l=  24 cons: SEQUENCE
 2562:d=10 hl=2 l=  22 cons: SEQUENCE
 2564:d=11 hl=2 l=  20 prim: OCTET STRING      [HEX DUMP]:F4BC670EB100326199E89E59B9841FBAEB460D13
 2586:d=5  hl=2 l=  13 cons: SEQUENCE
 2588:d=6  hl=2 l=   9 prim: OBJECT            :rsaEncryption
 2599:d=6  hl=2 l=   0 prim: NULL
 2601:d=5  hl=4 l= 256 prim: OCTET STRING      [HEX DUMP]:79D2C340E7CD19DE50D97411437F1F83D9FD67C28B15039BBDCF3E2D0387EB0BC53629D22E1229157939D3032E8D55A6637C5D21EECF61012A40F448982789E300EA7AECE946E4F2A4C9F1401ACB95D06C3D01B65879718B7E5A60446F5D61502921F6971C2A9A26C029FD37C5AA9273E0CDD53078E006E49B419D98A8DD9D4EE9717CFF112BC96209C2A4751F0547E4E812004A43598DC4E10DC6B9AE54585FD4C11FFA83B41F922B657ED1718E9EE7B3EAC27A5C2DD22AEDBAA5FEE06963B558A5857E92C4ED5708C59CB44970BA342B6676B827AEA053E61BB3373D841AF9960D0DCA1B8ADD667827636500F1D9AC81ECEECA99E604E2AC220800FBB91841
```

## 参考情報
https://qiita.com/rawr/items/f78a3830d894042f891b