성태의 닷넷 이야기
홈 주인
모아 놓은 자료
프로그래밍
질문/답변
사용자 관리
사용자
메뉴
아티클
외부 아티클
유용한 코드
온라인 기능
MathJax 입력기
최근 덧글
[정성태] How can I tell whether two programs...
[정성태] The case of the fail-fast crashes c...
[정성태] Creating Docker multi-arch images f...
[정성태] BinaryFormatter removed from .NET 9...
[정성태] Extending the Windows Shell Progres...
[우광현] 와..... 범위를 잡았으니 클라이언트가 해당 범위를 확인해본다...
[정성태] 딱히, 그것 이상으로 더 설명할 내용이 없습니다. 동적 포...
[정성태] If Windows 3.11 required a 32-bit p...
[정성태] What is a hard error, and what make...
[괴물신인] 질문작성자인데 이 글을 이제봤네요 ㄷㄷ 이 글처럼 타입별로 인...
글쓰기
제목
이름
암호
전자우편
HTML
홈페이지
유형
제니퍼 .NET
닷넷
COM 개체 관련
스크립트
VC++
VS.NET IDE
Windows
Team Foundation Server
디버깅 기술
오류 유형
개발 환경 구성
웹
기타
Linux
Java
DDK
Math
Phone
Graphics
사물인터넷
부모글 보이기/감추기
내용
<div style='display: inline'> <h1 style='font-family: Malgun Gothic, Consolas; font-size: 20pt; color: #006699; text-align: center; font-weight: bold'>"Microsoft Visual Studio Installer Projects" 프로젝트로 EXE 서명 및 MSI 파일 서명 방법</h1> <p> 비주얼 스튜디오 2019에는 정식 Setup 프로젝트가 없기 때문에 다음의 확장을 내려받아 설치합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > Microsoft Visual Studio Installer Projects ; <a target='tab' href='https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects'>https://marketplace.visualstudio.com/items?itemName=VisualStudioClient.MicrosoftVisualStudio2017InstallerProjects</a> </pre> <br /> 그다음, 예제로 "ConsoleApp1" 프로젝트와 "Setup1" 프로젝트를 생성합니다.<br /> <br /> <img onclick='toggle_img(this)' class='imgView' alt='sign_in_msi_1.png' src='/SysWebRes/bbs/sign_in_msi_1.png' /><br /> <br /> 당연히, "Setup1" 프로젝트에는 "ConsoleApp1" 프로젝트의 결과물이 포함되어야 하므로 위의 화면에서 "File Ssytem on Target Machine" / "Application Folder" 노드를 마우스 우 클릭해 "Add" / "Project Output..." 메뉴로 다음과 같이 "Add Project Output Group" 창을 띄우고,<br /> <br /> <img alt='sign_in_msi_2.png' src='/SysWebRes/bbs/sign_in_msi_2.png' /><br /> <br /> "Project:"에는 "ConsoleApp1", 그 하단에는 "Primary output"을 선택해 "OK"를 눌러 줍니다. 이제 "Setup1" 프로젝트를 빌드하면 setup1.msi 파일이 생성됩니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 자, 그런데 우리가 원하는 것은 인증서로 서명한,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ActiveX 서명 과정 자동화 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/327'>http://www.sysnet.pe.kr/2/0/327</a> </pre> <br /> exe 파일이 setup에 포함되는 것입니다. 이를 위한 사전 작업으로 test 용 pfx 파일을 하나 만들 텐데요.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > 윈도우에서 (테스트) 인증서 파일 만드는 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/12013'>http://www.sysnet.pe.kr/2/0/12013</a> </pre> <br /> "Developer Command Prompt for VS 2019" 명령행 창을 띄워 다음과 같이 2개의 명령어를 실행해 주면 (개인키를 담은) test.pfx 파일이 생성됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> <span style='color: blue; font-weight: bold'>makecert -n "CN=test_cert" -r -sv mycert.pvk mycert.cer</span> Succeeded c:\temp> <span style='color: blue; font-weight: bold'>pvk2pfx.exe -pvk mycert.pvk -spc mycert.cer -pfx mycert.pfx -po test</span> </pre> <br /> test.pfx 파일을 이용해 서명할 것이므로 이걸 솔루션 폴더에 복사해 줍니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 인증서도 구했으니, 이제 msi 파일과 exe 파일에 대해 서명하는 작업만 추가하면 됩니다. 우선 msi 파일 먼저 해볼 텐데요, 간단하게 Setup 프로젝트의 속성 창에,<br /> <br /> <img alt='sign_in_msi_3.png' src='/SysWebRes/bbs/sign_in_msi_3.png' /><br /> <br /> 보는 바와 같이 "PostBuildEvent"로 다음의 명령어를 등록합니다.<br /> <br /> <div style='BACKGROUND-COLOR: #ccffcc; padding: 10px 10px 5px 10px; MARGIN: 0px 10px 10px 10px; FONT-FAMILY: Malgun Gothic, Consolas, Verdana; COLOR: #005555'> "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\signtool.exe" sign /f <span class="tex2jax_ignore">$</span>(ProjectDir)..\mycert.pfx /p test /fd sha256 /v <span class="tex2jax_ignore">$</span>(BuiltOuputPath) </div><br /> <br /> 위의 명령에서 "signtool.exe"의 경로는 각자 환경에 따라 맞춰줘야 하고, pfx 파일도 다른 위치에 복사했다면 그 경로를 설정하면 됩니다. 이렇게 하고 빌드하면 Setup1.msi 파일이 정상적으로 서명된 것을 확인할 수 있습니다.<br /> <br /> <hr style='width: 50%' /><br /> <br /> 마지막으로 남은 작업이, 내부에 포함된 EXE 파일에 대한 서명입니다. 이게 좀 헷갈렸는데요. 일단, ConsoleApp1 프로젝트의 속성 창을 통해 "Build Events"의 "Post-build event command line:"에 다음의 내용을 등록합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\signtool.exe" sign /f <span class="tex2jax_ignore">$</span>(SolutionDir)mycert.pfx /p test /fd sha256 /v <span class="tex2jax_ignore">$</span>(TargetPath) </pre> <br /> 또는, csproj에 build task로,<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ASP.NET Web Application 프로젝트의 FileSystem 배포(Publish) 시 Before/After Task 설정 방법 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/11519'>http://www.sysnet.pe.kr/2/0/11519</a> </pre> <br /> 다음과 같이 등록해도 됩니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> ...[생략]... <span style='color: blue; font-weight: bold'><Target Name="AfterBuild"> <Exec WorkingDirectory="<span class="tex2jax_ignore">$</span>(WorkgroupDir)" Command="&quot;C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\signtool.exe&quot; sign /f <span class="tex2jax_ignore">$</span>(SolutionDir)mycert.pfx /p test /fd sha256 /v <span class="tex2jax_ignore">$</span>(TargetPath) " /> </Target></span> ...[생략]... </Project> </pre> <br /> 그런데, 위와 같이 설정하고 Setup1.msi로 설치해 보면 서명이 안 된 ConsoleApp1.exe가 출력됩니다. 이유가 좀 황당한데요, 우리가 서명했던 파일인 $(TargetPath)가 가리키는 경로는 /bin/Debug/ConsoleApp1.exe인 반면, Setup 프로젝트의 "Primary Output"은 "/obj/Debug/ConsoleApp1.exe"이기 때문입니다. <br /> <br /> <img alt='sign_in_msi_4.png' src='/SysWebRes/bbs/sign_in_msi_4.png' /><br /> <br /> 따라서, 다음과 같은 식으로 대상 출력 파일에 대한 경로를 조정(/bin/Debug ==> /obj/Debug)해야 합니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ["Post-build event command line:"에 설정한 경우] "C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\signtool.exe" sign /f <span class="tex2jax_ignore">$</span>(SolutionDir)mycert.pfx /p test /fd sha256 /v <span style='color: blue; font-weight: bold'><span class="tex2jax_ignore">$</span>(ProjectDir)obj\<span class="tex2jax_ignore">$</span>(ConfigurationName)\<span class="tex2jax_ignore">$</span>(TargetFileName)</span> </pre> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > ["csproj"의 Task로 설정한 경우] <Target Name="AfterBuild"> <Exec WorkingDirectory="<span class="tex2jax_ignore">$</span>(WorkgroupDir)" Command="&quot;C:\Program Files (x86)\Windows Kits\10\bin\10.0.18362.0\x64\signtool.exe&quot; sign /f &quot;<span class="tex2jax_ignore">$</span>(SolutionDir)mycert.pfx&quot; /p test /fd sha256 /v &quot;<span class="tex2jax_ignore">$</span>(ProjectDir)obj\<span class="tex2jax_ignore">$</span>(ConfigurationName)\<span class="tex2jax_ignore">$</span>(TargetFileName)&quot;" /> </Target> </pre> <br /> 끝입니다. 이제 Setup1 프로젝트를 빌드하면 msi 파일 및 그 내부에 포함된 ConsoleApp1.exe 파일도 정상적으로 서명이 된 걸 확인할 수 있습니다.<br /> <br /> (<a target='tab' href='https://www.sysnet.pe.kr/bbs/DownloadAttachment.aspx?fid=1511&boardid=331301885'>첨부 파일은 이 글에서 설명한 예제 프로젝트를 포함</a>합니다.)<br /> <br /> <hr style='width: 50%' /><br /> <br /> <a name='as_opt'></a> 참고로, 서명 시 다음과 같은 오류가 발생한다면?<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > c:\temp> signtool.exe sign /f mycert.pfx /p test /as /fd sha256 /v "C:\...[생략]...\Setup1.msi" The following certificate was selected: Issued to: test_cert Issued by: test_cert Expires: Sun Jan 01 08:59:59 2040 SHA1 hash: 1010E631A2FB3AFD7FBD1F819EC0FD5F2D3CF66C Done Adding Additional Store <span style='color: blue; font-weight: bold'>SignTool Error: Multiple signature support is not implemented for this filetype.</span> SignTool Error: An error occurred while attempting to sign: C:\...[생략]...\Setup1.msi Number of files successfully Signed: 0 Number of warnings: 0 Number of errors: 1 </pre> <br /> 이 오류의 원인은 "<a target='tab' href='https://learn.microsoft.com/ko-kr/dotnet/framework/tools/signtool-exe'>/as</a>" 옵션 때문입니다. 이것은 다중 서명할 때 사용하는 것으로써, 대상 파일(위의 예에서는 Setup1.msi)이 이미 서명되어 있어야 한다는 조건을 가집니다. (<span style='color: blue; font-weight: bold'>업데이트</span>: 2020-12-04 - 최신 signtool.exe에서는 이러한 제약이 없습니다.) 이에 대해서는 다음의 글을 참고하시고.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > signtool.exe의 다중 서명 기능 ; <a target='tab' href='http://www.sysnet.pe.kr/2/0/10875'>http://www.sysnet.pe.kr/2/0/10875</a> </pre> <br /> 한 가지 더 팁을 드리면, msi에 포함된 파일들을 확인하기 위해 직접 설치해 보는 것도 좋겠지만 <a target='tab' href='https://www.sysnet.pe.kr/2/0/1216#3122'>다음과 같이 명령어를 입력하면 msi 파일로부터 지정된 TARGETDIR에 압축을 해제</a>하므로 더 빠르게 확인 작업을 할 수 있을 것입니다.<br /> <br /> <pre style='margin: 10px 0px 10px 10px; padding: 10px 0px 10px 10px; background-color: #fbedbb; overflow: auto; font-family: Consolas, Verdana;' > <a target='tab' href='https://learn.microsoft.com/en-us/windows/win32/msi/command-line-options'>msiexec</a> /a "C:\...[생략]...\Setup1.msi" TARGETDIR=c:\temp /qb </pre> </p><br /> <br /><hr /><span style='color: Maroon'>[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]</span> </div>
첨부파일
스팸 방지용 인증 번호
4995
(왼쪽의 숫자를 입력해야 합니다.)