mirror of
https://github.com/mtrojnar/osslsigncode.git
synced 2025-07-02 19:22:47 -05:00
Compare commits
60 Commits
Author | SHA1 | Date | |
---|---|---|---|
8329a14f8b | |||
343b0af1fe | |||
d440f32780 | |||
fb082942d2 | |||
025e808c01 | |||
23b6d7782c | |||
4c3a1e887c | |||
97ee163e31 | |||
dfc3e46a77 | |||
ff9a6d3593 | |||
e81b08e02d | |||
0c85d54800 | |||
772bc22c94 | |||
d65a2b5286 | |||
a3fcf41e1a | |||
e00caac3db | |||
dd9b81281f | |||
6b56aef073 | |||
52bfff5756 | |||
4d52e9cc4b | |||
3292b02650 | |||
50c23daa4c | |||
9b7dae4572 | |||
62438908cb | |||
829e770250 | |||
a6c7c25dae | |||
10ca3a06ea | |||
9ea7e85468 | |||
68e8845ef1 | |||
475ea95ba3 | |||
d352dcc1a5 | |||
7734382436 | |||
d425d8bf25 | |||
4568c890cc | |||
4bd167a8be | |||
e7405fa839 | |||
776e2ec7b6 | |||
838aaaee8d | |||
e8f19a6efe | |||
3a8e25e5bb | |||
7d1b460dfe | |||
bc3e9e2172 | |||
21bce757ef | |||
6a43f62835 | |||
8780e6f8e4 | |||
78a23caa54 | |||
d92927aff4 | |||
4f412b5989 | |||
e6f3ff631d | |||
09135aabb8 | |||
de983e680f | |||
dc827b94e5 | |||
40ce811701 | |||
db5b4c4dc0 | |||
4ee429792d | |||
27686c0b0c | |||
21133f9c3b | |||
64305d6415 | |||
4dd836bab1 | |||
f57c213207 |
120
.github/workflows/ci.yml
vendored
120
.github/workflows/ci.yml
vendored
@ -1,4 +1,4 @@
|
||||
name: CI
|
||||
name: Continuous Integration
|
||||
|
||||
on:
|
||||
push:
|
||||
@ -7,7 +7,7 @@ on:
|
||||
env:
|
||||
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
|
||||
BUILD_TYPE: Release
|
||||
version: osslsigncode-2.9
|
||||
version: osslsigncode-2.10
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@ -27,14 +27,8 @@ jobs:
|
||||
os: ubuntu-22.04
|
||||
generator: Unix Makefiles
|
||||
vcpkg_root:
|
||||
- id: ubuntu-20.04
|
||||
triplet: x64-linux
|
||||
compiler: gcc
|
||||
os: ubuntu-20.04
|
||||
generator: Unix Makefiles
|
||||
vcpkg_root:
|
||||
- id: macOS
|
||||
triplet: x64-osx
|
||||
triplet: arm64-osx
|
||||
compiler: clang
|
||||
os: macOS-latest
|
||||
generator: Unix Makefiles
|
||||
@ -107,17 +101,23 @@ jobs:
|
||||
if: matrix.compiler == 'mingw'
|
||||
run: echo "D:/a/_temp/msys64/mingw64/bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
|
||||
|
||||
- name: Install apt dependencies (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get remove needrestart || echo Ignored
|
||||
sudo apt-get install -y libssl-dev zlib1g-dev python3-cryptography
|
||||
|
||||
- name: Install brew dependencies (macOS)
|
||||
- name: Set up Python (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.13'
|
||||
update-environment: false
|
||||
architecture: 'arm64'
|
||||
|
||||
- name: Set up Python virtual environment (Linux/macOS)
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
brew install python@3.8
|
||||
python -m venv --system-site-packages --copies venv
|
||||
|
||||
- name: Set up Python virtual environment (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
python.exe -m venv --system-site-packages --copies venv
|
||||
|
||||
- name: Install Xcode (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
@ -128,46 +128,66 @@ jobs:
|
||||
- name: Setup the oldest supported version of cmake (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
uses: jwlawson/actions-setup-cmake@v2.0
|
||||
with:
|
||||
cmake-version: '3.17.0'
|
||||
|
||||
- name: Install python3 cryptography module (Linux)
|
||||
if: runner.os == 'Linux'
|
||||
run: |
|
||||
source venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
python -m pip install --upgrade cryptography
|
||||
python -c "import sys; print(sys.executable)"
|
||||
python --version
|
||||
python -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||
|
||||
- name: Install python3 cryptography module (macOS)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
python3.8 -m ensurepip
|
||||
python3.8 -m pip install --upgrade pip
|
||||
python3.8 -m pip install cryptography
|
||||
source venv/bin/activate
|
||||
python -m pip install --upgrade pip
|
||||
ARCHFLAGS="-arch arm64" python -m pip install --upgrade cryptography
|
||||
python -c "import sys; print(sys.executable)"
|
||||
python --version
|
||||
python -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||
|
||||
- name: Install python3 cryptography module (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
C:/hostedtoolcache/windows/Python/3.12.3/x64/python3.exe -m ensurepip
|
||||
C:/hostedtoolcache/windows/Python/3.12.3/x64/python.exe -m pip install --upgrade pip
|
||||
C:/hostedtoolcache/windows/Python/3.12.3/x64/python.exe -m pip install cryptography
|
||||
.\venv\Scripts\Activate.ps1
|
||||
python.exe -m ensurepip
|
||||
python.exe -m pip install --upgrade pip
|
||||
python.exe -m pip install cryptography
|
||||
python.exe -c "import sys; print(sys.executable)"
|
||||
python.exe --version
|
||||
python.exe -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||
|
||||
- name: Configure CMake
|
||||
run: cmake
|
||||
-G "${{matrix.generator}}"
|
||||
-S ${{github.workspace}}
|
||||
-B ${{github.workspace}}/build
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
|
||||
-DCMAKE_INSTALL_PREFIX=${{github.workspace}}/dist
|
||||
-DVCPKG_TARGET_TRIPLET=${{matrix.triplet}}
|
||||
- name: Configure CMake (Linux/macOS)
|
||||
if: runner.os != 'Windows'
|
||||
run: |
|
||||
source venv/bin/activate
|
||||
cmake \
|
||||
-G "${{matrix.generator}}" \
|
||||
-S "${{github.workspace}}" \
|
||||
-B "${{github.workspace}}/build" \
|
||||
-DCMAKE_OSX_ARCHITECTURES=arm64 \
|
||||
-DCMAKE_BUILD_TYPE="${{env.BUILD_TYPE}}" \
|
||||
-DCMAKE_INSTALL_PREFIX="${{github.workspace}}/dist"
|
||||
|
||||
- name: Configure CMake (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
run: |
|
||||
.\venv\Scripts\Activate.ps1
|
||||
cmake `
|
||||
-G "${{matrix.generator}}" `
|
||||
-S "${{github.workspace}}" `
|
||||
-B "${{github.workspace}}/build" `
|
||||
-DCMAKE_BUILD_TYPE="${{env.BUILD_TYPE}}" `
|
||||
-DCMAKE_INSTALL_PREFIX="${{github.workspace}}/dist"
|
||||
|
||||
- name: Build
|
||||
run: cmake
|
||||
--build ${{github.workspace}}/build
|
||||
--config ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Show python version (macOS)
|
||||
working-directory: ${{github.workspace}}/build
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
python3.8 --version
|
||||
python3.8 -c "import sys; print(sys.executable)"
|
||||
python3.8 -c "import cryptography; print(f'Python3 cryptography version {cryptography.__version__}')"
|
||||
|
||||
- name: List files (Linux/macOS)
|
||||
if: runner.os != 'Windows'
|
||||
run: find .. -ls
|
||||
@ -176,9 +196,19 @@ jobs:
|
||||
if: runner.os == 'Windows'
|
||||
run: Get-ChildItem -Recurse -Name ..
|
||||
|
||||
- name: Test
|
||||
- name: Test (Linux/macOS)
|
||||
if: runner.os != 'Windows'
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: ctest -C ${{env.BUILD_TYPE}}
|
||||
run: |
|
||||
source ../venv/bin/activate
|
||||
ctest -C ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Test (Windows)
|
||||
if: runner.os == 'Windows'
|
||||
working-directory: ${{github.workspace}}/build
|
||||
run: |
|
||||
..\venv\Scripts\Activate.ps1
|
||||
ctest -C ${{env.BUILD_TYPE}}
|
||||
|
||||
- name: Upload the errors
|
||||
uses: actions/upload-artifact@v4
|
||||
|
16
.github/workflows/codespell.yml
vendored
Normal file
16
.github/workflows/codespell.yml
vendored
Normal file
@ -0,0 +1,16 @@
|
||||
name: Codespell
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
push:
|
||||
|
||||
jobs:
|
||||
codespell:
|
||||
name: Check for spelling errors
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: codespell-project/actions-codespell@master
|
||||
with:
|
||||
skip: '*.pem'
|
@ -10,8 +10,8 @@ set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
|
||||
|
||||
# configure basic project information
|
||||
project(osslsigncode
|
||||
VERSION 2.9
|
||||
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
|
||||
VERSION 2.10
|
||||
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT, MSI, APPX and script files"
|
||||
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
|
||||
LANGUAGES C)
|
||||
|
||||
@ -29,6 +29,9 @@ set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
# load CMake library modules
|
||||
include(FindOpenSSL)
|
||||
if(OPENSSL_VERSION VERSION_LESS "1.1.1")
|
||||
message(FATAL_ERROR "OpenSSL version must be at least 1.1.1")
|
||||
endif()
|
||||
if(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||
include(FindCURL)
|
||||
endif(OPENSSL_VERSION VERSION_LESS "3.0.0")
|
||||
@ -85,7 +88,7 @@ target_link_libraries(osslsigncode PRIVATE ${ZLIB_LIBRARIES})
|
||||
|
||||
if(NOT UNIX)
|
||||
# https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-shutdown
|
||||
target_link_libraries(osslsigncode PRIVATE Ws2_32.lib crypt32.lib)
|
||||
target_link_libraries(osslsigncode PRIVATE ws2_32.lib crypt32.lib)
|
||||
endif(NOT UNIX)
|
||||
|
||||
# add paths to linker search and installed rpath
|
||||
|
@ -1,4 +1,4 @@
|
||||
OpenSSL based Authenticode signing for PE/MSI/Java CAB files.
|
||||
OpenSSL based Authenticode signing for PE, CAB, CAT, MSI, APPX and script files.
|
||||
|
||||
Copyright (C) 2005-2014 Per Allansson <pallansson@gmail.com>
|
||||
Copyright (C) 2018-2022 Michał Trojnara <Michal.Trojnara@stunnel.org>
|
||||
|
14
NEWS.md
14
NEWS.md
@ -1,5 +1,19 @@
|
||||
# osslsigncode change log
|
||||
|
||||
### 2.10 (2025.06.23)
|
||||
|
||||
- added JavaScript signing
|
||||
- added PKCS#11 provider support (requires OpenSSL 3.0+)
|
||||
- added support for providers without specifying "-pkcs11module" option
|
||||
(OpenSSL 3.0+, e.g., for the upcoming CNG provider)
|
||||
- added compatibility with the CNG engine version 1.1 or later
|
||||
- added the "-engineCtrl" option to control hardware and CNG engines
|
||||
- added the '-blobFile' option to specify a file containing the blob content
|
||||
- improved unauthenticated blob support (thanks to Asger Hautop Drewsen)
|
||||
- improved UTF-8 handling for certificate subjects and issuers
|
||||
- fixed support for multiple signerInfo contentType OIDs (CTL and Authenticode)
|
||||
- fixed tests for python-cryptography >= 43.0.0
|
||||
|
||||
### 2.9 (2024.06.29)
|
||||
|
||||
- added a 64 bit long pseudo-random NONCE in the TSA request
|
||||
|
48
README.md
48
README.md
@ -23,7 +23,9 @@ tool would fail. And, so, osslsigncode was born.
|
||||
|
||||
## WHAT CAN IT DO?
|
||||
|
||||
It can sign and timestamp PE (EXE/SYS/DLL/etc), CAB, CAT and MSI files.
|
||||
It can sign and timestamp PE (EXE/SYS/DLL/etc), CAB, CAT, MSI and APPX files,
|
||||
as well as script files with extensions `.ps1`, `.ps1xml`, `.psc1`, `.psd1`,
|
||||
`.psm1`, `.cdxml`, `.mof`, and `.js`.
|
||||
It supports the equivalent of signtool.exe's "-j javasign.dll -jp low",
|
||||
i.e. add a valid signature for a CAB file containing Java files.
|
||||
It supports getting the timestamp through a proxy as well. It also
|
||||
@ -122,7 +124,7 @@ You can use a certificate and key stored in a PKCS#12 container:
|
||||
-n "Your Application" -i http://www.yourwebsite.com/ \
|
||||
-in yourapp.exe -out yourapp-signed.exe
|
||||
```
|
||||
To sign a CAB file containing java class files:
|
||||
To sign a CAB file containing Java class files:
|
||||
```
|
||||
osslsigncode sign -certs <cert-file> -key <key-file> \
|
||||
-n "Your Application" -i http://www.yourwebsite.com/ \
|
||||
@ -131,17 +133,51 @@ To sign a CAB file containing java class files:
|
||||
```
|
||||
Only the 'low' parameter is currently supported.
|
||||
|
||||
If you want to use PKCS11 token, you should indicate PKCS11 engine and module.
|
||||
If you want to use a PKCS#11 token, you should specify the PKCS#11 engine and module.
|
||||
An example of using osslsigncode with SoftHSM:
|
||||
```
|
||||
osslsigncode sign \
|
||||
-pkcs11engine /usr/lib64/engines-1.1/pkcs11.so \
|
||||
-engine /usr/lib64/engines-1.1/pkcs11.so \
|
||||
-pkcs11module /usr/lib64/pkcs11/libsofthsm2.so \
|
||||
-pkcs11cert 'pkcs11:token=softhsm-token;object=cert' \
|
||||
-key 'pkcs11:token=softhsm-token;object=key' \
|
||||
-in yourapp.exe -out yourapp-signed.exe
|
||||
```
|
||||
|
||||
Since OpenSSL 3.0, you can use a PKCS#11 token with the PKCS#11 provider.
|
||||
An example of using osslsigncode with OpenSC:
|
||||
```
|
||||
osslsigncode sign \
|
||||
-provider /usr/lib64/ossl-modules/pkcs11prov.so \
|
||||
-pkcs11module /usr/lib64/opensc-pkcs11.so \
|
||||
-pkcs11cert 'pkcs11:token=my-token;object=cert' \
|
||||
-key 'pkcs11:token=my-token;object=key' \
|
||||
-in yourapp.exe -out yourapp-signed.exe
|
||||
```
|
||||
|
||||
You can use a certificate and key stored in the Windows Certificate Store with
|
||||
the CNG engine version 1.1 or later. For more information, refer to
|
||||
|
||||
https://www.stunnel.org/cng-engine.html
|
||||
|
||||
A non-commercial edition of CNG engine is available for testing, personal,
|
||||
educational, or research purposes.
|
||||
|
||||
To use the CNG engine with osslsigncode, ensure that the `cng.dll` library is
|
||||
placed in the same directory as the `osslsigncode.exe` executable.
|
||||
|
||||
Below is an example of how to use osslsigncode with the CNG engine:
|
||||
```
|
||||
osslsigncode sign \
|
||||
-engine cng \
|
||||
-pkcs11cert osslsigncode_cert \
|
||||
-key osslsigncode_cert \
|
||||
-engineCtrl store_flags:0 \
|
||||
-engineCtrl store_name:MY \
|
||||
-engineCtrl PIN:yourpass \
|
||||
-in yourapp.exe -out yourapp-signed.exe
|
||||
```
|
||||
|
||||
You can check that the signed file is correct by right-clicking
|
||||
on it in Windows and choose Properties --> Digital Signatures,
|
||||
and then choose the signature from the list, and click on
|
||||
@ -179,13 +215,13 @@ osslsigncode.exe add -addUnauthenticatedBlob -in your_signed_file.exe -out out.e
|
||||
This feature allows for doing dumb things. Be very careful with what you put
|
||||
in the unauthenticated blob, as an attacker could modify this. Do NOT, under
|
||||
any circumstances, put a URL here that you will use to download an additional
|
||||
file. If you do do that, you would need to check the newly downloaded file is
|
||||
file. If you do that, you would need to check the newly downloaded file is
|
||||
code signed AND that it has been signed with your cert AND that it is the
|
||||
version you expect.
|
||||
|
||||
## BUGS, QUESTIONS etc.
|
||||
|
||||
Check whether your your question or suspected bug was already
|
||||
Check whether your question or suspected bug was already
|
||||
discussed on https://github.com/mtrojnar/osslsigncode/issues.
|
||||
Otherwise, open a new issue.
|
||||
|
||||
|
2
TODO.md
2
TODO.md
@ -1,4 +1,4 @@
|
||||
- signature extraction/removal/verificaton on MSI/CAB files
|
||||
- signature extraction/removal/verification on MSI/CAB files
|
||||
- clean up / untangle code
|
||||
- separate timestamping
|
||||
- remove mmap usage to increase portability
|
||||
|
62
appx.c
62
appx.c
@ -29,11 +29,6 @@
|
||||
#endif /* _MSC_VER */
|
||||
#endif /* PRIX64 */
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define fseeko _fseeki64
|
||||
#define ftello _ftelli64
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#define EOCDR_SIZE 22
|
||||
#define ZIP64_EOCD_LOCATOR_SIZE 20
|
||||
#define ZIP64_HEADER 0x01
|
||||
@ -293,7 +288,7 @@ static void zipWriteCentralDirectoryEntry(BIO *bio, uint64_t *sizeOnDisk, ZIP_CE
|
||||
static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64_t dataSize);
|
||||
static int zipOverrideFileData(ZIP_CENTRAL_DIRECTORY_ENTRY *entry, uint8_t *data, uint64_t dataSize);
|
||||
static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO *bio, uint64_t *sizeOnDisk);
|
||||
static void zipWriteLocalHeader(BIO *bio, uint64_t *sizeonDisk, ZIP_LOCAL_HEADER *heade);
|
||||
static void zipWriteLocalHeader(BIO *bio, uint64_t *sizeonDisk, ZIP_LOCAL_HEADER *header);
|
||||
static int zipEntryExist(ZIP_FILE *zip, const char *name);
|
||||
static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *md);
|
||||
static size_t zipReadFileDataByName(uint8_t **pData, ZIP_FILE *zip, const char *name);
|
||||
@ -878,11 +873,18 @@ static uint8_t *appx_calc_zip_central_directory_hash(ZIP_FILE *zip, const EVP_MD
|
||||
u_char *mdbuf = NULL;
|
||||
BIO *bhash = BIO_new(BIO_f_md());
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(bhash);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
if (!appx_write_central_directory(bhash, zip, 1, cdOffset)) {
|
||||
fprintf(stderr, "Unable to write central directory\n");
|
||||
@ -923,7 +925,7 @@ static int appx_write_central_directory(BIO *bio, ZIP_FILE *zip, int removeSigna
|
||||
if (removeSignature && !strcmp(entry->fileName, APP_SIGNATURE_FILENAME)) {
|
||||
continue;
|
||||
}
|
||||
/* APP_SIGNATURE is nt 'tainted' by offset shift after replacing the contents of [content_types] */
|
||||
/* APP_SIGNATURE is not 'tainted' by offset shift after replacing the contents of [content_types] */
|
||||
zipWriteCentralDirectoryEntry(bio, &sizeOnDisk, entry, strcmp(entry->fileName, APP_SIGNATURE_FILENAME) ? offsetDiff : 0);
|
||||
cdSize += sizeOnDisk;
|
||||
if (entry->overrideData) {
|
||||
@ -1005,11 +1007,18 @@ static uint8_t *appx_calc_zip_data_hash(uint64_t *cdOffset, ZIP_FILE *zip, const
|
||||
BIO *bhash = BIO_new(BIO_f_md());
|
||||
uint64_t noEntries = 0;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(bhash);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
*cdOffset = 0;
|
||||
for (entry = zip->centralDirectoryHead; entry != NULL; entry = entry->next) {
|
||||
@ -1421,7 +1430,7 @@ static void zipWriteCentralDirectoryEntry(BIO *bio, uint64_t *sizeOnDisk, ZIP_CE
|
||||
#if 0
|
||||
if (entry->extraFieldLen > 0 && entry->extraField)
|
||||
{
|
||||
/* TODO, if override daata, need to rewrite the extra field */
|
||||
/* TODO, if override data, need to rewrite the extra field */
|
||||
BIO_write(bio, entry->extraField, entry->extraFieldLen);
|
||||
}
|
||||
#endif
|
||||
@ -1493,6 +1502,7 @@ static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64
|
||||
|
||||
if (!get_current_position(bio, &offset)) {
|
||||
fprintf(stderr, "Unable to get offset\n");
|
||||
OPENSSL_free(header.fileName);
|
||||
OPENSSL_free(dataToWrite);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
@ -1502,6 +1512,7 @@ static int zipAppendSignatureFile(BIO *bio, ZIP_FILE *zip, uint8_t *data, uint64
|
||||
size_t check;
|
||||
if (!BIO_write_ex(bio, dataToWrite + written, toWrite, &check)
|
||||
|| check != toWrite) {
|
||||
OPENSSL_free(header.fileName);
|
||||
OPENSSL_free(dataToWrite);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
@ -1596,6 +1607,7 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
|
||||
{
|
||||
size_t check;
|
||||
ZIP_LOCAL_HEADER header;
|
||||
int ret = 0;
|
||||
|
||||
memset(&header, 0, sizeof(header));
|
||||
if (entry->offsetOfLocalHeader >= (uint64_t)zip->fileSize) {
|
||||
@ -1606,7 +1618,7 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
if (!zipReadLocalHeader(&header, zip, entry->compressedSize)) {
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
if (entry->overrideData) {
|
||||
header.compressedSize = entry->overrideData->compressedSize;
|
||||
@ -1617,14 +1629,14 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
|
||||
if (entry->overrideData) {
|
||||
if (!BIO_write_ex(bio, entry->overrideData->data, entry->overrideData->compressedSize, &check)
|
||||
|| check != entry->overrideData->compressedSize) {
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
if (entry->compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) {
|
||||
fprintf(stderr, "Corrupted compressedSize : 0x%08" PRIX64 "\n", entry->compressedSize);
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
if (fseeko(zip->file, (int64_t)entry->compressedSize, SEEK_CUR) < 0) {
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
*sizeOnDisk += entry->overrideData->compressedSize;
|
||||
} else {
|
||||
@ -1635,12 +1647,12 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
|
||||
size_t size = fread(data, 1, toWrite, zip->file);
|
||||
if (size != toWrite) {
|
||||
OPENSSL_free(data);
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
if (!BIO_write_ex(bio, data, toWrite, &check)
|
||||
|| check != toWrite) {
|
||||
OPENSSL_free(data);
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
*sizeOnDisk += toWrite;
|
||||
len -= toWrite;
|
||||
@ -1659,19 +1671,21 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
|
||||
}
|
||||
if (zip->isZip64) {
|
||||
if (fseeko(zip->file, 24, SEEK_CUR) < 0) {
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
*sizeOnDisk += 24;
|
||||
} else {
|
||||
if (fseeko(zip->file, 16, SEEK_CUR) < 0) {
|
||||
return 0; /* FAILED */
|
||||
goto out;
|
||||
}
|
||||
*sizeOnDisk += 16;
|
||||
}
|
||||
}
|
||||
ret = 1; /* OK */
|
||||
out:
|
||||
OPENSSL_free(header.fileName);
|
||||
OPENSSL_free(header.extraField);
|
||||
return 1; /* OK */
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1758,12 +1772,19 @@ static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
bhash = BIO_new(BIO_f_md());
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
OPENSSL_free(data);
|
||||
BIO_free_all(bhash);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
if (!bio_hash_data(bhash, (char *)data, 0, dataSize)) {
|
||||
OPENSSL_free(data);
|
||||
@ -1840,6 +1861,8 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
|
||||
uncompressedSize = entry->uncompressedSize;
|
||||
memset(&header, 0, sizeof(header));
|
||||
if (!zipReadLocalHeader(&header, zip, compressedSize)) {
|
||||
OPENSSL_free(header.fileName);
|
||||
OPENSSL_free(header.extraField);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
if (header.fileNameLen != entry->fileNameLen
|
||||
@ -1848,6 +1871,8 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
|
||||
|| header.uncompressedSize != uncompressedSize
|
||||
|| header.compression != entry->compression) {
|
||||
fprintf(stderr, "Local header does not match central directory entry\n");
|
||||
OPENSSL_free(header.fileName);
|
||||
OPENSSL_free(header.extraField);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
/* we don't really need those */
|
||||
@ -1883,7 +1908,7 @@ static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECT
|
||||
OPENSSL_free(compressedData);
|
||||
|
||||
if (ret != Z_OK) {
|
||||
fprintf(stderr, "Data decompresssion failed, zlib error: %d\n", ret);
|
||||
fprintf(stderr, "Data decompression failed, zlib error: %d\n", ret);
|
||||
OPENSSL_free(uncompressedData);
|
||||
return 0; /* FAILED */
|
||||
} else {
|
||||
@ -2149,6 +2174,7 @@ static int zipDeflate(uint8_t *dest, uint64_t *destLen, uint8_t *source, uLong s
|
||||
|
||||
err = deflateInit2(&stream, 8, Z_DEFLATED, -MAX_WBITS, 8, Z_DEFAULT_STRATEGY);
|
||||
if (err != Z_OK) {
|
||||
deflateEnd(&stream);
|
||||
return err;
|
||||
}
|
||||
stream.next_out = dest;
|
||||
|
9
cab.c
9
cab.c
@ -205,11 +205,18 @@ static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||
u_char *mdbuf = NULL;
|
||||
BIO *bhash = BIO_new(BIO_f_md());
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(bhash);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
|
||||
/* u1 signature[4] 4643534D MSCF: 0-3 */
|
||||
@ -689,7 +696,7 @@ static CAB_CTX *cab_ctx_get(char *indata, uint32_t filesize)
|
||||
* and consist of 4 bytes (little-endian order)
|
||||
* siglen - additional data size is located at offset 48 (from file beginning)
|
||||
* and consist of 4 bytes (little-endian order)
|
||||
* If there are additional headers, size of the CAB archive file is calcualted
|
||||
* If there are additional headers, size of the CAB archive file is calculated
|
||||
* as additional data offset plus additional data size.
|
||||
*/
|
||||
sigpos = GET_UINT32_LE(indata + 44);
|
||||
|
39
cat.c
39
cat.c
@ -55,8 +55,8 @@ FILE_FORMAT file_format_cat = {
|
||||
|
||||
/* Prototypes */
|
||||
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
|
||||
static int cat_add_ms_ctl_object(PKCS7 *p7);
|
||||
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents);
|
||||
static int cat_add_content_type(PKCS7 *p7, PKCS7 *cursig);
|
||||
static int cat_sign_content(PKCS7 *p7, PKCS7 *contents);
|
||||
static int cat_list_content(PKCS7 *p7);
|
||||
static int cat_print_content_member_digest(ASN1_TYPE *content);
|
||||
static int cat_print_content_member_name(ASN1_TYPE *content);
|
||||
@ -161,17 +161,17 @@ static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||
fprintf(stderr, "Creating a new signature failed\n");
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if (!cat_add_ms_ctl_object(p7)) {
|
||||
fprintf(stderr, "Adding MS_CTL_OBJID failed\n");
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if (!ctx->cat_ctx->p7 || !ctx->cat_ctx->p7->d.sign || !ctx->cat_ctx->p7->d.sign->contents) {
|
||||
fprintf(stderr, "Failed to get content\n");
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if (!cat_sign_ms_ctl_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
|
||||
if (!cat_add_content_type(p7, ctx->cat_ctx->p7)) {
|
||||
fprintf(stderr, "Adding content type failed\n");
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
if (!cat_sign_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
|
||||
fprintf(stderr, "Failed to set signed content\n");
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
@ -251,15 +251,30 @@ static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
|
||||
}
|
||||
|
||||
/*
|
||||
* Add "1.3.6.1.4.1.311.10.1" MS_CTL_OBJID signed attribute
|
||||
* Add a content type OID to the PKCS#7 signature structure.
|
||||
* The content type can be:
|
||||
* - "1.3.6.1.4.1.311.10.1" (MS_CTL_OBJID) for Certificate Trust Lists (CTL),
|
||||
* - "1.3.6.1.4.1.311.2.1.4" (SPC_INDIRECT_DATA_OBJID) for Authenticode data.
|
||||
* [in, out] p7: new PKCS#7 signature
|
||||
* [in] cursig: current PKCS#7 signature to determine content type
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
static int cat_add_ms_ctl_object(PKCS7 *p7)
|
||||
static int cat_add_content_type(PKCS7 *p7, PKCS7 *cursig)
|
||||
{
|
||||
const char *content_type;
|
||||
STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
|
||||
PKCS7_SIGNER_INFO *si;
|
||||
|
||||
if (is_content_type(cursig, SPC_INDIRECT_DATA_OBJID)) {
|
||||
/* Authenticode content */
|
||||
content_type = SPC_INDIRECT_DATA_OBJID;
|
||||
} else if (is_content_type(cursig, MS_CTL_OBJID)) {
|
||||
/* Certificate Trust List (CTL) */
|
||||
content_type = MS_CTL_OBJID;
|
||||
} else {
|
||||
fprintf(stderr, "Unsupported content type\n");
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
signer_info = PKCS7_get_signer_info(p7);
|
||||
if (!signer_info)
|
||||
return 0; /* FAILED */
|
||||
@ -267,7 +282,7 @@ static int cat_add_ms_ctl_object(PKCS7 *p7)
|
||||
if (!si)
|
||||
return 0; /* FAILED */
|
||||
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
|
||||
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
|
||||
V_ASN1_OBJECT, OBJ_txt2obj(content_type, 1)))
|
||||
return 0; /* FAILED */
|
||||
return 1; /* OK */
|
||||
}
|
||||
@ -280,7 +295,7 @@ static int cat_add_ms_ctl_object(PKCS7 *p7)
|
||||
* [in] contents: Certificate Trust List (CTL)
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
static int cat_sign_ms_ctl_content(PKCS7 *p7, PKCS7 *contents)
|
||||
static int cat_sign_content(PKCS7 *p7, PKCS7 *contents)
|
||||
{
|
||||
u_char *content;
|
||||
int seqhdrlen, content_length;
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
set(CPACK_PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(CPACK_PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "OpenSSL based Authenticode signing for PE, CAB, CAT, MSI, APPX and script files")
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${CPACK_PACKAGE_NAME})
|
||||
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING.txt")
|
||||
|
@ -75,9 +75,9 @@ if(Python3_FOUND)
|
||||
endif(NOT client_result)
|
||||
endif(EXISTS "${LOGS}/url.log")
|
||||
|
||||
set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat" "ps1" "psc1" "mof")
|
||||
set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx" "ps1" "psc1" "mof")
|
||||
set(extensions_nocatappx "exe" "ex_" "msi" "ps1" "psc1" "mof")
|
||||
set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat" "ps1" "psc1" "mof" "js")
|
||||
set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx" "ps1" "psc1" "mof" "js")
|
||||
set(extensions_nocatappx "exe" "ex_" "msi" "ps1" "psc1" "mof" "js")
|
||||
set(formats "pem" "der")
|
||||
|
||||
else(NOT cryptography_error)
|
||||
@ -219,6 +219,7 @@ if(Python3_FOUND AND NOT cryptography_error)
|
||||
add_test(NAME "added_${ext}"
|
||||
COMMAND ${Python3_EXECUTABLE} ${EXEC} ${OSSLSIGNCODE} "add"
|
||||
"-addUnauthenticatedBlob"
|
||||
"-blobFile" "${FILES}/unsigned.exe"
|
||||
"-add-msi-dse" "-h" "sha512"
|
||||
"-in" "${FILES}/signed.${ext}"
|
||||
"-out" "${FILES}/added.${ext}")
|
||||
|
78
helpers.c
78
helpers.c
@ -165,73 +165,76 @@ int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||
PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
|
||||
{
|
||||
int i, signer = -1;
|
||||
PKCS7 *p7;
|
||||
PKCS7_SIGNER_INFO *si = NULL;
|
||||
STACK_OF(X509) *chain = NULL;
|
||||
PKCS7 *p7 = PKCS7_new();
|
||||
|
||||
if (!p7)
|
||||
return NULL;
|
||||
|
||||
p7 = PKCS7_new();
|
||||
PKCS7_set_type(p7, NID_pkcs7_signed);
|
||||
PKCS7_content_new(p7, NID_pkcs7_data);
|
||||
if (ctx->options->cert != NULL) {
|
||||
/*
|
||||
* the private key and corresponding certificate are parsed from the PKCS12
|
||||
* structure or loaded from the security token, so we may omit to check
|
||||
* the consistency of a private key with the public key in an X509 certificate
|
||||
*/
|
||||
si = PKCS7_add_signature(p7, ctx->options->cert, ctx->options->pkey,
|
||||
ctx->options->md);
|
||||
if (si == NULL)
|
||||
return NULL; /* FAILED */
|
||||
} else {
|
||||
|
||||
/* find the signer's certificate located somewhere in the whole certificate chain */
|
||||
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
|
||||
X509 *signcert = sk_X509_value(ctx->options->certs, i);
|
||||
|
||||
if (X509_check_private_key(signcert, ctx->options->pkey)) {
|
||||
si = PKCS7_add_signature(p7, signcert, ctx->options->pkey, ctx->options->md);
|
||||
signer = i;
|
||||
if (signer > 0)
|
||||
printf("Warning: For optimal performance, consider placing the signer certificate at the beginning of the certificate chain.\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (si == NULL) {
|
||||
if (!si) {
|
||||
fprintf(stderr, "Failed to checking the consistency of a private key: %s\n",
|
||||
ctx->options->keyfile);
|
||||
fprintf(stderr, " with a public key in any X509 certificate: %s\n\n",
|
||||
#if !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||
ctx->options->certfile ? ctx->options->certfile : ctx->options->p11cert);
|
||||
#else
|
||||
ctx->options->certfile);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#endif /* !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (!pkcs7_signer_info_add_signing_time(si, ctx)) {
|
||||
return NULL; /* FAILED */
|
||||
goto err;
|
||||
}
|
||||
if (!pkcs7_signer_info_add_purpose(si, ctx)) {
|
||||
return NULL; /* FAILED */
|
||||
goto err;
|
||||
}
|
||||
if ((ctx->options->desc || ctx->options->url) &&
|
||||
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
|
||||
fprintf(stderr, "Couldn't allocate memory for opus info\n");
|
||||
return NULL; /* FAILED */
|
||||
goto err;
|
||||
}
|
||||
if ((ctx->options->nested_number >= 0) &&
|
||||
!pkcs7_signer_info_add_sequence_number(si, ctx)) {
|
||||
return NULL; /* FAILED */
|
||||
goto err;
|
||||
}
|
||||
/* create X509 chain sorted in ascending order by their DER encoding */
|
||||
chain = X509_chain_get_sorted(ctx, signer);
|
||||
if (chain == NULL) {
|
||||
if (!chain) {
|
||||
fprintf(stderr, "Failed to create a sorted certificate chain\n");
|
||||
return NULL; /* FAILED */
|
||||
goto err;
|
||||
}
|
||||
/* add sorted certificate chain */
|
||||
for (i=0; i<sk_X509_num(chain); i++) {
|
||||
PKCS7_add_certificate(p7, sk_X509_value(chain, i));
|
||||
(void)PKCS7_add_certificate(p7, sk_X509_value(chain, i));
|
||||
}
|
||||
/* add crls */
|
||||
if (ctx->options->crls) {
|
||||
for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++)
|
||||
PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i));
|
||||
(void)PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i));
|
||||
}
|
||||
sk_X509_free(chain);
|
||||
return p7; /* OK */
|
||||
|
||||
err:
|
||||
PKCS7_free(p7);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
|
||||
/*
|
||||
@ -461,7 +464,7 @@ void print_hash(const char *descript1, const char *descript2, const u_char *mdbu
|
||||
}
|
||||
|
||||
/*
|
||||
* [in] p7: new PKCS#7 signature
|
||||
* [in] p7: PKCS#7 signature
|
||||
* [in] objid: Microsoft OID Authenticode
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
@ -471,6 +474,10 @@ int is_content_type(PKCS7 *p7, const char *objid)
|
||||
int ret;
|
||||
|
||||
indir_objid = OBJ_txt2obj(objid, 1);
|
||||
if (!indir_objid) {
|
||||
fprintf(stderr, "Invalid object identifier: %s\n", objid);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
ret = p7 && PKCS7_type_is_signed(p7) &&
|
||||
!OBJ_cmp(p7->d.sign->contents->type, indir_objid) &&
|
||||
(p7->d.sign->contents->d.other->type == V_ASN1_SEQUENCE ||
|
||||
@ -732,11 +739,6 @@ static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
|
||||
int i;
|
||||
STACK_OF(X509) *chain = sk_X509_new(X509_compare);
|
||||
|
||||
/* add the signer's certificate */
|
||||
if (ctx->options->cert != NULL && !sk_X509_push(chain, ctx->options->cert)) {
|
||||
sk_X509_free(chain);
|
||||
return NULL;
|
||||
}
|
||||
if (signer != -1 && !sk_X509_push(chain, sk_X509_value(ctx->options->certs, signer))) {
|
||||
sk_X509_free(chain);
|
||||
return NULL;
|
||||
@ -779,6 +781,15 @@ static int X509_compare(const X509 *const *a, const X509 *const *b)
|
||||
size_t a_len, b_len;
|
||||
int ret;
|
||||
|
||||
#if OPENSSL_VERSION_NUMBER<0x30000000L
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wincompatible-pointer-types-discards-qualifiers"
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
|
||||
#endif
|
||||
#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */
|
||||
a_len = (size_t)i2d_X509(*a, NULL);
|
||||
a_tmp = a_data = OPENSSL_malloc(a_len);
|
||||
i2d_X509(*a, &a_tmp);
|
||||
@ -786,6 +797,13 @@ static int X509_compare(const X509 *const *a, const X509 *const *b)
|
||||
b_len = (size_t)i2d_X509(*b, NULL);
|
||||
b_tmp = b_data = OPENSSL_malloc(b_len);
|
||||
i2d_X509(*b, &b_tmp);
|
||||
#if OPENSSL_VERSION_NUMBER<0x30000000L
|
||||
#if defined(__clang__)
|
||||
#pragma clang diagnostic pop
|
||||
#elif defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
#endif /* OPENSSL_VERSION_NUMBER<0x30000000L */
|
||||
|
||||
ret = memcmp(a_data, b_data, MIN(a_len, b_len));
|
||||
OPENSSL_free(a_data);
|
||||
|
37
msi.c
37
msi.c
@ -373,11 +373,18 @@ static u_char *msi_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||
u_char *mdbuf = NULL;
|
||||
BIO *bhash = BIO_new(BIO_f_md());
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(bhash);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
if (!bio_hash_data(bhash, ctx->options->indata, 0, ctx->msi_ctx->fileend)) {
|
||||
fprintf(stderr, "Unable to calculate digest\n");
|
||||
@ -426,11 +433,18 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
||||
printf("Message digest algorithm : %s\n", OBJ_nid2sn(mdtype));
|
||||
md = EVP_get_digestbynid(mdtype);
|
||||
hash = BIO_new(BIO_f_md());
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(hash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(hash);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(hash, BIO_new(BIO_s_null()));
|
||||
if (ctx->msi_ctx->p_msiex) {
|
||||
BIO *prehash = BIO_new(BIO_f_md());
|
||||
@ -440,12 +454,19 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
|
||||
BIO_free_all(prehash);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(prehash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(hash);
|
||||
BIO_free_all(prehash);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(prehash, BIO_new(BIO_s_null()));
|
||||
|
||||
print_hash("Current MsiDigitalSignatureEx ", "", (u_char *)ctx->msi_ctx->p_msiex,
|
||||
@ -1785,7 +1806,6 @@ static int ministream_save(MSI_DIRENT *dirent, BIO *outdata, MSI_OUT *out)
|
||||
dirent->entry->startSectorLocation = out->sectorNum;
|
||||
/* ministream save */
|
||||
BIO_write(outdata, out->ministream, (int)out->miniStreamLen);
|
||||
OPENSSL_free(out->ministream);
|
||||
/* fill to the end with known data, such as all zeroes */
|
||||
if (out->miniStreamLen % out->sectorSize > 0) {
|
||||
remain = out->sectorSize - out->miniStreamLen % out->sectorSize;
|
||||
@ -2186,6 +2206,8 @@ static int msiout_set(MSI_FILE *msi, uint32_t len_msi, uint32_t len_msiex, MSI_O
|
||||
out->header = header_new(msi->m_hdr, out);
|
||||
out->minifatMemallocCount = msi->m_hdr->numMiniFATSector;
|
||||
out->fatMemallocCount = msi->m_hdr->numFATSector;
|
||||
out->difatMemallocCount = 0;
|
||||
out->difat = NULL;
|
||||
out->ministream = NULL;
|
||||
out->minifat = OPENSSL_malloc((uint64_t)out->minifatMemallocCount * out->sectorSize);
|
||||
out->fat = OPENSSL_malloc((uint64_t)out->fatMemallocCount * out->sectorSize);
|
||||
@ -2226,7 +2248,9 @@ static int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, uint
|
||||
out:
|
||||
OPENSSL_free(out.header);
|
||||
OPENSSL_free(out.fat);
|
||||
OPENSSL_free(out.difat);
|
||||
OPENSSL_free(out.minifat);
|
||||
OPENSSL_free(out.ministream);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -2295,11 +2319,18 @@ static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash)
|
||||
size_t written;
|
||||
BIO *prehash = BIO_new(BIO_f_md());
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(prehash, ctx->options->md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(prehash);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(prehash, BIO_new(BIO_s_null()));
|
||||
|
||||
if (!msi_prehash_dir(ctx->msi_ctx->dirent, prehash, 1)) {
|
||||
@ -2368,8 +2399,8 @@ static int msi_hash_length_get(FILE_FORMAT_CTX *ctx)
|
||||
/*
|
||||
* Get DigitalSignature and MsiDigitalSignatureEx streams
|
||||
* to check if the signature exists.
|
||||
* [in, out] ctx: structure holds input and output datafv
|
||||
* [returns] 0 on error or 1 on successs
|
||||
* [in, out] ctx: structure holds input and output data
|
||||
* [returns] 0 on error or 1 on success
|
||||
*/
|
||||
static int msi_check_file(FILE_FORMAT_CTX *ctx)
|
||||
{
|
||||
|
1080
osslsigncode.c
1080
osslsigncode.c
File diff suppressed because it is too large
Load Diff
@ -66,7 +66,9 @@
|
||||
#include <openssl/rand.h>
|
||||
#include <openssl/safestack.h>
|
||||
#include <openssl/ssl.h>
|
||||
#include <openssl/store.h>
|
||||
#include <openssl/ts.h>
|
||||
#include <openssl/ui.h>
|
||||
#include <openssl/x509.h>
|
||||
#include <openssl/x509v3.h> /* X509_PURPOSE */
|
||||
|
||||
@ -90,7 +92,9 @@
|
||||
#ifdef _MSC_VER
|
||||
/* not WIN32, because strcasecmp exists in MinGW */
|
||||
#define strcasecmp _stricmp
|
||||
#endif
|
||||
#define fseeko _fseeki64
|
||||
#define ftello _ftelli64
|
||||
#endif /* _MSC_VER */
|
||||
|
||||
#ifdef WIN32
|
||||
#define remove_file(filename) _unlink(filename)
|
||||
@ -242,6 +246,16 @@ typedef enum {
|
||||
|
||||
typedef unsigned char u_char;
|
||||
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
typedef struct {
|
||||
ASN1_OCTET_STRING *cmd;
|
||||
ASN1_OCTET_STRING *param;
|
||||
} EngineControl;
|
||||
|
||||
DECLARE_ASN1_FUNCTIONS(EngineControl)
|
||||
DEFINE_STACK_OF(EngineControl)
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
|
||||
typedef struct {
|
||||
char *infile;
|
||||
char *outfile;
|
||||
@ -254,10 +268,13 @@ typedef struct {
|
||||
int output_pkcs7;
|
||||
#ifndef OPENSSL_NO_ENGINE
|
||||
char *p11engine;
|
||||
char *p11module;
|
||||
char *p11cert;
|
||||
STACK_OF(EngineControl) *engine_ctrls;
|
||||
int login;
|
||||
#endif /* OPENSSL_NO_ENGINE */
|
||||
#if !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||
char *p11module;
|
||||
char *p11cert;
|
||||
#endif /* !defined(OPENSSL_NO_ENGINE) || OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||
int askpass;
|
||||
char *readpass;
|
||||
char *pass;
|
||||
@ -274,6 +291,7 @@ typedef struct {
|
||||
char *proxy;
|
||||
int noverifypeer;
|
||||
int addBlob;
|
||||
const char *blob_file;
|
||||
int nest;
|
||||
int index;
|
||||
int ignore_timestamp;
|
||||
@ -292,9 +310,9 @@ typedef struct {
|
||||
int jp;
|
||||
#if OPENSSL_VERSION_NUMBER>=0x30000000L
|
||||
int legacy;
|
||||
char *provider;
|
||||
#endif /* OPENSSL_VERSION_NUMBER>=0x30000000L */
|
||||
EVP_PKEY *pkey;
|
||||
X509 *cert;
|
||||
STACK_OF(X509) *certs;
|
||||
STACK_OF(X509) *xcerts;
|
||||
STACK_OF(X509_CRL) *crls;
|
||||
|
21
pe.c
21
pe.c
@ -779,11 +779,18 @@ static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||
uint32_t idx = 0, fileend;
|
||||
BIO *bhash = BIO_new(BIO_f_md());
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(bhash);
|
||||
return 0; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
if (ctx->pe_ctx->sigpos)
|
||||
fileend = ctx->pe_ctx->sigpos;
|
||||
@ -958,11 +965,18 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
||||
phlen = pphlen * (3 + (int)nsections + (int)(ctx->pe_ctx->fileend / pagesize));
|
||||
|
||||
bhash = BIO_new(BIO_f_md());
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(bhash);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|
||||
|| written != ctx->pe_ctx->header_size + 88) {
|
||||
@ -1005,6 +1019,10 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
||||
for (l=0; l<rs; l+=pagesize, pi++) {
|
||||
PUT_UINT32_LE(ro + l, res + pi*pphlen);
|
||||
bhash = BIO_new(BIO_f_md());
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(bhash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(bhash);
|
||||
@ -1012,6 +1030,9 @@ static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype)
|
||||
OPENSSL_free(res);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(bhash, BIO_new(BIO_s_null()));
|
||||
if (rs - l < pagesize) {
|
||||
if (!BIO_write_ex(bhash, ctx->options->indata + ro + l, rs - l, &written)
|
||||
|
72
script.c
72
script.c
@ -8,11 +8,17 @@
|
||||
#include "helpers.h"
|
||||
#include "utf.h"
|
||||
|
||||
typedef enum {comment_hash, comment_xml, comment_c, comment_not_found} comment_style;
|
||||
typedef enum {
|
||||
comment_hash,
|
||||
comment_xml,
|
||||
comment_c,
|
||||
comment_js,
|
||||
comment_not_found
|
||||
} COMMENT_STYLE;
|
||||
|
||||
typedef struct {
|
||||
const char *extension;
|
||||
comment_style comment;
|
||||
COMMENT_STYLE comment;
|
||||
} SCRIPT_FORMAT;
|
||||
|
||||
const SCRIPT_FORMAT supported_formats[] = {
|
||||
@ -23,21 +29,24 @@ const SCRIPT_FORMAT supported_formats[] = {
|
||||
{".psm1", comment_hash},
|
||||
{".cdxml", comment_xml},
|
||||
{".mof", comment_c},
|
||||
{".js", comment_js},
|
||||
{NULL, comment_not_found},
|
||||
};
|
||||
|
||||
const char *signature_header = "SIG # Begin signature block";
|
||||
const char *signature_footer = "SIG # End signature block";
|
||||
#define header_hash "SIG # Begin signature block"
|
||||
#define footer_hash "SIG # End signature block"
|
||||
#define header_js "Begin signature block"
|
||||
#define footer_js "End signature block"
|
||||
|
||||
typedef struct {
|
||||
const char *open;
|
||||
const char *close;
|
||||
const char *open, *close, *header, *footer;
|
||||
} SCRIPT_COMMENT;
|
||||
|
||||
const SCRIPT_COMMENT comment_text[] = {
|
||||
[comment_hash] = {"# ", ""},
|
||||
[comment_xml] = {"<!-- ", " -->"},
|
||||
[comment_c] = {"/* ", " */"}
|
||||
[comment_hash] = {"# ", "", header_hash, footer_hash},
|
||||
[comment_xml] = {"<!-- ", " -->", header_hash, footer_hash},
|
||||
[comment_c] = {"/* ", " */", header_hash, footer_hash},
|
||||
[comment_js] = {"// SIG // ", "", header_js, footer_js}
|
||||
};
|
||||
|
||||
struct script_ctx_st {
|
||||
@ -242,11 +251,18 @@ static u_char *script_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||
u_char *mdbuf;
|
||||
BIO *hash = BIO_new(BIO_f_md());
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(hash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(hash);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(hash, BIO_new(BIO_s_null()));
|
||||
if (!script_write_bio(hash, ctx->options->indata, ctx->script_ctx->fileend)) {
|
||||
BIO_free_all(hash);
|
||||
@ -326,8 +342,8 @@ static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||
const char *close_tag = ctx->script_ctx->comment_text->close;
|
||||
size_t open_tag_len = strlen(open_tag);
|
||||
size_t close_tag_len = strlen(close_tag);
|
||||
size_t signature_header_len = strlen(signature_header);
|
||||
size_t signature_footer_len = strlen(signature_footer);
|
||||
size_t header_len = strlen(ctx->script_ctx->comment_text->header);
|
||||
size_t footer_len = strlen(ctx->script_ctx->comment_text->footer);
|
||||
PKCS7 *retval = NULL;
|
||||
|
||||
if (!script_check_file(ctx)) {
|
||||
@ -337,6 +353,8 @@ static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||
if (ctx->script_ctx->utf == 8) {
|
||||
base64_len = signature_len;
|
||||
base64_data = OPENSSL_malloc(base64_len);
|
||||
if (!base64_data)
|
||||
return NULL; /* memory allocation failed */
|
||||
memcpy(base64_data, signature_data, base64_len);
|
||||
} else {
|
||||
base64_len = utf16_to_utf8((const void *)signature_data,
|
||||
@ -364,12 +382,12 @@ static PKCS7 *script_pkcs7_extract(FILE_FORMAT_CTX *ctx)
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
/* process signature_header and signature_footer */
|
||||
if (ptr + signature_header_len < base64_data + base64_len &&
|
||||
!memcmp(ptr, signature_header, signature_header_len))
|
||||
ptr += signature_header_len;
|
||||
if (ptr + signature_footer_len <= base64_data + base64_len &&
|
||||
!memcmp(ptr, signature_footer, signature_footer_len))
|
||||
/* process header and footer */
|
||||
if (ptr + header_len < base64_data + base64_len &&
|
||||
!memcmp(ptr, ctx->script_ctx->comment_text->header, header_len))
|
||||
ptr += header_len;
|
||||
if (ptr + footer_len <= base64_data + base64_len &&
|
||||
!memcmp(ptr, ctx->script_ctx->comment_text->footer, footer_len))
|
||||
break; /* success */
|
||||
|
||||
/* copy until the closing tag */
|
||||
@ -531,7 +549,9 @@ static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||
(void)BIO_set_close(bio, BIO_NOCLOSE);
|
||||
|
||||
/* split to individual lines and write to outdata */
|
||||
if (!write_commented(ctx, outdata, signature_header, strlen(signature_header)))
|
||||
if (!write_commented(ctx, outdata,
|
||||
ctx->script_ctx->comment_text->header,
|
||||
strlen(ctx->script_ctx->comment_text->header)))
|
||||
goto cleanup;
|
||||
for (i = 0; i < buffer->length; i += 64) {
|
||||
if (!write_commented(ctx, outdata, buffer->data + i,
|
||||
@ -539,7 +559,9 @@ static int script_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
if (!write_commented(ctx, outdata, signature_footer, strlen(signature_footer)))
|
||||
if (!write_commented(ctx, outdata,
|
||||
ctx->script_ctx->comment_text->footer,
|
||||
strlen(ctx->script_ctx->comment_text->footer)))
|
||||
goto cleanup;
|
||||
|
||||
/* signtool expects CRLF terminator at the end of the text file */
|
||||
@ -605,7 +627,7 @@ static SCRIPT_CTX *script_ctx_get(char *indata, uint32_t filesize, const SCRIPT_
|
||||
*ptr && commented_header_len < commented_header_size;
|
||||
commented_header_len++)
|
||||
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
|
||||
for (ptr = signature_header;
|
||||
for (ptr = comment->header;
|
||||
*ptr && commented_header_len < commented_header_size;
|
||||
commented_header_len++)
|
||||
ptr = utf8DecodeRune(ptr, 1, commented_header + commented_header_len);
|
||||
@ -671,6 +693,8 @@ static int write_commented(FILE_FORMAT_CTX *ctx, BIO *outdata, const char *data,
|
||||
* - closing tag
|
||||
* - trailing NUL ("\0") */
|
||||
line = OPENSSL_malloc(2 + open_tag_len + length + close_tag_len + 1);
|
||||
if (!line)
|
||||
return 0; /* memory allocation failed */
|
||||
strcpy(line, "\r\n");
|
||||
strcat(line, open_tag);
|
||||
memcpy(line + 2 + open_tag_len, data, length);
|
||||
@ -782,12 +806,18 @@ static BIO *script_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
|
||||
fileend = ctx->script_ctx->sigpos;
|
||||
else
|
||||
fileend = ctx->script_ctx->fileend;
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wcast-qual"
|
||||
#endif
|
||||
if (!BIO_set_md(hash, md)) {
|
||||
fprintf(stderr, "Unable to set the message digest of BIO\n");
|
||||
BIO_free_all(hash);
|
||||
return NULL; /* FAILED */
|
||||
}
|
||||
#if defined(__GNUC__)
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
BIO_push(hash, BIO_new(BIO_s_null()));
|
||||
if (!script_digest_convert(hash, ctx, fileend)) {
|
||||
fprintf(stderr, "Unable calc a message digest value\n");
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python3
|
||||
"""Implementation of a HTTP client"""
|
||||
"""Implementation of an HTTP client"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
@ -29,7 +29,7 @@ def main() -> None:
|
||||
# all exceptions are critical
|
||||
print(err, file=sys.stderr)
|
||||
else:
|
||||
print("Usage:\n\t{} COMMAND [ARG]...'".format(sys.argv[0]), file=sys.stderr)
|
||||
print("Usage:\n\t{} COMMAND [ARG]...".format(sys.argv[0]), file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
Binary file not shown.
1
tests/files/unsigned.js
Normal file
1
tests/files/unsigned.js
Normal file
@ -0,0 +1 @@
|
||||
console.log("Hello, world!");
|
@ -4,11 +4,60 @@
|
||||
import os
|
||||
import datetime
|
||||
import cryptography
|
||||
from cryptography import x509
|
||||
from cryptography.x509.oid import NameOID
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.primitives import serialization
|
||||
from cryptography.hazmat.primitives.asymmetric import rsa
|
||||
|
||||
# Explicit imports of cryptography submodules
|
||||
import cryptography.x509
|
||||
import cryptography.x509.oid
|
||||
import cryptography.hazmat.primitives.hashes
|
||||
import cryptography.hazmat.primitives.asymmetric.rsa
|
||||
import cryptography.hazmat.primitives.serialization
|
||||
import cryptography.hazmat.primitives.serialization.pkcs12
|
||||
|
||||
# Import classes and functions from the cryptography module
|
||||
from cryptography.x509 import (
|
||||
AuthorityKeyIdentifier,
|
||||
BasicConstraints,
|
||||
Certificate,
|
||||
CertificateBuilder,
|
||||
CertificateRevocationListBuilder,
|
||||
CRLDistributionPoints,
|
||||
CRLNumber,
|
||||
CRLReason,
|
||||
DistributionPoint,
|
||||
DNSName,
|
||||
ExtendedKeyUsage,
|
||||
KeyUsage,
|
||||
Name,
|
||||
NameAttribute,
|
||||
NameConstraints,
|
||||
random_serial_number,
|
||||
RevokedCertificateBuilder,
|
||||
ReasonFlags,
|
||||
SubjectKeyIdentifier,
|
||||
UniformResourceIdentifier
|
||||
)
|
||||
from cryptography.x509.oid import (
|
||||
ExtendedKeyUsageOID,
|
||||
NameOID
|
||||
)
|
||||
from cryptography.hazmat.primitives.hashes import SHA256
|
||||
from cryptography.hazmat.primitives.asymmetric.rsa import (
|
||||
generate_private_key,
|
||||
RSAPrivateKey
|
||||
)
|
||||
from cryptography.hazmat.primitives.serialization import (
|
||||
BestAvailableEncryption,
|
||||
Encoding,
|
||||
NoEncryption,
|
||||
PrivateFormat
|
||||
)
|
||||
from cryptography.hazmat.primitives.serialization.pkcs12 import serialize_key_and_certificates
|
||||
|
||||
try:
|
||||
if cryptography.__version__ >= '38.0.0':
|
||||
from cryptography.hazmat.primitives.serialization.pkcs12 import PBES
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
RESULT_PATH = os.getcwd()
|
||||
CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||
@ -28,25 +77,25 @@ class X509Extensions():
|
||||
self.port = cdp_port
|
||||
self.name = cdp_name
|
||||
|
||||
def create_x509_name(self, common_name) -> x509.Name:
|
||||
def create_x509_name(self, common_name) -> Name:
|
||||
"""Return x509.Name"""
|
||||
return x509.Name(
|
||||
return Name(
|
||||
[
|
||||
x509.NameAttribute(NameOID.COUNTRY_NAME, "PL"),
|
||||
x509.NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Mazovia Province"),
|
||||
x509.NameAttribute(NameOID.LOCALITY_NAME, "Warsaw"),
|
||||
x509.NameAttribute(NameOID.ORGANIZATION_NAME, "osslsigncode"),
|
||||
x509.NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, self.unit_name),
|
||||
x509.NameAttribute(NameOID.COMMON_NAME, common_name)
|
||||
NameAttribute(NameOID.COUNTRY_NAME, "PL"),
|
||||
NameAttribute(NameOID.STATE_OR_PROVINCE_NAME, "Mazovia Province"),
|
||||
NameAttribute(NameOID.LOCALITY_NAME, "Warsaw"),
|
||||
NameAttribute(NameOID.ORGANIZATION_NAME, "osslsigncode"),
|
||||
NameAttribute(NameOID.ORGANIZATIONAL_UNIT_NAME, self.unit_name),
|
||||
NameAttribute(NameOID.COMMON_NAME, common_name)
|
||||
]
|
||||
)
|
||||
|
||||
def create_x509_crldp(self) -> x509.CRLDistributionPoints:
|
||||
def create_x509_crldp(self) -> CRLDistributionPoints:
|
||||
"""Return x509.CRLDistributionPoints"""
|
||||
return x509.CRLDistributionPoints(
|
||||
return CRLDistributionPoints(
|
||||
[
|
||||
x509.DistributionPoint(
|
||||
full_name=[x509.UniformResourceIdentifier(
|
||||
DistributionPoint(
|
||||
full_name=[UniformResourceIdentifier(
|
||||
"http://127.0.0.1:" + str(self.port) + "/" + str(self.name))
|
||||
],
|
||||
relative_name=None,
|
||||
@ -56,10 +105,10 @@ class X509Extensions():
|
||||
]
|
||||
)
|
||||
|
||||
def create_x509_name_constraints(self) -> x509.NameConstraints:
|
||||
def create_x509_name_constraints(self) -> NameConstraints:
|
||||
"""Return x509.NameConstraints"""
|
||||
return x509.NameConstraints(
|
||||
permitted_subtrees = [x509.DNSName('test.com'), x509.DNSName('test.org')],
|
||||
return NameConstraints(
|
||||
permitted_subtrees = [DNSName('test.com'), DNSName('test.org')],
|
||||
excluded_subtrees = None
|
||||
)
|
||||
|
||||
@ -71,14 +120,14 @@ class IntermediateCACertificate(X509Extensions):
|
||||
self.issuer_key = issuer_key
|
||||
super().__init__("Certification Authority", 0, None)
|
||||
|
||||
def make_cert(self) -> (x509.Certificate, rsa.RSAPrivateKey):
|
||||
def make_cert(self) -> (Certificate, RSAPrivateKey):
|
||||
"""Generate intermediate CA certificate"""
|
||||
key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||
key_public = key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||
)
|
||||
key_usage = x509.KeyUsage(
|
||||
key_usage = KeyUsage(
|
||||
digital_signature=True,
|
||||
content_commitment=False,
|
||||
key_encipherment=False,
|
||||
@ -90,22 +139,22 @@ class IntermediateCACertificate(X509Extensions):
|
||||
decipher_only=False
|
||||
)
|
||||
cert = (
|
||||
x509.CertificateBuilder()
|
||||
CertificateBuilder()
|
||||
.subject_name(self.create_x509_name("Intermediate CA"))
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.public_key(key_public)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.serial_number(random_serial_number())
|
||||
.not_valid_before(date_20180101)
|
||||
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=0), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(key_public), critical=False)
|
||||
.add_extension(BasicConstraints(ca=True, path_length=0), critical=True)
|
||||
.add_extension(SubjectKeyIdentifier.from_public_key(key_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(key_usage, critical=True)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
.sign(self.issuer_key, SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, "intermediateCA.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||
|
||||
return cert, key
|
||||
|
||||
@ -114,7 +163,7 @@ class RootCACertificate(X509Extensions):
|
||||
"""Base class for Root CA certificate"""
|
||||
|
||||
def __init__(self):
|
||||
self.key_usage = x509.KeyUsage(
|
||||
self.key_usage = KeyUsage(
|
||||
digital_signature=True,
|
||||
content_commitment=False,
|
||||
key_encipherment=False,
|
||||
@ -127,7 +176,7 @@ class RootCACertificate(X509Extensions):
|
||||
)
|
||||
super().__init__("Certification Authority", 0, None)
|
||||
|
||||
def make_cert(self) -> (x509.Certificate, rsa.RSAPrivateKey):
|
||||
def make_cert(self) -> (Certificate, RSAPrivateKey):
|
||||
"""Generate CA certificates"""
|
||||
ca_root, root_key = self.make_ca_cert("Trusted Root CA", "CAroot.pem")
|
||||
ca_cert, ca_key = self.make_ca_cert("Root CA", "CACert.pem")
|
||||
@ -136,52 +185,52 @@ class RootCACertificate(X509Extensions):
|
||||
|
||||
def make_ca_cert(self, common_name, file_name) -> None:
|
||||
"""Generate self-signed root CA certificate"""
|
||||
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||
ca_public = ca_key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||
name = self.create_x509_name(common_name)
|
||||
ca_cert = (
|
||||
x509.CertificateBuilder()
|
||||
CertificateBuilder()
|
||||
.subject_name(name)
|
||||
.issuer_name(name)
|
||||
.public_key(ca_public)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.serial_number(random_serial_number())
|
||||
.not_valid_before(date_20170101)
|
||||
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(self.key_usage, critical=True)
|
||||
.sign(ca_key, hashes.SHA256())
|
||||
.sign(ca_key, SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, file_name)
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(ca_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(ca_cert.public_bytes(encoding=Encoding.PEM))
|
||||
return ca_cert, ca_key
|
||||
|
||||
def make_cross_cert(self, ca_root, root_key, ca_cert, ca_key) -> None:
|
||||
"""Generate cross-signed root CA certificate"""
|
||||
ca_public = ca_key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
ca_root.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
ca_root.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||
)
|
||||
ca_cross = (
|
||||
x509.CertificateBuilder()
|
||||
CertificateBuilder()
|
||||
.subject_name(ca_cert.subject)
|
||||
.issuer_name(ca_root.subject)
|
||||
.public_key(ca_public)
|
||||
.serial_number(ca_cert.serial_number)
|
||||
.not_valid_before(date_20180101)
|
||||
.not_valid_after(date_20180101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(self.key_usage, critical=True)
|
||||
.sign(root_key, hashes.SHA256())
|
||||
.sign(root_key, SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, "CAcross.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(ca_cross.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(ca_cross.public_bytes(encoding=Encoding.PEM))
|
||||
|
||||
def write_key(self, key, file_name) -> None:
|
||||
"""Write a private RSA key"""
|
||||
@ -194,27 +243,27 @@ class RootCACertificate(X509Extensions):
|
||||
file_path = os.path.join(CERTS_PATH, file_name + "p.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.BestAvailableEncryption(PASSWORD.encode())
|
||||
encoding=Encoding.PEM,
|
||||
format=PrivateFormat.PKCS8,
|
||||
encryption_algorithm=BestAvailableEncryption(PASSWORD.encode())
|
||||
)
|
||||
)
|
||||
# Write decrypted key in PEM format
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
encoding=Encoding.PEM,
|
||||
format=PrivateFormat.PKCS8,
|
||||
encryption_algorithm=NoEncryption()
|
||||
)
|
||||
)
|
||||
# Write the key in DER format
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".der")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(key.private_bytes(
|
||||
encoding=serialization.Encoding.DER,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
encoding=Encoding.DER,
|
||||
format=PrivateFormat.PKCS8,
|
||||
encryption_algorithm=NoEncryption()
|
||||
)
|
||||
)
|
||||
|
||||
@ -225,13 +274,13 @@ class TSARootCACertificate(X509Extensions):
|
||||
def __init__(self):
|
||||
super().__init__("Timestamp Authority Root CA", 0, None)
|
||||
|
||||
def make_cert(self) -> (x509.Certificate, rsa.RSAPrivateKey):
|
||||
def make_cert(self) -> (Certificate, RSAPrivateKey):
|
||||
"""Generate a Time Stamp Authority certificate"""
|
||||
ca_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
ca_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||
ca_public = ca_key.public_key()
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||
authority_key = AuthorityKeyIdentifier.from_issuer_public_key(ca_public)
|
||||
name = self.create_x509_name("TSA Root CA")
|
||||
key_usage = x509.KeyUsage(
|
||||
key_usage = KeyUsage(
|
||||
digital_signature=False,
|
||||
content_commitment=False,
|
||||
key_encipherment=False,
|
||||
@ -243,22 +292,22 @@ class TSARootCACertificate(X509Extensions):
|
||||
decipher_only=False
|
||||
)
|
||||
ca_cert = (
|
||||
x509.CertificateBuilder()
|
||||
CertificateBuilder()
|
||||
.subject_name(name)
|
||||
.issuer_name(name)
|
||||
.public_key(ca_public)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.serial_number(random_serial_number())
|
||||
.not_valid_before(date_20170101)
|
||||
.not_valid_after(date_20170101 + datetime.timedelta(days=7300))
|
||||
.add_extension(x509.BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(BasicConstraints(ca=True, path_length=None), critical=True)
|
||||
.add_extension(SubjectKeyIdentifier.from_public_key(ca_public), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(key_usage, critical=True)
|
||||
.sign(ca_key, hashes.SHA256())
|
||||
.sign(ca_key, SHA256())
|
||||
)
|
||||
file_path=os.path.join(CERTS_PATH, "TSACA.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(ca_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(ca_cert.public_bytes(encoding=Encoding.PEM))
|
||||
|
||||
return ca_cert, ca_key
|
||||
|
||||
@ -267,14 +316,14 @@ class TSARootCACertificate(X509Extensions):
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".key")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(key.private_bytes(
|
||||
encoding=serialization.Encoding.PEM,
|
||||
format=serialization.PrivateFormat.PKCS8,
|
||||
encryption_algorithm=serialization.NoEncryption()
|
||||
encoding=Encoding.PEM,
|
||||
format=PrivateFormat.PKCS8,
|
||||
encryption_algorithm=NoEncryption()
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class Certificate(X509Extensions):
|
||||
class LeafCertificate(X509Extensions):
|
||||
"""Base class for a leaf certificate"""
|
||||
|
||||
def __init__(self, issuer_cert, issuer_key, unit_name, common_name, cdp_port, cdp_name):
|
||||
@ -284,78 +333,78 @@ class Certificate(X509Extensions):
|
||||
self.common_name = common_name
|
||||
super().__init__(unit_name, cdp_port, cdp_name)
|
||||
|
||||
def make_cert(self, public_key, not_before, days) -> x509.Certificate:
|
||||
def make_cert(self, public_key, not_before, days) -> Certificate:
|
||||
"""Generate a leaf certificate"""
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||
)
|
||||
extended_key_usage = x509.ExtendedKeyUsage(
|
||||
[x509.oid.ExtendedKeyUsageOID.CODE_SIGNING]
|
||||
extended_key_usage = ExtendedKeyUsage(
|
||||
[ExtendedKeyUsageOID.CODE_SIGNING]
|
||||
)
|
||||
cert = (
|
||||
x509.CertificateBuilder()
|
||||
CertificateBuilder()
|
||||
.subject_name(self.create_x509_name(self.common_name))
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.public_key(public_key)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.serial_number(random_serial_number())
|
||||
.not_valid_before(not_before)
|
||||
.not_valid_after(not_before + datetime.timedelta(days=days))
|
||||
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=False)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||
.add_extension(BasicConstraints(ca=False, path_length=None), critical=False)
|
||||
.add_extension(SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(extended_key_usage, critical=False)
|
||||
.add_extension(self.create_x509_crldp(), critical=False)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
.sign(self.issuer_key, SHA256())
|
||||
)
|
||||
# Write PEM file and attach intermediate certificate
|
||||
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(self.issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||
file.write(self.issuer_cert.public_bytes(encoding=Encoding.PEM))
|
||||
|
||||
return cert
|
||||
|
||||
def revoke_cert(self, serial_number, file_name) -> None:
|
||||
"""Revoke a certificate"""
|
||||
revoked = (
|
||||
x509.RevokedCertificateBuilder()
|
||||
RevokedCertificateBuilder()
|
||||
.serial_number(serial_number)
|
||||
.revocation_date(date_20190101)
|
||||
.add_extension(x509.CRLReason(x509.ReasonFlags.superseded), critical=False)
|
||||
.add_extension(CRLReason(ReasonFlags.superseded), critical=False)
|
||||
.build()
|
||||
)
|
||||
# Generate CRL
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||
)
|
||||
crl = (
|
||||
x509.CertificateRevocationListBuilder()
|
||||
CertificateRevocationListBuilder()
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.last_update(date_20190101)
|
||||
.next_update(date_20190101 + datetime.timedelta(days=7300))
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(x509.CRLNumber(4097), critical=False)
|
||||
.add_extension(CRLNumber(4097), critical=False)
|
||||
.add_revoked_certificate(revoked)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
.sign(self.issuer_key, SHA256())
|
||||
)
|
||||
# Write CRL file
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(crl.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(crl.public_bytes(encoding=Encoding.PEM))
|
||||
|
||||
file_path = os.path.join(CERTS_PATH, file_name + ".der")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(crl.public_bytes(encoding=serialization.Encoding.DER))
|
||||
file.write(crl.public_bytes(encoding=Encoding.DER))
|
||||
|
||||
|
||||
class LeafCACertificate(Certificate):
|
||||
class LeafCACertificate(LeafCertificate):
|
||||
"""Base class for a leaf certificate"""
|
||||
|
||||
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
|
||||
super().__init__(issuer_cert, issuer_key, "CSP", common, cdp_port, "intermediateCA")
|
||||
|
||||
|
||||
class LeafTSACertificate(Certificate):
|
||||
class LeafTSACertificate(LeafCertificate):
|
||||
"""Base class for a TSA leaf certificate"""
|
||||
|
||||
def __init__(self, issuer_cert, issuer_key, common, cdp_port):
|
||||
@ -364,40 +413,40 @@ class LeafTSACertificate(Certificate):
|
||||
self.common_name = common
|
||||
super().__init__(issuer_cert, issuer_key, "Timestamp Root CA", common, cdp_port, "TSACA")
|
||||
|
||||
def make_cert(self, public_key, not_before, days) -> x509.Certificate:
|
||||
def make_cert(self, public_key, not_before, days) -> Certificate:
|
||||
"""Generate a TSA leaf certificate"""
|
||||
|
||||
authority_key = x509.AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(x509.SubjectKeyIdentifier).value
|
||||
authority_key = AuthorityKeyIdentifier.from_issuer_subject_key_identifier(
|
||||
self.issuer_cert.extensions.get_extension_for_class(SubjectKeyIdentifier).value
|
||||
)
|
||||
|
||||
# The TSA signing certificate must have exactly one extended key usage
|
||||
# assigned to it: timeStamping. The extended key usage must also be critical,
|
||||
# otherwise the certificate is going to be refused.
|
||||
extended_key_usage = x509.ExtendedKeyUsage(
|
||||
[x509.oid.ExtendedKeyUsageOID.TIME_STAMPING]
|
||||
extended_key_usage = ExtendedKeyUsage(
|
||||
[ExtendedKeyUsageOID.TIME_STAMPING]
|
||||
)
|
||||
cert = (
|
||||
x509.CertificateBuilder()
|
||||
CertificateBuilder()
|
||||
.subject_name(self.create_x509_name(self.common_name))
|
||||
.issuer_name(self.issuer_cert.subject)
|
||||
.public_key(public_key)
|
||||
.serial_number(x509.random_serial_number())
|
||||
.serial_number(random_serial_number())
|
||||
.not_valid_before(not_before)
|
||||
.not_valid_after(not_before + datetime.timedelta(days=days))
|
||||
.add_extension(x509.BasicConstraints(ca=False, path_length=None), critical=True)
|
||||
.add_extension(x509.SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||
.add_extension(BasicConstraints(ca=False, path_length=None), critical=True)
|
||||
.add_extension(SubjectKeyIdentifier.from_public_key(public_key), critical=False)
|
||||
.add_extension(authority_key, critical=False)
|
||||
.add_extension(extended_key_usage, critical=True)
|
||||
.add_extension(self.create_x509_crldp(), critical=False)
|
||||
.add_extension(self.create_x509_name_constraints(), critical=False)
|
||||
.sign(self.issuer_key, hashes.SHA256())
|
||||
.sign(self.issuer_key, SHA256())
|
||||
)
|
||||
# Write PEM file and attach intermediate certificate
|
||||
file_path = os.path.join(CERTS_PATH, self.common_name + ".pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(self.issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||
file.write(self.issuer_cert.public_bytes(encoding=Encoding.PEM))
|
||||
|
||||
return cert
|
||||
|
||||
@ -433,7 +482,7 @@ class CertificateMaker():
|
||||
issuer_cert, issuer_key = intermediate.make_cert()
|
||||
|
||||
# Generate private RSA key
|
||||
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
private_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||
public_key = private_key.public_key()
|
||||
root.write_key(key=private_key, file_name="key")
|
||||
|
||||
@ -460,7 +509,7 @@ class CertificateMaker():
|
||||
# Write DER file and attach intermediate certificate
|
||||
file_path = os.path.join(CERTS_PATH, "cert.der")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.DER))
|
||||
file.write(cert.public_bytes(encoding=Encoding.DER))
|
||||
|
||||
def make_tsa_certs(self):
|
||||
"""Make test TSA certificates"""
|
||||
@ -470,7 +519,7 @@ class CertificateMaker():
|
||||
issuer_cert, issuer_key = root.make_cert()
|
||||
|
||||
# Generate private RSA key
|
||||
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
|
||||
private_key = generate_private_key(public_exponent=65537, key_size=2048)
|
||||
public_key = private_key.public_key()
|
||||
root.write_key(key=private_key, file_name="TSA")
|
||||
|
||||
@ -486,8 +535,8 @@ class CertificateMaker():
|
||||
# Save the chain to be included in the TSA response
|
||||
file_path = os.path.join(CERTS_PATH, "tsa-chain.pem")
|
||||
with open(file_path, mode="wb") as file:
|
||||
file.write(cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(issuer_cert.public_bytes(encoding=serialization.Encoding.PEM))
|
||||
file.write(cert.public_bytes(encoding=Encoding.PEM))
|
||||
file.write(issuer_cert.public_bytes(encoding=Encoding.PEM))
|
||||
|
||||
|
||||
def write_pkcs12_container(self, cert, key, issuer) -> None:
|
||||
@ -499,16 +548,16 @@ class CertificateMaker():
|
||||
# and private key encryption: DES-EDE3-CBC (vel 3DES_CBC)
|
||||
# pylint: disable=no-member
|
||||
encryption = (
|
||||
serialization.PrivateFormat.PKCS12.encryption_builder()
|
||||
.key_cert_algorithm(serialization.pkcs12.PBES.PBESv1SHA1And3KeyTripleDESCBC)
|
||||
PrivateFormat.PKCS12.encryption_builder()
|
||||
.key_cert_algorithm(PBES.PBESv1SHA1And3KeyTripleDESCBC)
|
||||
.kdf_rounds(5000)
|
||||
.build(PASSWORD.encode())
|
||||
)
|
||||
else:
|
||||
encryption = serialization.BestAvailableEncryption(PASSWORD.encode())
|
||||
encryption = BestAvailableEncryption(PASSWORD.encode())
|
||||
|
||||
# Generate PKCS#12 struct
|
||||
pkcs12 = serialization.pkcs12.serialize_key_and_certificates(
|
||||
pkcs12 = serialize_key_and_certificates(
|
||||
name=b'certificate',
|
||||
key=key,
|
||||
cert=cert,
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python3
|
||||
"""Implementation of a HTTP server"""
|
||||
"""Implementation of an HTTP server"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
@ -17,7 +17,7 @@ CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||
CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
|
||||
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
||||
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
||||
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||
RESPONSE = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
||||
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
||||
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
|
||||
@ -26,7 +26,7 @@ OPENSSL_TS = ["openssl", "ts",
|
||||
"-reply", "-config", OPENSSL_CONF,
|
||||
"-passin", "pass:passme",
|
||||
"-queryfile", REQUEST,
|
||||
"-out", RESPONS]
|
||||
"-out", RESPONSE]
|
||||
|
||||
|
||||
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
|
||||
@ -86,7 +86,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||
self.send_header("Content-type", "application/timestamp-reply")
|
||||
self.end_headers()
|
||||
resp_data = b''
|
||||
with open(RESPONS, mode="rb") as file:
|
||||
with open(RESPONSE, mode="rb") as file:
|
||||
resp_data = file.read()
|
||||
self.wfile.write(resp_data)
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#!/usr/bin/python3
|
||||
"""Windows: Implementation of a HTTP server"""
|
||||
"""Windows: Implementation of an HTTP server"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
@ -16,7 +16,7 @@ CERTS_PATH = os.path.join(RESULT_PATH, "./Testing/certs/")
|
||||
CONF_PATH = os.path.join(RESULT_PATH, "./Testing/conf/")
|
||||
LOGS_PATH = os.path.join(RESULT_PATH, "./Testing/logs/")
|
||||
REQUEST = os.path.join(FILES_PATH, "./jreq.tsq")
|
||||
RESPONS = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||
RESPONSE = os.path.join(FILES_PATH, "./jresp.tsr")
|
||||
OPENSSL_CONF = os.path.join(CONF_PATH, "./openssl_tsa.cnf")
|
||||
SERVER_LOG = os.path.join(LOGS_PATH, "./server.log")
|
||||
URL_LOG = os.path.join(LOGS_PATH, "./url.log")
|
||||
@ -26,7 +26,7 @@ OPENSSL_TS = ["openssl", "ts",
|
||||
"-reply", "-config", OPENSSL_CONF,
|
||||
"-passin", "pass:passme",
|
||||
"-queryfile", REQUEST,
|
||||
"-out", RESPONS]
|
||||
"-out", RESPONSE]
|
||||
|
||||
|
||||
class RequestHandler(SimpleHTTPRequestHandler):
|
||||
@ -82,7 +82,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
||||
self.send_header("Content-type", "application/timestamp-reply")
|
||||
self.end_headers()
|
||||
resp_data = b''
|
||||
with open(RESPONS, mode="rb") as file:
|
||||
with open(RESPONSE, mode="rb") as file:
|
||||
resp_data = file.read()
|
||||
self.wfile.write(resp_data)
|
||||
except Exception as err: # pylint: disable=broad-except
|
||||
|
@ -55,3 +55,6 @@ CATATTR1=0x11010001:OSAttr:2:6.0
|
||||
|
||||
<HASH>MOFfile=..\files\unsigned.mof
|
||||
<HASH>MOFfileATTR1=0x11010001:File:unsigned.mof
|
||||
|
||||
<HASH>JSfile=..\files\unsigned.js
|
||||
<HASH>JSfileATTR1=0x11010001:File:unsigned.js
|
||||
|
@ -51,7 +51,7 @@ def clear_catalog(certs_path) -> None:
|
||||
file.write(random_hex)
|
||||
|
||||
def main() -> None:
|
||||
"""Wait for all tests certificate, compute leafhash"""
|
||||
"""Wait for all test certificates and compute leaf hash"""
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
|
Reference in New Issue
Block a user