자바스크립트를 활성화 해주세요

p057 Windows에서 인증서만들어 스크립트 서명하기

 ·  ☕ 6 min read

인증서

인증서를 생성하여 Powershell 스크립트에 서명할 수 있습니다. 서명을 사용하는 이유는 보안입니다. 실제로 dll이나 jar도 마찬가지입니다만, 악의적인 목적으로 동작을 가로채는 것을 막기 위한 것입니다.

서명되지 않은 스크립트를 사용하려면, Windows 보안 조치를 완전히 비활성화해야 하는데, 이는 좋지 않을 수 있다.

이하 우리가 하는 모든 것은 커맨드 프롬프트가 아니라 Powershell을 사용합니다.

인증 배경:
인증서는 인증기관(CA)에 의해 권한을 부여받습니다. CA는 인증서의 유효 여부를 확인합니다. 컴퓨터가 인증서를 사용하려고 할 때 “신뢰할 수 있는” CA의 인증서 유효성을 요청하여 인증서의 유효성을 확인해야 합니다.

비용을 지불하여 공식 CA에 서명된 인증서를 발급받을 수도 있고, 또는 개인 CA를 만들고, 개인 인증서를 만들고, 개인 CA로 인증서에 서명할 수도 있습니다. 우리는 후자의 과정을 이용하려 합니다.

Windows OS는 인증서 저장소에 유효한 CA 정보를 저장합니다. (again, “신뢰할 수 있는 CA 목록”). 저장 공간은
CurrentUser > Trusted Root Certification Authorities > Certificates 입니다.

일본어 OS를 사용하고 있는 제 환경에서는 다음과 같습니다. 신뢰할 수 있는 CA 목록입니다.

p057_certificates_store_ca_list.png

인증서를 관리하는 제어판을 실행하는 명령어는 certmgr입니다.

PS C:\temp\pwshprj> which certmgr
C:\Windows\system32\certmgr.MSC

용어

몇 가지 용어를 짚고 넘어가도록 하죠.

  • x509 : 인증서가 가져야할 항목을 정의한 데이타 정의입니다.
  • PKI : 공개 키 기반구조(public key infrastructure)라고 번역이 되는데, CA, RA, VA 기관으로 나누어 인증합니다 라는 의미입니다.
    • CA = Certification Authority
    • RA = Registration Authority
    • VA = Validation Authority
  • PKCS : 공개 키 암호 표준 “Public Key Cryptography Standards”. ‘RSA Security LLC’ 라는 회사가 발표하는 표준 포맷입니다. 몇가지 종류가 있는데, 7번이 서명을 위한 표준 포맷, 12번이 공개키와 개인키를 함께 저장하는 포맷입니다. 파일 확장자는 .p12 또는 .pfx 를 사용합니다.
    • PFX는 Personal Information Exchange 의 약자입니다.

인증서를 저장하는 포맷으로는 다음과 같은 것들이 있습니다.

  • .CER - CER 암호화 된 인증서. 복수의 인증서도 가능.
  • .DER - DER 암호화 된 인증서.
  • .PEM - (Privacy Enhanced Mail) Base64로 인코딩 된 인증서. “—–BEGIN CERTIFICATE—–“와 “—–END CERTIFICATE—–” 가운데에 들어간다.
  • .P7B - .p7c 참조.
  • .P7C - PKCS#7 서명 자료 구조(자료는 제외), 인증서이거나 CRL(복수도 가능).
  • .PFX - .p12 참조.
  • .P12 - PKCS#12, 공개 인증서와 암호로 보호되는 개인 키를 가질 수 있다(복수도 가능).

서명은 위조가 되었나 안되었나만을 확인하는 것인데,

GMO 그룹에서 운영하는 https://www.globalsign.com/ 은 마켓쉐어 6위 정도의 실적을 보이고 있습니다. 원래 영국에 있던 회사였는데 GMO그룹이 인수했습니다.

Powershell 인증서 관련 명령어

powershell에서 인증서와 관련된 명령어가 무엇이 있는 지 확인해 보았습니다.

 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
PS C:\temp\pwshprj> gcm *Certi*

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Get-RDCertificate                                  2.0.0.0    RemoteDesktop
Function        New-RDCertificate                                  2.0.0.0    RemoteDesktop
Function        Set-RDCertificate                                  2.0.0.0    RemoteDesktop
Cmdlet          Add-CertificateEnrollmentPolicyServer              1.0.0.0    PKI
Cmdlet          Export-Certificate                                 1.0.0.0    PKI
Cmdlet          Export-PfxCertificate                              1.0.0.0    PKI
Cmdlet          Get-Certificate                                    1.0.0.0    PKI
Cmdlet          Get-CertificateAutoEnrollmentPolicy                1.0.0.0    PKI
Cmdlet          Get-CertificateEnrollmentPolicyServer              1.0.0.0    PKI
Cmdlet          Get-CertificateNotificationTask                    1.0.0.0    PKI
Cmdlet          Get-PfxCertificate                                 3.0.0.0    Microsoft.PowerShell.Security
Cmdlet          Import-Certificate                                 1.0.0.0    PKI
Cmdlet          Import-PfxCertificate                              1.0.0.0    PKI
Cmdlet          New-CertificateNotificationTask                    1.0.0.0    PKI
Cmdlet          New-SelfSignedCertificate                          1.0.0.0    PKI
Cmdlet          Remove-CertificateEnrollmentPolicyServer           1.0.0.0    PKI
Cmdlet          Remove-CertificateNotificationTask                 1.0.0.0    PKI
Cmdlet          Set-CertificateAutoEnrollmentPolicy                1.0.0.0    PKI
Cmdlet          Switch-Certificate                                 1.0.0.0    PKI
Cmdlet          Test-Certificate                                   1.0.0.0    PKI
Application     dmcertinst.exe                                     10.0.14... C:\Windows\system32\dmcertinst.exe

이중에 New-SelfSignedCertificate 라고 하는 명령어가 있습니다. 자 이제 이 명령어를 이용하여 스크립트를 서명해 봅시다. 전체 과정은 5과정입니다.

step 1. 코드서명을 위한 인증서 만들기

1
2
3
4
5
6
7
8
New-SelfSignedCertificate -CertStoreLocation cert:\currentuser\my `
-Subject "CN=Local Code Signing" `
-KeyAlgorithm RSA `
-KeyLength 2048 `
-Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" `
-KeyExportPolicy Exportable `
-KeyUsage DigitalSignature `
-Type CodeSigningCert
1
2
3
4
5
6
7
8
New-SelfSignedCertificate 
-Subject "CN=System Error,e=mymail@mail.com" `
-KeyAlgorithm sha256 `
-KeyLength 2018 `
-FriendlyName "My Cert" `
-KeyUsage DigitalSignature `
-KeyUsageProperty Sign `
-Type CodeSigningCert 

step 2. OS의 인증서 저장소의 개인 인증서 열기

만들어진 인증서는 OS에 저장됩니다. 리눅스라면 파일시스템으로 저장되는데, 경로는 리눅스 타입에 따라 다릅니다.

  • “/etc/ssl/certs/ca-certificates.crt”, // Debian/Ubuntu/Gentoo etc.
  • “/etc/pki/tls/certs/ca-bundle.crt”, // Fedora/RHEL 6
  • “/etc/ssl/ca-bundle.pem”, // OpenSUSE
  • “/etc/pki/tls/cacert.pem”, // OpenELEC
  • “/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem”, // CentOS/RHEL 7
  • “/etc/ssl/cert.pem”, // Alpine Linux
  • “/etc/ssl/certs”, // SLES10/SLES11, https://golang.org/issue/12139
  • “/system/etc/security/cacerts”, // Android
  • “/usr/local/share/certs”, // FreeBSD
  • “/etc/pki/tls/certs”, // Fedora/RHEL
  • “/etc/openssl/certs”, // NetBSD
  • “/var/ssl/certs”, // AIX

윈도우즈는 파일시스켐으로 관리하지는 않고 있습니다.

저장되었는 지 확인합니다. 확인하는 방법은 몇 가지가 있습니다.

  • certmgr 에서 개인 > 인증서 에서 확인 할 수 있습니다., GUI 입니다.
  • cmd에서 certutil -store My 로도 확인할 수 있습니다.
  • powershell로 확인하기, 파일시스템처럼 접근해서 확인할 수 있습니다.
     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
    
    PS Cert:\CurrentUser\My> New-SelfSignedCertificate -CertStoreLocation cert:\currentuser\my `
    >> -Subject "CN=Local Code Signing" `
    >> -KeyAlgorithm RSA `
    >> -KeyLength 2048 `
    >> -Provider "Microsoft Enhanced RSA and AES Cryptographic Provider" `
    >> -KeyExportPolicy Exportable `
    >> -KeyUsage DigitalSignature `
    >> -Type CodeSigningCert
    
    
    PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\my
    
    Thumbprint                                Subject
    ----------                                -------
    3F3EF4020A8F2FA478B46BFD4E555251D9CCC953  CN=Local Code Signing
    
    
    PS Cert:\CurrentUser\My> dir
    
    
    PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\My
    
    Thumbprint                                Subject
    ----------                                -------
    330E27CC6CD03143762062542EA8D99B12D9B711  CN=localhost
    3F3EF4020A8F2FA478B46BFD4E555251D9CCC953  CN=Local Code Signing    
    

step 3. 개인 인증서를 신뢰할 수 있는 타입으로 저장하기

개인 > 증명서 에 있는 CN=Local Code Signing 인증서를 다음의 두 장소에 복사해 넣습니다.

  • 신뢰하는 루트 인증기관 (영어 “Trusted Root Certification Authorities”)
  • 신뢰하는 발행처 (영어 “Trusted Publishers”)

p057_trusted_CA_and_Publisher.png

step 4. script 서명하기

서명할 때는 Set-AuthenticodeSignature 명령어를 사용합니다.

$cert = Get-ChildItem cert:\CurrentUser\My -CodeSigning
Set-AuthenticodeSignature .\test.ps1 $cert

또는

$cert = Get-ChildItem Cert:\CurrentUser\My -CodeSigningCert
Set-AuthenticodeSignature .\test.ps1 $cert -HashAlgorithm `
sha256 -TimestampServer "http://timestamp.digicert.com"

실행한 결과는 다음과 같습니다.

 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
PS Cert:\CurrentUser\My> Get-ChildItem cert:\CurrentUser\My -CodeSigning | fl


Subject      : CN=Local Code Signing
Issuer       : CN=Local Code Signing
Thumbprint   : 3F3EF4020A8F2FA478B46BFD4E555251D9CCC953
FriendlyName :
NotBefore    : 2020/09/26 12:39:43
NotAfter     : 2021/09/26 12:59:43
Extensions   : {System.Security.Cryptography.Oid, System.Security.Cryptography.Oid, System.Security.Cryptography.Oid}

PS C:\temp\pwshprj> dir


    ディレクトリ: C:\temp\pwshprj


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----       2020/09/21      8:53             75 README.md
-a----       2020/09/21     10:00            137 test.ps1


PS C:\temp\pwshprj> cat test.ps1
function myfunction  {
    param (
        [string]$text
    )

    [int]$test
    Write-Host "You wrote: $text ."


}


PS C:\temp\pwshprj> $cert = Get-ChildItem cert:\CurrentUser\My -CodeSigning
PS C:\temp\pwshprj> Set-AuthenticodeSignature .\test.ps1 $cert


    ディレクトリ: C:\temp\pwshprj


SignerCertificate                         Status                                 Path
-----------------                         ------                                 ----
3F3EF4020A8F2FA478B46BFD4E555251D9CCC953  Valid                                  test.ps1


PS C:\temp\pwshprj> cat .\test.ps1
function myfunction  {
    param (
        [string]$text
    )

    [int]$test
    Write-Host "You wrote: $text ."


}



# SIG # Begin signature block
# MIIFdgYJKoZIhvcNAQcCoIIFZzCCBWMCAQExCzAJBgUrDgMCGgUAMGkGCisGAQQB
# gjcCAQSgWzBZMDQGCisGAQQBgjcCAR4wJgIDAQAABBAfzDtgWUsITrck0sYpfvNR
# AgEAAgEAAgEAAgEAAgEAMCEwCQYFKw4DAhoFAAQUrvaKRFD1k7RjzD6eorUSZqxB
# OwagggMOMIIDCjCCAfKgAwIBAgIQMF3cntmzua9FjRfu4pf1iTANBgkqhkiG9w0B
# AQUFADAdMRswGQYDVQQDDBJMb2NhbCBDb2RlIFNpZ25pbmcwHhcNMjAwOTI2MDMz
# OTQzWhcNMjEwOTI2MDM1OTQzWjAdMRswGQYDVQQDDBJMb2NhbCBDb2RlIFNpZ25p
# bmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDS1QjZt13tSS+AVGw4
# HjBi+tLDfZJ7L0FDCa8RHKpdpF4v/FAa5uayiPs6zgxO1QFOTnhA5o24Duv7Ig6V
# wCSjezJZv9mfH4tcJ5LsRrR0wjbKTs8jNOjRU9P9v6Dv8PJLz8y2tR8ivxJBmnoz
# 3ty7LLEDWnUGdGC+7xr6Zs2D+UdRG1X5SJqw3TLe33WvYHK6r0GCNWymuWjUihHv
# TZzu4Mtf62722qBReP9QCRGhDTwxCSu0rS/LDgIEa6bc23MTjRxf7C3ZI+04zdBS
# iufOtWlPbNu7KUZZyT7jOBcOvhWCuqbaYDOsudFeGpjA+UXgRNkG1N1zRucVlsxC
# yo/RAgMBAAGjRjBEMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcD
# AzAdBgNVHQ4EFgQUmEqtya+uXUWAeG+NLjJ+5OeAwGwwDQYJKoZIhvcNAQEFBQAD
# ggEBAHzPIwDo9Bqc/KmfjfN1Gb+y8CaQ9YkHUS+V8G02jTWMWdskkIy/cLSWIJBq
# IZaNyvTAf3+Orb9fNszdkvo07AUjpUSJyUF6UfMnnRA/tWkp+ulhuTSA19B4SFVQ
# nYwiymetMutpTeXH3HvvzALktVCXb1SmrTEYIj4VISIEyUBLJ0HwgOZ+T6Cq3FMO
# XgGNjI1h8KFKev0zT1qntlPBNYlFQnbpkVz0YNhNyvfEt5SxpIWw/QUPzfXF3HwU
# 35DBwa3VWI4zKJW6/9wa1nLpppBvu+MfDPyBDmRwOQ68S1vsGeodiISu046McNLy
# yR/EvH4HkIAT/alUr4lS5I3Zi/QxggHSMIIBzgIBATAxMB0xGzAZBgNVBAMMEkxv
# Y2FsIENvZGUgU2lnbmluZwIQMF3cntmzua9FjRfu4pf1iTAJBgUrDgMCGgUAoHgw
# GAYKKwYBBAGCNwIBDDEKMAigAoAAoQKAADAZBgkqhkiG9w0BCQMxDAYKKwYBBAGC
# NwIBBDAcBgorBgEEAYI3AgELMQ4wDAYKKwYBBAGCNwIBFTAjBgkqhkiG9w0BCQQx
# FgQUUl40/IMyhS8sq7gVVEqV/S6Ib78wDQYJKoZIhvcNAQEBBQAEggEAxgytjnpU
# j2ETO9n6AmgqdkSXIOmvvWVWgDbzJw1uCjd//07U0Fss1TVgxOAosRGy3qhNTROs
# yZub/UUMqnSqYCjRmFytvLRHz2aQW9BE5c2LVY1ZYBiO1uWgx4Azt3I4BprAzLCd
# fiY4rLPWvLLqJbFUUWKccpGymHzwUtzbZaddFu7C1AutSv3ldSDwuDoFlOxvQr9l
# Pbd8eErp5CA20M4lh/U6WJyHlNDhZk43vXznDGbBtt++oM354ktf9cnK7IZMcvqW
# nTTG4U8sjH+6z5vn5YqfRN/xGkrxzEU4v6dYcZLy+AYa75KBL4NYB2KDyEJWfr8a
# W92b29DeXRk+pw==
# SIG # End signature block
PS C:\temp\pwshprj>

스크립트 파일이 아닌 경우는 정상적으로 작동하지 않습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
PS C:\temp\pwshprj> Set-AuthenticodeSignature .\README.md $cert -HashAlgorithm `
>> sha256 -TimestampServer "http://timestamp.digicert.com"


    ディレクトリ: C:\temp\pwshprj


SignerCertificate                         Status                                 Path
-----------------                         ------                                 ----
                                          UnknownError                           README.md

step 6. test

현재의 세션에서만 ExecutionPlicy를 변경하려면 다음의 명령을 사용합니다.

Set-ExecutionPolicy -ExecutionPolicy AllSigned -Scope Process

테스트해본 결과는 다음과 같습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
PS C:\temp\pwshprj> Set-ExecutionPolicy -ExecutionPolicy AllSigned -Scope Process

実行ポリシーの変更
実行ポリシーは信頼されていないスクリプトからの保護に役立ちます実行ポリシーを変更するとabout_Execution_Policies
のヘルプ トピック (http://go.microsoft.com/fwlink/?LinkID=135170)
で説明されているセキュリティ上の危険にさらされる可能性があります実行ポリシーを変更しますか?
[Y] はい(Y)  [A] すべて続行(A)  [N] いいえ(N)  [L] すべて無視(L)  [S] 中断(S)  [?] ヘルプ (既定値は "N"): Y
PS C:\temp\pwshprj> Get-ExecutionPolicy
AllSigned
PS C:\temp\pwshprj> Get-ExecutionPolicy -list

        Scope ExecutionPolicy
        ----- ---------------
MachinePolicy       Undefined
   UserPolicy       Undefined
      Process       AllSigned
  CurrentUser       Undefined
 LocalMachine    RemoteSigned

PS C:\temp\pwshprj> . .\test.ps1
PS C:\temp\pwshprj> myfunction hello
0
You wrote: hello .
PS C:\temp\pwshprj>

이상으로 스크립트를 서명해 보았습니다.

레퍼런스

공유하기

tkim
글쓴이
tkim
Software Engineer