2018年7月
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
無料ブログはココログ

 

2018年7月 1日 (日)

電子証明書について その2

PKCS12ファイルの中に入れてある公開鍵証明書の情報は、X.509という規格に従っている。

RFC5280「Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile」で公開されている。(IPAにある日本語版は、データ型の所とか削ってあるので、併用して英語版を見ると良い)
X.509 は、以下のようになっている。
  • ASN.1という規格で記述されている。
  • TLV形式(タグ・長さ・データ)という形
  • タグは、1バイト。先頭2bitはclass、次の1bitはprimitive/constructedフラグ(p/c)、残り5bitはtag。
    ・class=00BはASN.1で定義されているデータ型。
    class=10Bは文脈依存。例えば、versionの所で使われている。1バイト目0xA0は、X.509v3証明書で示されている"version [0] Version DEFAULT v1."のところ、”class=80 p/c=20 tagid=00”がそれ。tag=0x00なのは"[0]"を示している。他には、"extensions [3]"のところ。0xA3→”class=80 p/c=20 tagid=03”となっている。
    ・primitive/constructedは、1のとき後者で構造体となっていると思えばOK。
    ・tagは、class=0x00、p/c=0x00ならASN.1で決められたデータ型になる。
  • 長さは、1バイト目が0x80より小の場合、データ長0~127バイトを示す。
    0x80より大の場合、7bitでそのあとのバイト数がデータ長を示す。例えば0x82,0x01,0x02としたら0x01*0x100+0x02=データ長258バイトとなる。0x80のときはあまりないと思われるけど、末尾0x00までがデータとなる。
  • データは、長さで示されたバイト数。
    特別なデータ型として、T=0x30や0x31のとき、Vの中が次の構造体のデータを示す。

class=00 p/c=20 tagid=10 len=1142 i=4
  class=00 p/c=20 tagid=10 len=862 i=8
    class=80 p/c=20 tagid=00 len=3 i=10
      class=00 p/c=00 tagid=02 len=1 i=13        *version=3 (値+1で扱う)
      2
    class=00 p/c=00 tagid=02 len=9 i=24        *serialNumber=0x99674fbc78d5f74b
    1.10538914813039E+19
    class=00 p/c=20 tagid=10 len=13 i=26
      class=00 p/c=00 tagid=06 len=9 i=37      *AlgrithmIdentifer OIDはsha256WithRSAEncryption
      1.2.840.113549.1.1.11
      class=00 p/c=00 tagid=05 len=0 i=39
    class=00 p/c=20 tagid=10 len=207 i=42      *発行者(Issuer)
      class=00 p/c=20 tagid=11 len=11 i=44
        class=00 p/c=20 tagid=10 len=9 i=46
          class=00 p/c=00 tagid=06 len=3 i=51  *countryName=JP
          2.5.4.6
          class=00 p/c=00 tagid=13 len=2 i=55
          4a 50
      class=00 p/c=20 tagid=11 len=16 i=57
        class=00 p/c=20 tagid=10 len=14 i=59
          class=00 p/c=00 tagid=06 len=3 i=64  *stateOrProvinceName(ST)=TOKYO
          2.5.4.8
          class=00 p/c=00 tagid=0c len=7 i=73
          53 41 49 54 41 4d 41
      class=00 p/c=20 tagid=11 len=17 i=75
        class=00 p/c=20 tagid=10 len=15 i=77
          class=00 p/c=00 tagid=06 len=3 i=82  *localityName(L)=MINATOKU
          2.5.4.7
          class=00 p/c=00 tagid=0c len=8 i=92
          4b 4f 53 49 47 41 59 41
      class=00 p/c=20 tagid=11 len=16 i=94
        class=00 p/c=20 tagid=10 len=14 i=96
          class=00 p/c=00 tagid=06 len=3 i=101  *organizationName(O)=COMPANY
          2.5.4.10
          class=00 p/c=00 tagid=0c len=7 i=110
          43 4f 4d 50 41 4e 59
      class=00 p/c=20 tagid=11 len=17 i=112
        class=00 p/c=20 tagid=10 len=15 i=114    *organizationalUnitName(OU)=JIGYOUBU
          class=00 p/c=00 tagid=06 len=3 i=119
          2.5.4.11
          class=00 p/c=00 tagid=0c len=8 i=129
          4a 49 47 59 4f 55 42 55
      class=00 p/c=20 tagid=11 len=11 i=131
        class=00 p/c=20 tagid=10 len=9 i=133
          class=00 p/c=00 tagid=06 len=3 i=138  *commonName(CN)=BU
          2.5.4.3
          class=00 p/c=00 tagid=0c len=2 i=142
          42 55
      class=00 p/c=20 tagid=11 len=15 i=144
        class=00 p/c=20 tagid=10 len=13 i=146
          class=00 p/c=00 tagid=06 len=3 i=151  *title=title1
          2.5.4.12
          class=00 p/c=00 tagid=0c len=6 i=159
          74 69 74 6c 65 31
      class=00 p/c=20 tagid=11 len=17 i=161
        class=00 p/c=20 tagid=10 len=15 i=163
          class=00 p/c=00 tagid=06 len=3 i=168  *surname(SN)=surname1
          2.5.4.4
          class=00 p/c=00 tagid=0c len=8 i=178
          73 75 72 6e 61 6d 65 31
      class=00 p/c=20 tagid=11 len=19 i=180
        class=00 p/c=20 tagid=10 len=17 i=182
          class=00 p/c=00 tagid=06 len=3 i=187  *givenName(GN)=givenname1
          2.5.4.42
          class=00 p/c=00 tagid=0c len=10 i=199
          67 69 76 65 6e 6e 61 6d 65 31
      class=00 p/c=20 tagid=11 len=17 i=201
        class=00 p/c=20 tagid=10 len=15 i=203
          class=00 p/c=00 tagid=06 len=3 i=208  *initials=initial1
          2.5.4.43
          class=00 p/c=00 tagid=0c len=8 i=218
          69 6e 69 74 69 61 6c 31
      class=00 p/c=20 tagid=11 len=29 i=220
        class=00 p/c=20 tagid=10 len=27 i=222
          class=00 p/c=00 tagid=06 len=9 i=233  *emailAddress=test1@test.com
          1.2.840.113549.1.9.1
          class=00 p/c=00 tagid=16 len=14 i=249
          74 65 73 74 31 40 74 65 73 74 2e 63 6f 6d
    class=00 p/c=20 tagid=10 len=30 i=251      *vallidity
      class=00 p/c=00 tagid=17 len=13 i=266    *notBefore=180701064133Z UTCTime->2018/07/01 06:41:33
      31 38 30 37 30 31 30 36 34 31 33 33 5a
      class=00 p/c=00 tagid=17 len=13 i=281    *notAfter =280628064133Z UTCTime->2028/06/28 06:41:33
      32 38 30 36 32 38 30 36 34 31 33 33 5a
    class=00 p/c=20 tagid=10 len=207 i=284
      class=00 p/c=20 tagid=11 len=11 i=286      *Issuer (内容はSubjectと同じ)
        class=00 p/c=20 tagid=10 len=9 i=288
          class=00 p/c=00 tagid=06 len=3 i=293
          2.5.4.6
          class=00 p/c=00 tagid=13 len=2 i=297
          4a 50
      class=00 p/c=20 tagid=11 len=16 i=299
        class=00 p/c=20 tagid=10 len=14 i=301
          class=00 p/c=00 tagid=06 len=3 i=306
          2.5.4.8
          class=00 p/c=00 tagid=0c len=7 i=315
          53 41 49 54 41 4d 41
      class=00 p/c=20 tagid=11 len=17 i=317
        class=00 p/c=20 tagid=10 len=15 i=319
          class=00 p/c=00 tagid=06 len=3 i=324
          2.5.4.7
          class=00 p/c=00 tagid=0c len=8 i=334
          4b 4f 53 49 47 41 59 41
      class=00 p/c=20 tagid=11 len=16 i=336
        class=00 p/c=20 tagid=10 len=14 i=338
          class=00 p/c=00 tagid=06 len=3 i=343
          2.5.4.10
          class=00 p/c=00 tagid=0c len=7 i=352
          43 4f 4d 50 41 4e 59
      class=00 p/c=20 tagid=11 len=17 i=354
        class=00 p/c=20 tagid=10 len=15 i=356
          class=00 p/c=00 tagid=06 len=3 i=361
          2.5.4.11
          class=00 p/c=00 tagid=0c len=8 i=371
          4a 49 47 59 4f 55 42 55
      class=00 p/c=20 tagid=11 len=11 i=373
        class=00 p/c=20 tagid=10 len=9 i=375
          class=00 p/c=00 tagid=06 len=3 i=380
          2.5.4.3
          class=00 p/c=00 tagid=0c len=2 i=384
          42 55
      class=00 p/c=20 tagid=11 len=15 i=386
        class=00 p/c=20 tagid=10 len=13 i=388
          class=00 p/c=00 tagid=06 len=3 i=393
          2.5.4.12
          class=00 p/c=00 tagid=0c len=6 i=401
          74 69 74 6c 65 31
      class=00 p/c=20 tagid=11 len=17 i=403
        class=00 p/c=20 tagid=10 len=15 i=405
          class=00 p/c=00 tagid=06 len=3 i=410
          2.5.4.4
          class=00 p/c=00 tagid=0c len=8 i=420
          73 75 72 6e 61 6d 65 31
      class=00 p/c=20 tagid=11 len=19 i=422
        class=00 p/c=20 tagid=10 len=17 i=424
          class=00 p/c=00 tagid=06 len=3 i=429
          2.5.4.42
          class=00 p/c=00 tagid=0c len=10 i=441
          67 69 76 65 6e 6e 61 6d 65 31
      class=00 p/c=20 tagid=11 len=17 i=443
        class=00 p/c=20 tagid=10 len=15 i=445
          class=00 p/c=00 tagid=06 len=3 i=450
          2.5.4.43
          class=00 p/c=00 tagid=0c len=8 i=460
          69 6e 69 74 69 61 6c 31
      class=00 p/c=20 tagid=11 len=29 i=462
        class=00 p/c=20 tagid=10 len=27 i=464
          class=00 p/c=00 tagid=06 len=9 i=475
          1.2.840.113549.1.9.1
          class=00 p/c=00 tagid=16 len=14 i=491
          74 65 73 74 31 40 74 65 73 74 2e 63 6f 6d
  class=00 p/c=20 tagid=10 len=290 i=495          *SubjectPublicKeyInfo
    class=00 p/c=20 tagid=10 len=13 i=497
      class=00 p/c=00 tagid=06 len=9 i=508      *algorithm=RSA encryption
      1.2.840.113549.1.1.1
      class=00 p/c=00 tagid=05 len=0 i=510
    class=00 p/c=00 tagid=03 len=271 i=785        *subjecPublicKey
    00 30 82 01 0a 02 82 01 01 00 da 7e c9 0b f6 60 ff c0 42 b1 7c 2a 59 0f 5a 89 4a f7 50 52 20 35 c4 20 8a e9 c0 b5 22 d9 e0 f0 e3 a0 01 bc 6e 74 a0 88 b1 55 b3 b5 a5 e9 94 21 28 dc 20 fe 1f 8f 66 a4 25 10 83 a5 4e 53 25 2c 80 b4 d2 7f 01 b7 fa 17 ec 83 84 d3 84 5e 05 81 ac fa a9 c7 27 19 72 ec ba 66 7e 0b 33 63 e3 b0 c8 77 88 b9 21 e3 48 6c df 89 55 1d 7f 9b e9 73 4f da 78 0c d1 25 88 d3 18 24 57 9c 73 0e 22 e6 da 53 f9 33 42 bc 9c e4 59 80 81 3c 7f 27 3f d7 5b 52 95 db 94 5d b7 33 b4 56 d6 ea 53 bd 74 82 92 51 dc bb 68 64 74 8c 52 91 75 39 a2 5f dd 77 0b c5 79 59 28 09 5f 87 eb d6 0c bc fe 16 e7 55 b4 38 a6 45 f5 9f aa 06 95 6c 90 e3 16 38 96 b6 ad 0e bf 55 39 1b 65 12 78 91 15 fb 90 93 a8 26 74 67 4a 77 f2 fe e5 37 d1 4c a1 8d a7 6d 98 56 9e 9b c8 74 7f 62 fb a2 f6 1d ff 97 ca 58 69 91 02 03 01 00 01
    class=80 p/c=20 tagid=03 len=83 i=870        *Extensions
    30 51 30 1d 06 03 55 1d 0e 04 16 04 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16 30 1f 06 03 55 1d 23 04 18 30 16 80 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16 30 0f 06 03 55 1d 13 01 01 ff 04 05 30 03 01 01 ff
    class=00 p/c=20 tagid=10 len=13 i=872
      class=00 p/c=00 tagid=06 len=9 i=883      *signatureAlgrithm=sha256WithRSAEncryption
      1.2.840.113549.1.1.11
      class=00 p/c=00 tagid=05 len=0 i=885
  class=00 p/c=00 tagid=03 len=257 i=1146          *signature
  00 22 87 e4 5e 43 31 4f 4b ea 51 ee dc d5 a9 0d c3 85 df d5 b9 80 f5 6f a1 b4 0a e7 8e 8c c5 0c 2d be ad c7 50 ab df 38 1e ae 73 7a 33 b9 48 02 d8 9d 98 57 a7 ed 09 15 ff 22 fe 4c ee a0 54 6e 34 b6 2f ca 1c 19 03 97 8f 67 72 3a 81 ae 8a dd fe 67 2e b8 2e 48 04 ad ce a6 a0 69 3a e7 67 b1 79 4a cd 33 91 1e 98 30 56 f0 14 4c 5a dd 97 b8 7a 98 7a dc 31 60 fd e6 bd a0 6b 5e 6f 9e 5b b9 3f b9 81 f1 89 15 b5 60 e4 40 40 f7 10 90 d9 46 68 44 3b ac 6d 55 0b 52 50 01 d5 71 0b 3e 9e 3c 35 06 f5 e1 f0 12 97 c5 41 45 9c 5b 7c a0 9f e4 64 36 8d 25 c5 11 7a d3 f7 8b ee 6b 00 c5 3f dd 60 78 ae 20 d6 48 44 44 a5 35 cc d9 73 d1 ee c7 80 f3 7b 91 49 f8 65 a5 ab 93 a9 fc ec b1 cf eb fb 5f 88 47 e3 64 c6 e4 69 c4 f2 96 67 bb 28 ec 28 e2 ad f5 89 3a 3b 31 63 95 d5 5e df 4b 2d c9 95

●Extensionsの部分を切り出して、構造を見てみる。

class=00 p/c=20 tagid=10 len=81 i=2
  class=00 p/c=20 tagid=10 len=29 i=4
    class=00 p/c=00 tagid=06 len=3 i=9        *Subject Key Identifier
    2.5.29.14
    class=00 p/c=00 tagid=04 len=22 i=33
    04 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16
  class=00 p/c=20 tagid=10 len=31 i=35
    class=00 p/c=00 tagid=06 len=3 i=40        *Authority Key Identifier
    2.5.29.35
    class=00 p/c=00 tagid=04 len=24 i=66
    30 16 80 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16
  class=00 p/c=20 tagid=10 len=15 i=68
    class=00 p/c=00 tagid=06 len=3 i=73        *Basic Constraints
    2.5.29.19
    class=00 p/c=00 tagid=01 len=1 i=76
    ff
class=00 p/c=00 tagid=04 len=5 i=83
30 03 01 01 ff

●Extensionsを切り出して関数に食わせた手順。dispASN1は前もって定義している

PS D:\cert> $r=New-Object regex("[0-9a-fA-F]{2}"); $tmp=@();
PS D:\cert> "30 51 30 1d 06 03 55 1d 0e 04 16 04 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16 30 1f 06
 03 55 1d 23 04 18 30 16 80 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16 30 0f 06 03 55 1d 13 01 01 ff
 04 05 30 03 01 01 ff" | %{$r.Matches($_)} | %{$tmp += [Convert]::ToByte("0x" + $_.Value, 16)}
PS D:\cert> dispASN1 $tmp
dispASN1 start
class=00 p/c=20 tagid=10 len=81 i=2
class=00 p/c=20 tagid=10 len=29 i=4
class=00 p/c=00 tagid=06 len=3 i=9
2.5.29.14
class=00 p/c=00 tagid=04 len=22 i=33
04 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16
class=00 p/c=20 tagid=10 len=31 i=35
class=00 p/c=00 tagid=06 len=3 i=40
2.5.29.35
class=00 p/c=00 tagid=04 len=24 i=66
30 16 80 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16
class=00 p/c=20 tagid=10 len=15 i=68
class=00 p/c=00 tagid=06 len=3 i=73
2.5.29.19
class=00 p/c=00 tagid=01 len=1 i=76
ff
class=00 p/c=00 tagid=04 len=5 i=83
30 03 01 01 ff
dispASN1 end

電子証明書について

お仕事で、電子証明書ファイルの情報について調べてみた。

●opensslのコマンドでPKCS12ファイルを作ってみて、中身を見る

openssl req -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/C=JP/ST=SAITAMA/L=KOSIGAYA/O=COMPANY/OU=JIGYOUBU/CN=BU/title=title1/SN=surname1/GN=givenname1/initials=initial1/emailAddress=test1@test.com" -config ./openssl.cfg -keyout test.pem -out test.crt

openssl pkcs12 -export -in test.crt -inkey test.pem -out test.p12

openssl x509 -text -in test.crt

●opensslのコマンドでPKCS12ファイルまで作ってみる。

D:\cert>openssl req -newkey rsa:2048 -days 3650 -nodes -x509 -subj "/C=JP/ST=SAITAMA/L=KOSIGAYA/O=COMPANY/OU=JIGYOUBU/CN=BU/title=title1/SN=surname1/GN=givenname1/initials=initial1/emailAddress=test1@test.com" -config ./openssl.cfg -keyout test.pem -out test.crt
Generating a 2048 bit RSA private key
........................+++
....................+++
writing new private key to 'test.pem'
-----

D:\cert>openssl pkcs12 -export -in test.crt -inkey test.pem -out test.p12
Enter Export Password:
Verifying - Enter Export Password:

D:\cert>dir
 ドライブ D のボリューム ラベルがありません。
 ボリューム シリアル番号は 86F4-1821 です

 D:\cert のディレクトリ

2018/07/01  14:56    

          . 2018/07/01  14:56   

          .. 2018/07/01  14:56             1,024 .rnd 2018/07/01  14:37            11,198 openssl.cfg 2018/07/01  14:56             1,604 test.crt 2018/07/01  14:56             2,725 test.p12 2018/07/01  14:56             1,732 test.pem                5 個のファイル              18,283 バイト                2 個のディレクトリ  124,596,654,080 バイトの空き領域


●opensslコマンドでcrtファイルの内容を見てみる。

D:\cert>openssl x509 -text -in test.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number:
            99:67:4f:bc:78:d5:f7:4b
    Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = JP, ST = SAITAMA, L = KOSIGAYA, O = COMPANY, OU = JIGYOUBU,CN = BU, title = title1, SN = surname1, GN = givenname1, initials = initial1, emailAddress = test1@test.com
        Validity
            Not Before: Jul  1 06:41:33 2018 GMT
            Not After : Jun 28 06:41:33 2028 GMT
        Subject: C = JP, ST = SAITAMA, L = KOSIGAYA, O = COMPANY, OU = JIGYOUBU, CN = BU, title = title1, SN = surname1, GN = givenname1, initials = initial1, emailAddress = test1@test.com
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (2048 bit)
                Modulus:
                    00:da:7e:c9:0b:f6:60:ff:c0:42:b1:7c:2a:59:0f:
                    5a:89:4a:f7:50:52:20:35:c4:20:8a:e9:c0:b5:22:
                    d9:e0:f0:e3:a0:01:bc:6e:74:a0:88:b1:55:b3:b5:
                    a5:e9:94:21:28:dc:20:fe:1f:8f:66:a4:25:10:83:
                    a5:4e:53:25:2c:80:b4:d2:7f:01:b7:fa:17:ec:83:
                    84:d3:84:5e:05:81:ac:fa:a9:c7:27:19:72:ec:ba:
                    66:7e:0b:33:63:e3:b0:c8:77:88:b9:21:e3:48:6c:
                    df:89:55:1d:7f:9b:e9:73:4f:da:78:0c:d1:25:88:
                    d3:18:24:57:9c:73:0e:22:e6:da:53:f9:33:42:bc:
                    9c:e4:59:80:81:3c:7f:27:3f:d7:5b:52:95:db:94:
                    5d:b7:33:b4:56:d6:ea:53:bd:74:82:92:51:dc:bb:
                    68:64:74:8c:52:91:75:39:a2:5f:dd:77:0b:c5:79:
                    59:28:09:5f:87:eb:d6:0c:bc:fe:16:e7:55:b4:38:
                    a6:45:f5:9f:aa:06:95:6c:90:e3:16:38:96:b6:ad:
                    0e:bf:55:39:1b:65:12:78:91:15:fb:90:93:a8:26:
                    74:67:4a:77:f2:fe:e5:37:d1:4c:a1:8d:a7:6d:98:
                    56:9e:9b:c8:74:7f:62:fb:a2:f6:1d:ff:97:ca:58:
                    69:91
                Exponent: 65537 (0x10001)
        X509v3 extensions:
            X509v3 Subject Key Identifier:
                FD:36:CA:12:16:EC:C9:62:B9:15:33:D3:A3:A8:11:10:2B:43:5C:16
            X509v3 Authority Key Identifier:
                keyid:FD:36:CA:12:16:EC:C9:62:B9:15:33:D3:A3:A8:11:10:2B:43:5C:16

            X509v3 Basic Constraints: critical
                CA:TRUE
    Signature Algorithm: sha256WithRSAEncryption
         22:87:e4:5e:43:31:4f:4b:ea:51:ee:dc:d5:a9:0d:c3:85:df:
         d5:b9:80:f5:6f:a1:b4:0a:e7:8e:8c:c5:0c:2d:be:ad:c7:50:
         ab:df:38:1e:ae:73:7a:33:b9:48:02:d8:9d:98:57:a7:ed:09:
         15:ff:22:fe:4c:ee:a0:54:6e:34:b6:2f:ca:1c:19:03:97:8f:
         67:72:3a:81:ae:8a:dd:fe:67:2e:b8:2e:48:04:ad:ce:a6:a0:
         69:3a:e7:67:b1:79:4a:cd:33:91:1e:98:30:56:f0:14:4c:5a:
         dd:97:b8:7a:98:7a:dc:31:60:fd:e6:bd:a0:6b:5e:6f:9e:5b:
         b9:3f:b9:81:f1:89:15:b5:60:e4:40:40:f7:10:90:d9:46:68:
         44:3b:ac:6d:55:0b:52:50:01:d5:71:0b:3e:9e:3c:35:06:f5:
         e1:f0:12:97:c5:41:45:9c:5b:7c:a0:9f:e4:64:36:8d:25:c5:
         11:7a:d3:f7:8b:ee:6b:00:c5:3f:dd:60:78:ae:20:d6:48:44:
         44:a5:35:cc:d9:73:d1:ee:c7:80:f3:7b:91:49:f8:65:a5:ab:
         93:a9:fc:ec:b1:cf:eb:fb:5f:88:47:e3:64:c6:e4:69:c4:f2:
         96:67:bb:28:ec:28:e2:ad:f5:89:3a:3b:31:63:95:d5:5e:df:
         4b:2d:c9:95
-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIJAJlnT7x41fdLMA0GCSqGSIb3DQEBCwUAMIHPMQswCQYD
VQQGEwJKUDEQMA4GA1UECAwHU0FJVEFNQTERMA8GA1UEBwwIS09TSUdBWUExEDAO
BgNVBAoMB0NPTVBBTlkxETAPBgNVBAsMCEpJR1lPVUJVMQswCQYDVQQDDAJCVTEP
MA0GA1UEDAwGdGl0bGUxMREwDwYDVQQEDAhzdXJuYW1lMTETMBEGA1UEKgwKZ2l2
ZW5uYW1lMTERMA8GA1UEKwwIaW5pdGlhbDExHTAbBgkqhkiG9w0BCQEWDnRlc3Qx
QHRlc3QuY29tMB4XDTE4MDcwMTA2NDEzM1oXDTI4MDYyODA2NDEzM1owgc8xCzAJ
BgNVBAYTAkpQMRAwDgYDVQQIDAdTQUlUQU1BMREwDwYDVQQHDAhLT1NJR0FZQTEQ
MA4GA1UECgwHQ09NUEFOWTERMA8GA1UECwwISklHWU9VQlUxCzAJBgNVBAMMAkJV
MQ8wDQYDVQQMDAZ0aXRsZTExETAPBgNVBAQMCHN1cm5hbWUxMRMwEQYDVQQqDApn
aXZlbm5hbWUxMREwDwYDVQQrDAhpbml0aWFsMTEdMBsGCSqGSIb3DQEJARYOdGVz
dDFAdGVzdC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDafskL
9mD/wEKxfCpZD1qJSvdQUiA1xCCK6cC1Itng8OOgAbxudKCIsVWztaXplCEo3CD+
H49mpCUQg6VOUyUsgLTSfwG3+hfsg4TThF4Fgaz6qccnGXLsumZ+CzNj47DId4i5
IeNIbN+JVR1/m+lzT9p4DNEliNMYJFeccw4i5tpT+TNCvJzkWYCBPH8nP9dbUpXb
lF23M7RW1upTvXSCklHcu2hkdIxSkXU5ol/ddwvFeVkoCV+H69YMvP4W51W0OKZF
9Z+qBpVskOMWOJa2rQ6/VTkbZRJ4kRX7kJOoJnRnSnfy/uU30UyhjadtmFaem8h0
f2L7ovYd/5fKWGmRAgMBAAGjUzBRMB0GA1UdDgQWBBT9NsoSFuzJYrkVM9OjqBEQ
K0NcFjAfBgNVHSMEGDAWgBT9NsoSFuzJYrkVM9OjqBEQK0NcFjAPBgNVHRMBAf8E
BTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAih+ReQzFPS+pR7tzVqQ3Dhd/VuYD1
b6G0CueOjMUMLb6tx1Cr3zgernN6M7lIAtidmFen7QkV/yL+TO6gVG40ti/KHBkD
l49ncjqBrord/mcuuC5IBK3OpqBpOudnsXlKzTORHpgwVvAUTFrdl7h6mHrcMWD9
5r2ga15vnlu5P7mB8YkVtWDkQED3EJDZRmhEO6xtVQtSUAHVcQs+njw1BvXh8BKX
xUFFnFt8oJ/kZDaNJcURetP3i+5rAMU/3WB4riDWSEREpTXM2XPR7seA83uRSfhl
pauTqfzssc/r+1+IR+NkxuRpxPKWZ7so7CjirfWJOjsxY5XVXt9LLcmV
-----END CERTIFICATE-----

●Powershellで公開鍵証明書の情報をASN.1として取得してみる

function dispASN1($x509bytes) {
write-host "dispASN1 start"
	$enc = [system.Text.Encoding]::GetEncoding("UTF-8")
	$i=0
	while($i -lt $x509bytes.length) {

		# get class & tagid(p/c)
		$class=($x509bytes[$i] -band 0xC0)
		$pc=($x509bytes[$i] -band 0x20)
		$tagid=($x509bytes[$i] -band 0x1f)
		$i++

		# get length
		$len=0
		if(($x509bytes[$i] -band 0x80) -eq 0x80) {
			$cnt=$x509bytes[$i] -band 0x7f
			$i++
			for($j=0; $j -lt $cnt; $j++) {
				$len=$len*0x100+$x509bytes[$i]
				$i++
			}
		} else {
			$len=$x509bytes[$i]
			$i++
		}

		$d=@()
		#if(($pc -eq 0) -and (($tagid -ne 0x00) -and ($tagid -ne 0x10) -and ($tagid -ne 0x11))) {
		if((($tagid -ne 0x00) -and ($tagid -ne 0x10) -and ($tagid -ne 0x11))) {
			for($j=0;$j -lt $len;$j++){
				$d += $x509bytes[$i]
				$i++
			}
		}
		write-host("class={0:x2} p/c={1:x2} tagid={2:x2} len={3} i={4}" -F $class, $pc, $tagid, $len, $i)
		if($class -eq 0) {
			switch($tagid) {
				{$_ -eq 0x02} {	# INTEGER
					$d1=0
					for($j=0;$j -lt $len; $j++) {
						$d1=$d1*0x100+$d[$j]
					}
					write-host("{0}" -F $d1)
				}
				#{($_ -eq 0x04) -and ($pc -ne 0)} {	# OCTET STRING
				{$_ -eq 0x04} {	# OCTET STRING
					if ($pc -eq 0) {
						foreach($d1 in $d) { write-host -nonewline ("{0:x2} " -F $d1)}
						if($d.count -gt 0) {write-host}
					} else {
						dipASN1 $d
					}
					break
				}
				{$_ -eq 0x06} {	# OID
					write-host -nonewline ("{0}.{1}" -F ([math]::Floor($d[0]/40)), ($d[0]%40))
					$id=0
					for($j=1;$j -lt $len; $j++) {
						$id = $id*128+($d[$j] -band 0x7f)
						if(($d[$j] -band 0x80) -ne 0x80) {
							write-host -nonewline (".{0}" -F $id)
							$id=0
						}
					}
					write-host
					break
				}
				{($_ -eq 0x10) -or ($_ -eq 0x11)} {
					break
				}
				default {
					foreach($d1 in $d) { write-host -nonewline ("{0:x2} " -F $d1)}
					if($d.count -gt 0) {write-host}
				}
			}
		} else {
			foreach($d1 in $d) { write-host -nonewline ("{0:x2} " -F $d1)}
			write-host
		}
	}
write-host "dispASN1 end"
}


if ($args.count -ne 1) {
	write-host "Invalid Argment. Perase set P12 File"
	return
}

$x509data = Get-PfxCertificate $args[0]
$certData = $x509data.GetRawCertData()

#$file="D:\work\暗号\my-identity.p12"
#$certData=@();[System.IO.File]::ReadAllBytes($file) | %{"{0:x2}" -F $_ }| %{$certData += [Convert]::ToByte("0x" + $_, 16)}
dispASN1 $certData

●その結果

PS D:\cert> .\dispASN1.ps1 .\test.p12
パスワードの入力: ****

dispASN1 start
class=00 p/c=20 tagid=10 len=1142 i=4
class=00 p/c=20 tagid=10 len=862 i=8
class=80 p/c=20 tagid=00 len=3 i=10

class=00 p/c=00 tagid=02 len=1 i=13
2
class=00 p/c=00 tagid=02 len=9 i=24
1.10538914813039E+19
class=00 p/c=20 tagid=10 len=13 i=26
class=00 p/c=00 tagid=06 len=9 i=37
1.2.840.113549.1.1.11
class=00 p/c=00 tagid=05 len=0 i=39
class=00 p/c=20 tagid=10 len=207 i=42
class=00 p/c=20 tagid=11 len=11 i=44
class=00 p/c=20 tagid=10 len=9 i=46
class=00 p/c=00 tagid=06 len=3 i=51
2.5.4.6
class=00 p/c=00 tagid=13 len=2 i=55
4a 50
class=00 p/c=20 tagid=11 len=16 i=57
class=00 p/c=20 tagid=10 len=14 i=59
class=00 p/c=00 tagid=06 len=3 i=64
2.5.4.8
class=00 p/c=00 tagid=0c len=7 i=73
53 41 49 54 41 4d 41
class=00 p/c=20 tagid=11 len=17 i=75
class=00 p/c=20 tagid=10 len=15 i=77
class=00 p/c=00 tagid=06 len=3 i=82
2.5.4.7
class=00 p/c=00 tagid=0c len=8 i=92
4b 4f 53 49 47 41 59 41
class=00 p/c=20 tagid=11 len=16 i=94
class=00 p/c=20 tagid=10 len=14 i=96
class=00 p/c=00 tagid=06 len=3 i=101
2.5.4.10
class=00 p/c=00 tagid=0c len=7 i=110
43 4f 4d 50 41 4e 59
class=00 p/c=20 tagid=11 len=17 i=112
class=00 p/c=20 tagid=10 len=15 i=114
class=00 p/c=00 tagid=06 len=3 i=119
2.5.4.11
class=00 p/c=00 tagid=0c len=8 i=129
4a 49 47 59 4f 55 42 55
class=00 p/c=20 tagid=11 len=11 i=131
class=00 p/c=20 tagid=10 len=9 i=133
class=00 p/c=00 tagid=06 len=3 i=138
2.5.4.3
class=00 p/c=00 tagid=0c len=2 i=142
42 55
class=00 p/c=20 tagid=11 len=15 i=144
class=00 p/c=20 tagid=10 len=13 i=146
class=00 p/c=00 tagid=06 len=3 i=151
2.5.4.12
class=00 p/c=00 tagid=0c len=6 i=159
74 69 74 6c 65 31
class=00 p/c=20 tagid=11 len=17 i=161
class=00 p/c=20 tagid=10 len=15 i=163
class=00 p/c=00 tagid=06 len=3 i=168
2.5.4.4
class=00 p/c=00 tagid=0c len=8 i=178
73 75 72 6e 61 6d 65 31
class=00 p/c=20 tagid=11 len=19 i=180
class=00 p/c=20 tagid=10 len=17 i=182
class=00 p/c=00 tagid=06 len=3 i=187
2.5.4.42
class=00 p/c=00 tagid=0c len=10 i=199
67 69 76 65 6e 6e 61 6d 65 31
class=00 p/c=20 tagid=11 len=17 i=201
class=00 p/c=20 tagid=10 len=15 i=203
class=00 p/c=00 tagid=06 len=3 i=208
2.5.4.43
class=00 p/c=00 tagid=0c len=8 i=218
69 6e 69 74 69 61 6c 31
class=00 p/c=20 tagid=11 len=29 i=220
class=00 p/c=20 tagid=10 len=27 i=222
class=00 p/c=00 tagid=06 len=9 i=233
1.2.840.113549.1.9.1
class=00 p/c=00 tagid=16 len=14 i=249
74 65 73 74 31 40 74 65 73 74 2e 63 6f 6d
class=00 p/c=20 tagid=10 len=30 i=251
class=00 p/c=00 tagid=17 len=13 i=266
31 38 30 37 30 31 30 36 34 31 33 33 5a
class=00 p/c=00 tagid=17 len=13 i=281
32 38 30 36 32 38 30 36 34 31 33 33 5a
class=00 p/c=20 tagid=10 len=207 i=284
class=00 p/c=20 tagid=11 len=11 i=286
class=00 p/c=20 tagid=10 len=9 i=288
class=00 p/c=00 tagid=06 len=3 i=293
2.5.4.6
class=00 p/c=00 tagid=13 len=2 i=297
4a 50
class=00 p/c=20 tagid=11 len=16 i=299
class=00 p/c=20 tagid=10 len=14 i=301
class=00 p/c=00 tagid=06 len=3 i=306
2.5.4.8
class=00 p/c=00 tagid=0c len=7 i=315
53 41 49 54 41 4d 41
class=00 p/c=20 tagid=11 len=17 i=317
class=00 p/c=20 tagid=10 len=15 i=319
class=00 p/c=00 tagid=06 len=3 i=324
2.5.4.7
class=00 p/c=00 tagid=0c len=8 i=334
4b 4f 53 49 47 41 59 41
class=00 p/c=20 tagid=11 len=16 i=336
class=00 p/c=20 tagid=10 len=14 i=338
class=00 p/c=00 tagid=06 len=3 i=343
2.5.4.10
class=00 p/c=00 tagid=0c len=7 i=352
43 4f 4d 50 41 4e 59
class=00 p/c=20 tagid=11 len=17 i=354
class=00 p/c=20 tagid=10 len=15 i=356
class=00 p/c=00 tagid=06 len=3 i=361
2.5.4.11
class=00 p/c=00 tagid=0c len=8 i=371
4a 49 47 59 4f 55 42 55
class=00 p/c=20 tagid=11 len=11 i=373
class=00 p/c=20 tagid=10 len=9 i=375
class=00 p/c=00 tagid=06 len=3 i=380
2.5.4.3
class=00 p/c=00 tagid=0c len=2 i=384
42 55
class=00 p/c=20 tagid=11 len=15 i=386
class=00 p/c=20 tagid=10 len=13 i=388
class=00 p/c=00 tagid=06 len=3 i=393
2.5.4.12
class=00 p/c=00 tagid=0c len=6 i=401
74 69 74 6c 65 31
class=00 p/c=20 tagid=11 len=17 i=403
class=00 p/c=20 tagid=10 len=15 i=405
class=00 p/c=00 tagid=06 len=3 i=410
2.5.4.4
class=00 p/c=00 tagid=0c len=8 i=420
73 75 72 6e 61 6d 65 31
class=00 p/c=20 tagid=11 len=19 i=422
class=00 p/c=20 tagid=10 len=17 i=424
class=00 p/c=00 tagid=06 len=3 i=429
2.5.4.42
class=00 p/c=00 tagid=0c len=10 i=441
67 69 76 65 6e 6e 61 6d 65 31
class=00 p/c=20 tagid=11 len=17 i=443
class=00 p/c=20 tagid=10 len=15 i=445
class=00 p/c=00 tagid=06 len=3 i=450
2.5.4.43
class=00 p/c=00 tagid=0c len=8 i=460
69 6e 69 74 69 61 6c 31
class=00 p/c=20 tagid=11 len=29 i=462
class=00 p/c=20 tagid=10 len=27 i=464
class=00 p/c=00 tagid=06 len=9 i=475
1.2.840.113549.1.9.1
class=00 p/c=00 tagid=16 len=14 i=491
74 65 73 74 31 40 74 65 73 74 2e 63 6f 6d
class=00 p/c=20 tagid=10 len=290 i=495
class=00 p/c=20 tagid=10 len=13 i=497
class=00 p/c=00 tagid=06 len=9 i=508
1.2.840.113549.1.1.1
class=00 p/c=00 tagid=05 len=0 i=510
class=00 p/c=00 tagid=03 len=271 i=785
00 30 82 01 0a 02 82 01 01 00 da 7e c9 0b f6 60 ff c0 42 b1 7c 2a 59 0f 5a 89 4a f7 50 52 20 35 c4 20 8a e9 c0 b5 22 d9 e0 f0 e3 a0 01 bc 6e 74 a0 88 b1 55 b3 b5 a5 e9 94 21 28 dc 20 fe 1f 8f 66 a4 25 10 83 a5 4e 53 25 2c 80 b4 d2 7f 01 b7 fa 17 ec 83 84 d3 84 5e 05 81 ac fa a9 c7 27 19 72 ec ba 66 7e 0b 33 63 e3 b0 c8 77 88 b9 21 e3 48 6c df 89 55 1d 7f 9b e9 73 4f da 78 0c d1 25 88 d3 18 24 57 9c 73 0e 22 e6 da 53 f9 33 42 bc 9c e4 59 80 81 3c 7f 27 3f d7 5b 52 95 db 94 5d b7 33 b4 56 d6 ea 53 bd 74 82 92 51 dc bb 68 64 74 8c 52 91 75 39 a2 5f dd 77 0b c5 79 59 28 09 5f 87 eb d6 0c bc fe 16 e7 55 b4 38 a6 45 f5 9f aa 06 95 6c 90 e3 16 38 96 b6 ad 0e bf 55 39 1b 65 12 78 91 15 fb 90 93 a8 26 74 67 4a 77 f2 fe e5 37 d1 4c a1 8d a7 6d 98 56 9e 9b c8 74 7f 62 fb a2 f6 1d ff 97 ca 58 69 91 02 03 01 00 01
class=80 p/c=20 tagid=03 len=83 i=870
30 51 30 1d 06 03 55 1d 0e 04 16 04 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16 30 1f 06 03 55 1d 23 04 18 30 16 80 14 fd 36 ca 12 16 ec c9 62 b9 15 33 d3 a3 a8 11 10 2b 43 5c 16 30 0f 06 03 55 1d 13 01 01 ff 04 05 30 03 01 01 ff
class=00 p/c=20 tagid=10 len=13 i=872
class=00 p/c=00 tagid=06 len=9 i=883
1.2.840.113549.1.1.11
class=00 p/c=00 tagid=05 len=0 i=885
class=00 p/c=00 tagid=03 len=257 i=1146
00 22 87 e4 5e 43 31 4f 4b ea 51 ee dc d5 a9 0d c3 85 df d5 b9 80 f5 6f a1 b4 0a e7 8e 8c c5 0c 2d be ad c7 50 ab df 38 1e ae 73 7a 33 b9 48 02 d8 9d 98 57 a7 ed 09 15 ff 22 fe 4c ee a0 54 6e 34 b6 2f ca 1c 19 03 97 8f 67 72 3a 81 ae 8a dd fe 67 2e b8 2e 48 04 ad ce a6 a0 69 3a e7 67 b1 79 4a cd 33 91 1e 98 30 56 f0 14 4c 5a dd 97 b8 7a 98 7a dc 31 60 fd e6 bd a0 6b 5e 6f 9e 5b b9 3f b9 81 f1 89 15 b5 60 e4 40 40 f7 10 90 d9 46 68 44 3b ac 6d 55 0b 52 50 01 d5 71 0b 3e 9e 3c 35 06 f5 e1 f0 12 97 c5 41 45 9c 5b 7c a0 9f e4 64 36 8d 25 c5 11 7a d3 f7 8b ee 6b 00 c5 3f dd 60 78 ae 20 d6 48 44 44 a5 35 cc d9 73 d1 ee c7 80 f3 7b 91 49 f8 65 a5 ab 93 a9 fc ec b1 cf eb fb 5f 88 47 e3 64 c6 e4 69 c4 f2 96 67 bb 28 ec 28 e2 ad f5 89 3a 3b 31 63 95 d5 5e df 4b 2d c9 95
dispASN1 end

2018年2月24日 (土)

Powershellワンライナーで実行ファイルのバージョンを取得

カレントディレクトリのexeとdllのバージョンを取得する。

PS C:\windows> Get-ChildItem *.dll,*.exe | % { "{0}`t{1}`t{2}" -F $_.Fullname, $_.VersionInfo.FileVersion, $_.VersionInf
o.productversion }
C:\windows\RtlExUpd.dll 1, 0, 4, 0      1, 0, 4, 0
C:\windows\twain_32.dll 1,7,1,3 1,7,1,0
C:\windows\AddCat.exe   1.0.0.1 1.0.0.1
C:\windows\bfsvc.exe    10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\explorer.exe 10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\HelpPane.exe 10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\hh.exe       10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\KSAIM64.exe  3,62,0,0        3,62,0,0
C:\windows\notepad.exe  10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\regedit.exe  10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\splwow64.exe 10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\UN020914.EXE 1, 3, 8, 1      1, 3, 8, 1
C:\windows\winhlp32.exe 10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15
C:\windows\write.exe    10.0.16299.15 (WinBuild.160101.0800)    10.0.16299.15

Powershellで日時を取得

PS > get-date -format "yyyy/MM/dd HH:mm:ss.fff"
2018/02/24 18:42:31.239

Powershellワンライナーでショートパス(フルパス)を取得する

ショートパス名を取りたいファイル・フォルダがあるところに移動して、以下のコマンドを実行。

・ファイル名

$fso=New-Object -ComObject Scripting.FileSystemObject; get-childitem | ? {!$_.psiscontainer} | %{$fso.getfile($_.fullname).shortpath}

・フォルダ名

$fso=New-Object -ComObject Scripting.FileSystemObject; get-childitem | ? {$_.psiscontainer} | %{$fso.getfolder($_.fullname).shortpath}

Powershellワンライナーで連番のディレクトリを作る

作りたいディレクトリに移動してから、以下のコマンドを実行する。

0..3 | %{ new-item ("{0:0000}" -F $_) -itemType Directory}

Powershellワンライナーでバイナリファイル←→16進数表記

・バイナリファイル読込→16進数表記でテキストファイル出力

[System.IO.File]::ReadAllBytes(<入力バイナリファイル名>) | %{"{0:x2}" -F $_ | out-file <出力ファイル名> -append}

・16進数表記テキストファイル→バイナリファイル出力

$r=New-Object regex("[0-9a-fA-F]{2}"); $tmp=@(); get-content <入力16進数表記テキストファイル> | %{$r.Matches($_)} | %{$tmp += [Convert]::ToByte("0x" + $_.Value, 16)};[System.IO.File]::WriteAllBytes(<出力バイナリファイル>, $tmp)

2017年7月30日 (日)

IEのCOMインターフェイスでSJISとかUTF-8をOnMemoryで表示させる方法

プログラムから(ファイルを使わないで)IEを起動しXMLを開く方法からの派生。

IEのCOMインターフェイスで、OnMemoryからIEで表示する方法としてMSHTML::HTMLDocument2::write(BSTR)を提示したが、BSTRで渡すIFである以上、UNICODE(UTF-16)=WideCharしか渡せないので、SHIFT-JISやUTF-8のようなMultiByteコードで表示できなかった。
これで何が問題になるかというと、inputタグに漢字コードを渡すhiddenなやつがあるとURLエンコードの結果がエンコードに引っ張られてUTF-8のみに固定されてしまったのだ。(なぜUTF-16にならないのかはよくわかっていないが、javascriptがUTF-8前提になっているのでHTML界隈ではUTF-8で扱うことになっているのだろう?)
んで、BSTR型ではない方法で、IEに内容を渡すIFがないのか探していたのだが、(お仕事で実装がほとんど終わったこの時期に)やり方を見つけた。

↓ここを参考にしましたんで、詳細はこちらを参照してください。
Loading HTML content from a Stream

※:GlobalFree()で解放例外が出るなーと思っていたら、CreateStreamOnHGlobal()の第二引数をfalseにしないとダメじゃないですか?

Visual Studio 2017からVisual C++  Win32コンソールアプリケーションから作成(文字セットをUNICODEから設定なしにしておく)。

#include "stdafx.h"
//#include <Strsafe.h>
#include <stdio.h>
#include <tchar.h>

#import <shdocvw.dll>
#import <mshtml.tlb>

bool writeHtml(SHDocVw::IWebBrowser2Ptr &pIE, const TCHAR* pszHTMLText)
{
bool ret = false;

HRESULT hr;
IStream* pStream = NULL;
IDispatch* pHtmlDoc = NULL;
IPersistStreamInit* pPersistStreamInit = NULL;

MSHTML::IHTMLDocument2Ptr pDoc(pIE->Document);
//if (pDoc == nullptr) {
if (pDoc == NULL) {
goto FUNC_END;
}

//size_t cchMax = 256;
size_t cchLength = _tcslen(pszHTMLText);
HGLOBAL hHTMLText = GlobalAlloc(GPTR, cchLength + 1);
if (hHTMLText == NULL) {
goto FUNC_END;
}
//StringCchCopy((TCHAR*)hHTMLText, cchLength + 1, pszHTMLText);
_tcscpy_s((TCHAR*)hHTMLText, cchLength + 1, pszHTMLText);
hr = CreateStreamOnHGlobal(hHTMLText, FALSE, &pStream);
if (FAILED(hr)) {
goto FUNC_END;
}

// Call the helper function to load the browser from the stream.
// Query for IPersistStreamInit.
hr = pDoc->QueryInterface(IID_IPersistStreamInit, (void**)&pPersistStreamInit);
if (FAILED(hr)) {
goto FUNC_END;
}

// Initialize the document.
hr = pPersistStreamInit->InitNew();
if (FAILED(hr)) {
goto FUNC_END;
}

// Load the contents of the stream.
hr = pPersistStreamInit->Load(pStream);
if (FAILED(hr)) {
goto FUNC_END;
}

ret = true;

FUNC_END:
pPersistStreamInit->Release();
pStream->Release();
//pDoc->Release();
pDoc->close();
GlobalFree(hHTMLText);

return ret;
}

// IEを起動してhtmlデータを書き込む
// IEをコントロールしたい(IEを閉じるなど)場合は、WebBrowserのインスタンスを外に出して管理した方がよい
void openIE(const TCHAR* pszHTMLText)
{
SHDocVw::IWebBrowser2Ptr pIE;

// IE 起動+HTMLデータ設定+表示
HRESULT hr = pIE.CreateInstance(__uuidof(SHDocVw::InternetExplorer));
if (FAILED(hr)) {
return;
}

pIE->Navigate(L"about:blank"); //何か設定しないでHTMLを書き込むと例外が発生する。空文字を入れると"http:///"となる

bool bRslt = writeHtml(pIE, pszHTMLText);
if (!bRslt)
{
return;
}
pIE->Visible = VARIANT_TRUE; // IEを表示状態にする。ここで見えるようになる。

pIE = NULL;
}

int main(int argc, char* argv[])
{
int rtn = -1;
HANDLE hFile = INVALID_HANDLE_VALUE;
DWORD dwFileSize = 0;
TCHAR* fileData = NULL;

HRESULT hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);

if (argc != 2) {
fprintf(stderr,
"INVALID ARGUMENT.\n"
" Please Input HTML FileName(FULL PATH).\n"
);
goto FUNC_END;
}

hFile = CreateFile(argv[1], GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
goto FUNC_END;
}
dwFileSize = GetFileSize(hFile, NULL);
fileData = new TCHAR[dwFileSize + 1];
DWORD dwReadSize = 0;
BOOL bRslt = ReadFile(hFile, (LPVOID)fileData, dwFileSize, &dwReadSize, NULL);
if (!bRslt) {
goto FUNC_END;
}
CloseHandle(hFile);
hFile = INVALID_HANDLE_VALUE;
fileData[dwFileSize] = '\0';

openIE(fileData);
rtn = 0;

FUNC_END:
if (fileData != NULL) {
delete[]fileData;
}
if (hFile != INVALID_HANDLE_VALUE) {
CloseHandle(hFile);
}
::CoUninitialize();

return rtn;

確認したHTMLファイルは以下。それぞれSHIFT-JISとUTF-8de保存し、引数にファイル名を設定すればOK
なお、UNICODE(UTF-16)で保存されたファイルはNG。
●sjis.html

<html>
<head>
<meta charset="SHIFT_JIS">
</head>
<body>
文字コード:SJIS
</body>
</html>

●utf8.html

<html>
<head>
<meta charset="UTF-8">
</head>
<body>
文字コード:UTF-8
</body>
</html>

2017年6月11日 (日)

文字コードについて(主にWindows)

お仕事で、文字コードに苦しんだのでちょっと調べてみた。
ファイル出力されたUNICODE(UTF-8)、Windowsアプリ内でBSTRやら_bstr_tやらの扱いが混乱してしまった。あと、WideChar、マルチバイト文字、2バイト文字とか。
文字コードで一般的に頭に思い浮かべるのはASCII、SHIFT-JIS、UTF-8。UNICODEも。UNICODEとUTF-8、UTF-16とかの違いは?EUC-JPってのもある。

つらつらと書きだしてみる。。

  • UNICODEとUTF-8について。
    UNICODEは、符号化文字集合や文字符号化方式を定めたもの。
  • 符号化文字集合は、文字に対する数値が割り振られたもの(論理コードとでもいうべきか)。文字コード、コードセット、キャラセット、CES。UNICODEは、U+0000~U+10ffffとか表記される。”犬”は、UNICODEでU+72ac
  • 文字符号化方式は、符号化文字集合をバイト列に扱う仕様、方法を記したもの(物理コードという感じ?)。エンコーディング、CEF。UTF-8は、UNICODEの符号化文字集合の一つで1~4バイトで表現される。”犬”をUTF-8でバイト列にすると0xe78aac。UTF-16だと0x72ac。SHIFT-JISだと0x8ca2。
    ASCII文字類はUTF-8・UTF-16だと0x00を加えて2バイトにする。
  • BSTRは、内部でWideCharで扱われる。正確に言うと、OLECHAR *であり、OLECHARはWIN32であるとき+OLE2ANSIではないときにWCHARとなる。それ以外の時はchar型となる。
  • _bstr_tは、BSTRのスマートポインタ、ヘルパークラス。デバッグで見るとメンバ変数を見ると、m_wstrメンバ変数(BSTR)とm_strメンバ変数(mutable char*)、m_RefCount(unsigned long:スマートポインタのカウンタ)がある。
    _bstr_tの変数を作ると、m_wstrメンバ変数にUTF-16(WideCharな 2バイト文字)で格納される。(const char*)でキャストするとm_strメンバ変数に新たに領域を確保してからロケールに従った変換結果(日本ならSHIFT-JISのマルチバイト)を格納する。変数の参照が終わると領域を解放する。
    ちなみに、DLL内の関数に_bstr_t変数を渡して(const char*)でキャストすると、_bstr_t変数のスコープ外にでたときに領域解放できない。EXEとDLLのメモリ空間が異なるため。BSTRで渡してDLL内部で変換するべき。
  • UNICODE(WideChar)をUTF-8やSHIFT-JIS(マルチバイト)に変換するには、WindowsAPIではWideCharToMultiByte()を使う。その逆はMultiByteToWideChar()を使う。UTF-8とSHIFT-JISの変換は、いったんUNICODE(WideChar)に変換してから、変換したい文字コード(マルチバイト)にする。
  • BSTRからロケールに合わせた文字コードにするにはOLE2T、W2Aとか使えるかも。MSDN「ATLとMFCの文字列変換マクロ」を参照のこと。

テキストエディタで保存した、SHIFT-JIS、UTF-8、UTF-16、UTF-16(BigEndian)をVisualStudioでバイナリとして開いてみると以下のようになる。UTF-8,16,16(BE)の先頭3バイトはBOMが付いている。

Photo

試してみたプログラム

// TestBSTR.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"comsuppw.lib")	// WideChar (link comsuppw.lib)
//#pragma comment(lib,"comsupp.lib")	// Not WideChar (link comsupp.lib)

#include "stdafx.h"
#include <windows.h>
#include <comutil.h>
#include <tchar.h>
#include <mbstring.h>

void dumpBin(LPCSTR type, LPCSTR data, size_t len) {
	printf("%s (address=0x%08x): \n", type, (unsigned int)data);
	for (size_t idx = 0; len > idx; idx++) {
		printf("\t");
		for (size_t cnt = 0; (len > idx) && (16 > cnt); cnt++, idx++) {
			printf("%02x ", (unsigned char)data[idx] );
		}
		printf("\n");
	}
}

// WideCharからMultiByteに変換
//関数内で領域を確保するので、使用後は開放すること
int convertWideToMulti(const wchar_t *pwsData, UINT encoding, LPSTR *pstrRslt)
{
	size_t len = wcslen(pwsData);
	int iW2MLen1 = WideCharToMultiByte(encoding, 0, pwsData, len, NULL, 0, NULL, NULL);
	if (iW2MLen1 == 0) {
		// 失敗
		return -1;
	}
	*pstrRslt = (LPSTR)malloc(iW2MLen1 + 1);
	if (*pstrRslt == NULL) {
		// 失敗
		return -1;
	}
	ZeroMemory(*pstrRslt, iW2MLen1 + 1);
	int iW2MLen2 = WideCharToMultiByte(encoding, 0, pwsData, len, (LPSTR)*pstrRslt, iW2MLen1, NULL, NULL);
	if (iW2MLen2 == 0) {
		// 失敗
		free(*pstrRslt);
		return -1;
	}
	return iW2MLen2;
}

// MultiByteからWideCharに変換
//関数内で領域を確保するので、使用後は開放すること
int convertMultiToWide(LPCSTR pcstrData, UINT encoding, LPWSTR *ppwsRslt )
{
	size_t len = strlen(pcstrData);
	int iW2MLen1 = MultiByteToWideChar(encoding, 0, pcstrData, len, NULL, 0);
	if (iW2MLen1 == 0) {
		// 失敗
		return -1;
	}
	*ppwsRslt = (LPWSTR)malloc((iW2MLen1 + 1)*2);
	if (*ppwsRslt == NULL) {
		// 失敗
		return -1;
	}
	ZeroMemory(*ppwsRslt, (iW2MLen1 + 1) * 2);
	int iW2MLen2 = MultiByteToWideChar(encoding, 0, pcstrData, len, (LPWSTR)*ppwsRslt, iW2MLen1);
	if (iW2MLen2 == 0) {
		// 失敗
		free(*ppwsRslt);
		return -1;
	}
	return iW2MLen2 * 2;
}

int main()
{
	const wchar_t *pwsData =
		L"kotatuinu!\n"
		L"炬燵犬!\n"
		L"コタツイヌ\n";

	printf("データ:%ls\n", pwsData);

	// wchar_t
	size_t len = wcslen(pwsData);
	dumpBin("wchar_t", (LPCSTR)pwsData, len*2);

	// _bstr_t -> BSTR
	_bstr_t bstrData1(pwsData);
	BSTR bsData1 = bstrData1;
	len = SysStringByteLen(bsData1);
	dumpBin("_bstr_t -> BSTR", (LPCSTR)bsData1, len);

	// _bstr_t.copy(false) -> BSTR
	// _bstr_t.copy(false)は_bstr_tのm_wstrメンバの領域を渡す→解放しちゃダメ
	BSTR bsData3 = bstrData1.copy(false);
	len = SysStringByteLen(bsData3);
	dumpBin("_bstr_t.copy(false) -> BSTR", (LPCSTR)bsData3, len);

	// _bstr_t.copy(true) -> BSTR
	// _bstr_t.copy(true)は新たに領域を取得する→SysFreeString()で解放が必要
	BSTR bsData2 = bstrData1.copy(true);
	len = SysStringByteLen(bsData2);
	dumpBin("_bstr_t.copy(true) -> BSTR", (LPCSTR)bsData2, len);
	::SysFreeString(bsData2);

	// _bstr_t -> const char *
	const char *szData1 = (const char*)bstrData1;
	len = strlen(szData1);
	dumpBin("_bstr_t -> const char *", (LPCSTR)szData1, len);

	// wchar->multibyte(encode UTF8)
	LPSTR pszData4;
	int iRtn = convertWideToMulti(pwsData, CP_UTF8, &pszData4);
	len = strlen(pszData4);
	len = _mbstrlen(pszData4);
	dumpBin("wchar->multibyte(encode UTF8)", (LPCSTR)pszData4, len);
	//free(pszData4);

	// wchar->multibyte(encode SHIFT-JIS)
	LPSTR pszData5;
	iRtn = convertWideToMulti(pwsData, CP_ACP, &pszData5);
	len = strlen(pszData5);
	len = _mbstrlen(pszData5);
	dumpBin("wchar->multibyte(encode SHIFT-JIS)", (LPCSTR)pszData5, len);
	free(pszData5);

	// multibyte(UTF-8)->wchar(UNICODE)->multibyte(SHIFT-JIS)
	LPWSTR pwsData1;
	LPSTR pszData6;
	iRtn = convertMultiToWide((LPCSTR)pszData4, CP_UTF8, &pwsData1);
	iRtn = convertWideToMulti(pwsData1, CP_ACP, &pszData6);
	dumpBin("multibyte(UTF-8)->wchar(UNICODE)->multibyte(SHIFT-JIS)", (LPCSTR)pszData6, iRtn);
	free(pszData4);
	free(pszData6);
	free(pwsData1);

	return 0;
}

出力結果

データ:kotatuinu!
wchar_t (address=0x00f5cc5c):
        6b 00 6f 00 74 00 61 00 74 00 75 00 69 00 6e 00
        00 21 00 0a 00 ac 70 f5 71 ac 72 01 ff 0a 00 7a
        80 ff 82 ff 72 ff 87 ff 0a 00
_bstr_t -> BSTR (address=0x00d96da4):
        6b 00 6f 00 74 00 61 00 74 00 75 00 69 00 6e 00
        00 21 00 0a 00 ac 70 f5 71 ac 72 01 ff 0a 00 7a
        80 ff 82 ff 72 ff 87 ff 0a 00
_bstr_t.copy(false) -> BSTR (address=0x00d96da4):
        6b 00 6f 00 74 00 61 00 74 00 75 00 69 00 6e 00
        00 21 00 0a 00 ac 70 f5 71 ac 72 01 ff 0a 00 7a
        80 ff 82 ff 72 ff 87 ff 0a 00
_bstr_t.copy(true) -> BSTR (address=0x00d96a44):
        6b 00 6f 00 74 00 61 00 74 00 75 00 69 00 6e 00
        00 21 00 0a 00 ac 70 f5 71 ac 72 01 ff 0a 00 7a
        80 ff 82 ff 72 ff 87 ff 0a 00
_bstr_t -> const char * (address=0x00d96ee0):
        6b 6f 74 61 74 75 69 6e 75 21 0a e0 78 e0 9d 8c
        81 49 0a ba c0 c2 b2 c7 0a
wchar->multibyte(encode UTF8) (address=0x00d8b6c0):
        6b 6f 74 61 74 75 69 6e 75 21 0a e7 82 ac e7 87
        e7 8a ac ef bc 81 0a ef bd ba ef be 80 ef be 82
        bd b2 ef be 87 0a
wchar->multibyte(encode SHIFT-JIS) (address=0x00d96d30):
        6b 6f 74 61 74 75 69 6e 75 21 0a e0 78 e0 9d 8c
        81 49 0a ba c0 c2 b2 c7 0a
multibyte(UTF-8)->wchar(UNICODE)->multibyte(SHIFT-JIS) (address=0x00d96fb8):
        6b 6f 74 61 74 75 69 6e 75 21 0a e0 78 e0 9d 8c
        81 49 0a ba c0 c2 b2 c7 0a

2017年5月24日 (水)

about:blankはインターネットゾーン!?

#2017/5/25修正(マイコンピュータゾーンを追記)

先日「プログラムから(ファイルを使わないで)IEを起動しXMLを開く方法」で開いたページプロパティのゾーンが”インターネット|保護モード:有効”となっていた。なんでインターネット?
ローカルファイルを開いた時には、”マイコンピュータ|保護モード:有効”となるのに。

ゾーンの違いにより何が異なるかというと、ローカルファイルではJavaScriptの実行に「ブロックされているコンテンツを許可」ボタンを押さなければいけないが、インターネットゾーンではそれが無くてもJavascriptは動くという動作の違いが出てくる。(ただしインターネットオプション-セキュリティの設定による)

Internet Explorerにはセキュリティゾーンというものがあり、インターネットオプション セキュリティで以下の4種類の設定ができる。
また、インターネットオプションには表示されていないが+1種類が隠しである。(レジストリの設定により表示できる)

  • インターネットゾーン
  • ローカル イントラネットゾーン
  • 信頼済みサイト ゾーン
  • 制限付きサイトゾーン
  • マイコンピュータゾーン

ローカルのファイルは、マイコンピュータゾーンに該当する。
ちなみに、インターネットオプション セキュリティにマイコンピュータゾーンを表示させるには、以下のレジストリを設定すればよい。
 HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\Zones\0
 項目:Flags の値を0x21から0x47にする、

インターネットゾーンは、ローカル イントラネットゾーン・信頼済みサイトゾーン・制限付きサイトゾーンのどれにも当てはまらないときに該当する。

信頼済みサイトゾーン・制限付きサイトゾーンは、明示的にURLを登録する必要があるので、通常の環境では当てはまらない。
ローカル イントラネットゾーンは、以下の3つの選択オプション+URLの登録で指定できる。

  • 他のゾーンに指定されていないローカル(イントラネット)のサイトを全て含める
  • プロキシサーバを使用しないサイトを全て含める(接続-LANの設定-プロキシサーバ接続で設定)
  • 全てのネットワークパス(UNC)を含める

"about:blank"は、ローカル イントラネットではないので(他のゾーンに設定されていないし)、結局、インターネットゾーンと判定されてしまう。
→参考:Microsoft TechNet「IE のセキュリティ ゾーンについて」

なお、"about:blank"は、空白ページを示すもので以下のレジストリにURLが登録されている。
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Internet Explorer\AboutURLs の blank項目。登録されている文字列値は"res://mshtml.dll/blank.htm"

about:blankを入力すると、res://mshtml.dll/blank.htmのページが表示される。
直接、URLに”res://mshtml.dll/blank.htm”を入れてIEで表示させると、ローカル イントラネットゾーンになる。仕事場のPCだとローカル イントラネットゾーンだったけど、家ではインターネットゾーンになった。(ちなみに上記レジストリキーを見ると他にもabout:系があることがわかる。)
about:blankをローカル イントラネットゾーンと判定されるためには、インターネットオプション-セキュリティ-ローカル イントラネットのサイトに追加するしかないようだ。でも、そんなことしてもちっともうれしくないか・・・。

インターネットオプション-セキュリティ-ローカル イントラネットのサイトは、以下のレジストリに登録されるので、無理やり通そうと思えばできなくはない・・・。HKEY_CURRENT_USER\SOFTWARE\Microsoft\Windows\CurrentVersion\Internet Settings\ZoneMap\Domains

→参考:MSDN「上級ユーザー向けの Internet Explorer セキュリティ ゾーン関連のレジストリ エントリ」

なお、ローカル イントラネットゾーンのページは「保護モード:無効」となっており、通常、インターネットゾーンのリンクを開くと「保護モード:有効」となるが、VC++ のデバック実行で開いたページからインターネットゾーンのリンクを開いても「保護モード:無効」のままになる。

保護モードが有効であると、IE上で動作するプロセスやアドオンがシステムへのアクセス権限などに制約される。つまり、保護モード:無効のままではヤバい。
(VC++のデバッグ実行ではなく)デバックオプションで生成したexeでも、exeファイルをキックして起動すれば上記の現象は起きないので、通常は問題にならないけど。テストで実行していたら、振る舞いが違うので悩んだので、ここに記しておく。

セキュリティ周りはとてもめんどくさく、環境・設定によって結果が変わってきて安定した結果を得られにくいので混乱してくる。
文句言われたくないので触りたくないな。

より以前の記事一覧