Skip to content

Commit

Permalink
Optionally code-sign files.
Browse files Browse the repository at this point in the history
  • Loading branch information
fancycode committed Jul 20, 2015
1 parent 2047efe commit fe30d2a
Show file tree
Hide file tree
Showing 4 changed files with 324 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@

/.vagrant
/build_result
/codesign-certificate.spc
/codesign-key.pvk
/Vagrantfile
*.iso
8 changes: 8 additions & 0 deletions scripts/vagrant/040_package.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ if exist libde265-*.exe (
del /q libde265-*.exe > NUL
)

if exist "C:\vagrant\scripts\vagrant\sign_files.cmd" (
call "C:\vagrant\scripts\vagrant\sign_files.cmd" "C:\Users\vagrant\LAVFilters\bin_Win32"
call "C:\vagrant\scripts\vagrant\sign_files.cmd" "C:\Users\vagrant\LAVFilters\bin_x64"
)

"C:\Program Files (x86)\Inno Setup 5\ISCC.exe" LAVFilters.iss

set TODAY=
Expand All @@ -14,5 +19,8 @@ if not exist "C:\vagrant\build_result\%TODAY:~0,8%-%TODAY:~8,6%" (
mkdir C:\vagrant\build_result\%TODAY:~0,8%-%TODAY:~8,6%
)
copy /y libde265-*.exe C:\vagrant\build_result\%TODAY:~0,8%-%TODAY:~8,6% >NUL
if exist "C:\vagrant\scripts\vagrant\sign_files.cmd" (
call "C:\vagrant\scripts\vagrant\sign_files.cmd" "C:\vagrant\build_result\%TODAY:~0,8%-%TODAY:~8,6%"
)

echo Done, installer copied to "build_result\%TODAY:~0,8%-%TODAY:~8,6%"
82 changes: 82 additions & 0 deletions scripts/vagrant/sign_files.cmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
@echo off
setlocal
rem Determine root folder of script (without trailing backslash)
set ROOT=%~dp0
set ROOT=%ROOT:~0,-1%

set SOURCE=%1
if "%SOURCE%" == "" (
echo USAGE: %0 ^<path\to\files^>
exit /b 1
)

set CERTIFICATE_FILE=C:\vagrant\codesign-certificate.spc
set PRIVATEKEY_FILE=C:\vagrant\codesign-key.pvk
set TIMESTAMP_URL=http://timestamp.verisign.com/scripts/timstamp.dll

if not exist "%CERTIFICATE_FILE%" (
echo No certificate found at "%CERTIFICATE_FILE%", skipping signature.
exit /b 0
)
if not exist "%PRIVATEKEY_FILE%" (
echo No private key found at "%PRIVATEKEY_FILE%", skipping signature.
exit /b 0
)

set SIGNFILE=C:\Users\vagrant\signfile.exe
if not exist "%SIGNFILE%" (
echo Compiling signature tool
call "%VS120COMNTOOLS%\vsvars32.bat"
cl /nologo /Fe:"%SIGNFILE%" /MT "%ROOT%\signfile.cc" crypt32.lib
if not "%errorlevel%" == "0" (
exit /b %errorlevel%
)
)

set PLINK=C:\Users\vagrant\plink.exe
if not exist "%PLINK%" (
echo Fetching plink
PowerShell Invoke-WebRequest -Uri '"http://the.earth.li/~sgtatham/putty/latest/x86/plink.exe"' -OutFile "%PLINK%"
)

goto main

rem function :signfile filename
:signfile
echo yes | "%PLINK%" Administrator@localhost -pw vagrant "%SIGNFILE%" "%CERTIFICATE_FILE%" "%PRIVATEKEY_FILE%" "%~1" "%TIMESTAMP_URL%"
goto :eof

:signfolder
echo Sign folder contents "%~1"
if exist "%~1\*.exe" (
for /f "tokens=*" %%G in ('dir /b "%~1\*.exe"') do (
call :signfile "%~1\%%G"
)
)
if exist "%~1\*.dll" (
for /f "tokens=*" %%G in ('dir /b "%~1\*.dll"') do (
call :signfile "%~1\%%G"
)
)
if exist "%~1\*.ax" (
for /f "tokens=*" %%G in ('dir /b "%~1\*.ax"') do (
call :signfile "%~1\%%G"
)
)
goto :eof

:main

setlocal enableextensions
set ATTR=%~a1
set DIRATTR=%ATTR:~0,1%

if /I "%DIRATTR%" == "d" (
call :signfolder "%SOURCE%"
for /f "tokens=*" %%G in ('dir /b /s /a:d "%SOURCE%\*"') do (
call :signfolder "%%G"
)
) else (
call :signfile "%SOURCE%"
)

232 changes: 232 additions & 0 deletions scripts/vagrant/signfile.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/**
* Simple tool to (code-)sign a file using private key / certificate.
* Copyright (c) 2015 struktur AG
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/

#include <stdio.h>
#include <windows.h>
#include <wincrypt.h>

// API documentation available at
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa387733%28v=vs.85%29.aspx
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa904940%28v=vs.85%29.aspx

typedef struct _SIGNER_FILE_INFO {
DWORD cbSize;
LPCWSTR pwszFileName;
HANDLE hFile;
} SIGNER_FILE_INFO, *PSIGNER_FILE_INFO;

typedef struct _SIGNER_BLOB_INFO {
DWORD cbSize;
GUID *pGuidSubject;
DWORD cbBlob;
BYTE *pbBlob;
LPCWSTR pwszDisplayName;
} SIGNER_BLOB_INFO, *PSIGNER_BLOB_INFO;

typedef struct _SIGNER_SUBJECT_INFO {
DWORD cbSize;
DWORD *pdwIndex;
DWORD dwSubjectChoice;
union {
SIGNER_FILE_INFO *pSignerFileInfo;
SIGNER_BLOB_INFO *pSignerBlobInfo;
};
} SIGNER_SUBJECT_INFO, *PSIGNER_SUBJECT_INFO;

const DWORD SIGNER_SUBJECT_BLOB = 0x2; // The subject is a BLOB.
const DWORD SIGNER_SUBJECT_FILE = 0x1; // The subject is a file.

typedef struct _SIGNER_ATTR_AUTHCODE {
DWORD cbSize;
BOOL fCommercial;
BOOL fIndividual;
LPCWSTR pwszName;
LPCWSTR pwszInfo;
} SIGNER_ATTR_AUTHCODE, *PSIGNER_ATTR_AUTHCODE;

typedef struct _SIGNER_SIGNATURE_INFO {
DWORD cbSize;
ALG_ID algidHash;
DWORD dwAttrChoice;
union {
SIGNER_ATTR_AUTHCODE *pAttrAuthcode;
};
PCRYPT_ATTRIBUTES psAuthenticated;
PCRYPT_ATTRIBUTES psUnauthenticated;
} SIGNER_SIGNATURE_INFO, *PSIGNER_SIGNATURE_INFO;

const DWORD SIGNER_AUTHCODE_ATTR = 1; // The signature has Authenticode attributes.
const DWORD SIGNER_NO_ATTR = 0; // The signature does not have Authenticode attributes.

typedef struct _SIGNER_CERT_STORE_INFO {
DWORD cbSize;
PCCERT_CONTEXT pSigningCert;
DWORD dwCertPolicy;
HCERTSTORE hCertStore;
} SIGNER_CERT_STORE_INFO, *PSIGNER_CERT_STORE_INFO;

typedef struct _SIGNER_SPC_CHAIN_INFO {
DWORD cbSize;
LPCWSTR pwszSpcFile;
DWORD dwCertPolicy;
HCERTSTORE hCertStore;
} SIGNER_SPC_CHAIN_INFO, *PSIGNER_SPC_CHAIN_INFO;

typedef struct _SIGNER_CERT {
DWORD cbSize;
DWORD dwCertChoice;
union {
LPCWSTR pwszSpcFile;
SIGNER_CERT_STORE_INFO *pCertStoreInfo;
SIGNER_SPC_CHAIN_INFO *pSpcChainInfo;
};
HWND hwnd;
} SIGNER_CERT, *PSIGNER_CERT;

const DWORD SIGNER_CERT_SPC_FILE = 1; // The certificate is stored in an SPC file.
const DWORD SIGNER_CERT_STORE = 2; // The certificate is stored in a certificate store.
const DWORD SIGNER_CERT_SPC_CHAIN = 3; // The certificate is stored in an SPC file and is associated with a certificate chain.

typedef struct _SIGNER_PROVIDER_INFO {
DWORD cbSize;
LPCWSTR pwszProviderName;
DWORD dwProviderType;
DWORD dwKeySpec;
DWORD dwPvkChoice;
union {
LPWSTR pwszPvkFileName;
LPWSTR pwszKeyContainer;
};
} SIGNER_PROVIDER_INFO, *PSIGNER_PROVIDER_INFO;

const DWORD PVK_TYPE_FILE_NAME = 0x1; // The private key information is a file name.
const DWORD PVK_TYPE_KEYCONTAINER = 0x02; // The private key information is a key container.

typedef HRESULT (WINAPI *SignerSignFunc)(
SIGNER_SUBJECT_INFO *pSubjectInfo,
SIGNER_CERT *pSignerCert,
SIGNER_SIGNATURE_INFO *pSignatureInfo,
SIGNER_PROVIDER_INFO *pProviderInfo,
LPCWSTR pwszHttpTimeStamp,
PCRYPT_ATTRIBUTES psRequest,
LPVOID pSipData
);

typedef HRESULT (WINAPI *SignerTimeStampFunc)(
SIGNER_SUBJECT_INFO *pSubjectInfo,
LPCWSTR pwszHttpTimeStamp,
PCRYPT_ATTRIBUTES psRequest,
LPVOID pSipData
);

wchar_t *convertCharArrayToLPCWSTR(const char* charArray) {
size_t len = strlen(charArray);
wchar_t* wString = (wchar_t*) calloc(1, (1+len)*sizeof(wchar_t));
if (wString != NULL) {
MultiByteToWideChar(CP_ACP, 0, charArray, -1, wString, 4096);
}
return wString;
}

int main(int argc, char *argv[]) {
if (argc < 4) {
fprintf(stderr, "USAGE %s <certificate.spc> <privatekey.pvk> <filetosign.ext> [timestampurl]\n", argv[0]);
return 1;
}

int returncode = 1;
LPWSTR certificate = convertCharArrayToLPCWSTR(argv[1]);
LPWSTR privatekey = convertCharArrayToLPCWSTR(argv[2]);
LPWSTR signfile = convertCharArrayToLPCWSTR(argv[3]);
LPWSTR timestampUrl = NULL;
if (argc > 4) {
timestampUrl = convertCharArrayToLPCWSTR(argv[4]);
}
HMODULE module = NULL;

SIGNER_FILE_INFO fileinfo = { 0 };
fileinfo.cbSize = sizeof(SIGNER_FILE_INFO);
fileinfo.pwszFileName = signfile;

SIGNER_SUBJECT_INFO subjectInfo = { 0 };
DWORD dwIndex = 0;
subjectInfo.cbSize = sizeof(SIGNER_SUBJECT_INFO);
subjectInfo.pdwIndex = &dwIndex;
subjectInfo.dwSubjectChoice = SIGNER_SUBJECT_FILE;
subjectInfo.pSignerFileInfo = &fileinfo;

SIGNER_SIGNATURE_INFO signatureInfo = { 0 };
signatureInfo.cbSize = sizeof(SIGNER_SIGNATURE_INFO);
signatureInfo.algidHash = CALG_SHA1;
signatureInfo.dwAttrChoice = SIGNER_NO_ATTR;

SIGNER_CERT cert = { 0 };
cert.cbSize = sizeof(SIGNER_CERT);
cert.dwCertChoice = SIGNER_CERT_SPC_FILE;
cert.pwszSpcFile = certificate;

SIGNER_PROVIDER_INFO providerInfo = { 0 };
providerInfo.cbSize = sizeof(SIGNER_PROVIDER_INFO);
providerInfo.pwszProviderName = MS_ENHANCED_PROV_W;
providerInfo.dwProviderType = PROV_RSA_FULL;
providerInfo.dwKeySpec = 0;
providerInfo.dwPvkChoice = PVK_TYPE_FILE_NAME;
providerInfo.pwszPvkFileName = privatekey;

module = LoadLibrary("mssign32.dll");
if (module == NULL) {
fprintf(stderr, "Could not load mssign32.dll: 0x%.8x\n", GetLastError());
goto exit;
}

SignerSignFunc pSignerSign = (SignerSignFunc) GetProcAddress(module, "SignerSign");
SignerTimeStampFunc pSignerTimeStamp = (SignerTimeStampFunc) GetProcAddress(module, "SignerTimeStamp");
if (pSignerSign == NULL || pSignerTimeStamp == NULL) {
fprintf(stderr, "mssign32.dll doesn't export necessary functions\n");
goto exit;
}

fprintf(stdout, "Signing \"%S\"...\n", signfile);
DWORD res = pSignerSign(&subjectInfo, &cert, &signatureInfo, &providerInfo, NULL, NULL, NULL);
if (res != 0) {
fprintf(stderr, "Error while signing: 0x%.8x\n", GetLastError());
goto exit;
}

if (timestampUrl != NULL) {
fprintf(stdout, "Timestamping using \"%S\"...\n", timestampUrl);
res = pSignerTimeStamp(&subjectInfo, timestampUrl, NULL, NULL);
if (res != 0) {
fprintf(stderr, "Error while timestamping: 0x%.8x\n", GetLastError());
goto exit;
}
}
fprintf(stdout, "Done\n");
returncode = 0;

exit:
if (module != NULL) {
FreeLibrary(module);
}
free(timestampUrl);
free(signfile);
free(privatekey);
free(certificate);
return returncode;
}

0 comments on commit fe30d2a

Please sign in to comment.