-
Notifications
You must be signed in to change notification settings - Fork 4
Code signing for Windows RT with open source tools
Since commit 29e6b0cb30f16cb825e5dd9a7d760ef3efb9d141
(pull request 22) generation of self-signing certificates and signing of target code is automatic. Timestamping is implemented with a command line OpenSSL call (openssl ts -reply
reading from stdin and writing to stdout). A fork of osslsigncode (branch short-circuit and/or tag 2.5-cmd) with command line TSA support is retrieved and built for the host configuration. The snakeoil
component (similar to the alike-named package found in many Linux distros) is responsible for generating the private key, creating the CSR (certificate signing request) and approving it twice into two distinct certificates with codeSigning
and timeStamping
extended purposes. All installed target *.exe
and *.dll
binaries are thus signed, including the MinGW runtime itself (provided by llvm-mingw
).
To sign an arbitrary PE32 executable manually, run ./usr/bin/selfsign.sh <binary-path>
from the MXE root anytime after snakeoil
is built.
The following articles have been used in preparation of this solution:
- Setting up a Time Stamping Authority with OpenSSL
- Trusted Timestamping (RFC 3161) in Digital Forensics
- OpenSSL manual pages, particularly openssl-req, openssl-ca and openssl-ts
See the below article for steps to sign PE32 code the original and manual way (e.g. if you must use original Windows SDK tools or their unmodified open source equivalents without Internet access).
While there are exploits that allow running arbitrary (including unsigned) code on Windows RT, they are relatively intrusive. Compared to them, the testsigning exploit can be applied irrespectively of the OS version, secure boot state and other exploits installed. It requires, however, that every binary (exe
and dll
) being loaded contained a digital signature. The trust chain does not matter (the certificate used to sign the code can be self-signed); however, a valid secure timestamp must be present.
While unsigned MXE targets can be build entirely on Linux without access to Windows systems, code signing typically involves running signtool.exe
, a closed-source Microsoft-provided binary. The process also requires accessing a digital timestamp service, involving a network connection and a third party.
It is possible, however, to utilize alternative tools to render the build process entirely self-contained.
The following steps apply to Ubuntu 20.04 "Focal Fossa". The optional steps to monitor the timestamp server with a web browser are loosely specific to WSL2; the keyword, however, is "optional".
If you already have a code signing certificate issued by a trusted authority, skip this chapter. (Keep in mind, however, that "official" certificates tend to die young, while self-signed certificates can have expiration dates millennia away.)
Otherwise, make sure OpenSSL is installed:
sudo apt-get install openssl
Then run:
openssl req -x509 -nodes -days 365000 -newkey rsa:2048 -keyout mxe.key -out mxe.crt
You will be asked for identification information (e.g. your country, state, company and contacts). Enter something that isn't likely to scare your eventual users. Now you have a certificate and a private key.
Before leaving the directory, pack the certificate and the key into a PKCS#12 store:
openssl pkcs12 -export -name Rita -in mxe.crt -inkey mxe.key -out mxe.p12 -password pass:
This is the credential storage format that the timestamp server would expect.
Install a recent JDK:
sudo apt-get install openjdk-17-jdk-headless
Clone the TSA server (or download a source tarball). The version I tested was tagged v2.2.2
.
git clone https://github.com/dnl50/tsa-server
cd tsa-server
git checkout v2.2.2
Create the application.properties
text file with tsa.certificate.path
pointing to the PKCS#12 store path, e.g. with the following command:
echo tsa.certificate.path=/home/mxe/Sign/mxe.p12 > application.properties
You needn't indicate the store password unless you indicated it earlier in openssl pkcs12
.
The default port of the timestamp authority protocol is decimal 318, which is well below 1024. To avoid running the server as root, we can either change the port, or grant the java
executable the required capability, or use authbind
. More information can be found here. I went the manual way:
$ which java
/usr/bin/java
$ ls -l /usr/bin/java
lrwxrwxrwx 1 root root 22 Oct 9 18:06 /usr/bin/java -> /etc/alternatives/java
$ sudo setcap CAP_NET_BIND_SERVICE=+eip `which java`
Failed to set capabilities on file `/usr/bin/java' (Invalid argument)
The value of the capability argument is not permitted for a file. Or the file is not a regular (non-symlink) file
Okay, let me look further.
$ ls -l /etc/alternatives/java
lrwxrwxrwx 1 root root 43 Oct 22 01:03 /etc/alternatives/java -> /usr/lib/jvm/java-17-openjdk-amd64/bin/java
$ ls -l /usr/lib/jvm/java-17-openjdk-amd64/bin/java
-rwxr-xr-x 1 root root 14496 Jul 22 01:57 /usr/lib/jvm/java-17-openjdk-amd64/bin/java
$ sudo setcap CAP_NET_BIND_SERVICE=+eip /usr/lib/jvm/java-17-openjdk-amd64/bin/java
$
Success! Now run:
./gradlew
./gradlew tasks
./gradlew bootRun
to see the progressive deployment of Gradle and project parsing; or just do ./gradlew bootRun
right away. The server is now running in the current terminal session. Launch another terminal (e.g. another terminal window) to build and run the signing client.
There are other open TSA implementations, such as El Bosso's, but they either require exotic SDKs/toolchains (C#, Go…) or are harder to configure.
There are two open source alternatives to signtool.exe
:
The latter is written in C++, builds with CMake and comes with clear installation instructions:
$ sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev
$ mkdir ../build-osslsc
$ cd ../build-osslsc
$ cmake ../osslsigncode
Ouch. It wants CMake version 3.17 or above, and Ubuntu 20.04 only bundles 3.16.3. Apparently, editing CMakeLists.txt helps:
$ nano ../osslsigncode/CMakeLists.txt
$ head -n 3 ../osslsigncode/CMakeLists.txt
# required cmake version
cmake_minimum_required(VERSION 3.16)
$ cmake ../osslsigncode
$ make -j
Success. Looks like no animal was harmed by relaxing the minor version.
Now let's have fun.
Let's assume we have just built a relatively standalone target, and let it be lua.exe
.
$ cd ~/Code/mxe
$ make lua
$ ~/Code/build-osslsc/osslsigncode sign -certs ~/Sign/mxe.crt -key ~/Sign/mxe.key -n Lua -i http://github.com/armdevvel -in usr/armv7-w64-mingw32/bin/lua.exe -out ~/Downloads/lua.exe -ts 127.0.0.1:318
Alternatively, it is possible to pass the entire credential store with -pkcs12 ~/Sign/mxe.p12 [-pass <pkcs12-password>]
.
Note that we have to indicate the timestamp server port explicitly. We could have changed it to 1318 and saved a trip.(
My ~/Downloads
is symlinked to my host W10 Downloads
folder. I copy the file to my Surface RT. No complaint about the signature, but it needs lua53.dll
, and I use a similar command line to sign the dynamic library. It turns out to have been the only missing dependency; lua.exe
runs now.
tsa-server
exposes a web interface on port 8080 to view the signing history. If you are on WSL (or another VM), you have to look up the IP address of the guest OS:
sudo apt-get install net-tools # if necessary
ifconfig
The first lines of the output will be:
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.28.204.23 netmask 255.255.240.0 broadcast 172.28.207.255
inet6 fe80::215:5dff:fec1:ead0 prefixlen 64 scopeid 0x20<link>
http://172.28.204.23:8080 will be the web interface front page, and http://172.28.204.23:8080/web/history the signing history log.
-
SignTool
, a C#/.NET app, is available from: https://forum.xda-developers.com/t/windows-rt-8-1-jailbreak-sign-tool.3228929/#post-87239669. It is hardcoded to use http://timestamp.verisign.com/scripts/timstamp.dll as the TSA server, but it's possible to change that and rebuild (source code comes along with a precompiled app). - A C#/.NET implementation of a secure timestamp server is available at https://github.com/Jemmy1228/TimeStampResponder-CSharp. We haven't evaluated it yet, but if it is functional and mature, together with
SignTool
they would make a complete in-place/on-device signing solution (since .NET runtime is a part of Windows RT).
At some point we may provide Mono build instructions for both tools. File an issue if you are interested in having them sooner than later.
Categories: General | Housekeeping | Component breeding tips | Common build problems | Bedtime reading