81 Commits

Author SHA1 Message Date
Michał Trojnara fac8164622 Release 2.12
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2026-02-02 17:53:25 +01:00
Michał Trojnara cbee1e723c Fixed buffer overflow while extracting msg digest
Reported and fixed by Antoni Klajn, Opera
2026-02-02 17:37:45 +01:00
Michał Trojnara f90327df09 Initial 2.12-dev commit 2026-01-21 00:08:58 +01:00
Michał Trojnara f3a590be69 Release 2.11
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2026-01-20 23:53:33 +01:00
Michał Trojnara 6631a5f10b Update trusted certificate list 2026-01-20 23:21:33 +01:00
Michał Trojnara 9924f0c085 Minor style improvements
- Reorder checks by corresponding RFC 5280 section numbers.
- Simplify comments.
2026-01-20 23:21:33 +01:00
olszomal 7d85ac5f04 Add GitHub issue and PR templates 2026-01-09 14:41:02 +01:00
olszomal feebbcd4d9 Print current CRL during certificate verification 2026-01-07 13:36:43 +01:00
olszomal d787541107 tests: add digitalSignature keyUsage to leaf certificate 2025-12-31 11:38:21 +01:00
olszomal 6390ae2746 Add keyUsage digitalSignature validation for signer certificate 2025-12-31 11:38:21 +01:00
Michał Trojnara a472d7fbff Comment returned CRL Content-Type 2025-12-22 19:26:21 +01:00
Chris Thibodeaux 27172a07ca Patch CRL fetch failure from expected file type
`application/octet-stream` response types caused CRL/TSA-CRL fetch failures
2025-12-22 19:22:01 +01:00
olszomal d77ddb9443 Disable keep-alive and remove the shutdown workaround.
Some RFC 3161 TSA servers (e.g. time.certum.pl) advertise
"Connection: close" but delay closing the connection,
when keep-alive was requested. The client waited for EOF and
attempted to work around this by explicitly shutting down the socket.
2025-12-19 15:11:12 +01:00
olszomal 988f72249b Simplify ASLR/PIE flags check for macOS 2025-12-16 06:42:01 +01:00
olszomal c23f92ca68 Improve PKCS#11 and CNG usage instructions in README 2025-09-22 11:16:29 +02:00
olszomal 842bd94aaf Remove duplicate certs from sorted X509 chain 2025-09-19 17:02:21 +02:00
olszomal 1d72c3da8c Improve key/cert loading logic and standardize usage file argument names 2025-09-19 17:02:21 +02:00
olszomal d792e8d0db Use bio_new_file() wrapper instead of BIO_new_file() for consistent file handling 2025-09-19 17:01:02 +02:00
olszomal bbdfc1d98a Avoid undefined behavior with BIO_get_fp by replacing BIO_new_file with fopen + BIO_new_fp 2025-09-19 17:01:02 +02:00
olszomal 5ac11e9f58 Fix -Wsign-conversion warning in x509_name_to_utf8() 2025-07-01 12:21:44 +02:00
Michał Trojnara 55541c6ace Initial 2.11-dev commit 2025-06-23 21:42:26 +02:00
Michał Trojnara 8329a14f8b Release 2.10
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2025-06-23 21:36:13 +02:00
Michał Trojnara 343b0af1fe Put globs in quotes 2025-06-23 21:21:34 +02:00
Michał Trojnara d440f32780 Codespell Action 2025-06-23 21:13:47 +02:00
Michał Trojnara fb082942d2 Descriptive Action name 2025-06-23 21:05:51 +02:00
Michał Trojnara 025e808c01 docs: fix typos in README 2025-06-20 16:26:18 +02:00
Michał Trojnara 23b6d7782c docs: fix typo in appx comments 2025-06-20 16:14:25 +02:00
Michał Trojnara 4c3a1e887c docs: fix typos in README 2025-06-20 16:04:36 +02:00
Michał Trojnara 97ee163e31 Document script file support 2025-06-20 14:06:05 +02:00
Michał Trojnara dfc3e46a77 Typos 2025-06-20 12:28:43 +02:00
Michał Trojnara ff9a6d3593 Check for invalid OID in is_content_type 2025-06-20 10:32:30 +02:00
Michał Trojnara e81b08e02d Fix a comment 2025-06-20 09:58:45 +02:00
Michał Trojnara 0c85d54800 Handle missing certificate names 2025-06-19 17:56:54 +02:00
Michał Trojnara 772bc22c94 Handle null return from curl_easy_init 2025-06-19 14:32:24 +02:00
Michał Trojnara d65a2b5286 Fix various typos 2025-06-19 14:18:26 +02:00
Michał Trojnara a3fcf41e1a Check memory allocation 2025-06-19 12:00:29 +02:00
fanquake e00caac3db cmake: drop USE_WIN32 define
This was added in #423, but it's only use was then removed in #435.
2025-06-18 18:46:28 +02:00
olszomal dd9b81281f Support loading OpenSSL 3.0+ providers without -pkcs11module option (e.g., CNG) 2025-06-05 17:13:10 +02:00
olszomal 6b56aef073 Add tests for handling JavaScript files 2025-06-05 14:41:36 +02:00
Michał Trojnara 52bfff5756 Avoid variable reuse 2025-06-04 18:42:41 +02:00
Michał Trojnara 4d52e9cc4b JavaScript format fix. 2025-06-04 18:38:28 +02:00
Michał Trojnara 3292b02650 JavaScript support
Resolves #437
2025-06-04 10:04:17 +02:00
Michał Trojnara 50c23daa4c Code simplification
No functional change intended.
2025-06-03 08:20:52 +02:00
Michał Trojnara 9b7dae4572 Support loading arbitrary engines via ENGINE_by_id()
Use ENGINE_by_id() for any engine name that doesn't contain a dot,
assuming it's an engine ID. If the name includes a dot (e.g., a file
extension), treat it as a path to a dynamic engine module.

See #436 for discussion.
2025-06-02 20:32:26 +02:00
Michał Trojnara 62438908cb Skip the "lib" prefix when guessing engine ID
Fix #436
2025-05-30 16:59:25 +02:00
olszomal 829e770250 Use _WIN32 instead of USE_WIN32 for MinGW compatibility 2025-05-27 10:17:03 +02:00
olszomal a6c7c25dae Update NEWS 2025-05-14 11:29:13 +02:00
olszomal 10ca3a06ea Suppress compiler warnings 2025-05-06 10:42:53 +02:00
olszomal 9ea7e85468 Fix engine-less builds 2025-05-06 10:42:53 +02:00
olszomal 68e8845ef1 Improve PKCS#7 verification with OpenSSL 3.5
Enhanced verification logic for PKCS#7 signedData structures by introducing a dedicated `verify_pkcs7_data()` function. This update addresses compatibility with older OpenSSL versions (< 3.0.5) and ensures correct handling of detached signed content using a BIO buffer.
The change enables support for PKCS#7 inner content (RFC 2315, section 7), as per OpenSSL PR#22575.
Refactored timestamp and authenticode verification functions to reduce duplication and properly manage X509_STORE and X509_CRL structures.
2025-05-01 11:21:29 +02:00
olszomal 475ea95ba3 Fix control flow and braces for engine and provider support 2025-05-01 11:21:29 +02:00
Maxim Bagryantsev d352dcc1a5 Do not try to load engine twice 2025-04-18 10:46:20 +02:00
olszomal 7734382436 Remove Ubuntu 20.04 from CI as it's no longer supported 2025-04-16 11:48:05 +02:00
Jānis Erdmanis d425d8bf25 fix capitalization ws2_32.lib
Windows and MacOS are both case-insensitive, and hence the issue of wrong capitalisation may not have surfaced. 

I am forming a recipe for cross-compilation for the Julia BinarBuilder environment, which uses Linux x86_64 as the host system. However, as it uses a sensitive filesystem, I hit a linking error that could only be fixed by changing the capitalization of `Ws2_32.lib` to lowercase. 

More on that can be found in the pull request:
https://github.com/JuliaPackaging/Yggdrasil/pull/10950
2025-04-16 11:47:49 +02:00
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 4dd836bab1 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
38 changed files with 3191 additions and 1434 deletions
+8
View File
@@ -0,0 +1,8 @@
<!--
Please use one of the available issue templates.
Bug reports without required information may be closed.
-->
If you are reporting a bug or crash, please use the appropriate issue template.
For questions or support, use please use [Discussions](<https://github.com/mtrojnar/osslsigncode/discussions>).
+74
View File
@@ -0,0 +1,74 @@
---
name: Crash report
about: Report a segmentation fault or other crash
labels: crash
---
<!--
Thank you for your crash report.
Note: Please search to see if an issue already exists for the bug you encountered.
-->
### Segmentation Fault / Crash Details
<!--
Provide exact, reproducible steps.
Include the complete command, exactly as executed.
-->
- Signal / exit code: <!-- SIGSEGV, SIGABRT -->
- Reproducibility: <!-- always / sometimes / once -->
- Affected command or operation: <!-- e.g. `osslsigncode sign`, `osslsigncode verify` -->
- First observed version:
- Last known working version (if any):
#### Backtrace
<!--
Provide a backtrace from gdb or lldb.
Build with debug symbols if possible. Use `bt full` if possible.
Crash reports without a backtrace may be closed without investigation.
-->
- `(gdb) bt`
#### Memory / Sanitizers
<!--
Attach relevant output if available.
-->
- [ ] Valgrind
- [ ] ASan / UBSan
- [ ] Other tools
#### Crash Context
<!--
Anything that may be relevant:
- OpenSSL provider / engine in use
- PKCS#11 modules
- Custom OpenSSL configuration
- Threading or concurrency
-->
### Environment
- Operating system and version (e.g. Ubuntu 24.04):
- Architecture (x86_64, arm64, etc.):
### Versions
<!--
Please verify that the issue is reproducible with the current upstream master.
-->
- osslsigncode built from:
- [ ] upstream master
- [ ] upstream release (tag):
- [ ] distribution package (name and version):
- `openssl version -a`
- `osslsigncode --version`
### Configuration / Settings
<!--
Anything that could affect signing or verification:
- Custom OpenSSL configuration
- Engine / provider settings
- Environment variables (OPENSSL_CONF, etc.)
-->
### Anything else
<!--
Links, references, related issues, workarounds or additional observations.
-->
@@ -0,0 +1,26 @@
---
name: Documentation
about: Report an error in (or missing) documentation
labels: documentation
---
<!--
Thank you for taking the time to report a documentation issue.
-->
### Documentation Location
<!--
Where is the problem located?
Provide a link, file path, or section name.
-->
### Issue Description
<!--
Describe what is wrong or missing.
-->
### Suggested Improvement (optional)
<!--
If you know how it should be fixed, describe it here.
Proposed wording or examples are especially helpful.
-->
@@ -0,0 +1,30 @@
---
name: Feature request
about: Suggest a new feature or improvement
labels: feature
---
<!--
Thank you for your feature request.
Please describe the use case and motivation as clearly as possible.
-->
### Use Case / Motivation
<!--
What problem are you trying to solve?
Why is this feature needed?
-->
### Proposed Change
<!--
Describe the feature or improvement you are proposing.
High-level description is sufficient.
-->
### Additional Notes (optional)
<!--
Anything else that may help:
- examples
- references
- related issues
-->
+17
View File
@@ -0,0 +1,17 @@
---
name: Questions / Support
about: Please use Q&A in Discussions instead
labels: question
---
### Questions and Support
Please do **not** use GitHub issues for general questions or support requests.
For:
- usage questions
- "how do I..." questions
please use [Q&A category in Discussions](<https://github.com/mtrojnar/osslsigncode/discussions/new?category=q-a>)
Bug reports and crashes should be reported using the appropriate issue templates.
+77
View File
@@ -0,0 +1,77 @@
---
name: Other bug report
about: Report a bug
labels: bug
---
<!--
Thank you for your bug report.
Note: Please search to see if an issue already exists for the bug you encountered.
-->
### Current Behavior
<!--
A concise description of what is happening.
Include error messages or incorrect results.
-->
### Expected Behavior
<!--
A concise description of what you expected to happen instead.
-->
### Steps To Reproduce & Observed Output
<!--
Provide exact, reproducible steps together with full stdout/stderr for each.
-->
1. Signing with osslsigncode
<!--
Full `osslsigncode sign` command and complete stdout/stderr output.
-->
2. Verification with osslsigncode
<!--
Full `osslsigncode verify` command and complete stdout/stderr output.
-->
3. Signing / verification with Windows signtool (if applicable)
<!--
Full signtool command (`signtool verify /pa /v`) and complete stdout/stderr output.
-->
### Environment
- Operating system and version (e.g. Ubuntu 24.04):
- Architecture (x86_64, arm64, etc.):
### Versions
<!--
Please verify that the issue is reproducible with the current upstream master.
-->
- osslsigncode built from:
- [ ] upstream master
- [ ] upstream release (tag):
- [ ] distribution package (name and version):
- `openssl version -a`
- `osslsigncode --version`
### Files
<!--
Attach files if possible, or mention that you will share them privately.
-->
- [ ] unsigned file
- [ ] file signed with osslsigncode
- [ ] file signed with signtool or the other tool (for comparison)
- [ ] certificate chain used for verification (PEM format)
### Configuration / Settings
<!--
Anything that could affect signing or verification:
- Custom OpenSSL configuration
- Engine / provider settings
- Environment variables (OPENSSL_CONF, etc.)
-->
### Anything else
<!--
Links, references, related issues, workarounds or additional observations.
-->
+65
View File
@@ -0,0 +1,65 @@
<!--
Thank you for your pull request.
Provide a concise summary of the changes in the PR title.
-->
### Pull Request Type
<!--
Limit this PR to a single type. If necessary, split changes into multiple PRs.
-->
- [ ] Bug fix
- [ ] New feature
- [ ] Code style / formatting / renaming
- [ ] Refactoring (no functional or API changes)
- [ ] Build / CI related changes
- [ ] Documentation
- [ ] Other (please describe):
### Related Issue
<!--
If this fixes a GitHub issue, make sure to have a line saying 'Fixes #XXXX' (without quotes) in the commit message.
-->
Issue number: N/A
### Current Behavior
<!--
Describe the current behavior or limitation this PR addresses.
Include error messages or crash symptoms if relevant.
-->
### New Behavior
<!--
Describe the new or changed behavior introduced by this PR.
-->
### Scope of Changes
<!--
Briefly describe what was changed and why.
Focus on relevant parts only.
-->
### Testing
<!--
Describe how the changes were tested.
Include commands, environments, or platforms if relevant.
-->
- [ ] Existing tests
- [ ] New tests added
- [ ] Manual testing
### Additional Notes
<!--
Any additional information relevant for reviewers:
- design decisions
- backward compatibility
- known limitations
-->
## License Declaration
<!--
All contributions to this project are licensed under the project's license.
By submitting this pull request, you confirm that you have the right to submit
the code and agree to license it accordingly.
-->
- [ ] I hereby agree to license my contribution under the project's license.
+75 -45
View File
@@ -1,4 +1,4 @@
name: CI
name: Continuous Integration
on:
push:
@@ -7,7 +7,7 @@ on:
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
version: osslsigncode-2.9
version: osslsigncode-2.12
jobs:
build:
@@ -27,14 +27,8 @@ jobs:
os: ubuntu-22.04
generator: Unix Makefiles
vcpkg_root:
- id: ubuntu-20.04
triplet: x64-linux
compiler: gcc
os: ubuntu-20.04
generator: Unix Makefiles
vcpkg_root:
- id: macOS
triplet: x64-osx
triplet: arm64-osx
compiler: clang
os: macOS-latest
generator: Unix Makefiles
@@ -107,17 +101,23 @@ jobs:
if: matrix.compiler == 'mingw'
run: echo "D:/a/_temp/msys64/mingw64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Install apt dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get remove needrestart || echo Ignored
sudo apt-get install -y libssl-dev zlib1g-dev python3-cryptography
- name: Install brew dependencies (macOS)
- 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: |
brew install python@3.8
python -m venv --system-site-packages --copies venv
- 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)
if: runner.os == 'macOS'
@@ -128,46 +128,66 @@ jobs:
- name: Setup the oldest supported version of cmake (macOS)
if: runner.os == 'macOS'
uses: jwlawson/actions-setup-cmake@v2.0
with:
cmake-version: '3.17.0'
- name: Install python3 cryptography module (Linux)
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: Install python3 cryptography module (macOS)
if: runner.os == 'macOS'
run: |
python3.8 -m ensurepip
python3.8 -m pip install --upgrade pip
python3.8 -m pip install cryptography
source venv/bin/activate
python -m pip install --upgrade pip
ARCHFLAGS="-arch arm64" 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: Install python3 cryptography module (Windows)
if: runner.os == 'Windows'
run: |
C:/hostedtoolcache/windows/Python/3.12.3/x64/python3.exe -m ensurepip
C:/hostedtoolcache/windows/Python/3.12.3/x64/python.exe -m pip install --upgrade pip
C:/hostedtoolcache/windows/Python/3.12.3/x64/python.exe -m pip install cryptography
.\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
run: 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
-DVCPKG_TARGET_TRIPLET=${{matrix.triplet}}
- 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
run: cmake
--build ${{github.workspace}}/build
--config ${{env.BUILD_TYPE}}
- name: Show python version (macOS)
working-directory: ${{github.workspace}}/build
if: runner.os == 'macOS'
run: |
python3.8 --version
python3.8 -c "import sys; print(sys.executable)"
python3.8 -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
- name: List files (Linux/macOS)
if: runner.os != 'Windows'
run: find .. -ls
@@ -176,9 +196,19 @@ jobs:
if: runner.os == 'Windows'
run: Get-ChildItem -Recurse -Name ..
- name: Test
- name: Test (Linux/macOS)
if: runner.os != 'Windows'
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
uses: actions/upload-artifact@v4
+16
View File
@@ -0,0 +1,16 @@
name: Codespell
on:
pull_request:
push:
jobs:
codespell:
name: Check for spelling errors
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: codespell-project/actions-codespell@master
with:
skip: '*.pem'
+6 -3
View File
@@ -10,8 +10,8 @@ set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
# configure basic project information
project(osslsigncode
VERSION 2.9
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
VERSION 2.12
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT, MSI, APPX and script files"
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
LANGUAGES C)
@@ -29,6 +29,9 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
# load CMake library modules
include(FindOpenSSL)
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")
@@ -85,7 +88,7 @@ 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)
target_link_libraries(osslsigncode PRIVATE ws2_32.lib crypt32.lib)
endif(NOT UNIX)
# add paths to linker search and installed rpath
+1 -1
View File
@@ -1,4 +1,4 @@
OpenSSL based Authenticode signing for PE/MSI/Java CAB files.
OpenSSL based Authenticode signing for PE, CAB, CAT, MSI, APPX and script files.
Copyright (C) 2005-2014 Per Allansson <pallansson@gmail.com>
Copyright (C) 2018-2022 Michał Trojnara <Michal.Trojnara@stunnel.org>
+37
View File
@@ -1,5 +1,42 @@
# osslsigncode change log
### 2.12 (2026.02.02)
**CRITICAL SECURITY VULNERABILITY**
This release fixes a critical memory corruption vulnerability. A malicious
attacker could create a signed file, which, when verified with osslsigncode,
triggers arbitrary code execution. Any previous version of osslsigncode should
be immediately upgraded if the tool is used for verification of untrusted
files.
- fixed a buffer overflow while extracting message digests
(reported and fixed by Antoni Klajn, Opera)
### 2.11 (2026.01.20)
- added keyUsage validation for signer certificate
(thanks to Hanqing Zhao and Zi-Quan You for reporting the issue)
- added printing CRL details during signature verification
- implemented a workaround for CRL servers returning the HTTP Content-Type
header other than application/pkix-crl (thanks to Chris Thibodeaux)
- fixed HTTP keep-alive handling
- fixed macOS compiler and linker flags
- fixed undefined BIO_get_fp() behavior with BIO_FLAGS_UPLINK_INTERNAL
### 2.10 (2025.06.23)
- added JavaScript signing
- added PKCS#11 provider support (requires OpenSSL 3.0+)
- added support for providers without specifying "-pkcs11module" option
(OpenSSL 3.0+, e.g., for the upcoming CNG provider)
- added compatibility with the CNG engine version 1.1 or later
- added the "-engineCtrl" option to control hardware and CNG engines
- added the '-blobFile' option to specify a file containing the blob content
- improved unauthenticated blob support (thanks to Asger Hautop Drewsen)
- improved UTF-8 handling for certificate subjects and issuers
- fixed support for multiple signerInfo contentType OIDs (CTL and Authenticode)
- fixed tests for python-cryptography >= 43.0.0
### 2.9 (2024.06.29)
- added a 64 bit long pseudo-random NONCE in the TSA request
+61 -8
View File
@@ -19,11 +19,13 @@ machine every time I need to sign a binary - I can compile and build
the binaries using Wine on my Linux machine, but I can't sign them
since the signtool.exe makes good use of the CryptoAPI in Windows, and
these APIs aren't (yet?) fully implemented in Wine, so the signtool.exe
tool would fail. And, so, osslsigncode was born.
tool would fail. And, so, osslsigncode was born.
## WHAT CAN IT DO?
It can sign and timestamp PE (EXE/SYS/DLL/etc), CAB, CAT and MSI files.
It can sign and timestamp PE (EXE/SYS/DLL/etc), CAB, CAT, MSI and APPX files,
as well as script files with extensions `.ps1`, `.ps1xml`, `.psc1`, `.psd1`,
`.psm1`, `.cdxml`, `.mof`, and `.js`.
It supports the equivalent of signtool.exe's "-j javasign.dll -jp low",
i.e. add a valid signature for a CAB file containing Java files.
It supports getting the timestamp through a proxy as well. It also
@@ -122,7 +124,7 @@ You can use a certificate and key stored in a PKCS#12 container:
-n "Your Application" -i http://www.yourwebsite.com/ \
-in yourapp.exe -out yourapp-signed.exe
```
To sign a CAB file containing java class files:
To sign a CAB file containing Java class files:
```
osslsigncode sign -certs <cert-file> -key <key-file> \
-n "Your Application" -i http://www.yourwebsite.com/ \
@@ -131,17 +133,68 @@ To sign a CAB file containing java class files:
```
Only the 'low' parameter is currently supported.
If you want to use PKCS11 token, you should indicate PKCS11 engine and module.
An example of using osslsigncode with SoftHSM:
### Using the PKCS#11 Engine with osslsigncode
If you want to use a PKCS#11 token, specify the PKCS#11 engine and module.
Example usage with SoftHSM:
```
osslsigncode sign \
-pkcs11engine /usr/lib64/engines-1.1/pkcs11.so \
-engine /usr/lib64/engines-1.1/pkcs11.so \
-pkcs11module /usr/lib64/pkcs11/libsofthsm2.so \
-pkcs11cert 'pkcs11:token=softhsm-token;object=cert' \
-key 'pkcs11:token=softhsm-token;object=key' \
-in yourapp.exe -out yourapp-signed.exe
```
### Using the PKCS#11 Provider with osslsigncode (OpenSSL 3.x only)
OpenSSL 3.0 introduced a new provider-based architecture. To use a PKCS#11 token
with `osslsigncode`, specify the PKCS#11 provider and module.
Example usage 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
```
### Using the CNG Engine with osslsigncode (Windows only)
The CNG engine allows using certificates and keys stored in the Windows
Certificate Store. It requires 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 ensure `osslsigncode` can locate and load the CNG engine module (`cng.dll`)
even when it is not installed in the default system engine directory, you can:
- Specify the full or relative path to `cng.dll`:
```
osslsigncode sign -engine C:\my\engines\cng.dll ...
```
- Or set the `OPENSSL_ENGINES` environment variable to the directory containing
`cng.dll`, and refer to the engine by its ID:
```
set OPENSSL_ENGINES=C:\my\engines
osslsigncode sign -engine cng ...
```
Below is an example of how to use `osslsigncode` with the CNG engine on Windows:
```
set OPENSSL_ENGINES=C:\my\engines
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
on it in Windows and choose Properties --> Digital Signatures,
and then choose the signature from the list, and click on
@@ -179,13 +232,13 @@ osslsigncode.exe add -addUnauthenticatedBlob -in your_signed_file.exe -out out.e
This feature allows for doing dumb things. Be very careful with what you put
in the unauthenticated blob, as an attacker could modify this. Do NOT, under
any circumstances, put a URL here that you will use to download an additional
file. If you do do that, you would need to check the newly downloaded file is
file. If you do that, you would need to check the newly downloaded file is
code signed AND that it has been signed with your cert AND that it is the
version you expect.
## BUGS, QUESTIONS etc.
Check whether your your question or suspected bug was already
Check whether your question or suspected bug was already
discussed on https://github.com/mtrojnar/osslsigncode/issues.
Otherwise, open a new issue.
+1 -1
View File
@@ -1,4 +1,4 @@
- signature extraction/removal/verificaton on MSI/CAB files
- signature extraction/removal/verification on MSI/CAB files
- clean up / untangle code
- separate timestamping
- remove mmap usage to increase portability
+50 -21
View File
@@ -29,11 +29,6 @@
#endif /* _MSC_VER */
#endif /* PRIX64 */
#if defined(_MSC_VER)
#define fseeko _fseeki64
#define ftello _ftelli64
#endif /* _MSC_VER */
#define EOCDR_SIZE 22
#define ZIP64_EOCD_LOCATOR_SIZE 20
#define ZIP64_HEADER 0x01
@@ -293,7 +288,7 @@ static void zipWriteCentralDirectoryEntry(BIO *bio, uint64_t *sizeOnDisk, ZIP_CE
static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64_t dataSize);
static int zipOverrideFileData(ZIP_CENTRAL_DIRECTORY_ENTRY *entry, uint8_t *data, uint64_t dataSize);
static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO *bio, uint64_t *sizeOnDisk);
static void zipWriteLocalHeader(BIO *bio, uint64_t *sizeonDisk, ZIP_LOCAL_HEADER *heade);
static void zipWriteLocalHeader(BIO *bio, uint64_t *sizeonDisk, ZIP_LOCAL_HEADER *header);
static int zipEntryExist(ZIP_FILE *zip, const char *name);
static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *md);
static size_t zipReadFileDataByName(uint8_t **pData, ZIP_FILE *zip, const char *name);
@@ -878,11 +873,18 @@ static uint8_t *appx_calc_zip_central_directory_hash(ZIP_FILE *zip, const EVP_MD
u_char *mdbuf = NULL;
BIO *bhash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (!appx_write_central_directory(bhash, zip, 1, cdOffset)) {
fprintf(stderr, "Unable to write central directory\n");
@@ -910,7 +912,7 @@ static int appx_write_central_directory(BIO *bio, ZIP_FILE *zip, int removeSigna
uint16_t noEntries = 0;
for (entry = zip->centralDirectoryHead; entry != NULL; entry = entry->next) {
/* the signature file is considered non existent for hashing purposes */
/* the signature file is considered nonexistent for hashing purposes */
uint64_t sizeOnDisk = 0;
if (noEntries > zip->centralDirectoryRecordCount) {
fprintf(stderr, "Corrupted central directory structure\n");
@@ -923,7 +925,7 @@ static int appx_write_central_directory(BIO *bio, ZIP_FILE *zip, int removeSigna
if (removeSignature && !strcmp(entry->fileName, APP_SIGNATURE_FILENAME)) {
continue;
}
/* APP_SIGNATURE is nt 'tainted' by offset shift after replacing the contents of [content_types] */
/* APP_SIGNATURE is not 'tainted' by offset shift after replacing the contents of [content_types] */
zipWriteCentralDirectoryEntry(bio, &sizeOnDisk, entry, strcmp(entry->fileName, APP_SIGNATURE_FILENAME) ? offsetDiff : 0);
cdSize += sizeOnDisk;
if (entry->overrideData) {
@@ -1005,11 +1007,18 @@ static uint8_t *appx_calc_zip_data_hash(uint64_t *cdOffset, ZIP_FILE *zip, const
BIO *bhash = BIO_new(BIO_f_md());
uint64_t noEntries = 0;
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
*cdOffset = 0;
for (entry = zip->centralDirectoryHead; entry != NULL; entry = entry->next) {
@@ -1178,7 +1187,7 @@ static int appx_compare_hashes(FILE_FORMAT_CTX *ctx)
return 0; /* FAILED */
}
} else if (!ctx->appx_ctx->calculatedCIHash && !ctx->appx_ctx->existingCIHash) {
/* this is fine, CI file is optional -> if it is missing we expect both hashes to be non existent */
/* this is fine, CI file is optional -> if it is missing we expect both hashes to be nonexistent */
} else {
fprintf(stderr, "Code Integrity hash missing\n");
return 0; /* FAILED */
@@ -1421,7 +1430,7 @@ static void zipWriteCentralDirectoryEntry(BIO *bio, uint64_t *sizeOnDisk, ZIP_CE
#if 0
if (entry->extraFieldLen > 0 && entry->extraField)
{
/* TODO, if override daata, need to rewrite the extra field */
/* TODO, if override data, need to rewrite the extra field */
BIO_write(bio, entry->extraField, entry->extraFieldLen);
}
#endif
@@ -1493,6 +1502,7 @@ static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64
if (!get_current_position(bio, &offset)) {
fprintf(stderr, "Unable to get offset\n");
OPENSSL_free(header.fileName);
OPENSSL_free(dataToWrite);
return 0; /* FAILED */
}
@@ -1502,6 +1512,7 @@ static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64
size_t check;
if (!BIO_write_ex(bio, dataToWrite + written, toWrite, &check)
|| check != toWrite) {
OPENSSL_free(header.fileName);
OPENSSL_free(dataToWrite);
return 0; /* FAILED */
}
@@ -1596,6 +1607,7 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
{
size_t check;
ZIP_LOCAL_HEADER header;
int ret = 0;
memset(&header, 0, sizeof(header));
if (entry->offsetOfLocalHeader >= (uint64_t)zip->fileSize) {
@@ -1606,7 +1618,7 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
return 0; /* FAILED */
}
if (!zipReadLocalHeader(&header, zip, entry->compressedSize)) {
return 0; /* FAILED */
goto out;
}
if (entry->overrideData) {
header.compressedSize = entry->overrideData->compressedSize;
@@ -1617,14 +1629,14 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
if (entry->overrideData) {
if (!BIO_write_ex(bio, entry->overrideData->data, entry->overrideData->compressedSize, &check)
|| check != entry->overrideData->compressedSize) {
return 0; /* FAILED */
goto out;
}
if (entry->compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) {
fprintf(stderr, "Corrupted compressedSize : 0x%08" PRIX64 "\n", entry->compressedSize);
return 0; /* FAILED */
goto out;
}
if (fseeko(zip->file, (int64_t)entry->compressedSize, SEEK_CUR) < 0) {
return 0; /* FAILED */
goto out;
}
*sizeOnDisk += entry->overrideData->compressedSize;
} else {
@@ -1635,12 +1647,12 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
size_t size = fread(data, 1, toWrite, zip->file);
if (size != toWrite) {
OPENSSL_free(data);
return 0; /* FAILED */
goto out;
}
if (!BIO_write_ex(bio, data, toWrite, &check)
|| check != toWrite) {
OPENSSL_free(data);
return 0; /* FAILED */
goto out;
}
*sizeOnDisk += toWrite;
len -= toWrite;
@@ -1659,19 +1671,21 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
}
if (zip->isZip64) {
if (fseeko(zip->file, 24, SEEK_CUR) < 0) {
return 0; /* FAILED */
goto out;
}
*sizeOnDisk += 24;
} else {
if (fseeko(zip->file, 16, SEEK_CUR) < 0) {
return 0; /* FAILED */
goto out;
}
*sizeOnDisk += 16;
}
}
ret = 1; /* OK */
out:
OPENSSL_free(header.fileName);
OPENSSL_free(header.extraField);
return 1; /* OK */
return ret;
}
/*
@@ -1758,12 +1772,19 @@ static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *
return NULL; /* FAILED */
}
bhash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
OPENSSL_free(data);
BIO_free_all(bhash);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (!bio_hash_data(bhash, (char *)data, 0, dataSize)) {
OPENSSL_free(data);
@@ -1840,6 +1861,8 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
uncompressedSize = entry->uncompressedSize;
memset(&header, 0, sizeof(header));
if (!zipReadLocalHeader(&header, zip, compressedSize)) {
OPENSSL_free(header.fileName);
OPENSSL_free(header.extraField);
return 0; /* FAILED */
}
if (header.fileNameLen != entry->fileNameLen
@@ -1848,6 +1871,8 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
|| header.uncompressedSize != uncompressedSize
|| header.compression != entry->compression) {
fprintf(stderr, "Local header does not match central directory entry\n");
OPENSSL_free(header.fileName);
OPENSSL_free(header.extraField);
return 0; /* FAILED */
}
/* we don't really need those */
@@ -1883,7 +1908,7 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
OPENSSL_free(compressedData);
if (ret != Z_OK) {
fprintf(stderr, "Data decompresssion failed, zlib error: %d\n", ret);
fprintf(stderr, "Data decompression failed, zlib error: %d\n", ret);
OPENSSL_free(uncompressedData);
return 0; /* FAILED */
} else {
@@ -2149,6 +2174,7 @@ static int zipDeflate(uint8_t *dest, uint64_t *destLen, uint8_t *source, uLong s
err = deflateInit2(&stream, 8, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
if (err != Z_OK) {
deflateEnd(&stream);
return err;
}
stream.next_out = dest;
@@ -2718,7 +2744,10 @@ static int get_current_position(BIO *bio, uint64_t *offset)
FILE *file = NULL;
int64_t pos;
BIO_get_fp(bio, &file);
if (BIO_get_fp(bio, &file) != 1 || file == NULL) {
fprintf(stderr, "BIO_get_fp() failed\n");
return 0; /* FAILED */
}
pos = ftello(file);
if (pos < 0) {
return 0; /* FAILED */
+11 -4
View File
@@ -205,11 +205,18 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
u_char *mdbuf = NULL;
BIO *bhash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
/* u1 signature[4] 4643534D MSCF: 0-3 */
@@ -335,9 +342,9 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
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);
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
@@ -689,7 +696,7 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
* and consist of 4 bytes (little-endian order)
* siglen - additional data size is located at offset 48 (from file beginning)
* and consist of 4 bytes (little-endian order)
* If there are additional headers, size of the CAB archive file is calcualted
* If there are additional headers, size of the CAB archive file is calculated
* as additional data offset plus additional data size.
*/
sigpos = GET_UINT32_LE(indata + 44);
+30 -16
View File
@@ -55,8 +55,8 @@ FILE_FORMAT file_format_cat = {
/* Prototypes */
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
static int cat_add_ms_ctl_object(PKCS7 *p7);
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents);
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);
@@ -161,17 +161,17 @@ static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
fprintf(stderr, "Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (!cat_add_ms_ctl_object(p7)) {
fprintf(stderr, "Adding MS_CTL_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!ctx->cat_ctx->p7 || !ctx->cat_ctx->p7->d.sign || !ctx->cat_ctx->p7->d.sign->contents) {
fprintf(stderr, "Failed to get content\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!cat_sign_ms_ctl_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
if (!cat_add_content_type(p7, ctx->cat_ctx->p7)) {
fprintf(stderr, "Adding content type failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!cat_sign_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
fprintf(stderr, "Failed to set signed content\n");
PKCS7_free(p7);
return NULL; /* FAILED */
@@ -251,15 +251,30 @@ static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
}
/*
* Add "1.3.6.1.4.1.311.10.1" MS_CTL_OBJID signed attribute
* 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_ms_ctl_object(PKCS7 *p7)
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 */
@@ -267,7 +282,7 @@ static int cat_add_ms_ctl_object(PKCS7 *p7)
if (!si)
return 0; /* FAILED */
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
V_ASN1_OBJECT, OBJ_txt2obj(content_type, 1)))
return 0; /* FAILED */
return 1; /* OK */
}
@@ -280,7 +295,7 @@ static int cat_add_ms_ctl_object(PKCS7 *p7)
* [in] contents: Certificate Trust List (CTL)
* [returns] 0 on error or 1 on success
*/
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents)
static int cat_sign_content(PKCS7 *p7, PKCS7 *contents)
{
u_char *content;
int seqhdrlen, content_length;
@@ -375,10 +390,9 @@ static int cat_print_content_member_digest(ASN1_TYPE *content)
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);
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
if (mdtype == -1) {
+1 -1
View File
@@ -3,7 +3,7 @@
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenSSL based Authenticode signing for PE, CAB, CAT, MSI, APPX and script files")
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING.txt")
+4 -3
View File
@@ -75,9 +75,9 @@ if(Python3_FOUND)
endif(NOT client_result)
endif(EXISTS "${LOGS}/url.log")
set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat" "ps1" "psc1" "mof")
set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx" "ps1" "psc1" "mof")
set(extensions_nocatappx "exe" "ex_" "msi" "ps1" "psc1" "mof")
set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat" "ps1" "psc1" "mof" "js")
set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx" "ps1" "psc1" "mof" "js")
set(extensions_nocatappx "exe" "ex_" "msi" "ps1" "psc1" "mof" "js")
set(formats "pem" "der")
else(NOT cryptography_error)
@@ -219,6 +219,7 @@ if(Python3_FOUND AND NOT cryptography_error)
add_test(NAME "added_${ext}"
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "add"
"-addUnauthenticatedBlob"
"-blobFile" "${FILES}/unsigned.exe"
"-add-msi-dse" "-h" "sha512"
"-in" "${FILES}/signed.${ext}"
"-out" "${FILES}/added.${ext}")
+4 -9
View File
@@ -96,16 +96,11 @@ function(add_compile_flags target)
message(WARNING "No stack protection supported")
endif(HAVE_STACK_PROTECTOR)
endif(HAVE_STACK_PROTECTOR_ALL)
# Support address space layout randomization (ASLR)
if(NOT (MINGW OR CYGWIN OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
OR ((CMAKE_SYSTEM_NAME MATCHES Darwin) AND (CMAKE_C_COMPILER_ID MATCHES Clang))))
# Support address space layout randomization (ASLR) / PIE
if(UNIX AND NOT APPLE)
target_compile_options(${target} PRIVATE -fPIE)
target_link_options(${target} PRIVATE -fPIE -pie)
target_link_options(${target} PRIVATE -Wl,-z,relro)
target_link_options(${target} PRIVATE -Wl,-z,now)
target_link_options(${target} PRIVATE -Wl,-z,noexecstack)
endif(NOT (MINGW OR CYGWIN OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
OR ((CMAKE_SYSTEM_NAME MATCHES Darwin) AND (CMAKE_C_COMPILER_ID MATCHES Clang))))
target_link_options(${target} PRIVATE -fPIE -pie -Wl,-z,relro,-z,now,-z,noexecstack)
endif(UNIX AND NOT APPLE)
target_link_options(${target} PRIVATE -fstack-check)
add_compile_flag_to_targets(${target})
endif(MSVC)
+1341 -638
View File
File diff suppressed because it is too large Load Diff
+18 -7
View File
@@ -10,6 +10,7 @@ from csv import reader
from requests import get
from requests.exceptions import RequestException
from concurrent.futures import ThreadPoolExecutor
from re import search
def download_cert(hash):
for attempt in range(10):
@@ -17,23 +18,33 @@ def download_cert(hash):
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'))
proxies = dict(https=f'socks5://{creds}@127.0.0.1:9050')
url = f'https://crt.sh/?sha1={hash}&match=='
resp = get(url, proxies=proxies)
resp.raise_for_status()
m = search(r'\bid=(\d+)\b', resp.content.decode('ascii', 'replace'))
id = m.group(1)
url = f'https://crt.sh/?d={id}'
resp = get(url, proxies=proxies)
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)
return resp.content.decode('utf-8', 'replace')
except Exception as e:
print(f'\n{url} attempt {attempt}: {e}', file=stderr)
print('\nGiving up on', hash, file=stderr)
resp = get('https://ccadb-public.secure.force.com/microsoft/IncludedCACertificateReportForMSFTCSV')
resp = get('https://ccadb.my.salesforce-sites.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:
with ThreadPoolExecutor(max_workers=10) as executor:
certs = executor.map(download_cert, hashes)
for cert in certs:
if cert is not None:
+120 -42
View File
@@ -17,6 +17,7 @@ static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_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);
static void sk_X509_remove_duplicates(STACK_OF(X509) *chain);
/*
* Common functions
@@ -165,73 +166,76 @@ int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
{
int i, signer = -1;
PKCS7 *p7;
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_content_new(p7, NID_pkcs7_data);
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) {
fprintf(stderr, "Failed to checking the consistency of a private key: %s\n",
ctx->options->keyfile);
fprintf(stderr, " with a public key in any X509 certificate: %s\n\n",
ctx->options->certfile);
return NULL; /* FAILED */
/* 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;
if (signer > 0)
printf("Warning: For optimal performance, consider placing the signer certificate at the beginning of the certificate chain.\n");
break;
}
}
if (!si) {
fprintf(stderr, "Failed to checking the consistency of a private key: %s\n",
ctx->options->keyfile);
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)) {
return NULL; /* FAILED */
goto err;
}
if (!pkcs7_signer_info_add_purpose(si, ctx)) {
return NULL; /* FAILED */
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");
return NULL; /* FAILED */
goto err;
}
if ((ctx->options->nested_number >= 0) &&
!pkcs7_signer_info_add_sequence_number(si, ctx)) {
return NULL; /* FAILED */
goto err;
}
/* create X509 chain sorted in ascending order by their DER encoding */
chain = X509_chain_get_sorted(ctx, signer);
if (chain == NULL) {
if (!chain) {
fprintf(stderr, "Failed to create a sorted certificate chain\n");
return NULL; /* FAILED */
goto err;
}
/* add sorted certificate chain */
for (i=0; i<sk_X509_num(chain); i++) {
PKCS7_add_certificate(p7, sk_X509_value(chain, i));
(void)PKCS7_add_certificate(p7, sk_X509_value(chain, i));
}
/* add crls */
if (ctx->options->crls) {
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 */
err:
PKCS7_free(p7);
return NULL; /* FAILED */
}
/*
@@ -461,7 +465,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
* [returns] 0 on error or 1 on success
*/
@@ -471,6 +475,10 @@ int is_content_type(PKCS7 *p7, const char *objid)
int ret;
indir_objid = OBJ_txt2obj(objid, 1);
if (!indir_objid) {
fprintf(stderr, "Invalid object identifier: %s\n", objid);
return 0; /* FAILED */
}
ret = p7 && PKCS7_type_is_signed(p7) &&
!OBJ_cmp(p7->d.sign->contents->type, indir_objid) &&
(p7->d.sign->contents->d.other->type == V_ASN1_SEQUENCE ||
@@ -540,6 +548,33 @@ SpcLink *spc_link_obsolete_get(void)
return link;
}
/*
* Safely extract digest from SpcIndirectDataContent
* [in] idc: parsed SpcIndirectDataContent
* [out] mdbuf: output buffer (must be EVP_MAX_MD_SIZE bytes)
* [out] mdtype: digest algorithm's NID
* [returns] -1 on error or digest length on success
*/
int spc_extract_digest_safe(SpcIndirectDataContent *idc,
u_char *mdbuf, int *mdtype)
{
int digest_len;
if (!idc || !idc->messageDigest || !idc->messageDigest->digest ||
!idc->messageDigest->digestAlgorithm) {
fprintf(stderr, "Missing digest data\n");
return -1;
}
digest_len = idc->messageDigest->digest->length;
if (digest_len <= 0 || digest_len > EVP_MAX_MD_SIZE) {
fprintf(stderr, "Invalid digest length: %d\n", digest_len);
return -1;
}
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)digest_len);
*mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
return digest_len;
}
/*
* [in] mdbuf, cmdbuf: message digests
* [in] mdtype: message digest algorithm type
@@ -732,11 +767,6 @@ 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);
/* add the signer's certificate */
if (ctx->options->cert != NULL && !sk_X509_push(chain, ctx->options->cert)) {
sk_X509_free(chain);
return NULL;
}
if (signer != -1 && !sk_X509_push(chain, sk_X509_value(ctx->options->certs, signer))) {
sk_X509_free(chain);
return NULL;
@@ -761,6 +791,9 @@ static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
}
/* sort certificate chain using the supplied comparison function */
sk_X509_sort(chain);
/* remove duplicates */
sk_X509_remove_duplicates(chain);
return chain;
}
@@ -779,6 +812,15 @@ static int X509_compare(const X509 *const *a, const X509 *const *b)
size_t a_len, b_len;
int ret;
#if OPENSSL_VERSION_NUMBER<0x30000000L
#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
#elif defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
#endif
#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */
a_len = (size_t)i2d_X509(*a, NULL);
a_tmp = a_data = OPENSSL_malloc(a_len);
i2d_X509(*a, &a_tmp);
@@ -786,6 +828,13 @@ static int X509_compare(const X509 *const *a, const X509 *const *b)
b_len = (size_t)i2d_X509(*b, NULL);
b_tmp = b_data = OPENSSL_malloc(b_len);
i2d_X509(*b, &b_tmp);
#if OPENSSL_VERSION_NUMBER<0x30000000L
#if defined(__clang__)
#pragma clang diagnostic pop
#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */
ret = memcmp(a_data, b_data, MIN(a_len, b_len));
OPENSSL_free(a_data);
@@ -796,6 +845,35 @@ static int X509_compare(const X509 *const *a, const X509 *const *b)
return ret;
}
/*
* Remove duplicate certificates from a sorted STACK_OF(X509).
*
* This function assumes the stack is sorted according to X.690-compliant
* certificate comparison, so duplicate certificates appear consecutively.
* It iterates through the stack and removes any duplicate certificates
* by comparing each element with its immediate predecessor.
* The stack is modified in place.
*/
static void sk_X509_remove_duplicates(STACK_OF(X509) *chain)
{
int i, n = sk_X509_num(chain);
if (n < 2)
return;
/* start from the second element */
for (i = 1; i < n; ) {
if (!X509_cmp(sk_X509_value(chain, i - 1), sk_X509_value(chain, i))) {
/* duplicate found: remove the certificate at index i */
(void)sk_X509_delete(chain, i);
n--; /* reduce stack size since one element was removed */
/* do not increment i, as next element shifts into index i */
} else {
i++; /* advance only if no removal was done */
}
}
}
/*
Local Variables:
c-basic-offset: 4
+2
View File
@@ -24,6 +24,8 @@ int is_content_type(PKCS7 *p7, const char *objid);
MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
SpcLink *spc_link_obsolete_get(void);
int spc_extract_digest_safe(SpcIndirectDataContent *idc,
u_char *mdbuf, int *mdtype);
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
/*
+37 -6
View File
@@ -373,11 +373,18 @@ static u_char *msi_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
u_char *mdbuf = NULL;
BIO *bhash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (!bio_hash_data(bhash, ctx->options->indata, 0, ctx->msi_ctx->fileend)) {
fprintf(stderr, "Unable to calculate digest\n");
@@ -412,9 +419,9 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
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);
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
@@ -426,11 +433,18 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
printf("Message digest algorithm : %s\n", OBJ_nid2sn(mdtype));
md = EVP_get_digestbynid(mdtype);
hash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(hash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(hash);
return 0; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(hash, BIO_new(BIO_s_null()));
if (ctx->msi_ctx->p_msiex) {
BIO *prehash = BIO_new(BIO_f_md());
@@ -440,12 +454,19 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
BIO_free_all(prehash);
return 0; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(prehash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(hash);
BIO_free_all(prehash);
return 0; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(prehash, BIO_new(BIO_s_null()));
print_hash("Current MsiDigitalSignatureEx ", "", (u_char *)ctx->msi_ctx->p_msiex,
@@ -1785,7 +1806,6 @@ static int ministream_save(MSI_DIRENT *dirent, BIO *outdata, MSI_OUT *out)
dirent->entry->startSectorLocation = out->sectorNum;
/* ministream save */
BIO_write(outdata, out->ministream, (int)out->miniStreamLen);
OPENSSL_free(out->ministream);
/* fill to the end with known data, such as all zeroes */
if (out->miniStreamLen % out->sectorSize > 0) {
remain = out->sectorSize - out->miniStreamLen % out->sectorSize;
@@ -2186,6 +2206,8 @@ static int msiout_set(MSI_FILE *msi, uint32_t len_msi, uint32_t len_msiex, MSI_O
out->header = header_new(msi->m_hdr, out);
out->minifatMemallocCount = msi->m_hdr->numMiniFATSector;
out->fatMemallocCount = msi->m_hdr->numFATSector;
out->difatMemallocCount = 0;
out->difat = NULL;
out->ministream = NULL;
out->minifat = OPENSSL_malloc((uint64_t)out->minifatMemallocCount * out->sectorSize);
out->fat = OPENSSL_malloc((uint64_t)out->fatMemallocCount * out->sectorSize);
@@ -2226,7 +2248,9 @@ static int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, uint
out:
OPENSSL_free(out.header);
OPENSSL_free(out.fat);
OPENSSL_free(out.difat);
OPENSSL_free(out.minifat);
OPENSSL_free(out.ministream);
return ret;
}
@@ -2295,11 +2319,18 @@ static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash)
size_t written;
BIO *prehash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(prehash, ctx->options->md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(prehash);
return 0; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(prehash, BIO_new(BIO_s_null()));
if (!msi_prehash_dir(ctx->msi_ctx->dirent, prehash, 1)) {
@@ -2368,8 +2399,8 @@ static int msi_hash_length_get(FILE_FORMAT_CTX *ctx)
/*
* Get DigitalSignature and MsiDigitalSignatureEx streams
* to check if the signature exists.
* [in, out] ctx: structure holds input and output datafv
* [returns] 0 on error or 1 on successs
* [in, out] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int msi_check_file(FILE_FORMAT_CTX *ctx)
{
+788 -472
View File
File diff suppressed because it is too large Load Diff
+22 -4
View File
@@ -66,7 +66,9 @@
#include <openssl/rand.h>
#include <openssl/safestack.h>
#include <openssl/ssl.h>
#include <openssl/store.h>
#include <openssl/ts.h>
#include <openssl/ui.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h> /* X509_PURPOSE */
@@ -90,7 +92,9 @@
#ifdef _MSC_VER
/* not WIN32, because strcasecmp exists in MinGW */
#define strcasecmp _stricmp
#endif
#define fseeko _fseeki64
#define ftello _ftelli64
#endif /* _MSC_VER */
#ifdef WIN32
#define remove_file(filename) _unlink(filename)
@@ -242,6 +246,16 @@ typedef enum {
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 {
char *infile;
char *outfile;
@@ -254,10 +268,13 @@ typedef struct {
int output_pkcs7;
#ifndef OPENSSL_NO_ENGINE
char *p11engine;
char *p11module;
char *p11cert;
STACK_OF(EngineControl) *engine_ctrls;
int login;
#endif /* OPENSSL_NO_ENGINE */
#if !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L
char *p11module;
char *p11cert;
#endif /* !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L */
int askpass;
char *readpass;
char *pass;
@@ -274,6 +291,7 @@ typedef struct {
char *proxy;
int noverifypeer;
int addBlob;
const char *blob_file;
int nest;
int index;
int ignore_timestamp;
@@ -292,9 +310,9 @@ typedef struct {
int jp;
#if OPENSSL_VERSION_NUMBER>=0x30000000L
int legacy;
char *provider;
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
EVP_PKEY *pkey;
X509 *cert;
STACK_OF(X509) *certs;
STACK_OF(X509) *xcerts;
STACK_OF(X509_CRL) *crls;
+24 -3
View File
@@ -255,9 +255,9 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
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);
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
@@ -779,11 +779,18 @@ static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
uint32_t idx = 0, fileend;
BIO *bhash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (ctx->pe_ctx->sigpos)
fileend = ctx->pe_ctx->sigpos;
@@ -958,11 +965,18 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
phlen = pphlen * (3 + (int)nsections + (int)(ctx->pe_ctx->fileend / pagesize));
bhash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|| written != ctx->pe_ctx->header_size + 88) {
@@ -1005,6 +1019,10 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
for (l=0; l<rs; l+=pagesize, pi++) {
PUT_UINT32_LE(ro + l, res + pi*pphlen);
bhash = BIO_new(BIO_f_md());
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(bhash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
@@ -1012,6 +1030,9 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
OPENSSL_free(res);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(bhash, BIO_new(BIO_s_null()));
if (rs - l < pagesize) {
if (!BIO_write_ex(bhash, ctx->options->indata + ro + l, rs - l, &written)
+54 -24
View File
@@ -8,11 +8,17 @@
#include "helpers.h"
#include "utf.h"
typedef enum {comment_hash, comment_xml, comment_c, comment_not_found} comment_style;
typedef enum {
comment_hash,
comment_xml,
comment_c,
comment_js,
comment_not_found
} COMMENT_STYLE;
typedef struct {
const char *extension;
comment_style comment;
COMMENT_STYLE comment;
} SCRIPT_FORMAT;
const SCRIPT_FORMAT supported_formats[] = {
@@ -23,21 +29,24 @@ const SCRIPT_FORMAT supported_formats[] = {
{".psm1", comment_hash},
{".cdxml", comment_xml},
{".mof", comment_c},
{".js", comment_js},
{NULL, comment_not_found},
};
const char *signature_header = "SIG # Begin signature block";
const char *signature_footer = "SIG # End signature block";
#define header_hash "SIG # Begin signature block"
#define footer_hash "SIG # End signature block"
#define header_js "Begin signature block"
#define footer_js "End signature block"
typedef struct {
const char *open;
const char *close;
const char *open, *close, *header, *footer;
} SCRIPT_COMMENT;
const SCRIPT_COMMENT comment_text[] = {
[comment_hash] = {"# ", ""},
[comment_xml] = {"<!-- ", " -->"},
[comment_c] = {"/* ", " */"}
[comment_hash] = {"# ", "", header_hash, footer_hash},
[comment_xml] = {"<!-- ", " -->", header_hash, footer_hash},
[comment_c] = {"/* ", " */", header_hash, footer_hash},
[comment_js] = {"// SIG // ", "", header_js, footer_js}
};
struct script_ctx_st {
@@ -242,11 +251,18 @@ 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 defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(hash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(hash);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(hash, BIO_new(BIO_s_null()));
if (!script_write_bio(hash, ctx->options->indata, ctx->script_ctx->fileend)) {
BIO_free_all(hash);
@@ -278,9 +294,9 @@ static int script_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
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);
if (spc_extract_digest_safe(idc, mdbuf, &mdtype) < 0) {
SpcIndirectDataContent_free(idc);
return 0; /* FAILED */
}
SpcIndirectDataContent_free(idc);
}
@@ -326,8 +342,8 @@ static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
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);
size_t header_len = strlen(ctx->script_ctx->comment_text->header);
size_t footer_len = strlen(ctx->script_ctx->comment_text->footer);
PKCS7 *retval = NULL;
if (!script_check_file(ctx)) {
@@ -337,6 +353,8 @@ static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
if (ctx->script_ctx->utf == 8) {
base64_len = signature_len;
base64_data = OPENSSL_malloc(base64_len);
if (!base64_data)
return NULL; /* memory allocation failed */
memcpy(base64_data, signature_data, base64_len);
} else {
base64_len = utf16_to_utf8((const void *)signature_data,
@@ -364,12 +382,12 @@ static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
}
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))
/* process header and footer */
if (ptr + header_len < base64_data + base64_len &&
!memcmp(ptr, ctx->script_ctx->comment_text->header, header_len))
ptr += header_len;
if (ptr + footer_len <= base64_data + base64_len &&
!memcmp(ptr, ctx->script_ctx->comment_text->footer, footer_len))
break; /* success */
/* copy until the closing tag */
@@ -531,7 +549,9 @@ static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
(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)))
if (!write_commented(ctx, outdata,
ctx->script_ctx->comment_text->header,
strlen(ctx->script_ctx->comment_text->header)))
goto cleanup;
for (i = 0; i < buffer->length; i += 64) {
if (!write_commented(ctx, outdata, buffer->data + i,
@@ -539,7 +559,9 @@ static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
goto cleanup;
}
}
if (!write_commented(ctx, outdata, signature_footer, strlen(signature_footer)))
if (!write_commented(ctx, outdata,
ctx->script_ctx->comment_text->footer,
strlen(ctx->script_ctx->comment_text->footer)))
goto cleanup;
/* signtool expects CRLF terminator at the end of the text file */
@@ -605,7 +627,7 @@ static SCRIPT_CTX *script_ctx_get(char *indata, uint32_t filesize, const SCRIPT_
*ptr && commented_header_len < commented_header_size;
commented_header_len++)
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
for (ptr = signature_header;
for (ptr = comment->header;
*ptr && commented_header_len < commented_header_size;
commented_header_len++)
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
@@ -671,6 +693,8 @@ static int write_commented(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *data,
* - closing tag
* - trailing NUL ("\0") */
line = OPENSSL_malloc(2 + open_tag_len + length + close_tag_len + 1);
if (!line)
return 0; /* memory allocation failed */
strcpy(line, "\r\n");
strcat(line, open_tag);
memcpy(line + 2 + open_tag_len, data, length);
@@ -782,12 +806,18 @@ static BIO *script_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
fileend = ctx->script_ctx->sigpos;
else
fileend = ctx->script_ctx->fileend;
#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wcast-qual"
#endif
if (!BIO_set_md(hash, md)) {
fprintf(stderr, "Unable to set the message digest of BIO\n");
BIO_free_all(hash);
return NULL; /* FAILED */
}
#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
BIO_push(hash, BIO_new(BIO_s_null()));
if (!script_digest_convert(hash, ctx, fileend)) {
fprintf(stderr, "Unable calc a message digest value\n");
+1 -1
View File
@@ -1,5 +1,5 @@
#!/usr/bin/python3
"""Implementation of a HTTP client"""
"""Implementation of an HTTP client"""
import os
import sys
+1 -1
View File
@@ -29,7 +29,7 @@ def main() -> None:
# all exceptions are critical
print(err, file=sys.stderr)
else:
print("Usage:\n\t{} COMMAND [ARG]...'".format(sys.argv[0]), file=sys.stderr)
print("Usage:\n\t{} COMMAND [ARG]...".format(sys.argv[0]), file=sys.stderr)
sys.exit(1)
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
console.log("Hello, world!");
+176 -115
View File
@@ -4,11 +4,60 @@
import os
import datetime
import cryptography
from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric import rsa
# 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/")
@@ -28,25 +77,25 @@ class X509Extensions():
self.port = cdp_port
self.name = cdp_name
def create_x509_name(self, common_name) -> x509.Name:
def create_x509_name(self, common_name) -> Name:
"""Return x509.Name"""
return x509.Name(
return Name(
[
x509.NameAttribute(NameOID.COUNTRY_NAME, "PL"),
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Mazovia Province"),
x509.NameAttribute(NameOID.LOCALITY_NAME, "Warsaw"),
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "osslsigncode"),
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, self.unit_name),
x509.NameAttribute(NameOID.COMMON_NAME, common_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) -> x509.CRLDistributionPoints:
def create_x509_crldp(self) -> CRLDistributionPoints:
"""Return x509.CRLDistributionPoints"""
return x509.CRLDistributionPoints(
return CRLDistributionPoints(
[
x509.DistributionPoint(
full_name=[x509.UniformResourceIdentifier(
DistributionPoint(
full_name=[UniformResourceIdentifier(
"http://127.0.0.1:" + str(self.port) + "/" + str(self.name))
],
relative_name=None,
@@ -56,10 +105,10 @@ class X509Extensions():
]
)
def create_x509_name_constraints(self) -> x509.NameConstraints:
def create_x509_name_constraints(self) -> NameConstraints:
"""Return x509.NameConstraints"""
return x509.NameConstraints(
permitted_subtrees = [x509.DNSName('test.com'), x509.DNSName('test.org')],
return NameConstraints(
permitted_subtrees = [DNSName('test.com'), DNSName('test.org')],
excluded_subtrees = None
)
@@ -71,14 +120,14 @@ class IntermediateCACertificate(X509Extensions):
self.issuer_key = issuer_key
super().__init__("Certification Authority", 0, None)
def make_cert(self) -> (x509.Certificate, rsa.RSAPrivateKey):
def make_cert(self) -> (Certificate, RSAPrivateKey):
"""Generate intermediate CA certificate"""
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
key = generate_private_key(public_exponent=65537, key_size=2048)
key_public = key.public_key()
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
key_usage = x509.KeyUsage(
key_usage = KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
@@ -90,22 +139,22 @@ class IntermediateCACertificate(X509Extensions):
decipher_only=False
)
cert = (
x509.CertificateBuilder()
CertificateBuilder()
.subject_name(self.create_x509_name("Intermediate CA"))
.issuer_name(self.issuer_cert.subject)
.public_key(key_public)
.serial_number(x509.random_serial_number())
.serial_number(random_serial_number())
.not_valid_before(date_20180101)
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
.add_extension(x509.BasicConstraints(ca=True, path_length=0), critical=True)
.add_extension(x509.SubjectKeyIdentifier.from_public_key(key_public), critical=False)
.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, hashes.SHA256())
.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=serialization.Encoding.PEM))
file.write(cert.public_bytes(encoding=Encoding.PEM))
return cert, key
@@ -114,7 +163,7 @@ class RootCACertificate(X509Extensions):
"""Base class for Root CA certificate"""
def __init__(self):
self.key_usage = x509.KeyUsage(
self.key_usage = KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
@@ -127,7 +176,7 @@ class RootCACertificate(X509Extensions):
)
super().__init__("Certification Authority", 0, None)
def make_cert(self) -> (x509.Certificate, rsa.RSAPrivateKey):
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")
@@ -136,52 +185,52 @@ class RootCACertificate(X509Extensions):
def make_ca_cert(self, common_name, file_name) -> None:
"""Generate self-signed root CA certificate"""
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
ca_public = ca_key.public_key()
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
name = self.create_x509_name(common_name)
ca_cert = (
x509.CertificateBuilder()
CertificateBuilder()
.subject_name(name)
.issuer_name(name)
.public_key(ca_public)
.serial_number(x509.random_serial_number())
.serial_number(random_serial_number())
.not_valid_before(date_20170101)
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
.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, hashes.SHA256())
.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=serialization.Encoding.PEM))
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 = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
ca_root.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
ca_root.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
ca_cross = (
x509.CertificateBuilder()
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(x509.BasicConstraints(ca=True, path_length=None), critical=True)
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
.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, hashes.SHA256())
.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=serialization.Encoding.PEM))
file.write(ca_cross.public_bytes(encoding=Encoding.PEM))
def write_key(self, key, file_name) -> None:
"""Write a private RSA key"""
@@ -194,27 +243,27 @@ class RootCACertificate(X509Extensions):
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=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.BestAvailableEncryption(PASSWORD.encode())
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=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
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=serialization.Encoding.DER,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
encoding=Encoding.DER,
format=PrivateFormat.PKCS8,
encryption_algorithm=NoEncryption()
)
)
@@ -225,13 +274,13 @@ class TSARootCACertificate(X509Extensions):
def __init__(self):
super().__init__("Timestamp Authority Root CA", 0, None)
def make_cert(self) -> (x509.Certificate, rsa.RSAPrivateKey):
def make_cert(self) -> (Certificate, RSAPrivateKey):
"""Generate a Time Stamp Authority certificate"""
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
ca_public = ca_key.public_key()
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
name = self.create_x509_name("TSA Root CA")
key_usage = x509.KeyUsage(
key_usage = KeyUsage(
digital_signature=False,
content_commitment=False,
key_encipherment=False,
@@ -243,22 +292,22 @@ class TSARootCACertificate(X509Extensions):
decipher_only=False
)
ca_cert = (
x509.CertificateBuilder()
CertificateBuilder()
.subject_name(name)
.issuer_name(name)
.public_key(ca_public)
.serial_number(x509.random_serial_number())
.serial_number(random_serial_number())
.not_valid_before(date_20170101)
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
.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, hashes.SHA256())
.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=serialization.Encoding.PEM))
file.write(ca_cert.public_bytes(encoding=Encoding.PEM))
return ca_cert, ca_key
@@ -267,14 +316,14 @@ class TSARootCACertificate(X509Extensions):
file_path = os.path.join(CERTS_PATH, file_name + ".key")
with open(file_path, mode="wb") as file:
file.write(key.private_bytes(
encoding=serialization.Encoding.PEM,
format=serialization.PrivateFormat.PKCS8,
encryption_algorithm=serialization.NoEncryption()
encoding=Encoding.PEM,
format=PrivateFormat.PKCS8,
encryption_algorithm=NoEncryption()
)
)
class Certificate(X509Extensions):
class LeafCertificate(X509Extensions):
"""Base class for a leaf certificate"""
def __init__(self, issuer_cert, issuer_key, unit_name, common_name, cdp_port, cdp_name):
@@ -284,78 +333,90 @@ class Certificate(X509Extensions):
self.common_name = common_name
super().__init__(unit_name, cdp_port, cdp_name)
def make_cert(self, public_key, not_before, days) -> x509.Certificate:
def make_cert(self, public_key, not_before, days) -> Certificate:
"""Generate a leaf certificate"""
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
extended_key_usage = x509.ExtendedKeyUsage(
[x509.oid.ExtendedKeyUsageOID.CODE_SIGNING]
key_usage = KeyUsage(
digital_signature=True,
content_commitment=False,
key_encipherment=False,
data_encipherment=False,
key_agreement=False,
key_cert_sign=False,
crl_sign=False,
encipher_only=False,
decipher_only=False
)
extended_key_usage = ExtendedKeyUsage(
[ExtendedKeyUsageOID.CODE_SIGNING]
)
cert = (
x509.CertificateBuilder()
CertificateBuilder()
.subject_name(self.create_x509_name(self.common_name))
.issuer_name(self.issuer_cert.subject)
.public_key(public_key)
.serial_number(x509.random_serial_number())
.serial_number(random_serial_number())
.not_valid_before(not_before)
.not_valid_after(not_before + datetime.timedelta(days=days))
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=False)
.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
.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(key_usage, critical=False)
.add_extension(extended_key_usage, critical=False)
.add_extension(self.create_x509_crldp(), critical=False)
.sign(self.issuer_key, hashes.SHA256())
.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=serialization.Encoding.PEM))
file.write(self.issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
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 = (
x509.RevokedCertificateBuilder()
RevokedCertificateBuilder()
.serial_number(serial_number)
.revocation_date(date_20190101)
.add_extension(x509.CRLReason(x509.ReasonFlags.superseded), critical=False)
.add_extension(CRLReason(ReasonFlags.superseded), critical=False)
.build()
)
# Generate CRL
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
)
crl = (
x509.CertificateRevocationListBuilder()
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(x509.CRLNumber(4097), critical=False)
.add_extension(CRLNumber(4097), critical=False)
.add_revoked_certificate(revoked)
.sign(self.issuer_key, hashes.SHA256())
.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=serialization.Encoding.PEM))
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=serialization.Encoding.DER))
file.write(crl.public_bytes(encoding=Encoding.DER))
class LeafCACertificate(Certificate):
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(Certificate):
class LeafTSACertificate(LeafCertificate):
"""Base class for a TSA leaf certificate"""
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
@@ -364,40 +425,40 @@ class LeafTSACertificate(Certificate):
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) -> x509.Certificate:
def make_cert(self, public_key, not_before, days) -> Certificate:
"""Generate a TSA leaf certificate"""
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
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 = x509.ExtendedKeyUsage(
[x509.oid.ExtendedKeyUsageOID.TIME_STAMPING]
extended_key_usage = ExtendedKeyUsage(
[ExtendedKeyUsageOID.TIME_STAMPING]
)
cert = (
x509.CertificateBuilder()
CertificateBuilder()
.subject_name(self.create_x509_name(self.common_name))
.issuer_name(self.issuer_cert.subject)
.public_key(public_key)
.serial_number(x509.random_serial_number())
.serial_number(random_serial_number())
.not_valid_before(not_before)
.not_valid_after(not_before + datetime.timedelta(days=days))
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
.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, hashes.SHA256())
.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=serialization.Encoding.PEM))
file.write(self.issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
file.write(cert.public_bytes(encoding=Encoding.PEM))
file.write(self.issuer_cert.public_bytes(encoding=Encoding.PEM))
return cert
@@ -433,7 +494,7 @@ class CertificateMaker():
issuer_cert, issuer_key = intermediate.make_cert()
# Generate private RSA key
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
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")
@@ -460,7 +521,7 @@ class CertificateMaker():
# 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=serialization.Encoding.DER))
file.write(cert.public_bytes(encoding=Encoding.DER))
def make_tsa_certs(self):
"""Make test TSA certificates"""
@@ -470,7 +531,7 @@ class CertificateMaker():
issuer_cert, issuer_key = root.make_cert()
# Generate private RSA key
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
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")
@@ -486,8 +547,8 @@ class CertificateMaker():
# 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=serialization.Encoding.PEM))
file.write(issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
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:
@@ -499,16 +560,16 @@ class CertificateMaker():
# and private key encryption: DES-EDE3-CBC (vel 3DES_CBC)
# pylint: disable=no-member
encryption = (
serialization.PrivateFormat.PKCS12.encryption_builder()
.key_cert_algorithm(serialization.pkcs12.PBES.PBESv1SHA1And3KeyTripleDESCBC)
PrivateFormat.PKCS12.encryption_builder()
.key_cert_algorithm(PBES.PBESv1SHA1And3KeyTripleDESCBC)
.kdf_rounds(5000)
.build(PASSWORD.encode())
)
else:
encryption = serialization.BestAvailableEncryption(PASSWORD.encode())
encryption = BestAvailableEncryption(PASSWORD.encode())
# Generate PKCS#12 struct
pkcs12 = serialization.pkcs12.serialize_key_and_certificates(
pkcs12 = serialize_key_and_certificates(
name=b'certificate',
key=key,
cert=cert,
+4 -4
View File
@@ -1,5 +1,5 @@
#!/usr/bin/python3
"""Implementation of a HTTP server"""
"""Implementation of an HTTP server"""
import argparse
import os
@@ -17,7 +17,7 @@ CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
RESPONSE = os.path.join(FILES_PATH, "./jresp.tsr")
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
@@ -26,7 +26,7 @@ OPENSSL_TS = ["openssl", "ts",
"-reply", "-config", OPENSSL_CONF,
"-passin", "pass:passme",
"-queryfile", REQUEST,
"-out", RESPONS]
"-out", RESPONSE]
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
@@ -86,7 +86,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.send_header("Content-type", "application/timestamp-reply")
self.end_headers()
resp_data = b''
with open(RESPONS, mode="rb") as file:
with open(RESPONSE, mode="rb") as file:
resp_data = file.read()
self.wfile.write(resp_data)
+4 -4
View File
@@ -1,5 +1,5 @@
#!/usr/bin/python3
"""Windows: Implementation of a HTTP server"""
"""Windows: Implementation of an HTTP server"""
import argparse
import os
@@ -16,7 +16,7 @@ CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
RESPONSE = os.path.join(FILES_PATH, "./jresp.tsr")
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
@@ -26,7 +26,7 @@ OPENSSL_TS = ["openssl", "ts",
"-reply", "-config", OPENSSL_CONF,
"-passin", "pass:passme",
"-queryfile", REQUEST,
"-out", RESPONS]
"-out", RESPONSE]
class RequestHandler(SimpleHTTPRequestHandler):
@@ -82,7 +82,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.send_header("Content-type", "application/timestamp-reply")
self.end_headers()
resp_data = b''
with open(RESPONS, mode="rb") as file:
with open(RESPONSE, mode="rb") as file:
resp_data = file.read()
self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except
@@ -55,3 +55,6 @@ CATATTR1=0x11010001:OSAttr:2:6.0
<HASH>MOFfile=..\files\unsigned.mof
<HASH>MOFfileATTR1=0x11010001:File:unsigned.mof
<HASH>JSfile=..\files\unsigned.js
<HASH>JSfileATTR1=0x11010001:File:unsigned.js
+1 -1
View File
@@ -51,7 +51,7 @@ def clear_catalog(certs_path) -> None:
file.write(random_hex)
def main() -> None:
"""Wait for all tests certificate, compute leafhash"""
"""Wait for all test certificates and compute leaf hash"""
parser = argparse.ArgumentParser()
parser.add_argument(