mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-04-06 01:18:05 -05:00
Compare commits
128 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
4568c890cc | ||
![]() |
4bd167a8be | ||
![]() |
e7405fa839 | ||
![]() |
776e2ec7b6 | ||
![]() |
838aaaee8d | ||
![]() |
e8f19a6efe | ||
![]() |
3a8e25e5bb | ||
![]() |
7d1b460dfe | ||
![]() |
bc3e9e2172 | ||
![]() |
21bce757ef | ||
![]() |
6a43f62835 | ||
![]() |
8780e6f8e4 | ||
![]() |
78a23caa54 | ||
![]() |
d92927aff4 | ||
![]() |
4f412b5989 | ||
![]() |
e6f3ff631d | ||
![]() |
09135aabb8 | ||
![]() |
de983e680f | ||
![]() |
dc827b94e5 | ||
![]() |
40ce811701 | ||
![]() |
db5b4c4dc0 | ||
![]() |
4ee429792d | ||
![]() |
27686c0b0c | ||
![]() |
21133f9c3b | ||
![]() |
64305d6415 | ||
![]() |
4dd836bab1 | ||
![]() |
f57c213207 | ||
![]() |
76ee550c9d | ||
![]() |
2b3228d549 | ||
![]() |
bad6e96e0f | ||
![]() |
3c8c74a8c3 | ||
![]() |
771014a41e | ||
![]() |
476168e09e | ||
![]() |
be4f010535 | ||
![]() |
2c27e2e37d | ||
![]() |
b829e7a802 | ||
![]() |
d0ae214cb4 | ||
![]() |
9b1a6c9fb8 | ||
![]() |
41b662a8fe | ||
![]() |
5232734071 | ||
![]() |
996cf20fa9 | ||
![]() |
825c9dad7c | ||
![]() |
6e5bef14e9 | ||
![]() |
a53bd2bdb3 | ||
![]() |
e4d471b885 | ||
![]() |
bcb9737dda | ||
![]() |
7a5389b719 | ||
![]() |
d9f0a8dade | ||
![]() |
aa8c8dd720 | ||
![]() |
16c5e5aa4a | ||
![]() |
ded1f7aa67 | ||
![]() |
6ad2679f17 | ||
![]() |
4776f43f04 | ||
![]() |
d9db038c65 | ||
![]() |
e8ef027776 | ||
![]() |
0a0761746f | ||
![]() |
f51e2a4869 | ||
![]() |
093ed12c66 | ||
![]() |
71a046a2d0 | ||
![]() |
c73f82b558 | ||
![]() |
b294f5d18f | ||
![]() |
e07bb7d6b2 | ||
![]() |
699bc85d0a | ||
![]() |
192e7a732b | ||
![]() |
656051676f | ||
![]() |
3998bcabb2 | ||
![]() |
fa40c57f80 | ||
![]() |
0b93a94ffa | ||
![]() |
105fd3af4a | ||
![]() |
86a594b087 | ||
![]() |
1dea73b038 | ||
![]() |
b661ed08ed | ||
![]() |
ead0584611 | ||
![]() |
bd7751147e | ||
![]() |
1bc7fc36b8 | ||
![]() |
42e9733916 | ||
![]() |
b2024cee9d | ||
![]() |
9d152b8477 | ||
![]() |
7a02d51a83 | ||
![]() |
dac68a3a4d | ||
![]() |
bd1ab77f44 | ||
![]() |
5ee859db2c | ||
![]() |
ee3c51f6d5 | ||
![]() |
cedb8b5798 | ||
![]() |
dcf58a00e7 | ||
![]() |
4576895718 | ||
![]() |
1bdcad619e | ||
![]() |
31b046cf98 | ||
![]() |
f3ac2c0c6f | ||
![]() |
f22c83514c | ||
![]() |
44ca1f38e6 | ||
![]() |
0985c47990 | ||
![]() |
aa158e40ec | ||
![]() |
5da62de5ef | ||
![]() |
4d08fbb2c1 | ||
![]() |
98b004edda | ||
![]() |
34bf3bc525 | ||
![]() |
64e1bba96b | ||
![]() |
46bcaa9d88 | ||
![]() |
867e0d446d | ||
![]() |
7285778cb0 | ||
![]() |
c909ba82d7 | ||
![]() |
7b60d6447d | ||
![]() |
588a1a0b5f | ||
![]() |
8a9b275494 | ||
![]() |
0db17be606 | ||
![]() |
f9ad19d4a2 | ||
![]() |
b9ca24d423 | ||
![]() |
8d2b562244 | ||
![]() |
6f4e9ab597 | ||
![]() |
6d6270094e | ||
![]() |
57563716d1 | ||
![]() |
8ab8a133f7 | ||
![]() |
ef5047038e | ||
![]() |
e290e03341 | ||
![]() |
900ffed596 | ||
![]() |
33253afb5e | ||
![]() |
3aba55e5e0 | ||
![]() |
898a53b2a7 | ||
![]() |
75ce1dadf5 | ||
![]() |
4166476030 | ||
![]() |
a5690f2d19 | ||
![]() |
cdb75578e9 | ||
![]() |
e2ab4a152d | ||
![]() |
b8e690f3bd | ||
![]() |
c89d6b43aa | ||
![]() |
9faed39931 | ||
![]() |
ecb17709fc |
148
.github/workflows/ci.yml
vendored
148
.github/workflows/ci.yml
vendored
@ -7,7 +7,7 @@ on:
|
|||||||
env:
|
env:
|
||||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
version: osslsigncode-2.7
|
version: osslsigncode-2.10-dev
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -15,6 +15,12 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- id: ubuntu-24.04
|
||||||
|
triplet: x64-linux
|
||||||
|
compiler: gcc
|
||||||
|
os: ubuntu-24.04
|
||||||
|
generator: Unix Makefiles
|
||||||
|
vcpkg_root:
|
||||||
- id: ubuntu-22.04
|
- id: ubuntu-22.04
|
||||||
triplet: x64-linux
|
triplet: x64-linux
|
||||||
compiler: gcc
|
compiler: gcc
|
||||||
@ -28,7 +34,7 @@ jobs:
|
|||||||
generator: Unix Makefiles
|
generator: Unix Makefiles
|
||||||
vcpkg_root:
|
vcpkg_root:
|
||||||
- id: macOS
|
- id: macOS
|
||||||
triplet: x64-osx
|
triplet: arm64-osx
|
||||||
compiler: clang
|
compiler: clang
|
||||||
os: macOS-latest
|
os: macOS-latest
|
||||||
generator: Unix Makefiles
|
generator: Unix Makefiles
|
||||||
@ -72,11 +78,11 @@ jobs:
|
|||||||
VCPKG_ROOT: ${{matrix.vcpkg_root}}
|
VCPKG_ROOT: ${{matrix.vcpkg_root}}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Cache the vcpkg archives
|
- name: Cache the vcpkg archives
|
||||||
if: matrix.cache != ''
|
if: matrix.cache != ''
|
||||||
uses: actions/cache@v3
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{matrix.cache}}
|
path: ${{matrix.cache}}
|
||||||
key: ${{matrix.id}}-${{hashFiles('vcpkg.json')}}
|
key: ${{matrix.id}}-${{hashFiles('vcpkg.json')}}
|
||||||
@ -90,11 +96,34 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
arch: ${{matrix.arch}}
|
arch: ${{matrix.arch}}
|
||||||
|
|
||||||
- name: Install apt dependencies (Linux)
|
- name: Install MSYS2
|
||||||
if: runner.os == 'Linux'
|
if: matrix.compiler == 'mingw'
|
||||||
|
uses: msys2/setup-msys2@v2
|
||||||
|
with:
|
||||||
|
update: true
|
||||||
|
install: mingw-w64-x86_64-ninja
|
||||||
|
|
||||||
|
- name: Put MSYS2_MinGW64 on PATH
|
||||||
|
if: matrix.compiler == 'mingw'
|
||||||
|
run: echo "D:/a/_temp/msys64/mingw64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||||
|
|
||||||
|
- name: Set up Python (macOS)
|
||||||
|
if: runner.os == 'macOS'
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: '3.13'
|
||||||
|
update-environment: false
|
||||||
|
architecture: 'arm64'
|
||||||
|
|
||||||
|
- name: Set up Python virtual environment (Linux/macOS)
|
||||||
|
if: runner.os != 'Windows'
|
||||||
run: |
|
run: |
|
||||||
sudo apt-get update
|
python -m venv --system-site-packages --copies venv
|
||||||
sudo apt-get install -y libssl-dev libcurl4-openssl-dev faketime
|
|
||||||
|
- name: Set up Python virtual environment (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
python.exe -m venv --system-site-packages --copies venv
|
||||||
|
|
||||||
- name: Install Xcode (macOS)
|
- name: Install Xcode (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
@ -104,46 +133,67 @@ jobs:
|
|||||||
|
|
||||||
- name: Setup the oldest supported version of cmake (macOS)
|
- name: Setup the oldest supported version of cmake (macOS)
|
||||||
if: runner.os == 'macOS'
|
if: runner.os == 'macOS'
|
||||||
uses: jwlawson/actions-setup-cmake@v1.12
|
uses: jwlawson/actions-setup-cmake@v2.0
|
||||||
with:
|
|
||||||
cmake-version: '3.17.0'
|
|
||||||
|
|
||||||
- name: Show OpenSSL version
|
- name: Install python3 cryptography module (Linux)
|
||||||
run: openssl version -a
|
if: runner.os == 'Linux'
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
python -m pip install --upgrade cryptography
|
||||||
|
python -c "import sys; print(sys.executable)"
|
||||||
|
python --version
|
||||||
|
python -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||||
|
|
||||||
- name: Configure CMake
|
- name: Install python3 cryptography module (macOS)
|
||||||
run: cmake
|
if: runner.os == 'macOS'
|
||||||
-G "${{matrix.generator}}"
|
run: |
|
||||||
-S ${{github.workspace}}
|
source venv/bin/activate
|
||||||
-B ${{github.workspace}}/build
|
python -m pip install --upgrade pip
|
||||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
ARCHFLAGS="-arch arm64" python -m pip install --upgrade cryptography
|
||||||
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/dist
|
python -c "import sys; print(sys.executable)"
|
||||||
-DVCPKG_TARGET_TRIPLET=${{matrix.triplet}}
|
python --version
|
||||||
|
python -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||||
|
|
||||||
|
- name: Install python3 cryptography module (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
.\venv\Scripts\Activate.ps1
|
||||||
|
python.exe -m ensurepip
|
||||||
|
python.exe -m pip install --upgrade pip
|
||||||
|
python.exe -m pip install cryptography
|
||||||
|
python.exe -c "import sys; print(sys.executable)"
|
||||||
|
python.exe --version
|
||||||
|
python.exe -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||||
|
|
||||||
|
- name: Configure CMake (Linux/macOS)
|
||||||
|
if: runner.os != 'Windows'
|
||||||
|
run: |
|
||||||
|
source venv/bin/activate
|
||||||
|
cmake \
|
||||||
|
-G "${{matrix.generator}}" \
|
||||||
|
-S "${{github.workspace}}" \
|
||||||
|
-B "${{github.workspace}}/build" \
|
||||||
|
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||||
|
-DCMAKE_BUILD_TYPE="${{env.BUILD_TYPE}}" \
|
||||||
|
-DCMAKE_INSTALL_PREFIX="${{github.workspace}}/dist"
|
||||||
|
|
||||||
|
- name: Configure CMake (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
run: |
|
||||||
|
.\venv\Scripts\Activate.ps1
|
||||||
|
cmake `
|
||||||
|
-G "${{matrix.generator}}" `
|
||||||
|
-S "${{github.workspace}}" `
|
||||||
|
-B "${{github.workspace}}/build" `
|
||||||
|
-DCMAKE_BUILD_TYPE="${{env.BUILD_TYPE}}" `
|
||||||
|
-DCMAKE_INSTALL_PREFIX="${{github.workspace}}/dist"
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: cmake
|
run: cmake
|
||||||
--build ${{github.workspace}}/build
|
--build ${{github.workspace}}/build
|
||||||
--config ${{env.BUILD_TYPE}}
|
--config ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
- name: Start HTTP server (macOS)
|
|
||||||
working-directory: ${{github.workspace}}/build
|
|
||||||
if: runner.os == 'macOS'
|
|
||||||
run: |
|
|
||||||
python3 --version
|
|
||||||
python3 ./Testing/server_http.py --port 19254
|
|
||||||
while test ! -s ./Testing/logs/port.log; do sleep 1; done
|
|
||||||
|
|
||||||
- name: Start HTTP server (Windows)
|
|
||||||
working-directory: ${{github.workspace}}\build
|
|
||||||
if: runner.os == 'Windows'
|
|
||||||
run: |
|
|
||||||
python.exe --version
|
|
||||||
$Args = '.\Testing\server_http.pyw --port 19254'
|
|
||||||
$File = '.\Testing\logs\port.log'
|
|
||||||
Start-Process -FilePath pythonw.exe -ArgumentList $Args
|
|
||||||
while(-not(Test-Path -Path $File -PathType Leaf) -or [String]::IsNullOrWhiteSpace((Get-Content $File))) {Start-Sleep -Seconds 1}
|
|
||||||
Get-Content '.\Testing\logs\server.log'
|
|
||||||
|
|
||||||
- name: List files (Linux/macOS)
|
- name: List files (Linux/macOS)
|
||||||
if: runner.os != 'Windows'
|
if: runner.os != 'Windows'
|
||||||
run: find .. -ls
|
run: find .. -ls
|
||||||
@ -152,12 +202,22 @@ jobs:
|
|||||||
if: runner.os == 'Windows'
|
if: runner.os == 'Windows'
|
||||||
run: Get-ChildItem -Recurse -Name ..
|
run: Get-ChildItem -Recurse -Name ..
|
||||||
|
|
||||||
- name: Test
|
- name: Test (Linux/macOS)
|
||||||
|
if: runner.os != 'Windows'
|
||||||
working-directory: ${{github.workspace}}/build
|
working-directory: ${{github.workspace}}/build
|
||||||
run: ctest -C ${{env.BUILD_TYPE}}
|
run: |
|
||||||
|
source ../venv/bin/activate
|
||||||
|
ctest -C ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
|
- name: Test (Windows)
|
||||||
|
if: runner.os == 'Windows'
|
||||||
|
working-directory: ${{github.workspace}}/build
|
||||||
|
run: |
|
||||||
|
..\venv\Scripts\Activate.ps1
|
||||||
|
ctest -C ${{env.BUILD_TYPE}}
|
||||||
|
|
||||||
- name: Upload the errors
|
- name: Upload the errors
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
if: failure()
|
if: failure()
|
||||||
with:
|
with:
|
||||||
name: errors-${{matrix.id}}
|
name: errors-${{matrix.id}}
|
||||||
@ -171,7 +231,7 @@ jobs:
|
|||||||
run: cmake --install ${{github.workspace}}/build
|
run: cmake --install ${{github.workspace}}/build
|
||||||
|
|
||||||
- name: Upload the executables
|
- name: Upload the executables
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{env.version}}-${{matrix.id}}
|
name: ${{env.version}}-${{matrix.id}}
|
||||||
path: ${{github.workspace}}/dist
|
path: ${{github.workspace}}/dist
|
||||||
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@ -25,11 +25,11 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
# Initializes the CodeQL tools for scanning.
|
# Initializes the CodeQL tools for scanning.
|
||||||
- name: Initialize CodeQL
|
- name: Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v2
|
uses: github/codeql-action/init@v3
|
||||||
with:
|
with:
|
||||||
languages: ${{ matrix.language }}
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
@ -43,7 +43,7 @@ jobs:
|
|||||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
# If this step fails, then you should remove it and run the build manually (see below)
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
- name: Autobuild
|
- name: Autobuild
|
||||||
uses: github/codeql-action/autobuild@v2
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
# ℹ️ Command-line programs to run using the OS shell.
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
||||||
@ -56,4 +56,4 @@ jobs:
|
|||||||
# ./location_of_script_within_repo/buildscript.sh
|
# ./location_of_script_within_repo/buildscript.sh
|
||||||
|
|
||||||
- name: Perform CodeQL Analysis
|
- name: Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v2
|
uses: github/codeql-action/analyze@v3
|
||||||
|
2
.github/workflows/coverity.yml
vendored
2
.github/workflows/coverity.yml
vendored
@ -10,7 +10,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
token: ${{secrets.COVERITY_SCAN_TOKEN}}
|
token: ${{secrets.COVERITY_SCAN_TOKEN}}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v4
|
||||||
if: env.token
|
if: env.token
|
||||||
- name: Get ready for scanning
|
- name: Get ready for scanning
|
||||||
if: env.token
|
if: env.token
|
||||||
|
@ -3,20 +3,20 @@ cmake_minimum_required(VERSION 3.17)
|
|||||||
|
|
||||||
# autodetect vcpkg CMAKE_TOOLCHAIN_FILE if VCPKG_ROOT is defined
|
# autodetect vcpkg CMAKE_TOOLCHAIN_FILE if VCPKG_ROOT is defined
|
||||||
# this needs to be configured before the project() directive
|
# this needs to be configured before the project() directive
|
||||||
if(DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
if((CMAKE_GENERATOR MATCHES "Ninja") AND DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||||
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
|
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" CACHE STRING "")
|
||||||
endif(DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
endif((CMAKE_GENERATOR MATCHES "Ninja") AND DEFINED ENV{VCPKG_ROOT} AND NOT $ENV{VCPKG_ROOT} STREQUAL "" AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
|
||||||
set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
|
set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
|
||||||
|
|
||||||
# configure basic project information
|
# configure basic project information
|
||||||
project(osslsigncode
|
project(osslsigncode
|
||||||
VERSION 2.7
|
VERSION 2.10
|
||||||
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
|
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
|
||||||
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
|
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
|
||||||
LANGUAGES C)
|
LANGUAGES C)
|
||||||
|
|
||||||
# force nonstandard version format for development packages
|
# force nonstandard version format for development packages
|
||||||
set(DEV "")
|
set(DEV "-dev")
|
||||||
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${DEV}")
|
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}${DEV}")
|
||||||
|
|
||||||
# version and contact information
|
# version and contact information
|
||||||
@ -27,9 +27,18 @@ set(PACKAGE_BUGREPORT "Michal.Trojnara@stunnel.org")
|
|||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
add_definitions(-DUSE_WIN32)
|
||||||
|
endif()
|
||||||
|
|
||||||
# load CMake library modules
|
# load CMake library modules
|
||||||
include(FindOpenSSL)
|
include(FindOpenSSL)
|
||||||
include(FindCURL)
|
if(OPENSSL_VERSION VERSION_LESS "1.1.1")
|
||||||
|
message(FATAL_ERROR "OpenSSL version must be at least 1.1.1")
|
||||||
|
endif()
|
||||||
|
if(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||||
|
include(FindCURL)
|
||||||
|
endif(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||||
include(FindZLIB)
|
include(FindZLIB)
|
||||||
|
|
||||||
# load CMake project modules
|
# load CMake project modules
|
||||||
@ -48,7 +57,7 @@ configure_file(Config.h.in config.h)
|
|||||||
target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1)
|
target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1)
|
||||||
|
|
||||||
# set sources
|
# set sources
|
||||||
target_sources(osslsigncode PRIVATE osslsigncode.c helpers.c msi.c pe.c cab.c cat.c appx.c)
|
target_sources(osslsigncode PRIVATE osslsigncode.c helpers.c utf.c msi.c pe.c cab.c cat.c appx.c script.c)
|
||||||
if(NOT UNIX)
|
if(NOT UNIX)
|
||||||
target_sources(osslsigncode PRIVATE applink.c)
|
target_sources(osslsigncode PRIVATE applink.c)
|
||||||
endif(NOT UNIX)
|
endif(NOT UNIX)
|
||||||
@ -64,6 +73,7 @@ target_include_directories(osslsigncode PRIVATE ${OPENSSL_INCLUDE_DIR})
|
|||||||
target_link_libraries(osslsigncode PRIVATE ${OPENSSL_LIBRARIES})
|
target_link_libraries(osslsigncode PRIVATE ${OPENSSL_LIBRARIES})
|
||||||
|
|
||||||
# set cURL includes/libraries
|
# set cURL includes/libraries
|
||||||
|
if(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||||
if(CURL_FOUND)
|
if(CURL_FOUND)
|
||||||
target_compile_definitions(osslsigncode PRIVATE ENABLE_CURL=1)
|
target_compile_definitions(osslsigncode PRIVATE ENABLE_CURL=1)
|
||||||
target_include_directories(osslsigncode PRIVATE ${CURL_INCLUDE_DIRS})
|
target_include_directories(osslsigncode PRIVATE ${CURL_INCLUDE_DIRS})
|
||||||
@ -72,6 +82,7 @@ if(CURL_FOUND)
|
|||||||
else(CURL_FOUND)
|
else(CURL_FOUND)
|
||||||
message(STATUS "cURL support disabled (library not found)")
|
message(STATUS "cURL support disabled (library not found)")
|
||||||
endif(CURL_FOUND)
|
endif(CURL_FOUND)
|
||||||
|
endif(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||||
|
|
||||||
if(NOT ZLIB_FOUND)
|
if(NOT ZLIB_FOUND)
|
||||||
message(FATAL_ERROR "Zlib library not found")
|
message(FATAL_ERROR "Zlib library not found")
|
||||||
@ -79,6 +90,11 @@ endif(NOT ZLIB_FOUND)
|
|||||||
target_include_directories(osslsigncode PRIVATE ${ZLIB_INCLUDE_DIR})
|
target_include_directories(osslsigncode PRIVATE ${ZLIB_INCLUDE_DIR})
|
||||||
target_link_libraries(osslsigncode PRIVATE ${ZLIB_LIBRARIES})
|
target_link_libraries(osslsigncode PRIVATE ${ZLIB_LIBRARIES})
|
||||||
|
|
||||||
|
if(NOT UNIX)
|
||||||
|
# https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown
|
||||||
|
target_link_libraries(osslsigncode PRIVATE Ws2_32.lib crypt32.lib)
|
||||||
|
endif(NOT UNIX)
|
||||||
|
|
||||||
# add paths to linker search and installed rpath
|
# add paths to linker search and installed rpath
|
||||||
set_target_properties(osslsigncode PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
|
set_target_properties(osslsigncode PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||||
|
|
||||||
|
32
Dockerfile
Normal file
32
Dockerfile
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Stage 1: Build osslsigncode on Alpine
|
||||||
|
FROM alpine:latest AS builder
|
||||||
|
|
||||||
|
# Install build dependencies
|
||||||
|
RUN apk add --no-cache build-base cmake openssl-dev zlib-dev
|
||||||
|
|
||||||
|
# Copy osslsigncode source code into the image
|
||||||
|
COPY . /source
|
||||||
|
|
||||||
|
# Build osslsigncode
|
||||||
|
RUN cd /source && \
|
||||||
|
mkdir -p build && \
|
||||||
|
cd build && \
|
||||||
|
rm -f CMakeCache.txt && \
|
||||||
|
cmake -S .. && \
|
||||||
|
cmake --build . && \
|
||||||
|
cmake --install .
|
||||||
|
|
||||||
|
# Stage 2: Create final image without build environment
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
# Copy compiled binary from builder stage
|
||||||
|
COPY --from=builder /usr/local/bin/osslsigncode /usr/local/bin/osslsigncode
|
||||||
|
|
||||||
|
# Install necessary runtime libraries (latest version)
|
||||||
|
RUN apk add --no-cache libcrypto3
|
||||||
|
|
||||||
|
# Set working directory
|
||||||
|
WORKDIR /workdir
|
||||||
|
|
||||||
|
# Declare volume to mount files
|
||||||
|
VOLUME [ "/workdir" ]
|
@ -3,50 +3,40 @@
|
|||||||
### Building osslsigncode source with MSYS2 MinGW 64-bit and MSYS2 packages:
|
### Building osslsigncode source with MSYS2 MinGW 64-bit and MSYS2 packages:
|
||||||
|
|
||||||
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
|
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
|
||||||
Once up and running install even mingw-w64-x86_64-gcc, mingw-w64-x86_64-curl.
|
Once up and running install the following packages:
|
||||||
```
|
```
|
||||||
pacman -S mingw-w64-x86_64-gcc mingw-w64-x86_64-curl
|
pacman -S make mingw-w64-x86_64-gcc mingw-w64-x86_64-cmake mingw-w64-x86_64-openssl mingw-w64-x86_64-python-cryptography
|
||||||
```
|
```
|
||||||
mingw-w64-x86_64-openssl and mingw-w64-x86_64-zlib packages are installed with dependencies.
|
mingw-w64-x86_64-zlib package is installed with dependencies.
|
||||||
|
|
||||||
2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables.
|
2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables.
|
||||||
```
|
```
|
||||||
cd osslsigncode-folder
|
cd osslsigncode-folder
|
||||||
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \
|
mkdir build && cd build && cmake -S .. -DCMAKE_BUILD_TYPE=Release -G "MSYS Makefiles"
|
||||||
-lcrypto -lssl -lcurl \
|
cmake --build . --verbose
|
||||||
-D 'PACKAGE_STRING="osslsigncode x.y"' \
|
|
||||||
-D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \
|
|
||||||
-D ENABLE_CURL
|
|
||||||
```
|
```
|
||||||
|
|
||||||
3) Run "Command prompt" and include "c:\msys64\mingw64\bin" folder as part of the path.
|
3) Make tests.
|
||||||
|
```
|
||||||
|
ctest
|
||||||
|
```
|
||||||
|
|
||||||
|
4) Run "Command prompt" and include "c:\msys64\mingw64\bin" folder as part of the path.
|
||||||
```
|
```
|
||||||
path=%path%;c:\msys64\mingw64\bin
|
path=%path%;c:\msys64\mingw64\bin
|
||||||
cd osslsigncode-folder
|
|
||||||
osslsigncode.exe -v
|
osslsigncode.exe -v
|
||||||
osslsigncode 2.4, using:
|
osslsigncode 2.8, using:
|
||||||
OpenSSL 1.1.1g 21 Apr 2020 (Library: OpenSSL 1.1.1g 21 Apr 2020)
|
OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023)
|
||||||
libcurl/7.70.0 OpenSSL/1.1.1g (Schannel) zlib/1.2.11 brotli/1.0.7 libidn2/2.3.0
|
No default -CAfile location detected
|
||||||
libpsl/0.21.0 (+libidn2/2.3.0) libssh2/1.9.0 nghttp2/1.40.0
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Building OpenSSL and osslsigncode sources with MSYS2 MinGW 64-bit:
|
||||||
### Building OpenSSL, Curl and osslsigncode sources with MSYS2 MinGW 64-bit:
|
|
||||||
|
|
||||||
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
|
1) Download and install MSYS2 from https://msys2.github.io/ and follow installation instructions.
|
||||||
Once up and running install even: perl make autoconf automake libtool pkg-config.
|
Once up and running install even: perl make autoconf automake libtool pkg-config.
|
||||||
```
|
```
|
||||||
pacman -S perl make autoconf automake libtool pkg-config
|
pacman -S perl make autoconf automake libtool pkg-config
|
||||||
```
|
```
|
||||||
Make sure there are no curl, brotli, libpsl, libidn2 and nghttp2 packages installed:
|
|
||||||
```
|
|
||||||
pacman -R mingw-w64-x86_64-curl \
|
|
||||||
mingw-w64-x86_64-brotli \
|
|
||||||
mingw-w64-x86_64-libpsl \
|
|
||||||
mingw-w64-x86_64-libidn2 \
|
|
||||||
mingw-w64-x86_64-nghttp2
|
|
||||||
```
|
|
||||||
|
|
||||||
Run "MSYS2 MinGW 64-bit" in the administrator mode.
|
Run "MSYS2 MinGW 64-bit" in the administrator mode.
|
||||||
|
|
||||||
2) Build and install OpenSSL.
|
2) Build and install OpenSSL.
|
||||||
@ -55,46 +45,30 @@
|
|||||||
./config --prefix='C:/OpenSSL' --openssldir='C:/OpenSSL'
|
./config --prefix='C:/OpenSSL' --openssldir='C:/OpenSSL'
|
||||||
make && make install
|
make && make install
|
||||||
```
|
```
|
||||||
3) Build and install curl.
|
|
||||||
```
|
|
||||||
cd curl-(version)
|
|
||||||
./buildconf
|
|
||||||
./configure --prefix='C:/curl' --with-ssl='C:/OpenSSL' \
|
|
||||||
--disable-ftp --disable-tftp --disable-file --disable-dict \
|
|
||||||
--disable-telnet --disable-imap --disable-smb --disable-smtp \
|
|
||||||
--disable-gopher --disable-pop --disable-pop3 --disable-rtsp \
|
|
||||||
--disable-ldap --disable-ldaps --disable-unix-sockets \
|
|
||||||
--disable-pthreads --without-zstd --without-zlib
|
|
||||||
make && make install
|
|
||||||
```
|
|
||||||
|
|
||||||
3) Build 64-bit Windows executables.
|
3) Configure a CMake project.
|
||||||
```
|
```
|
||||||
cd osslsigncode-folder
|
mkdir build && cd build && cmake -S .. -DCMAKE_BUILD_TYPE=Release -G "MSYS Makefiles" -DCMAKE_PREFIX_PATH="C:\OpenSSL"
|
||||||
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \
|
|
||||||
-L 'C:/OpenSSL/lib/' -lcrypto -lssl \
|
|
||||||
-I 'C:/OpenSSL/include/' \
|
|
||||||
-L 'C:/curl/lib' -lcurl \
|
|
||||||
-I 'C:/curl/include' \
|
|
||||||
-D 'PACKAGE_STRING="osslsigncode x.y"' \
|
|
||||||
-D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \
|
|
||||||
-D ENABLE_CURL
|
|
||||||
```
|
```
|
||||||
|
|
||||||
4) Run "Command prompt" and copy required libraries.
|
4) Run "Command prompt" and copy required libraries.
|
||||||
```
|
```
|
||||||
cd osslsigncode-folder
|
cd osslsigncode-folder
|
||||||
copy C:\OpenSSL\bin\libssl-1_1-x64.dll
|
copy C:\OpenSSL\bin\libssl-3-x64.dll
|
||||||
copy C:\OpenSSL\bin\libcrypto-1_1-x64.dll
|
copy C:\OpenSSL\bin\libcrypto-3-x64.dll
|
||||||
copy C:\curl\bin\libcurl-4.dll
|
|
||||||
|
|
||||||
osslsigncode.exe -v
|
|
||||||
osslsigncode 2.4, using:
|
|
||||||
OpenSSL 1.1.1k 25 Mar 2021 (Library: OpenSSL 1.1.1k 25 Mar 2021)
|
|
||||||
libcurl/7.78.0 OpenSSL/1.1.1k
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Building OpenSSL, Curl and osslsigncode sources with Microsoft Visual Studio:
|
5) Build 64-bit Windows executables.
|
||||||
|
```
|
||||||
|
cmake --build . --verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
6) Make tests.
|
||||||
|
```
|
||||||
|
ctest
|
||||||
|
```
|
||||||
|
|
||||||
|
### Building OpenSSL and osslsigncode sources with Microsoft Visual Studio:
|
||||||
|
|
||||||
1) Install and integrate vcpkg: https://vcpkg.io/en/getting-started.html
|
1) Install and integrate vcpkg: https://vcpkg.io/en/getting-started.html
|
||||||
|
|
||||||
|
47
NEWS.md
47
NEWS.md
@ -1,5 +1,52 @@
|
|||||||
# osslsigncode change log
|
# osslsigncode change log
|
||||||
|
|
||||||
|
### 2.10 (unreleased)
|
||||||
|
|
||||||
|
- added compatiblity with the CNG engine version 1.1 or later
|
||||||
|
- added the "-engineCtrl" option to control hardware and CNG engines
|
||||||
|
- improved unauthenticated blob support (thanks to Asger Hautop Drewsen)
|
||||||
|
- added the '-blobFile' option to specify a file containing the blob content
|
||||||
|
- added PKCS#11 provider support (requires OpenSSL 3.0)
|
||||||
|
|
||||||
|
### 2.9 (2024.06.29)
|
||||||
|
|
||||||
|
- added a 64 bit long pseudo-random NONCE in the TSA request
|
||||||
|
- missing NID_pkcs9_signingTime is no longer an error
|
||||||
|
- added support for PEM-encoded CRLs
|
||||||
|
- fixed the APPX central directory sorting order
|
||||||
|
- added a special "-" file name to read the passphrase from stdin
|
||||||
|
(by Steve McIntyre)
|
||||||
|
- used native HTTP client with OpenSSL 3.x, removing libcurl dependency
|
||||||
|
- added '-login' option to force a login to PKCS11 engines
|
||||||
|
(by Brad Hughes)
|
||||||
|
- added the "-ignore-crl" option to disable fetching and verifying
|
||||||
|
CRL Distribution Points
|
||||||
|
- changed error output to stderr instead of stdout
|
||||||
|
- various testing framework improvements
|
||||||
|
- various memory corruption fixes
|
||||||
|
|
||||||
|
### 2.8 (2024.03.03)
|
||||||
|
|
||||||
|
- Microsoft PowerShell signing sponsored by Cisco Systems, Inc.
|
||||||
|
- fixed setting unauthenticated attributes (Countersignature, Unauthenticated
|
||||||
|
Data Blob) in a nested signature
|
||||||
|
- added the "-index" option to verify a specific signature or modify its
|
||||||
|
unauthenticated attributes
|
||||||
|
- added CAT file verification
|
||||||
|
- added listing the contents of a CAT file with the "-verbose" option
|
||||||
|
- added the new "extract-data" command to extract a PKCS#7 data content to be
|
||||||
|
signed with "sign" and attached with "attach-signature"
|
||||||
|
- added PKCS9_SEQUENCE_NUMBER authenticated attribute support
|
||||||
|
- added the "-ignore-cdp" option to disable CRL Distribution Points (CDP)
|
||||||
|
online verification
|
||||||
|
- unsuccessful CRL retrieval and verification changed into a critical error
|
||||||
|
- the "-p" option modified to also use to configured proxy to connect CRL
|
||||||
|
Distribution Points
|
||||||
|
- added implicit allowlisting of the Microsoft Root Authority serial number
|
||||||
|
00C1008B3C3C8811D13EF663ECDF40
|
||||||
|
- added listing of certificate chain retrieved from the signature in case of
|
||||||
|
verification failure
|
||||||
|
|
||||||
### 2.7 (2023.09.19)
|
### 2.7 (2023.09.19)
|
||||||
|
|
||||||
- fixed signing CAB files (by Michael Brown)
|
- fixed signing CAB files (by Michael Brown)
|
||||||
|
40
README.md
40
README.md
@ -39,7 +39,7 @@ We highly recommend downloading a [release tarball](https://github.com/mtrojnar/
|
|||||||
|
|
||||||
* Install prerequisites on a Debian-based distributions, such as Ubuntu:
|
* Install prerequisites on a Debian-based distributions, such as Ubuntu:
|
||||||
```
|
```
|
||||||
sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev
|
sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev zlib1g-dev python3
|
||||||
```
|
```
|
||||||
* Install prerequisites on macOS with Homebrew:
|
* Install prerequisites on macOS with Homebrew:
|
||||||
```
|
```
|
||||||
@ -131,17 +131,51 @@ To sign a CAB file containing java class files:
|
|||||||
```
|
```
|
||||||
Only the 'low' parameter is currently supported.
|
Only the 'low' parameter is currently supported.
|
||||||
|
|
||||||
If you want to use PKCS11 token, you should indicate PKCS11 engine and module.
|
If you want to use a PKCS#11 token, you should specify the PKCS#11 engine and module.
|
||||||
An example of using osslsigncode with SoftHSM:
|
An example of using osslsigncode with SoftHSM:
|
||||||
```
|
```
|
||||||
osslsigncode sign \
|
osslsigncode sign \
|
||||||
-pkcs11engine /usr/lib64/engines-1.1/pkcs11.so \
|
-engine /usr/lib64/engines-1.1/pkcs11.so \
|
||||||
-pkcs11module /usr/lib64/pkcs11/libsofthsm2.so \
|
-pkcs11module /usr/lib64/pkcs11/libsofthsm2.so \
|
||||||
-pkcs11cert 'pkcs11:token=softhsm-token;object=cert' \
|
-pkcs11cert 'pkcs11:token=softhsm-token;object=cert' \
|
||||||
-key 'pkcs11:token=softhsm-token;object=key' \
|
-key 'pkcs11:token=softhsm-token;object=key' \
|
||||||
-in yourapp.exe -out yourapp-signed.exe
|
-in yourapp.exe -out yourapp-signed.exe
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Since OpenSSL 3.0, you can use a PKCS#11 token with the PKCS#11 provider.
|
||||||
|
An example of using osslsigncode with OpenSC:
|
||||||
|
```
|
||||||
|
osslsigncode sign \
|
||||||
|
-provider /usr/lib64/ossl-modules/pkcs11prov.so \
|
||||||
|
-pkcs11module /usr/lib64/opensc-pkcs11.so \
|
||||||
|
-pkcs11cert 'pkcs11:token=my-token;object=cert' \
|
||||||
|
-key 'pkcs11:token=my-token;object=key' \
|
||||||
|
-in yourapp.exe -out yourapp-signed.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
You can use a certificate and key stored in the Windows Certificate Store with
|
||||||
|
the CNG engine version 1.1 or later. For more information, refer to
|
||||||
|
|
||||||
|
https://www.stunnel.org/cng-engine.html
|
||||||
|
|
||||||
|
A non-commercial edition of CNG engine is available for testing, personal,
|
||||||
|
educational, or research purposes.
|
||||||
|
|
||||||
|
To use the CNG engine with osslsigncode, ensure that the `cng.dll` library is
|
||||||
|
placed in the same directory as the `osslsigncode.exe` executable.
|
||||||
|
|
||||||
|
Below is an example of how to use osslsigncode with the CNG engine:
|
||||||
|
```
|
||||||
|
osslsigncode sign \
|
||||||
|
-engine cng \
|
||||||
|
-pkcs11cert osslsigncode_cert \
|
||||||
|
-key osslsigncode_cert \
|
||||||
|
-engineCtrl store_flags:0 \
|
||||||
|
-engineCtrl store_name:MY \
|
||||||
|
-engineCtrl PIN:yourpass \
|
||||||
|
-in yourapp.exe -out yourapp-signed.exe
|
||||||
|
```
|
||||||
|
|
||||||
You can check that the signed file is correct by right-clicking
|
You can check that the signed file is correct by right-clicking
|
||||||
on it in Windows and choose Properties --> Digital Signatures,
|
on it in Windows and choose Properties --> Digital Signatures,
|
||||||
and then choose the signature from the list, and click on
|
and then choose the signature from the list, and click on
|
||||||
|
341
cab.c
341
cab.c
@ -43,32 +43,38 @@ struct cab_ctx_st {
|
|||||||
/* FILE_FORMAT method prototypes */
|
/* FILE_FORMAT method prototypes */
|
||||||
static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
static int cab_hash_length_get(FILE_FORMAT_CTX *ctx);
|
static int cab_hash_length_get(FILE_FORMAT_CTX *ctx);
|
||||||
static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
|
||||||
static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
||||||
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx);
|
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
|
||||||
static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||||
static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
static BIO *cab_bio_free(BIO *hash, BIO *outdata);
|
static void cab_bio_free(BIO *hash, BIO *outdata);
|
||||||
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx);
|
||||||
|
static int cab_is_detaching_supported(void);
|
||||||
|
|
||||||
FILE_FORMAT file_format_cab = {
|
FILE_FORMAT file_format_cab = {
|
||||||
.ctx_new = cab_ctx_new,
|
.ctx_new = cab_ctx_new,
|
||||||
.data_blob_get = cab_obsolete_link_get,
|
.data_blob_get = cab_obsolete_link_get,
|
||||||
|
.pkcs7_contents_get = cab_pkcs7_contents_get,
|
||||||
.hash_length_get = cab_hash_length_get,
|
.hash_length_get = cab_hash_length_get,
|
||||||
.check_file = cab_check_file,
|
|
||||||
.digest_calc = cab_digest_calc,
|
.digest_calc = cab_digest_calc,
|
||||||
.verify_digests = cab_verify_digests,
|
.verify_digests = cab_verify_digests,
|
||||||
.pkcs7_extract = cab_pkcs7_extract,
|
.pkcs7_extract = cab_pkcs7_extract,
|
||||||
|
.pkcs7_extract_to_nest = cab_pkcs7_extract_to_nest,
|
||||||
.remove_pkcs7 = cab_remove_pkcs7,
|
.remove_pkcs7 = cab_remove_pkcs7,
|
||||||
.pkcs7_prepare = cab_pkcs7_prepare,
|
.process_data = cab_process_data,
|
||||||
|
.pkcs7_signature_new = cab_pkcs7_signature_new,
|
||||||
.append_pkcs7 = cab_append_pkcs7,
|
.append_pkcs7 = cab_append_pkcs7,
|
||||||
.update_data_size = cab_update_data_size,
|
.update_data_size = cab_update_data_size,
|
||||||
.bio_free = cab_bio_free,
|
.bio_free = cab_bio_free,
|
||||||
.ctx_cleanup = cab_ctx_cleanup
|
.ctx_cleanup = cab_ctx_cleanup,
|
||||||
|
.is_detaching_supported = cab_is_detaching_supported
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
@ -77,6 +83,7 @@ static int cab_add_jp_attribute(PKCS7 *p7, int jp);
|
|||||||
static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t len, uint16_t flags);
|
static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t len, uint16_t flags);
|
||||||
static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
static int cab_check_file(FILE_FORMAT_CTX *ctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FILE_FORMAT method definitions
|
* FILE_FORMAT method definitions
|
||||||
@ -104,12 +111,12 @@ static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (memcmp(options->indata, "MSCF", 4)) {
|
if (memcmp(options->indata, "MSCF", 4)) {
|
||||||
unmap_file(options->infile, filesize);
|
unmap_file(options->indata, filesize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
cab_ctx = cab_ctx_get(options->indata, filesize);
|
cab_ctx = cab_ctx_get(options->indata, filesize);
|
||||||
if (!cab_ctx) {
|
if (!cab_ctx) {
|
||||||
unmap_file(options->infile, filesize);
|
unmap_file(options->indata, filesize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
||||||
@ -151,6 +158,32 @@ static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX
|
|||||||
return dtype; /* OK */
|
return dtype; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a data content to be signed.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] data content
|
||||||
|
*/
|
||||||
|
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
|
||||||
|
/* squash the unused parameter warning, use initialized message digest BIO */
|
||||||
|
(void)md;
|
||||||
|
|
||||||
|
/* Strip current signature and modify header */
|
||||||
|
if (ctx->cab_ctx->header_size == 20) {
|
||||||
|
if (!cab_modify_header(ctx, hash, NULL))
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
} else {
|
||||||
|
if (!cab_add_header(ctx, hash, NULL))
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
|
return pkcs7_set_content(content);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
||||||
@ -160,34 +193,6 @@ static int cab_hash_length_get(FILE_FORMAT_CTX *ctx)
|
|||||||
return EVP_MD_size(ctx->options->md);
|
return EVP_MD_size(ctx->options->md);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Check if the signature exists.
|
|
||||||
* [in, out] ctx: structure holds input and output data
|
|
||||||
* [in] detached: embedded/detached PKCS#7 signature switch
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
|
||||||
static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached)
|
|
||||||
{
|
|
||||||
if (!ctx) {
|
|
||||||
printf("Init error\n\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
if (detached) {
|
|
||||||
printf("Checking the specified catalog file\n\n");
|
|
||||||
return 1; /* OK */
|
|
||||||
}
|
|
||||||
if (ctx->cab_ctx->header_size != 20) {
|
|
||||||
printf("No signature found\n\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|
|
||||||
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
|
|
||||||
printf("No signature found\n\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
return 1; /* OK */
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute a message digest value of the signed or unsigned CAB file.
|
* Compute a message digest value of the signed or unsigned CAB file.
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
@ -201,7 +206,7 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
|||||||
BIO *bhash = BIO_new(BIO_f_md());
|
BIO *bhash = BIO_new(BIO_f_md());
|
||||||
|
|
||||||
if (!BIO_set_md(bhash, md)) {
|
if (!BIO_set_md(bhash, md)) {
|
||||||
printf("Unable to set the message digest of BIO\n");
|
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||||
BIO_free_all(bhash);
|
BIO_free_all(bhash);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -291,7 +296,7 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
|||||||
nfolders--;
|
nfolders--;
|
||||||
}
|
}
|
||||||
if (idx != coffFiles) {
|
if (idx != coffFiles) {
|
||||||
printf("Corrupt coffFiles value: 0x%08X\n", coffFiles);
|
fprintf(stderr, "Corrupt coffFiles value: 0x%08X\n", coffFiles);
|
||||||
BIO_free_all(bhash);
|
BIO_free_all(bhash);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -302,7 +307,7 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
|||||||
}
|
}
|
||||||
/* (variable) ab - the compressed data bytes */
|
/* (variable) ab - the compressed data bytes */
|
||||||
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
|
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
|
||||||
printf("Unable to calculate digest\n");
|
fprintf(stderr, "Unable to calculate digest\n");
|
||||||
BIO_free_all(bhash);
|
BIO_free_all(bhash);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -338,17 +343,17 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mdtype == -1) {
|
if (mdtype == -1) {
|
||||||
printf("Failed to extract current message digest\n\n");
|
fprintf(stderr, "Failed to extract current message digest\n\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
md = EVP_get_digestbynid(mdtype);
|
md = EVP_get_digestbynid(mdtype);
|
||||||
cmdbuf = cab_digest_calc(ctx, md);
|
cmdbuf = cab_digest_calc(ctx, md);
|
||||||
if (!cmdbuf) {
|
if (!cmdbuf) {
|
||||||
printf("Failed to calculate message digest\n\n");
|
fprintf(stderr, "Failed to calculate message digest\n\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
|
if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
|
||||||
printf("Signature verification: failed\n\n");
|
fprintf(stderr, "Signature verification: failed\n\n");
|
||||||
OPENSSL_free(cmdbuf);
|
OPENSSL_free(cmdbuf);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -363,11 +368,23 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
|||||||
*/
|
*/
|
||||||
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|
const u_char *blob;
|
||||||
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
|
|
||||||
|
if (!cab_check_file(ctx)) {
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
return pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen);
|
blob = (u_char *)ctx->options->indata + ctx->cab_ctx->sigpos;
|
||||||
|
return d2i_PKCS7(NULL, &blob, ctx->cab_ctx->siglen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract existing signature in DER format.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* pointer to PKCS#7 structure
|
||||||
|
*/
|
||||||
|
static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
return cab_pkcs7_extract(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -379,14 +396,18 @@ static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
|||||||
*/
|
*/
|
||||||
static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
size_t i, written, len;
|
size_t idx, written, len;
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
uint16_t nfolders, flags;
|
uint16_t nfolders, flags;
|
||||||
char *buf = OPENSSL_malloc(SIZE_64K);
|
char *buf;
|
||||||
|
|
||||||
/* squash the unused parameter warning */
|
/* squash the unused parameter warning */
|
||||||
(void)hash;
|
(void)hash;
|
||||||
|
|
||||||
|
if (!cab_check_file(ctx)) {
|
||||||
|
return 1; /* FAILED, no signature */
|
||||||
|
}
|
||||||
|
buf = OPENSSL_malloc(SIZE_64K);
|
||||||
/*
|
/*
|
||||||
* u1 signature[4] 4643534D MSCF: 0-3
|
* u1 signature[4] 4643534D MSCF: 0-3
|
||||||
* u4 reserved1 00000000: 4-7
|
* u4 reserved1 00000000: 4-7
|
||||||
@ -420,92 +441,100 @@ static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
* u2 iCabinet - number of this cabinet file in a set: 34-35
|
* u2 iCabinet - number of this cabinet file in a set: 34-35
|
||||||
*/
|
*/
|
||||||
BIO_write(outdata, ctx->options->indata + 32, 4);
|
BIO_write(outdata, ctx->options->indata + 32, 4);
|
||||||
i = cab_write_optional_names(outdata, ctx->options->indata, 60, flags);
|
idx = cab_write_optional_names(outdata, ctx->options->indata, 60, flags);
|
||||||
|
if (idx >= ctx->cab_ctx->fileend) {
|
||||||
|
fprintf(stderr, "Corrupt CAB file - too short\n");
|
||||||
|
OPENSSL_free(buf);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* (u8 * cFolders) CFFOLDER - structure contains information about
|
* (u8 * cFolders) CFFOLDER - structure contains information about
|
||||||
* one of the folders or partial folders stored in this cabinet file
|
* one of the folders or partial folders stored in this cabinet file
|
||||||
*/
|
*/
|
||||||
nfolders = GET_UINT16_LE(ctx->options->indata + 26);
|
nfolders = GET_UINT16_LE(ctx->options->indata + 26);
|
||||||
|
if (nfolders * 8 >= ctx->cab_ctx->fileend - idx) {
|
||||||
|
fprintf(stderr, "Corrupt cFolders value: 0x%08X\n", nfolders);
|
||||||
|
OPENSSL_free(buf);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
while (nfolders) {
|
while (nfolders) {
|
||||||
tmp = GET_UINT32_LE(ctx->options->indata + i);
|
tmp = GET_UINT32_LE(ctx->options->indata + idx);
|
||||||
tmp -= 24;
|
tmp -= 24;
|
||||||
PUT_UINT32_LE(tmp, buf);
|
PUT_UINT32_LE(tmp, buf);
|
||||||
BIO_write(outdata, buf, 4);
|
BIO_write(outdata, buf, 4);
|
||||||
BIO_write(outdata, ctx->options->indata + i + 4, 4);
|
BIO_write(outdata, ctx->options->indata + idx + 4, 4);
|
||||||
i+=8;
|
idx += 8;
|
||||||
nfolders--;
|
nfolders--;
|
||||||
}
|
}
|
||||||
OPENSSL_free(buf);
|
OPENSSL_free(buf);
|
||||||
/* Write what's left - the compressed data bytes */
|
/* Write what's left - the compressed data bytes */
|
||||||
len = ctx->cab_ctx->fileend - ctx->cab_ctx->siglen - i;
|
len = ctx->cab_ctx->fileend - ctx->cab_ctx->siglen - idx;
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
if (!BIO_write_ex(outdata, ctx->options->indata + i, len, &written))
|
if (!BIO_write_ex(outdata, ctx->options->indata + idx, len, &written))
|
||||||
return 1; /* FAILED */
|
return 1; /* FAILED */
|
||||||
len -= written;
|
len -= written;
|
||||||
i += written;
|
idx += written;
|
||||||
}
|
}
|
||||||
return 0; /* OK */
|
return 0; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain an existing signature or create a new one.
|
* Modify specific type data and calculate a hash (message digest) of data.
|
||||||
* [in, out] ctx: structure holds input and output data
|
* [in, out] ctx: structure holds input and output data
|
||||||
* [out] hash: message digest BIO
|
* [out] hash: message digest BIO
|
||||||
* [out] outdata: outdata file BIO
|
* [out] outdata: outdata file BIO
|
||||||
* [returns] pointer to PKCS#7 structure
|
* [returns] 1 on error or 0 on success
|
||||||
*/
|
*/
|
||||||
static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
PKCS7 *cursig = NULL, *p7 = NULL;
|
|
||||||
|
|
||||||
/* Strip current signature and modify header */
|
/* Strip current signature and modify header */
|
||||||
if (ctx->cab_ctx->header_size == 20) {
|
if (ctx->cab_ctx->header_size == 20) {
|
||||||
if (!cab_modify_header(ctx, hash, outdata))
|
if (!cab_modify_header(ctx, hash, outdata))
|
||||||
return NULL; /* FAILED */
|
return 0; /* FAILED */
|
||||||
} else {
|
} else {
|
||||||
if (!cab_add_header(ctx, hash, outdata))
|
if (!cab_add_header(ctx, hash, outdata))
|
||||||
return NULL; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
/* Obtain a current signature from previously-signed file */
|
return 1; /* OK */
|
||||||
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest)
|
}
|
||||||
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|
|
||||||
|| ctx->options->cmd == CMD_ADD) {
|
/*
|
||||||
cursig = pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen);
|
* Create a new PKCS#7 signature.
|
||||||
if (!cursig) {
|
* [in, out] ctx: structure holds input and output data
|
||||||
printf("Unable to extract existing signature\n");
|
* [out] hash: message digest BIO
|
||||||
return NULL; /* FAILED */
|
* [returns] pointer to PKCS#7 structure
|
||||||
}
|
*/
|
||||||
if (ctx->options->cmd == CMD_ADD)
|
static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||||
p7 = cursig;
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
PKCS7 *p7 = pkcs7_create(ctx);
|
||||||
|
|
||||||
|
if (!p7) {
|
||||||
|
fprintf(stderr, "Creating a new signature failed\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (ctx->options->cmd == CMD_ATTACH) {
|
if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) {
|
||||||
/* Obtain an existing PKCS#7 signature */
|
fprintf(stderr, "Adding jp attribute failed\n");
|
||||||
p7 = pkcs7_get_sigfile(ctx);
|
PKCS7_free(p7);
|
||||||
if (!p7) {
|
return NULL; /* FAILED */
|
||||||
printf("Unable to extract valid signature\n");
|
|
||||||
PKCS7_free(cursig);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
|
||||||
/* Create a new PKCS#7 signature */
|
|
||||||
p7 = pkcs7_create(ctx);
|
|
||||||
if (!p7) {
|
|
||||||
printf("Creating a new signature failed\n");
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
if (ctx->options->jp >= 0 && !cab_add_jp_attribute(p7, ctx->options->jp)) {
|
|
||||||
printf("Adding jp attribute failed\n");
|
|
||||||
PKCS7_free(p7);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
if (!add_indirect_data_object(p7, hash, ctx)) {
|
|
||||||
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
|
||||||
PKCS7_free(p7);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
if (!add_indirect_data_object(p7)) {
|
||||||
ctx->options->prevsig = cursig;
|
fprintf(stderr, "Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
|
if (!content) {
|
||||||
|
fprintf(stderr, "Failed to get spcIndirectDataContent\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!sign_spc_indirect_data_content(p7, content)) {
|
||||||
|
fprintf(stderr, "Failed to set signed content\n");
|
||||||
|
PKCS7_free(p7);
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
return p7;
|
return p7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -527,7 +556,7 @@ static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
|||||||
|
|
||||||
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|
||||||
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
||||||
printf("i2d_PKCS memory allocation failed: %d\n", len);
|
fprintf(stderr, "i2d_PKCS memory allocation failed: %d\n", len);
|
||||||
return 1; /* FAILED */
|
return 1; /* FAILED */
|
||||||
}
|
}
|
||||||
i2d_PKCS7(p7, &p);
|
i2d_PKCS7(p7, &p);
|
||||||
@ -580,40 +609,33 @@ static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
|||||||
* [out] outdata: outdata file BIO (unused)
|
* [out] outdata: outdata file BIO (unused)
|
||||||
* [returns] none
|
* [returns] none
|
||||||
*/
|
*/
|
||||||
static BIO *cab_bio_free(BIO *hash, BIO *outdata)
|
static void cab_bio_free(BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
/* squash the unused parameter warning */
|
/* squash the unused parameter warning */
|
||||||
(void)outdata;
|
(void)outdata;
|
||||||
|
|
||||||
BIO_free_all(hash);
|
BIO_free_all(hash);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocate a FILE_FORMAT_CTX structure and CAB format specific structure,
|
* Deallocate a FILE_FORMAT_CTX structure and CAB format specific structure,
|
||||||
* unmap indata file, unlink outfile.
|
* unmap indata file.
|
||||||
* [in, out] ctx: structure holds input and output data
|
* [in, out] ctx: structure holds input and output data
|
||||||
* [out] hash: message digest BIO
|
* [out] hash: message digest BIO
|
||||||
* [in] outdata: outdata file BIO
|
* [in] outdata: outdata file BIO
|
||||||
* [returns] none
|
* [returns] none
|
||||||
*/
|
*/
|
||||||
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
if (outdata) {
|
|
||||||
BIO_free_all(hash);
|
|
||||||
if (ctx->options->outfile) {
|
|
||||||
#ifdef WIN32
|
|
||||||
_unlink(ctx->options->outfile);
|
|
||||||
#else
|
|
||||||
unlink(ctx->options->outfile);
|
|
||||||
#endif /* WIN32 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unmap_file(ctx->options->indata, ctx->cab_ctx->fileend);
|
unmap_file(ctx->options->indata, ctx->cab_ctx->fileend);
|
||||||
OPENSSL_free(ctx->cab_ctx);
|
OPENSSL_free(ctx->cab_ctx);
|
||||||
OPENSSL_free(ctx);
|
OPENSSL_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int cab_is_detaching_supported(void)
|
||||||
|
{
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* CAB helper functions
|
* CAB helper functions
|
||||||
*/
|
*/
|
||||||
@ -631,19 +653,19 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
|
|||||||
uint16_t flags;
|
uint16_t flags;
|
||||||
|
|
||||||
if (filesize < 44) {
|
if (filesize < 44) {
|
||||||
printf("CAB file is too short\n");
|
fprintf(stderr, "CAB file is too short\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
reserved = GET_UINT32_LE(indata + 4);
|
reserved = GET_UINT32_LE(indata + 4);
|
||||||
if (reserved) {
|
if (reserved) {
|
||||||
printf("Reserved1: 0x%08X\n", reserved);
|
fprintf(stderr, "Reserved1: 0x%08X\n", reserved);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* flags specify bit-mapped values that indicate the presence of optional data */
|
/* flags specify bit-mapped values that indicate the presence of optional data */
|
||||||
flags = GET_UINT16_LE(indata + 30);
|
flags = GET_UINT16_LE(indata + 30);
|
||||||
if (flags & FLAG_PREV_CABINET) {
|
if (flags & FLAG_PREV_CABINET) {
|
||||||
/* FLAG_NEXT_CABINET works */
|
/* FLAG_NEXT_CABINET works */
|
||||||
printf("Multivolume cabinet file is unsupported: flags 0x%04X\n", flags);
|
fprintf(stderr, "Multivolume cabinet file is unsupported: flags 0x%04X\n", flags);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (flags & FLAG_RESERVE_PRESENT) {
|
if (flags & FLAG_RESERVE_PRESENT) {
|
||||||
@ -653,12 +675,12 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
|
|||||||
*/
|
*/
|
||||||
header_size = GET_UINT32_LE(indata + 36);
|
header_size = GET_UINT32_LE(indata + 36);
|
||||||
if (header_size != 20) {
|
if (header_size != 20) {
|
||||||
printf("Additional header size: 0x%08X\n", header_size);
|
fprintf(stderr, "Additional header size: 0x%08X\n", header_size);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
reserved = GET_UINT32_LE(indata + 40);
|
reserved = GET_UINT32_LE(indata + 40);
|
||||||
if (reserved != 0x00100000) {
|
if (reserved != 0x00100000) {
|
||||||
printf("abReserved: 0x%08X\n", reserved);
|
fprintf(stderr, "abReserved: 0x%08X\n", reserved);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -673,13 +695,13 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
|
|||||||
sigpos = GET_UINT32_LE(indata + 44);
|
sigpos = GET_UINT32_LE(indata + 44);
|
||||||
siglen = GET_UINT32_LE(indata + 48);
|
siglen = GET_UINT32_LE(indata + 48);
|
||||||
if ((sigpos < filesize && sigpos + siglen != filesize) || (sigpos >= filesize)) {
|
if ((sigpos < filesize && sigpos + siglen != filesize) || (sigpos >= filesize)) {
|
||||||
printf("Additional data offset:\t%u bytes\nAdditional data size:\t%u bytes\n",
|
fprintf(stderr, "Additional data offset:\t%u bytes\nAdditional data size:\t%u bytes\n",
|
||||||
sigpos, siglen);
|
sigpos, siglen);
|
||||||
printf("File size:\t\t%u bytes\n", filesize);
|
fprintf(stderr, "File size:\t\t%u bytes\n", filesize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) {
|
if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) {
|
||||||
printf("Corrupt signature\n");
|
fprintf(stderr, "Corrupt signature\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -790,7 +812,7 @@ static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t i, uin
|
|||||||
*/
|
*/
|
||||||
static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
size_t i, written, len;
|
size_t idx, written, len;
|
||||||
uint16_t nfolders, flags;
|
uint16_t nfolders, flags;
|
||||||
u_char buf[] = {0x00, 0x00};
|
u_char buf[] = {0x00, 0x00};
|
||||||
|
|
||||||
@ -828,24 +850,32 @@ static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
/* u4 abReserve: 56-59 */
|
/* u4 abReserve: 56-59 */
|
||||||
BIO_write(hash, ctx->options->indata + 56, 4);
|
BIO_write(hash, ctx->options->indata + 56, 4);
|
||||||
|
|
||||||
i = cab_write_optional_names(outdata, ctx->options->indata, 60, flags);
|
idx = cab_write_optional_names(outdata, ctx->options->indata, 60, flags);
|
||||||
|
if (idx >= ctx->cab_ctx->fileend) {
|
||||||
|
fprintf(stderr, "Corrupt CAB file - too short\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* (u8 * cFolders) CFFOLDER - structure contains information about
|
* (u8 * cFolders) CFFOLDER - structure contains information about
|
||||||
* one of the folders or partial folders stored in this cabinet file
|
* one of the folders or partial folders stored in this cabinet file
|
||||||
*/
|
*/
|
||||||
nfolders = GET_UINT16_LE(ctx->options->indata + 26);
|
nfolders = GET_UINT16_LE(ctx->options->indata + 26);
|
||||||
|
if (nfolders * 8 >= ctx->cab_ctx->fileend - idx) {
|
||||||
|
fprintf(stderr, "Corrupt cFolders value: 0x%08X\n", nfolders);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
while (nfolders) {
|
while (nfolders) {
|
||||||
BIO_write(hash, ctx->options->indata + i, 8);
|
BIO_write(hash, ctx->options->indata + idx, 8);
|
||||||
i += 8;
|
idx += 8;
|
||||||
nfolders--;
|
nfolders--;
|
||||||
}
|
}
|
||||||
/* Write what's left - the compressed data bytes */
|
/* Write what's left - the compressed data bytes */
|
||||||
len = ctx->cab_ctx->sigpos - i;
|
len = ctx->cab_ctx->sigpos - idx;
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
if (!BIO_write_ex(hash, ctx->options->indata + i, len, &written))
|
if (!BIO_write_ex(hash, ctx->options->indata + idx, len, &written))
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
len -= written;
|
len -= written;
|
||||||
i += written;
|
idx += written;
|
||||||
}
|
}
|
||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
@ -859,7 +889,7 @@ static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
*/
|
*/
|
||||||
static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
size_t i, written, len;
|
size_t idx, written, len;
|
||||||
uint32_t tmp;
|
uint32_t tmp;
|
||||||
uint16_t nfolders, flags;
|
uint16_t nfolders, flags;
|
||||||
u_char cabsigned[] = {
|
u_char cabsigned[] = {
|
||||||
@ -904,29 +934,62 @@ static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
BIO_write(outdata, cabsigned, 20);
|
BIO_write(outdata, cabsigned, 20);
|
||||||
BIO_write(hash, cabsigned+20, 4);
|
BIO_write(hash, cabsigned+20, 4);
|
||||||
|
|
||||||
i = cab_write_optional_names(outdata, ctx->options->indata, 36, flags);
|
idx = cab_write_optional_names(outdata, ctx->options->indata, 36, flags);
|
||||||
|
if (idx >= ctx->cab_ctx->fileend) {
|
||||||
|
fprintf(stderr, "Corrupt CAB file - too short\n");
|
||||||
|
OPENSSL_free(buf);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* (u8 * cFolders) CFFOLDER - structure contains information about
|
* (u8 * cFolders) CFFOLDER - structure contains information about
|
||||||
* one of the folders or partial folders stored in this cabinet file
|
* one of the folders or partial folders stored in this cabinet file
|
||||||
*/
|
*/
|
||||||
nfolders = GET_UINT16_LE(ctx->options->indata + 26);
|
nfolders = GET_UINT16_LE(ctx->options->indata + 26);
|
||||||
|
if (nfolders * 8 >= ctx->cab_ctx->fileend - idx) {
|
||||||
|
fprintf(stderr, "Corrupt cFolders value: 0x%08X\n", nfolders);
|
||||||
|
OPENSSL_free(buf);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
while (nfolders) {
|
while (nfolders) {
|
||||||
tmp = GET_UINT32_LE(ctx->options->indata + i);
|
tmp = GET_UINT32_LE(ctx->options->indata + idx);
|
||||||
tmp += 24;
|
tmp += 24;
|
||||||
PUT_UINT32_LE(tmp, buf);
|
PUT_UINT32_LE(tmp, buf);
|
||||||
BIO_write(hash, buf, 4);
|
BIO_write(hash, buf, 4);
|
||||||
BIO_write(hash, ctx->options->indata + i + 4, 4);
|
BIO_write(hash, ctx->options->indata + idx + 4, 4);
|
||||||
i += 8;
|
idx += 8;
|
||||||
nfolders--;
|
nfolders--;
|
||||||
}
|
}
|
||||||
OPENSSL_free(buf);
|
OPENSSL_free(buf);
|
||||||
/* Write what's left - the compressed data bytes */
|
/* Write what's left - the compressed data bytes */
|
||||||
len = ctx->cab_ctx->fileend - i;
|
len = ctx->cab_ctx->fileend - idx;
|
||||||
while (len > 0) {
|
while (len > 0) {
|
||||||
if (!BIO_write_ex(hash, ctx->options->indata + i, len, &written))
|
if (!BIO_write_ex(hash, ctx->options->indata + idx, len, &written))
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
len -= written;
|
len -= written;
|
||||||
i += written;
|
idx += written;
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the signature exists.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cab_check_file(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
fprintf(stderr, "Init error\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (ctx->cab_ctx->header_size != 20) {
|
||||||
|
fprintf(stderr, "No signature found\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|
||||||
|
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
|
||||||
|
fprintf(stderr, "No signature found\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
428
cat.c
428
cat.c
@ -5,34 +5,49 @@
|
|||||||
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
|
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
|
||||||
*
|
*
|
||||||
* Catalog files are a bit odd, in that they are only a PKCS7 blob.
|
* Catalog files are a bit odd, in that they are only a PKCS7 blob.
|
||||||
|
* CAT files do not support nesting (multiple signature)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "osslsigncode.h"
|
#include "osslsigncode.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
const u_char pkcs7_signed_data[] = {
|
typedef struct {
|
||||||
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
ASN1_BMPSTRING *tag;
|
||||||
0x01, 0x07, 0x02,
|
ASN1_INTEGER *flags;
|
||||||
};
|
ASN1_OCTET_STRING *value;
|
||||||
|
} CatNameValueContent;
|
||||||
|
|
||||||
|
DECLARE_ASN1_FUNCTIONS(CatNameValueContent)
|
||||||
|
|
||||||
|
ASN1_SEQUENCE(CatNameValueContent) = {
|
||||||
|
ASN1_SIMPLE(CatNameValueContent, tag, ASN1_BMPSTRING),
|
||||||
|
ASN1_SIMPLE(CatNameValueContent, flags, ASN1_INTEGER),
|
||||||
|
ASN1_SIMPLE(CatNameValueContent, value, ASN1_OCTET_STRING)
|
||||||
|
} ASN1_SEQUENCE_END(CatNameValueContent)
|
||||||
|
|
||||||
|
IMPLEMENT_ASN1_FUNCTIONS(CatNameValueContent)
|
||||||
|
|
||||||
struct cat_ctx_st {
|
struct cat_ctx_st {
|
||||||
uint32_t sigpos;
|
uint32_t sigpos;
|
||||||
uint32_t siglen;
|
uint32_t siglen;
|
||||||
uint32_t fileend;
|
uint32_t fileend;
|
||||||
|
PKCS7 *p7;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FILE_FORMAT method prototypes */
|
/* FILE_FORMAT method prototypes */
|
||||||
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
|
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
||||||
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx);
|
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx);
|
||||||
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||||
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
static BIO *cat_bio_free(BIO *hash, BIO *outdata);
|
static void cat_bio_free(BIO *hash, BIO *outdata);
|
||||||
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx);
|
||||||
|
|
||||||
FILE_FORMAT file_format_cat = {
|
FILE_FORMAT file_format_cat = {
|
||||||
.ctx_new = cat_ctx_new,
|
.ctx_new = cat_ctx_new,
|
||||||
|
.verify_digests = cat_verify_digests,
|
||||||
.pkcs7_extract = cat_pkcs7_extract,
|
.pkcs7_extract = cat_pkcs7_extract,
|
||||||
.pkcs7_prepare = cat_pkcs7_prepare,
|
.pkcs7_signature_new = cat_pkcs7_signature_new,
|
||||||
.append_pkcs7 = cat_append_pkcs7,
|
.append_pkcs7 = cat_append_pkcs7,
|
||||||
.bio_free = cat_bio_free,
|
.bio_free = cat_bio_free,
|
||||||
.ctx_cleanup = cat_ctx_cleanup,
|
.ctx_cleanup = cat_ctx_cleanup,
|
||||||
@ -40,6 +55,14 @@ FILE_FORMAT file_format_cat = {
|
|||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
|
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
|
||||||
|
static int cat_add_content_type(PKCS7 *p7, PKCS7 *cursig);
|
||||||
|
static int cat_sign_content(PKCS7 *p7, PKCS7 *contents);
|
||||||
|
static int cat_list_content(PKCS7 *p7);
|
||||||
|
static int cat_print_content_member_digest(ASN1_TYPE *content);
|
||||||
|
static int cat_print_content_member_name(ASN1_TYPE *content);
|
||||||
|
static void cat_print_base64(ASN1_OCTET_STRING *value);
|
||||||
|
static void cat_print_utf16_as_ascii(ASN1_OCTET_STRING *value);
|
||||||
|
static int cat_check_file(FILE_FORMAT_CTX *ctx);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FILE_FORMAT method definitions
|
* FILE_FORMAT method definitions
|
||||||
@ -58,16 +81,8 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
CAT_CTX *cat_ctx;
|
CAT_CTX *cat_ctx;
|
||||||
uint32_t filesize;
|
uint32_t filesize;
|
||||||
|
|
||||||
/* squash unused parameter warnings */
|
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH || options->cmd == CMD_EXTRACT_DATA) {
|
||||||
(void)outdata;
|
fprintf(stderr, "Unsupported command\n");
|
||||||
(void)hash;
|
|
||||||
|
|
||||||
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH) {
|
|
||||||
printf("Unsupported command\n");
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
if (options->cmd == CMD_VERIFY) {
|
|
||||||
printf("Use -catalog option\n");
|
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
filesize = get_file_size(options->infile);
|
filesize = get_file_size(options->infile);
|
||||||
@ -78,15 +93,9 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
if (!options->indata) {
|
if (!options->indata) {
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* the maximum size of a supported cat file is (2^24 -1) bytes */
|
|
||||||
if (memcmp(options->indata + ((GET_UINT8_LE(options->indata+1) == 0x82) ? 4 : 5),
|
|
||||||
pkcs7_signed_data, sizeof pkcs7_signed_data)) {
|
|
||||||
unmap_file(options->infile, filesize);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
cat_ctx = cat_ctx_get(options->indata, filesize);
|
cat_ctx = cat_ctx_get(options->indata, filesize);
|
||||||
if (!cat_ctx) {
|
if (!cat_ctx) {
|
||||||
unmap_file(options->infile, filesize);
|
unmap_file(options->indata, filesize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
||||||
@ -97,9 +106,8 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
/* Push hash on outdata, if hash is NULL the function does nothing */
|
/* Push hash on outdata, if hash is NULL the function does nothing */
|
||||||
BIO_push(hash, outdata);
|
BIO_push(hash, outdata);
|
||||||
|
|
||||||
if (options->nest)
|
if (options->cmd == CMD_VERIFY)
|
||||||
/* I've not tried using set_nested_signature as signtool won't do this */
|
printf("Warning: Use -catalog option to verify that a file, listed in catalog file, is signed\n");
|
||||||
printf("Warning: CAT files do not support nesting (multiple signature)\n");
|
|
||||||
if (options->jp >= 0)
|
if (options->jp >= 0)
|
||||||
printf("Warning: -jp option is only valid for CAB files\n");
|
printf("Warning: -jp option is only valid for CAB files\n");
|
||||||
if (options->pagehash == 1)
|
if (options->pagehash == 1)
|
||||||
@ -109,6 +117,19 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ContentInfo value is the inner content of pkcs7-signedData.
|
||||||
|
* An extra verification is not necessary when a content type data
|
||||||
|
* is the inner content of the signed-data type.
|
||||||
|
*/
|
||||||
|
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
||||||
|
{
|
||||||
|
/* squash unused parameter warnings */
|
||||||
|
(void)ctx;
|
||||||
|
(void)p7;
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Extract existing signature in DER format.
|
* Extract existing signature in DER format.
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
@ -116,76 +137,58 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
|
|||||||
*/
|
*/
|
||||||
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
return pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen);
|
if (!cat_check_file(ctx)) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
return PKCS7_dup(ctx->cat_ctx->p7);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain an existing signature or create a new one.
|
* Create a new PKCS#7 signature.
|
||||||
* [in, out] ctx: structure holds input and output data
|
* [in, out] ctx: structure holds input and output data
|
||||||
* [out] hash: message digest BIO (unused)
|
* [out] hash: message digest BIO (unused)
|
||||||
* [out] outdata: outdata file BIO (unused)
|
|
||||||
* [returns] pointer to PKCS#7 structure
|
* [returns] pointer to PKCS#7 structure
|
||||||
*/
|
*/
|
||||||
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||||
{
|
{
|
||||||
PKCS7 *cursig = NULL, *p7 = NULL;
|
PKCS7 *p7 = NULL;
|
||||||
|
|
||||||
/* squash unused parameter warnings */
|
/* squash unused parameter warnings */
|
||||||
(void)outdata;
|
|
||||||
(void)hash;
|
(void)hash;
|
||||||
|
|
||||||
/* Obtain an existing signature */
|
p7 = pkcs7_create(ctx);
|
||||||
cursig = pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen);
|
if (!p7) {
|
||||||
if (!cursig) {
|
fprintf(stderr, "Creating a new signature failed\n");
|
||||||
printf("Unable to extract existing signature\n");
|
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) {
|
if (!ctx->cat_ctx->p7 || !ctx->cat_ctx->p7->d.sign || !ctx->cat_ctx->p7->d.sign->contents) {
|
||||||
p7 = cursig;
|
fprintf(stderr, "Failed to get content\n");
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
PKCS7_free(p7);
|
||||||
/* Create a new signature */
|
return NULL; /* FAILED */
|
||||||
p7 = pkcs7_create(ctx);
|
}
|
||||||
if (!p7) {
|
if (!cat_add_content_type(p7, ctx->cat_ctx->p7)) {
|
||||||
printf("Creating a new signature failed\n");
|
fprintf(stderr, "Adding content type failed\n");
|
||||||
PKCS7_free(cursig);
|
PKCS7_free(p7);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!add_ms_ctl_object(p7, cursig)) {
|
if (!cat_sign_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
|
||||||
printf("Adding MS_CTL_OBJID failed\n");
|
fprintf(stderr, "Failed to set signed content\n");
|
||||||
PKCS7_free(p7);
|
PKCS7_free(p7);
|
||||||
PKCS7_free(cursig);
|
return NULL; /* FAILED */
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
PKCS7_free(cursig);
|
|
||||||
}
|
}
|
||||||
return p7; /* OK */
|
return p7; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Append signature to the outfile.
|
* Append signature to the outfile.
|
||||||
* [in, out] ctx: structure holds input and output data (unused)
|
* [in, out] ctx: structure holds input and output data
|
||||||
* [out] outdata: outdata file BIO
|
* [out] outdata: outdata file BIO
|
||||||
* [in] p7: PKCS#7 signature
|
* [in] p7: PKCS#7 signature
|
||||||
* [returns] 1 on error or 0 on success
|
* [returns] 1 on error or 0 on success
|
||||||
*/
|
*/
|
||||||
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||||
{
|
{
|
||||||
u_char *p = NULL;
|
return data_write_pkcs7(ctx, outdata, p7);
|
||||||
int len; /* signature length */
|
|
||||||
|
|
||||||
/* squash the unused parameter warning */
|
|
||||||
(void)ctx;
|
|
||||||
|
|
||||||
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|
|
||||||
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
|
||||||
printf("i2d_PKCS memory allocation failed: %d\n", len);
|
|
||||||
return 1; /* FAILED */
|
|
||||||
}
|
|
||||||
i2d_PKCS7(p7, &p);
|
|
||||||
p -= len;
|
|
||||||
i2d_PKCS7_bio(outdata, p7);
|
|
||||||
OPENSSL_free(p);
|
|
||||||
return 0; /* OK */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -194,36 +197,25 @@ static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
|||||||
* [out] outdata: outdata file BIO (unused)
|
* [out] outdata: outdata file BIO (unused)
|
||||||
* [returns] none
|
* [returns] none
|
||||||
*/
|
*/
|
||||||
static BIO *cat_bio_free(BIO *hash, BIO *outdata)
|
static void cat_bio_free(BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
/* squash the unused parameter warning */
|
/* squash the unused parameter warning */
|
||||||
(void)outdata;
|
(void)outdata;
|
||||||
|
|
||||||
BIO_free_all(hash);
|
BIO_free_all(hash);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocate a FILE_FORMAT_CTX structure and CAT format specific structure,
|
* Deallocate a FILE_FORMAT_CTX structure and CAT format specific structure,
|
||||||
* unmap indata file, unlink outfile.
|
* unmap indata file.
|
||||||
* [in, out] ctx: structure holds all input and output data
|
* [in, out] ctx: structure holds all input and output data
|
||||||
* [out] hash: message digest BIO
|
* [out] hash: message digest BIO
|
||||||
* [in] outdata: outdata file BIO
|
* [in] outdata: outdata file BIO
|
||||||
* [returns] none
|
* [returns] none
|
||||||
*/
|
*/
|
||||||
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
if (outdata) {
|
|
||||||
BIO_free_all(hash);
|
|
||||||
if (ctx->options->outfile) {
|
|
||||||
#ifdef WIN32
|
|
||||||
_unlink(ctx->options->outfile);
|
|
||||||
#else
|
|
||||||
unlink(ctx->options->outfile);
|
|
||||||
#endif /* WIN32 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unmap_file(ctx->options->indata, ctx->cat_ctx->fileend);
|
unmap_file(ctx->options->indata, ctx->cat_ctx->fileend);
|
||||||
|
PKCS7_free(ctx->cat_ctx->p7);
|
||||||
OPENSSL_free(ctx->cat_ctx);
|
OPENSSL_free(ctx->cat_ctx);
|
||||||
OPENSSL_free(ctx);
|
OPENSSL_free(ctx);
|
||||||
}
|
}
|
||||||
@ -233,25 +225,275 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Verify mapped CAT file TODO and create CAT format specific structure.
|
* Verify mapped PKCS#7 (CAT) file and create CAT format specific structure.
|
||||||
* [in] indata: mapped CAT file (unused)
|
* [in] indata: mapped file
|
||||||
* [in] filesize: size of CAT file
|
* [in] filesize: size of file
|
||||||
* [returns] pointer to CAT format specific structure
|
* [returns] pointer to CAT format specific structure
|
||||||
*/
|
*/
|
||||||
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
|
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
|
||||||
{
|
{
|
||||||
CAT_CTX *cat_ctx;
|
CAT_CTX *cat_ctx;
|
||||||
|
PKCS7 *p7;
|
||||||
|
|
||||||
/* squash the unused parameter warning */
|
p7 = pkcs7_read_data(indata, filesize);
|
||||||
(void)indata;
|
if (!p7)
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
if (!PKCS7_type_is_signed(p7)) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
|
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
|
||||||
|
cat_ctx->p7 = p7;
|
||||||
cat_ctx->sigpos = 0;
|
cat_ctx->sigpos = 0;
|
||||||
cat_ctx->siglen = filesize;
|
cat_ctx->siglen = filesize;
|
||||||
cat_ctx->fileend = filesize;
|
cat_ctx->fileend = filesize;
|
||||||
return cat_ctx; /* OK */
|
return cat_ctx; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a content type OID to the PKCS#7 signature structure.
|
||||||
|
* The content type can be:
|
||||||
|
* - "1.3.6.1.4.1.311.10.1" (MS_CTL_OBJID) for Certificate Trust Lists (CTL),
|
||||||
|
* - "1.3.6.1.4.1.311.2.1.4" (SPC_INDIRECT_DATA_OBJID) for Authenticode data.
|
||||||
|
* [in, out] p7: new PKCS#7 signature
|
||||||
|
* [in] cursig: current PKCS#7 signature to determine content type
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cat_add_content_type(PKCS7 *p7, PKCS7 *cursig)
|
||||||
|
{
|
||||||
|
const char *content_type;
|
||||||
|
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||||
|
PKCS7_SIGNER_INFO *si;
|
||||||
|
|
||||||
|
if (is_content_type(cursig, SPC_INDIRECT_DATA_OBJID)) {
|
||||||
|
/* Authenticode content */
|
||||||
|
content_type = SPC_INDIRECT_DATA_OBJID;
|
||||||
|
} else if (is_content_type(cursig, MS_CTL_OBJID)) {
|
||||||
|
/* Certificate Trust List (CTL) */
|
||||||
|
content_type = MS_CTL_OBJID;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Unsupported content type\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
signer_info = PKCS7_get_signer_info(p7);
|
||||||
|
if (!signer_info)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
|
||||||
|
if (!si)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
||||||
|
V_ASN1_OBJECT, OBJ_txt2obj(content_type, 1)))
|
||||||
|
return 0; /* FAILED */
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Sign the MS CTL blob.
|
||||||
|
* Certificate Trust List (CTL) is a list of file names or thumbprints.
|
||||||
|
* All the items in this list are authenticated (approved) by the signing entity.
|
||||||
|
* [in, out] p7: new PKCS#7 signature
|
||||||
|
* [in] contents: Certificate Trust List (CTL)
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cat_sign_content(PKCS7 *p7, PKCS7 *contents)
|
||||||
|
{
|
||||||
|
u_char *content;
|
||||||
|
int seqhdrlen, content_length;
|
||||||
|
|
||||||
|
if (!contents->d.other || !contents->d.other->value.sequence
|
||||||
|
|| !contents->d.other->value.sequence->data) {
|
||||||
|
fprintf(stderr, "Failed to get content value\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
seqhdrlen = asn1_simple_hdr_len(contents->d.other->value.sequence->data,
|
||||||
|
contents->d.other->value.sequence->length);
|
||||||
|
content = contents->d.other->value.sequence->data + seqhdrlen;
|
||||||
|
content_length = contents->d.other->value.sequence->length - seqhdrlen;
|
||||||
|
|
||||||
|
if (!pkcs7_sign_content(p7, content, content_length)) {
|
||||||
|
fprintf(stderr, "Failed to sign content\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!PKCS7_set_content(p7, PKCS7_dup(contents))) {
|
||||||
|
fprintf(stderr, "PKCS7_set_content failed\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print each member of the CAT file by using the "-verbose" option.
|
||||||
|
* [in, out] p7: catalog file to verify
|
||||||
|
* [returns] 1 on error or 0 on success
|
||||||
|
*/
|
||||||
|
static int cat_list_content(PKCS7 *p7)
|
||||||
|
{
|
||||||
|
MsCtlContent *ctlc;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ctlc = ms_ctl_content_get(p7);
|
||||||
|
if (!ctlc) {
|
||||||
|
fprintf(stderr, "Failed to extract MS_CTL_OBJID data\n");
|
||||||
|
return 1; /* FAILED */
|
||||||
|
}
|
||||||
|
printf("\nCatalog members:\n");
|
||||||
|
for (i = 0; i < sk_CatalogInfo_num(ctlc->header_attributes); i++) {
|
||||||
|
int j, found = 0;
|
||||||
|
CatalogInfo *header_attr = sk_CatalogInfo_value(ctlc->header_attributes, i);
|
||||||
|
if (header_attr == NULL)
|
||||||
|
continue;
|
||||||
|
for (j = 0; j < sk_CatalogAuthAttr_num(header_attr->attributes); j++) {
|
||||||
|
char object_txt[128];
|
||||||
|
CatalogAuthAttr *attribute;
|
||||||
|
ASN1_TYPE *content;
|
||||||
|
|
||||||
|
attribute = sk_CatalogAuthAttr_value(header_attr->attributes, j);
|
||||||
|
if (!attribute)
|
||||||
|
continue;
|
||||||
|
content = catalog_content_get(attribute);
|
||||||
|
if (!content)
|
||||||
|
continue;
|
||||||
|
object_txt[0] = 0x00;
|
||||||
|
OBJ_obj2txt(object_txt, sizeof object_txt, attribute->type, 1);
|
||||||
|
if (!strcmp(object_txt, CAT_NAMEVALUE_OBJID)) {
|
||||||
|
/* CAT_NAMEVALUE_OBJID OID: 1.3.6.1.4.1.311.12.2.1 */
|
||||||
|
found |= cat_print_content_member_name(content);
|
||||||
|
} else if (!strcmp(object_txt, SPC_INDIRECT_DATA_OBJID)) {
|
||||||
|
/* SPC_INDIRECT_DATA_OBJID OID: 1.3.6.1.4.1.311.2.1.4 */
|
||||||
|
found |= cat_print_content_member_digest(content);
|
||||||
|
}
|
||||||
|
ASN1_TYPE_free(content);
|
||||||
|
}
|
||||||
|
if (found)
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
MsCtlContent_free(ctlc);
|
||||||
|
ERR_print_errors_fp(stderr);
|
||||||
|
return 0; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a hash algorithm and a message digest from the SPC_INDIRECT_DATA_OBJID attribute.
|
||||||
|
* [in] content: catalog file content
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cat_print_content_member_digest(ASN1_TYPE *content)
|
||||||
|
{
|
||||||
|
SpcIndirectDataContent *idc;
|
||||||
|
u_char mdbuf[EVP_MAX_MD_SIZE];
|
||||||
|
const u_char *data ;
|
||||||
|
int mdtype = -1;
|
||||||
|
ASN1_STRING *value;
|
||||||
|
|
||||||
|
value = content->value.sequence;
|
||||||
|
data = ASN1_STRING_get0_data(value);
|
||||||
|
idc = d2i_SpcIndirectDataContent(NULL, &data, ASN1_STRING_length(value));
|
||||||
|
if (!idc)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
|
||||||
|
/* get a digest algorithm a message digest of the file from the content */
|
||||||
|
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
|
||||||
|
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
|
||||||
|
}
|
||||||
|
SpcIndirectDataContent_free(idc);
|
||||||
|
if (mdtype == -1) {
|
||||||
|
fprintf(stderr, "Failed to extract current message digest\n\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
printf("\tHash algorithm: %s\n", OBJ_nid2sn(mdtype));
|
||||||
|
print_hash("\tMessage digest", "", mdbuf, EVP_MD_size(EVP_get_digestbynid(mdtype)));
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a file name from the CAT_NAMEVALUE_OBJID attribute.
|
||||||
|
* [in] content: catalog file content
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cat_print_content_member_name(ASN1_TYPE *content)
|
||||||
|
{
|
||||||
|
CatNameValueContent *nvc;
|
||||||
|
const u_char *data = NULL;
|
||||||
|
ASN1_STRING *value;
|
||||||
|
|
||||||
|
value = content->value.sequence;
|
||||||
|
data = ASN1_STRING_get0_data(value);
|
||||||
|
nvc = d2i_CatNameValueContent(NULL, &data, ASN1_STRING_length(value));
|
||||||
|
if (!nvc) {
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
printf("\tFile name: ");
|
||||||
|
if (ASN1_INTEGER_get(nvc->flags) & 0x00020000) {
|
||||||
|
cat_print_base64(nvc->value);
|
||||||
|
} else {
|
||||||
|
cat_print_utf16_as_ascii(nvc->value);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
CatNameValueContent_free(nvc);
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a CAT_NAMEVALUE_OBJID attribute represented in base-64 encoding.
|
||||||
|
* [in] value: catalog member file name
|
||||||
|
* [returns] none
|
||||||
|
*/
|
||||||
|
static void cat_print_base64(ASN1_OCTET_STRING *value)
|
||||||
|
{
|
||||||
|
BIO *stdbio, *b64;
|
||||||
|
stdbio = BIO_new_fp(stdout, BIO_NOCLOSE);
|
||||||
|
b64 = BIO_new(BIO_f_base64());
|
||||||
|
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
stdbio = BIO_push(b64, stdbio);
|
||||||
|
ASN1_STRING_print_ex(stdbio, value, 0);
|
||||||
|
BIO_free_all(stdbio);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a CAT_NAMEVALUE_OBJID attribute represented in plaintext.
|
||||||
|
* [in] value: catalog member file name
|
||||||
|
* [returns] none
|
||||||
|
*/
|
||||||
|
static void cat_print_utf16_as_ascii(ASN1_OCTET_STRING *value)
|
||||||
|
{
|
||||||
|
const u_char *data;
|
||||||
|
int len, i;
|
||||||
|
|
||||||
|
data = ASN1_STRING_get0_data(value);
|
||||||
|
len = ASN1_STRING_length(value);
|
||||||
|
for (i = 0; i < len && (data[i] || data[i+1]); i+=2)
|
||||||
|
putchar(isprint(data[i]) && !data[i+1] ? data[i] : '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the signature exists.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int cat_check_file(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||||
|
PKCS7_SIGNER_INFO *si;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
fprintf(stderr, "Init error\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
signer_info = PKCS7_get_signer_info(ctx->cat_ctx->p7);
|
||||||
|
if (!signer_info) {
|
||||||
|
fprintf(stderr, "Failed catalog file\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
|
||||||
|
if (!si) {
|
||||||
|
fprintf(stderr, "No signature found\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (ctx->options->verbose) {
|
||||||
|
(void)cat_list_content(ctx->cat_ctx->p7);
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
Local Variables:
|
Local Variables:
|
||||||
c-basic-offset: 4
|
c-basic-offset: 4
|
||||||
|
File diff suppressed because it is too large
Load Diff
9038
code_signing_ca.pem
Normal file
9038
code_signing_ca.pem
Normal file
File diff suppressed because it is too large
Load Diff
41
get_code_signing_ca.py
Executable file
41
get_code_signing_ca.py
Executable file
@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
# © 2024 Michal Trojnara
|
||||||
|
# This script downloads Microsoft code signing certificates
|
||||||
|
# Tor is required for this script to work
|
||||||
|
# Redirect the script output to a PEM file
|
||||||
|
|
||||||
|
from sys import stderr
|
||||||
|
from time import sleep
|
||||||
|
from csv import reader
|
||||||
|
from requests import get
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
||||||
|
def download_cert(hash):
|
||||||
|
for attempt in range(10):
|
||||||
|
if attempt > 0:
|
||||||
|
sleep(10)
|
||||||
|
try:
|
||||||
|
creds = f'{attempt}{hash}:{attempt}{hash}'
|
||||||
|
resp = get(f'https://crt.sh/?d={hash}',
|
||||||
|
proxies=dict(https=f'socks5://{creds}@127.0.0.1:9050'))
|
||||||
|
resp.raise_for_status()
|
||||||
|
print('.', file=stderr, end='')
|
||||||
|
stderr.flush()
|
||||||
|
return resp.content.decode('utf-8')
|
||||||
|
except RequestException as e:
|
||||||
|
print(f'\nAttempt {attempt}: {e}', file=stderr)
|
||||||
|
print('\nGiving up on', hash, file=stderr)
|
||||||
|
|
||||||
|
resp = get('https://ccadb-public.secure.force.com/microsoft/IncludedCACertificateReportForMSFTCSV')
|
||||||
|
resp.raise_for_status()
|
||||||
|
lines = resp.content.decode('utf-8').splitlines()[1:]
|
||||||
|
hashes = [row[4] for row in reader(lines)
|
||||||
|
if row[0] != 'Disabled'
|
||||||
|
or row[4] == 'F38406E540D7A9D90CB4A9479299640FFB6DF9E224ECC7A01C0D9558D8DAD77D']
|
||||||
|
with ThreadPoolExecutor(max_workers=20) as executor:
|
||||||
|
certs = executor.map(download_cert, hashes)
|
||||||
|
for cert in certs:
|
||||||
|
if cert is not None:
|
||||||
|
print(cert)
|
||||||
|
print('\nDone', file=stderr)
|
689
helpers.c
689
helpers.c
@ -9,12 +9,14 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig);
|
|
||||||
static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx);
|
static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx);
|
||||||
static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx);
|
static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx);
|
||||||
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx);
|
|
||||||
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
||||||
|
static int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
||||||
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
||||||
|
static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
||||||
|
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer);
|
||||||
|
static int X509_compare(const X509 *const *a, const X509 *const *b);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Common functions
|
* Common functions
|
||||||
@ -35,16 +37,16 @@ uint32_t get_file_size(const char *infile)
|
|||||||
ret = stat(infile, &st);
|
ret = stat(infile, &st);
|
||||||
#endif
|
#endif
|
||||||
if (ret) {
|
if (ret) {
|
||||||
printf("Failed to open file: %s\n", infile);
|
fprintf(stderr, "Failed to open file: %s\n", infile);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st.st_size < 4) {
|
if (st.st_size < 4) {
|
||||||
printf("Unrecognized file type - file is too short: %s\n", infile);
|
fprintf(stderr, "Unrecognized file type - file is too short: %s\n", infile);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (st.st_size > UINT32_MAX) {
|
if (st.st_size > UINT32_MAX) {
|
||||||
printf("Unsupported file - too large: %s\n", infile);
|
fprintf(stderr, "Unsupported file - too large: %s\n", infile);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return (uint32_t)st.st_size;
|
return (uint32_t)st.st_size;
|
||||||
@ -84,7 +86,7 @@ char *map_file(const char *infile, const size_t size)
|
|||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
#else
|
#else
|
||||||
printf("No file mapping function\n");
|
fprintf(stderr, "No file mapping function\n");
|
||||||
return NULL;
|
return NULL;
|
||||||
#endif /* HAVE_SYS_MMAN_H */
|
#endif /* HAVE_SYS_MMAN_H */
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
@ -109,113 +111,52 @@ void unmap_file(char *indata, const size_t size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in, out] si: PKCS7_SIGNER_INFO structure
|
* Retrieve a decoded PKCS#7 structure
|
||||||
* [in] ctx: FILE_FORMAT_CTX structure
|
* [in] data: encoded PEM or DER data
|
||||||
* [returns] 0 on error or 1 on success
|
* [in] size: data size
|
||||||
*/
|
|
||||||
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
|
||||||
{
|
|
||||||
SpcSpOpusInfo *opus;
|
|
||||||
ASN1_STRING *astr;
|
|
||||||
int len;
|
|
||||||
u_char *p = NULL;
|
|
||||||
|
|
||||||
opus = spc_sp_opus_info_create(ctx);
|
|
||||||
if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
|
|
||||||
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
|
||||||
SpcSpOpusInfo_free(opus);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
i2d_SpcSpOpusInfo(opus, &p);
|
|
||||||
p -= len;
|
|
||||||
astr = ASN1_STRING_new();
|
|
||||||
ASN1_STRING_set(astr, p, len);
|
|
||||||
OPENSSL_free(p);
|
|
||||||
SpcSpOpusInfo_free(opus);
|
|
||||||
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
|
|
||||||
V_ASN1_SEQUENCE, astr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* [in, out] si: PKCS7_SIGNER_INFO structure
|
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
|
||||||
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
|
||||||
{
|
|
||||||
static const u_char purpose_ind[] = {
|
|
||||||
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
|
||||||
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
|
|
||||||
};
|
|
||||||
static const u_char purpose_comm[] = {
|
|
||||||
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
|
||||||
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
|
|
||||||
};
|
|
||||||
ASN1_STRING *purpose = ASN1_STRING_new();
|
|
||||||
|
|
||||||
if (ctx->options->comm) {
|
|
||||||
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
|
|
||||||
} else {
|
|
||||||
ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
|
|
||||||
}
|
|
||||||
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
|
|
||||||
V_ASN1_SEQUENCE, purpose);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
|
|
||||||
* adding the _current_ time. This allows to create a deterministic signature
|
|
||||||
* when no trusted timestamp server was specified, making osslsigncode
|
|
||||||
* behaviour closer to signtool.exe (which doesn't include any non-trusted
|
|
||||||
* time in this case.)
|
|
||||||
* [in, out] si: PKCS7_SIGNER_INFO structure
|
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
|
||||||
int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
|
||||||
{
|
|
||||||
if (ctx->options->time == INVALID_TIME) /* -time option was not specified */
|
|
||||||
return 1; /* SUCCESS */
|
|
||||||
return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,
|
|
||||||
ASN1_TIME_adj(NULL, ctx->options->time, 0, 0));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Retrieve a decoded PKCS#7 structure corresponding to the signature
|
|
||||||
* stored in the "sigin" file
|
|
||||||
* CMD_ATTACH command specific
|
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] pointer to PKCS#7 structure
|
* [returns] pointer to PKCS#7 structure
|
||||||
*/
|
*/
|
||||||
PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx)
|
PKCS7 *pkcs7_read_data(char *data, uint32_t size)
|
||||||
{
|
{
|
||||||
PKCS7 *p7 = NULL;
|
PKCS7 *p7 = NULL;
|
||||||
uint32_t filesize;
|
|
||||||
char *indata;
|
|
||||||
BIO *bio;
|
BIO *bio;
|
||||||
const char pemhdr[] = "-----BEGIN PKCS7-----";
|
const char pemhdr[] = "-----BEGIN PKCS7-----";
|
||||||
|
|
||||||
filesize = get_file_size(ctx->options->sigfile);
|
bio = BIO_new_mem_buf(data, (int)size);
|
||||||
if (!filesize) {
|
if (size >= sizeof pemhdr && !memcmp(data, pemhdr, sizeof pemhdr - 1)) {
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
indata = map_file(ctx->options->sigfile, filesize);
|
|
||||||
if (!indata) {
|
|
||||||
printf("Failed to open file: %s\n", ctx->options->sigfile);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
bio = BIO_new_mem_buf(indata, (int)filesize);
|
|
||||||
if (filesize >= sizeof pemhdr && !memcmp(indata, pemhdr, sizeof pemhdr - 1)) {
|
|
||||||
/* PEM format */
|
/* PEM format */
|
||||||
p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
|
p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
|
||||||
} else { /* DER format */
|
} else { /* DER format */
|
||||||
p7 = d2i_PKCS7_bio(bio, NULL);
|
p7 = d2i_PKCS7_bio(bio, NULL);
|
||||||
}
|
}
|
||||||
BIO_free_all(bio);
|
BIO_free_all(bio);
|
||||||
unmap_file(indata, filesize);
|
|
||||||
return p7;
|
return p7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] outdata: BIO outdata file
|
||||||
|
* [in] p7: PKCS#7 signature
|
||||||
|
* [returns] 1 on error or 0 on success
|
||||||
|
*/
|
||||||
|
int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
(void)BIO_reset(outdata);
|
||||||
|
if (ctx->options->output_pkcs7) {
|
||||||
|
/* PEM format */
|
||||||
|
ret = !PEM_write_bio_PKCS7(outdata, p7);
|
||||||
|
} else {
|
||||||
|
/* default DER format */
|
||||||
|
ret = !i2d_PKCS7_bio(outdata, p7);
|
||||||
|
}
|
||||||
|
if (ret) {
|
||||||
|
fprintf(stderr, "Unable to write pkcs7 object\n");
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate, set type, add content and return a new PKCS#7 signature
|
* Allocate, set type, add content and return a new PKCS#7 signature
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
@ -224,84 +165,85 @@ PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx)
|
|||||||
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
|
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
int i, signer = -1;
|
int i, signer = -1;
|
||||||
PKCS7 *p7;
|
|
||||||
PKCS7_SIGNER_INFO *si = NULL;
|
PKCS7_SIGNER_INFO *si = NULL;
|
||||||
|
STACK_OF(X509) *chain = NULL;
|
||||||
|
PKCS7 *p7 = PKCS7_new();
|
||||||
|
|
||||||
|
if (!p7)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
p7 = PKCS7_new();
|
|
||||||
PKCS7_set_type(p7, NID_pkcs7_signed);
|
PKCS7_set_type(p7, NID_pkcs7_signed);
|
||||||
|
|
||||||
if (ctx->options->cert != NULL) {
|
|
||||||
/*
|
|
||||||
* the private key and corresponding certificate are parsed from the PKCS12
|
|
||||||
* structure or loaded from the security token, so we may omit to check
|
|
||||||
* the consistency of a private key with the public key in an X509 certificate
|
|
||||||
*/
|
|
||||||
si = PKCS7_add_signature(p7, ctx->options->cert, ctx->options->pkey,
|
|
||||||
ctx->options->md);
|
|
||||||
if (si == NULL)
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
} else {
|
|
||||||
/* find the signer's certificate located somewhere in the whole certificate chain */
|
|
||||||
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
|
||||||
X509 *signcert = sk_X509_value(ctx->options->certs, i);
|
|
||||||
if (X509_check_private_key(signcert, ctx->options->pkey)) {
|
|
||||||
si = PKCS7_add_signature(p7, signcert, ctx->options->pkey, ctx->options->md);
|
|
||||||
signer = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (si == NULL) {
|
|
||||||
printf("Failed to checking the consistency of a private key: %s\n",
|
|
||||||
ctx->options->keyfile);
|
|
||||||
printf(" with a public key in any X509 certificate: %s\n\n",
|
|
||||||
ctx->options->certfile);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pkcs7_signer_info_add_signing_time(si, ctx);
|
|
||||||
|
|
||||||
if (!pkcs7_signer_info_add_purpose(si, ctx))
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
|
|
||||||
if ((ctx->options->desc || ctx->options->url) &&
|
|
||||||
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
|
|
||||||
printf("Couldn't allocate memory for opus info\n");
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
PKCS7_content_new(p7, NID_pkcs7_data);
|
PKCS7_content_new(p7, NID_pkcs7_data);
|
||||||
|
|
||||||
/* add the signer's certificate */
|
/* find the signer's certificate located somewhere in the whole certificate chain */
|
||||||
if (ctx->options->cert != NULL)
|
|
||||||
PKCS7_add_certificate(p7, ctx->options->cert);
|
|
||||||
if (signer != -1)
|
|
||||||
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->certs, signer));
|
|
||||||
|
|
||||||
/* add the certificate chain */
|
|
||||||
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
||||||
if (i == signer)
|
X509 *signcert = sk_X509_value(ctx->options->certs, i);
|
||||||
continue;
|
|
||||||
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->certs, i));
|
if (X509_check_private_key(signcert, ctx->options->pkey)) {
|
||||||
|
si = PKCS7_add_signature(p7, signcert, ctx->options->pkey, ctx->options->md);
|
||||||
|
signer = i;
|
||||||
|
if (signer > 0)
|
||||||
|
printf("Warning: For optimal performance, consider placing the signer certificate at the beginning of the certificate chain.\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/* add all cross certificates */
|
if (!si) {
|
||||||
if (ctx->options->xcerts) {
|
fprintf(stderr, "Failed to checking the consistency of a private key: %s\n",
|
||||||
for (i=0; i<sk_X509_num(ctx->options->xcerts); i++)
|
ctx->options->keyfile);
|
||||||
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->xcerts, i));
|
fprintf(stderr, " with a public key in any X509 certificate: %s\n\n",
|
||||||
|
#if !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||||
|
ctx->options->certfile ? ctx->options->certfile : ctx->options->p11cert);
|
||||||
|
#else
|
||||||
|
ctx->options->certfile);
|
||||||
|
#endif /* !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pkcs7_signer_info_add_signing_time(si, ctx)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (!pkcs7_signer_info_add_purpose(si, ctx)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if ((ctx->options->desc || ctx->options->url) &&
|
||||||
|
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
|
||||||
|
fprintf(stderr, "Couldn't allocate memory for opus info\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if ((ctx->options->nested_number >= 0) &&
|
||||||
|
!pkcs7_signer_info_add_sequence_number(si, ctx)) {
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
/* create X509 chain sorted in ascending order by their DER encoding */
|
||||||
|
chain = X509_chain_get_sorted(ctx, signer);
|
||||||
|
if (!chain) {
|
||||||
|
fprintf(stderr, "Failed to create a sorted certificate chain\n");
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
/* add sorted certificate chain */
|
||||||
|
for (i=0; i<sk_X509_num(chain); i++) {
|
||||||
|
(void)PKCS7_add_certificate(p7, sk_X509_value(chain, i));
|
||||||
}
|
}
|
||||||
/* add crls */
|
/* add crls */
|
||||||
if (ctx->options->crls) {
|
if (ctx->options->crls) {
|
||||||
for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++)
|
for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++)
|
||||||
PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i));
|
(void)PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i));
|
||||||
}
|
}
|
||||||
|
sk_X509_free(chain);
|
||||||
return p7; /* OK */
|
return p7; /* OK */
|
||||||
|
|
||||||
|
err:
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
* PE, MSI, CAB and APPX file specific
|
||||||
|
* Add "1.3.6.1.4.1.311.2.1.4" SPC_INDIRECT_DATA_OBJID signed attribute
|
||||||
* [in, out] p7: new PKCS#7 signature
|
* [in, out] p7: new PKCS#7 signature
|
||||||
* [in] hash: message digest BIO
|
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] 0 on error or 1 on success
|
* [returns] 0 on error or 1 on success
|
||||||
*/
|
*/
|
||||||
int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
int add_indirect_data_object(PKCS7 *p7)
|
||||||
{
|
{
|
||||||
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||||
PKCS7_SIGNER_INFO *si;
|
PKCS7_SIGNER_INFO *si;
|
||||||
@ -315,67 +257,152 @@ int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
|||||||
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
||||||
V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)))
|
V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)))
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
if (!pkcs7_set_data_content(p7, hash, ctx)) {
|
return 1; /* OK */
|
||||||
printf("Signing failed\n");
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* PE, MSI, CAB and APPX format specific
|
||||||
|
* Sign the MS Authenticode spcIndirectDataContent blob.
|
||||||
|
* The spcIndirectDataContent structure is used in Authenticode signatures
|
||||||
|
* to store the digest and other attributes of the signed file.
|
||||||
|
* [in, out] p7: new PKCS#7 signature
|
||||||
|
* [in] content: spcIndirectDataContent
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content)
|
||||||
|
{
|
||||||
|
int len, inf, tag, class;
|
||||||
|
long plen;
|
||||||
|
const u_char *data, *p;
|
||||||
|
PKCS7 *td7;
|
||||||
|
|
||||||
|
p = data = ASN1_STRING_get0_data(content);
|
||||||
|
len = ASN1_STRING_length(content);
|
||||||
|
inf = ASN1_get_object(&p, &plen, &tag, &class, len);
|
||||||
|
if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE
|
||||||
|
|| !pkcs7_sign_content(p7, p, (int)plen)) {
|
||||||
|
fprintf(stderr, "Failed to sign spcIndirectDataContent\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
td7 = PKCS7_new();
|
||||||
|
if (!td7) {
|
||||||
|
fprintf(stderr, "PKCS7_new failed\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
|
||||||
|
td7->d.other = ASN1_TYPE_new();
|
||||||
|
td7->d.other->type = V_ASN1_SEQUENCE;
|
||||||
|
td7->d.other->value.sequence = ASN1_STRING_new();
|
||||||
|
ASN1_STRING_set(td7->d.other->value.sequence, data, len);
|
||||||
|
if (!PKCS7_set_content(p7, td7)) {
|
||||||
|
fprintf(stderr, "PKCS7_set_content failed\n");
|
||||||
|
PKCS7_free(td7);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in, out] p7: new PKCS#7 signature
|
* Add encapsulated content to signed PKCS7 structure.
|
||||||
* [in] cursig: current PKCS#7 signature
|
* [in] content: spcIndirectDataContent
|
||||||
* [returns] 0 on error or 1 on success
|
* [returns] new PKCS#7 signature with encapsulated content
|
||||||
*/
|
*/
|
||||||
int add_ms_ctl_object(PKCS7 *p7, PKCS7 *cursig)
|
PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content)
|
||||||
{
|
{
|
||||||
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
PKCS7 *p7, *td7;
|
||||||
PKCS7_SIGNER_INFO *si;
|
|
||||||
|
|
||||||
signer_info = PKCS7_get_signer_info(p7);
|
p7 = PKCS7_new();
|
||||||
if (!signer_info)
|
if (!p7) {
|
||||||
return 0; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
|
|
||||||
if (!si)
|
|
||||||
return 0; /* FAILED */
|
|
||||||
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
|
||||||
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
|
|
||||||
return 0; /* FAILED */
|
|
||||||
if (!pkcs7_set_content_blob(p7, cursig)) {
|
|
||||||
printf("Signing failed\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
}
|
||||||
return 1; /* OK */
|
if (!PKCS7_set_type(p7, NID_pkcs7_signed)) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!PKCS7_content_new(p7, NID_pkcs7_data)) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
td7 = PKCS7_new();
|
||||||
|
if (!td7) {
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
|
||||||
|
td7->d.other = ASN1_TYPE_new();
|
||||||
|
td7->d.other->type = V_ASN1_SEQUENCE;
|
||||||
|
td7->d.other->value.sequence = content;
|
||||||
|
if (!PKCS7_set_content(p7, td7)) {
|
||||||
|
PKCS7_free(td7);
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
return p7;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig)
|
/*
|
||||||
|
* Return spcIndirectDataContent.
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] content
|
||||||
|
*/
|
||||||
|
ASN1_OCTET_STRING *spc_indirect_data_content_get(BIO *hash, FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
PKCS7 *contents;
|
ASN1_OCTET_STRING *content;
|
||||||
u_char *content;
|
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
|
||||||
int seqhdrlen, content_length;
|
int mdlen, hashlen, len = 0;
|
||||||
BIO *sigbio;
|
u_char *data, *p = NULL;
|
||||||
|
|
||||||
contents = cursig->d.sign->contents;
|
content = ASN1_OCTET_STRING_new();
|
||||||
seqhdrlen = asn1_simple_hdr_len(contents->d.other->value.sequence->data,
|
if (!content) {
|
||||||
contents->d.other->value.sequence->length);
|
return NULL; /* FAILED */
|
||||||
content = contents->d.other->value.sequence->data + seqhdrlen;
|
}
|
||||||
content_length = contents->d.other->value.sequence->length - seqhdrlen;
|
if (!spc_indirect_data_content_create(&p, &len, ctx)) {
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
hashlen = ctx->format->hash_length_get(ctx);
|
||||||
|
if (hashlen > EVP_MAX_MD_SIZE) {
|
||||||
|
/* APPX format specific */
|
||||||
|
mdlen = BIO_read(hash, (char*)mdbuf, hashlen);
|
||||||
|
} else {
|
||||||
|
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
|
||||||
|
}
|
||||||
|
data = OPENSSL_malloc((size_t)(len + mdlen));
|
||||||
|
memcpy(data, p, (size_t)len);
|
||||||
|
OPENSSL_free(p);
|
||||||
|
memcpy(data + len, mdbuf, (size_t)mdlen);
|
||||||
|
if (!ASN1_OCTET_STRING_set(content, data, len + mdlen)) {
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
OPENSSL_free(data);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
OPENSSL_free(data);
|
||||||
|
return content;
|
||||||
|
}
|
||||||
|
|
||||||
if ((sigbio = PKCS7_dataInit(sig, NULL)) == NULL) {
|
/*
|
||||||
printf("PKCS7_dataInit failed\n");
|
* Signs the data and place the signature in p7
|
||||||
|
* [in, out] p7: new PKCS#7 signature
|
||||||
|
* [in] data: content data
|
||||||
|
* [in] len: content length
|
||||||
|
*/
|
||||||
|
int pkcs7_sign_content(PKCS7 *p7, const u_char *data, int len)
|
||||||
|
{
|
||||||
|
BIO *p7bio;
|
||||||
|
|
||||||
|
if ((p7bio = PKCS7_dataInit(p7, NULL)) == NULL) {
|
||||||
|
fprintf(stderr, "PKCS7_dataInit failed\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
BIO_write(sigbio, content, content_length);
|
BIO_write(p7bio, data, len);
|
||||||
(void)BIO_flush(sigbio);
|
(void)BIO_flush(p7bio);
|
||||||
if (!PKCS7_dataFinal(sig, sigbio)) {
|
if (!PKCS7_dataFinal(p7, p7bio)) {
|
||||||
printf("PKCS7_dataFinal failed\n");
|
fprintf(stderr, "PKCS7_dataFinal failed\n");
|
||||||
return 0; /* FAILED */
|
BIO_free_all(p7bio);
|
||||||
}
|
|
||||||
BIO_free_all(sigbio);
|
|
||||||
if (!PKCS7_set_content(sig, PKCS7_dup(contents))) {
|
|
||||||
printf("PKCS7_set_content failed\n");
|
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
|
BIO_free_all(p7bio);
|
||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,7 +464,7 @@ void print_hash(const char *descript1, const char *descript2, const u_char *mdbu
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] p7: new PKCS#7 signature
|
* [in] p7: PKCS#7 signature
|
||||||
* [in] objid: Microsoft OID Authenticode
|
* [in] objid: Microsoft OID Authenticode
|
||||||
* [returns] 0 on error or 1 on success
|
* [returns] 0 on error or 1 on success
|
||||||
*/
|
*/
|
||||||
@ -456,29 +483,42 @@ int is_content_type(PKCS7 *p7, const char *objid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [out] p7: new PKCS#7 signature
|
* [in] p7: new PKCS#7 signature
|
||||||
* [in] hash: message digest BIO
|
* [returns] pointer to MsCtlContent structure
|
||||||
* [in] ctx: structure holds input and output data
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
*/
|
||||||
int pkcs7_set_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
|
MsCtlContent *ms_ctl_content_get(PKCS7 *p7)
|
||||||
{
|
{
|
||||||
u_char *p = NULL;
|
ASN1_STRING *value;
|
||||||
int len = 0;
|
const u_char *data;
|
||||||
u_char *buf;
|
|
||||||
|
|
||||||
if (!spc_indirect_data_content_get(&p, &len, ctx))
|
if (!is_content_type(p7, MS_CTL_OBJID)) {
|
||||||
return 0; /* FAILED */
|
fprintf(stderr, "Failed to find MS_CTL_OBJID\n");
|
||||||
buf = OPENSSL_malloc(SIZE_64K);
|
return NULL; /* FAILED */
|
||||||
memcpy(buf, p, (size_t)len);
|
|
||||||
OPENSSL_free(p);
|
|
||||||
if (!pkcs7_set_spc_indirect_data_content(p7, hash, buf, len, ctx)) {
|
|
||||||
OPENSSL_free(buf);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
}
|
||||||
OPENSSL_free(buf);
|
value = p7->d.sign->contents->d.other->value.sequence;
|
||||||
|
data = ASN1_STRING_get0_data(value);
|
||||||
|
return d2i_MsCtlContent(NULL, &data, ASN1_STRING_length(value));
|
||||||
|
}
|
||||||
|
|
||||||
return 1; /* OK */
|
/*
|
||||||
|
* [in] attribute: catalog attribute
|
||||||
|
* [returns] catalog content
|
||||||
|
*/
|
||||||
|
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute)
|
||||||
|
{
|
||||||
|
ASN1_STRING *value;
|
||||||
|
STACK_OF(ASN1_TYPE) *contents;
|
||||||
|
ASN1_TYPE *content;
|
||||||
|
const u_char *contents_data;
|
||||||
|
|
||||||
|
value = attribute->contents->value.sequence;
|
||||||
|
contents_data = ASN1_STRING_get0_data(value);
|
||||||
|
contents = d2i_ASN1_SET_ANY(NULL, &contents_data, ASN1_STRING_length(value));
|
||||||
|
if (!contents)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
content = sk_ASN1_TYPE_value(contents, 0);
|
||||||
|
sk_ASN1_TYPE_free(contents);
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -503,23 +543,6 @@ SpcLink *spc_link_obsolete_get(void)
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Retrieve a decoded PKCS#7 structure
|
|
||||||
* [in] indata: mapped file
|
|
||||||
* [in] sigpos: signature data offset
|
|
||||||
* [in] siglen: signature data size
|
|
||||||
* [returns] pointer to PKCS#7 structure
|
|
||||||
*/
|
|
||||||
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen)
|
|
||||||
{
|
|
||||||
PKCS7 *p7 = NULL;
|
|
||||||
const u_char *blob;
|
|
||||||
|
|
||||||
blob = (u_char *)indata + sigpos;
|
|
||||||
p7 = d2i_PKCS7(NULL, &blob, siglen);
|
|
||||||
return p7;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] mdbuf, cmdbuf: message digests
|
* [in] mdbuf, cmdbuf: message digests
|
||||||
* [in] mdtype: message digest algorithm type
|
* [in] mdtype: message digest algorithm type
|
||||||
@ -570,14 +593,22 @@ static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx)
|
|||||||
* [in] ctx: FILE_FORMAT_CTX structure
|
* [in] ctx: FILE_FORMAT_CTX structure
|
||||||
* [returns] 0 on error or 1 on success
|
* [returns] 0 on error or 1 on success
|
||||||
*/
|
*/
|
||||||
static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx)
|
static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
u_char *p = NULL;
|
u_char *p = NULL;
|
||||||
int hashlen, l = 0;
|
int mdtype, hashlen, l = 0;
|
||||||
int mdtype = EVP_MD_nid(ctx->options->md);
|
|
||||||
void *hash;
|
void *hash;
|
||||||
SpcIndirectDataContent *idc = SpcIndirectDataContent_new();
|
SpcIndirectDataContent *idc = SpcIndirectDataContent_new();
|
||||||
|
|
||||||
|
if (!ctx->format->data_blob_get || !ctx->format->hash_length_get) {
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (ctx->format->md_get) {
|
||||||
|
/* APPX file specific - use a hash algorithm specified in the AppxBlockMap.xml file */
|
||||||
|
mdtype = EVP_MD_nid(ctx->format->md_get(ctx));
|
||||||
|
} else {
|
||||||
|
mdtype = EVP_MD_nid(ctx->options->md);
|
||||||
|
}
|
||||||
idc->data->value = ASN1_TYPE_new();
|
idc->data->value = ASN1_TYPE_new();
|
||||||
idc->data->value->type = V_ASN1_SEQUENCE;
|
idc->data->value->type = V_ASN1_SEQUENCE;
|
||||||
idc->data->value->value.sequence = ASN1_STRING_new();
|
idc->data->value->value.sequence = ASN1_STRING_new();
|
||||||
@ -603,56 +634,164 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Replace the data part with the MS Authenticode spcIndirectDataContent blob
|
* [in, out] si: PKCS7_SIGNER_INFO structure
|
||||||
* [out] p7: new PKCS#7 signature
|
|
||||||
* [in] hash: message digest BIO
|
|
||||||
* [in] blob: SpcIndirectDataContent data
|
|
||||||
* [in] len: SpcIndirectDataContent data length
|
|
||||||
* [in] ctx: FILE_FORMAT_CTX structure
|
* [in] ctx: FILE_FORMAT_CTX structure
|
||||||
* [returns] 0 on error or 1 on success
|
* [returns] 0 on error or 1 on success
|
||||||
*/
|
*/
|
||||||
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx)
|
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
|
SpcSpOpusInfo *opus;
|
||||||
int mdlen, seqhdrlen, hashlen;
|
ASN1_STRING *astr;
|
||||||
BIO *bio;
|
int len;
|
||||||
PKCS7 *td7;
|
u_char *p = NULL;
|
||||||
|
|
||||||
hashlen = ctx->format->hash_length_get(ctx);
|
opus = spc_sp_opus_info_create(ctx);
|
||||||
if (hashlen > EVP_MAX_MD_SIZE) {
|
if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
|
||||||
/* APPX format specific */
|
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
||||||
mdlen = BIO_read(hash, (char*)mdbuf, hashlen);
|
SpcSpOpusInfo_free(opus);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
i2d_SpcSpOpusInfo(opus, &p);
|
||||||
|
p -= len;
|
||||||
|
astr = ASN1_STRING_new();
|
||||||
|
ASN1_STRING_set(astr, p, len);
|
||||||
|
OPENSSL_free(p);
|
||||||
|
SpcSpOpusInfo_free(opus);
|
||||||
|
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
|
||||||
|
V_ASN1_SEQUENCE, astr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
|
||||||
|
* adding the _current_ time. This allows to create a deterministic signature
|
||||||
|
* when no trusted timestamp server was specified, making osslsigncode
|
||||||
|
* behaviour closer to signtool.exe (which doesn't include any non-trusted
|
||||||
|
* time in this case.)
|
||||||
|
* [in, out] si: PKCS7_SIGNER_INFO structure
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
if (ctx->options->time == INVALID_TIME) /* -time option was not specified */
|
||||||
|
return 1; /* SUCCESS */
|
||||||
|
return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,
|
||||||
|
ASN1_TIME_adj(NULL, ctx->options->time, 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* [in, out] si: PKCS7_SIGNER_INFO structure
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
static const u_char purpose_ind[] = {
|
||||||
|
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
||||||
|
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
|
||||||
|
};
|
||||||
|
static const u_char purpose_comm[] = {
|
||||||
|
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
|
||||||
|
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
|
||||||
|
};
|
||||||
|
ASN1_STRING *purpose = ASN1_STRING_new();
|
||||||
|
|
||||||
|
if (ctx->options->comm) {
|
||||||
|
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
|
||||||
} else {
|
} else {
|
||||||
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
|
ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
|
||||||
}
|
}
|
||||||
memcpy(buf + len, mdbuf, (size_t)mdlen);
|
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
|
||||||
seqhdrlen = asn1_simple_hdr_len(buf, len);
|
V_ASN1_SEQUENCE, purpose);
|
||||||
|
}
|
||||||
|
|
||||||
if ((bio = PKCS7_dataInit(p7, NULL)) == NULL) {
|
/*
|
||||||
printf("PKCS7_dataInit failed\n");
|
* [in, out] si: PKCS7_SIGNER_INFO structure
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
ASN1_INTEGER *number = ASN1_INTEGER_new();
|
||||||
|
|
||||||
|
if (!number)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
if (!ASN1_INTEGER_set(number, ctx->options->nested_number + 1)) {
|
||||||
|
ASN1_INTEGER_free(number);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
BIO_write(bio, buf + seqhdrlen, len - seqhdrlen + mdlen);
|
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(PKCS9_SEQUENCE_NUMBER),
|
||||||
(void)BIO_flush(bio);
|
V_ASN1_INTEGER, number);
|
||||||
|
}
|
||||||
|
|
||||||
if (!PKCS7_dataFinal(p7, bio)) {
|
/*
|
||||||
printf("PKCS7_dataFinal failed\n");
|
* Create certificate chain sorted in ascending order by their DER encoding.
|
||||||
return 0; /* FAILED */
|
* [in] ctx: structure holds input and output data
|
||||||
}
|
* [in] signer: signer's certificate number in the certificate chain
|
||||||
BIO_free_all(bio);
|
* [returns] sorted certificate chain
|
||||||
|
*/
|
||||||
|
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
STACK_OF(X509) *chain = sk_X509_new(X509_compare);
|
||||||
|
|
||||||
td7 = PKCS7_new();
|
if (signer != -1 && !sk_X509_push(chain, sk_X509_value(ctx->options->certs, signer))) {
|
||||||
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
|
sk_X509_free(chain);
|
||||||
td7->d.other = ASN1_TYPE_new();
|
return NULL;
|
||||||
td7->d.other->type = V_ASN1_SEQUENCE;
|
|
||||||
td7->d.other->value.sequence = ASN1_STRING_new();
|
|
||||||
ASN1_STRING_set(td7->d.other->value.sequence, buf, len + mdlen);
|
|
||||||
if (!PKCS7_set_content(p7, td7)) {
|
|
||||||
PKCS7_free(td7);
|
|
||||||
printf("PKCS7_set_content failed\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
}
|
||||||
return 1; /* OK */
|
/* add the certificate chain */
|
||||||
|
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
||||||
|
if (i == signer)
|
||||||
|
continue;
|
||||||
|
if (!sk_X509_push(chain, sk_X509_value(ctx->options->certs, i))) {
|
||||||
|
sk_X509_free(chain);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* add all cross certificates */
|
||||||
|
if (ctx->options->xcerts) {
|
||||||
|
for (i=0; i<sk_X509_num(ctx->options->xcerts); i++) {
|
||||||
|
if (!sk_X509_push(chain, sk_X509_value(ctx->options->xcerts, i))) {
|
||||||
|
sk_X509_free(chain);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* sort certificate chain using the supplied comparison function */
|
||||||
|
sk_X509_sort(chain);
|
||||||
|
return chain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* X.690-compliant certificate comparison function
|
||||||
|
* Windows requires catalog files to use PKCS#7
|
||||||
|
* content ordering specified in X.690 section 11.6
|
||||||
|
* https://support.microsoft.com/en-us/topic/october-13-2020-kb4580358-security-only-update-d3f6eb3c-d7c4-a9cb-0de6-759386bf7113
|
||||||
|
* This algorithm is different from X509_cmp()
|
||||||
|
* [in] a_ptr, b_ptr: pointers to X509 certificates
|
||||||
|
* [returns] certificates order
|
||||||
|
*/
|
||||||
|
static int X509_compare(const X509 *const *a, const X509 *const *b)
|
||||||
|
{
|
||||||
|
u_char *a_data, *b_data, *a_tmp, *b_tmp;
|
||||||
|
size_t a_len, b_len;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
a_len = (size_t)i2d_X509(*a, NULL);
|
||||||
|
a_tmp = a_data = OPENSSL_malloc(a_len);
|
||||||
|
i2d_X509(*a, &a_tmp);
|
||||||
|
|
||||||
|
b_len = (size_t)i2d_X509(*b, NULL);
|
||||||
|
b_tmp = b_data = OPENSSL_malloc(b_len);
|
||||||
|
i2d_X509(*b, &b_tmp);
|
||||||
|
|
||||||
|
ret = memcmp(a_data, b_data, MIN(a_len, b_len));
|
||||||
|
OPENSSL_free(a_data);
|
||||||
|
OPENSSL_free(b_data);
|
||||||
|
|
||||||
|
if (ret == 0 && a_len != b_len) /* identical up to the length of the shorter DER */
|
||||||
|
ret = a_len < b_len ? -1 : 1; /* shorter is smaller */
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
16
helpers.h
16
helpers.h
@ -9,19 +9,21 @@
|
|||||||
uint32_t get_file_size(const char *infile);
|
uint32_t get_file_size(const char *infile);
|
||||||
char *map_file(const char *infile, const size_t size);
|
char *map_file(const char *infile, const size_t size);
|
||||||
void unmap_file(char *indata, const size_t size);
|
void unmap_file(char *indata, const size_t size);
|
||||||
int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
|
PKCS7 *pkcs7_read_data(char *indata, uint32_t size);
|
||||||
PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx);
|
int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx);
|
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx);
|
||||||
void add_content_type(PKCS7 *p7);
|
int add_indirect_data_object(PKCS7 *p7);
|
||||||
int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx);
|
int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content);
|
||||||
int add_ms_ctl_object(PKCS7 *p7, PKCS7 *cursig);
|
PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content);
|
||||||
|
ASN1_OCTET_STRING *spc_indirect_data_content_get(BIO *hash, FILE_FORMAT_CTX *ctx);
|
||||||
|
int pkcs7_sign_content(PKCS7 *p7, const u_char *data, int len);
|
||||||
int asn1_simple_hdr_len(const u_char *p, int len);
|
int asn1_simple_hdr_len(const u_char *p, int len);
|
||||||
int bio_hash_data(BIO *hash, char *indata, size_t idx, size_t fileend);
|
int bio_hash_data(BIO *hash, char *indata, size_t idx, size_t fileend);
|
||||||
void print_hash(const char *descript1, const char *descript2, const u_char *hashbuf, int length);
|
void print_hash(const char *descript1, const char *descript2, const u_char *hashbuf, int length);
|
||||||
int is_content_type(PKCS7 *p7, const char *objid);
|
int is_content_type(PKCS7 *p7, const char *objid);
|
||||||
int pkcs7_set_data_content(PKCS7 *sig, BIO *hash, FILE_FORMAT_CTX *ctx);
|
MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
|
||||||
|
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
|
||||||
SpcLink *spc_link_obsolete_get(void);
|
SpcLink *spc_link_obsolete_get(void);
|
||||||
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen);
|
|
||||||
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
|
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
2873
osslsigncode.c
2873
osslsigncode.c
File diff suppressed because it is too large
Load Diff
102
osslsigncode.h
102
osslsigncode.h
@ -14,6 +14,7 @@
|
|||||||
#define NOCRYPT
|
#define NOCRYPT
|
||||||
#define WIN32_LEAN_AND_MEAN
|
#define WIN32_LEAN_AND_MEAN
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
#include <winsock2.h>
|
||||||
#endif /* HAVE_WINDOWS_H */
|
#endif /* HAVE_WINDOWS_H */
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
#ifdef HAVE_CONFIG_H
|
||||||
@ -21,6 +22,7 @@
|
|||||||
#endif /* HAVE_CONFIG_H */
|
#endif /* HAVE_CONFIG_H */
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
@ -31,6 +33,7 @@
|
|||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
#ifdef HAVE_SYS_MMAN_H
|
#ifdef HAVE_SYS_MMAN_H
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#endif /* HAVE_SYS_MMAN_H */
|
#endif /* HAVE_SYS_MMAN_H */
|
||||||
@ -62,7 +65,10 @@
|
|||||||
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
|
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||||
#include <openssl/rand.h>
|
#include <openssl/rand.h>
|
||||||
#include <openssl/safestack.h>
|
#include <openssl/safestack.h>
|
||||||
|
#include <openssl/ssl.h>
|
||||||
|
#include <openssl/store.h>
|
||||||
#include <openssl/ts.h>
|
#include <openssl/ts.h>
|
||||||
|
#include <openssl/ui.h>
|
||||||
#include <openssl/x509.h>
|
#include <openssl/x509.h>
|
||||||
#include <openssl/x509v3.h> /* X509_PURPOSE */
|
#include <openssl/x509v3.h> /* X509_PURPOSE */
|
||||||
|
|
||||||
@ -73,20 +79,28 @@
|
|||||||
#endif /* SOCKET */
|
#endif /* SOCKET */
|
||||||
#endif /* __CYGWIN__ */
|
#endif /* __CYGWIN__ */
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
#define MAX_TS_SERVERS 256
|
|
||||||
#endif /* ENABLE_CURL */
|
#endif /* ENABLE_CURL */
|
||||||
|
|
||||||
|
/* Request nonce length, in bits (must be a multiple of 8). */
|
||||||
|
#define NONCE_LENGTH 64
|
||||||
|
#define MAX_TS_SERVERS 256
|
||||||
|
|
||||||
#if defined (HAVE_TERMIOS_H) || defined (HAVE_GETPASS)
|
#if defined (HAVE_TERMIOS_H) || defined (HAVE_GETPASS)
|
||||||
#define PROVIDE_ASKPASS 1
|
#define PROVIDE_ASKPASS 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _MSC_VER
|
||||||
#define FILE_CREATE_MODE "w+b"
|
/* not WIN32, because strcasecmp exists in MinGW */
|
||||||
#else
|
#define strcasecmp _stricmp
|
||||||
#define FILE_CREATE_MODE "w+bx"
|
#define fseeko _fseeki64
|
||||||
#endif
|
#define ftello _ftelli64
|
||||||
|
#endif /* _MSC_VER */
|
||||||
|
|
||||||
|
#ifdef WIN32
|
||||||
|
#define remove_file(filename) _unlink(filename)
|
||||||
|
#else
|
||||||
|
#define remove_file(filename) unlink(filename)
|
||||||
|
#endif /* WIN32 */
|
||||||
|
|
||||||
#define GET_UINT8_LE(p) ((const u_char *)(p))[0]
|
#define GET_UINT8_LE(p) ((const u_char *)(p))[0]
|
||||||
|
|
||||||
@ -175,6 +189,8 @@
|
|||||||
#define SPC_RFC3161_OBJID "1.3.6.1.4.1.311.3.3.1"
|
#define SPC_RFC3161_OBJID "1.3.6.1.4.1.311.3.3.1"
|
||||||
/* Microsoft OID Crypto 2.0 */
|
/* Microsoft OID Crypto 2.0 */
|
||||||
#define MS_CTL_OBJID "1.3.6.1.4.1.311.10.1"
|
#define MS_CTL_OBJID "1.3.6.1.4.1.311.10.1"
|
||||||
|
/* Microsoft OID Catalog */
|
||||||
|
#define CAT_NAMEVALUE_OBJID "1.3.6.1.4.1.311.12.2.1"
|
||||||
/* Microsoft OID Microsoft_Java */
|
/* Microsoft OID Microsoft_Java */
|
||||||
#define MS_JAVA_SOMETHING "1.3.6.1.4.1.311.15.1"
|
#define MS_JAVA_SOMETHING "1.3.6.1.4.1.311.15.1"
|
||||||
|
|
||||||
@ -184,6 +200,7 @@
|
|||||||
#define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4"
|
#define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4"
|
||||||
#define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5"
|
#define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5"
|
||||||
#define PKCS9_COUNTER_SIGNATURE "1.2.840.113549.1.9.6"
|
#define PKCS9_COUNTER_SIGNATURE "1.2.840.113549.1.9.6"
|
||||||
|
#define PKCS9_SEQUENCE_NUMBER "1.2.840.113549.1.9.25.4"
|
||||||
|
|
||||||
/* WIN_CERTIFICATE structure declared in Wintrust.h */
|
/* WIN_CERTIFICATE structure declared in Wintrust.h */
|
||||||
#define WIN_CERT_REVISION_2_0 0x0200
|
#define WIN_CERT_REVISION_2_0 0x0200
|
||||||
@ -208,9 +225,9 @@
|
|||||||
*/
|
*/
|
||||||
#define FLAG_RESERVE_PRESENT 0x0004
|
#define FLAG_RESERVE_PRESENT 0x0004
|
||||||
|
|
||||||
#define DO_EXIT_0(x) { printf(x); goto err_cleanup; }
|
#define DO_EXIT_0(x) { fprintf(stderr, x); goto err_cleanup; }
|
||||||
#define DO_EXIT_1(x, y) { printf(x, y); goto err_cleanup; }
|
#define DO_EXIT_1(x, y) { fprintf(stderr, x, y); goto err_cleanup; }
|
||||||
#define DO_EXIT_2(x, y, z) { printf(x, y, z); goto err_cleanup; }
|
#define DO_EXIT_2(x, y, z) { fprintf(stderr, x, y, z); goto err_cleanup; }
|
||||||
|
|
||||||
/* Default policy if request did not specify it. */
|
/* Default policy if request did not specify it. */
|
||||||
#define TSA_POLICY1 "1.2.3.4.1"
|
#define TSA_POLICY1 "1.2.3.4.1"
|
||||||
@ -218,6 +235,7 @@
|
|||||||
typedef enum {
|
typedef enum {
|
||||||
CMD_SIGN,
|
CMD_SIGN,
|
||||||
CMD_EXTRACT,
|
CMD_EXTRACT,
|
||||||
|
CMD_EXTRACT_DATA,
|
||||||
CMD_REMOVE,
|
CMD_REMOVE,
|
||||||
CMD_VERIFY,
|
CMD_VERIFY,
|
||||||
CMD_ADD,
|
CMD_ADD,
|
||||||
@ -228,6 +246,16 @@ typedef enum {
|
|||||||
|
|
||||||
typedef unsigned char u_char;
|
typedef unsigned char u_char;
|
||||||
|
|
||||||
|
#ifndef OPENSSL_NO_ENGINE
|
||||||
|
typedef struct {
|
||||||
|
ASN1_OCTET_STRING *cmd;
|
||||||
|
ASN1_OCTET_STRING *param;
|
||||||
|
} EngineControl;
|
||||||
|
|
||||||
|
DECLARE_ASN1_FUNCTIONS(EngineControl)
|
||||||
|
DEFINE_STACK_OF(EngineControl)
|
||||||
|
#endif /* OPENSSL_NO_ENGINE */
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
char *infile;
|
char *infile;
|
||||||
char *outfile;
|
char *outfile;
|
||||||
@ -242,6 +270,8 @@ typedef struct {
|
|||||||
char *p11engine;
|
char *p11engine;
|
||||||
char *p11module;
|
char *p11module;
|
||||||
char *p11cert;
|
char *p11cert;
|
||||||
|
int login;
|
||||||
|
STACK_OF(EngineControl) *engine_ctrls;
|
||||||
#endif /* OPENSSL_NO_ENGINE */
|
#endif /* OPENSSL_NO_ENGINE */
|
||||||
int askpass;
|
int askpass;
|
||||||
char *readpass;
|
char *readpass;
|
||||||
@ -252,40 +282,44 @@ typedef struct {
|
|||||||
const EVP_MD *md;
|
const EVP_MD *md;
|
||||||
char *url;
|
char *url;
|
||||||
time_t time;
|
time_t time;
|
||||||
#ifdef ENABLE_CURL
|
|
||||||
char *turl[MAX_TS_SERVERS];
|
char *turl[MAX_TS_SERVERS];
|
||||||
int nturl;
|
int nturl;
|
||||||
char *tsurl[MAX_TS_SERVERS];
|
char *tsurl[MAX_TS_SERVERS];
|
||||||
int ntsurl;
|
int ntsurl;
|
||||||
char *proxy;
|
char *proxy;
|
||||||
int noverifypeer;
|
int noverifypeer;
|
||||||
#endif /* ENABLE_CURL */
|
|
||||||
int addBlob;
|
int addBlob;
|
||||||
|
const char *blob_file;
|
||||||
int nest;
|
int nest;
|
||||||
|
int index;
|
||||||
int ignore_timestamp;
|
int ignore_timestamp;
|
||||||
|
int ignore_cdp;
|
||||||
|
int ignore_crl;
|
||||||
int verbose;
|
int verbose;
|
||||||
int add_msi_dse;
|
int add_msi_dse;
|
||||||
char *catalog;
|
char *catalog;
|
||||||
char *cafile;
|
char *cafile;
|
||||||
char *crlfile;
|
char *crlfile;
|
||||||
|
char *https_cafile;
|
||||||
|
char *https_crlfile;
|
||||||
char *tsa_cafile;
|
char *tsa_cafile;
|
||||||
char *tsa_crlfile;
|
char *tsa_crlfile;
|
||||||
char *leafhash;
|
char *leafhash;
|
||||||
int jp;
|
int jp;
|
||||||
#if OPENSSL_VERSION_NUMBER>=0x30000000L
|
#if OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||||
int legacy;
|
int legacy;
|
||||||
|
char *provider;
|
||||||
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
|
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||||
EVP_PKEY *pkey;
|
EVP_PKEY *pkey;
|
||||||
X509 *cert;
|
|
||||||
STACK_OF(X509) *certs;
|
STACK_OF(X509) *certs;
|
||||||
STACK_OF(X509) *xcerts;
|
STACK_OF(X509) *xcerts;
|
||||||
STACK_OF(X509_CRL) *crls;
|
STACK_OF(X509_CRL) *crls;
|
||||||
cmd_type_t cmd;
|
cmd_type_t cmd;
|
||||||
char *indata;
|
char *indata;
|
||||||
PKCS7 *prevsig;
|
|
||||||
char *tsa_certfile;
|
char *tsa_certfile;
|
||||||
char *tsa_keyfile;
|
char *tsa_keyfile;
|
||||||
time_t tsa_time;
|
time_t tsa_time;
|
||||||
|
int nested_number;
|
||||||
} GLOBAL_OPTIONS;
|
} GLOBAL_OPTIONS;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -326,6 +360,18 @@ typedef struct {
|
|||||||
|
|
||||||
DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo)
|
DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ASN1_INTEGER *a;
|
||||||
|
ASN1_OCTET_STRING *string;
|
||||||
|
ASN1_INTEGER *b;
|
||||||
|
ASN1_INTEGER *c;
|
||||||
|
ASN1_INTEGER *d;
|
||||||
|
ASN1_INTEGER *e;
|
||||||
|
ASN1_INTEGER *f;
|
||||||
|
} SpcSipInfo;
|
||||||
|
|
||||||
|
DECLARE_ASN1_FUNCTIONS(SpcSipInfo)
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ASN1_OBJECT *type;
|
ASN1_OBJECT *type;
|
||||||
ASN1_TYPE *value;
|
ASN1_TYPE *value;
|
||||||
@ -369,8 +415,6 @@ typedef struct {
|
|||||||
|
|
||||||
DECLARE_ASN1_FUNCTIONS(MessageImprint)
|
DECLARE_ASN1_FUNCTIONS(MessageImprint)
|
||||||
|
|
||||||
#ifdef ENABLE_CURL
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ASN1_OBJECT *type;
|
ASN1_OBJECT *type;
|
||||||
ASN1_OCTET_STRING *signature;
|
ASN1_OCTET_STRING *signature;
|
||||||
@ -413,8 +457,6 @@ typedef struct {
|
|||||||
|
|
||||||
DECLARE_ASN1_FUNCTIONS(TimeStampReq)
|
DECLARE_ASN1_FUNCTIONS(TimeStampReq)
|
||||||
|
|
||||||
#endif /* ENABLE_CURL */
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
ASN1_INTEGER *seconds;
|
ASN1_INTEGER *seconds;
|
||||||
ASN1_INTEGER *millis;
|
ASN1_INTEGER *millis;
|
||||||
@ -461,7 +503,17 @@ typedef struct {
|
|||||||
|
|
||||||
DECLARE_ASN1_FUNCTIONS(MsCtlContent)
|
DECLARE_ASN1_FUNCTIONS(MsCtlContent)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char *server;
|
||||||
|
const char *port;
|
||||||
|
int use_proxy;
|
||||||
|
int timeout;
|
||||||
|
SSL_CTX *ssl_ctx;
|
||||||
|
} HTTP_TLS_Info;
|
||||||
|
|
||||||
typedef struct file_format_st FILE_FORMAT;
|
typedef struct file_format_st FILE_FORMAT;
|
||||||
|
|
||||||
|
typedef struct script_ctx_st SCRIPT_CTX;
|
||||||
typedef struct msi_ctx_st MSI_CTX;
|
typedef struct msi_ctx_st MSI_CTX;
|
||||||
typedef struct pe_ctx_st PE_CTX;
|
typedef struct pe_ctx_st PE_CTX;
|
||||||
typedef struct cab_ctx_st CAB_CTX;
|
typedef struct cab_ctx_st CAB_CTX;
|
||||||
@ -472,6 +524,7 @@ typedef struct {
|
|||||||
FILE_FORMAT *format;
|
FILE_FORMAT *format;
|
||||||
GLOBAL_OPTIONS *options;
|
GLOBAL_OPTIONS *options;
|
||||||
union {
|
union {
|
||||||
|
SCRIPT_CTX *script_ctx;
|
||||||
MSI_CTX *msi_ctx;
|
MSI_CTX *msi_ctx;
|
||||||
PE_CTX *pe_ctx;
|
PE_CTX *pe_ctx;
|
||||||
CAB_CTX *cab_ctx;
|
CAB_CTX *cab_ctx;
|
||||||
@ -480,6 +533,7 @@ typedef struct {
|
|||||||
};
|
};
|
||||||
} FILE_FORMAT_CTX;
|
} FILE_FORMAT_CTX;
|
||||||
|
|
||||||
|
extern FILE_FORMAT file_format_script;
|
||||||
extern FILE_FORMAT file_format_msi;
|
extern FILE_FORMAT file_format_msi;
|
||||||
extern FILE_FORMAT file_format_pe;
|
extern FILE_FORMAT file_format_pe;
|
||||||
extern FILE_FORMAT file_format_cab;
|
extern FILE_FORMAT file_format_cab;
|
||||||
@ -488,19 +542,23 @@ extern FILE_FORMAT file_format_appx;
|
|||||||
|
|
||||||
struct file_format_st {
|
struct file_format_st {
|
||||||
FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata);
|
FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata);
|
||||||
|
const EVP_MD *(*md_get) (FILE_FORMAT_CTX *ctx);
|
||||||
ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
PKCS7 *(*pkcs7_contents_get) (FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
|
int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
|
||||||
int (*check_file) (FILE_FORMAT_CTX *ctx, int detached);
|
|
||||||
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
||||||
int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
|
int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
|
||||||
PKCS7 *(*pkcs7_extract) (FILE_FORMAT_CTX *ctx);
|
PKCS7 *(*pkcs7_extract) (FILE_FORMAT_CTX *ctx);
|
||||||
|
PKCS7 *(*pkcs7_extract_to_nest) (FILE_FORMAT_CTX *ctx);
|
||||||
int (*remove_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
int (*remove_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
PKCS7 *(*pkcs7_prepare) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
int (*process_data) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
PKCS7 *(*pkcs7_signature_new) (FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||||
int (*append_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
int (*append_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7);
|
void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7);
|
||||||
BIO *(*bio_free) (BIO *hash, BIO *outdata);
|
void (*bio_free) (BIO *hash, BIO *outdata);
|
||||||
void (*ctx_cleanup) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
void (*ctx_cleanup) (FILE_FORMAT_CTX *ctx);
|
||||||
|
int (*is_detaching_supported) (void);
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
449
pe.c
449
pe.c
@ -44,34 +44,40 @@ struct pe_ctx_st {
|
|||||||
/* FILE_FORMAT method prototypes */
|
/* FILE_FORMAT method prototypes */
|
||||||
static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
static int pe_hash_length_get(FILE_FORMAT_CTX *ctx);
|
static int pe_hash_length_get(FILE_FORMAT_CTX *ctx);
|
||||||
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached);
|
|
||||||
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
||||||
static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
|
static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
|
||||||
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx);
|
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
|
||||||
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||||
static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
static BIO *pe_bio_free(BIO *hash, BIO *outdata);
|
static void pe_bio_free(BIO *hash, BIO *outdata);
|
||||||
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx);
|
||||||
|
static int pe_is_detaching_supported(void);
|
||||||
|
|
||||||
FILE_FORMAT file_format_pe = {
|
FILE_FORMAT file_format_pe = {
|
||||||
.ctx_new = pe_ctx_new,
|
.ctx_new = pe_ctx_new,
|
||||||
.data_blob_get = pe_spc_image_data_get,
|
.data_blob_get = pe_spc_image_data_get,
|
||||||
|
.pkcs7_contents_get = pe_pkcs7_contents_get,
|
||||||
.hash_length_get = pe_hash_length_get,
|
.hash_length_get = pe_hash_length_get,
|
||||||
.check_file = pe_check_file,
|
|
||||||
.digest_calc = pe_digest_calc,
|
.digest_calc = pe_digest_calc,
|
||||||
.verify_digests = pe_verify_digests,
|
.verify_digests = pe_verify_digests,
|
||||||
.verify_indirect_data = pe_verify_indirect_data,
|
.verify_indirect_data = pe_verify_indirect_data,
|
||||||
.pkcs7_extract = pe_pkcs7_extract,
|
.pkcs7_extract = pe_pkcs7_extract,
|
||||||
|
.pkcs7_extract_to_nest = pe_pkcs7_extract_to_nest,
|
||||||
.remove_pkcs7 = pe_remove_pkcs7,
|
.remove_pkcs7 = pe_remove_pkcs7,
|
||||||
.pkcs7_prepare = pe_pkcs7_prepare,
|
.process_data = pe_process_data,
|
||||||
|
.pkcs7_signature_new = pe_pkcs7_signature_new,
|
||||||
.append_pkcs7 = pe_append_pkcs7,
|
.append_pkcs7 = pe_append_pkcs7,
|
||||||
.update_data_size = pe_update_data_size,
|
.update_data_size = pe_update_data_size,
|
||||||
.bio_free = pe_bio_free,
|
.bio_free = pe_bio_free,
|
||||||
.ctx_cleanup = pe_ctx_cleanup
|
.ctx_cleanup = pe_ctx_cleanup,
|
||||||
|
.is_detaching_supported = pe_is_detaching_supported
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Prototypes */
|
/* Prototypes */
|
||||||
@ -80,10 +86,12 @@ static PKCS7 *pe_pkcs7_get_file(char *indata, PE_CTX *pe_ctx);
|
|||||||
static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size);
|
static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size);
|
||||||
static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx);
|
static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx);
|
||||||
static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj);
|
static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj);
|
||||||
static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype);
|
static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype);
|
||||||
static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype);
|
static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype);
|
||||||
static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype);
|
static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype);
|
||||||
|
static int pe_check_file(FILE_FORMAT_CTX *ctx);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -112,12 +120,12 @@ static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outd
|
|||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (memcmp(options->indata, "MZ", 2)) {
|
if (memcmp(options->indata, "MZ", 2)) {
|
||||||
unmap_file(options->infile, filesize);
|
unmap_file(options->indata, filesize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
pe_ctx = pe_ctx_get(options->indata, filesize);
|
pe_ctx = pe_ctx_get(options->indata, filesize);
|
||||||
if (!pe_ctx) {
|
if (!pe_ctx) {
|
||||||
unmap_file(options->infile, filesize);
|
unmap_file(options->indata, filesize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
||||||
@ -170,6 +178,30 @@ static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX
|
|||||||
return dtype; /* OK */
|
return dtype; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a data content to be signed.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] data content
|
||||||
|
*/
|
||||||
|
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
BIO *bhash;
|
||||||
|
|
||||||
|
/* squash the unused parameter warning */
|
||||||
|
(void)hash;
|
||||||
|
|
||||||
|
bhash = pe_digest_calc_bio(ctx, md);
|
||||||
|
if (!bhash) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(bhash, ctx);
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return pkcs7_set_content(content);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
|
||||||
@ -180,121 +212,24 @@ static int pe_hash_length_get(FILE_FORMAT_CTX *ctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print current and calculated PE checksum,
|
* Returns a message digest value of a signed or unsigned PE file.
|
||||||
* check if the signature exists.
|
|
||||||
* [in, out] ctx: structure holds input and output data
|
|
||||||
* [in] detached: embedded/detached PKCS#7 signature switch
|
|
||||||
* [returns] 0 on error or 1 on success
|
|
||||||
*/
|
|
||||||
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached)
|
|
||||||
{
|
|
||||||
uint32_t real_pe_checksum, sum = 0;
|
|
||||||
|
|
||||||
if (!ctx) {
|
|
||||||
printf("Init error\n\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
real_pe_checksum = pe_calc_realchecksum(ctx);
|
|
||||||
if (ctx->pe_ctx->pe_checksum == real_pe_checksum) {
|
|
||||||
printf("PE checksum : %08X\n\n", real_pe_checksum);
|
|
||||||
} else {
|
|
||||||
printf("Current PE checksum : %08X\n", ctx->pe_ctx->pe_checksum);
|
|
||||||
printf("Calculated PE checksum: %08X\n", real_pe_checksum);
|
|
||||||
printf("Warning: invalid PE checksum\n\n");
|
|
||||||
}
|
|
||||||
if (detached) {
|
|
||||||
printf("Checking the specified catalog file\n\n");
|
|
||||||
return 1; /* OK */
|
|
||||||
}
|
|
||||||
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|
|
||||||
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
|
|
||||||
printf("No signature found\n\n");
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* If the sum of the rounded dwLength values does not equal the Size value,
|
|
||||||
* then either the attribute certificate table or the Size field is corrupted.
|
|
||||||
*/
|
|
||||||
while (sum < ctx->pe_ctx->siglen) {
|
|
||||||
uint32_t len = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->sigpos + sum);
|
|
||||||
if (ctx->pe_ctx->siglen - len > 8) {
|
|
||||||
printf("Corrupted attribute certificate table\n");
|
|
||||||
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
|
|
||||||
printf("Attribute certificate entry length: %08X\n\n", len);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
/* quadword align data */
|
|
||||||
len += len % 8 ? 8 - len % 8 : 0;
|
|
||||||
sum += len;
|
|
||||||
}
|
|
||||||
if (sum != ctx->pe_ctx->siglen) {
|
|
||||||
printf("Corrupted attribute certificate table\n");
|
|
||||||
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
|
|
||||||
printf("Sum of the rounded dwLength values: %08X\n\n", sum);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
return 1; /* OK */
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Compute a message digest value of a signed or unsigned PE file.
|
|
||||||
* [in] ctx: structure holds input and output data
|
* [in] ctx: structure holds input and output data
|
||||||
* [in] md: message digest algorithm
|
* [in] md: message digest algorithm
|
||||||
* [returns] pointer to calculated message digest
|
* [returns] pointer to calculated message digest
|
||||||
*/
|
*/
|
||||||
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||||
{
|
{
|
||||||
size_t written;
|
u_char *mdbuf;
|
||||||
uint32_t idx = 0, fileend;
|
BIO *bhash = pe_digest_calc_bio(ctx, md);
|
||||||
u_char *mdbuf = NULL;
|
if (!bhash) {
|
||||||
BIO *bhash = BIO_new(BIO_f_md());
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
if (!BIO_set_md(bhash, md)) {
|
|
||||||
printf("Unable to set the message digest of BIO\n");
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
|
||||||
if (ctx->pe_ctx->sigpos)
|
|
||||||
fileend = ctx->pe_ctx->sigpos;
|
|
||||||
else
|
|
||||||
fileend = ctx->pe_ctx->fileend;
|
|
||||||
|
|
||||||
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
|
|
||||||
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|
|
||||||
|| written != ctx->pe_ctx->header_size + 88) {
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
idx += (uint32_t)written + 4;
|
|
||||||
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
|
|
||||||
60 + ctx->pe_ctx->pe32plus * 16, &written)
|
|
||||||
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
idx += (uint32_t)written + 8;
|
|
||||||
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
|
|
||||||
printf("Unable to calculate digest\n");
|
|
||||||
BIO_free_all(bhash);
|
|
||||||
return 0; /* FAILED */
|
|
||||||
}
|
|
||||||
if (!ctx->pe_ctx->sigpos) {
|
|
||||||
/* pad (with 0's) unsigned PE file to 8 byte boundary */
|
|
||||||
int len = 8 - ctx->pe_ctx->fileend % 8;
|
|
||||||
if (len > 0 && len != 8) {
|
|
||||||
char *buf = OPENSSL_malloc(8);
|
|
||||||
memset(buf, 0, (size_t)len);
|
|
||||||
BIO_write(bhash, buf, len);
|
|
||||||
OPENSSL_free(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
|
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
|
||||||
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
|
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
|
||||||
BIO_free_all(bhash);
|
BIO_free_all(bhash);
|
||||||
return mdbuf; /* OK */
|
return mdbuf; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate message digest and page_hash and compare to values retrieved
|
* Calculate message digest and page_hash and compare to values retrieved
|
||||||
* from PKCS#7 signedData.
|
* from PKCS#7 signedData.
|
||||||
@ -316,7 +251,7 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
|||||||
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
|
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
|
||||||
if (idc) {
|
if (idc) {
|
||||||
if (!pe_page_hash_get(&ph, &phlen, &phtype, idc->data)) {
|
if (!pe_page_hash_get(&ph, &phlen, &phtype, idc->data)) {
|
||||||
printf("Failed to extract a page hash\n\n");
|
fprintf(stderr, "Failed to extract a page hash\n\n");
|
||||||
SpcIndirectDataContent_free(idc);
|
SpcIndirectDataContent_free(idc);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -328,25 +263,25 @@ static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (mdtype == -1) {
|
if (mdtype == -1) {
|
||||||
printf("Failed to extract current message digest\n\n");
|
fprintf(stderr, "Failed to extract current message digest\n\n");
|
||||||
OPENSSL_free(ph);
|
OPENSSL_free(ph);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
md = EVP_get_digestbynid(mdtype);
|
md = EVP_get_digestbynid(mdtype);
|
||||||
cmdbuf = pe_digest_calc(ctx, md);
|
cmdbuf = pe_digest_calc(ctx, md);
|
||||||
if (!cmdbuf) {
|
if (!cmdbuf) {
|
||||||
printf("Failed to calculate message digest\n\n");
|
fprintf(stderr, "Failed to calculate message digest\n\n");
|
||||||
OPENSSL_free(ph);
|
OPENSSL_free(ph);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
|
if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
|
||||||
printf("Signature verification: failed\n\n");
|
fprintf(stderr, "Signature verification: failed\n\n");
|
||||||
OPENSSL_free(ph);
|
OPENSSL_free(ph);
|
||||||
OPENSSL_free(cmdbuf);
|
OPENSSL_free(cmdbuf);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) {
|
if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) {
|
||||||
printf("Signature verification: failed\n\n");
|
fprintf(stderr, "Signature verification: failed\n\n");
|
||||||
OPENSSL_free(ph);
|
OPENSSL_free(ph);
|
||||||
OPENSSL_free(cmdbuf);
|
OPENSSL_free(cmdbuf);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
@ -368,11 +303,11 @@ static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOpti
|
|||||||
u_char *ph = NULL;
|
u_char *ph = NULL;
|
||||||
|
|
||||||
if (!pe_page_hash_get(&ph, &phlen, &phtype, obj)) {
|
if (!pe_page_hash_get(&ph, &phlen, &phtype, obj)) {
|
||||||
printf("Failed to extract a page hash\n\n");
|
fprintf(stderr, "Failed to extract a page hash\n\n");
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) {
|
if (!pe_verify_page_hash(ctx, ph, phlen, phtype)) {
|
||||||
printf("Page hash verification: failed\n\n");
|
fprintf(stderr, "Page hash verification: failed\n\n");
|
||||||
OPENSSL_free(ph);
|
OPENSSL_free(ph);
|
||||||
return 0; /* FAILED */
|
return 0; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -387,13 +322,22 @@ static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOpti
|
|||||||
*/
|
*/
|
||||||
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|
if (!pe_check_file(ctx)) {
|
||||||
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
|
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
return pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx);
|
return pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract existing signature in DER format.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] pointer to PKCS#7 structure
|
||||||
|
*/
|
||||||
|
static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
return pe_pkcs7_extract(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove existing signature.
|
* Remove existing signature.
|
||||||
* [in, out] ctx: structure holds input and output data
|
* [in, out] ctx: structure holds input and output data
|
||||||
@ -403,73 +347,70 @@ static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
|||||||
*/
|
*/
|
||||||
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
if (ctx->pe_ctx->sigpos == 0) {
|
if (!pe_check_file(ctx)) {
|
||||||
printf("PE file does not have any signature\n");
|
return 1; /* FAILED, no signature */
|
||||||
return 1; /* FAILED */
|
|
||||||
}
|
}
|
||||||
/* Strip current signature */
|
/* Strip current signature */
|
||||||
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
|
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
|
||||||
if (!pe_modify_header(ctx, hash, outdata)) {
|
if (!pe_modify_header(ctx, hash, outdata)) {
|
||||||
printf("Unable to modify file header\n");
|
fprintf(stderr, "Unable to modify file header\n");
|
||||||
return 1; /* FAILED */
|
return 1; /* FAILED */
|
||||||
}
|
}
|
||||||
return 0; /* OK */
|
return 0; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Obtain an existing signature or create a new one.
|
* Modify specific type data and calculate a hash (message digest) of data.
|
||||||
* [in, out] ctx: structure holds input and output data
|
* [in, out] ctx: structure holds input and output data
|
||||||
* [out] hash: message digest BIO
|
* [out] hash: message digest BIO
|
||||||
* [out] outdata: outdata file BIO
|
* [out] outdata: outdata file BIO
|
||||||
* [returns] pointer to PKCS#7 structure
|
* [returns] 1 on error or 0 on success
|
||||||
*/
|
*/
|
||||||
static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
PKCS7 *cursig = NULL, *p7 = NULL;
|
|
||||||
|
|
||||||
/* Obtain a current signature from previously-signed file */
|
|
||||||
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest)
|
|
||||||
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|
|
||||||
|| ctx->options->cmd == CMD_ADD) {
|
|
||||||
cursig = pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx);
|
|
||||||
if (!cursig) {
|
|
||||||
printf("Unable to extract existing signature\n");
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
if (ctx->options->cmd == CMD_ADD)
|
|
||||||
p7 = cursig;
|
|
||||||
}
|
|
||||||
if (ctx->pe_ctx->sigpos > 0) {
|
if (ctx->pe_ctx->sigpos > 0) {
|
||||||
/* Strip current signature */
|
/* Strip current signature */
|
||||||
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
|
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
|
||||||
}
|
}
|
||||||
if (!pe_modify_header(ctx, hash, outdata)) {
|
if (!pe_modify_header(ctx, hash, outdata)) {
|
||||||
printf("Unable to modify file header\n");
|
fprintf(stderr, "Unable to modify file header\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new PKCS#7 signature.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] hash: message digest BIO
|
||||||
|
* [returns] pointer to PKCS#7 structure
|
||||||
|
*/
|
||||||
|
static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
PKCS7 *p7 = pkcs7_create(ctx);
|
||||||
|
|
||||||
|
if (!p7) {
|
||||||
|
fprintf(stderr, "Creating a new signature failed\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (ctx->options->cmd == CMD_ATTACH) {
|
if (!add_indirect_data_object(p7)) {
|
||||||
/* Obtain an existing PKCS#7 signature */
|
fprintf(stderr, "Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
||||||
p7 = pkcs7_get_sigfile(ctx);
|
PKCS7_free(p7);
|
||||||
if (!p7) {
|
return NULL; /* FAILED */
|
||||||
printf("Unable to extract valid signature\n");
|
|
||||||
PKCS7_free(cursig);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
} else if (ctx->options->cmd == CMD_SIGN) {
|
|
||||||
/* Create a new PKCS#7 signature */
|
|
||||||
p7 = pkcs7_create(ctx);
|
|
||||||
if (!p7) {
|
|
||||||
printf("Creating a new signature failed\n");
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
if (!add_indirect_data_object(p7, hash, ctx)) {
|
|
||||||
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
|
||||||
PKCS7_free(p7);
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (ctx->options->nest)
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
ctx->options->prevsig = cursig;
|
if (!content) {
|
||||||
|
fprintf(stderr, "Failed to get spcIndirectDataContent\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!sign_spc_indirect_data_content(p7, content)) {
|
||||||
|
fprintf(stderr, "Failed to set signed content\n");
|
||||||
|
PKCS7_free(p7);
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
return p7;
|
return p7;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,7 +435,7 @@ static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
|||||||
|
|
||||||
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|
||||||
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
|
||||||
printf("i2d_PKCS memory allocation failed: %d\n", len);
|
fprintf(stderr, "i2d_PKCS memory allocation failed: %d\n", len);
|
||||||
return 1; /* FAILED */
|
return 1; /* FAILED */
|
||||||
}
|
}
|
||||||
i2d_PKCS7(p7, &p);
|
i2d_PKCS7(p7, &p);
|
||||||
@ -555,40 +496,33 @@ static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
|||||||
* [out] outdata: outdata file BIO (unused)
|
* [out] outdata: outdata file BIO (unused)
|
||||||
* [returns] none
|
* [returns] none
|
||||||
*/
|
*/
|
||||||
static BIO *pe_bio_free(BIO *hash, BIO *outdata)
|
static void pe_bio_free(BIO *hash, BIO *outdata)
|
||||||
{
|
{
|
||||||
/* squash the unused parameter warning */
|
/* squash the unused parameter warning */
|
||||||
(void)outdata;
|
(void)outdata;
|
||||||
|
|
||||||
BIO_free_all(hash);
|
BIO_free_all(hash);
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Deallocate a FILE_FORMAT_CTX structure and PE format specific structure,
|
* Deallocate a FILE_FORMAT_CTX structure and PE format specific structure,
|
||||||
* unmap indata file, unlink outfile.
|
* unmap indata file.
|
||||||
* [out] ctx: structure holds input and output data
|
* [out] ctx: structure holds input and output data
|
||||||
* [out] hash: message digest BIO
|
* [out] hash: message digest BIO
|
||||||
* [in] outdata: outdata file BIO
|
* [in] outdata: outdata file BIO
|
||||||
* [returns] none
|
* [returns] none
|
||||||
*/
|
*/
|
||||||
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx)
|
||||||
{
|
{
|
||||||
if (outdata) {
|
|
||||||
BIO_free_all(hash);
|
|
||||||
if (ctx->options->outfile) {
|
|
||||||
#ifdef WIN32
|
|
||||||
_unlink(ctx->options->outfile);
|
|
||||||
#else
|
|
||||||
unlink(ctx->options->outfile);
|
|
||||||
#endif /* WIN32 */
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unmap_file(ctx->options->indata, ctx->pe_ctx->fileend);
|
unmap_file(ctx->options->indata, ctx->pe_ctx->fileend);
|
||||||
OPENSSL_free(ctx->pe_ctx);
|
OPENSSL_free(ctx->pe_ctx);
|
||||||
OPENSSL_free(ctx);
|
OPENSSL_free(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int pe_is_detaching_supported(void)
|
||||||
|
{
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* PE helper functions
|
* PE helper functions
|
||||||
*/
|
*/
|
||||||
@ -606,7 +540,7 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
|
|||||||
uint16_t magic;
|
uint16_t magic;
|
||||||
|
|
||||||
if (filesize < 64) {
|
if (filesize < 64) {
|
||||||
printf("Corrupt DOS file - too short\n");
|
fprintf(stderr, "Corrupt DOS file - too short\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* SizeOfHeaders field specifies the combined size of an MS-DOS stub, PE header,
|
/* SizeOfHeaders field specifies the combined size of an MS-DOS stub, PE header,
|
||||||
@ -615,15 +549,15 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
|
|||||||
* because of a bug when checking section names for compatibility purposes */
|
* because of a bug when checking section names for compatibility purposes */
|
||||||
header_size = GET_UINT32_LE(indata + 60);
|
header_size = GET_UINT32_LE(indata + 60);
|
||||||
if (header_size < 44 || header_size > filesize) {
|
if (header_size < 44 || header_size > filesize) {
|
||||||
printf("Unexpected SizeOfHeaders field: 0x%08X\n", header_size);
|
fprintf(stderr, "Unexpected SizeOfHeaders field: 0x%08X\n", header_size);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (filesize < header_size + 176) {
|
if (filesize < header_size + 176) {
|
||||||
printf("Corrupt PE file - too short\n");
|
fprintf(stderr, "Corrupt PE file - too short\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (memcmp(indata + header_size, "PE\0\0", 4)) {
|
if (memcmp(indata + header_size, "PE\0\0", 4)) {
|
||||||
printf("Unrecognized DOS file type\n");
|
fprintf(stderr, "Unrecognized DOS file type\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* Magic field identifies the state of the image file. The most common number is
|
/* Magic field identifies the state of the image file. The most common number is
|
||||||
@ -636,7 +570,7 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
|
|||||||
} else if (magic == 0x10b) {
|
} else if (magic == 0x10b) {
|
||||||
pe32plus = 0;
|
pe32plus = 0;
|
||||||
} else {
|
} else {
|
||||||
printf("Corrupt PE file - found unknown magic %04X\n", magic);
|
fprintf(stderr, "Corrupt PE file - found unknown magic %04X\n", magic);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* The image file checksum */
|
/* The image file checksum */
|
||||||
@ -645,7 +579,7 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
|
|||||||
* in the remainder of the optional header. Each describes a location and size. */
|
* in the remainder of the optional header. Each describes a location and size. */
|
||||||
nrvas = GET_UINT32_LE(indata + header_size + 116 + pe32plus * 16);
|
nrvas = GET_UINT32_LE(indata + header_size + 116 + pe32plus * 16);
|
||||||
if (nrvas < 5) {
|
if (nrvas < 5) {
|
||||||
printf("Can not handle PE files without certificate table resource\n");
|
fprintf(stderr, "Can not handle PE files without certificate table resource\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* Certificate Table field specifies the attribute certificate table address (4 bytes) and size (4 bytes) */
|
/* Certificate Table field specifies the attribute certificate table address (4 bytes) and size (4 bytes) */
|
||||||
@ -653,14 +587,11 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
|
|||||||
siglen = GET_UINT32_LE(indata + header_size + 152 + pe32plus * 16 + 4);
|
siglen = GET_UINT32_LE(indata + header_size + 152 + pe32plus * 16 + 4);
|
||||||
/* Since fix for MS Bulletin MS12-024 we can really assume
|
/* Since fix for MS Bulletin MS12-024 we can really assume
|
||||||
that signature should be last part of file */
|
that signature should be last part of file */
|
||||||
if ((sigpos > 0 && sigpos < filesize && sigpos + siglen != filesize)
|
if ((sigpos != 0 || siglen != 0) &&
|
||||||
|| (sigpos >= filesize)) {
|
(sigpos == 0 || siglen == 0 || sigpos >= filesize || sigpos + siglen != filesize)) {
|
||||||
printf("Corrupt PE file - current signature not at the end of the file\n");
|
printf("Warning: Ignoring PE signature not at the end of the file\n");
|
||||||
return NULL; /* FAILED */
|
sigpos = 0;
|
||||||
}
|
siglen = 0;
|
||||||
if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) {
|
|
||||||
printf("Corrupt signature\n");
|
|
||||||
return NULL; /* FAILED */
|
|
||||||
}
|
}
|
||||||
pe_ctx = OPENSSL_zalloc(sizeof(PE_CTX));
|
pe_ctx = OPENSSL_zalloc(sizeof(PE_CTX));
|
||||||
pe_ctx->header_size = header_size;
|
pe_ctx->header_size = header_size;
|
||||||
@ -686,7 +617,7 @@ static PKCS7 *pe_pkcs7_get_file(char *indata, PE_CTX *pe_ctx)
|
|||||||
uint32_t pos = 0;
|
uint32_t pos = 0;
|
||||||
|
|
||||||
if (pe_ctx->siglen == 0 || pe_ctx->siglen > pe_ctx->fileend) {
|
if (pe_ctx->siglen == 0 || pe_ctx->siglen > pe_ctx->fileend) {
|
||||||
printf("Corrupted signature length: 0x%08X\n", pe_ctx->siglen);
|
fprintf(stderr, "Corrupted signature length: 0x%08X\n", pe_ctx->siglen);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
while (pos < pe_ctx->siglen) {
|
while (pos < pe_ctx->siglen) {
|
||||||
@ -836,6 +767,62 @@ static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
|||||||
return 1; /* OK */
|
return 1; /* OK */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute a message digest value of a signed or unsigned PE file.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] calculated message digest BIO
|
||||||
|
*/
|
||||||
|
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
size_t written;
|
||||||
|
uint32_t idx = 0, fileend;
|
||||||
|
BIO *bhash = BIO_new(BIO_f_md());
|
||||||
|
|
||||||
|
if (!BIO_set_md(bhash, md)) {
|
||||||
|
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||||
|
if (ctx->pe_ctx->sigpos)
|
||||||
|
fileend = ctx->pe_ctx->sigpos;
|
||||||
|
else
|
||||||
|
fileend = ctx->pe_ctx->fileend;
|
||||||
|
|
||||||
|
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
|
||||||
|
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|
||||||
|
|| written != ctx->pe_ctx->header_size + 88) {
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
idx += (uint32_t)written + 4;
|
||||||
|
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
|
||||||
|
60 + ctx->pe_ctx->pe32plus * 16, &written)
|
||||||
|
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
idx += (uint32_t)written + 8;
|
||||||
|
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
|
||||||
|
fprintf(stderr, "Unable to calculate digest\n");
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!ctx->pe_ctx->sigpos) {
|
||||||
|
/* pad (with 0's) unsigned PE file to 8 byte boundary */
|
||||||
|
int len = 8 - ctx->pe_ctx->fileend % 8;
|
||||||
|
if (len > 0 && len != 8) {
|
||||||
|
char *buf = OPENSSL_malloc(8);
|
||||||
|
memset(buf, 0, (size_t)len);
|
||||||
|
BIO_write(bhash, buf, len);
|
||||||
|
OPENSSL_free(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return bhash;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Page hash support
|
* Page hash support
|
||||||
*/
|
*/
|
||||||
@ -931,7 +918,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
* which immediately follows the headers, can be up to 65535 under Vista and later */
|
* which immediately follows the headers, can be up to 65535 under Vista and later */
|
||||||
nsections = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 6);
|
nsections = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 6);
|
||||||
if (nsections == 0) {
|
if (nsections == 0) {
|
||||||
printf("Corrupted number of sections: 0x%08X\n", nsections);
|
fprintf(stderr, "Corrupted number of sections: 0x%08X\n", nsections);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* FileAlignment is the alignment factor (in bytes) that is used to align
|
/* FileAlignment is the alignment factor (in bytes) that is used to align
|
||||||
@ -939,7 +926,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
* of 2 between 512 and 64 K, inclusive. The default is 512. */
|
* of 2 between 512 and 64 K, inclusive. The default is 512. */
|
||||||
alignment = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 60);
|
alignment = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 60);
|
||||||
if (alignment < 512 || alignment > UINT16_MAX) {
|
if (alignment < 512 || alignment > UINT16_MAX) {
|
||||||
printf("Corrupted file alignment factor: 0x%08X\n", alignment);
|
fprintf(stderr, "Corrupted file alignment factor: 0x%08X\n", alignment);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* SectionAlignment is the alignment (in bytes) of sections when they are
|
/* SectionAlignment is the alignment (in bytes) of sections when they are
|
||||||
@ -949,14 +936,14 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
* https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200 */
|
* https://devblogs.microsoft.com/oldnewthing/20210510-00/?p=105200 */
|
||||||
pagesize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 56);
|
pagesize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 56);
|
||||||
if (pagesize == 0 || pagesize < alignment || pagesize > 4194304) {
|
if (pagesize == 0 || pagesize < alignment || pagesize > 4194304) {
|
||||||
printf("Corrupted page size: 0x%08X\n", pagesize);
|
fprintf(stderr, "Corrupted page size: 0x%08X\n", pagesize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* SizeOfHeaders is the combined size of an MS-DOS stub, PE header,
|
/* SizeOfHeaders is the combined size of an MS-DOS stub, PE header,
|
||||||
* and section headers rounded up to a multiple of FileAlignment. */
|
* and section headers rounded up to a multiple of FileAlignment. */
|
||||||
hdrsize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 84);
|
hdrsize = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->header_size + 84);
|
||||||
if (hdrsize < ctx->pe_ctx->header_size || hdrsize > UINT32_MAX) {
|
if (hdrsize < ctx->pe_ctx->header_size || hdrsize > UINT32_MAX) {
|
||||||
printf("Corrupted headers size: 0x%08X\n", hdrsize);
|
fprintf(stderr, "Corrupted headers size: 0x%08X\n", hdrsize);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
/* SizeOfOptionalHeader is the size of the optional header, which is
|
/* SizeOfOptionalHeader is the size of the optional header, which is
|
||||||
@ -964,7 +951,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
* and can't be bigger than the file */
|
* and can't be bigger than the file */
|
||||||
opthdr_size = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 20);
|
opthdr_size = GET_UINT16_LE(ctx->options->indata + ctx->pe_ctx->header_size + 20);
|
||||||
if (opthdr_size == 0 || opthdr_size > ctx->pe_ctx->fileend) {
|
if (opthdr_size == 0 || opthdr_size > ctx->pe_ctx->fileend) {
|
||||||
printf("Corrupted optional header size: 0x%08X\n", opthdr_size);
|
fprintf(stderr, "Corrupted optional header size: 0x%08X\n", opthdr_size);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
pphlen = 4 + EVP_MD_size(md);
|
pphlen = 4 + EVP_MD_size(md);
|
||||||
@ -972,7 +959,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
|
|
||||||
bhash = BIO_new(BIO_f_md());
|
bhash = BIO_new(BIO_f_md());
|
||||||
if (!BIO_set_md(bhash, md)) {
|
if (!BIO_set_md(bhash, md)) {
|
||||||
printf("Unable to set the message digest of BIO\n");
|
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||||
BIO_free_all(bhash);
|
BIO_free_all(bhash);
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
@ -1019,7 +1006,7 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
PUT_UINT32_LE(ro + l, res + pi*pphlen);
|
PUT_UINT32_LE(ro + l, res + pi*pphlen);
|
||||||
bhash = BIO_new(BIO_f_md());
|
bhash = BIO_new(BIO_f_md());
|
||||||
if (!BIO_set_md(bhash, md)) {
|
if (!BIO_set_md(bhash, md)) {
|
||||||
printf("Unable to set the message digest of BIO\n");
|
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||||
BIO_free_all(bhash);
|
BIO_free_all(bhash);
|
||||||
OPENSSL_free(zeroes);
|
OPENSSL_free(zeroes);
|
||||||
OPENSSL_free(res);
|
OPENSSL_free(res);
|
||||||
@ -1112,7 +1099,7 @@ static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
|
|
||||||
ph = pe_page_hash_calc(&phlen, ctx, phtype);
|
ph = pe_page_hash_calc(&phlen, ctx, phtype);
|
||||||
if (!ph) {
|
if (!ph) {
|
||||||
printf("Failed to calculate page hash\n");
|
fprintf(stderr, "Failed to calculate page hash\n");
|
||||||
return NULL; /* FAILED */
|
return NULL; /* FAILED */
|
||||||
}
|
}
|
||||||
if (ctx->options->verbose)
|
if (ctx->options->verbose)
|
||||||
@ -1172,6 +1159,58 @@ static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype)
|
|||||||
return link;
|
return link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print current and calculated PE checksum,
|
||||||
|
* check if the signature exists.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int pe_check_file(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
uint32_t real_pe_checksum, sum = 0;
|
||||||
|
|
||||||
|
if (!ctx) {
|
||||||
|
fprintf(stderr, "Init error\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
real_pe_checksum = pe_calc_realchecksum(ctx);
|
||||||
|
if (ctx->pe_ctx->pe_checksum == real_pe_checksum) {
|
||||||
|
printf("PE checksum : %08X\n", real_pe_checksum);
|
||||||
|
} else {
|
||||||
|
printf("Current PE checksum : %08X\n", ctx->pe_ctx->pe_checksum);
|
||||||
|
printf("Calculated PE checksum: %08X\n", real_pe_checksum);
|
||||||
|
printf("Warning: invalid PE checksum\n");
|
||||||
|
}
|
||||||
|
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|
||||||
|
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
|
||||||
|
fprintf(stderr, "No signature found\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If the sum of the rounded dwLength values does not equal the Size value,
|
||||||
|
* then either the attribute certificate table or the Size field is corrupted.
|
||||||
|
*/
|
||||||
|
while (sum < ctx->pe_ctx->siglen) {
|
||||||
|
uint32_t len = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->sigpos + sum);
|
||||||
|
if (ctx->pe_ctx->siglen - len > 8) {
|
||||||
|
fprintf(stderr, "Corrupted attribute certificate table\n");
|
||||||
|
fprintf(stderr, "Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
|
||||||
|
fprintf(stderr, "Attribute certificate entry length: %08X\n\n", len);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
/* quadword align data */
|
||||||
|
len += len % 8 ? 8 - len % 8 : 0;
|
||||||
|
sum += len;
|
||||||
|
}
|
||||||
|
if (sum != ctx->pe_ctx->siglen) {
|
||||||
|
fprintf(stderr, "Corrupted attribute certificate table\n");
|
||||||
|
fprintf(stderr, "Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
|
||||||
|
fprintf(stderr, "Sum of the rounded dwLength values: %08X\n\n", sum);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Local Variables:
|
Local Variables:
|
||||||
c-basic-offset: 4
|
c-basic-offset: 4
|
||||||
|
875
script.c
Normal file
875
script.c
Normal file
@ -0,0 +1,875 @@
|
|||||||
|
/*
|
||||||
|
* Script file support library
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021-2024 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "osslsigncode.h"
|
||||||
|
#include "helpers.h"
|
||||||
|
#include "utf.h"
|
||||||
|
|
||||||
|
typedef enum {comment_hash, comment_xml, comment_c, comment_not_found} comment_style;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *extension;
|
||||||
|
comment_style comment;
|
||||||
|
} SCRIPT_FORMAT;
|
||||||
|
|
||||||
|
const SCRIPT_FORMAT supported_formats[] = {
|
||||||
|
{".ps1", comment_hash},
|
||||||
|
{".ps1xml", comment_xml},
|
||||||
|
{".psc1", comment_xml},
|
||||||
|
{".psd1", comment_hash},
|
||||||
|
{".psm1", comment_hash},
|
||||||
|
{".cdxml", comment_xml},
|
||||||
|
{".mof", comment_c},
|
||||||
|
{NULL, comment_not_found},
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *signature_header = "SIG # Begin signature block";
|
||||||
|
const char *signature_footer = "SIG # End signature block";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *open;
|
||||||
|
const char *close;
|
||||||
|
} SCRIPT_COMMENT;
|
||||||
|
|
||||||
|
const SCRIPT_COMMENT comment_text[] = {
|
||||||
|
[comment_hash] = {"# ", ""},
|
||||||
|
[comment_xml] = {"<!-- ", " -->"},
|
||||||
|
[comment_c] = {"/* ", " */"}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct script_ctx_st {
|
||||||
|
const SCRIPT_COMMENT *comment_text;
|
||||||
|
int utf;
|
||||||
|
uint32_t sigpos;
|
||||||
|
uint32_t fileend;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define LINE_MAX_LEN 100
|
||||||
|
|
||||||
|
/* FILE_FORMAT method prototypes */
|
||||||
|
static FILE_FORMAT_CTX *script_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
|
||||||
|
static ASN1_OBJECT *script_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *script_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||||
|
static int script_hash_length_get(FILE_FORMAT_CTX *ctx);
|
||||||
|
static u_char *script_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
|
static int script_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
||||||
|
static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx);
|
||||||
|
static PKCS7 *script_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
|
||||||
|
static int script_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
static int script_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
|
||||||
|
static PKCS7 *script_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||||
|
static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||||
|
static void script_bio_free(BIO *hash, BIO *outdata);
|
||||||
|
static void script_ctx_cleanup(FILE_FORMAT_CTX *ctx);
|
||||||
|
static int script_is_detaching_supported(void);
|
||||||
|
|
||||||
|
FILE_FORMAT file_format_script = {
|
||||||
|
.ctx_new = script_ctx_new,
|
||||||
|
.data_blob_get = script_spc_sip_info_get,
|
||||||
|
.pkcs7_contents_get = script_pkcs7_contents_get,
|
||||||
|
.hash_length_get = script_hash_length_get,
|
||||||
|
.digest_calc = script_digest_calc,
|
||||||
|
.verify_digests = script_verify_digests,
|
||||||
|
.pkcs7_extract = script_pkcs7_extract,
|
||||||
|
.pkcs7_extract_to_nest = script_pkcs7_extract_to_nest,
|
||||||
|
.remove_pkcs7 = script_remove_pkcs7,
|
||||||
|
.process_data = script_process_data,
|
||||||
|
.pkcs7_signature_new = script_pkcs7_signature_new,
|
||||||
|
.append_pkcs7 = script_append_pkcs7,
|
||||||
|
.bio_free = script_bio_free,
|
||||||
|
.ctx_cleanup = script_ctx_cleanup,
|
||||||
|
.is_detaching_supported = script_is_detaching_supported
|
||||||
|
};
|
||||||
|
|
||||||
|
/* helper functions */
|
||||||
|
static SCRIPT_CTX *script_ctx_get(char *indata, uint32_t filesize, const SCRIPT_COMMENT *comment, int utf);
|
||||||
|
static int write_commented(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *data, size_t length);
|
||||||
|
static int write_in_encoding(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *line, size_t length);
|
||||||
|
static size_t utf8_to_utf16(const char *data, size_t len, uint16_t **out_utf16);
|
||||||
|
static size_t utf16_to_utf8(const uint16_t *data, size_t len, char **out_utf8);
|
||||||
|
static BIO *script_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||||
|
static int script_digest_convert(BIO *hash, FILE_FORMAT_CTX *ctx, size_t len);
|
||||||
|
static int script_write_bio(BIO *data, char *indata, size_t len);
|
||||||
|
static int script_check_file(FILE_FORMAT_CTX *ctx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a script file format context.
|
||||||
|
* [in, out] options: structure holds the input data
|
||||||
|
* [out] hash: message digest BIO
|
||||||
|
* [in] outdata: outdata file BIO (unused)
|
||||||
|
* [returns] pointer to script file format context
|
||||||
|
*/
|
||||||
|
static FILE_FORMAT_CTX *script_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata)
|
||||||
|
{
|
||||||
|
FILE_FORMAT_CTX *ctx;
|
||||||
|
SCRIPT_CTX *script_ctx;
|
||||||
|
const SCRIPT_FORMAT *fmt;
|
||||||
|
uint32_t filesize;
|
||||||
|
const uint8_t utf16_bom[] = {0xff, 0xfe};
|
||||||
|
size_t name_len;
|
||||||
|
int utf;
|
||||||
|
|
||||||
|
/* squash the unused parameter warning */
|
||||||
|
(void)outdata;
|
||||||
|
|
||||||
|
/* find out whether our format is supported */
|
||||||
|
name_len = strlen(options->infile);
|
||||||
|
for (fmt = supported_formats; fmt->comment != comment_not_found; fmt++) {
|
||||||
|
size_t ext_len = strlen(fmt->extension);
|
||||||
|
if(name_len > ext_len && !strcasecmp(options->infile + name_len - ext_len, fmt->extension))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fmt->comment == comment_not_found)
|
||||||
|
return NULL;
|
||||||
|
printf("Script file format: %s\n", fmt->extension);
|
||||||
|
|
||||||
|
filesize = get_file_size(options->infile);
|
||||||
|
if (filesize == 0)
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
|
||||||
|
options->indata = map_file(options->infile, filesize);
|
||||||
|
if (!options->indata) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
utf = memcmp(options->indata, utf16_bom, sizeof utf16_bom) ? 8 : 16;
|
||||||
|
|
||||||
|
/* initialize script context */
|
||||||
|
script_ctx = script_ctx_get(options->indata, filesize, comment_text + fmt->comment, utf);
|
||||||
|
if (!script_ctx) {
|
||||||
|
unmap_file(options->indata, filesize);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* initialize file format context */
|
||||||
|
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
||||||
|
memset(ctx, 0, sizeof(FILE_FORMAT_CTX));
|
||||||
|
ctx->format = &file_format_script;
|
||||||
|
ctx->options = options;
|
||||||
|
ctx->script_ctx = script_ctx;
|
||||||
|
|
||||||
|
if (hash)
|
||||||
|
BIO_push(hash, BIO_new(BIO_s_null()));
|
||||||
|
|
||||||
|
/* FIXME: user interface logic belongs to osslsigncode.c */
|
||||||
|
if (options->pagehash == 1)
|
||||||
|
printf("Warning: -ph option is only valid for PE files\n");
|
||||||
|
if (options->jp >= 0)
|
||||||
|
printf("Warning: -jp option is only valid for CAB files\n");
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return SpcSipInfo object.
|
||||||
|
* Subject Interface Package (SIP) is an internal Microsoft API for
|
||||||
|
* transforming arbitrary files into a digestible stream.
|
||||||
|
* These ClassIDs are found in the indirect data section and identify
|
||||||
|
* the type of processor needed to validate the signature.
|
||||||
|
* https://github.com/sassoftware/relic/blob/620d0b75ec67c0158a8a9120950abe04327d922f/lib/authenticode/structs.go#L154
|
||||||
|
* [out] p: SpcSipInfo data
|
||||||
|
* [out] plen: SpcSipInfo data length
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] pointer to ASN1_OBJECT structure corresponding to SPC_SIPINFO_OBJID
|
||||||
|
*/
|
||||||
|
static ASN1_OBJECT *script_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
const u_char SpcUUIDSipInfoPs[] = {
|
||||||
|
0x1f, 0xcc, 0x3b, 0x60, 0x59, 0x4b, 0x08, 0x4e,
|
||||||
|
0xb7, 0x24, 0xd2, 0xc6, 0x29, 0x7e, 0xf3, 0x51
|
||||||
|
};
|
||||||
|
ASN1_OBJECT *dtype;
|
||||||
|
SpcSipInfo *si = SpcSipInfo_new();
|
||||||
|
|
||||||
|
/* squash the unused parameter warning */
|
||||||
|
(void)ctx;
|
||||||
|
|
||||||
|
ASN1_INTEGER_set(si->a, 65536);
|
||||||
|
ASN1_INTEGER_set(si->b, 0);
|
||||||
|
ASN1_INTEGER_set(si->c, 0);
|
||||||
|
ASN1_INTEGER_set(si->d, 0);
|
||||||
|
ASN1_INTEGER_set(si->e, 0);
|
||||||
|
ASN1_INTEGER_set(si->f, 0);
|
||||||
|
ASN1_OCTET_STRING_set(si->string, SpcUUIDSipInfoPs, sizeof SpcUUIDSipInfoPs);
|
||||||
|
*plen = i2d_SpcSipInfo(si, NULL);
|
||||||
|
*p = OPENSSL_malloc((size_t)*plen);
|
||||||
|
i2d_SpcSipInfo(si, p);
|
||||||
|
*p -= *plen;
|
||||||
|
dtype = OBJ_txt2obj(SPC_SIPINFO_OBJID, 1);
|
||||||
|
SpcSipInfo_free(si);
|
||||||
|
return dtype; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Allocate and return a data content to be signed.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] hash: message digest BIO
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] data content
|
||||||
|
*/
|
||||||
|
static PKCS7 *script_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
BIO *bhash;
|
||||||
|
|
||||||
|
/* squash the unused parameter warning */
|
||||||
|
(void)hash;
|
||||||
|
|
||||||
|
bhash = script_digest_calc_bio(ctx, md);
|
||||||
|
if (!bhash) {
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(bhash, ctx);
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
return pkcs7_set_content(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int script_hash_length_get(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
return EVP_MD_size(ctx->options->md);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute a simple sha1/sha256 message digest of the MSI file
|
||||||
|
* for use with a catalog file.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] pointer to calculated message digest
|
||||||
|
*/
|
||||||
|
static u_char *script_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
u_char *mdbuf;
|
||||||
|
BIO *hash = BIO_new(BIO_f_md());
|
||||||
|
|
||||||
|
if (!BIO_set_md(hash, md)) {
|
||||||
|
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||||
|
BIO_free_all(hash);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
BIO_push(hash, BIO_new(BIO_s_null()));
|
||||||
|
if (!script_write_bio(hash, ctx->options->indata, ctx->script_ctx->fileend)) {
|
||||||
|
BIO_free_all(hash);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
|
||||||
|
BIO_gets(hash, (char*)mdbuf, EVP_MD_size(md));
|
||||||
|
BIO_free_all(hash);
|
||||||
|
return mdbuf; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate the hash and compare to PKCS#7 signedData.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] p7: PKCS#7 signature
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int script_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
||||||
|
{
|
||||||
|
int mdtype = -1;
|
||||||
|
u_char mdbuf[EVP_MAX_MD_SIZE];
|
||||||
|
u_char *cmdbuf = NULL;
|
||||||
|
const EVP_MD *md;
|
||||||
|
BIO *bhash;
|
||||||
|
|
||||||
|
/* FIXME: this shared code most likely belongs in osslsigncode.c */
|
||||||
|
if (is_content_type(p7, SPC_INDIRECT_DATA_OBJID)) {
|
||||||
|
ASN1_STRING *content_val = p7->d.sign->contents->d.other->value.sequence;
|
||||||
|
const u_char *p = content_val->data;
|
||||||
|
SpcIndirectDataContent *idc = d2i_SpcIndirectDataContent(NULL, &p, content_val->length);
|
||||||
|
if (idc) {
|
||||||
|
if (idc->messageDigest && idc->messageDigest->digest && idc->messageDigest->digestAlgorithm) {
|
||||||
|
mdtype = OBJ_obj2nid(idc->messageDigest->digestAlgorithm->algorithm);
|
||||||
|
memcpy(mdbuf, idc->messageDigest->digest->data, (size_t)idc->messageDigest->digest->length);
|
||||||
|
}
|
||||||
|
SpcIndirectDataContent_free(idc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mdtype == -1) {
|
||||||
|
fprintf(stderr, "Failed to extract current message digest\n\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
md = EVP_get_digestbynid(mdtype);
|
||||||
|
bhash = script_digest_calc_bio(ctx, md);
|
||||||
|
if (!bhash)
|
||||||
|
return 0; /* FAILED */
|
||||||
|
|
||||||
|
cmdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
|
||||||
|
BIO_gets(bhash, (char*)cmdbuf, EVP_MD_size(md));
|
||||||
|
BIO_free_all(bhash);
|
||||||
|
|
||||||
|
if (!compare_digests(mdbuf, cmdbuf, mdtype)) {
|
||||||
|
fprintf(stderr, "Signature verification: failed\n\n");
|
||||||
|
OPENSSL_free(cmdbuf);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
OPENSSL_free(cmdbuf);
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract existing signature in DER format.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] pointer to PKCS#7 structure
|
||||||
|
*/
|
||||||
|
static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
const char *signature_data = ctx->options->indata + ctx->script_ctx->sigpos;
|
||||||
|
size_t signature_len = ctx->script_ctx->fileend - ctx->script_ctx->sigpos;
|
||||||
|
size_t base64_len;
|
||||||
|
char *ptr;
|
||||||
|
BIO *bio_mem, *bio_b64 = NULL;
|
||||||
|
char *base64_data = NULL;
|
||||||
|
char *clean_base64 = NULL;
|
||||||
|
int clean_base64_len = 0;
|
||||||
|
const char *open_tag = ctx->script_ctx->comment_text->open;
|
||||||
|
const char *close_tag = ctx->script_ctx->comment_text->close;
|
||||||
|
size_t open_tag_len = strlen(open_tag);
|
||||||
|
size_t close_tag_len = strlen(close_tag);
|
||||||
|
size_t signature_header_len = strlen(signature_header);
|
||||||
|
size_t signature_footer_len = strlen(signature_footer);
|
||||||
|
PKCS7 *retval = NULL;
|
||||||
|
|
||||||
|
if (!script_check_file(ctx)) {
|
||||||
|
return NULL; /* FAILED, no signature */
|
||||||
|
}
|
||||||
|
/* extract Base64 signature */
|
||||||
|
if (ctx->script_ctx->utf == 8) {
|
||||||
|
base64_len = signature_len;
|
||||||
|
base64_data = OPENSSL_malloc(base64_len);
|
||||||
|
memcpy(base64_data, signature_data, base64_len);
|
||||||
|
} else {
|
||||||
|
base64_len = utf16_to_utf8((const void *)signature_data,
|
||||||
|
signature_len, &base64_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* allocate memory for cleaned Base64 */
|
||||||
|
clean_base64 = OPENSSL_malloc(base64_len);
|
||||||
|
if (!clean_base64) {
|
||||||
|
fprintf(stderr, "Malloc failed\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* copy clean Base64 data */
|
||||||
|
for (ptr = base64_data;;) {
|
||||||
|
/* find the opening tag */
|
||||||
|
for(;;) {
|
||||||
|
if (ptr + open_tag_len >= base64_data + base64_len) {
|
||||||
|
fprintf(stderr, "Signature line too long\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (!memcmp(ptr, open_tag, (size_t)open_tag_len)) {
|
||||||
|
ptr += open_tag_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
ptr++;
|
||||||
|
}
|
||||||
|
/* process signature_header and signature_footer */
|
||||||
|
if (ptr + signature_header_len < base64_data + base64_len &&
|
||||||
|
!memcmp(ptr, signature_header, signature_header_len))
|
||||||
|
ptr += signature_header_len;
|
||||||
|
if (ptr + signature_footer_len <= base64_data + base64_len &&
|
||||||
|
!memcmp(ptr, signature_footer, signature_footer_len))
|
||||||
|
break; /* success */
|
||||||
|
|
||||||
|
/* copy until the closing tag */
|
||||||
|
for(;;) {
|
||||||
|
if (ptr + close_tag_len >= base64_data + base64_len) {
|
||||||
|
fprintf(stderr, "Signature line too long\n");
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
if (close_tag_len) {
|
||||||
|
if (!memcmp(ptr, close_tag, (size_t)close_tag_len)) {
|
||||||
|
ptr += close_tag_len;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (*ptr == '\r') {
|
||||||
|
ptr++;
|
||||||
|
} else if (*ptr == '\n') {
|
||||||
|
ptr++;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
clean_base64[clean_base64_len++] = *ptr++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare for Base64 decoding */
|
||||||
|
bio_mem = BIO_new_mem_buf(clean_base64, clean_base64_len);
|
||||||
|
bio_b64 = BIO_new(BIO_f_base64());
|
||||||
|
BIO_push(bio_b64, bio_mem);
|
||||||
|
BIO_set_flags(bio_b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
|
||||||
|
/* decode DER */
|
||||||
|
retval = d2i_PKCS7_bio(bio_b64, NULL);
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
OPENSSL_free(base64_data);
|
||||||
|
OPENSSL_free(clean_base64);
|
||||||
|
BIO_free_all(bio_b64);
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Extract existing signature in DER format.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [returns] pointer to PKCS#7 structure
|
||||||
|
*/
|
||||||
|
static PKCS7 *script_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
return script_pkcs7_extract(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Remove existing signature.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] hash: message digest BIO
|
||||||
|
* [out] outdata: outdata file BIO
|
||||||
|
* [returns] 1 on error or 0 on success
|
||||||
|
*/
|
||||||
|
static int script_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
|
{
|
||||||
|
/* squash the unused parameter warning */
|
||||||
|
(void)hash;
|
||||||
|
if (!script_check_file(ctx)) {
|
||||||
|
return 1; /* FAILED, no signature */
|
||||||
|
}
|
||||||
|
if (!script_write_bio(outdata, ctx->options->indata, ctx->script_ctx->sigpos)) {
|
||||||
|
return 1; /* FAILED */
|
||||||
|
}
|
||||||
|
return 0; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize outdata file and calculate a hash (message digest) of data.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] hash: message digest BIO
|
||||||
|
* [out] outdata: outdata file BIO
|
||||||
|
* [returns] 1 on error or 0 on success
|
||||||
|
*/
|
||||||
|
static int script_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
|
||||||
|
{
|
||||||
|
if (ctx->script_ctx->sigpos > 0) {
|
||||||
|
/* Strip current signature */
|
||||||
|
ctx->script_ctx->fileend = ctx->script_ctx->sigpos;
|
||||||
|
}
|
||||||
|
if (!script_write_bio(outdata, ctx->options->indata, ctx->script_ctx->fileend))
|
||||||
|
return 0; /* FAILED */
|
||||||
|
if (!script_digest_convert(hash, ctx, ctx->script_ctx->fileend))
|
||||||
|
return 0; /* FAILED */
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Create a new PKCS#7 signature.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] hash: message digest BIO
|
||||||
|
* [returns] pointer to PKCS#7 structure
|
||||||
|
*/
|
||||||
|
static PKCS7 *script_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||||
|
{
|
||||||
|
ASN1_OCTET_STRING *content;
|
||||||
|
PKCS7 *p7 = pkcs7_create(ctx);
|
||||||
|
|
||||||
|
if (!p7) {
|
||||||
|
fprintf(stderr, "Creating a new signature failed\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!add_indirect_data_object(p7)) {
|
||||||
|
fprintf(stderr, "Adding SPC_INDIRECT_DATA_OBJID failed\n");
|
||||||
|
PKCS7_free(p7);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
content = spc_indirect_data_content_get(hash, ctx);
|
||||||
|
if (!content) {
|
||||||
|
fprintf(stderr, "Failed to get spcIndirectDataContent\n");
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
if (!sign_spc_indirect_data_content(p7, content)) {
|
||||||
|
fprintf(stderr, "Failed to set signed content\n");
|
||||||
|
PKCS7_free(p7);
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
ASN1_OCTET_STRING_free(content);
|
||||||
|
return p7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Append signature to the outfile.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] outdata: outdata file BIO
|
||||||
|
* [in] p7: PKCS#7 signature
|
||||||
|
* [returns] 1 on error or 0 on success
|
||||||
|
*/
|
||||||
|
static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||||
|
{
|
||||||
|
BIO *bio, *b64;
|
||||||
|
BUF_MEM *buffer;
|
||||||
|
size_t i;
|
||||||
|
static const char crlf[] = {0x0d, 0x0a};
|
||||||
|
int ret = 1;
|
||||||
|
|
||||||
|
/* convert to BASE64 */
|
||||||
|
b64 = BIO_new(BIO_f_base64()); /* BIO for base64 encoding */
|
||||||
|
if (!b64)
|
||||||
|
return 1; /* FAILED */
|
||||||
|
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
|
||||||
|
bio = BIO_new(BIO_s_mem()); /* BIO to hold the base64 data */
|
||||||
|
if (!bio) {
|
||||||
|
BIO_free(b64);
|
||||||
|
return 1; /* FAILED */
|
||||||
|
}
|
||||||
|
bio = BIO_push(b64, bio); /* chain base64 BIO onto memory BIO */
|
||||||
|
if (!i2d_PKCS7_bio(bio, p7)) {
|
||||||
|
BIO_free_all(bio);
|
||||||
|
return 1; /* FAILED */
|
||||||
|
}
|
||||||
|
(void)BIO_flush(bio);
|
||||||
|
BIO_get_mem_ptr(bio, &buffer);
|
||||||
|
(void)BIO_set_close(bio, BIO_NOCLOSE);
|
||||||
|
|
||||||
|
/* split to individual lines and write to outdata */
|
||||||
|
if (!write_commented(ctx, outdata, signature_header, strlen(signature_header)))
|
||||||
|
goto cleanup;
|
||||||
|
for (i = 0; i < buffer->length; i += 64) {
|
||||||
|
if (!write_commented(ctx, outdata, buffer->data + i,
|
||||||
|
buffer->length - i < 64 ? buffer->length - i : 64)) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!write_commented(ctx, outdata, signature_footer, strlen(signature_footer)))
|
||||||
|
goto cleanup;
|
||||||
|
|
||||||
|
/* signtool expects CRLF terminator at the end of the text file */
|
||||||
|
if (!write_in_encoding(ctx, outdata, crlf, sizeof crlf))
|
||||||
|
goto cleanup;
|
||||||
|
ret = 0; /* OK */
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
BUF_MEM_free(buffer);
|
||||||
|
BIO_free_all(bio);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Free up an entire outdata BIO chain.
|
||||||
|
* [out] hash: message digest BIO
|
||||||
|
* [out] outdata: outdata file BIO
|
||||||
|
* [returns] none
|
||||||
|
*/
|
||||||
|
static void script_bio_free(BIO *hash, BIO *outdata)
|
||||||
|
{
|
||||||
|
BIO_free_all(hash);
|
||||||
|
BIO_free_all(outdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Deallocate a FILE_FORMAT_CTX structure and script format specific structures.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [out] hash: message digest BIO
|
||||||
|
* [out] outdata: outdata file BIO
|
||||||
|
* [returns] none
|
||||||
|
*/
|
||||||
|
static void script_ctx_cleanup(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
unmap_file(ctx->options->indata, ctx->script_ctx->fileend);
|
||||||
|
OPENSSL_free(ctx->script_ctx);
|
||||||
|
OPENSSL_free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int script_is_detaching_supported(void)
|
||||||
|
{
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Script helper functions
|
||||||
|
*/
|
||||||
|
|
||||||
|
static SCRIPT_CTX *script_ctx_get(char *indata, uint32_t filesize, const SCRIPT_COMMENT *comment, int utf)
|
||||||
|
{
|
||||||
|
SCRIPT_CTX *script_ctx;
|
||||||
|
|
||||||
|
const char *input_pos, *signature_pos, *ptr;
|
||||||
|
uint32_t line[LINE_MAX_LEN], commented_header[40], cr, lf;
|
||||||
|
size_t sig_pos = 0, line_pos = 0, commented_header_len = 0;
|
||||||
|
size_t commented_header_size = sizeof commented_header / sizeof(uint32_t);
|
||||||
|
|
||||||
|
utf8DecodeRune("\r", 1, &cr);
|
||||||
|
utf8DecodeRune("\n", 1, &lf);
|
||||||
|
|
||||||
|
/* compute runes for the commented signature header */
|
||||||
|
for (ptr = comment->open;
|
||||||
|
*ptr && commented_header_len < commented_header_size;
|
||||||
|
commented_header_len++)
|
||||||
|
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
|
||||||
|
for (ptr = signature_header;
|
||||||
|
*ptr && commented_header_len < commented_header_size;
|
||||||
|
commented_header_len++)
|
||||||
|
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
|
||||||
|
for (ptr = comment->close;
|
||||||
|
*ptr && commented_header_len < commented_header_size;
|
||||||
|
commented_header_len++)
|
||||||
|
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
|
||||||
|
|
||||||
|
/* find the signature header */
|
||||||
|
for (signature_pos = input_pos = indata; input_pos < indata + filesize; ) {
|
||||||
|
const char *input_prev = input_pos;
|
||||||
|
|
||||||
|
input_pos = utf == 8 ?
|
||||||
|
utf8DecodeRune(input_pos,
|
||||||
|
(size_t)(indata + filesize - input_pos),
|
||||||
|
line + line_pos) :
|
||||||
|
(const char *)utf16DecodeRune((const void *)input_pos,
|
||||||
|
(size_t)(indata + filesize - input_pos)/2,
|
||||||
|
line + line_pos);
|
||||||
|
|
||||||
|
if (!memcmp(line + line_pos, &lf, sizeof lf)) {
|
||||||
|
if (line_pos >= commented_header_len &&
|
||||||
|
!memcmp(line, commented_header, commented_header_len * sizeof(uint32_t))) {
|
||||||
|
sig_pos = (size_t)(signature_pos - indata);
|
||||||
|
if (!memcmp(line + line_pos - 1, &cr, sizeof cr))
|
||||||
|
sig_pos -= (size_t)utf / 8;
|
||||||
|
break; /* SUCCEEDED */
|
||||||
|
}
|
||||||
|
line_pos = 0;
|
||||||
|
signature_pos = input_prev; /* previous line */
|
||||||
|
} else if (line_pos < LINE_MAX_LEN - 1) {
|
||||||
|
line_pos++; /* we can ignore lines longer than our buffer */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("Signature position: %zu\n", sig_pos);
|
||||||
|
|
||||||
|
script_ctx = OPENSSL_malloc(sizeof(SCRIPT_CTX));
|
||||||
|
script_ctx->comment_text = comment;
|
||||||
|
script_ctx->utf = utf;
|
||||||
|
script_ctx->fileend = filesize;
|
||||||
|
script_ctx->sigpos = (uint32_t)sig_pos;
|
||||||
|
return script_ctx; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* write a commented line to the bio:
|
||||||
|
* - prepend with CRLF ("\r\n")
|
||||||
|
* - add opening/closing comment tags
|
||||||
|
* - adjust encoding if needed
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int write_commented(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *data, size_t length)
|
||||||
|
{
|
||||||
|
const char *open_tag = ctx->script_ctx->comment_text->open;
|
||||||
|
const char *close_tag = ctx->script_ctx->comment_text->close;
|
||||||
|
size_t open_tag_len = strlen(open_tag);
|
||||||
|
size_t close_tag_len = strlen(close_tag);
|
||||||
|
char *line;
|
||||||
|
|
||||||
|
/* the buffer needs to be long enough for:
|
||||||
|
* - CRLF ("\r\n")
|
||||||
|
* - opening tag
|
||||||
|
* - up to 64 bytes of data
|
||||||
|
* - closing tag
|
||||||
|
* - trailing NUL ("\0") */
|
||||||
|
line = OPENSSL_malloc(2 + open_tag_len + length + close_tag_len + 1);
|
||||||
|
strcpy(line, "\r\n");
|
||||||
|
strcat(line, open_tag);
|
||||||
|
memcpy(line + 2 + open_tag_len, data, length);
|
||||||
|
line[2 + open_tag_len + length] = '\0';
|
||||||
|
strcat(line, close_tag);
|
||||||
|
|
||||||
|
/* adjust encoding */
|
||||||
|
if (!write_in_encoding(ctx, outdata, line, strlen(line))) {
|
||||||
|
OPENSSL_free(line);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
OPENSSL_free(line);
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* adjust encoding if needed
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int write_in_encoding(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *line, size_t length)
|
||||||
|
{
|
||||||
|
size_t written;
|
||||||
|
if (ctx->script_ctx->utf == 8) {
|
||||||
|
if (!BIO_write_ex(outdata, line, length, &written)
|
||||||
|
|| written != length) {
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
uint16_t *utf16_data = NULL;
|
||||||
|
size_t utf16_len = utf8_to_utf16(line, length, &utf16_data);
|
||||||
|
|
||||||
|
if (!BIO_write_ex(outdata, utf16_data, utf16_len, &written)
|
||||||
|
|| written != utf16_len) {
|
||||||
|
OPENSSL_free(utf16_data);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
OPENSSL_free(utf16_data);
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert len bytes of UTF-8 to UTF-16
|
||||||
|
* return the number of output bytes
|
||||||
|
*/
|
||||||
|
static size_t utf8_to_utf16(const char *data, size_t len, uint16_t **out_utf16)
|
||||||
|
{
|
||||||
|
size_t utf16_len = utf8UTF16Count(data, len);
|
||||||
|
*out_utf16 = OPENSSL_malloc(utf16_len * sizeof(uint16_t));
|
||||||
|
if (!*out_utf16)
|
||||||
|
return 0; /* memory allocation failed */
|
||||||
|
|
||||||
|
const char *s = data;
|
||||||
|
uint16_t *d = *out_utf16;
|
||||||
|
uint32_t rune;
|
||||||
|
size_t remaining_len = len;
|
||||||
|
|
||||||
|
while (remaining_len > 0) {
|
||||||
|
s = utf8DecodeRune(s, remaining_len, &rune);
|
||||||
|
if (!s || s < data)
|
||||||
|
break; /* invalid UTF-8 sequence */
|
||||||
|
size_t consumed = (size_t)(s - data);
|
||||||
|
|
||||||
|
remaining_len -= consumed;
|
||||||
|
data = s;
|
||||||
|
d += utf16EncodeRune(rune, d);
|
||||||
|
}
|
||||||
|
return (size_t)(2 * (d - *out_utf16));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* convert len bytes of UTF-16 to UTF-8
|
||||||
|
* return the number of output bytes
|
||||||
|
*/
|
||||||
|
static size_t utf16_to_utf8(const uint16_t *data, size_t len, char **out_utf8)
|
||||||
|
{
|
||||||
|
size_t utf8_len = utf16UTF8Count(data, len/2);
|
||||||
|
*out_utf8 = OPENSSL_malloc(utf8_len);
|
||||||
|
if (!*out_utf8)
|
||||||
|
return 0; /* memory allocation failed */
|
||||||
|
|
||||||
|
const uint16_t *s = data;
|
||||||
|
char *d = *out_utf8;
|
||||||
|
uint32_t rune;
|
||||||
|
size_t remaining_len = len/2;
|
||||||
|
|
||||||
|
while (remaining_len > 0) {
|
||||||
|
s = utf16DecodeRune(s, remaining_len, &rune);
|
||||||
|
if (!s || s < data)
|
||||||
|
break; /* invalid UTF-16 sequence */
|
||||||
|
size_t consumed = (size_t)(s - data);
|
||||||
|
|
||||||
|
remaining_len -= consumed;
|
||||||
|
data = s;
|
||||||
|
d += utf8EncodeRune(rune, d);
|
||||||
|
}
|
||||||
|
return (size_t)(d - *out_utf8);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute a message digest value of a signed or unsigned script file.
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] md: message digest algorithm
|
||||||
|
* [returns] calculated message digest BIO
|
||||||
|
*/
|
||||||
|
static BIO *script_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||||
|
{
|
||||||
|
size_t fileend;
|
||||||
|
BIO *hash = BIO_new(BIO_f_md());
|
||||||
|
|
||||||
|
if (ctx->script_ctx->sigpos)
|
||||||
|
fileend = ctx->script_ctx->sigpos;
|
||||||
|
else
|
||||||
|
fileend = ctx->script_ctx->fileend;
|
||||||
|
|
||||||
|
if (!BIO_set_md(hash, md)) {
|
||||||
|
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||||
|
BIO_free_all(hash);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
BIO_push(hash, BIO_new(BIO_s_null()));
|
||||||
|
if (!script_digest_convert(hash, ctx, fileend)) {
|
||||||
|
fprintf(stderr, "Unable calc a message digest value\n");
|
||||||
|
BIO_free_all(hash);
|
||||||
|
return NULL; /* FAILED */
|
||||||
|
}
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Compute a message digest value
|
||||||
|
* [in, out] hash: message digest BIO
|
||||||
|
* [in] ctx: structure holds input and output data
|
||||||
|
* [in] len: mapped file length
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int script_digest_convert(BIO *hash, FILE_FORMAT_CTX *ctx, size_t len)
|
||||||
|
{
|
||||||
|
if (ctx->script_ctx->utf == 8) { /* need to convert to UTF-16 */
|
||||||
|
uint16_t *utf16_data = NULL;
|
||||||
|
size_t utf16_len = utf8_to_utf16(ctx->options->indata,
|
||||||
|
len, &utf16_data);
|
||||||
|
|
||||||
|
if (!script_write_bio(hash, (char *)utf16_data, utf16_len)) {
|
||||||
|
OPENSSL_free(utf16_data);
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
OPENSSL_free(utf16_data);
|
||||||
|
} else { /* already UTF-16 -> no need to convert */
|
||||||
|
if (!script_write_bio(hash, ctx->options->indata, len)) {
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Write len bytes from data to BIO
|
||||||
|
* [in, out] bio: message digest or outdata BIO
|
||||||
|
* [in] indata: mapped file
|
||||||
|
* [in] len: indata length
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int script_write_bio(BIO *bio, char *indata, size_t len)
|
||||||
|
{
|
||||||
|
size_t i = 0, written;
|
||||||
|
|
||||||
|
while (len > 0) {
|
||||||
|
if (!BIO_write_ex(bio, indata + i, len, &written))
|
||||||
|
return 0; /* FAILED */
|
||||||
|
len -= written;
|
||||||
|
i += written;
|
||||||
|
}
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check if the signature exists.
|
||||||
|
* [in, out] ctx: structure holds input and output data
|
||||||
|
* [returns] 0 on error or 1 on success
|
||||||
|
*/
|
||||||
|
static int script_check_file(FILE_FORMAT_CTX *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
fprintf(stderr, "Init error\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
if (ctx->script_ctx->sigpos == 0
|
||||||
|
|| ctx->script_ctx->sigpos > ctx->script_ctx->fileend) {
|
||||||
|
fprintf(stderr, "No signature found\n");
|
||||||
|
return 0; /* FAILED */
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1; /* OK */
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Local Variables:
|
||||||
|
c-basic-offset: 4
|
||||||
|
tab-width: 4
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
End:
|
||||||
|
|
||||||
|
vim: set ts=4 expandtab:
|
||||||
|
*/
|
2
tests/.gitignore
vendored
Normal file
2
tests/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
__pycache__
|
||||||
|
.pylintrc
|
@ -1,22 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDoTCCAomgAwIBAgIUfuEVHNA/1VLDJI9mhANrBndIj6swDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTcwMTAxMDAwMDAwWhcNMjYxMTEwMDAwMDAwWjBYMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEQMA4GA1UEAwwHUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
|
||||||
AQoCggEBAMRykK9mZCSpkVUbCq1r12OXvIDkcjj+g4JpyZOrmPpz5RvmLvYBBgeV
|
|
||||||
IsUcqHm3/uSLpOFu/pwFJ2CBZVPJ1d49Y9DVnNR1dUbneWX9tE7A6NV9IG1kVagM
|
|
||||||
veI/ANLuRi0H51aAZS9L8c6WxlR4+pxJoCZp1tyTGmfjxzBEXUWvyUrIMrW/r9TH
|
|
||||||
u5gGgR6k86EbH7q71XRLhLeEi9QGCG24gobngYNZa5mb8DgLCkUeFtRsrYGEUT0G
|
|
||||||
HTpAGXUrpAb3U7+4LkGaS6mc0NPTW4lz06Z3VhyYwwAbgU2DZQjMpqYWv6UctOP+
|
|
||||||
5elPDc/PrTAdHAgbOhgvt1HUlqgn7lUCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB
|
|
||||||
/zAdBgNVHQ4EFgQUWIpzlJI+vefcJwcNGHwwRms/2ncwHwYDVR0jBBgwFoAUWIpz
|
|
||||||
lJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA
|
|
||||||
A4IBAQAl+G1nXXW5u3notmAG5y8kwufFqNi5Jn1HVbT08w4IiteWMw3D9GEOCueM
|
|
||||||
g5A03bC/Xv1PRvMatXQSARRvvVl3y1l98sA+97SP/FFUla3W5Rn91OsWd4qkcXhv
|
|
||||||
CtPKHpz0SCjKLv3HG/C7fBJPG9XHMgkGZarM2KsQUlkn7DjdBccYcp/zJvtvm+be
|
|
||||||
nR5ZqE6LI52WCXg0w/KlJlildU5LE/bvHbfmRUVm/4GhUNN8ko8eG67ueuftkeTD
|
|
||||||
banKmnuSay02I42A0th2w8Hz7oaOUEpl8S9TfqeFuqLhtUP0FzUNMPAg0o5YTpe4
|
|
||||||
xAArbPbFvH2l3plEaYccKYvbAGT/
|
|
||||||
-----END CERTIFICATE-----
|
|
Binary file not shown.
@ -1,13 +0,0 @@
|
|||||||
-----BEGIN X509 CRL-----
|
|
||||||
MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJQTDEVMBMGA1UE
|
|
||||||
CgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
|
|
||||||
eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBFw0xOTAxMDEwMDAwMDBaFw00MzAx
|
|
||||||
MDEwMDAwMDBaMCcwJQIUSXAaPeUatfheDTFo77LnMBHgyeMXDTIzMDQyODEyMzMz
|
|
||||||
OVqgMDAuMB8GA1UdIwQYMBaAFOP6v42ECbVR/AiLDZ7f2WKtYXILMAsGA1UdFAQE
|
|
||||||
AgIQATANBgkqhkiG9w0BAQsFAAOCAQEARMWBcG6sanX3nwoSPGcUNEkYG2+qB8/w
|
|
||||||
wlcWWY7RfOGQWVHqbVvklJdTYFDw+mA6RuATMOd5S6hXa8tms4L2YQUmYyfNOyJu
|
|
||||||
+INPDnqueQshFZ8PqBTaP6O/NRI/LOLpcIIohgemwfPYPrbd/JqcLlQ2Vbgb9Lnb
|
|
||||||
CYZWGOF7AKC0ugTTvLuWr9LPwmWFdORtmm3UJfFOPDX6zmHPAPhBUuyrxl8UoNZB
|
|
||||||
ZPvgeBjbyQy3MaJsbaniwoOahmT+MbYV/0/YRwI5XDxjiOdJSBz3Wd5YDNDozvG6
|
|
||||||
zZMHtF9TkUZjmLUe3Jm0GnS33gU8SB6YdYpnnPg+Up4w5sye90pk9A==
|
|
||||||
-----END X509 CRL-----
|
|
@ -1,14 +0,0 @@
|
|||||||
-----BEGIN X509 CRL-----
|
|
||||||
MIICMzCCARsCAQEwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UEBhMCUEwxFTATBgNV
|
|
||||||
BAoMDG9zc2xzaWduY29kZTEgMB4GA1UECwwXQ2VydGlmaWNhdGlvbiBBdXRob3Jp
|
|
||||||
dHkxHzAdBgNVBAMMFkludGVybWVkaWF0ZSBDQSBDUkwgRFAXDTE5MDEwMTAwMDAw
|
|
||||||
MFoXDTQzMDEwMTAwMDAwMFowTjAlAhQxdzwUXgMSEn/RzOwbdKtxlLgYJhcNMjMw
|
|
||||||
NDI4MTIzMzQwWjAlAhRJcBo95Rq1+F4NMWjvsucwEeDJ4xcNMjMwNDI4MTIzMzM5
|
|
||||||
WqAwMC4wHwYDVR0jBBgwFoAUYbtAOknHjmiu3l8ONAUY387kFi8wCwYDVR0UBAQC
|
|
||||||
AhACMA0GCSqGSIb3DQEBCwUAA4IBAQBOPbjiBQ1jOEjfQ1Q3/DBfzFKxeL7Cdoiq
|
|
||||||
6l1psqamZRTmU0a+1qRH/qokB0gA1XeeYIZRcruthHDk87F+WZPCKIr5cqfH2RFA
|
|
||||||
xjDEkwgA8OZSdSMh+ZhBLBoGjZhFdnX/FknMcA23cLnzuv4RmsbiokwWrysebDNY
|
|
||||||
DbTQpa/OFvqmHmgXbhrBqUinF7gl1ppzXs/d+FjSg1aAre/lx3KEXCgc126kldS9
|
|
||||||
9+c//UPmltYB17ipVWBmVOyVHNphnHtqPElD9Gz1DooVZ1opsqRBh0APu7fqmm6A
|
|
||||||
5d/lvNlPrlu835/fgUF3YmyU+w4x5sQCBjprTD6QIbIzCXDXfpBj
|
|
||||||
-----END X509 CRL-----
|
|
@ -1,28 +0,0 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDhMfTdugKYNDCN
|
|
||||||
opsz9rTpYF710kq3fDN3JdmEFPoZfhZ58CBm+iZBJRCc8KoXMbKAgAZsFaUyU63M
|
|
||||||
07fYIxJeu3CTOi7kFQRy5bfGrEOnTBMKUqR+KcOZNeNYtfkv4eca25AtTyziJeBV
|
|
||||||
TOqDoVG5x75ad0+Ab4xA9bhbN4+7m5jS1aJeHtj8eDBkJOIOKGbZ0WEstffAIzWO
|
|
||||||
qCC+YFqxsXLO2hOxRgxgpsY9Va4bynn6HW0FZUcUQGEDH0Y17o2KInSyYASad7VI
|
|
||||||
F5jjiJnAzzvU701URZ7kjJFGbT9W7523Ljytl/Mvg+5qTG5JNQjVDsWHte6j1Kq8
|
|
||||||
bAHpZ6NjAgMBAAECggEBAKDpXmv1FxeE61C5aSc3WMwNxaznZ+Y2RFwV2phrmM4Q
|
|
||||||
b6UP9Uc/5YfVIUrTGObb5w207WHcEZ+ldWIPwqUZYm34h5dcEtd9QSGMjcXTn7/y
|
|
||||||
NwTASrOvygk3HU1tMjKJu+ZQD3Sgx5SMtgCdplEKO2iBlr3z1QYULubX7bSYPgcx
|
|
||||||
7sOOpEpITayd8HdOkqkqUvLKxAW5xhL2AzBQHaJiGL/zaW0uKEoOVuTrhNw4+Lnw
|
|
||||||
2IYGrdXpGLAd6hno4kOg2ZkJKWA4Yd+adroeV3BjJ2G1hLJAbPDtS/uB4ZnT1zQx
|
|
||||||
OlkqiPgnoH+16I+aLOs7MvIwQ7VRdF46Exk/9qIdHEECgYEA/sUoOQya1/JgPpbd
|
|
||||||
QeAViTvu9vCFJCnJMkyobG/CVHRDIsNwE/CpaQE+vCn/LpUeKD1KCHIjTOvLF4HM
|
|
||||||
CHt9SECApJESIdexKGP6DVoW+xnomojN/k0YW1JkrnXqmvDw5u/nvFz/JPncKZzB
|
|
||||||
+Ahx6ocORz+t10V8IRn6SlN0E4MCgYEA4khANwZ0Ys0CwVJkx5+mX3ukgXGsLDcB
|
|
||||||
p1bGrnXhbZOiZxxeWjbR/7b4PyAzsoqxiC/F3RGnU5TEPGnUUeGWv8UFsVsgd8tG
|
|
||||||
QvTOC5iEio6fs/IPZK4Asy4a5ByX6bXjbqSnypN+vf+9lFOvI/+yZ9zKejdoD5Xw
|
|
||||||
k150XRhWyqECfzDDi+9fekPbIJDaT39MZNLfpd2eK93AIcJ+6b3XplqD5lXBErK+
|
|
||||||
Xa67jkZ1w2InKJ6LHKCBOECA4V6eeW8mM9Sgg/77xXy0zDPu7u2fUMa/LsZlaQhD
|
|
||||||
uWXBX4QFDeKaO4H4aWKkajGpoXpVhsry0tsQ/qqkhaGuqxOq5T1Uu+MCgYEAhz2J
|
|
||||||
a5mm+9ntmJ9m7kxDwnOCWX8X2QEzMtFRQ7nedoAzIw84cRCsp/myGwBjBYWRH4T1
|
|
||||||
6+9+Ix0Zv8W8iQeb8peNlHeTSyWpo6DueM26AZnGZ2T3wEOi1XRrzAQu4xa7jEhK
|
|
||||||
pG9M47+yjbEKTyimdx7lwO/WeOIze9CLGYzPaqECgYBfgaE2HpG0SYKfDy0ipyxe
|
|
||||||
p5ZoGQUXksi7WHSWSTl3tA/0NTtYKCHKb1/hRezjmdRgTuqBaV3y2nF1XmlKw9EX
|
|
||||||
nYx/xAfhnyh9K7EZEMtDP2zL6tV1sp6b4Jd7sbFvM/bMJBY6KtKx59Y0u4nkgcH2
|
|
||||||
gt3jad7Axl6C3faOfjzeyw==
|
|
||||||
-----END PRIVATE KEY-----
|
|
@ -1,25 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEMzCCAxugAwIBAgIUBxGrWWn+gk2O0nxUeOQvpcu0HUQwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
|
||||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
|
||||||
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMFUxCzAJBgNVBAYT
|
|
||||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxHDAaBgNVBAsME1RpbWVzdGFtcCBB
|
|
||||||
dXRob3JpdHkxETAPBgNVBAMMCFRlc3QgVFNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
|
||||||
AQ8AMIIBCgKCAQEA4TH03boCmDQwjaKbM/a06WBe9dJKt3wzdyXZhBT6GX4WefAg
|
|
||||||
ZvomQSUQnPCqFzGygIAGbBWlMlOtzNO32CMSXrtwkzou5BUEcuW3xqxDp0wTClKk
|
|
||||||
finDmTXjWLX5L+HnGtuQLU8s4iXgVUzqg6FRuce+WndPgG+MQPW4WzePu5uY0tWi
|
|
||||||
Xh7Y/HgwZCTiDihm2dFhLLX3wCM1jqggvmBasbFyztoTsUYMYKbGPVWuG8p5+h1t
|
|
||||||
BWVHFEBhAx9GNe6NiiJ0smAEmne1SBeY44iZwM871O9NVEWe5IyRRm0/Vu+dty48
|
|
||||||
rZfzL4PuakxuSTUI1Q7Fh7Xuo9SqvGwB6WejYwIDAQABo4HvMIHsMAwGA1UdEwEB
|
|
||||||
/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwHQYDVR0OBBYEFHnEl41jHza4
|
|
||||||
2tqVE1fctzcQRFMNMB8GA1UdIwQYMBaAFE6fD2uX/Q6n9KjFBO5tB++jGixmMC0G
|
|
||||||
A1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvVFNBQ0EwVQYD
|
|
||||||
VR0eBE4wTKAYMAqCCHRlc3QuY29tMAqCCHRlc3Qub3JnoTAwCocIAAAAAAAAAAAw
|
|
||||||
IocgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDQYJKoZIhvcNAQEL
|
|
||||||
BQADggEBAKMnM+tX2AM6g9SSAbgAz25vHRs+/hzZN2EMZOz+ZsNZufRwRbDH4eC5
|
|
||||||
mm+s9PKw99vk/67vJk+IxfOLsZSleRX6h7DqXKhh5j8S/IPfOuIxWUfQGMlnfHNt
|
|
||||||
IdePg1vIQCwcj998e0NIdnioSnGrKRay0A1Y+7zY+9B8/sRCAamyAFyqjG5UG70q
|
|
||||||
NOZcuG52+ZHYfA3poW4MTBWTi+k9tK786RpRWj+I1ORBAJIFZ1SRzPQ5QL4XqE14
|
|
||||||
iKowHAJbo1/X6Xr/SW2B+oC+p5jmONRi/rwHnUEqWbkbi+CKWdlI+7HTApncofLi
|
|
||||||
JVHLUWz0r6IIp0mHrMwoI94yZBVXje0=
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,22 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDkDCCAnigAwIBAgIUf2df9lAckuBxsAT7UktJTpH8H3EwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
|
||||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
|
||||||
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0yNjExMTAwMDAwMDBaMGAxCzAJBgNVBAYT
|
|
||||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB
|
|
||||||
dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG
|
|
||||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH7Zl2oFIq75eVCHtPSH5apYifPyFvIAnB
|
|
||||||
J8D3/ylM+Ll5X0/mBkyU5yR7CN0T+WsroWmkkGLuDbrqRrGG30Zs6/DIgHnLn25l
|
|
||||||
rM/6C4B3TApIoBPLqLWaYd0EUwn5hyh5vJdolzCwZtr3swS1BZ23WlPXXWIO8F+m
|
|
||||||
E5QZiFWqjufoHWECyoa3OwJ+U/UcR+Tr/HnlBXaZswTJdr91R9imWZgAE6EF6qM5
|
|
||||||
ZnzNqgsjKPIN62FIcL3SD57CcR8fYvOAHGlY9r/CoDMuAs64wp/+oovC4J8WHvqV
|
|
||||||
xg/z32V7osNq4ko9IArTDESj1ZlL33uVGy/GnTAMZv1CKFMrCfMNAgMBAAGjQjBA
|
|
||||||
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE6fD2uX/Q6n9KjFBO5tB++jGixm
|
|
||||||
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEArE8W97mfL9a8NcaX
|
|
||||||
UmJwiBsoA8zGQ1uWV051JHuW+YbC1az2pRR0kXOLkXeCNhwHfxb8pvEjOToa341K
|
|
||||||
5NYFSRPJVkR09AaF7KjuLzZO821roxbZPPbS8GsFGJ5GbLe6F8EW06rCyLN03Y2q
|
|
||||||
bOAQvAof421193HIO0baBWE13QsLk2wQEYyB/Yld3919ub9plQLxapojRdK2s+cY
|
|
||||||
Juftt8hE3UDlfQkpnVbIpU4Q/LFtPztfxkcd9rkz/kujH+juBd2UnirjK3n86ReU
|
|
||||||
1MM2QvtnMlXyZiXHujrOkWGS57KaYdkDAV98zWk9Bx7g6K97cy0JPdBq2cnucUJw
|
|
||||||
0mCOiQ==
|
|
||||||
-----END CERTIFICATE-----
|
|
Binary file not shown.
@ -1,15 +0,0 @@
|
|||||||
-----BEGIN X509 CRL-----
|
|
||||||
MIICUzCCATsCAQEwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCUEwxFTATBgNV
|
|
||||||
BAoMDG9zc2xzaWduY29kZTEkMCIGA1UECwwbVGltZXN0YW1wIEF1dGhvcml0eSBS
|
|
||||||
b290IENBMRQwEgYDVQQDDAtUU0EgUm9vdCBDQRcNMTkwMTAxMDAwMDAwWhcNNDMw
|
|
||||||
MTAxMDAwMDAwWjB1MCUCFDF3PBReAxISf9HM7Bt0q3GUuBgmFw0yMzA0MjgxMjMz
|
|
||||||
NDBaMCUCFElwGj3lGrX4Xg0xaO+y5zAR4MnjFw0yMzA0MjgxMjMzMzlaMCUCFFcV
|
|
||||||
Ys5TRUZVMGFWN3Et/yQQme62Fw0yMzA0MjgxMjMzNDBaoDAwLjAfBgNVHSMEGDAW
|
|
||||||
gBROnw9rl/0Op/SoxQTubQfvoxosZjALBgNVHRQEBAICEAMwDQYJKoZIhvcNAQEL
|
|
||||||
BQADggEBAEu9tNvUMHJ69vCPdJH3FUuGPHuTyC32aLBoV/g/t9OD+95fDwwijKbX
|
|
||||||
QcypdgGEp4KEH4WQQ8JyhScgxd3gjnNoB9ITIZ14eZ9uslIZPaQztMDqvzLZcsLf
|
|
||||||
PXWWvCs8GO1K30VVqVual+OT8ojWBAgF49rg2OZX4JUAhXyaP360MtWEWVNghRwk
|
|
||||||
FhK7q6HOaNtxrIar1ZuDkvqEvmaEexJ/3HOGAM0DWmhneO2hIpCAfpYnGic66I69
|
|
||||||
17FQWE6WLTS+Hjc8qQEDPeGsSK3NWhGiOKDr1Zpjae5PknghxzfxE8u56t6pMBHj
|
|
||||||
DWYGMc57TpovDpTdla7YipkVxSrTkhI=
|
|
||||||
-----END X509 CRL-----
|
|
@ -1,28 +0,0 @@
|
|||||||
-----BEGIN PRIVATE KEY-----
|
|
||||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDPPtqTsdzCK99B
|
|
||||||
5zSNIiu429Tbc/S4Aa9eSsbjcefTy7NkCPankl8QeBIvQ75P98qH828iDlSH2u3N
|
|
||||||
Rp121r9wjEaM3qmkkyP0oWwjoK0du6y3hI59rHhOt3FqO0ec40Rf1yxrCKE+pCMd
|
|
||||||
TI+Ifozlxe/T7FhwxLjOIBIt4gDF6sOn06ToTC1CoVi/nd9E5vgKjuQW0F1Y7Hey
|
|
||||||
Ft64YStUXxvLB03mw8+bciZI3BQGrgOD9CCTWZVK7OO147qc8TEoQle1xKISM5wh
|
|
||||||
vaHbNUuhMRJG4qVyrZ54BICRW7r5cJZBBDVc5i1XD50Nup4wIjJtBAnPZDAwEwac
|
|
||||||
XZ53hHAPAgMBAAECggEAeGmume3XtEHFYAcz82SNPsULcc53u4nPGNwdnv0Jk3dh
|
|
||||||
bZf/p/FVpr384tVbeB8i38bDJWhqGN1NGd4Tk37GkGAQhbzBmEudsn8v06uBqirm
|
|
||||||
+WHdYIubAzF2hiCXRUKO8ZiVyEKlXT4E4Psg0k+lEcPlyp4h7LOAJNNhfKM5i8QF
|
|
||||||
3K7Pp/VcFqtwJSmu0vSycJOJWyUfqRLxgWS95r2EG1rwD46KFBCoHOa50kiZFdiI
|
|
||||||
q2h1XOiXtdaG1yn6HRS75gV4CR+MCGkczs9onSl4IpwNlq595NMCujhFcHjjKzwV
|
|
||||||
F4E/83ehtj7WruyNFwrFbabNAvLSY8nVBHabn/3L4QKBgQDrYHKn0njihjbaPT5v
|
|
||||||
1yoJyz/1eX/fscvDhQFvhQoirk/A3iSwOd1jszGvvYxRnfRnLDOszTCq/+CRSv09
|
|
||||||
sU7ECDcJPFJY8GzDMLjoBJRDtHdsFjU6tliHgyXFVpu46sIt0Z03Wglowyytc9ws
|
|
||||||
9e5uf3xolNbhdLTWfovoRp5LJwKBgQDhZ2qWOyGkVyuPn0GSVJVnOgK/PUd9b7Ze
|
|
||||||
R77i/P6sgp9d3eAXK46oYJM+6TPnQwZYE9CHUMMqHmtCm2iHqCEitZ9mvZgPt6p+
|
|
||||||
sR8HxJ/JAowDB8mOQ8usd/1S0M5e8SwSpuRajkYw0cndvwn+ezAlKsZyCN6sm73B
|
|
||||||
3ruQvVjk2QKBgAJG6pUJCjZWyg0Obp4yXKu/lZzQUhZd5/S6QqtLhC+VtBvPildS
|
|
||||||
F/ww7Zgfo03e01B0MwPG8GOXGhsNuKlyH6rx0WZ7eOh3WvYAcKl98dk907Ht/RHW
|
|
||||||
VcDp2eGw1szRKJO85WJ1soWa7cG3zzd4IZhcD14LopCHyoAQtVXH6RwdAoGAddQM
|
|
||||||
yNnCXVlgIST8LxVeQGb31qae/3htWd2hcKEWNHHYA0agBRy051oMvv9DLapA37wD
|
|
||||||
7yiNzS+3nEsHGpsOL0nIOPn1SooVa0MF2Ja1fGuDa3Yfq+nOx6q11xvmNYVXJ6zs
|
|
||||||
hFYJZS3Vm8Bo5gnZgiRZNnViidKkIHthi2kf1gkCgYBzaNgT4fbNPpgia/Vz3rd9
|
|
||||||
UIYpVzMEP6HkTVYXQH+qLzRpjl4HG6LanMbxtf/0MBHBwtEyVftKopgvkcJCDUCS
|
|
||||||
Ls+BYieF547/2W+pnV7lbz7eD6w2o7zNPNj/l+RB2PXgBZGQv1N4HgLsz+yk7eyI
|
|
||||||
s3UnnC/9NhgSMwB82OPX3g==
|
|
||||||
-----END PRIVATE KEY-----
|
|
@ -1,25 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEIjCCAwqgAwIBAgIUVxVizlNFRlUwYVY3cS3/JBCZ7rYwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
|
||||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
|
||||||
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMEQxCzAJBgNVBAYT
|
|
||||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA1RTQTEQMA4GA1UE
|
|
||||||
AwwHUmV2b2tlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM8+2pOx
|
|
||||||
3MIr30HnNI0iK7jb1Ntz9LgBr15KxuNx59PLs2QI9qeSXxB4Ei9Dvk/3yofzbyIO
|
|
||||||
VIfa7c1GnXbWv3CMRozeqaSTI/ShbCOgrR27rLeEjn2seE63cWo7R5zjRF/XLGsI
|
|
||||||
oT6kIx1Mj4h+jOXF79PsWHDEuM4gEi3iAMXqw6fTpOhMLUKhWL+d30Tm+AqO5BbQ
|
|
||||||
XVjsd7IW3rhhK1RfG8sHTebDz5tyJkjcFAauA4P0IJNZlUrs47XjupzxMShCV7XE
|
|
||||||
ohIznCG9ods1S6ExEkbipXKtnngEgJFbuvlwlkEENVzmLVcPnQ26njAiMm0ECc9k
|
|
||||||
MDATBpxdnneEcA8CAwEAAaOB7zCB7DAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
|
|
||||||
MAoGCCsGAQUFBwMIMB0GA1UdDgQWBBRWRawwlcW57baAiuBVmi0WFKIZqjAfBgNV
|
|
||||||
HSMEGDAWgBROnw9rl/0Op/SoxQTubQfvoxosZjAtBgNVHR8EJjAkMCKgIKAehhxo
|
|
||||||
dHRwOi8vMTI3LjAuMC4xOjE5MjU0L1RTQUNBMFUGA1UdHgROMEygGDAKggh0ZXN0
|
|
||||||
LmNvbTAKggh0ZXN0Lm9yZ6EwMAqHCAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAA
|
|
||||||
AAAAAAAAAAAAAAAAAAAAAAAAMA0GCSqGSIb3DQEBCwUAA4IBAQCQbgXQtFr5lWjs
|
|
||||||
tzlGJAuZfIq1f1arWWrJNSHrha9RUtm6uMoh2aMYByfEcopB9StqMo8QH4yS4LGZ
|
|
||||||
/6B81EF+dugIIb9BrE00ASgXxZ6aGGAe79VwqdG8DXp+VgRbBQA87S2KeSN8wfm+
|
|
||||||
G2AGRZF0JWS4iW5kGgrqeC14IN1FajHklrh7rOIwo/h7uVIOINWtQnHyBjlCQ6N4
|
|
||||||
OTFFgtIOY5KXtYM1A+Gx2nt3uZnEh/U/ZxHslUb55O017Qfkbf11JXFil4+ZfqMx
|
|
||||||
QuRuwMAWlyEg+1UfNae4Sg3XqPheshBzZ7ykwKGZZPeA/8kKfbXoE6Kdy5HmT/El
|
|
||||||
8e7rP/mN
|
|
||||||
-----END CERTIFICATE-----
|
|
Binary file not shown.
Binary file not shown.
@ -1,46 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIID7jCCAtagAwIBAgIULWwn/gLcPMAO/7oGqx5A306mxckwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
|
|
||||||
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMIGdMQswCQYDVQQG
|
|
||||||
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
|
|
||||||
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEUMBIGA1UEAwwL
|
|
||||||
Q2VydGlmaWNhdGUxJzAlBgkqhkiG9w0BCQEWGG9zc2xzaWduY29kZUBleGFtcGxl
|
|
||||||
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64qSULdxvTp7A4
|
|
||||||
2dl/JbLq7GJ4ZcPbtfUyvVTB5WuntN08bpgnxljON0Ig9lFpN2OOlms/SnodlE6Z
|
|
||||||
O8GY8kYu/aK3zHIHp3EykzRP1glf7ukcCMpcSaS5VUho0QQ9PVvvMHVNtaQ00r2i
|
|
||||||
34m8DbGj4aRUNI5eA6Xlzz8QnhvCgtRTVbp5ZRjxo1ZNq2eEZxa6UnFshlx6i0/o
|
|
||||||
kYPrdKTIvUv2zoRFd9H/7+B2Xwse+qppcZe0BiKSa4l6PrL2iHteYE29ggLLSqe+
|
|
||||||
zavGN7Ev7jP+bZLU/5eq58SBy8uFBDkh1FvZEPAnJ2X/vwNzySi6KTliCPc9Jf5G
|
|
||||||
wSJr+5MCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUVeUILLpF5PWz5rAD
|
|
||||||
iWzV/2oEP3UwHwYDVR0jBBgwFoAU4/q/jYQJtVH8CIsNnt/ZYq1hcgswEwYDVR0l
|
|
||||||
BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAHckjLcj9mswr08aF7MV
|
|
||||||
EZTKKh0IOaHj7oh6vLR5Yg2n+E+9Gog/+ulbKXNe/5A9QU2R1NdwZKEeUeSuF4qW
|
|
||||||
P3JB79BepgR6/VYKyVWH7St4ixy1GtNEFrHWsID212Jd0Rr3+kc9OJUO0aw3nvg7
|
|
||||||
Apsr1dztjwlUN2ugLzVoDJ2wMqlu5ZQW8pINIYet127cX5knW/acPCPcqPVD7jmm
|
|
||||||
C40xgqeKD2a6OafSS5hjO4UeCoeHnXlJ4Sep8wz8VDlu39Hr4dwFm8v9MuvBusCr
|
|
||||||
/sdwzTRAc6mhBL/4PyJrBRhibbTxSaDKBHeWcKpmNp4DIk1vc8h6yhDUb1fgafgX
|
|
||||||
7nI=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
|
||||||
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
|
|
||||||
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
|
|
||||||
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
|
|
||||||
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
|
|
||||||
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
|
|
||||||
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
|
|
||||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
|
|
||||||
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
|
||||||
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
|
|
||||||
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
|
|
||||||
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
|
|
||||||
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
|
|
||||||
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
|
|
||||||
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
|
|
||||||
-----END CERTIFICATE-----
|
|
Binary file not shown.
@ -1,47 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEPTCCAyWgAwIBAgIUZp72ahjzVryMA56ev7+Z8Rxyo2kwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0
|
|
||||||
ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMjQxMjMxMDAwMDAwWjCBqzEL
|
|
||||||
MAkGA1UEBhMCUEwxGTAXBgNVBAgMEE1hem92aWEgUHJvdmluY2UxDzANBgNVBAcM
|
|
||||||
BldhcnNhdzEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1AxIjAg
|
|
||||||
BgNVBAMMGUNlcnRpZmljYXRlIFg1MDl2MyBDUkwgRFAxJzAlBgkqhkiG9w0BCQEW
|
|
||||||
GG9zc2xzaWduY29kZUBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
|
|
||||||
ADCCAQoCggEBAL64qSULdxvTp7A42dl/JbLq7GJ4ZcPbtfUyvVTB5WuntN08bpgn
|
|
||||||
xljON0Ig9lFpN2OOlms/SnodlE6ZO8GY8kYu/aK3zHIHp3EykzRP1glf7ukcCMpc
|
|
||||||
SaS5VUho0QQ9PVvvMHVNtaQ00r2i34m8DbGj4aRUNI5eA6Xlzz8QnhvCgtRTVbp5
|
|
||||||
ZRjxo1ZNq2eEZxa6UnFshlx6i0/okYPrdKTIvUv2zoRFd9H/7+B2Xwse+qppcZe0
|
|
||||||
BiKSa4l6PrL2iHteYE29ggLLSqe+zavGN7Ev7jP+bZLU/5eq58SBy8uFBDkh1FvZ
|
|
||||||
EPAnJ2X/vwNzySi6KTliCPc9Jf5GwSJr+5MCAwEAAaOBmzCBmDAJBgNVHRMEAjAA
|
|
||||||
MB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJbNX/agQ/dTAfBgNVHSMEGDAWgBRhu0A6
|
|
||||||
SceOaK7eXw40BRjfzuQWLzATBgNVHSUEDDAKBggrBgEFBQcDAzA2BgNVHR8ELzAt
|
|
||||||
MCugKaAnhiVodHRwOi8vMTI3LjAuMC4xOjE5MjU0L2ludGVybWVkaWF0ZUNBMA0G
|
|
||||||
CSqGSIb3DQEBCwUAA4IBAQC2yNGXw1VZqBWY7cnJtiZpupKYCifRC1dEFlKcozpd
|
|
||||||
dhWHDKpGDCzqaL/WKpqFjOIrCbG6gsfB+nu2VQv4nE8lwwelMgpeVB+v197A1SvE
|
|
||||||
wLl71R5a7sxF0x5aBdUyWeCTeBLu6KuWQrpPcZVM3uMqhqCJ8CiSUtS1cKn1K1K0
|
|
||||||
KRSgFTs4AFUc0rOa3wYvytps4cw/TyDXArlvGVMlDHNLffEsx3vElZafaGvyEK0J
|
|
||||||
TsBM2dakcpP/ceuJU1gd8hLadzjfKOFml7z+qHfUa/mky+veK2M5vKn1ph55qYHc
|
|
||||||
WtEY/wwBjgqE2VseqMLb06J3tXmTKgESGXISAnqoau+t
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
|
|
||||||
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j
|
|
||||||
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4
|
|
||||||
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe
|
|
||||||
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp
|
|
||||||
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO
|
|
||||||
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw
|
|
||||||
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k
|
|
||||||
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD
|
|
||||||
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg
|
|
||||||
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB
|
|
||||||
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA
|
|
||||||
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK
|
|
||||||
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d
|
|
||||||
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,23 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDzjCCAragAwIBAgIUKUVnRllbtypXICoznroWil39jU4wDQYJKoZIhvcNAQEL
|
|
||||||
BQAwbzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEMMAoGA1UE
|
|
||||||
CwwDQ1NQMRIwEAYDVQQDDAljcm9zc2NlcnQxJzAlBgkqhkiG9w0BCQEWGG9zc2xz
|
|
||||||
aWduY29kZUBleGFtcGxlLmNvbTAeFw0xODAxMDEwMDAwMDBaFw0yMDA2MTkwMDAw
|
|
||||||
MDBaMG8xCzAJBgNVBAYTAlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNV
|
|
||||||
BAsMA0NTUDESMBAGA1UEAwwJY3Jvc3NjZXJ0MScwJQYJKoZIhvcNAQkBFhhvc3Ns
|
|
||||||
c2lnbmNvZGVAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
|
||||||
AoIBAQDFCjBrTLeh9wyMb6tJi1SMz+Pe6Eb8SCg4+soxBAu1EEVo4Ao810j2NVdc
|
|
||||||
aoQ2Ki097hl9LHcA0DMT8AFRHfXMXHSSHoYHsPcwHO6RJHXcDE4fSgkl41GtCnf+
|
|
||||||
qUOA+QZUqNNKNOELUHboydFMytNGjuSaO29BObkiHCRB8gnfKuqGZn9YrfU8AoGu
|
|
||||||
xv7RzKgD+uC/dTZSONAW+h7TuRn4/qtqTqfk5SnmTeEDbW3lyYLToRRKUKcYR68a
|
|
||||||
lT/IZ2cHCrZMqvykR2cCMCARbTyI8ZQ6ogzXS/tncJYu/RTtEoKiN1EweG5R0cgU
|
|
||||||
G0xQISw5RXMUSgWkWUL8rYpFcmahAgMBAAGjYjBgMAkGA1UdEwQCMAAwHQYDVR0O
|
|
||||||
BBYEFBt9u2LhSzaQrQLcja2QtFexM2tKMB8GA1UdIwQYMBaAFBt9u2LhSzaQrQLc
|
|
||||||
ja2QtFexM2tKMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IB
|
|
||||||
AQATfeXQ2kj+97IHUOtFZTjcIH47U6k8Po11WD+Af4PRmacOKaSv+rlmgpgHfQJV
|
|
||||||
nM90mxUvKzaoJeId/yR++U86rcu8a87njHoyDzx2HMcc47P/2VkErT9W4gyJE0Ws
|
|
||||||
JyIR0k0XZiYJ+pJOSjnd7SY2gs1oBT3+Go5TyClAfzAP+U10fK52q802XNPw5MY0
|
|
||||||
LEyRqCH4QYb71Hd4kGqROVy1EPv18d26apD9vK/zZuvOsbz23l0mdochYrtmfAA0
|
|
||||||
LuNwefIgxzki22+bZe7lJyuV5WsqSNGVty+fvqmw9JUfzeOpIzVK/SxqANJnZBBI
|
|
||||||
kapgFmTwk4JEfB3n2WTmbs9C
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,45 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIID6jCCAtKgAwIBAgIUW4SefwoiLUfTBaHpZyd8knsGVBswDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
|
|
||||||
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0xOTAxMDEwMDAwMDBaMIGZMQswCQYDVQQG
|
|
||||||
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
|
|
||||||
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UEAwwH
|
|
||||||
RXhwaXJlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUuY29t
|
|
||||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ2X8l
|
|
||||||
sursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7wZjy
|
|
||||||
Ri79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLfibwN
|
|
||||||
saPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0
|
|
||||||
pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77Nq8Y3
|
|
||||||
sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbBImv7
|
|
||||||
kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJbNX/
|
|
||||||
agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUEDDAK
|
|
||||||
BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAp06uHnxO63Ecn+knaXkfrNGg
|
|
||||||
pr+4WCc0onXYOE37+IwsCFaUqCIr1UsnnKWSzSlSR07FHI+VaV9r3knT6VPMVsUU
|
|
||||||
L89jHC2vLUvyJJOtuTpuOVGIzzCquYWvYRZrp2wmTceMSNhLcO1VGs28uwQojWEQ
|
|
||||||
ZsEdFvkYeWFInUQ1mF0dLnfQjh7RcTxMJ0CxZblJ086j3AbyzM6ZF6XAVPAqBH/S
|
|
||||||
gsBfLVGnZnMOwvKwsxViG1ikRusO6GtcIy6yxmNCUhWbIL+R59EYy++x3xLVUU90
|
|
||||||
YnScDN+xM9A2wHO1hQpLK6DIiHpbAzAgll5xD0JWh+efRWHEtGN5JTybowG9yA==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
|
||||||
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
|
|
||||||
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
|
|
||||||
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
|
|
||||||
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
|
|
||||||
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
|
|
||||||
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
|
|
||||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
|
|
||||||
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
|
||||||
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
|
|
||||||
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
|
|
||||||
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
|
|
||||||
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
|
|
||||||
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
|
|
||||||
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,22 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
|
||||||
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
|
|
||||||
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
|
|
||||||
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
|
|
||||||
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
|
|
||||||
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
|
|
||||||
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
|
|
||||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
|
|
||||||
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
|
||||||
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
|
|
||||||
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
|
|
||||||
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
|
|
||||||
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
|
|
||||||
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
|
|
||||||
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,22 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
|
|
||||||
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j
|
|
||||||
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4
|
|
||||||
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe
|
|
||||||
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp
|
|
||||||
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO
|
|
||||||
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw
|
|
||||||
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k
|
|
||||||
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD
|
|
||||||
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg
|
|
||||||
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB
|
|
||||||
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA
|
|
||||||
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK
|
|
||||||
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d
|
|
||||||
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF
|
|
||||||
-----END CERTIFICATE-----
|
|
Binary file not shown.
@ -1,27 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
MIIEpAIBAAKCAQEAvripJQt3G9OnsDjZ2X8lsursYnhlw9u19TK9VMHla6e03Txu
|
|
||||||
mCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7wZjyRi79orfMcgencTKTNE/WCV/u6RwI
|
|
||||||
ylxJpLlVSGjRBD09W+8wdU21pDTSvaLfibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNV
|
|
||||||
unllGPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0pMi9S/bOhEV30f/v4HZfCx76qmlx
|
|
||||||
l7QGIpJriXo+svaIe15gTb2CAstKp77Nq8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHU
|
|
||||||
W9kQ8CcnZf+/A3PJKLopOWII9z0l/kbBImv7kwIDAQABAoIBAQCEsjqNWcLPi53a
|
|
||||||
kFOSblKuf6FkidxUP2QEa/8rH5UeKBtA6rEQEGyCkUgFLKX00r4E+MpTaD/LYxUy
|
|
||||||
8o6PDnlSt5MlSbhnhkfMDKI6/WkwMJ0rd6PuF/PtNj3OGY+D4Y/1jSAsHZtJ2q7d
|
|
||||||
3pqlXEAy3pE6IpRGkcb8AD8H4+n96U4sNnytll6//5uD55PRbxZwB0mmNJOVoZJK
|
|
||||||
+CbW0wV3rKS0UslFot/b/jNvmCQym3UmWz3elShRTZTA7cdQt2YtKaFO5zFxbbh/
|
|
||||||
L0+Rija2tVyUPswSbeGxiyfF2RRt++91S6RONfc9B0JKwkNkbQEcM+dPIfIe/nIc
|
|
||||||
8CgSCUThAoGBAOUMBWLhxE6QW1KeR59d00wtnWzN7x1CQ43LciIRMz3C8BQLpRmX
|
|
||||||
DmTDASxy9B19tEhdVHzYhq/+1x+vM7TWiPeLg2IhvFZEhpIdN7J1n0iUI3P08dHn
|
|
||||||
KmvHSu1XGQfngIMT/Ey9xdMpAxsZVJsScuT3sUxnUKxzFpCvTuiCP4ibAoGBANUq
|
|
||||||
FyAywSsGCrl77BaQh9GDsrL3i67owfpWMs6JjywfEFdpfGZnJTCvlfKtv/Jrp4jB
|
|
||||||
p5PM5IOil63RqQXa8/pv9pQr2DUGmKegNhDGgflK5+BcbTpkAYIcGHekhoTy2TXU
|
|
||||||
BnlKaNy5Te80yEFVfFRejK1rQ2ZqHqZP3WtzBBxpAoGBAOGhAOFSg13dKIjvcKCV
|
|
||||||
/aLKQIzBJG6PKxrQMeNLTE3n7TXh7saRnlU2H77Yko9GmES845CEf9F5WhNVNLtM
|
|
||||||
puor3cXac7wLjwD6lTZQVhNaEr6UqW5bqNc5IB9DMF4v99Gn617xhqGnge68+jI0
|
|
||||||
b0gMk/QuxjLKwIzQlQvH2qxHAoGAaFYXx6zQHAzzBuL/JfRMZmK9/xdniY9oEu5K
|
|
||||||
JAn0yDXUO9ToDP+Dlpb7IDOndjL3Z9rR+WgamcvlzjCHONR5AyX2XYQwaZP2+GVU
|
|
||||||
0VU4nRrq8EiNNj1o95Rk7XrcVQrBArXrDUc8mH0jBmihdEkxd+JnnSKZdPGQWvtQ
|
|
||||||
d51ub7ECgYBHbn8uyl4sHLj6y5L2KjsVFpLJp7OFNv3UUN9TrY+rd+CjmTFBSE52
|
|
||||||
XaV7v8Ul5nDRom5D5R/z8iFK+3Nx7PJq+WesEAPfNPc+BJFkRdJW6ysp/jHnpRV/
|
|
||||||
rUTaWgQp5/em1GAvBHa8KAoPAS5WAY/lxByruBSTbUSNuC5gz52xzg==
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
Binary file not shown.
@ -1,30 +0,0 @@
|
|||||||
-----BEGIN RSA PRIVATE KEY-----
|
|
||||||
Proc-Type: 4,ENCRYPTED
|
|
||||||
DEK-Info: DES-EDE3-CBC,B9C24663685D6009
|
|
||||||
|
|
||||||
GMA8W6sGC+xtNYoPzX2j0driKlngRIbmABYMbm8TSac8du7/S8uBcG2i6z/d0Plu
|
|
||||||
pHr06uIcZDjCN0iWkhMGS7ai40ddBjxjDS/f9ppUZdOtTX4MzGfqb/d9LGVi1P8W
|
|
||||||
zYSuz7BI0B2ttcbpmMIhxdGMtRz8A/MDPm8eBnEmIYjRiW/ES2HfHlrm7CFlrd72
|
|
||||||
vgiAmFPtx9P5AE+KMFiSJDkSVMKX52yvLfBQAeBU2aQI7z5BTfwIpGgVKBT5qhq4
|
|
||||||
EwL24FrEJ1+20Q/Resd/nfqv6lzNPl6SQLhCgY25Yz0Ke9u8Xnhn1aoz1BCDtw8u
|
|
||||||
fnzmaqexf6w70rC1qX+CyrHLxO19lRUn5wChyPYaU2oAt3a0iKktQWdqHUIAGi+d
|
|
||||||
Q3DpgsXlQXuXHDeBh5KKePz6g1f7pjacpjH8t8Y3VqurQop8Ku5KiVln+WyVklbS
|
|
||||||
9ipr4Btf8NnWWD+kAvdo01ObRRGYxZwj/mlr9ePQ2d2vd9wNLe8zS0FZSzBE7cZH
|
|
||||||
OPMuZnjU9Ruub0GJpHzsNBhMNIl6M6c2DSphrUTZBG6Sogx/aVSxe3Z5sojULfNT
|
|
||||||
aifhUP/qR94nFokwRs77zXwWJlIF02g6caL8P/fPAcxIaItl+Q3DFo0wEZOzDI2X
|
|
||||||
7ijPoEj/TReVajulxCcISJs5F6gaPKhNW8FKxvFH+3LnMLW/BeHNSGgnIFftkI3Z
|
|
||||||
GqwcLN+X76qhPzS1UFF12fW9wYXjhMnR6bvVaadP6+XadZonyE+eGdRjZH0M2IIF
|
|
||||||
Jv6si9Zxw+sesmmFXzjU0jzv825rD0NtPpYKWaCdtX1x5fkk+A4T28Yu1uLWfJcs
|
|
||||||
4LhEkfhgILjLY02idjX4OKmwKm4w+QqBeajBCZiGTl6Fk2mvC0wCy53AEH3UTu8I
|
|
||||||
KRkEAcl1CxsYAHZb9B00ymk3iyGTQ/1luLZfPkGS6CMJPXjSjR0i8NmOaYa+Xhe7
|
|
||||||
bsCPYWeGT1ttJh+A5Dh39K00lSrIuQS9m3lKzdlHhZ8YL8DdeUAMBM6JKI3p8V9s
|
|
||||||
xeb/w9Vf7iZRLsL6yDqj4zm5HFifRpFDpD/E2rC6zpUvdFiy2p6J7Xpo2cu3wMIV
|
|
||||||
QL1te4aHVQhWsijV7LoaS3452NOnknxiNxXFWk2POwPHL1i6rmS7MlQwqDlLBilj
|
|
||||||
O2R4YZGjmRg69zr9xJJGQQnroFEagKdhedSJ2y+lqwxl1Kb+Lp0+SOVesxfjfoeZ
|
|
||||||
y0ctY7IJZksM0htETT6fhfJKSbMfM2uRL3FJkv1QyexnIlwmZxZgUyYAJemTZJBY
|
|
||||||
BbAhhmTRswhp5FWdfFbYez7cV9AIhtNCoGcNQuQ+wL9OmIQbmZjFUqLIcHVyX1xA
|
|
||||||
Zj5Jh6aybmnJTdXyIwUP3RdkHrD5JW8+d/0xMm1G89PtDJ6Q2+D3drtTB7A3ruUD
|
|
||||||
uyDhYtpyY9m940miAsvByK2jIUlA0hLb+9+1oiWcWarl7IwxpjP8CUG6nAF7BU6v
|
|
||||||
J/Hbikx0XMfycYp1EsQYUP4ku+S/PoJsMNU4bt248E+dDALxoyQN1Z41sYILBz4Y
|
|
||||||
ga6z4zCA5+66ug8z2yMbC4bCo0FZxuJLcw+Ok05+PT0fW9Z3egpybXVwwY4wc6vs
|
|
||||||
-----END RSA PRIVATE KEY-----
|
|
Binary file not shown.
@ -1 +0,0 @@
|
|||||||
passme
|
|
@ -1,45 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDvTCCAqWgAwIBAgIUSXAaPeUatfheDTFo77LnMBHgyeMwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
|
|
||||||
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMG0xCzAJBgNVBAYT
|
|
||||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UE
|
|
||||||
AwwHUmV2b2tlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUu
|
|
||||||
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ
|
|
||||||
2X8lsursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7
|
|
||||||
wZjyRi79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLf
|
|
||||||
ibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iR
|
|
||||||
g+t0pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77N
|
|
||||||
q8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbB
|
|
||||||
Imv7kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJ
|
|
||||||
bNX/agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUE
|
|
||||||
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAK/bCZPrxN+5HGQjZLIQg
|
|
||||||
jKfjTRL5xwBGs8+VW4i+xnaA14pyZjDlYzASmCE/ZiryVSMJ7fuQ0TVXGtz3N7PM
|
|
||||||
v9pRgtcohs62NJZ5dIrq4f/Op1bii29pAA8+2EHPJUyFBt23vyvlI/dBpkgQG6mi
|
|
||||||
OUEsXQ+Q2LUD4OOJffkc/gowXcB4WFjrtFAUuu9HeZUNzV5Mm5FQTGm9nCnWsDIb
|
|
||||||
b7Yx08hMy+6jtvkNPCDcFnos2bsipmVN4fCXkm5LPZNyMFoWReDbIKWASXaao2hN
|
|
||||||
gzWhwWsPlAGAlBPMVWEo3k2Cz/entbAijoyqS2koN4mZABy7m5+vfzFw/yvh1/lu
|
|
||||||
8w==
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
|
||||||
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe
|
|
||||||
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co
|
|
||||||
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S
|
|
||||||
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc
|
|
||||||
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4
|
|
||||||
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB
|
|
||||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV
|
|
||||||
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
|
||||||
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe
|
|
||||||
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc
|
|
||||||
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD
|
|
||||||
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q
|
|
||||||
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/
|
|
||||||
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE=
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,46 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEDDCCAvSgAwIBAgIUMXc8FF4DEhJ/0czsG3SrcZS4GCYwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0
|
|
||||||
ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMjQxMjMxMDAwMDAwWjB7MQsw
|
|
||||||
CQYDVQQGEwJQTDEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1Ax
|
|
||||||
HjAcBgNVBAMMFVJldm9rZWQgWDUwOXYzIENSTCBEUDEnMCUGCSqGSIb3DQEJARYY
|
|
||||||
b3NzbHNpZ25jb2RlQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
|
||||||
MIIBCgKCAQEAvripJQt3G9OnsDjZ2X8lsursYnhlw9u19TK9VMHla6e03TxumCfG
|
|
||||||
WM43QiD2UWk3Y46Waz9Keh2UTpk7wZjyRi79orfMcgencTKTNE/WCV/u6RwIylxJ
|
|
||||||
pLlVSGjRBD09W+8wdU21pDTSvaLfibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNVunll
|
|
||||||
GPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0pMi9S/bOhEV30f/v4HZfCx76qmlxl7QG
|
|
||||||
IpJriXo+svaIe15gTb2CAstKp77Nq8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ
|
|
||||||
8CcnZf+/A3PJKLopOWII9z0l/kbBImv7kwIDAQABo4GbMIGYMAkGA1UdEwQCMAAw
|
|
||||||
HQYDVR0OBBYEFFXlCCy6ReT1s+awA4ls1f9qBD91MB8GA1UdIwQYMBaAFGG7QDpJ
|
|
||||||
x45ort5fDjQFGN/O5BYvMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDYGA1UdHwQvMC0w
|
|
||||||
K6ApoCeGJWh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvaW50ZXJtZWRpYXRlQ0EwDQYJ
|
|
||||||
KoZIhvcNAQELBQADggEBALwDivFFBjB7AkLO1jPJFyJnq8C0gadoYq0Dq5roAFMq
|
|
||||||
Lirl0LGsdFTrZ2ljKOzNrFVfw4EQHedDCsKCtsgOXG1xxLQczwsuBcIaWGzSdW15
|
|
||||||
iNz+IKjHXSNOLEUvVcO6N6s1rt5U15lynaXFSdskBgJYA7vq6uA8RTWzhQC7aCv8
|
|
||||||
n3Tbpe8c7j6/y5NThffBu/YZypMoraZvPohCDfMZoFNT5GYXNWSeq7gipxtaCHcK
|
|
||||||
OdWBi5yajIZL05hg29y7r677KBbvo07EykhxQ10zEnskzuqc7hCCsuDrXbmt5brv
|
|
||||||
REYpeGvJAu0YrFg9yLSl8FJwk/XUzGvxa2MLPyL/sj4=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
|
||||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
|
||||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
|
|
||||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
|
||||||
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
|
|
||||||
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j
|
|
||||||
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4
|
|
||||||
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe
|
|
||||||
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp
|
|
||||||
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO
|
|
||||||
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw
|
|
||||||
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k
|
|
||||||
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD
|
|
||||||
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg
|
|
||||||
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB
|
|
||||||
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA
|
|
||||||
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK
|
|
||||||
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d
|
|
||||||
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1,47 +0,0 @@
|
|||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIEMzCCAxugAwIBAgIUBxGrWWn+gk2O0nxUeOQvpcu0HUQwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
|
||||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
|
||||||
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMFUxCzAJBgNVBAYT
|
|
||||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxHDAaBgNVBAsME1RpbWVzdGFtcCBB
|
|
||||||
dXRob3JpdHkxETAPBgNVBAMMCFRlc3QgVFNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
|
||||||
AQ8AMIIBCgKCAQEA4TH03boCmDQwjaKbM/a06WBe9dJKt3wzdyXZhBT6GX4WefAg
|
|
||||||
ZvomQSUQnPCqFzGygIAGbBWlMlOtzNO32CMSXrtwkzou5BUEcuW3xqxDp0wTClKk
|
|
||||||
finDmTXjWLX5L+HnGtuQLU8s4iXgVUzqg6FRuce+WndPgG+MQPW4WzePu5uY0tWi
|
|
||||||
Xh7Y/HgwZCTiDihm2dFhLLX3wCM1jqggvmBasbFyztoTsUYMYKbGPVWuG8p5+h1t
|
|
||||||
BWVHFEBhAx9GNe6NiiJ0smAEmne1SBeY44iZwM871O9NVEWe5IyRRm0/Vu+dty48
|
|
||||||
rZfzL4PuakxuSTUI1Q7Fh7Xuo9SqvGwB6WejYwIDAQABo4HvMIHsMAwGA1UdEwEB
|
|
||||||
/wQCMAAwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwgwHQYDVR0OBBYEFHnEl41jHza4
|
|
||||||
2tqVE1fctzcQRFMNMB8GA1UdIwQYMBaAFE6fD2uX/Q6n9KjFBO5tB++jGixmMC0G
|
|
||||||
A1UdHwQmMCQwIqAgoB6GHGh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvVFNBQ0EwVQYD
|
|
||||||
VR0eBE4wTKAYMAqCCHRlc3QuY29tMAqCCHRlc3Qub3JnoTAwCocIAAAAAAAAAAAw
|
|
||||||
IocgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwDQYJKoZIhvcNAQEL
|
|
||||||
BQADggEBAKMnM+tX2AM6g9SSAbgAz25vHRs+/hzZN2EMZOz+ZsNZufRwRbDH4eC5
|
|
||||||
mm+s9PKw99vk/67vJk+IxfOLsZSleRX6h7DqXKhh5j8S/IPfOuIxWUfQGMlnfHNt
|
|
||||||
IdePg1vIQCwcj998e0NIdnioSnGrKRay0A1Y+7zY+9B8/sRCAamyAFyqjG5UG70q
|
|
||||||
NOZcuG52+ZHYfA3poW4MTBWTi+k9tK786RpRWj+I1ORBAJIFZ1SRzPQ5QL4XqE14
|
|
||||||
iKowHAJbo1/X6Xr/SW2B+oC+p5jmONRi/rwHnUEqWbkbi+CKWdlI+7HTApncofLi
|
|
||||||
JVHLUWz0r6IIp0mHrMwoI94yZBVXje0=
|
|
||||||
-----END CERTIFICATE-----
|
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIDkDCCAnigAwIBAgIUf2df9lAckuBxsAT7UktJTpH8H3EwDQYJKoZIhvcNAQEL
|
|
||||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
|
||||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
|
||||||
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0yNjExMTAwMDAwMDBaMGAxCzAJBgNVBAYT
|
|
||||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB
|
|
||||||
dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG
|
|
||||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH7Zl2oFIq75eVCHtPSH5apYifPyFvIAnB
|
|
||||||
J8D3/ylM+Ll5X0/mBkyU5yR7CN0T+WsroWmkkGLuDbrqRrGG30Zs6/DIgHnLn25l
|
|
||||||
rM/6C4B3TApIoBPLqLWaYd0EUwn5hyh5vJdolzCwZtr3swS1BZ23WlPXXWIO8F+m
|
|
||||||
E5QZiFWqjufoHWECyoa3OwJ+U/UcR+Tr/HnlBXaZswTJdr91R9imWZgAE6EF6qM5
|
|
||||||
ZnzNqgsjKPIN62FIcL3SD57CcR8fYvOAHGlY9r/CoDMuAs64wp/+oovC4J8WHvqV
|
|
||||||
xg/z32V7osNq4ko9IArTDESj1ZlL33uVGy/GnTAMZv1CKFMrCfMNAgMBAAGjQjBA
|
|
||||||
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE6fD2uX/Q6n9KjFBO5tB++jGixm
|
|
||||||
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEArE8W97mfL9a8NcaX
|
|
||||||
UmJwiBsoA8zGQ1uWV051JHuW+YbC1az2pRR0kXOLkXeCNhwHfxb8pvEjOToa341K
|
|
||||||
5NYFSRPJVkR09AaF7KjuLzZO821roxbZPPbS8GsFGJ5GbLe6F8EW06rCyLN03Y2q
|
|
||||||
bOAQvAof421193HIO0baBWE13QsLk2wQEYyB/Yld3919ub9plQLxapojRdK2s+cY
|
|
||||||
Juftt8hE3UDlfQkpnVbIpU4Q/LFtPztfxkcd9rkz/kujH+juBd2UnirjK3n86ReU
|
|
||||||
1MM2QvtnMlXyZiXHujrOkWGS57KaYdkDAV98zWk9Bx7g6K97cy0JPdBq2cnucUJw
|
|
||||||
0mCOiQ==
|
|
||||||
-----END CERTIFICATE-----
|
|
@ -1 +0,0 @@
|
|||||||
55c4d523e595564af0ab635fd1e3aaba
|
|
40
tests/check_cryptography.py
Normal file
40
tests/check_cryptography.py
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
"""Check cryptography module."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
try:
|
||||||
|
import cryptography
|
||||||
|
print(cryptography.__version__, end="")
|
||||||
|
except ModuleNotFoundError as ierr:
|
||||||
|
print("Module not installed: {}".format(ierr))
|
||||||
|
sys.exit(1)
|
||||||
|
except ImportError as ierr:
|
||||||
|
print("Module not found: {}".format(ierr))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
class UnsupportedVersion(Exception):
|
||||||
|
"""Unsupported version"""
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Check python3-cryptography version"""
|
||||||
|
try:
|
||||||
|
version = tuple(int(num) for num in cryptography.__version__.split('.'))
|
||||||
|
if version < (37, 0, 2):
|
||||||
|
raise UnsupportedVersion("unsupported python3-cryptography version")
|
||||||
|
except UnsupportedVersion as err:
|
||||||
|
print(" {}".format(err), end="")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
|
# pylint: disable=pointless-string-statement
|
||||||
|
"""Local Variables:
|
||||||
|
c-basic-offset: 4
|
||||||
|
tab-width: 4
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
End:
|
||||||
|
vim: set ts=4 expandtab:
|
||||||
|
"""
|
@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
"""Implementation of a HTTP client"""
|
"""Implementation of a HTTP client"""
|
||||||
|
|
||||||
import os
|
import os
|
||||||
@ -5,17 +6,17 @@ import sys
|
|||||||
import http.client
|
import http.client
|
||||||
|
|
||||||
RESULT_PATH = os.getcwd()
|
RESULT_PATH = os.getcwd()
|
||||||
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
|
||||||
PORT_LOG = os.path.join(LOGS_PATH, "./port.log")
|
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""Creating a POST Request"""
|
"""Creating a POST Request"""
|
||||||
ret = 0
|
ret = 0
|
||||||
try:
|
try:
|
||||||
with open(PORT_LOG, 'r') as file:
|
file_path = os.path.join(RESULT_PATH, "./Testing/logs/url.log")
|
||||||
port = file.readline()
|
with open(file_path, mode="r", encoding="utf-8") as file:
|
||||||
conn = http.client.HTTPConnection('localhost', port)
|
url = file.readline()
|
||||||
|
host, port = url.split(":")
|
||||||
|
conn = http.client.HTTPConnection(host, port)
|
||||||
conn.request('POST', '/kill_server')
|
conn.request('POST', '/kill_server')
|
||||||
response = conn.getresponse()
|
response = conn.getresponse()
|
||||||
print("HTTP status code:", response.getcode(), end=', ')
|
print("HTTP status code:", response.getcode(), end=', ')
|
||||||
|
@ -1,424 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
result=0
|
|
||||||
|
|
||||||
test_result() {
|
|
||||||
if test "$1" -eq 0
|
|
||||||
then
|
|
||||||
printf "Succeeded\n" >> "makecerts.log"
|
|
||||||
else
|
|
||||||
printf "Failed\n" >> "makecerts.log"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
make_certs() {
|
|
||||||
password=passme
|
|
||||||
result_path=$(pwd)
|
|
||||||
cd $(dirname "$0")
|
|
||||||
script_path=$(pwd)
|
|
||||||
cd "${result_path}"
|
|
||||||
mkdir "tmp/"
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# OpenSSL settings
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
if test -n "$1"
|
|
||||||
then
|
|
||||||
OPENSSL="$1/bin/openssl"
|
|
||||||
export LD_LIBRARY_PATH="$1/lib:$1/lib64"
|
|
||||||
else
|
|
||||||
OPENSSL=openssl
|
|
||||||
fi
|
|
||||||
|
|
||||||
mkdir "CA/" 2>> "makecerts.log" 1>&2
|
|
||||||
touch "CA/index.txt"
|
|
||||||
echo -n "unique_subject = no" > "CA/index.txt.attr"
|
|
||||||
$OPENSSL rand -hex 16 > "CA/serial"
|
|
||||||
$OPENSSL rand -hex 16 > "tmp/tsa-serial"
|
|
||||||
echo 1001 > "CA/crlnumber"
|
|
||||||
date > "makecerts.log"
|
|
||||||
"$OPENSSL" version 2>> "makecerts.log" 1>&2
|
|
||||||
echo -n "$password" > tmp/password.txt
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Root CA certificate
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
printf "\nGenerate root CA certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" genrsa -out CA/CA.key \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_root.cnf"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/CA.key -out tmp/CACert.pem \
|
|
||||||
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Root CA" \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Private RSA keys
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
printf "\nGenerate private RSA encrypted key\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" genrsa -des3 -out CA/private.key -passout pass:"$password" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
cat CA/private.key >> tmp/keyp.pem 2>> "makecerts.log"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate private RSA decrypted key\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" rsa -in CA/private.key -passin pass:"$password" -out tmp/key.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nConvert the key to DER format\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" rsa -in tmp/key.pem -outform DER -out tmp/key.der -passout pass:"$password" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nConvert the key to PVK format\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" rsa -in tmp/key.pem -outform PVK -out tmp/key.pvk -pvk-none \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Intermediate CA certificates
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
|
||||||
|
|
||||||
printf "\nGenerate intermediate CA certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" genrsa -out CA/intermediateCA.key \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -key CA/intermediateCA.key -out CA/intermediateCA.csr \
|
|
||||||
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Intermediate CA" \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_root.cnf"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/intermediateCA.csr -out CA/intermediateCA.cer \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/intermediateCA.cer -out tmp/intermediateCA.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate a certificate to revoke\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/revoked.csr \
|
|
||||||
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=Revoked/emailAddress=osslsigncode@example.com" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/revoked.csr -out CA/revoked.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/revoked.cer -out tmp/revoked.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nRevoke above certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -revoke CA/revoked.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to revoked certificate\n" >> "makecerts.log"
|
|
||||||
cat tmp/intermediateCA.pem >> tmp/revoked.pem 2>> "makecerts.log"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate CRL file\n" >> "makecerts.log"
|
|
||||||
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -gencrl -crldays 8766 -out tmp/CACertCRL.pem \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate CSP Cross-Certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" genrsa -out CA/cross.key \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
TZ=GMT faketime -f '@2018-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_intermediate.cnf"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -x509 -days 900 -key CA/cross.key -out tmp/crosscert.pem \
|
|
||||||
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=crosscert/emailAddress=osslsigncode@example.com" \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate code signing certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/cert.csr \
|
|
||||||
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate/emailAddress=osslsigncode@example.com" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/cert.csr -out CA/cert.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/cert.cer -out tmp/cert.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nConvert the certificate to DER format\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" x509 -in tmp/cert.pem -outform DER -out tmp/cert.der \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to code signing certificate\n" >> "makecerts.log"
|
|
||||||
cat tmp/intermediateCA.pem >> tmp/cert.pem 2>> "makecerts.log"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nConvert the certificate to SPC format\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" crl2pkcs7 -nocrl -certfile tmp/cert.pem -outform DER -out tmp/cert.spc \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
ssl_version=$("$OPENSSL" version)
|
|
||||||
if test "${ssl_version:8:1}" -eq 3
|
|
||||||
then
|
|
||||||
printf "\nConvert the certificate and the key into legacy PKCS#12 container with\
|
|
||||||
RC2-40-CBC private key and certificate encryption algorithm\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/legacy.p12 -passout pass:"$password" \
|
|
||||||
-keypbe rc2-40-cbc -certpbe rc2-40-cbc -legacy \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
else
|
|
||||||
printf "\nConvert the certificate and the key into legacy PKCS#12 container with\
|
|
||||||
RC2-40-CBC private key and certificate encryption algorithm\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/legacy.p12 -passout pass:"$password" \
|
|
||||||
-keypbe rc2-40-cbc -certpbe rc2-40-cbc \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
fi
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nConvert the certificate and the key into a PKCS#12 container with\
|
|
||||||
AES-256-CBC private key and certificate encryption algorithm\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" pkcs12 -export -in tmp/cert.pem -inkey tmp/key.pem -out tmp/cert.p12 -passout pass:"$password" \
|
|
||||||
-keypbe aes-256-cbc -certpbe aes-256-cbc \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate expired certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/expired.csr \
|
|
||||||
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Expired/emailAddress=osslsigncode@example.com" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" ca -config "$CONF" -enddate "190101000000Z" -batch -in CA/expired.csr -out CA/expired.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/expired.cer -out tmp/expired.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to expired certificate\n" >> "makecerts.log"
|
|
||||||
cat tmp/intermediateCA.pem >> tmp/expired.pem 2>> "makecerts.log"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Intermediate CA certificates with CRL distribution point
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
CONF="${script_path}/openssl_intermediate_crldp.cnf"
|
|
||||||
|
|
||||||
printf "\nGenerate intermediate CA certificate with CRL distribution point\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" genrsa -out CA/intermediateCA_crldp.key \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_intermediate_crldp.cnf"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -key CA/intermediateCA_crldp.key -out CA/intermediateCA_crldp.csr \
|
|
||||||
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Intermediate CA CRL DP" \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_root.cnf"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/intermediateCA_crldp.csr -out CA/intermediateCA_crldp.cer \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/intermediateCA_crldp.cer -out tmp/intermediateCA_crldp.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate a certificate with X509v3 CRL Distribution Points extension to revoke\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/revoked_crldp.csr \
|
|
||||||
-subj "/C=PL/O=osslsigncode/OU=CSP/CN=Revoked X509v3 CRL DP/emailAddress=osslsigncode@example.com" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/revoked_crldp.csr -out CA/revoked_crldp.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/revoked_crldp.cer -out tmp/revoked_crldp.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nRevoke above certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -revoke CA/revoked_crldp.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to revoked certificate\n" >> "makecerts.log"
|
|
||||||
cat tmp/intermediateCA_crldp.pem >> tmp/revoked_crldp.pem 2>> "makecerts.log"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate CRL file\n" >> "makecerts.log"
|
|
||||||
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_intermediate_crldp.cnf"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -gencrl -crldays 8766 -out tmp/CACertCRL_crldp.pem \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nConvert CRL file from PEM to DER (for CRL Distribution Points server to use) \n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" crl -in tmp/CACertCRL_crldp.pem -inform PEM -out tmp/CACertCRL.der -outform DER \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate code signing certificate with X509v3 CRL Distribution Points extension\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/cert_crldp.csr \
|
|
||||||
-subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate X509v3 CRL DP/emailAddress=osslsigncode@example.com" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/cert_crldp.csr -out CA/cert_crldp.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/cert_crldp.cer -out tmp/cert_crldp.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nAttach intermediate certificate to code signing certificate\n" >> "makecerts.log"
|
|
||||||
cat tmp/intermediateCA_crldp.pem >> tmp/cert_crldp.pem 2>> "makecerts.log"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Time Stamp Authority certificates
|
|
||||||
################################################################################
|
|
||||||
printf "\nGenerate Root CA TSA certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" genrsa -out CA/TSACA.key \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_tsa_root.cnf"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/TSACA.key -out tmp/TSACA.pem \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate TSA certificate to revoke\n" >> "makecerts.log"
|
|
||||||
CONF="${script_path}/openssl_tsa_root.cnf"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -nodes -keyout tmp/TSA_revoked.key -out CA/TSA_revoked.csr \
|
|
||||||
-subj "/C=PL/O=osslsigncode/OU=TSA/CN=Revoked/emailAddress=osslsigncode@example.com" \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
CONF="${script_path}/openssl_tsa_root.cnf"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/TSA_revoked.csr -out CA/TSA_revoked.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/TSA_revoked.cer -out tmp/TSA_revoked.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nRevoke above certificate\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -revoke CA/TSA_revoked.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate TSA CRL file\n" >> "makecerts.log"
|
|
||||||
TZ=GMT faketime -f '@2019-01-01 00:00:00' /bin/bash -c '
|
|
||||||
script_path=$(pwd)
|
|
||||||
OPENSSL="$0"
|
|
||||||
export LD_LIBRARY_PATH="$1"
|
|
||||||
CONF="${script_path}/openssl_tsa_root.cnf"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -gencrl -crldays 8766 -out tmp/TSACertCRL.pem \
|
|
||||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nConvert TSA CRL file from PEM to DER (for CRL Distribution Points server to use)\n" >> "makecerts.log"
|
|
||||||
"$OPENSSL" crl -in tmp/TSACertCRL.pem -inform PEM -out tmp/TSACertCRL.der -outform DER \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nGenerate TSA certificate\n" >> "makecerts.log"
|
|
||||||
CONF="${script_path}/openssl_tsa.cnf"
|
|
||||||
"$OPENSSL" req -config "$CONF" -new -nodes -keyout tmp/TSA.key -out CA/TSA.csr \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
CONF="${script_path}/openssl_tsa_root.cnf"
|
|
||||||
"$OPENSSL" ca -config "$CONF" -batch -in CA/TSA.csr -out CA/TSA.cer \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
"$OPENSSL" x509 -in CA/TSA.cer -out tmp/TSA.pem \
|
|
||||||
2>> "makecerts.log" 1>&2
|
|
||||||
test_result $?
|
|
||||||
|
|
||||||
printf "\nSave the chain to be included in the TSA response\n" >> "makecerts.log"
|
|
||||||
cat tmp/TSA.pem tmp/TSACA.pem > tmp/tsa-chain.pem 2>> "makecerts.log"
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Copy new files
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
if test -s tmp/CACert.pem \
|
|
||||||
-a -s tmp/intermediateCA.pem -a -s tmp/intermediateCA_crldp.pem \
|
|
||||||
-a -s tmp/CACertCRL.pem -a -s tmp/CACertCRL.der \
|
|
||||||
-a -s tmp/TSACertCRL.pem -a -s tmp/TSACertCRL.der \
|
|
||||||
-a -s tmp/key.pem -a -s tmp/keyp.pem -a -s tmp/key.der -a -s tmp/key.pvk \
|
|
||||||
-a -s tmp/cert.pem -a -s tmp/cert.der -a -s tmp/cert.spc \
|
|
||||||
-a -s tmp/cert.p12 -a -s tmp/legacy.p12 -a -s tmp/cert_crldp.pem\
|
|
||||||
-a -s tmp/crosscert.pem -a -s tmp/expired.pem \
|
|
||||||
-a -s tmp/revoked.pem -a -s tmp/revoked_crldp.pem \
|
|
||||||
-a -s tmp/TSA_revoked.pem \
|
|
||||||
-a -s tmp/TSA.pem -a -s tmp/TSA.key -a -s tmp/tsa-chain.pem
|
|
||||||
then
|
|
||||||
mkdir -p "../certs"
|
|
||||||
cp tmp/* ../certs
|
|
||||||
printf "%s" "Keys & certificates successfully generated"
|
|
||||||
else
|
|
||||||
printf "%s" "Error logs ${result_path}/makecerts.log"
|
|
||||||
result=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Remove the working directory
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
rm -rf "CA/"
|
|
||||||
rm -rf "tmp/"
|
|
||||||
|
|
||||||
exit "$result"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
################################################################################
|
|
||||||
# Tests requirement and make certs
|
|
||||||
################################################################################
|
|
||||||
|
|
||||||
if test -n "$(command -v faketime)"
|
|
||||||
then
|
|
||||||
make_certs "$1"
|
|
||||||
result=$?
|
|
||||||
else
|
|
||||||
printf "%s" "faketime not found in \$PATH, please install faketime package"
|
|
||||||
result=1
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit "$result"
|
|
@ -1,73 +0,0 @@
|
|||||||
# OpenSSL intermediate CA configuration file
|
|
||||||
|
|
||||||
[ default ]
|
|
||||||
name = intermediateCA
|
|
||||||
default_ca = CA_default
|
|
||||||
|
|
||||||
[ CA_default ]
|
|
||||||
# Directory and file locations
|
|
||||||
dir = .
|
|
||||||
certs = $dir/CA
|
|
||||||
crl_dir = $dir/CA
|
|
||||||
new_certs_dir = $dir/CA
|
|
||||||
database = $dir/CA/index.txt
|
|
||||||
serial = $dir/CA/serial
|
|
||||||
rand_serial = yes
|
|
||||||
private_key = $dir/CA/$name.key
|
|
||||||
certificate = $dir/tmp/$name.pem
|
|
||||||
crlnumber = $dir/CA/crlnumber
|
|
||||||
crl_extensions = crl_ext
|
|
||||||
default_md = sha256
|
|
||||||
preserve = no
|
|
||||||
policy = policy_loose
|
|
||||||
default_startdate = 180101000000Z
|
|
||||||
default_enddate = 241231000000Z
|
|
||||||
x509_extensions = v3_req
|
|
||||||
email_in_dn = yes
|
|
||||||
default_days = 2200
|
|
||||||
|
|
||||||
[ req ]
|
|
||||||
# Options for the `req` tool
|
|
||||||
encrypt_key = no
|
|
||||||
default_bits = 2048
|
|
||||||
default_md = sha256
|
|
||||||
string_mask = utf8only
|
|
||||||
distinguished_name = req_distinguished_name
|
|
||||||
x509_extensions = usr_extensions
|
|
||||||
|
|
||||||
[ crl_ext ]
|
|
||||||
# Extension for CRLs
|
|
||||||
authorityKeyIdentifier = keyid:always
|
|
||||||
|
|
||||||
[ usr_extensions ]
|
|
||||||
# Extension to add when the -x509 option is used
|
|
||||||
basicConstraints = CA:FALSE
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid, issuer
|
|
||||||
extendedKeyUsage = codeSigning
|
|
||||||
|
|
||||||
[ v3_req ]
|
|
||||||
basicConstraints = CA:FALSE
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid, issuer
|
|
||||||
extendedKeyUsage = codeSigning
|
|
||||||
|
|
||||||
[ policy_loose ]
|
|
||||||
# Allow the intermediate CA to sign a more diverse range of certificates.
|
|
||||||
# See the POLICY FORMAT section of the `ca` man page.
|
|
||||||
countryName = optional
|
|
||||||
stateOrProvinceName = optional
|
|
||||||
localityName = optional
|
|
||||||
organizationName = optional
|
|
||||||
organizationalUnitName = optional
|
|
||||||
commonName = supplied
|
|
||||||
emailAddress = optional
|
|
||||||
|
|
||||||
[ req_distinguished_name ]
|
|
||||||
countryName = Country Name (2 letter code)
|
|
||||||
stateOrProvinceName = State or Province Name
|
|
||||||
localityName = Locality Name
|
|
||||||
0.organizationName = Organization Name
|
|
||||||
organizationalUnitName = Organizational Unit Name
|
|
||||||
commonName = Common Name
|
|
||||||
emailAddress = Email Address
|
|
@ -1,79 +0,0 @@
|
|||||||
# OpenSSL intermediate CA configuration file
|
|
||||||
|
|
||||||
[ default ]
|
|
||||||
name = intermediateCA
|
|
||||||
default_ca = CA_default
|
|
||||||
crl_url = http://127.0.0.1:19254/$name
|
|
||||||
|
|
||||||
[ CA_default ]
|
|
||||||
# Directory and file locations
|
|
||||||
dir = .
|
|
||||||
certs = $dir/CA
|
|
||||||
crl_dir = $dir/CA
|
|
||||||
new_certs_dir = $dir/CA
|
|
||||||
database = $dir/CA/index.txt
|
|
||||||
serial = $dir/CA/serial
|
|
||||||
rand_serial = yes
|
|
||||||
private_key = $dir/CA/$name\_crldp.key
|
|
||||||
certificate = $dir/tmp/$name\_crldp.pem
|
|
||||||
crlnumber = $dir/CA/crlnumber
|
|
||||||
crl_extensions = crl_ext
|
|
||||||
default_md = sha256
|
|
||||||
preserve = no
|
|
||||||
policy = policy_loose
|
|
||||||
default_startdate = 180101000000Z
|
|
||||||
default_enddate = 241231000000Z
|
|
||||||
x509_extensions = v3_req
|
|
||||||
email_in_dn = yes
|
|
||||||
default_days = 2200
|
|
||||||
|
|
||||||
[ req ]
|
|
||||||
# Options for the `req` tool
|
|
||||||
encrypt_key = no
|
|
||||||
default_bits = 2048
|
|
||||||
default_md = sha256
|
|
||||||
string_mask = utf8only
|
|
||||||
distinguished_name = req_distinguished_name
|
|
||||||
x509_extensions = usr_extensions
|
|
||||||
|
|
||||||
[ crl_ext ]
|
|
||||||
# Extension for CRLs
|
|
||||||
authorityKeyIdentifier = keyid:always
|
|
||||||
|
|
||||||
[ usr_extensions ]
|
|
||||||
# Extension to add when the -x509 option is used
|
|
||||||
basicConstraints = CA:FALSE
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid, issuer
|
|
||||||
extendedKeyUsage = codeSigning
|
|
||||||
|
|
||||||
[ v3_req ]
|
|
||||||
basicConstraints = CA:FALSE
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid, issuer
|
|
||||||
extendedKeyUsage = codeSigning
|
|
||||||
crlDistributionPoints = @crl_info
|
|
||||||
|
|
||||||
[ crl_info ]
|
|
||||||
# X509v3 CRL Distribution Points extension
|
|
||||||
URI.0 = $crl_url
|
|
||||||
|
|
||||||
[ policy_loose ]
|
|
||||||
# Allow the intermediate CA to sign a more diverse range of certificates.
|
|
||||||
# See the POLICY FORMAT section of the `ca` man page.
|
|
||||||
countryName = optional
|
|
||||||
stateOrProvinceName = optional
|
|
||||||
localityName = optional
|
|
||||||
organizationName = optional
|
|
||||||
organizationalUnitName = optional
|
|
||||||
commonName = supplied
|
|
||||||
emailAddress = optional
|
|
||||||
|
|
||||||
[ req_distinguished_name ]
|
|
||||||
countryName = Country Name (2 letter code)
|
|
||||||
stateOrProvinceName = State or Province Name
|
|
||||||
localityName = Locality Name
|
|
||||||
0.organizationName = Organization Name
|
|
||||||
organizationalUnitName = Organizational Unit Name
|
|
||||||
commonName = Common Name
|
|
||||||
emailAddress = Email Address
|
|
@ -1,65 +0,0 @@
|
|||||||
# OpenSSL root CA configuration file
|
|
||||||
|
|
||||||
[ ca ]
|
|
||||||
default_ca = CA_default
|
|
||||||
|
|
||||||
[ CA_default ]
|
|
||||||
# Directory and file locations.
|
|
||||||
dir = .
|
|
||||||
certs = $dir/CA
|
|
||||||
crl_dir = $dir/CA
|
|
||||||
new_certs_dir = $dir/CA
|
|
||||||
database = $dir/CA/index.txt
|
|
||||||
serial = $dir/CA/serial
|
|
||||||
rand_serial = yes
|
|
||||||
private_key = $dir/CA/CA.key
|
|
||||||
certificate = $dir/tmp/CACert.pem
|
|
||||||
crl_extensions = crl_ext
|
|
||||||
default_md = sha256
|
|
||||||
preserve = no
|
|
||||||
policy = policy_match
|
|
||||||
default_startdate = 180101000000Z
|
|
||||||
default_enddate = 260101000000Z
|
|
||||||
x509_extensions = v3_intermediate_ca
|
|
||||||
email_in_dn = yes
|
|
||||||
default_days = 3000
|
|
||||||
unique_subject = no
|
|
||||||
|
|
||||||
[ req ]
|
|
||||||
# Options for the `req` tool
|
|
||||||
encrypt_key = no
|
|
||||||
default_bits = 2048
|
|
||||||
default_md = sha256
|
|
||||||
string_mask = utf8only
|
|
||||||
x509_extensions = ca_extensions
|
|
||||||
distinguished_name = req_distinguished_name
|
|
||||||
|
|
||||||
[ ca_extensions ]
|
|
||||||
# Extension to add when the -x509 option is used
|
|
||||||
basicConstraints = critical, CA:true
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid:always,issuer
|
|
||||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
|
||||||
|
|
||||||
[ v3_intermediate_ca ]
|
|
||||||
# Extensions for a typical intermediate CA (`man x509v3_config`)
|
|
||||||
basicConstraints = critical, CA:true, pathlen:0
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid:always,issuer
|
|
||||||
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
|
|
||||||
|
|
||||||
[ policy_match ]
|
|
||||||
countryName = match
|
|
||||||
organizationName = match
|
|
||||||
organizationalUnitName = optional
|
|
||||||
commonName = supplied
|
|
||||||
emailAddress = optional
|
|
||||||
|
|
||||||
[ req_distinguished_name ]
|
|
||||||
countryName = Country Name (2 letter code)
|
|
||||||
stateOrProvinceName = State or Province Name
|
|
||||||
localityName = Locality Name
|
|
||||||
0.organizationName = Organization Name
|
|
||||||
organizationalUnitName = Organizational Unit Name
|
|
||||||
commonName = Common Name
|
|
||||||
emailAddress = Email Address
|
|
@ -44,3 +44,4 @@ ordering = yes
|
|||||||
tsa_name = yes
|
tsa_name = yes
|
||||||
ess_cert_id_chain = yes
|
ess_cert_id_chain = yes
|
||||||
ess_cert_id_alg = sha256
|
ess_cert_id_alg = sha256
|
||||||
|
crypto_device = builtin
|
||||||
|
@ -1,83 +0,0 @@
|
|||||||
# OpenSSL Root Timestamp Authority configuration file
|
|
||||||
|
|
||||||
[ default ]
|
|
||||||
name = TSACA
|
|
||||||
domain_suffix = timestampauthority
|
|
||||||
crl_url = http://127.0.0.1:19254/$name
|
|
||||||
name_opt = utf8, esc_ctrl, multiline, lname, align
|
|
||||||
default_ca = CA_default
|
|
||||||
|
|
||||||
[ CA_default ]
|
|
||||||
dir = .
|
|
||||||
certs = $dir/CA
|
|
||||||
crl_dir = $dir/CA
|
|
||||||
new_certs_dir = $dir/CA
|
|
||||||
database = $dir/CA/index.txt
|
|
||||||
serial = $dir/CA/serial
|
|
||||||
crlnumber = $dir/CA/crlnumber
|
|
||||||
crl_extensions = crl_ext
|
|
||||||
rand_serial = yes
|
|
||||||
private_key = $dir/CA/$name.key
|
|
||||||
certificate = $dir/tmp/$name.pem
|
|
||||||
default_md = sha256
|
|
||||||
default_days = 3650
|
|
||||||
default_crl_days = 365
|
|
||||||
policy = policy_match
|
|
||||||
default_startdate = 20180101000000Z
|
|
||||||
default_enddate = 20280101000000Z
|
|
||||||
unique_subject = no
|
|
||||||
email_in_dn = no
|
|
||||||
x509_extensions = tsa_extensions
|
|
||||||
|
|
||||||
[ policy_match ]
|
|
||||||
countryName = match
|
|
||||||
stateOrProvinceName = optional
|
|
||||||
organizationName = match
|
|
||||||
organizationalUnitName = optional
|
|
||||||
commonName = supplied
|
|
||||||
emailAddress = optional
|
|
||||||
|
|
||||||
[ tsa_extensions ]
|
|
||||||
basicConstraints = critical, CA:false
|
|
||||||
extendedKeyUsage = critical, timeStamping
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
authorityKeyIdentifier = keyid:always
|
|
||||||
crlDistributionPoints = @crl_info
|
|
||||||
nameConstraints = @name_constraints
|
|
||||||
|
|
||||||
[ crl_info ]
|
|
||||||
# X509v3 CRL Distribution Points extension
|
|
||||||
URI.0 = $crl_url
|
|
||||||
|
|
||||||
[ crl_ext ]
|
|
||||||
# Extension for CRLs
|
|
||||||
authorityKeyIdentifier = keyid:always
|
|
||||||
|
|
||||||
[ name_constraints ]
|
|
||||||
permitted;DNS.0=test.com
|
|
||||||
permitted;DNS.1=test.org
|
|
||||||
excluded;IP.0=0.0.0.0/0.0.0.0
|
|
||||||
excluded;IP.1=0:0:0:0:0:0:0:0/0:0:0:0:0:0:0:0
|
|
||||||
|
|
||||||
[ req ]
|
|
||||||
# Options for the `req` tool
|
|
||||||
default_bits = 2048
|
|
||||||
encrypt_key = yes
|
|
||||||
default_md = sha256
|
|
||||||
utf8 = yes
|
|
||||||
string_mask = utf8only
|
|
||||||
prompt = no
|
|
||||||
distinguished_name = ca_distinguished_name
|
|
||||||
x509_extensions = ca_extensions
|
|
||||||
|
|
||||||
[ ca_distinguished_name ]
|
|
||||||
countryName = "PL"
|
|
||||||
organizationName = "osslsigncode"
|
|
||||||
organizationalUnitName = "Timestamp Authority Root CA"
|
|
||||||
commonName = "TSA Root CA"
|
|
||||||
|
|
||||||
[ ca_extensions ]
|
|
||||||
# Extension to add when the -x509 option is used
|
|
||||||
basicConstraints = critical, CA:true
|
|
||||||
subjectKeyIdentifier = hash
|
|
||||||
keyUsage = critical, keyCertSign, cRLSign
|
|
47
tests/exec.py
Normal file
47
tests/exec.py
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
"""Implementation of a single ctest script."""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
|
|
||||||
|
def parse(value):
|
||||||
|
"""Read parameter from file."""
|
||||||
|
prefix = 'FILE '
|
||||||
|
if value.startswith(prefix):
|
||||||
|
with open(value[len(prefix):], mode="r", encoding="utf-8") as file:
|
||||||
|
return file.read().strip()
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Run osslsigncode with its options."""
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
try:
|
||||||
|
params = map(parse, sys.argv[1:])
|
||||||
|
proc = Popen(params, stdout=PIPE, stderr=PIPE, text=True)
|
||||||
|
stdout, stderr = proc.communicate()
|
||||||
|
print(stdout, file=sys.stderr)
|
||||||
|
if stderr:
|
||||||
|
print("Error:\n" + "-" * 58 + "\n" + stderr, file=sys.stderr)
|
||||||
|
sys.exit(proc.returncode)
|
||||||
|
except Exception as err: # pylint: disable=broad-except
|
||||||
|
# all exceptions are critical
|
||||||
|
print(err, file=sys.stderr)
|
||||||
|
else:
|
||||||
|
print("Usage:\n\t{} COMMAND [ARG]...'".format(sys.argv[0]), file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=pointless-string-statement
|
||||||
|
"""Local Variables:
|
||||||
|
c-basic-offset: 4
|
||||||
|
tab-width: 4
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
End:
|
||||||
|
vim: set ts=4 expandtab:
|
||||||
|
"""
|
0
tests/files/unsigned.256appx
Executable file → Normal file
0
tests/files/unsigned.256appx
Executable file → Normal file
0
tests/files/unsigned.512appx
Executable file → Normal file
0
tests/files/unsigned.512appx
Executable file → Normal file
Binary file not shown.
BIN
tests/files/unsigned.mof
Normal file
BIN
tests/files/unsigned.mof
Normal file
Binary file not shown.
2
tests/files/unsigned.ps1
Normal file
2
tests/files/unsigned.ps1
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
cls
|
||||||
|
Write-Host "żółć"
|
5
tests/files/unsigned.psc1
Normal file
5
tests/files/unsigned.psc1
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PSConsoleFile ConsoleSchemaVersion="1.0">
|
||||||
|
<PSVersion>5.1.19041.3930</PSVersion>
|
||||||
|
<PSSnapIns />
|
||||||
|
</PSConsoleFile>
|
581
tests/make_certificates.py
Normal file
581
tests/make_certificates.py
Normal file
@ -0,0 +1,581 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
"""Make test certificates"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import datetime
|
||||||
|
import cryptography
|
||||||
|
|
||||||
|
# Explicit imports of cryptography submodules
|
||||||
|
import cryptography.x509
|
||||||
|
import cryptography.x509.oid
|
||||||
|
import cryptography.hazmat.primitives.hashes
|
||||||
|
import cryptography.hazmat.primitives.asymmetric.rsa
|
||||||
|
import cryptography.hazmat.primitives.serialization
|
||||||
|
import cryptography.hazmat.primitives.serialization.pkcs12
|
||||||
|
|
||||||
|
# Import classes and functions from the cryptography module
|
||||||
|
from cryptography.x509 import (
|
||||||
|
AuthorityKeyIdentifier,
|
||||||
|
BasicConstraints,
|
||||||
|
Certificate,
|
||||||
|
CertificateBuilder,
|
||||||
|
CertificateRevocationListBuilder,
|
||||||
|
CRLDistributionPoints,
|
||||||
|
CRLNumber,
|
||||||
|
CRLReason,
|
||||||
|
DistributionPoint,
|
||||||
|
DNSName,
|
||||||
|
ExtendedKeyUsage,
|
||||||
|
KeyUsage,
|
||||||
|
Name,
|
||||||
|
NameAttribute,
|
||||||
|
NameConstraints,
|
||||||
|
random_serial_number,
|
||||||
|
RevokedCertificateBuilder,
|
||||||
|
ReasonFlags,
|
||||||
|
SubjectKeyIdentifier,
|
||||||
|
UniformResourceIdentifier
|
||||||
|
)
|
||||||
|
from cryptography.x509.oid import (
|
||||||
|
ExtendedKeyUsageOID,
|
||||||
|
NameOID
|
||||||
|
)
|
||||||
|
from cryptography.hazmat.primitives.hashes import SHA256
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.rsa import (
|
||||||
|
generate_private_key,
|
||||||
|
RSAPrivateKey
|
||||||
|
)
|
||||||
|
from cryptography.hazmat.primitives.serialization import (
|
||||||
|
BestAvailableEncryption,
|
||||||
|
Encoding,
|
||||||
|
NoEncryption,
|
||||||
|
PrivateFormat
|
||||||
|
)
|
||||||
|
from cryptography.hazmat.primitives.serialization.pkcs12 import serialize_key_and_certificates
|
||||||
|
|
||||||
|
try:
|
||||||
|
if cryptography.__version__ >= '38.0.0':
|
||||||
|
from cryptography.hazmat.primitives.serialization.pkcs12 import PBES
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
RESULT_PATH = os.getcwd()
|
||||||
|
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||||
|
|
||||||
|
date_20170101 = datetime.datetime(2017, 1, 1)
|
||||||
|
date_20180101 = datetime.datetime(2018, 1, 1)
|
||||||
|
date_20190101 = datetime.datetime(2019, 1, 1)
|
||||||
|
|
||||||
|
PASSWORD='passme'
|
||||||
|
|
||||||
|
|
||||||
|
class X509Extensions():
|
||||||
|
"""Base class for X509 Extensions"""
|
||||||
|
|
||||||
|
def __init__(self, unit_name, cdp_port, cdp_name):
|
||||||
|
self.unit_name = unit_name
|
||||||
|
self.port = cdp_port
|
||||||
|
self.name = cdp_name
|
||||||
|
|
||||||
|
def create_x509_name(self, common_name) -> Name:
|
||||||
|
"""Return x509.Name"""
|
||||||
|
return Name(
|
||||||
|
[
|
||||||
|
NameAttribute(NameOID.COUNTRY_NAME, "PL"),
|
||||||
|
NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Mazovia Province"),
|
||||||
|
NameAttribute(NameOID.LOCALITY_NAME, "Warsaw"),
|
||||||
|
NameAttribute(NameOID.ORGANIZATION_NAME, "osslsigncode"),
|
||||||
|
NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, self.unit_name),
|
||||||
|
NameAttribute(NameOID.COMMON_NAME, common_name)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_x509_crldp(self) -> CRLDistributionPoints:
|
||||||
|
"""Return x509.CRLDistributionPoints"""
|
||||||
|
return CRLDistributionPoints(
|
||||||
|
[
|
||||||
|
DistributionPoint(
|
||||||
|
full_name=[UniformResourceIdentifier(
|
||||||
|
"http://127.0.0.1:" + str(self.port) + "/" + str(self.name))
|
||||||
|
],
|
||||||
|
relative_name=None,
|
||||||
|
reasons=None,
|
||||||
|
crl_issuer=None
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
def create_x509_name_constraints(self) -> NameConstraints:
|
||||||
|
"""Return x509.NameConstraints"""
|
||||||
|
return NameConstraints(
|
||||||
|
permitted_subtrees = [DNSName('test.com'), DNSName('test.org')],
|
||||||
|
excluded_subtrees = None
|
||||||
|
)
|
||||||
|
|
||||||
|
class IntermediateCACertificate(X509Extensions):
|
||||||
|
"""Base class for Intermediate CA certificate"""
|
||||||
|
|
||||||
|
def __init__(self, issuer_cert, issuer_key):
|
||||||
|
self.issuer_cert = issuer_cert
|
||||||
|
self.issuer_key = issuer_key
|
||||||
|
super().__init__("Certification Authority", 0, None)
|
||||||
|
|
||||||
|
def make_cert(self) -> (Certificate, RSAPrivateKey):
|
||||||
|
"""Generate intermediate CA certificate"""
|
||||||
|
key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||||
|
key_public = key.public_key()
|
||||||
|
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||||
|
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||||
|
)
|
||||||
|
key_usage = KeyUsage(
|
||||||
|
digital_signature=True,
|
||||||
|
content_commitment=False,
|
||||||
|
key_encipherment=False,
|
||||||
|
data_encipherment=False,
|
||||||
|
key_agreement=False,
|
||||||
|
key_cert_sign=True,
|
||||||
|
crl_sign=True,
|
||||||
|
encipher_only=False,
|
||||||
|
decipher_only=False
|
||||||
|
)
|
||||||
|
cert = (
|
||||||
|
CertificateBuilder()
|
||||||
|
.subject_name(self.create_x509_name("Intermediate CA"))
|
||||||
|
.issuer_name(self.issuer_cert.subject)
|
||||||
|
.public_key(key_public)
|
||||||
|
.serial_number(random_serial_number())
|
||||||
|
.not_valid_before(date_20180101)
|
||||||
|
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
|
||||||
|
.add_extension(BasicConstraints(ca=True, path_length=0), critical=True)
|
||||||
|
.add_extension(SubjectKeyIdentifier.from_public_key(key_public), critical=False)
|
||||||
|
.add_extension(authority_key, critical=False)
|
||||||
|
.add_extension(key_usage, critical=True)
|
||||||
|
.sign(self.issuer_key, SHA256())
|
||||||
|
)
|
||||||
|
file_path=os.path.join(CERTS_PATH, "intermediateCA.pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
|
||||||
|
return cert, key
|
||||||
|
|
||||||
|
|
||||||
|
class RootCACertificate(X509Extensions):
|
||||||
|
"""Base class for Root CA certificate"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.key_usage = KeyUsage(
|
||||||
|
digital_signature=True,
|
||||||
|
content_commitment=False,
|
||||||
|
key_encipherment=False,
|
||||||
|
data_encipherment=False,
|
||||||
|
key_agreement=False,
|
||||||
|
key_cert_sign=True,
|
||||||
|
crl_sign=True,
|
||||||
|
encipher_only=False,
|
||||||
|
decipher_only=False
|
||||||
|
)
|
||||||
|
super().__init__("Certification Authority", 0, None)
|
||||||
|
|
||||||
|
def make_cert(self) -> (Certificate, RSAPrivateKey):
|
||||||
|
"""Generate CA certificates"""
|
||||||
|
ca_root, root_key = self.make_ca_cert("Trusted Root CA", "CAroot.pem")
|
||||||
|
ca_cert, ca_key = self.make_ca_cert("Root CA", "CACert.pem")
|
||||||
|
self.make_cross_cert(ca_root, root_key, ca_cert, ca_key)
|
||||||
|
return ca_cert, ca_key
|
||||||
|
|
||||||
|
def make_ca_cert(self, common_name, file_name) -> None:
|
||||||
|
"""Generate self-signed root CA certificate"""
|
||||||
|
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||||
|
ca_public = ca_key.public_key()
|
||||||
|
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||||
|
name = self.create_x509_name(common_name)
|
||||||
|
ca_cert = (
|
||||||
|
CertificateBuilder()
|
||||||
|
.subject_name(name)
|
||||||
|
.issuer_name(name)
|
||||||
|
.public_key(ca_public)
|
||||||
|
.serial_number(random_serial_number())
|
||||||
|
.not_valid_before(date_20170101)
|
||||||
|
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
|
||||||
|
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
|
||||||
|
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||||
|
.add_extension(authority_key, critical=False)
|
||||||
|
.add_extension(self.key_usage, critical=True)
|
||||||
|
.sign(ca_key, SHA256())
|
||||||
|
)
|
||||||
|
file_path=os.path.join(CERTS_PATH, file_name)
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(ca_cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
return ca_cert, ca_key
|
||||||
|
|
||||||
|
def make_cross_cert(self, ca_root, root_key, ca_cert, ca_key) -> None:
|
||||||
|
"""Generate cross-signed root CA certificate"""
|
||||||
|
ca_public = ca_key.public_key()
|
||||||
|
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||||
|
ca_root.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||||
|
)
|
||||||
|
ca_cross = (
|
||||||
|
CertificateBuilder()
|
||||||
|
.subject_name(ca_cert.subject)
|
||||||
|
.issuer_name(ca_root.subject)
|
||||||
|
.public_key(ca_public)
|
||||||
|
.serial_number(ca_cert.serial_number)
|
||||||
|
.not_valid_before(date_20180101)
|
||||||
|
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
|
||||||
|
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
|
||||||
|
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||||
|
.add_extension(authority_key, critical=False)
|
||||||
|
.add_extension(self.key_usage, critical=True)
|
||||||
|
.sign(root_key, SHA256())
|
||||||
|
)
|
||||||
|
file_path=os.path.join(CERTS_PATH, "CAcross.pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(ca_cross.public_bytes(encoding=Encoding.PEM))
|
||||||
|
|
||||||
|
def write_key(self, key, file_name) -> None:
|
||||||
|
"""Write a private RSA key"""
|
||||||
|
# Write password
|
||||||
|
file_path = os.path.join(CERTS_PATH, "password.txt")
|
||||||
|
with open(file_path, mode="w", encoding="utf-8") as file:
|
||||||
|
file.write("{}".format(PASSWORD))
|
||||||
|
|
||||||
|
# Write encrypted key in PEM format
|
||||||
|
file_path = os.path.join(CERTS_PATH, file_name + "p.pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(key.private_bytes(
|
||||||
|
encoding=Encoding.PEM,
|
||||||
|
format=PrivateFormat.PKCS8,
|
||||||
|
encryption_algorithm=BestAvailableEncryption(PASSWORD.encode())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Write decrypted key in PEM format
|
||||||
|
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(key.private_bytes(
|
||||||
|
encoding=Encoding.PEM,
|
||||||
|
format=PrivateFormat.PKCS8,
|
||||||
|
encryption_algorithm=NoEncryption()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
# Write the key in DER format
|
||||||
|
file_path = os.path.join(CERTS_PATH, file_name + ".der")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(key.private_bytes(
|
||||||
|
encoding=Encoding.DER,
|
||||||
|
format=PrivateFormat.PKCS8,
|
||||||
|
encryption_algorithm=NoEncryption()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TSARootCACertificate(X509Extensions):
|
||||||
|
"""Base class for TSA certificates"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__("Timestamp Authority Root CA", 0, None)
|
||||||
|
|
||||||
|
def make_cert(self) -> (Certificate, RSAPrivateKey):
|
||||||
|
"""Generate a Time Stamp Authority certificate"""
|
||||||
|
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||||
|
ca_public = ca_key.public_key()
|
||||||
|
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||||
|
name = self.create_x509_name("TSA Root CA")
|
||||||
|
key_usage = KeyUsage(
|
||||||
|
digital_signature=False,
|
||||||
|
content_commitment=False,
|
||||||
|
key_encipherment=False,
|
||||||
|
data_encipherment=False,
|
||||||
|
key_agreement=False,
|
||||||
|
key_cert_sign=True,
|
||||||
|
crl_sign=True,
|
||||||
|
encipher_only=False,
|
||||||
|
decipher_only=False
|
||||||
|
)
|
||||||
|
ca_cert = (
|
||||||
|
CertificateBuilder()
|
||||||
|
.subject_name(name)
|
||||||
|
.issuer_name(name)
|
||||||
|
.public_key(ca_public)
|
||||||
|
.serial_number(random_serial_number())
|
||||||
|
.not_valid_before(date_20170101)
|
||||||
|
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
|
||||||
|
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
|
||||||
|
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||||
|
.add_extension(authority_key, critical=False)
|
||||||
|
.add_extension(key_usage, critical=True)
|
||||||
|
.sign(ca_key, SHA256())
|
||||||
|
)
|
||||||
|
file_path=os.path.join(CERTS_PATH, "TSACA.pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(ca_cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
|
||||||
|
return ca_cert, ca_key
|
||||||
|
|
||||||
|
def write_key(self, key, file_name) -> None:
|
||||||
|
"""Write decrypted private RSA key into PEM format"""
|
||||||
|
file_path = os.path.join(CERTS_PATH, file_name + ".key")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(key.private_bytes(
|
||||||
|
encoding=Encoding.PEM,
|
||||||
|
format=PrivateFormat.PKCS8,
|
||||||
|
encryption_algorithm=NoEncryption()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class LeafCertificate(X509Extensions):
|
||||||
|
"""Base class for a leaf certificate"""
|
||||||
|
|
||||||
|
def __init__(self, issuer_cert, issuer_key, unit_name, common_name, cdp_port, cdp_name):
|
||||||
|
#pylint: disable=too-many-arguments
|
||||||
|
self.issuer_cert = issuer_cert
|
||||||
|
self.issuer_key = issuer_key
|
||||||
|
self.common_name = common_name
|
||||||
|
super().__init__(unit_name, cdp_port, cdp_name)
|
||||||
|
|
||||||
|
def make_cert(self, public_key, not_before, days) -> Certificate:
|
||||||
|
"""Generate a leaf certificate"""
|
||||||
|
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||||
|
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||||
|
)
|
||||||
|
extended_key_usage = ExtendedKeyUsage(
|
||||||
|
[ExtendedKeyUsageOID.CODE_SIGNING]
|
||||||
|
)
|
||||||
|
cert = (
|
||||||
|
CertificateBuilder()
|
||||||
|
.subject_name(self.create_x509_name(self.common_name))
|
||||||
|
.issuer_name(self.issuer_cert.subject)
|
||||||
|
.public_key(public_key)
|
||||||
|
.serial_number(random_serial_number())
|
||||||
|
.not_valid_before(not_before)
|
||||||
|
.not_valid_after(not_before + datetime.timedelta(days=days))
|
||||||
|
.add_extension(BasicConstraints(ca=False, path_length=None), critical=False)
|
||||||
|
.add_extension(SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||||
|
.add_extension(authority_key, critical=False)
|
||||||
|
.add_extension(extended_key_usage, critical=False)
|
||||||
|
.add_extension(self.create_x509_crldp(), critical=False)
|
||||||
|
.sign(self.issuer_key, SHA256())
|
||||||
|
)
|
||||||
|
# Write PEM file and attach intermediate certificate
|
||||||
|
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
file.write(self.issuer_cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
|
||||||
|
return cert
|
||||||
|
|
||||||
|
def revoke_cert(self, serial_number, file_name) -> None:
|
||||||
|
"""Revoke a certificate"""
|
||||||
|
revoked = (
|
||||||
|
RevokedCertificateBuilder()
|
||||||
|
.serial_number(serial_number)
|
||||||
|
.revocation_date(date_20190101)
|
||||||
|
.add_extension(CRLReason(ReasonFlags.superseded), critical=False)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
# Generate CRL
|
||||||
|
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||||
|
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||||
|
)
|
||||||
|
crl = (
|
||||||
|
CertificateRevocationListBuilder()
|
||||||
|
.issuer_name(self.issuer_cert.subject)
|
||||||
|
.last_update(date_20190101)
|
||||||
|
.next_update(date_20190101 + datetime.timedelta(days=7300))
|
||||||
|
.add_extension(authority_key, critical=False)
|
||||||
|
.add_extension(CRLNumber(4097), critical=False)
|
||||||
|
.add_revoked_certificate(revoked)
|
||||||
|
.sign(self.issuer_key, SHA256())
|
||||||
|
)
|
||||||
|
# Write CRL file
|
||||||
|
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(crl.public_bytes(encoding=Encoding.PEM))
|
||||||
|
|
||||||
|
file_path = os.path.join(CERTS_PATH, file_name + ".der")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(crl.public_bytes(encoding=Encoding.DER))
|
||||||
|
|
||||||
|
|
||||||
|
class LeafCACertificate(LeafCertificate):
|
||||||
|
"""Base class for a leaf certificate"""
|
||||||
|
|
||||||
|
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
|
||||||
|
super().__init__(issuer_cert, issuer_key, "CSP", common, cdp_port, "intermediateCA")
|
||||||
|
|
||||||
|
|
||||||
|
class LeafTSACertificate(LeafCertificate):
|
||||||
|
"""Base class for a TSA leaf certificate"""
|
||||||
|
|
||||||
|
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
|
||||||
|
self.issuer_cert = issuer_cert
|
||||||
|
self.issuer_key = issuer_key
|
||||||
|
self.common_name = common
|
||||||
|
super().__init__(issuer_cert, issuer_key, "Timestamp Root CA", common, cdp_port, "TSACA")
|
||||||
|
|
||||||
|
def make_cert(self, public_key, not_before, days) -> Certificate:
|
||||||
|
"""Generate a TSA leaf certificate"""
|
||||||
|
|
||||||
|
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||||
|
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||||
|
)
|
||||||
|
|
||||||
|
# The TSA signing certificate must have exactly one extended key usage
|
||||||
|
# assigned to it: timeStamping. The extended key usage must also be critical,
|
||||||
|
# otherwise the certificate is going to be refused.
|
||||||
|
extended_key_usage = ExtendedKeyUsage(
|
||||||
|
[ExtendedKeyUsageOID.TIME_STAMPING]
|
||||||
|
)
|
||||||
|
cert = (
|
||||||
|
CertificateBuilder()
|
||||||
|
.subject_name(self.create_x509_name(self.common_name))
|
||||||
|
.issuer_name(self.issuer_cert.subject)
|
||||||
|
.public_key(public_key)
|
||||||
|
.serial_number(random_serial_number())
|
||||||
|
.not_valid_before(not_before)
|
||||||
|
.not_valid_after(not_before + datetime.timedelta(days=days))
|
||||||
|
.add_extension(BasicConstraints(ca=False, path_length=None), critical=True)
|
||||||
|
.add_extension(SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||||
|
.add_extension(authority_key, critical=False)
|
||||||
|
.add_extension(extended_key_usage, critical=True)
|
||||||
|
.add_extension(self.create_x509_crldp(), critical=False)
|
||||||
|
.add_extension(self.create_x509_name_constraints(), critical=False)
|
||||||
|
.sign(self.issuer_key, SHA256())
|
||||||
|
)
|
||||||
|
# Write PEM file and attach intermediate certificate
|
||||||
|
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
file.write(self.issuer_cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
|
||||||
|
return cert
|
||||||
|
|
||||||
|
|
||||||
|
class CertificateMaker():
|
||||||
|
"""Base class for test certificates"""
|
||||||
|
|
||||||
|
def __init__(self, cdp_port, logs):
|
||||||
|
self.cdp_port = cdp_port
|
||||||
|
self.logs = logs
|
||||||
|
|
||||||
|
def make_certs(self) -> None:
|
||||||
|
"""Make test certificates"""
|
||||||
|
try:
|
||||||
|
self.make_ca_certs()
|
||||||
|
self.make_tsa_certs()
|
||||||
|
logs = os.path.join(CERTS_PATH, "./cert.log")
|
||||||
|
with open(logs, mode="w", encoding="utf-8") as file:
|
||||||
|
file.write("Test certificates generation succeeded")
|
||||||
|
except Exception as err: # pylint: disable=broad-except
|
||||||
|
with open(self.logs, mode="a", encoding="utf-8") as file:
|
||||||
|
file.write("Error: {}".format(err))
|
||||||
|
|
||||||
|
def make_ca_certs(self):
|
||||||
|
"""Make test certificates"""
|
||||||
|
|
||||||
|
# Generate root CA certificate
|
||||||
|
root = RootCACertificate()
|
||||||
|
ca_cert, ca_key = root.make_cert()
|
||||||
|
|
||||||
|
# Generate intermediate root CA certificate
|
||||||
|
intermediate = IntermediateCACertificate(ca_cert, ca_key)
|
||||||
|
issuer_cert, issuer_key = intermediate.make_cert()
|
||||||
|
|
||||||
|
# Generate private RSA key
|
||||||
|
private_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||||
|
public_key = private_key.public_key()
|
||||||
|
root.write_key(key=private_key, file_name="key")
|
||||||
|
|
||||||
|
# Generate expired certificate
|
||||||
|
expired = LeafCACertificate(issuer_cert, issuer_key, "expired", self.cdp_port)
|
||||||
|
expired.make_cert(public_key, date_20180101, 365)
|
||||||
|
|
||||||
|
# Generate revoked certificate
|
||||||
|
revoked = LeafCACertificate(issuer_cert, issuer_key, "revoked", self.cdp_port)
|
||||||
|
cert = revoked.make_cert(public_key, date_20180101, 5840)
|
||||||
|
revoked.revoke_cert(cert.serial_number, "CACertCRL")
|
||||||
|
|
||||||
|
# Generate code signing certificate
|
||||||
|
signer = LeafCACertificate(issuer_cert, issuer_key, "cert", self.cdp_port)
|
||||||
|
cert = signer.make_cert(public_key, date_20180101, 5840)
|
||||||
|
|
||||||
|
# Write a certificate and a key into PKCS#12 container
|
||||||
|
self.write_pkcs12_container(
|
||||||
|
cert=cert,
|
||||||
|
key=private_key,
|
||||||
|
issuer=issuer_cert
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write DER file and attach intermediate certificate
|
||||||
|
file_path = os.path.join(CERTS_PATH, "cert.der")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(cert.public_bytes(encoding=Encoding.DER))
|
||||||
|
|
||||||
|
def make_tsa_certs(self):
|
||||||
|
"""Make test TSA certificates"""
|
||||||
|
|
||||||
|
# Time Stamp Authority certificate
|
||||||
|
root = TSARootCACertificate()
|
||||||
|
issuer_cert, issuer_key = root.make_cert()
|
||||||
|
|
||||||
|
# Generate private RSA key
|
||||||
|
private_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||||
|
public_key = private_key.public_key()
|
||||||
|
root.write_key(key=private_key, file_name="TSA")
|
||||||
|
|
||||||
|
# Generate revoked TSA certificate
|
||||||
|
revoked = LeafTSACertificate(issuer_cert, issuer_key, "TSA_revoked", self.cdp_port)
|
||||||
|
cert = revoked.make_cert(public_key, date_20180101, 7300)
|
||||||
|
revoked.revoke_cert(cert.serial_number, "TSACertCRL")
|
||||||
|
|
||||||
|
# Generate TSA certificate
|
||||||
|
signer = LeafTSACertificate(issuer_cert, issuer_key, "TSA", self.cdp_port)
|
||||||
|
cert = signer.make_cert(public_key, date_20180101, 7300)
|
||||||
|
|
||||||
|
# Save the chain to be included in the TSA response
|
||||||
|
file_path = os.path.join(CERTS_PATH, "tsa-chain.pem")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
file.write(issuer_cert.public_bytes(encoding=Encoding.PEM))
|
||||||
|
|
||||||
|
|
||||||
|
def write_pkcs12_container(self, cert, key, issuer) -> None:
|
||||||
|
"""Write a certificate and a key into a PKCS#12 container"""
|
||||||
|
|
||||||
|
# Set an encryption algorithm
|
||||||
|
if cryptography.__version__ >= "38.0.0":
|
||||||
|
# For OpenSSL legacy mode use the default algorithm for certificate
|
||||||
|
# and private key encryption: DES-EDE3-CBC (vel 3DES_CBC)
|
||||||
|
# pylint: disable=no-member
|
||||||
|
encryption = (
|
||||||
|
PrivateFormat.PKCS12.encryption_builder()
|
||||||
|
.key_cert_algorithm(PBES.PBESv1SHA1And3KeyTripleDESCBC)
|
||||||
|
.kdf_rounds(5000)
|
||||||
|
.build(PASSWORD.encode())
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
encryption = BestAvailableEncryption(PASSWORD.encode())
|
||||||
|
|
||||||
|
# Generate PKCS#12 struct
|
||||||
|
pkcs12 = serialize_key_and_certificates(
|
||||||
|
name=b'certificate',
|
||||||
|
key=key,
|
||||||
|
cert=cert,
|
||||||
|
cas=(issuer,),
|
||||||
|
encryption_algorithm=encryption
|
||||||
|
)
|
||||||
|
|
||||||
|
# Write into a PKCS#12 container
|
||||||
|
file_path = os.path.join(CERTS_PATH, "cert.p12")
|
||||||
|
with open(file_path, mode="wb") as file:
|
||||||
|
file.write(pkcs12)
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=pointless-string-statement
|
||||||
|
"""Local Variables:
|
||||||
|
c-basic-offset: 4
|
||||||
|
tab-width: 4
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
End:
|
||||||
|
vim: set ts=4 expandtab:
|
||||||
|
"""
|
@ -1,3 +1,4 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
"""Implementation of a HTTP server"""
|
"""Implementation of a HTTP server"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
@ -6,7 +7,9 @@ import subprocess
|
|||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
from http.server import SimpleHTTPRequestHandler, HTTPServer
|
||||||
|
from socketserver import ThreadingMixIn
|
||||||
|
from make_certificates import CertificateMaker
|
||||||
|
|
||||||
RESULT_PATH = os.getcwd()
|
RESULT_PATH = os.getcwd()
|
||||||
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
|
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
|
||||||
@ -15,11 +18,9 @@ CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
|
|||||||
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
||||||
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
||||||
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||||
CACRL = os.path.join(CERTS_PATH, "./CACertCRL.der")
|
|
||||||
TSACRL = os.path.join(CERTS_PATH, "./TSACertCRL.der")
|
|
||||||
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
||||||
PORT_LOG = os.path.join(LOGS_PATH, "./port.log")
|
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
||||||
|
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
|
||||||
|
|
||||||
OPENSSL_TS = ["openssl", "ts",
|
OPENSSL_TS = ["openssl", "ts",
|
||||||
"-reply", "-config", OPENSSL_CONF,
|
"-reply", "-config", OPENSSL_CONF,
|
||||||
@ -28,6 +29,11 @@ OPENSSL_TS = ["openssl", "ts",
|
|||||||
"-out", RESPONS]
|
"-out", RESPONS]
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||||||
|
"""This variant of HTTPServer creates a new thread for every connection"""
|
||||||
|
daemon_threads = True
|
||||||
|
|
||||||
|
|
||||||
class RequestHandler(SimpleHTTPRequestHandler):
|
class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
"""Handle the HTTP POST request that arrive at the server"""
|
"""Handle the HTTP POST request that arrive at the server"""
|
||||||
|
|
||||||
@ -41,18 +47,22 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||||||
try:
|
try:
|
||||||
url = urlparse(self.path)
|
url = urlparse(self.path)
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header("Content-type", "application/crl")
|
self.send_header("Content-type", "application/pkix-crl")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
resp_data = b''
|
||||||
# Read the file and send the contents
|
# Read the file and send the contents
|
||||||
if url.path == "/intermediateCA":
|
if url.path == "/intermediateCA":
|
||||||
with open(CACRL, 'rb') as file:
|
file_path = os.path.join(CERTS_PATH, "./CACertCRL.der")
|
||||||
|
with open(file_path, 'rb') as file:
|
||||||
resp_data = file.read()
|
resp_data = file.read()
|
||||||
if url.path == "/TSACA":
|
if url.path == "/TSACA":
|
||||||
with open(TSACRL, 'rb') as file:
|
file_path = os.path.join(CERTS_PATH, "./TSACertCRL.der")
|
||||||
|
with open(file_path, 'rb') as file:
|
||||||
resp_data = file.read()
|
resp_data = file.read()
|
||||||
self.wfile.write(resp_data)
|
self.wfile.write(resp_data)
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
print(f"HTTP GET request error: {err}")
|
print("HTTP GET request error: {}".format(err))
|
||||||
|
|
||||||
|
|
||||||
def do_POST(self): # pylint: disable=invalid-name
|
def do_POST(self): # pylint: disable=invalid-name
|
||||||
""""Serves the POST request type"""
|
""""Serves the POST request type"""
|
||||||
@ -60,8 +70,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||||||
url = urlparse(self.path)
|
url = urlparse(self.path)
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
if url.path == "/kill_server":
|
if url.path == "/kill_server":
|
||||||
self.log_message(f"Deleting file: {PORT_LOG}")
|
self.log_message(f"Deleting file: {URL_LOG}")
|
||||||
os.remove(f"{PORT_LOG}")
|
os.remove(f"{URL_LOG}")
|
||||||
self.send_header('Content-type', 'text/plain')
|
self.send_header('Content-type', 'text/plain')
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
|
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
|
||||||
@ -71,17 +81,17 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||||||
post_data = self.rfile.read(content_length)
|
post_data = self.rfile.read(content_length)
|
||||||
with open(REQUEST, mode="wb") as file:
|
with open(REQUEST, mode="wb") as file:
|
||||||
file.write(post_data)
|
file.write(post_data)
|
||||||
openssl = subprocess.run(OPENSSL_TS,
|
openssl = subprocess.run(OPENSSL_TS, check=True, universal_newlines=True)
|
||||||
check=True, universal_newlines=True)
|
|
||||||
openssl.check_returncode()
|
openssl.check_returncode()
|
||||||
self.send_header("Content-type", "application/timestamp-reply")
|
self.send_header("Content-type", "application/timestamp-reply")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
resp_data = None
|
resp_data = b''
|
||||||
with open(RESPONS, mode="rb") as file:
|
with open(RESPONS, mode="rb") as file:
|
||||||
resp_data = file.read()
|
resp_data = file.read()
|
||||||
self.wfile.write(resp_data)
|
self.wfile.write(resp_data)
|
||||||
|
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
print(f"HTTP POST request error: {err}")
|
print("HTTP POST request error: {}".format(err))
|
||||||
|
|
||||||
|
|
||||||
class HttpServerThread():
|
class HttpServerThread():
|
||||||
@ -93,17 +103,18 @@ class HttpServerThread():
|
|||||||
self.server_thread = None
|
self.server_thread = None
|
||||||
|
|
||||||
def start_server(self, port) -> (int):
|
def start_server(self, port) -> (int):
|
||||||
"""Starting HTTP server on localhost and a random available port for binding"""
|
"""Starting HTTP server on 127.0.0.1 and a random available port for binding"""
|
||||||
self.server = ThreadingHTTPServer(('localhost', port), RequestHandler)
|
self.server = ThreadingHTTPServer(('127.0.0.1', port), RequestHandler)
|
||||||
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
||||||
self.server_thread.start()
|
self.server_thread.start()
|
||||||
hostname, port = self.server.server_address[:2]
|
hostname, port = self.server.server_address[:2]
|
||||||
print(f"HTTP server started, URL http://{hostname}:{port}")
|
print("HTTP server started, URL http://{}:{}".format(hostname, port))
|
||||||
return port
|
return port
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""Start HTTP server"""
|
"""Start HTTP server, make test certificates."""
|
||||||
|
|
||||||
ret = 0
|
ret = 0
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
@ -116,11 +127,16 @@ def main() -> None:
|
|||||||
try:
|
try:
|
||||||
server = HttpServerThread()
|
server = HttpServerThread()
|
||||||
port = server.start_server(args.port)
|
port = server.start_server(args.port)
|
||||||
with open(PORT_LOG, mode="w") as file:
|
with open(URL_LOG, mode="w", encoding="utf-8") as file:
|
||||||
file.write("{}".format(port))
|
file.write("127.0.0.1:{}".format(port))
|
||||||
|
tests = CertificateMaker(port, SERVER_LOG)
|
||||||
|
tests.make_certs()
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
print(f"OSError: {err}")
|
print("OSError: {}".format(err))
|
||||||
ret = err.errno
|
ret = err.errno
|
||||||
|
except Exception as err: # pylint: disable=broad-except
|
||||||
|
print("Error: {}".format(err))
|
||||||
|
ret = 1
|
||||||
finally:
|
finally:
|
||||||
sys.exit(ret)
|
sys.exit(ret)
|
||||||
|
|
||||||
@ -130,8 +146,11 @@ if __name__ == '__main__':
|
|||||||
fpid = os.fork()
|
fpid = os.fork()
|
||||||
if fpid > 0:
|
if fpid > 0:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
with open(SERVER_LOG, mode='w', encoding='utf-8') as log:
|
||||||
|
os.dup2(log.fileno(), sys.stdout.fileno())
|
||||||
|
os.dup2(log.fileno(), sys.stderr.fileno())
|
||||||
except OSError as ferr:
|
except OSError as ferr:
|
||||||
print(f"Fork #1 failed: {ferr.errno} {ferr.strerror}")
|
print("Fork #1 failed: {} {}".format(ferr.errno, ferr.strerror))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -139,7 +158,7 @@ if __name__ == '__main__':
|
|||||||
if fpid > 0:
|
if fpid > 0:
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
except OSError as ferr:
|
except OSError as ferr:
|
||||||
print(f"Fork #2 failed: {ferr.errno} {ferr.strerror}")
|
print("Fork #2 failed: {} {}".format(ferr.errno, ferr.strerror))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
# Start the daemon main loop
|
# Start the daemon main loop
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
"""Windows: Implementation of a HTTP server"""
|
"""Windows: Implementation of a HTTP server"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
import threading
|
import threading
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||||
|
from make_certificates import CertificateMaker
|
||||||
|
|
||||||
RESULT_PATH = os.getcwd()
|
RESULT_PATH = os.getcwd()
|
||||||
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
|
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
|
||||||
@ -14,11 +17,9 @@ CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
|
|||||||
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
||||||
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
||||||
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||||
CACRL = os.path.join(CERTS_PATH, "./CACertCRL.der")
|
|
||||||
TSACRL = os.path.join(CERTS_PATH, "./TSACertCRL.der")
|
|
||||||
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
||||||
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
||||||
PORT_LOG = os.path.join(LOGS_PATH, "./port.log")
|
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
|
||||||
|
|
||||||
|
|
||||||
OPENSSL_TS = ["openssl", "ts",
|
OPENSSL_TS = ["openssl", "ts",
|
||||||
@ -41,18 +42,22 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||||||
try:
|
try:
|
||||||
url = urlparse(self.path)
|
url = urlparse(self.path)
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
self.send_header("Content-type", "application/crl")
|
self.send_header("Content-type", "application/pkix-crl")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
|
resp_data = b''
|
||||||
# Read the file and send the contents
|
# Read the file and send the contents
|
||||||
if url.path == "/intermediateCA":
|
if url.path == "/intermediateCA":
|
||||||
with open(CACRL, 'rb') as file:
|
file_path = os.path.join(CERTS_PATH, "./CACertCRL.der")
|
||||||
|
with open(file_path, 'rb') as file:
|
||||||
resp_data = file.read()
|
resp_data = file.read()
|
||||||
if url.path == "/TSACA":
|
if url.path == "/TSACA":
|
||||||
with open(TSACRL, 'rb') as file:
|
file_path = os.path.join(CERTS_PATH, "./TSACertCRL.der")
|
||||||
|
with open(file_path, 'rb') as file:
|
||||||
resp_data = file.read()
|
resp_data = file.read()
|
||||||
self.wfile.write(resp_data)
|
self.wfile.write(resp_data)
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
print(f"HTTP GET request error: {err}")
|
print("HTTP GET request error: {}".format(err))
|
||||||
|
|
||||||
|
|
||||||
def do_POST(self): # pylint: disable=invalid-name
|
def do_POST(self): # pylint: disable=invalid-name
|
||||||
""""Serves the POST request type"""
|
""""Serves the POST request type"""
|
||||||
@ -60,8 +65,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||||||
url = urlparse(self.path)
|
url = urlparse(self.path)
|
||||||
self.send_response(200)
|
self.send_response(200)
|
||||||
if url.path == "/kill_server":
|
if url.path == "/kill_server":
|
||||||
self.log_message(f"Deleting file: {PORT_LOG}")
|
self.log_message(f"Deleting file: {URL_LOG}")
|
||||||
os.remove(f"{PORT_LOG}")
|
os.remove(f"{URL_LOG}")
|
||||||
self.send_header('Content-type', 'text/plain')
|
self.send_header('Content-type', 'text/plain')
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
|
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
|
||||||
@ -76,12 +81,12 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||||||
openssl.check_returncode()
|
openssl.check_returncode()
|
||||||
self.send_header("Content-type", "application/timestamp-reply")
|
self.send_header("Content-type", "application/timestamp-reply")
|
||||||
self.end_headers()
|
self.end_headers()
|
||||||
resp_data = None
|
resp_data = b''
|
||||||
with open(RESPONS, mode="rb") as file:
|
with open(RESPONS, mode="rb") as file:
|
||||||
resp_data = file.read()
|
resp_data = file.read()
|
||||||
self.wfile.write(resp_data)
|
self.wfile.write(resp_data)
|
||||||
except Exception as err: # pylint: disable=broad-except
|
except Exception as err: # pylint: disable=broad-except
|
||||||
print(f"HTTP POST request error: {err}")
|
print("HTTP POST request error: {}".format(err))
|
||||||
|
|
||||||
|
|
||||||
class HttpServerThread():
|
class HttpServerThread():
|
||||||
@ -92,28 +97,39 @@ class HttpServerThread():
|
|||||||
self.server = None
|
self.server = None
|
||||||
self.server_thread = None
|
self.server_thread = None
|
||||||
|
|
||||||
def start_server(self) -> (int):
|
def start_server(self, port) -> (int):
|
||||||
"""Starting HTTP server on localhost and a random available port for binding"""
|
"""Starting HTTP server on 127.0.0.1 and a random available port for binding"""
|
||||||
self.server = ThreadingHTTPServer(('localhost', 19254), RequestHandler)
|
self.server = ThreadingHTTPServer(('127.0.0.1', port), RequestHandler)
|
||||||
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
||||||
self.server_thread.start()
|
self.server_thread.start()
|
||||||
hostname, port = self.server.server_address[:2]
|
hostname, port = self.server.server_address[:2]
|
||||||
print(f"HTTP server started, URL http://{hostname}:{port}")
|
print("HTTP server started, URL http://{}:{}".format(hostname, port))
|
||||||
return port
|
return port
|
||||||
|
|
||||||
|
|
||||||
def main() -> None:
|
def main() -> None:
|
||||||
"""Start HTTP server"""
|
"""Start HTTP server"""
|
||||||
|
|
||||||
ret = 0
|
ret = 0
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"--port",
|
||||||
|
type=int,
|
||||||
|
default=0,
|
||||||
|
help="port number"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
try:
|
try:
|
||||||
sys.stdout = open(SERVER_LOG, "w")
|
sys.stdout = open(SERVER_LOG, "w")
|
||||||
sys.stderr = open(SERVER_LOG, "a")
|
sys.stderr = open(SERVER_LOG, "a")
|
||||||
server = HttpServerThread()
|
server = HttpServerThread()
|
||||||
port = server.start_server()
|
port = server.start_server(args.port)
|
||||||
with open(PORT_LOG, mode="w") as file:
|
with open(URL_LOG, mode="w") as file:
|
||||||
file.write("{}".format(port))
|
file.write("127.0.0.1:{}".format(port))
|
||||||
|
tests = CertificateMaker(port, SERVER_LOG)
|
||||||
|
tests.make_certs()
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
print(f"OSError: {err}")
|
print("OSError: {}".format(err))
|
||||||
ret = err.errno
|
ret = err.errno
|
||||||
finally:
|
finally:
|
||||||
sys.exit(ret)
|
sys.exit(ret)
|
||||||
|
57
tests/sources/CatalogDefinitionFileName.cdf
Normal file
57
tests/sources/CatalogDefinitionFileName.cdf
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# https://learn.microsoft.com/en-us/windows/win32/seccrypto/makecat
|
||||||
|
# makecat -v CatalogDefinitionFileName.cdf
|
||||||
|
|
||||||
|
# Define information about the entire catalog file.
|
||||||
|
[CatalogHeader]
|
||||||
|
|
||||||
|
# Name of the catalog file, including its extension.
|
||||||
|
Name=unsigned.cat
|
||||||
|
|
||||||
|
# Directory where the created unsigned.cat file will be placed.
|
||||||
|
ResultDir=..\files
|
||||||
|
|
||||||
|
# This option is not supported. Default value 1 is used.
|
||||||
|
PublicVersion=0x0000001
|
||||||
|
|
||||||
|
# Catalog version.
|
||||||
|
# If the version is set to 2, the HashAlgorithms option must contain SHA256.
|
||||||
|
CatalogVersion=2
|
||||||
|
|
||||||
|
# Name of the hashing algorithm used.
|
||||||
|
HashAlgorithms=SHA256
|
||||||
|
|
||||||
|
# Specifies whether to hash the files listed in the <HASH> option in the [CatalogFiles] section
|
||||||
|
PageHashes=true
|
||||||
|
|
||||||
|
# Type of message encoding used.
|
||||||
|
# The default EncodingType is PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, 0x00010001
|
||||||
|
EncodingType=0x00010001
|
||||||
|
|
||||||
|
# Specify an attribute of the catalog file.
|
||||||
|
# Set 1.3.6.1.4.1.311.12.2.1 CAT_NAMEVALUE_OBJID
|
||||||
|
# CATATTR1={type}:{oid}:{value} (optional)
|
||||||
|
# The OSAttr attribute specifies the target Windows version
|
||||||
|
CATATTR1=0x11010001:OSAttr:2:6.0
|
||||||
|
|
||||||
|
# Define each member of the catalog file.
|
||||||
|
[CatalogFiles]
|
||||||
|
|
||||||
|
<HASH>PEfile=..\files\unsigned.exe
|
||||||
|
# 0x00010000 Attribute is represented in plaintext. No conversion will be done.
|
||||||
|
<HASH>PEfileATTR1=0x11010001:File:unsigned.exe
|
||||||
|
|
||||||
|
<HASH>MSIfile=..\files\unsigned.msi
|
||||||
|
# 0x00020000 Attribute is represented in base-64 encoding.
|
||||||
|
<HASH>MSIfileATTR1=0x11020001:File:dW5zaWduZWQubXNp
|
||||||
|
|
||||||
|
<HASH>CABfile=..\files\unsigned.ex_
|
||||||
|
<HASH>CABfileATTR1=0x11010001:File:unsigned.ex_
|
||||||
|
|
||||||
|
<HASH>PS1file=..\files\unsigned.ps1
|
||||||
|
<HASH>PS1fileATTR1=0x11010001:File:unsigned.ps1
|
||||||
|
|
||||||
|
<HASH>PSC1file=..\files\unsigned.psc1
|
||||||
|
<HASH>PSC1fileATTR1=0x11010001:File:unsigned.psc1
|
||||||
|
|
||||||
|
<HASH>MOFfile=..\files\unsigned.mof
|
||||||
|
<HASH>MOFfileATTR1=0x11010001:File:unsigned.mof
|
Binary file not shown.
108
tests/start_server.py
Normal file
108
tests/start_server.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
"""Wait for all tests certificate, compute leafhash"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import binascii
|
||||||
|
import hashlib
|
||||||
|
import os
|
||||||
|
import pathlib
|
||||||
|
import platform
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
|
||||||
|
RESULT_PATH = os.getcwd()
|
||||||
|
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||||
|
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
||||||
|
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
||||||
|
if platform.system() == 'Windows':
|
||||||
|
DEFAULT_PYTHON = "C:/Program Files/Python/Python311/pythonw.exe"
|
||||||
|
DEFAULT_PROG = os.path.join(RESULT_PATH, "./Testing/server_http.pyw")
|
||||||
|
else:
|
||||||
|
DEFAULT_PYTHON = "/usr/bin/python3"
|
||||||
|
DEFAULT_PROG = os.path.join(RESULT_PATH, "./Testing/server_http.py")
|
||||||
|
|
||||||
|
|
||||||
|
def compute_sha256(file_name) -> str:
|
||||||
|
"""Compute a SHA256 hash of the leaf certificate (in DER form)"""
|
||||||
|
|
||||||
|
sha256_hash = hashlib.sha256()
|
||||||
|
file_path = os.path.join(CERTS_PATH, file_name)
|
||||||
|
with open(file_path, mode="rb") as file:
|
||||||
|
for bajt in iter(lambda: file.read(4096),b""):
|
||||||
|
sha256_hash.update(bajt)
|
||||||
|
return sha256_hash.hexdigest()
|
||||||
|
|
||||||
|
def clear_catalog(certs_path) -> None:
|
||||||
|
""""Clear a test certificates catalog."""
|
||||||
|
|
||||||
|
if os.path.exists(certs_path):
|
||||||
|
#Remove old test certificates
|
||||||
|
for root, _, files in os.walk(certs_path):
|
||||||
|
for file in files:
|
||||||
|
os.remove(os.path.join(root, file))
|
||||||
|
else:
|
||||||
|
os.mkdir(certs_path)
|
||||||
|
|
||||||
|
# Generate 16 random bytes and convert to hex
|
||||||
|
random_hex = binascii.b2a_hex(os.urandom(16)).decode()
|
||||||
|
serial = os.path.join(certs_path, "./tsa-serial")
|
||||||
|
with open(serial, mode="w", encoding="utf-8") as file:
|
||||||
|
file.write(random_hex)
|
||||||
|
|
||||||
|
def main() -> None:
|
||||||
|
"""Wait for all tests certificate, compute leafhash"""
|
||||||
|
|
||||||
|
parser = argparse.ArgumentParser()
|
||||||
|
parser.add_argument(
|
||||||
|
"--exe",
|
||||||
|
type=pathlib.Path,
|
||||||
|
default=DEFAULT_PYTHON,
|
||||||
|
help=f"the path to the python3 executable to use"
|
||||||
|
f"(default: {DEFAULT_PYTHON})",
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--script",
|
||||||
|
type=pathlib.Path,
|
||||||
|
default=DEFAULT_PROG,
|
||||||
|
help=f"the path to the python script to run"
|
||||||
|
f"(default: {DEFAULT_PROG})",
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
try:
|
||||||
|
clear_catalog(CERTS_PATH)
|
||||||
|
#pylint: disable=consider-using-with
|
||||||
|
subprocess.Popen([str(args.exe), str(args.script)])
|
||||||
|
|
||||||
|
cert_log = os.path.join(CERTS_PATH, "./cert.log")
|
||||||
|
while not (os.path.exists(cert_log) and os.path.getsize(cert_log) > 0):
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
leafhash = compute_sha256("cert.der")
|
||||||
|
file_path = os.path.join(CERTS_PATH, "./leafhash.txt")
|
||||||
|
with open(file_path, mode="w", encoding="utf-8") as file:
|
||||||
|
file.write("SHA256:{}".format(leafhash))
|
||||||
|
|
||||||
|
except OSError as err:
|
||||||
|
with open(SERVER_LOG, mode="w", encoding="utf-8") as file:
|
||||||
|
file.write("OSError: {}".format(err))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
except Exception as err: # pylint: disable=broad-except
|
||||||
|
with open(SERVER_LOG, mode="w", encoding="utf-8") as file:
|
||||||
|
file.write("Error: {}".format(err))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=pointless-string-statement
|
||||||
|
"""Local Variables:
|
||||||
|
c-basic-offset: 4
|
||||||
|
tab-width: 4
|
||||||
|
indent-tabs-mode: nil
|
||||||
|
End:
|
||||||
|
vim: set ts=4 expandtab:
|
||||||
|
"""
|
347
utf.c
Normal file
347
utf.c
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
// utf by pietro gagliardi (andlabs) — https://github.com/andlabs/utf/
|
||||||
|
// 10 november 2016
|
||||||
|
#include "utf.h"
|
||||||
|
|
||||||
|
// this code imitates Go's unicode/utf8 and unicode/utf16
|
||||||
|
// the biggest difference is that a rune is unsigned instead of signed (because Go guarantees what a right shift on a signed number will do, whereas C does not)
|
||||||
|
// it is also an imitation so we can license it under looser terms than the Go source
|
||||||
|
#define badrune 0xFFFD
|
||||||
|
|
||||||
|
// encoded must be at most 4 bytes
|
||||||
|
// TODO clean this code up somehow
|
||||||
|
size_t utf8EncodeRune(uint32_t rune, char *encoded)
|
||||||
|
{
|
||||||
|
uint8_t b, c, d, e;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
// not in the valid range for Unicode
|
||||||
|
if (rune > 0x10FFFF)
|
||||||
|
rune = badrune;
|
||||||
|
// surrogate runes cannot be encoded
|
||||||
|
if (rune >= 0xD800 && rune < 0xE000)
|
||||||
|
rune = badrune;
|
||||||
|
|
||||||
|
if (rune < 0x80) { // ASCII bytes represent themselves
|
||||||
|
b = (uint8_t) (rune & 0xFF);
|
||||||
|
n = 1;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (rune < 0x800) { // two-byte encoding
|
||||||
|
c = (uint8_t) (rune & 0x3F);
|
||||||
|
c |= 0x80;
|
||||||
|
rune >>= 6;
|
||||||
|
b = (uint8_t) (rune & 0x1F);
|
||||||
|
b |= 0xC0;
|
||||||
|
n = 2;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (rune < 0x10000) { // three-byte encoding
|
||||||
|
d = (uint8_t) (rune & 0x3F);
|
||||||
|
d |= 0x80;
|
||||||
|
rune >>= 6;
|
||||||
|
c = (uint8_t) (rune & 0x3F);
|
||||||
|
c |= 0x80;
|
||||||
|
rune >>= 6;
|
||||||
|
b = (uint8_t) (rune & 0x0F);
|
||||||
|
b |= 0xE0;
|
||||||
|
n = 3;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
// otherwise use a four-byte encoding
|
||||||
|
e = (uint8_t) (rune & 0x3F);
|
||||||
|
e |= 0x80;
|
||||||
|
rune >>= 6;
|
||||||
|
d = (uint8_t) (rune & 0x3F);
|
||||||
|
d |= 0x80;
|
||||||
|
rune >>= 6;
|
||||||
|
c = (uint8_t) (rune & 0x3F);
|
||||||
|
c |= 0x80;
|
||||||
|
rune >>= 6;
|
||||||
|
b = (uint8_t) (rune & 0x07);
|
||||||
|
b |= 0xF0;
|
||||||
|
n = 4;
|
||||||
|
|
||||||
|
done:
|
||||||
|
encoded[0] = (char)b;
|
||||||
|
if (n > 1)
|
||||||
|
encoded[1] = (char)c;
|
||||||
|
if (n > 2)
|
||||||
|
encoded[2] = (char)d;
|
||||||
|
if (n > 3)
|
||||||
|
encoded[3] = (char)e;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *utf8DecodeRune(const char *s, size_t nElem, uint32_t *rune)
|
||||||
|
{
|
||||||
|
uint8_t b, c;
|
||||||
|
uint8_t lowestAllowed, highestAllowed;
|
||||||
|
size_t i, expected;
|
||||||
|
int bad;
|
||||||
|
|
||||||
|
b = (uint8_t) (*s);
|
||||||
|
if (b < 0x80) { // ASCII bytes represent themselves
|
||||||
|
*rune = b;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
// 0xC0 and 0xC1 cover 2-byte overlong equivalents
|
||||||
|
// 0xF5 to 0xFD cover values > 0x10FFFF
|
||||||
|
// 0xFE and 0xFF were never defined (always illegal)
|
||||||
|
if (b < 0xC2 || b > 0xF4) { // invalid
|
||||||
|
*rune = badrune;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this determines the range of allowed first continuation bytes
|
||||||
|
lowestAllowed = 0x80;
|
||||||
|
highestAllowed = 0xBF;
|
||||||
|
switch (b) {
|
||||||
|
case 0xE0:
|
||||||
|
// disallow 3-byte overlong equivalents
|
||||||
|
lowestAllowed = 0xA0;
|
||||||
|
break;
|
||||||
|
case 0xED:
|
||||||
|
// disallow surrogate characters
|
||||||
|
highestAllowed = 0x9F;
|
||||||
|
break;
|
||||||
|
case 0xF0:
|
||||||
|
// disallow 4-byte overlong equivalents
|
||||||
|
lowestAllowed = 0x90;
|
||||||
|
break;
|
||||||
|
case 0xF4:
|
||||||
|
// disallow values > 0x10FFFF
|
||||||
|
highestAllowed = 0x8F;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// and this determines how many continuation bytes are expected
|
||||||
|
expected = 1;
|
||||||
|
if (b >= 0xE0)
|
||||||
|
expected++;
|
||||||
|
if (b >= 0xF0)
|
||||||
|
expected++;
|
||||||
|
if (nElem != 0) { // are there enough bytes?
|
||||||
|
nElem--;
|
||||||
|
if (nElem < expected) { // nope
|
||||||
|
*rune = badrune;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ensure that everything is correct
|
||||||
|
// if not, **only** consume the initial byte
|
||||||
|
bad = 0;
|
||||||
|
for (i = 0; i < expected; i++) {
|
||||||
|
c = (uint8_t) (s[1 + i]);
|
||||||
|
if (c < lowestAllowed || c > highestAllowed) {
|
||||||
|
bad = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// the old lowestAllowed and highestAllowed is only for the first continuation byte
|
||||||
|
lowestAllowed = 0x80;
|
||||||
|
highestAllowed = 0xBF;
|
||||||
|
}
|
||||||
|
if (bad) {
|
||||||
|
*rune = badrune;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now do the topmost bits
|
||||||
|
if (b < 0xE0)
|
||||||
|
*rune = b & 0x1F;
|
||||||
|
else if (b < 0xF0)
|
||||||
|
*rune = b & 0x0F;
|
||||||
|
else
|
||||||
|
*rune = b & 0x07;
|
||||||
|
s++; // we can finally move on
|
||||||
|
|
||||||
|
// now do the continuation bytes
|
||||||
|
for (; expected; expected--) {
|
||||||
|
c = (uint8_t) (*s);
|
||||||
|
s++;
|
||||||
|
c &= 0x3F; // strip continuation bits
|
||||||
|
*rune <<= 6;
|
||||||
|
*rune |= c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// encoded must have at most 2 elements
|
||||||
|
size_t utf16EncodeRune(uint32_t rune, uint16_t *encoded)
|
||||||
|
{
|
||||||
|
uint16_t low, high;
|
||||||
|
|
||||||
|
// not in the valid range for Unicode
|
||||||
|
if (rune > 0x10FFFF)
|
||||||
|
rune = badrune;
|
||||||
|
// surrogate runes cannot be encoded
|
||||||
|
if (rune >= 0xD800 && rune < 0xE000)
|
||||||
|
rune = badrune;
|
||||||
|
|
||||||
|
if (rune < 0x10000) {
|
||||||
|
encoded[0] = (uint16_t) rune;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
rune -= 0x10000;
|
||||||
|
low = (uint16_t) (rune & 0x3FF);
|
||||||
|
rune >>= 10;
|
||||||
|
high = (uint16_t) (rune & 0x3FF);
|
||||||
|
encoded[0] = high | 0xD800;
|
||||||
|
encoded[1] = low | 0xDC00;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO see if this can be cleaned up somehow
|
||||||
|
const uint16_t *utf16DecodeRune(const uint16_t *s, size_t nElem, uint32_t *rune)
|
||||||
|
{
|
||||||
|
uint16_t high, low;
|
||||||
|
|
||||||
|
if (*s < 0xD800 || *s >= 0xE000) {
|
||||||
|
// self-representing character
|
||||||
|
*rune = *s;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
if (*s >= 0xDC00) {
|
||||||
|
// out-of-order surrogates
|
||||||
|
*rune = badrune;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
if (nElem == 1) { // not enough elements
|
||||||
|
*rune = badrune;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
high = *s;
|
||||||
|
high &= 0x3FF;
|
||||||
|
if (s[1] < 0xDC00 || s[1] >= 0xE000) {
|
||||||
|
// bad surrogate pair
|
||||||
|
*rune = badrune;
|
||||||
|
s++;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
low = *s;
|
||||||
|
s++;
|
||||||
|
low &= 0x3FF;
|
||||||
|
*rune = high;
|
||||||
|
*rune <<= 10;
|
||||||
|
*rune |= low;
|
||||||
|
*rune += 0x10000;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO find a way to reduce the code in all of these somehow
|
||||||
|
// TODO find a way to remove u as well
|
||||||
|
size_t utf8RuneCount(const char *s, size_t nElem)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
uint32_t rune;
|
||||||
|
|
||||||
|
if (nElem != 0) {
|
||||||
|
const char *t, *u;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
t = s;
|
||||||
|
while (nElem != 0) {
|
||||||
|
u = utf8DecodeRune(t, nElem, &rune);
|
||||||
|
len++;
|
||||||
|
nElem -= (size_t)(u - t);
|
||||||
|
t = u;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
while (*s) {
|
||||||
|
s = utf8DecodeRune(s, nElem, &rune);
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t utf8UTF16Count(const char *s, size_t nElem)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
uint32_t rune;
|
||||||
|
uint16_t encoded[2];
|
||||||
|
|
||||||
|
if (nElem != 0) {
|
||||||
|
const char *t, *u;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
t = s;
|
||||||
|
while (nElem != 0) {
|
||||||
|
u = utf8DecodeRune(t, nElem, &rune);
|
||||||
|
len += utf16EncodeRune(rune, encoded);
|
||||||
|
nElem -= (size_t)(u - t);
|
||||||
|
t = u;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
while (*s) {
|
||||||
|
s = utf8DecodeRune(s, nElem, &rune);
|
||||||
|
len += utf16EncodeRune(rune, encoded);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t utf16RuneCount(const uint16_t *s, size_t nElem)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
uint32_t rune;
|
||||||
|
|
||||||
|
if (nElem != 0) {
|
||||||
|
const uint16_t *t, *u;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
t = s;
|
||||||
|
while (nElem != 0) {
|
||||||
|
u = utf16DecodeRune(t, nElem, &rune);
|
||||||
|
len++;
|
||||||
|
nElem -= (size_t)(u - t);
|
||||||
|
t = u;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
while (*s) {
|
||||||
|
s = utf16DecodeRune(s, nElem, &rune);
|
||||||
|
len++;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t utf16UTF8Count(const uint16_t *s, size_t nElem)
|
||||||
|
{
|
||||||
|
size_t len;
|
||||||
|
uint32_t rune;
|
||||||
|
char encoded[4];
|
||||||
|
|
||||||
|
if (nElem != 0) {
|
||||||
|
const uint16_t *t, *u;
|
||||||
|
|
||||||
|
len = 0;
|
||||||
|
t = s;
|
||||||
|
while (nElem != 0) {
|
||||||
|
u = utf16DecodeRune(t, nElem, &rune);
|
||||||
|
len += utf8EncodeRune(rune, encoded);
|
||||||
|
nElem -= (size_t)(u - t);
|
||||||
|
t = u;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
len = 0;
|
||||||
|
while (*s) {
|
||||||
|
s = utf16DecodeRune(s, nElem, &rune);
|
||||||
|
len += utf8EncodeRune(rune, encoded);
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
61
utf.h
Normal file
61
utf.h
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// utf by pietro gagliardi (andlabs) — https://github.com/andlabs/utf/
|
||||||
|
// 10 november 2016
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
// if nElem == 0, assume the buffer has no upper limit and is '\0' terminated
|
||||||
|
// otherwise, assume buffer is NOT '\0' terminated but is bounded by nElem *elements*
|
||||||
|
|
||||||
|
extern size_t utf8EncodeRune(uint32_t rune, char *encoded);
|
||||||
|
extern const char *utf8DecodeRune(const char *s, size_t nElem, uint32_t *rune);
|
||||||
|
extern size_t utf16EncodeRune(uint32_t rune, uint16_t *encoded);
|
||||||
|
extern const uint16_t *utf16DecodeRune(const uint16_t *s, size_t nElem, uint32_t *rune);
|
||||||
|
|
||||||
|
extern size_t utf8RuneCount(const char *s, size_t nElem);
|
||||||
|
extern size_t utf8UTF16Count(const char *s, size_t nElem);
|
||||||
|
extern size_t utf16RuneCount(const uint16_t *s, size_t nElem);
|
||||||
|
extern size_t utf16UTF8Count(const uint16_t *s, size_t nElem);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provide overloads on Windows for using these functions with wchar_t and WCHAR when wchar_t is a keyword in C++ mode (the default).
|
||||||
|
// Otherwise, you'd need to cast to pass a wchar_t pointer, WCHAR pointer, or equivalent to these functions.
|
||||||
|
// We use __wchar_t to be independent of the setting; see https://blogs.msdn.microsoft.com/oldnewthing/20161201-00/?p=94836 (ironically posted one day after I initially wrote this code!).
|
||||||
|
// TODO check this on MinGW-w64
|
||||||
|
// TODO check this under /Wall
|
||||||
|
// TODO C-style casts enough? or will that fail in /Wall?
|
||||||
|
// TODO same for UniChar/unichar on Mac? if both are unsigned then we have nothing to worry about
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
|
||||||
|
inline size_t utf16EncodeRune(uint32_t rune, __wchar_t *encoded)
|
||||||
|
{
|
||||||
|
return utf16EncodeRune(rune, reinterpret_cast<uint16_t *>(encoded));
|
||||||
|
}
|
||||||
|
|
||||||
|
inline const __wchar_t *utf16DecodeRune(const __wchar_t *s, size_t nElem, uint32_t *rune)
|
||||||
|
{
|
||||||
|
const uint16_t *ret;
|
||||||
|
|
||||||
|
ret = utf16DecodeRune(reinterpret_cast<const uint16_t *>(s), nElem, rune);
|
||||||
|
return reinterpret_cast<const __wchar_t *>(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t utf16RuneCount(const __wchar_t *s, size_t nElem)
|
||||||
|
{
|
||||||
|
return utf16RuneCount(reinterpret_cast<const uint16_t *>(s), nElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline size_t utf16UTF8Count(const __wchar_t *s, size_t nElem)
|
||||||
|
{
|
||||||
|
return utf16UTF8Count(reinterpret_cast<const uint16_t *>(s), nElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -3,10 +3,7 @@
|
|||||||
"version-string": "2.4",
|
"version-string": "2.4",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"openssl",
|
"openssl",
|
||||||
"curl",
|
"zlib"
|
||||||
{
|
],
|
||||||
"name": "python3",
|
"builtin-baseline": "9edb1b8e590cc086563301d735cae4b6e732d2d2"
|
||||||
"platform": "!(windows & static) & !osx"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user