jsign icon indicating copy to clipboard operation
jsign copied to clipboard

Pathname with spaces errors as if not quoted on Cygwin

Open drew-512 opened this issue 1 year ago • 7 comments

Hello again @ebourg -- many thanks for your efforts making jsign as an alternative to the pain known as signtool!

I seem to have come across an issue where jsign isn't processing quoted arguments properly? Importantly, this same exact script invokes jsign properly if instead of "Winter Wonders" it's a product name with no spaces.

This is the Cygwin .sh invocation:

"${THIS_DIR}/sign/jsign.cmd" --replace --storepass XXXXXX\
    --name "${TARGET_DESC}" --url "https://www.soundspectrum.com/" \
    --tsaurl "http://timestamp.sectigo.com" \
    --storetype YUBIKEY  --alias "X.509 Certificate for PIV Authentication" "${TARGET_FILE}"

And this is the output from set -x

+ '_DISTS/Winter Wonders/installer/sign/jsign.cmd' --replace --storepass XXXXXX--name 'Winter Wonders component' --url https://www.soundspectrum.com/ --tsaurl http://timestamp.sectigo.com --storetype YUBIKEY --alias 'X.509 Certificate for PIV Authentication' '_DISTS\Winter Wonders\installer\Winter Wonders\Arcade.dll'
'C:\Users\drew\soundspectrum.dev\_DISTS\Winter' is not recognized as an internal or external command,
operable program or batch file.

What you're seeing is a Cyu

drew-512 avatar Nov 25 '24 15:11 drew-512

many thanks for your efforts making jsign as an alternative to the pain known as signtool!

You're welcome :)

I seem to have come across an issue where jsign isn't processing quoted arguments properly?

Did you try escaping the spaces with \ ? You may also try using simple quotes instead of double quotes.

If it doesn't work you can also use a filelist file, that's a text file with the name of a file to sign on each line. The filelist file has to be prefixed with @ (this requires the latest development snapshot which can be downloaded from the GitHub Actions):

jsign --storetype YUBIKEY [...] @filelist.txt

Also, but that's unrelated to this issue, you can replace the YUBIKEY storetype with PIV, this one works natively with the Yubikey and doesn't require the PKCS#11 library to be installed.

ebourg avatar Nov 25 '24 17:11 ebourg

@drew-512 Did any of the suggestions work?

ebourg avatar Jan 15 '25 08:01 ebourg

Hi friend. By the time I encountered this and isolated jsign as the issue, I was worn down. I was not ready to edit build scripts because a tool was failing with properly quoted pathnames, so I switched to SmartCardTools ScSignTool which passes on a pin arg to signtool.

You should be able to reproduce this, no?

drew-512 avatar Jan 15 '25 13:01 drew-512

I'm unable to reproduce the issue. Do you think you could share a minimal script triggering the error?

ebourg avatar Jan 15 '25 14:01 ebourg

Ah, ok, will put that on the worklist.

drew-512 avatar Jan 24 '25 19:01 drew-512

Prolly best I can in short oder is paste the .sh script:

#!/bin/sh


# set -x # echos commands for debugging

TARGET_FILE="$1"
TARGET_DESC="$2"
THIS="$0"
THIS_DIR="$(dirname "$THIS")"
PWD=$(pwd)


echo "TARGET_FILE: $TARGET_FILE"
echo "TARGET_DESC: $TARGET_DESC"
echo "THIS:        $THIS"
echo "THIS_DIR:    $THIS_DIR"
echo "PWD:         $PWD"


#if on Cygwin, convert to Windows path
if [ -x "$(command -v cygpath)" ]; then  
    TARGET_FILE=$(cygpath -w "$TARGET_FILE")  # issue??
fi


# https://clarionhub.com/t/notes-on-signing-code-with-your-own-hardware-yubikey/6655
#
# may need to add C:\path\to\Installers\win\sign to PATH in Windows:
#     System Properties > Environment Variables > PATH 
#
"${THIS_DIR}/sign/scsigntool.exe" -pin 123456 sign /v \
    /sha1 ff130c13ad4216120fc3894d2fec569619e32655 \
    /fd SHA256 /d "${TARGET_DESC}"  \
    /du "https://www.soundspectrum.com/" /t "http://timestamp.sectigo.com" "${TARGET_FILE}"
    
exit 0


# jsign requires java installed, has been in production, is free, allows a pin to be specified, and auto-downloads a certchain (rather than requiring it via file. -- ACO 29MAY2024
#
# Use jsign jar from https://github.com/ebourg/jsign/tags or get jsign.nupkg (currently 6.0)
# Main: https://ebourg.github.io/jsign/
#
# november 2024: is jsign path parsing correctly?
#    https://github.com/ebourg/jsign/issues/263
#
"${THIS_DIR}/sign/jsign.cmd" --replace --storepass 123456 \
    --name "${TARGET_DESC}" --url "https://www.soundspectrum.com/" \
    --tsaurl "http://timestamp.sectigo.com" \
    --storetype YUBIKEY  --alias "X.509 Certificate for PIV Authentication" "${TARGET_FILE}"
#   --storetype PIV      --alias AUTHENTICATION                             "${TARGET_FILE}" # equivalent
exit 0


# Works but requires pin!!
"${THIS_DIR}/sign/signtool.exe" sign /v  /sha1 ff130c13ad8816120fc3892d2fec569619e32655  /fd SHA256 /d "${TARGET_DESC}" /du "https://www.soundspectrum.com/" /t "http://timestamp.sectigo.com" "${TARGET_FILE}"
exit 0

drew-512 avatar Jan 26 '25 19:01 drew-512

Did you try to replace $TARGET_FILE with $1 to see if cygpath is causing this issue?

ebourg avatar Jan 27 '25 08:01 ebourg

I'm unable to reproduce the issue as well, but there's definitely room for improvement in jsign.cmd.

@echo off
setlocal

@rem Add the YubiKey library path to the PATH environment variable
if exist "C:\Program Files\Yubico\Yubico PIV Tool\bin\" (
    set "PATH=%PATH%;C:\Program Files\Yubico\Yubico PIV Tool\bin"
)

java %JSIGN_OPTS% ^
     -Djava.net.useSystemProxies=true ^
     -Dbasename=jsign ^
-    -jar %~dp0\jsign-7.1.jar %*
+    -jar "%~dp0\jsign-7.1.jar" %*

... otherwise, jsign.cmd could cause the error:

Error: Unable to access jarfile C:\Users\drew\soundspectrum.dev\_DISTS\Winter

Since this utility seems to be paired with Chocolatey, I'm not sure if this even possible, but wanted to share.

tresf avatar Apr 24 '25 18:04 tresf

Appreciate your efforts gents.

Doing builds tomorrow and will revert to jsign and see if this is the issue (seems likely since I invoke jsign.cmd explicitly). It's always the dumb stuff, right? I refuse to go back to C++ work because I was dying inside from all the foot guns.

drew-512 avatar Apr 24 '25 19:04 drew-512

@tresf Good catch, thank you. Do you want to contribute a PR for jsign.cmd?

ebourg avatar Apr 24 '25 22:04 ebourg

@tresf Good catch, thank you. Do you want to contribute a PR for jsign.cmd?

Sure. I dug into this more because I couldn't for the life of me understand how it's been working for years without complaints...

Since this utility seems to be paired with Chocolatey, I'm not sure if this even possible, but wanted to share.

It turns out that Chocolatey coincidentally uses a path of C:\ProgramData\chocolatey\lib\jsign\tools, which is why this works. (Choco even wraps it in jsign.exe, which makes this rube-goldberg experiment even stranger to a casual onlooker).

This means that whitespaces should only break in edge-cases when someone installs Chocolatey to a different location, or in the OP's case, when jsign.cmd is used as a standalone helper in a directory with spaces.

I tested this using PowerShell, by relocating chocolatey to "test folder":

PS ~\Desktop\test folder\chocolatey\bin> .\jsign.exe --help
Error: Unable to access jarfile ~\Desktop\test

.. note that this still conflicts with the OP's error received through Cygwin. I tested through MSYS2, but it failed with the exact same error as PowerShell...

Image

I'll submit a PR to patch the .jar handling...

tresf avatar Apr 25 '25 15:04 tresf

this still conflicts with the OP's error received through Cygwin.

'C:\Users\drew\soundspectrum.dev\_DISTS\Winter' is not recognized as an internal or external command,
operable program or batch file.

@drew-512 I think I see what's going on here... I was scratching my head wondering why this would cause problem and remembered this handy-dandy utility:

https://cygwin.com/cygwin-ug-net/cygpath.html

In short, I think your error is unrelated to jsign and it's because you're using Windows paths in a POSIX script. You should be able to sanitize the C:\yadda\yadda into /cygdrive/c/yadda/yadda via something like:

# Convert to Unix-style path
THIS_DIR="$(cygpath -u "${THIS_DIR}")"

Note, since (I assume) the Java you're using is not POSIX-aware, I'd recommend that you do the opposite for any parameters and sanitize them to Windows paths (note -w instead of -u).

# Convert to Windows-style path
TARGET_FILE="$(cygpath -w "${TARGET_FILE}")"

(This code is untested)

tresf avatar Apr 25 '25 15:04 tresf

Hi gentlemen, picking this back up with jsign 7.4.

TLDR; happy to report that I can no longer repro issue (when spaces present in path) when invoking the jsign jar from (cygwin) bash explicitly:

#!/bin/sh

TARGET_FILE="$1"
TARGET_DESC="$2"
THIS="$0"
THIS_DIR="$(dirname "$THIS")"
PWD=$(pwd)

TOKEN_PIN="XXXXXX"

#if on Cygwin, convert to Windows path
if [ -x "$(command -v cygpath)" ]; then
    TARGET_FILE=$(cygpath -w "$TARGET_FILE")
fi

java    -Djava.net.useSystemProxies=true \
        -Dbasename=jsign \
        -Dlog4j2.loggerContextFactory=net.jsign.log4j.simple.SimpleLoggerContextFactory \
        -jar "${THIS_DIR}/sign/jsign-7.4.jar" \
        --replace --storepass "$TOKEN_PIN"  \
        --name "${TARGET_DESC}" --url "https://www.soundspectrum.com/" \
        --tsaurl "http://timestamp.sectigo.com" \
        --alg SHA-256   \
        --storetype ETOKEN  \
        "${TARGET_FILE}"
        

console output (note spaces in paths)

+ PWD=/home/drew/soundspectrum.dev
+ echo 'TARGET_FILE: _DISTS/Winter Wonders/installer/Winter Wonders//Arcade.dll'
TARGET_FILE: _DISTS/Winter Wonders/installer/Winter Wonders//Arcade.dll
+ echo 'TARGET_DESC: Winter Wonders component'
TARGET_DESC: Winter Wonders component
+ echo 'THIS:        _DISTS/Winter Wonders/installer/signtool.sh'
THIS:        _DISTS/Winter Wonders/installer/signtool.sh
+ echo 'THIS_DIR:    _DISTS/Winter Wonders/installer'
THIS_DIR:    _DISTS/Winter Wonders/installer
+ echo 'PWD:         /home/drew/soundspectrum.dev'
PWD:         /home/drew/soundspectrum.dev
+ TOKEN_PIN='XXXXXX'
++ command -v cygpath
+ '[' -x /usr/bin/cygpath ']'
++ cygpath -w '_DISTS/Winter Wonders/installer/Winter Wonders//Arcade.dll'
+ TARGET_FILE='_DISTS\Winter Wonders\installer\Winter Wonders\Arcade.dll'
+ java -Djava.net.useSystemProxies=true -Dbasename=jsign -Dlog4j2.loggerContextFactory=net.jsign.log4j.simple.SimpleLoggerContextFactory -jar '_DISTS/Winter Wonders/installer/sign/jsign-7.4.jar' --replace --storepass 'XXXXXX' --name 'Winter Wonders component' --url https://www.soundspectrum.com/ --tsaurl http://timestamp.sectigo.com --alg SHA-256 --storetype ETOKEN '_DISTS\Winter Wonders\installer\Winter Wonders\Arcade.dll'
Adding Authenticode signature to _DISTS\Winter Wonders\installer\Winter Wonders\Arcade.dll

Recommend close this issue as resolved or non-issue.

Thanks again for the investigation.

drew-512 avatar Nov 26 '25 19:11 drew-512

@drew-512 Thank you for the feedback! Closing the issue now.

ebourg avatar Nov 26 '25 21:11 ebourg