PKI: コード署名 (Code signing)

Windows 10 では、いくつかの種類のプログラムは、コード署名 (code signing) しなければ動作しない。

  • UWPアプリ. Microsoft Storeで公開する場合だけでなく, 組織内だけで展開するもの (LOBアプリ) であっても。
  • Accessibility アプリケーション. アプリケーションマニフェスト内で uiAccess='true' とする場合, コード署名しなければ, 実行が許可されない.
  • デバイスドライバ.
  • IME. どういう区別か不明だが, IME 以外の text service は "should" になっていて, 今のところコード署名がなくても動く.

このページでは, 組織で展開するようなプライベートなアプリケーションを想定して, コード署名の方法を解説する.

コード署名 (Code signing) とは

コード署名とは, プログラムのバイナリに, デジタル署名 (Digital signature) を付けることです。「署名」が signature で,「署名すること」が signing.

https://commons.wikimedia.org/wiki/File:Digital_Signature_diagram.svg

実行ファイルが改竄されていないことを証明し、実行ファイルの作成者を保証することができます。注意! 実行ファイルが正しく動作することを保証するものではありません

作成時は, 次のようにします (signing);

  1. 一方向ハッシュ関数でバイナリのハッシュ値を得る
  2. ハッシュ値を、作成者の秘密鍵で暗号化. これが signature.
  3. バイナリに、作成者の証明書と signature を埋め込む。

実行時は, 次のステップで検証 (verification) されます;

  1. 添付された証明書を検証し、作成者が本人であるか, を確認する。
  2. 証明書から作成者の公開鍵を取り出し, signature をその公開鍵で復号し、バイナリのハッシュ値と一致することを確認する

デジタル署名についてはこちら; 2.4 デジタル署名 - PKI関連技術に関するコンテンツ

Windows UWPアプリ

実行ファイルのフォーマットは署名を埋め込むことができますが、画像ファイルなどにはできません。そこで, UWPアプリでは, 配備する各ファイルのハッシュ値を集めたファイル AppxBlockMap.xml を作り, さらにこのファイルのハッシュ値に対して署名する, という方法を採っている.

https://blogs.msdn.microsoft.com/windowsappdev_ja/2012/12/12/appx/

なので, UWPアプリでは, 署名が付いているのは .exe ファイルではなく, AppxSignature.p7x というファイル.

実際の例

作り方が知りたい人は、次のセクションまで読み跳ばしてください。

Accessibility アプリケーション

マニフェストを表示してみる。SysInternals の SigCheck コマンドを使う.

> & 'C:\Program Files\SysinternalsSuite\sigcheck.exe' -m C:\windows\system32\Magnify.exe

Sigcheck v2.60 - File version and signature viewer
Copyright (C) 2004-2017 Mark Russinovich
Sysinternals - www.sysinternals.com

c:\windows\system32\Magnify.exe:
        Verified:       Signed
        Signing date:   18:04 2018/03/03
        Publisher:      Microsoft Windows
        Company:        Microsoft Corporation
        Description:    Microsoft Screen Magnifier
        Product:        Microsoftョ Windowsョ Operating System
        Prod version:   10.0.16299.248
        File version:   10.0.16299.248 (WinBuild.160101.0800)
        MachineType:    64-bit
        Manifest:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- Copyright (c) Microsoft Corporation -->
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity
    name="Microsoft.Windows.EndUser.Magnify"
    processorArchitecture="amd64"
    version="5.1.0.0"
    type="win32"/>
  <description>Magnifier</description>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
    <security>
      <requestedPrivileges>
        <requestedExecutionLevel level="asInvoker" uiAccess="true"/>
      </requestedPrivileges>
    </security>
  </trustInfo>
  <dependency>
    <dependentAssembly>
        <assemblyIdentity
          type="win32"
          name="Microsoft.Windows.Common-Controls"
          version="6.0.0.0"
          processorArchitecture="*"
          publicKeyToken="6595b64144ccf1df"
          language="*" />
    </dependentAssembly>
  </dependency>
  <application xmlns="urn:schemas-microsoft-com:asm.v3">
    <windowsSettings>
      <dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">per monitor</dpiAware>
    </windowsSettings>
  </application>
</assembly>

赤字の部分, <requestedExecutionLevel level="asInvoker" uiAccess="true"/> がある。これがあると、強い権限がある分、実行時のチェックが厳しい.

このバイナリの署名を表示してみる. SigCheck-i オプション;

> & 'C:\Program Files\SysinternalsSuite\sigcheck.exe' -i C:\windows\system32\Magnify.exe

Sigcheck v2.60 - File version and signature viewer
Copyright (C) 2004-2017 Mark Russinovich
Sysinternals - www.sysinternals.com

c:\windows\system32\Magnify.exe:
        Verified:       Signed
        Link date:      23:15 1993/12/23
        Signing date:   18:04 2018/03/03
        Catalog:        C:\WINDOWS\system32\CatRoot\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\Package_1051_for_KB4088776~31bf3856ad364e35~amd64~~10.0.1.3.cat
        Signers:
           Microsoft Windows
                Cert Status:    Valid
                Valid Usage:    NT5 Crypto, Code Signing
                Cert Issuer:    Microsoft Windows Production PCA 2011
                Serial Number:  33 00 00 01 74 69 DE 10 8B 37 65 A8 D7 00 00 00 00 01 74
                Thumbprint:     419E77AED546A1A6CF4DC23C1F977542FE289CF7
                Algorithm:      sha256RSA
                Valid from:     5:23 2017/08/12
                Valid to:       5:23 2018/08/12
           Microsoft Windows Production PCA 2011
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2010
                Serial Number:  61 07 76 56 00 00 00 00 00 08
                Thumbprint:     580A6F4CC4E4B669B9EBDC1B2B3E087B80D0678D
                Algorithm:      sha256RSA
                Valid from:     3:41 2011/10/20
                Valid to:       3:51 2026/10/20
           Microsoft Root Certificate Authority 2010
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2010
                Serial Number:  28 CC 3A 25 BF BA 44 AC 44 9A 9B 58 6B 43 39 AA
                Thumbprint:     3B1EFD3A66EA28B16697394703A72CA340A05BD5
                Algorithm:      sha256RSA
                Valid from:     6:57 2010/06/24
                Valid to:       7:04 2035/06/24
        Counter Signers:
           Microsoft Time-Stamp Service
                Cert Status:    Valid
                Valid Usage:    Timestamp Signing
                Cert Issuer:    Microsoft Time-Stamp PCA 2010
                Serial Number:  33 00 00 00 A5 48 17 72 27 F9 70 BE 63 00 00 00 00 00 A5
                Thumbprint:     9BC235DDFBB2262B1A143165502F1D539469826F
                Algorithm:      sha256RSA
                Valid from:     2:56 2016/09/08
                Valid to:       2:56 2018/09/08
           Microsoft Time-Stamp PCA 2010
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2010
                Serial Number:  61 09 81 2A 00 00 00 00 00 02
                Thumbprint:     2AA752FE64C49ABE82913C463529CF10FF2F04EE
                Algorithm:      sha256RSA
                Valid from:     6:36 2010/07/02
                Valid to:       6:46 2025/07/02
           Microsoft Root Certificate Authority 2010
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2010
                Serial Number:  28 CC 3A 25 BF BA 44 AC 44 9A 9B 58 6B 43 39 AA
                Thumbprint:     3B1EFD3A66EA28B16697394703A72CA340A05BD5
                Algorithm:      sha256RSA
                Valid from:     6:57 2010/06/24
                Valid to:       7:04 2035/06/24
        Company:        Microsoft Corporation
        Description:    Microsoft Screen Magnifier
        Product:        Microsoftョ Windowsョ Operating System
        Prod version:   10.0.16299.248
        File version:   10.0.16299.248 (WinBuild.160101.0800)
        MachineType:    64-bit

最終的に, Microsoft Root Certificate Authority 2010 まで繋がっていることが分かる。

UWPアプリ

アプリの実体は C:\Program Files\WindowsApps 以下にある. 上記のとおり, プログラムのほうではなく (または加えて), AppxSignature.p7x ファイルに対して署名されている。

> & 'C:\Program Files\SysinternalsSuite\sigcheck.exe' -i .\AppxSignature.p7x

Sigcheck v2.60 - File version and signature viewer
Copyright (C) 2004-2017 Mark Russinovich
Sysinternals - www.sysinternals.com

C:\Program Files\WindowsApps\MomendYazilim.DriverXP_1.0.0.5_x86__fvhpr3fm9t3ag\AppxSignature.p7x:
        Verified:       Signed
        File date:      14:22 2016/05/07
        Signing date:   0:30 2015/04/15
        Catalog:        C:\Program Files\WindowsApps\MomendYazilim.DriverXP_1.0.0.5_x86__fvhpr3fm9t3ag\AppxSignature.p7x
        Signers:
           8F53F2DB-2125-42EA-A116-5C366768CCFE
                Cert Status:    This certificate or one of the certificates in the certificate chain is not time valid.
                Valid Usage:    Windows Store, Code Signing
                Cert Issuer:    Microsoft Marketplace CA G 008
                Serial Number:  33 00 04 5A E4 8F 99 05 7B 6C 0E 7D 86 00 00 00 04 5A E4
                Thumbprint:     F26A03C4BC28905AAFE2949CFAA1B38ACF121F00
                Algorithm:      sha256RSA
                Valid from:     0:18 2015/04/15
                Valid to:       0:18 2015/04/18
           Microsoft Marketplace CA G 008
                Cert Status:    This certificate or one of the certificates in the certificate chain is not time valid.
                Valid Usage:    All
                Cert Issuer:    Microsoft MarketPlace PCA 2011
                Serial Number:  61 0B 25 C2 00 00 00 00 00 2E
                Thumbprint:     15332841E977A756198CF09AE00C480944EB31B0
                Algorithm:      sha256RSA
                Valid from:     5:31 2012/05/17
                Valid to:       5:41 2015/05/17
           Microsoft MarketPlace PCA 2011
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2011
                Serial Number:  61 12 44 A2 00 00 00 00 00 02
                Thumbprint:     EB9204785126C26ADADCBBD44FE2B0C642A71078
                Algorithm:      sha256RSA
                Valid from:     6:09 2011/03/29
                Valid to:       6:19 2031/03/29
           Microsoft Root Certificate Authority 2011
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2011
                Serial Number:  3F 8B C8 B5 FC 9F B2 96 43 B5 69 D6 6C 42 E1 44
                Thumbprint:     8F43288AD272F3103B6FB1428485EA3014C0BCFE
                Algorithm:      sha256RSA
                Valid from:     7:05 2011/03/23
                Valid to:       7:13 2036/03/23
        Counter Signers:
           Microsoft Time-Stamp Service
                Cert Status:    This certificate or one of the certificates in the certificate chain is not time valid.
                Valid Usage:    Timestamp Signing
                Cert Issuer:    Microsoft Time-Stamp PCA 2010
                Serial Number:  33 00 00 00 55 6E 9D DA 5A A6 F3 1C 5B 00 00 00 00 00 55
                Thumbprint:     51E945A7C9B57FB14A92177895425B4C2D4D66CE
                Algorithm:      sha256RSA
                Valid from:     2:32 2015/03/21
                Valid to:       2:32 2016/06/21
           Microsoft Time-Stamp PCA 2010
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2010
                Serial Number:  61 09 81 2A 00 00 00 00 00 02
                Thumbprint:     2AA752FE64C49ABE82913C463529CF10FF2F04EE
                Algorithm:      sha256RSA
                Valid from:     6:36 2010/07/02
                Valid to:       6:46 2025/07/02
           Microsoft Root Certificate Authority 2010
                Cert Status:    Valid
                Valid Usage:    All
                Cert Issuer:    Microsoft Root Certificate Authority 2010
                Serial Number:  28 CC 3A 25 BF BA 44 AC 44 9A 9B 58 6B 43 39 AA
                Thumbprint:     3B1EFD3A66EA28B16697394703A72CA340A05BD5
                Algorithm:      sha256RSA
                Valid from:     6:57 2010/06/24
                Valid to:       7:04 2035/06/24
        Company:        n/a
        Description:    n/a
        Product:        n/a
        Prod version:   n/a
        File version:   n/a
        MachineType:    n/a

こっちは, Microsoft Root Certificate Authority 2011 がルートCAになっている。

バイナリ作成者の秘密鍵と証明書を用意 (1回切り)

バイナリに署名するには, 自分の秘密鍵と証明書の両方が必要です。証明書は、自分の公開鍵に対して認証局 (CA) が署名したものです。

署名要求 (CSR)

CAに対して, 公開鍵に対する署名要求を出します。

以下は, 秘密鍵を同時に作る方法. すでに秘密鍵がある場合は, openssl req -new -key 秘密鍵ファイル名 -out CSRファイル名.

/usr/bin/CA.pl ファイルは openssl-perl パッケージに含まれる。

$ /usr/bin/CA.pl -newreq
====
openssl req  -new -keyout newkey.pem -out newreq.pem -days 365
Generating a 2048 bit RSA private key
......+++
.......................................+++
writing new private key to 'newkey.pem'
Enter PEM pass phrase:秘密鍵のパスワード
Verifying - Enter PEM pass phrase:確認
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:JP
State or Province Name (full name) []:Fukuoka
Locality Name (eg, city) [Default City]:Munakata
Organization Name (eg, company) [Default Company Ltd]:Netsphere Laboratories
Organizational Unit Name (eg, section) []:改行
Common Name (eg, your name or your server's hostname) []:Netsphere Laboratories Code Signing
Email Address []:hisashi.horikawa@gmail.com

Please enter the following 'extra' attributes                                  
to be sent with your certificate request                                       
A challenge password []:改行
An optional company name []:改行                                   
==> 0                                                                          
====                                                                           
Request is in newreq.pem, private key is in newkey.pem                          

秘密鍵 (newkey.pem ファイル) と 署名要求 (newreq.pem) ができた。秘密鍵は秘密にしなければなりません。

中間CAが署名する

/etc/pki/tls/openssl.cnf をコピーして, 設定ファイルを作ります。

バイナリ作成者はCAではないので, CA:FALSE.

目的は codeSigning. コード署名の場合の keyUsagedigitalSignature があればよい。

[ v3_ca ]

subjectKeyIdentifier=hash

authorityKeyIdentifier=keyid:always,issuer

# ここ
basicConstraints = critical,CA:FALSE

# Key usage: this is typical for a CA certificate. However since it will
# prevent it being used as an test self-signed certificate it is best
# left out by default.
keyUsage = digitalSignature

# これ
extendedKeyUsage = critical,codeSigning

Note.

Storeアプリの AppxSignature.p7x ファイルに付けられた証明書では, 目的は次の2つになっている:

  • Windows ストア (1.3.6.1.4.1.311.76.3.1)
  • コード署名 (1.3.6.1.5.5.7.3.3)

後者は上の codeSigning のこと。RFC 5280 May 2008; Obsoletes: 3280, 4325, 4630, で定義された, id-kp-codeSigning.

前者は, <wincrypt.h> でハードコードされている.

// Signer of Windows Store applications
#define szOID_WINDOWS_STORE_SIGNER      "1.3.6.1.4.1.311.76.3.1"

このような数字とピリオドの組み合わせで示された OID は, 例えば, 次のサイトで確認できる; OID Repository

CA.pl -signCA コマンドで, バイナリ作成者の公開鍵に署名して, 証明書を作る. カレントディレクトリに newreq.pem ファイルが必要。

$ OPENSSL_CONFIG="-config code-signing.cnf" /usr/bin/CA.pl -signCA
====
openssl ca -config code-signing.cnf -policy policy_anything -out newcert.pem -extensions v3_ca -infiles newreq.pem
Using configuration from code-signing.cnf
Check that the request matches the signature
Signature ok
Certificate Details:
        Serial Number: 4661 (0x1235)
        Validity
            Not Before: Mar  4 04:57:34 2018 GMT
            Not After : Mar  4 04:57:34 2019 GMT
        Subject:
            countryName               = JP
            stateOrProvinceName       = Fukuoka
            localityName              = Munakata
            organizationName          = Netsphere Laboratories
            commonName                = Netsphere Laboratories Code Signing
            emailAddress              = hisashi.horikawa@gmail.com
        X509v3 extensions:
            X509v3 Subject Key Identifier: 
                C5:37:D4:8C:A5:70:CE:5A:05:A2:4D:61:10:0E:5F:90:14:A1:C8:C4
            X509v3 Authority Key Identifier: 
                keyid:BE:CC:6A:D8:8D:D3:ED:4C:C1:52:77:5A:38:2F:41:9E:B8:8B:A1:BA

            X509v3 Basic Constraints: critical
                CA:FALSE
            X509v3 Key Usage: 
                Digital Signature
            X509v3 Extended Key Usage: critical
                Code Signing
Certificate is to be certified until Mar  4 04:57:34 2019 GMT (365 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
==> 0
====
Signed CA certificate is in newcert.pem

証明書が newcert.pem として保存される。

PKCS #12ファイルに変換

再び、バイナリ作成者の手順。

Visual Studio でビルド時に自動的に署名させるには, PKCS #12ファイルを作ってやります。

PKCS #12は, 証明書と秘密鍵を一つのファイルに格納する形式。PKCS #12のファイルを「証明書」と呼ぶのは正しくない。混乱の元。

拡張子は .p12 または .pfx (どちらでも可).

中間CAの証明書と、今回作ったバイナリ作成者の証明書と秘密鍵を一つにまとめます.

$ openssl pkcs12 -export -in code-signing.cert.pem \
          -inkey code-signing.private.pem \
          -certfile ../intermediate-ca/CA/cacert.pem -out code-signing.pfx
Enter pass phrase for code-signing.private.pem:秘密鍵のパスワード
Enter Export Password:改行  パスワードは空にしないと、ビルドに使えない
Verifying - Enter Export Password:改行

パスワードを付けたままだと, あらかじめ証明書ストアに格納しないといけなかった、ような。メモし忘れた。

バイナリに署名する (ビルドの度に)

署名を行う端末でも、あらかじめroot証明書をストアへ格納しておくことが必要です (手順は後述)。

UWPアプリ

Visual Studio で署名する. 単に package.appxmanifest のプロパティで, 先ほどの PKCS #12ファイルを指定すればOK.

Accessibility アプリケーション

SDK の SignTool sign コマンドで署名する. /aオプションで, 中間証明書も付けるのを忘れずに.

"C:\Program Files (x86)\Windows Kits\10\bin\10.0.16299.0\x86\signtool" sign /f ..\..\certs\code-signing2.pfx /a x64\Debug\*.exe x64\Debug\*.dll 

展開する端末で, root証明書を証明書ストアに格納

このセクションは、オレオレroot証明書を使った場合です。

実行時の検証に合格できるように, バイナリを配備 (deploy) するすべての端末で, root証明書を証明書ストアに格納します。

保存場所: ローカルコンピュータ (管理者権限が必要)

「証明書をすべて次のストアに配置」を選択. ストアを自分で選ぶ →「信頼されたルート証明機関」

この状態で、コード署名された実行ファイルの証明書が検証できればOKです。

失敗談: 最初, 中間CAとしてTLS用のを使ったら, バイナリ作成者の証明書の検証に失敗した。きちんと, ルートCAまでの経路それぞれについて, 目的フィールドもチェックされていた。エラい.