Compare commits

..

128 Commits
2.7 ... master

Author SHA1 Message Date
olszomal
4568c890cc Fixed resource leaks, CID 1639164, 1639165, 1639167, 1639168, 1639169 2025-03-31 13:19:35 +02:00
olszomal
4bd167a8be Fixed directly dereferencing parameter p7, CID 1576008 2025-03-31 13:19:35 +02:00
olszomal
e7405fa839 Simplify error handling in PKCS#7 certificate loading, CID 1639170 2025-03-31 13:19:35 +02:00
olszomal
776e2ec7b6 Fix memory management for ministream and difat in MSI output, CID 1639166 2025-03-31 13:19:35 +02:00
olszomal
838aaaee8d libp11 PKCS#11 provider support 2025-03-28 14:05:12 +01:00
olszomal
e8f19a6efe Added verbose output for digest encryption algorithm and signature during verification 2024-12-31 13:53:46 +01:00
olszomal
3a8e25e5bb Added support for multiple OID types in signer info attribute 2024-12-17 17:27:50 +01:00
olszomal
7d1b460dfe Style updates 2024-12-06 22:19:00 +01:00
olszomal
bc3e9e2172 Disable environment updates for Python setup 2024-12-06 22:19:00 +01:00
olszomal
21bce757ef Remove specific CMake version setup for macOS 2024-12-06 22:19:00 +01:00
olszomal
6a43f62835 Remove Python3_EXECUTABLE 2024-12-06 22:19:00 +01:00
olszomal
8780e6f8e4 Fixed pip install 2024-12-06 22:19:00 +01:00
olszomal
78a23caa54 Retain needrestart package in Linux dependency installation 2024-12-06 22:19:00 +01:00
olszomal
d92927aff4 Switch to venv on Linux 2024-12-06 22:19:00 +01:00
olszomal
4f412b5989 Removed VIRTUAL_ENV 2024-12-06 22:19:00 +01:00
olszomal
e6f3ff631d Switch to venv on Windows 2024-12-06 22:19:00 +01:00
olszomal
09135aabb8 Check Python and cryptography version in Windows CI workflow 2024-12-06 22:19:00 +01:00
olszomal
de983e680f Configured macOS environment for arm64 architecture 2024-12-06 22:19:00 +01:00
Michał Trojnara
dc827b94e5 Switch to venv on macOS 2024-12-06 22:19:00 +01:00
olszomal
40ce811701 Fixed conditional compilation for CURL and proxy support 2024-10-25 17:48:01 +02:00
Małgorzata Olszówka
db5b4c4dc0
Add the "-engineCtrl" option to control hardware and CNG engines (#405)
Documentation updated for CNG engine 1.1 compatibility.
2024-09-08 19:23:38 +02:00
olszomal
4ee429792d Refactor imports to use explicit submodule imports and organize class/function imports 2024-09-06 11:58:28 +02:00
Michał Trojnara
27686c0b0c Missing part of 4dd836bab1832b8a87331f2e73356cda4f01e998 2024-09-05 11:43:25 +02:00
olszomal
21133f9c3b Added the '-blobFile' option to specify a file containing the blob content 2024-09-04 17:51:35 +02:00
Petr Vaněk
64305d6415 tests: add import for python-cryptography >= 43.0.0
write_pkcs12_container method raises following error message with
python-cryptography-43.0.0:

  Error: module 'cryptography.hazmat.primitives.serialization' has no attribute 'pkcs12'

Explicit import of the pkcs12 module resolves the issue.
2024-09-02 13:05:55 +02:00
Michał Trojnara
4dd836bab1 Initial 2.10-dev commit 2024-06-29 21:58:55 +02:00
Michał Trojnara
f57c213207 Use the installed version of Python 2024-06-29 20:52:55 +02:00
Michał Trojnara
76ee550c9d Release 2.9
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2024-06-29 20:16:47 +02:00
olszomal
2b3228d549 Changed error output to stderr instead of stdout 2024-06-05 16:54:21 +02:00
Michał Trojnara
bad6e96e0f Not only include Code Signing certificates 2024-06-04 13:25:51 +02:00
olszomal
3c8c74a8c3 Handled memory reallocation error 2024-06-03 14:16:39 +02:00
olszomal
771014a41e Fixed uint32_t overflow when attaching a new MSI sector 2024-06-03 14:16:39 +02:00
olszomal
476168e09e Added the "-ignore-crl" option to disable CRL online verification 2024-06-03 12:16:02 +02:00
olszomal
be4f010535 Fixed to get CAT content value 2024-06-03 08:44:02 +02:00
Michał Trojnara
2c27e2e37d Fix Ubuntu 24.04 build 2024-06-02 00:07:37 +02:00
Michał Trojnara
b829e7a802 Fix macos build with GitHub Actions 2024-05-31 20:52:03 +02:00
olszomal
d0ae214cb4 Verified number of MSI sectors 2024-05-31 16:47:31 +02:00
olszomal
9b1a6c9fb8 Failed to get CAT content 2024-05-31 16:47:31 +02:00
olszomal
41b662a8fe Checked cFolders value 2024-05-31 16:47:31 +02:00
olszomal
5232734071 Fix fuzzer error - failed to sort central directory entry 2024-05-29 14:22:26 +02:00
olszomal
996cf20fa9 Fixed msi dirent memory leak 2024-05-29 14:22:26 +02:00
Brad Hughes
825c9dad7c Add '-login' option to force a login to PKCS11 engines 2024-05-22 19:06:06 +02:00
Małgorzata Olszówka
6e5bef14e9
Rewrite making test certificates (#393)
Also updates obsolete curl dependencies with zlib.
2024-05-22 18:59:53 +02:00
Michał Trojnara
a53bd2bdb3 Diagnostic formatting improvements 2024-04-18 09:49:55 +02:00
Michał Trojnara
e4d471b885 Code signing CA certificates
Based on:
https://learn.microsoft.com/en-us/security/trusted-root/participants-list
2024-04-16 16:50:25 +02:00
Michał Trojnara
bcb9737dda Remove the "openssl version" step from CI
We will likely link a different version of OpenSSL anyway,
so printing the version of the first OpenSSL command-line
executable on the PATH only adds to confusion.
2024-04-15 19:34:50 +02:00
olszomal
7a5389b719 Fixed cmake test cURL support 2024-04-10 17:09:01 +02:00
olszomal
d9f0a8dade Fixed missing Crypt32.lib when linking openssl statically 2024-04-10 17:09:01 +02:00
olszomal
aa8c8dd720 Type casting of the read() return value 2024-04-10 17:09:01 +02:00
olszomal
16c5e5aa4a Squashed logically dead code for curl response code for openssl version 3.0.0 and later, CID 1585046 2024-04-10 17:09:01 +02:00
Michał Trojnara
ded1f7aa67
Use native HTTP client with OpenSSL 3.0 or later (#378)
Co-authored-by: olszomal <Malgorzata.Olszowka@stunnel.org>
2024-04-09 19:33:31 +02:00
Steve McIntyre
6ad2679f17 Read the password from stdin if desired
Use the common convention: "-" means to use stdin

Signed-off-by: Steve McIntyre <steve.mcintyre@pexip.com>
2024-03-28 21:33:01 +01:00
olszomal
4776f43f04 Improved manual 2024-03-26 18:28:02 +01:00
olszomal
d9db038c65 Sort central directory entries in ascending order by offset 2024-03-20 11:19:46 +01:00
Michał Trojnara
e8ef027776 Simplify base64 decoding in script.c 2024-03-11 12:10:20 +01:00
olszomal
0a0761746f Fixed memory corruption 2024-03-08 16:59:34 +01:00
olszomal
f51e2a4869 Intercepted X509_V_FLAG_CHECK_SS_SIGNATURE verify error 2024-03-08 16:59:34 +01:00
olszomal
093ed12c66 Supported CRL decoding in DER and PEM format 2024-03-08 16:59:34 +01:00
olszomal
71a046a2d0 Ignore missing PKCS#9 signing time field (NID_pkcs9_signingTime: 1.2.840.113549.1.9.5) in the CMS_ContentInfo structure.
Timestamping time for verification is get from embedded content in this CMS_ContentInfo structure.
2024-03-08 16:59:34 +01:00
olszomal
c73f82b558 Set the NONCE field in a TSA request 2024-03-08 16:59:34 +01:00
Michał Trojnara
b294f5d18f Initial 2.9-dev commit 2024-03-05 16:34:32 +01:00
Michał Trojnara
e07bb7d6b2 Update workflow components 2024-03-05 15:51:29 +01:00
Michał Trojnara
699bc85d0a Release 2.8
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2024-03-03 23:32:15 +01:00
olszomal
192e7a732b Fixed memory leaks 2024-03-01 17:50:20 +01:00
olszomal
656051676f Changelog update 2024-02-29 17:57:22 +01:00
olszomal
3998bcabb2 Simplify BIO chain free up and FILE_FORMAT_CTX cleanup 2024-02-28 15:55:25 +01:00
olszomal
fa40c57f80 Simplify checking whether a signature exists 2024-02-28 11:55:21 +01:00
olszomal
0b93a94ffa Fixed cross-signed root CA certificate 2024-02-28 11:52:49 +01:00
olszomal
105fd3af4a Fix handling of printf format specifiers 2024-02-27 10:47:58 +01:00
Michał Trojnara
86a594b087 NEWS.md entry for Microsoft PowerShell signing
Closes #37
2024-02-22 16:39:57 +01:00
olszomal
1dea73b038 Install python@3.8 on macOS required for the Github Actions CI 2024-02-22 16:14:35 +01:00
olszomal
b661ed08ed Fix fuzzer error - corrupted data content 2024-02-20 17:48:55 +01:00
olszomal
ead0584611 Disable curl dependence 2024-02-20 17:48:31 +01:00
Michał Trojnara
bd7751147e Update Windows build documentation 2024-02-20 10:03:47 +01:00
olszomal
1bc7fc36b8 Connect to CRL Distribution Points through the configured proxy when verifying 2024-02-19 12:19:44 +01:00
Zeijlon (ThinLinc Team)
42e9733916
Fix python 3 compatibility in server_http.py (#350)
Building osslsigncode fails on systems with older versions of Python 3 due to the server_http.py script, part of the test procedure. This script requires the ThreadingHTTPServer module, introduced in Python version 3.7.

A workaround has been implemented to create a ThreadingHTTPServer locally, ensuring backward compatibility with older Python versions.
2024-02-16 12:39:48 +01:00
olszomal
b2024cee9d Add -ignore-cdp option to help 2024-02-16 12:30:29 +01:00
olszomal
9d152b8477 Fix url resource leak, CID 1583652, 1583653 2024-02-16 12:30:29 +01:00
olszomal
7a02d51a83 Print failed certificate chain retrieved from the signature 2024-02-15 13:07:02 +01:00
olszomal
dac68a3a4d Disable CRL Distribution Points online verification 2024-02-15 12:30:50 +01:00
Michał Trojnara
bd1ab77f44 Improve variable names and comments
No functional change intended.
2024-02-13 17:39:01 +01:00
olszomal
5ee859db2c Fixed out-of-bounds access, CID 1583604 2024-02-13 17:20:29 +01:00
olszomal
ee3c51f6d5 Check BIO_write_ex() return value, CID 1583605 2024-02-13 17:20:29 +01:00
Michał Trojnara
cedb8b5798 Print default -CAfile in "osslsigncode -v"
Fix #344
2024-02-12 12:31:57 +01:00
olszomal
dcf58a00e7 Fixed getting content 2024-02-12 11:41:08 +01:00
Michał Trojnara
4576895718 Initial script (text) format support
See #37 for details.
2024-02-12 10:54:18 +01:00
olszomal
1bdcad619e Remove http proxy configuration that may change behavior 2024-02-07 13:38:01 +01:00
olszomal
31b046cf98 Fix dereference after null check, CID 1576008 2024-01-24 09:23:55 +01:00
olszomal
f3ac2c0c6f Fix resource leak, CID 1576007 2024-01-24 09:23:55 +01:00
olszomal
f22c83514c Simplify obtaining an existing signature and creating a new one 2024-01-23 19:00:22 +01:00
olszomal
44ca1f38e6 PKCS9_SEQUENCE_NUMBER authenticated attribute support 2024-01-23 19:00:22 +01:00
olszomal
0985c47990 Add a new "-index" option to enable verification or addition of attributes to the signature at a certain position 2024-01-23 19:00:22 +01:00
olszomal
aa158e40ec Fix BIO memory leak 2024-01-10 16:03:08 +01:00
olszomal
5da62de5ef Fixed adding signing time 2024-01-08 11:48:10 +01:00
Michał Trojnara
4d08fbb2c1 Only use IPv4 127.0.0.1 for tests
Fix #331
2023-12-21 11:33:48 +01:00
Michał Trojnara
98b004edda Ignore garbage in PE sigpos/siglen 2023-12-20 11:26:50 +01:00
olszomal
34bf3bc525 tests for extract-data command 2023-12-19 13:07:19 +01:00
olszomal
64e1bba96b Add a new command extract-data to extract a PKCS#7 data content to be signed 2023-12-19 13:07:19 +01:00
olszomal
46bcaa9d88 Skip a null stream warning 2023-12-18 10:14:51 +01:00
olszomal
867e0d446d Fixed APPX file specific: attach-signature command 2023-12-18 10:14:29 +01:00
olszomal
7285778cb0 Use X509_LOOKUP_load_file() to load certificates with a lookup using the implementation X509_LOOKUP_file() 2023-12-03 18:33:50 +01:00
olszomal
c909ba82d7 tests: fixed string formatting in Python version earlier than 2.6 2023-11-22 17:53:50 +01:00
olszomal
7b60d6447d tests: initialize resp_data 2023-11-22 17:53:50 +01:00
olszomal
588a1a0b5f Use default certificates when the HTTP server fails 2023-11-22 17:53:50 +01:00
olszomal
8a9b275494 Fixed unmap_file() segmentation fault 2023-11-21 10:54:44 +01:00
olszomal
0db17be606 Listing each member of the CAT file 2023-11-20 17:20:03 +01:00
olszomal
f9ad19d4a2 Signature index presentation 2023-11-14 10:33:04 +01:00
olszomal
b9ca24d423 Check MsiDigitalSignatureEx 2023-11-14 10:33:04 +01:00
olszomal
8d2b562244 Group warnings for CAT files 2023-11-14 10:33:04 +01:00
olszomal
6f4e9ab597 Fix dereference after null check, CID 1570976 2023-11-14 10:33:04 +01:00
olszomal
6d6270094e Simplify unlinking outfile 2023-11-13 13:50:41 +01:00
olszomal
57563716d1 Enable x mode modifier if available 2023-11-13 13:50:41 +01:00
olszomal
8ab8a133f7 Overwriting an existing file is not supported 2023-11-13 13:50:41 +01:00
olszomal
ef5047038e Delete the output file in case of error 2023-11-13 13:50:41 +01:00
olszomal
e290e03341 tests: Add more tests for catalog files. 2023-11-07 14:56:48 +01:00
olszomal
900ffed596 Enable verification that a catalog file was signed by a valid certificate.
Simplify setting and signing a content blob.
Clean up a support library.
2023-11-07 14:56:48 +01:00
Michał Trojnara
33253afb5e Remove unneeded variables 2023-10-17 17:10:28 +02:00
Michał Trojnara
3aba55e5e0 Code simplification 2023-10-17 16:58:57 +02:00
olszomal
898a53b2a7 Create a certificate chain sorted in ascending order by DER encoding 2023-10-17 16:21:26 +02:00
Joe Tylka
75ce1dadf5 Add missing dependencies for install in fresh ubuntu 2023-10-10 16:19:42 +02:00
Michał Trojnara
4166476030 Initial Dockerfile 2023-10-09 17:24:22 +02:00
olszomal
a5690f2d19 Fixed resource leak, CID 1566947, 1566965, 1566967, 1568542, 1568543 2023-10-09 17:21:16 +02:00
olszomal
cdb75578e9 fixed windows segmentation fault 2023-10-06 19:41:43 +02:00
olszomal
e2ab4a152d improved verify callbacks 2023-10-06 19:41:31 +02:00
Michał Trojnara
b8e690f3bd Work around a GitHub Actions regression 2023-10-06 19:08:50 +02:00
olszomal
c89d6b43aa description of built-in TSA options 2023-09-25 15:22:11 +02:00
Michał Trojnara
9faed39931 Add builtin-baseline 2023-09-20 16:25:30 +02:00
Michał Trojnara
ecb17709fc Initial 2.8-dev commit 2023-09-19 22:03:02 +02:00
76 changed files with 16184 additions and 4136 deletions

View File

@ -7,7 +7,7 @@ on:
env: env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release BUILD_TYPE: Release
version: osslsigncode-2.7 version: osslsigncode-2.10-dev
jobs: jobs:
build: build:
@ -15,6 +15,12 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- id: ubuntu-24.04
triplet: x64-linux
compiler: gcc
os: ubuntu-24.04
generator: Unix Makefiles
vcpkg_root:
- id: ubuntu-22.04 - id: ubuntu-22.04
triplet: x64-linux triplet: x64-linux
compiler: gcc compiler: gcc
@ -28,7 +34,7 @@ jobs:
generator: Unix Makefiles generator: Unix Makefiles
vcpkg_root: vcpkg_root:
- id: macOS - id: macOS
triplet: x64-osx triplet: arm64-osx
compiler: clang compiler: clang
os: macOS-latest os: macOS-latest
generator: Unix Makefiles generator: Unix Makefiles
@ -72,11 +78,11 @@ jobs:
VCPKG_ROOT: ${{matrix.vcpkg_root}} VCPKG_ROOT: ${{matrix.vcpkg_root}}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
- name: Cache the vcpkg archives - name: Cache the vcpkg archives
if: matrix.cache != '' if: matrix.cache != ''
uses: actions/cache@v3 uses: actions/cache@v4
with: with:
path: ${{matrix.cache}} path: ${{matrix.cache}}
key: ${{matrix.id}}-${{hashFiles('vcpkg.json')}} key: ${{matrix.id}}-${{hashFiles('vcpkg.json')}}
@ -90,11 +96,34 @@ jobs:
with: with:
arch: ${{matrix.arch}} arch: ${{matrix.arch}}
- name: Install apt dependencies (Linux) - name: Install MSYS2
if: runner.os == 'Linux' if: matrix.compiler == 'mingw'
uses: msys2/setup-msys2@v2
with:
update: true
install: mingw-w64-x86_64-ninja
- name: Put MSYS2_MinGW64 on PATH
if: matrix.compiler == 'mingw'
run: echo "D:/a/_temp/msys64/mingw64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Set up Python (macOS)
if: runner.os == 'macOS'
uses: actions/setup-python@v4
with:
python-version: '3.13'
update-environment: false
architecture: 'arm64'
- name: Set up Python virtual environment (Linux/macOS)
if: runner.os != 'Windows'
run: | run: |
sudo apt-get update python -m venv --system-site-packages --copies venv
sudo apt-get install -y libssl-dev libcurl4-openssl-dev faketime
- name: Set up Python virtual environment (Windows)
if: runner.os == 'Windows'
run: |
python.exe -m venv --system-site-packages --copies venv
- name: Install Xcode (macOS) - name: Install Xcode (macOS)
if: runner.os == 'macOS' if: runner.os == 'macOS'
@ -104,46 +133,67 @@ jobs:
- name: Setup the oldest supported version of cmake (macOS) - name: Setup the oldest supported version of cmake (macOS)
if: runner.os == 'macOS' if: runner.os == 'macOS'
uses: jwlawson/actions-setup-cmake@v1.12 uses: jwlawson/actions-setup-cmake@v2.0
with:
cmake-version: '3.17.0'
- name: Show OpenSSL version - name: Install python3 cryptography module (Linux)
run: openssl version -a if: runner.os == 'Linux'
run: |
source venv/bin/activate
python -m pip install --upgrade pip
python -m pip install --upgrade cryptography
python -c "import sys; print(sys.executable)"
python --version
python -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
- name: Configure CMake - name: Install python3 cryptography module (macOS)
run: cmake if: runner.os == 'macOS'
-G "${{matrix.generator}}" run: |
-S ${{github.workspace}} source venv/bin/activate
-B ${{github.workspace}}/build python -m pip install --upgrade pip
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} ARCHFLAGS="-arch arm64" python -m pip install --upgrade cryptography
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/dist python -c "import sys; print(sys.executable)"
-DVCPKG_TARGET_TRIPLET=${{matrix.triplet}} python --version
python -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
- name: Install python3 cryptography module (Windows)
if: runner.os == 'Windows'
run: |
.\venv\Scripts\Activate.ps1
python.exe -m ensurepip
python.exe -m pip install --upgrade pip
python.exe -m pip install cryptography
python.exe -c "import sys; print(sys.executable)"
python.exe --version
python.exe -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
- name: Configure CMake (Linux/macOS)
if: runner.os != 'Windows'
run: |
source venv/bin/activate
cmake \
-G "${{matrix.generator}}" \
-S "${{github.workspace}}" \
-B "${{github.workspace}}/build" \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_BUILD_TYPE="${{env.BUILD_TYPE}}" \
-DCMAKE_INSTALL_PREFIX="${{github.workspace}}/dist"
- name: Configure CMake (Windows)
if: runner.os == 'Windows'
run: |
.\venv\Scripts\Activate.ps1
cmake `
-G "${{matrix.generator}}" `
-S "${{github.workspace}}" `
-B "${{github.workspace}}/build" `
-DCMAKE_BUILD_TYPE="${{env.BUILD_TYPE}}" `
-DCMAKE_INSTALL_PREFIX="${{github.workspace}}/dist"
- name: Build - name: Build
run: cmake run: cmake
--build ${{github.workspace}}/build --build ${{github.workspace}}/build
--config ${{env.BUILD_TYPE}} --config ${{env.BUILD_TYPE}}
- name: Start HTTP server (macOS)
working-directory: ${{github.workspace}}/build
if: runner.os == 'macOS'
run: |
python3 --version
python3 ./Testing/server_http.py --port 19254
while test ! -s ./Testing/logs/port.log; do sleep 1; done
- name: Start HTTP server (Windows)
working-directory: ${{github.workspace}}\build
if: runner.os == 'Windows'
run: |
python.exe --version
$Args = '.\Testing\server_http.pyw --port 19254'
$File = '.\Testing\logs\port.log'
Start-Process -FilePath pythonw.exe -ArgumentList $Args
while(-not(Test-Path -Path $File -PathType Leaf) -or [String]::IsNullOrWhiteSpace((Get-Content $File))) {Start-Sleep -Seconds 1}
Get-Content '.\Testing\logs\server.log'
- name: List files (Linux/macOS) - name: List files (Linux/macOS)
if: runner.os != 'Windows' if: runner.os != 'Windows'
run: find .. -ls run: find .. -ls
@ -152,12 +202,22 @@ jobs:
if: runner.os == 'Windows' if: runner.os == 'Windows'
run: Get-ChildItem -Recurse -Name .. run: Get-ChildItem -Recurse -Name ..
- name: Test - name: Test (Linux/macOS)
if: runner.os != 'Windows'
working-directory: ${{github.workspace}}/build working-directory: ${{github.workspace}}/build
run: ctest -C ${{env.BUILD_TYPE}} run: |
source ../venv/bin/activate
ctest -C ${{env.BUILD_TYPE}}
- name: Test (Windows)
if: runner.os == 'Windows'
working-directory: ${{github.workspace}}/build
run: |
..\venv\Scripts\Activate.ps1
ctest -C ${{env.BUILD_TYPE}}
- name: Upload the errors - name: Upload the errors
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
if: failure() if: failure()
with: with:
name: errors-${{matrix.id}} name: errors-${{matrix.id}}
@ -171,7 +231,7 @@ jobs:
run: cmake --install ${{github.workspace}}/build run: cmake --install ${{github.workspace}}/build
- name: Upload the executables - name: Upload the executables
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v4
with: with:
name: ${{env.version}}-${{matrix.id}} name: ${{env.version}}-${{matrix.id}}
path: ${{github.workspace}}/dist path: ${{github.workspace}}/dist

View File

@ -25,11 +25,11 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v3 uses: actions/checkout@v4
# Initializes the CodeQL tools for scanning. # Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL - name: Initialize CodeQL
uses: github/codeql-action/init@v2 uses: github/codeql-action/init@v3
with: with:
languages: ${{ matrix.language }} languages: ${{ matrix.language }}
@ -43,7 +43,7 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below) # If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild - name: Autobuild
uses: github/codeql-action/autobuild@v2 uses: github/codeql-action/autobuild@v3
# Command-line programs to run using the OS shell. # Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
@ -56,4 +56,4 @@ jobs:
# ./location_of_script_within_repo/buildscript.sh # ./location_of_script_within_repo/buildscript.sh
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v3

View File

@ -10,7 +10,7 @@ jobs:
env: env:
token: ${{secrets.COVERITY_SCAN_TOKEN}} token: ${{secrets.COVERITY_SCAN_TOKEN}}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v4
if: env.token if: env.token
- name: Get ready for scanning - name: Get ready for scanning
if: env.token if: env.token

View File

@ -3,20 +3,20 @@ cmake_minimum_required(VERSION 3.17)
# autodetect vcpkg CMAKE_TOOLCHAIN_FILE if VCPKG_ROOT is defined # autodetect vcpkg CMAKE_TOOLCHAIN_FILE if VCPKG_ROOT is defined
# this needs to be configured before the project() directive # this needs to be configured before the project() directive
if(DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) if((CMAKE_GENERATOR MATCHES "Ninja") AND DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "") set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
endif(DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) endif((CMAKE_GENERATOR MATCHES "Ninja") AND DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
# configure basic project information # configure basic project information
project(osslsigncode project(osslsigncode
VERSION 2.7 VERSION 2.10
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files" DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode" HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
LANGUAGES C) LANGUAGES C)
# force nonstandard version format for development packages # force nonstandard version format for development packages
set(DEV "") set(DEV "-dev")
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${DEV}") set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${DEV}")
# version and contact information # version and contact information
@ -27,9 +27,18 @@ set(PACKAGE_BUGREPORT "Michal.Trojnara@stunnel.org")
set(CMAKE_C_STANDARD 11) set(CMAKE_C_STANDARD 11)
set(CMAKE_C_STANDARD_REQUIRED ON) set(CMAKE_C_STANDARD_REQUIRED ON)
if(WIN32)
add_definitions(-DUSE_WIN32)
endif()
# load CMake library modules # load CMake library modules
include(FindOpenSSL) include(FindOpenSSL)
include(FindCURL) if(OPENSSL_VERSION VERSION_LESS "1.1.1")
message(FATAL_ERROR "OpenSSL version must be at least 1.1.1")
endif()
if(OPENSSL_VERSION VERSION_LESS "3.0.0")
include(FindCURL)
endif(OPENSSL_VERSION VERSION_LESS "3.0.0")
include(FindZLIB) include(FindZLIB)
# load CMake project modules # load CMake project modules
@ -48,7 +57,7 @@ configure_file(Config.h.in config.h)
target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1) target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1)
# set sources # set sources
target_sources(osslsigncode PRIVATE osslsigncode.c helpers.c msi.c pe.c cab.c cat.c appx.c) target_sources(osslsigncode PRIVATE osslsigncode.c helpers.c utf.c msi.c pe.c cab.c cat.c appx.c script.c)
if(NOT UNIX) if(NOT UNIX)
target_sources(osslsigncode PRIVATE applink.c) target_sources(osslsigncode PRIVATE applink.c)
endif(NOT UNIX) endif(NOT UNIX)
@ -64,6 +73,7 @@ target_include_directories(osslsigncode PRIVATE ${OPENSSL_INCLUDE_DIR})
target_link_libraries(osslsigncode PRIVATE ${OPENSSL_LIBRARIES}) target_link_libraries(osslsigncode PRIVATE ${OPENSSL_LIBRARIES})
# set cURL includes/libraries # set cURL includes/libraries
if(OPENSSL_VERSION VERSION_LESS "3.0.0")
if(CURL_FOUND) if(CURL_FOUND)
target_compile_definitions(osslsigncode PRIVATE ENABLE_CURL=1) target_compile_definitions(osslsigncode PRIVATE ENABLE_CURL=1)
target_include_directories(osslsigncode PRIVATE ${CURL_INCLUDE_DIRS}) target_include_directories(osslsigncode PRIVATE ${CURL_INCLUDE_DIRS})
@ -72,6 +82,7 @@ if(CURL_FOUND)
else(CURL_FOUND) else(CURL_FOUND)
message(STATUS "cURL support disabled (library not found)") message(STATUS "cURL support disabled (library not found)")
endif(CURL_FOUND) endif(CURL_FOUND)
endif(OPENSSL_VERSION VERSION_LESS "3.0.0")
if(NOT ZLIB_FOUND) if(NOT ZLIB_FOUND)
message(FATAL_ERROR "Zlib library not found") message(FATAL_ERROR "Zlib library not found")
@ -79,6 +90,11 @@ endif(NOT ZLIB_FOUND)
target_include_directories(osslsigncode PRIVATE ${ZLIB_INCLUDE_DIR}) target_include_directories(osslsigncode PRIVATE ${ZLIB_INCLUDE_DIR})
target_link_libraries(osslsigncode PRIVATE ${ZLIB_LIBRARIES}) target_link_libraries(osslsigncode PRIVATE ${ZLIB_LIBRARIES})
if(NOT UNIX)
# https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown
target_link_libraries(osslsigncode PRIVATE Ws2_32.lib crypt32.lib)
endif(NOT UNIX)
# add paths to linker search and installed rpath # add paths to linker search and installed rpath
set_target_properties(osslsigncode PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE) set_target_properties(osslsigncode PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)

32
Dockerfile Normal file
View File

@ -0,0 +1,32 @@
# Stage 1: Build osslsigncode on Alpine
FROM alpine:latest AS builder
# Install build dependencies
RUN apk add --no-cache build-base cmake openssl-dev zlib-dev
# Copy osslsigncode source code into the image
COPY . /source
# Build osslsigncode
RUN cd /source && \
mkdir -p build && \
cd build && \
rm -f CMakeCache.txt && \
cmake -S .. && \
cmake --build . && \
cmake --install .
# Stage 2: Create final image without build environment
FROM alpine:latest
# Copy compiled binary from builder stage
COPY --from=builder /usr/local/bin/osslsigncode /usr/local/bin/osslsigncode
# Install necessary runtime libraries (latest version)
RUN apk add --no-cache libcrypto3
# Set working directory
WORKDIR /workdir
# Declare volume to mount files
VOLUME [ "/workdir" ]

View File

@ -3,50 +3,40 @@
### Building osslsigncode source with MSYS2 MinGW 64-bit and MSYS2 packages: ### Building osslsigncode source with MSYS2 MinGW 64-bit and MSYS2 packages:
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions. 1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
Once up and running install even mingw-w64-x86_64-gcc, mingw-w64-x86_64-curl. Once up and running install the following packages:
``` ```
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-curl pacman -S make mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-openssl mingw-w64-x86_64-python-cryptography
``` ```
mingw-w64-x86_64-openssl and mingw-w64-x86_64-zlib packages are installed with dependencies. mingw-w64-x86_64-zlib package is installed with dependencies.
2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables. 2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables.
``` ```
cd osslsigncode-folder cd osslsigncode-folder
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \ mkdir build && cd build && cmake -S .. -DCMAKE_BUILD_TYPE=Release -G "MSYS Makefiles"
-lcrypto -lssl -lcurl \ cmake --build . --verbose
-D 'PACKAGE_STRING="osslsigncode x.y"' \
-D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \
-D ENABLE_CURL
``` ```
3) Run "Command prompt" and include "c:\msys64\mingw64\bin" folder as part of the path. 3) Make tests.
```
ctest
```
4) Run "Command prompt" and include "c:\msys64\mingw64\bin" folder as part of the path.
``` ```
path=%path%;c:\msys64\mingw64\bin path=%path%;c:\msys64\mingw64\bin
cd osslsigncode-folder
osslsigncode.exe -v osslsigncode.exe -v
osslsigncode 2.4, using: osslsigncode 2.8, using:
OpenSSL 1.1.1g 21 Apr 2020 (Library: OpenSSL 1.1.1g 21 Apr 2020) OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023)
libcurl/7.70.0 OpenSSL/1.1.1g (Schannel) zlib/1.2.11 brotli/1.0.7 libidn2/2.3.0 No default -CAfile location detected
libpsl/0.21.0 (+libidn2/2.3.0) libssh2/1.9.0 nghttp2/1.40.0
``` ```
### Building OpenSSL and osslsigncode sources with MSYS2 MinGW 64-bit:
### Building OpenSSL, Curl and osslsigncode sources with MSYS2 MinGW 64-bit:
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions. 1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
Once up and running install even: perl make autoconf automake libtool pkg-config. Once up and running install even: perl make autoconf automake libtool pkg-config.
``` ```
pacman -S perl make autoconf automake libtool pkg-config pacman -S perl make autoconf automake libtool pkg-config
``` ```
Make sure there are no curl, brotli, libpsl, libidn2 and nghttp2 packages installed:
```
pacman -R mingw-w64-x86_64-curl \
mingw-w64-x86_64-brotli \
mingw-w64-x86_64-libpsl \
mingw-w64-x86_64-libidn2 \
mingw-w64-x86_64-nghttp2
```
Run "MSYS2 MinGW 64-bit" in the administrator mode. Run "MSYS2 MinGW 64-bit" in the administrator mode.
2) Build and install OpenSSL. 2) Build and install OpenSSL.
@ -55,46 +45,30 @@
./config --prefix='C:/OpenSSL' --openssldir='C:/OpenSSL' ./config --prefix='C:/OpenSSL' --openssldir='C:/OpenSSL'
make && make install make && make install
``` ```
3) Build and install curl.
```
cd curl-(version)
./buildconf
./configure --prefix='C:/curl' --with-ssl='C:/OpenSSL' \
--disable-ftp --disable-tftp --disable-file --disable-dict \
--disable-telnet --disable-imap --disable-smb --disable-smtp \
--disable-gopher --disable-pop --disable-pop3 --disable-rtsp \
--disable-ldap --disable-ldaps --disable-unix-sockets \
--disable-pthreads --without-zstd --without-zlib
make && make install
```
3) Build 64-bit Windows executables. 3) Configure a CMake project.
``` ```
cd osslsigncode-folder mkdir build && cd build && cmake -S .. -DCMAKE_BUILD_TYPE=Release -G "MSYS Makefiles" -DCMAKE_PREFIX_PATH="C:\OpenSSL"
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \
-L 'C:/OpenSSL/lib/' -lcrypto -lssl \
-I 'C:/OpenSSL/include/' \
-L 'C:/curl/lib' -lcurl \
-I 'C:/curl/include' \
-D 'PACKAGE_STRING="osslsigncode x.y"' \
-D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \
-D ENABLE_CURL
``` ```
4) Run "Command prompt" and copy required libraries. 4) Run "Command prompt" and copy required libraries.
``` ```
cd osslsigncode-folder cd osslsigncode-folder
copy C:\OpenSSL\bin\libssl-1_1-x64.dll copy C:\OpenSSL\bin\libssl-3-x64.dll
copy C:\OpenSSL\bin\libcrypto-1_1-x64.dll copy C:\OpenSSL\bin\libcrypto-3-x64.dll
copy C:\curl\bin\libcurl-4.dll
osslsigncode.exe -v
osslsigncode 2.4, using:
OpenSSL 1.1.1k 25 Mar 2021 (Library: OpenSSL 1.1.1k 25 Mar 2021)
libcurl/7.78.0 OpenSSL/1.1.1k
``` ```
### Building OpenSSL, Curl and osslsigncode sources with Microsoft Visual Studio: 5) Build 64-bit Windows executables.
```
cmake --build . --verbose
```
6) Make tests.
```
ctest
```
### Building OpenSSL and osslsigncode sources with Microsoft Visual Studio:
1) Install and integrate vcpkg: https://vcpkg.io/en/getting-started.html 1) Install and integrate vcpkg: https://vcpkg.io/en/getting-started.html

47
NEWS.md
View File

@ -1,5 +1,52 @@
# osslsigncode change log # osslsigncode change log
### 2.10 (unreleased)
- added compatiblity with the CNG engine version 1.1 or later
- added the "-engineCtrl" option to control hardware and CNG engines
- improved unauthenticated blob support (thanks to Asger Hautop Drewsen)
- added the '-blobFile' option to specify a file containing the blob content
- added PKCS#11 provider support (requires OpenSSL 3.0)
### 2.9 (2024.06.29)
- added a 64 bit long pseudo-random NONCE in the TSA request
- missing NID_pkcs9_signingTime is no longer an error
- added support for PEM-encoded CRLs
- fixed the APPX central directory sorting order
- added a special "-" file name to read the passphrase from stdin
(by Steve McIntyre)
- used native HTTP client with OpenSSL 3.x, removing libcurl dependency
- added '-login' option to force a login to PKCS11 engines
(by Brad Hughes)
- added the "-ignore-crl" option to disable fetching and verifying
CRL Distribution Points
- changed error output to stderr instead of stdout
- various testing framework improvements
- various memory corruption fixes
### 2.8 (2024.03.03)
- Microsoft PowerShell signing sponsored by Cisco Systems, Inc.
- fixed setting unauthenticated attributes (Countersignature, Unauthenticated
Data Blob) in a nested signature
- added the "-index" option to verify a specific signature or modify its
unauthenticated attributes
- added CAT file verification
- added listing the contents of a CAT file with the "-verbose" option
- added the new "extract-data" command to extract a PKCS#7 data content to be
signed with "sign" and attached with "attach-signature"
- added PKCS9_SEQUENCE_NUMBER authenticated attribute support
- added the "-ignore-cdp" option to disable CRL Distribution Points (CDP)
online verification
- unsuccessful CRL retrieval and verification changed into a critical error
- the "-p" option modified to also use to configured proxy to connect CRL
Distribution Points
- added implicit allowlisting of the Microsoft Root Authority serial number
00C1008B3C3C8811D13EF663ECDF40
- added listing of certificate chain retrieved from the signature in case of
verification failure
### 2.7 (2023.09.19) ### 2.7 (2023.09.19)
- fixed signing CAB files (by Michael Brown) - fixed signing CAB files (by Michael Brown)

View File

@ -39,7 +39,7 @@ We highly recommend downloading a [release tarball](https://github.com/mtrojnar/
* Install prerequisites on a Debian-based distributions, such as Ubuntu: * Install prerequisites on a Debian-based distributions, such as Ubuntu:
``` ```
sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev zlib1g-dev python3
``` ```
* Install prerequisites on macOS with Homebrew: * Install prerequisites on macOS with Homebrew:
``` ```
@ -131,17 +131,51 @@ To sign a CAB file containing java class files:
``` ```
Only the 'low' parameter is currently supported. Only the 'low' parameter is currently supported.
If you want to use PKCS11 token, you should indicate PKCS11 engine and module. If you want to use a PKCS#11 token, you should specify the PKCS#11 engine and module.
An example of using osslsigncode with SoftHSM: An example of using osslsigncode with SoftHSM:
``` ```
osslsigncode sign \ osslsigncode sign \
-pkcs11engine /usr/lib64/engines-1.1/pkcs11.so \ -engine /usr/lib64/engines-1.1/pkcs11.so \
-pkcs11module /usr/lib64/pkcs11/libsofthsm2.so \ -pkcs11module /usr/lib64/pkcs11/libsofthsm2.so \
-pkcs11cert 'pkcs11:token=softhsm-token;object=cert' \ -pkcs11cert 'pkcs11:token=softhsm-token;object=cert' \
-key 'pkcs11:token=softhsm-token;object=key' \ -key 'pkcs11:token=softhsm-token;object=key' \
-in yourapp.exe -out yourapp-signed.exe -in yourapp.exe -out yourapp-signed.exe
``` ```
Since OpenSSL 3.0, you can use a PKCS#11 token with the PKCS#11 provider.
An example of using osslsigncode with OpenSC:
```
osslsigncode sign \
-provider /usr/lib64/ossl-modules/pkcs11prov.so \
-pkcs11module /usr/lib64/opensc-pkcs11.so \
-pkcs11cert 'pkcs11:token=my-token;object=cert' \
-key 'pkcs11:token=my-token;object=key' \
-in yourapp.exe -out yourapp-signed.exe
```
You can use a certificate and key stored in the Windows Certificate Store with
the CNG engine version 1.1 or later. For more information, refer to
https://www.stunnel.org/cng-engine.html
A non-commercial edition of CNG engine is available for testing, personal,
educational, or research purposes.
To use the CNG engine with osslsigncode, ensure that the `cng.dll` library is
placed in the same directory as the `osslsigncode.exe` executable.
Below is an example of how to use osslsigncode with the CNG engine:
```
osslsigncode sign \
-engine cng \
-pkcs11cert osslsigncode_cert \
-key osslsigncode_cert \
-engineCtrl store_flags:0 \
-engineCtrl store_name:MY \
-engineCtrl PIN:yourpass \
-in yourapp.exe -out yourapp-signed.exe
```
You can check that the signed file is correct by right-clicking You can check that the signed file is correct by right-clicking
on it in Windows and choose Properties --> Digital Signatures, on it in Windows and choose Properties --> Digital Signatures,
and then choose the signature from the list, and click on and then choose the signature from the list, and click on

541
appx.c

File diff suppressed because it is too large Load Diff

341
cab.c
View File

@ -43,32 +43,38 @@ struct cab_ctx_st {
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx); static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
static int cab_hash_length_get(FILE_FORMAT_CTX *ctx); static int cab_hash_length_get(FILE_FORMAT_CTX *ctx);
static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached);
static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md); static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *cab_bio_free(BIO *hash, BIO *outdata); static void cab_bio_free(BIO *hash, BIO *outdata);
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx);
static int cab_is_detaching_supported(void);
FILE_FORMAT file_format_cab = { FILE_FORMAT file_format_cab = {
.ctx_new = cab_ctx_new, .ctx_new = cab_ctx_new,
.data_blob_get = cab_obsolete_link_get, .data_blob_get = cab_obsolete_link_get,
.pkcs7_contents_get = cab_pkcs7_contents_get,
.hash_length_get = cab_hash_length_get, .hash_length_get = cab_hash_length_get,
.check_file = cab_check_file,
.digest_calc = cab_digest_calc, .digest_calc = cab_digest_calc,
.verify_digests = cab_verify_digests, .verify_digests = cab_verify_digests,
.pkcs7_extract = cab_pkcs7_extract, .pkcs7_extract = cab_pkcs7_extract,
.pkcs7_extract_to_nest = cab_pkcs7_extract_to_nest,
.remove_pkcs7 = cab_remove_pkcs7, .remove_pkcs7 = cab_remove_pkcs7,
.pkcs7_prepare = cab_pkcs7_prepare, .process_data = cab_process_data,
.pkcs7_signature_new = cab_pkcs7_signature_new,
.append_pkcs7 = cab_append_pkcs7, .append_pkcs7 = cab_append_pkcs7,
.update_data_size = cab_update_data_size, .update_data_size = cab_update_data_size,
.bio_free = cab_bio_free, .bio_free = cab_bio_free,
.ctx_cleanup = cab_ctx_cleanup .ctx_cleanup = cab_ctx_cleanup,
.is_detaching_supported = cab_is_detaching_supported
}; };
/* Prototypes */ /* Prototypes */
@ -77,6 +83,7 @@ static int cab_add_jp_attribute(PKCS7 *p7, int jp);
static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t len, uint16_t flags); static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t len, uint16_t flags);
static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static int cab_check_file(FILE_FORMAT_CTX *ctx);
/* /*
* FILE_FORMAT method definitions * FILE_FORMAT method definitions
@ -104,12 +111,12 @@ static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (memcmp(options->indata, "MSCF", 4)) { if (memcmp(options->indata, "MSCF", 4)) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
cab_ctx = cab_ctx_get(options->indata, filesize); cab_ctx = cab_ctx_get(options->indata, filesize);
if (!cab_ctx) { if (!cab_ctx) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX)); ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
@ -151,6 +158,32 @@ static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* OK */ return dtype; /* OK */
} }
/*
* Allocate and return a data content to be signed.
* [in] ctx: structure holds input and output data
* [in] hash: message digest BIO
* [in] md: message digest algorithm
* [returns] data content
*/
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
{
ASN1_OCTET_STRING *content;
/* squash the unused parameter warning, use initialized message digest BIO */
(void)md;
/* Strip current signature and modify header */
if (ctx->cab_ctx->header_size == 20) {
if (!cab_modify_header(ctx, hash, NULL))
return NULL; /* FAILED */
} else {
if (!cab_add_header(ctx, hash, NULL))
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(hash, ctx);
return pkcs7_set_content(content);
}
/* /*
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash) * [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
@ -160,34 +193,6 @@ static int cab_hash_length_get(FILE_FORMAT_CTX *ctx)
return EVP_MD_size(ctx->options->md); return EVP_MD_size(ctx->options->md);
} }
/*
* Check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [in] detached: embedded/detached PKCS#7 signature switch
* [returns] 0 on error or 1 on success
*/
static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached)
{
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
}
if (detached) {
printf("Checking the specified catalog file\n\n");
return 1; /* OK */
}
if (ctx->cab_ctx->header_size != 20) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
return 1; /* OK */
}
/* /*
* Compute a message digest value of the signed or unsigned CAB file. * Compute a message digest value of the signed or unsigned CAB file.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -201,7 +206,7 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
BIO *bhash = BIO_new(BIO_f_md()); BIO *bhash = BIO_new(BIO_f_md());
if (!BIO_set_md(bhash, md)) { if (!BIO_set_md(bhash, md)) {
printf("Unable to set the message digest of BIO\n"); fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash); BIO_free_all(bhash);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -291,7 +296,7 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
nfolders--; nfolders--;
} }
if (idx != coffFiles) { if (idx != coffFiles) {
printf("Corrupt coffFiles value: 0x%08X\n", coffFiles); fprintf(stderr, "Corrupt coffFiles value: 0x%08X\n", coffFiles);
BIO_free_all(bhash); BIO_free_all(bhash);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -302,7 +307,7 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
} }
/* (variable) ab - the compressed data bytes */ /* (variable) ab - the compressed data bytes */
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) { if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
printf("Unable to calculate digest\n"); fprintf(stderr, "Unable to calculate digest\n");
BIO_free_all(bhash); BIO_free_all(bhash);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -338,17 +343,17 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
} }
} }
if (mdtype == -1) { if (mdtype == -1) {
printf("Failed to extract current message digest\n\n"); fprintf(stderr, "Failed to extract current message digest\n\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
md = EVP_get_digestbynid(mdtype); md = EVP_get_digestbynid(mdtype);
cmdbuf = cab_digest_calc(ctx, md); cmdbuf = cab_digest_calc(ctx, md);
if (!cmdbuf) { if (!cmdbuf) {
printf("Failed to calculate message digest\n\n"); fprintf(stderr, "Failed to calculate message digest\n\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!compare_digests(mdbuf, cmdbuf, mdtype)) { if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
printf("Signature verification: failed\n\n"); fprintf(stderr, "Signature verification: failed\n\n");
OPENSSL_free(cmdbuf); OPENSSL_free(cmdbuf);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -363,11 +368,23 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
*/ */
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx) static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{ {
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0 const u_char *blob;
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
if (!cab_check_file(ctx)) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
return pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen); blob = (u_char *)ctx->options->indata + ctx->cab_ctx->sigpos;
return d2i_PKCS7(NULL, &blob, ctx->cab_ctx->siglen);
}
/*
* Extract existing signature in DER format.
* [in] ctx: structure holds input and output data
* pointer to PKCS#7 structure
*/
static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
{
return cab_pkcs7_extract(ctx);
} }
/* /*
@ -379,14 +396,18 @@ static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx)
*/ */
static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
size_t i, written, len; size_t idx, written, len;
uint32_t tmp; uint32_t tmp;
uint16_t nfolders, flags; uint16_t nfolders, flags;
char *buf = OPENSSL_malloc(SIZE_64K); char *buf;
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)hash; (void)hash;
if (!cab_check_file(ctx)) {
return 1; /* FAILED, no signature */
}
buf = OPENSSL_malloc(SIZE_64K);
/* /*
* u1 signature[4] 4643534D MSCF: 0-3 * u1 signature[4] 4643534D MSCF: 0-3
* u4 reserved1 00000000: 4-7 * u4 reserved1 00000000: 4-7
@ -420,92 +441,100 @@ static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
* u2 iCabinet - number of this cabinet file in a set: 34-35 * u2 iCabinet - number of this cabinet file in a set: 34-35
*/ */
BIO_write(outdata, ctx->options->indata + 32, 4); BIO_write(outdata, ctx->options->indata + 32, 4);
i = cab_write_optional_names(outdata, ctx->options->indata, 60, flags); idx = cab_write_optional_names(outdata, ctx->options->indata, 60, flags);
if (idx >= ctx->cab_ctx->fileend) {
fprintf(stderr, "Corrupt CAB file - too short\n");
OPENSSL_free(buf);
return 0; /* FAILED */
}
/* /*
* (u8 * cFolders) CFFOLDER - structure contains information about * (u8 * cFolders) CFFOLDER - structure contains information about
* one of the folders or partial folders stored in this cabinet file * one of the folders or partial folders stored in this cabinet file
*/ */
nfolders = GET_UINT16_LE(ctx->options->indata + 26); nfolders = GET_UINT16_LE(ctx->options->indata + 26);
if (nfolders * 8 >= ctx->cab_ctx->fileend - idx) {
fprintf(stderr, "Corrupt cFolders value: 0x%08X\n", nfolders);
OPENSSL_free(buf);
return 0; /* FAILED */
}
while (nfolders) { while (nfolders) {
tmp = GET_UINT32_LE(ctx->options->indata + i); tmp = GET_UINT32_LE(ctx->options->indata + idx);
tmp -= 24; tmp -= 24;
PUT_UINT32_LE(tmp, buf); PUT_UINT32_LE(tmp, buf);
BIO_write(outdata, buf, 4); BIO_write(outdata, buf, 4);
BIO_write(outdata, ctx->options->indata + i + 4, 4); BIO_write(outdata, ctx->options->indata + idx + 4, 4);
i+=8; idx += 8;
nfolders--; nfolders--;
} }
OPENSSL_free(buf); OPENSSL_free(buf);
/* Write what's left - the compressed data bytes */ /* Write what's left - the compressed data bytes */
len = ctx->cab_ctx->fileend - ctx->cab_ctx->siglen - i; len = ctx->cab_ctx->fileend - ctx->cab_ctx->siglen - idx;
while (len > 0) { while (len > 0) {
if (!BIO_write_ex(outdata, ctx->options->indata + i, len, &written)) if (!BIO_write_ex(outdata, ctx->options->indata + idx, len, &written))
return 1; /* FAILED */ return 1; /* FAILED */
len -= written; len -= written;
i += written; idx += written;
} }
return 0; /* OK */ return 0; /* OK */
} }
/* /*
* Obtain an existing signature or create a new one. * Modify specific type data and calculate a hash (message digest) of data.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [returns] pointer to PKCS#7 structure * [returns] 1 on error or 0 on success
*/ */
static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
PKCS7 *cursig = NULL, *p7 = NULL;
/* Strip current signature and modify header */ /* Strip current signature and modify header */
if (ctx->cab_ctx->header_size == 20) { if (ctx->cab_ctx->header_size == 20) {
if (!cab_modify_header(ctx, hash, outdata)) if (!cab_modify_header(ctx, hash, outdata))
return NULL; /* FAILED */ return 0; /* FAILED */
} else { } else {
if (!cab_add_header(ctx, hash, outdata)) if (!cab_add_header(ctx, hash, outdata))
return NULL; /* FAILED */ return 0; /* FAILED */
} }
/* Obtain a current signature from previously-signed file */ return 1; /* OK */
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest) }
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|| ctx->options->cmd == CMD_ADD) { /*
cursig = pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen); * Create a new PKCS#7 signature.
if (!cursig) { * [in, out] ctx: structure holds input and output data
printf("Unable to extract existing signature\n"); * [out] hash: message digest BIO
return NULL; /* FAILED */ * [returns] pointer to PKCS#7 structure
} */
if (ctx->options->cmd == CMD_ADD) static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
p7 = cursig; {
ASN1_OCTET_STRING *content;
PKCS7 *p7 = pkcs7_create(ctx);
if (!p7) {
fprintf(stderr, "Creating a new signature failed\n");
return NULL; /* FAILED */
} }
if (ctx->options->cmd == CMD_ATTACH) { if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) {
/* Obtain an existing PKCS#7 signature */ fprintf(stderr, "Adding jp attribute failed\n");
p7 = pkcs7_get_sigfile(ctx); PKCS7_free(p7);
if (!p7) { return NULL; /* FAILED */
printf("Unable to extract valid signature\n");
PKCS7_free(cursig);
return NULL; /* FAILED */
}
} else if (ctx->options->cmd == CMD_SIGN) {
/* Create a new PKCS#7 signature */
p7 = pkcs7_create(ctx);
if (!p7) {
printf("Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) {
printf("Adding jp attribute failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7, hash, ctx)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
} }
if (ctx->options->nest) if (!add_indirect_data_object(p7)) {
ctx->options->prevsig = cursig; fprintf(stderr, "Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
fprintf(stderr, "Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
}
if (!sign_spc_indirect_data_content(p7, content)) {
fprintf(stderr, "Failed to set signed content\n");
PKCS7_free(p7);
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
ASN1_OCTET_STRING_free(content);
return p7; return p7;
} }
@ -527,7 +556,7 @@ static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
if (((len = i2d_PKCS7(p7, NULL)) <= 0) if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|| (p = OPENSSL_malloc((size_t)len)) == NULL) { || (p = OPENSSL_malloc((size_t)len)) == NULL) {
printf("i2d_PKCS memory allocation failed: %d\n", len); fprintf(stderr, "i2d_PKCS memory allocation failed: %d\n", len);
return 1; /* FAILED */ return 1; /* FAILED */
} }
i2d_PKCS7(p7, &p); i2d_PKCS7(p7, &p);
@ -580,40 +609,33 @@ static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] none * [returns] none
*/ */
static BIO *cab_bio_free(BIO *hash, BIO *outdata) static void cab_bio_free(BIO *hash, BIO *outdata)
{ {
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)outdata; (void)outdata;
BIO_free_all(hash); BIO_free_all(hash);
return NULL;
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and CAB format specific structure, * Deallocate a FILE_FORMAT_CTX structure and CAB format specific structure,
* unmap indata file, unlink outfile. * unmap indata file.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [in] outdata: outdata file BIO * [in] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
if (ctx->options->outfile) {
#ifdef WIN32
_unlink(ctx->options->outfile);
#else
unlink(ctx->options->outfile);
#endif /* WIN32 */
}
}
unmap_file(ctx->options->indata, ctx->cab_ctx->fileend); unmap_file(ctx->options->indata, ctx->cab_ctx->fileend);
OPENSSL_free(ctx->cab_ctx); OPENSSL_free(ctx->cab_ctx);
OPENSSL_free(ctx); OPENSSL_free(ctx);
} }
static int cab_is_detaching_supported(void)
{
return 1; /* OK */
}
/* /*
* CAB helper functions * CAB helper functions
*/ */
@ -631,19 +653,19 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
uint16_t flags; uint16_t flags;
if (filesize < 44) { if (filesize < 44) {
printf("CAB file is too short\n"); fprintf(stderr, "CAB file is too short\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
reserved = GET_UINT32_LE(indata + 4); reserved = GET_UINT32_LE(indata + 4);
if (reserved) { if (reserved) {
printf("Reserved1: 0x%08X\n", reserved); fprintf(stderr, "Reserved1: 0x%08X\n", reserved);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* flags specify bit-mapped values that indicate the presence of optional data */ /* flags specify bit-mapped values that indicate the presence of optional data */
flags = GET_UINT16_LE(indata + 30); flags = GET_UINT16_LE(indata + 30);
if (flags & FLAG_PREV_CABINET) { if (flags & FLAG_PREV_CABINET) {
/* FLAG_NEXT_CABINET works */ /* FLAG_NEXT_CABINET works */
printf("Multivolume cabinet file is unsupported: flags 0x%04X\n", flags); fprintf(stderr, "Multivolume cabinet file is unsupported: flags 0x%04X\n", flags);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (flags & FLAG_RESERVE_PRESENT) { if (flags & FLAG_RESERVE_PRESENT) {
@ -653,12 +675,12 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
*/ */
header_size = GET_UINT32_LE(indata + 36); header_size = GET_UINT32_LE(indata + 36);
if (header_size != 20) { if (header_size != 20) {
printf("Additional header size: 0x%08X\n", header_size); fprintf(stderr, "Additional header size: 0x%08X\n", header_size);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
reserved = GET_UINT32_LE(indata + 40); reserved = GET_UINT32_LE(indata + 40);
if (reserved != 0x00100000) { if (reserved != 0x00100000) {
printf("abReserved: 0x%08X\n", reserved); fprintf(stderr, "abReserved: 0x%08X\n", reserved);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* /*
@ -673,13 +695,13 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
sigpos = GET_UINT32_LE(indata + 44); sigpos = GET_UINT32_LE(indata + 44);
siglen = GET_UINT32_LE(indata + 48); siglen = GET_UINT32_LE(indata + 48);
if ((sigpos < filesize && sigpos + siglen != filesize) || (sigpos >= filesize)) { if ((sigpos < filesize && sigpos + siglen != filesize) || (sigpos >= filesize)) {
printf("Additional data offset:\t%u bytes\nAdditional data size:\t%u bytes\n", fprintf(stderr, "Additional data offset:\t%u bytes\nAdditional data size:\t%u bytes\n",
sigpos, siglen); sigpos, siglen);
printf("File size:\t\t%u bytes\n", filesize); fprintf(stderr, "File size:\t\t%u bytes\n", filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) { if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) {
printf("Corrupt signature\n"); fprintf(stderr, "Corrupt signature\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
} }
@ -790,7 +812,7 @@ static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t i, uin
*/ */
static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
size_t i, written, len; size_t idx, written, len;
uint16_t nfolders, flags; uint16_t nfolders, flags;
u_char buf[] = {0x00, 0x00}; u_char buf[] = {0x00, 0x00};
@ -828,24 +850,32 @@ static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
/* u4 abReserve: 56-59 */ /* u4 abReserve: 56-59 */
BIO_write(hash, ctx->options->indata + 56, 4); BIO_write(hash, ctx->options->indata + 56, 4);
i = cab_write_optional_names(outdata, ctx->options->indata, 60, flags); idx = cab_write_optional_names(outdata, ctx->options->indata, 60, flags);
if (idx >= ctx->cab_ctx->fileend) {
fprintf(stderr, "Corrupt CAB file - too short\n");
return 0; /* FAILED */
}
/* /*
* (u8 * cFolders) CFFOLDER - structure contains information about * (u8 * cFolders) CFFOLDER - structure contains information about
* one of the folders or partial folders stored in this cabinet file * one of the folders or partial folders stored in this cabinet file
*/ */
nfolders = GET_UINT16_LE(ctx->options->indata + 26); nfolders = GET_UINT16_LE(ctx->options->indata + 26);
if (nfolders * 8 >= ctx->cab_ctx->fileend - idx) {
fprintf(stderr, "Corrupt cFolders value: 0x%08X\n", nfolders);
return 0; /* FAILED */
}
while (nfolders) { while (nfolders) {
BIO_write(hash, ctx->options->indata + i, 8); BIO_write(hash, ctx->options->indata + idx, 8);
i += 8; idx += 8;
nfolders--; nfolders--;
} }
/* Write what's left - the compressed data bytes */ /* Write what's left - the compressed data bytes */
len = ctx->cab_ctx->sigpos - i; len = ctx->cab_ctx->sigpos - idx;
while (len > 0) { while (len > 0) {
if (!BIO_write_ex(hash, ctx->options->indata + i, len, &written)) if (!BIO_write_ex(hash, ctx->options->indata + idx, len, &written))
return 0; /* FAILED */ return 0; /* FAILED */
len -= written; len -= written;
i += written; idx += written;
} }
return 1; /* OK */ return 1; /* OK */
} }
@ -859,7 +889,7 @@ static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
*/ */
static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
size_t i, written, len; size_t idx, written, len;
uint32_t tmp; uint32_t tmp;
uint16_t nfolders, flags; uint16_t nfolders, flags;
u_char cabsigned[] = { u_char cabsigned[] = {
@ -904,29 +934,62 @@ static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
BIO_write(outdata, cabsigned, 20); BIO_write(outdata, cabsigned, 20);
BIO_write(hash, cabsigned+20, 4); BIO_write(hash, cabsigned+20, 4);
i = cab_write_optional_names(outdata, ctx->options->indata, 36, flags); idx = cab_write_optional_names(outdata, ctx->options->indata, 36, flags);
if (idx >= ctx->cab_ctx->fileend) {
fprintf(stderr, "Corrupt CAB file - too short\n");
OPENSSL_free(buf);
return 0; /* FAILED */
}
/* /*
* (u8 * cFolders) CFFOLDER - structure contains information about * (u8 * cFolders) CFFOLDER - structure contains information about
* one of the folders or partial folders stored in this cabinet file * one of the folders or partial folders stored in this cabinet file
*/ */
nfolders = GET_UINT16_LE(ctx->options->indata + 26); nfolders = GET_UINT16_LE(ctx->options->indata + 26);
if (nfolders * 8 >= ctx->cab_ctx->fileend - idx) {
fprintf(stderr, "Corrupt cFolders value: 0x%08X\n", nfolders);
OPENSSL_free(buf);
return 0; /* FAILED */
}
while (nfolders) { while (nfolders) {
tmp = GET_UINT32_LE(ctx->options->indata + i); tmp = GET_UINT32_LE(ctx->options->indata + idx);
tmp += 24; tmp += 24;
PUT_UINT32_LE(tmp, buf); PUT_UINT32_LE(tmp, buf);
BIO_write(hash, buf, 4); BIO_write(hash, buf, 4);
BIO_write(hash, ctx->options->indata + i + 4, 4); BIO_write(hash, ctx->options->indata + idx + 4, 4);
i += 8; idx += 8;
nfolders--; nfolders--;
} }
OPENSSL_free(buf); OPENSSL_free(buf);
/* Write what's left - the compressed data bytes */ /* Write what's left - the compressed data bytes */
len = ctx->cab_ctx->fileend - i; len = ctx->cab_ctx->fileend - idx;
while (len > 0) { while (len > 0) {
if (!BIO_write_ex(hash, ctx->options->indata + i, len, &written)) if (!BIO_write_ex(hash, ctx->options->indata + idx, len, &written))
return 0; /* FAILED */ return 0; /* FAILED */
len -= written; len -= written;
i += written; idx += written;
}
return 1; /* OK */
}
/*
* Check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int cab_check_file(FILE_FORMAT_CTX *ctx)
{
if (!ctx) {
fprintf(stderr, "Init error\n");
return 0; /* FAILED */
}
if (ctx->cab_ctx->header_size != 20) {
fprintf(stderr, "No signature found\n");
return 0; /* FAILED */
}
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
fprintf(stderr, "No signature found\n");
return 0; /* FAILED */
} }
return 1; /* OK */ return 1; /* OK */
} }

428
cat.c
View File

@ -5,34 +5,49 @@
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org> * Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
* *
* Catalog files are a bit odd, in that they are only a PKCS7 blob. * Catalog files are a bit odd, in that they are only a PKCS7 blob.
* CAT files do not support nesting (multiple signature)
*/ */
#include "osslsigncode.h" #include "osslsigncode.h"
#include "helpers.h" #include "helpers.h"
const u_char pkcs7_signed_data[] = { typedef struct {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, ASN1_BMPSTRING *tag;
0x01, 0x07, 0x02, ASN1_INTEGER *flags;
}; ASN1_OCTET_STRING *value;
} CatNameValueContent;
DECLARE_ASN1_FUNCTIONS(CatNameValueContent)
ASN1_SEQUENCE(CatNameValueContent) = {
ASN1_SIMPLE(CatNameValueContent, tag, ASN1_BMPSTRING),
ASN1_SIMPLE(CatNameValueContent, flags, ASN1_INTEGER),
ASN1_SIMPLE(CatNameValueContent, value, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CatNameValueContent)
IMPLEMENT_ASN1_FUNCTIONS(CatNameValueContent)
struct cat_ctx_st { struct cat_ctx_st {
uint32_t sigpos; uint32_t sigpos;
uint32_t siglen; uint32_t siglen;
uint32_t fileend; uint32_t fileend;
PKCS7 *p7;
}; };
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *cat_bio_free(BIO *hash, BIO *outdata); static void cat_bio_free(BIO *hash, BIO *outdata);
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx);
FILE_FORMAT file_format_cat = { FILE_FORMAT file_format_cat = {
.ctx_new = cat_ctx_new, .ctx_new = cat_ctx_new,
.verify_digests = cat_verify_digests,
.pkcs7_extract = cat_pkcs7_extract, .pkcs7_extract = cat_pkcs7_extract,
.pkcs7_prepare = cat_pkcs7_prepare, .pkcs7_signature_new = cat_pkcs7_signature_new,
.append_pkcs7 = cat_append_pkcs7, .append_pkcs7 = cat_append_pkcs7,
.bio_free = cat_bio_free, .bio_free = cat_bio_free,
.ctx_cleanup = cat_ctx_cleanup, .ctx_cleanup = cat_ctx_cleanup,
@ -40,6 +55,14 @@ FILE_FORMAT file_format_cat = {
/* Prototypes */ /* Prototypes */
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize); static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
static int cat_add_content_type(PKCS7 *p7, PKCS7 *cursig);
static int cat_sign_content(PKCS7 *p7, PKCS7 *contents);
static int cat_list_content(PKCS7 *p7);
static int cat_print_content_member_digest(ASN1_TYPE *content);
static int cat_print_content_member_name(ASN1_TYPE *content);
static void cat_print_base64(ASN1_OCTET_STRING *value);
static void cat_print_utf16_as_ascii(ASN1_OCTET_STRING *value);
static int cat_check_file(FILE_FORMAT_CTX *ctx);
/* /*
* FILE_FORMAT method definitions * FILE_FORMAT method definitions
@ -58,16 +81,8 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
CAT_CTX *cat_ctx; CAT_CTX *cat_ctx;
uint32_t filesize; uint32_t filesize;
/* squash unused parameter warnings */ if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH || options->cmd == CMD_EXTRACT_DATA) {
(void)outdata; fprintf(stderr, "Unsupported command\n");
(void)hash;
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH) {
printf("Unsupported command\n");
return NULL; /* FAILED */
}
if (options->cmd == CMD_VERIFY) {
printf("Use -catalog option\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
filesize = get_file_size(options->infile); filesize = get_file_size(options->infile);
@ -78,15 +93,9 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
if (!options->indata) { if (!options->indata) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* the maximum size of a supported cat file is (2^24 -1) bytes */
if (memcmp(options->indata + ((GET_UINT8_LE(options->indata+1) == 0x82) ? 4 : 5),
pkcs7_signed_data, sizeof pkcs7_signed_data)) {
unmap_file(options->infile, filesize);
return NULL; /* FAILED */
}
cat_ctx = cat_ctx_get(options->indata, filesize); cat_ctx = cat_ctx_get(options->indata, filesize);
if (!cat_ctx) { if (!cat_ctx) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX)); ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
@ -97,9 +106,8 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
/* Push hash on outdata, if hash is NULL the function does nothing */ /* Push hash on outdata, if hash is NULL the function does nothing */
BIO_push(hash, outdata); BIO_push(hash, outdata);
if (options->nest) if (options->cmd == CMD_VERIFY)
/* I've not tried using set_nested_signature as signtool won't do this */ printf("Warning: Use -catalog option to verify that a file, listed in catalog file, is signed\n");
printf("Warning: CAT files do not support nesting (multiple signature)\n");
if (options->jp >= 0) if (options->jp >= 0)
printf("Warning: -jp option is only valid for CAB files\n"); printf("Warning: -jp option is only valid for CAB files\n");
if (options->pagehash == 1) if (options->pagehash == 1)
@ -109,6 +117,19 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
return ctx; return ctx;
} }
/*
* ContentInfo value is the inner content of pkcs7-signedData.
* An extra verification is not necessary when a content type data
* is the inner content of the signed-data type.
*/
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
{
/* squash unused parameter warnings */
(void)ctx;
(void)p7;
return 1; /* OK */
}
/* /*
* Extract existing signature in DER format. * Extract existing signature in DER format.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -116,76 +137,58 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
*/ */
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx) static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{ {
return pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen); if (!cat_check_file(ctx)) {
return NULL; /* FAILED */
}
return PKCS7_dup(ctx->cat_ctx->p7);
} }
/* /*
* Obtain an existing signature or create a new one. * Create a new PKCS#7 signature.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO (unused) * [out] hash: message digest BIO (unused)
* [out] outdata: outdata file BIO (unused)
* [returns] pointer to PKCS#7 structure * [returns] pointer to PKCS#7 structure
*/ */
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
{ {
PKCS7 *cursig = NULL, *p7 = NULL; PKCS7 *p7 = NULL;
/* squash unused parameter warnings */ /* squash unused parameter warnings */
(void)outdata;
(void)hash; (void)hash;
/* Obtain an existing signature */ p7 = pkcs7_create(ctx);
cursig = pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen); if (!p7) {
if (!cursig) { fprintf(stderr, "Creating a new signature failed\n");
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) { if (!ctx->cat_ctx->p7 || !ctx->cat_ctx->p7->d.sign || !ctx->cat_ctx->p7->d.sign->contents) {
p7 = cursig; fprintf(stderr, "Failed to get content\n");
} else if (ctx->options->cmd == CMD_SIGN) { PKCS7_free(p7);
/* Create a new signature */ return NULL; /* FAILED */
p7 = pkcs7_create(ctx); }
if (!p7) { if (!cat_add_content_type(p7, ctx->cat_ctx->p7)) {
printf("Creating a new signature failed\n"); fprintf(stderr, "Adding content type failed\n");
PKCS7_free(cursig); PKCS7_free(p7);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!add_ms_ctl_object(p7, cursig)) { if (!cat_sign_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
printf("Adding MS_CTL_OBJID failed\n"); fprintf(stderr, "Failed to set signed content\n");
PKCS7_free(p7); PKCS7_free(p7);
PKCS7_free(cursig); return NULL; /* FAILED */
return NULL; /* FAILED */
}
PKCS7_free(cursig);
} }
return p7; /* OK */ return p7; /* OK */
} }
/* /*
* Append signature to the outfile. * Append signature to the outfile.
* [in, out] ctx: structure holds input and output data (unused) * [in, out] ctx: structure holds input and output data
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [in] p7: PKCS#7 signature * [in] p7: PKCS#7 signature
* [returns] 1 on error or 0 on success * [returns] 1 on error or 0 on success
*/ */
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7) static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
{ {
u_char *p = NULL; return data_write_pkcs7(ctx, outdata, p7);
int len; /* signature length */
/* squash the unused parameter warning */
(void)ctx;
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
printf("i2d_PKCS memory allocation failed: %d\n", len);
return 1; /* FAILED */
}
i2d_PKCS7(p7, &p);
p -= len;
i2d_PKCS7_bio(outdata, p7);
OPENSSL_free(p);
return 0; /* OK */
} }
/* /*
@ -194,36 +197,25 @@ static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] none * [returns] none
*/ */
static BIO *cat_bio_free(BIO *hash, BIO *outdata) static void cat_bio_free(BIO *hash, BIO *outdata)
{ {
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)outdata; (void)outdata;
BIO_free_all(hash); BIO_free_all(hash);
return NULL;
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and CAT format specific structure, * Deallocate a FILE_FORMAT_CTX structure and CAT format specific structure,
* unmap indata file, unlink outfile. * unmap indata file.
* [in, out] ctx: structure holds all input and output data * [in, out] ctx: structure holds all input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [in] outdata: outdata file BIO * [in] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
if (ctx->options->outfile) {
#ifdef WIN32
_unlink(ctx->options->outfile);
#else
unlink(ctx->options->outfile);
#endif /* WIN32 */
}
}
unmap_file(ctx->options->indata, ctx->cat_ctx->fileend); unmap_file(ctx->options->indata, ctx->cat_ctx->fileend);
PKCS7_free(ctx->cat_ctx->p7);
OPENSSL_free(ctx->cat_ctx); OPENSSL_free(ctx->cat_ctx);
OPENSSL_free(ctx); OPENSSL_free(ctx);
} }
@ -233,25 +225,275 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
*/ */
/* /*
* Verify mapped CAT file TODO and create CAT format specific structure. * Verify mapped PKCS#7 (CAT) file and create CAT format specific structure.
* [in] indata: mapped CAT file (unused) * [in] indata: mapped file
* [in] filesize: size of CAT file * [in] filesize: size of file
* [returns] pointer to CAT format specific structure * [returns] pointer to CAT format specific structure
*/ */
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize) static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
{ {
CAT_CTX *cat_ctx; CAT_CTX *cat_ctx;
PKCS7 *p7;
/* squash the unused parameter warning */ p7 = pkcs7_read_data(indata, filesize);
(void)indata; if (!p7)
return NULL; /* FAILED */
if (!PKCS7_type_is_signed(p7)) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX)); cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
cat_ctx->p7 = p7;
cat_ctx->sigpos = 0; cat_ctx->sigpos = 0;
cat_ctx->siglen = filesize; cat_ctx->siglen = filesize;
cat_ctx->fileend = filesize; cat_ctx->fileend = filesize;
return cat_ctx; /* OK */ return cat_ctx; /* OK */
} }
/*
* Add a content type OID to the PKCS#7 signature structure.
* The content type can be:
* - "1.3.6.1.4.1.311.10.1" (MS_CTL_OBJID) for Certificate Trust Lists (CTL),
* - "1.3.6.1.4.1.311.2.1.4" (SPC_INDIRECT_DATA_OBJID) for Authenticode data.
* [in, out] p7: new PKCS#7 signature
* [in] cursig: current PKCS#7 signature to determine content type
* [returns] 0 on error or 1 on success
*/
static int cat_add_content_type(PKCS7 *p7, PKCS7 *cursig)
{
const char *content_type;
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
PKCS7_SIGNER_INFO *si;
if (is_content_type(cursig, SPC_INDIRECT_DATA_OBJID)) {
/* Authenticode content */
content_type = SPC_INDIRECT_DATA_OBJID;
} else if (is_content_type(cursig, MS_CTL_OBJID)) {
/* Certificate Trust List (CTL) */
content_type = MS_CTL_OBJID;
} else {
fprintf(stderr, "Unsupported content type\n");
return 0; /* FAILED */
}
signer_info = PKCS7_get_signer_info(p7);
if (!signer_info)
return 0; /* FAILED */
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si)
return 0; /* FAILED */
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
V_ASN1_OBJECT, OBJ_txt2obj(content_type, 1)))
return 0; /* FAILED */
return 1; /* OK */
}
/*
* Sign the MS CTL blob.
* Certificate Trust List (CTL) is a list of file names or thumbprints.
* All the items in this list are authenticated (approved) by the signing entity.
* [in, out] p7: new PKCS#7 signature
* [in] contents: Certificate Trust List (CTL)
* [returns] 0 on error or 1 on success
*/
static int cat_sign_content(PKCS7 *p7, PKCS7 *contents)
{
u_char *content;
int seqhdrlen, content_length;
if (!contents->d.other || !contents->d.other->value.sequence
|| !contents->d.other->value.sequence->data) {
fprintf(stderr, "Failed to get content value\n");
return 0; /* FAILED */
}
seqhdrlen = asn1_simple_hdr_len(contents->d.other->value.sequence->data,
contents->d.other->value.sequence->length);
content = contents->d.other->value.sequence->data + seqhdrlen;
content_length = contents->d.other->value.sequence->length - seqhdrlen;
if (!pkcs7_sign_content(p7, content, content_length)) {
fprintf(stderr, "Failed to sign content\n");
return 0; /* FAILED */
}
if (!PKCS7_set_content(p7, PKCS7_dup(contents))) {
fprintf(stderr, "PKCS7_set_content failed\n");
return 0; /* FAILED */
}
return 1; /* OK */
}
/*
* Print each member of the CAT file by using the "-verbose" option.
* [in, out] p7: catalog file to verify
* [returns] 1 on error or 0 on success
*/
static int cat_list_content(PKCS7 *p7)
{
MsCtlContent *ctlc;
int i;
ctlc = ms_ctl_content_get(p7);
if (!ctlc) {
fprintf(stderr, "Failed to extract MS_CTL_OBJID data\n");
return 1; /* FAILED */
}
printf("\nCatalog members:\n");
for (i = 0; i < sk_CatalogInfo_num(ctlc->header_attributes); i++) {
int j, found = 0;
CatalogInfo *header_attr = sk_CatalogInfo_value(ctlc->header_attributes, i);
if (header_attr == NULL)
continue;
for (j = 0; j < sk_CatalogAuthAttr_num(header_attr->attributes); j++) {
char object_txt[128];
CatalogAuthAttr *attribute;
ASN1_TYPE *content;
attribute = sk_CatalogAuthAttr_value(header_attr->attributes, j);
if (!attribute)
continue;
content = catalog_content_get(attribute);
if (!content)
continue;
object_txt[0] = 0x00;
OBJ_obj2txt(object_txt, sizeof object_txt, attribute->type, 1);
if (!strcmp(object_txt, CAT_NAMEVALUE_OBJID)) {
/* CAT_NAMEVALUE_OBJID OID: 1.3.6.1.4.1.311.12.2.1 */
found |= cat_print_content_member_name(content);
} else if (!strcmp(object_txt, SPC_INDIRECT_DATA_OBJID)) {
/* SPC_INDIRECT_DATA_OBJID OID: 1.3.6.1.4.1.311.2.1.4 */
found |= cat_print_content_member_digest(content);
}
ASN1_TYPE_free(content);
}
if (found)
printf("\n");
}
MsCtlContent_free(ctlc);
ERR_print_errors_fp(stderr);
return 0; /* OK */
}
/*
* Print a hash algorithm and a message digest from the SPC_INDIRECT_DATA_OBJID attribute.
* [in] content: catalog file content
* [returns] 0 on error or 1 on success
*/
static int cat_print_content_member_digest(ASN1_TYPE *content)
{
SpcIndirectDataContent *idc;
u_char mdbuf[EVP_MAX_MD_SIZE];
const u_char *data ;
int mdtype = -1;
ASN1_STRING *value;
value = content->value.sequence;
data = ASN1_STRING_get0_data(value);
idc = d2i_SpcIndirectDataContent(NULL, &data, ASN1_STRING_length(value));
if (!idc)
return 0; /* FAILED */
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
/* get a digest algorithm a message digest of the file from the content */
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
}
SpcIndirectDataContent_free(idc);
if (mdtype == -1) {
fprintf(stderr, "Failed to extract current message digest\n\n");
return 0; /* FAILED */
}
printf("\tHash algorithm: %s\n", OBJ_nid2sn(mdtype));
print_hash("\tMessage digest", "", mdbuf, EVP_MD_size(EVP_get_digestbynid(mdtype)));
return 1; /* OK */
}
/*
* Print a file name from the CAT_NAMEVALUE_OBJID attribute.
* [in] content: catalog file content
* [returns] 0 on error or 1 on success
*/
static int cat_print_content_member_name(ASN1_TYPE *content)
{
CatNameValueContent *nvc;
const u_char *data = NULL;
ASN1_STRING *value;
value = content->value.sequence;
data = ASN1_STRING_get0_data(value);
nvc = d2i_CatNameValueContent(NULL, &data, ASN1_STRING_length(value));
if (!nvc) {
return 0; /* FAILED */
}
printf("\tFile name: ");
if (ASN1_INTEGER_get(nvc->flags) & 0x00020000) {
cat_print_base64(nvc->value);
} else {
cat_print_utf16_as_ascii(nvc->value);
}
printf("\n");
CatNameValueContent_free(nvc);
return 1; /* OK */
}
/*
* Print a CAT_NAMEVALUE_OBJID attribute represented in base-64 encoding.
* [in] value: catalog member file name
* [returns] none
*/
static void cat_print_base64(ASN1_OCTET_STRING *value)
{
BIO *stdbio, *b64;
stdbio = BIO_new_fp(stdout, BIO_NOCLOSE);
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
stdbio = BIO_push(b64, stdbio);
ASN1_STRING_print_ex(stdbio, value, 0);
BIO_free_all(stdbio);
}
/*
* Print a CAT_NAMEVALUE_OBJID attribute represented in plaintext.
* [in] value: catalog member file name
* [returns] none
*/
static void cat_print_utf16_as_ascii(ASN1_OCTET_STRING *value)
{
const u_char *data;
int len, i;
data = ASN1_STRING_get0_data(value);
len = ASN1_STRING_length(value);
for (i = 0; i < len && (data[i] || data[i+1]); i+=2)
putchar(isprint(data[i]) && !data[i+1] ? data[i] : '.');
}
/*
* Check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int cat_check_file(FILE_FORMAT_CTX *ctx)
{
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
PKCS7_SIGNER_INFO *si;
if (!ctx) {
fprintf(stderr, "Init error\n");
return 0; /* FAILED */
}
signer_info = PKCS7_get_signer_info(ctx->cat_ctx->p7);
if (!signer_info) {
fprintf(stderr, "Failed catalog file\n");
return 0; /* FAILED */
}
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si) {
fprintf(stderr, "No signature found\n");
return 0; /* FAILED */
}
if (ctx->options->verbose) {
(void)cat_list_content(ctx->cat_ctx->p7);
}
return 1; /* OK */
}
/* /*
Local Variables: Local Variables:
c-basic-offset: 4 c-basic-offset: 4

File diff suppressed because it is too large Load Diff

9038
code_signing_ca.pem Normal file

File diff suppressed because it is too large Load Diff

41
get_code_signing_ca.py Executable file
View File

@ -0,0 +1,41 @@
#!/usr/bin/python3
# © 2024 Michal Trojnara
# This script downloads Microsoft code signing certificates
# Tor is required for this script to work
# Redirect the script output to a PEM file
from sys import stderr
from time import sleep
from csv import reader
from requests import get
from requests.exceptions import RequestException
from concurrent.futures import ThreadPoolExecutor
def download_cert(hash):
for attempt in range(10):
if attempt > 0:
sleep(10)
try:
creds = f'{attempt}{hash}:{attempt}{hash}'
resp = get(f'https://crt.sh/?d={hash}',
proxies=dict(https=f'socks5://{creds}@127.0.0.1:9050'))
resp.raise_for_status()
print('.', file=stderr, end='')
stderr.flush()
return resp.content.decode('utf-8')
except RequestException as e:
print(f'\nAttempt {attempt}: {e}', file=stderr)
print('\nGiving up on', hash, file=stderr)
resp = get('https://ccadb-public.secure.force.com/microsoft/IncludedCACertificateReportForMSFTCSV')
resp.raise_for_status()
lines = resp.content.decode('utf-8').splitlines()[1:]
hashes = [row[4] for row in reader(lines)
if row[0] != 'Disabled'
or row[4] == 'F38406E540D7A9D90CB4A9479299640FFB6DF9E224ECC7A01C0D9558D8DAD77D']
with ThreadPoolExecutor(max_workers=20) as executor:
certs = executor.map(download_cert, hashes)
for cert in certs:
if cert is not None:
print(cert)
print('\nDone', file=stderr)

689
helpers.c
View File

@ -9,12 +9,14 @@
#include "helpers.h" #include "helpers.h"
/* Prototypes */ /* Prototypes */
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig);
static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx); static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx);
static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx); static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx);
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer);
static int X509_compare(const X509 *const *a, const X509 *const *b);
/* /*
* Common functions * Common functions
@ -35,16 +37,16 @@ uint32_t get_file_size(const char *infile)
ret = stat(infile, &st); ret = stat(infile, &st);
#endif #endif
if (ret) { if (ret) {
printf("Failed to open file: %s\n", infile); fprintf(stderr, "Failed to open file: %s\n", infile);
return 0; return 0;
} }
if (st.st_size < 4) { if (st.st_size < 4) {
printf("Unrecognized file type - file is too short: %s\n", infile); fprintf(stderr, "Unrecognized file type - file is too short: %s\n", infile);
return 0; return 0;
} }
if (st.st_size > UINT32_MAX) { if (st.st_size > UINT32_MAX) {
printf("Unsupported file - too large: %s\n", infile); fprintf(stderr, "Unsupported file - too large: %s\n", infile);
return 0; return 0;
} }
return (uint32_t)st.st_size; return (uint32_t)st.st_size;
@ -84,7 +86,7 @@ char *map_file(const char *infile, const size_t size)
} }
close(fd); close(fd);
#else #else
printf("No file mapping function\n"); fprintf(stderr, "No file mapping function\n");
return NULL; return NULL;
#endif /* HAVE_SYS_MMAN_H */ #endif /* HAVE_SYS_MMAN_H */
#endif /* WIN32 */ #endif /* WIN32 */
@ -109,113 +111,52 @@ void unmap_file(char *indata, const size_t size)
} }
/* /*
* [in, out] si: PKCS7_SIGNER_INFO structure * Retrieve a decoded PKCS#7 structure
* [in] ctx: FILE_FORMAT_CTX structure * [in] data: encoded PEM or DER data
* [returns] 0 on error or 1 on success * [in] size: data size
*/
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
SpcSpOpusInfo *opus;
ASN1_STRING *astr;
int len;
u_char *p = NULL;
opus = spc_sp_opus_info_create(ctx);
if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
SpcSpOpusInfo_free(opus);
return 0; /* FAILED */
}
i2d_SpcSpOpusInfo(opus, &p);
p -= len;
astr = ASN1_STRING_new();
ASN1_STRING_set(astr, p, len);
OPENSSL_free(p);
SpcSpOpusInfo_free(opus);
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
V_ASN1_SEQUENCE, astr);
}
/*
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
static const u_char purpose_ind[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
};
static const u_char purpose_comm[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
};
ASN1_STRING *purpose = ASN1_STRING_new();
if (ctx->options->comm) {
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
} else {
ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
}
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
V_ASN1_SEQUENCE, purpose);
}
/*
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
* adding the _current_ time. This allows to create a deterministic signature
* when no trusted timestamp server was specified, making osslsigncode
* behaviour closer to signtool.exe (which doesn't include any non-trusted
* time in this case.)
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
if (ctx->options->time == INVALID_TIME) /* -time option was not specified */
return 1; /* SUCCESS */
return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,
ASN1_TIME_adj(NULL, ctx->options->time, 0, 0));
}
/*
* Retrieve a decoded PKCS#7 structure corresponding to the signature
* stored in the "sigin" file
* CMD_ATTACH command specific
* [in] ctx: structure holds input and output data
* [returns] pointer to PKCS#7 structure * [returns] pointer to PKCS#7 structure
*/ */
PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx) PKCS7 *pkcs7_read_data(char *data, uint32_t size)
{ {
PKCS7 *p7 = NULL; PKCS7 *p7 = NULL;
uint32_t filesize;
char *indata;
BIO *bio; BIO *bio;
const char pemhdr[] = "-----BEGIN PKCS7-----"; const char pemhdr[] = "-----BEGIN PKCS7-----";
filesize = get_file_size(ctx->options->sigfile); bio = BIO_new_mem_buf(data, (int)size);
if (!filesize) { if (size >= sizeof pemhdr && !memcmp(data, pemhdr, sizeof pemhdr - 1)) {
return NULL; /* FAILED */
}
indata = map_file(ctx->options->sigfile, filesize);
if (!indata) {
printf("Failed to open file: %s\n", ctx->options->sigfile);
return NULL; /* FAILED */
}
bio = BIO_new_mem_buf(indata, (int)filesize);
if (filesize >= sizeof pemhdr && !memcmp(indata, pemhdr, sizeof pemhdr - 1)) {
/* PEM format */ /* PEM format */
p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
} else { /* DER format */ } else { /* DER format */
p7 = d2i_PKCS7_bio(bio, NULL); p7 = d2i_PKCS7_bio(bio, NULL);
} }
BIO_free_all(bio); BIO_free_all(bio);
unmap_file(indata, filesize);
return p7; return p7;
} }
/*
* [in, out] ctx: structure holds input and output data
* [out] outdata: BIO outdata file
* [in] p7: PKCS#7 signature
* [returns] 1 on error or 0 on success
*/
int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
{
int ret;
(void)BIO_reset(outdata);
if (ctx->options->output_pkcs7) {
/* PEM format */
ret = !PEM_write_bio_PKCS7(outdata, p7);
} else {
/* default DER format */
ret = !i2d_PKCS7_bio(outdata, p7);
}
if (ret) {
fprintf(stderr, "Unable to write pkcs7 object\n");
}
return ret;
}
/* /*
* Allocate, set type, add content and return a new PKCS#7 signature * Allocate, set type, add content and return a new PKCS#7 signature
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -224,84 +165,85 @@ PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx)
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx) PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
{ {
int i, signer = -1; int i, signer = -1;
PKCS7 *p7;
PKCS7_SIGNER_INFO *si = NULL; PKCS7_SIGNER_INFO *si = NULL;
STACK_OF(X509) *chain = NULL;
PKCS7 *p7 = PKCS7_new();
if (!p7)
return NULL;
p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed); PKCS7_set_type(p7, NID_pkcs7_signed);
if (ctx->options->cert != NULL) {
/*
* the private key and corresponding certificate are parsed from the PKCS12
* structure or loaded from the security token, so we may omit to check
* the consistency of a private key with the public key in an X509 certificate
*/
si = PKCS7_add_signature(p7, ctx->options->cert, ctx->options->pkey,
ctx->options->md);
if (si == NULL)
return NULL; /* FAILED */
} else {
/* find the signer's certificate located somewhere in the whole certificate chain */
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
X509 *signcert = sk_X509_value(ctx->options->certs, i);
if (X509_check_private_key(signcert, ctx->options->pkey)) {
si = PKCS7_add_signature(p7, signcert, ctx->options->pkey, ctx->options->md);
signer = i;
break;
}
}
if (si == NULL) {
printf("Failed to checking the consistency of a private key: %s\n",
ctx->options->keyfile);
printf(" with a public key in any X509 certificate: %s\n\n",
ctx->options->certfile);
return NULL; /* FAILED */
}
}
pkcs7_signer_info_add_signing_time(si, ctx);
if (!pkcs7_signer_info_add_purpose(si, ctx))
return NULL; /* FAILED */
if ((ctx->options->desc || ctx->options->url) &&
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
printf("Couldn't allocate memory for opus info\n");
return NULL; /* FAILED */
}
PKCS7_content_new(p7, NID_pkcs7_data); PKCS7_content_new(p7, NID_pkcs7_data);
/* add the signer's certificate */ /* find the signer's certificate located somewhere in the whole certificate chain */
if (ctx->options->cert != NULL)
PKCS7_add_certificate(p7, ctx->options->cert);
if (signer != -1)
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->certs, signer));
/* add the certificate chain */
for (i=0; i<sk_X509_num(ctx->options->certs); i++) { for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
if (i == signer) X509 *signcert = sk_X509_value(ctx->options->certs, i);
continue;
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->certs, i)); if (X509_check_private_key(signcert, ctx->options->pkey)) {
si = PKCS7_add_signature(p7, signcert, ctx->options->pkey, ctx->options->md);
signer = i;
if (signer > 0)
printf("Warning: For optimal performance, consider placing the signer certificate at the beginning of the certificate chain.\n");
break;
}
} }
/* add all cross certificates */ if (!si) {
if (ctx->options->xcerts) { fprintf(stderr, "Failed to checking the consistency of a private key: %s\n",
for (i=0; i<sk_X509_num(ctx->options->xcerts); i++) ctx->options->keyfile);
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->xcerts, i)); fprintf(stderr, " with a public key in any X509 certificate: %s\n\n",
#if !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L
ctx->options->certfile ? ctx->options->certfile : ctx->options->p11cert);
#else
ctx->options->certfile);
#endif /* !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L */
goto err;
}
if (!pkcs7_signer_info_add_signing_time(si, ctx)) {
goto err;
}
if (!pkcs7_signer_info_add_purpose(si, ctx)) {
goto err;
}
if ((ctx->options->desc || ctx->options->url) &&
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
fprintf(stderr, "Couldn't allocate memory for opus info\n");
goto err;
}
if ((ctx->options->nested_number >= 0) &&
!pkcs7_signer_info_add_sequence_number(si, ctx)) {
goto err;
}
/* create X509 chain sorted in ascending order by their DER encoding */
chain = X509_chain_get_sorted(ctx, signer);
if (!chain) {
fprintf(stderr, "Failed to create a sorted certificate chain\n");
goto err;
}
/* add sorted certificate chain */
for (i=0; i<sk_X509_num(chain); i++) {
(void)PKCS7_add_certificate(p7, sk_X509_value(chain, i));
} }
/* add crls */ /* add crls */
if (ctx->options->crls) { if (ctx->options->crls) {
for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++) for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++)
PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i)); (void)PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i));
} }
sk_X509_free(chain);
return p7; /* OK */ return p7; /* OK */
err:
PKCS7_free(p7);
return NULL; /* FAILED */
} }
/* /*
* PE, MSI, CAB and APPX file specific
* Add "1.3.6.1.4.1.311.2.1.4" SPC_INDIRECT_DATA_OBJID signed attribute
* [in, out] p7: new PKCS#7 signature * [in, out] p7: new PKCS#7 signature
* [in] hash: message digest BIO
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success * [returns] 0 on error or 1 on success
*/ */
int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx) int add_indirect_data_object(PKCS7 *p7)
{ {
STACK_OF(PKCS7_SIGNER_INFO) *signer_info; STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
PKCS7_SIGNER_INFO *si; PKCS7_SIGNER_INFO *si;
@ -315,67 +257,152 @@ int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1))) V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)))
return 0; /* FAILED */ return 0; /* FAILED */
if (!pkcs7_set_data_content(p7, hash, ctx)) { return 1; /* OK */
printf("Signing failed\n"); }
/*
* PE, MSI, CAB and APPX format specific
* Sign the MS Authenticode spcIndirectDataContent blob.
* The spcIndirectDataContent structure is used in Authenticode signatures
* to store the digest and other attributes of the signed file.
* [in, out] p7: new PKCS#7 signature
* [in] content: spcIndirectDataContent
* [returns] 0 on error or 1 on success
*/
int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content)
{
int len, inf, tag, class;
long plen;
const u_char *data, *p;
PKCS7 *td7;
p = data = ASN1_STRING_get0_data(content);
len = ASN1_STRING_length(content);
inf = ASN1_get_object(&p, &plen, &tag, &class, len);
if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE
|| !pkcs7_sign_content(p7, p, (int)plen)) {
fprintf(stderr, "Failed to sign spcIndirectDataContent\n");
return 0; /* FAILED */
}
td7 = PKCS7_new();
if (!td7) {
fprintf(stderr, "PKCS7_new failed\n");
return 0; /* FAILED */
}
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
td7->d.other = ASN1_TYPE_new();
td7->d.other->type = V_ASN1_SEQUENCE;
td7->d.other->value.sequence = ASN1_STRING_new();
ASN1_STRING_set(td7->d.other->value.sequence, data, len);
if (!PKCS7_set_content(p7, td7)) {
fprintf(stderr, "PKCS7_set_content failed\n");
PKCS7_free(td7);
return 0; /* FAILED */ return 0; /* FAILED */
} }
return 1; /* OK */ return 1; /* OK */
} }
/* /*
* [in, out] p7: new PKCS#7 signature * Add encapsulated content to signed PKCS7 structure.
* [in] cursig: current PKCS#7 signature * [in] content: spcIndirectDataContent
* [returns] 0 on error or 1 on success * [returns] new PKCS#7 signature with encapsulated content
*/ */
int add_ms_ctl_object(PKCS7 *p7, PKCS7 *cursig) PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content)
{ {
STACK_OF(PKCS7_SIGNER_INFO) *signer_info; PKCS7 *p7, *td7;
PKCS7_SIGNER_INFO *si;
signer_info = PKCS7_get_signer_info(p7); p7 = PKCS7_new();
if (!signer_info) if (!p7) {
return 0; /* FAILED */ return NULL; /* FAILED */
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si)
return 0; /* FAILED */
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
return 0; /* FAILED */
if (!pkcs7_set_content_blob(p7, cursig)) {
printf("Signing failed\n");
return 0; /* FAILED */
} }
return 1; /* OK */ if (!PKCS7_set_type(p7, NID_pkcs7_signed)) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!PKCS7_content_new(p7, NID_pkcs7_data)) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
td7 = PKCS7_new();
if (!td7) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
td7->d.other = ASN1_TYPE_new();
td7->d.other->type = V_ASN1_SEQUENCE;
td7->d.other->value.sequence = content;
if (!PKCS7_set_content(p7, td7)) {
PKCS7_free(td7);
PKCS7_free(p7);
return NULL; /* FAILED */
}
return p7;
} }
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig) /*
* Return spcIndirectDataContent.
* [in] hash: message digest BIO
* [in] ctx: structure holds input and output data
* [returns] content
*/
ASN1_OCTET_STRING *spc_indirect_data_content_get(BIO *hash, FILE_FORMAT_CTX *ctx)
{ {
PKCS7 *contents; ASN1_OCTET_STRING *content;
u_char *content; u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
int seqhdrlen, content_length; int mdlen, hashlen, len = 0;
BIO *sigbio; u_char *data, *p = NULL;
contents = cursig->d.sign->contents; content = ASN1_OCTET_STRING_new();
seqhdrlen = asn1_simple_hdr_len(contents->d.other->value.sequence->data, if (!content) {
contents->d.other->value.sequence->length); return NULL; /* FAILED */
content = contents->d.other->value.sequence->data + seqhdrlen; }
content_length = contents->d.other->value.sequence->length - seqhdrlen; if (!spc_indirect_data_content_create(&p, &len, ctx)) {
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
hashlen = ctx->format->hash_length_get(ctx);
if (hashlen > EVP_MAX_MD_SIZE) {
/* APPX format specific */
mdlen = BIO_read(hash, (char*)mdbuf, hashlen);
} else {
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
}
data = OPENSSL_malloc((size_t)(len + mdlen));
memcpy(data, p, (size_t)len);
OPENSSL_free(p);
memcpy(data + len, mdbuf, (size_t)mdlen);
if (!ASN1_OCTET_STRING_set(content, data, len + mdlen)) {
ASN1_OCTET_STRING_free(content);
OPENSSL_free(data);
return NULL; /* FAILED */
}
OPENSSL_free(data);
return content;
}
if ((sigbio = PKCS7_dataInit(sig, NULL)) == NULL) { /*
printf("PKCS7_dataInit failed\n"); * Signs the data and place the signature in p7
* [in, out] p7: new PKCS#7 signature
* [in] data: content data
* [in] len: content length
*/
int pkcs7_sign_content(PKCS7 *p7, const u_char *data, int len)
{
BIO *p7bio;
if ((p7bio = PKCS7_dataInit(p7, NULL)) == NULL) {
fprintf(stderr, "PKCS7_dataInit failed\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
BIO_write(sigbio, content, content_length); BIO_write(p7bio, data, len);
(void)BIO_flush(sigbio); (void)BIO_flush(p7bio);
if (!PKCS7_dataFinal(sig, sigbio)) { if (!PKCS7_dataFinal(p7, p7bio)) {
printf("PKCS7_dataFinal failed\n"); fprintf(stderr, "PKCS7_dataFinal failed\n");
return 0; /* FAILED */ BIO_free_all(p7bio);
}
BIO_free_all(sigbio);
if (!PKCS7_set_content(sig, PKCS7_dup(contents))) {
printf("PKCS7_set_content failed\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
BIO_free_all(p7bio);
return 1; /* OK */ return 1; /* OK */
} }
@ -437,7 +464,7 @@ void print_hash(const char *descript1, const char *descript2, const u_char *mdbu
} }
/* /*
* [in] p7: new PKCS#7 signature * [in] p7: PKCS#7 signature
* [in] objid: Microsoft OID Authenticode * [in] objid: Microsoft OID Authenticode
* [returns] 0 on error or 1 on success * [returns] 0 on error or 1 on success
*/ */
@ -456,29 +483,42 @@ int is_content_type(PKCS7 *p7, const char *objid)
} }
/* /*
* [out] p7: new PKCS#7 signature * [in] p7: new PKCS#7 signature
* [in] hash: message digest BIO * [returns] pointer to MsCtlContent structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/ */
int pkcs7_set_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx) MsCtlContent *ms_ctl_content_get(PKCS7 *p7)
{ {
u_char *p = NULL; ASN1_STRING *value;
int len = 0; const u_char *data;
u_char *buf;
if (!spc_indirect_data_content_get(&p, &len, ctx)) if (!is_content_type(p7, MS_CTL_OBJID)) {
return 0; /* FAILED */ fprintf(stderr, "Failed to find MS_CTL_OBJID\n");
buf = OPENSSL_malloc(SIZE_64K); return NULL; /* FAILED */
memcpy(buf, p, (size_t)len);
OPENSSL_free(p);
if (!pkcs7_set_spc_indirect_data_content(p7, hash, buf, len, ctx)) {
OPENSSL_free(buf);
return 0; /* FAILED */
} }
OPENSSL_free(buf); value = p7->d.sign->contents->d.other->value.sequence;
data = ASN1_STRING_get0_data(value);
return d2i_MsCtlContent(NULL, &data, ASN1_STRING_length(value));
}
return 1; /* OK */ /*
* [in] attribute: catalog attribute
* [returns] catalog content
*/
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute)
{
ASN1_STRING *value;
STACK_OF(ASN1_TYPE) *contents;
ASN1_TYPE *content;
const u_char *contents_data;
value = attribute->contents->value.sequence;
contents_data = ASN1_STRING_get0_data(value);
contents = d2i_ASN1_SET_ANY(NULL, &contents_data, ASN1_STRING_length(value));
if (!contents)
return 0; /* FAILED */
content = sk_ASN1_TYPE_value(contents, 0);
sk_ASN1_TYPE_free(contents);
return content;
} }
/* /*
@ -503,23 +543,6 @@ SpcLink *spc_link_obsolete_get(void)
return link; return link;
} }
/*
* Retrieve a decoded PKCS#7 structure
* [in] indata: mapped file
* [in] sigpos: signature data offset
* [in] siglen: signature data size
* [returns] pointer to PKCS#7 structure
*/
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen)
{
PKCS7 *p7 = NULL;
const u_char *blob;
blob = (u_char *)indata + sigpos;
p7 = d2i_PKCS7(NULL, &blob, siglen);
return p7;
}
/* /*
* [in] mdbuf, cmdbuf: message digests * [in] mdbuf, cmdbuf: message digests
* [in] mdtype: message digest algorithm type * [in] mdtype: message digest algorithm type
@ -570,14 +593,22 @@ static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx)
* [in] ctx: FILE_FORMAT_CTX structure * [in] ctx: FILE_FORMAT_CTX structure
* [returns] 0 on error or 1 on success * [returns] 0 on error or 1 on success
*/ */
static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx) static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx)
{ {
u_char *p = NULL; u_char *p = NULL;
int hashlen, l = 0; int mdtype, hashlen, l = 0;
int mdtype = EVP_MD_nid(ctx->options->md);
void *hash; void *hash;
SpcIndirectDataContent *idc = SpcIndirectDataContent_new(); SpcIndirectDataContent *idc = SpcIndirectDataContent_new();
if (!ctx->format->data_blob_get || !ctx->format->hash_length_get) {
return 0; /* FAILED */
}
if (ctx->format->md_get) {
/* APPX file specific - use a hash algorithm specified in the AppxBlockMap.xml file */
mdtype = EVP_MD_nid(ctx->format->md_get(ctx));
} else {
mdtype = EVP_MD_nid(ctx->options->md);
}
idc->data->value = ASN1_TYPE_new(); idc->data->value = ASN1_TYPE_new();
idc->data->value->type = V_ASN1_SEQUENCE; idc->data->value->type = V_ASN1_SEQUENCE;
idc->data->value->value.sequence = ASN1_STRING_new(); idc->data->value->value.sequence = ASN1_STRING_new();
@ -603,56 +634,164 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
} }
/* /*
* Replace the data part with the MS Authenticode spcIndirectDataContent blob * [in, out] si: PKCS7_SIGNER_INFO structure
* [out] p7: new PKCS#7 signature
* [in] hash: message digest BIO
* [in] blob: SpcIndirectDataContent data
* [in] len: SpcIndirectDataContent data length
* [in] ctx: FILE_FORMAT_CTX structure * [in] ctx: FILE_FORMAT_CTX structure
* [returns] 0 on error or 1 on success * [returns] 0 on error or 1 on success
*/ */
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx) static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{ {
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24]; SpcSpOpusInfo *opus;
int mdlen, seqhdrlen, hashlen; ASN1_STRING *astr;
BIO *bio; int len;
PKCS7 *td7; u_char *p = NULL;
hashlen = ctx->format->hash_length_get(ctx); opus = spc_sp_opus_info_create(ctx);
if (hashlen > EVP_MAX_MD_SIZE) { if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
/* APPX format specific */ || (p = OPENSSL_malloc((size_t)len)) == NULL) {
mdlen = BIO_read(hash, (char*)mdbuf, hashlen); SpcSpOpusInfo_free(opus);
return 0; /* FAILED */
}
i2d_SpcSpOpusInfo(opus, &p);
p -= len;
astr = ASN1_STRING_new();
ASN1_STRING_set(astr, p, len);
OPENSSL_free(p);
SpcSpOpusInfo_free(opus);
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
V_ASN1_SEQUENCE, astr);
}
/*
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
* adding the _current_ time. This allows to create a deterministic signature
* when no trusted timestamp server was specified, making osslsigncode
* behaviour closer to signtool.exe (which doesn't include any non-trusted
* time in this case.)
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
if (ctx->options->time == INVALID_TIME) /* -time option was not specified */
return 1; /* SUCCESS */
return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,
ASN1_TIME_adj(NULL, ctx->options->time, 0, 0));
}
/*
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
static const u_char purpose_ind[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
};
static const u_char purpose_comm[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
};
ASN1_STRING *purpose = ASN1_STRING_new();
if (ctx->options->comm) {
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
} else { } else {
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE); ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
} }
memcpy(buf + len, mdbuf, (size_t)mdlen); return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
seqhdrlen = asn1_simple_hdr_len(buf, len); V_ASN1_SEQUENCE, purpose);
}
if ((bio = PKCS7_dataInit(p7, NULL)) == NULL) { /*
printf("PKCS7_dataInit failed\n"); * [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
ASN1_INTEGER *number = ASN1_INTEGER_new();
if (!number)
return 0; /* FAILED */
if (!ASN1_INTEGER_set(number, ctx->options->nested_number + 1)) {
ASN1_INTEGER_free(number);
return 0; /* FAILED */ return 0; /* FAILED */
} }
BIO_write(bio, buf + seqhdrlen, len - seqhdrlen + mdlen); return PKCS7_add_signed_attribute(si, OBJ_txt2nid(PKCS9_SEQUENCE_NUMBER),
(void)BIO_flush(bio); V_ASN1_INTEGER, number);
}
if (!PKCS7_dataFinal(p7, bio)) { /*
printf("PKCS7_dataFinal failed\n"); * Create certificate chain sorted in ascending order by their DER encoding.
return 0; /* FAILED */ * [in] ctx: structure holds input and output data
} * [in] signer: signer's certificate number in the certificate chain
BIO_free_all(bio); * [returns] sorted certificate chain
*/
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
{
int i;
STACK_OF(X509) *chain = sk_X509_new(X509_compare);
td7 = PKCS7_new(); if (signer != -1 && !sk_X509_push(chain, sk_X509_value(ctx->options->certs, signer))) {
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1); sk_X509_free(chain);
td7->d.other = ASN1_TYPE_new(); return NULL;
td7->d.other->type = V_ASN1_SEQUENCE;
td7->d.other->value.sequence = ASN1_STRING_new();
ASN1_STRING_set(td7->d.other->value.sequence, buf, len + mdlen);
if (!PKCS7_set_content(p7, td7)) {
PKCS7_free(td7);
printf("PKCS7_set_content failed\n");
return 0; /* FAILED */
} }
return 1; /* OK */ /* add the certificate chain */
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
if (i == signer)
continue;
if (!sk_X509_push(chain, sk_X509_value(ctx->options->certs, i))) {
sk_X509_free(chain);
return NULL;
}
}
/* add all cross certificates */
if (ctx->options->xcerts) {
for (i=0; i<sk_X509_num(ctx->options->xcerts); i++) {
if (!sk_X509_push(chain, sk_X509_value(ctx->options->xcerts, i))) {
sk_X509_free(chain);
return NULL;
}
}
}
/* sort certificate chain using the supplied comparison function */
sk_X509_sort(chain);
return chain;
}
/*
* X.690-compliant certificate comparison function
* Windows requires catalog files to use PKCS#7
* content ordering specified in X.690 section 11.6
* https://support.microsoft.com/en-us/topic/october-13-2020-kb4580358-security-only-update-d3f6eb3c-d7c4-a9cb-0de6-759386bf7113
* This algorithm is different from X509_cmp()
* [in] a_ptr, b_ptr: pointers to X509 certificates
* [returns] certificates order
*/
static int X509_compare(const X509 *const *a, const X509 *const *b)
{
u_char *a_data, *b_data, *a_tmp, *b_tmp;
size_t a_len, b_len;
int ret;
a_len = (size_t)i2d_X509(*a, NULL);
a_tmp = a_data = OPENSSL_malloc(a_len);
i2d_X509(*a, &a_tmp);
b_len = (size_t)i2d_X509(*b, NULL);
b_tmp = b_data = OPENSSL_malloc(b_len);
i2d_X509(*b, &b_tmp);
ret = memcmp(a_data, b_data, MIN(a_len, b_len));
OPENSSL_free(a_data);
OPENSSL_free(b_data);
if (ret == 0 && a_len != b_len) /* identical up to the length of the shorter DER */
ret = a_len < b_len ? -1 : 1; /* shorter is smaller */
return ret;
} }
/* /*

View File

@ -9,19 +9,21 @@
uint32_t get_file_size(const char *infile); uint32_t get_file_size(const char *infile);
char *map_file(const char *infile, const size_t size); char *map_file(const char *infile, const size_t size);
void unmap_file(char *indata, const size_t size); void unmap_file(char *indata, const size_t size);
int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); PKCS7 *pkcs7_read_data(char *indata, uint32_t size);
PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx); int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx); PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx);
void add_content_type(PKCS7 *p7); int add_indirect_data_object(PKCS7 *p7);
int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx); int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content);
int add_ms_ctl_object(PKCS7 *p7, PKCS7 *cursig); PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content);
ASN1_OCTET_STRING *spc_indirect_data_content_get(BIO *hash, FILE_FORMAT_CTX *ctx);
int pkcs7_sign_content(PKCS7 *p7, const u_char *data, int len);
int asn1_simple_hdr_len(const u_char *p, int len); int asn1_simple_hdr_len(const u_char *p, int len);
int bio_hash_data(BIO *hash, char *indata, size_t idx, size_t fileend); int bio_hash_data(BIO *hash, char *indata, size_t idx, size_t fileend);
void print_hash(const char *descript1, const char *descript2, const u_char *hashbuf, int length); void print_hash(const char *descript1, const char *descript2, const u_char *hashbuf, int length);
int is_content_type(PKCS7 *p7, const char *objid); int is_content_type(PKCS7 *p7, const char *objid);
int pkcs7_set_data_content(PKCS7 *sig, BIO *hash, FILE_FORMAT_CTX *ctx); MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
SpcLink *spc_link_obsolete_get(void); SpcLink *spc_link_obsolete_get(void);
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen);
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype); int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
/* /*

777
msi.c

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@
#define NOCRYPT #define NOCRYPT
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <winsock2.h>
#endif /* HAVE_WINDOWS_H */ #endif /* HAVE_WINDOWS_H */
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
@ -21,6 +22,7 @@
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <ctype.h> #include <ctype.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -31,6 +33,7 @@
#ifndef _WIN32 #ifndef _WIN32
#include <unistd.h> #include <unistd.h>
#include <sys/socket.h>
#ifdef HAVE_SYS_MMAN_H #ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h> #include <sys/mman.h>
#endif /* HAVE_SYS_MMAN_H */ #endif /* HAVE_SYS_MMAN_H */
@ -62,7 +65,10 @@
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */ #endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
#include <openssl/rand.h> #include <openssl/rand.h>
#include <openssl/safestack.h> #include <openssl/safestack.h>
#include <openssl/ssl.h>
#include <openssl/store.h>
#include <openssl/ts.h> #include <openssl/ts.h>
#include <openssl/ui.h>
#include <openssl/x509.h> #include <openssl/x509.h>
#include <openssl/x509v3.h> /* X509_PURPOSE */ #include <openssl/x509v3.h> /* X509_PURPOSE */
@ -73,20 +79,28 @@
#endif /* SOCKET */ #endif /* SOCKET */
#endif /* __CYGWIN__ */ #endif /* __CYGWIN__ */
#include <curl/curl.h> #include <curl/curl.h>
#define MAX_TS_SERVERS 256
#endif /* ENABLE_CURL */ #endif /* ENABLE_CURL */
/* Request nonce length, in bits (must be a multiple of 8). */
#define NONCE_LENGTH 64
#define MAX_TS_SERVERS 256
#if defined (HAVE_TERMIOS_H) || defined (HAVE_GETPASS) #if defined (HAVE_TERMIOS_H) || defined (HAVE_GETPASS)
#define PROVIDE_ASKPASS 1 #define PROVIDE_ASKPASS 1
#endif #endif
#ifdef _WIN32 #ifdef _MSC_VER
#define FILE_CREATE_MODE "w+b" /* not WIN32, because strcasecmp exists in MinGW */
#else #define strcasecmp _stricmp
#define FILE_CREATE_MODE "w+bx" #define fseeko _fseeki64
#endif #define ftello _ftelli64
#endif /* _MSC_VER */
#ifdef WIN32
#define remove_file(filename) _unlink(filename)
#else
#define remove_file(filename) unlink(filename)
#endif /* WIN32 */
#define GET_UINT8_LE(p) ((const u_char *)(p))[0] #define GET_UINT8_LE(p) ((const u_char *)(p))[0]
@ -175,6 +189,8 @@
#define SPC_RFC3161_OBJID "1.3.6.1.4.1.311.3.3.1" #define SPC_RFC3161_OBJID "1.3.6.1.4.1.311.3.3.1"
/* Microsoft OID Crypto 2.0 */ /* Microsoft OID Crypto 2.0 */
#define MS_CTL_OBJID "1.3.6.1.4.1.311.10.1" #define MS_CTL_OBJID "1.3.6.1.4.1.311.10.1"
/* Microsoft OID Catalog */
#define CAT_NAMEVALUE_OBJID "1.3.6.1.4.1.311.12.2.1"
/* Microsoft OID Microsoft_Java */ /* Microsoft OID Microsoft_Java */
#define MS_JAVA_SOMETHING "1.3.6.1.4.1.311.15.1" #define MS_JAVA_SOMETHING "1.3.6.1.4.1.311.15.1"
@ -184,6 +200,7 @@
#define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4" #define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4"
#define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5" #define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5"
#define PKCS9_COUNTER_SIGNATURE "1.2.840.113549.1.9.6" #define PKCS9_COUNTER_SIGNATURE "1.2.840.113549.1.9.6"
#define PKCS9_SEQUENCE_NUMBER "1.2.840.113549.1.9.25.4"
/* WIN_CERTIFICATE structure declared in Wintrust.h */ /* WIN_CERTIFICATE structure declared in Wintrust.h */
#define WIN_CERT_REVISION_2_0 0x0200 #define WIN_CERT_REVISION_2_0 0x0200
@ -208,9 +225,9 @@
*/ */
#define FLAG_RESERVE_PRESENT 0x0004 #define FLAG_RESERVE_PRESENT 0x0004
#define DO_EXIT_0(x) { printf(x); goto err_cleanup; } #define DO_EXIT_0(x) { fprintf(stderr, x); goto err_cleanup; }
#define DO_EXIT_1(x, y) { printf(x, y); goto err_cleanup; } #define DO_EXIT_1(x, y) { fprintf(stderr, x, y); goto err_cleanup; }
#define DO_EXIT_2(x, y, z) { printf(x, y, z); goto err_cleanup; } #define DO_EXIT_2(x, y, z) { fprintf(stderr, x, y, z); goto err_cleanup; }
/* Default policy if request did not specify it. */ /* Default policy if request did not specify it. */
#define TSA_POLICY1 "1.2.3.4.1" #define TSA_POLICY1 "1.2.3.4.1"
@ -218,6 +235,7 @@
typedef enum { typedef enum {
CMD_SIGN, CMD_SIGN,
CMD_EXTRACT, CMD_EXTRACT,
CMD_EXTRACT_DATA,
CMD_REMOVE, CMD_REMOVE,
CMD_VERIFY, CMD_VERIFY,
CMD_ADD, CMD_ADD,
@ -228,6 +246,16 @@ typedef enum {
typedef unsigned char u_char; typedef unsigned char u_char;
#ifndef OPENSSL_NO_ENGINE
typedef struct {
ASN1_OCTET_STRING *cmd;
ASN1_OCTET_STRING *param;
} EngineControl;
DECLARE_ASN1_FUNCTIONS(EngineControl)
DEFINE_STACK_OF(EngineControl)
#endif /* OPENSSL_NO_ENGINE */
typedef struct { typedef struct {
char *infile; char *infile;
char *outfile; char *outfile;
@ -242,6 +270,8 @@ typedef struct {
char *p11engine; char *p11engine;
char *p11module; char *p11module;
char *p11cert; char *p11cert;
int login;
STACK_OF(EngineControl) *engine_ctrls;
#endif /* OPENSSL_NO_ENGINE */ #endif /* OPENSSL_NO_ENGINE */
int askpass; int askpass;
char *readpass; char *readpass;
@ -252,40 +282,44 @@ typedef struct {
const EVP_MD *md; const EVP_MD *md;
char *url; char *url;
time_t time; time_t time;
#ifdef ENABLE_CURL
char *turl[MAX_TS_SERVERS]; char *turl[MAX_TS_SERVERS];
int nturl; int nturl;
char *tsurl[MAX_TS_SERVERS]; char *tsurl[MAX_TS_SERVERS];
int ntsurl; int ntsurl;
char *proxy; char *proxy;
int noverifypeer; int noverifypeer;
#endif /* ENABLE_CURL */
int addBlob; int addBlob;
const char *blob_file;
int nest; int nest;
int index;
int ignore_timestamp; int ignore_timestamp;
int ignore_cdp;
int ignore_crl;
int verbose; int verbose;
int add_msi_dse; int add_msi_dse;
char *catalog; char *catalog;
char *cafile; char *cafile;
char *crlfile; char *crlfile;
char *https_cafile;
char *https_crlfile;
char *tsa_cafile; char *tsa_cafile;
char *tsa_crlfile; char *tsa_crlfile;
char *leafhash; char *leafhash;
int jp; int jp;
#if OPENSSL_VERSION_NUMBER>=0x30000000L #if OPENSSL_VERSION_NUMBER>=0x30000000L
int legacy; int legacy;
char *provider;
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */ #endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
EVP_PKEY *pkey; EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *certs; STACK_OF(X509) *certs;
STACK_OF(X509) *xcerts; STACK_OF(X509) *xcerts;
STACK_OF(X509_CRL) *crls; STACK_OF(X509_CRL) *crls;
cmd_type_t cmd; cmd_type_t cmd;
char *indata; char *indata;
PKCS7 *prevsig;
char *tsa_certfile; char *tsa_certfile;
char *tsa_keyfile; char *tsa_keyfile;
time_t tsa_time; time_t tsa_time;
int nested_number;
} GLOBAL_OPTIONS; } GLOBAL_OPTIONS;
/* /*
@ -326,6 +360,18 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo) DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo)
typedef struct {
ASN1_INTEGER *a;
ASN1_OCTET_STRING *string;
ASN1_INTEGER *b;
ASN1_INTEGER *c;
ASN1_INTEGER *d;
ASN1_INTEGER *e;
ASN1_INTEGER *f;
} SpcSipInfo;
DECLARE_ASN1_FUNCTIONS(SpcSipInfo)
typedef struct { typedef struct {
ASN1_OBJECT *type; ASN1_OBJECT *type;
ASN1_TYPE *value; ASN1_TYPE *value;
@ -369,8 +415,6 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(MessageImprint) DECLARE_ASN1_FUNCTIONS(MessageImprint)
#ifdef ENABLE_CURL
typedef struct { typedef struct {
ASN1_OBJECT *type; ASN1_OBJECT *type;
ASN1_OCTET_STRING *signature; ASN1_OCTET_STRING *signature;
@ -413,8 +457,6 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(TimeStampReq) DECLARE_ASN1_FUNCTIONS(TimeStampReq)
#endif /* ENABLE_CURL */
typedef struct { typedef struct {
ASN1_INTEGER *seconds; ASN1_INTEGER *seconds;
ASN1_INTEGER *millis; ASN1_INTEGER *millis;
@ -461,7 +503,17 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(MsCtlContent) DECLARE_ASN1_FUNCTIONS(MsCtlContent)
typedef struct {
char *server;
const char *port;
int use_proxy;
int timeout;
SSL_CTX *ssl_ctx;
} HTTP_TLS_Info;
typedef struct file_format_st FILE_FORMAT; typedef struct file_format_st FILE_FORMAT;
typedef struct script_ctx_st SCRIPT_CTX;
typedef struct msi_ctx_st MSI_CTX; typedef struct msi_ctx_st MSI_CTX;
typedef struct pe_ctx_st PE_CTX; typedef struct pe_ctx_st PE_CTX;
typedef struct cab_ctx_st CAB_CTX; typedef struct cab_ctx_st CAB_CTX;
@ -472,6 +524,7 @@ typedef struct {
FILE_FORMAT *format; FILE_FORMAT *format;
GLOBAL_OPTIONS *options; GLOBAL_OPTIONS *options;
union { union {
SCRIPT_CTX *script_ctx;
MSI_CTX *msi_ctx; MSI_CTX *msi_ctx;
PE_CTX *pe_ctx; PE_CTX *pe_ctx;
CAB_CTX *cab_ctx; CAB_CTX *cab_ctx;
@ -480,6 +533,7 @@ typedef struct {
}; };
} FILE_FORMAT_CTX; } FILE_FORMAT_CTX;
extern FILE_FORMAT file_format_script;
extern FILE_FORMAT file_format_msi; extern FILE_FORMAT file_format_msi;
extern FILE_FORMAT file_format_pe; extern FILE_FORMAT file_format_pe;
extern FILE_FORMAT file_format_cab; extern FILE_FORMAT file_format_cab;
@ -488,19 +542,23 @@ extern FILE_FORMAT file_format_appx;
struct file_format_st { struct file_format_st {
FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata); FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata);
const EVP_MD *(*md_get) (FILE_FORMAT_CTX *ctx);
ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx); ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
PKCS7 *(*pkcs7_contents_get) (FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
int (*hash_length_get) (FILE_FORMAT_CTX *ctx); int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
int (*check_file) (FILE_FORMAT_CTX *ctx, int detached);
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md); u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7); int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7);
int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj); int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
PKCS7 *(*pkcs7_extract) (FILE_FORMAT_CTX *ctx); PKCS7 *(*pkcs7_extract) (FILE_FORMAT_CTX *ctx);
PKCS7 *(*pkcs7_extract_to_nest) (FILE_FORMAT_CTX *ctx);
int (*remove_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); int (*remove_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
PKCS7 *(*pkcs7_prepare) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); int (*process_data) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
PKCS7 *(*pkcs7_signature_new) (FILE_FORMAT_CTX *ctx, BIO *hash);
int (*append_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); int (*append_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7); void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7);
BIO *(*bio_free) (BIO *hash, BIO *outdata); void (*bio_free) (BIO *hash, BIO *outdata);
void (*ctx_cleanup) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); void (*ctx_cleanup) (FILE_FORMAT_CTX *ctx);
int (*is_detaching_supported) (void);
}; };
/* /*

449
pe.c
View File

@ -44,34 +44,40 @@ struct pe_ctx_st {
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx); static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
static int pe_hash_length_get(FILE_FORMAT_CTX *ctx); static int pe_hash_length_get(FILE_FORMAT_CTX *ctx);
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached);
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md); static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj); static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *pe_bio_free(BIO *hash, BIO *outdata); static void pe_bio_free(BIO *hash, BIO *outdata);
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx);
static int pe_is_detaching_supported(void);
FILE_FORMAT file_format_pe = { FILE_FORMAT file_format_pe = {
.ctx_new = pe_ctx_new, .ctx_new = pe_ctx_new,
.data_blob_get = pe_spc_image_data_get, .data_blob_get = pe_spc_image_data_get,
.pkcs7_contents_get = pe_pkcs7_contents_get,
.hash_length_get = pe_hash_length_get, .hash_length_get = pe_hash_length_get,
.check_file = pe_check_file,
.digest_calc = pe_digest_calc, .digest_calc = pe_digest_calc,
.verify_digests = pe_verify_digests, .verify_digests = pe_verify_digests,
.verify_indirect_data = pe_verify_indirect_data, .verify_indirect_data = pe_verify_indirect_data,
.pkcs7_extract = pe_pkcs7_extract, .pkcs7_extract = pe_pkcs7_extract,
.pkcs7_extract_to_nest = pe_pkcs7_extract_to_nest,
.remove_pkcs7 = pe_remove_pkcs7, .remove_pkcs7 = pe_remove_pkcs7,
.pkcs7_prepare = pe_pkcs7_prepare, .process_data = pe_process_data,
.pkcs7_signature_new = pe_pkcs7_signature_new,
.append_pkcs7 = pe_append_pkcs7, .append_pkcs7 = pe_append_pkcs7,
.update_data_size = pe_update_data_size, .update_data_size = pe_update_data_size,
.bio_free = pe_bio_free, .bio_free = pe_bio_free,
.ctx_cleanup = pe_ctx_cleanup .ctx_cleanup = pe_ctx_cleanup,
.is_detaching_supported = pe_is_detaching_supported
}; };
/* Prototypes */ /* Prototypes */
@ -80,10 +86,12 @@ static PKCS7 *pe_pkcs7_get_file(char *indata, PE_CTX *pe_ctx);
static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size); static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size);
static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx); static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx);
static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj); static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj);
static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype); static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype);
static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype); static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype);
static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype); static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype);
static int pe_check_file(FILE_FORMAT_CTX *ctx);
/* /*
@ -112,12 +120,12 @@ static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outd
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (memcmp(options->indata, "MZ", 2)) { if (memcmp(options->indata, "MZ", 2)) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
pe_ctx = pe_ctx_get(options->indata, filesize); pe_ctx = pe_ctx_get(options->indata, filesize);
if (!pe_ctx) { if (!pe_ctx) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX)); ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
@ -170,6 +178,30 @@ static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* OK */ return dtype; /* OK */
} }
/*
* Allocate and return a data content to be signed.
* [in] ctx: structure holds input and output data
* [in] hash: message digest BIO
* [in] md: message digest algorithm
* [returns] data content
*/
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
{
ASN1_OCTET_STRING *content;
BIO *bhash;
/* squash the unused parameter warning */
(void)hash;
bhash = pe_digest_calc_bio(ctx, md);
if (!bhash) {
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(bhash, ctx);
BIO_free_all(bhash);
return pkcs7_set_content(content);
}
/* /*
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash) * [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
@ -180,121 +212,24 @@ static int pe_hash_length_get(FILE_FORMAT_CTX *ctx)
} }
/* /*
* Print current and calculated PE checksum, * Returns a message digest value of a signed or unsigned PE file.
* check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [in] detached: embedded/detached PKCS#7 signature switch
* [returns] 0 on error or 1 on success
*/
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached)
{
uint32_t real_pe_checksum, sum = 0;
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
}
real_pe_checksum = pe_calc_realchecksum(ctx);
if (ctx->pe_ctx->pe_checksum == real_pe_checksum) {
printf("PE checksum : %08X\n\n", real_pe_checksum);
} else {
printf("Current PE checksum : %08X\n", ctx->pe_ctx->pe_checksum);
printf("Calculated PE checksum: %08X\n", real_pe_checksum);
printf("Warning: invalid PE checksum\n\n");
}
if (detached) {
printf("Checking the specified catalog file\n\n");
return 1; /* OK */
}
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
/*
* If the sum of the rounded dwLength values does not equal the Size value,
* then either the attribute certificate table or the Size field is corrupted.
*/
while (sum < ctx->pe_ctx->siglen) {
uint32_t len = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->sigpos + sum);
if (ctx->pe_ctx->siglen - len > 8) {
printf("Corrupted attribute certificate table\n");
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
printf("Attribute certificate entry length: %08X\n\n", len);
return 0; /* FAILED */
}
/* quadword align data */
len += len % 8 ? 8 - len % 8 : 0;
sum += len;
}
if (sum != ctx->pe_ctx->siglen) {
printf("Corrupted attribute certificate table\n");
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
printf("Sum of the rounded dwLength values: %08X\n\n", sum);
return 0; /* FAILED */
}
return 1; /* OK */
}
/* Compute a message digest value of a signed or unsigned PE file.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
* [in] md: message digest algorithm * [in] md: message digest algorithm
* [returns] pointer to calculated message digest * [returns] pointer to calculated message digest
*/ */
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md) static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
{ {
size_t written; u_char *mdbuf;
uint32_t idx = 0, fileend; BIO *bhash = pe_digest_calc_bio(ctx, md);
u_char *mdbuf = NULL; if (!bhash) {
BIO *bhash = BIO_new(BIO_f_md()); return 0; /* FAILED */
}
if (!BIO_set_md(bhash, md)) {
printf("Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
BIO_push(bhash, BIO_new(BIO_s_null()));
if (ctx->pe_ctx->sigpos)
fileend = ctx->pe_ctx->sigpos;
else
fileend = ctx->pe_ctx->fileend;
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|| written != ctx->pe_ctx->header_size + 88) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 4;
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
60 + ctx->pe_ctx->pe32plus * 16, &written)
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 8;
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
printf("Unable to calculate digest\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
if (!ctx->pe_ctx->sigpos) {
/* pad (with 0's) unsigned PE file to 8 byte boundary */
int len = 8 - ctx->pe_ctx->fileend % 8;
if (len > 0 && len != 8) {
char *buf = OPENSSL_malloc(8);
memset(buf, 0, (size_t)len);
BIO_write(bhash, buf, len);
OPENSSL_free(buf);
}
}
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md)); mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md)); BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
BIO_free_all(bhash); BIO_free_all(bhash);
return mdbuf; /* OK */ return mdbuf; /* OK */
} }
/* /*
* Calculate message digest and page_hash and compare to values retrieved * Calculate message digest and page_hash and compare to values retrieved
* from PKCS#7 signedData. * from PKCS#7 signedData.
@ -316,7 +251,7 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length); SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
if (idc) { if (idc) {
if (!pe_page_hash_get(&ph, &phlen, &phtype, idc->data)) { if (!pe_page_hash_get(&ph, &phlen, &phtype, idc->data)) {
printf("Failed to extract a page hash\n\n"); fprintf(stderr, "Failed to extract a page hash\n\n");
SpcIndirectDataContent_free(idc); SpcIndirectDataContent_free(idc);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -328,25 +263,25 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
} }
} }
if (mdtype == -1) { if (mdtype == -1) {
printf("Failed to extract current message digest\n\n"); fprintf(stderr, "Failed to extract current message digest\n\n");
OPENSSL_free(ph); OPENSSL_free(ph);
return 0; /* FAILED */ return 0; /* FAILED */
} }
md = EVP_get_digestbynid(mdtype); md = EVP_get_digestbynid(mdtype);
cmdbuf = pe_digest_calc(ctx, md); cmdbuf = pe_digest_calc(ctx, md);
if (!cmdbuf) { if (!cmdbuf) {
printf("Failed to calculate message digest\n\n"); fprintf(stderr, "Failed to calculate message digest\n\n");
OPENSSL_free(ph); OPENSSL_free(ph);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!compare_digests(mdbuf, cmdbuf, mdtype)) { if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
printf("Signature verification: failed\n\n"); fprintf(stderr, "Signature verification: failed\n\n");
OPENSSL_free(ph); OPENSSL_free(ph);
OPENSSL_free(cmdbuf); OPENSSL_free(cmdbuf);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) { if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) {
printf("Signature verification: failed\n\n"); fprintf(stderr, "Signature verification: failed\n\n");
OPENSSL_free(ph); OPENSSL_free(ph);
OPENSSL_free(cmdbuf); OPENSSL_free(cmdbuf);
return 0; /* FAILED */ return 0; /* FAILED */
@ -368,11 +303,11 @@ static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOpti
u_char *ph = NULL; u_char *ph = NULL;
if (!pe_page_hash_get(&ph, &phlen, &phtype, obj)) { if (!pe_page_hash_get(&ph, &phlen, &phtype, obj)) {
printf("Failed to extract a page hash\n\n"); fprintf(stderr, "Failed to extract a page hash\n\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) { if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) {
printf("Page hash verification: failed\n\n"); fprintf(stderr, "Page hash verification: failed\n\n");
OPENSSL_free(ph); OPENSSL_free(ph);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -387,13 +322,22 @@ static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOpti
*/ */
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx) static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{ {
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0 if (!pe_check_file(ctx)) {
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
return pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx); return pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx);
} }
/*
* Extract existing signature in DER format.
* [in] ctx: structure holds input and output data
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
{
return pe_pkcs7_extract(ctx);
}
/* /*
* Remove existing signature. * Remove existing signature.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
@ -403,73 +347,70 @@ static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx)
*/ */
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
if (ctx->pe_ctx->sigpos == 0) { if (!pe_check_file(ctx)) {
printf("PE file does not have any signature\n"); return 1; /* FAILED, no signature */
return 1; /* FAILED */
} }
/* Strip current signature */ /* Strip current signature */
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos; ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
if (!pe_modify_header(ctx, hash, outdata)) { if (!pe_modify_header(ctx, hash, outdata)) {
printf("Unable to modify file header\n"); fprintf(stderr, "Unable to modify file header\n");
return 1; /* FAILED */ return 1; /* FAILED */
} }
return 0; /* OK */ return 0; /* OK */
} }
/* /*
* Obtain an existing signature or create a new one. * Modify specific type data and calculate a hash (message digest) of data.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [returns] pointer to PKCS#7 structure * [returns] 1 on error or 0 on success
*/ */
static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
PKCS7 *cursig = NULL, *p7 = NULL;
/* Obtain a current signature from previously-signed file */
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest)
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|| ctx->options->cmd == CMD_ADD) {
cursig = pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx);
if (!cursig) {
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
}
if (ctx->options->cmd == CMD_ADD)
p7 = cursig;
}
if (ctx->pe_ctx->sigpos > 0) { if (ctx->pe_ctx->sigpos > 0) {
/* Strip current signature */ /* Strip current signature */
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos; ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
} }
if (!pe_modify_header(ctx, hash, outdata)) { if (!pe_modify_header(ctx, hash, outdata)) {
printf("Unable to modify file header\n"); fprintf(stderr, "Unable to modify file header\n");
return 0; /* FAILED */
}
return 1; /* OK */
}
/*
* Create a new PKCS#7 signature.
* [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
{
ASN1_OCTET_STRING *content;
PKCS7 *p7 = pkcs7_create(ctx);
if (!p7) {
fprintf(stderr, "Creating a new signature failed\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (ctx->options->cmd == CMD_ATTACH) { if (!add_indirect_data_object(p7)) {
/* Obtain an existing PKCS#7 signature */ fprintf(stderr, "Adding SPC_INDIRECT_DATA_OBJID failed\n");
p7 = pkcs7_get_sigfile(ctx); PKCS7_free(p7);
if (!p7) { return NULL; /* FAILED */
printf("Unable to extract valid signature\n");
PKCS7_free(cursig);
return NULL; /* FAILED */
}
} else if (ctx->options->cmd == CMD_SIGN) {
/* Create a new PKCS#7 signature */
p7 = pkcs7_create(ctx);
if (!p7) {
printf("Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7, hash, ctx)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
} }
if (ctx->options->nest) content = spc_indirect_data_content_get(hash, ctx);
ctx->options->prevsig = cursig; if (!content) {
fprintf(stderr, "Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
}
if (!sign_spc_indirect_data_content(p7, content)) {
fprintf(stderr, "Failed to set signed content\n");
PKCS7_free(p7);
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
ASN1_OCTET_STRING_free(content);
return p7; return p7;
} }
@ -494,7 +435,7 @@ static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
if (((len = i2d_PKCS7(p7, NULL)) <= 0) if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|| (p = OPENSSL_malloc((size_t)len)) == NULL) { || (p = OPENSSL_malloc((size_t)len)) == NULL) {
printf("i2d_PKCS memory allocation failed: %d\n", len); fprintf(stderr, "i2d_PKCS memory allocation failed: %d\n", len);
return 1; /* FAILED */ return 1; /* FAILED */
} }
i2d_PKCS7(p7, &p); i2d_PKCS7(p7, &p);
@ -555,40 +496,33 @@ static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] none * [returns] none
*/ */
static BIO *pe_bio_free(BIO *hash, BIO *outdata) static void pe_bio_free(BIO *hash, BIO *outdata)
{ {
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)outdata; (void)outdata;
BIO_free_all(hash); BIO_free_all(hash);
return NULL;
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and PE format specific structure, * Deallocate a FILE_FORMAT_CTX structure and PE format specific structure,
* unmap indata file, unlink outfile. * unmap indata file.
* [out] ctx: structure holds input and output data * [out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [in] outdata: outdata file BIO * [in] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
if (ctx->options->outfile) {
#ifdef WIN32
_unlink(ctx->options->outfile);
#else
unlink(ctx->options->outfile);
#endif /* WIN32 */
}
}
unmap_file(ctx->options->indata, ctx->pe_ctx->fileend); unmap_file(ctx->options->indata, ctx->pe_ctx->fileend);
OPENSSL_free(ctx->pe_ctx); OPENSSL_free(ctx->pe_ctx);
OPENSSL_free(ctx); OPENSSL_free(ctx);
} }
static int pe_is_detaching_supported(void)
{
return 1; /* OK */
}
/* /*
* PE helper functions * PE helper functions
*/ */
@ -606,7 +540,7 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
uint16_t magic; uint16_t magic;
if (filesize < 64) { if (filesize < 64) {
printf("Corrupt DOS file - too short\n"); fprintf(stderr, "Corrupt DOS file - too short\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* SizeOfHeaders field specifies the combined size of an MS-DOS stub, PE header, /* SizeOfHeaders field specifies the combined size of an MS-DOS stub, PE header,
@ -615,15 +549,15 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
* because of a bug when checking section names for compatibility purposes */ * because of a bug when checking section names for compatibility purposes */
header_size = GET_UINT32_LE(indata + 60); header_size = GET_UINT32_LE(indata + 60);
if (header_size < 44 || header_size > filesize) { if (header_size < 44 || header_size > filesize) {
printf("Unexpected SizeOfHeaders field: 0x%08X\n", header_size); fprintf(stderr, "Unexpected SizeOfHeaders field: 0x%08X\n", header_size);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (filesize < header_size + 176) { if (filesize < header_size + 176) {
printf("Corrupt PE file - too short\n"); fprintf(stderr, "Corrupt PE file - too short\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (memcmp(indata + header_size, "PE\0\0", 4)) { if (memcmp(indata + header_size, "PE\0\0", 4)) {
printf("Unrecognized DOS file type\n"); fprintf(stderr, "Unrecognized DOS file type\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* Magic field identifies the state of the image file. The most common number is /* Magic field identifies the state of the image file. The most common number is
@ -636,7 +570,7 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
} else if (magic == 0x10b) { } else if (magic == 0x10b) {
pe32plus = 0; pe32plus = 0;
} else { } else {
printf("Corrupt PE file - found unknown magic %04X\n", magic); fprintf(stderr, "Corrupt PE file - found unknown magic %04X\n", magic);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* The image file checksum */ /* The image file checksum */
@ -645,7 +579,7 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
* in the remainder of the optional header. Each describes a location and size. */ * in the remainder of the optional header. Each describes a location and size. */
nrvas = GET_UINT32_LE(indata + header_size + 116 + pe32plus * 16); nrvas = GET_UINT32_LE(indata + header_size + 116 + pe32plus * 16);
if (nrvas < 5) { if (nrvas < 5) {
printf("Can not handle PE files without certificate table resource\n"); fprintf(stderr, "Can not handle PE files without certificate table resource\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* Certificate Table field specifies the attribute certificate table address (4 bytes) and size (4 bytes) */ /* Certificate Table field specifies the attribute certificate table address (4 bytes) and size (4 bytes) */
@ -653,14 +587,11 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
siglen = GET_UINT32_LE(indata + header_size + 152 + pe32plus * 16 + 4); siglen = GET_UINT32_LE(indata + header_size + 152 + pe32plus * 16 + 4);
/* Since fix for MS Bulletin MS12-024 we can really assume /* Since fix for MS Bulletin MS12-024 we can really assume
that signature should be last part of file */ that signature should be last part of file */
if ((sigpos > 0 && sigpos < filesize && sigpos + siglen != filesize) if ((sigpos != 0 || siglen != 0) &&
|| (sigpos >= filesize)) { (sigpos == 0 || siglen == 0 || sigpos >= filesize || sigpos + siglen != filesize)) {
printf("Corrupt PE file - current signature not at the end of the file\n"); printf("Warning: Ignoring PE signature not at the end of the file\n");
return NULL; /* FAILED */ sigpos = 0;
} siglen = 0;
if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) {
printf("Corrupt signature\n");
return NULL; /* FAILED */
} }
pe_ctx = OPENSSL_zalloc(sizeof(PE_CTX)); pe_ctx = OPENSSL_zalloc(sizeof(PE_CTX));
pe_ctx->header_size = header_size; pe_ctx->header_size = header_size;
@ -686,7 +617,7 @@ static PKCS7 *pe_pkcs7_get_file(char *indata, PE_CTX *pe_ctx)
uint32_t pos = 0; uint32_t pos = 0;
if (pe_ctx->siglen == 0 || pe_ctx->siglen > pe_ctx->fileend) { if (pe_ctx->siglen == 0 || pe_ctx->siglen > pe_ctx->fileend) {
printf("Corrupted signature length: 0x%08X\n", pe_ctx->siglen); fprintf(stderr, "Corrupted signature length: 0x%08X\n", pe_ctx->siglen);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
while (pos < pe_ctx->siglen) { while (pos < pe_ctx->siglen) {
@ -836,6 +767,62 @@ static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
return 1; /* OK */ return 1; /* OK */
} }
/*
* Compute a message digest value of a signed or unsigned PE file.
* [in] ctx: structure holds input and output data
* [in] md: message digest algorithm
* [returns] calculated message digest BIO
*/
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
{
size_t written;
uint32_t idx = 0, fileend;
BIO *bhash = BIO_new(BIO_f_md());
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
BIO_push(bhash, BIO_new(BIO_s_null()));
if (ctx->pe_ctx->sigpos)
fileend = ctx->pe_ctx->sigpos;
else
fileend = ctx->pe_ctx->fileend;
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|| written != ctx->pe_ctx->header_size + 88) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 4;
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
60 + ctx->pe_ctx->pe32plus * 16, &written)
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 8;
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
fprintf(stderr, "Unable to calculate digest\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
if (!ctx->pe_ctx->sigpos) {
/* pad (with 0's) unsigned PE file to 8 byte boundary */
int len = 8 - ctx->pe_ctx->fileend % 8;
if (len > 0 && len != 8) {
char *buf = OPENSSL_malloc(8);
memset(buf, 0, (size_t)len);
BIO_write(bhash, buf, len);
OPENSSL_free(buf);
}
}
return bhash;
}
/* /*
* Page hash support * Page hash support
*/ */
@ -931,7 +918,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
* which immediately follows the headers, can be up to 65535 under Vista and later */ * which immediately follows the headers, can be up to 65535 under Vista and later */
nsections = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 6); nsections = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 6);
if (nsections == 0) { if (nsections == 0) {
printf("Corrupted number of sections: 0x%08X\n", nsections); fprintf(stderr, "Corrupted number of sections: 0x%08X\n", nsections);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* FileAlignment is the alignment factor (in bytes) that is used to align /* FileAlignment is the alignment factor (in bytes) that is used to align
@ -939,7 +926,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
* of 2 between 512 and 64 K, inclusive. The default is 512. */ * of 2 between 512 and 64 K, inclusive. The default is 512. */
alignment = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 60); alignment = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 60);
if (alignment < 512 || alignment > UINT16_MAX) { if (alignment < 512 || alignment > UINT16_MAX) {
printf("Corrupted file alignment factor: 0x%08X\n", alignment); fprintf(stderr, "Corrupted file alignment factor: 0x%08X\n", alignment);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* SectionAlignment is the alignment (in bytes) of sections when they are /* SectionAlignment is the alignment (in bytes) of sections when they are
@ -949,14 +936,14 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
* https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200 */ * https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200 */
pagesize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 56); pagesize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 56);
if (pagesize == 0 || pagesize < alignment || pagesize > 4194304) { if (pagesize == 0 || pagesize < alignment || pagesize > 4194304) {
printf("Corrupted page size: 0x%08X\n", pagesize); fprintf(stderr, "Corrupted page size: 0x%08X\n", pagesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* SizeOfHeaders is the combined size of an MS-DOS stub, PE header, /* SizeOfHeaders is the combined size of an MS-DOS stub, PE header,
* and section headers rounded up to a multiple of FileAlignment. */ * and section headers rounded up to a multiple of FileAlignment. */
hdrsize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 84); hdrsize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 84);
if (hdrsize < ctx->pe_ctx->header_size || hdrsize > UINT32_MAX) { if (hdrsize < ctx->pe_ctx->header_size || hdrsize > UINT32_MAX) {
printf("Corrupted headers size: 0x%08X\n", hdrsize); fprintf(stderr, "Corrupted headers size: 0x%08X\n", hdrsize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* SizeOfOptionalHeader is the size of the optional header, which is /* SizeOfOptionalHeader is the size of the optional header, which is
@ -964,7 +951,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
* and can't be bigger than the file */ * and can't be bigger than the file */
opthdr_size = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 20); opthdr_size = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 20);
if (opthdr_size == 0 || opthdr_size > ctx->pe_ctx->fileend) { if (opthdr_size == 0 || opthdr_size > ctx->pe_ctx->fileend) {
printf("Corrupted optional header size: 0x%08X\n", opthdr_size); fprintf(stderr, "Corrupted optional header size: 0x%08X\n", opthdr_size);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
pphlen = 4 + EVP_MD_size(md); pphlen = 4 + EVP_MD_size(md);
@ -972,7 +959,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
bhash = BIO_new(BIO_f_md()); bhash = BIO_new(BIO_f_md());
if (!BIO_set_md(bhash, md)) { if (!BIO_set_md(bhash, md)) {
printf("Unable to set the message digest of BIO\n"); fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash); BIO_free_all(bhash);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -1019,7 +1006,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
PUT_UINT32_LE(ro + l, res + pi*pphlen); PUT_UINT32_LE(ro + l, res + pi*pphlen);
bhash = BIO_new(BIO_f_md()); bhash = BIO_new(BIO_f_md());
if (!BIO_set_md(bhash, md)) { if (!BIO_set_md(bhash, md)) {
printf("Unable to set the message digest of BIO\n"); fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash); BIO_free_all(bhash);
OPENSSL_free(zeroes); OPENSSL_free(zeroes);
OPENSSL_free(res); OPENSSL_free(res);
@ -1112,7 +1099,7 @@ static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype)
ph = pe_page_hash_calc(&phlen, ctx, phtype); ph = pe_page_hash_calc(&phlen, ctx, phtype);
if (!ph) { if (!ph) {
printf("Failed to calculate page hash\n"); fprintf(stderr, "Failed to calculate page hash\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (ctx->options->verbose) if (ctx->options->verbose)
@ -1172,6 +1159,58 @@ static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype)
return link; return link;
} }
/*
* Print current and calculated PE checksum,
* check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pe_check_file(FILE_FORMAT_CTX *ctx)
{
uint32_t real_pe_checksum, sum = 0;
if (!ctx) {
fprintf(stderr, "Init error\n");
return 0; /* FAILED */
}
real_pe_checksum = pe_calc_realchecksum(ctx);
if (ctx->pe_ctx->pe_checksum == real_pe_checksum) {
printf("PE checksum : %08X\n", real_pe_checksum);
} else {
printf("Current PE checksum : %08X\n", ctx->pe_ctx->pe_checksum);
printf("Calculated PE checksum: %08X\n", real_pe_checksum);
printf("Warning: invalid PE checksum\n");
}
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
fprintf(stderr, "No signature found\n");
return 0; /* FAILED */
}
/*
* If the sum of the rounded dwLength values does not equal the Size value,
* then either the attribute certificate table or the Size field is corrupted.
*/
while (sum < ctx->pe_ctx->siglen) {
uint32_t len = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->sigpos + sum);
if (ctx->pe_ctx->siglen - len > 8) {
fprintf(stderr, "Corrupted attribute certificate table\n");
fprintf(stderr, "Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
fprintf(stderr, "Attribute certificate entry length: %08X\n\n", len);
return 0; /* FAILED */
}
/* quadword align data */
len += len % 8 ? 8 - len % 8 : 0;
sum += len;
}
if (sum != ctx->pe_ctx->siglen) {
fprintf(stderr, "Corrupted attribute certificate table\n");
fprintf(stderr, "Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
fprintf(stderr, "Sum of the rounded dwLength values: %08X\n\n", sum);
return 0; /* FAILED */
}
return 1; /* OK */
}
/* /*
Local Variables: Local Variables:
c-basic-offset: 4 c-basic-offset: 4

875
script.c Normal file
View File

@ -0,0 +1,875 @@
/*
* Script file support library
*
* Copyright (C) 2021-2024 Michał Trojnara <Michal.Trojnara@stunnel.org>
*/
#include "osslsigncode.h"
#include "helpers.h"
#include "utf.h"
typedef enum {comment_hash, comment_xml, comment_c, comment_not_found} comment_style;
typedef struct {
const char *extension;
comment_style comment;
} SCRIPT_FORMAT;
const SCRIPT_FORMAT supported_formats[] = {
{".ps1", comment_hash},
{".ps1xml", comment_xml},
{".psc1", comment_xml},
{".psd1", comment_hash},
{".psm1", comment_hash},
{".cdxml", comment_xml},
{".mof", comment_c},
{NULL, comment_not_found},
};
const char *signature_header = "SIG # Begin signature block";
const char *signature_footer = "SIG # End signature block";
typedef struct {
const char *open;
const char *close;
} SCRIPT_COMMENT;
const SCRIPT_COMMENT comment_text[] = {
[comment_hash] = {"# ", ""},
[comment_xml] = {"<!-- ", " -->"},
[comment_c] = {"/* ", " */"}
};
struct script_ctx_st {
const SCRIPT_COMMENT *comment_text;
int utf;
uint32_t sigpos;
uint32_t fileend;
};
#define LINE_MAX_LEN 100
/* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *script_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static ASN1_OBJECT *script_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
static PKCS7 *script_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
static int script_hash_length_get(FILE_FORMAT_CTX *ctx);
static u_char *script_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int script_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *script_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
static int script_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static int script_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *script_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static void script_bio_free(BIO *hash, BIO *outdata);
static void script_ctx_cleanup(FILE_FORMAT_CTX *ctx);
static int script_is_detaching_supported(void);
FILE_FORMAT file_format_script = {
.ctx_new = script_ctx_new,
.data_blob_get = script_spc_sip_info_get,
.pkcs7_contents_get = script_pkcs7_contents_get,
.hash_length_get = script_hash_length_get,
.digest_calc = script_digest_calc,
.verify_digests = script_verify_digests,
.pkcs7_extract = script_pkcs7_extract,
.pkcs7_extract_to_nest = script_pkcs7_extract_to_nest,
.remove_pkcs7 = script_remove_pkcs7,
.process_data = script_process_data,
.pkcs7_signature_new = script_pkcs7_signature_new,
.append_pkcs7 = script_append_pkcs7,
.bio_free = script_bio_free,
.ctx_cleanup = script_ctx_cleanup,
.is_detaching_supported = script_is_detaching_supported
};
/* helper functions */
static SCRIPT_CTX *script_ctx_get(char *indata, uint32_t filesize, const SCRIPT_COMMENT *comment, int utf);
static int write_commented(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *data, size_t length);
static int write_in_encoding(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *line, size_t length);
static size_t utf8_to_utf16(const char *data, size_t len, uint16_t **out_utf16);
static size_t utf16_to_utf8(const uint16_t *data, size_t len, char **out_utf8);
static BIO *script_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int script_digest_convert(BIO *hash, FILE_FORMAT_CTX *ctx, size_t len);
static int script_write_bio(BIO *data, char *indata, size_t len);
static int script_check_file(FILE_FORMAT_CTX *ctx);
/*
* Allocate and return a script file format context.
* [in, out] options: structure holds the input data
* [out] hash: message digest BIO
* [in] outdata: outdata file BIO (unused)
* [returns] pointer to script file format context
*/
static FILE_FORMAT_CTX *script_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata)
{
FILE_FORMAT_CTX *ctx;
SCRIPT_CTX *script_ctx;
const SCRIPT_FORMAT *fmt;
uint32_t filesize;
const uint8_t utf16_bom[] = {0xff, 0xfe};
size_t name_len;
int utf;
/* squash the unused parameter warning */
(void)outdata;
/* find out whether our format is supported */
name_len = strlen(options->infile);
for (fmt = supported_formats; fmt->comment != comment_not_found; fmt++) {
size_t ext_len = strlen(fmt->extension);
if(name_len > ext_len && !strcasecmp(options->infile + name_len - ext_len, fmt->extension))
break;
}
if (fmt->comment == comment_not_found)
return NULL;
printf("Script file format: %s\n", fmt->extension);
filesize = get_file_size(options->infile);
if (filesize == 0)
return NULL; /* FAILED */
options->indata = map_file(options->infile, filesize);
if (!options->indata) {
return NULL; /* FAILED */
}
utf = memcmp(options->indata, utf16_bom, sizeof utf16_bom) ? 8 : 16;
/* initialize script context */
script_ctx = script_ctx_get(options->indata, filesize, comment_text + fmt->comment, utf);
if (!script_ctx) {
unmap_file(options->indata, filesize);
return NULL; /* FAILED */
}
/* initialize file format context */
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
memset(ctx, 0, sizeof(FILE_FORMAT_CTX));
ctx->format = &file_format_script;
ctx->options = options;
ctx->script_ctx = script_ctx;
if (hash)
BIO_push(hash, BIO_new(BIO_s_null()));
/* FIXME: user interface logic belongs to osslsigncode.c */
if (options->pagehash == 1)
printf("Warning: -ph option is only valid for PE files\n");
if (options->jp >= 0)
printf("Warning: -jp option is only valid for CAB files\n");
return ctx;
}
/*
* Allocate and return SpcSipInfo object.
* Subject Interface Package (SIP) is an internal Microsoft API for
* transforming arbitrary files into a digestible stream.
* These ClassIDs are found in the indirect data section and identify
* the type of processor needed to validate the signature.
* https://github.com/sassoftware/relic/blob/620d0b75ec67c0158a8a9120950abe04327d922f/lib/authenticode/structs.go#L154
* [out] p: SpcSipInfo data
* [out] plen: SpcSipInfo data length
* [in] ctx: structure holds input and output data
* [returns] pointer to ASN1_OBJECT structure corresponding to SPC_SIPINFO_OBJID
*/
static ASN1_OBJECT *script_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx)
{
const u_char SpcUUIDSipInfoPs[] = {
0x1f, 0xcc, 0x3b, 0x60, 0x59, 0x4b, 0x08, 0x4e,
0xb7, 0x24, 0xd2, 0xc6, 0x29, 0x7e, 0xf3, 0x51
};
ASN1_OBJECT *dtype;
SpcSipInfo *si = SpcSipInfo_new();
/* squash the unused parameter warning */
(void)ctx;
ASN1_INTEGER_set(si->a, 65536);
ASN1_INTEGER_set(si->b, 0);
ASN1_INTEGER_set(si->c, 0);
ASN1_INTEGER_set(si->d, 0);
ASN1_INTEGER_set(si->e, 0);
ASN1_INTEGER_set(si->f, 0);
ASN1_OCTET_STRING_set(si->string, SpcUUIDSipInfoPs, sizeof SpcUUIDSipInfoPs);
*plen = i2d_SpcSipInfo(si, NULL);
*p = OPENSSL_malloc((size_t)*plen);
i2d_SpcSipInfo(si, p);
*p -= *plen;
dtype = OBJ_txt2obj(SPC_SIPINFO_OBJID, 1);
SpcSipInfo_free(si);
return dtype; /* OK */
}
/*
* Allocate and return a data content to be signed.
* [in] ctx: structure holds input and output data
* [in] hash: message digest BIO
* [in] md: message digest algorithm
* [returns] data content
*/
static PKCS7 *script_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
{
ASN1_OCTET_STRING *content;
BIO *bhash;
/* squash the unused parameter warning */
(void)hash;
bhash = script_digest_calc_bio(ctx, md);
if (!bhash) {
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(bhash, ctx);
BIO_free_all(bhash);
return pkcs7_set_content(content);
}
static int script_hash_length_get(FILE_FORMAT_CTX *ctx)
{
return EVP_MD_size(ctx->options->md);
}
/*
* Compute a simple sha1/sha256 message digest of the MSI file
* for use with a catalog file.
* [in] ctx: structure holds input and output data
* [in] md: message digest algorithm
* [returns] pointer to calculated message digest
*/
static u_char *script_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
{
u_char *mdbuf;
BIO *hash = BIO_new(BIO_f_md());
if (!BIO_set_md(hash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(hash);
return NULL; /* FAILED */
}
BIO_push(hash, BIO_new(BIO_s_null()));
if (!script_write_bio(hash, ctx->options->indata, ctx->script_ctx->fileend)) {
BIO_free_all(hash);
return NULL; /* FAILED */
}
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
BIO_gets(hash, (char*)mdbuf, EVP_MD_size(md));
BIO_free_all(hash);
return mdbuf; /* OK */
}
/*
* Calculate the hash and compare to PKCS#7 signedData.
* [in] ctx: structure holds input and output data
* [in] p7: PKCS#7 signature
* [returns] 0 on error or 1 on success
*/
static int script_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
{
int mdtype = -1;
u_char mdbuf[EVP_MAX_MD_SIZE];
u_char *cmdbuf = NULL;
const EVP_MD *md;
BIO *bhash;
/* FIXME: this shared code most likely belongs in osslsigncode.c */
if (is_content_type(p7, SPC_INDIRECT_DATA_OBJID)) {
ASN1_STRING *content_val = p7->d.sign->contents->d.other->value.sequence;
const u_char *p = content_val->data;
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
if (idc) {
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
}
SpcIndirectDataContent_free(idc);
}
}
if (mdtype == -1) {
fprintf(stderr, "Failed to extract current message digest\n\n");
return 0; /* FAILED */
}
md = EVP_get_digestbynid(mdtype);
bhash = script_digest_calc_bio(ctx, md);
if (!bhash)
return 0; /* FAILED */
cmdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
BIO_gets(bhash, (char*)cmdbuf, EVP_MD_size(md));
BIO_free_all(bhash);
if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
fprintf(stderr, "Signature verification: failed\n\n");
OPENSSL_free(cmdbuf);
return 0; /* FAILED */
}
OPENSSL_free(cmdbuf);
return 1; /* OK */
}
/*
* Extract existing signature in DER format.
* [in] ctx: structure holds input and output data
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{
const char *signature_data = ctx->options->indata + ctx->script_ctx->sigpos;
size_t signature_len = ctx->script_ctx->fileend - ctx->script_ctx->sigpos;
size_t base64_len;
char *ptr;
BIO *bio_mem, *bio_b64 = NULL;
char *base64_data = NULL;
char *clean_base64 = NULL;
int clean_base64_len = 0;
const char *open_tag = ctx->script_ctx->comment_text->open;
const char *close_tag = ctx->script_ctx->comment_text->close;
size_t open_tag_len = strlen(open_tag);
size_t close_tag_len = strlen(close_tag);
size_t signature_header_len = strlen(signature_header);
size_t signature_footer_len = strlen(signature_footer);
PKCS7 *retval = NULL;
if (!script_check_file(ctx)) {
return NULL; /* FAILED, no signature */
}
/* extract Base64 signature */
if (ctx->script_ctx->utf == 8) {
base64_len = signature_len;
base64_data = OPENSSL_malloc(base64_len);
memcpy(base64_data, signature_data, base64_len);
} else {
base64_len = utf16_to_utf8((const void *)signature_data,
signature_len, &base64_data);
}
/* allocate memory for cleaned Base64 */
clean_base64 = OPENSSL_malloc(base64_len);
if (!clean_base64) {
fprintf(stderr, "Malloc failed\n");
goto cleanup;
}
/* copy clean Base64 data */
for (ptr = base64_data;;) {
/* find the opening tag */
for(;;) {
if (ptr + open_tag_len >= base64_data + base64_len) {
fprintf(stderr, "Signature line too long\n");
goto cleanup;
}
if (!memcmp(ptr, open_tag, (size_t)open_tag_len)) {
ptr += open_tag_len;
break;
}
ptr++;
}
/* process signature_header and signature_footer */
if (ptr + signature_header_len < base64_data + base64_len &&
!memcmp(ptr, signature_header, signature_header_len))
ptr += signature_header_len;
if (ptr + signature_footer_len <= base64_data + base64_len &&
!memcmp(ptr, signature_footer, signature_footer_len))
break; /* success */
/* copy until the closing tag */
for(;;) {
if (ptr + close_tag_len >= base64_data + base64_len) {
fprintf(stderr, "Signature line too long\n");
goto cleanup;
}
if (close_tag_len) {
if (!memcmp(ptr, close_tag, (size_t)close_tag_len)) {
ptr += close_tag_len;
break;
}
}
if (*ptr == '\r') {
ptr++;
} else if (*ptr == '\n') {
ptr++;
break;
} else {
clean_base64[clean_base64_len++] = *ptr++;
}
}
}
/* prepare for Base64 decoding */
bio_mem = BIO_new_mem_buf(clean_base64, clean_base64_len);
bio_b64 = BIO_new(BIO_f_base64());
BIO_push(bio_b64, bio_mem);
BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
/* decode DER */
retval = d2i_PKCS7_bio(bio_b64, NULL);
cleanup:
OPENSSL_free(base64_data);
OPENSSL_free(clean_base64);
BIO_free_all(bio_b64);
return retval;
}
/*
* Extract existing signature in DER format.
* [in] ctx: structure holds input and output data
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *script_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
{
return script_pkcs7_extract(ctx);
}
/*
* Remove existing signature.
* [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO
* [out] outdata: outdata file BIO
* [returns] 1 on error or 0 on success
*/
static int script_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{
/* squash the unused parameter warning */
(void)hash;
if (!script_check_file(ctx)) {
return 1; /* FAILED, no signature */
}
if (!script_write_bio(outdata, ctx->options->indata, ctx->script_ctx->sigpos)) {
return 1; /* FAILED */
}
return 0; /* OK */
}
/*
* Initialize outdata file and calculate a hash (message digest) of data.
* [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO
* [out] outdata: outdata file BIO
* [returns] 1 on error or 0 on success
*/
static int script_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{
if (ctx->script_ctx->sigpos > 0) {
/* Strip current signature */
ctx->script_ctx->fileend = ctx->script_ctx->sigpos;
}
if (!script_write_bio(outdata, ctx->options->indata, ctx->script_ctx->fileend))
return 0; /* FAILED */
if (!script_digest_convert(hash, ctx, ctx->script_ctx->fileend))
return 0; /* FAILED */
return 1; /* OK */
}
/*
* Create a new PKCS#7 signature.
* [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *script_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
{
ASN1_OCTET_STRING *content;
PKCS7 *p7 = pkcs7_create(ctx);
if (!p7) {
fprintf(stderr, "Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7)) {
fprintf(stderr, "Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
fprintf(stderr, "Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
}
if (!sign_spc_indirect_data_content(p7, content)) {
fprintf(stderr, "Failed to set signed content\n");
PKCS7_free(p7);
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
ASN1_OCTET_STRING_free(content);
return p7;
}
/*
* Append signature to the outfile.
* [in, out] ctx: structure holds input and output data
* [out] outdata: outdata file BIO
* [in] p7: PKCS#7 signature
* [returns] 1 on error or 0 on success
*/
static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
{
BIO *bio, *b64;
BUF_MEM *buffer;
size_t i;
static const char crlf[] = {0x0d, 0x0a};
int ret = 1;
/* convert to BASE64 */
b64 = BIO_new(BIO_f_base64()); /* BIO for base64 encoding */
if (!b64)
return 1; /* FAILED */
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bio = BIO_new(BIO_s_mem()); /* BIO to hold the base64 data */
if (!bio) {
BIO_free(b64);
return 1; /* FAILED */
}
bio = BIO_push(b64, bio); /* chain base64 BIO onto memory BIO */
if (!i2d_PKCS7_bio(bio, p7)) {
BIO_free_all(bio);
return 1; /* FAILED */
}
(void)BIO_flush(bio);
BIO_get_mem_ptr(bio, &buffer);
(void)BIO_set_close(bio, BIO_NOCLOSE);
/* split to individual lines and write to outdata */
if (!write_commented(ctx, outdata, signature_header, strlen(signature_header)))
goto cleanup;
for (i = 0; i < buffer->length; i += 64) {
if (!write_commented(ctx, outdata, buffer->data + i,
buffer->length - i < 64 ? buffer->length - i : 64)) {
goto cleanup;
}
}
if (!write_commented(ctx, outdata, signature_footer, strlen(signature_footer)))
goto cleanup;
/* signtool expects CRLF terminator at the end of the text file */
if (!write_in_encoding(ctx, outdata, crlf, sizeof crlf))
goto cleanup;
ret = 0; /* OK */
cleanup:
BUF_MEM_free(buffer);
BIO_free_all(bio);
return ret;
}
/*
* Free up an entire outdata BIO chain.
* [out] hash: message digest BIO
* [out] outdata: outdata file BIO
* [returns] none
*/
static void script_bio_free(BIO *hash, BIO *outdata)
{
BIO_free_all(hash);
BIO_free_all(outdata);
}
/*
* Deallocate a FILE_FORMAT_CTX structure and script format specific structures.
* [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO
* [out] outdata: outdata file BIO
* [returns] none
*/
static void script_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{
unmap_file(ctx->options->indata, ctx->script_ctx->fileend);
OPENSSL_free(ctx->script_ctx);
OPENSSL_free(ctx);
}
static int script_is_detaching_supported(void)
{
return 1; /* OK */
}
/*
* Script helper functions
*/
static SCRIPT_CTX *script_ctx_get(char *indata, uint32_t filesize, const SCRIPT_COMMENT *comment, int utf)
{
SCRIPT_CTX *script_ctx;
const char *input_pos, *signature_pos, *ptr;
uint32_t line[LINE_MAX_LEN], commented_header[40], cr, lf;
size_t sig_pos = 0, line_pos = 0, commented_header_len = 0;
size_t commented_header_size = sizeof commented_header / sizeof(uint32_t);
utf8DecodeRune("\r", 1, &cr);
utf8DecodeRune("\n", 1, &lf);
/* compute runes for the commented signature header */
for (ptr = comment->open;
*ptr && commented_header_len < commented_header_size;
commented_header_len++)
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
for (ptr = signature_header;
*ptr && commented_header_len < commented_header_size;
commented_header_len++)
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
for (ptr = comment->close;
*ptr && commented_header_len < commented_header_size;
commented_header_len++)
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
/* find the signature header */
for (signature_pos = input_pos = indata; input_pos < indata + filesize; ) {
const char *input_prev = input_pos;
input_pos = utf == 8 ?
utf8DecodeRune(input_pos,
(size_t)(indata + filesize - input_pos),
line + line_pos) :
(const char *)utf16DecodeRune((const void *)input_pos,
(size_t)(indata + filesize - input_pos)/2,
line + line_pos);
if (!memcmp(line + line_pos, &lf, sizeof lf)) {
if (line_pos >= commented_header_len &&
!memcmp(line, commented_header, commented_header_len * sizeof(uint32_t))) {
sig_pos = (size_t)(signature_pos - indata);
if (!memcmp(line + line_pos - 1, &cr, sizeof cr))
sig_pos -= (size_t)utf / 8;
break; /* SUCCEEDED */
}
line_pos = 0;
signature_pos = input_prev; /* previous line */
} else if (line_pos < LINE_MAX_LEN - 1) {
line_pos++; /* we can ignore lines longer than our buffer */
}
}
printf("Signature position: %zu\n", sig_pos);
script_ctx = OPENSSL_malloc(sizeof(SCRIPT_CTX));
script_ctx->comment_text = comment;
script_ctx->utf = utf;
script_ctx->fileend = filesize;
script_ctx->sigpos = (uint32_t)sig_pos;
return script_ctx; /* OK */
}
/* write a commented line to the bio:
* - prepend with CRLF ("\r\n")
* - add opening/closing comment tags
* - adjust encoding if needed
* [returns] 0 on error or 1 on success
*/
static int write_commented(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *data, size_t length)
{
const char *open_tag = ctx->script_ctx->comment_text->open;
const char *close_tag = ctx->script_ctx->comment_text->close;
size_t open_tag_len = strlen(open_tag);
size_t close_tag_len = strlen(close_tag);
char *line;
/* the buffer needs to be long enough for:
* - CRLF ("\r\n")
* - opening tag
* - up to 64 bytes of data
* - closing tag
* - trailing NUL ("\0") */
line = OPENSSL_malloc(2 + open_tag_len + length + close_tag_len + 1);
strcpy(line, "\r\n");
strcat(line, open_tag);
memcpy(line + 2 + open_tag_len, data, length);
line[2 + open_tag_len + length] = '\0';
strcat(line, close_tag);
/* adjust encoding */
if (!write_in_encoding(ctx, outdata, line, strlen(line))) {
OPENSSL_free(line);
return 0; /* FAILED */
}
OPENSSL_free(line);
return 1; /* OK */
}
/* adjust encoding if needed
* [returns] 0 on error or 1 on success
*/
static int write_in_encoding(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *line, size_t length)
{
size_t written;
if (ctx->script_ctx->utf == 8) {
if (!BIO_write_ex(outdata, line, length, &written)
|| written != length) {
return 0; /* FAILED */
}
} else {
uint16_t *utf16_data = NULL;
size_t utf16_len = utf8_to_utf16(line, length, &utf16_data);
if (!BIO_write_ex(outdata, utf16_data, utf16_len, &written)
|| written != utf16_len) {
OPENSSL_free(utf16_data);
return 0; /* FAILED */
}
OPENSSL_free(utf16_data);
}
return 1; /* OK */
}
/* convert len bytes of UTF-8 to UTF-16
* return the number of output bytes
*/
static size_t utf8_to_utf16(const char *data, size_t len, uint16_t **out_utf16)
{
size_t utf16_len = utf8UTF16Count(data, len);
*out_utf16 = OPENSSL_malloc(utf16_len * sizeof(uint16_t));
if (!*out_utf16)
return 0; /* memory allocation failed */
const char *s = data;
uint16_t *d = *out_utf16;
uint32_t rune;
size_t remaining_len = len;
while (remaining_len > 0) {
s = utf8DecodeRune(s, remaining_len, &rune);
if (!s || s < data)
break; /* invalid UTF-8 sequence */
size_t consumed = (size_t)(s - data);
remaining_len -= consumed;
data = s;
d += utf16EncodeRune(rune, d);
}
return (size_t)(2 * (d - *out_utf16));
}
/* convert len bytes of UTF-16 to UTF-8
* return the number of output bytes
*/
static size_t utf16_to_utf8(const uint16_t *data, size_t len, char **out_utf8)
{
size_t utf8_len = utf16UTF8Count(data, len/2);
*out_utf8 = OPENSSL_malloc(utf8_len);
if (!*out_utf8)
return 0; /* memory allocation failed */
const uint16_t *s = data;
char *d = *out_utf8;
uint32_t rune;
size_t remaining_len = len/2;
while (remaining_len > 0) {
s = utf16DecodeRune(s, remaining_len, &rune);
if (!s || s < data)
break; /* invalid UTF-16 sequence */
size_t consumed = (size_t)(s - data);
remaining_len -= consumed;
data = s;
d += utf8EncodeRune(rune, d);
}
return (size_t)(d - *out_utf8);
}
/*
* Compute a message digest value of a signed or unsigned script file.
* [in] ctx: structure holds input and output data
* [in] md: message digest algorithm
* [returns] calculated message digest BIO
*/
static BIO *script_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
{
size_t fileend;
BIO *hash = BIO_new(BIO_f_md());
if (ctx->script_ctx->sigpos)
fileend = ctx->script_ctx->sigpos;
else
fileend = ctx->script_ctx->fileend;
if (!BIO_set_md(hash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(hash);
return NULL; /* FAILED */
}
BIO_push(hash, BIO_new(BIO_s_null()));
if (!script_digest_convert(hash, ctx, fileend)) {
fprintf(stderr, "Unable calc a message digest value\n");
BIO_free_all(hash);
return NULL; /* FAILED */
}
return hash;
}
/*
* Compute a message digest value
* [in, out] hash: message digest BIO
* [in] ctx: structure holds input and output data
* [in] len: mapped file length
* [returns] 0 on error or 1 on success
*/
static int script_digest_convert(BIO *hash, FILE_FORMAT_CTX *ctx, size_t len)
{
if (ctx->script_ctx->utf == 8) { /* need to convert to UTF-16 */
uint16_t *utf16_data = NULL;
size_t utf16_len = utf8_to_utf16(ctx->options->indata,
len, &utf16_data);
if (!script_write_bio(hash, (char *)utf16_data, utf16_len)) {
OPENSSL_free(utf16_data);
return 0; /* FAILED */
}
OPENSSL_free(utf16_data);
} else { /* already UTF-16 -> no need to convert */
if (!script_write_bio(hash, ctx->options->indata, len)) {
return 0; /* FAILED */
}
}
return 1; /* OK */
}
/*
* Write len bytes from data to BIO
* [in, out] bio: message digest or outdata BIO
* [in] indata: mapped file
* [in] len: indata length
* [returns] 0 on error or 1 on success
*/
static int script_write_bio(BIO *bio, char *indata, size_t len)
{
size_t i = 0, written;
while (len > 0) {
if (!BIO_write_ex(bio, indata + i, len, &written))
return 0; /* FAILED */
len -= written;
i += written;
}
return 1; /* OK */
}
/*
* Check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int script_check_file(FILE_FORMAT_CTX *ctx)
{
if (!ctx) {
fprintf(stderr, "Init error\n");
return 0; /* FAILED */
}
if (ctx->script_ctx->sigpos == 0
|| ctx->script_ctx->sigpos > ctx->script_ctx->fileend) {
fprintf(stderr, "No signature found\n");
return 0; /* FAILED */
}
return 1; /* OK */
}
/*
Local Variables:
c-basic-offset: 4
tab-width: 4
indent-tabs-mode: nil
End:
vim: set ts=4 expandtab:
*/

2
tests/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
__pycache__
.pylintrc

View File

@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDoTCCAomgAwIBAgIUfuEVHNA/1VLDJI9mhANrBndIj6swDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTcwMTAxMDAwMDAwWhcNMjYxMTEwMDAwMDAwWjBYMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEQMA4GA1UEAwwHUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAMRykK9mZCSpkVUbCq1r12OXvIDkcjj+g4JpyZOrmPpz5RvmLvYBBgeV
IsUcqHm3/uSLpOFu/pwFJ2CBZVPJ1d49Y9DVnNR1dUbneWX9tE7A6NV9IG1kVagM
veI/ANLuRi0H51aAZS9L8c6WxlR4+pxJoCZp1tyTGmfjxzBEXUWvyUrIMrW/r9TH
u5gGgR6k86EbH7q71XRLhLeEi9QGCG24gobngYNZa5mb8DgLCkUeFtRsrYGEUT0G
HTpAGXUrpAb3U7+4LkGaS6mc0NPTW4lz06Z3VhyYwwAbgU2DZQjMpqYWv6UctOP+
5elPDc/PrTAdHAgbOhgvt1HUlqgn7lUCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUWIpzlJI+vefcJwcNGHwwRms/2ncwHwYDVR0jBBgwFoAUWIpz
lJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA
A4IBAQAl+G1nXXW5u3notmAG5y8kwufFqNi5Jn1HVbT08w4IiteWMw3D9GEOCueM
g5A03bC/Xv1PRvMatXQSARRvvVl3y1l98sA+97SP/FFUla3W5Rn91OsWd4qkcXhv
CtPKHpz0SCjKLv3HG/C7fBJPG9XHMgkGZarM2KsQUlkn7DjdBccYcp/zJvtvm+be
nR5ZqE6LI52WCXg0w/KlJlildU5LE/bvHbfmRUVm/4GhUNN8ko8eG67ueuftkeTD
banKmnuSay02I42A0th2w8Hz7oaOUEpl8S9TfqeFuqLhtUP0FzUNMPAg0o5YTpe4
xAArbPbFvH2l3plEaYccKYvbAGT/
-----END CERTIFICATE-----

Binary file not shown.

View File

@ -1,13 +0,0 @@
-----BEGIN X509 CRL-----
MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJQTDEVMBMGA1UE
CgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBFw0xOTAxMDEwMDAwMDBaFw00MzAx
MDEwMDAwMDBaMCcwJQIUSXAaPeUatfheDTFo77LnMBHgyeMXDTIzMDQyODEyMzMz
OVqgMDAuMB8GA1UdIwQYMBaAFOP6v42ECbVR/AiLDZ7f2WKtYXILMAsGA1UdFAQE
AgIQATANBgkqhkiG9w0BAQsFAAOCAQEARMWBcG6sanX3nwoSPGcUNEkYG2+qB8/w
wlcWWY7RfOGQWVHqbVvklJdTYFDw+mA6RuATMOd5S6hXa8tms4L2YQUmYyfNOyJu
+INPDnqueQshFZ8PqBTaP6O/NRI/LOLpcIIohgemwfPYPrbd/JqcLlQ2Vbgb9Lnb
CYZWGOF7AKC0ugTTvLuWr9LPwmWFdORtmm3UJfFOPDX6zmHPAPhBUuyrxl8UoNZB
ZPvgeBjbyQy3MaJsbaniwoOahmT+MbYV/0/YRwI5XDxjiOdJSBz3Wd5YDNDozvG6
zZMHtF9TkUZjmLUe3Jm0GnS33gU8SB6YdYpnnPg+Up4w5sye90pk9A==
-----END X509 CRL-----

View File

@ -1,14 +0,0 @@
-----BEGIN X509 CRL-----
MIICMzCCARsCAQEwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UEBhMCUEwxFTATBgNV
BAoMDG9zc2xzaWduY29kZTEgMB4GA1UECwwXQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkxHzAdBgNVBAMMFkludGVybWVkaWF0ZSBDQSBDUkwgRFAXDTE5MDEwMTAwMDAw
MFoXDTQzMDEwMTAwMDAwMFowTjAlAhQxdzwUXgMSEn/RzOwbdKtxlLgYJhcNMjMw
NDI4MTIzMzQwWjAlAhRJcBo95Rq1+F4NMWjvsucwEeDJ4xcNMjMwNDI4MTIzMzM5
WqAwMC4wHwYDVR0jBBgwFoAUYbtAOknHjmiu3l8ONAUY387kFi8wCwYDVR0UBAQC
AhACMA0GCSqGSIb3DQEBCwUAA4IBAQBOPbjiBQ1jOEjfQ1Q3/DBfzFKxeL7Cdoiq
6l1psqamZRTmU0a+1qRH/qokB0gA1XeeYIZRcruthHDk87F+WZPCKIr5cqfH2RFA
xjDEkwgA8OZSdSMh+ZhBLBoGjZhFdnX/FknMcA23cLnzuv4RmsbiokwWrysebDNY
DbTQpa/OFvqmHmgXbhrBqUinF7gl1ppzXs/d+FjSg1aAre/lx3KEXCgc126kldS9
9+c//UPmltYB17ipVWBmVOyVHNphnHtqPElD9Gz1DooVZ1opsqRBh0APu7fqmm6A
5d/lvNlPrlu835/fgUF3YmyU+w4x5sQCBjprTD6QIbIzCXDXfpBj
-----END X509 CRL-----

View File

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDhMfTdugKYNDCN
opsz9rTpYF710kq3fDN3JdmEFPoZfhZ58CBm+iZBJRCc8KoXMbKAgAZsFaUyU63M
07fYIxJeu3CTOi7kFQRy5bfGrEOnTBMKUqR+KcOZNeNYtfkv4eca25AtTyziJeBV
TOqDoVG5x75ad0+Ab4xA9bhbN4+7m5jS1aJeHtj8eDBkJOIOKGbZ0WEstffAIzWO
qCC+YFqxsXLO2hOxRgxgpsY9Va4bynn6HW0FZUcUQGEDH0Y17o2KInSyYASad7VI
F5jjiJnAzzvU701URZ7kjJFGbT9W7523Ljytl/Mvg+5qTG5JNQjVDsWHte6j1Kq8
bAHpZ6NjAgMBAAECggEBAKDpXmv1FxeE61C5aSc3WMwNxaznZ+Y2RFwV2phrmM4Q
b6UP9Uc/5YfVIUrTGObb5w207WHcEZ+ldWIPwqUZYm34h5dcEtd9QSGMjcXTn7/y
NwTASrOvygk3HU1tMjKJu+ZQD3Sgx5SMtgCdplEKO2iBlr3z1QYULubX7bSYPgcx
7sOOpEpITayd8HdOkqkqUvLKxAW5xhL2AzBQHaJiGL/zaW0uKEoOVuTrhNw4+Lnw
2IYGrdXpGLAd6hno4kOg2ZkJKWA4Yd+adroeV3BjJ2G1hLJAbPDtS/uB4ZnT1zQx
OlkqiPgnoH+16I+aLOs7MvIwQ7VRdF46Exk/9qIdHEECgYEA/sUoOQya1/JgPpbd
QeAViTvu9vCFJCnJMkyobG/CVHRDIsNwE/CpaQE+vCn/LpUeKD1KCHIjTOvLF4HM
CHt9SECApJESIdexKGP6DVoW+xnomojN/k0YW1JkrnXqmvDw5u/nvFz/JPncKZzB
+Ahx6ocORz+t10V8IRn6SlN0E4MCgYEA4khANwZ0Ys0CwVJkx5+mX3ukgXGsLDcB
p1bGrnXhbZOiZxxeWjbR/7b4PyAzsoqxiC/F3RGnU5TEPGnUUeGWv8UFsVsgd8tG
QvTOC5iEio6fs/IPZK4Asy4a5ByX6bXjbqSnypN+vf+9lFOvI/+yZ9zKejdoD5Xw
k150XRhWyqECfzDDi+9fekPbIJDaT39MZNLfpd2eK93AIcJ+6b3XplqD5lXBErK+
Xa67jkZ1w2InKJ6LHKCBOECA4V6eeW8mM9Sgg/77xXy0zDPu7u2fUMa/LsZlaQhD
uWXBX4QFDeKaO4H4aWKkajGpoXpVhsry0tsQ/qqkhaGuqxOq5T1Uu+MCgYEAhz2J
a5mm+9ntmJ9m7kxDwnOCWX8X2QEzMtFRQ7nedoAzIw84cRCsp/myGwBjBYWRH4T1
6+9+Ix0Zv8W8iQeb8peNlHeTSyWpo6DueM26AZnGZ2T3wEOi1XRrzAQu4xa7jEhK
pG9M47+yjbEKTyimdx7lwO/WeOIze9CLGYzPaqECgYBfgaE2HpG0SYKfDy0ipyxe
p5ZoGQUXksi7WHSWSTl3tA/0NTtYKCHKb1/hRezjmdRgTuqBaV3y2nF1XmlKw9EX
nYx/xAfhnyh9K7EZEMtDP2zL6tV1sp6b4Jd7sbFvM/bMJBY6KtKx59Y0u4nkgcH2
gt3jad7Axl6C3faOfjzeyw==
-----END PRIVATE KEY-----

View File

@ -1,25 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEMzCCAxugAwIBAgIUBxGrWWn+gk2O0nxUeOQvpcu0HUQwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMFUxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxHDAaBgNVBAsME1RpbWVzdGFtcCBB
dXRob3JpdHkxETAPBgNVBAMMCFRlc3QgVFNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4TH03boCmDQwjaKbM/a06WBe9dJKt3wzdyXZhBT6GX4WefAg
ZvomQSUQnPCqFzGygIAGbBWlMlOtzNO32CMSXrtwkzou5BUEcuW3xqxDp0wTClKk
finDmTXjWLX5L+HnGtuQLU8s4iXgVUzqg6FRuce+WndPgG+MQPW4WzePu5uY0tWi
Xh7Y/HgwZCTiDihm2dFhLLX3wCM1jqggvmBasbFyztoTsUYMYKbGPVWuG8p5+h1t
BWVHFEBhAx9GNe6NiiJ0smAEmne1SBeY44iZwM871O9NVEWe5IyRRm0/Vu+dty48
rZfzL4PuakxuSTUI1Q7Fh7Xuo9SqvGwB6WejYwIDAQABo4HvMIHsMAwGA1UdEwEB
/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwHQYDVR0OBBYEFHnEl41jHza4
2tqVE1fctzcQRFMNMB8GA1UdIwQYMBaAFE6fD2uX/Q6n9KjFBO5tB++jGixmMC0G
A1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvVFNBQ0EwVQYD
VR0eBE4wTKAYMAqCCHRlc3QuY29tMAqCCHRlc3Qub3JnoTAwCocIAAAAAAAAAAAw
IocgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDQYJKoZIhvcNAQEL
BQADggEBAKMnM+tX2AM6g9SSAbgAz25vHRs+/hzZN2EMZOz+ZsNZufRwRbDH4eC5
mm+s9PKw99vk/67vJk+IxfOLsZSleRX6h7DqXKhh5j8S/IPfOuIxWUfQGMlnfHNt
IdePg1vIQCwcj998e0NIdnioSnGrKRay0A1Y+7zY+9B8/sRCAamyAFyqjG5UG70q
NOZcuG52+ZHYfA3poW4MTBWTi+k9tK786RpRWj+I1ORBAJIFZ1SRzPQ5QL4XqE14
iKowHAJbo1/X6Xr/SW2B+oC+p5jmONRi/rwHnUEqWbkbi+CKWdlI+7HTApncofLi
JVHLUWz0r6IIp0mHrMwoI94yZBVXje0=
-----END CERTIFICATE-----

View File

@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDkDCCAnigAwIBAgIUf2df9lAckuBxsAT7UktJTpH8H3EwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0yNjExMTAwMDAwMDBaMGAxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB
dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH7Zl2oFIq75eVCHtPSH5apYifPyFvIAnB
J8D3/ylM+Ll5X0/mBkyU5yR7CN0T+WsroWmkkGLuDbrqRrGG30Zs6/DIgHnLn25l
rM/6C4B3TApIoBPLqLWaYd0EUwn5hyh5vJdolzCwZtr3swS1BZ23WlPXXWIO8F+m
E5QZiFWqjufoHWECyoa3OwJ+U/UcR+Tr/HnlBXaZswTJdr91R9imWZgAE6EF6qM5
ZnzNqgsjKPIN62FIcL3SD57CcR8fYvOAHGlY9r/CoDMuAs64wp/+oovC4J8WHvqV
xg/z32V7osNq4ko9IArTDESj1ZlL33uVGy/GnTAMZv1CKFMrCfMNAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE6fD2uX/Q6n9KjFBO5tB++jGixm
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEArE8W97mfL9a8NcaX
UmJwiBsoA8zGQ1uWV051JHuW+YbC1az2pRR0kXOLkXeCNhwHfxb8pvEjOToa341K
5NYFSRPJVkR09AaF7KjuLzZO821roxbZPPbS8GsFGJ5GbLe6F8EW06rCyLN03Y2q
bOAQvAof421193HIO0baBWE13QsLk2wQEYyB/Yld3919ub9plQLxapojRdK2s+cY
Juftt8hE3UDlfQkpnVbIpU4Q/LFtPztfxkcd9rkz/kujH+juBd2UnirjK3n86ReU
1MM2QvtnMlXyZiXHujrOkWGS57KaYdkDAV98zWk9Bx7g6K97cy0JPdBq2cnucUJw
0mCOiQ==
-----END CERTIFICATE-----

Binary file not shown.

View File

@ -1,15 +0,0 @@
-----BEGIN X509 CRL-----
MIICUzCCATsCAQEwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCUEwxFTATBgNV
BAoMDG9zc2xzaWduY29kZTEkMCIGA1UECwwbVGltZXN0YW1wIEF1dGhvcml0eSBS
b290IENBMRQwEgYDVQQDDAtUU0EgUm9vdCBDQRcNMTkwMTAxMDAwMDAwWhcNNDMw
MTAxMDAwMDAwWjB1MCUCFDF3PBReAxISf9HM7Bt0q3GUuBgmFw0yMzA0MjgxMjMz
NDBaMCUCFElwGj3lGrX4Xg0xaO+y5zAR4MnjFw0yMzA0MjgxMjMzMzlaMCUCFFcV
Ys5TRUZVMGFWN3Et/yQQme62Fw0yMzA0MjgxMjMzNDBaoDAwLjAfBgNVHSMEGDAW
gBROnw9rl/0Op/SoxQTubQfvoxosZjALBgNVHRQEBAICEAMwDQYJKoZIhvcNAQEL
BQADggEBAEu9tNvUMHJ69vCPdJH3FUuGPHuTyC32aLBoV/g/t9OD+95fDwwijKbX
QcypdgGEp4KEH4WQQ8JyhScgxd3gjnNoB9ITIZ14eZ9uslIZPaQztMDqvzLZcsLf
PXWWvCs8GO1K30VVqVual+OT8ojWBAgF49rg2OZX4JUAhXyaP360MtWEWVNghRwk
FhK7q6HOaNtxrIar1ZuDkvqEvmaEexJ/3HOGAM0DWmhneO2hIpCAfpYnGic66I69
17FQWE6WLTS+Hjc8qQEDPeGsSK3NWhGiOKDr1Zpjae5PknghxzfxE8u56t6pMBHj
DWYGMc57TpovDpTdla7YipkVxSrTkhI=
-----END X509 CRL-----

View File

@ -1,28 +0,0 @@
-----BEGIN PRIVATE KEY-----
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDPPtqTsdzCK99B
5zSNIiu429Tbc/S4Aa9eSsbjcefTy7NkCPankl8QeBIvQ75P98qH828iDlSH2u3N
Rp121r9wjEaM3qmkkyP0oWwjoK0du6y3hI59rHhOt3FqO0ec40Rf1yxrCKE+pCMd
TI+Ifozlxe/T7FhwxLjOIBIt4gDF6sOn06ToTC1CoVi/nd9E5vgKjuQW0F1Y7Hey
Ft64YStUXxvLB03mw8+bciZI3BQGrgOD9CCTWZVK7OO147qc8TEoQle1xKISM5wh
vaHbNUuhMRJG4qVyrZ54BICRW7r5cJZBBDVc5i1XD50Nup4wIjJtBAnPZDAwEwac
XZ53hHAPAgMBAAECggEAeGmume3XtEHFYAcz82SNPsULcc53u4nPGNwdnv0Jk3dh
bZf/p/FVpr384tVbeB8i38bDJWhqGN1NGd4Tk37GkGAQhbzBmEudsn8v06uBqirm
+WHdYIubAzF2hiCXRUKO8ZiVyEKlXT4E4Psg0k+lEcPlyp4h7LOAJNNhfKM5i8QF
3K7Pp/VcFqtwJSmu0vSycJOJWyUfqRLxgWS95r2EG1rwD46KFBCoHOa50kiZFdiI
q2h1XOiXtdaG1yn6HRS75gV4CR+MCGkczs9onSl4IpwNlq595NMCujhFcHjjKzwV
F4E/83ehtj7WruyNFwrFbabNAvLSY8nVBHabn/3L4QKBgQDrYHKn0njihjbaPT5v
1yoJyz/1eX/fscvDhQFvhQoirk/A3iSwOd1jszGvvYxRnfRnLDOszTCq/+CRSv09
sU7ECDcJPFJY8GzDMLjoBJRDtHdsFjU6tliHgyXFVpu46sIt0Z03Wglowyytc9ws
9e5uf3xolNbhdLTWfovoRp5LJwKBgQDhZ2qWOyGkVyuPn0GSVJVnOgK/PUd9b7Ze
R77i/P6sgp9d3eAXK46oYJM+6TPnQwZYE9CHUMMqHmtCm2iHqCEitZ9mvZgPt6p+
sR8HxJ/JAowDB8mOQ8usd/1S0M5e8SwSpuRajkYw0cndvwn+ezAlKsZyCN6sm73B
3ruQvVjk2QKBgAJG6pUJCjZWyg0Obp4yXKu/lZzQUhZd5/S6QqtLhC+VtBvPildS
F/ww7Zgfo03e01B0MwPG8GOXGhsNuKlyH6rx0WZ7eOh3WvYAcKl98dk907Ht/RHW
VcDp2eGw1szRKJO85WJ1soWa7cG3zzd4IZhcD14LopCHyoAQtVXH6RwdAoGAddQM
yNnCXVlgIST8LxVeQGb31qae/3htWd2hcKEWNHHYA0agBRy051oMvv9DLapA37wD
7yiNzS+3nEsHGpsOL0nIOPn1SooVa0MF2Ja1fGuDa3Yfq+nOx6q11xvmNYVXJ6zs
hFYJZS3Vm8Bo5gnZgiRZNnViidKkIHthi2kf1gkCgYBzaNgT4fbNPpgia/Vz3rd9
UIYpVzMEP6HkTVYXQH+qLzRpjl4HG6LanMbxtf/0MBHBwtEyVftKopgvkcJCDUCS
Ls+BYieF547/2W+pnV7lbz7eD6w2o7zNPNj/l+RB2PXgBZGQv1N4HgLsz+yk7eyI
s3UnnC/9NhgSMwB82OPX3g==
-----END PRIVATE KEY-----

View File

@ -1,25 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEIjCCAwqgAwIBAgIUVxVizlNFRlUwYVY3cS3/JBCZ7rYwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMEQxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA1RTQTEQMA4GA1UE
AwwHUmV2b2tlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM8+2pOx
3MIr30HnNI0iK7jb1Ntz9LgBr15KxuNx59PLs2QI9qeSXxB4Ei9Dvk/3yofzbyIO
VIfa7c1GnXbWv3CMRozeqaSTI/ShbCOgrR27rLeEjn2seE63cWo7R5zjRF/XLGsI
oT6kIx1Mj4h+jOXF79PsWHDEuM4gEi3iAMXqw6fTpOhMLUKhWL+d30Tm+AqO5BbQ
XVjsd7IW3rhhK1RfG8sHTebDz5tyJkjcFAauA4P0IJNZlUrs47XjupzxMShCV7XE
ohIznCG9ods1S6ExEkbipXKtnngEgJFbuvlwlkEENVzmLVcPnQ26njAiMm0ECc9k
MDATBpxdnneEcA8CAwEAAaOB7zCB7DAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
MAoGCCsGAQUFBwMIMB0GA1UdDgQWBBRWRawwlcW57baAiuBVmi0WFKIZqjAfBgNV
HSMEGDAWgBROnw9rl/0Op/SoxQTubQfvoxosZjAtBgNVHR8EJjAkMCKgIKAehhxo
dHRwOi8vMTI3LjAuMC4xOjE5MjU0L1RTQUNBMFUGA1UdHgROMEygGDAKggh0ZXN0
LmNvbTAKggh0ZXN0Lm9yZ6EwMAqHCAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAMA0GCSqGSIb3DQEBCwUAA4IBAQCQbgXQtFr5lWjs
tzlGJAuZfIq1f1arWWrJNSHrha9RUtm6uMoh2aMYByfEcopB9StqMo8QH4yS4LGZ
/6B81EF+dugIIb9BrE00ASgXxZ6aGGAe79VwqdG8DXp+VgRbBQA87S2KeSN8wfm+
G2AGRZF0JWS4iW5kGgrqeC14IN1FajHklrh7rOIwo/h7uVIOINWtQnHyBjlCQ6N4
OTFFgtIOY5KXtYM1A+Gx2nt3uZnEh/U/ZxHslUb55O017Qfkbf11JXFil4+ZfqMx
QuRuwMAWlyEg+1UfNae4Sg3XqPheshBzZ7ykwKGZZPeA/8kKfbXoE6Kdy5HmT/El
8e7rP/mN
-----END CERTIFICATE-----

Binary file not shown.

Binary file not shown.

View File

@ -1,46 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID7jCCAtagAwIBAgIULWwn/gLcPMAO/7oGqx5A306mxckwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMIGdMQswCQYDVQQG
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEUMBIGA1UEAwwL
Q2VydGlmaWNhdGUxJzAlBgkqhkiG9w0BCQEWGG9zc2xzaWduY29kZUBleGFtcGxl
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64qSULdxvTp7A4
2dl/JbLq7GJ4ZcPbtfUyvVTB5WuntN08bpgnxljON0Ig9lFpN2OOlms/SnodlE6Z
O8GY8kYu/aK3zHIHp3EykzRP1glf7ukcCMpcSaS5VUho0QQ9PVvvMHVNtaQ00r2i
34m8DbGj4aRUNI5eA6Xlzz8QnhvCgtRTVbp5ZRjxo1ZNq2eEZxa6UnFshlx6i0/o
kYPrdKTIvUv2zoRFd9H/7+B2Xwse+qppcZe0BiKSa4l6PrL2iHteYE29ggLLSqe+
zavGN7Ev7jP+bZLU/5eq58SBy8uFBDkh1FvZEPAnJ2X/vwNzySi6KTliCPc9Jf5G
wSJr+5MCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUVeUILLpF5PWz5rAD
iWzV/2oEP3UwHwYDVR0jBBgwFoAU4/q/jYQJtVH8CIsNnt/ZYq1hcgswEwYDVR0l
BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAHckjLcj9mswr08aF7MV
EZTKKh0IOaHj7oh6vLR5Yg2n+E+9Gog/+ulbKXNe/5A9QU2R1NdwZKEeUeSuF4qW
P3JB79BepgR6/VYKyVWH7St4ixy1GtNEFrHWsID212Jd0Rr3+kc9OJUO0aw3nvg7
Apsr1dztjwlUN2ugLzVoDJ2wMqlu5ZQW8pINIYet127cX5knW/acPCPcqPVD7jmm
C40xgqeKD2a6OafSS5hjO4UeCoeHnXlJ4Sep8wz8VDlu39Hr4dwFm8v9MuvBusCr
/sdwzTRAc6mhBL/4PyJrBRhibbTxSaDKBHeWcKpmNp4DIk1vc8h6yhDUb1fgafgX
7nI=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
-----END CERTIFICATE-----

Binary file not shown.

View File

@ -1,47 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEPTCCAyWgAwIBAgIUZp72ahjzVryMA56ev7+Z8Rxyo2kwDQYJKoZIhvcNAQEL
BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0
ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMjQxMjMxMDAwMDAwWjCBqzEL
MAkGA1UEBhMCUEwxGTAXBgNVBAgMEE1hem92aWEgUHJvdmluY2UxDzANBgNVBAcM
BldhcnNhdzEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1AxIjAg
BgNVBAMMGUNlcnRpZmljYXRlIFg1MDl2MyBDUkwgRFAxJzAlBgkqhkiG9w0BCQEW
GG9zc2xzaWduY29kZUBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAL64qSULdxvTp7A42dl/JbLq7GJ4ZcPbtfUyvVTB5WuntN08bpgn
xljON0Ig9lFpN2OOlms/SnodlE6ZO8GY8kYu/aK3zHIHp3EykzRP1glf7ukcCMpc
SaS5VUho0QQ9PVvvMHVNtaQ00r2i34m8DbGj4aRUNI5eA6Xlzz8QnhvCgtRTVbp5
ZRjxo1ZNq2eEZxa6UnFshlx6i0/okYPrdKTIvUv2zoRFd9H/7+B2Xwse+qppcZe0
BiKSa4l6PrL2iHteYE29ggLLSqe+zavGN7Ev7jP+bZLU/5eq58SBy8uFBDkh1FvZ
EPAnJ2X/vwNzySi6KTliCPc9Jf5GwSJr+5MCAwEAAaOBmzCBmDAJBgNVHRMEAjAA
MB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJbNX/agQ/dTAfBgNVHSMEGDAWgBRhu0A6
SceOaK7eXw40BRjfzuQWLzATBgNVHSUEDDAKBggrBgEFBQcDAzA2BgNVHR8ELzAt
MCugKaAnhiVodHRwOi8vMTI3LjAuMC4xOjE5MjU0L2ludGVybWVkaWF0ZUNBMA0G
CSqGSIb3DQEBCwUAA4IBAQC2yNGXw1VZqBWY7cnJtiZpupKYCifRC1dEFlKcozpd
dhWHDKpGDCzqaL/WKpqFjOIrCbG6gsfB+nu2VQv4nE8lwwelMgpeVB+v197A1SvE
wLl71R5a7sxF0x5aBdUyWeCTeBLu6KuWQrpPcZVM3uMqhqCJ8CiSUtS1cKn1K1K0
KRSgFTs4AFUc0rOa3wYvytps4cw/TyDXArlvGVMlDHNLffEsx3vElZafaGvyEK0J
TsBM2dakcpP/ceuJU1gd8hLadzjfKOFml7z+qHfUa/mky+veK2M5vKn1ph55qYHc
WtEY/wwBjgqE2VseqMLb06J3tXmTKgESGXISAnqoau+t
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF
-----END CERTIFICATE-----

View File

@ -1,23 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDzjCCAragAwIBAgIUKUVnRllbtypXICoznroWil39jU4wDQYJKoZIhvcNAQEL
BQAwbzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEMMAoGA1UE
CwwDQ1NQMRIwEAYDVQQDDAljcm9zc2NlcnQxJzAlBgkqhkiG9w0BCQEWGG9zc2xz
aWduY29kZUBleGFtcGxlLmNvbTAeFw0xODAxMDEwMDAwMDBaFw0yMDA2MTkwMDAw
MDBaMG8xCzAJBgNVBAYTAlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNV
BAsMA0NTUDESMBAGA1UEAwwJY3Jvc3NjZXJ0MScwJQYJKoZIhvcNAQkBFhhvc3Ns
c2lnbmNvZGVAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDFCjBrTLeh9wyMb6tJi1SMz+Pe6Eb8SCg4+soxBAu1EEVo4Ao810j2NVdc
aoQ2Ki097hl9LHcA0DMT8AFRHfXMXHSSHoYHsPcwHO6RJHXcDE4fSgkl41GtCnf+
qUOA+QZUqNNKNOELUHboydFMytNGjuSaO29BObkiHCRB8gnfKuqGZn9YrfU8AoGu
xv7RzKgD+uC/dTZSONAW+h7TuRn4/qtqTqfk5SnmTeEDbW3lyYLToRRKUKcYR68a
lT/IZ2cHCrZMqvykR2cCMCARbTyI8ZQ6ogzXS/tncJYu/RTtEoKiN1EweG5R0cgU
G0xQISw5RXMUSgWkWUL8rYpFcmahAgMBAAGjYjBgMAkGA1UdEwQCMAAwHQYDVR0O
BBYEFBt9u2LhSzaQrQLcja2QtFexM2tKMB8GA1UdIwQYMBaAFBt9u2LhSzaQrQLc
ja2QtFexM2tKMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IB
AQATfeXQ2kj+97IHUOtFZTjcIH47U6k8Po11WD+Af4PRmacOKaSv+rlmgpgHfQJV
nM90mxUvKzaoJeId/yR++U86rcu8a87njHoyDzx2HMcc47P/2VkErT9W4gyJE0Ws
JyIR0k0XZiYJ+pJOSjnd7SY2gs1oBT3+Go5TyClAfzAP+U10fK52q802XNPw5MY0
LEyRqCH4QYb71Hd4kGqROVy1EPv18d26apD9vK/zZuvOsbz23l0mdochYrtmfAA0
LuNwefIgxzki22+bZe7lJyuV5WsqSNGVty+fvqmw9JUfzeOpIzVK/SxqANJnZBBI
kapgFmTwk4JEfB3n2WTmbs9C
-----END CERTIFICATE-----

View File

@ -1,45 +0,0 @@
-----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIUW4SefwoiLUfTBaHpZyd8knsGVBswDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0xOTAxMDEwMDAwMDBaMIGZMQswCQYDVQQG
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UEAwwH
RXhwaXJlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUuY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ2X8l
sursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7wZjy
Ri79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLfibwN
saPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0
pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77Nq8Y3
sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbBImv7
kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJbNX/
agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUEDDAK
BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAp06uHnxO63Ecn+knaXkfrNGg
pr+4WCc0onXYOE37+IwsCFaUqCIr1UsnnKWSzSlSR07FHI+VaV9r3knT6VPMVsUU
L89jHC2vLUvyJJOtuTpuOVGIzzCquYWvYRZrp2wmTceMSNhLcO1VGs28uwQojWEQ
ZsEdFvkYeWFInUQ1mF0dLnfQjh7RcTxMJ0CxZblJ086j3AbyzM6ZF6XAVPAqBH/S
gsBfLVGnZnMOwvKwsxViG1ikRusO6GtcIy6yxmNCUhWbIL+R59EYy++x3xLVUU90
YnScDN+xM9A2wHO1hQpLK6DIiHpbAzAgll5xD0JWh+efRWHEtGN5JTybowG9yA==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
-----END CERTIFICATE-----

View File

@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
-----END CERTIFICATE-----

View File

@ -1,22 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF
-----END CERTIFICATE-----

Binary file not shown.

View File

@ -1,27 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAvripJQt3G9OnsDjZ2X8lsursYnhlw9u19TK9VMHla6e03Txu
mCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7wZjyRi79orfMcgencTKTNE/WCV/u6RwI
ylxJpLlVSGjRBD09W+8wdU21pDTSvaLfibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNV
unllGPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0pMi9S/bOhEV30f/v4HZfCx76qmlx
l7QGIpJriXo+svaIe15gTb2CAstKp77Nq8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHU
W9kQ8CcnZf+/A3PJKLopOWII9z0l/kbBImv7kwIDAQABAoIBAQCEsjqNWcLPi53a
kFOSblKuf6FkidxUP2QEa/8rH5UeKBtA6rEQEGyCkUgFLKX00r4E+MpTaD/LYxUy
8o6PDnlSt5MlSbhnhkfMDKI6/WkwMJ0rd6PuF/PtNj3OGY+D4Y/1jSAsHZtJ2q7d
3pqlXEAy3pE6IpRGkcb8AD8H4+n96U4sNnytll6//5uD55PRbxZwB0mmNJOVoZJK
+CbW0wV3rKS0UslFot/b/jNvmCQym3UmWz3elShRTZTA7cdQt2YtKaFO5zFxbbh/
L0+Rija2tVyUPswSbeGxiyfF2RRt++91S6RONfc9B0JKwkNkbQEcM+dPIfIe/nIc
8CgSCUThAoGBAOUMBWLhxE6QW1KeR59d00wtnWzN7x1CQ43LciIRMz3C8BQLpRmX
DmTDASxy9B19tEhdVHzYhq/+1x+vM7TWiPeLg2IhvFZEhpIdN7J1n0iUI3P08dHn
KmvHSu1XGQfngIMT/Ey9xdMpAxsZVJsScuT3sUxnUKxzFpCvTuiCP4ibAoGBANUq
FyAywSsGCrl77BaQh9GDsrL3i67owfpWMs6JjywfEFdpfGZnJTCvlfKtv/Jrp4jB
p5PM5IOil63RqQXa8/pv9pQr2DUGmKegNhDGgflK5+BcbTpkAYIcGHekhoTy2TXU
BnlKaNy5Te80yEFVfFRejK1rQ2ZqHqZP3WtzBBxpAoGBAOGhAOFSg13dKIjvcKCV
/aLKQIzBJG6PKxrQMeNLTE3n7TXh7saRnlU2H77Yko9GmES845CEf9F5WhNVNLtM
puor3cXac7wLjwD6lTZQVhNaEr6UqW5bqNc5IB9DMF4v99Gn617xhqGnge68+jI0
b0gMk/QuxjLKwIzQlQvH2qxHAoGAaFYXx6zQHAzzBuL/JfRMZmK9/xdniY9oEu5K
JAn0yDXUO9ToDP+Dlpb7IDOndjL3Z9rR+WgamcvlzjCHONR5AyX2XYQwaZP2+GVU
0VU4nRrq8EiNNj1o95Rk7XrcVQrBArXrDUc8mH0jBmihdEkxd+JnnSKZdPGQWvtQ
d51ub7ECgYBHbn8uyl4sHLj6y5L2KjsVFpLJp7OFNv3UUN9TrY+rd+CjmTFBSE52
XaV7v8Ul5nDRom5D5R/z8iFK+3Nx7PJq+WesEAPfNPc+BJFkRdJW6ysp/jHnpRV/
rUTaWgQp5/em1GAvBHa8KAoPAS5WAY/lxByruBSTbUSNuC5gz52xzg==
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@ -1,30 +0,0 @@
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,B9C24663685D6009
GMA8W6sGC+xtNYoPzX2j0driKlngRIbmABYMbm8TSac8du7/S8uBcG2i6z/d0Plu
pHr06uIcZDjCN0iWkhMGS7ai40ddBjxjDS/f9ppUZdOtTX4MzGfqb/d9LGVi1P8W
zYSuz7BI0B2ttcbpmMIhxdGMtRz8A/MDPm8eBnEmIYjRiW/ES2HfHlrm7CFlrd72
vgiAmFPtx9P5AE+KMFiSJDkSVMKX52yvLfBQAeBU2aQI7z5BTfwIpGgVKBT5qhq4
EwL24FrEJ1+20Q/Resd/nfqv6lzNPl6SQLhCgY25Yz0Ke9u8Xnhn1aoz1BCDtw8u
fnzmaqexf6w70rC1qX+CyrHLxO19lRUn5wChyPYaU2oAt3a0iKktQWdqHUIAGi+d
Q3DpgsXlQXuXHDeBh5KKePz6g1f7pjacpjH8t8Y3VqurQop8Ku5KiVln+WyVklbS
9ipr4Btf8NnWWD+kAvdo01ObRRGYxZwj/mlr9ePQ2d2vd9wNLe8zS0FZSzBE7cZH
OPMuZnjU9Ruub0GJpHzsNBhMNIl6M6c2DSphrUTZBG6Sogx/aVSxe3Z5sojULfNT
aifhUP/qR94nFokwRs77zXwWJlIF02g6caL8P/fPAcxIaItl+Q3DFo0wEZOzDI2X
7ijPoEj/TReVajulxCcISJs5F6gaPKhNW8FKxvFH+3LnMLW/BeHNSGgnIFftkI3Z
GqwcLN+X76qhPzS1UFF12fW9wYXjhMnR6bvVaadP6+XadZonyE+eGdRjZH0M2IIF
Jv6si9Zxw+sesmmFXzjU0jzv825rD0NtPpYKWaCdtX1x5fkk+A4T28Yu1uLWfJcs
4LhEkfhgILjLY02idjX4OKmwKm4w+QqBeajBCZiGTl6Fk2mvC0wCy53AEH3UTu8I
KRkEAcl1CxsYAHZb9B00ymk3iyGTQ/1luLZfPkGS6CMJPXjSjR0i8NmOaYa+Xhe7
bsCPYWeGT1ttJh+A5Dh39K00lSrIuQS9m3lKzdlHhZ8YL8DdeUAMBM6JKI3p8V9s
xeb/w9Vf7iZRLsL6yDqj4zm5HFifRpFDpD/E2rC6zpUvdFiy2p6J7Xpo2cu3wMIV
QL1te4aHVQhWsijV7LoaS3452NOnknxiNxXFWk2POwPHL1i6rmS7MlQwqDlLBilj
O2R4YZGjmRg69zr9xJJGQQnroFEagKdhedSJ2y+lqwxl1Kb+Lp0+SOVesxfjfoeZ
y0ctY7IJZksM0htETT6fhfJKSbMfM2uRL3FJkv1QyexnIlwmZxZgUyYAJemTZJBY
BbAhhmTRswhp5FWdfFbYez7cV9AIhtNCoGcNQuQ+wL9OmIQbmZjFUqLIcHVyX1xA
Zj5Jh6aybmnJTdXyIwUP3RdkHrD5JW8+d/0xMm1G89PtDJ6Q2+D3drtTB7A3ruUD
uyDhYtpyY9m940miAsvByK2jIUlA0hLb+9+1oiWcWarl7IwxpjP8CUG6nAF7BU6v
J/Hbikx0XMfycYp1EsQYUP4ku+S/PoJsMNU4bt248E+dDALxoyQN1Z41sYILBz4Y
ga6z4zCA5+66ug8z2yMbC4bCo0FZxuJLcw+Ok05+PT0fW9Z3egpybXVwwY4wc6vs
-----END RSA PRIVATE KEY-----

Binary file not shown.

View File

@ -1 +0,0 @@
passme

View File

@ -1,45 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIDvTCCAqWgAwIBAgIUSXAaPeUatfheDTFo77LnMBHgyeMwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMG0xCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UE
AwwHUmV2b2tlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUu
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ
2X8lsursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7
wZjyRi79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLf
ibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iR
g+t0pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77N
q8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbB
Imv7kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJ
bNX/agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUE
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAK/bCZPrxN+5HGQjZLIQg
jKfjTRL5xwBGs8+VW4i+xnaA14pyZjDlYzASmCE/ZiryVSMJ7fuQ0TVXGtz3N7PM
v9pRgtcohs62NJZ5dIrq4f/Op1bii29pAA8+2EHPJUyFBt23vyvlI/dBpkgQG6mi
OUEsXQ+Q2LUD4OOJffkc/gowXcB4WFjrtFAUuu9HeZUNzV5Mm5FQTGm9nCnWsDIb
b7Yx08hMy+6jtvkNPCDcFnos2bsipmVN4fCXkm5LPZNyMFoWReDbIKWASXaao2hN
gzWhwWsPlAGAlBPMVWEo3k2Cz/entbAijoyqS2koN4mZABy7m5+vfzFw/yvh1/lu
8w==
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
-----END CERTIFICATE-----

View File

@ -1,46 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEDDCCAvSgAwIBAgIUMXc8FF4DEhJ/0czsG3SrcZS4GCYwDQYJKoZIhvcNAQEL
BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0
ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMjQxMjMxMDAwMDAwWjB7MQsw
CQYDVQQGEwJQTDEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1Ax
HjAcBgNVBAMMFVJldm9rZWQgWDUwOXYzIENSTCBEUDEnMCUGCSqGSIb3DQEJARYY
b3NzbHNpZ25jb2RlQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAvripJQt3G9OnsDjZ2X8lsursYnhlw9u19TK9VMHla6e03TxumCfG
WM43QiD2UWk3Y46Waz9Keh2UTpk7wZjyRi79orfMcgencTKTNE/WCV/u6RwIylxJ
pLlVSGjRBD09W+8wdU21pDTSvaLfibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNVunll
GPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0pMi9S/bOhEV30f/v4HZfCx76qmlxl7QG
IpJriXo+svaIe15gTb2CAstKp77Nq8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ
8CcnZf+/A3PJKLopOWII9z0l/kbBImv7kwIDAQABo4GbMIGYMAkGA1UdEwQCMAAw
HQYDVR0OBBYEFFXlCCy6ReT1s+awA4ls1f9qBD91MB8GA1UdIwQYMBaAFGG7QDpJ
x45ort5fDjQFGN/O5BYvMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDYGA1UdHwQvMC0w
K6ApoCeGJWh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvaW50ZXJtZWRpYXRlQ0EwDQYJ
KoZIhvcNAQELBQADggEBALwDivFFBjB7AkLO1jPJFyJnq8C0gadoYq0Dq5roAFMq
Lirl0LGsdFTrZ2ljKOzNrFVfw4EQHedDCsKCtsgOXG1xxLQczwsuBcIaWGzSdW15
iNz+IKjHXSNOLEUvVcO6N6s1rt5U15lynaXFSdskBgJYA7vq6uA8RTWzhQC7aCv8
n3Tbpe8c7j6/y5NThffBu/YZypMoraZvPohCDfMZoFNT5GYXNWSeq7gipxtaCHcK
OdWBi5yajIZL05hg29y7r677KBbvo07EykhxQ10zEnskzuqc7hCCsuDrXbmt5brv
REYpeGvJAu0YrFg9yLSl8FJwk/XUzGvxa2MLPyL/sj4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF
-----END CERTIFICATE-----

View File

@ -1,47 +0,0 @@
-----BEGIN CERTIFICATE-----
MIIEMzCCAxugAwIBAgIUBxGrWWn+gk2O0nxUeOQvpcu0HUQwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMFUxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxHDAaBgNVBAsME1RpbWVzdGFtcCBB
dXRob3JpdHkxETAPBgNVBAMMCFRlc3QgVFNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEA4TH03boCmDQwjaKbM/a06WBe9dJKt3wzdyXZhBT6GX4WefAg
ZvomQSUQnPCqFzGygIAGbBWlMlOtzNO32CMSXrtwkzou5BUEcuW3xqxDp0wTClKk
finDmTXjWLX5L+HnGtuQLU8s4iXgVUzqg6FRuce+WndPgG+MQPW4WzePu5uY0tWi
Xh7Y/HgwZCTiDihm2dFhLLX3wCM1jqggvmBasbFyztoTsUYMYKbGPVWuG8p5+h1t
BWVHFEBhAx9GNe6NiiJ0smAEmne1SBeY44iZwM871O9NVEWe5IyRRm0/Vu+dty48
rZfzL4PuakxuSTUI1Q7Fh7Xuo9SqvGwB6WejYwIDAQABo4HvMIHsMAwGA1UdEwEB
/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwHQYDVR0OBBYEFHnEl41jHza4
2tqVE1fctzcQRFMNMB8GA1UdIwQYMBaAFE6fD2uX/Q6n9KjFBO5tB++jGixmMC0G
A1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvVFNBQ0EwVQYD
VR0eBE4wTKAYMAqCCHRlc3QuY29tMAqCCHRlc3Qub3JnoTAwCocIAAAAAAAAAAAw
IocgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDQYJKoZIhvcNAQEL
BQADggEBAKMnM+tX2AM6g9SSAbgAz25vHRs+/hzZN2EMZOz+ZsNZufRwRbDH4eC5
mm+s9PKw99vk/67vJk+IxfOLsZSleRX6h7DqXKhh5j8S/IPfOuIxWUfQGMlnfHNt
IdePg1vIQCwcj998e0NIdnioSnGrKRay0A1Y+7zY+9B8/sRCAamyAFyqjG5UG70q
NOZcuG52+ZHYfA3poW4MTBWTi+k9tK786RpRWj+I1ORBAJIFZ1SRzPQ5QL4XqE14
iKowHAJbo1/X6Xr/SW2B+oC+p5jmONRi/rwHnUEqWbkbi+CKWdlI+7HTApncofLi
JVHLUWz0r6IIp0mHrMwoI94yZBVXje0=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDkDCCAnigAwIBAgIUf2df9lAckuBxsAT7UktJTpH8H3EwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0yNjExMTAwMDAwMDBaMGAxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB
dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH7Zl2oFIq75eVCHtPSH5apYifPyFvIAnB
J8D3/ylM+Ll5X0/mBkyU5yR7CN0T+WsroWmkkGLuDbrqRrGG30Zs6/DIgHnLn25l
rM/6C4B3TApIoBPLqLWaYd0EUwn5hyh5vJdolzCwZtr3swS1BZ23WlPXXWIO8F+m
E5QZiFWqjufoHWECyoa3OwJ+U/UcR+Tr/HnlBXaZswTJdr91R9imWZgAE6EF6qM5
ZnzNqgsjKPIN62FIcL3SD57CcR8fYvOAHGlY9r/CoDMuAs64wp/+oovC4J8WHvqV
xg/z32V7osNq4ko9IArTDESj1ZlL33uVGy/GnTAMZv1CKFMrCfMNAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE6fD2uX/Q6n9KjFBO5tB++jGixm
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEArE8W97mfL9a8NcaX
UmJwiBsoA8zGQ1uWV051JHuW+YbC1az2pRR0kXOLkXeCNhwHfxb8pvEjOToa341K
5NYFSRPJVkR09AaF7KjuLzZO821roxbZPPbS8GsFGJ5GbLe6F8EW06rCyLN03Y2q
bOAQvAof421193HIO0baBWE13QsLk2wQEYyB/Yld3919ub9plQLxapojRdK2s+cY
Juftt8hE3UDlfQkpnVbIpU4Q/LFtPztfxkcd9rkz/kujH+juBd2UnirjK3n86ReU
1MM2QvtnMlXyZiXHujrOkWGS57KaYdkDAV98zWk9Bx7g6K97cy0JPdBq2cnucUJw
0mCOiQ==
-----END CERTIFICATE-----

View File

@ -1 +0,0 @@
55c4d523e595564af0ab635fd1e3aaba

View File

@ -0,0 +1,40 @@
#!/usr/bin/python3
"""Check cryptography module."""
import sys
try:
import cryptography
print(cryptography.__version__, end="")
except ModuleNotFoundError as ierr:
print("Module not installed: {}".format(ierr))
sys.exit(1)
except ImportError as ierr:
print("Module not found: {}".format(ierr))
sys.exit(1)
class UnsupportedVersion(Exception):
"""Unsupported version"""
def main() -> None:
"""Check python3-cryptography version"""
try:
version = tuple(int(num) for num in cryptography.__version__.split('.'))
if version < (37, 0, 2):
raise UnsupportedVersion("unsupported python3-cryptography version")
except UnsupportedVersion as err:
print(" {}".format(err), end="")
sys.exit(1)
if __name__ == '__main__':
main()
# pylint: disable=pointless-string-statement
"""Local Variables:
c-basic-offset: 4
tab-width: 4
indent-tabs-mode: nil
End:
vim: set ts=4 expandtab:
"""

View File

@ -1,3 +1,4 @@
#!/usr/bin/python3
"""Implementation of a HTTP client""" """Implementation of a HTTP client"""
import os import os
@ -5,17 +6,17 @@ import sys
import http.client import http.client
RESULT_PATH = os.getcwd() RESULT_PATH = os.getcwd()
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
PORT_LOG = os.path.join(LOGS_PATH, "./port.log")
def main() -> None: def main() -> None:
"""Creating a POST Request""" """Creating a POST Request"""
ret = 0 ret = 0
try: try:
with open(PORT_LOG, 'r') as file: file_path = os.path.join(RESULT_PATH, "./Testing/logs/url.log")
port = file.readline() with open(file_path, mode="r", encoding="utf-8") as file:
conn = http.client.HTTPConnection('localhost', port) url = file.readline()
host, port = url.split(":")
conn = http.client.HTTPConnection(host, port)
conn.request('POST', '/kill_server') conn.request('POST', '/kill_server')
response = conn.getresponse() response = conn.getresponse()
print("HTTP status code:", response.getcode(), end=', ') print("HTTP status code:", response.getcode(), end=', ')

View File

@ -1,424 +0,0 @@
#!/bin/bash
result=0
test_result() {
if test "$1" -eq 0
then
printf "Succeeded\n" >> "makecerts.log"
else
printf "Failed\n" >> "makecerts.log"
fi
}
make_certs() {
password=passme
result_path=$(pwd)
cd $(dirname "$0")
script_path=$(pwd)
cd "${result_path}"
mkdir "tmp/"
################################################################################
# OpenSSL settings
################################################################################
if test -n "$1"
then
OPENSSL="$1/bin/openssl"
export LD_LIBRARY_PATH="$1/lib:$1/lib64"
else
OPENSSL=openssl
fi
mkdir "CA/" 2>> "makecerts.log" 1>&2
touch "CA/index.txt"
echo -n "unique_subject = no" > "CA/index.txt.attr"
$OPENSSL rand -hex 16 > "CA/serial"
$OPENSSL rand -hex 16 > "tmp/tsa-serial"
echo 1001 > "CA/crlnumber"
date > "makecerts.log"
"$OPENSSL" version 2>> "makecerts.log" 1>&2
echo -n "$password" > tmp/password.txt
################################################################################
# Root CA certificate
################################################################################
printf "\nGenerate root CA certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/CA.key \
2>> "makecerts.log" 1>&2
test_result $?
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_root.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/CA.key -out tmp/CACert.pem \
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Root CA" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
################################################################################
# Private RSA keys
################################################################################
printf "\nGenerate private RSA encrypted key\n" >> "makecerts.log"
"$OPENSSL" genrsa -des3 -out CA/private.key -passout pass:"$password" \
2>> "makecerts.log" 1>&2
test_result $?
cat CA/private.key >> tmp/keyp.pem 2>> "makecerts.log"
test_result $?
printf "\nGenerate private RSA decrypted key\n" >> "makecerts.log"
"$OPENSSL" rsa -in CA/private.key -passin pass:"$password" -out tmp/key.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nConvert the key to DER format\n" >> "makecerts.log"
"$OPENSSL" rsa -in tmp/key.pem -outform DER -out tmp/key.der -passout pass:"$password" \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nConvert the key to PVK format\n" >> "makecerts.log"
"$OPENSSL" rsa -in tmp/key.pem -outform PVK -out tmp/key.pvk -pvk-none \
2>> "makecerts.log" 1>&2
test_result $?
################################################################################
# Intermediate CA certificates
################################################################################
CONF="${script_path}/openssl_intermediate.cnf"
printf "\nGenerate intermediate CA certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/intermediateCA.key \
2>> "makecerts.log" 1>&2
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_intermediate.cnf"
"$OPENSSL" req -config "$CONF" -new -key CA/intermediateCA.key -out CA/intermediateCA.csr \
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Intermediate CA" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_root.cnf"
"$OPENSSL" ca -config "$CONF" -batch -in CA/intermediateCA.csr -out CA/intermediateCA.cer \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
"$OPENSSL" x509 -in CA/intermediateCA.cer -out tmp/intermediateCA.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nGenerate a certificate to revoke\n" >> "makecerts.log"
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/revoked.csr \
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=Revoked/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" ca -config "$CONF" -batch -in CA/revoked.csr -out CA/revoked.cer \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" x509 -in CA/revoked.cer -out tmp/revoked.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nRevoke above certificate\n" >> "makecerts.log"
"$OPENSSL" ca -config "$CONF" -revoke CA/revoked.cer \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nAttach intermediate certificate to revoked certificate\n" >> "makecerts.log"
cat tmp/intermediateCA.pem >> tmp/revoked.pem 2>> "makecerts.log"
test_result $?
printf "\nGenerate CRL file\n" >> "makecerts.log"
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_intermediate.cnf"
"$OPENSSL" ca -config "$CONF" -gencrl -crldays 8766 -out tmp/CACertCRL.pem \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nGenerate CSP Cross-Certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/cross.key \
2>> "makecerts.log" 1>&2
TZ=GMT faketime -f '@2018-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_intermediate.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 900 -key CA/cross.key -out tmp/crosscert.pem \
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=crosscert/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nGenerate code signing certificate\n" >> "makecerts.log"
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/cert.csr \
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" ca -config "$CONF" -batch -in CA/cert.csr -out CA/cert.cer \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" x509 -in CA/cert.cer -out tmp/cert.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nConvert the certificate to DER format\n" >> "makecerts.log"
"$OPENSSL" x509 -in tmp/cert.pem -outform DER -out tmp/cert.der \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nAttach intermediate certificate to code signing certificate\n" >> "makecerts.log"
cat tmp/intermediateCA.pem >> tmp/cert.pem 2>> "makecerts.log"
test_result $?
printf "\nConvert the certificate to SPC format\n" >> "makecerts.log"
"$OPENSSL" crl2pkcs7 -nocrl -certfile tmp/cert.pem -outform DER -out tmp/cert.spc \
2>> "makecerts.log" 1>&2
test_result $?
ssl_version=$("$OPENSSL" version)
if test "${ssl_version:8:1}" -eq 3
then
printf "\nConvert the certificate and the key into legacy PKCS#12 container with\
RC2-40-CBC private key and certificate encryption algorithm\n" >> "makecerts.log"
"$OPENSSL" pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/legacy.p12 -passout pass:"$password" \
-keypbe rc2-40-cbc -certpbe rc2-40-cbc -legacy \
2>> "makecerts.log" 1>&2
else
printf "\nConvert the certificate and the key into legacy PKCS#12 container with\
RC2-40-CBC private key and certificate encryption algorithm\n" >> "makecerts.log"
"$OPENSSL" pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/legacy.p12 -passout pass:"$password" \
-keypbe rc2-40-cbc -certpbe rc2-40-cbc \
2>> "makecerts.log" 1>&2
fi
test_result $?
printf "\nConvert the certificate and the key into a PKCS#12 container with\
AES-256-CBC private key and certificate encryption algorithm\n" >> "makecerts.log"
"$OPENSSL" pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/cert.p12 -passout pass:"$password" \
-keypbe aes-256-cbc -certpbe aes-256-cbc \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nGenerate expired certificate\n" >> "makecerts.log"
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/expired.csr \
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Expired/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" ca -config "$CONF" -enddate "190101000000Z" -batch -in CA/expired.csr -out CA/expired.cer \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" x509 -in CA/expired.cer -out tmp/expired.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nAttach intermediate certificate to expired certificate\n" >> "makecerts.log"
cat tmp/intermediateCA.pem >> tmp/expired.pem 2>> "makecerts.log"
test_result $?
################################################################################
# Intermediate CA certificates with CRL distribution point
################################################################################
CONF="${script_path}/openssl_intermediate_crldp.cnf"
printf "\nGenerate intermediate CA certificate with CRL distribution point\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/intermediateCA_crldp.key \
2>> "makecerts.log" 1>&2
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_intermediate_crldp.cnf"
"$OPENSSL" req -config "$CONF" -new -key CA/intermediateCA_crldp.key -out CA/intermediateCA_crldp.csr \
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Intermediate CA CRL DP" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_root.cnf"
"$OPENSSL" ca -config "$CONF" -batch -in CA/intermediateCA_crldp.csr -out CA/intermediateCA_crldp.cer \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
"$OPENSSL" x509 -in CA/intermediateCA_crldp.cer -out tmp/intermediateCA_crldp.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nGenerate a certificate with X509v3 CRL Distribution Points extension to revoke\n" >> "makecerts.log"
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/revoked_crldp.csr \
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=Revoked X509v3 CRL DP/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" ca -config "$CONF" -batch -in CA/revoked_crldp.csr -out CA/revoked_crldp.cer \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" x509 -in CA/revoked_crldp.cer -out tmp/revoked_crldp.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nRevoke above certificate\n" >> "makecerts.log"
"$OPENSSL" ca -config "$CONF" -revoke CA/revoked_crldp.cer \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nAttach intermediate certificate to revoked certificate\n" >> "makecerts.log"
cat tmp/intermediateCA_crldp.pem >> tmp/revoked_crldp.pem 2>> "makecerts.log"
test_result $?
printf "\nGenerate CRL file\n" >> "makecerts.log"
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_intermediate_crldp.cnf"
"$OPENSSL" ca -config "$CONF" -gencrl -crldays 8766 -out tmp/CACertCRL_crldp.pem \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nConvert CRL file from PEM to DER (for CRL Distribution Points server to use) \n" >> "makecerts.log"
"$OPENSSL" crl -in tmp/CACertCRL_crldp.pem -inform PEM -out tmp/CACertCRL.der -outform DER \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nGenerate code signing certificate with X509v3 CRL Distribution Points extension\n" >> "makecerts.log"
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/cert_crldp.csr \
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate X509v3 CRL DP/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" ca -config "$CONF" -batch -in CA/cert_crldp.csr -out CA/cert_crldp.cer \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" x509 -in CA/cert_crldp.cer -out tmp/cert_crldp.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nAttach intermediate certificate to code signing certificate\n" >> "makecerts.log"
cat tmp/intermediateCA_crldp.pem >> tmp/cert_crldp.pem 2>> "makecerts.log"
test_result $?
################################################################################
# Time Stamp Authority certificates
################################################################################
printf "\nGenerate Root CA TSA certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/TSACA.key \
2>> "makecerts.log" 1>&2
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_tsa_root.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/TSACA.key -out tmp/TSACA.pem \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nGenerate TSA certificate to revoke\n" >> "makecerts.log"
CONF="${script_path}/openssl_tsa_root.cnf"
"$OPENSSL" req -config "$CONF" -new -nodes -keyout tmp/TSA_revoked.key -out CA/TSA_revoked.csr \
-subj "/C=PL/O=osslsigncode/OU=TSA/CN=Revoked/emailAddress=osslsigncode@example.com" \
2>> "makecerts.log" 1>&2
test_result $?
CONF="${script_path}/openssl_tsa_root.cnf"
"$OPENSSL" ca -config "$CONF" -batch -in CA/TSA_revoked.csr -out CA/TSA_revoked.cer \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" x509 -in CA/TSA_revoked.cer -out tmp/TSA_revoked.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nRevoke above certificate\n" >> "makecerts.log"
"$OPENSSL" ca -config "$CONF" -revoke CA/TSA_revoked.cer \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nGenerate TSA CRL file\n" >> "makecerts.log"
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
script_path=$(pwd)
OPENSSL="$0"
export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_tsa_root.cnf"
"$OPENSSL" ca -config "$CONF" -gencrl -crldays 8766 -out tmp/TSACertCRL.pem \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nConvert TSA CRL file from PEM to DER (for CRL Distribution Points server to use)\n" >> "makecerts.log"
"$OPENSSL" crl -in tmp/TSACertCRL.pem -inform PEM -out tmp/TSACertCRL.der -outform DER \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nGenerate TSA certificate\n" >> "makecerts.log"
CONF="${script_path}/openssl_tsa.cnf"
"$OPENSSL" req -config "$CONF" -new -nodes -keyout tmp/TSA.key -out CA/TSA.csr \
2>> "makecerts.log" 1>&2
test_result $?
CONF="${script_path}/openssl_tsa_root.cnf"
"$OPENSSL" ca -config "$CONF" -batch -in CA/TSA.csr -out CA/TSA.cer \
2>> "makecerts.log" 1>&2
test_result $?
"$OPENSSL" x509 -in CA/TSA.cer -out tmp/TSA.pem \
2>> "makecerts.log" 1>&2
test_result $?
printf "\nSave the chain to be included in the TSA response\n" >> "makecerts.log"
cat tmp/TSA.pem tmp/TSACA.pem > tmp/tsa-chain.pem 2>> "makecerts.log"
################################################################################
# Copy new files
################################################################################
if test -s tmp/CACert.pem \
-a -s tmp/intermediateCA.pem -a -s tmp/intermediateCA_crldp.pem \
-a -s tmp/CACertCRL.pem -a -s tmp/CACertCRL.der \
-a -s tmp/TSACertCRL.pem -a -s tmp/TSACertCRL.der \
-a -s tmp/key.pem -a -s tmp/keyp.pem -a -s tmp/key.der -a -s tmp/key.pvk \
-a -s tmp/cert.pem -a -s tmp/cert.der -a -s tmp/cert.spc \
-a -s tmp/cert.p12 -a -s tmp/legacy.p12 -a -s tmp/cert_crldp.pem\
-a -s tmp/crosscert.pem -a -s tmp/expired.pem \
-a -s tmp/revoked.pem -a -s tmp/revoked_crldp.pem \
-a -s tmp/TSA_revoked.pem \
-a -s tmp/TSA.pem -a -s tmp/TSA.key -a -s tmp/tsa-chain.pem
then
mkdir -p "../certs"
cp tmp/* ../certs
printf "%s" "Keys & certificates successfully generated"
else
printf "%s" "Error logs ${result_path}/makecerts.log"
result=1
fi
################################################################################
# Remove the working directory
################################################################################
rm -rf "CA/"
rm -rf "tmp/"
exit "$result"
}
################################################################################
# Tests requirement and make certs
################################################################################
if test -n "$(command -v faketime)"
then
make_certs "$1"
result=$?
else
printf "%s" "faketime not found in \$PATH, please install faketime package"
result=1
fi
exit "$result"

View File

@ -1,73 +0,0 @@
# OpenSSL intermediate CA configuration file
[ default ]
name = intermediateCA
default_ca = CA_default
[ CA_default ]
# Directory and file locations
dir = .
certs = $dir/CA
crl_dir = $dir/CA
new_certs_dir = $dir/CA
database = $dir/CA/index.txt
serial = $dir/CA/serial
rand_serial = yes
private_key = $dir/CA/$name.key
certificate = $dir/tmp/$name.pem
crlnumber = $dir/CA/crlnumber
crl_extensions = crl_ext
default_md = sha256
preserve = no
policy = policy_loose
default_startdate = 180101000000Z
default_enddate = 241231000000Z
x509_extensions = v3_req
email_in_dn = yes
default_days = 2200
[ req ]
# Options for the `req` tool
encrypt_key = no
default_bits = 2048
default_md = sha256
string_mask = utf8only
distinguished_name = req_distinguished_name
x509_extensions = usr_extensions
[ crl_ext ]
# Extension for CRLs
authorityKeyIdentifier = keyid:always
[ usr_extensions ]
# Extension to add when the -x509 option is used
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid, issuer
extendedKeyUsage = codeSigning
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid, issuer
extendedKeyUsage = codeSigning
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address

View File

@ -1,79 +0,0 @@
# OpenSSL intermediate CA configuration file
[ default ]
name = intermediateCA
default_ca = CA_default
crl_url = http://127.0.0.1:19254/$name
[ CA_default ]
# Directory and file locations
dir = .
certs = $dir/CA
crl_dir = $dir/CA
new_certs_dir = $dir/CA
database = $dir/CA/index.txt
serial = $dir/CA/serial
rand_serial = yes
private_key = $dir/CA/$name\_crldp.key
certificate = $dir/tmp/$name\_crldp.pem
crlnumber = $dir/CA/crlnumber
crl_extensions = crl_ext
default_md = sha256
preserve = no
policy = policy_loose
default_startdate = 180101000000Z
default_enddate = 241231000000Z
x509_extensions = v3_req
email_in_dn = yes
default_days = 2200
[ req ]
# Options for the `req` tool
encrypt_key = no
default_bits = 2048
default_md = sha256
string_mask = utf8only
distinguished_name = req_distinguished_name
x509_extensions = usr_extensions
[ crl_ext ]
# Extension for CRLs
authorityKeyIdentifier = keyid:always
[ usr_extensions ]
# Extension to add when the -x509 option is used
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid, issuer
extendedKeyUsage = codeSigning
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid, issuer
extendedKeyUsage = codeSigning
crlDistributionPoints = @crl_info
[ crl_info ]
# X509v3 CRL Distribution Points extension
URI.0 = $crl_url
[ policy_loose ]
# Allow the intermediate CA to sign a more diverse range of certificates.
# See the POLICY FORMAT section of the `ca` man page.
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address

View File

@ -1,65 +0,0 @@
# OpenSSL root CA configuration file
[ ca ]
default_ca = CA_default
[ CA_default ]
# Directory and file locations.
dir = .
certs = $dir/CA
crl_dir = $dir/CA
new_certs_dir = $dir/CA
database = $dir/CA/index.txt
serial = $dir/CA/serial
rand_serial = yes
private_key = $dir/CA/CA.key
certificate = $dir/tmp/CACert.pem
crl_extensions = crl_ext
default_md = sha256
preserve = no
policy = policy_match
default_startdate = 180101000000Z
default_enddate = 260101000000Z
x509_extensions = v3_intermediate_ca
email_in_dn = yes
default_days = 3000
unique_subject = no
[ req ]
# Options for the `req` tool
encrypt_key = no
default_bits = 2048
default_md = sha256
string_mask = utf8only
x509_extensions = ca_extensions
distinguished_name = req_distinguished_name
[ ca_extensions ]
# Extension to add when the -x509 option is used
basicConstraints = critical, CA:true
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions for a typical intermediate CA (`man x509v3_config`)
basicConstraints = critical, CA:true, pathlen:0
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ policy_match ]
countryName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit Name
commonName = Common Name
emailAddress = Email Address

View File

@ -44,3 +44,4 @@ ordering = yes
tsa_name = yes tsa_name = yes
ess_cert_id_chain = yes ess_cert_id_chain = yes
ess_cert_id_alg = sha256 ess_cert_id_alg = sha256
crypto_device = builtin

View File

@ -1,83 +0,0 @@
# OpenSSL Root Timestamp Authority configuration file
[ default ]
name = TSACA
domain_suffix = timestampauthority
crl_url = http://127.0.0.1:19254/$name
name_opt = utf8, esc_ctrl, multiline, lname, align
default_ca = CA_default
[ CA_default ]
dir = .
certs = $dir/CA
crl_dir = $dir/CA
new_certs_dir = $dir/CA
database = $dir/CA/index.txt
serial = $dir/CA/serial
crlnumber = $dir/CA/crlnumber
crl_extensions = crl_ext
rand_serial = yes
private_key = $dir/CA/$name.key
certificate = $dir/tmp/$name.pem
default_md = sha256
default_days = 3650
default_crl_days = 365
policy = policy_match
default_startdate = 20180101000000Z
default_enddate = 20280101000000Z
unique_subject = no
email_in_dn = no
x509_extensions = tsa_extensions
[ policy_match ]
countryName = match
stateOrProvinceName = optional
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ tsa_extensions ]
basicConstraints = critical, CA:false
extendedKeyUsage = critical, timeStamping
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always
crlDistributionPoints = @crl_info
nameConstraints = @name_constraints
[ crl_info ]
# X509v3 CRL Distribution Points extension
URI.0 = $crl_url
[ crl_ext ]
# Extension for CRLs
authorityKeyIdentifier = keyid:always
[ name_constraints ]
permitted;DNS.0=test.com
permitted;DNS.1=test.org
excluded;IP.0=0.0.0.0/0.0.0.0
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0
[ req ]
# Options for the `req` tool
default_bits = 2048
encrypt_key = yes
default_md = sha256
utf8 = yes
string_mask = utf8only
prompt = no
distinguished_name = ca_distinguished_name
x509_extensions = ca_extensions
[ ca_distinguished_name ]
countryName = "PL"
organizationName = "osslsigncode"
organizationalUnitName = "Timestamp Authority Root CA"
commonName = "TSA Root CA"
[ ca_extensions ]
# Extension to add when the -x509 option is used
basicConstraints = critical, CA:true
subjectKeyIdentifier = hash
keyUsage = critical, keyCertSign, cRLSign

47
tests/exec.py Normal file
View File

@ -0,0 +1,47 @@
#!/usr/bin/python3
"""Implementation of a single ctest script."""
import sys
from subprocess import Popen, PIPE
def parse(value):
"""Read parameter from file."""
prefix = 'FILE '
if value.startswith(prefix):
with open(value[len(prefix):], mode="r", encoding="utf-8") as file:
return file.read().strip()
return value
def main() -> None:
"""Run osslsigncode with its options."""
if len(sys.argv) > 1:
try:
params = map(parse, sys.argv[1:])
proc = Popen(params, stdout=PIPE, stderr=PIPE, text=True)
stdout, stderr = proc.communicate()
print(stdout, file=sys.stderr)
if stderr:
print("Error:\n" + "-" * 58 + "\n" + stderr, file=sys.stderr)
sys.exit(proc.returncode)
except Exception as err: # pylint: disable=broad-except
# all exceptions are critical
print(err, file=sys.stderr)
else:
print("Usage:\n\t{} COMMAND [ARG]...'".format(sys.argv[0]), file=sys.stderr)
sys.exit(1)
if __name__ == "__main__":
main()
# pylint: disable=pointless-string-statement
"""Local Variables:
c-basic-offset: 4
tab-width: 4
indent-tabs-mode: nil
End:
vim: set ts=4 expandtab:
"""

0
tests/files/unsigned.256appx Executable file → Normal file
View File

0
tests/files/unsigned.512appx Executable file → Normal file
View File

Binary file not shown.

BIN
tests/files/unsigned.mof Normal file

Binary file not shown.

2
tests/files/unsigned.ps1 Normal file
View File

@ -0,0 +1,2 @@
cls
Write-Host "żółć"

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<PSConsoleFile ConsoleSchemaVersion="1.0">
<PSVersion>5.1.19041.3930</PSVersion>
<PSSnapIns />
</PSConsoleFile>

581
tests/make_certificates.py Normal file
View File

@ -0,0 +1,581 @@
#!/usr/bin/python3
"""Make test certificates"""
import os
import datetime
import cryptography
# Explicit imports of cryptography submodules
import cryptography.x509
import cryptography.x509.oid
import cryptography.hazmat.primitives.hashes
import cryptography.hazmat.primitives.asymmetric.rsa
import cryptography.hazmat.primitives.serialization
import cryptography.hazmat.primitives.serialization.pkcs12
# Import classes and functions from the cryptography module
from cryptography.x509 import (
AuthorityKeyIdentifier,
BasicConstraints,
Certificate,
CertificateBuilder,
CertificateRevocationListBuilder,
CRLDistributionPoints,
CRLNumber,
CRLReason,
DistributionPoint,
DNSName,
ExtendedKeyUsage,
KeyUsage,
Name,
NameAttribute,
NameConstraints,
random_serial_number,
RevokedCertificateBuilder,
ReasonFlags,
SubjectKeyIdentifier,
UniformResourceIdentifier
)
from cryptography.x509.oid import (
ExtendedKeyUsageOID,
NameOID
)
from cryptography.hazmat.primitives.hashes import SHA256
from cryptography.hazmat.primitives.asymmetric.rsa import (
generate_private_key,
RSAPrivateKey
)
from cryptography.hazmat.primitives.serialization import (
BestAvailableEncryption,
Encoding,
NoEncryption,
PrivateFormat
)
from cryptography.hazmat.primitives.serialization.pkcs12 import serialize_key_and_certificates
try:
if cryptography.__version__ >= '38.0.0':
from cryptography.hazmat.primitives.serialization.pkcs12 import PBES
except ImportError:
pass
RESULT_PATH = os.getcwd()
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
date_20170101 = datetime.datetime(2017, 1, 1)
date_20180101 = datetime.datetime(2018, 1, 1)
date_20190101 = datetime.datetime(2019, 1, 1)
PASSWORD='passme'
class X509Extensions():
"""Base class for X509 Extensions"""
def __init__(self, unit_name, cdp_port, cdp_name):
self.unit_name = unit_name
self.port = cdp_port
self.name = cdp_name
def create_x509_name(self, common_name) -> Name:
"""Return x509.Name"""
return Name(
[
NameAttribute(NameOID.COUNTRY_NAME, "PL"),
NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Mazovia Province"),
NameAttribute(NameOID.LOCALITY_NAME, "Warsaw"),
NameAttribute(NameOID.ORGANIZATION_NAME, "osslsigncode"),
NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, self.unit_name),
NameAttribute(NameOID.COMMON_NAME, common_name)
]
)
def create_x509_crldp(self) -> CRLDistributionPoints:
"""Return x509.CRLDistributionPoints"""
return CRLDistributionPoints(
[
DistributionPoint(
full_name=[UniformResourceIdentifier(
"http://127.0.0.1:" + str(self.port) + "/" + str(self.name))
],
relative_name=None,
reasons=None,
crl_issuer=None
)
]
)
def create_x509_name_constraints(self) -> NameConstraints:
"""Return x509.NameConstraints"""
return NameConstraints(
permitted_subtrees = [DNSName('test.com'), DNSName('test.org')],
excluded_subtrees = None
)
class IntermediateCACertificate(X509Extensions):
"""Base class for Intermediate CA certificate"""
def __init__(self, issuer_cert, issuer_key):
self.issuer_cert = issuer_cert
self.issuer_key = issuer_key
super().__init__("Certification Authority", 0, None)
def make_cert(self) -> (Certificate, RSAPrivateKey):
"""Generate intermediate CA certificate"""
key = generate_private_key(public_exponent=65537, key_size=2048)
key_public = key.public_key()
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
key_usage = KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False
)
cert = (
CertificateBuilder()
.subject_name(self.create_x509_name("Intermediate CA"))
.issuer_name(self.issuer_cert.subject)
.public_key(key_public)
.serial_number(random_serial_number())
.not_valid_before(date_20180101)
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
.add_extension(BasicConstraints(ca=True, path_length=0), critical=True)
.add_extension(SubjectKeyIdentifier.from_public_key(key_public), critical=False)
.add_extension(authority_key, critical=False)
.add_extension(key_usage, critical=True)
.sign(self.issuer_key, SHA256())
)
file_path=os.path.join(CERTS_PATH, "intermediateCA.pem")
with open(file_path, mode="wb") as file:
file.write(cert.public_bytes(encoding=Encoding.PEM))
return cert, key
class RootCACertificate(X509Extensions):
"""Base class for Root CA certificate"""
def __init__(self):
self.key_usage = KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False
)
super().__init__("Certification Authority", 0, None)
def make_cert(self) -> (Certificate, RSAPrivateKey):
"""Generate CA certificates"""
ca_root, root_key = self.make_ca_cert("Trusted Root CA", "CAroot.pem")
ca_cert, ca_key = self.make_ca_cert("Root CA", "CACert.pem")
self.make_cross_cert(ca_root, root_key, ca_cert, ca_key)
return ca_cert, ca_key
def make_ca_cert(self, common_name, file_name) -> None:
"""Generate self-signed root CA certificate"""
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
ca_public = ca_key.public_key()
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
name = self.create_x509_name(common_name)
ca_cert = (
CertificateBuilder()
.subject_name(name)
.issuer_name(name)
.public_key(ca_public)
.serial_number(random_serial_number())
.not_valid_before(date_20170101)
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
.add_extension(authority_key, critical=False)
.add_extension(self.key_usage, critical=True)
.sign(ca_key, SHA256())
)
file_path=os.path.join(CERTS_PATH, file_name)
with open(file_path, mode="wb") as file:
file.write(ca_cert.public_bytes(encoding=Encoding.PEM))
return ca_cert, ca_key
def make_cross_cert(self, ca_root, root_key, ca_cert, ca_key) -> None:
"""Generate cross-signed root CA certificate"""
ca_public = ca_key.public_key()
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
ca_root.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
ca_cross = (
CertificateBuilder()
.subject_name(ca_cert.subject)
.issuer_name(ca_root.subject)
.public_key(ca_public)
.serial_number(ca_cert.serial_number)
.not_valid_before(date_20180101)
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
.add_extension(authority_key, critical=False)
.add_extension(self.key_usage, critical=True)
.sign(root_key, SHA256())
)
file_path=os.path.join(CERTS_PATH, "CAcross.pem")
with open(file_path, mode="wb") as file:
file.write(ca_cross.public_bytes(encoding=Encoding.PEM))
def write_key(self, key, file_name) -> None:
"""Write a private RSA key"""
# Write password
file_path = os.path.join(CERTS_PATH, "password.txt")
with open(file_path, mode="w", encoding="utf-8") as file:
file.write("{}".format(PASSWORD))
# Write encrypted key in PEM format
file_path = os.path.join(CERTS_PATH, file_name + "p.pem")
with open(file_path, mode="wb") as file:
file.write(key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.PKCS8,
encryption_algorithm=BestAvailableEncryption(PASSWORD.encode())
)
)
# Write decrypted key in PEM format
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
with open(file_path, mode="wb") as file:
file.write(key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.PKCS8,
encryption_algorithm=NoEncryption()
)
)
# Write the key in DER format
file_path = os.path.join(CERTS_PATH, file_name + ".der")
with open(file_path, mode="wb") as file:
file.write(key.private_bytes(
encoding=Encoding.DER,
format=PrivateFormat.PKCS8,
encryption_algorithm=NoEncryption()
)
)
class TSARootCACertificate(X509Extensions):
"""Base class for TSA certificates"""
def __init__(self):
super().__init__("Timestamp Authority Root CA", 0, None)
def make_cert(self) -> (Certificate, RSAPrivateKey):
"""Generate a Time Stamp Authority certificate"""
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
ca_public = ca_key.public_key()
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
name = self.create_x509_name("TSA Root CA")
key_usage = KeyUsage(
digital_signature=False,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=True,
crl_sign=True,
encipher_only=False,
decipher_only=False
)
ca_cert = (
CertificateBuilder()
.subject_name(name)
.issuer_name(name)
.public_key(ca_public)
.serial_number(random_serial_number())
.not_valid_before(date_20170101)
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
.add_extension(authority_key, critical=False)
.add_extension(key_usage, critical=True)
.sign(ca_key, SHA256())
)
file_path=os.path.join(CERTS_PATH, "TSACA.pem")
with open(file_path, mode="wb") as file:
file.write(ca_cert.public_bytes(encoding=Encoding.PEM))
return ca_cert, ca_key
def write_key(self, key, file_name) -> None:
"""Write decrypted private RSA key into PEM format"""
file_path = os.path.join(CERTS_PATH, file_name + ".key")
with open(file_path, mode="wb") as file:
file.write(key.private_bytes(
encoding=Encoding.PEM,
format=PrivateFormat.PKCS8,
encryption_algorithm=NoEncryption()
)
)
class LeafCertificate(X509Extensions):
"""Base class for a leaf certificate"""
def __init__(self, issuer_cert, issuer_key, unit_name, common_name, cdp_port, cdp_name):
#pylint: disable=too-many-arguments
self.issuer_cert = issuer_cert
self.issuer_key = issuer_key
self.common_name = common_name
super().__init__(unit_name, cdp_port, cdp_name)
def make_cert(self, public_key, not_before, days) -> Certificate:
"""Generate a leaf certificate"""
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
extended_key_usage = ExtendedKeyUsage(
[ExtendedKeyUsageOID.CODE_SIGNING]
)
cert = (
CertificateBuilder()
.subject_name(self.create_x509_name(self.common_name))
.issuer_name(self.issuer_cert.subject)
.public_key(public_key)
.serial_number(random_serial_number())
.not_valid_before(not_before)
.not_valid_after(not_before + datetime.timedelta(days=days))
.add_extension(BasicConstraints(ca=False, path_length=None), critical=False)
.add_extension(SubjectKeyIdentifier.from_public_key(public_key), critical=False)
.add_extension(authority_key, critical=False)
.add_extension(extended_key_usage, critical=False)
.add_extension(self.create_x509_crldp(), critical=False)
.sign(self.issuer_key, SHA256())
)
# Write PEM file and attach intermediate certificate
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
with open(file_path, mode="wb") as file:
file.write(cert.public_bytes(encoding=Encoding.PEM))
file.write(self.issuer_cert.public_bytes(encoding=Encoding.PEM))
return cert
def revoke_cert(self, serial_number, file_name) -> None:
"""Revoke a certificate"""
revoked = (
RevokedCertificateBuilder()
.serial_number(serial_number)
.revocation_date(date_20190101)
.add_extension(CRLReason(ReasonFlags.superseded), critical=False)
.build()
)
# Generate CRL
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
crl = (
CertificateRevocationListBuilder()
.issuer_name(self.issuer_cert.subject)
.last_update(date_20190101)
.next_update(date_20190101 + datetime.timedelta(days=7300))
.add_extension(authority_key, critical=False)
.add_extension(CRLNumber(4097), critical=False)
.add_revoked_certificate(revoked)
.sign(self.issuer_key, SHA256())
)
# Write CRL file
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
with open(file_path, mode="wb") as file:
file.write(crl.public_bytes(encoding=Encoding.PEM))
file_path = os.path.join(CERTS_PATH, file_name + ".der")
with open(file_path, mode="wb") as file:
file.write(crl.public_bytes(encoding=Encoding.DER))
class LeafCACertificate(LeafCertificate):
"""Base class for a leaf certificate"""
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
super().__init__(issuer_cert, issuer_key, "CSP", common, cdp_port, "intermediateCA")
class LeafTSACertificate(LeafCertificate):
"""Base class for a TSA leaf certificate"""
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
self.issuer_cert = issuer_cert
self.issuer_key = issuer_key
self.common_name = common
super().__init__(issuer_cert, issuer_key, "Timestamp Root CA", common, cdp_port, "TSACA")
def make_cert(self, public_key, not_before, days) -> Certificate:
"""Generate a TSA leaf certificate"""
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
# The TSA signing certificate must have exactly one extended key usage
# assigned to it: timeStamping. The extended key usage must also be critical,
# otherwise the certificate is going to be refused.
extended_key_usage = ExtendedKeyUsage(
[ExtendedKeyUsageOID.TIME_STAMPING]
)
cert = (
CertificateBuilder()
.subject_name(self.create_x509_name(self.common_name))
.issuer_name(self.issuer_cert.subject)
.public_key(public_key)
.serial_number(random_serial_number())
.not_valid_before(not_before)
.not_valid_after(not_before + datetime.timedelta(days=days))
.add_extension(BasicConstraints(ca=False, path_length=None), critical=True)
.add_extension(SubjectKeyIdentifier.from_public_key(public_key), critical=False)
.add_extension(authority_key, critical=False)
.add_extension(extended_key_usage, critical=True)
.add_extension(self.create_x509_crldp(), critical=False)
.add_extension(self.create_x509_name_constraints(), critical=False)
.sign(self.issuer_key, SHA256())
)
# Write PEM file and attach intermediate certificate
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
with open(file_path, mode="wb") as file:
file.write(cert.public_bytes(encoding=Encoding.PEM))
file.write(self.issuer_cert.public_bytes(encoding=Encoding.PEM))
return cert
class CertificateMaker():
"""Base class for test certificates"""
def __init__(self, cdp_port, logs):
self.cdp_port = cdp_port
self.logs = logs
def make_certs(self) -> None:
"""Make test certificates"""
try:
self.make_ca_certs()
self.make_tsa_certs()
logs = os.path.join(CERTS_PATH, "./cert.log")
with open(logs, mode="w", encoding="utf-8") as file:
file.write("Test certificates generation succeeded")
except Exception as err: # pylint: disable=broad-except
with open(self.logs, mode="a", encoding="utf-8") as file:
file.write("Error: {}".format(err))
def make_ca_certs(self):
"""Make test certificates"""
# Generate root CA certificate
root = RootCACertificate()
ca_cert, ca_key = root.make_cert()
# Generate intermediate root CA certificate
intermediate = IntermediateCACertificate(ca_cert, ca_key)
issuer_cert, issuer_key = intermediate.make_cert()
# Generate private RSA key
private_key = generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
root.write_key(key=private_key, file_name="key")
# Generate expired certificate
expired = LeafCACertificate(issuer_cert, issuer_key, "expired", self.cdp_port)
expired.make_cert(public_key, date_20180101, 365)
# Generate revoked certificate
revoked = LeafCACertificate(issuer_cert, issuer_key, "revoked", self.cdp_port)
cert = revoked.make_cert(public_key, date_20180101, 5840)
revoked.revoke_cert(cert.serial_number, "CACertCRL")
# Generate code signing certificate
signer = LeafCACertificate(issuer_cert, issuer_key, "cert", self.cdp_port)
cert = signer.make_cert(public_key, date_20180101, 5840)
# Write a certificate and a key into PKCS#12 container
self.write_pkcs12_container(
cert=cert,
key=private_key,
issuer=issuer_cert
)
# Write DER file and attach intermediate certificate
file_path = os.path.join(CERTS_PATH, "cert.der")
with open(file_path, mode="wb") as file:
file.write(cert.public_bytes(encoding=Encoding.DER))
def make_tsa_certs(self):
"""Make test TSA certificates"""
# Time Stamp Authority certificate
root = TSARootCACertificate()
issuer_cert, issuer_key = root.make_cert()
# Generate private RSA key
private_key = generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()
root.write_key(key=private_key, file_name="TSA")
# Generate revoked TSA certificate
revoked = LeafTSACertificate(issuer_cert, issuer_key, "TSA_revoked", self.cdp_port)
cert = revoked.make_cert(public_key, date_20180101, 7300)
revoked.revoke_cert(cert.serial_number, "TSACertCRL")
# Generate TSA certificate
signer = LeafTSACertificate(issuer_cert, issuer_key, "TSA", self.cdp_port)
cert = signer.make_cert(public_key, date_20180101, 7300)
# Save the chain to be included in the TSA response
file_path = os.path.join(CERTS_PATH, "tsa-chain.pem")
with open(file_path, mode="wb") as file:
file.write(cert.public_bytes(encoding=Encoding.PEM))
file.write(issuer_cert.public_bytes(encoding=Encoding.PEM))
def write_pkcs12_container(self, cert, key, issuer) -> None:
"""Write a certificate and a key into a PKCS#12 container"""
# Set an encryption algorithm
if cryptography.__version__ >= "38.0.0":
# For OpenSSL legacy mode use the default algorithm for certificate
# and private key encryption: DES-EDE3-CBC (vel 3DES_CBC)
# pylint: disable=no-member
encryption = (
PrivateFormat.PKCS12.encryption_builder()
.key_cert_algorithm(PBES.PBESv1SHA1And3KeyTripleDESCBC)
.kdf_rounds(5000)
.build(PASSWORD.encode())
)
else:
encryption = BestAvailableEncryption(PASSWORD.encode())
# Generate PKCS#12 struct
pkcs12 = serialize_key_and_certificates(
name=b'certificate',
key=key,
cert=cert,
cas=(issuer,),
encryption_algorithm=encryption
)
# Write into a PKCS#12 container
file_path = os.path.join(CERTS_PATH, "cert.p12")
with open(file_path, mode="wb") as file:
file.write(pkcs12)
# pylint: disable=pointless-string-statement
"""Local Variables:
c-basic-offset: 4
tab-width: 4
indent-tabs-mode: nil
End:
vim: set ts=4 expandtab:
"""

View File

@ -1,3 +1,4 @@
#!/usr/bin/python3
"""Implementation of a HTTP server""" """Implementation of a HTTP server"""
import argparse import argparse
@ -6,7 +7,9 @@ import subprocess
import sys import sys
import threading import threading
from urllib.parse import urlparse from urllib.parse import urlparse
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer from http.server import SimpleHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
from make_certificates import CertificateMaker
RESULT_PATH = os.getcwd() RESULT_PATH = os.getcwd()
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/") FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
@ -15,11 +18,9 @@ CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/") LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq") REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr") RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
CACRL = os.path.join(CERTS_PATH, "./CACertCRL.der")
TSACRL = os.path.join(CERTS_PATH, "./TSACertCRL.der")
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf") OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
PORT_LOG = os.path.join(LOGS_PATH, "./port.log") SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
OPENSSL_TS = ["openssl", "ts", OPENSSL_TS = ["openssl", "ts",
"-reply", "-config", OPENSSL_CONF, "-reply", "-config", OPENSSL_CONF,
@ -28,6 +29,11 @@ OPENSSL_TS = ["openssl", "ts",
"-out", RESPONS] "-out", RESPONS]
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
"""This variant of HTTPServer creates a new thread for every connection"""
daemon_threads = True
class RequestHandler(SimpleHTTPRequestHandler): class RequestHandler(SimpleHTTPRequestHandler):
"""Handle the HTTP POST request that arrive at the server""" """Handle the HTTP POST request that arrive at the server"""
@ -41,18 +47,22 @@ class RequestHandler(SimpleHTTPRequestHandler):
try: try:
url = urlparse(self.path) url = urlparse(self.path)
self.send_response(200) self.send_response(200)
self.send_header("Content-type", "application/crl") self.send_header("Content-type", "application/pkix-crl")
self.end_headers() self.end_headers()
resp_data = b''
# Read the file and send the contents # Read the file and send the contents
if url.path == "/intermediateCA": if url.path == "/intermediateCA":
with open(CACRL, 'rb') as file: file_path = os.path.join(CERTS_PATH, "./CACertCRL.der")
with open(file_path, 'rb') as file:
resp_data = file.read() resp_data = file.read()
if url.path == "/TSACA": if url.path == "/TSACA":
with open(TSACRL, 'rb') as file: file_path = os.path.join(CERTS_PATH, "./TSACertCRL.der")
with open(file_path, 'rb') as file:
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP GET request error: {err}") print("HTTP GET request error: {}".format(err))
def do_POST(self): # pylint: disable=invalid-name def do_POST(self): # pylint: disable=invalid-name
""""Serves the POST request type""" """"Serves the POST request type"""
@ -60,8 +70,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
url = urlparse(self.path) url = urlparse(self.path)
self.send_response(200) self.send_response(200)
if url.path == "/kill_server": if url.path == "/kill_server":
self.log_message(f"Deleting file: {PORT_LOG}") self.log_message(f"Deleting file: {URL_LOG}")
os.remove(f"{PORT_LOG}") os.remove(f"{URL_LOG}")
self.send_header('Content-type', 'text/plain') self.send_header('Content-type', 'text/plain')
self.end_headers() self.end_headers()
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8')) self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
@ -71,17 +81,17 @@ class RequestHandler(SimpleHTTPRequestHandler):
post_data = self.rfile.read(content_length) post_data = self.rfile.read(content_length)
with open(REQUEST, mode="wb") as file: with open(REQUEST, mode="wb") as file:
file.write(post_data) file.write(post_data)
openssl = subprocess.run(OPENSSL_TS, openssl = subprocess.run(OPENSSL_TS, check=True, universal_newlines=True)
check=True, universal_newlines=True)
openssl.check_returncode() openssl.check_returncode()
self.send_header("Content-type", "application/timestamp-reply") self.send_header("Content-type", "application/timestamp-reply")
self.end_headers() self.end_headers()
resp_data = None resp_data = b''
with open(RESPONS, mode="rb") as file: with open(RESPONS, mode="rb") as file:
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP POST request error: {err}") print("HTTP POST request error: {}".format(err))
class HttpServerThread(): class HttpServerThread():
@ -93,17 +103,18 @@ class HttpServerThread():
self.server_thread = None self.server_thread = None
def start_server(self, port) -> (int): def start_server(self, port) -> (int):
"""Starting HTTP server on localhost and a random available port for binding""" """Starting HTTP server on 127.0.0.1 and a random available port for binding"""
self.server = ThreadingHTTPServer(('localhost', port), RequestHandler) self.server = ThreadingHTTPServer(('127.0.0.1', port), RequestHandler)
self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.start() self.server_thread.start()
hostname, port = self.server.server_address[:2] hostname, port = self.server.server_address[:2]
print(f"HTTP server started, URL http://{hostname}:{port}") print("HTTP server started, URL http://{}:{}".format(hostname, port))
return port return port
def main() -> None: def main() -> None:
"""Start HTTP server""" """Start HTTP server, make test certificates."""
ret = 0 ret = 0
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument( parser.add_argument(
@ -116,11 +127,16 @@ def main() -> None:
try: try:
server = HttpServerThread() server = HttpServerThread()
port = server.start_server(args.port) port = server.start_server(args.port)
with open(PORT_LOG, mode="w") as file: with open(URL_LOG, mode="w", encoding="utf-8") as file:
file.write("{}".format(port)) file.write("127.0.0.1:{}".format(port))
tests = CertificateMaker(port, SERVER_LOG)
tests.make_certs()
except OSError as err: except OSError as err:
print(f"OSError: {err}") print("OSError: {}".format(err))
ret = err.errno ret = err.errno
except Exception as err: # pylint: disable=broad-except
print("Error: {}".format(err))
ret = 1
finally: finally:
sys.exit(ret) sys.exit(ret)
@ -130,8 +146,11 @@ if __name__ == '__main__':
fpid = os.fork() fpid = os.fork()
if fpid > 0: if fpid > 0:
sys.exit(0) sys.exit(0)
with open(SERVER_LOG, mode='w', encoding='utf-8') as log:
os.dup2(log.fileno(), sys.stdout.fileno())
os.dup2(log.fileno(), sys.stderr.fileno())
except OSError as ferr: except OSError as ferr:
print(f"Fork #1 failed: {ferr.errno} {ferr.strerror}") print("Fork #1 failed: {} {}".format(ferr.errno, ferr.strerror))
sys.exit(1) sys.exit(1)
try: try:
@ -139,7 +158,7 @@ if __name__ == '__main__':
if fpid > 0: if fpid > 0:
sys.exit(0) sys.exit(0)
except OSError as ferr: except OSError as ferr:
print(f"Fork #2 failed: {ferr.errno} {ferr.strerror}") print("Fork #2 failed: {} {}".format(ferr.errno, ferr.strerror))
sys.exit(1) sys.exit(1)
# Start the daemon main loop # Start the daemon main loop

View File

@ -1,11 +1,14 @@
#!/usr/bin/python3
"""Windows: Implementation of a HTTP server""" """Windows: Implementation of a HTTP server"""
import argparse
import os import os
import subprocess import subprocess
import sys import sys
import threading import threading
from urllib.parse import urlparse from urllib.parse import urlparse
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
from make_certificates import CertificateMaker
RESULT_PATH = os.getcwd() RESULT_PATH = os.getcwd()
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/") FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
@ -14,11 +17,9 @@ CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/") LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq") REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr") RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
CACRL = os.path.join(CERTS_PATH, "./CACertCRL.der")
TSACRL = os.path.join(CERTS_PATH, "./TSACertCRL.der")
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf") OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log") SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
PORT_LOG = os.path.join(LOGS_PATH, "./port.log") URL_LOG = os.path.join(LOGS_PATH, "./url.log")
OPENSSL_TS = ["openssl", "ts", OPENSSL_TS = ["openssl", "ts",
@ -41,18 +42,22 @@ class RequestHandler(SimpleHTTPRequestHandler):
try: try:
url = urlparse(self.path) url = urlparse(self.path)
self.send_response(200) self.send_response(200)
self.send_header("Content-type", "application/crl") self.send_header("Content-type", "application/pkix-crl")
self.end_headers() self.end_headers()
resp_data = b''
# Read the file and send the contents # Read the file and send the contents
if url.path == "/intermediateCA": if url.path == "/intermediateCA":
with open(CACRL, 'rb') as file: file_path = os.path.join(CERTS_PATH, "./CACertCRL.der")
with open(file_path, 'rb') as file:
resp_data = file.read() resp_data = file.read()
if url.path == "/TSACA": if url.path == "/TSACA":
with open(TSACRL, 'rb') as file: file_path = os.path.join(CERTS_PATH, "./TSACertCRL.der")
with open(file_path, 'rb') as file:
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP GET request error: {err}") print("HTTP GET request error: {}".format(err))
def do_POST(self): # pylint: disable=invalid-name def do_POST(self): # pylint: disable=invalid-name
""""Serves the POST request type""" """"Serves the POST request type"""
@ -60,8 +65,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
url = urlparse(self.path) url = urlparse(self.path)
self.send_response(200) self.send_response(200)
if url.path == "/kill_server": if url.path == "/kill_server":
self.log_message(f"Deleting file: {PORT_LOG}") self.log_message(f"Deleting file: {URL_LOG}")
os.remove(f"{PORT_LOG}") os.remove(f"{URL_LOG}")
self.send_header('Content-type', 'text/plain') self.send_header('Content-type', 'text/plain')
self.end_headers() self.end_headers()
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8')) self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
@ -76,12 +81,12 @@ class RequestHandler(SimpleHTTPRequestHandler):
openssl.check_returncode() openssl.check_returncode()
self.send_header("Content-type", "application/timestamp-reply") self.send_header("Content-type", "application/timestamp-reply")
self.end_headers() self.end_headers()
resp_data = None resp_data = b''
with open(RESPONS, mode="rb") as file: with open(RESPONS, mode="rb") as file:
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP POST request error: {err}") print("HTTP POST request error: {}".format(err))
class HttpServerThread(): class HttpServerThread():
@ -92,28 +97,39 @@ class HttpServerThread():
self.server = None self.server = None
self.server_thread = None self.server_thread = None
def start_server(self) -> (int): def start_server(self, port) -> (int):
"""Starting HTTP server on localhost and a random available port for binding""" """Starting HTTP server on 127.0.0.1 and a random available port for binding"""
self.server = ThreadingHTTPServer(('localhost', 19254), RequestHandler) self.server = ThreadingHTTPServer(('127.0.0.1', port), RequestHandler)
self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.start() self.server_thread.start()
hostname, port = self.server.server_address[:2] hostname, port = self.server.server_address[:2]
print(f"HTTP server started, URL http://{hostname}:{port}") print("HTTP server started, URL http://{}:{}".format(hostname, port))
return port return port
def main() -> None: def main() -> None:
"""Start HTTP server""" """Start HTTP server"""
ret = 0 ret = 0
parser = argparse.ArgumentParser()
parser.add_argument(
"--port",
type=int,
default=0,
help="port number"
)
args = parser.parse_args()
try: try:
sys.stdout = open(SERVER_LOG, "w") sys.stdout = open(SERVER_LOG, "w")
sys.stderr = open(SERVER_LOG, "a") sys.stderr = open(SERVER_LOG, "a")
server = HttpServerThread() server = HttpServerThread()
port = server.start_server() port = server.start_server(args.port)
with open(PORT_LOG, mode="w") as file: with open(URL_LOG, mode="w") as file:
file.write("{}".format(port)) file.write("127.0.0.1:{}".format(port))
tests = CertificateMaker(port, SERVER_LOG)
tests.make_certs()
except OSError as err: except OSError as err:
print(f"OSError: {err}") print("OSError: {}".format(err))
ret = err.errno ret = err.errno
finally: finally:
sys.exit(ret) sys.exit(ret)

View File

@ -0,0 +1,57 @@
# https://learn.microsoft.com/en-us/windows/win32/seccrypto/makecat
# makecat -v CatalogDefinitionFileName.cdf
# Define information about the entire catalog file.
[CatalogHeader]
# Name of the catalog file, including its extension.
Name=unsigned.cat
# Directory where the created unsigned.cat file will be placed.
ResultDir=..\files
# This option is not supported. Default value 1 is used.
PublicVersion=0x0000001
# Catalog version.
# If the version is set to 2, the HashAlgorithms option must contain SHA256.
CatalogVersion=2
# Name of the hashing algorithm used.
HashAlgorithms=SHA256
# Specifies whether to hash the files listed in the <HASH> option in the [CatalogFiles] section
PageHashes=true
# Type of message encoding used.
# The default EncodingType is PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0x00010001
EncodingType=0x00010001
# Specify an attribute of the catalog file.
# Set 1.3.6.1.4.1.311.12.2.1 CAT_NAMEVALUE_OBJID
# CATATTR1={type}:{oid}:{value} (optional)
# The OSAttr attribute specifies the target Windows version
CATATTR1=0x11010001:OSAttr:2:6.0
# Define each member of the catalog file.
[CatalogFiles]
<HASH>PEfile=..\files\unsigned.exe
# 0x00010000 Attribute is represented in plaintext. No conversion will be done.
<HASH>PEfileATTR1=0x11010001:File:unsigned.exe
<HASH>MSIfile=..\files\unsigned.msi
# 0x00020000 Attribute is represented in base-64 encoding.
<HASH>MSIfileATTR1=0x11020001:File:dW5zaWduZWQubXNp
<HASH>CABfile=..\files\unsigned.ex_
<HASH>CABfileATTR1=0x11010001:File:unsigned.ex_
<HASH>PS1file=..\files\unsigned.ps1
<HASH>PS1fileATTR1=0x11010001:File:unsigned.ps1
<HASH>PSC1file=..\files\unsigned.psc1
<HASH>PSC1fileATTR1=0x11010001:File:unsigned.psc1
<HASH>MOFfile=..\files\unsigned.mof
<HASH>MOFfileATTR1=0x11010001:File:unsigned.mof

Binary file not shown.

108
tests/start_server.py Normal file
View File

@ -0,0 +1,108 @@
#!/usr/bin/python3
"""Wait for all tests certificate, compute leafhash"""
import argparse
import binascii
import hashlib
import os
import pathlib
import platform
import subprocess
import sys
import time
RESULT_PATH = os.getcwd()
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
if platform.system() == 'Windows':
DEFAULT_PYTHON = "C:/Program Files/Python/Python311/pythonw.exe"
DEFAULT_PROG = os.path.join(RESULT_PATH, "./Testing/server_http.pyw")
else:
DEFAULT_PYTHON = "/usr/bin/python3"
DEFAULT_PROG = os.path.join(RESULT_PATH, "./Testing/server_http.py")
def compute_sha256(file_name) -> str:
"""Compute a SHA256 hash of the leaf certificate (in DER form)"""
sha256_hash = hashlib.sha256()
file_path = os.path.join(CERTS_PATH, file_name)
with open(file_path, mode="rb") as file:
for bajt in iter(lambda: file.read(4096),b""):
sha256_hash.update(bajt)
return sha256_hash.hexdigest()
def clear_catalog(certs_path) -> None:
""""Clear a test certificates catalog."""
if os.path.exists(certs_path):
#Remove old test certificates
for root, _, files in os.walk(certs_path):
for file in files:
os.remove(os.path.join(root, file))
else:
os.mkdir(certs_path)
# Generate 16 random bytes and convert to hex
random_hex = binascii.b2a_hex(os.urandom(16)).decode()
serial = os.path.join(certs_path, "./tsa-serial")
with open(serial, mode="w", encoding="utf-8") as file:
file.write(random_hex)
def main() -> None:
"""Wait for all tests certificate, compute leafhash"""
parser = argparse.ArgumentParser()
parser.add_argument(
"--exe",
type=pathlib.Path,
default=DEFAULT_PYTHON,
help=f"the path to the python3 executable to use"
f"(default: {DEFAULT_PYTHON})",
)
parser.add_argument(
"--script",
type=pathlib.Path,
default=DEFAULT_PROG,
help=f"the path to the python script to run"
f"(default: {DEFAULT_PROG})",
)
args = parser.parse_args()
try:
clear_catalog(CERTS_PATH)
#pylint: disable=consider-using-with
subprocess.Popen([str(args.exe), str(args.script)])
cert_log = os.path.join(CERTS_PATH, "./cert.log")
while not (os.path.exists(cert_log) and os.path.getsize(cert_log) > 0):
time.sleep(1)
leafhash = compute_sha256("cert.der")
file_path = os.path.join(CERTS_PATH, "./leafhash.txt")
with open(file_path, mode="w", encoding="utf-8") as file:
file.write("SHA256:{}".format(leafhash))
except OSError as err:
with open(SERVER_LOG, mode="w", encoding="utf-8") as file:
file.write("OSError: {}".format(err))
sys.exit(1)
except Exception as err: # pylint: disable=broad-except
with open(SERVER_LOG, mode="w", encoding="utf-8") as file:
file.write("Error: {}".format(err))
sys.exit(1)
if __name__ == "__main__":
main()
# pylint: disable=pointless-string-statement
"""Local Variables:
c-basic-offset: 4
tab-width: 4
indent-tabs-mode: nil
End:
vim: set ts=4 expandtab:
"""

347
utf.c Normal file
View File

@ -0,0 +1,347 @@
// utf by pietro gagliardi (andlabs) — https://github.com/andlabs/utf/
// 10 november 2016
#include "utf.h"
// this code imitates Go's unicode/utf8 and unicode/utf16
// the biggest difference is that a rune is unsigned instead of signed (because Go guarantees what a right shift on a signed number will do, whereas C does not)
// it is also an imitation so we can license it under looser terms than the Go source
#define badrune 0xFFFD
// encoded must be at most 4 bytes
// TODO clean this code up somehow
size_t utf8EncodeRune(uint32_t rune, char *encoded)
{
uint8_t b, c, d, e;
size_t n;
// not in the valid range for Unicode
if (rune > 0x10FFFF)
rune = badrune;
// surrogate runes cannot be encoded
if (rune >= 0xD800 && rune < 0xE000)
rune = badrune;
if (rune < 0x80) { // ASCII bytes represent themselves
b = (uint8_t) (rune & 0xFF);
n = 1;
goto done;
}
if (rune < 0x800) { // two-byte encoding
c = (uint8_t) (rune & 0x3F);
c |= 0x80;
rune >>= 6;
b = (uint8_t) (rune & 0x1F);
b |= 0xC0;
n = 2;
goto done;
}
if (rune < 0x10000) { // three-byte encoding
d = (uint8_t) (rune & 0x3F);
d |= 0x80;
rune >>= 6;
c = (uint8_t) (rune & 0x3F);
c |= 0x80;
rune >>= 6;
b = (uint8_t) (rune & 0x0F);
b |= 0xE0;
n = 3;
goto done;
}
// otherwise use a four-byte encoding
e = (uint8_t) (rune & 0x3F);
e |= 0x80;
rune >>= 6;
d = (uint8_t) (rune & 0x3F);
d |= 0x80;
rune >>= 6;
c = (uint8_t) (rune & 0x3F);
c |= 0x80;
rune >>= 6;
b = (uint8_t) (rune & 0x07);
b |= 0xF0;
n = 4;
done:
encoded[0] = (char)b;
if (n > 1)
encoded[1] = (char)c;
if (n > 2)
encoded[2] = (char)d;
if (n > 3)
encoded[3] = (char)e;
return n;
}
const char *utf8DecodeRune(const char *s, size_t nElem, uint32_t *rune)
{
uint8_t b, c;
uint8_t lowestAllowed, highestAllowed;
size_t i, expected;
int bad;
b = (uint8_t) (*s);
if (b < 0x80) { // ASCII bytes represent themselves
*rune = b;
s++;
return s;
}
// 0xC0 and 0xC1 cover 2-byte overlong equivalents
// 0xF5 to 0xFD cover values > 0x10FFFF
// 0xFE and 0xFF were never defined (always illegal)
if (b < 0xC2 || b > 0xF4) { // invalid
*rune = badrune;
s++;
return s;
}
// this determines the range of allowed first continuation bytes
lowestAllowed = 0x80;
highestAllowed = 0xBF;
switch (b) {
case 0xE0:
// disallow 3-byte overlong equivalents
lowestAllowed = 0xA0;
break;
case 0xED:
// disallow surrogate characters
highestAllowed = 0x9F;
break;
case 0xF0:
// disallow 4-byte overlong equivalents
lowestAllowed = 0x90;
break;
case 0xF4:
// disallow values > 0x10FFFF
highestAllowed = 0x8F;
break;
}
// and this determines how many continuation bytes are expected
expected = 1;
if (b >= 0xE0)
expected++;
if (b >= 0xF0)
expected++;
if (nElem != 0) { // are there enough bytes?
nElem--;
if (nElem < expected) { // nope
*rune = badrune;
s++;
return s;
}
}
// ensure that everything is correct
// if not, **only** consume the initial byte
bad = 0;
for (i = 0; i < expected; i++) {
c = (uint8_t) (s[1 + i]);
if (c < lowestAllowed || c > highestAllowed) {
bad = 1;
break;
}
// the old lowestAllowed and highestAllowed is only for the first continuation byte
lowestAllowed = 0x80;
highestAllowed = 0xBF;
}
if (bad) {
*rune = badrune;
s++;
return s;
}
// now do the topmost bits
if (b < 0xE0)
*rune = b & 0x1F;
else if (b < 0xF0)
*rune = b & 0x0F;
else
*rune = b & 0x07;
s++; // we can finally move on
// now do the continuation bytes
for (; expected; expected--) {
c = (uint8_t) (*s);
s++;
c &= 0x3F; // strip continuation bits
*rune <<= 6;
*rune |= c;
}
return s;
}
// encoded must have at most 2 elements
size_t utf16EncodeRune(uint32_t rune, uint16_t *encoded)
{
uint16_t low, high;
// not in the valid range for Unicode
if (rune > 0x10FFFF)
rune = badrune;
// surrogate runes cannot be encoded
if (rune >= 0xD800 && rune < 0xE000)
rune = badrune;
if (rune < 0x10000) {
encoded[0] = (uint16_t) rune;
return 1;
}
rune -= 0x10000;
low = (uint16_t) (rune & 0x3FF);
rune >>= 10;
high = (uint16_t) (rune & 0x3FF);
encoded[0] = high | 0xD800;
encoded[1] = low | 0xDC00;
return 2;
}
// TODO see if this can be cleaned up somehow
const uint16_t *utf16DecodeRune(const uint16_t *s, size_t nElem, uint32_t *rune)
{
uint16_t high, low;
if (*s < 0xD800 || *s >= 0xE000) {
// self-representing character
*rune = *s;
s++;
return s;
}
if (*s >= 0xDC00) {
// out-of-order surrogates
*rune = badrune;
s++;
return s;
}
if (nElem == 1) { // not enough elements
*rune = badrune;
s++;
return s;
}
high = *s;
high &= 0x3FF;
if (s[1] < 0xDC00 || s[1] >= 0xE000) {
// bad surrogate pair
*rune = badrune;
s++;
return s;
}
s++;
low = *s;
s++;
low &= 0x3FF;
*rune = high;
*rune <<= 10;
*rune |= low;
*rune += 0x10000;
return s;
}
// TODO find a way to reduce the code in all of these somehow
// TODO find a way to remove u as well
size_t utf8RuneCount(const char *s, size_t nElem)
{
size_t len;
uint32_t rune;
if (nElem != 0) {
const char *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = utf8DecodeRune(t, nElem, &rune);
len++;
nElem -= (size_t)(u - t);
t = u;
}
return len;
}
len = 0;
while (*s) {
s = utf8DecodeRune(s, nElem, &rune);
len++;
}
return len;
}
size_t utf8UTF16Count(const char *s, size_t nElem)
{
size_t len;
uint32_t rune;
uint16_t encoded[2];
if (nElem != 0) {
const char *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = utf8DecodeRune(t, nElem, &rune);
len += utf16EncodeRune(rune, encoded);
nElem -= (size_t)(u - t);
t = u;
}
return len;
}
len = 0;
while (*s) {
s = utf8DecodeRune(s, nElem, &rune);
len += utf16EncodeRune(rune, encoded);
}
return len;
}
size_t utf16RuneCount(const uint16_t *s, size_t nElem)
{
size_t len;
uint32_t rune;
if (nElem != 0) {
const uint16_t *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = utf16DecodeRune(t, nElem, &rune);
len++;
nElem -= (size_t)(u - t);
t = u;
}
return len;
}
len = 0;
while (*s) {
s = utf16DecodeRune(s, nElem, &rune);
len++;
}
return len;
}
size_t utf16UTF8Count(const uint16_t *s, size_t nElem)
{
size_t len;
uint32_t rune;
char encoded[4];
if (nElem != 0) {
const uint16_t *t, *u;
len = 0;
t = s;
while (nElem != 0) {
u = utf16DecodeRune(t, nElem, &rune);
len += utf8EncodeRune(rune, encoded);
nElem -= (size_t)(u - t);
t = u;
}
return len;
}
len = 0;
while (*s) {
s = utf16DecodeRune(s, nElem, &rune);
len += utf8EncodeRune(rune, encoded);
}
return len;
}

61
utf.h Normal file
View File

@ -0,0 +1,61 @@
// utf by pietro gagliardi (andlabs) — https://github.com/andlabs/utf/
// 10 november 2016
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
// if nElem == 0, assume the buffer has no upper limit and is '\0' terminated
// otherwise, assume buffer is NOT '\0' terminated but is bounded by nElem *elements*
extern size_t utf8EncodeRune(uint32_t rune, char *encoded);
extern const char *utf8DecodeRune(const char *s, size_t nElem, uint32_t *rune);
extern size_t utf16EncodeRune(uint32_t rune, uint16_t *encoded);
extern const uint16_t *utf16DecodeRune(const uint16_t *s, size_t nElem, uint32_t *rune);
extern size_t utf8RuneCount(const char *s, size_t nElem);
extern size_t utf8UTF16Count(const char *s, size_t nElem);
extern size_t utf16RuneCount(const uint16_t *s, size_t nElem);
extern size_t utf16UTF8Count(const uint16_t *s, size_t nElem);
#ifdef __cplusplus
}
// Provide overloads on Windows for using these functions with wchar_t and WCHAR when wchar_t is a keyword in C++ mode (the default).
// Otherwise, you'd need to cast to pass a wchar_t pointer, WCHAR pointer, or equivalent to these functions.
// We use __wchar_t to be independent of the setting; see https://blogs.msdn.microsoft.com/oldnewthing/20161201-00/?p=94836 (ironically posted one day after I initially wrote this code!).
// TODO check this on MinGW-w64
// TODO check this under /Wall
// TODO C-style casts enough? or will that fail in /Wall?
// TODO same for UniChar/unichar on Mac? if both are unsigned then we have nothing to worry about
#if defined(_MSC_VER)
inline size_t utf16EncodeRune(uint32_t rune, __wchar_t *encoded)
{
return utf16EncodeRune(rune, reinterpret_cast<uint16_t *>(encoded));
}
inline const __wchar_t *utf16DecodeRune(const __wchar_t *s, size_t nElem, uint32_t *rune)
{
const uint16_t *ret;
ret = utf16DecodeRune(reinterpret_cast<const uint16_t *>(s), nElem, rune);
return reinterpret_cast<const __wchar_t *>(ret);
}
inline size_t utf16RuneCount(const __wchar_t *s, size_t nElem)
{
return utf16RuneCount(reinterpret_cast<const uint16_t *>(s), nElem);
}
inline size_t utf16UTF8Count(const __wchar_t *s, size_t nElem)
{
return utf16UTF8Count(reinterpret_cast<const uint16_t *>(s), nElem);
}
#endif
#endif

View File

@ -3,10 +3,7 @@
"version-string": "2.4", "version-string": "2.4",
"dependencies": [ "dependencies": [
"openssl", "openssl",
"curl", "zlib"
{ ],
"name": "python3", "builtin-baseline": "9edb1b8e590cc086563301d735cae4b6e732d2d2"
"platform": "!(windows & static) & !osx"
}
]
} }