mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-07-02 19:22:47 -05:00
Compare commits
223 Commits
Author | SHA1 | Date | |
---|---|---|---|
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 | |||
9ebd79ad18 | |||
1700455533 | |||
a6f767f5a3 | |||
4c5b329bc4 | |||
5626482e82 | |||
2d21a2121c | |||
5d2bf2c80f | |||
5b8376ce32 | |||
1fc2c937f2 | |||
2ed54490a6 | |||
a096aa8a33 | |||
aa08566a63 | |||
c04b229ce2 | |||
adcfd9a33f | |||
f2f3a8891c | |||
29eedf9059 | |||
d6f94d71f7 | |||
a509a66c65 | |||
7bf4c92d83 | |||
0a0fdfe96a | |||
199f2b4586 | |||
a92c4a5522 | |||
dc44ed5f5b | |||
c6990878c2 | |||
abbbfabdc7 | |||
2a4b75842a | |||
56e7a72e8a | |||
b61bcaac2e | |||
924af9e783 | |||
cb80c7d188 | |||
76bb06bf7e | |||
4b6027a4f7 | |||
de6a65cc67 | |||
c90166ba8d | |||
b00ceee310 | |||
54e61cb76a | |||
fb731f2b5e | |||
eec5a0755d | |||
41d98c3917 | |||
7fa0b21ddd | |||
e0eb331baf | |||
7bb21c3539 | |||
edcb18d63f | |||
3d7b8d2a21 | |||
7bfe3b5db9 | |||
dd365d68c4 | |||
09555e8c05 | |||
e4aa06f0c0 | |||
46e9ee447f | |||
3e7247d9dc | |||
d2f1b9c035 | |||
4199310cdf | |||
0204d04a25 | |||
246f0abbfc | |||
0f51a06b8f | |||
44a6768089 | |||
93f5f800d6 | |||
4db6ed0cad | |||
32b65659be | |||
8e74a05b40 | |||
83e47e0252 | |||
41e6042c26 | |||
33c1fdaa85 | |||
11eb76d4f3 | |||
b0391244a6 | |||
83f6ceeaea | |||
b96a7a2232 | |||
ff8034af2e | |||
bde67ec1e2 | |||
c5ad70d31a | |||
27a2a2bfa3 | |||
827f167f8b | |||
4098a5efc7 | |||
e88bc1ca14 | |||
dd2aaf0804 | |||
08113a08cb | |||
29843ccf40 | |||
5fef4faf47 | |||
5981c740c9 | |||
f3af509973 | |||
c29e14e697 | |||
4da5526c05 | |||
4ec23dbaa5 | |||
d9979c4bc6 | |||
695892b8bf | |||
192ff59916 | |||
506daf84ac | |||
bb6322e378 | |||
b0eaa96d45 | |||
fade782e58 | |||
199a852c12 | |||
95a8a9d9c1 | |||
c197d7727c | |||
efbe570f27 | |||
fef65536f6 | |||
1155a9c338 | |||
f67ca8aac5 | |||
d59601f2b9 | |||
7f87f930f7 | |||
dadca2516d | |||
a862378280 | |||
c4ec6debe5 | |||
08c205a02f | |||
acfece2c26 | |||
61cf89f26f | |||
07a927f34a | |||
257cb1fb08 | |||
c48a6cdef0 | |||
8bba4496c0 | |||
dfc13c9bf8 | |||
f57b469c29 | |||
c718882ffb | |||
3109bdf0ab | |||
7aca21b481 | |||
8c113b3a86 | |||
f3a5ecce9c | |||
1c678bf926 | |||
454e15326d | |||
db556d0a2d | |||
8bdd22c183 | |||
cc4e5a5076 | |||
b8cb44fa47 |
81
.github/workflows/ci.yml
vendored
81
.github/workflows/ci.yml
vendored
@ -7,7 +7,7 @@ on:
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
version: osslsigncode-2.5
|
||||
version: osslsigncode-2.9
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -15,6 +15,12 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- id: ubuntu-24.04
|
||||
triplet: x64-linux
|
||||
compiler: gcc
|
||||
os: ubuntu-24.04
|
||||
generator: Unix Makefiles
|
||||
vcpkg_root:
|
||||
- id: ubuntu-22.04
|
||||
triplet: x64-linux
|
||||
compiler: gcc
|
||||
@ -27,12 +33,6 @@ jobs:
|
||||
os: ubuntu-20.04
|
||||
generator: Unix Makefiles
|
||||
vcpkg_root:
|
||||
- id: ubuntu-18.04
|
||||
triplet: x64-linux
|
||||
compiler: gcc
|
||||
os: ubuntu-18.04
|
||||
generator: Unix Makefiles
|
||||
vcpkg_root:
|
||||
- id: macOS
|
||||
triplet: x64-osx
|
||||
compiler: clang
|
||||
@ -78,11 +78,11 @@ jobs:
|
||||
VCPKG_ROOT: ${{matrix.vcpkg_root}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Cache the vcpkg archives
|
||||
if: matrix.cache != ''
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{matrix.cache}}
|
||||
key: ${{matrix.id}}-${{hashFiles('vcpkg.json')}}
|
||||
@ -96,24 +96,61 @@ jobs:
|
||||
with:
|
||||
arch: ${{matrix.arch}}
|
||||
|
||||
- name: Install MSYS2
|
||||
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: Install apt dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: sudo apt-get install -y libssl-dev libcurl4-openssl-dev faketime
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get remove needrestart || echo Ignored
|
||||
sudo apt-get install -y libssl-dev zlib1g-dev python3-cryptography
|
||||
|
||||
- name: Install brew dependencies (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew install python@3.8
|
||||
|
||||
- name: Install Xcode (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: maxim-lobanov/setup-xcode@v1
|
||||
with:
|
||||
xcode-version: latest-stable
|
||||
|
||||
- name: Setup the oldest supported version of cmake (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
|
||||
run: openssl version -a
|
||||
- name: Install python3 cryptography module (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
python3.8 -m ensurepip
|
||||
python3.8 -m pip install --upgrade pip
|
||||
python3.8 -m pip install cryptography
|
||||
|
||||
- name: Install python3 cryptography module (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
C:/hostedtoolcache/windows/Python/3.12.3/x64/python3.exe -m ensurepip
|
||||
C:/hostedtoolcache/windows/Python/3.12.3/x64/python.exe -m pip install --upgrade pip
|
||||
C:/hostedtoolcache/windows/Python/3.12.3/x64/python.exe -m pip install cryptography
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake
|
||||
-G "${{matrix.generator}}"
|
||||
-S ${{github.workspace}}
|
||||
-B ${{github.workspace}}/build
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/dist
|
||||
-DVCPKG_TARGET_TRIPLET=${{matrix.triplet}}
|
||||
@ -123,6 +160,14 @@ jobs:
|
||||
--build ${{github.workspace}}/build
|
||||
--config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Show python version (macOS)
|
||||
working-directory: ${{github.workspace}}/build
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
python3.8 --version
|
||||
python3.8 -c "import sys; print(sys.executable)"
|
||||
python3.8 -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||
|
||||
- name: List files (Linux/macOS)
|
||||
if: runner.os != 'Windows'
|
||||
run: find .. -ls
|
||||
@ -136,17 +181,21 @@ jobs:
|
||||
run: ctest -C ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Upload the errors
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: errors-${{matrix.id}}
|
||||
path: ${{github.workspace}}/build/Testing/Temporary/LastTest.log
|
||||
path: |
|
||||
${{github.workspace}}/build/Testing/Temporary/LastTest.log
|
||||
${{github.workspace}}/build/Testing/conf/makecerts.log
|
||||
${{github.workspace}}/build/Testing/logs/server.log
|
||||
${{github.workspace}}/build/Testing/logs/port.log
|
||||
|
||||
- name: Install
|
||||
run: cmake --install ${{github.workspace}}/build
|
||||
|
||||
- name: Upload the executables
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ${{env.version}}-${{matrix.id}}
|
||||
path: ${{github.workspace}}/dist
|
||||
|
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@ -25,11 +25,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
@ -43,7 +43,7 @@ jobs:
|
||||
# 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)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ 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
|
||||
@ -56,4 +56,4 @@ jobs:
|
||||
# ./location_of_script_within_repo/buildscript.sh
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
5
.github/workflows/coverity.yml
vendored
5
.github/workflows/coverity.yml
vendored
@ -2,7 +2,7 @@ name: Coverity Scan
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
coverity:
|
||||
@ -10,11 +10,12 @@ jobs:
|
||||
env:
|
||||
token: ${{secrets.COVERITY_SCAN_TOKEN}}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
if: env.token
|
||||
- name: Get ready for scanning
|
||||
if: env.token
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libssl-dev libcurl4-openssl-dev
|
||||
cmake -S ${{github.workspace}} -B ${{github.workspace}}/build
|
||||
- uses: vapier/coverity-scan-action@v1
|
||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -12,7 +12,6 @@ CPackSourceConfig.cmake
|
||||
CTestTestfile.cmake
|
||||
install_manifest.txt
|
||||
Makefile
|
||||
missing
|
||||
osslsigncode
|
||||
osslsigncode.exe
|
||||
stamp-h1
|
||||
|
@ -3,17 +3,17 @@ cmake_minimum_required(VERSION 3.17)
|
||||
|
||||
# autodetect vcpkg CMAKE_TOOLCHAIN_FILE if VCPKG_ROOT is defined
|
||||
# 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)
|
||||
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)
|
||||
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 "")
|
||||
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
|
||||
|
||||
# configure basic project information
|
||||
project(osslsigncode
|
||||
VERSION 2.5
|
||||
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
|
||||
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
|
||||
LANGUAGES C)
|
||||
VERSION 2.9
|
||||
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
|
||||
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
|
||||
LANGUAGES C)
|
||||
|
||||
# force nonstandard version format for development packages
|
||||
set(DEV "")
|
||||
@ -29,7 +29,10 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# load CMake library modules
|
||||
include(FindOpenSSL)
|
||||
include(FindCURL)
|
||||
if(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||
include(FindCURL)
|
||||
endif(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||
include(FindZLIB)
|
||||
|
||||
# load CMake project modules
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${PROJECT_SOURCE_DIR}/cmake")
|
||||
@ -47,9 +50,9 @@ configure_file(Config.h.in config.h)
|
||||
target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1)
|
||||
|
||||
# set sources
|
||||
target_sources(osslsigncode PRIVATE osslsigncode.c msi.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)
|
||||
target_sources(osslsigncode PRIVATE applink.c)
|
||||
target_sources(osslsigncode PRIVATE applink.c)
|
||||
endif(NOT UNIX)
|
||||
|
||||
# set include directories
|
||||
@ -57,20 +60,33 @@ target_include_directories(osslsigncode PRIVATE "${PROJECT_BINARY_DIR}")
|
||||
|
||||
# set OpenSSL includes/libraries
|
||||
if(NOT OPENSSL_FOUND)
|
||||
message(FATAL_ERROR "OpenSSL library not found")
|
||||
message(FATAL_ERROR "OpenSSL library not found")
|
||||
endif(NOT OPENSSL_FOUND)
|
||||
target_include_directories(osslsigncode PRIVATE ${OPENSSL_INCLUDE_DIR})
|
||||
target_link_libraries(osslsigncode PRIVATE ${OPENSSL_LIBRARIES})
|
||||
|
||||
# set cURL includes/libraries
|
||||
if(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||
if(CURL_FOUND)
|
||||
target_compile_definitions(osslsigncode PRIVATE ENABLE_CURL=1)
|
||||
target_include_directories(osslsigncode PRIVATE ${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(osslsigncode PRIVATE ${CURL_LIBRARIES})
|
||||
message(STATUS "cURL support enabled")
|
||||
target_compile_definitions(osslsigncode PRIVATE ENABLE_CURL=1)
|
||||
target_include_directories(osslsigncode PRIVATE ${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(osslsigncode PRIVATE ${CURL_LIBRARIES})
|
||||
message(STATUS "cURL support enabled")
|
||||
else(CURL_FOUND)
|
||||
message(STATUS "cURL support disabled (library not found)")
|
||||
message(STATUS "cURL support disabled (library not found)")
|
||||
endif(CURL_FOUND)
|
||||
endif(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||
|
||||
if(NOT ZLIB_FOUND)
|
||||
message(FATAL_ERROR "Zlib library not found")
|
||||
endif(NOT ZLIB_FOUND)
|
||||
target_include_directories(osslsigncode PRIVATE ${ZLIB_INCLUDE_DIR})
|
||||
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
|
||||
set_target_properties(osslsigncode PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
|
||||
@ -82,14 +98,22 @@ include(CMakeTest)
|
||||
set(BINDIR "${CMAKE_INSTALL_PREFIX}/bin")
|
||||
install(TARGETS osslsigncode RUNTIME DESTINATION ${BINDIR})
|
||||
if(UNIX)
|
||||
include(CMakeDist)
|
||||
include(CMakeDist)
|
||||
else(UNIX)
|
||||
install(
|
||||
DIRECTORY ${PROJECT_BINARY_DIR}/ DESTINATION ${BINDIR}
|
||||
FILES_MATCHING
|
||||
PATTERN "*.dll"
|
||||
PATTERN "vcpkg_installed" EXCLUDE
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "Testing" EXCLUDE
|
||||
)
|
||||
install(
|
||||
DIRECTORY ${PROJECT_BINARY_DIR}/ DESTINATION ${BINDIR}
|
||||
FILES_MATCHING
|
||||
PATTERN "*.dll"
|
||||
PATTERN "vcpkg_installed" EXCLUDE
|
||||
PATTERN "CMakeFiles" EXCLUDE
|
||||
PATTERN "Testing" EXCLUDE)
|
||||
endif(UNIX)
|
||||
|
||||
#[[
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
vim: set ts=4 expandtab:
|
||||
]]
|
||||
|
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:
|
||||
|
||||
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.
|
||||
```
|
||||
cd osslsigncode-folder
|
||||
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \
|
||||
-lcrypto -lssl -lcurl \
|
||||
-D 'PACKAGE_STRING="osslsigncode x.y"' \
|
||||
-D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \
|
||||
-D ENABLE_CURL
|
||||
mkdir build && cd build && cmake -S .. -DCMAKE_BUILD_TYPE=Release -G "MSYS Makefiles"
|
||||
cmake --build . --verbose
|
||||
```
|
||||
|
||||
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
|
||||
cd osslsigncode-folder
|
||||
osslsigncode.exe -v
|
||||
osslsigncode 2.4, using:
|
||||
OpenSSL 1.1.1g 21 Apr 2020 (Library: OpenSSL 1.1.1g 21 Apr 2020)
|
||||
libcurl/7.70.0 OpenSSL/1.1.1g (Schannel) zlib/1.2.11 brotli/1.0.7 libidn2/2.3.0
|
||||
libpsl/0.21.0 (+libidn2/2.3.0) libssh2/1.9.0 nghttp2/1.40.0
|
||||
osslsigncode 2.8, using:
|
||||
OpenSSL 3.2.0 23 Nov 2023 (Library: OpenSSL 3.2.0 23 Nov 2023)
|
||||
No default -CAfile location detected
|
||||
```
|
||||
|
||||
|
||||
### Building OpenSSL, Curl and osslsigncode sources with MSYS2 MinGW 64-bit:
|
||||
### Building OpenSSL and osslsigncode sources with MSYS2 MinGW 64-bit:
|
||||
|
||||
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.
|
||||
```
|
||||
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.
|
||||
|
||||
2) Build and install OpenSSL.
|
||||
@ -55,46 +45,30 @@
|
||||
./config --prefix='C:/OpenSSL' --openssldir='C:/OpenSSL'
|
||||
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
|
||||
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
|
||||
mkdir build && cd build && cmake -S .. -DCMAKE_BUILD_TYPE=Release -G "MSYS Makefiles" -DCMAKE_PREFIX_PATH="C:\OpenSSL"
|
||||
```
|
||||
|
||||
4) Run "Command prompt" and copy required libraries.
|
||||
```
|
||||
cd osslsigncode-folder
|
||||
copy C:\OpenSSL\bin\libssl-1_1-x64.dll
|
||||
copy C:\OpenSSL\bin\libcrypto-1_1-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
|
||||
copy C:\OpenSSL\bin\libssl-3-x64.dll
|
||||
copy C:\OpenSSL\bin\libcrypto-3-x64.dll
|
||||
```
|
||||
|
||||
### 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
|
||||
|
||||
|
56
NEWS.md
56
NEWS.md
@ -1,5 +1,61 @@
|
||||
# osslsigncode change log
|
||||
|
||||
### 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)
|
||||
|
||||
- fixed signing CAB files (by Michael Brown)
|
||||
- fixed handling of unsupported commands (by Maxim Bagryantsev)
|
||||
- fixed writing DIFAT sectors
|
||||
- added APPX support (by Maciej Panek and Małgorzata Olszówka)
|
||||
- added a built-in TSA response generation (-TSA-certs, -TSA-key
|
||||
and -TSA-time options)
|
||||
|
||||
### 2.6 (2023.05.29)
|
||||
|
||||
- modular architecture implemented to simplify adding file formats
|
||||
- added verification of CRLs specified in the signing certificate
|
||||
- added MSI DIFAT sectors support (by Max Bagryantsev)
|
||||
- added legacy provider support for OpenSSL 3.0.0 and later
|
||||
- fixed numerous bugs
|
||||
|
||||
### 2.5 (2022.08.12)
|
||||
|
||||
- fixed the Unix executable install path
|
||||
|
11
README.md
11
README.md
@ -39,14 +39,14 @@ We highly recommend downloading a [release tarball](https://github.com/mtrojnar/
|
||||
|
||||
* 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:
|
||||
```
|
||||
brew install cmake pkg-config openssl@1.1
|
||||
export PKG_CONFIG_PATH="/usr/local/opt/openssl@1.1/lib/pkgconfig"
|
||||
```
|
||||
**NOTE:** osslsigncode requires CMake 3.6 or newer.
|
||||
**NOTE:** osslsigncode requires CMake 3.17 or newer.
|
||||
|
||||
You may need to use `cmake3` instead of `cmake` to complete the following steps on your system.
|
||||
* Navigate to the build directory and run CMake to configure the osslsigncode project
|
||||
@ -54,12 +54,13 @@ You may need to use `cmake3` instead of `cmake` to complete the following steps
|
||||
```
|
||||
mkdir build && cd build && cmake -S ..
|
||||
```
|
||||
with specific compile options:
|
||||
optional CMake parameters:
|
||||
```
|
||||
-DCMAKE_BUILD_TYPE=Debug
|
||||
-DCMAKE_C_COMPILER=clang
|
||||
-DCMAKE_PREFIX_PATH=[openssl directory];[curl directory]
|
||||
-DCMAKE_INSTALL_PREFIX=[installation directory]
|
||||
-DBASH_COMPLETION_USER_DIR=[bash completion installation directory]
|
||||
|
||||
```
|
||||
* Then call that build system to actually compile/link the osslsigncode project (alias `make`):
|
||||
@ -180,9 +181,7 @@ in the unauthenticated blob, as an attacker could modify this. Do NOT, under
|
||||
any circumstances, put a URL here that you will use to download an additional
|
||||
file. If you do do that, you would need to check the newly downloaded file is
|
||||
code signed AND that it has been signed with your cert AND that it is the
|
||||
version you expect. You should consider using asymmetrical encryption for the
|
||||
data you put in the blob, such that the executable contains the public key to
|
||||
decrypt the data. Basically, be VERY careful.
|
||||
version you expect.
|
||||
|
||||
## BUGS, QUESTIONS etc.
|
||||
|
||||
|
490
cat.c
Normal file
490
cat.c
Normal file
@ -0,0 +1,490 @@
|
||||
/*
|
||||
* CAT file support library
|
||||
*
|
||||
* Copyright (C) 2021-2023 Michał Trojnara <Michal.Trojnara@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.
|
||||
* CAT files do not support nesting (multiple signature)
|
||||
*/
|
||||
|
||||
#include "osslsigncode.h"
|
||||
#include "helpers.h"
|
||||
|
||||
typedef struct {
|
||||
ASN1_BMPSTRING *tag;
|
||||
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 {
|
||||
uint32_t sigpos;
|
||||
uint32_t siglen;
|
||||
uint32_t fileend;
|
||||
PKCS7 *p7;
|
||||
};
|
||||
|
||||
/* FILE_FORMAT method prototypes */
|
||||
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_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
|
||||
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||
static void cat_bio_free(BIO *hash, BIO *outdata);
|
||||
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx);
|
||||
|
||||
FILE_FORMAT file_format_cat = {
|
||||
.ctx_new = cat_ctx_new,
|
||||
.verify_digests = cat_verify_digests,
|
||||
.pkcs7_extract = cat_pkcs7_extract,
|
||||
.pkcs7_signature_new = cat_pkcs7_signature_new,
|
||||
.append_pkcs7 = cat_append_pkcs7,
|
||||
.bio_free = cat_bio_free,
|
||||
.ctx_cleanup = cat_ctx_cleanup,
|
||||
};
|
||||
|
||||
/* Prototypes */
|
||||
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
|
||||
static int cat_add_ms_ctl_object(PKCS7 *p7);
|
||||
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents);
|
||||
static int cat_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
|
||||
*/
|
||||
|
||||
/*
|
||||
* Allocate and return a CAT file format context.
|
||||
* [in, out] options: structure holds the input data
|
||||
* [out] hash: message digest BIO (unused)
|
||||
* [in] outdata: outdata file BIO (unused)
|
||||
* [returns] pointer to CAT file format context
|
||||
*/
|
||||
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata)
|
||||
{
|
||||
FILE_FORMAT_CTX *ctx;
|
||||
CAT_CTX *cat_ctx;
|
||||
uint32_t filesize;
|
||||
|
||||
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH || options->cmd == CMD_EXTRACT_DATA) {
|
||||
fprintf(stderr, "Unsupported command\n");
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
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 */
|
||||
}
|
||||
cat_ctx = cat_ctx_get(options->indata, filesize);
|
||||
if (!cat_ctx) {
|
||||
unmap_file(options->indata, filesize);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
|
||||
ctx->format = &file_format_cat;
|
||||
ctx->options = options;
|
||||
ctx->cat_ctx = cat_ctx;
|
||||
|
||||
/* Push hash on outdata, if hash is NULL the function does nothing */
|
||||
BIO_push(hash, outdata);
|
||||
|
||||
if (options->cmd == CMD_VERIFY)
|
||||
printf("Warning: Use -catalog option to verify that a file, listed in catalog file, is signed\n");
|
||||
if (options->jp >= 0)
|
||||
printf("Warning: -jp option is only valid for CAB files\n");
|
||||
if (options->pagehash == 1)
|
||||
printf("Warning: -ph option is only valid for PE files\n");
|
||||
if (options->add_msi_dse == 1)
|
||||
printf("Warning: -add-msi-dse option is only valid for MSI files\n");
|
||||
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.
|
||||
* [in] ctx: structure holds input and output data
|
||||
* [returns] pointer to PKCS#7 structure
|
||||
*/
|
||||
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||
{
|
||||
if (!cat_check_file(ctx)) {
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
return PKCS7_dup(ctx->cat_ctx->p7);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a new PKCS#7 signature.
|
||||
* [in, out] ctx: structure holds input and output data
|
||||
* [out] hash: message digest BIO (unused)
|
||||
* [returns] pointer to PKCS#7 structure
|
||||
*/
|
||||
static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||
{
|
||||
PKCS7 *p7 = NULL;
|
||||
|
||||
/* squash unused parameter warnings */
|
||||
(void)hash;
|
||||
|
||||
p7 = pkcs7_create(ctx);
|
||||
if (!p7) {
|
||||
fprintf(stderr, "Creating a new signature failed\n");
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if (!cat_add_ms_ctl_object(p7)) {
|
||||
fprintf(stderr, "Adding MS_CTL_OBJID failed\n");
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if (!ctx->cat_ctx->p7 || !ctx->cat_ctx->p7->d.sign || !ctx->cat_ctx->p7->d.sign->contents) {
|
||||
fprintf(stderr, "Failed to get content\n");
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if (!cat_sign_ms_ctl_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
|
||||
fprintf(stderr, "Failed to set signed content\n");
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
return p7; /* OK */
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||
{
|
||||
return data_write_pkcs7(ctx, outdata, p7);
|
||||
}
|
||||
|
||||
/*
|
||||
* Free up an entire message digest BIO chain.
|
||||
* [out] hash: message digest BIO
|
||||
* [out] outdata: outdata file BIO (unused)
|
||||
* [returns] none
|
||||
*/
|
||||
static void cat_bio_free(BIO *hash, BIO *outdata)
|
||||
{
|
||||
/* squash the unused parameter warning */
|
||||
(void)outdata;
|
||||
BIO_free_all(hash);
|
||||
}
|
||||
|
||||
/*
|
||||
* Deallocate a FILE_FORMAT_CTX structure and CAT format specific structure,
|
||||
* unmap indata file.
|
||||
* [in, out] ctx: structure holds all input and output data
|
||||
* [out] hash: message digest BIO
|
||||
* [in] outdata: outdata file BIO
|
||||
* [returns] none
|
||||
*/
|
||||
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx)
|
||||
{
|
||||
unmap_file(ctx->options->indata, ctx->cat_ctx->fileend);
|
||||
PKCS7_free(ctx->cat_ctx->p7);
|
||||
OPENSSL_free(ctx->cat_ctx);
|
||||
OPENSSL_free(ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* CAT helper functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Verify mapped PKCS#7 (CAT) file and create CAT format specific structure.
|
||||
* [in] indata: mapped file
|
||||
* [in] filesize: size of file
|
||||
* [returns] pointer to CAT format specific structure
|
||||
*/
|
||||
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
|
||||
{
|
||||
CAT_CTX *cat_ctx;
|
||||
PKCS7 *p7;
|
||||
|
||||
p7 = pkcs7_read_data(indata, filesize);
|
||||
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->p7 = p7;
|
||||
cat_ctx->sigpos = 0;
|
||||
cat_ctx->siglen = filesize;
|
||||
cat_ctx->fileend = filesize;
|
||||
return cat_ctx; /* OK */
|
||||
}
|
||||
|
||||
/*
|
||||
* Add "1.3.6.1.4.1.311.10.1" MS_CTL_OBJID signed attribute
|
||||
* [in, out] p7: new PKCS#7 signature
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
static int cat_add_ms_ctl_object(PKCS7 *p7)
|
||||
{
|
||||
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||
PKCS7_SIGNER_INFO *si;
|
||||
|
||||
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(MS_CTL_OBJID, 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_ms_ctl_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:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
|
||||
vim: set ts=4 expandtab:
|
||||
*/
|
@ -25,3 +25,12 @@ list(APPEND CPACK_SOURCE_IGNORE_FILES "/build/")
|
||||
|
||||
include(CPack)
|
||||
add_custom_target(dist COMMAND ${CMAKE_MAKE_PROGRAM} package_source)
|
||||
|
||||
#[[
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
vim: set ts=4 expandtab:
|
||||
]]
|
||||
|
@ -1,298 +1,624 @@
|
||||
# make test
|
||||
# ctest -C Release
|
||||
|
||||
########## Configure ##########
|
||||
|
||||
include(FindPython3)
|
||||
enable_testing()
|
||||
|
||||
set(FILES "${PROJECT_BINARY_DIR}/Testing/files")
|
||||
set(CERTS "${PROJECT_BINARY_DIR}/Testing/certs")
|
||||
set(CONF "${PROJECT_BINARY_DIR}/Testing/conf")
|
||||
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/files"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/conf"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/tsa_server.py"
|
||||
DESTINATION "${PROJECT_BINARY_DIR}/Testing"
|
||||
)
|
||||
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/certs/ca-bundle.crt"
|
||||
DESTINATION "${CONF}"
|
||||
)
|
||||
|
||||
set(priv_p12 "-pkcs12" "${CERTS}/cert.p12" "-readpass" "${CERTS}/password.txt")
|
||||
set(priv_spc "-certs" "${CERTS}/cert.spc" "-key" "${CERTS}/key.pvk" "-pass" "passme")
|
||||
set(priv_der "-certs" "${CERTS}/cert.pem" "-key" "${CERTS}/key.der" "-pass" "passme")
|
||||
set(priv_pkey "-certs" "${CERTS}/cert.pem" "-key" "${CERTS}/keyp.pem" "-pass" "passme")
|
||||
set(sign_opt "-time" "1556708400"
|
||||
"-add-msi-dse" "-comm" "-ph" "-jp" "low"
|
||||
"-h" "sha512" "-i" "https://www.osslsigncode.com/"
|
||||
"-n" "osslsigncode" "-ac" "${CERTS}/crosscert.pem"
|
||||
)
|
||||
|
||||
if(CMAKE_HOST_UNIX)
|
||||
execute_process(
|
||||
COMMAND "${CONF}/makecerts.sh"
|
||||
WORKING_DIRECTORY ${CONF}
|
||||
OUTPUT_VARIABLE makecerts_output
|
||||
RESULT_VARIABLE makecerts_result
|
||||
)
|
||||
else()
|
||||
set(makecerts_result 1)
|
||||
endif()
|
||||
if(makecerts_result)
|
||||
message(STATUS "makecerts.sh failed")
|
||||
if(makecerts_output)
|
||||
message(STATUS "${makecerts_output}")
|
||||
endif()
|
||||
file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/tests/certs"
|
||||
DESTINATION "${PROJECT_BINARY_DIR}/Testing"
|
||||
)
|
||||
endif()
|
||||
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E sha256sum "${CERTS}/cert.der"
|
||||
OUTPUT_VARIABLE sha256sum
|
||||
)
|
||||
string(SUBSTRING ${sha256sum} 0 64 leafhash)
|
||||
set(verify_opt "-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem"
|
||||
"-TSA-CAfile" "${CERTS}/TSACA.pem"
|
||||
)
|
||||
set(extensions_4 "exe" "ex_" "msi" "cat")
|
||||
set(extensions_3 "exe" "ex_" "msi")
|
||||
set(files_4 "signed" "nested" "added")
|
||||
set(files_3 "removed" "attached_pem" "attached_der")
|
||||
set(sign_formats "pem" "der")
|
||||
set(pem_certs "cert" "expired" "revoked")
|
||||
set(failed_certs "expired" "revoked")
|
||||
|
||||
add_test(
|
||||
NAME version
|
||||
COMMAND osslsigncode --version
|
||||
)
|
||||
|
||||
foreach(ext ${extensions_4})
|
||||
# Signing time: May 1 00:00:00 2019 GMT
|
||||
set(sign_${ext} )
|
||||
add_test(
|
||||
NAME signed_${ext}
|
||||
COMMAND osslsigncode "sign" ${sign_opt} ${priv_p12}
|
||||
"-in" "${FILES}/unsigned.${ext}" "-out" "${FILES}/signed.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_3})
|
||||
add_test(
|
||||
NAME removed_${ext}
|
||||
COMMAND osslsigncode "remove-signature"
|
||||
"-in" "${FILES}/signed.${ext}" "-out" "${FILES}/removed.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_3})
|
||||
add_test(
|
||||
NAME extract_pem_${ext}
|
||||
COMMAND osslsigncode "extract-signature" "-pem"
|
||||
"-in" "${FILES}/signed.${ext}" "-out" "${FILES}/${ext}.pem"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_3})
|
||||
add_test(
|
||||
NAME extract_der_${ext}
|
||||
COMMAND osslsigncode "extract-signature"
|
||||
"-in" "${FILES}/signed.${ext}" "-out" "${FILES}/${ext}.der"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_3})
|
||||
set_tests_properties(removed_${ext} extract_pem_${ext} extract_der_${ext}
|
||||
PROPERTIES DEPENDS sign_${ext}
|
||||
REQUIRED_FILES "${FILES}/signed.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_3})
|
||||
foreach(format ${sign_formats})
|
||||
# Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
add_test(
|
||||
NAME attached_${format}_${ext}
|
||||
COMMAND osslsigncode "attach-signature" ${verify_opt}
|
||||
"-time" "1567296000"
|
||||
"-require-leaf-hash" "SHA256:${leafhash}"
|
||||
"-add-msi-dse" "-h" "sha512" "-nest"
|
||||
"-sigin" "${FILES}/${ext}.${format}"
|
||||
"-in" "${FILES}/signed.${ext}" "-out" "${FILES}/attached_${format}.${ext}"
|
||||
)
|
||||
set_tests_properties(attached_${format}_${ext} PROPERTIES
|
||||
DEPENDS extract_pem_${ext}
|
||||
REQUIRED_FILES "${FILES}/signed.${ext}"
|
||||
REQUIRED_FILES "${FILES}/${ext}.${format}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_4})
|
||||
add_test(
|
||||
NAME added_${ext}
|
||||
COMMAND osslsigncode "add"
|
||||
"-addUnauthenticatedBlob" "-add-msi-dse" "-h" "sha512"
|
||||
"-in" "${FILES}/signed.${ext}" "-out" "${FILES}/added.${ext}"
|
||||
)
|
||||
set_tests_properties(added_${ext} PROPERTIES
|
||||
DEPENDS sign_${ext}
|
||||
REQUIRED_FILES "${FILES}/signed.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_4})
|
||||
add_test(
|
||||
NAME nested_${ext}
|
||||
COMMAND osslsigncode "sign" "-nest" ${sign_opt} ${priv_der}
|
||||
"-in" "${FILES}/signed.${ext}" "-out" "${FILES}/nested.${ext}"
|
||||
)
|
||||
set_tests_properties(nested_${ext} PROPERTIES
|
||||
DEPENDS sign_${ext}
|
||||
REQUIRED_FILES "${FILES}/signed.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
|
||||
|
||||
foreach(file ${files_4})
|
||||
foreach(ext ${extensions_4})
|
||||
# Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
add_test(
|
||||
NAME verify_${file}_${ext}
|
||||
COMMAND osslsigncode "verify" ${verify_opt}
|
||||
"-time" "1567296000"
|
||||
"-require-leaf-hash" "SHA256:${leafhash}"
|
||||
"-in" "${FILES}/${file}.${ext}"
|
||||
)
|
||||
set_tests_properties(verify_${file}_${ext} PROPERTIES
|
||||
DEPENDS ${file}_${ext}
|
||||
REQUIRED_FILES "${FILES}/${file}.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
foreach(file ${files_3})
|
||||
foreach(ext ${extensions_3})
|
||||
# Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
add_test(
|
||||
NAME verify_${file}_${ext}
|
||||
COMMAND osslsigncode "verify" ${verify_opt}
|
||||
"-time" "1567296000"
|
||||
"-require-leaf-hash" "SHA256:${leafhash}"
|
||||
"-in" "${FILES}/${file}.${ext}"
|
||||
)
|
||||
set_tests_properties(verify_${file}_${ext} PROPERTIES
|
||||
DEPENDS ${file}_${ext}
|
||||
REQUIRED_FILES "${FILES}/${file}.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
|
||||
foreach(ext ${extensions_3})
|
||||
set_tests_properties(verify_removed_${ext} PROPERTIES
|
||||
WILL_FAIL TRUE
|
||||
)
|
||||
endforeach()
|
||||
|
||||
|
||||
if(Python3_FOUND)
|
||||
foreach(ext ${extensions_4})
|
||||
foreach(cert ${pem_certs})
|
||||
add_test(
|
||||
NAME sign_ts_${cert}_${ext}
|
||||
COMMAND ${Python3_EXECUTABLE} "${PROJECT_BINARY_DIR}/Testing/tsa_server.py"
|
||||
"--certs" "${CERTS}/${cert}.pem" "--key" "${CERTS}/key.pem"
|
||||
"--input" "${FILES}/unsigned.${ext}" "--output" "${FILES}/ts_${cert}.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
execute_process(
|
||||
COMMAND ${Python3_EXECUTABLE} "check_cryptography.py"
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/tests"
|
||||
OUTPUT_VARIABLE cryptography_output
|
||||
RESULT_VARIABLE cryptography_error)
|
||||
|
||||
foreach(ext ${extensions_4})
|
||||
# Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
add_test(
|
||||
NAME verify_ts_cert_${ext}
|
||||
COMMAND osslsigncode "verify" ${verify_opt}
|
||||
"-time" "1567296000"
|
||||
"-in" "${FILES}/ts_cert.${ext}"
|
||||
)
|
||||
set_tests_properties(verify_ts_cert_${ext} PROPERTIES
|
||||
DEPENDS sign_ts_${cert}_${ext}
|
||||
REQUIRED_FILES "${FILES}/ts_cert.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
if(NOT cryptography_error)
|
||||
message(STATUS "Using python3-cryptography version ${cryptography_output}")
|
||||
option(STOP_SERVER "Stop HTTP server after tests" ON)
|
||||
|
||||
# Signature verification time: Jan 1 00:00:00 2035 GMT
|
||||
foreach(ext ${extensions_4})
|
||||
add_test(
|
||||
NAME verify_ts_future_${ext}
|
||||
COMMAND osslsigncode "verify" ${verify_opt}
|
||||
"-time" "2051222400"
|
||||
"-in" "${FILES}/ts_cert.${ext}"
|
||||
)
|
||||
set_tests_properties(verify_ts_future_${ext} PROPERTIES
|
||||
DEPENDS sign_ts_${cert}_${ext}
|
||||
REQUIRED_FILES "${FILES}/ts_cert.${ext}"
|
||||
)
|
||||
endforeach()
|
||||
# Remove http proxy configuration that may change behavior
|
||||
unset(ENV{HTTP_PROXY})
|
||||
unset(ENV{http_proxy})
|
||||
|
||||
# Signature verification time: Jan 1 00:00:00 2035 GMT
|
||||
# enabled "-ignore-timestamp" option
|
||||
foreach(ext ${extensions_4})
|
||||
add_test(
|
||||
NAME verify_ts_ignore_${ext}
|
||||
COMMAND osslsigncode "verify" ${verify_opt}
|
||||
"-time" "2051222400"
|
||||
"-ignore-timestamp"
|
||||
"-in" "${FILES}/ts_cert.${ext}"
|
||||
)
|
||||
set_tests_properties(verify_ts_ignore_${ext} PROPERTIES
|
||||
DEPENDS sign_ts_${cert}_${ext}
|
||||
REQUIRED_FILES "${FILES}/ts_cert.${ext}"
|
||||
WILL_FAIL TRUE
|
||||
)
|
||||
endforeach()
|
||||
set(TEST_DIR "${PROJECT_BINARY_DIR}/Testing")
|
||||
if(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
|
||||
set(OSSLSIGNCODE "${PROJECT_BINARY_DIR}/${CMAKE_BUILD_TYPE}/osslsigncode")
|
||||
else(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
|
||||
set(OSSLSIGNCODE "${PROJECT_BINARY_DIR}/osslsigncode")
|
||||
endif(CMAKE_GENERATOR STREQUAL "Ninja Multi-Config")
|
||||
set(EXEC "${TEST_DIR}/exec.py")
|
||||
set(FILES "${TEST_DIR}/files")
|
||||
set(CERTS "${TEST_DIR}/certs")
|
||||
set(CONF "${TEST_DIR}/conf")
|
||||
set(LOGS "${TEST_DIR}/logs")
|
||||
|
||||
# Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
# Certificate has expired or revoked
|
||||
foreach(ext ${extensions_4})
|
||||
foreach(cert ${failed_certs})
|
||||
add_test(
|
||||
NAME verify_ts_${cert}_${ext}
|
||||
COMMAND osslsigncode "verify" ${verify_opt}
|
||||
"-time" "1567296000"
|
||||
"-in" "${FILES}/ts_${cert}.${ext}"
|
||||
)
|
||||
set_tests_properties(verify_ts_${cert}_${ext} PROPERTIES
|
||||
DEPENDS sign_ts_${cert}_${ext}
|
||||
REQUIRED_FILES "${FILES}/ts_${cert}.${ext}"
|
||||
WILL_FAIL TRUE
|
||||
)
|
||||
endforeach()
|
||||
endforeach()
|
||||
file(MAKE_DIRECTORY "${LOGS}")
|
||||
|
||||
else()
|
||||
message(STATUS "Python3 was not found, skip timestamping tests")
|
||||
endif()
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/certs/ca-bundle.crt"
|
||||
DESTINATION "${CONF}")
|
||||
|
||||
foreach(ext ${extensions_4})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/signed.${ext}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/nested.${ext}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/removed.${ext}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/added.${ext}")
|
||||
foreach(cert ${pem_certs})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/ts_${cert}.${ext}")
|
||||
endforeach()
|
||||
foreach(format ${sign_formats})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${ext}.${format}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${ext}.${format}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/attached_${format}.${ext}")
|
||||
endforeach()
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jreq.tsq")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jresp.tsr")
|
||||
endforeach()
|
||||
add_test(NAME remove_files COMMAND ${CMAKE_COMMAND} -E rm -f ${OUTPUT_FILES})
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/files"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/conf"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/client_http.py"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/make_certificates.py"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/start_server.py"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/exec.py"
|
||||
DESTINATION "${TEST_DIR}/")
|
||||
|
||||
if(UNIX)
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/server_http.py"
|
||||
DESTINATION "${TEST_DIR}/")
|
||||
set(SERVER_HTTP "${TEST_DIR}/server_http.py")
|
||||
set(Python3w_EXECUTABLE ${Python3_EXECUTABLE})
|
||||
else(UNIX)
|
||||
file(COPY
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/tests/server_http.pyw"
|
||||
DESTINATION "${TEST_DIR}/")
|
||||
set(SERVER_HTTP "${TEST_DIR}/server_http.pyw")
|
||||
get_filename_component(PYTHON_DIRECTORY ${Python3_EXECUTABLE} DIRECTORY)
|
||||
set(Python3w_EXECUTABLE "${PYTHON_DIRECTORY}/pythonw.exe")
|
||||
endif(UNIX)
|
||||
|
||||
if(EXISTS "${LOGS}/url.log")
|
||||
# Stop HTTP server if running
|
||||
message(STATUS "Try to kill HTTP server")
|
||||
execute_process(
|
||||
COMMAND ${Python3_EXECUTABLE} "${TEST_DIR}/client_http.py"
|
||||
OUTPUT_VARIABLE client_output
|
||||
RESULT_VARIABLE client_result)
|
||||
if(NOT client_result)
|
||||
# Successfully closed
|
||||
message(STATUS "${client_output}")
|
||||
endif(NOT client_result)
|
||||
endif(EXISTS "${LOGS}/url.log")
|
||||
|
||||
set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat" "ps1" "psc1" "mof")
|
||||
set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx" "ps1" "psc1" "mof")
|
||||
set(extensions_nocatappx "exe" "ex_" "msi" "ps1" "psc1" "mof")
|
||||
set(formats "pem" "der")
|
||||
|
||||
else(NOT cryptography_error)
|
||||
message(STATUS "CTest skips tests: ${cryptography_output}")
|
||||
endif(NOT cryptography_error)
|
||||
|
||||
else(Python3_FOUND)
|
||||
message(STATUS "CTest skips tests: Python3 not found")
|
||||
endif(Python3_FOUND)
|
||||
|
||||
|
||||
########## Testing ##########
|
||||
|
||||
enable_testing()
|
||||
|
||||
### osslsigncode version ###
|
||||
if(Python3_FOUND AND NOT cryptography_error)
|
||||
|
||||
### Start ###
|
||||
add_test(NAME "version"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE}
|
||||
"--version")
|
||||
|
||||
add_test(NAME "start_server"
|
||||
COMMAND ${Python3_EXECUTABLE} "${TEST_DIR}/start_server.py"
|
||||
"--exe" ${Python3w_EXECUTABLE}
|
||||
"--script" ${SERVER_HTTP})
|
||||
set_tests_properties("start_server" PROPERTIES
|
||||
TIMEOUT 60)
|
||||
set(ALL_TESTS "version" "start_server")
|
||||
|
||||
### Sign ###
|
||||
|
||||
# Sign with PKCS#12 container with private key and certificate encryption algorithm
|
||||
# Signing time: May 1 00:00:00 2019 GMT (1556668800)
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "signed_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "sign"
|
||||
"-pkcs12" "${CERTS}/cert.p12"
|
||||
"-readpass" "${CERTS}/password.txt"
|
||||
"-ac" "${CERTS}/CAcross.pem"
|
||||
"-time" "1556668800"
|
||||
"-add-msi-dse"
|
||||
"-comm"
|
||||
"-ph"
|
||||
"-jp" "low"
|
||||
"-h" "sha512" "-i" "https://www.osslsigncode.com/"
|
||||
"-n" "osslsigncode"
|
||||
"-in" "${FILES}/unsigned.${ext}"
|
||||
"-out" "${FILES}/signed.${ext}")
|
||||
set_tests_properties("signed_${ext}" PROPERTIES
|
||||
DEPENDS "start_server")
|
||||
list(APPEND ALL_TESTS "signed_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Sign with revoked certificate
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "revoked_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "sign"
|
||||
"-certs" "${CERTS}/revoked.pem"
|
||||
"-key" "${CERTS}/keyp.pem"
|
||||
"-readpass" "${CERTS}/password.txt"
|
||||
"-ac" "${CERTS}/CAcross.pem"
|
||||
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
|
||||
"-add-msi-dse"
|
||||
"-comm"
|
||||
"-ph"
|
||||
"-jp" "low"
|
||||
"-h" "sha512" "-i" "https://www.osslsigncode.com/"
|
||||
"-n" "osslsigncode"
|
||||
"-in" "${FILES}/unsigned.${ext}"
|
||||
"-out" "${FILES}/revoked.${ext}")
|
||||
set_tests_properties("revoked_${ext}" PROPERTIES
|
||||
DEPENDS "start_server")
|
||||
list(APPEND ALL_TESTS "revoked_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Remove signature
|
||||
# Unsupported command for CAT files
|
||||
foreach(ext ${extensions_nocat})
|
||||
add_test(NAME "removed_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "remove-signature"
|
||||
"-in" "${FILES}/signed.${ext}"
|
||||
"-out" "${FILES}/removed.${ext}")
|
||||
set_tests_properties("removed_${ext}" PROPERTIES
|
||||
DEPENDS "signed_${ext}")
|
||||
list(APPEND ALL_TESTS "removed_${ext}")
|
||||
endforeach(ext ${extensions_nocat})
|
||||
|
||||
# Extract PKCS#7 signature in PEM format
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "extract_pem_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "extract-signature"
|
||||
"-pem" # PEM format
|
||||
"-in" "${FILES}/signed.${ext}"
|
||||
"-out" "${FILES}/${ext}.pem")
|
||||
set_tests_properties("extract_pem_${ext}" PROPERTIES
|
||||
DEPENDS "signed_${ext}")
|
||||
list(APPEND ALL_TESTS "extract_pem_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Extract PKCS#7 signature in default DER format
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "extract_der_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "extract-signature"
|
||||
"-in" "${FILES}/signed.${ext}"
|
||||
"-out" "${FILES}/${ext}.der")
|
||||
set_tests_properties("extract_der_${ext}" PROPERTIES
|
||||
DEPENDS "signed_${ext}")
|
||||
list(APPEND ALL_TESTS "extract_der_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Attach a nested signature in PEM or DER format
|
||||
# Unsupported command for CAT files
|
||||
foreach(ext ${extensions_nocat})
|
||||
foreach(format ${formats})
|
||||
add_test(NAME "attached_${format}_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "attach-signature"
|
||||
# sign options
|
||||
"-add-msi-dse"
|
||||
"-h" "sha512"
|
||||
"-nest"
|
||||
"-sigin" "${FILES}/${ext}.${format}"
|
||||
"-in" "${FILES}/signed.${ext}"
|
||||
"-out" "${FILES}/attached_${format}.${ext}"
|
||||
# verify options
|
||||
"-require-leaf-hash" "FILE ${CERTS}/leafhash.txt"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem")
|
||||
set_tests_properties("attached_${format}_${ext}" PROPERTIES
|
||||
DEPENDS "signed_${ext};extract_pem_${ext};extract_der_${ext}")
|
||||
list(APPEND ALL_TESTS "attached_${format}_${ext}")
|
||||
endforeach(format ${formats})
|
||||
endforeach(ext ${extensions_nocat})
|
||||
|
||||
# Add an unauthenticated blob to a previously-signed file
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "added_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "add"
|
||||
"-addUnauthenticatedBlob"
|
||||
"-add-msi-dse" "-h" "sha512"
|
||||
"-in" "${FILES}/signed.${ext}"
|
||||
"-out" "${FILES}/added.${ext}")
|
||||
set_tests_properties("added_${ext}" PROPERTIES
|
||||
DEPENDS "signed_${ext}")
|
||||
list(APPEND ALL_TESTS "added_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Add the new nested signature instead of replacing the first one
|
||||
# APPX files do not support nesting (multiple signature)
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "nested_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "sign"
|
||||
"-nest"
|
||||
"-certs" "${CERTS}/cert.pem"
|
||||
"-key" "${CERTS}/key.der"
|
||||
"-pass" "passme"
|
||||
"-ac" "${CERTS}/CAcross.pem"
|
||||
"-time" "1556755200" # Signing time: May 2 00:00:00 2019 GMT
|
||||
"-add-msi-dse"
|
||||
"-comm"
|
||||
"-ph"
|
||||
"-jp" "low"
|
||||
"-h" "sha512"
|
||||
"-i" "https://www.osslsigncode.com/"
|
||||
"-n" "osslsigncode"
|
||||
"-in" "${FILES}/signed.${ext}"
|
||||
"-out" "${FILES}/nested.${ext}")
|
||||
set_tests_properties("nested_${ext}" PROPERTIES
|
||||
DEPENDS "signed_${ext}")
|
||||
list(APPEND ALL_TESTS "nested_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
|
||||
### Verify signature ###
|
||||
|
||||
# Verify PE/MSI/CAB files signed in the catalog file
|
||||
# CAT and APPX files do not support detached PKCS#7 signature
|
||||
foreach(ext ${extensions_nocatappx})
|
||||
add_test(NAME "verify_catalog_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-catalog" "${FILES}/signed.cat" # catalog file
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-require-leaf-hash" "FILE ${CERTS}/leafhash.txt"
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem"
|
||||
"-in" "${FILES}/unsigned.${ext}")
|
||||
set_tests_properties("verify_catalog_${ext}" PROPERTIES
|
||||
DEPENDS "signed_${ext}")
|
||||
list(APPEND ALL_TESTS "verify_catalog_${ext}")
|
||||
endforeach(ext ${extensions_nocatappx})
|
||||
|
||||
# Verify signature
|
||||
set(files "signed" "nested" "added" "revoked")
|
||||
foreach(file ${files})
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "verify_${file}_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem"
|
||||
"-in" "${FILES}/${file}.${ext}")
|
||||
set_tests_properties("verify_${file}_${ext}" PROPERTIES
|
||||
DEPENDS "${file}_${ext}")
|
||||
list(APPEND ALL_TESTS "verify_${file}_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
endforeach(file ${files})
|
||||
|
||||
# "revoked" tests are expected to fail
|
||||
set(files "revoked")
|
||||
foreach(file ${files})
|
||||
foreach(ext ${extensions_all})
|
||||
set_tests_properties("verify_${file}_${ext}" PROPERTIES
|
||||
WILL_FAIL TRUE)
|
||||
endforeach(ext ${extensions_all})
|
||||
endforeach(file ${files})
|
||||
|
||||
# Verify removed signature
|
||||
# "removed" tests are expected to fail
|
||||
# "remove-signature" command is unsupported for CAT files
|
||||
set(files "removed")
|
||||
foreach(file ${files})
|
||||
foreach(ext ${extensions_nocat})
|
||||
add_test(NAME "verify_${file}_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem"
|
||||
"-in" "${FILES}/${file}.${ext}")
|
||||
set_tests_properties("verify_${file}_${ext}" PROPERTIES
|
||||
DEPENDS "${file}_${ext}"
|
||||
WILL_FAIL TRUE)
|
||||
list(APPEND ALL_TESTS "verify_${file}_${ext}")
|
||||
endforeach(ext ${extensions_nocat})
|
||||
endforeach(file ${files})
|
||||
|
||||
# Verify attached signature
|
||||
# "attach-signature" command is unsupported for CAT files
|
||||
set(files "attached_pem" "attached_der")
|
||||
foreach(file ${files})
|
||||
foreach(ext ${extensions_nocat})
|
||||
add_test(NAME "verify_${file}_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem"
|
||||
"-in" "${FILES}/${file}.${ext}")
|
||||
set_tests_properties("verify_${file}_${ext}" PROPERTIES
|
||||
DEPENDS "${file}_${ext}")
|
||||
list(APPEND ALL_TESTS "verify_${file}_${ext}")
|
||||
endforeach(ext ${extensions_nocat})
|
||||
endforeach(file ${files})
|
||||
|
||||
|
||||
### Extract a data content to be signed ###
|
||||
|
||||
# Unsupported command "extract-data" for CAT files
|
||||
foreach(ext ${extensions_nocat})
|
||||
# Extract PKCS#7 with data content, output in PEM format
|
||||
add_test(NAME "data_${ext}_pem"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "extract-data"
|
||||
"-ph"
|
||||
"-h" "sha384"
|
||||
"-add-msi-dse"
|
||||
"-pem" # PEM format
|
||||
"-in" "${FILES}/unsigned.${ext}"
|
||||
"-out" "${FILES}/data_${ext}.pem")
|
||||
|
||||
# Extract PKCS#7 with data content, output in default DER format
|
||||
add_test(NAME "data_${ext}_der"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "extract-data"
|
||||
"-ph"
|
||||
"-h" "sha384"
|
||||
"-add-msi-dse"
|
||||
"-in" "${FILES}/unsigned.${ext}"
|
||||
"-out" "${FILES}/data_${ext}.der")
|
||||
|
||||
foreach(data_format ${formats})
|
||||
set_tests_properties("data_${ext}_${data_format}" PROPERTIES
|
||||
DEPENDS "start_server")
|
||||
list(APPEND ALL_TESTS "data_${ext}_${data_format}")
|
||||
endforeach(data_format ${formats})
|
||||
|
||||
# Sign a data content, output in DER format
|
||||
foreach(data_format ${formats})
|
||||
add_test(NAME "signed_data_${ext}_${data_format}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "sign"
|
||||
"-pkcs12" "${CERTS}/cert.p12"
|
||||
"-readpass" "${CERTS}/password.txt"
|
||||
"-ac" "${CERTS}/CAcross.pem"
|
||||
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
|
||||
"-add-msi-dse"
|
||||
"-comm"
|
||||
"-ph"
|
||||
"-jp" "low"
|
||||
"-h" "sha384"
|
||||
"-i" "https://www.osslsigncode.com/"
|
||||
"-n" "osslsigncode"
|
||||
"-in" "${FILES}/data_${ext}.${data_format}"
|
||||
"-out" "${FILES}/signed_data_${ext}_${data_format}.der")
|
||||
set_tests_properties("signed_data_${ext}_${data_format}" PROPERTIES
|
||||
DEPENDS "data_${ext}_pem;data_${ext}_der")
|
||||
list(APPEND ALL_TESTS "signed_data_${ext}_${data_format}")
|
||||
endforeach(data_format ${formats})
|
||||
|
||||
# Sign a data content, output in PEM format
|
||||
foreach(data_format ${formats})
|
||||
add_test(NAME "signed_data_pem_${ext}_${data_format}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "sign"
|
||||
"-pkcs12" "${CERTS}/cert.p12"
|
||||
"-readpass" "${CERTS}/password.txt"
|
||||
"-ac" "${CERTS}/CAcross.pem"
|
||||
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
|
||||
"-add-msi-dse"
|
||||
"-comm"
|
||||
"-ph"
|
||||
"-jp" "low"
|
||||
"-h" "sha384"
|
||||
"-i" "https://www.osslsigncode.com/"
|
||||
"-n" "osslsigncode"
|
||||
"-pem" # PEM format
|
||||
"-in" "${FILES}/data_${ext}.${data_format}"
|
||||
"-out" "${FILES}/signed_data_${ext}_${data_format}.pem")
|
||||
set_tests_properties("signed_data_pem_${ext}_${data_format}" PROPERTIES
|
||||
DEPENDS "data_${ext}_${data_format}")
|
||||
list(APPEND ALL_TESTS "signed_data_pem_${ext}_${data_format}")
|
||||
endforeach(data_format ${formats})
|
||||
|
||||
# Attach signature in PEM or DER format
|
||||
foreach(data_format ${formats})
|
||||
foreach(format ${formats})
|
||||
add_test(NAME "attached_data_${ext}_${data_format}_${format}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "attach-signature"
|
||||
# sign options
|
||||
"-add-msi-dse"
|
||||
"-h" "sha384"
|
||||
"-sigin" "${FILES}/signed_data_${ext}_${data_format}.${format}"
|
||||
"-in" "${FILES}/unsigned.${ext}"
|
||||
"-out" "${FILES}/attached_data_${data_format}_${format}.${ext}"
|
||||
# verify options
|
||||
"-require-leaf-hash" "FILE ${CERTS}/leafhash.txt"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem")
|
||||
set_tests_properties("attached_data_${ext}_${data_format}_${format}" PROPERTIES
|
||||
DEPENDS "signed_data_${ext}_${data_format};signed_data_pem_${ext}_${data_format}")
|
||||
list(APPEND ALL_TESTS "attached_data_${ext}_${data_format}_${format}")
|
||||
endforeach(format ${formats})
|
||||
endforeach(data_format ${formats})
|
||||
endforeach(ext ${extensions_nocat})
|
||||
|
||||
|
||||
if(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0" OR CURL_FOUND)
|
||||
|
||||
### Sign with Time-Stamp Authority ###
|
||||
|
||||
# Sign with the RFC3161 Time-Stamp Authority
|
||||
set(pem_certs "cert" "expired" "revoked")
|
||||
foreach(ext ${extensions_all})
|
||||
foreach(cert ${pem_certs})
|
||||
add_test(NAME "sign_ts_${cert}_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "sign"
|
||||
"-certs" "${CERTS}/${cert}.pem"
|
||||
"-key" "${CERTS}/key.pem"
|
||||
"-ac" "${CERTS}/CAcross.pem"
|
||||
"-comm"
|
||||
"-ph"
|
||||
"-jp" "low"
|
||||
"-h" "sha384"
|
||||
"-i" "https://www.osslsigncode.com/"
|
||||
"-n" "osslsigncode"
|
||||
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
|
||||
"-ts" "FILE ${LOGS}/url.log"
|
||||
"-in" "${FILES}/unsigned.${ext}"
|
||||
"-out" "${FILES}/ts_${cert}.${ext}")
|
||||
set_tests_properties("sign_ts_${cert}_${ext}" PROPERTIES
|
||||
ENVIRONMENT "HTTP_PROXY=;http_proxy="
|
||||
DEPENDS "start_server")
|
||||
list(APPEND ALL_TESTS "sign_ts_${cert}_${ext}")
|
||||
endforeach(cert ${pem_certs})
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
|
||||
### Verify Time-Stamp Authority ###
|
||||
|
||||
# Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "verify_ts_cert_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-TSA-CAfile" "${CERTS}/TSACA.pem"
|
||||
"-in" "${FILES}/ts_cert.${ext}")
|
||||
set_tests_properties("verify_ts_cert_${ext}" PROPERTIES
|
||||
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
|
||||
DEPENDS "sign_ts_cert_${ext}")
|
||||
list(APPEND ALL_TESTS "verify_ts_cert_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Signature verification time: Jan 1 00:00:00 2035 GMT
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "verify_ts_future_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "2051222400" # Signature verification time: Jan 1 00:00:00 2035 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-TSA-CAfile" "${CERTS}/TSACA.pem"
|
||||
"-in" "${FILES}/ts_cert.${ext}")
|
||||
set_tests_properties("verify_ts_future_${ext}" PROPERTIES
|
||||
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
|
||||
DEPENDS "sign_ts_cert_${ext}")
|
||||
list(APPEND ALL_TESTS "verify_ts_future_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Verify with ignored timestamp
|
||||
# This tests are expected to fail
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "verify_ts_ignore_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "2051222400" # Signature verification time: Jan 1 00:00:00 2035 GMT
|
||||
"-ignore-timestamp"
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-TSA-CAfile" "${CERTS}/TSACA.pem"
|
||||
"-in" "${FILES}/ts_cert.${ext}")
|
||||
set_tests_properties("verify_ts_ignore_${ext}" PROPERTIES
|
||||
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
|
||||
DEPENDS "sign_ts_cert_${ext}"
|
||||
WILL_FAIL TRUE)
|
||||
list(APPEND ALL_TESTS "verify_ts_ignore_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
|
||||
### Verify CRL Distribution Points ###
|
||||
|
||||
# Verify file signed with X509v3 CRL Distribution Points extension
|
||||
# Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
# Check X509v3 CRL Distribution Points extension, don't use "-CRLfile" and "-TSA-CRLfile" options
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "verify_ts_cert_crldp_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-TSA-CAfile" "${CERTS}/TSACA.pem"
|
||||
"-in" "${FILES}/ts_cert.${ext}")
|
||||
set_tests_properties("verify_ts_cert_crldp_${ext}" PROPERTIES
|
||||
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
|
||||
DEPENDS "sign_ts_cert_${ext}")
|
||||
list(APPEND ALL_TESTS "verify_ts_cert_crldp_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Verify with expired or revoked certificate, ignore X509v3 CRL Distribution Points extension
|
||||
# This tests are expected to fail
|
||||
set(failed_certs "expired" "revoked")
|
||||
foreach(ext ${extensions_all})
|
||||
foreach(cert ${failed_certs})
|
||||
add_test(NAME "verify_ts_${cert}_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-CRLfile" "${CERTS}/CACertCRL.pem"
|
||||
"-ignore-cdp"
|
||||
"-TSA-CAfile" "${CERTS}/TSACA.pem"
|
||||
"-in" "${FILES}/ts_${cert}.${ext}")
|
||||
set_tests_properties("verify_ts_${cert}_${ext}" PROPERTIES
|
||||
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
|
||||
DEPENDS "sign_ts_${cert}_${ext}"
|
||||
WILL_FAIL TRUE)
|
||||
list(APPEND ALL_TESTS "verify_ts_${cert}_${ext}")
|
||||
endforeach(cert ${failed_certs})
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
# Verify with revoked certificate contains X509v3 CRL Distribution Points extension
|
||||
# Check X509v3 CRL Distribution Points extension, don't use "-CRLfile" and "-TSA-CRLfile" options
|
||||
# This test is expected to fail
|
||||
foreach(ext ${extensions_all})
|
||||
add_test(NAME "verify_ts_revoked_crldp_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "verify"
|
||||
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
|
||||
"-CAfile" "${CERTS}/CACert.pem"
|
||||
"-TSA-CAfile" "${CERTS}/TSACA.pem"
|
||||
"-in" "${FILES}/ts_revoked.${ext}")
|
||||
set_tests_properties("verify_ts_revoked_crldp_${ext}" PROPERTIES
|
||||
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
|
||||
DEPENDS "sign_ts_revoked_${ext}"
|
||||
WILL_FAIL TRUE)
|
||||
list(APPEND ALL_TESTS "verify_ts_revoked_crldp_${ext}")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
### Cleanup ###
|
||||
# Stop HTTP server
|
||||
if(STOP_SERVER)
|
||||
add_test(NAME "stop_server"
|
||||
COMMAND ${Python3_EXECUTABLE} "${TEST_DIR}/client_http.py")
|
||||
set_tests_properties("stop_server" PROPERTIES
|
||||
DEPENDS "${ALL_TESTS}")
|
||||
list(APPEND ALL_TESTS "stop_server")
|
||||
else(STOP_SERVER)
|
||||
message(STATUS "Keep HTTP server after tests")
|
||||
endif(STOP_SERVER)
|
||||
|
||||
else(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0" OR CURL_FOUND)
|
||||
message(STATUS "CTest skips some tests")
|
||||
endif(OPENSSL_VERSION VERSION_GREATER_EQUAL "3.0.0" OR CURL_FOUND)
|
||||
|
||||
# Delete test files
|
||||
set(names "signed" "nested" "revoked" "removed" "added")
|
||||
foreach(ext ${extensions_all})
|
||||
foreach(name ${names})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${name}.${ext}")
|
||||
endforeach(name ${names})
|
||||
foreach(cert ${pem_certs})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/ts_${cert}.${ext}")
|
||||
endforeach(cert ${pem_certs})
|
||||
foreach(format ${formats})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${ext}.${format}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${ext}.${format}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/attached_${format}.${ext}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/data_${ext}.${format}")
|
||||
foreach(data_format ${formats})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/signed_data_${ext}_${format}.${data_format}")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/attached_data_${data_format}_${format}.${ext}")
|
||||
endforeach(data_format ${formats})
|
||||
endforeach(format ${formats})
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jreq.tsq")
|
||||
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jresp.tsr")
|
||||
endforeach(ext ${extensions_all})
|
||||
|
||||
add_test(NAME "remove_files"
|
||||
COMMAND ${CMAKE_COMMAND} -E rm -f ${OUTPUT_FILES})
|
||||
|
||||
set_tests_properties("remove_files" PROPERTIES
|
||||
DEPENDS "${ALL_TESTS}")
|
||||
|
||||
endif(Python3_FOUND AND NOT cryptography_error)
|
||||
|
||||
|
||||
#[[
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
vim: set ts=4 expandtab:
|
||||
]]
|
||||
|
@ -2,16 +2,25 @@ include(CheckIncludeFile)
|
||||
include(CheckFunctionExists)
|
||||
|
||||
if(UNIX)
|
||||
check_function_exists(getpass HAVE_GETPASS)
|
||||
check_include_file(termios.h HAVE_TERMIOS_H)
|
||||
check_include_file(sys/mman.h HAVE_SYS_MMAN_H)
|
||||
if(HAVE_SYS_MMAN_H)
|
||||
check_function_exists(mmap HAVE_MMAP)
|
||||
endif(HAVE_SYS_MMAN_H)
|
||||
check_function_exists(getpass HAVE_GETPASS)
|
||||
check_include_file(termios.h HAVE_TERMIOS_H)
|
||||
check_include_file(sys/mman.h HAVE_SYS_MMAN_H)
|
||||
if(HAVE_SYS_MMAN_H)
|
||||
check_function_exists(mmap HAVE_MMAP)
|
||||
endif(HAVE_SYS_MMAN_H)
|
||||
else(UNIX)
|
||||
check_include_file(windows.h HAVE_MAPVIEWOFFILE)
|
||||
check_include_file(windows.h HAVE_MAPVIEWOFFILE)
|
||||
endif(UNIX)
|
||||
|
||||
if(NOT (HAVE_MMAP OR HAVE_MAPVIEWOFFILE))
|
||||
message(FATAL_ERROR "Error: Need file mapping function to build.")
|
||||
message(FATAL_ERROR "Error: Need file mapping function to build.")
|
||||
endif(NOT (HAVE_MMAP OR HAVE_MAPVIEWOFFILE))
|
||||
|
||||
#[[
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
vim: set ts=4 expandtab:
|
||||
]]
|
||||
|
@ -1,13 +1,32 @@
|
||||
# This list describes the default variables included in the bash-completion package:
|
||||
# BASH_COMPLETION_VERSION "@VERSION@"
|
||||
# BASH_COMPLETION_PREFIX "@prefix@"
|
||||
# BASH_COMPLETION_COMPATDIR "@sysconfdir@/bash_completion.d"
|
||||
# BASH_COMPLETION_COMPLETIONSDIR "@datadir@/@PACKAGE@/completions"
|
||||
# BASH_COMPLETION_HELPERSDIR "@datadir@/@PACKAGE@/helpers"
|
||||
# BASH_COMPLETION_FOUND "TRUE"
|
||||
# https://github.com/scop/bash-completion/blob/master/bash-completion-config.cmake.in
|
||||
|
||||
if(NOT MSVC)
|
||||
find_package(bash-completion QUIET)
|
||||
if(NOT BASH_COMPLETION_COMPLETIONSDIR)
|
||||
if(BASH_COMPLETION_COMPATDIR)
|
||||
set(BASH_COMPLETION_COMPLETIONSDIR ${BASH_COMPLETION_COMPATDIR})
|
||||
else()
|
||||
set(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share")
|
||||
set(BASH_COMPLETION_COMPLETIONSDIR "${SHAREDIR}/bash-completion/completions")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "Using bash completions dir ${BASH_COMPLETION_COMPLETIONSDIR}")
|
||||
install(FILES "osslsigncode.bash" DESTINATION ${BASH_COMPLETION_COMPLETIONSDIR})
|
||||
endif()
|
||||
if(BASH_COMPLETION_USER_DIR)
|
||||
set(BASH_COMPLETION_COMPLETIONSDIR "${BASH_COMPLETION_USER_DIR}/bash-completion/completions")
|
||||
else(BASH_COMPLETION_USER_DIR)
|
||||
find_package(bash-completion QUIET)
|
||||
if(NOT BASH_COMPLETION_FOUND)
|
||||
set(SHAREDIR "${CMAKE_INSTALL_PREFIX}/share")
|
||||
set(BASH_COMPLETION_COMPLETIONSDIR "${SHAREDIR}/bash-completion/completions")
|
||||
endif(NOT BASH_COMPLETION_FOUND)
|
||||
endif(BASH_COMPLETION_USER_DIR)
|
||||
|
||||
message(STATUS "Using bash completions dir ${BASH_COMPLETION_COMPLETIONSDIR}")
|
||||
install(FILES "osslsigncode.bash" DESTINATION ${BASH_COMPLETION_COMPLETIONSDIR})
|
||||
endif(NOT MSVC)
|
||||
|
||||
#[[
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
vim: set ts=4 expandtab:
|
||||
]]
|
||||
|
@ -3,111 +3,121 @@ include(CheckCCompilerFlag)
|
||||
set(CMAKE_REQUIRED_QUIET ON)
|
||||
|
||||
function(add_debug_flag_if_supported flagname targets)
|
||||
check_c_compiler_flag("${flagname}" HAVE_FLAG_${flagname})
|
||||
if (HAVE_FLAG_${flagname})
|
||||
foreach(target ${targets})
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:DEBUG>:${flagname}>)
|
||||
endforeach()
|
||||
endif()
|
||||
endfunction()
|
||||
check_c_compiler_flag("${flagname}" HAVE_FLAG_${flagname})
|
||||
if (HAVE_FLAG_${flagname})
|
||||
foreach(target ${targets})
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:DEBUG>:${flagname}>)
|
||||
endforeach(target ${targets})
|
||||
endif(HAVE_FLAG_${flagname})
|
||||
endfunction(add_debug_flag_if_supported flagname targets)
|
||||
|
||||
function(add_compile_flag_to_targets targets)
|
||||
set(CHECKED_DEBUG_FLAGS
|
||||
"-ggdb"
|
||||
"-g"
|
||||
"-O2"
|
||||
"-pedantic"
|
||||
"-Wall"
|
||||
"-Wextra"
|
||||
"-Wno-long-long"
|
||||
"-Wconversion"
|
||||
"-D_FORTIFY_SOURCE=2"
|
||||
"-Wformat=2"
|
||||
"-Wredundant-decls"
|
||||
"-Wcast-qual"
|
||||
"-Wnull-dereference"
|
||||
"-Wno-deprecated-declarations"
|
||||
"-Wmissing-declarations"
|
||||
"-Wmissing-prototypes"
|
||||
"-Wmissing-noreturn"
|
||||
"-Wmissing-braces"
|
||||
"-Wparentheses"
|
||||
"-Wstrict-aliasing=3"
|
||||
"-Wstrict-overflow=2"
|
||||
"-Wlogical-op"
|
||||
"-Wwrite-strings"
|
||||
"-Wcast-align=strict"
|
||||
"-Wdisabled-optimization"
|
||||
"-Wshift-overflow=2"
|
||||
"-Wundef"
|
||||
"-Wshadow"
|
||||
"-Wmisleading-indentation"
|
||||
"-Wabsolute-value"
|
||||
"-Wunused-parameter"
|
||||
"-Wunused-function"
|
||||
)
|
||||
foreach(flag ${CHECKED_DEBUG_FLAGS})
|
||||
add_debug_flag_if_supported(${flag} ${targets})
|
||||
endforeach()
|
||||
endfunction()
|
||||
set(CHECKED_DEBUG_FLAGS
|
||||
"-ggdb"
|
||||
"-g"
|
||||
"-O2"
|
||||
"-pedantic"
|
||||
"-Wall"
|
||||
"-Wextra"
|
||||
"-Wno-long-long"
|
||||
"-Wconversion"
|
||||
"-D_FORTIFY_SOURCE=2"
|
||||
"-Wformat=2"
|
||||
"-Wredundant-decls"
|
||||
"-Wcast-qual"
|
||||
"-Wnull-dereference"
|
||||
"-Wno-deprecated-declarations"
|
||||
"-Wmissing-declarations"
|
||||
"-Wmissing-prototypes"
|
||||
"-Wmissing-noreturn"
|
||||
"-Wmissing-braces"
|
||||
"-Wparentheses"
|
||||
"-Wstrict-aliasing=3"
|
||||
"-Wstrict-overflow=2"
|
||||
"-Wlogical-op"
|
||||
"-Wwrite-strings"
|
||||
"-Wcast-align=strict"
|
||||
"-Wdisabled-optimization"
|
||||
"-Wshift-overflow=2"
|
||||
"-Wundef"
|
||||
"-Wshadow"
|
||||
"-Wmisleading-indentation"
|
||||
"-Wabsolute-value"
|
||||
"-Wunused-parameter"
|
||||
"-Wunused-function")
|
||||
foreach(flag ${CHECKED_DEBUG_FLAGS})
|
||||
add_debug_flag_if_supported(${flag} ${targets})
|
||||
endforeach(flag ${CHECKED_DEBUG_FLAGS})
|
||||
endfunction(add_compile_flag_to_targets targets)
|
||||
|
||||
function(add_compile_flags target)
|
||||
if(MSVC)
|
||||
# Enable parallel builds
|
||||
target_compile_options(${target} PRIVATE /MP)
|
||||
# Use address space layout randomization, generate PIE code for ASLR (default on)
|
||||
target_link_options(${target} PRIVATE /DYNAMICBASE)
|
||||
# Create terminal server aware application (default on)
|
||||
target_link_options(${target} PRIVATE /TSAWARE)
|
||||
# Mark the binary as compatible with Intel Control-flow Enforcement Technology (CET) Shadow Stack
|
||||
target_link_options(${target} PRIVATE /CETCOMPAT)
|
||||
# Enable compiler generation of Control Flow Guard security checks
|
||||
target_compile_options(${target} PRIVATE /guard:cf)
|
||||
target_link_options(${target} PRIVATE /guard:cf)
|
||||
# Buffer Security Check
|
||||
target_compile_options(${target} PRIVATE /GS)
|
||||
# Suppress startup banner
|
||||
target_link_options(${target} PRIVATE /NOLOGO)
|
||||
# Generate debug info
|
||||
target_link_options(${target} PRIVATE /DEBUG)
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
# High entropy ASLR for 64 bits targets (default on)
|
||||
target_link_options(${target} PRIVATE /HIGHENTROPYVA)
|
||||
# Enable generation of EH Continuation (EHCONT) metadata by the compiler
|
||||
#target_compile_options(${target} PRIVATE /guard:ehcont)
|
||||
#target_link_options(${target} PRIVATE /guard:ehcont)
|
||||
else()
|
||||
# Can handle addresses larger than 2 gigabytes
|
||||
target_link_options(${target} PRIVATE /LARGEADDRESSAWARE)
|
||||
# Safe structured exception handlers (x86 only)
|
||||
target_link_options(${target} PRIVATE /SAFESEH)
|
||||
endif()
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:DEBUG>:/D_FORTIFY_SOURCE=2>)
|
||||
# Unrecognized compiler options are errors
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:DEBUG>:/options:strict>)
|
||||
else(MSVC)
|
||||
check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
|
||||
if(HAVE_STACK_PROTECTOR_ALL)
|
||||
target_link_options(${target} PRIVATE -fstack-protector-all)
|
||||
else()
|
||||
check_c_compiler_flag("-fstack-protector" HAVE_STACK_PROTECTOR)
|
||||
if(HAVE_STACK_PROTECTOR)
|
||||
target_link_options(${target} PRIVATE -fstack-protector)
|
||||
else()
|
||||
message(WARNING "No stack protection supported")
|
||||
endif()
|
||||
endif()
|
||||
# Support address space layout randomization (ASLR)
|
||||
if(NOT (MINGW OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
|
||||
target_compile_options(${target} PRIVATE -fPIE)
|
||||
target_link_options(${target} PRIVATE -fPIE -pie)
|
||||
target_link_options(${target} PRIVATE -Wl,-z,relro)
|
||||
target_link_options(${target} PRIVATE -Wl,-z,now)
|
||||
target_link_options(${target} PRIVATE -Wl,-z,noexecstack)
|
||||
endif(NOT (MINGW OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"))
|
||||
target_link_options(${target} PRIVATE -fstack-check)
|
||||
add_compile_flag_to_targets(${target})
|
||||
endif(MSVC)
|
||||
endfunction()
|
||||
if(MSVC)
|
||||
# Enable parallel builds
|
||||
target_compile_options(${target} PRIVATE /MP)
|
||||
# Use address space layout randomization, generate PIE code for ASLR (default on)
|
||||
target_link_options(${target} PRIVATE /DYNAMICBASE)
|
||||
# Create terminal server aware application (default on)
|
||||
target_link_options(${target} PRIVATE /TSAWARE)
|
||||
# Mark the binary as compatible with Intel Control-flow Enforcement Technology (CET) Shadow Stack
|
||||
target_link_options(${target} PRIVATE /CETCOMPAT)
|
||||
# Enable compiler generation of Control Flow Guard security checks
|
||||
target_compile_options(${target} PRIVATE /guard:cf)
|
||||
target_link_options(${target} PRIVATE /guard:cf)
|
||||
# Buffer Security Check
|
||||
target_compile_options(${target} PRIVATE /GS)
|
||||
# Suppress startup banner
|
||||
target_link_options(${target} PRIVATE /NOLOGO)
|
||||
# Generate debug info
|
||||
target_link_options(${target} PRIVATE /DEBUG)
|
||||
if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
# High entropy ASLR for 64 bits targets (default on)
|
||||
target_link_options(${target} PRIVATE /HIGHENTROPYVA)
|
||||
# Enable generation of EH Continuation (EHCONT) metadata by the compiler
|
||||
#target_compile_options(${target} PRIVATE /guard:ehcont)
|
||||
#target_link_options(${target} PRIVATE /guard:ehcont)
|
||||
else("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
# Can handle addresses larger than 2 gigabytes
|
||||
target_link_options(${target} PRIVATE /LARGEADDRESSAWARE)
|
||||
# Safe structured exception handlers (x86 only)
|
||||
target_link_options(${target} PRIVATE /SAFESEH)
|
||||
endif("${CMAKE_SIZEOF_VOID_P}" STREQUAL "8")
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:DEBUG>:/D_FORTIFY_SOURCE=2>)
|
||||
# Unrecognized compiler options are errors
|
||||
target_compile_options(${target} PRIVATE $<$<CONFIG:DEBUG>:/options:strict>)
|
||||
else(MSVC)
|
||||
check_c_compiler_flag("-fstack-protector-all" HAVE_STACK_PROTECTOR_ALL)
|
||||
if(HAVE_STACK_PROTECTOR_ALL)
|
||||
target_link_options(${target} PRIVATE -fstack-protector-all)
|
||||
else(HAVE_STACK_PROTECTOR_ALL)
|
||||
check_c_compiler_flag("-fstack-protector" HAVE_STACK_PROTECTOR)
|
||||
if(HAVE_STACK_PROTECTOR)
|
||||
target_link_options(${target} PRIVATE -fstack-protector)
|
||||
else(HAVE_STACK_PROTECTOR)
|
||||
message(WARNING "No stack protection supported")
|
||||
endif(HAVE_STACK_PROTECTOR)
|
||||
endif(HAVE_STACK_PROTECTOR_ALL)
|
||||
# Support address space layout randomization (ASLR)
|
||||
if(NOT (MINGW OR CYGWIN OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
|
||||
OR ((CMAKE_SYSTEM_NAME MATCHES Darwin) AND (CMAKE_C_COMPILER_ID MATCHES Clang))))
|
||||
target_compile_options(${target} PRIVATE -fPIE)
|
||||
target_link_options(${target} PRIVATE -fPIE -pie)
|
||||
target_link_options(${target} PRIVATE -Wl,-z,relro)
|
||||
target_link_options(${target} PRIVATE -Wl,-z,now)
|
||||
target_link_options(${target} PRIVATE -Wl,-z,noexecstack)
|
||||
endif(NOT (MINGW OR CYGWIN OR CMAKE_C_COMPILER_ID STREQUAL "AppleClang"
|
||||
OR ((CMAKE_SYSTEM_NAME MATCHES Darwin) AND (CMAKE_C_COMPILER_ID MATCHES Clang))))
|
||||
target_link_options(${target} PRIVATE -fstack-check)
|
||||
add_compile_flag_to_targets(${target})
|
||||
endif(MSVC)
|
||||
endfunction(add_compile_flags target)
|
||||
|
||||
add_compile_flags(osslsigncode)
|
||||
|
||||
#[[
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
vim: set ts=4 expandtab:
|
||||
]]
|
||||
|
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)
|
807
helpers.c
Normal file
807
helpers.c
Normal file
@ -0,0 +1,807 @@
|
||||
/*
|
||||
* osslsigncode support library
|
||||
*
|
||||
* Copyright (C) 2021-2023 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
||||
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
|
||||
*/
|
||||
|
||||
#include "osslsigncode.h"
|
||||
#include "helpers.h"
|
||||
|
||||
/* Prototypes */
|
||||
static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx);
|
||||
static int spc_indirect_data_content_create(u_char **blob, 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_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_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
|
||||
*/
|
||||
|
||||
/*
|
||||
* [in] infile
|
||||
* [returns] file size
|
||||
*/
|
||||
uint32_t get_file_size(const char *infile)
|
||||
{
|
||||
int ret;
|
||||
#ifdef _WIN32
|
||||
struct _stat64 st;
|
||||
ret = _stat64(infile, &st);
|
||||
#else
|
||||
struct stat st;
|
||||
ret = stat(infile, &st);
|
||||
#endif
|
||||
if (ret) {
|
||||
fprintf(stderr, "Failed to open file: %s\n", infile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (st.st_size < 4) {
|
||||
fprintf(stderr, "Unrecognized file type - file is too short: %s\n", infile);
|
||||
return 0;
|
||||
}
|
||||
if (st.st_size > UINT32_MAX) {
|
||||
fprintf(stderr, "Unsupported file - too large: %s\n", infile);
|
||||
return 0;
|
||||
}
|
||||
return (uint32_t)st.st_size;
|
||||
}
|
||||
|
||||
/*
|
||||
* [in] infile: starting address for the new mapping
|
||||
* [returns] pointer to the mapped area
|
||||
*/
|
||||
char *map_file(const char *infile, const size_t size)
|
||||
{
|
||||
char *indata = NULL;
|
||||
#ifdef WIN32
|
||||
HANDLE fhandle, fmap;
|
||||
(void)size;
|
||||
fhandle = CreateFile(infile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
|
||||
if (fhandle == INVALID_HANDLE_VALUE) {
|
||||
return NULL;
|
||||
}
|
||||
fmap = CreateFileMapping(fhandle, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
CloseHandle(fhandle);
|
||||
if (fmap == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
indata = (char *)MapViewOfFile(fmap, FILE_MAP_READ, 0, 0, 0);
|
||||
CloseHandle(fmap);
|
||||
#else
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
int fd = open(infile, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
return NULL;
|
||||
}
|
||||
indata = mmap(0, size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
if (indata == MAP_FAILED) {
|
||||
close(fd);
|
||||
return NULL;
|
||||
}
|
||||
close(fd);
|
||||
#else
|
||||
fprintf(stderr, "No file mapping function\n");
|
||||
return NULL;
|
||||
#endif /* HAVE_SYS_MMAN_H */
|
||||
#endif /* WIN32 */
|
||||
return indata;
|
||||
}
|
||||
|
||||
/*
|
||||
* [in] indata: starting address space
|
||||
* [in] size: mapped area length
|
||||
* [returns] none
|
||||
*/
|
||||
void unmap_file(char *indata, const size_t size)
|
||||
{
|
||||
if (!indata)
|
||||
return;
|
||||
#ifdef WIN32
|
||||
(void)size;
|
||||
UnmapViewOfFile(indata);
|
||||
#else
|
||||
munmap(indata, size);
|
||||
#endif /* WIN32 */
|
||||
}
|
||||
|
||||
/*
|
||||
* Retrieve a decoded PKCS#7 structure
|
||||
* [in] data: encoded PEM or DER data
|
||||
* [in] size: data size
|
||||
* [returns] pointer to PKCS#7 structure
|
||||
*/
|
||||
PKCS7 *pkcs7_read_data(char *data, uint32_t size)
|
||||
{
|
||||
PKCS7 *p7 = NULL;
|
||||
BIO *bio;
|
||||
const char pemhdr[] = "-----BEGIN PKCS7-----";
|
||||
|
||||
bio = BIO_new_mem_buf(data, (int)size);
|
||||
if (size >= sizeof pemhdr && !memcmp(data, pemhdr, sizeof pemhdr - 1)) {
|
||||
/* PEM format */
|
||||
p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
|
||||
} else { /* DER format */
|
||||
p7 = d2i_PKCS7_bio(bio, NULL);
|
||||
}
|
||||
BIO_free_all(bio);
|
||||
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
|
||||
* [in] ctx: structure holds input and output data
|
||||
* [returns] pointer to PKCS#7 structure
|
||||
*/
|
||||
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
|
||||
{
|
||||
int i, signer = -1;
|
||||
PKCS7 *p7;
|
||||
PKCS7_SIGNER_INFO *si = NULL;
|
||||
STACK_OF(X509) *chain = NULL;
|
||||
|
||||
p7 = PKCS7_new();
|
||||
PKCS7_set_type(p7, NID_pkcs7_signed);
|
||||
PKCS7_content_new(p7, NID_pkcs7_data);
|
||||
if (ctx->options->cert != NULL) {
|
||||
/*
|
||||
* the private key and corresponding certificate are parsed from the PKCS12
|
||||
* structure or loaded from the security token, so we may omit to check
|
||||
* the consistency of a private key with the public key in an X509 certificate
|
||||
*/
|
||||
si = PKCS7_add_signature(p7, ctx->options->cert, ctx->options->pkey,
|
||||
ctx->options->md);
|
||||
if (si == NULL)
|
||||
return NULL; /* FAILED */
|
||||
} else {
|
||||
/* find the signer's certificate located somewhere in the whole certificate chain */
|
||||
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
||||
X509 *signcert = sk_X509_value(ctx->options->certs, i);
|
||||
if (X509_check_private_key(signcert, ctx->options->pkey)) {
|
||||
si = PKCS7_add_signature(p7, signcert, ctx->options->pkey, ctx->options->md);
|
||||
signer = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (si == NULL) {
|
||||
fprintf(stderr, "Failed to checking the consistency of a private key: %s\n",
|
||||
ctx->options->keyfile);
|
||||
fprintf(stderr, " with a public key in any X509 certificate: %s\n\n",
|
||||
ctx->options->certfile);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
}
|
||||
if (!pkcs7_signer_info_add_signing_time(si, ctx)) {
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
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)) {
|
||||
fprintf(stderr, "Couldn't allocate memory for opus info\n");
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if ((ctx->options->nested_number >= 0) &&
|
||||
!pkcs7_signer_info_add_sequence_number(si, ctx)) {
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
/* create X509 chain sorted in ascending order by their DER encoding */
|
||||
chain = X509_chain_get_sorted(ctx, signer);
|
||||
if (chain == NULL) {
|
||||
fprintf(stderr, "Failed to create a sorted certificate chain\n");
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
/* add sorted certificate chain */
|
||||
for (i=0; i<sk_X509_num(chain); i++) {
|
||||
PKCS7_add_certificate(p7, sk_X509_value(chain, i));
|
||||
}
|
||||
/* add crls */
|
||||
if (ctx->options->crls) {
|
||||
for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++)
|
||||
PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i));
|
||||
}
|
||||
sk_X509_free(chain);
|
||||
return p7; /* OK */
|
||||
}
|
||||
|
||||
/*
|
||||
* 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
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
int add_indirect_data_object(PKCS7 *p7)
|
||||
{
|
||||
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||
PKCS7_SIGNER_INFO *si;
|
||||
|
||||
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(SPC_INDIRECT_DATA_OBJID, 1)))
|
||||
return 0; /* FAILED */
|
||||
return 1; /* OK */
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 1; /* OK */
|
||||
}
|
||||
|
||||
/*
|
||||
* Add encapsulated content to signed PKCS7 structure.
|
||||
* [in] content: spcIndirectDataContent
|
||||
* [returns] new PKCS#7 signature with encapsulated content
|
||||
*/
|
||||
PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content)
|
||||
{
|
||||
PKCS7 *p7, *td7;
|
||||
|
||||
p7 = PKCS7_new();
|
||||
if (!p7) {
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
ASN1_OCTET_STRING *content;
|
||||
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
|
||||
int mdlen, hashlen, len = 0;
|
||||
u_char *data, *p = NULL;
|
||||
|
||||
content = ASN1_OCTET_STRING_new();
|
||||
if (!content) {
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 */
|
||||
}
|
||||
BIO_write(p7bio, data, len);
|
||||
(void)BIO_flush(p7bio);
|
||||
if (!PKCS7_dataFinal(p7, p7bio)) {
|
||||
fprintf(stderr, "PKCS7_dataFinal failed\n");
|
||||
BIO_free_all(p7bio);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
BIO_free_all(p7bio);
|
||||
return 1; /* OK */
|
||||
}
|
||||
|
||||
/* Return the header length (tag and length octets) of the ASN.1 type
|
||||
* [in] p: ASN.1 data
|
||||
* [in] len: ASN.1 data length
|
||||
* [returns] header length
|
||||
*/
|
||||
int asn1_simple_hdr_len(const u_char *p, int len)
|
||||
{
|
||||
if (len <= 2 || p[0] > 0x31)
|
||||
return 0;
|
||||
return (p[1]&0x80) ? (2 + (p[1]&0x7f)) : 2;
|
||||
}
|
||||
|
||||
/*
|
||||
* [in, out] hash: BIO with message digest method
|
||||
* [in] indata: starting address space
|
||||
* [in] idx: offset
|
||||
* [in] fileend: the length of the hashed area
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
int bio_hash_data(BIO *hash, char *indata, size_t idx, size_t fileend)
|
||||
{
|
||||
while (idx < fileend) {
|
||||
size_t want, written;
|
||||
want = fileend - idx;
|
||||
if (want > SIZE_64K)
|
||||
want = SIZE_64K;
|
||||
if (!BIO_write_ex(hash, indata + idx, want, &written))
|
||||
return 0; /* FAILED */
|
||||
idx += written;
|
||||
}
|
||||
return 1; /* OK */
|
||||
}
|
||||
|
||||
/*
|
||||
* [in] descript1, descript2: descriptions
|
||||
* [in] mdbuf: message digest
|
||||
* [in] len: message digest length
|
||||
* [returns] none
|
||||
*/
|
||||
void print_hash(const char *descript1, const char *descript2, const u_char *mdbuf, int len)
|
||||
{
|
||||
char *hexbuf = NULL;
|
||||
int size, i, j = 0;
|
||||
|
||||
size = 2 * len + 1;
|
||||
hexbuf = OPENSSL_malloc((size_t)size);
|
||||
for (i = 0; i < len; i++) {
|
||||
#ifdef WIN32
|
||||
j += sprintf_s(hexbuf + j, size - j, "%02X", mdbuf[i]);
|
||||
#else
|
||||
j += sprintf(hexbuf + j, "%02X", mdbuf[i]);
|
||||
#endif /* WIN32 */
|
||||
}
|
||||
printf("%s: %s %s\n", descript1, hexbuf, descript2);
|
||||
OPENSSL_free(hexbuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* [in] p7: new PKCS#7 signature
|
||||
* [in] objid: Microsoft OID Authenticode
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
int is_content_type(PKCS7 *p7, const char *objid)
|
||||
{
|
||||
ASN1_OBJECT *indir_objid;
|
||||
int ret;
|
||||
|
||||
indir_objid = OBJ_txt2obj(objid, 1);
|
||||
ret = p7 && PKCS7_type_is_signed(p7) &&
|
||||
!OBJ_cmp(p7->d.sign->contents->type, indir_objid) &&
|
||||
(p7->d.sign->contents->d.other->type == V_ASN1_SEQUENCE ||
|
||||
p7->d.sign->contents->d.other->type == V_ASN1_OCTET_STRING);
|
||||
ASN1_OBJECT_free(indir_objid);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* [in] p7: new PKCS#7 signature
|
||||
* [returns] pointer to MsCtlContent structure
|
||||
*/
|
||||
MsCtlContent *ms_ctl_content_get(PKCS7 *p7)
|
||||
{
|
||||
ASN1_STRING *value;
|
||||
const u_char *data;
|
||||
|
||||
if (!is_content_type(p7, MS_CTL_OBJID)) {
|
||||
fprintf(stderr, "Failed to find MS_CTL_OBJID\n");
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
value = p7->d.sign->contents->d.other->value.sequence;
|
||||
data = ASN1_STRING_get0_data(value);
|
||||
return d2i_MsCtlContent(NULL, &data, ASN1_STRING_length(value));
|
||||
}
|
||||
|
||||
/*
|
||||
* [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;
|
||||
}
|
||||
|
||||
/*
|
||||
* PE and CAB format specific
|
||||
* [in] none
|
||||
* [returns] pointer to SpcLink
|
||||
*/
|
||||
SpcLink *spc_link_obsolete_get(void)
|
||||
{
|
||||
const u_char obsolete[] = {
|
||||
0x00, 0x3c, 0x00, 0x3c, 0x00, 0x3c, 0x00, 0x4f,
|
||||
0x00, 0x62, 0x00, 0x73, 0x00, 0x6f, 0x00, 0x6c,
|
||||
0x00, 0x65, 0x00, 0x74, 0x00, 0x65, 0x00, 0x3e,
|
||||
0x00, 0x3e, 0x00, 0x3e
|
||||
};
|
||||
SpcLink *link = SpcLink_new();
|
||||
link->type = 2;
|
||||
link->value.file = SpcString_new();
|
||||
link->value.file->type = 0;
|
||||
link->value.file->value.unicode = ASN1_BMPSTRING_new();
|
||||
ASN1_STRING_set(link->value.file->value.unicode, obsolete, sizeof obsolete);
|
||||
return link;
|
||||
}
|
||||
|
||||
/*
|
||||
* [in] mdbuf, cmdbuf: message digests
|
||||
* [in] mdtype: message digest algorithm type
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype)
|
||||
{
|
||||
int mdlen = EVP_MD_size(EVP_get_digestbynid(mdtype));
|
||||
int mdok = !memcmp(mdbuf, cmdbuf, (size_t)mdlen);
|
||||
printf("Message digest algorithm : %s\n", OBJ_nid2sn(mdtype));
|
||||
print_hash("Current message digest ", "", mdbuf, mdlen);
|
||||
print_hash("Calculated message digest ", mdok ? "\n" : " MISMATCH!!!\n", cmdbuf, mdlen);
|
||||
return mdok;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper functions
|
||||
*/
|
||||
|
||||
/*
|
||||
* [in] ctx: FILE_FORMAT_CTX structure
|
||||
* [returns] pointer to SpcSpOpusInfo structure
|
||||
*/
|
||||
static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx)
|
||||
{
|
||||
SpcSpOpusInfo *info = SpcSpOpusInfo_new();
|
||||
|
||||
if (ctx->options->desc) {
|
||||
info->programName = SpcString_new();
|
||||
info->programName->type = 1;
|
||||
info->programName->value.ascii = ASN1_IA5STRING_new();
|
||||
ASN1_STRING_set((ASN1_STRING *)info->programName->value.ascii,
|
||||
ctx->options->desc, (int)strlen(ctx->options->desc));
|
||||
}
|
||||
if (ctx->options->url) {
|
||||
info->moreInfo = SpcLink_new();
|
||||
info->moreInfo->type = 0;
|
||||
info->moreInfo->value.url = ASN1_IA5STRING_new();
|
||||
ASN1_STRING_set((ASN1_STRING *)info->moreInfo->value.url,
|
||||
ctx->options->url, (int)strlen(ctx->options->url));
|
||||
}
|
||||
return info;
|
||||
}
|
||||
|
||||
/*
|
||||
* [out] blob: SpcIndirectDataContent data
|
||||
* [out] len: SpcIndirectDataContent data length
|
||||
* [in] ctx: FILE_FORMAT_CTX structure
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx)
|
||||
{
|
||||
u_char *p = NULL;
|
||||
int mdtype, hashlen, l = 0;
|
||||
void *hash;
|
||||
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->type = V_ASN1_SEQUENCE;
|
||||
idc->data->value->value.sequence = ASN1_STRING_new();
|
||||
idc->data->type = ctx->format->data_blob_get(&p, &l, ctx);
|
||||
idc->data->value->value.sequence->data = p;
|
||||
idc->data->value->value.sequence->length = l;
|
||||
idc->messageDigest->digestAlgorithm->algorithm = OBJ_nid2obj(mdtype);
|
||||
idc->messageDigest->digestAlgorithm->parameters = ASN1_TYPE_new();
|
||||
idc->messageDigest->digestAlgorithm->parameters->type = V_ASN1_NULL;
|
||||
|
||||
hashlen = ctx->format->hash_length_get(ctx);
|
||||
hash = OPENSSL_zalloc((size_t)hashlen);
|
||||
ASN1_OCTET_STRING_set(idc->messageDigest->digest, hash, hashlen);
|
||||
OPENSSL_free(hash);
|
||||
|
||||
*len = i2d_SpcIndirectDataContent(idc, NULL);
|
||||
*blob = OPENSSL_malloc((size_t)*len);
|
||||
p = *blob;
|
||||
i2d_SpcIndirectDataContent(idc, &p);
|
||||
SpcIndirectDataContent_free(idc);
|
||||
*len -= hashlen;
|
||||
return 1; /* OK */
|
||||
}
|
||||
|
||||
/*
|
||||
* [in, out] si: PKCS7_SIGNER_INFO structure
|
||||
* [in] ctx: FILE_FORMAT_CTX structure
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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 {
|
||||
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);
|
||||
}
|
||||
|
||||
/*
|
||||
* [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 PKCS7_add_signed_attribute(si, OBJ_txt2nid(PKCS9_SEQUENCE_NUMBER),
|
||||
V_ASN1_INTEGER, number);
|
||||
}
|
||||
|
||||
/*
|
||||
* Create certificate chain sorted in ascending order by their DER encoding.
|
||||
* [in] ctx: structure holds input and output data
|
||||
* [in] signer: signer's certificate number in the certificate chain
|
||||
* [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);
|
||||
|
||||
/* add the signer's certificate */
|
||||
if (ctx->options->cert != NULL && !sk_X509_push(chain, ctx->options->cert)) {
|
||||
sk_X509_free(chain);
|
||||
return NULL;
|
||||
}
|
||||
if (signer != -1 && !sk_X509_push(chain, sk_X509_value(ctx->options->certs, signer))) {
|
||||
sk_X509_free(chain);
|
||||
return NULL;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
|
||||
vim: set ts=4 expandtab:
|
||||
*/
|
37
helpers.h
Normal file
37
helpers.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* osslsigncode support library
|
||||
*
|
||||
* Copyright (C) 2021-2023 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
||||
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
|
||||
*/
|
||||
|
||||
/* Common functions */
|
||||
uint32_t get_file_size(const char *infile);
|
||||
char *map_file(const char *infile, const size_t size);
|
||||
void unmap_file(char *indata, const size_t size);
|
||||
PKCS7 *pkcs7_read_data(char *indata, uint32_t size);
|
||||
int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
|
||||
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx);
|
||||
int add_indirect_data_object(PKCS7 *p7);
|
||||
int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content);
|
||||
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 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);
|
||||
int is_content_type(PKCS7 *p7, const char *objid);
|
||||
MsCtlContent *ms_ctl_content_get(PKCS7 *p7);
|
||||
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute);
|
||||
SpcLink *spc_link_obsolete_get(void);
|
||||
int compare_digests(u_char *mdbuf, u_char *cmdbuf, int mdtype);
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
|
||||
vim: set ts=4 expandtab:
|
||||
*/
|
238
msi.h
238
msi.h
@ -1,238 +0,0 @@
|
||||
/*
|
||||
* MSI file support library
|
||||
*
|
||||
* Copyright (C) 2021 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
||||
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
|
||||
*
|
||||
* Reference specifications:
|
||||
* http://en.wikipedia.org/wiki/Compound_File_Binary_Format
|
||||
* https://msdn.microsoft.com/en-us/library/dd942138.aspx
|
||||
* https://github.com/microsoft/compoundfilereader
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <openssl/safestack.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/crypto.h>
|
||||
#include <openssl/evp.h>
|
||||
|
||||
#define MAXREGSECT 0xfffffffa /* maximum regular sector number */
|
||||
#define DIFSECT 0xfffffffc /* specifies a DIFAT sector in the FAT */
|
||||
#define FATSECT 0xfffffffd /* specifies a FAT sector in the FAT */
|
||||
#define ENDOFCHAIN 0xfffffffe /* end of a linked chain of sectors */
|
||||
#define NOSTREAM 0xffffffff /* terminator or empty pointer */
|
||||
#define FREESECT 0xffffffff /* empty unallocated free sectors */
|
||||
|
||||
#define DIR_UNKNOWN 0
|
||||
#define DIR_STORAGE 1
|
||||
#define DIR_STREAM 2
|
||||
#define DIR_ROOT 5
|
||||
|
||||
#define RED_COLOR 0
|
||||
#define BLACK_COLOR 1
|
||||
|
||||
#define DIFAT_IN_HEADER 109
|
||||
#define MINI_STREAM_CUTOFF_SIZE 0x00001000 /* 4096 bytes */
|
||||
#define HEADER_SIZE 0x200 /* 512 bytes, independent of sector size */
|
||||
#define MAX_SECTOR_SIZE 0x1000 /* 4096 bytes */
|
||||
|
||||
#define HEADER_SIGNATURE 0x00 /* 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 */
|
||||
#define HEADER_CLSID 0x08 /* reserved and unused */
|
||||
#define HEADER_MINOR_VER 0x18 /* SHOULD be set to 0x003E */
|
||||
#define HEADER_MAJOR_VER 0x1a /* MUST be set to either 0x0003 (version 3) or 0x0004 (version 4) */
|
||||
#define HEADER_BYTE_ORDER 0x1c /* 0xfe 0xff == Intel Little Endian */
|
||||
#define HEADER_SECTOR_SHIFT 0x1e /* MUST be set to 0x0009, or 0x000c */
|
||||
#define HEADER_MINI_SECTOR_SHIFT 0x20 /* MUST be set to 0x0006 */
|
||||
#define RESERVED 0x22 /* reserved and unused */
|
||||
#define HEADER_DIR_SECTORS_NUM 0x28
|
||||
#define HEADER_FAT_SECTORS_NUM 0x2c
|
||||
#define HEADER_DIR_SECTOR_LOC 0x30
|
||||
#define HEADER_TRANSACTION 0x34
|
||||
#define HEADER_MINI_STREAM_CUTOFF 0x38 /* 4096 bytes */
|
||||
#define HEADER_MINI_FAT_SECTOR_LOC 0x3c
|
||||
#define HEADER_MINI_FAT_SECTORS_NUM 0x40
|
||||
#define HEADER_DIFAT_SECTOR_LOC 0x44
|
||||
#define HEADER_DIFAT_SECTORS_NUM 0x48
|
||||
#define HEADER_DIFAT 0x4c
|
||||
|
||||
#define DIRENT_SIZE 0x80 /* 128 bytes */
|
||||
#define DIRENT_MAX_NAME_SIZE 0x40 /* 64 bytes */
|
||||
|
||||
#define DIRENT_NAME 0x00
|
||||
#define DIRENT_NAME_LEN 0x40 /* length in bytes incl 0 terminator */
|
||||
#define DIRENT_TYPE 0x42
|
||||
#define DIRENT_COLOUR 0x43
|
||||
#define DIRENT_LEFT_SIBLING_ID 0x44
|
||||
#define DIRENT_RIGHT_SIBLING_ID 0x48
|
||||
#define DIRENT_CHILD_ID 0x4c
|
||||
#define DIRENT_CLSID 0x50
|
||||
#define DIRENT_STATE_BITS 0x60
|
||||
#define DIRENT_CREATE_TIME 0x64
|
||||
#define DIRENT_MODIFY_TIME 0x6c
|
||||
#define DIRENT_START_SECTOR_LOC 0x74
|
||||
#define DIRENT_FILE_SIZE 0x78
|
||||
|
||||
#define GET_UINT8_LE(p) ((const u_char *)(p))[0]
|
||||
|
||||
#define GET_UINT16_LE(p) (uint16_t)(((const u_char *)(p))[0] | \
|
||||
(((const u_char *)(p))[1] << 8))
|
||||
|
||||
#define GET_UINT32_LE(p) (uint32_t)(((const u_char *)(p))[0] | \
|
||||
(((const u_char *)(p))[1] << 8) | \
|
||||
(((const u_char *)(p))[2] << 16) | \
|
||||
(((const u_char *)(p))[3] << 24))
|
||||
|
||||
#define PUT_UINT8_LE(i, p) ((u_char *)(p))[0] = (u_char)((i) & 0xff);
|
||||
|
||||
#define PUT_UINT16_LE(i,p) ((u_char *)(p))[0] = (u_char)((i) & 0xff); \
|
||||
((u_char *)(p))[1] = (u_char)(((i) >> 8) & 0xff)
|
||||
|
||||
#define PUT_UINT32_LE(i,p) ((u_char *)(p))[0] = (u_char)((i) & 0xff); \
|
||||
((u_char *)(p))[1] = (u_char)(((i) >> 8) & 0xff); \
|
||||
((u_char *)(p))[2] = (u_char)(((i) >> 16) & 0xff); \
|
||||
((u_char *)(p))[3] = (u_char)(((i) >> 24) & 0xff)
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define SIZE_64K 65536 /* 2^16 */
|
||||
#define SIZE_16M 16777216 /* 2^24 */
|
||||
|
||||
typedef unsigned char u_char;
|
||||
|
||||
typedef struct {
|
||||
u_char signature[8]; /* 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 */
|
||||
u_char unused_clsid[16]; /* reserved and unused */
|
||||
uint16_t minorVersion;
|
||||
uint16_t majorVersion;
|
||||
uint16_t byteOrder;
|
||||
uint16_t sectorShift; /* power of 2 */
|
||||
uint16_t miniSectorShift; /* power of 2 */
|
||||
u_char reserved[6]; /* reserved and unused */
|
||||
uint32_t numDirectorySector;
|
||||
uint32_t numFATSector;
|
||||
uint32_t firstDirectorySectorLocation;
|
||||
uint32_t transactionSignatureNumber; /* reserved */
|
||||
uint32_t miniStreamCutoffSize;
|
||||
uint32_t firstMiniFATSectorLocation;
|
||||
uint32_t numMiniFATSector;
|
||||
uint32_t firstDIFATSectorLocation;
|
||||
uint32_t numDIFATSector;
|
||||
uint32_t headerDIFAT[DIFAT_IN_HEADER];
|
||||
} MSI_FILE_HDR;
|
||||
|
||||
typedef struct {
|
||||
u_char name[DIRENT_MAX_NAME_SIZE];
|
||||
uint16_t nameLen;
|
||||
uint8_t type;
|
||||
uint8_t colorFlag;
|
||||
uint32_t leftSiblingID;
|
||||
uint32_t rightSiblingID;
|
||||
uint32_t childID;
|
||||
u_char clsid[16];
|
||||
u_char stateBits[4];
|
||||
u_char creationTime[8];
|
||||
u_char modifiedTime[8];
|
||||
uint32_t startSectorLocation;
|
||||
u_char size[8];
|
||||
} MSI_ENTRY;
|
||||
|
||||
typedef struct msi_dirent_struct {
|
||||
u_char name[DIRENT_MAX_NAME_SIZE];
|
||||
uint16_t nameLen;
|
||||
uint8_t type;
|
||||
MSI_ENTRY *entry;
|
||||
STACK_OF(MSI_DIRENT) *children;
|
||||
struct msi_dirent_struct *next; /* for cycle detection */
|
||||
} MSI_DIRENT;
|
||||
|
||||
DEFINE_STACK_OF(MSI_DIRENT)
|
||||
|
||||
typedef struct {
|
||||
const u_char *m_buffer;
|
||||
uint32_t m_bufferLen;
|
||||
MSI_FILE_HDR *m_hdr;
|
||||
uint32_t m_sectorSize;
|
||||
uint32_t m_minisectorSize;
|
||||
uint32_t m_miniStreamStartSector;
|
||||
} MSI_FILE;
|
||||
|
||||
typedef struct {
|
||||
char *header;
|
||||
char *ministream;
|
||||
char *minifat;
|
||||
char *fat;
|
||||
uint32_t dirtreeLen;
|
||||
uint32_t miniStreamLen;
|
||||
uint32_t minifatLen;
|
||||
uint32_t fatLen;
|
||||
uint32_t ministreamsMemallocCount;
|
||||
uint32_t minifatMemallocCount;
|
||||
uint32_t fatMemallocCount;
|
||||
uint32_t dirtreeSectorsCount;
|
||||
uint32_t minifatSectorsCount;
|
||||
uint32_t fatSectorsCount;
|
||||
uint32_t miniSectorNum;
|
||||
uint32_t sectorNum;
|
||||
uint32_t sectorSize;
|
||||
} MSI_OUT;
|
||||
|
||||
static const u_char msi_magic[] = {
|
||||
0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1
|
||||
};
|
||||
|
||||
static const u_char digital_signature[] = {
|
||||
0x05, 0x00, 0x44, 0x00, 0x69, 0x00, 0x67, 0x00,
|
||||
0x69, 0x00, 0x74, 0x00, 0x61, 0x00, 0x6C, 0x00,
|
||||
0x53, 0x00, 0x69, 0x00, 0x67, 0x00, 0x6E, 0x00,
|
||||
0x61, 0x00, 0x74, 0x00, 0x75, 0x00, 0x72, 0x00,
|
||||
0x65, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const u_char digital_signature_ex[] = {
|
||||
0x05, 0x00, 0x4D, 0x00, 0x73, 0x00, 0x69, 0x00,
|
||||
0x44, 0x00, 0x69, 0x00, 0x67, 0x00, 0x69, 0x00,
|
||||
0x74, 0x00, 0x61, 0x00, 0x6C, 0x00, 0x53, 0x00,
|
||||
0x69, 0x00, 0x67, 0x00, 0x6E, 0x00, 0x61, 0x00,
|
||||
0x74, 0x00, 0x75, 0x00, 0x72, 0x00, 0x65, 0x00,
|
||||
0x45, 0x00, 0x78, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const u_char msi_root_entry[] = {
|
||||
0x52, 0x00, 0x6F, 0x00, 0x6F, 0x00, 0x74, 0x00,
|
||||
0x20, 0x00, 0x45, 0x00, 0x6E, 0x00, 0x74, 0x00,
|
||||
0x72, 0x00, 0x79, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static const u_char msi_zeroes[] = {
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len);
|
||||
MSI_FILE *msi_file_new(char *buffer, uint32_t len);
|
||||
void msi_file_free(MSI_FILE *msi);
|
||||
MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi);
|
||||
int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret);
|
||||
MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse);
|
||||
void msi_dirent_free(MSI_DIRENT *dirent);
|
||||
int msi_prehash_dir(MSI_DIRENT *dirent, BIO *hash, int is_root);
|
||||
int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root);
|
||||
int msi_calc_digest(char *indata, int mdtype, u_char *mdbuf, uint32_t fileend);
|
||||
int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen);
|
||||
int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p, uint32_t len,
|
||||
u_char *p_msiex, uint32_t len_msiex, BIO *outdata);
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: t
|
||||
End:
|
||||
|
||||
vim: set ts=4 noexpandtab:
|
||||
*/
|
10505
osslsigncode.c
10505
osslsigncode.c
File diff suppressed because it is too large
Load Diff
556
osslsigncode.h
Normal file
556
osslsigncode.h
Normal file
@ -0,0 +1,556 @@
|
||||
/*
|
||||
* Copyright (C) 2021-2023 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
||||
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
|
||||
*/
|
||||
|
||||
#define OPENSSL_API_COMPAT 0x10100000L
|
||||
#define OPENSSL_NO_DEPRECATED
|
||||
|
||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||
#define HAVE_WINDOWS_H
|
||||
#endif /* _MSC_VER || __MINGW32__ */
|
||||
|
||||
#ifdef HAVE_WINDOWS_H
|
||||
#define NOCRYPT
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winsock2.h>
|
||||
#endif /* HAVE_WINDOWS_H */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#ifdef HAVE_SYS_MMAN_H
|
||||
#include <sys/mman.h>
|
||||
#endif /* HAVE_SYS_MMAN_H */
|
||||
#ifdef HAVE_TERMIOS_H
|
||||
#include <termios.h>
|
||||
#endif /* HAVE_TERMIOS_H */
|
||||
#endif /* _WIN32 */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <openssl/asn1t.h>
|
||||
#include <openssl/bio.h>
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/cms.h>
|
||||
#include <openssl/conf.h>
|
||||
#include <openssl/crypto.h>
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
#include <openssl/engine.h>
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/objects.h>
|
||||
#include <openssl/pem.h>
|
||||
#include <openssl/pkcs7.h>
|
||||
#include <openssl/pkcs12.h>
|
||||
#if OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||
#include <openssl/provider.h>
|
||||
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/safestack.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h> /* X509_PURPOSE */
|
||||
|
||||
#ifdef ENABLE_CURL
|
||||
#ifdef __CYGWIN__
|
||||
#ifndef SOCKET
|
||||
#define SOCKET UINT_PTR
|
||||
#endif /* SOCKET */
|
||||
#endif /* __CYGWIN__ */
|
||||
#include <curl/curl.h>
|
||||
#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)
|
||||
#define PROVIDE_ASKPASS 1
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
/* not WIN32, because strcasecmp exists in MinGW */
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
|
||||
#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_UINT16_LE(p) (uint16_t)(((const u_char *)(p))[0] | \
|
||||
(((const u_char *)(p))[1] << 8))
|
||||
|
||||
#define GET_UINT32_LE(p) (uint32_t)(((const u_char *)(p))[0] | \
|
||||
(((const u_char *)(p))[1] << 8) | \
|
||||
(((const u_char *)(p))[2] << 16) | \
|
||||
(((const u_char *)(p))[3] << 24))
|
||||
|
||||
#define PUT_UINT8_LE(i, p) ((u_char *)(p))[0] = (u_char)((i) & 0xff);
|
||||
|
||||
#define PUT_UINT16_LE(i,p) ((u_char *)(p))[0] = (u_char)((i) & 0xff); \
|
||||
((u_char *)(p))[1] = (u_char)(((i) >> 8) & 0xff)
|
||||
|
||||
#define PUT_UINT32_LE(i,p) ((u_char *)(p))[0] = (u_char)((i) & 0xff); \
|
||||
((u_char *)(p))[1] = (u_char)(((i) >> 8) & 0xff); \
|
||||
((u_char *)(p))[2] = (u_char)(((i) >> 16) & 0xff); \
|
||||
((u_char *)(p))[3] = (u_char)(((i) >> 24) & 0xff)
|
||||
|
||||
#ifndef FALSE
|
||||
#define FALSE 0
|
||||
#endif
|
||||
|
||||
#ifndef TRUE
|
||||
#define TRUE 1
|
||||
#endif
|
||||
|
||||
#define SIZE_64K 65536 /* 2^16 */
|
||||
#define SIZE_16M 16777216 /* 2^24 */
|
||||
|
||||
/*
|
||||
* Macro names:
|
||||
* linux: __BYTE_ORDER == __LITTLE_ENDIAN | __BIG_ENDIAN
|
||||
* BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
|
||||
* bsd: _BYTE_ORDER == _LITTLE_ENDIAN | _BIG_ENDIAN
|
||||
* BYTE_ORDER == LITTLE_ENDIAN | BIG_ENDIAN
|
||||
* solaris: _LITTLE_ENDIAN | _BIG_ENDIAN
|
||||
*/
|
||||
|
||||
#ifndef BYTE_ORDER
|
||||
#define LITTLE_ENDIAN 1234
|
||||
#define BIG_ENDIAN 4321
|
||||
#define BYTE_ORDER LITTLE_ENDIAN
|
||||
#endif /* BYTE_ORDER */
|
||||
|
||||
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
|
||||
#error "Cannot determine the endian-ness of this platform"
|
||||
#endif
|
||||
|
||||
#ifndef LOWORD
|
||||
#define LOWORD(x) ((x) & 0xFFFF)
|
||||
#endif /* LOWORD */
|
||||
#ifndef HIWORD
|
||||
#define HIWORD(x) (((x) >> 16) & 0xFFFF)
|
||||
#endif /* HIWORD */
|
||||
|
||||
#if BYTE_ORDER == BIG_ENDIAN
|
||||
#define LE_UINT16(x) ((((x) >> 8) & 0x00FF) | \
|
||||
(((x) << 8) & 0xFF00))
|
||||
#define LE_UINT32(x) (((x) >> 24) | \
|
||||
(((x) & 0x00FF0000) >> 8) | \
|
||||
(((x) & 0x0000FF00) << 8) | \
|
||||
((x) << 24))
|
||||
#else
|
||||
#define LE_UINT16(x) (x)
|
||||
#define LE_UINT32(x) (x)
|
||||
#endif /* BYTE_ORDER == BIG_ENDIAN */
|
||||
|
||||
#define MIN(a,b) ((a) < (b) ? a : b)
|
||||
#define INVALID_TIME ((time_t)-1)
|
||||
|
||||
/* Microsoft OID Authenticode */
|
||||
#define SPC_INDIRECT_DATA_OBJID "1.3.6.1.4.1.311.2.1.4"
|
||||
#define SPC_STATEMENT_TYPE_OBJID "1.3.6.1.4.1.311.2.1.11"
|
||||
#define SPC_SP_OPUS_INFO_OBJID "1.3.6.1.4.1.311.2.1.12"
|
||||
#define SPC_PE_IMAGE_DATA_OBJID "1.3.6.1.4.1.311.2.1.15"
|
||||
#define SPC_CAB_DATA_OBJID "1.3.6.1.4.1.311.2.1.25"
|
||||
#define SPC_SIPINFO_OBJID "1.3.6.1.4.1.311.2.1.30"
|
||||
#define SPC_PE_IMAGE_PAGE_HASHES_V1 "1.3.6.1.4.1.311.2.3.1" /* SHA1 */
|
||||
#define SPC_PE_IMAGE_PAGE_HASHES_V2 "1.3.6.1.4.1.311.2.3.2" /* SHA256 */
|
||||
#define SPC_NESTED_SIGNATURE_OBJID "1.3.6.1.4.1.311.2.4.1"
|
||||
/* Microsoft OID Time Stamping */
|
||||
#define SPC_TIME_STAMP_REQUEST_OBJID "1.3.6.1.4.1.311.3.2.1"
|
||||
#define SPC_RFC3161_OBJID "1.3.6.1.4.1.311.3.3.1"
|
||||
/* Microsoft OID Crypto 2.0 */
|
||||
#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 */
|
||||
#define MS_JAVA_SOMETHING "1.3.6.1.4.1.311.15.1"
|
||||
|
||||
#define SPC_UNAUTHENTICATED_DATA_BLOB_OBJID "1.3.6.1.4.1.42921.1.2.1"
|
||||
|
||||
/* Public Key Cryptography Standards PKCS#9 */
|
||||
#define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4"
|
||||
#define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5"
|
||||
#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 */
|
||||
#define WIN_CERT_REVISION_2_0 0x0200
|
||||
#define WIN_CERT_TYPE_PKCS_SIGNED_DATA 0x0002
|
||||
|
||||
/*
|
||||
* FLAG_PREV_CABINET is set if the cabinet file is not the first in a set
|
||||
* of cabinet files. When this bit is set, the szCabinetPrev and szDiskPrev
|
||||
* fields are present in this CFHEADER.
|
||||
*/
|
||||
#define FLAG_PREV_CABINET 0x0001
|
||||
/*
|
||||
* FLAG_NEXT_CABINET is set if the cabinet file is not the last in a set of
|
||||
* cabinet files. When this bit is set, the szCabinetNext and szDiskNext
|
||||
* fields are present in this CFHEADER.
|
||||
*/
|
||||
#define FLAG_NEXT_CABINET 0x0002
|
||||
/*
|
||||
* FLAG_RESERVE_PRESENT is set if the cabinet file contains any reserved
|
||||
* fields. When this bit is set, the cbCFHeader, cbCFFolder, and cbCFData
|
||||
* fields are present in this CFHEADER.
|
||||
*/
|
||||
#define FLAG_RESERVE_PRESENT 0x0004
|
||||
|
||||
#define DO_EXIT_0(x) { fprintf(stderr, x); goto err_cleanup; }
|
||||
#define DO_EXIT_1(x, y) { fprintf(stderr, x, y); 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. */
|
||||
#define TSA_POLICY1 "1.2.3.4.1"
|
||||
|
||||
typedef enum {
|
||||
CMD_SIGN,
|
||||
CMD_EXTRACT,
|
||||
CMD_EXTRACT_DATA,
|
||||
CMD_REMOVE,
|
||||
CMD_VERIFY,
|
||||
CMD_ADD,
|
||||
CMD_ATTACH,
|
||||
CMD_HELP,
|
||||
CMD_DEFAULT
|
||||
} cmd_type_t;
|
||||
|
||||
typedef unsigned char u_char;
|
||||
|
||||
typedef struct {
|
||||
char *infile;
|
||||
char *outfile;
|
||||
char *sigfile;
|
||||
char *certfile;
|
||||
char *xcertfile;
|
||||
char *keyfile;
|
||||
char *pvkfile;
|
||||
char *pkcs12file;
|
||||
int output_pkcs7;
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
char *p11engine;
|
||||
char *p11module;
|
||||
char *p11cert;
|
||||
int login;
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
int askpass;
|
||||
char *readpass;
|
||||
char *pass;
|
||||
int comm;
|
||||
int pagehash;
|
||||
char *desc;
|
||||
const EVP_MD *md;
|
||||
char *url;
|
||||
time_t time;
|
||||
char *turl[MAX_TS_SERVERS];
|
||||
int nturl;
|
||||
char *tsurl[MAX_TS_SERVERS];
|
||||
int ntsurl;
|
||||
char *proxy;
|
||||
int noverifypeer;
|
||||
int addBlob;
|
||||
int nest;
|
||||
int index;
|
||||
int ignore_timestamp;
|
||||
int ignore_cdp;
|
||||
int ignore_crl;
|
||||
int verbose;
|
||||
int add_msi_dse;
|
||||
char *catalog;
|
||||
char *cafile;
|
||||
char *crlfile;
|
||||
char *https_cafile;
|
||||
char *https_crlfile;
|
||||
char *tsa_cafile;
|
||||
char *tsa_crlfile;
|
||||
char *leafhash;
|
||||
int jp;
|
||||
#if OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||
int legacy;
|
||||
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||
EVP_PKEY *pkey;
|
||||
X509 *cert;
|
||||
STACK_OF(X509) *certs;
|
||||
STACK_OF(X509) *xcerts;
|
||||
STACK_OF(X509_CRL) *crls;
|
||||
cmd_type_t cmd;
|
||||
char *indata;
|
||||
char *tsa_certfile;
|
||||
char *tsa_keyfile;
|
||||
time_t tsa_time;
|
||||
int nested_number;
|
||||
} GLOBAL_OPTIONS;
|
||||
|
||||
/*
|
||||
* ASN.1 definitions (more or less from official MS Authenticode docs)
|
||||
*/
|
||||
typedef struct {
|
||||
int type;
|
||||
union {
|
||||
ASN1_BMPSTRING *unicode;
|
||||
ASN1_IA5STRING *ascii;
|
||||
} value;
|
||||
} SpcString;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(SpcString)
|
||||
|
||||
typedef struct {
|
||||
ASN1_OCTET_STRING *classId;
|
||||
ASN1_OCTET_STRING *serializedData;
|
||||
} SpcSerializedObject;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(SpcSerializedObject)
|
||||
|
||||
typedef struct {
|
||||
int type;
|
||||
union {
|
||||
ASN1_IA5STRING *url;
|
||||
SpcSerializedObject *moniker;
|
||||
SpcString *file;
|
||||
} value;
|
||||
} SpcLink;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(SpcLink)
|
||||
|
||||
typedef struct {
|
||||
SpcString *programName;
|
||||
SpcLink *moreInfo;
|
||||
} 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 {
|
||||
ASN1_OBJECT *type;
|
||||
ASN1_TYPE *value;
|
||||
} SpcAttributeTypeAndOptionalValue;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(SpcAttributeTypeAndOptionalValue)
|
||||
|
||||
typedef struct {
|
||||
ASN1_OBJECT *algorithm;
|
||||
ASN1_TYPE *parameters;
|
||||
} AlgorithmIdentifier;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(AlgorithmIdentifier)
|
||||
|
||||
typedef struct {
|
||||
AlgorithmIdentifier *digestAlgorithm;
|
||||
ASN1_OCTET_STRING *digest;
|
||||
} DigestInfo;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(DigestInfo)
|
||||
|
||||
typedef struct {
|
||||
SpcAttributeTypeAndOptionalValue *data;
|
||||
DigestInfo *messageDigest;
|
||||
} SpcIndirectDataContent;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(SpcIndirectDataContent)
|
||||
|
||||
typedef struct CatalogAuthAttr_st {
|
||||
ASN1_OBJECT *type;
|
||||
ASN1_TYPE *contents;
|
||||
} CatalogAuthAttr;
|
||||
|
||||
DEFINE_STACK_OF(CatalogAuthAttr)
|
||||
DECLARE_ASN1_FUNCTIONS(CatalogAuthAttr)
|
||||
|
||||
typedef struct {
|
||||
AlgorithmIdentifier *digestAlgorithm;
|
||||
ASN1_OCTET_STRING *digest;
|
||||
} MessageImprint;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(MessageImprint)
|
||||
|
||||
typedef struct {
|
||||
ASN1_OBJECT *type;
|
||||
ASN1_OCTET_STRING *signature;
|
||||
} TimeStampRequestBlob;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(TimeStampRequestBlob)
|
||||
|
||||
typedef struct {
|
||||
ASN1_OBJECT *type;
|
||||
TimeStampRequestBlob *blob;
|
||||
} TimeStampRequest;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(TimeStampRequest)
|
||||
|
||||
/* RFC3161 Time stamping */
|
||||
|
||||
typedef struct {
|
||||
ASN1_INTEGER *status;
|
||||
STACK_OF(ASN1_UTF8STRING) *statusString;
|
||||
ASN1_BIT_STRING *failInfo;
|
||||
} PKIStatusInfo;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(PKIStatusInfo)
|
||||
|
||||
typedef struct {
|
||||
PKIStatusInfo *status;
|
||||
PKCS7 *token;
|
||||
} TimeStampResp;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(TimeStampResp)
|
||||
|
||||
typedef struct {
|
||||
ASN1_INTEGER *version;
|
||||
MessageImprint *messageImprint;
|
||||
ASN1_OBJECT *reqPolicy;
|
||||
ASN1_INTEGER *nonce;
|
||||
ASN1_BOOLEAN certReq;
|
||||
STACK_OF(X509_EXTENSION) *extensions;
|
||||
} TimeStampReq;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(TimeStampReq)
|
||||
|
||||
typedef struct {
|
||||
ASN1_INTEGER *seconds;
|
||||
ASN1_INTEGER *millis;
|
||||
ASN1_INTEGER *micros;
|
||||
} TimeStampAccuracy;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(TimeStampAccuracy)
|
||||
|
||||
typedef struct {
|
||||
ASN1_INTEGER *version;
|
||||
ASN1_OBJECT *policy_id;
|
||||
MessageImprint *messageImprint;
|
||||
ASN1_INTEGER *serial;
|
||||
ASN1_GENERALIZEDTIME *time;
|
||||
TimeStampAccuracy *accuracy;
|
||||
ASN1_BOOLEAN ordering;
|
||||
ASN1_INTEGER *nonce;
|
||||
GENERAL_NAME *tsa;
|
||||
STACK_OF(X509_EXTENSION) *extensions;
|
||||
} TimeStampToken;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(TimeStampToken)
|
||||
|
||||
typedef struct {
|
||||
ASN1_OCTET_STRING *digest;
|
||||
STACK_OF(CatalogAuthAttr) *attributes;
|
||||
} CatalogInfo;
|
||||
|
||||
DEFINE_STACK_OF(CatalogInfo)
|
||||
DECLARE_ASN1_FUNCTIONS(CatalogInfo)
|
||||
|
||||
typedef struct {
|
||||
/* 1.3.6.1.4.1.311.12.1.1 MS_CATALOG_LIST */
|
||||
SpcAttributeTypeAndOptionalValue *type;
|
||||
ASN1_OCTET_STRING *identifier;
|
||||
ASN1_UTCTIME *time;
|
||||
/* 1.3.6.1.4.1.311.12.1.2 CatalogVersion = 1
|
||||
* 1.3.6.1.4.1.311.12.1.3 CatalogVersion = 2 */
|
||||
SpcAttributeTypeAndOptionalValue *version;
|
||||
STACK_OF(CatalogInfo) *header_attributes;
|
||||
/* 1.3.6.1.4.1.311.12.2.1 CAT_NAMEVALUE_OBJID */
|
||||
ASN1_TYPE *filename;
|
||||
} 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 script_ctx_st SCRIPT_CTX;
|
||||
typedef struct msi_ctx_st MSI_CTX;
|
||||
typedef struct pe_ctx_st PE_CTX;
|
||||
typedef struct cab_ctx_st CAB_CTX;
|
||||
typedef struct cat_ctx_st CAT_CTX;
|
||||
typedef struct appx_ctx_st APPX_CTX;
|
||||
|
||||
typedef struct {
|
||||
FILE_FORMAT *format;
|
||||
GLOBAL_OPTIONS *options;
|
||||
union {
|
||||
SCRIPT_CTX *script_ctx;
|
||||
MSI_CTX *msi_ctx;
|
||||
PE_CTX *pe_ctx;
|
||||
CAB_CTX *cab_ctx;
|
||||
CAT_CTX *cat_ctx;
|
||||
APPX_CTX *appx_ctx;
|
||||
};
|
||||
} FILE_FORMAT_CTX;
|
||||
|
||||
extern FILE_FORMAT file_format_script;
|
||||
extern FILE_FORMAT file_format_msi;
|
||||
extern FILE_FORMAT file_format_pe;
|
||||
extern FILE_FORMAT file_format_cab;
|
||||
extern FILE_FORMAT file_format_cat;
|
||||
extern FILE_FORMAT file_format_appx;
|
||||
|
||||
struct file_format_st {
|
||||
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);
|
||||
PKCS7 *(*pkcs7_contents_get) (FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
|
||||
int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
|
||||
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
|
||||
int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7);
|
||||
int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
|
||||
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 (*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);
|
||||
void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7);
|
||||
void (*bio_free) (BIO *hash, BIO *outdata);
|
||||
void (*ctx_cleanup) (FILE_FORMAT_CTX *ctx);
|
||||
int (*is_detaching_supported) (void);
|
||||
};
|
||||
|
||||
/*
|
||||
Local Variables:
|
||||
c-basic-offset: 4
|
||||
tab-width: 4
|
||||
indent-tabs-mode: nil
|
||||
End:
|
||||
|
||||
vim: set ts=4 expandtab:
|
||||
*/
|
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-----
|
||||
MIIDoTCCAomgAwIBAgIUOK8lwJ8A1Oqw8jDAb3TF06ve+PcwDQYJKoZIhvcNAQEL
|
||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
||||
MTcwMTAxMDAwMDAwWhcNMjYxMTEwMDAwMDAwWjBYMQswCQYDVQQGEwJQTDEVMBMG
|
||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
||||
cml0eTEQMA4GA1UEAwwHUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
|
||||
AQoCggEBAKzObJwYq4t9Y/OOQLqUNLU8RDXq284L8zQgRLkvApF87FNN7kozIgC9
|
||||
/HAgJSho/Lup5lzkCWa3fjkYm1EBrL+JihesSaCxxe7LOg6tRaY+WxikwMUnlkNE
|
||||
s3R+DogeGVsla4q0FEcICiz3FHTfSAUVmrN3Nj1ll7npJXrqmXxfCuO3slgjUkHq
|
||||
tdZ5t1rSWwbiUhGIQKLzo3/uw2XoOI28qpoOw+0/y8AyjWs8My3u8GrYFr+qh5fx
|
||||
Y0Zp0EhhAJo23Xd43XmeVKjuKIOaHu3JiM8sp9K1WFsTvFNAO27TBRn/X0mJCeDX
|
||||
T117dQxhWOCcQ/uRGuXICT4ign8MLtUCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB
|
||||
/zAdBgNVHQ4EFgQU6ewx3DIpbR8OptEmDFlYNELRqP4wHwYDVR0jBBgwFoAU6ewx
|
||||
3DIpbR8OptEmDFlYNELRqP4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA
|
||||
A4IBAQAhRMun0IzPmHVFM+SOfSCPVAgogWpqR5XlBAFlS+Aen6v3ukQAQjEhfBbE
|
||||
dZG6ye9i0ebf9qXYTvSq5wfaqP7FGb2/Z96uPXNMXPi796KjLW2CG578DitORPb7
|
||||
x1eV3UGrQX2bMQ0JbGkBU+DIdIRBqDfad/kjLtm5eHyCbaodSWdaZO4LSUIy3MBx
|
||||
2UeBj2qD4RTA0Dt7hG7RA5QdTxHlZyLIk8HX3krZ+il5RmSbOnQs/XqK5DJp4J5p
|
||||
122sIO4Y9ki+Wewzx8f3/7mcVbcMo67GwRHo8bk3GjWE74pczyrzfP68vDQ4tn85
|
||||
NcLPeLClfSziJD09z+Iyp94EQeKX
|
||||
-----END CERTIFICATE-----
|
@ -1,13 +0,0 @@
|
||||
-----BEGIN X509 CRL-----
|
||||
MIIB9zCB4AIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJQTDEVMBMGA1UE
|
||||
CgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
|
||||
eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBFw0xOTAxMDEwMDAwMDBaFw00MzAx
|
||||
MDEwMDAwMDBaMCcwJQIUOpY5wp7DtqsdxII7sxculedk0PYXDTIyMDcyNjEzMDk1
|
||||
NlqgIzAhMB8GA1UdIwQYMBaAFJ4FrAtb4UB/ag702URPiid97ziLMA0GCSqGSIb3
|
||||
DQEBCwUAA4IBAQA4Kw0vEJrtjjMam16iN/stOMxJDgkp1IQzA3narxr9fEjX5Ynk
|
||||
JztuEExtowPIDOLGWCySXNEMmxCzXNAMvlUq+UQvnWrwgHQ9R7TBYIcAY+VRmzKz
|
||||
T4PXvDSL2WMuJ1dLWoIcL2D0wEdti7YMvAnCrOC8HAPGgke5QcOgSfMSAYSAtpiw
|
||||
PZAFgcuo53AodlCw9J+CPcHPYw+C2QExOy8s8q6d8Xgjg+Ge7v3RxLWy74sNPl0u
|
||||
uZ79vcLNEeqEXxKaw5abqDqIDcUKIT3b62KsSxkak9IGNMLcTASw1V+YaKVLSYNW
|
||||
NTuc5WJblfZi/q7WUMKkmRERzvdg2rf0CSH1
|
||||
-----END X509 CRL-----
|
@ -1,28 +0,0 @@
|
||||
-----BEGIN PRIVATE KEY-----
|
||||
MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCivbbTCnbOqPoV
|
||||
7VVP/KJzgslx8yfX9laGwTsvzqStQtG8j40ljR85WD/bgy3I5duebudg7JhOVH2f
|
||||
aSqbh8SCzP4YNDFcseDIuHdoXi54POgW3S/wbe8l8P7g3btcBgnlXh/izhUlEMib
|
||||
Q/8G8UZj0n/MgKMLzcXc4t2eQ4Pzw7xAPqoXBZ20Fg2rFBfUsDDLc5F7lpO5t1WQ
|
||||
dXTYmF0oAL/HLmd+HKe5Xgp9jJ6XacesjWLnhRdZ06uUP9cgo+Jem4QZxeFhOtMe
|
||||
KAf7JH3Juz2Gi0a+4dMSNzES4m8RAlf6pXh4kAh7EhMNb/Ir6ZpY8uKM7dtn38mh
|
||||
1f59EKc9AgMBAAECggEAK5zB0P695hYcpyGqOjxO4LvM9m+eXt7SQ1ynWuF6+j+s
|
||||
62ZhAg42rux6eH5IF82ZtHSuJyhgjKVR4RWS6IlS3WbINX5PODMnNUNSJLMQqwJP
|
||||
hEkUXs9nRni2JVbmrfukTUaTLvnhasR7rjhjsN2Z6ohv3UMf7rrfapmVoKMhSoLd
|
||||
jqvZ2ZoaT5mfTiK/5PDyWqrt/vmvE4VlipAsvudwozG5vQDEsCNDNUTg5OTGnPUU
|
||||
i0xeQTioqzCcweIlEaWhj/eMHx/eAeZ6V0Evid/YwTDlbTqVDWZGLJ/phOnKJs3V
|
||||
j+eOv7E2d1ga7149SPDIv5Y0YZ91v3M06ICk5o66gQKBgQDSM+YyR5YOJTSAuAcI
|
||||
uKTc33wwCbPiJF/F1zLJDdPp2IamZQbuNIX/8fOG3Gho+OnfNAykMcr3rFrug2vi
|
||||
9GhWDQqguYGh16xos+2zNan6P/s0/rQ4OfPIsTEGC8X3fJeMzZUNMvnyN/FXzzus
|
||||
020o29gu59esEfGHEsvAupC3IQKBgQDGMqGLgrU4oW/5mmm4BZlwwkZJNMmFH49u
|
||||
Qe4Ylj87SQduExJMmTfrmANqQXu7RXG0IxLcvhwMLVCCYAkvuBv1awsbg2yfP1Pn
|
||||
Wb/K+5CaHaxnpwSpRiGaN6fnAPDl8PnALMVXtQGru2MMcISxOIFQ9slHth0lmaMo
|
||||
odIPIL1YnQKBgAOSskUEhn5zD3NorWXujY7blabTY2VirOYWBFz6iTGeZpuJeBaw
|
||||
ed6h5DvUn0m5gXAz2EsqNYMEQP9w6HKRKPzdd+LHhHaVze5xsIatUNhaIhECi1mx
|
||||
Un2E1Yp+xLyyN3lDPVdeGHWPkeCmOyNy7JYXNpOFiVr5axuarC/4e+FBAoGAeuRR
|
||||
/mshaufOwnnYK15tcdlEM4gjnAOhr7/5ng0rT9tMXBg/NHeckNxE4dGQouHASu2k
|
||||
eHL4eSRv0ycxCwGhdF7XGEw5QdTGdaDUp0ussaLMj8ijv0HY/AKefUG8HRd6BIq+
|
||||
Ik/9pTofhEsQO8LJjCY5T9m/4NyOqlcMJI0sWpECgYBvPLnutbBXYONVAE3jL05K
|
||||
hWwenKpv5Aaa11ahqzhil2Tj+VOMtmvhsSc5loSG83qp5LtN4LxyR0Vn9AGN7Z+d
|
||||
Ut6LHeZ/DMW3/RPT+1MIKm6WLNxgk5YvuCxprdpfE5tTmV9/t+t3Uao7TRsLPl2o
|
||||
qAKz8Fvq0el5RW3EtAgd4A==
|
||||
-----END PRIVATE KEY-----
|
@ -1,28 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEzTCCA7WgAwIBAgIUfRjXKciCGA4XbhbhxbAwfpcLGmowDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
||||
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMFUxCzAJBgNVBAYT
|
||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxHDAaBgNVBAsME1RpbWVzdGFtcCBB
|
||||
dXRob3JpdHkxETAPBgNVBAMMCFRlc3QgVFNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAor220wp2zqj6Fe1VT/yic4LJcfMn1/ZWhsE7L86krULRvI+N
|
||||
JY0fOVg/24MtyOXbnm7nYOyYTlR9n2kqm4fEgsz+GDQxXLHgyLh3aF4ueDzoFt0v
|
||||
8G3vJfD+4N27XAYJ5V4f4s4VJRDIm0P/BvFGY9J/zICjC83F3OLdnkOD88O8QD6q
|
||||
FwWdtBYNqxQX1LAwy3ORe5aTubdVkHV02JhdKAC/xy5nfhynuV4KfYyel2nHrI1i
|
||||
54UXWdOrlD/XIKPiXpuEGcXhYTrTHigH+yR9ybs9hotGvuHTEjcxEuJvEQJX+qV4
|
||||
eJAIexITDW/yK+maWPLijO3bZ9/JodX+fRCnPQIDAQABo4IBiDCCAYQwDAYDVR0T
|
||||
AQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAdBgNVHQ4EFgQUKWCqogni
|
||||
6SseJ/P6LXo0M2cK++QwHwYDVR0jBBgwFoAU/5nNuG4Tm4v2y9uKf428/4fVQesw
|
||||
gYQGCCsGAQUFBwEBBHgwdjA5BggrBgEFBQcwAoYtaHR0cDovL1RTQUNBLnRpbWVz
|
||||
dGFtcGF1dGhvcml0eS5jb20vVFNBQ0EuY3J0MDkGCCsGAQUFBzABhi1odHRwOi8v
|
||||
b2NzcC5UU0FDQS50aW1lc3RhbXBhdXRob3JpdHkuY29tOjkwODAwPgYDVR0fBDcw
|
||||
NTAzoDGgL4YtaHR0cDovL1RTQUNBLnRpbWVzdGFtcGF1dGhvcml0eS5jb20vVFNB
|
||||
Q0EuY3JsMFUGA1UdHgROMEygGDAKggh0ZXN0LmNvbTAKggh0ZXN0Lm9yZ6EwMAqH
|
||||
CAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQB4YXa5nVWUzWSsUDMfYFTEETOe8boUErwfrDNBuj6z
|
||||
B5en20FhI49i6PCYEfNq3vrAtPOEFJj+KPomN3C46VLxbUEvqWLdq6EyzWvVVmXK
|
||||
VLeC0qV0m6CFM8GplaWzZdfFTQaaLUhgY08ZU2gp4QsoS2YjAosxlZrNSm6pBbv3
|
||||
q+Og1KeSK8gKS0V89k+6e3LOEF6KaNWKSkoz5xDniQY//mTjiDcNmYUh0KhHfhdU
|
||||
eO92M82uJSaDqnRs5HsWPs6z6qdfpuvj++OtQ1VCM2p5SEH2sEomdeN3YYChuG4h
|
||||
yzn0mYAdbTyGJHlFm17AH+SQRbVqCKYdHDaqsMb+fWzi
|
||||
-----END CERTIFICATE-----
|
@ -1,22 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkDCCAnigAwIBAgIUJ0nfE+EVsIThltlY2LHVWMJVIq4wDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
||||
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0yNjExMTAwMDAwMDBaMGAxCzAJBgNVBAYT
|
||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB
|
||||
dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGOTX1f9dmtUiyzlsUInRIGfRMya338SVx
|
||||
vYGeOwdpTSSGlYUVwR9AuFewQF5+klelstCJe+SoUG0AdzS30mRWlQrhip4UdvdW
|
||||
T2gkNKbSn6DQzlWoQej9izqRLxAsbuszgkvnLOBEmPaLimDsCgu0bAN95Hp0Hls9
|
||||
O/fVmzh8VuV4iscxc7q13ZB7CylWgwd55CFEGd/jpJ6kMwSHbOLoBWp4GQ3KxR+c
|
||||
ASAo0FapU2WSZB2EYWszRiyq91X+AvIYN4ypTv7RccgfUvnZ2qFykJAkf/wgkynu
|
||||
Qg7rCUNfUEpDc7jlqtDWR7iLrtHBkA17C3IU8ymmKQYWfw3ZyBwvAgMBAAGjQjBA
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP+ZzbhuE5uL9svbin+NvP+H1UHr
|
||||
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAbj3aFwIUxvzwgywO
|
||||
gj01JM8GNbw1E4MGdkaNI8rgeY8ay15ZXhR9NpRWWb6Y7IXPq5XhuEktVte5Z4Kf
|
||||
XLBrr7Xe9VVqJL9zd1tMzOEM/zG77rZf/iXBTZLkCtQc/GOEY4TTWKNEl5hiWVE0
|
||||
po97GX5XHoeyHlWQ75sd9z6MxFxmvdp9/uyYD700e9sd5gcD8LGvHw2DNy8vntYV
|
||||
ia9h95N9i1umffxU460o8W5GoIcsD13B3YftvnWhGSXqovBRFgcPAQZ4eW9Qh/zA
|
||||
4zQBQrRvmREPihXVdgtWVpbRchP99oSZBrYr7Hh/P69rycklquqxJl1ol1wbT6dK
|
||||
S5Gmng==
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
Binary file not shown.
@ -1,46 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID7jCCAtagAwIBAgIUdLInHjkevRVCr7I78r5++6eSrZ0wDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
|
||||
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMIGdMQswCQYDVQQG
|
||||
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
|
||||
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEUMBIGA1UEAwwL
|
||||
Q2VydGlmaWNhdGUxJzAlBgkqhkiG9w0BCQEWGG9zc2xzaWduY29kZUBleGFtcGxl
|
||||
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJLJ3Vty2lgJw+5
|
||||
ouAV4ZqkIwvfWPcE7zD1CfQIL2802jVuCSTkN9cfFVYMKFEPJxQWJAKoCzr/Ux8z
|
||||
Yt9BXO5o39+z7umLKmc6pfrZJ6kG4msrMjZv36LsCQyfjUc1O9H1aiOQEvRQY2pF
|
||||
2v5dfqRMrAqH1ESQHCggUBjElWj9oMFax8jyO7JxTzuttOb6mhDmqz4q2u4LwZGH
|
||||
lBofgOAB54Mlv41x7dDh85i/jayXuYYmsjRwCuBAn14+D2zImyPDx5UaUJJMzujo
|
||||
QriOZ4KU2dHRgy0+vd7ZbrL1kRY1axyNQ+jBk7UHnlZZ2CCkhBoZIM6ez3ljPwgr
|
||||
cpg0RtcCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUBxPEs09WXDxGqb+D
|
||||
WTFgcUQd0AEwHwYDVR0jBBgwFoAUngWsC1vhQH9qDvTZRE+KJ33vOIswEwYDVR0l
|
||||
BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAKK2e1s1puUFbNjglopi
|
||||
mKZ4Pks2zb6LVUGG6Q4XQ1dWe25ovt68jWv56HFyCMI1N+L8q0+Ku2eOfLObS7Ej
|
||||
FFRUWEIXDgipryDTGzoWRM380fuYpL/j7Rt1/xmIHWTFibf/6gK/naRXsFH3dEbb
|
||||
7DDWQ5pAd2d60dB+ThUEIZQTQd/926Kuk5oESvP08fXMYTuiYARypG1gmiuvxQ9N
|
||||
mDJP6CHxyJR/LB4tb0RAqnLkVsXVBDnRYWdEvkuhoqTtbhVzVbL3mPeEmVYypxxd
|
||||
NdrHpU5zmxFSin2T3F0TneNcT+MDV+dQcWyTGNYs/fnmo85LsiakJixGv1qx8PTs
|
||||
8iE=
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrDCCApSgAwIBAgIUUPCDF21g2spK7557HZUhqSxBltMwDQYJKoZIhvcNAQEL
|
||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAyMs1XoC0NUT5YgydibOrE5SWBKk5C47B6tv6gA4t3zZJ
|
||||
wejaiPkj+aTIU3Ww5DO/Gpz0GuqCHNBczIw92Cfvv8kyWzUy46bRkpBJLFav0JXS
|
||||
B3xQaPlHWeXqMfVAGuM5ExT4CjjYKFsrgV1Q300thCHBhvr8TPekDIf+6J7NSz1P
|
||||
062pYgypfqsA8OwKaQbgOL9v4QRmHoolnEDc1dK/FS4f3p9dlifl7kcSVGQK0yit
|
||||
7Uncn250icCxMxS3MOE2NfuplUOSN6h6poWNGUsx00O7Dy9nUndUwJRpFfKXTV3v
|
||||
GtlmFLNoho+ss/usnxjxggWBcRtKhqd8nGSJUlzs0wIDAQABo2YwZDASBgNVHRMB
|
||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBSeBawLW+FAf2oO9NlET4onfe84izAfBgNV
|
||||
HSMEGDAWgBTp7DHcMiltHw6m0SYMWVg0QtGo/jAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAD/FBa4stJGd/Acg2E2soI071B/l9B7FiqIRpCFuLVC4
|
||||
1m7TIcjioIpZrxXwE1Egf8A9/6D/kKZtWnOljcxtPBEb+1/gB61M381RIgoMQ/Pf
|
||||
7XX2yakk6mscUjbSTR//Mj1sYOs2r6ueZBp0whzF9nVvA43G6WMpf6XZqmhlg/oV
|
||||
ynytW1Iu1SPoru3y8dX/lsukvKCak7MAp1eBcuUJxS56DnKcV9xgC30m3g+CErI3
|
||||
qsOJ7lcfDP6fDjy7MfBsZBiY64MqwlDjjn7+Pleo69JedMwurHLhKnfm07DBPy8X
|
||||
+EnQk61xHEjQtTsddXyQGQV3yjqylOF2AgsAf256uuA=
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
@ -1,23 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDzjCCAragAwIBAgIUGjZdQYlcAtlqZOsQ7eWRimQ9PIcwDQYJKoZIhvcNAQEL
|
||||
BQAwbzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEMMAoGA1UE
|
||||
CwwDQ1NQMRIwEAYDVQQDDAljcm9zc2NlcnQxJzAlBgkqhkiG9w0BCQEWGG9zc2xz
|
||||
aWduY29kZUBleGFtcGxlLmNvbTAeFw0xODAxMDEwMDAwMDBaFw0yMDA2MTkwMDAw
|
||||
MDBaMG8xCzAJBgNVBAYTAlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNV
|
||||
BAsMA0NTUDESMBAGA1UEAwwJY3Jvc3NjZXJ0MScwJQYJKoZIhvcNAQkBFhhvc3Ns
|
||||
c2lnbmNvZGVAZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
|
||||
AoIBAQDJU6WNMOEoErLYb5Qc7jsvVgruPM7DJTZ4vUpJNYAyprSDHciaKSa4SiYS
|
||||
84Mxc6tzBoJvKOAwpxzzONOqPVWUd5J244urgvfHgSGWsbA8bakiIYlETopnecFk
|
||||
B3ZELR33CPqIbpYYMYujhPGFa1xxZxFykJ1iBhZ8Gh3W4wHi/2kW6hTQkihMtUPP
|
||||
Xxc2XWACj/tz22OSdgNZcIfhXiy2HOuPch+0UlDR4UmlJIR5aet1y832hHoeeevo
|
||||
qfhfGOm9rRf9nyxKDwTyaN7JVOb7A1k6KJEJoe1zfIwT56mgoA433iUWFMLB6hKU
|
||||
be3zV1vGjk77Kk7atcvEMTRq+rwHAgMBAAGjYjBgMAkGA1UdEwQCMAAwHQYDVR0O
|
||||
BBYEFEXgglEcDh+8oCCvjlxrN/Y7C4YwMB8GA1UdIwQYMBaAFEXgglEcDh+8oCCv
|
||||
jlxrN/Y7C4YwMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IB
|
||||
AQBo8UqUEjxGQCVU/IgphwKA8Rb/uAyBYm+AjqFDs82lA6ze0n08Bj+eciVkxscA
|
||||
0deivOC1sDD88QkLzSQ9CPk4e7+m7nx5SFUnUWY+o3ln+cTbGSM0jW9hme0LtHXX
|
||||
QxDSKDBhQonRQk7lQ+TwFR7ol+y5SdZy7YQ+v/25qO6MMQgSPykJIa4vF7lwrYhu
|
||||
qL+1MJx/ryTbCUExcKNNkWHZJRc9ZvtdWEHYpBSZl5xmJdKMLnHAu5uv8N2pezzp
|
||||
PfujldZky7bnERaTM+bf/LvKXS8RfQGrCLu9QjgPVa6ysZV6gXTsEtwYh64vucjS
|
||||
s7IhdLxfiT0xYkK4JWrRLc38
|
||||
-----END CERTIFICATE-----
|
@ -1,45 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIID6jCCAtKgAwIBAgIUdtBZJAw8/6JVNMiQpN3PEROI8rowDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
|
||||
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0xOTAxMDEwMDAwMDBaMIGZMQswCQYDVQQG
|
||||
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
|
||||
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UEAwwH
|
||||
RXhwaXJlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUuY29t
|
||||
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsksndW3LaWAnD7mi4BXh
|
||||
mqQjC99Y9wTvMPUJ9AgvbzTaNW4JJOQ31x8VVgwoUQ8nFBYkAqgLOv9THzNi30Fc
|
||||
7mjf37Pu6YsqZzql+tknqQbiaysyNm/fouwJDJ+NRzU70fVqI5AS9FBjakXa/l1+
|
||||
pEysCofURJAcKCBQGMSVaP2gwVrHyPI7snFPO6205vqaEOarPira7gvBkYeUGh+A
|
||||
4AHngyW/jXHt0OHzmL+NrJe5hiayNHAK4ECfXj4PbMibI8PHlRpQkkzO6OhCuI5n
|
||||
gpTZ0dGDLT693tlusvWRFjVrHI1D6MGTtQeeVlnYIKSEGhkgzp7PeWM/CCtymDRG
|
||||
1wIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBQHE8SzT1ZcPEapv4NZMWBx
|
||||
RB3QATAfBgNVHSMEGDAWgBSeBawLW+FAf2oO9NlET4onfe84izATBgNVHSUEDDAK
|
||||
BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAX1Ar7jRAXdcA0Wu37yRi58QN
|
||||
hpa1VLXadqfB+i5Y4e3DzqnMbpkLWsFzreC1AG0RjLe52s4PRUE6boGlpUeAyfFC
|
||||
Qu2Gl/REVWwMCYV8bq3vQZkYQjklAXCQLWFk5TrzuDmBcV8+fY518nWw+xmcYwW5
|
||||
5oehLsvB4nxoBzlHgcdDwS5b2dmpCKCbZFLU9aA9DjAVvY/9B8emyj7Sh2sEK0Yf
|
||||
xwHlATTVq5O0/9tvVZQmYsbpS0iCRGBM+spTEhDT4WGsaRO6wP+Ucgp6Ym3ahMvz
|
||||
tHME3uUanKWVoDb69sguGZ6KlnZZZdIX1AJ3dlTXCrzEO9xsoAzqzsxVJGrraQ==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrDCCApSgAwIBAgIUUPCDF21g2spK7557HZUhqSxBltMwDQYJKoZIhvcNAQEL
|
||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAyMs1XoC0NUT5YgydibOrE5SWBKk5C47B6tv6gA4t3zZJ
|
||||
wejaiPkj+aTIU3Ww5DO/Gpz0GuqCHNBczIw92Cfvv8kyWzUy46bRkpBJLFav0JXS
|
||||
B3xQaPlHWeXqMfVAGuM5ExT4CjjYKFsrgV1Q300thCHBhvr8TPekDIf+6J7NSz1P
|
||||
062pYgypfqsA8OwKaQbgOL9v4QRmHoolnEDc1dK/FS4f3p9dlifl7kcSVGQK0yit
|
||||
7Uncn250icCxMxS3MOE2NfuplUOSN6h6poWNGUsx00O7Dy9nUndUwJRpFfKXTV3v
|
||||
GtlmFLNoho+ss/usnxjxggWBcRtKhqd8nGSJUlzs0wIDAQABo2YwZDASBgNVHRMB
|
||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBSeBawLW+FAf2oO9NlET4onfe84izAfBgNV
|
||||
HSMEGDAWgBTp7DHcMiltHw6m0SYMWVg0QtGo/jAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAD/FBa4stJGd/Acg2E2soI071B/l9B7FiqIRpCFuLVC4
|
||||
1m7TIcjioIpZrxXwE1Egf8A9/6D/kKZtWnOljcxtPBEb+1/gB61M381RIgoMQ/Pf
|
||||
7XX2yakk6mscUjbSTR//Mj1sYOs2r6ueZBp0whzF9nVvA43G6WMpf6XZqmhlg/oV
|
||||
ynytW1Iu1SPoru3y8dX/lsukvKCak7MAp1eBcuUJxS56DnKcV9xgC30m3g+CErI3
|
||||
qsOJ7lcfDP6fDjy7MfBsZBiY64MqwlDjjn7+Pleo69JedMwurHLhKnfm07DBPy8X
|
||||
+EnQk61xHEjQtTsddXyQGQV3yjqylOF2AgsAf256uuA=
|
||||
-----END CERTIFICATE-----
|
@ -1,22 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrDCCApSgAwIBAgIUUPCDF21g2spK7557HZUhqSxBltMwDQYJKoZIhvcNAQEL
|
||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAyMs1XoC0NUT5YgydibOrE5SWBKk5C47B6tv6gA4t3zZJ
|
||||
wejaiPkj+aTIU3Ww5DO/Gpz0GuqCHNBczIw92Cfvv8kyWzUy46bRkpBJLFav0JXS
|
||||
B3xQaPlHWeXqMfVAGuM5ExT4CjjYKFsrgV1Q300thCHBhvr8TPekDIf+6J7NSz1P
|
||||
062pYgypfqsA8OwKaQbgOL9v4QRmHoolnEDc1dK/FS4f3p9dlifl7kcSVGQK0yit
|
||||
7Uncn250icCxMxS3MOE2NfuplUOSN6h6poWNGUsx00O7Dy9nUndUwJRpFfKXTV3v
|
||||
GtlmFLNoho+ss/usnxjxggWBcRtKhqd8nGSJUlzs0wIDAQABo2YwZDASBgNVHRMB
|
||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBSeBawLW+FAf2oO9NlET4onfe84izAfBgNV
|
||||
HSMEGDAWgBTp7DHcMiltHw6m0SYMWVg0QtGo/jAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAD/FBa4stJGd/Acg2E2soI071B/l9B7FiqIRpCFuLVC4
|
||||
1m7TIcjioIpZrxXwE1Egf8A9/6D/kKZtWnOljcxtPBEb+1/gB61M381RIgoMQ/Pf
|
||||
7XX2yakk6mscUjbSTR//Mj1sYOs2r6ueZBp0whzF9nVvA43G6WMpf6XZqmhlg/oV
|
||||
ynytW1Iu1SPoru3y8dX/lsukvKCak7MAp1eBcuUJxS56DnKcV9xgC30m3g+CErI3
|
||||
qsOJ7lcfDP6fDjy7MfBsZBiY64MqwlDjjn7+Pleo69JedMwurHLhKnfm07DBPy8X
|
||||
+EnQk61xHEjQtTsddXyQGQV3yjqylOF2AgsAf256uuA=
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
@ -1,27 +0,0 @@
|
||||
-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEogIBAAKCAQEAsksndW3LaWAnD7mi4BXhmqQjC99Y9wTvMPUJ9AgvbzTaNW4J
|
||||
JOQ31x8VVgwoUQ8nFBYkAqgLOv9THzNi30Fc7mjf37Pu6YsqZzql+tknqQbiaysy
|
||||
Nm/fouwJDJ+NRzU70fVqI5AS9FBjakXa/l1+pEysCofURJAcKCBQGMSVaP2gwVrH
|
||||
yPI7snFPO6205vqaEOarPira7gvBkYeUGh+A4AHngyW/jXHt0OHzmL+NrJe5hiay
|
||||
NHAK4ECfXj4PbMibI8PHlRpQkkzO6OhCuI5ngpTZ0dGDLT693tlusvWRFjVrHI1D
|
||||
6MGTtQeeVlnYIKSEGhkgzp7PeWM/CCtymDRG1wIDAQABAoIBACR/jgxT9ZgUvupR
|
||||
Li6BTDXD9AiyKBwpPm3fO7JhGpTBVQorBGQw891t14hN5NLzLyTFg4mnrOTe770r
|
||||
X8okL0n+3hWFWBsnCf8n2mKHob7QUfluVlEehcFsYE3dO6agFybb/mZZUAgDjNZs
|
||||
hnAb45juuSlOtP10Is90DfGEDLH5IeY1xjzc7Qv/CFxCffIAC8QmQYUTihJ2m5aE
|
||||
7Hvs79oEcSvbRJDYbykzrJ0eeIaEvfOxkWJnnJHrhiONzb8qgj3DLiZdX1qeo1Ao
|
||||
ldNxEG9n3Axd6M0nhajz0qbDV11S8YiKfP10XRQh5xv7lZi7MjvrRxFTFYpSrXwi
|
||||
YYyFNoECgYEA6YnIYg1nIe3qaI3Me1RQQTGRl8M/dQc2d98Pz5mez9vN3TIW6nEs
|
||||
QYw/9OKG1ercbD+YnuaV+1izuAcA3mNlSDReTtzInAotJjTH1V3WYqvBTVUZSb6T
|
||||
5qSBfRDC3AULFvHeX5c5wqgfB3U9KLDfVBfaHnMerg6dAGsYZPhPMrkCgYEAw3Eg
|
||||
5BRTzbqG0WXF25rycTeHCcylMZRjI+TVcIa8AGqNSCK4HgAWp89XPIV3WceVqe2R
|
||||
Lyn1jtA2MgGGcMBDFlOWF+h9j2/j27Z+pyIbBF9LAraJuBOG6dezd50y5Ur6HK/f
|
||||
e5lnjvElIYdz+RX+rmw8NFcIUbSAfE7rGinDvg8CgYBDx86VzsgJC/FFySn4/X6R
|
||||
fV6BSpTHVYGUhvQiz7ZNI8F7GoeWIaSznY4OeBSkT5cL/+U+8TPEkHkQx0+UPArw
|
||||
Suq4PtImn7l85kK9hY+scacX18QQKDTq8wH2F4BGtVwDm81rtwt3mK3wzzEh9zvK
|
||||
P2X6AnV8FReyQGMDIyJxWQKBgD6nu9WitqMTkzj6GY4nhGXLWV1I4ASe/5F4QPzM
|
||||
FOVFQ3nGt6PWf2zYyay7VOHRXCeX451tJC3ejiFF3+WxnVBBB7Muc2JSiofbX4sR
|
||||
Ifwq2I9MGaaLjArXfc9w8+oSOVCNCWZEbbCjmjW/iOxnorgkNsDIzf/zj+VKH5DJ
|
||||
ptj9AoGAUpB6nPES3Nnj8DsbpHCnShYMl/rFxzxg2pJJosXzuS/ttuBT2DlT5eiY
|
||||
aZcL1DGSp2CD4QXbVuDHPkQMPzVfZzKAuCZlotEMR9byK46aYIkQueym45e0PGZP
|
||||
djKZm+cxF+W55jBkBBhV6wSOLNRWCUYiIIq3RmwWjkopNvSlwY4=
|
||||
-----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,6DB255395263EDD5
|
||||
|
||||
A83CH4mv7u89RbT8Tpz4gxImKGBw69Zr3LstRXlliGYobby5YBx/YimkA9wFCZK/
|
||||
B1eitWwy0F6axDZQYHKi+yvUJDPB9arXtClvYknMhwrHV1GHLSYeqb9oZJeqNyDZ
|
||||
Qd3lxTbUtkMVJgJNrl2kOezm6/srnAw4uA7NyAvrs2vEzB48q4VlysrJq+f9mLXj
|
||||
vCmrfUwY999lSifRmoxqeWlqNUQ2tgHHXYMNagpvxYXsfe1UvEH9aa6+UsO9S0py
|
||||
7dyfSu95QpWyVNqkWi1VAtNbo2VpjJ6NJLAk+dy/rNqN3a4KnWeIzkYssWTsKB08
|
||||
VyHrRLePPx5qdarsczZtf+M2PxhHHnl/09+Nrp5BUcMV31j3v3VSM0K+CHEucAk7
|
||||
95rUtSUNywKUQeSgXrG1eLX7kXwRQ7PPCz3sPtvmJRIvQlGgLiTbKPsG52m3kAIw
|
||||
zgXPcH2lYb3855occznl72jMUucxXq8gq0bC4xbEg/yJV8p1IuUEFhLGI9s9T4JV
|
||||
cO9NKwmSjpHFo1ULhB7o6uMmV2rYDK+5GbQHxZgHj3ES+i53eFMWGubPEEOmqSh3
|
||||
9K7gtW9y971tNfhp9ba8RnYXT6xW2nMTM4koO9b4ptdwRo5bMKFvWY8eecXfsDAG
|
||||
OJ+aXkDr8jsn1Xauq1m4TM71wn2wUx95KaCpL55UNBEn7aH9qlNFfxdyzXMPYS36
|
||||
zgWK44BV3PTSIGgW61NVwHwzi3bFfymortVxGpelzy2dggWVvI3uzKocLFQ8f4oe
|
||||
Y0HWSmGVPF3uFHNCZtCB/Tpbz6YwP/YYStqAcryeS5Yo9Hdkh8pBVnYiKdTFEUW2
|
||||
RbClgeB2MV+zttsqvmodfkviS4BjWgoIV5szxWOePnO8kQAHA/Ml3CyDPOX6rqI5
|
||||
lDKiUojEMLgir/3YWWcmigEIgRsyF3CL1s+kTR3S8e9QRe8RiliRUKW5gXrLEa6j
|
||||
eUjs4kgCrvmQvwyZYJjWl+r7ycmk+yB/EZs8P39KRR/pfeZDUCZIOx8vkJBt57hC
|
||||
oTNJ5llFzRcmEraElXmDOAuvmj3Lx/4qzY545rtzll3mFHJEX4qITslIX1ksZz1p
|
||||
DncuqgIECzmZIeHPbnw7Nkv6EkoPzTOlccqnCH/SumFr2fhctv9x13gGcO4kSsqO
|
||||
63yZCFHjMz/mos3l51aIAizj5wQO3BOo+RyKoSQohvPzVtSgjhYMZsAPzXKxF0/H
|
||||
9VH0DekEb1WwPSbGZw8kpx9ePlglGqOBinTL6QW8YmFPbjy9RDd1di+fxh4Qe024
|
||||
8gERZpdSsMoZ+NP0nr/TSbDISFPqcLzzMpC+V8Fc/QkNvSkR1GLlNQrxLoyfK0VX
|
||||
0evysXDxqIWK9+TH7hIS1lf3i2gMkLMppMso1v2Cqf0zRj1oM3MI743QE9XTXKRz
|
||||
iAwaEDDPZWS/00T9fqNrHgtSPNpsbeYZQPYaC2lq1kTIEOlUfZZvMy5lxVPVZ8y2
|
||||
foit+0DewZsqLDJwbjZ3wYMERVEY7KagoInQa3A1ZC9SkFiCb4fNEbRF13gfjrSz
|
||||
muRbKAhEhkzJDFRocIaTKZPIWdvC73tAW66v1Zha74mxuckgnQPPqQ==
|
||||
-----END RSA PRIVATE KEY-----
|
@ -1 +0,0 @@
|
||||
passme
|
@ -1,45 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDvTCCAqWgAwIBAgIUOpY5wp7DtqsdxII7sxculedk0PYwDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
|
||||
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMG0xCzAJBgNVBAYT
|
||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UE
|
||||
AwwHUmV2b2tlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUu
|
||||
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsksndW3LaWAnD7mi
|
||||
4BXhmqQjC99Y9wTvMPUJ9AgvbzTaNW4JJOQ31x8VVgwoUQ8nFBYkAqgLOv9THzNi
|
||||
30Fc7mjf37Pu6YsqZzql+tknqQbiaysyNm/fouwJDJ+NRzU70fVqI5AS9FBjakXa
|
||||
/l1+pEysCofURJAcKCBQGMSVaP2gwVrHyPI7snFPO6205vqaEOarPira7gvBkYeU
|
||||
Gh+A4AHngyW/jXHt0OHzmL+NrJe5hiayNHAK4ECfXj4PbMibI8PHlRpQkkzO6OhC
|
||||
uI5ngpTZ0dGDLT693tlusvWRFjVrHI1D6MGTtQeeVlnYIKSEGhkgzp7PeWM/CCty
|
||||
mDRG1wIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBQHE8SzT1ZcPEapv4NZ
|
||||
MWBxRB3QATAfBgNVHSMEGDAWgBSeBawLW+FAf2oO9NlET4onfe84izATBgNVHSUE
|
||||
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAYVJiPrkACW/tK487fYS/
|
||||
gYzU3fYVCTfHpAv3njarNzy8UBNqBYr0kDg0DLoOWqGV7ogTtlbQP4IIjAQI/kW6
|
||||
cEreW8yU5VxO+kxDo+7oG9VEbR85i6kQW2ubJsXV6yBtf5aAbXEqImYrtjh7UObb
|
||||
BbQiUI1ll2dXWqvZGxr3Fz1uz8nPMYlBpVjpCh6JF8otdWwABmxRnqUvoLO6BZbH
|
||||
/gdUkouXfio9BlWkWaJXJGXMW8B7ozpjuCHSHyfvGKDA3YIfa7++A1BIKxW72jIF
|
||||
jRJDw/rwnV59tiEcBWmp2T6vV+rD8yaS+LotRPYD/ck/jEj/mV+N077KLmuZpdJF
|
||||
ag==
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDrDCCApSgAwIBAgIUUPCDF21g2spK7557HZUhqSxBltMwDQYJKoZIhvcNAQEL
|
||||
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
|
||||
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
|
||||
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
|
||||
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
|
||||
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
|
||||
AAOCAQ8AMIIBCgKCAQEAyMs1XoC0NUT5YgydibOrE5SWBKk5C47B6tv6gA4t3zZJ
|
||||
wejaiPkj+aTIU3Ww5DO/Gpz0GuqCHNBczIw92Cfvv8kyWzUy46bRkpBJLFav0JXS
|
||||
B3xQaPlHWeXqMfVAGuM5ExT4CjjYKFsrgV1Q300thCHBhvr8TPekDIf+6J7NSz1P
|
||||
062pYgypfqsA8OwKaQbgOL9v4QRmHoolnEDc1dK/FS4f3p9dlifl7kcSVGQK0yit
|
||||
7Uncn250icCxMxS3MOE2NfuplUOSN6h6poWNGUsx00O7Dy9nUndUwJRpFfKXTV3v
|
||||
GtlmFLNoho+ss/usnxjxggWBcRtKhqd8nGSJUlzs0wIDAQABo2YwZDASBgNVHRMB
|
||||
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBSeBawLW+FAf2oO9NlET4onfe84izAfBgNV
|
||||
HSMEGDAWgBTp7DHcMiltHw6m0SYMWVg0QtGo/jAOBgNVHQ8BAf8EBAMCAYYwDQYJ
|
||||
KoZIhvcNAQELBQADggEBAD/FBa4stJGd/Acg2E2soI071B/l9B7FiqIRpCFuLVC4
|
||||
1m7TIcjioIpZrxXwE1Egf8A9/6D/kKZtWnOljcxtPBEb+1/gB61M381RIgoMQ/Pf
|
||||
7XX2yakk6mscUjbSTR//Mj1sYOs2r6ueZBp0whzF9nVvA43G6WMpf6XZqmhlg/oV
|
||||
ynytW1Iu1SPoru3y8dX/lsukvKCak7MAp1eBcuUJxS56DnKcV9xgC30m3g+CErI3
|
||||
qsOJ7lcfDP6fDjy7MfBsZBiY64MqwlDjjn7+Pleo69JedMwurHLhKnfm07DBPy8X
|
||||
+EnQk61xHEjQtTsddXyQGQV3yjqylOF2AgsAf256uuA=
|
||||
-----END CERTIFICATE-----
|
Binary file not shown.
@ -1,50 +0,0 @@
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIEzTCCA7WgAwIBAgIUfRjXKciCGA4XbhbhxbAwfpcLGmowDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
||||
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMFUxCzAJBgNVBAYT
|
||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxHDAaBgNVBAsME1RpbWVzdGFtcCBB
|
||||
dXRob3JpdHkxETAPBgNVBAMMCFRlc3QgVFNBMIIBIjANBgkqhkiG9w0BAQEFAAOC
|
||||
AQ8AMIIBCgKCAQEAor220wp2zqj6Fe1VT/yic4LJcfMn1/ZWhsE7L86krULRvI+N
|
||||
JY0fOVg/24MtyOXbnm7nYOyYTlR9n2kqm4fEgsz+GDQxXLHgyLh3aF4ueDzoFt0v
|
||||
8G3vJfD+4N27XAYJ5V4f4s4VJRDIm0P/BvFGY9J/zICjC83F3OLdnkOD88O8QD6q
|
||||
FwWdtBYNqxQX1LAwy3ORe5aTubdVkHV02JhdKAC/xy5nfhynuV4KfYyel2nHrI1i
|
||||
54UXWdOrlD/XIKPiXpuEGcXhYTrTHigH+yR9ybs9hotGvuHTEjcxEuJvEQJX+qV4
|
||||
eJAIexITDW/yK+maWPLijO3bZ9/JodX+fRCnPQIDAQABo4IBiDCCAYQwDAYDVR0T
|
||||
AQH/BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDAdBgNVHQ4EFgQUKWCqogni
|
||||
6SseJ/P6LXo0M2cK++QwHwYDVR0jBBgwFoAU/5nNuG4Tm4v2y9uKf428/4fVQesw
|
||||
gYQGCCsGAQUFBwEBBHgwdjA5BggrBgEFBQcwAoYtaHR0cDovL1RTQUNBLnRpbWVz
|
||||
dGFtcGF1dGhvcml0eS5jb20vVFNBQ0EuY3J0MDkGCCsGAQUFBzABhi1odHRwOi8v
|
||||
b2NzcC5UU0FDQS50aW1lc3RhbXBhdXRob3JpdHkuY29tOjkwODAwPgYDVR0fBDcw
|
||||
NTAzoDGgL4YtaHR0cDovL1RTQUNBLnRpbWVzdGFtcGF1dGhvcml0eS5jb20vVFNB
|
||||
Q0EuY3JsMFUGA1UdHgROMEygGDAKggh0ZXN0LmNvbTAKggh0ZXN0Lm9yZ6EwMAqH
|
||||
CAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMA0G
|
||||
CSqGSIb3DQEBCwUAA4IBAQB4YXa5nVWUzWSsUDMfYFTEETOe8boUErwfrDNBuj6z
|
||||
B5en20FhI49i6PCYEfNq3vrAtPOEFJj+KPomN3C46VLxbUEvqWLdq6EyzWvVVmXK
|
||||
VLeC0qV0m6CFM8GplaWzZdfFTQaaLUhgY08ZU2gp4QsoS2YjAosxlZrNSm6pBbv3
|
||||
q+Og1KeSK8gKS0V89k+6e3LOEF6KaNWKSkoz5xDniQY//mTjiDcNmYUh0KhHfhdU
|
||||
eO92M82uJSaDqnRs5HsWPs6z6qdfpuvj++OtQ1VCM2p5SEH2sEomdeN3YYChuG4h
|
||||
yzn0mYAdbTyGJHlFm17AH+SQRbVqCKYdHDaqsMb+fWzi
|
||||
-----END CERTIFICATE-----
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDkDCCAnigAwIBAgIUJ0nfE+EVsIThltlY2LHVWMJVIq4wDQYJKoZIhvcNAQEL
|
||||
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
|
||||
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
|
||||
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0yNjExMTAwMDAwMDBaMGAxCzAJBgNVBAYT
|
||||
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB
|
||||
dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG
|
||||
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGOTX1f9dmtUiyzlsUInRIGfRMya338SVx
|
||||
vYGeOwdpTSSGlYUVwR9AuFewQF5+klelstCJe+SoUG0AdzS30mRWlQrhip4UdvdW
|
||||
T2gkNKbSn6DQzlWoQej9izqRLxAsbuszgkvnLOBEmPaLimDsCgu0bAN95Hp0Hls9
|
||||
O/fVmzh8VuV4iscxc7q13ZB7CylWgwd55CFEGd/jpJ6kMwSHbOLoBWp4GQ3KxR+c
|
||||
ASAo0FapU2WSZB2EYWszRiyq91X+AvIYN4ypTv7RccgfUvnZ2qFykJAkf/wgkynu
|
||||
Qg7rCUNfUEpDc7jlqtDWR7iLrtHBkA17C3IU8ymmKQYWfw3ZyBwvAgMBAAGjQjBA
|
||||
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP+ZzbhuE5uL9svbin+NvP+H1UHr
|
||||
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAbj3aFwIUxvzwgywO
|
||||
gj01JM8GNbw1E4MGdkaNI8rgeY8ay15ZXhR9NpRWWb6Y7IXPq5XhuEktVte5Z4Kf
|
||||
XLBrr7Xe9VVqJL9zd1tMzOEM/zG77rZf/iXBTZLkCtQc/GOEY4TTWKNEl5hiWVE0
|
||||
po97GX5XHoeyHlWQ75sd9z6MxFxmvdp9/uyYD700e9sd5gcD8LGvHw2DNy8vntYV
|
||||
ia9h95N9i1umffxU460o8W5GoIcsD13B3YftvnWhGSXqovBRFgcPAQZ4eW9Qh/zA
|
||||
4zQBQrRvmREPihXVdgtWVpbRchP99oSZBrYr7Hh/P69rycklquqxJl1ol1wbT6dK
|
||||
S5Gmng==
|
||||
-----END CERTIFICATE-----
|
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:
|
||||
"""
|
51
tests/client_http.py
Normal file
51
tests/client_http.py
Normal file
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/python3
|
||||
"""Implementation of a HTTP client"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import http.client
|
||||
|
||||
RESULT_PATH = os.getcwd()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Creating a POST Request"""
|
||||
ret = 0
|
||||
try:
|
||||
file_path = os.path.join(RESULT_PATH, "./Testing/logs/url.log")
|
||||
with open(file_path, mode="r", encoding="utf-8") as file:
|
||||
url = file.readline()
|
||||
host, port = url.split(":")
|
||||
conn = http.client.HTTPConnection(host, port)
|
||||
conn.request('POST', '/kill_server')
|
||||
response = conn.getresponse()
|
||||
print("HTTP status code:", response.getcode(), end=', ')
|
||||
try:
|
||||
text = response.read()
|
||||
print(text.decode("UTF-8"), end='', flush=True)
|
||||
except OSError as err:
|
||||
print(f"Warning: {err}")
|
||||
conn.close()
|
||||
except OSError as err:
|
||||
print(f"OSError: {err}")
|
||||
ret = err.errno
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print(f"HTTP client error: {err}")
|
||||
ret = err
|
||||
finally:
|
||||
sys.exit(ret)
|
||||
|
||||
|
||||
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,260 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
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/"
|
||||
rm -rf "../certs"
|
||||
|
||||
# OpenSSL settings
|
||||
CONF="${script_path}/openssl_intermediate.cnf"
|
||||
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 > "tsa-serial"
|
||||
echo 1001 > "CA/crlnumber"
|
||||
date > "makecerts.log"
|
||||
"$OPENSSL" version 2>> "makecerts.log" 1>&2
|
||||
echo -n "$password" > tmp/password.txt
|
||||
|
||||
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 $?
|
||||
|
||||
printf "\nGenerate intermediate CA certificate\n" >> "makecerts.log"
|
||||
"$OPENSSL" genrsa -out CA/intermediate.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/intermediate.key -out CA/intermediate.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/intermediate.csr -out CA/intermediate.cer \
|
||||
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
|
||||
test_result $?
|
||||
"$OPENSSL" x509 -in CA/intermediate.cer -out tmp/intermediate.pem \
|
||||
2>> "makecerts.log" 1>&2
|
||||
test_result $?
|
||||
|
||||
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 "\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/intermediate.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 "\nConvert revoked certificate to SPC format\n" >> "makecerts.log"
|
||||
"$OPENSSL" crl2pkcs7 -in tmp/CACertCRL.pem -certfile tmp/revoked.pem -outform DER -out tmp/revoked.spc \
|
||||
2>> "makecerts.log" 1>&2
|
||||
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 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 $?
|
||||
|
||||
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/intermediate.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 $?
|
||||
|
||||
printf "\nConvert the certificate and the key into a PKCS#12 container\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/intermediate.pem >> tmp/expired.pem 2>> "makecerts.log"
|
||||
test_result $?
|
||||
|
||||
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\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/intermediate.pem -a -s tmp/CACert.pem -a -s tmp/CACertCRL.pem \
|
||||
-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.p12 -a -s tmp/cert.der -a -s tmp/cert.spc \
|
||||
-a -s tmp/crosscert.pem -a -s tmp/expired.pem -a -s tmp/revoked.pem -a -s tmp/revoked.spc \
|
||||
-a -s tmp/TSA.pem -a -s tmp/TSA.key -a -s tmp/tsa-chain.pem
|
||||
then
|
||||
mkdir "../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
|
||||
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,72 +0,0 @@
|
||||
# OpenSSL intermediate CA configuration file
|
||||
|
||||
[ default ]
|
||||
name = intermediate
|
||||
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
|
||||
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,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
|
||||
ess_cert_id_chain = yes
|
||||
ess_cert_id_alg = sha256
|
||||
crypto_device = builtin
|
||||
|
@ -1,83 +0,0 @@
|
||||
# OpenSSL Root Timestamp Authority configuration file
|
||||
|
||||
[ default ]
|
||||
name = TSACA
|
||||
domain_suffix = timestampauthority.com
|
||||
aia_url = http://$name.$domain_suffix/$name.crt
|
||||
crl_url = http://$name.$domain_suffix/$name.crl
|
||||
ocsp_url = http://ocsp.$name.$domain_suffix:9080
|
||||
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
|
||||
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
|
||||
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
|
||||
authorityInfoAccess = @issuer_info
|
||||
crlDistributionPoints = @crl_info
|
||||
nameConstraints = @name_constraints
|
||||
|
||||
[ issuer_info ]
|
||||
caIssuers;URI.0 = $aia_url
|
||||
OCSP;URI.0 = $ocsp_url
|
||||
|
||||
[ crl_info ]
|
||||
URI.0 = $crl_url
|
||||
|
||||
[ 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:
|
||||
"""
|
BIN
tests/files/unsigned.256appx
Normal file
BIN
tests/files/unsigned.256appx
Normal file
Binary file not shown.
BIN
tests/files/unsigned.512appx
Normal file
BIN
tests/files/unsigned.512appx
Normal file
Binary file not shown.
BIN
tests/files/unsigned.cat
Executable file → Normal file
BIN
tests/files/unsigned.cat
Executable file → Normal file
Binary file not shown.
0
tests/files/unsigned.exe
Executable file → Normal file
0
tests/files/unsigned.exe
Executable file → Normal file
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>
|
532
tests/make_certificates.py
Normal file
532
tests/make_certificates.py
Normal file
@ -0,0 +1,532 @@
|
||||
#!/usr/bin/python3
|
||||
"""Make test certificates"""
|
||||
|
||||
import os
|
||||
import datetime
|
||||
import cryptography
|
||||
from cryptography import x509
|
||||
from cryptography.x509.oid import NameOID
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
|
||||
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) -> x509.Name:
|
||||
"""Return x509.Name"""
|
||||
return x509.Name(
|
||||
[
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, "PL"),
|
||||
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Mazovia Province"),
|
||||
x509.NameAttribute(NameOID.LOCALITY_NAME, "Warsaw"),
|
||||
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "osslsigncode"),
|
||||
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, self.unit_name),
|
||||
x509.NameAttribute(NameOID.COMMON_NAME, common_name)
|
||||
]
|
||||
)
|
||||
|
||||
def create_x509_crldp(self) -> x509.CRLDistributionPoints:
|
||||
"""Return x509.CRLDistributionPoints"""
|
||||
return x509.CRLDistributionPoints(
|
||||
[
|
||||
x509.DistributionPoint(
|
||||
full_name=[x509.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) -> x509.NameConstraints:
|
||||
"""Return x509.NameConstraints"""
|
||||
return x509.NameConstraints(
|
||||
permitted_subtrees = [x509.DNSName('test.com'), x509.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) -> (x509.Certificate, rsa.RSAPrivateKey):
|
||||
"""Generate intermediate CA certificate"""
|
||||
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
key_public = key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
)
|
||||
key_usage = x509.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 = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(self.create_x509_name("Intermediate CA"))
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.public_key(key_public)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(date_20180101)
|
||||
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=0), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(key_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(key_usage, critical=True)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, "intermediateCA.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
|
||||
return cert, key
|
||||
|
||||
|
||||
class RootCACertificate(X509Extensions):
|
||||
"""Base class for Root CA certificate"""
|
||||
|
||||
def __init__(self):
|
||||
self.key_usage = x509.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) -> (x509.Certificate, rsa.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 = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
ca_public = ca_key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||
name = self.create_x509_name(common_name)
|
||||
ca_cert = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(name)
|
||||
.issuer_name(name)
|
||||
.public_key(ca_public)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(date_20170101)
|
||||
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(self.key_usage, critical=True)
|
||||
.sign(ca_key, hashes.SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, file_name)
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(ca_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
return ca_cert, ca_key
|
||||
|
||||
def make_cross_cert(self, ca_root, root_key, ca_cert, ca_key) -> None:
|
||||
"""Generate cross-signed root CA certificate"""
|
||||
ca_public = ca_key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
ca_root.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
)
|
||||
ca_cross = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(ca_cert.subject)
|
||||
.issuer_name(ca_root.subject)
|
||||
.public_key(ca_public)
|
||||
.serial_number(ca_cert.serial_number)
|
||||
.not_valid_before(date_20180101)
|
||||
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(self.key_usage, critical=True)
|
||||
.sign(root_key, hashes.SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, "CAcross.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(ca_cross.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
|
||||
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=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.BestAvailableEncryption(PASSWORD.encode())
|
||||
)
|
||||
)
|
||||
# Write decrypted key in PEM format
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
)
|
||||
)
|
||||
# Write the key in DER format
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".der")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(key.private_bytes(
|
||||
encoding=serialization.Encoding.DER,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class TSARootCACertificate(X509Extensions):
|
||||
"""Base class for TSA certificates"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__("Timestamp Authority Root CA", 0, None)
|
||||
|
||||
def make_cert(self) -> (x509.Certificate, rsa.RSAPrivateKey):
|
||||
"""Generate a Time Stamp Authority certificate"""
|
||||
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
ca_public = ca_key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||
name = self.create_x509_name("TSA Root CA")
|
||||
key_usage = x509.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 = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(name)
|
||||
.issuer_name(name)
|
||||
.public_key(ca_public)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(date_20170101)
|
||||
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(key_usage, critical=True)
|
||||
.sign(ca_key, hashes.SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, "TSACA.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(ca_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
|
||||
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=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Certificate(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) -> x509.Certificate:
|
||||
"""Generate a leaf certificate"""
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
)
|
||||
extended_key_usage = x509.ExtendedKeyUsage(
|
||||
[x509.oid.ExtendedKeyUsageOID.CODE_SIGNING]
|
||||
)
|
||||
cert = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(self.create_x509_name(self.common_name))
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.public_key(public_key)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(not_before)
|
||||
.not_valid_after(not_before + datetime.timedelta(days=days))
|
||||
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=False)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(extended_key_usage, critical=False)
|
||||
.add_extension(self.create_x509_crldp(), critical=False)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
)
|
||||
# Write PEM file and attach intermediate certificate
|
||||
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(self.issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
|
||||
return cert
|
||||
|
||||
def revoke_cert(self, serial_number, file_name) -> None:
|
||||
"""Revoke a certificate"""
|
||||
revoked = (
|
||||
x509.RevokedCertificateBuilder()
|
||||
.serial_number(serial_number)
|
||||
.revocation_date(date_20190101)
|
||||
.add_extension(x509.CRLReason(x509.ReasonFlags.superseded), critical=False)
|
||||
.build()
|
||||
)
|
||||
# Generate CRL
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
)
|
||||
crl = (
|
||||
x509.CertificateRevocationListBuilder()
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.last_update(date_20190101)
|
||||
.next_update(date_20190101 + datetime.timedelta(days=7300))
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(x509.CRLNumber(4097), critical=False)
|
||||
.add_revoked_certificate(revoked)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
)
|
||||
# Write CRL file
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(crl.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".der")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(crl.public_bytes(encoding=serialization.Encoding.DER))
|
||||
|
||||
|
||||
class LeafCACertificate(Certificate):
|
||||
"""Base class for a leaf certificate"""
|
||||
|
||||
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
|
||||
super().__init__(issuer_cert, issuer_key, "CSP", common, cdp_port, "intermediateCA")
|
||||
|
||||
|
||||
class LeafTSACertificate(Certificate):
|
||||
"""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) -> x509.Certificate:
|
||||
"""Generate a TSA leaf certificate"""
|
||||
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
)
|
||||
|
||||
# The TSA signing certificate must have exactly one extended key usage
|
||||
# assigned to it: timeStamping. The extended key usage must also be critical,
|
||||
# otherwise the certificate is going to be refused.
|
||||
extended_key_usage = x509.ExtendedKeyUsage(
|
||||
[x509.oid.ExtendedKeyUsageOID.TIME_STAMPING]
|
||||
)
|
||||
cert = (
|
||||
x509.CertificateBuilder()
|
||||
.subject_name(self.create_x509_name(self.common_name))
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.public_key(public_key)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.not_valid_before(not_before)
|
||||
.not_valid_after(not_before + datetime.timedelta(days=days))
|
||||
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(extended_key_usage, critical=True)
|
||||
.add_extension(self.create_x509_crldp(), critical=False)
|
||||
.add_extension(self.create_x509_name_constraints(), critical=False)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
)
|
||||
# Write PEM file and attach intermediate certificate
|
||||
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(self.issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
|
||||
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 = rsa.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=serialization.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 = rsa.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=serialization.Encoding.PEM))
|
||||
file.write(issuer_cert.public_bytes(encoding=serialization.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 = (
|
||||
serialization.PrivateFormat.PKCS12.encryption_builder()
|
||||
.key_cert_algorithm(serialization.pkcs12.PBES.PBESv1SHA1And3KeyTripleDESCBC)
|
||||
.kdf_rounds(5000)
|
||||
.build(PASSWORD.encode())
|
||||
)
|
||||
else:
|
||||
encryption = serialization.BestAvailableEncryption(PASSWORD.encode())
|
||||
|
||||
# Generate PKCS#12 struct
|
||||
pkcs12 = serialization.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:
|
||||
"""
|
175
tests/server_http.py
Normal file
175
tests/server_http.py
Normal file
@ -0,0 +1,175 @@
|
||||
#!/usr/bin/python3
|
||||
"""Implementation of a HTTP server"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
from urllib.parse import urlparse
|
||||
from http.server import SimpleHTTPRequestHandler, HTTPServer
|
||||
from socketserver import ThreadingMixIn
|
||||
from make_certificates import CertificateMaker
|
||||
|
||||
RESULT_PATH = os.getcwd()
|
||||
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
|
||||
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||
CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
|
||||
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
||||
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
||||
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
||||
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
||||
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
|
||||
|
||||
OPENSSL_TS = ["openssl", "ts",
|
||||
"-reply", "-config", OPENSSL_CONF,
|
||||
"-passin", "pass:passme",
|
||||
"-queryfile", REQUEST,
|
||||
"-out", RESPONS]
|
||||
|
||||
|
||||
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
"""This variant of HTTPServer creates a new thread for every connection"""
|
||||
daemon_threads = True
|
||||
|
||||
|
||||
class RequestHandler(SimpleHTTPRequestHandler):
|
||||
"""Handle the HTTP POST request that arrive at the server"""
|
||||
|
||||
def __init__(self, request, client_address, server):
|
||||
# Save the server handle
|
||||
self.server = server
|
||||
SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
|
||||
|
||||
def do_GET(self): # pylint: disable=invalid-name
|
||||
""""Serves the GET request type"""
|
||||
try:
|
||||
url = urlparse(self.path)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/pkix-crl")
|
||||
self.end_headers()
|
||||
resp_data = b''
|
||||
# Read the file and send the contents
|
||||
if url.path == "/intermediateCA":
|
||||
file_path = os.path.join(CERTS_PATH, "./CACertCRL.der")
|
||||
with open(file_path, 'rb') as file:
|
||||
resp_data = file.read()
|
||||
if url.path == "/TSACA":
|
||||
file_path = os.path.join(CERTS_PATH, "./TSACertCRL.der")
|
||||
with open(file_path, 'rb') as file:
|
||||
resp_data = file.read()
|
||||
self.wfile.write(resp_data)
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print("HTTP GET request error: {}".format(err))
|
||||
|
||||
|
||||
def do_POST(self): # pylint: disable=invalid-name
|
||||
""""Serves the POST request type"""
|
||||
try:
|
||||
url = urlparse(self.path)
|
||||
self.send_response(200)
|
||||
if url.path == "/kill_server":
|
||||
self.log_message(f"Deleting file: {URL_LOG}")
|
||||
os.remove(f"{URL_LOG}")
|
||||
self.send_header('Content-type', 'text/plain')
|
||||
self.end_headers()
|
||||
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
|
||||
self.server.shutdown()
|
||||
else:
|
||||
content_length = int(self.headers['Content-Length'])
|
||||
post_data = self.rfile.read(content_length)
|
||||
with open(REQUEST, mode="wb") as file:
|
||||
file.write(post_data)
|
||||
openssl = subprocess.run(OPENSSL_TS, check=True, universal_newlines=True)
|
||||
openssl.check_returncode()
|
||||
self.send_header("Content-type", "application/timestamp-reply")
|
||||
self.end_headers()
|
||||
resp_data = b''
|
||||
with open(RESPONS, mode="rb") as file:
|
||||
resp_data = file.read()
|
||||
self.wfile.write(resp_data)
|
||||
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print("HTTP POST request error: {}".format(err))
|
||||
|
||||
|
||||
class HttpServerThread():
|
||||
"""TSA server thread handler"""
|
||||
# pylint: disable=too-few-public-methods
|
||||
|
||||
def __init__(self):
|
||||
self.server = None
|
||||
self.server_thread = None
|
||||
|
||||
def start_server(self, port) -> (int):
|
||||
"""Starting HTTP server on 127.0.0.1 and a random available port for binding"""
|
||||
self.server = ThreadingHTTPServer(('127.0.0.1', port), RequestHandler)
|
||||
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
||||
self.server_thread.start()
|
||||
hostname, port = self.server.server_address[:2]
|
||||
print("HTTP server started, URL http://{}:{}".format(hostname, port))
|
||||
return port
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Start HTTP server, make test certificates."""
|
||||
|
||||
ret = 0
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=0,
|
||||
help="port number"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
server = HttpServerThread()
|
||||
port = server.start_server(args.port)
|
||||
with open(URL_LOG, mode="w", encoding="utf-8") as file:
|
||||
file.write("127.0.0.1:{}".format(port))
|
||||
tests = CertificateMaker(port, SERVER_LOG)
|
||||
tests.make_certs()
|
||||
except OSError as err:
|
||||
print("OSError: {}".format(err))
|
||||
ret = err.errno
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print("Error: {}".format(err))
|
||||
ret = 1
|
||||
finally:
|
||||
sys.exit(ret)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
fpid = os.fork()
|
||||
if fpid > 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:
|
||||
print("Fork #1 failed: {} {}".format(ferr.errno, ferr.strerror))
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
fpid = os.fork()
|
||||
if fpid > 0:
|
||||
sys.exit(0)
|
||||
except OSError as ferr:
|
||||
print("Fork #2 failed: {} {}".format(ferr.errno, ferr.strerror))
|
||||
sys.exit(1)
|
||||
|
||||
# Start the daemon main loop
|
||||
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:
|
||||
"""
|
149
tests/server_http.pyw
Normal file
149
tests/server_http.pyw
Normal file
@ -0,0 +1,149 @@
|
||||
#!/usr/bin/python3
|
||||
"""Windows: Implementation of a HTTP server"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
from urllib.parse import urlparse
|
||||
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
|
||||
from make_certificates import CertificateMaker
|
||||
|
||||
RESULT_PATH = os.getcwd()
|
||||
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
|
||||
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||
CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
|
||||
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
||||
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
||||
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
||||
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
||||
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
|
||||
|
||||
|
||||
OPENSSL_TS = ["openssl", "ts",
|
||||
"-reply", "-config", OPENSSL_CONF,
|
||||
"-passin", "pass:passme",
|
||||
"-queryfile", REQUEST,
|
||||
"-out", RESPONS]
|
||||
|
||||
|
||||
class RequestHandler(SimpleHTTPRequestHandler):
|
||||
"""Handle the HTTP POST request that arrive at the server"""
|
||||
|
||||
def __init__(self, request, client_address, server):
|
||||
# Save the server handle
|
||||
self.server = server
|
||||
SimpleHTTPRequestHandler.__init__(self, request, client_address, server)
|
||||
|
||||
def do_GET(self): # pylint: disable=invalid-name
|
||||
""""Serves the GET request type"""
|
||||
try:
|
||||
url = urlparse(self.path)
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/pkix-crl")
|
||||
self.end_headers()
|
||||
resp_data = b''
|
||||
# Read the file and send the contents
|
||||
if url.path == "/intermediateCA":
|
||||
file_path = os.path.join(CERTS_PATH, "./CACertCRL.der")
|
||||
with open(file_path, 'rb') as file:
|
||||
resp_data = file.read()
|
||||
if url.path == "/TSACA":
|
||||
file_path = os.path.join(CERTS_PATH, "./TSACertCRL.der")
|
||||
with open(file_path, 'rb') as file:
|
||||
resp_data = file.read()
|
||||
self.wfile.write(resp_data)
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print("HTTP GET request error: {}".format(err))
|
||||
|
||||
|
||||
def do_POST(self): # pylint: disable=invalid-name
|
||||
""""Serves the POST request type"""
|
||||
try:
|
||||
url = urlparse(self.path)
|
||||
self.send_response(200)
|
||||
if url.path == "/kill_server":
|
||||
self.log_message(f"Deleting file: {URL_LOG}")
|
||||
os.remove(f"{URL_LOG}")
|
||||
self.send_header('Content-type', 'text/plain')
|
||||
self.end_headers()
|
||||
self.wfile.write(bytes('Shutting down HTTP server', 'utf-8'))
|
||||
self.server.shutdown()
|
||||
else:
|
||||
content_length = int(self.headers['Content-Length'])
|
||||
post_data = self.rfile.read(content_length)
|
||||
with open(REQUEST, mode="wb") as file:
|
||||
file.write(post_data)
|
||||
openssl = subprocess.run(OPENSSL_TS,
|
||||
check=True, universal_newlines=True)
|
||||
openssl.check_returncode()
|
||||
self.send_header("Content-type", "application/timestamp-reply")
|
||||
self.end_headers()
|
||||
resp_data = b''
|
||||
with open(RESPONS, mode="rb") as file:
|
||||
resp_data = file.read()
|
||||
self.wfile.write(resp_data)
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print("HTTP POST request error: {}".format(err))
|
||||
|
||||
|
||||
class HttpServerThread():
|
||||
"""TSA server thread handler"""
|
||||
# pylint: disable=too-few-public-methods
|
||||
|
||||
def __init__(self):
|
||||
self.server = None
|
||||
self.server_thread = None
|
||||
|
||||
def start_server(self, port) -> (int):
|
||||
"""Starting HTTP server on 127.0.0.1 and a random available port for binding"""
|
||||
self.server = ThreadingHTTPServer(('127.0.0.1', port), RequestHandler)
|
||||
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
||||
self.server_thread.start()
|
||||
hostname, port = self.server.server_address[:2]
|
||||
print("HTTP server started, URL http://{}:{}".format(hostname, port))
|
||||
return port
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Start HTTP server"""
|
||||
|
||||
ret = 0
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
type=int,
|
||||
default=0,
|
||||
help="port number"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
try:
|
||||
sys.stdout = open(SERVER_LOG, "w")
|
||||
sys.stderr = open(SERVER_LOG, "a")
|
||||
server = HttpServerThread()
|
||||
port = server.start_server(args.port)
|
||||
with open(URL_LOG, mode="w") as file:
|
||||
file.write("127.0.0.1:{}".format(port))
|
||||
tests = CertificateMaker(port, SERVER_LOG)
|
||||
tests.make_certs()
|
||||
except OSError as err:
|
||||
print("OSError: {}".format(err))
|
||||
ret = err.errno
|
||||
finally:
|
||||
sys.exit(ret)
|
||||
|
||||
|
||||
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:
|
||||
"""
|
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:
|
||||
"""
|
@ -1,152 +0,0 @@
|
||||
"""Implementation of a Time Stamping Authority HTTP server"""
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import os
|
||||
import pathlib
|
||||
import subprocess
|
||||
import sys
|
||||
import threading
|
||||
from http.server import BaseHTTPRequestHandler, HTTPServer
|
||||
|
||||
RESULT_PATH = os.getcwd()
|
||||
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
|
||||
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||
CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
|
||||
DEFAULT_IN = os.path.join(FILES_PATH, "./unsigned.exe")
|
||||
DEFAULT_OUT = os.path.join(FILES_PATH, "./ts.exe")
|
||||
DEFAULT_CERT = os.path.join(CERTS_PATH, "./cert.pem")
|
||||
DEFAULT_KEY = os.path.join(CERTS_PATH, "./key.pem")
|
||||
DEFAULT_CROSSCERT = os.path.join(CERTS_PATH, "./crosscert.pem")
|
||||
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
||||
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
||||
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||
|
||||
if os.path.exists(os.path.join(RESULT_PATH, "./Release/")):
|
||||
OSSLSIGNCODE_FILE = os.path.join(RESULT_PATH, "./Release/osslsigncode")
|
||||
elif os.path.exists(os.path.join(RESULT_PATH, "./Debug/")):
|
||||
OSSLSIGNCODE_FILE = os.path.join(RESULT_PATH, "./Debug/osslsigncode")
|
||||
else:
|
||||
OSSLSIGNCODE_FILE = os.path.join(RESULT_PATH, "./osslsigncode")
|
||||
|
||||
DEFAULT_OPENSSL = ["openssl", "ts",
|
||||
"-reply", "-config", OPENSSL_CONF,
|
||||
"-passin", "pass:passme",
|
||||
"-queryfile", REQUEST,
|
||||
"-out", RESPONS]
|
||||
|
||||
|
||||
class RequestHandler(BaseHTTPRequestHandler):
|
||||
"""Handle the HTTP POST request that arrive at the server"""
|
||||
|
||||
def do_POST(self):
|
||||
""""Serves the POST request type"""
|
||||
try:
|
||||
content_length = int(self.headers['Content-Length'])
|
||||
post_data = self.rfile.read(content_length)
|
||||
with open(REQUEST, mode="wb") as file:
|
||||
file.write(post_data)
|
||||
openssl = subprocess.run(DEFAULT_OPENSSL,
|
||||
check=True, universal_newlines=True)
|
||||
openssl.check_returncode()
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "application/timestamp-reply")
|
||||
self.end_headers()
|
||||
resp_data = None
|
||||
with open(RESPONS, mode="rb") as file:
|
||||
resp_data = file.read()
|
||||
self.wfile.write(resp_data)
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print(f"HTTP POST request error: {err}")
|
||||
|
||||
|
||||
class HttpServerThread():
|
||||
"""TSA server thread handler"""
|
||||
|
||||
def __init__(self):
|
||||
self.server = None
|
||||
self.server_thread = None
|
||||
|
||||
def start_server(self) -> (str, int):
|
||||
"""Starting TSA server on localhost and a first available port"""
|
||||
self.server = HTTPServer(("127.0.0.1", 0), RequestHandler)
|
||||
self.server_thread = threading.Thread(target=self.server.serve_forever)
|
||||
self.server_thread.start()
|
||||
hostname, port = self.server.server_address[:2]
|
||||
print(f"Timestamp server started, URL: http://{hostname}:{port}")
|
||||
return hostname, port
|
||||
|
||||
def shut_down(self):
|
||||
"""Shutting down the server"""
|
||||
if self.server:
|
||||
self.server.shutdown()
|
||||
self.server_thread.join()
|
||||
print("Server is down")
|
||||
|
||||
|
||||
def parse_args() -> str:
|
||||
"""Parse the command-line arguments."""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--input",
|
||||
type=pathlib.Path,
|
||||
default=DEFAULT_IN,
|
||||
help="input file"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--output",
|
||||
type=pathlib.Path,
|
||||
default=DEFAULT_OUT,
|
||||
help="output file"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--certs",
|
||||
type=pathlib.Path,
|
||||
default=DEFAULT_CERT,
|
||||
help="signing certificate"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--key",
|
||||
type=pathlib.Path,
|
||||
default=DEFAULT_KEY,
|
||||
help="private key"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--crosscert",
|
||||
type=pathlib.Path,
|
||||
default=DEFAULT_CROSSCERT,
|
||||
help="additional certificates"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
program = [OSSLSIGNCODE_FILE, "sign", "-in", args.input, "-out", args.output,
|
||||
"-certs", args.certs, "-key", args.key,
|
||||
"-addUnauthenticatedBlob", "-add-msi-dse", "-comm", "-ph", "-jp", "low",
|
||||
"-h", "sha384", "-time", "1556668800", "-i", "https://www.osslsigncode.com/",
|
||||
"-n", "osslsigncode", "-ac", args.crosscert, "-ts"]
|
||||
return program
|
||||
|
||||
def main() -> None:
|
||||
"""Main program"""
|
||||
ret = 0
|
||||
program = parse_args()
|
||||
server = HttpServerThread()
|
||||
hostname, port = server.start_server()
|
||||
program.append(f"{hostname}:{port}")
|
||||
try:
|
||||
osslsigncode = subprocess.run(program, check=True, universal_newlines=True)
|
||||
osslsigncode.check_returncode()
|
||||
except subprocess.CalledProcessError as err:
|
||||
ret = err.returncode
|
||||
except OSError as err:
|
||||
print(f"OSError: {err}")
|
||||
ret = err.errno
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
print(f"osslsigncode error: {err}")
|
||||
ret = 1
|
||||
finally:
|
||||
server.shut_down()
|
||||
sys.exit(ret)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
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",
|
||||
"dependencies": [
|
||||
"openssl",
|
||||
"curl",
|
||||
{
|
||||
"name": "python3",
|
||||
"platform": "!(windows & static) & !osx"
|
||||
}
|
||||
]
|
||||
"zlib"
|
||||
],
|
||||
"builtin-baseline": "9edb1b8e590cc086563301d735cae4b6e732d2d2"
|
||||
}
|
||||
|
Reference in New Issue
Block a user