ebourg / jsign

Java implementation of Microsoft Authenticode for signing Windows executables, installers & scripts
https://ebourg.github.io/jsign
Apache License 2.0
250 stars 107 forks source link

Signing fails on files/folders with extended Unicode characters #133

Closed kenlasko closed 1 year ago

kenlasko commented 1 year ago

I have an application that resides in a Debian-based Docker container that creates folders and PowerShell scripts that sometimes have extended Unicode characters in the file/folder names (as well as within the contents of said PS1 script). If the file and folder names both contain basic ASCII characters, I am able to successfully add an Authenticode signature via JSign. This works even when the contents of the PS1 file has extended Unicode characters in it. The file is encoded as UTF-8. Here's an example:

jsign --certfile /app/kl_codesign.spc --keyfile /app/kl_codesign.pvk --keypass SuperPassword --tsaurl http://timestamp.digicert.com --replace --encoding ISO-8859-1 Shkoder.ps1

If the parent foldername contains extended Unicode characters (/app/output/Shkodër in the below example), signing fails with the following error (EVEN WHEN RUN FROM WITHIN THE FOLDER):

jsign: Couldn't open the file Shkoder.ps1
java.nio.file.NoSuchFileException: AL-Shkoder-MSTeams.ps1
        at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
        at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
        at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
        at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:219)
        at java.base/java.nio.file.Files.newByteChannel(Files.java:371)
        at java.base/java.nio.file.Files.newByteChannel(Files.java:422)
        at net.jsign.pe.PEFile.<init>(PEFile.java:115)
        at net.jsign.pe.PEFile.isPEFile(PEFile.java:96)
        at net.jsign.Signable.of(Signable.java:108)
        at net.jsign.SignerHelper.sign(SignerHelper.java:533)
        at net.jsign.JsignCLI.execute(JsignCLI.java:117)
        at net.jsign.JsignCLI.main(JsignCLI.java:40)

If the filename includes extended Unicode characters, the "ls" command shows the filename to be Shkod'$'\303\253''r.ps1. Using that filename in the command line results in the following error:

jsign: The file Shkod'$'\303\253''r.ps1 couldn't be found

This is all running on a Raspberry Pi 4 My container is running Debian GNU/Linux 10 (buster) My host OS is running Debian GNU/Linux 11 (bullseye)

ebourg commented 1 year ago

Thank you for reporting this issue, what version of Java did you use? Does it also fail outside of the container?

kenlasko commented 1 year ago

I used apt install to install the JSign .deb package inside my container and it auto-installed all required packages: openjdk version "11.0.16" 2022-07-19 OpenJDK Runtime Environment (build 11.0.16+8-post-Debian-1deb10u1) OpenJDK 64-Bit Server VM (build 11.0.16+8-post-Debian-1deb10u1, mixed mode)

I haven't tried outside the container, as I try to keep a clean environment outside of my Docker containers.

ebourg commented 1 year ago

I haven't been able to reproduce the issue on Debian. Do you think you could post a Dockerfile reproducing the issue?

kenlasko commented 1 year ago

Sure thing. This is running on a RPi4 running latest 64-bit version of Bullseye

FROM mono:slim
WORKDIR /app
COPY ./config/jsign_4.1_all.deb ./
RUN apt update &&\
    apt install --no-install-recommends mono-complete mono-vbnc mono-fastcgi-server4 nginx -y &&\
    apt install ./jsign_4.1_all.deb -y &&\
    rm -rf /var/lib/apt/lists/*
COPY ./config/start_server ./start_server
COPY ./config/kl_codesign.* ./
COPY ./config/fastcgi_params /etc/nginx/fastcgi_params
COPY ./config/default-config /etc/nginx/sites-enabled/default
COPY ./config/mysql_net_v4.5.2 /app/mysql_net_v4.5.2
RUN gacutil /i mysql_net_v4.5.2/MySql.Data.dll &&\
    chmod +x start_server 
EXPOSE 80
ENV MONO_OPTIONS=--debug
CMD ./start_server
ebourg commented 1 year ago

I've been able to reproduce the issue with this Dockerfile using the same mono:slim base image:

FROM mono:slim

WORKDIR /app

RUN apt update &&\
    apt install --no-install-recommends wget default-jre-headless -y &&\
    wget https://github.com/ebourg/jsign/releases/download/4.1/jsign_4.1_all.deb &&\
    dpkg -i jsign_4.1_all.deb &&\
    wget https://github.com/ebourg/jsign/raw/master/jsign-core/src/test/resources/wineyes.exe -O /app/winêyes.exe &&\
    wget https://github.com/ebourg/jsign/raw/master/jsign-core/src/test/resources/keystores/keystore.p12  &&\
    rm -rf /var/lib/apt/lists/*

CMD jsign --keystore keystore.p12 --storepass password /app/winêyes.exe

The locale is not properly configured, adding this solves the issue:

RUN DEBIAN_FRONTEND=noninteractive apt install -y locales && \
  sed -i -e 's/# en_US.UTF-8 UTF-8/en_US.UTF-8 UTF-8/' /etc/locale.gen && \
  dpkg-reconfigure --frontend=noninteractive locales && \
  update-locale LANG=en_US.UTF-8

ENV LANG en_US.UTF-8

My guess is that the container defaults to ASCII encoding, and java doesn't decode the escaped character sequences passed by the shell.

I can't do much at the Jsign level if the environment isn't fully configured I think.

kenlasko commented 1 year ago

That's amazing! I added your additions to my DOCKERFILE and rebuilt my image/container and I am no longer having any issues with JSign and extended UTF-8 characters! Thank you very much for looking into this and providing a solution. I had suspected the issue wasn't with JSign, but with Java. I guess it was at an even lower level than that.