PKI: コード署名 (Code signing)

Windows 10のUWPアプリは、署名しなければならない。Microsoft Storeで公開する場合だけでなく, 組織内で展開 (LOBアプリ) であっても。

あるいは, accessibility アプリケーションで, アプリケーションマニフェスト内で uiAccess='true' とする場合も, コード署名しなければ実行が許可されない.

デバイスドライバも、コード署名しなければならない。

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

コード署名 (Code signing) とは

コード署名は, プログラムのバイナリに, デジタル署名 (Digital signature) を付けたもの。

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

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

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

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

実行時は, 証明書を検証したうえで、signature を作成者の公開鍵で復号し、バイナリのハッシュ値と一致することを確認します。

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アプリ

上記のとおり, AppxSignature.p7x ファイルに対して署名されている。アプリの実体は, C:\Program Files\WindowsApps 以下にある.

> & '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になっている。

バイナリ作成者の秘密鍵と証明書を用意

バイナリに署名するには, 秘密鍵と証明書の両方が必要です。

署名要求 (CSR)

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

以下は, 秘密鍵を同時に作る方法. すでに秘密鍵がある場合は, openssl req -new コマンド.

$ /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.pemnewreq.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:改行

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

バイナリに署名する

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証明書を証明書ストアに格納

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

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

これで、コード署名証明書が検証できればOKです。

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