66 Commits
2.7 ... 2.8

Author SHA1 Message Date
699bc85d0a Release 2.8
Signed-off-by: Michał Trojnara <Michal.Trojnara@stunnel.org>
2024-03-03 23:32:15 +01:00
192e7a732b Fixed memory leaks 2024-03-01 17:50:20 +01:00
656051676f Changelog update 2024-02-29 17:57:22 +01:00
3998bcabb2 Simplify BIO chain free up and FILE_FORMAT_CTX cleanup 2024-02-28 15:55:25 +01:00
fa40c57f80 Simplify checking whether a signature exists 2024-02-28 11:55:21 +01:00
0b93a94ffa Fixed cross-signed root CA certificate 2024-02-28 11:52:49 +01:00
105fd3af4a Fix handling of printf format specifiers 2024-02-27 10:47:58 +01:00
86a594b087 NEWS.md entry for Microsoft PowerShell signing
Closes #37
2024-02-22 16:39:57 +01:00
1dea73b038 Install python@3.8 on macOS required for the Github Actions CI 2024-02-22 16:14:35 +01:00
b661ed08ed Fix fuzzer error - corrupted data content 2024-02-20 17:48:55 +01:00
ead0584611 Disable curl dependence 2024-02-20 17:48:31 +01:00
bd7751147e Update Windows build documentation 2024-02-20 10:03:47 +01:00
1bc7fc36b8 Connect to CRL Distribution Points through the configured proxy when verifying 2024-02-19 12:19:44 +01:00
42e9733916 Fix python 3 compatibility in server_http.py (#350)
Building osslsigncode fails on systems with older versions of Python 3 due to the server_http.py script, part of the test procedure. This script requires the ThreadingHTTPServer module, introduced in Python version 3.7.

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

View File

@ -7,7 +7,7 @@ on:
env: env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release BUILD_TYPE: Release
version: osslsigncode-2.7 version: osslsigncode-2.8
jobs: jobs:
build: build:
@ -90,12 +90,28 @@ jobs:
with: with:
arch: ${{matrix.arch}} 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) - name: Install apt dependencies (Linux)
if: runner.os == 'Linux' if: runner.os == 'Linux'
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y libssl-dev libcurl4-openssl-dev faketime sudo apt-get install -y libssl-dev libcurl4-openssl-dev faketime
- name: Install brew dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew install python@3.8
- name: Install Xcode (macOS) - name: Install Xcode (macOS)
if: runner.os == 'macOS' if: runner.os == 'macOS'
uses: maxim-lobanov/setup-xcode@v1 uses: maxim-lobanov/setup-xcode@v1
@ -129,8 +145,8 @@ jobs:
working-directory: ${{github.workspace}}/build working-directory: ${{github.workspace}}/build
if: runner.os == 'macOS' if: runner.os == 'macOS'
run: | run: |
python3 --version python3.8 --version
python3 ./Testing/server_http.py --port 19254 python3.8 ./Testing/server_http.py --port 19254
while test ! -s ./Testing/logs/port.log; do sleep 1; done while test ! -s ./Testing/logs/port.log; do sleep 1; done
- name: Start HTTP server (Windows) - name: Start HTTP server (Windows)

View File

@ -10,7 +10,7 @@ set(BUILTIN_SOCKET ON CACHE BOOL "") # for static Python
# configure basic project information # configure basic project information
project(osslsigncode project(osslsigncode
VERSION 2.7 VERSION 2.8
DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files" DESCRIPTION "OpenSSL based Authenticode signing for PE, CAB, CAT and MSI files"
HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode" HOMEPAGE_URL "https://github.com/mtrojnar/osslsigncode"
LANGUAGES C) LANGUAGES C)
@ -48,7 +48,7 @@ configure_file(Config.h.in config.h)
target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1) target_compile_definitions(osslsigncode PRIVATE HAVE_CONFIG_H=1)
# set sources # set sources
target_sources(osslsigncode PRIVATE osslsigncode.c helpers.c msi.c pe.c cab.c cat.c appx.c) target_sources(osslsigncode PRIVATE osslsigncode.c helpers.c utf.c msi.c pe.c cab.c cat.c appx.c script.c)
if(NOT UNIX) if(NOT UNIX)
target_sources(osslsigncode PRIVATE applink.c) target_sources(osslsigncode PRIVATE applink.c)
endif(NOT UNIX) endif(NOT UNIX)

32
Dockerfile Normal file
View File

@ -0,0 +1,32 @@
# Stage 1: Build osslsigncode on Alpine
FROM alpine:latest AS builder
# Install build dependencies
RUN apk add --no-cache build-base cmake openssl-dev curl-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 libcurl
# Set working directory
WORKDIR /workdir
# Declare volume to mount files
VOLUME [ "/workdir" ]

View File

@ -12,7 +12,7 @@
2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables. 2) Run "MSYS2 MinGW 64-bit" and build 64-bit Windows executables.
``` ```
cd osslsigncode-folder cd osslsigncode-folder
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \ x86_64-w64-mingw32-gcc *.c -o osslsigncode.exe \
-lcrypto -lssl -lcurl \ -lcrypto -lssl -lcurl \
-D 'PACKAGE_STRING="osslsigncode x.y"' \ -D 'PACKAGE_STRING="osslsigncode x.y"' \
-D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \ -D 'PACKAGE_BUGREPORT="Your.Email@example.com"' \
@ -71,7 +71,7 @@
3) Build 64-bit Windows executables. 3) Build 64-bit Windows executables.
``` ```
cd osslsigncode-folder cd osslsigncode-folder
x86_64-w64-mingw32-gcc osslsigncode.c msi.c -o osslsigncode.exe \ x86_64-w64-mingw32-gcc *.c -o osslsigncode.exe \
-L 'C:/OpenSSL/lib/' -lcrypto -lssl \ -L 'C:/OpenSSL/lib/' -lcrypto -lssl \
-I 'C:/OpenSSL/include/' \ -I 'C:/OpenSSL/include/' \
-L 'C:/curl/lib' -lcurl \ -L 'C:/curl/lib' -lcurl \

22
NEWS.md
View File

@ -1,5 +1,27 @@
# osslsigncode change log # osslsigncode change log
### 2.8 (2024.03.03)
- Microsoft PowerShell signing sponsored by Cisco Systems, Inc.
- fixed setting unauthenticated attributes (Countersignature, Unauthenticated
Data Blob) in a nested signature
- added the "-index" option to verify a specific signature or modify its
unauthenticated attributes
- added CAT file verification
- added listing the contents of a CAT file with the "-verbose" option
- added the new "extract-data" command to extract a PKCS#7 data content to be
signed with "sign" and attached with "attach-signature"
- added PKCS9_SEQUENCE_NUMBER authenticated attribute support
- added the "-ignore-cdp" option to disable CRL Distribution Points (CDP)
online verification
- unsuccessful CRL retrieval and verification changed into a critical error
- the "-p" option modified to also use to configured proxy to connect CRL
Distribution Points
- added implicit allowlisting of the Microsoft Root Authority serial number
00C1008B3C3C8811D13EF663ECDF40
- added listing of certificate chain retrieved from the signature in case of
verification failure
### 2.7 (2023.09.19) ### 2.7 (2023.09.19)
- fixed signing CAB files (by Michael Brown) - fixed signing CAB files (by Michael Brown)

View File

@ -39,7 +39,7 @@ We highly recommend downloading a [release tarball](https://github.com/mtrojnar/
* Install prerequisites on a Debian-based distributions, such as Ubuntu: * Install prerequisites on a Debian-based distributions, such as Ubuntu:
``` ```
sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev sudo apt update && sudo apt install cmake libssl-dev libcurl4-openssl-dev zlib1g-dev python3
``` ```
* Install prerequisites on macOS with Homebrew: * Install prerequisites on macOS with Homebrew:
``` ```

264
appx.c
View File

@ -6,6 +6,7 @@
* Copyright (C) 2023 Michał Trojnara <Michal.Trojnara@stunnel.org> * Copyright (C) 2023 Michał Trojnara <Michal.Trojnara@stunnel.org>
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org> * Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
* *
* APPX files do not support nesting (multiple signature)
*/ */
#define _FILE_OFFSET_BITS 64 #define _FILE_OFFSET_BITS 64
@ -16,10 +17,22 @@
#include <zlib.h> #include <zlib.h>
#include <inttypes.h> #include <inttypes.h>
#ifndef PRIX64
#if defined(_MSC_VER)
#define PRIX64 "I64X"
#else /* _MSC_VER */
#if ULONG_MAX == 0xFFFFFFFFFFFFFFFF
#define PRIX64 "lX"
#else /* ULONG_MAX == 0xFFFFFFFFFFFFFFFF */
#define PRIX64 "llX"
#endif /* ULONG_MAX == 0xFFFFFFFFFFFFFFFF */
#endif /* _MSC_VER */
#endif /* PRIX64 */
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define fseeko _fseeki64 #define fseeko _fseeki64
#define ftello _ftelli64 #define ftello _ftelli64
#endif #endif /* _MSC_VER */
#define EOCDR_SIZE 22 #define EOCDR_SIZE 22
#define ZIP64_EOCD_LOCATOR_SIZE 20 #define ZIP64_EOCD_LOCATOR_SIZE 20
@ -233,26 +246,30 @@ struct appx_ctx_st {
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static const EVP_MD *appx_md_get(FILE_FORMAT_CTX *ctx);
static ASN1_OBJECT *appx_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx); static ASN1_OBJECT *appx_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
static PKCS7 *appx_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
static int appx_hash_length_get(FILE_FORMAT_CTX *ctx); static int appx_hash_length_get(FILE_FORMAT_CTX *ctx);
static int appx_check_file(FILE_FORMAT_CTX *ctx, int detached);
static int appx_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static int appx_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *appx_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *appx_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *appx_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int appx_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *appx_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int appx_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int appx_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *appx_bio_free(BIO *hash, BIO *outdata); static void appx_bio_free(BIO *hash, BIO *outdata);
static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx);
FILE_FORMAT file_format_appx = { FILE_FORMAT file_format_appx = {
.ctx_new = appx_ctx_new, .ctx_new = appx_ctx_new,
.md_get = appx_md_get,
.data_blob_get = appx_spc_sip_info_get, .data_blob_get = appx_spc_sip_info_get,
.pkcs7_contents_get = appx_pkcs7_contents_get,
.hash_length_get = appx_hash_length_get, .hash_length_get = appx_hash_length_get,
.check_file = appx_check_file,
.verify_digests = appx_verify_digests, .verify_digests = appx_verify_digests,
.pkcs7_extract = appx_pkcs7_extract, .pkcs7_extract = appx_pkcs7_extract,
.remove_pkcs7 = appx_remove_pkcs7, .remove_pkcs7 = appx_remove_pkcs7,
.pkcs7_prepare = appx_pkcs7_prepare, .process_data = appx_process_data,
.pkcs7_signature_new = appx_pkcs7_signature_new,
.append_pkcs7 = appx_append_pkcs7, .append_pkcs7 = appx_append_pkcs7,
.bio_free = appx_bio_free, .bio_free = appx_bio_free,
.ctx_cleanup = appx_ctx_cleanup, .ctx_cleanup = appx_ctx_cleanup,
@ -277,8 +294,8 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
static void zipWriteLocalHeader(BIO *bio, uint64_t *sizeonDisk, ZIP_LOCAL_HEADER *heade); static void zipWriteLocalHeader(BIO *bio, uint64_t *sizeonDisk, ZIP_LOCAL_HEADER *heade);
static int zipEntryExist(ZIP_FILE *zip, const char *name); static int zipEntryExist(ZIP_FILE *zip, const char *name);
static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *md); static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *md);
static int zipReadFileDataByName(uint8_t **pData, uint64_t *dataSize, ZIP_FILE *zip, const char *name); static size_t zipReadFileDataByName(uint8_t **pData, ZIP_FILE *zip, const char *name);
static int zipReadFileData(ZIP_FILE *zip, uint8_t **pData, uint64_t *dataSize, ZIP_CENTRAL_DIRECTORY_ENTRY *entry); static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECTORY_ENTRY *entry);
static int zipReadLocalHeader(ZIP_LOCAL_HEADER *header, ZIP_FILE *zip, uint64_t compressedSize); static int zipReadLocalHeader(ZIP_LOCAL_HEADER *header, ZIP_FILE *zip, uint64_t compressedSize);
static int zipInflate(uint8_t *dest, uint64_t *destLen, uint8_t *source, uLong *sourceLen); static int zipInflate(uint8_t *dest, uint64_t *destLen, uint8_t *source, uLong *sourceLen);
static int zipDeflate(uint8_t *dest, uint64_t *destLen, uint8_t *source, uLong sourceLen); static int zipDeflate(uint8_t *dest, uint64_t *destLen, uint8_t *source, uLong sourceLen);
@ -344,10 +361,8 @@ static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *ou
if (zipGetCDEntryByName(zip, APPXBUNDLE_MANIFEST_FILENAME)) { if (zipGetCDEntryByName(zip, APPXBUNDLE_MANIFEST_FILENAME)) {
ctx->appx_ctx->isBundle = 1; ctx->appx_ctx->isBundle = 1;
} }
if (options->nest) if (options->cmd == CMD_SIGN || options->cmd==CMD_ATTACH
/* I've not tried using set_nested_signature as signtool won't do this */ || options->cmd==CMD_ADD || options->cmd == CMD_EXTRACT_DATA) {
printf("Warning: APPX files do not support nesting (multiple signature)\n");
if (options->cmd == CMD_SIGN || options->cmd==CMD_ATTACH || options->cmd==CMD_ADD) {
printf("Warning: Ignore -h option, use the hash algorithm specified in AppxBlockMap.xml\n"); printf("Warning: Ignore -h option, use the hash algorithm specified in AppxBlockMap.xml\n");
} }
if (options->pagehash == 1) if (options->pagehash == 1)
@ -359,6 +374,16 @@ static FILE_FORMAT_CTX *appx_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *ou
return ctx; return ctx;
} }
/*
* Return a hash algorithm specified in the AppxBlockMap.xml file.
* [in] ctx: structure holds input and output data
* [returns] hash algorithm
*/
static const EVP_MD *appx_md_get(FILE_FORMAT_CTX *ctx)
{
return ctx->appx_ctx->md;
}
/* /*
* Allocate and return SpcSipInfo object. * Allocate and return SpcSipInfo object.
* [out] p: SpcSipInfo data * [out] p: SpcSipInfo data
@ -394,6 +419,41 @@ static ASN1_OBJECT *appx_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* OK */ return dtype; /* OK */
} }
/*
* Allocate and return a data content to be signed.
* [in] ctx: structure holds input and output data
* [in] hash: message digest BIO
* [in] md: message digest algorithm
* [returns] data content
*/
static PKCS7 *appx_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
{
ASN1_OCTET_STRING *content;
ZIP_CENTRAL_DIRECTORY_ENTRY *entry;
BIO *bhash;
/* squash unused parameter warnings */
(void)md;
(void)hash;
/* Create and append a new signature content types entry */
entry = zipGetCDEntryByName(ctx->appx_ctx->zip, CONTENT_TYPES_FILENAME);
if (!entry) {
printf("Not a valid .appx file: content types file missing\n");
return NULL; /* FAILED */
}
if (!appx_append_ct_signature_entry(ctx->appx_ctx->zip, entry)) {
return NULL; /* FAILED */
}
bhash = appx_calculate_hashes(ctx);
if (!bhash) {
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(bhash, ctx);
BIO_free_all(bhash);
return pkcs7_set_content(content);
}
/* /*
* Get concatenated hashes length. * Get concatenated hashes length.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -404,25 +464,6 @@ static int appx_hash_length_get(FILE_FORMAT_CTX *ctx)
return ctx->appx_ctx->hashlen; return ctx->appx_ctx->hashlen;
} }
/*
* Check if the signature exists.
* [in] ctx: structure holds input and output data
* [in] detached: embedded/detached PKCS#7 signature switch
* [returns] 0 on error or 1 on success
*/
static int appx_check_file(FILE_FORMAT_CTX *ctx, int detached)
{
if (detached) {
printf("APPX format does not support detached PKCS#7 signature\n");
return 0; /* FAILED */
}
if (!zipEntryExist(ctx->appx_ctx->zip, APP_SIGNATURE_FILENAME)) {
printf("%s does not exist\n", APP_SIGNATURE_FILENAME);
return 0; /* FAILED */
}
return 1; /* OK */
}
/* /*
* Calculate message digest and compare to value retrieved from PKCS#7 signedData. * Calculate message digest and compare to value retrieved from PKCS#7 signedData.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -470,9 +511,15 @@ static PKCS7 *appx_pkcs7_extract(FILE_FORMAT_CTX *ctx)
PKCS7 *p7; PKCS7 *p7;
uint8_t *data = NULL; uint8_t *data = NULL;
const u_char *blob; const u_char *blob;
uint64_t dataSize = 0; size_t dataSize;
if (!zipReadFileDataByName(&data, &dataSize, ctx->appx_ctx->zip, APP_SIGNATURE_FILENAME)) { /* Check if the signature exists */
if (!zipEntryExist(ctx->appx_ctx->zip, APP_SIGNATURE_FILENAME)) {
printf("%s does not exist\n", APP_SIGNATURE_FILENAME);
return NULL; /* FAILED */
}
dataSize = zipReadFileDataByName(&data, ctx->appx_ctx->zip, APP_SIGNATURE_FILENAME);
if (dataSize <= 0) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* P7X format is just 0x504B4358 (PKCX) followed by PKCS#7 data in the DER format */ /* P7X format is just 0x504B4358 (PKCX) followed by PKCS#7 data in the DER format */
@ -496,6 +543,8 @@ static PKCS7 *appx_pkcs7_extract(FILE_FORMAT_CTX *ctx)
*/ */
static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
uint8_t *data = NULL;
size_t dataSize;
uint64_t cdOffset, noEntries = 0; uint64_t cdOffset, noEntries = 0;
ZIP_FILE *zip = ctx->appx_ctx->zip; ZIP_FILE *zip = ctx->appx_ctx->zip;
ZIP_CENTRAL_DIRECTORY_ENTRY *entry = zipGetCDEntryByName(zip, CONTENT_TYPES_FILENAME); ZIP_CENTRAL_DIRECTORY_ENTRY *entry = zipGetCDEntryByName(zip, CONTENT_TYPES_FILENAME);
@ -507,6 +556,12 @@ static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
printf("Not a valid .appx file: content types file missing\n"); printf("Not a valid .appx file: content types file missing\n");
return 1; /* FAILED */ return 1; /* FAILED */
} }
/* read signature data */
dataSize = zipReadFileDataByName(&data, ctx->appx_ctx->zip, APP_SIGNATURE_FILENAME);
if (dataSize <= 0) {
return 1; /* FAILED, no signature */
}
OPENSSL_free(data);
if (!appx_remove_ct_signature_entry(zip, entry)) { if (!appx_remove_ct_signature_entry(zip, entry)) {
printf("Failed to remove signature entry\n"); printf("Failed to remove signature entry\n");
return 1; /* FAILED */ return 1; /* FAILED */
@ -540,60 +595,78 @@ static int appx_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
} }
/* /*
* Obtain an existing signature or create a new one. * Modify specific type data.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO (unused) * [out] hash: message digest BIO (unused)
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] pointer to PKCS#7 structure * [returns] 1 on error or 0 on success
*/ */
static PKCS7 *appx_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int appx_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
PKCS7 *cursig = NULL, *p7 = NULL; ZIP_CENTRAL_DIRECTORY_ENTRY *entry;
/* squash unused parameter warnings */ /* squash unused parameter warnings */
(void)outdata; (void)outdata;
(void)hash; (void)hash;
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) { /* Create and append a new signature content types entry */
/* Obtain an existing signature */
cursig = appx_pkcs7_extract(ctx);
if (!cursig) {
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
}
return cursig;
} else if (ctx->options->cmd == CMD_SIGN) {
BIO *hashes;
ZIP_CENTRAL_DIRECTORY_ENTRY *entry;
/* Create a new signature */
entry = zipGetCDEntryByName(ctx->appx_ctx->zip, CONTENT_TYPES_FILENAME); entry = zipGetCDEntryByName(ctx->appx_ctx->zip, CONTENT_TYPES_FILENAME);
if (!entry) { if (!entry) {
printf("Not a valid .appx file: content types file missing\n"); printf("Not a valid .appx file: content types file missing\n");
return NULL; /* FAILED */ return 1; /* FAILED */
} }
if (!appx_append_ct_signature_entry(ctx->appx_ctx->zip, entry)) { if (!appx_append_ct_signature_entry(ctx->appx_ctx->zip, entry)) {
return NULL; /* FAILED */ return 1; /* FAILED */
} }
/* create hash blob from concatenated APPX hashes */ return 0; /* OK */
}
/*
* 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 *appx_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
{
ASN1_OCTET_STRING *content;
PKCS7 *p7 = NULL;
BIO *hashes;
/* squash unused parameter warnings */
(void)hash;
/* Create hash blob from concatenated APPX hashes */
hashes = appx_calculate_hashes(ctx); hashes = appx_calculate_hashes(ctx);
if (!hashes) { if (!hashes) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* Create a new PKCS#7 signature */
p7 = pkcs7_create(ctx); p7 = pkcs7_create(ctx);
if (!p7) { if (!p7) {
printf("Creating a new signature failed\n"); printf("Creating a new signature failed\n");
BIO_free_all(hashes);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!add_indirect_data_object(p7, hashes, ctx)) { if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
BIO_free_all(hashes); BIO_free_all(hashes);
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(hashes, ctx);
BIO_free_all(hashes);
if (!content) {
printf("Failed to get spcIndirectDataContent\n");
PKCS7_free(p7); PKCS7_free(p7);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
BIO_free_all(hashes); if (!sign_spc_indirect_data_content(p7, content)) {
printf("Failed to set signed content\n");
PKCS7_free(p7);
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
} }
ASN1_OCTET_STRING_free(content);
return p7; /* OK */ return p7; /* OK */
} }
@ -684,27 +757,21 @@ static int appx_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static BIO *appx_bio_free(BIO *hash, BIO *outdata) static void appx_bio_free(BIO *hash, BIO *outdata)
{ {
BIO_free_all(outdata); BIO_free_all(outdata);
BIO_free_all(hash); BIO_free_all(hash);
return NULL; /* OK */
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and PE format specific structure, * Deallocate a FILE_FORMAT_CTX structure and PE format specific structure.
* unmap indata file, unlink outfile.
* [out] ctx: structure holds input and output data * [out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [in] outdata: outdata file BIO * [in] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void appx_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
BIO_free_all(outdata);
}
freeZip(ctx->appx_ctx->zip); freeZip(ctx->appx_ctx->zip);
OPENSSL_free(ctx->appx_ctx->calculatedBMHash); OPENSSL_free(ctx->appx_ctx->calculatedBMHash);
OPENSSL_free(ctx->appx_ctx->calculatedCTHash); OPENSSL_free(ctx->appx_ctx->calculatedCTHash);
@ -1129,7 +1196,8 @@ static int appx_remove_ct_signature_entry(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_E
size_t dataSize, ipos, len; size_t dataSize, ipos, len;
int ret; int ret;
if (!zipReadFileData(zip, &data, (uint64_t *)&dataSize, entry)) { dataSize = zipReadFileData(zip, &data, entry);
if (dataSize <= 0) {
return 0; /* FAILED */ return 0; /* FAILED */
} }
cpos = strstr((const char *)data, SIGNATURE_CONTENT_TYPES_ENTRY); cpos = strstr((const char *)data, SIGNATURE_CONTENT_TYPES_ENTRY);
@ -1161,7 +1229,8 @@ static int appx_append_ct_signature_entry(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_E
size_t dataSize, newSize, ipos, len; size_t dataSize, newSize, ipos, len;
int ret; int ret;
if (!zipReadFileData(zip, &data, (uint64_t *)&dataSize, entry)) { dataSize = zipReadFileData(zip, &data, entry);
if (dataSize <= 0) {
return 0; /* FAILED */ return 0; /* FAILED */
} }
existingEntry = strstr((const char *)data, SIGNATURE_CONTENT_TYPES_ENTRY); existingEntry = strstr((const char *)data, SIGNATURE_CONTENT_TYPES_ENTRY);
@ -1196,13 +1265,13 @@ static int appx_append_ct_signature_entry(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_E
static const EVP_MD *appx_get_md(ZIP_FILE *zip) static const EVP_MD *appx_get_md(ZIP_FILE *zip)
{ {
uint8_t *data = NULL; uint8_t *data = NULL;
uint64_t dataSize = 0;
char *start, *end, *pos; char *start, *end, *pos;
char *valueStart = NULL, *valueEnd = NULL; char *valueStart = NULL, *valueEnd = NULL;
const EVP_MD *md = NULL; const EVP_MD *md = NULL;
size_t slen; size_t slen, dataSize;
if (!zipReadFileDataByName(&data, &dataSize, zip, BLOCK_MAP_FILENAME)) { dataSize = zipReadFileDataByName(&data, zip, BLOCK_MAP_FILENAME);
if (dataSize <= 0) {
printf("Could not read: %s\n", BLOCK_MAP_FILENAME); printf("Could not read: %s\n", BLOCK_MAP_FILENAME);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -1527,7 +1596,7 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
memset(&header, 0, sizeof(header)); memset(&header, 0, sizeof(header));
if (entry->offsetOfLocalHeader >= (uint64_t)zip->fileSize) { if (entry->offsetOfLocalHeader >= (uint64_t)zip->fileSize) {
printf("Corrupted relative offset of local header : 0x%08lX\n", entry->offsetOfLocalHeader); printf("Corrupted relative offset of local header : 0x%08" PRIX64 "\n", entry->offsetOfLocalHeader);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (fseeko(zip->file, (int64_t)entry->offsetOfLocalHeader, SEEK_SET) < 0) { if (fseeko(zip->file, (int64_t)entry->offsetOfLocalHeader, SEEK_SET) < 0) {
@ -1548,7 +1617,7 @@ static int zipRewriteData(ZIP_FILE *zip, ZIP_CENTRAL_DIRECTORY_ENTRY *entry, BIO
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (entry->compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) { if (entry->compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) {
printf("Corrupted compressedSize : 0x%08lX\n", entry->compressedSize); printf("Corrupted compressedSize : 0x%08" PRIX64 "\n", entry->compressedSize);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (fseeko(zip->file, (int64_t)entry->compressedSize, SEEK_CUR) < 0) { if (fseeko(zip->file, (int64_t)entry->compressedSize, SEEK_CUR) < 0) {
@ -1677,11 +1746,12 @@ static int zipEntryExist(ZIP_FILE *zip, const char *name)
static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *md) static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *md)
{ {
uint8_t *data = NULL; uint8_t *data = NULL;
uint64_t dataSize = 0; size_t dataSize;
u_char *mdbuf = NULL; u_char *mdbuf = NULL;
BIO *bhash; BIO *bhash;
if (!zipReadFileDataByName(&data, &dataSize, zip, fileName)) { dataSize = zipReadFileDataByName(&data, zip, fileName);
if (dataSize <= 0) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
bhash = BIO_new(BIO_f_md()); bhash = BIO_new(BIO_f_md());
@ -1708,12 +1778,11 @@ static u_char *zipCalcDigest(ZIP_FILE *zip, const char *fileName, const EVP_MD *
/* /*
* Read file data by name. * Read file data by name.
* [out] pData: pointer to data * [out] pData: pointer to data
* [out] dataSize: data size
* [in] zip: structure holds specific ZIP data * [in] zip: structure holds specific ZIP data
* [in] name: one of ZIP container file * [in] name: one of ZIP container file
* [returns] 0 on error or 1 on success * [returns] 0 on error or data size on success
*/ */
static int zipReadFileDataByName(uint8_t **pData, uint64_t *dataSize, ZIP_FILE *zip, const char *name) static size_t zipReadFileDataByName(uint8_t **pData, ZIP_FILE *zip, const char *name)
{ {
ZIP_CENTRAL_DIRECTORY_ENTRY *entry; ZIP_CENTRAL_DIRECTORY_ENTRY *entry;
uint64_t noEntries = 0; uint64_t noEntries = 0;
@ -1729,7 +1798,7 @@ static int zipReadFileDataByName(uint8_t **pData, uint64_t *dataSize, ZIP_FILE *
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!strcmp(entry->fileName, name)) { if (!strcmp(entry->fileName, name)) {
return zipReadFileData(zip, pData, dataSize, entry); return zipReadFileData(zip, pData, entry);
} }
} }
return 0; /* FAILED */ return 0; /* FAILED */
@ -1739,20 +1808,19 @@ static int zipReadFileDataByName(uint8_t **pData, uint64_t *dataSize, ZIP_FILE *
* Read file data. * Read file data.
* [in, out] zip: structure holds specific ZIP data * [in, out] zip: structure holds specific ZIP data
* [out] pData: pointer to data * [out] pData: pointer to data
* [out] dataSize: data size
* [in] entry: central directory structure * [in] entry: central directory structure
* [returns] 0 on error or 1 on success * [returns] 0 on error or data size on success
*/ */
static int zipReadFileData(ZIP_FILE *zip, uint8_t **pData, uint64_t *dataSize, ZIP_CENTRAL_DIRECTORY_ENTRY *entry) static size_t zipReadFileData(ZIP_FILE *zip, uint8_t **pData, ZIP_CENTRAL_DIRECTORY_ENTRY *entry)
{ {
FILE *file = zip->file; FILE *file = zip->file;
uint8_t *compressedData = NULL; uint8_t *compressedData = NULL;
uint64_t compressedSize = 0; uint64_t compressedSize = 0;
uint64_t uncompressedSize = 0; uint64_t uncompressedSize = 0;
size_t size; size_t size, dataSize = 0;
if (entry->offsetOfLocalHeader >= (uint64_t)zip->fileSize) { if (entry->offsetOfLocalHeader >= (uint64_t)zip->fileSize) {
printf("Corrupted relative offset of local header : 0x%08lX\n", entry->offsetOfLocalHeader); printf("Corrupted relative offset of local header : 0x%08" PRIX64 "\n", entry->offsetOfLocalHeader);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (fseeko(file, (int64_t)entry->offsetOfLocalHeader, SEEK_SET) < 0) { if (fseeko(file, (int64_t)entry->offsetOfLocalHeader, SEEK_SET) < 0) {
@ -1784,7 +1852,7 @@ static int zipReadFileData(ZIP_FILE *zip, uint8_t **pData, uint64_t *dataSize, Z
OPENSSL_free(header.extraField); OPENSSL_free(header.extraField);
if (compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) { if (compressedSize > (uint64_t)zip->fileSize - entry->offsetOfLocalHeader) {
printf("Corrupted compressedSize : 0x%08lX\n", entry->compressedSize); printf("Corrupted compressedSize : 0x%08" PRIX64 "\n", entry->compressedSize);
return 0; /* FAILED */ return 0; /* FAILED */
} }
compressedData = OPENSSL_zalloc(compressedSize + 1); compressedData = OPENSSL_zalloc(compressedSize + 1);
@ -1796,15 +1864,19 @@ static int zipReadFileData(ZIP_FILE *zip, uint8_t **pData, uint64_t *dataSize, Z
compressedData[compressedSize] = 0; compressedData[compressedSize] = 0;
} }
if (entry->compression == COMPRESSION_NONE) { if (entry->compression == COMPRESSION_NONE) {
if (compressedSize == 0) {
OPENSSL_free(compressedData);
return 0; /* FAILED */
}
*pData = compressedData; *pData = compressedData;
*dataSize = compressedSize; dataSize = compressedSize;
} else if (entry->compression == COMPRESSION_DEFLATE) { } else if (entry->compression == COMPRESSION_DEFLATE) {
uint8_t *uncompressedData = OPENSSL_zalloc(uncompressedSize + 1); uint8_t *uncompressedData = OPENSSL_zalloc(uncompressedSize + 1);
uint64_t destLen = uncompressedSize; uint64_t destLen = uncompressedSize;
uint64_t sourceLen = compressedSize; uint64_t sourceLen = compressedSize;
int ret; int ret;
ret = zipInflate(uncompressedData, &destLen, compressedData, &sourceLen); ret = zipInflate(uncompressedData, &destLen, compressedData, (uLong *)&sourceLen);
OPENSSL_free(compressedData); OPENSSL_free(compressedData);
if (ret != Z_OK) { if (ret != Z_OK) {
@ -1812,15 +1884,19 @@ static int zipReadFileData(ZIP_FILE *zip, uint8_t **pData, uint64_t *dataSize, Z
OPENSSL_free(uncompressedData); OPENSSL_free(uncompressedData);
return 0; /* FAILED */ return 0; /* FAILED */
} else { } else {
if (destLen == 0) {
OPENSSL_free(uncompressedData);
return 0; /* FAILED */
}
*pData = uncompressedData; *pData = uncompressedData;
*dataSize = destLen; dataSize = destLen;
} }
} else { } else {
printf("Unsupported compression mode: %d\n", entry->compression); printf("Unsupported compression mode: %d\n", entry->compression);
OPENSSL_free(compressedData); OPENSSL_free(compressedData);
return 0; /* FAILED */ return 0; /* FAILED */
} }
return 1; /* OK */ return dataSize;
} }
/* /*
@ -1893,7 +1969,7 @@ static int zipReadLocalHeader(ZIP_LOCAL_HEADER *header, ZIP_FILE *zip, uint64_t
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (compressedSize > (uint64_t)(zip->fileSize - offset)) { if (compressedSize > (uint64_t)(zip->fileSize - offset)) {
printf("Corrupted compressedSize : 0x%08lX\n", compressedSize); printf("Corrupted compressedSize : 0x%08" PRIX64 "\n", compressedSize);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (fseeko(file, (int64_t)compressedSize, SEEK_CUR) < 0) { if (fseeko(file, (int64_t)compressedSize, SEEK_CUR) < 0) {
@ -2133,7 +2209,7 @@ static ZIP_FILE *openZip(const char *filename)
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (zip->locator.eocdOffset >= (uint64_t)zip->fileSize) { if (zip->locator.eocdOffset >= (uint64_t)zip->fileSize) {
printf("Corrupted end of central directory locator offset : 0x%08lX\n", zip->locator.eocdOffset); printf("Corrupted end of central directory locator offset : 0x%08" PRIX64 "\n", zip->locator.eocdOffset);
freeZip(zip); freeZip(zip);
return 0; /* FAILED */ return 0; /* FAILED */
} }
@ -2162,13 +2238,13 @@ static ZIP_FILE *openZip(const char *filename)
zip->centralDirectorySize = zip->eocdr.centralDirectorySize; zip->centralDirectorySize = zip->eocdr.centralDirectorySize;
zip->centralDirectoryRecordCount = (uint64_t)zip->eocdr.totalEntries; zip->centralDirectoryRecordCount = (uint64_t)zip->eocdr.totalEntries;
if (zip->centralDirectoryRecordCount > UINT16_MAX) { if (zip->centralDirectoryRecordCount > UINT16_MAX) {
printf("Corrupted total number of entries in the central directory : 0x%08lX\n", zip->centralDirectoryRecordCount); printf("Corrupted total number of entries in the central directory : 0x%08" PRIX64 "\n", zip->centralDirectoryRecordCount);
freeZip(zip); freeZip(zip);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
} }
if (zip->centralDirectoryOffset >= (uint64_t)zip->fileSize) { if (zip->centralDirectoryOffset >= (uint64_t)zip->fileSize) {
printf("Corrupted central directory offset : 0x%08lX\n", zip->centralDirectoryOffset); printf("Corrupted central directory offset : 0x%08" PRIX64 "\n", zip->centralDirectoryOffset);
freeZip(zip); freeZip(zip);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
@ -2560,7 +2636,7 @@ static int readZip64EOCDR(ZIP64_EOCDR *eocdr, FILE *file, uint64_t offset)
/* zip64 extensible data sector (comment) */ /* zip64 extensible data sector (comment) */
eocdr->commentLen = eocdr->eocdrSize - 44; eocdr->commentLen = eocdr->eocdrSize - 44;
if (eocdr->commentLen > UINT16_MAX) { if (eocdr->commentLen > UINT16_MAX) {
printf("Corrupted file comment length : 0x%08lX\n", eocdr->commentLen); printf("Corrupted file comment length : 0x%08" PRIX64 "\n", eocdr->commentLen);
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (eocdr->commentLen > 0) { if (eocdr->commentLen > 0) {

211
cab.c
View File

@ -43,32 +43,38 @@ struct cab_ctx_st {
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx); static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
static int cab_hash_length_get(FILE_FORMAT_CTX *ctx); static int cab_hash_length_get(FILE_FORMAT_CTX *ctx);
static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached);
static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md); static u_char *cab_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int cab_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *cab_bio_free(BIO *hash, BIO *outdata); static void cab_bio_free(BIO *hash, BIO *outdata);
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx);
static int cab_is_detaching_supported(void);
FILE_FORMAT file_format_cab = { FILE_FORMAT file_format_cab = {
.ctx_new = cab_ctx_new, .ctx_new = cab_ctx_new,
.data_blob_get = cab_obsolete_link_get, .data_blob_get = cab_obsolete_link_get,
.pkcs7_contents_get = cab_pkcs7_contents_get,
.hash_length_get = cab_hash_length_get, .hash_length_get = cab_hash_length_get,
.check_file = cab_check_file,
.digest_calc = cab_digest_calc, .digest_calc = cab_digest_calc,
.verify_digests = cab_verify_digests, .verify_digests = cab_verify_digests,
.pkcs7_extract = cab_pkcs7_extract, .pkcs7_extract = cab_pkcs7_extract,
.pkcs7_extract_to_nest = cab_pkcs7_extract_to_nest,
.remove_pkcs7 = cab_remove_pkcs7, .remove_pkcs7 = cab_remove_pkcs7,
.pkcs7_prepare = cab_pkcs7_prepare, .process_data = cab_process_data,
.pkcs7_signature_new = cab_pkcs7_signature_new,
.append_pkcs7 = cab_append_pkcs7, .append_pkcs7 = cab_append_pkcs7,
.update_data_size = cab_update_data_size, .update_data_size = cab_update_data_size,
.bio_free = cab_bio_free, .bio_free = cab_bio_free,
.ctx_cleanup = cab_ctx_cleanup .ctx_cleanup = cab_ctx_cleanup,
.is_detaching_supported = cab_is_detaching_supported
}; };
/* Prototypes */ /* Prototypes */
@ -77,6 +83,7 @@ static int cab_add_jp_attribute(PKCS7 *p7, int jp);
static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t len, uint16_t flags); static size_t cab_write_optional_names(BIO *outdata, char *indata, size_t len, uint16_t flags);
static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static int cab_check_file(FILE_FORMAT_CTX *ctx);
/* /*
* FILE_FORMAT method definitions * FILE_FORMAT method definitions
@ -104,12 +111,12 @@ static FILE_FORMAT_CTX *cab_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (memcmp(options->indata, "MSCF", 4)) { if (memcmp(options->indata, "MSCF", 4)) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
cab_ctx = cab_ctx_get(options->indata, filesize); cab_ctx = cab_ctx_get(options->indata, filesize);
if (!cab_ctx) { if (!cab_ctx) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX)); ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
@ -151,6 +158,32 @@ static ASN1_OBJECT *cab_obsolete_link_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* OK */ return dtype; /* OK */
} }
/*
* Allocate and return a data content to be signed.
* [in] ctx: structure holds input and output data
* [in] hash: message digest BIO
* [in] md: message digest algorithm
* [returns] data content
*/
static PKCS7 *cab_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
{
ASN1_OCTET_STRING *content;
/* squash the unused parameter warning, use initialized message digest BIO */
(void)md;
/* Strip current signature and modify header */
if (ctx->cab_ctx->header_size == 20) {
if (!cab_modify_header(ctx, hash, NULL))
return NULL; /* FAILED */
} else {
if (!cab_add_header(ctx, hash, NULL))
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(hash, ctx);
return pkcs7_set_content(content);
}
/* /*
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash) * [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
@ -160,34 +193,6 @@ static int cab_hash_length_get(FILE_FORMAT_CTX *ctx)
return EVP_MD_size(ctx->options->md); return EVP_MD_size(ctx->options->md);
} }
/*
* Check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [in] detached: embedded/detached PKCS#7 signature switch
* [returns] 0 on error or 1 on success
*/
static int cab_check_file(FILE_FORMAT_CTX *ctx, int detached)
{
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
}
if (detached) {
printf("Checking the specified catalog file\n\n");
return 1; /* OK */
}
if (ctx->cab_ctx->header_size != 20) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
return 1; /* OK */
}
/* /*
* Compute a message digest value of the signed or unsigned CAB file. * Compute a message digest value of the signed or unsigned CAB file.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -363,11 +368,23 @@ static int cab_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
*/ */
static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx) static PKCS7 *cab_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{ {
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0 const u_char *blob;
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
if (!cab_check_file(ctx)) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
return pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen); blob = (u_char *)ctx->options->indata + ctx->cab_ctx->sigpos;
return d2i_PKCS7(NULL, &blob, ctx->cab_ctx->siglen);
}
/*
* Extract existing signature in DER format.
* [in] ctx: structure holds input and output data
* pointer to PKCS#7 structure
*/
static PKCS7 *cab_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
{
return cab_pkcs7_extract(ctx);
} }
/* /*
@ -382,11 +399,15 @@ static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
size_t i, written, len; size_t i, written, len;
uint32_t tmp; uint32_t tmp;
uint16_t nfolders, flags; uint16_t nfolders, flags;
char *buf = OPENSSL_malloc(SIZE_64K); char *buf;
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)hash; (void)hash;
if (!cab_check_file(ctx)) {
return 1; /* FAILED, no signature */
}
buf = OPENSSL_malloc(SIZE_64K);
/* /*
* u1 signature[4] 4643534D MSCF: 0-3 * u1 signature[4] 4643534D MSCF: 0-3
* u4 reserved1 00000000: 4-7 * u4 reserved1 00000000: 4-7
@ -448,47 +469,36 @@ static int cab_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
} }
/* /*
* Obtain an existing signature or create a new one. * Modify specific type data and calculate a hash (message digest) of data.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [returns] pointer to PKCS#7 structure * [returns] 1 on error or 0 on success
*/ */
static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int cab_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
PKCS7 *cursig = NULL, *p7 = NULL;
/* Strip current signature and modify header */ /* Strip current signature and modify header */
if (ctx->cab_ctx->header_size == 20) { if (ctx->cab_ctx->header_size == 20) {
if (!cab_modify_header(ctx, hash, outdata)) if (!cab_modify_header(ctx, hash, outdata))
return NULL; /* FAILED */ return 1; /* FAILED */
} else { } else {
if (!cab_add_header(ctx, hash, outdata)) if (!cab_add_header(ctx, hash, outdata))
return NULL; /* FAILED */ return 1; /* FAILED */
} }
/* Obtain a current signature from previously-signed file */ return 0; /* OK */
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest)
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|| ctx->options->cmd == CMD_ADD) {
cursig = pkcs7_get(ctx->options->indata, ctx->cab_ctx->sigpos, ctx->cab_ctx->siglen);
if (!cursig) {
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
} }
if (ctx->options->cmd == CMD_ADD)
p7 = cursig; /*
} * Create a new PKCS#7 signature.
if (ctx->options->cmd == CMD_ATTACH) { * [in, out] ctx: structure holds input and output data
/* Obtain an existing PKCS#7 signature */ * [out] hash: message digest BIO
p7 = pkcs7_get_sigfile(ctx); * [returns] pointer to PKCS#7 structure
if (!p7) { */
printf("Unable to extract valid signature\n"); static PKCS7 *cab_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
PKCS7_free(cursig); {
return NULL; /* FAILED */ ASN1_OCTET_STRING *content;
} PKCS7 *p7 = pkcs7_create(ctx);
} else if (ctx->options->cmd == CMD_SIGN) {
/* Create a new PKCS#7 signature */
p7 = pkcs7_create(ctx);
if (!p7) { if (!p7) {
printf("Creating a new signature failed\n"); printf("Creating a new signature failed\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
@ -498,14 +508,23 @@ static PKCS7 *cab_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
PKCS7_free(p7); PKCS7_free(p7);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!add_indirect_data_object(p7, hash, ctx)) { if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7); PKCS7_free(p7);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
printf("Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
} }
if (ctx->options->nest) if (!sign_spc_indirect_data_content(p7, content)) {
ctx->options->prevsig = cursig; printf("Failed to set signed content\n");
PKCS7_free(p7);
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
ASN1_OCTET_STRING_free(content);
return p7; return p7;
} }
@ -580,40 +599,33 @@ static void cab_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] none * [returns] none
*/ */
static BIO *cab_bio_free(BIO *hash, BIO *outdata) static void cab_bio_free(BIO *hash, BIO *outdata)
{ {
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)outdata; (void)outdata;
BIO_free_all(hash); BIO_free_all(hash);
return NULL;
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and CAB format specific structure, * Deallocate a FILE_FORMAT_CTX structure and CAB format specific structure,
* unmap indata file, unlink outfile. * unmap indata file.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [in] outdata: outdata file BIO * [in] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void cab_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
if (ctx->options->outfile) {
#ifdef WIN32
_unlink(ctx->options->outfile);
#else
unlink(ctx->options->outfile);
#endif /* WIN32 */
}
}
unmap_file(ctx->options->indata, ctx->cab_ctx->fileend); unmap_file(ctx->options->indata, ctx->cab_ctx->fileend);
OPENSSL_free(ctx->cab_ctx); OPENSSL_free(ctx->cab_ctx);
OPENSSL_free(ctx); OPENSSL_free(ctx);
} }
static int cab_is_detaching_supported(void)
{
return 1; /* OK */
}
/* /*
* CAB helper functions * CAB helper functions
*/ */
@ -931,6 +943,29 @@ static int cab_add_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
return 1; /* OK */ return 1; /* OK */
} }
/*
* Check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int cab_check_file(FILE_FORMAT_CTX *ctx)
{
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
}
if (ctx->cab_ctx->header_size != 20) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
if (ctx->cab_ctx->sigpos == 0 || ctx->cab_ctx->siglen == 0
|| ctx->cab_ctx->sigpos > ctx->cab_ctx->fileend) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
return 1; /* OK */
}
/* /*
Local Variables: Local Variables:
c-basic-offset: 4 c-basic-offset: 4

387
cat.c
View File

@ -5,34 +5,49 @@
* Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org> * Author: Małgorzata Olszówka <Malgorzata.Olszowka@stunnel.org>
* *
* Catalog files are a bit odd, in that they are only a PKCS7 blob. * Catalog files are a bit odd, in that they are only a PKCS7 blob.
* CAT files do not support nesting (multiple signature)
*/ */
#include "osslsigncode.h" #include "osslsigncode.h"
#include "helpers.h" #include "helpers.h"
const u_char pkcs7_signed_data[] = { typedef struct {
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, ASN1_BMPSTRING *tag;
0x01, 0x07, 0x02, ASN1_INTEGER *flags;
}; ASN1_OCTET_STRING *value;
} CatNameValueContent;
DECLARE_ASN1_FUNCTIONS(CatNameValueContent)
ASN1_SEQUENCE(CatNameValueContent) = {
ASN1_SIMPLE(CatNameValueContent, tag, ASN1_BMPSTRING),
ASN1_SIMPLE(CatNameValueContent, flags, ASN1_INTEGER),
ASN1_SIMPLE(CatNameValueContent, value, ASN1_OCTET_STRING)
} ASN1_SEQUENCE_END(CatNameValueContent)
IMPLEMENT_ASN1_FUNCTIONS(CatNameValueContent)
struct cat_ctx_st { struct cat_ctx_st {
uint32_t sigpos; uint32_t sigpos;
uint32_t siglen; uint32_t siglen;
uint32_t fileend; uint32_t fileend;
PKCS7 *p7;
}; };
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *cat_bio_free(BIO *hash, BIO *outdata); static void cat_bio_free(BIO *hash, BIO *outdata);
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx);
FILE_FORMAT file_format_cat = { FILE_FORMAT file_format_cat = {
.ctx_new = cat_ctx_new, .ctx_new = cat_ctx_new,
.verify_digests = cat_verify_digests,
.pkcs7_extract = cat_pkcs7_extract, .pkcs7_extract = cat_pkcs7_extract,
.pkcs7_prepare = cat_pkcs7_prepare, .pkcs7_signature_new = cat_pkcs7_signature_new,
.append_pkcs7 = cat_append_pkcs7, .append_pkcs7 = cat_append_pkcs7,
.bio_free = cat_bio_free, .bio_free = cat_bio_free,
.ctx_cleanup = cat_ctx_cleanup, .ctx_cleanup = cat_ctx_cleanup,
@ -40,6 +55,14 @@ FILE_FORMAT file_format_cat = {
/* Prototypes */ /* Prototypes */
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize); static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize);
static int cat_add_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 * FILE_FORMAT method definitions
@ -58,18 +81,10 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
CAT_CTX *cat_ctx; CAT_CTX *cat_ctx;
uint32_t filesize; uint32_t filesize;
/* squash unused parameter warnings */ if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH || options->cmd == CMD_EXTRACT_DATA) {
(void)outdata;
(void)hash;
if (options->cmd == CMD_REMOVE || options->cmd==CMD_ATTACH) {
printf("Unsupported command\n"); printf("Unsupported command\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (options->cmd == CMD_VERIFY) {
printf("Use -catalog option\n");
return NULL; /* FAILED */
}
filesize = get_file_size(options->infile); filesize = get_file_size(options->infile);
if (filesize == 0) if (filesize == 0)
return NULL; /* FAILED */ return NULL; /* FAILED */
@ -78,15 +93,9 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
if (!options->indata) { if (!options->indata) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
/* the maximum size of a supported cat file is (2^24 -1) bytes */
if (memcmp(options->indata + ((GET_UINT8_LE(options->indata+1) == 0x82) ? 4 : 5),
pkcs7_signed_data, sizeof pkcs7_signed_data)) {
unmap_file(options->infile, filesize);
return NULL; /* FAILED */
}
cat_ctx = cat_ctx_get(options->indata, filesize); cat_ctx = cat_ctx_get(options->indata, filesize);
if (!cat_ctx) { if (!cat_ctx) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX)); ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
@ -97,9 +106,8 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
/* Push hash on outdata, if hash is NULL the function does nothing */ /* Push hash on outdata, if hash is NULL the function does nothing */
BIO_push(hash, outdata); BIO_push(hash, outdata);
if (options->nest) if (options->cmd == CMD_VERIFY)
/* I've not tried using set_nested_signature as signtool won't do this */ printf("Warning: Use -catalog option to verify that a file, listed in catalog file, is signed\n");
printf("Warning: CAT files do not support nesting (multiple signature)\n");
if (options->jp >= 0) if (options->jp >= 0)
printf("Warning: -jp option is only valid for CAB files\n"); printf("Warning: -jp option is only valid for CAB files\n");
if (options->pagehash == 1) if (options->pagehash == 1)
@ -109,6 +117,19 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
return ctx; return ctx;
} }
/*
* ContentInfo value is the inner content of pkcs7-signedData.
* An extra verification is not necessary when a content type data
* is the inner content of the signed-data type.
*/
static int cat_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
{
/* squash unused parameter warnings */
(void)ctx;
(void)p7;
return 1; /* OK */
}
/* /*
* Extract existing signature in DER format. * Extract existing signature in DER format.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -116,76 +137,53 @@ static FILE_FORMAT_CTX *cat_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
*/ */
static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx) static PKCS7 *cat_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{ {
return pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen); if (!cat_check_file(ctx)) {
return NULL; /* FAILED */
}
return PKCS7_dup(ctx->cat_ctx->p7);
} }
/* /*
* Obtain an existing signature or create a new one. * Create a new PKCS#7 signature.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO (unused) * [out] hash: message digest BIO (unused)
* [out] outdata: outdata file BIO (unused)
* [returns] pointer to PKCS#7 structure * [returns] pointer to PKCS#7 structure
*/ */
static PKCS7 *cat_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static PKCS7 *cat_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
{ {
PKCS7 *cursig = NULL, *p7 = NULL; PKCS7 *p7 = NULL;
/* squash unused parameter warnings */ /* squash unused parameter warnings */
(void)outdata;
(void)hash; (void)hash;
/* Obtain an existing signature */
cursig = pkcs7_get(ctx->options->indata, ctx->cat_ctx->sigpos, ctx->cat_ctx->siglen);
if (!cursig) {
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
}
if (ctx->options->cmd == CMD_ADD || ctx->options->cmd == CMD_ATTACH) {
p7 = cursig;
} else if (ctx->options->cmd == CMD_SIGN) {
/* Create a new signature */
p7 = pkcs7_create(ctx); p7 = pkcs7_create(ctx);
if (!p7) { if (!p7) {
printf("Creating a new signature failed\n"); printf("Creating a new signature failed\n");
PKCS7_free(cursig);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!add_ms_ctl_object(p7, cursig)) { if (!cat_add_ms_ctl_object(p7)) {
printf("Adding MS_CTL_OBJID failed\n"); printf("Adding MS_CTL_OBJID failed\n");
PKCS7_free(p7); PKCS7_free(p7);
PKCS7_free(cursig);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
PKCS7_free(cursig); if (!cat_sign_ms_ctl_content(p7, ctx->cat_ctx->p7->d.sign->contents)) {
printf("Failed to set signed content\n");
PKCS7_free(p7);
return 0; /* FAILED */
} }
return p7; /* OK */ return p7; /* OK */
} }
/* /*
* Append signature to the outfile. * Append signature to the outfile.
* [in, out] ctx: structure holds input and output data (unused) * [in, out] ctx: structure holds input and output data
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [in] p7: PKCS#7 signature * [in] p7: PKCS#7 signature
* [returns] 1 on error or 0 on success * [returns] 1 on error or 0 on success
*/ */
static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7) static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
{ {
u_char *p = NULL; return data_write_pkcs7(ctx, outdata, p7);
int len; /* signature length */
/* squash the unused parameter warning */
(void)ctx;
if (((len = i2d_PKCS7(p7, NULL)) <= 0)
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
printf("i2d_PKCS memory allocation failed: %d\n", len);
return 1; /* FAILED */
}
i2d_PKCS7(p7, &p);
p -= len;
i2d_PKCS7_bio(outdata, p7);
OPENSSL_free(p);
return 0; /* OK */
} }
/* /*
@ -194,36 +192,25 @@ static int cat_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] none * [returns] none
*/ */
static BIO *cat_bio_free(BIO *hash, BIO *outdata) static void cat_bio_free(BIO *hash, BIO *outdata)
{ {
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)outdata; (void)outdata;
BIO_free_all(hash); BIO_free_all(hash);
return NULL;
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and CAT format specific structure, * Deallocate a FILE_FORMAT_CTX structure and CAT format specific structure,
* unmap indata file, unlink outfile. * unmap indata file.
* [in, out] ctx: structure holds all input and output data * [in, out] ctx: structure holds all input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [in] outdata: outdata file BIO * [in] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
if (ctx->options->outfile) {
#ifdef WIN32
_unlink(ctx->options->outfile);
#else
unlink(ctx->options->outfile);
#endif /* WIN32 */
}
}
unmap_file(ctx->options->indata, ctx->cat_ctx->fileend); unmap_file(ctx->options->indata, ctx->cat_ctx->fileend);
PKCS7_free(ctx->cat_ctx->p7);
OPENSSL_free(ctx->cat_ctx); OPENSSL_free(ctx->cat_ctx);
OPENSSL_free(ctx); OPENSSL_free(ctx);
} }
@ -233,25 +220,255 @@ static void cat_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
*/ */
/* /*
* Verify mapped CAT file TODO and create CAT format specific structure. * Verify mapped PKCS#7 (CAT) file and create CAT format specific structure.
* [in] indata: mapped CAT file (unused) * [in] indata: mapped file
* [in] filesize: size of CAT file * [in] filesize: size of file
* [returns] pointer to CAT format specific structure * [returns] pointer to CAT format specific structure
*/ */
static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize) static CAT_CTX *cat_ctx_get(char *indata, uint32_t filesize)
{ {
CAT_CTX *cat_ctx; CAT_CTX *cat_ctx;
PKCS7 *p7;
/* squash the unused parameter warning */ p7 = pkcs7_read_data(indata, filesize);
(void)indata; if (!p7)
return NULL; /* FAILED */
if (!PKCS7_type_is_signed(p7)) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX)); cat_ctx = OPENSSL_zalloc(sizeof(CAT_CTX));
cat_ctx->p7 = p7;
cat_ctx->sigpos = 0; cat_ctx->sigpos = 0;
cat_ctx->siglen = filesize; cat_ctx->siglen = filesize;
cat_ctx->fileend = filesize; cat_ctx->fileend = filesize;
return cat_ctx; /* OK */ return cat_ctx; /* OK */
} }
/*
* Add "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;
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)) {
printf("Failed to sign content\n");
return 0; /* FAILED */
}
if (!PKCS7_set_content(p7, PKCS7_dup(contents))) {
printf("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) {
printf("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(stdout);
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) {
printf("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) {
printf("Init error\n\n");
return 0; /* FAILED */
}
signer_info = PKCS7_get_signer_info(ctx->cat_ctx->p7);
if (!signer_info) {
printf("Failed catalog file\n\n");
return 0; /* FAILED */
}
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
if (ctx->options->verbose) {
(void)cat_list_content(ctx->cat_ctx->p7);
}
return 1; /* OK */
}
/* /*
Local Variables: Local Variables:
c-basic-offset: 4 c-basic-offset: 4

View File

@ -5,6 +5,10 @@
option(STOP_SERVER "Stop HTTP server after tests" ON) option(STOP_SERVER "Stop HTTP server after tests" ON)
# Remove http proxy configuration that may change behavior
unset(ENV{HTTP_PROXY})
unset(ENV{http_proxy})
include(FindPython3) include(FindPython3)
set(TEST_DIR "${PROJECT_BINARY_DIR}/Testing") set(TEST_DIR "${PROJECT_BINARY_DIR}/Testing")
@ -70,6 +74,8 @@ else(WIN32 OR APPLE)
RESULT_VARIABLE server_error) RESULT_VARIABLE server_error)
if(server_error) if(server_error)
message(STATUS "HTTP server failed: ${server_error}") message(STATUS "HTTP server failed: ${server_error}")
message(STATUS "Use python3 to start HTTP server: \"python3 Testing/server_http.py --port 19254\"")
set(default_certs 1)
else(server_error) else(server_error)
# Check if file exists and is no-empty # Check if file exists and is no-empty
while(NOT EXISTS ${LOGS}/port.log) while(NOT EXISTS ${LOGS}/port.log)
@ -123,9 +129,10 @@ string(SUBSTRING ${sha256sum} 0 64 leafhash)
enable_testing() enable_testing()
set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat") set(extensions_all "exe" "ex_" "msi" "256appx" "512appx" "cat" "ps1" "psc1" "mof")
set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx") set(extensions_nocat "exe" "ex_" "msi" "256appx" "512appx" "ps1" "psc1" "mof")
set(extensions_nocatappx "exe" "ex_" "msi") set(extensions_nocatappx "exe" "ex_" "msi" "ps1" "psc1" "mof")
set(formats "pem" "der")
# Test 1 # Test 1
# Print osslsigncode version # Print osslsigncode version
@ -134,7 +141,7 @@ add_test(NAME version
### Sign ### ### Sign ###
# Tests 2-5 # Tests 2-7
# Sign with PKCS#12 container with legacy RC2-40-CBC private key and certificate encryption algorithm # Sign with PKCS#12 container with legacy RC2-40-CBC private key and certificate encryption algorithm
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
add_test( add_test(
@ -142,7 +149,7 @@ foreach(ext ${extensions_all})
COMMAND osslsigncode "sign" COMMAND osslsigncode "sign"
"-pkcs12" "${CERTS}/legacy.p12" "-pkcs12" "${CERTS}/legacy.p12"
"-readpass" "${CERTS}/password.txt" "-readpass" "${CERTS}/password.txt"
"-ac" "${CERTS}/crosscert.pem" "-ac" "${CERTS}/CAcross.pem"
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT "-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
"-add-msi-dse" "-add-msi-dse"
"-comm" "-comm"
@ -154,7 +161,7 @@ foreach(ext ${extensions_all})
"-out" "${FILES}/legacy.${ext}") "-out" "${FILES}/legacy.${ext}")
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
# Tests 6-9 # Tests 8-13
# Sign with PKCS#12 container with legacy RC2-40-CBC private key and certificate encryption algorithm # Sign with PKCS#12 container with legacy RC2-40-CBC private key and certificate encryption algorithm
# Disable legacy mode and don't automatically load the legacy provider # Disable legacy mode and don't automatically load the legacy provider
# Option "-nolegacy" requires OpenSSL 3.0.0 or later # Option "-nolegacy" requires OpenSSL 3.0.0 or later
@ -167,7 +174,7 @@ if(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
"-pkcs12" "${CERTS}/legacy.p12" "-pkcs12" "${CERTS}/legacy.p12"
"-readpass" "${CERTS}/password.txt" "-readpass" "${CERTS}/password.txt"
"-nolegacy" # Disable legacy mode "-nolegacy" # Disable legacy mode
"-ac" "${CERTS}/crosscert.pem" "-ac" "${CERTS}/CAcross.pem"
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT "-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
"-add-msi-dse" "-add-msi-dse"
"-comm" "-comm"
@ -184,7 +191,7 @@ if(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
endif(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0) endif(OPENSSL_VERSION VERSION_GREATER_EQUAL 3.0.0)
# Tests 10-13 # Tests 14-19
# Sign with PKCS#12 container with AES-256-CBC private key and certificate encryption algorithm # Sign with PKCS#12 container with AES-256-CBC private key and certificate encryption algorithm
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
add_test( add_test(
@ -192,7 +199,7 @@ foreach(ext ${extensions_all})
COMMAND osslsigncode "sign" COMMAND osslsigncode "sign"
"-pkcs12" "${CERTS}/cert.p12" "-pkcs12" "${CERTS}/cert.p12"
"-readpass" "${CERTS}/password.txt" "-readpass" "${CERTS}/password.txt"
"-ac" "${CERTS}/crosscert.pem" "-ac" "${CERTS}/CAcross.pem"
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT "-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
"-add-msi-dse" "-add-msi-dse"
"-comm" "-comm"
@ -204,7 +211,7 @@ foreach(ext ${extensions_all})
"-out" "${FILES}/signed.${ext}") "-out" "${FILES}/signed.${ext}")
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
# Tests 14-17 # Tests 20-25
# Sign with revoked certificate # Sign with revoked certificate
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
add_test( add_test(
@ -213,7 +220,7 @@ foreach(ext ${extensions_all})
"-certs" "${CERTS}/revoked.pem" "-certs" "${CERTS}/revoked.pem"
"-key" "${CERTS}/keyp.pem" "-key" "${CERTS}/keyp.pem"
"-readpass" "${CERTS}/password.txt" "-readpass" "${CERTS}/password.txt"
"-ac" "${CERTS}/crosscert.pem" "-ac" "${CERTS}/CAcross.pem"
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT "-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT
"-add-msi-dse" "-add-msi-dse"
"-comm" "-comm"
@ -225,7 +232,7 @@ foreach(ext ${extensions_all})
"-out" "${FILES}/revoked.${ext}") "-out" "${FILES}/revoked.${ext}")
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
# Tests 18-20 # Tests 26-30
# Remove signature # Remove signature
# Unsupported command for CAT files # Unsupported command for CAT files
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_nocat})
@ -241,7 +248,7 @@ foreach(ext ${extensions_nocat})
REQUIRED_FILES "${FILES}/signed.${ext}") REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_nocat})
# Tests 21-24 # Tests 31-36
# Extract PKCS#7 signature in PEM format # Extract PKCS#7 signature in PEM format
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
add_test( add_test(
@ -257,7 +264,7 @@ foreach(ext ${extensions_all})
REQUIRED_FILES "${FILES}/signed.${ext}") REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
# Tests 25-28 # Tests 37-42
# Extract PKCS#7 signature in default DER format # Extract PKCS#7 signature in default DER format
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
add_test( add_test(
@ -272,17 +279,15 @@ foreach(ext ${extensions_all})
REQUIRED_FILES "${FILES}/signed.${ext}") REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
# Tests 29-34 # Tests 43-52
# Attach signature in PEM or DER format # Attach a nested signature in PEM or DER format
# Unsupported command for CAT files # Unsupported command for CAT files
set(formats "pem" "der")
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_nocat})
foreach(format ${formats}) foreach(format ${formats})
add_test( add_test(
NAME attached_${format}_${ext} NAME attached_${format}_${ext}
COMMAND osslsigncode "attach-signature" COMMAND osslsigncode "attach-signature"
# sign options # sign options
"-time" "1567296000" # Signing and signature verification time: Sep 1 00:00:00 2019 GMT
"-require-leaf-hash" "SHA256:${leafhash}" "-require-leaf-hash" "SHA256:${leafhash}"
"-add-msi-dse" "-add-msi-dse"
"-h" "sha512" "-h" "sha512"
@ -291,6 +296,7 @@ foreach(ext ${extensions_nocat})
"-in" "${FILES}/signed.${ext}" "-in" "${FILES}/signed.${ext}"
"-out" "${FILES}/attached_${format}.${ext}" "-out" "${FILES}/attached_${format}.${ext}"
# verify options # verify options
"-time" "1567296000" # Signature verification time: Sep 1 00:00:00 2019 GMT
"-CAfile" "${CERTS}/CACert.pem" "-CAfile" "${CERTS}/CACert.pem"
"-CRLfile" "${CERTS}/CACertCRL.pem") "-CRLfile" "${CERTS}/CACertCRL.pem")
set_tests_properties( set_tests_properties(
@ -302,7 +308,7 @@ foreach(ext ${extensions_nocat})
endforeach(format ${formats}) endforeach(format ${formats})
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_nocat})
# Tests 35-38 # Tests 53-58
# Add an unauthenticated blob to a previously-signed file # Add an unauthenticated blob to a previously-signed file
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
add_test( add_test(
@ -319,8 +325,9 @@ foreach(ext ${extensions_all})
REQUIRED_FILES "${FILES}/signed.${ext}") REQUIRED_FILES "${FILES}/signed.${ext}")
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
# Tests 39-42 # Tests 59-64
# Add the new nested signature instead of replacing the first one # Add the new nested signature instead of replacing the first one
# APPX files do not support nesting (multiple signature)
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
add_test( add_test(
NAME nested_${ext} NAME nested_${ext}
@ -329,8 +336,8 @@ foreach(ext ${extensions_all})
"-certs" "${CERTS}/cert.pem" "-certs" "${CERTS}/cert.pem"
"-key" "${CERTS}/key.der" "-key" "${CERTS}/key.der"
"-pass" "passme" "-pass" "passme"
"-ac" "${CERTS}/crosscert.pem" "-ac" "${CERTS}/CAcross.pem"
"-time" "1556668800" # Signing time: May 1 00:00:00 2019 GMT "-time" "1556755200" # Signing time: May 2 00:00:00 2019 GMT
"-add-msi-dse" "-add-msi-dse"
"-comm" "-comm"
"-ph" "-ph"
@ -350,9 +357,9 @@ endforeach(ext ${extensions_all})
### Verify signature ### ### Verify signature ###
# Tests 43-45 # Tests 65-67
# Verify PE/MSI/CAB files signed in the catalog file # Verify PE/MSI/CAB files signed in the catalog file
# APPX does not support detached PKCS#7 signature # CAT and APPX files do not support detached PKCS#7 signature
foreach(ext ${extensions_nocatappx}) foreach(ext ${extensions_nocatappx})
add_test( add_test(
NAME verify_catalog_${ext} NAME verify_catalog_${ext}
@ -371,9 +378,64 @@ foreach(ext ${extensions_nocatappx})
REQUIRED_FILES "${FILES}/unsigned.${ext}") REQUIRED_FILES "${FILES}/unsigned.${ext}")
endforeach(ext ${extensions_nocatappx}) endforeach(ext ${extensions_nocatappx})
# Tests 46-69 # Tests 68-97
# Verify signature # Verify signature
set(files "legacy" "signed" "nested" "added" "removed" "revoked" "attached_pem" "attached_der") set(files "legacy" "signed" "nested" "added" "revoked")
foreach(file ${files})
foreach(ext ${extensions_all})
add_test(
NAME verify_${file}_${ext}
COMMAND 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}"
REQUIRED_FILES "${FILES}/${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})
# Tests 98-102
# 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 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}"
REQUIRED_FILES "${FILES}/${file}.${ext}"
WILL_FAIL TRUE)
endforeach(ext ${extensions_nocat})
endforeach(file ${files})
# Tests 103-112
# Verify attached signature
# "attach-signature" command is unsupported for CAT files
set(files "attached_pem" "attached_der")
foreach(file ${files}) foreach(file ${files})
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_nocat})
add_test( add_test(
@ -391,22 +453,12 @@ foreach(file ${files})
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_nocat})
endforeach(file ${files}) endforeach(file ${files})
# "Removed" and "revoked" tests are expected to fail
set(files "removed" "revoked")
foreach(file ${files})
foreach(ext ${extensions_nocat})
set_tests_properties(
verify_${file}_${ext}
PROPERTIES
WILL_FAIL TRUE)
endforeach(ext ${extensions_nocat})
endforeach(file ${files})
if(Python3_FOUND OR server_error) if((Python3_FOUND OR server_error) AND CURL_FOUND)
### Sign with Time-Stamp Authority ### ### Sign with Time-Stamp Authority ###
# Tests 70-89 # Tests 113-142
# Sign with the RFC3161 Time-Stamp Authority # Sign with the RFC3161 Time-Stamp Authority
# Use "cert" "expired" "revoked" without X509v3 CRL Distribution Points extension # Use "cert" "expired" "revoked" without X509v3 CRL Distribution Points extension
# and "cert_crldp" "revoked_crldp" contain X509v3 CRL Distribution Points extension # and "cert_crldp" "revoked_crldp" contain X509v3 CRL Distribution Points extension
@ -418,7 +470,7 @@ if(Python3_FOUND OR server_error)
COMMAND osslsigncode "sign" COMMAND osslsigncode "sign"
"-certs" "${CERTS}/${cert}.pem" "-certs" "${CERTS}/${cert}.pem"
"-key" "${CERTS}/key.pem" "-key" "${CERTS}/key.pem"
"-ac" "${CERTS}/crosscert.pem" "-ac" "${CERTS}/CAcross.pem"
"-comm" "-comm"
"-ph" "-ph"
"-jp" "low" "-jp" "low"
@ -432,6 +484,7 @@ if(Python3_FOUND OR server_error)
set_tests_properties( set_tests_properties(
sign_ts_${cert}_${ext} sign_ts_${cert}_${ext}
PROPERTIES PROPERTIES
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
REQUIRED_FILES "${LOGS}/port.log") REQUIRED_FILES "${LOGS}/port.log")
endforeach(cert ${pem_certs}) endforeach(cert ${pem_certs})
endforeach(ext ${extensions_all}) endforeach(ext ${extensions_all})
@ -439,9 +492,9 @@ if(Python3_FOUND OR server_error)
### Verify Time-Stamp Authority ### ### Verify Time-Stamp Authority ###
# Tests 90-92 # Tests 143-148
# Signature verification time: Sep 1 00:00:00 2019 GMT # Signature verification time: Sep 1 00:00:00 2019 GMT
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_all})
add_test( add_test(
NAME verify_ts_cert_${ext} NAME verify_ts_cert_${ext}
COMMAND osslsigncode "verify" COMMAND osslsigncode "verify"
@ -452,14 +505,15 @@ if(Python3_FOUND OR server_error)
set_tests_properties( set_tests_properties(
verify_ts_cert_${ext} verify_ts_cert_${ext}
PROPERTIES PROPERTIES
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
DEPENDS "sign_ts_cert_${ext}" DEPENDS "sign_ts_cert_${ext}"
REQUIRED_FILES "${FILES}/ts_cert.${ext}" REQUIRED_FILES "${FILES}/ts_cert.${ext}"
REQUIRED_FILES "${LOGS}/port.log") REQUIRED_FILES "${LOGS}/port.log")
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_all})
# Tests 93-95 # Tests 149-154
# Signature verification time: Jan 1 00:00:00 2035 GMT # Signature verification time: Jan 1 00:00:00 2035 GMT
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_all})
add_test( add_test(
NAME verify_ts_future_${ext} NAME verify_ts_future_${ext}
COMMAND osslsigncode "verify" COMMAND osslsigncode "verify"
@ -470,15 +524,16 @@ if(Python3_FOUND OR server_error)
set_tests_properties( set_tests_properties(
verify_ts_future_${ext} verify_ts_future_${ext}
PROPERTIES PROPERTIES
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
DEPENDS "sign_ts_cert_${ext}" DEPENDS "sign_ts_cert_${ext}"
REQUIRED_FILES "${FILES}/ts_cert.${ext}" REQUIRED_FILES "${FILES}/ts_cert.${ext}"
REQUIRED_FILES "${LOGS}/port.log") REQUIRED_FILES "${LOGS}/port.log")
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_all})
# Tests 96-98 # Tests 155-160
# Verify with ignored timestamp # Verify with ignored timestamp
# This tests are expected to fail # This tests are expected to fail
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_all})
add_test( add_test(
NAME verify_ts_ignore_${ext} NAME verify_ts_ignore_${ext}
COMMAND osslsigncode "verify" COMMAND osslsigncode "verify"
@ -490,20 +545,21 @@ if(Python3_FOUND OR server_error)
set_tests_properties( set_tests_properties(
verify_ts_ignore_${ext} verify_ts_ignore_${ext}
PROPERTIES PROPERTIES
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
DEPENDS "sign_ts_cert_${ext}" DEPENDS "sign_ts_cert_${ext}"
REQUIRED_FILES "${FILES}/ts_cert.${ext}" REQUIRED_FILES "${FILES}/ts_cert.${ext}"
REQUIRED_FILES "${LOGS}/port.log" REQUIRED_FILES "${LOGS}/port.log"
WILL_FAIL TRUE) WILL_FAIL TRUE)
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_all})
### Verify CRL Distribution Points ### ### Verify CRL Distribution Points ###
# Tests 99-101 # Tests 161-166
# Verify file signed with X509v3 CRL Distribution Points extension # Verify file signed with X509v3 CRL Distribution Points extension
# Signature verification time: Sep 1 00:00:00 2019 GMT # Signature verification time: Sep 1 00:00:00 2019 GMT
# Check X509v3 CRL Distribution Points extension, don't use "-CRLfile" and "-TSA-CRLfile" options # Check X509v3 CRL Distribution Points extension, don't use "-CRLfile" and "-TSA-CRLfile" options
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_all})
add_test( add_test(
NAME verify_ts_cert_crldp_${ext} NAME verify_ts_cert_crldp_${ext}
COMMAND osslsigncode "verify" COMMAND osslsigncode "verify"
@ -514,16 +570,17 @@ if(Python3_FOUND OR server_error)
set_tests_properties( set_tests_properties(
verify_ts_cert_crldp_${ext} verify_ts_cert_crldp_${ext}
PROPERTIES PROPERTIES
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
DEPENDS "sign_ts_cert_crldp_${ext}" DEPENDS "sign_ts_cert_crldp_${ext}"
REQUIRED_FILES "${FILES}/ts_cert_crldp.${ext}" REQUIRED_FILES "${FILES}/ts_cert_crldp.${ext}"
REQUIRED_FILES "${LOGS}/port.log") REQUIRED_FILES "${LOGS}/port.log")
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_all})
# Tests 102-107 # Tests 167-183
# Verify with expired or revoked certificate without X509v3 CRL Distribution Points extension # Verify with expired or revoked certificate without X509v3 CRL Distribution Points extension
# This tests are expected to fail # This tests are expected to fail
set(failed_certs "expired" "revoked") set(failed_certs "expired" "revoked")
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_all})
foreach(cert ${failed_certs}) foreach(cert ${failed_certs})
add_test( add_test(
NAME verify_ts_${cert}_${ext} NAME verify_ts_${cert}_${ext}
@ -536,18 +593,19 @@ if(Python3_FOUND OR server_error)
set_tests_properties( set_tests_properties(
verify_ts_${cert}_${ext} verify_ts_${cert}_${ext}
PROPERTIES PROPERTIES
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
DEPENDS "sign_ts_${cert}_${ext}" DEPENDS "sign_ts_${cert}_${ext}"
REQUIRED_FILES "${FILES}/ts_${cert}.${ext}" REQUIRED_FILES "${FILES}/ts_${cert}.${ext}"
REQUIRED_FILES "${LOGS}/port.log" REQUIRED_FILES "${LOGS}/port.log"
WILL_FAIL TRUE) WILL_FAIL TRUE)
endforeach(cert ${failed_certs}) endforeach(cert ${failed_certs})
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_all})
# Tests 108-110 # Tests 178-184
# Verify with revoked certificate contains X509v3 CRL Distribution Points extension # Verify with revoked certificate contains X509v3 CRL Distribution Points extension
# Check X509v3 CRL Distribution Points extension, don't use "-CRLfile" and "-TSA-CRLfile" options # Check X509v3 CRL Distribution Points extension, don't use "-CRLfile" and "-TSA-CRLfile" options
# This test is expected to fail # This test is expected to fail
foreach(ext ${extensions_nocat}) foreach(ext ${extensions_all})
add_test( add_test(
NAME verify_ts_revoked_crldp_${ext} NAME verify_ts_revoked_crldp_${ext}
COMMAND osslsigncode "verify" COMMAND osslsigncode "verify"
@ -558,16 +616,102 @@ if(Python3_FOUND OR server_error)
set_tests_properties( set_tests_properties(
verify_ts_revoked_crldp_${ext} verify_ts_revoked_crldp_${ext}
PROPERTIES PROPERTIES
ENVIRONMENT "HTTP_PROXY=;http_proxy=;"
DEPENDS "sign_ts_revoked_crldp_${ext}" DEPENDS "sign_ts_revoked_crldp_${ext}"
REQUIRED_FILES "${FILES}/ts_revoked_crldp.${ext}" REQUIRED_FILES "${FILES}/ts_revoked_crldp.${ext}"
REQUIRED_FILES "${LOGS}/port.log" REQUIRED_FILES "${LOGS}/port.log"
WILL_FAIL TRUE) WILL_FAIL TRUE)
endforeach(ext ${extensions_all})
# Tests 185-234
# 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 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 osslsigncode "extract-data"
"-ph"
"-h" "sha384"
"-add-msi-dse"
"-in" "${FILES}/unsigned.${ext}"
"-out" "${FILES}/data_${ext}.der")
# Sign a data content, output in DER format
foreach(data_format ${formats})
add_test(
NAME signed_data_${ext}_${data_format}
COMMAND 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")
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 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")
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 osslsigncode "attach-signature"
# sign options
"-require-leaf-hash" "SHA256:${leafhash}"
"-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
"-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_data_${ext}_${data_format}:data_${ext}_${format}")
endforeach(format ${formats})
endforeach(data_format ${formats})
endforeach(ext ${extensions_nocat}) endforeach(ext ${extensions_nocat})
### Cleanup ### ### Cleanup ###
# Test 111
# Stop HTTP server # Stop HTTP server
if(STOP_SERVER) if(STOP_SERVER)
add_test(NAME stop_server add_test(NAME stop_server
@ -580,21 +724,16 @@ if(Python3_FOUND OR server_error)
message(STATUS "Keep HTTP server after tests") message(STATUS "Keep HTTP server after tests")
endif(STOP_SERVER) endif(STOP_SERVER)
else(Python3_FOUND OR server_error) else((Python3_FOUND OR server_error) AND CURL_FOUND)
message(STATUS "CTest skips some tests") message(STATUS "CTest skips some tests")
endif(Python3_FOUND OR server_error) endif((Python3_FOUND OR server_error) AND CURL_FOUND)
# Test 112
# Delete test files # Delete test files
set(names "legacy" "signed" "signed_crldp" "nested" "revoked" "removed" "added")
foreach(ext ${extensions_all}) foreach(ext ${extensions_all})
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/legacy.${ext}") foreach(name ${names})
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/signed.${ext}") set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${name}.${ext}")
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/signed_crldp.${ext}") endforeach(name ${names})
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/nested.${ext}")
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/revoked.${ext}")
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/removed.${ext}")
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/added.${ext}")
foreach(cert ${pem_certs}) foreach(cert ${pem_certs})
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/ts_${cert}.${ext}") set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/ts_${cert}.${ext}")
endforeach(cert ${pem_certs}) endforeach(cert ${pem_certs})
@ -602,6 +741,11 @@ foreach(ext ${extensions_all})
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${ext}.${format}") set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/${ext}.${format}")
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}/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}) endforeach(format ${formats})
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jreq.tsq") set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jreq.tsq")
set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jresp.tsr") set(OUTPUT_FILES ${OUTPUT_FILES} "${FILES}/jresp.tsr")

608
helpers.c
View File

@ -9,12 +9,14 @@
#include "helpers.h" #include "helpers.h"
/* Prototypes */ /* Prototypes */
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig);
static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx); static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx);
static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx); static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx);
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx); static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx);
static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer);
static int X509_compare(const X509 *const *a, const X509 *const *b);
/* /*
* Common functions * Common functions
@ -109,113 +111,52 @@ void unmap_file(char *indata, const size_t size)
} }
/* /*
* [in, out] si: PKCS7_SIGNER_INFO structure * Retrieve a decoded PKCS#7 structure
* [in] ctx: FILE_FORMAT_CTX structure * [in] data: encoded PEM or DER data
* [returns] 0 on error or 1 on success * [in] size: data size
*/
static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
SpcSpOpusInfo *opus;
ASN1_STRING *astr;
int len;
u_char *p = NULL;
opus = spc_sp_opus_info_create(ctx);
if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
|| (p = OPENSSL_malloc((size_t)len)) == NULL) {
SpcSpOpusInfo_free(opus);
return 0; /* FAILED */
}
i2d_SpcSpOpusInfo(opus, &p);
p -= len;
astr = ASN1_STRING_new();
ASN1_STRING_set(astr, p, len);
OPENSSL_free(p);
SpcSpOpusInfo_free(opus);
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
V_ASN1_SEQUENCE, astr);
}
/*
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
static const u_char purpose_ind[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
};
static const u_char purpose_comm[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
};
ASN1_STRING *purpose = ASN1_STRING_new();
if (ctx->options->comm) {
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
} else {
ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
}
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
V_ASN1_SEQUENCE, purpose);
}
/*
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
* adding the _current_ time. This allows to create a deterministic signature
* when no trusted timestamp server was specified, making osslsigncode
* behaviour closer to signtool.exe (which doesn't include any non-trusted
* time in this case.)
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
if (ctx->options->time == INVALID_TIME) /* -time option was not specified */
return 1; /* SUCCESS */
return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,
ASN1_TIME_adj(NULL, ctx->options->time, 0, 0));
}
/*
* Retrieve a decoded PKCS#7 structure corresponding to the signature
* stored in the "sigin" file
* CMD_ATTACH command specific
* [in] ctx: structure holds input and output data
* [returns] pointer to PKCS#7 structure * [returns] pointer to PKCS#7 structure
*/ */
PKCS7 *pkcs7_get_sigfile(FILE_FORMAT_CTX *ctx) PKCS7 *pkcs7_read_data(char *data, uint32_t size)
{ {
PKCS7 *p7 = NULL; PKCS7 *p7 = NULL;
uint32_t filesize;
char *indata;
BIO *bio; BIO *bio;
const char pemhdr[] = "-----BEGIN PKCS7-----"; const char pemhdr[] = "-----BEGIN PKCS7-----";
filesize = get_file_size(ctx->options->sigfile); bio = BIO_new_mem_buf(data, (int)size);
if (!filesize) { if (size >= sizeof pemhdr && !memcmp(data, pemhdr, sizeof pemhdr - 1)) {
return NULL; /* FAILED */
}
indata = map_file(ctx->options->sigfile, filesize);
if (!indata) {
printf("Failed to open file: %s\n", ctx->options->sigfile);
return NULL; /* FAILED */
}
bio = BIO_new_mem_buf(indata, (int)filesize);
if (filesize >= sizeof pemhdr && !memcmp(indata, pemhdr, sizeof pemhdr - 1)) {
/* PEM format */ /* PEM format */
p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL); p7 = PEM_read_bio_PKCS7(bio, NULL, NULL, NULL);
} else { /* DER format */ } else { /* DER format */
p7 = d2i_PKCS7_bio(bio, NULL); p7 = d2i_PKCS7_bio(bio, NULL);
} }
BIO_free_all(bio); BIO_free_all(bio);
unmap_file(indata, filesize);
return p7; return p7;
} }
/*
* [in, out] ctx: structure holds input and output data
* [out] outdata: BIO outdata file
* [in] p7: PKCS#7 signature
* [returns] 1 on error or 0 on success
*/
int data_write_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
{
int ret;
(void)BIO_reset(outdata);
if (ctx->options->output_pkcs7) {
/* PEM format */
ret = !PEM_write_bio_PKCS7(outdata, p7);
} else {
/* default DER format */
ret = !i2d_PKCS7_bio(outdata, p7);
}
if (ret) {
printf("Unable to write pkcs7 object\n");
}
return ret;
}
/* /*
* Allocate, set type, add content and return a new PKCS#7 signature * Allocate, set type, add content and return a new PKCS#7 signature
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
@ -226,10 +167,11 @@ PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
int i, signer = -1; int i, signer = -1;
PKCS7 *p7; PKCS7 *p7;
PKCS7_SIGNER_INFO *si = NULL; PKCS7_SIGNER_INFO *si = NULL;
STACK_OF(X509) *chain = NULL;
p7 = PKCS7_new(); p7 = PKCS7_new();
PKCS7_set_type(p7, NID_pkcs7_signed); PKCS7_set_type(p7, NID_pkcs7_signed);
PKCS7_content_new(p7, NID_pkcs7_data);
if (ctx->options->cert != NULL) { if (ctx->options->cert != NULL) {
/* /*
* the private key and corresponding certificate are parsed from the PKCS12 * the private key and corresponding certificate are parsed from the PKCS12
@ -258,50 +200,47 @@ PKCS7 *pkcs7_create(FILE_FORMAT_CTX *ctx)
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
} }
pkcs7_signer_info_add_signing_time(si, ctx); if (!pkcs7_signer_info_add_signing_time(si, ctx)) {
if (!pkcs7_signer_info_add_purpose(si, ctx))
return NULL; /* FAILED */ return NULL; /* FAILED */
}
if (!pkcs7_signer_info_add_purpose(si, ctx)) {
return NULL; /* FAILED */
}
if ((ctx->options->desc || ctx->options->url) && if ((ctx->options->desc || ctx->options->url) &&
!pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) { !pkcs7_signer_info_add_spc_sp_opus_info(si, ctx)) {
printf("Couldn't allocate memory for opus info\n"); printf("Couldn't allocate memory for opus info\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
PKCS7_content_new(p7, NID_pkcs7_data); if ((ctx->options->nested_number >= 0) &&
!pkcs7_signer_info_add_sequence_number(si, ctx)) {
/* add the signer's certificate */ return NULL; /* FAILED */
if (ctx->options->cert != NULL)
PKCS7_add_certificate(p7, ctx->options->cert);
if (signer != -1)
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->certs, signer));
/* add the certificate chain */
for (i=0; i<sk_X509_num(ctx->options->certs); i++) {
if (i == signer)
continue;
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->certs, i));
} }
/* add all cross certificates */ /* create X509 chain sorted in ascending order by their DER encoding */
if (ctx->options->xcerts) { chain = X509_chain_get_sorted(ctx, signer);
for (i=0; i<sk_X509_num(ctx->options->xcerts); i++) if (chain == NULL) {
PKCS7_add_certificate(p7, sk_X509_value(ctx->options->xcerts, i)); printf("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 */ /* add crls */
if (ctx->options->crls) { if (ctx->options->crls) {
for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++) for (i=0; i<sk_X509_CRL_num(ctx->options->crls); i++)
PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i)); PKCS7_add_crl(p7, sk_X509_CRL_value(ctx->options->crls, i));
} }
sk_X509_free(chain);
return p7; /* OK */ 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 * [in, out] p7: new PKCS#7 signature
* [in] hash: message digest BIO
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success * [returns] 0 on error or 1 on success
*/ */
int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx) int add_indirect_data_object(PKCS7 *p7)
{ {
STACK_OF(PKCS7_SIGNER_INFO) *signer_info; STACK_OF(PKCS7_SIGNER_INFO) *signer_info;
PKCS7_SIGNER_INFO *si; PKCS7_SIGNER_INFO *si;
@ -315,67 +254,151 @@ int add_indirect_data_object(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx)
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType, if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1))) V_ASN1_OBJECT, OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1)))
return 0; /* FAILED */ return 0; /* FAILED */
if (!pkcs7_set_data_content(p7, hash, ctx)) { return 1; /* OK */
printf("Signing failed\n"); }
/*
* PE, MSI, CAB and APPX format specific
* Sign the MS Authenticode spcIndirectDataContent blob.
* The spcIndirectDataContent structure is used in Authenticode signatures
* to store the digest and other attributes of the signed file.
* [in, out] p7: new PKCS#7 signature
* [in] content: spcIndirectDataContent
* [returns] 0 on error or 1 on success
*/
int sign_spc_indirect_data_content(PKCS7 *p7, ASN1_OCTET_STRING *content)
{
int len, inf, tag, class;
long plen;
const u_char *data, *p;
PKCS7 *td7;
p = data = ASN1_STRING_get0_data(content);
len = ASN1_STRING_length(content);
inf = ASN1_get_object(&p, &plen, &tag, &class, len);
if (inf != V_ASN1_CONSTRUCTED || tag != V_ASN1_SEQUENCE
|| !pkcs7_sign_content(p7, p, (int)plen)) {
printf("Failed to sign spcIndirectDataContent\n");
return 0; /* FAILED */
}
td7 = PKCS7_new();
if (!td7) {
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)) {
printf("PKCS7_set_content failed\n");
PKCS7_free(td7);
return 0; /* FAILED */ return 0; /* FAILED */
} }
return 1; /* OK */ return 1; /* OK */
} }
/* /*
* [in, out] p7: new PKCS#7 signature * Add encapsulated content to signed PKCS7 structure.
* [in] cursig: current PKCS#7 signature * [in] content: spcIndirectDataContent
* [returns] 0 on error or 1 on success * [returns] new PKCS#7 signature with encapsulated content
*/ */
int add_ms_ctl_object(PKCS7 *p7, PKCS7 *cursig) PKCS7 *pkcs7_set_content(ASN1_OCTET_STRING *content)
{ {
STACK_OF(PKCS7_SIGNER_INFO) *signer_info; PKCS7 *p7, *td7;
PKCS7_SIGNER_INFO *si;
signer_info = PKCS7_get_signer_info(p7); p7 = PKCS7_new();
if (!signer_info) if (!p7) {
return 0; /* FAILED */ return NULL; /* FAILED */
si = sk_PKCS7_SIGNER_INFO_value(signer_info, 0);
if (!si)
return 0; /* FAILED */
if (!PKCS7_add_signed_attribute(si, NID_pkcs9_contentType,
V_ASN1_OBJECT, OBJ_txt2obj(MS_CTL_OBJID, 1)))
return 0; /* FAILED */
if (!pkcs7_set_content_blob(p7, cursig)) {
printf("Signing failed\n");
return 0; /* FAILED */
} }
return 1; /* OK */ if (!PKCS7_set_type(p7, NID_pkcs7_signed)) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
if (!PKCS7_content_new(p7, NID_pkcs7_data)) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
td7 = PKCS7_new();
if (!td7) {
PKCS7_free(p7);
return NULL; /* FAILED */
}
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1);
td7->d.other = ASN1_TYPE_new();
td7->d.other->type = V_ASN1_SEQUENCE;
td7->d.other->value.sequence = content;
if (!PKCS7_set_content(p7, td7)) {
PKCS7_free(td7);
PKCS7_free(p7);
return NULL; /* FAILED */
}
return p7;
} }
static int pkcs7_set_content_blob(PKCS7 *sig, PKCS7 *cursig) /*
* Return spcIndirectDataContent.
* [in] hash: message digest BIO
* [in] ctx: structure holds input and output data
* [returns] content
*/
ASN1_OCTET_STRING *spc_indirect_data_content_get(BIO *hash, FILE_FORMAT_CTX *ctx)
{ {
PKCS7 *contents; ASN1_OCTET_STRING *content;
u_char *content; u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24];
int seqhdrlen, content_length; int mdlen, hashlen, len = 0;
BIO *sigbio; u_char *data, *p = NULL;
contents = cursig->d.sign->contents; content = ASN1_OCTET_STRING_new();
seqhdrlen = asn1_simple_hdr_len(contents->d.other->value.sequence->data, if (!content) {
contents->d.other->value.sequence->length); return NULL; /* FAILED */
content = contents->d.other->value.sequence->data + seqhdrlen; }
content_length = contents->d.other->value.sequence->length - seqhdrlen; if (!spc_indirect_data_content_create(&p, &len, ctx)) {
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
hashlen = ctx->format->hash_length_get(ctx);
if (hashlen > EVP_MAX_MD_SIZE) {
/* APPX format specific */
mdlen = BIO_read(hash, (char*)mdbuf, hashlen);
} else {
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE);
}
data = OPENSSL_malloc((size_t)(len + mdlen));
memcpy(data, p, (size_t)len);
OPENSSL_free(p);
memcpy(data + len, mdbuf, (size_t)mdlen);
if (!ASN1_OCTET_STRING_set(content, data, len + mdlen)) {
ASN1_OCTET_STRING_free(content);
OPENSSL_free(data);
return NULL; /* FAILED */
}
OPENSSL_free(data);
return content;
}
if ((sigbio = PKCS7_dataInit(sig, NULL)) == NULL) { /*
* 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) {
printf("PKCS7_dataInit failed\n"); printf("PKCS7_dataInit failed\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
BIO_write(sigbio, content, content_length); BIO_write(p7bio, data, len);
(void)BIO_flush(sigbio); (void)BIO_flush(p7bio);
if (!PKCS7_dataFinal(sig, sigbio)) { if (!PKCS7_dataFinal(p7, p7bio)) {
printf("PKCS7_dataFinal failed\n"); printf("PKCS7_dataFinal failed\n");
BIO_free_all(p7bio);
return 0; /* FAILED */ return 0; /* FAILED */
} }
BIO_free_all(sigbio); BIO_free_all(p7bio);
if (!PKCS7_set_content(sig, PKCS7_dup(contents))) {
printf("PKCS7_set_content failed\n");
return 0; /* FAILED */
}
return 1; /* OK */ return 1; /* OK */
} }
@ -456,29 +479,42 @@ int is_content_type(PKCS7 *p7, const char *objid)
} }
/* /*
* [out] p7: new PKCS#7 signature * [in] p7: new PKCS#7 signature
* [in] hash: message digest BIO * [returns] pointer to MsCtlContent structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/ */
int pkcs7_set_data_content(PKCS7 *p7, BIO *hash, FILE_FORMAT_CTX *ctx) MsCtlContent *ms_ctl_content_get(PKCS7 *p7)
{ {
u_char *p = NULL; ASN1_STRING *value;
int len = 0; const u_char *data;
u_char *buf;
if (!spc_indirect_data_content_get(&p, &len, ctx)) if (!is_content_type(p7, MS_CTL_OBJID)) {
return 0; /* FAILED */ printf("Failed to find MS_CTL_OBJID\n");
buf = OPENSSL_malloc(SIZE_64K); return NULL; /* FAILED */
memcpy(buf, p, (size_t)len); }
OPENSSL_free(p); value = p7->d.sign->contents->d.other->value.sequence;
if (!pkcs7_set_spc_indirect_data_content(p7, hash, buf, len, ctx)) { data = ASN1_STRING_get0_data(value);
OPENSSL_free(buf); return d2i_MsCtlContent(NULL, &data, ASN1_STRING_length(value));
return 0; /* FAILED */
} }
OPENSSL_free(buf);
return 1; /* OK */ /*
* [in] attribute: catalog attribute
* [returns] catalog content
*/
ASN1_TYPE *catalog_content_get(CatalogAuthAttr *attribute)
{
ASN1_STRING *value;
STACK_OF(ASN1_TYPE) *contents;
ASN1_TYPE *content;
const u_char *contents_data;
value = attribute->contents->value.sequence;
contents_data = ASN1_STRING_get0_data(value);
contents = d2i_ASN1_SET_ANY(NULL, &contents_data, ASN1_STRING_length(value));
if (!contents)
return 0; /* FAILED */
content = sk_ASN1_TYPE_value(contents, 0);
sk_ASN1_TYPE_free(contents);
return content;
} }
/* /*
@ -503,23 +539,6 @@ SpcLink *spc_link_obsolete_get(void)
return link; return link;
} }
/*
* Retrieve a decoded PKCS#7 structure
* [in] indata: mapped file
* [in] sigpos: signature data offset
* [in] siglen: signature data size
* [returns] pointer to PKCS#7 structure
*/
PKCS7 *pkcs7_get(char *indata, uint32_t sigpos, uint32_t siglen)
{
PKCS7 *p7 = NULL;
const u_char *blob;
blob = (u_char *)indata + sigpos;
p7 = d2i_PKCS7(NULL, &blob, siglen);
return p7;
}
/* /*
* [in] mdbuf, cmdbuf: message digests * [in] mdbuf, cmdbuf: message digests
* [in] mdtype: message digest algorithm type * [in] mdtype: message digest algorithm type
@ -570,14 +589,22 @@ static SpcSpOpusInfo *spc_sp_opus_info_create(FILE_FORMAT_CTX *ctx)
* [in] ctx: FILE_FORMAT_CTX structure * [in] ctx: FILE_FORMAT_CTX structure
* [returns] 0 on error or 1 on success * [returns] 0 on error or 1 on success
*/ */
static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CTX *ctx) static int spc_indirect_data_content_create(u_char **blob, int *len, FILE_FORMAT_CTX *ctx)
{ {
u_char *p = NULL; u_char *p = NULL;
int hashlen, l = 0; int mdtype, hashlen, l = 0;
int mdtype = EVP_MD_nid(ctx->options->md);
void *hash; void *hash;
SpcIndirectDataContent *idc = SpcIndirectDataContent_new(); SpcIndirectDataContent *idc = SpcIndirectDataContent_new();
if (!ctx->format->data_blob_get || !ctx->format->hash_length_get) {
return 0; /* FAILED */
}
if (ctx->format->md_get) {
/* APPX file specific - use a hash algorithm specified in the AppxBlockMap.xml file */
mdtype = EVP_MD_nid(ctx->format->md_get(ctx));
} else {
mdtype = EVP_MD_nid(ctx->options->md);
}
idc->data->value = ASN1_TYPE_new(); idc->data->value = ASN1_TYPE_new();
idc->data->value->type = V_ASN1_SEQUENCE; idc->data->value->type = V_ASN1_SEQUENCE;
idc->data->value->value.sequence = ASN1_STRING_new(); idc->data->value->value.sequence = ASN1_STRING_new();
@ -603,56 +630,169 @@ static int spc_indirect_data_content_get(u_char **blob, int *len, FILE_FORMAT_CT
} }
/* /*
* Replace the data part with the MS Authenticode spcIndirectDataContent blob * [in, out] si: PKCS7_SIGNER_INFO structure
* [out] p7: new PKCS#7 signature
* [in] hash: message digest BIO
* [in] blob: SpcIndirectDataContent data
* [in] len: SpcIndirectDataContent data length
* [in] ctx: FILE_FORMAT_CTX structure * [in] ctx: FILE_FORMAT_CTX structure
* [returns] 0 on error or 1 on success * [returns] 0 on error or 1 on success
*/ */
static int pkcs7_set_spc_indirect_data_content(PKCS7 *p7, BIO *hash, u_char *buf, int len, FILE_FORMAT_CTX *ctx) static int pkcs7_signer_info_add_spc_sp_opus_info(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{ {
u_char mdbuf[5 * EVP_MAX_MD_SIZE + 24]; SpcSpOpusInfo *opus;
int mdlen, seqhdrlen, hashlen; ASN1_STRING *astr;
BIO *bio; int len;
PKCS7 *td7; u_char *p = NULL;
hashlen = ctx->format->hash_length_get(ctx); opus = spc_sp_opus_info_create(ctx);
if (hashlen > EVP_MAX_MD_SIZE) { if ((len = i2d_SpcSpOpusInfo(opus, NULL)) <= 0
/* APPX format specific */ || (p = OPENSSL_malloc((size_t)len)) == NULL) {
mdlen = BIO_read(hash, (char*)mdbuf, hashlen); SpcSpOpusInfo_free(opus);
return 0; /* FAILED */
}
i2d_SpcSpOpusInfo(opus, &p);
p -= len;
astr = ASN1_STRING_new();
ASN1_STRING_set(astr, p, len);
OPENSSL_free(p);
SpcSpOpusInfo_free(opus);
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_SP_OPUS_INFO_OBJID),
V_ASN1_SEQUENCE, astr);
}
/*
* Add a custom, non-trusted time to the PKCS7 structure to prevent OpenSSL
* adding the _current_ time. This allows to create a deterministic signature
* when no trusted timestamp server was specified, making osslsigncode
* behaviour closer to signtool.exe (which doesn't include any non-trusted
* time in this case.)
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_signing_time(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
if (ctx->options->time == INVALID_TIME) /* -time option was not specified */
return 1; /* SUCCESS */
return PKCS7_add_signed_attribute(si, NID_pkcs9_signingTime, V_ASN1_UTCTIME,
ASN1_TIME_adj(NULL, ctx->options->time, 0, 0));
}
/*
* [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_purpose(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
static const u_char purpose_ind[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x15
};
static const u_char purpose_comm[] = {
0x30, 0x0c, 0x06, 0x0a, 0x2b, 0x06, 0x01, 0x04,
0x01, 0x82, 0x37, 0x02, 0x01, 0x16
};
ASN1_STRING *purpose = ASN1_STRING_new();
if (ctx->options->comm) {
ASN1_STRING_set(purpose, purpose_comm, sizeof purpose_comm);
} else { } else {
mdlen = BIO_gets(hash, (char*)mdbuf, EVP_MAX_MD_SIZE); ASN1_STRING_set(purpose, purpose_ind, sizeof purpose_ind);
}
return PKCS7_add_signed_attribute(si, OBJ_txt2nid(SPC_STATEMENT_TYPE_OBJID),
V_ASN1_SEQUENCE, purpose);
} }
memcpy(buf + len, mdbuf, (size_t)mdlen);
seqhdrlen = asn1_simple_hdr_len(buf, len);
if ((bio = PKCS7_dataInit(p7, NULL)) == NULL) { /*
printf("PKCS7_dataInit failed\n"); * [in, out] si: PKCS7_SIGNER_INFO structure
* [in] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pkcs7_signer_info_add_sequence_number(PKCS7_SIGNER_INFO *si, FILE_FORMAT_CTX *ctx)
{
ASN1_INTEGER *number = ASN1_INTEGER_new();
if (!number)
return 0; /* FAILED */
if (!ASN1_INTEGER_set(number, ctx->options->nested_number + 1)) {
ASN1_INTEGER_free(number);
return 0; /* FAILED */ return 0; /* FAILED */
} }
BIO_write(bio, buf + seqhdrlen, len - seqhdrlen + mdlen); return PKCS7_add_signed_attribute(si, OBJ_txt2nid(PKCS9_SEQUENCE_NUMBER),
(void)BIO_flush(bio); V_ASN1_INTEGER, number);
if (!PKCS7_dataFinal(p7, bio)) {
printf("PKCS7_dataFinal failed\n");
return 0; /* FAILED */
} }
BIO_free_all(bio);
td7 = PKCS7_new(); /*
td7->type = OBJ_txt2obj(SPC_INDIRECT_DATA_OBJID, 1); * Create certificate chain sorted in ascending order by their DER encoding.
td7->d.other = ASN1_TYPE_new(); * [in] ctx: structure holds input and output data
td7->d.other->type = V_ASN1_SEQUENCE; * [in] signer: signer's certificate number in the certificate chain
td7->d.other->value.sequence = ASN1_STRING_new(); * [returns] sorted certificate chain
ASN1_STRING_set(td7->d.other->value.sequence, buf, len + mdlen); */
if (!PKCS7_set_content(p7, td7)) { static STACK_OF(X509) *X509_chain_get_sorted(FILE_FORMAT_CTX *ctx, int signer)
PKCS7_free(td7); {
printf("PKCS7_set_content failed\n"); int i;
return 0; /* FAILED */ 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;
} }
return 1; /* OK */ 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;
} }
/* /*

View File

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

441
msi.c
View File

@ -100,30 +100,6 @@ static const u_char msi_zeroes[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
}; };
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)
ASN1_SEQUENCE(SpcSipInfo) = {
ASN1_SIMPLE(SpcSipInfo, a, ASN1_INTEGER),
ASN1_SIMPLE(SpcSipInfo, string, ASN1_OCTET_STRING),
ASN1_SIMPLE(SpcSipInfo, b, ASN1_INTEGER),
ASN1_SIMPLE(SpcSipInfo, c, ASN1_INTEGER),
ASN1_SIMPLE(SpcSipInfo, d, ASN1_INTEGER),
ASN1_SIMPLE(SpcSipInfo, e, ASN1_INTEGER),
ASN1_SIMPLE(SpcSipInfo, f, ASN1_INTEGER),
} ASN1_SEQUENCE_END(SpcSipInfo)
IMPLEMENT_ASN1_FUNCTIONS(SpcSipInfo)
typedef struct { typedef struct {
u_char signature[8]; /* 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 */ u_char signature[8]; /* 0xd0, 0xcf, 0x11, 0xe0, 0xa1, 0xb1, 0x1a, 0xe1 */
u_char unused_clsid[16]; /* reserved and unused */ u_char unused_clsid[16]; /* reserved and unused */
@ -215,44 +191,50 @@ struct msi_ctx_st {
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx); static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
static PKCS7 *msi_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
static int msi_hash_length_get(FILE_FORMAT_CTX *ctx); static int msi_hash_length_get(FILE_FORMAT_CTX *ctx);
static int msi_check_file(FILE_FORMAT_CTX *ctx, int detached);
static u_char *msi_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md); static u_char *msi_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static PKCS7 *msi_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *msi_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *msi_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
static int msi_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int msi_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *msi_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int msi_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *msi_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int msi_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int msi_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *msi_bio_free(BIO *hash, BIO *outdata); static void msi_bio_free(BIO *hash, BIO *outdata);
static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx);
static int msi_is_detaching_supported(void);
FILE_FORMAT file_format_msi = { FILE_FORMAT file_format_msi = {
.ctx_new = msi_ctx_new, .ctx_new = msi_ctx_new,
.data_blob_get = msi_spc_sip_info_get, .data_blob_get = msi_spc_sip_info_get,
.pkcs7_contents_get = msi_pkcs7_contents_get,
.hash_length_get = msi_hash_length_get, .hash_length_get = msi_hash_length_get,
.check_file = msi_check_file,
.digest_calc = msi_digest_calc, .digest_calc = msi_digest_calc,
.verify_digests = msi_verify_digests, .verify_digests = msi_verify_digests,
.pkcs7_extract = msi_pkcs7_extract, .pkcs7_extract = msi_pkcs7_extract,
.pkcs7_extract_to_nest = msi_pkcs7_extract_to_nest,
.remove_pkcs7 = msi_remove_pkcs7, .remove_pkcs7 = msi_remove_pkcs7,
.pkcs7_prepare = msi_pkcs7_prepare, .process_data = msi_process_data,
.pkcs7_signature_new = msi_pkcs7_signature_new,
.append_pkcs7 = msi_append_pkcs7, .append_pkcs7 = msi_append_pkcs7,
.bio_free = msi_bio_free, .bio_free = msi_bio_free,
.ctx_cleanup = msi_ctx_cleanup .ctx_cleanup = msi_ctx_cleanup,
.is_detaching_supported = msi_is_detaching_supported
}; };
/* Prototypes */ /* Prototypes */
static MSI_CTX *msi_ctx_get(char *indata, uint32_t filesize); static MSI_CTX *msi_ctx_get(char *indata, uint32_t filesize);
static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds, static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds);
char **p, uint32_t len);
static int recurse_entry(MSI_FILE *msi, uint32_t entryID, MSI_DIRENT *parent); static int recurse_entry(MSI_FILE *msi, uint32_t entryID, MSI_DIRENT *parent);
static int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, uint32_t len_msi, static int msi_file_write(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, uint32_t len_msi,
u_char *p_msiex, uint32_t len_msiex, BIO *outdata); u_char *p_msiex, uint32_t len_msiex, BIO *outdata);
static MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse); static MSI_ENTRY *msi_signatures_get(MSI_DIRENT *dirent, MSI_ENTRY **dse);
static int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len); static int msi_file_read(MSI_FILE *msi, MSI_ENTRY *entry, uint32_t offset, char *buffer, uint32_t len);
static int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen); static int msi_dirent_delete(MSI_DIRENT *dirent, const u_char *name, uint16_t nameLen);
static BIO *msi_digest_calc_bio(FILE_FORMAT_CTX *ctx, BIO *hash);
static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash); static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash);
static int msi_check_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, MSI_ENTRY *dse); static int msi_check_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, MSI_ENTRY *dse, PKCS7 *p7);
static int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root); static int msi_hash_dir(MSI_FILE *msi, MSI_DIRENT *dirent, BIO *hash, int is_root);
static MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi); static MSI_ENTRY *msi_root_entry_get(MSI_FILE *msi);
static void msi_file_free(MSI_FILE *msi); static void msi_file_free(MSI_FILE *msi);
@ -260,6 +242,7 @@ static MSI_FILE *msi_file_new(char *buffer, uint32_t len);
static int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret); static int msi_dirent_new(MSI_FILE *msi, MSI_ENTRY *entry, MSI_DIRENT *parent, MSI_DIRENT **ret);
static void msi_dirent_free(MSI_DIRENT *dirent); static void msi_dirent_free(MSI_DIRENT *dirent);
static int msi_prehash_dir(MSI_DIRENT *dirent, BIO *hash, int is_root); static int msi_prehash_dir(MSI_DIRENT *dirent, BIO *hash, int is_root);
static int msi_check_file(FILE_FORMAT_CTX *ctx);
/* /*
* FILE_FORMAT method definitions * FILE_FORMAT method definitions
@ -290,12 +273,12 @@ static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (memcmp(options->indata, msi_magic, sizeof msi_magic)) { if (memcmp(options->indata, msi_magic, sizeof msi_magic)) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
msi_ctx = msi_ctx_get(options->indata, filesize); msi_ctx = msi_ctx_get(options->indata, filesize);
if (!msi_ctx) { if (!msi_ctx) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX)); ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
@ -315,6 +298,10 @@ static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
/* /*
* Allocate and return SpcSipInfo object. * 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.
* [out] p: SpcSipInfo data * [out] p: SpcSipInfo data
* [out] plen: SpcSipInfo data length * [out] plen: SpcSipInfo data length
* [in] ctx: structure holds input and output data (unused) * [in] ctx: structure holds input and output data (unused)
@ -322,7 +309,7 @@ static FILE_FORMAT_CTX *msi_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *out
*/ */
static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx) static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx)
{ {
const u_char msistr[] = { const u_char SpcUUIDSipInfoMsi[] = {
0xf1, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x10, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46
}; };
@ -338,7 +325,7 @@ static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX
ASN1_INTEGER_set(si->d, 0); ASN1_INTEGER_set(si->d, 0);
ASN1_INTEGER_set(si->e, 0); ASN1_INTEGER_set(si->e, 0);
ASN1_INTEGER_set(si->f, 0); ASN1_INTEGER_set(si->f, 0);
ASN1_OCTET_STRING_set(si->string, msistr, sizeof msistr); ASN1_OCTET_STRING_set(si->string, SpcUUIDSipInfoMsi, sizeof SpcUUIDSipInfoMsi);
*plen = i2d_SpcSipInfo(si, NULL); *plen = i2d_SpcSipInfo(si, NULL);
*p = OPENSSL_malloc((size_t)*plen); *p = OPENSSL_malloc((size_t)*plen);
i2d_SpcSipInfo(si, p); i2d_SpcSipInfo(si, p);
@ -349,74 +336,29 @@ static ASN1_OBJECT *msi_spc_sip_info_get(u_char **p, int *plen, FILE_FORMAT_CTX
} }
/* /*
* Allocate and return a data content to be signed.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash) * [in] hash: message digest BIO
* [in] md: message digest algorithm
* [returns] data content
*/ */
static int msi_hash_length_get(FILE_FORMAT_CTX *ctx) static PKCS7 *msi_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
{ {
return EVP_MD_size(ctx->options->md); ASN1_OCTET_STRING *content;
}
/* /* squash the unused parameter warning, use initialized message digest BIO */
* Get DigitalSignature and MsiDigitalSignatureEx streams, (void)md;
* check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [in] detached: embedded/detached PKCS#7 signature switch (unused)
* [returns] 0 on error or 1 on successs
*/
static int msi_check_file(FILE_FORMAT_CTX *ctx, int detached)
{
char *indata = NULL;
uint32_t inlen;
MSI_ENTRY *ds, *dse = NULL;
/* squash the unused parameter warning */ if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) {
(void)detached; printf("Unable to calc MsiDigitalSignatureEx\n");
return NULL; /* FAILED */
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
} }
if (detached) { if (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) {
printf("Checking the specified catalog file\n\n"); printf("Unable to msi_handle_dir()\n");
return 1; /* OK */ return NULL; /* FAILED */
} }
ds = msi_signatures_get(ctx->msi_ctx->dirent, &dse); content = spc_indirect_data_content_get(hash, ctx);
if (!ds) { return pkcs7_set_content(content);
printf("MSI file has no signature\n\n");
return 0; /* FAILED */
}
inlen = GET_UINT32_LE(ds->size);
if (inlen == 0 || inlen >= MAXREGSECT) {
printf("Corrupted DigitalSignature stream length 0x%08X\n", inlen);
return 0; /* FAILED */
}
indata = OPENSSL_malloc((size_t)inlen);
if (!msi_file_read(ctx->msi_ctx->msi, ds, 0, indata, inlen)) {
printf("DigitalSignature stream data error\n\n");
OPENSSL_free(indata);
return 0; /* FAILED */
}
if (!dse) {
printf("Warning: MsiDigitalSignatureEx stream doesn't exist\n");
} else {
ctx->msi_ctx->len_msiex = GET_UINT32_LE(dse->size);
if (ctx->msi_ctx->len_msiex == 0 || ctx->msi_ctx->len_msiex >= MAXREGSECT) {
printf("Corrupted MsiDigitalSignatureEx stream length 0x%08X\n",
ctx->msi_ctx->len_msiex);
OPENSSL_free(indata);
return 0; /* FAILED */
}
ctx->msi_ctx->p_msiex = OPENSSL_malloc((size_t)ctx->msi_ctx->len_msiex);
if (!msi_file_read(ctx->msi_ctx->msi, dse, 0, (char *)ctx->msi_ctx->p_msiex,
ctx->msi_ctx->len_msiex)) {
printf("MsiDigitalSignatureEx stream data error\n\n");
OPENSSL_free(indata);
return 0; /* FAILED */
}
}
OPENSSL_free(indata);
return 1; /* OK */
} }
/* /*
@ -554,21 +496,54 @@ static int msi_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7)
static PKCS7 *msi_pkcs7_extract(FILE_FORMAT_CTX *ctx) static PKCS7 *msi_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{ {
PKCS7 *p7; PKCS7 *p7;
uint32_t len; MSI_ENTRY *ds;
char *p;
if (!msi_check_file(ctx)) {
return NULL; /* FAILED, no signature */
}
ds = msi_signatures_get(ctx->msi_ctx->dirent, NULL);
MSI_ENTRY *ds = msi_signatures_get(ctx->msi_ctx->dirent, NULL);
if (!ds) { if (!ds) {
printf("MSI file has no signature\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
len = GET_UINT32_LE(ds->size); p7 = msi_pkcs7_get_digital_signature(ctx, ds);
if (len == 0 || len >= MAXREGSECT) { if (!p7) {
printf("Corrupted DigitalSignature stream length 0x%08X\n", len); printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
}
return p7;
}
/*
* Extract existing signature in DER format.
* Perform a sanity check for the MsiDigitalSignatureEx section.
* [in] ctx: structure holds input and output data
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *msi_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
{
PKCS7 *p7;
MSI_ENTRY *ds, *dse = NULL;
if (!msi_check_file(ctx)) {
return NULL; /* FAILED, no signature */
}
ds = msi_signatures_get(ctx->msi_ctx->dirent, &dse);
if (!ds) {
printf("MSI file has no signature\n");
return NULL; /* FAILED */
}
p7 = msi_pkcs7_get_digital_signature(ctx, ds);
if (!p7) {
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
}
/* perform a sanity check for the MsiDigitalSignatureEx section */
if (!msi_check_MsiDigitalSignatureEx(ctx, dse, p7)) {
PKCS7_free(p7);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
p = OPENSSL_malloc((size_t)len);
p7 = msi_pkcs7_get_digital_signature(ctx, ds, &p, len);
OPENSSL_free(p);
return p7; return p7;
} }
@ -581,9 +556,15 @@ static PKCS7 *msi_pkcs7_extract(FILE_FORMAT_CTX *ctx)
*/ */
static int msi_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int msi_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
MSI_ENTRY *ds;
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)hash; (void)hash;
ds = msi_signatures_get(ctx->msi_ctx->dirent, NULL);
if (!ds) {
return 1; /* FAILED, no signature */
}
if (!msi_dirent_delete(ctx->msi_ctx->dirent, digital_signature_ex, if (!msi_dirent_delete(ctx->msi_ctx->dirent, digital_signature_ex,
sizeof digital_signature_ex)) { sizeof digital_signature_ex)) {
return 1; /* FAILED */ return 1; /* FAILED */
@ -601,81 +582,56 @@ static int msi_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
} }
/* /*
* Obtain an existing signature or create a new one. * Calculate a hash (message digest) of data.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] pointer to PKCS#7 structure * [returns] 1 on error or 0 on success
*/ */
static PKCS7 *msi_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int msi_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
PKCS7 *cursig = NULL, *p7 = NULL;
uint32_t len;
char *p;
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)outdata; (void)outdata;
if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) { hash = msi_digest_calc_bio(ctx, hash);
printf("Unable to calc MsiDigitalSignatureEx\n"); if (!hash) {
return NULL; /* FAILED */ return 1; /* FAILED */
} }
if (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) { return 0; /* OK */
printf("Unable to msi_handle_dir()\n");
return NULL; /* FAILED */
} }
/* Obtain a current signature from previously-signed file */
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest) /*
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest) * Create a new PKCS#7 signature.
|| ctx->options->cmd == CMD_ADD) { * [in, out] ctx: structure holds input and output data
MSI_ENTRY *dse = NULL; * [out] hash: message digest BIO
MSI_ENTRY *ds = msi_signatures_get(ctx->msi_ctx->dirent, &dse); * [returns] pointer to PKCS#7 structure
if (!ds) { */
printf("MSI file has no signature\n\n"); static PKCS7 *msi_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
return NULL; /* FAILED */ {
} ASN1_OCTET_STRING *content;
if (!msi_check_MsiDigitalSignatureEx(ctx, dse)) { PKCS7 *p7 = pkcs7_create(ctx);
return NULL; /* FAILED */
}
len = GET_UINT32_LE(ds->size);
if (len == 0 || len >= MAXREGSECT) {
printf("Corrupted DigitalSignature stream length 0x%08X\n", len);
return NULL; /* FAILED */
}
p = OPENSSL_malloc((size_t)len);
/* get current signature */
cursig = msi_pkcs7_get_digital_signature(ctx, ds, &p, len);
OPENSSL_free(p);
if (!cursig) {
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
}
if (ctx->options->cmd == CMD_ADD)
p7 = cursig;
}
if (ctx->options->cmd == CMD_ATTACH) {
/* Obtain an existing PKCS#7 signature */
p7 = pkcs7_get_sigfile(ctx);
if (!p7) {
printf("Unable to extract valid signature\n");
PKCS7_free(cursig);
return NULL; /* FAILED */
}
} else if (ctx->options->cmd == CMD_SIGN) {
/* Create a new PKCS#7 signature */
p7 = pkcs7_create(ctx);
if (!p7) { if (!p7) {
printf("Creating a new signature failed\n"); printf("Creating a new signature failed\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!add_indirect_data_object(p7, hash, ctx)) { if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7); PKCS7_free(p7);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
printf("Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
} }
if (ctx->options->nest) if (!sign_spc_indirect_data_content(p7, content)) {
ctx->options->prevsig = cursig; printf("Failed to set signed content\n");
PKCS7_free(p7);
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
ASN1_OCTET_STRING_free(content);
return p7; return p7;
} }
@ -715,34 +671,22 @@ static int msi_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static BIO *msi_bio_free(BIO *hash, BIO *outdata) static void msi_bio_free(BIO *hash, BIO *outdata)
{ {
BIO_free_all(hash); BIO_free_all(hash);
BIO_free_all(outdata); BIO_free_all(outdata);
return NULL;
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and MSI format specific structures, * Deallocate a FILE_FORMAT_CTX structure and MSI format specific structures,
* unmap indata file, unlink outfile. * unmap indata file.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
BIO_free_all(outdata);
if (ctx->options->outfile) {
#ifdef WIN32
_unlink(ctx->options->outfile);
#else
unlink(ctx->options->outfile);
#endif /* WIN32 */
}
}
unmap_file(ctx->options->indata, ctx->msi_ctx->fileend); unmap_file(ctx->options->indata, ctx->msi_ctx->fileend);
msi_file_free(ctx->msi_ctx->msi); msi_file_free(ctx->msi_ctx->msi);
msi_dirent_free(ctx->msi_ctx->dirent); msi_dirent_free(ctx->msi_ctx->dirent);
@ -751,6 +695,11 @@ static void msi_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
OPENSSL_free(ctx); OPENSSL_free(ctx);
} }
static int msi_is_detaching_supported(void)
{
return 1; /* OK */
}
/* /*
* MSI helper functions * MSI helper functions
*/ */
@ -791,18 +740,26 @@ static MSI_CTX *msi_ctx_get(char *indata, uint32_t filesize)
return msi_ctx; /* OK */ return msi_ctx; /* OK */
} }
static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds, static PKCS7 *msi_pkcs7_get_digital_signature(FILE_FORMAT_CTX *ctx, MSI_ENTRY *ds)
char **p, uint32_t len)
{ {
PKCS7 *p7 = NULL; PKCS7 *p7 = NULL;
const u_char *blob; const u_char *blob;
char *p;
uint32_t len = GET_UINT32_LE(ds->size);
if (!msi_file_read(ctx->msi_ctx->msi, ds, 0, *p, len)) { if (len == 0 || len >= MAXREGSECT) {
printf("Corrupted DigitalSignature stream length 0x%08X\n", len);
return NULL; /* FAILED */
}
p = OPENSSL_malloc((size_t)len);
if (!msi_file_read(ctx->msi_ctx->msi, ds, 0, p, len)) {
printf("DigitalSignature stream data error\n"); printf("DigitalSignature stream data error\n");
OPENSSL_free(p);
return NULL; return NULL;
} }
blob = (u_char *)*p; blob = (u_char *)p;
p7 = d2i_PKCS7(NULL, &blob, len); p7 = d2i_PKCS7(NULL, &blob, len);
OPENSSL_free(p);
if (!p7) { if (!p7) {
printf("Failed to extract PKCS7 data\n"); printf("Failed to extract PKCS7 data\n");
return NULL; return NULL;
@ -1695,9 +1652,8 @@ static int stream_handle(MSI_FILE *msi, MSI_DIRENT *dirent, u_char *p_msi, uint3
/* DigitalSignature or MsiDigitalSignatureEx: inlen == 0 */ /* DigitalSignature or MsiDigitalSignatureEx: inlen == 0 */
inlen = stream_read(msi, child->entry, p_msi, len_msi, p_msiex, len_msiex, &indata, inlen, is_root); inlen = stream_read(msi, child->entry, p_msi, len_msi, p_msiex, len_msiex, &indata, inlen, is_root);
if (inlen == 0) { if (inlen == 0) {
printf("Failed to read stream data\n");
OPENSSL_free(indata); OPENSSL_free(indata);
continue; continue; /* skip a null stream */
} }
/* set the size of the user-defined data if this is a stream object */ /* set the size of the user-defined data if this is a stream object */
PUT_UINT32_LE(inlen, buf); PUT_UINT32_LE(inlen, buf);
@ -2179,6 +2135,25 @@ out:
return ret; return ret;
} }
/*
* Compute a message digest value of a signed or unsigned MSI file.
* [in] ctx: structure holds input and output data
* [in] md: message digest algorithm
* [returns] calculated message digest BIO
*/
static BIO *msi_digest_calc_bio(FILE_FORMAT_CTX *ctx, BIO *hash)
{
if (ctx->options->add_msi_dse && !msi_calc_MsiDigitalSignatureEx(ctx, hash)) {
printf("Unable to calc MsiDigitalSignatureEx\n");
return NULL; /* FAILED */
}
if (!msi_hash_dir(ctx->msi_ctx->msi, ctx->msi_ctx->dirent, hash, 1)) {
printf("Unable to msi_handle_dir()\n");
return NULL; /* FAILED */
}
return hash;
}
/* /*
* MsiDigitalSignatureEx is an enhanced signature type that * MsiDigitalSignatureEx is an enhanced signature type that
* can be used when signing MSI files. In addition to * can be used when signing MSI files. In addition to
@ -2188,7 +2163,7 @@ out:
* The file content hashing part stays the same, so the * The file content hashing part stays the same, so the
* msi_handle_dir() function can be used across both variants. * msi_handle_dir() function can be used across both variants.
* *
* When an MsiDigitalSigntaureEx section is present in an MSI file, * When an MsiDigitalSignatureEx section is present in an MSI file,
* the meaning of the DigitalSignature section changes: Instead * the meaning of the DigitalSignature section changes: Instead
* of being merely a file content hash (as what is output by the * of being merely a file content hash (as what is output by the
* msi_handle_dir() function), it is now hashes both content * msi_handle_dir() function), it is now hashes both content
@ -2236,6 +2211,11 @@ static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash)
printf("Unable to calculate MSI pre-hash ('metadata') hash\n"); printf("Unable to calculate MSI pre-hash ('metadata') hash\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (ctx->msi_ctx->p_msiex) {
/* attach-signature counts MsiDigitalSignatureEx stream data twice */
OPENSSL_free(ctx->msi_ctx->p_msiex);
ctx->msi_ctx->p_msiex = NULL;
}
ctx->msi_ctx->p_msiex = OPENSSL_malloc(EVP_MAX_MD_SIZE); ctx->msi_ctx->p_msiex = OPENSSL_malloc(EVP_MAX_MD_SIZE);
ctx->msi_ctx->len_msiex = (uint32_t)BIO_gets(prehash, ctx->msi_ctx->len_msiex = (uint32_t)BIO_gets(prehash,
(char *)ctx->msi_ctx->p_msiex, EVP_MAX_MD_SIZE); (char *)ctx->msi_ctx->p_msiex, EVP_MAX_MD_SIZE);
@ -2252,29 +2232,98 @@ static int msi_calc_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, BIO *hash)
* section, we can't add a nested signature of a different MD type * section, we can't add a nested signature of a different MD type
* without breaking the initial signature. * without breaking the initial signature.
*/ */
static int msi_check_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, MSI_ENTRY *dse) static int msi_check_MsiDigitalSignatureEx(FILE_FORMAT_CTX *ctx, MSI_ENTRY *dse, PKCS7 *p7)
{ {
if (dse && GET_UINT32_LE(dse->size) != (uint32_t)EVP_MD_size(ctx->options->md)) { if (dse && GET_UINT32_LE(dse->size) != (uint32_t)EVP_MD_size(ctx->options->md)) {
printf("Unable to add nested signature with a different MD type (-h parameter) " X509_ALGOR *alg;
"than what exists in the MSI file already.\nThis is due to the presence of " const ASN1_OBJECT *aoid;
"MsiDigitalSignatureEx (-add-msi-dse parameter).\n\n");
alg = sk_X509_ALGOR_value(p7->d.sign->md_algs, 0);
X509_ALGOR_get0(&aoid, NULL, NULL, alg);
printf("Message digest algorithm found : %s\n", OBJ_nid2sn(OBJ_obj2nid(aoid)));
printf("It is not possible to add a nested signature of a different MD type to the MSI file "
"without invalidating the initial signature, as the file contains MsiDigitalSignatureEx.\n"
"The file should be signed again, rather than adding a nested signature.\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (!dse && ctx->options->add_msi_dse) { if (!dse && ctx->options->add_msi_dse) {
printf("Unable to add signature with -add-msi-dse parameter " printf("It is not possible to add a nested signature using the -add-msi-dse parameter "
"without breaking the initial signature.\n\n"); "without invalidating the initial signature, as the file does not contain MsiDigitalSignatureEx.\n"
"The file should be signed again, rather than adding a nested signature.\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
if (dse && !ctx->options->add_msi_dse) { if (dse && !ctx->options->add_msi_dse) {
printf("Unable to add signature without -add-msi-dse parameter " printf("It is not possible to add a signature without using the -add-msi-dse parameter, "
"without breaking the initial signature.\nThis is due to the presence of " "as doing so would invalidate the initial signature due to the presence of MsiDigitalSignatureEx.\n"
"MsiDigitalSignatureEx (-add-msi-dse parameter).\n" "In this case, consider using the -add-msi-dse option.\n");
"Should use -add-msi-dse options in this case.\n\n");
return 0; /* FAILED */ return 0; /* FAILED */
} }
return 1; /* OK */ return 1; /* OK */
} }
/*
* [in] ctx: structure holds input and output data
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
*/
static int msi_hash_length_get(FILE_FORMAT_CTX *ctx)
{
return EVP_MD_size(ctx->options->md);
}
/*
* 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
*/
static int msi_check_file(FILE_FORMAT_CTX *ctx)
{
char *indata = NULL;
uint32_t inlen;
MSI_ENTRY *ds, *dse = NULL;
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
}
ds = msi_signatures_get(ctx->msi_ctx->dirent, &dse);
if (!ds) {
printf("MSI file has no signature\n\n");
return 0; /* FAILED */
}
inlen = GET_UINT32_LE(ds->size);
if (inlen == 0 || inlen >= MAXREGSECT) {
printf("Corrupted DigitalSignature stream length 0x%08X\n", inlen);
return 0; /* FAILED */
}
indata = OPENSSL_malloc((size_t)inlen);
if (!msi_file_read(ctx->msi_ctx->msi, ds, 0, indata, inlen)) {
printf("DigitalSignature stream data error\n\n");
OPENSSL_free(indata);
return 0; /* FAILED */
}
if (!dse) {
printf("Warning: MsiDigitalSignatureEx stream doesn't exist\n");
} else {
ctx->msi_ctx->len_msiex = GET_UINT32_LE(dse->size);
if (ctx->msi_ctx->len_msiex == 0 || ctx->msi_ctx->len_msiex >= MAXREGSECT) {
printf("Corrupted MsiDigitalSignatureEx stream length 0x%08X\n",
ctx->msi_ctx->len_msiex);
OPENSSL_free(indata);
return 0; /* FAILED */
}
ctx->msi_ctx->p_msiex = OPENSSL_malloc((size_t)ctx->msi_ctx->len_msiex);
if (!msi_file_read(ctx->msi_ctx->msi, dse, 0, (char *)ctx->msi_ctx->p_msiex,
ctx->msi_ctx->len_msiex)) {
printf("MsiDigitalSignatureEx stream data error\n\n");
OPENSSL_free(indata);
return 0; /* FAILED */
}
}
OPENSSL_free(indata);
return 1; /* OK */
}
/* /*
Local Variables: Local Variables:
c-basic-offset: 4 c-basic-offset: 4

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,7 @@
#endif /* HAVE_CONFIG_H */ #endif /* HAVE_CONFIG_H */
#include <ctype.h> #include <ctype.h>
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
@ -73,20 +74,24 @@
#endif /* SOCKET */ #endif /* SOCKET */
#endif /* __CYGWIN__ */ #endif /* __CYGWIN__ */
#include <curl/curl.h> #include <curl/curl.h>
#endif /* ENABLE_CURL */
#define MAX_TS_SERVERS 256 #define MAX_TS_SERVERS 256
#endif /* ENABLE_CURL */
#if defined (HAVE_TERMIOS_H) || defined (HAVE_GETPASS) #if defined (HAVE_TERMIOS_H) || defined (HAVE_GETPASS)
#define PROVIDE_ASKPASS 1 #define PROVIDE_ASKPASS 1
#endif #endif
#ifdef _WIN32 #ifdef _MSC_VER
#define FILE_CREATE_MODE "w+b" /* not WIN32, because strcasecmp exists in MinGW */
#else #define strcasecmp _stricmp
#define FILE_CREATE_MODE "w+bx"
#endif #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_UINT8_LE(p) ((const u_char *)(p))[0]
@ -175,6 +180,8 @@
#define SPC_RFC3161_OBJID "1.3.6.1.4.1.311.3.3.1" #define SPC_RFC3161_OBJID "1.3.6.1.4.1.311.3.3.1"
/* Microsoft OID Crypto 2.0 */ /* Microsoft OID Crypto 2.0 */
#define MS_CTL_OBJID "1.3.6.1.4.1.311.10.1" #define MS_CTL_OBJID "1.3.6.1.4.1.311.10.1"
/* Microsoft OID Catalog */
#define CAT_NAMEVALUE_OBJID "1.3.6.1.4.1.311.12.2.1"
/* Microsoft OID Microsoft_Java */ /* Microsoft OID Microsoft_Java */
#define MS_JAVA_SOMETHING "1.3.6.1.4.1.311.15.1" #define MS_JAVA_SOMETHING "1.3.6.1.4.1.311.15.1"
@ -184,6 +191,7 @@
#define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4" #define PKCS9_MESSAGE_DIGEST "1.2.840.113549.1.9.4"
#define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5" #define PKCS9_SIGNING_TIME "1.2.840.113549.1.9.5"
#define PKCS9_COUNTER_SIGNATURE "1.2.840.113549.1.9.6" #define PKCS9_COUNTER_SIGNATURE "1.2.840.113549.1.9.6"
#define PKCS9_SEQUENCE_NUMBER "1.2.840.113549.1.9.25.4"
/* WIN_CERTIFICATE structure declared in Wintrust.h */ /* WIN_CERTIFICATE structure declared in Wintrust.h */
#define WIN_CERT_REVISION_2_0 0x0200 #define WIN_CERT_REVISION_2_0 0x0200
@ -218,6 +226,7 @@
typedef enum { typedef enum {
CMD_SIGN, CMD_SIGN,
CMD_EXTRACT, CMD_EXTRACT,
CMD_EXTRACT_DATA,
CMD_REMOVE, CMD_REMOVE,
CMD_VERIFY, CMD_VERIFY,
CMD_ADD, CMD_ADD,
@ -252,17 +261,17 @@ typedef struct {
const EVP_MD *md; const EVP_MD *md;
char *url; char *url;
time_t time; time_t time;
#ifdef ENABLE_CURL
char *turl[MAX_TS_SERVERS]; char *turl[MAX_TS_SERVERS];
int nturl; int nturl;
char *tsurl[MAX_TS_SERVERS]; char *tsurl[MAX_TS_SERVERS];
int ntsurl; int ntsurl;
char *proxy; char *proxy;
int noverifypeer; int noverifypeer;
#endif /* ENABLE_CURL */
int addBlob; int addBlob;
int nest; int nest;
int index;
int ignore_timestamp; int ignore_timestamp;
int ignore_cdp;
int verbose; int verbose;
int add_msi_dse; int add_msi_dse;
char *catalog; char *catalog;
@ -282,10 +291,10 @@ typedef struct {
STACK_OF(X509_CRL) *crls; STACK_OF(X509_CRL) *crls;
cmd_type_t cmd; cmd_type_t cmd;
char *indata; char *indata;
PKCS7 *prevsig;
char *tsa_certfile; char *tsa_certfile;
char *tsa_keyfile; char *tsa_keyfile;
time_t tsa_time; time_t tsa_time;
int nested_number;
} GLOBAL_OPTIONS; } GLOBAL_OPTIONS;
/* /*
@ -326,6 +335,18 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo) DECLARE_ASN1_FUNCTIONS(SpcSpOpusInfo)
typedef struct {
ASN1_INTEGER *a;
ASN1_OCTET_STRING *string;
ASN1_INTEGER *b;
ASN1_INTEGER *c;
ASN1_INTEGER *d;
ASN1_INTEGER *e;
ASN1_INTEGER *f;
} SpcSipInfo;
DECLARE_ASN1_FUNCTIONS(SpcSipInfo)
typedef struct { typedef struct {
ASN1_OBJECT *type; ASN1_OBJECT *type;
ASN1_TYPE *value; ASN1_TYPE *value;
@ -369,8 +390,6 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(MessageImprint) DECLARE_ASN1_FUNCTIONS(MessageImprint)
#ifdef ENABLE_CURL
typedef struct { typedef struct {
ASN1_OBJECT *type; ASN1_OBJECT *type;
ASN1_OCTET_STRING *signature; ASN1_OCTET_STRING *signature;
@ -413,8 +432,6 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(TimeStampReq) DECLARE_ASN1_FUNCTIONS(TimeStampReq)
#endif /* ENABLE_CURL */
typedef struct { typedef struct {
ASN1_INTEGER *seconds; ASN1_INTEGER *seconds;
ASN1_INTEGER *millis; ASN1_INTEGER *millis;
@ -462,6 +479,8 @@ typedef struct {
DECLARE_ASN1_FUNCTIONS(MsCtlContent) DECLARE_ASN1_FUNCTIONS(MsCtlContent)
typedef struct file_format_st FILE_FORMAT; typedef struct file_format_st FILE_FORMAT;
typedef struct script_ctx_st SCRIPT_CTX;
typedef struct msi_ctx_st MSI_CTX; typedef struct msi_ctx_st MSI_CTX;
typedef struct pe_ctx_st PE_CTX; typedef struct pe_ctx_st PE_CTX;
typedef struct cab_ctx_st CAB_CTX; typedef struct cab_ctx_st CAB_CTX;
@ -472,6 +491,7 @@ typedef struct {
FILE_FORMAT *format; FILE_FORMAT *format;
GLOBAL_OPTIONS *options; GLOBAL_OPTIONS *options;
union { union {
SCRIPT_CTX *script_ctx;
MSI_CTX *msi_ctx; MSI_CTX *msi_ctx;
PE_CTX *pe_ctx; PE_CTX *pe_ctx;
CAB_CTX *cab_ctx; CAB_CTX *cab_ctx;
@ -480,6 +500,7 @@ typedef struct {
}; };
} FILE_FORMAT_CTX; } FILE_FORMAT_CTX;
extern FILE_FORMAT file_format_script;
extern FILE_FORMAT file_format_msi; extern FILE_FORMAT file_format_msi;
extern FILE_FORMAT file_format_pe; extern FILE_FORMAT file_format_pe;
extern FILE_FORMAT file_format_cab; extern FILE_FORMAT file_format_cab;
@ -488,19 +509,23 @@ extern FILE_FORMAT file_format_appx;
struct file_format_st { struct file_format_st {
FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata); FILE_FORMAT_CTX *(*ctx_new) (GLOBAL_OPTIONS *option, BIO *hash, BIO *outdata);
const EVP_MD *(*md_get) (FILE_FORMAT_CTX *ctx);
ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx); ASN1_OBJECT *(*data_blob_get) (u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
PKCS7 *(*pkcs7_contents_get) (FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
int (*hash_length_get) (FILE_FORMAT_CTX *ctx); int (*hash_length_get) (FILE_FORMAT_CTX *ctx);
int (*check_file) (FILE_FORMAT_CTX *ctx, int detached);
u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md); u_char *(*digest_calc) (FILE_FORMAT_CTX *ctx, const EVP_MD *md);
int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7); int (*verify_digests) (FILE_FORMAT_CTX *ctx, PKCS7 *p7);
int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj); int (*verify_indirect_data) (FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
PKCS7 *(*pkcs7_extract) (FILE_FORMAT_CTX *ctx); PKCS7 *(*pkcs7_extract) (FILE_FORMAT_CTX *ctx);
PKCS7 *(*pkcs7_extract_to_nest) (FILE_FORMAT_CTX *ctx);
int (*remove_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); int (*remove_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
PKCS7 *(*pkcs7_prepare) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); int (*process_data) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
PKCS7 *(*pkcs7_signature_new) (FILE_FORMAT_CTX *ctx, BIO *hash);
int (*append_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); int (*append_pkcs7) (FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7); void (*update_data_size) (FILE_FORMAT_CTX *data, BIO *outdata, PKCS7 *p7);
BIO *(*bio_free) (BIO *hash, BIO *outdata); void (*bio_free) (BIO *hash, BIO *outdata);
void (*ctx_cleanup) (FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); void (*ctx_cleanup) (FILE_FORMAT_CTX *ctx);
int (*is_detaching_supported) (void);
}; };
/* /*

377
pe.c
View File

@ -44,34 +44,40 @@ struct pe_ctx_st {
/* FILE_FORMAT method prototypes */ /* FILE_FORMAT method prototypes */
static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata); static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outdata);
static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx); static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX *ctx);
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md);
static int pe_hash_length_get(FILE_FORMAT_CTX *ctx); static int pe_hash_length_get(FILE_FORMAT_CTX *ctx);
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached);
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md); static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7); static int pe_verify_digests(FILE_FORMAT_CTX *ctx, PKCS7 *p7);
static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj); static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOptionalValue *obj);
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx); static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx);
static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx);
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash);
static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static int pe_append_pkcs7(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7); static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7);
static BIO *pe_bio_free(BIO *hash, BIO *outdata); static void pe_bio_free(BIO *hash, BIO *outdata);
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx);
static int pe_is_detaching_supported(void);
FILE_FORMAT file_format_pe = { FILE_FORMAT file_format_pe = {
.ctx_new = pe_ctx_new, .ctx_new = pe_ctx_new,
.data_blob_get = pe_spc_image_data_get, .data_blob_get = pe_spc_image_data_get,
.pkcs7_contents_get = pe_pkcs7_contents_get,
.hash_length_get = pe_hash_length_get, .hash_length_get = pe_hash_length_get,
.check_file = pe_check_file,
.digest_calc = pe_digest_calc, .digest_calc = pe_digest_calc,
.verify_digests = pe_verify_digests, .verify_digests = pe_verify_digests,
.verify_indirect_data = pe_verify_indirect_data, .verify_indirect_data = pe_verify_indirect_data,
.pkcs7_extract = pe_pkcs7_extract, .pkcs7_extract = pe_pkcs7_extract,
.pkcs7_extract_to_nest = pe_pkcs7_extract_to_nest,
.remove_pkcs7 = pe_remove_pkcs7, .remove_pkcs7 = pe_remove_pkcs7,
.pkcs7_prepare = pe_pkcs7_prepare, .process_data = pe_process_data,
.pkcs7_signature_new = pe_pkcs7_signature_new,
.append_pkcs7 = pe_append_pkcs7, .append_pkcs7 = pe_append_pkcs7,
.update_data_size = pe_update_data_size, .update_data_size = pe_update_data_size,
.bio_free = pe_bio_free, .bio_free = pe_bio_free,
.ctx_cleanup = pe_ctx_cleanup .ctx_cleanup = pe_ctx_cleanup,
.is_detaching_supported = pe_is_detaching_supported
}; };
/* Prototypes */ /* Prototypes */
@ -80,10 +86,12 @@ static PKCS7 *pe_pkcs7_get_file(char *indata, PE_CTX *pe_ctx);
static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size); static uint32_t pe_calc_checksum(BIO *bio, uint32_t header_size);
static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx); static uint32_t pe_calc_realchecksum(FILE_FORMAT_CTX *ctx);
static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata); static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata);
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md);
static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj); static int pe_page_hash_get(u_char **ph, int *phlen, int *phtype, SpcAttributeTypeAndOptionalValue *obj);
static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype); static u_char *pe_page_hash_calc(int *rphlen, FILE_FORMAT_CTX *ctx, int phtype);
static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype); static int pe_verify_page_hash(FILE_FORMAT_CTX *ctx, u_char *ph, int phlen, int phtype);
static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype); static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype);
static int pe_check_file(FILE_FORMAT_CTX *ctx);
/* /*
@ -112,12 +120,12 @@ static FILE_FORMAT_CTX *pe_ctx_new(GLOBAL_OPTIONS *options, BIO *hash, BIO *outd
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (memcmp(options->indata, "MZ", 2)) { if (memcmp(options->indata, "MZ", 2)) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
pe_ctx = pe_ctx_get(options->indata, filesize); pe_ctx = pe_ctx_get(options->indata, filesize);
if (!pe_ctx) { if (!pe_ctx) {
unmap_file(options->infile, filesize); unmap_file(options->indata, filesize);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX)); ctx = OPENSSL_malloc(sizeof(FILE_FORMAT_CTX));
@ -170,6 +178,30 @@ static ASN1_OBJECT *pe_spc_image_data_get(u_char **p, int *plen, FILE_FORMAT_CTX
return dtype; /* OK */ return dtype; /* OK */
} }
/*
* Allocate and return a data content to be signed.
* [in] ctx: structure holds input and output data
* [in] hash: message digest BIO
* [in] md: message digest algorithm
* [returns] data content
*/
static PKCS7 *pe_pkcs7_contents_get(FILE_FORMAT_CTX *ctx, BIO *hash, const EVP_MD *md)
{
ASN1_OCTET_STRING *content;
BIO *bhash;
/* squash the unused parameter warning */
(void)hash;
bhash = pe_digest_calc_bio(ctx, md);
if (!bhash) {
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(bhash, ctx);
BIO_free_all(bhash);
return pkcs7_set_content(content);
}
/* /*
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
* [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash) * [returns] the size of the message digest when passed an EVP_MD structure (the size of the hash)
@ -180,121 +212,24 @@ static int pe_hash_length_get(FILE_FORMAT_CTX *ctx)
} }
/* /*
* Print current and calculated PE checksum, * Returns a message digest value of a signed or unsigned PE file.
* check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [in] detached: embedded/detached PKCS#7 signature switch
* [returns] 0 on error or 1 on success
*/
static int pe_check_file(FILE_FORMAT_CTX *ctx, int detached)
{
uint32_t real_pe_checksum, sum = 0;
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
}
real_pe_checksum = pe_calc_realchecksum(ctx);
if (ctx->pe_ctx->pe_checksum == real_pe_checksum) {
printf("PE checksum : %08X\n\n", real_pe_checksum);
} else {
printf("Current PE checksum : %08X\n", ctx->pe_ctx->pe_checksum);
printf("Calculated PE checksum: %08X\n", real_pe_checksum);
printf("Warning: invalid PE checksum\n\n");
}
if (detached) {
printf("Checking the specified catalog file\n\n");
return 1; /* OK */
}
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
/*
* If the sum of the rounded dwLength values does not equal the Size value,
* then either the attribute certificate table or the Size field is corrupted.
*/
while (sum < ctx->pe_ctx->siglen) {
uint32_t len = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->sigpos + sum);
if (ctx->pe_ctx->siglen - len > 8) {
printf("Corrupted attribute certificate table\n");
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
printf("Attribute certificate entry length: %08X\n\n", len);
return 0; /* FAILED */
}
/* quadword align data */
len += len % 8 ? 8 - len % 8 : 0;
sum += len;
}
if (sum != ctx->pe_ctx->siglen) {
printf("Corrupted attribute certificate table\n");
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
printf("Sum of the rounded dwLength values: %08X\n\n", sum);
return 0; /* FAILED */
}
return 1; /* OK */
}
/* Compute a message digest value of a signed or unsigned PE file.
* [in] ctx: structure holds input and output data * [in] ctx: structure holds input and output data
* [in] md: message digest algorithm * [in] md: message digest algorithm
* [returns] pointer to calculated message digest * [returns] pointer to calculated message digest
*/ */
static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md) static u_char *pe_digest_calc(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
{ {
size_t written; u_char *mdbuf;
uint32_t idx = 0, fileend; BIO *bhash = pe_digest_calc_bio(ctx, md);
u_char *mdbuf = NULL; if (!bhash) {
BIO *bhash = BIO_new(BIO_f_md());
if (!BIO_set_md(bhash, md)) {
printf("Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return 0; /* FAILED */ return 0; /* FAILED */
} }
BIO_push(bhash, BIO_new(BIO_s_null()));
if (ctx->pe_ctx->sigpos)
fileend = ctx->pe_ctx->sigpos;
else
fileend = ctx->pe_ctx->fileend;
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|| written != ctx->pe_ctx->header_size + 88) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 4;
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
60 + ctx->pe_ctx->pe32plus * 16, &written)
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 8;
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
printf("Unable to calculate digest\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
if (!ctx->pe_ctx->sigpos) {
/* pad (with 0's) unsigned PE file to 8 byte boundary */
int len = 8 - ctx->pe_ctx->fileend % 8;
if (len > 0 && len != 8) {
char *buf = OPENSSL_malloc(8);
memset(buf, 0, (size_t)len);
BIO_write(bhash, buf, len);
OPENSSL_free(buf);
}
}
mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md)); mdbuf = OPENSSL_malloc((size_t)EVP_MD_size(md));
BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md)); BIO_gets(bhash, (char*)mdbuf, EVP_MD_size(md));
BIO_free_all(bhash); BIO_free_all(bhash);
return mdbuf; /* OK */ return mdbuf; /* OK */
} }
/* /*
* Calculate message digest and page_hash and compare to values retrieved * Calculate message digest and page_hash and compare to values retrieved
* from PKCS#7 signedData. * from PKCS#7 signedData.
@ -387,13 +322,22 @@ static int pe_verify_indirect_data(FILE_FORMAT_CTX *ctx, SpcAttributeTypeAndOpti
*/ */
static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx) static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx)
{ {
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0 if (!pe_check_file(ctx)) {
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
return pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx); return pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx);
} }
/*
* Extract existing signature in DER format.
* [in] ctx: structure holds input and output data
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *pe_pkcs7_extract_to_nest(FILE_FORMAT_CTX *ctx)
{
return pe_pkcs7_extract(ctx);
}
/* /*
* Remove existing signature. * Remove existing signature.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
@ -403,9 +347,8 @@ static PKCS7 *pe_pkcs7_extract(FILE_FORMAT_CTX *ctx)
*/ */
static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
if (ctx->pe_ctx->sigpos == 0) { if (!pe_check_file(ctx)) {
printf("PE file does not have any signature\n"); return 1; /* FAILED, no signature */
return 1; /* FAILED */
} }
/* Strip current signature */ /* Strip current signature */
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos; ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
@ -417,59 +360,57 @@ static int pe_remove_pkcs7(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
} }
/* /*
* Obtain an existing signature or create a new one. * Modify specific type data and calculate a hash (message digest) of data.
* [in, out] ctx: structure holds input and output data * [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [out] outdata: outdata file BIO * [out] outdata: outdata file BIO
* [returns] pointer to PKCS#7 structure * [returns] 1 on error or 0 on success
*/ */
static PKCS7 *pe_pkcs7_prepare(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static int pe_process_data(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
{ {
PKCS7 *cursig = NULL, *p7 = NULL;
/* Obtain a current signature from previously-signed file */
if ((ctx->options->cmd == CMD_SIGN && ctx->options->nest)
|| (ctx->options->cmd == CMD_ATTACH && ctx->options->nest)
|| ctx->options->cmd == CMD_ADD) {
cursig = pe_pkcs7_get_file(ctx->options->indata, ctx->pe_ctx);
if (!cursig) {
printf("Unable to extract existing signature\n");
return NULL; /* FAILED */
}
if (ctx->options->cmd == CMD_ADD)
p7 = cursig;
}
if (ctx->pe_ctx->sigpos > 0) { if (ctx->pe_ctx->sigpos > 0) {
/* Strip current signature */ /* Strip current signature */
ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos; ctx->pe_ctx->fileend = ctx->pe_ctx->sigpos;
} }
if (!pe_modify_header(ctx, hash, outdata)) { if (!pe_modify_header(ctx, hash, outdata)) {
printf("Unable to modify file header\n"); printf("Unable to modify file header\n");
return NULL; /* FAILED */ return 1; /* FAILED */
} }
if (ctx->options->cmd == CMD_ATTACH) { return 0; /* OK */
/* Obtain an existing PKCS#7 signature */
p7 = pkcs7_get_sigfile(ctx);
if (!p7) {
printf("Unable to extract valid signature\n");
PKCS7_free(cursig);
return NULL; /* FAILED */
} }
} else if (ctx->options->cmd == CMD_SIGN) {
/* Create a new PKCS#7 signature */ /*
p7 = pkcs7_create(ctx); * Create a new PKCS#7 signature.
* [in, out] ctx: structure holds input and output data
* [out] hash: message digest BIO
* [returns] pointer to PKCS#7 structure
*/
static PKCS7 *pe_pkcs7_signature_new(FILE_FORMAT_CTX *ctx, BIO *hash)
{
ASN1_OCTET_STRING *content;
PKCS7 *p7 = pkcs7_create(ctx);
if (!p7) { if (!p7) {
printf("Creating a new signature failed\n"); printf("Creating a new signature failed\n");
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
if (!add_indirect_data_object(p7, hash, ctx)) { if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n"); printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7); PKCS7_free(p7);
return NULL; /* FAILED */ return NULL; /* FAILED */
} }
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
printf("Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
} }
if (ctx->options->nest) if (!sign_spc_indirect_data_content(p7, content)) {
ctx->options->prevsig = cursig; printf("Failed to set signed content\n");
PKCS7_free(p7);
ASN1_OCTET_STRING_free(content);
return NULL; /* FAILED */
}
ASN1_OCTET_STRING_free(content);
return p7; return p7;
} }
@ -555,40 +496,33 @@ static void pe_update_data_size(FILE_FORMAT_CTX *ctx, BIO *outdata, PKCS7 *p7)
* [out] outdata: outdata file BIO (unused) * [out] outdata: outdata file BIO (unused)
* [returns] none * [returns] none
*/ */
static BIO *pe_bio_free(BIO *hash, BIO *outdata) static void pe_bio_free(BIO *hash, BIO *outdata)
{ {
/* squash the unused parameter warning */ /* squash the unused parameter warning */
(void)outdata; (void)outdata;
BIO_free_all(hash); BIO_free_all(hash);
return NULL;
} }
/* /*
* Deallocate a FILE_FORMAT_CTX structure and PE format specific structure, * Deallocate a FILE_FORMAT_CTX structure and PE format specific structure,
* unmap indata file, unlink outfile. * unmap indata file.
* [out] ctx: structure holds input and output data * [out] ctx: structure holds input and output data
* [out] hash: message digest BIO * [out] hash: message digest BIO
* [in] outdata: outdata file BIO * [in] outdata: outdata file BIO
* [returns] none * [returns] none
*/ */
static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata) static void pe_ctx_cleanup(FILE_FORMAT_CTX *ctx)
{ {
if (outdata) {
BIO_free_all(hash);
if (ctx->options->outfile) {
#ifdef WIN32
_unlink(ctx->options->outfile);
#else
unlink(ctx->options->outfile);
#endif /* WIN32 */
}
}
unmap_file(ctx->options->indata, ctx->pe_ctx->fileend); unmap_file(ctx->options->indata, ctx->pe_ctx->fileend);
OPENSSL_free(ctx->pe_ctx); OPENSSL_free(ctx->pe_ctx);
OPENSSL_free(ctx); OPENSSL_free(ctx);
} }
static int pe_is_detaching_supported(void)
{
return 1; /* OK */
}
/* /*
* PE helper functions * PE helper functions
*/ */
@ -653,14 +587,11 @@ static PE_CTX *pe_ctx_get(char *indata, uint32_t filesize)
siglen = GET_UINT32_LE(indata + header_size + 152 + pe32plus * 16 + 4); siglen = GET_UINT32_LE(indata + header_size + 152 + pe32plus * 16 + 4);
/* Since fix for MS Bulletin MS12-024 we can really assume /* Since fix for MS Bulletin MS12-024 we can really assume
that signature should be last part of file */ that signature should be last part of file */
if ((sigpos > 0 && sigpos < filesize && sigpos + siglen != filesize) if ((sigpos != 0 || siglen != 0) &&
|| (sigpos >= filesize)) { (sigpos == 0 || siglen == 0 || sigpos >= filesize || sigpos + siglen != filesize)) {
printf("Corrupt PE file - current signature not at the end of the file\n"); printf("Ignoring PE signature not at the end of the file\n");
return NULL; /* FAILED */ sigpos = 0;
} siglen = 0;
if ((sigpos > 0 && siglen == 0) || (sigpos == 0 && siglen > 0)) {
printf("Corrupt signature\n");
return NULL; /* FAILED */
} }
pe_ctx = OPENSSL_zalloc(sizeof(PE_CTX)); pe_ctx = OPENSSL_zalloc(sizeof(PE_CTX));
pe_ctx->header_size = header_size; pe_ctx->header_size = header_size;
@ -836,6 +767,62 @@ static int pe_modify_header(FILE_FORMAT_CTX *ctx, BIO *hash, BIO *outdata)
return 1; /* OK */ return 1; /* OK */
} }
/*
* Compute a message digest value of a signed or unsigned PE file.
* [in] ctx: structure holds input and output data
* [in] md: message digest algorithm
* [returns] calculated message digest BIO
*/
static BIO *pe_digest_calc_bio(FILE_FORMAT_CTX *ctx, const EVP_MD *md)
{
size_t written;
uint32_t idx = 0, fileend;
BIO *bhash = BIO_new(BIO_f_md());
if (!BIO_set_md(bhash, md)) {
printf("Unable to set the message digest of BIO\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
BIO_push(bhash, BIO_new(BIO_s_null()));
if (ctx->pe_ctx->sigpos)
fileend = ctx->pe_ctx->sigpos;
else
fileend = ctx->pe_ctx->fileend;
/* ctx->pe_ctx->header_size + 88 + 4 + 60 + ctx->pe_ctx->pe32plus * 16 + 8 */
if (!BIO_write_ex(bhash, ctx->options->indata, ctx->pe_ctx->header_size + 88, &written)
|| written != ctx->pe_ctx->header_size + 88) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 4;
if (!BIO_write_ex(bhash, ctx->options->indata + idx,
60 + ctx->pe_ctx->pe32plus * 16, &written)
|| written != 60 + ctx->pe_ctx->pe32plus * 16) {
BIO_free_all(bhash);
return 0; /* FAILED */
}
idx += (uint32_t)written + 8;
if (!bio_hash_data(bhash, ctx->options->indata, idx, fileend)) {
printf("Unable to calculate digest\n");
BIO_free_all(bhash);
return 0; /* FAILED */
}
if (!ctx->pe_ctx->sigpos) {
/* pad (with 0's) unsigned PE file to 8 byte boundary */
int len = 8 - ctx->pe_ctx->fileend % 8;
if (len > 0 && len != 8) {
char *buf = OPENSSL_malloc(8);
memset(buf, 0, (size_t)len);
BIO_write(bhash, buf, len);
OPENSSL_free(buf);
}
}
return bhash;
}
/* /*
* Page hash support * Page hash support
*/ */
@ -1172,6 +1159,58 @@ static SpcLink *pe_page_hash_link_get(FILE_FORMAT_CTX *ctx, int phtype)
return link; return link;
} }
/*
* Print current and calculated PE checksum,
* check if the signature exists.
* [in, out] ctx: structure holds input and output data
* [returns] 0 on error or 1 on success
*/
static int pe_check_file(FILE_FORMAT_CTX *ctx)
{
uint32_t real_pe_checksum, sum = 0;
if (!ctx) {
printf("Init error\n\n");
return 0; /* FAILED */
}
real_pe_checksum = pe_calc_realchecksum(ctx);
if (ctx->pe_ctx->pe_checksum == real_pe_checksum) {
printf("PE checksum : %08X\n\n", real_pe_checksum);
} else {
printf("Current PE checksum : %08X\n", ctx->pe_ctx->pe_checksum);
printf("Calculated PE checksum: %08X\n", real_pe_checksum);
printf("Warning: invalid PE checksum\n\n");
}
if (ctx->pe_ctx->sigpos == 0 || ctx->pe_ctx->siglen == 0
|| ctx->pe_ctx->sigpos > ctx->pe_ctx->fileend) {
printf("No signature found\n\n");
return 0; /* FAILED */
}
/*
* If the sum of the rounded dwLength values does not equal the Size value,
* then either the attribute certificate table or the Size field is corrupted.
*/
while (sum < ctx->pe_ctx->siglen) {
uint32_t len = GET_UINT32_LE(ctx->options->indata + ctx->pe_ctx->sigpos + sum);
if (ctx->pe_ctx->siglen - len > 8) {
printf("Corrupted attribute certificate table\n");
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
printf("Attribute certificate entry length: %08X\n\n", len);
return 0; /* FAILED */
}
/* quadword align data */
len += len % 8 ? 8 - len % 8 : 0;
sum += len;
}
if (sum != ctx->pe_ctx->siglen) {
printf("Corrupted attribute certificate table\n");
printf("Attribute certificate table size : %08X\n", ctx->pe_ctx->siglen);
printf("Sum of the rounded dwLength values: %08X\n\n", sum);
return 0; /* FAILED */
}
return 1; /* OK */
}
/* /*
Local Variables: Local Variables:
c-basic-offset: 4 c-basic-offset: 4

891
script.c Normal file
View File

@ -0,0 +1,891 @@
/*
* 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)) {
printf("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) {
printf("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)) {
printf("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, der_max_length, der_length;
char *ptr;
BIO *bio_mem, *bio_b64 = NULL;
char *base64_data = NULL;
char *der_data = NULL;
const char *der_tmp;
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) {
printf("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) {
printf("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) {
printf("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);
/* allocate memory for DER output */
der_max_length = BIO_ctrl_pending(bio_b64);
der_data = OPENSSL_malloc(der_max_length);
if (!der_data)
goto cleanup;
/* decode Base64 to DER */
if (!BIO_read_ex(bio_b64, der_data, der_max_length, &der_length))
goto cleanup;
if (der_length <= 0)
goto cleanup;
/* decode DER */
der_tmp = der_data;
retval = d2i_PKCS7(NULL, (const unsigned char **)&der_tmp, (int)der_length);
cleanup:
OPENSSL_free(base64_data);
OPENSSL_free(clean_base64);
OPENSSL_free(der_data);
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 1; /* FAILED */
if (!script_digest_convert(hash, ctx, ctx->script_ctx->fileend))
return 1; /* FAILED */
return 0; /* 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) {
printf("Creating a new signature failed\n");
return NULL; /* FAILED */
}
if (!add_indirect_data_object(p7)) {
printf("Adding SPC_INDIRECT_DATA_OBJID failed\n");
PKCS7_free(p7);
return NULL; /* FAILED */
}
content = spc_indirect_data_content_get(hash, ctx);
if (!content) {
printf("Failed to get spcIndirectDataContent\n");
return NULL; /* FAILED */
}
if (!sign_spc_indirect_data_content(p7, content)) {
printf("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)) {
printf("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)) {
printf("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) {
printf("Init error\n\n");
return 0; /* FAILED */
}
if (ctx->script_ctx->sigpos == 0
|| ctx->script_ctx->sigpos > ctx->script_ctx->fileend) {
printf("No signature found\n\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:
*/

View File

@ -1,22 +1,22 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDoTCCAomgAwIBAgIUfuEVHNA/1VLDJI9mhANrBndIj6swDQYJKoZIhvcNAQEL MIIDoTCCAomgAwIBAgIUVD6Q+gnrOmJWbEnmfydpUg2JNmswDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTcwMTAxMDAwMDAwWhcNMjYxMTEwMDAwMDAwWjBYMQswCQYDVQQGEwJQTDEVMBMG MTcwMTAxMDAwMDAwWhcNMzYxMjI3MDAwMDAwWjBYMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEQMA4GA1UEAwwHUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC cml0eTEQMA4GA1UEAwwHUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC
AQoCggEBAMRykK9mZCSpkVUbCq1r12OXvIDkcjj+g4JpyZOrmPpz5RvmLvYBBgeV AQoCggEBAMUvCAWI9LrgtVw9RARZLFb/qB1868H86eyr8oITzXl6u9FSQwvGH1MG
IsUcqHm3/uSLpOFu/pwFJ2CBZVPJ1d49Y9DVnNR1dUbneWX9tE7A6NV9IG1kVagM szRhuD9TJAjy1uIiVPJ7ez2VjKXm2G9lUZMPJQRt50XTGbsGGDi4ITU1W3P+HI5u
veI/ANLuRi0H51aAZS9L8c6WxlR4+pxJoCZp1tyTGmfjxzBEXUWvyUrIMrW/r9TH 45I0IL14Qv/R8X26lndBzlY4ImoCTAN4KzdfvoGLaMpNvbC1P7a4mlukrumi3WKT
u5gGgR6k86EbH7q71XRLhLeEi9QGCG24gobngYNZa5mb8DgLCkUeFtRsrYGEUT0G RAq46Mj5DAqr63NOolWimtTB+h0ZWv+xxngR7cfo+EimvhPB7y3xhY9OJ/27l6mJ
HTpAGXUrpAb3U7+4LkGaS6mc0NPTW4lz06Z3VhyYwwAbgU2DZQjMpqYWv6UctOP+ uQJohz5PmzhZByluMhicTsd2cJEKQb7jnih492okCj6vH/FJmKg+DzXKTyue5Ki4
5elPDc/PrTAdHAgbOhgvt1HUlqgn7lUCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB 2jhzM9v1npyIkd7s/gnZVEsHH6oQIt8CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB
/zAdBgNVHQ4EFgQUWIpzlJI+vefcJwcNGHwwRms/2ncwHwYDVR0jBBgwFoAUWIpz /zAdBgNVHQ4EFgQUGjxG/vql0oJgItr7HsLaW+koiMgwHwYDVR0jBBgwFoAUGjxG
lJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA /vql0oJgItr7HsLaW+koiMgwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUA
A4IBAQAl+G1nXXW5u3notmAG5y8kwufFqNi5Jn1HVbT08w4IiteWMw3D9GEOCueM A4IBAQAy7AKbO8B8Njseqjy2LAj2sKHCLc1jsQa7izOAtr852NYFAfpBvkqQfxne
g5A03bC/Xv1PRvMatXQSARRvvVl3y1l98sA+97SP/FFUla3W5Rn91OsWd4qkcXhv 8k5iPKmcJE+Sm4wv3V/lzx2AHEXAPa7BgiAo7yeo9UbrDgRRGw4MirQ/djp44ekv
CtPKHpz0SCjKLv3HG/C7fBJPG9XHMgkGZarM2KsQUlkn7DjdBccYcp/zJvtvm+be KCc54bSE/paUZyEWKr8NbdBy7SZfZ/Dd+XUY2lbm3Mue3AzWl4xp4StoT6oaw6VI
nR5ZqE6LI52WCXg0w/KlJlildU5LE/bvHbfmRUVm/4GhUNN8ko8eG67ueuftkeTD H6bIhZupond/RWp4jmHHEfvl4T6YLzl5FC+Ec2xBbpk5vAVZgyfrlv+W6V/il/X9
banKmnuSay02I42A0th2w8Hz7oaOUEpl8S9TfqeFuqLhtUP0FzUNMPAg0o5YTpe4 KTZl5ax4FJAm7vPn6fsgdAM5y24zJUAkeakKFsBYtoVoGg1iiFuMEGwFRn7EZYl1
xAArbPbFvH2l3plEaYccKYvbAGT/ 8D16qEH+YPLCzujH1PhzjmmAfKl2
-----END CERTIFICATE----- -----END CERTIFICATE-----

Binary file not shown.

View File

@ -2,12 +2,12 @@
MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJQTDEVMBMGA1UE MIICBDCB7QIBATANBgkqhkiG9w0BAQsFADBgMQswCQYDVQQGEwJQTDEVMBMGA1UE
CgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0 CgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhvcml0
eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBFw0xOTAxMDEwMDAwMDBaFw00MzAx eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBFw0xOTAxMDEwMDAwMDBaFw00MzAx
MDEwMDAwMDBaMCcwJQIUSXAaPeUatfheDTFo77LnMBHgyeMXDTIzMDQyODEyMzMz MDEwMDAwMDBaMCcwJQIUazbrVgbYb+IN803UmJJa0DPHQsAXDTI0MDIyNzE1MzAx
OVqgMDAuMB8GA1UdIwQYMBaAFOP6v42ECbVR/AiLDZ7f2WKtYXILMAsGA1UdFAQE NFqgMDAuMB8GA1UdIwQYMBaAFGQQ8as5N9zB/bsdyD9BWHdiJ+8pMAsGA1UdFAQE
AgIQATANBgkqhkiG9w0BAQsFAAOCAQEARMWBcG6sanX3nwoSPGcUNEkYG2+qB8/w AgIQATANBgkqhkiG9w0BAQsFAAOCAQEAV+Ce8WaNN/PXbVT9rOy/TS2EDrM/oFPG
wlcWWY7RfOGQWVHqbVvklJdTYFDw+mA6RuATMOd5S6hXa8tms4L2YQUmYyfNOyJu vwZr2IQDcBtgFV5DpNZRKJo2m4mjPPt1eCjE404U2r6081bvq3PtwSPwezV+uCzF
+INPDnqueQshFZ8PqBTaP6O/NRI/LOLpcIIohgemwfPYPrbd/JqcLlQ2Vbgb9Lnb dDUafeR0eZhmzxD8M2Jmi5hGp3fQevDrA4+RR33DneYSNfzGx35VN8v/L7/TuA5X
CYZWGOF7AKC0ugTTvLuWr9LPwmWFdORtmm3UJfFOPDX6zmHPAPhBUuyrxl8UoNZB 0PG8b5hL9f3vsVXvFRj6hMkRy5m+gxFfWW/Uw3fXIt9sDLJ+eAKURdqn1c3CEwD6
ZPvgeBjbyQy3MaJsbaniwoOahmT+MbYV/0/YRwI5XDxjiOdJSBz3Wd5YDNDozvG6 bzh0s6dSXT4wp5/l96x8fKAv5hMqDC7KufvwjhhSXdYXDOHDQcv0g5aLo8Ug8dHg
zZMHtF9TkUZjmLUe3Jm0GnS33gU8SB6YdYpnnPg+Up4w5sye90pk9A== NJHqbTAAViyGfvsS9/pYb8kHpAWvaADK84tzaMzj7uCDXlCZEjIr7w==
-----END X509 CRL----- -----END X509 CRL-----

View File

@ -2,13 +2,13 @@
MIICMzCCARsCAQEwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UEBhMCUEwxFTATBgNV MIICMzCCARsCAQEwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UEBhMCUEwxFTATBgNV
BAoMDG9zc2xzaWduY29kZTEgMB4GA1UECwwXQ2VydGlmaWNhdGlvbiBBdXRob3Jp BAoMDG9zc2xzaWduY29kZTEgMB4GA1UECwwXQ2VydGlmaWNhdGlvbiBBdXRob3Jp
dHkxHzAdBgNVBAMMFkludGVybWVkaWF0ZSBDQSBDUkwgRFAXDTE5MDEwMTAwMDAw dHkxHzAdBgNVBAMMFkludGVybWVkaWF0ZSBDQSBDUkwgRFAXDTE5MDEwMTAwMDAw
MFoXDTQzMDEwMTAwMDAwMFowTjAlAhQxdzwUXgMSEn/RzOwbdKtxlLgYJhcNMjMw MFoXDTQzMDEwMTAwMDAwMFowTjAlAhQcZvYIe2b1FreAKfoi/uGkSGJCthcNMjQw
NDI4MTIzMzQwWjAlAhRJcBo95Rq1+F4NMWjvsucwEeDJ4xcNMjMwNDI4MTIzMzM5 MjI3MTUzMDE0WjAlAhRrNutWBthv4g3zTdSYklrQM8dCwBcNMjQwMjI3MTUzMDE0
WqAwMC4wHwYDVR0jBBgwFoAUYbtAOknHjmiu3l8ONAUY387kFi8wCwYDVR0UBAQC WqAwMC4wHwYDVR0jBBgwFoAUFDxiqeJxiJbmZ4erKH0pBIhq7SMwCwYDVR0UBAQC
AhACMA0GCSqGSIb3DQEBCwUAA4IBAQBOPbjiBQ1jOEjfQ1Q3/DBfzFKxeL7Cdoiq AhACMA0GCSqGSIb3DQEBCwUAA4IBAQBZzGXEP4XdKuJ8ANIBGPu1Z+7T+4ln+nu3
6l1psqamZRTmU0a+1qRH/qokB0gA1XeeYIZRcruthHDk87F+WZPCKIr5cqfH2RFA MEPC9BexVAA02YPZx6i4c3cHC87aOL7zsr/K9OeF5MAYzi2QJwsenF4b9QL2rzQV
xjDEkwgA8OZSdSMh+ZhBLBoGjZhFdnX/FknMcA23cLnzuv4RmsbiokwWrysebDNY sCAb3sY5ImAxN38GTJ+oI+uTeOefNE0wS7pP4phRmYNZwyDhxA2iT76+luoygyth
DbTQpa/OFvqmHmgXbhrBqUinF7gl1ppzXs/d+FjSg1aAre/lx3KEXCgc126kldS9 NesiGalMFDrJvUM1DADTZGQrz9cQVgFq9WTcta9rdTYqSNctxkbpQaY0hgssH1Sh
9+c//UPmltYB17ipVWBmVOyVHNphnHtqPElD9Gz1DooVZ1opsqRBh0APu7fqmm6A hWlSiFttciA2XVD7Ju/Qv9zN4nCQC0LskgKhqsefsOukpo6jqJ92OmNrrNaERfqs
5d/lvNlPrlu835/fgUF3YmyU+w4x5sQCBjprTD6QIbIzCXDXfpBj Yavzuj6DlcnE46ZxA0y2Du1apz0WDlbcAnsEqfNSDDCid09v+V9a
-----END X509 CRL----- -----END X509 CRL-----

22
tests/certs/CAcross.pem Normal file
View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDqTCCApGgAwIBAgIUKFKqG3FwQAmy4HgYyO4mGEiQ8QAwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD1RydXN0ZWQgUm9v
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0zNzEyMjcwMDAwMDBaMFgxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxIDAeBgNVBAsMF0NlcnRpZmljYXRp
b24gQXV0aG9yaXR5MRAwDgYDVQQDDAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEAxS8IBYj0uuC1XD1EBFksVv+oHXzrwfzp7KvyghPNeXq7
0VJDC8YfUwazNGG4P1MkCPLW4iJU8nt7PZWMpebYb2VRkw8lBG3nRdMZuwYYOLgh
NTVbc/4cjm7jkjQgvXhC/9HxfbqWd0HOVjgiagJMA3grN1++gYtoyk29sLU/tria
W6Su6aLdYpNECrjoyPkMCqvrc06iVaKa1MH6HRla/7HGeBHtx+j4SKa+E8HvLfGF
j04n/buXqYm5AmiHPk+bOFkHKW4yGJxOx3ZwkQpBvuOeKHj3aiQKPq8f8UmYqD4P
NcpPK57kqLjaOHMz2/WenIiR3uz+CdlUSwcfqhAi3wIDAQABo2MwYTAPBgNVHRMB
Af8EBTADAQH/MB0GA1UdDgQWBBQaPEb++qXSgmAi2vsewtpb6SiIyDAfBgNVHSME
GDAWgBSzLyt07qrH3+rgkQCvS/YZ3jR+fzAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZI
hvcNAQELBQADggEBADCY4hadNyzoz0CpdpBcFjyglxOkgcitIAgvoc2N5zwHrkg7
BgJM1BJmCyki0AhXRKwl7sYbzNHgAhP1pBNjZqO13+cRcqPKvrxpYnsv11HaPS2E
Ee/8EwHB3JlWlmWd6PHaJV0usRjDOuJnV/I/9mdFfIUcY0aoA36o2CCRJRKcvvVp
Ztomnvw8IqFTn3GCNK3TRmVf2RYMhsDNQoEEidJENwCCRlcojmk1Ld95T89QsGOR
cWJAHzyfbMQxRD7kQPZ4B2M8MvU3uD6nsamzvVM7H0UkSNuYLVkpU/wTUR8eQ2LI
wFyi9JhKP4hF/RBuSzIHpXWO46GvzAO5dXZPLm0=
-----END CERTIFICATE-----

22
tests/certs/CAroot.pem Normal file
View File

@ -0,0 +1,22 @@
-----BEGIN CERTIFICATE-----
MIIDsTCCApmgAwIBAgIUQQOniemvgowXmc2hZSZoIWEF8DUwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD1RydXN0ZWQgUm9v
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0zNjEyMjcwMDAwMDBaMGAxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxIDAeBgNVBAsMF0NlcnRpZmljYXRp
b24gQXV0aG9yaXR5MRgwFgYDVQQDDA9UcnVzdGVkIFJvb3QgQ0EwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCL2tfObRQcJ4fo/jarNfQVmeqjulYkLLNG
UtYmFSAxkcYbmpfHpsSxnW9sbDZV8Cp6tFa97V7XATCNL/r671lpZjkYEj0NkjBE
84OI0pkAEwWC5m3+dl3wehu977OcV7cMxNTmAHJwEadXR3jmZV625/lja1QqgkqK
MqOty2pJNmsRUEogjFoh00eulnapW5u72ovq9IDgjjhdvAClwkTY5jsLTeDwgvfS
MRjAmef2qExI/l760Bl0xe4XDdROgN90npS/zuKcCkThtvmffiUZsyeel1kto1pF
zkYGJroWSJl0Jt+dpJHcpSXOXP5M+LnuLV4nl5vqwksdPzswQvuZAgMBAAGjYzBh
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLMvK3Tuqsff6uCRAK9L9hneNH5/
MB8GA1UdIwQYMBaAFLMvK3Tuqsff6uCRAK9L9hneNH5/MA4GA1UdDwEB/wQEAwIB
hjANBgkqhkiG9w0BAQsFAAOCAQEAesmiOEl8OA+T4DDOgjfhY6+pUZDDKpsx//mj
/1bxr+akfwL3dN5IBq8g8tJJHOLqrl7Lard7onDRnz8GZmpkPvFa87QD2PU2addo
DAQWdYsDrNMWkAE37Wk7FZ0RyFHiBopRUMspKmx/XwvJf+rhkidjJYxCo317i/Z8
fWi//wGsI6ogezOsMCxNEcIn2PltGfDiVFklmwsXhyfvGYfctqepu661a/7hFUaP
uN0iEboTDcQuiWwwEEwMe55L1rjDlpRkGUBah5FteGmVwk0AoT4b+1FVrj9Q6sEa
Ge6gsrhu2syUF9CErTW/CiV+jONe2ygw4welOBo598QW71w7Vw==
-----END CERTIFICATE-----

View File

@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
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
gt3jad7Axl6C3faOfjzeyw== b1+6D1aGpwt+11f9ubd+Nw==
-----END PRIVATE KEY----- -----END PRIVATE KEY-----

View File

@ -1,25 +1,25 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
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
JVHLUWz0r6IIp0mHrMwoI94yZBVXje0= hpE0ajpKT0x/dNa/qCwl/9zc8XxGnPk=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,22 +1,22 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
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
0mCOiQ== QepMyA==
-----END CERTIFICATE----- -----END CERTIFICATE-----

Binary file not shown.

View File

@ -2,14 +2,14 @@
MIICUzCCATsCAQEwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCUEwxFTATBgNV MIICUzCCATsCAQEwDQYJKoZIhvcNAQELBQAwYDELMAkGA1UEBhMCUEwxFTATBgNV
BAoMDG9zc2xzaWduY29kZTEkMCIGA1UECwwbVGltZXN0YW1wIEF1dGhvcml0eSBS BAoMDG9zc2xzaWduY29kZTEkMCIGA1UECwwbVGltZXN0YW1wIEF1dGhvcml0eSBS
b290IENBMRQwEgYDVQQDDAtUU0EgUm9vdCBDQRcNMTkwMTAxMDAwMDAwWhcNNDMw b290IENBMRQwEgYDVQQDDAtUU0EgUm9vdCBDQRcNMTkwMTAxMDAwMDAwWhcNNDMw
MTAxMDAwMDAwWjB1MCUCFDF3PBReAxISf9HM7Bt0q3GUuBgmFw0yMzA0MjgxMjMz MTAxMDAwMDAwWjB1MCUCFA5lCWy+o133yMUTfqtWmkigL1MeFw0yNDAyMjcxNTMw
NDBaMCUCFElwGj3lGrX4Xg0xaO+y5zAR4MnjFw0yMzA0MjgxMjMzMzlaMCUCFFcV MTVaMCUCFBxm9gh7ZvUWt4Ap+iL+4aRIYkK2Fw0yNDAyMjcxNTMwMTRaMCUCFGs2
Ys5TRUZVMGFWN3Et/yQQme62Fw0yMzA0MjgxMjMzNDBaoDAwLjAfBgNVHSMEGDAW 61YG2G/iDfNN1JiSWtAzx0LAFw0yNDAyMjcxNTMwMTRaoDAwLjAfBgNVHSMEGDAW
gBROnw9rl/0Op/SoxQTubQfvoxosZjALBgNVHRQEBAICEAMwDQYJKoZIhvcNAQEL gBQ/Lo89CPWO9O/WTHvV+3Dt/60o+TALBgNVHRQEBAICEAMwDQYJKoZIhvcNAQEL
BQADggEBAEu9tNvUMHJ69vCPdJH3FUuGPHuTyC32aLBoV/g/t9OD+95fDwwijKbX BQADggEBAJ1HK2LepVJyOfqbODFxD6GJo5jr1HEnoaZ1h/iJTZZyDYfRf8d8Y/VG
QcypdgGEp4KEH4WQQ8JyhScgxd3gjnNoB9ITIZ14eZ9uslIZPaQztMDqvzLZcsLf Iva00gj2KVy8tOlO0FrUR1Tqk42IjaPld0lXqKl4hkmCUWLpLgual5JcQPHhDUnT
PXWWvCs8GO1K30VVqVual+OT8ojWBAgF49rg2OZX4JUAhXyaP360MtWEWVNghRwk hiIDvbI5UHGCWeN+unXFRuT9CvtAM+3FOhuL9bBnXwdlOxZPWL8wnYT0jB/HzdKP
FhK7q6HOaNtxrIar1ZuDkvqEvmaEexJ/3HOGAM0DWmhneO2hIpCAfpYnGic66I69 KOWfN7eEXo6tTL8XxRJ5LxjwbrK1eZCdQqL2Rt2W8JTMweeqv9PkNqzYeDAvKc0s
17FQWE6WLTS+Hjc8qQEDPeGsSK3NWhGiOKDr1Zpjae5PknghxzfxE8u56t6pMBHj UCkKj+aNxQlNPy+Tw/MckJK1NE921b8LwuV0uzBrOg0Gr62RnnPGa6Z5YLArczWo
DWYGMc57TpovDpTdla7YipkVxSrTkhI= aZlLVsJuQrOxxyXe/kygCu9lqjaf4CI=
-----END X509 CRL----- -----END X509 CRL-----

View File

@ -1,28 +1,28 @@
-----BEGIN PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
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
s3UnnC/9NhgSMwB82OPX3g== jkdwUMLiaSrpf8KSTL3NxM0=
-----END PRIVATE KEY----- -----END PRIVATE KEY-----

View File

@ -1,25 +1,25 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEIjCCAwqgAwIBAgIUVxVizlNFRlUwYVY3cS3/JBCZ7rYwDQYJKoZIhvcNAQEL MIIEIjCCAwqgAwIBAgIUDmUJbL6jXffIxRN+q1aaSKAvUx4wDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0yODAxMDEwMDAwMDBaMEQxCzAJBgNVBAYT dCBDQTAeFw0xODAxMDEwMDAwMDBaFw0zODAxMDEwMDAwMDBaMEQxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA1RTQTEQMA4GA1UE AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA1RTQTEQMA4GA1UE
AwwHUmV2b2tlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM8+2pOx AwwHUmV2b2tlZDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPFTyXAJ
3MIr30HnNI0iK7jb1Ntz9LgBr15KxuNx59PLs2QI9qeSXxB4Ei9Dvk/3yofzbyIO x5YR6yYchC70zyYjOccVabEUXnkTXoOx5avUrYVs4qc2/V102FQcWEFAKFwY+f8K
VIfa7c1GnXbWv3CMRozeqaSTI/ShbCOgrR27rLeEjn2seE63cWo7R5zjRF/XLGsI /B84xHsNsIROu3L0dS2grd8JVlC5giNnBEtlkHavIuA7g8r6PTtnrXIAGLs0oEq/
oT6kIx1Mj4h+jOXF79PsWHDEuM4gEi3iAMXqw6fTpOhMLUKhWL+d30Tm+AqO5BbQ ygchItRBw2DusEBmGYC6sqk27YanP+MWkVfB3o77zGexgUtPTPKOurSsS8uZZB3k
XVjsd7IW3rhhK1RfG8sHTebDz5tyJkjcFAauA4P0IJNZlUrs47XjupzxMShCV7XE UFBpW3s/5T0YfcYKDSSZ2EhcB919KerOPQ4yefNV2cRit3WZjH5kDubQKZUnDffR
ohIznCG9ods1S6ExEkbipXKtnngEgJFbuvlwlkEENVzmLVcPnQ26njAiMm0ECc9k BdaLJrHCKY0dS+WkiJkDyiXXu0DJuKeE8vmdIz8tFnY833QSDJfVu/fH9woISI5g
MDATBpxdnneEcA8CAwEAAaOB7zCB7DAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM 9JnvFdWatEaMK2MCAwEAAaOB7zCB7DAMBgNVHRMBAf8EAjAAMBYGA1UdJQEB/wQM
MAoGCCsGAQUFBwMIMB0GA1UdDgQWBBRWRawwlcW57baAiuBVmi0WFKIZqjAfBgNV MAoGCCsGAQUFBwMIMB0GA1UdDgQWBBTTuQ7LmtwtVydASwFBXd4xUIEh3jAfBgNV
HSMEGDAWgBROnw9rl/0Op/SoxQTubQfvoxosZjAtBgNVHR8EJjAkMCKgIKAehhxo HSMEGDAWgBQ/Lo89CPWO9O/WTHvV+3Dt/60o+TAtBgNVHR8EJjAkMCKgIKAehhxo
dHRwOi8vMTI3LjAuMC4xOjE5MjU0L1RTQUNBMFUGA1UdHgROMEygGDAKggh0ZXN0 dHRwOi8vMTI3LjAuMC4xOjE5MjU0L1RTQUNBMFUGA1UdHgROMEygGDAKggh0ZXN0
LmNvbTAKggh0ZXN0Lm9yZ6EwMAqHCAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAA LmNvbTAKggh0ZXN0Lm9yZ6EwMAqHCAAAAAAAAAAAMCKHIAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAMA0GCSqGSIb3DQEBCwUAA4IBAQCQbgXQtFr5lWjs AAAAAAAAAAAAAAAAAAAAAAAAMA0GCSqGSIb3DQEBCwUAA4IBAQBMiBltqGRRLmK9
tzlGJAuZfIq1f1arWWrJNSHrha9RUtm6uMoh2aMYByfEcopB9StqMo8QH4yS4LGZ 0RymCJ4oxmX2jwZ4SM7fem39Ozei7NIQIw5nlkPJ7ZWyfQQNFMIujfwJJGzDguax
/6B81EF+dugIIb9BrE00ASgXxZ6aGGAe79VwqdG8DXp+VgRbBQA87S2KeSN8wfm+ mMJHWngzbKjkbdSHnQswxT79RRwenlIKkExck6p2OUT82nGu/6TBIYutMJlITwKF
G2AGRZF0JWS4iW5kGgrqeC14IN1FajHklrh7rOIwo/h7uVIOINWtQnHyBjlCQ6N4 5OEmu+WneCvTkvEs0wussIug7E7dV6jJO9/TbwWyrtqU/t9GNRbu/4FIdQ9p9pK9
OTFFgtIOY5KXtYM1A+Gx2nt3uZnEh/U/ZxHslUb55O017Qfkbf11JXFil4+ZfqMx BcqaPmjn7IqnLs94THFfMFH0HVkqpLOfa9Wa8uc/C7WyIMTkchXb4U7/8B/hsDj7
QuRuwMAWlyEg+1UfNae4Sg3XqPheshBzZ7ykwKGZZPeA/8kKfbXoE6Kdy5HmT/El BfKwN/F+IMNw4Rfqytk2JSWuV4pr7MiBweLKBwGgt4DhvfZj32Y/WFNANxtYkE9e
8e7rP/mN 55mIPqG5
-----END CERTIFICATE----- -----END CERTIFICATE-----

Binary file not shown.

Binary file not shown.

View File

@ -1,46 +1,46 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIID7jCCAtagAwIBAgIULWwn/gLcPMAO/7oGqx5A306mxckwDQYJKoZIhvcNAQEL MIID7jCCAtagAwIBAgIUKiF/FG2pQjlbId3ox+nQHL/tJ4UwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0 CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMIGdMQswCQYDVQQG ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0zNDEyMzEwMDAwMDBaMIGdMQswCQYDVQQG
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3 EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEUMBIGA1UEAwwL MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEUMBIGA1UEAwwL
Q2VydGlmaWNhdGUxJzAlBgkqhkiG9w0BCQEWGG9zc2xzaWduY29kZUBleGFtcGxl Q2VydGlmaWNhdGUxJzAlBgkqhkiG9w0BCQEWGG9zc2xzaWduY29kZUBleGFtcGxl
LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL64qSULdxvTp7A4 LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMdBCaytt9xsrUx0
2dl/JbLq7GJ4ZcPbtfUyvVTB5WuntN08bpgnxljON0Ig9lFpN2OOlms/SnodlE6Z 2Fekq+IrsR2cC1pL9NANN3TbBv8RKt1IefMh8TjA1uPaOYZvz3o2ml9qKGmJ+uxH
O8GY8kYu/aK3zHIHp3EykzRP1glf7ukcCMpcSaS5VUho0QQ9PVvvMHVNtaQ00r2i kzLojKbg98bcmxBrkWemLQwmRv1hZIO8D4xiYRd0O0KZizrvwWwlNADzXXWw7iz+
34m8DbGj4aRUNI5eA6Xlzz8QnhvCgtRTVbp5ZRjxo1ZNq2eEZxa6UnFshlx6i0/o MPPWkXj2nT5MpOTi3S851SwOc/c9SYCazCP8rMGItKHLO7iCjK3sFwBDI9eaTd2N
kYPrdKTIvUv2zoRFd9H/7+B2Xwse+qppcZe0BiKSa4l6PrL2iHteYE29ggLLSqe+ EjqEHadIymHRizeTOaYv34FokQiRgR/zk4flT6+b6DQHxnlbIivV61OP4bBlFtXX
zavGN7Ev7jP+bZLU/5eq58SBy8uFBDkh1FvZEPAnJ2X/vwNzySi6KTliCPc9Jf5G jC4iGdHLIahhVMlw6ixGqR6910psIp0ST0KM8ly+N+1rPhoNkNSLqkzGUudKo7mV
wSJr+5MCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQUVeUILLpF5PWz5rAD t+Cp4EMCAwEAAaNiMGAwCQYDVR0TBAIwADAdBgNVHQ4EFgQU6a4Ta3t0UCTG04bC
iWzV/2oEP3UwHwYDVR0jBBgwFoAU4/q/jYQJtVH8CIsNnt/ZYq1hcgswEwYDVR0l WMCotMPLyWUwHwYDVR0jBBgwFoAUZBDxqzk33MH9ux3IP0FYd2In7ykwEwYDVR0l
BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAHckjLcj9mswr08aF7MV BAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQADggEBAN2Sad4rLRSKWmaRRUCn
EZTKKh0IOaHj7oh6vLR5Yg2n+E+9Gog/+ulbKXNe/5A9QU2R1NdwZKEeUeSuF4qW syRO45y7zzvCRApHVSoeBUmtHP+n/OZ3rJTixfluqiGFAqbaXgTN8IantyfqoTjV
P3JB79BepgR6/VYKyVWH7St4ixy1GtNEFrHWsID212Jd0Rr3+kc9OJUO0aw3nvg7 XgCP1qzSM3staLCkeAiZ0/OLW+hyHopP8aXX2ez/hMojB/J1b457+vkuudnNiLx8
Apsr1dztjwlUN2ugLzVoDJ2wMqlu5ZQW8pINIYet127cX5knW/acPCPcqPVD7jmm by44nonUnJb3zyxmCSxcBklNP1wlxYjbbq5hFJ/et2/Y5Ct6igYAEMsYZUEUq3e7
C40xgqeKD2a6OafSS5hjO4UeCoeHnXlJ4Sep8wz8VDlu39Hr4dwFm8v9MuvBusCr g2GWbqNN/i2tnJyGjDPrNRdOuODuclfIDnYSPn83a40XHn+Hgl9SmoXuSdDutAXC
/sdwzTRAc6mhBL/4PyJrBRhibbTxSaDKBHeWcKpmNp4DIk1vc8h6yhDUb1fgafgX b017GsOa7OV3ZPildcIa3d/yk4S3L56SdoY+Py4NIIDmxcjji1e91qCrrFfGYwmg
7nI= TkQ=
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL MIIDrDCCApSgAwIBAgIUcRGFYn4pUMRoDtFZhU1EOAPdiWwwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe AAOCAQ8AMIIBCgKCAQEA5yrw3i+fvxBSODvCoQb+9ibWRozmphJBp57tKv9ZraQ5
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co THK+PkCdjNiJuxZn8F1QLsjJo6JqrrXufYln7wixK0Seu4uV6I2TRzcRyJx29D89
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S 0G9GrTXKn7v8z32QAqCgtwSZ17uWYTFmRAYPllWXcWDONsVyw3UF2nClndL7GMqM
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc gDizlwsfg8HmRpZegn82I7Y2DXccm9a7pFHuBHpwenKqfBnMsXo3Jj4Xlr1cLTrh
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4 +6ksS5YogOsOd9b5Dfz6FaGmmwrlUWHwdi+EzdnSpOnXzmgflF23sZQ0ynsVvmpl
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB iD4rXBWnxnQ6Ken3wVPNrA/0ZYGbgSKrcv+/olkh5QIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBRkEPGrOTfcwf27Hcg/QVh3YifvKTAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ HSMEGDAWgBQaPEb++qXSgmAi2vsewtpb6SiIyDAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe KoZIhvcNAQELBQADggEBAL22kK3SDGnr3lhRE7ipptlKalrQKfpght0XEKm5hxCL
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc tougN2wtaTEWMwr2YfGJohcKBaGKQ+Bv6WY+EV+hJE4qEUFh6BGqRMtuZdiAbkG+
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD EveEMhZWQzgf9rUID+Y9Eg+NfCxlpkdQPjUxUV9OkGIshlxkUP8Y+C0h0xIcwq5v
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q hAfNiJAdcw4fUvtLkpEOFoOjThB8zxOu+Cl3xLCcNOMPLdSxd3YXjy6CMuuOk4RB
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/ gOc8YCyyEvwb9KmARZpMOcQJmucMhs+aC3DF+n71g+agFhDl3Z0QkyyyRjAcD04+
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE= sAR9C8PbqSCQAdydHbAFViEX6x3oGJ7L6zEDcIS10wg=
-----END CERTIFICATE----- -----END CERTIFICATE-----

Binary file not shown.

View File

@ -1,47 +1,47 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEPTCCAyWgAwIBAgIUZp72ahjzVryMA56ev7+Z8Rxyo2kwDQYJKoZIhvcNAQEL MIIEPTCCAyWgAwIBAgIUe8Im9GuMCHMi3/FDfLgzoE8vTKgwDQYJKoZIhvcNAQEL
BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0 CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0
ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMjQxMjMxMDAwMDAwWjCBqzEL ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMzQxMjMxMDAwMDAwWjCBqzEL
MAkGA1UEBhMCUEwxGTAXBgNVBAgMEE1hem92aWEgUHJvdmluY2UxDzANBgNVBAcM MAkGA1UEBhMCUEwxGTAXBgNVBAgMEE1hem92aWEgUHJvdmluY2UxDzANBgNVBAcM
BldhcnNhdzEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1AxIjAg BldhcnNhdzEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1AxIjAg
BgNVBAMMGUNlcnRpZmljYXRlIFg1MDl2MyBDUkwgRFAxJzAlBgkqhkiG9w0BCQEW BgNVBAMMGUNlcnRpZmljYXRlIFg1MDl2MyBDUkwgRFAxJzAlBgkqhkiG9w0BCQEW
GG9zc2xzaWduY29kZUBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP GG9zc2xzaWduY29kZUBleGFtcGxlLmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEP
ADCCAQoCggEBAL64qSULdxvTp7A42dl/JbLq7GJ4ZcPbtfUyvVTB5WuntN08bpgn ADCCAQoCggEBAMdBCaytt9xsrUx02Fekq+IrsR2cC1pL9NANN3TbBv8RKt1IefMh
xljON0Ig9lFpN2OOlms/SnodlE6ZO8GY8kYu/aK3zHIHp3EykzRP1glf7ukcCMpc 8TjA1uPaOYZvz3o2ml9qKGmJ+uxHkzLojKbg98bcmxBrkWemLQwmRv1hZIO8D4xi
SaS5VUho0QQ9PVvvMHVNtaQ00r2i34m8DbGj4aRUNI5eA6Xlzz8QnhvCgtRTVbp5 YRd0O0KZizrvwWwlNADzXXWw7iz+MPPWkXj2nT5MpOTi3S851SwOc/c9SYCazCP8
ZRjxo1ZNq2eEZxa6UnFshlx6i0/okYPrdKTIvUv2zoRFd9H/7+B2Xwse+qppcZe0 rMGItKHLO7iCjK3sFwBDI9eaTd2NEjqEHadIymHRizeTOaYv34FokQiRgR/zk4fl
BiKSa4l6PrL2iHteYE29ggLLSqe+zavGN7Ev7jP+bZLU/5eq58SBy8uFBDkh1FvZ T6+b6DQHxnlbIivV61OP4bBlFtXXjC4iGdHLIahhVMlw6ixGqR6910psIp0ST0KM
EPAnJ2X/vwNzySi6KTliCPc9Jf5GwSJr+5MCAwEAAaOBmzCBmDAJBgNVHRMEAjAA 8ly+N+1rPhoNkNSLqkzGUudKo7mVt+Cp4EMCAwEAAaOBmzCBmDAJBgNVHRMEAjAA
MB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJbNX/agQ/dTAfBgNVHSMEGDAWgBRhu0A6 MB0GA1UdDgQWBBTprhNre3RQJMbThsJYwKi0w8vJZTAfBgNVHSMEGDAWgBQUPGKp
SceOaK7eXw40BRjfzuQWLzATBgNVHSUEDDAKBggrBgEFBQcDAzA2BgNVHR8ELzAt 4nGIluZnh6sofSkEiGrtIzATBgNVHSUEDDAKBggrBgEFBQcDAzA2BgNVHR8ELzAt
MCugKaAnhiVodHRwOi8vMTI3LjAuMC4xOjE5MjU0L2ludGVybWVkaWF0ZUNBMA0G MCugKaAnhiVodHRwOi8vMTI3LjAuMC4xOjE5MjU0L2ludGVybWVkaWF0ZUNBMA0G
CSqGSIb3DQEBCwUAA4IBAQC2yNGXw1VZqBWY7cnJtiZpupKYCifRC1dEFlKcozpd CSqGSIb3DQEBCwUAA4IBAQBlJrcOaJQQ3TuYaVtmH8VbCdF3GQE+255g0Kq4sWoO
dhWHDKpGDCzqaL/WKpqFjOIrCbG6gsfB+nu2VQv4nE8lwwelMgpeVB+v197A1SvE ZgZm6LmRkchuoOXqeZ7aAV6HnGGpZf64ShPSZ3KPt4/UVYkRyS0UihN2ACsGrS4o
wLl71R5a7sxF0x5aBdUyWeCTeBLu6KuWQrpPcZVM3uMqhqCJ8CiSUtS1cKn1K1K0 ZjOaaoM2xDxttngKV3lAF4xbx18RvAsx9QIzQhzowaSUBQNuu5W4tne/6h7htuwA
KRSgFTs4AFUc0rOa3wYvytps4cw/TyDXArlvGVMlDHNLffEsx3vElZafaGvyEK0J KNc0go4fqpCqQjNRVeB1IN50BzUrlHu3zQzfH0LDyUTt2gnObLHMl566Ft0azAG9
TsBM2dakcpP/ceuJU1gd8hLadzjfKOFml7z+qHfUa/mky+veK2M5vKn1ph55qYHc emHRM+BOUjKY3ZTjM+JEzpwWgse6e4r+J2fYVYIEtkSfm4ZZnAs5WFWI5o8tqr4b
WtEY/wwBjgqE2VseqMLb06J3tXmTKgESGXISAnqoau+t ruBN7l6oP6R3ugOtPk7tW4x7OO0QoDnfa418MkBlXeqL
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL MIIDszCCApugAwIBAgIUN3RBnJCUJ8HmbeNjJZ/6jsXJLGEwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j hvcNAQEBBQADggEPADCCAQoCggEBAME32IBpxW4FhVuZe1PTarEskVHP233QjZtx
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4 poC67/lUK44gtFmsxYsMrDYmmny5pfoM/Byxl5/rorEddLqtDe1kd1SpXUvEYxox
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe s5rizRd5sZPgkwNoJkSVyNZFwj7gKZHeg6IQHSxNgmTybZ+eZqiNvEveksj3lGpM
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp Xrbiew7cXUyIP636GPtYxLyIbwDVP0jScqcA/dmSAqofFVUi0SW3OS1hpyXAmmx8
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO hQHJRKPjPgitZVgjwf5X8/eMTa+ca9dRlRFLk7AcbkF6NcbLm+cRo816nO0EBFV4
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw Sn2dW9uYqJIfZcpRQ7wbv4fUCghwrk9h3gXrb7AweyK8nyYlmosCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUFDxiqeJxiJbmZ4erKH0pBIhq
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD 7SMwHwYDVR0jBBgwFoAUGjxG/vql0oJgItr7HsLaW+koiMgwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAlI/1XnGc9WzL53rRascZc1EgWAnej9YFS
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB Dax5+nozYTihC8BRxGfSh1FGRVsmFWhZ0z0XogJJC2bZrQ/36+vwoILItcsWHrQr
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA rFoZa6s1Uo7ZCd9SfmXjbhMLQgydocCh9YIF66CAkQLwRXc1QIpF7nuZ+rxk0ru1
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK uGjjBrFRfdSdzlFnyK6wfFzi6LtYDVgVEHC7zzL9E/cyuGo7qQ++SoOg99HjTVY1
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d PS3ea522bRO2bJpYwZJvvbg020DAfm686VXwAadODdBkI2h6U5SwTxp4SkSmq9SI
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF mjtERFtnAKD0R2YrX4RzuIckezvwsqLDkQjMnI9XQmv5HWUZimcC
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

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

View File

@ -1,45 +1,45 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIID6jCCAtKgAwIBAgIUW4SefwoiLUfTBaHpZyd8knsGVBswDQYJKoZIhvcNAQEL MIID6jCCAtKgAwIBAgIUcgUgRT1Lx8XLdgp7xcWxVl9YBjYwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0 CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0xOTAxMDEwMDAwMDBaMIGZMQswCQYDVQQG ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0xOTAxMDEwMDAwMDBaMIGZMQswCQYDVQQG
EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3 EwJQTDEZMBcGA1UECAwQTWF6b3ZpYSBQcm92aW5jZTEPMA0GA1UEBwwGV2Fyc2F3
MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UEAwwH MRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UEAwwH
RXhwaXJlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUuY29t RXhwaXJlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUuY29t
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ2X8l MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0EJrK233GytTHTYV6Sr
sursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7wZjy 4iuxHZwLWkv00A03dNsG/xEq3Uh58yHxOMDW49o5hm/PejaaX2ooaYn67EeTMuiM
Ri79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLfibwN puD3xtybEGuRZ6YtDCZG/WFkg7wPjGJhF3Q7QpmLOu/BbCU0APNddbDuLP4w89aR
saPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0 ePadPkyk5OLdLznVLA5z9z1JgJrMI/yswYi0ocs7uIKMrewXAEMj15pN3Y0SOoQd
pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77Nq8Y3 p0jKYdGLN5M5pi/fgWiRCJGBH/OTh+VPr5voNAfGeVsiK9XrU4/hsGUW1deMLiIZ
sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbBImv7 0cshqGFUyXDqLEapHr3XSmwinRJPQozyXL437Ws+Gg2Q1IuqTMZS50qjuZW34Kng
kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJbNX/ QwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBTprhNre3RQJMbThsJYwKi0
agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUEDDAK w8vJZTAfBgNVHSMEGDAWgBRkEPGrOTfcwf27Hcg/QVh3YifvKTATBgNVHSUEDDAK
BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAp06uHnxO63Ecn+knaXkfrNGg BggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEA0AxgPkboWfIOMYFOP6kQ4nxY
pr+4WCc0onXYOE37+IwsCFaUqCIr1UsnnKWSzSlSR07FHI+VaV9r3knT6VPMVsUU jQ+kAH842ALjm/5z20fYPS0k3LiCNS0FfBPzygeWQLwDGcH2QX6Lfec62CeIe9R9
L89jHC2vLUvyJJOtuTpuOVGIzzCquYWvYRZrp2wmTceMSNhLcO1VGs28uwQojWEQ IAdsX+nNxn9FeIZssfMK3EPgksGUybUNub78mXPrnhCNjYf/GmDY/Cf7jhBtNphK
ZsEdFvkYeWFInUQ1mF0dLnfQjh7RcTxMJ0CxZblJ086j3AbyzM6ZF6XAVPAqBH/S 6zCPOC0WDrupnLW7r4FyrB1j2CEgaHhiSmlQ+19rqbvcNfaCOMfe7IfiwkvVIzE6
gsBfLVGnZnMOwvKwsxViG1ikRusO6GtcIy6yxmNCUhWbIL+R59EYy++x3xLVUU90 tQhnudB/HnW3+pWT83n/KQk0F8lu00fahkak/0bPidTe4zOvepabiWYQXKJ9ZXhm
YnScDN+xM9A2wHO1hQpLK6DIiHpbAzAgll5xD0JWh+efRWHEtGN5JTybowG9yA== UW7FHHSM5Vbn2A6zyEht7rcK/gkpHbkckoIi6bDMFMp+K9o3qV7PzZPkaau7fg==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL MIIDrDCCApSgAwIBAgIUcRGFYn4pUMRoDtFZhU1EOAPdiWwwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe AAOCAQ8AMIIBCgKCAQEA5yrw3i+fvxBSODvCoQb+9ibWRozmphJBp57tKv9ZraQ5
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co THK+PkCdjNiJuxZn8F1QLsjJo6JqrrXufYln7wixK0Seu4uV6I2TRzcRyJx29D89
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S 0G9GrTXKn7v8z32QAqCgtwSZ17uWYTFmRAYPllWXcWDONsVyw3UF2nClndL7GMqM
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc gDizlwsfg8HmRpZegn82I7Y2DXccm9a7pFHuBHpwenKqfBnMsXo3Jj4Xlr1cLTrh
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4 +6ksS5YogOsOd9b5Dfz6FaGmmwrlUWHwdi+EzdnSpOnXzmgflF23sZQ0ynsVvmpl
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB iD4rXBWnxnQ6Ken3wVPNrA/0ZYGbgSKrcv+/olkh5QIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBRkEPGrOTfcwf27Hcg/QVh3YifvKTAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ HSMEGDAWgBQaPEb++qXSgmAi2vsewtpb6SiIyDAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe KoZIhvcNAQELBQADggEBAL22kK3SDGnr3lhRE7ipptlKalrQKfpght0XEKm5hxCL
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc tougN2wtaTEWMwr2YfGJohcKBaGKQ+Bv6WY+EV+hJE4qEUFh6BGqRMtuZdiAbkG+
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD EveEMhZWQzgf9rUID+Y9Eg+NfCxlpkdQPjUxUV9OkGIshlxkUP8Y+C0h0xIcwq5v
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q hAfNiJAdcw4fUvtLkpEOFoOjThB8zxOu+Cl3xLCcNOMPLdSxd3YXjy6CMuuOk4RB
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/ gOc8YCyyEvwb9KmARZpMOcQJmucMhs+aC3DF+n71g+agFhDl3Z0QkyyyRjAcD04+
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE= sAR9C8PbqSCQAdydHbAFViEX6x3oGJ7L6zEDcIS10wg=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,22 +1,22 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL MIIDrDCCApSgAwIBAgIUcRGFYn4pUMRoDtFZhU1EOAPdiWwwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe AAOCAQ8AMIIBCgKCAQEA5yrw3i+fvxBSODvCoQb+9ibWRozmphJBp57tKv9ZraQ5
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co THK+PkCdjNiJuxZn8F1QLsjJo6JqrrXufYln7wixK0Seu4uV6I2TRzcRyJx29D89
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S 0G9GrTXKn7v8z32QAqCgtwSZ17uWYTFmRAYPllWXcWDONsVyw3UF2nClndL7GMqM
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc gDizlwsfg8HmRpZegn82I7Y2DXccm9a7pFHuBHpwenKqfBnMsXo3Jj4Xlr1cLTrh
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4 +6ksS5YogOsOd9b5Dfz6FaGmmwrlUWHwdi+EzdnSpOnXzmgflF23sZQ0ynsVvmpl
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB iD4rXBWnxnQ6Ken3wVPNrA/0ZYGbgSKrcv+/olkh5QIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBRkEPGrOTfcwf27Hcg/QVh3YifvKTAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ HSMEGDAWgBQaPEb++qXSgmAi2vsewtpb6SiIyDAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe KoZIhvcNAQELBQADggEBAL22kK3SDGnr3lhRE7ipptlKalrQKfpght0XEKm5hxCL
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc tougN2wtaTEWMwr2YfGJohcKBaGKQ+Bv6WY+EV+hJE4qEUFh6BGqRMtuZdiAbkG+
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD EveEMhZWQzgf9rUID+Y9Eg+NfCxlpkdQPjUxUV9OkGIshlxkUP8Y+C0h0xIcwq5v
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q hAfNiJAdcw4fUvtLkpEOFoOjThB8zxOu+Cl3xLCcNOMPLdSxd3YXjy6CMuuOk4RB
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/ gOc8YCyyEvwb9KmARZpMOcQJmucMhs+aC3DF+n71g+agFhDl3Z0QkyyyRjAcD04+
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE= sAR9C8PbqSCQAdydHbAFViEX6x3oGJ7L6zEDcIS10wg=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,22 +1,22 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL MIIDszCCApugAwIBAgIUN3RBnJCUJ8HmbeNjJZ/6jsXJLGEwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j hvcNAQEBBQADggEPADCCAQoCggEBAME32IBpxW4FhVuZe1PTarEskVHP233QjZtx
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4 poC67/lUK44gtFmsxYsMrDYmmny5pfoM/Byxl5/rorEddLqtDe1kd1SpXUvEYxox
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe s5rizRd5sZPgkwNoJkSVyNZFwj7gKZHeg6IQHSxNgmTybZ+eZqiNvEveksj3lGpM
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp Xrbiew7cXUyIP636GPtYxLyIbwDVP0jScqcA/dmSAqofFVUi0SW3OS1hpyXAmmx8
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO hQHJRKPjPgitZVgjwf5X8/eMTa+ca9dRlRFLk7AcbkF6NcbLm+cRo816nO0EBFV4
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw Sn2dW9uYqJIfZcpRQ7wbv4fUCghwrk9h3gXrb7AweyK8nyYlmosCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUFDxiqeJxiJbmZ4erKH0pBIhq
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD 7SMwHwYDVR0jBBgwFoAUGjxG/vql0oJgItr7HsLaW+koiMgwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAlI/1XnGc9WzL53rRascZc1EgWAnej9YFS
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB Dax5+nozYTihC8BRxGfSh1FGRVsmFWhZ0z0XogJJC2bZrQ/36+vwoILItcsWHrQr
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA rFoZa6s1Uo7ZCd9SfmXjbhMLQgydocCh9YIF66CAkQLwRXc1QIpF7nuZ+rxk0ru1
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK uGjjBrFRfdSdzlFnyK6wfFzi6LtYDVgVEHC7zzL9E/cyuGo7qQ++SoOg99HjTVY1
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d PS3ea522bRO2bJpYwZJvvbg020DAfm686VXwAadODdBkI2h6U5SwTxp4SkSmq9SI
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF mjtERFtnAKD0R2YrX4RzuIckezvwsqLDkQjMnI9XQmv5HWUZimcC
-----END CERTIFICATE----- -----END CERTIFICATE-----

Binary file not shown.

View File

@ -1,27 +1,28 @@
-----BEGIN RSA PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
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
-----END RSA PRIVATE KEY----- GlIpzzm+MYzra4yB4VpRw5ES
-----END PRIVATE KEY-----

Binary file not shown.

View File

@ -1,30 +1,30 @@
-----BEGIN RSA PRIVATE KEY----- -----BEGIN ENCRYPTED PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED MIIFHDBOBgkqhkiG9w0BBQ0wQTApBgkqhkiG9w0BBQwwHAQIY7PpABd5xsYCAggA
DEK-Info: DES-EDE3-CBC,B9C24663685D6009 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 XwiQ2Rt3JBHrzPy9wXL8hw==
-----END RSA PRIVATE KEY----- -----END ENCRYPTED PRIVATE KEY-----

Binary file not shown.

View File

@ -1,45 +1,45 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDvTCCAqWgAwIBAgIUSXAaPeUatfheDTFo77LnMBHgyeMwDQYJKoZIhvcNAQEL MIIDvTCCAqWgAwIBAgIUazbrVgbYb+IN803UmJJa0DPHQsAwDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0 CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0ludGVybWVkaWF0
ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0yNDEyMzEwMDAwMDBaMG0xCzAJBgNVBAYT ZSBDQTAeFw0xODAxMDEwMDAwMDBaFw0zNDEyMzEwMDAwMDBaMG0xCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UE AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxDDAKBgNVBAsMA0NTUDEQMA4GA1UE
AwwHUmV2b2tlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUu AwwHUmV2b2tlZDEnMCUGCSqGSIb3DQEJARYYb3NzbHNpZ25jb2RlQGV4YW1wbGUu
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvripJQt3G9OnsDjZ Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx0EJrK233GytTHTY
2X8lsursYnhlw9u19TK9VMHla6e03TxumCfGWM43QiD2UWk3Y46Waz9Keh2UTpk7 V6Sr4iuxHZwLWkv00A03dNsG/xEq3Uh58yHxOMDW49o5hm/PejaaX2ooaYn67EeT
wZjyRi79orfMcgencTKTNE/WCV/u6RwIylxJpLlVSGjRBD09W+8wdU21pDTSvaLf MuiMpuD3xtybEGuRZ6YtDCZG/WFkg7wPjGJhF3Q7QpmLOu/BbCU0APNddbDuLP4w
ibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNVunllGPGjVk2rZ4RnFrpScWyGXHqLT+iR 89aRePadPkyk5OLdLznVLA5z9z1JgJrMI/yswYi0ocs7uIKMrewXAEMj15pN3Y0S
g+t0pMi9S/bOhEV30f/v4HZfCx76qmlxl7QGIpJriXo+svaIe15gTb2CAstKp77N OoQdp0jKYdGLN5M5pi/fgWiRCJGBH/OTh+VPr5voNAfGeVsiK9XrU4/hsGUW1deM
q8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ8CcnZf+/A3PJKLopOWII9z0l/kbB LiIZ0cshqGFUyXDqLEapHr3XSmwinRJPQozyXL437Ws+Gg2Q1IuqTMZS50qjuZW3
Imv7kwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBRV5QgsukXk9bPmsAOJ 4KngQwIDAQABo2IwYDAJBgNVHRMEAjAAMB0GA1UdDgQWBBTprhNre3RQJMbThsJY
bNX/agQ/dTAfBgNVHSMEGDAWgBTj+r+NhAm1UfwIiw2e39lirWFyCzATBgNVHSUE wKi0w8vJZTAfBgNVHSMEGDAWgBRkEPGrOTfcwf27Hcg/QVh3YifvKTATBgNVHSUE
DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAK/bCZPrxN+5HGQjZLIQg DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAFJjwxpYA2jzrmF1mdKx/
jKfjTRL5xwBGs8+VW4i+xnaA14pyZjDlYzASmCE/ZiryVSMJ7fuQ0TVXGtz3N7PM up8gl6iISsHDc7oLAv63oUYXpFwzpNfvi1TGqYVhntAH2t/1XdA1HKdBp2LDsEnt
v9pRgtcohs62NJZ5dIrq4f/Op1bii29pAA8+2EHPJUyFBt23vyvlI/dBpkgQG6mi Av66c6HxyNPka26ZGD70+w5q8uHrIOO6MZw0eaLwu9bJI4cLbRXlKwxkGSzXHGYs
OUEsXQ+Q2LUD4OOJffkc/gowXcB4WFjrtFAUuu9HeZUNzV5Mm5FQTGm9nCnWsDIb 1hGR2YwAiMrqtVMPetlpd62y6qUZc0lEOhjJ6DsIfqSgO8AsdyI7Ao+cDqEZ1I/Q
b7Yx08hMy+6jtvkNPCDcFnos2bsipmVN4fCXkm5LPZNyMFoWReDbIKWASXaao2hN Oi1Agn8kz8TtfWKxkX06EoL4DrZCDb1/w0CGQJATq77pKst+zw+B+2EKqlpuG3s/
gzWhwWsPlAGAlBPMVWEo3k2Cz/entbAijoyqS2koN4mZABy7m5+vfzFw/yvh1/lu FE7RkCjG7bEFIDEK2909BXQNyQJzp7ih9X8QeEx5fnPr9lDfe/75YjRqoHkfmcTC
8w== Hw==
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDrDCCApSgAwIBAgIUXhcDbb/3vPpWoFCmesKw0dazbzIwDQYJKoZIhvcNAQEL MIIDrDCCApSgAwIBAgIUcRGFYn4pUMRoDtFZhU1EOAPdiWwwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBgMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF cml0eTEYMBYGA1UEAwwPSW50ZXJtZWRpYXRlIENBMIIBIjANBgkqhkiG9w0BAQEF
AAOCAQ8AMIIBCgKCAQEA3FMSnznxLiZh2qZ2M4/Y3FcqzNy9XxE1DG5ahUoRifCe AAOCAQ8AMIIBCgKCAQEA5yrw3i+fvxBSODvCoQb+9ibWRozmphJBp57tKv9ZraQ5
LWPGvREPG599ds55MesKqAPo1xAyd7hpQmd+IWzQhvDQntR4BkCQv6PoHQ2WO9co THK+PkCdjNiJuxZn8F1QLsjJo6JqrrXufYln7wixK0Seu4uV6I2TRzcRyJx29D89
CfQ59U5h4pie82IROPHMg31PNYF7MVt2cjBtQco2wvL7XLroYo5nmi20qvsNh53S 0G9GrTXKn7v8z32QAqCgtwSZ17uWYTFmRAYPllWXcWDONsVyw3UF2nClndL7GMqM
nJ0vGsIhdBd5UVn7S5NghHYF03cmFiZVuSvN3ovFl1k0iIH+eJdfYXBiTqtcUCAc gDizlwsfg8HmRpZegn82I7Y2DXccm9a7pFHuBHpwenKqfBnMsXo3Jj4Xlr1cLTrh
0+ngTui3LWd18QB6M6HYdT1a0MihGs1g0RE7ni2C5iwBn4FOe+eHzZOq5AcWVGR4 +6ksS5YogOsOd9b5Dfz6FaGmmwrlUWHwdi+EzdnSpOnXzmgflF23sZQ0ynsVvmpl
ZSvDc+6O22sy0esBYsPElJBnQLOPyIRwd4B8MO6PewIDAQABo2YwZDASBgNVHRMB iD4rXBWnxnQ6Ken3wVPNrA/0ZYGbgSKrcv+/olkh5QIDAQABo2YwZDASBgNVHRMB
Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBTj+r+NhAm1UfwIiw2e39lirWFyCzAfBgNV Af8ECDAGAQH/AgEAMB0GA1UdDgQWBBRkEPGrOTfcwf27Hcg/QVh3YifvKTAfBgNV
HSMEGDAWgBRYinOUkj6959wnBw0YfDBGaz/adzAOBgNVHQ8BAf8EBAMCAYYwDQYJ HSMEGDAWgBQaPEb++qXSgmAi2vsewtpb6SiIyDAOBgNVHQ8BAf8EBAMCAYYwDQYJ
KoZIhvcNAQELBQADggEBACn3BOVCATol6TC31cKPvh9hOOq9uvgREGG1paTmZNhe KoZIhvcNAQELBQADggEBAL22kK3SDGnr3lhRE7ipptlKalrQKfpght0XEKm5hxCL
JsrIUkD2KZN7dpAJEJF7uu2LaCm0F5VqQUj3SdYHD3neHiOeO8jzgM4BWgqZ3lZc tougN2wtaTEWMwr2YfGJohcKBaGKQ+Bv6WY+EV+hJE4qEUFh6BGqRMtuZdiAbkG+
FQfGbNoR4QQMADMJYKJ/LCRjBKUrHDvkvuQHkb+y8yUg1UtNpeH3cFty2/eo7VWD EveEMhZWQzgf9rUID+Y9Eg+NfCxlpkdQPjUxUV9OkGIshlxkUP8Y+C0h0xIcwq5v
Su5Jd1vVIo4XkQDBPr5UR9LVSMfhvhX4pcvijmETTEYn3ZZ2KeF1q5JC1Le+322Q hAfNiJAdcw4fUvtLkpEOFoOjThB8zxOu+Cl3xLCcNOMPLdSxd3YXjy6CMuuOk4RB
xwgVhiJak3GUh06mYQf6qFSRanu78Jeyw8IlsS+o8V9W+dqYYDOENDYNJGB5MaS/ gOc8YCyyEvwb9KmARZpMOcQJmucMhs+aC3DF+n71g+agFhDl3Z0QkyyyRjAcD04+
yAA20r1RAb2RmPPbpiPjR2FKzNDxu7nHd4EecbSevdE= sAR9C8PbqSCQAdydHbAFViEX6x3oGJ7L6zEDcIS10wg=
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,46 +1,46 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIEDDCCAvSgAwIBAgIUMXc8FF4DEhJ/0czsG3SrcZS4GCYwDQYJKoZIhvcNAQEL MIIEDDCCAvSgAwIBAgIUHGb2CHtm9Ra3gCn6Iv7hpEhiQrYwDQYJKoZIhvcNAQEL
BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwZzELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0 CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNVBAMMFkludGVybWVkaWF0
ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMjQxMjMxMDAwMDAwWjB7MQsw ZSBDQSBDUkwgRFAwHhcNMTgwMTAxMDAwMDAwWhcNMzQxMjMxMDAwMDAwWjB7MQsw
CQYDVQQGEwJQTDEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1Ax CQYDVQQGEwJQTDEVMBMGA1UECgwMb3NzbHNpZ25jb2RlMQwwCgYDVQQLDANDU1Ax
HjAcBgNVBAMMFVJldm9rZWQgWDUwOXYzIENSTCBEUDEnMCUGCSqGSIb3DQEJARYY HjAcBgNVBAMMFVJldm9rZWQgWDUwOXYzIENSTCBEUDEnMCUGCSqGSIb3DQEJARYY
b3NzbHNpZ25jb2RlQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A b3NzbHNpZ25jb2RlQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAvripJQt3G9OnsDjZ2X8lsursYnhlw9u19TK9VMHla6e03TxumCfG MIIBCgKCAQEAx0EJrK233GytTHTYV6Sr4iuxHZwLWkv00A03dNsG/xEq3Uh58yHx
WM43QiD2UWk3Y46Waz9Keh2UTpk7wZjyRi79orfMcgencTKTNE/WCV/u6RwIylxJ OMDW49o5hm/PejaaX2ooaYn67EeTMuiMpuD3xtybEGuRZ6YtDCZG/WFkg7wPjGJh
pLlVSGjRBD09W+8wdU21pDTSvaLfibwNsaPhpFQ0jl4DpeXPPxCeG8KC1FNVunll F3Q7QpmLOu/BbCU0APNddbDuLP4w89aRePadPkyk5OLdLznVLA5z9z1JgJrMI/ys
GPGjVk2rZ4RnFrpScWyGXHqLT+iRg+t0pMi9S/bOhEV30f/v4HZfCx76qmlxl7QG wYi0ocs7uIKMrewXAEMj15pN3Y0SOoQdp0jKYdGLN5M5pi/fgWiRCJGBH/OTh+VP
IpJriXo+svaIe15gTb2CAstKp77Nq8Y3sS/uM/5tktT/l6rnxIHLy4UEOSHUW9kQ r5voNAfGeVsiK9XrU4/hsGUW1deMLiIZ0cshqGFUyXDqLEapHr3XSmwinRJPQozy
8CcnZf+/A3PJKLopOWII9z0l/kbBImv7kwIDAQABo4GbMIGYMAkGA1UdEwQCMAAw XL437Ws+Gg2Q1IuqTMZS50qjuZW34KngQwIDAQABo4GbMIGYMAkGA1UdEwQCMAAw
HQYDVR0OBBYEFFXlCCy6ReT1s+awA4ls1f9qBD91MB8GA1UdIwQYMBaAFGG7QDpJ HQYDVR0OBBYEFOmuE2t7dFAkxtOGwljAqLTDy8llMB8GA1UdIwQYMBaAFBQ8Yqni
x45ort5fDjQFGN/O5BYvMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDYGA1UdHwQvMC0w cYiW5meHqyh9KQSIau0jMBMGA1UdJQQMMAoGCCsGAQUFBwMDMDYGA1UdHwQvMC0w
K6ApoCeGJWh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvaW50ZXJtZWRpYXRlQ0EwDQYJ K6ApoCeGJWh0dHA6Ly8xMjcuMC4wLjE6MTkyNTQvaW50ZXJtZWRpYXRlQ0EwDQYJ
KoZIhvcNAQELBQADggEBALwDivFFBjB7AkLO1jPJFyJnq8C0gadoYq0Dq5roAFMq KoZIhvcNAQELBQADggEBAJ5WxnDiAiRPr7EvTRD7iaxixAY/2wgASXWekQLpvJ8Y
Lirl0LGsdFTrZ2ljKOzNrFVfw4EQHedDCsKCtsgOXG1xxLQczwsuBcIaWGzSdW15 /ehaVdZWE8ft76y73F4NC62JfjWgAZHE+we3LSO+eB5kznM+Ctzrf/brR1MorSOu
iNz+IKjHXSNOLEUvVcO6N6s1rt5U15lynaXFSdskBgJYA7vq6uA8RTWzhQC7aCv8 iq78uz2pjwmQBpby6uDMii9r1txR62GYiLrZJizE+13AOVKBo5EW0PuwX3wKjk+s
n3Tbpe8c7j6/y5NThffBu/YZypMoraZvPohCDfMZoFNT5GYXNWSeq7gipxtaCHcK Z5Mp9y7+GVzCSXwJC4wNMw/ZJZgr+o5D8msMh3UPgxUfT1rZ7THW3IwXao3ZtTXw
OdWBi5yajIZL05hg29y7r677KBbvo07EykhxQ10zEnskzuqc7hCCsuDrXbmt5brv EA6uJoLVNb8FLfAVA1CFL0MlPgyiM2iNs+jIuhF7hPmMc8Je2qAr97ADdLCHWnRv
REYpeGvJAu0YrFg9yLSl8FJwk/XUzGvxa2MLPyL/sj4= Majsbns7OCCFROF2qSQiyzVO5Hn1kiPSP7qmLMak610=
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDszCCApugAwIBAgIUdUqeYLe6em9A4BIXcQhE2lS8KTUwDQYJKoZIhvcNAQEL MIIDszCCApugAwIBAgIUN3RBnJCUJ8HmbeNjJZ/6jsXJLGEwDQYJKoZIhvcNAQEL
BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE BQAwWDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEgMB4GA1UE
CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN CwwXQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxEDAOBgNVBAMMB1Jvb3QgQ0EwHhcN
MTgwMTAxMDAwMDAwWhcNMjYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG MTgwMTAxMDAwMDAwWhcNMzYwMTAxMDAwMDAwWjBnMQswCQYDVQQGEwJQTDEVMBMG
A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv A1UECgwMb3NzbHNpZ25jb2RlMSAwHgYDVQQLDBdDZXJ0aWZpY2F0aW9uIEF1dGhv
cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI cml0eTEfMB0GA1UEAwwWSW50ZXJtZWRpYXRlIENBIENSTCBEUDCCASIwDQYJKoZI
hvcNAQEBBQADggEPADCCAQoCggEBANoHRxZ1qxQKLm8MLYswvTf9FBq05unFxE9j hvcNAQEBBQADggEPADCCAQoCggEBAME32IBpxW4FhVuZe1PTarEskVHP233QjZtx
nea4njWqBkg3cT/jZo2sDHlkN+q3BFEL/K+mej0/LqfW6eXrskHj6OLyXas2/HR4 poC67/lUK44gtFmsxYsMrDYmmny5pfoM/Byxl5/rorEddLqtDe1kd1SpXUvEYxox
UYsby8djwazvt4LLiMS5yfo3GlRv5p44F1ruYu7/km7J/6pUxQMB+lTXKA4TzUWe s5rizRd5sZPgkwNoJkSVyNZFwj7gKZHeg6IQHSxNgmTybZ+eZqiNvEveksj3lGpM
n/xa2xGm0ZDXvQC1GlPJ1mD/fm0JeS6g8iMdTfvKPKKFMArz+wGWBiqbAKnmuDfp Xrbiew7cXUyIP636GPtYxLyIbwDVP0jScqcA/dmSAqofFVUi0SW3OS1hpyXAmmx8
J3j64nWyRCArH+tGgvOmqkXAUBh9A0T1AfdF1Q5kFKzFq38zKI6lPELo0qEio9SO hQHJRKPjPgitZVgjwf5X8/eMTa+ca9dRlRFLk7AcbkF6NcbLm+cRo816nO0EBFV4
W+aOVVDtknTXmqKtawFyhn2e3UEzISYmFv2Wfc/dLnmBzRLNR9cCAwEAAaNmMGQw Sn2dW9uYqJIfZcpRQ7wbv4fUCghwrk9h3gXrb7AweyK8nyYlmosCAwEAAaNmMGQw
EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUYbtAOknHjmiu3l8ONAUY387k EgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUFDxiqeJxiJbmZ4erKH0pBIhq
Fi8wHwYDVR0jBBgwFoAUWIpzlJI+vefcJwcNGHwwRms/2ncwDgYDVR0PAQH/BAQD 7SMwHwYDVR0jBBgwFoAUGjxG/vql0oJgItr7HsLaW+koiMgwDgYDVR0PAQH/BAQD
AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQBJ69rsOHP4qKnu/wRS/D3fV/voLHB624Rg AgGGMA0GCSqGSIb3DQEBCwUAA4IBAQAlI/1XnGc9WzL53rRascZc1EgWAnej9YFS
RpC4RshZMPVL60LaouJo1GMHj3IwyHVHGFkTxGYP0IIgcMUCnkmpSfX1tahYU+kB Dax5+nozYTihC8BRxGfSh1FGRVsmFWhZ0z0XogJJC2bZrQ/36+vwoILItcsWHrQr
4fSCxheLg79g2y3Z1jTQxFOvRjn5t4BIk4Rq4o9E7n1x+8jcaCBSjmna9j6i5lgA rFoZa6s1Uo7ZCd9SfmXjbhMLQgydocCh9YIF66CAkQLwRXc1QIpF7nuZ+rxk0ru1
QjazvdXrhhgrkvvMtk2wtk1laiHUHFgb9zxzNhhZFzy+QXwQv+Zj1N0swKfTP2gK uGjjBrFRfdSdzlFnyK6wfFzi6LtYDVgVEHC7zzL9E/cyuGo7qQ++SoOg99HjTVY1
Rxls7e47SnMdvthINZpdvUwT5pBZnMKHqgQK6YbWcopBpuw7zOTJp6Ghqzqzwa4d PS3ea522bRO2bJpYwZJvvbg020DAfm686VXwAadODdBkI2h6U5SwTxp4SkSmq9SI
CwUtEB7f0e7dWeG7DFJ2cNPcpXaigNtvfdRR3W1RduX9FCODihFF mjtERFtnAKD0R2YrX4RzuIckezvwsqLDkQjMnI9XQmv5HWUZimcC
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1,47 +1,47 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
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
JVHLUWz0r6IIp0mHrMwoI94yZBVXje0= hpE0ajpKT0x/dNa/qCwl/9zc8XxGnPk=
-----END CERTIFICATE----- -----END CERTIFICATE-----
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIIDkDCCAnigAwIBAgIUf2df9lAckuBxsAT7UktJTpH8H3EwDQYJKoZIhvcNAQEL MIIDkDCCAnigAwIBAgIULFuB5HWsyba6VHu2Ygv2vt4R4/swDQYJKoZIhvcNAQEL
BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE BQAwYDELMAkGA1UEBhMCUEwxFTATBgNVBAoMDG9zc2xzaWduY29kZTEkMCIGA1UE
CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v CwwbVGltZXN0YW1wIEF1dGhvcml0eSBSb290IENBMRQwEgYDVQQDDAtUU0EgUm9v
dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0yNjExMTAwMDAwMDBaMGAxCzAJBgNVBAYT dCBDQTAeFw0xNzAxMDEwMDAwMDBaFw0zNjEyMjcwMDAwMDBaMGAxCzAJBgNVBAYT
AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB AlBMMRUwEwYDVQQKDAxvc3Nsc2lnbmNvZGUxJDAiBgNVBAsMG1RpbWVzdGFtcCBB
dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG dXRob3JpdHkgUm9vdCBDQTEUMBIGA1UEAwwLVFNBIFJvb3QgQ0EwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDH7Zl2oFIq75eVCHtPSH5apYifPyFvIAnB SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDBo8JJDwVm6UTZvA2g/tOZ3xIbKYXI92Rn
J8D3/ylM+Ll5X0/mBkyU5yR7CN0T+WsroWmkkGLuDbrqRrGG30Zs6/DIgHnLn25l T/FCCUycsB5tmoSWcmy1AB6UDv7bFMGy4mdbxnErtdytGj+hEIO3O2EBbpBLAmlJ
rM/6C4B3TApIoBPLqLWaYd0EUwn5hyh5vJdolzCwZtr3swS1BZ23WlPXXWIO8F+m CEVNRrz/YbxGoJmeAii9s3jignUpTr/qLMSKkLowuqABZl2XtCp7Q83YlZPkVhFL
E5QZiFWqjufoHWECyoa3OwJ+U/UcR+Tr/HnlBXaZswTJdr91R9imWZgAE6EF6qM5 kCAny89cG/QGAUxViN7HB4jWzhcBTTfD4PFvSU1HZNhPM0Y6BCpv2qrof3/tPnQr
ZnzNqgsjKPIN62FIcL3SD57CcR8fYvOAHGlY9r/CoDMuAs64wp/+oovC4J8WHvqV xM2zVZoIonQpf6paga61O9fM4wc1GqxGGwARz6Bxq6w2OxRDsV/biqP9gVUj0XmF
xg/z32V7osNq4ko9IArTDESj1ZlL33uVGy/GnTAMZv1CKFMrCfMNAgMBAAGjQjBA 6o/draf3MkDswOUZyKpujOUIf12ezXJFPWaCRN1Rl0vwV2CyVxkvAgMBAAGjQjBA
MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE6fD2uX/Q6n9KjFBO5tB++jGixm MA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFD8ujz0I9Y7079ZMe9X7cO3/rSj5
MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEArE8W97mfL9a8NcaX MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAQEAtHmPfVgu6Y7uWcpq
UmJwiBsoA8zGQ1uWV051JHuW+YbC1az2pRR0kXOLkXeCNhwHfxb8pvEjOToa341K AdawOTZ/2ICOvAMmQ0LcXKmSpgsneHiyAL1Wwe2/XxTwmrpHylOapIIuV3irHCXU
5NYFSRPJVkR09AaF7KjuLzZO821roxbZPPbS8GsFGJ5GbLe6F8EW06rCyLN03Y2q CxaTMUyZGfXoUWsxnR8bcb5ac/aFKkC3ynE2/IfFyJOQ724cK5FRK1+piVleP4Rx
bOAQvAof421193HIO0baBWE13QsLk2wQEYyB/Yld3919ub9plQLxapojRdK2s+cY C04KQiuxuVLedyvGh5OPU/94ZW2JuuBjImVAO/lUbYhAUSpwueX2lYKSSPLkPfDx
Juftt8hE3UDlfQkpnVbIpU4Q/LFtPztfxkcd9rkz/kujH+juBd2UnirjK3n86ReU AsIp55x70iQ+EsgARvseVY2JRzvRnuh66V4P15wn3dIzjtWQ1/t007wMk5Lji5dQ
1MM2QvtnMlXyZiXHujrOkWGS57KaYdkDAV98zWk9Bx7g6K97cy0JPdBq2cnucUJw iSvdyqULBytBqDtLPLzRuma1KJEPRIamF1j6Or6HaHSVUorRhqI3XuxEUGdO4LxZ
0mCOiQ== QepMyA==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View File

@ -1 +1 @@
55c4d523e595564af0ab635fd1e3aaba bb7fd13ddf056e0a3e621d3537b25478

View File

@ -15,7 +15,7 @@ def main() -> None:
try: try:
with open(PORT_LOG, 'r') as file: with open(PORT_LOG, 'r') as file:
port = file.readline() port = file.readline()
conn = http.client.HTTPConnection('localhost', port) conn = http.client.HTTPConnection('127.0.0.1', port)
conn.request('POST', '/kill_server') conn.request('POST', '/kill_server')
response = conn.getresponse() response = conn.getresponse()
print("HTTP status code:", response.getcode(), end=', ') print("HTTP status code:", response.getcode(), end=', ')

View File

@ -42,11 +42,11 @@ make_certs() {
echo -n "$password" > tmp/password.txt echo -n "$password" > tmp/password.txt
################################################################################ ################################################################################
# Root CA certificate # Root CA certificates
################################################################################ ################################################################################
printf "\nGenerate root CA certificate\n" >> "makecerts.log" printf "\nGenerate trusted root CA certificate\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/CA.key \ "$OPENSSL" genrsa -out CA/CAroot.key \
2>> "makecerts.log" 1>&2 2>> "makecerts.log" 1>&2
test_result $? test_result $?
TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c ' TZ=GMT faketime -f '@2017-01-01 00:00:00' /bin/bash -c '
@ -54,11 +54,48 @@ make_certs() {
OPENSSL="$0" OPENSSL="$0"
export LD_LIBRARY_PATH="$1" export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_root.cnf" CONF="${script_path}/openssl_root.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/CA.key -out tmp/CACert.pem \ "$OPENSSL" req -config "$CONF" -new -x509 -days 7300 -key CA/CAroot.key -out tmp/CAroot.pem \
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Trusted Root CA" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nPrepare the Certificate Signing Request (CSR)\n" >> "makecerts.log"
"$OPENSSL" genrsa -out CA/CA.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_root.cnf"
"$OPENSSL" req -config "$CONF" -new -key CA/CA.key -out CA/CACert.csr \
-subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Root CA" \ -subj "/C=PL/O=osslsigncode/OU=Certification Authority/CN=Root CA" \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH" 2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $? test_result $?
printf "\nGenerate Self-signed root CA certificate\n" >> "makecerts.log"
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" x509 -req -days 7300 -extfile "$CONF" -extensions ca_extensions \
-signkey CA/CA.key \
-in CA/CACert.csr -out tmp/CACert.pem \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
printf "\nGenerate Cross-signed root CA certificate\n" >> "makecerts.log"
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_root.cnf"
"$OPENSSL" x509 -req -days 7300 -extfile "$CONF" -extensions ca_extensions \
-CA tmp/CAroot.pem -CAkey CA/CAroot.key -CAserial CA/CAroot.srl \
-CAcreateserial -in CA/CACert.csr -out tmp/CAcross.pem \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $?
################################################################################ ################################################################################
# Private RSA keys # Private RSA keys
################################################################################ ################################################################################
@ -146,19 +183,6 @@ make_certs() {
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH" 2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $? 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" printf "\nGenerate code signing certificate\n" >> "makecerts.log"
"$OPENSSL" req -config "$CONF" -new -key CA/private.key -passin pass:"$password" -out CA/cert.csr \ "$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" \ -subj "/C=PL/ST=Mazovia Province/L=Warsaw/O=osslsigncode/OU=CSP/CN=Certificate/emailAddress=osslsigncode@example.com" \
@ -319,7 +343,7 @@ make_certs() {
OPENSSL="$0" OPENSSL="$0"
export LD_LIBRARY_PATH="$1" export LD_LIBRARY_PATH="$1"
CONF="${script_path}/openssl_tsa_root.cnf" CONF="${script_path}/openssl_tsa_root.cnf"
"$OPENSSL" req -config "$CONF" -new -x509 -days 3600 -key CA/TSACA.key -out tmp/TSACA.pem \ "$OPENSSL" req -config "$CONF" -new -x509 -days 7300 -key CA/TSACA.key -out tmp/TSACA.pem \
2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH" 2>> "makecerts.log" 1>&2' "$OPENSSL" "$LD_LIBRARY_PATH"
test_result $? test_result $?
@ -377,14 +401,14 @@ make_certs() {
# Copy new files # Copy new files
################################################################################ ################################################################################
if test -s tmp/CACert.pem \ if test -s tmp/CACert.pem -a -s tmp/CAcross.pem -a -s tmp/CAroot.pem \
-a -s tmp/intermediateCA.pem -a -s tmp/intermediateCA_crldp.pem \ -a -s tmp/intermediateCA.pem -a -s tmp/intermediateCA_crldp.pem \
-a -s tmp/CACertCRL.pem -a -s tmp/CACertCRL.der \ -a -s tmp/CACertCRL.pem -a -s tmp/CACertCRL.der \
-a -s tmp/TSACertCRL.pem -a -s tmp/TSACertCRL.der \ -a -s tmp/TSACertCRL.pem -a -s tmp/TSACertCRL.der \
-a -s tmp/key.pem -a -s tmp/keyp.pem -a -s tmp/key.der -a -s tmp/key.pvk \ -a -s tmp/key.pem -a -s tmp/keyp.pem -a -s tmp/key.der -a -s tmp/key.pvk \
-a -s tmp/cert.pem -a -s tmp/cert.der -a -s tmp/cert.spc \ -a -s tmp/cert.pem -a -s tmp/cert.der -a -s tmp/cert.spc \
-a -s tmp/cert.p12 -a -s tmp/legacy.p12 -a -s tmp/cert_crldp.pem\ -a -s tmp/cert.p12 -a -s tmp/legacy.p12 -a -s tmp/cert_crldp.pem\
-a -s tmp/crosscert.pem -a -s tmp/expired.pem \ -a -s tmp/expired.pem \
-a -s tmp/revoked.pem -a -s tmp/revoked_crldp.pem \ -a -s tmp/revoked.pem -a -s tmp/revoked_crldp.pem \
-a -s tmp/TSA_revoked.pem \ -a -s tmp/TSA_revoked.pem \
-a -s tmp/TSA.pem -a -s tmp/TSA.key -a -s tmp/tsa-chain.pem -a -s tmp/TSA.pem -a -s tmp/TSA.key -a -s tmp/tsa-chain.pem

View File

@ -20,8 +20,8 @@ crl_extensions = crl_ext
default_md = sha256 default_md = sha256
preserve = no preserve = no
policy = policy_loose policy = policy_loose
default_startdate = 180101000000Z default_startdate = 20180101000000Z
default_enddate = 241231000000Z default_enddate = 20341231000000Z
x509_extensions = v3_req x509_extensions = v3_req
email_in_dn = yes email_in_dn = yes
default_days = 2200 default_days = 2200

View File

@ -21,8 +21,8 @@ crl_extensions = crl_ext
default_md = sha256 default_md = sha256
preserve = no preserve = no
policy = policy_loose policy = policy_loose
default_startdate = 180101000000Z default_startdate = 20180101000000Z
default_enddate = 241231000000Z default_enddate = 20341231000000Z
x509_extensions = v3_req x509_extensions = v3_req
email_in_dn = yes email_in_dn = yes
default_days = 2200 default_days = 2200

View File

@ -18,8 +18,8 @@ crl_extensions = crl_ext
default_md = sha256 default_md = sha256
preserve = no preserve = no
policy = policy_match policy = policy_match
default_startdate = 180101000000Z default_startdate = 20180101000000Z
default_enddate = 260101000000Z default_enddate = 20360101000000Z
x509_extensions = v3_intermediate_ca x509_extensions = v3_intermediate_ca
email_in_dn = yes email_in_dn = yes
default_days = 3000 default_days = 3000

View File

@ -24,7 +24,7 @@ default_days = 3650
default_crl_days = 365 default_crl_days = 365
policy = policy_match policy = policy_match
default_startdate = 20180101000000Z default_startdate = 20180101000000Z
default_enddate = 20280101000000Z default_enddate = 20380101000000Z
unique_subject = no unique_subject = no
email_in_dn = no email_in_dn = no
x509_extensions = tsa_extensions x509_extensions = tsa_extensions

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

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

Binary file not shown.

BIN
tests/files/unsigned.mof Normal file

Binary file not shown.

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

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

View File

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

View File

@ -6,7 +6,8 @@ import subprocess
import sys import sys
import threading import threading
from urllib.parse import urlparse from urllib.parse import urlparse
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer from http.server import SimpleHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
RESULT_PATH = os.getcwd() RESULT_PATH = os.getcwd()
FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/") FILES_PATH = os.path.join(RESULT_PATH, "./Testing/files/")
@ -27,6 +28,8 @@ OPENSSL_TS = ["openssl", "ts",
"-queryfile", REQUEST, "-queryfile", REQUEST,
"-out", RESPONS] "-out", RESPONS]
class ThreadingHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
class RequestHandler(SimpleHTTPRequestHandler): class RequestHandler(SimpleHTTPRequestHandler):
"""Handle the HTTP POST request that arrive at the server""" """Handle the HTTP POST request that arrive at the server"""
@ -43,6 +46,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.send_response(200) self.send_response(200)
self.send_header("Content-type", "application/crl") self.send_header("Content-type", "application/crl")
self.end_headers() self.end_headers()
resp_data = b''
# Read the file and send the contents # Read the file and send the contents
if url.path == "/intermediateCA": if url.path == "/intermediateCA":
with open(CACRL, 'rb') as file: with open(CACRL, 'rb') as file:
@ -52,7 +56,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP GET request error: {err}") print("HTTP GET request error: {}".format(err))
def do_POST(self): # pylint: disable=invalid-name def do_POST(self): # pylint: disable=invalid-name
""""Serves the POST request type""" """"Serves the POST request type"""
@ -76,12 +81,12 @@ class RequestHandler(SimpleHTTPRequestHandler):
openssl.check_returncode() openssl.check_returncode()
self.send_header("Content-type", "application/timestamp-reply") self.send_header("Content-type", "application/timestamp-reply")
self.end_headers() self.end_headers()
resp_data = None resp_data = b''
with open(RESPONS, mode="rb") as file: with open(RESPONS, mode="rb") as file:
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP POST request error: {err}") print("HTTP POST request error: {}".format(err))
class HttpServerThread(): class HttpServerThread():
@ -93,12 +98,12 @@ class HttpServerThread():
self.server_thread = None self.server_thread = None
def start_server(self, port) -> (int): def start_server(self, port) -> (int):
"""Starting HTTP server on localhost and a random available port for binding""" """Starting HTTP server on 127.0.0.1 and a random available port for binding"""
self.server = ThreadingHTTPServer(('localhost', port), RequestHandler) self.server = ThreadingHTTPServer(('127.0.0.1', port), RequestHandler)
self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.start() self.server_thread.start()
hostname, port = self.server.server_address[:2] hostname, port = self.server.server_address[:2]
print(f"HTTP server started, URL http://{hostname}:{port}") print("HTTP server started, URL http://{}:{}".format(hostname, port))
return port return port
@ -119,7 +124,7 @@ def main() -> None:
with open(PORT_LOG, mode="w") as file: with open(PORT_LOG, mode="w") as file:
file.write("{}".format(port)) file.write("{}".format(port))
except OSError as err: except OSError as err:
print(f"OSError: {err}") print("OSError: {}".format(err))
ret = err.errno ret = err.errno
finally: finally:
sys.exit(ret) sys.exit(ret)
@ -131,7 +136,7 @@ if __name__ == '__main__':
if fpid > 0: if fpid > 0:
sys.exit(0) sys.exit(0)
except OSError as ferr: except OSError as ferr:
print(f"Fork #1 failed: {ferr.errno} {ferr.strerror}") print("Fork #1 failed: {} {}".format(ferr.errno, ferr.strerror))
sys.exit(1) sys.exit(1)
try: try:
@ -139,7 +144,7 @@ if __name__ == '__main__':
if fpid > 0: if fpid > 0:
sys.exit(0) sys.exit(0)
except OSError as ferr: except OSError as ferr:
print(f"Fork #2 failed: {ferr.errno} {ferr.strerror}") print("Fork #2 failed: {} {}".format(ferr.errno, ferr.strerror))
sys.exit(1) sys.exit(1)
# Start the daemon main loop # Start the daemon main loop

View File

@ -43,6 +43,7 @@ class RequestHandler(SimpleHTTPRequestHandler):
self.send_response(200) self.send_response(200)
self.send_header("Content-type", "application/crl") self.send_header("Content-type", "application/crl")
self.end_headers() self.end_headers()
resp_data = b''
# Read the file and send the contents # Read the file and send the contents
if url.path == "/intermediateCA": if url.path == "/intermediateCA":
with open(CACRL, 'rb') as file: with open(CACRL, 'rb') as file:
@ -52,7 +53,8 @@ class RequestHandler(SimpleHTTPRequestHandler):
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP GET request error: {err}") print("HTTP GET request error: {}".format(err))
def do_POST(self): # pylint: disable=invalid-name def do_POST(self): # pylint: disable=invalid-name
""""Serves the POST request type""" """"Serves the POST request type"""
@ -76,12 +78,12 @@ class RequestHandler(SimpleHTTPRequestHandler):
openssl.check_returncode() openssl.check_returncode()
self.send_header("Content-type", "application/timestamp-reply") self.send_header("Content-type", "application/timestamp-reply")
self.end_headers() self.end_headers()
resp_data = None resp_data = b''
with open(RESPONS, mode="rb") as file: with open(RESPONS, mode="rb") as file:
resp_data = file.read() resp_data = file.read()
self.wfile.write(resp_data) self.wfile.write(resp_data)
except Exception as err: # pylint: disable=broad-except except Exception as err: # pylint: disable=broad-except
print(f"HTTP POST request error: {err}") print("HTTP POST request error: {}".format(err))
class HttpServerThread(): class HttpServerThread():
@ -93,12 +95,12 @@ class HttpServerThread():
self.server_thread = None self.server_thread = None
def start_server(self) -> (int): def start_server(self) -> (int):
"""Starting HTTP server on localhost and a random available port for binding""" """Starting HTTP server on 127.0.0.1 and a random available port for binding"""
self.server = ThreadingHTTPServer(('localhost', 19254), RequestHandler) self.server = ThreadingHTTPServer(('127.0.0.1', 19254), RequestHandler)
self.server_thread = threading.Thread(target=self.server.serve_forever) self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.start() self.server_thread.start()
hostname, port = self.server.server_address[:2] hostname, port = self.server.server_address[:2]
print(f"HTTP server started, URL http://{hostname}:{port}") print("HTTP server started, URL http://{}:{}".format(hostname, port))
return port return port
@ -113,7 +115,7 @@ def main() -> None:
with open(PORT_LOG, mode="w") as file: with open(PORT_LOG, mode="w") as file:
file.write("{}".format(port)) file.write("{}".format(port))
except OSError as err: except OSError as err:
print(f"OSError: {err}") print("OSError: {}".format(err))
ret = err.errno ret = err.errno
finally: finally:
sys.exit(ret) sys.exit(ret)

View File

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

Binary file not shown.

347
utf.c Normal file
View File

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

61
utf.h Normal file
View File

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

View File

@ -8,5 +8,6 @@
"name": "python3", "name": "python3",
"platform": "!(windows & static) & !osx" "platform": "!(windows & static) & !osx"
} }
] ],
"builtin-baseline": "9edb1b8e590cc086563301d735cae4b6e732d2d2"
} }