Skip to content

Instantly share code, notes, and snippets.

@darianmiller
Last active January 19, 2022 16:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save darianmiller/9de8aeb1979ef2eba9ea6069c669bca1 to your computer and use it in GitHub Desktop.
Save darianmiller/9de8aeb1979ef2eba9ea6069c669bca1 to your computer and use it in GitHub Desktop.
Setup code signing git commits on Windows using GPG
echo Use GnuPG on Windows for Code Signing git commits
@echo off
SETLOCAL
rem useful if running batch file from Explorer with hard-coded passphrase
rem cd /d %~dp0
cls
echo SetupSignedCommits.bat
echo https://gist.github.com/darianmiller/9de8aeb1979ef2eba9ea6069c669bca1
echo Created December 5, 2021
echo Related blog article: https://www.ideasawakened.com/post/configure-git-for-signed-commits-on-windows-using-gpg
echo.
echo Author: Darian Miller
echo https://github.com/darianmiller
echo https://www.linkedin.com/in/darianm/
echo.
echo This batch file will attempt to:
echo A) Optionally, run GPG to create a new keypair (RSA 4096-bit key length) for signing purposes
echo Run once to create keypair and then run again in different directory to configure other local repos
echo Alternatively, run once to create keypair and set the Global git config for all your local repos
echo B) Optionally, navigate to GitHub or GitLab so you can paste your public key into their web interface
echo Will also launch notepad containing your exported Public Key cert
echo C) Optionally, configure your git config on your machine
echo This sets your git user info and enables code signing with your new private key on each commit
echo Settings can be configured "Global" for all repositories or "Local" for the current repository
echo NOTE: If updating LOCAL settings, ensure you run this batch file within a repository workspace folder
echo D) Optionally, extend the GPG agent TTL setting
echo Cached passwords used by the GPG agent expire after 10 minutes of inactivity and cached for a max of 2 hours
echo For ease of use, you can extend this to 1-year to prevent having to repeatedly re-input your passphrase
echo.
echo Directions before use:
echo 1. Customize your user information and certificate parameters within this batch file
echo 2. Optionally verify paths to git.exe and gpg.exe (default Git for Windows installs should work as-is)
echo 3. Comment out or delete the next EXIT /B line and save your changes when ready
echo 4. At a command prompt within a git workspace run: SetupSignedCommits.bat your-secret-passphrase-here
EXIT /B
echo.
REM ----------------------
REM 1. CUSTOMIZE YOUR INFO
REM ----------------------
set FirstName=John
set LastName=Smith
set EmailAddress=johnsmith@yourhost.com
set CertComment=For signing Git commits
set CertExpires=0
rem Note: set CertExpires = 0 for no expiration or set to specific number of seconds (or optionally use days/weeks/months/years designator)
rem #d= days, #w = weeks, #m = months, #y = years. Example: 180 means the cert will expire in 180 seconds, 1y means 1 year
rem Assume passwphrase is first parameter
IF ["%~1"]==[""] (
echo.
echo Usage: SetupSignedCommits.bat passphrase
echo.
echo Please enter your passphrase
EXIT /B
)
rem If desired, remove the IF empty check block above and hard-code password here
rem Also note: passphrase is only used when creating new keypair
set Passphrase=%1
REM ----------------
REM 2. VERIFY PATHS
REM ----------------
rem if you have a custom install, set default locations manually. If git/gpg is in the system PATH, simply remove the path designation.
rem Download and install if missing: https://gitforwindows.org/
rem You can test at a command prompt by typing in the path configured here with a version parameter:
rem "%PROGRAMFILES%\Git\usr\bin\gpg.exe" --version
rem "%PROGRAMFILES%\Git\bin\git.exe" --version
SET GPGCommand="%PROGRAMFILES%\Git\usr\bin\gpg.exe"
if NOT EXIST %GPGCommand% (
echo Could not find gpg.exe, terminating
exit /b
)
SET GITCommand="%PROGRAMFILES%\Git\bin\git.exe"
if NOT EXIST %GITCommand% (
echo Could not find git.exe, terminating
exit /b
)
REM -------------------------------------
REM A. OPTIONALLY GENERATE A NEW KEYPAIR
REM -------------------------------------
CHOICE /C:YN /M "Create a new keypair for %EmailAddress%?"
IF ERRORLEVEL = 2 GOTO NavigateOption
%GPGCommand% --batch --pinentry-mode=loopback --passphrase "%Passphrase%" --quick-generate-key "%FirstName% %LastName% (%CertComment%) <%EmailAddress%>" rsa4096 sign %CertExpires%
REM -----------------------
REM B. OPTIONALLY NAVIGATE
REM -----------------------
:NavigateOption
CHOICE /N /C:HLO /M "Adding new Public Key to GitHub, GitLab, or Other? [Enter H, L, or O]: "
IF ERRORLEVEL == 3 GOTO SkipPublicKeyExport
IF ERRORLEVEL == 2 GOTO GitLab
IF ERRORLEVEL == 1 GOTO GitHub
GOTO SkipPublicKeyExport
:GitHub
rem Auto-navigate to github add GPG key page - Sign on to github as needed and then paste the public key and hit the Add gpg key button
start https://github.com/settings/gpg/new
rem Consider enabling vigilant mode
rem start https://github.com/settings/keys
GOTO ExportPublicKey
:GitLab
start https://gitlab.com/-/profile/gpg_keys
GOTO ExportPublicKey
:ExportPublicKey
set TempPKFileName=%TEMP%\MyNewPublicKey_%RANDOM%.txt
%GPGCommand% -ao %TempPKFileName% --export %EmailAddress%
start notepad.exe %TempPKFileName%
echo.
echo Copy your PUBLIC KEY now shown in Notepad and paste into the website to add a new GPG key to your account.
echo If this temp file is empty, upgrade your old version of GPG by installing the latest Git for Windows version
echo.
rem pause, wait to delete temp file export
pause
del %TempPKFileName%
:SkipPublicKeyExport
REM ----------------------------
REM C. OPTIONALLY CONFIGURE GIT
REM ----------------------------
CHOICE /N /C:GLS /M "Configure Global, Local, or Skip updating your Git config? [Enter G, L, or S]: "
IF ERRORLEVEL == 3 GOTO ConfigureGitFinished
IF ERRORLEVEL == 2 GOTO ConfigureLocalGit
IF ERRORLEVEL == 1 GOTO ConfigureGlobalGit
GOTO ConfigureGitFinished
:ConfigureGlobalGit
SET GITScope=--global
GOTO ConfigureGit
:ConfigureLocalGit
SET GITScope=--local
GOTO ConfigureGit
:ConfigureGit
%GITCommand% config %GITScope% user.name "%FirstName% %LastName%"
%GITCommand% config %GITScope% user.email %EmailAddress%
rem tell Git where to find GPG so it can sign commits
%GITCommand% config %GITScope% gpg.program %GPGCommand%
rem ask Git to sign all commits
%GITCommand% config %GITScope% commit.gpgsign true
rem Export the public key id to put into Git's config
rem Example output for the command: gpg --with-colons --list-keys %EmailAddress%'
rem tru:o:1:1638593381:1:3:1:5
rem pub:u:4096:1:8F660347585C99DA:1638593497:1654145497::u:::scSC::::::23::0:
rem fpr:::::::::07024D220A0BE54695F3A4808F660347585C99DA:
rem uid:u::::1638593497::DAF7992F9D19CC7B0B084F559DAAB09FBA90CA47::John Smith <johnsmith@null.com>::::::::::0:
rem Lets grab the third line of text which contains key signature
set "linethree="
for /F "skip=2 delims=" %%i in ('"%GPGCommand%" --with-colons --list-keys %EmailAddress%') do set "linethree=%%i"&GOTO DoneParsingKeyList
:DoneParsingKeyList
rem now extract the 160-bit, 40 hex character fingerprint 07024D220A0BE54695F3A4808F660347585C99DA from the third line of text fpr:::::::::07024D220A0BE54695F3A4808F660347585C99DA:
set keysignature=%linethree:~12,40%
rem configure Git to use the key just created
%GITCommand% config %GITScope% user.signingkey %keysignature%
rem view Global git settings if desired:
rem notepad "%USERPROFILE%\.gitconfig"
GOTO ConfigureGitFinished
:ConfigureGitFinished
REM -------------------------
REM D. OPTIONALLY EXTEND TTL
REM -------------------------
rem don't change existing settings if any found
SET AgentConfigFile="%USERPROFILE%\.gnupg\gpg-agent.conf"
IF NOT EXIST %AgentConfigFile% (
rem by default you will be asked to re-input your password after 10 minutes of inactivity, or at least every 2 hours... extend this as desired
CHOICE /C:YN /M "Extend default gpg-agent timeout? "
IF ERRORLEVEL == 2 GOTO AgentFinished
IF ERRORLEVEL == 1 GOTO ConfigureAgent
GOTO AgentFinished
)
:ConfigureAgent
rem default-cache-ttl max age in seconds of cached passphrase (timer is reset on each use) Default is 600 seconds
rem max-cache-ttl max age in seconds of cached passphrase regardless of use (force re-entry of passhprase on next use) Default is 7200 seconds
rem https://www.gnupg.org/documentation/manuals/gnupg/Agent-Options.html
(
echo default-cache-ttl 31536000
echo max-cache-ttl 31536000
) > %AgentConfigFile%
rem to view current settings:
rem gpgconf --list-options gpg-agent
rem
rem technically, should reload the agent if it's running so it gets new config values:
rem gpgconf.exe --reload gpg-agent
:AgentFinished
REM -------------
REM E. ALL DONE!
REM -------------
rem for verifying current list of keys found in the ".gnupg" folder in your user homepath
echo.
echo Current GPG keys for %EmailAddress%:
%GPGCommand% --list-keys %EmailAddress%
rem Useful for testing purposes - delete new keyring after creating it
rem pause
rem %GPGCommand% --delete-secret-keys %EmailAddress%
rem %GPGCommand% --delete-key %EmailAddress%
rem for more info:
rem gpg commands https://www.gnupg.org/documentation/manuals/gnupg/Operational-GPG-Commands.html
rem GitHub Vigilant mode changelog: https://github.blog/changelog/2021-04-28-flag-unsigned-commits-with-vigilant-mode/
rem GitHub help page: https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification
rem GitLab help page: https://docs.gitlab.com/ee/user/project/repository/gpg_signed_commits/index.html
rem GitHub desktop currently does not support signing: https://docs.github.com/en/authentication/managing-commit-signature-verification/signing-tags
rem Azure DevOps currently not supported in display: https://github.com/MicrosoftDocs/azure-devops-docs/issues/1381 also https://developercommunity.visualstudio.com/t/can-we-have-signed-commits/486953
echo Process complete!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment